Add Apple mDNS reponder

This commit is contained in:
Ron Pedde 2003-10-23 21:43:01 +00:00
parent 1aba1107cd
commit d971a35a46
14 changed files with 7812 additions and 29 deletions

View File

@ -3,28 +3,53 @@
<TITLE>mt-daapd administration</TITLE>
</HEAD>
<BODY>
<h1>Config</h1>
<FORM METHOD="POST" ACTION="/config-update.html">
<TABLE>
<TR>
<TD>Web Root</TD>
<TD><INPUT TYPE="TEXT" NAME="WEB_ROOT" READONLY
VALUE="@WEB_ROOT@"></TD>
</TR>
<TR>
<TD>Port</TD>
<TD><INPUT TYPE="TEXT" NAME="PORT" READONLY
VALUE="@PORT@"></TD>
</TR>
<TR>
<TD>Admin Password</TD>
<TD><INPUT TYPE="TEXT" NAME="ADMINPW"
VALUE="@ADMINPW@"></TD>
</TR>
</TABLE>
<INPUT TYPE="SUBMIT" NAME="SUBMIT" VALUE="Submit">
</FORM>
<CENTER>
<A HREF="config.html">Configure</A> |
<A HREF="status.html">Status</A> |
<A HREF="services.html">Services</A>
</CENTER>
<HR>
<i>@RELEASE@</i>
<CENTER><H1>Welcome</H1></CENTER>
<P>
Welcome to mt-daapd (better name pending), a pthreads
implementation of Apple's DAAP, including a multicast DNS
responder for iTunes.
</P>
<P>
This server is provided under the terms of the GPL. See the
file LICENSE in the root directory of this distribution for more
information on the rights provided to you by the GPL. For newest
versions of this software, check the SourceForge web site at <A
HREF="http://xxx.sourceforge.net">http://xxx.sourceforge.net</A>.
</P>
<P>
Portions of this work (the MDNS responder) are Copyright (C)
1999-2001 Apple Computer, Inc. All rights reserved. See the
file APPLE_LICENSE in the root directory for more information
on the rights provided to you by the ASPL.
</P>
<P>
<B>WARNING: NO WARRANTY</B><BR>
BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO
WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE
LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS"
WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED,
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE
ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS
WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE
COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
</P>
<HR>
<I>@RELEASE@</I>
</BODY>
</HTML>

View File

@ -16,7 +16,7 @@ AC_ARG_ENABLE(debug,Enable debugging features,CPPFLAGS="$CPPFLAGS -DDEBUG -g")
dnl Darwin's stupid cpp preprocessor....
case $host in
*darwin*)
CPPFLAGS="$CPPFLAGS -no-cpp-precomp";;
CPPFLAGS="$CPPFLAGS -no-cpp-precomp -DHAVE_SOCKADDR_SA_LEN";;
esac
dnl Checks for libraries.

View File

@ -82,7 +82,7 @@ install_sh = /Users/ron/Documents/School/cs4953-Concurrency/mt-daapd/install-sh
#
sbin_PROGRAMS = mt-daapd
mt_daapd_SOURCES = main.c uici.c webserver.c configfile.c err.c restart.c
mt_daapd_SOURCES = main.c rend.c uici.c webserver.c configfile.c err.c restart.c mdns/mDNS.c mdns/mDNSClientAPI.h mdns/mDNSDebug.h mdns/mDNSPosix.c mdns/mDNSUNP.c
subdir = src
mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
CONFIG_HEADER = $(top_builddir)/config.h
@ -90,8 +90,10 @@ CONFIG_CLEAN_FILES =
sbin_PROGRAMS = mt-daapd$(EXEEXT)
PROGRAMS = $(sbin_PROGRAMS)
am_mt_daapd_OBJECTS = main.$(OBJEXT) uici.$(OBJEXT) webserver.$(OBJEXT) \
configfile.$(OBJEXT) err.$(OBJEXT) restart.$(OBJEXT)
am_mt_daapd_OBJECTS = main.$(OBJEXT) rend.$(OBJEXT) uici.$(OBJEXT) \
webserver.$(OBJEXT) configfile.$(OBJEXT) err.$(OBJEXT) \
restart.$(OBJEXT) mDNS.$(OBJEXT) mDNSPosix.$(OBJEXT) \
mDNSUNP.$(OBJEXT)
mt_daapd_OBJECTS = $(am_mt_daapd_OBJECTS)
mt_daapd_LDADD = $(LDADD)
mt_daapd_DEPENDENCIES =
@ -99,13 +101,15 @@ mt_daapd_LDFLAGS =
DEFS = -DHAVE_CONFIG_H
DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir)
CPPFLAGS = -DDEBUG -g -no-cpp-precomp
CPPFLAGS = -DDEBUG -g -no-cpp-precomp -DHAVE_SOCKADDR_SA_LEN
LDFLAGS = -lpthread
LIBS =
depcomp = $(SHELL) $(top_srcdir)/depcomp
am__depfiles_maybe = depfiles
DEP_FILES = ./$(DEPDIR)/configfile.Po ./$(DEPDIR)/err.Po \
./$(DEPDIR)/main.Po ./$(DEPDIR)/restart.Po \
./$(DEPDIR)/mDNS.Po ./$(DEPDIR)/mDNSPosix.Po \
./$(DEPDIR)/mDNSUNP.Po ./$(DEPDIR)/main.Po \
./$(DEPDIR)/rend.Po ./$(DEPDIR)/restart.Po \
./$(DEPDIR)/uici.Po ./$(DEPDIR)/webserver.Po
COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
@ -149,6 +153,9 @@ uninstall-sbinPROGRAMS:
clean-sbinPROGRAMS:
-test -z "$(sbin_PROGRAMS)" || rm -f $(sbin_PROGRAMS)
mDNS.$(OBJEXT): mdns/mDNS.c
mDNSPosix.$(OBJEXT): mdns/mDNSPosix.c
mDNSUNP.$(OBJEXT): mdns/mDNSUNP.c
mt-daapd$(EXEEXT): $(mt_daapd_OBJECTS) $(mt_daapd_DEPENDENCIES)
@rm -f mt-daapd$(EXEEXT)
$(LINK) $(mt_daapd_LDFLAGS) $(mt_daapd_OBJECTS) $(mt_daapd_LDADD) $(LIBS)
@ -161,7 +168,11 @@ distclean-compile:
include ./$(DEPDIR)/configfile.Po
include ./$(DEPDIR)/err.Po
include ./$(DEPDIR)/mDNS.Po
include ./$(DEPDIR)/mDNSPosix.Po
include ./$(DEPDIR)/mDNSUNP.Po
include ./$(DEPDIR)/main.Po
include ./$(DEPDIR)/rend.Po
include ./$(DEPDIR)/restart.Po
include ./$(DEPDIR)/uici.Po
include ./$(DEPDIR)/webserver.Po
@ -180,6 +191,42 @@ distclean-depend:
depfile='$(DEPDIR)/$*.Po' tmpdepfile='$(DEPDIR)/$*.TPo' \
$(CCDEPMODE) $(depcomp) \
$(COMPILE) -c `cygpath -w $<`
mDNS.o: mdns/mDNS.c
source='mdns/mDNS.c' object='mDNS.o' libtool=no \
depfile='$(DEPDIR)/mDNS.Po' tmpdepfile='$(DEPDIR)/mDNS.TPo' \
$(CCDEPMODE) $(depcomp) \
$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mDNS.o `test -f 'mdns/mDNS.c' || echo '$(srcdir)/'`mdns/mDNS.c
mDNS.obj: mdns/mDNS.c
source='mdns/mDNS.c' object='mDNS.obj' libtool=no \
depfile='$(DEPDIR)/mDNS.Po' tmpdepfile='$(DEPDIR)/mDNS.TPo' \
$(CCDEPMODE) $(depcomp) \
$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mDNS.obj `cygpath -w mdns/mDNS.c`
mDNSPosix.o: mdns/mDNSPosix.c
source='mdns/mDNSPosix.c' object='mDNSPosix.o' libtool=no \
depfile='$(DEPDIR)/mDNSPosix.Po' tmpdepfile='$(DEPDIR)/mDNSPosix.TPo' \
$(CCDEPMODE) $(depcomp) \
$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mDNSPosix.o `test -f 'mdns/mDNSPosix.c' || echo '$(srcdir)/'`mdns/mDNSPosix.c
mDNSPosix.obj: mdns/mDNSPosix.c
source='mdns/mDNSPosix.c' object='mDNSPosix.obj' libtool=no \
depfile='$(DEPDIR)/mDNSPosix.Po' tmpdepfile='$(DEPDIR)/mDNSPosix.TPo' \
$(CCDEPMODE) $(depcomp) \
$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mDNSPosix.obj `cygpath -w mdns/mDNSPosix.c`
mDNSUNP.o: mdns/mDNSUNP.c
source='mdns/mDNSUNP.c' object='mDNSUNP.o' libtool=no \
depfile='$(DEPDIR)/mDNSUNP.Po' tmpdepfile='$(DEPDIR)/mDNSUNP.TPo' \
$(CCDEPMODE) $(depcomp) \
$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mDNSUNP.o `test -f 'mdns/mDNSUNP.c' || echo '$(srcdir)/'`mdns/mDNSUNP.c
mDNSUNP.obj: mdns/mDNSUNP.c
source='mdns/mDNSUNP.c' object='mDNSUNP.obj' libtool=no \
depfile='$(DEPDIR)/mDNSUNP.Po' tmpdepfile='$(DEPDIR)/mDNSUNP.TPo' \
$(CCDEPMODE) $(depcomp) \
$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mDNSUNP.obj `cygpath -w mdns/mDNSUNP.c`
CCDEPMODE = depmode=gcc
uninstall-info-am:

View File

