reactos/base/services/tcpsvcs/skelserver.c

199 lines
5.3 KiB
C

/*
* PROJECT: ReactOS simple TCP/IP services
* LICENSE: GPL - See COPYING in the top level directory
* FILE: base/services/tcpsvcs/skelserver.c
* PURPOSE: Sets up a server and listens for connections
* COPYRIGHT: Copyright 2005 - 2008 Ged Murphy <gedmurphy@gmail.com>
*
*/
#include "tcpsvcs.h"
#define BUF 1024
static SOCKET
SetUpListener(USHORT Port)
{
SOCKET sock;
SOCKADDR_IN server;
BOOL bSetup = FALSE;
sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock != INVALID_SOCKET)
{
ZeroMemory(&server, sizeof(SOCKADDR_IN));
server.sin_family = AF_INET;
server.sin_addr.s_addr = htonl(INADDR_ANY);
server.sin_port = Port;
if (bind(sock, (SOCKADDR*)&server, sizeof(SOCKADDR_IN)) != SOCKET_ERROR)
{
if (listen(sock, SOMAXCONN) != SOCKET_ERROR)
{
bSetup = TRUE;
}
else
{
LogEvent(L"listen() failed", WSAGetLastError(), 0, LOG_ERROR);
}
}
else
{
LogEvent(L"bind() failed", WSAGetLastError(), 0, LOG_ERROR);
}
}
else
{
LogEvent(L"socket() failed", WSAGetLastError(), 0, LOG_ERROR);
}
return bSetup ? sock : INVALID_SOCKET;
}
static VOID
AcceptConnections(SOCKET listeningSocket,
LPTHREAD_START_ROUTINE lpService,
LPWSTR lpName)
{
SOCKADDR_IN client;
SOCKET sock;
HANDLE hThread;
TIMEVAL timeVal;
FD_SET readFD;
WCHAR logBuf[256];
INT timeOut = 2000;
timeVal.tv_sec = timeOut / 1000;
timeVal.tv_usec = timeOut % 1000;
while (!bShutdown)
{
INT selRet = 0;
FD_ZERO(&readFD);
FD_SET(listeningSocket, &readFD);
selRet = select(0, &readFD, NULL, NULL, &timeVal);
if (selRet > 0)
{
if (!bShutdown || FD_ISSET(listeningSocket, &readFD))
{
INT addrSize = sizeof(SOCKADDR_IN);
sock = accept(listeningSocket, (SOCKADDR*)&client, &addrSize);
if (sock != INVALID_SOCKET)
{
swprintf(logBuf,
L"Accepted connection to %s server from %S:%d",
lpName,
inet_ntoa(client.sin_addr),
ntohs(client.sin_port));
LogEvent(logBuf, 0, 0, LOG_FILE);
swprintf(logBuf, L"Creating worker thread for %s", lpName);
LogEvent(logBuf, 0, 0, LOG_FILE);
if (!bShutdown)
{
hThread = CreateThread(0, 0, lpService, (void*)sock, 0, NULL);
if (hThread != NULL)
{
CloseHandle(hThread);
}
else
{
swprintf(logBuf, L"Failed to start worker thread for the %s server",
lpName);
LogEvent(logBuf, 0, 0, LOG_FILE);
}
}
}
else
{
LogEvent(L"accept failed", WSAGetLastError(), 0, LOG_ERROR);
}
}
}
else if (selRet == SOCKET_ERROR)
{
LogEvent(L"select failed", WSAGetLastError(), 0, LOG_ERROR);
}
}
}
BOOL
ShutdownConnection(SOCKET sock,
BOOL bRec)
{
WCHAR logBuf[256];
/* Disallow any further data sends. This will tell the other side
that we want to go away now. If we skip this step, we don't
shut the connection down nicely. */
if (shutdown(sock, SD_SEND) == SOCKET_ERROR)
{
LogEvent(L"Error in shutdown()", WSAGetLastError(), 0, LOG_ERROR);
return FALSE;
}
/* Receive any extra data still sitting on the socket
before we close it */
if (bRec)
{
CHAR readBuffer[BUF];
INT ret;
do
{
ret = recv(sock, readBuffer, BUF, 0);
if (ret >= 0)
{
swprintf(logBuf, L"FYI, received %d unexpected bytes during shutdown", ret);
LogEvent(logBuf, 0, 0, LOG_FILE);
}
} while (ret > 0);
}
closesocket(sock);
return TRUE;
}
DWORD WINAPI
StartServer(LPVOID lpParam)
{
SOCKET listeningSocket;
PSERVICES pServices;
TCHAR logBuf[256];
pServices = (PSERVICES)lpParam;
swprintf(logBuf, L"Starting %s server", pServices->lpName);
LogEvent(logBuf, 0, 0, LOG_FILE);
if (!bShutdown)
{
listeningSocket = SetUpListener(htons(pServices->Port));
if (!bShutdown && listeningSocket != INVALID_SOCKET)
{
swprintf(logBuf,
L"%s is waiting for connections on port %d",
pServices->lpName,
pServices->Port);
LogEvent(logBuf, 0, 0, LOG_FILE);
AcceptConnections(listeningSocket, pServices->lpService, pServices->lpName);
}
else
{
LogEvent(L"Socket error when setting up listener", 0, 0, LOG_FILE);
}
}
swprintf(logBuf, L"Exiting %s thread", pServices->lpName);
LogEvent(logBuf, 0, 0, LOG_FILE);
ExitThread(0);
}