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.33 2007/04/16 20:49:39 cheshire
21 Fix compile errors for mDNSPosix build
23 Revision 1.32 2006/08/14 23:24:46 cheshire
24 Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
26 Revision 1.31 2006/06/12 18:22:42 cheshire
27 <rdar://problem/4580067> mDNSResponder building warnings under Red Hat 64-bit (LP64) Linux
29 Revision 1.30 2005/10/26 22:21:16 cheshire
30 <rdar://problem/4149841> Potential buffer overflow in mDNSResponderPosix
32 Revision 1.29 2005/03/04 21:35:33 cheshire
33 <rdar://problem/4037201> Services.txt file not parsed properly when it contains more than one service
35 Revision 1.28 2005/01/11 01:55:26 ksekar
36 Fix compile errors in Posix debug build
38 Revision 1.27 2004/12/01 04:28:43 cheshire
39 <rdar://problem/3872803> Darwin patches for Solaris and Suse
40 Use version of daemon() provided in mDNSUNP.c instead of local copy
42 Revision 1.26 2004/11/30 22:37:01 cheshire
43 Update copyright dates and add "Mode: C; tab-width: 4" headers
45 Revision 1.25 2004/11/11 02:00:51 cheshire
46 Minor fixes to getopt, error message
48 Revision 1.24 2004/11/09 19:32:10 rpantos
49 Suggestion from Ademar de Souza Reis Jr. to allow comments in services file
51 Revision 1.23 2004/09/17 01:08:54 cheshire
52 Renamed mDNSClientAPI.h to mDNSEmbeddedAPI.h
53 The name "mDNSClientAPI.h" is misleading to new developers looking at this code. The interfaces
54 declared in that file are ONLY appropriate to single-address-space embedded applications.
55 For clients on general-purpose computers, the interfaces defined in dns_sd.h should be used.
57 Revision 1.22 2004/09/16 01:58:22 cheshire
60 Revision 1.21 2004/06/15 03:48:07 cheshire
61 Update mDNSResponderPosix to take multiple name=val arguments in a sane way
63 Revision 1.20 2004/05/18 23:51:26 cheshire
64 Tidy up all checkin comments to use consistent "<rdar://problem/xxxxxxx>" format for bug numbers
66 Revision 1.19 2004/03/12 08:03:14 cheshire
69 Revision 1.18 2004/01/25 00:00:55 cheshire
70 Change to use mDNSOpaque16fromIntVal() instead of shifting and masking
72 Revision 1.17 2003/12/11 19:11:55 cheshire
75 Revision 1.16 2003/08/14 02:19:55 cheshire
76 <rdar://problem/3375491> Split generic ResourceRecord type into two separate types: AuthRecord and CacheRecord
78 Revision 1.15 2003/08/12 19:56:26 cheshire
81 Revision 1.14 2003/08/06 18:20:51 cheshire
84 Revision 1.13 2003/07/23 00:00:04 cheshire
87 Revision 1.12 2003/07/15 01:55:16 cheshire
88 <rdar://problem/3315777> Need to implement service registration with subtypes
90 Revision 1.11 2003/07/14 18:11:54 cheshire
91 Fix stricter compiler warnings
93 Revision 1.10 2003/07/10 20:27:31 cheshire
94 <rdar://problem/3318717> mDNSResponder Posix version is missing a 'b' in the getopt option string
96 Revision 1.9 2003/07/02 21:19:59 cheshire
97 <rdar://problem/3313413> Update copyright notices, etc., in source code comments
99 Revision 1.8 2003/06/18 05:48:41 cheshire
102 Revision 1.7 2003/05/06 00:00:50 cheshire
103 <rdar://problem/3248914> Rationalize naming of domainname manipulation functions
105 Revision 1.6 2003/03/08 00:35:56 cheshire
106 Switched to using new "mDNS_Execute" model (see "mDNSCore/Implementer Notes.txt")
108 Revision 1.5 2003/02/20 06:48:36 cheshire
109 <rdar://problem/3169535> Xserve RAID needs to do interface-specific registrations
110 Reviewed by: Josh Graessley, Bob Bradley
112 Revision 1.4 2003/01/28 03:07:46 cheshire
113 Add extra parameter to mDNS_RenameAndReregisterService(),
114 and add support for specifying a domain other than dot-local.
116 Revision 1.3 2002/09/21 20:44:53 zarzycki
119 Revision 1.2 2002/09/19 04:20:44 cheshire
120 Remove high-ascii characters that confuse some systems
122 Revision 1.1 2002/09/17 06:24:35 cheshire
127 #include "mDNSEmbeddedAPI.h"// Defines the interface to the client layer above
128 #include "mDNSPosix.h" // Defines the specific types needed to run mDNS on this platform
131 #include <stdio.h> // For printf()
132 #include <stdlib.h> // For exit() etc.
133 #include <string.h> // For strlen() etc.
134 #include <unistd.h> // For select()
135 #include <errno.h> // For errno, EINTR
139 #if COMPILER_LIKES_PRAGMA_MARK
140 #pragma mark ***** Globals
143 static mDNS mDNSStorage
; // mDNS core uses this to store its globals
144 static mDNS_PlatformSupport PlatformStorage
; // Stores this platform's globals
146 mDNSexport
const char ProgramName
[] = "mDNSResponderPosix";
148 static const char *gProgramName
= ProgramName
;
150 #if COMPILER_LIKES_PRAGMA_MARK
151 #pragma mark ***** Signals
154 static volatile mDNSBool gReceivedSigUsr1
;
155 static volatile mDNSBool gReceivedSigHup
;
156 static volatile mDNSBool gStopNow
;
158 // We support 4 signals.
160 // o SIGUSR1 toggles verbose mode on and off in debug builds
161 // o SIGHUP triggers the program to re-read its preferences.
162 // o SIGINT causes an orderly shutdown of the program.
163 // o SIGQUIT causes a somewhat orderly shutdown (direct but dangerous)
164 // o SIGKILL kills us dead (easy to implement :-)
166 // There are fatal race conditions in our signal handling, but there's not much
167 // we can do about them while remaining within the Posix space. Specifically,
168 // if a signal arrives after we test the globals its sets but before we call
169 // select, the signal will be dropped. The user will have to send the signal
170 // again. Unfortunately, Posix does not have a "sigselect" to atomically
171 // modify the signal mask and start a select.
173 static void HandleSigUsr1(int sigraised
)
174 // If we get a SIGUSR1 we toggle the state of the
177 assert(sigraised
== SIGUSR1
);
178 gReceivedSigUsr1
= mDNStrue
;
181 static void HandleSigHup(int sigraised
)
182 // A handler for SIGHUP that causes us to break out of the
183 // main event loop when the user kill 1's us. This has the
184 // effect of triggered the main loop to deregister the
185 // current services and re-read the preferences.
187 assert(sigraised
== SIGHUP
);
188 gReceivedSigHup
= mDNStrue
;
191 static void HandleSigInt(int sigraised
)
192 // A handler for SIGINT that causes us to break out of the
193 // main event loop when the user types ^C. This has the
194 // effect of quitting the program.
196 assert(sigraised
== SIGINT
);
198 if (gMDNSPlatformPosixVerboseLevel
> 0) {
199 fprintf(stderr
, "\nSIGINT\n");
204 static void HandleSigQuit(int sigraised
)
205 // If we get a SIGQUIT the user is desperate and we
206 // just call mDNS_Close directly. This is definitely
207 // not safe (because it could reenter mDNS), but
208 // we presume that the user has already tried the safe
211 assert(sigraised
== SIGQUIT
);
213 if (gMDNSPlatformPosixVerboseLevel
> 0) {
214 fprintf(stderr
, "\nSIGQUIT\n");
216 mDNS_Close(&mDNSStorage
);
220 #if COMPILER_LIKES_PRAGMA_MARK
221 #pragma mark ***** Parameter Checking
224 static mDNSBool
CheckThatRichTextNameIsUsable(const char *richTextName
, mDNSBool printExplanation
)
225 // Checks that richTextName is reasonable
226 // label and, if it isn't and printExplanation is true, prints
227 // an explanation of why not.
229 mDNSBool result
= mDNStrue
;
230 if (result
&& strlen(richTextName
) > 63) {
231 if (printExplanation
) {
233 "%s: Service name is too long (must be 63 characters or less)\n",
238 if (result
&& richTextName
[0] == 0) {
239 if (printExplanation
) {
240 fprintf(stderr
, "%s: Service name can't be empty\n", gProgramName
);
247 static mDNSBool
CheckThatServiceTypeIsUsable(const char *serviceType
, mDNSBool printExplanation
)
248 // Checks that serviceType is a reasonable service type
249 // label and, if it isn't and printExplanation is true, prints
250 // an explanation of why not.
255 if (result
&& strlen(serviceType
) > 63) {
256 if (printExplanation
) {
258 "%s: Service type is too long (must be 63 characters or less)\n",
263 if (result
&& serviceType
[0] == 0) {
264 if (printExplanation
) {
266 "%s: Service type can't be empty\n",
274 static mDNSBool
CheckThatPortNumberIsUsable(long portNumber
, mDNSBool printExplanation
)
275 // Checks that portNumber is a reasonable port number
276 // and, if it isn't and printExplanation is true, prints
277 // an explanation of why not.
282 if (result
&& (portNumber
<= 0 || portNumber
> 65535)) {
283 if (printExplanation
) {
285 "%s: Port number specified by -p must be in range 1..65535\n",
293 #if COMPILER_LIKES_PRAGMA_MARK
294 #pragma mark ***** Command Line Arguments
297 static const char kDefaultPIDFile
[] = "/var/run/mDNSResponder.pid";
298 static const char kDefaultServiceType
[] = "_afpovertcp._tcp.";
299 static const char kDefaultServiceDomain
[] = "local.";
301 kDefaultPortNumber
= 548
304 static void PrintUsage()
307 "Usage: %s [-v level ] [-r] [-n name] [-t type] [-d domain] [-p port] [-f file] [-b] [-P pidfile] [-x name=val ...]\n",
309 fprintf(stderr
, " -v verbose mode, level is a number from 0 to 2\n");
310 fprintf(stderr
, " 0 = no debugging info (default)\n");
311 fprintf(stderr
, " 1 = standard debugging info\n");
312 fprintf(stderr
, " 2 = intense debugging info\n");
313 fprintf(stderr
, " can be cycled kill -USR1\n");
314 fprintf(stderr
, " -r also bind to port 53 (port 5353 is always bound)\n");
315 fprintf(stderr
, " -n uses 'name' as the service name (required)\n");
316 fprintf(stderr
, " -t uses 'type' as the service type (default is '%s')\n", kDefaultServiceType
);
317 fprintf(stderr
, " -d uses 'domain' as the service domain (default is '%s')\n", kDefaultServiceDomain
);
318 fprintf(stderr
, " -p uses 'port' as the port number (default is '%d')\n", kDefaultPortNumber
);
319 fprintf(stderr
, " -f reads a service list from 'file'\n");
320 fprintf(stderr
, " -b forces daemon (background) mode\n");
321 fprintf(stderr
, " -P uses 'pidfile' as the PID file\n");
322 fprintf(stderr
, " (default is '%s')\n", kDefaultPIDFile
);
323 fprintf(stderr
, " only meaningful if -b also specified\n");
324 fprintf(stderr
, " -x stores name=val in TXT record (default is empty).\n");
325 fprintf(stderr
, " MUST be the last command-line argument;\n");
326 fprintf(stderr
, " all subsequent arguments after -x are treated as name=val pairs.\n");
329 static mDNSBool gAvoidPort53
= mDNStrue
;
330 static const char *gServiceName
= "";
331 static const char *gServiceType
= kDefaultServiceType
;
332 static const char *gServiceDomain
= kDefaultServiceDomain
;
333 static mDNSu8 gServiceText
[sizeof(RDataBody
)];
334 static mDNSu16 gServiceTextLen
= 0;
335 static int gPortNumber
= kDefaultPortNumber
;
336 static const char *gServiceFile
= "";
337 static mDNSBool gDaemon
= mDNSfalse
;
338 static const char *gPIDFile
= kDefaultPIDFile
;
340 static void ParseArguments(int argc
, char **argv
)
341 // Parses our command line arguments into the global variables
346 // Set gProgramName to the last path component of argv[0]
348 gProgramName
= strrchr(argv
[0], '/');
349 if (gProgramName
== NULL
) {
350 gProgramName
= argv
[0];
355 // Parse command line options using getopt.
358 ch
= getopt(argc
, argv
, "v:rn:t:d:p:f:dP:bx");
362 gMDNSPlatformPosixVerboseLevel
= atoi(optarg
);
363 if (gMDNSPlatformPosixVerboseLevel
< 0 || gMDNSPlatformPosixVerboseLevel
> 2) {
365 "%s: Verbose mode must be in the range 0..2\n",
371 gAvoidPort53
= mDNSfalse
;
374 gServiceName
= optarg
;
375 if ( ! CheckThatRichTextNameIsUsable(gServiceName
, mDNStrue
) ) {
380 gServiceType
= optarg
;
381 if ( ! CheckThatServiceTypeIsUsable(gServiceType
, mDNStrue
) ) {
386 gServiceDomain
= optarg
;
389 gPortNumber
= atol(optarg
);
390 if ( ! CheckThatPortNumberIsUsable(gPortNumber
, mDNStrue
) ) {
395 gServiceFile
= optarg
;
404 while (optind
< argc
)
406 gServiceText
[gServiceTextLen
] = strlen(argv
[optind
]);
407 memcpy(gServiceText
+gServiceTextLen
+1, argv
[optind
], gServiceText
[gServiceTextLen
]);
408 gServiceTextLen
+= 1 + gServiceText
[gServiceTextLen
];
422 // Check for any left over command line arguments.
424 if (optind
!= argc
) {
426 fprintf(stderr
, "%s: Unexpected argument '%s'\n", gProgramName
, argv
[optind
]);
430 // Check for inconsistency between the arguments.
432 if ( (gServiceName
[0] == 0) && (gServiceFile
[0] == 0) ) {
434 fprintf(stderr
, "%s: You must specify a service name to register (-n) or a service file (-f).\n", gProgramName
);
439 #if COMPILER_LIKES_PRAGMA_MARK
440 #pragma mark ***** Registration
443 typedef struct PosixService PosixService
;
445 struct PosixService
{
446 ServiceRecordSet coreServ
;
451 static PosixService
*gServiceList
= NULL
;
453 static void RegistrationCallback(mDNS
*const m
, ServiceRecordSet
*const thisRegistration
, mStatus status
)
454 // mDNS core calls this routine to tell us about the status of
455 // our registration. The appropriate action to take depends
456 // entirely on the value of status.
460 case mStatus_NoError
:
461 debugf("Callback: %##s Name Registered", thisRegistration
->RR_SRV
.resrec
.name
->c
);
462 // Do nothing; our name was successfully registered. We may
463 // get more call backs in the future.
466 case mStatus_NameConflict
:
467 debugf("Callback: %##s Name Conflict", thisRegistration
->RR_SRV
.resrec
.name
->c
);
469 // In the event of a conflict, this sample RegistrationCallback
470 // just calls mDNS_RenameAndReregisterService to automatically
471 // pick a new unique name for the service. For a device such as a
472 // printer, this may be appropriate. For a device with a user
473 // interface, and a screen, and a keyboard, the appropriate response
474 // may be to prompt the user and ask them to choose a new name for
477 // Also, what do we do if mDNS_RenameAndReregisterService returns an
478 // error. Right now I have no place to send that error to.
480 status
= mDNS_RenameAndReregisterService(m
, thisRegistration
, mDNSNULL
);
481 assert(status
== mStatus_NoError
);
484 case mStatus_MemFree
:
485 debugf("Callback: %##s Memory Free", thisRegistration
->RR_SRV
.resrec
.name
->c
);
487 // When debugging is enabled, make sure that thisRegistration
488 // is not on our gServiceList.
492 PosixService
*cursor
;
494 cursor
= gServiceList
;
495 while (cursor
!= NULL
) {
496 assert(&cursor
->coreServ
!= thisRegistration
);
497 cursor
= cursor
->next
;
501 free(thisRegistration
);
505 debugf("Callback: %##s Unknown Status %ld", thisRegistration
->RR_SRV
.resrec
.name
->c
, status
);
510 static int gServiceID
= 0;
512 static mStatus
RegisterOneService(const char * richTextName
,
513 const char * serviceType
,
514 const char * serviceDomain
,
520 PosixService
* thisServ
;
525 status
= mStatus_NoError
;
526 thisServ
= (PosixService
*) malloc(sizeof(*thisServ
));
527 if (thisServ
== NULL
) {
528 status
= mStatus_NoMemoryErr
;
530 if (status
== mStatus_NoError
) {
531 MakeDomainLabelFromLiteralString(&name
, richTextName
);
532 MakeDomainNameFromDNSNameString(&type
, serviceType
);
533 MakeDomainNameFromDNSNameString(&domain
, serviceDomain
);
534 status
= mDNS_RegisterService(&mDNSStorage
, &thisServ
->coreServ
,
535 &name
, &type
, &domain
, // Name, type, domain
536 NULL
, mDNSOpaque16fromIntVal(portNumber
),
537 text
, textLen
, // TXT data, length
539 mDNSInterface_Any
, // Interface ID
540 RegistrationCallback
, thisServ
); // Callback and context
542 if (status
== mStatus_NoError
) {
543 thisServ
->serviceID
= gServiceID
;
546 thisServ
->next
= gServiceList
;
547 gServiceList
= thisServ
;
549 if (gMDNSPlatformPosixVerboseLevel
> 0) {
551 "%s: Registered service %d, name '%s', type '%s', port %ld\n",
559 if (thisServ
!= NULL
) {
566 static mDNSBool
ReadALine(char *buf
, size_t bufSize
, FILE *fp
)
567 // Read a line, skipping over any blank lines or lines starting with '#'
571 good
= (fgets(buf
, bufSize
, fp
) != NULL
);
572 skip
= (good
&& (buf
[0] == '#'));
573 } while (good
&& skip
);
576 int len
= strlen( buf
);
577 if ( buf
[len
- 1] == '\r' || buf
[len
- 1] == '\n')
583 static mStatus
RegisterServicesInFile(const char *filePath
)
585 mStatus status
= mStatus_NoError
;
586 FILE * fp
= fopen(filePath
, "r");
590 status
= mStatus_UnknownErr
;
592 if (status
== mStatus_NoError
) {
593 mDNSBool good
= mDNStrue
;
598 const char *dom
= kDefaultServiceDomain
;
600 mDNSu8 text
[sizeof(RDataBody
)];
601 unsigned int textLen
= 0;
604 // Skip over any blank lines.
605 do ch
= fgetc(fp
); while ( ch
== '\n' || ch
== '\r' );
606 if (ch
!= EOF
) good
= (ungetc(ch
, fp
) == ch
);
608 // Read three lines, check them for validity, and register the service.
609 good
= ReadALine(name
, sizeof(name
), fp
);
611 good
= ReadALine(type
, sizeof(type
), fp
);
615 while (*p
&& *p
!= ' ') p
++;
622 good
= ReadALine(port
, sizeof(port
), fp
);
625 good
= CheckThatRichTextNameIsUsable(name
, mDNSfalse
)
626 && CheckThatServiceTypeIsUsable(type
, mDNSfalse
)
627 && CheckThatPortNumberIsUsable(atol(port
), mDNSfalse
);
632 if (!ReadALine(rawText
, sizeof(rawText
), fp
)) break;
633 len
= strlen(rawText
);
636 unsigned int newlen
= textLen
+ 1 + len
;
637 if (len
== 0 || newlen
>= sizeof(text
)) break;
639 memcpy(text
+ textLen
+ 1, rawText
, len
);
643 fprintf(stderr
, "%s: TXT attribute too long for name = %s, type = %s, port = %s\n",
644 gProgramName
, name
, type
, port
);
648 status
= RegisterOneService(name
, type
, dom
, text
, textLen
, atol(port
));
649 if (status
!= mStatus_NoError
) {
650 fprintf(stderr
, "%s: Failed to register service, name = %s, type = %s, port = %s\n",
651 gProgramName
, name
, type
, port
);
652 status
= mStatus_NoError
; // keep reading
655 } while (good
&& !feof(fp
));
658 fprintf(stderr
, "%s: Error reading service file %s\n", gProgramName
, filePath
);
670 static mStatus
RegisterOurServices(void)
674 status
= mStatus_NoError
;
675 if (gServiceName
[0] != 0) {
676 status
= RegisterOneService(gServiceName
,
679 gServiceText
, gServiceTextLen
,
682 if (status
== mStatus_NoError
&& gServiceFile
[0] != 0) {
683 status
= RegisterServicesInFile(gServiceFile
);
688 static void DeregisterOurServices(void)
690 PosixService
*thisServ
;
693 while (gServiceList
!= NULL
) {
694 thisServ
= gServiceList
;
695 gServiceList
= thisServ
->next
;
697 thisServID
= thisServ
->serviceID
;
699 mDNS_DeregisterService(&mDNSStorage
, &thisServ
->coreServ
);
701 if (gMDNSPlatformPosixVerboseLevel
> 0) {
703 "%s: Deregistered service %d\n",
705 thisServ
->serviceID
);
710 #if COMPILER_LIKES_PRAGMA_MARK
711 #pragma mark **** Main
714 int main(int argc
, char **argv
)
719 // Parse our command line arguments. This won't come back if there's an error.
721 ParseArguments(argc
, argv
);
723 // If we're told to run as a daemon, then do that straight away.
724 // Note that we don't treat the inability to create our PID
725 // file as an error. Also note that we assign getpid to a long
726 // because printf has no format specified for pid_t.
729 if (gMDNSPlatformPosixVerboseLevel
> 0) {
730 fprintf(stderr
, "%s: Starting in daemon mode\n", gProgramName
);
737 fp
= fopen(gPIDFile
, "w");
739 fprintf(fp
, "%ld\n", (long) getpid());
745 if (gMDNSPlatformPosixVerboseLevel
> 0) {
746 fprintf(stderr
, "%s: Starting in foreground mode, PID %ld\n", gProgramName
, (long) getpid());
750 status
= mDNS_Init(&mDNSStorage
, &PlatformStorage
,
751 mDNS_Init_NoCache
, mDNS_Init_ZeroCacheSize
,
752 mDNS_Init_AdvertiseLocalAddresses
,
753 mDNS_Init_NoInitCallback
, mDNS_Init_NoInitCallbackContext
);
754 if (status
!= mStatus_NoError
) return(2);
756 status
= RegisterOurServices();
757 if (status
!= mStatus_NoError
) return(2);
759 signal(SIGHUP
, HandleSigHup
); // SIGHUP has to be sent by kill -HUP <pid>
760 signal(SIGINT
, HandleSigInt
); // SIGINT is what you get for a Ctrl-C
761 signal(SIGQUIT
, HandleSigQuit
); // SIGQUIT is what you get for a Ctrl-\ (indeed)
762 signal(SIGUSR1
, HandleSigUsr1
); // SIGUSR1 has to be sent by kill -USR1 <pid>
768 struct timeval timeout
;
771 // 1. Set up the fd_set as usual here.
772 // This example client has no file descriptors of its own,
773 // but a real application would call FD_SET to add them to the set here
776 // 2. Set up the timeout.
777 // This example client has no other work it needs to be doing,
778 // so we set an effectively infinite timeout
779 timeout
.tv_sec
= 0x3FFFFFFF;
782 // 3. Give the mDNSPosix layer a chance to add its information to the fd_set and timeout
783 mDNSPosixGetFDSet(&mDNSStorage
, &nfds
, &readfds
, &timeout
);
785 // 4. Call select as normal
786 verbosedebugf("select(%d, %d.%06d)", nfds
, timeout
.tv_sec
, timeout
.tv_usec
);
787 result
= select(nfds
, &readfds
, NULL
, NULL
, &timeout
);
791 verbosedebugf("select() returned %d errno %d", result
, errno
);
792 if (errno
!= EINTR
) gStopNow
= mDNStrue
;
795 if (gReceivedSigUsr1
)
797 gReceivedSigUsr1
= mDNSfalse
;
798 gMDNSPlatformPosixVerboseLevel
+= 1;
799 if (gMDNSPlatformPosixVerboseLevel
> 2)
800 gMDNSPlatformPosixVerboseLevel
= 0;
801 if ( gMDNSPlatformPosixVerboseLevel
> 0 )
802 fprintf(stderr
, "\nVerbose level %d\n", gMDNSPlatformPosixVerboseLevel
);
806 if (gMDNSPlatformPosixVerboseLevel
> 0)
807 fprintf(stderr
, "\nSIGHUP\n");
808 gReceivedSigHup
= mDNSfalse
;
809 DeregisterOurServices();
810 status
= mDNSPlatformPosixRefreshInterfaceList(&mDNSStorage
);
811 if (status
!= mStatus_NoError
) break;
812 status
= RegisterOurServices();
813 if (status
!= mStatus_NoError
) break;
819 // 5. Call mDNSPosixProcessFDSet to let the mDNSPosix layer do its work
820 mDNSPosixProcessFDSet(&mDNSStorage
, &readfds
);
822 // 6. This example client has no other work it needs to be doing,
823 // but a real client would do its work here
830 DeregisterOurServices();
831 mDNS_Close(&mDNSStorage
);
833 if (status
== mStatus_NoError
) {
838 if ( (result
!= 0) || (gMDNSPlatformPosixVerboseLevel
> 0) ) {
839 fprintf(stderr
, "%s: Finished with status %d, result %d\n", gProgramName
, (int)status
, result
);