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