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.28 2005/01/11 01:55:26 ksekar
28 Fix compile errors in Posix debug build
30 Revision 1.27 2004/12/01 04:28:43 cheshire
31 <rdar://problem/3872803> Darwin patches for Solaris and Suse
32 Use version of daemon() provided in mDNSUNP.c instead of local copy
34 Revision 1.26 2004/11/30 22:37:01 cheshire
35 Update copyright dates and add "Mode: C; tab-width: 4" headers
37 Revision 1.25 2004/11/11 02:00:51 cheshire
38 Minor fixes to getopt, error message
40 Revision 1.24 2004/11/09 19:32:10 rpantos
41 Suggestion from Ademar de Souza Reis Jr. to allow comments in services file
43 Revision 1.23 2004/09/17 01:08:54 cheshire
44 Renamed mDNSClientAPI.h to mDNSEmbeddedAPI.h
45 The name "mDNSClientAPI.h" is misleading to new developers looking at this code. The interfaces
46 declared in that file are ONLY appropriate to single-address-space embedded applications.
47 For clients on general-purpose computers, the interfaces defined in dns_sd.h should be used.
49 Revision 1.22 2004/09/16 01:58:22 cheshire
52 Revision 1.21 2004/06/15 03:48:07 cheshire
53 Update mDNSResponderPosix to take multiple name=val arguments in a sane way
55 Revision 1.20 2004/05/18 23:51:26 cheshire
56 Tidy up all checkin comments to use consistent "<rdar://problem/xxxxxxx>" format for bug numbers
58 Revision 1.19 2004/03/12 08:03:14 cheshire
61 Revision 1.18 2004/01/25 00:00:55 cheshire
62 Change to use mDNSOpaque16fromIntVal() instead of shifting and masking
64 Revision 1.17 2003/12/11 19:11:55 cheshire
67 Revision 1.16 2003/08/14 02:19:55 cheshire
68 <rdar://problem/3375491> Split generic ResourceRecord type into two separate types: AuthRecord and CacheRecord
70 Revision 1.15 2003/08/12 19:56:26 cheshire
73 Revision 1.14 2003/08/06 18:20:51 cheshire
76 Revision 1.13 2003/07/23 00:00:04 cheshire
79 Revision 1.12 2003/07/15 01:55:16 cheshire
80 <rdar://problem/3315777> Need to implement service registration with subtypes
82 Revision 1.11 2003/07/14 18:11:54 cheshire
83 Fix stricter compiler warnings
85 Revision 1.10 2003/07/10 20:27:31 cheshire
86 <rdar://problem/3318717> mDNSResponder Posix version is missing a 'b' in the getopt option string
88 Revision 1.9 2003/07/02 21:19:59 cheshire
89 <rdar://problem/3313413> Update copyright notices, etc., in source code comments
91 Revision 1.8 2003/06/18 05:48:41 cheshire
94 Revision 1.7 2003/05/06 00:00:50 cheshire
95 <rdar://problem/3248914> Rationalize naming of domainname manipulation functions
97 Revision 1.6 2003/03/08 00:35:56 cheshire
98 Switched to using new "mDNS_Execute" model (see "mDNSCore/Implementer Notes.txt")
100 Revision 1.5 2003/02/20 06:48:36 cheshire
101 <rdar://problem/3169535> Xserve RAID needs to do interface-specific registrations
102 Reviewed by: Josh Graessley, Bob Bradley
104 Revision 1.4 2003/01/28 03:07:46 cheshire
105 Add extra parameter to mDNS_RenameAndReregisterService(),
106 and add support for specifying a domain other than dot-local.
108 Revision 1.3 2002/09/21 20:44:53 zarzycki
111 Revision 1.2 2002/09/19 04:20:44 cheshire
112 Remove high-ascii characters that confuse some systems
114 Revision 1.1 2002/09/17 06:24:35 cheshire
119 #include "mDNSEmbeddedAPI.h"// Defines the interface to the client layer above
120 #include "mDNSPosix.h" // Defines the specific types needed to run mDNS on this platform
123 #include <stdio.h> // For printf()
124 #include <stdlib.h> // For exit() etc.
125 #include <string.h> // For strlen() etc.
126 #include <unistd.h> // For select()
127 #include <errno.h> // For errno, EINTR
131 #if COMPILER_LIKES_PRAGMA_MARK
132 #pragma mark ***** Globals
135 static mDNS mDNSStorage
; // mDNS core uses this to store its globals
136 static mDNS_PlatformSupport PlatformStorage
; // Stores this platform's globals
138 static const char *gProgramName
= "mDNSResponderPosix";
140 #if COMPILER_LIKES_PRAGMA_MARK
141 #pragma mark ***** Signals
144 static volatile mDNSBool gReceivedSigUsr1
;
145 static volatile mDNSBool gReceivedSigHup
;
146 static volatile mDNSBool gStopNow
;
148 // We support 4 signals.
150 // o SIGUSR1 toggles verbose mode on and off in debug builds
151 // o SIGHUP triggers the program to re-read its preferences.
152 // o SIGINT causes an orderly shutdown of the program.
153 // o SIGQUIT causes a somewhat orderly shutdown (direct but dangerous)
154 // o SIGKILL kills us dead (easy to implement :-)
156 // There are fatal race conditions in our signal handling, but there's not much
157 // we can do about them while remaining within the Posix space. Specifically,
158 // if a signal arrives after we test the globals its sets but before we call
159 // select, the signal will be dropped. The user will have to send the signal
160 // again. Unfortunately, Posix does not have a "sigselect" to atomically
161 // modify the signal mask and start a select.
163 static void HandleSigUsr1(int sigraised
)
164 // If we get a SIGUSR1 we toggle the state of the
167 assert(sigraised
== SIGUSR1
);
168 gReceivedSigUsr1
= mDNStrue
;
171 static void HandleSigHup(int sigraised
)
172 // A handler for SIGHUP that causes us to break out of the
173 // main event loop when the user kill 1's us. This has the
174 // effect of triggered the main loop to deregister the
175 // current services and re-read the preferences.
177 assert(sigraised
== SIGHUP
);
178 gReceivedSigHup
= mDNStrue
;
181 static void HandleSigInt(int sigraised
)
182 // A handler for SIGINT that causes us to break out of the
183 // main event loop when the user types ^C. This has the
184 // effect of quitting the program.
186 assert(sigraised
== SIGINT
);
188 if (gMDNSPlatformPosixVerboseLevel
> 0) {
189 fprintf(stderr
, "\nSIGINT\n");
194 static void HandleSigQuit(int sigraised
)
195 // If we get a SIGQUIT the user is desperate and we
196 // just call mDNS_Close directly. This is definitely
197 // not safe (because it could reenter mDNS), but
198 // we presume that the user has already tried the safe
201 assert(sigraised
== SIGQUIT
);
203 if (gMDNSPlatformPosixVerboseLevel
> 0) {
204 fprintf(stderr
, "\nSIGQUIT\n");
206 mDNS_Close(&mDNSStorage
);
210 #if COMPILER_LIKES_PRAGMA_MARK
211 #pragma mark ***** Parameter Checking
214 static mDNSBool
CheckThatRichTextHostNameIsUsable(const char *richTextHostName
, mDNSBool printExplanation
)
215 // Checks that richTextHostName is a reasonable host name
216 // label and, if it isn't and printExplanation is true, prints
217 // an explanation of why not.
220 domainlabel richLabel
;
221 domainlabel poorLabel
;
224 if (result
&& strlen(richTextHostName
) > 63) {
225 if (printExplanation
) {
227 "%s: Host name is too long (must be 63 characters or less)\n",
232 if (result
&& richTextHostName
[0] == 0) {
233 if (printExplanation
) {
234 fprintf(stderr
, "%s: Host name can't be empty\n", gProgramName
);
239 MakeDomainLabelFromLiteralString(&richLabel
, richTextHostName
);
240 ConvertUTF8PstringToRFC1034HostLabel(richLabel
.c
, &poorLabel
);
241 if (poorLabel
.c
[0] == 0) {
242 if (printExplanation
) {
244 "%s: Host name doesn't produce a usable RFC-1034 name\n",
253 static mDNSBool
CheckThatServiceTypeIsUsable(const char *serviceType
, mDNSBool printExplanation
)
254 // Checks that serviceType is a reasonable service type
255 // label and, if it isn't and printExplanation is true, prints
256 // an explanation of why not.
261 if (result
&& strlen(serviceType
) > 63) {
262 if (printExplanation
) {
264 "%s: Service type is too long (must be 63 characters or less)\n",
269 if (result
&& serviceType
[0] == 0) {
270 if (printExplanation
) {
272 "%s: Service type can't be empty\n",
280 static mDNSBool
CheckThatPortNumberIsUsable(long portNumber
, mDNSBool printExplanation
)
281 // Checks that portNumber is a reasonable port number
282 // and, if it isn't and printExplanation is true, prints
283 // an explanation of why not.
288 if (result
&& (portNumber
<= 0 || portNumber
> 65535)) {
289 if (printExplanation
) {
291 "%s: Port number specified by -p must be in range 1..65535\n",
299 #if COMPILER_LIKES_PRAGMA_MARK
300 #pragma mark ***** Command Line Arguments
303 static const char kDefaultPIDFile
[] = "/var/run/mDNSResponder.pid";
304 static const char kDefaultServiceType
[] = "_afpovertcp._tcp.";
305 static const char kDefaultServiceDomain
[] = "local.";
307 kDefaultPortNumber
= 548
310 static void PrintUsage()
313 "Usage: %s [-v level ] [-r] [-n name] [-t type] [-d domain] [-p port] [-f file] [-b] [-P pidfile] [-x name=val ...]\n",
315 fprintf(stderr
, " -v verbose mode, level is a number from 0 to 2\n");
316 fprintf(stderr
, " 0 = no debugging info (default)\n");
317 fprintf(stderr
, " 1 = standard debugging info\n");
318 fprintf(stderr
, " 2 = intense debugging info\n");
319 fprintf(stderr
, " can be cycled kill -USR1\n");
320 fprintf(stderr
, " -r also bind to port 53 (port 5353 is always bound)\n");
321 fprintf(stderr
, " -n uses 'name' as the host name (default is none)\n");
322 fprintf(stderr
, " -t uses 'type' as the service type (default is '%s')\n", kDefaultServiceType
);
323 fprintf(stderr
, " -d uses 'domain' as the service domain (default is '%s')\n", kDefaultServiceDomain
);
324 fprintf(stderr
, " -p uses 'port' as the port number (default is '%d')\n", kDefaultPortNumber
);
325 fprintf(stderr
, " -f reads a service list from 'file'\n");
326 fprintf(stderr
, " -b forces daemon (background) mode\n");
327 fprintf(stderr
, " -P uses 'pidfile' as the PID file\n");
328 fprintf(stderr
, " (default is '%s')\n", kDefaultPIDFile
);
329 fprintf(stderr
, " only meaningful if -b also specified\n");
330 fprintf(stderr
, " -x stores name=val in TXT record (default is empty).\n");
331 fprintf(stderr
, " MUST be the last command-line argument;\n");
332 fprintf(stderr
, " all subsequent arguments after -x are treated as name=val pairs.\n");
335 static mDNSBool gAvoidPort53
= mDNStrue
;
336 static const char *gRichTextHostName
= "";
337 static const char *gServiceType
= kDefaultServiceType
;
338 static const char *gServiceDomain
= kDefaultServiceDomain
;
339 static mDNSu8 gServiceText
[sizeof(RDataBody
)];
340 static mDNSu16 gServiceTextLen
= 0;
341 static int gPortNumber
= kDefaultPortNumber
;
342 static const char *gServiceFile
= "";
343 static mDNSBool gDaemon
= mDNSfalse
;
344 static const char *gPIDFile
= kDefaultPIDFile
;
346 static void ParseArguments(int argc
, char **argv
)
347 // Parses our command line arguments into the global variables
352 // Set gProgramName to the last path component of argv[0]
354 gProgramName
= strrchr(argv
[0], '/');
355 if (gProgramName
== NULL
) {
356 gProgramName
= argv
[0];
361 // Parse command line options using getopt.
364 ch
= getopt(argc
, argv
, "v:rn:t:d:p:f:dP:bx");
368 gMDNSPlatformPosixVerboseLevel
= atoi(optarg
);
369 if (gMDNSPlatformPosixVerboseLevel
< 0 || gMDNSPlatformPosixVerboseLevel
> 2) {
371 "%s: Verbose mode must be in the range 0..2\n",
377 gAvoidPort53
= mDNSfalse
;
380 gRichTextHostName
= optarg
;
381 if ( ! CheckThatRichTextHostNameIsUsable(gRichTextHostName
, mDNStrue
) ) {
386 gServiceType
= optarg
;
387 if ( ! CheckThatServiceTypeIsUsable(gServiceType
, mDNStrue
) ) {
392 gServiceDomain
= optarg
;
395 gPortNumber
= atol(optarg
);
396 if ( ! CheckThatPortNumberIsUsable(gPortNumber
, mDNStrue
) ) {
401 gServiceFile
= optarg
;
410 while (optind
< argc
)
412 gServiceText
[gServiceTextLen
] = strlen(argv
[optind
]);
413 memcpy(gServiceText
+gServiceTextLen
+1, argv
[optind
], gServiceText
[gServiceTextLen
]);
414 gServiceTextLen
+= 1 + gServiceText
[gServiceTextLen
];
428 // Check for any left over command line arguments.
430 if (optind
!= argc
) {
432 fprintf(stderr
, "%s: Unexpected argument '%s'\n", gProgramName
, argv
[optind
]);
436 // Check for inconsistency between the arguments.
438 if ( (gRichTextHostName
[0] == 0) && (gServiceFile
[0] == 0) ) {
440 fprintf(stderr
, "%s: You must specify a service to register (-n) or a service file (-f).\n", gProgramName
);
445 #if COMPILER_LIKES_PRAGMA_MARK
446 #pragma mark ***** Registration
449 typedef struct PosixService PosixService
;
451 struct PosixService
{
452 ServiceRecordSet coreServ
;
457 static PosixService
*gServiceList
= NULL
;
459 static void RegistrationCallback(mDNS
*const m
, ServiceRecordSet
*const thisRegistration
, mStatus status
)
460 // mDNS core calls this routine to tell us about the status of
461 // our registration. The appropriate action to take depends
462 // entirely on the value of status.
466 case mStatus_NoError
:
467 debugf("Callback: %##s Name Registered", thisRegistration
->RR_SRV
.resrec
.name
->c
);
468 // Do nothing; our name was successfully registered. We may
469 // get more call backs in the future.
472 case mStatus_NameConflict
:
473 debugf("Callback: %##s Name Conflict", thisRegistration
->RR_SRV
.resrec
.name
->c
);
475 // In the event of a conflict, this sample RegistrationCallback
476 // just calls mDNS_RenameAndReregisterService to automatically
477 // pick a new unique name for the service. For a device such as a
478 // printer, this may be appropriate. For a device with a user
479 // interface, and a screen, and a keyboard, the appropriate response
480 // may be to prompt the user and ask them to choose a new name for
483 // Also, what do we do if mDNS_RenameAndReregisterService returns an
484 // error. Right now I have no place to send that error to.
486 status
= mDNS_RenameAndReregisterService(m
, thisRegistration
, mDNSNULL
);
487 assert(status
== mStatus_NoError
);
490 case mStatus_MemFree
:
491 debugf("Callback: %##s Memory Free", thisRegistration
->RR_SRV
.resrec
.name
->c
);
493 // When debugging is enabled, make sure that thisRegistration
494 // is not on our gServiceList.
498 PosixService
*cursor
;
500 cursor
= gServiceList
;
501 while (cursor
!= NULL
) {
502 assert(&cursor
->coreServ
!= thisRegistration
);
503 cursor
= cursor
->next
;
507 free(thisRegistration
);
511 debugf("Callback: %##s Unknown Status %ld", thisRegistration
->RR_SRV
.resrec
.name
->c
, status
);
516 static int gServiceID
= 0;
518 static mStatus
RegisterOneService(const char * richTextHostName
,
519 const char * serviceType
,
520 const char * serviceDomain
,
526 PosixService
* thisServ
;
531 status
= mStatus_NoError
;
532 thisServ
= (PosixService
*) malloc(sizeof(*thisServ
));
533 if (thisServ
== NULL
) {
534 status
= mStatus_NoMemoryErr
;
536 if (status
== mStatus_NoError
) {
537 MakeDomainLabelFromLiteralString(&name
, richTextHostName
);
538 MakeDomainNameFromDNSNameString(&type
, serviceType
);
539 MakeDomainNameFromDNSNameString(&domain
, serviceDomain
);
540 status
= mDNS_RegisterService(&mDNSStorage
, &thisServ
->coreServ
,
541 &name
, &type
, &domain
, // Name, type, domain
542 NULL
, mDNSOpaque16fromIntVal(portNumber
),
543 text
, textLen
, // TXT data, length
545 mDNSInterface_Any
, // Interface ID
546 RegistrationCallback
, thisServ
); // Callback and context
548 if (status
== mStatus_NoError
) {
549 thisServ
->serviceID
= gServiceID
;
552 thisServ
->next
= gServiceList
;
553 gServiceList
= thisServ
;
555 if (gMDNSPlatformPosixVerboseLevel
> 0) {
557 "%s: Registered service %d, name '%s', type '%s', port %ld\n",
565 if (thisServ
!= NULL
) {
572 static mDNSBool
ReadALine(char *buf
, size_t bufSize
, FILE *fp
)
573 // Read a line, skipping over any blank lines or lines starting with '#'
577 good
= (fgets(buf
, bufSize
, fp
) != NULL
);
578 skip
= (good
&& (buf
[0] == '#' || buf
[0] == '\r' || buf
[0] == '\n'));
579 } while (good
&& skip
);
582 int len
= strlen( buf
);
583 if ( buf
[len
- 1] == '\r' || buf
[len
- 1] == '\n')
589 static mStatus
RegisterServicesInFile(const char *filePath
)
591 mStatus status
= mStatus_NoError
;
592 FILE * fp
= fopen(filePath
, "r");
596 status
= mStatus_UnknownErr
;
598 if (status
== mStatus_NoError
) {
599 mDNSBool good
= mDNStrue
;
603 const char *dom
= kDefaultServiceDomain
;
605 mDNSu8 text
[sizeof(RDataBody
)];
609 // Read three lines, check them for validity, and register the service.
610 good
= ReadALine(name
, sizeof(name
), fp
);
612 good
= ReadALine(type
, sizeof(type
), fp
);
616 while (*p
&& *p
!= ' ') p
++;
623 good
= ReadALine(port
, sizeof(port
), fp
);
626 good
= CheckThatRichTextHostNameIsUsable(name
, mDNSfalse
)
627 && CheckThatServiceTypeIsUsable(type
, mDNSfalse
)
628 && CheckThatPortNumberIsUsable(atol(port
), mDNSfalse
);
632 if (!ReadALine(rawText
, sizeof(rawText
), fp
)) break;
633 text
[textLen
] = strlen(rawText
);
634 if (text
[textLen
] == 0) break;
635 memcpy(text
+ textLen
+ 1, rawText
, text
[textLen
]);
636 textLen
+= 1 + text
[textLen
];
640 status
= RegisterOneService(name
, type
, dom
, text
, textLen
, atol(port
));
641 if (status
!= mStatus_NoError
) {
643 "%s: Failed to register service, name = %s, type = %s, port = %s\n",
648 status
= mStatus_NoError
; // keep reading
651 } while (good
&& !feof(fp
));
654 fprintf(stderr
, "%s: Error reading service file %s\n", gProgramName
, filePath
);
666 static mStatus
RegisterOurServices(void)
670 status
= mStatus_NoError
;
671 if (gRichTextHostName
[0] != 0) {
672 status
= RegisterOneService(gRichTextHostName
,
675 gServiceText
, gServiceTextLen
,
678 if (status
== mStatus_NoError
&& gServiceFile
[0] != 0) {
679 status
= RegisterServicesInFile(gServiceFile
);
684 static void DeregisterOurServices(void)
686 PosixService
*thisServ
;
689 while (gServiceList
!= NULL
) {
690 thisServ
= gServiceList
;
691 gServiceList
= thisServ
->next
;
693 thisServID
= thisServ
->serviceID
;
695 mDNS_DeregisterService(&mDNSStorage
, &thisServ
->coreServ
);
697 if (gMDNSPlatformPosixVerboseLevel
> 0) {
699 "%s: Deregistered service %d\n",
701 thisServ
->serviceID
);
706 #if COMPILER_LIKES_PRAGMA_MARK
707 #pragma mark **** Main
710 int main(int argc
, char **argv
)
715 // Parse our command line arguments. This won't come back if there's an error.
717 ParseArguments(argc
, argv
);
719 // If we're told to run as a daemon, then do that straight away.
720 // Note that we don't treat the inability to create our PID
721 // file as an error. Also note that we assign getpid to a long
722 // because printf has no format specified for pid_t.
725 if (gMDNSPlatformPosixVerboseLevel
> 0) {
726 fprintf(stderr
, "%s: Starting in daemon mode\n", gProgramName
);
733 fp
= fopen(gPIDFile
, "w");
735 fprintf(fp
, "%ld\n", (long) getpid());
741 if (gMDNSPlatformPosixVerboseLevel
> 0) {
742 fprintf(stderr
, "%s: Starting in foreground mode, PID %ld\n", gProgramName
, (long) getpid());
746 status
= mDNS_Init(&mDNSStorage
, &PlatformStorage
,
747 mDNS_Init_NoCache
, mDNS_Init_ZeroCacheSize
,
748 mDNS_Init_AdvertiseLocalAddresses
,
749 mDNS_Init_NoInitCallback
, mDNS_Init_NoInitCallbackContext
);
750 if (status
!= mStatus_NoError
) return(2);
752 status
= RegisterOurServices();
753 if (status
!= mStatus_NoError
) return(2);
755 signal(SIGHUP
, HandleSigHup
); // SIGHUP has to be sent by kill -HUP <pid>
756 signal(SIGINT
, HandleSigInt
); // SIGINT is what you get for a Ctrl-C
757 signal(SIGQUIT
, HandleSigQuit
); // SIGQUIT is what you get for a Ctrl-\ (indeed)
758 signal(SIGUSR1
, HandleSigUsr1
); // SIGUSR1 has to be sent by kill -USR1 <pid>
764 struct timeval timeout
;
767 // 1. Set up the fd_set as usual here.
768 // This example client has no file descriptors of its own,
769 // but a real application would call FD_SET to add them to the set here
772 // 2. Set up the timeout.
773 // This example client has no other work it needs to be doing,
774 // so we set an effectively infinite timeout
775 timeout
.tv_sec
= 0x3FFFFFFF;
778 // 3. Give the mDNSPosix layer a chance to add its information to the fd_set and timeout
779 mDNSPosixGetFDSet(&mDNSStorage
, &nfds
, &readfds
, &timeout
);
781 // 4. Call select as normal
782 verbosedebugf("select(%d, %d.%06d)", nfds
, timeout
.tv_sec
, timeout
.tv_usec
);
783 result
= select(nfds
, &readfds
, NULL
, NULL
, &timeout
);
787 verbosedebugf("select() returned %d errno %d", result
, errno
);
788 if (errno
!= EINTR
) gStopNow
= mDNStrue
;
791 if (gReceivedSigUsr1
)
793 gReceivedSigUsr1
= mDNSfalse
;
794 gMDNSPlatformPosixVerboseLevel
+= 1;
795 if (gMDNSPlatformPosixVerboseLevel
> 2)
796 gMDNSPlatformPosixVerboseLevel
= 0;
797 if ( gMDNSPlatformPosixVerboseLevel
> 0 )
798 fprintf(stderr
, "\nVerbose level %d\n", gMDNSPlatformPosixVerboseLevel
);
802 if (gMDNSPlatformPosixVerboseLevel
> 0)
803 fprintf(stderr
, "\nSIGHUP\n");
804 gReceivedSigHup
= mDNSfalse
;
805 DeregisterOurServices();
806 status
= mDNSPlatformPosixRefreshInterfaceList(&mDNSStorage
);
807 if (status
!= mStatus_NoError
) break;
808 status
= RegisterOurServices();
809 if (status
!= mStatus_NoError
) break;
815 // 5. Call mDNSPosixProcessFDSet to let the mDNSPosix layer do its work
816 mDNSPosixProcessFDSet(&mDNSStorage
, &readfds
);
818 // 6. This example client has no other work it needs to be doing,
819 // but a real client would do its work here
826 DeregisterOurServices();
827 mDNS_Close(&mDNSStorage
);
829 if (status
== mStatus_NoError
) {
834 if ( (result
!= 0) || (gMDNSPlatformPosixVerboseLevel
> 0) ) {
835 fprintf(stderr
, "%s: Finished with status %ld, result %d\n", gProgramName
, status
, result
);