3 * Copyright (C) 2005 ReactOS Team
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)
17 extern BOOL bShutDown
;
20 DWORD WINAPI
StartServer(LPVOID lpParam
)
22 SOCKET ListeningSocket
;
26 pServices
= (PSERVICES
)lpParam
;
29 ListeningSocket
= SetUpListener(htons(pServices
->Port
));
30 if (ListeningSocket
== INVALID_SOCKET
)
32 LogEvent("Socket error when setting up listener\n", 0, TRUE
);
36 _stprintf(buf
, _T("%s is waiting for connections on port %d...\n"),
37 pServices
->Name
, pServices
->Port
);
38 LogEvent(buf
, 0, FALSE
);
41 AcceptConnections(ListeningSocket
, pServices
->Service
, pServices
->Name
);
47 SOCKET
SetUpListener(USHORT Port
)
52 Sock
= socket(AF_INET
, SOCK_STREAM
, 0);
53 if (Sock
!= INVALID_SOCKET
)
55 Server
.sin_family
= AF_INET
;
56 Server
.sin_addr
.s_addr
= htonl(INADDR_ANY
);
57 Server
.sin_port
= Port
;
58 if (bind(Sock
, (SOCKADDR
*)&Server
, sizeof(SOCKADDR_IN
)) != SOCKET_ERROR
)
60 listen(Sock
, SOMAXCONN
);
64 LogEvent(_T("bind() failed\n"), 0, TRUE
);
67 return INVALID_SOCKET
;
70 /* note: consider allowing a maximum number of connections
71 * A number of threads can be allocated and worker threads will
72 * only be spawned if a free space is available
74 typedef struct _WORKER_THREAD {
82 VOID
AcceptConnections(SOCKET ListeningSocket
,
83 LPTHREAD_START_ROUTINE Service
, TCHAR
*Name
)
90 INT nAddrSize
= sizeof(Client
);
93 INT TimeOut
= 2000; // 2 seconds
97 /* set timeout values */
98 TimeVal
.tv_sec
= TimeOut
/ 1000;
99 TimeVal
.tv_usec
= TimeOut
% 1000;
101 while (! bShutDown
) // (i<MAX_CLIENTS && !bShutDown)
106 FD_SET(ListeningSocket
, &ReadFDS
);
108 SelRet
= select(0, &ReadFDS
, NULL
, NULL
, &TimeVal
);
109 if (SelRet
== SOCKET_ERROR
)
111 LogEvent(_T("select failed\n"), 0, TRUE
);
116 /* don't call FD_ISSET if bShutDown flag is set */
117 if ((! bShutDown
) || (FD_ISSET(ListeningSocket
, &ReadFDS
)))
119 Sock
= accept(ListeningSocket
, (SOCKADDR
*)&Client
, &nAddrSize
);
120 if (Sock
!= INVALID_SOCKET
)
122 _stprintf(buf
, _T("Accepted connection to %s server from %s:%d\n"),
123 Name
, inet_ntoa(Client
.sin_addr
), ntohs(Client
.sin_port
));
124 LogEvent(buf
, 0, FALSE
);
125 _stprintf(buf
, _T("Creating new thread for %s\n"), Name
);
126 LogEvent(buf
, 0, FALSE
);
128 hThread
= CreateThread(0, 0, Service
, (void*)Sock
, 0, &ThreadID
);
130 /* Check the return value for success. */
133 _stprintf(buf
, _T("Failed to start worker thread for "
134 "the %s server....\n"), Name
);
135 LogEvent(buf
, 0, TRUE
);
138 WaitForSingleObject(hThread
, INFINITE
);
140 CloseHandle(hThread
);
144 LogEvent(_T("accept failed\n"), 0, TRUE
);
152 BOOL
ShutdownConnection(SOCKET Sock
, BOOL bRec
)
156 /* Disallow any further data sends. This will tell the other side
157 that we want to go away now. If we skip this step, we don't
158 shut the connection down nicely. */
159 if (shutdown(Sock
, SD_SEND
) == SOCKET_ERROR
)
161 LogEvent(_T("Error in shutdown()\n"), 0, TRUE
);
165 /* Receive any extra data still sitting on the socket. After all
166 data is received, this call will block until the remote host
167 acknowledges the TCP control packet sent by the shutdown above.
168 Then we'll get a 0 back from recv, signalling that the remote
169 host has closed its side of the connection. */
172 char ReadBuffer
[BUF
];
173 int NewBytes
= recv(Sock
, ReadBuffer
, BUF
, 0);
174 if (NewBytes
== SOCKET_ERROR
)
176 else if (NewBytes
!= 0)
178 _stprintf(buf
, _T("FYI, received %d unexpected bytes during shutdown\n"), NewBytes
);
179 LogEvent(buf
, 0, FALSE
);
183 /* Close the socket. */
184 if (closesocket(Sock
) == SOCKET_ERROR
)