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 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 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 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 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 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 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 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 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 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 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