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