diff --git a/qse/samples/app/TcpGate.cpp b/qse/samples/app/TcpGate.cpp index 4896a12e..f334e030 100644 --- a/qse/samples/app/TcpGate.cpp +++ b/qse/samples/app/TcpGate.cpp @@ -1,433 +1,495 @@ #include "TcpGate.hpp" #include "MainApp.hpp" -#include -#include #include #include // -------------------------------------------------------------------------- -#define CMD_OK "OK" -#define CMD_ERR "ERR" -#define CMD_WARN "WARN" +#define CMD_OK_ "OK" +#define CMD_ERR_ "ERR" +#define CMD_WARN_ "WARN" -#define CMD_DISCON "DISCON" -#define CMD_SHTDWN "SHTDWN" -#define CMD_ENVGET "ENVGET" -#define CMD_ENVSET "ENVSET" -#define CMD_ENVLST "ENVLST" -#define CMD_ENVITM "ENVITM" +#define CMD_DISCON_ "DISCON" +#define CMD_SHTDWN_ "SHTDWN" +#define CMD_ENVGET_ "ENVGET" +#define CMD_ENVSET_ "ENVSET" +#define CMD_ENVSAV_ "ENVSAV" +#define CMD_ENVLST_ "ENVLST" +#define CMD_ENVITM_ "ENVITM" +#define CMD_OPTGET_ "OPTGET" +#define CMD_OPTSET_ "OPTSET" + +#define MSG_UNABLE_TO_STORE_ "unable to store" +#define MSG_UNABLE_TO_SET_VALUE_ "unable to set value" +#define MSG_UNKNOWN_COMMAND_ "unknown command" #define PROC_CHECK_ARG_COUNT(cmd,n) do { \ if (cmd.getArgCount() != (n)) { \ - this->sendErrCmd (E_ENARGS, (const qse_mchar_t*)QSE_NULL); \ + this->sendErrCmd (E_ENARGS); \ return 0; \ } \ } while(0) #define PROC_CHECK_ARG_COUNT2(cmd,n1,n2) do { \ if (cmd.getArgCount() != (n1) && cmd.getArgCount() != (n2)) { \ - this->sendErrCmd (E_ENARGS, (const qse_mchar_t*)QSE_NULL); \ + this->sendErrCmd (E_ENARGS); \ return 0; \ } \ } while(0) #define PROC_CHECK_ARG_COUNT_RANGE(cmd,n1,n2) do { \ if (cmd.getArgCount() < (n1) || cmd.getArgCount() > (n2)) { \ - this->sendErrCmd (E_ENARGS, (const qse_mchar_t*)QSE_NULL); \ + this->sendErrCmd (E_ENARGS); \ return 0; \ } \ } while(0) -class Proto: public QSE::Sttp +TcpGateProto::TcpGateProto (MainApp* app, QSE::Socket* sck): QSE::Sttp(), app(app), sck(sck), opt_autosave(1) { -public: - typedef int (Proto::*CmdProc) (const QSE::SttpCmd& cmd); + this->cmd_dict.insert (QSE_T(CMD_DISCON_), &TcpGateProto::proc_discon); + this->cmd_dict.insert (QSE_T(CMD_SHTDWN_), &TcpGateProto::proc_shtdwn); + this->cmd_dict.insert (QSE_T(CMD_ENVLST_), &TcpGateProto::proc_envlst); + this->cmd_dict.insert (QSE_T(CMD_ENVGET_), &TcpGateProto::proc_envget); + this->cmd_dict.insert (QSE_T(CMD_ENVSET_), &TcpGateProto::proc_envset); + this->cmd_dict.insert (QSE_T(CMD_ENVSAV_), &TcpGateProto::proc_envsav); + this->cmd_dict.insert (QSE_T(CMD_OPTGET_), &TcpGateProto::proc_optget); + this->cmd_dict.insert (QSE_T(CMD_OPTSET_), &TcpGateProto::proc_optset); +} - Proto (MainApp* app, QSE::Socket* sck): QSE::Sttp(), app(app), sck(sck) +int TcpGateProto::sendCmd (const qse_mchar_t* cmd, qse_size_t nargs, ...) +{ + int x; + va_list ap; + + va_start (ap, nargs); + if (QSE_APP_LOG_ENABLED(this->app, QSE_LOG_INFO)) { - this->cmd_dict.insert (QSE_T(CMD_DISCON), &Proto::proc_discon); - this->cmd_dict.insert (QSE_T(CMD_SHTDWN), &Proto::proc_shtdwn); - this->cmd_dict.insert (QSE_T(CMD_ENVLST), &Proto::proc_envlst); - this->cmd_dict.insert (QSE_T(CMD_ENVGET), &Proto::proc_envget); - this->cmd_dict.insert (QSE_T(CMD_ENVSET), &Proto::proc_envset); - } + va_list xap; + int h = (int)this->sck->getHandle(); - int sendCmd (const qse_mchar_t* cmd, qse_size_t nargs, ...) - { - int x; - va_list ap; + va_copy (xap, ap); - va_start (ap, nargs); - if (QSE_APP_LOG_ENABLED(this->app, QSE_LOG_INFO)) + // ugly - any better way to call QSE_APP_LOGX in a single call? better to store arguments to a buffer first and call QSE_APP_LOGX with it? + switch (nargs) { - va_list xap; - int h = (int)this->sck->getHandle(); + case 0: + QSE_APP_LOG2 (this->app, QSE_LOG_INFO, QSE_T("[h=%d,R] %hs\n"), h, cmd); + break; - va_copy (xap, ap); + case 1: + QSE_APP_LOG3 (this->app, QSE_LOG_INFO, QSE_T("[h=%d,R] %hs %hs\n"), h, cmd, va_arg(xap, qse_mchar_t*)); + break; - // ugly - any better way to call QSE_APP_LOGX in a single call? better to store arguments to a buffer first and call QSE_APP_LOGX with it? - switch (nargs) + case 2: { - case 0: - QSE_APP_LOG2 (this->app, QSE_LOG_INFO, QSE_T("[h=%d,R] %hs\n"), h, cmd); - break; - - case 1: - QSE_APP_LOG3 (this->app, QSE_LOG_INFO, QSE_T("[h=%d,R] %hs %hs\n"), h, cmd, va_arg(xap, qse_mchar_t*)); - break; - - case 2: - { - qse_mchar_t* x[] = { va_arg(xap, qse_mchar_t*), va_arg(xap, qse_mchar_t*) }; - QSE_APP_LOG4 (this->app, QSE_LOG_INFO, QSE_T("[h=%d,R] %hs %hs %hs\n"), h, cmd, x[0], x[1]); - break; - } - - case 3: - { - qse_mchar_t* x[] = { va_arg(xap, qse_mchar_t*), va_arg(xap, qse_mchar_t*), va_arg(xap, qse_mchar_t*) }; - QSE_APP_LOG5 (this->app, QSE_LOG_INFO, QSE_T("[h=%d,R] %hs %hs %hs %hs\n"), h, cmd, x[0], x[1], x[2]); - break; - } - - case 4: - { - qse_mchar_t* x[] = { va_arg(xap, qse_mchar_t*), va_arg(xap, qse_mchar_t*), va_arg(xap, qse_mchar_t*), va_arg(xap, qse_mchar_t*) }; - QSE_APP_LOG6 (this->app, QSE_LOG_INFO, QSE_T("[h=%d,R] %hs %hs %hs %hs %hs\n"), h, cmd, x[0], x[1], x[2], x[3]); - break; - } - - case 5: - { - qse_mchar_t* x[] = { va_arg(xap, qse_mchar_t*), va_arg(xap, qse_mchar_t*), va_arg(xap, qse_mchar_t*), va_arg(xap, qse_mchar_t*), va_arg(xap, qse_mchar_t*) }; - QSE_APP_LOG7 (this->app, QSE_LOG_INFO, QSE_T("[h=%d,R] %hs %hs %hs %hs %hs %hs\n"), h, cmd, x[0], x[1], x[2], x[3], x[4]); - break; - } - - case 6: - { - qse_mchar_t* x[] = { va_arg(xap, qse_mchar_t*), va_arg(xap, qse_mchar_t*), va_arg(xap, qse_mchar_t*), va_arg(xap, qse_mchar_t*), va_arg(xap, qse_mchar_t*), va_arg(xap, qse_mchar_t*) }; - QSE_APP_LOG8 (this->app, QSE_LOG_INFO, QSE_T("[h=%d,R] %hs %hs %hs %hs %hs %hs %hs\n"), h, cmd, x[0], x[1], x[2], x[3], x[4], x[5]); - break; - } - - case 7: - { - qse_mchar_t* x[] = { va_arg(xap, qse_mchar_t*), va_arg(xap, qse_mchar_t*), va_arg(xap, qse_mchar_t*), va_arg(xap, qse_mchar_t*), va_arg(xap, qse_mchar_t*), va_arg(xap, qse_mchar_t*), va_arg(xap, qse_mchar_t*) }; - QSE_APP_LOG9 (this->app, QSE_LOG_INFO, QSE_T("[h=%d,R] %hs %hs %hs %hs %hs %hs %hs %hs\n"), h, cmd, x[0], x[1], x[2], x[3], x[4], x[5], x[6]); - break; - } - - default: - { - qse_mchar_t* x[] = { va_arg(xap, qse_mchar_t*), va_arg(xap, qse_mchar_t*), va_arg(xap, qse_mchar_t*), va_arg(xap, qse_mchar_t*), va_arg(xap, qse_mchar_t*), va_arg(xap, qse_mchar_t*), va_arg(xap, qse_mchar_t*) }; - QSE_APP_LOG9 (this->app, QSE_LOG_INFO, QSE_T("[h=%d,R] %hs %hs %hs %hs %hs %hs %hs %hs %hs ...\n"), h, cmd, x[0], x[1], x[2], x[3], x[4], x[5], x[6]); - break; - } + qse_mchar_t* x[] = { va_arg(xap, qse_mchar_t*), va_arg(xap, qse_mchar_t*) }; + QSE_APP_LOG4 (this->app, QSE_LOG_INFO, QSE_T("[h=%d,R] %hs %hs %hs\n"), h, cmd, x[0], x[1]); + break; } - va_end (xap); - } - - x = QSE::Sttp::sendCmdV(cmd, nargs, ap); - va_end (ap); - - return x; - } - - int sendCmd (const qse_wchar_t* cmd, qse_size_t nargs, ...) - { - int x; - va_list ap; - - va_start (ap, nargs); - - if (QSE_APP_LOG_ENABLED(this->app, QSE_LOG_INFO)) - { - va_list xap; - int h = (int)this->sck->getHandle(); - - va_copy (xap, ap); - - // ugly - any better way to call QSE_APP_LOGX in a single call? better to store arguments to a buffer first and call QSE_APP_LOGX with it? - switch (nargs) + case 3: { - case 0: - QSE_APP_LOG2 (this->app, QSE_LOG_INFO, QSE_T("[h=%d,R] %ls\n"), h, cmd); - break; - - case 1: - QSE_APP_LOG3 (this->app, QSE_LOG_INFO, QSE_T("[h=%d,R] %ls %ls\n"), h, cmd, va_arg(xap, qse_wchar_t*)); - break; - - case 2: - { - qse_wchar_t* x[] = { va_arg(xap, qse_wchar_t*), va_arg(xap, qse_wchar_t*) }; - QSE_APP_LOG4 (this->app, QSE_LOG_INFO, QSE_T("[h=%d,R] %ls %ls %ls\n"), h, cmd, x[0], x[1]); - break; - } - - case 3: - { - qse_wchar_t* x[] = { va_arg(xap, qse_wchar_t*), va_arg(xap, qse_wchar_t*), va_arg(xap, qse_wchar_t*) }; - QSE_APP_LOG5 (this->app, QSE_LOG_INFO, QSE_T("[h=%d,R] %ls %ls %ls %ls\n"), h, cmd, x[0], x[1], x[2]); - break; - } - - case 4: - { - qse_wchar_t* x[] = { va_arg(xap, qse_wchar_t*), va_arg(xap, qse_wchar_t*), va_arg(xap, qse_wchar_t*), va_arg(xap, qse_wchar_t*) }; - QSE_APP_LOG6 (this->app, QSE_LOG_INFO, QSE_T("[h=%d,R] %ls %ls %ls %ls %ls\n"), h, cmd, x[0], x[1], x[2], x[3]); - break; - } - - case 5: - { - qse_wchar_t* x[] = { va_arg(xap, qse_wchar_t*), va_arg(xap, qse_wchar_t*), va_arg(xap, qse_wchar_t*), va_arg(xap, qse_wchar_t*), va_arg(xap, qse_wchar_t*) }; - QSE_APP_LOG7 (this->app, QSE_LOG_INFO, QSE_T("[h=%d,R] %ls %ls %ls %ls %ls %ls\n"), h, cmd, x[0], x[1], x[2], x[3], x[4]); - break; - } - - case 6: - { - qse_wchar_t* x[] = { va_arg(xap, qse_wchar_t*), va_arg(xap, qse_wchar_t*), va_arg(xap, qse_wchar_t*), va_arg(xap, qse_wchar_t*), va_arg(xap, qse_wchar_t*), va_arg(xap, qse_wchar_t*) }; - QSE_APP_LOG8 (this->app, QSE_LOG_INFO, QSE_T("[h=%d,R] %ls %ls %ls %ls %ls %ls %ls\n"), h, cmd, x[0], x[1], x[2], x[3], x[4], x[5]); - break; - } - - case 7: - { - qse_wchar_t* x[] = { va_arg(xap, qse_wchar_t*), va_arg(xap, qse_wchar_t*), va_arg(xap, qse_wchar_t*), va_arg(xap, qse_wchar_t*), va_arg(xap, qse_wchar_t*), va_arg(xap, qse_wchar_t*), va_arg(xap, qse_wchar_t*) }; - QSE_APP_LOG9 (this->app, QSE_LOG_INFO, QSE_T("[h=%d,R] %ls %ls %ls %ls %ls %ls %ls %ls\n"), h, cmd, x[0], x[1], x[2], x[3], x[4], x[5], x[6]); - break; - } - - default: - { - qse_wchar_t* x[] = { va_arg(xap, qse_wchar_t*), va_arg(xap, qse_wchar_t*), va_arg(xap, qse_wchar_t*), va_arg(xap, qse_wchar_t*), va_arg(xap, qse_wchar_t*), va_arg(xap, qse_wchar_t*), va_arg(xap, qse_wchar_t*) }; - QSE_APP_LOG9 (this->app, QSE_LOG_INFO, QSE_T("[h=%d,R] %ls %ls %ls %ls %ls %ls %ls %ls %ls ...\n"), h, cmd, x[0], x[1], x[2], x[3], x[4], x[5], x[6]); - break; - } + qse_mchar_t* x[] = { va_arg(xap, qse_mchar_t*), va_arg(xap, qse_mchar_t*), va_arg(xap, qse_mchar_t*) }; + QSE_APP_LOG5 (this->app, QSE_LOG_INFO, QSE_T("[h=%d,R] %hs %hs %hs %hs\n"), h, cmd, x[0], x[1], x[2]); + break; } - va_end (xap); - } - - x = QSE::Sttp::sendCmdV(cmd, nargs, ap); - va_end (ap); - - return x; - } - - int sendErrCmd (ErrorNumber err, const qse_mchar_t* msg) - { - qse_mchar_t buf[32]; - qse_fmtintmaxtombs(buf, QSE_COUNTOF(buf), err, 10, -1, '\0', QSE_NULL); - QSE::TypesErrorNumberToMbstr x; - return this->sendCmd(CMD_ERR, 2, buf, (msg? msg: x(err))); - } - - int sendErrCmd (ErrorNumber err, const qse_wchar_t* msg) - { - qse_wchar_t buf[32]; - qse_fmtintmaxtowcs(buf, QSE_COUNTOF(buf), err, 10, -1, '\0', QSE_NULL); - QSE::TypesErrorNumberToWcstr x; - return this->sendCmd(QSE_WT(CMD_ERR), 2, buf, (msg? msg: x(err))); - } - - int sendWarnCmd (ErrorNumber err, const qse_mchar_t* msg) - { - qse_mchar_t buf[32]; - qse_fmtintmaxtombs(buf, QSE_COUNTOF(buf), err, 10, -1, '\0', QSE_NULL); - QSE::TypesErrorNumberToMbstr x; - return this->sendCmd(CMD_WARN, 2, buf, (msg? msg: x(err))); - } - - int sendWarnCmd (ErrorNumber err, const qse_wchar_t* msg) - { - qse_wchar_t buf[32]; - qse_fmtintmaxtowcs(buf, QSE_COUNTOF(buf), err, 10, -1, '\0', QSE_NULL); - QSE::TypesErrorNumberToWcstr x; - return this->sendCmd(QSE_WT(CMD_WARN), 2, buf, (msg? msg: x(err))); - } - - int sendOkCmd () - { - return this->sendCmd(CMD_OK, 0); - } - int sendOkCmd (const qse_mchar_t* msg1) - { - return this->sendCmd(CMD_OK, 1, msg1); - } - int sendOkCmd (const qse_mchar_t* msg1, const qse_mchar_t* msg2) - { - return this->sendCmd(CMD_OK, 2, msg1, msg2); - } - int sendOkCmd (const qse_wchar_t* msg1) - { - return this->sendCmd(QSE_WT(CMD_OK), 1, msg1); - } - int sendOkCmd (const qse_wchar_t* msg1, const qse_wchar_t* msg2) - { - return this->sendCmd(QSE_WT(CMD_OK), 2, msg1, msg2); - } - -protected: - MainApp* app; - QSE::Socket* sck; - - typedef QSE::HashTable CmdDict; - CmdDict cmd_dict; - - int handle_command (const QSE::SttpCmd& cmd) - { - if (QSE_APP_LOG_ENABLED(this->app, QSE_LOG_INFO)) - { - int h = this->sck->getHandle(); - const qse_char_t* name = cmd.name.getData(); - - // ugly - any better way to call QSE_APP_LOGX in a single call? better to store arguments to a buffer first and call QSE_APP_LOGX with it? - switch (cmd.getArgCount()) + case 4: { - case 0: - QSE_APP_LOG2 (this->app, QSE_LOG_INFO, QSE_T("[h=%d,Q] %js\n"), h, name); - break; + qse_mchar_t* x[] = { va_arg(xap, qse_mchar_t*), va_arg(xap, qse_mchar_t*), va_arg(xap, qse_mchar_t*), va_arg(xap, qse_mchar_t*) }; + QSE_APP_LOG6 (this->app, QSE_LOG_INFO, QSE_T("[h=%d,R] %hs %hs %hs %hs %hs\n"), h, cmd, x[0], x[1], x[2], x[3]); + break; + } - case 1: - QSE_APP_LOG3 (this->app, QSE_LOG_INFO, QSE_T("[h=%d,Q] %js %js\n"), h, name, cmd.getArgAt(0)); - break; + case 5: + { + qse_mchar_t* x[] = { va_arg(xap, qse_mchar_t*), va_arg(xap, qse_mchar_t*), va_arg(xap, qse_mchar_t*), va_arg(xap, qse_mchar_t*), va_arg(xap, qse_mchar_t*) }; + QSE_APP_LOG7 (this->app, QSE_LOG_INFO, QSE_T("[h=%d,R] %hs %hs %hs %hs %hs %hs\n"), h, cmd, x[0], x[1], x[2], x[3], x[4]); + break; + } - case 2: - QSE_APP_LOG4 (this->app, QSE_LOG_INFO, QSE_T("[h=%d,Q] %js %js %js\n"), h, name, cmd.getArgAt(0), cmd.getArgAt(1)); - break; + case 6: + { + qse_mchar_t* x[] = { va_arg(xap, qse_mchar_t*), va_arg(xap, qse_mchar_t*), va_arg(xap, qse_mchar_t*), va_arg(xap, qse_mchar_t*), va_arg(xap, qse_mchar_t*), va_arg(xap, qse_mchar_t*) }; + QSE_APP_LOG8 (this->app, QSE_LOG_INFO, QSE_T("[h=%d,R] %hs %hs %hs %hs %hs %hs %hs\n"), h, cmd, x[0], x[1], x[2], x[3], x[4], x[5]); + break; + } - case 3: - QSE_APP_LOG5 (this->app, QSE_LOG_INFO, QSE_T("[h=%d,Q] %js %js %js %js\n"), h, name, cmd.getArgAt(0), cmd.getArgAt(1), cmd.getArgAt(2)); - break; + case 7: + { + qse_mchar_t* x[] = { va_arg(xap, qse_mchar_t*), va_arg(xap, qse_mchar_t*), va_arg(xap, qse_mchar_t*), va_arg(xap, qse_mchar_t*), va_arg(xap, qse_mchar_t*), va_arg(xap, qse_mchar_t*), va_arg(xap, qse_mchar_t*) }; + QSE_APP_LOG9 (this->app, QSE_LOG_INFO, QSE_T("[h=%d,R] %hs %hs %hs %hs %hs %hs %hs %hs\n"), h, cmd, x[0], x[1], x[2], x[3], x[4], x[5], x[6]); + break; + } - case 4: - QSE_APP_LOG6 (this->app, QSE_LOG_INFO, QSE_T("[h=%d,Q] %js %js %js %js %js\n"), h, name, cmd.getArgAt(0), cmd.getArgAt(1), cmd.getArgAt(2), cmd.getArgAt(3)); - break; - - case 5: - QSE_APP_LOG7 (this->app, QSE_LOG_INFO, QSE_T("[h=%d,Q] %js %js %js %js %js %js\n"), h, name, cmd.getArgAt(0), cmd.getArgAt(1), cmd.getArgAt(2), cmd.getArgAt(3), cmd.getArgAt(4)); - break; - - case 6: - QSE_APP_LOG8 (this->app, QSE_LOG_INFO, QSE_T("[h=%d,Q] %js %js %js %js %js %js %js\n"), h, name, cmd.getArgAt(0), cmd.getArgAt(1), cmd.getArgAt(2), cmd.getArgAt(3), cmd.getArgAt(4), cmd.getArgAt(5)); - break; - - case 7: - QSE_APP_LOG9 (this->app, QSE_LOG_INFO, QSE_T("[h=%d,Q] %js %js %js %js %js %js %js %js\n"), h, name, cmd.getArgAt(0), cmd.getArgAt(1), cmd.getArgAt(2), cmd.getArgAt(3), cmd.getArgAt(4), cmd.getArgAt(5), cmd.getArgAt(6)); - break; - - default: - QSE_APP_LOG9 (this->app, QSE_LOG_INFO, QSE_T("[h=%d,Q] %js %js %js %js %js %js %js %js ...\n"), h, name, cmd.getArgAt(0), cmd.getArgAt(1), cmd.getArgAt(2), cmd.getArgAt(3), cmd.getArgAt(4), cmd.getArgAt(5), cmd.getArgAt(6)); - break; + default: + { + qse_mchar_t* x[] = { va_arg(xap, qse_mchar_t*), va_arg(xap, qse_mchar_t*), va_arg(xap, qse_mchar_t*), va_arg(xap, qse_mchar_t*), va_arg(xap, qse_mchar_t*), va_arg(xap, qse_mchar_t*), va_arg(xap, qse_mchar_t*) }; + QSE_APP_LOG9 (this->app, QSE_LOG_INFO, QSE_T("[h=%d,R] %hs %hs %hs %hs %hs %hs %hs %hs %hs ...\n"), h, cmd, x[0], x[1], x[2], x[3], x[4], x[5], x[6]); + break; } } - CmdDict::Pair* pair = this->cmd_dict.search(cmd.name); - if (!pair) return this->sendErrCmd(E_ENOENT, "unknown command"); - - return (this->*(pair->value))(cmd); + va_end (xap); } - int write_bytes (const qse_uint8_t* data, qse_size_t len) + x = QSE::Sttp::sendCmdV(cmd, nargs, ap); + va_end (ap); + + return x; +} + +int TcpGateProto::sendCmd (const qse_wchar_t* cmd, qse_size_t nargs, ...) +{ + int x; + va_list ap; + + va_start (ap, nargs); + + if (QSE_APP_LOG_ENABLED(this->app, QSE_LOG_INFO)) { - int n = this->sck->sendx(data, len, QSE_NULL); - if (QSE_UNLIKELY(n <= -1)) this->setErrorFmt(E_ESYSERR, QSE_T("%js"), sck->getErrorMsg()); - return n; - } + va_list xap; + int h = (int)this->sck->getHandle(); - int proc_discon (const QSE::SttpCmd& cmd) - { - PROC_CHECK_ARG_COUNT (cmd, 0); - - this->sendOkCmd (); // success and failure doesn't matter - sck->shutdown (); - return 0; - } - - int proc_shtdwn (const QSE::SttpCmd& cmd) - { - PROC_CHECK_ARG_COUNT_RANGE(cmd, 0, 1); - int ret = 0; - - if (cmd.getArgCount() >= 1) ret = qse_strtoi(cmd.getArgAt(0), 0, QSE_NULL); - - this->sendOkCmd (); // success and failure doesn't matter - this->app->stop (ret); - return 0; - } - - int proc_envlst (const QSE::SttpCmd& cmd) - { - PROC_CHECK_ARG_COUNT (cmd, 0); + va_copy (xap, ap); + // ugly - any better way to call QSE_APP_LOGX in a single call? better to store arguments to a buffer first and call QSE_APP_LOGX with it? + switch (nargs) { - QSE::ScopedMutexLocker sml (this->app->getEnvMutex()); - const MainApp::Env::ItemList& item_list = this->app->getEnv().getItemList(); - for (const MainApp::Env::ItemList::Node* np = item_list.getHeadNode(); np; np = np->getNextNode()) + case 0: + QSE_APP_LOG2 (this->app, QSE_LOG_INFO, QSE_T("[h=%d,R] %ls\n"), h, cmd); + break; + + case 1: + QSE_APP_LOG3 (this->app, QSE_LOG_INFO, QSE_T("[h=%d,R] %ls %ls\n"), h, cmd, va_arg(xap, qse_wchar_t*)); + break; + + case 2: { - const MainApp::Env::Item& item = np->value; - const qse_char_t* val = this->app->getEnv().getValue(item.name); - QSE_ASSERT (val != QSE_NULL); - if (this->sendCmd(QSE_T(CMD_ENVITM), 2, item.name, val) <= -1) return -1; - } + qse_wchar_t* x[] = { va_arg(xap, qse_wchar_t*), va_arg(xap, qse_wchar_t*) }; + QSE_APP_LOG4 (this->app, QSE_LOG_INFO, QSE_T("[h=%d,R] %ls %ls %ls\n"), h, cmd, x[0], x[1]); + break; + } + + case 3: + { + qse_wchar_t* x[] = { va_arg(xap, qse_wchar_t*), va_arg(xap, qse_wchar_t*), va_arg(xap, qse_wchar_t*) }; + QSE_APP_LOG5 (this->app, QSE_LOG_INFO, QSE_T("[h=%d,R] %ls %ls %ls %ls\n"), h, cmd, x[0], x[1], x[2]); + break; + } + + case 4: + { + qse_wchar_t* x[] = { va_arg(xap, qse_wchar_t*), va_arg(xap, qse_wchar_t*), va_arg(xap, qse_wchar_t*), va_arg(xap, qse_wchar_t*) }; + QSE_APP_LOG6 (this->app, QSE_LOG_INFO, QSE_T("[h=%d,R] %ls %ls %ls %ls %ls\n"), h, cmd, x[0], x[1], x[2], x[3]); + break; + } + + case 5: + { + qse_wchar_t* x[] = { va_arg(xap, qse_wchar_t*), va_arg(xap, qse_wchar_t*), va_arg(xap, qse_wchar_t*), va_arg(xap, qse_wchar_t*), va_arg(xap, qse_wchar_t*) }; + QSE_APP_LOG7 (this->app, QSE_LOG_INFO, QSE_T("[h=%d,R] %ls %ls %ls %ls %ls %ls\n"), h, cmd, x[0], x[1], x[2], x[3], x[4]); + break; + } + + case 6: + { + qse_wchar_t* x[] = { va_arg(xap, qse_wchar_t*), va_arg(xap, qse_wchar_t*), va_arg(xap, qse_wchar_t*), va_arg(xap, qse_wchar_t*), va_arg(xap, qse_wchar_t*), va_arg(xap, qse_wchar_t*) }; + QSE_APP_LOG8 (this->app, QSE_LOG_INFO, QSE_T("[h=%d,R] %ls %ls %ls %ls %ls %ls %ls\n"), h, cmd, x[0], x[1], x[2], x[3], x[4], x[5]); + break; + } + + case 7: + { + qse_wchar_t* x[] = { va_arg(xap, qse_wchar_t*), va_arg(xap, qse_wchar_t*), va_arg(xap, qse_wchar_t*), va_arg(xap, qse_wchar_t*), va_arg(xap, qse_wchar_t*), va_arg(xap, qse_wchar_t*), va_arg(xap, qse_wchar_t*) }; + QSE_APP_LOG9 (this->app, QSE_LOG_INFO, QSE_T("[h=%d,R] %ls %ls %ls %ls %ls %ls %ls %ls\n"), h, cmd, x[0], x[1], x[2], x[3], x[4], x[5], x[6]); + break; + } + + default: + { + qse_wchar_t* x[] = { va_arg(xap, qse_wchar_t*), va_arg(xap, qse_wchar_t*), va_arg(xap, qse_wchar_t*), va_arg(xap, qse_wchar_t*), va_arg(xap, qse_wchar_t*), va_arg(xap, qse_wchar_t*), va_arg(xap, qse_wchar_t*) }; + QSE_APP_LOG9 (this->app, QSE_LOG_INFO, QSE_T("[h=%d,R] %ls %ls %ls %ls %ls %ls %ls %ls %ls ...\n"), h, cmd, x[0], x[1], x[2], x[3], x[4], x[5], x[6]); + break; + } } - return this->sendOkCmd(); + va_end (xap); } - int proc_envget (const QSE::SttpCmd& cmd) - { - PROC_CHECK_ARG_COUNT (cmd, 1); + x = QSE::Sttp::sendCmdV(cmd, nargs, ap); + va_end (ap); + return x; +} + +int TcpGateProto::sendErrCmd (ErrorNumber err) +{ + qse_mchar_t buf[32]; + qse_fmtintmaxtombs(buf, QSE_COUNTOF(buf), err, 10, -1, '\0', QSE_NULL); + QSE::TypesErrorNumberToMbstr x; + return this->sendCmd(CMD_ERR_, 2, buf, x(err)); +} + +int TcpGateProto::sendErrCmd (ErrorNumber err, const qse_mchar_t* msg) +{ + qse_mchar_t buf[32]; + qse_fmtintmaxtombs(buf, QSE_COUNTOF(buf), err, 10, -1, '\0', QSE_NULL); + QSE::TypesErrorNumberToMbstr x; + return this->sendCmd(CMD_ERR_, 2, buf, (msg? msg: x(err))); +} + +int TcpGateProto::sendErrCmd (ErrorNumber err, const qse_wchar_t* msg) +{ + qse_wchar_t buf[32]; + qse_fmtintmaxtowcs(buf, QSE_COUNTOF(buf), err, 10, -1, '\0', QSE_NULL); + QSE::TypesErrorNumberToWcstr x; + return this->sendCmd(QSE_WT(CMD_ERR_), 2, buf, (msg? msg: x(err))); +} + +int TcpGateProto::sendWarnCmd (ErrorNumber err) +{ + qse_mchar_t buf[32]; + qse_fmtintmaxtombs(buf, QSE_COUNTOF(buf), err, 10, -1, '\0', QSE_NULL); + QSE::TypesErrorNumberToMbstr x; + return this->sendCmd(CMD_WARN_, 2, buf, x(err)); +} + +int TcpGateProto::sendWarnCmd (ErrorNumber err, const qse_mchar_t* msg) +{ + qse_mchar_t buf[32]; + qse_fmtintmaxtombs(buf, QSE_COUNTOF(buf), err, 10, -1, '\0', QSE_NULL); + QSE::TypesErrorNumberToMbstr x; + return this->sendCmd(CMD_WARN_, 2, buf, (msg? msg: x(err))); +} + +int TcpGateProto::sendWarnCmd (ErrorNumber err, const qse_wchar_t* msg) +{ + qse_wchar_t buf[32]; + qse_fmtintmaxtowcs(buf, QSE_COUNTOF(buf), err, 10, -1, '\0', QSE_NULL); + QSE::TypesErrorNumberToWcstr x; + return this->sendCmd(QSE_WT(CMD_WARN_), 2, buf, (msg? msg: x(err))); +} + +int TcpGateProto::sendOkCmd () +{ + return this->sendCmd(CMD_OK_, 0); +} +int TcpGateProto::sendOkCmd (const qse_mchar_t* msg1) +{ + return this->sendCmd(CMD_OK_, 1, msg1); +} +int TcpGateProto::sendOkCmd (const qse_mchar_t* msg1, const qse_mchar_t* msg2) +{ + return this->sendCmd(CMD_OK_, 2, msg1, msg2); +} +int TcpGateProto::sendOkCmd (const qse_wchar_t* msg1) +{ + return this->sendCmd(QSE_WT(CMD_OK_), 1, msg1); +} +int TcpGateProto::sendOkCmd (const qse_wchar_t* msg1, const qse_wchar_t* msg2) +{ + return this->sendCmd(QSE_WT(CMD_OK_), 2, msg1, msg2); +} + +int TcpGateProto::handle_command (const QSE::SttpCmd& cmd) +{ + if (QSE_APP_LOG_ENABLED(this->app, QSE_LOG_INFO)) + { + int h = this->sck->getHandle(); + const qse_char_t* name = cmd.name.getData(); + + // ugly - any better way to call QSE_APP_LOGX in a single call? better to store arguments to a buffer first and call QSE_APP_LOGX with it? + switch (cmd.getArgCount()) { - QSE::ScopedMutexLocker sml (this->app->getEnvMutex()); - const qse_char_t* val = this->app->getEnv().getValue(cmd.getArgAt(0)); - if (!val) goto noent; - return this->sendOkCmd(val); - } + case 0: + QSE_APP_LOG2 (this->app, QSE_LOG_INFO, QSE_T("[h=%d,Q] %js\n"), h, name); + break; - noent: - return this->sendErrCmd(E_ENOENT, (const qse_mchar_t*)QSE_NULL); + case 1: + QSE_APP_LOG3 (this->app, QSE_LOG_INFO, QSE_T("[h=%d,Q] %js %js\n"), h, name, cmd.getArgAt(0)); + break; + + case 2: + QSE_APP_LOG4 (this->app, QSE_LOG_INFO, QSE_T("[h=%d,Q] %js %js %js\n"), h, name, cmd.getArgAt(0), cmd.getArgAt(1)); + break; + + case 3: + QSE_APP_LOG5 (this->app, QSE_LOG_INFO, QSE_T("[h=%d,Q] %js %js %js %js\n"), h, name, cmd.getArgAt(0), cmd.getArgAt(1), cmd.getArgAt(2)); + break; + + case 4: + QSE_APP_LOG6 (this->app, QSE_LOG_INFO, QSE_T("[h=%d,Q] %js %js %js %js %js\n"), h, name, cmd.getArgAt(0), cmd.getArgAt(1), cmd.getArgAt(2), cmd.getArgAt(3)); + break; + + case 5: + QSE_APP_LOG7 (this->app, QSE_LOG_INFO, QSE_T("[h=%d,Q] %js %js %js %js %js %js\n"), h, name, cmd.getArgAt(0), cmd.getArgAt(1), cmd.getArgAt(2), cmd.getArgAt(3), cmd.getArgAt(4)); + break; + + case 6: + QSE_APP_LOG8 (this->app, QSE_LOG_INFO, QSE_T("[h=%d,Q] %js %js %js %js %js %js %js\n"), h, name, cmd.getArgAt(0), cmd.getArgAt(1), cmd.getArgAt(2), cmd.getArgAt(3), cmd.getArgAt(4), cmd.getArgAt(5)); + break; + + case 7: + QSE_APP_LOG9 (this->app, QSE_LOG_INFO, QSE_T("[h=%d,Q] %js %js %js %js %js %js %js %js\n"), h, name, cmd.getArgAt(0), cmd.getArgAt(1), cmd.getArgAt(2), cmd.getArgAt(3), cmd.getArgAt(4), cmd.getArgAt(5), cmd.getArgAt(6)); + break; + + default: + QSE_APP_LOG9 (this->app, QSE_LOG_INFO, QSE_T("[h=%d,Q] %js %js %js %js %js %js %js %js ...\n"), h, name, cmd.getArgAt(0), cmd.getArgAt(1), cmd.getArgAt(2), cmd.getArgAt(3), cmd.getArgAt(4), cmd.getArgAt(5), cmd.getArgAt(6)); + break; + } } - int proc_envset (const QSE::SttpCmd& cmd) + CmdDict::Pair* pair = this->cmd_dict.search(cmd.name); + if (!pair) return this->sendErrCmd(E_ENOENT, MSG_UNKNOWN_COMMAND_); + + return (this->*(pair->value))(cmd); +} + +int TcpGateProto::write_bytes (const qse_uint8_t* data, qse_size_t len) +{ + int n = this->sck->sendx(data, len, QSE_NULL); + if (QSE_UNLIKELY(n <= -1)) this->setErrorFmt(E_ESYSERR, QSE_T("%js"), sck->getErrorMsg()); + return n; +} + +int TcpGateProto::proc_discon (const QSE::SttpCmd& cmd) +{ + PROC_CHECK_ARG_COUNT (cmd, 0); + + this->sendOkCmd (); // success and failure doesn't matter + sck->shutdown (); + return 0; +} + +int TcpGateProto::proc_shtdwn (const QSE::SttpCmd& cmd) +{ + PROC_CHECK_ARG_COUNT_RANGE(cmd, 0, 1); + int ret = 0; + + if (cmd.getArgCount() >= 1) ret = qse_strtoi(cmd.getArgAt(0), 0, QSE_NULL); + + this->sendOkCmd (); // success and failure doesn't matter + this->app->stop (ret); + return 0; +} + +int TcpGateProto::proc_envlst (const QSE::SttpCmd& cmd) +{ + PROC_CHECK_ARG_COUNT (cmd, 0); + { - PROC_CHECK_ARG_COUNT (cmd, 2); - - const qse_char_t* name = cmd.getArgAt(0); - const qse_char_t* val = cmd.getArgAt(1); - - // TODO: session acl? - //if (!this->_login.isRootUser()) return this->sendErrCmd (ERR_EPERM); - - MainApp::Env& env = this->app->getEnv(); - QSE::ScopedMutexLocker sml (this->app->getEnvMutex()); - if (this->app->getEnv().setValue(name, val) <= -1) + const MainApp::Env::ItemList& item_list = this->app->getEnv().getItemList(); + for (const MainApp::Env::ItemList::Node* np = item_list.getHeadNode(); np; np = np->getNextNode()) { - return this->sendErrCmd(E_EOTHER, "unable to set value"); - } - - const qse_char_t* v = env.getValue(name); - QSE_ASSERT (v != QSE_NULL); - - if (env.store(this->app->getConfFile().getData()) <= -1) // TODO: full path - { - if (this->sendWarnCmd(E_EOTHER, "unable to store") <= -1) return -1; - } - - return this->sendOkCmd(v); + const MainApp::Env::Item& item = np->value; + const qse_char_t* val = this->app->getEnv().getValue(item.name); + QSE_ASSERT (val != QSE_NULL); + if (this->sendCmd(QSE_T(CMD_ENVITM_), 2, item.name, val) <= -1) return -1; + } } -}; + return this->sendOkCmd(); +} +int TcpGateProto::proc_envget (const QSE::SttpCmd& cmd) +{ + PROC_CHECK_ARG_COUNT (cmd, 1); + + { + QSE::ScopedMutexLocker sml (this->app->getEnvMutex()); + const qse_char_t* val = this->app->getEnv().getValue(cmd.getArgAt(0)); + if (!val) goto noent; + return this->sendOkCmd(val); + } + +noent: + return this->sendErrCmd(E_ENOENT); +} + +int TcpGateProto::proc_envset (const QSE::SttpCmd& cmd) +{ + PROC_CHECK_ARG_COUNT (cmd, 2); + + const qse_char_t* name = cmd.getArgAt(0); + const qse_char_t* val = cmd.getArgAt(1); + + // TODO: session acl? + //if (!this->_login.isRootUser()) return this->sendErrCmd (ERR_EPERM); + + MainApp::Env& env = this->app->getEnv(); + + QSE::ScopedMutexLocker sml (this->app->getEnvMutex()); + if (this->app->getEnv().setValue(name, val) <= -1) + { + return this->sendErrCmd(E_EOTHER, MSG_UNABLE_TO_SET_VALUE_); + } + + const qse_char_t* v = env.getValue(name); + QSE_ASSERT (v != QSE_NULL); + + if (this->opt_autosave && env.store(this->app->getConfFile().getData()) <= -1) // TODO: full path + { + if (this->sendWarnCmd(E_EOTHER, MSG_UNABLE_TO_STORE_) <= -1) return -1; + } + + return this->sendOkCmd(v); +} + +int TcpGateProto::proc_envsav (const QSE::SttpCmd& cmd) +{ + PROC_CHECK_ARG_COUNT (cmd, 0); + + // TODO: session acl? + //if (!this->_login.isRootUser()) return this->sendErrCmd (ERR_EPERM); + + MainApp::Env& env = this->app->getEnv(); + + QSE::ScopedMutexLocker sml (this->app->getEnvMutex()); + if (env.store(this->app->getConfFile().getData()) <= -1) + { + return this->sendWarnCmd(E_EOTHER, MSG_UNABLE_TO_STORE_); + } + + return this->sendOkCmd(); +} + +int TcpGateProto::proc_optget (const QSE::SttpCmd& cmd) +{ + PROC_CHECK_ARG_COUNT (cmd, 1); + + const qse_char_t* k = cmd.getArgAt(0); + + if (qse_strcasecmp(k, QSE_T("AUTOSAVE")) == 0) + { + qse_mchar_t tmp[32]; + qse_mbsxfmt(tmp, QSE_COUNTOF(tmp), "%d", this->opt_autosave); + return this->sendOkCmd(tmp); + } + + return this->sendErrCmd(E_EINVAL); +} + +int TcpGateProto::proc_optset (const QSE::SttpCmd& cmd) +{ + PROC_CHECK_ARG_COUNT (cmd, 2); + + const qse_char_t* k = cmd.getArgAt(0); + const qse_char_t* v = cmd.getArgAt(1); + + if (qse_strcasecmp(k, QSE_T("AUTOSAVE")) == 0) + { + this->opt_autosave = qse_strtoi(v, 10, QSE_NULL); + } + else + { + return this->sendErrCmd(E_EINVAL); + } + + return this->sendOkCmd(); +} // -------------------------------------------------------------------------- @@ -451,7 +513,7 @@ int TcpGate::handle_connection (Connection* connection) connection->address.toStrBuf(addrbuf, QSE_COUNTOF(addrbuf)); - Proto proto (this->app, &connection->socket); + TcpGateProto proto(this->app, &connection->socket); while (!this->isHaltRequested()) { diff --git a/qse/samples/app/TcpGate.hpp b/qse/samples/app/TcpGate.hpp index 3ff40d5f..c14b903d 100644 --- a/qse/samples/app/TcpGate.hpp +++ b/qse/samples/app/TcpGate.hpp @@ -3,9 +3,54 @@ #include #include +#include +#include class MainApp; +class TcpGateProto: public QSE::Sttp +{ +public: + typedef int (TcpGateProto::*CmdProc) (const QSE::SttpCmd& cmd); + + TcpGateProto (MainApp* app, QSE::Socket* sck); + + int sendCmd (const qse_mchar_t* cmd, qse_size_t nargs, ...); + int sendCmd (const qse_wchar_t* cmd, qse_size_t nargs, ...); + int sendErrCmd (ErrorNumber err); + int sendErrCmd (ErrorNumber err, const qse_mchar_t* msg); + int sendErrCmd (ErrorNumber err, const qse_wchar_t* msg); + int sendWarnCmd (ErrorNumber err); + int sendWarnCmd (ErrorNumber err, const qse_mchar_t* msg); + int sendWarnCmd (ErrorNumber err, const qse_wchar_t* msg); + int sendOkCmd (); + int sendOkCmd (const qse_mchar_t* msg1); + int sendOkCmd (const qse_mchar_t* msg1, const qse_mchar_t* msg2); + int sendOkCmd (const qse_wchar_t* msg1); + int sendOkCmd (const qse_wchar_t* msg1, const qse_wchar_t* msg2); + +protected: + MainApp* app; + QSE::Socket* sck; + + typedef QSE::HashTable CmdDict; + CmdDict cmd_dict; + + int opt_autosave; + + int handle_command (const QSE::SttpCmd& cmd); + int write_bytes (const qse_uint8_t* data, qse_size_t len); + + int proc_discon (const QSE::SttpCmd& cmd); + int proc_shtdwn (const QSE::SttpCmd& cmd); + int proc_envlst (const QSE::SttpCmd& cmd); + int proc_envget (const QSE::SttpCmd& cmd); + int proc_envset (const QSE::SttpCmd& cmd); + int proc_envsav (const QSE::SttpCmd& cmd); + int proc_optget (const QSE::SttpCmd& cmd); + int proc_optset (const QSE::SttpCmd& cmd); +}; + class TcpGate: public QSE::TcpServer, public QSE::Thread { public: