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.27 2004/12/01 04:28:43 cheshire
28 <rdar://problem/3872803> Darwin patches for Solaris and Suse
29 Use version of daemon() provided in mDNSUNP.c instead of local copy
31 Revision 1.26 2004/11/30 22:37:01 cheshire
32 Update copyright dates and add "Mode: C; tab-width: 4" headers
34 Revision 1.25 2004/11/11 02:00:51 cheshire
35 Minor fixes to getopt, error message
37 Revision 1.24 2004/11/09 19:32:10 rpantos
38 Suggestion from Ademar de Souza Reis Jr. to allow comments in services file
40 Revision 1.23 2004/09/17 01:08:54 cheshire
41 Renamed mDNSClientAPI.h to mDNSEmbeddedAPI.h
42 The name "mDNSClientAPI.h" is misleading to new developers looking at this code. The interfaces
43 declared in that file are ONLY appropriate to single-address-space embedded applications.
44 For clients on general-purpose computers, the interfaces defined in dns_sd.h should be used.
46 Revision 1.22 2004/09/16 01:58:22 cheshire
49 Revision 1.21 2004/06/15 03:48:07 cheshire
50 Update mDNSResponderPosix to take multiple name=val arguments in a sane way
52 Revision 1.20 2004/05/18 23:51:26 cheshire
53 Tidy up all checkin comments to use consistent "<rdar://problem/xxxxxxx>" format for bug numbers
55 Revision 1.19 2004/03/12 08:03:14 cheshire
58 Revision 1.18 2004/01/25 00:00:55 cheshire
59 Change to use mDNSOpaque16fromIntVal() instead of shifting and masking
61 Revision 1.17 2003/12/11 19:11:55 cheshire
64 Revision 1.16 2003/08/14 02:19:55 cheshire
65 <rdar://problem/3375491> Split generic ResourceRecord type into two separate types: AuthRecord and CacheRecord
67 Revision 1.15 2003/08/12 19:56:26 cheshire
70 Revision 1.14 2003/08/06 18:20:51 cheshire
73 Revision 1.13 2003/07/23 00:00:04 cheshire
76 Revision 1.12 2003/07/15 01:55:16 cheshire
77 <rdar://problem/3315777> Need to implement service registration with subtypes
79 Revision 1.11 2003/07/14 18:11:54 cheshire
80 Fix stricter compiler warnings
82 Revision 1.10 2003/07/10 20:27:31 cheshire
83 <rdar://problem/3318717> mDNSResponder Posix version is missing a 'b' in the getopt option string
85 Revision 1.9 2003/07/02 21:19:59 cheshire
86 <rdar://problem/3313413> Update copyright notices, etc., in source code comments
88 Revision 1.8 2003/06/18 05:48:41 cheshire
91 Revision 1.7 2003/05/06 00:00:50 cheshire
92 <rdar://problem/3248914> Rationalize naming of domainname manipulation functions
94 Revision 1.6 2003/03/08 00:35:56 cheshire
95 Switched to using new "mDNS_Execute" model (see "mDNSCore/Implementer Notes.txt")
97 Revision 1.5 2003/02/20 06:48:36 cheshire
98 <rdar://problem/3169535> Xserve RAID needs to do interface-specific registrations
99 Reviewed by: Josh Graessley, Bob Bradley
101 Revision 1.4 2003/01/28 03:07:46 cheshire
102 Add extra parameter to mDNS_RenameAndReregisterService(),
103 and add support for specifying a domain other than dot-local.
105 Revision 1.3 2002/09/21 20:44:53 zarzycki
108 Revision 1.2 2002/09/19 04:20:44 cheshire
109 Remove high-ascii characters that confuse some systems
111 Revision 1.1 2002/09/17 06:24:35 cheshire
116 #include "mDNSEmbeddedAPI.h"// Defines the interface to the client layer above
117 #include "mDNSPosix.h" // Defines the specific types needed to run mDNS on this platform
120 #include <stdio.h> // For printf()
121 #include <stdlib.h> // For exit() etc.
122 #include <string.h> // For strlen() etc.
123 #include <unistd.h> // For select()
124 #include <errno.h> // For errno, EINTR
128 #if COMPILER_LIKES_PRAGMA_MARK
129 #pragma mark ***** Globals
132 static mDNS mDNSStorage
; // mDNS core uses this to store its globals
133 static mDNS_PlatformSupport PlatformStorage
; // Stores this platform's globals
135 static const char *gProgramName
= "mDNSResponderPosix";
137 #if COMPILER_LIKES_PRAGMA_MARK
138 #pragma mark ***** Signals
141 static volatile mDNSBool gReceivedSigUsr1
;
142 static volatile mDNSBool gReceivedSigHup
;
143 static volatile mDNSBool gStopNow
;
145 // We support 4 signals.
147 // o SIGUSR1 toggles verbose mode on and off in debug builds
148 // o SIGHUP triggers the program to re-read its preferences.
149 // o SIGINT causes an orderly shutdown of the program.
150 // o SIGQUIT causes a somewhat orderly shutdown (direct but dangerous)
151 // o SIGKILL kills us dead (easy to implement :-)
153 // There are fatal race conditions in our signal handling, but there's not much
154 // we can do about them while remaining within the Posix space. Specifically,
155 // if a signal arrives after we test the globals its sets but before we call
156 // select, the signal will be dropped. The user will have to send the signal
157 // again. Unfortunately, Posix does not have a "sigselect" to atomically
158 // modify the signal mask and start a select.
160 static void HandleSigUsr1(int sigraised
)
161 // If we get a SIGUSR1 we toggle the state of the
164 assert(sigraised
== SIGUSR1
);
165 gReceivedSigUsr1
= mDNStrue
;
168 static void HandleSigHup(int sigraised
)
169 // A handler for SIGHUP that causes us to break out of the
170 // main event loop when the user kill 1's us. This has the
171 // effect of triggered the main loop to deregister the
172 // current services and re-read the preferences.
174 assert(sigraised
== SIGHUP
);
175 gReceivedSigHup
= mDNStrue
;
178 static void HandleSigInt(int sigraised
)
179 // A handler for SIGINT that causes us to break out of the
180 // main event loop when the user types ^C. This has the
181 // effect of quitting the program.
183 assert(sigraised
== SIGINT
);
185 if (gMDNSPlatformPosixVerboseLevel
> 0) {
186 fprintf(stderr
, "\nSIGINT\n");
191 static void HandleSigQuit(int sigraised
)
192 // If we get a SIGQUIT the user is desperate and we
193 // just call mDNS_Close directly. This is definitely
194 // not safe (because it could reenter mDNS), but
195 // we presume that the user has already tried the safe
198 assert(sigraised
== SIGQUIT
);
200 if (gMDNSPlatformPosixVerboseLevel
> 0) {
201 fprintf(stderr
, "\nSIGQUIT\n");
203 mDNS_Close(&mDNSStorage
);
207 #if COMPILER_LIKES_PRAGMA_MARK
208 #pragma mark ***** Parameter Checking
211 static mDNSBool
CheckThatRichTextHostNameIsUsable(const char *richTextHostName
, mDNSBool printExplanation
)
212 // Checks that richTextHostName is a reasonable host name
213 // label and, if it isn't and printExplanation is true, prints
214 // an explanation of why not.
217 domainlabel richLabel
;
218 domainlabel poorLabel
;
221 if (result
&& strlen(richTextHostName
) > 63) {
222 if (printExplanation
) {
224 "%s: Host name is too long (must be 63 characters or less)\n",
229 if (result
&& richTextHostName
[0] == 0) {
230 if (printExplanation
) {
231 fprintf(stderr
, "%s: Host name can't be empty\n", gProgramName
);
236 MakeDomainLabelFromLiteralString(&richLabel
, richTextHostName
);
237 ConvertUTF8PstringToRFC1034HostLabel(richLabel
.c
, &poorLabel
);
238 if (poorLabel
.c
[0] == 0) {
239 if (printExplanation
) {
241 "%s: Host name doesn't produce a usable RFC-1034 name\n",
250 static mDNSBool
CheckThatServiceTypeIsUsable(const char *serviceType
, mDNSBool printExplanation
)
251 // Checks that serviceType is a reasonable service type
252 // label and, if it isn't and printExplanation is true, prints
253 // an explanation of why not.
258 if (result
&& strlen(serviceType
) > 63) {
259 if (printExplanation
) {
261 "%s: Service type is too long (must be 63 characters or less)\n",
266 if (result
&& serviceType
[0] == 0) {
267 if (printExplanation
) {
269 "%s: Service type can't be empty\n",
277 static mDNSBool
CheckThatPortNumberIsUsable(long portNumber
, mDNSBool printExplanation
)
278 // Checks that portNumber is a reasonable port number
279 // and, if it isn't and printExplanation is true, prints
280 // an explanation of why not.
285 if (result
&& (portNumber
<= 0 || portNumber
> 65535)) {
286 if (printExplanation
) {
288 "%s: Port number specified by -p must be in range 1..65535\n",
296 #if COMPILER_LIKES_PRAGMA_MARK
297 #pragma mark ***** Command Line Arguments
300 static const char kDefaultPIDFile
[] = "/var/run/mDNSResponder.pid";
301 static const char kDefaultServiceType
[] = "_afpovertcp._tcp.";
302 static const char kDefaultServiceDomain
[] = "local.";
304 kDefaultPortNumber
= 548
307 static void PrintUsage()
310 "Usage: %s [-v level ] [-r] [-n name] [-t type] [-d domain] [-p port] [-f file] [-b] [-P pidfile] [-x name=val ...]\n",
312 fprintf(stderr
, " -v verbose mode, level is a number from 0 to 2\n");
313 fprintf(stderr
, " 0 = no debugging info (default)\n");
314 fprintf(stderr
, " 1 = standard debugging info\n");
315 fprintf(stderr
, " 2 = intense debugging info\n");
316 fprintf(stderr
, " can be cycled kill -USR1\n");
317 fprintf(stderr
, " -r also bind to port 53 (port 5353 is always bound)\n");
318 fprintf(stderr
, " -n uses 'name' as the host name (default is none)\n");
319 fprintf(stderr
, " -t uses 'type' as the service type (default is '%s')\n", kDefaultServiceType
);
320 fprintf(stderr
, " -d uses 'domain' as the service domain (default is '%s')\n", kDefaultServiceDomain
);
321 fprintf(stderr
, " -p uses 'port' as the port number (default is '%d')\n", kDefaultPortNumber
);
322 fprintf(stderr
, " -f reads a service list from 'file'\n");
323 fprintf(stderr
, " -b forces daemon (background) mode\n");
324 fprintf(stderr
, " -P uses 'pidfile' as the PID file\n");
325 fprintf(stderr
, " (default is '%s')\n", kDefaultPIDFile
);
326 fprintf(stderr
, " only meaningful if -b also specified\n");
327 fprintf(stderr
, " -x stores name=val in TXT record (default is empty).\n");
328 fprintf(stderr
, " MUST be the last command-line argument;\n");
329 fprintf(stderr
, " all subsequent arguments after -x are treated as name=val pairs.\n");
332 static mDNSBool gAvoidPort53
= mDNStrue
;
333 static const char *gRichTextHostName
= "";
334 static const char *gServiceType
= kDefaultServiceType
;
335 static const char *gServiceDomain
= kDefaultServiceDomain
;
336 static mDNSu8 gServiceText
[sizeof(RDataBody
)];
337 static mDNSu16 gServiceTextLen
= 0;
338 static int gPortNumber
= kDefaultPortNumber
;
339 static const char *gServiceFile
= "";
340 static mDNSBool gDaemon
= mDNSfalse
;
341 static const char *gPIDFile
= kDefaultPIDFile
;
343 static void ParseArguments(int argc
, char **argv
)
344 // Parses our command line arguments into the global variables
349 // Set gProgramName to the last path component of argv[0]
351 gProgramName
= strrchr(argv
[0], '/');
352 if (gProgramName
== NULL
) {
353 gProgramName
= argv
[0];
358 // Parse command line options using getopt.
361 ch
= getopt(argc
, argv
, "v:rn:t:d:p:f:dP:bx");
365 gMDNSPlatformPosixVerboseLevel
= atoi(optarg
);
366 if (gMDNSPlatformPosixVerboseLevel
< 0 || gMDNSPlatformPosixVerboseLevel
> 2) {
368 "%s: Verbose mode must be in the range 0..2\n",
374 gAvoidPort53
= mDNSfalse
;
377 gRichTextHostName
= optarg
;
378 if ( ! CheckThatRichTextHostNameIsUsable(gRichTextHostName
, mDNStrue
) ) {
383 gServiceType
= optarg
;
384 if ( ! CheckThatServiceTypeIsUsable(gServiceType
, mDNStrue
) ) {
389 gServiceDomain
= optarg
;
392 gPortNumber
= atol(optarg
);
393 if ( ! CheckThatPortNumberIsUsable(gPortNumber
, mDNStrue
) ) {
398 gServiceFile
= optarg
;
407 while (optind
< argc
)
409 gServiceText
[gServiceTextLen
] = strlen(argv
[optind
]);
410 memcpy(gServiceText
+gServiceTextLen
+1, argv
[optind
], gServiceText
[gServiceTextLen
]);
411 gServiceTextLen
+= 1 + gServiceText
[gServiceTextLen
];
425 // Check for any left over command line arguments.
427 if (optind
!= argc
) {
429 fprintf(stderr
, "%s: Unexpected argument '%s'\n", gProgramName
, argv
[optind
]);
433 // Check for inconsistency between the arguments.
435 if ( (gRichTextHostName
[0] == 0) && (gServiceFile
[0] == 0) ) {
437 fprintf(stderr
, "%s: You must specify a service to register (-n) or a service file (-f).\n", gProgramName
);
442 #if COMPILER_LIKES_PRAGMA_MARK
443 #pragma mark ***** Registration
446 typedef struct PosixService PosixService
;
448 struct PosixService
{
449 ServiceRecordSet coreServ
;
454 static PosixService
*gServiceList
= NULL
;
456 static void RegistrationCallback(mDNS
*const m
, ServiceRecordSet
*const thisRegistration
, mStatus status
)
457 // mDNS core calls this routine to tell us about the status of
458 // our registration. The appropriate action to take depends
459 // entirely on the value of status.
463 case mStatus_NoError
:
464 debugf("Callback: %##s Name Registered", thisRegistration
->RR_SRV
.resrec
.name
.c
);
465 // Do nothing; our name was successfully registered. We may
466 // get more call backs in the future.
469 case mStatus_NameConflict
:
470 debugf("Callback: %##s Name Conflict", thisRegistration
->RR_SRV
.resrec
.name
.c
);
472 // In the event of a conflict, this sample RegistrationCallback
473 // just calls mDNS_RenameAndReregisterService to automatically
474 // pick a new unique name for the service. For a device such as a
475 // printer, this may be appropriate. For a device with a user
476 // interface, and a screen, and a keyboard, the appropriate response
477 // may be to prompt the user and ask them to choose a new name for
480 // Also, what do we do if mDNS_RenameAndReregisterService returns an
481 // error. Right now I have no place to send that error to.
483 status
= mDNS_RenameAndReregisterService(m
, thisRegistration
, mDNSNULL
);
484 assert(status
== mStatus_NoError
);
487 case mStatus_MemFree
:
488 debugf("Callback: %##s Memory Free", thisRegistration
->RR_SRV
.resrec
.name
.c
);
490 // When debugging is enabled, make sure that thisRegistration
491 // is not on our gServiceList.
495 PosixService
*cursor
;
497 cursor
= gServiceList
;
498 while (cursor
!= NULL
) {
499 assert(&cursor
->coreServ
!= thisRegistration
);
500 cursor
= cursor
->next
;
504 free(thisRegistration
);
508 debugf("Callback: %##s Unknown Status %ld", thisRegistration
->RR_SRV
.resrec
.name
.c
, status
);
513 static int gServiceID
= 0;
515 static mStatus
RegisterOneService(const char * richTextHostName
,
516 const char * serviceType
,
517 const char * serviceDomain
,
523 PosixService
* thisServ
;
528 status
= mStatus_NoError
;
529 thisServ
= (PosixService
*) malloc(sizeof(*thisServ
));
530 if (thisServ
== NULL
) {
531 status
= mStatus_NoMemoryErr
;
533 if (status
== mStatus_NoError
) {
534 MakeDomainLabelFromLiteralString(&name
, richTextHostName
);
535 MakeDomainNameFromDNSNameString(&type
, serviceType
);
536 MakeDomainNameFromDNSNameString(&domain
, serviceDomain
);
537 status
= mDNS_RegisterService(&mDNSStorage
, &thisServ
->coreServ
,
538 &name
, &type
, &domain
, // Name, type, domain
539 NULL
, mDNSOpaque16fromIntVal(portNumber
),
540 text
, textLen
, // TXT data, length
542 mDNSInterface_Any
, // Interface ID
543 RegistrationCallback
, thisServ
); // Callback and context
545 if (status
== mStatus_NoError
) {
546 thisServ
->serviceID
= gServiceID
;
549 thisServ
->next
= gServiceList
;
550 gServiceList
= thisServ
;
552 if (gMDNSPlatformPosixVerboseLevel
> 0) {
554 "%s: Registered service %d, name '%s', type '%s', port %ld\n",
562 if (thisServ
!= NULL
) {
569 static mDNSBool
ReadALine(char *buf
, size_t bufSize
, FILE *fp
)
570 // Read a line, skipping over any blank lines or lines starting with '#'
574 good
= (fgets(buf
, bufSize
, fp
) != NULL
);
575 skip
= (good
&& (buf
[0] == '#' || buf
[0] == '\r' || buf
[0] == '\n'));
576 } while (good
&& skip
);
579 int len
= strlen( buf
);
580 if ( buf
[len
- 1] == '\r' || buf
[len
- 1] == '\n')
586 static mStatus
RegisterServicesInFile(const char *filePath
)
588 mStatus status
= mStatus_NoError
;
589 FILE * fp
= fopen(filePath
, "r");
593 status
= mStatus_UnknownErr
;
595 if (status
== mStatus_NoError
) {
596 mDNSBool good
= mDNStrue
;
600 const char *dom
= kDefaultServiceDomain
;
602 mDNSu8 text
[sizeof(RDataBody
)];
606 // Read three lines, check them for validity, and register the service.
607 good
= ReadALine(name
, sizeof(name
), fp
);
609 good
= ReadALine(type
, sizeof(type
), fp
);
613 while (*p
&& *p
!= ' ') p
++;
620 good
= ReadALine(port
, sizeof(port
), fp
);
623 good
= CheckThatRichTextHostNameIsUsable(name
, mDNSfalse
)
624 && CheckThatServiceTypeIsUsable(type
, mDNSfalse
)
625 && CheckThatPortNumberIsUsable(atol(port
), mDNSfalse
);
629 if (!ReadALine(rawText
, sizeof(rawText
), fp
)) break;
630 text
[textLen
] = strlen(rawText
);
631 if (text
[textLen
] == 0) break;
632 memcpy(text
+ textLen
+ 1, rawText
, text
[textLen
]);
633 textLen
+= 1 + text
[textLen
];
637 status
= RegisterOneService(name
, type
, dom
, text
, textLen
, atol(port
));
638 if (status
!= mStatus_NoError
) {
640 "%s: Failed to register service, name = %s, type = %s, port = %s\n",
645 status
= mStatus_NoError
; // keep reading
648 } while (good
&& !feof(fp
));
651 fprintf(stderr
, "%s: Error reading service file %s\n", gProgramName
, filePath
);
663 static mStatus
RegisterOurServices(void)
667 status
= mStatus_NoError
;
668 if (gRichTextHostName
[0] != 0) {
669 status
= RegisterOneService(gRichTextHostName
,
672 gServiceText
, gServiceTextLen
,
675 if (status
== mStatus_NoError
&& gServiceFile
[0] != 0) {
676 status
= RegisterServicesInFile(gServiceFile
);
681 static void DeregisterOurServices(void)
683 PosixService
*thisServ
;
686 while (gServiceList
!= NULL
) {
687 thisServ
= gServiceList
;
688 gServiceList
= thisServ
->next
;
690 thisServID
= thisServ
->serviceID
;
692 mDNS_DeregisterService(&mDNSStorage
, &thisServ
->coreServ
);
694 if (gMDNSPlatformPosixVerboseLevel
> 0) {
696 "%s: Deregistered service %d\n",
698 thisServ
->serviceID
);
703 #if COMPILER_LIKES_PRAGMA_MARK
704 #pragma mark **** Main
707 int main(int argc
, char **argv
)
712 // Parse our command line arguments. This won't come back if there's an error.
714 ParseArguments(argc
, argv
);
716 // If we're told to run as a daemon, then do that straight away.
717 // Note that we don't treat the inability to create our PID
718 // file as an error. Also note that we assign getpid to a long
719 // because printf has no format specified for pid_t.
722 if (gMDNSPlatformPosixVerboseLevel
> 0) {
723 fprintf(stderr
, "%s: Starting in daemon mode\n", gProgramName
);
730 fp
= fopen(gPIDFile
, "w");
732 fprintf(fp
, "%ld\n", (long) getpid());
738 if (gMDNSPlatformPosixVerboseLevel
> 0) {
739 fprintf(stderr
, "%s: Starting in foreground mode, PID %ld\n", gProgramName
, (long) getpid());
743 status
= mDNS_Init(&mDNSStorage
, &PlatformStorage
,
744 mDNS_Init_NoCache
, mDNS_Init_ZeroCacheSize
,
745 mDNS_Init_AdvertiseLocalAddresses
,
746 mDNS_Init_NoInitCallback
, mDNS_Init_NoInitCallbackContext
);
747 if (status
!= mStatus_NoError
) return(2);
749 status
= RegisterOurServices();
750 if (status
!= mStatus_NoError
) return(2);
752 signal(SIGHUP
, HandleSigHup
); // SIGHUP has to be sent by kill -HUP <pid>
753 signal(SIGINT
, HandleSigInt
); // SIGINT is what you get for a Ctrl-C
754 signal(SIGQUIT
, HandleSigQuit
); // SIGQUIT is what you get for a Ctrl-\ (indeed)
755 signal(SIGUSR1
, HandleSigUsr1
); // SIGUSR1 has to be sent by kill -USR1 <pid>
761 struct timeval timeout
;
764 // 1. Set up the fd_set as usual here.
765 // This example client has no file descriptors of its own,
766 // but a real application would call FD_SET to add them to the set here
769 // 2. Set up the timeout.
770 // This example client has no other work it needs to be doing,
771 // so we set an effectively infinite timeout
772 timeout
.tv_sec
= 0x3FFFFFFF;
775 // 3. Give the mDNSPosix layer a chance to add its information to the fd_set and timeout
776 mDNSPosixGetFDSet(&mDNSStorage
, &nfds
, &readfds
, &timeout
);
778 // 4. Call select as normal
779 verbosedebugf("select(%d, %d.%06d)", nfds
, timeout
.tv_sec
, timeout
.tv_usec
);
780 result
= select(nfds
, &readfds
, NULL
, NULL
, &timeout
);
784 verbosedebugf("select() returned %d errno %d", result
, errno
);
785 if (errno
!= EINTR
) gStopNow
= mDNStrue
;
788 if (gReceivedSigUsr1
)
790 gReceivedSigUsr1
= mDNSfalse
;
791 gMDNSPlatformPosixVerboseLevel
+= 1;
792 if (gMDNSPlatformPosixVerboseLevel
> 2)
793 gMDNSPlatformPosixVerboseLevel
= 0;
794 if ( gMDNSPlatformPosixVerboseLevel
> 0 )
795 fprintf(stderr
, "\nVerbose level %d\n", gMDNSPlatformPosixVerboseLevel
);
799 if (gMDNSPlatformPosixVerboseLevel
> 0)
800 fprintf(stderr
, "\nSIGHUP\n");
801 gReceivedSigHup
= mDNSfalse
;
802 DeregisterOurServices();
803 status
= mDNSPlatformPosixRefreshInterfaceList(&mDNSStorage
);
804 if (status
!= mStatus_NoError
) break;
805 status
= RegisterOurServices();
806 if (status
!= mStatus_NoError
) break;
812 // 5. Call mDNSPosixProcessFDSet to let the mDNSPosix layer do its work
813 mDNSPosixProcessFDSet(&mDNSStorage
, &readfds
);
815 // 6. This example client has no other work it needs to be doing,
816 // but a real client would do its work here
823 DeregisterOurServices();
824 mDNS_Close(&mDNSStorage
);
826 if (status
== mStatus_NoError
) {
831 if ( (result
!= 0) || (gMDNSPlatformPosixVerboseLevel
> 0) ) {
832 fprintf(stderr
, "%s: Finished with status %ld, result %d\n", gProgramName
, status
, result
);