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 bShutDownFlag
;
18 extern BOOL bPauseFlag
;
20 DWORD WINAPI
StartServer(LPVOID lpParam
)
22 SOCKET ListeningSocket
;
24 const TCHAR
* HostIP
= "127.0.0.1";
27 pServices
= (PSERVICES
)lpParam
;
30 ListeningSocket
= SetUpListener(HostIP
, htons(pServices
->Port
));
31 if (ListeningSocket
== INVALID_SOCKET
)
33 LogEvent("Socket error when setting up listener", 0, TRUE
);
37 _stprintf(temp
, _T("%s is waiting for connections on port %d...\n"),
38 pServices
->Name
, pServices
->Port
);
39 LogEvent(temp
, 0, FALSE
);
41 AcceptConnections(ListeningSocket
, pServices
->Service
, pServices
->Name
);
43 LogEvent(_T("Detaching Winsock2...\n"), 0, FALSE
);
49 SOCKET
SetUpListener(const char* ServAddr
, int Port
)
54 Sock
= socket(AF_INET
, SOCK_STREAM
, 0);
55 if (Sock
!= INVALID_SOCKET
)
57 Server
.sin_family
= AF_INET
;
58 Server
.sin_addr
.s_addr
= htonl(INADDR_ANY
);
59 Server
.sin_port
= Port
;
60 if (bind(Sock
, (SOCKADDR
*)&Server
, sizeof(SOCKADDR_IN
)) != SOCKET_ERROR
)
62 listen(Sock
, SOMAXCONN
);
66 LogEvent(_T("bind() failed\n"), 0, TRUE
);
69 return INVALID_SOCKET
;
72 /* note: consider allowing a maximum number of connections
73 * A number of threads can be allocated and worker threads will
74 * only be spawned if a free space is available
76 typedef struct _WORKER_THREAD {
84 VOID
AcceptConnections(SOCKET ListeningSocket
,
85 LPTHREAD_START_ROUTINE Service
, TCHAR
*Name
)
92 INT nAddrSize
= sizeof(Client
);
95 INT TimeOut
= 2000; // 2 seconds
98 /* monitor for incomming connections */
101 /* set timeout values */
102 TimeVal
.tv_sec
= TimeOut
/ 1000;
103 TimeVal
.tv_usec
= TimeOut
% 1000;
105 while (! bShutDownFlag
) // (i<MAX_CLIENTS && !bShutDownFlag)
107 FD_SET(ListeningSocket
, &ReadFDS
);
108 if (select(0, &ReadFDS
, NULL
, NULL
, &TimeVal
) == SOCKET_ERROR
)
110 LogEvent(_T("select failed\n"), 0, TRUE
);
114 if (FD_ISSET(ListeningSocket
, &ReadFDS
))
116 Sock
= accept(ListeningSocket
, (SOCKADDR
*)&Client
, &nAddrSize
);
117 if (Sock
!= INVALID_SOCKET
)
119 _stprintf(temp
, _T("Accepted connection to %s server from %s:%d\n"),
120 Name
, inet_ntoa(Client
.sin_addr
), ntohs(Client
.sin_port
));
121 LogEvent(temp
, 0, FALSE
);
122 _stprintf(temp
, _T("Creating new thread for %s\n"), Name
);
123 LogEvent(temp
, 0, FALSE
);
125 hThread
= CreateThread(0, 0, Service
, (void*)Sock
, 0, &ThreadID
);
127 /* Check the return value for success. */
130 _stprintf(temp
, _T("Failed to start worker thread for "
131 "the %s server....\n"), Name
);
132 LogEvent(temp
, 0, TRUE
);
135 //Do we need to wait, or just kill it?
136 WaitForSingleObject(hThread
, INFINITE
);
141 LogEvent(_T("accept failed\n"), 0, TRUE
);
148 BOOL
ShutdownConnection(SOCKET Sock
, BOOL bRec
)
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
)
157 LogEvent(_T("Error in shutdown()\n"), 0, TRUE
);
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. */
168 char ReadBuffer
[BUF
];
169 int NewBytes
= recv(Sock
, ReadBuffer
, BUF
, 0);
170 if (NewBytes
== SOCKET_ERROR
)
172 else if (NewBytes
!= 0)
174 _stprintf(temp
, _T("FYI, received %d unexpected bytes during shutdown\n"), NewBytes
);
175 LogEvent(temp
, 0, FALSE
);
179 /* Close the socket. */
180 if (closesocket(Sock
) == SOCKET_ERROR
)