@ -34,6 +34,7 @@
#include "configfile.h"
#include "err.h"
#include "rend.h"
#include "webserver.h"
// 3689
@ -172,6 +173,8 @@ int main(int argc, char *argv[]) {
char *configfile=NULL;
WSCONFIG ws_config;
WSHANDLE server;
pid_t rendezvous_pid;
#ifdef DEBUG
char *optval="d:c:";
#else
@ -230,6 +233,8 @@ int main(int argc, char *argv[]) {
ws_registerhandler(server, "^.*$",config_handler,config_auth);
rend_init(&rendezvous_pid);
while(1) {
sleep(20);
}

896
src/mdns/Responder.c Executable file
View File

@ -0,0 +1,896 @@
/*
* Copyright (c) 2002 Apple Computer, Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* The contents of this file constitute Original Code as defined in and
* are subject to the Apple Public Source License Version 1.2 (the
* "License"). You may not use this file except in compliance with the
* License. Please obtain a copy of the License at
* http://www.apple.com/publicsource and read it before using this file.
*
* This 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 OR NON-INFRINGEMENT. Please see the
* License for the specific language governing rights and limitations
* under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
/*
File: responder.c
Contains: Code to implement an mDNS responder on the Posix platform.
Written by: Quinn
Copyright: Copyright (c) 2002 by Apple Computer, Inc., All Rights Reserved.
Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Computer, Inc.
("Apple") in consideration of your agreement to the following terms, and your
use, installation, modification or redistribution of this Apple software
constitutes acceptance of these terms. If you do not agree with these terms,
please do not use, install, modify or redistribute this Apple software.
In consideration of your agreement to abide by the following terms, and subject
to these terms, Apple grants you a personal, non-exclusive license, under Apple's
copyrights in this original Apple software (the "Apple Software"), to use,
reproduce, modify and redistribute the Apple Software, with or without
modifications, in source and/or binary forms; provided that if you redistribute
the Apple Software in its entirety and without modifications, you must retain
this notice and the following text and disclaimers in all such redistributions of
the Apple Software. Neither the name, trademarks, service marks or logos of
Apple Computer, Inc. may be used to endorse or promote products derived from the
Apple Software without specific prior written permission from Apple. Except as
expressly stated in this notice, no other rights or licenses, express or implied,
are granted by Apple herein, including but not limited to any patent rights that
may be infringed by your derivative works or by other works in which the Apple
Software may be incorporated.
The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO
WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN
COMBINATION WITH YOUR PRODUCTS.
IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION
OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT
(INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Change History (most recent first):
$Log$
Revision 1.1 2003/10/23 21:43:01 ron
Add Apple mDNS reponder
Revision 1.3 2002/09/21 20:44:53 zarzycki
Added APSL info
Revision 1.2 2002/09/19 04:20:44 cheshire
Remove high-ascii characters that confuse some systems
Revision 1.1 2002/09/17 06:24:35 cheshire
First checkin
*/
#include "mDNSClientAPI.h"// Defines the interface to the client layer above
#include "mDNSPosix.h" // Defines the specific types needed to run mDNS on this platform
#include <assert.h>
#include <stdio.h> // For printf()
#include <stdlib.h> // For exit() etc.
#include <string.h> // For strlen() etc.
#include <unistd.h> // For select()
#include <errno.h> // For errno, EINTR
#include <signal.h>
#include <fcntl.h>
#pragma mark ***** Globals
static mDNS mDNSStorage; // mDNS core uses this to store its globals
static mDNS_PlatformSupport PlatformStorage; // Stores this platform's globals
static const char *gProgramName = "mDNSResponderPosix";
#pragma mark ***** Signals
static volatile mDNSBool gReceivedSigUsr1;
static volatile mDNSBool gReceivedSigHup;
static volatile mDNSBool gStopNow;
// We support 4 signals.
//
// o SIGUSR1 toggles verbose mode on and off in debug builds
// o SIGHUP triggers the program to re-read its preferences.
// o SIGINT causes an orderly shutdown of the program.
// o SIGQUIT causes a somewhat orderly shutdown (direct but dangerous)
// o SIGKILL kills us dead (easy to implement :-)
//
// There are fatal race conditions in our signal handling, but there's not much
// we can do about them while remaining within the Posix space. Specifically,
// if a signal arrives after we test the globals its sets but before we call
// select, the signal will be dropped. The user will have to send the signal
// again. Unfortunately, Posix does not have a "sigselect" to atomically
// modify the signal mask and start a select.
static void HandleSigUsr1(int sigraised)
// If we get a SIGUSR1 we toggle the state of the
// verbose mode.
{
assert(sigraised == SIGUSR1);
gReceivedSigUsr1 = mDNStrue;
}
static void HandleSigHup(int sigraised)
// A handler for SIGHUP that causes us to break out of the
// main event loop when the user kill 1's us. This has the
// effect of triggered the main loop to deregister the
// current services and re-read the preferences.
{
assert(sigraised == SIGHUP);
gReceivedSigHup = mDNStrue;
}
static void HandleSigInt(int sigraised)
// A handler for SIGINT that causes us to break out of the
// main event loop when the user types ^C. This has the
// effect of quitting the program.
{
assert(sigraised == SIGINT);
if (gMDNSPlatformPosixVerboseLevel > 0) {
fprintf(stderr, "\nSIGINT\n");
}
gStopNow = mDNStrue;
}
static void HandleSigQuit(int sigraised)
// If we get a SIGQUIT the user is desperate and we
// just call mDNS_Close directly. This is definitely
// not safe (because it could reenter mDNS), but
// we presume that the user has already tried the safe
// alternatives.
{
assert(sigraised == SIGQUIT);
if (gMDNSPlatformPosixVerboseLevel > 0) {
fprintf(stderr, "\nSIGQUIT\n");
}
mDNS_Close(&mDNSStorage);
exit(0);
}
#pragma mark ***** Parameter Checking
static mDNSBool CheckThatRichTextHostNameIsUsable(const char *richTextHostName, mDNSBool printExplanation)
// Checks that richTextHostName is a reasonable host name
// label and, if it isn't and printExplanation is true, prints
// an explanation of why not.
{
mDNSBool result;
domainlabel richLabel;
domainlabel poorLabel;
result = mDNStrue;
if (result && strlen(richTextHostName) > 63) {
if (printExplanation) {
fprintf(stderr,
"%s: Host name is too long (must be 63 characters or less)\n",
gProgramName);
}
result = mDNSfalse;
}
if (result && richTextHostName[0] == 0) {
if (printExplanation) {
fprintf(stderr, "%s: Host name can't be empty\n", gProgramName);
}
result = mDNSfalse;
}
if (result) {
ConvertCStringToDomainLabel(richTextHostName, &richLabel);
ConvertUTF8PstringToRFC1034HostLabel(richLabel.c, &poorLabel);
if (poorLabel.c[0] == 0) {
if (printExplanation) {
fprintf(stderr,
"%s: Host name doesn't produce a usable RFC-1034 name\n",
gProgramName);
}
result = mDNSfalse;
}
}
return result;
}
static mDNSBool CheckThatServiceTypeIsUsable(const char *serviceType, mDNSBool printExplanation)
// Checks that serviceType is a reasonable service type
// label and, if it isn't and printExplanation is true, prints
// an explanation of why not.
{
mDNSBool result;
result = mDNStrue;
if (result && strlen(serviceType) > 63) {
if (printExplanation) {
fprintf(stderr,
"%s: Service type is too long (must be 63 characters or less)\n",
gProgramName);
}
result = mDNSfalse;
}
if (result && serviceType[0] == 0) {
if (printExplanation) {
fprintf(stderr,
"%s: Service type can't be empty\n",
gProgramName);
}
result = mDNSfalse;
}
return result;
}
static mDNSBool CheckThatServiceTextIsUsable(const char *serviceText, mDNSBool printExplanation,
mDNSu8 *pStringList, mDNSu16 *pStringListLen)
// Checks that serviceText is a reasonable service text record
// and, if it isn't and printExplanation is true, prints
// an explanation of why not. Also parse the text into
// the packed PString buffer denoted by pStringList and
// return the length of that buffer in *pStringListLen.
// Note that this routine assumes that the buffer is
// sizeof(RDataBody) bytes long.
{
mDNSBool result;
size_t serviceTextLen;
// Note that parsing a C string into a PString list always
// expands the data by one character, so the following
// compare is ">=", not ">". Here's the logic:
//
// #1 For a string with not ^A's, the PString length is one
// greater than the C string length because we add a length
// byte.
// #2 For every regular (not ^A) character you add to the C
// string, you add a regular character to the PString list.
// This does not affect the equivalence stated in #1.
// #3 For every ^A you add to the C string, you add a length
// byte to the PString list but you also eliminate the ^A,
// which again does not affect the equivalence stated in #1.
result = mDNStrue;
serviceTextLen = strlen(serviceText);
if (result && strlen(serviceText) >= sizeof(RDataBody)) {
if (printExplanation) {
fprintf(stderr,
"%s: Service text record is too long (must be less than %d characters)\n",
gProgramName,
(int) sizeof(RDataBody) );
}
result = mDNSfalse;
}
// Now break the string up into PStrings delimited by ^A.
// We know the data will fit so we can ignore buffer overrun concerns.
// However, we still have to treat runs long than 255 characters as
// an error.
if (result) {
int lastPStringOffset;
int i;
int thisPStringLen;
// This algorithm is a little tricky. We start by copying
// the string directly into the output buffer, shifted up by
// one byte. We then fill in the first byte with a ^A.
// We then walk backwards through the buffer and, for each
// ^A that we find, we replace it with the difference between
// its offset and the offset of the last ^A that we found
// (ie lastPStringOffset).
memcpy(&pStringList[1], serviceText, serviceTextLen);
pStringList[0] = 1;
lastPStringOffset = serviceTextLen + 1;
for (i = serviceTextLen; i >= 0; i--) {
if ( pStringList[i] == 1 ) {
thisPStringLen = (lastPStringOffset - i - 1);
assert(thisPStringLen >= 0);
if (thisPStringLen > 255) {
result = mDNSfalse;
if (printExplanation) {
fprintf(stderr,
"%s: Each component of the service text record must be 255 characters or less\n",
gProgramName);
}
break;
} else {
pStringList[i] = thisPStringLen;
lastPStringOffset = i;
}
}
}
*pStringListLen = serviceTextLen + 1;
}
return result;
}
static mDNSBool CheckThatPortNumberIsUsable(long portNumber, mDNSBool printExplanation)
// Checks that portNumber is a reasonable port number
// and, if it isn't and printExplanation is true, prints
// an explanation of why not.
{
mDNSBool result;
result = mDNStrue;
if (result && (portNumber <= 0 || portNumber > 65535)) {
if (printExplanation) {
fprintf(stderr,
"%s: Port number specified by -p must be in range 1..65535\n",
gProgramName);
}
result = mDNSfalse;
}
return result;
}
#pragma mark ***** Command Line Arguments
static const char kDefaultPIDFile[] = "/var/run/mDNSResponder.pid";
static const char kDefaultServiceType[] = "_afpovertcp._tcp.";
enum {
kDefaultPortNumber = 548
};
static void PrintUsage(char **argv)
{
fprintf(stderr,
"Usage: %s [-v level ] [-r] [-n name] [-t type] [-x TXT] [-p port] [-f file] [-d] [-P pidfile]\n",
gProgramName);
fprintf(stderr, " -v verbose mode, level is a number from 0 to 2\n");
fprintf(stderr, " 0 = no debugging info (default)\n");
fprintf(stderr, " 1 = standard debugging info\n");
fprintf(stderr, " 2 = intense debugging info\n");
fprintf(stderr, " can be cycled kill -USR1\n");
fprintf(stderr, " -r also bind to port 53 (port 5353 is always bound)\n");
fprintf(stderr, " -n uses 'name' as the host name (default is none)\n");
fprintf(stderr, " -t uses 'type' as the service type (default is '%s')\n", kDefaultServiceType);
fprintf(stderr, " -x uses 'TXT' as the service TXT record (default is empty)\n");
fprintf(stderr, " -p uses 'port' as the port number (default is '%d')\n", kDefaultPortNumber);
fprintf(stderr, " -f reads a service list from 'file'\n");
fprintf(stderr, " -d forces daemon mode\n");
fprintf(stderr, " -P uses 'pidfile' as the PID file\n");
fprintf(stderr, " (default is '%s')\n", kDefaultPIDFile);
fprintf(stderr, " only meaningful if -d also specified\n");
}
static mDNSBool gAvoidPort53 = mDNStrue;
static const char *gRichTextHostName = "";
static const char *gServiceType = kDefaultServiceType;
static mDNSu8 gServiceText[sizeof(RDataBody)];
static mDNSu16 gServiceTextLen = 0;
static int gPortNumber = kDefaultPortNumber;
static const char *gServiceFile = "";
static mDNSBool gDaemon = mDNSfalse;
static const char *gPIDFile = kDefaultPIDFile;
static void ParseArguments(int argc, char **argv)
// Parses our command line arguments into the global variables
// listed above.
{
int ch;
// Set gProgramName to the last path component of argv[0]
gProgramName = strrchr(argv[0], '/');
if (gProgramName == NULL) {
gProgramName = argv[0];
} else {
gProgramName += 1;
}
// Parse command line options using getopt.
do {
ch = getopt(argc, argv, "v:rn:x:t:p:f:dP");
if (ch != -1) {
switch (ch) {
case 'v':
gMDNSPlatformPosixVerboseLevel = atoi(optarg);
if (gMDNSPlatformPosixVerboseLevel < 0 || gMDNSPlatformPosixVerboseLevel > 2) {
fprintf(stderr,
"%s: Verbose mode must be in the range 0..2\n",
gProgramName);
exit(1);
}
break;
case 'r':
gAvoidPort53 = mDNSfalse;
break;
case 'n':
gRichTextHostName = optarg;
if ( ! CheckThatRichTextHostNameIsUsable(gRichTextHostName, mDNStrue) ) {
exit(1);
}
break;
case 't':
gServiceType = optarg;
if ( ! CheckThatServiceTypeIsUsable(gServiceType, mDNStrue) ) {
exit(1);
}
break;
case 'x':
if ( ! CheckThatServiceTextIsUsable(optarg, mDNStrue, gServiceText, &gServiceTextLen) ) {
exit(1);
}
break;
case 'p':
gPortNumber = atol(optarg);
if ( ! CheckThatPortNumberIsUsable(gPortNumber, mDNStrue) ) {
exit(1);
}
break;
case 'f':
gServiceFile = optarg;
break;
case 'd':
gDaemon = mDNStrue;
break;
case 'P':
gPIDFile = optarg;
break;
case '?':
default:
PrintUsage(argv);
exit(1);
break;
}
}
} while (ch != -1);
// Check for any left over command line arguments.
if (optind != argc) {
fprintf(stderr, "%s: Unexpected argument '%s'\n", gProgramName, argv[optind]);
exit(1);
}
// Check for inconsistency between the arguments.
if ( (gRichTextHostName[0] == 0) && (gServiceFile[0] == 0) ) {
fprintf(stderr, "%s: You must specify a service to register (-n) or a service file (-f).\n", gProgramName);
exit(1);
}
}
#pragma mark ***** Registration
typedef struct PosixService PosixService;
struct PosixService {
ServiceRecordSet coreServ;
PosixService *next;
int serviceID;
};
static PosixService *gServiceList = NULL;
static void RegistrationCallback(mDNS *const m, ServiceRecordSet *const thisRegistration, mStatus status)
// mDNS core calls this routine to tell us about the status of
// our registration. The appropriate action to take depends
// entirely on the value of status.
{
switch (status) {
case mStatus_NoError:
debugf("Callback: %##s Name Registered", thisRegistration->RR_SRV.name.c);
// Do nothing; our name was successfully registered. We may
// get more call backs in the future.
break;
case mStatus_NameConflict:
debugf("Callback: %##s Name Conflict", thisRegistration->RR_SRV.name.c);
// In the event of a conflict, this sample RegistrationCallback
// just calls mDNS_RenameAndReregisterService to automatically
// pick a new unique name for the service. For a device such as a
// printer, this may be appropriate. For a device with a user
// interface, and a screen, and a keyboard, the appropriate response
// may be to prompt the user and ask them to choose a new name for
// the service.
//
// Also, what do we do if mDNS_RenameAndReregisterService returns an
// error. Right now I have no place to send that error to.
status = mDNS_RenameAndReregisterService(m, thisRegistration);
assert(status == mStatus_NoError);
break;
case mStatus_MemFree:
debugf("Callback: %##s Memory Free", thisRegistration->RR_SRV.name.c);
// When debugging is enabled, make sure that thisRegistration
// is not on our gServiceList.
#if !defined(NDEBUG)
{
PosixService *cursor;
cursor = gServiceList;
while (cursor != NULL) {
assert(&cursor->coreServ != thisRegistration);
cursor = cursor->next;
}
}
#endif
free(thisRegistration);
break;
default:
debugf("Callback: %##s Unknown Status %d", thisRegistration->RR_SRV.name.c, status);
break;
}
}
static int gServiceID = 0;
static mStatus RegisterOneService(const char * richTextHostName,
const char * serviceType,
const mDNSu8 text[],
mDNSu16 textLen,
long portNumber)
{
mStatus status;
PosixService * thisServ;
mDNSOpaque16 port;
domainlabel name;
domainname type;
domainname domain;
status = mStatus_NoError;
thisServ = (PosixService *) malloc(sizeof(*thisServ));
if (thisServ == NULL) {
status = mStatus_NoMemoryErr;
}
if (status == mStatus_NoError) {
ConvertCStringToDomainLabel(richTextHostName, &name);
ConvertCStringToDomainName(serviceType, &type);
ConvertCStringToDomainName("local.", &domain);
port.b[0] = (portNumber >> 8) & 0x0FF;
port.b[1] = (portNumber >> 0) & 0x0FF;;
status = mDNS_RegisterService(&mDNSStorage, &thisServ->coreServ,
&name, &type, &domain,
NULL,
port,
text, textLen,
RegistrationCallback, thisServ);
}
if (status == mStatus_NoError) {
thisServ->serviceID = gServiceID;
gServiceID += 1;
thisServ->next = gServiceList;
gServiceList = thisServ;
if (gMDNSPlatformPosixVerboseLevel > 0) {
fprintf(stderr,
"%s: Registered service %d, name '%s', type '%s', port %ld\n",
gProgramName,
thisServ->serviceID,
richTextHostName,
serviceType,
portNumber);
}
} else {
if (thisServ != NULL) {
free(thisServ);
}
}
return status;
}
static mDNSBool ReadALine(char *buf, size_t bufSize, FILE *fp)
{
mDNSBool good;
size_t len;
good = (fgets(buf, bufSize, fp) != NULL);
if (good) {
len = strlen(buf);
good = (len > 0 && buf[len - 1] == '\n');
}
if (good) {
buf[len - 1] = 0;
}
return good;
}
static mStatus RegisterServicesInFile(const char *filePath)
{
mStatus status;
FILE * fp;
int junk;
mDNSBool good;
int ch;
char name[256];
char type[256];
char rawText[1024];
mDNSu8 text[sizeof(RDataBody)];
mDNSu16 textLen;
char port[256];
status = mStatus_NoError;
fp = fopen(filePath, "r");
if (fp == NULL) {
status = mStatus_UnknownErr;
}
if (status == mStatus_NoError) {
good = mDNStrue;
do {
// Skip over any blank lines.
do {
ch = fgetc(fp);
} while ( ch == '\n' || ch == '\r' );
if (ch != EOF) {
good = (ungetc(ch, fp) == ch);
}
// Read three lines, check them for validity, and register the service.
if ( good && ! feof(fp) ) {
good = ReadALine(name, sizeof(name), fp);
if (good) {
good = ReadALine(type, sizeof(type), fp);
}
if (good) {
good = ReadALine(rawText, sizeof(rawText), fp);
}
if (good) {
good = ReadALine(port, sizeof(port), fp);
}
if (good) {
good = CheckThatRichTextHostNameIsUsable(name, mDNSfalse)
&& CheckThatServiceTypeIsUsable(type, mDNSfalse)
&& CheckThatServiceTextIsUsable(rawText, mDNSfalse, text, &textLen)
&& CheckThatPortNumberIsUsable(atol(port), mDNSfalse);
}
if (good) {
status = RegisterOneService(name, type, text, textLen, atol(port));
if (status != mStatus_NoError) {
fprintf(stderr,
"%s: Failed to register service, name = %s, type = %s, port = %s\n",
gProgramName,
name,
type,
port);
status = mStatus_NoError; // keep reading
}
}
}
} while (good && !feof(fp));
if ( ! good ) {
fprintf(stderr, "%s: Error reading service file %s\n", gProgramName, gServiceFile);
}
}
if (fp != NULL) {
junk = fclose(fp);
assert(junk == 0);
}
return status;
}
static mStatus RegisterOurServices(void)
{
mStatus status;
status = mStatus_NoError;
if (gRichTextHostName[0] != 0) {
status = RegisterOneService(gRichTextHostName,
gServiceType,
gServiceText, gServiceTextLen,
gPortNumber);
}
if (status == mStatus_NoError && gServiceFile[0] != 0) {
status = RegisterServicesInFile(gServiceFile);
}
return status;
}
static void DeregisterOurServices(void)
{
PosixService *thisServ;
int thisServID;
while (gServiceList != NULL) {
thisServ = gServiceList;
gServiceList = thisServ->next;
thisServID = thisServ->serviceID;
mDNS_DeregisterService(&mDNSStorage, &thisServ->coreServ);
if (gMDNSPlatformPosixVerboseLevel > 0) {
fprintf(stderr,
"%s: Deregistered service %d\n",
gProgramName,
thisServ->serviceID);
}
}
}
#pragma mark **** Main
#if !defined(HAVE_DAEMON)
// The version of Solaris that I tested on didn't have the daemon
// call. This implementation was basically stolen from the
// Mac OS X standard C library.
static int daemon(int nochdir, int noclose)
{
int fd;
switch (fork()) {
case -1:
return (-1);
case 0:
break;
default:
_exit(0);
}
if (setsid() == -1)
return (-1);
if (!nochdir)
(void)chdir("/");
if (!noclose && (fd = _open("/dev/null", O_RDWR, 0)) != -1) {
(void)dup2(fd, STDIN_FILENO);
(void)dup2(fd, STDOUT_FILENO);
(void)dup2(fd, STDERR_FILENO);
if (fd > 2)
(void)_close(fd);
}
return (0);
}
#endif
int main(int argc, char **argv)
{
mStatus status;
int result;
// Parse our command line arguments. This won't come back if there's an error.
ParseArguments(argc, argv);
// If we're told to run as a daemon, then do that straight away.
// Note that we don't treat the inability to create our PID
// file as an error. Also note that we assign getpid to a long
// because printf has no format specified for pid_t.
if (gDaemon) {
if (gMDNSPlatformPosixVerboseLevel > 0) {
fprintf(stderr, "%s: Starting in daemon mode\n", gProgramName);
}
daemon(0,0);
{
FILE *fp;
int junk;
fp = fopen(gPIDFile, "w");
if (fp != NULL) {
fprintf(fp, "%ld\n", (long) getpid());
junk = fclose(fp);
assert(junk == 0);
}
}
} else {
if (gMDNSPlatformPosixVerboseLevel > 0) {
fprintf(stderr, "%s: Starting in foreground mode, PID %ld\n", gProgramName, (long) getpid());
}
}
status = mDNS_Init(&mDNSStorage, &PlatformStorage,
mDNS_Init_NoCache, mDNS_Init_ZeroCacheSize,
mDNS_Init_AdvertiseLocalAddresses,
mDNS_Init_NoInitCallback, mDNS_Init_NoInitCallbackContext);
if (status != mStatus_NoError) return(2);
status = RegisterOurServices();
if (status != mStatus_NoError) return(2);
signal(SIGHUP, HandleSigHup); // SIGHUP has to be sent by kill -HUP <pid>
signal(SIGINT, HandleSigInt); // SIGINT is what you get for a Ctrl-C
signal(SIGQUIT, HandleSigQuit); // SIGQUIT is what you get for a Ctrl-\ (indeed)
signal(SIGUSR1, HandleSigUsr1); // SIGUSR1 has to be sent by kill -USR1 <pid>
while (!gStopNow)
{
int nfds = 0;
fd_set readfds;
struct timeval timeout;
int result;
// 1. Set up the fd_set as usual here.
// This example client has no file descriptors of its own,
// but a real application would call FD_SET to add them to the set here
FD_ZERO(&readfds);
// 2. Set up the timeout.
// This example client has no other work it needs to be doing,
// so we set an effectively infinite timeout
timeout.tv_sec = 0x3FFFFFFF;
timeout.tv_usec = 0;
// 3. Give the mDNSPosix layer a chance to add its information to the fd_set and timeout
mDNSPosixGetFDSet(&mDNSStorage, &nfds, &readfds, &timeout);
// 4. Call select as normal
verbosedebugf("select(%d, %d.%06d)", nfds, timeout.tv_sec, timeout.tv_usec);
result = select(nfds, &readfds, NULL, NULL, &timeout);
if (result < 0)
{
verbosedebugf("select() returned %d errno %d", result, errno);
if (errno != EINTR) gStopNow = mDNStrue;
else
{
if (gReceivedSigUsr1)
{
gReceivedSigUsr1 = mDNSfalse;
gMDNSPlatformPosixVerboseLevel += 1;
if (gMDNSPlatformPosixVerboseLevel > 2)
gMDNSPlatformPosixVerboseLevel = 0;
if ( gMDNSPlatformPosixVerboseLevel > 0 )
fprintf(stderr, "\nVerbose level %d\n", gMDNSPlatformPosixVerboseLevel);
}
if (gReceivedSigHup)
{
if (gMDNSPlatformPosixVerboseLevel > 0)
fprintf(stderr, "\nSIGHUP\n");
gReceivedSigHup = mDNSfalse;
DeregisterOurServices();
status = mDNSPlatformPosixRefreshInterfaceList(&mDNSStorage);
if (status != mStatus_NoError) break;
status = RegisterOurServices();
if (status != mStatus_NoError) break;
}
}
}
else
{
// 5. Call mDNSPosixProcessFDSet to let the mDNSPosix layer do its work
mDNSPosixProcessFDSet(&mDNSStorage, result, &readfds);
// 6. This example client has no other work it needs to be doing,
// but a real client would do its work here
// ... (do work) ...
}
}
debugf("Exiting");
DeregisterOurServices();
mDNS_Close(&mDNSStorage);
if (status == mStatus_NoError) {
result = 0;
} else {
result = 2;
}
if ( (result != 0) || (gMDNSPlatformPosixVerboseLevel > 0) ) {
fprintf(stderr, "%s: Finished with status %ld, result %d\n", gProgramName, status, result);
}
return result;
}

4298
src/mdns/mDNS.c Normal file

File diff suppressed because it is too large Load Diff

660
src/mdns/mDNSClientAPI.h Normal file
View File

@ -0,0 +1,660 @@
/*
* Copyright (c) 2002 Apple Computer, Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* The contents of this file constitute Original Code as defined in and
* are subject to the Apple Public Source License Version 1.2 (the
* "License"). You may not use this file except in compliance with the
* License. Please obtain a copy of the License at
* http://www.apple.com/publicsource and read it before using this file.
*
* This 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 OR NON-INFRINGEMENT. Please see the
* License for the specific language governing rights and limitations
* under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
/*
File: mDNSClientAPI.h
Contains: Programming interface to the mDNS core.
Written by: Stuart Cheshire
Version: mDNS Core, September 2002
Copyright: Copyright (c) 2002 by Apple Computer, Inc., All Rights Reserved.
Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Computer, Inc.
("Apple") in consideration of your agreement to the following terms, and your
use, installation, modification or redistribution of this Apple software
constitutes acceptance of these terms. If you do not agree with these terms,
please do not use, install, modify or redistribute this Apple software.
In consideration of your agreement to abide by the following terms, and subject
to these terms, Apple grants you a personal, non-exclusive license, under Apple's
copyrights in this original Apple software (the "Apple Software"), to use,
reproduce, modify and redistribute the Apple Software, with or without
modifications, in source and/or binary forms; provided that if you redistribute
the Apple Software in its entirety and without modifications, you must retain
this notice and the following text and disclaimers in all such redistributions of
the Apple Software. Neither the name, trademarks, service marks or logos of
Apple Computer, Inc. may be used to endorse or promote products derived from the
Apple Software without specific prior written permission from Apple. Except as
expressly stated in this notice, no other rights or licenses, express or implied,
are granted by Apple herein, including but not limited to any patent rights that
may be infringed by your derivative works or by other works in which the Apple
Software may be incorporated.
The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO
WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN
COMBINATION WITH YOUR PRODUCTS.
IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION
OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT
(INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Change History (most recent first):
$Log$
Revision 1.1 2003/10/23 21:43:01 ron
Add Apple mDNS reponder
Revision 1.25 2002/09/21 20:44:49 zarzycki
Added APSL info
Revision 1.24 2002/09/19 23:47:35 cheshire
Added mDNS_RegisterNoSuchService() function for assertion of non-existance
of a particular named service
Revision 1.23 2002/09/19 21:25:34 cheshire
mDNS_sprintf() doesn't need to be in a separate file
Revision 1.22 2002/09/19 04:20:43 cheshire
Remove high-ascii characters that confuse some systems
Revision 1.21 2002/09/17 01:06:35 cheshire
Change mDNS_AdvertiseLocalAddresses to be a parameter to mDNS_Init()
Revision 1.20 2002/09/16 18:41:41 cheshire
Merge in license terms from Quinn's copy, in preparation for Darwin release
*/
#ifndef __mDNSClientAPI_h
#define __mDNSClientAPI_h
#include <stdarg.h> // stdarg.h is required for for va_list support for the mDNS_vsprintf declaration
#include "mDNSDebug.h"
#ifdef __cplusplus
extern "C" {
#endif
// ***************************************************************************
// Function scope indicators
// If you see "mDNSlocal" before a function name, it means the function is not callable outside this file
#define mDNSlocal static
// If you see "mDNSexport" before a symbol, it means the symbol is exported for use by clients
#define mDNSexport
// ***************************************************************************
#if 0
#pragma mark - DNS Resource Record class and type constants
#endif
typedef enum // From RFC 1035
{
kDNSClass_IN = 1, // Internet
kDNSClass_CS = 2, // CSNET
kDNSClass_CH = 3, // CHAOS
kDNSClass_HS = 4, // Hesiod
kDNSClass_NONE = 254, // Used in DNS UPDATE [RFC 2136]
kDNSQClass_ANY = 255, // Not a DNS class, but a DNS query class, meaning "all classes"
kDNSQClass_Mask = 0x7FFF, // Multicast DNS uses the bottom 15 bits to identify the record class...
kDNSClass_UniqueRRSet = 0x8000 // ... and the top bit indicates that all other cached records are now invalid
} DNS_ClassValues;
typedef enum // From RFC 1035
{
kDNSType_A = 1, // 1 Address
kDNSType_NS, // 2 Name Server
kDNSType_MD, // 3 Mail Destination
kDNSType_MF, // 4 Mail Forwarder
kDNSType_CNAME, // 5 Canonical Name
kDNSType_SOA, // 6 Start of Authority
kDNSType_MB, // 7 Mailbox
kDNSType_MG, // 8 Mail Group
kDNSType_MR, // 9 Mail Rename
kDNSType_NULL, // 10 NULL RR
kDNSType_WKS, // 11 Well-known-service
kDNSType_PTR, // 12 Domain name pointer
kDNSType_HINFO, // 13 Host information
kDNSType_MINFO, // 14 Mailbox information
kDNSType_MX, // 15 Mail Exchanger
kDNSType_TXT, // 16 Arbitrary text string
kDNSType_SRV = 33, // 33 Service record
kDNSQType_ANY = 255 // Not a DNS type, but a DNS query type, meaning "all types"
} DNS_TypeValues;
// ***************************************************************************
#if 0
#pragma mark - Simple types
#endif
// mDNS defines its own names for these common types to simplify portability across
// multiple platforms that may each have their own (different) names for these types.
typedef unsigned char mDNSBool;
typedef signed char mDNSs8;
typedef unsigned char mDNSu8;
typedef signed short mDNSs16;
typedef unsigned short mDNSu16;
typedef signed long mDNSs32;
typedef unsigned long mDNSu32;
// These types are for opaque two- and four-byte identifiers.
// The "NotAnInteger" fields of the unions allow the value to be conveniently passed around in a register
// for the sake of efficiency, but don't forget -- just because it is in a register doesn't mean it is an
// integer. Operations like add, multiply, increment, decrement, etc., are undefined for opaque identifiers.
typedef union { mDNSu8 b[2]; mDNSu16 NotAnInteger; } mDNSOpaque16;
typedef union { mDNSu8 b[4]; mDNSu32 NotAnInteger; } mDNSOpaque32;
typedef mDNSOpaque16 mDNSIPPort; // An IP port is a two-byte opaque identifier (not an integer)
typedef mDNSOpaque32 mDNSIPAddr; // An IP address is a four-byte opaque identifier (not an integer)
enum { mDNSfalse = 0, mDNStrue = 1 };
#define mDNSNULL 0L
enum
{
mStatus_Waiting = 1,
mStatus_NoError = 0,
// mDNS Error codes are in the range FFFE FF00 (-65792) to FFFE FFFF (-65537)
mStatus_UnknownErr = -65537, // 0xFFFE FFFF
mStatus_NoSuchNameErr = -65538,
mStatus_NoMemoryErr = -65539,
mStatus_BadParamErr = -65540,
mStatus_BadReferenceErr = -65541,
mStatus_BadStateErr = -65542,
mStatus_BadFlagsErr = -65543,
mStatus_UnsupportedErr = -65544,
mStatus_NotInitializedErr = -65545,
mStatus_NoCache = -65546,
mStatus_AlreadyRegistered = -65547,
mStatus_NameConflict = -65548,
mStatus_Invalid = -65549,
mStatus_MemFree = -65792 // 0xFFFE FF00
};
typedef mDNSs32 mStatus;
#define MAX_DOMAIN_LABEL 63
typedef struct { mDNSu8 c[ 64]; } domainlabel; // One label: length byte and up to 63 characters
#define MAX_DOMAIN_NAME 255
typedef struct { mDNSu8 c[256]; } domainname; // Up to 255 bytes of length-prefixed domainlabels
typedef struct { mDNSu8 c[256]; } UTF8str255; // Null-terminated C string
// ***************************************************************************
#if 0
#pragma mark - Resource Record structures
#endif
// Shared Resource Records do not have to be unique
// -- Shared Resource Records are used for NIAS service PTRs
// -- It is okay for several hosts to have RRs with the same name but different RDATA
// -- We use a random delay on replies to reduce collisions when all the hosts reply to the same query
// -- These RRs typically have moderately high TTLs (e.g. one hour)
// -- These records are announced on startup and topology changes for the benefit of passive listeners
// Unique Resource Records should be unique among hosts within any given mDNS scope
// -- The majority of Resource Records are of this type
// -- If two entities on the network have RRs with the same name but different RDATA, this is a conflict
// -- Replies may be sent immediately, because only one host should be replying to any particular query
// -- These RRs typically have low TTLs (e.g. ten seconds)
// -- On startup and after topology changes, a host issues queries to verify uniqueness
// Known Unique Resource Records are treated like Unique Resource Records, except that mDNS does
// not have to verify their uniqueness because this is already known by other means (e.g. the RR name
// is derived from the host's IP or Ethernet address, which is already known to be a unique identifier).
enum
{
kDNSRecordTypeUnregistered = 0x00, // Not currently in any list
kDNSRecordTypeDeregistering = 0x01, // Shared record about to announce its departure and leave the list
kDNSRecordTypeUnique = 0x08, // Will become a kDNSRecordTypeVerified when probing is complete
kDNSRecordTypePacketAnswer = 0x10, // Received in the Answer Section of a DNS Response
kDNSRecordTypePacketAdditional = 0x11, // Received in the Additional Section of a DNS Response
kDNSRecordTypePacketUniqueAns = 0x18, // Received in the Answer Section of a DNS Response with kDNSQClass_CacheFlushBit set
kDNSRecordTypePacketUniqueAdd = 0x19, // Received in the Additional Section of a DNS Response with kDNSQClass_CacheFlushBit set
kDNSRecordTypeShared = 0x20, // Shared means record name does not have to be unique -- so use random delay on replies
kDNSRecordTypeVerified = 0x28, // Unique means mDNS should check that name is unique (and then send immediate replies)
kDNSRecordTypeKnownUnique = 0x29, // Known Unique means mDNS can assume name is unique without checking
kDNSRecordTypeUniqueMask = 0x08, // Test for records that are supposed to not be shared with other hosts
kDNSRecordTypeRegisteredMask = 0xF8, // Test for records that have not had mDNS_Deregister called on them yet
kDNSRecordTypeActiveMask = 0xF0 // Test for all records that have finished their probing and are now active
};
enum
{
kDNSSendPriorityNone = 0, // Don't need to send this record right now
kDNSSendPriorityAdditional = 1, // Send this record as an additional, if we have space in the packet
kDNSSendPriorityAnswer = 2 // Need to send this record as an answer
};
typedef struct { mDNSu16 priority; mDNSu16 weight; mDNSIPPort port; domainname target; } rdataSRV;
typedef union
{
mDNSu8 data[512]; // Generic untyped data (temporarily set 512 for the benefit of iChat)
mDNSIPAddr ip; // For 'A' record
domainname name; // For PTR and CNAME records
UTF8str255 txt; // For TXT record
rdataSRV srv; // For SRV record
} RDataBody;
typedef struct
{
mDNSu16 MaxRDLength; // Amount of storage allocated for rdata (usually sizeof(RDataBody))
mDNSu16 RDLength; // Size of the rdata currently stored here
RDataBody u;
} RData;
typedef struct ResourceRecord_struct ResourceRecord;
typedef struct ResourceRecord_struct *ResourceRecordPtr;
typedef struct mDNS_struct mDNS;
typedef struct mDNS_PlatformSupport_struct mDNS_PlatformSupport;
typedef void mDNSRecordCallback(mDNS *const m, ResourceRecord *const rr, mStatus result);
typedef void mDNSRecordUpdateCallback(mDNS *const m, ResourceRecord *const rr, RData *OldRData);
// Fields labelled "AR:" apply to our authoritative records
// Fields labelled "CR:" apply to cache records
// Fields labelled "--:" apply to both
// (May want to make this a union later, but not now, because using the
// same storage for two different purposes always makes debugging harder.)
struct ResourceRecord_struct
{
ResourceRecord *next; // --: Next in list
// Field Group 1: Persistent metadata for Authoritative Records
ResourceRecord *Additional1; // AR: Recommended additional record to include in response
ResourceRecord *Additional2; // AR: Another additional
ResourceRecord *DependentOn; // AR: This record depends on another for its uniqueness checking
ResourceRecord *RRSet; // AR: This unique record is part of an RRSet
mDNSRecordCallback *Callback; // AR: Callback function to call for state changes
void *Context; // AR: Context parameter for the callback function
mDNSu8 RecordType; // --: See enum above
mDNSu8 HostTarget; // AR: Set if the target of this record (PTR, CNAME, SRV, etc.) is our host name
// Field Group 2: Transient state for Authoritative Records
mDNSu8 Acknowledged; // AR: Set if we've given the success callback to the client
mDNSu8 ProbeCount; // AR: Number of probes remaining before this record is valid (kDNSRecordTypeUnique)
mDNSu8 AnnounceCount; // AR: Number of announcements remaining (kDNSRecordTypeShared)
mDNSu8 IncludeInProbe; // AR: Set if this RR is being put into a probe right now
mDNSu8 SendPriority; // AR: See enum above
mDNSIPAddr Requester; // AR: Used for inter-packet duplicate suppression
// If set, give the IP address of the last host that sent a truncated query for this record
// If set to all-ones, more than one host sent such a request in the last few milliseconds
ResourceRecord *NextResponse; // AR: Link to the next element in the chain of responses to generate
const mDNSu8 *NR_AnswerTo; // AR: Set if this record was selected by virtue of being a direct answer to a question
ResourceRecord *NR_AdditionalTo; // AR: Set if this record was selected by virtue of being additional to another
mDNSs32 LastSendTime; // AR: In platform time units
mDNSs32 NextSendTime; // AR: In platform time units
mDNSs32 NextSendInterval; // AR: In platform time units
RData *NewRData; // AR: Set if we are updating this record with new rdata
mDNSRecordUpdateCallback *UpdateCallback;
// Field Group 3: Transient state for Cache Records
ResourceRecord *NextDupSuppress; // CR: Link to the next element in the chain of duplicate suppression answers to send
mDNSs32 TimeRcvd; // CR: In platform time units
mDNSs32 LastUsed; // CR: In platform time units
mDNSu32 UseCount; // CR: Number of times this RR has been used to answer a question
mDNSu32 UnansweredQueries; // CR: Number of times we've issued a query for this record without getting an answer
mDNSBool Active; // CR: Set if there is currently a question referencing this answer
mDNSBool NewData; // CR: Set if this is a record we just received
// Field Group 4: The actual information pertaining to this resource record
mDNSIPAddr InterfaceAddr; // --: Set if this RR is specific to one interface (e.g. a linklocal address)
// For records received off the wire, InterfaceAddr is *always* set to the receiving interface
// For our authoritative records, InterfaceAddr is usually zero,
// except those few records that are interface-specific (e.g. linklocal address records)
domainname name; // --: All the rest are used both in our authoritative records and in cache records
mDNSu16 rrtype;
mDNSu16 rrclass;
mDNSu32 rroriginalttl; // In seconds.
mDNSu32 rrremainingttl; // In seconds. Always set to correct value before calling question callback.
mDNSu16 rdestimate; // Upper bound on size of rdata after name compression
RData *rdata; // Pointer to storage for this rdata
RData rdatastorage; // Normally the storage is right here, except for oversized records
};
typedef struct NetworkInterfaceInfo_struct NetworkInterfaceInfo;
struct NetworkInterfaceInfo_struct
{
NetworkInterfaceInfo *next;
mDNSIPAddr ip;
mDNSBool Advertise; // Set Advertise to false if you are only searching on this interface
// Standard ResourceRecords that every Responder host should have (one per active IP address)
ResourceRecord RR_A1; // 'A' (address) record for our ".local" name
ResourceRecord RR_A2; // 'A' record for our ".local.arpa" name
ResourceRecord RR_PTR; // PTR (reverse lookup) record
};
typedef struct ExtraResourceRecord_struct ExtraResourceRecord;
struct ExtraResourceRecord_struct
{
ExtraResourceRecord *next;
ResourceRecord r;
// Note: Add any additional fields *before* the ResourceRecord in this structure, not at the end.
// In some cases clients can allocate larger chunks of memory and set r->rdata->MaxRDLength to indicate
// that this extra memory is available, which would result in any fields after the ResourceRecord getting smashed
};
typedef struct ServiceRecordSet_struct ServiceRecordSet;
typedef void mDNSServiceCallback(mDNS *const m, ServiceRecordSet *const sr, mStatus result);
struct ServiceRecordSet_struct
{
mDNSServiceCallback *Callback;
void *Context;
ExtraResourceRecord *Extras; // Optional list of extra ResourceRecords attached to this service registration
mDNSBool Conflict; // Set if this record set was forcibly deregistered because of a conflict
domainname Host; // Set if this service record does not use the standard target host name
ResourceRecord RR_PTR; // e.g. _printer._tcp.local. PTR Name._printer._tcp.local.
ResourceRecord RR_SRV; // e.g. Name._printer._tcp.local. SRV 0 0 port target
ResourceRecord RR_TXT; // e.g. Name._printer._tcp.local. TXT PrintQueueName
// Don't add any fields after ResourceRecord RR_TXT.
// This is where the implicit extra space goes if we allocate a ServiceRecordSet containing an oversized RR_TXT record
};
// ***************************************************************************
#if 0
#pragma mark - Question structures
#endif
typedef struct DNSQuestion_struct DNSQuestion;
typedef void mDNSQuestionCallback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer);
struct DNSQuestion_struct
{
DNSQuestion *next;
mDNSs32 NextQTime; // In platform time units
mDNSs32 ThisQInterval; // In platform time units (zero for questions not in list)
// ThisQInterval will be non-zero for an active question;
// Zero for a cancelled or inactive question
mDNSs32 NextQInterval;
DNSQuestion *DuplicateOf;
mDNSIPAddr InterfaceAddr; // Non-zero if you want to issue link-local queries only on a single specific IP interface
domainname name;
mDNSu16 rrtype;
mDNSu16 rrclass;
mDNSQuestionCallback *Callback;
void *Context;
};
typedef struct
{
domainname name;
mDNSIPAddr InterfaceAddr; // Local (source) IP Interface (needed for scoped addresses such as link-local)
mDNSIPAddr ip; // Remote (destination) IP address where this service can be accessed
mDNSIPPort port; // Port where this service can be accessed
mDNSu16 TXTlen;
mDNSu8 TXTinfo[2048]; // Additional demultiplexing information (e.g. LPR queue name)
} ServiceInfo;
typedef struct ServiceInfoQuery_struct ServiceInfoQuery;
typedef void ServiceInfoQueryCallback(mDNS *const m, ServiceInfoQuery *query);
struct ServiceInfoQuery_struct
{
DNSQuestion qSRV;
DNSQuestion qTXT;
DNSQuestion qADD;
mDNSu8 GotSRV;
mDNSu8 GotTXT;
mDNSu8 GotADD;
ServiceInfo *info;
ServiceInfoQueryCallback *Callback;
void *Context;
};
// ***************************************************************************
#if 0
#pragma mark - Main mDNS object, used to hold all the mDNS state
#endif
typedef void mDNSCallback(mDNS *const m, mStatus result);
struct mDNS_struct
{
mDNS_PlatformSupport *p; // Pointer to platform-specific data of indeterminite size
mDNSBool AdvertiseLocalAddresses;
mStatus mDNSPlatformStatus;
mDNSCallback *Callback;
void *Context;
mDNSu32 mDNS_busy; // For debugging: To catch and report locking failures
mDNSu8 lock_rrcache; // For debugging: Set at times when these lists may not be modified
mDNSu8 lock_Questions;
mDNSu8 lock_Records;
mDNSu8 padding;
// These fields only required for mDNS Searcher...
DNSQuestion *ActiveQuestions; // List of all active questions
DNSQuestion *NewQuestions; // Fresh questions not yet answered from cache
DNSQuestion *CurrentQuestion; // Next question about to be examined in AnswerLocalQuestions()
mDNSu32 rrcache_size;
mDNSu32 rrcache_used;
mDNSu32 rrcache_report;
ResourceRecord *rrcache_free;
ResourceRecord *rrcache;
// Fields below only required for mDNS Responder...
domainlabel nicelabel; // Rich text label encoded using canonically precomposed UTF-8
domainlabel hostlabel; // Conforms to RFC 1034 "letter-digit-hyphen" ARPANET host name rules
domainname hostname1; // Primary Host Name, e.g. "Foo.local."
domainname hostname2; // Secondary Host Name, e.g. "Foo.local.arpa."
ResourceRecord *ResourceRecords;
ResourceRecord *CurrentRecord; // Next ResourceRecord about to be examined
NetworkInterfaceInfo *HostInterfaces;
mDNSs32 SuppressSending;
mDNSs32 SuppressProbes;
mDNSBool SleepState;
mDNSBool NetChanged;
};
// ***************************************************************************
#if 0
#pragma mark - Useful Static Constants
#endif
extern const ResourceRecord zeroRR;
extern const mDNSIPPort zeroIPPort;
extern const mDNSIPAddr zeroIPAddr;
extern const mDNSIPAddr onesIPAddr;
extern const mDNSIPPort UnicastDNSPort;
extern const mDNSIPPort MulticastDNSPort;
extern const mDNSIPAddr AllDNSLinkGroup;
extern const mDNSIPAddr AllDNSAdminGroup;
// ***************************************************************************
#if 0
#pragma mark - Main Client Functions
#endif
// Every client should call mDNS_Init, passing in storage for the mDNS object, mDNS_PlatformSupport object, and rrcache.
// The rrcachesize parameter is the size of (i.e. number of entries in) the rrcache array passed in.
// When mDNS has finished setting up the initComplete callback is called
// A client can also spin and poll the mDNSPlatformStatus field to see when it changes from mStatus_Waiting to mStatus_NoError
//
// Call mDNS_Close to tidy up before exiting
//
// Call mDNS_Register with a completed ResourceRecord object to register a resource record
// If the resource record type is kDNSRecordTypeUnique (or kDNSknownunique) then if a conflicting resource record is discovered,
// the resource record's mDNSRecordCallback will be called with error code mStatus_NameConflict. The callback should deregister
// the record, and may then try registering the record again after picking a new name (e.g. by automatically appending a number).
//
// Call mDNS_StartQuery to initiate a query. mDNS will proceed to issue Multicast DNS query packets, and any time a reply
// is received containing a record which matches the question, the DNSQuestion's mDNSAnswerCallback function will be called
// Call mDNS_StopQuery when no more answers are required
//
// The mDNS routines are intentionally not thread-safe -- adding locking operations would add overhead that may not
// be necessary or appropriate on every platform. Instead, code in a pre-emptive environment calling any mDNS routine
// (except mDNS_Init and mDNS_Close) is responsible for doing the necessary synchronization to ensure that mDNS code is
// not re-entered. This includes both client software above mDNS, and the platform support code below. For example, if
// the support code on a particular platform implements timer callbacks at interrupt time, then clients on that platform
// need to disable interrupts or do similar concurrency control to ensure that the mDNS code is not entered by an
// interrupt-time timer callback while in the middle of processing a client call.
extern mStatus mDNS_Init (mDNS *const m, mDNS_PlatformSupport *const p,
ResourceRecord *rrcachestorage, mDNSu32 rrcachesize,
mDNSBool AdvertiseLocalAddresses,
mDNSCallback *Callback, void *Context);
#define mDNS_Init_NoCache mDNSNULL
#define mDNS_Init_ZeroCacheSize 0
#define mDNS_Init_AdvertiseLocalAddresses mDNStrue
#define mDNS_Init_DontAdvertiseLocalAddresses mDNSfalse
#define mDNS_Init_NoInitCallback mDNSNULL
#define mDNS_Init_NoInitCallbackContext mDNSNULL
extern void mDNS_Close (mDNS *const m);
extern mStatus mDNS_Register (mDNS *const m, ResourceRecord *const rr);
extern mStatus mDNS_Update (mDNS *const m, ResourceRecord *const rr, mDNSu32 newttl,
RData *const newrdata, mDNSRecordUpdateCallback *Callback);
extern void mDNS_Deregister(mDNS *const m, ResourceRecord *const rr);
extern mStatus mDNS_StartQuery(mDNS *const m, DNSQuestion *const question);
extern void mDNS_StopQuery (mDNS *const m, DNSQuestion *const question);
// ***************************************************************************
#if 0
#pragma mark - General utility and helper functions
#endif
// mDNS_RegisterHostSet is a single call to register the standard resource records associated with every host.
// mDNS_RegisterService is a single call to register the set of resource records associated with a given named service.
//
// mDNS_StartResolveService is single call which is equivalent to multiple calls to mDNS_StartQuery,
// to find the IP address, port number, and demultiplexing information for a given named service.
// As with mDNS_StartQuery, it executes asynchronously, and calls the ServiceInfoQueryCallback when the answer is
// found. After the service is resolved, the client should call mDNS_StopResolveService to complete the transaction.
// The client can also call mDNS_StopResolveService at any time to abort the transaction.
//
// mDNS_GetBrowseDomains is a special case of the mDNS_StartQuery call, where the resulting answers
// are a list of PTR records indicating (in the rdata) domains that are recommended for browsing.
// After getting the list of domains to browse, call mDNS_StopQuery to end the search.
// mDNS_GetDefaultBrowseDomain returns the name of the domain that should be highlighted by default.
//
// mDNS_GetRegistrationDomains and mDNS_GetDefaultRegistrationDomain are the equivalent calls to get the list
// of one or more domains that should be offered to the user as choices for where they may register their service,
// and the default domain in which to register in the case where the user has made no selection.
extern void mDNS_SetupResourceRecord(ResourceRecord *rr, RData *RDataStorage, mDNSIPAddr InterfaceAddr,
mDNSu16 rrtype, mDNSu32 ttl, mDNSu8 RecordType, mDNSRecordCallback Callback, void *Context);
extern void mDNS_GenerateFQDN(mDNS *const m);
extern mStatus mDNS_RegisterInterface (mDNS *const m, NetworkInterfaceInfo *set);
extern void mDNS_DeregisterInterface(mDNS *const m, NetworkInterfaceInfo *set);
extern mStatus mDNS_RegisterService (mDNS *const m, ServiceRecordSet *sr,
const domainlabel *const name, const domainname *const type, const domainname *const domain,
const domainname *const host, mDNSIPPort port, const mDNSu8 txtinfo[], mDNSu16 txtlen,
mDNSServiceCallback Callback, void *Context);
extern mStatus mDNS_AddRecordToService(mDNS *const m, ServiceRecordSet *sr, ExtraResourceRecord *extra, RData *rdata, mDNSu32 ttl);
extern mStatus mDNS_RemoveRecordFromService(mDNS *const m, ServiceRecordSet *sr, ExtraResourceRecord *extra);
extern mStatus mDNS_RenameAndReregisterService(mDNS *const m, ServiceRecordSet *const sr);
extern void mDNS_DeregisterService(mDNS *const m, ServiceRecordSet *sr);
extern mStatus mDNS_RegisterNoSuchService(mDNS *const m, ResourceRecord *const rr,
const domainlabel *const name, const domainname *const type, const domainname *const domain,
mDNSRecordCallback Callback, void *Context);
#define mDNS_DeregisterNoSuchService mDNS_Deregister
extern mStatus mDNS_StartBrowse(mDNS *const m, DNSQuestion *const question,
const domainname *const srv, const domainname *const domain,
const mDNSIPAddr InterfaceAddr, mDNSQuestionCallback *Callback, void *Context);
#define mDNS_StopBrowse mDNS_StopQuery
extern mStatus mDNS_StartResolveService(mDNS *const m, ServiceInfoQuery *query, ServiceInfo *info, ServiceInfoQueryCallback *Callback, void *Context);
extern void mDNS_StopResolveService (mDNS *const m, ServiceInfoQuery *query);
typedef enum
{
mDNS_DomainTypeBrowse = 0,
mDNS_DomainTypeBrowseDefault = 1,
mDNS_DomainTypeRegistration = 2,
mDNS_DomainTypeRegistrationDefault = 3
} mDNS_DomainType;
extern mStatus mDNS_GetDomains(mDNS *const m, DNSQuestion *const question, mDNSu8 DomainType, const mDNSIPAddr InterfaceAddr, mDNSQuestionCallback *Callback, void *Context);
#define mDNS_StopGetDomains mDNS_StopQuery
extern mStatus mDNS_AdvertiseDomains(mDNS *const m, ResourceRecord *rr, mDNSu8 DomainType, const mDNSIPAddr InterfaceAddr, char *domname);
#define mDNS_StopAdvertiseDomains mDNS_Deregister
// ***************************************************************************
#if 0
#pragma mark - DNS name utility functions
#endif
// In order to expose the full capabilities of the DNS protocol (which allows any arbitrary eight-bit values
// in domain name labels, including unlikely characters like ascii nulls and even dots) all the mDNS APIs
// work with DNS's native length-prefixed strings. For convenience in C, the following utility functions
// are provided for converting between C's null-terminated strings and DNS's length-prefixed strings.
extern mDNSBool SameDomainName(const domainname *const d1, const domainname *const d2);
extern mDNSu16 DomainNameLength(const domainname *const name);
extern void AppendDomainLabelToName(domainname *const name, const domainlabel *const label);
extern void AppendStringLabelToName(domainname *const name, const char *cstr);
extern void AppendDomainNameToName(domainname *const name, const domainname *const append);
extern void AppendStringNameToName(domainname *const name, const char *cstr);
extern void ConvertCStringToDomainLabel(const char *src, domainlabel *label);
extern mDNSu8 *ConvertCStringToDomainName(const char *const cstr, domainname *name);
extern char *ConvertDomainLabelToCString_withescape(const domainlabel *const name, char *cstr, char esc);
#define ConvertDomainLabelToCString_unescaped(D,C) ConvertDomainLabelToCString_withescape((D), (C), 0)
#define ConvertDomainLabelToCString(D,C) ConvertDomainLabelToCString_withescape((D), (C), '\\')
extern char *ConvertDomainNameToCString_withescape(const domainname *const name, char *cstr, char esc);
#define ConvertDomainNameToCString_unescaped(D,C) ConvertDomainNameToCString_withescape((D), (C), 0)
#define ConvertDomainNameToCString(D,C) ConvertDomainNameToCString_withescape((D), (C), '\\')
extern void ConvertUTF8PstringToRFC1034HostLabel(const mDNSu8 UTF8Name[], domainlabel *const hostlabel);
extern mDNSu8 *ConstructServiceName(domainname *const fqdn, const domainlabel *const name, const domainname *const type, const domainname *const domain);
extern mDNSBool DeconstructServiceName(const domainname *const fqdn, domainlabel *const name, domainname *const type, domainname *const domain);
// ***************************************************************************
#if 0
#pragma mark - Other utility functions
#endif
extern int mDNS_sprintf(char *sbuffer, const char *fmt, ...);
extern int mDNS_vsprintf(char *sbuffer, const char *fmt, va_list arg);
extern void IncrementLabelSuffix(domainlabel *name, mDNSBool RichText);
#ifdef __cplusplus
}
#endif
#endif

129
src/mdns/mDNSDebug.h Normal file
View File

@ -0,0 +1,129 @@
/*
* Copyright (c) 2002 Apple Computer, Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* The contents of this file constitute Original Code as defined in and
* are subject to the Apple Public Source License Version 1.2 (the
* "License"). You may not use this file except in compliance with the
* License. Please obtain a copy of the License at
* http://www.apple.com/publicsource and read it before using this file.
*
* This 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 OR NON-INFRINGEMENT. Please see the
* License for the specific language governing rights and limitations
* under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
/*
File: mDNSDebug.h
Contains: mDNS debugging interface.
Written by: Stuart Cheshire
Version: mDNS Core, September 2002
Copyright: Copyright (c) 2002 by Apple Computer, Inc., All Rights Reserved.
Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Computer, Inc.
("Apple") in consideration of your agreement to the following terms, and your
use, installation, modification or redistribution of this Apple software
constitutes acceptance of these terms. If you do not agree with these terms,
please do not use, install, modify or redistribute this Apple software.
In consideration of your agreement to abide by the following terms, and subject
to these terms, Apple grants you a personal, non-exclusive license, under Apple's
copyrights in this original Apple software (the "Apple Software"), to use,
reproduce, modify and redistribute the Apple Software, with or without
modifications, in source and/or binary forms; provided that if you redistribute
the Apple Software in its entirety and without modifications, you must retain
this notice and the following text and disclaimers in all such redistributions of
the Apple Software. Neither the name, trademarks, service marks or logos of
Apple Computer, Inc. may be used to endorse or promote products derived from the
Apple Software without specific prior written permission from Apple. Except as
expressly stated in this notice, no other rights or licenses, express or implied,
are granted by Apple herein, including but not limited to any patent rights that
may be infringed by your derivative works or by other works in which the Apple
Software may be incorporated.
The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO
WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN
COMBINATION WITH YOUR PRODUCTS.
IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION
OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT
(INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Change History (most recent first):
$Log$
Revision 1.1 2003/10/23 21:43:01 ron
Add Apple mDNS reponder
Revision 1.9 2002/09/21 20:44:49 zarzycki
Added APSL info
Revision 1.8 2002/09/19 04:20:43 cheshire
Remove high-ascii characters that confuse some systems
Revision 1.7 2002/09/16 18:41:42 cheshire
Merge in license terms from Quinn's copy, in preparation for Darwin release
*/
#ifndef __mDNSDebug_h
#define __mDNSDebug_h
// Set MDNS_DEBUGMSGS to 0 to optimize debugf() calls out of the compiled code
// Set MDNS_DEBUGMSGS to 1 to generate normal debugging messages
// Set MDNS_DEBUGMSGS to 2 to generate verbose debugging messages
// MDNS_DEBUGMSGS is normally set in the project options (or makefile) but can also be set here if desired
//#define MDNS_DEBUGMSGS 2
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
#ifdef DEBUG
#define debugf debugf_
extern void debugf_(const char *format, ...);
#else // If debug breaks are off, use a preprocessor trick to optimize those calls out of the code
#if( defined( __GNUC__ ) )
#define debugf( ARGS... ) ((void)0)
#elif( defined( __MWERKS__ ) )
#define debugf( ... )
#else
#define debugf 1 ? ((void)0) : (void)
#endif
#endif /* DEBUG */
#ifdef EXTRADEBUG
#define verbosedebugf verbosedebugf_
extern void verbosedebugf_(const char *format, ...);
#else
#if( defined( __GNUC__ ) )
#define verbosedebugf( ARGS... ) ((void)0)
#elif( defined( __MWERKS__ ) )
#define verbosedebugf( ... )
#else
#define verbosedebugf 1 ? ((void)0) : (void)
#endif
#endif /* DEBUG */
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,162 @@
/*
* Copyright (c) 2002 Apple Computer, Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* The contents of this file constitute Original Code as defined in and
* are subject to the Apple Public Source License Version 1.2 (the
* "License"). You may not use this file except in compliance with the
* License. Please obtain a copy of the License at
* http://www.apple.com/publicsource and read it before using this file.
*
* This 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 OR NON-INFRINGEMENT. Please see the
* License for the specific language governing rights and limitations
* under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
/*
File: mDNSPlatformFunctions.h
Contains: Prototype for functions implemented and callable by the platform.
Written by: Stuart Cheshire
Version: mDNS Core, September 2002
Copyright: Copyright (c) 2002 by Apple Computer, Inc., All Rights Reserved.
Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Computer, Inc.
("Apple") in consideration of your agreement to the following terms, and your
use, installation, modification or redistribution of this Apple software
constitutes acceptance of these terms. If you do not agree with these terms,
please do not use, install, modify or redistribute this Apple software.
In consideration of your agreement to abide by the following terms, and subject
to these terms, Apple grants you a personal, non-exclusive license, under Apple's
copyrights in this original Apple software (the "Apple Software"), to use,
reproduce, modify and redistribute the Apple Software, with or without
modifications, in source and/or binary forms; provided that if you redistribute
the Apple Software in its entirety and without modifications, you must retain
this notice and the following text and disclaimers in all such redistributions of
the Apple Software. Neither the name, trademarks, service marks or logos of
Apple Computer, Inc. may be used to endorse or promote products derived from the
Apple Software without specific prior written permission from Apple. Except as
expressly stated in this notice, no other rights or licenses, express or implied,
are granted by Apple herein, including but not limited to any patent rights that
may be infringed by your derivative works or by other works in which the Apple
Software may be incorporated.
The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO
WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN
COMBINATION WITH YOUR PRODUCTS.
IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION
OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT
(INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Change History (most recent first):
$Log$
Revision 1.1 2003/10/23 21:43:01 ron
Add Apple mDNS reponder
Revision 1.10 2002/09/21 20:44:49 zarzycki
Added APSL info
Revision 1.9 2002/09/19 04:20:43 cheshire
Remove high-ascii characters that confuse some systems
Revision 1.8 2002/09/16 23:12:14 cheshire
Minor code tidying
Revision 1.7 2002/09/16 18:41:42 cheshire
Merge in license terms from Quinn's copy, in preparation for Darwin release
*/
#ifndef __mDNSPlatformFunctions_h
#define __mDNSPlatformFunctions_h
// ***************************************************************************
// Support functions which must be provided by each set of specific PlatformSupport files
// mDNSPlatformInit() typically opens a communication endpoint, and starts listening for mDNS packets.
// When Setup is complete, the callback is called.
// mDNSPlatformSendUDP() sends one UDP packet
// When a packet is received, the PlatformSupport code calls mDNSCoreReceive()
// mDNSPlatformScheduleTask() indicates that a timer should be set,
// and mDNSCoreTask() should be called when the timer expires
// mDNSPlatformClose() tidies up on exit
#ifdef __cplusplus
extern "C" {
#endif
// ***************************************************************************
// DNS protocol message format
typedef struct
{
mDNSOpaque16 id;
mDNSOpaque16 flags;
mDNSu16 numQuestions;
mDNSu16 numAnswers;
mDNSu16 numAuthorities;
mDNSu16 numAdditionals;
} DNSMessageHeader;
// We can send and receive packets up to 9000 bytes (Ethernet Jumbo Frame size, if that ever becomes widely used)
// However, in the normal case we try to limit packets to 1500 bytes so that we don't get IP fragmentation on standard Ethernet
#define AbsoluteMaxDNSMessageData 8960
#define NormalMaxDNSMessageData 1460
typedef struct
{
DNSMessageHeader h; // Note: Size 12 bytes
mDNSu8 data[AbsoluteMaxDNSMessageData]; // 20 (IP) + 8 (UDP) + 12 (header) + 8960 (data) = 9000
} DNSMessage;
// ***************************************************************************
// Functions
// Every platform support module must provide the following functions
extern mStatus mDNSPlatformInit (mDNS *const m);
extern void mDNSPlatformClose (mDNS *const m);
extern mStatus mDNSPlatformSendUDP(const mDNS *const m, const DNSMessage *const msg, const mDNSu8 *const end,
mDNSIPAddr src, mDNSIPPort srcport, mDNSIPAddr dst, mDNSIPPort dstport);
extern mDNSs32 mDNSPlatformOneSecond;
extern mDNSs32 mDNSPlatformTimeNow();
extern void mDNSPlatformScheduleTask(const mDNS *const m, mDNSs32 NextTaskTime);
extern void mDNSPlatformLock (const mDNS *const m);
extern void mDNSPlatformUnlock (const mDNS *const m);
extern void mDNSPlatformStrCopy(const void *src, void *dst);
extern mDNSu32 mDNSPlatformStrLen (const void *src);
extern void mDNSPlatformMemCopy(const void *src, void *dst, mDNSu32 len);
extern mDNSBool mDNSPlatformMemSame(const void *src, const void *dst, mDNSu32 len);
extern void mDNSPlatformMemZero( void *dst, mDNSu32 len);
// The core mDNS code provides these functions, for the platform support code to call at appropriate times
extern void mDNSCoreInitComplete(mDNS *const m, mStatus result);
extern void mDNSCoreReceive(mDNS *const m, DNSMessage *const msg, const mDNSu8 *const end,
mDNSIPAddr srcaddr, mDNSIPPort srcport, mDNSIPAddr dstaddr, mDNSIPPort dstport, mDNSIPAddr InterfaceAddr);
extern void mDNSCoreTask (mDNS *const m);
extern void mDNSCoreSleep (mDNS *const m, mDNSBool wake);
#ifdef __cplusplus
}
#endif
#endif

890
src/mdns/mDNSPosix.c Executable file
View File

@ -0,0 +1,890 @@
/*
* Copyright (c) 2002 Apple Computer, Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* The contents of this file constitute Original Code as defined in and
* are subject to the Apple Public Source License Version 1.2 (the
* "License"). You may not use this file except in compliance with the
* License. Please obtain a copy of the License at
* http://www.apple.com/publicsource and read it before using this file.
*
* This 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 OR NON-INFRINGEMENT. Please see the
* License for the specific language governing rights and limitations
* under the License.
*
* @APPLE_LICENSE_HEADER_END@
Change History (most recent first):
$Log$
Revision 1.1 2003/10/23 21:43:01 ron
Add Apple mDNS reponder
Revision 1.3 2002/09/21 20:44:53 zarzycki
Added APSL info
Revision 1.2 2002/09/19 21:25:36 cheshire
mDNS_sprintf() doesn't need to be in a separate file
Revision 1.1 2002/09/17 06:24:34 cheshire
First checkin
*/
#include "mDNSClientAPI.h" // Defines the interface provided to the client layer above
#include "mDNSPlatformFunctions.h" // Defines the interface to the supporting layer below
#include "mDNSPosix.h" // Defines the specific types needed to run mDNS on this platform
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/uio.h>
#include <netinet/in.h>
#include "err.h"
#include "mDNSUNP.h"
// ***************************************************************************
// Structures
// PosixNetworkInterface is a record extension of the core NetworkInterfaceInfo
// type that supports extra fields needed by the Posix platform.
//
// IMPORTANT: coreIntf must be the first field in the structure because
// we cast between pointers to the two different types regularly.
typedef struct PosixNetworkInterface PosixNetworkInterface;
struct PosixNetworkInterface {
NetworkInterfaceInfo coreIntf;
const char * intfName;
PosixNetworkInterface * aliasIntf;
int index;
int multicastSocket;
};
// ***************************************************************************
// Functions
int gMDNSPlatformPosixVerboseLevel = 0;
// Note, this uses mDNS_vsprintf instead of standard "vsprintf", because mDNS_vsprintf knows
// how to print special data types like IP addresses and length-prefixed domain names
mDNSexport void debugf_(const char *format, ...)
{
unsigned char buffer[512];
va_list ptr;
va_start(ptr,format);
buffer[mDNS_vsprintf((char *)buffer, format, ptr)] = 0;
va_end(ptr);
DPRINTF(ERR_INFO,"%s\n",buffer);
}
mDNSexport void verbosedebugf_(const char *format, ...)
{
unsigned char buffer[512];
va_list ptr;
va_start(ptr,format);
buffer[mDNS_vsprintf((char *)buffer, format, ptr)] = 0;
va_end(ptr);
DPRINTF(ERR_DEBUG,"%s\n",buffer);
}
static mStatus PosixErrorToStatus(int errNum)
// For the moment we map all Posix errors to mStatus_UnknownErr. Ultimately
// it would probably be a good idea to map them to their appropriate mStatus
// value.
{
mStatus result;
if (errNum == 0) {
result = mStatus_NoError;
} else {
result = mStatus_UnknownErr;
}
return result;
}
#pragma mark ***** Send and Receive
mDNSexport mStatus mDNSPlatformSendUDP(const mDNS *const m, const DNSMessage *const msg, const mDNSu8 *const end,
mDNSIPAddr src, mDNSIPPort srcPort, mDNSIPAddr dst, mDNSIPPort dstPort)
// mDNS core calls this routine when it needs to send a packet.
{
int err;
struct sockaddr_in to;
PosixNetworkInterface * thisIntf;
assert(m != NULL);
assert(msg != NULL);
assert(end != NULL);
assert( (((char *) end) - ((char *) msg)) > 0 );
assert(src.NotAnInteger != 0); // Can't send from zero source address
assert(srcPort.NotAnInteger != 0); // Nor from a zero source port
assert(dstPort.NotAnInteger != 0); // Nor from a zero source port
to.sin_family = AF_INET;
to.sin_port = dstPort.NotAnInteger;
to.sin_addr.s_addr = dst. NotAnInteger;
// Loop through all the interfaces looking for one whose address
// matches the source address, and send on that.
err = 0;
thisIntf = (PosixNetworkInterface *)(m->HostInterfaces);
while (thisIntf && err == 0) {
if (thisIntf->coreIntf.ip.NotAnInteger == src.NotAnInteger) {
err = sendto(thisIntf->multicastSocket,
msg, (char*)end - (char*)msg,
0, // flags
(struct sockaddr *)&to, sizeof(to));
if (err > 0) {
err = 0;
} else if (err < 0) {
verbosedebugf("mDNSPlatformSendUDP got error %d (%s) sending packet to %.4a on interface %.4a/%s/%d",
errno, strerror(errno), &dst, &thisIntf->coreIntf.ip, thisIntf->intfName, thisIntf->index);
}
}
thisIntf = (PosixNetworkInterface *)(thisIntf->coreIntf.next);
}
return PosixErrorToStatus(err);
}
static void SocketDataReady(mDNS *const m, PosixNetworkInterface *intf, int skt)
// This routine is called where the main loop detects that
// data is available on a socket.
{
mDNSIPAddr intfAddr;
mDNSIPAddr senderAddr, destAddr;
mDNSIPPort senderPort;
ssize_t packetLen;
DNSMessage packet;
struct my_in_pktinfo packetInfo;
struct sockaddr_in from;
socklen_t fromLen;
int flags;
mDNSBool reject;
assert(m != NULL);
assert(intf != NULL);
assert(skt >= 0);
fromLen = sizeof(from);
flags = 0;
packetLen = recvfrom_flags(skt, &packet, sizeof(packet), &flags,
(struct sockaddr *) &from, &fromLen,
&packetInfo);
if (packetLen >= 0) {
assert(fromLen == sizeof(from));
intfAddr = intf->coreIntf.ip;
senderAddr.NotAnInteger = from.sin_addr.s_addr;
senderPort.NotAnInteger = from.sin_port;
destAddr.NotAnInteger = packetInfo.ipi_addr.s_addr;
// If we have broken IP_RECVDSTADDR functionality (so far
// I've only seen this on OpenBSD) then apply a hack to
// convince mDNS Core that this isn't a spoof packet.
// Basically what we do is check to see whether the
// packet arrived as a multicast and, if so, set its
// destAddr to the mDNS address.
//
// I must admit that I could just be doing something
// wrong on OpenBSD and hence triggering this problem
// but I'm at a loss as to how.
#if HAVE_BROKEN_RECVDSTADDR
if ( (destAddr.NotAnInteger == 0) && (flags & MSG_MCAST) ) {
destAddr.NotAnInteger = AllDNSLinkGroup.NotAnInteger;
}
#endif
// We only accept the packet if the interface on which it came
// in matches the interface associated with this socket.
// We do this match by name or by index, depending on which
// information is available. recvfrom_flags sets the name
// to "" if the name isn't available, or the index to -1
// if the index is available. This accomodates the various
// different capabilities of our target platforms.
reject = mDNSfalse;
if ( packetInfo.ipi_ifname[0] != 0 ) {
reject = (strcmp(packetInfo.ipi_ifname, intf->intfName) != 0);
} else if ( packetInfo.ipi_ifindex != -1 ) {
reject = (packetInfo.ipi_ifindex != intf->index);
}
if (reject) {
debugf("SocketDataReady ignored a packet from %.4a to %.4a on interface %s/%d expecting %.4a/%s/%d",
&senderAddr, &destAddr, packetInfo.ipi_ifname, packetInfo.ipi_ifindex, &intf->coreIntf.ip, intf->intfName, intf->index);
packetLen = -1;
} else {
verbosedebugf("SocketDataReady got a packet from %.4a to %.4a on interface %.4a/%s/%d",
&senderAddr, &destAddr, &intf->coreIntf.ip, intf->intfName, intf->index);
}
}
if (packetLen >= 0 && packetLen < sizeof(DNSMessageHeader)) {
debugf("SocketDataReady packet length (%d) too short", packetLen);
packetLen = -1;
}
if (packetLen >= 0) {
mDNSCoreReceive(m,
&packet, (mDNSu8 *)&packet + packetLen,
senderAddr, senderPort,
destAddr, MulticastDNSPort,
intf->coreIntf.ip);
}
}
#pragma mark ***** Init and Term
// On OS X this gets the text of the field labelled "Computer Name" in the Sharing Prefs Control Panel
// Other platforms can either get the information from the appropriate place,
// or they can alternatively just require all registering services to provide an explicit name
mDNSlocal void GetUserSpecifiedFriendlyComputerName(domainlabel *const namelabel)
{
ConvertCStringToDomainLabel("Fill in Default Service Name Here", namelabel);
}
// This gets the current hostname, truncating it at the first dot if necessary
mDNSlocal void GetUserSpecifiedRFC1034ComputerName(domainlabel *const namelabel)
{
int len = 0;
gethostname(&namelabel->c[1], MAX_DOMAIN_LABEL);
while (len < MAX_DOMAIN_LABEL && namelabel->c[len+1] && namelabel->c[len+1] != '.') len++;
namelabel->c[0] = len;
}
static PosixNetworkInterface *SearchForInterfaceByName(mDNS *const m, const char *intfName)
// Searches the interface list looking for the named interface.
// Returns a pointer to if it found, or NULL otherwise.
{
PosixNetworkInterface *intf;
assert(m != NULL);
assert(intfName != NULL);
intf = (PosixNetworkInterface*)(m->HostInterfaces);
while ( (intf != NULL) && (strcmp(intf->intfName, intfName) != 0) ) {
intf = (PosixNetworkInterface *)(intf->coreIntf.next);
}
return intf;
}
static void FreePosixNetworkInterface(PosixNetworkInterface *intf)
// Frees the specified PosixNetworkInterface structure.
// The underlying interface must have already been
// deregistered with the mDNS core.
{
int junk;
assert(intf != NULL);
if (intf->intfName != NULL) {
free( (void *) intf->intfName);
}
if (intf->multicastSocket != -1) {
junk = close(intf->multicastSocket);
assert(junk == 0);
}
free(intf);
}
static void ClearInterfaceList(mDNS *const m)
{
// Grab the first interface, deregister it, free it, and
// repeat until done.
assert(m != NULL);
while (m->HostInterfaces) {
PosixNetworkInterface *intf;
intf = (PosixNetworkInterface*)(m->HostInterfaces);
mDNS_DeregisterInterface(m, &intf->coreIntf);
if (gMDNSPlatformPosixVerboseLevel > 0) {
fprintf(stderr, "Deregistered interface %s\n", intf->intfName);
}
FreePosixNetworkInterface(intf);
}
}
static int SetupSocket(struct sockaddr_in *intfAddr, mDNSIPPort port, int *sktPtr)
// Sets up a multicast send/receive socket for the specified
// port on the interface specified by the IP addrelss intfAddr.
{
int err;
int junk;
struct ip_mreq imr;
struct sockaddr_in bindAddr;
static const int kOn = 1;
static const int kIntTwoFiveFive = 255;
static const unsigned char kByteTwoFiveFive = 255;
assert(intfAddr != NULL);
assert(sktPtr != NULL);
assert(*sktPtr == -1);
// Open the socket...
err = 0;
*sktPtr = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (*sktPtr < 0) {
err = errno;
perror("socket");
}
// ... with a shared UDP port
if (err == 0) {
#if defined(SO_REUSEPORT)
err = setsockopt(*sktPtr, SOL_SOCKET, SO_REUSEPORT, &kOn, sizeof(kOn));
#elif defined(SO_REUSEADDR)
err = setsockopt(*sktPtr, SOL_SOCKET, SO_REUSEADDR, &kOn, sizeof(kOn));
#else
#error This platform has no way to avoid address busy errors on multicast.
#endif
if (err < 0) {
err = errno;
perror("setsockopt - SO_REUSExxxx");
}
}
// We want to receive destination addresses and interface identifiers.
if (err == 0) {
#if defined(IP_PKTINFO)
// Linux
err = setsockopt(*sktPtr, IPPROTO_IP, IP_PKTINFO, &kOn, sizeof(kOn));
if (err < 0) {
err = errno;
perror("setsockopt - IP_PKTINFO");
}
#elif defined(IP_RECVDSTADDR) || defined(IP_RECVIF)
// BSD and Solaris
#if defined(IP_RECVDSTADDR)
err = setsockopt(*sktPtr, IPPROTO_IP, IP_RECVDSTADDR, &kOn, sizeof(kOn));
if (err < 0) {
err = errno;
perror("setsockopt - IP_RECVDSTADDR");
}
#endif
#if defined(IP_RECVIF)
if (err == 0) {
err = setsockopt(*sktPtr, IPPROTO_IP, IP_RECVIF, &kOn, sizeof(kOn));
if (err < 0) {
err = errno;
perror("setsockopt - IP_RECVIF");
}
}
#endif
#else
#error This platform has no way to get the destination interface information.
#endif
}
// Add multicast group membership on this interface
if (err == 0) {
imr.imr_multiaddr.s_addr = AllDNSLinkGroup.NotAnInteger;
imr.imr_interface = intfAddr->sin_addr;
err = setsockopt(*sktPtr, IPPROTO_IP, IP_ADD_MEMBERSHIP, &imr, sizeof(imr));
if (err < 0) {
err = errno;
perror("setsockopt - IP_ADD_MEMBERSHIP");
}
}
// Specify outgoing interface too
if (err == 0) {
err = setsockopt(*sktPtr, IPPROTO_IP, IP_MULTICAST_IF, &intfAddr->sin_addr, sizeof(intfAddr->sin_addr));
if (err < 0) {
err = errno;
perror("setsockopt - IP_MULTICAST_IF");
}
}
// Per the mDNS spec, send unicast packets with TTL 255
if (err == 0) {
err = setsockopt(*sktPtr, IPPROTO_IP, IP_TTL, &kIntTwoFiveFive, sizeof(kIntTwoFiveFive));
if (err < 0) {
err = errno;
perror("setsockopt - IP_TTL");
}
}
// and multicast packets with TTL 255 too
// There's some debate as to whether IP_MULTICAST_TTL is an int or a byte
// so we just try both.
if (err == 0) {
err = setsockopt(*sktPtr, IPPROTO_IP, IP_MULTICAST_TTL,
&kByteTwoFiveFive, sizeof(kByteTwoFiveFive));
if (err < 0 && errno == EINVAL) {
err = setsockopt(*sktPtr, IPPROTO_IP, IP_MULTICAST_TTL,
&kIntTwoFiveFive, sizeof(kIntTwoFiveFive));
}
if (err < 0) {
err = errno;
perror("setsockopt - IP_MULTICAST_TTL");
}
}
// And start listening for packets
if (err == 0) {
bindAddr.sin_family = AF_INET;
bindAddr.sin_port = port.NotAnInteger;
bindAddr.sin_addr.s_addr = 0; // Want to receive multicasts AND unicasts on this socket
err = bind(*sktPtr, (struct sockaddr *) &bindAddr, sizeof(bindAddr));
if (err < 0) {
err = errno;
perror("bind");
fflush(stderr);
}
}
// Set the socket to non-blocking.
if (err == 0) {
err = fcntl(*sktPtr, F_GETFL, 0);
if (err < 0) {
err = errno;
} else {
err = fcntl(*sktPtr, F_SETFL, err | O_NONBLOCK);
if (err < 0) {
err = errno;
}
}
}
// Clean up
if (err != 0 && *sktPtr != -1) {
junk = close(*sktPtr);
assert(junk == 0);
*sktPtr = -1;
}
assert( (err == 0) == (*sktPtr != -1) );
return err;
}
static int SetupOneInterface(mDNS *const m, struct sockaddr_in *intfAddr, const char *intfName, int index)
// Creates a PosixNetworkInterface for the interface whose
// IP address is intfAddr and whose name is intfName
// and registers it with mDNS core.
{
int err = 0;
PosixNetworkInterface *intf;
assert(m != NULL);
assert(intfAddr != NULL);
assert(intfName != NULL);
// Allocate the interface structure itself.
err = 0;
intf = malloc(sizeof(*intf));
if (intf == NULL) {
assert(0); // this is bad
err = ENOMEM;
}
// And make a copy of the intfName.
if (err == 0) {
intf->intfName = strdup(intfName);
if (intf->intfName == NULL) {
assert(0); // this is bad
err = ENOMEM;
}
}
if (err == 0) {
// Set up the fields required by the mDNS core.
intf->coreIntf.ip.NotAnInteger = intfAddr->sin_addr.s_addr;
intf->coreIntf.Advertise = m->AdvertiseLocalAddresses;
// Set up the extra fields in PosixNetworkInterface.
assert(intf->intfName != NULL); // intf->intfName already set up above
intf->aliasIntf = SearchForInterfaceByName(m, intf->intfName);
intf->index = index;
intf->multicastSocket = -1;
if (intf->aliasIntf) {
debugf("SetupOneInterface: %s %.4a is an alias of %.4a",
intfName, &intf->coreIntf.ip, &intf->aliasIntf->coreIntf.ip);
}
}
// Set up the multicast socket
if (err == 0) {
err = SetupSocket(intfAddr, MulticastDNSPort, &intf->multicastSocket);
}
// The interface is all ready to go, let's register it with the mDNS core.
if (err == 0) {
err = mDNS_RegisterInterface(m, &intf->coreIntf);
}
// Clean up.
if (err == 0) {
debugf("SetupOneInterface: %s %.4a Registered", intf->intfName, &intf->coreIntf.ip);
if (gMDNSPlatformPosixVerboseLevel > 0) {
fprintf(stderr, "Registered interface %s\n", intf->intfName);
}
} else {
// Use intfName instead of intf->intfName in the next line to avoid
// dereferencing NULL.
debugf("SetupOneInterface: %s %.4a failed to register %d", intfName, &intfAddr->sin_addr, err);
if (intf != NULL) {
FreePosixNetworkInterface(intf);
intf = NULL;
}
}
assert( (err == 0) == (intf != NULL) );
return err;
}
static int SetupInterfaceList(mDNS *const m)
{
int err;
struct ifi_info *intfList;
struct ifi_info *thisIntf;
struct ifi_info *firstLoopbackIntf;
assert(m != NULL);
debugf("SetupInterfaceList");
err = 0;
intfList = get_ifi_info(AF_INET, mDNStrue);
if (intfList == NULL) {
debugf("No interfaces present?");
err = ENOENT;
}
if (err == 0) {
debugf("Rolling through interfaces");
firstLoopbackIntf = NULL;
thisIntf = intfList;
while (thisIntf != NULL) {
debugf("Checking %s",thisIntf->ifi_name);
if ( (thisIntf->ifi_addr->sa_family == AF_INET)
&& (thisIntf->ifi_flags & IFF_UP) ) {
// The Mac OS X code also avoids interfaces with the
// IFF_POINTOPOINT flag set. This prevents nuisance phone
// calls when dial-on-demand is enabled. I specifically didn't
// pull in this feature because most UNIX hosts don't use
// PPP dial-on-demand. If you nee this you should add
// the conditional:
//
// && !(thisIntf->ifi_flags & IFF_POINTOPOINT)
//
// to the above "if" statement.
if (thisIntf->ifi_flags & IFF_LOOPBACK) {
if (firstLoopbackIntf == NULL) {
firstLoopbackIntf = thisIntf;
}
} else {
// We ignore any errors from SetupOneInterface because we want the
// program to continue to run on any other interfaces and
// SetupOneInterface has already printed an appropriate diagnostic
// message.
(void) SetupOneInterface(m,
(struct sockaddr_in *) thisIntf->ifi_addr,
thisIntf->ifi_name,
thisIntf->ifi_index);
}
}
thisIntf = thisIntf->ifi_next;
}
// If we found no normal interfaces but we did find a loopback
// interface, register the loopback interface. This allows self-
// discovery if no interfaces are configured. Note that this
// still doesn't work on Mac OS X 10.2 and earlier, for reasons
// that are still being investigated [Radar ID 3016042].
if ( (m->HostInterfaces == NULL) && (firstLoopbackIntf != NULL) ) {
(void) SetupOneInterface(m,
(struct sockaddr_in *) firstLoopbackIntf->ifi_addr,
firstLoopbackIntf->ifi_name,
firstLoopbackIntf->ifi_index);
}
}
// Clean up.
if (intfList != NULL) {
free_ifi_info(intfList);
}
return err;
}
mDNSexport mStatus mDNSPlatformInit(mDNS *const m)
// mDNS core calls this routine to initialise the platform-
// specific data.
{
int err;
assert(m != NULL);
// Tell mDNS core the names of this machine.
// Set up the nice label
m->nicelabel.c[0] = 0;
GetUserSpecifiedFriendlyComputerName(&m->nicelabel);
if (m->nicelabel.c[0] == 0) ConvertCStringToDomainLabel("Macintosh", &m->nicelabel);
// Set up the RFC 1034-compliant label
m->hostlabel.c[0] = 0;
GetUserSpecifiedRFC1034ComputerName(&m->hostlabel);
if (m->hostlabel.c[0] == 0) ConvertCStringToDomainLabel("Macintosh", &m->hostlabel);
mDNS_GenerateFQDN(m);
// Tell mDNS core about the network interfaces on this machine.
err = SetupInterfaceList(m);
if(err) {
DPRINTF(ERR_WARN,"Error in SetupInterfaceList: %s\n",strerror(errno));
}
// We don't do asynchronous initialization on the Posix platform, so by the time
// we get here the setup will already have succeeded or failed. If it succeeded,
// we should just call mDNSCoreInitComplete() immediately.
if (err == 0)
mDNSCoreInitComplete(m, mStatus_NoError);
return PosixErrorToStatus(err);
}
mDNSexport void mDNSPlatformClose(mDNS *const m)
// mDNS core calls this routine to clean up the platform-specific
// data. In our case all we need to do is to tear down every
// network interface.
{
assert(m != NULL);
ClearInterfaceList(m);
}
extern mStatus mDNSPlatformPosixRefreshInterfaceList(mDNS *const m)
{
int err;
ClearInterfaceList(m);
err = SetupInterfaceList(m);
return PosixErrorToStatus(err);
}
#pragma mark ***** Locking
// On the Posix platform, locking is a no-op because we only ever enter
// mDNS core on the main thread.
mDNSexport void mDNSPlatformLock (const mDNS *const m)
// mDNS core calls this routine when it wants to prevent
// the platform from reentering mDNS core code.
{
#pragma unused(m)
}
mDNSexport void mDNSPlatformUnlock (const mDNS *const m)
// mDNS core calls this routine when it release the lock
// taken by mDNSPlatformLock and allow the platform to
// reenter mDNS core code.
{
#pragma unused(m)
}
#pragma mark ***** Strings
mDNSexport void mDNSPlatformStrCopy(const void *src, void *dst)
// mDNS core calls this routine to copy C strings.
// On the Posix platform this maps directly to the
// ANSI C strcpy.
{
strcpy((char *)dst, (char *)src);
}
mDNSexport mDNSu32 mDNSPlatformStrLen (const void *src)
// mDNS core calls this routine to get the length of a C string.
// On the Posix platform this maps directly to the ANSI C strlen.
{
return strlen((char*)src);
}
mDNSexport void mDNSPlatformMemCopy(const void *src, void *dst, mDNSu32 len)
// mDNS core calls this routine to copy memory.
// On the Posix platform this maps directly to the
// ANSI C memcpy.
{
memcpy(dst, src, len);
}
mDNSexport mDNSBool mDNSPlatformMemSame(const void *src, const void *dst, mDNSu32 len)
// mDNS core calls this routine to test whether blocks
// of memory are byte-for-byte identical.
// On the Posix platform this is a simple wrapper around
// ANSI C memcmp.
{
return memcmp(dst, src, len) == 0;
}
mDNSexport void mDNSPlatformMemZero( void *dst, mDNSu32 len)
// mDNS core calls this routine to clear blocks of memory.
// On the Posix platform this is a simple wrapper around
// ANSI C memset.
{
memset(dst, 0, len);
}
mDNSexport mDNSs32 mDNSPlatformOneSecond = 1024;
#define ConvertTV(X) ( ((X).tv_sec << 10) | ((X).tv_usec * 16 / 15625) )
mDNSexport mDNSs32 mDNSPlatformTimeNow()
{
struct timeval tv;
gettimeofday(&tv, NULL);
// tp.tv_sec is seconds since 1st January 1970 (GMT, with no adjustment for daylight savings time)
// tp.tv_usec is microseconds since the start of this second (i.e. values 0 to 999999)
// We use the lower 22 bits of tp.tv_sec for the top 22 bits of our result
// and we multiply tp.tv_usec by 16 / 15625 to get a value in the range 0-1023 to go in the bottom 10 bits.
// This gives us a proper modular (cyclic) counter that has a resolution of roughly 1ms (actually 1/1024 second)
// and correctly cycles every 2^22 seconds (4194304 seconds = approx 48 days).
return(ConvertTV(tv));
}
mDNSexport void mDNSPlatformScheduleTask(const mDNS *const m, mDNSs32 nextTaskTime)
// mDNS core calls this routine to tell the platform when it should next
// give time to the core by calling mDNSCoreTask. nextTaskTime is the
// time at which the platform should call mDNSCoreTask. This time
// supercedes any previous times set by this routine. The time is
// in platform time units; there are mDNSPlatformOneSecond platform
// time units per second. The time is an absolute time, derived by
// adding N platform time units to the value returned by
// mDNSPlatformTimeNow. Note that the time might be in the past,
// in which case the platform should call mDNSCoreTask as soon as
// possible. Also note that the quantity is a signed 32 bit number
// and thus it's quite possible that it'll wrap during the life time
// of the platform. mDNS core handles this perfectly, and so should
// your platform.
{
mDNSs32 delta;
assert(m != NULL);
gettimeofday(&m->p->NextEvent, NULL); // Get time now
delta = nextTaskTime - ConvertTV(m->p->NextEvent); // Work out how many ticks from now to nextTaskTime
if (delta < 0) delta = 0;
m->p->NextEvent.tv_sec += (delta >> 10); // Convert that to a struct timeval
m->p->NextEvent.tv_usec += ((delta & 0x3FF) * 15625) / 16;
if (m->p->NextEvent.tv_usec >= 1000000) // Correct if we incremented tv_usec above one million
{
m->p->NextEvent.tv_usec -= 1000000;
m->p->NextEvent.tv_sec += 1;
}
}
mDNSexport void mDNSPosixGetFDSet(const mDNS *const m, int *nfds, fd_set *readfds, struct timeval *timeout)
{
PosixNetworkInterface *info = (PosixNetworkInterface *)(m->HostInterfaces);
struct timeval n = m->p->NextEvent, tp;
gettimeofday(&tp, NULL); // Get time now
// If we're already past NextEvent, then interval is zero
if (tp.tv_sec > n.tv_sec || ((tp.tv_sec == n.tv_sec && tp.tv_usec > n.tv_usec)))
tp.tv_sec = tp.tv_usec = 0;
else // else, interval is NextEvent minus timenow
{
if (n.tv_usec < tp.tv_usec)
{
n.tv_usec += 1000000;
n.tv_sec -= 1;
}
tp.tv_sec = n.tv_sec - tp.tv_sec;
tp.tv_usec = n.tv_usec - tp.tv_usec;
}
// If client's proposed timeout is more than what we want, then reduce it
if (timeout->tv_sec > tp.tv_sec ||
(timeout->tv_sec == tp.tv_sec && timeout->tv_usec > tp.tv_usec))
*timeout = tp;
while (info)
{
if (*nfds < info->multicastSocket + 1)
*nfds = info->multicastSocket + 1;
FD_SET(info->multicastSocket, readfds);
info = (PosixNetworkInterface *)(info->coreIntf.next);
}
}
mDNSexport void mDNSPosixProcessFDSet(mDNS *const m, int selectresult, fd_set *readfds)
{
assert(m != NULL);
assert(readfds != NULL);
if (selectresult == 0)
{
debugf("Timeout");
mDNSCoreTask(m);
}
else
{
PosixNetworkInterface *info = (PosixNetworkInterface *)(m->HostInterfaces);
debugf("Got a packet");
while (info)
{
if (FD_ISSET(info->multicastSocket, readfds))
{
FD_CLR(info->multicastSocket, readfds);
SocketDataReady(m, info, info->multicastSocket);
}
info = (PosixNetworkInterface *)(info->coreIntf.next);
}
}
}

116
src/mdns/mDNSPosix.h Executable file
View File

@ -0,0 +1,116 @@
/*
* Copyright (c) 2002 Apple Computer, Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* The contents of this file constitute Original Code as defined in and
* are subject to the Apple Public Source License Version 1.2 (the
* "License"). You may not use this file except in compliance with the
* License. Please obtain a copy of the License at
* http://www.apple.com/publicsource and read it before using this file.
*
* This 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 OR NON-INFRINGEMENT. Please see the
* License for the specific language governing rights and limitations
* under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
/*
File: mDNSPlatformPosix.h
Contains: Interface to the Posix platform code.
Written by: Quinn
Copyright: Copyright (c) 2002 by Apple Computer, Inc., All Rights Reserved.
Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Computer, Inc.
("Apple") in consideration of your agreement to the following terms, and your
use, installation, modification or redistribution of this Apple software
constitutes acceptance of these terms. If you do not agree with these terms,
please do not use, install, modify or redistribute this Apple software.
In consideration of your agreement to abide by the following terms, and subject
to these terms, Apple grants you a personal, non-exclusive license, under Apple's
copyrights in this original Apple software (the "Apple Software"), to use,
reproduce, modify and redistribute the Apple Software, with or without
modifications, in source and/or binary forms; provided that if you redistribute
the Apple Software in its entirety and without modifications, you must retain
this notice and the following text and disclaimers in all such redistributions of
the Apple Software. Neither the name, trademarks, service marks or logos of
Apple Computer, Inc. may be used to endorse or promote products derived from the
Apple Software without specific prior written permission from Apple. Except as
expressly stated in this notice, no other rights or licenses, express or implied,
are granted by Apple herein, including but not limited to any patent rights that
may be infringed by your derivative works or by other works in which the Apple
Software may be incorporated.
The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO
WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN
COMBINATION WITH YOUR PRODUCTS.
IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION
OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT
(INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Change History (most recent first):
$Log$
Revision 1.1 2003/10/23 21:43:01 ron
Add Apple mDNS reponder
Revision 1.3 2002/09/21 20:44:53 zarzycki
Added APSL info
Revision 1.2 2002/09/19 04:20:44 cheshire
Remove high-ascii characters that confuse some systems
Revision 1.1 2002/09/17 06:24:34 cheshire
First checkin
*/
#ifndef __mDNSPlatformPosix_h
#define __mDNSPlatformPosix_h
#include <sys/time.h>
#ifdef __cplusplus
extern "C" {
#endif
// This is a global because debugf_() needs to be able to check its value
extern int gMDNSPlatformPosixVerboseLevel;
struct mDNS_PlatformSupport_struct
{
struct timeval NextEvent;
};
extern mStatus mDNSPlatformPosixRefreshInterfaceList(mDNS *const m);
// See comment in implementation.
// Call mDNSPosixGetFDSet before calling select(), to update the parameters
// as may be necessary to meet the needs of the mDNSCore code.
// The timeout pointer MUST NOT be NULL.
// Set timeout->tv_sec to 0x3FFFFFFF if you want to have effectively no timeout
// After calling mDNSPosixGetFDSet(), call select(nfds, &readfds, NULL, NULL, &timeout); as usual
// After select() returns, call mDNSPosixProcessFDSet() to let mDNSCore do its work
extern void mDNSPosixGetFDSet(const mDNS *const m, int *nfds, fd_set *readfds, struct timeval *timeout);
extern void mDNSPosixProcessFDSet(mDNS *const m, int selectresult, fd_set *readfds);
#ifdef __cplusplus
}
#endif
#endif

420
src/mdns/mDNSUNP.c Executable file
View File

@ -0,0 +1,420 @@
/*
* Copyright (c) 2002 Apple Computer, Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* The contents of this file constitute Original Code as defined in and
* are subject to the Apple Public Source License Version 1.2 (the
* "License"). You may not use this file except in compliance with the
* License. Please obtain a copy of the License at
* http://www.apple.com/publicsource and read it before using this file.
*
* This 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 OR NON-INFRINGEMENT. Please see the
* License for the specific language governing rights and limitations
* under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
/*
File: mDNSUNP.c
Contains: Code derived from "UNIX Network Programming".
Written by: Quinn
Copyright: Copyright (c) 2002 by Apple Computer, Inc., All Rights Reserved.
Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Computer, Inc.
("Apple") in consideration of your agreement to the following terms, and your
use, installation, modification or redistribution of this Apple software
constitutes acceptance of these terms. If you do not agree with these terms,
please do not use, install, modify or redistribute this Apple software.
In consideration of your agreement to abide by the following terms, and subject
to these terms, Apple grants you a personal, non-exclusive license, under Apple's
copyrights in this original Apple software (the "Apple Software"), to use,
reproduce, modify and redistribute the Apple Software, with or without
modifications, in source and/or binary forms; provided that if you redistribute
the Apple Software in its entirety and without modifications, you must retain
this notice and the following text and disclaimers in all such redistributions of
the Apple Software. Neither the name, trademarks, service marks or logos of
Apple Computer, Inc. may be used to endorse or promote products derived from the
Apple Software without specific prior written permission from Apple. Except as
expressly stated in this notice, no other rights or licenses, express or implied,
are granted by Apple herein, including but not limited to any patent rights that
may be infringed by your derivative works or by other works in which the Apple
Software may be incorporated.
The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO
WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN
COMBINATION WITH YOUR PRODUCTS.
IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION
OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT
(INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Change History (most recent first):
$Log$
Revision 1.1 2003/10/23 21:43:01 ron
Add Apple mDNS reponder
Revision 1.3 2002/09/21 20:44:53 zarzycki
Added APSL info
Revision 1.2 2002/09/19 04:20:44 cheshire
Remove high-ascii characters that confuse some systems
Revision 1.1 2002/09/17 06:24:34 cheshire
First checkin
*/
#include "mDNSUNP.h"
#include <errno.h>
#include <assert.h>
#include <string.h>
#include <stdlib.h>
#include <sys/uio.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <stdio.h>
#include "err.h"
/* Solaris defined SIOCGIFCONF etc in <sys/sockio.h> but
other platforms don't even have that include file. So,
if we haven't yet got a definition, let's try to find
<sys/sockio.h>.
*/
#ifndef SIOCGIFCONF
#include <sys/sockio.h>
#endif
/* sockaddr_dl is only referenced if we're using IP_RECVIF,
so only include the header in that case.
*/
#ifdef IP_RECVIF
#include <net/if_dl.h>
#endif
#define max(a,b) ((a) > (b) ? (a) : (b))
struct ifi_info *get_ifi_info(int family, int doaliases)
{
int junk;
struct ifi_info *ifi, *ifihead, **ifipnext;
int sockfd, len, lastlen, flags, myflags;
char *ptr, *buf, lastname[IFNAMSIZ], *cptr;
struct ifconf ifc;
struct ifreq *ifr, ifrcopy;
struct sockaddr_in *sinptr;
int index;
index = 0;
sockfd = -1;
buf = NULL;
ifihead = NULL;
sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if (sockfd < 0) {
goto gotError;
}
lastlen = 0;
len = 100 * sizeof(struct ifreq); /* initial buffer size guess */
for ( ; ; ) {
buf = malloc(len);
if (buf == NULL) {
goto gotError;
}
ifc.ifc_len = len;
ifc.ifc_buf = buf;
if (ioctl(sockfd, SIOCGIFCONF, &ifc) < 0) {
if (errno != EINVAL || lastlen != 0) {
goto gotError;
}
} else {
if (ifc.ifc_len == lastlen)
break; /* success, len has not changed */
lastlen = ifc.ifc_len;
}
len += 10 * sizeof(struct ifreq); /* increment */
free(buf);
}
ifihead = NULL;
ifipnext = &ifihead;
lastname[0] = 0;
/* end get_ifi_info1 */
/* include get_ifi_info2 */
for (ptr = buf; ptr < buf + ifc.ifc_len; ) {
ifr = (struct ifreq *) ptr;
#ifdef HAVE_SOCKADDR_SA_LEN
len = max(sizeof(struct sockaddr), ifr->ifr_addr.sa_len);
#else
switch (ifr->ifr_addr.sa_family) {
#ifdef IPV6
case AF_INET6:
len = sizeof(struct sockaddr_in6);
break;
#endif
case AF_INET:
default:
len = sizeof(struct sockaddr);
break;
}
#endif /* HAVE_SOCKADDR_SA_LEN */
ptr += sizeof(ifr->ifr_name) + len; /* for next one in buffer */
DPRINTF(ERR_DEBUG,"intf %d name=%s AF=%d", index, ifr->ifr_name,
ifr->ifr_addr.sa_family);
if (ifr->ifr_addr.sa_family != family)
continue; /* ignore if not desired address family */
myflags = 0;
if ( (cptr = strchr(ifr->ifr_name, ':')) != NULL)
*cptr = 0; /* replace colon will null */
if (strncmp(lastname, ifr->ifr_name, IFNAMSIZ) == 0) {
if (doaliases == 0)
continue; /* already processed this interface */
myflags = IFI_ALIAS;
}
memcpy(lastname, ifr->ifr_name, IFNAMSIZ);
ifrcopy = *ifr;
if (ioctl(sockfd, SIOCGIFFLAGS, &ifrcopy) < 0) {
goto gotError;
}
flags = ifrcopy.ifr_flags;
if ((flags & IFF_UP) == 0)
continue; /* ignore if interface not up */
ifi = calloc(1, sizeof(struct ifi_info));
if (ifi == NULL) {
goto gotError;
}
*ifipnext = ifi; /* prev points to this new one */
ifipnext = &ifi->ifi_next; /* pointer to next one goes here */
ifi->ifi_flags = flags; /* IFF_xxx values */
ifi->ifi_myflags = myflags; /* IFI_xxx values */
index += 1;
ifi->ifi_index = index;
memcpy(ifi->ifi_name, ifr->ifr_name, IFI_NAME);
ifi->ifi_name[IFI_NAME-1] = '\0';
/* end get_ifi_info2 */
/* include get_ifi_info3 */
switch (ifr->ifr_addr.sa_family) {
case AF_INET:
sinptr = (struct sockaddr_in *) &ifr->ifr_addr;
if (ifi->ifi_addr == NULL) {
ifi->ifi_addr = calloc(1, sizeof(struct sockaddr_in));
if (ifi->ifi_addr == NULL) {
goto gotError;
}
memcpy(ifi->ifi_addr, sinptr, sizeof(struct sockaddr_in));
#ifdef SIOCGIFBRDADDR
if (flags & IFF_BROADCAST) {
if (ioctl(sockfd, SIOCGIFBRDADDR, &ifrcopy) < 0) {
goto gotError;
}
sinptr = (struct sockaddr_in *) &ifrcopy.ifr_broadaddr;
ifi->ifi_brdaddr = calloc(1, sizeof(struct sockaddr_in));
if (ifi->ifi_brdaddr == NULL) {
goto gotError;
}
memcpy(ifi->ifi_brdaddr, sinptr, sizeof(struct sockaddr_in));
}
#endif
#ifdef SIOCGIFDSTADDR
if (flags & IFF_POINTOPOINT) {
if (ioctl(sockfd, SIOCGIFDSTADDR, &ifrcopy) < 0) {
goto gotError;
}
sinptr = (struct sockaddr_in *) &ifrcopy.ifr_dstaddr;
ifi->ifi_dstaddr = calloc(1, sizeof(struct sockaddr_in));
if (ifi->ifi_dstaddr == NULL) {
goto gotError;
}
memcpy(ifi->ifi_dstaddr, sinptr, sizeof(struct sockaddr_in));
}
#endif
}
break;
default:
break;
}
}
goto done;
gotError:
if (ifihead != NULL) {
free_ifi_info(ifihead);
ifihead = NULL;
}
done:
if (buf != NULL) {
free(buf);
}
if (sockfd != -1) {
junk = close(sockfd);
assert(junk == 0);
}
return(ifihead); /* pointer to first structure in linked list */
}
/* end get_ifi_info3 */
/* include free_ifi_info */
void
free_ifi_info(struct ifi_info *ifihead)
{
struct ifi_info *ifi, *ifinext;
for (ifi = ifihead; ifi != NULL; ifi = ifinext) {
if (ifi->ifi_addr != NULL)
free(ifi->ifi_addr);
if (ifi->ifi_brdaddr != NULL)
free(ifi->ifi_brdaddr);
if (ifi->ifi_dstaddr != NULL)
free(ifi->ifi_dstaddr);
ifinext = ifi->ifi_next; /* can't fetch ifi_next after free() */
free(ifi); /* the ifi_info{} itself */
}
}
/* end free_ifi_info */
ssize_t
recvfrom_flags(int fd, void *ptr, size_t nbytes, int *flagsp,
struct sockaddr *sa, socklen_t *salenptr, struct my_in_pktinfo *pktp)
{
struct msghdr msg;
struct iovec iov[1];
ssize_t n;
#ifdef HAVE_MSGHDR_MSG_CONTROL
struct cmsghdr *cmptr;
union {
struct cmsghdr cm;
char control[1024];
} control_un;
msg.msg_control = control_un.control;
msg.msg_controllen = sizeof(control_un.control);
msg.msg_flags = 0;
#else
memset(&msg, 0, sizeof(msg)); /* make certain msg_accrightslen = 0 */
#endif
msg.msg_name = (void *) sa;
msg.msg_namelen = *salenptr;
iov[0].iov_base = ptr;
iov[0].iov_len = nbytes;
msg.msg_iov = iov;
msg.msg_iovlen = 1;
if ( (n = recvmsg(fd, &msg, *flagsp)) < 0)
return(n);
*salenptr = msg.msg_namelen; /* pass back results */
if (pktp) {
/* 0.0.0.0, i/f = -1 */
/* We set the interface to -1 so that the caller can
tell whether we returned a meaningful value or
just some default. Previously this code just
set the value to 0, but I'm concerned that 0
might be a valid interface value.
*/
memset(pktp, 0, sizeof(struct my_in_pktinfo));
pktp->ipi_ifindex = -1;
}
/* end recvfrom_flags1 */
/* include recvfrom_flags2 */
#ifndef HAVE_MSGHDR_MSG_CONTROL
*flagsp = 0; /* pass back results */
return(n);
#else
*flagsp = msg.msg_flags; /* pass back results */
if (msg.msg_controllen < sizeof(struct cmsghdr) ||
(msg.msg_flags & MSG_CTRUNC) || pktp == NULL)
return(n);
for (cmptr = CMSG_FIRSTHDR(&msg); cmptr != NULL;
cmptr = CMSG_NXTHDR(&msg, cmptr)) {
#ifdef IP_PKTINFO
#if in_pktinfo_definition_is_missing
struct in_pktinfo
{
int ipi_ifindex;
struct in_addr ipi_spec_dst;
struct in_addr ipi_addr;
};
#endif
if (cmptr->cmsg_level == IPPROTO_IP &&
cmptr->cmsg_type == IP_PKTINFO) {
struct in_pktinfo *tmp;
tmp = (struct in_pktinfo *) CMSG_DATA(cmptr);
memcpy(&pktp->ipi_addr, &tmp->ipi_addr, sizeof(struct in_addr));
pktp->ipi_ifindex = tmp->ipi_ifindex;
continue;
}
#endif
#ifdef IP_RECVDSTADDR
if (cmptr->cmsg_level == IPPROTO_IP &&
cmptr->cmsg_type == IP_RECVDSTADDR) {
memcpy(&pktp->ipi_addr, CMSG_DATA(cmptr),
sizeof(struct in_addr));
continue;
}
#endif
#ifdef IP_RECVIF
if (cmptr->cmsg_level == IPPROTO_IP &&
cmptr->cmsg_type == IP_RECVIF) {
struct sockaddr_dl *sdl;
int nameLen;
sdl = (struct sockaddr_dl *) CMSG_DATA(cmptr);
pktp->ipi_ifindex = sdl->sdl_index;
nameLen = sdl->sdl_nlen;
if (nameLen > (IFI_NAME - 1)) {
nameLen = IFI_NAME - 1;
}
strncpy(pktp->ipi_ifname, sdl->sdl_data, nameLen);
assert(pktp->ipi_ifname[IFI_NAME - 1] == 0);
// null terminated because of memset above
continue;
}
#endif
assert(0); // unknown ancillary data
}
return(n);
#endif /* HAVE_MSGHDR_MSG_CONTROL */
}

135
src/mdns/mDNSUNP.h Executable file
View File

@ -0,0 +1,135 @@
/*
* Copyright (c) 2002 Apple Computer, Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* The contents of this file constitute Original Code as defined in and
* are subject to the Apple Public Source License Version 1.2 (the
* "License"). You may not use this file except in compliance with the
* License. Please obtain a copy of the License at
* http://www.apple.com/publicsource and read it before using this file.
*
* This 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 OR NON-INFRINGEMENT. Please see the
* License for the specific language governing rights and limitations
* under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
/*
File: mDNSUNP.h
Contains: Interface to code derived from "UNIX Network Programming".
Written by: Quinn
Copyright: Copyright (c) 2002 by Apple Computer, Inc., All Rights Reserved.
Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Computer, Inc.
("Apple") in consideration of your agreement to the following terms, and your
use, installation, modification or redistribution of this Apple software
constitutes acceptance of these terms. If you do not agree with these terms,
please do not use, install, modify or redistribute this Apple software.
In consideration of your agreement to abide by the following terms, and subject
to these terms, Apple grants you a personal, non-exclusive license, under Apple's
copyrights in this original Apple software (the "Apple Software"), to use,
reproduce, modify and redistribute the Apple Software, with or without
modifications, in source and/or binary forms; provided that if you redistribute
the Apple Software in its entirety and without modifications, you must retain
this notice and the following text and disclaimers in all such redistributions of
the Apple Software. Neither the name, trademarks, service marks or logos of
Apple Computer, Inc. may be used to endorse or promote products derived from the
Apple Software without specific prior written permission from Apple. Except as
expressly stated in this notice, no other rights or licenses, express or implied,
are granted by Apple herein, including but not limited to any patent rights that
may be infringed by your derivative works or by other works in which the Apple
Software may be incorporated.
The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO
WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN
COMBINATION WITH YOUR PRODUCTS.
IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION
OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT
(INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Change History (most recent first):
$Log$
Revision 1.1 2003/10/23 21:43:01 ron
Add Apple mDNS reponder
Revision 1.3 2002/09/21 20:44:53 zarzycki
Added APSL info
Revision 1.2 2002/09/19 04:20:44 cheshire
Remove high-ascii characters that confuse some systems
Revision 1.1 2002/09/17 06:24:35 cheshire
First checkin
*/
#ifndef __mDNSUNP_h
#define __mDNSUNP_h
#include <sys/types.h>
#include <sys/socket.h>
#include <net/if.h>
#include <netinet/in.h>
#ifdef __cplusplus
extern "C" {
#endif
#if !defined(HAVE_SOCKLEN_T)
typedef unsigned int socklen_t;
#endif
#define IFI_NAME 16 /* same as IFNAMSIZ in <net/if.h> */
#define IFI_HADDR 8 /* allow for 64-bit EUI-64 in future */
// Renamed from my_in_pktinfo because in_pktinfo is used by Linux.
struct my_in_pktinfo {
struct in_addr ipi_addr; /* dst IPv4 address */
int ipi_ifindex; /* received interface index */
char ipi_ifname[IFI_NAME]; /* received interface name */
};
extern ssize_t recvfrom_flags(int fd, void *ptr, size_t nbytes, int *flagsp,
struct sockaddr *sa, socklen_t *salenptr, struct my_in_pktinfo *pktp);
struct ifi_info {
char ifi_name[IFI_NAME]; /* interface name, null terminated */
u_char ifi_haddr[IFI_HADDR]; /* hardware address */
u_short ifi_hlen; /* #bytes in hardware address: 0, 6, 8 */
short ifi_flags; /* IFF_xxx constants from <net/if.h> */
short ifi_myflags; /* our own IFI_xxx flags */
int ifi_index; /* interface index */
struct sockaddr *ifi_addr; /* primary address */
struct sockaddr *ifi_brdaddr;/* broadcast address */
struct sockaddr *ifi_dstaddr;/* destination address */
struct ifi_info *ifi_next; /* next of these structures */
};
#define IFI_ALIAS 1 /* ifi_addr is an alias */
extern struct ifi_info *get_ifi_info(int family, int doaliases);
extern void free_ifi_info(struct ifi_info *);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -648,7 +648,7 @@ void *ws_dispatcher(void *arg) {
if(!can_dispatch) { /* auth failed, or need auth */
ws_addarg(&pwsc->response_headers,"Connection","close");
ws_addarg(&pwsc->response_headers,"WWW-Authenticate",
"Basic");
"Basic realm=\"webserver\"");
pwsc->close=1;
ws_returnerror(pwsc,401,"Unauthorized");
return NULL;