| /* -*- Mode: C; tab-width: 4 -*- |
| * |
| * Copyright (c) 2004 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 strcpy() |
| |
| #include <Events.h> // For WaitNextEvent() |
| |
| #include <OpenTransport.h> |
| #include <OpenTptInternet.h> |
| |
| #include <SIOUX.h> // For SIOUXHandleOneEvent() |
| |
| #include "dns_sd.h" |
| |
| typedef union { UInt8 b[2]; UInt16 NotAnInteger; } mDNSOpaque16; |
| static UInt16 mDNSVal16(mDNSOpaque16 x) { return((UInt16)(x.b[0]<<8 | x.b[1])); } |
| static mDNSOpaque16 mDNSOpaque16fromIntVal(UInt16 v) |
| { mDNSOpaque16 x; x.b[0] = (UInt8)(v >> 8); x.b[1] = (UInt8)(v & 0xFF); return(x); } |
| |
| typedef struct RegisteredService_struct RegisteredService; |
| struct RegisteredService_struct |
| { |
| RegisteredService *next; |
| DNSServiceRef sdRef; |
| Boolean gotresult; |
| DNSServiceErrorType errorCode; |
| char namestr[64]; |
| char typestr[kDNSServiceMaxDomainName]; |
| char domstr [kDNSServiceMaxDomainName]; |
| }; |
| |
| static RegisteredService p1, p2, afp, http, njp; |
| static RegisteredService *services = NULL, **nextservice = &services; |
| |
| static void RegCallback(DNSServiceRef sdRef, DNSServiceFlags flags, DNSServiceErrorType errorCode, |
| const char *name, const char *regtype, const char *domain, void *context) |
| { |
| RegisteredService *rs = (RegisteredService *)context; |
| (void)sdRef; // Unused |
| (void)flags; // Unused |
| rs->gotresult = true; |
| rs->errorCode = errorCode; |
| strcpy(rs->namestr, name); |
| strcpy(rs->typestr, regtype); |
| strcpy(rs->domstr, domain); |
| } |
| |
| static DNSServiceErrorType RegisterService(RegisteredService *rs, mDNSOpaque16 OpaquePort, |
| const char name[], const char type[], const char domain[], const char txtinfo[]) |
| { |
| DNSServiceErrorType err; |
| unsigned char txtbuffer[257]; |
| strncpy((char*)txtbuffer+1, txtinfo, 255); |
| txtbuffer[256] = 0; |
| txtbuffer[0] = (unsigned char)strlen((char*)txtbuffer); |
| rs->gotresult = 0; |
| rs->errorCode = kDNSServiceErr_NoError; |
| err = DNSServiceRegister(&rs->sdRef, /* kDNSServiceFlagsAutoRename*/ 0, 0, |
| name, type, domain, NULL, OpaquePort.NotAnInteger, (unsigned short)(1+txtbuffer[0]), txtbuffer, RegCallback, rs); |
| if (err) |
| printf("RegisterService(%s %s %s) failed %d\n", name, type, domain, err); |
| else |
| { *nextservice = rs; nextservice = &rs->next; } |
| return(err); |
| } |
| |
| // 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. |
| static DNSServiceErrorType RegisterFakeServiceForTesting(RegisteredService *rs, |
| const char name[], const char type[], const char domain[], const char txtinfo[]) |
| { |
| static UInt16 NextPort = 0xF000; |
| return RegisterService(rs, mDNSOpaque16fromIntVal(NextPort++), name, type, domain, txtinfo); |
| } |
| |
| // 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. |
| static DNSServiceErrorType CreateProxyRegistrationForRealService(RegisteredService *rs, |
| const char *servicetype, UInt16 PortAsNumber, const char txtinfo[]) |
| { |
| mDNSOpaque16 OpaquePort = mDNSOpaque16fromIntVal(PortAsNumber); |
| 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 = OpaquePort.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) |
| err = RegisterService(rs, OpaquePort, "", servicetype, "local.", txtinfo); |
| else if (err) |
| printf("OTBind failed %d", err); |
| |
| OTCloseProvider(ep); |
| return(err); |
| } |
| |
| // YieldSomeTime() just cooperatively yields some time to other processes running on classic Mac OS |
| static Boolean YieldSomeTime(UInt32 milliseconds) |
| { |
| extern Boolean SIOUXQuitting; |
| EventRecord e; |
| WaitNextEvent(everyEvent, &e, milliseconds / 17, NULL); |
| SIOUXHandleOneEvent(&e); |
| return(SIOUXQuitting); |
| } |
| |
| int main() |
| { |
| OSStatus err; |
| RegisteredService *s; |
| |
| 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\n"); |
| |
| err = InitOpenTransport(); |
| if (err) { printf("InitOpenTransport failed %d", err); return(err); } |
| |
| printf("Advertising Services...\n"); |
| |
| #define SRSET 0 |
| #if SRSET==0 |
| RegisterFakeServiceForTesting(&p1, "Web Server One", "_http._tcp.", "local.", "path=/index.html"); |
| RegisterFakeServiceForTesting(&p2, "Web Server Two", "_http._tcp.", "local.", "path=/path.html"); |
| #elif SRSET==1 |
| RegisterFakeServiceForTesting(&p1, "Epson Stylus 900N", "_printer._tcp.", "local.", "rn=lpq1"); |
| RegisterFakeServiceForTesting(&p2, "HP LaserJet", "_printer._tcp.", "local.", "rn=lpq2"); |
| #else |
| RegisterFakeServiceForTesting(&p1, "My Printer", "_printer._tcp.", "local.", "rn=lpq3"); |
| RegisterFakeServiceForTesting(&p2, "My Other Printer", "_printer._tcp.", "local.", "lrn=pq4"); |
| #endif |
| |
| // If AFP Server is running, register a record for it |
| CreateProxyRegistrationForRealService(&afp, "_afpovertcp._tcp.", 548, ""); |
| |
| // If Web Server is running, register a record for it |
| CreateProxyRegistrationForRealService(&http, "_http._tcp.", 80, "path=/index.html"); |
| |
| while (!YieldSomeTime(35)) |
| for (s = services; s; s = s->next) |
| if (s->gotresult) |
| { |
| printf("%s %s %s registered\n", s->namestr, s->typestr, s->domstr); |
| s->gotresult = false; |
| } |
| |
| for (s = services; s; s = s->next) |
| if (s->sdRef) DNSServiceRefDeallocate(s->sdRef); |
| |
| CloseOpenTransport(); |
| return(0); |
| } |