#include "precompile.h"
#include "sp_sps.h"
#include "sp_def.h"
#include "sp_logwithlinkforc.h"
#include "memutil.h"
#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);
#ifdef _WIN32
ioctlsocket(conn_fd, FIONBIO, &iMode);
#else
_ioctlsocket(conn_fd, FIONBIO, &iMode);
#endif //_WIN32
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 const char *_GetFileName(const char *pszFilePath)
{
int i=strlen(pszFilePath);
for( ; i>0 && pszFilePath[i-1]!='\\'; i--)NULL;
return pszFilePath+i;
}
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;
}