]> git.saurik.com Git - apple/mdnsresponder.git/blob - mDNSWindows/Applications/SystemService/Service.c
d65fa58184da96517435959c5e4d5c9d408288e6
[apple/mdnsresponder.git] / mDNSWindows / Applications / SystemService / Service.c
1 /*
2 * Copyright (c) 2003-2004 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
7 *
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * file.
14 *
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
22 *
23 * @APPLE_LICENSE_HEADER_END@
24
25 Change History (most recent first):
26
27 $Log: Service.c,v $
28 Revision 1.1 2004/01/30 02:58:39 bradley
29 mDNSResponder Windows Service. Provides global Rendezvous support with an IPC interface.
30
31 */
32
33 #include <stdio.h>
34 #include <stdlib.h>
35
36 #define _WIN32_WINNT 0x0400
37
38 #include "CommonServices.h"
39 #include "DebugServices.h"
40
41 #include "DNSSDDirect.h"
42 #include "RMxServer.h"
43
44 #include "Resource.h"
45
46 #include "mDNSClientAPI.h"
47
48 #if 0
49 #pragma mark == Constants ==
50 #endif
51
52 //===========================================================================================================================
53 // Constants
54 //===========================================================================================================================
55
56 #define DEBUG_NAME "[Server] "
57 #define kServiceName "Rendezvous"
58 #define kServiceDependencies "Tcpip\0winmgmt\0\0"
59
60 #if 0
61 #pragma mark == Prototypes ==
62 #endif
63
64 //===========================================================================================================================
65 // Prototypes
66 //===========================================================================================================================
67
68 int main( int argc, char *argv[] );
69 static void Usage( void );
70 static BOOL WINAPI ConsoleControlHandler( DWORD inControlEvent );
71 static OSStatus InstallService( const char *inName, const char *inDisplayName, const char *inDescription, const char *inPath );
72 static OSStatus RemoveService( const char *inName );
73 static OSStatus SetServiceDescription( SC_HANDLE inSCM, const char *inServiceName, const char *inDescription );
74 static void ReportStatus( int inType, const char *inFormat, ... );
75 static OSStatus RunDirect( int argc, char *argv[] );
76
77 static void WINAPI ServiceMain( DWORD argc, LPSTR argv[] );
78 static OSStatus ServiceSetupEventLogging( void );
79 static void WINAPI ServiceControlHandler( DWORD inControl );
80
81 static OSStatus ServiceRun( int argc, char *argv[] );
82 static void ServiceStop( void );
83
84 static OSStatus ServiceSpecificInitialize( int argc, char *argv[] );
85 static OSStatus ServiceSpecificRun( int argc, char *argv[] );
86 static OSStatus ServiceSpecificStop( void );
87 static void ServiceSpecificFinalize( int argc, char *argv[] );
88
89 #include "mDNSClientAPI.h"
90
91 #if 0
92 #pragma mark == Globals ==
93 #endif
94
95 //===========================================================================================================================
96 // Globals
97 //===========================================================================================================================
98
99 DEBUG_LOCAL BOOL gServiceQuietMode = FALSE;
100 DEBUG_LOCAL SERVICE_TABLE_ENTRY gServiceDispatchTable[] =
101 {
102 { kServiceName, ServiceMain },
103 { NULL, NULL }
104 };
105 DEBUG_LOCAL SERVICE_STATUS gServiceStatus;
106 DEBUG_LOCAL SERVICE_STATUS_HANDLE gServiceStatusHandle = NULL;
107 DEBUG_LOCAL HANDLE gServiceEventSource = NULL;
108 DEBUG_LOCAL bool gServiceAllowRemote = false;
109 DEBUG_LOCAL int gServiceCacheEntryCount = 0; // 0 means to use the DNS-SD default.
110
111 #if 0
112 #pragma mark -
113 #endif
114
115 //===========================================================================================================================
116 // main
117 //===========================================================================================================================
118
119 int main( int argc, char *argv[] )
120 {
121 OSStatus err;
122 BOOL ok;
123 BOOL start;
124 int i;
125
126 debug_initialize( kDebugOutputTypeMetaConsole );
127 debug_set_property( kDebugPropertyTagPrintLevel, kDebugLevelVerbose );
128
129 // Install a Console Control Handler to handle things like control-c signals.
130
131 ok = SetConsoleCtrlHandler( ConsoleControlHandler, TRUE );
132 err = translate_errno( ok, (OSStatus) GetLastError(), kUnknownErr );
133 require_noerr( err, exit );
134
135 // Default to automatically starting the service dispatcher if no extra arguments are specified.
136
137 start = ( argc <= 1 );
138
139 // Parse arguments.
140
141 for( i = 1; i < argc; ++i )
142 {
143 if( strcmp( argv[ i ], "-install" ) == 0 ) // Install
144 {
145 char desc[ 256 ];
146
147 desc[ 0 ] = 0;
148 LoadStringA( GetModuleHandle( NULL ), IDS_SERVICE_DESCRIPTION, desc, sizeof( desc ) );
149 err = InstallService( kServiceName, kServiceName, desc, argv[ 0 ] );
150 if( err )
151 {
152 ReportStatus( EVENTLOG_ERROR_TYPE, "install service failed (%d)\n", err );
153 goto exit;
154 }
155 }
156 else if( strcmp( argv[ i ], "-remove" ) == 0 ) // Remove
157 {
158 err = RemoveService( kServiceName );
159 if( err )
160 {
161 ReportStatus( EVENTLOG_ERROR_TYPE, "remove service failed (%d)\n", err );
162 goto exit;
163 }
164 }
165 else if( strcmp( argv[ i ], "-start" ) == 0 ) // Start
166 {
167 start = TRUE;
168 }
169 else if( strcmp( argv[ i ], "-server" ) == 0 ) // Server
170 {
171 err = RunDirect( argc, argv );
172 if( err )
173 {
174 ReportStatus( EVENTLOG_ERROR_TYPE, "run service directly failed (%d)\n", err );
175 }
176 goto exit;
177 }
178 else if( strcmp( argv[ i ], "-q" ) == 0 ) // Quiet Mode (toggle)
179 {
180 gServiceQuietMode = !gServiceQuietMode;
181 }
182 else if( strcmp( argv[ i ], "-remote" ) == 0 ) // Allow Remote Connections
183 {
184 gServiceAllowRemote = true;
185 }
186 else if( strcmp( argv[ i ], "-cache" ) == 0 ) // Number of mDNS cache entries
187 {
188 if( i <= argc )
189 {
190 ReportStatus( EVENTLOG_ERROR_TYPE, "-cache used, but number of cache entries not specified\n" );
191 err = kParamErr;
192 goto exit;
193 }
194 gServiceCacheEntryCount = atoi( argv[ ++i ] );
195 }
196 else if( ( strcmp( argv[ i ], "-help" ) == 0 ) || // Help
197 ( strcmp( argv[ i ], "-h" ) == 0 ) )
198 {
199 Usage();
200 err = 0;
201 break;
202 }
203 else
204 {
205 Usage();
206 err = kParamErr;
207 break;
208 }
209 }
210
211 // Start the service dispatcher if requested. This does not return until all services have terminated. If any
212 // global initialization is needed, it should be done before starting the service dispatcher, but only if it
213 // will take less than 30 seconds. Otherwise, use a separate thread for it and start the dispatcher immediately.
214
215 if( start )
216 {
217 ok = StartServiceCtrlDispatcher( gServiceDispatchTable );
218 err = translate_errno( ok, (OSStatus) GetLastError(), kInUseErr );
219 if( err != kNoErr )
220 {
221 ReportStatus( EVENTLOG_ERROR_TYPE, "start service dispatcher failed (%d)\n", err );
222 goto exit;
223 }
224 }
225 err = 0;
226
227 exit:
228 dlog( kDebugLevelTrace, DEBUG_NAME "exited (%d %m)\n", err, err );
229 return( (int) err );
230 }
231
232 //===========================================================================================================================
233 // Usage
234 //===========================================================================================================================
235
236 static void Usage( void )
237 {
238 fprintf( stderr, "\n" );
239 fprintf( stderr, "mDNSResponder 1.0d1\n" );
240 fprintf( stderr, "\n" );
241 fprintf( stderr, " <no args> Runs the service normally\n" );
242 fprintf( stderr, " -install Creates the service and starts it\n" );
243 fprintf( stderr, " -remove Stops the service and deletes it\n" );
244 fprintf( stderr, " -start Starts the service dispatcher after processing all other arguments\n" );
245 fprintf( stderr, " -server Runs the service directly as a server (for debugging)\n" );
246 fprintf( stderr, " -q Toggles Quiet Mode (no events or output)\n" );
247 fprintf( stderr, " -remote Allow remote connections\n" );
248 fprintf( stderr, " -cache n Number of mDNS cache entries (defaults to %d)\n", kDNSServiceCacheEntryCountDefault );
249 fprintf( stderr, " -h[elp] Display Help/Usage\n" );
250 fprintf( stderr, "\n" );
251 }
252
253 //===========================================================================================================================
254 // ConsoleControlHandler
255 //===========================================================================================================================
256
257 static BOOL WINAPI ConsoleControlHandler( DWORD inControlEvent )
258 {
259 BOOL handled;
260 OSStatus err;
261
262 handled = FALSE;
263 switch( inControlEvent )
264 {
265 case CTRL_C_EVENT:
266 case CTRL_BREAK_EVENT:
267 case CTRL_CLOSE_EVENT:
268 case CTRL_LOGOFF_EVENT:
269 case CTRL_SHUTDOWN_EVENT:
270 err = ServiceSpecificStop();
271 require_noerr( err, exit );
272
273 handled = TRUE;
274 break;
275
276 default:
277 break;
278 }
279
280 exit:
281 return( handled );
282 }
283
284 //===========================================================================================================================
285 // InstallService
286 //===========================================================================================================================
287
288 static OSStatus InstallService( const char *inName, const char *inDisplayName, const char *inDescription, const char *inPath )
289 {
290 OSStatus err;
291 SC_HANDLE scm;
292 SC_HANDLE service;
293 BOOL ok;
294 TCHAR fullPath[ MAX_PATH ];
295 TCHAR * namePtr;
296 DWORD size;
297
298 scm = NULL;
299 service = NULL;
300
301 // Get a full path to the executable since a relative path may have been specified.
302
303 size = GetFullPathName( inPath, sizeof( fullPath ), fullPath, &namePtr );
304 err = translate_errno( size > 0, (OSStatus) GetLastError(), kPathErr );
305 require_noerr( err, exit );
306
307 // Create the service and start it.
308
309 scm = OpenSCManager( NULL, NULL, SC_MANAGER_ALL_ACCESS );
310 err = translate_errno( scm, (OSStatus) GetLastError(), kOpenErr );
311 require_noerr( err, exit );
312
313 service = CreateService( scm, inName, inDisplayName, SERVICE_ALL_ACCESS, SERVICE_WIN32_SHARE_PROCESS,
314 SERVICE_AUTO_START, SERVICE_ERROR_NORMAL, inPath, NULL, NULL, kServiceDependencies,
315 NULL, NULL );
316 err = translate_errno( service, (OSStatus) GetLastError(), kDuplicateErr );
317 require_noerr( err, exit );
318
319 if( inDescription )
320 {
321 err = SetServiceDescription( scm, inName, inDescription );
322 check_noerr( err );
323 }
324
325 ok = StartService( service, 0, NULL );
326 err = translate_errno( ok, (OSStatus) GetLastError(), kInUseErr );
327 require_noerr( err, exit );
328
329 ReportStatus( EVENTLOG_SUCCESS, "installed service \"%s\"/\"%s\" at \"%s\"\n", inName, inDisplayName, inPath );
330 err = kNoErr;
331
332 exit:
333 if( service )
334 {
335 CloseServiceHandle( service );
336 }
337 if( scm )
338 {
339 CloseServiceHandle( scm );
340 }
341 return( err );
342 }
343
344 //===========================================================================================================================
345 // RemoveService
346 //===========================================================================================================================
347
348 static OSStatus RemoveService( const char *inName )
349 {
350 OSStatus err;
351 SC_HANDLE scm;
352 SC_HANDLE service;
353 BOOL ok;
354 SERVICE_STATUS status;
355
356 scm = NULL;
357 service = NULL;
358
359 // Open a connection to the service.
360
361 scm = OpenSCManager( 0, 0, SC_MANAGER_ALL_ACCESS );
362 err = translate_errno( scm, (OSStatus) GetLastError(), kOpenErr );
363 require_noerr( err, exit );
364
365 service = OpenService( scm, inName, SERVICE_STOP | SERVICE_QUERY_STATUS | DELETE );
366 err = translate_errno( service, (OSStatus) GetLastError(), kNotFoundErr );
367 require_noerr( err, exit );
368
369 // Stop the service, if it is not already stopped, then delete it.
370
371 ok = QueryServiceStatus( service, &status );
372 err = translate_errno( ok, (OSStatus) GetLastError(), kAuthenticationErr );
373 require_noerr( err, exit );
374
375 if( status.dwCurrentState != SERVICE_STOPPED )
376 {
377 ok = ControlService( service, SERVICE_CONTROL_STOP, &status );
378 check_translated_errno( ok, (OSStatus) GetLastError(), kAuthenticationErr );
379 }
380
381 ok = DeleteService( service );
382 err = translate_errno( ok, (OSStatus) GetLastError(), kDeletedErr );
383 require_noerr( err, exit );
384
385 ReportStatus( EVENTLOG_SUCCESS, "Removed service \"%s\"\n", inName );
386 err = ERROR_SUCCESS;
387
388 exit:
389 if( service )
390 {
391 CloseServiceHandle( service );
392 }
393 if( scm )
394 {
395 CloseServiceHandle( scm );
396 }
397 return( err );
398 }
399
400 //===========================================================================================================================
401 // SetServiceDescription
402 //===========================================================================================================================
403
404 static OSStatus SetServiceDescription( SC_HANDLE inSCM, const char *inServiceName, const char *inDescription )
405 {
406 OSStatus err;
407 SC_LOCK lock;
408 SC_HANDLE service;
409 SERVICE_DESCRIPTION description;
410 BOOL ok;
411
412 check( inServiceName );
413 check( inDescription );
414
415 lock = NULL;
416 service = NULL;
417
418 // Open the database (if not provided) and lock it to prevent other access while re-configuring.
419
420 if( !inSCM )
421 {
422 inSCM = OpenSCManager( NULL, NULL, SC_MANAGER_ALL_ACCESS );
423 err = translate_errno( inSCM, (OSStatus) GetLastError(), kOpenErr );
424 require_noerr( err, exit );
425 }
426
427 lock = LockServiceDatabase( inSCM );
428 err = translate_errno( lock, (OSStatus) GetLastError(), kInUseErr );
429 require_noerr( err, exit );
430
431 // Open a handle to the service.
432
433 service = OpenService( inSCM, inServiceName, SERVICE_CHANGE_CONFIG );
434 err = translate_errno( service, (OSStatus) GetLastError(), kNotFoundErr );
435 require_noerr( err, exit );
436
437 // Change the description.
438
439 description.lpDescription = (char *) inDescription;
440 ok = ChangeServiceConfig2( service, SERVICE_CONFIG_DESCRIPTION, &description );
441 err = translate_errno( ok, (OSStatus) GetLastError(), kParamErr );
442 require_noerr( err, exit );
443
444 err = ERROR_SUCCESS;
445
446 exit:
447 // Close the service and release the lock.
448
449 if( service )
450 {
451 CloseServiceHandle( service );
452 }
453 if( lock )
454 {
455 UnlockServiceDatabase( lock );
456 }
457 return( err );
458 }
459
460 //===========================================================================================================================
461 // ReportStatus
462 //===========================================================================================================================
463
464 static void ReportStatus( int inType, const char *inFormat, ... )
465 {
466 if( !gServiceQuietMode )
467 {
468 va_list args;
469
470 va_start( args, inFormat );
471 if( gServiceEventSource )
472 {
473 char s[ 1024 ];
474 BOOL ok;
475 const char * array[ 1 ];
476
477 vsprintf( s, inFormat, args );
478 array[ 0 ] = s;
479 ok = ReportEvent( gServiceEventSource, (WORD) inType, 0, 0x20000001L, NULL, 1, 0, array, NULL );
480 check_translated_errno( ok, GetLastError(), kUnknownErr );
481 }
482 else
483 {
484 int n;
485
486 n = vfprintf( stderr, inFormat, args );
487 check( n >= 0 );
488 }
489 va_end( args );
490 }
491 }
492
493 //===========================================================================================================================
494 // RunDirect
495 //===========================================================================================================================
496
497 static OSStatus RunDirect( int argc, char *argv[] )
498 {
499 OSStatus err;
500 BOOL initialized;
501
502 initialized = FALSE;
503
504 err = ServiceSpecificInitialize( argc, argv );
505 require_noerr( err, exit );
506 initialized = TRUE;
507
508 // Run the service. This does not return until the service quits or is stopped.
509
510 ReportStatus( EVENTLOG_SUCCESS, "Running \"%s\" service directly\n", kServiceName );
511
512 err = ServiceSpecificRun( argc, argv );
513 require_noerr( err, exit );
514
515 // Clean up.
516
517 exit:
518 if( initialized )
519 {
520 ServiceSpecificFinalize( argc, argv );
521 }
522 return( err );
523 }
524
525 #if 0
526 #pragma mark -
527 #endif
528
529 //===========================================================================================================================
530 // ServiceMain
531 //===========================================================================================================================
532
533 static void WINAPI ServiceMain( DWORD argc, LPSTR argv[] )
534 {
535 OSStatus err;
536 BOOL ok;
537 char desc[ 256 ];
538
539 err = ServiceSetupEventLogging();
540 require_noerr( err, exit );
541
542 // Initialize the service status and register the service control handler with the name of the service.
543
544 gServiceStatus.dwServiceType = SERVICE_WIN32_SHARE_PROCESS;
545 gServiceStatus.dwCurrentState = 0;
546 gServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP;
547 gServiceStatus.dwWin32ExitCode = NO_ERROR;
548 gServiceStatus.dwServiceSpecificExitCode = NO_ERROR;
549 gServiceStatus.dwCheckPoint = 0;
550 gServiceStatus.dwWaitHint = 0;
551
552 gServiceStatusHandle = RegisterServiceCtrlHandler( argv[ 0 ], ServiceControlHandler );
553 err = translate_errno( gServiceStatusHandle, (OSStatus) GetLastError(), kInUseErr );
554 require_noerr( err, exit );
555
556 // Setup the description. This should be done by the installer, but it doesn't support that yet.
557
558 desc[ 0 ] = '\0';
559 LoadStringA( GetModuleHandle( NULL ), IDS_SERVICE_DESCRIPTION, desc, sizeof( desc ) );
560 err = SetServiceDescription( NULL, kServiceName, desc );
561 check_noerr( err );
562
563 // Mark the service as starting.
564
565 gServiceStatus.dwCurrentState = SERVICE_START_PENDING;
566 gServiceStatus.dwCheckPoint = 0;
567 gServiceStatus.dwWaitHint = 5000; // 5 seconds
568 ok = SetServiceStatus( gServiceStatusHandle, &gServiceStatus );
569 check_translated_errno( ok, GetLastError(), kParamErr );
570
571 // Run the service. This does not return until the service quits or is stopped.
572
573 err = ServiceRun( (int) argc, argv );
574 if( err != kNoErr )
575 {
576 gServiceStatus.dwWin32ExitCode = ERROR_SERVICE_SPECIFIC_ERROR;
577 gServiceStatus.dwServiceSpecificExitCode = (DWORD) err;
578 }
579
580 // Service-specific work is done so mark the service as stopped.
581
582 gServiceStatus.dwCurrentState = SERVICE_STOPPED;
583 ok = SetServiceStatus( gServiceStatusHandle, &gServiceStatus );
584 check_translated_errno( ok, GetLastError(), kParamErr );
585
586 // Note: The service status handle should not be closed according to Microsoft documentation.
587
588 exit:
589 if( gServiceEventSource )
590 {
591 ok = DeregisterEventSource( gServiceEventSource );
592 check_translated_errno( ok, GetLastError(), kUnknownErr );
593 gServiceEventSource = NULL;
594 }
595 }
596
597 //===========================================================================================================================
598 // ServiceSetupEventLogging
599 //===========================================================================================================================
600
601 static OSStatus ServiceSetupEventLogging( void )
602 {
603 OSStatus err;
604 HKEY key;
605 const char * s;
606 DWORD typesSupported;
607 char path[ MAX_PATH ];
608 DWORD n;
609
610 key = NULL;
611
612 // Add/Open source name as a sub-key under the Application key in the EventLog registry key.
613
614 s = "SYSTEM\\CurrentControlSet\\Services\\EventLog\\Application\\" kServiceName;
615 err = RegCreateKey( HKEY_LOCAL_MACHINE, s, &key );
616 require_noerr( err, exit );
617
618 // Add the name to the EventMessageFile subkey.
619
620 path[ 0 ] = '\0';
621 GetModuleFileName( NULL, path, MAX_PATH );
622 n = (DWORD)( strlen( path ) + 1 );
623 err = RegSetValueEx( key, "EventMessageFile", 0, REG_EXPAND_SZ, (const LPBYTE) path, n );
624 require_noerr( err, exit );
625
626 // Set the supported event types in the TypesSupported subkey.
627
628 typesSupported = 0
629 | EVENTLOG_SUCCESS
630 | EVENTLOG_ERROR_TYPE
631 | EVENTLOG_WARNING_TYPE
632 | EVENTLOG_INFORMATION_TYPE
633 | EVENTLOG_AUDIT_SUCCESS
634 | EVENTLOG_AUDIT_FAILURE;
635 err = RegSetValueEx( key, "TypesSupported", 0, REG_DWORD, (const LPBYTE) &typesSupported, sizeof( DWORD ) );
636 require_noerr( err, exit );
637
638 // Set up the event source.
639
640 gServiceEventSource = RegisterEventSource( NULL, kServiceName );
641 err = translate_errno( gServiceEventSource, (OSStatus) GetLastError(), kParamErr );
642 require_noerr( err, exit );
643
644 exit:
645 if( key )
646 {
647 RegCloseKey( key );
648 }
649 return( err );
650 }
651
652 //===========================================================================================================================
653 // ServiceControlHandler
654 //===========================================================================================================================
655
656 static void WINAPI ServiceControlHandler( DWORD inControl )
657 {
658 BOOL setStatus;
659 BOOL ok;
660
661 setStatus = TRUE;
662 switch( inControl )
663 {
664 case SERVICE_CONTROL_STOP:
665 dlog( kDebugLevelNotice, DEBUG_NAME "ServiceControlHandler: SERVICE_CONTROL_STOP\n" );
666
667 ServiceStop();
668 setStatus = FALSE;
669 break;
670
671 default:
672 dlog( kDebugLevelNotice, DEBUG_NAME "ServiceControlHandler: event (0x%08X)\n", inControl );
673 break;
674 }
675
676 if( setStatus && gServiceStatusHandle )
677 {
678 ok = SetServiceStatus( gServiceStatusHandle, &gServiceStatus );
679 check_translated_errno( ok, GetLastError(), kUnknownErr );
680 }
681 }
682
683 //===========================================================================================================================
684 // ServiceRun
685 //===========================================================================================================================
686
687 static OSStatus ServiceRun( int argc, char *argv[] )
688 {
689 OSStatus err;
690 BOOL initialized;
691 BOOL ok;
692
693 DEBUG_UNUSED( argc );
694 DEBUG_UNUSED( argv );
695
696 initialized = FALSE;
697
698 // Initialize the service-specific stuff and mark the service as running.
699
700 err = ServiceSpecificInitialize( argc, argv );
701 require_noerr( err, exit );
702 initialized = TRUE;
703
704 gServiceStatus.dwCurrentState = SERVICE_RUNNING;
705 ok = SetServiceStatus( gServiceStatusHandle, &gServiceStatus );
706 check_translated_errno( ok, GetLastError(), kParamErr );
707
708 // Run the service-specific stuff. This does not return until the service quits or is stopped.
709
710 ReportStatus( EVENTLOG_INFORMATION_TYPE, "mDNSResponder started\n" );
711 err = ServiceSpecificRun( argc, argv );
712 ReportStatus( EVENTLOG_INFORMATION_TYPE, "mDNSResponder stopped (%d)\n", err );
713 require_noerr( err, exit );
714
715 // Service stopped. Clean up and we're done.
716
717 exit:
718 if( initialized )
719 {
720 ServiceSpecificFinalize( argc, argv );
721 }
722 return( err );
723 }
724
725 //===========================================================================================================================
726 // ServiceStop
727 //===========================================================================================================================
728
729 static void ServiceStop( void )
730 {
731 BOOL ok;
732 OSStatus err;
733
734 // Signal the event to cause the service to exit.
735
736 if( gServiceStatusHandle )
737 {
738 gServiceStatus.dwCurrentState = SERVICE_STOP_PENDING;
739 ok = SetServiceStatus( gServiceStatusHandle, &gServiceStatus );
740 check_translated_errno( ok, GetLastError(), kParamErr );
741 }
742
743 err = ServiceSpecificStop();
744 check_noerr( err );
745 }
746
747 #if 0
748 #pragma mark -
749 #pragma mark == Service Specific ==
750 #endif
751
752 //===========================================================================================================================
753 // ServiceSpecificInitialize
754 //===========================================================================================================================
755
756 static OSStatus ServiceSpecificInitialize( int argc, char *argv[] )
757 {
758 OSStatus err;
759 DNSServiceInitializeFlags initFlags;
760 RMxServerFlags flags;
761
762 DEBUG_UNUSED( argc );
763 DEBUG_UNUSED( argv );
764
765 initFlags = kDNSServiceInitializeFlagsAdvertise | kDNSServiceInitializeFlagsNoServerCheck;
766 err = DNSServiceInitialize_direct( initFlags, gServiceCacheEntryCount );
767 require_noerr( err, exit );
768
769 flags = 0;
770 if( gServiceAllowRemote )
771 {
772 flags |= kRMxServerFlagsAllowRemote;
773 }
774 err = RMxServerInitialize( flags );
775 require_noerr( err, exit );
776
777 exit:
778 if( err != kNoErr )
779 {
780 ServiceSpecificFinalize( argc, argv );
781 }
782 return( err );
783 }
784
785 //===========================================================================================================================
786 // ServiceSpecificRun
787 //===========================================================================================================================
788
789 static OSStatus ServiceSpecificRun( int argc, char *argv[] )
790 {
791 OSStatus err;
792
793 DEBUG_UNUSED( argc );
794 DEBUG_UNUSED( argv );
795
796 err = RMxServerRun();
797 require_noerr( err, exit );
798
799 exit:
800 return( err );
801 }
802
803 //===========================================================================================================================
804 // ServiceSpecificStop
805 //===========================================================================================================================
806
807 static OSStatus ServiceSpecificStop( void )
808 {
809 OSStatus err;
810
811 err = RMxServerStop( kRMxServerStopFlagsNoWait );
812 require_noerr( err, exit );
813
814 exit:
815 return( err );
816 }
817
818 //===========================================================================================================================
819 // ServiceSpecificFinalize
820 //===========================================================================================================================
821
822 static void ServiceSpecificFinalize( int argc, char *argv[] )
823 {
824 DEBUG_UNUSED( argc );
825 DEBUG_UNUSED( argv );
826
827 RMxServerFinalize();
828 DNSServiceFinalize_direct();
829 }