1 /* -*- Mode: C; tab-width: 4 -*-
3 * Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved.
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
9 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 Change History (most recent first):
20 Revision 1.3 2006/08/14 23:24:29 cheshire
21 Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
23 Revision 1.2 2004/05/27 06:30:21 cheshire
24 Add code to test DNSServiceQueryRecord()
26 Revision 1.1 2004/03/12 21:30:25 cheshire
27 Build a System-Context Shared Library from mDNSCore, for the benefit of developers
28 like Muse Research who want to be able to use mDNS/DNS-SD from GPL-licensed code.
32 #include <stdio.h> // For printf()
33 #include <string.h> // For strcpy()
35 #include <Events.h> // For WaitNextEvent()
36 #include <CodeFragments.h> // For SIOkUnresolvedCFragSymbolAddress
38 #include <SIOUX.h> // For SIOUXHandleOneEvent()
40 #include <OpenTransport.h>
41 #include <OpenTptInternet.h>
48 typedef union { UInt8 b
[2]; UInt16 NotAnInteger
; } mDNSOpaque16
;
49 static UInt16
mDNSVal16(mDNSOpaque16 x
) { return((UInt16
)(x
.b
[0]<<8 | x
.b
[1])); }
50 static mDNSOpaque16
mDNSOpaque16fromIntVal(UInt16 v
)
51 { mDNSOpaque16 x
; x
.b
[0] = (UInt8
)(v
>> 8); x
.b
[1] = (UInt8
)(v
& 0xFF); return(x
); }
55 OTLIFO serviceinfolist
;
56 Boolean headerPrinted
;
62 SearcherServices
*services
;
63 char name
[kDNSServiceMaxDomainName
];
64 char type
[kDNSServiceMaxDomainName
];
65 char domn
[kDNSServiceMaxDomainName
];
66 char host
[kDNSServiceMaxDomainName
];
67 char text
[kDNSServiceMaxDomainName
];
69 mDNSOpaque16 notAnIntPort
;
76 static SearcherServices services
;
78 // PrintServiceInfo prints the service information to standard out
79 // A real application might want to do something else with the information
80 static void PrintServiceInfo(SearcherServices
*services
)
82 OTLink
*link
= OTReverseList(OTLIFOStealList(&services
->serviceinfolist
));
86 linkedServiceInfo
*s
= OTGetLinkObject(link
, linkedServiceInfo
, link
);
88 if (!services
->headerPrinted
)
90 printf("%-55s Type Domain Target Host IP Address Port Info\n", "Name");
91 services
->headerPrinted
= true;
96 if (s
->add
) printf("%-55s available for browsing\n", s
->domn
);
97 else printf("%-55s no longer available for browsing\n", s
->domn
);
102 unsigned char *p
= (unsigned char *)&s
->address
;
103 sprintf(ip
, "%d.%d.%d.%d", p
[0], p
[1], p
[2], p
[3]);
104 printf("%-55s %-16s %-14s ", s
->name
, s
->type
, s
->domn
);
105 if (s
->add
) printf("%-15s %-15s %5d %s\n", s
->host
, ip
, mDNSVal16(s
->notAnIntPort
), s
->text
);
106 else printf("Removed\n");
114 static void FoundInstanceAddress(DNSServiceRef sdRef
, DNSServiceFlags flags
, uint32_t interfaceIndex
, DNSServiceErrorType errorCode
,
115 const char *fullname
, uint16_t rrtype
, uint16_t rrclass
, uint16_t rdlen
, const void *rdata
, uint32_t ttl
, void *context
)
117 linkedServiceInfo
*info
= (linkedServiceInfo
*)context
;
118 SearcherServices
*services
= info
->services
;
119 (void)sdRef
; // Unused
120 (void)interfaceIndex
; // Unused
121 (void)fullname
; // Unused
123 if (errorCode
== kDNSServiceErr_NoError
)
124 if (flags
& kDNSServiceFlagsAdd
)
125 if (rrclass
== ns_c_in
&& rrtype
== ns_t_a
&& rdlen
== sizeof(info
->address
))
127 memcpy(&info
->address
, rdata
, sizeof(info
->address
));
128 DNSServiceRefDeallocate(info
->sdRef
);
129 OTLIFOEnqueue(&services
->serviceinfolist
, &info
->link
);
133 static void FoundInstanceInfo(DNSServiceRef sdRef
, DNSServiceFlags flags
, uint32_t interfaceIndex
,
134 DNSServiceErrorType errorCode
, const char *fullname
, const char *hosttarget
, uint16_t notAnIntPort
,
135 uint16_t txtLen
, const char *txtRecord
, void *context
)
137 linkedServiceInfo
*info
= (linkedServiceInfo
*)context
;
138 SearcherServices
*services
= info
->services
;
139 (void)sdRef
; // Unused
140 (void)flags
; // Unused
141 (void)interfaceIndex
; // Unused
142 (void)errorCode
; // Unused
143 (void)fullname
; // Unused
144 strcpy(info
->host
, hosttarget
);
145 if (txtLen
== 0) info
->text
[0] = 0;
148 strncpy(info
->text
, txtRecord
+1, txtRecord
[0]);
149 info
->text
[txtRecord
[0]] = 0;
151 info
->notAnIntPort
.NotAnInteger
= notAnIntPort
;
152 DNSServiceRefDeallocate(info
->sdRef
);
153 DNSServiceQueryRecord(&info
->sdRef
, 0, 0, info
->host
, ns_t_a
, ns_c_in
, FoundInstanceAddress
, info
);
156 // When a new named instance of a service is found, FoundInstance() is called.
157 // In this sample code we turn around and immediately to a DNSServiceResolve() to resolve that service name
158 // to find its target host, port, and txtinfo, but a normal browing application would just display the name.
159 // Resolving every single thing you find can be quite hard on the network, so you shouldn't do this
160 // in a real application. Defer resolving until the client has picked which instance from the
161 // long list of services is the one they want to use, and then resolve only that one.
162 static void FoundInstance(DNSServiceRef client
, DNSServiceFlags flags
, uint32_t interface
, DNSServiceErrorType errorCode
,
163 const char *replyName
, const char *replyType
, const char *replyDomain
, void *context
)
165 #pragma unused(client, interface, errorCode)
166 SearcherServices
*services
= (SearcherServices
*)context
;
167 linkedServiceInfo
*info
;
169 if (!services
) { DebugStr("\pFoundInstance: services is NULL"); return; }
171 info
= (linkedServiceInfo
*)OTAllocMem(sizeof(linkedServiceInfo
));
172 if (!info
) { services
->lostRecords
= true; return; }
174 info
->services
= services
;
175 strcpy(info
->name
, replyName
);
176 strcpy(info
->type
, replyType
);
177 strcpy(info
->domn
, replyDomain
);
179 info
->add
= (flags
& kDNSServiceFlagsAdd
) ? true : false;
182 if (!info
->add
) // If TTL == 0 we're deleting a service,
183 OTLIFOEnqueue(&services
->serviceinfolist
, &info
->link
);
184 else // else we're adding a new service
185 DNSServiceResolve(&info
->sdRef
, 0, 0, info
->name
, info
->type
, info
->domn
, FoundInstanceInfo
, info
);
188 // YieldSomeTime() just cooperatively yields some time to other processes running on classic Mac OS
189 static Boolean
YieldSomeTime(UInt32 milliseconds
)
191 extern Boolean SIOUXQuitting
;
193 WaitNextEvent(everyEvent
, &e
, milliseconds
/ 17, NULL
);
194 SIOUXHandleOneEvent(&e
);
195 return(SIOUXQuitting
);
203 DNSServiceErrorType dse
;
205 SIOUXSettings
.asktosaveonclose
= false;
206 SIOUXSettings
.userwindowtitle
= "\pMulticast DNS Searcher";
207 SIOUXSettings
.rows
= 40;
208 SIOUXSettings
.columns
= 160;
210 printf("DNS-SD Search Client\n\n");
211 printf("This software reports errors using MacsBug breaks,\n");
212 printf("so if you don't have MacsBug installed your Mac may crash.\n\n");
213 printf("******************************************************************************\n\n");
215 if (DNSServiceBrowse
== (void*)kUnresolvedCFragSymbolAddress
)
217 printf("Before you can use mDNS/DNS-SD clients, you need to place the \n");
218 printf("\"Multicast DNS & DNS-SD\" Extension in the Extensions Folder and restart\n");
222 err
= InitOpenTransport();
223 if (err
) { printf("InitOpenTransport failed %d", err
); return(err
); }
225 // Make sure OT has a large enough memory pool for us to draw from at OTNotifier (interrupt) time
226 tempmem
= OTAllocMem(0x10000);
227 if (tempmem
) OTFreeMem(tempmem
);
228 else printf("**** Warning: OTAllocMem couldn't pre-allocate 64K for us.\n");
230 services
.serviceinfolist
.fHead
= NULL
;
231 services
.headerPrinted
= false;
232 services
.lostRecords
= false;
234 printf("Sending mDNS service lookup queries and waiting for responses...\n\n");
235 dse
= DNSServiceBrowse(&sdRef
, 0, 0, "_http._tcp", "", FoundInstance
, &services
);
236 if (dse
== kDNSServiceErr_NoError
)
238 while (!YieldSomeTime(35))
240 if (services
.serviceinfolist
.fHead
)
241 PrintServiceInfo(&services
);
243 if (services
.lostRecords
)
245 services
.lostRecords
= false;
246 printf("**** Warning: Out of memory: Records have been missed.\n");
251 DNSServiceRefDeallocate(sdRef
);
252 CloseOpenTransport();