From e9de6513ebd91336505a4fd053c54acca804a6cc Mon Sep 17 00:00:00 2001 From: Apex Liu Date: Wed, 1 Jun 2022 11:25:49 +0800 Subject: [PATCH] =?UTF-8?q?1.=20=E5=8E=BB=E6=8E=89=E5=9C=A8rdp=E7=9A=84sid?= =?UTF-8?q?=E5=89=8D=E5=A1=AB=E5=86=99=E7=9A=84=E4=B8=A4=E4=B8=AA=E5=AD=97?= =?UTF-8?q?=E8=8A=82=EF=BC=9B2.=20=E6=A0=BC=E5=BC=8F=E5=8C=96=E9=83=A8?= =?UTF-8?q?=E5=88=86=E4=BB=A3=E7=A0=81=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build/builder/build-external.py | 5 +- client/tp_assist_macos/src/csrc/ts_cfg.cpp | 136 ++--- client/tp_assist_macos/src/csrc/ts_cfg.h | 22 +- client/tp_assist_macos/src/csrc/ts_env.cpp | 26 +- client/tp_assist_macos/src/csrc/ts_env.h | 31 +- .../tp_assist_macos/src/csrc/ts_http_rpc.cpp | 470 +++++++++-------- client/tp_assist_macos/src/csrc/ts_http_rpc.h | 85 +-- .../tp_assist_macos/src/csrc/ts_ws_client.cpp | 489 +++++++++--------- .../tp_assist_macos/src/csrc/ts_ws_client.h | 6 +- server/tp_core/core/ts_session.cpp | 6 +- .../www/teleport/static/js/ops/remote-list.js | 8 +- 11 files changed, 675 insertions(+), 609 deletions(-) diff --git a/build/builder/build-external.py b/build/builder/build-external.py index 6e413ea..abf9287 100644 --- a/build/builder/build-external.py +++ b/build/builder/build-external.py @@ -692,8 +692,8 @@ class BuilderMacOS(BuilderBase): cc.w('already exists, skip.') def _build_openssl(self, file_name): - cc.w('skip build openssl again.') - return + # cc.w('skip build openssl again.') + # return if not self._download_openssl(file_name): return @@ -943,6 +943,7 @@ def main(): builder.build_jsoncpp() builder.build_mongoose() builder.build_zlib() + builder.build_mbedtls() builder.build_openssl() elif command == 'ext-server': builder.prepare_python() diff --git a/client/tp_assist_macos/src/csrc/ts_cfg.cpp b/client/tp_assist_macos/src/csrc/ts_cfg.cpp index 8b604d9..0ebd320 100644 --- a/client/tp_assist_macos/src/csrc/ts_cfg.cpp +++ b/client/tp_assist_macos/src/csrc/ts_cfg.cpp @@ -3,44 +3,47 @@ TsCfg g_cfg; -TsCfg::TsCfg() -{} +TsCfg::TsCfg() {} -TsCfg::~TsCfg() -{} +TsCfg::~TsCfg() {} -bool TsCfg::init(void) { - ex_astr file_content; - if(!ex_read_text_file(g_env.m_cfg_file, file_content)) { - EXLOGE("can not load config file.\n"); - return false; - } - - if(!_load(file_content)) - return false; +bool TsCfg::init(void) +{ + ex_astr file_content; + if (!ex_read_text_file(g_env.m_cfg_file, file_content)) + { + EXLOGE("can not load config file.\n"); + return false; + } - if(!m_root.isObject()) { + if (!_load(file_content)) + return false; + + if (!m_root.isObject()) + { EXLOGE("invalid config file, not in json format?\n"); return false; } - - if(m_root["file_version"].isNull()) { + + if (m_root["file_version"].isNull()) + { EXLOGE("invalid config file, maybe need create new one?\n"); return false; } - - if(!m_root["file_version"].isInt()) { - + + if (!m_root["file_version"].isInt()) + { + } - - return true; + + return true; } bool TsCfg::save(const ex_astr& new_value) { - if(!_load(new_value)) - return false; - + if (!_load(new_value)) + return false; + Json::StreamWriterBuilder jwb; jwb["indentation"] = " "; jwb["emitUTF8"] = true; @@ -49,67 +52,78 @@ bool TsCfg::save(const ex_astr& new_value) jwriter->write(m_root, &os); ex_astr val = os.str(); - if(!ex_write_text_file(g_env.m_cfg_file, val)) { - EXLOGE("can not save config file.\n"); - return false; - } + if (!ex_write_text_file(g_env.m_cfg_file, val)) + { + EXLOGE("can not save config file.\n"); + return false; + } - return true; + return true; } -bool TsCfg::_parse_app(const Json::Value& m_root, const ex_astr& str_app, APP_CONFIG& cfg) { +bool TsCfg::_parse_app(const Json::Value& m_root, const ex_astr& str_app, APP_CONFIG& cfg) +{ const Json::Value& jApp = m_root[str_app.c_str()]; - if(!jApp.isObject()) + if (!jApp.isObject()) return false; - - if (!jApp["selected"].isString()) { + + if (!jApp["selected"].isString()) + { EXLOGE("invalid config, error 2.\n"); return false; } ex_astr _selected = jApp["selected"].asCString();; - if (!jApp["available"].isArray() || jApp["available"].size() == 0) { + if (!jApp["available"].isArray() || jApp["available"].size() == 0) + { EXLOGE("invalid config, error 3.\n"); return false; } const Json::Value& jAppList = jApp["available"]; int i = 0; - for (i = 0; i < jAppList.size(); ++i) { + for (i = 0; i < jAppList.size(); ++i) + { if ( - !jAppList[i]["name"].isString() - || !jAppList[i]["app"].isString() - || !jAppList[i]["cmdline"].isString() - || !jAppList[i]["desc"].isArray() - ) { + !jAppList[i]["name"].isString() + || !jAppList[i]["app"].isString() + || !jAppList[i]["cmdline"].isString() + || !jAppList[i]["desc"].isArray() + ) + { EXLOGE("invalid config, error 4.\n"); return false; } - - if(jAppList[i]["name"].asString().empty()) { + + if (jAppList[i]["name"].asString().empty()) + { EXLOGE("invalid config, need name.\n"); return false; } - if (jAppList[i]["display"].isNull() || jAppList[i]["display"].asString().empty()) { + if (jAppList[i]["display"].isNull() || jAppList[i]["display"].asString().empty()) + { cfg.display = jAppList[i]["name"].asCString(); - } else + } + else cfg.display = jAppList[i]["display"].asCString(); if (jAppList[i]["name"].asCString() != _selected) continue; - + cfg.name = jAppList[i]["name"].asCString(); cfg.display = jAppList[i]["display"].asCString(); cfg.application = jAppList[i]["app"].asCString(); cfg.cmdline = jAppList[i]["cmdline"].asCString(); - if(jAppList[i]["desc"].size() > 0) { + if (jAppList[i]["desc"].size() > 0) + { const Json::Value& jAppDescList = jAppList[i]["desc"]; - + int j = 0; - for(j = 0; j < jAppDescList.size(); ++j) { - if(!jAppDescList[j].isString()) + for (j = 0; j < jAppDescList.size(); ++j) + { + if (!jAppDescList[j].isString()) return false; cfg.description.push_back(jAppDescList[j].asCString()); } @@ -122,28 +136,30 @@ bool TsCfg::_parse_app(const Json::Value& m_root, const ex_astr& str_app, APP_CO } -bool TsCfg::_load(const ex_astr& str_json) { +bool TsCfg::_load(const ex_astr& str_json) +{ Json::CharReaderBuilder jcrb; std::unique_ptr const jreader(jcrb.newCharReader()); - const char *str_json_begin = str_json.c_str(); + const char* str_json_begin = str_json.c_str(); ex_astr err; - if (!jreader->parse(str_json_begin, str_json_begin + str_json.length(), &m_root, &err)) { + if (!jreader->parse(str_json_begin, str_json_begin + str_json.length(), &m_root, &err)) + { EXLOGE("can not parse new config data, not in json format? %s\n", err.c_str()); return false; } - //=================================== - // check config - //=================================== - if(!_parse_app(m_root, "ssh", ssh)) + //=================================== + // check config + //=================================== + if (!_parse_app(m_root, "ssh", ssh)) return false; - if(!_parse_app(m_root, "sftp", sftp)) + if (!_parse_app(m_root, "sftp", sftp)) return false; - if(!_parse_app(m_root, "telnet", telnet)) + if (!_parse_app(m_root, "telnet", telnet)) return false; - if(!_parse_app(m_root, "rdp", rdp)) + if (!_parse_app(m_root, "rdp", rdp)) return false; - return true; + return true; } diff --git a/client/tp_assist_macos/src/csrc/ts_cfg.h b/client/tp_assist_macos/src/csrc/ts_cfg.h index 97b9033..8d9d836 100644 --- a/client/tp_assist_macos/src/csrc/ts_cfg.h +++ b/client/tp_assist_macos/src/csrc/ts_cfg.h @@ -6,36 +6,40 @@ #include -typedef struct APP_CONFIG { +typedef struct APP_CONFIG +{ ex_astr name; ex_astr display; ex_astr application; ex_astr cmdline; ex_astrs description; -}APP_CONFIG; +} APP_CONFIG; class TsCfg { public: - TsCfg(); - virtual ~TsCfg(); + TsCfg(); + + virtual ~TsCfg(); + + bool init(void); - bool init(void); bool save(const ex_astr& new_value); - Json::Value& get_root() {return m_root;} - + Json::Value& get_root() { return m_root; } + APP_CONFIG ssh; APP_CONFIG sftp; APP_CONFIG telnet; APP_CONFIG rdp; protected: - bool _load(const ex_astr& str_json); + bool _load(const ex_astr& str_json); + bool _parse_app(const Json::Value& m_root, const ex_astr& str_app, APP_CONFIG& cfg); protected: - Json::Value m_root; + Json::Value m_root; }; extern TsCfg g_cfg; diff --git a/client/tp_assist_macos/src/csrc/ts_env.cpp b/client/tp_assist_macos/src/csrc/ts_env.cpp index 9bac173..47564a2 100644 --- a/client/tp_assist_macos/src/csrc/ts_env.cpp +++ b/client/tp_assist_macos/src/csrc/ts_env.cpp @@ -1,6 +1,7 @@ #include "ts_env.h" #include + #ifdef EX_OS_WIN32 # include //# include @@ -12,34 +13,33 @@ TsEnv g_env; // //======================================================= -TsEnv::TsEnv() -{} +TsEnv::TsEnv() {} -TsEnv::~TsEnv() -{} +TsEnv::~TsEnv() {} bool TsEnv::init(const char* bundle_path, const char* cfg_file, const char* res_path, const char* log_path) { ex_astr2wstr(bundle_path, m_bundle_path); ex_astr2wstr(cfg_file, m_cfg_file); - ex_astr2wstr(res_path, m_res_path); + ex_astr2wstr(res_path, m_res_path); ex_astr2wstr(log_path, m_log_path); #ifdef EX_DEBUG m_site_path = L"/Users/apex/work/tp4a/teleport/client/tp_assist_macos/site"; //m_bundle_path = L"/Users/apex/work/tp4a/teleport/out/client/x64/release"; #else - m_site_path = m_res_path; - ex_path_join(m_site_path, false, L"site", NULL); + m_site_path = m_res_path; + ex_path_join(m_site_path, false, L"site", NULL); #endif - - return true; + + return true; } extern "C" { -int mg_ssl_if_mbed_random(void *ctx, unsigned char *buf, size_t len) { - (void) ctx; - while (len--) *buf++ = (arc4random() % 255); - return 0; +int mg_ssl_if_mbed_random(void* ctx, unsigned char* buf, size_t len) +{ + (void)ctx; + while (len--) { *buf++ = (arc4random() % 255); } + return 0; } } diff --git a/client/tp_assist_macos/src/csrc/ts_env.h b/client/tp_assist_macos/src/csrc/ts_env.h index 5ab95e0..d82234e 100644 --- a/client/tp_assist_macos/src/csrc/ts_env.h +++ b/client/tp_assist_macos/src/csrc/ts_env.h @@ -6,25 +6,26 @@ class TsEnv { public: - TsEnv(); - ~TsEnv(); + TsEnv(); - bool init(const char* bundle_path, const char* cfg_file, const char* res_path, const char* log_path); + ~TsEnv(); + + bool init(const char* bundle_path, const char* cfg_file, const char* res_path, const char* log_path); public: ex_wstr m_bundle_path; - ex_wstr m_cfg_file; - ex_wstr m_res_path; - -// ex_wstr m_exec_file; -// ex_wstr m_exec_path; -// -// ex_wstr m_ssh_client_conf_file; -// ex_wstr m_scp_client_conf_file; -// ex_wstr m_telnet_client_conf_file; - ex_wstr m_log_path; - ex_wstr m_site_path; -// ex_wstr m_tools_path; + ex_wstr m_cfg_file; + ex_wstr m_res_path; + + // ex_wstr m_exec_file; + // ex_wstr m_exec_path; + // + // ex_wstr m_ssh_client_conf_file; + // ex_wstr m_scp_client_conf_file; + // ex_wstr m_telnet_client_conf_file; + ex_wstr m_log_path; + ex_wstr m_site_path; + // ex_wstr m_tools_path; }; extern TsEnv g_env; diff --git a/client/tp_assist_macos/src/csrc/ts_http_rpc.cpp b/client/tp_assist_macos/src/csrc/ts_http_rpc.cpp index dcd3fc3..3143fcc 100644 --- a/client/tp_assist_macos/src/csrc/ts_http_rpc.cpp +++ b/client/tp_assist_macos/src/csrc/ts_http_rpc.cpp @@ -17,23 +17,26 @@ TsHttpRpc g_http_interface; TsHttpRpc::TsHttpRpc() : ExThreadBase("http-rpc-thread") { - mg_mgr_init(&m_mg_mgr, NULL); + mg_mgr_init(&m_mg_mgr, NULL); } TsHttpRpc::~TsHttpRpc() { - mg_mgr_free(&m_mg_mgr); + mg_mgr_free(&m_mg_mgr); } -bool TsHttpRpc::init() { +bool TsHttpRpc::init() +{ struct mg_connection* nc = NULL; - for(int port = TS_HTTP_RPC_PORT_MIN; port < TS_HTTP_RPC_PORT_MAX; ++port) { - char addr[128] = { 0 }; + for (int port = TS_HTTP_RPC_PORT_MIN; port < TS_HTTP_RPC_PORT_MAX; ++port) + { + char addr[128] = {0}; ex_strformat(addr, 128, "tcp://127.0.0.1:%d", port); nc = mg_bind(&m_mg_mgr, addr, _mg_event_handler); - if (!nc) { + if (!nc) + { EXLOGW("[WRN] can not start HTTP-RPC listener, maybe port %d is already in use.\n", port); continue; } @@ -41,8 +44,9 @@ bool TsHttpRpc::init() { m_port = port; break; } - - if(m_port == 0) { + + if (m_port == 0) + { EXLOGE("[rpc] can not listen on port %d~%d\n", TS_HTTP_RPC_PORT_MIN, TS_HTTP_RPC_PORT_MAX); return false; } @@ -54,7 +58,8 @@ bool TsHttpRpc::init() { return _on_init(); } -bool TsHttpRpc::_on_init() { +bool TsHttpRpc::_on_init() +{ m_content_type_map[".js"] = "application/javascript"; m_content_type_map[".png"] = "image/png"; m_content_type_map[".jpeg"] = "image/jpeg"; @@ -73,258 +78,262 @@ bool TsHttpRpc::_on_init() { void TsHttpRpc::_thread_loop(void) { - while (!m_need_stop) - { - mg_mgr_poll(&m_mg_mgr, 500); - } + while (!m_need_stop) + { + mg_mgr_poll(&m_mg_mgr, 500); + } - EXLOGV("[core] rpc main loop end.\n"); + EXLOGV("[core] rpc main loop end.\n"); } -void TsHttpRpc::_mg_event_handler(struct mg_connection *nc, int ev, void *ev_data) +void TsHttpRpc::_mg_event_handler(struct mg_connection* nc, int ev, void* ev_data) { - struct http_message *hm = (struct http_message*)ev_data; + struct http_message* hm = (struct http_message*)ev_data; - TsHttpRpc* _this = (TsHttpRpc*)nc->user_data; - if (NULL == _this) - { - EXLOGE("[ERROR] invalid http request.\n"); - return; - } + TsHttpRpc* _this = (TsHttpRpc*)nc->user_data; + if (NULL == _this) + { + EXLOGE("[ERROR] invalid http request.\n"); + return; + } - switch (ev) - { - case MG_EV_HTTP_REQUEST: - { - ex_astr uri; - ex_chars _uri; - _uri.resize(hm->uri.len + 1); - memset(&_uri[0], 0, hm->uri.len + 1); - memcpy(&_uri[0], hm->uri.p, hm->uri.len); - uri = &_uri[0]; + switch (ev) + { + case MG_EV_HTTP_REQUEST: + { + ex_astr uri; + ex_chars _uri; + _uri.resize(hm->uri.len + 1); + memset(&_uri[0], 0, hm->uri.len + 1); + memcpy(&_uri[0], hm->uri.p, hm->uri.len); + uri = &_uri[0]; #ifdef EX_DEBUG - const char* dbg_method = NULL; - if (hm->method.len == 3 && 0 == memcmp(hm->method.p, "GET", hm->method.len)) - dbg_method = "GET"; - else if (hm->method.len == 4 && 0 == memcmp(hm->method.p, "POST", hm->method.len)) - dbg_method = "POST"; - else - dbg_method = "UNSUPPORTED-HTTP-METHOD"; + const char* dbg_method = NULL; + if (hm->method.len == 3 && 0 == memcmp(hm->method.p, "GET", hm->method.len)) + dbg_method = "GET"; + else if (hm->method.len == 4 && 0 == memcmp(hm->method.p, "POST", hm->method.len)) + dbg_method = "POST"; + else + dbg_method = "UNSUPPORTED-HTTP-METHOD"; - EXLOGV("[rpc] got %s request: %s\n", dbg_method, uri.c_str()); + EXLOGV("[rpc] got %s request: %s\n", dbg_method, uri.c_str()); #endif - ex_astr ret_buf; + ex_astr ret_buf; bool b_is_html = false; - if (uri == "/") { + if (uri == "/") + { uri = "/status.html"; b_is_html = true; } - else if (uri == "/config") { + else if (uri == "/config") + { uri = "/index.html"; b_is_html = true; } - ex_astr temp; - size_t offset = uri.find("/", 1); - if (offset > 0) - { - temp = uri.substr(1, offset-1); + ex_astr temp; + size_t offset = uri.find("/", 1); + if (offset > 0) + { + temp = uri.substr(1, offset - 1); - if(temp == "api") { - ex_astr method; - ex_astr json_param; - int rv = _this->_parse_request(hm, method, json_param); - if (0 != rv) - { - EXLOGE("[ERROR] http-rpc got invalid request.\n"); - _this->_create_json_ret(ret_buf, rv); - } - else - { - _this->_process_js_request(method, json_param, ret_buf); - } + if (temp == "api") + { + ex_astr method; + ex_astr json_param; + int rv = _this->_parse_request(hm, method, json_param); + if (0 != rv) + { + EXLOGE("[ERROR] http-rpc got invalid request.\n"); + _this->_create_json_ret(ret_buf, rv); + } + else + { + _this->_process_js_request(method, json_param, ret_buf); + } - mg_printf(nc, "HTTP/1.0 200 OK\r\nAccess-Control-Allow-Origin: *\r\nContent-Length: %ld\r\nContent-Type: application/json\r\n\r\n%s", ret_buf.length(), ret_buf.c_str()); - nc->flags |= MG_F_SEND_AND_CLOSE; - return; - } - } + mg_printf(nc, "HTTP/1.0 200 OK\r\nAccess-Control-Allow-Origin: *\r\nContent-Length: %ld\r\nContent-Type: application/json\r\n\r\n%s", ret_buf.length(), ret_buf.c_str()); + nc->flags |= MG_F_SEND_AND_CLOSE; + return; + } + } - ex_astr file_suffix; - offset = uri.rfind("."); - if (offset > 0) - { - file_suffix = uri.substr(offset, uri.length()); - } + ex_astr file_suffix; + offset = uri.rfind("."); + if (offset > 0) + { + file_suffix = uri.substr(offset, uri.length()); + } - ex_wstr2astr(g_env.m_site_path, temp); - ex_astr index_path = temp + uri; + ex_wstr2astr(g_env.m_site_path, temp); + ex_astr index_path = temp + uri; - FILE* file = ex_fopen(index_path.c_str(), "rb"); - if (file) - { - unsigned long file_size = 0; - char* buf = 0; - size_t ret = 0; + FILE* file = ex_fopen(index_path.c_str(), "rb"); + if (file) + { + unsigned long file_size = 0; + char* buf = 0; + size_t ret = 0; - fseek(file, 0, SEEK_END); - file_size = ftell(file); - buf = new char[file_size]; - memset(buf, 0, file_size); - fseek(file, 0, SEEK_SET); - ret = fread(buf, 1, file_size, file); - fclose(file); + fseek(file, 0, SEEK_END); + file_size = ftell(file); + buf = new char[file_size]; + memset(buf, 0, file_size); + fseek(file, 0, SEEK_SET); + ret = fread(buf, 1, file_size, file); + fclose(file); - ex_astr content_type = _this->get_content_type(file_suffix); + ex_astr content_type = _this->get_content_type(file_suffix); - mg_printf(nc, "HTTP/1.0 200 OK\r\nAccess-Control-Allow-Origin: *\r\nContent-Length: %ld\r\nContent-Type: %s\r\n\r\n", file_size, content_type.c_str()); - mg_send(nc, buf, (int)file_size); - delete []buf; - nc->flags |= MG_F_SEND_AND_CLOSE; - return; - } else if (b_is_html) { - ex_wstr page = L"404 Not Found

