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>
14 static WCHAR ServiceName
[] = L
"tcpsvcs";
16 volatile BOOL bShutdown
= FALSE
;
17 volatile BOOL bPause
= FALSE
;
19 typedef struct _ServiceInfo
21 SERVICE_STATUS servStatus
;
22 SERVICE_STATUS_HANDLE hStatus
;
23 } SERVICEINFO
, *PSERVICEINFO
;
26 Services
[NUM_SERVICES
] =
28 {ECHO_PORT
, L
"Echo", EchoHandler
},
29 {DISCARD_PORT
, L
"Discard", DiscardHandler
},
30 {DAYTIME_PORT
, L
"Daytime", DaytimeHandler
},
31 {QOTD_PORT
, L
"QOTD", QotdHandler
},
32 {CHARGEN_PORT
, L
"Chargen", ChargenHandler
}
37 UpdateStatus(PSERVICEINFO pServInfo
,
44 pServInfo
->servStatus
.dwCheckPoint
+= Check
;
46 pServInfo
->servStatus
.dwCheckPoint
= Check
;
49 pServInfo
->servStatus
.dwCurrentState
= NewStatus
;
53 L
"Service state 0x%lx, CheckPoint %lu",
54 pServInfo
->servStatus
.dwCurrentState
,
55 pServInfo
->servStatus
.dwCheckPoint
);
56 LogEvent(szSet
, 0, 0, LOG_FILE
);
58 if (!SetServiceStatus(pServInfo
->hStatus
, &pServInfo
->servStatus
))
59 LogEvent(L
"Cannot set service status", GetLastError(), 0, LOG_ALL
);
64 CreateServers(PSERVICEINFO pServInfo
)
66 DWORD dwThreadId
[NUM_SERVICES
];
67 HANDLE hThread
[NUM_SERVICES
];
73 if ((RetVal
= WSAStartup(MAKEWORD(2, 2), &wsaData
)) != 0)
75 swprintf(buf
, L
"WSAStartup() failed : %lu\n", RetVal
);
76 LogEvent(buf
, 0, 100, LOG_ALL
);
80 UpdateStatus(pServInfo
, 0, 1);
82 LogEvent(L
"\nCreating server Threads", 0, 0, LOG_FILE
);
84 /* Create worker threads. */
85 for (i
= 0; i
< NUM_SERVICES
; i
++)
87 swprintf(buf
, L
"Creating thread for %s server", Services
[i
].lpName
);
88 LogEvent(buf
, 0, 0, LOG_FILE
);
90 hThread
[i
] = CreateThread(NULL
,
97 if (hThread
[i
] == NULL
)
99 swprintf(buf
, L
"\nError creating %s server thread\n", Services
[i
].lpName
);
100 LogEvent(buf
, GetLastError(), 0, LOG_ALL
);
104 UpdateStatus(pServInfo
, 0, 1);
107 LogEvent(L
"Setting service status to running", 0, 0, LOG_FILE
);
108 UpdateStatus(pServInfo
, SERVICE_RUNNING
, 0);
110 /* Wait until all threads have terminated. */
111 WaitForMultipleObjects(NUM_SERVICES
, hThread
, TRUE
, INFINITE
);
113 for (i
= 0; i
< NUM_SERVICES
; i
++)
115 if (hThread
[i
] != NULL
)
116 CloseHandle(hThread
[i
]);
119 LogEvent(L
"Detaching Winsock2", 0, 0, LOG_FILE
);
126 ServerCtrlHandler(DWORD dwControl
,
131 PSERVICEINFO pServInfo
= (PSERVICEINFO
)lpContext
;
135 case SERVICE_CONTROL_SHUTDOWN
:
136 case SERVICE_CONTROL_STOP
:
137 LogEvent(L
"\nSetting the service to SERVICE_STOP_PENDING", 0, 0, LOG_FILE
);
138 InterlockedExchange((LONG
*)&bShutdown
, TRUE
);
139 pServInfo
->servStatus
.dwWin32ExitCode
= 0;
140 pServInfo
->servStatus
.dwWaitHint
= 5000;
141 UpdateStatus(pServInfo
, SERVICE_STOP_PENDING
, 1);
144 case SERVICE_CONTROL_PAUSE
: /* not yet implemented */
145 LogEvent(L
"Setting the service to SERVICE_PAUSED", 0, 0, LOG_FILE
);
146 InterlockedExchange((LONG
*)&bPause
, TRUE
);
147 UpdateStatus(pServInfo
, SERVICE_PAUSED
, 0);
150 case SERVICE_CONTROL_CONTINUE
:
151 LogEvent(L
"Setting the service to SERVICE_RUNNING", 0, 0, LOG_FILE
);
152 InterlockedExchange((LONG
*)&bPause
, FALSE
);
153 UpdateStatus(pServInfo
, SERVICE_RUNNING
, 0);
156 case SERVICE_CONTROL_INTERROGATE
:
157 SetServiceStatus(pServInfo
->hStatus
, &pServInfo
->servStatus
);
161 if (dwControl
> 127 && dwControl
< 256) /* user defined */
162 LogEvent(L
"User defined control code", 0, 0, LOG_FILE
);
164 LogEvent(L
"ERROR: Bad control code", 0, 0, LOG_FILE
);
170 ServiceMain(DWORD argc
, LPWSTR argv
[])
172 SERVICEINFO servInfo
;
174 LogEvent(L
"Entering ServiceMain.", 0, 0, LOG_FILE
);
176 servInfo
.servStatus
.dwServiceType
= SERVICE_WIN32_OWN_PROCESS
;
177 servInfo
.servStatus
.dwCurrentState
= SERVICE_STOPPED
;
178 servInfo
.servStatus
.dwControlsAccepted
= SERVICE_ACCEPT_STOP
| SERVICE_ACCEPT_SHUTDOWN
| SERVICE_ACCEPT_PAUSE_CONTINUE
;
179 servInfo
.servStatus
.dwWin32ExitCode
= ERROR_SERVICE_SPECIFIC_ERROR
;
180 servInfo
.servStatus
.dwServiceSpecificExitCode
= 0;
181 servInfo
.servStatus
.dwCheckPoint
= 0;
182 servInfo
.servStatus
.dwWaitHint
= 2 * CS_TIMEOUT
;
184 LogEvent(L
"Registering service control handler", 0, 0, LOG_FILE
);
185 servInfo
.hStatus
= RegisterServiceCtrlHandlerExW(ServiceName
,
186 (LPHANDLER_FUNCTION_EX
)ServerCtrlHandler
,
188 if (!servInfo
.hStatus
)
189 LogEvent(L
"Failed to register service", GetLastError(), 100, LOG_ALL
);
191 UpdateStatus(&servInfo
, SERVICE_START_PENDING
, 1);
193 if (!CreateServers(&servInfo
))
195 LogEvent(L
"Error creating servers", GetLastError(), 1, LOG_ALL
);
196 servInfo
.servStatus
.dwServiceSpecificExitCode
= 1;
197 UpdateStatus(&servInfo
, SERVICE_STOPPED
, 0);
201 LogEvent(L
"Service threads shut down. Set SERVICE_STOPPED status", 0, 0, LOG_FILE
);
202 UpdateStatus(&servInfo
, SERVICE_STOPPED
, 0);
204 LogEvent(L
"Leaving ServiceMain\n", 0, 0, LOG_FILE
);
208 int _tmain (int argc
, LPTSTR argv
[])
210 SERVICE_TABLE_ENTRYW ServiceTable
[] =
212 {ServiceName
, ServiceMain
},
218 if (!StartServiceCtrlDispatcherW(ServiceTable
))
219 LogEvent(L
"failed to start the service control dispatcher", GetLastError(), 101, LOG_ALL
);