2 * Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
23 Change History (most recent first):
26 Revision 1.2 2004/05/27 06:30:21 cheshire
27 Add code to test DNSServiceQueryRecord()
29 Revision 1.1 2004/03/12 21:30:25 cheshire
30 Build a System-Context Shared Library from mDNSCore, for the benefit of developers
31 like Muse Research who want to be able to use mDNS/DNS-SD from GPL-licensed code.
35 #include <stdio.h> // For printf()
36 #include <string.h> // For strcpy()
38 #include <Events.h> // For WaitNextEvent()
39 #include <CodeFragments.h> // For SIOkUnresolvedCFragSymbolAddress
41 #include <SIOUX.h> // For SIOUXHandleOneEvent()
43 #include <OpenTransport.h>
44 #include <OpenTptInternet.h>
51 typedef union { UInt8 b
[2]; UInt16 NotAnInteger
; } mDNSOpaque16
;
52 static UInt16
mDNSVal16(mDNSOpaque16 x
) { return((UInt16
)(x
.b
[0]<<8 | x
.b
[1])); }
53 static mDNSOpaque16
mDNSOpaque16fromIntVal(UInt16 v
)
54 { mDNSOpaque16 x
; x
.b
[0] = (UInt8
)(v
>> 8); x
.b
[1] = (UInt8
)(v
& 0xFF); return(x
); }
58 OTLIFO serviceinfolist
;
59 Boolean headerPrinted
;
65 SearcherServices
*services
;
66 char name
[kDNSServiceMaxDomainName
];
67 char type
[kDNSServiceMaxDomainName
];
68 char domn
[kDNSServiceMaxDomainName
];
69 char host
[kDNSServiceMaxDomainName
];
70 char text
[kDNSServiceMaxDomainName
];
72 mDNSOpaque16 notAnIntPort
;
79 static SearcherServices services
;
81 // PrintServiceInfo prints the service information to standard out
82 // A real application might want to do something else with the information
83 static void PrintServiceInfo(SearcherServices
*services
)
85 OTLink
*link
= OTReverseList(OTLIFOStealList(&services
->serviceinfolist
));
89 linkedServiceInfo
*s
= OTGetLinkObject(link
, linkedServiceInfo
, link
);
91 if (!services
->headerPrinted
)
93 printf("%-55s Type Domain Target Host IP Address Port Info\n", "Name");
94 services
->headerPrinted
= true;
99 if (s
->add
) printf("%-55s available for browsing\n", s
->domn
);
100 else printf("%-55s no longer available for browsing\n", s
->domn
);
105 unsigned char *p
= (unsigned char *)&s
->address
;
106 sprintf(ip
, "%d.%d.%d.%d", p
[0], p
[1], p
[2], p
[3]);
107 printf("%-55s %-16s %-14s ", s
->name
, s
->type
, s
->domn
);
108 if (s
->add
) printf("%-15s %-15s %5d %s\n", s
->host
, ip
, mDNSVal16(s
->notAnIntPort
), s
->text
);
109 else printf("Removed\n");
117 static void FoundInstanceAddress(DNSServiceRef sdRef
, DNSServiceFlags flags
, uint32_t interfaceIndex
, DNSServiceErrorType errorCode
,
118 const char *fullname
, uint16_t rrtype
, uint16_t rrclass
, uint16_t rdlen
, const void *rdata
, uint32_t ttl
, void *context
)
120 linkedServiceInfo
*info
= (linkedServiceInfo
*)context
;
121 SearcherServices
*services
= info
->services
;
122 (void)sdRef
; // Unused
123 (void)interfaceIndex
; // Unused
124 (void)fullname
; // Unused
126 if (errorCode
== kDNSServiceErr_NoError
)
127 if (flags
& kDNSServiceFlagsAdd
)
128 if (rrclass
== ns_c_in
&& rrtype
== ns_t_a
&& rdlen
== sizeof(info
->address
))
130 memcpy(&info
->address
, rdata
, sizeof(info
->address
));
131 DNSServiceRefDeallocate(info
->sdRef
);
132 OTLIFOEnqueue(&services
->serviceinfolist
, &info
->link
);
136 static void FoundInstanceInfo(DNSServiceRef sdRef
, DNSServiceFlags flags
, uint32_t interfaceIndex
,
137 DNSServiceErrorType errorCode
, const char *fullname
, const char *hosttarget
, uint16_t notAnIntPort
,
138 uint16_t txtLen
, const char *txtRecord
, void *context
)
140 linkedServiceInfo
*info
= (linkedServiceInfo
*)context
;
141 SearcherServices
*services
= info
->services
;
142 (void)sdRef
; // Unused
143 (void)flags
; // Unused
144 (void)interfaceIndex
; // Unused
145 (void)errorCode
; // Unused
146 (void)fullname
; // Unused
147 strcpy(info
->host
, hosttarget
);
148 if (txtLen
== 0) info
->text
[0] = 0;
151 strncpy(info
->text
, txtRecord
+1, txtRecord
[0]);
152 info
->text
[txtRecord
[0]] = 0;
154 info
->notAnIntPort
.NotAnInteger
= notAnIntPort
;
155 DNSServiceRefDeallocate(info
->sdRef
);
156 DNSServiceQueryRecord(&info
->sdRef
, 0, 0, info
->host
, ns_t_a
, ns_c_in
, FoundInstanceAddress
, info
);
159 // When a new named instance of a service is found, FoundInstance() is called.
160 // In this sample code we turn around and immediately to a DNSServiceResolve() to resolve that service name
161 // to find its target host, port, and txtinfo, but a normal browing application would just display the name.
162 // Resolving every single thing you find can be quite hard on the network, so you shouldn't do this
163 // in a real application. Defer resolving until the client has picked which instance from the
164 // long list of services is the one they want to use, and then resolve only that one.
165 static void FoundInstance(DNSServiceRef client
, DNSServiceFlags flags
, uint32_t interface
, DNSServiceErrorType errorCode
,
166 const char *replyName
, const char *replyType
, const char *replyDomain
, void *context
)
168 #pragma unused(client, interface, errorCode)
169 SearcherServices
*services
= (SearcherServices
*)context
;
170 linkedServiceInfo
*info
;
172 if (!services
) { DebugStr("\pFoundInstance: services is NULL"); return; }
174 info
= (linkedServiceInfo
*)OTAllocMem(sizeof(linkedServiceInfo
));
175 if (!info
) { services
->lostRecords
= true; return; }
177 info
->services
= services
;
178 strcpy(info
->name
, replyName
);
179 strcpy(info
->type
, replyType
);
180 strcpy(info
->domn
, replyDomain
);
182 info
->add
= (flags
& kDNSServiceFlagsAdd
) ? true : false;
185 if (!info
->add
) // If TTL == 0 we're deleting a service,
186 OTLIFOEnqueue(&services
->serviceinfolist
, &info
->link
);
187 else // else we're adding a new service
188 DNSServiceResolve(&info
->sdRef
, 0, 0, info
->name
, info
->type
, info
->domn
, FoundInstanceInfo
, info
);
191 // YieldSomeTime() just cooperatively yields some time to other processes running on classic Mac OS
192 static Boolean
YieldSomeTime(UInt32 milliseconds
)
194 extern Boolean SIOUXQuitting
;
196 WaitNextEvent(everyEvent
, &e
, milliseconds
/ 17, NULL
);
197 SIOUXHandleOneEvent(&e
);
198 return(SIOUXQuitting
);
206 DNSServiceErrorType dse
;
208 SIOUXSettings
.asktosaveonclose
= false;
209 SIOUXSettings
.userwindowtitle
= "\pMulticast DNS Searcher";
210 SIOUXSettings
.rows
= 40;
211 SIOUXSettings
.columns
= 160;
213 printf("DNS-SD Search Client\n\n");
214 printf("This software reports errors using MacsBug breaks,\n");
215 printf("so if you don't have MacsBug installed your Mac may crash.\n\n");
216 printf("******************************************************************************\n\n");
218 if (DNSServiceBrowse
== (void*)kUnresolvedCFragSymbolAddress
)
220 printf("Before you can use mDNS/DNS-SD clients, you need to place the \n");
221 printf("\"Multicast DNS & DNS-SD\" Extension in the Extensions Folder and restart\n");
225 err
= InitOpenTransport();
226 if (err
) { printf("InitOpenTransport failed %d", err
); return(err
); }
228 // Make sure OT has a large enough memory pool for us to draw from at OTNotifier (interrupt) time
229 tempmem
= OTAllocMem(0x10000);
230 if (tempmem
) OTFreeMem(tempmem
);
231 else printf("**** Warning: OTAllocMem couldn't pre-allocate 64K for us.\n");
233 services
.serviceinfolist
.fHead
= NULL
;
234 services
.headerPrinted
= false;
235 services
.lostRecords
= false;
237 printf("Sending mDNS service lookup queries and waiting for responses...\n\n");
238 dse
= DNSServiceBrowse(&sdRef
, 0, 0, "_http._tcp", "", FoundInstance
, &services
);
239 if (dse
== kDNSServiceErr_NoError
)
241 while (!YieldSomeTime(35))
243 if (services
.serviceinfolist
.fHead
)
244 PrintServiceInfo(&services
);
246 if (services
.lostRecords
)
248 services
.lostRecords
= false;
249 printf("**** Warning: Out of memory: Records have been missed.\n");
254 DNSServiceRefDeallocate(sdRef
);
255 CloseOpenTransport();