1 /* 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> 7 * 8 */ 9 10 #include "tcpsvcs.h" 11 12 #include <winsvc.h> 13 14 static WCHAR ServiceName[] = L"tcpsvcs"; 15 16 volatile BOOL bShutdown = FALSE; 17 volatile BOOL bPause = FALSE; 18 19 typedef struct _ServiceInfo 20 { 21 SERVICE_STATUS servStatus; 22 SERVICE_STATUS_HANDLE hStatus; 23 } SERVICEINFO, *PSERVICEINFO; 24 25 static SERVICES 26 Services[NUM_SERVICES] = 27 { 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} 33 }; 34 35 36 static VOID 37 UpdateStatus(PSERVICEINFO pServInfo, 38 DWORD NewStatus, 39 DWORD Check) 40 { 41 WCHAR szSet[50]; 42 43 if (Check > 0) 44 pServInfo->servStatus.dwCheckPoint += Check; 45 else 46 pServInfo->servStatus.dwCheckPoint = Check; 47 48 if (NewStatus > 0) 49 pServInfo->servStatus.dwCurrentState = NewStatus; 50 51 _snwprintf(szSet, 52 49, 53 L"Service state 0x%lx, CheckPoint %lu", 54 pServInfo->servStatus.dwCurrentState, 55 pServInfo->servStatus.dwCheckPoint); 56 LogEvent(szSet, 0, 0, LOG_FILE); 57 58 if (!SetServiceStatus(pServInfo->hStatus, &pServInfo->servStatus)) 59 LogEvent(L"Cannot set service status", GetLastError(), 0, LOG_ALL); 60 } 61 62 63 static BOOL 64 CreateServers(PSERVICEINFO pServInfo) 65 { 66 DWORD dwThreadId[NUM_SERVICES]; 67 HANDLE hThread[NUM_SERVICES]; 68 WSADATA wsaData; 69 WCHAR buf[256]; 70 INT i; 71 DWORD RetVal; 72 73 if ((RetVal = WSAStartup(MAKEWORD(2, 2), &wsaData)) != 0) 74 { 75 swprintf(buf, L"WSAStartup() failed : %lu\n", RetVal); 76 LogEvent(buf, 0, 100, LOG_ALL); 77 return FALSE; 78 } 79 80 UpdateStatus(pServInfo, 0, 1); 81 82 LogEvent(L"\nCreating server Threads", 0, 0, LOG_FILE); 83 84 /* Create worker threads. */ 85 for (i = 0; i < NUM_SERVICES; i++) 86 { 87 swprintf(buf, L"Creating thread for %s server", Services[i].lpName); 88 LogEvent(buf, 0, 0, LOG_FILE); 89 90 hThread[i] = CreateThread(NULL, 91 0, 92 StartServer, 93 &Services[i], 94 0, 95 &dwThreadId[i]); 96 97 if (hThread[i] == NULL) 98 { 99 swprintf(buf, L"\nError creating %s server thread\n", Services[i].lpName); 100 LogEvent(buf, GetLastError(), 0, LOG_ALL); 101 return FALSE; 102 } 103 104 UpdateStatus(pServInfo, 0, 1); 105 } 106 107 LogEvent(L"Setting service status to running", 0, 0, LOG_FILE); 108 UpdateStatus(pServInfo, SERVICE_RUNNING, 0); 109 110 /* Wait until all threads have terminated. */ 111 WaitForMultipleObjects(NUM_SERVICES, hThread, TRUE, INFINITE); 112 113 for (i = 0; i < NUM_SERVICES; i++) 114 { 115 if (hThread[i] != NULL) 116 CloseHandle(hThread[i]); 117 } 118 119 LogEvent(L"Detaching Winsock2", 0, 0, LOG_FILE); 120 WSACleanup(); 121 122 return TRUE; 123 } 124 125 VOID WINAPI 126 ServerCtrlHandler(DWORD dwControl, 127 DWORD dwEventType, 128 LPVOID lpEventData, 129 LPVOID lpContext) 130 { 131 PSERVICEINFO pServInfo = (PSERVICEINFO)lpContext; 132 133 switch (dwControl) 134 { 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); 142 break; 143 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); 148 break; 149 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); 154 break; 155 156 case SERVICE_CONTROL_INTERROGATE: 157 SetServiceStatus(pServInfo->hStatus, &pServInfo->servStatus); 158 break; 159 160 default: 161 if (dwControl > 127 && dwControl < 256) /* user defined */ 162 LogEvent(L"User defined control code", 0, 0, LOG_FILE); 163 else 164 LogEvent(L"ERROR: Bad control code", 0, 0, LOG_FILE); 165 break; 166 } 167 } 168 169 VOID WINAPI 170 ServiceMain(DWORD argc, LPWSTR argv[]) 171 { 172 SERVICEINFO servInfo; 173 174 LogEvent(L"Entering ServiceMain.", 0, 0, LOG_FILE); 175 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; 183 184 LogEvent(L"Registering service control handler", 0, 0, LOG_FILE); 185 servInfo.hStatus = RegisterServiceCtrlHandlerExW(ServiceName, 186 (LPHANDLER_FUNCTION_EX)ServerCtrlHandler, 187 &servInfo); 188 if (!servInfo.hStatus) 189 LogEvent(L"Failed to register service", GetLastError(), 100, LOG_ALL); 190 191 UpdateStatus(&servInfo, SERVICE_START_PENDING, 1); 192 193 if (!CreateServers(&servInfo)) 194 { 195 LogEvent(L"Error creating servers", GetLastError(), 1, LOG_ALL); 196 servInfo.servStatus.dwServiceSpecificExitCode = 1; 197 UpdateStatus(&servInfo, SERVICE_STOPPED, 0); 198 return; 199 } 200 201 LogEvent(L"Service threads shut down. Set SERVICE_STOPPED status", 0, 0, LOG_FILE); 202 UpdateStatus(&servInfo, SERVICE_STOPPED, 0); 203 204 LogEvent(L"Leaving ServiceMain\n", 0, 0, LOG_FILE); 205 } 206 207 208 int _tmain (int argc, LPTSTR argv []) 209 { 210 SERVICE_TABLE_ENTRYW ServiceTable[] = 211 { 212 {ServiceName, ServiceMain}, 213 {NULL, NULL } 214 }; 215 216 if (InitLogging()) 217 { 218 if (!StartServiceCtrlDispatcherW(ServiceTable)) 219 LogEvent(L"failed to start the service control dispatcher", GetLastError(), 101, LOG_ALL); 220 221 UninitLogging(); 222 } 223 224 return 0; 225 } 226