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.
18 #include <stdio.h> // For printf()
19 #include <string.h> // For strcpy()
21 #include <Events.h> // For WaitNextEvent()
22 #include <CodeFragments.h> // For SIOkUnresolvedCFragSymbolAddress
24 #include <SIOUX.h> // For SIOUXHandleOneEvent()
26 #include <OpenTransport.h>
27 #include <OpenTptInternet.h>
34 typedef union { UInt8 b
[2]; UInt16 NotAnInteger
; } mDNSOpaque16
;
35 static UInt16
mDNSVal16(mDNSOpaque16 x
) { return((UInt16
)(x
.b
[0]<<8 | x
.b
[1])); }
36 static mDNSOpaque16
mDNSOpaque16fromIntVal(UInt16 v
)
37 { mDNSOpaque16 x
; x
.b
[0] = (UInt8
)(v
>> 8); x
.b
[1] = (UInt8
)(v
& 0xFF); return(x
); }
41 OTLIFO serviceinfolist
;
42 Boolean headerPrinted
;
48 SearcherServices
*services
;
49 char name
[kDNSServiceMaxDomainName
];
50 char type
[kDNSServiceMaxDomainName
];
51 char domn
[kDNSServiceMaxDomainName
];
52 char host
[kDNSServiceMaxDomainName
];
53 char text
[kDNSServiceMaxDomainName
];
55 mDNSOpaque16 notAnIntPort
;
62 static SearcherServices services
;
64 // PrintServiceInfo prints the service information to standard out
65 // A real application might want to do something else with the information
66 static void PrintServiceInfo(SearcherServices
*services
)
68 OTLink
*link
= OTReverseList(OTLIFOStealList(&services
->serviceinfolist
));
72 linkedServiceInfo
*s
= OTGetLinkObject(link
, linkedServiceInfo
, link
);
74 if (!services
->headerPrinted
)
76 printf("%-55s Type Domain Target Host IP Address Port Info\n", "Name");
77 services
->headerPrinted
= true;
82 if (s
->add
) printf("%-55s available for browsing\n", s
->domn
);
83 else printf("%-55s no longer available for browsing\n", s
->domn
);
88 unsigned char *p
= (unsigned char *)&s
->address
;
89 sprintf(ip
, "%d.%d.%d.%d", p
[0], p
[1], p
[2], p
[3]);
90 printf("%-55s %-16s %-14s ", s
->name
, s
->type
, s
->domn
);
91 if (s
->add
) printf("%-15s %-15s %5d %s\n", s
->host
, ip
, mDNSVal16(s
->notAnIntPort
), s
->text
);
92 else printf("Removed\n");
100 static void FoundInstanceAddress(DNSServiceRef sdRef
, DNSServiceFlags flags
, uint32_t interfaceIndex
, DNSServiceErrorType errorCode
,
101 const char *fullname
, uint16_t rrtype
, uint16_t rrclass
, uint16_t rdlen
, const void *rdata
, uint32_t ttl
, void *context
)
103 linkedServiceInfo
*info
= (linkedServiceInfo
*)context
;
104 SearcherServices
*services
= info
->services
;
105 (void)sdRef
; // Unused
106 (void)interfaceIndex
; // Unused
107 (void)fullname
; // Unused
109 if (errorCode
== kDNSServiceErr_NoError
)
110 if (flags
& kDNSServiceFlagsAdd
)
111 if (rrclass
== ns_c_in
&& rrtype
== ns_t_a
&& rdlen
== sizeof(info
->address
))
113 memcpy(&info
->address
, rdata
, sizeof(info
->address
));
114 DNSServiceRefDeallocate(info
->sdRef
);
115 OTLIFOEnqueue(&services
->serviceinfolist
, &info
->link
);
119 static void FoundInstanceInfo(DNSServiceRef sdRef
, DNSServiceFlags flags
, uint32_t interfaceIndex
,
120 DNSServiceErrorType errorCode
, const char *fullname
, const char *hosttarget
, uint16_t notAnIntPort
,
121 uint16_t txtLen
, const unsigned char *txtRecord
, void *context
)
123 linkedServiceInfo
*info
= (linkedServiceInfo
*)context
;
124 SearcherServices
*services
= info
->services
;
125 (void)sdRef
; // Unused
126 (void)flags
; // Unused
127 (void)interfaceIndex
; // Unused
128 (void)errorCode
; // Unused
129 (void)fullname
; // Unused
130 strcpy(info
->host
, hosttarget
);
131 if (txtLen
== 0) info
->text
[0] = 0;
134 strncpy(info
->text
, (char *)txtRecord
+1, txtRecord
[0]);
135 info
->text
[txtRecord
[0]] = 0;
137 info
->notAnIntPort
.NotAnInteger
= notAnIntPort
;
138 DNSServiceRefDeallocate(info
->sdRef
);
139 DNSServiceQueryRecord(&info
->sdRef
, 0, 0, info
->host
, ns_t_a
, ns_c_in
, FoundInstanceAddress
, info
);
142 // When a new named instance of a service is found, FoundInstance() is called.
143 // In this sample code we turn around and immediately to a DNSServiceResolve() to resolve that service name
144 // to find its target host, port, and txtinfo, but a normal browing application would just display the name.
145 // Resolving every single thing you find can be quite hard on the network, so you shouldn't do this
146 // in a real application. Defer resolving until the client has picked which instance from the
147 // long list of services is the one they want to use, and then resolve only that one.
148 static void FoundInstance(DNSServiceRef client
, DNSServiceFlags flags
, uint32_t interface
, DNSServiceErrorType errorCode
,
149 const char *replyName
, const char *replyType
, const char *replyDomain
, void *context
)
151 #pragma unused(client, interface, errorCode)
152 SearcherServices
*services
= (SearcherServices
*)context
;
153 linkedServiceInfo
*info
;
155 if (!services
) { DebugStr("\pFoundInstance: services is NULL"); return; }
157 info
= (linkedServiceInfo
*)OTAllocMem(sizeof(linkedServiceInfo
));
158 if (!info
) { services
->lostRecords
= true; return; }
160 info
->services
= services
;
161 strcpy(info
->name
, replyName
);
162 strcpy(info
->type
, replyType
);
163 strcpy(info
->domn
, replyDomain
);
165 info
->add
= (flags
& kDNSServiceFlagsAdd
) ? true : false;
168 if (!info
->add
) // If TTL == 0 we're deleting a service,
169 OTLIFOEnqueue(&services
->serviceinfolist
, &info
->link
);
170 else // else we're adding a new service
171 DNSServiceResolve(&info
->sdRef
, 0, 0, info
->name
, info
->type
, info
->domn
, FoundInstanceInfo
, info
);
174 // YieldSomeTime() just cooperatively yields some time to other processes running on classic Mac OS
175 static Boolean
YieldSomeTime(UInt32 milliseconds
)
177 extern Boolean SIOUXQuitting
;
179 WaitNextEvent(everyEvent
, &e
, milliseconds
/ 17, NULL
);
180 SIOUXHandleOneEvent(&e
);
181 return(SIOUXQuitting
);
189 DNSServiceErrorType dse
;
191 SIOUXSettings
.asktosaveonclose
= false;
192 SIOUXSettings
.userwindowtitle
= "\pMulticast DNS Searcher";
193 SIOUXSettings
.rows
= 40;
194 SIOUXSettings
.columns
= 160;
196 printf("DNS-SD Search Client\n\n");
197 printf("This software reports errors using MacsBug breaks,\n");
198 printf("so if you don't have MacsBug installed your Mac may crash.\n\n");
199 printf("******************************************************************************\n\n");
201 if (DNSServiceBrowse
== (void*)kUnresolvedCFragSymbolAddress
)
203 printf("Before you can use mDNS/DNS-SD clients, you need to place the \n");
204 printf("\"Multicast DNS & DNS-SD\" Extension in the Extensions Folder and restart\n");
208 err
= InitOpenTransport();
209 if (err
) { printf("InitOpenTransport failed %d", err
); return(err
); }
211 // Make sure OT has a large enough memory pool for us to draw from at OTNotifier (interrupt) time
212 tempmem
= OTAllocMem(0x10000);
213 if (tempmem
) OTFreeMem(tempmem
);
214 else printf("**** Warning: OTAllocMem couldn't pre-allocate 64K for us.\n");
216 services
.serviceinfolist
.fHead
= NULL
;
217 services
.headerPrinted
= false;
218 services
.lostRecords
= false;
220 printf("Sending mDNS service lookup queries and waiting for responses...\n\n");
221 dse
= DNSServiceBrowse(&sdRef
, 0, 0, "_http._tcp", "", FoundInstance
, &services
);
222 if (dse
== kDNSServiceErr_NoError
)
224 while (!YieldSomeTime(35))
226 if (services
.serviceinfolist
.fHead
)
227 PrintServiceInfo(&services
);
229 if (services
.lostRecords
)
231 services
.lostRecords
= false;
232 printf("**** Warning: Out of memory: Records have been missed.\n");
237 DNSServiceRefDeallocate(sdRef
);
238 CloseOpenTransport();