source: rtems-libbsd/mDNSResponder/mDNSPosix/Responder.c @ 7d33d36

55-freebsd-126-freebsd-12
Last change on this file since 7d33d36 was 7d33d36, checked in by Sebastian Huber <sebastian.huber@…>, on 09/19/18 at 06:54:52

mDNSResponder: Update to v765.30.11

The sources can be obtained via:

https://opensource.apple.com/tarballs/mDNSResponder/mDNSResponder-765.30.11.tar.gz

Update #3522.

  • Property mode set to 100755
File size: 26.8 KB
Line 
1/* -*- Mode: C; tab-width: 4 -*-
2 *
3 * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
4 *
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
8 *
9 *     http://www.apache.org/licenses/LICENSE-2.0
10 *
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.
16 */
17
18#if __APPLE__
19// In Mac OS X 10.5 and later trying to use the daemon function gives a “‘daemon’ is deprecated”
20// error, which prevents compilation because we build with "-Werror".
21// Since this is supposed to be portable cross-platform code, we don't care that daemon is
22// deprecated on Mac OS X 10.5, so we use this preprocessor trick to eliminate the error message.
23#define daemon yes_we_know_that_daemon_is_deprecated_in_os_x_10_5_thankyou
24#endif
25
26#include <assert.h>
27#include <stdio.h>          // For printf()
28#include <stdlib.h>         // For exit() etc.
29#include <string.h>         // For strlen() etc.
30#include <unistd.h>         // For select()
31#include <errno.h>          // For errno, EINTR
32#include <signal.h>
33#include <fcntl.h>
34
35#if __APPLE__
36#undef daemon
37extern int daemon(int, int);
38#endif
39
40#include "mDNSEmbeddedAPI.h" // Defines the interface to the client layer above
41#include "mDNSPosix.h"      // Defines the specific types needed to run mDNS on this platform
42#include "mDNSUNP.h"        // For daemon()
43
44#if COMPILER_LIKES_PRAGMA_MARK
45#pragma mark ***** Globals
46#endif
47
48static mDNS mDNSStorage;       // mDNS core uses this to store its globals
49static mDNS_PlatformSupport PlatformStorage;  // Stores this platform's globals
50
51mDNSexport const char ProgramName[] = "mDNSResponderPosix";
52
53static const char *gProgramName = ProgramName;
54
55#if COMPILER_LIKES_PRAGMA_MARK
56#pragma mark ***** Signals
57#endif
58
59static volatile mDNSBool gReceivedSigUsr1;
60static volatile mDNSBool gReceivedSigHup;
61static volatile mDNSBool gStopNow;
62
63// We support 4 signals.
64//
65// o SIGUSR1 toggles verbose mode on and off in debug builds
66// o SIGHUP  triggers the program to re-read its preferences.
67// o SIGINT  causes an orderly shutdown of the program.
68// o SIGQUIT causes a somewhat orderly shutdown (direct but dangerous)
69// o SIGKILL kills us dead (easy to implement :-)
70//
71// There are fatal race conditions in our signal handling, but there's not much
72// we can do about them while remaining within the Posix space.  Specifically,
73// if a signal arrives after we test the globals its sets but before we call
74// select, the signal will be dropped.  The user will have to send the signal
75// again.  Unfortunately, Posix does not have a "sigselect" to atomically
76// modify the signal mask and start a select.
77
78static void HandleSigUsr1(int sigraised)
79// If we get a SIGUSR1 we toggle the state of the
80// verbose mode.
81{
82    assert(sigraised == SIGUSR1);
83    gReceivedSigUsr1 = mDNStrue;
84}
85
86static void HandleSigHup(int sigraised)
87// A handler for SIGHUP that causes us to break out of the
88// main event loop when the user kill 1's us.  This has the
89// effect of triggered the main loop to deregister the
90// current services and re-read the preferences.
91{
92    assert(sigraised == SIGHUP);
93    gReceivedSigHup = mDNStrue;
94}
95
96static void HandleSigInt(int sigraised)
97// A handler for SIGINT that causes us to break out of the
98// main event loop when the user types ^C.  This has the
99// effect of quitting the program.
100{
101    assert(sigraised == SIGINT);
102
103    if (gMDNSPlatformPosixVerboseLevel > 0) {
104        fprintf(stderr, "\nSIGINT\n");
105    }
106    gStopNow = mDNStrue;
107}
108
109static void HandleSigQuit(int sigraised)
110// If we get a SIGQUIT the user is desperate and we
111// just call mDNS_Close directly.  This is definitely
112// not safe (because it could reenter mDNS), but
113// we presume that the user has already tried the safe
114// alternatives.
115{
116    assert(sigraised == SIGQUIT);
117
118    if (gMDNSPlatformPosixVerboseLevel > 0) {
119        fprintf(stderr, "\nSIGQUIT\n");
120    }
121    mDNS_Close(&mDNSStorage);
122    exit(0);
123}
124
125#if COMPILER_LIKES_PRAGMA_MARK
126#pragma mark ***** Parameter Checking
127#endif
128
129static mDNSBool CheckThatRichTextNameIsUsable(const char *richTextName, mDNSBool printExplanation)
130// Checks that richTextName is reasonable
131// label and, if it isn't and printExplanation is true, prints
132// an explanation of why not.
133{
134    mDNSBool result = mDNStrue;
135    if (result && strlen(richTextName) > 63) {
136        if (printExplanation) {
137            fprintf(stderr,
138                    "%s: Service name is too long (must be 63 characters or less)\n",
139                    gProgramName);
140        }
141        result = mDNSfalse;
142    }
143    if (result && richTextName[0] == 0) {
144        if (printExplanation) {
145            fprintf(stderr, "%s: Service name can't be empty\n", gProgramName);
146        }
147        result = mDNSfalse;
148    }
149    return result;
150}
151
152static mDNSBool CheckThatServiceTypeIsUsable(const char *serviceType, mDNSBool printExplanation)
153// Checks that serviceType is a reasonable service type
154// label and, if it isn't and printExplanation is true, prints
155// an explanation of why not.
156{
157    mDNSBool result;
158
159    result = mDNStrue;
160    if (result && strlen(serviceType) > 63) {
161        if (printExplanation) {
162            fprintf(stderr,
163                    "%s: Service type is too long (must be 63 characters or less)\n",
164                    gProgramName);
165        }
166        result = mDNSfalse;
167    }
168    if (result && serviceType[0] == 0) {
169        if (printExplanation) {
170            fprintf(stderr,
171                    "%s: Service type can't be empty\n",
172                    gProgramName);
173        }
174        result = mDNSfalse;
175    }
176    return result;
177}
178
179static mDNSBool CheckThatPortNumberIsUsable(long portNumber, mDNSBool printExplanation)
180// Checks that portNumber is a reasonable port number
181// and, if it isn't and printExplanation is true, prints
182// an explanation of why not.
183{
184    mDNSBool result;
185
186    result = mDNStrue;
187    if (result && (portNumber <= 0 || portNumber > 65535)) {
188        if (printExplanation) {
189            fprintf(stderr,
190                    "%s: Port number specified by -p must be in range 1..65535\n",
191                    gProgramName);
192        }
193        result = mDNSfalse;
194    }
195    return result;
196}
197
198#if COMPILER_LIKES_PRAGMA_MARK
199#pragma mark ***** Command Line Arguments
200#endif
201
202static const char kDefaultPIDFile[]     = "/var/run/mDNSResponder.pid";
203static const char kDefaultServiceType[] = "_afpovertcp._tcp.";
204static const char kDefaultServiceDomain[] = "local.";
205enum {
206    kDefaultPortNumber = 548
207};
208
209static void PrintUsage()
210{
211    fprintf(stderr,
212            "Usage: %s [-v level ] [-r] [-n name] [-t type] [-d domain] [-p port] [-f file] [-b] [-P pidfile] [-x name=val ...]\n",
213            gProgramName);
214    fprintf(stderr, "          -v verbose mode, level is a number from 0 to 2\n");
215    fprintf(stderr, "             0 = no debugging info (default)\n");
216    fprintf(stderr, "             1 = standard debugging info\n");
217    fprintf(stderr, "             2 = intense debugging info\n");
218    fprintf(stderr, "             can be cycled kill -USR1\n");
219    fprintf(stderr, "          -r also bind to port 53 (port 5353 is always bound)\n");
220    fprintf(stderr, "          -n uses 'name' as the service name (required)\n");
221    fprintf(stderr, "          -t uses 'type' as the service type (default is '%s')\n", kDefaultServiceType);
222    fprintf(stderr, "          -d uses 'domain' as the service domain (default is '%s')\n", kDefaultServiceDomain);
223    fprintf(stderr, "          -p uses 'port' as the port number (default is '%d')\n",  kDefaultPortNumber);
224    fprintf(stderr, "          -f reads a service list from 'file'\n");
225    fprintf(stderr, "          -b forces daemon (background) mode\n");
226    fprintf(stderr, "          -P uses 'pidfile' as the PID file\n");
227    fprintf(stderr, "             (default is '%s')\n",  kDefaultPIDFile);
228    fprintf(stderr, "             only meaningful if -b also specified\n");
229    fprintf(stderr, "          -x stores name=val in TXT record (default is empty).\n");
230    fprintf(stderr, "             MUST be the last command-line argument;\n");
231    fprintf(stderr, "             all subsequent arguments after -x are treated as name=val pairs.\n");
232}
233
234static mDNSBool gAvoidPort53      = mDNStrue;
235static const char *gServiceName      = "";
236static const char *gServiceType      = kDefaultServiceType;
237static const char *gServiceDomain    = kDefaultServiceDomain;
238static mDNSu8 gServiceText[sizeof(RDataBody)];
239static mDNSu16 gServiceTextLen   = 0;
240static int gPortNumber       = kDefaultPortNumber;
241static const char *gServiceFile      = "";
242static mDNSBool gDaemon           = mDNSfalse;
243static const char *gPIDFile          = kDefaultPIDFile;
244
245static void ParseArguments(int argc, char **argv)
246// Parses our command line arguments into the global variables
247// listed above.
248{
249    int ch;
250
251    // Set gProgramName to the last path component of argv[0]
252
253    gProgramName = strrchr(argv[0], '/');
254    if (gProgramName == NULL) {
255        gProgramName = argv[0];
256    } else {
257        gProgramName += 1;
258    }
259
260    // Parse command line options using getopt.
261
262    do {
263        ch = getopt(argc, argv, "v:rn:t:d:p:f:dP:bx");
264        if (ch != -1) {
265            switch (ch) {
266            case 'v':
267                gMDNSPlatformPosixVerboseLevel = atoi(optarg);
268                if (gMDNSPlatformPosixVerboseLevel < 0 || gMDNSPlatformPosixVerboseLevel > 2) {
269                    fprintf(stderr,
270                            "%s: Verbose mode must be in the range 0..2\n",
271                            gProgramName);
272                    exit(1);
273                }
274                break;
275            case 'r':
276                gAvoidPort53 = mDNSfalse;
277                break;
278            case 'n':
279                gServiceName = optarg;
280                if ( !CheckThatRichTextNameIsUsable(gServiceName, mDNStrue) ) {
281                    exit(1);
282                }
283                break;
284            case 't':
285                gServiceType = optarg;
286                if ( !CheckThatServiceTypeIsUsable(gServiceType, mDNStrue) ) {
287                    exit(1);
288                }
289                break;
290            case 'd':
291                gServiceDomain = optarg;
292                break;
293            case 'p':
294                gPortNumber = atol(optarg);
295                if ( !CheckThatPortNumberIsUsable(gPortNumber, mDNStrue) ) {
296                    exit(1);
297                }
298                break;
299            case 'f':
300                gServiceFile = optarg;
301                break;
302            case 'b':
303                gDaemon = mDNStrue;
304                break;
305            case 'P':
306                gPIDFile = optarg;
307                break;
308            case 'x':
309                while (optind < argc)
310                {
311                    gServiceText[gServiceTextLen] = strlen(argv[optind]);
312                    mDNSPlatformMemCopy(gServiceText+gServiceTextLen+1, argv[optind], gServiceText[gServiceTextLen]);
313                    gServiceTextLen += 1 + gServiceText[gServiceTextLen];
314                    optind++;
315                }
316                ch = -1;
317                break;
318            case '?':
319            default:
320                PrintUsage();
321                exit(1);
322                break;
323            }
324        }
325    } while (ch != -1);
326
327    // Check for any left over command line arguments.
328
329    if (optind != argc) {
330        PrintUsage();
331        fprintf(stderr, "%s: Unexpected argument '%s'\n", gProgramName, argv[optind]);
332        exit(1);
333    }
334
335    // Check for inconsistency between the arguments.
336
337    if ( (gServiceName[0] == 0) && (gServiceFile[0] == 0) ) {
338        PrintUsage();
339        fprintf(stderr, "%s: You must specify a service name to register (-n) or a service file (-f).\n", gProgramName);
340        exit(1);
341    }
342}
343
344#if COMPILER_LIKES_PRAGMA_MARK
345#pragma mark ***** Registration
346#endif
347
348typedef struct PosixService PosixService;
349
350struct PosixService {
351    ServiceRecordSet coreServ;
352    PosixService *next;
353    int serviceID;
354};
355
356static PosixService *gServiceList = NULL;
357
358static void RegistrationCallback(mDNS *const m, ServiceRecordSet *const thisRegistration, mStatus status)
359// mDNS core calls this routine to tell us about the status of
360// our registration.  The appropriate action to take depends
361// entirely on the value of status.
362{
363    switch (status) {
364
365    case mStatus_NoError:
366        debugf("Callback: %##s Name Registered",   thisRegistration->RR_SRV.resrec.name->c);
367        // Do nothing; our name was successfully registered.  We may
368        // get more call backs in the future.
369        break;
370
371    case mStatus_NameConflict:
372        debugf("Callback: %##s Name Conflict",     thisRegistration->RR_SRV.resrec.name->c);
373
374        // In the event of a conflict, this sample RegistrationCallback
375        // just calls mDNS_RenameAndReregisterService to automatically
376        // pick a new unique name for the service. For a device such as a
377        // printer, this may be appropriate.  For a device with a user
378        // interface, and a screen, and a keyboard, the appropriate response
379        // may be to prompt the user and ask them to choose a new name for
380        // the service.
381        //
382        // Also, what do we do if mDNS_RenameAndReregisterService returns an
383        // error.  Right now I have no place to send that error to.
384
385        status = mDNS_RenameAndReregisterService(m, thisRegistration, mDNSNULL);
386        assert(status == mStatus_NoError);
387        break;
388
389    case mStatus_MemFree:
390        debugf("Callback: %##s Memory Free",       thisRegistration->RR_SRV.resrec.name->c);
391
392        // When debugging is enabled, make sure that thisRegistration
393        // is not on our gServiceList.
394
395            #if !defined(NDEBUG)
396        {
397            PosixService *cursor;
398
399            cursor = gServiceList;
400            while (cursor != NULL) {
401                assert(&cursor->coreServ != thisRegistration);
402                cursor = cursor->next;
403            }
404        }
405            #endif
406        free(thisRegistration);
407        break;
408
409    default:
410        debugf("Callback: %##s Unknown Status %ld", thisRegistration->RR_SRV.resrec.name->c, status);
411        break;
412    }
413}
414
415static int gServiceID = 0;
416
417static mStatus RegisterOneService(const char *  richTextName,
418                                  const char *  serviceType,
419                                  const char *  serviceDomain,
420                                  const mDNSu8 text[],
421                                  mDNSu16 textLen,
422                                  long portNumber)
423{
424    mStatus status;
425    PosixService *      thisServ;
426    domainlabel name;
427    domainname type;
428    domainname domain;
429
430    status = mStatus_NoError;
431    thisServ = (PosixService *) malloc(sizeof(*thisServ));
432    if (thisServ == NULL) {
433        status = mStatus_NoMemoryErr;
434    }
435    if (status == mStatus_NoError) {
436        MakeDomainLabelFromLiteralString(&name,  richTextName);
437        MakeDomainNameFromDNSNameString(&type, serviceType);
438        MakeDomainNameFromDNSNameString(&domain, serviceDomain);
439        status = mDNS_RegisterService(&mDNSStorage, &thisServ->coreServ,
440                                      &name, &type, &domain, // Name, type, domain
441                                      NULL, mDNSOpaque16fromIntVal(portNumber),
442                                      text, textLen, // TXT data, length
443                                      NULL, 0,      // Subtypes
444                                      mDNSInterface_Any, // Interface ID
445                                      RegistrationCallback, thisServ, 0); // Callback, context, flags
446    }
447    if (status == mStatus_NoError) {
448        thisServ->serviceID = gServiceID;
449        gServiceID += 1;
450
451        thisServ->next = gServiceList;
452        gServiceList = thisServ;
453
454        if (gMDNSPlatformPosixVerboseLevel > 0) {
455            fprintf(stderr,
456                    "%s: Registered service %d, name \"%s\", type \"%s\", domain \"%s\",  port %ld\n",
457                    gProgramName,
458                    thisServ->serviceID,
459                    richTextName,
460                    serviceType,
461                    serviceDomain,
462                    portNumber);
463        }
464    } else {
465        if (thisServ != NULL) {
466            free(thisServ);
467        }
468    }
469    return status;
470}
471
472static mDNSBool ReadALine(char *buf, size_t bufSize, FILE *fp, mDNSBool skipBlankLines)
473{
474    size_t len;
475    mDNSBool readNextLine;
476
477    do {
478        readNextLine = mDNSfalse;
479
480        if (fgets(buf, bufSize, fp) == NULL)
481            return mDNSfalse;   // encountered EOF or an error condition
482
483        // These first characters indicate a blank line.
484        if (buf[0] == ' ' || buf[0] == '\t' || buf[0] == '\r' || buf[0] == '\n') {
485            if (!skipBlankLines)
486                return mDNSfalse;
487            readNextLine = mDNStrue;
488        }
489        // always skip comment lines
490        if (buf[0] == '#')
491            readNextLine = mDNStrue;
492
493    } while (readNextLine);
494
495    len = strlen( buf);
496    if ( buf[len - 1] == '\r' || buf[len - 1] == '\n')
497        buf[len - 1] = '\0';
498
499    return mDNStrue;
500}
501
502static mStatus RegisterServicesInFile(const char *filePath)
503{
504    mStatus status = mStatus_NoError;
505    FILE *      fp = fopen(filePath, "r");
506    int rv;
507
508    if (fp == NULL) {
509        return mStatus_UnknownErr;
510    }
511
512    if (gMDNSPlatformPosixVerboseLevel > 1)
513        fprintf(stderr, "Parsing %s for services\n", filePath);
514
515    do {
516        char nameBuf[256];
517        char * name = nameBuf;
518        char type[256];
519        const char *dom = kDefaultServiceDomain;
520        char rawText[1024];
521        mDNSu8 text[sizeof(RDataBody)];
522        unsigned int textLen = 0;
523        char port[256];
524        char *p;
525
526        // Read the service name, type, port, and optional text record fields.
527        // Skip blank lines while looking for the next service name.
528        if (!ReadALine(name, sizeof(nameBuf), fp, mDNStrue))
529            break;
530
531        // Special case that allows service name to begin with a '#'
532        // character by escaping it with a '\' to distiguish it from
533        // a comment line.  Remove the leading '\' here before
534        // registering the service.
535        if (name[0] == '\\' && name[1] == '#')
536            name++;
537
538        if (gMDNSPlatformPosixVerboseLevel > 1)
539            fprintf(stderr, "Service name: \"%s\"\n", name);
540
541        // Don't skip blank lines in calls to ReadAline() after finding the
542        // service name since the next blank line indicates the end
543        // of this service record.
544        if (!ReadALine(type, sizeof(type), fp, mDNSfalse))
545            break;
546
547        // see if a domain name is specified
548        p = type;
549        while (*p && *p != ' ' && *p != '\t') p++;
550        if (*p) {
551            *p = 0; // NULL terminate the <type>.<protocol> string
552            // skip any leading whitespace before domain name
553            p++;
554            while (*p && (*p == ' ' || *p == '\t')) p++;
555            if (*p)
556                dom = p;
557        }
558        if (gMDNSPlatformPosixVerboseLevel > 1) {
559            fprintf(stderr, "Service type: \"%s\"\n", type);
560            fprintf(stderr, "Service domain: \"%s\"\n", dom);
561        }
562
563        if (!ReadALine(port, sizeof(port), fp, mDNSfalse))
564            break;
565        if (gMDNSPlatformPosixVerboseLevel > 1)
566            fprintf(stderr, "Service port: %s\n", port);
567
568        if (   !CheckThatRichTextNameIsUsable(name, mDNStrue)
569               || !CheckThatServiceTypeIsUsable(type, mDNStrue)
570               || !CheckThatPortNumberIsUsable(atol(port), mDNStrue))
571            break;
572
573        // read the TXT record fields
574        while (1) {
575            int len;
576            if (!ReadALine(rawText, sizeof(rawText), fp, mDNSfalse)) break;
577            if (gMDNSPlatformPosixVerboseLevel > 1)
578                fprintf(stderr, "Text string: \"%s\"\n", rawText);
579            len = strlen(rawText);
580            if (len <= 255)
581            {
582                unsigned int newlen = textLen + 1 + len;
583                if (len == 0 || newlen >= sizeof(text)) break;
584                text[textLen] = len;
585                mDNSPlatformMemCopy(text + textLen + 1, rawText, len);
586                textLen = newlen;
587            }
588            else
589                fprintf(stderr, "%s: TXT attribute too long for name = %s, type = %s, port = %s\n",
590                        gProgramName, name, type, port);
591        }
592
593        status = RegisterOneService(name, type, dom, text, textLen, atol(port));
594        if (status != mStatus_NoError) {
595            // print error, but try to read and register other services in the file
596            fprintf(stderr, "%s: Failed to register service, name \"%s\", type \"%s\", domain \"%s\", port %s\n",
597                    gProgramName, name, type, dom, port);
598        }
599
600    } while (!feof(fp));
601
602    if (!feof(fp)) {
603        fprintf(stderr, "%s: Error reading service file %s\n", gProgramName, filePath);
604        status = mStatus_UnknownErr;
605    }
606
607    rv = fclose(fp);
608    assert(rv == 0);
609
610    return status;
611}
612
613static mStatus RegisterOurServices(void)
614{
615    mStatus status;
616
617    status = mStatus_NoError;
618    if (gServiceName[0] != 0) {
619        status = RegisterOneService(gServiceName,
620                                    gServiceType,
621                                    gServiceDomain,
622                                    gServiceText, gServiceTextLen,
623                                    gPortNumber);
624    }
625    if (status == mStatus_NoError && gServiceFile[0] != 0) {
626        status = RegisterServicesInFile(gServiceFile);
627    }
628    return status;
629}
630
631static void DeregisterOurServices(void)
632{
633    PosixService *thisServ;
634    int thisServID;
635
636    while (gServiceList != NULL) {
637        thisServ = gServiceList;
638        gServiceList = thisServ->next;
639
640        thisServID = thisServ->serviceID;
641
642        mDNS_DeregisterService(&mDNSStorage, &thisServ->coreServ);
643
644        if (gMDNSPlatformPosixVerboseLevel > 0) {
645            fprintf(stderr,
646                    "%s: Deregistered service %d\n",
647                    gProgramName,
648                    thisServ->serviceID);
649        }
650    }
651}
652
653#if COMPILER_LIKES_PRAGMA_MARK
654#pragma mark **** Main
655#endif
656
657int main(int argc, char **argv)
658{
659    mStatus status;
660    int result;
661
662    // Parse our command line arguments.  This won't come back if there's an error.
663
664    ParseArguments(argc, argv);
665
666    // If we're told to run as a daemon, then do that straight away.
667    // Note that we don't treat the inability to create our PID
668    // file as an error.  Also note that we assign getpid to a long
669    // because printf has no format specified for pid_t.
670
671    if (gDaemon) {
672        int result;
673        if (gMDNSPlatformPosixVerboseLevel > 0) {
674            fprintf(stderr, "%s: Starting in daemon mode\n", gProgramName);
675        }
676        result = daemon(0,0);
677        if (result == 0) {
678            FILE *fp;
679            int junk;
680
681            fp = fopen(gPIDFile, "w");
682            if (fp != NULL) {
683                fprintf(fp, "%ld\n", (long) getpid());
684                junk = fclose(fp);
685                assert(junk == 0);
686            }
687        } else {
688            fprintf(stderr, "%s: Could not run as daemon - exiting\n", gProgramName);
689            exit(result);
690        }
691    } else {
692        if (gMDNSPlatformPosixVerboseLevel > 0) {
693            fprintf(stderr, "%s: Starting in foreground mode, PID %ld\n", gProgramName, (long) getpid());
694        }
695    }
696
697    status = mDNS_Init(&mDNSStorage, &PlatformStorage,
698                       mDNS_Init_NoCache, mDNS_Init_ZeroCacheSize,
699                       mDNS_Init_AdvertiseLocalAddresses,
700                       mDNS_Init_NoInitCallback, mDNS_Init_NoInitCallbackContext);
701    if (status != mStatus_NoError) return(2);
702
703    status = RegisterOurServices();
704    if (status != mStatus_NoError) return(2);
705
706    signal(SIGHUP,  HandleSigHup);      // SIGHUP has to be sent by kill -HUP <pid>
707    signal(SIGINT,  HandleSigInt);      // SIGINT is what you get for a Ctrl-C
708    signal(SIGQUIT, HandleSigQuit);     // SIGQUIT is what you get for a Ctrl-\ (indeed)
709    signal(SIGUSR1, HandleSigUsr1);     // SIGUSR1 has to be sent by kill -USR1 <pid>
710
711    while (!gStopNow)
712    {
713        int nfds = 0;
714        fd_set readfds;
715        struct timeval timeout;
716        int result;
717
718        // 1. Set up the fd_set as usual here.
719        // This example client has no file descriptors of its own,
720        // but a real application would call FD_SET to add them to the set here
721        FD_ZERO(&readfds);
722
723        // 2. Set up the timeout.
724        // This example client has no other work it needs to be doing,
725        // so we set an effectively infinite timeout
726        timeout.tv_sec = 0x3FFFFFFF;
727        timeout.tv_usec = 0;
728
729        // 3. Give the mDNSPosix layer a chance to add its information to the fd_set and timeout
730        mDNSPosixGetFDSet(&mDNSStorage, &nfds, &readfds, &timeout);
731
732        // 4. Call select as normal
733        verbosedebugf("select(%d, %d.%06d)", nfds, timeout.tv_sec, timeout.tv_usec);
734        result = select(nfds, &readfds, NULL, NULL, &timeout);
735
736        if (result < 0)
737        {
738            verbosedebugf("select() returned %d errno %d", result, errno);
739            if (errno != EINTR) gStopNow = mDNStrue;
740            else
741            {
742                if (gReceivedSigUsr1)
743                {
744                    gReceivedSigUsr1 = mDNSfalse;
745                    gMDNSPlatformPosixVerboseLevel += 1;
746                    if (gMDNSPlatformPosixVerboseLevel > 2)
747                        gMDNSPlatformPosixVerboseLevel = 0;
748                    if ( gMDNSPlatformPosixVerboseLevel > 0 )
749                        fprintf(stderr, "\nVerbose level %d\n", gMDNSPlatformPosixVerboseLevel);
750                }
751                if (gReceivedSigHup)
752                {
753                    if (gMDNSPlatformPosixVerboseLevel > 0)
754                        fprintf(stderr, "\nSIGHUP\n");
755                    gReceivedSigHup = mDNSfalse;
756                    DeregisterOurServices();
757                    status = mDNSPlatformPosixRefreshInterfaceList(&mDNSStorage);
758                    if (status != mStatus_NoError) break;
759                    status = RegisterOurServices();
760                    if (status != mStatus_NoError) break;
761                }
762            }
763        }
764        else
765        {
766            // 5. Call mDNSPosixProcessFDSet to let the mDNSPosix layer do its work
767            mDNSPosixProcessFDSet(&mDNSStorage, &readfds);
768
769            // 6. This example client has no other work it needs to be doing,
770            // but a real client would do its work here
771            // ... (do work) ...
772        }
773    }
774
775    debugf("Exiting");
776
777    DeregisterOurServices();
778    mDNS_Close(&mDNSStorage);
779
780    if (status == mStatus_NoError) {
781        result = 0;
782    } else {
783        result = 2;
784    }
785    if ( (result != 0) || (gMDNSPlatformPosixVerboseLevel > 0) ) {
786        fprintf(stderr, "%s: Finished with status %d, result %d\n", gProgramName, (int)status, result);
787    }
788
789    return result;
790}
Note: See TracBrowser for help on using the repository browser.