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.30 2005/10/26 22:21:16 cheshire
28 <rdar://problem/4149841> Potential buffer overflow in mDNSResponderPosix
30 Revision 1.29 2005/03/04 21:35:33 cheshire
31 <rdar://problem/4037201> Services.txt file not parsed properly when it contains more than one service
33 Revision 1.28 2005/01/11 01:55:26 ksekar
34 Fix compile errors in Posix debug build
36 Revision 1.27 2004/12/01 04:28:43 cheshire
37 <rdar://problem/3872803> Darwin patches for Solaris and Suse
38 Use version of daemon() provided in mDNSUNP.c instead of local copy
40 Revision 1.26 2004/11/30 22:37:01 cheshire
41 Update copyright dates and add "Mode: C; tab-width: 4" headers
43 Revision 1.25 2004/11/11 02:00:51 cheshire
44 Minor fixes to getopt, error message
46 Revision 1.24 2004/11/09 19:32:10 rpantos
47 Suggestion from Ademar de Souza Reis Jr. to allow comments in services file
49 Revision 1.23 2004/09/17 01:08:54 cheshire
50 Renamed mDNSClientAPI.h to mDNSEmbeddedAPI.h
51 The name "mDNSClientAPI.h" is misleading to new developers looking at this code. The interfaces
52 declared in that file are ONLY appropriate to single-address-space embedded applications.
53 For clients on general-purpose computers, the interfaces defined in dns_sd.h should be used.
55 Revision 1.22 2004/09/16 01:58:22 cheshire
58 Revision 1.21 2004/06/15 03:48:07 cheshire
59 Update mDNSResponderPosix to take multiple name=val arguments in a sane way
61 Revision 1.20 2004/05/18 23:51:26 cheshire
62 Tidy up all checkin comments to use consistent "<rdar://problem/xxxxxxx>" format for bug numbers
64 Revision 1.19 2004/03/12 08:03:14 cheshire
67 Revision 1.18 2004/01/25 00:00:55 cheshire
68 Change to use mDNSOpaque16fromIntVal() instead of shifting and masking
70 Revision 1.17 2003/12/11 19:11:55 cheshire
73 Revision 1.16 2003/08/14 02:19:55 cheshire
74 <rdar://problem/3375491> Split generic ResourceRecord type into two separate types: AuthRecord and CacheRecord
76 Revision 1.15 2003/08/12 19:56:26 cheshire
79 Revision 1.14 2003/08/06 18:20:51 cheshire
82 Revision 1.13 2003/07/23 00:00:04 cheshire
85 Revision 1.12 2003/07/15 01:55:16 cheshire
86 <rdar://problem/3315777> Need to implement service registration with subtypes
88 Revision 1.11 2003/07/14 18:11:54 cheshire
89 Fix stricter compiler warnings
91 Revision 1.10 2003/07/10 20:27:31 cheshire
92 <rdar://problem/3318717> mDNSResponder Posix version is missing a 'b' in the getopt option string
94 Revision 1.9 2003/07/02 21:19:59 cheshire
95 <rdar://problem/3313413> Update copyright notices, etc., in source code comments
97 Revision 1.8 2003/06/18 05:48:41 cheshire
100 Revision 1.7 2003/05/06 00:00:50 cheshire
101 <rdar://problem/3248914> Rationalize naming of domainname manipulation functions
103 Revision 1.6 2003/03/08 00:35:56 cheshire
104 Switched to using new "mDNS_Execute" model (see "mDNSCore/Implementer Notes.txt")
106 Revision 1.5 2003/02/20 06:48:36 cheshire
107 <rdar://problem/3169535> Xserve RAID needs to do interface-specific registrations
108 Reviewed by: Josh Graessley, Bob Bradley
110 Revision 1.4 2003/01/28 03:07:46 cheshire
111 Add extra parameter to mDNS_RenameAndReregisterService(),
112 and add support for specifying a domain other than dot-local.
114 Revision 1.3 2002/09/21 20:44:53 zarzycki
117 Revision 1.2 2002/09/19 04:20:44 cheshire
118 Remove high-ascii characters that confuse some systems
120 Revision 1.1 2002/09/17 06:24:35 cheshire
125 #include "mDNSEmbeddedAPI.h"// Defines the interface to the client layer above
126 #include "mDNSPosix.h" // Defines the specific types needed to run mDNS on this platform
129 #include <stdio.h> // For printf()
130 #include <stdlib.h> // For exit() etc.
131 #include <string.h> // For strlen() etc.
132 #include <unistd.h> // For select()
133 #include <errno.h> // For errno, EINTR
137 #if COMPILER_LIKES_PRAGMA_MARK
138 #pragma mark ***** Globals
141 static mDNS mDNSStorage
; // mDNS core uses this to store its globals
142 static mDNS_PlatformSupport PlatformStorage
; // Stores this platform's globals
144 static const char *gProgramName
= "mDNSResponderPosix";
146 #if COMPILER_LIKES_PRAGMA_MARK
147 #pragma mark ***** Signals
150 static volatile mDNSBool gReceivedSigUsr1
;
151 static volatile mDNSBool gReceivedSigHup
;
152 static volatile mDNSBool gStopNow
;
154 // We support 4 signals.
156 // o SIGUSR1 toggles verbose mode on and off in debug builds
157 // o SIGHUP triggers the program to re-read its preferences.
158 // o SIGINT causes an orderly shutdown of the program.
159 // o SIGQUIT causes a somewhat orderly shutdown (direct but dangerous)
160 // o SIGKILL kills us dead (easy to implement :-)
162 // There are fatal race conditions in our signal handling, but there's not much
163 // we can do about them while remaining within the Posix space. Specifically,
164 // if a signal arrives after we test the globals its sets but before we call
165 // select, the signal will be dropped. The user will have to send the signal
166 // again. Unfortunately, Posix does not have a "sigselect" to atomically
167 // modify the signal mask and start a select.
169 static void HandleSigUsr1(int sigraised
)
170 // If we get a SIGUSR1 we toggle the state of the
173 assert(sigraised
== SIGUSR1
);
174 gReceivedSigUsr1
= mDNStrue
;
177 static void HandleSigHup(int sigraised
)
178 // A handler for SIGHUP that causes us to break out of the
179 // main event loop when the user kill 1's us. This has the
180 // effect of triggered the main loop to deregister the
181 // current services and re-read the preferences.
183 assert(sigraised
== SIGHUP
);
184 gReceivedSigHup
= mDNStrue
;
187 static void HandleSigInt(int sigraised
)
188 // A handler for SIGINT that causes us to break out of the
189 // main event loop when the user types ^C. This has the
190 // effect of quitting the program.
192 assert(sigraised
== SIGINT
);
194 if (gMDNSPlatformPosixVerboseLevel
> 0) {
195 fprintf(stderr
, "\nSIGINT\n");
200 static void HandleSigQuit(int sigraised
)
201 // If we get a SIGQUIT the user is desperate and we
202 // just call mDNS_Close directly. This is definitely
203 // not safe (because it could reenter mDNS), but
204 // we presume that the user has already tried the safe
207 assert(sigraised
== SIGQUIT
);
209 if (gMDNSPlatformPosixVerboseLevel
> 0) {
210 fprintf(stderr
, "\nSIGQUIT\n");
212 mDNS_Close(&mDNSStorage
);
216 #if COMPILER_LIKES_PRAGMA_MARK
217 #pragma mark ***** Parameter Checking
220 static mDNSBool
CheckThatRichTextNameIsUsable(const char *richTextName
, mDNSBool printExplanation
)
221 // Checks that richTextName is reasonable
222 // label and, if it isn't and printExplanation is true, prints
223 // an explanation of why not.
225 mDNSBool result
= mDNStrue
;
226 if (result
&& strlen(richTextName
) > 63) {
227 if (printExplanation
) {
229 "%s: Service name is too long (must be 63 characters or less)\n",
234 if (result
&& richTextName
[0] == 0) {
235 if (printExplanation
) {
236 fprintf(stderr
, "%s: Service name can't be empty\n", gProgramName
);
243 static mDNSBool
CheckThatServiceTypeIsUsable(const char *serviceType
, mDNSBool printExplanation
)
244 // Checks that serviceType is a reasonable service type
245 // label and, if it isn't and printExplanation is true, prints
246 // an explanation of why not.
251 if (result
&& strlen(serviceType
) > 63) {
252 if (printExplanation
) {
254 "%s: Service type is too long (must be 63 characters or less)\n",
259 if (result
&& serviceType
[0] == 0) {
260 if (printExplanation
) {
262 "%s: Service type can't be empty\n",
270 static mDNSBool
CheckThatPortNumberIsUsable(long portNumber
, mDNSBool printExplanation
)
271 // Checks that portNumber is a reasonable port number
272 // and, if it isn't and printExplanation is true, prints
273 // an explanation of why not.
278 if (result
&& (portNumber
<= 0 || portNumber
> 65535)) {
279 if (printExplanation
) {
281 "%s: Port number specified by -p must be in range 1..65535\n",
289 #if COMPILER_LIKES_PRAGMA_MARK
290 #pragma mark ***** Command Line Arguments
293 static const char kDefaultPIDFile
[] = "/var/run/mDNSResponder.pid";
294 static const char kDefaultServiceType
[] = "_afpovertcp._tcp.";
295 static const char kDefaultServiceDomain
[] = "local.";
297 kDefaultPortNumber
= 548
300 static void PrintUsage()
303 "Usage: %s [-v level ] [-r] [-n name] [-t type] [-d domain] [-p port] [-f file] [-b] [-P pidfile] [-x name=val ...]\n",
305 fprintf(stderr
, " -v verbose mode, level is a number from 0 to 2\n");
306 fprintf(stderr
, " 0 = no debugging info (default)\n");
307 fprintf(stderr
, " 1 = standard debugging info\n");
308 fprintf(stderr
, " 2 = intense debugging info\n");
309 fprintf(stderr
, " can be cycled kill -USR1\n");
310 fprintf(stderr
, " -r also bind to port 53 (port 5353 is always bound)\n");
311 fprintf(stderr
, " -n uses 'name' as the service name (required)\n");
312 fprintf(stderr
, " -t uses 'type' as the service type (default is '%s')\n", kDefaultServiceType
);
313 fprintf(stderr
, " -d uses 'domain' as the service domain (default is '%s')\n", kDefaultServiceDomain
);
314 fprintf(stderr
, " -p uses 'port' as the port number (default is '%d')\n", kDefaultPortNumber
);
315 fprintf(stderr
, " -f reads a service list from 'file'\n");
316 fprintf(stderr
, " -b forces daemon (background) mode\n");
317 fprintf(stderr
, " -P uses 'pidfile' as the PID file\n");
318 fprintf(stderr
, " (default is '%s')\n", kDefaultPIDFile
);
319 fprintf(stderr
, " only meaningful if -b also specified\n");
320 fprintf(stderr
, " -x stores name=val in TXT record (default is empty).\n");
321 fprintf(stderr
, " MUST be the last command-line argument;\n");
322 fprintf(stderr
, " all subsequent arguments after -x are treated as name=val pairs.\n");
325 static mDNSBool gAvoidPort53
= mDNStrue
;
326 static const char *gServiceName
= "";
327 static const char *gServiceType
= kDefaultServiceType
;
328 static const char *gServiceDomain
= kDefaultServiceDomain
;
329 static mDNSu8 gServiceText
[sizeof(RDataBody
)];
330 static mDNSu16 gServiceTextLen
= 0;
331 static int gPortNumber
= kDefaultPortNumber
;
332 static const char *gServiceFile
= "";
333 static mDNSBool gDaemon
= mDNSfalse
;
334 static const char *gPIDFile
= kDefaultPIDFile
;
336 static void ParseArguments(int argc
, char **argv
)
337 // Parses our command line arguments into the global variables
342 // Set gProgramName to the last path component of argv[0]
344 gProgramName
= strrchr(argv
[0], '/');
345 if (gProgramName
== NULL
) {
346 gProgramName
= argv
[0];
351 // Parse command line options using getopt.
354 ch
= getopt(argc
, argv
, "v:rn:t:d:p:f:dP:bx");
358 gMDNSPlatformPosixVerboseLevel
= atoi(optarg
);
359 if (gMDNSPlatformPosixVerboseLevel
< 0 || gMDNSPlatformPosixVerboseLevel
> 2) {
361 "%s: Verbose mode must be in the range 0..2\n",
367 gAvoidPort53
= mDNSfalse
;
370 gServiceName
= optarg
;
371 if ( ! CheckThatRichTextNameIsUsable(gServiceName
, mDNStrue
) ) {
376 gServiceType
= optarg
;
377 if ( ! CheckThatServiceTypeIsUsable(gServiceType
, mDNStrue
) ) {
382 gServiceDomain
= optarg
;
385 gPortNumber
= atol(optarg
);
386 if ( ! CheckThatPortNumberIsUsable(gPortNumber
, mDNStrue
) ) {
391 gServiceFile
= optarg
;
400 while (optind
< argc
)
402 gServiceText
[gServiceTextLen
] = strlen(argv
[optind
]);
403 memcpy(gServiceText
+gServiceTextLen
+1, argv
[optind
], gServiceText
[gServiceTextLen
]);
404 gServiceTextLen
+= 1 + gServiceText
[gServiceTextLen
];
418 // Check for any left over command line arguments.
420 if (optind
!= argc
) {
422 fprintf(stderr
, "%s: Unexpected argument '%s'\n", gProgramName
, argv
[optind
]);
426 // Check for inconsistency between the arguments.
428 if ( (gServiceName
[0] == 0) && (gServiceFile
[0] == 0) ) {
430 fprintf(stderr
, "%s: You must specify a service name to register (-n) or a service file (-f).\n", gProgramName
);
435 #if COMPILER_LIKES_PRAGMA_MARK
436 #pragma mark ***** Registration
439 typedef struct PosixService PosixService
;
441 struct PosixService
{
442 ServiceRecordSet coreServ
;
447 static PosixService
*gServiceList
= NULL
;
449 static void RegistrationCallback(mDNS
*const m
, ServiceRecordSet
*const thisRegistration
, mStatus status
)
450 // mDNS core calls this routine to tell us about the status of
451 // our registration. The appropriate action to take depends
452 // entirely on the value of status.
456 case mStatus_NoError
:
457 debugf("Callback: %##s Name Registered", thisRegistration
->RR_SRV
.resrec
.name
->c
);
458 // Do nothing; our name was successfully registered. We may
459 // get more call backs in the future.
462 case mStatus_NameConflict
:
463 debugf("Callback: %##s Name Conflict", thisRegistration
->RR_SRV
.resrec
.name
->c
);
465 // In the event of a conflict, this sample RegistrationCallback
466 // just calls mDNS_RenameAndReregisterService to automatically
467 // pick a new unique name for the service. For a device such as a
468 // printer, this may be appropriate. For a device with a user
469 // interface, and a screen, and a keyboard, the appropriate response
470 // may be to prompt the user and ask them to choose a new name for
473 // Also, what do we do if mDNS_RenameAndReregisterService returns an
474 // error. Right now I have no place to send that error to.
476 status
= mDNS_RenameAndReregisterService(m
, thisRegistration
, mDNSNULL
);
477 assert(status
== mStatus_NoError
);
480 case mStatus_MemFree
:
481 debugf("Callback: %##s Memory Free", thisRegistration
->RR_SRV
.resrec
.name
->c
);
483 // When debugging is enabled, make sure that thisRegistration
484 // is not on our gServiceList.
488 PosixService
*cursor
;
490 cursor
= gServiceList
;
491 while (cursor
!= NULL
) {
492 assert(&cursor
->coreServ
!= thisRegistration
);
493 cursor
= cursor
->next
;
497 free(thisRegistration
);
501 debugf("Callback: %##s Unknown Status %ld", thisRegistration
->RR_SRV
.resrec
.name
->c
, status
);
506 static int gServiceID
= 0;
508 static mStatus
RegisterOneService(const char * richTextName
,
509 const char * serviceType
,
510 const char * serviceDomain
,
516 PosixService
* thisServ
;
521 status
= mStatus_NoError
;
522 thisServ
= (PosixService
*) malloc(sizeof(*thisServ
));
523 if (thisServ
== NULL
) {
524 status
= mStatus_NoMemoryErr
;
526 if (status
== mStatus_NoError
) {
527 MakeDomainLabelFromLiteralString(&name
, richTextName
);
528 MakeDomainNameFromDNSNameString(&type
, serviceType
);
529 MakeDomainNameFromDNSNameString(&domain
, serviceDomain
);
530 status
= mDNS_RegisterService(&mDNSStorage
, &thisServ
->coreServ
,
531 &name
, &type
, &domain
, // Name, type, domain
532 NULL
, mDNSOpaque16fromIntVal(portNumber
),
533 text
, textLen
, // TXT data, length
535 mDNSInterface_Any
, // Interface ID
536 RegistrationCallback
, thisServ
); // Callback and context
538 if (status
== mStatus_NoError
) {
539 thisServ
->serviceID
= gServiceID
;
542 thisServ
->next
= gServiceList
;
543 gServiceList
= thisServ
;
545 if (gMDNSPlatformPosixVerboseLevel
> 0) {
547 "%s: Registered service %d, name '%s', type '%s', port %ld\n",
555 if (thisServ
!= NULL
) {
562 static mDNSBool
ReadALine(char *buf
, size_t bufSize
, FILE *fp
)
563 // Read a line, skipping over any blank lines or lines starting with '#'
567 good
= (fgets(buf
, bufSize
, fp
) != NULL
);
568 skip
= (good
&& (buf
[0] == '#'));
569 } while (good
&& skip
);
572 int len
= strlen( buf
);
573 if ( buf
[len
- 1] == '\r' || buf
[len
- 1] == '\n')
579 static mStatus
RegisterServicesInFile(const char *filePath
)
581 mStatus status
= mStatus_NoError
;
582 FILE * fp
= fopen(filePath
, "r");
586 status
= mStatus_UnknownErr
;
588 if (status
== mStatus_NoError
) {
589 mDNSBool good
= mDNStrue
;
594 const char *dom
= kDefaultServiceDomain
;
596 mDNSu8 text
[sizeof(RDataBody
)];
597 unsigned int textLen
= 0;
600 // Skip over any blank lines.
601 do ch
= fgetc(fp
); while ( ch
== '\n' || ch
== '\r' );
602 if (ch
!= EOF
) good
= (ungetc(ch
, fp
) == ch
);
604 // Read three lines, check them for validity, and register the service.
605 good
= ReadALine(name
, sizeof(name
), fp
);
607 good
= ReadALine(type
, sizeof(type
), fp
);
611 while (*p
&& *p
!= ' ') p
++;
618 good
= ReadALine(port
, sizeof(port
), fp
);
621 good
= CheckThatRichTextNameIsUsable(name
, mDNSfalse
)
622 && CheckThatServiceTypeIsUsable(type
, mDNSfalse
)
623 && CheckThatPortNumberIsUsable(atol(port
), mDNSfalse
);
628 if (!ReadALine(rawText
, sizeof(rawText
), fp
)) break;
629 len
= strlen(rawText
);
632 unsigned int newlen
= textLen
+ 1 + len
;
633 if (len
== 0 || newlen
>= sizeof(text
)) break;
635 memcpy(text
+ textLen
+ 1, rawText
, len
);
639 fprintf(stderr
, "%s: TXT attribute too long for name = %s, type = %s, port = %s\n",
640 gProgramName
, name
, type
, port
);
644 status
= RegisterOneService(name
, type
, dom
, text
, textLen
, atol(port
));
645 if (status
!= mStatus_NoError
) {
646 fprintf(stderr
, "%s: Failed to register service, name = %s, type = %s, port = %s\n",
647 gProgramName
, name
, type
, port
);
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 (gServiceName
[0] != 0) {
672 status
= RegisterOneService(gServiceName
,
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
);