1 /* -*- Mode: C; tab-width: 4 -*-
3 * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
17 Change History (most recent first):
20 Revision 1.32 2006/08/14 23:24:46 cheshire
21 Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
23 Revision 1.31 2006/06/12 18:22:42 cheshire
24 <rdar://problem/4580067> mDNSResponder building warnings under Red Hat 64-bit (LP64) Linux
26 Revision 1.30 2005/10/26 22:21:16 cheshire
27 <rdar://problem/4149841> Potential buffer overflow in mDNSResponderPosix
29 Revision 1.29 2005/03/04 21:35:33 cheshire
30 <rdar://problem/4037201> Services.txt file not parsed properly when it contains more than one service
32 Revision 1.28 2005/01/11 01:55:26 ksekar
33 Fix compile errors in Posix debug build
35 Revision 1.27 2004/12/01 04:28:43 cheshire
36 <rdar://problem/3872803> Darwin patches for Solaris and Suse
37 Use version of daemon() provided in mDNSUNP.c instead of local copy
39 Revision 1.26 2004/11/30 22:37:01 cheshire
40 Update copyright dates and add "Mode: C; tab-width: 4" headers
42 Revision 1.25 2004/11/11 02:00:51 cheshire
43 Minor fixes to getopt, error message
45 Revision 1.24 2004/11/09 19:32:10 rpantos
46 Suggestion from Ademar de Souza Reis Jr. to allow comments in services file
48 Revision 1.23 2004/09/17 01:08:54 cheshire
49 Renamed mDNSClientAPI.h to mDNSEmbeddedAPI.h
50 The name "mDNSClientAPI.h" is misleading to new developers looking at this code. The interfaces
51 declared in that file are ONLY appropriate to single-address-space embedded applications.
52 For clients on general-purpose computers, the interfaces defined in dns_sd.h should be used.
54 Revision 1.22 2004/09/16 01:58:22 cheshire
57 Revision 1.21 2004/06/15 03:48:07 cheshire
58 Update mDNSResponderPosix to take multiple name=val arguments in a sane way
60 Revision 1.20 2004/05/18 23:51:26 cheshire
61 Tidy up all checkin comments to use consistent "<rdar://problem/xxxxxxx>" format for bug numbers
63 Revision 1.19 2004/03/12 08:03:14 cheshire
66 Revision 1.18 2004/01/25 00:00:55 cheshire
67 Change to use mDNSOpaque16fromIntVal() instead of shifting and masking
69 Revision 1.17 2003/12/11 19:11:55 cheshire
72 Revision 1.16 2003/08/14 02:19:55 cheshire
73 <rdar://problem/3375491> Split generic ResourceRecord type into two separate types: AuthRecord and CacheRecord
75 Revision 1.15 2003/08/12 19:56:26 cheshire
78 Revision 1.14 2003/08/06 18:20:51 cheshire
81 Revision 1.13 2003/07/23 00:00:04 cheshire
84 Revision 1.12 2003/07/15 01:55:16 cheshire
85 <rdar://problem/3315777> Need to implement service registration with subtypes
87 Revision 1.11 2003/07/14 18:11:54 cheshire
88 Fix stricter compiler warnings
90 Revision 1.10 2003/07/10 20:27:31 cheshire
91 <rdar://problem/3318717> mDNSResponder Posix version is missing a 'b' in the getopt option string
93 Revision 1.9 2003/07/02 21:19:59 cheshire
94 <rdar://problem/3313413> Update copyright notices, etc., in source code comments
96 Revision 1.8 2003/06/18 05:48:41 cheshire
99 Revision 1.7 2003/05/06 00:00:50 cheshire
100 <rdar://problem/3248914> Rationalize naming of domainname manipulation functions
102 Revision 1.6 2003/03/08 00:35:56 cheshire
103 Switched to using new "mDNS_Execute" model (see "mDNSCore/Implementer Notes.txt")
105 Revision 1.5 2003/02/20 06:48:36 cheshire
106 <rdar://problem/3169535> Xserve RAID needs to do interface-specific registrations
107 Reviewed by: Josh Graessley, Bob Bradley
109 Revision 1.4 2003/01/28 03:07:46 cheshire
110 Add extra parameter to mDNS_RenameAndReregisterService(),
111 and add support for specifying a domain other than dot-local.
113 Revision 1.3 2002/09/21 20:44:53 zarzycki
116 Revision 1.2 2002/09/19 04:20:44 cheshire
117 Remove high-ascii characters that confuse some systems
119 Revision 1.1 2002/09/17 06:24:35 cheshire
124 #include "mDNSEmbeddedAPI.h"// Defines the interface to the client layer above
125 #include "mDNSPosix.h" // Defines the specific types needed to run mDNS on this platform
128 #include <stdio.h> // For printf()
129 #include <stdlib.h> // For exit() etc.
130 #include <string.h> // For strlen() etc.
131 #include <unistd.h> // For select()
132 #include <errno.h> // For errno, EINTR
136 #if COMPILER_LIKES_PRAGMA_MARK
137 #pragma mark ***** Globals
140 static mDNS mDNSStorage
; // mDNS core uses this to store its globals
141 static mDNS_PlatformSupport PlatformStorage
; // Stores this platform's globals
143 static const char *gProgramName
= "mDNSResponderPosix";
145 #if COMPILER_LIKES_PRAGMA_MARK
146 #pragma mark ***** Signals
149 static volatile mDNSBool gReceivedSigUsr1
;
150 static volatile mDNSBool gReceivedSigHup
;
151 static volatile mDNSBool gStopNow
;
153 // We support 4 signals.
155 // o SIGUSR1 toggles verbose mode on and off in debug builds
156 // o SIGHUP triggers the program to re-read its preferences.
157 // o SIGINT causes an orderly shutdown of the program.
158 // o SIGQUIT causes a somewhat orderly shutdown (direct but dangerous)
159 // o SIGKILL kills us dead (easy to implement :-)
161 // There are fatal race conditions in our signal handling, but there's not much
162 // we can do about them while remaining within the Posix space. Specifically,
163 // if a signal arrives after we test the globals its sets but before we call
164 // select, the signal will be dropped. The user will have to send the signal
165 // again. Unfortunately, Posix does not have a "sigselect" to atomically
166 // modify the signal mask and start a select.
168 static void HandleSigUsr1(int sigraised
)
169 // If we get a SIGUSR1 we toggle the state of the
172 assert(sigraised
== SIGUSR1
);
173 gReceivedSigUsr1
= mDNStrue
;
176 static void HandleSigHup(int sigraised
)
177 // A handler for SIGHUP that causes us to break out of the
178 // main event loop when the user kill 1's us. This has the
179 // effect of triggered the main loop to deregister the
180 // current services and re-read the preferences.
182 assert(sigraised
== SIGHUP
);
183 gReceivedSigHup
= mDNStrue
;
186 static void HandleSigInt(int sigraised
)
187 // A handler for SIGINT that causes us to break out of the
188 // main event loop when the user types ^C. This has the
189 // effect of quitting the program.
191 assert(sigraised
== SIGINT
);
193 if (gMDNSPlatformPosixVerboseLevel
> 0) {
194 fprintf(stderr
, "\nSIGINT\n");
199 static void HandleSigQuit(int sigraised
)
200 // If we get a SIGQUIT the user is desperate and we
201 // just call mDNS_Close directly. This is definitely
202 // not safe (because it could reenter mDNS), but
203 // we presume that the user has already tried the safe
206 assert(sigraised
== SIGQUIT
);
208 if (gMDNSPlatformPosixVerboseLevel
> 0) {
209 fprintf(stderr
, "\nSIGQUIT\n");
211 mDNS_Close(&mDNSStorage
);
215 #if COMPILER_LIKES_PRAGMA_MARK
216 #pragma mark ***** Parameter Checking
219 static mDNSBool
CheckThatRichTextNameIsUsable(const char *richTextName
, mDNSBool printExplanation
)
220 // Checks that richTextName is reasonable
221 // label and, if it isn't and printExplanation is true, prints
222 // an explanation of why not.
224 mDNSBool result
= mDNStrue
;
225 if (result
&& strlen(richTextName
) > 63) {
226 if (printExplanation
) {
228 "%s: Service name is too long (must be 63 characters or less)\n",
233 if (result
&& richTextName
[0] == 0) {
234 if (printExplanation
) {
235 fprintf(stderr
, "%s: Service name can't be empty\n", gProgramName
);
242 static mDNSBool
CheckThatServiceTypeIsUsable(const char *serviceType
, mDNSBool printExplanation
)
243 // Checks that serviceType is a reasonable service type
244 // label and, if it isn't and printExplanation is true, prints
245 // an explanation of why not.
250 if (result
&& strlen(serviceType
) > 63) {
251 if (printExplanation
) {
253 "%s: Service type is too long (must be 63 characters or less)\n",
258 if (result
&& serviceType
[0] == 0) {
259 if (printExplanation
) {
261 "%s: Service type can't be empty\n",
269 static mDNSBool
CheckThatPortNumberIsUsable(long portNumber
, mDNSBool printExplanation
)
270 // Checks that portNumber is a reasonable port number
271 // and, if it isn't and printExplanation is true, prints
272 // an explanation of why not.
277 if (result
&& (portNumber
<= 0 || portNumber
> 65535)) {
278 if (printExplanation
) {
280 "%s: Port number specified by -p must be in range 1..65535\n",
288 #if COMPILER_LIKES_PRAGMA_MARK
289 #pragma mark ***** Command Line Arguments
292 static const char kDefaultPIDFile
[] = "/var/run/mDNSResponder.pid";
293 static const char kDefaultServiceType
[] = "_afpovertcp._tcp.";
294 static const char kDefaultServiceDomain
[] = "local.";
296 kDefaultPortNumber
= 548
299 static void PrintUsage()
302 "Usage: %s [-v level ] [-r] [-n name] [-t type] [-d domain] [-p port] [-f file] [-b] [-P pidfile] [-x name=val ...]\n",
304 fprintf(stderr
, " -v verbose mode, level is a number from 0 to 2\n");
305 fprintf(stderr
, " 0 = no debugging info (default)\n");
306 fprintf(stderr
, " 1 = standard debugging info\n");
307 fprintf(stderr
, " 2 = intense debugging info\n");
308 fprintf(stderr
, " can be cycled kill -USR1\n");
309 fprintf(stderr
, " -r also bind to port 53 (port 5353 is always bound)\n");
310 fprintf(stderr
, " -n uses 'name' as the service name (required)\n");
311 fprintf(stderr
, " -t uses 'type' as the service type (default is '%s')\n", kDefaultServiceType
);
312 fprintf(stderr
, " -d uses 'domain' as the service domain (default is '%s')\n", kDefaultServiceDomain
);
313 fprintf(stderr
, " -p uses 'port' as the port number (default is '%d')\n", kDefaultPortNumber
);
314 fprintf(stderr
, " -f reads a service list from 'file'\n");
315 fprintf(stderr
, " -b forces daemon (background) mode\n");
316 fprintf(stderr
, " -P uses 'pidfile' as the PID file\n");
317 fprintf(stderr
, " (default is '%s')\n", kDefaultPIDFile
);
318 fprintf(stderr
, " only meaningful if -b also specified\n");
319 fprintf(stderr
, " -x stores name=val in TXT record (default is empty).\n");
320 fprintf(stderr
, " MUST be the last command-line argument;\n");
321 fprintf(stderr
, " all subsequent arguments after -x are treated as name=val pairs.\n");
324 static mDNSBool gAvoidPort53
= mDNStrue
;
325 static const char *gServiceName
= "";
326 static const char *gServiceType
= kDefaultServiceType
;
327 static const char *gServiceDomain
= kDefaultServiceDomain
;
328 static mDNSu8 gServiceText
[sizeof(RDataBody
)];
329 static mDNSu16 gServiceTextLen
= 0;
330 static int gPortNumber
= kDefaultPortNumber
;
331 static const char *gServiceFile
= "";
332 static mDNSBool gDaemon
= mDNSfalse
;
333 static const char *gPIDFile
= kDefaultPIDFile
;
335 static void ParseArguments(int argc
, char **argv
)
336 // Parses our command line arguments into the global variables
341 // Set gProgramName to the last path component of argv[0]
343 gProgramName
= strrchr(argv
[0], '/');
344 if (gProgramName
== NULL
) {
345 gProgramName
= argv
[0];
350 // Parse command line options using getopt.
353 ch
= getopt(argc
, argv
, "v:rn:t:d:p:f:dP:bx");
357 gMDNSPlatformPosixVerboseLevel
= atoi(optarg
);
358 if (gMDNSPlatformPosixVerboseLevel
< 0 || gMDNSPlatformPosixVerboseLevel
> 2) {
360 "%s: Verbose mode must be in the range 0..2\n",
366 gAvoidPort53
= mDNSfalse
;
369 gServiceName
= optarg
;
370 if ( ! CheckThatRichTextNameIsUsable(gServiceName
, mDNStrue
) ) {
375 gServiceType
= optarg
;
376 if ( ! CheckThatServiceTypeIsUsable(gServiceType
, mDNStrue
) ) {
381 gServiceDomain
= optarg
;
384 gPortNumber
= atol(optarg
);
385 if ( ! CheckThatPortNumberIsUsable(gPortNumber
, mDNStrue
) ) {
390 gServiceFile
= optarg
;
399 while (optind
< argc
)
401 gServiceText
[gServiceTextLen
] = strlen(argv
[optind
]);
402 memcpy(gServiceText
+gServiceTextLen
+1, argv
[optind
], gServiceText
[gServiceTextLen
]);
403 gServiceTextLen
+= 1 + gServiceText
[gServiceTextLen
];
417 // Check for any left over command line arguments.
419 if (optind
!= argc
) {
421 fprintf(stderr
, "%s: Unexpected argument '%s'\n", gProgramName
, argv
[optind
]);
425 // Check for inconsistency between the arguments.
427 if ( (gServiceName
[0] == 0) && (gServiceFile
[0] == 0) ) {
429 fprintf(stderr
, "%s: You must specify a service name to register (-n) or a service file (-f).\n", gProgramName
);
434 #if COMPILER_LIKES_PRAGMA_MARK
435 #pragma mark ***** Registration
438 typedef struct PosixService PosixService
;
440 struct PosixService
{
441 ServiceRecordSet coreServ
;
446 static PosixService
*gServiceList
= NULL
;
448 static void RegistrationCallback(mDNS
*const m
, ServiceRecordSet
*const thisRegistration
, mStatus status
)
449 // mDNS core calls this routine to tell us about the status of
450 // our registration. The appropriate action to take depends
451 // entirely on the value of status.
455 case mStatus_NoError
:
456 debugf("Callback: %##s Name Registered", thisRegistration
->RR_SRV
.resrec
.name
->c
);
457 // Do nothing; our name was successfully registered. We may
458 // get more call backs in the future.
461 case mStatus_NameConflict
:
462 debugf("Callback: %##s Name Conflict", thisRegistration
->RR_SRV
.resrec
.name
->c
);
464 // In the event of a conflict, this sample RegistrationCallback
465 // just calls mDNS_RenameAndReregisterService to automatically
466 // pick a new unique name for the service. For a device such as a
467 // printer, this may be appropriate. For a device with a user
468 // interface, and a screen, and a keyboard, the appropriate response
469 // may be to prompt the user and ask them to choose a new name for
472 // Also, what do we do if mDNS_RenameAndReregisterService returns an
473 // error. Right now I have no place to send that error to.
475 status
= mDNS_RenameAndReregisterService(m
, thisRegistration
, mDNSNULL
);
476 assert(status
== mStatus_NoError
);
479 case mStatus_MemFree
:
480 debugf("Callback: %##s Memory Free", thisRegistration
->RR_SRV
.resrec
.name
->c
);
482 // When debugging is enabled, make sure that thisRegistration
483 // is not on our gServiceList.
487 PosixService
*cursor
;
489 cursor
= gServiceList
;
490 while (cursor
!= NULL
) {
491 assert(&cursor
->coreServ
!= thisRegistration
);
492 cursor
= cursor
->next
;
496 free(thisRegistration
);
500 debugf("Callback: %##s Unknown Status %ld", thisRegistration
->RR_SRV
.resrec
.name
->c
, status
);
505 static int gServiceID
= 0;
507 static mStatus
RegisterOneService(const char * richTextName
,
508 const char * serviceType
,
509 const char * serviceDomain
,
515 PosixService
* thisServ
;
520 status
= mStatus_NoError
;
521 thisServ
= (PosixService
*) malloc(sizeof(*thisServ
));
522 if (thisServ
== NULL
) {
523 status
= mStatus_NoMemoryErr
;
525 if (status
== mStatus_NoError
) {
526 MakeDomainLabelFromLiteralString(&name
, richTextName
);
527 MakeDomainNameFromDNSNameString(&type
, serviceType
);
528 MakeDomainNameFromDNSNameString(&domain
, serviceDomain
);
529 status
= mDNS_RegisterService(&mDNSStorage
, &thisServ
->coreServ
,
530 &name
, &type
, &domain
, // Name, type, domain
531 NULL
, mDNSOpaque16fromIntVal(portNumber
),
532 text
, textLen
, // TXT data, length
534 mDNSInterface_Any
, // Interface ID
535 RegistrationCallback
, thisServ
); // Callback and context
537 if (status
== mStatus_NoError
) {
538 thisServ
->serviceID
= gServiceID
;
541 thisServ
->next
= gServiceList
;
542 gServiceList
= thisServ
;
544 if (gMDNSPlatformPosixVerboseLevel
> 0) {
546 "%s: Registered service %d, name '%s', type '%s', port %ld\n",
554 if (thisServ
!= NULL
) {
561 static mDNSBool
ReadALine(char *buf
, size_t bufSize
, FILE *fp
)
562 // Read a line, skipping over any blank lines or lines starting with '#'
566 good
= (fgets(buf
, bufSize
, fp
) != NULL
);
567 skip
= (good
&& (buf
[0] == '#'));
568 } while (good
&& skip
);
571 int len
= strlen( buf
);
572 if ( buf
[len
- 1] == '\r' || buf
[len
- 1] == '\n')
578 static mStatus
RegisterServicesInFile(const char *filePath
)
580 mStatus status
= mStatus_NoError
;
581 FILE * fp
= fopen(filePath
, "r");
585 status
= mStatus_UnknownErr
;
587 if (status
== mStatus_NoError
) {
588 mDNSBool good
= mDNStrue
;
593 const char *dom
= kDefaultServiceDomain
;
595 mDNSu8 text
[sizeof(RDataBody
)];
596 unsigned int textLen
= 0;
599 // Skip over any blank lines.
600 do ch
= fgetc(fp
); while ( ch
== '\n' || ch
== '\r' );
601 if (ch
!= EOF
) good
= (ungetc(ch
, fp
) == ch
);
603 // Read three lines, check them for validity, and register the service.
604 good
= ReadALine(name
, sizeof(name
), fp
);
606 good
= ReadALine(type
, sizeof(type
), fp
);
610 while (*p
&& *p
!= ' ') p
++;
617 good
= ReadALine(port
, sizeof(port
), fp
);
620 good
= CheckThatRichTextNameIsUsable(name
, mDNSfalse
)
621 && CheckThatServiceTypeIsUsable(type
, mDNSfalse
)
622 && CheckThatPortNumberIsUsable(atol(port
), mDNSfalse
);
627 if (!ReadALine(rawText
, sizeof(rawText
), fp
)) break;
628 len
= strlen(rawText
);
631 unsigned int newlen
= textLen
+ 1 + len
;
632 if (len
== 0 || newlen
>= sizeof(text
)) break;
634 memcpy(text
+ textLen
+ 1, rawText
, len
);
638 fprintf(stderr
, "%s: TXT attribute too long for name = %s, type = %s, port = %s\n",
639 gProgramName
, name
, type
, port
);
643 status
= RegisterOneService(name
, type
, dom
, text
, textLen
, atol(port
));
644 if (status
!= mStatus_NoError
) {
645 fprintf(stderr
, "%s: Failed to register service, name = %s, type = %s, port = %s\n",
646 gProgramName
, name
, type
, port
);
647 status
= mStatus_NoError
; // keep reading
650 } while (good
&& !feof(fp
));
653 fprintf(stderr
, "%s: Error reading service file %s\n", gProgramName
, filePath
);
665 static mStatus
RegisterOurServices(void)
669 status
= mStatus_NoError
;
670 if (gServiceName
[0] != 0) {
671 status
= RegisterOneService(gServiceName
,
674 gServiceText
, gServiceTextLen
,
677 if (status
== mStatus_NoError
&& gServiceFile
[0] != 0) {
678 status
= RegisterServicesInFile(gServiceFile
);
683 static void DeregisterOurServices(void)
685 PosixService
*thisServ
;
688 while (gServiceList
!= NULL
) {
689 thisServ
= gServiceList
;
690 gServiceList
= thisServ
->next
;
692 thisServID
= thisServ
->serviceID
;
694 mDNS_DeregisterService(&mDNSStorage
, &thisServ
->coreServ
);
696 if (gMDNSPlatformPosixVerboseLevel
> 0) {
698 "%s: Deregistered service %d\n",
700 thisServ
->serviceID
);
705 #if COMPILER_LIKES_PRAGMA_MARK
706 #pragma mark **** Main
709 int main(int argc
, char **argv
)
714 // Parse our command line arguments. This won't come back if there's an error.
716 ParseArguments(argc
, argv
);
718 // If we're told to run as a daemon, then do that straight away.
719 // Note that we don't treat the inability to create our PID
720 // file as an error. Also note that we assign getpid to a long
721 // because printf has no format specified for pid_t.
724 if (gMDNSPlatformPosixVerboseLevel
> 0) {
725 fprintf(stderr
, "%s: Starting in daemon mode\n", gProgramName
);
732 fp
= fopen(gPIDFile
, "w");
734 fprintf(fp
, "%ld\n", (long) getpid());
740 if (gMDNSPlatformPosixVerboseLevel
> 0) {
741 fprintf(stderr
, "%s: Starting in foreground mode, PID %ld\n", gProgramName
, (long) getpid());
745 status
= mDNS_Init(&mDNSStorage
, &PlatformStorage
,
746 mDNS_Init_NoCache
, mDNS_Init_ZeroCacheSize
,
747 mDNS_Init_AdvertiseLocalAddresses
,
748 mDNS_Init_NoInitCallback
, mDNS_Init_NoInitCallbackContext
);
749 if (status
!= mStatus_NoError
) return(2);
751 status
= RegisterOurServices();
752 if (status
!= mStatus_NoError
) return(2);
754 signal(SIGHUP
, HandleSigHup
); // SIGHUP has to be sent by kill -HUP <pid>
755 signal(SIGINT
, HandleSigInt
); // SIGINT is what you get for a Ctrl-C
756 signal(SIGQUIT
, HandleSigQuit
); // SIGQUIT is what you get for a Ctrl-\ (indeed)
757 signal(SIGUSR1
, HandleSigUsr1
); // SIGUSR1 has to be sent by kill -USR1 <pid>
763 struct timeval timeout
;
766 // 1. Set up the fd_set as usual here.
767 // This example client has no file descriptors of its own,
768 // but a real application would call FD_SET to add them to the set here
771 // 2. Set up the timeout.
772 // This example client has no other work it needs to be doing,
773 // so we set an effectively infinite timeout
774 timeout
.tv_sec
= 0x3FFFFFFF;
777 // 3. Give the mDNSPosix layer a chance to add its information to the fd_set and timeout
778 mDNSPosixGetFDSet(&mDNSStorage
, &nfds
, &readfds
, &timeout
);
780 // 4. Call select as normal
781 verbosedebugf("select(%d, %d.%06d)", nfds
, timeout
.tv_sec
, timeout
.tv_usec
);
782 result
= select(nfds
, &readfds
, NULL
, NULL
, &timeout
);
786 verbosedebugf("select() returned %d errno %d", result
, errno
);
787 if (errno
!= EINTR
) gStopNow
= mDNStrue
;
790 if (gReceivedSigUsr1
)
792 gReceivedSigUsr1
= mDNSfalse
;
793 gMDNSPlatformPosixVerboseLevel
+= 1;
794 if (gMDNSPlatformPosixVerboseLevel
> 2)
795 gMDNSPlatformPosixVerboseLevel
= 0;
796 if ( gMDNSPlatformPosixVerboseLevel
> 0 )
797 fprintf(stderr
, "\nVerbose level %d\n", gMDNSPlatformPosixVerboseLevel
);
801 if (gMDNSPlatformPosixVerboseLevel
> 0)
802 fprintf(stderr
, "\nSIGHUP\n");
803 gReceivedSigHup
= mDNSfalse
;
804 DeregisterOurServices();
805 status
= mDNSPlatformPosixRefreshInterfaceList(&mDNSStorage
);
806 if (status
!= mStatus_NoError
) break;
807 status
= RegisterOurServices();
808 if (status
!= mStatus_NoError
) break;
814 // 5. Call mDNSPosixProcessFDSet to let the mDNSPosix layer do its work
815 mDNSPosixProcessFDSet(&mDNSStorage
, &readfds
);
817 // 6. This example client has no other work it needs to be doing,
818 // but a real client would do its work here
825 DeregisterOurServices();
826 mDNS_Close(&mDNSStorage
);
828 if (status
== mStatus_NoError
) {
833 if ( (result
!= 0) || (gMDNSPlatformPosixVerboseLevel
> 0) ) {
834 fprintf(stderr
, "%s: Finished with status %d, result %d\n", gProgramName
, (int)status
, result
);