blob: eff6a5f4e7af9d84a0a0832921feaa10d0de39a0 [file] [log] [blame]
/* -*- Mode: C; tab-width: 4 -*-
*
* Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <stdio.h> // For printf()
#include <string.h> // For strlen() etc.
#include <Events.h> // For WaitNextEvent()
#include <SIOUX.h> // For SIOUXHandleOneEvent()
#include "mDNSEmbeddedAPI.h" // Defines the interface to the client layer above
#include "mDNSMacOS9.h" // Defines the specific types needed to run mDNS on this platform
// These don't have to be globals, but their memory does need to remain valid for as
// long as the search is going on. They are declared as globals here for simplicity.
static mDNS m;
static mDNS_PlatformSupport p;
static ServiceRecordSet p1, p2, afp, http, njp;
static AuthRecord browsedomain1, browsedomain2;
// This sample code 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.
mDNSlocal void Callback(mDNS *const m, ServiceRecordSet *const sr, mStatus result)
{
switch (result)
{
case mStatus_NoError: debugf("Callback: %##s Name Registered", sr->RR_SRV.resrec.name->c); break;
case mStatus_NameConflict: debugf("Callback: %##s Name Conflict", sr->RR_SRV.resrec.name->c); break;
case mStatus_MemFree: debugf("Callback: %##s Memory Free", sr->RR_SRV.resrec.name->c); break;
default: debugf("Callback: %##s Unknown Result %d", sr->RR_SRV.resrec.name->c, result); break;
}
if (result == mStatus_NameConflict) mDNS_RenameAndReregisterService(m, sr, mDNSNULL);
}
// RegisterService() is a simple wrapper function which takes C string
// parameters, converts them to domainname parameters, and calls mDNS_RegisterService()
mDNSlocal void RegisterService(mDNS *m, ServiceRecordSet *recordset,
UInt16 PortAsNumber, const char txtinfo[],
const domainlabel *const n, const char type[], const char domain[])
{
domainname t;
domainname d;
char buffer[MAX_ESCAPED_DOMAIN_NAME];
UInt8 txtbuffer[512];
MakeDomainNameFromDNSNameString(&t, type);
MakeDomainNameFromDNSNameString(&d, domain);
if (txtinfo)
{
strncpy((char*)txtbuffer+1, txtinfo, sizeof(txtbuffer)-1);
txtbuffer[0] = (UInt8)strlen(txtinfo);
}
else
txtbuffer[0] = 0;
mDNS_RegisterService(m, recordset,
n, &t, &d, // Name, type, domain
mDNSNULL, mDNSOpaque16fromIntVal(PortAsNumber),
txtbuffer, (mDNSu16)(1+txtbuffer[0]), // TXT data, length
mDNSNULL, 0, // Subtypes (none)
mDNSInterface_Any, // Interface ID
Callback, mDNSNULL); // Callback and context
ConvertDomainNameToCString(recordset->RR_SRV.resrec.name, buffer);
printf("Made Service Records for %s\n", buffer);
}
// RegisterFakeServiceForTesting() simulates the effect of services being registered on
// dynamically-allocated port numbers. No real service exists on that port -- this is just for testing.
mDNSlocal void RegisterFakeServiceForTesting(mDNS *m, ServiceRecordSet *recordset, const char txtinfo[],
const char name[], const char type[], const char domain[])
{
static UInt16 NextPort = 0xF000;
domainlabel n;
MakeDomainLabelFromLiteralString(&n, name);
RegisterService(m, recordset, NextPort++, txtinfo, &n, type, domain);
}
// CreateProxyRegistrationForRealService() checks to see if the given port is currently
// in use, and if so, advertises the specified service as present on that port.
// This is useful for advertising existing real services (Personal Web Sharing, Personal
// File Sharing, etc.) that currently don't register with mDNS Service Discovery themselves.
mDNSlocal OSStatus CreateProxyRegistrationForRealService(mDNS *m, UInt16 PortAsNumber, const char txtinfo[],
const char *servicetype, ServiceRecordSet *recordset)
{
InetAddress ia;
TBind bindReq;
OSStatus err;
TEndpointInfo endpointinfo;
EndpointRef ep = OTOpenEndpoint(OTCreateConfiguration(kTCPName), 0, &endpointinfo, &err);
if (!ep || err) { printf("OTOpenEndpoint (CreateProxyRegistrationForRealService) failed %d", err); return(err); }
ia.fAddressType = AF_INET;
ia.fPort = mDNSOpaque16fromIntVal(PortAsNumber).NotAnInteger;
ia.fHost = 0;
bindReq.addr.maxlen = sizeof(ia);
bindReq.addr.len = sizeof(ia);
bindReq.addr.buf = (UInt8*)&ia;
bindReq.qlen = 0;
err = OTBind(ep, &bindReq, NULL);
if (err == kOTBadAddressErr)
RegisterService(m, recordset, PortAsNumber, txtinfo, &m->nicelabel, servicetype, "local.");
else if (err)
debugf("OTBind failed %d", err);
OTCloseProvider(ep);
return(noErr);
}
// Done once on startup, and then again every time our address changes
mDNSlocal OSStatus mDNSResponderTestSetup(mDNS *m)
{
char buffer[MAX_ESCAPED_DOMAIN_NAME];
mDNSv4Addr ip = m->HostInterfaces->ip.ip.v4;
ConvertDomainNameToCString(&m->MulticastHostname, buffer);
printf("Name %s\n", buffer);
printf("IP %d.%d.%d.%d\n", ip.b[0], ip.b[1], ip.b[2], ip.b[3]);
printf("\n");
printf("Registering Service Records\n");
// Create example printer discovery records
//static ServiceRecordSet p1, p2;
#define SRSET 0
#if SRSET==0
RegisterFakeServiceForTesting(m, &p1, "path=/index.html", "Web Server One", "_http._tcp.", "local.");
RegisterFakeServiceForTesting(m, &p2, "path=/path.html", "Web Server Two", "_http._tcp.", "local.");
#elif SRSET==1
RegisterFakeServiceForTesting(m, &p1, "rn=lpq1", "Epson Stylus 900N", "_printer._tcp.", "local.");
RegisterFakeServiceForTesting(m, &p2, "rn=lpq2", "HP LaserJet", "_printer._tcp.", "local.");
#else
RegisterFakeServiceForTesting(m, &p1, "rn=lpq3", "My Printer", "_printer._tcp.", "local.");
RegisterFakeServiceForTesting(m, &p2, "lrn=pq4", "My Other Printer", "_printer._tcp.", "local.");
#endif
// If AFP Server is running, register a record for it
CreateProxyRegistrationForRealService(m, 548, "", "_afpovertcp._tcp.", &afp);
// If Web Server is running, register a record for it
CreateProxyRegistrationForRealService(m, 80, "", "_http._tcp.", &http);
// And pretend we always have an NJP server running on port 80 too
//RegisterService(m, &njp, 80, "NJP/", &m->nicelabel, "_njp._tcp.", "local.");
// Advertise that apple.com. is available for browsing
mDNS_AdvertiseDomains(m, &browsedomain1, mDNS_DomainTypeBrowse, mDNSInterface_Any, "apple.com.");
mDNS_AdvertiseDomains(m, &browsedomain2, mDNS_DomainTypeBrowse, mDNSInterface_Any, "IL 2\\4th Floor.apple.com.");
return(kOTNoError);
}
// YieldSomeTime() just cooperatively yields some time to other processes running on classic Mac OS
mDNSlocal Boolean YieldSomeTime(UInt32 milliseconds)
{
extern Boolean SIOUXQuitting;
EventRecord e;
WaitNextEvent(everyEvent, &e, milliseconds / 17, NULL);
SIOUXHandleOneEvent(&e);
return(SIOUXQuitting);
}
int main()
{
mStatus err;
Boolean DoneSetup = false;
SIOUXSettings.asktosaveonclose = false;
SIOUXSettings.userwindowtitle = "\pMulticast DNS Responder";
printf("Multicast DNS Responder\n\n");
printf("This software reports errors using MacsBug breaks,\n");
printf("so if you don't have MacsBug installed your Mac may crash.\n\n");
printf("******************************************************************************\n");
err = InitOpenTransport();
if (err) { debugf("InitOpenTransport failed %d", err); return(err); }
err = mDNS_Init(&m, &p, mDNS_Init_NoCache, mDNS_Init_ZeroCacheSize,
mDNS_Init_AdvertiseLocalAddresses, mDNS_Init_NoInitCallback, mDNS_Init_NoInitCallbackContext);
if (err) return(err);
while (!YieldSomeTime(35))
{
#if MDNS_ONLYSYSTEMTASK
// For debugging, use "#define MDNS_ONLYSYSTEMTASK 1" and call mDNSPlatformIdle() periodically.
// For shipping code, don't define MDNS_ONLYSYSTEMTASK, and you don't need to call mDNSPlatformIdle()
extern void mDNSPlatformIdle(mDNS *const m);
mDNSPlatformIdle(&m); // Only needed for debugging version
#endif
if (m.mDNSPlatformStatus == mStatus_NoError && !DoneSetup)
{
DoneSetup = true;
printf("\nListening for mDNS queries...\n");
mDNSResponderTestSetup(&m);
}
}
if (p1.RR_SRV.resrec.RecordType ) mDNS_DeregisterService(&m, &p1);
if (p2.RR_SRV.resrec.RecordType ) mDNS_DeregisterService(&m, &p2);
if (afp.RR_SRV.resrec.RecordType ) mDNS_DeregisterService(&m, &afp);
if (http.RR_SRV.resrec.RecordType) mDNS_DeregisterService(&m, &http);
if (njp.RR_SRV.resrec.RecordType ) mDNS_DeregisterService(&m, &njp);
mDNS_Close(&m);
return(0);
}