- Don't call winsock initialiser for each seperate server thread
[reactos.git] / reactos / apps / utils / net / tcpsvcs / tcpsvcs.c
1 #include <stdio.h>
2 #include <winsock2.h>
3 #include <tchar.h>
4 #include "tcpsvcs.h"
5
6 #if 0
7 /*
8 * globals
9 */
10 static SERVICE_STATUS hServStatus;
11 static SERVICE_STATUS_HANDLE hSStat;
12 FILE *hLogFile;
13 BOOL bLogEvents = TRUE;
14 BOOL ShutDown, PauseFlag;
15 LPTSTR LogFileName = "tcpsvcs_log.txt";
16
17 static SERVICE_TABLE_ENTRY
18 ServiceTable[2] =
19 {
20 {_T("tcpsvcs"), ServiceMain},
21 {NULL, NULL}
22 };
23 #endif
24
25 static SERVICES
26 Services[NUM_SERVICES] =
27 {
28 {ECHO_PORT, _T("Echo"), EchoHandler},
29 {DISCARD_PORT, _T("Discard"), DiscardHandler},
30 {DAYTIME_PORT, _T("Daytime"), DaytimeHandler},
31 {QOTD_PORT, _T("QOTD"), QotdHandler},
32 {CHARGEN_PORT, _T("Chargen"), ChargenHandler}
33 };
34
35
36 int main(void)
37 {
38 DWORD dwThreadId[NUM_SERVICES];
39 HANDLE hThread[NUM_SERVICES];
40 WSADATA wsaData;
41 DWORD RetVal;
42 INT i;
43
44 if ((RetVal = WSAStartup(MAKEWORD(2, 2), &wsaData)) != 0)
45 {
46 _tprintf(_T("WSAStartup() failed : %lu\n"), RetVal);
47 return -1;
48 }
49
50 /* Create MAX_THREADS worker threads. */
51 for( i=0; i<NUM_SERVICES; i++ )
52 {
53 _tprintf(_T("Starting %s server....\n"), Services[i].Name);
54
55 hThread[i] = CreateThread(
56 NULL, // default security attributes
57 0, // use default stack size
58 StartServer, // thread function
59 &Services[i], // argument to thread function
60 0, // use default creation flags
61 &dwThreadId[i]); // returns the thread identifier
62
63 /* Check the return value for success. */
64 if (hThread[i] == NULL)
65 {
66 _tprintf(_T("Failed to start %s server....\n"), Services[i].Name);
67 ExitProcess(i);
68 }
69 }
70
71 /* Wait until all threads have terminated. */
72 WaitForMultipleObjects(NUM_SERVICES, hThread, TRUE, INFINITE);
73
74 /* Close all thread handles upon completion. */
75 for(i=0; i<NUM_SERVICES; i++)
76 {
77 CloseHandle(hThread[i]);
78 }
79 return 0;
80 }
81
82
83
84 /* code to run tcpsvcs as a service */
85 #if 0
86 int
87 main(int argc, char *argv[])
88 {
89 //DPRINT("tcpsvcs: main() started. See tcpsvcs_log.txt for info\n");
90
91 if (!StartServiceCtrlDispatcher(ServiceTable))
92 _tprintf(_T("failed to start the service control dispatcher\n"));
93
94 //DPRINT("tcpsvcs: main() done\n");
95
96 return 0;
97 }
98
99
100 static VOID WINAPI
101 ServiceMain(DWORD argc, LPTSTR argv[])
102 {
103 DWORD i;
104
105 hLogFile = fopen(LogFileName, _T("w+"));
106 if (hLogFile == NULL)
107 return;
108
109 LogEvent(_T("Entering ServiceMain"), 0, FALSE);
110
111 hServStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
112 hServStatus.dwCurrentState = SERVICE_START_PENDING;
113 hServStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP |
114 SERVICE_ACCEPT_SHUTDOWN | SERVICE_ACCEPT_PAUSE_CONTINUE;
115 hServStatus.dwWin32ExitCode = ERROR_SERVICE_SPECIFIC_ERROR;
116 hServStatus.dwServiceSpecificExitCode = 0;
117 hServStatus.dwCheckPoint = 0;
118 hServStatus.dwWaitHint = 2*CS_TIMEOUT;
119
120 hSStat = RegisterServiceCtrlHandler("tcpsvcs", ServerCtrlHandler);
121 if (hSStat == 0)
122 LogEvent(_T("Failed to register service\n"), 100, TRUE);
123
124 LogEvent(_T("Control handler registered successfully"), 0, FALSE);
125 SetServiceStatus (hSStat, &hServStatus);
126 LogEvent(_T("Service status set to SERVICE_START_PENDING"), 0, FALSE);
127
128 if (CreateServers() != 0)
129 {
130 hServStatus.dwCurrentState = SERVICE_STOPPED;
131 hServStatus.dwServiceSpecificExitCode = 1;
132 SetServiceStatus(hSStat, &hServStatus);
133 return;
134 }
135
136 LogEvent(_T("Service threads shut down. Set SERVICE_STOPPED status"), 0, FALSE);
137 /* We will only return here when the ServiceSpecific function
138 completes, indicating system shutdown. */
139 UpdateStatus (SERVICE_STOPPED, 0);
140 LogEvent(_T("Service status set to SERVICE_STOPPED"), 0, FALSE);
141 fclose(hLogFile); /* Clean up everything, in general */
142 return;
143
144 }
145
146 VOID WINAPI
147 ServerCtrlHandler(DWORD Control)
148 {
149 switch (Control)
150 {
151 case SERVICE_CONTROL_SHUTDOWN: /* fall through */
152 case SERVICE_CONTROL_STOP:
153 ShutDown = TRUE;
154 UpdateStatus(SERVICE_STOP_PENDING, -1);
155 break;
156 case SERVICE_CONTROL_PAUSE:
157 PauseFlag = TRUE;
158 break;
159 case SERVICE_CONTROL_CONTINUE:
160 PauseFlag = FALSE;
161 break;
162 case SERVICE_CONTROL_INTERROGATE:
163 break;
164 default:
165 if (Control > 127 && Control < 256) /* user defined */
166 break;
167 }
168 UpdateStatus(-1, -1); /* increment checkpoint */
169 return;
170 }
171
172
173 void UpdateStatus (int NewStatus, int Check)
174 /* Set a new service status and checkpoint (either specific value or increment) */
175 {
176 if (Check < 0 ) hServStatus.dwCheckPoint++;
177 else hServStatus.dwCheckPoint = Check;
178 if (NewStatus >= 0) hServStatus.dwCurrentState = NewStatus;
179 if (!SetServiceStatus (hSStat, &hServStatus))
180 LogEvent (_T("Cannot set service status"), 101, TRUE);
181 return;
182 }
183
184 INT
185 CreateServers()
186 {
187 DWORD dwThreadId[NUM_SERVICES];
188 HANDLE hThread[NUM_SERVICES];
189 INT i;
190
191 UpdateStatus(-1, -1); /* increment checkpoint */
192
193 /* Create MAX_THREADS worker threads. */
194 for( i=0; i<NUM_SERVICES; i++ )
195 {
196 _tprintf(_T("Starting %s server....\n"), Services[i].Name);
197
198 hThread[i] = CreateThread(
199 NULL, // default security attributes
200 0, // use default stack size
201 StartServer, // thread function
202 &Services[i], // argument to thread function
203 0, // use default creation flags
204 &dwThreadId[i]); // returns the thread identifier
205
206 /* Check the return value for success. */
207 if (hThread[i] == NULL)
208 {
209 _tprintf(_T("Failed to start %s server....\n"), Services[i].Name);
210 ExitProcess(i);
211 }
212 }
213
214 /* Wait until all threads have terminated. */
215 WaitForMultipleObjects(NUM_SERVICES, hThread, TRUE, INFINITE);
216
217 /* Close all thread handles upon completion. */
218 for(i=0; i<NUM_SERVICES; i++)
219 {
220 CloseHandle(hThread[i]);
221 }
222 return 0;
223 }
224
225
226 /* LogEvent is similar to the ReportError function used elsewhere
227 For a service, however, we ReportEvent rather than write to standard
228 error. Eventually, this function should go into the utility
229 library. */
230 VOID
231 LogEvent (LPCTSTR UserMessage, DWORD ExitCode, BOOL PrintErrorMsg)
232 {
233 DWORD eMsgLen, ErrNum = GetLastError ();
234 LPTSTR lpvSysMsg;
235 TCHAR MessageBuffer[512];
236
237 if (PrintErrorMsg) {
238 eMsgLen = FormatMessage (FORMAT_MESSAGE_ALLOCATE_BUFFER |
239 FORMAT_MESSAGE_FROM_SYSTEM, NULL,
240 ErrNum, MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT),
241 (LPTSTR)&lpvSysMsg, 0, NULL);
242
243 _stprintf (MessageBuffer, _T("\n%s %s ErrNum = %d. ExitCode = %d."),
244 UserMessage, lpvSysMsg, ErrNum, ExitCode);
245 HeapFree (GetProcessHeap (), 0, lpvSysMsg);
246 /* Explained in Chapter 6. */
247 } else {
248 _stprintf (MessageBuffer, _T("\n%s ExitCode = %d."),
249 UserMessage, ExitCode);
250 }
251
252 fputs (MessageBuffer, hLogFile);
253
254 if (ExitCode > 0)
255 ExitProcess (ExitCode);
256 else
257 return;
258 }
259
260 #endif