147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt/* -*- Mode: C; tab-width: 4 -*-
247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt *
347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt *
547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt * Licensed under the Apache License, Version 2.0 (the "License");
647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt * you may not use this file except in compliance with the License.
747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt * You may obtain a copy of the License at
847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt *
947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt *     http://www.apache.org/licenses/LICENSE-2.0
1047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt *
1147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt * Unless required by applicable law or agreed to in writing, software
1247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt * distributed under the License is distributed on an "AS IS" BASIS,
1347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt * See the License for the specific language governing permissions and
1547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt * limitations under the License.
1647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt */
1747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
1847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#if __APPLE__
1947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// In Mac OS X 10.5 and later trying to use the daemon function gives a “‘daemon’ is deprecated”
2047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// error, which prevents compilation because we build with "-Werror".
2147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// Since this is supposed to be portable cross-platform code, we don't care that daemon is
2247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// deprecated on Mac OS X 10.5, so we use this preprocessor trick to eliminate the error message.
2347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#define daemon yes_we_know_that_daemon_is_deprecated_in_os_x_10_5_thankyou
2447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#endif
2547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
2647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#include <assert.h>
2747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#include <stdio.h>			// For printf()
2847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#include <stdlib.h>			// For exit() etc.
2947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#include <string.h>			// For strlen() etc.
3047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#include <unistd.h>			// For select()
3147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#include <errno.h>			// For errno, EINTR
3247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#include <signal.h>
3347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#include <fcntl.h>
3447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
3547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#if __APPLE__
3647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#undef daemon
3747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwaltextern int daemon(int, int);
3847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#endif
3947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
4047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#include "mDNSEmbeddedAPI.h"// Defines the interface to the client layer above
4147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#include "mDNSPosix.h"		// Defines the specific types needed to run mDNS on this platform
4247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#include "mDNSUNP.h"		// For daemon()
4347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
4447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#if COMPILER_LIKES_PRAGMA_MARK
4547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#pragma mark ***** Globals
4647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#endif
4747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
4847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwaltstatic mDNS mDNSStorage;       // mDNS core uses this to store its globals
4947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwaltstatic mDNS_PlatformSupport PlatformStorage;  // Stores this platform's globals
5047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
5147e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport const char ProgramName[] = "mDNSResponderPosix";
5247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
5347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwaltstatic const char *gProgramName = ProgramName;
5447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
5547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#if COMPILER_LIKES_PRAGMA_MARK
5647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#pragma mark ***** Signals
5747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#endif
5847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
5947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwaltstatic volatile mDNSBool gReceivedSigUsr1;
6047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwaltstatic volatile mDNSBool gReceivedSigHup;
6147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwaltstatic volatile mDNSBool gStopNow;
6247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
6347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// We support 4 signals.
6447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt//
6547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// o SIGUSR1 toggles verbose mode on and off in debug builds
6647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// o SIGHUP  triggers the program to re-read its preferences.
6747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// o SIGINT  causes an orderly shutdown of the program.
6847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// o SIGQUIT causes a somewhat orderly shutdown (direct but dangerous)
6947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// o SIGKILL kills us dead (easy to implement :-)
7047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt//
7147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// There are fatal race conditions in our signal handling, but there's not much
7247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// we can do about them while remaining within the Posix space.  Specifically,
7347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// if a signal arrives after we test the globals its sets but before we call
7447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// select, the signal will be dropped.  The user will have to send the signal
7547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// again.  Unfortunately, Posix does not have a "sigselect" to atomically
7647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// modify the signal mask and start a select.
7747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
7847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwaltstatic void HandleSigUsr1(int sigraised)
7947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt    // If we get a SIGUSR1 we toggle the state of the
8047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt    // verbose mode.
8147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt{
8247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt    assert(sigraised == SIGUSR1);
8347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt    gReceivedSigUsr1 = mDNStrue;
8447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt}
8547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
8647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwaltstatic void HandleSigHup(int sigraised)
8747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt    // A handler for SIGHUP that causes us to break out of the
8847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt    // main event loop when the user kill 1's us.  This has the
8947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt    // effect of triggered the main loop to deregister the
9047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt    // current services and re-read the preferences.
9147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt{
9247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt    assert(sigraised == SIGHUP);
9347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	gReceivedSigHup = mDNStrue;
9447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt}
9547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
9647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwaltstatic void HandleSigInt(int sigraised)
9747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt    // A handler for SIGINT that causes us to break out of the
9847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt    // main event loop when the user types ^C.  This has the
9947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt    // effect of quitting the program.
10047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt{
10147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt    assert(sigraised == SIGINT);
10247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
10347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt    if (gMDNSPlatformPosixVerboseLevel > 0) {
10447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt        fprintf(stderr, "\nSIGINT\n");
10547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt    }
10647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt    gStopNow = mDNStrue;
10747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt}
10847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
10947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwaltstatic void HandleSigQuit(int sigraised)
11047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt    // If we get a SIGQUIT the user is desperate and we
11147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt    // just call mDNS_Close directly.  This is definitely
11247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt    // not safe (because it could reenter mDNS), but
11347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt    // we presume that the user has already tried the safe
11447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt    // alternatives.
11547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt{
11647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt    assert(sigraised == SIGQUIT);
11747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
11847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt    if (gMDNSPlatformPosixVerboseLevel > 0) {
11947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt        fprintf(stderr, "\nSIGQUIT\n");
12047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt    }
12147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt    mDNS_Close(&mDNSStorage);
12247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt    exit(0);
12347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt}
12447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
12547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#if COMPILER_LIKES_PRAGMA_MARK
12647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#pragma mark ***** Parameter Checking
12747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#endif
12847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
12947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwaltstatic mDNSBool CheckThatRichTextNameIsUsable(const char *richTextName, mDNSBool printExplanation)
13047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt    // Checks that richTextName is reasonable
13147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt    // label and, if it isn't and printExplanation is true, prints
13247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt    // an explanation of why not.
13347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt{
13447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt    mDNSBool result = mDNStrue;
13547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt    if (result && strlen(richTextName) > 63) {
13647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt        if (printExplanation) {
13747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt            fprintf(stderr,
13847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt                    "%s: Service name is too long (must be 63 characters or less)\n",
13947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt                    gProgramName);
14047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt        }
14147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt        result = mDNSfalse;
14247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt    }
14347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt    if (result && richTextName[0] == 0) {
14447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt        if (printExplanation) {
14547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt            fprintf(stderr, "%s: Service name can't be empty\n", gProgramName);
14647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt        }
14747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt        result = mDNSfalse;
14847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt    }
14947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt    return result;
15047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt}
15147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
15247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwaltstatic mDNSBool CheckThatServiceTypeIsUsable(const char *serviceType, mDNSBool printExplanation)
15347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt    // Checks that serviceType is a reasonable service type
15447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt    // label and, if it isn't and printExplanation is true, prints
15547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt    // an explanation of why not.
15647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt{
15747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt    mDNSBool result;
15847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
15947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt    result = mDNStrue;
16047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt    if (result && strlen(serviceType) > 63) {
16147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt        if (printExplanation) {
16247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt            fprintf(stderr,
16347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt                    "%s: Service type is too long (must be 63 characters or less)\n",
16447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt                    gProgramName);
16547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt        }
16647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt        result = mDNSfalse;
16747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt    }
16847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt    if (result && serviceType[0] == 0) {
16947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt        if (printExplanation) {
17047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt            fprintf(stderr,
17147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt                    "%s: Service type can't be empty\n",
17247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt                    gProgramName);
17347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt        }
17447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt        result = mDNSfalse;
17547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt    }
17647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt    return result;
17747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt}
17847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
17947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwaltstatic mDNSBool CheckThatPortNumberIsUsable(long portNumber, mDNSBool printExplanation)
18047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt    // Checks that portNumber is a reasonable port number
18147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt    // and, if it isn't and printExplanation is true, prints
18247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt    // an explanation of why not.
18347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt{
18447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt    mDNSBool result;
18547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
18647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt    result = mDNStrue;
18747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt    if (result && (portNumber <= 0 || portNumber > 65535)) {
18847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt        if (printExplanation) {
18947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt            fprintf(stderr,
19047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt                    "%s: Port number specified by -p must be in range 1..65535\n",
19147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt                    gProgramName);
19247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt        }
19347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt        result = mDNSfalse;
19447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt    }
19547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt    return result;
19647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt}
19747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
19847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#if COMPILER_LIKES_PRAGMA_MARK
19947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#pragma mark ***** Command Line Arguments
20047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#endif
20147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
20247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwaltstatic const char kDefaultPIDFile[]     = "/var/run/mDNSResponder.pid";
20347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwaltstatic const char kDefaultServiceType[] = "_afpovertcp._tcp.";
20447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwaltstatic const char kDefaultServiceDomain[] = "local.";
20547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwaltenum {
20647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt    kDefaultPortNumber = 548
20747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt};
20847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
20947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwaltstatic void PrintUsage()
21047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt{
21147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt    fprintf(stderr,
21247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt            "Usage: %s [-v level ] [-r] [-n name] [-t type] [-d domain] [-p port] [-f file] [-b] [-P pidfile] [-x name=val ...]\n",
21347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt            gProgramName);
21447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt    fprintf(stderr, "          -v verbose mode, level is a number from 0 to 2\n");
21547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt    fprintf(stderr, "             0 = no debugging info (default)\n");
21647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt    fprintf(stderr, "             1 = standard debugging info\n");
21747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt    fprintf(stderr, "             2 = intense debugging info\n");
21847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt    fprintf(stderr, "             can be cycled kill -USR1\n");
21947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt    fprintf(stderr, "          -r also bind to port 53 (port 5353 is always bound)\n");
22047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt    fprintf(stderr, "          -n uses 'name' as the service name (required)\n");
22147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt    fprintf(stderr, "          -t uses 'type' as the service type (default is '%s')\n", kDefaultServiceType);
22247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt    fprintf(stderr, "          -d uses 'domain' as the service domain (default is '%s')\n", kDefaultServiceDomain);
22347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt    fprintf(stderr, "          -p uses 'port' as the port number (default is '%d')\n",  kDefaultPortNumber);
22447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt    fprintf(stderr, "          -f reads a service list from 'file'\n");
22547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt    fprintf(stderr, "          -b forces daemon (background) mode\n");
22647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt    fprintf(stderr, "          -P uses 'pidfile' as the PID file\n");
22747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt    fprintf(stderr, "             (default is '%s')\n",  kDefaultPIDFile);
22847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt    fprintf(stderr, "             only meaningful if -b also specified\n");
22947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt    fprintf(stderr, "          -x stores name=val in TXT record (default is empty).\n");
23047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt    fprintf(stderr, "             MUST be the last command-line argument;\n");
23147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt    fprintf(stderr, "             all subsequent arguments after -x are treated as name=val pairs.\n");
23247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt}
23347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
23447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwaltstatic   mDNSBool  gAvoidPort53      = mDNStrue;
23547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwaltstatic const char *gServiceName      = "";
23647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwaltstatic const char *gServiceType      = kDefaultServiceType;
23747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwaltstatic const char *gServiceDomain    = kDefaultServiceDomain;
23847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwaltstatic mDNSu8      gServiceText[sizeof(RDataBody)];
23947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwaltstatic mDNSu16     gServiceTextLen   = 0;
24047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwaltstatic        int  gPortNumber       = kDefaultPortNumber;
24147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwaltstatic const char *gServiceFile      = "";
24247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwaltstatic   mDNSBool  gDaemon           = mDNSfalse;
24347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwaltstatic const char *gPIDFile          = kDefaultPIDFile;
24447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
24547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwaltstatic void ParseArguments(int argc, char **argv)
24647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt    // Parses our command line arguments into the global variables
24747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt    // listed above.
24847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt{
24947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt    int ch;
25047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
25147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt    // Set gProgramName to the last path component of argv[0]
25247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
25347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt    gProgramName = strrchr(argv[0], '/');
25447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt    if (gProgramName == NULL) {
25547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt        gProgramName = argv[0];
25647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt    } else {
25747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt        gProgramName += 1;
25847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt    }
25947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
26047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt    // Parse command line options using getopt.
26147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
26247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt    do {
26347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt        ch = getopt(argc, argv, "v:rn:t:d:p:f:dP:bx");
26447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt        if (ch != -1) {
26547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt            switch (ch) {
26647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt                case 'v':
26747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt                    gMDNSPlatformPosixVerboseLevel = atoi(optarg);
26847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt                    if (gMDNSPlatformPosixVerboseLevel < 0 || gMDNSPlatformPosixVerboseLevel > 2) {
26947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt                        fprintf(stderr,
27047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt                                "%s: Verbose mode must be in the range 0..2\n",
27147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt                                gProgramName);
27247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt                        exit(1);
27347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt                    }
27447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt                    break;
27547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt                case 'r':
27647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt                    gAvoidPort53 = mDNSfalse;
27747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt                    break;
27847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt                case 'n':
27947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt                    gServiceName = optarg;
28047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt                    if ( ! CheckThatRichTextNameIsUsable(gServiceName, mDNStrue) ) {
28147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt                        exit(1);
28247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt                    }
28347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt                    break;
28447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt                case 't':
28547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt                    gServiceType = optarg;
28647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt                    if ( ! CheckThatServiceTypeIsUsable(gServiceType, mDNStrue) ) {
28747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt                        exit(1);
28847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt                    }
28947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt                    break;
29047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt                case 'd':
29147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt                    gServiceDomain = optarg;
29247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt                    break;
29347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt                case 'p':
29447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt                    gPortNumber = atol(optarg);
29547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt                    if ( ! CheckThatPortNumberIsUsable(gPortNumber, mDNStrue) ) {
29647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt                        exit(1);
29747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt                    }
29847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt                    break;
29947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt                case 'f':
30047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt                    gServiceFile = optarg;
30147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt                    break;
30247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt                case 'b':
30347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt                    gDaemon = mDNStrue;
30447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt                    break;
30547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt                case 'P':
30647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt                    gPIDFile = optarg;
30747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt                    break;
30847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt                case 'x':
30947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt                	while (optind < argc)
31047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt                		{
31147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt                		gServiceText[gServiceTextLen] = strlen(argv[optind]);
31247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt                		mDNSPlatformMemCopy(gServiceText+gServiceTextLen+1, argv[optind], gServiceText[gServiceTextLen]);
31347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt                		gServiceTextLen += 1 + gServiceText[gServiceTextLen];
31447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt                		optind++;
31547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt                		}
31647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt                	ch = -1;
31747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt                	break;
31847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt                case '?':
31947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt                default:
32047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt                    PrintUsage();
32147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt                    exit(1);
32247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt                    break;
32347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt            }
32447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt        }
32547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt    } while (ch != -1);
32647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
32747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt    // Check for any left over command line arguments.
32847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
32947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt    if (optind != argc) {
33047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	    PrintUsage();
33147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt        fprintf(stderr, "%s: Unexpected argument '%s'\n", gProgramName, argv[optind]);
33247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt        exit(1);
33347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt    }
33447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
33547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt    // Check for inconsistency between the arguments.
33647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
33747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt    if ( (gServiceName[0] == 0) && (gServiceFile[0] == 0) ) {
33847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt    	PrintUsage();
33947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt        fprintf(stderr, "%s: You must specify a service name to register (-n) or a service file (-f).\n", gProgramName);
34047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt        exit(1);
34147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt    }
34247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt}
34347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
34447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#if COMPILER_LIKES_PRAGMA_MARK
34547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#pragma mark ***** Registration
34647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#endif
34747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
34847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalttypedef struct PosixService PosixService;
34947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
35047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwaltstruct PosixService {
35147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt    ServiceRecordSet coreServ;
35247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt    PosixService *next;
35347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt    int serviceID;
35447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt};
35547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
35647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwaltstatic PosixService *gServiceList = NULL;
35747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
35847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwaltstatic void RegistrationCallback(mDNS *const m, ServiceRecordSet *const thisRegistration, mStatus status)
35947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt    // mDNS core calls this routine to tell us about the status of
36047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt    // our registration.  The appropriate action to take depends
36147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt    // entirely on the value of status.
36247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt{
36347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt    switch (status) {
36447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
36547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt        case mStatus_NoError:
36647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt            debugf("Callback: %##s Name Registered",   thisRegistration->RR_SRV.resrec.name->c);
36747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt            // Do nothing; our name was successfully registered.  We may
36847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt            // get more call backs in the future.
36947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt            break;
37047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
37147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt        case mStatus_NameConflict:
37247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt            debugf("Callback: %##s Name Conflict",     thisRegistration->RR_SRV.resrec.name->c);
37347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
37447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt            // In the event of a conflict, this sample RegistrationCallback
37547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt            // just calls mDNS_RenameAndReregisterService to automatically
37647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt            // pick a new unique name for the service. For a device such as a
37747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt            // printer, this may be appropriate.  For a device with a user
37847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt            // interface, and a screen, and a keyboard, the appropriate response
37947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt            // may be to prompt the user and ask them to choose a new name for
38047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt            // the service.
38147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt            //
38247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt            // Also, what do we do if mDNS_RenameAndReregisterService returns an
38347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt            // error.  Right now I have no place to send that error to.
38447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
38547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt            status = mDNS_RenameAndReregisterService(m, thisRegistration, mDNSNULL);
38647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt            assert(status == mStatus_NoError);
38747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt            break;
38847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
38947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt        case mStatus_MemFree:
39047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt            debugf("Callback: %##s Memory Free",       thisRegistration->RR_SRV.resrec.name->c);
39147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
39247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt            // When debugging is enabled, make sure that thisRegistration
39347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt            // is not on our gServiceList.
39447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
39547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt            #if !defined(NDEBUG)
39647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt                {
39747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt                    PosixService *cursor;
39847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
39947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt                    cursor = gServiceList;
40047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt                    while (cursor != NULL) {
40147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt                        assert(&cursor->coreServ != thisRegistration);
40247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt                        cursor = cursor->next;
40347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt                    }
40447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt                }
40547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt            #endif
40647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt            free(thisRegistration);
40747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt            break;
40847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
40947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt        default:
41047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt            debugf("Callback: %##s Unknown Status %ld", thisRegistration->RR_SRV.resrec.name->c, status);
41147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt            break;
41247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt    }
41347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt}
41447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
41547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwaltstatic int gServiceID = 0;
41647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
41747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwaltstatic mStatus RegisterOneService(const char *  richTextName,
41847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt                                  const char *  serviceType,
41947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt                                  const char *  serviceDomain,
42047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt                                  const mDNSu8  text[],
42147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt                                  mDNSu16       textLen,
42247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt                                  long          portNumber)
42347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt{
42447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt    mStatus             status;
42547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt    PosixService *      thisServ;
42647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt    domainlabel         name;
42747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt    domainname          type;
42847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt    domainname          domain;
42947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
43047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt    status = mStatus_NoError;
43147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt    thisServ = (PosixService *) malloc(sizeof(*thisServ));
43247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt    if (thisServ == NULL) {
43347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt        status = mStatus_NoMemoryErr;
43447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt    }
43547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt    if (status == mStatus_NoError) {
43647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt        MakeDomainLabelFromLiteralString(&name,  richTextName);
43747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt        MakeDomainNameFromDNSNameString(&type, serviceType);
43847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt        MakeDomainNameFromDNSNameString(&domain, serviceDomain);
43947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt        status = mDNS_RegisterService(&mDNSStorage, &thisServ->coreServ,
44047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt                &name, &type, &domain,				// Name, type, domain
44147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt                NULL, mDNSOpaque16fromIntVal(portNumber),
44247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt                text, textLen,						// TXT data, length
44347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt                NULL, 0,							// Subtypes
44447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt                mDNSInterface_Any,					// Interface ID
44547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt                RegistrationCallback, thisServ, 0);	// Callback, context, flags
44647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt    }
44747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt    if (status == mStatus_NoError) {
44847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt        thisServ->serviceID = gServiceID;
44947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt        gServiceID += 1;
45047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
45147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt        thisServ->next = gServiceList;
45247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt        gServiceList = thisServ;
45347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
45447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt        if (gMDNSPlatformPosixVerboseLevel > 0) {
45547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt            fprintf(stderr,
45647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt                    "%s: Registered service %d, name \"%s\", type \"%s\", domain \"%s\",  port %ld\n",
45747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt                    gProgramName,
45847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt                    thisServ->serviceID,
45947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt                    richTextName,
46047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt                    serviceType,
46147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt                    serviceDomain,
46247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt                    portNumber);
46347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt        }
46447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt    } else {
46547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt        if (thisServ != NULL) {
46647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt            free(thisServ);
46747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt        }
46847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt    }
46947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt    return status;
47047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt}
47147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
47247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwaltstatic mDNSBool ReadALine(char *buf, size_t bufSize, FILE *fp, mDNSBool skipBlankLines)
47347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt{
47447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	size_t	len;
47547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	mDNSBool readNextLine;
47647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
47747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	do {
47847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		readNextLine = mDNSfalse;
47947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
48047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		if (fgets(buf, bufSize, fp) == NULL)
48147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			return mDNSfalse;	// encountered EOF or an error condition
48247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
48347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		// These first characters indicate a blank line.
48447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		if (buf[0] == ' ' || buf[0] == '\t' || buf[0] == '\r' || buf[0] == '\n') {
48547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			if (!skipBlankLines)
48647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				return mDNSfalse;
48747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			readNextLine = mDNStrue;
48847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
48947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		// always skip comment lines
49047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		if (buf[0] == '#')
49147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			readNextLine = mDNStrue;
49247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
49347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	} while (readNextLine);
49447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
49547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	len = strlen( buf);
49647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if ( buf[len - 1] == '\r' || buf[len - 1] == '\n')
49747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		buf[len - 1] = '\0';
49847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
49947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt    return mDNStrue;
50047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt}
50147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
50247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwaltstatic mStatus RegisterServicesInFile(const char *filePath)
50347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt{
50447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt    mStatus     status = mStatus_NoError;
50547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt    FILE *      fp = fopen(filePath, "r");
50647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
50747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt    if (fp == NULL) {
50847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt        return mStatus_UnknownErr;
50947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt    }
51047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
51147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (gMDNSPlatformPosixVerboseLevel > 1)
51247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		fprintf(stderr, "Parsing %s for services\n", filePath);
51347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
51447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	do {
51547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		char nameBuf[256];
51647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		char * name = nameBuf;
51747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		char type[256];
51847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		const char *dom = kDefaultServiceDomain;
51947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		char rawText[1024];
52047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		mDNSu8  text[sizeof(RDataBody)];
52147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		unsigned int textLen = 0;
52247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		char port[256];
52347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		char *p;
52447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
52547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		// Read the service name, type, port, and optional text record fields.
52647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		// Skip blank lines while looking for the next service name.
52747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		if (! ReadALine(name, sizeof(nameBuf), fp, mDNStrue))
52847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			break;
52947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
53047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		// Special case that allows service name to begin with a '#'
53147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		// character by escaping it with a '\' to distiguish it from
53247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		// a comment line.  Remove the leading '\' here before
53347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		// registering the service.
53447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		if (name[0] == '\\' && name[1] == '#')
53547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			name++;
53647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
53747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		if (gMDNSPlatformPosixVerboseLevel > 1)
53847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			fprintf(stderr, "Service name: \"%s\"\n", name);
53947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
54047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		// Don't skip blank lines in calls to ReadAline() after finding the
54147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		// service name since the next blank line indicates the end
54247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		// of this service record.
54347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		if (! ReadALine(type, sizeof(type), fp, mDNSfalse))
54447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			break;
54547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
54647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		// see if a domain name is specified
54747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		p = type;
54847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		while (*p && *p != ' ' && *p != '\t') p++;
54947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		if (*p) {
55047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			*p = 0;	// NULL terminate the <type>.<protocol> string
55147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			// skip any leading whitespace before domain name
55247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			p++;
55347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			while (*p && (*p == ' ' || *p == '\t')) p++;
55447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			if (*p)
55547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				dom = p;
55647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
55747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		if (gMDNSPlatformPosixVerboseLevel > 1) {
55847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			fprintf(stderr, "Service type: \"%s\"\n", type);
55947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			fprintf(stderr, "Service domain: \"%s\"\n", dom);
56047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
56147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
56247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		if (! ReadALine(port, sizeof(port), fp, mDNSfalse))
56347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			break;
56447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		if (gMDNSPlatformPosixVerboseLevel > 1)
56547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			fprintf(stderr, "Service port: %s\n", port);
56647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
56747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		if (   ! CheckThatRichTextNameIsUsable(name, mDNStrue)
56847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			|| ! CheckThatServiceTypeIsUsable(type, mDNStrue)
56947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			|| ! CheckThatPortNumberIsUsable(atol(port), mDNStrue))
57047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			break;
57147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
57247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		// read the TXT record fields
57347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		while (1) {
57447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			int len;
57547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			if (!ReadALine(rawText, sizeof(rawText), fp, mDNSfalse)) break;
57647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			if (gMDNSPlatformPosixVerboseLevel > 1)
57747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				fprintf(stderr, "Text string: \"%s\"\n", rawText);
57847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			len = strlen(rawText);
57947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			if (len <= 255)
58047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				{
58147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				unsigned int newlen = textLen + 1 + len;
58247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				if (len == 0 || newlen >= sizeof(text)) break;
58347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				text[textLen] = len;
58447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				mDNSPlatformMemCopy(text + textLen + 1, rawText, len);
58547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				textLen = newlen;
58647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				}
58747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			else
58847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				fprintf(stderr, "%s: TXT attribute too long for name = %s, type = %s, port = %s\n",
58947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt					gProgramName, name, type, port);
59047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
59147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
59247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		status = RegisterOneService(name, type, dom, text, textLen, atol(port));
59347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		if (status != mStatus_NoError) {
59447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			// print error, but try to read and register other services in the file
59547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			fprintf(stderr, "%s: Failed to register service, name \"%s\", type \"%s\", domain \"%s\", port %s\n",
59647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt					gProgramName, name, type, dom, port);
59747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
59847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
59947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	} while (!feof(fp));
60047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
60147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (!feof(fp)) {
60247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		fprintf(stderr, "%s: Error reading service file %s\n", gProgramName, filePath);
60347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		status = mStatus_UnknownErr;
60447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	}
60547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
606f48f8a2e3417f93bc1f45930dbf9c4ea7523523dDave Platt	{
607f48f8a2e3417f93bc1f45930dbf9c4ea7523523dDave Platt// __ANDROID__ : replaced assert(fclose(..))
608f48f8a2e3417f93bc1f45930dbf9c4ea7523523dDave Platt		int fp_closed = fclose(fp);
609f48f8a2e3417f93bc1f45930dbf9c4ea7523523dDave Platt		assert(0 == fp_closed);
610f48f8a2e3417f93bc1f45930dbf9c4ea7523523dDave Platt	}
61147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
61247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	return status;
61347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt}
61447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
61547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwaltstatic mStatus RegisterOurServices(void)
61647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt{
61747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt    mStatus status;
61847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
61947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt    status = mStatus_NoError;
62047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt    if (gServiceName[0] != 0) {
62147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt        status = RegisterOneService(gServiceName,
62247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt                                    gServiceType,
62347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt                                    gServiceDomain,
62447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt                                    gServiceText, gServiceTextLen,
62547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt                                    gPortNumber);
62647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt    }
62747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt    if (status == mStatus_NoError && gServiceFile[0] != 0) {
62847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt        status = RegisterServicesInFile(gServiceFile);
62947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt    }
63047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt    return status;
63147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt}
63247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
63347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwaltstatic void DeregisterOurServices(void)
63447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt{
63547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt    PosixService *thisServ;
63647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt    int thisServID;
63747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
63847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt    while (gServiceList != NULL) {
63947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt        thisServ = gServiceList;
64047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt        gServiceList = thisServ->next;
64147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
64247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt        thisServID = thisServ->serviceID;
64347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
64447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt        mDNS_DeregisterService(&mDNSStorage, &thisServ->coreServ);
64547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
64647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt        if (gMDNSPlatformPosixVerboseLevel > 0) {
64747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt            fprintf(stderr,
64847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt                    "%s: Deregistered service %d\n",
64947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt                    gProgramName,
65047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt                    thisServ->serviceID);
65147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt        }
65247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt    }
65347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt}
65447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
65547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#if COMPILER_LIKES_PRAGMA_MARK
65647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#pragma mark **** Main
65747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#endif
65847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
65947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwaltint main(int argc, char **argv)
66047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt{
66147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt    mStatus status;
66247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt    int     result;
66347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
66447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt    // Parse our command line arguments.  This won't come back if there's an error.
66547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
66647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt    ParseArguments(argc, argv);
66747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
66847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt    // If we're told to run as a daemon, then do that straight away.
66947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt    // Note that we don't treat the inability to create our PID
67047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt    // file as an error.  Also note that we assign getpid to a long
67147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt    // because printf has no format specified for pid_t.
67247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
67347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt    if (gDaemon) {
67447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt    	int result;
67547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt        if (gMDNSPlatformPosixVerboseLevel > 0) {
67647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt            fprintf(stderr, "%s: Starting in daemon mode\n", gProgramName);
67747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt        }
67847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt        result = daemon(0,0);
67947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt        if (result == 0) {
68047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt            FILE *fp;
68147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt            int  junk;
68247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
68347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt            fp = fopen(gPIDFile, "w");
68447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt            if (fp != NULL) {
68547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt                fprintf(fp, "%ld\n", (long) getpid());
68647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt                junk = fclose(fp);
68747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt                assert(junk == 0);
68847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt            }
68947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt        } else {
69047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt            fprintf(stderr, "%s: Could not run as daemon - exiting\n", gProgramName);
69147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt            exit(result);
69247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt        }
69347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt    } else {
69447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt        if (gMDNSPlatformPosixVerboseLevel > 0) {
69547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt            fprintf(stderr, "%s: Starting in foreground mode, PID %ld\n", gProgramName, (long) getpid());
69647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt        }
69747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt    }
69847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
69947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt    status = mDNS_Init(&mDNSStorage, &PlatformStorage,
70047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt    	mDNS_Init_NoCache, mDNS_Init_ZeroCacheSize,
70147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt    	mDNS_Init_AdvertiseLocalAddresses,
70247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt    	mDNS_Init_NoInitCallback, mDNS_Init_NoInitCallbackContext);
70347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt    if (status != mStatus_NoError) return(2);
70447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
70547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	status = RegisterOurServices();
70647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt    if (status != mStatus_NoError) return(2);
70747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
70847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt    signal(SIGHUP,  HandleSigHup);      // SIGHUP has to be sent by kill -HUP <pid>
70947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt    signal(SIGINT,  HandleSigInt);      // SIGINT is what you get for a Ctrl-C
71047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt    signal(SIGQUIT, HandleSigQuit);     // SIGQUIT is what you get for a Ctrl-\ (indeed)
71147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt    signal(SIGUSR1, HandleSigUsr1);     // SIGUSR1 has to be sent by kill -USR1 <pid>
71247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
71347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	while (!gStopNow)
71447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
71547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		int nfds = 0;
71647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		fd_set readfds;
71747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		struct timeval timeout;
71847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		int result;
71947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
72047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		// 1. Set up the fd_set as usual here.
72147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		// This example client has no file descriptors of its own,
72247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		// but a real application would call FD_SET to add them to the set here
72347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		FD_ZERO(&readfds);
72447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
72547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		// 2. Set up the timeout.
72647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		// This example client has no other work it needs to be doing,
72747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		// so we set an effectively infinite timeout
72847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		timeout.tv_sec = 0x3FFFFFFF;
72947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		timeout.tv_usec = 0;
73047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
73147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		// 3. Give the mDNSPosix layer a chance to add its information to the fd_set and timeout
73247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		mDNSPosixGetFDSet(&mDNSStorage, &nfds, &readfds, &timeout);
73347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
73447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		// 4. Call select as normal
73547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		verbosedebugf("select(%d, %d.%06d)", nfds, timeout.tv_sec, timeout.tv_usec);
73647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		result = select(nfds, &readfds, NULL, NULL, &timeout);
73747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
73847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		if (result < 0)
73947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			{
74047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			verbosedebugf("select() returned %d errno %d", result, errno);
74147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			if (errno != EINTR) gStopNow = mDNStrue;
74247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			else
74347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				{
74447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				if (gReceivedSigUsr1)
74547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt					{
74647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt					gReceivedSigUsr1 = mDNSfalse;
74747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt					gMDNSPlatformPosixVerboseLevel += 1;
74847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt					if (gMDNSPlatformPosixVerboseLevel > 2)
74947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt						gMDNSPlatformPosixVerboseLevel = 0;
75047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt					if ( gMDNSPlatformPosixVerboseLevel > 0 )
75147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt						fprintf(stderr, "\nVerbose level %d\n", gMDNSPlatformPosixVerboseLevel);
75247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt					}
75347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				if (gReceivedSigHup)
75447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt					{
75547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt					if (gMDNSPlatformPosixVerboseLevel > 0)
75647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt						fprintf(stderr, "\nSIGHUP\n");
75747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt					gReceivedSigHup = mDNSfalse;
75847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt					DeregisterOurServices();
75947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt					status = mDNSPlatformPosixRefreshInterfaceList(&mDNSStorage);
76047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt					if (status != mStatus_NoError) break;
76147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt					status = RegisterOurServices();
76247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt					if (status != mStatus_NoError) break;
76347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt					}
76447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				}
76547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			}
76647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		else
76747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			{
76847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			// 5. Call mDNSPosixProcessFDSet to let the mDNSPosix layer do its work
76947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			mDNSPosixProcessFDSet(&mDNSStorage, &readfds);
77047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
77147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			// 6. This example client has no other work it needs to be doing,
77247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			// but a real client would do its work here
77347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			// ... (do work) ...
77447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			}
77547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
77647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
77747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	debugf("Exiting");
77847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
77947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	DeregisterOurServices();
78047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	mDNS_Close(&mDNSStorage);
78147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
78247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt    if (status == mStatus_NoError) {
78347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt        result = 0;
78447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt    } else {
78547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt        result = 2;
78647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt    }
78747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt    if ( (result != 0) || (gMDNSPlatformPosixVerboseLevel > 0) ) {
78847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt        fprintf(stderr, "%s: Finished with status %d, result %d\n", gProgramName, (int)status, result);
78947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt    }
79047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
79147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt    return result;
79247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt}
793