822bd0dd42ef26a5c302b8d4d05d34acfd0b75db
[reactos.git] / reactos / services / tcpsvcs / skelserver.c
1 /*
2 * ReactOS Services
3 * Copyright (C) 2005 ReactOS Team
4 *
5 * LICENCE: GPL - See COPYING in the top level directory
6 * PROJECT: ReactOS simple TCP/IP services
7 * FILE: apps/utils/net/tcpsvcs/skelserver.c
8 * PURPOSE: Provide CharGen, Daytime, Discard, Echo, and Qotd services
9 * PROGRAMMERS: Ged Murphy (gedmurphy@gmail.com)
10 * REVISIONS:
11 * GM 04/10/05 Created
12 *
13 */
14
15 #include "tcpsvcs.h"
16
17 extern BOOL bShutDown;
18 extern BOOL bPause;
19
20 DWORD WINAPI StartServer(LPVOID lpParam)
21 {
22 SOCKET ListeningSocket;
23 PSERVICES pServices;
24 const TCHAR* HostIP = "127.0.0.1";
25 TCHAR buf[256];
26
27 pServices = (PSERVICES)lpParam;
28
29 //DebugBreak();
30 ListeningSocket = SetUpListener(HostIP, htons(pServices->Port));
31 if (ListeningSocket == INVALID_SOCKET)
32 {
33 LogEvent("Socket error when setting up listener", 0, TRUE);
34 return 3;
35 }
36
37 _stprintf(buf, _T("%s is waiting for connections on port %d...\n"),
38 pServices->Name, pServices->Port);
39 LogEvent(buf, 0, FALSE);
40
41 if (! bShutDown)
42 AcceptConnections(ListeningSocket, pServices->Service, pServices->Name);
43
44 ExitThread(0);
45 }
46
47
48 SOCKET SetUpListener(const char* ServAddr, int Port)
49 {
50 SOCKET Sock;
51 SOCKADDR_IN Server;
52
53 Sock = socket(AF_INET, SOCK_STREAM, 0);
54 if (Sock != INVALID_SOCKET)
55 {
56 Server.sin_family = AF_INET;
57 Server.sin_addr.s_addr = htonl(INADDR_ANY);
58 Server.sin_port = Port;
59 if (bind(Sock, (SOCKADDR*)&Server, sizeof(SOCKADDR_IN)) != SOCKET_ERROR)
60 {
61 listen(Sock, SOMAXCONN);
62 return Sock;
63 }
64 else
65 LogEvent(_T("bind() failed\n"), 0, TRUE);
66
67 }
68 return INVALID_SOCKET;
69 }
70
71 /* note: consider allowing a maximum number of connections
72 * A number of threads can be allocated and worker threads will
73 * only be spawned if a free space is available
74
75 typedef struct _WORKER_THREAD {
76 DWORD num;
77 BOOL available;
78 HANDLE hThread;
79 } WORKER_THREAD;
80
81 */
82
83 VOID AcceptConnections(SOCKET ListeningSocket,
84 LPTHREAD_START_ROUTINE Service, TCHAR *Name)
85 {
86 SOCKADDR_IN Client;
87 SOCKET Sock;
88 HANDLE hThread;
89 TIMEVAL TimeVal;
90 FD_SET ReadFDS;
91 INT nAddrSize = sizeof(Client);
92 DWORD ThreadID;
93 TCHAR buf[256];
94 INT TimeOut = 2000; // 2 seconds
95
96 //DebugBreak();
97 /* monitor for incomming connections */
98 FD_ZERO(&ReadFDS);
99
100 /* set timeout values */
101 TimeVal.tv_sec = TimeOut / 1000;
102 TimeVal.tv_usec = TimeOut % 1000;
103
104 while (! bShutDown) // (i<MAX_CLIENTS && !bShutDown)
105 {
106 FD_SET(ListeningSocket, &ReadFDS);
107 if (select(0, &ReadFDS, NULL, NULL, &TimeVal) == SOCKET_ERROR)
108 {
109 LogEvent(_T("select failed\n"), 0, TRUE);
110 return;
111 }
112
113 /* don't call FD_ISSET if bShutDown flag is set */
114 if ((! bShutDown) || (FD_ISSET(ListeningSocket, &ReadFDS)))
115 {
116 Sock = accept(ListeningSocket, (SOCKADDR*)&Client, &nAddrSize);
117 if (Sock != INVALID_SOCKET)
118 {
119 _stprintf(buf, _T("Accepted connection to %s server from %s:%d\n"),
120 Name, inet_ntoa(Client.sin_addr), ntohs(Client.sin_port));
121 LogEvent(buf, 0, FALSE);
122 _stprintf(buf, _T("Creating new thread for %s\n"), Name);
123 LogEvent(buf, 0, FALSE);
124
125 hThread = CreateThread(0, 0, Service, (void*)Sock, 0, &ThreadID);
126
127 /* Check the return value for success. */
128 if (hThread == NULL)
129 {
130 _stprintf(buf, _T("Failed to start worker thread for "
131 "the %s server....\n"), Name);
132 LogEvent(buf, 0, TRUE);
133 }
134
135 WaitForSingleObject(hThread, INFINITE);
136
137 CloseHandle(hThread);
138 }
139 else
140 {
141 LogEvent(_T("accept failed\n"), 0, TRUE);
142 return;
143 }
144 }
145 }
146 }
147
148 BOOL ShutdownConnection(SOCKET Sock, BOOL bRec)
149 {
150 TCHAR buf[256];
151
152 /* Disallow any further data sends. This will tell the other side
153 that we want to go away now. If we skip this step, we don't
154 shut the connection down nicely. */
155 if (shutdown(Sock, SD_SEND) == SOCKET_ERROR)
156 {
157 LogEvent(_T("Error in shutdown()\n"), 0, TRUE);
158 return FALSE;
159 }
160
161 /* Receive any extra data still sitting on the socket. After all
162 data is received, this call will block until the remote host
163 acknowledges the TCP control packet sent by the shutdown above.
164 Then we'll get a 0 back from recv, signalling that the remote
165 host has closed its side of the connection. */
166 if (bRec)
167 {
168 char ReadBuffer[BUF];
169 int NewBytes = recv(Sock, ReadBuffer, BUF, 0);
170 if (NewBytes == SOCKET_ERROR)
171 return FALSE;
172 else if (NewBytes != 0)
173 {
174 _stprintf(buf, _T("FYI, received %d unexpected bytes during shutdown\n"), NewBytes);
175 LogEvent(buf, 0, FALSE);
176 }
177 }
178
179 /* Close the socket. */
180 if (closesocket(Sock) == SOCKET_ERROR)
181 return FALSE;
182
183 return TRUE;
184 }