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.183 2005/06/13 22:39:11 cheshire
28 <rdar://problem/4144870> Missing return statement in handle_enum_request() error handling
30 Revision 1.182 2005/03/21 00:39:31 shersche
31 <rdar://problem/4021486> Fix build warnings on Win32 platform
33 Revision 1.181 2005/03/20 20:21:32 shersche
34 <rdar://problem/4056827> mDNSResponder crashes when incorrect interface index is passed to DNSServiceRegister()
35 Text record length and data parameters must be initialized to 0 and NULL to ensure that the service request
36 object is cleaned up correctly when encountering an interface index error.
38 Revision 1.180 2005/03/10 00:13:12 cheshire
39 <rdar://problem/4043098> DNSServiceBrowse no longer returning error codes for invalid types
40 In handle_browse_request(), mStatus err was being set correctly if an error occurred,
41 but the end of the function returned mStatus_NoError intead of err.
43 Revision 1.179 2005/03/04 02:47:26 ksekar
44 <rdar://problem/4026393> SCPreference domains disappear from enumeration when moving out from firewall
46 Revision 1.178 2005/02/25 19:35:38 ksekar
47 <rdar://problem/4023750> Non-local empty string registration failures should not return errors to caller
49 Revision 1.177 2005/02/25 03:05:41 cheshire
50 Change "broken pipe" message to debugf()
52 Revision 1.176 2005/02/24 18:44:45 ksekar
53 <rdar://problem/4018516> Printer Sharing does not get re-registered with wide-area
55 Revision 1.175 2005/02/21 21:31:25 ksekar
56 <rdar://problem/4015162> changed LogMsg to debugf
58 Revision 1.174 2005/02/20 01:41:17 cheshire
59 Fix compiler signed/unsigned warning
61 Revision 1.173 2005/02/18 01:26:42 cheshire
62 <rdar://problem/4012162> "Could not write data to client after 60 seconds" message could be more helpful
63 Log additional information about failed client
65 Revision 1.172 2005/02/18 00:58:35 cheshire
66 <rdar://problem/4012162> "Could not write data to client after 60 seconds" message could be more helpful
68 Revision 1.171 2005/02/18 00:43:12 cheshire
69 <rdar://problem/4010245> mDNSResponder should auto-truncate service names that are too long
71 Revision 1.170 2005/02/16 01:15:02 cheshire
72 Improve LogOperation() debugging messages for DNSServiceBrowse and DNSServiceRegister
74 Revision 1.169 2005/02/08 01:57:14 cheshire
75 More detailed error reporting in udsserver_init()
77 Revision 1.168 2005/02/03 00:44:37 cheshire
78 <rdar://problem/3986663> DNSServiceUpdateRecord returns kDNSServiceErr_Invalid when rdlen=0, rdata=NULL
80 Revision 1.167 2005/02/02 02:19:32 cheshire
81 Add comment explaining why unlink(MDNS_UDS_SERVERPATH); fails
83 Revision 1.166 2005/02/01 19:58:52 ksekar
84 Shortened cryptic "broken pipe" syslog message
86 Revision 1.165 2005/02/01 19:56:47 ksekar
87 Moved LogMsg from daemon.c to uds_daemon.c, cleaned up wording
89 Revision 1.164 2005/01/28 06:07:55 cheshire
90 Don't use deliver_error() from within handle_regrecord_request()
92 Revision 1.163 2005/01/28 01:39:16 cheshire
93 Include file descriptor number in "broken pipe" message
95 Revision 1.162 2005/01/27 23:59:20 cheshire
96 Remove extraneous LogMsg
98 Revision 1.161 2005/01/27 22:57:56 cheshire
99 Fix compile errors on gcc4
101 Revision 1.160 2005/01/27 20:52:11 cheshire
102 <rdar://problem/3972566> mDNSResponder leaks sockets for add/update/remove record calls
104 Revision 1.159 2005/01/27 01:45:25 cheshire
105 <rdar://problem/3976147> mDNSResponder should never call exit(1);
107 Revision 1.158 2005/01/25 17:28:07 ksekar
108 <rdar://problem/3971467> Should not return "local" twice for domain enumeration
110 Revision 1.157 2005/01/21 02:20:39 cheshire
111 Fix mistake in LogOperation() format string
113 Revision 1.156 2005/01/19 19:15:36 ksekar
114 Refinement to <rdar://problem/3954575> - Simplify mDNS_PurgeResultsForDomain logic and move into daemon layer
116 Revision 1.155 2005/01/19 03:00:47 cheshire
117 Show Add/Rmv in DNSServiceBrowse LogOperation() message
119 Revision 1.154 2005/01/15 00:56:42 ksekar
120 <rdar://problem/3954575> Unicast services don't disappear when logging
123 Revision 1.153 2005/01/14 18:44:28 ksekar
124 <rdar://problem/3954609> mDNSResponder is crashing when changing domains
126 Revision 1.152 2005/01/13 17:16:38 ksekar
127 Back out checkin 1.150 - correct fix is on clientstub side
129 Revision 1.151 2005/01/11 21:06:29 ksekar
130 Changed now-benign LogMsg to debugf
132 Revision 1.150 2005/01/07 23:59:15 ksekar
133 <rdar://problem/3942900> dnd-sd shows the wrong port numbers
135 Revision 1.149 2004/12/20 23:20:35 cheshire
136 <rdar://problem/3928361> mDNSResponder crashes repeatedly when printer sharing is enabled
137 Make sure to call mDNS_SetupResourceRecord() for all newly created AuthRecords
139 Revision 1.148 2004/12/20 20:37:35 cheshire
140 AllowRemoteQuery not set for the extras in a ServiceRecordSet
142 Revision 1.147 2004/12/20 00:15:41 cheshire
143 Include client file descriptor numbers in udsserver_info() output
145 Revision 1.146 2004/12/17 05:25:47 cheshire
146 <rdar://problem/3925163> Shorten DNS-SD queries to avoid NAT bugs
148 Revision 1.145 2004/12/16 21:39:46 cheshire
149 Include CacheGroup objects in CacheUsed count
151 Revision 1.144 2004/12/16 21:27:38 ksekar
152 Fixed build failures when compiled with verbose debugging messages
154 Revision 1.143 2004/12/16 20:13:02 cheshire
155 <rdar://problem/3324626> Cache memory management improvements
157 Revision 1.142 2004/12/16 08:07:33 shersche
158 Fix compiler error (mixed declarations and code) on Windows
160 Revision 1.141 2004/12/16 01:56:21 cheshire
161 Improve DNSServiceEnumerateDomains syslog message
163 Revision 1.140 2004/12/14 03:02:10 ksekar
164 <rdar://problem/3919016> Rare race condition can cause crash
166 Revision 1.139 2004/12/13 21:18:45 ksekar
167 Include uDNS registrations in CountPeerRegistrations
169 Revision 1.138 2004/12/13 18:23:18 ksekar
170 <rdar://problem/3915805> mDNSResponder error when quitting iChat -
171 don't close sockets delivering errors to blocked clients
173 Revision 1.137 2004/12/13 00:09:22 ksekar
174 <rdar://problem/3915805> mDNSResponder error when quitting iChat
176 Revision 1.136 2004/12/11 01:52:10 cheshire
177 <rdar://problem/3785820> Support kDNSServiceFlagsAllowRemoteQuery for registering services too
179 Revision 1.135 2004/12/10 20:46:37 cheshire
180 Change LogOperation message to debugf
182 Revision 1.134 2004/12/10 13:19:37 cheshire
183 Add verbosedebugf() logging message in CountPeerRegistrations()
185 Revision 1.133 2004/12/10 05:27:26 cheshire
186 <rdar://problem/3909147> Guard against multiple autoname services of the same type on the same machine
188 Revision 1.132 2004/12/10 04:28:28 cheshire
189 <rdar://problem/3914406> User not notified of name changes for services using new UDS API
191 Revision 1.131 2004/12/10 02:09:25 cheshire
192 <rdar://problem/3898376> Modify default TTLs
194 Revision 1.130 2004/12/10 00:55:24 cheshire
195 Add full name and type to LogOperation messages for DNSServiceAddRecord/UpdateRecord/RemoveRecord
197 Revision 1.129 2004/12/09 03:17:23 ksekar
198 <rdar://problem/3910435> DomainEnumeration interface index should be zero
200 Revision 1.128 2004/12/07 21:26:05 ksekar
201 <rdar://problem/3908336> DNSServiceRegisterRecord() can crash on deregistration
203 Revision 1.127 2004/12/07 20:42:34 cheshire
204 Add explicit context parameter to mDNS_RemoveRecordFromService()
206 Revision 1.126 2004/12/07 17:23:55 ksekar
209 Revision 1.125 2004/12/06 21:15:23 ksekar
210 <rdar://problem/3884386> mDNSResponder crashed in CheckServiceRegistrations
212 Revision 1.124 2004/11/30 02:19:14 cheshire
213 <rdar://problem/3827971> Raise maxfds.rlim_cur for mDNSResponder
215 Revision 1.123 2004/11/29 23:50:57 cheshire
216 Checkin 1.122 not necessary
218 Revision 1.122 2004/11/24 17:55:01 ksekar
219 Added log message clarifying <rdar://problem/3869241> For unicast operations, verify that service types are legal
221 Revision 1.121 2004/11/24 04:45:52 cheshire
224 Revision 1.120 2004/11/24 00:10:44 cheshire
225 <rdar://problem/3869241> For unicast operations, verify that service types are legal
227 Revision 1.119 2004/11/23 23:54:17 ksekar
228 <rdar://problem/3890318> Wide-Area DNSServiceRegisterRecord() failures
229 can crash mDNSResponder
231 Revision 1.118 2004/11/23 22:33:01 cheshire
232 <rdar://problem/3654910> Remove temporary workaround code for iChat
234 Revision 1.117 2004/11/23 20:23:10 ksekar
235 Fixed LogOperation that causes crash on connected service deregistrations
237 Revision 1.116 2004/11/23 03:39:47 cheshire
238 Let interface name/index mapping capability live directly in JNISupport.c,
239 instead of having to call through to the daemon via IPC to get this information.
241 Revision 1.115 2004/11/13 00:12:53 ksekar
242 Fixed some LogOperation printf converstions for debug builds.
244 Revision 1.114 2004/11/12 18:25:45 shersche
245 Tidy up cross platform usleep code fragment.
247 Revision 1.113 2004/11/12 03:21:41 rpantos
248 rdar://problem/3809541 Add DNSSDMapIfIndexToName, DNSSDMapNameToIfIndex.
250 Revision 1.112 2004/11/11 16:58:32 ksekar
251 Removed unused code (previously wrapped in #if 0)
253 Revision 1.111 2004/11/05 22:47:37 shersche
254 Conditionally compile usleep(1000) to be Sleep(1) on Windows
255 Submitted by: Pavel Repin <prepin@gmail.com>
257 Revision 1.110 2004/11/05 19:56:56 ksekar
258 <rdar://problem/3862646> We no longer need to browse .Mac domains by
259 default - changed #if 0 to more descriptive #ifdef _HAVE_SETDOMAIN_SUPPORT_
261 Revision 1.109 2004/11/04 03:40:45 cheshire
262 More debugging messages
264 Revision 1.108 2004/11/03 02:25:51 cheshire
265 <rdar://problem/3324137> Conflict for Computer Name should update *all* empty string services, not just the one with the conflict
267 Revision 1.107 2004/11/02 19:39:23 ksekar
268 <rdar://problem/3862646> We no longer need to browse .Mac domains by default
270 Revision 1.106 2004/11/02 02:12:21 cheshire
271 <rdar://problem/3839111> Remove unnecessary memory allocations
273 Revision 1.105 2004/10/28 19:07:19 cheshire
274 Add some more debugging checks and improved LogOperation() messages
276 Revision 1.104 2004/10/26 18:53:15 cheshire
277 Avoid unused variable warning
279 Revision 1.103 2004/10/26 07:15:55 cheshire
280 Add file descriptor number to all LogOperation messages
282 Revision 1.102 2004/10/26 06:11:42 cheshire
283 Add improved logging to aid in diagnosis of <rdar://problem/3842714> mDNSResponder crashed
285 Revision 1.101 2004/10/26 04:31:44 cheshire
286 Rename CountSubTypes() as ChopSubTypes()
288 Revision 1.100 2004/10/26 01:17:48 cheshire
289 Use "#if 0" instead of commenting out code
291 Revision 1.99 2004/10/19 21:33:22 cheshire
292 <rdar://problem/3844991> Cannot resolve non-local registrations using the mach API
293 Added flag 'kDNSServiceFlagsForceMulticast'. Passing through an interface id for a unicast name
294 doesn't force multicast unless you set this flag to indicate explicitly that this is what you want
296 Revision 1.98 2004/10/14 01:59:33 cheshire
297 <rdar://problem/3839208> UDS resolves don't work for uDNS services
299 Revision 1.97 2004/10/13 00:58:35 cheshire
300 <rdar://problem/3832738> Registering a proxy doesn't work
302 Revision 1.96 2004/09/30 00:25:00 ksekar
303 <rdar://problem/3695802> Dynamically update default registration domains on config change
305 Revision 1.95 2004/09/26 23:20:36 ksekar
306 <rdar://problem/3813108> Allow default registrations in multiple wide-area domains
308 Revision 1.94 2004/09/22 18:27:06 ksekar
309 <rdar://problem/3811427> allow DNSServiceAddRecord to pass zero to get
312 Revision 1.93 2004/09/22 02:39:44 cheshire
313 <rdar://problem/3810757> Allow DNSServiceRegisterRecord to pass zero to get default record TTL
315 Revision 1.92 2004/09/22 02:34:04 cheshire
316 Rename parameter "ttl" to "GetTTL" for clarity
318 Revision 1.91 2004/09/22 02:25:43 cheshire
321 Revision 1.90 2004/09/21 23:40:12 ksekar
322 <rdar://problem/3810349> mDNSResponder to return errors on NAT traversal failure
324 Revision 1.89 2004/09/21 23:29:51 cheshire
325 <rdar://problem/3680045> DNSServiceResolve should delay sending packets
327 Revision 1.88 2004/09/21 23:12:46 cheshire
328 Reorder initialization of question fields to match structure order
330 Revision 1.87 2004/09/21 22:18:33 cheshire
331 In SIGINFO output, display a '-' next to records that have the Unique bit set
333 Revision 1.86 2004/09/21 21:05:11 cheshire
334 Move duplicate code out of mDNSMacOSX/daemon.c and mDNSPosix/PosixDaemon.c,
335 into mDNSShared/uds_daemon.c
337 Revision 1.85 2004/09/18 01:11:58 ksekar
338 <rdar://problem/3806734> Add a user's default domain to empty-string browse list
340 Revision 1.84 2004/09/17 01:08:55 cheshire
341 Renamed mDNSClientAPI.h to mDNSEmbeddedAPI.h
342 The name "mDNSClientAPI.h" is misleading to new developers looking at this code. The interfaces
343 declared in that file are ONLY appropriate to single-address-space embedded applications.
344 For clients on general-purpose computers, the interfaces defined in dns_sd.h should be used.
346 Revision 1.83 2004/09/16 23:26:33 cheshire
347 Move version check inside preceeding "if" that checks we have a complete header
349 Revision 1.82 2004/09/16 23:14:25 cheshire
350 Changes for Windows compatibility
352 Revision 1.81 2004/09/16 21:46:38 ksekar
353 <rdar://problem/3665304> Need SPI for LoginWindow to associate a UID with a Wide Area domain
355 Revision 1.80 2004/09/16 01:58:23 cheshire
356 Fix compiler warnings
358 Revision 1.79 2004/09/16 00:24:49 cheshire
359 <rdar://problem/3803162> Fix unsafe use of mDNSPlatformTimeNow()
361 Revision 1.78 2004/09/15 21:44:20 cheshire
362 <rdar://problem/3681031> Randomize initial timenow_adjust value in mDNS_Init
363 Show time value in log to help diagnose errors
365 Revision 1.77 2004/09/15 00:19:18 cheshire
366 <rdar://problem/3785823> read_rr_from_ipc_msg should use mDNS_SetupResourceRecord()
368 Revision 1.76 2004/09/02 06:39:52 cheshire
369 Minor textual cleanup for clarity
371 Revision 1.75 2004/09/02 03:48:47 cheshire
372 <rdar://problem/3709039> Disable targeted unicast query support by default
373 1. New flag kDNSServiceFlagsAllowRemoteQuery to indicate we want to allow remote queries for this record
374 2. New field AllowRemoteQuery in AuthRecord structure
375 3. uds_daemon.c sets AllowRemoteQuery if kDNSServiceFlagsAllowRemoteQuery is set
376 4. mDNS.c only answers remote queries if AllowRemoteQuery is set
378 Revision 1.74 2004/08/25 02:32:47 cheshire
379 Minor cleanup: replace "®type[0]" with "regtype"
381 Revision 1.73 2004/08/25 02:30:40 cheshire
382 <rdar://problem/3588761> Current method of doing subtypes causes name collisions
384 Revision 1.72 2004/08/14 03:22:42 cheshire
385 <rdar://problem/3762579> Dynamic DNS UI <-> mDNSResponder glue
386 Add GetUserSpecifiedDDNSName() routine
387 Convert ServiceRegDomain to domainname instead of C string
388 Replace mDNS_GenerateFQDN/mDNS_GenerateGlobalFQDN with mDNS_SetFQDNs
390 Revision 1.71 2004/08/11 04:21:21 rpantos
393 Revision 1.70 2004/08/11 02:07:00 cheshire
394 Remove "mDNS *globalInstance" parameter from udsserver_init()
395 Move CheckForDuplicateRegistrations from daemon.c
396 <rdar://problem/3501938> No warning when accidentally registering the same service multiple times using socket API
398 Revision 1.69 2004/08/10 16:14:48 cheshire
399 Fix debug builds (oops)
401 Revision 1.68 2004/08/10 06:24:56 cheshire
402 Use types with precisely defined sizes for 'op' and 'reg_index', for better
403 compatibility if the daemon and the client stub are built using different compilers
405 Revision 1.67 2004/07/27 07:14:16 shersche
406 make error socket non-blocking after call to connect()
408 Revision 1.66 2004/07/13 21:24:25 rpantos
409 Fix for <rdar://problem/3701120>.
411 Revision 1.65 2004/06/26 03:17:14 shersche
412 implement cross-platform strerror function
414 Submitted by: herscher
416 Revision 1.64 2004/06/25 00:26:27 rpantos
417 Changes to fix the Posix build on Solaris.
419 Revision 1.63 2004/06/24 03:43:44 rpantos
420 Fix previous checkin so it builds on Windows.
422 Revision 1.62 2004/06/24 00:57:08 ksekar
423 Replaced code acccidentally removed in checkin 1.59.
425 Revision 1.61 2004/06/19 00:09:39 cheshire
426 Remove unused strsep() implementation
428 Revision 1.60 2004/06/18 19:10:00 cheshire
429 <rdar://problem/3588761> Current method of doing subtypes causes name collisions
431 Revision 1.59 2004/06/18 05:10:31 rpantos
432 Changes to allow code to be used on Windows
434 Revision 1.58 2004/06/15 03:54:08 cheshire
435 Include mDNS_TimeNow(&mDNSStorage) in SIGINFO output
437 Revision 1.57 2004/06/12 01:47:27 ksekar
438 <rdar://problem/3690241>: BBEdit crashes when trying to check for newer version
439 udsserver_idle compared time in ticks to interval in seconds.
441 Revision 1.56 2004/06/12 01:35:47 cheshire
442 Changes for Windows compatibility
444 Revision 1.55 2004/06/05 00:04:27 cheshire
445 <rdar://problem/3668639>: wide-area domains should be returned in reg. domain enumeration
447 Revision 1.54 2004/06/01 22:22:52 ksekar
448 <rdar://problem/3668635>: wide-area default registrations should be in
451 Revision 1.53 2004/05/28 23:42:37 ksekar
452 <rdar://problem/3258021>: Feature: DNS server->client notification on record changes (#7805)
454 Revision 1.52 2004/05/26 00:39:49 ksekar
455 <rdar://problem/3667105>: wide-area DNS-SD servers don't appear in
457 Use local-only InterfaceID for GetDomains calls for sockets-API
459 Revision 1.51 2004/05/18 23:51:27 cheshire
460 Tidy up all checkin comments to use consistent "<rdar://problem/xxxxxxx>" format for bug numbers
462 Revision 1.50 2004/05/14 16:39:47 ksekar
463 Browse for iChat locally for now.
465 Revision 1.49 2004/05/13 21:33:52 ksekar
466 Clean up non-local registration control via config file. Force iChat
467 registrations to be local for now.
469 Revision 1.48 2004/05/13 04:13:19 ksekar
470 Updated SIGINFO handler for multi-domain browses
472 Revision 1.47 2004/05/12 22:04:01 ksekar
473 Implemented multi-domain browsing by default for uds_daemon.
475 Revision 1.46 2004/05/06 18:42:58 ksekar
476 General dns_sd.h API cleanup, including the following radars:
477 <rdar://problem/3592068>: Remove flags with zero value
478 <rdar://problem/3479569>: Passing in NULL causes a crash.
480 Revision 1.45 2004/03/12 08:49:28 cheshire
481 #include <sys/socket.h>
483 Revision 1.44 2004/02/25 01:25:27 ksekar
484 <rdar://problem/3569212>: DNSServiceRegisterRecord flags not error-checked
486 Revision 1.43 2004/02/24 01:46:40 cheshire
487 Manually reinstate lost checkin 1.36
489 Revision 1.42 2004/02/05 19:39:29 cheshire
490 Move creation of /var/run/mDNSResponder.pid to uds_daemon.c,
491 so that all platforms get this functionality
493 Revision 1.41 2004/02/03 18:59:02 cheshire
494 Change "char *domain" parameter for format_enumeration_reply to "const char *domain"
496 Revision 1.40 2004/01/28 03:41:00 cheshire
497 <rdar://problem/3541946>: Need ability to do targeted queries as well as multicast queries
499 Revision 1.39 2004/01/25 00:03:21 cheshire
500 Change to use mDNSVal16() instead of private PORT_AS_NUM() macro
502 Revision 1.38 2004/01/19 19:51:46 cheshire
503 Fix compiler error (mixed declarations and code) on some versions of Linux
505 Revision 1.37 2003/12/08 21:11:42 rpantos
506 Changes necessary to support mDNSResponder on Linux.
508 Revision 1.36 2003/12/04 23:40:57 cheshire
509 <rdar://problem/3484766>: Security: Crashing bug in mDNSResponder
510 Fix some more code that should use buffer size MAX_ESCAPED_DOMAIN_NAME (1005) instead of 256-byte buffers.
512 Revision 1.35 2003/12/03 19:10:22 ksekar
513 <rdar://problem/3498644>: malloc'd data not zero'd
515 Revision 1.34 2003/12/03 02:00:01 ksekar
516 <rdar://problem/3498644>: malloc'd data not zero'd
518 Revision 1.33 2003/11/22 01:18:46 ksekar
519 <rdar://problem/3486646>: config change handler not called for dns-sd services
521 Revision 1.32 2003/11/20 21:46:12 ksekar
522 <rdar://problem/3486635>: leak: DNSServiceRegisterRecord
524 Revision 1.31 2003/11/20 20:33:05 ksekar
525 <rdar://problem/3486635>: leak: DNSServiceRegisterRecord
527 Revision 1.30 2003/11/20 02:10:55 ksekar
528 <rdar://problem/3486643>: cleanup DNSServiceAdd/RemoveRecord
530 Revision 1.29 2003/11/14 21:18:32 cheshire
531 <rdar://problem/3484766>: Security: Crashing bug in mDNSResponder
532 Fix code that should use buffer size MAX_ESCAPED_DOMAIN_NAME (1005) instead of 256-byte buffers.
534 Revision 1.28 2003/11/08 22:18:29 cheshire
535 <rdar://problem/3477870>: Don't need to show process ID in *every* mDNSResponder syslog message
537 Revision 1.27 2003/11/05 22:44:57 ksekar
538 <rdar://problem/3335230>: No bounds checking when reading data from client
539 Reviewed by: Stuart Cheshire
541 Revision 1.26 2003/10/23 17:51:04 ksekar
542 <rdar://problem/3335216>: handle blocked clients more efficiently
543 Changed gettimeofday() to mDNS_TimeNow(&mDNSStorage);
545 Revision 1.25 2003/10/22 23:37:49 ksekar
546 <rdar://problem/3459141>: crash/hang in abort_client
548 Revision 1.24 2003/10/21 20:59:40 ksekar
549 <rdar://problem/3335216>: handle blocked clients more efficiently
551 Revision 1.23 2003/09/23 02:12:43 cheshire
552 Also include port number in list of services registered via new UDS API
554 Revision 1.22 2003/08/19 16:03:55 ksekar
555 <rdar://problem/3380097>: ER: SIGINFO dump should include resolves started by DNSServiceQueryRecord
556 Check termination_context for NULL before dereferencing.
558 Revision 1.21 2003/08/19 05:39:43 cheshire
559 <rdar://problem/3380097> SIGINFO dump should include resolves started by DNSServiceQueryRecord
561 Revision 1.20 2003/08/16 03:39:01 cheshire
562 <rdar://problem/3338440> InterfaceID -1 indicates "local only"
564 Revision 1.19 2003/08/15 20:16:03 cheshire
565 <rdar://problem/3366590> mDNSResponder takes too much RPRVT
566 We want to avoid touching the rdata pages, so we don't page them in.
567 1. RDLength was stored with the rdata, which meant touching the page just to find the length.
568 Moved this from the RData to the ResourceRecord object.
569 2. To avoid unnecessarily touching the rdata just to compare it,
570 compute a hash of the rdata and store the hash in the ResourceRecord object.
572 Revision 1.18 2003/08/15 00:38:00 ksekar
573 <rdar://problem/3377005>: Bug: buffer overrun when reading long rdata from client
575 Revision 1.17 2003/08/14 02:18:21 cheshire
576 <rdar://problem/3375491> Split generic ResourceRecord type into two separate types: AuthRecord and CacheRecord
578 Revision 1.16 2003/08/13 23:58:52 ksekar
579 <rdar://problem/3374911>: Bug: UDS Sub-type browsing works, but not sub-type registration
580 Fixed pointer increment error, moved subtype reading for-loop for easier error bailout.
582 Revision 1.15 2003/08/13 17:30:33 ksekar
583 <rdar://problem/3374671>: DNSServiceAddRecord doesn't work
584 Fixed various problems with handling the AddRecord request and freeing the ExtraResourceRecords.
586 Revision 1.14 2003/08/12 19:56:25 cheshire
593 #define dnssd_strerror(X) win32_strerror(X)
594 #define usleep(X) Sleep(((X)+999)/1000)
595 static char * win32_strerror(int inErrorCode
);
599 #include <sys/ioctl.h>
600 #include <sys/types.h>
601 #include <sys/time.h>
602 #include <sys/resource.h>
603 #define dnssd_strerror(X) strerror(X)
608 #include "mDNSEmbeddedAPI.h"
609 #include "DNSCommon.h"
610 #include "uds_daemon.h"
612 #include "dnssd_ipc.h"
614 // Apple specific configuration functionality, not required for other platforms
616 #include <sys/ucred.h>
617 #ifndef LOCAL_PEERCRED
618 #define LOCAL_PEERCRED 0x001 /* retrieve peer credentials */
619 #endif // LOCAL_PEERCRED
622 // Types and Data Structures
623 // ----------------------------------------------------------------------
634 typedef void (*req_termination_fn
)(void *);
636 typedef struct registered_record_entry
640 struct registered_record_entry
*next
;
641 client_context_t client_context
;
642 struct request_state
*rstate
;
643 } registered_record_entry
;
645 // A single registered service: ServiceRecordSet + bookkeeping
646 // Note that we duplicate some fields from parent service_info object
647 // to facilitate cleanup, when instances and parent may be deallocated at different times.
648 typedef struct service_instance
650 struct service_instance
*next
;
651 mDNSBool autoname
; // Set if this name is tied to the Computer Name
652 mDNSBool autorename
; // Set if this client wants us to automatically rename on conflict
653 mDNSBool allowremotequery
; // Respond to unicast queries from outside the local link?
654 mDNSBool rename_on_memfree
; // Set on config change when we deregister original name
657 mDNSBool default_local
; // is this the "local." from an empty-string registration?
658 struct request_state
*request
;
660 AuthRecord
*subtypes
;
661 ServiceRecordSet srs
; // note - must be last field in struct
664 // A client-created service. May reference several service_info objects if default
665 // settings cause registration in multiple domains.
672 char type_as_string
[MAX_ESCAPED_DOMAIN_NAME
];
674 mDNSBool default_domain
;
676 mDNSBool autoname
; // Set if this name is tied to the Computer Name
677 mDNSBool autorename
; // Set if this client wants us to automatically rename on conflict
678 mDNSBool allowremotequery
; // Respond to unicast queries from outside the local link?
680 mDNSInterfaceID InterfaceID
;
681 service_instance
*instances
;
682 struct request_state
*request
;
685 // for multi-domain default browsing
686 typedef struct browser_t
690 struct browser_t
*next
;
693 // parent struct for browser instances: list pointer plus metadata
696 mDNSBool default_domain
;
699 mDNSInterfaceID interface_id
;
700 struct request_state
*rstate
;
706 mStatus err
; // Note: This field is in NETWORK byte order
709 } undelivered_error_t
;
711 typedef struct request_state
713 // connection structures
716 // state of read (in case message is read over several recv() calls)
718 uint32_t hdr_bytes
; // bytes of header already read
720 uint32_t data_bytes
; // bytes of message data already read
721 char *msgbuf
; // pointer to data storage to pass to free()
722 char *msgdata
; // pointer to data to be read from (may be modified)
723 int bufsize
; // size of data storage
725 // reply, termination, error, and client context info
726 int no_reply
; // don't send asynchronous replies to client
727 int time_blocked
; // record time of a blocked client
728 void *client_context
; // don't touch this - pointer only valid in client's addr space
729 struct reply_state
*replies
; // corresponding (active) reply list
730 undelivered_error_t
*u_err
;
731 void *termination_context
;
732 req_termination_fn terminate
;
734 //!!!KRS toss these pointers in a union
735 // registration context associated with this request (null if not applicable)
736 registered_record_entry
*reg_recs
; // muliple registrations for a connection-oriented request
737 service_info
*service_registration
;
738 browser_info_t
*browser_info
;
739 struct request_state
*next
;
742 // struct physically sits between ipc message header and call-specific fields in the message buffer
745 DNSServiceFlags flags
; // Note: This field is in NETWORK byte order
746 uint32_t ifi
; // Note: This field is in NETWORK byte order
747 DNSServiceErrorType error
; // Note: This field is in NETWORK byte order
750 typedef struct reply_state
752 // state of the transmission
757 // context of the reply
758 struct request_state
*request
; // the request that this answers
759 struct reply_state
*next
; // if there are multiple unsent replies
760 // pointer into message buffer - allows fields to be changed after message is formatted
763 char *sdata
; // pointer to start of call-specific data
764 // pointer to malloc'd buffer
768 // domain enumeration and resolv calls require 2 mDNSCore calls, so we need separate interconnected
769 // structures to handle callbacks
772 DNSQuestion question
;
773 mDNS_DomainType type
;
774 request_state
*rstate
;
781 request_state
*rstate
;
782 } enum_termination_t
;
786 request_state
*rstate
;
789 // const ResourceRecord *txt;
790 // const ResourceRecord *srv;
796 mDNSu8 txtdata
[AbsoluteMaxDNSMessageData
];
797 } resolve_termination_t
;
799 #ifdef _HAVE_SETDOMAIN_SUPPORT_
800 typedef struct default_browse_list_t
802 struct default_browse_list_t
*next
;
805 } default_browse_list_t
;
807 static default_browse_list_t
*default_browse_list
= NULL
;
808 #endif // _HAVE_SETDOMAIN_SUPPORT_
811 mDNSexport mDNS mDNSStorage
;
812 #define gmDNS (&mDNSStorage)
814 static dnssd_sock_t listenfd
= dnssd_InvalidSocket
;
815 static request_state
* all_requests
= NULL
;
817 #define MAX_TIME_BLOCKED 60 * mDNSPlatformOneSecond // try to send data to a blocked client for 60 seconds before
818 // terminating connection
819 #define MSG_PAD_BYTES 5 // pad message buffer (read from client) with n zero'd bytes to guarantee
820 // n get_string() calls w/o buffer overrun
821 // private function prototypes
822 static void connect_callback(void *info
);
823 static int read_msg(request_state
*rs
);
824 static int send_msg(reply_state
*rs
);
825 static void abort_request(request_state
*rs
);
826 static void request_callback(void *info
);
827 static void handle_resolve_request(request_state
*rstate
);
828 static void question_result_callback(mDNS
*const m
, DNSQuestion
*question
, const ResourceRecord
*const answer
, mDNSBool AddRecord
);
829 static void question_termination_callback(void *context
);
830 static void handle_browse_request(request_state
*request
);
831 static void browse_termination_callback(void *context
);
832 static void browse_result_callback(mDNS
*const m
, DNSQuestion
*question
, const ResourceRecord
*const answer
, mDNSBool AddRecord
);
833 static void handle_regservice_request(request_state
*request
);
834 static void regservice_termination_callback(void *context
);
835 static void process_service_registration(ServiceRecordSet
*const srs
, mDNSBool SuppressError
);
836 static void regservice_callback(mDNS
*const m
, ServiceRecordSet
*const srs
, mStatus result
);
837 static mStatus
handle_add_request(request_state
*rstate
);
838 static mStatus
handle_update_request(request_state
*rstate
);
839 static mStatus
gen_rr_response(domainname
*servicename
, mDNSInterfaceID id
, request_state
*request
, reply_state
**rep
);
840 static void append_reply(request_state
*req
, reply_state
*rep
);
841 static int build_domainname_from_strings(domainname
*srv
, char *name
, char *regtype
, char *domain
);
842 static void enum_termination_callback(void *context
);
843 static void enum_result_callback(mDNS
*const m
, DNSQuestion
*question
, const ResourceRecord
*const answer
, mDNSBool AddRecord
);
844 static void handle_query_request(request_state
*rstate
);
845 static reply_state
*format_enumeration_reply(request_state
*rstate
, const char *domain
, DNSServiceFlags flags
, uint32_t ifi
, DNSServiceErrorType err
);
846 static void handle_enum_request(request_state
*rstate
);
847 static mStatus
handle_regrecord_request(request_state
*rstate
);
848 static void regrecord_callback(mDNS
*const m
, AuthRecord
* rr
, mStatus result
);
849 static void connected_registration_termination(void *context
);
850 static void handle_reconfirm_request(request_state
*rstate
);
851 static AuthRecord
*read_rr_from_ipc_msg(char *msgbuf
, int ttl
, int validate_flags
);
852 static mStatus
handle_removerecord_request(request_state
*rstate
);
853 static void reset_connected_rstate(request_state
*rstate
);
854 static int deliver_error(request_state
*rstate
, mStatus err
);
855 static int deliver_async_error(request_state
*rs
, reply_op_t op
, mStatus err
);
856 static transfer_state
send_undelivered_error(request_state
*rs
);
857 static reply_state
*create_reply(reply_op_t op
, size_t datalen
, request_state
*request
);
858 static void update_callback(mDNS
*const m
, AuthRecord
*const rr
, RData
*oldrd
);
859 static void my_perror(char *errmsg
);
860 static void unlink_request(request_state
*rs
);
861 static void resolve_result_callback(mDNS
*const m
, DNSQuestion
*question
, const ResourceRecord
*const answer
, mDNSBool AddRecord
);
862 static void resolve_termination_callback(void *context
);
863 static int validate_message(request_state
*rstate
);
864 static mStatus
remove_extra(request_state
*rstate
, service_instance
*serv
);
865 static mStatus
remove_record(request_state
*rstate
);
866 static void free_service_instance(service_instance
*srv
);
867 static uint32_t dnssd_htonl(uint32_t l
);
868 static void handle_setdomain_request(request_state
*rstate
);
870 // initialization, setup/teardown functions
872 // If a platform specifies its own PID file name, we use that
874 #define PID_FILE "/var/run/mDNSResponder.pid"
877 mDNSlocal
void LogClientInfo(request_state
*req
)
879 void *t
= req
->termination_context
;
882 if (req
->terminate
== regservice_termination_callback
)
884 service_instance
*ptr
;
885 for (ptr
= ((service_info
*)t
)->instances
; ptr
; ptr
= ptr
->next
)
886 LogMsgNoIdent("%3d: DNSServiceRegister %##s %u", req
->sd
, ptr
->srs
.RR_SRV
.resrec
.name
->c
, SRS_PORT(&ptr
->srs
));
888 else if (req
->terminate
== browse_termination_callback
)
891 for (blist
= req
->browser_info
->browsers
; blist
; blist
= blist
->next
)
892 LogMsgNoIdent("%3d: DNSServiceBrowse %##s", req
->sd
, blist
->q
.qname
.c
);
894 else if (req
->terminate
== resolve_termination_callback
)
895 LogMsgNoIdent("%3d: DNSServiceResolve %##s", req
->sd
, ((resolve_termination_t
*)t
)->qsrv
.qname
.c
);
896 else if (req
->terminate
== question_termination_callback
)
897 LogMsgNoIdent("%3d: DNSServiceQueryRecord %##s", req
->sd
, ((DNSQuestion
*) t
)->qname
.c
);
898 else if (req
->terminate
== enum_termination_callback
)
899 LogMsgNoIdent("%3d: DNSServiceEnumerateDomains %##s", req
->sd
, ((enum_termination_t
*) t
)->all
->question
.qname
.c
);
903 static void FatalError(char *errmsg
)
905 LogMsg("%s: %s", errmsg
, dnssd_strerror(dnssd_errno()));
906 *(long*)0 = 0; // On OS X abort() doesn't generate a crash log, but writing to zero does
907 abort(); // On platforms where writing to zero doesn't generate an exception, abort instead
910 int udsserver_init(void)
912 dnssd_sockaddr_t laddr
;
918 // If a particular platform wants to opt out of having a PID file, define PID_FILE to be ""
921 FILE *fp
= fopen(PID_FILE
, "w");
924 fprintf(fp
, "%d\n", getpid());
929 if ((listenfd
= socket(AF_DNSSD
, SOCK_STREAM
, 0)) == dnssd_InvalidSocket
)
931 my_perror("ERROR: socket(AF_DNSSD, SOCK_STREAM, 0); failed");
935 bzero(&laddr
, sizeof(laddr
));
937 #if defined(USE_TCP_LOOPBACK)
939 laddr
.sin_family
= AF_INET
;
940 laddr
.sin_port
= htons(MDNS_TCP_SERVERPORT
);
941 laddr
.sin_addr
.s_addr
= inet_addr(MDNS_TCP_SERVERADDR
);
942 ret
= bind(listenfd
, (struct sockaddr
*) &laddr
, sizeof(laddr
));
945 my_perror("ERROR: bind(listenfd, (struct sockaddr *) &laddr, sizeof(laddr)); failed");
951 mode_t mask
= umask(0);
952 unlink(MDNS_UDS_SERVERPATH
); //OK if this fails
953 laddr
.sun_family
= AF_LOCAL
;
954 #ifndef NOT_HAVE_SA_LEN
955 // According to Stevens (section 3.2), there is no portable way to
956 // determine whether sa_len is defined on a particular platform.
957 laddr
.sun_len
= sizeof(struct sockaddr_un
);
959 strcpy(laddr
.sun_path
, MDNS_UDS_SERVERPATH
);
960 ret
= bind(listenfd
, (struct sockaddr
*) &laddr
, sizeof(laddr
));
964 my_perror("ERROR: bind(listenfd, (struct sockaddr *) &laddr, sizeof(laddr)); failed");
972 // SEH: do we even need to do this on windows? this socket
973 // will be given to WSAEventSelect which will automatically
974 // set it to non-blocking
976 if (ioctlsocket(listenfd
, FIONBIO
, &opt
) != 0)
978 if (fcntl(listenfd
, F_SETFL
, O_NONBLOCK
) != 0)
981 my_perror("ERROR: could not set listen socket to non-blocking mode");
985 if (listen(listenfd
, LISTENQ
) != 0)
987 my_perror("ERROR: could not listen on listen socket");
991 if (mStatus_NoError
!= udsSupportAddFDToEventLoop(listenfd
, connect_callback
, (void *) NULL
))
993 my_perror("ERROR: could not add listen socket to event loop");
997 #if !defined(PLATFORM_NO_RLIMIT)
999 // Set maximum number of open file descriptors
1000 #define MIN_OPENFILES 10240
1001 struct rlimit maxfds
, newfds
;
1003 // Due to bugs in OS X (<rdar://problem/2941095>, <rdar://problem/3342704>, <rdar://problem/3839173>)
1004 // you have to get and set rlimits once before getrlimit will return sensible values
1005 if (getrlimit(RLIMIT_NOFILE
, &maxfds
) < 0) { my_perror("ERROR: Unable to get file descriptor limit"); return 0; }
1006 if (setrlimit(RLIMIT_NOFILE
, &maxfds
) < 0) my_perror("ERROR: Unable to set maximum file descriptor limit");
1008 if (getrlimit(RLIMIT_NOFILE
, &maxfds
) < 0) { my_perror("ERROR: Unable to get file descriptor limit"); return 0; }
1009 newfds
.rlim_max
= (maxfds
.rlim_max
> MIN_OPENFILES
) ? maxfds
.rlim_max
: MIN_OPENFILES
;
1010 newfds
.rlim_cur
= (maxfds
.rlim_cur
> MIN_OPENFILES
) ? maxfds
.rlim_cur
: MIN_OPENFILES
;
1011 if (newfds
.rlim_max
!= maxfds
.rlim_max
|| newfds
.rlim_cur
!= maxfds
.rlim_cur
)
1012 if (setrlimit(RLIMIT_NOFILE
, &newfds
) < 0) my_perror("ERROR: Unable to set maximum file descriptor limit");
1014 if (getrlimit(RLIMIT_NOFILE
, &maxfds
) < 0) { my_perror("ERROR: Unable to get file descriptor limit"); return 0; }
1015 debugf("maxfds.rlim_max %d", (long)maxfds
.rlim_max
);
1016 debugf("maxfds.rlim_cur %d", (long)maxfds
.rlim_cur
);
1024 my_perror("ERROR: udsserver_init");
1028 int udsserver_exit(void)
1030 dnssd_close(listenfd
);
1032 #if !defined(USE_TCP_LOOPBACK)
1033 // Currently, we're unable to remove /var/run/mdnsd because we've changed to userid "nobody"
1034 // to give up unnecessary privilege, but we need to be root to remove this Unix Domain Socket.
1035 // It would be nice if we could find a solution to this problem
1036 if (unlink(MDNS_UDS_SERVERPATH
))
1037 debugf("Unable to remove %s", MDNS_UDS_SERVERPATH
);
1043 mDNSs32
udsserver_idle(mDNSs32 nextevent
)
1045 request_state
*req
= all_requests
, *tmp
, *prev
= NULL
;
1047 transfer_state result
;
1048 mDNSs32 now
= mDNS_TimeNow(&mDNSStorage
);
1052 result
= t_uninitialized
;
1054 result
= send_undelivered_error(req
);
1055 if (result
!= t_error
&& result
!= t_morecoming
&& // don't try to send msg if send_error failed
1056 (req
->ts
== t_complete
|| req
->ts
== t_morecoming
))
1060 if (req
->replies
->next
) req
->replies
->rhdr
->flags
|= dnssd_htonl(kDNSServiceFlagsMoreComing
);
1061 result
= send_msg(req
->replies
);
1062 if (result
== t_complete
)
1064 fptr
= req
->replies
;
1065 req
->replies
= req
->replies
->next
;
1066 freeL("udsserver_idle", fptr
);
1067 req
->time_blocked
= 0; // reset failure counter after successful send
1069 else if (result
== t_terminated
|| result
== t_error
)
1074 else if (result
== t_morecoming
) break; // client's queues are full, move to next
1077 if (result
== t_morecoming
)
1079 if (!req
->time_blocked
) req
->time_blocked
= now
;
1080 debugf("udsserver_idle: client has been blocked for %ld seconds", (now
- req
->time_blocked
) / mDNSPlatformOneSecond
);
1081 if (now
- req
->time_blocked
>= MAX_TIME_BLOCKED
)
1083 LogMsg("Could not write data to client %d after %ld seconds - aborting connection", req
->sd
, MAX_TIME_BLOCKED
/ mDNSPlatformOneSecond
);
1086 result
= t_terminated
;
1088 else if (nextevent
- now
> mDNSPlatformOneSecond
) nextevent
= now
+ mDNSPlatformOneSecond
; // try again in a second
1090 if (result
== t_terminated
|| result
== t_error
)
1091 //since we're already doing a list traversal, we unlink the request manunally instead of calling unlink_request()
1094 if (prev
) prev
->next
= req
->next
;
1095 if (req
== all_requests
) all_requests
= all_requests
->next
;
1097 freeL("udsserver_idle", tmp
);
1108 void udsserver_info(mDNS
*const m
)
1110 mDNSs32 now
= mDNS_TimeNow(m
);
1111 mDNSu32 CacheUsed
= 0, CacheActive
= 0;
1117 LogMsgNoIdent("Timenow 0x%08lX (%ld)", (mDNSu32
)now
, now
);
1119 for (slot
= 0; slot
< CACHE_HASH_SLOTS
; slot
++)
1120 for(cg
= m
->rrcache_hash
[slot
]; cg
; cg
=cg
->next
)
1122 CacheUsed
++; // Count one cache entity for the CacheGroup object
1123 for (rr
= cg
->members
; rr
; rr
=rr
->next
)
1125 mDNSs32 remain
= rr
->resrec
.rroriginalttl
- (now
- rr
->TimeRcvd
) / mDNSPlatformOneSecond
;
1127 if (rr
->CRActiveQuestion
) CacheActive
++;
1128 LogMsgNoIdent("%s%6ld %s%-6s%-6s%s",
1129 rr
->CRActiveQuestion
? "*" : " ", remain
,
1130 (rr
->resrec
.RecordType
& kDNSRecordTypePacketUniqueMask
) ? "-" : " ", DNSTypeName(rr
->resrec
.rrtype
),
1131 ((NetworkInterfaceInfo
*)rr
->resrec
.InterfaceID
)->ifname
, CRDisplayString(m
, rr
));
1132 usleep(1000); // Limit rate a little so we don't flood syslog too fast
1136 if (m
->rrcache_totalused
!= CacheUsed
)
1137 LogMsgNoIdent("Cache use mismatch: rrcache_totalused is %lu, true count %lu", m
->rrcache_totalused
, CacheUsed
);
1138 if (m
->rrcache_active
!= CacheActive
)
1139 LogMsgNoIdent("Cache use mismatch: rrcache_active is %lu, true count %lu", m
->rrcache_active
, CacheActive
);
1140 LogMsgNoIdent("Cache currently contains %lu records; %lu referenced by active questions", CacheUsed
, CacheActive
);
1142 for (req
= all_requests
; req
; req
=req
->next
)
1145 now
= mDNS_TimeNow(m
);
1146 LogMsgNoIdent("Timenow 0x%08lX (%ld)", (mDNSu32
)now
, now
);
1149 static void rename_service(service_instance
*srv
)
1151 if (srv
->autoname
&& !SameDomainLabel(srv
->name
.c
, gmDNS
->nicelabel
.c
))
1153 srv
->rename_on_memfree
= 1;
1154 if (mDNS_DeregisterService(gmDNS
, &srv
->srs
)) // If service deregistered already, we can re-register immediately
1155 regservice_callback(gmDNS
, &srv
->srs
, mStatus_MemFree
);
1159 void udsserver_handle_configchange(void)
1164 for (req
= all_requests
; req
; req
= req
->next
)
1166 if (req
->service_registration
)
1168 service_instance
*ptr
;
1169 for (ptr
= req
->service_registration
->instances
; ptr
; ptr
= ptr
->next
)
1170 rename_service(ptr
);
1175 static void connect_callback(void *info
)
1178 dnssd_socklen_t len
;
1179 unsigned long optval
;
1180 dnssd_sockaddr_t cliaddr
;
1181 request_state
*rstate
;
1182 (void)info
; // Unused
1184 len
= (dnssd_socklen_t
) sizeof(cliaddr
);
1186 sd
= accept(listenfd
, (struct sockaddr
*) &cliaddr
, &len
);
1188 if (sd
== dnssd_InvalidSocket
)
1190 if (dnssd_errno() == dnssd_EWOULDBLOCK
) return;
1191 my_perror("ERROR: accept");
1197 // Some environments (e.g. OS X) support turning off SIGPIPE for a socket
1198 if (setsockopt(sd
, SOL_SOCKET
, SO_NOSIGPIPE
, &optval
, sizeof(optval
)) < 0)
1200 my_perror("ERROR: setsockopt - SO_NOSIGPIPE - aborting client");
1207 if (ioctlsocket(sd
, FIONBIO
, &optval
) != 0)
1209 if (fcntl(sd
, F_SETFL
, O_NONBLOCK
) != 0)
1212 my_perror("ERROR: fcntl(sd, F_SETFL, O_NONBLOCK) - aborting client");
1217 // allocate a request_state struct that will live with the socket
1218 rstate
= mallocL("connect_callback", sizeof(request_state
));
1219 if (!rstate
) FatalError("ERROR: malloc");
1220 bzero(rstate
, sizeof(request_state
));
1221 rstate
->ts
= t_morecoming
;
1224 LogOperation("%3d: Adding FD", rstate
->sd
);
1225 if ( mStatus_NoError
!= udsSupportAddFDToEventLoop( sd
, request_callback
, rstate
))
1227 rstate
->next
= all_requests
;
1228 all_requests
= rstate
;
1232 static void request_callback(void *info
)
1234 request_state
*rstate
= info
;
1235 transfer_state result
;
1236 dnssd_sockaddr_t cliaddr
;
1237 int dedicated_error_socket
;
1242 result
= read_msg(rstate
);
1243 if (result
== t_morecoming
)
1247 if (result
== t_terminated
)
1249 abort_request(rstate
);
1250 unlink_request(rstate
);
1253 if (result
== t_error
)
1255 abort_request(rstate
);
1256 unlink_request(rstate
);
1260 if (rstate
->hdr
.version
!= VERSION
)
1262 LogMsg("ERROR: client incompatible with daemon (client version = %d, "
1263 "daemon version = %d)\n", rstate
->hdr
.version
, VERSION
);
1264 abort_request(rstate
);
1265 unlink_request(rstate
);
1269 if (validate_message(rstate
) < 0)
1271 // note that we cannot deliver an error message if validation fails, since the path to the error socket
1272 // may be contained in the (invalid) message body for some message types
1273 abort_request(rstate
);
1274 unlink_request(rstate
);
1275 LogMsg("Invalid message sent by client - may indicate a malicious program running on this machine!");
1279 // check if client wants silent operation
1280 if (rstate
->hdr
.flags
& IPC_FLAGS_NOREPLY
) rstate
->no_reply
= 1;
1282 dedicated_error_socket
= (rstate
->hdr
.op
== reg_record_request
|| rstate
->hdr
.op
== add_record_request
||
1283 rstate
->hdr
.op
== update_record_request
|| rstate
->hdr
.op
== remove_record_request
);
1285 if (((rstate
->hdr
.flags
& IPC_FLAGS_REUSE_SOCKET
) == 0) != dedicated_error_socket
)
1286 LogMsg("WARNING: client request %d with incorrect flags setting 0x%X", rstate
->hdr
.op
, rstate
->hdr
.flags
);
1288 // check if primary socket is to be used for synchronous errors, else open new socket
1289 if (dedicated_error_socket
)
1293 dnssd_sock_t errfd
= socket(AF_DNSSD
, SOCK_STREAM
, 0);
1294 if (errfd
== dnssd_InvalidSocket
)
1296 my_perror("ERROR: socket");
1297 abort_request(rstate
);
1298 unlink_request(rstate
);
1302 #if defined(USE_TCP_LOOPBACK)
1305 port
.b
[0] = rstate
->msgdata
[0];
1306 port
.b
[1] = rstate
->msgdata
[1];
1307 rstate
->msgdata
+= 2;
1308 cliaddr
.sin_family
= AF_INET
;
1309 cliaddr
.sin_port
= port
.NotAnInteger
;
1310 cliaddr
.sin_addr
.s_addr
= inet_addr(MDNS_TCP_SERVERADDR
);
1314 char ctrl_path
[MAX_CTLPATH
];
1315 get_string(&rstate
->msgdata
, ctrl_path
, 256); // path is first element in message buffer
1316 bzero(&cliaddr
, sizeof(cliaddr
));
1317 cliaddr
.sun_family
= AF_LOCAL
;
1318 strcpy(cliaddr
.sun_path
, ctrl_path
);
1321 if (connect(errfd
, (struct sockaddr
*)&cliaddr
, sizeof(cliaddr
)) < 0)
1323 my_perror("ERROR: connect");
1324 abort_request(rstate
);
1325 unlink_request(rstate
);
1329 if (ioctlsocket(errfd
, FIONBIO
, &opt
) != 0)
1331 if (fcntl(errfd
, F_SETFL
, O_NONBLOCK
) != 0)
1334 my_perror("ERROR: could not set control socket to non-blocking mode");
1335 abort_request(rstate
);
1336 unlink_request(rstate
);
1340 switch(rstate
->hdr
.op
)
1342 case reg_record_request
: err
= handle_regrecord_request (rstate
); break;
1343 case add_record_request
: err
= handle_add_request (rstate
); break;
1344 case update_record_request
: err
= handle_update_request (rstate
); break;
1345 case remove_record_request
: err
= handle_removerecord_request(rstate
); break;
1346 default: LogMsg("%3d: ERROR: udsserver_recv_request - unsupported request type: %d", rstate
->sd
, rstate
->hdr
.op
);
1349 err
= dnssd_htonl(err
);
1350 nwritten
= send(errfd
, (dnssd_sockbuf_t
) &err
, sizeof(err
), 0);
1351 // On a freshly-created Unix Domain Socket, the kernel should *never* fail to buffer a four-byte write for us.
1352 // If not, we don't attempt to handle this failure, but we do log it.
1353 if (nwritten
< (int)sizeof(err
))
1354 LogMsg("ERROR: failed to write error response back to caller: %d %d %s",
1355 nwritten
, dnssd_errno(), dnssd_strerror(dnssd_errno()));
1357 reset_connected_rstate(rstate
); // Reset ready to accept the next request on this pipe
1361 switch(rstate
->hdr
.op
)
1363 case resolve_request
: handle_resolve_request (rstate
); break;
1364 case query_request
: handle_query_request (rstate
); break;
1365 case browse_request
: handle_browse_request (rstate
); break;
1366 case reg_service_request
: handle_regservice_request(rstate
); break;
1367 case enumeration_request
: handle_enum_request (rstate
); break;
1368 case reconfirm_record_request
: handle_reconfirm_request (rstate
); break;
1369 case setdomain_request
: handle_setdomain_request (rstate
); break;
1370 default: LogMsg("%3d: ERROR: udsserver_recv_request - unsupported request type: %d", rstate
->sd
, rstate
->hdr
.op
);
1375 // mDNS operation functions. Each operation has 3 associated functions - a request handler that parses
1376 // the client's request and makes the appropriate mDNSCore call, a result handler (passed as a callback
1377 // to the mDNSCore routine) that sends results back to the client, and a termination routine that aborts
1378 // the mDNSCore operation if the client dies or closes its socket.
1380 // query and resolve calls have separate request handlers that parse the arguments from the client and
1381 // massage the name parameters appropriately, but the rest of the operations (making the query call,
1382 // delivering the result to the client, and termination) are identical.
1384 static void handle_query_request(request_state
*rstate
)
1386 DNSServiceFlags flags
;
1389 uint16_t rrtype
, rrclass
;
1392 mDNSInterfaceID InterfaceID
;
1395 if (rstate
->ts
!= t_complete
)
1397 LogMsg("ERROR: handle_query_request - transfer state != t_complete");
1400 ptr
= rstate
->msgdata
;
1403 LogMsg("ERROR: handle_query_request - NULL msgdata");
1407 flags
= get_flags(&ptr
);
1408 ifi
= get_long(&ptr
);
1409 if (get_string(&ptr
, name
, 256) < 0) goto bad_param
;
1410 rrtype
= get_short(&ptr
);
1411 rrclass
= get_short(&ptr
);
1412 InterfaceID
= mDNSPlatformInterfaceIDfromInterfaceIndex(gmDNS
, ifi
);
1413 if (ifi
&& !InterfaceID
) goto bad_param
;
1415 q
= mallocL("DNSQuestion", sizeof(DNSQuestion
));
1416 if (!q
) FatalError("ERROR: handle_query - malloc");
1417 bzero(q
, sizeof(DNSQuestion
));
1419 q
->InterfaceID
= InterfaceID
;
1420 q
->Target
= zeroAddr
;
1421 if (!MakeDomainNameFromDNSNameString(&q
->qname
, name
)) { freeL("DNSQuestion", q
); goto bad_param
; }
1423 q
->qclass
= rrclass
;
1424 q
->LongLived
= (flags
& kDNSServiceFlagsLongLivedQuery
) != 0;
1425 q
->ExpectUnique
= mDNSfalse
;
1426 q
->ForceMCast
= (flags
& kDNSServiceFlagsForceMulticast
) != 0;
1427 q
->QuestionCallback
= question_result_callback
;
1428 q
->QuestionContext
= rstate
;
1430 rstate
->termination_context
= q
;
1431 rstate
->terminate
= question_termination_callback
;
1433 LogOperation("%3d: DNSServiceQueryRecord(%##s, %s) START", rstate
->sd
, q
->qname
.c
, DNSTypeName(q
->qtype
));
1434 result
= mDNS_StartQuery(gmDNS
, q
);
1435 if (result
!= mStatus_NoError
) LogMsg("ERROR: mDNS_StartQuery: %d", (int)result
);
1437 if (result
) rstate
->terminate
= NULL
;
1438 if (deliver_error(rstate
, result
) < 0) goto error
;
1442 deliver_error(rstate
, mStatus_BadParamErr
);
1443 rstate
->terminate
= NULL
; // don't try to terminate insuccessful Core calls
1445 abort_request(rstate
);
1446 unlink_request(rstate
);
1450 static void handle_resolve_request(request_state
*rstate
)
1452 DNSServiceFlags flags
;
1453 uint32_t interfaceIndex
;
1454 mDNSInterfaceID InterfaceID
;
1455 char name
[256], regtype
[MAX_ESCAPED_DOMAIN_NAME
], domain
[MAX_ESCAPED_DOMAIN_NAME
];
1456 char *ptr
; // message data pointer
1458 resolve_termination_t
*term
;
1461 if (rstate
->ts
!= t_complete
)
1463 LogMsg("ERROR: handle_resolve_request - transfer state != t_complete");
1464 abort_request(rstate
);
1465 unlink_request(rstate
);
1469 // extract the data from the message
1470 ptr
= rstate
->msgdata
;
1473 LogMsg("ERROR: handle_resolve_request - NULL msgdata");
1474 abort_request(rstate
);
1475 unlink_request(rstate
);
1478 flags
= get_flags(&ptr
);
1479 interfaceIndex
= get_long(&ptr
);
1480 InterfaceID
= mDNSPlatformInterfaceIDfromInterfaceIndex(gmDNS
, interfaceIndex
);
1481 if (interfaceIndex
&& !InterfaceID
)
1482 { LogMsg("ERROR: handle_resolve_request - Couldn't find InterfaceID for interfaceIndex %d", interfaceIndex
); goto bad_param
; }
1483 if (get_string(&ptr
, name
, 256) < 0 ||
1484 get_string(&ptr
, regtype
, MAX_ESCAPED_DOMAIN_NAME
) < 0 ||
1485 get_string(&ptr
, domain
, MAX_ESCAPED_DOMAIN_NAME
) < 0)
1486 { LogMsg("ERROR: handle_resolve_request - Couldn't read name/regtype/domain"); goto bad_param
; }
1488 // free memory in rstate since we don't need it anymore
1489 freeL("handle_resolve_request", rstate
->msgbuf
);
1490 rstate
->msgbuf
= NULL
;
1492 if (build_domainname_from_strings(&fqdn
, name
, regtype
, domain
) < 0)
1493 { LogMsg("ERROR: handle_resolve_request - Couldn't build_domainname_from_strings “%s” “%s” “%s”", name
, regtype
, domain
); goto bad_param
; }
1495 // set up termination info
1496 term
= mallocL("handle_resolve_request", sizeof(resolve_termination_t
));
1497 bzero(term
, sizeof(*term
));
1498 if (!term
) FatalError("ERROR: malloc");
1501 term
->qsrv
.InterfaceID
= InterfaceID
;
1502 term
->qsrv
.Target
= zeroAddr
;
1503 memcpy(&term
->qsrv
.qname
, &fqdn
, MAX_DOMAIN_NAME
);
1504 term
->qsrv
.qtype
= kDNSType_SRV
;
1505 term
->qsrv
.qclass
= kDNSClass_IN
;
1506 term
->qsrv
.LongLived
= mDNSfalse
;
1507 term
->qsrv
.ExpectUnique
= mDNStrue
;
1508 term
->qsrv
.ForceMCast
= mDNSfalse
;
1509 term
->qsrv
.QuestionCallback
= resolve_result_callback
;
1510 term
->qsrv
.QuestionContext
= rstate
;
1512 term
->qtxt
.InterfaceID
= InterfaceID
;
1513 term
->qtxt
.Target
= zeroAddr
;
1514 memcpy(&term
->qtxt
.qname
, &fqdn
, MAX_DOMAIN_NAME
);
1515 term
->qtxt
.qtype
= kDNSType_TXT
;
1516 term
->qtxt
.qclass
= kDNSClass_IN
;
1517 term
->qtxt
.LongLived
= mDNSfalse
;
1518 term
->qtxt
.ExpectUnique
= mDNStrue
;
1519 term
->qtxt
.ForceMCast
= mDNSfalse
;
1520 term
->qtxt
.QuestionCallback
= resolve_result_callback
;
1521 term
->qtxt
.QuestionContext
= rstate
;
1523 term
->rstate
= rstate
;
1524 rstate
->termination_context
= term
;
1525 rstate
->terminate
= resolve_termination_callback
;
1527 // ask the questions
1528 LogOperation("%3d: DNSServiceResolve(%##s) START", rstate
->sd
, term
->qsrv
.qname
.c
);
1529 err
= mDNS_StartQuery(gmDNS
, &term
->qsrv
);
1530 if (!err
) err
= mDNS_StartQuery(gmDNS
, &term
->qtxt
);
1534 freeL("handle_resolve_request", term
);
1535 rstate
->terminate
= NULL
; // prevent abort_request() from invoking termination callback
1537 if (deliver_error(rstate
, err
) < 0 || err
)
1539 abort_request(rstate
);
1540 unlink_request(rstate
);
1545 deliver_error(rstate
, mStatus_BadParamErr
);
1546 abort_request(rstate
);
1547 unlink_request(rstate
);
1550 static void resolve_termination_callback(void *context
)
1552 resolve_termination_t
*term
= context
;
1557 LogMsg("ERROR: resolve_termination_callback: double termination");
1561 LogOperation("%3d: DNSServiceResolve(%##s) STOP", rs
->sd
, term
->qtxt
.qname
.c
);
1563 mDNS_StopQuery(gmDNS
, &term
->qtxt
);
1564 mDNS_StopQuery(gmDNS
, &term
->qsrv
);
1566 freeL("resolve_termination_callback", term
);
1567 rs
->termination_context
= NULL
;
1570 static void resolve_result_callback(mDNS
*const m
, DNSQuestion
*question
, const ResourceRecord
*const answer
, mDNSBool AddRecord
)
1573 char fullname
[MAX_ESCAPED_DOMAIN_NAME
], target
[MAX_ESCAPED_DOMAIN_NAME
];
1575 transfer_state result
;
1577 request_state
*rs
= question
->QuestionContext
;
1578 resolve_termination_t
*res
= rs
->termination_context
;
1581 LogOperation("%3d: DNSServiceResolve(%##s, %s) RESULT %s", rs
->sd
, question
->qname
.c
, DNSTypeName(question
->qtype
), RRDisplayString(m
, answer
));
1583 // This code used to do this trick of just keeping a copy of the pointer to
1584 // the answer record in the cache, but the unicast query code doesn't currently
1585 // put its answer records in the cache, so for now we can't do this.
1589 // if (answer->rrtype == kDNSType_TXT && res->txt == answer) res->txt = mDNSNULL;
1590 // if (answer->rrtype == kDNSType_SRV && res->srv == answer) res->srv = mDNSNULL;
1594 // if (answer->rrtype == kDNSType_TXT) res->txt = answer;
1595 // if (answer->rrtype == kDNSType_SRV) res->srv = answer;
1597 if (answer
->rrtype
== kDNSType_SRV
)
1599 AssignDomainName(&res
->target
, &answer
->rdata
->u
.srv
.target
);
1600 res
->port
= answer
->rdata
->u
.srv
.port
;
1601 res
->srv
= mDNStrue
;
1603 if (answer
->rrtype
== kDNSType_TXT
)
1605 if (answer
->rdlength
> AbsoluteMaxDNSMessageData
) return;
1606 res
->txtlen
= answer
->rdlength
;
1607 mDNSPlatformMemCopy(answer
->rdata
->u
.data
, res
->txtdata
, res
->txtlen
);
1608 res
->txt
= mDNStrue
;
1611 if (!res
->txt
|| !res
->srv
) return; // only deliver result to client if we have both answers
1613 ConvertDomainNameToCString(answer
->name
, fullname
);
1614 ConvertDomainNameToCString(&res
->target
, target
);
1616 // calculate reply length
1617 len
+= sizeof(DNSServiceFlags
);
1618 len
+= sizeof(uint32_t); // interface index
1619 len
+= sizeof(DNSServiceErrorType
);
1620 len
+= strlen(fullname
) + 1;
1621 len
+= strlen(target
) + 1;
1622 len
+= 2 * sizeof(uint16_t); // port, txtLen
1625 // allocate/init reply header
1626 rep
= create_reply(resolve_reply
, len
, rs
);
1627 rep
->rhdr
->flags
= dnssd_htonl(0);
1628 rep
->rhdr
->ifi
= dnssd_htonl(mDNSPlatformInterfaceIndexfromInterfaceID(gmDNS
, answer
->InterfaceID
));
1629 rep
->rhdr
->error
= dnssd_htonl(kDNSServiceErr_NoError
);
1633 // write reply data to message
1634 put_string(fullname
, &data
);
1635 put_string(target
, &data
);
1636 *data
++ = res
->port
.b
[0];
1637 *data
++ = res
->port
.b
[1];
1638 put_short(res
->txtlen
, &data
);
1639 put_rdata(res
->txtlen
, res
->txtdata
, &data
);
1641 result
= send_msg(rep
);
1642 if (result
== t_error
|| result
== t_terminated
)
1646 freeL("resolve_result_callback", rep
);
1648 else if (result
== t_complete
) freeL("resolve_result_callback", rep
);
1649 else append_reply(rs
, rep
);
1652 // what gets called when a resolve is completed and we need to send the data back to the client
1653 static void question_result_callback(mDNS
*const m
, DNSQuestion
*question
, const ResourceRecord
*const answer
, mDNSBool AddRecord
)
1656 char name
[MAX_ESCAPED_DOMAIN_NAME
];
1657 request_state
*req
= question
->QuestionContext
;
1662 LogOperation("%3d: DNSServiceQueryRecord(%##s, %s) RESULT %s", req
->sd
, question
->qname
.c
, DNSTypeName(question
->qtype
), RRDisplayString(m
, answer
));
1663 //mDNS_StopQuery(m, question);
1665 // calculate reply data length
1666 len
= sizeof(DNSServiceFlags
);
1667 len
+= 2 * sizeof(uint32_t); // if index + ttl
1668 len
+= sizeof(DNSServiceErrorType
);
1669 len
+= 3 * sizeof(uint16_t); // type, class, rdlen
1670 len
+= answer
->rdlength
;
1671 ConvertDomainNameToCString(answer
->name
, name
);
1672 len
+= strlen(name
) + 1;
1674 rep
= create_reply(query_reply
, len
, req
);
1676 rep
->rhdr
->flags
= dnssd_htonl(AddRecord
? kDNSServiceFlagsAdd
: 0);
1677 rep
->rhdr
->ifi
= dnssd_htonl(mDNSPlatformInterfaceIndexfromInterfaceID(gmDNS
, answer
->InterfaceID
));
1678 rep
->rhdr
->error
= dnssd_htonl(kDNSServiceErr_NoError
);
1682 put_string(name
, &data
);
1683 put_short(answer
->rrtype
, &data
);
1684 put_short(answer
->rrclass
, &data
);
1685 put_short(answer
->rdlength
, &data
);
1686 put_rdata(answer
->rdlength
, answer
->rdata
->u
.data
, &data
);
1687 put_long(AddRecord
? answer
->rroriginalttl
: 0, &data
);
1689 append_reply(req
, rep
);
1693 static void question_termination_callback(void *context
)
1695 DNSQuestion
*q
= context
;
1696 LogOperation("%3d: DNSServiceQueryRecord(%##s, %s) STOP", ((request_state
*)q
->QuestionContext
)->sd
, q
->qname
.c
, DNSTypeName(q
->qtype
));
1697 mDNS_StopQuery(gmDNS
, q
); // no need to error check
1698 freeL("question_termination_callback", q
);
1701 // If there's a comma followed by another character,
1702 // FindFirstSubType overwrites the comma with a nul and returns the pointer to the next character.
1703 // Otherwise, it returns a pointer to the final nul at the end of the string
1704 static char *FindFirstSubType(char *p
)
1708 if (p
[0] == '\\' && p
[1]) p
+= 2;
1709 else if (p
[0] == ',' && p
[1]) { *p
++ = 0; return(p
); }
1715 // If there's a comma followed by another character,
1716 // FindNextSubType overwrites the comma with a nul and returns the pointer to the next character.
1717 // If it finds an illegal unescaped dot in the subtype name, it returns mDNSNULL
1718 // Otherwise, it returns a pointer to the final nul at the end of the string
1719 static char *FindNextSubType(char *p
)
1723 if (p
[0] == '\\' && p
[1]) // If escape character
1724 p
+= 2; // ignore following character
1725 else if (p
[0] == ',') // If we found a comma
1730 else if (p
[0] == '.')
1737 // Returns -1 if illegal subtype found
1738 mDNSexport mDNSs32
ChopSubTypes(char *regtype
)
1740 mDNSs32 NumSubTypes
= 0;
1741 char *stp
= FindFirstSubType(regtype
);
1742 while (stp
&& *stp
) // If we found a comma...
1744 if (*stp
== ',') return(-1);
1746 stp
= FindNextSubType(stp
);
1748 if (!stp
) return(-1);
1749 return(NumSubTypes
);
1752 mDNSexport AuthRecord
*AllocateSubTypes(mDNSs32 NumSubTypes
, char *p
)
1754 AuthRecord
*st
= mDNSNULL
;
1758 st
= mallocL("ServiceSubTypes", NumSubTypes
* sizeof(AuthRecord
));
1759 if (!st
) return(mDNSNULL
);
1760 for (i
= 0; i
< NumSubTypes
; i
++)
1762 mDNS_SetupResourceRecord(&st
[i
], mDNSNULL
, mDNSInterface_Any
, kDNSQType_ANY
, kStandardTTL
, 0, mDNSNULL
, mDNSNULL
);
1765 if (!MakeDomainNameFromDNSNameString(st
[i
].resrec
.name
, p
))
1766 { freeL("ServiceSubTypes", st
); return(mDNSNULL
); }
1772 #ifdef _HAVE_SETDOMAIN_SUPPORT_
1773 static void free_defdomain(mDNS
*const m
, AuthRecord
*const rr
, mStatus result
)
1776 if (result
== mStatus_MemFree
) free(rr
->RecordContext
); // context is the enclosing list structure
1780 static void handle_setdomain_request(request_state
*request
)
1782 mStatus err
= mStatus_NoError
;
1784 char domainstr
[MAX_ESCAPED_DOMAIN_NAME
];
1786 DNSServiceFlags flags
;
1787 #ifdef _HAVE_SETDOMAIN_SUPPORT_
1792 if (request
->ts
!= t_complete
)
1794 LogMsg("ERROR: handle_setdomain_request - transfer state != t_complete");
1795 abort_request(request
);
1796 unlink_request(request
);
1800 // extract flags/domain from message
1801 ptr
= request
->msgdata
;
1802 flags
= get_flags(&ptr
);
1803 if (get_string(&ptr
, domainstr
, MAX_ESCAPED_DOMAIN_NAME
) < 0 ||
1804 !MakeDomainNameFromDNSNameString(&domain
, domainstr
))
1805 { err
= mStatus_BadParamErr
; goto end
; }
1807 freeL("handle_setdomain_request", request
->msgbuf
);
1808 request
->msgbuf
= NULL
;
1810 debugf("%3d: DNSServiceSetDefaultDomainForUser(%##s)", request
->sd
, domain
.c
);
1812 #ifdef _HAVE_SETDOMAIN_SUPPORT_
1813 // this functionality currently only used for Apple-specific configuration, so we don't burned other platforms by mandating
1814 // the existence of this socket option
1815 xuclen
= sizeof(xuc
);
1816 if (getsockopt(request
->sd
, 0, LOCAL_PEERCRED
, &xuc
, &xuclen
))
1817 { my_perror("ERROR: getsockopt, LOCAL_PEERCRED"); err
= mStatus_UnknownErr
; goto end
; }
1818 if (xuc
.cr_version
!= XUCRED_VERSION
) { LogMsg("getsockopt, LOCAL_PEERCRED - bad version"); err
= mStatus_UnknownErr
; goto end
; }
1819 LogMsg("Default domain %s %s for UID %d", domainstr
, flags
& kDNSServiceFlagsAdd
? "set" : "removed", xuc
.cr_uid
);
1821 if (flags
& kDNSServiceFlagsAdd
)
1823 // register a local-only PRT record
1824 default_browse_list_t
*newelem
= malloc(sizeof(default_browse_list_t
));
1825 if (!newelem
) { LogMsg("ERROR: malloc"); err
= mStatus_NoMemoryErr
; goto end
; }
1826 mDNS_SetupResourceRecord(&newelem
->ptr_rec
, mDNSNULL
, mDNSInterface_LocalOnly
, kDNSType_PTR
, 7200, kDNSRecordTypeShared
, free_defdomain
, newelem
);
1827 MakeDomainNameFromDNSNameString(&newelem
->ptr_rec
.resrec
.name
, mDNS_DomainTypeNames
[mDNS_DomainTypeBrowseDefault
]);
1828 AppendDNSNameString (&newelem
->ptr_rec
.resrec
.name
, "local");
1829 AssignDomainName(&newelem
->ptr_rec
.resrec
.rdata
->u
.name
, &domain
);
1830 newelem
->uid
= xuc
.cr_uid
;
1831 err
= mDNS_Register(gmDNS
, &newelem
->ptr_rec
);
1832 if (err
) free(newelem
);
1836 newelem
->next
= default_browse_list
;
1837 default_browse_list
= newelem
;
1843 // remove - find in list, deregister
1844 default_browse_list_t
*ptr
= default_browse_list
, *prev
= NULL
;
1847 if (SameDomainName(&ptr
->ptr_rec
.resrec
.rdata
->u
.name
, &domain
))
1849 if (prev
) prev
->next
= ptr
->next
;
1850 else default_browse_list
= ptr
->next
;
1851 err
= mDNS_Deregister(gmDNS
, &ptr
->ptr_rec
);
1857 if (!ptr
) { LogMsg("Attempt to remove nonexistent domain %s for UID %d", domainstr
, xuc
.cr_uid
); err
= mStatus_Invalid
; }
1860 err
= mStatus_NoError
;
1861 #endif // _HAVE_SETDOMAIN_SUPPORT_
1864 deliver_error(request
, err
);
1865 abort_request(request
);
1866 unlink_request(request
);
1869 static mStatus
add_domain_to_browser(browser_info_t
*info
, const domainname
*d
)
1874 for (p
= info
->browsers
; p
; p
= p
->next
)
1876 if (SameDomainName(&p
->domain
, d
))
1877 { debugf("add_domain_to_browser - attempt to add domain %##d already in list", d
->c
); return mStatus_AlreadyRegistered
; }
1880 b
= mallocL("browser_t", sizeof(*b
));
1881 if (!b
) return mStatus_NoMemoryErr
;
1882 AssignDomainName(&b
->domain
, d
);
1883 err
= mDNS_StartBrowse(gmDNS
, &b
->q
, &info
->regtype
, d
, info
->interface_id
, info
->ForceMCast
, browse_result_callback
, info
->rstate
);
1886 LogMsg("mDNS_StartBrowse returned %d for type %##s domain %##s", err
, info
->regtype
.c
, d
->c
);
1887 freeL("browser_t", b
);
1891 b
->next
= info
->browsers
;
1897 static void handle_browse_request(request_state
*request
)
1899 DNSServiceFlags flags
;
1900 uint32_t interfaceIndex
;
1901 mDNSInterfaceID InterfaceID
;
1902 char regtype
[MAX_ESCAPED_DOMAIN_NAME
], domain
[MAX_ESCAPED_DOMAIN_NAME
];
1903 domainname typedn
, d
, temp
;
1904 mDNSs32 NumSubTypes
;
1906 mStatus err
= mStatus_NoError
;
1907 DNameListElem
*search_domain_list
, *sdom
;
1908 browser_info_t
*info
= NULL
;
1910 if (request
->ts
!= t_complete
)
1912 LogMsg("ERROR: handle_browse_request - transfer state != t_complete");
1913 abort_request(request
);
1914 unlink_request(request
);
1918 // extract data from message
1919 ptr
= request
->msgdata
;
1920 flags
= get_flags(&ptr
);
1921 interfaceIndex
= get_long(&ptr
);
1922 if (get_string(&ptr
, regtype
, MAX_ESCAPED_DOMAIN_NAME
) < 0 ||
1923 get_string(&ptr
, domain
, MAX_ESCAPED_DOMAIN_NAME
) < 0)
1924 { err
= mStatus_BadParamErr
; goto error
; }
1925 freeL("handle_browse_request", request
->msgbuf
);
1926 request
->msgbuf
= NULL
;
1928 InterfaceID
= mDNSPlatformInterfaceIDfromInterfaceIndex(gmDNS
, interfaceIndex
);
1929 if (interfaceIndex
&& !InterfaceID
) { err
= mStatus_BadParamErr
; goto error
; }
1932 NumSubTypes
= ChopSubTypes(regtype
); // Note: Modifies regtype string to remove trailing subtypes
1933 if (NumSubTypes
< 0 || NumSubTypes
> 1) { err
= mStatus_BadParamErr
; goto error
; }
1934 if (NumSubTypes
== 1 && !AppendDNSNameString(&typedn
, regtype
+ strlen(regtype
) + 1))
1935 { err
= mStatus_BadParamErr
; goto error
; }
1937 if (!regtype
[0] || !AppendDNSNameString(&typedn
, regtype
)) { err
= mStatus_BadParamErr
; goto error
; }
1939 if (!MakeDomainNameFromDNSNameString(&temp
, regtype
)) { err
= mStatus_BadParamErr
; goto error
; }
1940 if (temp
.c
[0] > 15 && domain
[0] == 0) strcpy(domain
, "local."); // For over-long service types, we only allow domain "local"
1942 // allocate and set up browser info
1943 info
= mallocL("browser_info_t", sizeof(*info
));
1944 if (!info
) { err
= mStatus_NoMemoryErr
; goto error
; }
1946 request
->browser_info
= info
;
1947 info
->ForceMCast
= (flags
& kDNSServiceFlagsForceMulticast
) != 0;
1948 info
->interface_id
= InterfaceID
;
1949 AssignDomainName(&info
->regtype
, &typedn
);
1950 info
->rstate
= request
;
1951 info
->default_domain
= !domain
[0];
1952 info
->browsers
= NULL
;
1954 // setup termination context
1955 request
->termination_context
= info
;
1956 request
->terminate
= browse_termination_callback
;
1958 LogOperation("%3d: DNSServiceBrowse(\"%##s\", \"%s\") START", request
->sd
, info
->regtype
.c
, domain
);
1961 if (!MakeDomainNameFromDNSNameString(&d
, domain
)) { err
= mStatus_BadParamErr
; goto error
; }
1962 err
= add_domain_to_browser(info
, &d
);
1967 search_domain_list
= mDNSPlatformGetSearchDomainList();
1968 for (sdom
= search_domain_list
; sdom
; sdom
= sdom
->next
)
1970 err
= add_domain_to_browser(info
, &sdom
->name
);
1973 if (SameDomainName(&sdom
->name
, &localdomain
)) break;
1974 else err
= mStatus_NoError
; // suppress errors for non-local "default" domains
1978 mDNS_FreeDNameList(search_domain_list
);
1981 deliver_error(request
, err
);
1985 if (info
) freeL("browser_info_t", info
);
1986 if (request
->termination_context
) request
->termination_context
= NULL
;
1987 deliver_error(request
, err
);
1988 abort_request(request
);
1989 unlink_request(request
);
1992 static void browse_result_callback(mDNS
*const m
, DNSQuestion
*question
, const ResourceRecord
*const answer
, mDNSBool AddRecord
)
1994 request_state
*req
= question
->QuestionContext
;
1998 LogOperation("%3d: DNSServiceBrowse(%##s, %s) RESULT %s %s",
1999 req
->sd
, question
->qname
.c
, DNSTypeName(question
->qtype
), AddRecord
? "Add" : "Rmv", RRDisplayString(m
, answer
));
2001 err
= gen_rr_response(&answer
->rdata
->u
.name
, answer
->InterfaceID
, req
, &rep
);
2004 if (deliver_async_error(req
, browse_reply
, err
) < 0)
2007 unlink_request(req
);
2011 if (AddRecord
) rep
->rhdr
->flags
|= dnssd_htonl(kDNSServiceFlagsAdd
); // non-zero TTL indicates add
2012 append_reply(req
, rep
);
2016 static void browse_termination_callback(void *context
)
2018 browser_info_t
*info
= context
;
2023 while(info
->browsers
)
2025 ptr
= info
->browsers
;
2026 info
->browsers
= ptr
->next
;
2027 LogOperation("%3d: DNSServiceBrowse(%##s) STOP", info
->rstate
->sd
, ptr
->q
.qname
.c
);
2028 mDNS_StopBrowse(gmDNS
, &ptr
->q
); // no need to error-check result
2029 freeL("browse_termination_callback", ptr
);
2032 info
->rstate
->termination_context
= NULL
;
2033 freeL("browser_info", info
);
2036 mDNSexport
void udsserver_default_browse_domain_changed(const domainname
*d
, mDNSBool add
)
2040 for (r
= all_requests
; r
; r
= r
->next
)
2042 browser_info_t
*info
= r
->browser_info
;
2044 if (!info
|| !info
->default_domain
) continue;
2045 if (add
) add_domain_to_browser(info
, d
);
2048 browser_t
**ptr
= &info
->browsers
;
2051 if (SameDomainName(&(*ptr
)->domain
, d
))
2053 browser_t
*remove
= *ptr
;
2054 *ptr
= (*ptr
)->next
;
2055 if (remove
->q
.LongLived
)
2057 // give goodbyes for known answers.
2058 // note that since events are sent to client via udsserver_idle(), we don't need to worry about the question being cancelled mid-loop
2059 CacheRecord
*ka
= remove
->q
.uDNS_info
.knownAnswers
;
2060 while (ka
) { remove
->q
.QuestionCallback(gmDNS
, &remove
->q
, &ka
->resrec
, mDNSfalse
); ka
= ka
->next
; }
2062 mDNS_StopBrowse(gmDNS
, &remove
->q
);
2063 freeL("browser_t", remove
);
2066 ptr
= &(*ptr
)->next
;
2068 LogMsg("Requested removal of default domain %##s not in list for sd %d", d
->c
, r
->sd
);
2073 // Count how many other service records we have locally with the same name, but different rdata.
2074 // For auto-named services, we can have at most one per machine -- if we allowed two auto-named services of
2075 // the same type on the same machine, we'd get into an infinite autoimmune-response loop of continuous renaming.
2076 mDNSexport
int CountPeerRegistrations(mDNS
*const m
, ServiceRecordSet
*const srs
)
2079 ResourceRecord
*r
= &srs
->RR_SRV
.resrec
;
2081 ServiceRecordSet
*s
;
2083 for (rr
= m
->ResourceRecords
; rr
; rr
=rr
->next
)
2084 if (rr
->resrec
.rrtype
== kDNSType_SRV
&& SameDomainName(rr
->resrec
.name
, r
->name
) && !SameRData(&rr
->resrec
, r
))
2087 for (rr
= m
->uDNS_info
.RecordRegistrations
; rr
; rr
=rr
->next
)
2088 if (rr
->uDNS_info
.state
!= regState_Unregistered
&& rr
->resrec
.rrtype
== kDNSType_SRV
&& SameDomainName(rr
->resrec
.name
, r
->name
) && !SameRData(&rr
->resrec
, r
))
2091 for (s
= m
->uDNS_info
.ServiceRegistrations
; s
; s
= s
->next
)
2092 if (s
->uDNS_info
.state
!= regState_Unregistered
&& SameDomainName(s
->RR_SRV
.resrec
.name
, r
->name
) && !SameRData(&s
->RR_SRV
.resrec
, r
))
2095 verbosedebugf("%d peer registrations for %##s", count
, r
->name
->c
);
2099 mDNSexport
int CountExistingRegistrations(domainname
*srv
, mDNSIPPort port
)
2103 for (rr
= gmDNS
->ResourceRecords
; rr
; rr
=rr
->next
)
2104 if (rr
->resrec
.rrtype
== kDNSType_SRV
&&
2105 rr
->resrec
.rdata
->u
.srv
.port
.NotAnInteger
== port
.NotAnInteger
&&
2106 SameDomainName(rr
->resrec
.name
, srv
))
2111 static mStatus
register_service_instance(request_state
*request
, const domainname
*domain
)
2113 service_info
*info
= request
->service_registration
;
2114 service_instance
*ptr
, *instance
;
2118 for (ptr
= info
->instances
; ptr
; ptr
= ptr
->next
)
2120 if (SameDomainName(&ptr
->domain
, domain
))
2121 { LogMsg("register_service_instance: domain %##s already registered", domain
->c
); return mStatus_AlreadyRegistered
; }
2124 instance_size
= sizeof(*instance
);
2125 if (info
->txtlen
> sizeof(RDataBody
)) instance_size
+= (info
->txtlen
- sizeof(RDataBody
));
2126 instance
= mallocL("service_instance", instance_size
);
2127 if (!instance
) { my_perror("ERROR: malloc"); return mStatus_NoMemoryErr
; }
2129 instance
->subtypes
= AllocateSubTypes(info
->num_subtypes
, info
->type_as_string
);
2130 if (info
->num_subtypes
&& !instance
->subtypes
)
2131 { free_service_instance(instance
); instance
= NULL
; FatalError("ERROR: malloc"); }
2132 instance
->request
= request
;
2133 instance
->sd
= request
->sd
;
2134 instance
->autoname
= info
->autoname
;
2135 instance
->autorename
= info
->autorename
;
2136 instance
->allowremotequery
= info
->allowremotequery
;
2137 instance
->rename_on_memfree
= 0;
2138 instance
->name
= info
->name
;
2139 AssignDomainName(&instance
->domain
, domain
);
2140 instance
->default_local
= (info
->default_domain
&& SameDomainName(domain
, &localdomain
));
2141 result
= mDNS_RegisterService(gmDNS
, &instance
->srs
, &instance
->name
, &info
->type
, domain
, info
->host
.c
[0] ? &info
->host
: NULL
, info
->port
,
2142 info
->txtdata
, info
->txtlen
, instance
->subtypes
, info
->num_subtypes
, info
->InterfaceID
, regservice_callback
, instance
);
2144 if (result
) free_service_instance(instance
);
2147 instance
->next
= info
->instances
;
2148 info
->instances
= instance
;
2153 mDNSexport
void udsserver_default_reg_domain_changed(const domainname
*d
, mDNSBool add
)
2155 request_state
*rstate
;
2158 LogMsg("%s registration domain %##s", add
? "Adding" : "Removing", d
->c
);
2159 for (rstate
= all_requests
; rstate
; rstate
= rstate
->next
)
2161 if (rstate
->terminate
!= regservice_termination_callback
) continue;
2162 info
= rstate
->service_registration
;
2163 if (!info
) { LogMsg("udsserver_default_reg_domain_changed - NULL service info"); continue; } // this should never happen
2164 if (!info
->default_domain
) continue;
2166 // valid default registration
2167 if (add
) register_service_instance(rstate
, d
);
2170 // find the instance to remove
2171 service_instance
*si
= rstate
->service_registration
->instances
, *prev
= NULL
;
2174 if (SameDomainName(&si
->domain
, d
))
2177 if (prev
) prev
->next
= si
->next
;
2178 else info
->instances
= si
->next
;
2179 err
= mDNS_DeregisterService(gmDNS
, &si
->srs
);
2182 LogMsg("udsserver_default_reg_domain_changed - mDNS_DeregisterService err %d", err
);
2183 free_service_instance(si
);
2190 if (!si
) debugf("udsserver_default_reg_domain_changed - domain %##s not registered", d
->c
); // normal if registration failed
2195 // service registration
2196 static void handle_regservice_request(request_state
*request
)
2198 DNSServiceFlags flags
;
2200 char name
[1024]; // Lots of spare space for extra-long names that we'll auto-truncate down to 63 bytes
2201 char domain
[MAX_ESCAPED_DOMAIN_NAME
], host
[MAX_ESCAPED_DOMAIN_NAME
];
2205 service_info
*service
= NULL
;
2207 if (request
->ts
!= t_complete
)
2209 LogMsg("ERROR: handle_regservice_request - transfer state != t_complete");
2210 abort_request(request
);
2211 unlink_request(request
);
2215 service
= mallocL("service_info", sizeof(*service
));
2216 if (!service
) { my_perror("ERROR: malloc"); result
= mStatus_NoMemoryErr
; goto finish
; }
2218 service
->instances
= NULL
;
2219 service
->request
= request
;
2220 service
->txtlen
= 0;
2221 service
->txtdata
= NULL
;
2222 request
->service_registration
= service
;
2223 request
->termination_context
= request
->service_registration
;
2224 request
->terminate
= regservice_termination_callback
;
2226 // extract data from message
2227 ptr
= request
->msgdata
;
2228 flags
= get_flags(&ptr
);
2229 ifi
= get_long(&ptr
);
2230 service
->InterfaceID
= mDNSPlatformInterfaceIDfromInterfaceIndex(gmDNS
, ifi
);
2231 if (ifi
&& !service
->InterfaceID
)
2232 { LogMsg("ERROR: handle_regservice_request - Couldn't find InterfaceID for interfaceIndex %d", ifi
); goto bad_param
; }
2233 if (get_string(&ptr
, name
, sizeof(name
)) < 0 ||
2234 get_string(&ptr
, service
->type_as_string
, MAX_ESCAPED_DOMAIN_NAME
) < 0 ||
2235 get_string(&ptr
, domain
, MAX_ESCAPED_DOMAIN_NAME
) < 0 ||
2236 get_string(&ptr
, host
, MAX_ESCAPED_DOMAIN_NAME
) < 0)
2237 { LogMsg("ERROR: handle_regservice_request - Couldn't read name/regtype/domain"); goto bad_param
; }
2239 service
->port
.b
[0] = *ptr
++;
2240 service
->port
.b
[1] = *ptr
++;
2242 service
->txtlen
= get_short(&ptr
);
2243 if (service
->txtlen
)
2245 service
->txtdata
= mallocL("txtdata", service
->txtlen
);
2246 if (!service
->txtdata
) { my_perror("ERROR: malloc"); result
= mStatus_NoMemoryErr
; goto finish
; }
2247 memcpy(service
->txtdata
, get_rdata(&ptr
, service
->txtlen
), service
->txtlen
);
2249 else service
->txtdata
= NULL
;
2251 // Check for sub-types after the service type
2252 service
->num_subtypes
= ChopSubTypes(service
->type_as_string
); // Note: Modifies regtype string to remove trailing subtypes
2253 if (service
->num_subtypes
< 0)
2254 { LogMsg("ERROR: handle_regservice_request - ChopSubTypes failed %s", service
->type_as_string
); goto bad_param
; }
2256 // Don't try to construct "domainname t" until *after* ChopSubTypes has worked its magic
2257 if (!*service
->type_as_string
|| !MakeDomainNameFromDNSNameString(&service
->type
, service
->type_as_string
))
2258 { LogMsg("ERROR: handle_regservice_request - service->type_as_string bad %s", service
->type_as_string
); goto bad_param
; }
2262 service
->name
= (gmDNS
)->nicelabel
;
2263 service
->autoname
= mDNStrue
;
2267 // If the client is allowing AutoRename, then truncate name to legal length before converting it to a DomainLabel
2268 if ((flags
& kDNSServiceFlagsNoAutoRename
) == 0)
2270 int newlen
= TruncateUTF8ToLength((mDNSu8
*)name
, mDNSPlatformStrLen(name
), MAX_DOMAIN_LABEL
);
2273 if (!MakeDomainLabelFromLiteralString(&service
->name
, name
))
2274 { LogMsg("ERROR: handle_regservice_request - name bad %s", name
); goto bad_param
; }
2275 service
->autoname
= mDNSfalse
;
2280 service
->default_domain
= mDNSfalse
;
2281 if (!MakeDomainNameFromDNSNameString(&d
, domain
))
2282 { LogMsg("ERROR: handle_regservice_request - domain bad %s", domain
); goto bad_param
; }
2286 service
->default_domain
= mDNStrue
;
2287 MakeDomainNameFromDNSNameString(&d
, "local.");
2290 if (!ConstructServiceName(&srv
, &service
->name
, &service
->type
, &d
))
2291 { LogMsg("ERROR: handle_regservice_request - Couldn't ConstructServiceName from, “%#s” “%##s” “%##s”", service
->name
.c
, service
->type
.c
, d
.c
); goto bad_param
; }
2293 if (!MakeDomainNameFromDNSNameString(&service
->host
, host
))
2294 { LogMsg("ERROR: handle_regservice_request - host bad %s", host
); goto bad_param
; }
2295 service
->autorename
= (flags
& kDNSServiceFlagsNoAutoRename
) == 0;
2296 service
->allowremotequery
= (flags
& kDNSServiceFlagsAllowRemoteQuery
) != 0;
2298 // Some clients use mDNS for lightweight copy protection, registering a pseudo-service with
2299 // a port number of zero. When two instances of the protected client are allowed to run on one
2300 // machine, we don't want to see misleading "Bogus client" messages in syslog and the console.
2301 if (service
->port
.NotAnInteger
)
2303 int count
= CountExistingRegistrations(&srv
, service
->port
);
2305 LogMsg("Client application registered %d identical instances of service %##s port %u.",
2306 count
+1, srv
.c
, mDNSVal16(service
->port
));
2309 LogOperation("%3d: DNSServiceRegister(\"%s\", \"%s\", \"%s\", \"%s\", %u) START",
2310 request
->sd
, name
, service
->type_as_string
, domain
, host
, mDNSVal16(service
->port
));
2311 result
= register_service_instance(request
, &d
);
2313 if (!result
&& !*domain
)
2315 DNameListElem
*ptr
, *def_domains
= mDNSPlatformGetRegDomainList();
2316 for (ptr
= def_domains
; ptr
; ptr
= ptr
->next
)
2317 register_service_instance(request
, &ptr
->name
);
2318 // note that we don't report errors for non-local, non-explicit domains
2319 mDNS_FreeDNameList(def_domains
);
2323 deliver_error(request
, result
);
2324 if (result
!= mStatus_NoError
)
2326 abort_request(request
);
2327 unlink_request(request
);
2330 reset_connected_rstate(request
); // prepare to receive add/remove messages
2335 //if (service) freeL("service_info", service); Don't think we should do this -- abort_request will free it a second time and crash
2336 deliver_error(request
, mStatus_BadParamErr
);
2337 abort_request(request
);
2338 unlink_request(request
);
2341 // service registration callback performs three duties - frees memory for deregistered services,
2342 // handles name conflicts, and delivers completed registration information to the client (via
2343 // process_service_registraion())
2345 static void regservice_callback(mDNS
*const m
, ServiceRecordSet
*const srs
, mStatus result
)
2348 mDNSBool SuppressError
= mDNSfalse
;
2349 service_instance
*instance
= srs
->ServiceContext
;
2351 if (!srs
) { LogMsg("regservice_callback: srs is NULL %d", result
); return; }
2352 if (!instance
) { LogMsg("regservice_callback: srs->ServiceContext is NULL %d", result
); return; }
2354 if (instance
->request
&& instance
->request
->service_registration
)
2356 service_info
*info
= instance
->request
->service_registration
;
2357 if (info
->default_domain
&& !instance
->default_local
) SuppressError
= mDNStrue
;
2358 // don't send errors up to client for wide-area, empty-string registrations
2361 if (result
== mStatus_NoError
)
2362 LogOperation("%3d: DNSServiceRegister(%##s, %u) REGISTERED ", instance
->sd
, srs
->RR_SRV
.resrec
.name
->c
, mDNSVal16(srs
->RR_SRV
.resrec
.rdata
->u
.srv
.port
));
2363 else if (result
== mStatus_MemFree
)
2364 LogOperation("%3d: DNSServiceRegister(%##s, %u) DEREGISTERED", instance
->sd
, srs
->RR_SRV
.resrec
.name
->c
, mDNSVal16(srs
->RR_SRV
.resrec
.rdata
->u
.srv
.port
));
2365 else if (result
== mStatus_NameConflict
)
2366 LogOperation("%3d: DNSServiceRegister(%##s, %u) NAME CONFLICT", instance
->sd
, srs
->RR_SRV
.resrec
.name
->c
, mDNSVal16(srs
->RR_SRV
.resrec
.rdata
->u
.srv
.port
));
2368 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
);
2370 if (result
== mStatus_NoError
)
2372 if (instance
->allowremotequery
)
2374 ExtraResourceRecord
*e
;
2375 srs
->RR_ADV
.AllowRemoteQuery
= mDNStrue
;
2376 srs
->RR_PTR
.AllowRemoteQuery
= mDNStrue
;
2377 srs
->RR_SRV
.AllowRemoteQuery
= mDNStrue
;
2378 srs
->RR_TXT
.AllowRemoteQuery
= mDNStrue
;
2379 for (e
= instance
->srs
.Extras
; e
; e
= e
->next
) e
->r
.AllowRemoteQuery
= mDNStrue
;
2381 process_service_registration(srs
, SuppressError
);
2382 if (instance
->autoname
&& CountPeerRegistrations(m
, srs
) == 0)
2383 RecordUpdatedNiceLabel(m
, 0); // Successfully got new name, tell user immediately
2386 else if (result
== mStatus_MemFree
)
2388 if (instance
->rename_on_memfree
)
2390 instance
->rename_on_memfree
= 0;
2391 instance
->name
= gmDNS
->nicelabel
;
2392 err
= mDNS_RenameAndReregisterService(gmDNS
, srs
, &instance
->name
);
2393 if (err
) LogMsg("ERROR: regservice_callback - RenameAndReregisterService returned %ld", err
);
2394 // error should never happen - safest to log and continue
2398 free_service_instance(instance
);
2402 else if (result
== mStatus_NameConflict
)
2404 if (instance
->autoname
&& CountPeerRegistrations(m
, srs
) == 0)
2406 // On conflict for an autoname service, rename and reregister *all* autoname services
2407 IncrementLabelSuffix(&m
->nicelabel
, mDNStrue
);
2408 m
->MainCallback(m
, mStatus_ConfigChanged
);
2410 else if (instance
->autoname
|| instance
->autorename
)
2412 mDNS_RenameAndReregisterService(gmDNS
, srs
, mDNSNULL
);
2417 request_state
*rs
= instance
->request
;
2418 if (!rs
) { LogMsg("ERROR: regservice_callback: received result %ld with a NULL request pointer", result
); return; }
2419 free_service_instance(instance
);
2420 if (!SuppressError
&& deliver_async_error(rs
, reg_service_reply
, result
) < 0)
2430 request_state
*rs
= instance
->request
;
2431 if (!rs
) { LogMsg("ERROR: regservice_callback: received result %ld with a NULL request pointer", result
); return; }
2432 if (result
!= mStatus_NATTraversal
) LogMsg("ERROR: unknown result in regservice_callback: %ld", result
);
2433 free_service_instance(instance
);
2434 if (!SuppressError
&& deliver_async_error(rs
, reg_service_reply
, result
) < 0)
2443 mDNSexport
void FreeExtraRR(mDNS
*const m
, AuthRecord
*const rr
, mStatus result
)
2445 ExtraResourceRecord
*extra
= (ExtraResourceRecord
*)rr
->RecordContext
;
2448 if (result
!= mStatus_MemFree
) { LogMsg("Error: FreeExtraRR invoked with unexpected error %d", result
); return; }
2450 debugf("%##s: MemFree", rr
->resrec
.name
->c
);
2451 if (rr
->resrec
.rdata
!= &rr
->rdatastorage
)
2452 freeL("Extra RData", rr
->resrec
.rdata
);
2453 freeL("ExtraResourceRecord", extra
);
2456 static mStatus
add_record_to_service(request_state
*rstate
, service_instance
*instance
, uint16_t rrtype
, uint16_t rdlen
, char *rdata
, uint32_t ttl
)
2458 ServiceRecordSet
*srs
= &instance
->srs
;
2459 ExtraResourceRecord
*extra
;
2463 if (rdlen
> sizeof(RDataBody
)) size
= rdlen
;
2464 else size
= sizeof(RDataBody
);
2466 extra
= mallocL("ExtraResourceRecord", sizeof(*extra
) - sizeof(RDataBody
) + size
);
2469 my_perror("ERROR: malloc");
2470 return mStatus_NoMemoryErr
;
2473 bzero(extra
, sizeof(ExtraResourceRecord
)); // OK if oversized rdata not zero'd
2474 extra
->r
.resrec
.rrtype
= rrtype
;
2475 extra
->r
.rdatastorage
.MaxRDLength
= (mDNSu16
) size
;
2476 extra
->r
.resrec
.rdlength
= rdlen
;
2477 memcpy(&extra
->r
.rdatastorage
.u
.data
, rdata
, rdlen
);
2479 result
= mDNS_AddRecordToService(gmDNS
, srs
, extra
, &extra
->r
.rdatastorage
, ttl
);
2480 if (result
) { freeL("ExtraResourceRecord", extra
); return result
; }
2482 extra
->ClientID
= rstate
->hdr
.reg_index
;
2486 static mStatus
handle_add_request(request_state
*rstate
)
2489 uint16_t rrtype
, rdlen
;
2491 mStatus result
= mStatus_UnknownErr
;
2492 DNSServiceFlags flags
;
2493 service_info
*srvinfo
= rstate
->service_registration
;
2494 service_instance
*i
;
2496 if (!srvinfo
) { LogMsg("handle_add_request called with NULL service_registration"); return(-1); }
2498 ptr
= rstate
->msgdata
;
2499 flags
= get_flags(&ptr
);
2500 rrtype
= get_short(&ptr
);
2501 rdlen
= get_short(&ptr
);
2502 rdata
= get_rdata(&ptr
, rdlen
);
2503 ttl
= get_long(&ptr
);
2505 if (!ttl
) ttl
= DefaultTTLforRRType(rrtype
);
2507 LogOperation("%3d: DNSServiceAddRecord(%##s, %s)", rstate
->sd
,
2508 (srvinfo
->instances
) ? srvinfo
->instances
->srs
.RR_SRV
.resrec
.name
->c
: NULL
, DNSTypeName(rrtype
));
2510 for (i
= srvinfo
->instances
; i
; i
= i
->next
)
2512 result
= add_record_to_service(rstate
, i
, rrtype
, rdlen
, rdata
, ttl
);
2513 if (result
&& i
->default_local
) break;
2514 else result
= mStatus_NoError
; // suppress non-local default errors
2520 static mStatus
update_record(AuthRecord
*rr
, uint16_t rdlen
, char *rdata
, uint32_t ttl
)
2526 if (rdlen
> sizeof(RDataBody
)) rdsize
= rdlen
;
2527 else rdsize
= sizeof(RDataBody
);
2528 newrd
= mallocL("handle_update_request", sizeof(RData
) - sizeof(RDataBody
) + rdsize
);
2529 if (!newrd
) FatalError("ERROR: malloc");
2530 newrd
->MaxRDLength
= (mDNSu16
) rdsize
;
2531 memcpy(&newrd
->u
, rdata
, rdlen
);
2533 // BIND named (name daemon) doesn't allow TXT records with zero-length rdata. This is strictly speaking correct,
2534 // since RFC 1035 specifies a TXT record as "One or more <character-string>s", not "Zero or more <character-string>s".
2535 // Since some legacy apps try to create zero-length TXT records, we'll silently correct it here.
2536 if (rr
->resrec
.rrtype
== kDNSType_TXT
&& rdlen
== 0) { rdlen
= 1; newrd
->u
.txt
.c
[0] = 0; }
2538 result
= mDNS_Update(gmDNS
, rr
, ttl
, rdlen
, newrd
, update_callback
);
2539 if (result
) { LogMsg("ERROR: mDNS_Update - %ld", result
); freeL("handle_update_request", newrd
); }
2543 static mStatus
handle_update_request(request_state
*rstate
)
2548 mStatus result
= mStatus_BadReferenceErr
;
2549 service_info
*srvinfo
= rstate
->service_registration
;
2550 service_instance
*i
;
2551 AuthRecord
*rr
= NULL
;
2553 // get the message data
2554 ptr
= rstate
->msgdata
;
2555 get_flags(&ptr
); // flags unused
2556 rdlen
= get_short(&ptr
);
2557 rdata
= get_rdata(&ptr
, rdlen
);
2558 ttl
= get_long(&ptr
);
2560 if (rstate
->reg_recs
)
2562 // update an individually registered record
2563 registered_record_entry
*reptr
;
2564 for (reptr
= rstate
->reg_recs
; reptr
; reptr
= reptr
->next
)
2566 if (reptr
->key
== rstate
->hdr
.reg_index
)
2568 result
= update_record(reptr
->rr
, rdlen
, rdata
, ttl
);
2572 result
= mStatus_BadReferenceErr
;
2576 // update a record from a service record set
2577 if (!srvinfo
) { result
= mStatus_BadReferenceErr
; goto end
; }
2578 for (i
= srvinfo
->instances
; i
; i
= i
->next
)
2580 if (rstate
->hdr
.reg_index
== TXT_RECORD_INDEX
) rr
= &i
->srs
.RR_TXT
;
2583 ExtraResourceRecord
*e
;
2584 for (e
= i
->srs
.Extras
; e
; e
= e
->next
)
2585 if (e
->ClientID
== rstate
->hdr
.reg_index
) { rr
= &e
->r
; break; }
2588 if (!rr
) { result
= mStatus_BadReferenceErr
; goto end
; }
2589 result
= update_record(rr
, rdlen
, rdata
, ttl
);
2590 if (result
&& i
->default_local
) goto end
;
2591 else result
= mStatus_NoError
; // suppress non-local default errors
2595 LogOperation("%3d: DNSServiceUpdateRecord(%##s, %s)", rstate
->sd
,
2596 (srvinfo
->instances
) ? srvinfo
->instances
->srs
.RR_SRV
.resrec
.name
->c
: NULL
,
2597 rr
? DNSTypeName(rr
->resrec
.rrtype
) : "<NONE>");
2602 static void update_callback(mDNS
*const m
, AuthRecord
*const rr
, RData
*oldrd
)
2605 if (oldrd
!= &rr
->rdatastorage
) freeL("update_callback", oldrd
);
2608 static void process_service_registration(ServiceRecordSet
*const srs
, mDNSBool SuppressError
)
2611 transfer_state send_result
;
2613 service_instance
*instance
= srs
->ServiceContext
;
2614 request_state
*req
= instance
->request
;
2616 if (!req
) { LogMsg("ERROR: process_service_registration - null request object"); return; }
2617 err
= gen_rr_response(srs
->RR_SRV
.resrec
.name
, srs
->RR_SRV
.resrec
.InterfaceID
, req
, &rep
);
2620 if (SuppressError
&& deliver_async_error(req
, reg_service_reply
, err
) < 0)
2623 unlink_request(req
);
2627 send_result
= send_msg(rep
);
2628 if (send_result
== t_error
|| send_result
== t_terminated
)
2631 unlink_request(req
);
2632 freeL("process_service_registration", rep
);
2634 else if (send_result
== t_complete
) freeL("process_service_registration", rep
);
2635 else append_reply(req
, rep
);
2638 static void free_service_instance(service_instance
*srv
)
2640 request_state
*rstate
= srv
->request
;
2641 ExtraResourceRecord
*e
= srv
->srs
.Extras
, *tmp
;
2643 // clear pointers from parent struct
2646 service_instance
*ptr
= rstate
->service_registration
->instances
, *prev
= NULL
;
2651 if (prev
) prev
->next
= ptr
->next
;
2652 else rstate
->service_registration
->instances
= ptr
->next
;
2662 e
->r
.RecordContext
= e
;
2665 FreeExtraRR(gmDNS
, &tmp
->r
, mStatus_MemFree
);
2668 if (srv
->subtypes
) { freeL("regservice_callback", srv
->subtypes
); srv
->subtypes
= NULL
; }
2669 freeL("regservice_callback", srv
);
2672 static void regservice_termination_callback(void *context
)
2674 service_info
*info
= context
;
2675 service_instance
*i
, *p
;
2676 if (!info
) { LogMsg("regservice_termination_callback context is NULL"); return; }
2677 if (!info
->request
) { LogMsg("regservice_termination_callback info->request is NULL"); return; }
2678 i
= info
->instances
;
2683 p
->request
= NULL
; // clear back pointer
2684 // only safe to free memory if registration is not valid, i.e. deregister fails (which invalidates p)
2685 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
));
2686 if (mDNS_DeregisterService(gmDNS
, &p
->srs
)) free_service_instance(p
);
2688 info
->request
->service_registration
= NULL
; // clear pointer from request back to info
2689 if (info
->txtdata
) { freeL("txtdata", info
->txtdata
); info
->txtdata
= NULL
; }
2690 freeL("service_info", info
);
2693 static mStatus
handle_regrecord_request(request_state
*rstate
)
2696 registered_record_entry
*re
;
2699 if (rstate
->ts
!= t_complete
)
2701 LogMsg("ERROR: handle_regrecord_request - transfer state != t_complete");
2702 abort_request(rstate
);
2703 unlink_request(rstate
);
2707 rr
= read_rr_from_ipc_msg(rstate
->msgdata
, 1, 1);
2708 if (!rr
) return(mStatus_BadParamErr
);
2710 // allocate registration entry, link into list
2711 re
= mallocL("handle_regrecord_request", sizeof(registered_record_entry
));
2712 if (!re
) FatalError("ERROR: malloc");
2713 re
->key
= rstate
->hdr
.reg_index
;
2715 re
->rstate
= rstate
;
2716 re
->client_context
= rstate
->hdr
.client_context
;
2717 rr
->RecordContext
= re
;
2718 rr
->RecordCallback
= regrecord_callback
;
2719 re
->next
= rstate
->reg_recs
;
2720 rstate
->reg_recs
= re
;
2722 if (!rstate
->terminate
)
2724 rstate
->terminate
= connected_registration_termination
;
2725 rstate
->termination_context
= rstate
;
2728 if (rr
->resrec
.rroriginalttl
== 0)
2729 rr
->resrec
.rroriginalttl
= DefaultTTLforRRType(rr
->resrec
.rrtype
);
2731 LogOperation("%3d: DNSServiceRegisterRecord %s", rstate
->sd
, RRDisplayString(gmDNS
, &rr
->resrec
));
2732 result
= mDNS_Register(gmDNS
, rr
);
2736 static void regrecord_callback(mDNS
*const m
, AuthRecord
* rr
, mStatus result
)
2738 registered_record_entry
*re
= rr
->RecordContext
;
2739 request_state
*rstate
= re
? re
->rstate
: NULL
;
2747 // parent struct alreadt freed by termination callback
2748 if (!result
) LogMsg("Error: regrecord_callback: successful registration of orphaned record");
2751 if (result
!= mStatus_MemFree
) LogMsg("regrecord_callback: error %d received after parent termination", result
);
2752 freeL("regrecord_callback", rr
);
2757 // format result, add to the list for the request, including the client context in the header
2758 len
= sizeof(DNSServiceFlags
);
2759 len
+= sizeof(uint32_t); //interfaceIndex
2760 len
+= sizeof(DNSServiceErrorType
);
2762 reply
= create_reply(reg_record_reply
, len
, rstate
);
2763 reply
->mhdr
->client_context
= re
->client_context
;
2764 reply
->rhdr
->flags
= dnssd_htonl(0);
2765 reply
->rhdr
->ifi
= dnssd_htonl(mDNSPlatformInterfaceIndexfromInterfaceID(gmDNS
, rr
->resrec
.InterfaceID
));
2766 reply
->rhdr
->error
= dnssd_htonl(result
);
2770 // unlink from list, free memory
2771 registered_record_entry
**ptr
= &re
->rstate
->reg_recs
;
2772 while (*ptr
&& (*ptr
) != re
) ptr
= &(*ptr
)->next
;
2773 if (!*ptr
) { LogMsg("regrecord_callback - record not in list!"); return; }
2774 *ptr
= (*ptr
)->next
;
2775 freeL("regrecord_callback", re
->rr
);
2777 freeL("regrecord_callback", re
);
2781 ts
= send_msg(reply
);
2783 if (ts
== t_error
|| ts
== t_terminated
) { abort_request(rstate
); unlink_request(rstate
); }
2784 else if (ts
== t_complete
) freeL("regrecord_callback", reply
);
2785 else if (ts
== t_morecoming
) append_reply(rstate
, reply
); // client is blocked, link reply into list
2788 static void connected_registration_termination(void *context
)
2791 registered_record_entry
*fptr
, *ptr
= ((request_state
*)context
)->reg_recs
;
2796 shared
= fptr
->rr
->resrec
.RecordType
== kDNSRecordTypeShared
;
2797 fptr
->rr
->RecordContext
= NULL
;
2798 mDNS_Deregister(gmDNS
, fptr
->rr
);
2799 freeL("connected_registration_termination", fptr
);
2803 static mStatus
handle_removerecord_request(request_state
*rstate
)
2805 mStatus err
= mStatus_BadReferenceErr
;
2807 service_info
*srvinfo
= rstate
->service_registration
;
2809 ptr
= rstate
->msgdata
;
2810 get_flags(&ptr
); // flags unused
2812 if (rstate
->reg_recs
) err
= remove_record(rstate
); // remove individually registered record
2813 else if (!srvinfo
) LogOperation("%3d: DNSServiceRemoveRecord (bad ref)", rstate
->sd
);
2816 service_instance
*i
;
2817 LogOperation("%3d: DNSServiceRemoveRecord(%##s)", rstate
->sd
,
2818 (srvinfo
->instances
) ? srvinfo
->instances
->srs
.RR_SRV
.resrec
.name
->c
: NULL
);
2819 for (i
= srvinfo
->instances
; i
; i
= i
->next
)
2821 err
= remove_extra(rstate
, i
);
2822 if (err
&& i
->default_local
) break;
2823 else err
= mStatus_NoError
; // suppress non-local default errors
2830 // remove a resource record registered via DNSServiceRegisterRecord()
2831 static mStatus
remove_record(request_state
*rstate
)
2834 mStatus err
= mStatus_UnknownErr
;
2835 registered_record_entry
*e
, **ptr
= &rstate
->reg_recs
;
2837 while(*ptr
&& (*ptr
)->key
!= rstate
->hdr
.reg_index
) ptr
= &(*ptr
)->next
;
2838 if (!*ptr
) { LogMsg("DNSServiceRemoveRecord - bad reference"); return mStatus_BadReferenceErr
; }
2840 *ptr
= e
->next
; // unlink
2842 LogOperation("%3d: DNSServiceRemoveRecord(%#s)", rstate
->sd
, e
->rr
->resrec
.name
->c
);
2843 shared
= e
->rr
->resrec
.RecordType
== kDNSRecordTypeShared
;
2844 e
->rr
->RecordContext
= NULL
;
2845 err
= mDNS_Deregister(gmDNS
, e
->rr
);
2848 LogMsg("ERROR: remove_record, mDNS_Deregister: %ld", err
);
2849 freeL("remove_record", e
->rr
);
2850 freeL("remove_record", e
);
2855 static mStatus
remove_extra(request_state
*rstate
, service_instance
*serv
)
2857 mStatus err
= mStatus_BadReferenceErr
;
2858 ExtraResourceRecord
*ptr
;
2860 for (ptr
= serv
->srs
.Extras
; ptr
; ptr
= ptr
->next
)
2862 if (ptr
->ClientID
== rstate
->hdr
.reg_index
) // found match
2863 return mDNS_RemoveRecordFromService(gmDNS
, &serv
->srs
, ptr
, FreeExtraRR
, ptr
);
2868 // domain enumeration
2869 static void handle_enum_request(request_state
*rstate
)
2871 DNSServiceFlags flags
;
2873 mDNSInterfaceID InterfaceID
;
2874 char *ptr
= rstate
->msgdata
;
2875 domain_enum_t
*def
, *all
;
2876 enum_termination_t
*term
;
2880 if (rstate
->ts
!= t_complete
)
2882 LogMsg("ERROR: handle_enum_request - transfer state != t_complete");
2883 abort_request(rstate
);
2884 unlink_request(rstate
);
2888 flags
= get_flags(&ptr
);
2889 ifi
= get_long(&ptr
);
2890 InterfaceID
= mDNSPlatformInterfaceIDfromInterfaceIndex(gmDNS
, ifi
);
2891 if (ifi
&& !InterfaceID
)
2893 deliver_error(rstate
, mStatus_BadParamErr
);
2894 abort_request(rstate
);
2895 unlink_request(rstate
);
2899 // allocate context structures
2900 def
= mallocL("handle_enum_request", sizeof(domain_enum_t
));
2901 all
= mallocL("handle_enum_request", sizeof(domain_enum_t
));
2902 term
= mallocL("handle_enum_request", sizeof(enum_termination_t
));
2903 if (!def
|| !all
|| !term
) FatalError("ERROR: malloc");
2905 // enumeration requires multiple questions, so we must link all the context pointers so that
2906 // necessary context can be reached from the callbacks
2907 def
->rstate
= rstate
;
2908 all
->rstate
= rstate
;
2911 term
->rstate
= rstate
;
2912 rstate
->termination_context
= term
;
2913 rstate
->terminate
= enum_termination_callback
;
2914 def
->question
.QuestionContext
= def
;
2915 def
->type
= (flags
& kDNSServiceFlagsRegistrationDomains
) ?
2916 mDNS_DomainTypeRegistrationDefault
: mDNS_DomainTypeBrowseDefault
;
2917 all
->question
.QuestionContext
= all
;
2918 all
->type
= (flags
& kDNSServiceFlagsRegistrationDomains
) ?
2919 mDNS_DomainTypeRegistration
: mDNS_DomainTypeBrowse
;
2921 // if the caller hasn't specified an explicit interface, we use local-only to get the system-wide list.
2922 if (!InterfaceID
) InterfaceID
= mDNSInterface_LocalOnly
;
2925 LogOperation("%3d: DNSServiceEnumerateDomains(%X=%s)", rstate
->sd
, flags
,
2926 (flags
& kDNSServiceFlagsBrowseDomains
) ? "kDNSServiceFlagsBrowseDomains" :
2927 (flags
& kDNSServiceFlagsRegistrationDomains
) ? "kDNSServiceFlagsRegistrationDomains" : "<<Unknown>>");
2928 err
= mDNS_GetDomains(gmDNS
, &all
->question
, all
->type
, NULL
, InterfaceID
, enum_result_callback
, all
);
2929 if (err
== mStatus_NoError
)
2930 err
= mDNS_GetDomains(gmDNS
, &def
->question
, def
->type
, NULL
, InterfaceID
, enum_result_callback
, def
);
2931 result
= deliver_error(rstate
, err
); // send error *before* returning local domain
2933 if (result
< 0 || err
)
2935 abort_request(rstate
);
2936 unlink_request(rstate
);
2941 static void enum_result_callback(mDNS
*const m
, DNSQuestion
*question
, const ResourceRecord
*const answer
, mDNSBool AddRecord
)
2943 char domain
[MAX_ESCAPED_DOMAIN_NAME
];
2944 domain_enum_t
*de
= question
->QuestionContext
;
2945 DNSServiceFlags flags
= 0;
2949 if (answer
->rrtype
!= kDNSType_PTR
) return;
2950 if (!AddRecord
&& de
->type
!= mDNS_DomainTypeBrowse
) return;
2954 flags
|= kDNSServiceFlagsAdd
;
2955 if (de
->type
== mDNS_DomainTypeRegistrationDefault
|| de
->type
== mDNS_DomainTypeBrowseDefault
)
2956 flags
|= kDNSServiceFlagsDefault
;
2958 ConvertDomainNameToCString(&answer
->rdata
->u
.name
, domain
);
2959 // note that we do NOT propagate specific interface indexes to the client - for example, a domain we learn from
2960 // a machine's system preferences may be discovered on the LocalOnly interface, but should be browsed on the
2961 // network, so we just pass kDNSServiceInterfaceIndexAny
2962 reply
= format_enumeration_reply(de
->rstate
, domain
, flags
, kDNSServiceInterfaceIndexAny
, kDNSServiceErr_NoError
);
2965 LogMsg("ERROR: enum_result_callback, format_enumeration_reply");
2969 append_reply(de
->rstate
, reply
);
2973 static reply_state
*format_enumeration_reply(request_state
*rstate
, const char *domain
, DNSServiceFlags flags
, uint32_t ifi
, DNSServiceErrorType err
)
2980 len
= sizeof(DNSServiceFlags
);
2981 len
+= sizeof(uint32_t);
2982 len
+= sizeof(DNSServiceErrorType
);
2983 len
+= strlen(domain
) + 1;
2985 reply
= create_reply(enumeration_reply
, len
, rstate
);
2986 reply
->rhdr
->flags
= dnssd_htonl(flags
);
2987 reply
->rhdr
->ifi
= dnssd_htonl(ifi
);
2988 reply
->rhdr
->error
= dnssd_htonl(err
);
2989 data
= reply
->sdata
;
2990 put_string(domain
, &data
);
2994 static void enum_termination_callback(void *context
)
2996 enum_termination_t
*t
= context
;
2997 mDNS
*coredata
= gmDNS
;
2999 mDNS_StopGetDomains(coredata
, &t
->all
->question
);
3000 mDNS_StopGetDomains(coredata
, &t
->def
->question
);
3001 freeL("enum_termination_callback", t
->all
);
3002 freeL("enum_termination_callback", t
->def
);
3003 t
->rstate
->termination_context
= NULL
;
3004 freeL("enum_termination_callback", t
);
3007 static void handle_reconfirm_request(request_state
*rstate
)
3011 rr
= read_rr_from_ipc_msg(rstate
->msgdata
, 0, 1);
3013 LogOperation("%3d: DNSServiceReconfirmRecord(%##s) %s", rstate
->sd
, RRDisplayString(gmDNS
, &rr
->resrec
));
3014 mDNS_ReconfirmByValue(gmDNS
, &rr
->resrec
);
3015 abort_request(rstate
);
3016 unlink_request(rstate
);
3017 freeL("handle_reconfirm_request", rr
);
3020 // setup rstate to accept new reg/dereg requests
3021 static void reset_connected_rstate(request_state
*rstate
)
3023 rstate
->ts
= t_morecoming
;
3024 rstate
->hdr_bytes
= 0;
3025 rstate
->data_bytes
= 0;
3026 if (rstate
->msgbuf
) freeL("reset_connected_rstate", rstate
->msgbuf
);
3027 rstate
->msgbuf
= NULL
;
3028 rstate
->bufsize
= 0;
3031 // returns a resource record (allocated w/ malloc) containing the data found in an IPC message
3032 // data must be in format flags, interfaceIndex, name, rrtype, rrclass, rdlen, rdata, (optional)ttl
3033 // (ttl only extracted/set if ttl argument is non-zero). returns NULL for a bad-parameter error
3034 static AuthRecord
*read_rr_from_ipc_msg(char *msgbuf
, int GetTTL
, int validate_flags
)
3036 char *rdata
, name
[256];
3038 DNSServiceFlags flags
;
3039 uint32_t interfaceIndex
;
3040 uint16_t type
, class, rdlen
;
3043 flags
= get_flags(&msgbuf
);
3044 if (validate_flags
&&
3045 !((flags
& kDNSServiceFlagsShared
) == kDNSServiceFlagsShared
) &&
3046 !((flags
& kDNSServiceFlagsUnique
) == kDNSServiceFlagsUnique
))
3048 LogMsg("ERROR: Bad resource record flags (must be kDNSServiceFlagsShared or kDNSServiceFlagsUnique)");
3052 interfaceIndex
= get_long(&msgbuf
);
3053 if (get_string(&msgbuf
, name
, 256) < 0)
3055 LogMsg("ERROR: read_rr_from_ipc_msg - get_string");
3058 type
= get_short(&msgbuf
);
3059 class = get_short(&msgbuf
);
3060 rdlen
= get_short(&msgbuf
);
3062 if (rdlen
> sizeof(RDataBody
)) storage_size
= rdlen
;
3063 else storage_size
= sizeof(RDataBody
);
3065 rr
= mallocL("read_rr_from_ipc_msg", sizeof(AuthRecord
) - sizeof(RDataBody
) + storage_size
);
3066 if (!rr
) FatalError("ERROR: malloc");
3067 bzero(rr
, sizeof(AuthRecord
)); // ok if oversized rdata not zero'd
3069 mDNS_SetupResourceRecord(rr
, mDNSNULL
, mDNSPlatformInterfaceIDfromInterfaceIndex(gmDNS
, interfaceIndex
),
3070 type
, 0, (mDNSu8
) ((flags
& kDNSServiceFlagsShared
) ? kDNSRecordTypeShared
: kDNSRecordTypeUnique
), mDNSNULL
, mDNSNULL
);
3072 if (!MakeDomainNameFromDNSNameString(rr
->resrec
.name
, name
))
3074 LogMsg("ERROR: bad name: %s", name
);
3075 freeL("read_rr_from_ipc_msg", rr
);
3078 if (flags
& kDNSServiceFlagsAllowRemoteQuery
) rr
->AllowRemoteQuery
= mDNStrue
;
3079 rr
->resrec
.rrclass
= class;
3080 rr
->resrec
.rdlength
= rdlen
;
3081 rr
->resrec
.rdata
->MaxRDLength
= rdlen
;
3082 rdata
= get_rdata(&msgbuf
, rdlen
);
3083 memcpy(rr
->resrec
.rdata
->u
.data
, rdata
, rdlen
);
3086 rr
->resrec
.rroriginalttl
= get_long(&msgbuf
);
3091 // generate a response message for a browse result, service registration result, or any other call with the
3092 // identical callback signature. on successful completion rep is set to point to a malloc'd reply_state struct,
3093 // and mStatus_NoError is returned. otherwise the appropriate error is returned.
3095 static mStatus
gen_rr_response(domainname
*servicename
, mDNSInterfaceID id
, request_state
*request
, reply_state
**rep
)
3100 domainname type
, dom
;
3101 char namestr
[MAX_DOMAIN_LABEL
+1]; // Unescaped name: up to 63 bytes plus C-string terminating NULL.
3102 char typestr
[MAX_ESCAPED_DOMAIN_NAME
];
3103 char domstr
[MAX_ESCAPED_DOMAIN_NAME
];
3107 if (!DeconstructServiceName(servicename
, &name
, &type
, &dom
))
3108 return kDNSServiceErr_Unknown
;
3110 ConvertDomainLabelToCString_unescaped(&name
, namestr
);
3111 ConvertDomainNameToCString(&type
, typestr
);
3112 ConvertDomainNameToCString(&dom
, domstr
);
3114 // calculate reply data length
3115 len
= sizeof(DNSServiceFlags
);
3116 len
+= sizeof(uint32_t); // if index
3117 len
+= sizeof(DNSServiceErrorType
);
3118 len
+= (int) (strlen(namestr
) + 1);
3119 len
+= (int) (strlen(typestr
) + 1);
3120 len
+= (int) (strlen(domstr
) + 1);
3122 *rep
= create_reply(query_reply
, len
, request
);
3124 (*rep
)->rhdr
->flags
= dnssd_htonl(0);
3125 (*rep
)->rhdr
->ifi
= dnssd_htonl(mDNSPlatformInterfaceIndexfromInterfaceID(gmDNS
, id
));
3126 (*rep
)->rhdr
->error
= dnssd_htonl(kDNSServiceErr_NoError
);
3128 data
= (*rep
)->sdata
;
3130 put_string(namestr
, &data
);
3131 put_string(typestr
, &data
);
3132 put_string(domstr
, &data
);
3133 return mStatus_NoError
;
3136 static int build_domainname_from_strings(domainname
*srv
, char *name
, char *regtype
, char *domain
)
3141 if (!MakeDomainLabelFromLiteralString(&n
, name
)) return -1;
3142 if (!MakeDomainNameFromDNSNameString(&t
, regtype
)) return -1;
3143 if (!MakeDomainNameFromDNSNameString(&d
, domain
)) return -1;
3144 if (!ConstructServiceName(srv
, &n
, &t
, &d
)) return -1;
3148 // append a reply to the list in a request object
3149 static void append_reply(request_state
*req
, reply_state
*rep
)
3153 if (!req
->replies
) req
->replies
= rep
;
3157 while (ptr
->next
) ptr
= ptr
->next
;
3163 // read_msg may be called any time when the transfer state (rs->ts) is t_morecoming.
3164 // returns the current state of the request (morecoming, error, complete, terminated.)
3165 // if there is no data on the socket, the socket will be closed and t_terminated will be returned
3166 static int read_msg(request_state
*rs
)
3170 char buf
[4]; // dummy for death notification
3172 if (rs
->ts
== t_terminated
|| rs
->ts
== t_error
)
3174 LogMsg("ERROR: read_msg called with transfer state terminated or error");
3179 if (rs
->ts
== t_complete
)
3180 { // this must be death or something is wrong
3181 nread
= recv(rs
->sd
, buf
, 4, 0);
3182 if (!nread
) { rs
->ts
= t_terminated
; return t_terminated
; }
3183 if (nread
< 0) goto rerror
;
3184 LogMsg("ERROR: read data from a completed request.");
3189 if (rs
->ts
!= t_morecoming
)
3191 LogMsg("ERROR: read_msg called with invalid transfer state (%d)", rs
->ts
);
3196 if (rs
->hdr_bytes
< sizeof(ipc_msg_hdr
))
3198 nleft
= sizeof(ipc_msg_hdr
) - rs
->hdr_bytes
;
3199 nread
= recv(rs
->sd
, (char *)&rs
->hdr
+ rs
->hdr_bytes
, nleft
, 0);
3200 if (nread
== 0) { rs
->ts
= t_terminated
; return t_terminated
; }
3201 if (nread
< 0) goto rerror
;
3202 rs
->hdr_bytes
+= nread
;
3203 if (rs
->hdr_bytes
== sizeof(ipc_msg_hdr
))
3205 ConvertHeaderBytes(&rs
->hdr
);
3206 if (rs
->hdr
.version
!= VERSION
)
3208 LogMsg("ERROR: read_msg - client version 0x%08X does not match daemon version 0x%08X", rs
->hdr
.version
, VERSION
);
3213 if (rs
->hdr_bytes
> sizeof(ipc_msg_hdr
))
3215 LogMsg("ERROR: read_msg - read too many header bytes");
3221 // only read data if header is complete
3222 if (rs
->hdr_bytes
== sizeof(ipc_msg_hdr
))
3224 if (rs
->hdr
.datalen
== 0) // ok in removerecord requests
3226 rs
->ts
= t_complete
;
3231 if (!rs
->msgbuf
) // allocate the buffer first time through
3233 rs
->msgbuf
= mallocL("read_msg", rs
->hdr
.datalen
+ MSG_PAD_BYTES
);
3236 my_perror("ERROR: malloc");
3240 rs
->msgdata
= rs
->msgbuf
;
3242 bzero(rs
->msgbuf
, rs
->hdr
.datalen
+ MSG_PAD_BYTES
);
3243 nleft
= rs
->hdr
.datalen
- rs
->data_bytes
;
3244 nread
= recv(rs
->sd
, rs
->msgbuf
+ rs
->data_bytes
, nleft
, 0);
3245 if (nread
== 0) { rs
->ts
= t_terminated
; return t_terminated
; }
3246 if (nread
< 0) goto rerror
;
3247 rs
->data_bytes
+= nread
;
3248 if (rs
->data_bytes
> rs
->hdr
.datalen
)
3250 LogMsg("ERROR: read_msg - read too many data bytes");
3256 if (rs
->hdr_bytes
== sizeof(ipc_msg_hdr
) && rs
->data_bytes
== rs
->hdr
.datalen
)
3257 rs
->ts
= t_complete
;
3258 else rs
->ts
= t_morecoming
;
3263 if (dnssd_errno() == dnssd_EWOULDBLOCK
|| dnssd_errno() == dnssd_EINTR
) return t_morecoming
;
3264 my_perror("ERROR: read_msg");
3269 static int send_msg(reply_state
*rs
)
3275 LogMsg("ERROR: send_msg called with NULL message buffer");
3279 if (rs
->request
->no_reply
) //!!!KRS this behavior should be optimized if it becomes more common
3281 rs
->ts
= t_complete
;
3282 freeL("send_msg", rs
->msgbuf
);
3286 ConvertHeaderBytes(rs
->mhdr
);
3287 nwriten
= send(rs
->sd
, rs
->msgbuf
+ rs
->nwriten
, rs
->len
- rs
->nwriten
, 0);
3288 ConvertHeaderBytes(rs
->mhdr
);
3291 if (dnssd_errno() == dnssd_EINTR
|| dnssd_errno() == dnssd_EWOULDBLOCK
) nwriten
= 0;
3294 #if !defined(PLATFORM_NO_EPIPE)
3295 if (dnssd_errno() == EPIPE
)
3297 debugf("%3d: broken pipe", rs
->sd
);
3298 rs
->ts
= t_terminated
;
3299 rs
->request
->ts
= t_terminated
;
3300 return t_terminated
;
3305 my_perror("ERROR: send\n");
3311 rs
->nwriten
+= nwriten
;
3313 if (rs
->nwriten
== rs
->len
)
3315 rs
->ts
= t_complete
;
3316 freeL("send_msg", rs
->msgbuf
);
3321 static reply_state
*create_reply(reply_op_t op
, size_t datalen
, request_state
*request
)
3327 if ((unsigned)datalen
< sizeof(reply_hdr
))
3329 LogMsg("ERROR: create_reply - data length less than lenght of required fields");
3333 totallen
= (int) (datalen
+ sizeof(ipc_msg_hdr
));
3334 reply
= mallocL("create_reply", sizeof(reply_state
));
3335 if (!reply
) FatalError("ERROR: malloc");
3336 bzero(reply
, sizeof(reply_state
));
3337 reply
->ts
= t_morecoming
;
3338 reply
->sd
= request
->sd
;
3339 reply
->request
= request
;
3340 reply
->len
= totallen
;
3341 reply
->msgbuf
= mallocL("create_reply", totallen
);
3342 if (!reply
->msgbuf
) FatalError("ERROR: malloc");
3343 bzero(reply
->msgbuf
, totallen
);
3344 reply
->mhdr
= (ipc_msg_hdr
*)reply
->msgbuf
;
3345 reply
->rhdr
= (reply_hdr
*)(reply
->msgbuf
+ sizeof(ipc_msg_hdr
));
3346 reply
->sdata
= reply
->msgbuf
+ sizeof(ipc_msg_hdr
) + sizeof(reply_hdr
);
3347 reply
->mhdr
->version
= VERSION
;
3348 reply
->mhdr
->op
= op
;
3349 reply
->mhdr
->datalen
= totallen
- sizeof(ipc_msg_hdr
);
3353 static int deliver_error(request_state
*rstate
, mStatus err
)
3356 undelivered_error_t
*undeliv
;
3358 err
= dnssd_htonl(err
);
3359 nwritten
= send(rstate
->sd
, (dnssd_sockbuf_t
) &err
, sizeof(mStatus
), 0);
3360 if (nwritten
< (int)sizeof(mStatus
))
3362 if (dnssd_errno() == dnssd_EINTR
|| dnssd_errno() == dnssd_EWOULDBLOCK
)
3366 my_perror("ERROR: send - unable to deliver error to client");
3371 //client blocked - store result and come backr
3372 undeliv
= mallocL("deliver_error", sizeof(undelivered_error_t
));
3373 if (!undeliv
) FatalError("ERROR: malloc");
3375 undeliv
->nwritten
= nwritten
;
3376 undeliv
->sd
= rstate
->sd
;
3377 rstate
->u_err
= undeliv
;
3384 // returns 0 on success, -1 if send is incomplete, or on terminal failure (request is aborted)
3385 static transfer_state
send_undelivered_error(request_state
*rs
)
3389 nwritten
= send(rs
->u_err
->sd
, (char *)(&rs
->u_err
->err
) + rs
->u_err
->nwritten
, sizeof(mStatus
) - rs
->u_err
->nwritten
, 0);
3392 if (dnssd_errno() == dnssd_EINTR
|| dnssd_errno() == dnssd_EWOULDBLOCK
)
3396 my_perror("ERROR: send - unable to deliver error to client\n");
3400 if ((unsigned int)(nwritten
+ rs
->u_err
->nwritten
) >= sizeof(mStatus
))
3402 freeL("send_undelivered_error", rs
->u_err
);
3406 rs
->u_err
->nwritten
+= nwritten
;
3407 return t_morecoming
;
3410 // send bogus data along with an error code to the app callback
3411 // returns 0 on success (linking reply into list of not fully delivered),
3412 // -1 on failure (request should be aborted)
3413 static int deliver_async_error(request_state
*rs
, reply_op_t op
, mStatus err
)
3419 if (rs
->no_reply
) return 0;
3420 len
= 256; // long enough for any reply handler to read all args w/o buffer overrun
3421 reply
= create_reply(op
, len
, rs
);
3422 reply
->rhdr
->error
= dnssd_htonl(err
);
3423 ts
= send_msg(reply
);
3424 if (ts
== t_error
|| ts
== t_terminated
)
3426 freeL("deliver_async_error", reply
);
3429 else if (ts
== t_complete
) freeL("deliver_async_error", reply
);
3430 else if (ts
== t_morecoming
) append_reply(rs
, reply
); // client is blocked, link reply into list
3434 static void abort_request(request_state
*rs
)
3436 reply_state
*rep
, *ptr
;
3438 if (rs
->terminate
) rs
->terminate(rs
->termination_context
); // terminate field may not be set yet
3439 if (rs
->msgbuf
) freeL("abort_request", rs
->msgbuf
);
3440 LogOperation("%3d: Removing FD", rs
->sd
);
3441 udsSupportRemoveFDFromEventLoop(rs
->sd
); // Note: This also closes file descriptor rs->sd for us
3442 rs
->sd
= dnssd_InvalidSocket
;
3444 // free pending replies
3448 if (rep
->msgbuf
) freeL("abort_request", rep
->msgbuf
);
3451 freeL("abort_request", ptr
);
3456 freeL("abort_request", rs
->u_err
);
3461 static void unlink_request(request_state
*rs
)
3465 if (rs
== all_requests
)
3467 all_requests
= all_requests
->next
;
3468 freeL("unlink_request", rs
);
3471 for(ptr
= all_requests
; ptr
->next
; ptr
= ptr
->next
)
3472 if (ptr
->next
== rs
)
3474 ptr
->next
= rs
->next
;
3475 freeL("unlink_request", rs
);
3480 //hack to search-replace perror's to LogMsg's
3481 static void my_perror(char *errmsg
)
3483 LogMsg("%s: %s", errmsg
, dnssd_strerror(dnssd_errno()));
3486 // check that the message delivered by the client is sufficiently long to extract the required data from the buffer
3487 // without overrunning it.
3488 // returns 0 on success, -1 on error.
3490 static int validate_message(request_state
*rstate
)
3494 switch(rstate
->hdr
.op
)
3496 case resolve_request
: min_size
= sizeof(DNSServiceFlags
) + // flags
3497 sizeof(uint32_t) + // interface
3498 (3 * sizeof(char)); // name, regtype, domain
3500 case query_request
: min_size
= sizeof(DNSServiceFlags
) + // flags
3501 sizeof(uint32_t) + // interface
3502 sizeof(char) + // fullname
3503 (2 * sizeof(uint16_t)); // type, class
3505 case browse_request
: min_size
= sizeof(DNSServiceFlags
) + // flags
3506 sizeof(uint32_t) + // interface
3507 (2 * sizeof(char)); // regtype, domain
3509 case reg_service_request
: min_size
= sizeof(DNSServiceFlags
) + // flags
3510 sizeof(uint32_t) + // interface
3511 (4 * sizeof(char)) + // name, type, domain, host
3512 (2 * sizeof(uint16_t)); // port, textlen
3514 case enumeration_request
: min_size
= sizeof(DNSServiceFlags
) + // flags
3515 sizeof(uint32_t); // interface
3517 case reg_record_request
: min_size
= sizeof(DNSServiceFlags
) + // flags
3518 sizeof(uint32_t) + // interface
3519 sizeof(char) + // fullname
3520 (3 * sizeof(uint16_t)) + // type, class, rdlen
3521 sizeof(uint32_t); // ttl
3523 case add_record_request
: min_size
= sizeof(DNSServiceFlags
) + // flags
3524 (2 * sizeof(uint16_t)) + // type, rdlen
3525 sizeof(uint32_t); // ttl
3527 case update_record_request
: min_size
= sizeof(DNSServiceFlags
) + // flags
3528 sizeof(uint16_t) + // rdlen
3529 sizeof(uint32_t); // ttl
3531 case remove_record_request
: min_size
= sizeof(DNSServiceFlags
); // flags
3533 case reconfirm_record_request
: min_size
=sizeof(DNSServiceFlags
) + // flags
3534 sizeof(uint32_t) + // interface
3535 sizeof(char) + // fullname
3536 (3 * sizeof(uint16_t)); // type, class, rdlen
3538 case setdomain_request
: min_size
= sizeof(DNSServiceFlags
) + sizeof(char); // flags + domain
3541 LogMsg("ERROR: validate_message - unsupported request type: %d", rstate
->hdr
.op
);
3545 return (rstate
->data_bytes
>= min_size
? 0 : -1);
3549 static uint32_t dnssd_htonl(uint32_t l
)
3554 data
= (char*) &ret
;
3563 static char * win32_strerror(int inErrorCode
)
3565 static char buffer
[1024];
3568 memset(buffer
, 0, sizeof(buffer
));
3571 FORMAT_MESSAGE_FROM_SYSTEM
| FORMAT_MESSAGE_IGNORE_INSERTS
,
3573 (DWORD
) inErrorCode
,
3574 MAKELANGID( LANG_NEUTRAL
, SUBLANG_DEFAULT
),
3581 // Remove any trailing CR's or LF's since some messages have them.
3583 while( ( n
> 0 ) && isspace( ( (unsigned char *) buffer
)[ n
- 1 ] ) )
3585 buffer
[ --n
] = '\0';