2 * PROJECT: ReactOS simple TCP/IP services
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: /base/services/tcpsvcs/tcpsvcs.c
5 * PURPOSE: Provide CharGen, Daytime, Discard, Echo, and Qotd services
6 * COPYRIGHT: Copyright 2005 - 2008 Ged Murphy <gedmurphy@reactos.org>
12 static WCHAR ServiceName
[] = L
"tcpsvcs";
14 volatile BOOL bShutdown
= FALSE
;
15 volatile BOOL bPause
= FALSE
;
17 typedef struct _ServiceInfo
19 SERVICE_STATUS servStatus
;
20 SERVICE_STATUS_HANDLE hStatus
;
21 } SERVICEINFO
, *PSERVICEINFO
;
24 Services
[NUM_SERVICES
] =
26 {ECHO_PORT
, L
"Echo", EchoHandler
},
27 {DISCARD_PORT
, L
"Discard", DiscardHandler
},
28 {DAYTIME_PORT
, L
"Daytime", DaytimeHandler
},
29 {QOTD_PORT
, L
"QOTD", QotdHandler
},
30 {CHARGEN_PORT
, L
"Chargen", ChargenHandler
}
35 UpdateStatus(PSERVICEINFO pServInfo
,
42 pServInfo
->servStatus
.dwCheckPoint
+= Check
;
44 pServInfo
->servStatus
.dwCheckPoint
= Check
;
47 pServInfo
->servStatus
.dwCurrentState
= NewStatus
;
51 L
"Service state 0x%lu, CheckPoint %lu",
52 pServInfo
->servStatus
.dwCurrentState
,
53 pServInfo
->servStatus
.dwCheckPoint
);
54 LogEvent(szSet
, 0, 0, LOG_FILE
);
56 if (!SetServiceStatus(pServInfo
->hStatus
, &pServInfo
->servStatus
))
57 LogEvent(L
"Cannot set service status", GetLastError(), 0, LOG_ALL
);
62 CreateServers(PSERVICEINFO pServInfo
)
64 DWORD dwThreadId
[NUM_SERVICES
];
65 HANDLE hThread
[NUM_SERVICES
];
71 if ((RetVal
= WSAStartup(MAKEWORD(2, 2), &wsaData
)) != 0)
73 _swprintf(buf
, L
"WSAStartup() failed : %lu\n", RetVal
);
74 LogEvent(buf
, 0, 100, LOG_ALL
);
78 UpdateStatus(pServInfo
, 0, 1);
80 LogEvent(L
"\nCreating server Threads", 0, 0, LOG_FILE
);
82 /* Create worker threads. */
83 for (i
= 0; i
< NUM_SERVICES
; i
++)
85 _swprintf(buf
, L
"Creating thread for %s server", Services
[i
].lpName
);
86 LogEvent(buf
, 0, 0, LOG_FILE
);
88 hThread
[i
] = CreateThread(NULL
,
95 if (hThread
[i
] == NULL
)
97 _swprintf(buf
, L
"\nError creating %s server thread\n", Services
[i
].lpName
);
98 LogEvent(buf
, GetLastError(), 0, LOG_ALL
);
102 UpdateStatus(pServInfo
, 0, 1);
105 LogEvent(L
"Setting service status to running", 0, 0, LOG_FILE
);
106 UpdateStatus(pServInfo
, SERVICE_RUNNING
, 0);
108 /* Wait until all threads have terminated. */
109 WaitForMultipleObjects(NUM_SERVICES
, hThread
, TRUE
, INFINITE
);
111 for (i
= 0; i
< NUM_SERVICES
; i
++)
113 if (hThread
[i
] != NULL
)
114 CloseHandle(hThread
[i
]);
117 LogEvent(L
"Detaching Winsock2", 0, 0, LOG_FILE
);
124 ServerCtrlHandler(DWORD dwControl
,
129 PSERVICEINFO pServInfo
= (PSERVICEINFO
)lpContext
;
133 case SERVICE_CONTROL_SHUTDOWN
:
134 case SERVICE_CONTROL_STOP
:
135 LogEvent(L
"\nSetting the service to SERVICE_STOP_PENDING", 0, 0, LOG_FILE
);
136 InterlockedExchange((LONG
*)&bShutdown
, TRUE
);
137 pServInfo
->servStatus
.dwWin32ExitCode
= 0;
138 pServInfo
->servStatus
.dwWaitHint
= 0;
139 UpdateStatus(pServInfo
, SERVICE_STOP_PENDING
, 1);
142 case SERVICE_CONTROL_PAUSE
: /* not yet implemented */
143 LogEvent(L
"Setting the service to SERVICE_PAUSED", 0, 0, LOG_FILE
);
144 InterlockedExchange((LONG
*)&bPause
, TRUE
);
145 UpdateStatus(pServInfo
, SERVICE_PAUSED
, 0);
148 case SERVICE_CONTROL_CONTINUE
:
149 LogEvent(L
"Setting the service to SERVICE_RUNNING", 0, 0, LOG_FILE
);
150 InterlockedExchange((LONG
*)&bPause
, FALSE
);
151 UpdateStatus(pServInfo
, SERVICE_RUNNING
, 0);
154 case SERVICE_CONTROL_INTERROGATE
:
158 if (dwControl
> 127 && dwControl
< 256) /* user defined */
159 LogEvent(L
"User defined control code", 0, 0, LOG_FILE
);
161 LogEvent(L
"ERROR: Bad control code", 0, 0, LOG_FILE
);
167 ServiceMain(DWORD argc
, LPWSTR argv
[])
169 SERVICEINFO servInfo
;
171 LogEvent(L
"Entering ServiceMain.", 0, 0, LOG_FILE
);
173 servInfo
.servStatus
.dwServiceType
= SERVICE_WIN32_OWN_PROCESS
;
174 servInfo
.servStatus
.dwCurrentState
= SERVICE_STOPPED
;
175 servInfo
.servStatus
.dwControlsAccepted
= SERVICE_ACCEPT_STOP
| SERVICE_ACCEPT_SHUTDOWN
| SERVICE_ACCEPT_PAUSE_CONTINUE
;
176 servInfo
.servStatus
.dwWin32ExitCode
= ERROR_SERVICE_SPECIFIC_ERROR
;
177 servInfo
.servStatus
.dwServiceSpecificExitCode
= 0;
178 servInfo
.servStatus
.dwCheckPoint
= 0;
179 servInfo
.servStatus
.dwWaitHint
= 2 * CS_TIMEOUT
;
181 LogEvent(L
"Registering service control handler", 0, 0, LOG_FILE
);
182 servInfo
.hStatus
= RegisterServiceCtrlHandlerExW(ServiceName
,
183 (LPHANDLER_FUNCTION_EX
)ServerCtrlHandler
,
185 if (!servInfo
.hStatus
)
186 LogEvent(L
"Failed to register service", GetLastError(), 100, LOG_ALL
);
188 UpdateStatus(&servInfo
, SERVICE_START_PENDING
, 1);
190 if (!CreateServers(&servInfo
))
192 LogEvent(L
"Error creating servers", GetLastError(), 1, LOG_ALL
);
193 servInfo
.servStatus
.dwServiceSpecificExitCode
= 1;
194 UpdateStatus(&servInfo
, SERVICE_STOPPED
, 0);
198 LogEvent(L
"Service threads shut down. Set SERVICE_STOPPED status", 0, 0, LOG_FILE
);
199 UpdateStatus(&servInfo
, SERVICE_STOPPED
, 0);
201 LogEvent(L
"Leaving ServiceMain\n", 0, 0, LOG_FILE
);
205 int _tmain (int argc
, LPTSTR argv
[])
207 SERVICE_TABLE_ENTRYW ServiceTable
[] =
209 {ServiceName
, ServiceMain
},
215 if (!StartServiceCtrlDispatcherW(ServiceTable
))
216 LogEvent(L
"failed to start the service control dispatcher", GetLastError(), 101, LOG_ALL
);