[NTOS:KE/x64] Handle NMI vs swapgs race condition
[reactos.git] / base / services / tcpsvcs / skelserver.c
1 /*
2 * PROJECT: ReactOS simple TCP/IP services
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: base/services/tcpsvcs/skelserver.c
5 * PURPOSE: Sets up a server and listens for connections
6 * COPYRIGHT: Copyright 2005 - 2008 Ged Murphy <gedmurphy@gmail.com>
7 *
8 */
9
10 #include "tcpsvcs.h"
11
12 #define BUF 1024
13
14 static SOCKET
15 SetUpListener(USHORT Port)
16 {
17 SOCKET sock;
18 SOCKADDR_IN server;
19 BOOL bSetup = FALSE;
20
21 sock = socket(AF_INET, SOCK_STREAM, 0);
22 if (sock != INVALID_SOCKET)
23 {
24 ZeroMemory(&server, sizeof(SOCKADDR_IN));
25 server.sin_family = AF_INET;
26 server.sin_addr.s_addr = htonl(INADDR_ANY);
27 server.sin_port = Port;
28
29 if (bind(sock, (SOCKADDR*)&server, sizeof(SOCKADDR_IN)) != SOCKET_ERROR)
30 {
31 if (listen(sock, SOMAXCONN) != SOCKET_ERROR)
32 {
33 bSetup = TRUE;
34 }
35 else
36 {
37 LogEvent(L"listen() failed", WSAGetLastError(), 0, LOG_ERROR);
38 }
39 }
40 else
41 {
42 LogEvent(L"bind() failed", WSAGetLastError(), 0, LOG_ERROR);
43 }
44 }
45 else
46 {
47 LogEvent(L"socket() failed", WSAGetLastError(), 0, LOG_ERROR);
48 }
49
50 return bSetup ? sock : INVALID_SOCKET;
51 }
52
53
54 static VOID
55 AcceptConnections(SOCKET listeningSocket,
56 LPTHREAD_START_ROUTINE lpService,
57 LPWSTR lpName)
58 {
59 SOCKADDR_IN client;
60 SOCKET sock;
61 HANDLE hThread;
62 TIMEVAL timeVal;
63 FD_SET readFD;
64 WCHAR logBuf[256];
65 INT timeOut = 2000;
66
67 timeVal.tv_sec = timeOut / 1000;
68 timeVal.tv_usec = timeOut % 1000;
69
70 while (!bShutdown)
71 {
72 INT selRet = 0;
73
74 FD_ZERO(&readFD);
75 FD_SET(listeningSocket, &readFD);
76
77 selRet = select(0, &readFD, NULL, NULL, &timeVal);
78 if (selRet > 0)
79 {
80 if (!bShutdown || FD_ISSET(listeningSocket, &readFD))
81 {
82 INT addrSize = sizeof(SOCKADDR_IN);
83
84 sock = accept(listeningSocket, (SOCKADDR*)&client, &addrSize);
85 if (sock != INVALID_SOCKET)
86 {
87 swprintf(logBuf,
88 L"Accepted connection to %s server from %S:%d",
89 lpName,
90 inet_ntoa(client.sin_addr),
91 ntohs(client.sin_port));
92 LogEvent(logBuf, 0, 0, LOG_FILE);
93
94 swprintf(logBuf, L"Creating worker thread for %s", lpName);
95 LogEvent(logBuf, 0, 0, LOG_FILE);
96
97 if (!bShutdown)
98 {
99 hThread = CreateThread(0, 0, lpService, (void*)sock, 0, NULL);
100 if (hThread != NULL)
101 {
102 CloseHandle(hThread);
103 }
104 else
105 {
106 swprintf(logBuf, L"Failed to start worker thread for the %s server",
107 lpName);
108 LogEvent(logBuf, 0, 0, LOG_FILE);
109 }
110 }
111 }
112 else
113 {
114 LogEvent(L"accept failed", WSAGetLastError(), 0, LOG_ERROR);
115 }
116 }
117 }
118 else if (selRet == SOCKET_ERROR)
119 {
120 LogEvent(L"select failed", WSAGetLastError(), 0, LOG_ERROR);
121 }
122 }
123 }
124
125 BOOL
126 ShutdownConnection(SOCKET sock,
127 BOOL bRec)
128 {
129 WCHAR logBuf[256];
130
131 /* Disallow any further data sends. This will tell the other side
132 that we want to go away now. If we skip this step, we don't
133 shut the connection down nicely. */
134 if (shutdown(sock, SD_SEND) == SOCKET_ERROR)
135 {
136 LogEvent(L"Error in shutdown()", WSAGetLastError(), 0, LOG_ERROR);
137 return FALSE;
138 }
139
140 /* Receive any extra data still sitting on the socket
141 before we close it */
142 if (bRec)
143 {
144 CHAR readBuffer[BUF];
145 INT ret;
146
147 do
148 {
149 ret = recv(sock, readBuffer, BUF, 0);
150 if (ret >= 0)
151 {
152 swprintf(logBuf, L"FYI, received %d unexpected bytes during shutdown", ret);
153 LogEvent(logBuf, 0, 0, LOG_FILE);
154 }
155 } while (ret > 0);
156 }
157
158 closesocket(sock);
159
160 return TRUE;
161 }
162
163
164 DWORD WINAPI
165 StartServer(LPVOID lpParam)
166 {
167 SOCKET listeningSocket;
168 PSERVICES pServices;
169 TCHAR logBuf[256];
170
171 pServices = (PSERVICES)lpParam;
172
173 swprintf(logBuf, L"Starting %s server", pServices->lpName);
174 LogEvent(logBuf, 0, 0, LOG_FILE);
175
176 if (!bShutdown)
177 {
178 listeningSocket = SetUpListener(htons(pServices->Port));
179 if (!bShutdown && listeningSocket != INVALID_SOCKET)
180 {
181 swprintf(logBuf,
182 L"%s is waiting for connections on port %d",
183 pServices->lpName,
184 pServices->Port);
185 LogEvent(logBuf, 0, 0, LOG_FILE);
186
187 AcceptConnections(listeningSocket, pServices->lpService, pServices->lpName);
188 }
189 else
190 {
191 LogEvent(L"Socket error when setting up listener", 0, 0, LOG_FILE);
192 }
193 }
194
195 swprintf(logBuf, L"Exiting %s thread", pServices->lpName);
196 LogEvent(logBuf, 0, 0, LOG_FILE);
197 ExitThread(0);
198 }