1 /*
2 * PROJECT: ReactOS api tests
3 * LICENSE: GPLv2+ - See COPYING in the top level directory
4 * PURPOSE: Test for service networking
5 * PROGRAMMER: Pierre Schweitzer
6 */
7
8 #include "precomp.h"
9
10 #include "svchlp.h"
11
12 #define WIN32_NO_STATUS
13 #include <iphlpapi.h>
14 #include <winsock2.h>
15
16 /*** Service part of the test ***/
17
18 static SERVICE_STATUS_HANDLE status_handle;
19
20 static void
report_service_status(DWORD dwCurrentState,DWORD dwWin32ExitCode,DWORD dwWaitHint)21 report_service_status(DWORD dwCurrentState,
22 DWORD dwWin32ExitCode,
23 DWORD dwWaitHint)
24 {
25 BOOL res;
26 SERVICE_STATUS status;
27
28 status.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
29 status.dwCurrentState = dwCurrentState;
30 status.dwWin32ExitCode = dwWin32ExitCode;
31 status.dwWaitHint = dwWaitHint;
32
33 status.dwServiceSpecificExitCode = 0;
34 status.dwCheckPoint = 0;
35
36 if ( (dwCurrentState == SERVICE_START_PENDING) ||
37 (dwCurrentState == SERVICE_STOP_PENDING) ||
38 (dwCurrentState == SERVICE_STOPPED) )
39 {
40 status.dwControlsAccepted = 0;
41 }
42 else
43 {
44 status.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;
45 }
46
47 #if 0
48 if ( (dwCurrentState == SERVICE_RUNNING) || (dwCurrentState == SERVICE_STOPPED) )
49 status.dwCheckPoint = 0;
50 else
51 status.dwCheckPoint = dwCheckPoint++;
52 #endif
53
54 res = SetServiceStatus(status_handle, &status);
55 service_ok(res, "SetServiceStatus(%d) failed: %lu\n", dwCurrentState, GetLastError());
56 }
57
service_handler(DWORD ctrl)58 static VOID WINAPI service_handler(DWORD ctrl)
59 {
60 switch(ctrl)
61 {
62 case SERVICE_CONTROL_STOP:
63 case SERVICE_CONTROL_SHUTDOWN:
64 report_service_status(SERVICE_STOP_PENDING, NO_ERROR, 0);
65 default:
66 report_service_status(SERVICE_RUNNING, NO_ERROR, 0);
67 }
68 }
69
GetExtendedTcpTableWithAlloc(PVOID * TcpTable,BOOL Order,DWORD Family,TCP_TABLE_CLASS Class)70 static DWORD GetExtendedTcpTableWithAlloc(PVOID *TcpTable, BOOL Order, DWORD Family, TCP_TABLE_CLASS Class)
71 {
72 DWORD ret;
73 DWORD Size = 0;
74
75 *TcpTable = NULL;
76
77 ret = GetExtendedTcpTable(*TcpTable, &Size, Order, Family, Class, 0);
78 if (ret == ERROR_INSUFFICIENT_BUFFER)
79 {
80 *TcpTable = HeapAlloc(GetProcessHeap(), 0, Size);
81 if (*TcpTable == NULL)
82 {
83 return ERROR_OUTOFMEMORY;
84 }
85
86 ret = GetExtendedTcpTable(*TcpTable, &Size, Order, Family, Class, 0);
87 if (ret != NO_ERROR)
88 {
89 HeapFree(GetProcessHeap(), 0, *TcpTable);
90 *TcpTable = NULL;
91 }
92 }
93
94 return ret;
95 }
96
GetExtendedUdpTableWithAlloc(PVOID * UdpTable,BOOL Order,DWORD Family,UDP_TABLE_CLASS Class)97 static DWORD GetExtendedUdpTableWithAlloc(PVOID *UdpTable, BOOL Order, DWORD Family, UDP_TABLE_CLASS Class)
98 {
99 DWORD ret;
100 DWORD Size = 0;
101
102 *UdpTable = NULL;
103
104 ret = GetExtendedUdpTable(*UdpTable, &Size, Order, Family, Class, 0);
105 if (ret == ERROR_INSUFFICIENT_BUFFER)
106 {
107 *UdpTable = HeapAlloc(GetProcessHeap(), 0, Size);
108 if (*UdpTable == NULL)
109 {
110 return ERROR_OUTOFMEMORY;
111 }
112
113 ret = GetExtendedUdpTable(*UdpTable, &Size, Order, Family, Class, 0);
114 if (ret != NO_ERROR)
115 {
116 HeapFree(GetProcessHeap(), 0, *UdpTable);
117 *UdpTable = NULL;
118 }
119 }
120
121 return ret;
122 }
123
124 static void
test_tcp(LPWSTR svc_name,DWORD service_tag)125 test_tcp(LPWSTR svc_name, DWORD service_tag)
126 {
127 SOCKET sock;
128 SOCKADDR_IN server;
129 PMIB_TCPTABLE_OWNER_MODULE TcpTableOwnerMod;
130 DWORD i, ret;
131 BOOLEAN Found;
132 DWORD Pid = GetCurrentProcessId();
133
134 sock = socket(AF_INET, SOCK_STREAM, 0);
135 service_ok(sock != INVALID_SOCKET, "Socket creation failed!\n");
136
137 ZeroMemory(&server, sizeof(SOCKADDR_IN));
138 server.sin_family = AF_INET;
139 server.sin_addr.s_addr = htonl(INADDR_ANY);
140 server.sin_port = htons(9876);
141
142 ret = bind(sock, (SOCKADDR*)&server, sizeof(SOCKADDR_IN));
143 service_ok(ret != SOCKET_ERROR, "binding failed\n");
144
145 ret = listen(sock, SOMAXCONN);
146 service_ok(ret != SOCKET_ERROR, "listening failed\n");
147
148 ret = GetExtendedTcpTableWithAlloc((PVOID *)&TcpTableOwnerMod, TRUE, AF_INET, TCP_TABLE_OWNER_MODULE_LISTENER);
149 service_ok(ret == ERROR_SUCCESS, "GetExtendedTcpTableWithAlloc failed: %x\n", ret);
150 if (ret == ERROR_SUCCESS)
151 {
152 service_ok(TcpTableOwnerMod->dwNumEntries > 0, "No TCP connections?!\n");
153
154 Found = FALSE;
155 for (i = 0; i < TcpTableOwnerMod->dwNumEntries; ++i)
156 {
157 if (TcpTableOwnerMod->table[i].dwState == MIB_TCP_STATE_LISTEN &&
158 TcpTableOwnerMod->table[i].dwLocalAddr == 0 &&
159 TcpTableOwnerMod->table[i].dwLocalPort == htons(9876) &&
160 TcpTableOwnerMod->table[i].dwRemoteAddr == 0)
161 {
162 Found = TRUE;
163 break;
164 }
165 }
166
167 service_ok(Found, "Our socket wasn't found!\n");
168 if (Found)
169 {
170 DWORD Size = 0;
171 PTCPIP_OWNER_MODULE_BASIC_INFO BasicInfo = NULL;
172
173 service_ok(TcpTableOwnerMod->table[i].dwOwningPid == Pid, "Invalid owner\n");
174 service_ok((DWORD)(TcpTableOwnerMod->table[i].OwningModuleInfo[0]) == service_tag, "Invalid tag: %x - %x\n", (DWORD)TcpTableOwnerMod->table[i].OwningModuleInfo[0], service_tag);
175
176 ret = GetOwnerModuleFromTcpEntry(&TcpTableOwnerMod->table[i], TCPIP_OWNER_MODULE_INFO_BASIC, BasicInfo, &Size);
177 service_ok(ret == ERROR_INSUFFICIENT_BUFFER, "GetOwnerModuleFromTcpEntry failed with: %x\n", ret);
178 if (ERROR_INSUFFICIENT_BUFFER == ERROR_INSUFFICIENT_BUFFER)
179 {
180 BasicInfo = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, Size);
181 service_ok(BasicInfo != NULL, "HeapAlloc failed\n");
182
183 ret = GetOwnerModuleFromTcpEntry(&TcpTableOwnerMod->table[i], TCPIP_OWNER_MODULE_INFO_BASIC, BasicInfo, &Size);
184 service_ok(ret == ERROR_SUCCESS, "GetOwnerModuleFromTcpEntry failed with: %x\n", ret);
185 service_ok(_wcsicmp(svc_name, BasicInfo->pModulePath) == 0, "Mismatching names (%S, %S)\n", svc_name, BasicInfo->pModulePath);
186 service_ok(_wcsicmp(svc_name, BasicInfo->pModuleName) == 0, "Mismatching names (%S, %S)\n", svc_name, BasicInfo->pModuleName);
187 }
188 }
189
190 HeapFree(GetProcessHeap(), 0, TcpTableOwnerMod);
191 }
192
193 closesocket(sock);
194 }
195
196 static void
test_udp(LPWSTR svc_name,DWORD service_tag)197 test_udp(LPWSTR svc_name, DWORD service_tag)
198 {
199 SOCKET sock;
200 SOCKADDR_IN server;
201 PMIB_UDPTABLE_OWNER_MODULE UdpTableOwnerMod;
202 DWORD i, ret;
203 BOOLEAN Found;
204 DWORD Pid = GetCurrentProcessId();
205
206 sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
207 service_ok(sock != INVALID_SOCKET, "Socket creation failed!\n");
208
209 ZeroMemory(&server, sizeof(SOCKADDR_IN));
210 server.sin_family = AF_INET;
211 server.sin_addr.s_addr = htonl(INADDR_ANY);
212 server.sin_port = htons(9876);
213
214 ret = bind(sock, (SOCKADDR*)&server, sizeof(SOCKADDR_IN));
215 service_ok(ret != SOCKET_ERROR, "binding failed\n");
216
217 ret = GetExtendedUdpTableWithAlloc((PVOID *)&UdpTableOwnerMod, TRUE, AF_INET, UDP_TABLE_OWNER_MODULE);
218 service_ok(ret == ERROR_SUCCESS, "GetExtendedUdpTableWithAlloc failed: %x\n", ret);
219 if (ret == ERROR_SUCCESS)
220 {
221 service_ok(UdpTableOwnerMod->dwNumEntries > 0, "No TCP connections?!\n");
222
223 Found = FALSE;
224 for (i = 0; i < UdpTableOwnerMod->dwNumEntries; ++i)
225 {
226 if (UdpTableOwnerMod->table[i].dwLocalAddr == 0 &&
227 UdpTableOwnerMod->table[i].dwLocalPort == htons(9876))
228 {
229 Found = TRUE;
230 break;
231 }
232 }
233
234 service_ok(Found, "Our socket wasn't found!\n");
235 if (Found)
236 {
237 DWORD Size = 0;
238 PTCPIP_OWNER_MODULE_BASIC_INFO BasicInfo = NULL;
239
240 service_ok(UdpTableOwnerMod->table[i].dwOwningPid == Pid, "Invalid owner\n");
241 service_ok((DWORD)(UdpTableOwnerMod->table[i].OwningModuleInfo[0]) == service_tag, "Invalid tag: %x - %x\n", (DWORD)UdpTableOwnerMod->table[i].OwningModuleInfo[0], service_tag);
242
243 ret = GetOwnerModuleFromUdpEntry(&UdpTableOwnerMod->table[i], TCPIP_OWNER_MODULE_INFO_BASIC, BasicInfo, &Size);
244 service_ok(ret == ERROR_INSUFFICIENT_BUFFER, "GetOwnerModuleFromUdpEntry failed with: %x\n", ret);
245 if (ret == ERROR_INSUFFICIENT_BUFFER)
246 {
247 BasicInfo = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, Size);
248 service_ok(BasicInfo != NULL, "HeapAlloc failed\n");
249
250 ret = GetOwnerModuleFromUdpEntry(&UdpTableOwnerMod->table[i], TCPIP_OWNER_MODULE_INFO_BASIC, BasicInfo, &Size);
251 service_ok(ret == ERROR_SUCCESS, "GetOwnerModuleFromUdpEntry failed with: %x\n", ret);
252 service_ok(_wcsicmp(svc_name, BasicInfo->pModulePath) == 0, "Mismatching names (%S, %S)\n", svc_name, BasicInfo->pModulePath);
253 service_ok(_wcsicmp(svc_name, BasicInfo->pModuleName) == 0, "Mismatching names (%S, %S)\n", svc_name, BasicInfo->pModuleName);
254 }
255 }
256
257 HeapFree(GetProcessHeap(), 0, UdpTableOwnerMod);
258 }
259
260 closesocket(sock);
261 }
262
263 static void WINAPI
service_main(DWORD dwArgc,LPWSTR * lpszArgv)264 service_main(DWORD dwArgc, LPWSTR* lpszArgv)
265 {
266 // SERVICE_STATUS_HANDLE status_handle;
267 PTEB Teb;
268 WSADATA wsaData;
269
270 UNREFERENCED_PARAMETER(dwArgc);
271
272 /* Register our service for control (lpszArgv[0] holds the service name) */
273 status_handle = RegisterServiceCtrlHandlerW(lpszArgv[0], service_handler);
274 service_ok(status_handle != NULL, "RegisterServiceCtrlHandler failed: %lu\n", GetLastError());
275 if (!status_handle)
276 return;
277
278 /* Report SERVICE_RUNNING status */
279 report_service_status(SERVICE_RUNNING, NO_ERROR, 4000);
280
281 /* Check our tag is not 0 */
282 Teb = NtCurrentTeb();
283 service_ok(Teb->SubProcessTag != 0, "SubProcessTag is not defined!\n");
284
285 if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
286 {
287 skip("Failed to init WS2\n");
288 goto quit;
289 }
290
291 test_tcp(lpszArgv[0], PtrToUlong(Teb->SubProcessTag));
292 test_udp(lpszArgv[0], PtrToUlong(Teb->SubProcessTag));
293
294 WSACleanup();
295 quit:
296 /* Work is done */
297 report_service_status(SERVICE_STOPPED, NO_ERROR, 0);
298 }
299
start_service(PCSTR service_nameA,PCWSTR service_nameW)300 static BOOL start_service(PCSTR service_nameA, PCWSTR service_nameW)
301 {
302 BOOL res;
303
304 SERVICE_TABLE_ENTRYW servtbl[] =
305 {
306 { (PWSTR)service_nameW, service_main },
307 { NULL, NULL }
308 };
309
310 res = StartServiceCtrlDispatcherW(servtbl);
311 service_ok(res, "StartServiceCtrlDispatcherW failed: %lu\n", GetLastError());
312 return res;
313 }
314
315
316 /*** Tester part of the test ***/
317
318 static void
my_test_server(PCSTR service_nameA,PCWSTR service_nameW,void * param)319 my_test_server(PCSTR service_nameA,
320 PCWSTR service_nameW,
321 void *param)
322 {
323 BOOL res;
324 SC_HANDLE hSC = NULL;
325 SC_HANDLE hService = NULL;
326 SERVICE_STATUS ServiceStatus;
327
328 /* Open the SCM */
329 hSC = OpenSCManagerW(NULL, NULL, SC_MANAGER_ALL_ACCESS);
330 if (!hSC)
331 {
332 skip("OpenSCManagerW failed with error %lu!\n", GetLastError());
333 return;
334 }
335
336 /* First create ourselves as a service running in the default LocalSystem account */
337 hService = register_service_exW(hSC, L"ServiceNetwork", service_nameW, NULL,
338 SERVICE_ALL_ACCESS,
339 SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS,
340 SERVICE_DEMAND_START,
341 SERVICE_ERROR_IGNORE,
342 NULL, NULL, NULL,
343 NULL, NULL);
344 if (!hService)
345 {
346 skip("CreateServiceW failed with error %lu!\n", GetLastError());
347 goto Cleanup;
348 }
349
350 /* Start it */
351 if (!StartServiceW(hService, 0, NULL))
352 {
353 skip("StartServiceW failed with error %lu!\n", GetLastError());
354 goto Cleanup;
355 }
356
357 /* Wait for the service to stop by itself */
358 do
359 {
360 Sleep(100);
361 ZeroMemory(&ServiceStatus, sizeof(ServiceStatus));
362 res = QueryServiceStatus(hService, &ServiceStatus);
363 } while (res && ServiceStatus.dwCurrentState != SERVICE_STOPPED);
364 ok(res, "QueryServiceStatus failed: %lu\n", GetLastError());
365 ok(ServiceStatus.dwCurrentState == SERVICE_STOPPED, "ServiceStatus.dwCurrentState = %lx\n", ServiceStatus.dwCurrentState);
366
367 /* Be sure the service is really stopped */
368 res = ControlService(hService, SERVICE_CONTROL_STOP, &ServiceStatus);
369 if (!res && ServiceStatus.dwCurrentState != SERVICE_STOPPED &&
370 ServiceStatus.dwCurrentState != SERVICE_STOP_PENDING &&
371 GetLastError() != ERROR_SERVICE_NOT_ACTIVE)
372 {
373 skip("ControlService failed with error %lu!\n", GetLastError());
374 goto Cleanup;
375 }
376
377 #if 0
378 trace("Service stopped. Going to restart it...\n");
379
380 /* Now change the service configuration to make it start under the NetworkService account */
381 if (!ChangeServiceConfigW(hService,
382 SERVICE_NO_CHANGE,
383 SERVICE_NO_CHANGE,
384 SERVICE_NO_CHANGE,
385 NULL, NULL, NULL, NULL,
386 L"NT AUTHORITY\\NetworkService", L"",
387 NULL))
388 {
389 skip("ChangeServiceConfigW failed with error %lu!\n", GetLastError());
390 goto Cleanup;
391 }
392
393 /* Start it */
394 if (!StartServiceW(hService, 0, NULL))
395 {
396 skip("StartServiceW failed with error %lu!\n", GetLastError());
397 goto Cleanup;
398 }
399
400 /* Wait for the service to stop by itself */
401 do
402 {
403 Sleep(100);
404 ZeroMemory(&ServiceStatus, sizeof(ServiceStatus));
405 res = QueryServiceStatus(hService, &ServiceStatus);
406 } while (res && ServiceStatus.dwCurrentState != SERVICE_STOPPED);
407 ok(res, "QueryServiceStatus failed: %lu\n", GetLastError());
408 ok(ServiceStatus.dwCurrentState == SERVICE_STOPPED, "ServiceStatus.dwCurrentState = %lx\n", ServiceStatus.dwCurrentState);
409
410 /* Be sure the service is really stopped */
411 res = ControlService(hService, SERVICE_CONTROL_STOP, &ServiceStatus);
412 if (!res && ServiceStatus.dwCurrentState != SERVICE_STOPPED &&
413 ServiceStatus.dwCurrentState != SERVICE_STOP_PENDING &&
414 GetLastError() != ERROR_SERVICE_NOT_ACTIVE)
415 {
416 skip("ControlService failed with error %lu!\n", GetLastError());
417 goto Cleanup;
418 }
419 #endif
420
421 Cleanup:
422 if (hService)
423 {
424 res = DeleteService(hService);
425 ok(res, "DeleteService failed: %lu\n", GetLastError());
426 CloseServiceHandle(hService);
427 }
428
429 if (hSC)
430 CloseServiceHandle(hSC);
431 }
432
START_TEST(ServiceNetwork)433 START_TEST(ServiceNetwork)
434 {
435 int argc;
436 char** argv;
437
438 /* Check whether this test is started as a separated service process */
439 argc = winetest_get_mainargs(&argv);
440 if (argc >= 3)
441 {
442 service_process(start_service, argc, argv);
443 return;
444 }
445
446 /* We are started as the real test */
447 test_runner(my_test_server, NULL);
448 // trace("Returned from test_runner\n");
449 }
450