1 /* -*- Mode: C; tab-width: 4 -*-
3 * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
5 * @APPLE_LICENSE_HEADER_START@
7 * This file contains Original Code and/or Modifications of Original Code
8 * as defined in and that are subject to the Apple Public Source License
9 * Version 2.0 (the 'License'). You may not use this file except in
10 * compliance with the License. Please obtain a copy of the License at
11 * http://www.opensource.apple.com/apsl/ and read it before using this
14 * The Original Code and all software distributed under the License are
15 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
19 * Please see the License for the specific language governing rights and
20 * limitations under the License.
22 * @APPLE_LICENSE_HEADER_END@
24 Change History (most recent first):
27 Revision 1.29 2005/03/04 21:35:33 cheshire
28 <rdar://problem/4037201> Services.txt file not parsed properly when it contains more than one service
30 Revision 1.28 2005/01/11 01:55:26 ksekar
31 Fix compile errors in Posix debug build
33 Revision 1.27 2004/12/01 04:28:43 cheshire
34 <rdar://problem/3872803> Darwin patches for Solaris and Suse
35 Use version of daemon() provided in mDNSUNP.c instead of local copy
37 Revision 1.26 2004/11/30 22:37:01 cheshire
38 Update copyright dates and add "Mode: C; tab-width: 4" headers
40 Revision 1.25 2004/11/11 02:00:51 cheshire
41 Minor fixes to getopt, error message
43 Revision 1.24 2004/11/09 19:32:10 rpantos
44 Suggestion from Ademar de Souza Reis Jr. to allow comments in services file
46 Revision 1.23 2004/09/17 01:08:54 cheshire
47 Renamed mDNSClientAPI.h to mDNSEmbeddedAPI.h
48 The name "mDNSClientAPI.h" is misleading to new developers looking at this code. The interfaces
49 declared in that file are ONLY appropriate to single-address-space embedded applications.
50 For clients on general-purpose computers, the interfaces defined in dns_sd.h should be used.
52 Revision 1.22 2004/09/16 01:58:22 cheshire
55 Revision 1.21 2004/06/15 03:48:07 cheshire
56 Update mDNSResponderPosix to take multiple name=val arguments in a sane way
58 Revision 1.20 2004/05/18 23:51:26 cheshire
59 Tidy up all checkin comments to use consistent "<rdar://problem/xxxxxxx>" format for bug numbers
61 Revision 1.19 2004/03/12 08:03:14 cheshire
64 Revision 1.18 2004/01/25 00:00:55 cheshire
65 Change to use mDNSOpaque16fromIntVal() instead of shifting and masking
67 Revision 1.17 2003/12/11 19:11:55 cheshire
70 Revision 1.16 2003/08/14 02:19:55 cheshire
71 <rdar://problem/3375491> Split generic ResourceRecord type into two separate types: AuthRecord and CacheRecord
73 Revision 1.15 2003/08/12 19:56:26 cheshire
76 Revision 1.14 2003/08/06 18:20:51 cheshire
79 Revision 1.13 2003/07/23 00:00:04 cheshire
82 Revision 1.12 2003/07/15 01:55:16 cheshire
83 <rdar://problem/3315777> Need to implement service registration with subtypes
85 Revision 1.11 2003/07/14 18:11:54 cheshire
86 Fix stricter compiler warnings
88 Revision 1.10 2003/07/10 20:27:31 cheshire
89 <rdar://problem/3318717> mDNSResponder Posix version is missing a 'b' in the getopt option string
91 Revision 1.9 2003/07/02 21:19:59 cheshire
92 <rdar://problem/3313413> Update copyright notices, etc., in source code comments
94 Revision 1.8 2003/06/18 05:48:41 cheshire
97 Revision 1.7 2003/05/06 00:00:50 cheshire
98 <rdar://problem/3248914> Rationalize naming of domainname manipulation functions
100 Revision 1.6 2003/03/08 00:35:56 cheshire
101 Switched to using new "mDNS_Execute" model (see "mDNSCore/Implementer Notes.txt")
103 Revision 1.5 2003/02/20 06:48:36 cheshire
104 <rdar://problem/3169535> Xserve RAID needs to do interface-specific registrations
105 Reviewed by: Josh Graessley, Bob Bradley
107 Revision 1.4 2003/01/28 03:07:46 cheshire
108 Add extra parameter to mDNS_RenameAndReregisterService(),
109 and add support for specifying a domain other than dot-local.
111 Revision 1.3 2002/09/21 20:44:53 zarzycki
114 Revision 1.2 2002/09/19 04:20:44 cheshire
115 Remove high-ascii characters that confuse some systems
117 Revision 1.1 2002/09/17 06:24:35 cheshire
122 #include "mDNSEmbeddedAPI.h"// Defines the interface to the client layer above
123 #include "mDNSPosix.h" // Defines the specific types needed to run mDNS on this platform
126 #include <stdio.h> // For printf()
127 #include <stdlib.h> // For exit() etc.
128 #include <string.h> // For strlen() etc.
129 #include <unistd.h> // For select()
130 #include <errno.h> // For errno, EINTR
134 #if COMPILER_LIKES_PRAGMA_MARK
135 #pragma mark ***** Globals
138 static mDNS mDNSStorage
; // mDNS core uses this to store its globals
139 static mDNS_PlatformSupport PlatformStorage
; // Stores this platform's globals
141 static const char *gProgramName
= "mDNSResponderPosix";
143 #if COMPILER_LIKES_PRAGMA_MARK
144 #pragma mark ***** Signals
147 static volatile mDNSBool gReceivedSigUsr1
;
148 static volatile mDNSBool gReceivedSigHup
;
149 static volatile mDNSBool gStopNow
;
151 // We support 4 signals.
153 // o SIGUSR1 toggles verbose mode on and off in debug builds
154 // o SIGHUP triggers the program to re-read its preferences.
155 // o SIGINT causes an orderly shutdown of the program.
156 // o SIGQUIT causes a somewhat orderly shutdown (direct but dangerous)
157 // o SIGKILL kills us dead (easy to implement :-)
159 // There are fatal race conditions in our signal handling, but there's not much
160 // we can do about them while remaining within the Posix space. Specifically,
161 // if a signal arrives after we test the globals its sets but before we call
162 // select, the signal will be dropped. The user will have to send the signal
163 // again. Unfortunately, Posix does not have a "sigselect" to atomically
164 // modify the signal mask and start a select.
166 static void HandleSigUsr1(int sigraised
)
167 // If we get a SIGUSR1 we toggle the state of the
170 assert(sigraised
== SIGUSR1
);
171 gReceivedSigUsr1
= mDNStrue
;
174 static void HandleSigHup(int sigraised
)
175 // A handler for SIGHUP that causes us to break out of the
176 // main event loop when the user kill 1's us. This has the
177 // effect of triggered the main loop to deregister the
178 // current services and re-read the preferences.
180 assert(sigraised
== SIGHUP
);
181 gReceivedSigHup
= mDNStrue
;
184 static void HandleSigInt(int sigraised
)
185 // A handler for SIGINT that causes us to break out of the
186 // main event loop when the user types ^C. This has the
187 // effect of quitting the program.
189 assert(sigraised
== SIGINT
);
191 if (gMDNSPlatformPosixVerboseLevel
> 0) {
192 fprintf(stderr
, "\nSIGINT\n");
197 static void HandleSigQuit(int sigraised
)
198 // If we get a SIGQUIT the user is desperate and we
199 // just call mDNS_Close directly. This is definitely
200 // not safe (because it could reenter mDNS), but
201 // we presume that the user has already tried the safe
204 assert(sigraised
== SIGQUIT
);
206 if (gMDNSPlatformPosixVerboseLevel
> 0) {
207 fprintf(stderr
, "\nSIGQUIT\n");
209 mDNS_Close(&mDNSStorage
);
213 #if COMPILER_LIKES_PRAGMA_MARK
214 #pragma mark ***** Parameter Checking
217 static mDNSBool
CheckThatRichTextNameIsUsable(const char *richTextName
, mDNSBool printExplanation
)
218 // Checks that richTextName is reasonable
219 // label and, if it isn't and printExplanation is true, prints
220 // an explanation of why not.
222 mDNSBool result
= mDNStrue
;
223 if (result
&& strlen(richTextName
) > 63) {
224 if (printExplanation
) {
226 "%s: Service name is too long (must be 63 characters or less)\n",
231 if (result
&& richTextName
[0] == 0) {
232 if (printExplanation
) {
233 fprintf(stderr
, "%s: Service name can't be empty\n", gProgramName
);
240 static mDNSBool
CheckThatServiceTypeIsUsable(const char *serviceType
, mDNSBool printExplanation
)
241 // Checks that serviceType is a reasonable service type
242 // label and, if it isn't and printExplanation is true, prints
243 // an explanation of why not.
248 if (result
&& strlen(serviceType
) > 63) {
249 if (printExplanation
) {
251 "%s: Service type is too long (must be 63 characters or less)\n",
256 if (result
&& serviceType
[0] == 0) {
257 if (printExplanation
) {
259 "%s: Service type can't be empty\n",
267 static mDNSBool
CheckThatPortNumberIsUsable(long portNumber
, mDNSBool printExplanation
)
268 // Checks that portNumber is a reasonable port number
269 // and, if it isn't and printExplanation is true, prints
270 // an explanation of why not.
275 if (result
&& (portNumber
<= 0 || portNumber
> 65535)) {
276 if (printExplanation
) {
278 "%s: Port number specified by -p must be in range 1..65535\n",
286 #if COMPILER_LIKES_PRAGMA_MARK
287 #pragma mark ***** Command Line Arguments
290 static const char kDefaultPIDFile
[] = "/var/run/mDNSResponder.pid";
291 static const char kDefaultServiceType
[] = "_afpovertcp._tcp.";
292 static const char kDefaultServiceDomain
[] = "local.";
294 kDefaultPortNumber
= 548
297 static void PrintUsage()
300 "Usage: %s [-v level ] [-r] [-n name] [-t type] [-d domain] [-p port] [-f file] [-b] [-P pidfile] [-x name=val ...]\n",
302 fprintf(stderr
, " -v verbose mode, level is a number from 0 to 2\n");
303 fprintf(stderr
, " 0 = no debugging info (default)\n");
304 fprintf(stderr
, " 1 = standard debugging info\n");
305 fprintf(stderr
, " 2 = intense debugging info\n");
306 fprintf(stderr
, " can be cycled kill -USR1\n");
307 fprintf(stderr
, " -r also bind to port 53 (port 5353 is always bound)\n");
308 fprintf(stderr
, " -n uses 'name' as the service name (required)\n");
309 fprintf(stderr
, " -t uses 'type' as the service type (default is '%s')\n", kDefaultServiceType
);
310 fprintf(stderr
, " -d uses 'domain' as the service domain (default is '%s')\n", kDefaultServiceDomain
);
311 fprintf(stderr
, " -p uses 'port' as the port number (default is '%d')\n", kDefaultPortNumber
);
312 fprintf(stderr
, " -f reads a service list from 'file'\n");
313 fprintf(stderr
, " -b forces daemon (background) mode\n");
314 fprintf(stderr
, " -P uses 'pidfile' as the PID file\n");
315 fprintf(stderr
, " (default is '%s')\n", kDefaultPIDFile
);
316 fprintf(stderr
, " only meaningful if -b also specified\n");
317 fprintf(stderr
, " -x stores name=val in TXT record (default is empty).\n");
318 fprintf(stderr
, " MUST be the last command-line argument;\n");
319 fprintf(stderr
, " all subsequent arguments after -x are treated as name=val pairs.\n");
322 static mDNSBool gAvoidPort53
= mDNStrue
;
323 static const char *gServiceName
= "";
324 static const char *gServiceType
= kDefaultServiceType
;
325 static const char *gServiceDomain
= kDefaultServiceDomain
;
326 static mDNSu8 gServiceText
[sizeof(RDataBody
)];
327 static mDNSu16 gServiceTextLen
= 0;
328 static int gPortNumber
= kDefaultPortNumber
;
329 static const char *gServiceFile
= "";
330 static mDNSBool gDaemon
= mDNSfalse
;
331 static const char *gPIDFile
= kDefaultPIDFile
;
333 static void ParseArguments(int argc
, char **argv
)
334 // Parses our command line arguments into the global variables
339 // Set gProgramName to the last path component of argv[0]
341 gProgramName
= strrchr(argv
[0], '/');
342 if (gProgramName
== NULL
) {
343 gProgramName
= argv
[0];
348 // Parse command line options using getopt.
351 ch
= getopt(argc
, argv
, "v:rn:t:d:p:f:dP:bx");
355 gMDNSPlatformPosixVerboseLevel
= atoi(optarg
);
356 if (gMDNSPlatformPosixVerboseLevel
< 0 || gMDNSPlatformPosixVerboseLevel
> 2) {
358 "%s: Verbose mode must be in the range 0..2\n",
364 gAvoidPort53
= mDNSfalse
;
367 gServiceName
= optarg
;
368 if ( ! CheckThatRichTextNameIsUsable(gServiceName
, mDNStrue
) ) {
373 gServiceType
= optarg
;
374 if ( ! CheckThatServiceTypeIsUsable(gServiceType
, mDNStrue
) ) {
379 gServiceDomain
= optarg
;
382 gPortNumber
= atol(optarg
);
383 if ( ! CheckThatPortNumberIsUsable(gPortNumber
, mDNStrue
) ) {
388 gServiceFile
= optarg
;
397 while (optind
< argc
)
399 gServiceText
[gServiceTextLen
] = strlen(argv
[optind
]);
400 memcpy(gServiceText
+gServiceTextLen
+1, argv
[optind
], gServiceText
[gServiceTextLen
]);
401 gServiceTextLen
+= 1 + gServiceText
[gServiceTextLen
];
415 // Check for any left over command line arguments.
417 if (optind
!= argc
) {
419 fprintf(stderr
, "%s: Unexpected argument '%s'\n", gProgramName
, argv
[optind
]);
423 // Check for inconsistency between the arguments.
425 if ( (gServiceName
[0] == 0) && (gServiceFile
[0] == 0) ) {
427 fprintf(stderr
, "%s: You must specify a service name to register (-n) or a service file (-f).\n", gProgramName
);
432 #if COMPILER_LIKES_PRAGMA_MARK
433 #pragma mark ***** Registration
436 typedef struct PosixService PosixService
;
438 struct PosixService
{
439 ServiceRecordSet coreServ
;
444 static PosixService
*gServiceList
= NULL
;
446 static void RegistrationCallback(mDNS
*const m
, ServiceRecordSet
*const thisRegistration
, mStatus status
)
447 // mDNS core calls this routine to tell us about the status of
448 // our registration. The appropriate action to take depends
449 // entirely on the value of status.
453 case mStatus_NoError
:
454 debugf("Callback: %##s Name Registered", thisRegistration
->RR_SRV
.resrec
.name
->c
);
455 // Do nothing; our name was successfully registered. We may
456 // get more call backs in the future.
459 case mStatus_NameConflict
:
460 debugf("Callback: %##s Name Conflict", thisRegistration
->RR_SRV
.resrec
.name
->c
);
462 // In the event of a conflict, this sample RegistrationCallback
463 // just calls mDNS_RenameAndReregisterService to automatically
464 // pick a new unique name for the service. For a device such as a
465 // printer, this may be appropriate. For a device with a user
466 // interface, and a screen, and a keyboard, the appropriate response
467 // may be to prompt the user and ask them to choose a new name for
470 // Also, what do we do if mDNS_RenameAndReregisterService returns an
471 // error. Right now I have no place to send that error to.
473 status
= mDNS_RenameAndReregisterService(m
, thisRegistration
, mDNSNULL
);
474 assert(status
== mStatus_NoError
);
477 case mStatus_MemFree
:
478 debugf("Callback: %##s Memory Free", thisRegistration
->RR_SRV
.resrec
.name
->c
);
480 // When debugging is enabled, make sure that thisRegistration
481 // is not on our gServiceList.
485 PosixService
*cursor
;
487 cursor
= gServiceList
;
488 while (cursor
!= NULL
) {
489 assert(&cursor
->coreServ
!= thisRegistration
);
490 cursor
= cursor
->next
;
494 free(thisRegistration
);
498 debugf("Callback: %##s Unknown Status %ld", thisRegistration
->RR_SRV
.resrec
.name
->c
, status
);
503 static int gServiceID
= 0;
505 static mStatus
RegisterOneService(const char * richTextName
,
506 const char * serviceType
,
507 const char * serviceDomain
,
513 PosixService
* thisServ
;
518 status
= mStatus_NoError
;
519 thisServ
= (PosixService
*) malloc(sizeof(*thisServ
));
520 if (thisServ
== NULL
) {
521 status
= mStatus_NoMemoryErr
;
523 if (status
== mStatus_NoError
) {
524 MakeDomainLabelFromLiteralString(&name
, richTextName
);
525 MakeDomainNameFromDNSNameString(&type
, serviceType
);
526 MakeDomainNameFromDNSNameString(&domain
, serviceDomain
);
527 status
= mDNS_RegisterService(&mDNSStorage
, &thisServ
->coreServ
,
528 &name
, &type
, &domain
, // Name, type, domain
529 NULL
, mDNSOpaque16fromIntVal(portNumber
),
530 text
, textLen
, // TXT data, length
532 mDNSInterface_Any
, // Interface ID
533 RegistrationCallback
, thisServ
); // Callback and context
535 if (status
== mStatus_NoError
) {
536 thisServ
->serviceID
= gServiceID
;
539 thisServ
->next
= gServiceList
;
540 gServiceList
= thisServ
;
542 if (gMDNSPlatformPosixVerboseLevel
> 0) {
544 "%s: Registered service %d, name '%s', type '%s', port %ld\n",
552 if (thisServ
!= NULL
) {
559 static mDNSBool
ReadALine(char *buf
, size_t bufSize
, FILE *fp
)
560 // Read a line, skipping over any blank lines or lines starting with '#'
564 good
= (fgets(buf
, bufSize
, fp
) != NULL
);
565 skip
= (good
&& (buf
[0] == '#'));
566 } while (good
&& skip
);
569 int len
= strlen( buf
);
570 if ( buf
[len
- 1] == '\r' || buf
[len
- 1] == '\n')
576 static mStatus
RegisterServicesInFile(const char *filePath
)
578 mStatus status
= mStatus_NoError
;
579 FILE * fp
= fopen(filePath
, "r");
583 status
= mStatus_UnknownErr
;
585 if (status
== mStatus_NoError
) {
586 mDNSBool good
= mDNStrue
;
591 const char *dom
= kDefaultServiceDomain
;
593 mDNSu8 text
[sizeof(RDataBody
)];
597 // Skip over any blank lines.
598 do ch
= fgetc(fp
); while ( ch
== '\n' || ch
== '\r' );
599 if (ch
!= EOF
) good
= (ungetc(ch
, fp
) == ch
);
601 // Read three lines, check them for validity, and register the service.
602 good
= ReadALine(name
, sizeof(name
), fp
);
604 good
= ReadALine(type
, sizeof(type
), fp
);
608 while (*p
&& *p
!= ' ') p
++;
615 good
= ReadALine(port
, sizeof(port
), fp
);
618 good
= CheckThatRichTextNameIsUsable(name
, mDNSfalse
)
619 && CheckThatServiceTypeIsUsable(type
, mDNSfalse
)
620 && CheckThatPortNumberIsUsable(atol(port
), mDNSfalse
);
625 if (!ReadALine(rawText
, sizeof(rawText
), fp
)) break;
626 len
= strlen(rawText
);
630 if (text
[textLen
] == 0) break;
631 memcpy(text
+ textLen
+ 1, rawText
, text
[textLen
]);
632 textLen
+= 1 + text
[textLen
];
635 fprintf(stderr
, "%s: TXT attribute too long for name = %s, type = %s, port = %s\n",
636 gProgramName
, name
, type
, port
);
640 status
= RegisterOneService(name
, type
, dom
, text
, textLen
, atol(port
));
641 if (status
!= mStatus_NoError
) {
642 fprintf(stderr
, "%s: Failed to register service, name = %s, type = %s, port = %s\n",
643 gProgramName
, name
, type
, port
);
644 status
= mStatus_NoError
; // keep reading
647 } while (good
&& !feof(fp
));
650 fprintf(stderr
, "%s: Error reading service file %s\n", gProgramName
, filePath
);
662 static mStatus
RegisterOurServices(void)
666 status
= mStatus_NoError
;
667 if (gServiceName
[0] != 0) {
668 status
= RegisterOneService(gServiceName
,
671 gServiceText
, gServiceTextLen
,
674 if (status
== mStatus_NoError
&& gServiceFile
[0] != 0) {
675 status
= RegisterServicesInFile(gServiceFile
);
680 static void DeregisterOurServices(void)
682 PosixService
*thisServ
;
685 while (gServiceList
!= NULL
) {
686 thisServ
= gServiceList
;
687 gServiceList
= thisServ
->next
;
689 thisServID
= thisServ
->serviceID
;
691 mDNS_DeregisterService(&mDNSStorage
, &thisServ
->coreServ
);
693 if (gMDNSPlatformPosixVerboseLevel
> 0) {
695 "%s: Deregistered service %d\n",
697 thisServ
->serviceID
);
702 #if COMPILER_LIKES_PRAGMA_MARK
703 #pragma mark **** Main
706 int main(int argc
, char **argv
)
711 // Parse our command line arguments. This won't come back if there's an error.
713 ParseArguments(argc
, argv
);
715 // If we're told to run as a daemon, then do that straight away.
716 // Note that we don't treat the inability to create our PID
717 // file as an error. Also note that we assign getpid to a long
718 // because printf has no format specified for pid_t.
721 if (gMDNSPlatformPosixVerboseLevel
> 0) {
722 fprintf(stderr
, "%s: Starting in daemon mode\n", gProgramName
);
729 fp
= fopen(gPIDFile
, "w");
731 fprintf(fp
, "%ld\n", (long) getpid());
737 if (gMDNSPlatformPosixVerboseLevel
> 0) {
738 fprintf(stderr
, "%s: Starting in foreground mode, PID %ld\n", gProgramName
, (long) getpid());
742 status
= mDNS_Init(&mDNSStorage
, &PlatformStorage
,
743 mDNS_Init_NoCache
, mDNS_Init_ZeroCacheSize
,
744 mDNS_Init_AdvertiseLocalAddresses
,
745 mDNS_Init_NoInitCallback
, mDNS_Init_NoInitCallbackContext
);
746 if (status
!= mStatus_NoError
) return(2);
748 status
= RegisterOurServices();
749 if (status
!= mStatus_NoError
) return(2);
751 signal(SIGHUP
, HandleSigHup
); // SIGHUP has to be sent by kill -HUP <pid>
752 signal(SIGINT
, HandleSigInt
); // SIGINT is what you get for a Ctrl-C
753 signal(SIGQUIT
, HandleSigQuit
); // SIGQUIT is what you get for a Ctrl-\ (indeed)
754 signal(SIGUSR1
, HandleSigUsr1
); // SIGUSR1 has to be sent by kill -USR1 <pid>
760 struct timeval timeout
;
763 // 1. Set up the fd_set as usual here.
764 // This example client has no file descriptors of its own,
765 // but a real application would call FD_SET to add them to the set here
768 // 2. Set up the timeout.
769 // This example client has no other work it needs to be doing,
770 // so we set an effectively infinite timeout
771 timeout
.tv_sec
= 0x3FFFFFFF;
774 // 3. Give the mDNSPosix layer a chance to add its information to the fd_set and timeout
775 mDNSPosixGetFDSet(&mDNSStorage
, &nfds
, &readfds
, &timeout
);
777 // 4. Call select as normal
778 verbosedebugf("select(%d, %d.%06d)", nfds
, timeout
.tv_sec
, timeout
.tv_usec
);
779 result
= select(nfds
, &readfds
, NULL
, NULL
, &timeout
);
783 verbosedebugf("select() returned %d errno %d", result
, errno
);
784 if (errno
!= EINTR
) gStopNow
= mDNStrue
;
787 if (gReceivedSigUsr1
)
789 gReceivedSigUsr1
= mDNSfalse
;
790 gMDNSPlatformPosixVerboseLevel
+= 1;
791 if (gMDNSPlatformPosixVerboseLevel
> 2)
792 gMDNSPlatformPosixVerboseLevel
= 0;
793 if ( gMDNSPlatformPosixVerboseLevel
> 0 )
794 fprintf(stderr
, "\nVerbose level %d\n", gMDNSPlatformPosixVerboseLevel
);
798 if (gMDNSPlatformPosixVerboseLevel
> 0)
799 fprintf(stderr
, "\nSIGHUP\n");
800 gReceivedSigHup
= mDNSfalse
;
801 DeregisterOurServices();
802 status
= mDNSPlatformPosixRefreshInterfaceList(&mDNSStorage
);
803 if (status
!= mStatus_NoError
) break;
804 status
= RegisterOurServices();
805 if (status
!= mStatus_NoError
) break;
811 // 5. Call mDNSPosixProcessFDSet to let the mDNSPosix layer do its work
812 mDNSPosixProcessFDSet(&mDNSStorage
, &readfds
);
814 // 6. This example client has no other work it needs to be doing,
815 // but a real client would do its work here
822 DeregisterOurServices();
823 mDNS_Close(&mDNSStorage
);
825 if (status
== mStatus_NoError
) {
830 if ( (result
!= 0) || (gMDNSPlatformPosixVerboseLevel
> 0) ) {
831 fprintf(stderr
, "%s: Finished with status %ld, result %d\n", gProgramName
, status
, result
);