xref: /reactos/base/services/tcpsvcs/skelserver.c (revision c424146e)
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 }
200