]> git.saurik.com Git - apple/mdnsresponder.git/blobdiff - mDNSPosix/PosixDaemon.c
mDNSResponder-66.3.tar.gz
[apple/mdnsresponder.git] / mDNSPosix / PosixDaemon.c
diff --git a/mDNSPosix/PosixDaemon.c b/mDNSPosix/PosixDaemon.c
new file mode 100644 (file)
index 0000000..6e943de
--- /dev/null
@@ -0,0 +1,323 @@
+/*
+ * Copyright (c) 2003 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved.
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+
+       File:           daemon.c
+
+       Contains:       main & associated Application layer for mDNSResponder on Linux.
+
+       Version:        1.0
+       Tabs:           4 spaces
+
+    Change History (most recent first):
+
+$Log: PosixDaemon.c,v $
+Revision 1.10  2004/06/08 04:59:40  cheshire
+Tidy up wording -- log messages are already prefixed with "mDNSResponder", so don't need to repeat it
+
+Revision 1.9  2004/05/29 00:14:20  rpantos
+<rdar://problem/3508093> Runtime check to disable prod mdnsd on OS X.
+
+Revision 1.8  2004/04/07 01:19:04  cheshire
+Hash slot value should be unsigned
+
+Revision 1.7  2004/02/14 06:34:57  cheshire
+Use LogMsg instead of fprintf( stderr
+
+Revision 1.6  2004/02/14 01:10:42  rpantos
+Allow daemon to run if 'nobody' is not defined, with a warning. (For Roku HD1000.)
+
+Revision 1.5  2004/02/05 07:45:43  cheshire
+Add Log header
+
+Revision 1.4  2004/01/28 21:14:23  cheshire
+Reconcile debug_mode and gDebugLogging into a single flag (mDNS_DebugMode)
+
+Revision 1.3  2004/01/19 19:51:46  cheshire
+Fix compiler error (mixed declarations and code) on some versions of Linux
+
+Revision 1.2  2003/12/11 03:03:51  rpantos
+Clean up mDNSPosix so that it builds on OS X again.
+
+Revision 1.1  2003/12/08 20:47:02  rpantos
+Add support for mDNSResponder on Linux.
+
+*/
+
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <errno.h>
+#include <pwd.h>
+#include <sys/types.h>
+
+#include "mDNSClientAPI.h"
+#include "mDNSDebug.h"
+#include "mDNSPosix.h"
+#include "uds_daemon.h"
+
+
+static void            ParseCmdLinArgs( int argc, char **argv);
+static void            DumpStateLog( mDNS *m);
+static mStatus MainLoop( mDNS *m);
+
+
+#define RR_CACHE_SIZE 500
+static CacheRecord gRRCache[RR_CACHE_SIZE];
+
+extern const char mDNSResponderVersionString[];
+
+int            main( int argc, char **argv)
+{
+       mDNS                                    mDNSRecord;
+       mDNS_PlatformSupport    platformStorage;
+       mStatus                                 err;
+
+       bzero( &mDNSRecord, sizeof mDNSRecord);
+       bzero( &platformStorage, sizeof platformStorage);
+
+       ParseCmdLinArgs( argc, argv);
+
+       err = mDNS_Init( &mDNSRecord, &platformStorage, gRRCache, RR_CACHE_SIZE, mDNS_Init_AdvertiseLocalAddresses, 
+                                       mDNS_Init_NoInitCallback, mDNS_Init_NoInitCallbackContext); 
+
+       if ( mStatus_NoError == err)
+               err = udsserver_init( &mDNSRecord);
+
+       // 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( &mDNSRecord);
+       mDNS_Close( &mDNSRecord);
+
+       if (udsserver_exit() < 0)
+               LogMsg("ExitCallback: udsserver_exit failed");
+ #if MDNS_DEBUGMSGS > 0
+       printf( "mDNSResponder exiting normally with %ld\n", err);
+ #endif
+       return err;
+}
+
+
+static void    ParseCmdLinArgs( int argc, char **argv)
+// Do appropriate things at startup with command line arguments. Calls exit() if unhappy.
+{
+       if ( argc > 1)
+       {
+               if ( 0 == strcmp( argv[1], "-debug"))
+               {
+                       mDNS_DebugMode = mDNStrue;
+               }
+               else
+                       printf( "Usage: mDNSResponder [-debug]\n");
+       }
+
+       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 mDNSResponder should only be used on OS X for testing - exiting");
+                       exit( -1);
+               }
+#endif
+       }
+}
+
+
+static void            DumpStateLog( mDNS *m)
+// Dump a little log of what we've been up to.
+{
+       mDNSu32 slot;
+       CacheRecord *rr;
+       mDNSu32 CacheUsed = 0, CacheActive = 0;
+       mDNSs32 now = mDNSPlatformTimeNow();
+
+       LogMsgIdent(mDNSResponderVersionString, "---- BEGIN STATE LOG ----");
+
+       for (slot = 0; slot < CACHE_HASH_SLOTS; slot++)
+               {
+               mDNSu32 SlotUsed = 0;
+               for (rr = m->rrcache_hash[slot]; rr; rr=rr->next)
+                       {
+                       mDNSs32 remain = rr->resrec.rroriginalttl - (now - rr->TimeRcvd) / mDNSPlatformOneSecond;
+                       CacheUsed++;
+                       SlotUsed++;
+                       if (rr->CRActiveQuestion) CacheActive++;
+                       LogMsgNoIdent("%s%6ld %-6s%-6s%s", rr->CRActiveQuestion ? "*" : " ", remain, DNSTypeName(rr->resrec.rrtype),
+                               ((PosixNetworkInterface *)rr->resrec.InterfaceID)->intfName, GetRRDisplayString(m, rr));
+                       usleep(1000);   // Limit rate a little so we don't flood syslog too fast
+                       }
+               if (m->rrcache_used[slot] != SlotUsed)
+                       LogMsgNoIdent("Cache use mismatch: rrcache_used[slot] is %lu, true count %lu", m->rrcache_used[slot], SlotUsed);
+               }
+       if (m->rrcache_totalused != CacheUsed)
+               LogMsgNoIdent("Cache use mismatch: rrcache_totalused is %lu, true count %lu", m->rrcache_totalused, CacheUsed);
+       if (m->rrcache_active != CacheActive)
+               LogMsgNoIdent("Cache use mismatch: rrcache_active is %lu, true count %lu", m->rrcache_active, CacheActive);
+       LogMsgNoIdent("Cache currently contains %lu records; %lu referenced by active questions", CacheUsed, CacheActive);
+
+       udsserver_info();
+
+       LogMsgIdent(mDNSResponderVersionString, "----  END STATE LOG  ----");
+}
+
+static mStatus MainLoop( mDNS *m)
+// Loop until we quit.
+{
+       sigset_t        signals;
+       mDNSBool        gotData = mDNSfalse;
+
+       mDNSPosixListenForSignalInEventLoop( SIGINT);
+       mDNSPosixListenForSignalInEventLoop( SIGTERM);
+       mDNSPosixListenForSignalInEventLoop( SIGUSR1);
+       mDNSPosixListenForSignalInEventLoop( SIGPIPE);
+
+       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 - mDNSPlatformTimeNow();
+                       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, SIGUSR1))
+                       DumpStateLog( m);
+               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.
+                       LogMsg("Received SIGPIPE - ignoring");
+               if ( sigismember( &signals, SIGINT) || sigismember( &signals, SIGTERM))
+                       break;
+       }
+
+       return EINTR;
+}
+
+
+//             uds_daemon support              ////////////////////////////////////////////////////////////
+
+#if MDNS_MALLOC_DEBUGGING >= 2
+#define LogMalloc LogMsg
+#else
+#define        LogMalloc(ARGS...) ((void)0)
+#endif
+
+
+mStatus udsSupportAddFDToEventLoop( int fd, udsEventCallback callback, void *context)
+/* Support routine for uds_daemon.c */
+{
+       // Depends on the fact that udsEventCallback == mDNSPosixEventCallback
+       return mDNSPosixAddFDToEventLoop( fd, callback, context);
+}
+
+mStatus udsSupportRemoveFDFromEventLoop( int fd)
+{
+       return mDNSPosixRemoveFDFromEventLoop( fd);
+}
+
+#if MACOSX_MDNS_MALLOC_DEBUGGING >= 1
+
+void *mallocL(char *msg, unsigned int size)
+{
+       unsigned long *mem = malloc(size+8);
+       if (!mem)
+       {
+               LogMsg("malloc( %s : %d ) failed", msg, size);
+               return(NULL); 
+       }
+       else
+       {
+               LogMalloc("malloc( %s : %lu ) = %p", msg, size, &mem[2]);
+               mem[0] = 0xDEAD1234;
+               mem[1] = size;
+               //bzero(&mem[2], size);
+               memset(&mem[2], 0xFF, size);
+//             validatelists(&mDNSStorage);
+               return(&mem[2]);
+       }
+}
+
+void freeL(char *msg, void *x)
+{
+       if (!x)
+               LogMsg("free( %s @ NULL )!", msg);
+       else
+       {
+               unsigned long *mem = ((unsigned long *)x) - 2;
+               if (mem[0] != 0xDEAD1234)
+                       { LogMsg("free( %s @ %p ) !!!! NOT ALLOCATED !!!!", msg, &mem[2]); return; }
+               if (mem[1] > 8000)
+                       { LogMsg("free( %s : %ld @ %p) too big!", msg, mem[1], &mem[2]); return; }
+               LogMalloc("free( %s : %ld @ %p)", msg, mem[1], &mem[2]);
+               //bzero(mem, mem[1]+8);
+               memset(mem, 0xDD, mem[1]+8);
+//             validatelists(&mDNSStorage);
+               free(mem);
+       }
+}
+
+#endif // MACOSX_MDNS_MALLOC_DEBUGGING >= 1
+
+
+
+// For convenience when using the "strings" command, this is the last thing in the file
+#if mDNSResponderVersion > 1
+mDNSexport const char mDNSResponderVersionString[] = "mDNSResponder-" STRINGIFY(mDNSResponderVersion) " (" __DATE__ " " __TIME__ ") ";
+#else
+mDNSexport const char mDNSResponderVersionString[] = "mDNSResponder (Engineering Build) (" __DATE__ " " __TIME__ ") ";
+#endif