]> git.saurik.com Git - apple/mdnsresponder.git/blob - mDNSPosix/PosixDaemon.c
mDNSResponder-66.3.tar.gz
[apple/mdnsresponder.git] / mDNSPosix / PosixDaemon.c
1 /*
2 * Copyright (c) 2003 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
7 *
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * file.
14 *
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
22 *
23 * @APPLE_LICENSE_HEADER_END@
24
25 File: daemon.c
26
27 Contains: main & associated Application layer for mDNSResponder on Linux.
28
29 Version: 1.0
30 Tabs: 4 spaces
31
32 Change History (most recent first):
33
34 $Log: PosixDaemon.c,v $
35 Revision 1.10 2004/06/08 04:59:40 cheshire
36 Tidy up wording -- log messages are already prefixed with "mDNSResponder", so don't need to repeat it
37
38 Revision 1.9 2004/05/29 00:14:20 rpantos
39 <rdar://problem/3508093> Runtime check to disable prod mdnsd on OS X.
40
41 Revision 1.8 2004/04/07 01:19:04 cheshire
42 Hash slot value should be unsigned
43
44 Revision 1.7 2004/02/14 06:34:57 cheshire
45 Use LogMsg instead of fprintf( stderr
46
47 Revision 1.6 2004/02/14 01:10:42 rpantos
48 Allow daemon to run if 'nobody' is not defined, with a warning. (For Roku HD1000.)
49
50 Revision 1.5 2004/02/05 07:45:43 cheshire
51 Add Log header
52
53 Revision 1.4 2004/01/28 21:14:23 cheshire
54 Reconcile debug_mode and gDebugLogging into a single flag (mDNS_DebugMode)
55
56 Revision 1.3 2004/01/19 19:51:46 cheshire
57 Fix compiler error (mixed declarations and code) on some versions of Linux
58
59 Revision 1.2 2003/12/11 03:03:51 rpantos
60 Clean up mDNSPosix so that it builds on OS X again.
61
62 Revision 1.1 2003/12/08 20:47:02 rpantos
63 Add support for mDNSResponder on Linux.
64
65 */
66
67 #include <stdio.h>
68 #include <string.h>
69 #include <unistd.h>
70 #include <stdlib.h>
71 #include <signal.h>
72 #include <errno.h>
73 #include <pwd.h>
74 #include <sys/types.h>
75
76 #include "mDNSClientAPI.h"
77 #include "mDNSDebug.h"
78 #include "mDNSPosix.h"
79 #include "uds_daemon.h"
80
81
82 static void ParseCmdLinArgs( int argc, char **argv);
83 static void DumpStateLog( mDNS *m);
84 static mStatus MainLoop( mDNS *m);
85
86
87 #define RR_CACHE_SIZE 500
88 static CacheRecord gRRCache[RR_CACHE_SIZE];
89
90 extern const char mDNSResponderVersionString[];
91
92 int main( int argc, char **argv)
93 {
94 mDNS mDNSRecord;
95 mDNS_PlatformSupport platformStorage;
96 mStatus err;
97
98 bzero( &mDNSRecord, sizeof mDNSRecord);
99 bzero( &platformStorage, sizeof platformStorage);
100
101 ParseCmdLinArgs( argc, argv);
102
103 err = mDNS_Init( &mDNSRecord, &platformStorage, gRRCache, RR_CACHE_SIZE, mDNS_Init_AdvertiseLocalAddresses,
104 mDNS_Init_NoInitCallback, mDNS_Init_NoInitCallbackContext);
105
106 if ( mStatus_NoError == err)
107 err = udsserver_init( &mDNSRecord);
108
109 // Now that we're finished with anything privileged, switch over to running as "nobody"
110 if ( mStatus_NoError == err)
111 {
112 const struct passwd *pw = getpwnam("nobody");
113 if ( pw != NULL)
114 setuid( pw->pw_uid);
115 else
116 LogMsg("WARNING: mdnsd continuing as root because user \"nobody\" does not exist");
117 }
118
119 if ( mStatus_NoError == err)
120 err = MainLoop( &mDNSRecord);
121
122 mDNS_Close( &mDNSRecord);
123
124 if (udsserver_exit() < 0)
125 LogMsg("ExitCallback: udsserver_exit failed");
126
127 #if MDNS_DEBUGMSGS > 0
128 printf( "mDNSResponder exiting normally with %ld\n", err);
129 #endif
130
131 return err;
132 }
133
134
135 static void ParseCmdLinArgs( int argc, char **argv)
136 // Do appropriate things at startup with command line arguments. Calls exit() if unhappy.
137 {
138 if ( argc > 1)
139 {
140 if ( 0 == strcmp( argv[1], "-debug"))
141 {
142 mDNS_DebugMode = mDNStrue;
143 }
144 else
145 printf( "Usage: mDNSResponder [-debug]\n");
146 }
147
148 if ( !mDNS_DebugMode)
149 {
150 int result = daemon( 0, 0);
151
152 if ( result != 0)
153 {
154 LogMsg("Could not run as daemon - exiting");
155 exit( result);
156 }
157
158 #if __APPLE__
159 {
160 LogMsg("The POSIX mDNSResponder should only be used on OS X for testing - exiting");
161 exit( -1);
162 }
163 #endif
164 }
165 }
166
167
168 static void DumpStateLog( mDNS *m)
169 // Dump a little log of what we've been up to.
170 {
171 mDNSu32 slot;
172 CacheRecord *rr;
173 mDNSu32 CacheUsed = 0, CacheActive = 0;
174 mDNSs32 now = mDNSPlatformTimeNow();
175
176 LogMsgIdent(mDNSResponderVersionString, "---- BEGIN STATE LOG ----");
177
178 for (slot = 0; slot < CACHE_HASH_SLOTS; slot++)
179 {
180 mDNSu32 SlotUsed = 0;
181 for (rr = m->rrcache_hash[slot]; rr; rr=rr->next)
182 {
183 mDNSs32 remain = rr->resrec.rroriginalttl - (now - rr->TimeRcvd) / mDNSPlatformOneSecond;
184 CacheUsed++;
185 SlotUsed++;
186 if (rr->CRActiveQuestion) CacheActive++;
187 LogMsgNoIdent("%s%6ld %-6s%-6s%s", rr->CRActiveQuestion ? "*" : " ", remain, DNSTypeName(rr->resrec.rrtype),
188 ((PosixNetworkInterface *)rr->resrec.InterfaceID)->intfName, GetRRDisplayString(m, rr));
189 usleep(1000); // Limit rate a little so we don't flood syslog too fast
190 }
191 if (m->rrcache_used[slot] != SlotUsed)
192 LogMsgNoIdent("Cache use mismatch: rrcache_used[slot] is %lu, true count %lu", m->rrcache_used[slot], SlotUsed);
193 }
194 if (m->rrcache_totalused != CacheUsed)
195 LogMsgNoIdent("Cache use mismatch: rrcache_totalused is %lu, true count %lu", m->rrcache_totalused, CacheUsed);
196 if (m->rrcache_active != CacheActive)
197 LogMsgNoIdent("Cache use mismatch: rrcache_active is %lu, true count %lu", m->rrcache_active, CacheActive);
198 LogMsgNoIdent("Cache currently contains %lu records; %lu referenced by active questions", CacheUsed, CacheActive);
199
200 udsserver_info();
201
202 LogMsgIdent(mDNSResponderVersionString, "---- END STATE LOG ----");
203 }
204
205 static mStatus MainLoop( mDNS *m)
206 // Loop until we quit.
207 {
208 sigset_t signals;
209 mDNSBool gotData = mDNSfalse;
210
211 mDNSPosixListenForSignalInEventLoop( SIGINT);
212 mDNSPosixListenForSignalInEventLoop( SIGTERM);
213 mDNSPosixListenForSignalInEventLoop( SIGUSR1);
214 mDNSPosixListenForSignalInEventLoop( SIGPIPE);
215
216 for ( ; ;)
217 {
218 // Work out how long we expect to sleep before the next scheduled task
219 struct timeval timeout;
220 mDNSs32 ticks;
221
222 // Only idle if we didn't find any data the last time around
223 if ( !gotData)
224 {
225 mDNSs32 nextTimerEvent = mDNS_Execute(m);
226
227 nextTimerEvent = udsserver_idle( nextTimerEvent);
228
229 ticks = nextTimerEvent - mDNSPlatformTimeNow();
230 if (ticks < 1) ticks = 1;
231 }
232 else // otherwise call EventLoop again with 0 timemout
233 ticks = 0;
234
235 timeout.tv_sec = ticks / mDNSPlatformOneSecond;
236 timeout.tv_usec = (ticks % mDNSPlatformOneSecond) * 1000000 / mDNSPlatformOneSecond;
237
238 (void) mDNSPosixRunEventLoopOnce( m, &timeout, &signals, &gotData);
239
240 if ( sigismember( &signals, SIGUSR1))
241 DumpStateLog( m);
242 if ( sigismember( &signals, SIGPIPE)) // happens when we try to write to a dead client; death should be detected soon in request_callback() and cleaned up.
243 LogMsg("Received SIGPIPE - ignoring");
244 if ( sigismember( &signals, SIGINT) || sigismember( &signals, SIGTERM))
245 break;
246 }
247
248 return EINTR;
249 }
250
251
252 // uds_daemon support ////////////////////////////////////////////////////////////
253
254 #if MDNS_MALLOC_DEBUGGING >= 2
255 #define LogMalloc LogMsg
256 #else
257 #define LogMalloc(ARGS...) ((void)0)
258 #endif
259
260
261 mStatus udsSupportAddFDToEventLoop( int fd, udsEventCallback callback, void *context)
262 /* Support routine for uds_daemon.c */
263 {
264 // Depends on the fact that udsEventCallback == mDNSPosixEventCallback
265 return mDNSPosixAddFDToEventLoop( fd, callback, context);
266 }
267
268 mStatus udsSupportRemoveFDFromEventLoop( int fd)
269 {
270 return mDNSPosixRemoveFDFromEventLoop( fd);
271 }
272
273 #if MACOSX_MDNS_MALLOC_DEBUGGING >= 1
274
275 void *mallocL(char *msg, unsigned int size)
276 {
277 unsigned long *mem = malloc(size+8);
278 if (!mem)
279 {
280 LogMsg("malloc( %s : %d ) failed", msg, size);
281 return(NULL);
282 }
283 else
284 {
285 LogMalloc("malloc( %s : %lu ) = %p", msg, size, &mem[2]);
286 mem[0] = 0xDEAD1234;
287 mem[1] = size;
288 //bzero(&mem[2], size);
289 memset(&mem[2], 0xFF, size);
290 // validatelists(&mDNSStorage);
291 return(&mem[2]);
292 }
293 }
294
295 void freeL(char *msg, void *x)
296 {
297 if (!x)
298 LogMsg("free( %s @ NULL )!", msg);
299 else
300 {
301 unsigned long *mem = ((unsigned long *)x) - 2;
302 if (mem[0] != 0xDEAD1234)
303 { LogMsg("free( %s @ %p ) !!!! NOT ALLOCATED !!!!", msg, &mem[2]); return; }
304 if (mem[1] > 8000)
305 { LogMsg("free( %s : %ld @ %p) too big!", msg, mem[1], &mem[2]); return; }
306 LogMalloc("free( %s : %ld @ %p)", msg, mem[1], &mem[2]);
307 //bzero(mem, mem[1]+8);
308 memset(mem, 0xDD, mem[1]+8);
309 // validatelists(&mDNSStorage);
310 free(mem);
311 }
312 }
313
314 #endif // MACOSX_MDNS_MALLOC_DEBUGGING >= 1
315
316
317
318 // For convenience when using the "strings" command, this is the last thing in the file
319 #if mDNSResponderVersion > 1
320 mDNSexport const char mDNSResponderVersionString[] = "mDNSResponder-" STRINGIFY(mDNSResponderVersion) " (" __DATE__ " " __TIME__ ") ";
321 #else
322 mDNSexport const char mDNSResponderVersionString[] = "mDNSResponder (Engineering Build) (" __DATE__ " " __TIME__ ") ";
323 #endif