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.36 2009/01/15 03:39:08 mkrochma
21 Fix warning about ignoring return value of daemon
23 Revision 1.35 2009/01/13 05:31:34 mkrochma
24 <rdar://problem/6491367> Replace bzero, bcopy with mDNSPlatformMemZero, mDNSPlatformMemCopy, memset, memcpy
26 Revision 1.34 2009/01/11 03:20:06 mkrochma
27 <rdar://problem/5797526> Fixes from Igor Seleznev to get mdnsd working on Solaris
29 Revision 1.33 2007/04/16 20:49:39 cheshire
30 Fix compile errors for mDNSPosix build
32 Revision 1.32 2006/08/14 23:24:46 cheshire
33 Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
35 Revision 1.31 2006/06/12 18:22:42 cheshire
36 <rdar://problem/4580067> mDNSResponder building warnings under Red Hat 64-bit (LP64) Linux
38 Revision 1.30 2005/10/26 22:21:16 cheshire
39 <rdar://problem/4149841> Potential buffer overflow in mDNSResponderPosix
41 Revision 1.29 2005/03/04 21:35:33 cheshire
42 <rdar://problem/4037201> Services.txt file not parsed properly when it contains more than one service
44 Revision 1.28 2005/01/11 01:55:26 ksekar
45 Fix compile errors in Posix debug build
47 Revision 1.27 2004/12/01 04:28:43 cheshire
48 <rdar://problem/3872803> Darwin patches for Solaris and Suse
49 Use version of daemon() provided in mDNSUNP.c instead of local copy
51 Revision 1.26 2004/11/30 22:37:01 cheshire
52 Update copyright dates and add "Mode: C; tab-width: 4" headers
54 Revision 1.25 2004/11/11 02:00:51 cheshire
55 Minor fixes to getopt, error message
57 Revision 1.24 2004/11/09 19:32:10 rpantos
58 Suggestion from Ademar de Souza Reis Jr. to allow comments in services file
60 Revision 1.23 2004/09/17 01:08:54 cheshire
61 Renamed mDNSClientAPI.h to mDNSEmbeddedAPI.h
62 The name "mDNSClientAPI.h" is misleading to new developers looking at this code. The interfaces
63 declared in that file are ONLY appropriate to single-address-space embedded applications.
64 For clients on general-purpose computers, the interfaces defined in dns_sd.h should be used.
66 Revision 1.22 2004/09/16 01:58:22 cheshire
69 Revision 1.21 2004/06/15 03:48:07 cheshire
70 Update mDNSResponderPosix to take multiple name=val arguments in a sane way
72 Revision 1.20 2004/05/18 23:51:26 cheshire
73 Tidy up all checkin comments to use consistent "<rdar://problem/xxxxxxx>" format for bug numbers
75 Revision 1.19 2004/03/12 08:03:14 cheshire
78 Revision 1.18 2004/01/25 00:00:55 cheshire
79 Change to use mDNSOpaque16fromIntVal() instead of shifting and masking
81 Revision 1.17 2003/12/11 19:11:55 cheshire
84 Revision 1.16 2003/08/14 02:19:55 cheshire
85 <rdar://problem/3375491> Split generic ResourceRecord type into two separate types: AuthRecord and CacheRecord
87 Revision 1.15 2003/08/12 19:56:26 cheshire
90 Revision 1.14 2003/08/06 18:20:51 cheshire
93 Revision 1.13 2003/07/23 00:00:04 cheshire
96 Revision 1.12 2003/07/15 01:55:16 cheshire
97 <rdar://problem/3315777> Need to implement service registration with subtypes
99 Revision 1.11 2003/07/14 18:11:54 cheshire
100 Fix stricter compiler warnings
102 Revision 1.10 2003/07/10 20:27:31 cheshire
103 <rdar://problem/3318717> mDNSResponder Posix version is missing a 'b' in the getopt option string
105 Revision 1.9 2003/07/02 21:19:59 cheshire
106 <rdar://problem/3313413> Update copyright notices, etc., in source code comments
108 Revision 1.8 2003/06/18 05:48:41 cheshire
111 Revision 1.7 2003/05/06 00:00:50 cheshire
112 <rdar://problem/3248914> Rationalize naming of domainname manipulation functions
114 Revision 1.6 2003/03/08 00:35:56 cheshire
115 Switched to using new "mDNS_Execute" model (see "mDNSCore/Implementer Notes.txt")
117 Revision 1.5 2003/02/20 06:48:36 cheshire
118 <rdar://problem/3169535> Xserve RAID needs to do interface-specific registrations
119 Reviewed by: Josh Graessley, Bob Bradley
121 Revision 1.4 2003/01/28 03:07:46 cheshire
122 Add extra parameter to mDNS_RenameAndReregisterService(),
123 and add support for specifying a domain other than dot-local.
125 Revision 1.3 2002/09/21 20:44:53 zarzycki
128 Revision 1.2 2002/09/19 04:20:44 cheshire
129 Remove high-ascii characters that confuse some systems
131 Revision 1.1 2002/09/17 06:24:35 cheshire
136 #include "mDNSEmbeddedAPI.h"// Defines the interface to the client layer above
137 #include "mDNSPosix.h" // Defines the specific types needed to run mDNS on this platform
138 #include "mDNSUNP.h" // For daemon()
141 #include <stdio.h> // For printf()
142 #include <stdlib.h> // For exit() etc.
143 #include <string.h> // For strlen() etc.
144 #include <unistd.h> // For select()
145 #include <errno.h> // For errno, EINTR
149 #if COMPILER_LIKES_PRAGMA_MARK
150 #pragma mark ***** Globals
153 static mDNS mDNSStorage
; // mDNS core uses this to store its globals
154 static mDNS_PlatformSupport PlatformStorage
; // Stores this platform's globals
156 mDNSexport
const char ProgramName
[] = "mDNSResponderPosix";
158 static const char *gProgramName
= ProgramName
;
160 #if COMPILER_LIKES_PRAGMA_MARK
161 #pragma mark ***** Signals
164 static volatile mDNSBool gReceivedSigUsr1
;
165 static volatile mDNSBool gReceivedSigHup
;
166 static volatile mDNSBool gStopNow
;
168 // We support 4 signals.
170 // o SIGUSR1 toggles verbose mode on and off in debug builds
171 // o SIGHUP triggers the program to re-read its preferences.
172 // o SIGINT causes an orderly shutdown of the program.
173 // o SIGQUIT causes a somewhat orderly shutdown (direct but dangerous)
174 // o SIGKILL kills us dead (easy to implement :-)
176 // There are fatal race conditions in our signal handling, but there's not much
177 // we can do about them while remaining within the Posix space. Specifically,
178 // if a signal arrives after we test the globals its sets but before we call
179 // select, the signal will be dropped. The user will have to send the signal
180 // again. Unfortunately, Posix does not have a "sigselect" to atomically
181 // modify the signal mask and start a select.
183 static void HandleSigUsr1(int sigraised
)
184 // If we get a SIGUSR1 we toggle the state of the
187 assert(sigraised
== SIGUSR1
);
188 gReceivedSigUsr1
= mDNStrue
;
191 static void HandleSigHup(int sigraised
)
192 // A handler for SIGHUP that causes us to break out of the
193 // main event loop when the user kill 1's us. This has the
194 // effect of triggered the main loop to deregister the
195 // current services and re-read the preferences.
197 assert(sigraised
== SIGHUP
);
198 gReceivedSigHup
= mDNStrue
;
201 static void HandleSigInt(int sigraised
)
202 // A handler for SIGINT that causes us to break out of the
203 // main event loop when the user types ^C. This has the
204 // effect of quitting the program.
206 assert(sigraised
== SIGINT
);
208 if (gMDNSPlatformPosixVerboseLevel
> 0) {
209 fprintf(stderr
, "\nSIGINT\n");
214 static void HandleSigQuit(int sigraised
)
215 // If we get a SIGQUIT the user is desperate and we
216 // just call mDNS_Close directly. This is definitely
217 // not safe (because it could reenter mDNS), but
218 // we presume that the user has already tried the safe
221 assert(sigraised
== SIGQUIT
);
223 if (gMDNSPlatformPosixVerboseLevel
> 0) {
224 fprintf(stderr
, "\nSIGQUIT\n");
226 mDNS_Close(&mDNSStorage
);
230 #if COMPILER_LIKES_PRAGMA_MARK
231 #pragma mark ***** Parameter Checking
234 static mDNSBool
CheckThatRichTextNameIsUsable(const char *richTextName
, mDNSBool printExplanation
)
235 // Checks that richTextName is reasonable
236 // label and, if it isn't and printExplanation is true, prints
237 // an explanation of why not.
239 mDNSBool result
= mDNStrue
;
240 if (result
&& strlen(richTextName
) > 63) {
241 if (printExplanation
) {
243 "%s: Service name is too long (must be 63 characters or less)\n",
248 if (result
&& richTextName
[0] == 0) {
249 if (printExplanation
) {
250 fprintf(stderr
, "%s: Service name can't be empty\n", gProgramName
);
257 static mDNSBool
CheckThatServiceTypeIsUsable(const char *serviceType
, mDNSBool printExplanation
)
258 // Checks that serviceType is a reasonable service type
259 // label and, if it isn't and printExplanation is true, prints
260 // an explanation of why not.
265 if (result
&& strlen(serviceType
) > 63) {
266 if (printExplanation
) {
268 "%s: Service type is too long (must be 63 characters or less)\n",
273 if (result
&& serviceType
[0] == 0) {
274 if (printExplanation
) {
276 "%s: Service type can't be empty\n",
284 static mDNSBool
CheckThatPortNumberIsUsable(long portNumber
, mDNSBool printExplanation
)
285 // Checks that portNumber is a reasonable port number
286 // and, if it isn't and printExplanation is true, prints
287 // an explanation of why not.
292 if (result
&& (portNumber
<= 0 || portNumber
> 65535)) {
293 if (printExplanation
) {
295 "%s: Port number specified by -p must be in range 1..65535\n",
303 #if COMPILER_LIKES_PRAGMA_MARK
304 #pragma mark ***** Command Line Arguments
307 static const char kDefaultPIDFile
[] = "/var/run/mDNSResponder.pid";
308 static const char kDefaultServiceType
[] = "_afpovertcp._tcp.";
309 static const char kDefaultServiceDomain
[] = "local.";
311 kDefaultPortNumber
= 548
314 static void PrintUsage()
317 "Usage: %s [-v level ] [-r] [-n name] [-t type] [-d domain] [-p port] [-f file] [-b] [-P pidfile] [-x name=val ...]\n",
319 fprintf(stderr
, " -v verbose mode, level is a number from 0 to 2\n");
320 fprintf(stderr
, " 0 = no debugging info (default)\n");
321 fprintf(stderr
, " 1 = standard debugging info\n");
322 fprintf(stderr
, " 2 = intense debugging info\n");
323 fprintf(stderr
, " can be cycled kill -USR1\n");
324 fprintf(stderr
, " -r also bind to port 53 (port 5353 is always bound)\n");
325 fprintf(stderr
, " -n uses 'name' as the service name (required)\n");
326 fprintf(stderr
, " -t uses 'type' as the service type (default is '%s')\n", kDefaultServiceType
);
327 fprintf(stderr
, " -d uses 'domain' as the service domain (default is '%s')\n", kDefaultServiceDomain
);
328 fprintf(stderr
, " -p uses 'port' as the port number (default is '%d')\n", kDefaultPortNumber
);
329 fprintf(stderr
, " -f reads a service list from 'file'\n");
330 fprintf(stderr
, " -b forces daemon (background) mode\n");
331 fprintf(stderr
, " -P uses 'pidfile' as the PID file\n");
332 fprintf(stderr
, " (default is '%s')\n", kDefaultPIDFile
);
333 fprintf(stderr
, " only meaningful if -b also specified\n");
334 fprintf(stderr
, " -x stores name=val in TXT record (default is empty).\n");
335 fprintf(stderr
, " MUST be the last command-line argument;\n");
336 fprintf(stderr
, " all subsequent arguments after -x are treated as name=val pairs.\n");
339 static mDNSBool gAvoidPort53
= mDNStrue
;
340 static const char *gServiceName
= "";
341 static const char *gServiceType
= kDefaultServiceType
;
342 static const char *gServiceDomain
= kDefaultServiceDomain
;
343 static mDNSu8 gServiceText
[sizeof(RDataBody
)];
344 static mDNSu16 gServiceTextLen
= 0;
345 static int gPortNumber
= kDefaultPortNumber
;
346 static const char *gServiceFile
= "";
347 static mDNSBool gDaemon
= mDNSfalse
;
348 static const char *gPIDFile
= kDefaultPIDFile
;
350 static void ParseArguments(int argc
, char **argv
)
351 // Parses our command line arguments into the global variables
356 // Set gProgramName to the last path component of argv[0]
358 gProgramName
= strrchr(argv
[0], '/');
359 if (gProgramName
== NULL
) {
360 gProgramName
= argv
[0];
365 // Parse command line options using getopt.
368 ch
= getopt(argc
, argv
, "v:rn:t:d:p:f:dP:bx");
372 gMDNSPlatformPosixVerboseLevel
= atoi(optarg
);
373 if (gMDNSPlatformPosixVerboseLevel
< 0 || gMDNSPlatformPosixVerboseLevel
> 2) {
375 "%s: Verbose mode must be in the range 0..2\n",
381 gAvoidPort53
= mDNSfalse
;
384 gServiceName
= optarg
;
385 if ( ! CheckThatRichTextNameIsUsable(gServiceName
, mDNStrue
) ) {
390 gServiceType
= optarg
;
391 if ( ! CheckThatServiceTypeIsUsable(gServiceType
, mDNStrue
) ) {
396 gServiceDomain
= optarg
;
399 gPortNumber
= atol(optarg
);
400 if ( ! CheckThatPortNumberIsUsable(gPortNumber
, mDNStrue
) ) {
405 gServiceFile
= optarg
;
414 while (optind
< argc
)
416 gServiceText
[gServiceTextLen
] = strlen(argv
[optind
]);
417 mDNSPlatformMemCopy(gServiceText
+gServiceTextLen
+1, argv
[optind
], gServiceText
[gServiceTextLen
]);
418 gServiceTextLen
+= 1 + gServiceText
[gServiceTextLen
];
432 // Check for any left over command line arguments.
434 if (optind
!= argc
) {
436 fprintf(stderr
, "%s: Unexpected argument '%s'\n", gProgramName
, argv
[optind
]);
440 // Check for inconsistency between the arguments.
442 if ( (gServiceName
[0] == 0) && (gServiceFile
[0] == 0) ) {
444 fprintf(stderr
, "%s: You must specify a service name to register (-n) or a service file (-f).\n", gProgramName
);
449 #if COMPILER_LIKES_PRAGMA_MARK
450 #pragma mark ***** Registration
453 typedef struct PosixService PosixService
;
455 struct PosixService
{
456 ServiceRecordSet coreServ
;
461 static PosixService
*gServiceList
= NULL
;
463 static void RegistrationCallback(mDNS
*const m
, ServiceRecordSet
*const thisRegistration
, mStatus status
)
464 // mDNS core calls this routine to tell us about the status of
465 // our registration. The appropriate action to take depends
466 // entirely on the value of status.
470 case mStatus_NoError
:
471 debugf("Callback: %##s Name Registered", thisRegistration
->RR_SRV
.resrec
.name
->c
);
472 // Do nothing; our name was successfully registered. We may
473 // get more call backs in the future.
476 case mStatus_NameConflict
:
477 debugf("Callback: %##s Name Conflict", thisRegistration
->RR_SRV
.resrec
.name
->c
);
479 // In the event of a conflict, this sample RegistrationCallback
480 // just calls mDNS_RenameAndReregisterService to automatically
481 // pick a new unique name for the service. For a device such as a
482 // printer, this may be appropriate. For a device with a user
483 // interface, and a screen, and a keyboard, the appropriate response
484 // may be to prompt the user and ask them to choose a new name for
487 // Also, what do we do if mDNS_RenameAndReregisterService returns an
488 // error. Right now I have no place to send that error to.
490 status
= mDNS_RenameAndReregisterService(m
, thisRegistration
, mDNSNULL
);
491 assert(status
== mStatus_NoError
);
494 case mStatus_MemFree
:
495 debugf("Callback: %##s Memory Free", thisRegistration
->RR_SRV
.resrec
.name
->c
);
497 // When debugging is enabled, make sure that thisRegistration
498 // is not on our gServiceList.
502 PosixService
*cursor
;
504 cursor
= gServiceList
;
505 while (cursor
!= NULL
) {
506 assert(&cursor
->coreServ
!= thisRegistration
);
507 cursor
= cursor
->next
;
511 free(thisRegistration
);
515 debugf("Callback: %##s Unknown Status %ld", thisRegistration
->RR_SRV
.resrec
.name
->c
, status
);
520 static int gServiceID
= 0;
522 static mStatus
RegisterOneService(const char * richTextName
,
523 const char * serviceType
,
524 const char * serviceDomain
,
530 PosixService
* thisServ
;
535 status
= mStatus_NoError
;
536 thisServ
= (PosixService
*) malloc(sizeof(*thisServ
));
537 if (thisServ
== NULL
) {
538 status
= mStatus_NoMemoryErr
;
540 if (status
== mStatus_NoError
) {
541 MakeDomainLabelFromLiteralString(&name
, richTextName
);
542 MakeDomainNameFromDNSNameString(&type
, serviceType
);
543 MakeDomainNameFromDNSNameString(&domain
, serviceDomain
);
544 status
= mDNS_RegisterService(&mDNSStorage
, &thisServ
->coreServ
,
545 &name
, &type
, &domain
, // Name, type, domain
546 NULL
, mDNSOpaque16fromIntVal(portNumber
),
547 text
, textLen
, // TXT data, length
549 mDNSInterface_Any
, // Interface ID
550 RegistrationCallback
, thisServ
); // Callback and context
552 if (status
== mStatus_NoError
) {
553 thisServ
->serviceID
= gServiceID
;
556 thisServ
->next
= gServiceList
;
557 gServiceList
= thisServ
;
559 if (gMDNSPlatformPosixVerboseLevel
> 0) {
561 "%s: Registered service %d, name '%s', type '%s', port %ld\n",
569 if (thisServ
!= NULL
) {
576 static mDNSBool
ReadALine(char *buf
, size_t bufSize
, FILE *fp
)
577 // Read a line, skipping over any blank lines or lines starting with '#'
581 good
= (fgets(buf
, bufSize
, fp
) != NULL
);
582 skip
= (good
&& (buf
[0] == '#'));
583 } while (good
&& skip
);
586 int len
= strlen( buf
);
587 if ( buf
[len
- 1] == '\r' || buf
[len
- 1] == '\n')
593 static mStatus
RegisterServicesInFile(const char *filePath
)
595 mStatus status
= mStatus_NoError
;
596 FILE * fp
= fopen(filePath
, "r");
600 status
= mStatus_UnknownErr
;
602 if (status
== mStatus_NoError
) {
603 mDNSBool good
= mDNStrue
;
608 const char *dom
= kDefaultServiceDomain
;
610 mDNSu8 text
[sizeof(RDataBody
)];
611 unsigned int textLen
= 0;
614 // Skip over any blank lines.
615 do ch
= fgetc(fp
); while ( ch
== '\n' || ch
== '\r' );
616 if (ch
!= EOF
) good
= (ungetc(ch
, fp
) == ch
);
618 // Read three lines, check them for validity, and register the service.
619 good
= ReadALine(name
, sizeof(name
), fp
);
621 good
= ReadALine(type
, sizeof(type
), fp
);
625 while (*p
&& *p
!= ' ') p
++;
632 good
= ReadALine(port
, sizeof(port
), fp
);
635 good
= CheckThatRichTextNameIsUsable(name
, mDNSfalse
)
636 && CheckThatServiceTypeIsUsable(type
, mDNSfalse
)
637 && CheckThatPortNumberIsUsable(atol(port
), mDNSfalse
);
642 if (!ReadALine(rawText
, sizeof(rawText
), fp
)) break;
643 len
= strlen(rawText
);
646 unsigned int newlen
= textLen
+ 1 + len
;
647 if (len
== 0 || newlen
>= sizeof(text
)) break;
649 mDNSPlatformMemCopy(text
+ textLen
+ 1, rawText
, len
);
653 fprintf(stderr
, "%s: TXT attribute too long for name = %s, type = %s, port = %s\n",
654 gProgramName
, name
, type
, port
);
658 status
= RegisterOneService(name
, type
, dom
, text
, textLen
, atol(port
));
659 if (status
!= mStatus_NoError
) {
660 fprintf(stderr
, "%s: Failed to register service, name = %s, type = %s, port = %s\n",
661 gProgramName
, name
, type
, port
);
662 status
= mStatus_NoError
; // keep reading
665 } while (good
&& !feof(fp
));
668 fprintf(stderr
, "%s: Error reading service file %s\n", gProgramName
, filePath
);
680 static mStatus
RegisterOurServices(void)
684 status
= mStatus_NoError
;
685 if (gServiceName
[0] != 0) {
686 status
= RegisterOneService(gServiceName
,
689 gServiceText
, gServiceTextLen
,
692 if (status
== mStatus_NoError
&& gServiceFile
[0] != 0) {
693 status
= RegisterServicesInFile(gServiceFile
);
698 static void DeregisterOurServices(void)
700 PosixService
*thisServ
;
703 while (gServiceList
!= NULL
) {
704 thisServ
= gServiceList
;
705 gServiceList
= thisServ
->next
;
707 thisServID
= thisServ
->serviceID
;
709 mDNS_DeregisterService(&mDNSStorage
, &thisServ
->coreServ
);
711 if (gMDNSPlatformPosixVerboseLevel
> 0) {
713 "%s: Deregistered service %d\n",
715 thisServ
->serviceID
);
720 #if COMPILER_LIKES_PRAGMA_MARK
721 #pragma mark **** Main
724 int main(int argc
, char **argv
)
729 // Parse our command line arguments. This won't come back if there's an error.
731 ParseArguments(argc
, argv
);
733 // If we're told to run as a daemon, then do that straight away.
734 // Note that we don't treat the inability to create our PID
735 // file as an error. Also note that we assign getpid to a long
736 // because printf has no format specified for pid_t.
740 if (gMDNSPlatformPosixVerboseLevel
> 0) {
741 fprintf(stderr
, "%s: Starting in daemon mode\n", gProgramName
);
743 result
= daemon(0,0);
748 fp
= fopen(gPIDFile
, "w");
750 fprintf(fp
, "%ld\n", (long) getpid());
755 fprintf(stderr
, "%s: Could not run as daemon - exiting\n", gProgramName
);
759 if (gMDNSPlatformPosixVerboseLevel
> 0) {
760 fprintf(stderr
, "%s: Starting in foreground mode, PID %ld\n", gProgramName
, (long) getpid());
764 status
= mDNS_Init(&mDNSStorage
, &PlatformStorage
,
765 mDNS_Init_NoCache
, mDNS_Init_ZeroCacheSize
,
766 mDNS_Init_AdvertiseLocalAddresses
,
767 mDNS_Init_NoInitCallback
, mDNS_Init_NoInitCallbackContext
);
768 if (status
!= mStatus_NoError
) return(2);
770 status
= RegisterOurServices();
771 if (status
!= mStatus_NoError
) return(2);
773 signal(SIGHUP
, HandleSigHup
); // SIGHUP has to be sent by kill -HUP <pid>
774 signal(SIGINT
, HandleSigInt
); // SIGINT is what you get for a Ctrl-C
775 signal(SIGQUIT
, HandleSigQuit
); // SIGQUIT is what you get for a Ctrl-\ (indeed)
776 signal(SIGUSR1
, HandleSigUsr1
); // SIGUSR1 has to be sent by kill -USR1 <pid>
782 struct timeval timeout
;
785 // 1. Set up the fd_set as usual here.
786 // This example client has no file descriptors of its own,
787 // but a real application would call FD_SET to add them to the set here
790 // 2. Set up the timeout.
791 // This example client has no other work it needs to be doing,
792 // so we set an effectively infinite timeout
793 timeout
.tv_sec
= 0x3FFFFFFF;
796 // 3. Give the mDNSPosix layer a chance to add its information to the fd_set and timeout
797 mDNSPosixGetFDSet(&mDNSStorage
, &nfds
, &readfds
, &timeout
);
799 // 4. Call select as normal
800 verbosedebugf("select(%d, %d.%06d)", nfds
, timeout
.tv_sec
, timeout
.tv_usec
);
801 result
= select(nfds
, &readfds
, NULL
, NULL
, &timeout
);
805 verbosedebugf("select() returned %d errno %d", result
, errno
);
806 if (errno
!= EINTR
) gStopNow
= mDNStrue
;
809 if (gReceivedSigUsr1
)
811 gReceivedSigUsr1
= mDNSfalse
;
812 gMDNSPlatformPosixVerboseLevel
+= 1;
813 if (gMDNSPlatformPosixVerboseLevel
> 2)
814 gMDNSPlatformPosixVerboseLevel
= 0;
815 if ( gMDNSPlatformPosixVerboseLevel
> 0 )
816 fprintf(stderr
, "\nVerbose level %d\n", gMDNSPlatformPosixVerboseLevel
);
820 if (gMDNSPlatformPosixVerboseLevel
> 0)
821 fprintf(stderr
, "\nSIGHUP\n");
822 gReceivedSigHup
= mDNSfalse
;
823 DeregisterOurServices();
824 status
= mDNSPlatformPosixRefreshInterfaceList(&mDNSStorage
);
825 if (status
!= mStatus_NoError
) break;
826 status
= RegisterOurServices();
827 if (status
!= mStatus_NoError
) break;
833 // 5. Call mDNSPosixProcessFDSet to let the mDNSPosix layer do its work
834 mDNSPosixProcessFDSet(&mDNSStorage
, &readfds
);
836 // 6. This example client has no other work it needs to be doing,
837 // but a real client would do its work here
844 DeregisterOurServices();
845 mDNS_Close(&mDNSStorage
);
847 if (status
== mStatus_NoError
) {
852 if ( (result
!= 0) || (gMDNSPlatformPosixVerboseLevel
> 0) ) {
853 fprintf(stderr
, "%s: Finished with status %d, result %d\n", gProgramName
, (int)status
, result
);