]> sjero.net Git - iperf/blob - src/service.c
Original 2.0.2 iperf sources
[iperf] / src / service.c
1 // THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
2 // ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
3 // THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
4 // PARTICULAR PURPOSE.
5 //
6 // Copyright (C) 1993-1997  Microsoft Corporation.  All Rights Reserved.
7 //
8 //  MODULE:   service.c
9 //
10 //  PURPOSE:  Implements functions required by all services
11 //            windows.
12 //
13 //  FUNCTIONS:
14 //    main(int argc, char **argv);
15 //    service_ctrl(DWORD dwCtrlCode);
16 //    service_main(DWORD dwArgc, LPTSTR *lpszArgv);
17 //    CmdInstallService();
18 //    CmdRemoveService();
19 //    ControlHandler ( DWORD dwCtrlType );
20 //    GetLastErrorText( LPTSTR lpszBuf, DWORD dwSize );
21 //
22 //  COMMENTS:
23 //
24 //  AUTHOR: Craig Link - Microsoft Developer Support
25 //
26
27 /*
28  * modified Mar.07, 2002 by Feng Qin <fqin@ncsa.uiuc.edu>
29  *          Mar.15, 2002
30  *
31  * removed some functions we don't use at all
32  * add code to start the service immediately after service is installed
33  * 
34  * $Id: service.c,v 1.1.1.1 2004/05/18 01:50:44 kgibbs Exp $
35  */
36
37 #ifdef WIN32
38 #include <windows.h>
39 #include <stdio.h>
40 #include <stdlib.h>
41 #include <process.h>
42 #include <tchar.h>
43
44 #include "service.h"
45
46
47
48 // internal variables
49 SERVICE_STATUS          ssStatus;       // current status of the service
50 SERVICE_STATUS_HANDLE   sshStatusHandle;
51 DWORD                   dwErr = 0;
52 TCHAR                   szErr[256];
53
54 //
55 //  FUNCTION: service_main
56 //
57 //  PURPOSE: To perform actual initialization of the service
58 //
59 //  PARAMETERS:
60 //    dwArgc   - number of command line arguments
61 //    lpszArgv - array of command line arguments
62 //
63 //  RETURN VALUE:
64 //    none
65 //
66 //  COMMENTS:
67 //    This routine performs the service initialization and then calls
68 //    the user defined ServiceStart() routine to perform majority
69 //    of the work.
70 //
71 void WINAPI service_main(DWORD dwArgc, LPTSTR *lpszArgv) {
72     // register our service control handler:
73     //
74     sshStatusHandle = RegisterServiceCtrlHandler( TEXT(SZSERVICENAME), service_ctrl);
75
76     if ( !sshStatusHandle )
77         goto clean;
78
79     // SERVICE_STATUS members that don't change in example
80     //
81     ssStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
82     ssStatus.dwServiceSpecificExitCode = 0;
83
84     // report the status to the service control manager.
85     //
86     if ( !ReportStatusToSCMgr(
87                              SERVICE_START_PENDING, // service state
88                              NO_ERROR,              // exit code
89                              3000) )                 // wait hint
90         goto clean;
91
92
93     ServiceStart( dwArgc, lpszArgv );
94
95     clean:
96
97     // try to report the stopped status to the service control manager.
98     //
99     if ( sshStatusHandle )
100         (VOID)ReportStatusToSCMgr(
101                                  SERVICE_STOPPED,
102                                  dwErr,
103                                  0);
104
105     return;
106 }
107
108
109
110 //
111 //  FUNCTION: service_ctrl
112 //
113 //  PURPOSE: This function is called by the SCM whenever
114 //           ControlService() is called on this service.
115 //
116 //  PARAMETERS:
117 //    dwCtrlCode - type of control requested
118 //
119 //  RETURN VALUE:
120 //    none
121 //
122 //  COMMENTS:
123 //
124 VOID WINAPI service_ctrl(DWORD dwCtrlCode) {
125     // Handle the requested control code.
126     //
127     switch ( dwCtrlCode ) {
128         // Stop the service.
129         //
130         // SERVICE_STOP_PENDING should be reported before
131         // setting the Stop Event - hServerStopEvent - in
132         // ServiceStop().  This avoids a race condition
133         // which may result in a 1053 - The Service did not respond...
134         // error.
135         case SERVICE_CONTROL_STOP:
136             ReportStatusToSCMgr(SERVICE_STOP_PENDING, NO_ERROR, 0);
137             ServiceStop();
138
139             return;
140
141             // Update the service status.
142             //
143         case SERVICE_CONTROL_INTERROGATE:
144             break;
145
146             // invalid control code
147             //
148         default:
149             break;
150
151     }
152     ReportStatusToSCMgr(SERVICE_STOPPED, NO_ERROR, 0);
153 //    ReportStatusToSCMgr(ssStatus.dwCurrentState, NO_ERROR, 0);
154 }
155
156
157
158 //
159 //  FUNCTION: ReportStatusToSCMgr()
160 //
161 //  PURPOSE: Sets the current status of the service and
162 //           reports it to the Service Control Manager
163 //
164 //  PARAMETERS:
165 //    dwCurrentState - the state of the service
166 //    dwWin32ExitCode - error code to report
167 //    dwWaitHint - worst case estimate to next checkpoint
168 //
169 //  RETURN VALUE:
170 //    TRUE  - success
171 //    FALSE - failure
172 //
173 //  COMMENTS:
174 //
175 BOOL ReportStatusToSCMgr(DWORD dwCurrentState,
176                          DWORD dwWin32ExitCode,
177                          DWORD dwWaitHint) {
178     static DWORD dwCheckPoint = 1;
179     BOOL fResult = TRUE;
180
181
182     if ( dwCurrentState == SERVICE_START_PENDING )
183         ssStatus.dwControlsAccepted = 0;
184     else
185         ssStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP;
186
187     ssStatus.dwCurrentState = dwCurrentState;
188     ssStatus.dwWin32ExitCode = dwWin32ExitCode;
189     ssStatus.dwWaitHint = dwWaitHint;
190
191     if ( ( dwCurrentState == SERVICE_RUNNING ) ||
192          ( dwCurrentState == SERVICE_STOPPED ) )
193         ssStatus.dwCheckPoint = 0;
194     else
195         ssStatus.dwCheckPoint = dwCheckPoint++;
196
197
198     // Report the status of the service to the service control manager.
199     //
200     if ( !(fResult = SetServiceStatus( sshStatusHandle, &ssStatus)) ) {
201         AddToMessageLog(TEXT("SetServiceStatus"));
202     }
203     return fResult;
204 }
205
206
207
208 //
209 //  FUNCTION: AddToMessageLog(LPTSTR lpszMsg)
210 //
211 //  PURPOSE: Allows any thread to log an error message
212 //
213 //  PARAMETERS:
214 //    lpszMsg - text for message
215 //
216 //  RETURN VALUE:
217 //    none
218 //
219 //  COMMENTS:
220 //
221 VOID AddToMessageLog(LPTSTR lpszMsg) {
222     TCHAR   szMsg[256];
223     HANDLE  hEventSource;
224     LPTSTR  lpszStrings[2];
225
226
227     dwErr = GetLastError();
228
229     // Use event logging to log the error.
230     //
231     hEventSource = RegisterEventSource(NULL, TEXT(SZSERVICENAME));
232
233     printf(lpszMsg);
234
235     _stprintf(szMsg, TEXT("%s error: %d"), TEXT(SZSERVICENAME), dwErr);
236     lpszStrings[0] = szMsg;
237     lpszStrings[1] = lpszMsg;
238
239     if ( hEventSource != NULL ) {
240         ReportEvent(hEventSource, // handle of event source
241                     EVENTLOG_ERROR_TYPE,  // event type
242                     0,                    // event category
243                     0,                    // event ID
244                     NULL,                 // current user's SID
245                     2,                    // strings in lpszStrings
246                     0,                    // no bytes of raw data
247                     lpszStrings,          // array of error strings
248                     NULL);                // no raw data
249
250         (VOID) DeregisterEventSource(hEventSource);
251     }
252 }
253
254
255
256
257 ///////////////////////////////////////////////////////////////////
258 //
259 //  The following code handles service installation and removal
260 //
261 //
262 //  FUNCTION: CmdInstallService()
263 //
264 //  PURPOSE: Installs the service and Starts it
265 //
266 //  PARAMETERS:
267 //    argc: number of arguments
268 //      argv: all of the arguments including the program's name
269 //
270 //  RETURN VALUE:
271 //    none
272 //
273 //  COMMENTS:
274 //
275 void CmdInstallService(int argc, char **argv) {
276     SC_HANDLE   schService;
277     SC_HANDLE   schSCManager;
278
279     TCHAR szPath[512];
280
281     if ( GetModuleFileName( NULL, szPath, 512 ) == 0 ) {
282         _tprintf(TEXT("Unable to install %s - %s\n"), TEXT(SZSERVICEDISPLAYNAME), GetLastErrorText(szErr, 256));
283         return;
284     }
285
286     schSCManager = OpenSCManager(
287                                 NULL,                   // machine (NULL == local)
288                                 NULL,                   // database (NULL == default)
289                                 SC_MANAGER_ALL_ACCESS   // access required
290                                 );
291     if ( schSCManager ) {
292         schService = OpenService(schSCManager, TEXT(SZSERVICENAME), SERVICE_ALL_ACCESS);
293         if ( !schService ) {
294             schService = CreateService(
295                                       schSCManager,               // SCManager database
296                                       TEXT(SZSERVICENAME),        // name of service
297                                       TEXT(SZSERVICEDISPLAYNAME), // name to display
298                                       SERVICE_ALL_ACCESS,         // desired access
299                                       SERVICE_WIN32_OWN_PROCESS,  // service type
300                                       SERVICE_DEMAND_START,       // start type
301                                       SERVICE_ERROR_NORMAL,       // error control type
302                                       szPath,                     // service's binary
303                                       NULL,                       // no load ordering group
304                                       NULL,                       // no tag identifier
305                                       TEXT(SZDEPENDENCIES),       // dependencies
306                                       NULL,                       // LocalSystem account
307                                       NULL);                      // no password
308         } else {
309             _tprintf(TEXT("%s already installed.\n"), TEXT(SZSERVICEDISPLAYNAME) );
310         }
311         if ( schService ) {
312             if ( QueryServiceStatus( schService, &ssStatus ) ) {
313                 int rc;
314                 if ( ssStatus.dwCurrentState == SERVICE_STOPPED ) {
315                     rc = StartService(schService, argc-1, argv+1);
316                 }
317
318
319                 if ( rc != 0 )
320                     _tprintf(TEXT("%s started.\n"), TEXT(SZSERVICEDISPLAYNAME) );
321             }
322
323             CloseServiceHandle(schService);
324         } else {
325             _tprintf(TEXT("CreateService failed - %s\n"), GetLastErrorText(szErr, 256));
326         }
327
328         CloseServiceHandle(schSCManager);
329     } else
330         _tprintf(TEXT("OpenSCManager failed - %s\n"), GetLastErrorText(szErr,256));
331
332
333 }
334
335
336
337 //
338 //  FUNCTION: CmdRemoveService()
339 //
340 //  PURPOSE: Stops and removes the service
341 //
342 //  PARAMETERS:
343 //    none
344 //
345 //  RETURN VALUE:
346 //    TRUE: service exists and is removed
347 //      FALSE: service doesn't exist
348 //
349 //  COMMENTS:
350 //
351 BOOL CmdRemoveService() {
352     BOOL isExist = FALSE;
353     SC_HANDLE   schService;
354     SC_HANDLE   schSCManager;
355
356     schSCManager = OpenSCManager(
357                                 NULL,                   // machine (NULL == local)
358                                 NULL,                   // database (NULL == default)
359                                 SC_MANAGER_ALL_ACCESS   // access required
360                                 );
361     if ( schSCManager ) {
362         schService = OpenService(schSCManager, TEXT(SZSERVICENAME), SERVICE_ALL_ACCESS);
363
364         if ( schService ) {
365             isExist = TRUE;
366             // try to stop the service
367             if ( ControlService( schService, SERVICE_CONTROL_STOP, &ssStatus ) ) {
368                 _tprintf(TEXT("Stopping %s."), TEXT(SZSERVICEDISPLAYNAME));
369                 Sleep( 1000 );
370
371                 while ( QueryServiceStatus( schService, &ssStatus ) ) {
372                     if ( ssStatus.dwCurrentState == SERVICE_STOP_PENDING ) {
373                         _tprintf(TEXT("."));
374                         Sleep( 1000 );
375                     } else
376                         break;
377                 }
378
379                 if ( ssStatus.dwCurrentState == SERVICE_STOPPED )
380                     _tprintf(TEXT("\n%s stopped.\n"), TEXT(SZSERVICEDISPLAYNAME) );
381                 else
382                     _tprintf(TEXT("\n%s failed to stop.\n"), TEXT(SZSERVICEDISPLAYNAME) );
383
384             }
385
386             // now remove the service
387             if ( DeleteService(schService) )
388                 _tprintf(TEXT("%s removed.\n"), TEXT(SZSERVICEDISPLAYNAME) );
389             else
390                 _tprintf(TEXT("DeleteService failed - %s\n"), GetLastErrorText(szErr,256));
391
392
393             CloseServiceHandle(schService);
394         }
395
396         CloseServiceHandle(schSCManager);
397     } else
398         _tprintf(TEXT("OpenSCManager failed - %s\n"), GetLastErrorText(szErr,256));
399
400     return isExist;
401 }
402
403 //
404 //  FUNCTION: CmdStartService()
405 //
406 //  PURPOSE: Start service if it exists
407 //
408 //  PARAMETERS:
409 //    argc: number of arguments
410 //      argv: arguments including program's name
411 //
412 //  RETURN VALUE:
413 //    TRUE: service exists and is started
414 //      FALSE: service doesn't exist
415 //
416 //  COMMENTS:
417 //
418 BOOL CmdStartService(int argc, char **argv) {
419     BOOL isExist = FALSE;
420     SC_HANDLE   schService;
421     SC_HANDLE   schSCManager;
422
423     schSCManager = OpenSCManager(
424                                 NULL,                   // machine (NULL == local)
425                                 NULL,                   // database (NULL == default)
426                                 SC_MANAGER_ALL_ACCESS   // access required
427                                 );
428     if ( schSCManager ) {
429         schService = OpenService(schSCManager, TEXT(SZSERVICENAME), SERVICE_ALL_ACCESS);
430
431         if ( schService ) {
432             isExist = TRUE;
433             if ( QueryServiceStatus( schService, &ssStatus ) ) {
434                 int rc;
435                 if ( ssStatus.dwCurrentState == SERVICE_STOPPED ) {
436                     rc = StartService(schService, argc-1, argv+1);
437                 }
438
439
440                 if ( rc != 0 )
441                     _tprintf(TEXT("%s started.\n"), TEXT(SZSERVICEDISPLAYNAME) );
442             }
443             CloseServiceHandle(schService);            
444         }
445         CloseServiceHandle(schSCManager);
446     } else
447         _tprintf(TEXT("OpenSCManager failed - %s\n"), GetLastErrorText(szErr,256));
448
449     return isExist;
450 }
451
452
453
454
455 //
456 //  FUNCTION: GetLastErrorText
457 //
458 //  PURPOSE: copies error message text to string
459 //
460 //  PARAMETERS:
461 //    lpszBuf - destination buffer
462 //    dwSize - size of buffer
463 //
464 //  RETURN VALUE:
465 //    destination buffer
466 //
467 //  COMMENTS:
468 //
469 LPTSTR GetLastErrorText( LPTSTR lpszBuf, DWORD dwSize ) {
470     DWORD dwRet;
471     LPTSTR lpszTemp = NULL;
472
473     dwRet = FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |FORMAT_MESSAGE_ARGUMENT_ARRAY,
474                            NULL,
475                            GetLastError(),
476                            LANG_NEUTRAL,
477                            (LPTSTR)&lpszTemp,
478                            0,
479                            NULL );
480
481     // supplied buffer is not long enough
482     if ( !dwRet || ( (long)dwSize < (long)dwRet+14 ) )
483         lpszBuf[0] = TEXT('\0');
484     else {
485         lpszTemp[lstrlen(lpszTemp)-2] = TEXT('\0');  //remove cr and newline character
486         _stprintf( lpszBuf, TEXT("%s (0x%x)"), lpszTemp, GetLastError() );
487     }
488
489     if ( lpszTemp )
490         LocalFree((HLOCAL) lpszTemp );
491
492     return lpszBuf;
493 }
494
495 #endif