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 LPTSTR ServiceName
= _T("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
, _T("Echo"), EchoHandler
},
27 {DISCARD_PORT
, _T("Discard"), DiscardHandler
},
28 {DAYTIME_PORT
, _T("Daytime"), DaytimeHandler
},
29 {QOTD_PORT
, _T("QOTD"), QotdHandler
},
30 {CHARGEN_PORT
, _T("Chargen"), ChargenHandler
}
35 UpdateStatus(PSERVICEINFO pServInfo
,
42 pServInfo
->servStatus
.dwCheckPoint
+= Check
;
44 pServInfo
->servStatus
.dwCheckPoint
= Check
;
47 pServInfo
->servStatus
.dwCurrentState
= NewStatus
;
51 _T("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(_T("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 _stprintf(buf
, _T("WSAStartup() failed : %lu\n"), RetVal
);
74 LogEvent(buf
, 0, 100, LOG_ALL
);
78 UpdateStatus(pServInfo
, 0, 1);
80 LogEvent(_T("\nCreating server Threads"), 0, 0, LOG_FILE
);
82 /* Create worker threads. */
83 for(i
= 0; i
< NUM_SERVICES
; i
++)
85 _stprintf(buf
, _T("Creating thread for %s server"), Services
[i
].Name
);
86 LogEvent(buf
, 0, 0, LOG_FILE
);
88 hThread
[i
] = CreateThread(NULL
,
95 if (hThread
[i
] == NULL
)
97 _stprintf(buf
, _T("\nFailed to start %s server\n"), Services
[i
].Name
);
98 LogEvent(buf
, GetLastError(), 0, LOG_ALL
);
101 UpdateStatus(pServInfo
, 0, 1);
104 LogEvent(_T("Setting service status to running"), 0, 0, LOG_FILE
);
105 UpdateStatus(pServInfo
, SERVICE_RUNNING
, 0);
107 /* Wait until all threads have terminated. */
108 WaitForMultipleObjects(NUM_SERVICES
, hThread
, TRUE
, INFINITE
);
110 for(i
= 0; i
< NUM_SERVICES
; i
++)
112 if (hThread
[i
] != NULL
)
113 CloseHandle(hThread
[i
]);
116 LogEvent(_T("Detaching Winsock2"), 0, 0, LOG_FILE
);
123 ServerCtrlHandler(DWORD dwControl
,
128 PSERVICEINFO pServInfo
= (PSERVICEINFO
)lpContext
;
132 case SERVICE_CONTROL_SHUTDOWN
:
133 case SERVICE_CONTROL_STOP
:
134 LogEvent(_T("\nSetting the service to SERVICE_STOP_PENDING"), 0, 0, LOG_FILE
);
135 InterlockedExchange((LONG
*)&bShutdown
, TRUE
);
136 pServInfo
->servStatus
.dwWin32ExitCode
= 0;
137 pServInfo
->servStatus
.dwWaitHint
= 0;
138 UpdateStatus(pServInfo
, SERVICE_STOP_PENDING
, 1);
141 case SERVICE_CONTROL_PAUSE
: /* not yet implemented */
142 LogEvent(_T("Setting the service to SERVICE_PAUSED"), 0, 0, LOG_FILE
);
143 InterlockedExchange((LONG
*)&bPause
, TRUE
);
144 UpdateStatus(pServInfo
, SERVICE_PAUSED
, 0);
147 case SERVICE_CONTROL_CONTINUE
:
148 LogEvent(_T("Setting the service to SERVICE_RUNNING"), 0, 0, LOG_FILE
);
149 InterlockedExchange((LONG
*)&bPause
, FALSE
);
150 UpdateStatus(pServInfo
, SERVICE_RUNNING
, 0);
153 case SERVICE_CONTROL_INTERROGATE
:
157 if (dwControl
> 127 && dwControl
< 256) /* user defined */
158 LogEvent(_T("User defined control code"), 0, 0, LOG_FILE
);
160 LogEvent(_T("ERROR: Bad control code"), 0, 0, LOG_FILE
);
166 ServiceMain(DWORD argc
, LPTSTR argv
[])
168 SERVICEINFO servInfo
;
170 LogEvent (_T("Entering ServiceMain."), 0, 0, LOG_FILE
);
172 servInfo
.servStatus
.dwServiceType
= SERVICE_WIN32_OWN_PROCESS
;
173 servInfo
.servStatus
.dwCurrentState
= SERVICE_STOPPED
;
174 servInfo
.servStatus
.dwControlsAccepted
= SERVICE_ACCEPT_STOP
| SERVICE_ACCEPT_SHUTDOWN
| SERVICE_ACCEPT_PAUSE_CONTINUE
;
175 servInfo
.servStatus
.dwWin32ExitCode
= ERROR_SERVICE_SPECIFIC_ERROR
;
176 servInfo
.servStatus
.dwServiceSpecificExitCode
= 0;
177 servInfo
.servStatus
.dwCheckPoint
= 0;
178 servInfo
.servStatus
.dwWaitHint
= 2 * CS_TIMEOUT
;
180 LogEvent(_T("Registering service control handler"), 0, 0, LOG_FILE
);
181 servInfo
.hStatus
= RegisterServiceCtrlHandlerEx(ServiceName
,
182 (LPHANDLER_FUNCTION_EX
)ServerCtrlHandler
,
184 if (!servInfo
.hStatus
)
185 LogEvent(_T("Failed to register service\n"), GetLastError(), 100, LOG_ALL
);
187 UpdateStatus(&servInfo
, SERVICE_START_PENDING
, 1);
189 if (!CreateServers(&servInfo
))
191 servInfo
.servStatus
.dwServiceSpecificExitCode
= 1;
192 UpdateStatus(&servInfo
, SERVICE_STOPPED
, 0);
196 LogEvent(_T("Service threads shut down. Set SERVICE_STOPPED status"), 0, 0, LOG_FILE
);
197 UpdateStatus(&servInfo
, SERVICE_STOPPED
, 0);
199 LogEvent(_T("Leaving ServiceMain\n"), 0, 0, LOG_FILE
);
203 int _tmain (int argc
, LPTSTR argv
[])
205 SERVICE_TABLE_ENTRY ServiceTable
[] =
207 {ServiceName
, ServiceMain
},
213 if (!StartServiceCtrlDispatcher(ServiceTable
))
214 LogEvent(_T("failed to start the service control dispatcher"), GetLastError(), 101, LOG_ALL
);