]> git.saurik.com Git - apple/mdnsresponder.git/blob - mDNSPosix/PosixDaemon.c
mDNSResponder-107.6.tar.gz
[apple/mdnsresponder.git] / mDNSPosix / PosixDaemon.c
1 /* -*- Mode: C; tab-width: 4 -*-
2 *
3 * Copyright (c) 2003-2004 Apple Computer, Inc. All rights reserved.
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16
17 File: daemon.c
18
19 Contains: main & associated Application layer for mDNSResponder on Linux.
20
21 Change History (most recent first):
22
23 $Log: PosixDaemon.c,v $
24 Revision 1.29.2.1 2006/08/29 06:24:34 cheshire
25 Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
26
27 Revision 1.29 2005/08/04 03:37:45 mkrochma
28 Temporary workaround to fix posix after mDNS_SetPrimaryInterfaceInfo changed
29
30 Revision 1.28 2005/07/19 11:21:09 cheshire
31 <rdar://problem/4170449> Unix Domain Socket leak in mdnsd
32
33 Revision 1.27 2005/02/04 00:39:59 cheshire
34 Move ParseDNSServers() from PosixDaemon.c to mDNSPosix.c so all Posix client layers can use it
35
36 Revision 1.26 2005/02/02 02:21:30 cheshire
37 Update references to "mDNSResponder" to say "mdnsd" instead
38
39 Revision 1.25 2005/01/27 20:01:50 cheshire
40 udsSupportRemoveFDFromEventLoop() needs to close the file descriptor as well
41
42 Revision 1.24 2005/01/19 19:20:49 ksekar
43 <rdar://problem/3960191> Need a way to turn off domain discovery
44
45 Revision 1.23 2004/12/16 20:17:11 cheshire
46 <rdar://problem/3324626> Cache memory management improvements
47
48 Revision 1.22 2004/12/10 13:12:08 cheshire
49 Create no-op function RecordUpdatedNiceLabel(), required by uds_daemon.c
50
51 Revision 1.21 2004/12/01 20:57:20 ksekar
52 <rdar://problem/3873921> Wide Area Service Discovery must be split-DNS aware
53
54 Revision 1.20 2004/12/01 04:28:43 cheshire
55 <rdar://problem/3872803> Darwin patches for Solaris and Suse
56 Use version of daemon() provided in mDNSUNP.c instead of local copy
57
58 Revision 1.19 2004/12/01 03:30:29 cheshire
59 <rdar://problem/3889346> Add Unicast DNS support to mDNSPosix
60
61 Revision 1.18 2004/11/30 22:45:59 cheshire
62 Minor code tidying
63
64 Revision 1.17 2004/11/30 22:18:59 cheshire
65 <rdar://problem/3889351> Posix needs to read the list of unicast DNS servers and set server list
66
67 Revision 1.16 2004/09/21 21:05:12 cheshire
68 Move duplicate code out of mDNSMacOSX/daemon.c and mDNSPosix/PosixDaemon.c,
69 into mDNSShared/uds_daemon.c
70
71 Revision 1.15 2004/09/17 01:08:53 cheshire
72 Renamed mDNSClientAPI.h to mDNSEmbeddedAPI.h
73 The name "mDNSClientAPI.h" is misleading to new developers looking at this code. The interfaces
74 declared in that file are ONLY appropriate to single-address-space embedded applications.
75 For clients on general-purpose computers, the interfaces defined in dns_sd.h should be used.
76
77 Revision 1.14 2004/09/16 00:24:49 cheshire
78 <rdar://problem/3803162> Fix unsafe use of mDNSPlatformTimeNow()
79
80 Revision 1.13 2004/08/11 01:59:41 cheshire
81 Remove "mDNS *globalInstance" parameter from udsserver_init()
82
83 Revision 1.12 2004/06/28 23:19:19 cheshire
84 Fix "Daemon_Init declared but never defined" warning on Linux
85
86 Revision 1.11 2004/06/25 00:26:27 rpantos
87 Changes to fix the Posix build on Solaris.
88
89 Revision 1.10 2004/06/08 04:59:40 cheshire
90 Tidy up wording -- log messages are already prefixed with "mDNSResponder", so don't need to repeat it
91
92 Revision 1.9 2004/05/29 00:14:20 rpantos
93 <rdar://problem/3508093> Runtime check to disable prod mdnsd on OS X.
94
95 Revision 1.8 2004/04/07 01:19:04 cheshire
96 Hash slot value should be unsigned
97
98 Revision 1.7 2004/02/14 06:34:57 cheshire
99 Use LogMsg instead of fprintf( stderr
100
101 Revision 1.6 2004/02/14 01:10:42 rpantos
102 Allow daemon to run if 'nobody' is not defined, with a warning. (For Roku HD1000.)
103
104 Revision 1.5 2004/02/05 07:45:43 cheshire
105 Add Log header
106
107 Revision 1.4 2004/01/28 21:14:23 cheshire
108 Reconcile debug_mode and gDebugLogging into a single flag (mDNS_DebugMode)
109
110 Revision 1.3 2004/01/19 19:51:46 cheshire
111 Fix compiler error (mixed declarations and code) on some versions of Linux
112
113 Revision 1.2 2003/12/11 03:03:51 rpantos
114 Clean up mDNSPosix so that it builds on OS X again.
115
116 Revision 1.1 2003/12/08 20:47:02 rpantos
117 Add support for mDNSResponder on Linux.
118 */
119
120 #include <stdio.h>
121 #include <string.h>
122 #include <unistd.h>
123 #include <stdlib.h>
124 #include <signal.h>
125 #include <errno.h>
126 #include <fcntl.h>
127 #include <pwd.h>
128 #include <sys/types.h>
129
130 #include "mDNSEmbeddedAPI.h"
131 #include "mDNSDebug.h"
132 #include "mDNSPosix.h"
133 #include "uds_daemon.h"
134 #include "PlatformCommon.h"
135
136 #define CONFIG_FILE "/etc/mdnsd.conf"
137 static domainname DynDNSZone; // Default wide-area zone for service registration
138 static domainname DynDNSHostname;
139
140 #define RR_CACHE_SIZE 500
141 static CacheEntity gRRCache[RR_CACHE_SIZE];
142
143 extern const char mDNSResponderVersionString[];
144
145 static void Reconfigure(mDNS *m)
146 {
147 mDNSAddr DynDNSIP;
148 mDNS_SetPrimaryInterfaceInfo(m, NULL, NULL, NULL);
149 mDNS_DeleteDNSServers(m);
150 if (ParseDNSServers(m, uDNS_SERVERS_FILE) < 0)
151 LogMsg("Unable to parse DNS server list. Unicast DNS-SD unavailable");
152 ReadDDNSSettingsFromConfFile(m, CONFIG_FILE, &DynDNSHostname, &DynDNSZone, NULL);
153 FindDefaultRouteIP(&DynDNSIP);
154 if (DynDNSHostname.c[0]) mDNS_AddDynDNSHostName(m, &DynDNSHostname, NULL, NULL);
155 if (DynDNSIP.type) mDNS_SetPrimaryInterfaceInfo(m, &DynDNSIP, NULL, NULL);
156 }
157
158 // Do appropriate things at startup with command line arguments. Calls exit() if unhappy.
159 static void ParseCmdLinArgs(int argc, char **argv)
160 {
161 if (argc > 1)
162 {
163 if (0 == strcmp(argv[1], "-debug")) mDNS_DebugMode = mDNStrue;
164 else printf("Usage: %s [-debug]\n", argv[0]);
165 }
166
167 if (!mDNS_DebugMode)
168 {
169 int result = daemon(0, 0);
170 if (result != 0) { LogMsg("Could not run as daemon - exiting"); exit(result); }
171 #if __APPLE__
172 LogMsg("The POSIX mdnsd should only be used on OS X for testing - exiting");
173 exit(-1);
174 #endif
175 }
176 }
177
178 static void DumpStateLog(mDNS *const m)
179 // Dump a little log of what we've been up to.
180 {
181 LogMsgIdent(mDNSResponderVersionString, "---- BEGIN STATE LOG ----");
182 udsserver_info(m);
183 LogMsgIdent(mDNSResponderVersionString, "---- END STATE LOG ----");
184 }
185
186 static mStatus MainLoop(mDNS *m) // Loop until we quit.
187 {
188 sigset_t signals;
189 mDNSBool gotData = mDNSfalse;
190
191 mDNSPosixListenForSignalInEventLoop(SIGINT);
192 mDNSPosixListenForSignalInEventLoop(SIGTERM);
193 mDNSPosixListenForSignalInEventLoop(SIGUSR1);
194 mDNSPosixListenForSignalInEventLoop(SIGPIPE);
195 mDNSPosixListenForSignalInEventLoop(SIGHUP) ;
196
197 for (; ;)
198 {
199 // Work out how long we expect to sleep before the next scheduled task
200 struct timeval timeout;
201 mDNSs32 ticks;
202
203 // Only idle if we didn't find any data the last time around
204 if (!gotData)
205 {
206 mDNSs32 nextTimerEvent = mDNS_Execute(m);
207 nextTimerEvent = udsserver_idle(nextTimerEvent);
208 ticks = nextTimerEvent - mDNS_TimeNow(m);
209 if (ticks < 1) ticks = 1;
210 }
211 else // otherwise call EventLoop again with 0 timemout
212 ticks = 0;
213
214 timeout.tv_sec = ticks / mDNSPlatformOneSecond;
215 timeout.tv_usec = (ticks % mDNSPlatformOneSecond) * 1000000 / mDNSPlatformOneSecond;
216
217 (void) mDNSPosixRunEventLoopOnce(m, &timeout, &signals, &gotData);
218
219 if (sigismember(&signals, SIGHUP )) Reconfigure(m);
220 if (sigismember(&signals, SIGUSR1)) DumpStateLog(m);
221 // SIGPIPE happens when we try to write to a dead client; death should be detected soon in request_callback() and cleaned up.
222 if (sigismember(&signals, SIGPIPE)) LogMsg("Received SIGPIPE - ignoring");
223 if (sigismember(&signals, SIGINT) || sigismember(&signals, SIGTERM)) break;
224 }
225 return EINTR;
226 }
227
228 int main(int argc, char **argv)
229 {
230 #define mDNSRecord mDNSStorage
231 mDNS_PlatformSupport platformStorage;
232 mStatus err;
233
234 bzero(&mDNSRecord, sizeof mDNSRecord);
235 bzero(&platformStorage, sizeof platformStorage);
236
237 ParseCmdLinArgs(argc, argv);
238
239 LogMsgIdent(mDNSResponderVersionString, "starting");
240
241 err = mDNS_Init(&mDNSRecord, &platformStorage, gRRCache, RR_CACHE_SIZE, mDNS_Init_AdvertiseLocalAddresses,
242 mDNS_Init_NoInitCallback, mDNS_Init_NoInitCallbackContext);
243
244 if (mStatus_NoError == err)
245 err = udsserver_init();
246
247 Reconfigure(&mDNSRecord);
248
249 // Now that we're finished with anything privileged, switch over to running as "nobody"
250 if (mStatus_NoError == err)
251 {
252 const struct passwd *pw = getpwnam("nobody");
253 if (pw != NULL)
254 setuid(pw->pw_uid);
255 else
256 LogMsg("WARNING: mdnsd continuing as root because user \"nobody\" does not exist");
257 }
258
259 if (mStatus_NoError == err)
260 err = MainLoop(&mDNSRecord);
261
262 LogMsgIdent(mDNSResponderVersionString, "stopping");
263
264 mDNS_Close(&mDNSRecord);
265
266 if (udsserver_exit() < 0)
267 LogMsg("ExitCallback: udsserver_exit failed");
268
269 #if MDNS_DEBUGMSGS > 0
270 printf("mDNSResponder exiting normally with %ld\n", err);
271 #endif
272
273 return err;
274 }
275
276 // uds_daemon support ////////////////////////////////////////////////////////////
277
278 #if MDNS_MALLOC_DEBUGGING >= 2
279 #define LogMalloc LogMsg
280 #else
281 #define LogMalloc(ARGS...) ((void)0)
282 #endif
283
284 mStatus udsSupportAddFDToEventLoop(int fd, udsEventCallback callback, void *context)
285 /* Support routine for uds_daemon.c */
286 {
287 // Depends on the fact that udsEventCallback == mDNSPosixEventCallback
288 return mDNSPosixAddFDToEventLoop(fd, callback, context);
289 }
290
291 mStatus udsSupportRemoveFDFromEventLoop(int fd) // Note: This also CLOSES the file descriptor
292 {
293 mStatus err = mDNSPosixRemoveFDFromEventLoop(fd);
294 close(fd);
295 return err;
296 }
297
298 mDNSexport void RecordUpdatedNiceLabel(mDNS *const m, mDNSs32 delay)
299 {
300 (void)m;
301 (void)delay;
302 // No-op, for now
303 }
304
305 #if MACOSX_MDNS_MALLOC_DEBUGGING >= 1
306
307 void *mallocL(char *msg, unsigned int size)
308 {
309 unsigned long *mem = malloc(size+8);
310 if (!mem)
311 {
312 LogMsg("malloc( %s : %d ) failed", msg, size);
313 return(NULL);
314 }
315 else
316 {
317 LogMalloc("malloc( %s : %lu ) = %p", msg, size, &mem[2]);
318 mem[0] = 0xDEAD1234;
319 mem[1] = size;
320 //bzero(&mem[2], size);
321 memset(&mem[2], 0xFF, size);
322 // validatelists(&mDNSStorage);
323 return(&mem[2]);
324 }
325 }
326
327 void freeL(char *msg, void *x)
328 {
329 if (!x)
330 LogMsg("free( %s @ NULL )!", msg);
331 else
332 {
333 unsigned long *mem = ((unsigned long *)x) - 2;
334 if (mem[0] != 0xDEAD1234)
335 { LogMsg("free( %s @ %p ) !!!! NOT ALLOCATED !!!!", msg, &mem[2]); return; }
336 if (mem[1] > 8000)
337 { LogMsg("free( %s : %ld @ %p) too big!", msg, mem[1], &mem[2]); return; }
338 LogMalloc("free( %s : %ld @ %p)", msg, mem[1], &mem[2]);
339 //bzero(mem, mem[1]+8);
340 memset(mem, 0xDD, mem[1]+8);
341 // validatelists(&mDNSStorage);
342 free(mem);
343 }
344 }
345
346 #endif // MACOSX_MDNS_MALLOC_DEBUGGING >= 1
347
348 // For convenience when using the "strings" command, this is the last thing in the file
349 #if mDNSResponderVersion > 1
350 mDNSexport const char mDNSResponderVersionString[] = "mDNSResponder-" STRINGIFY(mDNSResponderVersion) " (" __DATE__ " " __TIME__ ") ";
351 #else
352 mDNSexport const char mDNSResponderVersionString[] = "mDNSResponder (Engineering Build) (" __DATE__ " " __TIME__ ") ";
353 #endif