#include "precompile.h" #include "sp_sps.h" #include "sp_def.h" #include "sp_logwithlinkforc.h" #include "memutil.h" #include #define SILVERLIGHT_POLICY_PORT 943 #define MAX_TIMEOUT 30000 static const char *req_policy = ""; static const int req_policy_len = 22; static const char *res_policy = "\r\n" "\r\n" " \r\n" " \r\n" " \r\n" " \r\n" " \r\n" " \r\n" " \r\n" " \r\n" " \r\n" " \r\n" "\r\n"; static const int res_policy_len = 323; struct sp_sps_t { WSAEVENT evt_ready; int result; WSAEVENT evt_stop; HANDLE worker_thread; }; static void __on_accept(SOCKET policy_fd) { struct sockaddr_in from_addr; int from_len = sizeof(from_addr); SOCKET conn_fd = accept(policy_fd, (struct sockaddr*)&from_addr, &from_len); u_long iMode = 0; int recved = 0; char req_buf[512]; int buf_len = sizeof(req_buf); int sended = 0; int need_send = res_policy_len; BOOL opt; if (conn_fd == INVALID_SOCKET) { DbgWithLinkForC(LOG_LEVEL_WARN, LOG_TYPE_SYSTEM, "accept new connection fd failed!"); return; } DbgWithLinkForC(LOG_LEVEL_INFO, LOG_TYPE_SYSTEM, "accept from %s:%d", inet_ntoa(from_addr.sin_addr), ntohs(from_addr.sin_port)); WSAEventSelect(conn_fd, NULL, 0); _ioctlsocket(conn_fd, FIONBIO, &iMode); opt = TRUE; setsockopt(conn_fd, IPPROTO_TCP, TCP_NODELAY, (char*)&opt, sizeof(opt)); opt = TRUE; setsockopt(conn_fd, SOL_SOCKET, SO_DONTLINGER, (char*)&opt, sizeof(opt)); while (recved < req_policy_len) { int t = recv(conn_fd, req_buf+recved, req_policy_len-recved, 0); if (t <= 0) { DbgWithLinkForC(LOG_LEVEL_WARN, LOG_TYPE_SYSTEM, "recv conn_fd failed! error:%d", WSAGetLastError()); goto on_error; } else { recved += t; } } if (_strnicmp(req_policy, req_buf, req_policy_len) != 0) { DbgWithLinkForC(LOG_LEVEL_WARN, LOG_TYPE_SYSTEM, "warning: req_buf not equal to !!!"); goto on_error; } while (sended < need_send) { int t = send(conn_fd, res_policy+sended, res_policy_len-sended, 0); if (t <= 0) { DbgWithLinkForC(LOG_LEVEL_WARN, LOG_TYPE_SYSTEM, "send res policy failed!"); goto on_error; } else { sended += t; } } shutdown(conn_fd, SD_BOTH); on_error: closesocket(conn_fd); } static unsigned int __stdcall __sps_worker_proc(void *arg) { sp_sps_t *sps = (sp_sps_t*)arg; WSAEVENT evt[2] = {sps->evt_stop}; SOCKET fd = INVALID_SOCKET; struct sockaddr_in addr = {0}; fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (fd == INVALID_SOCKET) { sps->result = -1; goto on_start_error; } addr.sin_family = AF_INET; addr.sin_port = htons(SILVERLIGHT_POLICY_PORT); addr.sin_addr.s_addr = htonl(INADDR_ANY); // only for debug //addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); if (bind(fd, (struct sockaddr*)&addr, sizeof(addr)) != 0 || listen(fd, 5) != 0) { sps->result = -1; goto on_start_error; } evt[1] = WSACreateEvent(); WSAEventSelect(fd, evt[1], FD_ACCEPT | FD_CLOSE); sps->result = 0; WSASetEvent(sps->evt_ready); for(;;) { DWORD dwRet = WSAWaitForMultipleEvents(ARRAYSIZE(evt), &evt[0], FALSE, MAX_TIMEOUT, FALSE); if (dwRet == WSA_WAIT_EVENT_0) { break; // stop } else if (dwRet == WSA_WAIT_EVENT_0+1) { WSANETWORKEVENTS netevents; if (WSAEnumNetworkEvents(fd, evt[1], &netevents) != SOCKET_ERROR) { if (netevents.lNetworkEvents & FD_ACCEPT) { if (netevents.iErrorCode[FD_ACCEPT_BIT] == 0) { __on_accept(fd); } } if (netevents.lNetworkEvents & FD_CLOSE) { DbgWithLinkForC(LOG_LEVEL_WARN, LOG_TYPE_SYSTEM, "accept closed! err %d %s %d", WSAGetLastError(), _GetFileName(__FILE__), __LINE__); break; } } else { DbgWithLinkForC(LOG_LEVEL_WARN, LOG_TYPE_SYSTEM, "WSAGetLastError %d %s %d", WSAGetLastError(), _GetFileName(__FILE__), __LINE__); } } else if (dwRet == WSA_WAIT_TIMEOUT) { continue; } else { break; } } on_start_error: if (evt[1]) { WSAEventSelect(fd, evt[1], 0); WSACloseEvent(evt[1]); evt[1] = NULL; } if (fd != INVALID_SOCKET) { closesocket(fd); } WSASetEvent(sps->evt_ready); return sps->result; } int sp_sps_create(sp_sps_t **p_sps) { sp_sps_t *sps = MALLOC_T(sp_sps_t); sps->evt_ready = WSACreateEvent(); sps->evt_stop = WSACreateEvent(); sps->worker_thread = NULL; *p_sps = sps; return 0; } int sp_sps_start(sp_sps_t *sps) { WSAResetEvent(sps->evt_ready); WSAResetEvent(sps->evt_stop); sps->result = 0; sps->worker_thread = (HANDLE)_beginthreadex(NULL, 0, &__sps_worker_proc, sps, 0, NULL); if (sps->worker_thread) { WSAEVENT evt[1] = {sps->evt_ready}; WSAWaitForMultipleEvents(1, &evt[0], FALSE, WSA_INFINITE, FALSE); if (sps->result != 0) { WaitForSingleObject(sps->worker_thread, INFINITE); CloseHandle(sps->worker_thread); sps->worker_thread = NULL; } return sps->result; } else { return Error_Resource; } } void sp_sps_destroy(sp_sps_t *sps) { WSACloseEvent(sps->evt_ready); WSACloseEvent(sps->evt_stop); free(sps); } void sp_sps_stop(sp_sps_t *sps) { WSASetEvent(sps->evt_stop); WaitForSingleObject(sps->worker_thread, INFINITE); CloseHandle(sps->worker_thread); sps->worker_thread = NULL; }