147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt/* -*- Mode: C; tab-width: 4 -*-
247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt *
347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt *
547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt * Licensed under the Apache License, Version 2.0 (the "License");
647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt * you may not use this file except in compliance with the License.
747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt * You may obtain a copy of the License at
847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt *
947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt *     http://www.apache.org/licenses/LICENSE-2.0
1047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt *
1147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt * Unless required by applicable law or agreed to in writing, software
1247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt * distributed under the License is distributed on an "AS IS" BASIS,
1347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt * See the License for the specific language governing permissions and
1547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt * limitations under the License.
1647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt */
1747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
1847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#include <stdio.h>				// For printf()
1947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#include <stdlib.h>				// For exit() etc.
2047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#include <string.h>				// For strlen() etc.
2147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#include <unistd.h>				// For select()
2247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#include <signal.h>				// For SIGINT, SIGTERM
2347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#include <errno.h>				// For errno, EINTR
2447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#include <netinet/in.h>			// For INADDR_NONE
2547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#include <arpa/inet.h>			// For inet_addr()
2647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#include <netdb.h>				// For gethostbyname()
2747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
2847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#include "mDNSEmbeddedAPI.h"	// Defines the interface to the client layer above
2947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#include "mDNSPosix.h"			// Defines the specific types needed to run mDNS on this platform
3047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#include "ExampleClientApp.h"
3147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
3247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// Compatibility workaround: Solaris 2.5 has no INADDR_NONE
3347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#ifndef	INADDR_NONE
3447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#define	INADDR_NONE	(mDNSu32)0xffffffff
3547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#endif
3647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
3747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt//*************************************************************************************************************
3847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// Globals
3947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwaltstatic mDNS mDNSStorage;       // mDNS core uses this to store its globals
4047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwaltstatic mDNS_PlatformSupport PlatformStorage;  // Stores this platform's globals
4147e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport const char ProgramName[] = "mDNSProxyResponderPosix";
4247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
4347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt//*************************************************************************************************************
4447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// Proxy Host Registration
4547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
4647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalttypedef struct
4747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
4847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	mDNSv4Addr ip;
4947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	domainlabel hostlabel;		// Conforms to standard DNS letter-digit-hyphen host name rules
5047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	AuthRecord RR_A;		// 'A' (address) record for our ".local" name
5147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	AuthRecord RR_PTR;		// PTR (reverse lookup) record
5247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	} ProxyHost;
5347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
5447e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal void HostNameCallback(mDNS *const m, AuthRecord *const rr, mStatus result)
5547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
5647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	ProxyHost *f = (ProxyHost*)rr->RecordContext;
5747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (result == mStatus_NoError)
5847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		debugf("Host name successfully registered: %##s", rr->resrec.name->c);
5947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	else
6047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
6147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		debugf("Host name conflict for %##s", rr->resrec.name->c);
6247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		mDNS_Deregister(m, &f->RR_A);
6347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		mDNS_Deregister(m, &f->RR_PTR);
6447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		exit(-1);
6547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
6647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	}
6747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
6847e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal mStatus mDNS_RegisterProxyHost(mDNS *m, ProxyHost *p)
6947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
7047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	char buffer[32];
7147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
7247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	mDNS_SetupResourceRecord(&p->RR_A,   mDNSNULL, mDNSInterface_Any, kDNSType_A,   60, kDNSRecordTypeUnique,      AuthRecordAny, HostNameCallback, p);
7347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	mDNS_SetupResourceRecord(&p->RR_PTR, mDNSNULL, mDNSInterface_Any, kDNSType_PTR, 60, kDNSRecordTypeKnownUnique, AuthRecordAny, HostNameCallback, p);
7447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
7547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	p->RR_A.namestorage.c[0] = 0;
7647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	AppendDomainLabel(&p->RR_A.namestorage, &p->hostlabel);
7747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	AppendLiteralLabelString(&p->RR_A.namestorage, "local");
7847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
7947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// Note: This is reverse order compared to a normal dotted-decimal IP address, so we can't use our customary "%.4a" format code
8047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	mDNS_snprintf(buffer, sizeof(buffer), "%d.%d.%d.%d.in-addr.arpa.", p->ip.b[3], p->ip.b[2], p->ip.b[1], p->ip.b[0]);
8147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	MakeDomainNameFromDNSNameString(&p->RR_PTR.namestorage, buffer);
8247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	p->RR_PTR.ForceMCast = mDNStrue; // This PTR points to our dot-local name, so don't ever try to write it into a uDNS server
8347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
8447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	p->RR_A.  resrec.rdata->u.ipv4 = p->ip;
8547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	AssignDomainName(&p->RR_PTR.resrec.rdata->u.name, p->RR_A.resrec.name);
8647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
8747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	mDNS_Register(m, &p->RR_A);
8847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	mDNS_Register(m, &p->RR_PTR);
8947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
9047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	debugf("Made Proxy Host Records for %##s", p->RR_A.resrec.name->c);
9147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
9247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	return(mStatus_NoError);
9347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	}
9447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
9547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt//*************************************************************************************************************
9647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// Service Registration
9747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
9847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// This sample ServiceCallback just calls mDNS_RenameAndReregisterService to automatically pick a new
9947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// unique name for the service. For a device such as a printer, this may be appropriate.
10047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// For a device with a user interface, and a screen, and a keyboard, the appropriate
10147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// response may be to prompt the user and ask them to choose a new name for the service.
10247e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal void ServiceCallback(mDNS *const m, ServiceRecordSet *const sr, mStatus result)
10347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
10447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	switch (result)
10547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
10647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		case mStatus_NoError:      debugf("Callback: %##s Name Registered",    sr->RR_SRV.resrec.name->c); break;
10747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		case mStatus_NameConflict: debugf("Callback: %##s Name Conflict",      sr->RR_SRV.resrec.name->c); break;
10847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		case mStatus_MemFree:      debugf("Callback: %##s Memory Free",        sr->RR_SRV.resrec.name->c); break;
10947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		default:                   debugf("Callback: %##s Unknown Result %ld", sr->RR_SRV.resrec.name->c, result); break;
11047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
11147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
11247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (result == mStatus_NoError)
11347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
11447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		char buffer[MAX_ESCAPED_DOMAIN_NAME];
11547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		ConvertDomainNameToCString(sr->RR_SRV.resrec.name, buffer);
11647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		printf("Service %s now registered and active\n", buffer);
11747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
11847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
11947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (result == mStatus_NameConflict)
12047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
12147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		char buffer1[MAX_ESCAPED_DOMAIN_NAME], buffer2[MAX_ESCAPED_DOMAIN_NAME];
12247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		ConvertDomainNameToCString(sr->RR_SRV.resrec.name, buffer1);
12347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		mDNS_RenameAndReregisterService(m, sr, mDNSNULL);
12447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		ConvertDomainNameToCString(sr->RR_SRV.resrec.name, buffer2);
12547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		printf("Name Conflict! %s renamed as %s\n", buffer1, buffer2);
12647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
12747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	}
12847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
12947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// RegisterService() is a simple wrapper function which takes C string
13047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// parameters, converts them to domainname parameters, and calls mDNS_RegisterService()
13147e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal void RegisterService(mDNS *m, ServiceRecordSet *recordset,
13247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	const char name[], const char type[], const char domain[],
13347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	const domainname *host, mDNSu16 PortAsNumber, int argc, char **argv)
13447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
13547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	domainlabel n;
13647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	domainname t, d;
13747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	unsigned char txtbuffer[1024], *bptr = txtbuffer;
13847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	char buffer[MAX_ESCAPED_DOMAIN_NAME];
13947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
14047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	MakeDomainLabelFromLiteralString(&n, name);
14147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	MakeDomainNameFromDNSNameString(&t, type);
14247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	MakeDomainNameFromDNSNameString(&d, domain);
14347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	while (argc)
14447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
14547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		int len = strlen(argv[0]);
14647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		if (len > 255 || bptr + 1 + len >= txtbuffer + sizeof(txtbuffer)) break;
14747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		printf("STR: %s\n", argv[0]);
14847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		bptr[0] = len;
14947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		strcpy((char*)(bptr+1), argv[0]);
15047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		bptr += 1 + len;
15147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		argc--;
15247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		argv++;
15347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
15447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
15547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	mDNS_RegisterService(m, recordset,
15647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		&n, &t, &d,					// Name, type, domain
15747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		host, mDNSOpaque16fromIntVal(PortAsNumber),
15847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		txtbuffer, bptr-txtbuffer,	// TXT data, length
15947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		mDNSNULL, 0,				// Subtypes
16047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		mDNSInterface_Any,			// Interface ID
16147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		ServiceCallback, mDNSNULL, 0);	// Callback, context, flags
16247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
16347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	ConvertDomainNameToCString(recordset->RR_SRV.resrec.name, buffer);
16447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	printf("Made Service Records for %s\n", buffer);
16547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	}
16647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
16747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt//*************************************************************************************************************
16847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// Service non-existence assertion
16947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// (claiming a service name without actually providing a service at that name, to prevent anyone else using that name)
17047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// This is useful to avoid confusion between similar services
17147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// e.g. A printer that implements IPP printing service using the name "My Printer", but doesn't implement LPR service,
17247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// should also claim the LPR service name "My Printer" to stop a different printer offering LPR service under the same name,
17347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// since it would be confusing to users to have two equivalent services with the same name.
17447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
17547e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal void NoSuchServiceCallback(mDNS *const m, AuthRecord *const rr, mStatus result)
17647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
17747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	const domainname *proxyhostname = (const domainname *)rr->RecordContext;
17847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	switch (result)
17947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
18047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		case mStatus_NoError:      debugf("Callback: %##s Name Registered",    rr->resrec.name->c); break;
18147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		case mStatus_NameConflict: debugf("Callback: %##s Name Conflict",      rr->resrec.name->c); break;
18247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		case mStatus_MemFree:      debugf("Callback: %##s Memory Free",        rr->resrec.name->c); break;
18347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		default:                   debugf("Callback: %##s Unknown Result %ld", rr->resrec.name->c, result); break;
18447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
18547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
18647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (result == mStatus_NoError)
18747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
18847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		char buffer[MAX_ESCAPED_DOMAIN_NAME];
18947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		ConvertDomainNameToCString(rr->resrec.name, buffer);
19047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		printf("Non-existence assertion %s now registered and active\n", buffer);
19147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
19247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
19347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (result == mStatus_NameConflict)
19447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
19547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		domainlabel n;
19647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		domainname t, d;
19747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		char buffer1[MAX_ESCAPED_DOMAIN_NAME], buffer2[MAX_ESCAPED_DOMAIN_NAME];
19847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		ConvertDomainNameToCString(rr->resrec.name, buffer1);
19947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		DeconstructServiceName(rr->resrec.name, &n, &t, &d);
20047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		IncrementLabelSuffix(&n, mDNStrue);
20147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		mDNS_RegisterNoSuchService(m, rr, &n, &t, &d, proxyhostname, mDNSInterface_Any, NoSuchServiceCallback, mDNSNULL, mDNSfalse);
20247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		ConvertDomainNameToCString(rr->resrec.name, buffer2);
20347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		printf("Name Conflict! %s renamed as %s\n", buffer1, buffer2);
20447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
20547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	}
20647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
20747e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal void RegisterNoSuchService(mDNS *m, AuthRecord *const rr, domainname *proxyhostname,
20847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	const char name[], const char type[], const char domain[])
20947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
21047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	domainlabel n;
21147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	domainname t, d;
21247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	char buffer[MAX_ESCAPED_DOMAIN_NAME];
21347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	MakeDomainLabelFromLiteralString(&n, name);
21447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	MakeDomainNameFromDNSNameString(&t, type);
21547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	MakeDomainNameFromDNSNameString(&d, domain);
21647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	mDNS_RegisterNoSuchService(m, rr, &n, &t, &d, proxyhostname, mDNSInterface_Any, NoSuchServiceCallback, proxyhostname, mDNSfalse);
21747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	ConvertDomainNameToCString(rr->resrec.name, buffer);
21847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	printf("Made Non-existence Record for %s\n", buffer);
21947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	}
22047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
22147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt//*************************************************************************************************************
22247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// Main
22347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
22447e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport int main(int argc, char **argv)
22547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
22647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	mStatus			status;
22747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	sigset_t		signals;
22847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
22947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (argc < 3) goto usage;
23047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
23147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	status = mDNS_Init(&mDNSStorage, &PlatformStorage,
23247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		mDNS_Init_NoCache, mDNS_Init_ZeroCacheSize,
23347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		mDNS_Init_DontAdvertiseLocalAddresses,
23447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		mDNS_Init_NoInitCallback, mDNS_Init_NoInitCallbackContext);
23547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (status) { fprintf(stderr, "Daemon start: mDNS_Init failed %d\n", (int)status); return(status); }
23647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
23747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	mDNSPosixListenForSignalInEventLoop(SIGINT);
23847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	mDNSPosixListenForSignalInEventLoop(SIGTERM);
23947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
24047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (!strcmp(argv[1], "-"))
24147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
24247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		domainname proxyhostname;
24347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		AuthRecord proxyrecord;
24447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		if (argc < 5) goto usage;
24547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		proxyhostname.c[0] = 0;
24647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		AppendLiteralLabelString(&proxyhostname, argv[2]);
24747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		AppendLiteralLabelString(&proxyhostname, "local");
24847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		RegisterNoSuchService(&mDNSStorage, &proxyrecord, &proxyhostname, argv[3], argv[4], "local.");
24947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
25047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	else
25147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
25247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		ProxyHost proxyhost;
25347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		ServiceRecordSet proxyservice;
25447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
25547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		proxyhost.ip.NotAnInteger = inet_addr(argv[1]);
25647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		if (proxyhost.ip.NotAnInteger == INADDR_NONE)	// INADDR_NONE is 0xFFFFFFFF
25747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			{
25847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			struct hostent *h = gethostbyname(argv[1]);
25947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			if (h) proxyhost.ip.NotAnInteger = *(long*)h->h_addr;
26047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			}
26147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		if (proxyhost.ip.NotAnInteger == INADDR_NONE)	// INADDR_NONE is 0xFFFFFFFF
26247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			{
26347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			fprintf(stderr, "%s is not valid host address\n", argv[1]);
26447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			return(-1);
26547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			}
26647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
26747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		MakeDomainLabelFromLiteralString(&proxyhost.hostlabel, argv[2]);
26847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
26947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		mDNS_RegisterProxyHost(&mDNSStorage, &proxyhost);
27047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
27147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		if (argc >=6)
27247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			RegisterService(&mDNSStorage, &proxyservice, argv[3], argv[4], "local.",
27347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							proxyhost.RR_A.resrec.name, atoi(argv[5]), argc-6, &argv[6]);
27447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
27547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
27647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	do
27747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
27847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		struct timeval	timeout = { 0x3FFFFFFF, 0 };	// wait until SIGINT or SIGTERM
27947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		mDNSBool		gotSomething;
28047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		mDNSPosixRunEventLoopOnce(&mDNSStorage, &timeout, &signals, &gotSomething);
28147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
28247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	while ( !( sigismember( &signals, SIGINT) || sigismember( &signals, SIGTERM)));
28347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
28447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	mDNS_Close(&mDNSStorage);
28547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
28647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	return(0);
28747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
28847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwaltusage:
28947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	fprintf(stderr, "%s ip hostlabel [srvname srvtype port txt [txt ...]]\n", argv[0]);
29047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	fprintf(stderr, "ip        Real IP address (or valid host name) of the host where the service actually resides\n");
29147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	fprintf(stderr, "hostlabel First label of the dot-local host name to create for this host, e.g. \"foo\" for \"foo.local.\"\n");
29247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	fprintf(stderr, "srvname   Descriptive name of service, e.g. \"Stuart's Ink Jet Printer\"\n");
29347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	fprintf(stderr, "srvtype   IANA service type, e.g. \"_ipp._tcp\" or \"_ssh._tcp\", etc.\n");
29447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	fprintf(stderr, "port      Port number where the service resides (1-65535)\n");
29547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	fprintf(stderr, "txt       Additional name/value pairs specified in service definition, e.g. \"pdl=application/postscript\"\n");
29647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	fprintf(stderr, "e.g. %s 169.254.12.34 thehost                                (just create a dot-local host name)\n", argv[0]);
29747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	fprintf(stderr, "or   %s 169.254.12.34 thehost \"My Printer\" _printer._tcp. 515 rp=lpt1 pdl=application/postscript\n", argv[0]);
29847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	fprintf(stderr, "or   %s -             thehost \"My Printer\" _printer._tcp.           (assertion of non-existence)\n", argv[0]);
29947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	return(-1);
30047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	}
301