PosixDaemon.c revision 1.11.2.1 1 1.1 tsarna /* -*- Mode: C; tab-width: 4 -*-
2 1.1 tsarna *
3 1.1 tsarna * Copyright (c) 2003-2004 Apple Computer, Inc. All rights reserved.
4 1.1 tsarna *
5 1.1 tsarna * Licensed under the Apache License, Version 2.0 (the "License");
6 1.1 tsarna * you may not use this file except in compliance with the License.
7 1.1 tsarna * You may obtain a copy of the License at
8 1.9 christos *
9 1.1 tsarna * http://www.apache.org/licenses/LICENSE-2.0
10 1.9 christos *
11 1.1 tsarna * Unless required by applicable law or agreed to in writing, software
12 1.1 tsarna * distributed under the License is distributed on an "AS IS" BASIS,
13 1.1 tsarna * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 1.1 tsarna * See the License for the specific language governing permissions and
15 1.1 tsarna * limitations under the License.
16 1.1 tsarna
17 1.9 christos File: daemon.c
18 1.1 tsarna
19 1.9 christos Contains: main & associated Application layer for mDNSResponder on Linux.
20 1.1 tsarna
21 1.6 pettai */
22 1.1 tsarna
23 1.6 pettai #if __APPLE__
24 1.6 pettai // In Mac OS X 10.5 and later trying to use the daemon function gives a daemon is deprecated
25 1.6 pettai // error, which prevents compilation because we build with "-Werror".
26 1.6 pettai // Since this is supposed to be portable cross-platform code, we don't care that daemon is
27 1.6 pettai // deprecated on Mac OS X 10.5, so we use this preprocessor trick to eliminate the error message.
28 1.6 pettai #define daemon yes_we_know_that_daemon_is_deprecated_in_os_x_10_5_thankyou
29 1.6 pettai #endif
30 1.1 tsarna
31 1.1 tsarna #include <stdio.h>
32 1.1 tsarna #include <string.h>
33 1.1 tsarna #include <unistd.h>
34 1.1 tsarna #include <stdlib.h>
35 1.1 tsarna #include <signal.h>
36 1.1 tsarna #include <errno.h>
37 1.1 tsarna #include <fcntl.h>
38 1.1 tsarna #include <pwd.h>
39 1.1 tsarna #include <sys/types.h>
40 1.1 tsarna
41 1.6 pettai #if __APPLE__
42 1.6 pettai #undef daemon
43 1.6 pettai extern int daemon(int, int);
44 1.6 pettai #endif
45 1.6 pettai
46 1.1 tsarna #include "mDNSEmbeddedAPI.h"
47 1.1 tsarna #include "mDNSPosix.h"
48 1.9 christos #include "mDNSUNP.h" // For daemon()
49 1.1 tsarna #include "uds_daemon.h"
50 1.1 tsarna #include "PlatformCommon.h"
51 1.11.2.1 pgoyette #include "DNSCommon.h"
52 1.1 tsarna
53 1.1 tsarna #define CONFIG_FILE "/etc/mdnsd.conf"
54 1.1 tsarna static domainname DynDNSZone; // Default wide-area zone for service registration
55 1.1 tsarna static domainname DynDNSHostname;
56 1.1 tsarna
57 1.1 tsarna #define RR_CACHE_SIZE 500
58 1.1 tsarna static CacheEntity gRRCache[RR_CACHE_SIZE];
59 1.1 tsarna static mDNS_PlatformSupport PlatformStorage;
60 1.1 tsarna
61 1.1 tsarna mDNSlocal void mDNS_StatusCallback(mDNS *const m, mStatus result)
62 1.9 christos {
63 1.9 christos (void)m; // Unused
64 1.9 christos if (result == mStatus_NoError)
65 1.9 christos {
66 1.9 christos // On successful registration of dot-local mDNS host name, daemon may want to check if
67 1.9 christos // any name conflict and automatic renaming took place, and if so, record the newly negotiated
68 1.9 christos // name in persistent storage for next time. It should also inform the user of the name change.
69 1.9 christos // On Mac OS X we store the current dot-local mDNS host name in the SCPreferences store,
70 1.9 christos // and notify the user with a CFUserNotification.
71 1.9 christos }
72 1.9 christos else if (result == mStatus_ConfigChanged)
73 1.9 christos {
74 1.9 christos udsserver_handle_configchange(m);
75 1.9 christos }
76 1.9 christos else if (result == mStatus_GrowCache)
77 1.9 christos {
78 1.9 christos // Allocate another chunk of cache storage
79 1.9 christos CacheEntity *storage = malloc(sizeof(CacheEntity) * RR_CACHE_SIZE);
80 1.9 christos if (storage) mDNS_GrowCache(m, storage, RR_CACHE_SIZE);
81 1.9 christos }
82 1.9 christos }
83 1.1 tsarna
84 1.1 tsarna // %%% Reconfigure() probably belongs in the platform support layer (mDNSPosix.c), not the daemon cde
85 1.1 tsarna // -- all client layers running on top of mDNSPosix.c need to handle network configuration changes,
86 1.1 tsarna // not only the Unix Domain Socket Daemon
87 1.1 tsarna
88 1.1 tsarna static void Reconfigure(mDNS *m)
89 1.9 christos {
90 1.9 christos mDNSAddr DynDNSIP;
91 1.9 christos const mDNSAddr dummy = { mDNSAddrType_IPv4, { { { 1, 1, 1, 1 } } } };;
92 1.9 christos mDNS_SetPrimaryInterfaceInfo(m, NULL, NULL, NULL);
93 1.11.2.1 pgoyette mDNS_Lock(m);
94 1.9 christos if (ParseDNSServers(m, uDNS_SERVERS_FILE) < 0)
95 1.9 christos LogMsg("Unable to parse DNS server list. Unicast DNS-SD unavailable");
96 1.11.2.1 pgoyette mDNS_Unlock(m);
97 1.9 christos ReadDDNSSettingsFromConfFile(m, CONFIG_FILE, &DynDNSHostname, &DynDNSZone, NULL);
98 1.9 christos mDNSPlatformSourceAddrForDest(&DynDNSIP, &dummy);
99 1.9 christos if (DynDNSHostname.c[0]) mDNS_AddDynDNSHostName(m, &DynDNSHostname, NULL, NULL);
100 1.9 christos if (DynDNSIP.type) mDNS_SetPrimaryInterfaceInfo(m, &DynDNSIP, NULL, NULL);
101 1.9 christos mDNS_ConfigChanged(m);
102 1.9 christos }
103 1.1 tsarna
104 1.1 tsarna // Do appropriate things at startup with command line arguments. Calls exit() if unhappy.
105 1.1 tsarna mDNSlocal void ParseCmdLinArgs(int argc, char **argv)
106 1.9 christos {
107 1.9 christos if (argc > 1)
108 1.9 christos {
109 1.9 christos if (0 == strcmp(argv[1], "-debug")) mDNS_DebugMode = mDNStrue;
110 1.9 christos else printf("Usage: %s [-debug]\n", argv[0]);
111 1.9 christos }
112 1.9 christos
113 1.9 christos if (!mDNS_DebugMode)
114 1.9 christos {
115 1.9 christos int result = daemon(0, 0);
116 1.9 christos if (result != 0) { LogMsg("Could not run as daemon - exiting"); exit(result); }
117 1.1 tsarna #if __APPLE__
118 1.9 christos LogMsg("The POSIX mdnsd should only be used on OS X for testing - exiting");
119 1.9 christos exit(-1);
120 1.1 tsarna #endif
121 1.9 christos }
122 1.9 christos }
123 1.1 tsarna
124 1.10 christos mDNSlocal void DumpStateLog()
125 1.1 tsarna // Dump a little log of what we've been up to.
126 1.9 christos {
127 1.10 christos LogMsg("---- BEGIN STATE LOG ----");
128 1.10 christos udsserver_info();
129 1.9 christos LogMsg("---- END STATE LOG ----");
130 1.9 christos }
131 1.9 christos
132 1.9 christos mDNSlocal mStatus MainLoop(mDNS *m) // Loop until we quit.
133 1.9 christos {
134 1.9 christos sigset_t signals;
135 1.9 christos mDNSBool gotData = mDNSfalse;
136 1.9 christos
137 1.9 christos mDNSPosixListenForSignalInEventLoop(SIGINT);
138 1.9 christos mDNSPosixListenForSignalInEventLoop(SIGTERM);
139 1.9 christos mDNSPosixListenForSignalInEventLoop(SIGUSR1);
140 1.9 christos mDNSPosixListenForSignalInEventLoop(SIGPIPE);
141 1.9 christos mDNSPosixListenForSignalInEventLoop(SIGHUP) ;
142 1.9 christos
143 1.9 christos for (; ;)
144 1.9 christos {
145 1.9 christos // Work out how long we expect to sleep before the next scheduled task
146 1.9 christos struct timeval timeout;
147 1.9 christos mDNSs32 ticks;
148 1.9 christos
149 1.9 christos // Only idle if we didn't find any data the last time around
150 1.9 christos if (!gotData)
151 1.9 christos {
152 1.9 christos mDNSs32 nextTimerEvent = mDNS_Execute(m);
153 1.9 christos nextTimerEvent = udsserver_idle(nextTimerEvent);
154 1.9 christos ticks = nextTimerEvent - mDNS_TimeNow(m);
155 1.9 christos if (ticks < 1) ticks = 1;
156 1.4 tsarna }
157 1.9 christos else // otherwise call EventLoop again with 0 timemout
158 1.9 christos ticks = 0;
159 1.2 tsarna
160 1.9 christos timeout.tv_sec = ticks / mDNSPlatformOneSecond;
161 1.9 christos timeout.tv_usec = (ticks % mDNSPlatformOneSecond) * 1000000 / mDNSPlatformOneSecond;
162 1.1 tsarna
163 1.9 christos (void) mDNSPosixRunEventLoopOnce(m, &timeout, &signals, &gotData);
164 1.1 tsarna
165 1.9 christos if (sigismember(&signals, SIGHUP )) Reconfigure(m);
166 1.10 christos if (sigismember(&signals, SIGUSR1)) DumpStateLog();
167 1.9 christos // SIGPIPE happens when we try to write to a dead client; death should be detected soon in request_callback() and cleaned up.
168 1.9 christos if (sigismember(&signals, SIGPIPE)) LogMsg("Received SIGPIPE - ignoring");
169 1.9 christos if (sigismember(&signals, SIGINT) || sigismember(&signals, SIGTERM)) break;
170 1.9 christos }
171 1.9 christos return EINTR;
172 1.9 christos }
173 1.1 tsarna
174 1.1 tsarna int main(int argc, char **argv)
175 1.9 christos {
176 1.9 christos mStatus err;
177 1.9 christos
178 1.9 christos ParseCmdLinArgs(argc, argv);
179 1.9 christos
180 1.9 christos LogMsg("%s starting", mDNSResponderVersionString);
181 1.1 tsarna
182 1.9 christos err = mDNS_Init(&mDNSStorage, &PlatformStorage, gRRCache, RR_CACHE_SIZE, mDNS_Init_AdvertiseLocalAddresses,
183 1.9 christos mDNS_StatusCallback, mDNS_Init_NoInitCallbackContext);
184 1.1 tsarna
185 1.9 christos if (mStatus_NoError == err)
186 1.9 christos err = udsserver_init(mDNSNULL, 0);
187 1.1 tsarna
188 1.9 christos Reconfigure(&mDNSStorage);
189 1.9 christos
190 1.9 christos // Now that we're finished with anything privileged, switch over to running as "nobody"
191 1.9 christos if (mStatus_NoError == err)
192 1.9 christos {
193 1.9 christos const struct passwd *pw = getpwnam("nobody");
194 1.9 christos if (pw != NULL)
195 1.9 christos setuid(pw->pw_uid);
196 1.9 christos else
197 1.9 christos LogMsg("WARNING: mdnsd continuing as root because user \"nobody\" does not exist");
198 1.9 christos }
199 1.9 christos
200 1.9 christos if (mStatus_NoError == err)
201 1.9 christos err = MainLoop(&mDNSStorage);
202 1.9 christos
203 1.9 christos LogMsg("%s stopping", mDNSResponderVersionString);
204 1.9 christos
205 1.9 christos mDNS_Close(&mDNSStorage);
206 1.9 christos
207 1.9 christos if (udsserver_exit() < 0)
208 1.9 christos LogMsg("ExitCallback: udsserver_exit failed");
209 1.1 tsarna
210 1.1 tsarna #if MDNS_DEBUGMSGS > 0
211 1.9 christos printf("mDNSResponder exiting normally with %ld\n", err);
212 1.1 tsarna #endif
213 1.9 christos
214 1.9 christos return err;
215 1.9 christos }
216 1.1 tsarna
217 1.1 tsarna // uds_daemon support ////////////////////////////////////////////////////////////
218 1.1 tsarna
219 1.6 pettai mStatus udsSupportAddFDToEventLoop(int fd, udsEventCallback callback, void *context, void **platform_data)
220 1.1 tsarna /* Support routine for uds_daemon.c */
221 1.9 christos {
222 1.9 christos // Depends on the fact that udsEventCallback == mDNSPosixEventCallback
223 1.9 christos (void) platform_data;
224 1.9 christos return mDNSPosixAddFDToEventLoop(fd, callback, context);
225 1.9 christos }
226 1.1 tsarna
227 1.6 pettai int udsSupportReadFD(dnssd_sock_t fd, char *buf, int len, int flags, void *platform_data)
228 1.9 christos {
229 1.9 christos (void) platform_data;
230 1.9 christos return recv(fd, buf, len, flags);
231 1.9 christos }
232 1.9 christos
233 1.9 christos mStatus udsSupportRemoveFDFromEventLoop(int fd, void *platform_data) // Note: This also CLOSES the file descriptor
234 1.9 christos {
235 1.9 christos mStatus err = mDNSPosixRemoveFDFromEventLoop(fd);
236 1.9 christos (void) platform_data;
237 1.9 christos close(fd);
238 1.9 christos return err;
239 1.9 christos }
240 1.1 tsarna
241 1.10 christos mDNSexport void RecordUpdatedNiceLabel(mDNSs32 delay)
242 1.9 christos {
243 1.9 christos (void)delay;
244 1.9 christos // No-op, for now
245 1.9 christos }
246 1.1 tsarna
247 1.1 tsarna #if _BUILDING_XCODE_PROJECT_
248 1.1 tsarna // If the process crashes, then this string will be magically included in the automatically-generated crash log
249 1.1 tsarna const char *__crashreporter_info__ = mDNSResponderVersionString_SCCS + 5;
250 1.9 christos asm (".desc ___crashreporter_info__, 0x10");
251 1.1 tsarna #endif
252 1.1 tsarna
253 1.1 tsarna // For convenience when using the "strings" command, this is the last thing in the file
254 1.1 tsarna #if mDNSResponderVersion > 1
255 1.11 christos mDNSexport const char mDNSResponderVersionString_SCCS[] = "@(#) mDNSResponder-" STRINGIFY(mDNSResponderVersion)
256 1.11 christos #ifndef MDNS_VERSIONSTR_NODTS
257 1.11 christos " (" __DATE__ " " __TIME__ ")"
258 1.11 christos #endif
259 1.11 christos ;
260 1.1 tsarna #else
261 1.11 christos mDNSexport const char mDNSResponderVersionString_SCCS[] = "@(#) mDNSResponder (Engineering Build)"
262 1.11 christos #ifndef MDNS_VERSIONSTR_NODTS
263 1.11 christos " (" __DATE__ " " __TIME__ ")"
264 1.11 christos #endif
265 1.11 christos ;
266 1.1 tsarna #endif
267