1/* -*- Mode: C; tab-width: 4 -*- 2 * 3 * Copyright (c) 2004 Apple Computer, Inc. All rights reserved. 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18#include <stdio.h> // For printf() 19#include <string.h> // For strcpy() 20 21#include <Events.h> // For WaitNextEvent() 22 23#include <OpenTransport.h> 24#include <OpenTptInternet.h> 25 26#include <SIOUX.h> // For SIOUXHandleOneEvent() 27 28#include "dns_sd.h" 29 30typedef union { UInt8 b[2]; UInt16 NotAnInteger; } mDNSOpaque16; 31static UInt16 mDNSVal16(mDNSOpaque16 x) { return((UInt16)(x.b[0]<<8 | x.b[1])); } 32static mDNSOpaque16 mDNSOpaque16fromIntVal(UInt16 v) 33{ mDNSOpaque16 x; x.b[0] = (UInt8)(v >> 8); x.b[1] = (UInt8)(v & 0xFF); return(x); } 34 35typedef struct RegisteredService_struct RegisteredService; 36struct RegisteredService_struct 37{ 38 RegisteredService *next; 39 DNSServiceRef sdRef; 40 Boolean gotresult; 41 DNSServiceErrorType errorCode; 42 char namestr[64]; 43 char typestr[kDNSServiceMaxDomainName]; 44 char domstr [kDNSServiceMaxDomainName]; 45}; 46 47static RegisteredService p1, p2, afp, http, njp; 48static RegisteredService *services = NULL, **nextservice = &services; 49 50static void RegCallback(DNSServiceRef sdRef, DNSServiceFlags flags, DNSServiceErrorType errorCode, 51 const char *name, const char *regtype, const char *domain, void *context) 52{ 53 RegisteredService *rs = (RegisteredService *)context; 54 (void)sdRef; // Unused 55 (void)flags; // Unused 56 rs->gotresult = true; 57 rs->errorCode = errorCode; 58 strcpy(rs->namestr, name); 59 strcpy(rs->typestr, regtype); 60 strcpy(rs->domstr, domain); 61} 62 63static DNSServiceErrorType RegisterService(RegisteredService *rs, mDNSOpaque16 OpaquePort, 64 const char name[], const char type[], const char domain[], const char txtinfo[]) 65{ 66 DNSServiceErrorType err; 67 unsigned char txtbuffer[257]; 68 strncpy((char*)txtbuffer+1, txtinfo, 255); 69 txtbuffer[256] = 0; 70 txtbuffer[0] = (unsigned char)strlen((char*)txtbuffer); 71 rs->gotresult = 0; 72 rs->errorCode = kDNSServiceErr_NoError; 73 err = DNSServiceRegister(&rs->sdRef, /* kDNSServiceFlagsAutoRename*/ 0, 0, 74 name, type, domain, NULL, OpaquePort.NotAnInteger, (unsigned short)(1+txtbuffer[0]), txtbuffer, RegCallback, rs); 75 if (err) 76 printf("RegisterService(%s %s %s) failed %d\n", name, type, domain, err); 77 else 78 { *nextservice = rs; nextservice = &rs->next; } 79 return(err); 80} 81 82// RegisterFakeServiceForTesting() simulates the effect of services being registered on 83// dynamically-allocated port numbers. No real service exists on that port -- this is just for testing. 84static DNSServiceErrorType RegisterFakeServiceForTesting(RegisteredService *rs, 85 const char name[], const char type[], const char domain[], const char txtinfo[]) 86{ 87 static UInt16 NextPort = 0xF000; 88 return RegisterService(rs, mDNSOpaque16fromIntVal(NextPort++), name, type, domain, txtinfo); 89} 90 91// CreateProxyRegistrationForRealService() checks to see if the given port is currently 92// in use, and if so, advertises the specified service as present on that port. 93// This is useful for advertising existing real services (Personal Web Sharing, Personal 94// File Sharing, etc.) that currently don't register with mDNS Service Discovery themselves. 95static DNSServiceErrorType CreateProxyRegistrationForRealService(RegisteredService *rs, 96 const char *servicetype, UInt16 PortAsNumber, const char txtinfo[]) 97{ 98 mDNSOpaque16 OpaquePort = mDNSOpaque16fromIntVal(PortAsNumber); 99 InetAddress ia; 100 TBind bindReq; 101 OSStatus err; 102 TEndpointInfo endpointinfo; 103 EndpointRef ep = OTOpenEndpoint(OTCreateConfiguration(kTCPName), 0, &endpointinfo, &err); 104 if (!ep || err) { printf("OTOpenEndpoint (CreateProxyRegistrationForRealService) failed %d", err); return(err); } 105 106 ia.fAddressType = AF_INET; 107 ia.fPort = OpaquePort.NotAnInteger; 108 ia.fHost = 0; 109 bindReq.addr.maxlen = sizeof(ia); 110 bindReq.addr.len = sizeof(ia); 111 bindReq.addr.buf = (UInt8*)&ia; 112 bindReq.qlen = 0; 113 err = OTBind(ep, &bindReq, NULL); 114 115 if (err == kOTBadAddressErr) 116 err = RegisterService(rs, OpaquePort, "", servicetype, "local.", txtinfo); 117 else if (err) 118 printf("OTBind failed %d", err); 119 120 OTCloseProvider(ep); 121 return(err); 122} 123 124// YieldSomeTime() just cooperatively yields some time to other processes running on classic Mac OS 125static Boolean YieldSomeTime(UInt32 milliseconds) 126{ 127 extern Boolean SIOUXQuitting; 128 EventRecord e; 129 WaitNextEvent(everyEvent, &e, milliseconds / 17, NULL); 130 SIOUXHandleOneEvent(&e); 131 return(SIOUXQuitting); 132} 133 134int main() 135{ 136 OSStatus err; 137 RegisteredService *s; 138 139 SIOUXSettings.asktosaveonclose = false; 140 SIOUXSettings.userwindowtitle = "\pMulticast DNS Responder"; 141 142 printf("Multicast DNS Responder\n\n"); 143 printf("This software reports errors using MacsBug breaks,\n"); 144 printf("so if you don't have MacsBug installed your Mac may crash.\n\n"); 145 printf("******************************************************************************\n\n"); 146 147 err = InitOpenTransport(); 148 if (err) { printf("InitOpenTransport failed %d", err); return(err); } 149 150 printf("Advertising Services...\n"); 151 152#define SRSET 0 153#if SRSET==0 154 RegisterFakeServiceForTesting(&p1, "Web Server One", "_http._tcp.", "local.", "path=/index.html"); 155 RegisterFakeServiceForTesting(&p2, "Web Server Two", "_http._tcp.", "local.", "path=/path.html"); 156#elif SRSET==1 157 RegisterFakeServiceForTesting(&p1, "Epson Stylus 900N", "_printer._tcp.", "local.", "rn=lpq1"); 158 RegisterFakeServiceForTesting(&p2, "HP LaserJet", "_printer._tcp.", "local.", "rn=lpq2"); 159#else 160 RegisterFakeServiceForTesting(&p1, "My Printer", "_printer._tcp.", "local.", "rn=lpq3"); 161 RegisterFakeServiceForTesting(&p2, "My Other Printer", "_printer._tcp.", "local.", "lrn=pq4"); 162#endif 163 164 // If AFP Server is running, register a record for it 165 CreateProxyRegistrationForRealService(&afp, "_afpovertcp._tcp.", 548, ""); 166 167 // If Web Server is running, register a record for it 168 CreateProxyRegistrationForRealService(&http, "_http._tcp.", 80, "path=/index.html"); 169 170 while (!YieldSomeTime(35)) 171 for (s = services; s; s = s->next) 172 if (s->gotresult) 173 { 174 printf("%s %s %s registered\n", s->namestr, s->typestr, s->domstr); 175 s->gotresult = false; 176 } 177 178 for (s = services; s; s = s->next) 179 if (s->sdRef) DNSServiceRefDeallocate(s->sdRef); 180 181 CloseOpenTransport(); 182 return(0); 183} 184