diff --git a/server/tp_core/core/ts_http_rpc.cpp b/server/tp_core/core/ts_http_rpc.cpp index e8bd3f6..d9530ab 100644 --- a/server/tp_core/core/ts_http_rpc.cpp +++ b/server/tp_core/core/ts_http_rpc.cpp @@ -1,553 +1,570 @@ -#include "ts_http_rpc.h" -#include "ts_ver.h" -#include "ts_env.h" -#include "ts_session.h" -#include "ts_crypto.h" -#include "ts_web_rpc.h" -#include "tp_tpp_mgr.h" - -extern TppManager g_tpp_mgr; - -#include - - -#define HEXTOI(x) (isdigit(x) ? x - '0' : x - 'W') -int ts_url_decode(const char *src, int src_len, char *dst, int dst_len, int is_form_url_encoded) -{ - int i, j, a, b; - - for (i = j = 0; i < src_len && j < dst_len - 1; i++, j++) - { - if (src[i] == '%') - { - if (i < src_len - 2 && isxdigit(*(const unsigned char *)(src + i + 1)) && - isxdigit(*(const unsigned char *)(src + i + 2))) { - a = tolower(*(const unsigned char *)(src + i + 1)); - b = tolower(*(const unsigned char *)(src + i + 2)); - dst[j] = (char)((HEXTOI(a) << 4) | HEXTOI(b)); - i += 2; - } - else - { - return -1; - } - } - else if (is_form_url_encoded && src[i] == '+') - { - dst[j] = ' '; - } - else - { - dst[j] = src[i]; - } - } - - dst[j] = '\0'; /* Null-terminate the destination */ - - return i >= src_len ? j : -1; -} - -TsHttpRpc::TsHttpRpc() : - ExThreadBase("http-rpc-thread") -{ - mg_mgr_init(&m_mg_mgr, NULL); -} - -TsHttpRpc::~TsHttpRpc() -{ - mg_mgr_free(&m_mg_mgr); -} - -void TsHttpRpc::_thread_loop(void) -{ - EXLOGI("[core] TeleportServer-RPC ready on %s:%d\n", m_host_ip.c_str(), m_host_port); - - while (!m_need_stop) - { - mg_mgr_poll(&m_mg_mgr, 500); - } - - EXLOGV("[core] rpc main loop end.\n"); -} - - -bool TsHttpRpc::init(void) -{ - struct mg_connection* nc = NULL; - - m_host_ip = g_env.rpc_bind_ip; - m_host_port = g_env.rpc_bind_port; - - char addr[128] = { 0 }; - // if (0 == strcmp(m_host_ip.c_str(), "127.0.0.1") || 0 == strcmp(m_host_ip.c_str(), "localhost")) - // ex_strformat(addr, 128, ":%d", m_host_port); - // else - // ex_strformat(addr, 128, "%s:%d", m_host_ip.c_str(), m_host_port); - if (0 == strcmp(m_host_ip.c_str(), "0.0.0.0")) - ex_strformat(addr, 128, ":%d", m_host_port); - else - ex_strformat(addr, 128, "%s:%d", m_host_ip.c_str(), m_host_port); - - nc = mg_bind(&m_mg_mgr, addr, _mg_event_handler); - if (NULL == nc) - { - EXLOGE("[core] rpc listener failed to bind at %s.\n", addr); - return false; - } - - nc->user_data = this; - - mg_set_protocol_http_websocket(nc); - - // 导致内存泄露的地方(每次请求约消耗1KB内存) - // DO NOT USE MULTITHREADING OF MG. - // cpq (one of the authors of MG) commented on 3 Feb: Multithreading support has been removed. - // https://github.com/cesanta/mongoose/commit/707b9ed2d6f177b3ad8787cb16a1bff90ddad992 - //mg_enable_multithreading(nc); - - return true; -} - -void TsHttpRpc::_mg_event_handler(struct mg_connection *nc, int ev, void *ev_data) -{ - struct http_message *hm = (struct http_message*)ev_data; - - TsHttpRpc* _this = (TsHttpRpc*)nc->user_data; - if (NULL == _this) - { - EXLOGE("[core] rpc invalid http request.\n"); - return; - } - - switch (ev) - { - case MG_EV_HTTP_REQUEST: - { - ex_astr ret_buf; - - ex_astr uri; - uri.assign(hm->uri.p, hm->uri.len); - - //EXLOGD("[core] rpc got request: %s\n", uri.c_str()); - - if (uri == "/rpc") - { - ex_astr method; - Json::Value json_param; - - ex_rv rv = _this->_parse_request(hm, method, json_param); - if (TPE_OK != rv) - { - EXLOGE("[core] rpc got invalid request.\n"); - _this->_create_json_ret(ret_buf, rv); - } - else - { - EXLOGD("[core] rpc got request method `%s`\n", method.c_str()); - _this->_process_request(method, json_param, ret_buf); - } - } - else - { - EXLOGE("[core] rpc got invalid request: not `rpc` uri.\n"); - _this->_create_json_ret(ret_buf, TPE_PARAM, "not a `rpc` request."); - } - - mg_printf(nc, "HTTP/1.0 200 OK\r\nAccess-Control-Allow-Origin: *\r\nContent-Length: %d\r\nContent-Type: application/json\r\n\r\n%s", (int)ret_buf.size() - 1, &ret_buf[0]); - nc->flags |= MG_F_SEND_AND_CLOSE; - } - break; - default: - break; - } -} - -ex_rv TsHttpRpc::_parse_request(struct http_message* req, ex_astr& func_cmd, Json::Value& json_param) -{ - if (NULL == req) - return TPE_PARAM; - - 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_astr json_str; - bool need_decode = false; - if (is_get) { - json_str.assign(req->query_string.p, req->query_string.len); - need_decode = true; - } - else { - json_str.assign(req->body.p, req->body.len); - if (json_str.length() > 0 && json_str[0] == '%') - need_decode = true; - } - - if (need_decode) { - // 将参数进行 url-decode 解码 - int len = json_str.length() * 2; - ex_chars sztmp; - sztmp.resize(len); - memset(&sztmp[0], 0, len); - if (-1 == ts_url_decode(json_str.c_str(), json_str.length(), &sztmp[0], len, 0)) - return TPE_HTTP_URL_ENCODE; - - json_str = &sztmp[0]; - } - - if (0 == json_str.length()) - return TPE_PARAM; - - Json::Reader jreader; - - if (!jreader.parse(json_str.c_str(), json_param)) - return TPE_JSON_FORMAT; - - if (json_param.isArray()) - return TPE_PARAM; - - if (json_param["method"].isNull() || !json_param["method"].isString()) - return TPE_PARAM; - - func_cmd = json_param["method"].asCString(); - json_param = json_param["param"]; - - return TPE_OK; -} - -void TsHttpRpc::_create_json_ret(ex_astr& buf, int errcode, const Json::Value& jr_data) -{ - // 返回: {"code":errcode, "data":{jr_data}} - - Json::FastWriter jr_writer; - Json::Value jr_root; - - jr_root["code"] = errcode; - jr_root["data"] = jr_data; - buf = jr_writer.write(jr_root); -} - -void TsHttpRpc::_create_json_ret(ex_astr& buf, int errcode) -{ - // 返回: {"code":errcode} - - Json::FastWriter jr_writer; - Json::Value jr_root; - - jr_root["code"] = errcode; - buf = jr_writer.write(jr_root); -} - -void TsHttpRpc::_create_json_ret(ex_astr& buf, int errcode, const char* message) -{ - // 返回: {"code":errcode, "message":message} - - Json::FastWriter jr_writer; - Json::Value jr_root; - - jr_root["code"] = errcode; - jr_root["message"] = message; - buf = jr_writer.write(jr_root); -} - -void TsHttpRpc::_process_request(const ex_astr& func_cmd, const Json::Value& json_param, ex_astr& buf) -{ - if (func_cmd == "request_session") { - _rpc_func_request_session(json_param, buf); - } - else if (func_cmd == "kill_sessions") { - _rpc_func_kill_sessions(json_param, buf); - } - else if (func_cmd == "get_config") { - _rpc_func_get_config(json_param, buf); - } - else if (func_cmd == "set_config") { - _rpc_func_set_config(json_param, buf); - } - else if (func_cmd == "enc") { - _rpc_func_enc(json_param, buf); - } - else if (func_cmd == "exit") { - _rpc_func_exit(json_param, buf); - } - else { - EXLOGE("[core] rpc got unknown command: %s\n", func_cmd.c_str()); - _create_json_ret(buf, TPE_UNKNOWN_CMD); - } -} - -extern bool g_exit_flag; // 要求整个TS退出的标志(用于停止各个工作线程) -void TsHttpRpc::_rpc_func_exit(const Json::Value& json_param, ex_astr& buf) -{ - // 设置一个全局退出标志 - g_exit_flag = true; - _create_json_ret(buf, TPE_OK); -} - -void TsHttpRpc::_rpc_func_get_config(const Json::Value& json_param, ex_astr& buf) -{ - Json::Value jr_data; - - ex_astr _replay_name; - ex_wstr2astr(g_env.m_replay_path, _replay_name); - jr_data["replay-path"] = _replay_name; - - jr_data["web-server-rpc"] = g_env.web_server_rpc; - - ex_astr _version; - ex_wstr2astr(TP_SERVER_VER, _version); - jr_data["version"] = _version; - - ExIniFile& ini = g_env.get_ini(); - ex_ini_sections& secs = ini.GetAllSections(); - ex_ini_sections::iterator it = secs.begin(); - for (; it != secs.end(); ++it) - { - if (it->first.length() > 9 && 0 == wcsncmp(it->first.c_str(), L"protocol-", 9)) - { - ex_wstr name; - name.assign(it->first, 9, it->first.length() - 9); - ex_astr _name; - ex_wstr2astr(name, _name); - - bool enabled = false; - it->second->GetBool(L"enabled", enabled, false); - - ex_wstr ip; - if (!it->second->GetStr(L"bind-ip", ip)) - continue; - ex_astr _ip; - ex_wstr2astr(ip, _ip); - - int port; - it->second->GetInt(L"bind-port", port, 52189); - - jr_data[_name.c_str()]["enable"] = enabled; - jr_data[_name.c_str()]["ip"] = _ip; - jr_data[_name.c_str()]["port"] = port; - } - } - - _create_json_ret(buf, TPE_OK, jr_data); -} - -void TsHttpRpc::_rpc_func_request_session(const Json::Value& json_param, ex_astr& buf) -{ - // https://github.com/tp4a/teleport/wiki/TELEPORT-CORE-JSON-RPC#request_session - - int conn_id = 0; - ex_rv rv = TPE_OK; - - if (json_param["conn_id"].isNull()) - { - _create_json_ret(buf, TPE_PARAM); - return; - } - if (!json_param["conn_id"].isInt()) - { - _create_json_ret(buf, TPE_PARAM); - return; - } - - conn_id = json_param["conn_id"].asInt(); - if (0 == conn_id) - { - _create_json_ret(buf, TPE_PARAM); - return; - } - - TS_CONNECT_INFO* info = new TS_CONNECT_INFO; - if ((rv = ts_web_rpc_get_conn_info(conn_id, *info)) != TPE_OK) - { - _create_json_ret(buf, rv); - return; - } - -// info->ref_count = 0; -// info->ticket_start = ex_get_tick_count(); -// - // 生成一个session-id(内部会避免重复) - ex_astr sid; - if (!g_session_mgr.request_session(sid, info)) { - _create_json_ret(buf, TPE_FAILED); - return; - } - - EXLOGD("[core] rpc new session-id: %s\n", sid.c_str()); - - Json::Value jr_data; - jr_data["sid"] = sid; - - _create_json_ret(buf, TPE_OK, jr_data); -} - -void TsHttpRpc::_rpc_func_kill_sessions(const Json::Value& json_param, ex_astr& buf) { - /* - { - "sessions": ["0123456", "ABCDEF", ...] - } - */ - - if (json_param.isArray()) { - _create_json_ret(buf, TPE_PARAM); - return; - } - - if (json_param["sessions"].isNull() || !json_param["sessions"].isArray()) { - _create_json_ret(buf, TPE_PARAM); - return; - } - - Json::Value s = json_param["sessions"]; - int cnt = s.size(); - for (int i = 0; i < cnt; ++i) { - if (!s[i].isString()) { - _create_json_ret(buf, TPE_PARAM); - return; - } - } - - EXLOGV("[core] try to kill %d sessions.\n", cnt); - ex_astr sp = s.toStyledString(); - g_tpp_mgr.kill_sessions(sp); - - _create_json_ret(buf, TPE_OK); -} - -void TsHttpRpc::_rpc_func_enc(const Json::Value& json_param, ex_astr& buf) -{ - // https://github.com/tp4a/teleport/wiki/TELEPORT-CORE-JSON-RPC#enc - // 加密一个字符串 [ p=plain-text, c=cipher-text ] - // 入参: {"p":"need be encrypt"} - // 示例: {"p":"this-is-a-password"} - // p: 被加密的字符串 - // 返回: - // data域中的"c"的内容是加密后密文的base64编码结果 - // 示例: {"code":0, "data":{"c":"Mxs340a9r3fs+3sdf=="}} - // 错误返回: {"code":1234} - - if (json_param.isArray()) - { - _create_json_ret(buf, TPE_PARAM); - return; - } - - ex_astr plain_text; - - if (json_param["p"].isNull() || !json_param["p"].isString()) - { - _create_json_ret(buf, TPE_PARAM); - return; - } - - plain_text = json_param["p"].asCString(); - if (plain_text.length() == 0) - { - _create_json_ret(buf, TPE_PARAM); - return; - } - ex_astr cipher_text; - - if (!ts_db_field_encrypt(plain_text, cipher_text)) - { - _create_json_ret(buf, TPE_FAILED); - return; - } - - Json::Value jr_data; - jr_data["c"] = cipher_text; - _create_json_ret(buf, TPE_OK, jr_data); -} - -void TsHttpRpc::_rpc_func_set_config(const Json::Value& json_param, ex_astr& buf) -{ - // https://github.com/tp4a/teleport/wiki/TELEPORT-CORE-JSON-RPC#set_config - /* - { - "noop-timeout": 15 # 按分钟计 - } - */ - - if (json_param.isArray()) { - _create_json_ret(buf, TPE_PARAM); - return; - } - - if (json_param["noop_timeout"].isNull() || !json_param["noop_timeout"].isUInt()) { - _create_json_ret(buf, TPE_PARAM); - return; - } - - int noop_timeout = json_param["noop_timeout"].asUInt(); - EXLOGV("[core] set run-time config:\n"); - EXLOGV("[core] noop_timeout = %dm\n", noop_timeout); - - ex_astr sp = json_param.toStyledString(); - g_tpp_mgr.set_runtime_config(sp); - - _create_json_ret(buf, TPE_OK); -} - - -/* -void TsHttpRpc::_rpc_func_enc(const Json::Value& json_param, ex_astr& buf) -{ - // https://github.com/tp4a/teleport/wiki/TELEPORT-CORE-JSON-RPC#enc - // 加密多个个字符串 [ p=plain-text, c=cipher-text ] - // 入参: {"p":["need be encrypt", "plain to cipher"]} - // 示例: {"p":["password-for-A"]} - // p: 被加密的字符串 - // 返回: - // data域中的"c"的内容是加密后密文的base64编码结果 - // 示例: {"code":0, "data":{"c":["Mxs340a9r3fs+3sdf=="]}} - // 错误返回: {"code":1234} - - if (json_param.isArray()) - { - _create_json_ret(buf, TPE_PARAM); - return; - } - - ex_astr plain_text; - - if (json_param["p"].isNull() || !json_param["p"].isArray()) - { - _create_json_ret(buf, TPE_PARAM); - return; - } - - Json::Value c; - - Json::Value p = json_param["p"]; - int cnt = p.size(); - for (int i = 0; i < cnt; ++i) - { - if (!p[i].isString()) { - _create_json_ret(buf, TPE_PARAM); - return; - } - - ex_astr p_txt = p[i].asCString(); - if (p_txt.length() == 0) { - c["c"].append(""); - } - - ex_astr c_txt; - if (!ts_db_field_encrypt(p_txt, c_txt)) - { - _create_json_ret(buf, TPE_FAILED); - return; - } - - c["c"].append(c_txt); - } - - Json::Value jr_data; - jr_data["c"] = c; - _create_json_ret(buf, TPE_OK, jr_data); -} -*/ +锘#include "ts_http_rpc.h" +#include "ts_ver.h" +#include "ts_env.h" +#include "ts_session.h" +#include "ts_crypto.h" +#include "ts_web_rpc.h" +#include "tp_tpp_mgr.h" + +extern TppManager g_tpp_mgr; + +#include + + +#define HEXTOI(x) (isdigit(x) ? x - '0' : x - 'W') +int ts_url_decode(const char *src, int src_len, char *dst, int dst_len, int is_form_url_encoded) +{ + int i, j, a, b; + + for (i = j = 0; i < src_len && j < dst_len - 1; i++, j++) + { + if (src[i] == '%') + { + if (i < src_len - 2 && isxdigit(*(const unsigned char *)(src + i + 1)) && + isxdigit(*(const unsigned char *)(src + i + 2))) { + a = tolower(*(const unsigned char *)(src + i + 1)); + b = tolower(*(const unsigned char *)(src + i + 2)); + dst[j] = (char)((HEXTOI(a) << 4) | HEXTOI(b)); + i += 2; + } + else + { + return -1; + } + } + else if (is_form_url_encoded && src[i] == '+') + { + dst[j] = ' '; + } + else + { + dst[j] = src[i]; + } + } + + dst[j] = '\0'; /* Null-terminate the destination */ + + return i >= src_len ? j : -1; +} + +TsHttpRpc::TsHttpRpc() : + ExThreadBase("http-rpc-thread") +{ + mg_mgr_init(&m_mg_mgr, NULL); +} + +TsHttpRpc::~TsHttpRpc() +{ + mg_mgr_free(&m_mg_mgr); +} + +void TsHttpRpc::_thread_loop(void) +{ + EXLOGI("[core] TeleportServer-RPC ready on %s:%d\n", m_host_ip.c_str(), m_host_port); + + while (!m_need_stop) + { + mg_mgr_poll(&m_mg_mgr, 500); + } + + EXLOGV("[core] rpc main loop end.\n"); +} + + +bool TsHttpRpc::init(void) +{ + struct mg_connection* nc = NULL; + + m_host_ip = g_env.rpc_bind_ip; + m_host_port = g_env.rpc_bind_port; + + char addr[128] = { 0 }; + // if (0 == strcmp(m_host_ip.c_str(), "127.0.0.1") || 0 == strcmp(m_host_ip.c_str(), "localhost")) + // ex_strformat(addr, 128, ":%d", m_host_port); + // else + // ex_strformat(addr, 128, "%s:%d", m_host_ip.c_str(), m_host_port); + if (0 == strcmp(m_host_ip.c_str(), "0.0.0.0")) + ex_strformat(addr, 128, ":%d", m_host_port); + else + ex_strformat(addr, 128, "%s:%d", m_host_ip.c_str(), m_host_port); + + nc = mg_bind(&m_mg_mgr, addr, _mg_event_handler); + if (NULL == nc) + { + EXLOGE("[core] rpc listener failed to bind at %s.\n", addr); + return false; + } + + nc->user_data = this; + + mg_set_protocol_http_websocket(nc); + + // 瀵艰嚧鍐呭瓨娉勯湶鐨勫湴鏂癸紙姣忔璇锋眰绾︽秷鑰1KB鍐呭瓨锛 + // DO NOT USE MULTITHREADING OF MG. + // cpq (one of the authors of MG) commented on 3 Feb: Multithreading support has been removed. + // https://github.com/cesanta/mongoose/commit/707b9ed2d6f177b3ad8787cb16a1bff90ddad992 + //mg_enable_multithreading(nc); + + return true; +} + +void TsHttpRpc::_mg_event_handler(struct mg_connection *nc, int ev, void *ev_data) +{ + struct http_message *hm = (struct http_message*)ev_data; + + TsHttpRpc* _this = (TsHttpRpc*)nc->user_data; + if (NULL == _this) + { + EXLOGE("[core] rpc invalid http request.\n"); + return; + } + + switch (ev) + { + case MG_EV_HTTP_REQUEST: + { + ex_astr ret_buf; + + ex_astr uri; + uri.assign(hm->uri.p, hm->uri.len); + + //EXLOGD("[core] rpc got request: %s\n", uri.c_str()); + + if (uri == "/rpc") + { + ex_astr method; + Json::Value json_param; + + ex_rv rv = _this->_parse_request(hm, method, json_param); + if (TPE_OK != rv) + { + EXLOGE("[core] rpc got invalid request.\n"); + _this->_create_json_ret(ret_buf, rv); + } + else + { + EXLOGD("[core] rpc got request method `%s`\n", method.c_str()); + _this->_process_request(method, json_param, ret_buf); + } + } + else + { + EXLOGE("[core] rpc got invalid request: not `rpc` uri.\n"); + _this->_create_json_ret(ret_buf, TPE_PARAM, "not a `rpc` request."); + } + + mg_printf(nc, "HTTP/1.0 200 OK\r\nAccess-Control-Allow-Origin: *\r\nContent-Length: %d\r\nContent-Type: application/json\r\n\r\n%s", (int)ret_buf.length(), &ret_buf[0]); + nc->flags |= MG_F_SEND_AND_CLOSE; + } + break; + default: + break; + } +} + +ex_rv TsHttpRpc::_parse_request(struct http_message* req, ex_astr& func_cmd, Json::Value& json_param) +{ + if (NULL == req) + return TPE_PARAM; + + 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_astr json_str; + bool need_decode = false; + if (is_get) { + json_str.assign(req->query_string.p, req->query_string.len); + need_decode = true; + } + else { + json_str.assign(req->body.p, req->body.len); + if (json_str.length() > 0 && json_str[0] == '%') + need_decode = true; + } + + if (need_decode) { + // 灏嗗弬鏁拌繘琛 url-decode 瑙g爜 + int len = json_str.length() * 2; + ex_chars sztmp; + sztmp.resize(len); + memset(&sztmp[0], 0, len); + if (-1 == ts_url_decode(json_str.c_str(), json_str.length(), &sztmp[0], len, 0)) + return TPE_HTTP_URL_ENCODE; + + json_str = &sztmp[0]; + } + + if (0 == json_str.length()) + return TPE_PARAM; + + //Json::Reader jreader; + Json::CharReaderBuilder jcrb; + std::unique_ptr const jreader(jcrb.newCharReader()); + const char *str_json_begin = json_str.c_str(); + ex_astr err; + + //if (!jreader.parse(json_str.c_str(), json_param)) + if (!jreader->parse(str_json_begin, str_json_begin + json_str.length(), &json_param, &err)) + return TPE_JSON_FORMAT; + + if (json_param.isArray()) + return TPE_PARAM; + + if (json_param["method"].isNull() || !json_param["method"].isString()) + return TPE_PARAM; + + func_cmd = json_param["method"].asCString(); + json_param = json_param["param"]; + + return TPE_OK; +} + +void TsHttpRpc::_create_json_ret(ex_astr& buf, int errcode, const Json::Value& jr_data) +{ + // 杩斿洖锛 {"code":errcode, "data":{jr_data}} + + //Json::FastWriter jr_writer; + Json::Value jr_root; + jr_root["code"] = errcode; + jr_root["data"] = jr_data; + //buf = jr_writer.write(jr_root); + Json::StreamWriterBuilder jwb; + std::unique_ptr jwriter(jwb.newStreamWriter()); + ex_aoss os; + jwriter->write(jr_root, &os); + buf = os.str(); +} + +void TsHttpRpc::_create_json_ret(ex_astr& buf, int errcode) +{ + // 杩斿洖锛 {"code":errcode} + + //Json::FastWriter jr_writer; + Json::Value jr_root; + jr_root["code"] = errcode; + //buf = jr_writer.write(jr_root); + Json::StreamWriterBuilder jwb; + std::unique_ptr jwriter(jwb.newStreamWriter()); + ex_aoss os; + jwriter->write(jr_root, &os); + buf = os.str(); +} + +void TsHttpRpc::_create_json_ret(ex_astr& buf, int errcode, const char* message) +{ + // 杩斿洖锛 {"code":errcode, "message":message} + + //Json::FastWriter jr_writer; + Json::Value jr_root; + jr_root["code"] = errcode; + jr_root["message"] = message; + //buf = jr_writer.write(jr_root); + Json::StreamWriterBuilder jwb; + std::unique_ptr jwriter(jwb.newStreamWriter()); + ex_aoss os; + jwriter->write(jr_root, &os); + buf = os.str(); +} + +void TsHttpRpc::_process_request(const ex_astr& func_cmd, const Json::Value& json_param, ex_astr& buf) +{ + if (func_cmd == "request_session") { + _rpc_func_request_session(json_param, buf); + } + else if (func_cmd == "kill_sessions") { + _rpc_func_kill_sessions(json_param, buf); + } + else if (func_cmd == "get_config") { + _rpc_func_get_config(json_param, buf); + } + else if (func_cmd == "set_config") { + _rpc_func_set_config(json_param, buf); + } + else if (func_cmd == "enc") { + _rpc_func_enc(json_param, buf); + } + else if (func_cmd == "exit") { + _rpc_func_exit(json_param, buf); + } + else { + EXLOGE("[core] rpc got unknown command: %s\n", func_cmd.c_str()); + _create_json_ret(buf, TPE_UNKNOWN_CMD); + } +} + +extern bool g_exit_flag; // 瑕佹眰鏁翠釜TS閫鍑虹殑鏍囧織锛堢敤浜庡仠姝㈠悇涓伐浣滅嚎绋嬶級 +void TsHttpRpc::_rpc_func_exit(const Json::Value& json_param, ex_astr& buf) +{ + // 璁剧疆涓涓叏灞閫鍑烘爣蹇 + g_exit_flag = true; + _create_json_ret(buf, TPE_OK); +} + +void TsHttpRpc::_rpc_func_get_config(const Json::Value& json_param, ex_astr& buf) +{ + Json::Value jr_data; + + ex_astr _replay_name; + ex_wstr2astr(g_env.m_replay_path, _replay_name); + jr_data["replay-path"] = _replay_name; + + jr_data["web-server-rpc"] = g_env.web_server_rpc; + + ex_astr _version; + ex_wstr2astr(TP_SERVER_VER, _version); + jr_data["version"] = _version; + + ExIniFile& ini = g_env.get_ini(); + ex_ini_sections& secs = ini.GetAllSections(); + ex_ini_sections::iterator it = secs.begin(); + for (; it != secs.end(); ++it) + { + if (it->first.length() > 9 && 0 == wcsncmp(it->first.c_str(), L"protocol-", 9)) + { + ex_wstr name; + name.assign(it->first, 9, it->first.length() - 9); + ex_astr _name; + ex_wstr2astr(name, _name); + + bool enabled = false; + it->second->GetBool(L"enabled", enabled, false); + + ex_wstr ip; + if (!it->second->GetStr(L"bind-ip", ip)) + continue; + ex_astr _ip; + ex_wstr2astr(ip, _ip); + + int port; + it->second->GetInt(L"bind-port", port, 52189); + + jr_data[_name.c_str()]["enable"] = enabled; + jr_data[_name.c_str()]["ip"] = _ip; + jr_data[_name.c_str()]["port"] = port; + } + } + + _create_json_ret(buf, TPE_OK, jr_data); +} + +void TsHttpRpc::_rpc_func_request_session(const Json::Value& json_param, ex_astr& buf) +{ + // https://github.com/tp4a/teleport/wiki/TELEPORT-CORE-JSON-RPC#request_session + + int conn_id = 0; + ex_rv rv = TPE_OK; + + if (json_param["conn_id"].isNull()) + { + _create_json_ret(buf, TPE_PARAM); + return; + } + if (!json_param["conn_id"].isInt()) + { + _create_json_ret(buf, TPE_PARAM); + return; + } + + conn_id = json_param["conn_id"].asInt(); + if (0 == conn_id) + { + _create_json_ret(buf, TPE_PARAM); + return; + } + + TS_CONNECT_INFO* info = new TS_CONNECT_INFO; + if ((rv = ts_web_rpc_get_conn_info(conn_id, *info)) != TPE_OK) + { + _create_json_ret(buf, rv); + return; + } + +// info->ref_count = 0; +// info->ticket_start = ex_get_tick_count(); +// + // 鐢熸垚涓涓猻ession-id锛堝唴閮ㄤ細閬垮厤閲嶅锛 + ex_astr sid; + if (!g_session_mgr.request_session(sid, info)) { + _create_json_ret(buf, TPE_FAILED); + return; + } + + EXLOGD("[core] rpc new session-id: %s\n", sid.c_str()); + + Json::Value jr_data; + jr_data["sid"] = sid; + + _create_json_ret(buf, TPE_OK, jr_data); +} + +void TsHttpRpc::_rpc_func_kill_sessions(const Json::Value& json_param, ex_astr& buf) { + /* + { + "sessions": ["0123456", "ABCDEF", ...] + } + */ + + if (json_param.isArray()) { + _create_json_ret(buf, TPE_PARAM); + return; + } + + if (json_param["sessions"].isNull() || !json_param["sessions"].isArray()) { + _create_json_ret(buf, TPE_PARAM); + return; + } + + Json::Value s = json_param["sessions"]; + int cnt = s.size(); + for (int i = 0; i < cnt; ++i) { + if (!s[i].isString()) { + _create_json_ret(buf, TPE_PARAM); + return; + } + } + + EXLOGV("[core] try to kill %d sessions.\n", cnt); + ex_astr sp = s.toStyledString(); + g_tpp_mgr.kill_sessions(sp); + + _create_json_ret(buf, TPE_OK); +} + +void TsHttpRpc::_rpc_func_enc(const Json::Value& json_param, ex_astr& buf) +{ + // https://github.com/tp4a/teleport/wiki/TELEPORT-CORE-JSON-RPC#enc + // 鍔犲瘑涓涓瓧绗︿覆 [ p=plain-text, c=cipher-text ] + // 鍏ュ弬: {"p":"need be encrypt"} + // 绀轰緥: {"p":"this-is-a-password"} + // p: 琚姞瀵嗙殑瀛楃涓 + // 杩斿洖锛 + // data鍩熶腑鐨"c"鐨勫唴瀹规槸鍔犲瘑鍚庡瘑鏂囩殑base64缂栫爜缁撴灉 + // 绀轰緥: {"code":0, "data":{"c":"Mxs340a9r3fs+3sdf=="}} + // 閿欒杩斿洖锛 {"code":1234} + + if (json_param.isArray()) + { + _create_json_ret(buf, TPE_PARAM); + return; + } + + ex_astr plain_text; + + if (json_param["p"].isNull() || !json_param["p"].isString()) + { + _create_json_ret(buf, TPE_PARAM); + return; + } + + plain_text = json_param["p"].asCString(); + if (plain_text.length() == 0) + { + _create_json_ret(buf, TPE_PARAM); + return; + } + ex_astr cipher_text; + + if (!ts_db_field_encrypt(plain_text, cipher_text)) + { + _create_json_ret(buf, TPE_FAILED); + return; + } + + Json::Value jr_data; + jr_data["c"] = cipher_text; + _create_json_ret(buf, TPE_OK, jr_data); +} + +void TsHttpRpc::_rpc_func_set_config(const Json::Value& json_param, ex_astr& buf) +{ + // https://github.com/tp4a/teleport/wiki/TELEPORT-CORE-JSON-RPC#set_config + /* + { + "noop-timeout": 15 # 鎸夊垎閽熻 + } + */ + + if (json_param.isArray()) { + _create_json_ret(buf, TPE_PARAM); + return; + } + + if (json_param["noop_timeout"].isNull() || !json_param["noop_timeout"].isUInt()) { + _create_json_ret(buf, TPE_PARAM); + return; + } + + int noop_timeout = json_param["noop_timeout"].asUInt(); + EXLOGV("[core] set run-time config:\n"); + EXLOGV("[core] noop_timeout = %dm\n", noop_timeout); + + ex_astr sp = json_param.toStyledString(); + g_tpp_mgr.set_runtime_config(sp); + + _create_json_ret(buf, TPE_OK); +} + + +/* +void TsHttpRpc::_rpc_func_enc(const Json::Value& json_param, ex_astr& buf) +{ + // https://github.com/tp4a/teleport/wiki/TELEPORT-CORE-JSON-RPC#enc + // 鍔犲瘑澶氫釜涓瓧绗︿覆 [ p=plain-text, c=cipher-text ] + // 鍏ュ弬: {"p":["need be encrypt", "plain to cipher"]} + // 绀轰緥: {"p":["password-for-A"]} + // p: 琚姞瀵嗙殑瀛楃涓 + // 杩斿洖锛 + // data鍩熶腑鐨"c"鐨勫唴瀹规槸鍔犲瘑鍚庡瘑鏂囩殑base64缂栫爜缁撴灉 + // 绀轰緥: {"code":0, "data":{"c":["Mxs340a9r3fs+3sdf=="]}} + // 閿欒杩斿洖锛 {"code":1234} + + if (json_param.isArray()) + { + _create_json_ret(buf, TPE_PARAM); + return; + } + + ex_astr plain_text; + + if (json_param["p"].isNull() || !json_param["p"].isArray()) + { + _create_json_ret(buf, TPE_PARAM); + return; + } + + Json::Value c; + + Json::Value p = json_param["p"]; + int cnt = p.size(); + for (int i = 0; i < cnt; ++i) + { + if (!p[i].isString()) { + _create_json_ret(buf, TPE_PARAM); + return; + } + + ex_astr p_txt = p[i].asCString(); + if (p_txt.length() == 0) { + c["c"].append(""); + } + + ex_astr c_txt; + if (!ts_db_field_encrypt(p_txt, c_txt)) + { + _create_json_ret(buf, TPE_FAILED); + return; + } + + c["c"].append(c_txt); + } + + Json::Value jr_data; + jr_data["c"] = c; + _create_json_ret(buf, TPE_OK, jr_data); +} +*/ diff --git a/server/tp_core/core/ts_web_rpc.cpp b/server/tp_core/core/ts_web_rpc.cpp index cf5b899..1ec813a 100644 --- a/server/tp_core/core/ts_web_rpc.cpp +++ b/server/tp_core/core/ts_web_rpc.cpp @@ -1,320 +1,359 @@ -#include "ts_web_rpc.h" -#include "ts_env.h" -#include "ts_crypto.h" -#include "ts_http_client.h" - -#include "../common/ts_const.h" - -#include -#include - -bool ts_web_rpc_register_core() -{ - Json::FastWriter json_writer; - Json::Value jreq; - jreq["method"] = "register_core"; - jreq["param"]["rpc"] = g_env.core_server_rpc; - - ex_astr json_param; - json_param = json_writer.write(jreq); - - ex_astr param; - ts_url_encode(json_param.c_str(), param); - - ex_astr url = g_env.web_server_rpc; - url += "?"; - url += param; - - ex_astr body; - return ts_http_get(url, body); -} - -int ts_web_rpc_get_conn_info(int conn_id, TS_CONNECT_INFO& info) -{ - Json::FastWriter json_writer; - Json::Value jreq; - jreq["method"] = "get_conn_info"; - jreq["param"]["conn_id"] = conn_id; - - ex_astr json_param; - json_param = json_writer.write(jreq); - - ex_astr param; - ts_url_encode(json_param.c_str(), param); - - ex_astr url = g_env.web_server_rpc; - url += "?"; - url += param; - - ex_astr body; - if (!ts_http_get(url, body)) - { - EXLOGE("[core] get conn info from web-server failed: can not connect to web-server.\n"); - return TPE_NETWORK; - } - if (body.length() == 0) { - EXLOGE("[core] get conn info from web-server failed: got nothing.\n"); - return TPE_NETWORK; - } - - Json::Reader jreader; - Json::Value jret; - - if (!jreader.parse(body.c_str(), jret)) - return TPE_PARAM; - if (!jret.isObject()) - return TPE_PARAM; - if (!jret["data"].isObject()) - return TPE_PARAM; - - Json::Value& _jret = jret["data"]; - - if(!_jret["user_id"].isInt()) - EXLOGE("connection info: need `user_id`.\n"); - if(!_jret["host_id"].isInt()) - EXLOGE("connection info: need `host_id`.\n"); - if(!_jret["acc_id"].isInt()) - EXLOGE("connection info: need `acc_id`.\n"); - if(!_jret["conn_port"].isInt()) - EXLOGE("connection info: need `conn_port`.\n"); - if(!_jret["protocol_type"].isInt()) - EXLOGE("connection info: need `protocol_type`.\n"); - if(!_jret["protocol_sub_type"].isInt()) - EXLOGE("connection info: need `protocol_sub_type`.\n"); - if(!_jret["auth_type"].isInt()) - EXLOGE("connection info: need `auth_type`.\n"); - if (!_jret["protocol_flag"].isUInt()) - EXLOGE("connection info: need `protocol_flag`.\n"); - if (!_jret["record_flag"].isUInt()) - EXLOGE("connection info: need `record_flag`.\n"); - if (!_jret["_enc"].isInt()) - EXLOGE("connection info: need `_enc`.\n"); - if(!_jret["user_username"].isString()) - EXLOGE("connection info: need `user_username`.\n"); - if(!_jret["host_ip"].isString()) - EXLOGE("connection info: need `host_ip`.\n"); - if(!_jret["conn_ip"].isString()) - EXLOGE("connection info: need `conn_ip`.\n"); - if(!_jret["client_ip"].isString()) - EXLOGE("connection info: need `client_ip`.\n"); - if(!_jret["acc_username"].isString()) - EXLOGE("connection info: need `acc_username`.\n"); - if(!_jret["acc_secret"].isString()) - EXLOGE("connection info: need `acc_secret`.\n"); - if(!_jret["username_prompt"].isString()) - EXLOGE("connection info: need `username_prompt`.\n"); - if(!_jret["password_prompt"].isString()) - EXLOGE("connection info: need `password_prompt`.\n"); - - if ( - !_jret["user_id"].isInt() - || !_jret["host_id"].isInt() - || !_jret["acc_id"].isInt() - || !_jret["conn_port"].isInt() - || !_jret["protocol_type"].isInt() - || !_jret["protocol_sub_type"].isInt() - || !_jret["auth_type"].isInt() - || !_jret["protocol_flag"].isUInt() - || !_jret["record_flag"].isUInt() - || !_jret["_enc"].isInt() - - || !_jret["user_username"].isString() - || !_jret["host_ip"].isString() - || !_jret["conn_ip"].isString() - || !_jret["client_ip"].isString() - || !_jret["acc_username"].isString() - || !_jret["acc_secret"].isString() - || !_jret["username_prompt"].isString() - || !_jret["password_prompt"].isString() - ) - { - EXLOGE("got connection info from web-server, but not all info valid.\n"); - return TPE_PARAM; - } - - int user_id; - int host_id; - int acc_id; - ex_astr user_username;// 申请本次连接的用户名 - ex_astr host_ip;// 真正的远程主机IP(如果是直接连接模式,则与remote_host_ip相同) - ex_astr conn_ip;// 要连接的远程主机的IP(如果是端口映射模式,则为路由主机的IP) - int conn_port;// 要连接的远程主机的端口(如果是端口映射模式,则为路由主机的端口) - ex_astr client_ip; - ex_astr acc_username; // 远程主机的账号 - ex_astr acc_secret;// 远程主机账号的密码(或者私钥) - ex_astr username_prompt; - ex_astr password_prompt; - int protocol_type = 0; - int protocol_sub_type = 0; - int auth_type = 0; - int protocol_flag = 0; - int record_flag = 0; - bool _enc; - - user_id = _jret["user_id"].asInt(); - host_id = _jret["host_id"].asInt(); - acc_id = _jret["acc_id"].asInt(); - user_username = _jret["user_username"].asString(); - host_ip = _jret["host_ip"].asString(); - conn_ip = _jret["conn_ip"].asString(); - conn_port = _jret["conn_port"].asInt(); - client_ip = _jret["client_ip"].asString(); - acc_username = _jret["acc_username"].asString(); - acc_secret = _jret["acc_secret"].asString(); - username_prompt = _jret["username_prompt"].asString(); - password_prompt = _jret["password_prompt"].asString(); - protocol_type = _jret["protocol_type"].asInt(); - protocol_sub_type = _jret["protocol_sub_type"].asInt(); - protocol_flag = _jret["protocol_flag"].asUInt(); - record_flag = _jret["record_flag"].asUInt(); - auth_type = _jret["auth_type"].asInt(); - _enc = _jret["_enc"].asBool(); - - - // 进一步判断参数是否合法 - // 注意,account_id可以为-1,表示这是一次测试连接。 - if (user_id <= 0 || host_id <= 0 - || user_username.length() == 0 - || host_ip.length() == 0 || conn_ip.length() == 0 || client_ip.length() == 0 - || conn_port <= 0 || conn_port >= 65535 - || acc_username.length() == 0 || acc_secret.length() == 0 - || !(protocol_type == TP_PROTOCOL_TYPE_RDP || protocol_type == TP_PROTOCOL_TYPE_SSH || protocol_type == TP_PROTOCOL_TYPE_TELNET) - || !(auth_type == TP_AUTH_TYPE_NONE || auth_type == TP_AUTH_TYPE_PASSWORD || auth_type == TP_AUTH_TYPE_PRIVATE_KEY) - ) - { - return TPE_PARAM; - } - - if (_enc) { - ex_astr _auth; - if (!ts_db_field_decrypt(acc_secret, _auth)) - return TPE_FAILED; - - acc_secret = _auth; - } - - info.user_id = user_id; - info.host_id = host_id; - info.acc_id = acc_id; - info.user_username = user_username; - info.host_ip = host_ip; - info.conn_ip = conn_ip; - info.conn_port = conn_port; - info.client_ip = client_ip; - info.acc_username = acc_username; - info.acc_secret = acc_secret; - info.username_prompt = username_prompt; - info.password_prompt = password_prompt; - info.protocol_type = protocol_type; - info.protocol_sub_type = protocol_sub_type; - info.auth_type = auth_type; - info.protocol_flag = protocol_flag; - info.record_flag = record_flag; - - return TPE_OK; -} - -bool ts_web_rpc_session_begin(TS_CONNECT_INFO& info, int& record_id) -{ - Json::FastWriter json_writer; - Json::Value jreq; - - jreq["method"] = "session_begin"; - jreq["param"]["sid"] = info.sid.c_str(); - jreq["param"]["user_id"] = info.user_id; - jreq["param"]["host_id"] = info.host_id; - jreq["param"]["acc_id"] = info.acc_id; - jreq["param"]["user_username"] = info.user_username.c_str(); - jreq["param"]["acc_username"] = info.acc_username.c_str(); - jreq["param"]["host_ip"] = info.host_ip.c_str(); - jreq["param"]["conn_ip"] = info.conn_ip.c_str(); - jreq["param"]["client_ip"] = info.client_ip.c_str(); - //jreq["param"]["sys_type"] = info.sys_type; - jreq["param"]["conn_port"] = info.conn_port; - jreq["param"]["auth_type"] = info.auth_type; - jreq["param"]["protocol_type"] = info.protocol_type; - jreq["param"]["protocol_sub_type"] = info.protocol_sub_type; - - ex_astr json_param; - json_param = json_writer.write(jreq); - - ex_astr param; - ts_url_encode(json_param.c_str(), param); - - ex_astr url = g_env.web_server_rpc; - url += "?"; - url += param; - - ex_astr body; - if (!ts_http_get(url, body)) - { - // EXLOGV("request `rpc::session_begin` from web return: "); - // EXLOGV(body.c_str()); - // EXLOGV("\n"); - return false; - } - - Json::Reader jreader; - Json::Value jret; - - if (!jreader.parse(body.c_str(), jret)) - return false; - if (!jret.isObject()) - return false; - if (!jret["data"].isObject()) - return false; - if (!jret["data"]["rid"].isUInt()) - return false; - - record_id = jret["data"]["rid"].asUInt(); - - return true; -} - -bool ts_web_rpc_session_update(int record_id, int protocol_sub_type, int state) { - Json::FastWriter json_writer; - Json::Value jreq; - jreq["method"] = "session_update"; - jreq["param"]["rid"] = record_id; - jreq["param"]["protocol_sub_type"] = protocol_sub_type; - jreq["param"]["code"] = state; - - ex_astr json_param; - json_param = json_writer.write(jreq); - - ex_astr param; - ts_url_encode(json_param.c_str(), param); - - ex_astr url = g_env.web_server_rpc; - url += "?"; - url += param; - - ex_astr body; - return ts_http_get(url, body); -} - - -//session 结束 -bool ts_web_rpc_session_end(const char* sid, int record_id, int ret_code) -{ - // TODO: 对指定的sid相关的会话的引用计数减一(但减到0时销毁) - - Json::FastWriter json_writer; - Json::Value jreq; - jreq["method"] = "session_end"; - jreq["param"]["rid"] = record_id; - jreq["param"]["code"] = ret_code; - - ex_astr json_param; - json_param = json_writer.write(jreq); - - ex_astr param; - ts_url_encode(json_param.c_str(), param); - - ex_astr url = g_env.web_server_rpc; - url += "?"; - url += param; - - ex_astr body; - return ts_http_get(url, body); -} +锘#include "ts_web_rpc.h" +#include "ts_env.h" +#include "ts_crypto.h" +#include "ts_http_client.h" + +#include "../common/ts_const.h" + +#include +#include + +bool ts_web_rpc_register_core() +{ + //Json::FastWriter json_writer; + Json::Value jreq; + jreq["method"] = "register_core"; + jreq["param"]["rpc"] = g_env.core_server_rpc; + + ex_astr json_param; + //json_param = json_writer.write(jreq); + Json::StreamWriterBuilder jwb; + std::unique_ptr jwriter(jwb.newStreamWriter()); + ex_aoss os; + jwriter->write(jreq, &os); + json_param = os.str(); + + ex_astr param; + ts_url_encode(json_param.c_str(), param); + + ex_astr url = g_env.web_server_rpc; + url += "?"; + url += param; + + ex_astr body; + return ts_http_get(url, body); +} + +int ts_web_rpc_get_conn_info(int conn_id, TS_CONNECT_INFO& info) +{ + //Json::FastWriter json_writer; + Json::Value jreq; + jreq["method"] = "get_conn_info"; + jreq["param"]["conn_id"] = conn_id; + + ex_astr json_param; + //json_param = json_writer.write(jreq); + Json::StreamWriterBuilder jwb; + std::unique_ptr jwriter(jwb.newStreamWriter()); + ex_aoss os; + jwriter->write(jreq, &os); + json_param = os.str(); + + ex_astr param; + ts_url_encode(json_param.c_str(), param); + + ex_astr url = g_env.web_server_rpc; + url += "?"; + url += param; + + ex_astr body; + if (!ts_http_get(url, body)) + { + EXLOGE("[core] get conn info from web-server failed: can not connect to web-server.\n"); + return TPE_NETWORK; + } + if (body.length() == 0) { + EXLOGE("[core] get conn info from web-server failed: got nothing.\n"); + return TPE_NETWORK; + } + + //Json::Reader jreader; + Json::Value jret; + + //if (!jreader.parse(body.c_str(), jret)) + Json::CharReaderBuilder jcrb; + std::unique_ptr const jreader(jcrb.newCharReader()); + const char *str_json_begin = body.c_str(); + ex_astr err; + + //if (!jreader.parse(func_args.c_str(), jsRoot)) { + if (!jreader->parse(str_json_begin, str_json_begin + body.length(), &jret, &err)) + return TPE_PARAM; + if (!jret.isObject()) + return TPE_PARAM; + if (!jret["data"].isObject()) + return TPE_PARAM; + + Json::Value& _jret = jret["data"]; + + if(!_jret["user_id"].isInt()) + EXLOGE("connection info: need `user_id`.\n"); + if(!_jret["host_id"].isInt()) + EXLOGE("connection info: need `host_id`.\n"); + if(!_jret["acc_id"].isInt()) + EXLOGE("connection info: need `acc_id`.\n"); + if(!_jret["conn_port"].isInt()) + EXLOGE("connection info: need `conn_port`.\n"); + if(!_jret["protocol_type"].isInt()) + EXLOGE("connection info: need `protocol_type`.\n"); + if(!_jret["protocol_sub_type"].isInt()) + EXLOGE("connection info: need `protocol_sub_type`.\n"); + if(!_jret["auth_type"].isInt()) + EXLOGE("connection info: need `auth_type`.\n"); + if (!_jret["protocol_flag"].isUInt()) + EXLOGE("connection info: need `protocol_flag`.\n"); + if (!_jret["record_flag"].isUInt()) + EXLOGE("connection info: need `record_flag`.\n"); + if (!_jret["_enc"].isInt()) + EXLOGE("connection info: need `_enc`.\n"); + if(!_jret["user_username"].isString()) + EXLOGE("connection info: need `user_username`.\n"); + if(!_jret["host_ip"].isString()) + EXLOGE("connection info: need `host_ip`.\n"); + if(!_jret["conn_ip"].isString()) + EXLOGE("connection info: need `conn_ip`.\n"); + if(!_jret["client_ip"].isString()) + EXLOGE("connection info: need `client_ip`.\n"); + if(!_jret["acc_username"].isString()) + EXLOGE("connection info: need `acc_username`.\n"); + if(!_jret["acc_secret"].isString()) + EXLOGE("connection info: need `acc_secret`.\n"); + if(!_jret["username_prompt"].isString()) + EXLOGE("connection info: need `username_prompt`.\n"); + if(!_jret["password_prompt"].isString()) + EXLOGE("connection info: need `password_prompt`.\n"); + + if ( + !_jret["user_id"].isInt() + || !_jret["host_id"].isInt() + || !_jret["acc_id"].isInt() + || !_jret["conn_port"].isInt() + || !_jret["protocol_type"].isInt() + || !_jret["protocol_sub_type"].isInt() + || !_jret["auth_type"].isInt() + || !_jret["protocol_flag"].isUInt() + || !_jret["record_flag"].isUInt() + || !_jret["_enc"].isInt() + + || !_jret["user_username"].isString() + || !_jret["host_ip"].isString() + || !_jret["conn_ip"].isString() + || !_jret["client_ip"].isString() + || !_jret["acc_username"].isString() + || !_jret["acc_secret"].isString() + || !_jret["username_prompt"].isString() + || !_jret["password_prompt"].isString() + ) + { + EXLOGE("got connection info from web-server, but not all info valid.\n"); + return TPE_PARAM; + } + + int user_id; + int host_id; + int acc_id; + ex_astr user_username;// 鐢宠鏈杩炴帴鐨勭敤鎴峰悕 + ex_astr host_ip;// 鐪熸鐨勮繙绋嬩富鏈篒P锛堝鏋滄槸鐩存帴杩炴帴妯″紡锛屽垯涓巖emote_host_ip鐩稿悓锛 + ex_astr conn_ip;// 瑕佽繛鎺ョ殑杩滅▼涓绘満鐨処P锛堝鏋滄槸绔彛鏄犲皠妯″紡锛屽垯涓鸿矾鐢变富鏈虹殑IP锛 + int conn_port;// 瑕佽繛鎺ョ殑杩滅▼涓绘満鐨勭鍙o紙濡傛灉鏄鍙f槧灏勬ā寮忥紝鍒欎负璺敱涓绘満鐨勭鍙o級 + ex_astr client_ip; + ex_astr acc_username; // 杩滅▼涓绘満鐨勮处鍙 + ex_astr acc_secret;// 杩滅▼涓绘満璐﹀彿鐨勫瘑鐮侊紙鎴栬呯閽ワ級 + ex_astr username_prompt; + ex_astr password_prompt; + int protocol_type = 0; + int protocol_sub_type = 0; + int auth_type = 0; + int protocol_flag = 0; + int record_flag = 0; + bool _enc; + + user_id = _jret["user_id"].asInt(); + host_id = _jret["host_id"].asInt(); + acc_id = _jret["acc_id"].asInt(); + user_username = _jret["user_username"].asString(); + host_ip = _jret["host_ip"].asString(); + conn_ip = _jret["conn_ip"].asString(); + conn_port = _jret["conn_port"].asInt(); + client_ip = _jret["client_ip"].asString(); + acc_username = _jret["acc_username"].asString(); + acc_secret = _jret["acc_secret"].asString(); + username_prompt = _jret["username_prompt"].asString(); + password_prompt = _jret["password_prompt"].asString(); + protocol_type = _jret["protocol_type"].asInt(); + protocol_sub_type = _jret["protocol_sub_type"].asInt(); + protocol_flag = _jret["protocol_flag"].asUInt(); + record_flag = _jret["record_flag"].asUInt(); + auth_type = _jret["auth_type"].asInt(); + _enc = _jret["_enc"].asBool(); + + + // 杩涗竴姝ュ垽鏂弬鏁版槸鍚﹀悎娉 + // 娉ㄦ剰锛宎ccount_id鍙互涓-1锛岃〃绀鸿繖鏄竴娆℃祴璇曡繛鎺ャ + if (user_id <= 0 || host_id <= 0 + || user_username.length() == 0 + || host_ip.length() == 0 || conn_ip.length() == 0 || client_ip.length() == 0 + || conn_port <= 0 || conn_port >= 65535 + || acc_username.length() == 0 || acc_secret.length() == 0 + || !(protocol_type == TP_PROTOCOL_TYPE_RDP || protocol_type == TP_PROTOCOL_TYPE_SSH || protocol_type == TP_PROTOCOL_TYPE_TELNET) + || !(auth_type == TP_AUTH_TYPE_NONE || auth_type == TP_AUTH_TYPE_PASSWORD || auth_type == TP_AUTH_TYPE_PRIVATE_KEY) + ) + { + return TPE_PARAM; + } + + if (_enc) { + ex_astr _auth; + if (!ts_db_field_decrypt(acc_secret, _auth)) + return TPE_FAILED; + + acc_secret = _auth; + } + + info.user_id = user_id; + info.host_id = host_id; + info.acc_id = acc_id; + info.user_username = user_username; + info.host_ip = host_ip; + info.conn_ip = conn_ip; + info.conn_port = conn_port; + info.client_ip = client_ip; + info.acc_username = acc_username; + info.acc_secret = acc_secret; + info.username_prompt = username_prompt; + info.password_prompt = password_prompt; + info.protocol_type = protocol_type; + info.protocol_sub_type = protocol_sub_type; + info.auth_type = auth_type; + info.protocol_flag = protocol_flag; + info.record_flag = record_flag; + + return TPE_OK; +} + +bool ts_web_rpc_session_begin(TS_CONNECT_INFO& info, int& record_id) +{ + //Json::FastWriter json_writer; + Json::Value jreq; + + jreq["method"] = "session_begin"; + jreq["param"]["sid"] = info.sid.c_str(); + jreq["param"]["user_id"] = info.user_id; + jreq["param"]["host_id"] = info.host_id; + jreq["param"]["acc_id"] = info.acc_id; + jreq["param"]["user_username"] = info.user_username.c_str(); + jreq["param"]["acc_username"] = info.acc_username.c_str(); + jreq["param"]["host_ip"] = info.host_ip.c_str(); + jreq["param"]["conn_ip"] = info.conn_ip.c_str(); + jreq["param"]["client_ip"] = info.client_ip.c_str(); + //jreq["param"]["sys_type"] = info.sys_type; + jreq["param"]["conn_port"] = info.conn_port; + jreq["param"]["auth_type"] = info.auth_type; + jreq["param"]["protocol_type"] = info.protocol_type; + jreq["param"]["protocol_sub_type"] = info.protocol_sub_type; + + ex_astr json_param; + //json_param = json_writer.write(jreq); + Json::StreamWriterBuilder jwb; + std::unique_ptr jwriter(jwb.newStreamWriter()); + ex_aoss os; + jwriter->write(jreq, &os); + json_param = os.str(); + + ex_astr param; + ts_url_encode(json_param.c_str(), param); + + ex_astr url = g_env.web_server_rpc; + url += "?"; + url += param; + + ex_astr body; + if (!ts_http_get(url, body)) + { + // EXLOGV("request `rpc::session_begin` from web return: "); + // EXLOGV(body.c_str()); + // EXLOGV("\n"); + return false; + } + + //Json::Reader jreader; + Json::Value jret; + + //if (!jreader.parse(body.c_str(), jret)) + Json::CharReaderBuilder jcrb; + std::unique_ptr const jreader(jcrb.newCharReader()); + const char *str_json_begin = body.c_str(); + ex_astr err; + + //if (!jreader.parse(func_args.c_str(), jsRoot)) { + if (!jreader->parse(str_json_begin, str_json_begin + body.length(), &jret, &err)) + return false; + if (!jret.isObject()) + return false; + if (!jret["data"].isObject()) + return false; + if (!jret["data"]["rid"].isUInt()) + return false; + + record_id = jret["data"]["rid"].asUInt(); + + return true; +} + +bool ts_web_rpc_session_update(int record_id, int protocol_sub_type, int state) { + //Json::FastWriter json_writer; + Json::Value jreq; + jreq["method"] = "session_update"; + jreq["param"]["rid"] = record_id; + jreq["param"]["protocol_sub_type"] = protocol_sub_type; + jreq["param"]["code"] = state; + + ex_astr json_param; + //json_param = json_writer.write(jreq); + Json::StreamWriterBuilder jwb; + std::unique_ptr jwriter(jwb.newStreamWriter()); + ex_aoss os; + jwriter->write(jreq, &os); + json_param = os.str(); + + ex_astr param; + ts_url_encode(json_param.c_str(), param); + + ex_astr url = g_env.web_server_rpc; + url += "?"; + url += param; + + ex_astr body; + return ts_http_get(url, body); +} + + +//session 缁撴潫 +bool ts_web_rpc_session_end(const char* sid, int record_id, int ret_code) +{ + // TODO: 瀵规寚瀹氱殑sid鐩稿叧鐨勪細璇濈殑寮曠敤璁℃暟鍑忎竴锛堜絾鍑忓埌0鏃堕攢姣侊級 + + //Json::FastWriter json_writer; + Json::Value jreq; + jreq["method"] = "session_end"; + jreq["param"]["rid"] = record_id; + jreq["param"]["code"] = ret_code; + + ex_astr json_param; + //json_param = json_writer.write(jreq); + Json::StreamWriterBuilder jwb; + std::unique_ptr jwriter(jwb.newStreamWriter()); + ex_aoss os; + jwriter->write(jreq, &os); + json_param = os.str(); + + ex_astr param; + ts_url_encode(json_param.c_str(), param); + + ex_astr url = g_env.web_server_rpc; + url += "?"; + url += param; + + ex_astr body; + return ts_http_get(url, body); +}