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