1 /* -*- Mode: C; tab-width: 4 -*-
3 * Copyright (c) 2003-2006 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):
19 $Log: uds_daemon.c,v $
20 Revision 1.201.2.1 2006/08/29 06:24:36 cheshire
21 Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
23 Revision 1.201 2006/06/29 03:02:47 cheshire
24 <rdar://problem/4607042> mDNSResponder NXDOMAIN and CNAME support
26 Revision 1.200 2006/06/28 08:56:26 cheshire
27 Added "_op" to the end of the operation code enum values,
28 to differentiate them from the routines with the same names
30 Revision 1.199 2006/06/28 08:53:39 cheshire
31 Added (commented out) debugging messages
33 Revision 1.198 2006/06/27 20:16:07 cheshire
36 Revision 1.197 2006/05/18 01:32:35 cheshire
37 <rdar://problem/4472706> iChat: Lost connection with Bonjour
38 (mDNSResponder insufficiently defensive against malformed browsing PTR responses)
40 Revision 1.196 2006/05/05 07:07:13 cheshire
41 <rdar://problem/4538206> mDNSResponder fails when UDS reads deliver partial data
43 Revision 1.195 2006/04/25 20:56:28 mkrochma
44 Added comment about previous checkin
46 Revision 1.194 2006/04/25 18:29:36 mkrochma
47 Workaround for warning: unused variable 'status' when building mDNSPosix
49 Revision 1.193 2006/03/19 17:14:38 cheshire
50 <rdar://problem/4483117> Need faster purging of stale records
51 read_rr_from_ipc_msg was not setting namehash and rdatahash
53 Revision 1.192 2006/03/18 20:58:32 cheshire
56 Revision 1.191 2006/03/10 22:19:43 cheshire
57 Update debugging message in resolve_result_callback() to indicate whether event is ADD or RMV
59 Revision 1.190 2006/03/10 21:56:12 cheshire
60 <rdar://problem/4111464> After record update, old record sometimes remains in cache
61 When service TXT and SRV record both change, clients with active resolve calls get *two* callbacks, one
62 when the TXT data changes, and then immediately afterwards a second callback with the new port number
63 This change suppresses the first unneccessary (and confusing) callback
65 Revision 1.189 2006/01/06 00:56:31 cheshire
66 <rdar://problem/4400573> Should remove PID file on exit
68 Revision 1.188 2005/10/11 22:15:03 cheshire
69 <rdar://problem/4296042> Add memory corruption safeguards to uds_daemon.c
70 Only compile uds_validatelists() when building for Mac OS X
72 Revision 1.187 2005/10/11 20:30:27 cheshire
73 <rdar://problem/4296042> Add memory corruption safeguards to uds_daemon.c
75 Revision 1.186 2005/09/12 07:11:53 herscher
76 <rdar://problem/4248878> Lazily call RegisterSearchDomains to workaround crashes of several routers. This code is conditionally compiled, and currently is only enabled on Windows platforms.
78 Revision 1.185 2005/07/29 00:55:10 ksekar
79 Removed validation check in uds_validatelists which generated false alarms
81 Revision 1.184 2005/07/04 22:40:26 cheshire
82 Additional debugging code to help catch memory corruption
84 Revision 1.183 2005/06/13 22:39:11 cheshire
85 <rdar://problem/4144870> Missing return statement in handle_enum_request() error handling
87 Revision 1.182 2005/03/21 00:39:31 shersche
88 <rdar://problem/4021486> Fix build warnings on Win32 platform
90 Revision 1.181 2005/03/20 20:21:32 shersche
91 <rdar://problem/4056827> mDNSResponder crashes when incorrect interface index is passed to DNSServiceRegister()
92 Text record length and data parameters must be initialized to 0 and NULL to ensure that the service request
93 object is cleaned up correctly when encountering an interface index error.
95 Revision 1.180 2005/03/10 00:13:12 cheshire
96 <rdar://problem/4043098> DNSServiceBrowse no longer returning error codes for invalid types
97 In handle_browse_request(), mStatus err was being set correctly if an error occurred,
98 but the end of the function returned mStatus_NoError intead of err.
100 Revision 1.179 2005/03/04 02:47:26 ksekar
101 <rdar://problem/4026393> SCPreference domains disappear from enumeration when moving out from firewall
103 Revision 1.178 2005/02/25 19:35:38 ksekar
104 <rdar://problem/4023750> Non-local empty string registration failures should not return errors to caller
106 Revision 1.177 2005/02/25 03:05:41 cheshire
107 Change "broken pipe" message to debugf()
109 Revision 1.176 2005/02/24 18:44:45 ksekar
110 <rdar://problem/4018516> Printer Sharing does not get re-registered with wide-area
112 Revision 1.175 2005/02/21 21:31:25 ksekar
113 <rdar://problem/4015162> changed LogMsg to debugf
115 Revision 1.174 2005/02/20 01:41:17 cheshire
116 Fix compiler signed/unsigned warning
118 Revision 1.173 2005/02/18 01:26:42 cheshire
119 <rdar://problem/4012162> "Could not write data to client after 60 seconds" message could be more helpful
120 Log additional information about failed client
122 Revision 1.172 2005/02/18 00:58:35 cheshire
123 <rdar://problem/4012162> "Could not write data to client after 60 seconds" message could be more helpful
125 Revision 1.171 2005/02/18 00:43:12 cheshire
126 <rdar://problem/4010245> mDNSResponder should auto-truncate service names that are too long
128 Revision 1.170 2005/02/16 01:15:02 cheshire
129 Improve LogOperation() debugging messages for DNSServiceBrowse and DNSServiceRegister
131 Revision 1.169 2005/02/08 01:57:14 cheshire
132 More detailed error reporting in udsserver_init()
134 Revision 1.168 2005/02/03 00:44:37 cheshire
135 <rdar://problem/3986663> DNSServiceUpdateRecord returns kDNSServiceErr_Invalid when rdlen=0, rdata=NULL
137 Revision 1.167 2005/02/02 02:19:32 cheshire
138 Add comment explaining why unlink(MDNS_UDS_SERVERPATH); fails
140 Revision 1.166 2005/02/01 19:58:52 ksekar
141 Shortened cryptic "broken pipe" syslog message
143 Revision 1.165 2005/02/01 19:56:47 ksekar
144 Moved LogMsg from daemon.c to uds_daemon.c, cleaned up wording
146 Revision 1.164 2005/01/28 06:07:55 cheshire
147 Don't use deliver_error() from within handle_regrecord_request()
149 Revision 1.163 2005/01/28 01:39:16 cheshire
150 Include file descriptor number in "broken pipe" message
152 Revision 1.162 2005/01/27 23:59:20 cheshire
153 Remove extraneous LogMsg
155 Revision 1.161 2005/01/27 22:57:56 cheshire
156 Fix compile errors on gcc4
158 Revision 1.160 2005/01/27 20:52:11 cheshire
159 <rdar://problem/3972566> mDNSResponder leaks sockets for add/update/remove record calls
161 Revision 1.159 2005/01/27 01:45:25 cheshire
162 <rdar://problem/3976147> mDNSResponder should never call exit(1);
164 Revision 1.158 2005/01/25 17:28:07 ksekar
165 <rdar://problem/3971467> Should not return "local" twice for domain enumeration
167 Revision 1.157 2005/01/21 02:20:39 cheshire
168 Fix mistake in LogOperation() format string
170 Revision 1.156 2005/01/19 19:15:36 ksekar
171 Refinement to <rdar://problem/3954575> - Simplify mDNS_PurgeResultsForDomain logic and move into daemon layer
173 Revision 1.155 2005/01/19 03:00:47 cheshire
174 Show Add/Rmv in DNSServiceBrowse LogOperation() message
176 Revision 1.154 2005/01/15 00:56:42 ksekar
177 <rdar://problem/3954575> Unicast services don't disappear when logging
180 Revision 1.153 2005/01/14 18:44:28 ksekar
181 <rdar://problem/3954609> mDNSResponder is crashing when changing domains
183 Revision 1.152 2005/01/13 17:16:38 ksekar
184 Back out checkin 1.150 - correct fix is on clientstub side
186 Revision 1.151 2005/01/11 21:06:29 ksekar
187 Changed now-benign LogMsg to debugf
189 Revision 1.150 2005/01/07 23:59:15 ksekar
190 <rdar://problem/3942900> dnd-sd shows the wrong port numbers
192 Revision 1.149 2004/12/20 23:20:35 cheshire
193 <rdar://problem/3928361> mDNSResponder crashes repeatedly when printer sharing is enabled
194 Make sure to call mDNS_SetupResourceRecord() for all newly created AuthRecords
196 Revision 1.148 2004/12/20 20:37:35 cheshire
197 AllowRemoteQuery not set for the extras in a ServiceRecordSet
199 Revision 1.147 2004/12/20 00:15:41 cheshire
200 Include client file descriptor numbers in udsserver_info() output
202 Revision 1.146 2004/12/17 05:25:47 cheshire
203 <rdar://problem/3925163> Shorten DNS-SD queries to avoid NAT bugs
205 Revision 1.145 2004/12/16 21:39:46 cheshire
206 Include CacheGroup objects in CacheUsed count
208 Revision 1.144 2004/12/16 21:27:38 ksekar
209 Fixed build failures when compiled with verbose debugging messages
211 Revision 1.143 2004/12/16 20:13:02 cheshire
212 <rdar://problem/3324626> Cache memory management improvements
214 Revision 1.142 2004/12/16 08:07:33 shersche
215 Fix compiler error (mixed declarations and code) on Windows
217 Revision 1.141 2004/12/16 01:56:21 cheshire
218 Improve DNSServiceEnumerateDomains syslog message
220 Revision 1.140 2004/12/14 03:02:10 ksekar
221 <rdar://problem/3919016> Rare race condition can cause crash
223 Revision 1.139 2004/12/13 21:18:45 ksekar
224 Include uDNS registrations in CountPeerRegistrations
226 Revision 1.138 2004/12/13 18:23:18 ksekar
227 <rdar://problem/3915805> mDNSResponder error when quitting iChat -
228 don't close sockets delivering errors to blocked clients
230 Revision 1.137 2004/12/13 00:09:22 ksekar
231 <rdar://problem/3915805> mDNSResponder error when quitting iChat
233 Revision 1.136 2004/12/11 01:52:10 cheshire
234 <rdar://problem/3785820> Support kDNSServiceFlagsAllowRemoteQuery for registering services too
236 Revision 1.135 2004/12/10 20:46:37 cheshire
237 Change LogOperation message to debugf
239 Revision 1.134 2004/12/10 13:19:37 cheshire
240 Add verbosedebugf() logging message in CountPeerRegistrations()
242 Revision 1.133 2004/12/10 05:27:26 cheshire
243 <rdar://problem/3909147> Guard against multiple autoname services of the same type on the same machine
245 Revision 1.132 2004/12/10 04:28:28 cheshire
246 <rdar://problem/3914406> User not notified of name changes for services using new UDS API
248 Revision 1.131 2004/12/10 02:09:25 cheshire
249 <rdar://problem/3898376> Modify default TTLs
251 Revision 1.130 2004/12/10 00:55:24 cheshire
252 Add full name and type to LogOperation messages for DNSServiceAddRecord/UpdateRecord/RemoveRecord
254 Revision 1.129 2004/12/09 03:17:23 ksekar
255 <rdar://problem/3910435> DomainEnumeration interface index should be zero
257 Revision 1.128 2004/12/07 21:26:05 ksekar
258 <rdar://problem/3908336> DNSServiceRegisterRecord() can crash on deregistration
260 Revision 1.127 2004/12/07 20:42:34 cheshire
261 Add explicit context parameter to mDNS_RemoveRecordFromService()
263 Revision 1.126 2004/12/07 17:23:55 ksekar
266 Revision 1.125 2004/12/06 21:15:23 ksekar
267 <rdar://problem/3884386> mDNSResponder crashed in CheckServiceRegistrations
269 Revision 1.124 2004/11/30 02:19:14 cheshire
270 <rdar://problem/3827971> Raise maxfds.rlim_cur for mDNSResponder
272 Revision 1.123 2004/11/29 23:50:57 cheshire
273 Checkin 1.122 not necessary
275 Revision 1.122 2004/11/24 17:55:01 ksekar
276 Added log message clarifying <rdar://problem/3869241> For unicast operations, verify that service types are legal
278 Revision 1.121 2004/11/24 04:45:52 cheshire
281 Revision 1.120 2004/11/24 00:10:44 cheshire
282 <rdar://problem/3869241> For unicast operations, verify that service types are legal
284 Revision 1.119 2004/11/23 23:54:17 ksekar
285 <rdar://problem/3890318> Wide-Area DNSServiceRegisterRecord() failures
286 can crash mDNSResponder
288 Revision 1.118 2004/11/23 22:33:01 cheshire
289 <rdar://problem/3654910> Remove temporary workaround code for iChat
291 Revision 1.117 2004/11/23 20:23:10 ksekar
292 Fixed LogOperation that causes crash on connected service deregistrations
294 Revision 1.116 2004/11/23 03:39:47 cheshire
295 Let interface name/index mapping capability live directly in JNISupport.c,
296 instead of having to call through to the daemon via IPC to get this information.
298 Revision 1.115 2004/11/13 00:12:53 ksekar
299 Fixed some LogOperation printf converstions for debug builds.
301 Revision 1.114 2004/11/12 18:25:45 shersche
302 Tidy up cross platform usleep code fragment.
304 Revision 1.113 2004/11/12 03:21:41 rpantos
305 rdar://problem/3809541 Add DNSSDMapIfIndexToName, DNSSDMapNameToIfIndex.
307 Revision 1.112 2004/11/11 16:58:32 ksekar
308 Removed unused code (previously wrapped in #if 0)
310 Revision 1.111 2004/11/05 22:47:37 shersche
311 Conditionally compile usleep(1000) to be Sleep(1) on Windows
312 Submitted by: Pavel Repin <prepin@gmail.com>
314 Revision 1.110 2004/11/05 19:56:56 ksekar
315 <rdar://problem/3862646> We no longer need to browse .Mac domains by
316 default - changed #if 0 to more descriptive #ifdef _HAVE_SETDOMAIN_SUPPORT_
318 Revision 1.109 2004/11/04 03:40:45 cheshire
319 More debugging messages
321 Revision 1.108 2004/11/03 02:25:51 cheshire
322 <rdar://problem/3324137> Conflict for Computer Name should update *all* empty string services, not just the one with the conflict
324 Revision 1.107 2004/11/02 19:39:23 ksekar
325 <rdar://problem/3862646> We no longer need to browse .Mac domains by default
327 Revision 1.106 2004/11/02 02:12:21 cheshire
328 <rdar://problem/3839111> Remove unnecessary memory allocations
330 Revision 1.105 2004/10/28 19:07:19 cheshire
331 Add some more debugging checks and improved LogOperation() messages
333 Revision 1.104 2004/10/26 18:53:15 cheshire
334 Avoid unused variable warning
336 Revision 1.103 2004/10/26 07:15:55 cheshire
337 Add file descriptor number to all LogOperation messages
339 Revision 1.102 2004/10/26 06:11:42 cheshire
340 Add improved logging to aid in diagnosis of <rdar://problem/3842714> mDNSResponder crashed
342 Revision 1.101 2004/10/26 04:31:44 cheshire
343 Rename CountSubTypes() as ChopSubTypes()
345 Revision 1.100 2004/10/26 01:17:48 cheshire
346 Use "#if 0" instead of commenting out code
348 Revision 1.99 2004/10/19 21:33:22 cheshire
349 <rdar://problem/3844991> Cannot resolve non-local registrations using the mach API
350 Added flag 'kDNSServiceFlagsForceMulticast'. Passing through an interface id for a unicast name
351 doesn't force multicast unless you set this flag to indicate explicitly that this is what you want
353 Revision 1.98 2004/10/14 01:59:33 cheshire
354 <rdar://problem/3839208> UDS resolves don't work for uDNS services
356 Revision 1.97 2004/10/13 00:58:35 cheshire
357 <rdar://problem/3832738> Registering a proxy doesn't work
359 Revision 1.96 2004/09/30 00:25:00 ksekar
360 <rdar://problem/3695802> Dynamically update default registration domains on config change
362 Revision 1.95 2004/09/26 23:20:36 ksekar
363 <rdar://problem/3813108> Allow default registrations in multiple wide-area domains
365 Revision 1.94 2004/09/22 18:27:06 ksekar
366 <rdar://problem/3811427> allow DNSServiceAddRecord to pass zero to get
369 Revision 1.93 2004/09/22 02:39:44 cheshire
370 <rdar://problem/3810757> Allow DNSServiceRegisterRecord to pass zero to get default record TTL
372 Revision 1.92 2004/09/22 02:34:04 cheshire
373 Rename parameter "ttl" to "GetTTL" for clarity
375 Revision 1.91 2004/09/22 02:25:43 cheshire
378 Revision 1.90 2004/09/21 23:40:12 ksekar
379 <rdar://problem/3810349> mDNSResponder to return errors on NAT traversal failure
381 Revision 1.89 2004/09/21 23:29:51 cheshire
382 <rdar://problem/3680045> DNSServiceResolve should delay sending packets
384 Revision 1.88 2004/09/21 23:12:46 cheshire
385 Reorder initialization of question fields to match structure order
387 Revision 1.87 2004/09/21 22:18:33 cheshire
388 In SIGINFO output, display a '-' next to records that have the Unique bit set
390 Revision 1.86 2004/09/21 21:05:11 cheshire
391 Move duplicate code out of mDNSMacOSX/daemon.c and mDNSPosix/PosixDaemon.c,
392 into mDNSShared/uds_daemon.c
394 Revision 1.85 2004/09/18 01:11:58 ksekar
395 <rdar://problem/3806734> Add a user's default domain to empty-string browse list
397 Revision 1.84 2004/09/17 01:08:55 cheshire
398 Renamed mDNSClientAPI.h to mDNSEmbeddedAPI.h
399 The name "mDNSClientAPI.h" is misleading to new developers looking at this code. The interfaces
400 declared in that file are ONLY appropriate to single-address-space embedded applications.
401 For clients on general-purpose computers, the interfaces defined in dns_sd.h should be used.
403 Revision 1.83 2004/09/16 23:26:33 cheshire
404 Move version check inside preceeding "if" that checks we have a complete header
406 Revision 1.82 2004/09/16 23:14:25 cheshire
407 Changes for Windows compatibility
409 Revision 1.81 2004/09/16 21:46:38 ksekar
410 <rdar://problem/3665304> Need SPI for LoginWindow to associate a UID with a Wide Area domain
412 Revision 1.80 2004/09/16 01:58:23 cheshire
413 Fix compiler warnings
415 Revision 1.79 2004/09/16 00:24:49 cheshire
416 <rdar://problem/3803162> Fix unsafe use of mDNSPlatformTimeNow()
418 Revision 1.78 2004/09/15 21:44:20 cheshire
419 <rdar://problem/3681031> Randomize initial timenow_adjust value in mDNS_Init
420 Show time value in log to help diagnose errors
422 Revision 1.77 2004/09/15 00:19:18 cheshire
423 <rdar://problem/3785823> read_rr_from_ipc_msg should use mDNS_SetupResourceRecord()
425 Revision 1.76 2004/09/02 06:39:52 cheshire
426 Minor textual cleanup for clarity
428 Revision 1.75 2004/09/02 03:48:47 cheshire
429 <rdar://problem/3709039> Disable targeted unicast query support by default
430 1. New flag kDNSServiceFlagsAllowRemoteQuery to indicate we want to allow remote queries for this record
431 2. New field AllowRemoteQuery in AuthRecord structure
432 3. uds_daemon.c sets AllowRemoteQuery if kDNSServiceFlagsAllowRemoteQuery is set
433 4. mDNS.c only answers remote queries if AllowRemoteQuery is set
435 Revision 1.74 2004/08/25 02:32:47 cheshire
436 Minor cleanup: replace "®type[0]" with "regtype"
438 Revision 1.73 2004/08/25 02:30:40 cheshire
439 <rdar://problem/3588761> Current method of doing subtypes causes name collisions
441 Revision 1.72 2004/08/14 03:22:42 cheshire
442 <rdar://problem/3762579> Dynamic DNS UI <-> mDNSResponder glue
443 Add GetUserSpecifiedDDNSName() routine
444 Convert ServiceRegDomain to domainname instead of C string
445 Replace mDNS_GenerateFQDN/mDNS_GenerateGlobalFQDN with mDNS_SetFQDNs
447 Revision 1.71 2004/08/11 04:21:21 rpantos
450 Revision 1.70 2004/08/11 02:07:00 cheshire
451 Remove "mDNS *globalInstance" parameter from udsserver_init()
452 Move CheckForDuplicateRegistrations from daemon.c
453 <rdar://problem/3501938> No warning when accidentally registering the same service multiple times using socket API
455 Revision 1.69 2004/08/10 16:14:48 cheshire
456 Fix debug builds (oops)
458 Revision 1.68 2004/08/10 06:24:56 cheshire
459 Use types with precisely defined sizes for 'op' and 'reg_index', for better
460 compatibility if the daemon and the client stub are built using different compilers
462 Revision 1.67 2004/07/27 07:14:16 shersche
463 make error socket non-blocking after call to connect()
465 Revision 1.66 2004/07/13 21:24:25 rpantos
466 Fix for <rdar://problem/3701120>.
468 Revision 1.65 2004/06/26 03:17:14 shersche
469 implement cross-platform strerror function
471 Submitted by: herscher
473 Revision 1.64 2004/06/25 00:26:27 rpantos
474 Changes to fix the Posix build on Solaris.
476 Revision 1.63 2004/06/24 03:43:44 rpantos
477 Fix previous checkin so it builds on Windows.
479 Revision 1.62 2004/06/24 00:57:08 ksekar
480 Replaced code acccidentally removed in checkin 1.59.
482 Revision 1.61 2004/06/19 00:09:39 cheshire
483 Remove unused strsep() implementation
485 Revision 1.60 2004/06/18 19:10:00 cheshire
486 <rdar://problem/3588761> Current method of doing subtypes causes name collisions
488 Revision 1.59 2004/06/18 05:10:31 rpantos
489 Changes to allow code to be used on Windows
491 Revision 1.58 2004/06/15 03:54:08 cheshire
492 Include mDNS_TimeNow(&mDNSStorage) in SIGINFO output
494 Revision 1.57 2004/06/12 01:47:27 ksekar
495 <rdar://problem/3690241>: BBEdit crashes when trying to check for newer version
496 udsserver_idle compared time in ticks to interval in seconds.
498 Revision 1.56 2004/06/12 01:35:47 cheshire
499 Changes for Windows compatibility
501 Revision 1.55 2004/06/05 00:04:27 cheshire
502 <rdar://problem/3668639>: wide-area domains should be returned in reg. domain enumeration
504 Revision 1.54 2004/06/01 22:22:52 ksekar
505 <rdar://problem/3668635>: wide-area default registrations should be in
508 Revision 1.53 2004/05/28 23:42:37 ksekar
509 <rdar://problem/3258021>: Feature: DNS server->client notification on record changes (#7805)
511 Revision 1.52 2004/05/26 00:39:49 ksekar
512 <rdar://problem/3667105>: wide-area DNS-SD servers don't appear in
514 Use local-only InterfaceID for GetDomains calls for sockets-API
516 Revision 1.51 2004/05/18 23:51:27 cheshire
517 Tidy up all checkin comments to use consistent "<rdar://problem/xxxxxxx>" format for bug numbers
519 Revision 1.50 2004/05/14 16:39:47 ksekar
520 Browse for iChat locally for now.
522 Revision 1.49 2004/05/13 21:33:52 ksekar
523 Clean up non-local registration control via config file. Force iChat
524 registrations to be local for now.
526 Revision 1.48 2004/05/13 04:13:19 ksekar
527 Updated SIGINFO handler for multi-domain browses
529 Revision 1.47 2004/05/12 22:04:01 ksekar
530 Implemented multi-domain browsing by default for uds_daemon.
532 Revision 1.46 2004/05/06 18:42:58 ksekar
533 General dns_sd.h API cleanup, including the following radars:
534 <rdar://problem/3592068>: Remove flags with zero value
535 <rdar://problem/3479569>: Passing in NULL causes a crash.
537 Revision 1.45 2004/03/12 08:49:28 cheshire
538 #include <sys/socket.h>
540 Revision 1.44 2004/02/25 01:25:27 ksekar
541 <rdar://problem/3569212>: DNSServiceRegisterRecord flags not error-checked
543 Revision 1.43 2004/02/24 01:46:40 cheshire
544 Manually reinstate lost checkin 1.36
546 Revision 1.42 2004/02/05 19:39:29 cheshire
547 Move creation of /var/run/mDNSResponder.pid to uds_daemon.c,
548 so that all platforms get this functionality
550 Revision 1.41 2004/02/03 18:59:02 cheshire
551 Change "char *domain" parameter for format_enumeration_reply to "const char *domain"
553 Revision 1.40 2004/01/28 03:41:00 cheshire
554 <rdar://problem/3541946>: Need ability to do targeted queries as well as multicast queries
556 Revision 1.39 2004/01/25 00:03:21 cheshire
557 Change to use mDNSVal16() instead of private PORT_AS_NUM() macro
559 Revision 1.38 2004/01/19 19:51:46 cheshire
560 Fix compiler error (mixed declarations and code) on some versions of Linux
562 Revision 1.37 2003/12/08 21:11:42 rpantos
563 Changes necessary to support mDNSResponder on Linux.
565 Revision 1.36 2003/12/04 23:40:57 cheshire
566 <rdar://problem/3484766>: Security: Crashing bug in mDNSResponder
567 Fix some more code that should use buffer size MAX_ESCAPED_DOMAIN_NAME (1005) instead of 256-byte buffers.
569 Revision 1.35 2003/12/03 19:10:22 ksekar
570 <rdar://problem/3498644>: malloc'd data not zero'd
572 Revision 1.34 2003/12/03 02:00:01 ksekar
573 <rdar://problem/3498644>: malloc'd data not zero'd
575 Revision 1.33 2003/11/22 01:18:46 ksekar
576 <rdar://problem/3486646>: config change handler not called for dns-sd services
578 Revision 1.32 2003/11/20 21:46:12 ksekar
579 <rdar://problem/3486635>: leak: DNSServiceRegisterRecord
581 Revision 1.31 2003/11/20 20:33:05 ksekar
582 <rdar://problem/3486635>: leak: DNSServiceRegisterRecord
584 Revision 1.30 2003/11/20 02:10:55 ksekar
585 <rdar://problem/3486643>: cleanup DNSServiceAdd/RemoveRecord
587 Revision 1.29 2003/11/14 21:18:32 cheshire
588 <rdar://problem/3484766>: Security: Crashing bug in mDNSResponder
589 Fix code that should use buffer size MAX_ESCAPED_DOMAIN_NAME (1005) instead of 256-byte buffers.
591 Revision 1.28 2003/11/08 22:18:29 cheshire
592 <rdar://problem/3477870>: Don't need to show process ID in *every* mDNSResponder syslog message
594 Revision 1.27 2003/11/05 22:44:57 ksekar
595 <rdar://problem/3335230>: No bounds checking when reading data from client
596 Reviewed by: Stuart Cheshire
598 Revision 1.26 2003/10/23 17:51:04 ksekar
599 <rdar://problem/3335216>: handle blocked clients more efficiently
600 Changed gettimeofday() to mDNS_TimeNow(&mDNSStorage);
602 Revision 1.25 2003/10/22 23:37:49 ksekar
603 <rdar://problem/3459141>: crash/hang in abort_client
605 Revision 1.24 2003/10/21 20:59:40 ksekar
606 <rdar://problem/3335216>: handle blocked clients more efficiently
608 Revision 1.23 2003/09/23 02:12:43 cheshire
609 Also include port number in list of services registered via new UDS API
611 Revision 1.22 2003/08/19 16:03:55 ksekar
612 <rdar://problem/3380097>: ER: SIGINFO dump should include resolves started by DNSServiceQueryRecord
613 Check termination_context for NULL before dereferencing.
615 Revision 1.21 2003/08/19 05:39:43 cheshire
616 <rdar://problem/3380097> SIGINFO dump should include resolves started by DNSServiceQueryRecord
618 Revision 1.20 2003/08/16 03:39:01 cheshire
619 <rdar://problem/3338440> InterfaceID -1 indicates "local only"
621 Revision 1.19 2003/08/15 20:16:03 cheshire
622 <rdar://problem/3366590> mDNSResponder takes too much RPRVT
623 We want to avoid touching the rdata pages, so we don't page them in.
624 1. RDLength was stored with the rdata, which meant touching the page just to find the length.
625 Moved this from the RData to the ResourceRecord object.
626 2. To avoid unnecessarily touching the rdata just to compare it,
627 compute a hash of the rdata and store the hash in the ResourceRecord object.
629 Revision 1.18 2003/08/15 00:38:00 ksekar
630 <rdar://problem/3377005>: Bug: buffer overrun when reading long rdata from client
632 Revision 1.17 2003/08/14 02:18:21 cheshire
633 <rdar://problem/3375491> Split generic ResourceRecord type into two separate types: AuthRecord and CacheRecord
635 Revision 1.16 2003/08/13 23:58:52 ksekar
636 <rdar://problem/3374911>: Bug: UDS Sub-type browsing works, but not sub-type registration
637 Fixed pointer increment error, moved subtype reading for-loop for easier error bailout.
639 Revision 1.15 2003/08/13 17:30:33 ksekar
640 <rdar://problem/3374671>: DNSServiceAddRecord doesn't work
641 Fixed various problems with handling the AddRecord request and freeing the ExtraResourceRecords.
643 Revision 1.14 2003/08/12 19:56:25 cheshire
650 #define MDNS_LAZY_REGISTER_SEARCH_DOMAINS
651 #define dnssd_strerror(X) win32_strerror(X)
652 #define usleep(X) Sleep(((X)+999)/1000)
653 static char * win32_strerror(int inErrorCode
);
657 #include <sys/ioctl.h>
658 #include <sys/types.h>
659 #include <sys/time.h>
660 #include <sys/resource.h>
661 #define dnssd_strerror(X) strerror(X)
666 #include "mDNSEmbeddedAPI.h"
667 #include "DNSCommon.h"
668 #include "uds_daemon.h"
670 #include "dnssd_ipc.h"
672 // Apple specific configuration functionality, not required for other platforms
674 #include <sys/ucred.h>
675 #ifndef LOCAL_PEERCRED
676 #define LOCAL_PEERCRED 0x001 /* retrieve peer credentials */
677 #endif // LOCAL_PEERCRED
680 #if defined(MDNS_LAZY_REGISTER_SEARCH_DOMAINS)
681 extern mStatus
dDNS_RegisterSearchDomains( mDNS
* const m
);
684 // Types and Data Structures
685 // ----------------------------------------------------------------------
696 typedef void (*req_termination_fn
)(void *);
698 typedef struct registered_record_entry
702 struct registered_record_entry
*next
;
703 client_context_t client_context
;
704 struct request_state
*rstate
;
705 } registered_record_entry
;
707 // A single registered service: ServiceRecordSet + bookkeeping
708 // Note that we duplicate some fields from parent service_info object
709 // to facilitate cleanup, when instances and parent may be deallocated at different times.
710 typedef struct service_instance
712 struct service_instance
*next
;
713 mDNSBool autoname
; // Set if this name is tied to the Computer Name
714 mDNSBool autorename
; // Set if this client wants us to automatically rename on conflict
715 mDNSBool allowremotequery
; // Respond to unicast queries from outside the local link?
716 mDNSBool rename_on_memfree
; // Set on config change when we deregister original name
719 mDNSBool default_local
; // is this the "local." from an empty-string registration?
720 struct request_state
*request
;
722 AuthRecord
*subtypes
;
723 ServiceRecordSet srs
; // note - must be last field in struct
726 // A client-created service. May reference several service_info objects if default
727 // settings cause registration in multiple domains.
734 char type_as_string
[MAX_ESCAPED_DOMAIN_NAME
];
736 mDNSBool default_domain
;
738 mDNSBool autoname
; // Set if this name is tied to the Computer Name
739 mDNSBool autorename
; // Set if this client wants us to automatically rename on conflict
740 mDNSBool allowremotequery
; // Respond to unicast queries from outside the local link?
742 mDNSInterfaceID InterfaceID
;
743 service_instance
*instances
;
744 struct request_state
*request
;
747 // for multi-domain default browsing
748 typedef struct browser_t
752 struct browser_t
*next
;
755 // parent struct for browser instances: list pointer plus metadata
758 mDNSBool default_domain
;
761 mDNSInterfaceID interface_id
;
762 struct request_state
*rstate
;
768 mStatus err
; // Note: This field is in NETWORK byte order
771 } undelivered_error_t
;
773 typedef struct request_state
775 // connection structures
778 // state of read (in case message is read over several recv() calls)
780 uint32_t hdr_bytes
; // bytes of header already read
782 uint32_t data_bytes
; // bytes of message data already read
783 char *msgbuf
; // pointer to data storage to pass to free()
784 char *msgdata
; // pointer to data to be read from (may be modified)
785 int bufsize
; // size of data storage
787 // reply, termination, error, and client context info
788 int no_reply
; // don't send asynchronous replies to client
789 int time_blocked
; // record time of a blocked client
790 void *client_context
; // don't touch this - pointer only valid in client's addr space
791 struct reply_state
*replies
; // corresponding (active) reply list
792 undelivered_error_t
*u_err
;
793 void *termination_context
;
794 req_termination_fn terminate
;
796 //!!!KRS toss these pointers in a union
797 // registration context associated with this request (null if not applicable)
798 registered_record_entry
*reg_recs
; // muliple registrations for a connection-oriented request
799 service_info
*service_registration
;
800 browser_info_t
*browser_info
;
801 struct request_state
*next
;
804 // struct physically sits between ipc message header and call-specific fields in the message buffer
807 DNSServiceFlags flags
; // Note: This field is in NETWORK byte order
808 uint32_t ifi
; // Note: This field is in NETWORK byte order
809 DNSServiceErrorType error
; // Note: This field is in NETWORK byte order
812 typedef struct reply_state
814 // state of the transmission
819 // context of the reply
820 struct request_state
*request
; // the request that this answers
821 struct reply_state
*next
; // if there are multiple unsent replies
822 // pointer into message buffer - allows fields to be changed after message is formatted
825 char *sdata
; // pointer to start of call-specific data
826 // pointer to malloc'd buffer
830 // domain enumeration and resolv calls require 2 mDNSCore calls, so we need separate interconnected
831 // structures to handle callbacks
834 DNSQuestion question
;
835 mDNS_DomainType type
;
836 request_state
*rstate
;
843 request_state
*rstate
;
844 } enum_termination_t
;
848 request_state
*rstate
;
851 // const ResourceRecord *txt;
852 // const ResourceRecord *srv;
857 mDNSu8 txtdata
[AbsoluteMaxDNSMessageData
];
858 } resolve_termination_t
;
860 #ifdef _HAVE_SETDOMAIN_SUPPORT_
861 typedef struct default_browse_list_t
863 struct default_browse_list_t
*next
;
866 } default_browse_list_t
;
868 static default_browse_list_t
*default_browse_list
= NULL
;
869 #endif // _HAVE_SETDOMAIN_SUPPORT_
872 mDNSexport mDNS mDNSStorage
;
873 #define gmDNS (&mDNSStorage)
875 static dnssd_sock_t listenfd
= dnssd_InvalidSocket
;
876 static request_state
* all_requests
= NULL
;
878 #define MAX_TIME_BLOCKED 60 * mDNSPlatformOneSecond // try to send data to a blocked client for 60 seconds before
879 // terminating connection
880 #define MSG_PAD_BYTES 5 // pad message buffer (read from client) with n zero'd bytes to guarantee
881 // n get_string() calls w/o buffer overrun
882 // private function prototypes
883 mDNSlocal
void connect_callback(void *info
);
884 mDNSlocal
int read_msg(request_state
*rs
);
885 mDNSlocal
int send_msg(reply_state
*rs
);
886 mDNSlocal
void abort_request(request_state
*rs
);
887 mDNSlocal
void request_callback(void *info
);
888 mDNSlocal
void handle_resolve_request(request_state
*rstate
);
889 mDNSlocal
void question_result_callback(mDNS
*const m
, DNSQuestion
*question
, const ResourceRecord
*const answer
, mDNSBool AddRecord
);
890 mDNSlocal
void question_termination_callback(void *context
);
891 mDNSlocal
void handle_browse_request(request_state
*request
);
892 mDNSlocal
void browse_termination_callback(void *context
);
893 mDNSlocal
void handle_regservice_request(request_state
*request
);
894 mDNSlocal
void regservice_termination_callback(void *context
);
895 mDNSlocal
void regservice_callback(mDNS
*const m
, ServiceRecordSet
*const srs
, mStatus result
);
896 mDNSlocal mStatus
handle_add_request(request_state
*rstate
);
897 mDNSlocal mStatus
handle_update_request(request_state
*rstate
);
898 mDNSlocal
void append_reply(request_state
*req
, reply_state
*rep
);
899 mDNSlocal
int build_domainname_from_strings(domainname
*srv
, char *name
, char *regtype
, char *domain
);
900 mDNSlocal
void enum_termination_callback(void *context
);
901 mDNSlocal
void enum_result_callback(mDNS
*const m
, DNSQuestion
*question
, const ResourceRecord
*const answer
, mDNSBool AddRecord
);
902 mDNSlocal
void handle_query_request(request_state
*rstate
);
903 mDNSlocal reply_state
*format_enumeration_reply(request_state
*rstate
, const char *domain
, DNSServiceFlags flags
, uint32_t ifi
, DNSServiceErrorType err
);
904 mDNSlocal
void handle_enum_request(request_state
*rstate
);
905 mDNSlocal mStatus
handle_regrecord_request(request_state
*rstate
);
906 mDNSlocal
void regrecord_callback(mDNS
*const m
, AuthRecord
* rr
, mStatus result
);
907 mDNSlocal
void connected_registration_termination(void *context
);
908 mDNSlocal
void handle_reconfirm_request(request_state
*rstate
);
909 mDNSlocal AuthRecord
*read_rr_from_ipc_msg(char *msgbuf
, int ttl
, int validate_flags
);
910 mDNSlocal mStatus
handle_removerecord_request(request_state
*rstate
);
911 mDNSlocal
void reset_connected_rstate(request_state
*rstate
);
912 mDNSlocal
int deliver_error(request_state
*rstate
, mStatus err
);
913 mDNSlocal
int deliver_async_error(request_state
*rs
, reply_op_t op
, mStatus err
);
914 mDNSlocal transfer_state
send_undelivered_error(request_state
*rs
);
915 mDNSlocal reply_state
*create_reply(reply_op_t op
, size_t datalen
, request_state
*request
);
916 mDNSlocal
void update_callback(mDNS
*const m
, AuthRecord
*const rr
, RData
*oldrd
);
917 mDNSlocal
void my_perror(char *errmsg
);
918 mDNSlocal
void unlink_request(request_state
*rs
);
919 mDNSlocal
void resolve_result_callback(mDNS
*const m
, DNSQuestion
*question
, const ResourceRecord
*const answer
, mDNSBool AddRecord
);
920 mDNSlocal
void resolve_termination_callback(void *context
);
921 mDNSlocal
int validate_message(request_state
*rstate
);
922 mDNSlocal mStatus
remove_extra(request_state
*rstate
, service_instance
*serv
);
923 mDNSlocal mStatus
remove_record(request_state
*rstate
);
924 mDNSlocal
void free_service_instance(service_instance
*srv
);
925 mDNSlocal
uint32_t dnssd_htonl(uint32_t l
);
926 mDNSlocal
void handle_setdomain_request(request_state
*rstate
);
928 // initialization, setup/teardown functions
930 // If a platform specifies its own PID file name, we use that
932 #define PID_FILE "/var/run/mDNSResponder.pid"
935 mDNSlocal
void LogClientInfo(request_state
*req
)
937 void *t
= req
->termination_context
;
940 if (req
->terminate
== regservice_termination_callback
)
942 service_instance
*ptr
;
943 for (ptr
= ((service_info
*)t
)->instances
; ptr
; ptr
= ptr
->next
)
944 LogMsgNoIdent("%3d: DNSServiceRegister %##s %u", req
->sd
, ptr
->srs
.RR_SRV
.resrec
.name
->c
, SRS_PORT(&ptr
->srs
));
946 else if (req
->terminate
== browse_termination_callback
)
949 for (blist
= req
->browser_info
->browsers
; blist
; blist
= blist
->next
)
950 LogMsgNoIdent("%3d: DNSServiceBrowse %##s", req
->sd
, blist
->q
.qname
.c
);
952 else if (req
->terminate
== resolve_termination_callback
)
953 LogMsgNoIdent("%3d: DNSServiceResolve %##s", req
->sd
, ((resolve_termination_t
*)t
)->qsrv
.qname
.c
);
954 else if (req
->terminate
== question_termination_callback
)
955 LogMsgNoIdent("%3d: DNSServiceQueryRecord %##s", req
->sd
, ((DNSQuestion
*) t
)->qname
.c
);
956 else if (req
->terminate
== enum_termination_callback
)
957 LogMsgNoIdent("%3d: DNSServiceEnumerateDomains %##s", req
->sd
, ((enum_termination_t
*) t
)->all
->question
.qname
.c
);
961 mDNSlocal
void FatalError(char *errmsg
)
963 LogMsg("%s: %s", errmsg
, dnssd_strerror(dnssd_errno()));
964 *(long*)0 = 0; // On OS X abort() doesn't generate a crash log, but writing to zero does
965 abort(); // On platforms where writing to zero doesn't generate an exception, abort instead
968 int udsserver_init(void)
970 dnssd_sockaddr_t laddr
;
976 // If a particular platform wants to opt out of having a PID file, define PID_FILE to be ""
979 FILE *fp
= fopen(PID_FILE
, "w");
982 fprintf(fp
, "%d\n", getpid());
987 if ((listenfd
= socket(AF_DNSSD
, SOCK_STREAM
, 0)) == dnssd_InvalidSocket
)
989 my_perror("ERROR: socket(AF_DNSSD, SOCK_STREAM, 0); failed");
993 bzero(&laddr
, sizeof(laddr
));
995 #if defined(USE_TCP_LOOPBACK)
997 laddr
.sin_family
= AF_INET
;
998 laddr
.sin_port
= htons(MDNS_TCP_SERVERPORT
);
999 laddr
.sin_addr
.s_addr
= inet_addr(MDNS_TCP_SERVERADDR
);
1000 ret
= bind(listenfd
, (struct sockaddr
*) &laddr
, sizeof(laddr
));
1003 my_perror("ERROR: bind(listenfd, (struct sockaddr *) &laddr, sizeof(laddr)); failed");
1009 mode_t mask
= umask(0);
1010 unlink(MDNS_UDS_SERVERPATH
); //OK if this fails
1011 laddr
.sun_family
= AF_LOCAL
;
1012 #ifndef NOT_HAVE_SA_LEN
1013 // According to Stevens (section 3.2), there is no portable way to
1014 // determine whether sa_len is defined on a particular platform.
1015 laddr
.sun_len
= sizeof(struct sockaddr_un
);
1017 strcpy(laddr
.sun_path
, MDNS_UDS_SERVERPATH
);
1018 ret
= bind(listenfd
, (struct sockaddr
*) &laddr
, sizeof(laddr
));
1022 my_perror("ERROR: bind(listenfd, (struct sockaddr *) &laddr, sizeof(laddr)); failed");
1030 // SEH: do we even need to do this on windows? this socket
1031 // will be given to WSAEventSelect which will automatically
1032 // set it to non-blocking
1034 if (ioctlsocket(listenfd
, FIONBIO
, &opt
) != 0)
1036 if (fcntl(listenfd
, F_SETFL
, O_NONBLOCK
) != 0)
1039 my_perror("ERROR: could not set listen socket to non-blocking mode");
1043 if (listen(listenfd
, LISTENQ
) != 0)
1045 my_perror("ERROR: could not listen on listen socket");
1049 if (mStatus_NoError
!= udsSupportAddFDToEventLoop(listenfd
, connect_callback
, (void *) NULL
))
1051 my_perror("ERROR: could not add listen socket to event loop");
1055 #if !defined(PLATFORM_NO_RLIMIT)
1057 // Set maximum number of open file descriptors
1058 #define MIN_OPENFILES 10240
1059 struct rlimit maxfds
, newfds
;
1061 // Due to bugs in OS X (<rdar://problem/2941095>, <rdar://problem/3342704>, <rdar://problem/3839173>)
1062 // you have to get and set rlimits once before getrlimit will return sensible values
1063 if (getrlimit(RLIMIT_NOFILE
, &maxfds
) < 0) { my_perror("ERROR: Unable to get file descriptor limit"); return 0; }
1064 if (setrlimit(RLIMIT_NOFILE
, &maxfds
) < 0) my_perror("ERROR: Unable to set maximum file descriptor limit");
1066 if (getrlimit(RLIMIT_NOFILE
, &maxfds
) < 0) { my_perror("ERROR: Unable to get file descriptor limit"); return 0; }
1067 newfds
.rlim_max
= (maxfds
.rlim_max
> MIN_OPENFILES
) ? maxfds
.rlim_max
: MIN_OPENFILES
;
1068 newfds
.rlim_cur
= (maxfds
.rlim_cur
> MIN_OPENFILES
) ? maxfds
.rlim_cur
: MIN_OPENFILES
;
1069 if (newfds
.rlim_max
!= maxfds
.rlim_max
|| newfds
.rlim_cur
!= maxfds
.rlim_cur
)
1070 if (setrlimit(RLIMIT_NOFILE
, &newfds
) < 0) my_perror("ERROR: Unable to set maximum file descriptor limit");
1072 if (getrlimit(RLIMIT_NOFILE
, &maxfds
) < 0) { my_perror("ERROR: Unable to get file descriptor limit"); return 0; }
1073 debugf("maxfds.rlim_max %d", (long)maxfds
.rlim_max
);
1074 debugf("maxfds.rlim_cur %d", (long)maxfds
.rlim_cur
);
1082 my_perror("ERROR: udsserver_init");
1086 int udsserver_exit(void)
1088 dnssd_close(listenfd
);
1090 #if !defined(USE_TCP_LOOPBACK)
1091 // Currently, we're unable to remove /var/run/mdnsd because we've changed to userid "nobody"
1092 // to give up unnecessary privilege, but we need to be root to remove this Unix Domain Socket.
1093 // It would be nice if we could find a solution to this problem
1094 if (unlink(MDNS_UDS_SERVERPATH
))
1095 debugf("Unable to remove %s", MDNS_UDS_SERVERPATH
);
1098 if (PID_FILE
[0]) unlink(PID_FILE
);
1103 mDNSs32
udsserver_idle(mDNSs32 nextevent
)
1105 request_state
*req
= all_requests
, *tmp
, *prev
= NULL
;
1107 transfer_state result
;
1108 mDNSs32 now
= mDNS_TimeNow(&mDNSStorage
);
1112 result
= t_uninitialized
;
1114 result
= send_undelivered_error(req
);
1115 if (result
!= t_error
&& result
!= t_morecoming
&& // don't try to send msg if send_error failed
1116 (req
->ts
== t_complete
|| req
->ts
== t_morecoming
))
1120 if (req
->replies
->next
) req
->replies
->rhdr
->flags
|= dnssd_htonl(kDNSServiceFlagsMoreComing
);
1121 result
= send_msg(req
->replies
);
1122 if (result
== t_complete
)
1124 fptr
= req
->replies
;
1125 req
->replies
= req
->replies
->next
;
1126 freeL("udsserver_idle", fptr
);
1127 req
->time_blocked
= 0; // reset failure counter after successful send
1129 else if (result
== t_terminated
|| result
== t_error
)
1134 else if (result
== t_morecoming
) break; // client's queues are full, move to next
1137 if (result
== t_morecoming
)
1139 if (!req
->time_blocked
) req
->time_blocked
= now
;
1140 debugf("udsserver_idle: client has been blocked for %ld seconds", (now
- req
->time_blocked
) / mDNSPlatformOneSecond
);
1141 if (now
- req
->time_blocked
>= MAX_TIME_BLOCKED
)
1143 LogMsg("Could not write data to client %d after %ld seconds - aborting connection", req
->sd
, MAX_TIME_BLOCKED
/ mDNSPlatformOneSecond
);
1146 result
= t_terminated
;
1148 else if (nextevent
- now
> mDNSPlatformOneSecond
) nextevent
= now
+ mDNSPlatformOneSecond
; // try again in a second
1150 if (result
== t_terminated
|| result
== t_error
)
1151 //since we're already doing a list traversal, we unlink the request manually instead of calling unlink_request()
1154 if (prev
) prev
->next
= req
->next
;
1155 if (req
== all_requests
) all_requests
= all_requests
->next
;
1157 freeL("udsserver_idle", tmp
);
1168 mDNSexport
void udsserver_info(mDNS
*const m
)
1170 mDNSs32 now
= mDNS_TimeNow(m
);
1171 mDNSu32 CacheUsed
= 0, CacheActive
= 0;
1177 LogMsgNoIdent("Timenow 0x%08lX (%ld)", (mDNSu32
)now
, now
);
1179 LogMsgNoIdent("Slt Q TTL U Type if len rdata");
1180 for (slot
= 0; slot
< CACHE_HASH_SLOTS
; slot
++)
1181 for(cg
= m
->rrcache_hash
[slot
]; cg
; cg
=cg
->next
)
1183 CacheUsed
++; // Count one cache entity for the CacheGroup object
1184 for (rr
= cg
->members
; rr
; rr
=rr
->next
)
1186 mDNSs32 remain
= rr
->resrec
.rroriginalttl
- (now
- rr
->TimeRcvd
) / mDNSPlatformOneSecond
;
1188 if (rr
->CRActiveQuestion
) CacheActive
++;
1189 LogMsgNoIdent("%3d %s%6ld %s %-6s%-6s%s",
1191 rr
->CRActiveQuestion
? "*" : " ",
1193 (rr
->resrec
.RecordType
& kDNSRecordTypePacketUniqueMask
) ? "-" : " ",
1194 DNSTypeName(rr
->resrec
.rrtype
),
1195 ((NetworkInterfaceInfo
*)rr
->resrec
.InterfaceID
)->ifname
,
1196 CRDisplayString(m
, rr
));
1197 usleep(1000); // Limit rate a little so we don't flood syslog too fast
1201 if (m
->rrcache_totalused
!= CacheUsed
)
1202 LogMsgNoIdent("Cache use mismatch: rrcache_totalused is %lu, true count %lu", m
->rrcache_totalused
, CacheUsed
);
1203 if (m
->rrcache_active
!= CacheActive
)
1204 LogMsgNoIdent("Cache use mismatch: rrcache_active is %lu, true count %lu", m
->rrcache_active
, CacheActive
);
1205 LogMsgNoIdent("Cache currently contains %lu records; %lu referenced by active questions", CacheUsed
, CacheActive
);
1207 for (req
= all_requests
; req
; req
=req
->next
)
1210 now
= mDNS_TimeNow(m
);
1211 LogMsgNoIdent("Timenow 0x%08lX (%ld)", (mDNSu32
)now
, now
);
1214 #if __MACOSX__ && MACOSX_MDNS_MALLOC_DEBUGGING
1215 mDNSexport
void uds_validatelists(void)
1218 for (req
= all_requests
; req
; req
=req
->next
)
1219 if (req
->sd
< 0 && req
->sd
!= -2)
1220 LogMemCorruption("UDS request list: %p is garbage (%X)", req
, req
->sd
);
1224 mDNSlocal
void rename_service(service_instance
*srv
)
1226 if (srv
->autoname
&& !SameDomainLabel(srv
->name
.c
, gmDNS
->nicelabel
.c
))
1228 srv
->rename_on_memfree
= 1;
1229 if (mDNS_DeregisterService(gmDNS
, &srv
->srs
)) // If service deregistered already, we can re-register immediately
1230 regservice_callback(gmDNS
, &srv
->srs
, mStatus_MemFree
);
1234 mDNSexport
void udsserver_handle_configchange(void)
1238 for (req
= all_requests
; req
; req
= req
->next
)
1240 if (req
->service_registration
)
1242 service_instance
*ptr
;
1243 for (ptr
= req
->service_registration
->instances
; ptr
; ptr
= ptr
->next
)
1244 rename_service(ptr
);
1249 mDNSlocal
void connect_callback(void *info
)
1252 dnssd_socklen_t len
;
1253 unsigned long optval
;
1254 dnssd_sockaddr_t cliaddr
;
1255 request_state
*rstate
;
1256 (void)info
; // Unused
1258 len
= (dnssd_socklen_t
) sizeof(cliaddr
);
1260 sd
= accept(listenfd
, (struct sockaddr
*) &cliaddr
, &len
);
1262 if (sd
== dnssd_InvalidSocket
)
1264 if (dnssd_errno() == dnssd_EWOULDBLOCK
) return;
1265 my_perror("ERROR: accept");
1271 // Some environments (e.g. OS X) support turning off SIGPIPE for a socket
1272 if (setsockopt(sd
, SOL_SOCKET
, SO_NOSIGPIPE
, &optval
, sizeof(optval
)) < 0)
1274 my_perror("ERROR: setsockopt - SO_NOSIGPIPE - aborting client");
1281 if (ioctlsocket(sd
, FIONBIO
, &optval
) != 0)
1283 if (fcntl(sd
, F_SETFL
, O_NONBLOCK
) != 0)
1286 my_perror("ERROR: fcntl(sd, F_SETFL, O_NONBLOCK) - aborting client");
1291 // allocate a request_state struct that will live with the socket
1292 rstate
= mallocL("connect_callback", sizeof(request_state
));
1293 if (!rstate
) FatalError("ERROR: malloc");
1294 bzero(rstate
, sizeof(request_state
));
1295 rstate
->ts
= t_morecoming
;
1298 LogOperation("%3d: Adding FD", rstate
->sd
);
1299 if ( mStatus_NoError
!= udsSupportAddFDToEventLoop( sd
, request_callback
, rstate
))
1301 rstate
->next
= all_requests
;
1302 all_requests
= rstate
;
1306 mDNSlocal
void request_callback(void *info
)
1308 request_state
*rstate
= info
;
1309 transfer_state result
;
1310 dnssd_sockaddr_t cliaddr
;
1311 int dedicated_error_socket
;
1316 result
= read_msg(rstate
);
1317 if (result
== t_morecoming
)
1321 if (result
== t_terminated
)
1323 abort_request(rstate
);
1324 unlink_request(rstate
);
1327 if (result
== t_error
)
1329 abort_request(rstate
);
1330 unlink_request(rstate
);
1334 if (rstate
->hdr
.version
!= VERSION
)
1336 LogMsg("ERROR: client incompatible with daemon (client version = %d, "
1337 "daemon version = %d)\n", rstate
->hdr
.version
, VERSION
);
1338 abort_request(rstate
);
1339 unlink_request(rstate
);
1343 if (validate_message(rstate
) < 0)
1345 // note that we cannot deliver an error message if validation fails, since the path to the error socket
1346 // may be contained in the (invalid) message body for some message types
1347 abort_request(rstate
);
1348 unlink_request(rstate
);
1349 LogMsg("Invalid message sent by client - may indicate a malicious program running on this machine!");
1353 // check if client wants silent operation
1354 if (rstate
->hdr
.flags
& IPC_FLAGS_NOREPLY
) rstate
->no_reply
= 1;
1356 dedicated_error_socket
= (rstate
->hdr
.op
== reg_record_request
|| rstate
->hdr
.op
== add_record_request
||
1357 rstate
->hdr
.op
== update_record_request
|| rstate
->hdr
.op
== remove_record_request
);
1359 if (((rstate
->hdr
.flags
& IPC_FLAGS_REUSE_SOCKET
) == 0) != dedicated_error_socket
)
1360 LogMsg("WARNING: client request %d with incorrect flags setting 0x%X", rstate
->hdr
.op
, rstate
->hdr
.flags
);
1362 // check if primary socket is to be used for synchronous errors, else open new socket
1363 if (dedicated_error_socket
)
1367 dnssd_sock_t errfd
= socket(AF_DNSSD
, SOCK_STREAM
, 0);
1368 if (errfd
== dnssd_InvalidSocket
)
1370 my_perror("ERROR: socket");
1371 abort_request(rstate
);
1372 unlink_request(rstate
);
1376 //LogOperation("request_callback: Opened dedicated errfd %d", errfd);
1378 #if defined(USE_TCP_LOOPBACK)
1381 port
.b
[0] = rstate
->msgdata
[0];
1382 port
.b
[1] = rstate
->msgdata
[1];
1383 rstate
->msgdata
+= 2;
1384 cliaddr
.sin_family
= AF_INET
;
1385 cliaddr
.sin_port
= port
.NotAnInteger
;
1386 cliaddr
.sin_addr
.s_addr
= inet_addr(MDNS_TCP_SERVERADDR
);
1390 char ctrl_path
[MAX_CTLPATH
];
1391 get_string(&rstate
->msgdata
, ctrl_path
, 256); // path is first element in message buffer
1392 bzero(&cliaddr
, sizeof(cliaddr
));
1393 cliaddr
.sun_family
= AF_LOCAL
;
1394 strcpy(cliaddr
.sun_path
, ctrl_path
);
1397 //LogOperation("request_callback: Connecting to “%s”", cliaddr.sun_path);
1398 if (connect(errfd
, (struct sockaddr
*)&cliaddr
, sizeof(cliaddr
)) < 0)
1400 //LogOperation("request_callback: Couldn't connect to “%s”", cliaddr.sun_path);
1401 my_perror("ERROR: connect");
1402 abort_request(rstate
);
1403 unlink_request(rstate
);
1407 if (ioctlsocket(errfd
, FIONBIO
, &opt
) != 0)
1409 if (fcntl(errfd
, F_SETFL
, O_NONBLOCK
) != 0)
1412 my_perror("ERROR: could not set control socket to non-blocking mode");
1413 abort_request(rstate
);
1414 unlink_request(rstate
);
1418 switch(rstate
->hdr
.op
)
1420 case reg_record_request
: err
= handle_regrecord_request (rstate
); break;
1421 case add_record_request
: err
= handle_add_request (rstate
); break;
1422 case update_record_request
: err
= handle_update_request (rstate
); break;
1423 case remove_record_request
: err
= handle_removerecord_request(rstate
); break;
1424 default: LogMsg("%3d: ERROR: udsserver_recv_request - unsupported request type: %d", rstate
->sd
, rstate
->hdr
.op
);
1427 //LogOperation("request_callback: Returning error code %d on socket %d", err, errfd);
1428 err
= dnssd_htonl(err
);
1429 nwritten
= send(errfd
, (dnssd_sockbuf_t
) &err
, sizeof(err
), 0);
1430 // On a freshly-created Unix Domain Socket, the kernel should *never* fail to buffer a four-byte write for us.
1431 // If not, we don't attempt to handle this failure, but we do log it.
1432 if (nwritten
< (int)sizeof(err
))
1433 LogMsg("ERROR: failed to write error response back to caller: %d %d %s",
1434 nwritten
, dnssd_errno(), dnssd_strerror(dnssd_errno()));
1435 //else LogOperation("request_callback: Returned error code %d on socket %d", err, errfd);
1437 //LogOperation("request_callback: Closed errfd %d", errfd);
1438 reset_connected_rstate(rstate
); // Reset ready to accept the next request on this pipe
1442 switch(rstate
->hdr
.op
)
1444 case resolve_request
: handle_resolve_request (rstate
); break;
1445 case query_request
: handle_query_request (rstate
); break;
1446 case browse_request
: handle_browse_request (rstate
); break;
1447 case reg_service_request
: handle_regservice_request(rstate
); break;
1448 case enumeration_request
: handle_enum_request (rstate
); break;
1449 case reconfirm_record_request
: handle_reconfirm_request (rstate
); break;
1450 case setdomain_request
: handle_setdomain_request (rstate
); break;
1451 default: LogMsg("%3d: ERROR: udsserver_recv_request - unsupported request type: %d", rstate
->sd
, rstate
->hdr
.op
);
1456 // mDNS operation functions. Each operation has 3 associated functions - a request handler that parses
1457 // the client's request and makes the appropriate mDNSCore call, a result handler (passed as a callback
1458 // to the mDNSCore routine) that sends results back to the client, and a termination routine that aborts
1459 // the mDNSCore operation if the client dies or closes its socket.
1461 // query and resolve calls have separate request handlers that parse the arguments from the client and
1462 // massage the name parameters appropriately, but the rest of the operations (making the query call,
1463 // delivering the result to the client, and termination) are identical.
1465 mDNSlocal
void handle_query_request(request_state
*rstate
)
1467 DNSServiceFlags flags
;
1470 uint16_t rrtype
, rrclass
;
1473 mDNSInterfaceID InterfaceID
;
1476 if (rstate
->ts
!= t_complete
)
1478 LogMsg("ERROR: handle_query_request - transfer state != t_complete");
1481 ptr
= rstate
->msgdata
;
1484 LogMsg("ERROR: handle_query_request - NULL msgdata");
1488 flags
= get_flags(&ptr
);
1489 ifi
= get_long(&ptr
);
1490 if (get_string(&ptr
, name
, 256) < 0) goto bad_param
;
1491 rrtype
= get_short(&ptr
);
1492 rrclass
= get_short(&ptr
);
1493 InterfaceID
= mDNSPlatformInterfaceIDfromInterfaceIndex(gmDNS
, ifi
);
1494 if (ifi
&& !InterfaceID
) goto bad_param
;
1496 q
= mallocL("DNSQuestion", sizeof(DNSQuestion
));
1497 if (!q
) FatalError("ERROR: handle_query - malloc");
1498 bzero(q
, sizeof(DNSQuestion
));
1500 q
->InterfaceID
= InterfaceID
;
1501 q
->Target
= zeroAddr
;
1502 if (!MakeDomainNameFromDNSNameString(&q
->qname
, name
)) { freeL("DNSQuestion", q
); goto bad_param
; }
1504 q
->qclass
= rrclass
;
1505 q
->LongLived
= (flags
& kDNSServiceFlagsLongLivedQuery
) != 0;
1506 q
->ExpectUnique
= mDNSfalse
;
1507 q
->ForceMCast
= (flags
& kDNSServiceFlagsForceMulticast
) != 0;
1508 q
->ReturnCNAME
= (flags
& kDNSServiceFlagsReturnCNAME
) != 0;
1509 q
->QuestionCallback
= question_result_callback
;
1510 q
->QuestionContext
= rstate
;
1512 rstate
->termination_context
= q
;
1513 rstate
->terminate
= question_termination_callback
;
1515 LogOperation("%3d: DNSServiceQueryRecord(%##s, %s) START", rstate
->sd
, q
->qname
.c
, DNSTypeName(q
->qtype
));
1516 result
= mDNS_StartQuery(gmDNS
, q
);
1517 if (result
!= mStatus_NoError
) LogMsg("ERROR: mDNS_StartQuery: %d", (int)result
);
1519 if (result
) rstate
->terminate
= NULL
;
1520 if (deliver_error(rstate
, result
) < 0) goto error
;
1524 deliver_error(rstate
, mStatus_BadParamErr
);
1525 rstate
->terminate
= NULL
; // don't try to terminate insuccessful Core calls
1527 abort_request(rstate
);
1528 unlink_request(rstate
);
1532 mDNSlocal
void handle_resolve_request(request_state
*rstate
)
1534 DNSServiceFlags flags
;
1535 uint32_t interfaceIndex
;
1536 mDNSInterfaceID InterfaceID
;
1537 char name
[256], regtype
[MAX_ESCAPED_DOMAIN_NAME
], domain
[MAX_ESCAPED_DOMAIN_NAME
];
1538 char *ptr
; // message data pointer
1540 resolve_termination_t
*term
;
1543 if (rstate
->ts
!= t_complete
)
1545 LogMsg("ERROR: handle_resolve_request - transfer state != t_complete");
1546 abort_request(rstate
);
1547 unlink_request(rstate
);
1551 // extract the data from the message
1552 ptr
= rstate
->msgdata
;
1555 LogMsg("ERROR: handle_resolve_request - NULL msgdata");
1556 abort_request(rstate
);
1557 unlink_request(rstate
);
1560 flags
= get_flags(&ptr
);
1561 interfaceIndex
= get_long(&ptr
);
1562 InterfaceID
= mDNSPlatformInterfaceIDfromInterfaceIndex(gmDNS
, interfaceIndex
);
1563 if (interfaceIndex
&& !InterfaceID
)
1564 { LogMsg("ERROR: handle_resolve_request - Couldn't find InterfaceID for interfaceIndex %d", interfaceIndex
); goto bad_param
; }
1565 if (get_string(&ptr
, name
, 256) < 0 ||
1566 get_string(&ptr
, regtype
, MAX_ESCAPED_DOMAIN_NAME
) < 0 ||
1567 get_string(&ptr
, domain
, MAX_ESCAPED_DOMAIN_NAME
) < 0)
1568 { LogMsg("ERROR: handle_resolve_request - Couldn't read name/regtype/domain"); goto bad_param
; }
1570 // free memory in rstate since we don't need it anymore
1571 freeL("handle_resolve_request", rstate
->msgbuf
);
1572 rstate
->msgbuf
= NULL
;
1574 if (build_domainname_from_strings(&fqdn
, name
, regtype
, domain
) < 0)
1575 { LogMsg("ERROR: handle_resolve_request - Couldn't build_domainname_from_strings “%s” “%s” “%s”", name
, regtype
, domain
); goto bad_param
; }
1577 // set up termination info
1578 term
= mallocL("handle_resolve_request", sizeof(resolve_termination_t
));
1579 bzero(term
, sizeof(*term
));
1580 if (!term
) FatalError("ERROR: malloc");
1583 term
->qsrv
.InterfaceID
= InterfaceID
;
1584 term
->qsrv
.Target
= zeroAddr
;
1585 memcpy(&term
->qsrv
.qname
, &fqdn
, MAX_DOMAIN_NAME
);
1586 term
->qsrv
.qtype
= kDNSType_SRV
;
1587 term
->qsrv
.qclass
= kDNSClass_IN
;
1588 term
->qsrv
.LongLived
= mDNSfalse
;
1589 term
->qsrv
.ExpectUnique
= mDNStrue
;
1590 term
->qsrv
.ForceMCast
= mDNSfalse
;
1591 term
->qsrv
.QuestionCallback
= resolve_result_callback
;
1592 term
->qsrv
.QuestionContext
= rstate
;
1594 term
->qtxt
.InterfaceID
= InterfaceID
;
1595 term
->qtxt
.Target
= zeroAddr
;
1596 memcpy(&term
->qtxt
.qname
, &fqdn
, MAX_DOMAIN_NAME
);
1597 term
->qtxt
.qtype
= kDNSType_TXT
;
1598 term
->qtxt
.qclass
= kDNSClass_IN
;
1599 term
->qtxt
.LongLived
= mDNSfalse
;
1600 term
->qtxt
.ExpectUnique
= mDNStrue
;
1601 term
->qtxt
.ForceMCast
= mDNSfalse
;
1602 term
->qtxt
.QuestionCallback
= resolve_result_callback
;
1603 term
->qtxt
.QuestionContext
= rstate
;
1605 term
->rstate
= rstate
;
1606 rstate
->termination_context
= term
;
1607 rstate
->terminate
= resolve_termination_callback
;
1609 // ask the questions
1610 LogOperation("%3d: DNSServiceResolve(%##s) START", rstate
->sd
, term
->qsrv
.qname
.c
);
1611 err
= mDNS_StartQuery(gmDNS
, &term
->qsrv
);
1612 if (!err
) err
= mDNS_StartQuery(gmDNS
, &term
->qtxt
);
1616 freeL("handle_resolve_request", term
);
1617 rstate
->terminate
= NULL
; // prevent abort_request() from invoking termination callback
1619 if (deliver_error(rstate
, err
) < 0 || err
)
1621 abort_request(rstate
);
1622 unlink_request(rstate
);
1627 deliver_error(rstate
, mStatus_BadParamErr
);
1628 abort_request(rstate
);
1629 unlink_request(rstate
);
1632 mDNSlocal
void resolve_termination_callback(void *context
)
1634 resolve_termination_t
*term
= context
;
1639 LogMsg("ERROR: resolve_termination_callback: double termination");
1643 LogOperation("%3d: DNSServiceResolve(%##s) STOP", rs
->sd
, term
->qtxt
.qname
.c
);
1645 mDNS_StopQuery(gmDNS
, &term
->qtxt
);
1646 mDNS_StopQuery(gmDNS
, &term
->qsrv
);
1648 freeL("resolve_termination_callback", term
);
1649 rs
->termination_context
= NULL
;
1652 mDNSlocal
void resolve_result_callback(mDNS
*const m
, DNSQuestion
*question
, const ResourceRecord
*const answer
, mDNSBool AddRecord
)
1655 char fullname
[MAX_ESCAPED_DOMAIN_NAME
], target
[MAX_ESCAPED_DOMAIN_NAME
];
1657 transfer_state result
;
1659 request_state
*rs
= question
->QuestionContext
;
1660 resolve_termination_t
*res
= rs
->termination_context
;
1663 LogOperation("%3d: DNSServiceResolve(%##s, %s) %s %s",
1664 rs
->sd
, question
->qname
.c
, DNSTypeName(question
->qtype
), AddRecord
? "ADD" : "RMV", RRDisplayString(m
, answer
));
1666 // This code used to do this trick of just keeping a copy of the pointer to
1667 // the answer record in the cache, but the unicast query code doesn't currently
1668 // put its answer records in the cache, so for now we can't do this.
1672 // After unicast query code is updated to store its records in the common cache, use this...
1673 // if (answer->rrtype == kDNSType_SRV && res->srv == answer) res->srv = mDNSNULL;
1674 // if (answer->rrtype == kDNSType_TXT && res->txt == answer) res->txt = mDNSNULL;
1675 // intead of this...
1676 if (answer
->rrtype
== kDNSType_SRV
&& res
->srv
&& SameRDataBody(answer
, (RDataBody
*)&res
->srvdata
))
1677 res
->srv
= mDNSfalse
;
1678 if (answer
->rrtype
== kDNSType_TXT
&& res
->txt
&& answer
->rdlength
== res
->txtlen
&& SameRDataBody(answer
, (RDataBody
*)&res
->txtdata
))
1679 res
->txt
= mDNSfalse
;
1683 // After unicast query code is updated to store its records in the common cache, use this...
1684 // if (answer->rrtype == kDNSType_SRV) res->srv = answer;
1685 // if (answer->rrtype == kDNSType_TXT) res->txt = answer;
1686 // intead of this...
1687 if (answer
->rrtype
== kDNSType_SRV
)
1689 res
->srvdata
= answer
->rdata
->u
.srv
;
1690 res
->srv
= mDNStrue
;
1692 if (answer
->rrtype
== kDNSType_TXT
)
1694 if (answer
->rdlength
> AbsoluteMaxDNSMessageData
) return;
1695 res
->txtlen
= answer
->rdlength
;
1696 mDNSPlatformMemCopy(answer
->rdata
->u
.data
, res
->txtdata
, res
->txtlen
);
1697 res
->txt
= mDNStrue
;
1700 if (!res
->txt
|| !res
->srv
) return; // only deliver result to client if we have both answers
1702 ConvertDomainNameToCString(answer
->name
, fullname
);
1703 ConvertDomainNameToCString(&res
->srvdata
.target
, target
);
1705 // calculate reply length
1706 len
+= sizeof(DNSServiceFlags
);
1707 len
+= sizeof(uint32_t); // interface index
1708 len
+= sizeof(DNSServiceErrorType
);
1709 len
+= strlen(fullname
) + 1;
1710 len
+= strlen(target
) + 1;
1711 len
+= 2 * sizeof(uint16_t); // port, txtLen
1714 // allocate/init reply header
1715 rep
= create_reply(resolve_reply_op
, len
, rs
);
1716 rep
->rhdr
->flags
= dnssd_htonl(0);
1717 rep
->rhdr
->ifi
= dnssd_htonl(mDNSPlatformInterfaceIndexfromInterfaceID(gmDNS
, answer
->InterfaceID
));
1718 rep
->rhdr
->error
= dnssd_htonl(kDNSServiceErr_NoError
);
1722 // write reply data to message
1723 put_string(fullname
, &data
);
1724 put_string(target
, &data
);
1725 *data
++ = res
->srvdata
.port
.b
[0];
1726 *data
++ = res
->srvdata
.port
.b
[1];
1727 put_short(res
->txtlen
, &data
);
1728 put_rdata(res
->txtlen
, res
->txtdata
, &data
);
1730 result
= send_msg(rep
);
1731 if (result
== t_error
|| result
== t_terminated
)
1735 freeL("resolve_result_callback", rep
);
1737 else if (result
== t_complete
) freeL("resolve_result_callback", rep
);
1738 else append_reply(rs
, rep
);
1741 // what gets called when a resolve is completed and we need to send the data back to the client
1742 mDNSlocal
void question_result_callback(mDNS
*const m
, DNSQuestion
*question
, const ResourceRecord
*const answer
, mDNSBool AddRecord
)
1745 char name
[MAX_ESCAPED_DOMAIN_NAME
];
1746 request_state
*req
= question
->QuestionContext
;
1751 LogOperation("%3d: DNSServiceQueryRecord(%##s, %s) RESULT %s", req
->sd
, question
->qname
.c
, DNSTypeName(question
->qtype
), RRDisplayString(m
, answer
));
1752 //mDNS_StopQuery(m, question);
1754 if (answer
->rdlength
== 0)
1756 deliver_async_error(req
, query_reply_op
, kDNSServiceErr_NoSuchRecord
);
1760 // calculate reply data length
1761 len
= sizeof(DNSServiceFlags
);
1762 len
+= 2 * sizeof(uint32_t); // if index + ttl
1763 len
+= sizeof(DNSServiceErrorType
);
1764 len
+= 3 * sizeof(uint16_t); // type, class, rdlen
1765 len
+= answer
->rdlength
;
1766 ConvertDomainNameToCString(answer
->name
, name
);
1767 len
+= strlen(name
) + 1;
1769 rep
= create_reply(query_reply_op
, len
, req
);
1771 rep
->rhdr
->flags
= dnssd_htonl(AddRecord
? kDNSServiceFlagsAdd
: 0);
1772 rep
->rhdr
->ifi
= dnssd_htonl(mDNSPlatformInterfaceIndexfromInterfaceID(gmDNS
, answer
->InterfaceID
));
1773 rep
->rhdr
->error
= dnssd_htonl(kDNSServiceErr_NoError
);
1777 put_string(name
, &data
);
1778 put_short(answer
->rrtype
, &data
);
1779 put_short(answer
->rrclass
, &data
);
1780 put_short(answer
->rdlength
, &data
);
1781 put_rdata(answer
->rdlength
, answer
->rdata
->u
.data
, &data
);
1782 put_long(AddRecord
? answer
->rroriginalttl
: 0, &data
);
1784 append_reply(req
, rep
);
1788 mDNSlocal
void question_termination_callback(void *context
)
1790 DNSQuestion
*q
= context
;
1791 LogOperation("%3d: DNSServiceQueryRecord(%##s, %s) STOP", ((request_state
*)q
->QuestionContext
)->sd
, q
->qname
.c
, DNSTypeName(q
->qtype
));
1792 mDNS_StopQuery(gmDNS
, q
); // no need to error check
1793 freeL("question_termination_callback", q
);
1796 // If there's a comma followed by another character,
1797 // FindFirstSubType overwrites the comma with a nul and returns the pointer to the next character.
1798 // Otherwise, it returns a pointer to the final nul at the end of the string
1799 mDNSlocal
char *FindFirstSubType(char *p
)
1803 if (p
[0] == '\\' && p
[1]) p
+= 2;
1804 else if (p
[0] == ',' && p
[1]) { *p
++ = 0; return(p
); }
1810 // If there's a comma followed by another character,
1811 // FindNextSubType overwrites the comma with a nul and returns the pointer to the next character.
1812 // If it finds an illegal unescaped dot in the subtype name, it returns mDNSNULL
1813 // Otherwise, it returns a pointer to the final nul at the end of the string
1814 mDNSlocal
char *FindNextSubType(char *p
)
1818 if (p
[0] == '\\' && p
[1]) // If escape character
1819 p
+= 2; // ignore following character
1820 else if (p
[0] == ',') // If we found a comma
1825 else if (p
[0] == '.')
1832 // Returns -1 if illegal subtype found
1833 mDNSexport mDNSs32
ChopSubTypes(char *regtype
)
1835 mDNSs32 NumSubTypes
= 0;
1836 char *stp
= FindFirstSubType(regtype
);
1837 while (stp
&& *stp
) // If we found a comma...
1839 if (*stp
== ',') return(-1);
1841 stp
= FindNextSubType(stp
);
1843 if (!stp
) return(-1);
1844 return(NumSubTypes
);
1847 mDNSexport AuthRecord
*AllocateSubTypes(mDNSs32 NumSubTypes
, char *p
)
1849 AuthRecord
*st
= mDNSNULL
;
1853 st
= mallocL("ServiceSubTypes", NumSubTypes
* sizeof(AuthRecord
));
1854 if (!st
) return(mDNSNULL
);
1855 for (i
= 0; i
< NumSubTypes
; i
++)
1857 mDNS_SetupResourceRecord(&st
[i
], mDNSNULL
, mDNSInterface_Any
, kDNSQType_ANY
, kStandardTTL
, 0, mDNSNULL
, mDNSNULL
);
1860 if (!MakeDomainNameFromDNSNameString(st
[i
].resrec
.name
, p
))
1861 { freeL("ServiceSubTypes", st
); return(mDNSNULL
); }
1867 #ifdef _HAVE_SETDOMAIN_SUPPORT_
1868 mDNSlocal
void free_defdomain(mDNS
*const m
, AuthRecord
*const rr
, mStatus result
)
1871 if (result
== mStatus_MemFree
) free(rr
->RecordContext
); // context is the enclosing list structure
1875 mDNSlocal
void handle_setdomain_request(request_state
*request
)
1877 mStatus err
= mStatus_NoError
;
1879 char domainstr
[MAX_ESCAPED_DOMAIN_NAME
];
1881 DNSServiceFlags flags
;
1882 #ifdef _HAVE_SETDOMAIN_SUPPORT_
1887 if (request
->ts
!= t_complete
)
1889 LogMsg("ERROR: handle_setdomain_request - transfer state != t_complete");
1890 abort_request(request
);
1891 unlink_request(request
);
1895 // extract flags/domain from message
1896 ptr
= request
->msgdata
;
1897 flags
= get_flags(&ptr
);
1898 if (get_string(&ptr
, domainstr
, MAX_ESCAPED_DOMAIN_NAME
) < 0 ||
1899 !MakeDomainNameFromDNSNameString(&domain
, domainstr
))
1900 { err
= mStatus_BadParamErr
; goto end
; }
1902 freeL("handle_setdomain_request", request
->msgbuf
);
1903 request
->msgbuf
= NULL
;
1905 debugf("%3d: DNSServiceSetDefaultDomainForUser(%##s)", request
->sd
, domain
.c
);
1907 #ifdef _HAVE_SETDOMAIN_SUPPORT_
1908 // this functionality currently only used for Apple-specific configuration, so we don't burned other platforms by mandating
1909 // the existence of this socket option
1910 xuclen
= sizeof(xuc
);
1911 if (getsockopt(request
->sd
, 0, LOCAL_PEERCRED
, &xuc
, &xuclen
))
1912 { my_perror("ERROR: getsockopt, LOCAL_PEERCRED"); err
= mStatus_UnknownErr
; goto end
; }
1913 if (xuc
.cr_version
!= XUCRED_VERSION
) { LogMsg("getsockopt, LOCAL_PEERCRED - bad version"); err
= mStatus_UnknownErr
; goto end
; }
1914 LogMsg("Default domain %s %s for UID %d", domainstr
, flags
& kDNSServiceFlagsAdd
? "set" : "removed", xuc
.cr_uid
);
1916 if (flags
& kDNSServiceFlagsAdd
)
1918 // register a local-only PRT record
1919 default_browse_list_t
*newelem
= malloc(sizeof(default_browse_list_t
));
1920 if (!newelem
) { LogMsg("ERROR: malloc"); err
= mStatus_NoMemoryErr
; goto end
; }
1921 mDNS_SetupResourceRecord(&newelem
->ptr_rec
, mDNSNULL
, mDNSInterface_LocalOnly
, kDNSType_PTR
, 7200, kDNSRecordTypeShared
, free_defdomain
, newelem
);
1922 MakeDomainNameFromDNSNameString(&newelem
->ptr_rec
.resrec
.name
, mDNS_DomainTypeNames
[mDNS_DomainTypeBrowseDefault
]);
1923 AppendDNSNameString (&newelem
->ptr_rec
.resrec
.name
, "local");
1924 AssignDomainName(&newelem
->ptr_rec
.resrec
.rdata
->u
.name
, &domain
);
1925 newelem
->uid
= xuc
.cr_uid
;
1926 err
= mDNS_Register(gmDNS
, &newelem
->ptr_rec
);
1927 if (err
) free(newelem
);
1931 newelem
->next
= default_browse_list
;
1932 default_browse_list
= newelem
;
1938 // remove - find in list, deregister
1939 default_browse_list_t
*ptr
= default_browse_list
, *prev
= NULL
;
1942 if (SameDomainName(&ptr
->ptr_rec
.resrec
.rdata
->u
.name
, &domain
))
1944 if (prev
) prev
->next
= ptr
->next
;
1945 else default_browse_list
= ptr
->next
;
1946 err
= mDNS_Deregister(gmDNS
, &ptr
->ptr_rec
);
1952 if (!ptr
) { LogMsg("Attempt to remove nonexistent domain %s for UID %d", domainstr
, xuc
.cr_uid
); err
= mStatus_Invalid
; }
1955 err
= mStatus_NoError
;
1956 #endif // _HAVE_SETDOMAIN_SUPPORT_
1959 deliver_error(request
, err
);
1960 abort_request(request
);
1961 unlink_request(request
);
1964 // Generates a response message giving name, type, domain, plus interface index,
1965 // suitable for a browse result or service registration result.
1966 // On successful completion rep is set to point to a malloc'd reply_state struct
1967 mDNSlocal mStatus
GenerateNTDResponse(domainname
*servicename
, mDNSInterfaceID id
, request_state
*request
, reply_state
**rep
)
1970 domainname type
, dom
;
1972 if (!DeconstructServiceName(servicename
, &name
, &type
, &dom
))
1973 return kDNSServiceErr_Invalid
;
1976 char namestr
[MAX_DOMAIN_LABEL
+1];
1977 char typestr
[MAX_ESCAPED_DOMAIN_NAME
];
1978 char domstr
[MAX_ESCAPED_DOMAIN_NAME
];
1982 ConvertDomainLabelToCString_unescaped(&name
, namestr
);
1983 ConvertDomainNameToCString(&type
, typestr
);
1984 ConvertDomainNameToCString(&dom
, domstr
);
1986 // Calculate reply data length
1987 len
= sizeof(DNSServiceFlags
);
1988 len
+= sizeof(uint32_t); // if index
1989 len
+= sizeof(DNSServiceErrorType
);
1990 len
+= (int) (strlen(namestr
) + 1);
1991 len
+= (int) (strlen(typestr
) + 1);
1992 len
+= (int) (strlen(domstr
) + 1);
1994 // Build reply header
1995 *rep
= create_reply(query_reply_op
, len
, request
);
1996 (*rep
)->rhdr
->flags
= dnssd_htonl(0);
1997 (*rep
)->rhdr
->ifi
= dnssd_htonl(mDNSPlatformInterfaceIndexfromInterfaceID(gmDNS
, id
));
1998 (*rep
)->rhdr
->error
= dnssd_htonl(kDNSServiceErr_NoError
);
2001 data
= (*rep
)->sdata
;
2002 put_string(namestr
, &data
);
2003 put_string(typestr
, &data
);
2004 put_string(domstr
, &data
);
2006 return mStatus_NoError
;
2010 mDNSlocal
void FoundInstance(mDNS
*const m
, DNSQuestion
*question
, const ResourceRecord
*const answer
, mDNSBool AddRecord
)
2012 request_state
*req
= question
->QuestionContext
;
2016 if (answer
->rrtype
!= kDNSType_PTR
)
2017 { LogMsg("%3d: FoundInstance: Should not be called with rrtype %d (not a PTR record)", req
->sd
, answer
->rrtype
); return; }
2019 if (GenerateNTDResponse(&answer
->rdata
->u
.name
, answer
->InterfaceID
, req
, &rep
) != mStatus_NoError
)
2021 LogMsg("%3d: FoundInstance: %##s PTR %##s received from network is not valid DNS-SD service pointer",
2022 req
->sd
, answer
->name
->c
, answer
->rdata
->u
.name
.c
);
2026 LogOperation("%3d: DNSServiceBrowse(%##s, %s) RESULT %s %s",
2027 req
->sd
, question
->qname
.c
, DNSTypeName(question
->qtype
), AddRecord
? "Add" : "Rmv", RRDisplayString(m
, answer
));
2029 if (AddRecord
) rep
->rhdr
->flags
|= dnssd_htonl(kDNSServiceFlagsAdd
);
2030 append_reply(req
, rep
);
2033 mDNSlocal mStatus
add_domain_to_browser(browser_info_t
*info
, const domainname
*d
)
2038 for (p
= info
->browsers
; p
; p
= p
->next
)
2040 if (SameDomainName(&p
->domain
, d
))
2041 { debugf("add_domain_to_browser - attempt to add domain %##d already in list", d
->c
); return mStatus_AlreadyRegistered
; }
2044 b
= mallocL("browser_t", sizeof(*b
));
2045 if (!b
) return mStatus_NoMemoryErr
;
2046 AssignDomainName(&b
->domain
, d
);
2047 err
= mDNS_StartBrowse(gmDNS
, &b
->q
, &info
->regtype
, d
, info
->interface_id
, info
->ForceMCast
, FoundInstance
, info
->rstate
);
2050 LogMsg("mDNS_StartBrowse returned %d for type %##s domain %##s", err
, info
->regtype
.c
, d
->c
);
2051 freeL("browser_t", b
);
2055 b
->next
= info
->browsers
;
2061 mDNSlocal
void handle_browse_request(request_state
*request
)
2063 DNSServiceFlags flags
;
2064 uint32_t interfaceIndex
;
2065 mDNSInterfaceID InterfaceID
;
2066 char regtype
[MAX_ESCAPED_DOMAIN_NAME
], domain
[MAX_ESCAPED_DOMAIN_NAME
];
2067 domainname typedn
, d
, temp
;
2068 mDNSs32 NumSubTypes
;
2070 mStatus err
= mStatus_NoError
;
2071 DNameListElem
*search_domain_list
, *sdom
;
2072 browser_info_t
*info
= NULL
;
2074 if (request
->ts
!= t_complete
)
2076 LogMsg("ERROR: handle_browse_request - transfer state != t_complete");
2077 abort_request(request
);
2078 unlink_request(request
);
2082 // extract data from message
2083 ptr
= request
->msgdata
;
2084 flags
= get_flags(&ptr
);
2085 interfaceIndex
= get_long(&ptr
);
2086 if (get_string(&ptr
, regtype
, MAX_ESCAPED_DOMAIN_NAME
) < 0 ||
2087 get_string(&ptr
, domain
, MAX_ESCAPED_DOMAIN_NAME
) < 0)
2088 { err
= mStatus_BadParamErr
; goto error
; }
2089 freeL("handle_browse_request", request
->msgbuf
);
2090 request
->msgbuf
= NULL
;
2092 InterfaceID
= mDNSPlatformInterfaceIDfromInterfaceIndex(gmDNS
, interfaceIndex
);
2093 if (interfaceIndex
&& !InterfaceID
) { err
= mStatus_BadParamErr
; goto error
; }
2095 #if defined(MDNS_LAZY_REGISTER_SEARCH_DOMAINS)
2096 if ( !domain
|| ( domain
[0] == '\0' ) )
2098 dDNS_RegisterSearchDomains( gmDNS
);
2103 NumSubTypes
= ChopSubTypes(regtype
); // Note: Modifies regtype string to remove trailing subtypes
2104 if (NumSubTypes
< 0 || NumSubTypes
> 1) { err
= mStatus_BadParamErr
; goto error
; }
2105 if (NumSubTypes
== 1 && !AppendDNSNameString(&typedn
, regtype
+ strlen(regtype
) + 1))
2106 { err
= mStatus_BadParamErr
; goto error
; }
2108 if (!regtype
[0] || !AppendDNSNameString(&typedn
, regtype
)) { err
= mStatus_BadParamErr
; goto error
; }
2110 if (!MakeDomainNameFromDNSNameString(&temp
, regtype
)) { err
= mStatus_BadParamErr
; goto error
; }
2111 if (temp
.c
[0] > 15 && domain
[0] == 0) strcpy(domain
, "local."); // For over-long service types, we only allow domain "local"
2113 // allocate and set up browser info
2114 info
= mallocL("browser_info_t", sizeof(*info
));
2115 if (!info
) { err
= mStatus_NoMemoryErr
; goto error
; }
2117 request
->browser_info
= info
;
2118 info
->ForceMCast
= (flags
& kDNSServiceFlagsForceMulticast
) != 0;
2119 info
->interface_id
= InterfaceID
;
2120 AssignDomainName(&info
->regtype
, &typedn
);
2121 info
->rstate
= request
;
2122 info
->default_domain
= !domain
[0];
2123 info
->browsers
= NULL
;
2125 // setup termination context
2126 request
->termination_context
= info
;
2127 request
->terminate
= browse_termination_callback
;
2129 LogOperation("%3d: DNSServiceBrowse(\"%##s\", \"%s\") START", request
->sd
, info
->regtype
.c
, domain
);
2132 if (!MakeDomainNameFromDNSNameString(&d
, domain
)) { err
= mStatus_BadParamErr
; goto error
; }
2133 err
= add_domain_to_browser(info
, &d
);
2138 search_domain_list
= mDNSPlatformGetSearchDomainList();
2139 for (sdom
= search_domain_list
; sdom
; sdom
= sdom
->next
)
2141 err
= add_domain_to_browser(info
, &sdom
->name
);
2144 if (SameDomainName(&sdom
->name
, &localdomain
)) break;
2145 else err
= mStatus_NoError
; // suppress errors for non-local "default" domains
2149 mDNS_FreeDNameList(search_domain_list
);
2152 deliver_error(request
, err
);
2156 if (info
) freeL("browser_info_t", info
);
2157 if (request
->termination_context
) request
->termination_context
= NULL
;
2158 deliver_error(request
, err
);
2159 abort_request(request
);
2160 unlink_request(request
);
2163 mDNSlocal
void browse_termination_callback(void *context
)
2165 browser_info_t
*info
= context
;
2170 while(info
->browsers
)
2172 ptr
= info
->browsers
;
2173 info
->browsers
= ptr
->next
;
2174 LogOperation("%3d: DNSServiceBrowse(%##s) STOP", info
->rstate
->sd
, ptr
->q
.qname
.c
);
2175 mDNS_StopBrowse(gmDNS
, &ptr
->q
); // no need to error-check result
2176 freeL("browse_termination_callback", ptr
);
2179 info
->rstate
->termination_context
= NULL
;
2180 freeL("browser_info", info
);
2183 mDNSexport
void udsserver_default_browse_domain_changed(const domainname
*d
, mDNSBool add
)
2187 for (r
= all_requests
; r
; r
= r
->next
)
2189 browser_info_t
*info
= r
->browser_info
;
2191 if (!info
|| !info
->default_domain
) continue;
2192 if (add
) add_domain_to_browser(info
, d
);
2195 browser_t
**ptr
= &info
->browsers
;
2198 if (SameDomainName(&(*ptr
)->domain
, d
))
2200 browser_t
*remove
= *ptr
;
2201 *ptr
= (*ptr
)->next
;
2202 if (remove
->q
.LongLived
)
2204 // Give goodbyes for known answers.
2205 // Note that this a special case where we know that the QuestionCallback function is our own
2206 // code (it's FoundInstance), and that callback routine doesn't ever cancel its operation, so we
2207 // don't need to guard against the question being cancelled mid-loop the way the mDNSCore routines do.
2208 CacheRecord
*ka
= remove
->q
.uDNS_info
.knownAnswers
;
2209 while (ka
) { remove
->q
.QuestionCallback(gmDNS
, &remove
->q
, &ka
->resrec
, mDNSfalse
); ka
= ka
->next
; }
2211 mDNS_StopBrowse(gmDNS
, &remove
->q
);
2212 freeL("browser_t", remove
);
2215 ptr
= &(*ptr
)->next
;
2217 LogMsg("Requested removal of default domain %##s not in list for sd %d", d
->c
, r
->sd
);
2222 // Count how many other service records we have locally with the same name, but different rdata.
2223 // For auto-named services, we can have at most one per machine -- if we allowed two auto-named services of
2224 // the same type on the same machine, we'd get into an infinite autoimmune-response loop of continuous renaming.
2225 mDNSexport
int CountPeerRegistrations(mDNS
*const m
, ServiceRecordSet
*const srs
)
2228 ResourceRecord
*r
= &srs
->RR_SRV
.resrec
;
2230 ServiceRecordSet
*s
;
2232 for (rr
= m
->ResourceRecords
; rr
; rr
=rr
->next
)
2233 if (rr
->resrec
.rrtype
== kDNSType_SRV
&& SameDomainName(rr
->resrec
.name
, r
->name
) && !SameRData(&rr
->resrec
, r
))
2236 for (rr
= m
->uDNS_info
.RecordRegistrations
; rr
; rr
=rr
->next
)
2237 if (rr
->uDNS_info
.state
!= regState_Unregistered
&& rr
->resrec
.rrtype
== kDNSType_SRV
&& SameDomainName(rr
->resrec
.name
, r
->name
) && !SameRData(&rr
->resrec
, r
))
2240 for (s
= m
->uDNS_info
.ServiceRegistrations
; s
; s
= s
->next
)
2241 if (s
->uDNS_info
.state
!= regState_Unregistered
&& SameDomainName(s
->RR_SRV
.resrec
.name
, r
->name
) && !SameRData(&s
->RR_SRV
.resrec
, r
))
2244 verbosedebugf("%d peer registrations for %##s", count
, r
->name
->c
);
2248 mDNSexport
int CountExistingRegistrations(domainname
*srv
, mDNSIPPort port
)
2252 for (rr
= gmDNS
->ResourceRecords
; rr
; rr
=rr
->next
)
2253 if (rr
->resrec
.rrtype
== kDNSType_SRV
&&
2254 rr
->resrec
.rdata
->u
.srv
.port
.NotAnInteger
== port
.NotAnInteger
&&
2255 SameDomainName(rr
->resrec
.name
, srv
))
2260 mDNSlocal mStatus
register_service_instance(request_state
*request
, const domainname
*domain
)
2262 service_info
*info
= request
->service_registration
;
2263 service_instance
*ptr
, *instance
;
2267 for (ptr
= info
->instances
; ptr
; ptr
= ptr
->next
)
2269 if (SameDomainName(&ptr
->domain
, domain
))
2270 { LogMsg("register_service_instance: domain %##s already registered", domain
->c
); return mStatus_AlreadyRegistered
; }
2273 instance_size
= sizeof(*instance
);
2274 if (info
->txtlen
> sizeof(RDataBody
)) instance_size
+= (info
->txtlen
- sizeof(RDataBody
));
2275 instance
= mallocL("service_instance", instance_size
);
2276 if (!instance
) { my_perror("ERROR: malloc"); return mStatus_NoMemoryErr
; }
2278 instance
->subtypes
= AllocateSubTypes(info
->num_subtypes
, info
->type_as_string
);
2279 if (info
->num_subtypes
&& !instance
->subtypes
)
2280 { free_service_instance(instance
); instance
= NULL
; FatalError("ERROR: malloc"); }
2281 instance
->request
= request
;
2282 instance
->sd
= request
->sd
;
2283 instance
->autoname
= info
->autoname
;
2284 instance
->autorename
= info
->autorename
;
2285 instance
->allowremotequery
= info
->allowremotequery
;
2286 instance
->rename_on_memfree
= 0;
2287 instance
->name
= info
->name
;
2288 AssignDomainName(&instance
->domain
, domain
);
2289 instance
->default_local
= (info
->default_domain
&& SameDomainName(domain
, &localdomain
));
2290 result
= mDNS_RegisterService(gmDNS
, &instance
->srs
, &instance
->name
, &info
->type
, domain
, info
->host
.c
[0] ? &info
->host
: NULL
, info
->port
,
2291 info
->txtdata
, info
->txtlen
, instance
->subtypes
, info
->num_subtypes
, info
->InterfaceID
, regservice_callback
, instance
);
2293 if (result
) free_service_instance(instance
);
2296 instance
->next
= info
->instances
;
2297 info
->instances
= instance
;
2302 mDNSexport
void udsserver_default_reg_domain_changed(const domainname
*d
, mDNSBool add
)
2304 request_state
*rstate
;
2307 LogMsg("%s registration domain %##s", add
? "Adding" : "Removing", d
->c
);
2308 for (rstate
= all_requests
; rstate
; rstate
= rstate
->next
)
2310 if (rstate
->terminate
!= regservice_termination_callback
) continue;
2311 info
= rstate
->service_registration
;
2312 if (!info
) { LogMsg("udsserver_default_reg_domain_changed - NULL service info"); continue; } // this should never happen
2313 if (!info
->default_domain
) continue;
2315 // valid default registration
2316 if (add
) register_service_instance(rstate
, d
);
2319 // find the instance to remove
2320 service_instance
*si
= rstate
->service_registration
->instances
, *prev
= NULL
;
2323 if (SameDomainName(&si
->domain
, d
))
2326 if (prev
) prev
->next
= si
->next
;
2327 else info
->instances
= si
->next
;
2328 err
= mDNS_DeregisterService(gmDNS
, &si
->srs
);
2331 LogMsg("udsserver_default_reg_domain_changed - mDNS_DeregisterService err %d", err
);
2332 free_service_instance(si
);
2339 if (!si
) debugf("udsserver_default_reg_domain_changed - domain %##s not registered", d
->c
); // normal if registration failed
2344 // service registration
2345 mDNSlocal
void handle_regservice_request(request_state
*request
)
2347 DNSServiceFlags flags
;
2349 char name
[1024]; // Lots of spare space for extra-long names that we'll auto-truncate down to 63 bytes
2350 char domain
[MAX_ESCAPED_DOMAIN_NAME
], host
[MAX_ESCAPED_DOMAIN_NAME
];
2354 service_info
*service
= NULL
;
2356 if (request
->ts
!= t_complete
)
2358 LogMsg("ERROR: handle_regservice_request - transfer state != t_complete");
2359 abort_request(request
);
2360 unlink_request(request
);
2364 service
= mallocL("service_info", sizeof(*service
));
2365 if (!service
) { my_perror("ERROR: malloc"); result
= mStatus_NoMemoryErr
; goto finish
; }
2367 service
->instances
= NULL
;
2368 service
->request
= request
;
2369 service
->txtlen
= 0;
2370 service
->txtdata
= NULL
;
2371 request
->service_registration
= service
;
2372 request
->termination_context
= request
->service_registration
;
2373 request
->terminate
= regservice_termination_callback
;
2375 // extract data from message
2376 ptr
= request
->msgdata
;
2377 flags
= get_flags(&ptr
);
2378 ifi
= get_long(&ptr
);
2379 service
->InterfaceID
= mDNSPlatformInterfaceIDfromInterfaceIndex(gmDNS
, ifi
);
2380 if (ifi
&& !service
->InterfaceID
)
2381 { LogMsg("ERROR: handle_regservice_request - Couldn't find InterfaceID for interfaceIndex %d", ifi
); goto bad_param
; }
2382 if (get_string(&ptr
, name
, sizeof(name
)) < 0 ||
2383 get_string(&ptr
, service
->type_as_string
, MAX_ESCAPED_DOMAIN_NAME
) < 0 ||
2384 get_string(&ptr
, domain
, MAX_ESCAPED_DOMAIN_NAME
) < 0 ||
2385 get_string(&ptr
, host
, MAX_ESCAPED_DOMAIN_NAME
) < 0)
2386 { LogMsg("ERROR: handle_regservice_request - Couldn't read name/regtype/domain"); goto bad_param
; }
2388 service
->port
.b
[0] = *ptr
++;
2389 service
->port
.b
[1] = *ptr
++;
2391 service
->txtlen
= get_short(&ptr
);
2392 if (service
->txtlen
)
2394 service
->txtdata
= mallocL("txtdata", service
->txtlen
);
2395 if (!service
->txtdata
) { my_perror("ERROR: malloc"); result
= mStatus_NoMemoryErr
; goto finish
; }
2396 memcpy(service
->txtdata
, get_rdata(&ptr
, service
->txtlen
), service
->txtlen
);
2398 else service
->txtdata
= NULL
;
2400 // Check for sub-types after the service type
2401 service
->num_subtypes
= ChopSubTypes(service
->type_as_string
); // Note: Modifies regtype string to remove trailing subtypes
2402 if (service
->num_subtypes
< 0)
2403 { LogMsg("ERROR: handle_regservice_request - ChopSubTypes failed %s", service
->type_as_string
); goto bad_param
; }
2405 // Don't try to construct "domainname t" until *after* ChopSubTypes has worked its magic
2406 if (!*service
->type_as_string
|| !MakeDomainNameFromDNSNameString(&service
->type
, service
->type_as_string
))
2407 { LogMsg("ERROR: handle_regservice_request - service->type_as_string bad %s", service
->type_as_string
); goto bad_param
; }
2411 service
->name
= (gmDNS
)->nicelabel
;
2412 service
->autoname
= mDNStrue
;
2416 // If the client is allowing AutoRename, then truncate name to legal length before converting it to a DomainLabel
2417 if ((flags
& kDNSServiceFlagsNoAutoRename
) == 0)
2419 int newlen
= TruncateUTF8ToLength((mDNSu8
*)name
, mDNSPlatformStrLen(name
), MAX_DOMAIN_LABEL
);
2422 if (!MakeDomainLabelFromLiteralString(&service
->name
, name
))
2423 { LogMsg("ERROR: handle_regservice_request - name bad %s", name
); goto bad_param
; }
2424 service
->autoname
= mDNSfalse
;
2429 service
->default_domain
= mDNSfalse
;
2430 if (!MakeDomainNameFromDNSNameString(&d
, domain
))
2431 { LogMsg("ERROR: handle_regservice_request - domain bad %s", domain
); goto bad_param
; }
2435 service
->default_domain
= mDNStrue
;
2436 MakeDomainNameFromDNSNameString(&d
, "local.");
2439 if (!ConstructServiceName(&srv
, &service
->name
, &service
->type
, &d
))
2440 { LogMsg("ERROR: handle_regservice_request - Couldn't ConstructServiceName from, “%#s” “%##s” “%##s”", service
->name
.c
, service
->type
.c
, d
.c
); goto bad_param
; }
2442 if (!MakeDomainNameFromDNSNameString(&service
->host
, host
))
2443 { LogMsg("ERROR: handle_regservice_request - host bad %s", host
); goto bad_param
; }
2444 service
->autorename
= (flags
& kDNSServiceFlagsNoAutoRename
) == 0;
2445 service
->allowremotequery
= (flags
& kDNSServiceFlagsAllowRemoteQuery
) != 0;
2447 // Some clients use mDNS for lightweight copy protection, registering a pseudo-service with
2448 // a port number of zero. When two instances of the protected client are allowed to run on one
2449 // machine, we don't want to see misleading "Bogus client" messages in syslog and the console.
2450 if (service
->port
.NotAnInteger
)
2452 int count
= CountExistingRegistrations(&srv
, service
->port
);
2454 LogMsg("Client application registered %d identical instances of service %##s port %u.",
2455 count
+1, srv
.c
, mDNSVal16(service
->port
));
2458 LogOperation("%3d: DNSServiceRegister(\"%s\", \"%s\", \"%s\", \"%s\", %u) START",
2459 request
->sd
, name
, service
->type_as_string
, domain
, host
, mDNSVal16(service
->port
));
2460 result
= register_service_instance(request
, &d
);
2462 if (!result
&& !*domain
)
2464 DNameListElem
*ptr
, *def_domains
= mDNSPlatformGetRegDomainList();
2465 for (ptr
= def_domains
; ptr
; ptr
= ptr
->next
)
2466 register_service_instance(request
, &ptr
->name
);
2467 // note that we don't report errors for non-local, non-explicit domains
2468 mDNS_FreeDNameList(def_domains
);
2472 deliver_error(request
, result
);
2473 if (result
!= mStatus_NoError
)
2475 abort_request(request
);
2476 unlink_request(request
);
2479 reset_connected_rstate(request
); // prepare to receive add/remove messages
2484 //if (service) freeL("service_info", service); Don't think we should do this -- abort_request will free it a second time and crash
2485 deliver_error(request
, mStatus_BadParamErr
);
2486 abort_request(request
);
2487 unlink_request(request
);
2490 // service registration callback performs three duties - frees memory for deregistered services,
2491 // handles name conflicts, and delivers completed registration information to the client (via
2492 // process_service_registraion())
2494 mDNSlocal
void regservice_callback(mDNS
*const m
, ServiceRecordSet
*const srs
, mStatus result
)
2497 mDNSBool SuppressError
= mDNSfalse
;
2498 service_instance
*instance
= srs
->ServiceContext
;
2500 if (!srs
) { LogMsg("regservice_callback: srs is NULL %d", result
); return; }
2501 if (!instance
) { LogMsg("regservice_callback: srs->ServiceContext is NULL %d", result
); return; }
2503 if (instance
->request
&& instance
->request
->service_registration
)
2505 service_info
*info
= instance
->request
->service_registration
;
2506 if (info
->default_domain
&& !instance
->default_local
) SuppressError
= mDNStrue
;
2507 // don't send errors up to client for wide-area, empty-string registrations
2510 if (result
== mStatus_NoError
)
2511 LogOperation("%3d: DNSServiceRegister(%##s, %u) REGISTERED ", instance
->sd
, srs
->RR_SRV
.resrec
.name
->c
, mDNSVal16(srs
->RR_SRV
.resrec
.rdata
->u
.srv
.port
));
2512 else if (result
== mStatus_MemFree
)
2513 LogOperation("%3d: DNSServiceRegister(%##s, %u) DEREGISTERED", instance
->sd
, srs
->RR_SRV
.resrec
.name
->c
, mDNSVal16(srs
->RR_SRV
.resrec
.rdata
->u
.srv
.port
));
2514 else if (result
== mStatus_NameConflict
)
2515 LogOperation("%3d: DNSServiceRegister(%##s, %u) NAME CONFLICT", instance
->sd
, srs
->RR_SRV
.resrec
.name
->c
, mDNSVal16(srs
->RR_SRV
.resrec
.rdata
->u
.srv
.port
));
2517 LogOperation("%3d: DNSServiceRegister(%##s, %u) CALLBACK %d", instance
->sd
, srs
->RR_SRV
.resrec
.name
->c
, mDNSVal16(srs
->RR_SRV
.resrec
.rdata
->u
.srv
.port
), result
);
2519 if (result
== mStatus_NoError
)
2521 request_state
*req
= instance
->request
;
2522 if (instance
->allowremotequery
)
2524 ExtraResourceRecord
*e
;
2525 srs
->RR_ADV
.AllowRemoteQuery
= mDNStrue
;
2526 srs
->RR_PTR
.AllowRemoteQuery
= mDNStrue
;
2527 srs
->RR_SRV
.AllowRemoteQuery
= mDNStrue
;
2528 srs
->RR_TXT
.AllowRemoteQuery
= mDNStrue
;
2529 for (e
= instance
->srs
.Extras
; e
; e
= e
->next
) e
->r
.AllowRemoteQuery
= mDNStrue
;
2532 if (!req
) LogMsg("ERROR: regservice_callback - null request object");
2536 if (GenerateNTDResponse(srs
->RR_SRV
.resrec
.name
, srs
->RR_SRV
.resrec
.InterfaceID
, req
, &rep
) != mStatus_NoError
)
2537 LogMsg("%3d: regservice_callback: %##s is not valid DNS-SD SRV name", req
->sd
, srs
->RR_SRV
.resrec
.name
->c
);
2540 transfer_state send_result
= send_msg(rep
);
2541 if (send_result
== t_error
|| send_result
== t_terminated
)
2542 { abort_request(req
); unlink_request(req
); freeL("reply_state", rep
); }
2543 else if (send_result
== t_complete
) freeL("regservice_callback", rep
);
2544 else append_reply(req
, rep
);
2547 if (instance
->autoname
&& CountPeerRegistrations(m
, srs
) == 0)
2548 RecordUpdatedNiceLabel(m
, 0); // Successfully got new name, tell user immediately
2551 else if (result
== mStatus_MemFree
)
2553 if (instance
->rename_on_memfree
)
2555 instance
->rename_on_memfree
= 0;
2556 instance
->name
= gmDNS
->nicelabel
;
2557 err
= mDNS_RenameAndReregisterService(gmDNS
, srs
, &instance
->name
);
2558 if (err
) LogMsg("ERROR: regservice_callback - RenameAndReregisterService returned %ld", err
);
2559 // error should never happen - safest to log and continue
2563 free_service_instance(instance
);
2567 else if (result
== mStatus_NameConflict
)
2569 if (instance
->autoname
&& CountPeerRegistrations(m
, srs
) == 0)
2571 // On conflict for an autoname service, rename and reregister *all* autoname services
2572 IncrementLabelSuffix(&m
->nicelabel
, mDNStrue
);
2573 m
->MainCallback(m
, mStatus_ConfigChanged
);
2575 else if (instance
->autoname
|| instance
->autorename
)
2577 mDNS_RenameAndReregisterService(gmDNS
, srs
, mDNSNULL
);
2582 request_state
*rs
= instance
->request
;
2583 if (!rs
) { LogMsg("ERROR: regservice_callback: received result %ld with a NULL request pointer", result
); return; }
2584 free_service_instance(instance
);
2585 if (!SuppressError
&& deliver_async_error(rs
, reg_service_reply_op
, result
) < 0)
2595 request_state
*rs
= instance
->request
;
2596 if (!rs
) { LogMsg("ERROR: regservice_callback: received result %ld with a NULL request pointer", result
); return; }
2597 if (result
!= mStatus_NATTraversal
) LogMsg("ERROR: unknown result in regservice_callback: %ld", result
);
2598 free_service_instance(instance
);
2599 if (!SuppressError
&& deliver_async_error(rs
, reg_service_reply_op
, result
) < 0)
2608 mDNSexport
void FreeExtraRR(mDNS
*const m
, AuthRecord
*const rr
, mStatus result
)
2610 ExtraResourceRecord
*extra
= (ExtraResourceRecord
*)rr
->RecordContext
;
2613 if (result
!= mStatus_MemFree
) { LogMsg("Error: FreeExtraRR invoked with unexpected error %d", result
); return; }
2615 debugf("%##s: MemFree", rr
->resrec
.name
->c
);
2616 if (rr
->resrec
.rdata
!= &rr
->rdatastorage
)
2617 freeL("Extra RData", rr
->resrec
.rdata
);
2618 freeL("ExtraResourceRecord", extra
);
2621 mDNSlocal mStatus
add_record_to_service(request_state
*rstate
, service_instance
*instance
, uint16_t rrtype
, uint16_t rdlen
, char *rdata
, uint32_t ttl
)
2623 ServiceRecordSet
*srs
= &instance
->srs
;
2624 ExtraResourceRecord
*extra
;
2628 if (rdlen
> sizeof(RDataBody
)) size
= rdlen
;
2629 else size
= sizeof(RDataBody
);
2631 extra
= mallocL("ExtraResourceRecord", sizeof(*extra
) - sizeof(RDataBody
) + size
);
2634 my_perror("ERROR: malloc");
2635 return mStatus_NoMemoryErr
;
2638 bzero(extra
, sizeof(ExtraResourceRecord
)); // OK if oversized rdata not zero'd
2639 extra
->r
.resrec
.rrtype
= rrtype
;
2640 extra
->r
.rdatastorage
.MaxRDLength
= (mDNSu16
) size
;
2641 extra
->r
.resrec
.rdlength
= rdlen
;
2642 memcpy(&extra
->r
.rdatastorage
.u
.data
, rdata
, rdlen
);
2644 result
= mDNS_AddRecordToService(gmDNS
, srs
, extra
, &extra
->r
.rdatastorage
, ttl
);
2645 if (result
) { freeL("ExtraResourceRecord", extra
); return result
; }
2647 extra
->ClientID
= rstate
->hdr
.reg_index
;
2651 mDNSlocal mStatus
handle_add_request(request_state
*rstate
)
2654 uint16_t rrtype
, rdlen
;
2656 mStatus result
= mStatus_UnknownErr
;
2657 DNSServiceFlags flags
;
2658 service_info
*srvinfo
= rstate
->service_registration
;
2659 service_instance
*i
;
2661 if (!srvinfo
) { LogMsg("handle_add_request called with NULL service_registration"); return(-1); }
2663 ptr
= rstate
->msgdata
;
2664 flags
= get_flags(&ptr
);
2665 rrtype
= get_short(&ptr
);
2666 rdlen
= get_short(&ptr
);
2667 rdata
= get_rdata(&ptr
, rdlen
);
2668 ttl
= get_long(&ptr
);
2670 if (!ttl
) ttl
= DefaultTTLforRRType(rrtype
);
2672 LogOperation("%3d: DNSServiceAddRecord(%##s, %s)", rstate
->sd
,
2673 (srvinfo
->instances
) ? srvinfo
->instances
->srs
.RR_SRV
.resrec
.name
->c
: NULL
, DNSTypeName(rrtype
));
2675 for (i
= srvinfo
->instances
; i
; i
= i
->next
)
2677 result
= add_record_to_service(rstate
, i
, rrtype
, rdlen
, rdata
, ttl
);
2678 if (result
&& i
->default_local
) break;
2679 else result
= mStatus_NoError
; // suppress non-local default errors
2685 mDNSlocal mStatus
update_record(AuthRecord
*rr
, uint16_t rdlen
, char *rdata
, uint32_t ttl
)
2691 if (rdlen
> sizeof(RDataBody
)) rdsize
= rdlen
;
2692 else rdsize
= sizeof(RDataBody
);
2693 newrd
= mallocL("handle_update_request", sizeof(RData
) - sizeof(RDataBody
) + rdsize
);
2694 if (!newrd
) FatalError("ERROR: malloc");
2695 newrd
->MaxRDLength
= (mDNSu16
) rdsize
;
2696 memcpy(&newrd
->u
, rdata
, rdlen
);
2698 // BIND named (name daemon) doesn't allow TXT records with zero-length rdata. This is strictly speaking correct,
2699 // since RFC 1035 specifies a TXT record as "One or more <character-string>s", not "Zero or more <character-string>s".
2700 // Since some legacy apps try to create zero-length TXT records, we'll silently correct it here.
2701 if (rr
->resrec
.rrtype
== kDNSType_TXT
&& rdlen
== 0) { rdlen
= 1; newrd
->u
.txt
.c
[0] = 0; }
2703 result
= mDNS_Update(gmDNS
, rr
, ttl
, rdlen
, newrd
, update_callback
);
2704 if (result
) { LogMsg("ERROR: mDNS_Update - %ld", result
); freeL("handle_update_request", newrd
); }
2708 mDNSlocal mStatus
handle_update_request(request_state
*rstate
)
2713 mStatus result
= mStatus_BadReferenceErr
;
2714 service_info
*srvinfo
= rstate
->service_registration
;
2715 service_instance
*i
;
2716 AuthRecord
*rr
= NULL
;
2718 // get the message data
2719 ptr
= rstate
->msgdata
;
2720 get_flags(&ptr
); // flags unused
2721 rdlen
= get_short(&ptr
);
2722 rdata
= get_rdata(&ptr
, rdlen
);
2723 ttl
= get_long(&ptr
);
2725 if (rstate
->reg_recs
)
2727 // update an individually registered record
2728 registered_record_entry
*reptr
;
2729 for (reptr
= rstate
->reg_recs
; reptr
; reptr
= reptr
->next
)
2731 if (reptr
->key
== rstate
->hdr
.reg_index
)
2733 result
= update_record(reptr
->rr
, rdlen
, rdata
, ttl
);
2737 result
= mStatus_BadReferenceErr
;
2741 // update a record from a service record set
2742 if (!srvinfo
) { result
= mStatus_BadReferenceErr
; goto end
; }
2743 for (i
= srvinfo
->instances
; i
; i
= i
->next
)
2745 if (rstate
->hdr
.reg_index
== TXT_RECORD_INDEX
) rr
= &i
->srs
.RR_TXT
;
2748 ExtraResourceRecord
*e
;
2749 for (e
= i
->srs
.Extras
; e
; e
= e
->next
)
2750 if (e
->ClientID
== rstate
->hdr
.reg_index
) { rr
= &e
->r
; break; }
2753 if (!rr
) { result
= mStatus_BadReferenceErr
; goto end
; }
2754 result
= update_record(rr
, rdlen
, rdata
, ttl
);
2755 if (result
&& i
->default_local
) goto end
;
2756 else result
= mStatus_NoError
; // suppress non-local default errors
2760 LogOperation("%3d: DNSServiceUpdateRecord(%##s, %s)", rstate
->sd
,
2761 (srvinfo
->instances
) ? srvinfo
->instances
->srs
.RR_SRV
.resrec
.name
->c
: NULL
,
2762 rr
? DNSTypeName(rr
->resrec
.rrtype
) : "<NONE>");
2767 mDNSlocal
void update_callback(mDNS
*const m
, AuthRecord
*const rr
, RData
*oldrd
)
2770 if (oldrd
!= &rr
->rdatastorage
) freeL("update_callback", oldrd
);
2773 mDNSlocal
void free_service_instance(service_instance
*srv
)
2775 request_state
*rstate
= srv
->request
;
2776 ExtraResourceRecord
*e
= srv
->srs
.Extras
, *tmp
;
2778 // clear pointers from parent struct
2781 service_instance
*ptr
= rstate
->service_registration
->instances
, *prev
= NULL
;
2786 if (prev
) prev
->next
= ptr
->next
;
2787 else rstate
->service_registration
->instances
= ptr
->next
;
2797 e
->r
.RecordContext
= e
;
2800 FreeExtraRR(gmDNS
, &tmp
->r
, mStatus_MemFree
);
2803 if (srv
->subtypes
) { freeL("regservice_callback", srv
->subtypes
); srv
->subtypes
= NULL
; }
2804 freeL("regservice_callback", srv
);
2807 mDNSlocal
void regservice_termination_callback(void *context
)
2809 service_info
*info
= context
;
2810 service_instance
*i
, *p
;
2811 if (!info
) { LogMsg("regservice_termination_callback context is NULL"); return; }
2812 if (!info
->request
) { LogMsg("regservice_termination_callback info->request is NULL"); return; }
2813 i
= info
->instances
;
2818 p
->request
= NULL
; // clear back pointer
2819 // only safe to free memory if registration is not valid, i.e. deregister fails (which invalidates p)
2820 LogOperation("%3d: DNSServiceRegister(%##s, %u) STOP", info
->request
->sd
, p
->srs
.RR_SRV
.resrec
.name
->c
, mDNSVal16(p
->srs
.RR_SRV
.resrec
.rdata
->u
.srv
.port
));
2821 if (mDNS_DeregisterService(gmDNS
, &p
->srs
)) free_service_instance(p
);
2823 info
->request
->service_registration
= NULL
; // clear pointer from request back to info
2824 if (info
->txtdata
) { freeL("txtdata", info
->txtdata
); info
->txtdata
= NULL
; }
2825 freeL("service_info", info
);
2828 mDNSlocal mStatus
handle_regrecord_request(request_state
*rstate
)
2831 registered_record_entry
*re
;
2834 if (rstate
->ts
!= t_complete
)
2836 LogMsg("ERROR: handle_regrecord_request - transfer state != t_complete");
2837 abort_request(rstate
);
2838 unlink_request(rstate
);
2842 rr
= read_rr_from_ipc_msg(rstate
->msgdata
, 1, 1);
2843 if (!rr
) return(mStatus_BadParamErr
);
2845 // allocate registration entry, link into list
2846 re
= mallocL("handle_regrecord_request", sizeof(registered_record_entry
));
2847 if (!re
) FatalError("ERROR: malloc");
2848 re
->key
= rstate
->hdr
.reg_index
;
2850 re
->rstate
= rstate
;
2851 re
->client_context
= rstate
->hdr
.client_context
;
2852 rr
->RecordContext
= re
;
2853 rr
->RecordCallback
= regrecord_callback
;
2854 re
->next
= rstate
->reg_recs
;
2855 rstate
->reg_recs
= re
;
2857 if (!rstate
->terminate
)
2859 rstate
->terminate
= connected_registration_termination
;
2860 rstate
->termination_context
= rstate
;
2863 if (rr
->resrec
.rroriginalttl
== 0)
2864 rr
->resrec
.rroriginalttl
= DefaultTTLforRRType(rr
->resrec
.rrtype
);
2866 LogOperation("%3d: DNSServiceRegisterRecord %s", rstate
->sd
, RRDisplayString(gmDNS
, &rr
->resrec
));
2867 result
= mDNS_Register(gmDNS
, rr
);
2871 mDNSlocal
void regrecord_callback(mDNS
*const m
, AuthRecord
* rr
, mStatus result
)
2873 registered_record_entry
*re
= rr
->RecordContext
;
2874 request_state
*rstate
= re
? re
->rstate
: NULL
;
2882 // parent struct alreadt freed by termination callback
2883 if (!result
) LogMsg("Error: regrecord_callback: successful registration of orphaned record");
2886 if (result
!= mStatus_MemFree
) LogMsg("regrecord_callback: error %d received after parent termination", result
);
2887 freeL("regrecord_callback", rr
);
2892 // format result, add to the list for the request, including the client context in the header
2893 len
= sizeof(DNSServiceFlags
);
2894 len
+= sizeof(uint32_t); //interfaceIndex
2895 len
+= sizeof(DNSServiceErrorType
);
2897 reply
= create_reply(reg_record_reply_op
, len
, rstate
);
2898 reply
->mhdr
->client_context
= re
->client_context
;
2899 reply
->rhdr
->flags
= dnssd_htonl(0);
2900 reply
->rhdr
->ifi
= dnssd_htonl(mDNSPlatformInterfaceIndexfromInterfaceID(gmDNS
, rr
->resrec
.InterfaceID
));
2901 reply
->rhdr
->error
= dnssd_htonl(result
);
2905 // unlink from list, free memory
2906 registered_record_entry
**ptr
= &re
->rstate
->reg_recs
;
2907 while (*ptr
&& (*ptr
) != re
) ptr
= &(*ptr
)->next
;
2908 if (!*ptr
) { LogMsg("regrecord_callback - record not in list!"); return; }
2909 *ptr
= (*ptr
)->next
;
2910 freeL("regrecord_callback", re
->rr
);
2912 freeL("regrecord_callback", re
);
2916 ts
= send_msg(reply
);
2918 if (ts
== t_error
|| ts
== t_terminated
) { abort_request(rstate
); unlink_request(rstate
); }
2919 else if (ts
== t_complete
) freeL("regrecord_callback", reply
);
2920 else if (ts
== t_morecoming
) append_reply(rstate
, reply
); // client is blocked, link reply into list
2923 mDNSlocal
void connected_registration_termination(void *context
)
2926 registered_record_entry
*fptr
, *ptr
= ((request_state
*)context
)->reg_recs
;
2931 shared
= fptr
->rr
->resrec
.RecordType
== kDNSRecordTypeShared
;
2932 fptr
->rr
->RecordContext
= NULL
;
2933 mDNS_Deregister(gmDNS
, fptr
->rr
);
2934 freeL("connected_registration_termination", fptr
);
2938 mDNSlocal mStatus
handle_removerecord_request(request_state
*rstate
)
2940 mStatus err
= mStatus_BadReferenceErr
;
2942 service_info
*srvinfo
= rstate
->service_registration
;
2944 ptr
= rstate
->msgdata
;
2945 get_flags(&ptr
); // flags unused
2947 if (rstate
->reg_recs
) err
= remove_record(rstate
); // remove individually registered record
2948 else if (!srvinfo
) LogOperation("%3d: DNSServiceRemoveRecord (bad ref)", rstate
->sd
);
2951 service_instance
*i
;
2952 LogOperation("%3d: DNSServiceRemoveRecord(%##s)", rstate
->sd
,
2953 (srvinfo
->instances
) ? srvinfo
->instances
->srs
.RR_SRV
.resrec
.name
->c
: NULL
);
2954 for (i
= srvinfo
->instances
; i
; i
= i
->next
)
2956 err
= remove_extra(rstate
, i
);
2957 if (err
&& i
->default_local
) break;
2958 else err
= mStatus_NoError
; // suppress non-local default errors
2965 // remove a resource record registered via DNSServiceRegisterRecord()
2966 mDNSlocal mStatus
remove_record(request_state
*rstate
)
2969 mStatus err
= mStatus_UnknownErr
;
2970 registered_record_entry
*e
, **ptr
= &rstate
->reg_recs
;
2972 while(*ptr
&& (*ptr
)->key
!= rstate
->hdr
.reg_index
) ptr
= &(*ptr
)->next
;
2973 if (!*ptr
) { LogMsg("DNSServiceRemoveRecord - bad reference"); return mStatus_BadReferenceErr
; }
2975 *ptr
= e
->next
; // unlink
2977 LogOperation("%3d: DNSServiceRemoveRecord(%#s)", rstate
->sd
, e
->rr
->resrec
.name
->c
);
2978 shared
= e
->rr
->resrec
.RecordType
== kDNSRecordTypeShared
;
2979 e
->rr
->RecordContext
= NULL
;
2980 err
= mDNS_Deregister(gmDNS
, e
->rr
);
2983 LogMsg("ERROR: remove_record, mDNS_Deregister: %ld", err
);
2984 freeL("remove_record", e
->rr
);
2985 freeL("remove_record", e
);
2990 mDNSlocal mStatus
remove_extra(request_state
*rstate
, service_instance
*serv
)
2992 mStatus err
= mStatus_BadReferenceErr
;
2993 ExtraResourceRecord
*ptr
;
2995 for (ptr
= serv
->srs
.Extras
; ptr
; ptr
= ptr
->next
)
2997 if (ptr
->ClientID
== rstate
->hdr
.reg_index
) // found match
2998 return mDNS_RemoveRecordFromService(gmDNS
, &serv
->srs
, ptr
, FreeExtraRR
, ptr
);
3003 // domain enumeration
3004 mDNSlocal
void handle_enum_request(request_state
*rstate
)
3006 DNSServiceFlags flags
;
3008 mDNSInterfaceID InterfaceID
;
3009 char *ptr
= rstate
->msgdata
;
3010 domain_enum_t
*def
, *all
;
3011 enum_termination_t
*term
;
3015 if (rstate
->ts
!= t_complete
)
3017 LogMsg("ERROR: handle_enum_request - transfer state != t_complete");
3018 abort_request(rstate
);
3019 unlink_request(rstate
);
3023 flags
= get_flags(&ptr
);
3024 ifi
= get_long(&ptr
);
3025 InterfaceID
= mDNSPlatformInterfaceIDfromInterfaceIndex(gmDNS
, ifi
);
3026 if (ifi
&& !InterfaceID
)
3028 deliver_error(rstate
, mStatus_BadParamErr
);
3029 abort_request(rstate
);
3030 unlink_request(rstate
);
3034 // allocate context structures
3035 def
= mallocL("handle_enum_request", sizeof(domain_enum_t
));
3036 all
= mallocL("handle_enum_request", sizeof(domain_enum_t
));
3037 term
= mallocL("handle_enum_request", sizeof(enum_termination_t
));
3038 if (!def
|| !all
|| !term
) FatalError("ERROR: malloc");
3040 #if defined(MDNS_LAZY_REGISTER_SEARCH_DOMAINS)
3041 dDNS_RegisterSearchDomains( gmDNS
);
3044 // enumeration requires multiple questions, so we must link all the context pointers so that
3045 // necessary context can be reached from the callbacks
3046 def
->rstate
= rstate
;
3047 all
->rstate
= rstate
;
3050 term
->rstate
= rstate
;
3051 rstate
->termination_context
= term
;
3052 rstate
->terminate
= enum_termination_callback
;
3053 def
->question
.QuestionContext
= def
;
3054 def
->type
= (flags
& kDNSServiceFlagsRegistrationDomains
) ?
3055 mDNS_DomainTypeRegistrationDefault
: mDNS_DomainTypeBrowseDefault
;
3056 all
->question
.QuestionContext
= all
;
3057 all
->type
= (flags
& kDNSServiceFlagsRegistrationDomains
) ?
3058 mDNS_DomainTypeRegistration
: mDNS_DomainTypeBrowse
;
3060 // if the caller hasn't specified an explicit interface, we use local-only to get the system-wide list.
3061 if (!InterfaceID
) InterfaceID
= mDNSInterface_LocalOnly
;
3064 LogOperation("%3d: DNSServiceEnumerateDomains(%X=%s)", rstate
->sd
, flags
,
3065 (flags
& kDNSServiceFlagsBrowseDomains
) ? "kDNSServiceFlagsBrowseDomains" :
3066 (flags
& kDNSServiceFlagsRegistrationDomains
) ? "kDNSServiceFlagsRegistrationDomains" : "<<Unknown>>");
3067 err
= mDNS_GetDomains(gmDNS
, &all
->question
, all
->type
, NULL
, InterfaceID
, enum_result_callback
, all
);
3068 if (err
== mStatus_NoError
)
3069 err
= mDNS_GetDomains(gmDNS
, &def
->question
, def
->type
, NULL
, InterfaceID
, enum_result_callback
, def
);
3070 result
= deliver_error(rstate
, err
); // send error *before* returning local domain
3072 if (result
< 0 || err
)
3074 abort_request(rstate
);
3075 unlink_request(rstate
);
3080 mDNSlocal
void enum_result_callback(mDNS
*const m
, DNSQuestion
*question
, const ResourceRecord
*const answer
, mDNSBool AddRecord
)
3082 char domain
[MAX_ESCAPED_DOMAIN_NAME
];
3083 domain_enum_t
*de
= question
->QuestionContext
;
3084 DNSServiceFlags flags
= 0;
3088 if (answer
->rrtype
!= kDNSType_PTR
) return;
3089 if (!AddRecord
&& de
->type
!= mDNS_DomainTypeBrowse
) return;
3093 flags
|= kDNSServiceFlagsAdd
;
3094 if (de
->type
== mDNS_DomainTypeRegistrationDefault
|| de
->type
== mDNS_DomainTypeBrowseDefault
)
3095 flags
|= kDNSServiceFlagsDefault
;
3097 ConvertDomainNameToCString(&answer
->rdata
->u
.name
, domain
);
3098 // note that we do NOT propagate specific interface indexes to the client - for example, a domain we learn from
3099 // a machine's system preferences may be discovered on the LocalOnly interface, but should be browsed on the
3100 // network, so we just pass kDNSServiceInterfaceIndexAny
3101 reply
= format_enumeration_reply(de
->rstate
, domain
, flags
, kDNSServiceInterfaceIndexAny
, kDNSServiceErr_NoError
);
3104 LogMsg("ERROR: enum_result_callback, format_enumeration_reply");
3108 append_reply(de
->rstate
, reply
);
3112 mDNSlocal reply_state
*format_enumeration_reply(request_state
*rstate
, const char *domain
, DNSServiceFlags flags
, uint32_t ifi
, DNSServiceErrorType err
)
3118 len
= sizeof(DNSServiceFlags
);
3119 len
+= sizeof(uint32_t);
3120 len
+= sizeof(DNSServiceErrorType
);
3121 len
+= strlen(domain
) + 1;
3123 reply
= create_reply(enumeration_reply_op
, len
, rstate
);
3124 reply
->rhdr
->flags
= dnssd_htonl(flags
);
3125 reply
->rhdr
->ifi
= dnssd_htonl(ifi
);
3126 reply
->rhdr
->error
= dnssd_htonl(err
);
3127 data
= reply
->sdata
;
3128 put_string(domain
, &data
);
3132 mDNSlocal
void enum_termination_callback(void *context
)
3134 enum_termination_t
*t
= context
;
3135 mDNS
*coredata
= gmDNS
;
3137 mDNS_StopGetDomains(coredata
, &t
->all
->question
);
3138 mDNS_StopGetDomains(coredata
, &t
->def
->question
);
3139 freeL("enum_termination_callback", t
->all
);
3140 freeL("enum_termination_callback", t
->def
);
3141 t
->rstate
->termination_context
= NULL
;
3142 freeL("enum_termination_callback", t
);
3145 mDNSlocal
void handle_reconfirm_request(request_state
*rstate
)
3147 AuthRecord
*rr
= read_rr_from_ipc_msg(rstate
->msgdata
, 0, 0);
3150 mStatus status
= mDNS_ReconfirmByValue(gmDNS
, &rr
->resrec
);
3152 (status
== mStatus_NoError
) ?
3153 "%3d: DNSServiceReconfirmRecord(%s) interface %d initiated" :
3154 "%3d: DNSServiceReconfirmRecord(%s) interface %d failed: %d",
3155 rstate
->sd
, RRDisplayString(gmDNS
, &rr
->resrec
),
3156 mDNSPlatformInterfaceIndexfromInterfaceID(gmDNS
, rr
->resrec
.InterfaceID
), status
);
3157 status
= 0; // Adding this line eliminates a build failure when building mDNSPosix on Tiger
3159 abort_request(rstate
);
3160 unlink_request(rstate
);
3161 freeL("handle_reconfirm_request", rr
);
3164 // setup rstate to accept new reg/dereg requests
3165 mDNSlocal
void reset_connected_rstate(request_state
*rstate
)
3167 rstate
->ts
= t_morecoming
;
3168 rstate
->hdr_bytes
= 0;
3169 rstate
->data_bytes
= 0;
3170 if (rstate
->msgbuf
) freeL("reset_connected_rstate", rstate
->msgbuf
);
3171 rstate
->msgbuf
= NULL
;
3172 rstate
->bufsize
= 0;
3175 // returns a resource record (allocated w/ malloc) containing the data found in an IPC message
3176 // data must be in format flags, interfaceIndex, name, rrtype, rrclass, rdlen, rdata, (optional)ttl
3177 // (ttl only extracted/set if ttl argument is non-zero). returns NULL for a bad-parameter error
3178 mDNSlocal AuthRecord
*read_rr_from_ipc_msg(char *msgbuf
, int GetTTL
, int validate_flags
)
3180 char *rdata
, name
[256];
3182 DNSServiceFlags flags
;
3183 uint32_t interfaceIndex
;
3184 uint16_t type
, class, rdlen
;
3187 flags
= get_flags(&msgbuf
);
3188 if (validate_flags
&&
3189 !((flags
& kDNSServiceFlagsShared
) == kDNSServiceFlagsShared
) &&
3190 !((flags
& kDNSServiceFlagsUnique
) == kDNSServiceFlagsUnique
))
3192 LogMsg("ERROR: Bad resource record flags (must be kDNSServiceFlagsShared or kDNSServiceFlagsUnique)");
3196 interfaceIndex
= get_long(&msgbuf
);
3197 if (get_string(&msgbuf
, name
, 256) < 0)
3199 LogMsg("ERROR: read_rr_from_ipc_msg - get_string");
3202 type
= get_short(&msgbuf
);
3203 class = get_short(&msgbuf
);
3204 rdlen
= get_short(&msgbuf
);
3206 if (rdlen
> sizeof(RDataBody
)) storage_size
= rdlen
;
3207 else storage_size
= sizeof(RDataBody
);
3209 rr
= mallocL("read_rr_from_ipc_msg", sizeof(AuthRecord
) - sizeof(RDataBody
) + storage_size
);
3210 if (!rr
) FatalError("ERROR: malloc");
3211 bzero(rr
, sizeof(AuthRecord
)); // ok if oversized rdata not zero'd
3213 mDNS_SetupResourceRecord(rr
, mDNSNULL
, mDNSPlatformInterfaceIDfromInterfaceIndex(gmDNS
, interfaceIndex
),
3214 type
, 0, (mDNSu8
) ((flags
& kDNSServiceFlagsShared
) ? kDNSRecordTypeShared
: kDNSRecordTypeUnique
), mDNSNULL
, mDNSNULL
);
3216 if (!MakeDomainNameFromDNSNameString(rr
->resrec
.name
, name
))
3218 LogMsg("ERROR: bad name: %s", name
);
3219 freeL("read_rr_from_ipc_msg", rr
);
3223 if (flags
& kDNSServiceFlagsAllowRemoteQuery
) rr
->AllowRemoteQuery
= mDNStrue
;
3224 rr
->resrec
.rrclass
= class;
3225 rr
->resrec
.rdlength
= rdlen
;
3226 rr
->resrec
.rdata
->MaxRDLength
= rdlen
;
3227 rdata
= get_rdata(&msgbuf
, rdlen
);
3228 memcpy(rr
->resrec
.rdata
->u
.data
, rdata
, rdlen
);
3229 if (GetTTL
) rr
->resrec
.rroriginalttl
= get_long(&msgbuf
);
3230 rr
->resrec
.namehash
= DomainNameHashValue(rr
->resrec
.name
);
3231 SetNewRData(&rr
->resrec
, mDNSNULL
, 0); // Sets rr->rdatahash for us
3235 mDNSlocal
int build_domainname_from_strings(domainname
*srv
, char *name
, char *regtype
, char *domain
)
3240 if (!MakeDomainLabelFromLiteralString(&n
, name
)) return -1;
3241 if (!MakeDomainNameFromDNSNameString(&t
, regtype
)) return -1;
3242 if (!MakeDomainNameFromDNSNameString(&d
, domain
)) return -1;
3243 if (!ConstructServiceName(srv
, &n
, &t
, &d
)) return -1;
3247 // append a reply to the list in a request object
3248 mDNSlocal
void append_reply(request_state
*req
, reply_state
*rep
)
3252 if (!req
->replies
) req
->replies
= rep
;
3256 while (ptr
->next
) ptr
= ptr
->next
;
3262 // read_msg may be called any time when the transfer state (rs->ts) is t_morecoming.
3263 // returns the current state of the request (morecoming, error, complete, terminated.)
3264 // if there is no data on the socket, the socket will be closed and t_terminated will be returned
3265 mDNSlocal
int read_msg(request_state
*rs
)
3269 char buf
[4]; // dummy for death notification
3271 if (rs
->ts
== t_terminated
|| rs
->ts
== t_error
)
3273 LogMsg("ERROR: read_msg called with transfer state terminated or error");
3278 if (rs
->ts
== t_complete
)
3279 { // this must be death or something is wrong
3280 nread
= recv(rs
->sd
, buf
, 4, 0);
3281 if (!nread
) { rs
->ts
= t_terminated
; return t_terminated
; }
3282 if (nread
< 0) goto rerror
;
3283 LogMsg("ERROR: read data from a completed request.");
3288 if (rs
->ts
!= t_morecoming
)
3290 LogMsg("ERROR: read_msg called with invalid transfer state (%d)", rs
->ts
);
3295 if (rs
->hdr_bytes
< sizeof(ipc_msg_hdr
))
3297 nleft
= sizeof(ipc_msg_hdr
) - rs
->hdr_bytes
;
3298 nread
= recv(rs
->sd
, (char *)&rs
->hdr
+ rs
->hdr_bytes
, nleft
, 0);
3299 if (nread
== 0) { rs
->ts
= t_terminated
; return t_terminated
; }
3300 if (nread
< 0) goto rerror
;
3301 rs
->hdr_bytes
+= nread
;
3302 if (rs
->hdr_bytes
== sizeof(ipc_msg_hdr
))
3304 ConvertHeaderBytes(&rs
->hdr
);
3305 if (rs
->hdr
.version
!= VERSION
)
3307 LogMsg("ERROR: read_msg - client version 0x%08X does not match daemon version 0x%08X", rs
->hdr
.version
, VERSION
);
3312 if (rs
->hdr_bytes
> sizeof(ipc_msg_hdr
))
3314 LogMsg("ERROR: read_msg - read too many header bytes");
3320 // only read data if header is complete
3321 if (rs
->hdr_bytes
== sizeof(ipc_msg_hdr
))
3323 if (rs
->hdr
.datalen
== 0) // ok in removerecord requests
3325 rs
->ts
= t_complete
;
3330 if (!rs
->msgbuf
) // allocate the buffer first time through
3332 rs
->msgbuf
= mallocL("read_msg", rs
->hdr
.datalen
+ MSG_PAD_BYTES
);
3335 my_perror("ERROR: malloc");
3339 rs
->msgdata
= rs
->msgbuf
;
3340 bzero(rs
->msgbuf
, rs
->hdr
.datalen
+ MSG_PAD_BYTES
);
3342 nleft
= rs
->hdr
.datalen
- rs
->data_bytes
;
3343 nread
= recv(rs
->sd
, rs
->msgbuf
+ rs
->data_bytes
, nleft
, 0);
3344 if (nread
== 0) { rs
->ts
= t_terminated
; return t_terminated
; }
3345 if (nread
< 0) goto rerror
;
3346 rs
->data_bytes
+= nread
;
3347 if (rs
->data_bytes
> rs
->hdr
.datalen
)
3349 LogMsg("ERROR: read_msg - read too many data bytes");
3355 if (rs
->hdr_bytes
== sizeof(ipc_msg_hdr
) && rs
->data_bytes
== rs
->hdr
.datalen
)
3356 rs
->ts
= t_complete
;
3357 else rs
->ts
= t_morecoming
;
3362 if (dnssd_errno() == dnssd_EWOULDBLOCK
|| dnssd_errno() == dnssd_EINTR
) return t_morecoming
;
3363 my_perror("ERROR: read_msg");
3368 mDNSlocal
int send_msg(reply_state
*rs
)
3374 LogMsg("ERROR: send_msg called with NULL message buffer");
3378 if (rs
->request
->no_reply
) //!!!KRS this behavior should be optimized if it becomes more common
3380 rs
->ts
= t_complete
;
3381 freeL("send_msg", rs
->msgbuf
);
3385 ConvertHeaderBytes(rs
->mhdr
);
3386 nwriten
= send(rs
->sd
, rs
->msgbuf
+ rs
->nwriten
, rs
->len
- rs
->nwriten
, 0);
3387 ConvertHeaderBytes(rs
->mhdr
);
3390 if (dnssd_errno() == dnssd_EINTR
|| dnssd_errno() == dnssd_EWOULDBLOCK
) nwriten
= 0;
3393 #if !defined(PLATFORM_NO_EPIPE)
3394 if (dnssd_errno() == EPIPE
)
3396 debugf("%3d: broken pipe", rs
->sd
);
3397 rs
->ts
= t_terminated
;
3398 rs
->request
->ts
= t_terminated
;
3399 return t_terminated
;
3404 my_perror("ERROR: send\n");
3410 rs
->nwriten
+= nwriten
;
3412 if (rs
->nwriten
== rs
->len
)
3414 rs
->ts
= t_complete
;
3415 freeL("send_msg", rs
->msgbuf
);
3420 mDNSlocal reply_state
*create_reply(reply_op_t op
, size_t datalen
, request_state
*request
)
3425 if ((unsigned)datalen
< sizeof(reply_hdr
))
3427 LogMsg("ERROR: create_reply - data length less than lenght of required fields");
3431 totallen
= (int) (datalen
+ sizeof(ipc_msg_hdr
));
3432 reply
= mallocL("create_reply", sizeof(reply_state
));
3433 if (!reply
) FatalError("ERROR: malloc");
3434 bzero(reply
, sizeof(reply_state
));
3435 reply
->ts
= t_morecoming
;
3436 reply
->sd
= request
->sd
;
3437 reply
->request
= request
;
3438 reply
->len
= totallen
;
3439 reply
->msgbuf
= mallocL("create_reply", totallen
);
3440 if (!reply
->msgbuf
) FatalError("ERROR: malloc");
3441 bzero(reply
->msgbuf
, totallen
);
3442 reply
->mhdr
= (ipc_msg_hdr
*)reply
->msgbuf
;
3443 reply
->rhdr
= (reply_hdr
*)(reply
->msgbuf
+ sizeof(ipc_msg_hdr
));
3444 reply
->sdata
= reply
->msgbuf
+ sizeof(ipc_msg_hdr
) + sizeof(reply_hdr
);
3445 reply
->mhdr
->version
= VERSION
;
3446 reply
->mhdr
->op
= op
;
3447 reply
->mhdr
->datalen
= totallen
- sizeof(ipc_msg_hdr
);
3451 mDNSlocal
int deliver_error(request_state
*rstate
, mStatus err
)
3454 undelivered_error_t
*undeliv
;
3456 err
= dnssd_htonl(err
);
3457 nwritten
= send(rstate
->sd
, (dnssd_sockbuf_t
) &err
, sizeof(mStatus
), 0);
3458 if (nwritten
< (int)sizeof(mStatus
))
3460 if (dnssd_errno() == dnssd_EINTR
|| dnssd_errno() == dnssd_EWOULDBLOCK
)
3464 my_perror("ERROR: send - unable to deliver error to client");
3469 //client blocked - store result and come backr
3470 undeliv
= mallocL("deliver_error", sizeof(undelivered_error_t
));
3471 if (!undeliv
) FatalError("ERROR: malloc");
3473 undeliv
->nwritten
= nwritten
;
3474 undeliv
->sd
= rstate
->sd
;
3475 rstate
->u_err
= undeliv
;
3482 // returns 0 on success, -1 if send is incomplete, or on terminal failure (request is aborted)
3483 mDNSlocal transfer_state
send_undelivered_error(request_state
*rs
)
3487 nwritten
= send(rs
->u_err
->sd
, (char *)(&rs
->u_err
->err
) + rs
->u_err
->nwritten
, sizeof(mStatus
) - rs
->u_err
->nwritten
, 0);
3490 if (dnssd_errno() == dnssd_EINTR
|| dnssd_errno() == dnssd_EWOULDBLOCK
)
3494 my_perror("ERROR: send - unable to deliver error to client\n");
3498 if ((unsigned int)(nwritten
+ rs
->u_err
->nwritten
) >= sizeof(mStatus
))
3500 freeL("send_undelivered_error", rs
->u_err
);
3504 rs
->u_err
->nwritten
+= nwritten
;
3505 return t_morecoming
;
3508 // send bogus data along with an error code to the app callback
3509 // returns 0 on success (linking reply into list of not fully delivered),
3510 // -1 on failure (request should be aborted)
3511 mDNSlocal
int deliver_async_error(request_state
*rs
, reply_op_t op
, mStatus err
)
3517 if (rs
->no_reply
) return 0;
3518 len
= 256; // long enough for any reply handler to read all args w/o buffer overrun
3519 reply
= create_reply(op
, len
, rs
);
3520 reply
->rhdr
->error
= dnssd_htonl(err
);
3521 ts
= send_msg(reply
);
3522 if (ts
== t_error
|| ts
== t_terminated
)
3524 freeL("deliver_async_error", reply
);
3527 else if (ts
== t_complete
) freeL("deliver_async_error", reply
);
3528 else if (ts
== t_morecoming
) append_reply(rs
, reply
); // client is blocked, link reply into list
3532 mDNSlocal
void abort_request(request_state
*rs
)
3534 reply_state
*rep
, *ptr
;
3536 if (rs
->terminate
) rs
->terminate(rs
->termination_context
); // terminate field may not be set yet
3537 if (rs
->msgbuf
) freeL("abort_request", rs
->msgbuf
);
3538 LogOperation("%3d: Removing FD", rs
->sd
);
3539 udsSupportRemoveFDFromEventLoop(rs
->sd
); // Note: This also closes file descriptor rs->sd for us
3541 // Don't use dnssd_InvalidSocket (-1) because that's the sentinel value MACOSX_MDNS_MALLOC_DEBUGGING uses
3542 // for detecting when the memory for an object is inadvertently freed while the object is still on some list
3545 // free pending replies
3549 if (rep
->msgbuf
) freeL("abort_request", rep
->msgbuf
);
3552 freeL("abort_request", ptr
);
3557 freeL("abort_request", rs
->u_err
);
3562 mDNSlocal
void unlink_request(request_state
*rs
)
3566 if (rs
== all_requests
)
3568 all_requests
= all_requests
->next
;
3569 freeL("unlink_request", rs
);
3572 for(ptr
= all_requests
; ptr
->next
; ptr
= ptr
->next
)
3573 if (ptr
->next
== rs
)
3575 ptr
->next
= rs
->next
;
3576 freeL("unlink_request", rs
);
3581 //hack to search-replace perror's to LogMsg's
3582 mDNSlocal
void my_perror(char *errmsg
)
3584 LogMsg("%s: %s", errmsg
, dnssd_strerror(dnssd_errno()));
3587 // check that the message delivered by the client is sufficiently long to extract the required data from the buffer
3588 // without overrunning it.
3589 // returns 0 on success, -1 on error.
3591 mDNSlocal
int validate_message(request_state
*rstate
)
3595 switch(rstate
->hdr
.op
)
3597 case resolve_request
: min_size
= sizeof(DNSServiceFlags
) + // flags
3598 sizeof(uint32_t) + // interface
3599 (3 * sizeof(char)); // name, regtype, domain
3601 case query_request
: min_size
= sizeof(DNSServiceFlags
) + // flags
3602 sizeof(uint32_t) + // interface
3603 sizeof(char) + // fullname
3604 (2 * sizeof(uint16_t)); // type, class
3606 case browse_request
: min_size
= sizeof(DNSServiceFlags
) + // flags
3607 sizeof(uint32_t) + // interface
3608 (2 * sizeof(char)); // regtype, domain
3610 case reg_service_request
: min_size
= sizeof(DNSServiceFlags
) + // flags
3611 sizeof(uint32_t) + // interface
3612 (4 * sizeof(char)) + // name, type, domain, host
3613 (2 * sizeof(uint16_t)); // port, textlen
3615 case enumeration_request
: min_size
= sizeof(DNSServiceFlags
) + // flags
3616 sizeof(uint32_t); // interface
3618 case reg_record_request
: min_size
= sizeof(DNSServiceFlags
) + // flags
3619 sizeof(uint32_t) + // interface
3620 sizeof(char) + // fullname
3621 (3 * sizeof(uint16_t)) + // type, class, rdlen
3622 sizeof(uint32_t); // ttl
3624 case add_record_request
: min_size
= sizeof(DNSServiceFlags
) + // flags
3625 (2 * sizeof(uint16_t)) + // type, rdlen
3626 sizeof(uint32_t); // ttl
3628 case update_record_request
: min_size
= sizeof(DNSServiceFlags
) + // flags
3629 sizeof(uint16_t) + // rdlen
3630 sizeof(uint32_t); // ttl
3632 case remove_record_request
: min_size
= sizeof(DNSServiceFlags
); // flags
3634 case reconfirm_record_request
: min_size
=sizeof(DNSServiceFlags
) + // flags
3635 sizeof(uint32_t) + // interface
3636 sizeof(char) + // fullname
3637 (3 * sizeof(uint16_t)); // type, class, rdlen
3639 case setdomain_request
: min_size
= sizeof(DNSServiceFlags
) + sizeof(char); // flags + domain
3642 LogMsg("ERROR: validate_message - unsupported request type: %d", rstate
->hdr
.op
);
3646 return (rstate
->data_bytes
>= min_size
? 0 : -1);
3650 mDNSlocal
uint32_t dnssd_htonl(uint32_t l
)
3655 data
= (char*) &ret
;
3664 mDNSlocal
char * win32_strerror(int inErrorCode
)
3666 static char buffer
[1024];
3669 memset(buffer
, 0, sizeof(buffer
));
3672 FORMAT_MESSAGE_FROM_SYSTEM
| FORMAT_MESSAGE_IGNORE_INSERTS
,
3674 (DWORD
) inErrorCode
,
3675 MAKELANGID( LANG_NEUTRAL
, SUBLANG_DEFAULT
),
3682 // Remove any trailing CR's or LF's since some messages have them.
3684 while( ( n
> 0 ) && isspace( ( (unsigned char *) buffer
)[ n
- 1 ] ) )
3686 buffer
[ --n
] = '\0';