#include "bizchan.h" #include "quicklz.h" #define WIN32_LEAN_AND_MEAN #include #include #include #include #include #include #include #include "chan_protocol.h" //#include "acmstrdec.h" //#include "acmstrenc.h" #include "openssl\rc4.h" #include "ListEntry.h" #include #include "jpeg2k.h" #include "chinaEncrypt.h" #include #pragma comment(lib, "dbghelp.lib") #define PING_INTERVAL 10000 // 10s #define MAX_TIMEOUT 60000 //超时时间60S,20170313修改,解决排队机闪呼的问题 #define DEFAULT_RX_BUF_SIZE 8192 #define KEY_LEN 16 #define ENCRYPT_CHINA 1 typedef struct recv_info_t { int offset; char *buf; int buf_len; char *unzip_buf; int unzip_len; qlz_state_decompress decompress_state; }recv_info_t; typedef struct send_buf_node { LIST_ENTRY entry; char *buf; int left; int sended; int need_encrypt; }send_buf_node; typedef struct send_info_t { //send_buf_node *send_list; LIST_ENTRY send_list; CRITICAL_SECTION lock; //qlz_state_compress compress_state; }send_info_t; typedef struct img_recv_t { char *data; int length; int offset; int id; }img_recv_t; struct bizchan_t { bizchan_config_t config; OnRecvPacket winsync_on_recv_cb; OnMode mode_cb; void *winsync_user_data; bizchan_callback_t cb; void *tag; HANDLE work_thread; HANDLE evt; volatile int stop_flag; recv_info_t recv_info; send_info_t send_info; int screen_img_id; int photo_img_id; int b_primary_server; int remote_video_rtp_port; int remote_video_desc; char remote_client_id[32]; int connected; char local_pwd[KEY_LEN]; char remote_pwd[KEY_LEN]; RC4_KEY local_key; RC4_KEY remote_key; int remote_version; LARGE_INTEGER last_remote_active_time; LARGE_INTEGER last_local_active_time; screen_decoder_session_t *dec_session; }; typedef int (*lpfn_cryptionfun)(unsigned char * out ,int outLen,const unsigned char * in,int inLen); static lpfn_cryptionfun decodestring = NULL; static lpfn_cryptionfun encodestring = NULL; static unsigned char seed_key []= {0x81,0x32,0x13,0xf5,0x29,0x3b,0x52,0x37,0x61,0x98,0x33,0x15,0x72,0x31,0xfe,0x34}; static __inline unsigned int hash32_buf(const void *bf, size_t len, unsigned int hash) { const unsigned char *s = (const unsigned char*)bf; while (len-- != 0) /* "nemesi": k=257, r=r*257 */ hash = hash * 257 + *s++; return (hash * 257); } static void generate_rand_key(char *key, int size) { int i; srand(GetTickCount()*33); for (i = 0; i < size; ++i) { key[i] = (char)(rand() & 0xff); } srand(GetCurrentProcessId() * 33); for (i = 0; i < size; ++i) { key[i] ^= (char)(rand() & 0xff); } } static __inline unsigned long hash_key(const char *key, int size) { return hash32_buf(key, size, 0); } static __inline int check_hash(char *key, int size, int hash_code) { return hash32_buf(key, size, 0) == hash_code; } static __inline void GetTick(LARGE_INTEGER *last, LARGE_INTEGER *lt) { DWORD dwNow = GetTickCount(); if (last->LowPart > dwNow) { lt->LowPart = dwNow; lt->HighPart = last->HighPart + 1; } else { lt->LowPart = dwNow; lt->HighPart = last->HighPart; } } void bizlog(bizchan_t *chan, const char* fmt, ...) { if (chan){ va_list arg; va_start(arg, fmt); if (chan->cb.dbg) { (*chan->cb.dbg)(chan->cb.user_data, fmt, arg); } va_end(arg); } } BIZCHAN_API(int) bizchan_lib_init() { WSADATA wsaData; return WSAStartup(0x0202, &wsaData); } BIZCHAN_API(int) bizchan_lib_term() { return WSACleanup(); } static int config_copy(const bizchan_config_t *src, bizchan_config_t *dst) { memcpy(dst, src, sizeof(bizchan_config_t)); dst->proxy_server = _strdup(src->proxy_server); dst->bak_proxy_server = _strdup(src->bak_proxy_server); dst->session_id = _strdup(src->session_id); dst->agent_id = _strdup(src->agent_id); dst->client_id = _strdup(src->client_id); return 0; } static int config_check(const bizchan_config_t *config) { if (!config->proxy_server) return -1; if (config->proxy_server_port <= 0 || config->proxy_server_port >= 0xffff) return -1; if (config->bak_proxy_server) { if (config->bak_proxy_server_port <= 0 || config->bak_proxy_server_port >= 0xffff) return -1; } if (!config->session_id) return -1; if (!config->agent_id) return -1; return 0; } static void config_free(bizchan_config_t *config) { free(config->proxy_server); free(config->bak_proxy_server); free(config->session_id); free(config->agent_id); free(config->client_id); } static int callback_check(const bizchan_callback_t *cb) { if (!cb->on_close) { return -1; } if (!cb->on_connect) { return -1; } if (!cb->on_recv_pkt) { return -1; } return 0; } static void invoke_on_connect(bizchan_t *chan, int error) { if (error == 0) { chan->cb.on_connect(chan, error, chan->b_primary_server ? chan->config.proxy_server : chan->config.bak_proxy_server, chan->remote_video_rtp_port, chan->remote_video_desc, chan->remote_client_id, chan->cb.user_data); } else { chan->cb.on_connect(chan, error, NULL, 0, 0, NULL, chan->cb.user_data); } } //static FILE *rx_log_fp = NULL; static void invoke_on_recv_pkt(bizchan_t *chan, int type, int sub_type, int id, const char *pkt, int pkt_size) { /*if (rx_log_fp == NULL) { rx_log_fp = fopen("c:\\rxlog.txt", "wt"); fprintf(rx_log_fp, "===================\n"); } { SYSTEMTIME st; GetLocalTime(&st); fprintf(rx_log_fp, "[%02d:%02d:%02d.%03d] type = %d, sub_type = %d, id = %d, pkt_size = %d, hash = %d\n", st.wHour, st.wMinute, st.wSecond, st.wMilliseconds, type, sub_type, id, pkt_size, hash32_buf(pkt, pkt_size, 0)); fflush(rx_log_fp); }*/ //Dbg(chan, "invoke_on_recv_pkt, type:%d, sub_type:%d, id:%d, pkt_size:%d", type, sub_type, id, pkt_size); if (type == ACM_TYPE_SRN) { int cat = ACM_SRN_CAT(sub_type); if (cat == ACM_SRN_ANS) { if (id == chan->screen_img_id) { if (pkt_size == 4) { int err; memcpy(&err, pkt, 4); chan->cb.on_recv_screen(chan, id, err, 0, 0, NULL, 0, chan->cb.user_data); } else { int size = 0; int width, height; int rc; char *dec_buf = NULL; rc = screen_decoder_session_decode(chan->dec_session, pkt, pkt_size, &width, &height, dec_buf, &size); if (rc == 0) { dec_buf = (char*)malloc(size); rc = screen_decoder_session_decode(chan->dec_session, pkt, pkt_size, &width, &height, dec_buf, &size); } if (rc == 0) { chan->cb.on_recv_screen(chan, id, 0, width, height, dec_buf, size, chan->cb.user_data); } else { chan->cb.on_recv_screen(chan, id, rc, 0, 0, NULL, 0, chan->cb.user_data); } if (dec_buf) free(dec_buf); } } } else { chan->cb.on_recv_pkt(chan, type, sub_type, id, pkt, pkt_size, chan->cb.user_data); } } else if (type == ACM_TYPE_PHT) { int cat = ACM_PHT_CAT(sub_type); if (cat == ACM_PHT_ANS) { if (id == chan->photo_img_id) { if (pkt_size == 4) { int err; memcpy(&err, pkt, 4); chan->cb.on_recv_photo(chan, id, err, 0, 0, NULL, 0, chan->cb.user_data); } else { jpeg2k_raw_image raw_image = {0}; jpeg2k_coded_image codec_image = {0}; int rc; codec_image.data = (unsigned char*)pkt; codec_image.len = pkt_size; rc = jpeg2k_decode(&raw_image, &codec_image); if (rc == 0) { chan->cb.on_recv_photo(chan, id, 0, raw_image.width, raw_image.height, (const char*)&raw_image.data[0], raw_image.len, chan->cb.user_data); jpeg2k_decode_free(&raw_image); } else { chan->cb.on_recv_photo(chan, id, rc, 0, 0, NULL, 0, chan->cb.user_data); } } } } else { chan->cb.on_recv_pkt(chan, type, sub_type, id, pkt, pkt_size, chan->cb.user_data); } } else if (type == ACM_TYPE_SYNC) { if (chan->winsync_on_recv_cb) { chan->winsync_on_recv_cb(sub_type, pkt, pkt_size, chan->winsync_user_data); } //同时上报应用层,用于应用层判断采用哪种同步方式(Sivilight或者chrome H5) chan->cb.on_recv_pkt(chan, type, sub_type, id, pkt, pkt_size, chan->cb.user_data); } else if (type == ACM_TYPE_MODE) { if (chan->mode_cb) { chan->mode_cb(TRUE, chan->winsync_user_data); } chan->cb.on_recv_pkt(chan, type, sub_type, id, pkt, pkt_size, chan->cb.user_data); } else if (type == ACM_TYPE_PING) { //..... remote ping, nothing todo } else { chan->cb.on_recv_pkt(chan, type, sub_type, id, pkt, pkt_size, chan->cb.user_data); } } static void invoke_on_close(bizchan_t *chan) { if (chan->cb.on_close) { chan->cb.on_close(chan, chan->cb.user_data); } } static void invoke_on_destroy(bizchan_t *chan) { if (chan->cb.on_destroy) { chan->cb.on_destroy(chan, chan->cb.user_data); } } static FILE *fp = NULL; static int on_recv2(bizchan_t *chan, SOCKET conn) { int n; char buf[0x10000+sizeof(acm_hdr)]; if (fp == NULL) { fp = fopen ("g:\\rx.dat", "wb"); } do { n = recv(conn, buf, sizeof(buf), 0); if (n > 0) { fwrite(buf, 1, n, fp); fflush(fp); } } while (n > 0); return (n == 0 || (GetLastError() == WSAEWOULDBLOCK)) ? 0 : -1; } static int on_recv(bizchan_t *chan, SOCKET conn) { recv_info_t *ri = &chan->recv_info; int n; do { n = recv(conn, ri->buf+ri->offset, ri->buf_len-ri->offset, 0); if (n > 0) { int i = 0; ri->offset += n; GetTick(&chan->last_remote_active_time, &chan->last_remote_active_time); while (ri->offset-i >= sizeof(acm_hdr)) { acm_hdr *hdr = (acm_hdr*)&ri->buf[i]; //Dbg(chan, "on_recv, i:%d offset:%d, recv_length:%d", i, ri->offset, n); //bizlog(chan, "on_recv, encrypt:%u, type:%u, sub_type:%u, length:%lu, compress:%u", hdr->encrypt, hdr->type, hdr->sub_type, hdr->length, hdr->compress); if (hdr->length == 0) { printf("broken"); } if (ri->offset-i >= hdr->length+sizeof(acm_hdr)) { if (hdr->encrypt) { int dec_length = hdr->length; char *dec_buf = (char*)malloc(hdr->length); int sm4_dec_result = DecStrWithSM4_ECB(chan->remote_pwd, sizeof(chan->remote_pwd), (unsigned char*)(&hdr->data[0]), hdr->length, (unsigned char*)dec_buf, &dec_length); if (sm4_dec_result != 0){ bizlog(chan, "DecStrWithSM4_ECB failed, type:%u, sub_type:%u, length:%lu", hdr->type, hdr->sub_type, hdr->length); RC4_set_key(&chan->remote_key, sizeof(chan->remote_pwd), (unsigned char*)chan->remote_pwd); RC4(&chan->remote_key, hdr->length, (const unsigned char*)(&hdr->data[0]), (unsigned char*)dec_buf); dec_length = hdr->length; } if (hdr->compress) { int len = (int)qlz_size_decompressed(dec_buf); char *unzip_buf = (char*)malloc(len); len = qlz_decompress(dec_buf, unzip_buf, &ri->decompress_state); if (check_hash(unzip_buf, len, hdr->hash)) { invoke_on_recv_pkt(chan, hdr->type, hdr->sub_type, hdr->id, unzip_buf, len); } else { //OutputDebugStringA("pkt hash failed!\n"); bizlog(chan, "encrypt compress pkt hash failed! type:%u, sub_type:%u, length:%lu, hash:%lu, unzip:%d", hdr->type, hdr->sub_type, hdr->length, hdr->hash, len); } free(unzip_buf); } else { //sm4解密后hdr->length长度与内容长度不一致,采用dec_length变量 if (check_hash(dec_buf, dec_length, hdr->hash)) { invoke_on_recv_pkt(chan, hdr->type, hdr->sub_type, hdr->id, dec_buf, dec_length); } else { //OutputDebugStringA("pkt hash failed!\n"); bizlog(chan, "encrypt uncompress pkt hash failed! type:%u, sub_type:%u, length:%lu, hash:%lu", hdr->type, hdr->sub_type, hdr->length, hdr->hash); } } free(dec_buf); } else { if (hdr->compress) { int len = (int)qlz_size_decompressed((const char*)&hdr->data[0]); char *unzip_buf = (char*)malloc(len); len = qlz_decompress((const char*)&hdr->data[0], unzip_buf, &ri->decompress_state); if (check_hash(unzip_buf, len, hdr->hash)) { invoke_on_recv_pkt(chan, hdr->type, hdr->sub_type, hdr->id, unzip_buf, len); } else { //OutputDebugStringA("pkt hash failed!\n"); bizlog(chan, "compress pkt hash failed! type:%u, sub_type:%u, length:%lu, hash:%lu, unzip:%d", hdr->type, hdr->sub_type, hdr->length, hdr->hash, len); } free(unzip_buf); } else { if (check_hash((char*)&hdr->data[0], hdr->length, hdr->hash)) { invoke_on_recv_pkt(chan, hdr->type, hdr->sub_type, hdr->id, (const char*)&hdr->data[0], hdr->length); } else { //OutputDebugStringA("pkt hash failed!\n"); bizlog(chan, "uncompress pkt hash failed! type:%u, sub_type:%u, length:%lu, hash:%lu", hdr->type, hdr->sub_type, hdr->length, hdr->hash); } } } i += hdr->length+sizeof(acm_hdr); } else { break; } } if (i != ri->offset) { memmove(&ri->buf[0], &ri->buf[i], ri->offset-i); } ri->offset -= i; if (ri->offset == ri->buf_len) { // double large ri->buf_len = 2 * ri->buf_len; ri->buf = (char*)realloc(ri->buf, ri->buf_len); } } } while (n > 0); return (n == 0 || (GetLastError() == WSAEWOULDBLOCK)) ? 0 : -1; } static int on_send(bizchan_t *chan, SOCKET conn) { send_info_t *si = &chan->send_info; int n = 0; EnterCriticalSection(&si->lock); if (!ListEntry_IsEmpty(&si->send_list)) { do { send_buf_node *t = CONTAINING_RECORD(ListEntry_GetHead(&si->send_list), send_buf_node, entry); if (t->need_encrypt) { //SM4加密,密文会比明文长16字节 int enc_length = t->left + sizeof(acm_hdr)+16; acm_hdr *hdr = (acm_hdr*)t->buf; char *enc_buf = (char*)malloc(t->left+sizeof(acm_hdr) + 16); //version为2代表支持国密,采用SM4加密 if(chan->remote_version != 1){ EncStrWithSM4_ECB(chan->local_pwd, sizeof(chan->local_pwd), (unsigned char*)(&hdr->data[0]), hdr->length, (unsigned char*)(enc_buf+sizeof(acm_hdr)), &enc_length); hdr->length = enc_length; t->left = enc_length + sizeof(acm_hdr); //Dbg(chan, "enc_length:%d", enc_length); } else { RC4_set_key(&chan->local_key, sizeof(chan->local_pwd), (unsigned char*)chan->local_pwd); RC4(&chan->local_key, t->left, (const unsigned char*)(&hdr->data[0]), (unsigned char*)(enc_buf+sizeof(acm_hdr))); } memcpy(enc_buf, hdr, sizeof(acm_hdr)); free(t->buf); t->buf = enc_buf; t->need_encrypt = 0; } n = send(conn, t->buf+t->sended, t->left, 0); if (n > 0) { char tmp[32] = {0}; _snprintf(tmp, 32, "send out %d bytes!\n", n); OutputDebugStringA(tmp); //Dbg(chan, tmp); t->left -= n; t->sended += n; if (t->left == 0) { ListEntry_DeleteNode(&t->entry); free(t->buf); free(t); } GetTick(&chan->last_local_active_time, &chan->last_local_active_time); } } while (n > 0 && !ListEntry_IsEmpty(&si->send_list)); } LeaveCriticalSection(&si->lock); return (n >= 0 || (GetLastError() == WSAEWOULDBLOCK)) ? 0 : -1; } static void on_close(bizchan_t *chan) { invoke_on_close(chan); } static int prepare_socket(SOCKET s, HANDLE evt) { BOOL opt = TRUE; int rc; rc = setsockopt(s, IPPROTO_TCP, TCP_NODELAY, (char*)&opt, sizeof(opt)); opt = TRUE; if (rc == 0) rc = setsockopt(s, SOL_SOCKET, SO_DONTLINGER, (char*)&opt, sizeof(opt)); if (rc == 0) rc = WSAEventSelect(s, evt, FD_CONNECT | FD_ACCEPT | FD_CLOSE | FD_READ | FD_WRITE); return rc; } static void dump_exception(PEXCEPTION_POINTERS ExceptionInfo) { char tmp[MAX_PATH]; HANDLE hDumpFile; sprintf(tmp, ".\\bizchan_%d.dmp", GetCurrentProcessId()); hDumpFile = CreateFileA( tmp, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL ); if( ( hDumpFile != NULL ) && ( hDumpFile != INVALID_HANDLE_VALUE ) ) { MINIDUMP_EXCEPTION_INFORMATION mdei; MINIDUMP_TYPE mdt; mdei.ThreadId = GetCurrentThreadId(); mdei.ExceptionPointers = ExceptionInfo; mdei.ClientPointers = FALSE; mdt = MiniDumpWithFullMemory; MiniDumpWriteDump( GetCurrentProcess(), GetCurrentProcessId(), hDumpFile, mdt, (ExceptionInfo != 0) ? &mdei : 0, 0, 0 ); CloseHandle( hDumpFile ); } } static BOOL addr_is_domain(const char* pserver_addr) { BOOL bret = FALSE; if (NULL == pserver_addr){ return bret; } if (strstr(pserver_addr, ".com") ||strstr(pserver_addr, ".cn")){ bret = TRUE; } return bret; } static unsigned long biz_get_inetaddr(bizchan_t *chan, BOOL bprimary, const char* pserver) { unsigned long uret = 0; if (NULL == pserver){ return uret; } uret = inet_addr(pserver); return uret; } static void process(bizchan_t *chan) { SOCKET conn = INVALID_SOCKET; struct sockaddr_in addr = {0}; int rc; HANDLE evts[2] = {chan->evt, NULL}; evts[1] = WSACreateEvent(); // try connect to primary proxy server addr.sin_family = AF_INET; addr.sin_port = htons(chan->config.proxy_server_port); //addr.sin_addr.s_addr = inet_addr(chan->config.proxy_server); addr.sin_addr.s_addr = biz_get_inetaddr(chan, TRUE, chan->config.proxy_server); chan->b_primary_server = TRUE; conn = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (conn == INVALID_SOCKET) { goto on_error; } rc = prepare_socket(conn, evts[1]); if (rc != 0) { goto on_error; } rc = connect(conn, (struct sockaddr*)&addr, sizeof(addr)); if (rc == -1 && WSAGetLastError() == WSAEWOULDBLOCK) { rc = 0; } if (rc == -1 && chan->config.bak_proxy_server && strlen(chan->config.bak_proxy_server)) { // try connect to back proxy server closesocket(conn); conn = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (conn == INVALID_SOCKET) { goto on_error; } WSAResetEvent(evts[1]); rc = prepare_socket(conn, evts[1]); if (rc != 0) { goto on_error; } addr.sin_port = htons(chan->config.bak_proxy_server_port); //addr.sin_addr.s_addr = inet_addr(chan->config.bak_proxy_server); addr.sin_addr.s_addr = biz_get_inetaddr(chan, FALSE, chan->config.bak_proxy_server); chan->b_primary_server = 0; rc = connect(conn, (struct sockaddr*)&addr, sizeof(addr)); if (rc == -1 && WSAGetLastError() == WSAEWOULDBLOCK) { rc = 0; } } if (rc == -1) { goto on_error; } if (rc == 0) { proxy_ack_hdr ack_hdr; int ack_hdr_recv_bytes = 0; lpfn_cryptionfun encodefun = encodestring; lpfn_cryptionfun decodefun = decodestring; while (!chan->stop_flag && !chan->connected) { // wait until connected DWORD dwRet = WaitForMultipleObjects(2, evts, FALSE, MAX_TIMEOUT); if (dwRet == WAIT_OBJECT_0) { WSAResetEvent(evts[0]); } else if (dwRet == WAIT_OBJECT_0+1) { int error = 0; WSANETWORKEVENTS netevents; if (WSAEnumNetworkEvents(conn, evts[1], &netevents) != SOCKET_ERROR) { if (netevents.lNetworkEvents & FD_CONNECT) { if (netevents.iErrorCode[FD_CONNECT_BIT]) error = netevents.iErrorCode[FD_CONNECT_BIT]; } if (error == 0) { if (netevents.lNetworkEvents & FD_WRITE) { error = netevents.iErrorCode[FD_WRITE_BIT]; if (error == 0) { int enc_length = KEY_LEN; proxy_hdr hdr = {0}; hdr.tag[0] = 'A'; hdr.tag[1] = 'C'; hdr.tag[2] = 'M'; hdr.version = ACM_PROTOCOL_VERSION; generate_rand_key(chan->local_pwd, KEY_LEN/2); //等待全部升级后再采用SM4加密 #if ENCRYPT_CHINA EncWithSM4_ECB(seed_key, (unsigned char*)&chan->local_pwd[0], KEY_LEN / 2, (unsigned char*)&hdr.encrypt_key[0], &enc_length); bizlog(chan, "%s","use SM4 password_crypt_type"); #else encodefun((unsigned char*)&hdr.encrypt_key[0], sizeof(hdr.encrypt_key), (unsigned char*)&chan->local_pwd[0], sizeof(chan->local_pwd)); bizlog(chan, "use old password_crypt_type"); #endif hdr.encrypt_keyhash = hash_key(chan->local_pwd, sizeof(chan->local_pwd)); memset(hdr.callee_id, ' ', sizeof(hdr.callee_id)); memset(hdr.caller_id, ' ', sizeof(hdr.caller_id)); memset(hdr.client_id, ' ', sizeof(hdr.client_id)); strncpy(&hdr.callee_id[0], chan->config.agent_id, sizeof(hdr.callee_id)-1); strncpy(&hdr.caller_id[0], chan->config.session_id, sizeof(hdr.caller_id)-1); if (chan->config.client_id) { strncpy(&hdr.client_id[0], chan->config.client_id, sizeof(hdr.client_id)-1); } else { hdr.client_id[0] = 0; } hdr.rtp_port = chan->config.video.rtp_port; hdr.media_desc = chan->config.video.desc; if (send(conn, (char*)&hdr, sizeof(hdr), 0) != sizeof(hdr)) { error = -1; } } } } if (error == 0) { if (netevents.lNetworkEvents & FD_CLOSE) error = -1; } if (error == 0) { if (netevents.lNetworkEvents & FD_READ) { error = netevents.iErrorCode[FD_READ_BIT]; if (error == 0) { int t; do { t = recv(conn, (char*)&ack_hdr + ack_hdr_recv_bytes, sizeof(ack_hdr) - ack_hdr_recv_bytes, 0); if (t > 0) { ack_hdr_recv_bytes += t; if (ack_hdr_recv_bytes == sizeof(ack_hdr)) { int hash_result = 1; int dec_length = KEY_LEN; int dec_result = DecWithSM4_ECB(seed_key, (unsigned char*)&ack_hdr.encrypt_key[0], sizeof(ack_hdr.encrypt_key), (unsigned char*)&chan->remote_pwd[0], &dec_length); bizlog(chan, "use SM4 Decode password result:%d", dec_result); //解密成功还要做hashcheck后,才能确认password正确 if (dec_result == 0) { hash_result = check_hash(chan->remote_pwd, sizeof(chan->remote_pwd), ack_hdr.encrypt_keyhash); } if(dec_result != 0 && hash_result){ dec_result = decodefun((unsigned char*)&chan->remote_pwd[0], sizeof(chan->remote_pwd), (unsigned char*)&ack_hdr.encrypt_key[0], sizeof(ack_hdr.encrypt_key)); bizlog(chan, "use old Decode password result:%d", dec_result); } if (check_hash(chan->remote_pwd, sizeof(chan->remote_pwd), ack_hdr.encrypt_keyhash)) { chan->remote_video_rtp_port = ack_hdr.rtp_port; chan->remote_video_desc = ack_hdr.media_desc; memcpy(chan->remote_client_id, ack_hdr.client_id, sizeof(chan->remote_client_id)); chan->remote_version = ack_hdr.version; bizlog(chan, "remote_acm_version:%d", chan->remote_version); chan->connected = 1; break; } else { error = -1; } } } } while (t > 0 && error == 0); if (t <= 0 && (WSAGetLastError() != WSAEWOULDBLOCK)) error = -1; } } } if (error != 0) goto on_error; } } else { goto on_error; } } } assert(conn != INVALID_SOCKET); if (chan->connected) { invoke_on_connect(chan, 0); chan->recv_info.offset = 0; rc = on_recv(chan, conn); if (rc) { on_close(chan); goto on_error; } while (!chan->stop_flag) { DWORD dwRet = WaitForMultipleObjects(2, evts, FALSE, 1000); if (dwRet == WAIT_OBJECT_0) { WSAResetEvent(chan->evt); rc = on_send(chan, conn); if (rc != 0) break; } else if (dwRet == WAIT_OBJECT_0+1) { WSANETWORKEVENTS netevents; if (WSAEnumNetworkEvents(conn, evts[1], &netevents) != SOCKET_ERROR) { if (netevents.lNetworkEvents & FD_READ) { rc = on_recv(chan, conn); } if (netevents.lNetworkEvents & FD_WRITE) { rc = on_send(chan, conn); } if (rc || (netevents.lNetworkEvents & FD_CLOSE)) { break; } } } else if (dwRet == WAIT_TIMEOUT) { LARGE_INTEGER now; GetTick(&chan->last_remote_active_time, &now); if (now.QuadPart - chan->last_remote_active_time.QuadPart >= PING_INTERVAL) { GetTick(&chan->last_local_active_time, &now); if (now.QuadPart - chan->last_local_active_time.QuadPart >= PING_INTERVAL) { bizchan_post_pkt(chan, ACM_TYPE_PING, 0, 0, 0, 0, NULL, 0); } } } else { goto on_error; } } on_close(chan); } on_error: if (!chan->connected) { invoke_on_connect(chan, -1); // connect failed! } else { //.... bizlog(chan, "%s", "connected, and error!"); } if (conn != INVALID_SOCKET) { closesocket(conn); } WSACloseEvent(evts[1]); } static unsigned int __stdcall work_proc(void *arg) { bizchan_t *chan = (bizchan_t *)arg; __try { process(chan); } __except(dump_exception(GetExceptionInformation()), EXCEPTION_EXECUTE_HANDLER) { //.... } return 0; } static int init_decode_func() { int ret = -1; if (!encodestring) { HMODULE hInst = LoadLibraryA("acmstrenc.dll"); if (hInst) { encodestring = (lpfn_cryptionfun)GetProcAddress(hInst, "encodestring"); } if (!encodestring) return ret; } if (!decodestring) { HMODULE hInst = LoadLibraryA("acmstrdec.dll"); if (hInst) { decodestring = (lpfn_cryptionfun)GetProcAddress(hInst, "decodestring"); } if (!decodestring) return ret; } if (encodestring && decodestring){ ret = 0; } return ret; } BIZCHAN_API(int) bizchan_create(const bizchan_config_t *config, const bizchan_callback_t *cb, bizchan_t **p_chan) { bizchan_t *chan = NULL; if (-1 == init_decode_func()){ return -1; } if (!config || !p_chan) { return -1; } if (config_check(config) != 0) { return -1; } if (callback_check(cb) != 0) { return -1; } chan = (bizchan_t*)malloc(sizeof(bizchan_t)); if (!chan) { goto on_error; } memset(chan, 0, sizeof(bizchan_t)); chan->recv_info.buf_len = DEFAULT_RX_BUF_SIZE; chan->recv_info.buf = (char*)malloc(chan->recv_info.buf_len); if (!chan->recv_info.buf) { goto on_error; } if (config_copy(config, &chan->config) != 0) { goto on_error; } memcpy(&chan->cb, cb, sizeof(bizchan_callback_t)); ListEntry_InitHead(&chan->send_info.send_list); InitializeCriticalSection(&chan->send_info.lock); screen_decoder_session_create(&chan->dec_session); chan->evt = WSACreateEvent(); if (!chan->evt) { goto on_error; } *p_chan = chan; return 0; on_error: bizchan_destroy(chan); return -1; } BIZCHAN_API(int) bizchan_winsync_set_cb(bizchan_t *chan, OnRecvPacket pkt_cb, OnMode mode_cb, void *user_data) { chan->winsync_on_recv_cb = pkt_cb; chan->mode_cb = mode_cb; chan->winsync_user_data = user_data; return 0; } BIZCHAN_API(void) bizchan_destroy(bizchan_t *chan) { if (chan) { if (chan->evt) { WSACloseEvent(chan->evt); chan->evt = NULL; } invoke_on_destroy(chan); assert(chan->work_thread == NULL); config_free(&chan->config); if (chan->recv_info.buf) { free(chan->recv_info.buf); } if (chan->recv_info.unzip_buf) { free(chan->recv_info.unzip_buf); } while (!ListEntry_IsEmpty(&chan->send_info.send_list)) { send_buf_node *p = CONTAINING_RECORD(ListEntry_RemoveListHead(&chan->send_info.send_list), send_buf_node, entry); free(p->buf); free(p); } DeleteCriticalSection(&chan->send_info.lock); if (chan->dec_session) { screen_decoder_session_destroy(chan->dec_session); chan->dec_session = NULL; } free(chan); } } BIZCHAN_API(void) bizchan_set_tag(bizchan_t *chan, void *tag) { chan->tag = tag; } BIZCHAN_API(void*) bizchan_get_tag(bizchan_t *chan) { return chan->tag; } BIZCHAN_API(int) bizchan_start_connect(bizchan_t *chan) { if (!chan) { return -1; } if (chan->work_thread) { return -1; } WSAResetEvent(chan->evt); chan->stop_flag = 0; chan->connected = 0; chan->work_thread = (HANDLE)_beginthreadex(NULL, 0, &work_proc, chan, 0, NULL); if (!chan->work_thread) { return -1; } // we now return, when connected, on_connect will invoked in work_proc thread return 0; } BIZCHAN_API(int) bizchan_start_close(bizchan_t *chan) { chan->stop_flag = 1; WSASetEvent(chan->evt); return 0; } BIZCHAN_API(int) bizchan_close(bizchan_t *chan) { if (chan->work_thread) { WaitForSingleObject(chan->work_thread, INFINITE); CloseHandle(chan->work_thread); chan->work_thread = NULL; } return 0; } //static FILE *tx_log_fp = NULL; BIZCHAN_API(int) bizchan_post_pkt(bizchan_t *chan, int type, int compress, int encrypt, int sub_type, int id, const char *pkt, int pkt_size) { send_buf_node *t; if (!chan->connected) return -1; t = (send_buf_node *)malloc(sizeof(send_buf_node)); if (type == ACM_TYPE_SRN) { int cat = ACM_SRN_CAT(sub_type); if (cat == ACM_SRN_REQ) { chan->screen_img_id = id; } } else if (type == ACM_TYPE_PHT) { int cat = ACM_PHT_CAT(sub_type); if (cat == ACM_PHT_REQ) { chan->photo_img_id = id; } } if (!compress || pkt_size == 0) { acm_hdr *hdr; t->buf = (char*)malloc(pkt_size + sizeof(acm_hdr)); t->left = pkt_size + sizeof(acm_hdr); t->sended = 0; hdr = (acm_hdr*)&t->buf[0]; hdr->compress = 0; hdr->length = pkt_size; hdr->sub_type = sub_type; hdr->type = type; hdr->id = id; hdr->encrypt = !!encrypt; hdr->hash = hash_key(pkt, pkt_size); memcpy(&hdr->data[0], pkt, pkt_size); t->need_encrypt = encrypt; } else { qlz_state_compress state_compress; acm_hdr *hdr; int new_pkt_size; t->buf = (char*)malloc(2*pkt_size + sizeof(acm_hdr) + 16); hdr = (acm_hdr *)&t->buf[0]; new_pkt_size = (int)qlz_compress(pkt, (char*)&hdr->data[0], pkt_size, &state_compress); if (new_pkt_size < pkt_size) { hdr->compress = 1; hdr->length = new_pkt_size; t->left = new_pkt_size + sizeof(acm_hdr); } else { hdr->compress = 0; hdr->length = pkt_size; memcpy(&hdr->data[0], pkt, pkt_size); t->left = pkt_size + sizeof(acm_hdr); } hdr->type = type; hdr->id = id; hdr->sub_type = sub_type; hdr->encrypt = !!encrypt; hdr->hash = hash_key(pkt, pkt_size); t->sended = 0; t->need_encrypt = encrypt; } EnterCriticalSection(&chan->send_info.lock); ListEntry_AddTail(&chan->send_info.send_list, &t->entry); LeaveCriticalSection(&chan->send_info.lock); WSASetEvent(chan->evt); return 0; } BIZCHAN_API(int) bizchan_winsync_send(bizchan_t *chan, int sub_type, const void *buf, int size) { if (chan && chan->work_thread) { return bizchan_post_pkt(chan, ACM_TYPE_SYNC, 1, sub_type, 1, 0, (const char*)buf, size); } else { return -1; } }