404 Not Found


Teleport Assistor configuration page not found.

"; - ex_wstr2astr(page, ret_buf, EX_CODEPAGE_UTF8); + mg_printf(nc, "HTTP/1.0 200 OK\r\nAccess-Control-Allow-Origin: *\r\nContent-Length: %ld\r\nContent-Type: %s\r\n\r\n", file_size, content_type.c_str()); + mg_send(nc, buf, (int)file_size); + delete[]buf; + nc->flags |= MG_F_SEND_AND_CLOSE; + return; + } + else if (b_is_html) + { + ex_wstr page = L"404 Not Found

404 Not Found


Teleport Assistor configuration page not found.

"; + ex_wstr2astr(page, ret_buf, EX_CODEPAGE_UTF8); - mg_printf(nc, "HTTP/1.0 404 File Not Found\r\nAccess-Control-Allow-Origin: *\r\nContent-Length: %ld\r\nContent-Type: text/html\r\n\r\n%s", ret_buf.length(), ret_buf.c_str()); - nc->flags |= MG_F_SEND_AND_CLOSE; - return; - } + mg_printf(nc, "HTTP/1.0 404 File Not Found\r\nAccess-Control-Allow-Origin: *\r\nContent-Length: %ld\r\nContent-Type: text/html\r\n\r\n%s", ret_buf.length(), ret_buf.c_str()); + nc->flags |= MG_F_SEND_AND_CLOSE; + return; + } - } - break; - default: - break; - } + } + break; + default: break; + } } int TsHttpRpc::_parse_request(struct http_message* req, ex_astr& func_cmd, ex_astr& func_args) { - if (NULL == req) - return TPE_FAILED; + if (NULL == req) + return TPE_FAILED; - bool is_get = true; - if (req->method.len == 3 && 0 == memcmp(req->method.p, "GET", req->method.len)) - is_get = true; - else if (req->method.len == 4 && 0 == memcmp(req->method.p, "POST", req->method.len)) - is_get = false; - else - return TPE_HTTP_METHOD; + bool is_get = true; + if (req->method.len == 3 && 0 == memcmp(req->method.p, "GET", req->method.len)) + is_get = true; + else if (req->method.len == 4 && 0 == memcmp(req->method.p, "POST", req->method.len)) + is_get = false; + else + return TPE_HTTP_METHOD; - ex_astrs strs; + ex_astrs strs; - size_t pos_start = 1; // skip first charactor, it must be '/' + size_t pos_start = 1; // skip first charactor, it must be '/' - size_t i = 0; - for (i = pos_start; i < req->uri.len; ++i) - { - if (req->uri.p[i] == '/') - { - if (i - pos_start > 0) - { - ex_astr tmp_uri; - tmp_uri.assign(req->uri.p + pos_start, i - pos_start); - strs.push_back(tmp_uri); - } - pos_start = i + 1; // skip current split chactor. - } - } - if (pos_start < req->uri.len) - { - ex_astr tmp_uri; - tmp_uri.assign(req->uri.p + pos_start, req->uri.len - pos_start); - strs.push_back(tmp_uri); - } + size_t i = 0; + for (i = pos_start; i < req->uri.len; ++i) + { + if (req->uri.p[i] == '/') + { + if (i - pos_start > 0) + { + ex_astr tmp_uri; + tmp_uri.assign(req->uri.p + pos_start, i - pos_start); + strs.push_back(tmp_uri); + } + pos_start = i + 1; // skip current split chactor. + } + } + if (pos_start < req->uri.len) + { + ex_astr tmp_uri; + tmp_uri.assign(req->uri.p + pos_start, req->uri.len - pos_start); + strs.push_back(tmp_uri); + } - if (0 == strs.size() || strs[0] != "api") - return TPE_PARAM; + if (0 == strs.size() || strs[0] != "api") + return TPE_PARAM; - if (is_get) - { - if (2 == strs.size()) - { - func_cmd = strs[1]; - } - else if (3 == strs.size()) - { - func_cmd = strs[1]; - func_args = strs[2]; - } - else - { - return TPE_PARAM; - } - } - else - { - if (2 == strs.size()) - { - func_cmd = strs[1]; - } - else - { - return TPE_PARAM; - } + if (is_get) + { + if (2 == strs.size()) + { + func_cmd = strs[1]; + } + else if (3 == strs.size()) + { + func_cmd = strs[1]; + func_args = strs[2]; + } + else + { + return TPE_PARAM; + } + } + else + { + if (2 == strs.size()) + { + func_cmd = strs[1]; + } + else + { + return TPE_PARAM; + } - if (req->body.len > 0) - { - func_args.assign(req->body.p, req->body.len); - } - } + if (req->body.len > 0) + { + func_args.assign(req->body.p, req->body.len); + } + } - if (func_args.length() > 0) - { - // decode param with url-decode. - size_t len = func_args.length() * 2; - ex_chars sztmp; - sztmp.resize(len); - memset(&sztmp[0], 0, len); - if (-1 == ex_url_decode(func_args.c_str(), (int)func_args.length(), &sztmp[0], (int)len, 0)) - return TPE_HTTP_URL_ENCODE; + if (func_args.length() > 0) + { + // decode param with url-decode. + size_t len = func_args.length() * 2; + ex_chars sztmp; + sztmp.resize(len); + memset(&sztmp[0], 0, len); + if (-1 == ex_url_decode(func_args.c_str(), (int)func_args.length(), &sztmp[0], (int)len, 0)) + return TPE_HTTP_URL_ENCODE; - func_args = &sztmp[0]; - } + func_args = &sztmp[0]; + } - EXLOGV("[rpc] method=%s, json_param=%s\n", func_cmd.c_str(), func_args.c_str()); + EXLOGV("[rpc] method=%s, json_param=%s\n", func_cmd.c_str(), func_args.c_str()); - return TPE_OK; + return TPE_OK; } void TsHttpRpc::_process_js_request(const ex_astr& func_cmd, const ex_astr& func_args, ex_astr& buf) { - if (func_cmd == "get_version") - { - _rpc_func_get_version(func_args, buf); - } - else if (func_cmd == "get_config") - { - _rpc_func_get_config(func_args, buf); - } - else if (func_cmd == "set_config") - { - _rpc_func_set_config(func_args, buf); - } - else if (func_cmd == "file_action") - { - _rpc_func_file_action(func_args, buf); - } - else - { - EXLOGE("[rpc] got unknown command: %s\n", func_cmd.c_str()); - _create_json_ret(buf, TPE_UNKNOWN_CMD); - } + if (func_cmd == "get_version") + { + _rpc_func_get_version(func_args, buf); + } + else if (func_cmd == "get_config") + { + _rpc_func_get_config(func_args, buf); + } + else if (func_cmd == "set_config") + { + _rpc_func_set_config(func_args, buf); + } + else if (func_cmd == "file_action") + { + _rpc_func_file_action(func_args, buf); + } + else + { + EXLOGE("[rpc] got unknown command: %s\n", func_cmd.c_str()); + _create_json_ret(buf, TPE_UNKNOWN_CMD); + } } void TsHttpRpc::_create_json_ret(ex_astr& buf, int errcode) { - // return {"code":123} + // return {"code":123} - Json::Value jr_root; - jr_root["code"] = errcode; + Json::Value jr_root; + jr_root["code"] = errcode; Json::StreamWriterBuilder jwb; std::unique_ptr jwriter(jwb.newStreamWriter()); ex_aoss os; @@ -341,31 +350,35 @@ void TsHttpRpc::_create_json_ret(ex_astr& buf, Json::Value& jr_root) buf = os.str(); } -void TsHttpRpc::_rpc_func_get_config(const ex_astr& func_args, ex_astr& buf) { - Json::Value jr_root; - jr_root["code"] = 0; - jr_root["data"] = g_cfg.get_root(); - _create_json_ret(buf, jr_root); +void TsHttpRpc::_rpc_func_get_config(const ex_astr& func_args, ex_astr& buf) +{ + Json::Value jr_root; + jr_root["code"] = 0; + jr_root["data"] = g_cfg.get_root(); + _create_json_ret(buf, jr_root); } -void TsHttpRpc::_rpc_func_set_config(const ex_astr& func_args, ex_astr& buf) { +void TsHttpRpc::_rpc_func_set_config(const ex_astr& func_args, ex_astr& buf) +{ Json::CharReaderBuilder jcrb; std::unique_ptr const jreader(jcrb.newCharReader()); - const char *str_json_begin = func_args.c_str(); + const char* str_json_begin = func_args.c_str(); Json::Value jsRoot; ex_astr err; - if (!jreader->parse(str_json_begin, str_json_begin + func_args.length(), &jsRoot, &err)) { + if (!jreader->parse(str_json_begin, str_json_begin + func_args.length(), &jsRoot, &err)) + { _create_json_ret(buf, TPE_JSON_FORMAT); return; } - if(!g_cfg.save(func_args)) - _create_json_ret(buf, TPE_FAILED); - else - _create_json_ret(buf, TPE_OK); + if (!g_cfg.save(func_args)) + _create_json_ret(buf, TPE_FAILED); + else + _create_json_ret(buf, TPE_OK); } -void TsHttpRpc::_rpc_func_file_action(const ex_astr& func_args, ex_astr& buf) { +void TsHttpRpc::_rpc_func_file_action(const ex_astr& func_args, ex_astr& buf) +{ _create_json_ret(buf, TPE_FAILED); #if 0 Json::Reader jreader; @@ -406,13 +419,14 @@ void TsHttpRpc::_rpc_func_file_action(const ex_astr& func_args, ex_astr& buf) { #endif } -void TsHttpRpc::_rpc_func_get_version(const ex_astr& func_args, ex_astr& buf) { - Json::Value root_ret; - ex_wstr w_version = TP_ASSIST_VER; - ex_astr version; - ex_wstr2astr(w_version, version, EX_CODEPAGE_UTF8); - root_ret["version"] = version; - root_ret["code"] = TPE_OK; - _create_json_ret(buf, root_ret); - return; +void TsHttpRpc::_rpc_func_get_version(const ex_astr& func_args, ex_astr& buf) +{ + Json::Value root_ret; + ex_wstr w_version = TP_ASSIST_VER; + ex_astr version; + ex_wstr2astr(w_version, version, EX_CODEPAGE_UTF8); + root_ret["version"] = version; + root_ret["code"] = TPE_OK; + _create_json_ret(buf, root_ret); + return; } diff --git a/client/tp_assist_macos/src/csrc/ts_http_rpc.h b/client/tp_assist_macos/src/csrc/ts_http_rpc.h index 70ce1de..d462936 100644 --- a/client/tp_assist_macos/src/csrc/ts_http_rpc.h +++ b/client/tp_assist_macos/src/csrc/ts_http_rpc.h @@ -16,13 +16,13 @@ //================================================================= # HTTP-RPC-INTERFACE: - + listen on http://localhost:50022. - + ---------------- GET method: http://127.0.0.1:50022/method/json_param - + here `json_param` is string in json format and encoded by url_encode(). ---------------- @@ -30,22 +30,22 @@ http://127.0.0.1:50022/method here the data field of POST should be json_param. - - + + ## URI detail: - + - method the method to request to execute. - json_param param of the method and it is optional. ## RESULT A string in json format should returned with following format: - + {"code":0,"data":varb} `code` field always exists and 0 means success. `data` field is optional. - + */ @@ -54,47 +54,54 @@ typedef std::map content_type_map; class TsHttpRpc : public ExThreadBase { public: - TsHttpRpc(); - ~TsHttpRpc(); + TsHttpRpc(); + + ~TsHttpRpc(); bool init(); - int get_port() {return m_port;} + int get_port() { return m_port; } - ex_astr get_content_type(ex_astr file_suffix) - { - content_type_map::iterator it = m_content_type_map.find(file_suffix); - if (it != m_content_type_map.end()) - { - return it->second; - } - else - { - return "application/octet-stream"; - } - }; + ex_astr get_content_type(ex_astr file_suffix) + { + content_type_map::iterator it = m_content_type_map.find(file_suffix); + if (it != m_content_type_map.end()) + { + return it->second; + } + else + { + return "application/octet-stream"; + } + }; protected: - void _thread_loop(void); + void _thread_loop(void); bool _on_init(); - -private: - int _parse_request(struct http_message* req, ex_astr& func_cmd, ex_astr& func_args); - void _process_js_request(const ex_astr& func_cmd, const ex_astr& func_args, ex_astr& buf); - void _create_json_ret(ex_astr& buf, int errcode); - void _create_json_ret(ex_astr& buf, Json::Value& jr_root); - - void _rpc_func_get_config(const ex_astr& func_args, ex_astr& buf); - void _rpc_func_set_config(const ex_astr& func_args, ex_astr& buf); - void _rpc_func_file_action(const ex_astr& func_args, ex_astr& buf); - void _rpc_func_get_version(const ex_astr& func_args, ex_astr& buf); - - static void _mg_event_handler(struct mg_connection *nc, int ev, void *ev_data); private: - content_type_map m_content_type_map; - struct mg_mgr m_mg_mgr; + int _parse_request(struct http_message* req, ex_astr& func_cmd, ex_astr& func_args); + + void _process_js_request(const ex_astr& func_cmd, const ex_astr& func_args, ex_astr& buf); + + void _create_json_ret(ex_astr& buf, int errcode); + + void _create_json_ret(ex_astr& buf, Json::Value& jr_root); + + void _rpc_func_get_config(const ex_astr& func_args, ex_astr& buf); + + void _rpc_func_set_config(const ex_astr& func_args, ex_astr& buf); + + void _rpc_func_file_action(const ex_astr& func_args, ex_astr& buf); + + void _rpc_func_get_version(const ex_astr& func_args, ex_astr& buf); + + static void _mg_event_handler(struct mg_connection* nc, int ev, void* ev_data); + +private: + content_type_map m_content_type_map; + struct mg_mgr m_mg_mgr; int m_port; }; diff --git a/client/tp_assist_macos/src/csrc/ts_ws_client.cpp b/client/tp_assist_macos/src/csrc/ts_ws_client.cpp index 0d4920d..80eefbd 100644 --- a/client/tp_assist_macos/src/csrc/ts_ws_client.cpp +++ b/client/tp_assist_macos/src/csrc/ts_ws_client.cpp @@ -31,49 +31,49 @@ void TsWsClient::url_scheme_handler(const std::string& url) { // e.g.: // url: teleport://register?param={"ws_url":"ws://127.0.0.1:7190/ws/assist/","assist_id":1234,"session_id":"tp_5678"} - + EXLOGV("url-schema: %s\n", url.c_str()); - + std::string protocol; std::string method; std::string param; - + std::string::size_type pos_protocol = url.find("://"); if (pos_protocol == std::string::npos) { EXLOGE("[ws] invalid url: %s\n", url.c_str()); return; } - + std::string::size_type pos_method = url.find('?'); if (pos_method == std::string::npos) { EXLOGE("[ws] invalid url: %s\n", url.c_str()); return; } - + protocol.assign(url, 0, pos_protocol); if (protocol != "teleport") { EXLOGE("[ws] invalid protocol: %s\n", protocol.c_str()); return; } - + method.assign(url, pos_protocol + 3, pos_method - pos_protocol - 3); - if(method.empty()) + if (method.empty()) { EXLOGE("[ws] no method, what should I do now?\n"); return; } - + param.assign(url, pos_method + 7); // ?param= if (param.empty()) { EXLOGE("[ws] invalid protocol: %s\n", protocol.c_str()); return; } - - + + // decode param with url-decode. size_t len = param.length() * 2; ex_chars sztmp; @@ -85,13 +85,13 @@ void TsWsClient::url_scheme_handler(const std::string& url) return; } param = &sztmp[0]; - + EXLOGV("[rpc] method=%s, json_param=%s\n", method.c_str(), param.c_str()); - + Json::CharReaderBuilder jcrb; std::unique_ptr const jreader(jcrb.newCharReader()); const char* str_json_begin = param.c_str(); - + Json::Value js_root; ex_astr err; if (!jreader->parse(str_json_begin, str_json_begin + param.length(), &js_root, &err)) @@ -104,16 +104,16 @@ void TsWsClient::url_scheme_handler(const std::string& url) EXLOGE("[ws] invalid param, need json object: %s\n", param.c_str()); return; } - + if (method == "register") { _process_register(param, js_root); } - else if(method == "run") + else if (method == "run") { _process_run(param, js_root); } - else if(method == "replay_rdp") + else if (method == "replay_rdp") { _process_replay_rdp(param, js_root); } @@ -127,18 +127,18 @@ void TsWsClient::url_scheme_handler(const std::string& url) void TsWsClient::_process_register(const std::string& param, Json::Value& js_root) { // {"ws_url":"ws://127.0.0.1:7190/ws/assist/","assist_id":1234,"session_id":"tp_5678"} - + // check param if (!js_root["ws_url"].isString() || !js_root["assist_id"].isNumeric() || !js_root["session_id"].isString()) { EXLOGE("[ws] invalid param: %s\n", param.c_str()); return; } - + std::string ws_url = js_root["ws_url"].asCString(); uint32_t assist_id = js_root["assist_id"].asUInt(); std::string session_id = js_root["session_id"].asCString(); - + std::string protocol; protocol.assign(ws_url, 0, 5); if (protocol == "ws://" || protocol == "wss:/") @@ -155,11 +155,11 @@ void TsWsClient::_process_register(const std::string& param, Json::Value& js_roo void TsWsClient::_process_run(const std::string& param, Json::Value& js_root) { // wrapper for _rpc_func_run_client(). - + Json::Value js_param; js_param["method"] = "run"; js_param["param"] = js_root; - + AssistMessage msg_req; std::string buf; _rpc_func_run_client(buf, msg_req, js_param); @@ -168,11 +168,11 @@ void TsWsClient::_process_run(const std::string& param, Json::Value& js_root) void TsWsClient::_process_replay_rdp(const std::string& param, Json::Value& js_root) { // wrapper for _rpc_func_replay_rdp(). - + Json::Value js_param; js_param["method"] = "replay_rdp"; js_param["param"] = js_root; - + AssistMessage msg_req; std::string buf; _rpc_func_replay_rdp(buf, msg_req, js_param); @@ -181,9 +181,9 @@ void TsWsClient::_process_replay_rdp(const std::string& param, Json::Value& js_r // ============================================================================ TsWsClient::TsWsClient() : -ExThreadBase("ws-client-thread"), -m_nc(NULL), -m_assist_id(0) + ExThreadBase("ws-client-thread"), + m_nc(NULL), + m_assist_id(0) { mg_mgr_init(&m_mg_mgr, NULL); } @@ -199,7 +199,7 @@ void TsWsClient::_thread_loop(void) { mg_mgr_poll(&m_mg_mgr, 500); } - + EXLOGV("[ws] main loop end.\n"); } @@ -207,23 +207,23 @@ void TsWsClient::_register(const std::string& ws_url, uint32_t assist_id, const { if (m_assist_id == 0) m_assist_id = assist_id; - + ex_wstr w_ver(TP_ASSIST_VER); ex_astr a_ver; ex_wstr2astr(w_ver, a_ver); - + // char msg[256] = {0}; ex_strformat( - msg, 256, "{\"type\":0,\"method\":\"register\",\"param\":{\"client\":\"assist\",\"sid\":\"%s\",\"request_assist_id\":%u,\"assist_id\":%u,\"assist_ver\":\"%s\"}}", - session_id.c_str(), assist_id, m_assist_id, a_ver.c_str()); - + msg, 256, "{\"type\":0,\"method\":\"register\",\"param\":{\"client\":\"assist\",\"sid\":\"%s\",\"request_assist_id\":%u,\"assist_id\":%u,\"assist_ver\":\"%s\"}}", + session_id.c_str(), assist_id, m_assist_id, a_ver.c_str()); + if (!m_is_running) { // not start yet. std::string url = ws_url; url += msg; - + m_nc = mg_connect_ws(&m_mg_mgr, _mg_event_handler, url.c_str(), NULL, NULL); if (!m_nc) { @@ -231,12 +231,12 @@ void TsWsClient::_register(const std::string& ws_url, uint32_t assist_id, const return; } m_nc->user_data = this; - + start(); return; } - - + + EXLOGV("[ws] send: %s\n", msg); mg_send_websocket_frame(m_nc, WEBSOCKET_OP_TEXT, msg, strlen(msg)); } @@ -250,60 +250,60 @@ void TsWsClient::_mg_event_handler(struct mg_connection* nc, int ev, void* ev_da EXLOGE("[ERROR] invalid request.\n"); return; } - + switch (ev) { - case MG_EV_CONNECT: + case MG_EV_CONNECT: + { + int status = *((int*)ev_data); + if (status != 0) { - int status = *((int*)ev_data); - if (status != 0) - { - EXLOGE("[ERROR] -- connect to ws server failed: %d\n", status); - } - - break; + EXLOGE("[ERROR] -- connect to ws server failed: %d\n", status); } - - case MG_EV_WEBSOCKET_HANDSHAKE_DONE: + + break; + } + + case MG_EV_WEBSOCKET_HANDSHAKE_DONE: + { + auto* hm = (struct http_message*)ev_data; + if (hm->resp_code == 101) { - auto* hm = (struct http_message*)ev_data; - if (hm->resp_code == 101) - { - EXLOGV("-- ws server connected\n"); - } - else - { - EXLOGE("[ERROR] -- connect to ws server failed, HTTP code: %d\n", hm->resp_code); - } - break; + EXLOGV("-- ws server connected\n"); } - - - case MG_EV_WEBSOCKET_FRAME: + else { - // on_message(). - auto* wm = (struct websocket_message*)ev_data; - // EXLOGV("%d: %s\n", wm->size, wm->data); - std::string message; - message.assign((const char*)wm->data, wm->size); - std::string buf; - _this->_on_message(message, buf); - - if (!buf.empty()) - { - mg_send_websocket_frame(nc, WEBSOCKET_OP_TEXT, buf.c_str(), buf.length()); - } - - break; + EXLOGE("[ERROR] -- connect to ws server failed, HTTP code: %d\n", hm->resp_code); } - - - case MG_EV_CLOSE: + break; + } + + + case MG_EV_WEBSOCKET_FRAME: + { + // on_message(). + auto* wm = (struct websocket_message*)ev_data; + // EXLOGV("%d: %s\n", wm->size, wm->data); + std::string message; + message.assign((const char*)wm->data, wm->size); + std::string buf; + _this->_on_message(message, buf); + + if (!buf.empty()) { - EXLOGV("-- ws server disconnected\n"); - _this->m_need_stop = true; - break; + mg_send_websocket_frame(nc, WEBSOCKET_OP_TEXT, buf.c_str(), buf.length()); } + + break; + } + + + case MG_EV_CLOSE: + { + EXLOGV("-- ws server disconnected\n"); + _this->m_need_stop = true; + break; + } } } @@ -328,7 +328,7 @@ void TsWsClient::_create_response(ex_astr& buf, const AssistMessage& msg_ret, in js_ret["code"] = err_code; js_ret["message"] = message; js_ret["data"] = data; - + Json::StreamWriterBuilder jwb; jwb["indentation"] = ""; // 压缩格式,没有换行和不必要的空白字符 std::unique_ptr js_writer(jwb.newStreamWriter()); @@ -349,15 +349,15 @@ void TsWsClient::_on_message(const std::string& message, std::string& buf) // "protocol_sub_type":200,"protocol_flag":4294967295 // } // } - + EXLOGV("on_message: %s\n", message.c_str()); - + AssistMessage msg_req; - + Json::CharReaderBuilder jrb; std::unique_ptr const js_reader(jrb.newCharReader()); const char* str_json_begin = message.c_str(); - + Json::Value js_root; ex_astr err; if (!js_reader->parse(str_json_begin, str_json_begin + message.length(), &js_root, &err)) @@ -370,57 +370,57 @@ void TsWsClient::_on_message(const std::string& message, std::string& buf) _create_response(buf, msg_req, TPE_PARAM); return; } - + if (js_root["type"].isNull() || !js_root["type"].isInt()) { _create_response(buf, msg_req, TPE_PARAM); return; } - + int cmd_type = js_root["type"].asInt(); if (!(cmd_type == MESSAGE_TYPE_REQUEST || cmd_type == MESSAGE_TYPE_RESPONSE)) { _create_response(buf, msg_req, TPE_PARAM); return; } - + // 收到的信息已经是“返回值”了,说明已经是一条命令的结束了,不用继续处理 // todo: 可能需要记录日志,或者展示结果。 if (cmd_type == MESSAGE_TYPE_RESPONSE) return; - + if (js_root["method"].isNull() || !js_root["method"].isString() || js_root["command_id"].isNull() || !js_root["command_id"].isInt()) { _create_response(buf, msg_req, TPE_PARAM); return; } - + msg_req.command_id = js_root["command_id"].asInt(); msg_req.method = js_root["method"].asString(); - + if (msg_req.command_id == 0 || msg_req.method.empty()) { _create_response(buf, msg_req, TPE_PARAM); return; } - + if (msg_req.method == "run") { _rpc_func_run_client(buf, msg_req, js_root); } - else if(msg_req.method == "replay_rdp") + else if (msg_req.method == "replay_rdp") { _rpc_func_replay_rdp(buf, msg_req, js_root); } - else if(msg_req.method == "get_config") + else if (msg_req.method == "get_config") { _rpc_func_get_config(buf, msg_req, js_root); } - else if(msg_req.method == "set_config") + else if (msg_req.method == "set_config") { _rpc_func_set_config(buf, msg_req, js_root); } - else if(msg_req.method == "select_file") + else if (msg_req.method == "select_file") { _rpc_func_select_file(buf, msg_req, js_root); } @@ -434,9 +434,9 @@ void TsWsClient::_on_message(const std::string& message, std::string& buf) void TsWsClient::_rpc_func_get_config(ex_astr& buf, AssistMessage& msg_req, Json::Value& js_root) { Json::Value& ret = g_cfg.get_root(); - if(ret["os_type"].isNull()) + if (ret["os_type"].isNull()) ret["os_type"] = "macos"; - + _create_response(buf, msg_req, TPE_OK, "", ret); } @@ -448,12 +448,12 @@ void TsWsClient::_rpc_func_set_config(ex_astr& buf, AssistMessage& msg_req, Json return; } Json::Value& js_param = js_root["param"]; - + Json::StreamWriterBuilder jwb; std::unique_ptr js_writer(jwb.newStreamWriter()); ex_aoss os; js_writer->write(js_param, &os); - + if (!g_cfg.save(os.str())) _create_response(buf, msg_req, TPE_FAILED); else @@ -476,91 +476,98 @@ void TsWsClient::_rpc_func_replay_rdp(ex_astr& buf, AssistMessage& msg_req, Json // "sid":"tp_1622707094_1c8e4fd4006c6ad5" // } // } - + if (js_root["param"].isNull() || !js_root["param"].isObject()) { _create_response(buf, msg_req, TPE_PARAM); return; } Json::Value& js_param = js_root["param"]; - + // check param if (!js_param["rid"].isNumeric() || !js_param["web"].isString() || !js_param["sid"].isString() - ) + ) { _create_response(buf, msg_req, TPE_PARAM); return; } - + ex_astrs s_argv; - + ex_wstr w_exec_file = g_env.m_bundle_path; ex_path_join(w_exec_file, false, L"Contents", L"Resources", L"tp-player.app", L"Contents", L"MacOS", L"tp-player", nullptr); // ex_path_join(w_exec_file, false, L"tp-player.app", L"Contents", L"MacOS", L"tp-player", nullptr); ex_astr exec_file; ex_wstr2astr(w_exec_file, exec_file); - + s_argv.push_back(exec_file); - - + + int rid = js_param["rid"].asInt(); ex_astr a_url_base = js_param["web"].asCString(); ex_astr a_sid = js_param["sid"].asCString(); - - char cmd_args[1024] = { 0 }; + + char cmd_args[1024] = {0}; ex_strformat(cmd_args, 1023, "%s/%s/%d", a_url_base.c_str(), a_sid.c_str(), rid); s_argv.push_back(cmd_args); - + ex_wstr w_cmd_args; ex_astr2wstr(cmd_args, w_cmd_args); - + char total_cmd[1024] = {0}; ex_strformat(total_cmd, 1023, "%s %s", exec_file.c_str(), cmd_args); - + Json::Value js_ret; - + ex_astr utf8_path; //ex_wstr2astr(total_cmd, utf8_path, EX_CODEPAGE_UTF8); js_ret["cmdline"] = total_cmd; - + // EXLOGD(utf8_path.c_str()); - + // for macOS, Create Process should be fork()/exec()... int ret_code = TPE_OK; pid_t processId; - if ((processId = fork()) == 0) { - + if ((processId = fork()) == 0) + { + int i = 0; - char** _argv = (char**)calloc(s_argv.size()+1, sizeof(char*)); + char** _argv = (char**)calloc(s_argv.size() + 1, sizeof(char*)); if (!_argv) return; - + for (i = 0; i < s_argv.size(); ++i) { _argv[i] = ex_strdup(s_argv[i].c_str()); } _argv[i] = NULL; - + execv(exec_file.c_str(), _argv); - - for(i = 0; i < s_argv.size(); ++i) { - if(_argv[i] != NULL) { + + for (i = 0; i < s_argv.size(); ++i) + { + if (_argv[i] != NULL) + { free(_argv[i]); } } free(_argv); - - } else if (processId < 0) { + + } + else if (processId < 0) + { ret_code = TPE_FAILED; - } else { + } + else + { ret_code = TPE_OK; } - + // _create_json_ret(buf, root_ret); _create_response(buf, msg_req, ret_code, "", js_ret); - + } void TsWsClient::_rpc_func_run_client(ex_astr& buf, AssistMessage& msg_req, Json::Value& js_root) @@ -573,84 +580,87 @@ void TsWsClient::_rpc_func_run_client(ex_astr& buf, AssistMessage& msg_req, Json // "protocol_sub_type":200,"protocol_flag":4294967295 // } // } - + if (js_root["param"].isNull() || !js_root["param"].isObject()) { _create_response(buf, msg_req, TPE_PARAM); return; } Json::Value& js_param = js_root["param"]; - + // check param if (!js_param["teleport_ip"].isString() || !js_param["teleport_port"].isNumeric() || !js_param["remote_host_ip"].isString() || !js_param["session_id"].isString() || !js_param["protocol_type"].isNumeric() || !js_param["protocol_sub_type"].isNumeric() || !js_param["protocol_flag"].isNumeric() - ) + ) { _create_response(buf, msg_req, TPE_PARAM); return; } - + const char* interactive_mode = "no"; bool is_interactive_mode = false; - if(!js_param["is_interactive"].isNull()) { - if(!js_param["is_interactive"].isBool()) { + if (!js_param["is_interactive"].isNull()) + { + if (!js_param["is_interactive"].isBool()) + { _create_response(buf, msg_req, TPE_PARAM); return; } - if(js_param["is_interactive"].asBool()) { + if (js_param["is_interactive"].asBool()) + { interactive_mode = "yes"; is_interactive_mode = true; } } - + int pro_type = js_param["protocol_type"].asUInt(); int pro_sub = js_param["protocol_sub_type"].asInt(); ex_u32 protocol_flag = js_param["protocol_flag"].asUInt(); - + ex_astr teleport_ip = js_param["teleport_ip"].asCString(); int teleport_port = js_param["teleport_port"].asUInt(); char _port[64] = {0}; ex_strformat(_port, 64, "%d", teleport_port); ex_astr str_teleport_port = _port; - + ex_astr real_host_ip = js_param["remote_host_ip"].asCString(); ex_astr real_host_name = js_param["remote_host_name"].asCString(); ex_astr sid = js_param["session_id"].asCString(); - - + + ex_astr s_exec; ex_astr s_arg; ex_astrs s_argv; - - + + if (pro_type == TP_PROTOCOL_TYPE_RDP) { //============================================== // RDP //============================================== - + if (g_cfg.rdp.application.length() == 0) { _create_response(buf, msg_req, TPE_NOT_EXISTS, "助手未配置本地RDP客户端,请检查您的助手设置。"); return; } - + if (!ex_is_file_exists(g_cfg.rdp.application.c_str())) { _create_response(buf, msg_req, TPE_NOT_EXISTS, "无法定位助手配置的RDP客户端,请检查您的助手设置。"); return; } - + bool flag_clipboard = ((protocol_flag & TP_FLAG_RDP_CLIPBOARD) == TP_FLAG_RDP_CLIPBOARD); bool flag_disk = ((protocol_flag & TP_FLAG_RDP_DISK) == TP_FLAG_RDP_DISK); bool flag_console = ((protocol_flag & TP_FLAG_RDP_CONSOLE) == TP_FLAG_RDP_CONSOLE); - + int rdp_w = 800; int rdp_h = 640; bool rdp_console = false; - + if (!js_param["rdp_width"].isNull()) { if (js_param["rdp_width"].isNumeric()) @@ -663,7 +673,7 @@ void TsWsClient::_rpc_func_run_client(ex_astr& buf, AssistMessage& msg_req, Json return; } } - + if (!js_param["rdp_height"].isNull()) { if (js_param["rdp_height"].isNumeric()) @@ -676,7 +686,7 @@ void TsWsClient::_rpc_func_run_client(ex_astr& buf, AssistMessage& msg_req, Json return; } } - + if (!js_param["rdp_console"].isNull()) { if (js_param["rdp_console"].isBool()) @@ -689,25 +699,27 @@ void TsWsClient::_rpc_func_run_client(ex_astr& buf, AssistMessage& msg_req, Json return; } } - + if (!flag_console) rdp_console = false; - - - size_t split_pos = sid.length() - 2; - ex_astr real_sid = sid.substr(0, split_pos); - ex_astr str_pwd_len = sid.substr(split_pos, sid.length()); - size_t n_pwd_len = strtol(str_pwd_len.c_str(), NULL, 16); - n_pwd_len -= real_sid.length(); - n_pwd_len -= 2; - char szPwd[256] = {0}; - for (int i = 0; i < n_pwd_len; i++) - { - szPwd[i] = '*'; - } - + + + // size_t split_pos = sid.length() - 2; + // ex_astr real_sid = sid.substr(0, split_pos); + // ex_astr str_pwd_len = sid.substr(split_pos, sid.length()); + // size_t n_pwd_len = strtol(str_pwd_len.c_str(), NULL, 16); + // n_pwd_len -= real_sid.length(); + // n_pwd_len -= 2; + // char szPwd[256] = {0}; + // for (int i = 0; i < n_pwd_len; i++) + // { + // szPwd[i] = '*'; + // } + + // ex_astr real_sid(sid); + //ex_astr2wstr(real_sid, w_sid); - + //w_exe_path = _T("\""); //w_exe_path += g_cfg.rdp_app + _T("\" "); //w_exe_path += g_cfg.rdp_cmdline; @@ -717,10 +729,10 @@ void TsWsClient::_rpc_func_run_client(ex_astr& buf, AssistMessage& msg_req, Json //s_exec = "/usr/local/Cellar/freerdp/1.0.2_1/bin/xfreerdp"; s_exec = g_cfg.rdp.application; s_arg = g_cfg.rdp.cmdline; - - sid = "02" + real_sid; + + // sid = "02" + real_sid; // s_argv.push_back("/f"); - + s_argv.push_back("/sec:tls"); s_argv.push_back("-wallpaper"); s_argv.push_back("-themes"); @@ -728,20 +740,21 @@ void TsWsClient::_rpc_func_run_client(ex_astr& buf, AssistMessage& msg_req, Json s_argv.push_back("/cert-ignore"); // Automatically accept certificate on first connect s_argv.push_back("/cert-tofu"); - - ex_astr _tmp_pass = "/p:PLACEHOLDER"; + + // ex_astr _tmp_pass = "/p:PLACEHOLDER"; + ex_astr _tmp_pass = "/p:******"; //_tmp_pass += szPwd; s_argv.push_back(_tmp_pass); - + //#if 0 //s_argv.push_back(s_exec.c_str()); - + { // ex_astr username = "02" + real_sid; // s_argv.push_back("/u:"); // s_argv.push_back(username.c_str()); - - + + if (rdp_w == 0 || rdp_h == 0) { s_argv.push_back("/f"); @@ -755,20 +768,20 @@ void TsWsClient::_rpc_func_run_client(ex_astr& buf, AssistMessage& msg_req, Json char sz_width[64] = {0}; ex_strformat(sz_width, 63, "/w:%d", rdp_w); s_argv.push_back(sz_width); - + char sz_height[64] = {0}; ex_strformat(sz_height, 63, "/h:%d", rdp_h); s_argv.push_back(sz_height); } - + if (flag_console && rdp_console) s_argv.push_back("/admin"); - + // if(flag_clipboard) // s_argv.push_back("+clipboard"); // else // s_argv.push_back("-clipboard"); - + // if(flag_disk) // s_argv.push_back("+drives"); // else @@ -787,17 +800,17 @@ void TsWsClient::_rpc_func_run_client(ex_astr& buf, AssistMessage& msg_req, Json //============================================== // SSH //============================================== - + if (pro_sub == TP_PROTOCOL_TYPE_SSH_SHELL) { if (g_cfg.ssh.name == "terminal" || g_cfg.ssh.name == "iterm2") { char szCmd[1024] = {0}; ex_strformat(szCmd, 1023, "ssh %s@%s -p %d -o \"StrictHostKeyChecking no\"", sid.c_str(), teleport_ip.c_str(), teleport_port); - + char szTitle[128] = {0}; ex_strformat(szTitle, 127, "TP#%s", real_host_ip.c_str()); - + int ret = AppDelegate_start_ssh_client(g_app, szCmd, g_cfg.ssh.name.c_str(), g_cfg.ssh.cmdline.c_str(), szTitle, interactive_mode); if (ret == 0) _create_response(buf, msg_req, TPE_OK); @@ -805,34 +818,34 @@ void TsWsClient::_rpc_func_run_client(ex_astr& buf, AssistMessage& msg_req, Json _create_response(buf, msg_req, TPE_FAILED); return; } - + if (g_cfg.ssh.application.length() == 0) { _create_response(buf, msg_req, TPE_NOT_EXISTS); return; } - + s_exec = g_cfg.ssh.application; s_argv.push_back(s_exec.c_str()); - + s_arg = g_cfg.ssh.cmdline; } else { - + // sorry, SFTP not supported yet for macOS. // _create_json_ret(buf, TPE_NOT_IMPLEMENT); // return; - + if (g_cfg.sftp.application.length() == 0) { _create_response(buf, msg_req, TPE_NOT_EXISTS); return; } - + s_exec = g_cfg.sftp.application; s_argv.push_back(s_exec.c_str()); - + s_arg = g_cfg.sftp.cmdline; } } @@ -841,21 +854,21 @@ void TsWsClient::_rpc_func_run_client(ex_astr& buf, AssistMessage& msg_req, Json //============================================== // TELNET //============================================== - + // sorry, TELNET not supported yet for macOS. // _create_json_ret(buf, TPE_NOT_IMPLEMENT); // return; - + g_cfg.telnet.name = "iterm2"; - + if (g_cfg.telnet.name == "terminal" || g_cfg.telnet.name == "iterm2") { char szCmd[1024] = {0}; ex_strformat(szCmd, 1023, "telnet -l %s %s %d", sid.c_str(), teleport_ip.c_str(), teleport_port); - + char szTitle[128] = {0}; ex_strformat(szTitle, 127, "TP#%s", real_host_ip.c_str()); - + int ret = AppDelegate_start_ssh_client(g_app, szCmd, g_cfg.telnet.name.c_str(), g_cfg.telnet.cmdline.c_str(), szTitle, interactive_mode); if (ret == 0) _create_response(buf, msg_req, TPE_OK); @@ -863,38 +876,43 @@ void TsWsClient::_rpc_func_run_client(ex_astr& buf, AssistMessage& msg_req, Json _create_response(buf, msg_req, TPE_FAILED); return; } - + if (g_cfg.telnet.application.length() == 0) { _create_response(buf, msg_req, TPE_NOT_EXISTS); return; } - + s_exec = g_cfg.telnet.application; s_argv.push_back(s_exec.c_str()); - + s_arg = g_cfg.telnet.cmdline; } - + //---- split s_arg and push to s_argv --- ex_astr::size_type p1 = 0; ex_astr::size_type p2 = 0; ex_astr tmp; - - for(;;){ + + for (;;) + { p1 = s_arg.find("{password:"); - if(p1 != ex_astr::npos) { - p2 = s_arg.find('}', p1+10); - if(p2 == ex_astr::npos) { + if (p1 != ex_astr::npos) + { + p2 = s_arg.find('}', p1 + 10); + if (p2 == ex_astr::npos) + { _create_response(buf, msg_req, TPE_PARAM); return; } - - if(is_interactive_mode) { + + if (is_interactive_mode) + { // 如果需要用户自己输入密码,则客户端命令行就不能带密码字段,需要抹去这个参数 - s_arg.erase(p1, p2-p1+1); + s_arg.erase(p1, p2 - p1 + 1); } - else{ + else + { s_arg.erase(p2, 1); s_arg.erase(p1, 10); } @@ -905,20 +923,25 @@ void TsWsClient::_rpc_func_run_client(ex_astr& buf, AssistMessage& msg_req, Json } } - for(;;){ + for (;;) + { p1 = s_arg.find("{interactive:"); - if(p1 != ex_astr::npos) { - p2 = s_arg.find('}', p1+13); - if(p2 == ex_astr::npos) { + if (p1 != ex_astr::npos) + { + p2 = s_arg.find('}', p1 + 13); + if (p2 == ex_astr::npos) + { _create_response(buf, msg_req, TPE_PARAM); return; } - - if(!is_interactive_mode) { + + if (!is_interactive_mode) + { // 如果无需用户自己输入密码,则需要抹去这个参数 - s_arg.erase(p1, p2-p1+1); + s_arg.erase(p1, p2 - p1 + 1); } - else{ + else + { s_arg.erase(p2, 1); s_arg.erase(p1, 13); } @@ -929,7 +952,7 @@ void TsWsClient::_rpc_func_run_client(ex_astr& buf, AssistMessage& msg_req, Json } } - + tmp = s_arg; for (;;) { @@ -938,48 +961,48 @@ void TsWsClient::_rpc_func_run_client(ex_astr& buf, AssistMessage& msg_req, Json { break; } - + if (tmp[0] == '"') { p1 = 1; p2 = tmp.find('"', p1); - + if (p2 == ex_astr::npos) { _create_response(buf, msg_req, TPE_PARAM); return; } - + ex_astr _t; _t.assign(tmp, p1, p2 - p1); tmp.erase(0, p2 + 2); - + s_argv.push_back(_t); } else { p1 = 0; p2 = tmp.find(' ', p1); - + if (p2 == ex_astr::npos) { s_argv.push_back(tmp); tmp.clear(); break; } - + ex_astr _t; _t.assign(tmp, p1, p2 - p1); tmp.erase(0, p2 + 1); - + s_argv.push_back(_t); } } - - + + Json::Value js_data; ex_astr utf8_path = s_exec; - + ex_astrs::iterator it = s_argv.begin(); for (; it != s_argv.end(); ++it) { @@ -989,31 +1012,31 @@ void TsWsClient::_rpc_func_run_client(ex_astr& buf, AssistMessage& msg_req, Json ex_replace_all((*it), "{real_ip}", real_host_ip); ex_replace_all((*it), "{host_name}", real_host_name); //ex_replace_all(utf8_path, _T("{assist_tools_path}"), g_env.m_tools_path.c_str()); - + utf8_path += " "; utf8_path += (*it); } - + js_data["path"] = utf8_path; - + // for macOS, Create Process should be fork()/exec()... pid_t processId; if ((processId = fork()) == 0) { - + int i = 0; char** _argv = (char**)calloc(s_argv.size() + 1, sizeof(char*)); if (!_argv) return; - + for (i = 0; i < s_argv.size(); ++i) { _argv[i] = ex_strdup(s_argv[i].c_str()); } _argv[i] = NULL; - + execv(s_exec.c_str(), _argv); - + for (i = 0; i < s_argv.size(); ++i) { if (_argv[i] != NULL) diff --git a/client/tp_assist_macos/src/csrc/ts_ws_client.h b/client/tp_assist_macos/src/csrc/ts_ws_client.h index f54dd76..49650be 100644 --- a/client/tp_assist_macos/src/csrc/ts_ws_client.h +++ b/client/tp_assist_macos/src/csrc/ts_ws_client.h @@ -34,6 +34,7 @@ public: ~TsWsClient(); void init(); + void stop_all_client(); void url_scheme_handler(const std::string& url); @@ -57,7 +58,7 @@ private: void _rpc_func_select_file(ex_astr& buf, AssistMessage& msg_req, Json::Value& js_root); void _rpc_func_replay_rdp(ex_astr& buf, AssistMessage& msg_req, Json::Value& js_root); - + void _send_result(int err_code, Json::Value& jr_root); void _create_response(ex_astr& buf, const AssistMessage& msg_ret, int err_code); @@ -69,8 +70,9 @@ private: static void _mg_event_handler(struct mg_connection* nc, int ev, void* ev_data); void _process_register(const std::string& param, Json::Value& js_root); - + void _process_run(const std::string& param, Json::Value& js_root); + void _process_replay_rdp(const std::string& param, Json::Value& js_root); private: diff --git a/server/tp_core/core/ts_session.cpp b/server/tp_core/core/ts_session.cpp index 2447cc0..14381aa 100644 --- a/server/tp_core/core/ts_session.cpp +++ b/server/tp_core/core/ts_session.cpp @@ -161,9 +161,9 @@ bool TsSessionManager::request_session(ex_astr& sid, TS_CONNECT_INFO* info) if (info->protocol_type == TP_PROTOCOL_TYPE_RDP) { info->ref_count = 1; // 因为RDP连接之前可能会有很长时间用于确认是否连接、是否信任证书,所以很容易超时,我们认为将引用计数+1,防止因超时被清除。 - char szTmp[8] = {0}; - snprintf(szTmp, 8, "%02X", (unsigned char)(info->acc_username.length() + info->acc_secret.length())); - sid += szTmp; + // char szTmp[8] = {0}; + // snprintf(szTmp, 8, "%02X", (unsigned char)(info->acc_username.length() + info->acc_secret.length())); + // sid += szTmp; } return true; diff --git a/server/www/teleport/static/js/ops/remote-list.js b/server/www/teleport/static/js/ops/remote-list.js index ca4e19f..8cf049d 100644 --- a/server/www/teleport/static/js/ops/remote-list.js +++ b/server/www/teleport/static/js/ops/remote-list.js @@ -518,11 +518,9 @@ $app.connect_remote = function (uni_id, acc_id, host_id, protocol_type, protocol is_interactive: false, }; if (protocol_type === TP_PROTOCOL_TYPE_RDP) { - args.extends({ - rdp_width: $app.dlg_rdp_options.rdp_w, - rdp_height: $app.dlg_rdp_options.rdp_h, - rdp_console: $app.dlg_rdp_options.rdp_console - }); + args.rdp_width = $app.dlg_rdp_options.rdp_w; + args.rdp_height = $app.dlg_rdp_options.rdp_h; + args.rdp_console = $app.dlg_rdp_options.rdp_console; } if (uni_id === 'none')