summaryrefslogtreecommitdiffstats
path: root/mDNSResponder/mDNSPosix/PosixDaemon.c
blob: 88b3292cbeeae5b72ff64d2c24dfae2ecdd328bd (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
/* -*- Mode: C; tab-width: 4 -*-
 *
 * Copyright (c) 2003-2004 Apple Computer, Inc. All rights reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.

    File:		daemon.c

    Contains:	main & associated Application layer for mDNSResponder on Linux.

 */

#if __APPLE__
// In Mac OS X 10.5 and later trying to use the daemon function gives a “‘daemon’ is deprecated”
// error, which prevents compilation because we build with "-Werror".
// Since this is supposed to be portable cross-platform code, we don't care that daemon is
// deprecated on Mac OS X 10.5, so we use this preprocessor trick to eliminate the error message.
#define daemon yes_we_know_that_daemon_is_deprecated_in_os_x_10_5_thankyou
#endif

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <signal.h>
#include <errno.h>
#include <fcntl.h>
#include <pwd.h>
#include <sys/types.h>

#if __APPLE__
#undef daemon
extern int daemon(int, int);
#endif

#include "mDNSEmbeddedAPI.h"
#include "mDNSPosix.h"
#include "mDNSUNP.h"        // For daemon()
#include "uds_daemon.h"
#include "PlatformCommon.h"

#define CONFIG_FILE "/etc/mdnsd.conf"
static domainname DynDNSZone;                // Default wide-area zone for service registration
static domainname DynDNSHostname;

#define RR_CACHE_SIZE 500
static CacheEntity gRRCache[RR_CACHE_SIZE];
static mDNS_PlatformSupport PlatformStorage;

mDNSlocal void mDNS_StatusCallback(mDNS *const m, mStatus result)
{
    (void)m; // Unused
    if (result == mStatus_NoError)
    {
        // On successful registration of dot-local mDNS host name, daemon may want to check if
        // any name conflict and automatic renaming took place, and if so, record the newly negotiated
        // name in persistent storage for next time. It should also inform the user of the name change.
        // On Mac OS X we store the current dot-local mDNS host name in the SCPreferences store,
        // and notify the user with a CFUserNotification.
    }
    else if (result == mStatus_ConfigChanged)
    {
        udsserver_handle_configchange(m);
    }
    else if (result == mStatus_GrowCache)
    {
        // Allocate another chunk of cache storage
        CacheEntity *storage = malloc(sizeof(CacheEntity) * RR_CACHE_SIZE);
        if (storage) mDNS_GrowCache(m, storage, RR_CACHE_SIZE);
    }
}

// %%% Reconfigure() probably belongs in the platform support layer (mDNSPosix.c), not the daemon cde
// -- all client layers running on top of mDNSPosix.c need to handle network configuration changes,
// not only the Unix Domain Socket Daemon

static void Reconfigure(mDNS *m)
{
    mDNSAddr DynDNSIP;
    const mDNSAddr dummy = { mDNSAddrType_IPv4, { { { 1, 1, 1, 1 } } } };;
    mDNS_SetPrimaryInterfaceInfo(m, NULL, NULL, NULL);
    if (ParseDNSServers(m, uDNS_SERVERS_FILE) < 0)
        LogMsg("Unable to parse DNS server list. Unicast DNS-SD unavailable");
    ReadDDNSSettingsFromConfFile(m, CONFIG_FILE, &DynDNSHostname, &DynDNSZone, NULL);
    mDNSPlatformSourceAddrForDest(&DynDNSIP, &dummy);
    if (DynDNSHostname.c[0]) mDNS_AddDynDNSHostName(m, &DynDNSHostname, NULL, NULL);
    if (DynDNSIP.type) mDNS_SetPrimaryInterfaceInfo(m, &DynDNSIP, NULL, NULL);
    mDNS_ConfigChanged(m);
}

// Do appropriate things at startup with command line arguments. Calls exit() if unhappy.
mDNSlocal void ParseCmdLinArgs(int argc, char **argv)
{
    if (argc > 1)
    {
        if (0 == strcmp(argv[1], "-debug")) mDNS_DebugMode = mDNStrue;
        else printf("Usage: %s [-debug]\n", argv[0]);
    }

    if (!mDNS_DebugMode)
    {
        int result = daemon(0, 0);
        if (result != 0) { LogMsg("Could not run as daemon - exiting"); exit(result); }
#if __APPLE__
        LogMsg("The POSIX mdnsd should only be used on OS X for testing - exiting");
        exit(-1);
#endif
    }
}

mDNSlocal void DumpStateLog(mDNS *const m)
// Dump a little log of what we've been up to.
{
    LogMsg("---- BEGIN STATE LOG ----");
    udsserver_info(m);
    LogMsg("----  END STATE LOG  ----");
}

mDNSlocal mStatus MainLoop(mDNS *m) // Loop until we quit.
{
    sigset_t signals;
    mDNSBool gotData = mDNSfalse;

    mDNSPosixListenForSignalInEventLoop(SIGINT);
    mDNSPosixListenForSignalInEventLoop(SIGTERM);
    mDNSPosixListenForSignalInEventLoop(SIGUSR1);
    mDNSPosixListenForSignalInEventLoop(SIGPIPE);
    mDNSPosixListenForSignalInEventLoop(SIGHUP) ;

    for (; ;)
    {
        // Work out how long we expect to sleep before the next scheduled task
        struct timeval timeout;
        mDNSs32 ticks;

        // Only idle if we didn't find any data the last time around
        if (!gotData)
        {
            mDNSs32 nextTimerEvent = mDNS_Execute(m);
            nextTimerEvent = udsserver_idle(nextTimerEvent);
            ticks = nextTimerEvent - mDNS_TimeNow(m);
            if (ticks < 1) ticks = 1;
        }
        else    // otherwise call EventLoop again with 0 timemout
            ticks = 0;

        timeout.tv_sec = ticks / mDNSPlatformOneSecond;
        timeout.tv_usec = (ticks % mDNSPlatformOneSecond) * 1000000 / mDNSPlatformOneSecond;

        (void) mDNSPosixRunEventLoopOnce(m, &timeout, &signals, &gotData);

        if (sigismember(&signals, SIGHUP )) Reconfigure(m);
        if (sigismember(&signals, SIGUSR1)) DumpStateLog(m);
        // SIGPIPE happens when we try to write to a dead client; death should be detected soon in request_callback() and cleaned up.
        if (sigismember(&signals, SIGPIPE)) LogMsg("Received SIGPIPE - ignoring");
        if (sigismember(&signals, SIGINT) || sigismember(&signals, SIGTERM)) break;
    }
    return EINTR;
}

int main(int argc, char **argv)
{
    mStatus err;

    ParseCmdLinArgs(argc, argv);

    LogMsg("%s starting", mDNSResponderVersionString);

    err = mDNS_Init(&mDNSStorage, &PlatformStorage, gRRCache, RR_CACHE_SIZE, mDNS_Init_AdvertiseLocalAddresses,
                    mDNS_StatusCallback, mDNS_Init_NoInitCallbackContext);

    if (mStatus_NoError == err)
        err = udsserver_init(mDNSNULL, 0);

    Reconfigure(&mDNSStorage);

    // Now that we're finished with anything privileged, switch over to running as "nobody"
    if (mStatus_NoError == err)
    {
        const struct passwd *pw = getpwnam("nobody");
        if (pw != NULL)
            setuid(pw->pw_uid);
        else
            LogMsg("WARNING: mdnsd continuing as root because user \"nobody\" does not exist");
    }

    if (mStatus_NoError == err)
        err = MainLoop(&mDNSStorage);

    LogMsg("%s stopping", mDNSResponderVersionString);

    mDNS_Close(&mDNSStorage);

    if (udsserver_exit() < 0)
        LogMsg("ExitCallback: udsserver_exit failed");

 #if MDNS_DEBUGMSGS > 0
    printf("mDNSResponder exiting normally with %ld\n", err);
 #endif

    return err;
}

//		uds_daemon support		////////////////////////////////////////////////////////////

mStatus udsSupportAddFDToEventLoop(int fd, udsEventCallback callback, void *context, void **platform_data)
/* Support routine for uds_daemon.c */
{
    // Depends on the fact that udsEventCallback == mDNSPosixEventCallback
    (void) platform_data;
    return mDNSPosixAddFDToEventLoop(fd, callback, context);
}

int udsSupportReadFD(dnssd_sock_t fd, char *buf, int len, int flags, void *platform_data)
{
    (void) platform_data;
    return recv(fd, buf, len, flags);
}

mStatus udsSupportRemoveFDFromEventLoop(int fd, void *platform_data)        // Note: This also CLOSES the file descriptor
{
    mStatus err = mDNSPosixRemoveFDFromEventLoop(fd);
    (void) platform_data;
    close(fd);
    return err;
}

mDNSexport void RecordUpdatedNiceLabel(mDNS *const m, mDNSs32 delay)
{
    (void)m;
    (void)delay;
    // No-op, for now
}

#if _BUILDING_XCODE_PROJECT_
// If the process crashes, then this string will be magically included in the automatically-generated crash log
const char *__crashreporter_info__ = mDNSResponderVersionString_SCCS + 5;
asm (".desc ___crashreporter_info__, 0x10");
#endif

// For convenience when using the "strings" command, this is the last thing in the file
#if mDNSResponderVersion > 1
mDNSexport const char mDNSResponderVersionString_SCCS[] = "@(#) mDNSResponder-" STRINGIFY(mDNSResponderVersion) " (" __DATE__ " " __TIME__ ")";
#elif MDNS_VERSIONSTR_NODTS
mDNSexport const char mDNSResponderVersionString_SCCS[] = "@(#) mDNSResponder (Engineering Build)";
#else
mDNSexport const char mDNSResponderVersionString_SCCS[] = "@(#) mDNSResponder (Engineering Build) (" __DATE__ " " __TIME__ ")";
#endif