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.139 2004/12/13 21:18:45 ksekar
28 Include uDNS registrations in CountPeerRegistrations
30 Revision 1.138 2004/12/13 18:23:18 ksekar
31 <rdar://problem/3915805> mDNSResponder error when quitting iChat -
32 don't close sockets delivering errors to blocked clients
34 Revision 1.137 2004/12/13 00:09:22 ksekar
35 <rdar://problem/3915805> mDNSResponder error when quitting iChat
37 Revision 1.136 2004/12/11 01:52:10 cheshire
38 <rdar://problem/3785820> Support kDNSServiceFlagsAllowRemoteQuery for registering services too
40 Revision 1.135 2004/12/10 20:46:37 cheshire
41 Change LogOperation message to debugf
43 Revision 1.134 2004/12/10 13:19:37 cheshire
44 Add verbosedebugf() logging message in CountPeerRegistrations()
46 Revision 1.133 2004/12/10 05:27:26 cheshire
47 <rdar://problem/3909147> Guard against multiple autoname services of the same type on the same machine
49 Revision 1.132 2004/12/10 04:28:28 cheshire
50 <rdar://problem/3914406> User not notified of name changes for services using new UDS API
52 Revision 1.131 2004/12/10 02:09:25 cheshire
53 <rdar://problem/3898376> Modify default TTLs
55 Revision 1.130 2004/12/10 00:55:24 cheshire
56 Add full name and type to LogOperation messages for DNSServiceAddRecord/UpdateRecord/RemoveRecord
58 Revision 1.129 2004/12/09 03:17:23 ksekar
59 <rdar://problem/3910435> DomainEnumeration interface index should be zero
61 Revision 1.128 2004/12/07 21:26:05 ksekar
62 <rdar://problem/3908336> DNSServiceRegisterRecord() can crash on deregistration
64 Revision 1.127 2004/12/07 20:42:34 cheshire
65 Add explicit context parameter to mDNS_RemoveRecordFromService()
67 Revision 1.126 2004/12/07 17:23:55 ksekar
70 Revision 1.125 2004/12/06 21:15:23 ksekar
71 <rdar://problem/3884386> mDNSResponder crashed in CheckServiceRegistrations
73 Revision 1.124 2004/11/30 02:19:14 cheshire
74 <rdar://problem/3827971> Raise maxfds.rlim_cur for mDNSResponder
76 Revision 1.123 2004/11/29 23:50:57 cheshire
77 Checkin 1.122 not necessary
79 Revision 1.122 2004/11/24 17:55:01 ksekar
80 Added log message clarifying <rdar://problem/3869241> For unicast operations, verify that service types are legal
82 Revision 1.121 2004/11/24 04:45:52 cheshire
85 Revision 1.120 2004/11/24 00:10:44 cheshire
86 <rdar://problem/3869241> For unicast operations, verify that service types are legal
88 Revision 1.119 2004/11/23 23:54:17 ksekar
89 <rdar://problem/3890318> Wide-Area DNSServiceRegisterRecord() failures
90 can crash mDNSResponder
92 Revision 1.118 2004/11/23 22:33:01 cheshire
93 <rdar://problem/3654910> Remove temporary workaround code for iChat
95 Revision 1.117 2004/11/23 20:23:10 ksekar
96 Fixed LogOperation that causes crash on connected service deregistrations
98 Revision 1.116 2004/11/23 03:39:47 cheshire
99 Let interface name/index mapping capability live directly in JNISupport.c,
100 instead of having to call through to the daemon via IPC to get this information.
102 Revision 1.115 2004/11/13 00:12:53 ksekar
103 Fixed some LogOperation printf converstions for debug builds.
105 Revision 1.114 2004/11/12 18:25:45 shersche
106 Tidy up cross platform usleep code fragment.
108 Revision 1.113 2004/11/12 03:21:41 rpantos
109 rdar://problem/3809541 Add DNSSDMapIfIndexToName, DNSSDMapNameToIfIndex.
111 Revision 1.112 2004/11/11 16:58:32 ksekar
112 Removed unused code (previously wrapped in #if 0)
114 Revision 1.111 2004/11/05 22:47:37 shersche
115 Conditionally compile usleep(1000) to be Sleep(1) on Windows
116 Submitted by: Pavel Repin <prepin@gmail.com>
118 Revision 1.110 2004/11/05 19:56:56 ksekar
119 <rdar://problem/3862646> We no longer need to browse .Mac domains by
120 default - changed #if 0 to more descriptive #ifdef _HAVE_SETDOMAIN_SUPPORT_
122 Revision 1.109 2004/11/04 03:40:45 cheshire
123 More debugging messages
125 Revision 1.108 2004/11/03 02:25:51 cheshire
126 <rdar://problem/3324137> Conflict for Computer Name should update *all* empty string services, not just the one with the conflict
128 Revision 1.107 2004/11/02 19:39:23 ksekar
129 <rdar://problem/3862646> We no longer need to browse .Mac domains by default
131 Revision 1.106 2004/11/02 02:12:21 cheshire
132 <rdar://problem/3839111> Remove unnecessary memory allocations
134 Revision 1.105 2004/10/28 19:07:19 cheshire
135 Add some more debugging checks and improved LogOperation() messages
137 Revision 1.104 2004/10/26 18:53:15 cheshire
138 Avoid unused variable warning
140 Revision 1.103 2004/10/26 07:15:55 cheshire
141 Add file descriptor number to all LogOperation messages
143 Revision 1.102 2004/10/26 06:11:42 cheshire
144 Add improved logging to aid in diagnosis of <rdar://problem/3842714> mDNSResponder crashed
146 Revision 1.101 2004/10/26 04:31:44 cheshire
147 Rename CountSubTypes() as ChopSubTypes()
149 Revision 1.100 2004/10/26 01:17:48 cheshire
150 Use "#if 0" instead of commenting out code
152 Revision 1.99 2004/10/19 21:33:22 cheshire
153 <rdar://problem/3844991> Cannot resolve non-local registrations using the mach API
154 Added flag 'kDNSServiceFlagsForceMulticast'. Passing through an interface id for a unicast name
155 doesn't force multicast unless you set this flag to indicate explicitly that this is what you want
157 Revision 1.98 2004/10/14 01:59:33 cheshire
158 <rdar://problem/3839208> UDS resolves don't work for uDNS services
160 Revision 1.97 2004/10/13 00:58:35 cheshire
161 <rdar://problem/3832738> Registering a proxy doesn't work
163 Revision 1.96 2004/09/30 00:25:00 ksekar
164 <rdar://problem/3695802> Dynamically update default registration domains on config change
166 Revision 1.95 2004/09/26 23:20:36 ksekar
167 <rdar://problem/3813108> Allow default registrations in multiple wide-area domains
169 Revision 1.94 2004/09/22 18:27:06 ksekar
170 <rdar://problem/3811427> allow DNSServiceAddRecord to pass zero to get
173 Revision 1.93 2004/09/22 02:39:44 cheshire
174 <rdar://problem/3810757> Allow DNSServiceRegisterRecord to pass zero to get default record TTL
176 Revision 1.92 2004/09/22 02:34:04 cheshire
177 Rename parameter "ttl" to "GetTTL" for clarity
179 Revision 1.91 2004/09/22 02:25:43 cheshire
182 Revision 1.90 2004/09/21 23:40:12 ksekar
183 <rdar://problem/3810349> mDNSResponder to return errors on NAT traversal failure
185 Revision 1.89 2004/09/21 23:29:51 cheshire
186 <rdar://problem/3680045> DNSServiceResolve should delay sending packets
188 Revision 1.88 2004/09/21 23:12:46 cheshire
189 Reorder initialization of question fields to match structure order
191 Revision 1.87 2004/09/21 22:18:33 cheshire
192 In SIGINFO output, display a '-' next to records that have the Unique bit set
194 Revision 1.86 2004/09/21 21:05:11 cheshire
195 Move duplicate code out of mDNSMacOSX/daemon.c and mDNSPosix/PosixDaemon.c,
196 into mDNSShared/uds_daemon.c
198 Revision 1.85 2004/09/18 01:11:58 ksekar
199 <rdar://problem/3806734> Add a user's default domain to empty-string browse list
201 Revision 1.84 2004/09/17 01:08:55 cheshire
202 Renamed mDNSClientAPI.h to mDNSEmbeddedAPI.h
203 The name "mDNSClientAPI.h" is misleading to new developers looking at this code. The interfaces
204 declared in that file are ONLY appropriate to single-address-space embedded applications.
205 For clients on general-purpose computers, the interfaces defined in dns_sd.h should be used.
207 Revision 1.83 2004/09/16 23:26:33 cheshire
208 Move version check inside preceeding "if" that checks we have a complete header
210 Revision 1.82 2004/09/16 23:14:25 cheshire
211 Changes for Windows compatibility
213 Revision 1.81 2004/09/16 21:46:38 ksekar
214 <rdar://problem/3665304> Need SPI for LoginWindow to associate a UID with a Wide Area Rendezvous domain
216 Revision 1.80 2004/09/16 01:58:23 cheshire
217 Fix compiler warnings
219 Revision 1.79 2004/09/16 00:24:49 cheshire
220 <rdar://problem/3803162> Fix unsafe use of mDNSPlatformTimeNow()
222 Revision 1.78 2004/09/15 21:44:20 cheshire
223 <rdar://problem/3681031> Randomize initial timenow_adjust value in mDNS_Init
224 Show time value in log to help diagnose errors
226 Revision 1.77 2004/09/15 00:19:18 cheshire
227 <rdar://problem/3785823> read_rr_from_ipc_msg should use mDNS_SetupResourceRecord()
229 Revision 1.76 2004/09/02 06:39:52 cheshire
230 Minor textual cleanup for clarity
232 Revision 1.75 2004/09/02 03:48:47 cheshire
233 <rdar://problem/3709039> Disable targeted unicast query support by default
234 1. New flag kDNSServiceFlagsAllowRemoteQuery to indicate we want to allow remote queries for this record
235 2. New field AllowRemoteQuery in AuthRecord structure
236 3. uds_daemon.c sets AllowRemoteQuery if kDNSServiceFlagsAllowRemoteQuery is set
237 4. mDNS.c only answers remote queries if AllowRemoteQuery is set
239 Revision 1.74 2004/08/25 02:32:47 cheshire
240 Minor cleanup: replace "®type[0]" with "regtype"
242 Revision 1.73 2004/08/25 02:30:40 cheshire
243 <rdar://problem/3588761> Current method of doing subtypes causes name collisions
245 Revision 1.72 2004/08/14 03:22:42 cheshire
246 <rdar://problem/3762579> Dynamic DNS UI <-> mDNSResponder glue
247 Add GetUserSpecifiedDDNSName() routine
248 Convert ServiceRegDomain to domainname instead of C string
249 Replace mDNS_GenerateFQDN/mDNS_GenerateGlobalFQDN with mDNS_SetFQDNs
251 Revision 1.71 2004/08/11 04:21:21 rpantos
254 Revision 1.70 2004/08/11 02:07:00 cheshire
255 Remove "mDNS *globalInstance" parameter from udsserver_init()
256 Move CheckForDuplicateRegistrations from daemon.c
257 <rdar://problem/3501938> No warning when accidentally registering the same service multiple times using socket API
259 Revision 1.69 2004/08/10 16:14:48 cheshire
260 Fix debug builds (oops)
262 Revision 1.68 2004/08/10 06:24:56 cheshire
263 Use types with precisely defined sizes for 'op' and 'reg_index', for better
264 compatibility if the daemon and the client stub are built using different compilers
266 Revision 1.67 2004/07/27 07:14:16 shersche
267 make error socket non-blocking after call to connect()
269 Revision 1.66 2004/07/13 21:24:25 rpantos
270 Fix for <rdar://problem/3701120>.
272 Revision 1.65 2004/06/26 03:17:14 shersche
273 implement cross-platform strerror function
275 Submitted by: herscher
277 Revision 1.64 2004/06/25 00:26:27 rpantos
278 Changes to fix the Posix build on Solaris.
280 Revision 1.63 2004/06/24 03:43:44 rpantos
281 Fix previous checkin so it builds on Windows.
283 Revision 1.62 2004/06/24 00:57:08 ksekar
284 Replaced code acccidentally removed in checkin 1.59.
286 Revision 1.61 2004/06/19 00:09:39 cheshire
287 Remove unused strsep() implementation
289 Revision 1.60 2004/06/18 19:10:00 cheshire
290 <rdar://problem/3588761> Current method of doing subtypes causes name collisions
292 Revision 1.59 2004/06/18 05:10:31 rpantos
293 Changes to allow code to be used on Windows
295 Revision 1.58 2004/06/15 03:54:08 cheshire
296 Include mDNS_TimeNow(&mDNSStorage) in SIGINFO output
298 Revision 1.57 2004/06/12 01:47:27 ksekar
299 <rdar://problem/3690241>: BBEdit crashes when trying to check for newer version
300 udsserver_idle compared time in ticks to interval in seconds.
302 Revision 1.56 2004/06/12 01:35:47 cheshire
303 Changes for Windows compatibility
305 Revision 1.55 2004/06/05 00:04:27 cheshire
306 <rdar://problem/3668639>: wide-area domains should be returned in reg. domain enumeration
308 Revision 1.54 2004/06/01 22:22:52 ksekar
309 <rdar://problem/3668635>: wide-area default registrations should be in
312 Revision 1.53 2004/05/28 23:42:37 ksekar
313 <rdar://problem/3258021>: Feature: DNS server->client notification on record changes (#7805)
315 Revision 1.52 2004/05/26 00:39:49 ksekar
316 <rdar://problem/3667105>: wide-area DNS-SD servers don't appear in
318 Use local-only InterfaceID for GetDomains calls for sockets-API
320 Revision 1.51 2004/05/18 23:51:27 cheshire
321 Tidy up all checkin comments to use consistent "<rdar://problem/xxxxxxx>" format for bug numbers
323 Revision 1.50 2004/05/14 16:39:47 ksekar
324 Browse for iChat locally for now.
326 Revision 1.49 2004/05/13 21:33:52 ksekar
327 Clean up non-local registration control via config file. Force iChat
328 registrations to be local for now.
330 Revision 1.48 2004/05/13 04:13:19 ksekar
331 Updated SIGINFO handler for multi-domain browses
333 Revision 1.47 2004/05/12 22:04:01 ksekar
334 Implemented multi-domain browsing by default for uds_daemon.
336 Revision 1.46 2004/05/06 18:42:58 ksekar
337 General dns_sd.h API cleanup, including the following radars:
338 <rdar://problem/3592068>: Remove flags with zero value
339 <rdar://problem/3479569>: Passing in NULL causes a crash.
341 Revision 1.45 2004/03/12 08:49:28 cheshire
342 #include <sys/socket.h>
344 Revision 1.44 2004/02/25 01:25:27 ksekar
345 <rdar://problem/3569212>: DNSServiceRegisterRecord flags not error-checked
347 Revision 1.43 2004/02/24 01:46:40 cheshire
348 Manually reinstate lost checkin 1.36
350 Revision 1.42 2004/02/05 19:39:29 cheshire
351 Move creation of /var/run/mDNSResponder.pid to uds_daemon.c,
352 so that all platforms get this functionality
354 Revision 1.41 2004/02/03 18:59:02 cheshire
355 Change "char *domain" parameter for format_enumeration_reply to "const char *domain"
357 Revision 1.40 2004/01/28 03:41:00 cheshire
358 <rdar://problem/3541946>: Need ability to do targeted queries as well as multicast queries
360 Revision 1.39 2004/01/25 00:03:21 cheshire
361 Change to use mDNSVal16() instead of private PORT_AS_NUM() macro
363 Revision 1.38 2004/01/19 19:51:46 cheshire
364 Fix compiler error (mixed declarations and code) on some versions of Linux
366 Revision 1.37 2003/12/08 21:11:42 rpantos
367 Changes necessary to support mDNSResponder on Linux.
369 Revision 1.36 2003/12/04 23:40:57 cheshire
370 <rdar://problem/3484766>: Security: Crashing bug in mDNSResponder
371 Fix some more code that should use buffer size MAX_ESCAPED_DOMAIN_NAME (1005) instead of 256-byte buffers.
373 Revision 1.35 2003/12/03 19:10:22 ksekar
374 <rdar://problem/3498644>: malloc'd data not zero'd
376 Revision 1.34 2003/12/03 02:00:01 ksekar
377 <rdar://problem/3498644>: malloc'd data not zero'd
379 Revision 1.33 2003/11/22 01:18:46 ksekar
380 <rdar://problem/3486646>: config change handler not called for dns-sd services
382 Revision 1.32 2003/11/20 21:46:12 ksekar
383 <rdar://problem/3486635>: leak: DNSServiceRegisterRecord
385 Revision 1.31 2003/11/20 20:33:05 ksekar
386 <rdar://problem/3486635>: leak: DNSServiceRegisterRecord
388 Revision 1.30 2003/11/20 02:10:55 ksekar
389 <rdar://problem/3486643>: cleanup DNSServiceAdd/RemoveRecord
391 Revision 1.29 2003/11/14 21:18:32 cheshire
392 <rdar://problem/3484766>: Security: Crashing bug in mDNSResponder
393 Fix code that should use buffer size MAX_ESCAPED_DOMAIN_NAME (1005) instead of 256-byte buffers.
395 Revision 1.28 2003/11/08 22:18:29 cheshire
396 <rdar://problem/3477870>: Don't need to show process ID in *every* mDNSResponder syslog message
398 Revision 1.27 2003/11/05 22:44:57 ksekar
399 <rdar://problem/3335230>: No bounds checking when reading data from client
400 Reviewed by: Stuart Cheshire
402 Revision 1.26 2003/10/23 17:51:04 ksekar
403 <rdar://problem/3335216>: handle blocked clients more efficiently
404 Changed gettimeofday() to mDNS_TimeNow(&mDNSStorage);
406 Revision 1.25 2003/10/22 23:37:49 ksekar
407 <rdar://problem/3459141>: crash/hang in abort_client
409 Revision 1.24 2003/10/21 20:59:40 ksekar
410 <rdar://problem/3335216>: handle blocked clients moreefficiently
412 Revision 1.23 2003/09/23 02:12:43 cheshire
413 Also include port number in list of services registered via new UDS API
415 Revision 1.22 2003/08/19 16:03:55 ksekar
416 <rdar://problem/3380097>: ER: SIGINFO dump should include resolves started by DNSServiceQueryRecord
417 Check termination_context for NULL before dereferencing.
419 Revision 1.21 2003/08/19 05:39:43 cheshire
420 <rdar://problem/3380097> SIGINFO dump should include resolves started by DNSServiceQueryRecord
422 Revision 1.20 2003/08/16 03:39:01 cheshire
423 <rdar://problem/3338440> InterfaceID -1 indicates "local only"
425 Revision 1.19 2003/08/15 20:16:03 cheshire
426 <rdar://problem/3366590> mDNSResponder takes too much RPRVT
427 We want to avoid touching the rdata pages, so we don't page them in.
428 1. RDLength was stored with the rdata, which meant touching the page just to find the length.
429 Moved this from the RData to the ResourceRecord object.
430 2. To avoid unnecessarily touching the rdata just to compare it,
431 compute a hash of the rdata and store the hash in the ResourceRecord object.
433 Revision 1.18 2003/08/15 00:38:00 ksekar
434 <rdar://problem/3377005>: Bug: buffer overrun when reading long rdata from client
436 Revision 1.17 2003/08/14 02:18:21 cheshire
437 <rdar://problem/3375491> Split generic ResourceRecord type into two separate types: AuthRecord and CacheRecord
439 Revision 1.16 2003/08/13 23:58:52 ksekar
440 <rdar://problem/3374911>: Bug: UDS Sub-type browsing works, but not sub-type registration
441 Fixed pointer increment error, moved subtype reading for-loop for easier error bailout.
443 Revision 1.15 2003/08/13 17:30:33 ksekar
444 <rdar://problem/3374671>: DNSServiceAddRecord doesn't work
445 Fixed various problems with handling the AddRecord request and freeing the ExtraResourceRecords.
447 Revision 1.14 2003/08/12 19:56:25 cheshire
454 #define dnssd_strerror(X) win32_strerror(X)
455 #define usleep(X) Sleep(((X)+999)/1000)
456 static char * win32_strerror(int inErrorCode
);
460 #include <sys/ioctl.h>
461 #include <sys/types.h>
462 #include <sys/time.h>
463 #include <sys/resource.h>
464 #define dnssd_strerror(X) strerror(X)
469 #include "mDNSEmbeddedAPI.h"
470 #include "DNSCommon.h"
471 #include "uds_daemon.h"
473 #include "dnssd_ipc.h"
475 // Apple specific configuration functionality, not required for other platforms
477 #include <sys/ucred.h>
478 #ifndef LOCAL_PEERCRED
479 #define LOCAL_PEERCRED 0x001 /* retrieve peer credentials */
480 #endif // LOCAL_PEERCRED
483 // Types and Data Structures
484 // ----------------------------------------------------------------------
495 typedef void (*req_termination_fn
)(void *);
497 typedef struct registered_record_entry
501 struct registered_record_entry
*next
;
502 client_context_t client_context
;
503 struct request_state
*rstate
;
504 } registered_record_entry
;
506 // A single registered service: ServiceRecordSet + bookkeeping
507 // Note that we duplicate some fields from parent service_info object
508 // to facilitate cleanup, when instances and parent may be deallocated at different times.
509 typedef struct service_instance
511 struct service_instance
*next
;
512 mDNSBool autoname
; // Set if this name is tied to the Computer Name
513 mDNSBool autorename
; // Set if this client wants us to automatically rename on conflict
514 mDNSBool allowremotequery
; // Respond to unicast queries from outside the local link?
515 mDNSBool rename_on_memfree
; // Set on config change when we deregister original name
518 mDNSBool default_local
; // is this the "local." from an empty-string registration?
519 struct request_state
*request
;
521 AuthRecord
*subtypes
;
522 ServiceRecordSet srs
; // note - must be last field in struct
525 // A client-created service. May reference several service_info objects if default
526 // settings cause registration in multiple domains.
533 char type_as_string
[MAX_ESCAPED_DOMAIN_NAME
];
535 mDNSBool default_domain
;
537 mDNSBool autoname
; // Set if this name is tied to the Computer Name
538 mDNSBool autorename
; // Set if this client wants us to automatically rename on conflict
539 mDNSBool allowremotequery
; // Respond to unicast queries from outside the local link?
541 mDNSInterfaceID InterfaceID
;
542 service_instance
*instances
;
543 struct request_state
*request
;
546 // for multi-domain default browsing
547 typedef struct browser_t
551 struct browser_t
*next
;
554 // parent struct for browser instances: list pointer plus metadata
557 mDNSBool default_domain
;
560 mDNSInterfaceID interface_id
;
561 struct request_state
*rstate
;
567 mStatus err
; // Note: This field is in NETWORK byte order
570 } undelivered_error_t
;
572 typedef struct request_state
574 // connection structures
575 dnssd_sock_t sd
, errfd
;
577 // state of read (in case message is read over several recv() calls)
579 uint32_t hdr_bytes
; // bytes of header already read
581 uint32_t data_bytes
; // bytes of message data already read
582 char *msgbuf
; // pointer to data storage to pass to free()
583 char *msgdata
; // pointer to data to be read from (may be modified)
584 int bufsize
; // size of data storage
586 // reply, termination, error, and client context info
587 int no_reply
; // don't send asynchronous replies to client
588 int time_blocked
; // record time of a blocked client
589 void *client_context
; // don't touch this - pointer only valid in client's addr space
590 struct reply_state
*replies
; // corresponding (active) reply list
591 undelivered_error_t
*u_err
;
592 void *termination_context
;
593 req_termination_fn terminate
;
595 //!!!KRS toss these pointers in a union
596 // registration context associated with this request (null if not applicable)
597 registered_record_entry
*reg_recs
; // muliple registrations for a connection-oriented request
598 service_info
*service_registration
;
599 browser_info_t
*browser_info
;
600 struct request_state
*next
;
603 // struct physically sits between ipc message header and call-specific fields in the message buffer
606 DNSServiceFlags flags
; // Note: This field is in NETWORK byte order
607 uint32_t ifi
; // Note: This field is in NETWORK byte order
608 DNSServiceErrorType error
; // Note: This field is in NETWORK byte order
612 typedef struct reply_state
614 // state of the transmission
619 // context of the reply
620 struct request_state
*request
; // the request that this answers
621 struct reply_state
*next
; // if there are multiple unsent replies
622 // pointer into message buffer - allows fields to be changed after message is formatted
625 char *sdata
; // pointer to start of call-specific data
626 // pointer to malloc'd buffer
631 // domain enumeration and resolv calls require 2 mDNSCore calls, so we need separate interconnected
632 // structures to handle callbacks
635 DNSQuestion question
;
636 mDNS_DomainType type
;
637 request_state
*rstate
;
644 request_state
*rstate
;
645 } enum_termination_t
;
649 request_state
*rstate
;
652 // const ResourceRecord *txt;
653 // const ResourceRecord *srv;
659 mDNSu8 txtdata
[AbsoluteMaxDNSMessageData
];
660 } resolve_termination_t
;
662 #ifdef _HAVE_SETDOMAIN_SUPPORT_
663 typedef struct default_browse_list_t
665 struct default_browse_list_t
*next
;
668 } default_browse_list_t
;
670 static default_browse_list_t
*default_browse_list
= NULL
;
671 #endif // _HAVE_SETDOMAIN_SUPPORT_
674 mDNSexport mDNS mDNSStorage
;
675 #define gmDNS (&mDNSStorage)
677 static dnssd_sock_t listenfd
= dnssd_InvalidSocket
;
678 static request_state
* all_requests
= NULL
;
680 #define MAX_TIME_BLOCKED 60 * mDNSPlatformOneSecond // try to send data to a blocked client for 60 seconds before
681 // terminating connection
682 #define MSG_PAD_BYTES 5 // pad message buffer (read from client) with n zero'd bytes to guarantee
683 // n get_string() calls w/o buffer overrun
684 // private function prototypes
685 static void connect_callback(void *info
);
686 static int read_msg(request_state
*rs
);
687 static int send_msg(reply_state
*rs
);
688 static void abort_request(request_state
*rs
);
689 static void request_callback(void *info
);
690 static void handle_resolve_request(request_state
*rstate
);
691 static void question_result_callback(mDNS
*const m
, DNSQuestion
*question
, const ResourceRecord
*const answer
, mDNSBool AddRecord
);
692 static void question_termination_callback(void *context
);
693 static void handle_browse_request(request_state
*request
);
694 static void browse_termination_callback(void *context
);
695 static void browse_result_callback(mDNS
*const m
, DNSQuestion
*question
, const ResourceRecord
*const answer
, mDNSBool AddRecord
);
696 static void handle_regservice_request(request_state
*request
);
697 static void regservice_termination_callback(void *context
);
698 static void process_service_registration(ServiceRecordSet
*const srs
);
699 static void regservice_callback(mDNS
*const m
, ServiceRecordSet
*const srs
, mStatus result
);
700 static void handle_add_request(request_state
*rstate
);
701 static void handle_update_request(request_state
*rstate
);
702 static mStatus
gen_rr_response(domainname
*servicename
, mDNSInterfaceID id
, request_state
*request
, reply_state
**rep
);
703 static void append_reply(request_state
*req
, reply_state
*rep
);
704 static int build_domainname_from_strings(domainname
*srv
, char *name
, char *regtype
, char *domain
);
705 static void enum_termination_callback(void *context
);
706 static void enum_result_callback(mDNS
*const m
, DNSQuestion
*question
, const ResourceRecord
*const answer
, mDNSBool AddRecord
);
707 static void handle_query_request(request_state
*rstate
);
708 static reply_state
*format_enumeration_reply(request_state
*rstate
, const char *domain
, DNSServiceFlags flags
, uint32_t ifi
, DNSServiceErrorType err
);
709 static void handle_enum_request(request_state
*rstate
);
710 static void handle_regrecord_request(request_state
*rstate
);
711 static void regrecord_callback(mDNS
*const m
, AuthRecord
*const rr
, mStatus result
);
712 static void connected_registration_termination(void *context
);
713 static void handle_reconfirm_request(request_state
*rstate
);
714 static AuthRecord
*read_rr_from_ipc_msg(char *msgbuf
, int ttl
, int validate_flags
);
715 static void handle_removerecord_request(request_state
*rstate
);
716 static void reset_connected_rstate(request_state
*rstate
);
717 static int deliver_error(request_state
*rstate
, mStatus err
);
718 static int deliver_async_error(request_state
*rs
, reply_op_t op
, mStatus err
);
719 static transfer_state
send_undelivered_error(request_state
*rs
);
720 static reply_state
*create_reply(reply_op_t op
, size_t datalen
, request_state
*request
);
721 static void update_callback(mDNS
*const m
, AuthRecord
*const rr
, RData
*oldrd
);
722 static void my_perror(char *errmsg
);
723 static void unlink_request(request_state
*rs
);
724 static void resolve_result_callback(mDNS
*const m
, DNSQuestion
*question
, const ResourceRecord
*const answer
, mDNSBool AddRecord
);
725 static void resolve_termination_callback(void *context
);
726 static int validate_message(request_state
*rstate
);
727 static mStatus
remove_extra(request_state
*rstate
, service_instance
*serv
);
728 static mStatus
remove_record(request_state
*rstate
);
729 static void free_service_instance(service_instance
*srv
);
730 static uint32_t dnssd_htonl(uint32_t l
);
731 static void handle_setdomain_request(request_state
*rstate
);
733 // initialization, setup/teardown functions
735 // If a platform specifies its own PID file name, we use that
737 #define PID_FILE "/var/run/mDNSResponder.pid"
740 int udsserver_init(void)
742 dnssd_sockaddr_t laddr
;
748 // If a particular platform wants to opt out of having a PID file, define PID_FILE to be ""
751 FILE *fp
= fopen(PID_FILE
, "w");
754 fprintf(fp
, "%d\n", getpid());
759 if ((listenfd
= socket(AF_DNSSD
, SOCK_STREAM
, 0)) == dnssd_InvalidSocket
)
762 bzero(&laddr
, sizeof(laddr
));
764 #if defined(USE_TCP_LOOPBACK)
766 laddr
.sin_family
= AF_INET
;
767 laddr
.sin_port
= htons(MDNS_TCP_SERVERPORT
);
768 laddr
.sin_addr
.s_addr
= inet_addr(MDNS_TCP_SERVERADDR
);
769 ret
= bind(listenfd
, (struct sockaddr
*) &laddr
, sizeof(laddr
));
775 mode_t mask
= umask(0);
776 unlink(MDNS_UDS_SERVERPATH
); //OK if this fails
777 laddr
.sun_family
= AF_LOCAL
;
778 # ifndef NOT_HAVE_SA_LEN
779 // According to Stevens (section 3.2), there is no portable way to
780 // determine whether sa_len is defined on a particular platform.
781 laddr
.sun_len
= sizeof(struct sockaddr_un
);
783 strcpy(laddr
.sun_path
, MDNS_UDS_SERVERPATH
);
784 ret
= bind(listenfd
, (struct sockaddr
*) &laddr
, sizeof(laddr
));
793 // SEH: do we even need to do this on windows? this socket
794 // will be given to WSAEventSelect which will automatically
795 // set it to non-blocking
797 if (ioctlsocket(listenfd
, FIONBIO
, &opt
) != 0)
799 if (fcntl(listenfd
, F_SETFL
, O_NONBLOCK
) != 0)
802 my_perror("ERROR: could not set listen socket to non-blocking mode");
806 if (listen(listenfd
, LISTENQ
) != 0)
808 my_perror("ERROR: could not listen on listen socket");
812 if (mStatus_NoError
!= udsSupportAddFDToEventLoop(listenfd
, connect_callback
, (void *) NULL
))
814 my_perror("ERROR: could not add listen socket to event loop");
818 #if !defined(PLATFORM_NO_RLIMIT)
820 // Set maximum number of open file descriptors
821 #define MIN_OPENFILES 10240
822 struct rlimit maxfds
, newfds
;
824 // Due to bugs in OS X (<rdar://problem/2941095>, <rdar://problem/3342704>, <rdar://problem/3839173>)
825 // you have to get and set rlimits once before getrlimit will return sensible values
826 if (getrlimit(RLIMIT_NOFILE
, &maxfds
) < 0) { my_perror("ERROR: Unable to get file descriptor limit"); return 0; }
827 if (setrlimit(RLIMIT_NOFILE
, &maxfds
) < 0) my_perror("ERROR: Unable to set maximum file descriptor limit");
829 if (getrlimit(RLIMIT_NOFILE
, &maxfds
) < 0) { my_perror("ERROR: Unable to get file descriptor limit"); return 0; }
830 newfds
.rlim_max
= (maxfds
.rlim_max
> MIN_OPENFILES
) ? maxfds
.rlim_max
: MIN_OPENFILES
;
831 newfds
.rlim_cur
= (maxfds
.rlim_cur
> MIN_OPENFILES
) ? maxfds
.rlim_cur
: MIN_OPENFILES
;
832 if (newfds
.rlim_max
!= maxfds
.rlim_max
|| newfds
.rlim_cur
!= maxfds
.rlim_cur
)
833 if (setrlimit(RLIMIT_NOFILE
, &newfds
) < 0) my_perror("ERROR: Unable to set maximum file descriptor limit");
835 if (getrlimit(RLIMIT_NOFILE
, &maxfds
) < 0) { my_perror("ERROR: Unable to get file descriptor limit"); return 0; }
836 debugf("maxfds.rlim_max %d", (long)maxfds
.rlim_max
);
837 debugf("maxfds.rlim_cur %d", (long)maxfds
.rlim_cur
);
845 my_perror("ERROR: udsserver_init");
849 int udsserver_exit(void)
851 dnssd_close(listenfd
);
853 #if !defined(USE_TCP_LOOPBACK)
854 unlink(MDNS_UDS_SERVERPATH
);
861 mDNSs32
udsserver_idle(mDNSs32 nextevent
)
863 request_state
*req
= all_requests
, *tmp
, *prev
= NULL
;
865 transfer_state result
;
866 mDNSs32 now
= mDNS_TimeNow(&mDNSStorage
);
870 result
= t_uninitialized
;
872 result
= send_undelivered_error(req
);
873 if (result
!= t_error
&& result
!= t_morecoming
&& // don't try to send msg if send_error failed
874 (req
->ts
== t_complete
|| req
->ts
== t_morecoming
))
878 if (req
->replies
->next
) req
->replies
->rhdr
->flags
|= dnssd_htonl(kDNSServiceFlagsMoreComing
);
879 result
= send_msg(req
->replies
);
880 if (result
== t_complete
)
883 req
->replies
= req
->replies
->next
;
884 freeL("udsserver_idle", fptr
);
885 req
->time_blocked
= 0; // reset failure counter after successful send
887 else if (result
== t_terminated
|| result
== t_error
)
892 else if (result
== t_morecoming
) break; // client's queues are full, move to next
895 if (result
== t_morecoming
)
897 if (!req
->time_blocked
) req
->time_blocked
= now
;
898 debugf("udsserver_idle: client has been blocked for %ld seconds", (now
- req
->time_blocked
) / mDNSPlatformOneSecond
);
899 if (now
- req
->time_blocked
>= MAX_TIME_BLOCKED
)
901 LogMsg("Could not write data to client after %ld seconds - aborting connection", MAX_TIME_BLOCKED
/ mDNSPlatformOneSecond
);
903 result
= t_terminated
;
905 else if (nextevent
- now
> mDNSPlatformOneSecond
) nextevent
= now
+ mDNSPlatformOneSecond
; // try again in a second
907 if (result
== t_terminated
|| result
== t_error
)
908 //since we're already doing a list traversal, we unlink the request manunally instead of calling unlink_request()
911 if (prev
) prev
->next
= req
->next
;
912 if (req
== all_requests
) all_requests
= all_requests
->next
;
914 freeL("udsserver_idle", tmp
);
925 void udsserver_info(mDNS
*const m
)
927 mDNSs32 now
= mDNS_TimeNow(m
);
928 mDNSu32 CacheUsed
= 0, CacheActive
= 0;
932 LogMsgNoIdent("Timenow 0x%08lX (%ld)", (mDNSu32
)now
, now
);
934 for (slot
= 0; slot
< CACHE_HASH_SLOTS
; slot
++)
936 mDNSu32 SlotUsed
= 0;
938 for (rr
= m
->rrcache_hash
[slot
]; rr
; rr
=rr
->next
)
940 mDNSs32 remain
= rr
->resrec
.rroriginalttl
- (now
- rr
->TimeRcvd
) / mDNSPlatformOneSecond
;
943 if (rr
->CRActiveQuestion
) CacheActive
++;
944 LogMsgNoIdent("%s%6ld %s%-6s%-6s%s",
945 rr
->CRActiveQuestion
? "*" : " ", remain
,
946 (rr
->resrec
.RecordType
& kDNSRecordTypePacketUniqueMask
) ? "-" : " ", DNSTypeName(rr
->resrec
.rrtype
),
947 ((NetworkInterfaceInfo
*)rr
->resrec
.InterfaceID
)->ifname
, CRDisplayString(m
, rr
));
948 usleep(1000); // Limit rate a little so we don't flood syslog too fast
950 if (m
->rrcache_used
[slot
] != SlotUsed
)
951 LogMsgNoIdent("Cache use mismatch: rrcache_used[slot] is %lu, true count %lu", m
->rrcache_used
[slot
], SlotUsed
);
953 if (m
->rrcache_totalused
!= CacheUsed
)
954 LogMsgNoIdent("Cache use mismatch: rrcache_totalused is %lu, true count %lu", m
->rrcache_totalused
, CacheUsed
);
955 if (m
->rrcache_active
!= CacheActive
)
956 LogMsgNoIdent("Cache use mismatch: rrcache_active is %lu, true count %lu", m
->rrcache_active
, CacheActive
);
957 LogMsgNoIdent("Cache currently contains %lu records; %lu referenced by active questions", CacheUsed
, CacheActive
);
959 for (req
= all_requests
; req
; req
=req
->next
)
961 void *t
= req
->termination_context
;
963 if (req
->terminate
== regservice_termination_callback
)
965 service_instance
*ptr
;
966 for (ptr
= ((service_info
*)t
)->instances
; ptr
; ptr
= ptr
->next
)
967 LogMsgNoIdent("DNSServiceRegister %##s %u", ptr
->srs
.RR_SRV
.resrec
.name
.c
, SRS_PORT(&ptr
->srs
));
969 else if (req
->terminate
== browse_termination_callback
)
972 for (blist
= req
->browser_info
->browsers
; blist
; blist
= blist
->next
)
973 LogMsgNoIdent("DNSServiceBrowse %##s", blist
->q
.qname
.c
);
975 else if (req
->terminate
== resolve_termination_callback
)
976 LogMsgNoIdent("DNSServiceResolve %##s", ((resolve_termination_t
*)t
)->qsrv
.qname
.c
);
977 else if (req
->terminate
== question_termination_callback
)
978 LogMsgNoIdent("DNSServiceQueryRecord %##s", ((DNSQuestion
*) t
)->qname
.c
);
979 else if (req
->terminate
== enum_termination_callback
)
980 LogMsgNoIdent("DNSServiceEnumerateDomains %##s", ((enum_termination_t
*) t
)->all
->question
.qname
.c
);
983 now
= mDNS_TimeNow(m
);
984 LogMsgNoIdent("Timenow 0x%08lX (%ld)", (mDNSu32
)now
, now
);
987 static void rename_service(service_instance
*srv
)
989 if (srv
->autoname
&& !SameDomainLabel(srv
->name
.c
, gmDNS
->nicelabel
.c
))
991 srv
->rename_on_memfree
= 1;
992 if (mDNS_DeregisterService(gmDNS
, &srv
->srs
)) // If service deregistered already, we can re-register immediately
993 regservice_callback(gmDNS
, &srv
->srs
, mStatus_MemFree
);
997 void udsserver_handle_configchange(void)
1002 for (req
= all_requests
; req
; req
= req
->next
)
1004 if (req
->service_registration
)
1006 service_instance
*ptr
;
1007 for (ptr
= req
->service_registration
->instances
; ptr
; ptr
= ptr
->next
)
1008 rename_service(ptr
);
1013 static void connect_callback(void *info
)
1017 unsigned long optval
;
1018 dnssd_sockaddr_t cliaddr
;
1019 request_state
*rstate
;
1020 (void)info
; // Unused
1022 len
= (int) sizeof(cliaddr
);
1024 sd
= accept(listenfd
, (struct sockaddr
*) &cliaddr
, &len
);
1026 if (sd
== dnssd_InvalidSocket
)
1028 if (dnssd_errno() == dnssd_EWOULDBLOCK
) return;
1029 my_perror("ERROR: accept");
1035 // Some environments (e.g. OS X) support turning off SIGPIPE for a socket
1036 if (setsockopt(sd
, SOL_SOCKET
, SO_NOSIGPIPE
, &optval
, sizeof(optval
)) < 0)
1038 my_perror("ERROR: setsockopt - SOL_NOSIGPIPE - aborting client");
1045 if (ioctlsocket(sd
, FIONBIO
, &optval
) != 0)
1047 if (fcntl(sd
, F_SETFL
, O_NONBLOCK
) != 0)
1050 my_perror("ERROR: setsockopt - SOL_NOSIGPIPE - aborting client");
1055 // allocate a request_state struct that will live with the socket
1056 rstate
= mallocL("connect_callback", sizeof(request_state
));
1059 my_perror("ERROR: malloc");
1062 bzero(rstate
, sizeof(request_state
));
1063 rstate
->ts
= t_morecoming
;
1066 LogOperation("%3d: Adding FD", rstate
->sd
);
1067 if ( mStatus_NoError
!= udsSupportAddFDToEventLoop( sd
, request_callback
, rstate
))
1069 rstate
->next
= all_requests
;
1070 all_requests
= rstate
;
1075 static void request_callback(void *info
)
1077 request_state
*rstate
= info
;
1078 transfer_state result
;
1079 dnssd_sockaddr_t cliaddr
;
1084 result
= read_msg(rstate
);
1085 if (result
== t_morecoming
)
1089 if (result
== t_terminated
)
1091 abort_request(rstate
);
1092 unlink_request(rstate
);
1095 if (result
== t_error
)
1097 abort_request(rstate
);
1098 unlink_request(rstate
);
1102 if (rstate
->hdr
.version
!= VERSION
)
1104 LogMsg("ERROR: client incompatible with daemon (client version = %d, "
1105 "daemon version = %d)\n", rstate
->hdr
.version
, VERSION
);
1106 abort_request(rstate
);
1107 unlink_request(rstate
);
1111 if (validate_message(rstate
) < 0)
1113 // note that we cannot deliver an error message if validation fails, since the path to the error socket
1114 // may be contained in the (invalid) message body for some message types
1115 abort_request(rstate
);
1116 unlink_request(rstate
);
1117 LogMsg("Invalid message sent by client - may indicate a malicious program running on this machine!");
1121 // check if client wants silent operation
1122 if (rstate
->hdr
.flags
& IPC_FLAGS_NOREPLY
) rstate
->no_reply
= 1;
1124 // check if primary socket is to be used for synchronous errors, else open new socket
1125 if (rstate
->hdr
.flags
& IPC_FLAGS_REUSE_SOCKET
)
1126 rstate
->errfd
= rstate
->sd
;
1129 if ((rstate
->errfd
= socket(AF_DNSSD
, SOCK_STREAM
, 0)) == dnssd_InvalidSocket
)
1131 my_perror("ERROR: socket");
1135 #if defined(USE_TCP_LOOPBACK)
1138 port
.b
[0] = rstate
->msgdata
[0];
1139 port
.b
[1] = rstate
->msgdata
[1];
1140 rstate
->msgdata
+= 2;
1141 cliaddr
.sin_family
= AF_INET
;
1142 cliaddr
.sin_port
= port
.NotAnInteger
;
1143 cliaddr
.sin_addr
.s_addr
= inet_addr(MDNS_TCP_SERVERADDR
);
1147 char ctrl_path
[MAX_CTLPATH
];
1148 get_string(&rstate
->msgdata
, ctrl_path
, 256); // path is first element in message buffer
1149 bzero(&cliaddr
, sizeof(cliaddr
));
1150 cliaddr
.sun_family
= AF_LOCAL
;
1151 strcpy(cliaddr
.sun_path
, ctrl_path
);
1154 if (connect(rstate
->errfd
, (struct sockaddr
*)&cliaddr
, sizeof(cliaddr
)) < 0)
1156 my_perror("ERROR: connect");
1157 abort_request(rstate
);
1158 unlink_request(rstate
);
1162 if (ioctlsocket(rstate
->errfd
, FIONBIO
, &opt
) != 0)
1164 if (fcntl(rstate
->errfd
, F_SETFL
, O_NONBLOCK
) != 0)
1167 my_perror("ERROR: could not set control socket to non-blocking mode");
1168 abort_request(rstate
);
1169 unlink_request(rstate
);
1174 switch(rstate
->hdr
.op
)
1176 case resolve_request
: handle_resolve_request(rstate
); break;
1177 case query_request
: handle_query_request(rstate
); break;
1178 case browse_request
: handle_browse_request(rstate
); break;
1179 case reg_service_request
: handle_regservice_request(rstate
); break;
1180 case enumeration_request
: handle_enum_request(rstate
); break;
1181 case reg_record_request
: handle_regrecord_request(rstate
); break;
1182 case add_record_request
: handle_add_request(rstate
); break;
1183 case update_record_request
: handle_update_request(rstate
); break;
1184 case remove_record_request
: handle_removerecord_request(rstate
); break;
1185 case reconfirm_record_request
: handle_reconfirm_request(rstate
); break;
1186 case setdomain_request
: handle_setdomain_request(rstate
); break;
1188 LogMsg("%3d: ERROR: udsserver_recv_request - unsupported request type: %d", rstate
->sd
, rstate
->hdr
.op
);
1192 // mDNS operation functions. Each operation has 3 associated functions - a request handler that parses
1193 // the client's request and makes the appropriate mDNSCore call, a result handler (passed as a callback
1194 // to the mDNSCore routine) that sends results back to the client, and a termination routine that aborts
1195 // the mDNSCore operation if the client dies or closes its socket.
1198 // query and resolve calls have separate request handlers that parse the arguments from the client and
1199 // massage the name parameters appropriately, but the rest of the operations (making the query call,
1200 // delivering the result to the client, and termination) are identical.
1202 static void handle_query_request(request_state
*rstate
)
1204 DNSServiceFlags flags
;
1207 uint16_t rrtype
, rrclass
;
1210 mDNSInterfaceID InterfaceID
;
1213 if (rstate
->ts
!= t_complete
)
1215 LogMsg("ERROR: handle_query_request - transfer state != t_complete");
1218 ptr
= rstate
->msgdata
;
1221 LogMsg("ERROR: handle_query_request - NULL msgdata");
1225 flags
= get_flags(&ptr
);
1226 ifi
= get_long(&ptr
);
1227 if (get_string(&ptr
, name
, 256) < 0) goto bad_param
;
1228 rrtype
= get_short(&ptr
);
1229 rrclass
= get_short(&ptr
);
1230 InterfaceID
= mDNSPlatformInterfaceIDfromInterfaceIndex(gmDNS
, ifi
);
1231 if (ifi
&& !InterfaceID
) goto bad_param
;
1233 q
= mallocL("DNSQuestion", sizeof(DNSQuestion
));
1236 my_perror("ERROR: handle_query - malloc");
1239 bzero(q
, sizeof(DNSQuestion
));
1241 q
->InterfaceID
= InterfaceID
;
1242 q
->Target
= zeroAddr
;
1243 if (!MakeDomainNameFromDNSNameString(&q
->qname
, name
)) { freeL("DNSQuestion", q
); goto bad_param
; }
1245 q
->qclass
= rrclass
;
1246 q
->LongLived
= (flags
& kDNSServiceFlagsLongLivedQuery
) != 0;
1247 q
->ExpectUnique
= mDNSfalse
;
1248 q
->ForceMCast
= (flags
& kDNSServiceFlagsForceMulticast
) != 0;
1249 q
->QuestionCallback
= question_result_callback
;
1250 q
->QuestionContext
= rstate
;
1252 rstate
->termination_context
= q
;
1253 rstate
->terminate
= question_termination_callback
;
1255 LogOperation("%3d: DNSServiceQueryRecord(%##s, %s) START", rstate
->sd
, q
->qname
.c
, DNSTypeName(q
->qtype
));
1256 result
= mDNS_StartQuery(gmDNS
, q
);
1257 if (result
!= mStatus_NoError
) LogMsg("ERROR: mDNS_StartQuery: %d", (int)result
);
1259 if (result
) rstate
->terminate
= NULL
;
1260 if (deliver_error(rstate
, result
) < 0) goto error
;
1264 deliver_error(rstate
, mStatus_BadParamErr
);
1265 rstate
->terminate
= NULL
; // don't try to terminate insuccessful Core calls
1267 abort_request(rstate
);
1268 unlink_request(rstate
);
1272 static void handle_resolve_request(request_state
*rstate
)
1274 DNSServiceFlags flags
;
1275 uint32_t interfaceIndex
;
1276 mDNSInterfaceID InterfaceID
;
1277 char name
[256], regtype
[MAX_ESCAPED_DOMAIN_NAME
], domain
[MAX_ESCAPED_DOMAIN_NAME
];
1278 char *ptr
; // message data pointer
1280 resolve_termination_t
*term
;
1283 if (rstate
->ts
!= t_complete
)
1285 LogMsg("ERROR: handle_resolve_request - transfer state != t_complete");
1286 abort_request(rstate
);
1287 unlink_request(rstate
);
1291 // extract the data from the message
1292 ptr
= rstate
->msgdata
;
1295 LogMsg("ERROR: handle_resolve_request - NULL msgdata");
1296 abort_request(rstate
);
1297 unlink_request(rstate
);
1300 flags
= get_flags(&ptr
);
1301 interfaceIndex
= get_long(&ptr
);
1302 InterfaceID
= mDNSPlatformInterfaceIDfromInterfaceIndex(gmDNS
, interfaceIndex
);
1303 if (interfaceIndex
&& !InterfaceID
)
1304 { LogMsg("ERROR: handle_resolve_request - Couldn't find InterfaceID for interfaceIndex %d", interfaceIndex
); goto bad_param
; }
1305 if (get_string(&ptr
, name
, 256) < 0 ||
1306 get_string(&ptr
, regtype
, MAX_ESCAPED_DOMAIN_NAME
) < 0 ||
1307 get_string(&ptr
, domain
, MAX_ESCAPED_DOMAIN_NAME
) < 0)
1308 { LogMsg("ERROR: handle_resolve_request - Couldn't read name/regtype/domain"); goto bad_param
; }
1310 // free memory in rstate since we don't need it anymore
1311 freeL("handle_resolve_request", rstate
->msgbuf
);
1312 rstate
->msgbuf
= NULL
;
1314 if (build_domainname_from_strings(&fqdn
, name
, regtype
, domain
) < 0)
1315 { LogMsg("ERROR: handle_resolve_request - Couldn't build_domainname_from_strings “%s” “%s” “%s”", name
, regtype
, domain
); goto bad_param
; }
1317 // set up termination info
1318 term
= mallocL("handle_resolve_request", sizeof(resolve_termination_t
));
1319 bzero(term
, sizeof(*term
));
1320 if (!term
) goto malloc_error
;
1323 term
->qsrv
.InterfaceID
= InterfaceID
;
1324 term
->qsrv
.Target
= zeroAddr
;
1325 memcpy(&term
->qsrv
.qname
, &fqdn
, MAX_DOMAIN_NAME
);
1326 term
->qsrv
.qtype
= kDNSType_SRV
;
1327 term
->qsrv
.qclass
= kDNSClass_IN
;
1328 term
->qsrv
.LongLived
= mDNSfalse
;
1329 term
->qsrv
.ExpectUnique
= mDNStrue
;
1330 term
->qsrv
.ForceMCast
= mDNSfalse
;
1331 term
->qsrv
.QuestionCallback
= resolve_result_callback
;
1332 term
->qsrv
.QuestionContext
= rstate
;
1334 term
->qtxt
.InterfaceID
= InterfaceID
;
1335 term
->qtxt
.Target
= zeroAddr
;
1336 memcpy(&term
->qtxt
.qname
, &fqdn
, MAX_DOMAIN_NAME
);
1337 term
->qtxt
.qtype
= kDNSType_TXT
;
1338 term
->qtxt
.qclass
= kDNSClass_IN
;
1339 term
->qtxt
.LongLived
= mDNSfalse
;
1340 term
->qtxt
.ExpectUnique
= mDNStrue
;
1341 term
->qtxt
.ForceMCast
= mDNSfalse
;
1342 term
->qtxt
.QuestionCallback
= resolve_result_callback
;
1343 term
->qtxt
.QuestionContext
= rstate
;
1345 term
->rstate
= rstate
;
1346 rstate
->termination_context
= term
;
1347 rstate
->terminate
= resolve_termination_callback
;
1349 // ask the questions
1350 LogOperation("%3d: DNSServiceResolve(%##s) START", rstate
->sd
, term
->qsrv
.qname
.c
);
1351 err
= mDNS_StartQuery(gmDNS
, &term
->qsrv
);
1352 if (!err
) err
= mDNS_StartQuery(gmDNS
, &term
->qtxt
);
1356 freeL("handle_resolve_request", term
);
1357 rstate
->terminate
= NULL
; // prevent abort_request() from invoking termination callback
1359 if (deliver_error(rstate
, err
) < 0 || err
)
1361 abort_request(rstate
);
1362 unlink_request(rstate
);
1367 deliver_error(rstate
, mStatus_BadParamErr
);
1368 abort_request(rstate
);
1369 unlink_request(rstate
);
1373 my_perror("ERROR: malloc");
1377 static void resolve_termination_callback(void *context
)
1379 resolve_termination_t
*term
= context
;
1384 LogMsg("ERROR: resolve_termination_callback: double termination");
1388 LogOperation("%3d: DNSServiceResolve(%##s) STOP", rs
->sd
, term
->qtxt
.qname
.c
);
1390 mDNS_StopQuery(gmDNS
, &term
->qtxt
);
1391 mDNS_StopQuery(gmDNS
, &term
->qsrv
);
1393 freeL("resolve_termination_callback", term
);
1394 rs
->termination_context
= NULL
;
1397 static void resolve_result_callback(mDNS
*const m
, DNSQuestion
*question
, const ResourceRecord
*const answer
, mDNSBool AddRecord
)
1400 char fullname
[MAX_ESCAPED_DOMAIN_NAME
], target
[MAX_ESCAPED_DOMAIN_NAME
];
1402 transfer_state result
;
1404 request_state
*rs
= question
->QuestionContext
;
1405 resolve_termination_t
*res
= rs
->termination_context
;
1408 LogOperation("%3d: DNSServiceResolve(%##s, %s) RESULT %s", rs
->sd
, question
->qname
.c
, DNSTypeName(question
->qtype
), RRDisplayString(m
, answer
));
1410 // This code used to do this trick of just keeping a copy of the pointer to
1411 // the answer record in the cache, but the unicast query code doesn't currently
1412 // put its answer records in the cache, so for now we can't do this.
1416 // if (answer->rrtype == kDNSType_TXT && res->txt == answer) res->txt = mDNSNULL;
1417 // if (answer->rrtype == kDNSType_SRV && res->srv == answer) res->srv = mDNSNULL;
1421 // if (answer->rrtype == kDNSType_TXT) res->txt = answer;
1422 // if (answer->rrtype == kDNSType_SRV) res->srv = answer;
1424 if (answer
->rrtype
== kDNSType_SRV
)
1426 AssignDomainName(res
->target
, answer
->rdata
->u
.srv
.target
);
1427 res
->port
= answer
->rdata
->u
.srv
.port
;
1428 res
->srv
= mDNStrue
;
1430 if (answer
->rrtype
== kDNSType_TXT
)
1432 if (answer
->rdlength
> AbsoluteMaxDNSMessageData
) return;
1433 res
->txtlen
= answer
->rdlength
;
1434 mDNSPlatformMemCopy(answer
->rdata
->u
.data
, res
->txtdata
, res
->txtlen
);
1435 res
->txt
= mDNStrue
;
1438 if (!res
->txt
|| !res
->srv
) return; // only deliver result to client if we have both answers
1440 ConvertDomainNameToCString(&answer
->name
, fullname
);
1441 ConvertDomainNameToCString(&res
->target
, target
);
1443 // calculate reply length
1444 len
+= sizeof(DNSServiceFlags
);
1445 len
+= sizeof(uint32_t); // interface index
1446 len
+= sizeof(DNSServiceErrorType
);
1447 len
+= strlen(fullname
) + 1;
1448 len
+= strlen(target
) + 1;
1449 len
+= 2 * sizeof(uint16_t); // port, txtLen
1452 // allocate/init reply header
1453 rep
= create_reply(resolve_reply
, len
, rs
);
1454 rep
->rhdr
->flags
= dnssd_htonl(0);
1455 rep
->rhdr
->ifi
= dnssd_htonl(mDNSPlatformInterfaceIndexfromInterfaceID(gmDNS
, answer
->InterfaceID
));
1456 rep
->rhdr
->error
= dnssd_htonl(kDNSServiceErr_NoError
);
1460 // write reply data to message
1461 put_string(fullname
, &data
);
1462 put_string(target
, &data
);
1463 *data
++ = res
->port
.b
[0];
1464 *data
++ = res
->port
.b
[1];
1465 put_short(res
->txtlen
, &data
);
1466 put_rdata(res
->txtlen
, res
->txtdata
, &data
);
1468 result
= send_msg(rep
);
1469 if (result
== t_error
|| result
== t_terminated
)
1473 freeL("resolve_result_callback", rep
);
1475 else if (result
== t_complete
) freeL("resolve_result_callback", rep
);
1476 else append_reply(rs
, rep
);
1479 // what gets called when a resolve is completed and we need to send the data back to the client
1480 static void question_result_callback(mDNS
*const m
, DNSQuestion
*question
, const ResourceRecord
*const answer
, mDNSBool AddRecord
)
1483 char name
[MAX_ESCAPED_DOMAIN_NAME
];
1484 request_state
*req
= question
->QuestionContext
;
1489 LogOperation("%3d: DNSServiceQueryRecord(%##s, %s) RESULT %s", req
->sd
, question
->qname
.c
, DNSTypeName(question
->qtype
), RRDisplayString(m
, answer
));
1490 //mDNS_StopQuery(m, question);
1492 // calculate reply data length
1493 len
= sizeof(DNSServiceFlags
);
1494 len
+= 2 * sizeof(uint32_t); // if index + ttl
1495 len
+= sizeof(DNSServiceErrorType
);
1496 len
+= 3 * sizeof(uint16_t); // type, class, rdlen
1497 len
+= answer
->rdlength
;
1498 ConvertDomainNameToCString(&answer
->name
, name
);
1499 len
+= strlen(name
) + 1;
1501 rep
= create_reply(query_reply
, len
, req
);
1503 rep
->rhdr
->flags
= dnssd_htonl(AddRecord
? kDNSServiceFlagsAdd
: 0);
1504 rep
->rhdr
->ifi
= dnssd_htonl(mDNSPlatformInterfaceIndexfromInterfaceID(gmDNS
, answer
->InterfaceID
));
1505 rep
->rhdr
->error
= dnssd_htonl(kDNSServiceErr_NoError
);
1509 put_string(name
, &data
);
1510 put_short(answer
->rrtype
, &data
);
1511 put_short(answer
->rrclass
, &data
);
1512 put_short(answer
->rdlength
, &data
);
1513 put_rdata(answer
->rdlength
, (char *)&answer
->rdata
->u
, &data
);
1514 put_long(AddRecord
? answer
->rroriginalttl
: 0, &data
);
1516 append_reply(req
, rep
);
1520 static void question_termination_callback(void *context
)
1522 DNSQuestion
*q
= context
;
1523 LogOperation("%3d: DNSServiceQueryRecord(%##s, %s) STOP", ((request_state
*)q
->QuestionContext
)->sd
, q
->qname
.c
, DNSTypeName(q
->qtype
));
1524 mDNS_StopQuery(gmDNS
, q
); // no need to error check
1525 freeL("question_termination_callback", q
);
1528 // If there's a comma followed by another character,
1529 // FindFirstSubType overwrites the comma with a nul and returns the pointer to the next character.
1530 // Otherwise, it returns a pointer to the final nul at the end of the string
1531 static char *FindFirstSubType(char *p
)
1535 if (p
[0] == '\\' && p
[1]) p
+= 2;
1536 else if (p
[0] == ',' && p
[1]) { *p
++ = 0; return(p
); }
1542 // If there's a comma followed by another character,
1543 // FindNextSubType overwrites the comma with a nul and returns the pointer to the next character.
1544 // If it finds an illegal unescaped dot in the subtype name, it returns mDNSNULL
1545 // Otherwise, it returns a pointer to the final nul at the end of the string
1546 static char *FindNextSubType(char *p
)
1550 if (p
[0] == '\\' && p
[1]) // If escape character
1551 p
+= 2; // ignore following character
1552 else if (p
[0] == ',') // If we found a comma
1557 else if (p
[0] == '.')
1564 // Returns -1 if illegal subtype found
1565 mDNSexport mDNSs32
ChopSubTypes(char *regtype
)
1567 mDNSs32 NumSubTypes
= 0;
1568 char *stp
= FindFirstSubType(regtype
);
1569 while (stp
&& *stp
) // If we found a comma...
1571 if (*stp
== ',') return(-1);
1573 stp
= FindNextSubType(stp
);
1575 if (!stp
) return(-1);
1576 return(NumSubTypes
);
1579 mDNSexport AuthRecord
*AllocateSubTypes(mDNSs32 NumSubTypes
, char *p
)
1581 AuthRecord
*st
= mDNSNULL
;
1585 st
= mallocL("ServiceSubTypes", NumSubTypes
* sizeof(AuthRecord
));
1586 if (!st
) return(mDNSNULL
);
1587 for (i
= 0; i
< NumSubTypes
; i
++)
1591 if (!MakeDomainNameFromDNSNameString(&st
[i
].resrec
.name
, p
))
1592 { freeL("ServiceSubTypes", st
); return(mDNSNULL
); }
1599 #ifdef _HAVE_SETDOMAIN_SUPPORT_
1600 static void free_defdomain(mDNS
*const m
, AuthRecord
*const rr
, mStatus result
)
1603 if (result
== mStatus_MemFree
) free(rr
->RecordContext
); // context is the enclosing list structure
1607 static void handle_setdomain_request(request_state
*request
)
1609 mStatus err
= mStatus_NoError
;
1611 char domainstr
[MAX_ESCAPED_DOMAIN_NAME
];
1613 DNSServiceFlags flags
;
1614 #ifdef _HAVE_SETDOMAIN_SUPPORT_
1619 if (request
->ts
!= t_complete
)
1621 LogMsg("ERROR: handle_setdomain_request - transfer state != t_complete");
1622 abort_request(request
);
1623 unlink_request(request
);
1627 // extract flags/domain from message
1628 ptr
= request
->msgdata
;
1629 flags
= get_flags(&ptr
);
1630 if (get_string(&ptr
, domainstr
, MAX_ESCAPED_DOMAIN_NAME
) < 0 ||
1631 !MakeDomainNameFromDNSNameString(&domain
, domainstr
))
1632 { err
= mStatus_BadParamErr
; goto end
; }
1634 freeL("handle_setdomain_request", request
->msgbuf
);
1635 request
->msgbuf
= NULL
;
1637 debugf("%3d: DNSServiceSetDefaultDomainForUser(%##s)", request
->sd
, domain
.c
);
1639 #ifdef _HAVE_SETDOMAIN_SUPPORT_
1640 // this functionality currently only used for Apple-specific configuration, so we don't burned other platforms by mandating
1641 // the existence of this socket option
1642 xuclen
= sizeof(xuc
);
1643 if (getsockopt(request
->sd
, 0, LOCAL_PEERCRED
, &xuc
, &xuclen
))
1644 { my_perror("ERROR: getsockopt, LOCAL_PEERCRED"); err
= mStatus_UnknownErr
; goto end
; }
1645 if (xuc
.cr_version
!= XUCRED_VERSION
) { LogMsg("getsockopt, LOCAL_PEERCRED - bad version"); err
= mStatus_UnknownErr
; goto end
; }
1646 LogMsg("Default domain %s %s for UID %d", domainstr
, flags
& kDNSServiceFlagsAdd
? "set" : "removed", xuc
.cr_uid
);
1648 if (flags
& kDNSServiceFlagsAdd
)
1650 // register a local-only PRT record
1651 default_browse_list_t
*newelem
= malloc(sizeof(default_browse_list_t
));
1652 if (!newelem
) { LogMsg("ERROR: malloc"); err
= mStatus_NoMemoryErr
; goto end
; }
1653 mDNS_SetupResourceRecord(&newelem
->ptr_rec
, mDNSNULL
, mDNSInterface_LocalOnly
, kDNSType_PTR
, 7200, kDNSRecordTypeShared
, free_defdomain
, newelem
);
1654 MakeDomainNameFromDNSNameString(&newelem
->ptr_rec
.resrec
.name
, "_default._browse._dns-sd._udp.local.");
1655 AssignDomainName(newelem
->ptr_rec
.resrec
.rdata
->u
.name
, domain
);
1656 newelem
->uid
= xuc
.cr_uid
;
1657 err
= mDNS_Register(gmDNS
, &newelem
->ptr_rec
);
1658 if (err
) free(newelem
);
1662 newelem
->next
= default_browse_list
;
1663 default_browse_list
= newelem
;
1669 // remove - find in list, deregister
1670 default_browse_list_t
*ptr
= default_browse_list
, *prev
= NULL
;
1673 if (SameDomainName(&ptr
->ptr_rec
.resrec
.rdata
->u
.name
, &domain
))
1675 if (prev
) prev
->next
= ptr
->next
;
1676 else default_browse_list
= ptr
->next
;
1677 err
= mDNS_Deregister(gmDNS
, &ptr
->ptr_rec
);
1683 if (!ptr
) { LogMsg("Attempt to remove nonexistent domain %s for UID %d", domainstr
, xuc
.cr_uid
); err
= mStatus_Invalid
; }
1686 err
= mStatus_NoError
;
1687 #endif // _HAVE_SETDOMAIN_SUPPORT_
1690 deliver_error(request
, err
);
1691 abort_request(request
);
1692 unlink_request(request
);
1695 static mStatus
add_domain_to_browser(browser_info_t
*info
, const domainname
*d
)
1700 for (p
= info
->browsers
; p
; p
= p
->next
)
1702 if (SameDomainName(&p
->domain
, d
))
1703 { LogMsg("add_domain_to_browser - attempt to add domain %##d already in list", d
->c
); return mStatus_AlreadyRegistered
; }
1706 b
= mallocL("browser_t", sizeof(*b
));
1707 if (!b
) return mStatus_NoMemoryErr
;
1708 AssignDomainName(b
->domain
, *d
);
1709 err
= mDNS_StartBrowse(gmDNS
, &b
->q
, &info
->regtype
, d
, info
->interface_id
, info
->ForceMCast
, browse_result_callback
, info
->rstate
);
1712 LogMsg("mDNS_StartBrowse returned %d for type %##s domain %##s", err
, info
->regtype
.c
, d
->c
);
1713 freeL("browser_t", b
);
1717 b
->next
= info
->browsers
;
1723 static void handle_browse_request(request_state
*request
)
1725 DNSServiceFlags flags
;
1726 uint32_t interfaceIndex
;
1727 mDNSInterfaceID InterfaceID
;
1728 char regtype
[MAX_ESCAPED_DOMAIN_NAME
], domain
[MAX_ESCAPED_DOMAIN_NAME
];
1729 domainname typedn
, d
, temp
;
1730 mDNSs32 NumSubTypes
;
1733 DNameListElem
*search_domain_list
, *sdom
;
1734 browser_info_t
*info
= NULL
;
1736 if (request
->ts
!= t_complete
)
1738 LogMsg("ERROR: handle_browse_request - transfer state != t_complete");
1739 abort_request(request
);
1740 unlink_request(request
);
1744 // extract data from message
1745 ptr
= request
->msgdata
;
1746 flags
= get_flags(&ptr
);
1747 interfaceIndex
= get_long(&ptr
);
1748 if (get_string(&ptr
, regtype
, MAX_ESCAPED_DOMAIN_NAME
) < 0 ||
1749 get_string(&ptr
, domain
, MAX_ESCAPED_DOMAIN_NAME
) < 0)
1750 { err
= mStatus_BadParamErr
; goto error
; }
1751 freeL("handle_browse_request", request
->msgbuf
);
1752 request
->msgbuf
= NULL
;
1754 InterfaceID
= mDNSPlatformInterfaceIDfromInterfaceIndex(gmDNS
, interfaceIndex
);
1755 if (interfaceIndex
&& !InterfaceID
) { err
= mStatus_BadParamErr
; goto error
; }
1758 NumSubTypes
= ChopSubTypes(regtype
); // Note: Modifies regtype string to remove trailing subtypes
1759 if (NumSubTypes
< 0 || NumSubTypes
> 1) { err
= mStatus_BadParamErr
; goto error
; }
1760 if (NumSubTypes
== 1 && !AppendDNSNameString(&typedn
, regtype
+ strlen(regtype
) + 1))
1761 { err
= mStatus_BadParamErr
; goto error
; }
1763 if (!regtype
[0] || !AppendDNSNameString(&typedn
, regtype
)) { err
= mStatus_BadParamErr
; goto error
; }
1765 if (!MakeDomainNameFromDNSNameString(&temp
, regtype
)) { err
= mStatus_BadParamErr
; goto error
; }
1766 if (temp
.c
[0] > 15 && domain
[0] == 0) strcpy(domain
, "local."); // For over-long service types, we only allow domain "local"
1768 // allocate and set up browser info
1769 info
= mallocL("browser_info_t", sizeof(*info
));
1770 if (!info
) { err
= mStatus_NoMemoryErr
; goto error
; }
1772 request
->browser_info
= info
;
1773 info
->ForceMCast
= (flags
& kDNSServiceFlagsForceMulticast
) != 0;
1774 info
->interface_id
= InterfaceID
;
1775 AssignDomainName(info
->regtype
, typedn
);
1776 info
->rstate
= request
;
1777 info
->default_domain
= !domain
[0];
1778 info
->browsers
= NULL
;
1780 // setup termination context
1781 request
->termination_context
= info
;
1782 request
->terminate
= browse_termination_callback
;
1784 LogOperation("%3d: DNSServiceBrowse(%##s%s) START", request
->sd
, info
->regtype
.c
, domain
);
1787 if (!MakeDomainNameFromDNSNameString(&d
, domain
)) { err
= mStatus_BadParamErr
; goto error
; }
1788 err
= add_domain_to_browser(info
, &d
);
1793 search_domain_list
= mDNSPlatformGetSearchDomainList();
1794 for (sdom
= search_domain_list
; sdom
; sdom
= sdom
->next
)
1796 err
= add_domain_to_browser(info
, &sdom
->name
);
1799 if (SameDomainName(&sdom
->name
, &localdomain
)) break;
1800 else err
= mStatus_NoError
; // suppress errors for non-local "default" domains
1804 mDNS_FreeDNameList(search_domain_list
);
1807 deliver_error(request
, mStatus_NoError
);
1811 if (info
) freeL("browser_info_t", info
);
1812 if (request
->termination_context
) request
->termination_context
= NULL
;
1813 deliver_error(request
, err
);
1814 abort_request(request
);
1815 unlink_request(request
);
1818 static void browse_result_callback(mDNS
*const m
, DNSQuestion
*question
, const ResourceRecord
*const answer
, mDNSBool AddRecord
)
1820 request_state
*req
= question
->QuestionContext
;
1824 LogOperation("%3d: DNSServiceBrowse(%##s, %s) RESULT %s", req
->sd
, question
->qname
.c
, DNSTypeName(question
->qtype
), RRDisplayString(m
, answer
));
1826 err
= gen_rr_response(&answer
->rdata
->u
.name
, answer
->InterfaceID
, req
, &rep
);
1829 if (deliver_async_error(req
, browse_reply
, err
) < 0)
1832 unlink_request(req
);
1836 if (AddRecord
) rep
->rhdr
->flags
|= dnssd_htonl(kDNSServiceFlagsAdd
); // non-zero TTL indicates add
1837 append_reply(req
, rep
);
1841 static void browse_termination_callback(void *context
)
1843 browser_info_t
*info
= context
;
1848 while(info
->browsers
)
1850 ptr
= info
->browsers
;
1851 info
->browsers
= ptr
->next
;
1852 LogOperation("%3d: DNSServiceBrowse(%##s) STOP", info
->rstate
->sd
, ptr
->q
.qname
.c
);
1853 mDNS_StopBrowse(gmDNS
, &ptr
->q
); // no need to error-check result
1854 freeL("browse_termination_callback", ptr
);
1857 info
->rstate
->termination_context
= NULL
;
1858 freeL("browser_info", info
);
1861 mDNSexport
void udsserver_default_browse_domain_changed(const domainname
*d
, mDNSBool add
)
1865 for (r
= all_requests
; r
; r
= r
->next
)
1867 browser_info_t
*info
= r
->browser_info
;
1869 if (!info
|| !info
->default_domain
) continue;
1870 if (add
) add_domain_to_browser(info
, d
);
1873 browser_t
*ptr
= info
->browsers
, *prev
= NULL
;
1876 if (SameDomainName(&ptr
->domain
, d
))
1878 if (prev
) prev
->next
= ptr
->next
;
1879 else info
->browsers
= ptr
->next
;
1880 mDNS_StopBrowse(gmDNS
, &ptr
->q
);
1881 freeL("browser_t", ptr
);
1887 if (!ptr
) LogMsg("Requested removal of default domain %##s not in list for sd %s", d
->c
, r
->sd
);
1892 // Count how many other service records we have locally with the same name, but different rdata.
1893 // For auto-named services, we can have at most one per machine -- if we allowed two auto-named services of
1894 // the same type on the same machine, we'd get into an infinite autoimmune-response loop of continuous renaming.
1895 mDNSexport
int CountPeerRegistrations(mDNS
*const m
, ServiceRecordSet
*const srs
)
1898 ResourceRecord
*r
= &srs
->RR_SRV
.resrec
;
1900 ServiceRecordSet
*s
;
1902 for (rr
= m
->ResourceRecords
; rr
; rr
=rr
->next
)
1903 if (rr
->resrec
.rrtype
== kDNSType_SRV
&& SameDomainName(&rr
->resrec
.name
, &r
->name
) && !SameRData(&rr
->resrec
, r
))
1906 for (rr
= m
->uDNS_info
.RecordRegistrations
; rr
; rr
=rr
->next
)
1907 if (rr
->uDNS_info
.state
!= regState_Unregistered
&& rr
->resrec
.rrtype
== kDNSType_SRV
&& SameDomainName(&rr
->resrec
.name
, &r
->name
) && !SameRData(&rr
->resrec
, r
))
1910 for (s
= m
->uDNS_info
.ServiceRegistrations
; s
; s
= s
->next
)
1911 if (s
->uDNS_info
.state
!= regState_Unregistered
&& SameDomainName(&s
->RR_SRV
.resrec
.name
, &r
->name
) && !SameRData(&s
->RR_SRV
.resrec
, r
))
1914 verbosedebugf("%d peer registrations for %##s", count
, r
->name
.c
);
1918 mDNSexport
int CountExistingRegistrations(domainname
*srv
, mDNSIPPort port
)
1922 for (rr
= gmDNS
->ResourceRecords
; rr
; rr
=rr
->next
)
1923 if (rr
->resrec
.rrtype
== kDNSType_SRV
&&
1924 rr
->resrec
.rdata
->u
.srv
.port
.NotAnInteger
== port
.NotAnInteger
&&
1925 SameDomainName(&rr
->resrec
.name
, srv
))
1930 static mStatus
register_service_instance(request_state
*request
, const domainname
*domain
)
1932 service_info
*info
= request
->service_registration
;
1933 service_instance
*ptr
, *instance
;
1937 for (ptr
= info
->instances
; ptr
; ptr
= ptr
->next
)
1939 if (SameDomainName(&ptr
->domain
, domain
))
1940 { LogMsg("register_service_instance: domain %##s already registered", domain
->c
); return mStatus_AlreadyRegistered
; }
1943 instance_size
= sizeof(*instance
);
1944 if (info
->txtlen
> sizeof(RDataBody
)) instance_size
+= (info
->txtlen
- sizeof(RDataBody
));
1945 instance
= mallocL("service_instance", instance_size
);
1946 if (!instance
) { my_perror("ERROR: malloc"); return mStatus_NoMemoryErr
; }
1948 instance
->subtypes
= AllocateSubTypes(info
->num_subtypes
, info
->type_as_string
);
1949 if (info
->num_subtypes
&& !instance
->subtypes
)
1950 { free_service_instance(instance
); instance
= NULL
; goto malloc_error
; }
1951 instance
->request
= request
;
1952 instance
->sd
= request
->sd
;
1953 instance
->autoname
= info
->autoname
;
1954 instance
->autorename
= info
->autorename
;
1955 instance
->allowremotequery
= info
->allowremotequery
;
1956 instance
->rename_on_memfree
= 0;
1957 instance
->name
= info
->name
;
1958 AssignDomainName(instance
->domain
, *domain
);
1959 instance
->default_local
= (info
->default_domain
&& SameDomainName(domain
, &localdomain
));
1960 result
= mDNS_RegisterService(gmDNS
, &instance
->srs
, &instance
->name
, &info
->type
, domain
, info
->host
.c
[0] ? &info
->host
: NULL
, info
->port
,
1961 info
->txtdata
, info
->txtlen
, instance
->subtypes
, info
->num_subtypes
, info
->InterfaceID
, regservice_callback
, instance
);
1963 if (result
) free_service_instance(instance
);
1966 instance
->next
= info
->instances
;
1967 info
->instances
= instance
;
1972 my_perror("ERROR: malloc");
1976 mDNSexport
void udsserver_default_reg_domain_changed(const domainname
*d
, mDNSBool add
)
1978 request_state
*rstate
;
1981 for (rstate
= all_requests
; rstate
; rstate
= rstate
->next
)
1983 if (rstate
->terminate
!= regservice_termination_callback
) continue;
1984 info
= rstate
->service_registration
;
1985 if (!info
) { LogMsg("udsserver_default_reg_domain_changed - NULL service info"); continue; } // this should never happen
1986 if (!info
->default_domain
) continue;
1988 // valid default registration
1989 if (add
) register_service_instance(rstate
, d
);
1992 // find the instance to remove
1993 service_instance
*si
= rstate
->service_registration
->instances
, *prev
= NULL
;
1996 if (SameDomainName(&si
->domain
, d
))
1999 if (prev
) prev
->next
= si
->next
;
2000 else info
->instances
= si
->next
;
2001 err
= mDNS_DeregisterService(gmDNS
, &si
->srs
);
2004 LogMsg("udsserver_default_reg_domain_changed - mDNS_DeregisterService err %d", err
);
2005 free_service_instance(si
);
2012 if (!si
) LogMsg("udsserver_default_reg_domain_changed - domain %##s not registered", d
->c
);
2017 // service registration
2018 static void handle_regservice_request(request_state
*request
)
2020 DNSServiceFlags flags
;
2022 char name
[256], domain
[MAX_ESCAPED_DOMAIN_NAME
], host
[MAX_ESCAPED_DOMAIN_NAME
];
2026 service_info
*service
= NULL
;
2028 if (request
->ts
!= t_complete
)
2030 LogMsg("ERROR: handle_regservice_request - transfer state != t_complete");
2031 abort_request(request
);
2032 unlink_request(request
);
2036 service
= mallocL("service_info", sizeof(*service
));
2037 if (!service
) { my_perror("ERROR: malloc"); result
= mStatus_NoMemoryErr
; goto finish
; }
2039 service
->instances
= NULL
;
2040 service
->request
= request
;
2041 request
->service_registration
= service
;
2042 request
->termination_context
= request
->service_registration
;
2043 request
->terminate
= regservice_termination_callback
;
2045 // extract data from message
2046 ptr
= request
->msgdata
;
2047 flags
= get_flags(&ptr
);
2048 ifi
= get_long(&ptr
);
2049 service
->InterfaceID
= mDNSPlatformInterfaceIDfromInterfaceIndex(gmDNS
, ifi
);
2050 if (ifi
&& !service
->InterfaceID
)
2051 { LogMsg("ERROR: handle_regservice_request - Couldn't find InterfaceID for interfaceIndex %d", ifi
); goto bad_param
; }
2052 if (get_string(&ptr
, name
, 256) < 0 ||
2053 get_string(&ptr
, service
->type_as_string
, MAX_ESCAPED_DOMAIN_NAME
) < 0 ||
2054 get_string(&ptr
, domain
, MAX_ESCAPED_DOMAIN_NAME
) < 0 ||
2055 get_string(&ptr
, host
, MAX_ESCAPED_DOMAIN_NAME
) < 0)
2056 { LogMsg("ERROR: handle_regservice_request - Couldn't read name/regtype/domain"); goto bad_param
; }
2058 service
->port
.b
[0] = *ptr
++;
2059 service
->port
.b
[1] = *ptr
++;
2060 service
->txtlen
= get_short(&ptr
);
2061 service
->txtdata
= get_rdata(&ptr
, service
->txtlen
);
2063 // Check for sub-types after the service type
2064 service
->num_subtypes
= ChopSubTypes(service
->type_as_string
); // Note: Modifies regtype string to remove trailing subtypes
2065 if (service
->num_subtypes
< 0)
2066 { LogMsg("ERROR: handle_regservice_request - ChopSubTypes failed %s", service
->type_as_string
); goto bad_param
; }
2068 // Don't try to construct "domainname t" until *after* ChopSubTypes has worked its magic
2069 if (!*service
->type_as_string
|| !MakeDomainNameFromDNSNameString(&service
->type
, service
->type_as_string
))
2070 { LogMsg("ERROR: handle_regservice_request - service->type_as_string bad %s", service
->type_as_string
); goto bad_param
; }
2074 service
->name
= (gmDNS
)->nicelabel
;
2075 service
->autoname
= mDNStrue
;
2079 if (!MakeDomainLabelFromLiteralString(&service
->name
, name
))
2080 { LogMsg("ERROR: handle_regservice_request - name bad %s", name
); goto bad_param
; }
2081 service
->autoname
= mDNSfalse
;
2086 service
->default_domain
= mDNSfalse
;
2087 if (!MakeDomainNameFromDNSNameString(&d
, domain
))
2088 { LogMsg("ERROR: handle_regservice_request - domain bad %s", domain
); goto bad_param
; }
2092 service
->default_domain
= mDNStrue
;
2093 MakeDomainNameFromDNSNameString(&d
, "local.");
2096 if (!ConstructServiceName(&srv
, &service
->name
, &service
->type
, &d
))
2097 { LogMsg("ERROR: handle_regservice_request - Couldn't ConstructServiceName from, “%#s” “%##s” “%##s”", service
->name
.c
, service
->type
.c
, d
.c
); goto bad_param
; }
2099 if (!MakeDomainNameFromDNSNameString(&service
->host
, host
))
2100 { LogMsg("ERROR: handle_regservice_request - host bad %s", host
); goto bad_param
; }
2101 service
->autorename
= (flags
& kDNSServiceFlagsNoAutoRename
) == 0;
2102 service
->allowremotequery
= (flags
& kDNSServiceFlagsAllowRemoteQuery
) != 0;
2104 // Some clients use mDNS for lightweight copy protection, registering a pseudo-service with
2105 // a port number of zero. When two instances of the protected client are allowed to run on one
2106 // machine, we don't want to see misleading "Bogus client" messages in syslog and the console.
2107 if (service
->port
.NotAnInteger
)
2109 int count
= CountExistingRegistrations(&srv
, service
->port
);
2111 LogMsg("Client application registered %d identical instances of service %##s port %u.",
2112 count
+1, srv
.c
, mDNSVal16(service
->port
));
2115 LogOperation("%3d: DNSServiceRegister(%##s, %u) START", request
->sd
, srv
.c
, mDNSVal16(service
->port
));
2116 result
= register_service_instance(request
, &d
);
2118 if (!result
&& !*domain
)
2120 DNameListElem
*ptr
, *def_domains
= mDNSPlatformGetRegDomainList();
2121 for (ptr
= def_domains
; ptr
; ptr
= ptr
->next
)
2122 register_service_instance(request
, &ptr
->name
);
2123 // note that we don't report errors for non-local, non-explicit domains
2124 mDNS_FreeDNameList(def_domains
);
2128 deliver_error(request
, result
);
2129 if (result
!= mStatus_NoError
)
2131 abort_request(request
);
2132 unlink_request(request
);
2135 reset_connected_rstate(request
); // reset to receive add/remove messages
2140 //if (service) freeL("service_info", service); Don't think we should do this -- abort_request will free it a second time and crash
2141 deliver_error(request
, mStatus_BadParamErr
);
2142 abort_request(request
);
2143 unlink_request(request
);
2146 // service registration callback performs three duties - frees memory for deregistered services,
2147 // handles name conflicts, and delivers completed registration information to the client (via
2148 // process_service_registraion())
2150 static void regservice_callback(mDNS
*const m
, ServiceRecordSet
*const srs
, mStatus result
)
2153 service_instance
*instance
= srs
->ServiceContext
;
2155 if (!srs
) { LogMsg("regservice_callback: srs is NULL %d", result
); return; }
2156 if (!instance
) { LogMsg("regservice_callback: srs->ServiceContext is NULL %d", result
); return; }
2158 if (result
== mStatus_NoError
)
2159 LogOperation("%3d: DNSServiceRegister(%##s, %u) REGISTERED ", instance
->sd
, srs
->RR_SRV
.resrec
.name
.c
, mDNSVal16(srs
->RR_SRV
.resrec
.rdata
->u
.srv
.port
));
2160 else if (result
== mStatus_MemFree
)
2161 LogOperation("%3d: DNSServiceRegister(%##s, %u) DEREGISTERED", instance
->sd
, srs
->RR_SRV
.resrec
.name
.c
, mDNSVal16(srs
->RR_SRV
.resrec
.rdata
->u
.srv
.port
));
2162 else if (result
== mStatus_NameConflict
)
2163 LogOperation("%3d: DNSServiceRegister(%##s, %u) NAME CONFLICT", instance
->sd
, srs
->RR_SRV
.resrec
.name
.c
, mDNSVal16(srs
->RR_SRV
.resrec
.rdata
->u
.srv
.port
));
2165 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
);
2167 if (result
== mStatus_NoError
)
2169 if (instance
->allowremotequery
)
2171 srs
->RR_ADV
.AllowRemoteQuery
= mDNStrue
;
2172 srs
->RR_PTR
.AllowRemoteQuery
= mDNStrue
;
2173 srs
->RR_SRV
.AllowRemoteQuery
= mDNStrue
;
2174 srs
->RR_TXT
.AllowRemoteQuery
= mDNStrue
;
2176 process_service_registration(srs
);
2177 if (instance
->autoname
&& CountPeerRegistrations(m
, srs
) == 0)
2178 RecordUpdatedNiceLabel(m
, 0); // Successfully got new name, tell user immediately
2181 else if (result
== mStatus_MemFree
)
2183 if (instance
->rename_on_memfree
)
2185 instance
->rename_on_memfree
= 0;
2186 instance
->name
= gmDNS
->nicelabel
;
2187 err
= mDNS_RenameAndReregisterService(gmDNS
, srs
, &instance
->name
);
2188 if (err
) LogMsg("ERROR: regservice_callback - RenameAndReregisterService returned %ld", err
);
2189 // error should never happen - safest to log and continue
2193 free_service_instance(instance
);
2197 else if (result
== mStatus_NameConflict
)
2199 if (instance
->autoname
&& CountPeerRegistrations(m
, srs
) == 0)
2201 // On conflict for an autoname service, rename and reregister *all* autoname services
2202 IncrementLabelSuffix(&m
->nicelabel
, mDNStrue
);
2203 m
->MainCallback(m
, mStatus_ConfigChanged
);
2205 else if (instance
->autoname
|| instance
->autorename
)
2207 mDNS_RenameAndReregisterService(gmDNS
, srs
, mDNSNULL
);
2212 request_state
*rs
= instance
->request
;
2213 if (!rs
) { LogMsg("ERROR: regservice_callback: received result %ld with a NULL request pointer", result
); return; }
2214 free_service_instance(instance
);
2215 if (deliver_async_error(rs
, reg_service_reply
, result
) < 0)
2225 request_state
*rs
= instance
->request
;
2226 if (!rs
) { LogMsg("ERROR: regservice_callback: received result %ld with a NULL request pointer", result
); return; }
2227 if (result
!= mStatus_NATTraversal
) LogMsg("ERROR: unknown result in regservice_callback: %ld", result
);
2228 free_service_instance(instance
);
2229 if (deliver_async_error(rs
, reg_service_reply
, result
) < 0)
2238 mDNSexport
void FreeExtraRR(mDNS
*const m
, AuthRecord
*const rr
, mStatus result
)
2240 ExtraResourceRecord
*extra
= (ExtraResourceRecord
*)rr
->RecordContext
;
2243 if (result
!= mStatus_MemFree
) { LogMsg("Error: FreeExtraRR invoked with unexpected error %d", result
); return; }
2245 debugf("%##s: MemFree", rr
->resrec
.name
.c
);
2246 if (rr
->resrec
.rdata
!= &rr
->rdatastorage
)
2247 freeL("Extra RData", rr
->resrec
.rdata
);
2248 freeL("ExtraResourceRecord", extra
);
2252 static mStatus
add_record_to_service(request_state
*rstate
, service_instance
*instance
, uint16_t rrtype
, uint16_t rdlen
, char *rdata
, uint32_t ttl
)
2254 ServiceRecordSet
*srs
= &instance
->srs
;
2255 ExtraResourceRecord
*extra
;
2259 if (rdlen
> sizeof(RDataBody
)) size
= rdlen
;
2260 else size
= sizeof(RDataBody
);
2262 extra
= mallocL("ExtraResourceRecord", sizeof(*extra
) - sizeof(RDataBody
) + size
);
2265 my_perror("ERROR: malloc");
2266 return mStatus_NoMemoryErr
;
2269 bzero(extra
, sizeof(ExtraResourceRecord
)); // OK if oversized rdata not zero'd
2270 extra
->r
.resrec
.rrtype
= rrtype
;
2271 extra
->r
.rdatastorage
.MaxRDLength
= (mDNSu16
) size
;
2272 extra
->r
.resrec
.rdlength
= rdlen
;
2273 memcpy(&extra
->r
.rdatastorage
.u
.data
, rdata
, rdlen
);
2275 result
= mDNS_AddRecordToService(gmDNS
, srs
, extra
, &extra
->r
.rdatastorage
, ttl
);
2276 if (result
) { freeL("ExtraResourceRecord", extra
); return result
; }
2278 extra
->ClientID
= rstate
->hdr
.reg_index
;
2283 static void handle_add_request(request_state
*rstate
)
2286 uint16_t rrtype
, rdlen
;
2288 mStatus result
= mStatus_UnknownErr
;
2289 DNSServiceFlags flags
;
2290 service_info
*srvinfo
= rstate
->service_registration
;
2291 service_instance
*i
;
2293 if (!srvinfo
) { LogMsg("handle_add_request called with NULL service_registration"); return; }
2295 ptr
= rstate
->msgdata
;
2296 flags
= get_flags(&ptr
);
2297 rrtype
= get_short(&ptr
);
2298 rdlen
= get_short(&ptr
);
2299 rdata
= get_rdata(&ptr
, rdlen
);
2300 ttl
= get_long(&ptr
);
2302 if (!ttl
) ttl
= DefaultTTLforRRType(rrtype
);
2304 LogOperation("%3d: DNSServiceAddRecord(%##s, %s)", rstate
->sd
,
2305 (srvinfo
->instances
) ? srvinfo
->instances
->srs
.RR_SRV
.resrec
.name
.c
: NULL
, DNSTypeName(rrtype
));
2307 for (i
= srvinfo
->instances
; i
; i
= i
->next
)
2309 result
= add_record_to_service(rstate
, i
, rrtype
, rdlen
, rdata
, ttl
);
2310 if (result
&& i
->default_local
) break;
2311 else result
= mStatus_NoError
; // suppress non-local default errors
2314 deliver_error(rstate
, result
);
2315 reset_connected_rstate(rstate
);
2318 static mStatus
update_record(AuthRecord
*rr
, uint16_t rdlen
, char *rdata
, uint32_t ttl
)
2324 if (rdlen
> sizeof(RDataBody
)) rdsize
= rdlen
;
2325 else rdsize
= sizeof(RDataBody
);
2326 newrd
= mallocL("handle_update_request", sizeof(RData
) - sizeof(RDataBody
) + rdsize
);
2329 my_perror("ERROR: malloc");
2332 newrd
->MaxRDLength
= (mDNSu16
) rdsize
;
2333 memcpy(&newrd
->u
, rdata
, rdlen
);
2334 result
= mDNS_Update(gmDNS
, rr
, ttl
, rdlen
, newrd
, update_callback
);
2335 if (result
) { LogMsg("ERROR: mDNS_Update - %ld", result
); freeL("handle_update_request", newrd
); }
2339 static void handle_update_request(request_state
*rstate
)
2344 mStatus result
= mStatus_BadReferenceErr
;
2345 service_info
*srvinfo
= rstate
->service_registration
;
2346 service_instance
*i
;
2347 AuthRecord
*rr
= NULL
;
2349 // get the message data
2350 ptr
= rstate
->msgdata
;
2351 get_flags(&ptr
); // flags unused
2352 rdlen
= get_short(&ptr
);
2353 rdata
= get_rdata(&ptr
, rdlen
);
2354 ttl
= get_long(&ptr
);
2356 if (rstate
->reg_recs
)
2358 // update an individually registered record
2359 registered_record_entry
*reptr
;
2360 for (reptr
= rstate
->reg_recs
; reptr
; reptr
= reptr
->next
)
2362 if (reptr
->key
== rstate
->hdr
.reg_index
)
2364 result
= update_record(reptr
->rr
, rdlen
, rdata
, ttl
);
2368 result
= mStatus_BadReferenceErr
;
2372 // update a record from a service record set
2373 if (!srvinfo
) { result
= mStatus_BadReferenceErr
; goto end
; }
2374 for (i
= srvinfo
->instances
; i
; i
= i
->next
)
2376 if (rstate
->hdr
.reg_index
== TXT_RECORD_INDEX
) rr
= &i
->srs
.RR_TXT
;
2379 ExtraResourceRecord
*e
;
2380 for (e
= i
->srs
.Extras
; e
; e
= e
->next
)
2381 if (e
->ClientID
== rstate
->hdr
.reg_index
) { rr
= &e
->r
; break; }
2384 if (!rr
) { result
= mStatus_BadReferenceErr
; goto end
; }
2385 result
= update_record(rr
, rdlen
, rdata
, ttl
);
2386 if (result
&& i
->default_local
) goto end
;
2387 else result
= mStatus_NoError
; // suppress non-local default errors
2391 LogOperation("%3d: DNSServiceUpdateRecord(%##s, %s)", rstate
->sd
,
2392 (srvinfo
->instances
) ? srvinfo
->instances
->srs
.RR_SRV
.resrec
.name
.c
: NULL
,
2393 rr
? DNSTypeName(rr
->resrec
.rrtype
) : "<NONE>");
2395 deliver_error(rstate
, result
);
2396 reset_connected_rstate(rstate
);
2399 static void update_callback(mDNS
*const m
, AuthRecord
*const rr
, RData
*oldrd
)
2402 if (oldrd
!= &rr
->rdatastorage
) freeL("update_callback", oldrd
);
2405 static void process_service_registration(ServiceRecordSet
*const srs
)
2408 transfer_state send_result
;
2410 service_instance
*instance
= srs
->ServiceContext
;
2411 request_state
*req
= instance
->request
;
2414 err
= gen_rr_response(&srs
->RR_SRV
.resrec
.name
, srs
->RR_SRV
.resrec
.InterfaceID
, req
, &rep
);
2417 if (deliver_async_error(req
, reg_service_reply
, err
) < 0)
2420 unlink_request(req
);
2424 send_result
= send_msg(rep
);
2425 if (send_result
== t_error
|| send_result
== t_terminated
)
2428 unlink_request(req
);
2429 freeL("process_service_registration", rep
);
2431 else if (send_result
== t_complete
) freeL("process_service_registration", rep
);
2432 else append_reply(req
, rep
);
2435 static void free_service_instance(service_instance
*srv
)
2437 request_state
*rstate
= srv
->request
;
2438 ExtraResourceRecord
*e
= srv
->srs
.Extras
, *tmp
;
2440 // clear pointers from parent struct
2443 service_instance
*ptr
= rstate
->service_registration
->instances
, *prev
= NULL
;
2448 if (prev
) prev
->next
= ptr
->next
;
2449 else rstate
->service_registration
->instances
= ptr
->next
;
2459 e
->r
.RecordContext
= e
;
2462 FreeExtraRR(gmDNS
, &tmp
->r
, mStatus_MemFree
);
2465 if (srv
->subtypes
) { freeL("regservice_callback", srv
->subtypes
); srv
->subtypes
= NULL
; }
2466 freeL("regservice_callback", srv
);
2469 static void regservice_termination_callback(void *context
)
2471 service_info
*info
= context
;
2472 service_instance
*i
, *p
;
2473 if (!info
) { LogMsg("regservice_termination_callback context is NULL"); return; }
2474 if (!info
->request
) { LogMsg("regservice_termination_callback info->request is NULL"); return; }
2475 i
= info
->instances
;
2480 p
->request
= NULL
; // clear back pointer
2481 // only safe to free memory if registration is not valid, ie deregister fails (which invalidates p)
2482 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
));
2483 if (mDNS_DeregisterService(gmDNS
, &p
->srs
)) free_service_instance(p
);
2485 info
->request
->service_registration
= NULL
; // clear pointer from request back to info
2486 freeL("service_info", info
);
2489 static void handle_regrecord_request(request_state
*rstate
)
2492 registered_record_entry
*re
;
2495 if (rstate
->ts
!= t_complete
)
2497 LogMsg("ERROR: handle_regrecord_request - transfer state != t_complete");
2498 abort_request(rstate
);
2499 unlink_request(rstate
);
2503 rr
= read_rr_from_ipc_msg(rstate
->msgdata
, 1, 1);
2506 deliver_error(rstate
, mStatus_BadParamErr
);
2510 // allocate registration entry, link into list
2511 re
= mallocL("handle_regrecord_request", sizeof(registered_record_entry
));
2512 if (!re
) goto malloc_error
;
2513 re
->key
= rstate
->hdr
.reg_index
;
2515 re
->rstate
= rstate
;
2516 re
->client_context
= rstate
->hdr
.client_context
;
2517 rr
->RecordContext
= re
;
2518 rr
->RecordCallback
= regrecord_callback
;
2519 re
->next
= rstate
->reg_recs
;
2520 rstate
->reg_recs
= re
;
2522 if (!rstate
->terminate
)
2524 rstate
->terminate
= connected_registration_termination
;
2525 rstate
->termination_context
= rstate
;
2528 if (rr
->resrec
.rroriginalttl
== 0)
2529 rr
->resrec
.rroriginalttl
= DefaultTTLforRRType(rr
->resrec
.rrtype
);
2531 LogOperation("%3d: DNSServiceRegisterRecord %s", rstate
->sd
, RRDisplayString(gmDNS
, &rr
->resrec
));
2532 result
= mDNS_Register(gmDNS
, rr
);
2533 deliver_error(rstate
, result
);
2534 reset_connected_rstate(rstate
);
2538 my_perror("ERROR: malloc");
2542 static void regrecord_callback(mDNS
*const m
, AuthRecord
* rr
, mStatus result
)
2544 registered_record_entry
*re
= rr
->RecordContext
;
2545 request_state
*rstate
= re
? re
->rstate
: NULL
;
2553 // parent struct alreadt freed by termination callback
2554 if (!result
) LogMsg("Error: regrecord_callback: successful registration of orphaned record");
2557 if (result
!= mStatus_MemFree
) LogMsg("regrecord_callback: error %d received after parent termination", result
);
2558 freeL("regrecord_callback", rr
);
2563 // format result, add to the list for the request, including the client context in the header
2564 len
= sizeof(DNSServiceFlags
);
2565 len
+= sizeof(uint32_t); //interfaceIndex
2566 len
+= sizeof(DNSServiceErrorType
);
2568 reply
= create_reply(reg_record_reply
, len
, rstate
);
2569 reply
->mhdr
->client_context
= re
->client_context
;
2570 reply
->rhdr
->flags
= dnssd_htonl(0);
2571 reply
->rhdr
->ifi
= dnssd_htonl(mDNSPlatformInterfaceIndexfromInterfaceID(gmDNS
, rr
->resrec
.InterfaceID
));
2572 reply
->rhdr
->error
= dnssd_htonl(result
);
2576 // unlink from list, free memory
2577 registered_record_entry
**ptr
= &re
->rstate
->reg_recs
;
2578 while (*ptr
&& (*ptr
) != re
) ptr
= &(*ptr
)->next
;
2579 if (!*ptr
) { LogMsg("regrecord_callback - record not in list!"); return; }
2580 *ptr
= (*ptr
)->next
;
2581 freeL("regrecord_callback", re
->rr
);
2583 freeL("regrecord_callback", re
);
2587 ts
= send_msg(reply
);
2589 if (ts
== t_error
|| ts
== t_terminated
) { abort_request(rstate
); unlink_request(rstate
); }
2590 else if (ts
== t_complete
) freeL("regrecord_callback", reply
);
2591 else if (ts
== t_morecoming
) append_reply(rstate
, reply
); // client is blocked, link reply into list
2594 static void connected_registration_termination(void *context
)
2597 registered_record_entry
*fptr
, *ptr
= ((request_state
*)context
)->reg_recs
;
2602 shared
= fptr
->rr
->resrec
.RecordType
== kDNSRecordTypeShared
;
2603 fptr
->rr
->RecordContext
= NULL
;
2604 mDNS_Deregister(gmDNS
, fptr
->rr
);
2605 freeL("connected_registration_termination", fptr
);
2609 static void handle_removerecord_request(request_state
*rstate
)
2611 mStatus err
= mStatus_BadReferenceErr
;
2613 service_info
*srvinfo
= rstate
->service_registration
;
2615 ptr
= rstate
->msgdata
;
2616 get_flags(&ptr
); // flags unused
2618 if (rstate
->reg_recs
) err
= remove_record(rstate
); // remove individually registered record
2619 else if (!srvinfo
) LogOperation("%3d: DNSServiceRemoveRecord (bad ref)", rstate
->sd
);
2622 LogOperation("%3d: DNSServiceRemoveRecord(%##s, %s)", rstate
->sd
,
2623 (srvinfo
->instances
) ? srvinfo
->instances
->srs
.RR_SRV
.resrec
.name
.c
: NULL
);
2624 service_instance
*i
;
2625 for (i
= srvinfo
->instances
; i
; i
= i
->next
)
2627 err
= remove_extra(rstate
, i
);
2628 if (err
&& i
->default_local
) break;
2629 else err
= mStatus_NoError
; // suppress non-local default errors
2633 reset_connected_rstate(rstate
);
2634 if (deliver_error(rstate
, err
) < 0)
2636 abort_request(rstate
);
2637 unlink_request(rstate
);
2641 // remove a resource record registered via DNSServiceRegisterRecord()
2642 static mStatus
remove_record(request_state
*rstate
)
2645 mStatus err
= mStatus_UnknownErr
;
2646 registered_record_entry
*e
, **ptr
= &rstate
->reg_recs
;
2648 while(*ptr
&& (*ptr
)->key
!= rstate
->hdr
.reg_index
) ptr
= &(*ptr
)->next
;
2649 if (!*ptr
) { LogMsg("DNSServiceRemoveRecord - bad reference"); return mStatus_BadReferenceErr
; }
2651 *ptr
= e
->next
; // unlink
2653 LogOperation("%3d: DNSServiceRemoveRecord(%#s)", rstate
->sd
, e
->rr
->resrec
.name
.c
);
2654 shared
= e
->rr
->resrec
.RecordType
== kDNSRecordTypeShared
;
2655 e
->rr
->RecordContext
= NULL
;
2656 err
= mDNS_Deregister(gmDNS
, e
->rr
);
2659 LogMsg("ERROR: remove_record, mDNS_Deregister: %ld", err
);
2660 freeL("remove_record", e
->rr
);
2661 freeL("remove_record", e
);
2667 static mStatus
remove_extra(request_state
*rstate
, service_instance
*serv
)
2669 mStatus err
= mStatus_BadReferenceErr
;
2670 ExtraResourceRecord
*ptr
;
2672 for (ptr
= serv
->srs
.Extras
; ptr
; ptr
= ptr
->next
)
2674 if (ptr
->ClientID
== rstate
->hdr
.reg_index
) // found match
2675 return mDNS_RemoveRecordFromService(gmDNS
, &serv
->srs
, ptr
, FreeExtraRR
, ptr
);
2680 // domain enumeration
2681 static void handle_enum_request(request_state
*rstate
)
2683 DNSServiceFlags flags
, add_default
;
2685 mDNSInterfaceID InterfaceID
;
2686 char *ptr
= rstate
->msgdata
;
2687 domain_enum_t
*def
, *all
;
2688 enum_termination_t
*term
;
2689 reply_state
*reply
; // initial default reply
2694 if (rstate
->ts
!= t_complete
)
2696 LogMsg("ERROR: handle_enum_request - transfer state != t_complete");
2697 abort_request(rstate
);
2698 unlink_request(rstate
);
2702 flags
= get_flags(&ptr
);
2703 ifi
= get_long(&ptr
);
2704 InterfaceID
= mDNSPlatformInterfaceIDfromInterfaceIndex(gmDNS
, ifi
);
2705 if (ifi
&& !InterfaceID
)
2707 deliver_error(rstate
, mStatus_BadParamErr
);
2708 abort_request(rstate
);
2709 unlink_request(rstate
);
2712 // allocate context structures
2713 def
= mallocL("handle_enum_request", sizeof(domain_enum_t
));
2714 all
= mallocL("handle_enum_request", sizeof(domain_enum_t
));
2715 term
= mallocL("handle_enum_request", sizeof(enum_termination_t
));
2716 if (!def
|| !all
|| !term
)
2718 my_perror("ERROR: malloc");
2722 // enumeration requires multiple questions, so we must link all the context pointers so that
2723 // necessary context can be reached from the callbacks
2724 def
->rstate
= rstate
;
2725 all
->rstate
= rstate
;
2728 term
->rstate
= rstate
;
2729 rstate
->termination_context
= term
;
2730 rstate
->terminate
= enum_termination_callback
;
2731 def
->question
.QuestionContext
= def
;
2732 def
->type
= (flags
& kDNSServiceFlagsRegistrationDomains
) ?
2733 mDNS_DomainTypeRegistrationDefault
: mDNS_DomainTypeBrowseDefault
;
2734 all
->question
.QuestionContext
= all
;
2735 all
->type
= (flags
& kDNSServiceFlagsRegistrationDomains
) ?
2736 mDNS_DomainTypeRegistration
: mDNS_DomainTypeBrowse
;
2738 // if the caller hasn't specified an explicit interface, we use local-only to get the system-wide list.
2739 if (!InterfaceID
) InterfaceID
= mDNSInterface_LocalOnly
;
2742 LogOperation("%3d: DNSServiceEnumerateDomains(%X)", rstate
->sd
, flags
);
2743 err
= mDNS_GetDomains(gmDNS
, &all
->question
, all
->type
, NULL
, InterfaceID
, enum_result_callback
, all
);
2744 if (err
== mStatus_NoError
)
2745 err
= mDNS_GetDomains(gmDNS
, &def
->question
, def
->type
, NULL
, InterfaceID
, enum_result_callback
, def
);
2746 result
= deliver_error(rstate
, err
); // send error *before* returning local domain
2748 if (result
< 0 || err
)
2750 abort_request(rstate
);
2751 unlink_request(rstate
);
2755 // provide local. as the first domain automatically
2756 add_default
= kDNSServiceFlagsDefault
| kDNSServiceFlagsAdd
;
2757 reply
= format_enumeration_reply(rstate
, "local.", add_default
, ifi
, 0);
2758 tr
= send_msg(reply
);
2759 if (tr
== t_error
|| tr
== t_terminated
)
2761 freeL("handle_enum_request", def
);
2762 freeL("handle_enum_request", all
);
2763 abort_request(rstate
);
2764 unlink_request(rstate
);
2767 if (tr
== t_complete
) freeL("handle_enum_request", reply
);
2768 if (tr
== t_morecoming
) append_reply(rstate
, reply
); // couldn't send whole reply because client is blocked - link into list
2771 static void enum_result_callback(mDNS
*const m
, DNSQuestion
*question
, const ResourceRecord
*const answer
, mDNSBool AddRecord
)
2773 char domain
[MAX_ESCAPED_DOMAIN_NAME
];
2774 domain_enum_t
*de
= question
->QuestionContext
;
2775 DNSServiceFlags flags
= 0;
2779 if (answer
->rrtype
!= kDNSType_PTR
) return;
2782 flags
|= kDNSServiceFlagsAdd
;
2783 if (de
->type
== mDNS_DomainTypeRegistrationDefault
|| de
->type
== mDNS_DomainTypeBrowseDefault
)
2784 flags
|= kDNSServiceFlagsDefault
;
2786 ConvertDomainNameToCString(&answer
->rdata
->u
.name
, domain
);
2787 // note that we do NOT propagate specific interface indexes to the client - for example, a domain we learn from
2788 // a machine's system preferences may be discovered on the LocalOnly interface, but should be browsed on the
2789 // network, so we just pass kDNSServiceInterfaceIndexAny
2790 reply
= format_enumeration_reply(de
->rstate
, domain
, flags
, kDNSServiceInterfaceIndexAny
, kDNSServiceErr_NoError
);
2793 LogMsg("ERROR: enum_result_callback, format_enumeration_reply");
2797 append_reply(de
->rstate
, reply
);
2801 static reply_state
*format_enumeration_reply(request_state
*rstate
, const char *domain
, DNSServiceFlags flags
, uint32_t ifi
, DNSServiceErrorType err
)
2808 len
= sizeof(DNSServiceFlags
);
2809 len
+= sizeof(uint32_t);
2810 len
+= sizeof(DNSServiceErrorType
);
2811 len
+= strlen(domain
) + 1;
2813 reply
= create_reply(enumeration_reply
, len
, rstate
);
2814 reply
->rhdr
->flags
= dnssd_htonl(flags
);
2815 reply
->rhdr
->ifi
= dnssd_htonl(ifi
);
2816 reply
->rhdr
->error
= dnssd_htonl(err
);
2817 data
= reply
->sdata
;
2818 put_string(domain
, &data
);
2822 static void enum_termination_callback(void *context
)
2824 enum_termination_t
*t
= context
;
2825 mDNS
*coredata
= gmDNS
;
2827 mDNS_StopGetDomains(coredata
, &t
->all
->question
);
2828 mDNS_StopGetDomains(coredata
, &t
->def
->question
);
2829 freeL("enum_termination_callback", t
->all
);
2830 freeL("enum_termination_callback", t
->def
);
2831 t
->rstate
->termination_context
= NULL
;
2832 freeL("enum_termination_callback", t
);
2835 static void handle_reconfirm_request(request_state
*rstate
)
2839 rr
= read_rr_from_ipc_msg(rstate
->msgdata
, 0, 1);
2841 LogOperation("%3d: DNSServiceReconfirmRecord(%##s) %s", rstate
->sd
, RRDisplayString(gmDNS
, &rr
->resrec
));
2842 mDNS_ReconfirmByValue(gmDNS
, &rr
->resrec
);
2843 abort_request(rstate
);
2844 unlink_request(rstate
);
2845 freeL("handle_reconfirm_request", rr
);
2849 // setup rstate to accept new reg/dereg requests
2850 static void reset_connected_rstate(request_state
*rstate
)
2852 rstate
->ts
= t_morecoming
;
2853 rstate
->hdr_bytes
= 0;
2854 rstate
->data_bytes
= 0;
2855 if (rstate
->msgbuf
) freeL("reset_connected_rstate", rstate
->msgbuf
);
2856 rstate
->msgbuf
= NULL
;
2857 rstate
->bufsize
= 0;
2862 // returns a resource record (allocated w/ malloc) containing the data found in an IPC message
2863 // data must be in format flags, interfaceIndex, name, rrtype, rrclass, rdlen, rdata, (optional)ttl
2864 // (ttl only extracted/set if ttl argument is non-zero). returns NULL for a bad-parameter error
2865 static AuthRecord
*read_rr_from_ipc_msg(char *msgbuf
, int GetTTL
, int validate_flags
)
2867 char *rdata
, name
[256];
2869 DNSServiceFlags flags
;
2870 uint32_t interfaceIndex
;
2871 uint16_t type
, class, rdlen
;
2874 flags
= get_flags(&msgbuf
);
2875 if (validate_flags
&&
2876 !((flags
& kDNSServiceFlagsShared
) == kDNSServiceFlagsShared
) &&
2877 !((flags
& kDNSServiceFlagsUnique
) == kDNSServiceFlagsUnique
))
2879 LogMsg("ERROR: Bad resource record flags (must be kDNSServiceFlagsShared or kDNSServiceFlagsUnique)");
2883 interfaceIndex
= get_long(&msgbuf
);
2884 if (get_string(&msgbuf
, name
, 256) < 0)
2886 LogMsg("ERROR: read_rr_from_ipc_msg - get_string");
2889 type
= get_short(&msgbuf
);
2890 class = get_short(&msgbuf
);
2891 rdlen
= get_short(&msgbuf
);
2893 if (rdlen
> sizeof(RDataBody
)) storage_size
= rdlen
;
2894 else storage_size
= sizeof(RDataBody
);
2896 rr
= mallocL("read_rr_from_ipc_msg", sizeof(AuthRecord
) - sizeof(RDataBody
) + storage_size
);
2899 my_perror("ERROR: malloc");
2902 bzero(rr
, sizeof(AuthRecord
)); // ok if oversized rdata not zero'd
2904 mDNS_SetupResourceRecord(rr
, mDNSNULL
, mDNSPlatformInterfaceIDfromInterfaceIndex(gmDNS
, interfaceIndex
),
2905 type
, 0, (flags
& kDNSServiceFlagsShared
) ? kDNSRecordTypeShared
: kDNSRecordTypeUnique
, mDNSNULL
, mDNSNULL
);
2907 if (!MakeDomainNameFromDNSNameString(&rr
->resrec
.name
, name
))
2909 LogMsg("ERROR: bad name: %s", name
);
2910 freeL("read_rr_from_ipc_msg", rr
);
2913 if (flags
& kDNSServiceFlagsAllowRemoteQuery
) rr
->AllowRemoteQuery
= mDNStrue
;
2914 rr
->resrec
.rrclass
= class;
2915 rr
->resrec
.rdlength
= rdlen
;
2916 rr
->resrec
.rdata
->MaxRDLength
= rdlen
;
2917 rdata
= get_rdata(&msgbuf
, rdlen
);
2918 memcpy(rr
->resrec
.rdata
->u
.data
, rdata
, rdlen
);
2921 rr
->resrec
.rroriginalttl
= get_long(&msgbuf
);
2927 // generate a response message for a browse result, service registration result, or any other call with the
2928 // identical callback signature. on successful completion rep is set to point to a malloc'd reply_state struct,
2929 // and mStatus_NoError is returned. otherwise the appropriate error is returned.
2931 static mStatus
gen_rr_response(domainname
*servicename
, mDNSInterfaceID id
, request_state
*request
, reply_state
**rep
)
2936 domainname type
, dom
;
2937 char namestr
[MAX_DOMAIN_LABEL
+1]; // Unescaped name: up to 63 bytes plus C-string terminating NULL.
2938 char typestr
[MAX_ESCAPED_DOMAIN_NAME
];
2939 char domstr
[MAX_ESCAPED_DOMAIN_NAME
];
2943 if (!DeconstructServiceName(servicename
, &name
, &type
, &dom
))
2944 return kDNSServiceErr_Unknown
;
2946 ConvertDomainLabelToCString_unescaped(&name
, namestr
);
2947 ConvertDomainNameToCString(&type
, typestr
);
2948 ConvertDomainNameToCString(&dom
, domstr
);
2950 // calculate reply data length
2951 len
= sizeof(DNSServiceFlags
);
2952 len
+= sizeof(uint32_t); // if index
2953 len
+= sizeof(DNSServiceErrorType
);
2954 len
+= (int) (strlen(namestr
) + 1);
2955 len
+= (int) (strlen(typestr
) + 1);
2956 len
+= (int) (strlen(domstr
) + 1);
2958 *rep
= create_reply(query_reply
, len
, request
);
2960 (*rep
)->rhdr
->flags
= dnssd_htonl(0);
2961 (*rep
)->rhdr
->ifi
= dnssd_htonl(mDNSPlatformInterfaceIndexfromInterfaceID(gmDNS
, id
));
2962 (*rep
)->rhdr
->error
= dnssd_htonl(kDNSServiceErr_NoError
);
2964 data
= (*rep
)->sdata
;
2966 put_string(namestr
, &data
);
2967 put_string(typestr
, &data
);
2968 put_string(domstr
, &data
);
2969 return mStatus_NoError
;
2973 static int build_domainname_from_strings(domainname
*srv
, char *name
, char *regtype
, char *domain
)
2978 if (!MakeDomainLabelFromLiteralString(&n
, name
)) return -1;
2979 if (!MakeDomainNameFromDNSNameString(&t
, regtype
)) return -1;
2980 if (!MakeDomainNameFromDNSNameString(&d
, domain
)) return -1;
2981 if (!ConstructServiceName(srv
, &n
, &t
, &d
)) return -1;
2986 // append a reply to the list in a request object
2987 static void append_reply(request_state
*req
, reply_state
*rep
)
2991 if (!req
->replies
) req
->replies
= rep
;
2995 while (ptr
->next
) ptr
= ptr
->next
;
3002 // read_msg may be called any time when the transfer state (rs->ts) is t_morecoming.
3003 // returns the current state of the request (morecoming, error, complete, terminated.)
3004 // if there is no data on the socket, the socket will be closed and t_terminated will be returned
3005 static int read_msg(request_state
*rs
)
3009 char buf
[4]; // dummy for death notification
3011 if (rs
->ts
== t_terminated
|| rs
->ts
== t_error
)
3013 LogMsg("ERROR: read_msg called with transfer state terminated or error");
3018 if (rs
->ts
== t_complete
)
3019 { // this must be death or something is wrong
3020 nread
= recv(rs
->sd
, buf
, 4, 0);
3021 if (!nread
) { rs
->ts
= t_terminated
; return t_terminated
; }
3022 if (nread
< 0) goto rerror
;
3023 LogMsg("ERROR: read data from a completed request.");
3028 if (rs
->ts
!= t_morecoming
)
3030 LogMsg("ERROR: read_msg called with invalid transfer state (%d)", rs
->ts
);
3035 if (rs
->hdr_bytes
< sizeof(ipc_msg_hdr
))
3037 nleft
= sizeof(ipc_msg_hdr
) - rs
->hdr_bytes
;
3038 nread
= recv(rs
->sd
, (char *)&rs
->hdr
+ rs
->hdr_bytes
, nleft
, 0);
3039 if (nread
== 0) { rs
->ts
= t_terminated
; return t_terminated
; }
3040 if (nread
< 0) goto rerror
;
3041 rs
->hdr_bytes
+= nread
;
3042 if (rs
->hdr_bytes
== sizeof(ipc_msg_hdr
))
3044 ConvertHeaderBytes(&rs
->hdr
);
3045 if (rs
->hdr
.version
!= VERSION
)
3047 LogMsg("ERROR: read_msg - client version 0x%08X does not match daemon version 0x%08X", rs
->hdr
.version
, VERSION
);
3052 if (rs
->hdr_bytes
> sizeof(ipc_msg_hdr
))
3054 LogMsg("ERROR: read_msg - read too many header bytes");
3060 // only read data if header is complete
3061 if (rs
->hdr_bytes
== sizeof(ipc_msg_hdr
))
3063 if (rs
->hdr
.datalen
== 0) // ok in removerecord requests
3065 rs
->ts
= t_complete
;
3070 if (!rs
->msgbuf
) // allocate the buffer first time through
3072 rs
->msgbuf
= mallocL("read_msg", rs
->hdr
.datalen
+ MSG_PAD_BYTES
);
3075 my_perror("ERROR: malloc");
3079 rs
->msgdata
= rs
->msgbuf
;
3081 bzero(rs
->msgbuf
, rs
->hdr
.datalen
+ MSG_PAD_BYTES
);
3082 nleft
= rs
->hdr
.datalen
- rs
->data_bytes
;
3083 nread
= recv(rs
->sd
, rs
->msgbuf
+ rs
->data_bytes
, nleft
, 0);
3084 if (nread
== 0) { rs
->ts
= t_terminated
; return t_terminated
; }
3085 if (nread
< 0) goto rerror
;
3086 rs
->data_bytes
+= nread
;
3087 if (rs
->data_bytes
> rs
->hdr
.datalen
)
3089 LogMsg("ERROR: read_msg - read too many data bytes");
3095 if (rs
->hdr_bytes
== sizeof(ipc_msg_hdr
) && rs
->data_bytes
== rs
->hdr
.datalen
)
3096 rs
->ts
= t_complete
;
3097 else rs
->ts
= t_morecoming
;
3102 if (dnssd_errno() == dnssd_EWOULDBLOCK
|| dnssd_errno() == dnssd_EINTR
) return t_morecoming
;
3103 my_perror("ERROR: read_msg");
3109 static int send_msg(reply_state
*rs
)
3115 LogMsg("ERROR: send_msg called with NULL message buffer");
3119 if (rs
->request
->no_reply
) //!!!KRS this behavior should be optimized if it becomes more common
3121 rs
->ts
= t_complete
;
3122 freeL("send_msg", rs
->msgbuf
);
3126 ConvertHeaderBytes(rs
->mhdr
);
3127 nwriten
= send(rs
->sd
, rs
->msgbuf
+ rs
->nwriten
, rs
->len
- rs
->nwriten
, 0);
3128 ConvertHeaderBytes(rs
->mhdr
);
3131 if (dnssd_errno() == dnssd_EINTR
|| dnssd_errno() == dnssd_EWOULDBLOCK
) nwriten
= 0;
3134 #if !defined(PLATFORM_NO_EPIPE)
3135 if (dnssd_errno() == EPIPE
)
3137 LogMsg("broken pipe - cleanup should be handled by run-loop read wakeup");
3138 rs
->ts
= t_terminated
;
3139 rs
->request
->ts
= t_terminated
;
3140 return t_terminated
;
3145 my_perror("ERROR: send\n");
3151 rs
->nwriten
+= nwriten
;
3153 if (rs
->nwriten
== rs
->len
)
3155 rs
->ts
= t_complete
;
3156 freeL("send_msg", rs
->msgbuf
);
3163 static reply_state
*create_reply(reply_op_t op
, size_t datalen
, request_state
*request
)
3169 if ((unsigned)datalen
< sizeof(reply_hdr
))
3171 LogMsg("ERROR: create_reply - data length less than lenght of required fields");
3175 totallen
= (int) (datalen
+ sizeof(ipc_msg_hdr
));
3176 reply
= mallocL("create_reply", sizeof(reply_state
));
3179 my_perror("ERROR: malloc");
3182 bzero(reply
, sizeof(reply_state
));
3183 reply
->ts
= t_morecoming
;
3184 reply
->sd
= request
->sd
;
3185 reply
->request
= request
;
3186 reply
->len
= totallen
;
3187 reply
->msgbuf
= mallocL("create_reply", totallen
);
3190 my_perror("ERROR: malloc");
3193 bzero(reply
->msgbuf
, totallen
);
3194 reply
->mhdr
= (ipc_msg_hdr
*)reply
->msgbuf
;
3195 reply
->rhdr
= (reply_hdr
*)(reply
->msgbuf
+ sizeof(ipc_msg_hdr
));
3196 reply
->sdata
= reply
->msgbuf
+ sizeof(ipc_msg_hdr
) + sizeof(reply_hdr
);
3197 reply
->mhdr
->version
= VERSION
;
3198 reply
->mhdr
->op
= op
;
3199 reply
->mhdr
->datalen
= totallen
- sizeof(ipc_msg_hdr
);
3204 static int deliver_error(request_state
*rstate
, mStatus err
)
3207 undelivered_error_t
*undeliv
;
3209 err
= dnssd_htonl(err
);
3210 nwritten
= send(rstate
->errfd
, &err
, sizeof(mStatus
), 0);
3211 if (nwritten
< (int)sizeof(mStatus
))
3213 if (dnssd_errno() == dnssd_EINTR
|| dnssd_errno() == dnssd_EWOULDBLOCK
)
3217 my_perror("ERROR: send - unable to deliver error to client");
3220 //client blocked - store result and come backr
3221 undeliv
= mallocL("deliver_error", sizeof(undelivered_error_t
));
3224 my_perror("ERROR: malloc");
3228 undeliv
->nwritten
= nwritten
;
3229 undeliv
->sd
= rstate
->errfd
;
3230 rstate
->u_err
= undeliv
;
3241 // returns 0 on success, -1 if send is incomplete, or on terminal failure (request is aborted)
3242 static transfer_state
send_undelivered_error(request_state
*rs
)
3246 nwritten
= send(rs
->u_err
->sd
, (char *)(&rs
->u_err
->err
) + rs
->u_err
->nwritten
, sizeof(mStatus
) - rs
->u_err
->nwritten
, 0);
3249 if (dnssd_errno() == dnssd_EINTR
|| dnssd_errno() == dnssd_EWOULDBLOCK
)
3253 my_perror("ERROR: send - unable to deliver error to client\n");
3257 if (nwritten
+ rs
->u_err
->nwritten
== sizeof(mStatus
))
3259 freeL("send_undelivered_error", rs
->u_err
);
3263 rs
->u_err
->nwritten
+= nwritten
;
3264 return t_morecoming
;
3268 // send bogus data along with an error code to the app callback
3269 // returns 0 on success (linking reply into list of not fully delivered),
3270 // -1 on failure (request should be aborted)
3271 static int deliver_async_error(request_state
*rs
, reply_op_t op
, mStatus err
)
3277 if (rs
->no_reply
) return 0;
3278 len
= 256; // long enough for any reply handler to read all args w/o buffer overrun
3279 reply
= create_reply(op
, len
, rs
);
3280 reply
->rhdr
->error
= dnssd_htonl(err
);
3281 ts
= send_msg(reply
);
3282 if (ts
== t_error
|| ts
== t_terminated
)
3284 freeL("deliver_async_error", reply
);
3287 else if (ts
== t_complete
) freeL("deliver_async_error", reply
);
3288 else if (ts
== t_morecoming
) append_reply(rs
, reply
); // client is blocked, link reply into list
3293 static void abort_request(request_state
*rs
)
3295 reply_state
*rep
, *ptr
;
3297 if (rs
->terminate
) rs
->terminate(rs
->termination_context
); // terminate field may not be set yet
3298 if (rs
->msgbuf
) freeL("abort_request", rs
->msgbuf
);
3299 LogOperation("%3d: Removing FD", rs
->sd
);
3300 udsSupportRemoveFDFromEventLoop(rs
->sd
);
3301 rs
->sd
= dnssd_InvalidSocket
;
3302 if (rs
->errfd
!= rs
->sd
&& rs
->errfd
!= dnssd_InvalidSocket
) dnssd_close(rs
->errfd
);
3303 rs
->errfd
= dnssd_InvalidSocket
;
3305 // free pending replies
3309 if (rep
->msgbuf
) freeL("abort_request", rep
->msgbuf
);
3312 freeL("abort_request", ptr
);
3317 freeL("abort_request", rs
->u_err
);
3323 static void unlink_request(request_state
*rs
)
3327 if (rs
== all_requests
)
3329 all_requests
= all_requests
->next
;
3330 freeL("unlink_request", rs
);
3333 for(ptr
= all_requests
; ptr
->next
; ptr
= ptr
->next
)
3334 if (ptr
->next
== rs
)
3336 ptr
->next
= rs
->next
;
3337 freeL("unlink_request", rs
);
3344 //hack to search-replace perror's to LogMsg's
3345 static void my_perror(char *errmsg
)
3347 LogMsg("%s: %s", errmsg
, dnssd_strerror(dnssd_errno()));
3350 // check that the message delivered by the client is sufficiently long to extract the required data from the buffer
3351 // without overrunning it.
3352 // returns 0 on success, -1 on error.
3354 static int validate_message(request_state
*rstate
)
3358 switch(rstate
->hdr
.op
)
3360 case resolve_request
: min_size
= sizeof(DNSServiceFlags
) + // flags
3361 sizeof(uint32_t) + // interface
3362 (3 * sizeof(char)); // name, regtype, domain
3364 case query_request
: min_size
= sizeof(DNSServiceFlags
) + // flags
3365 sizeof(uint32_t) + // interface
3366 sizeof(char) + // fullname
3367 (2 * sizeof(uint16_t)); // type, class
3369 case browse_request
: min_size
= sizeof(DNSServiceFlags
) + // flags
3370 sizeof(uint32_t) + // interface
3371 (2 * sizeof(char)); // regtype, domain
3373 case reg_service_request
: min_size
= sizeof(DNSServiceFlags
) + // flags
3374 sizeof(uint32_t) + // interface
3375 (4 * sizeof(char)) + // name, type, domain, host
3376 (2 * sizeof(uint16_t)); // port, textlen
3378 case enumeration_request
: min_size
= sizeof(DNSServiceFlags
) + // flags
3379 sizeof(uint32_t); // interface
3381 case reg_record_request
: min_size
= sizeof(DNSServiceFlags
) + // flags
3382 sizeof(uint32_t) + // interface
3383 sizeof(char) + // fullname
3384 (3 * sizeof(uint16_t)) + // type, class, rdlen
3385 sizeof(uint32_t); // ttl
3387 case add_record_request
: min_size
= sizeof(DNSServiceFlags
) + // flags
3388 (2 * sizeof(uint16_t)) + // type, rdlen
3389 sizeof(uint32_t); // ttl
3391 case update_record_request
: min_size
= sizeof(DNSServiceFlags
) + // flags
3392 sizeof(uint16_t) + // rdlen
3393 sizeof(uint32_t); // ttl
3395 case remove_record_request
: min_size
= sizeof(DNSServiceFlags
); // flags
3397 case reconfirm_record_request
: min_size
=sizeof(DNSServiceFlags
) + // flags
3398 sizeof(uint32_t) + // interface
3399 sizeof(char) + // fullname
3400 (3 * sizeof(uint16_t)); // type, class, rdlen
3402 case setdomain_request
: min_size
= sizeof(DNSServiceFlags
) + sizeof(char); // flags + domain
3405 LogMsg("ERROR: validate_message - unsupported request type: %d", rstate
->hdr
.op
);
3409 return (rstate
->data_bytes
>= min_size
? 0 : -1);
3414 static uint32_t dnssd_htonl(uint32_t l
)
3419 data
= (char*) &ret
;
3429 static char * win32_strerror(int inErrorCode
)
3431 static char buffer
[1024];
3434 memset(buffer
, 0, sizeof(buffer
));
3437 FORMAT_MESSAGE_FROM_SYSTEM
| FORMAT_MESSAGE_IGNORE_INSERTS
,
3439 (DWORD
) inErrorCode
,
3440 MAKELANGID( LANG_NEUTRAL
, SUBLANG_DEFAULT
),
3447 // Remove any trailing CR's or LF's since some messages have them.
3449 while( ( n
> 0 ) && isspace( ( (unsigned char *) buffer
)[ n
- 1 ] ) )
3451 buffer
[ --n
] = '\0';