From b1524fd6a08e36236c54ac47f8c8b5fd337bab82 Mon Sep 17 00:00:00 2001 From: Apex Liu Date: Sat, 3 Nov 2018 14:11:02 +0800 Subject: [PATCH] try to fix thread problem when use libuv. --- common/libex/include/ex/ex_thread.h | 10 +- common/libex/src/ex_thread.cpp | 253 ++-- server/.idea/encodings.xml | 7 +- server/CMakeLists.txt | 7 +- server/tp_core/core/main.cpp | 3 +- server/tp_core/core/ts_http_rpc.cpp | 6 +- server/tp_core/core/ts_http_rpc.h | 1 - server/tp_core/core/ts_main.cpp | 270 ++-- server/tp_core/core/ts_session.cpp | 286 ++-- server/tp_core/core/ts_session.h | 3 - server/tp_core/protocol/telnet/CMakeLists.txt | 12 +- .../tp_core/protocol/telnet/telnet_conn.cpp | 215 +-- server/tp_core/protocol/telnet/telnet_conn.h | 56 +- .../tp_core/protocol/telnet/telnet_proxy.cpp | 331 ++--- server/tp_core/protocol/telnet/telnet_proxy.h | 74 +- .../protocol/telnet/telnet_session.cpp | 1243 ++++++++--------- 16 files changed, 1355 insertions(+), 1422 deletions(-) diff --git a/common/libex/include/ex/ex_thread.h b/common/libex/include/ex/ex_thread.h index 9c66e35..f3d4170 100644 --- a/common/libex/include/ex/ex_thread.h +++ b/common/libex/include/ex/ex_thread.h @@ -31,10 +31,12 @@ public: bool terminate(void); protected: - // 线程循环 + // main loop of this thread. virtual void _thread_loop(void) = 0; - // 设置停止标志,让线程能够正常结束 - virtual void _set_stop_flag(void) = 0; + // called by another thread when thread ready to stop. + virtual void _on_stop(void) {}; + // called inside thread when thread fully stopped. + virtual void _on_stopped(void) {}; #ifdef EX_OS_WIN32 static unsigned int WINAPI _thread_func(LPVOID lpParam); @@ -46,7 +48,7 @@ protected: ex_astr m_thread_name; EX_THREAD_HANDLE m_handle; bool m_is_running; - bool m_stop_flag; + bool m_need_stop; }; diff --git a/common/libex/src/ex_thread.cpp b/common/libex/src/ex_thread.cpp index 3641a92..e3a8089 100644 --- a/common/libex/src/ex_thread.cpp +++ b/common/libex/src/ex_thread.cpp @@ -9,90 +9,91 @@ #ifdef EX_OS_WIN32 unsigned int WINAPI ExThreadBase::_thread_func(LPVOID pParam) #else -void* ExThreadBase::_thread_func(void* pParam) + +void *ExThreadBase::_thread_func(void *pParam) #endif { - ExThreadBase* p = (ExThreadBase*)pParam; - ex_astr thread_name = p->m_thread_name; - p->m_is_running = true; - p->_thread_loop(); - p->m_is_running = false; -// if(!p->m_stop_by_request) -// p->m_thread_manager->_remove_thread(p); + ExThreadBase *_this = (ExThreadBase *) pParam; - EXLOGV(" # thread [%s] end.\n", thread_name.c_str()); + _this->m_is_running = true; + _this->_thread_loop(); + _this->m_is_running = false; + _this->m_handle = 0; - return 0; + _this->_on_stopped(); + + EXLOGV(" # thread [%s] exit.\n", _this->m_thread_name.c_str()); + return 0; } -ExThreadBase::ExThreadBase(const char* thread_name) : - m_handle(0), - m_is_running(false), - m_stop_flag(false) -{ - m_thread_name = thread_name; +ExThreadBase::ExThreadBase(const char *thread_name) : + m_handle(0), + m_is_running(false), + m_need_stop(false) { + m_thread_name = thread_name; } -ExThreadBase::~ExThreadBase() -{ +ExThreadBase::~ExThreadBase() { + if(m_is_running) { + EXLOGE(" # thread [%s] not stop before destroy.\n", m_thread_name.c_str()); + } } -bool ExThreadBase::start(void) -{ - EXLOGV(" . thread [%s] starting.\n", m_thread_name.c_str()); +bool ExThreadBase::start(void) { + m_need_stop = false; + EXLOGV(" . thread [%s] starting.\n", m_thread_name.c_str()); #ifdef WIN32 - HANDLE h = (HANDLE)_beginthreadex(NULL, 0, _thread_func, (void*)this, 0, NULL); + HANDLE h = (HANDLE)_beginthreadex(NULL, 0, _thread_func, (void*)this, 0, NULL); - if (NULL == h) - { - return false; - } - m_handle = h; + if (NULL == h) + { + return false; + } + m_listener_handle = h; #else - pthread_t ptid = 0; - int ret = pthread_create(&ptid, NULL, _thread_func, (void*)this); - if (ret != 0) - { - return false; - } - m_handle = ptid; + pthread_t ptid = 0; + int ret = pthread_create(&ptid, NULL, _thread_func, (void *) this); + if (ret != 0) { + return false; + } + m_handle = ptid; #endif - return true; + return true; } -bool ExThreadBase::stop(void) -{ - EXLOGV("[thread] try to stop thread [%s].\n", m_thread_name.c_str()); - _set_stop_flag(); +bool ExThreadBase::stop(void) { + if (m_handle == 0) { + EXLOGW("[thread] thread [%s] already stopped.\n", m_thread_name.c_str()); + return true; + } - EXLOGV("[thread] wait thread [%s] end.\n", m_thread_name.c_str()); + EXLOGV("[thread] try to stop thread [%s].\n", m_thread_name.c_str()); + m_need_stop = true; + _on_stop(); - if(m_handle == 0) - return true; + EXLOGV("[thread] wait thread [%s] exit.\n", m_thread_name.c_str()); #ifdef EX_OS_WIN32 - if (WaitForSingleObject(m_handle, INFINITE) != WAIT_OBJECT_0) - { - return false; - } + if (WaitForSingleObject(m_listener_handle, INFINITE) != WAIT_OBJECT_0) + { + return false; + } #else - if (pthread_join(m_handle, NULL) != 0) - { - return false; - } + if (pthread_join(m_handle, NULL) != 0) { + return false; + } #endif - return true; + return true; } -bool ExThreadBase::terminate(void) -{ +bool ExThreadBase::terminate(void) { #ifdef EX_OS_WIN32 - return TerminateThread(m_handle, 1) ? true : false; + return (TerminateThread(m_listener_handle, 1) == TRUE); #else - return pthread_cancel(m_handle) == 0 ? true : false; + return (pthread_cancel(m_handle) == 0); #endif } @@ -100,105 +101,89 @@ bool ExThreadBase::terminate(void) // //========================================================= -ExThreadManager::ExThreadManager() -{} +ExThreadManager::ExThreadManager() {} -ExThreadManager::~ExThreadManager() -{ - if (m_threads.size() > 0) - { - EXLOGE("when destroy thread manager, there are %d thread not exit.\n", m_threads.size()); - stop_all(); - } +ExThreadManager::~ExThreadManager() { + if (!m_threads.empty()) { + EXLOGE("when destroy thread manager, there are %d thread not exit.\n", m_threads.size()); + stop_all(); + } } -void ExThreadManager::stop_all(void) -{ - ExThreadSmartLock locker(m_lock); +void ExThreadManager::stop_all(void) { + ExThreadSmartLock locker(m_lock); - ex_threads::iterator it = m_threads.begin(); - for (; it != m_threads.end(); ++it) - { - (*it)->stop(); - } - m_threads.clear(); + ex_threads::iterator it = m_threads.begin(); + for (; it != m_threads.end(); ++it) { + (*it)->stop(); + } + m_threads.clear(); } -void ExThreadManager::add(ExThreadBase* tb) -{ - ExThreadSmartLock locker(m_lock); +void ExThreadManager::add(ExThreadBase *tb) { + ExThreadSmartLock locker(m_lock); - ex_threads::iterator it = m_threads.begin(); - for (; it != m_threads.end(); ++it) - { - if ((*it) == tb) - { - EXLOGE("when add thread to manager, it already exist.\n"); - return; - } - } + ex_threads::iterator it = m_threads.begin(); + for (; it != m_threads.end(); ++it) { + if ((*it) == tb) { + EXLOGE("when add thread to manager, it already exist.\n"); + return; + } + } - m_threads.push_back(tb); + m_threads.push_back(tb); } -void ExThreadManager::remove(ExThreadBase* tb) -{ - ExThreadSmartLock locker(m_lock); +void ExThreadManager::remove(ExThreadBase *tb) { + ExThreadSmartLock locker(m_lock); - ex_threads::iterator it = m_threads.begin(); - for (; it != m_threads.end(); ++it) - { - if ((*it) == tb) - { - //delete (*it); - m_threads.erase(it); - return; - } - } - EXLOGE("when remove thread from manager, it not exist.\n"); + ex_threads::iterator it = m_threads.begin(); + for (; it != m_threads.end(); ++it) { + if ((*it) == tb) { + m_threads.erase(it); + return; + } + } + EXLOGE("thread not hold by thread-manager while remove it.\n"); } //========================================================= // //========================================================= -ExThreadLock::ExThreadLock() -{ +ExThreadLock::ExThreadLock() { #ifdef EX_OS_WIN32 - InitializeCriticalSection(&m_locker); + InitializeCriticalSection(&m_locker); #else - pthread_mutexattr_t attr; - pthread_mutexattr_init(&attr); - pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); - pthread_mutex_init(&m_locker, &attr); - pthread_mutexattr_destroy(&attr); + pthread_mutexattr_t attr; + pthread_mutexattr_init(&attr); + pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); + pthread_mutex_init(&m_locker, &attr); + pthread_mutexattr_destroy(&attr); #endif } -ExThreadLock::~ExThreadLock() -{ +ExThreadLock::~ExThreadLock() { #ifdef EX_OS_WIN32 - DeleteCriticalSection(&m_locker); + DeleteCriticalSection(&m_locker); #else - pthread_mutex_destroy(&m_locker); + pthread_mutex_destroy(&m_locker); #endif } -void ExThreadLock::lock(void) -{ +void ExThreadLock::lock(void) { #ifdef EX_OS_WIN32 - EnterCriticalSection(&m_locker); + EnterCriticalSection(&m_locker); #else - pthread_mutex_lock(&m_locker); + pthread_mutex_lock(&m_locker); #endif } -void ExThreadLock::unlock(void) -{ +void ExThreadLock::unlock(void) { #ifdef EX_OS_WIN32 - LeaveCriticalSection(&m_locker); + LeaveCriticalSection(&m_locker); #else - pthread_mutex_unlock(&m_locker); + pthread_mutex_unlock(&m_locker); #endif } @@ -206,39 +191,35 @@ void ExThreadLock::unlock(void) // //========================================================= -int ex_atomic_add(volatile int* pt, int t) -{ +int ex_atomic_add(volatile int *pt, int t) { #ifdef EX_OS_WIN32 - return (int)InterlockedExchangeAdd((long*)pt, (long)t); + return (int)InterlockedExchangeAdd((long*)pt, (long)t); #else - return __sync_add_and_fetch(pt, t); + return __sync_add_and_fetch(pt, t); #endif } -int ex_atomic_inc(volatile int* pt) -{ +int ex_atomic_inc(volatile int *pt) { #ifdef EX_OS_WIN32 - return (int)InterlockedIncrement((long*)pt); + return (int)InterlockedIncrement((long*)pt); #else - return __sync_add_and_fetch(pt, 1); + return __sync_add_and_fetch(pt, 1); #endif } -int ex_atomic_dec(volatile int* pt) -{ +int ex_atomic_dec(volatile int *pt) { #ifdef EX_OS_WIN32 - return (int)InterlockedDecrement((long*)pt); + return (int)InterlockedDecrement((long*)pt); #else - return __sync_add_and_fetch(pt, -1); + return __sync_add_and_fetch(pt, -1); #endif } -ex_u64 ex_get_thread_id(void) -{ +ex_u64 ex_get_thread_id(void) { #ifdef EX_OS_WIN32 - return GetCurrentThreadId(); + return GetCurrentThreadId(); #else - return (ex_u64)pthread_self(); + return (ex_u64) pthread_self(); #endif } diff --git a/server/.idea/encodings.xml b/server/.idea/encodings.xml index 6230eb5..de095c5 100644 --- a/server/.idea/encodings.xml +++ b/server/.idea/encodings.xml @@ -31,11 +31,9 @@ - - - + @@ -43,7 +41,10 @@ + + + diff --git a/server/CMakeLists.txt b/server/CMakeLists.txt index 92b3a9e..5b06ff7 100644 --- a/server/CMakeLists.txt +++ b/server/CMakeLists.txt @@ -4,7 +4,8 @@ project(teleport) MESSAGE(STATUS "operation system is ${CMAKE_SYSTEM}") MESSAGE(STATUS "current source directory is ${CMAKE_CURRENT_SOURCE_DIR}") -set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${teleport_SOURCE_DIR}/../out/server/x64/bin") +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/../out/server/x64/bin") +set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/../out/server/x64/bin") set(CMAKE_CONFIGURATION_TYPES Debug Release) @@ -13,13 +14,13 @@ if("${CMAKE_SYSTEM_NAME}" STREQUAL "Darwin") MESSAGE(STATUS "build on macOS...") set(OS_MACOS 1) set(OS_POSIX 1) - set(TP_EXTERNAL_RELEASE_DIR "${teleport_SOURCE_DIR}/../external/macos/release") + set(TP_EXTERNAL_RELEASE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../external/macos/release") elseif("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux") set(OS_LINUX 1) set(OS_POSIX 1) MESSAGE(STATUS "build on Linux...") add_subdirectory(tp_web/src) - set(TP_EXTERNAL_RELEASE_DIR "${teleport_SOURCE_DIR}/../external/linux/release") + set(TP_EXTERNAL_RELEASE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../external/linux/release") elseif("${CMAKE_SYSTEM_NAME}" STREQUAL "Windows") MESSAGE(FATAL_ERROR "unsupported platform: Windows") else() diff --git a/server/tp_core/core/main.cpp b/server/tp_core/core/main.cpp index 5e89d56..acc8ea7 100644 --- a/server/tp_core/core/main.cpp +++ b/server/tp_core/core/main.cpp @@ -359,9 +359,8 @@ void _sig_handler(int signum, siginfo_t* info, void* ptr) { if (signum == SIGINT || signum == SIGTERM) { - EXLOGW("[core] received signal SIGINT, exit now.\n"); + EXLOGW("\n[core] received signal SIGINT, exit now.\n"); g_exit_flag = true; - // exit(1); } } diff --git a/server/tp_core/core/ts_http_rpc.cpp b/server/tp_core/core/ts_http_rpc.cpp index 7ab2264..91ae096 100644 --- a/server/tp_core/core/ts_http_rpc.cpp +++ b/server/tp_core/core/ts_http_rpc.cpp @@ -62,7 +62,7 @@ void TsHttpRpc::_thread_loop(void) { EXLOGI("[core] TeleportServer-RPC ready on %s:%d\n", m_host_ip.c_str(), m_host_port); - while (!m_stop_flag) + while (!m_need_stop) { mg_mgr_poll(&m_mg_mgr, 500); } @@ -70,10 +70,6 @@ void TsHttpRpc::_thread_loop(void) EXLOGV("[core] rpc main loop end.\n"); } -void TsHttpRpc::_set_stop_flag(void) -{ - m_stop_flag = true; -} bool TsHttpRpc::init(void) { diff --git a/server/tp_core/core/ts_http_rpc.h b/server/tp_core/core/ts_http_rpc.h index c99c241..fc19d2e 100644 --- a/server/tp_core/core/ts_http_rpc.h +++ b/server/tp_core/core/ts_http_rpc.h @@ -20,7 +20,6 @@ public: protected: void _thread_loop(void); - void _set_stop_flag(void); private: ex_rv _parse_request(struct http_message* req, ex_astr& func_cmd, Json::Value& json_param); diff --git a/server/tp_core/core/ts_main.cpp b/server/tp_core/core/ts_main.cpp index e8dfb44..1d7e8b6 100644 --- a/server/tp_core/core/ts_main.cpp +++ b/server/tp_core/core/ts_main.cpp @@ -10,96 +10,93 @@ bool g_exit_flag = false; -TPP_CONNECT_INFO* tpp_get_connect_info(const char* sid) -{ - TS_CONNECT_INFO sinfo; - bool ret = g_session_mgr.get_connect_info(sid, sinfo); - if (!ret) - return NULL; +TPP_CONNECT_INFO *tpp_get_connect_info(const char *sid) { + TS_CONNECT_INFO sinfo; + bool ret = g_session_mgr.get_connect_info(sid, sinfo); + if (!ret) + return NULL; - TPP_CONNECT_INFO* info = (TPP_CONNECT_INFO*)calloc(1, sizeof(TPP_CONNECT_INFO)); - - info->sid = (char*)calloc(1, sinfo.sid.length() + 1); - ex_strcpy(info->sid, sinfo.sid.length() + 1, sinfo.sid.c_str()); - info->user_username = (char*)calloc(1, sinfo.user_username.length() + 1); - ex_strcpy(info->user_username, sinfo.user_username.length() + 1, sinfo.user_username.c_str()); - info->host_ip = (char*)calloc(1, sinfo.host_ip.length() + 1); - ex_strcpy(info->host_ip, sinfo.host_ip.length() + 1, sinfo.host_ip.c_str()); - info->conn_ip = (char*)calloc(1, sinfo.conn_ip.length() + 1); - ex_strcpy(info->conn_ip, sinfo.conn_ip.length() + 1, sinfo.conn_ip.c_str()); - info->client_ip = (char*)calloc(1, sinfo.client_ip.length() + 1); - ex_strcpy(info->client_ip, sinfo.client_ip.length() + 1, sinfo.client_ip.c_str()); - info->acc_username = (char*)calloc(1, sinfo.acc_username.length() + 1); - ex_strcpy(info->acc_username, sinfo.acc_username.length() + 1, sinfo.acc_username.c_str()); - info->acc_secret = (char*)calloc(1, sinfo.acc_secret.length() + 1); - ex_strcpy(info->acc_secret, sinfo.acc_secret.length() + 1, sinfo.acc_secret.c_str()); - info->username_prompt = (char*)calloc(1, sinfo.username_prompt.length() + 1); - ex_strcpy(info->username_prompt, sinfo.username_prompt.length() + 1, sinfo.username_prompt.c_str()); - info->password_prompt = (char*)calloc(1, sinfo.password_prompt.length() + 1); - ex_strcpy(info->password_prompt, sinfo.password_prompt.length() + 1, sinfo.password_prompt.c_str()); + TPP_CONNECT_INFO *info = (TPP_CONNECT_INFO *) calloc(1, sizeof(TPP_CONNECT_INFO)); - info->user_id = sinfo.user_id; - info->host_id = sinfo.host_id; - info->acc_id = sinfo.acc_id; - info->conn_port = sinfo.conn_port; - info->protocol_type = sinfo.protocol_type; - info->protocol_sub_type = sinfo.protocol_sub_type; - info->protocol_flag = sinfo.protocol_flag; - info->record_flag = sinfo.record_flag; - info->auth_type= sinfo.auth_type; + info->sid = (char *) calloc(1, sinfo.sid.length() + 1); + ex_strcpy(info->sid, sinfo.sid.length() + 1, sinfo.sid.c_str()); + info->user_username = (char *) calloc(1, sinfo.user_username.length() + 1); + ex_strcpy(info->user_username, sinfo.user_username.length() + 1, sinfo.user_username.c_str()); + info->host_ip = (char *) calloc(1, sinfo.host_ip.length() + 1); + ex_strcpy(info->host_ip, sinfo.host_ip.length() + 1, sinfo.host_ip.c_str()); + info->conn_ip = (char *) calloc(1, sinfo.conn_ip.length() + 1); + ex_strcpy(info->conn_ip, sinfo.conn_ip.length() + 1, sinfo.conn_ip.c_str()); + info->client_ip = (char *) calloc(1, sinfo.client_ip.length() + 1); + ex_strcpy(info->client_ip, sinfo.client_ip.length() + 1, sinfo.client_ip.c_str()); + info->acc_username = (char *) calloc(1, sinfo.acc_username.length() + 1); + ex_strcpy(info->acc_username, sinfo.acc_username.length() + 1, sinfo.acc_username.c_str()); + info->acc_secret = (char *) calloc(1, sinfo.acc_secret.length() + 1); + ex_strcpy(info->acc_secret, sinfo.acc_secret.length() + 1, sinfo.acc_secret.c_str()); + info->username_prompt = (char *) calloc(1, sinfo.username_prompt.length() + 1); + ex_strcpy(info->username_prompt, sinfo.username_prompt.length() + 1, sinfo.username_prompt.c_str()); + info->password_prompt = (char *) calloc(1, sinfo.password_prompt.length() + 1); + ex_strcpy(info->password_prompt, sinfo.password_prompt.length() + 1, sinfo.password_prompt.c_str()); - return info; + info->user_id = sinfo.user_id; + info->host_id = sinfo.host_id; + info->acc_id = sinfo.acc_id; + info->conn_port = sinfo.conn_port; + info->protocol_type = sinfo.protocol_type; + info->protocol_sub_type = sinfo.protocol_sub_type; + info->protocol_flag = sinfo.protocol_flag; + info->record_flag = sinfo.record_flag; + info->auth_type = sinfo.auth_type; + + return info; } -void tpp_free_connect_info(TPP_CONNECT_INFO* info) -{ - if (NULL == info) - return; +void tpp_free_connect_info(TPP_CONNECT_INFO *info) { + if (NULL == info) + return; - g_session_mgr.free_connect_info(info->sid); + g_session_mgr.free_connect_info(info->sid); - free(info->sid); - free(info->user_username); - free(info->host_ip); - free(info->conn_ip); - free(info->client_ip); - free(info->acc_username); - free(info->acc_secret); - free(info->username_prompt); - free(info->password_prompt); - free(info); + free(info->sid); + free(info->user_username); + free(info->host_ip); + free(info->conn_ip); + free(info->client_ip); + free(info->acc_username); + free(info->acc_secret); + free(info->username_prompt); + free(info->password_prompt); + free(info); } -bool tpp_session_begin(const TPP_CONNECT_INFO* info, int* db_id) -{ - if (NULL == info || NULL == db_id) - return false; +bool tpp_session_begin(const TPP_CONNECT_INFO *info, int *db_id) { + if (NULL == info || NULL == db_id) + return false; - TS_CONNECT_INFO sinfo; - sinfo.sid = info->sid; - sinfo.user_id = info->user_id; - sinfo.host_id = info->host_id; - sinfo.acc_id = info->acc_id; - sinfo.user_username = info->user_username; - sinfo.host_ip = info->host_ip; - sinfo.conn_ip = info->conn_ip; - sinfo.client_ip = info->client_ip; - sinfo.acc_username = info->acc_username; + TS_CONNECT_INFO sinfo; + sinfo.sid = info->sid; + sinfo.user_id = info->user_id; + sinfo.host_id = info->host_id; + sinfo.acc_id = info->acc_id; + sinfo.user_username = info->user_username; + sinfo.host_ip = info->host_ip; + sinfo.conn_ip = info->conn_ip; + sinfo.client_ip = info->client_ip; + sinfo.acc_username = info->acc_username; - sinfo.conn_port = info->conn_port; - sinfo.protocol_type = info->protocol_type; - sinfo.protocol_sub_type = info->protocol_sub_type; - sinfo.auth_type = info->auth_type; + sinfo.conn_port = info->conn_port; + sinfo.protocol_type = info->protocol_type; + sinfo.protocol_sub_type = info->protocol_sub_type; + sinfo.auth_type = info->auth_type; - return ts_web_rpc_session_begin(sinfo, *db_id); + return ts_web_rpc_session_begin(sinfo, *db_id); } bool tpp_session_update(int db_id, int protocol_sub_type, int state) { - return ts_web_rpc_session_update(db_id, protocol_sub_type, state); + return ts_web_rpc_session_update(db_id, protocol_sub_type, state); } -bool tpp_session_end(const char* sid, int db_id, int ret) { - return ts_web_rpc_session_end(sid, db_id, ret); +bool tpp_session_end(const char *sid, int db_id, int ret) { + return ts_web_rpc_session_end(sid, db_id, ret); } // typedef struct TPP_LIB @@ -246,87 +243,78 @@ bool tpp_session_end(const char* sid, int db_id, int ret) { // } // } -int ts_main(void) -{ - ExIniFile& ini = g_env.get_ini(); +int ts_main(void) { + ExIniFile &ini = g_env.get_ini(); - EXLOGI(L"\n"); - EXLOGI(L"###############################################################\n"); - EXLOGI(L"Load config file: %ls.\n", ini.get_filename().c_str()); - EXLOGI(L"Teleport Core Server starting ...\n"); + EXLOGI(L"\n"); + EXLOGI(L"###############################################################\n"); + EXLOGI(L"Load config file: %ls.\n", ini.get_filename().c_str()); + EXLOGI(L"Teleport Core Server starting ...\n"); - ex_ini_sections& secs = ini.GetAllSections(); - TsHttpRpc rpc; + ex_ini_sections &secs = ini.GetAllSections(); + TsHttpRpc rpc; - // 枚举配置文件中的[protocol-xxx]小节,加载对应的协议动态库 - bool all_ok = true; + // 枚举配置文件中的[protocol-xxx]小节,加载对应的协议动态库 + bool all_ok = true; - do { - if (!g_session_mgr.start()) - { - EXLOGE(L"[core] failed to start session-id manager.\n"); - all_ok = false; - break; - } + do { + if (!g_session_mgr.start()) { + EXLOGE(L"[core] failed to start session-id manager.\n"); + all_ok = false; + break; + } - if (!rpc.init() || !rpc.start()) - { - EXLOGE(L"[core] rpc init/start failed.\n"); - all_ok = false; - break; - } + if (!rpc.init() || !rpc.start()) { + EXLOGE(L"[core] rpc init/start failed.\n"); + all_ok = false; + break; + } - 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 libname; - if (!it->second->GetStr(L"lib", libname)) - continue; + 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 libname; + if (!it->second->GetStr(L"lib", libname)) + continue; - bool enabled = false; - it->second->GetBool(L"enabled", enabled, false); - if (!enabled) - { - EXLOGV(L"[core] `%ls` not enabled.\n", libname.c_str()); - continue; - } + bool enabled = false; + it->second->GetBool(L"enabled", enabled, false); + if (!enabled) { + EXLOGV(L"[core] `%ls` not enabled.\n", libname.c_str()); + continue; + } - if (!g_tpp_mgr.load_tpp(libname)) - { - all_ok = false; - break; - } - } - } + if (!g_tpp_mgr.load_tpp(libname)) { + all_ok = false; + break; + } + } + } - } while (0); + } while (0); - if (0 == g_tpp_mgr.count()) - { - all_ok = false; - } + if (0 == g_tpp_mgr.count()) { + all_ok = false; + } - if (!all_ok) - { - g_exit_flag = true; - } + if (!all_ok) { + g_exit_flag = true; + } - if (!g_exit_flag) { - ts_web_rpc_register_core(); + if (!g_exit_flag) { + ts_web_rpc_register_core(); - EXLOGV("[core] ---- initialized, ready for service ----\n"); - while (!g_exit_flag) - { - ex_sleep_ms(1000); - g_tpp_mgr.timer(); - } - } + EXLOGV("[core] ---- initialized, ready for service ----\n"); + while (!g_exit_flag) { + ex_sleep_ms(1000); + g_tpp_mgr.timer(); + } + } - g_tpp_mgr.stop_all(); - rpc.stop(); - g_session_mgr.stop(); + EXLOGW("[core] try to stop all thread and exit.\n"); + g_tpp_mgr.stop_all(); + rpc.stop(); + g_session_mgr.stop(); - return 0; + return 0; } diff --git a/server/tp_core/core/ts_session.cpp b/server/tp_core/core/ts_session.cpp index a708e1b..deee94f 100644 --- a/server/tp_core/core/ts_session.cpp +++ b/server/tp_core/core/ts_session.cpp @@ -7,188 +7,166 @@ TsSessionManager g_session_mgr; TsSessionManager::TsSessionManager() : - ExThreadBase("sid-mgr-thread") -{ + ExThreadBase("sid-mgr-thread") { } -TsSessionManager::~TsSessionManager() -{ - ts_connections::iterator it_conn = m_connections.begin(); - for (; it_conn != m_connections.end(); ++it_conn) - { - delete it_conn->second; - } - m_connections.clear(); +TsSessionManager::~TsSessionManager() { + ts_connections::iterator it_conn = m_connections.begin(); + for (; it_conn != m_connections.end(); ++it_conn) { + delete it_conn->second; + } + m_connections.clear(); } -void TsSessionManager::_thread_loop(void) -{ - for (;;) - { - ex_sleep_ms(1000); - if (m_stop_flag) - return; - _remove_expired_connect_info(); - } +void TsSessionManager::_thread_loop(void) { + for (;;) { + ex_sleep_ms(1000); + if (m_need_stop) + return; + _remove_expired_connect_info(); + } } -void TsSessionManager::_set_stop_flag(void) -{ - m_stop_flag = true; +void TsSessionManager::_remove_expired_connect_info(void) { + // 超过15秒未进行连接的connect-info会被移除 + + ExThreadSmartLock locker(m_lock); + + ex_u64 _now = ex_get_tick_count(); + ts_connections::iterator it = m_connections.begin(); + for (; it != m_connections.end();) { + //EXLOGD("[core] check expired connect info: [%s] %d, %d %d %d\n", it->first.c_str(), it->second->ref_count, int(_now), int(it->second->ticket_start), int(_now - it->second->ticket_start)); + if (it->second->ref_count == 0 && _now - 15000 > it->second->ticket_start) { + EXLOGD("[core] remove connection info, because timeout: %s\n", it->first.c_str()); + delete it->second; + m_connections.erase(it++); + EXLOGD("[core] there are %d connection info exists.\n", m_connections.size()); + } else { + ++it; + } + } } +bool TsSessionManager::get_connect_info(const ex_astr &sid, TS_CONNECT_INFO &info) { + ExThreadSmartLock locker(m_lock); -void TsSessionManager::_remove_expired_connect_info(void) -{ - // 超过15秒未进行连接的connect-info会被移除 + ts_connections::iterator it = m_connections.find(sid); + if (it == m_connections.end()) + return false; - ExThreadSmartLock locker(m_lock); + info.sid = it->second->sid; + info.user_id = it->second->user_id; + info.host_id = it->second->host_id; + info.acc_id = it->second->acc_id; + info.user_username = it->second->user_username; + info.host_ip = it->second->host_ip; + info.conn_ip = it->second->conn_ip; + info.conn_port = it->second->conn_port; + info.client_ip = it->second->client_ip; + info.acc_username = it->second->acc_username; + info.acc_secret = it->second->acc_secret; + info.username_prompt = it->second->username_prompt; + info.password_prompt = it->second->password_prompt; + info.protocol_type = it->second->protocol_type; + info.protocol_sub_type = it->second->protocol_sub_type; + info.protocol_flag = it->second->protocol_flag; + info.record_flag = it->second->record_flag; + info.auth_type = it->second->auth_type; - ex_u64 _now = ex_get_tick_count(); - ts_connections::iterator it = m_connections.begin(); - for (; it != m_connections.end(); ) - { - //EXLOGD("[core] check expired connect info: [%s] %d, %d %d %d\n", it->first.c_str(), it->second->ref_count, int(_now), int(it->second->ticket_start), int(_now - it->second->ticket_start)); - if (it->second->ref_count == 0 && _now - 15000 > it->second->ticket_start) - { - EXLOGD("[core] remove connection info, because timeout: %s\n", it->first.c_str()); - delete it->second; - m_connections.erase(it++); - EXLOGD("[core] there are %d connection info exists.\n", m_connections.size()); - } - else - { - ++it; - } - } + it->second->ref_count++; + + return true; } -bool TsSessionManager::get_connect_info(const ex_astr& sid, TS_CONNECT_INFO& info) -{ - ExThreadSmartLock locker(m_lock); +bool TsSessionManager::free_connect_info(const ex_astr &sid) { + ExThreadSmartLock locker(m_lock); - ts_connections::iterator it = m_connections.find(sid); - if (it == m_connections.end()) - return false; + ts_connections::iterator it = m_connections.find(sid); + if (it == m_connections.end()) + return false; - info.sid = it->second->sid; - info.user_id = it->second->user_id; - info.host_id = it->second->host_id; - info.acc_id = it->second->acc_id; - info.user_username = it->second->user_username; - info.host_ip = it->second->host_ip; - info.conn_ip = it->second->conn_ip; - info.conn_port = it->second->conn_port; - info.client_ip = it->second->client_ip; - info.acc_username = it->second->acc_username; - info.acc_secret = it->second->acc_secret; - info.username_prompt = it->second->username_prompt; - info.password_prompt = it->second->password_prompt; - info.protocol_type = it->second->protocol_type; - info.protocol_sub_type = it->second->protocol_sub_type; - info.protocol_flag = it->second->protocol_flag; - info.record_flag = it->second->record_flag; - info.auth_type = it->second->auth_type; + it->second->ref_count--; - it->second->ref_count++; + // 对于RDP来说,此时不要移除连接信息,系统自带RDP客户端在第一次连接时进行协议协商,然后马上会断开,之后立即重新连接一次(第二次连接之前可能会提示证书信息,如果用户长时间不操作,可能会导致超时)。 + // 因此,我们将其引用计数减低,并更新一下最后访问时间,让定时器来移除它。 + if (it->second->protocol_type != TP_PROTOCOL_TYPE_RDP) { + if (it->second->ref_count <= 0) { + EXLOGD("[core] remove connection info, because all connections closed: %s\n", it->first.c_str()); + delete it->second; + m_connections.erase(it); + EXLOGD("[core] there are %d connection info exists.\n", m_connections.size()); + } + } else { + if (it->second->ref_count == 1) + it->second->ref_count = 0; + it->second->ticket_start = ex_get_tick_count() + 45000; // 我们将时间向后移动45秒,这样如果没有发生RDP的第二次连接,这个连接信息就会在一分钟后被清除。 + } - return true; + + return true; } -bool TsSessionManager::free_connect_info(const ex_astr& sid) { - ExThreadSmartLock locker(m_lock); +bool TsSessionManager::request_session(ex_astr &sid, TS_CONNECT_INFO *info) { + ExThreadSmartLock locker(m_lock); - ts_connections::iterator it = m_connections.find(sid); - if (it == m_connections.end()) - return false; + EXLOGD("[core] request session: account: [%s], protocol: [%d], auth-mode: [%d]\n", info->acc_username.c_str(), + info->protocol_type, info->auth_type); - it->second->ref_count--; + ex_astr _sid; + int retried = 0; + ts_connections::iterator it; + for (;;) { + _gen_session_id(_sid, info, 6); + it = m_connections.find(_sid); + if (it == m_connections.end()) + break; - // 对于RDP来说,此时不要移除连接信息,系统自带RDP客户端在第一次连接时进行协议协商,然后马上会断开,之后立即重新连接一次(第二次连接之前可能会提示证书信息,如果用户长时间不操作,可能会导致超时)。 - // 因此,我们将其引用计数减低,并更新一下最后访问时间,让定时器来移除它。 - if (it->second->protocol_type != TP_PROTOCOL_TYPE_RDP) { - if (it->second->ref_count <= 0) { - EXLOGD("[core] remove connection info, because all connections closed: %s\n", it->first.c_str()); - delete it->second; - m_connections.erase(it); - EXLOGD("[core] there are %d connection info exists.\n", m_connections.size()); - } - } - else { - if (it->second->ref_count == 1) - it->second->ref_count = 0; - it->second->ticket_start = ex_get_tick_count() + 45000; // 我们将时间向后移动45秒,这样如果没有发生RDP的第二次连接,这个连接信息就会在一分钟后被清除。 - } + retried++; + if (retried > 50) + return false; + } + info->sid = _sid; + info->ref_count = 0; + info->ticket_start = ex_get_tick_count(); + m_connections.insert(std::make_pair(_sid, info)); - return true; + sid = _sid; + 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; + } + + return true; } -bool TsSessionManager::request_session(ex_astr& sid, TS_CONNECT_INFO* info) -{ - ExThreadSmartLock locker(m_lock); +void TsSessionManager::_gen_session_id(ex_astr &sid, const TS_CONNECT_INFO *info, int len) { + mbedtls_sha1_context sha; + ex_u8 sha_digist[20] = {0}; - EXLOGD("[core] request session: account: [%s], protocol: [%d], auth-mode: [%d]\n", info->acc_username.c_str(), info->protocol_type, info->auth_type); + ex_u64 _tick = ex_get_tick_count(); + ex_u64 _tid = ex_get_thread_id(); - ex_astr _sid; - int retried = 0; - ts_connections::iterator it; - for (;;) - { - _gen_session_id(_sid, info, 6); - it = m_connections.find(_sid); - if (it == m_connections.end()) - break; + mbedtls_sha1_init(&sha); + mbedtls_sha1_starts(&sha); + mbedtls_sha1_update(&sha, (const unsigned char *) &_tick, sizeof(ex_u64)); + mbedtls_sha1_update(&sha, (const unsigned char *) &_tid, sizeof(ex_u64)); + mbedtls_sha1_update(&sha, (const unsigned char *) info->conn_ip.c_str(), info->conn_ip.length()); + mbedtls_sha1_update(&sha, (const unsigned char *) info->client_ip.c_str(), info->client_ip.length()); + mbedtls_sha1_update(&sha, (const unsigned char *) info->acc_username.c_str(), info->acc_username.length()); + mbedtls_sha1_finish(&sha, sha_digist); + mbedtls_sha1_free(&sha); - retried++; - if (retried > 50) - return false; - } + char szTmp[64] = {0}; + int _len = len / 2 + 1; + int i = 0; + int offset = 0; + for (i = 0; i < _len; ++i) { + snprintf(szTmp + offset, 64 - offset, "%02X", sha_digist[i]); + offset += 2; + } - info->sid = _sid; - info->ref_count = 0; - info->ticket_start = ex_get_tick_count(); - m_connections.insert(std::make_pair(_sid, info)); - - sid = _sid; - 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; - } - - return true; -} - -void TsSessionManager::_gen_session_id(ex_astr& sid, const TS_CONNECT_INFO* info, int len) -{ - mbedtls_sha1_context sha; - ex_u8 sha_digist[20] = { 0 }; - - ex_u64 _tick = ex_get_tick_count(); - ex_u64 _tid = ex_get_thread_id(); - - mbedtls_sha1_init(&sha); - mbedtls_sha1_starts(&sha); - mbedtls_sha1_update(&sha, (const unsigned char*)&_tick, sizeof(ex_u64)); - mbedtls_sha1_update(&sha, (const unsigned char*)&_tid, sizeof(ex_u64)); - mbedtls_sha1_update(&sha, (const unsigned char*)info->conn_ip.c_str(), info->conn_ip.length()); - mbedtls_sha1_update(&sha, (const unsigned char*)info->client_ip.c_str(), info->client_ip.length()); - mbedtls_sha1_update(&sha, (const unsigned char*)info->acc_username.c_str(), info->acc_username.length()); - mbedtls_sha1_finish(&sha, sha_digist); - mbedtls_sha1_free(&sha); - - char szTmp[64] = { 0 }; - int _len = len / 2 + 1; - int i = 0; - int offset = 0; - for (i = 0; i < _len; ++i) - { - snprintf(szTmp + offset, 64 - offset, "%02X", sha_digist[i]); - offset += 2; - } - - sid.assign(szTmp, len); + sid.assign(szTmp, len); } diff --git a/server/tp_core/core/ts_session.h b/server/tp_core/core/ts_session.h index 23271de..e227351 100644 --- a/server/tp_core/core/ts_session.h +++ b/server/tp_core/core/ts_session.h @@ -57,10 +57,7 @@ public: bool free_connect_info(const ex_astr& sid); protected: - // 线程循环 void _thread_loop(void); - // 设置停止标志,让线程能够正常结束 - void _set_stop_flag(void); private: void _gen_session_id(ex_astr& sid, const TS_CONNECT_INFO* info, int len); diff --git a/server/tp_core/protocol/telnet/CMakeLists.txt b/server/tp_core/protocol/telnet/CMakeLists.txt index 7e781d6..fafe24d 100644 --- a/server/tp_core/protocol/telnet/CMakeLists.txt +++ b/server/tp_core/protocol/telnet/CMakeLists.txt @@ -19,19 +19,19 @@ list(REMOVE_ITEM DIR_TELNET_SRCS "./stdafx.cpp") include_directories( ../../../../common/libex/include - ../../../../common/teleport - ../../../../external/jsoncpp/include + ../../../../common/teleport + ../../../../external/jsoncpp/include ) include_directories( - ${TP_EXTERNAL_RELEASE_DIR}/include + ${TP_EXTERNAL_RELEASE_DIR}/include ) link_directories(${TP_EXTERNAL_RELEASE_DIR}/lib) add_library(tptelnet SHARED ${DIR_TELNET_SRCS}) if (OS_LINUX) - target_link_libraries(tptelnet uv dl pthread rt util) + target_link_libraries(tptelnet uv dl pthread rt util) elseif (OS_MACOS) - target_link_libraries(tptelnet uv dl pthread util) -endif() + target_link_libraries(tptelnet uv dl pthread util) +endif () diff --git a/server/tp_core/protocol/telnet/telnet_conn.cpp b/server/tp_core/protocol/telnet/telnet_conn.cpp index 0d08d78..45ae854 100644 --- a/server/tp_core/protocol/telnet/telnet_conn.cpp +++ b/server/tp_core/protocol/telnet/telnet_conn.cpp @@ -4,72 +4,90 @@ #include "../../common/ts_const.h" #include -ex_astr _uv_str_error(int retcode) -{ - ex_astr err; - err = uv_err_name(retcode); - err += ":"; - err += uv_strerror(retcode); - return err; +ex_astr _uv_str_error(int retcode) { + ex_astr err; + err = uv_err_name(retcode); + err += ":"; + err += uv_strerror(retcode); + return err; } TelnetConn::TelnetConn(TelnetSession *sess, bool is_server_side) : m_session(sess), m_is_server(is_server_side) { if (is_server_side) { - m_name = "cli<->tp"; - m_state = TELNET_CONN_STATE_CONNECTED; - } - else { - m_name = "tp<->srv"; - m_state = TELNET_CONN_STATE_FREE; + m_name = "cli<->tp"; + m_state = TELNET_CONN_STATE_CONNECTED; + } else { + m_name = "tp<->srv"; + m_state = TELNET_CONN_STATE_FREE; } - m_timer_running = false; + m_timer_running = false; uv_tcp_init(sess->get_loop(), &m_handle); m_handle.data = this; + uv_async_init(sess->get_loop(), &m_stop_handle, _on_stop_cb); + m_stop_handle.data = this; } TelnetConn::~TelnetConn() { } bool TelnetConn::start_recv() { - int err = uv_read_start((uv_stream_t *)&m_handle, _on_alloc, _on_recv); - if (err != 0) { - EXLOGE("[telnet] [%s] can not start to read.\n", m_name); - m_session->close(TP_SESS_STAT_ERR_IO); - return false; - } + int err = uv_read_start((uv_stream_t *) &m_handle, _on_alloc, _on_recv); + if (err != 0) { + EXLOGE("[telnet] [%s] can not start to read.\n", m_name); + m_session->close(TP_SESS_STAT_ERR_IO); + return false; + } - return true; + return true; } void TelnetConn::close() { - if (m_state == TELNET_CONN_STATE_FREE || m_state == TELNET_CONN_STATE_CLOSING) - return; + if (m_state == TELNET_CONN_STATE_FREE || m_state == TELNET_CONN_STATE_CLOSING) + return; + uv_async_send(&m_stop_handle); +} - if (m_timer_running) { - m_timer_running = false; - uv_timer_stop(&m_timer_connect_timeout); +void TelnetConn::_do_close() { + if (m_state == TELNET_CONN_STATE_FREE || m_state == TELNET_CONN_STATE_CLOSING) + return; - EXLOGW("[telnet] [%s] try to close while it connecting.\n", m_name); - m_state = TELNET_CONN_STATE_CLOSING; - uv_close(handle(), NULL); + if (m_timer_running) { + m_timer_running = false; + uv_timer_stop(&m_timer_connect_timeout); - return; - } + EXLOGW("[telnet] [%s] try to close while it connecting.\n", m_name); + m_state = TELNET_CONN_STATE_CLOSING; + uv_close(handle(), NULL); - uv_read_stop((uv_stream_t*)&m_handle); - uv_close(handle() , _uv_on_closed); + return; + } + + uv_read_stop((uv_stream_t *) &m_handle); + uv_close(handle(), _uv_on_closed); +} + +//static +void TelnetConn::_on_stop_cb(uv_async_t *handle) { + TelnetConn *_this = (TelnetConn *) handle->data; + uv_close((uv_handle_t *) &_this->m_stop_handle, _this->_on_stop_handler_closed); +} + +//static +void TelnetConn::_on_stop_handler_closed(uv_handle_t *handle) { + TelnetConn *_this = (TelnetConn *) handle->data; + _this->_do_close(); } void TelnetConn::_uv_on_closed(uv_handle_t *handle) { - TelnetConn *_this = (TelnetConn *)handle->data; - _this->m_state = TELNET_CONN_STATE_FREE; - _this->m_session->on_conn_close(); + TelnetConn *_this = (TelnetConn *) handle->data; + _this->m_state = TELNET_CONN_STATE_FREE; + _this->m_session->on_conn_close(); } void TelnetConn::_on_alloc(uv_handle_t *handle, size_t suggested_size, uv_buf_t *buf) { - TelnetConn *_this = (TelnetConn *) handle->data; +// TelnetConn *_this = (TelnetConn *) handle->data; buf->base = (char *) calloc(1, suggested_size); buf->len = suggested_size; } @@ -80,16 +98,15 @@ void TelnetConn::_on_recv(uv_stream_t *handle, ssize_t nread, const uv_buf_t *bu if (nread == 0) { free(buf->base); return; - } - else if (nread < 0) { + } else if (nread < 0) { free(buf->base); - if (nread == UV_EOF) - EXLOGD("[telnet] [%s] [recv] disconnected.\n", _this->m_name); - else if(nread == UV_ECONNRESET) - EXLOGD("[telnet] [%s] [recv] connection reset by peer.\n", _this->m_name); - else - EXLOGD("[telnet] [%s] [recv] %s.\n", _this->m_name, _uv_str_error(nread).c_str()); + if (nread == UV_EOF) + EXLOGD("[telnet] [%s] [recv] disconnected.\n", _this->m_name); + else if (nread == UV_ECONNRESET) + EXLOGD("[telnet] [%s] [recv] connection reset by peer.\n", _this->m_name); + else + EXLOGD("[telnet] [%s] [recv] %s.\n", _this->m_name, _uv_str_error(nread).c_str()); // if (nread == -4077) @@ -101,13 +118,12 @@ void TelnetConn::_on_recv(uv_stream_t *handle, ssize_t nread, const uv_buf_t *bu _this->m_session->close(TP_SESS_STAT_END); return; - } - else { + } else { // #ifdef LOG_DATA // if(!_this->m_session->is_relay()) // EXLOG_BIN((ex_u8*)buf->base, nread, "[telnet] [%s] RECV %d.", _this->m_name, nread); // #endif - } + } _this->m_buf_data.append((ex_u8 *) buf->base, nread); free(buf->base); @@ -129,7 +145,7 @@ bool TelnetConn::_raw_send(const ex_u8 *data, size_t size) { // EXLOG_BIN(data, size, "[telnet] [%s] SEND %dB.", m_name, size); // #endif - uv_write_t *w = (uv_write_t *) calloc(1, sizeof(uv_write_t)); + uv_write_t *w = (uv_write_t *) calloc(1, sizeof(uv_write_t)); ex_u8 *_data = (ex_u8 *) calloc(1, size); if (NULL == _data) { @@ -170,13 +186,14 @@ void TelnetConn::connect(const char *server_ip, ex_u16 server_port) { if (m_state == TELNET_CONN_STATE_CONNECTED) { // 当前已经连接上了服务器了,断开重连 - EXLOGV("[telnet] [%s] [%s] try to disconnect. %s:%d\n", m_name, m_session->client_addr(), server_ip, server_port); - m_state = TELNET_CONN_STATE_CLOSING; + EXLOGV("[telnet] [%s] [%s] try to disconnect from real TELNET server %s:%d and reconnect.\n", m_name, + m_session->client_addr(), server_ip, server_port); + m_state = TELNET_CONN_STATE_CLOSING; uv_close((uv_handle_t *) &m_handle, _uv_on_reconnect); return; - } - else { - EXLOGV("[telnet] [%s] [%s] try to connect to real TELNET server at %s:%d\n", m_name, m_session->client_addr(), server_ip, server_port); + } else { + EXLOGV("[telnet] [%s] [%s] try to connect to real TELNET server %s:%d\n", m_name, m_session->client_addr(), + server_ip, server_port); } struct sockaddr_in addr; @@ -185,53 +202,51 @@ void TelnetConn::connect(const char *server_ip, ex_u16 server_port) { uv_connect_t *conn_req = (uv_connect_t *) calloc(1, sizeof(uv_connect_t)); conn_req->data = this; - // 设置一个超时回调,如果超时发生时连接尚未完成,就报错 - uv_timer_init(m_session->get_loop(), &m_timer_connect_timeout); - m_timer_connect_timeout.data = this; + // 设置一个超时回调,如果超时发生时连接尚未完成,就报错 + uv_timer_init(m_session->get_loop(), &m_timer_connect_timeout); + m_timer_connect_timeout.data = this; #ifdef EX_DEBUG - uv_timer_start(&m_timer_connect_timeout, _uv_on_connect_timeout, 5000, 0); + uv_timer_start(&m_timer_connect_timeout, _uv_on_connect_timeout, 5000, 0); #else - uv_timer_start(&m_timer_connect_timeout, _uv_on_connect_timeout, 10000, 0); + uv_timer_start(&m_timer_connect_timeout, _uv_on_connect_timeout, 10000, 0); #endif - m_timer_running = true; + m_timer_running = true; - //m_is_connecting = true; - m_state = TELNET_CONN_STATE_CONNECTING; + m_state = TELNET_CONN_STATE_CONNECTING; int err = 0; if ((err = uv_tcp_connect(conn_req, &m_handle, (const struct sockaddr *) &addr, _uv_on_connected)) != 0) { free(conn_req); EXLOGE("[telnet] [%s] can not connect to server: %s\n", m_name, uv_strerror(err)); - m_timer_running = false; - uv_timer_stop(&m_timer_connect_timeout); - uv_close((uv_handle_t*)&m_timer_connect_timeout, _uv_on_timer_connect_timeout_closed); + m_timer_running = false; + uv_timer_stop(&m_timer_connect_timeout); + uv_close((uv_handle_t *) &m_timer_connect_timeout, NULL); - m_state = TELNET_CONN_STATE_FREE; + m_state = TELNET_CONN_STATE_FREE; m_session->close(TP_SESS_STAT_ERR_CONNECT); } } -void TelnetConn::_uv_on_connect_timeout(uv_timer_t *timer) -{ - TelnetConn *_this = (TelnetConn *)timer->data; +void TelnetConn::_uv_on_connect_timeout(uv_timer_t *timer) { + TelnetConn *_this = (TelnetConn *) timer->data; - if (_this->m_timer_running) { - _this->m_timer_running = false; - uv_timer_stop(&_this->m_timer_connect_timeout); - uv_close((uv_handle_t*)&_this->m_timer_connect_timeout, _this->_uv_on_timer_connect_timeout_closed); - } + if (_this->m_timer_running) { + _this->m_timer_running = false; + uv_timer_stop(&_this->m_timer_connect_timeout); + uv_close((uv_handle_t *) &_this->m_timer_connect_timeout, NULL); + } - // 如果在连接成功之前就超时了,则关闭连接 - EXLOGE("[telnet] [%s] timeout when connect to real TELNET server, cancel connection.\n", _this->m_name); - _this->m_state = TELNET_CONN_STATE_CLOSING; - uv_close(_this->handle(), _uv_on_closed); + // 如果在连接成功之前就超时了,则关闭连接 + EXLOGE("[telnet] [%s] timeout when connect to real TELNET server.\n", _this->m_name); + _this->m_state = TELNET_CONN_STATE_CLOSING; + uv_close(_this->handle(), _uv_on_closed); } void TelnetConn::_uv_on_reconnect(uv_handle_t *handle) { - TelnetConn *_this = (TelnetConn *)handle->data; - _this->m_state = TELNET_CONN_STATE_FREE; + TelnetConn *_this = (TelnetConn *) handle->data; + _this->m_state = TELNET_CONN_STATE_FREE; uv_tcp_init(_this->m_session->get_loop(), &_this->m_handle); _this->m_handle.data = _this; @@ -240,33 +255,33 @@ void TelnetConn::_uv_on_reconnect(uv_handle_t *handle) { } void TelnetConn::_uv_on_connected(uv_connect_t *req, int status) { - TelnetConn *_this = (TelnetConn *)req->data; + TelnetConn *_this = (TelnetConn *) req->data; free(req); - if (_this->m_timer_running) { - _this->m_timer_running = false; - uv_timer_stop(&_this->m_timer_connect_timeout); - uv_close((uv_handle_t*)&_this->m_timer_connect_timeout, _this->_uv_on_timer_connect_timeout_closed); - } + if (_this->m_timer_running) { + _this->m_timer_running = false; + uv_timer_stop(&_this->m_timer_connect_timeout); + uv_close((uv_handle_t *) &_this->m_timer_connect_timeout, NULL); + } - if (status != 0) { - EXLOGE("[telnet] [%s] cannot connect to real TELNET server. %s\n", _this->m_name, uv_strerror(status)); - _this->m_state = TELNET_CONN_STATE_FREE; - _this->m_session->close(TP_SESS_STAT_ERR_CONNECT); - return; - } + if (status != 0) { + EXLOGE("[telnet] [%s] cannot connect to real TELNET server. %s\n", _this->m_name, uv_strerror(status)); + _this->m_state = TELNET_CONN_STATE_FREE; + _this->m_session->close(TP_SESS_STAT_ERR_CONNECT); + return; + } - EXLOGW("[telnet] [%s] real TELNET server connected.\n", _this->m_session->client_addr()); - _this->m_state = TELNET_CONN_STATE_CONNECTED; + EXLOGW("[telnet] [%s] real TELNET server connected.\n", _this->m_session->client_addr()); + _this->m_state = TELNET_CONN_STATE_CONNECTED; - if (!_this->start_recv()) { - _this->m_session->close(TP_SESS_STAT_ERR_IO); - return; - } + if (!_this->start_recv()) { + _this->m_session->close(TP_SESS_STAT_ERR_IO); + return; + } _this->m_session->do_next(_this, s_server_connected); } //static -void TelnetConn::_uv_on_timer_connect_timeout_closed(uv_handle_t *handle) { -} +//void TelnetConn::_uv_on_timer_connect_timeout_closed(uv_handle_t *handle) { +//} diff --git a/server/tp_core/protocol/telnet/telnet_conn.h b/server/tp_core/protocol/telnet/telnet_conn.h index 653deee..4eebd1c 100644 --- a/server/tp_core/protocol/telnet/telnet_conn.h +++ b/server/tp_core/protocol/telnet/telnet_conn.h @@ -8,10 +8,10 @@ //#define LOG_DATA -#define TELNET_CONN_STATE_FREE 0 // not connected yet or closed -#define TELNET_CONN_STATE_CONNECTING 1 // connecting -#define TELNET_CONN_STATE_CONNECTED 2 // connected. -#define TELNET_CONN_STATE_CLOSING 3 // closing. +#define TELNET_CONN_STATE_FREE 0 // not connected yet or closed +#define TELNET_CONN_STATE_CONNECTING 1 // connecting +#define TELNET_CONN_STATE_CONNECTED 2 // connected. +#define TELNET_CONN_STATE_CLOSING 3 // closing. class TelnetSession; @@ -19,40 +19,59 @@ class TelnetSession; class TelnetConn { public: TelnetConn(TelnetSession *sess, bool is_server_side); + ~TelnetConn(); TelnetSession *session() { return m_session; } - // just for debug-info + // just for debug-info const char *name() const { return m_name; } - bool is_server_side() const { return m_is_server; } - ex_u8 state() const { return m_state; } + bool is_server_side() const { return m_is_server; } + + ex_u8 state() const { return m_state; } uv_handle_t *handle() { return (uv_handle_t *) &m_handle; } + uv_tcp_t *tcp_handle() { return &m_handle; } + uv_stream_t *stream_handle() { return (uv_stream_t *) &m_handle; } MemBuffer &data() { return m_buf_data; } bool send(MemBuffer &mbuf); + bool send(const ex_u8 *data, size_t size); - // connect to real server, for proxy-client-side only. + // connect to real server, for proxy-client-side only. void connect(const char *server_ip, ex_u16 server_port = 3389); - // try to close this connection. return current TELNET_CONN_STATE_XXXX. - void close(); - bool start_recv(); + + // try to close this connection. return current TELNET_CONN_STATE_XXXX. + void close(); + + bool start_recv(); private: static void _on_alloc(uv_handle_t *handle, size_t suggested_size, uv_buf_t *buf); + static void _on_recv(uv_stream_t *handle, ssize_t nread, const uv_buf_t *buf); + static void _on_send_done(uv_write_t *req, int status); - static void _uv_on_connect_timeout(uv_timer_t *timer); + + static void _uv_on_connect_timeout(uv_timer_t *timer); + static void _uv_on_connected(uv_connect_t *req, int status); + static void _uv_on_reconnect(uv_handle_t *handle); - static void _uv_on_closed(uv_handle_t *handle); - static void _uv_on_timer_connect_timeout_closed(uv_handle_t *handle); + + static void _uv_on_closed(uv_handle_t *handle); + +// static void _uv_on_timer_connect_timeout_closed(uv_handle_t *handle); + static void _on_stop_cb(uv_async_t *handle); + + static void _on_stop_handler_closed(uv_handle_t *handle); + + void _do_close(); bool _raw_send(const ex_u8 *data, size_t size); @@ -60,14 +79,15 @@ private: TelnetSession *m_session; bool m_is_server; - // for debug-info. + // for debug-info. const char *m_name; uv_tcp_t m_handle; - uv_timer_t m_timer_connect_timeout; - bool m_timer_running; // does m_timer_connect_timeout initialized and started. + uv_timer_t m_timer_connect_timeout; + bool m_timer_running; // does m_timer_connect_timeout initialized and started. + uv_async_t m_stop_handle; // event for stop whole listener handler. - ex_u8 m_state; // TELNET_CONN_STATE_XXXX + ex_u8 m_state; // TELNET_CONN_STATE_XXXX // 作为client需要的数据(远程主机信息) std::string m_server_ip; diff --git a/server/tp_core/protocol/telnet/telnet_proxy.cpp b/server/tp_core/protocol/telnet/telnet_proxy.cpp index 0dcb040..969e365 100644 --- a/server/tp_core/protocol/telnet/telnet_proxy.cpp +++ b/server/tp_core/protocol/telnet/telnet_proxy.cpp @@ -4,228 +4,239 @@ TelnetProxy g_telnet_proxy; -TelnetProxy::TelnetProxy() : ExThreadBase("telnet-proxy-thread") -{ - memset(&m_loop, 0, sizeof(uv_loop_t)); - m_timer_counter = 0; - m_noop_timeout_sec = 900; +TelnetProxy::TelnetProxy() : ExThreadBase("telnet-proxy-thread") { + memset(&m_loop, 0, sizeof(uv_loop_t)); + m_timer_counter = 0; + m_noop_timeout_sec = 900; } -TelnetProxy::~TelnetProxy() -{ - if (m_sessions.size() > 0) - EXLOGE("[telnet] not all session stopped.\n"); +TelnetProxy::~TelnetProxy() { + if (!m_sessions.empty()) + EXLOGE("[telnet] not all session stopped.\n"); } -bool TelnetProxy::init() -{ - if (0 != uv_loop_init(&m_loop)) - return false; +bool TelnetProxy::init() { + if (0 != uv_loop_init(&m_loop)) + return false; - if (0 != uv_async_init(&m_loop, &m_clean_session_handle, _on_clean_session_cb)) - return false; - m_clean_session_handle.data = this; + if (0 != uv_async_init(&m_loop, &m_clean_session_handle, _on_clean_session_cb)) + return false; + m_clean_session_handle.data = this; - m_host_ip = g_telnet_env.bind_ip; - m_host_port = g_telnet_env.bind_port; + if (0 != uv_async_init(&m_loop, &m_stop_handle, _on_stop_cb)) + return false; + m_stop_handle.data = this; - if (0 != uv_tcp_init(&m_loop, &m_handle)) - return false; - m_handle.data = this; + m_host_ip = g_telnet_env.bind_ip; + m_host_port = g_telnet_env.bind_port; - return true; + if (0 != uv_tcp_init(&m_loop, &m_listener_handle)) + return false; + m_listener_handle.data = this; + + return true; } void TelnetProxy::timer() { - // timer() will be called per one second, and I will do my job per 5 seconds. - m_timer_counter++; - if (m_timer_counter < 5) - return; + // timer() will be called per one second, and I will do my job per 5 seconds. + m_timer_counter++; + if (m_timer_counter < 5) + return; - m_timer_counter = 0; + m_timer_counter = 0; - ExThreadSmartLock locker(m_lock); - ex_u32 t_now = (ex_u32)time(NULL); - ts_telnet_sessions::iterator it = m_sessions.begin(); - for (; it != m_sessions.end(); ++it) - { - it->first->save_record(); - if(0 != m_noop_timeout_sec) - it->first->check_noop_timeout(t_now, m_noop_timeout_sec); - } + ExThreadSmartLock locker(m_lock); + ex_u32 t_now = (ex_u32) time(NULL); + ts_telnet_sessions::iterator it = m_sessions.begin(); + for (; it != m_sessions.end(); ++it) { + it->first->save_record(); + if (0 != m_noop_timeout_sec) + it->first->check_noop_timeout(t_now, m_noop_timeout_sec); + } } void TelnetProxy::set_cfg(ex_u32 noop_timeout) { - m_noop_timeout_sec = noop_timeout; + m_noop_timeout_sec = noop_timeout; } -void TelnetProxy::kill_sessions(const ex_astrs& sessions) { - ExThreadSmartLock locker(m_lock); - ts_telnet_sessions::iterator it = m_sessions.begin(); - for (; it != m_sessions.end(); ++it) { - for (size_t i = 0; i < sessions.size(); ++i) { - if (it->first->sid() == sessions[i]) { - EXLOGW("[telnet] try to kill %s\n", sessions[i].c_str()); - it->first->check_noop_timeout(0, 0); // 立即结束 - } - } - } +void TelnetProxy::kill_sessions(const ex_astrs &sessions) { + ExThreadSmartLock locker(m_lock); + ts_telnet_sessions::iterator it = m_sessions.begin(); + for (; it != m_sessions.end(); ++it) { + for (size_t i = 0; i < sessions.size(); ++i) { + if (it->first->sid() == sessions[i]) { + EXLOGW("[telnet] try to kill %s\n", sessions[i].c_str()); + it->first->check_noop_timeout(0, 0); // 立即结束 + } + } + } } -void TelnetProxy::_thread_loop(void) -{ - struct sockaddr_in addr; - if (0 != uv_ip4_addr(m_host_ip.c_str(), m_host_port, &addr)) { - EXLOGE("[telnet] invalid ip/port for TELNET listener.\n"); - return; - } +void TelnetProxy::_thread_loop(void) { + struct sockaddr_in addr; + if (0 != uv_ip4_addr(m_host_ip.c_str(), m_host_port, &addr)) { + EXLOGE("[telnet] invalid ip/port for TELNET listener.\n"); + return; + } - if (0 != uv_tcp_bind(&m_handle, (const struct sockaddr*) &addr, 0)) { - EXLOGE("[telnet] can not bind %s:%d.\n", m_host_ip.c_str(), m_host_port); - return; - } + if (0 != uv_tcp_bind(&m_listener_handle, (const struct sockaddr *) &addr, 0)) { + EXLOGE("[telnet] can not bind %s:%d.\n", m_host_ip.c_str(), m_host_port); + return; + } - // 开始监听,有客户端连接到来时,会回调 _on_client_connect() - if (0 != uv_listen((uv_stream_t*)&m_handle, 8, _on_client_connect)) { - EXLOGE("[telnet] can not listen on %s:%d.\n", m_host_ip.c_str(), m_host_port); - return; - } + // 开始监听,有客户端连接到来时,会回调 _on_client_connect() + if (0 != uv_listen((uv_stream_t *) &m_listener_handle, 8, _on_client_connect)) { + EXLOGE("[telnet] can not listen on %s:%d.\n", m_host_ip.c_str(), m_host_port); + return; + } - EXLOGI("[telnet] TeleportServer-TELNET ready on %s:%d\n", m_host_ip.c_str(), m_host_port); + EXLOGI("[telnet] TeleportServer-TELNET ready on %s:%d\n", m_host_ip.c_str(), m_host_port); - int err = 0; - if ((err = uv_run(&m_loop, UV_RUN_DEFAULT)) != 0) { - EXLOGE("[telnet] main-loop end. %s\n", uv_strerror(err)); - } + int err = 0; + if ((err = uv_run(&m_loop, UV_RUN_DEFAULT)) != 0) { + EXLOGE("[telnet] main-loop end. %s\n", uv_strerror(err)); + } - // 注意,如果在 uv_loop_close() 内部崩溃,可能某个uv的handle未关闭。 - uv_loop_close(&m_loop); + // https://github.com/libuv/libuv/issues/709 + // + // uv_close is not thread safe (see the docs here. That means you cannot call it from outside of the loop thread. + // http://docs.libuv.org/en/v1.x/design.html#the-i-o-loop + // + // The usual way to approach this when the loop is running in another thread is to use a uv_async_t handle, + // because uv_async_send is thread safe. You could have one such handle and call uv_stop in its callback. + // Then, after uv_run returns you can use uv_walk to close all handles and run the loop one last time so + // that close callbacks are called. - EXLOGV("[telnet] main-loop end.\n"); -} + // 注意,如果在 uv_loop_close() 内部崩溃,可能某个uv的handle未关闭。 + uv_loop_close(&m_loop); -void TelnetProxy::_set_stop_flag(void) { - m_stop_flag = true; - - if (m_is_running) { - uv_close((uv_handle_t*)&m_handle, _on_listener_closed); - } + EXLOGV("[telnet] main-loop end.\n"); } // static -void TelnetProxy::_on_listener_closed(uv_handle_t* handle) -{ - TelnetProxy* _this = (TelnetProxy*)handle->data; - EXLOGV("[telnet] listener close.\n"); +void TelnetProxy::_on_stop(void) { + ExThreadBase::_on_stop(); - _this->_close_all_sessions(); + if (m_is_running) { + uv_async_send(&m_stop_handle); + } +} + +// static +void TelnetProxy::_on_listener_closed(uv_handle_t *handle) { + TelnetProxy *_this = (TelnetProxy *) handle->data; + EXLOGV("[telnet] listener close.\n"); + + uv_close((uv_handle_t *) &_this->m_stop_handle, _on_stop_handle_closed); +// _this->_close_all_sessions(); } void TelnetProxy::clean_session() { - uv_async_send(&m_clean_session_handle); + uv_async_send(&m_clean_session_handle); } -void TelnetProxy::_close_all_sessions(void) -{ - ExThreadSmartLock locker(m_lock); +void TelnetProxy::_close_all_sessions(void) { + ExThreadSmartLock locker(m_lock); - if (m_sessions.size() == 0) { - _close_clean_session_handle(); - return; - } + if (m_sessions.empty()) { + _close_clean_session_handle(); + return; + } - ts_telnet_sessions::iterator it = m_sessions.begin(); - for (; it != m_sessions.end(); ++it) - { - it->first->close(TP_SESS_STAT_ERR_RESET); - } + ts_telnet_sessions::iterator it = m_sessions.begin(); + for (; it != m_sessions.end(); ++it) { + it->first->close(TP_SESS_STAT_ERR_RESET); + } } // static -void TelnetProxy::_on_clean_session_cb(uv_async_t* handle) -{ - TelnetProxy* _this = (TelnetProxy*)handle->data; +void TelnetProxy::_on_clean_session_cb(uv_async_t *handle) { + TelnetProxy *_this = (TelnetProxy *) handle->data; - // check closed session - ExThreadSmartLock locker(_this->m_lock); + // check closed session + ExThreadSmartLock locker(_this->m_lock); - ts_telnet_sessions::iterator it = _this->m_sessions.begin(); - for (; it != _this->m_sessions.end(); ) - { - if (it->first->is_closed()) { - delete it->first; - _this->m_sessions.erase(it++); - EXLOGD("[telnet] - removed one session.\n"); - } - else { - it++; - } - } + ts_telnet_sessions::iterator it = _this->m_sessions.begin(); + for (; it != _this->m_sessions.end();) { + if (it->first->is_closed()) { + delete it->first; + _this->m_sessions.erase(it++); + EXLOGD("[telnet] - removed one session.\n"); + } else { + it++; + } + } - if (_this->m_stop_flag && _this->m_sessions.size() == 0) { - _this->_close_clean_session_handle(); - } + if (_this->m_need_stop && _this->m_sessions.empty()) { + _this->_close_clean_session_handle(); + } +} + +////static +//void TelnetProxy::_on_clean_session_handle_closed(uv_handle_t *handle) { +//} + +//static +void TelnetProxy::_on_stop_handle_closed(uv_handle_t *handle) { + TelnetProxy *_this = (TelnetProxy *) handle->data; + _this->_close_all_sessions(); } //static -void TelnetProxy::_on_clean_session_handle_closed(uv_handle_t *handle) { +void TelnetProxy::_on_stop_cb(uv_async_t *handle) { + TelnetProxy *_this = (TelnetProxy *) handle->data; + uv_close((uv_handle_t *) &_this->m_listener_handle, _on_listener_closed); } // static -void TelnetProxy::_on_client_connect(uv_stream_t* server, int status) -{ - if (0 != status) - return; +void TelnetProxy::_on_client_connect(uv_stream_t *server, int status) { + if (0 != status) + return; - TelnetProxy* _this = (TelnetProxy*)server->data; - _this->_on_accept(server); + TelnetProxy *_this = (TelnetProxy *) server->data; + _this->_on_accept(server); } -bool TelnetProxy::_on_accept(uv_stream_t* server) -{ - TelnetSession* sess = new TelnetSession(this); +bool TelnetProxy::_on_accept(uv_stream_t *server) { + TelnetSession *sess = new TelnetSession(this); - if (0 != uv_accept(server, sess->client()->stream_handle())) - { - EXLOGE("[telnet] socket accept failed.\n"); - delete sess; - return false; - } + if (0 != uv_accept(server, sess->client()->stream_handle())) { + EXLOGE("[telnet] socket accept failed.\n"); + delete sess; + return false; + } - if (m_stop_flag) - { - delete sess; - return false; - } + if (m_need_stop) { + delete sess; + return false; + } - // 获取客户端IP地址和端口号 - struct sockaddr sock_client; - int namelen = sizeof(sock_client); - if (0 == uv_tcp_getpeername(sess->client()->tcp_handle(), &sock_client, &namelen)) - { - sockaddr_in* addrin = (sockaddr_in*)&sock_client; - char ip[17] = { 0 }; - if (0 == uv_ip4_name(addrin, ip, sizeof(ip))) - { - char client_addr[64] = { 0 }; - snprintf(client_addr, 64, "%s:%d", ip, addrin->sin_port); - sess->client_addr(client_addr); - } - } + // 获取客户端IP地址和端口号 + struct sockaddr sock_client; + int namelen = sizeof(sock_client); + if (0 == uv_tcp_getpeername(sess->client()->tcp_handle(), &sock_client, &namelen)) { + sockaddr_in *addrin = (sockaddr_in *) &sock_client; + char ip[17] = {0}; + if (0 == uv_ip4_name(addrin, ip, sizeof(ip))) { + char client_addr[64] = {0}; + snprintf(client_addr, 64, "%s:%d", ip, addrin->sin_port); + sess->client_addr(client_addr); + } + } - EXLOGV("\n=================== NEW TELNET CLIENT [%s] ============\n", sess->client_addr()); + EXLOGV("\n=================== NEW TELNET CLIENT [%s] ============\n", sess->client_addr()); - { - ExThreadSmartLock locker(m_lock); - m_sessions.insert(std::make_pair(sess, 0)); - } + { + ExThreadSmartLock locker(m_lock); + m_sessions.insert(std::make_pair(sess, 0)); + } - sess->client()->start_recv(); + sess->client()->start_recv(); - return true; + return true; } void TelnetProxy::_close_clean_session_handle() { - uv_close((uv_handle_t*)&m_clean_session_handle, _on_clean_session_handle_closed); + uv_close((uv_handle_t *) &m_clean_session_handle, NULL); } diff --git a/server/tp_core/protocol/telnet/telnet_proxy.h b/server/tp_core/protocol/telnet/telnet_proxy.h index bfd3f2c..5b1a14a 100644 --- a/server/tp_core/protocol/telnet/telnet_proxy.h +++ b/server/tp_core/protocol/telnet/telnet_proxy.h @@ -6,53 +6,65 @@ #include "telnet_session.h" -typedef std::map ts_telnet_sessions; +typedef std::map ts_telnet_sessions; -class TelnetProxy : public ExThreadBase -{ +class TelnetProxy : public ExThreadBase { public: - TelnetProxy(); - ~TelnetProxy(); + TelnetProxy(); - bool init(); - void timer(); - void set_cfg(ex_u32 noop_timeout); - void kill_sessions(const ex_astrs& sessions); + ~TelnetProxy(); - uv_loop_t* get_loop() { return &m_loop; } + bool init(); - void clean_session(); + void timer(); + + void set_cfg(ex_u32 noop_timeout); + + void kill_sessions(const ex_astrs &sessions); + + uv_loop_t *get_loop() { return &m_loop; } + + void clean_session(); protected: - void _thread_loop(); - void _set_stop_flag(); - void _close_all_sessions(); - void _close_clean_session_handle(); + void _thread_loop(); + + void _on_stop(); + + void _close_all_sessions(); + + void _close_clean_session_handle(); private: - static void _on_client_connect(uv_stream_t* server, int status); - static void _on_listener_closed(uv_handle_t* handle); - static void _on_clean_session_cb(uv_async_t* handle); - static void _on_clean_session_handle_closed(uv_handle_t *handle); + static void _on_client_connect(uv_stream_t *server, int status); - bool _on_accept(uv_stream_t* server); + static void _on_listener_closed(uv_handle_t *handle); + + static void _on_clean_session_cb(uv_async_t *handle); + +// static void _on_clean_session_handle_closed(uv_handle_t *handle); + + static void _on_stop_cb(uv_async_t *handle); + + static void _on_stop_handle_closed(uv_handle_t *handle); + + bool _on_accept(uv_stream_t *server); private: - bool m_stop_flag; - int m_timer_counter; - // - ex_u32 m_noop_timeout_sec; + int m_timer_counter; + ex_u32 m_noop_timeout_sec; - uv_loop_t m_loop; - uv_tcp_t m_handle; - uv_async_t m_clean_session_handle; + uv_loop_t m_loop; + uv_tcp_t m_listener_handle; + uv_async_t m_clean_session_handle; + uv_async_t m_stop_handle; // event for stop whole listener handler. - ExThreadLock m_lock; + ExThreadLock m_lock; - ex_astr m_host_ip; - int m_host_port; + ex_astr m_host_ip; + int m_host_port; - ts_telnet_sessions m_sessions; + ts_telnet_sessions m_sessions; }; extern TelnetProxy g_telnet_proxy; diff --git a/server/tp_core/protocol/telnet/telnet_session.cpp b/server/tp_core/protocol/telnet/telnet_session.cpp index 242222e..56349cd 100644 --- a/server/tp_core/protocol/telnet/telnet_session.cpp +++ b/server/tp_core/protocol/telnet/telnet_session.cpp @@ -3,168 +3,164 @@ #include "tpp_env.h" #include -#define TELNET_IAC 0xFF -#define TELNET_DONT 0xFE -#define TELNET_DO 0xFD -#define TELNET_WONT 0xFC -#define TELNET_WILL 0xFB -#define TELNET_SB 0xFA -#define TELNET_SE 0xF0 +#define TELNET_IAC 0xFF +#define TELNET_DONT 0xFE +#define TELNET_DO 0xFD +#define TELNET_WONT 0xFC +#define TELNET_WILL 0xFB +#define TELNET_SB 0xFA +#define TELNET_SE 0xF0 TelnetSession::TelnetSession(TelnetProxy *proxy) : - m_proxy(proxy), - m_conn_info(NULL) -{ - m_state = TP_SESS_STAT_RUNNING; - m_startup_win_size_recorded = false; - m_db_id = 0; - m_is_relay = false; - m_is_closed = false; - m_first_client_pkg = true; - m_last_access_timestamp = (ex_u32)time(NULL); + m_proxy(proxy), + m_conn_info(NULL) { + m_state = TP_SESS_STAT_RUNNING; + m_startup_win_size_recorded = false; + m_db_id = 0; + m_is_relay = false; + m_is_closed = false; + m_first_client_pkg = true; + m_last_access_timestamp = (ex_u32) time(NULL); - m_win_width = 0; - m_win_height = 0; + m_win_width = 0; + m_win_height = 0; - m_is_putty_mode = false; + m_is_putty_mode = false; - m_username_sent = false; - m_password_sent = false; + m_username_sent = false; + m_password_sent = false; - m_conn_server = new TelnetConn(this, false); - m_conn_client = new TelnetConn(this, true); + m_conn_server = new TelnetConn(this, false); + m_conn_client = new TelnetConn(this, true); - m_status = s_client_connect; + m_status = s_client_connect; - m_client_addr = "unknown-ip"; + m_client_addr = "unknown-ip"; } TelnetSession::~TelnetSession() { - delete m_conn_client; - delete m_conn_server; + delete m_conn_client; + delete m_conn_server; - if (NULL != m_conn_info) { - g_telnet_env.free_connect_info(m_conn_info); - } + if (NULL != m_conn_info) { + g_telnet_env.free_connect_info(m_conn_info); + } - EXLOGD("[telnet] session destroy.\n"); + EXLOGD("[telnet] session destroy.\n"); } void TelnetSession::save_record() { - m_rec.save_record(); + m_rec.save_record(); } void TelnetSession::check_noop_timeout(ex_u32 t_now, ex_u32 timeout) { - if (t_now == 0) - EXLOGW("[telnet] try close session by kill.\n"); - else if (t_now - m_last_access_timestamp > timeout) - EXLOGW("[telnet] try close session by timeout.\n"); - if (t_now == 0 || t_now - m_last_access_timestamp > timeout) - _do_close(TP_SESS_STAT_END); + if (t_now == 0) + EXLOGW("[telnet] try close session by kill.\n"); + else if (t_now - m_last_access_timestamp > timeout) + EXLOGW("[telnet] try close session by timeout.\n"); + if (t_now == 0 || t_now - m_last_access_timestamp > timeout) + _do_close(TP_SESS_STAT_END); } void TelnetSession::_session_error(int err_code) { - int db_id = 0; - if (!g_telnet_env.session_begin(m_conn_info, &db_id) || db_id == 0) - { - EXLOGE("[telnet] can not write session error to database.\n"); - return; - } + int db_id = 0; + if (!g_telnet_env.session_begin(m_conn_info, &db_id) || db_id == 0) { + EXLOGE("[telnet] can not write session error to database.\n"); + return; + } - g_telnet_env.session_end(m_sid.c_str(), db_id, err_code); + g_telnet_env.session_end(m_sid.c_str(), db_id, err_code); } bool TelnetSession::_on_session_begin() { - if (!g_telnet_env.session_begin(m_conn_info, &m_db_id)) { - EXLOGE("[telnet] can not save to database, session begin failed.\n"); - return false; - } + if (!g_telnet_env.session_begin(m_conn_info, &m_db_id)) { + EXLOGE("[telnet] can not save to database, session begin failed.\n"); + return false; + } - if (!g_telnet_env.session_update(m_db_id, m_conn_info->protocol_sub_type, TP_SESS_STAT_STARTED)) { - EXLOGE("[telnet] can not update state, session begin failed.\n"); - return false; - } + if (!g_telnet_env.session_update(m_db_id, m_conn_info->protocol_sub_type, TP_SESS_STAT_STARTED)) { + EXLOGE("[telnet] can not update state, session begin failed.\n"); + return false; + } - m_rec.begin(g_telnet_env.replay_path.c_str(), L"tp-telnet", m_db_id, m_conn_info); + m_rec.begin(g_telnet_env.replay_path.c_str(), L"tp-telnet", m_db_id, m_conn_info); - return true; + return true; } -bool TelnetSession::_on_session_end() -{ - if (m_db_id > 0) - { - // 如果会话过程中没有发生错误,则将其状态改为结束,否则记录下错误值 - if (m_state == TP_SESS_STAT_RUNNING || m_state == TP_SESS_STAT_STARTED) - m_state = TP_SESS_STAT_END; +bool TelnetSession::_on_session_end() { + if (m_db_id > 0) { + // 如果会话过程中没有发生错误,则将其状态改为结束,否则记录下错误值 + if (m_state == TP_SESS_STAT_RUNNING || m_state == TP_SESS_STAT_STARTED) + m_state = TP_SESS_STAT_END; - EXLOGD("[telnet] session end with code: %d\n", m_state); - g_telnet_env.session_end(m_sid.c_str(), m_db_id, m_state); - } + EXLOGD("[telnet] session end with code: %d\n", m_state); + g_telnet_env.session_end(m_sid.c_str(), m_db_id, m_state); + } - return true; + return true; } uv_loop_t *TelnetSession::get_loop(void) { - return m_proxy->get_loop(); + return m_proxy->get_loop(); } void TelnetSession::close(int err_code) { - _do_close(err_code); + _do_close(err_code); } void TelnetSession::do_next(TelnetConn *conn, sess_state status) { - if (m_status < s_close) - m_status = status; + if (m_status < s_close) + m_status = status; - do_next(conn); + do_next(conn); } void TelnetSession::do_next(TelnetConn *conn) { - sess_state new_status; - ASSERT(m_status != s_dead); + sess_state new_status; + ASSERT(m_status != s_dead); - switch (m_status) { - case s_noop: - return; + switch (m_status) { + case s_noop: + return; - case s_client_connect: - new_status = _do_client_connect(conn); - break; + case s_client_connect: + new_status = _do_client_connect(conn); + break; - case s_negotiation_with_client: - new_status = _do_negotiation_with_client(conn); - break; - case s_server_connected: - new_status = _do_server_connected(); - break; - case s_relay: - new_status = _do_relay(conn); - break; + case s_negotiation_with_client: + new_status = _do_negotiation_with_client(conn); + break; + case s_server_connected: + new_status = _do_server_connected(); + break; + case s_relay: + new_status = _do_relay(conn); + break; - case s_close: - new_status = _do_close(m_state); - break; - case s_closing: - new_status = _do_check_closing(); - break; - case s_all_conn_closed: - new_status = s_dead; - break; - default: - //UNREACHABLE(); - return; - } + case s_close: + new_status = _do_close(m_state); + break; + case s_closing: + new_status = _do_check_closing(); + break; + case s_all_conn_closed: + new_status = s_dead; + break; + default: + //UNREACHABLE(); + return; + } - m_status = new_status; + m_status = new_status; - if (m_status == s_dead) { - EXLOGW("[telnet] try to remove session.\n"); - _on_session_end(); - m_is_closed = true; - m_proxy->clean_session(); - } + if (m_status == s_dead) { + EXLOGW("[telnet] try to remove session.\n"); + _on_session_end(); + m_is_closed = true; + m_proxy->clean_session(); + } } /* @@ -174,276 +170,248 @@ void TelnetSession::do_next(TelnetConn *conn) { */ sess_state TelnetSession::_do_close(int state) { - EXLOGD("[telnet] _do_close(). m_status=%d\n", m_status); - if (m_status >= s_close) - return m_status; + EXLOGD("[telnet] _do_close(). m_status=%d\n", m_status); + if (m_status >= s_close) + return m_status; - if (state == TP_SESS_STAT_END) { - if (!m_is_relay) - m_state = TP_SESS_STAT_ERR_INTERNAL; - else - m_state = state; - } - else { - if (!m_is_relay) - _session_error(state); - m_state = state; - } - EXLOGV("[telnet] close session.\n"); - EXLOGD("[telnet] _do_close(), conn_client::state=%d, conn_server:state=%d\n", m_conn_client->state(), m_conn_server->state()); + if (state == TP_SESS_STAT_END) { + if (!m_is_relay) + m_state = TP_SESS_STAT_ERR_INTERNAL; + else + m_state = state; + } else { + if (!m_is_relay) + _session_error(state); + m_state = state; + } + EXLOGV("[telnet] close session.\n"); + EXLOGD("[telnet] _do_close(), conn_client::state=%d, conn_server:state=%d\n", m_conn_client->state(), + m_conn_server->state()); - m_conn_client->close(); - m_conn_server->close(); - m_status = s_closing; - return m_status; + m_conn_client->close(); + m_conn_server->close(); + m_status = s_closing; + return m_status; } sess_state TelnetSession::_do_check_closing() { - if (m_conn_client->state() == TELNET_CONN_STATE_FREE && m_conn_server->state() == TELNET_CONN_STATE_FREE) - return s_all_conn_closed; - else - return s_closing; + if (m_conn_client->state() == TELNET_CONN_STATE_FREE && m_conn_server->state() == TELNET_CONN_STATE_FREE) + return s_all_conn_closed; + else + return s_closing; } void TelnetSession::on_conn_close() { - EXLOGD("[telnet] on_conn_close(), conn_client::state=%d, conn_server:state=%d\n", m_conn_client->state(), m_conn_server->state()); - if (m_conn_client->state() == TELNET_CONN_STATE_FREE && m_conn_server->state() == TELNET_CONN_STATE_FREE) { - m_status = s_all_conn_closed; - do_next(m_conn_client); - } + EXLOGD("[telnet] on_conn_close(), conn_client::state=%d, conn_server:state=%d\n", m_conn_client->state(), + m_conn_server->state()); + if (m_conn_client->state() == TELNET_CONN_STATE_FREE && m_conn_server->state() == TELNET_CONN_STATE_FREE) { + m_status = s_all_conn_closed; + do_next(m_conn_client); + } } -sess_state TelnetSession::_do_client_connect(TelnetConn* conn) { - // putty会率先发第一个包,SecureCRT会通过脚本发第一个包 - return _do_negotiation_with_client(conn); +sess_state TelnetSession::_do_client_connect(TelnetConn *conn) { + // putty会率先发第一个包,SecureCRT会通过脚本发第一个包 + return _do_negotiation_with_client(conn); } -sess_state TelnetSession::_do_negotiation_with_client(TelnetConn* conn) { - if (NULL == conn) - return s_negotiation_with_client; +sess_state TelnetSession::_do_negotiation_with_client(TelnetConn *conn) { + if (NULL == conn) + return s_negotiation_with_client; - if (0 == conn->data().size()) - return s_negotiation_with_client; + if (0 == conn->data().size()) + return s_negotiation_with_client; - if (m_first_client_pkg) { - m_first_client_pkg = false; + if (m_first_client_pkg) { + m_first_client_pkg = false; - MemBuffer& mbuf = conn->data(); + MemBuffer &mbuf = conn->data(); - if (mbuf.size() > 14 && 0 == memcmp(mbuf.data(), "session:", 8)) { - m_is_putty_mode = false; + if (mbuf.size() > 14 && 0 == memcmp(mbuf.data(), "session:", 8)) { + m_is_putty_mode = false; - mbuf.pop(8); - for (; mbuf.size() > 0; ) { - if (mbuf.data()[mbuf.size() - 1] == 0x0a || mbuf.data()[mbuf.size() - 1] == 0x0d) - mbuf.size(mbuf.size() - 1); - else - break; - } + mbuf.pop(8); + for (; mbuf.size() > 0;) { + if (mbuf.data()[mbuf.size() - 1] == 0x0a || mbuf.data()[mbuf.size() - 1] == 0x0d) + mbuf.size(mbuf.size() - 1); + else + break; + } - mbuf.append((ex_u8*)"\x00", 1); - m_sid = (char*)mbuf.data(); + mbuf.append((ex_u8 *) "\x00", 1); + m_sid = (char *) mbuf.data(); - return _do_connect_server(); - } - else { - m_is_putty_mode = true; - } - } + return _do_connect_server(); + } else { + m_is_putty_mode = true; + } + } - MemBuffer mbuf_msg; - mbuf_msg.reserve(128); - MemStream ms_msg(mbuf_msg); + MemBuffer mbuf_msg; + mbuf_msg.reserve(128); + MemStream ms_msg(mbuf_msg); - MemBuffer mbuf_resp; - mbuf_resp.reserve(conn->data().size()); - MemStream ms_resp(mbuf_resp); + MemBuffer mbuf_resp; + mbuf_resp.reserve(conn->data().size()); + MemStream ms_resp(mbuf_resp); - MemBuffer mbuf_sub; - mbuf_sub.reserve(128); - MemStream ms_sub(mbuf_sub); + MemBuffer mbuf_sub; + mbuf_sub.reserve(128); + MemStream ms_sub(mbuf_sub); - MemStream s(conn->data()); - ex_u8 ch = 0; - ex_u8 ch_cmd = 0; - for (; s.left() > 0;) - { - ch = s.get_u8(); - if (ch == TELNET_IAC) - { - if (s.left() < 2) - return _do_close(TP_SESS_STAT_ERR_BAD_PKG); + MemStream s(conn->data()); + ex_u8 ch = 0; + ex_u8 ch_cmd = 0; + for (; s.left() > 0;) { + ch = s.get_u8(); + if (ch == TELNET_IAC) { + if (s.left() < 2) + return _do_close(TP_SESS_STAT_ERR_BAD_PKG); - if (mbuf_sub.size() > 0) - { - // 已经得到一个sub negotiation,在处理新的数据前,先处理掉旧的 - EXLOG_BIN(mbuf_sub.data(), mbuf_sub.size(), "-=-=-=-=-="); - ms_sub.reset(); - } + if (mbuf_sub.size() > 0) { + // 已经得到一个sub negotiation,在处理新的数据前,先处理掉旧的 + EXLOG_BIN(mbuf_sub.data(), mbuf_sub.size(), "-=-=-=-=-="); + ms_sub.reset(); + } - ch_cmd = s.get_u8(); - if (ch_cmd == TELNET_SB) - { - // SUB NEGOTIATION,变长数据,以 FF F0 结束 - bool have_SE = false; - ex_u8 ch_sub = 0; - for (; s.left() > 0;) - { - ch_sub = s.get_u8(); - if (ch_sub == TELNET_IAC) - { - if (s.left() > 0) - { - if (s.get_u8() == TELNET_SE) - { - have_SE = true; - break; - } - else - return _do_close(TP_SESS_STAT_ERR_BAD_PKG); - } - } - else - { - ms_sub.put_u8(ch_sub); - } - } + ch_cmd = s.get_u8(); + if (ch_cmd == TELNET_SB) { + // SUB NEGOTIATION,变长数据,以 FF F0 结束 + bool have_SE = false; + ex_u8 ch_sub = 0; + for (; s.left() > 0;) { + ch_sub = s.get_u8(); + if (ch_sub == TELNET_IAC) { + if (s.left() > 0) { + if (s.get_u8() == TELNET_SE) { + have_SE = true; + break; + } else + return _do_close(TP_SESS_STAT_ERR_BAD_PKG); + } + } else { + ms_sub.put_u8(ch_sub); + } + } - if (!have_SE) - return _do_close(TP_SESS_STAT_ERR_BAD_PKG); - } - else if (ch_cmd == TELNET_DONT) - { - ms_resp.put_u8(TELNET_IAC); - ms_resp.put_u8(TELNET_WONT); - ms_resp.put_u8(s.get_u8()); - } - else if (ch_cmd == TELNET_DO) - { - ms_resp.put_u8(TELNET_IAC); - ms_resp.put_u8(TELNET_WILL); - ms_resp.put_u8(s.get_u8()); - } - else if (ch_cmd == TELNET_WONT) - { - ms_resp.put_u8(TELNET_IAC); - ms_resp.put_u8(TELNET_DONT); - ms_resp.put_u8(s.get_u8()); - } - else if (ch_cmd == TELNET_WILL) - { - ms_resp.put_u8(TELNET_IAC); - ms_resp.put_u8(TELNET_DO); - ms_resp.put_u8(s.get_u8()); - } - else - { - s.skip(1); - } - } - else - { - ms_msg.put_u8(ch); - } - } + if (!have_SE) + return _do_close(TP_SESS_STAT_ERR_BAD_PKG); + } else if (ch_cmd == TELNET_DONT) { + ms_resp.put_u8(TELNET_IAC); + ms_resp.put_u8(TELNET_WONT); + ms_resp.put_u8(s.get_u8()); + } else if (ch_cmd == TELNET_DO) { + ms_resp.put_u8(TELNET_IAC); + ms_resp.put_u8(TELNET_WILL); + ms_resp.put_u8(s.get_u8()); + } else if (ch_cmd == TELNET_WONT) { + ms_resp.put_u8(TELNET_IAC); + ms_resp.put_u8(TELNET_DONT); + ms_resp.put_u8(s.get_u8()); + } else if (ch_cmd == TELNET_WILL) { + ms_resp.put_u8(TELNET_IAC); + ms_resp.put_u8(TELNET_DO); + ms_resp.put_u8(s.get_u8()); + } else { + s.skip(1); + } + } else { + ms_msg.put_u8(ch); + } + } - conn->data().empty(); + conn->data().empty(); - if (mbuf_resp.size() > 0) - { - conn->send(mbuf_resp.data(), mbuf_resp.size()); - } + if (mbuf_resp.size() > 0) { + conn->send(mbuf_resp.data(), mbuf_resp.size()); + } - if (mbuf_sub.size() == 5) - { - // 客户端窗口大小 - if (0x1f == mbuf_sub.data()[0]) { - ms_sub.rewind(); - ms_sub.skip(1); - m_win_width = ms_sub.get_u16_be(); - m_win_height = ms_sub.get_u16_be(); + if (mbuf_sub.size() == 5) { + // 客户端窗口大小 + if (0x1f == mbuf_sub.data()[0]) { + ms_sub.rewind(); + ms_sub.skip(1); + m_win_width = ms_sub.get_u16_be(); + m_win_height = ms_sub.get_u16_be(); - ms_resp.reset(); - ms_resp.put_u8(TELNET_IAC); - ms_resp.put_u8(TELNET_SB); - ms_resp.put_bin(mbuf_sub.data(), 5); - ms_resp.put_u8(TELNET_IAC); - ms_resp.put_u8(TELNET_SE); - conn->send(mbuf_resp.data(), mbuf_resp.size()); - } + ms_resp.reset(); + ms_resp.put_u8(TELNET_IAC); + ms_resp.put_u8(TELNET_SB); + ms_resp.put_bin(mbuf_sub.data(), 5); + ms_resp.put_u8(TELNET_IAC); + ms_resp.put_u8(TELNET_SE); + conn->send(mbuf_resp.data(), mbuf_resp.size()); + } - // 发送下列指令,putty才会将登陆用户名发过来(也就是SID) - ex_u8 _d[] = { - 0xff, 0xfa, 0x27, 0x01, - 0x03, 0x53, 0x46, 0x55, 0x54, 0x4c, 0x4e, 0x54, 0x56, 0x45, 0x52, 0x03, 0x53, 0x46, 0x55, 0x54, - 0x4c, 0x4e, 0x54, 0x4d, 0x4f, 0x44, 0x45, 0xff, 0xf0 - }; - m_conn_client->send((ex_u8*)_d, sizeof(_d)); - return s_negotiation_with_client; - } + // 发送下列指令,putty才会将登陆用户名发过来(也就是SID) + ex_u8 _d[] = { + 0xff, 0xfa, 0x27, 0x01, + 0x03, 0x53, 0x46, 0x55, 0x54, 0x4c, 0x4e, 0x54, 0x56, 0x45, 0x52, 0x03, 0x53, 0x46, 0x55, 0x54, + 0x4c, 0x4e, 0x54, 0x4d, 0x4f, 0x44, 0x45, 0xff, 0xf0 + }; + m_conn_client->send((ex_u8 *) _d, sizeof(_d)); + return s_negotiation_with_client; + } - if (mbuf_sub.size() > 8) - { - // 可能含有putty的登录用户名信息(就是SID啦) - if (0 == memcmp(mbuf_sub.data(), "\x27\x00\x00\x55\x53\x45\x52\x01", 8)) // '...USER. - { - mbuf_sub.pop(8); - for (; mbuf_sub.size() > 0;) - { - if (mbuf_sub.data()[mbuf_sub.size() - 1] == 0x0a || mbuf_sub.data()[mbuf_sub.size() - 1] == 0x0d) - mbuf_sub.size(mbuf_sub.size() - 1); - else - break; - } + if (mbuf_sub.size() > 8) { + // 可能含有putty的登录用户名信息(就是SID啦) + if (0 == memcmp(mbuf_sub.data(), "\x27\x00\x00\x55\x53\x45\x52\x01", 8)) // '...USER. + { + mbuf_sub.pop(8); + for (; mbuf_sub.size() > 0;) { + if (mbuf_sub.data()[mbuf_sub.size() - 1] == 0x0a || mbuf_sub.data()[mbuf_sub.size() - 1] == 0x0d) + mbuf_sub.size(mbuf_sub.size() - 1); + else + break; + } - mbuf_sub.append((ex_u8*)"\x00", 1); - m_sid = (char*)mbuf_sub.data(); - } - } + mbuf_sub.append((ex_u8 *) "\x00", 1); + m_sid = (char *) mbuf_sub.data(); + } + } - if (m_sid.length() > 0) - { - return _do_connect_server(); - } + if (m_sid.length() > 0) { + return _do_connect_server(); + } - return s_negotiation_with_client; + return s_negotiation_with_client; } sess_state TelnetSession::_do_connect_server() { - EXLOGW("[telnet] session-id: [%s]\n", m_sid.c_str()); + EXLOGW("[telnet] session-id: [%s]\n", m_sid.c_str()); - m_conn_info = g_telnet_env.get_connect_info(m_sid.c_str()); + m_conn_info = g_telnet_env.get_connect_info(m_sid.c_str()); - if (NULL == m_conn_info) { - EXLOGE("[telnet] no such session: %s\n", m_sid.c_str()); - return _do_close(TP_SESS_STAT_ERR_SESSION); - } - else { - m_conn_ip = m_conn_info->conn_ip; - m_conn_port = m_conn_info->conn_port; - m_acc_name = m_conn_info->acc_username; - m_acc_secret = m_conn_info->acc_secret; - m_username_prompt = m_conn_info->username_prompt; - m_password_prompt = m_conn_info->password_prompt; + if (NULL == m_conn_info) { + EXLOGE("[telnet] no such session: %s\n", m_sid.c_str()); + return _do_close(TP_SESS_STAT_ERR_SESSION); + } else { + m_conn_ip = m_conn_info->conn_ip; + m_conn_port = m_conn_info->conn_port; + m_acc_name = m_conn_info->acc_username; + m_acc_secret = m_conn_info->acc_secret; + m_username_prompt = m_conn_info->username_prompt; + m_password_prompt = m_conn_info->password_prompt; - if (m_conn_info->protocol_type != TP_PROTOCOL_TYPE_TELNET) { - EXLOGE("[telnet] session '%s' is not for TELNET.\n", m_sid.c_str()); - return _do_close(TP_SESS_STAT_ERR_SESSION); - } + if (m_conn_info->protocol_type != TP_PROTOCOL_TYPE_TELNET) { + EXLOGE("[telnet] session '%s' is not for TELNET.\n", m_sid.c_str()); + return _do_close(TP_SESS_STAT_ERR_SESSION); + } - if (m_conn_info->auth_type != TP_AUTH_TYPE_NONE) { - if (m_acc_name.length() == 0 || m_username_prompt.length() == 0 || m_acc_secret.length() == 0 || m_password_prompt.length() == 0) { - EXLOGE("[telnet] invalid connection param.\n"); - return _do_close(TP_SESS_STAT_ERR_SESSION); - } - } + if (m_conn_info->auth_type != TP_AUTH_TYPE_NONE) { + if (m_acc_name.length() == 0 || m_username_prompt.length() == 0 || m_acc_secret.length() == 0 || + m_password_prompt.length() == 0) { + EXLOGE("[telnet] invalid connection param.\n"); + return _do_close(TP_SESS_STAT_ERR_SESSION); + } + } - } + } - // try to connect to real server. - m_conn_server->connect(m_conn_ip.c_str(), m_conn_port); + // try to connect to real server. + m_conn_server->connect(m_conn_ip.c_str(), m_conn_port); // ex_astr szmsg = "Connect to "; // szmsg += m_conn_ip; @@ -451,184 +419,172 @@ sess_state TelnetSession::_do_connect_server() { // m_conn_client->send((ex_u8*)szmsg.c_str(), szmsg.length()); - return s_noop; + return s_noop; } sess_state TelnetSession::_do_server_connected() { - m_conn_client->data().empty(); - m_conn_server->data().empty(); + m_conn_client->data().empty(); + m_conn_server->data().empty(); - m_status = s_relay; + m_status = s_relay; - // 如果没有设置用户名/密码,则无需登录 - if (m_conn_info->auth_type == TP_AUTH_TYPE_NONE) { - m_username_sent = true; - m_password_sent = true; - } + // 如果没有设置用户名/密码,则无需登录 + if (m_conn_info->auth_type == TP_AUTH_TYPE_NONE) { + m_username_sent = true; + m_password_sent = true; + } - m_is_relay = true; - EXLOGW("[telnet] enter relay mode.\n"); + m_is_relay = true; + EXLOGW("[telnet] enter relay mode.\n"); - if (!_on_session_begin()) { - return _do_close(TP_SESS_STAT_ERR_INTERNAL); - } + if (!_on_session_begin()) { + return _do_close(TP_SESS_STAT_ERR_INTERNAL); + } - int w = 50; - if (m_win_width != 0) { + int w = 50; + if (m_win_width != 0) { #ifdef EX_OS_WIN32 - int w = min(m_win_width, 128); + int w = min(m_win_width, 128); #else - int w = std::min(m_win_width, 128); + int w = std::min(m_win_width, 128); #endif - m_startup_win_size_recorded = true; - m_rec.record_win_size_startup(m_win_width, m_win_height); - } + m_startup_win_size_recorded = true; + m_rec.record_win_size_startup(m_win_width, m_win_height); + } - char buf[512] = { 0 }; + char buf[512] = {0}; - const char *auth_mode = NULL; - if (m_conn_info->auth_type == TP_AUTH_TYPE_PASSWORD) - auth_mode = "password"; - else if (m_conn_info->auth_type == TP_AUTH_TYPE_NONE) - auth_mode = "nothing"; - else - auth_mode = "unknown"; + const char *auth_mode = NULL; + if (m_conn_info->auth_type == TP_AUTH_TYPE_PASSWORD) + auth_mode = "password"; + else if (m_conn_info->auth_type == TP_AUTH_TYPE_NONE) + auth_mode = "nothing"; + else + auth_mode = "unknown"; - ex_astr line(w, '='); + ex_astr line(w, '='); - snprintf(buf, sizeof(buf), - "\r\n"\ - "%s\r\n"\ - "Teleport TELNET Bastion Server...\r\n"\ - " - teleport to %s:%d\r\n"\ - " - authroized by %s\r\n"\ - "%s\r\n"\ - "\r\n\r\n", - line.c_str(), - m_conn_ip.c_str(), - m_conn_port, auth_mode, - line.c_str() - ); + snprintf(buf, sizeof(buf), + "\r\n"\ + "%s\r\n"\ + "Teleport TELNET Bastion Server...\r\n"\ + " - teleport to %s:%d\r\n"\ + " - authroized by %s\r\n"\ + "%s\r\n"\ + "\r\n\r\n", + line.c_str(), + m_conn_ip.c_str(), + m_conn_port, auth_mode, + line.c_str() + ); - m_conn_client->send((ex_u8*)buf, strlen(buf)); + m_conn_client->send((ex_u8 *) buf, strlen(buf)); - if (m_is_putty_mode) - { - if (m_conn_info->auth_type != TP_AUTH_TYPE_NONE) { - ex_astr login_info = "login: "; - login_info += m_conn_info->acc_username; - login_info += "\r\n"; - m_conn_client->send((ex_u8*)login_info.c_str(), login_info.length()); - m_rec.record(TS_RECORD_TYPE_TELNET_DATA, (ex_u8*)login_info.c_str(), login_info.length()); - } + if (m_is_putty_mode) { + if (m_conn_info->auth_type != TP_AUTH_TYPE_NONE) { + ex_astr login_info = "login: "; + login_info += m_conn_info->acc_username; + login_info += "\r\n"; + m_conn_client->send((ex_u8 *) login_info.c_str(), login_info.length()); + m_rec.record(TS_RECORD_TYPE_TELNET_DATA, (ex_u8 *) login_info.c_str(), login_info.length()); + } - ex_u8 _d[] = "\xff\xfb\x1f\xff\xfb\x20\xff\xfb\x18\xff\xfb\x27\xff\xfd\x01\xff\xfb\x03\xff\xfd\x03"; - m_conn_server->send(_d, sizeof(_d) - 1); - } + ex_u8 _d[] = "\xff\xfb\x1f\xff\xfb\x20\xff\xfb\x18\xff\xfb\x27\xff\xfd\x01\xff\xfb\x03\xff\xfd\x03"; + m_conn_server->send(_d, sizeof(_d) - 1); + } - return s_relay; + return s_relay; } sess_state TelnetSession::_do_relay(TelnetConn *conn) { - m_last_access_timestamp = (ex_u32)time(NULL); + m_last_access_timestamp = (ex_u32) time(NULL); - TelnetSession* _this = conn->session(); - bool is_processed = false; + TelnetSession *_this = conn->session(); + bool is_processed = false; - if (conn->is_server_side()) - { + if (conn->is_server_side()) { // EXLOG_BIN(m_conn_client->data().data(), m_conn_client->data().size(), "<-- client:"); - // 收到了客户端发来的数据 - if (_this->m_is_putty_mode && !_this->m_username_sent) - { - if (_this->_putty_replace_username(m_conn_client, m_conn_server)) - { - //_this->m_username_sent = true; - is_processed = true; - } - } + // 收到了客户端发来的数据 + if (_this->m_is_putty_mode && !_this->m_username_sent) { + if (_this->_putty_replace_username(m_conn_client, m_conn_server)) { + //_this->m_username_sent = true; + is_processed = true; + } + } - if (is_processed) - { - m_conn_client->data().empty(); - return s_relay; - } + if (is_processed) { + m_conn_client->data().empty(); + return s_relay; + } - if (_this->_parse_win_size(m_conn_client)) { - if (!m_startup_win_size_recorded) { - m_rec.record_win_size_startup(m_win_width, m_win_height); - m_startup_win_size_recorded = true; - } - m_rec.record_win_size_change(m_win_width, m_win_height); - } + if (_this->_parse_win_size(m_conn_client)) { + if (!m_startup_win_size_recorded) { + m_rec.record_win_size_startup(m_win_width, m_win_height); + m_startup_win_size_recorded = true; + } + m_rec.record_win_size_change(m_win_width, m_win_height); + } - m_conn_server->send(m_conn_client->data().data(), m_conn_client->data().size()); - m_conn_client->data().empty(); - } - else - { + m_conn_server->send(m_conn_client->data().data(), m_conn_client->data().size()); + m_conn_client->data().empty(); + } else { // EXLOG_BIN(m_conn_server->data().data(), m_conn_server->data().size(), "--> server:"); - - // 收到了服务端返回的数据 - if (m_conn_server->data().data()[0] != TELNET_IAC) - m_rec.record(TS_RECORD_TYPE_TELNET_DATA, m_conn_server->data().data(), m_conn_server->data().size()); - if (!_this->m_username_sent && _this->m_acc_name.length() > 0) - { - if (_this->_parse_find_and_send(m_conn_server, m_conn_client, _this->m_username_prompt.c_str(), _this->m_acc_name.c_str())) - { + // 收到了服务端返回的数据 + if (m_conn_server->data().data()[0] != TELNET_IAC) + m_rec.record(TS_RECORD_TYPE_TELNET_DATA, m_conn_server->data().data(), m_conn_server->data().size()); + + if (!_this->m_username_sent && _this->m_acc_name.length() > 0) { + if (_this->_parse_find_and_send(m_conn_server, m_conn_client, _this->m_username_prompt.c_str(), + _this->m_acc_name.c_str())) { // _this->m_username_sent = true; - is_processed = true; - } - } - if (!_this->m_password_sent && _this->m_password_prompt.length() > 0) - { - if (_this->_parse_find_and_send(m_conn_server, m_conn_client, _this->m_password_prompt.c_str(), _this->m_acc_secret.c_str())) - { + is_processed = true; + } + } + if (!_this->m_password_sent && _this->m_password_prompt.length() > 0) { + if (_this->_parse_find_and_send(m_conn_server, m_conn_client, _this->m_password_prompt.c_str(), + _this->m_acc_secret.c_str())) { _this->m_username_sent = true; _this->m_password_sent = true; _this->m_username_sent = true; - is_processed = true; - } - } + is_processed = true; + } + } - if (is_processed) - { - m_conn_server->data().empty(); - return s_relay; - } + if (is_processed) { + m_conn_server->data().empty(); + return s_relay; + } - m_conn_client->send(m_conn_server->data().data(), m_conn_server->data().size()); - m_conn_server->data().empty(); - } + m_conn_client->send(m_conn_server->data().data(), m_conn_server->data().size()); + m_conn_server->data().empty(); + } - return s_relay; + return s_relay; } -bool TelnetSession::_parse_find_and_send(TelnetConn* conn_recv, TelnetConn* conn_remote, const char* find, const char* send) -{ +bool TelnetSession::_parse_find_and_send(TelnetConn *conn_recv, TelnetConn *conn_remote, const char *find, + const char *send) { // EXLOGV("find prompt and send: [%s] => [%s]\n", find, send); // EXLOG_BIN(conn_recv->data().data(), conn_recv->data().size(), "find prompt in data:"); - size_t find_len = strlen(find); - size_t send_len = strlen(send); + size_t find_len = strlen(find); + size_t send_len = strlen(send); if (0 == find_len || 0 == send_len || conn_recv->data().size() < find_len) { return false; } int find_range = conn_recv->data().size() - find_len; - for (int i = 0; i <= find_range; ++i) - { - if (0 == memcmp(conn_recv->data().data() + i, find, find_len)) - { + for (int i = 0; i <= find_range; ++i) { + if (0 == memcmp(conn_recv->data().data() + i, find, find_len)) { conn_remote->send(conn_recv->data().data(), conn_recv->data().size()); conn_recv->data().empty(); MemBuffer mbuf_msg; mbuf_msg.reserve(128); - mbuf_msg.append((ex_u8*)send, send_len); - mbuf_msg.append((ex_u8*)"\x0d\x0a", 2); + mbuf_msg.append((ex_u8 *) send, send_len); + mbuf_msg.append((ex_u8 *) "\x0d\x0a", 2); // EXLOG_BIN(mbuf_msg.data(), mbuf_msg.size(), "find prompt and send:"); conn_recv->send(mbuf_msg.data(), mbuf_msg.size()); return true; @@ -636,233 +592,210 @@ bool TelnetSession::_parse_find_and_send(TelnetConn* conn_recv, TelnetConn* conn } #if 0 - MemBuffer mbuf_msg; - mbuf_msg.reserve(128); - MemStream ms_msg(mbuf_msg); + MemBuffer mbuf_msg; + mbuf_msg.reserve(128); + MemStream ms_msg(mbuf_msg); - MemStream s(conn_recv->data()); - ex_u8 ch = 0; - ex_u8 ch_cmd = 0; - for (; s.left() > 0;) - { - ch = s.get_u8(); - if (ch == TELNET_IAC) - { - if (s.left() < 2) - return false; + MemStream s(conn_recv->data()); + ex_u8 ch = 0; + ex_u8 ch_cmd = 0; + for (; s.left() > 0;) + { + ch = s.get_u8(); + if (ch == TELNET_IAC) + { + if (s.left() < 2) + return false; - ch_cmd = s.get_u8(); - if (ch_cmd == TELNET_SB) - { - // SUB NEGOTIATION,变长数据,以 FF F0 结束 - bool have_SE = false; - ex_u8 ch_sub = 0; - for (; s.left() > 0;) - { - ch_sub = s.get_u8(); - if (ch_sub == TELNET_IAC) - { - if (s.left() > 0) - { - if (s.get_u8() == TELNET_SE) - { - have_SE = true; - break; - } - else - return false; - } - } - } + ch_cmd = s.get_u8(); + if (ch_cmd == TELNET_SB) + { + // SUB NEGOTIATION,变长数据,以 FF F0 结束 + bool have_SE = false; + ex_u8 ch_sub = 0; + for (; s.left() > 0;) + { + ch_sub = s.get_u8(); + if (ch_sub == TELNET_IAC) + { + if (s.left() > 0) + { + if (s.get_u8() == TELNET_SE) + { + have_SE = true; + break; + } + else + return false; + } + } + } - if (!have_SE) - return false; - } - else - { - s.skip(1); - } - } - else - { - ms_msg.put_u8(ch); - } - } + if (!have_SE) + return false; + } + else + { + s.skip(1); + } + } + else + { + ms_msg.put_u8(ch); + } + } - if (mbuf_msg.size() < find_len) - return false; + if (mbuf_msg.size() < find_len) + return false; - int find_range = mbuf_msg.size() - find_len; - for (int i = 0; i < find_range; ++i) - { - if (0 == memcmp(mbuf_msg.data() + i, find, find_len)) - { - conn_remote->send(conn_recv->data().data(), conn_recv->data().size()); - conn_recv->data().empty(); + int find_range = mbuf_msg.size() - find_len; + for (int i = 0; i < find_range; ++i) + { + if (0 == memcmp(mbuf_msg.data() + i, find, find_len)) + { + conn_remote->send(conn_recv->data().data(), conn_recv->data().size()); + conn_recv->data().empty(); - mbuf_msg.empty(); - mbuf_msg.append((ex_u8*)send, send_len); - mbuf_msg.append((ex_u8*)"\x0d\x0a", 2); - conn_recv->send(mbuf_msg.data(), mbuf_msg.size()); - return true; - } - } + mbuf_msg.empty(); + mbuf_msg.append((ex_u8*)send, send_len); + mbuf_msg.append((ex_u8*)"\x0d\x0a", 2); + conn_recv->send(mbuf_msg.data(), mbuf_msg.size()); + return true; + } + } #endif - return false; + return false; } -bool TelnetSession::_putty_replace_username(TelnetConn* conn_recv, TelnetConn* conn_remote) -{ - bool replaced = false; +bool TelnetSession::_putty_replace_username(TelnetConn *conn_recv, TelnetConn *conn_remote) { + bool replaced = false; - MemBuffer mbuf_msg; - mbuf_msg.reserve(128); - MemStream ms_msg(mbuf_msg); + MemBuffer mbuf_msg; + mbuf_msg.reserve(128); + MemStream ms_msg(mbuf_msg); - MemStream s(conn_recv->data()); - ex_u8 ch = 0; - ex_u8 ch_cmd = 0; - for (; s.left() > 0;) - { - ch = s.get_u8(); - if (ch == TELNET_IAC) - { - if (s.left() < 2) - return false; + MemStream s(conn_recv->data()); + ex_u8 ch = 0; + ex_u8 ch_cmd = 0; + for (; s.left() > 0;) { + ch = s.get_u8(); + if (ch == TELNET_IAC) { + if (s.left() < 2) + return false; - ch_cmd = s.get_u8(); - if (ch_cmd == TELNET_SB) - { - size_t _begin = s.offset(); - size_t _end = 0; + ch_cmd = s.get_u8(); + if (ch_cmd == TELNET_SB) { + size_t _begin = s.offset(); + size_t _end = 0; - // SUB NEGOTIATION,变长数据,以 FF F0 结束 - bool have_SE = false; - ex_u8 ch_sub = 0; - for (; s.left() > 0;) - { - _end = s.offset(); - ch_sub = s.get_u8(); - if (ch_sub == TELNET_IAC) - { - if (s.left() > 0) - { - if (s.get_u8() == TELNET_SE) - { - have_SE = true; - break; - } - else - return false; - } - } - } + // SUB NEGOTIATION,变长数据,以 FF F0 结束 + bool have_SE = false; + ex_u8 ch_sub = 0; + for (; s.left() > 0;) { + _end = s.offset(); + ch_sub = s.get_u8(); + if (ch_sub == TELNET_IAC) { + if (s.left() > 0) { + if (s.get_u8() == TELNET_SE) { + have_SE = true; + break; + } else + return false; + } + } + } - if (!have_SE) - return false; + if (!have_SE) + return false; - size_t len = _end - _begin; - if (len <= 8 || 0 != memcmp("\x27\x00\x00\x55\x53\x45\x52\x01", conn_recv->data().data() + _begin, 8)) - { - ms_msg.put_u8(TELNET_IAC); - ms_msg.put_u8(TELNET_SB); - ms_msg.put_bin(conn_recv->data().data() + _begin, len); - ms_msg.put_u8(TELNET_IAC); - ms_msg.put_u8(TELNET_SE); - continue; - } + size_t len = _end - _begin; + if (len <= 8 || 0 != memcmp("\x27\x00\x00\x55\x53\x45\x52\x01", conn_recv->data().data() + _begin, 8)) { + ms_msg.put_u8(TELNET_IAC); + ms_msg.put_u8(TELNET_SB); + ms_msg.put_bin(conn_recv->data().data() + _begin, len); + ms_msg.put_u8(TELNET_IAC); + ms_msg.put_u8(TELNET_SE); + continue; + } - // 到这里就找到了客户端发来的用户名,我们将其替换为真实的远程账号。 + // 到这里就找到了客户端发来的用户名,我们将其替换为真实的远程账号。 - ms_msg.put_u8(TELNET_IAC); - ms_msg.put_u8(TELNET_SB); - ms_msg.put_bin((ex_u8*)"\x27\x00\x00\x55\x53\x45\x52\x01", 8); + ms_msg.put_u8(TELNET_IAC); + ms_msg.put_u8(TELNET_SB); + ms_msg.put_bin((ex_u8 *) "\x27\x00\x00\x55\x53\x45\x52\x01", 8); - ms_msg.put_bin((ex_u8*)m_acc_name.c_str(), m_acc_name.length()); + ms_msg.put_bin((ex_u8 *) m_acc_name.c_str(), m_acc_name.length()); - ms_msg.put_u8(TELNET_IAC); - ms_msg.put_u8(TELNET_SE); + ms_msg.put_u8(TELNET_IAC); + ms_msg.put_u8(TELNET_SE); - replaced = true; - } - else - { - ms_msg.put_u8(ch); - ms_msg.put_u8(ch_cmd); - ms_msg.put_u8(s.get_u8()); - } - } - else - { - ms_msg.put_u8(ch); - } - } + replaced = true; + } else { + ms_msg.put_u8(ch); + ms_msg.put_u8(ch_cmd); + ms_msg.put_u8(s.get_u8()); + } + } else { + ms_msg.put_u8(ch); + } + } - if (replaced) - { - conn_remote->send(mbuf_msg.data(), mbuf_msg.size()); - return true; - } + if (replaced) { + conn_remote->send(mbuf_msg.data(), mbuf_msg.size()); + return true; + } - return false; + return false; } -bool TelnetSession::_parse_win_size(TelnetConn* conn) { - if (conn->data().size() < 9) - return false; - if (conn->data().data()[0] != TELNET_IAC) - return false; +bool TelnetSession::_parse_win_size(TelnetConn *conn) { + if (conn->data().size() < 9) + return false; + if (conn->data().data()[0] != TELNET_IAC) + return false; - bool is_sub = false; - MemStream s(conn->data()); - for (; s.left() > 0;) - { - if (s.get_u8() == TELNET_IAC) - { - if (s.left() < 2) - return false; + bool is_sub = false; + MemStream s(conn->data()); + for (; s.left() > 0;) { + if (s.get_u8() == TELNET_IAC) { + if (s.left() < 2) + return false; - if (s.get_u8() == TELNET_SB) - { - size_t _begin = s.offset(); - size_t _end = 0; + if (s.get_u8() == TELNET_SB) { + size_t _begin = s.offset(); + size_t _end = 0; - // SUB NEGOTIATION,变长数据,以 TELNET_IAC+TELNET_SE (FF F0) 结束 - bool have_SE = false; - ex_u8 ch_sub = 0; - for (; s.left() > 0;) - { - _end = s.offset(); - if (s.get_u8() == TELNET_IAC) - { - if (s.left() > 0) - { - if (s.get_u8() == TELNET_SE) - { - have_SE = true; - break; - } - else - return false; - } - } - } + // SUB NEGOTIATION,变长数据,以 TELNET_IAC+TELNET_SE (FF F0) 结束 + bool have_SE = false; + ex_u8 ch_sub = 0; + for (; s.left() > 0;) { + _end = s.offset(); + if (s.get_u8() == TELNET_IAC) { + if (s.left() > 0) { + if (s.get_u8() == TELNET_SE) { + have_SE = true; + break; + } else + return false; + } + } + } - if (!have_SE) - return false; + if (!have_SE) + return false; - size_t len = _end - _begin; - if (len == 5 && 0x1F == conn->data().data()[_begin]) { - s.seek(_begin + 1); - m_win_width = s.get_u16_be(); - m_win_height = s.get_u16_be(); - return true; - } - } - } - } + size_t len = _end - _begin; + if (len == 5 && 0x1F == conn->data().data()[_begin]) { + s.seek(_begin + 1); + m_win_width = s.get_u16_be(); + m_win_height = s.get_u16_be(); + return true; + } + } + } + } - return false; + return false; }