1 /* -*- Mode: C; tab-width: 4 -*-
3 * Copyright (c) 2003 Apple Computer, Inc. All rights reserved.
5 * @APPLE_LICENSE_HEADER_START@
7 * This file contains Original Code and/or Modifications of Original Code
8 * as defined in and that are subject to the Apple Public Source License
9 * Version 2.0 (the 'License'). You may not use this file except in
10 * compliance with the License. Please obtain a copy of the License at
11 * http://www.opensource.apple.com/apsl/ and read it before using this
14 * The Original Code and all software distributed under the License are
15 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
19 * Please see the License for the specific language governing rights and
20 * limitations under the License.
22 * @APPLE_LICENSE_HEADER_END@
24 Change History (most recent first):
26 $Log: uds_daemon.c,v $
27 Revision 1.180 2005/03/10 00:13:12 cheshire
28 <rdar://problem/4043098> DNSServiceBrowse no longer returning error codes for invalid types
29 In handle_browse_request(), mStatus err was being set correctly if an error occurred,
30 but the end of the function returned mStatus_NoError intead of err.
32 Revision 1.179 2005/03/04 02:47:26 ksekar
33 <rdar://problem/4026393> SCPreference domains disappear from enumeration when moving out from firewall
35 Revision 1.178 2005/02/25 19:35:38 ksekar
36 <rdar://problem/4023750> Non-local empty string registration failures should not return errors to caller
38 Revision 1.177 2005/02/25 03:05:41 cheshire
39 Change "broken pipe" message to debugf()
41 Revision 1.176 2005/02/24 18:44:45 ksekar
42 <rdar://problem/4018516> Printer Sharing does not get re-registered with wide-area
44 Revision 1.175 2005/02/21 21:31:25 ksekar
45 <rdar://problem/4015162> changed LogMsg to debugf
47 Revision 1.174 2005/02/20 01:41:17 cheshire
48 Fix compiler signed/unsigned warning
50 Revision 1.173 2005/02/18 01:26:42 cheshire
51 <rdar://problem/4012162> "Could not write data to client after 60 seconds" message could be more helpful
52 Log additional information about failed client
54 Revision 1.172 2005/02/18 00:58:35 cheshire
55 <rdar://problem/4012162> "Could not write data to client after 60 seconds" message could be more helpful
57 Revision 1.171 2005/02/18 00:43:12 cheshire
58 <rdar://problem/4010245> mDNSResponder should auto-truncate service names that are too long
60 Revision 1.170 2005/02/16 01:15:02 cheshire
61 Improve LogOperation() debugging messages for DNSServiceBrowse and DNSServiceRegister
63 Revision 1.169 2005/02/08 01:57:14 cheshire
64 More detailed error reporting in udsserver_init()
66 Revision 1.168 2005/02/03 00:44:37 cheshire
67 <rdar://problem/3986663> DNSServiceUpdateRecord returns kDNSServiceErr_Invalid when rdlen=0, rdata=NULL
69 Revision 1.167 2005/02/02 02:19:32 cheshire
70 Add comment explaining why unlink(MDNS_UDS_SERVERPATH); fails
72 Revision 1.166 2005/02/01 19:58:52 ksekar
73 Shortened cryptic "broken pipe" syslog message
75 Revision 1.165 2005/02/01 19:56:47 ksekar
76 Moved LogMsg from daemon.c to uds_daemon.c, cleaned up wording
78 Revision 1.164 2005/01/28 06:07:55 cheshire
79 Don't use deliver_error() from within handle_regrecord_request()
81 Revision 1.163 2005/01/28 01:39:16 cheshire
82 Include file descriptor number in "broken pipe" message
84 Revision 1.162 2005/01/27 23:59:20 cheshire
85 Remove extraneous LogMsg
87 Revision 1.161 2005/01/27 22:57:56 cheshire
88 Fix compile errors on gcc4
90 Revision 1.160 2005/01/27 20:52:11 cheshire
91 <rdar://problem/3972566> mDNSResponder leaks sockets for add/update/remove record calls
93 Revision 1.159 2005/01/27 01:45:25 cheshire
94 <rdar://problem/3976147> mDNSResponder should never call exit(1);
96 Revision 1.158 2005/01/25 17:28:07 ksekar
97 <rdar://problem/3971467> Should not return "local" twice for domain enumeration
99 Revision 1.157 2005/01/21 02:20:39 cheshire
100 Fix mistake in LogOperation() format string
102 Revision 1.156 2005/01/19 19:15:36 ksekar
103 Refinement to <rdar://problem/3954575> - Simplify mDNS_PurgeResultsForDomain logic and move into daemon layer
105 Revision 1.155 2005/01/19 03:00:47 cheshire
106 Show Add/Rmv in DNSServiceBrowse LogOperation() message
108 Revision 1.154 2005/01/15 00:56:42 ksekar
109 <rdar://problem/3954575> Unicast services don't disappear when logging
112 Revision 1.153 2005/01/14 18:44:28 ksekar
113 <rdar://problem/3954609> mDNSResponder is crashing when changing domains
115 Revision 1.152 2005/01/13 17:16:38 ksekar
116 Back out checkin 1.150 - correct fix is on clientstub side
118 Revision 1.151 2005/01/11 21:06:29 ksekar
119 Changed now-benign LogMsg to debugf
121 Revision 1.150 2005/01/07 23:59:15 ksekar
122 <rdar://problem/3942900> dnd-sd shows the wrong port numbers
124 Revision 1.149 2004/12/20 23:20:35 cheshire
125 <rdar://problem/3928361> mDNSResponder crashes repeatedly when printer sharing is enabled
126 Make sure to call mDNS_SetupResourceRecord() for all newly created AuthRecords
128 Revision 1.148 2004/12/20 20:37:35 cheshire
129 AllowRemoteQuery not set for the extras in a ServiceRecordSet
131 Revision 1.147 2004/12/20 00:15:41 cheshire
132 Include client file descriptor numbers in udsserver_info() output
134 Revision 1.146 2004/12/17 05:25:47 cheshire
135 <rdar://problem/3925163> Shorten DNS-SD queries to avoid NAT bugs
137 Revision 1.145 2004/12/16 21:39:46 cheshire
138 Include CacheGroup objects in CacheUsed count
140 Revision 1.144 2004/12/16 21:27:38 ksekar
141 Fixed build failures when compiled with verbose debugging messages
143 Revision 1.143 2004/12/16 20:13:02 cheshire
144 <rdar://problem/3324626> Cache memory management improvements
146 Revision 1.142 2004/12/16 08:07:33 shersche
147 Fix compiler error (mixed declarations and code) on Windows
149 Revision 1.141 2004/12/16 01:56:21 cheshire
150 Improve DNSServiceEnumerateDomains syslog message
152 Revision 1.140 2004/12/14 03:02:10 ksekar
153 <rdar://problem/3919016> Rare race condition can cause crash
155 Revision 1.139 2004/12/13 21:18:45 ksekar
156 Include uDNS registrations in CountPeerRegistrations
158 Revision 1.138 2004/12/13 18:23:18 ksekar
159 <rdar://problem/3915805> mDNSResponder error when quitting iChat -
160 don't close sockets delivering errors to blocked clients
162 Revision 1.137 2004/12/13 00:09:22 ksekar
163 <rdar://problem/3915805> mDNSResponder error when quitting iChat
165 Revision 1.136 2004/12/11 01:52:10 cheshire
166 <rdar://problem/3785820> Support kDNSServiceFlagsAllowRemoteQuery for registering services too
168 Revision 1.135 2004/12/10 20:46:37 cheshire
169 Change LogOperation message to debugf
171 Revision 1.134 2004/12/10 13:19:37 cheshire
172 Add verbosedebugf() logging message in CountPeerRegistrations()
174 Revision 1.133 2004/12/10 05:27:26 cheshire
175 <rdar://problem/3909147> Guard against multiple autoname services of the same type on the same machine
177 Revision 1.132 2004/12/10 04:28:28 cheshire
178 <rdar://problem/3914406> User not notified of name changes for services using new UDS API
180 Revision 1.131 2004/12/10 02:09:25 cheshire
181 <rdar://problem/3898376> Modify default TTLs
183 Revision 1.130 2004/12/10 00:55:24 cheshire
184 Add full name and type to LogOperation messages for DNSServiceAddRecord/UpdateRecord/RemoveRecord
186 Revision 1.129 2004/12/09 03:17:23 ksekar
187 <rdar://problem/3910435> DomainEnumeration interface index should be zero
189 Revision 1.128 2004/12/07 21:26:05 ksekar
190 <rdar://problem/3908336> DNSServiceRegisterRecord() can crash on deregistration
192 Revision 1.127 2004/12/07 20:42:34 cheshire
193 Add explicit context parameter to mDNS_RemoveRecordFromService()
195 Revision 1.126 2004/12/07 17:23:55 ksekar
198 Revision 1.125 2004/12/06 21:15:23 ksekar
199 <rdar://problem/3884386> mDNSResponder crashed in CheckServiceRegistrations
201 Revision 1.124 2004/11/30 02:19:14 cheshire
202 <rdar://problem/3827971> Raise maxfds.rlim_cur for mDNSResponder
204 Revision 1.123 2004/11/29 23:50:57 cheshire
205 Checkin 1.122 not necessary
207 Revision 1.122 2004/11/24 17:55:01 ksekar
208 Added log message clarifying <rdar://problem/3869241> For unicast operations, verify that service types are legal
210 Revision 1.121 2004/11/24 04:45:52 cheshire
213 Revision 1.120 2004/11/24 00:10:44 cheshire
214 <rdar://problem/3869241> For unicast operations, verify that service types are legal
216 Revision 1.119 2004/11/23 23:54:17 ksekar
217 <rdar://problem/3890318> Wide-Area DNSServiceRegisterRecord() failures
218 can crash mDNSResponder
220 Revision 1.118 2004/11/23 22:33:01 cheshire
221 <rdar://problem/3654910> Remove temporary workaround code for iChat
223 Revision 1.117 2004/11/23 20:23:10 ksekar
224 Fixed LogOperation that causes crash on connected service deregistrations
226 Revision 1.116 2004/11/23 03:39:47 cheshire
227 Let interface name/index mapping capability live directly in JNISupport.c,
228 instead of having to call through to the daemon via IPC to get this information.
230 Revision 1.115 2004/11/13 00:12:53 ksekar
231 Fixed some LogOperation printf converstions for debug builds.
233 Revision 1.114 2004/11/12 18:25:45 shersche
234 Tidy up cross platform usleep code fragment.
236 Revision 1.113 2004/11/12 03:21:41 rpantos
237 rdar://problem/3809541 Add DNSSDMapIfIndexToName, DNSSDMapNameToIfIndex.
239 Revision 1.112 2004/11/11 16:58:32 ksekar
240 Removed unused code (previously wrapped in #if 0)
242 Revision 1.111 2004/11/05 22:47:37 shersche
243 Conditionally compile usleep(1000) to be Sleep(1) on Windows
244 Submitted by: Pavel Repin <prepin@gmail.com>
246 Revision 1.110 2004/11/05 19:56:56 ksekar
247 <rdar://problem/3862646> We no longer need to browse .Mac domains by
248 default - changed #if 0 to more descriptive #ifdef _HAVE_SETDOMAIN_SUPPORT_
250 Revision 1.109 2004/11/04 03:40:45 cheshire
251 More debugging messages
253 Revision 1.108 2004/11/03 02:25:51 cheshire
254 <rdar://problem/3324137> Conflict for Computer Name should update *all* empty string services, not just the one with the conflict
256 Revision 1.107 2004/11/02 19:39:23 ksekar
257 <rdar://problem/3862646> We no longer need to browse .Mac domains by default
259 Revision 1.106 2004/11/02 02:12:21 cheshire
260 <rdar://problem/3839111> Remove unnecessary memory allocations
262 Revision 1.105 2004/10/28 19:07:19 cheshire
263 Add some more debugging checks and improved LogOperation() messages
265 Revision 1.104 2004/10/26 18:53:15 cheshire
266 Avoid unused variable warning
268 Revision 1.103 2004/10/26 07:15:55 cheshire
269 Add file descriptor number to all LogOperation messages
271 Revision 1.102 2004/10/26 06:11:42 cheshire
272 Add improved logging to aid in diagnosis of <rdar://problem/3842714> mDNSResponder crashed
274 Revision 1.101 2004/10/26 04:31:44 cheshire
275 Rename CountSubTypes() as ChopSubTypes()
277 Revision 1.100 2004/10/26 01:17:48 cheshire
278 Use "#if 0" instead of commenting out code
280 Revision 1.99 2004/10/19 21:33:22 cheshire
281 <rdar://problem/3844991> Cannot resolve non-local registrations using the mach API
282 Added flag 'kDNSServiceFlagsForceMulticast'. Passing through an interface id for a unicast name
283 doesn't force multicast unless you set this flag to indicate explicitly that this is what you want
285 Revision 1.98 2004/10/14 01:59:33 cheshire
286 <rdar://problem/3839208> UDS resolves don't work for uDNS services
288 Revision 1.97 2004/10/13 00:58:35 cheshire
289 <rdar://problem/3832738> Registering a proxy doesn't work
291 Revision 1.96 2004/09/30 00:25:00 ksekar
292 <rdar://problem/3695802> Dynamically update default registration domains on config change
294 Revision 1.95 2004/09/26 23:20:36 ksekar
295 <rdar://problem/3813108> Allow default registrations in multiple wide-area domains
297 Revision 1.94 2004/09/22 18:27:06 ksekar
298 <rdar://problem/3811427> allow DNSServiceAddRecord to pass zero to get
301 Revision 1.93 2004/09/22 02:39:44 cheshire
302 <rdar://problem/3810757> Allow DNSServiceRegisterRecord to pass zero to get default record TTL
304 Revision 1.92 2004/09/22 02:34:04 cheshire
305 Rename parameter "ttl" to "GetTTL" for clarity
307 Revision 1.91 2004/09/22 02:25:43 cheshire
310 Revision 1.90 2004/09/21 23:40:12 ksekar
311 <rdar://problem/3810349> mDNSResponder to return errors on NAT traversal failure
313 Revision 1.89 2004/09/21 23:29:51 cheshire
314 <rdar://problem/3680045> DNSServiceResolve should delay sending packets
316 Revision 1.88 2004/09/21 23:12:46 cheshire
317 Reorder initialization of question fields to match structure order
319 Revision 1.87 2004/09/21 22:18:33 cheshire
320 In SIGINFO output, display a '-' next to records that have the Unique bit set
322 Revision 1.86 2004/09/21 21:05:11 cheshire
323 Move duplicate code out of mDNSMacOSX/daemon.c and mDNSPosix/PosixDaemon.c,
324 into mDNSShared/uds_daemon.c
326 Revision 1.85 2004/09/18 01:11:58 ksekar
327 <rdar://problem/3806734> Add a user's default domain to empty-string browse list
329 Revision 1.84 2004/09/17 01:08:55 cheshire
330 Renamed mDNSClientAPI.h to mDNSEmbeddedAPI.h
331 The name "mDNSClientAPI.h" is misleading to new developers looking at this code. The interfaces
332 declared in that file are ONLY appropriate to single-address-space embedded applications.
333 For clients on general-purpose computers, the interfaces defined in dns_sd.h should be used.
335 Revision 1.83 2004/09/16 23:26:33 cheshire
336 Move version check inside preceeding "if" that checks we have a complete header
338 Revision 1.82 2004/09/16 23:14:25 cheshire
339 Changes for Windows compatibility
341 Revision 1.81 2004/09/16 21:46:38 ksekar
342 <rdar://problem/3665304> Need SPI for LoginWindow to associate a UID with a Wide Area domain
344 Revision 1.80 2004/09/16 01:58:23 cheshire
345 Fix compiler warnings
347 Revision 1.79 2004/09/16 00:24:49 cheshire
348 <rdar://problem/3803162> Fix unsafe use of mDNSPlatformTimeNow()
350 Revision 1.78 2004/09/15 21:44:20 cheshire
351 <rdar://problem/3681031> Randomize initial timenow_adjust value in mDNS_Init
352 Show time value in log to help diagnose errors
354 Revision 1.77 2004/09/15 00:19:18 cheshire
355 <rdar://problem/3785823> read_rr_from_ipc_msg should use mDNS_SetupResourceRecord()
357 Revision 1.76 2004/09/02 06:39:52 cheshire
358 Minor textual cleanup for clarity
360 Revision 1.75 2004/09/02 03:48:47 cheshire
361 <rdar://problem/3709039> Disable targeted unicast query support by default
362 1. New flag kDNSServiceFlagsAllowRemoteQuery to indicate we want to allow remote queries for this record
363 2. New field AllowRemoteQuery in AuthRecord structure
364 3. uds_daemon.c sets AllowRemoteQuery if kDNSServiceFlagsAllowRemoteQuery is set
365 4. mDNS.c only answers remote queries if AllowRemoteQuery is set
367 Revision 1.74 2004/08/25 02:32:47 cheshire
368 Minor cleanup: replace "®type[0]" with "regtype"
370 Revision 1.73 2004/08/25 02:30:40 cheshire
371 <rdar://problem/3588761> Current method of doing subtypes causes name collisions
373 Revision 1.72 2004/08/14 03:22:42 cheshire
374 <rdar://problem/3762579> Dynamic DNS UI <-> mDNSResponder glue
375 Add GetUserSpecifiedDDNSName() routine
376 Convert ServiceRegDomain to domainname instead of C string
377 Replace mDNS_GenerateFQDN/mDNS_GenerateGlobalFQDN with mDNS_SetFQDNs
379 Revision 1.71 2004/08/11 04:21:21 rpantos
382 Revision 1.70 2004/08/11 02:07:00 cheshire
383 Remove "mDNS *globalInstance" parameter from udsserver_init()
384 Move CheckForDuplicateRegistrations from daemon.c
385 <rdar://problem/3501938> No warning when accidentally registering the same service multiple times using socket API
387 Revision 1.69 2004/08/10 16:14:48 cheshire
388 Fix debug builds (oops)
390 Revision 1.68 2004/08/10 06:24:56 cheshire
391 Use types with precisely defined sizes for 'op' and 'reg_index', for better
392 compatibility if the daemon and the client stub are built using different compilers
394 Revision 1.67 2004/07/27 07:14:16 shersche
395 make error socket non-blocking after call to connect()
397 Revision 1.66 2004/07/13 21:24:25 rpantos
398 Fix for <rdar://problem/3701120>.
400 Revision 1.65 2004/06/26 03:17:14 shersche
401 implement cross-platform strerror function
403 Submitted by: herscher
405 Revision 1.64 2004/06/25 00:26:27 rpantos
406 Changes to fix the Posix build on Solaris.
408 Revision 1.63 2004/06/24 03:43:44 rpantos
409 Fix previous checkin so it builds on Windows.
411 Revision 1.62 2004/06/24 00:57:08 ksekar
412 Replaced code acccidentally removed in checkin 1.59.
414 Revision 1.61 2004/06/19 00:09:39 cheshire
415 Remove unused strsep() implementation
417 Revision 1.60 2004/06/18 19:10:00 cheshire
418 <rdar://problem/3588761> Current method of doing subtypes causes name collisions
420 Revision 1.59 2004/06/18 05:10:31 rpantos
421 Changes to allow code to be used on Windows
423 Revision 1.58 2004/06/15 03:54:08 cheshire
424 Include mDNS_TimeNow(&mDNSStorage) in SIGINFO output
426 Revision 1.57 2004/06/12 01:47:27 ksekar
427 <rdar://problem/3690241>: BBEdit crashes when trying to check for newer version
428 udsserver_idle compared time in ticks to interval in seconds.
430 Revision 1.56 2004/06/12 01:35:47 cheshire
431 Changes for Windows compatibility
433 Revision 1.55 2004/06/05 00:04:27 cheshire
434 <rdar://problem/3668639>: wide-area domains should be returned in reg. domain enumeration
436 Revision 1.54 2004/06/01 22:22:52 ksekar
437 <rdar://problem/3668635>: wide-area default registrations should be in
440 Revision 1.53 2004/05/28 23:42:37 ksekar
441 <rdar://problem/3258021>: Feature: DNS server->client notification on record changes (#7805)
443 Revision 1.52 2004/05/26 00:39:49 ksekar
444 <rdar://problem/3667105>: wide-area DNS-SD servers don't appear in
446 Use local-only InterfaceID for GetDomains calls for sockets-API
448 Revision 1.51 2004/05/18 23:51:27 cheshire
449 Tidy up all checkin comments to use consistent "<rdar://problem/xxxxxxx>" format for bug numbers
451 Revision 1.50 2004/05/14 16:39:47 ksekar
452 Browse for iChat locally for now.
454 Revision 1.49 2004/05/13 21:33:52 ksekar
455 Clean up non-local registration control via config file. Force iChat
456 registrations to be local for now.
458 Revision 1.48 2004/05/13 04:13:19 ksekar
459 Updated SIGINFO handler for multi-domain browses
461 Revision 1.47 2004/05/12 22:04:01 ksekar
462 Implemented multi-domain browsing by default for uds_daemon.
464 Revision 1.46 2004/05/06 18:42:58 ksekar
465 General dns_sd.h API cleanup, including the following radars:
466 <rdar://problem/3592068>: Remove flags with zero value
467 <rdar://problem/3479569>: Passing in NULL causes a crash.
469 Revision 1.45 2004/03/12 08:49:28 cheshire
470 #include <sys/socket.h>
472 Revision 1.44 2004/02/25 01:25:27 ksekar
473 <rdar://problem/3569212>: DNSServiceRegisterRecord flags not error-checked
475 Revision 1.43 2004/02/24 01:46:40 cheshire
476 Manually reinstate lost checkin 1.36
478 Revision 1.42 2004/02/05 19:39:29 cheshire
479 Move creation of /var/run/mDNSResponder.pid to uds_daemon.c,
480 so that all platforms get this functionality
482 Revision 1.41 2004/02/03 18:59:02 cheshire
483 Change "char *domain" parameter for format_enumeration_reply to "const char *domain"
485 Revision 1.40 2004/01/28 03:41:00 cheshire
486 <rdar://problem/3541946>: Need ability to do targeted queries as well as multicast queries
488 Revision 1.39 2004/01/25 00:03:21 cheshire
489 Change to use mDNSVal16() instead of private PORT_AS_NUM() macro
491 Revision 1.38 2004/01/19 19:51:46 cheshire
492 Fix compiler error (mixed declarations and code) on some versions of Linux
494 Revision 1.37 2003/12/08 21:11:42 rpantos
495 Changes necessary to support mDNSResponder on Linux.
497 Revision 1.36 2003/12/04 23:40:57 cheshire
498 <rdar://problem/3484766>: Security: Crashing bug in mDNSResponder
499 Fix some more code that should use buffer size MAX_ESCAPED_DOMAIN_NAME (1005) instead of 256-byte buffers.
501 Revision 1.35 2003/12/03 19:10:22 ksekar
502 <rdar://problem/3498644>: malloc'd data not zero'd
504 Revision 1.34 2003/12/03 02:00:01 ksekar
505 <rdar://problem/3498644>: malloc'd data not zero'd
507 Revision 1.33 2003/11/22 01:18:46 ksekar
508 <rdar://problem/3486646>: config change handler not called for dns-sd services
510 Revision 1.32 2003/11/20 21:46:12 ksekar
511 <rdar://problem/3486635>: leak: DNSServiceRegisterRecord
513 Revision 1.31 2003/11/20 20:33:05 ksekar
514 <rdar://problem/3486635>: leak: DNSServiceRegisterRecord
516 Revision 1.30 2003/11/20 02:10:55 ksekar
517 <rdar://problem/3486643>: cleanup DNSServiceAdd/RemoveRecord
519 Revision 1.29 2003/11/14 21:18:32 cheshire
520 <rdar://problem/3484766>: Security: Crashing bug in mDNSResponder
521 Fix code that should use buffer size MAX_ESCAPED_DOMAIN_NAME (1005) instead of 256-byte buffers.
523 Revision 1.28 2003/11/08 22:18:29 cheshire
524 <rdar://problem/3477870>: Don't need to show process ID in *every* mDNSResponder syslog message
526 Revision 1.27 2003/11/05 22:44:57 ksekar
527 <rdar://problem/3335230>: No bounds checking when reading data from client
528 Reviewed by: Stuart Cheshire
530 Revision 1.26 2003/10/23 17:51:04 ksekar
531 <rdar://problem/3335216>: handle blocked clients more efficiently
532 Changed gettimeofday() to mDNS_TimeNow(&mDNSStorage);
534 Revision 1.25 2003/10/22 23:37:49 ksekar
535 <rdar://problem/3459141>: crash/hang in abort_client
537 Revision 1.24 2003/10/21 20:59:40 ksekar
538 <rdar://problem/3335216>: handle blocked clients moreefficiently
540 Revision 1.23 2003/09/23 02:12:43 cheshire
541 Also include port number in list of services registered via new UDS API
543 Revision 1.22 2003/08/19 16:03:55 ksekar
544 <rdar://problem/3380097>: ER: SIGINFO dump should include resolves started by DNSServiceQueryRecord
545 Check termination_context for NULL before dereferencing.
547 Revision 1.21 2003/08/19 05:39:43 cheshire
548 <rdar://problem/3380097> SIGINFO dump should include resolves started by DNSServiceQueryRecord
550 Revision 1.20 2003/08/16 03:39:01 cheshire
551 <rdar://problem/3338440> InterfaceID -1 indicates "local only"
553 Revision 1.19 2003/08/15 20:16:03 cheshire
554 <rdar://problem/3366590> mDNSResponder takes too much RPRVT
555 We want to avoid touching the rdata pages, so we don't page them in.
556 1. RDLength was stored with the rdata, which meant touching the page just to find the length.
557 Moved this from the RData to the ResourceRecord object.
558 2. To avoid unnecessarily touching the rdata just to compare it,
559 compute a hash of the rdata and store the hash in the ResourceRecord object.
561 Revision 1.18 2003/08/15 00:38:00 ksekar
562 <rdar://problem/3377005>: Bug: buffer overrun when reading long rdata from client
564 Revision 1.17 2003/08/14 02:18:21 cheshire
565 <rdar://problem/3375491> Split generic ResourceRecord type into two separate types: AuthRecord and CacheRecord
567 Revision 1.16 2003/08/13 23:58:52 ksekar
568 <rdar://problem/3374911>: Bug: UDS Sub-type browsing works, but not sub-type registration
569 Fixed pointer increment error, moved subtype reading for-loop for easier error bailout.
571 Revision 1.15 2003/08/13 17:30:33 ksekar
572 <rdar://problem/3374671>: DNSServiceAddRecord doesn't work
573 Fixed various problems with handling the AddRecord request and freeing the ExtraResourceRecords.
575 Revision 1.14 2003/08/12 19:56:25 cheshire
582 #define dnssd_strerror(X) win32_strerror(X)
583 #define usleep(X) Sleep(((X)+999)/1000)
584 static char * win32_strerror(int inErrorCode
);
588 #include <sys/ioctl.h>
589 #include <sys/types.h>
590 #include <sys/time.h>
591 #include <sys/resource.h>
592 #define dnssd_strerror(X) strerror(X)
597 #include "mDNSEmbeddedAPI.h"
598 #include "DNSCommon.h"
599 #include "uds_daemon.h"
601 #include "dnssd_ipc.h"
603 // Apple specific configuration functionality, not required for other platforms
605 #include <sys/ucred.h>
606 #ifndef LOCAL_PEERCRED
607 #define LOCAL_PEERCRED 0x001 /* retrieve peer credentials */
608 #endif // LOCAL_PEERCRED
611 // Types and Data Structures
612 // ----------------------------------------------------------------------
623 typedef void (*req_termination_fn
)(void *);
625 typedef struct registered_record_entry
629 struct registered_record_entry
*next
;
630 client_context_t client_context
;
631 struct request_state
*rstate
;
632 } registered_record_entry
;
634 // A single registered service: ServiceRecordSet + bookkeeping
635 // Note that we duplicate some fields from parent service_info object
636 // to facilitate cleanup, when instances and parent may be deallocated at different times.
637 typedef struct service_instance
639 struct service_instance
*next
;
640 mDNSBool autoname
; // Set if this name is tied to the Computer Name
641 mDNSBool autorename
; // Set if this client wants us to automatically rename on conflict
642 mDNSBool allowremotequery
; // Respond to unicast queries from outside the local link?
643 mDNSBool rename_on_memfree
; // Set on config change when we deregister original name
646 mDNSBool default_local
; // is this the "local." from an empty-string registration?
647 struct request_state
*request
;
649 AuthRecord
*subtypes
;
650 ServiceRecordSet srs
; // note - must be last field in struct
653 // A client-created service. May reference several service_info objects if default
654 // settings cause registration in multiple domains.
661 char type_as_string
[MAX_ESCAPED_DOMAIN_NAME
];
663 mDNSBool default_domain
;
665 mDNSBool autoname
; // Set if this name is tied to the Computer Name
666 mDNSBool autorename
; // Set if this client wants us to automatically rename on conflict
667 mDNSBool allowremotequery
; // Respond to unicast queries from outside the local link?
669 mDNSInterfaceID InterfaceID
;
670 service_instance
*instances
;
671 struct request_state
*request
;
674 // for multi-domain default browsing
675 typedef struct browser_t
679 struct browser_t
*next
;
682 // parent struct for browser instances: list pointer plus metadata
685 mDNSBool default_domain
;
688 mDNSInterfaceID interface_id
;
689 struct request_state
*rstate
;
695 mStatus err
; // Note: This field is in NETWORK byte order
698 } undelivered_error_t
;
700 typedef struct request_state
702 // connection structures
705 // state of read (in case message is read over several recv() calls)
707 uint32_t hdr_bytes
; // bytes of header already read
709 uint32_t data_bytes
; // bytes of message data already read
710 char *msgbuf
; // pointer to data storage to pass to free()
711 char *msgdata
; // pointer to data to be read from (may be modified)
712 int bufsize
; // size of data storage
714 // reply, termination, error, and client context info
715 int no_reply
; // don't send asynchronous replies to client
716 int time_blocked
; // record time of a blocked client
717 void *client_context
; // don't touch this - pointer only valid in client's addr space
718 struct reply_state
*replies
; // corresponding (active) reply list
719 undelivered_error_t
*u_err
;
720 void *termination_context
;
721 req_termination_fn terminate
;
723 //!!!KRS toss these pointers in a union
724 // registration context associated with this request (null if not applicable)
725 registered_record_entry
*reg_recs
; // muliple registrations for a connection-oriented request
726 service_info
*service_registration
;
727 browser_info_t
*browser_info
;
728 struct request_state
*next
;
731 // struct physically sits between ipc message header and call-specific fields in the message buffer
734 DNSServiceFlags flags
; // Note: This field is in NETWORK byte order
735 uint32_t ifi
; // Note: This field is in NETWORK byte order
736 DNSServiceErrorType error
; // Note: This field is in NETWORK byte order
739 typedef struct reply_state
741 // state of the transmission
746 // context of the reply
747 struct request_state
*request
; // the request that this answers
748 struct reply_state
*next
; // if there are multiple unsent replies
749 // pointer into message buffer - allows fields to be changed after message is formatted
752 char *sdata
; // pointer to start of call-specific data
753 // pointer to malloc'd buffer
757 // domain enumeration and resolv calls require 2 mDNSCore calls, so we need separate interconnected
758 // structures to handle callbacks
761 DNSQuestion question
;
762 mDNS_DomainType type
;
763 request_state
*rstate
;
770 request_state
*rstate
;
771 } enum_termination_t
;
775 request_state
*rstate
;
778 // const ResourceRecord *txt;
779 // const ResourceRecord *srv;
785 mDNSu8 txtdata
[AbsoluteMaxDNSMessageData
];
786 } resolve_termination_t
;
788 #ifdef _HAVE_SETDOMAIN_SUPPORT_
789 typedef struct default_browse_list_t
791 struct default_browse_list_t
*next
;
794 } default_browse_list_t
;
796 static default_browse_list_t
*default_browse_list
= NULL
;
797 #endif // _HAVE_SETDOMAIN_SUPPORT_
800 mDNSexport mDNS mDNSStorage
;
801 #define gmDNS (&mDNSStorage)
803 static dnssd_sock_t listenfd
= dnssd_InvalidSocket
;
804 static request_state
* all_requests
= NULL
;
806 #define MAX_TIME_BLOCKED 60 * mDNSPlatformOneSecond // try to send data to a blocked client for 60 seconds before
807 // terminating connection
808 #define MSG_PAD_BYTES 5 // pad message buffer (read from client) with n zero'd bytes to guarantee
809 // n get_string() calls w/o buffer overrun
810 // private function prototypes
811 static void connect_callback(void *info
);
812 static int read_msg(request_state
*rs
);
813 static int send_msg(reply_state
*rs
);
814 static void abort_request(request_state
*rs
);
815 static void request_callback(void *info
);
816 static void handle_resolve_request(request_state
*rstate
);
817 static void question_result_callback(mDNS
*const m
, DNSQuestion
*question
, const ResourceRecord
*const answer
, mDNSBool AddRecord
);
818 static void question_termination_callback(void *context
);
819 static void handle_browse_request(request_state
*request
);
820 static void browse_termination_callback(void *context
);
821 static void browse_result_callback(mDNS
*const m
, DNSQuestion
*question
, const ResourceRecord
*const answer
, mDNSBool AddRecord
);
822 static void handle_regservice_request(request_state
*request
);
823 static void regservice_termination_callback(void *context
);
824 static void process_service_registration(ServiceRecordSet
*const srs
, mDNSBool SuppressError
);
825 static void regservice_callback(mDNS
*const m
, ServiceRecordSet
*const srs
, mStatus result
);
826 static mStatus
handle_add_request(request_state
*rstate
);
827 static mStatus
handle_update_request(request_state
*rstate
);
828 static mStatus
gen_rr_response(domainname
*servicename
, mDNSInterfaceID id
, request_state
*request
, reply_state
**rep
);
829 static void append_reply(request_state
*req
, reply_state
*rep
);
830 static int build_domainname_from_strings(domainname
*srv
, char *name
, char *regtype
, char *domain
);
831 static void enum_termination_callback(void *context
);
832 static void enum_result_callback(mDNS
*const m
, DNSQuestion
*question
, const ResourceRecord
*const answer
, mDNSBool AddRecord
);
833 static void handle_query_request(request_state
*rstate
);
834 static reply_state
*format_enumeration_reply(request_state
*rstate
, const char *domain
, DNSServiceFlags flags
, uint32_t ifi
, DNSServiceErrorType err
);
835 static void handle_enum_request(request_state
*rstate
);
836 static mStatus
handle_regrecord_request(request_state
*rstate
);
837 static void regrecord_callback(mDNS
*const m
, AuthRecord
*const rr
, mStatus result
);
838 static void connected_registration_termination(void *context
);
839 static void handle_reconfirm_request(request_state
*rstate
);
840 static AuthRecord
*read_rr_from_ipc_msg(char *msgbuf
, int ttl
, int validate_flags
);
841 static mStatus
handle_removerecord_request(request_state
*rstate
);
842 static void reset_connected_rstate(request_state
*rstate
);
843 static int deliver_error(request_state
*rstate
, mStatus err
);
844 static int deliver_async_error(request_state
*rs
, reply_op_t op
, mStatus err
);
845 static transfer_state
send_undelivered_error(request_state
*rs
);
846 static reply_state
*create_reply(reply_op_t op
, size_t datalen
, request_state
*request
);
847 static void update_callback(mDNS
*const m
, AuthRecord
*const rr
, RData
*oldrd
);
848 static void my_perror(char *errmsg
);
849 static void unlink_request(request_state
*rs
);
850 static void resolve_result_callback(mDNS
*const m
, DNSQuestion
*question
, const ResourceRecord
*const answer
, mDNSBool AddRecord
);
851 static void resolve_termination_callback(void *context
);
852 static int validate_message(request_state
*rstate
);
853 static mStatus
remove_extra(request_state
*rstate
, service_instance
*serv
);
854 static mStatus
remove_record(request_state
*rstate
);
855 static void free_service_instance(service_instance
*srv
);
856 static uint32_t dnssd_htonl(uint32_t l
);
857 static void handle_setdomain_request(request_state
*rstate
);
859 // initialization, setup/teardown functions
861 // If a platform specifies its own PID file name, we use that
863 #define PID_FILE "/var/run/mDNSResponder.pid"
866 mDNSlocal
void LogClientInfo(request_state
*req
)
868 void *t
= req
->termination_context
;
871 if (req
->terminate
== regservice_termination_callback
)
873 service_instance
*ptr
;
874 for (ptr
= ((service_info
*)t
)->instances
; ptr
; ptr
= ptr
->next
)
875 LogMsgNoIdent("%3d: DNSServiceRegister %##s %u", req
->sd
, ptr
->srs
.RR_SRV
.resrec
.name
->c
, SRS_PORT(&ptr
->srs
));
877 else if (req
->terminate
== browse_termination_callback
)
880 for (blist
= req
->browser_info
->browsers
; blist
; blist
= blist
->next
)
881 LogMsgNoIdent("%3d: DNSServiceBrowse %##s", req
->sd
, blist
->q
.qname
.c
);
883 else if (req
->terminate
== resolve_termination_callback
)
884 LogMsgNoIdent("%3d: DNSServiceResolve %##s", req
->sd
, ((resolve_termination_t
*)t
)->qsrv
.qname
.c
);
885 else if (req
->terminate
== question_termination_callback
)
886 LogMsgNoIdent("%3d: DNSServiceQueryRecord %##s", req
->sd
, ((DNSQuestion
*) t
)->qname
.c
);
887 else if (req
->terminate
== enum_termination_callback
)
888 LogMsgNoIdent("%3d: DNSServiceEnumerateDomains %##s", req
->sd
, ((enum_termination_t
*) t
)->all
->question
.qname
.c
);
892 static void FatalError(char *errmsg
)
894 LogMsg("%s: %s", errmsg
, dnssd_strerror(dnssd_errno()));
895 *(long*)0 = 0; // On OS X abort() doesn't generate a crash log, but writing to zero does
896 abort(); // On platforms where writing to zero doesn't generate an exception, abort instead
899 int udsserver_init(void)
901 dnssd_sockaddr_t laddr
;
907 // If a particular platform wants to opt out of having a PID file, define PID_FILE to be ""
910 FILE *fp
= fopen(PID_FILE
, "w");
913 fprintf(fp
, "%d\n", getpid());
918 if ((listenfd
= socket(AF_DNSSD
, SOCK_STREAM
, 0)) == dnssd_InvalidSocket
)
920 my_perror("ERROR: socket(AF_DNSSD, SOCK_STREAM, 0); failed");
924 bzero(&laddr
, sizeof(laddr
));
926 #if defined(USE_TCP_LOOPBACK)
928 laddr
.sin_family
= AF_INET
;
929 laddr
.sin_port
= htons(MDNS_TCP_SERVERPORT
);
930 laddr
.sin_addr
.s_addr
= inet_addr(MDNS_TCP_SERVERADDR
);
931 ret
= bind(listenfd
, (struct sockaddr
*) &laddr
, sizeof(laddr
));
934 my_perror("ERROR: bind(listenfd, (struct sockaddr *) &laddr, sizeof(laddr)); failed");
940 mode_t mask
= umask(0);
941 unlink(MDNS_UDS_SERVERPATH
); //OK if this fails
942 laddr
.sun_family
= AF_LOCAL
;
943 #ifndef NOT_HAVE_SA_LEN
944 // According to Stevens (section 3.2), there is no portable way to
945 // determine whether sa_len is defined on a particular platform.
946 laddr
.sun_len
= sizeof(struct sockaddr_un
);
948 strcpy(laddr
.sun_path
, MDNS_UDS_SERVERPATH
);
949 ret
= bind(listenfd
, (struct sockaddr
*) &laddr
, sizeof(laddr
));
953 my_perror("ERROR: bind(listenfd, (struct sockaddr *) &laddr, sizeof(laddr)); failed");
961 // SEH: do we even need to do this on windows? this socket
962 // will be given to WSAEventSelect which will automatically
963 // set it to non-blocking
965 if (ioctlsocket(listenfd
, FIONBIO
, &opt
) != 0)
967 if (fcntl(listenfd
, F_SETFL
, O_NONBLOCK
) != 0)
970 my_perror("ERROR: could not set listen socket to non-blocking mode");
974 if (listen(listenfd
, LISTENQ
) != 0)
976 my_perror("ERROR: could not listen on listen socket");
980 if (mStatus_NoError
!= udsSupportAddFDToEventLoop(listenfd
, connect_callback
, (void *) NULL
))
982 my_perror("ERROR: could not add listen socket to event loop");
986 #if !defined(PLATFORM_NO_RLIMIT)
988 // Set maximum number of open file descriptors
989 #define MIN_OPENFILES 10240
990 struct rlimit maxfds
, newfds
;
992 // Due to bugs in OS X (<rdar://problem/2941095>, <rdar://problem/3342704>, <rdar://problem/3839173>)
993 // you have to get and set rlimits once before getrlimit will return sensible values
994 if (getrlimit(RLIMIT_NOFILE
, &maxfds
) < 0) { my_perror("ERROR: Unable to get file descriptor limit"); return 0; }
995 if (setrlimit(RLIMIT_NOFILE
, &maxfds
) < 0) my_perror("ERROR: Unable to set maximum file descriptor limit");
997 if (getrlimit(RLIMIT_NOFILE
, &maxfds
) < 0) { my_perror("ERROR: Unable to get file descriptor limit"); return 0; }
998 newfds
.rlim_max
= (maxfds
.rlim_max
> MIN_OPENFILES
) ? maxfds
.rlim_max
: MIN_OPENFILES
;
999 newfds
.rlim_cur
= (maxfds
.rlim_cur
> MIN_OPENFILES
) ? maxfds
.rlim_cur
: MIN_OPENFILES
;
1000 if (newfds
.rlim_max
!= maxfds
.rlim_max
|| newfds
.rlim_cur
!= maxfds
.rlim_cur
)
1001 if (setrlimit(RLIMIT_NOFILE
, &newfds
) < 0) my_perror("ERROR: Unable to set maximum file descriptor limit");
1003 if (getrlimit(RLIMIT_NOFILE
, &maxfds
) < 0) { my_perror("ERROR: Unable to get file descriptor limit"); return 0; }
1004 debugf("maxfds.rlim_max %d", (long)maxfds
.rlim_max
);
1005 debugf("maxfds.rlim_cur %d", (long)maxfds
.rlim_cur
);
1013 my_perror("ERROR: udsserver_init");
1017 int udsserver_exit(void)
1019 dnssd_close(listenfd
);
1021 #if !defined(USE_TCP_LOOPBACK)
1022 // Currently, we're unable to remove /var/run/mdnsd because we've changed to userid "nobody"
1023 // to give up unnecessary privilege, but we need to be root to remove this Unix Domain Socket.
1024 // It would be nice if we could find a solution to this problem
1025 if (unlink(MDNS_UDS_SERVERPATH
))
1026 debugf("Unable to remove %s", MDNS_UDS_SERVERPATH
);
1032 mDNSs32
udsserver_idle(mDNSs32 nextevent
)
1034 request_state
*req
= all_requests
, *tmp
, *prev
= NULL
;
1036 transfer_state result
;
1037 mDNSs32 now
= mDNS_TimeNow(&mDNSStorage
);
1041 result
= t_uninitialized
;
1043 result
= send_undelivered_error(req
);
1044 if (result
!= t_error
&& result
!= t_morecoming
&& // don't try to send msg if send_error failed
1045 (req
->ts
== t_complete
|| req
->ts
== t_morecoming
))
1049 if (req
->replies
->next
) req
->replies
->rhdr
->flags
|= dnssd_htonl(kDNSServiceFlagsMoreComing
);
1050 result
= send_msg(req
->replies
);
1051 if (result
== t_complete
)
1053 fptr
= req
->replies
;
1054 req
->replies
= req
->replies
->next
;
1055 freeL("udsserver_idle", fptr
);
1056 req
->time_blocked
= 0; // reset failure counter after successful send
1058 else if (result
== t_terminated
|| result
== t_error
)
1063 else if (result
== t_morecoming
) break; // client's queues are full, move to next
1066 if (result
== t_morecoming
)
1068 if (!req
->time_blocked
) req
->time_blocked
= now
;
1069 debugf("udsserver_idle: client has been blocked for %ld seconds", (now
- req
->time_blocked
) / mDNSPlatformOneSecond
);
1070 if (now
- req
->time_blocked
>= MAX_TIME_BLOCKED
)
1072 LogMsg("Could not write data to client %d after %ld seconds - aborting connection", req
->sd
, MAX_TIME_BLOCKED
/ mDNSPlatformOneSecond
);
1075 result
= t_terminated
;
1077 else if (nextevent
- now
> mDNSPlatformOneSecond
) nextevent
= now
+ mDNSPlatformOneSecond
; // try again in a second
1079 if (result
== t_terminated
|| result
== t_error
)
1080 //since we're already doing a list traversal, we unlink the request manunally instead of calling unlink_request()
1083 if (prev
) prev
->next
= req
->next
;
1084 if (req
== all_requests
) all_requests
= all_requests
->next
;
1086 freeL("udsserver_idle", tmp
);
1097 void udsserver_info(mDNS
*const m
)
1099 mDNSs32 now
= mDNS_TimeNow(m
);
1100 mDNSu32 CacheUsed
= 0, CacheActive
= 0;
1106 LogMsgNoIdent("Timenow 0x%08lX (%ld)", (mDNSu32
)now
, now
);
1108 for (slot
= 0; slot
< CACHE_HASH_SLOTS
; slot
++)
1109 for(cg
= m
->rrcache_hash
[slot
]; cg
; cg
=cg
->next
)
1111 CacheUsed
++; // Count one cache entity for the CacheGroup object
1112 for (rr
= cg
->members
; rr
; rr
=rr
->next
)
1114 mDNSs32 remain
= rr
->resrec
.rroriginalttl
- (now
- rr
->TimeRcvd
) / mDNSPlatformOneSecond
;
1116 if (rr
->CRActiveQuestion
) CacheActive
++;
1117 LogMsgNoIdent("%s%6ld %s%-6s%-6s%s",
1118 rr
->CRActiveQuestion
? "*" : " ", remain
,
1119 (rr
->resrec
.RecordType
& kDNSRecordTypePacketUniqueMask
) ? "-" : " ", DNSTypeName(rr
->resrec
.rrtype
),
1120 ((NetworkInterfaceInfo
*)rr
->resrec
.InterfaceID
)->ifname
, CRDisplayString(m
, rr
));
1121 usleep(1000); // Limit rate a little so we don't flood syslog too fast
1125 if (m
->rrcache_totalused
!= CacheUsed
)
1126 LogMsgNoIdent("Cache use mismatch: rrcache_totalused is %lu, true count %lu", m
->rrcache_totalused
, CacheUsed
);
1127 if (m
->rrcache_active
!= CacheActive
)
1128 LogMsgNoIdent("Cache use mismatch: rrcache_active is %lu, true count %lu", m
->rrcache_active
, CacheActive
);
1129 LogMsgNoIdent("Cache currently contains %lu records; %lu referenced by active questions", CacheUsed
, CacheActive
);
1131 for (req
= all_requests
; req
; req
=req
->next
)
1134 now
= mDNS_TimeNow(m
);
1135 LogMsgNoIdent("Timenow 0x%08lX (%ld)", (mDNSu32
)now
, now
);
1138 static void rename_service(service_instance
*srv
)
1140 if (srv
->autoname
&& !SameDomainLabel(srv
->name
.c
, gmDNS
->nicelabel
.c
))
1142 srv
->rename_on_memfree
= 1;
1143 if (mDNS_DeregisterService(gmDNS
, &srv
->srs
)) // If service deregistered already, we can re-register immediately
1144 regservice_callback(gmDNS
, &srv
->srs
, mStatus_MemFree
);
1148 void udsserver_handle_configchange(void)
1153 for (req
= all_requests
; req
; req
= req
->next
)
1155 if (req
->service_registration
)
1157 service_instance
*ptr
;
1158 for (ptr
= req
->service_registration
->instances
; ptr
; ptr
= ptr
->next
)
1159 rename_service(ptr
);
1164 static void connect_callback(void *info
)
1168 unsigned long optval
;
1169 dnssd_sockaddr_t cliaddr
;
1170 request_state
*rstate
;
1171 (void)info
; // Unused
1173 len
= (int) sizeof(cliaddr
);
1175 sd
= accept(listenfd
, (struct sockaddr
*) &cliaddr
, &len
);
1177 if (sd
== dnssd_InvalidSocket
)
1179 if (dnssd_errno() == dnssd_EWOULDBLOCK
) return;
1180 my_perror("ERROR: accept");
1186 // Some environments (e.g. OS X) support turning off SIGPIPE for a socket
1187 if (setsockopt(sd
, SOL_SOCKET
, SO_NOSIGPIPE
, &optval
, sizeof(optval
)) < 0)
1189 my_perror("ERROR: setsockopt - SO_NOSIGPIPE - aborting client");
1196 if (ioctlsocket(sd
, FIONBIO
, &optval
) != 0)
1198 if (fcntl(sd
, F_SETFL
, O_NONBLOCK
) != 0)
1201 my_perror("ERROR: fcntl(sd, F_SETFL, O_NONBLOCK) - aborting client");
1206 // allocate a request_state struct that will live with the socket
1207 rstate
= mallocL("connect_callback", sizeof(request_state
));
1208 if (!rstate
) FatalError("ERROR: malloc");
1209 bzero(rstate
, sizeof(request_state
));
1210 rstate
->ts
= t_morecoming
;
1213 LogOperation("%3d: Adding FD", rstate
->sd
);
1214 if ( mStatus_NoError
!= udsSupportAddFDToEventLoop( sd
, request_callback
, rstate
))
1216 rstate
->next
= all_requests
;
1217 all_requests
= rstate
;
1221 static void request_callback(void *info
)
1223 request_state
*rstate
= info
;
1224 transfer_state result
;
1225 dnssd_sockaddr_t cliaddr
;
1226 int dedicated_error_socket
;
1231 result
= read_msg(rstate
);
1232 if (result
== t_morecoming
)
1236 if (result
== t_terminated
)
1238 abort_request(rstate
);
1239 unlink_request(rstate
);
1242 if (result
== t_error
)
1244 abort_request(rstate
);
1245 unlink_request(rstate
);
1249 if (rstate
->hdr
.version
!= VERSION
)
1251 LogMsg("ERROR: client incompatible with daemon (client version = %d, "
1252 "daemon version = %d)\n", rstate
->hdr
.version
, VERSION
);
1253 abort_request(rstate
);
1254 unlink_request(rstate
);
1258 if (validate_message(rstate
) < 0)
1260 // note that we cannot deliver an error message if validation fails, since the path to the error socket
1261 // may be contained in the (invalid) message body for some message types
1262 abort_request(rstate
);
1263 unlink_request(rstate
);
1264 LogMsg("Invalid message sent by client - may indicate a malicious program running on this machine!");
1268 // check if client wants silent operation
1269 if (rstate
->hdr
.flags
& IPC_FLAGS_NOREPLY
) rstate
->no_reply
= 1;
1271 dedicated_error_socket
= (rstate
->hdr
.op
== reg_record_request
|| rstate
->hdr
.op
== add_record_request
||
1272 rstate
->hdr
.op
== update_record_request
|| rstate
->hdr
.op
== remove_record_request
);
1274 if (((rstate
->hdr
.flags
& IPC_FLAGS_REUSE_SOCKET
) == 0) != dedicated_error_socket
)
1275 LogMsg("WARNING: client request %d with incorrect flags setting 0x%X", rstate
->hdr
.op
, rstate
->hdr
.flags
);
1277 // check if primary socket is to be used for synchronous errors, else open new socket
1278 if (dedicated_error_socket
)
1282 int errfd
= socket(AF_DNSSD
, SOCK_STREAM
, 0);
1283 if (errfd
== dnssd_InvalidSocket
)
1285 my_perror("ERROR: socket");
1286 abort_request(rstate
);
1287 unlink_request(rstate
);
1291 #if defined(USE_TCP_LOOPBACK)
1294 port
.b
[0] = rstate
->msgdata
[0];
1295 port
.b
[1] = rstate
->msgdata
[1];
1296 rstate
->msgdata
+= 2;
1297 cliaddr
.sin_family
= AF_INET
;
1298 cliaddr
.sin_port
= port
.NotAnInteger
;
1299 cliaddr
.sin_addr
.s_addr
= inet_addr(MDNS_TCP_SERVERADDR
);
1303 char ctrl_path
[MAX_CTLPATH
];
1304 get_string(&rstate
->msgdata
, ctrl_path
, 256); // path is first element in message buffer
1305 bzero(&cliaddr
, sizeof(cliaddr
));
1306 cliaddr
.sun_family
= AF_LOCAL
;
1307 strcpy(cliaddr
.sun_path
, ctrl_path
);
1310 if (connect(errfd
, (struct sockaddr
*)&cliaddr
, sizeof(cliaddr
)) < 0)
1312 my_perror("ERROR: connect");
1313 abort_request(rstate
);
1314 unlink_request(rstate
);
1318 if (ioctlsocket(errfd
, FIONBIO
, &opt
) != 0)
1320 if (fcntl(errfd
, F_SETFL
, O_NONBLOCK
) != 0)
1323 my_perror("ERROR: could not set control socket to non-blocking mode");
1324 abort_request(rstate
);
1325 unlink_request(rstate
);
1329 switch(rstate
->hdr
.op
)
1331 case reg_record_request
: err
= handle_regrecord_request (rstate
); break;
1332 case add_record_request
: err
= handle_add_request (rstate
); break;
1333 case update_record_request
: err
= handle_update_request (rstate
); break;
1334 case remove_record_request
: err
= handle_removerecord_request(rstate
); break;
1335 default: LogMsg("%3d: ERROR: udsserver_recv_request - unsupported request type: %d", rstate
->sd
, rstate
->hdr
.op
);
1338 err
= dnssd_htonl(err
);
1339 nwritten
= send(errfd
, &err
, sizeof(err
), 0);
1340 // On a freshly-created Unix Domain Socket, the kernel should *never* fail to buffer a four-byte write for us.
1341 // If not, we don't attempt to handle this failure, but we do log it.
1342 if (nwritten
< (int)sizeof(err
))
1343 LogMsg("ERROR: failed to write error response back to caller: %d %d %s",
1344 nwritten
, dnssd_errno(), dnssd_strerror(dnssd_errno()));
1346 reset_connected_rstate(rstate
); // Reset ready to accept the next request on this pipe
1350 switch(rstate
->hdr
.op
)
1352 case resolve_request
: handle_resolve_request (rstate
); break;
1353 case query_request
: handle_query_request (rstate
); break;
1354 case browse_request
: handle_browse_request (rstate
); break;
1355 case reg_service_request
: handle_regservice_request(rstate
); break;
1356 case enumeration_request
: handle_enum_request (rstate
); break;
1357 case reconfirm_record_request
: handle_reconfirm_request (rstate
); break;
1358 case setdomain_request
: handle_setdomain_request (rstate
); break;
1359 default: LogMsg("%3d: ERROR: udsserver_recv_request - unsupported request type: %d", rstate
->sd
, rstate
->hdr
.op
);
1364 // mDNS operation functions. Each operation has 3 associated functions - a request handler that parses
1365 // the client's request and makes the appropriate mDNSCore call, a result handler (passed as a callback
1366 // to the mDNSCore routine) that sends results back to the client, and a termination routine that aborts
1367 // the mDNSCore operation if the client dies or closes its socket.
1369 // query and resolve calls have separate request handlers that parse the arguments from the client and
1370 // massage the name parameters appropriately, but the rest of the operations (making the query call,
1371 // delivering the result to the client, and termination) are identical.
1373 static void handle_query_request(request_state
*rstate
)
1375 DNSServiceFlags flags
;
1378 uint16_t rrtype
, rrclass
;
1381 mDNSInterfaceID InterfaceID
;
1384 if (rstate
->ts
!= t_complete
)
1386 LogMsg("ERROR: handle_query_request - transfer state != t_complete");
1389 ptr
= rstate
->msgdata
;
1392 LogMsg("ERROR: handle_query_request - NULL msgdata");
1396 flags
= get_flags(&ptr
);
1397 ifi
= get_long(&ptr
);
1398 if (get_string(&ptr
, name
, 256) < 0) goto bad_param
;
1399 rrtype
= get_short(&ptr
);
1400 rrclass
= get_short(&ptr
);
1401 InterfaceID
= mDNSPlatformInterfaceIDfromInterfaceIndex(gmDNS
, ifi
);
1402 if (ifi
&& !InterfaceID
) goto bad_param
;
1404 q
= mallocL("DNSQuestion", sizeof(DNSQuestion
));
1405 if (!q
) FatalError("ERROR: handle_query - malloc");
1406 bzero(q
, sizeof(DNSQuestion
));
1408 q
->InterfaceID
= InterfaceID
;
1409 q
->Target
= zeroAddr
;
1410 if (!MakeDomainNameFromDNSNameString(&q
->qname
, name
)) { freeL("DNSQuestion", q
); goto bad_param
; }
1412 q
->qclass
= rrclass
;
1413 q
->LongLived
= (flags
& kDNSServiceFlagsLongLivedQuery
) != 0;
1414 q
->ExpectUnique
= mDNSfalse
;
1415 q
->ForceMCast
= (flags
& kDNSServiceFlagsForceMulticast
) != 0;
1416 q
->QuestionCallback
= question_result_callback
;
1417 q
->QuestionContext
= rstate
;
1419 rstate
->termination_context
= q
;
1420 rstate
->terminate
= question_termination_callback
;
1422 LogOperation("%3d: DNSServiceQueryRecord(%##s, %s) START", rstate
->sd
, q
->qname
.c
, DNSTypeName(q
->qtype
));
1423 result
= mDNS_StartQuery(gmDNS
, q
);
1424 if (result
!= mStatus_NoError
) LogMsg("ERROR: mDNS_StartQuery: %d", (int)result
);
1426 if (result
) rstate
->terminate
= NULL
;
1427 if (deliver_error(rstate
, result
) < 0) goto error
;
1431 deliver_error(rstate
, mStatus_BadParamErr
);
1432 rstate
->terminate
= NULL
; // don't try to terminate insuccessful Core calls
1434 abort_request(rstate
);
1435 unlink_request(rstate
);
1439 static void handle_resolve_request(request_state
*rstate
)
1441 DNSServiceFlags flags
;
1442 uint32_t interfaceIndex
;
1443 mDNSInterfaceID InterfaceID
;
1444 char name
[256], regtype
[MAX_ESCAPED_DOMAIN_NAME
], domain
[MAX_ESCAPED_DOMAIN_NAME
];
1445 char *ptr
; // message data pointer
1447 resolve_termination_t
*term
;
1450 if (rstate
->ts
!= t_complete
)
1452 LogMsg("ERROR: handle_resolve_request - transfer state != t_complete");
1453 abort_request(rstate
);
1454 unlink_request(rstate
);
1458 // extract the data from the message
1459 ptr
= rstate
->msgdata
;
1462 LogMsg("ERROR: handle_resolve_request - NULL msgdata");
1463 abort_request(rstate
);
1464 unlink_request(rstate
);
1467 flags
= get_flags(&ptr
);
1468 interfaceIndex
= get_long(&ptr
);
1469 InterfaceID
= mDNSPlatformInterfaceIDfromInterfaceIndex(gmDNS
, interfaceIndex
);
1470 if (interfaceIndex
&& !InterfaceID
)
1471 { LogMsg("ERROR: handle_resolve_request - Couldn't find InterfaceID for interfaceIndex %d", interfaceIndex
); goto bad_param
; }
1472 if (get_string(&ptr
, name
, 256) < 0 ||
1473 get_string(&ptr
, regtype
, MAX_ESCAPED_DOMAIN_NAME
) < 0 ||
1474 get_string(&ptr
, domain
, MAX_ESCAPED_DOMAIN_NAME
) < 0)
1475 { LogMsg("ERROR: handle_resolve_request - Couldn't read name/regtype/domain"); goto bad_param
; }
1477 // free memory in rstate since we don't need it anymore
1478 freeL("handle_resolve_request", rstate
->msgbuf
);
1479 rstate
->msgbuf
= NULL
;
1481 if (build_domainname_from_strings(&fqdn
, name
, regtype
, domain
) < 0)
1482 { LogMsg("ERROR: handle_resolve_request - Couldn't build_domainname_from_strings “%s” “%s” “%s”", name
, regtype
, domain
); goto bad_param
; }
1484 // set up termination info
1485 term
= mallocL("handle_resolve_request", sizeof(resolve_termination_t
));
1486 bzero(term
, sizeof(*term
));
1487 if (!term
) FatalError("ERROR: malloc");
1490 term
->qsrv
.InterfaceID
= InterfaceID
;
1491 term
->qsrv
.Target
= zeroAddr
;
1492 memcpy(&term
->qsrv
.qname
, &fqdn
, MAX_DOMAIN_NAME
);
1493 term
->qsrv
.qtype
= kDNSType_SRV
;
1494 term
->qsrv
.qclass
= kDNSClass_IN
;
1495 term
->qsrv
.LongLived
= mDNSfalse
;
1496 term
->qsrv
.ExpectUnique
= mDNStrue
;
1497 term
->qsrv
.ForceMCast
= mDNSfalse
;
1498 term
->qsrv
.QuestionCallback
= resolve_result_callback
;
1499 term
->qsrv
.QuestionContext
= rstate
;
1501 term
->qtxt
.InterfaceID
= InterfaceID
;
1502 term
->qtxt
.Target
= zeroAddr
;
1503 memcpy(&term
->qtxt
.qname
, &fqdn
, MAX_DOMAIN_NAME
);
1504 term
->qtxt
.qtype
= kDNSType_TXT
;
1505 term
->qtxt
.qclass
= kDNSClass_IN
;
1506 term
->qtxt
.LongLived
= mDNSfalse
;
1507 term
->qtxt
.ExpectUnique
= mDNStrue
;
1508 term
->qtxt
.ForceMCast
= mDNSfalse
;
1509 term
->qtxt
.QuestionCallback
= resolve_result_callback
;
1510 term
->qtxt
.QuestionContext
= rstate
;
1512 term
->rstate
= rstate
;
1513 rstate
->termination_context
= term
;
1514 rstate
->terminate
= resolve_termination_callback
;
1516 // ask the questions
1517 LogOperation("%3d: DNSServiceResolve(%##s) START", rstate
->sd
, term
->qsrv
.qname
.c
);
1518 err
= mDNS_StartQuery(gmDNS
, &term
->qsrv
);
1519 if (!err
) err
= mDNS_StartQuery(gmDNS
, &term
->qtxt
);
1523 freeL("handle_resolve_request", term
);
1524 rstate
->terminate
= NULL
; // prevent abort_request() from invoking termination callback
1526 if (deliver_error(rstate
, err
) < 0 || err
)
1528 abort_request(rstate
);
1529 unlink_request(rstate
);
1534 deliver_error(rstate
, mStatus_BadParamErr
);
1535 abort_request(rstate
);
1536 unlink_request(rstate
);
1539 static void resolve_termination_callback(void *context
)
1541 resolve_termination_t
*term
= context
;
1546 LogMsg("ERROR: resolve_termination_callback: double termination");
1550 LogOperation("%3d: DNSServiceResolve(%##s) STOP", rs
->sd
, term
->qtxt
.qname
.c
);
1552 mDNS_StopQuery(gmDNS
, &term
->qtxt
);
1553 mDNS_StopQuery(gmDNS
, &term
->qsrv
);
1555 freeL("resolve_termination_callback", term
);
1556 rs
->termination_context
= NULL
;
1559 static void resolve_result_callback(mDNS
*const m
, DNSQuestion
*question
, const ResourceRecord
*const answer
, mDNSBool AddRecord
)
1562 char fullname
[MAX_ESCAPED_DOMAIN_NAME
], target
[MAX_ESCAPED_DOMAIN_NAME
];
1564 transfer_state result
;
1566 request_state
*rs
= question
->QuestionContext
;
1567 resolve_termination_t
*res
= rs
->termination_context
;
1570 LogOperation("%3d: DNSServiceResolve(%##s, %s) RESULT %s", rs
->sd
, question
->qname
.c
, DNSTypeName(question
->qtype
), RRDisplayString(m
, answer
));
1572 // This code used to do this trick of just keeping a copy of the pointer to
1573 // the answer record in the cache, but the unicast query code doesn't currently
1574 // put its answer records in the cache, so for now we can't do this.
1578 // if (answer->rrtype == kDNSType_TXT && res->txt == answer) res->txt = mDNSNULL;
1579 // if (answer->rrtype == kDNSType_SRV && res->srv == answer) res->srv = mDNSNULL;
1583 // if (answer->rrtype == kDNSType_TXT) res->txt = answer;
1584 // if (answer->rrtype == kDNSType_SRV) res->srv = answer;
1586 if (answer
->rrtype
== kDNSType_SRV
)
1588 AssignDomainName(&res
->target
, &answer
->rdata
->u
.srv
.target
);
1589 res
->port
= answer
->rdata
->u
.srv
.port
;
1590 res
->srv
= mDNStrue
;
1592 if (answer
->rrtype
== kDNSType_TXT
)
1594 if (answer
->rdlength
> AbsoluteMaxDNSMessageData
) return;
1595 res
->txtlen
= answer
->rdlength
;
1596 mDNSPlatformMemCopy(answer
->rdata
->u
.data
, res
->txtdata
, res
->txtlen
);
1597 res
->txt
= mDNStrue
;
1600 if (!res
->txt
|| !res
->srv
) return; // only deliver result to client if we have both answers
1602 ConvertDomainNameToCString(answer
->name
, fullname
);
1603 ConvertDomainNameToCString(&res
->target
, target
);
1605 // calculate reply length
1606 len
+= sizeof(DNSServiceFlags
);
1607 len
+= sizeof(uint32_t); // interface index
1608 len
+= sizeof(DNSServiceErrorType
);
1609 len
+= strlen(fullname
) + 1;
1610 len
+= strlen(target
) + 1;
1611 len
+= 2 * sizeof(uint16_t); // port, txtLen
1614 // allocate/init reply header
1615 rep
= create_reply(resolve_reply
, len
, rs
);
1616 rep
->rhdr
->flags
= dnssd_htonl(0);
1617 rep
->rhdr
->ifi
= dnssd_htonl(mDNSPlatformInterfaceIndexfromInterfaceID(gmDNS
, answer
->InterfaceID
));
1618 rep
->rhdr
->error
= dnssd_htonl(kDNSServiceErr_NoError
);
1622 // write reply data to message
1623 put_string(fullname
, &data
);
1624 put_string(target
, &data
);
1625 *data
++ = res
->port
.b
[0];
1626 *data
++ = res
->port
.b
[1];
1627 put_short(res
->txtlen
, &data
);
1628 put_rdata(res
->txtlen
, res
->txtdata
, &data
);
1630 result
= send_msg(rep
);
1631 if (result
== t_error
|| result
== t_terminated
)
1635 freeL("resolve_result_callback", rep
);
1637 else if (result
== t_complete
) freeL("resolve_result_callback", rep
);
1638 else append_reply(rs
, rep
);
1641 // what gets called when a resolve is completed and we need to send the data back to the client
1642 static void question_result_callback(mDNS
*const m
, DNSQuestion
*question
, const ResourceRecord
*const answer
, mDNSBool AddRecord
)
1645 char name
[MAX_ESCAPED_DOMAIN_NAME
];
1646 request_state
*req
= question
->QuestionContext
;
1651 LogOperation("%3d: DNSServiceQueryRecord(%##s, %s) RESULT %s", req
->sd
, question
->qname
.c
, DNSTypeName(question
->qtype
), RRDisplayString(m
, answer
));
1652 //mDNS_StopQuery(m, question);
1654 // calculate reply data length
1655 len
= sizeof(DNSServiceFlags
);
1656 len
+= 2 * sizeof(uint32_t); // if index + ttl
1657 len
+= sizeof(DNSServiceErrorType
);
1658 len
+= 3 * sizeof(uint16_t); // type, class, rdlen
1659 len
+= answer
->rdlength
;
1660 ConvertDomainNameToCString(answer
->name
, name
);
1661 len
+= strlen(name
) + 1;
1663 rep
= create_reply(query_reply
, len
, req
);
1665 rep
->rhdr
->flags
= dnssd_htonl(AddRecord
? kDNSServiceFlagsAdd
: 0);
1666 rep
->rhdr
->ifi
= dnssd_htonl(mDNSPlatformInterfaceIndexfromInterfaceID(gmDNS
, answer
->InterfaceID
));
1667 rep
->rhdr
->error
= dnssd_htonl(kDNSServiceErr_NoError
);
1671 put_string(name
, &data
);
1672 put_short(answer
->rrtype
, &data
);
1673 put_short(answer
->rrclass
, &data
);
1674 put_short(answer
->rdlength
, &data
);
1675 put_rdata(answer
->rdlength
, answer
->rdata
->u
.data
, &data
);
1676 put_long(AddRecord
? answer
->rroriginalttl
: 0, &data
);
1678 append_reply(req
, rep
);
1682 static void question_termination_callback(void *context
)
1684 DNSQuestion
*q
= context
;
1685 LogOperation("%3d: DNSServiceQueryRecord(%##s, %s) STOP", ((request_state
*)q
->QuestionContext
)->sd
, q
->qname
.c
, DNSTypeName(q
->qtype
));
1686 mDNS_StopQuery(gmDNS
, q
); // no need to error check
1687 freeL("question_termination_callback", q
);
1690 // If there's a comma followed by another character,
1691 // FindFirstSubType overwrites the comma with a nul and returns the pointer to the next character.
1692 // Otherwise, it returns a pointer to the final nul at the end of the string
1693 static char *FindFirstSubType(char *p
)
1697 if (p
[0] == '\\' && p
[1]) p
+= 2;
1698 else if (p
[0] == ',' && p
[1]) { *p
++ = 0; return(p
); }
1704 // If there's a comma followed by another character,
1705 // FindNextSubType overwrites the comma with a nul and returns the pointer to the next character.
1706 // If it finds an illegal unescaped dot in the subtype name, it returns mDNSNULL
1707 // Otherwise, it returns a pointer to the final nul at the end of the string
1708 static char *FindNextSubType(char *p
)
1712 if (p
[0] == '\\' && p
[1]) // If escape character
1713 p
+= 2; // ignore following character
1714 else if (p
[0] == ',') // If we found a comma
1719 else if (p
[0] == '.')
1726 // Returns -1 if illegal subtype found
1727 mDNSexport mDNSs32
ChopSubTypes(char *regtype
)
1729 mDNSs32 NumSubTypes
= 0;
1730 char *stp
= FindFirstSubType(regtype
);
1731 while (stp
&& *stp
) // If we found a comma...
1733 if (*stp
== ',') return(-1);
1735 stp
= FindNextSubType(stp
);
1737 if (!stp
) return(-1);
1738 return(NumSubTypes
);
1741 mDNSexport AuthRecord
*AllocateSubTypes(mDNSs32 NumSubTypes
, char *p
)
1743 AuthRecord
*st
= mDNSNULL
;
1747 st
= mallocL("ServiceSubTypes", NumSubTypes
* sizeof(AuthRecord
));
1748 if (!st
) return(mDNSNULL
);
1749 for (i
= 0; i
< NumSubTypes
; i
++)
1751 mDNS_SetupResourceRecord(&st
[i
], mDNSNULL
, mDNSInterface_Any
, kDNSQType_ANY
, kStandardTTL
, 0, mDNSNULL
, mDNSNULL
);
1754 if (!MakeDomainNameFromDNSNameString(st
[i
].resrec
.name
, p
))
1755 { freeL("ServiceSubTypes", st
); return(mDNSNULL
); }
1761 #ifdef _HAVE_SETDOMAIN_SUPPORT_
1762 static void free_defdomain(mDNS
*const m
, AuthRecord
*const rr
, mStatus result
)
1765 if (result
== mStatus_MemFree
) free(rr
->RecordContext
); // context is the enclosing list structure
1769 static void handle_setdomain_request(request_state
*request
)
1771 mStatus err
= mStatus_NoError
;
1773 char domainstr
[MAX_ESCAPED_DOMAIN_NAME
];
1775 DNSServiceFlags flags
;
1776 #ifdef _HAVE_SETDOMAIN_SUPPORT_
1781 if (request
->ts
!= t_complete
)
1783 LogMsg("ERROR: handle_setdomain_request - transfer state != t_complete");
1784 abort_request(request
);
1785 unlink_request(request
);
1789 // extract flags/domain from message
1790 ptr
= request
->msgdata
;
1791 flags
= get_flags(&ptr
);
1792 if (get_string(&ptr
, domainstr
, MAX_ESCAPED_DOMAIN_NAME
) < 0 ||
1793 !MakeDomainNameFromDNSNameString(&domain
, domainstr
))
1794 { err
= mStatus_BadParamErr
; goto end
; }
1796 freeL("handle_setdomain_request", request
->msgbuf
);
1797 request
->msgbuf
= NULL
;
1799 debugf("%3d: DNSServiceSetDefaultDomainForUser(%##s)", request
->sd
, domain
.c
);
1801 #ifdef _HAVE_SETDOMAIN_SUPPORT_
1802 // this functionality currently only used for Apple-specific configuration, so we don't burned other platforms by mandating
1803 // the existence of this socket option
1804 xuclen
= sizeof(xuc
);
1805 if (getsockopt(request
->sd
, 0, LOCAL_PEERCRED
, &xuc
, &xuclen
))
1806 { my_perror("ERROR: getsockopt, LOCAL_PEERCRED"); err
= mStatus_UnknownErr
; goto end
; }
1807 if (xuc
.cr_version
!= XUCRED_VERSION
) { LogMsg("getsockopt, LOCAL_PEERCRED - bad version"); err
= mStatus_UnknownErr
; goto end
; }
1808 LogMsg("Default domain %s %s for UID %d", domainstr
, flags
& kDNSServiceFlagsAdd
? "set" : "removed", xuc
.cr_uid
);
1810 if (flags
& kDNSServiceFlagsAdd
)
1812 // register a local-only PRT record
1813 default_browse_list_t
*newelem
= malloc(sizeof(default_browse_list_t
));
1814 if (!newelem
) { LogMsg("ERROR: malloc"); err
= mStatus_NoMemoryErr
; goto end
; }
1815 mDNS_SetupResourceRecord(&newelem
->ptr_rec
, mDNSNULL
, mDNSInterface_LocalOnly
, kDNSType_PTR
, 7200, kDNSRecordTypeShared
, free_defdomain
, newelem
);
1816 MakeDomainNameFromDNSNameString(&newelem
->ptr_rec
.resrec
.name
, mDNS_DomainTypeNames
[mDNS_DomainTypeBrowseDefault
]);
1817 AppendDNSNameString (&newelem
->ptr_rec
.resrec
.name
, "local");
1818 AssignDomainName(&newelem
->ptr_rec
.resrec
.rdata
->u
.name
, &domain
);
1819 newelem
->uid
= xuc
.cr_uid
;
1820 err
= mDNS_Register(gmDNS
, &newelem
->ptr_rec
);
1821 if (err
) free(newelem
);
1825 newelem
->next
= default_browse_list
;
1826 default_browse_list
= newelem
;
1832 // remove - find in list, deregister
1833 default_browse_list_t
*ptr
= default_browse_list
, *prev
= NULL
;
1836 if (SameDomainName(&ptr
->ptr_rec
.resrec
.rdata
->u
.name
, &domain
))
1838 if (prev
) prev
->next
= ptr
->next
;
1839 else default_browse_list
= ptr
->next
;
1840 err
= mDNS_Deregister(gmDNS
, &ptr
->ptr_rec
);
1846 if (!ptr
) { LogMsg("Attempt to remove nonexistent domain %s for UID %d", domainstr
, xuc
.cr_uid
); err
= mStatus_Invalid
; }
1849 err
= mStatus_NoError
;
1850 #endif // _HAVE_SETDOMAIN_SUPPORT_
1853 deliver_error(request
, err
);
1854 abort_request(request
);
1855 unlink_request(request
);
1858 static mStatus
add_domain_to_browser(browser_info_t
*info
, const domainname
*d
)
1863 for (p
= info
->browsers
; p
; p
= p
->next
)
1865 if (SameDomainName(&p
->domain
, d
))
1866 { debugf("add_domain_to_browser - attempt to add domain %##d already in list", d
->c
); return mStatus_AlreadyRegistered
; }
1869 b
= mallocL("browser_t", sizeof(*b
));
1870 if (!b
) return mStatus_NoMemoryErr
;
1871 AssignDomainName(&b
->domain
, d
);
1872 err
= mDNS_StartBrowse(gmDNS
, &b
->q
, &info
->regtype
, d
, info
->interface_id
, info
->ForceMCast
, browse_result_callback
, info
->rstate
);
1875 LogMsg("mDNS_StartBrowse returned %d for type %##s domain %##s", err
, info
->regtype
.c
, d
->c
);
1876 freeL("browser_t", b
);
1880 b
->next
= info
->browsers
;
1886 static void handle_browse_request(request_state
*request
)
1888 DNSServiceFlags flags
;
1889 uint32_t interfaceIndex
;
1890 mDNSInterfaceID InterfaceID
;
1891 char regtype
[MAX_ESCAPED_DOMAIN_NAME
], domain
[MAX_ESCAPED_DOMAIN_NAME
];
1892 domainname typedn
, d
, temp
;
1893 mDNSs32 NumSubTypes
;
1895 mStatus err
= mStatus_NoError
;
1896 DNameListElem
*search_domain_list
, *sdom
;
1897 browser_info_t
*info
= NULL
;
1899 if (request
->ts
!= t_complete
)
1901 LogMsg("ERROR: handle_browse_request - transfer state != t_complete");
1902 abort_request(request
);
1903 unlink_request(request
);
1907 // extract data from message
1908 ptr
= request
->msgdata
;
1909 flags
= get_flags(&ptr
);
1910 interfaceIndex
= get_long(&ptr
);
1911 if (get_string(&ptr
, regtype
, MAX_ESCAPED_DOMAIN_NAME
) < 0 ||
1912 get_string(&ptr
, domain
, MAX_ESCAPED_DOMAIN_NAME
) < 0)
1913 { err
= mStatus_BadParamErr
; goto error
; }
1914 freeL("handle_browse_request", request
->msgbuf
);
1915 request
->msgbuf
= NULL
;
1917 InterfaceID
= mDNSPlatformInterfaceIDfromInterfaceIndex(gmDNS
, interfaceIndex
);
1918 if (interfaceIndex
&& !InterfaceID
) { err
= mStatus_BadParamErr
; goto error
; }
1921 NumSubTypes
= ChopSubTypes(regtype
); // Note: Modifies regtype string to remove trailing subtypes
1922 if (NumSubTypes
< 0 || NumSubTypes
> 1) { err
= mStatus_BadParamErr
; goto error
; }
1923 if (NumSubTypes
== 1 && !AppendDNSNameString(&typedn
, regtype
+ strlen(regtype
) + 1))
1924 { err
= mStatus_BadParamErr
; goto error
; }
1926 if (!regtype
[0] || !AppendDNSNameString(&typedn
, regtype
)) { err
= mStatus_BadParamErr
; goto error
; }
1928 if (!MakeDomainNameFromDNSNameString(&temp
, regtype
)) { err
= mStatus_BadParamErr
; goto error
; }
1929 if (temp
.c
[0] > 15 && domain
[0] == 0) strcpy(domain
, "local."); // For over-long service types, we only allow domain "local"
1931 // allocate and set up browser info
1932 info
= mallocL("browser_info_t", sizeof(*info
));
1933 if (!info
) { err
= mStatus_NoMemoryErr
; goto error
; }
1935 request
->browser_info
= info
;
1936 info
->ForceMCast
= (flags
& kDNSServiceFlagsForceMulticast
) != 0;
1937 info
->interface_id
= InterfaceID
;
1938 AssignDomainName(&info
->regtype
, &typedn
);
1939 info
->rstate
= request
;
1940 info
->default_domain
= !domain
[0];
1941 info
->browsers
= NULL
;
1943 // setup termination context
1944 request
->termination_context
= info
;
1945 request
->terminate
= browse_termination_callback
;
1947 LogOperation("%3d: DNSServiceBrowse(\"%##s\", \"%s\") START", request
->sd
, info
->regtype
.c
, domain
);
1950 if (!MakeDomainNameFromDNSNameString(&d
, domain
)) { err
= mStatus_BadParamErr
; goto error
; }
1951 err
= add_domain_to_browser(info
, &d
);
1956 search_domain_list
= mDNSPlatformGetSearchDomainList();
1957 for (sdom
= search_domain_list
; sdom
; sdom
= sdom
->next
)
1959 err
= add_domain_to_browser(info
, &sdom
->name
);
1962 if (SameDomainName(&sdom
->name
, &localdomain
)) break;
1963 else err
= mStatus_NoError
; // suppress errors for non-local "default" domains
1967 mDNS_FreeDNameList(search_domain_list
);
1970 deliver_error(request
, err
);
1974 if (info
) freeL("browser_info_t", info
);
1975 if (request
->termination_context
) request
->termination_context
= NULL
;
1976 deliver_error(request
, err
);
1977 abort_request(request
);
1978 unlink_request(request
);
1981 static void browse_result_callback(mDNS
*const m
, DNSQuestion
*question
, const ResourceRecord
*const answer
, mDNSBool AddRecord
)
1983 request_state
*req
= question
->QuestionContext
;
1987 LogOperation("%3d: DNSServiceBrowse(%##s, %s) RESULT %s %s",
1988 req
->sd
, question
->qname
.c
, DNSTypeName(question
->qtype
), AddRecord
? "Add" : "Rmv", RRDisplayString(m
, answer
));
1990 err
= gen_rr_response(&answer
->rdata
->u
.name
, answer
->InterfaceID
, req
, &rep
);
1993 if (deliver_async_error(req
, browse_reply
, err
) < 0)
1996 unlink_request(req
);
2000 if (AddRecord
) rep
->rhdr
->flags
|= dnssd_htonl(kDNSServiceFlagsAdd
); // non-zero TTL indicates add
2001 append_reply(req
, rep
);
2005 static void browse_termination_callback(void *context
)
2007 browser_info_t
*info
= context
;
2012 while(info
->browsers
)
2014 ptr
= info
->browsers
;
2015 info
->browsers
= ptr
->next
;
2016 LogOperation("%3d: DNSServiceBrowse(%##s) STOP", info
->rstate
->sd
, ptr
->q
.qname
.c
);
2017 mDNS_StopBrowse(gmDNS
, &ptr
->q
); // no need to error-check result
2018 freeL("browse_termination_callback", ptr
);
2021 info
->rstate
->termination_context
= NULL
;
2022 freeL("browser_info", info
);
2025 mDNSexport
void udsserver_default_browse_domain_changed(const domainname
*d
, mDNSBool add
)
2029 for (r
= all_requests
; r
; r
= r
->next
)
2031 browser_info_t
*info
= r
->browser_info
;
2033 if (!info
|| !info
->default_domain
) continue;
2034 if (add
) add_domain_to_browser(info
, d
);
2037 browser_t
**ptr
= &info
->browsers
;
2040 if (SameDomainName(&(*ptr
)->domain
, d
))
2042 browser_t
*remove
= *ptr
;
2043 *ptr
= (*ptr
)->next
;
2044 if (remove
->q
.LongLived
)
2046 // give goodbyes for known answers.
2047 // note that since events are sent to client via udsserver_idle(), we don't need to worry about the question being cancelled mid-loop
2048 CacheRecord
*ka
= remove
->q
.uDNS_info
.knownAnswers
;
2049 while (ka
) { remove
->q
.QuestionCallback(gmDNS
, &remove
->q
, &ka
->resrec
, mDNSfalse
); ka
= ka
->next
; }
2051 mDNS_StopBrowse(gmDNS
, &remove
->q
);
2052 freeL("browser_t", remove
);
2055 ptr
= &(*ptr
)->next
;
2057 LogMsg("Requested removal of default domain %##s not in list for sd %d", d
->c
, r
->sd
);
2062 // Count how many other service records we have locally with the same name, but different rdata.
2063 // For auto-named services, we can have at most one per machine -- if we allowed two auto-named services of
2064 // the same type on the same machine, we'd get into an infinite autoimmune-response loop of continuous renaming.
2065 mDNSexport
int CountPeerRegistrations(mDNS
*const m
, ServiceRecordSet
*const srs
)
2068 ResourceRecord
*r
= &srs
->RR_SRV
.resrec
;
2070 ServiceRecordSet
*s
;
2072 for (rr
= m
->ResourceRecords
; rr
; rr
=rr
->next
)
2073 if (rr
->resrec
.rrtype
== kDNSType_SRV
&& SameDomainName(rr
->resrec
.name
, r
->name
) && !SameRData(&rr
->resrec
, r
))
2076 for (rr
= m
->uDNS_info
.RecordRegistrations
; rr
; rr
=rr
->next
)
2077 if (rr
->uDNS_info
.state
!= regState_Unregistered
&& rr
->resrec
.rrtype
== kDNSType_SRV
&& SameDomainName(rr
->resrec
.name
, r
->name
) && !SameRData(&rr
->resrec
, r
))
2080 for (s
= m
->uDNS_info
.ServiceRegistrations
; s
; s
= s
->next
)
2081 if (s
->uDNS_info
.state
!= regState_Unregistered
&& SameDomainName(s
->RR_SRV
.resrec
.name
, r
->name
) && !SameRData(&s
->RR_SRV
.resrec
, r
))
2084 verbosedebugf("%d peer registrations for %##s", count
, r
->name
->c
);
2088 mDNSexport
int CountExistingRegistrations(domainname
*srv
, mDNSIPPort port
)
2092 for (rr
= gmDNS
->ResourceRecords
; rr
; rr
=rr
->next
)
2093 if (rr
->resrec
.rrtype
== kDNSType_SRV
&&
2094 rr
->resrec
.rdata
->u
.srv
.port
.NotAnInteger
== port
.NotAnInteger
&&
2095 SameDomainName(rr
->resrec
.name
, srv
))
2100 static mStatus
register_service_instance(request_state
*request
, const domainname
*domain
)
2102 service_info
*info
= request
->service_registration
;
2103 service_instance
*ptr
, *instance
;
2107 for (ptr
= info
->instances
; ptr
; ptr
= ptr
->next
)
2109 if (SameDomainName(&ptr
->domain
, domain
))
2110 { LogMsg("register_service_instance: domain %##s already registered", domain
->c
); return mStatus_AlreadyRegistered
; }
2113 instance_size
= sizeof(*instance
);
2114 if (info
->txtlen
> sizeof(RDataBody
)) instance_size
+= (info
->txtlen
- sizeof(RDataBody
));
2115 instance
= mallocL("service_instance", instance_size
);
2116 if (!instance
) { my_perror("ERROR: malloc"); return mStatus_NoMemoryErr
; }
2118 instance
->subtypes
= AllocateSubTypes(info
->num_subtypes
, info
->type_as_string
);
2119 if (info
->num_subtypes
&& !instance
->subtypes
)
2120 { free_service_instance(instance
); instance
= NULL
; FatalError("ERROR: malloc"); }
2121 instance
->request
= request
;
2122 instance
->sd
= request
->sd
;
2123 instance
->autoname
= info
->autoname
;
2124 instance
->autorename
= info
->autorename
;
2125 instance
->allowremotequery
= info
->allowremotequery
;
2126 instance
->rename_on_memfree
= 0;
2127 instance
->name
= info
->name
;
2128 AssignDomainName(&instance
->domain
, domain
);
2129 instance
->default_local
= (info
->default_domain
&& SameDomainName(domain
, &localdomain
));
2130 result
= mDNS_RegisterService(gmDNS
, &instance
->srs
, &instance
->name
, &info
->type
, domain
, info
->host
.c
[0] ? &info
->host
: NULL
, info
->port
,
2131 info
->txtdata
, info
->txtlen
, instance
->subtypes
, info
->num_subtypes
, info
->InterfaceID
, regservice_callback
, instance
);
2133 if (result
) free_service_instance(instance
);
2136 instance
->next
= info
->instances
;
2137 info
->instances
= instance
;
2142 mDNSexport
void udsserver_default_reg_domain_changed(const domainname
*d
, mDNSBool add
)
2144 request_state
*rstate
;
2147 LogMsg("%s registration domain %##s", add
? "Adding" : "Removing", d
->c
);
2148 for (rstate
= all_requests
; rstate
; rstate
= rstate
->next
)
2150 if (rstate
->terminate
!= regservice_termination_callback
) continue;
2151 info
= rstate
->service_registration
;
2152 if (!info
) { LogMsg("udsserver_default_reg_domain_changed - NULL service info"); continue; } // this should never happen
2153 if (!info
->default_domain
) continue;
2155 // valid default registration
2156 if (add
) register_service_instance(rstate
, d
);
2159 // find the instance to remove
2160 service_instance
*si
= rstate
->service_registration
->instances
, *prev
= NULL
;
2163 if (SameDomainName(&si
->domain
, d
))
2166 if (prev
) prev
->next
= si
->next
;
2167 else info
->instances
= si
->next
;
2168 err
= mDNS_DeregisterService(gmDNS
, &si
->srs
);
2171 LogMsg("udsserver_default_reg_domain_changed - mDNS_DeregisterService err %d", err
);
2172 free_service_instance(si
);
2179 if (!si
) debugf("udsserver_default_reg_domain_changed - domain %##s not registered", d
->c
); // normal if registration failed
2184 // service registration
2185 static void handle_regservice_request(request_state
*request
)
2187 DNSServiceFlags flags
;
2189 char name
[1024]; // Lots of spare space for extra-long names that we'll auto-truncate down to 63 bytes
2190 char domain
[MAX_ESCAPED_DOMAIN_NAME
], host
[MAX_ESCAPED_DOMAIN_NAME
];
2194 service_info
*service
= NULL
;
2196 if (request
->ts
!= t_complete
)
2198 LogMsg("ERROR: handle_regservice_request - transfer state != t_complete");
2199 abort_request(request
);
2200 unlink_request(request
);
2204 service
= mallocL("service_info", sizeof(*service
));
2205 if (!service
) { my_perror("ERROR: malloc"); result
= mStatus_NoMemoryErr
; goto finish
; }
2207 service
->instances
= NULL
;
2208 service
->request
= request
;
2209 request
->service_registration
= service
;
2210 request
->termination_context
= request
->service_registration
;
2211 request
->terminate
= regservice_termination_callback
;
2213 // extract data from message
2214 ptr
= request
->msgdata
;
2215 flags
= get_flags(&ptr
);
2216 ifi
= get_long(&ptr
);
2217 service
->InterfaceID
= mDNSPlatformInterfaceIDfromInterfaceIndex(gmDNS
, ifi
);
2218 if (ifi
&& !service
->InterfaceID
)
2219 { LogMsg("ERROR: handle_regservice_request - Couldn't find InterfaceID for interfaceIndex %d", ifi
); goto bad_param
; }
2220 if (get_string(&ptr
, name
, sizeof(name
)) < 0 ||
2221 get_string(&ptr
, service
->type_as_string
, MAX_ESCAPED_DOMAIN_NAME
) < 0 ||
2222 get_string(&ptr
, domain
, MAX_ESCAPED_DOMAIN_NAME
) < 0 ||
2223 get_string(&ptr
, host
, MAX_ESCAPED_DOMAIN_NAME
) < 0)
2224 { LogMsg("ERROR: handle_regservice_request - Couldn't read name/regtype/domain"); goto bad_param
; }
2226 service
->port
.b
[0] = *ptr
++;
2227 service
->port
.b
[1] = *ptr
++;
2229 service
->txtlen
= get_short(&ptr
);
2230 if (service
->txtlen
)
2232 service
->txtdata
= mallocL("txtdata", service
->txtlen
);
2233 if (!service
->txtdata
) { my_perror("ERROR: malloc"); result
= mStatus_NoMemoryErr
; goto finish
; }
2234 memcpy(service
->txtdata
, get_rdata(&ptr
, service
->txtlen
), service
->txtlen
);
2236 else service
->txtdata
= NULL
;
2238 // Check for sub-types after the service type
2239 service
->num_subtypes
= ChopSubTypes(service
->type_as_string
); // Note: Modifies regtype string to remove trailing subtypes
2240 if (service
->num_subtypes
< 0)
2241 { LogMsg("ERROR: handle_regservice_request - ChopSubTypes failed %s", service
->type_as_string
); goto bad_param
; }
2243 // Don't try to construct "domainname t" until *after* ChopSubTypes has worked its magic
2244 if (!*service
->type_as_string
|| !MakeDomainNameFromDNSNameString(&service
->type
, service
->type_as_string
))
2245 { LogMsg("ERROR: handle_regservice_request - service->type_as_string bad %s", service
->type_as_string
); goto bad_param
; }
2249 service
->name
= (gmDNS
)->nicelabel
;
2250 service
->autoname
= mDNStrue
;
2254 // If the client is allowing AutoRename, then truncate name to legal length before converting it to a DomainLabel
2255 if ((flags
& kDNSServiceFlagsNoAutoRename
) == 0)
2257 int newlen
= TruncateUTF8ToLength((mDNSu8
*)name
, mDNSPlatformStrLen(name
), MAX_DOMAIN_LABEL
);
2260 if (!MakeDomainLabelFromLiteralString(&service
->name
, name
))
2261 { LogMsg("ERROR: handle_regservice_request - name bad %s", name
); goto bad_param
; }
2262 service
->autoname
= mDNSfalse
;
2267 service
->default_domain
= mDNSfalse
;
2268 if (!MakeDomainNameFromDNSNameString(&d
, domain
))
2269 { LogMsg("ERROR: handle_regservice_request - domain bad %s", domain
); goto bad_param
; }
2273 service
->default_domain
= mDNStrue
;
2274 MakeDomainNameFromDNSNameString(&d
, "local.");
2277 if (!ConstructServiceName(&srv
, &service
->name
, &service
->type
, &d
))
2278 { LogMsg("ERROR: handle_regservice_request - Couldn't ConstructServiceName from, “%#s” “%##s” “%##s”", service
->name
.c
, service
->type
.c
, d
.c
); goto bad_param
; }
2280 if (!MakeDomainNameFromDNSNameString(&service
->host
, host
))
2281 { LogMsg("ERROR: handle_regservice_request - host bad %s", host
); goto bad_param
; }
2282 service
->autorename
= (flags
& kDNSServiceFlagsNoAutoRename
) == 0;
2283 service
->allowremotequery
= (flags
& kDNSServiceFlagsAllowRemoteQuery
) != 0;
2285 // Some clients use mDNS for lightweight copy protection, registering a pseudo-service with
2286 // a port number of zero. When two instances of the protected client are allowed to run on one
2287 // machine, we don't want to see misleading "Bogus client" messages in syslog and the console.
2288 if (service
->port
.NotAnInteger
)
2290 int count
= CountExistingRegistrations(&srv
, service
->port
);
2292 LogMsg("Client application registered %d identical instances of service %##s port %u.",
2293 count
+1, srv
.c
, mDNSVal16(service
->port
));
2296 LogOperation("%3d: DNSServiceRegister(\"%s\", \"%s\", \"%s\", \"%s\", %u) START",
2297 request
->sd
, name
, service
->type_as_string
, domain
, host
, mDNSVal16(service
->port
));
2298 result
= register_service_instance(request
, &d
);
2300 if (!result
&& !*domain
)
2302 DNameListElem
*ptr
, *def_domains
= mDNSPlatformGetRegDomainList();
2303 for (ptr
= def_domains
; ptr
; ptr
= ptr
->next
)
2304 register_service_instance(request
, &ptr
->name
);
2305 // note that we don't report errors for non-local, non-explicit domains
2306 mDNS_FreeDNameList(def_domains
);
2310 deliver_error(request
, result
);
2311 if (result
!= mStatus_NoError
)
2313 abort_request(request
);
2314 unlink_request(request
);
2317 reset_connected_rstate(request
); // prepare to receive add/remove messages
2322 //if (service) freeL("service_info", service); Don't think we should do this -- abort_request will free it a second time and crash
2323 deliver_error(request
, mStatus_BadParamErr
);
2324 abort_request(request
);
2325 unlink_request(request
);
2328 // service registration callback performs three duties - frees memory for deregistered services,
2329 // handles name conflicts, and delivers completed registration information to the client (via
2330 // process_service_registraion())
2332 static void regservice_callback(mDNS
*const m
, ServiceRecordSet
*const srs
, mStatus result
)
2335 mDNSBool SuppressError
= mDNSfalse
;
2336 service_instance
*instance
= srs
->ServiceContext
;
2338 if (!srs
) { LogMsg("regservice_callback: srs is NULL %d", result
); return; }
2339 if (!instance
) { LogMsg("regservice_callback: srs->ServiceContext is NULL %d", result
); return; }
2341 if (instance
->request
&& instance
->request
->service_registration
)
2343 service_info
*info
= instance
->request
->service_registration
;
2344 if (info
->default_domain
&& !instance
->default_local
) SuppressError
= mDNStrue
;
2345 // don't send errors up to client for wide-area, empty-string registrations
2348 if (result
== mStatus_NoError
)
2349 LogOperation("%3d: DNSServiceRegister(%##s, %u) REGISTERED ", instance
->sd
, srs
->RR_SRV
.resrec
.name
->c
, mDNSVal16(srs
->RR_SRV
.resrec
.rdata
->u
.srv
.port
));
2350 else if (result
== mStatus_MemFree
)
2351 LogOperation("%3d: DNSServiceRegister(%##s, %u) DEREGISTERED", instance
->sd
, srs
->RR_SRV
.resrec
.name
->c
, mDNSVal16(srs
->RR_SRV
.resrec
.rdata
->u
.srv
.port
));
2352 else if (result
== mStatus_NameConflict
)
2353 LogOperation("%3d: DNSServiceRegister(%##s, %u) NAME CONFLICT", instance
->sd
, srs
->RR_SRV
.resrec
.name
->c
, mDNSVal16(srs
->RR_SRV
.resrec
.rdata
->u
.srv
.port
));
2355 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
);
2357 if (result
== mStatus_NoError
)
2359 if (instance
->allowremotequery
)
2361 ExtraResourceRecord
*e
;
2362 srs
->RR_ADV
.AllowRemoteQuery
= mDNStrue
;
2363 srs
->RR_PTR
.AllowRemoteQuery
= mDNStrue
;
2364 srs
->RR_SRV
.AllowRemoteQuery
= mDNStrue
;
2365 srs
->RR_TXT
.AllowRemoteQuery
= mDNStrue
;
2366 for (e
= instance
->srs
.Extras
; e
; e
= e
->next
) e
->r
.AllowRemoteQuery
= mDNStrue
;
2368 process_service_registration(srs
, SuppressError
);
2369 if (instance
->autoname
&& CountPeerRegistrations(m
, srs
) == 0)
2370 RecordUpdatedNiceLabel(m
, 0); // Successfully got new name, tell user immediately
2373 else if (result
== mStatus_MemFree
)
2375 if (instance
->rename_on_memfree
)
2377 instance
->rename_on_memfree
= 0;
2378 instance
->name
= gmDNS
->nicelabel
;
2379 err
= mDNS_RenameAndReregisterService(gmDNS
, srs
, &instance
->name
);
2380 if (err
) LogMsg("ERROR: regservice_callback - RenameAndReregisterService returned %ld", err
);
2381 // error should never happen - safest to log and continue
2385 free_service_instance(instance
);
2389 else if (result
== mStatus_NameConflict
)
2391 if (instance
->autoname
&& CountPeerRegistrations(m
, srs
) == 0)
2393 // On conflict for an autoname service, rename and reregister *all* autoname services
2394 IncrementLabelSuffix(&m
->nicelabel
, mDNStrue
);
2395 m
->MainCallback(m
, mStatus_ConfigChanged
);
2397 else if (instance
->autoname
|| instance
->autorename
)
2399 mDNS_RenameAndReregisterService(gmDNS
, srs
, mDNSNULL
);
2404 request_state
*rs
= instance
->request
;
2405 if (!rs
) { LogMsg("ERROR: regservice_callback: received result %ld with a NULL request pointer", result
); return; }
2406 free_service_instance(instance
);
2407 if (!SuppressError
&& deliver_async_error(rs
, reg_service_reply
, result
) < 0)
2417 request_state
*rs
= instance
->request
;
2418 if (!rs
) { LogMsg("ERROR: regservice_callback: received result %ld with a NULL request pointer", result
); return; }
2419 if (result
!= mStatus_NATTraversal
) LogMsg("ERROR: unknown result in regservice_callback: %ld", result
);
2420 free_service_instance(instance
);
2421 if (!SuppressError
&& deliver_async_error(rs
, reg_service_reply
, result
) < 0)
2430 mDNSexport
void FreeExtraRR(mDNS
*const m
, AuthRecord
*const rr
, mStatus result
)
2432 ExtraResourceRecord
*extra
= (ExtraResourceRecord
*)rr
->RecordContext
;
2435 if (result
!= mStatus_MemFree
) { LogMsg("Error: FreeExtraRR invoked with unexpected error %d", result
); return; }
2437 debugf("%##s: MemFree", rr
->resrec
.name
->c
);
2438 if (rr
->resrec
.rdata
!= &rr
->rdatastorage
)
2439 freeL("Extra RData", rr
->resrec
.rdata
);
2440 freeL("ExtraResourceRecord", extra
);
2443 static mStatus
add_record_to_service(request_state
*rstate
, service_instance
*instance
, uint16_t rrtype
, uint16_t rdlen
, char *rdata
, uint32_t ttl
)
2445 ServiceRecordSet
*srs
= &instance
->srs
;
2446 ExtraResourceRecord
*extra
;
2450 if (rdlen
> sizeof(RDataBody
)) size
= rdlen
;
2451 else size
= sizeof(RDataBody
);
2453 extra
= mallocL("ExtraResourceRecord", sizeof(*extra
) - sizeof(RDataBody
) + size
);
2456 my_perror("ERROR: malloc");
2457 return mStatus_NoMemoryErr
;
2460 bzero(extra
, sizeof(ExtraResourceRecord
)); // OK if oversized rdata not zero'd
2461 extra
->r
.resrec
.rrtype
= rrtype
;
2462 extra
->r
.rdatastorage
.MaxRDLength
= (mDNSu16
) size
;
2463 extra
->r
.resrec
.rdlength
= rdlen
;
2464 memcpy(&extra
->r
.rdatastorage
.u
.data
, rdata
, rdlen
);
2466 result
= mDNS_AddRecordToService(gmDNS
, srs
, extra
, &extra
->r
.rdatastorage
, ttl
);
2467 if (result
) { freeL("ExtraResourceRecord", extra
); return result
; }
2469 extra
->ClientID
= rstate
->hdr
.reg_index
;
2473 static mStatus
handle_add_request(request_state
*rstate
)
2476 uint16_t rrtype
, rdlen
;
2478 mStatus result
= mStatus_UnknownErr
;
2479 DNSServiceFlags flags
;
2480 service_info
*srvinfo
= rstate
->service_registration
;
2481 service_instance
*i
;
2483 if (!srvinfo
) { LogMsg("handle_add_request called with NULL service_registration"); return(-1); }
2485 ptr
= rstate
->msgdata
;
2486 flags
= get_flags(&ptr
);
2487 rrtype
= get_short(&ptr
);
2488 rdlen
= get_short(&ptr
);
2489 rdata
= get_rdata(&ptr
, rdlen
);
2490 ttl
= get_long(&ptr
);
2492 if (!ttl
) ttl
= DefaultTTLforRRType(rrtype
);
2494 LogOperation("%3d: DNSServiceAddRecord(%##s, %s)", rstate
->sd
,
2495 (srvinfo
->instances
) ? srvinfo
->instances
->srs
.RR_SRV
.resrec
.name
->c
: NULL
, DNSTypeName(rrtype
));
2497 for (i
= srvinfo
->instances
; i
; i
= i
->next
)
2499 result
= add_record_to_service(rstate
, i
, rrtype
, rdlen
, rdata
, ttl
);
2500 if (result
&& i
->default_local
) break;
2501 else result
= mStatus_NoError
; // suppress non-local default errors
2507 static mStatus
update_record(AuthRecord
*rr
, uint16_t rdlen
, char *rdata
, uint32_t ttl
)
2513 if (rdlen
> sizeof(RDataBody
)) rdsize
= rdlen
;
2514 else rdsize
= sizeof(RDataBody
);
2515 newrd
= mallocL("handle_update_request", sizeof(RData
) - sizeof(RDataBody
) + rdsize
);
2516 if (!newrd
) FatalError("ERROR: malloc");
2517 newrd
->MaxRDLength
= (mDNSu16
) rdsize
;
2518 memcpy(&newrd
->u
, rdata
, rdlen
);
2520 // BIND named (name daemon) doesn't allow TXT records with zero-length rdata. This is strictly speaking correct,
2521 // since RFC 1035 specifies a TXT record as "One or more <character-string>s", not "Zero or more <character-string>s".
2522 // Since some legacy apps try to create zero-length TXT records, we'll silently correct it here.
2523 if (rr
->resrec
.rrtype
== kDNSType_TXT
&& rdlen
== 0) { rdlen
= 1; newrd
->u
.txt
.c
[0] = 0; }
2525 result
= mDNS_Update(gmDNS
, rr
, ttl
, rdlen
, newrd
, update_callback
);
2526 if (result
) { LogMsg("ERROR: mDNS_Update - %ld", result
); freeL("handle_update_request", newrd
); }
2530 static mStatus
handle_update_request(request_state
*rstate
)
2535 mStatus result
= mStatus_BadReferenceErr
;
2536 service_info
*srvinfo
= rstate
->service_registration
;
2537 service_instance
*i
;
2538 AuthRecord
*rr
= NULL
;
2540 // get the message data
2541 ptr
= rstate
->msgdata
;
2542 get_flags(&ptr
); // flags unused
2543 rdlen
= get_short(&ptr
);
2544 rdata
= get_rdata(&ptr
, rdlen
);
2545 ttl
= get_long(&ptr
);
2547 if (rstate
->reg_recs
)
2549 // update an individually registered record
2550 registered_record_entry
*reptr
;
2551 for (reptr
= rstate
->reg_recs
; reptr
; reptr
= reptr
->next
)
2553 if (reptr
->key
== rstate
->hdr
.reg_index
)
2555 result
= update_record(reptr
->rr
, rdlen
, rdata
, ttl
);
2559 result
= mStatus_BadReferenceErr
;
2563 // update a record from a service record set
2564 if (!srvinfo
) { result
= mStatus_BadReferenceErr
; goto end
; }
2565 for (i
= srvinfo
->instances
; i
; i
= i
->next
)
2567 if (rstate
->hdr
.reg_index
== TXT_RECORD_INDEX
) rr
= &i
->srs
.RR_TXT
;
2570 ExtraResourceRecord
*e
;
2571 for (e
= i
->srs
.Extras
; e
; e
= e
->next
)
2572 if (e
->ClientID
== rstate
->hdr
.reg_index
) { rr
= &e
->r
; break; }
2575 if (!rr
) { result
= mStatus_BadReferenceErr
; goto end
; }
2576 result
= update_record(rr
, rdlen
, rdata
, ttl
);
2577 if (result
&& i
->default_local
) goto end
;
2578 else result
= mStatus_NoError
; // suppress non-local default errors
2582 LogOperation("%3d: DNSServiceUpdateRecord(%##s, %s)", rstate
->sd
,
2583 (srvinfo
->instances
) ? srvinfo
->instances
->srs
.RR_SRV
.resrec
.name
->c
: NULL
,
2584 rr
? DNSTypeName(rr
->resrec
.rrtype
) : "<NONE>");
2589 static void update_callback(mDNS
*const m
, AuthRecord
*const rr
, RData
*oldrd
)
2592 if (oldrd
!= &rr
->rdatastorage
) freeL("update_callback", oldrd
);
2595 static void process_service_registration(ServiceRecordSet
*const srs
, mDNSBool SuppressError
)
2598 transfer_state send_result
;
2600 service_instance
*instance
= srs
->ServiceContext
;
2601 request_state
*req
= instance
->request
;
2603 if (!req
) { LogMsg("ERROR: process_service_registration - null request object"); return; }
2604 err
= gen_rr_response(srs
->RR_SRV
.resrec
.name
, srs
->RR_SRV
.resrec
.InterfaceID
, req
, &rep
);
2607 if (SuppressError
&& deliver_async_error(req
, reg_service_reply
, err
) < 0)
2610 unlink_request(req
);
2614 send_result
= send_msg(rep
);
2615 if (send_result
== t_error
|| send_result
== t_terminated
)
2618 unlink_request(req
);
2619 freeL("process_service_registration", rep
);
2621 else if (send_result
== t_complete
) freeL("process_service_registration", rep
);
2622 else append_reply(req
, rep
);
2625 static void free_service_instance(service_instance
*srv
)
2627 request_state
*rstate
= srv
->request
;
2628 ExtraResourceRecord
*e
= srv
->srs
.Extras
, *tmp
;
2630 // clear pointers from parent struct
2633 service_instance
*ptr
= rstate
->service_registration
->instances
, *prev
= NULL
;
2638 if (prev
) prev
->next
= ptr
->next
;
2639 else rstate
->service_registration
->instances
= ptr
->next
;
2649 e
->r
.RecordContext
= e
;
2652 FreeExtraRR(gmDNS
, &tmp
->r
, mStatus_MemFree
);
2655 if (srv
->subtypes
) { freeL("regservice_callback", srv
->subtypes
); srv
->subtypes
= NULL
; }
2656 freeL("regservice_callback", srv
);
2659 static void regservice_termination_callback(void *context
)
2661 service_info
*info
= context
;
2662 service_instance
*i
, *p
;
2663 if (!info
) { LogMsg("regservice_termination_callback context is NULL"); return; }
2664 if (!info
->request
) { LogMsg("regservice_termination_callback info->request is NULL"); return; }
2665 i
= info
->instances
;
2670 p
->request
= NULL
; // clear back pointer
2671 // only safe to free memory if registration is not valid, i.e. deregister fails (which invalidates p)
2672 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
));
2673 if (mDNS_DeregisterService(gmDNS
, &p
->srs
)) free_service_instance(p
);
2675 info
->request
->service_registration
= NULL
; // clear pointer from request back to info
2676 if (info
->txtdata
) { freeL("txtdata", info
->txtdata
); info
->txtdata
= NULL
; }
2677 freeL("service_info", info
);
2680 static mStatus
handle_regrecord_request(request_state
*rstate
)
2683 registered_record_entry
*re
;
2686 if (rstate
->ts
!= t_complete
)
2688 LogMsg("ERROR: handle_regrecord_request - transfer state != t_complete");
2689 abort_request(rstate
);
2690 unlink_request(rstate
);
2694 rr
= read_rr_from_ipc_msg(rstate
->msgdata
, 1, 1);
2695 if (!rr
) return(mStatus_BadParamErr
);
2697 // allocate registration entry, link into list
2698 re
= mallocL("handle_regrecord_request", sizeof(registered_record_entry
));
2699 if (!re
) FatalError("ERROR: malloc");
2700 re
->key
= rstate
->hdr
.reg_index
;
2702 re
->rstate
= rstate
;
2703 re
->client_context
= rstate
->hdr
.client_context
;
2704 rr
->RecordContext
= re
;
2705 rr
->RecordCallback
= regrecord_callback
;
2706 re
->next
= rstate
->reg_recs
;
2707 rstate
->reg_recs
= re
;
2709 if (!rstate
->terminate
)
2711 rstate
->terminate
= connected_registration_termination
;
2712 rstate
->termination_context
= rstate
;
2715 if (rr
->resrec
.rroriginalttl
== 0)
2716 rr
->resrec
.rroriginalttl
= DefaultTTLforRRType(rr
->resrec
.rrtype
);
2718 LogOperation("%3d: DNSServiceRegisterRecord %s", rstate
->sd
, RRDisplayString(gmDNS
, &rr
->resrec
));
2719 result
= mDNS_Register(gmDNS
, rr
);
2723 static void regrecord_callback(mDNS
*const m
, AuthRecord
* rr
, mStatus result
)
2725 registered_record_entry
*re
= rr
->RecordContext
;
2726 request_state
*rstate
= re
? re
->rstate
: NULL
;
2734 // parent struct alreadt freed by termination callback
2735 if (!result
) LogMsg("Error: regrecord_callback: successful registration of orphaned record");
2738 if (result
!= mStatus_MemFree
) LogMsg("regrecord_callback: error %d received after parent termination", result
);
2739 freeL("regrecord_callback", rr
);
2744 // format result, add to the list for the request, including the client context in the header
2745 len
= sizeof(DNSServiceFlags
);
2746 len
+= sizeof(uint32_t); //interfaceIndex
2747 len
+= sizeof(DNSServiceErrorType
);
2749 reply
= create_reply(reg_record_reply
, len
, rstate
);
2750 reply
->mhdr
->client_context
= re
->client_context
;
2751 reply
->rhdr
->flags
= dnssd_htonl(0);
2752 reply
->rhdr
->ifi
= dnssd_htonl(mDNSPlatformInterfaceIndexfromInterfaceID(gmDNS
, rr
->resrec
.InterfaceID
));
2753 reply
->rhdr
->error
= dnssd_htonl(result
);
2757 // unlink from list, free memory
2758 registered_record_entry
**ptr
= &re
->rstate
->reg_recs
;
2759 while (*ptr
&& (*ptr
) != re
) ptr
= &(*ptr
)->next
;
2760 if (!*ptr
) { LogMsg("regrecord_callback - record not in list!"); return; }
2761 *ptr
= (*ptr
)->next
;
2762 freeL("regrecord_callback", re
->rr
);
2764 freeL("regrecord_callback", re
);
2768 ts
= send_msg(reply
);
2770 if (ts
== t_error
|| ts
== t_terminated
) { abort_request(rstate
); unlink_request(rstate
); }
2771 else if (ts
== t_complete
) freeL("regrecord_callback", reply
);
2772 else if (ts
== t_morecoming
) append_reply(rstate
, reply
); // client is blocked, link reply into list
2775 static void connected_registration_termination(void *context
)
2778 registered_record_entry
*fptr
, *ptr
= ((request_state
*)context
)->reg_recs
;
2783 shared
= fptr
->rr
->resrec
.RecordType
== kDNSRecordTypeShared
;
2784 fptr
->rr
->RecordContext
= NULL
;
2785 mDNS_Deregister(gmDNS
, fptr
->rr
);
2786 freeL("connected_registration_termination", fptr
);
2790 static mStatus
handle_removerecord_request(request_state
*rstate
)
2792 mStatus err
= mStatus_BadReferenceErr
;
2794 service_info
*srvinfo
= rstate
->service_registration
;
2796 ptr
= rstate
->msgdata
;
2797 get_flags(&ptr
); // flags unused
2799 if (rstate
->reg_recs
) err
= remove_record(rstate
); // remove individually registered record
2800 else if (!srvinfo
) LogOperation("%3d: DNSServiceRemoveRecord (bad ref)", rstate
->sd
);
2803 service_instance
*i
;
2804 LogOperation("%3d: DNSServiceRemoveRecord(%##s)", rstate
->sd
,
2805 (srvinfo
->instances
) ? srvinfo
->instances
->srs
.RR_SRV
.resrec
.name
->c
: NULL
);
2806 for (i
= srvinfo
->instances
; i
; i
= i
->next
)
2808 err
= remove_extra(rstate
, i
);
2809 if (err
&& i
->default_local
) break;
2810 else err
= mStatus_NoError
; // suppress non-local default errors
2817 // remove a resource record registered via DNSServiceRegisterRecord()
2818 static mStatus
remove_record(request_state
*rstate
)
2821 mStatus err
= mStatus_UnknownErr
;
2822 registered_record_entry
*e
, **ptr
= &rstate
->reg_recs
;
2824 while(*ptr
&& (*ptr
)->key
!= rstate
->hdr
.reg_index
) ptr
= &(*ptr
)->next
;
2825 if (!*ptr
) { LogMsg("DNSServiceRemoveRecord - bad reference"); return mStatus_BadReferenceErr
; }
2827 *ptr
= e
->next
; // unlink
2829 LogOperation("%3d: DNSServiceRemoveRecord(%#s)", rstate
->sd
, e
->rr
->resrec
.name
->c
);
2830 shared
= e
->rr
->resrec
.RecordType
== kDNSRecordTypeShared
;
2831 e
->rr
->RecordContext
= NULL
;
2832 err
= mDNS_Deregister(gmDNS
, e
->rr
);
2835 LogMsg("ERROR: remove_record, mDNS_Deregister: %ld", err
);
2836 freeL("remove_record", e
->rr
);
2837 freeL("remove_record", e
);
2842 static mStatus
remove_extra(request_state
*rstate
, service_instance
*serv
)
2844 mStatus err
= mStatus_BadReferenceErr
;
2845 ExtraResourceRecord
*ptr
;
2847 for (ptr
= serv
->srs
.Extras
; ptr
; ptr
= ptr
->next
)
2849 if (ptr
->ClientID
== rstate
->hdr
.reg_index
) // found match
2850 return mDNS_RemoveRecordFromService(gmDNS
, &serv
->srs
, ptr
, FreeExtraRR
, ptr
);
2855 // domain enumeration
2856 static void handle_enum_request(request_state
*rstate
)
2858 DNSServiceFlags flags
;
2860 mDNSInterfaceID InterfaceID
;
2861 char *ptr
= rstate
->msgdata
;
2862 domain_enum_t
*def
, *all
;
2863 enum_termination_t
*term
;
2867 if (rstate
->ts
!= t_complete
)
2869 LogMsg("ERROR: handle_enum_request - transfer state != t_complete");
2870 abort_request(rstate
);
2871 unlink_request(rstate
);
2875 flags
= get_flags(&ptr
);
2876 ifi
= get_long(&ptr
);
2877 InterfaceID
= mDNSPlatformInterfaceIDfromInterfaceIndex(gmDNS
, ifi
);
2878 if (ifi
&& !InterfaceID
)
2880 deliver_error(rstate
, mStatus_BadParamErr
);
2881 abort_request(rstate
);
2882 unlink_request(rstate
);
2885 // allocate context structures
2886 def
= mallocL("handle_enum_request", sizeof(domain_enum_t
));
2887 all
= mallocL("handle_enum_request", sizeof(domain_enum_t
));
2888 term
= mallocL("handle_enum_request", sizeof(enum_termination_t
));
2889 if (!def
|| !all
|| !term
) FatalError("ERROR: malloc");
2891 // enumeration requires multiple questions, so we must link all the context pointers so that
2892 // necessary context can be reached from the callbacks
2893 def
->rstate
= rstate
;
2894 all
->rstate
= rstate
;
2897 term
->rstate
= rstate
;
2898 rstate
->termination_context
= term
;
2899 rstate
->terminate
= enum_termination_callback
;
2900 def
->question
.QuestionContext
= def
;
2901 def
->type
= (flags
& kDNSServiceFlagsRegistrationDomains
) ?
2902 mDNS_DomainTypeRegistrationDefault
: mDNS_DomainTypeBrowseDefault
;
2903 all
->question
.QuestionContext
= all
;
2904 all
->type
= (flags
& kDNSServiceFlagsRegistrationDomains
) ?
2905 mDNS_DomainTypeRegistration
: mDNS_DomainTypeBrowse
;
2907 // if the caller hasn't specified an explicit interface, we use local-only to get the system-wide list.
2908 if (!InterfaceID
) InterfaceID
= mDNSInterface_LocalOnly
;
2911 LogOperation("%3d: DNSServiceEnumerateDomains(%X=%s)", rstate
->sd
, flags
,
2912 (flags
& kDNSServiceFlagsBrowseDomains
) ? "kDNSServiceFlagsBrowseDomains" :
2913 (flags
& kDNSServiceFlagsRegistrationDomains
) ? "kDNSServiceFlagsRegistrationDomains" : "<<Unknown>>");
2914 err
= mDNS_GetDomains(gmDNS
, &all
->question
, all
->type
, NULL
, InterfaceID
, enum_result_callback
, all
);
2915 if (err
== mStatus_NoError
)
2916 err
= mDNS_GetDomains(gmDNS
, &def
->question
, def
->type
, NULL
, InterfaceID
, enum_result_callback
, def
);
2917 result
= deliver_error(rstate
, err
); // send error *before* returning local domain
2919 if (result
< 0 || err
)
2921 abort_request(rstate
);
2922 unlink_request(rstate
);
2927 static void enum_result_callback(mDNS
*const m
, DNSQuestion
*question
, const ResourceRecord
*const answer
, mDNSBool AddRecord
)
2929 char domain
[MAX_ESCAPED_DOMAIN_NAME
];
2930 domain_enum_t
*de
= question
->QuestionContext
;
2931 DNSServiceFlags flags
= 0;
2935 if (answer
->rrtype
!= kDNSType_PTR
) return;
2936 if (!AddRecord
&& de
->type
!= mDNS_DomainTypeBrowse
) return;
2940 flags
|= kDNSServiceFlagsAdd
;
2941 if (de
->type
== mDNS_DomainTypeRegistrationDefault
|| de
->type
== mDNS_DomainTypeBrowseDefault
)
2942 flags
|= kDNSServiceFlagsDefault
;
2944 ConvertDomainNameToCString(&answer
->rdata
->u
.name
, domain
);
2945 // note that we do NOT propagate specific interface indexes to the client - for example, a domain we learn from
2946 // a machine's system preferences may be discovered on the LocalOnly interface, but should be browsed on the
2947 // network, so we just pass kDNSServiceInterfaceIndexAny
2948 reply
= format_enumeration_reply(de
->rstate
, domain
, flags
, kDNSServiceInterfaceIndexAny
, kDNSServiceErr_NoError
);
2951 LogMsg("ERROR: enum_result_callback, format_enumeration_reply");
2955 append_reply(de
->rstate
, reply
);
2959 static reply_state
*format_enumeration_reply(request_state
*rstate
, const char *domain
, DNSServiceFlags flags
, uint32_t ifi
, DNSServiceErrorType err
)
2966 len
= sizeof(DNSServiceFlags
);
2967 len
+= sizeof(uint32_t);
2968 len
+= sizeof(DNSServiceErrorType
);
2969 len
+= strlen(domain
) + 1;
2971 reply
= create_reply(enumeration_reply
, len
, rstate
);
2972 reply
->rhdr
->flags
= dnssd_htonl(flags
);
2973 reply
->rhdr
->ifi
= dnssd_htonl(ifi
);
2974 reply
->rhdr
->error
= dnssd_htonl(err
);
2975 data
= reply
->sdata
;
2976 put_string(domain
, &data
);
2980 static void enum_termination_callback(void *context
)
2982 enum_termination_t
*t
= context
;
2983 mDNS
*coredata
= gmDNS
;
2985 mDNS_StopGetDomains(coredata
, &t
->all
->question
);
2986 mDNS_StopGetDomains(coredata
, &t
->def
->question
);
2987 freeL("enum_termination_callback", t
->all
);
2988 freeL("enum_termination_callback", t
->def
);
2989 t
->rstate
->termination_context
= NULL
;
2990 freeL("enum_termination_callback", t
);
2993 static void handle_reconfirm_request(request_state
*rstate
)
2997 rr
= read_rr_from_ipc_msg(rstate
->msgdata
, 0, 1);
2999 LogOperation("%3d: DNSServiceReconfirmRecord(%##s) %s", rstate
->sd
, RRDisplayString(gmDNS
, &rr
->resrec
));
3000 mDNS_ReconfirmByValue(gmDNS
, &rr
->resrec
);
3001 abort_request(rstate
);
3002 unlink_request(rstate
);
3003 freeL("handle_reconfirm_request", rr
);
3006 // setup rstate to accept new reg/dereg requests
3007 static void reset_connected_rstate(request_state
*rstate
)
3009 rstate
->ts
= t_morecoming
;
3010 rstate
->hdr_bytes
= 0;
3011 rstate
->data_bytes
= 0;
3012 if (rstate
->msgbuf
) freeL("reset_connected_rstate", rstate
->msgbuf
);
3013 rstate
->msgbuf
= NULL
;
3014 rstate
->bufsize
= 0;
3017 // returns a resource record (allocated w/ malloc) containing the data found in an IPC message
3018 // data must be in format flags, interfaceIndex, name, rrtype, rrclass, rdlen, rdata, (optional)ttl
3019 // (ttl only extracted/set if ttl argument is non-zero). returns NULL for a bad-parameter error
3020 static AuthRecord
*read_rr_from_ipc_msg(char *msgbuf
, int GetTTL
, int validate_flags
)
3022 char *rdata
, name
[256];
3024 DNSServiceFlags flags
;
3025 uint32_t interfaceIndex
;
3026 uint16_t type
, class, rdlen
;
3029 flags
= get_flags(&msgbuf
);
3030 if (validate_flags
&&
3031 !((flags
& kDNSServiceFlagsShared
) == kDNSServiceFlagsShared
) &&
3032 !((flags
& kDNSServiceFlagsUnique
) == kDNSServiceFlagsUnique
))
3034 LogMsg("ERROR: Bad resource record flags (must be kDNSServiceFlagsShared or kDNSServiceFlagsUnique)");
3038 interfaceIndex
= get_long(&msgbuf
);
3039 if (get_string(&msgbuf
, name
, 256) < 0)
3041 LogMsg("ERROR: read_rr_from_ipc_msg - get_string");
3044 type
= get_short(&msgbuf
);
3045 class = get_short(&msgbuf
);
3046 rdlen
= get_short(&msgbuf
);
3048 if (rdlen
> sizeof(RDataBody
)) storage_size
= rdlen
;
3049 else storage_size
= sizeof(RDataBody
);
3051 rr
= mallocL("read_rr_from_ipc_msg", sizeof(AuthRecord
) - sizeof(RDataBody
) + storage_size
);
3052 if (!rr
) FatalError("ERROR: malloc");
3053 bzero(rr
, sizeof(AuthRecord
)); // ok if oversized rdata not zero'd
3055 mDNS_SetupResourceRecord(rr
, mDNSNULL
, mDNSPlatformInterfaceIDfromInterfaceIndex(gmDNS
, interfaceIndex
),
3056 type
, 0, (flags
& kDNSServiceFlagsShared
) ? kDNSRecordTypeShared
: kDNSRecordTypeUnique
, mDNSNULL
, mDNSNULL
);
3058 if (!MakeDomainNameFromDNSNameString(rr
->resrec
.name
, name
))
3060 LogMsg("ERROR: bad name: %s", name
);
3061 freeL("read_rr_from_ipc_msg", rr
);
3064 if (flags
& kDNSServiceFlagsAllowRemoteQuery
) rr
->AllowRemoteQuery
= mDNStrue
;
3065 rr
->resrec
.rrclass
= class;
3066 rr
->resrec
.rdlength
= rdlen
;
3067 rr
->resrec
.rdata
->MaxRDLength
= rdlen
;
3068 rdata
= get_rdata(&msgbuf
, rdlen
);
3069 memcpy(rr
->resrec
.rdata
->u
.data
, rdata
, rdlen
);
3072 rr
->resrec
.rroriginalttl
= get_long(&msgbuf
);
3077 // generate a response message for a browse result, service registration result, or any other call with the
3078 // identical callback signature. on successful completion rep is set to point to a malloc'd reply_state struct,
3079 // and mStatus_NoError is returned. otherwise the appropriate error is returned.
3081 static mStatus
gen_rr_response(domainname
*servicename
, mDNSInterfaceID id
, request_state
*request
, reply_state
**rep
)
3086 domainname type
, dom
;
3087 char namestr
[MAX_DOMAIN_LABEL
+1]; // Unescaped name: up to 63 bytes plus C-string terminating NULL.
3088 char typestr
[MAX_ESCAPED_DOMAIN_NAME
];
3089 char domstr
[MAX_ESCAPED_DOMAIN_NAME
];
3093 if (!DeconstructServiceName(servicename
, &name
, &type
, &dom
))
3094 return kDNSServiceErr_Unknown
;
3096 ConvertDomainLabelToCString_unescaped(&name
, namestr
);
3097 ConvertDomainNameToCString(&type
, typestr
);
3098 ConvertDomainNameToCString(&dom
, domstr
);
3100 // calculate reply data length
3101 len
= sizeof(DNSServiceFlags
);
3102 len
+= sizeof(uint32_t); // if index
3103 len
+= sizeof(DNSServiceErrorType
);
3104 len
+= (int) (strlen(namestr
) + 1);
3105 len
+= (int) (strlen(typestr
) + 1);
3106 len
+= (int) (strlen(domstr
) + 1);
3108 *rep
= create_reply(query_reply
, len
, request
);
3110 (*rep
)->rhdr
->flags
= dnssd_htonl(0);
3111 (*rep
)->rhdr
->ifi
= dnssd_htonl(mDNSPlatformInterfaceIndexfromInterfaceID(gmDNS
, id
));
3112 (*rep
)->rhdr
->error
= dnssd_htonl(kDNSServiceErr_NoError
);
3114 data
= (*rep
)->sdata
;
3116 put_string(namestr
, &data
);
3117 put_string(typestr
, &data
);
3118 put_string(domstr
, &data
);
3119 return mStatus_NoError
;
3122 static int build_domainname_from_strings(domainname
*srv
, char *name
, char *regtype
, char *domain
)
3127 if (!MakeDomainLabelFromLiteralString(&n
, name
)) return -1;
3128 if (!MakeDomainNameFromDNSNameString(&t
, regtype
)) return -1;
3129 if (!MakeDomainNameFromDNSNameString(&d
, domain
)) return -1;
3130 if (!ConstructServiceName(srv
, &n
, &t
, &d
)) return -1;
3134 // append a reply to the list in a request object
3135 static void append_reply(request_state
*req
, reply_state
*rep
)
3139 if (!req
->replies
) req
->replies
= rep
;
3143 while (ptr
->next
) ptr
= ptr
->next
;
3149 // read_msg may be called any time when the transfer state (rs->ts) is t_morecoming.
3150 // returns the current state of the request (morecoming, error, complete, terminated.)
3151 // if there is no data on the socket, the socket will be closed and t_terminated will be returned
3152 static int read_msg(request_state
*rs
)
3156 char buf
[4]; // dummy for death notification
3158 if (rs
->ts
== t_terminated
|| rs
->ts
== t_error
)
3160 LogMsg("ERROR: read_msg called with transfer state terminated or error");
3165 if (rs
->ts
== t_complete
)
3166 { // this must be death or something is wrong
3167 nread
= recv(rs
->sd
, buf
, 4, 0);
3168 if (!nread
) { rs
->ts
= t_terminated
; return t_terminated
; }
3169 if (nread
< 0) goto rerror
;
3170 LogMsg("ERROR: read data from a completed request.");
3175 if (rs
->ts
!= t_morecoming
)
3177 LogMsg("ERROR: read_msg called with invalid transfer state (%d)", rs
->ts
);
3182 if (rs
->hdr_bytes
< sizeof(ipc_msg_hdr
))
3184 nleft
= sizeof(ipc_msg_hdr
) - rs
->hdr_bytes
;
3185 nread
= recv(rs
->sd
, (char *)&rs
->hdr
+ rs
->hdr_bytes
, nleft
, 0);
3186 if (nread
== 0) { rs
->ts
= t_terminated
; return t_terminated
; }
3187 if (nread
< 0) goto rerror
;
3188 rs
->hdr_bytes
+= nread
;
3189 if (rs
->hdr_bytes
== sizeof(ipc_msg_hdr
))
3191 ConvertHeaderBytes(&rs
->hdr
);
3192 if (rs
->hdr
.version
!= VERSION
)
3194 LogMsg("ERROR: read_msg - client version 0x%08X does not match daemon version 0x%08X", rs
->hdr
.version
, VERSION
);
3199 if (rs
->hdr_bytes
> sizeof(ipc_msg_hdr
))
3201 LogMsg("ERROR: read_msg - read too many header bytes");
3207 // only read data if header is complete
3208 if (rs
->hdr_bytes
== sizeof(ipc_msg_hdr
))
3210 if (rs
->hdr
.datalen
== 0) // ok in removerecord requests
3212 rs
->ts
= t_complete
;
3217 if (!rs
->msgbuf
) // allocate the buffer first time through
3219 rs
->msgbuf
= mallocL("read_msg", rs
->hdr
.datalen
+ MSG_PAD_BYTES
);
3222 my_perror("ERROR: malloc");
3226 rs
->msgdata
= rs
->msgbuf
;
3228 bzero(rs
->msgbuf
, rs
->hdr
.datalen
+ MSG_PAD_BYTES
);
3229 nleft
= rs
->hdr
.datalen
- rs
->data_bytes
;
3230 nread
= recv(rs
->sd
, rs
->msgbuf
+ rs
->data_bytes
, nleft
, 0);
3231 if (nread
== 0) { rs
->ts
= t_terminated
; return t_terminated
; }
3232 if (nread
< 0) goto rerror
;
3233 rs
->data_bytes
+= nread
;
3234 if (rs
->data_bytes
> rs
->hdr
.datalen
)
3236 LogMsg("ERROR: read_msg - read too many data bytes");
3242 if (rs
->hdr_bytes
== sizeof(ipc_msg_hdr
) && rs
->data_bytes
== rs
->hdr
.datalen
)
3243 rs
->ts
= t_complete
;
3244 else rs
->ts
= t_morecoming
;
3249 if (dnssd_errno() == dnssd_EWOULDBLOCK
|| dnssd_errno() == dnssd_EINTR
) return t_morecoming
;
3250 my_perror("ERROR: read_msg");
3255 static int send_msg(reply_state
*rs
)
3261 LogMsg("ERROR: send_msg called with NULL message buffer");
3265 if (rs
->request
->no_reply
) //!!!KRS this behavior should be optimized if it becomes more common
3267 rs
->ts
= t_complete
;
3268 freeL("send_msg", rs
->msgbuf
);
3272 ConvertHeaderBytes(rs
->mhdr
);
3273 nwriten
= send(rs
->sd
, rs
->msgbuf
+ rs
->nwriten
, rs
->len
- rs
->nwriten
, 0);
3274 ConvertHeaderBytes(rs
->mhdr
);
3277 if (dnssd_errno() == dnssd_EINTR
|| dnssd_errno() == dnssd_EWOULDBLOCK
) nwriten
= 0;
3280 #if !defined(PLATFORM_NO_EPIPE)
3281 if (dnssd_errno() == EPIPE
)
3283 debugf("%3d: broken pipe", rs
->sd
);
3284 rs
->ts
= t_terminated
;
3285 rs
->request
->ts
= t_terminated
;
3286 return t_terminated
;
3291 my_perror("ERROR: send\n");
3297 rs
->nwriten
+= nwriten
;
3299 if (rs
->nwriten
== rs
->len
)
3301 rs
->ts
= t_complete
;
3302 freeL("send_msg", rs
->msgbuf
);
3307 static reply_state
*create_reply(reply_op_t op
, size_t datalen
, request_state
*request
)
3313 if ((unsigned)datalen
< sizeof(reply_hdr
))
3315 LogMsg("ERROR: create_reply - data length less than lenght of required fields");
3319 totallen
= (int) (datalen
+ sizeof(ipc_msg_hdr
));
3320 reply
= mallocL("create_reply", sizeof(reply_state
));
3321 if (!reply
) FatalError("ERROR: malloc");
3322 bzero(reply
, sizeof(reply_state
));
3323 reply
->ts
= t_morecoming
;
3324 reply
->sd
= request
->sd
;
3325 reply
->request
= request
;
3326 reply
->len
= totallen
;
3327 reply
->msgbuf
= mallocL("create_reply", totallen
);
3328 if (!reply
->msgbuf
) FatalError("ERROR: malloc");
3329 bzero(reply
->msgbuf
, totallen
);
3330 reply
->mhdr
= (ipc_msg_hdr
*)reply
->msgbuf
;
3331 reply
->rhdr
= (reply_hdr
*)(reply
->msgbuf
+ sizeof(ipc_msg_hdr
));
3332 reply
->sdata
= reply
->msgbuf
+ sizeof(ipc_msg_hdr
) + sizeof(reply_hdr
);
3333 reply
->mhdr
->version
= VERSION
;
3334 reply
->mhdr
->op
= op
;
3335 reply
->mhdr
->datalen
= totallen
- sizeof(ipc_msg_hdr
);
3339 static int deliver_error(request_state
*rstate
, mStatus err
)
3342 undelivered_error_t
*undeliv
;
3344 err
= dnssd_htonl(err
);
3345 nwritten
= send(rstate
->sd
, &err
, sizeof(mStatus
), 0);
3346 if (nwritten
< (int)sizeof(mStatus
))
3348 if (dnssd_errno() == dnssd_EINTR
|| dnssd_errno() == dnssd_EWOULDBLOCK
)
3352 my_perror("ERROR: send - unable to deliver error to client");
3357 //client blocked - store result and come backr
3358 undeliv
= mallocL("deliver_error", sizeof(undelivered_error_t
));
3359 if (!undeliv
) FatalError("ERROR: malloc");
3361 undeliv
->nwritten
= nwritten
;
3362 undeliv
->sd
= rstate
->sd
;
3363 rstate
->u_err
= undeliv
;
3370 // returns 0 on success, -1 if send is incomplete, or on terminal failure (request is aborted)
3371 static transfer_state
send_undelivered_error(request_state
*rs
)
3375 nwritten
= send(rs
->u_err
->sd
, (char *)(&rs
->u_err
->err
) + rs
->u_err
->nwritten
, sizeof(mStatus
) - rs
->u_err
->nwritten
, 0);
3378 if (dnssd_errno() == dnssd_EINTR
|| dnssd_errno() == dnssd_EWOULDBLOCK
)
3382 my_perror("ERROR: send - unable to deliver error to client\n");
3386 if ((unsigned int)(nwritten
+ rs
->u_err
->nwritten
) >= sizeof(mStatus
))
3388 freeL("send_undelivered_error", rs
->u_err
);
3392 rs
->u_err
->nwritten
+= nwritten
;
3393 return t_morecoming
;
3396 // send bogus data along with an error code to the app callback
3397 // returns 0 on success (linking reply into list of not fully delivered),
3398 // -1 on failure (request should be aborted)
3399 static int deliver_async_error(request_state
*rs
, reply_op_t op
, mStatus err
)
3405 if (rs
->no_reply
) return 0;
3406 len
= 256; // long enough for any reply handler to read all args w/o buffer overrun
3407 reply
= create_reply(op
, len
, rs
);
3408 reply
->rhdr
->error
= dnssd_htonl(err
);
3409 ts
= send_msg(reply
);
3410 if (ts
== t_error
|| ts
== t_terminated
)
3412 freeL("deliver_async_error", reply
);
3415 else if (ts
== t_complete
) freeL("deliver_async_error", reply
);
3416 else if (ts
== t_morecoming
) append_reply(rs
, reply
); // client is blocked, link reply into list
3420 static void abort_request(request_state
*rs
)
3422 reply_state
*rep
, *ptr
;
3424 if (rs
->terminate
) rs
->terminate(rs
->termination_context
); // terminate field may not be set yet
3425 if (rs
->msgbuf
) freeL("abort_request", rs
->msgbuf
);
3426 LogOperation("%3d: Removing FD", rs
->sd
);
3427 udsSupportRemoveFDFromEventLoop(rs
->sd
); // Note: This also closes file descriptor rs->sd for us
3428 rs
->sd
= dnssd_InvalidSocket
;
3430 // free pending replies
3434 if (rep
->msgbuf
) freeL("abort_request", rep
->msgbuf
);
3437 freeL("abort_request", ptr
);
3442 freeL("abort_request", rs
->u_err
);
3447 static void unlink_request(request_state
*rs
)
3451 if (rs
== all_requests
)
3453 all_requests
= all_requests
->next
;
3454 freeL("unlink_request", rs
);
3457 for(ptr
= all_requests
; ptr
->next
; ptr
= ptr
->next
)
3458 if (ptr
->next
== rs
)
3460 ptr
->next
= rs
->next
;
3461 freeL("unlink_request", rs
);
3466 //hack to search-replace perror's to LogMsg's
3467 static void my_perror(char *errmsg
)
3469 LogMsg("%s: %s", errmsg
, dnssd_strerror(dnssd_errno()));
3472 // check that the message delivered by the client is sufficiently long to extract the required data from the buffer
3473 // without overrunning it.
3474 // returns 0 on success, -1 on error.
3476 static int validate_message(request_state
*rstate
)
3480 switch(rstate
->hdr
.op
)
3482 case resolve_request
: min_size
= sizeof(DNSServiceFlags
) + // flags
3483 sizeof(uint32_t) + // interface
3484 (3 * sizeof(char)); // name, regtype, domain
3486 case query_request
: min_size
= sizeof(DNSServiceFlags
) + // flags
3487 sizeof(uint32_t) + // interface
3488 sizeof(char) + // fullname
3489 (2 * sizeof(uint16_t)); // type, class
3491 case browse_request
: min_size
= sizeof(DNSServiceFlags
) + // flags
3492 sizeof(uint32_t) + // interface
3493 (2 * sizeof(char)); // regtype, domain
3495 case reg_service_request
: min_size
= sizeof(DNSServiceFlags
) + // flags
3496 sizeof(uint32_t) + // interface
3497 (4 * sizeof(char)) + // name, type, domain, host
3498 (2 * sizeof(uint16_t)); // port, textlen
3500 case enumeration_request
: min_size
= sizeof(DNSServiceFlags
) + // flags
3501 sizeof(uint32_t); // interface
3503 case reg_record_request
: min_size
= sizeof(DNSServiceFlags
) + // flags
3504 sizeof(uint32_t) + // interface
3505 sizeof(char) + // fullname
3506 (3 * sizeof(uint16_t)) + // type, class, rdlen
3507 sizeof(uint32_t); // ttl
3509 case add_record_request
: min_size
= sizeof(DNSServiceFlags
) + // flags
3510 (2 * sizeof(uint16_t)) + // type, rdlen
3511 sizeof(uint32_t); // ttl
3513 case update_record_request
: min_size
= sizeof(DNSServiceFlags
) + // flags
3514 sizeof(uint16_t) + // rdlen
3515 sizeof(uint32_t); // ttl
3517 case remove_record_request
: min_size
= sizeof(DNSServiceFlags
); // flags
3519 case reconfirm_record_request
: min_size
=sizeof(DNSServiceFlags
) + // flags
3520 sizeof(uint32_t) + // interface
3521 sizeof(char) + // fullname
3522 (3 * sizeof(uint16_t)); // type, class, rdlen
3524 case setdomain_request
: min_size
= sizeof(DNSServiceFlags
) + sizeof(char); // flags + domain
3527 LogMsg("ERROR: validate_message - unsupported request type: %d", rstate
->hdr
.op
);
3531 return (rstate
->data_bytes
>= min_size
? 0 : -1);
3535 static uint32_t dnssd_htonl(uint32_t l
)
3540 data
= (char*) &ret
;
3549 static char * win32_strerror(int inErrorCode
)
3551 static char buffer
[1024];
3554 memset(buffer
, 0, sizeof(buffer
));
3557 FORMAT_MESSAGE_FROM_SYSTEM
| FORMAT_MESSAGE_IGNORE_INSERTS
,
3559 (DWORD
) inErrorCode
,
3560 MAKELANGID( LANG_NEUTRAL
, SUBLANG_DEFAULT
),
3567 // Remove any trailing CR's or LF's since some messages have them.
3569 while( ( n
> 0 ) && isspace( ( (unsigned char *) buffer
)[ n
- 1 ] ) )
3571 buffer
[ --n
] = '\0';