]> git.saurik.com Git - apple/mdnsresponder.git/blob - mDNSShared/uds_daemon.c
964d2fc1c2cbc9b162875fdb2f73129f00b4175f
[apple/mdnsresponder.git] / mDNSShared / uds_daemon.c
1 /* -*- Mode: C; tab-width: 4 -*-
2 *
3 * Copyright (c) 2003 Apple Computer, Inc. All rights reserved.
4 *
5 * @APPLE_LICENSE_HEADER_START@
6 *
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
12 * file.
13 *
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.
21 *
22 * @APPLE_LICENSE_HEADER_END@
23
24 Change History (most recent first):
25
26 $Log: uds_daemon.c,v $
27 Revision 1.180 2005/03/10 00:13:12 cheshire
28 <rdar://problem/4043098> DNSServiceBrowse no longer returning error codes for invalid types
29 In handle_browse_request(), mStatus err was being set correctly if an error occurred,
30 but the end of the function returned mStatus_NoError intead of err.
31
32 Revision 1.179 2005/03/04 02:47:26 ksekar
33 <rdar://problem/4026393> SCPreference domains disappear from enumeration when moving out from firewall
34
35 Revision 1.178 2005/02/25 19:35:38 ksekar
36 <rdar://problem/4023750> Non-local empty string registration failures should not return errors to caller
37
38 Revision 1.177 2005/02/25 03:05:41 cheshire
39 Change "broken pipe" message to debugf()
40
41 Revision 1.176 2005/02/24 18:44:45 ksekar
42 <rdar://problem/4018516> Printer Sharing does not get re-registered with wide-area
43
44 Revision 1.175 2005/02/21 21:31:25 ksekar
45 <rdar://problem/4015162> changed LogMsg to debugf
46
47 Revision 1.174 2005/02/20 01:41:17 cheshire
48 Fix compiler signed/unsigned warning
49
50 Revision 1.173 2005/02/18 01:26:42 cheshire
51 <rdar://problem/4012162> "Could not write data to client after 60 seconds" message could be more helpful
52 Log additional information about failed client
53
54 Revision 1.172 2005/02/18 00:58:35 cheshire
55 <rdar://problem/4012162> "Could not write data to client after 60 seconds" message could be more helpful
56
57 Revision 1.171 2005/02/18 00:43:12 cheshire
58 <rdar://problem/4010245> mDNSResponder should auto-truncate service names that are too long
59
60 Revision 1.170 2005/02/16 01:15:02 cheshire
61 Improve LogOperation() debugging messages for DNSServiceBrowse and DNSServiceRegister
62
63 Revision 1.169 2005/02/08 01:57:14 cheshire
64 More detailed error reporting in udsserver_init()
65
66 Revision 1.168 2005/02/03 00:44:37 cheshire
67 <rdar://problem/3986663> DNSServiceUpdateRecord returns kDNSServiceErr_Invalid when rdlen=0, rdata=NULL
68
69 Revision 1.167 2005/02/02 02:19:32 cheshire
70 Add comment explaining why unlink(MDNS_UDS_SERVERPATH); fails
71
72 Revision 1.166 2005/02/01 19:58:52 ksekar
73 Shortened cryptic "broken pipe" syslog message
74
75 Revision 1.165 2005/02/01 19:56:47 ksekar
76 Moved LogMsg from daemon.c to uds_daemon.c, cleaned up wording
77
78 Revision 1.164 2005/01/28 06:07:55 cheshire
79 Don't use deliver_error() from within handle_regrecord_request()
80
81 Revision 1.163 2005/01/28 01:39:16 cheshire
82 Include file descriptor number in "broken pipe" message
83
84 Revision 1.162 2005/01/27 23:59:20 cheshire
85 Remove extraneous LogMsg
86
87 Revision 1.161 2005/01/27 22:57:56 cheshire
88 Fix compile errors on gcc4
89
90 Revision 1.160 2005/01/27 20:52:11 cheshire
91 <rdar://problem/3972566> mDNSResponder leaks sockets for add/update/remove record calls
92
93 Revision 1.159 2005/01/27 01:45:25 cheshire
94 <rdar://problem/3976147> mDNSResponder should never call exit(1);
95
96 Revision 1.158 2005/01/25 17:28:07 ksekar
97 <rdar://problem/3971467> Should not return "local" twice for domain enumeration
98
99 Revision 1.157 2005/01/21 02:20:39 cheshire
100 Fix mistake in LogOperation() format string
101
102 Revision 1.156 2005/01/19 19:15:36 ksekar
103 Refinement to <rdar://problem/3954575> - Simplify mDNS_PurgeResultsForDomain logic and move into daemon layer
104
105 Revision 1.155 2005/01/19 03:00:47 cheshire
106 Show Add/Rmv in DNSServiceBrowse LogOperation() message
107
108 Revision 1.154 2005/01/15 00:56:42 ksekar
109 <rdar://problem/3954575> Unicast services don't disappear when logging
110 out of VPN
111
112 Revision 1.153 2005/01/14 18:44:28 ksekar
113 <rdar://problem/3954609> mDNSResponder is crashing when changing domains
114
115 Revision 1.152 2005/01/13 17:16:38 ksekar
116 Back out checkin 1.150 - correct fix is on clientstub side
117
118 Revision 1.151 2005/01/11 21:06:29 ksekar
119 Changed now-benign LogMsg to debugf
120
121 Revision 1.150 2005/01/07 23:59:15 ksekar
122 <rdar://problem/3942900> dnd-sd shows the wrong port numbers
123
124 Revision 1.149 2004/12/20 23:20:35 cheshire
125 <rdar://problem/3928361> mDNSResponder crashes repeatedly when printer sharing is enabled
126 Make sure to call mDNS_SetupResourceRecord() for all newly created AuthRecords
127
128 Revision 1.148 2004/12/20 20:37:35 cheshire
129 AllowRemoteQuery not set for the extras in a ServiceRecordSet
130
131 Revision 1.147 2004/12/20 00:15:41 cheshire
132 Include client file descriptor numbers in udsserver_info() output
133
134 Revision 1.146 2004/12/17 05:25:47 cheshire
135 <rdar://problem/3925163> Shorten DNS-SD queries to avoid NAT bugs
136
137 Revision 1.145 2004/12/16 21:39:46 cheshire
138 Include CacheGroup objects in CacheUsed count
139
140 Revision 1.144 2004/12/16 21:27:38 ksekar
141 Fixed build failures when compiled with verbose debugging messages
142
143 Revision 1.143 2004/12/16 20:13:02 cheshire
144 <rdar://problem/3324626> Cache memory management improvements
145
146 Revision 1.142 2004/12/16 08:07:33 shersche
147 Fix compiler error (mixed declarations and code) on Windows
148
149 Revision 1.141 2004/12/16 01:56:21 cheshire
150 Improve DNSServiceEnumerateDomains syslog message
151
152 Revision 1.140 2004/12/14 03:02:10 ksekar
153 <rdar://problem/3919016> Rare race condition can cause crash
154
155 Revision 1.139 2004/12/13 21:18:45 ksekar
156 Include uDNS registrations in CountPeerRegistrations
157
158 Revision 1.138 2004/12/13 18:23:18 ksekar
159 <rdar://problem/3915805> mDNSResponder error when quitting iChat -
160 don't close sockets delivering errors to blocked clients
161
162 Revision 1.137 2004/12/13 00:09:22 ksekar
163 <rdar://problem/3915805> mDNSResponder error when quitting iChat
164
165 Revision 1.136 2004/12/11 01:52:10 cheshire
166 <rdar://problem/3785820> Support kDNSServiceFlagsAllowRemoteQuery for registering services too
167
168 Revision 1.135 2004/12/10 20:46:37 cheshire
169 Change LogOperation message to debugf
170
171 Revision 1.134 2004/12/10 13:19:37 cheshire
172 Add verbosedebugf() logging message in CountPeerRegistrations()
173
174 Revision 1.133 2004/12/10 05:27:26 cheshire
175 <rdar://problem/3909147> Guard against multiple autoname services of the same type on the same machine
176
177 Revision 1.132 2004/12/10 04:28:28 cheshire
178 <rdar://problem/3914406> User not notified of name changes for services using new UDS API
179
180 Revision 1.131 2004/12/10 02:09:25 cheshire
181 <rdar://problem/3898376> Modify default TTLs
182
183 Revision 1.130 2004/12/10 00:55:24 cheshire
184 Add full name and type to LogOperation messages for DNSServiceAddRecord/UpdateRecord/RemoveRecord
185
186 Revision 1.129 2004/12/09 03:17:23 ksekar
187 <rdar://problem/3910435> DomainEnumeration interface index should be zero
188
189 Revision 1.128 2004/12/07 21:26:05 ksekar
190 <rdar://problem/3908336> DNSServiceRegisterRecord() can crash on deregistration
191
192 Revision 1.127 2004/12/07 20:42:34 cheshire
193 Add explicit context parameter to mDNS_RemoveRecordFromService()
194
195 Revision 1.126 2004/12/07 17:23:55 ksekar
196 Fixed LogOperation
197
198 Revision 1.125 2004/12/06 21:15:23 ksekar
199 <rdar://problem/3884386> mDNSResponder crashed in CheckServiceRegistrations
200
201 Revision 1.124 2004/11/30 02:19:14 cheshire
202 <rdar://problem/3827971> Raise maxfds.rlim_cur for mDNSResponder
203
204 Revision 1.123 2004/11/29 23:50:57 cheshire
205 Checkin 1.122 not necessary
206
207 Revision 1.122 2004/11/24 17:55:01 ksekar
208 Added log message clarifying <rdar://problem/3869241> For unicast operations, verify that service types are legal
209
210 Revision 1.121 2004/11/24 04:45:52 cheshire
211 Spelling mistake
212
213 Revision 1.120 2004/11/24 00:10:44 cheshire
214 <rdar://problem/3869241> For unicast operations, verify that service types are legal
215
216 Revision 1.119 2004/11/23 23:54:17 ksekar
217 <rdar://problem/3890318> Wide-Area DNSServiceRegisterRecord() failures
218 can crash mDNSResponder
219
220 Revision 1.118 2004/11/23 22:33:01 cheshire
221 <rdar://problem/3654910> Remove temporary workaround code for iChat
222
223 Revision 1.117 2004/11/23 20:23:10 ksekar
224 Fixed LogOperation that causes crash on connected service deregistrations
225
226 Revision 1.116 2004/11/23 03:39:47 cheshire
227 Let interface name/index mapping capability live directly in JNISupport.c,
228 instead of having to call through to the daemon via IPC to get this information.
229
230 Revision 1.115 2004/11/13 00:12:53 ksekar
231 Fixed some LogOperation printf converstions for debug builds.
232
233 Revision 1.114 2004/11/12 18:25:45 shersche
234 Tidy up cross platform usleep code fragment.
235
236 Revision 1.113 2004/11/12 03:21:41 rpantos
237 rdar://problem/3809541 Add DNSSDMapIfIndexToName, DNSSDMapNameToIfIndex.
238
239 Revision 1.112 2004/11/11 16:58:32 ksekar
240 Removed unused code (previously wrapped in #if 0)
241
242 Revision 1.111 2004/11/05 22:47:37 shersche
243 Conditionally compile usleep(1000) to be Sleep(1) on Windows
244 Submitted by: Pavel Repin <prepin@gmail.com>
245
246 Revision 1.110 2004/11/05 19:56:56 ksekar
247 <rdar://problem/3862646> We no longer need to browse .Mac domains by
248 default - changed #if 0 to more descriptive #ifdef _HAVE_SETDOMAIN_SUPPORT_
249
250 Revision 1.109 2004/11/04 03:40:45 cheshire
251 More debugging messages
252
253 Revision 1.108 2004/11/03 02:25:51 cheshire
254 <rdar://problem/3324137> Conflict for Computer Name should update *all* empty string services, not just the one with the conflict
255
256 Revision 1.107 2004/11/02 19:39:23 ksekar
257 <rdar://problem/3862646> We no longer need to browse .Mac domains by default
258
259 Revision 1.106 2004/11/02 02:12:21 cheshire
260 <rdar://problem/3839111> Remove unnecessary memory allocations
261
262 Revision 1.105 2004/10/28 19:07:19 cheshire
263 Add some more debugging checks and improved LogOperation() messages
264
265 Revision 1.104 2004/10/26 18:53:15 cheshire
266 Avoid unused variable warning
267
268 Revision 1.103 2004/10/26 07:15:55 cheshire
269 Add file descriptor number to all LogOperation messages
270
271 Revision 1.102 2004/10/26 06:11:42 cheshire
272 Add improved logging to aid in diagnosis of <rdar://problem/3842714> mDNSResponder crashed
273
274 Revision 1.101 2004/10/26 04:31:44 cheshire
275 Rename CountSubTypes() as ChopSubTypes()
276
277 Revision 1.100 2004/10/26 01:17:48 cheshire
278 Use "#if 0" instead of commenting out code
279
280 Revision 1.99 2004/10/19 21:33:22 cheshire
281 <rdar://problem/3844991> Cannot resolve non-local registrations using the mach API
282 Added flag 'kDNSServiceFlagsForceMulticast'. Passing through an interface id for a unicast name
283 doesn't force multicast unless you set this flag to indicate explicitly that this is what you want
284
285 Revision 1.98 2004/10/14 01:59:33 cheshire
286 <rdar://problem/3839208> UDS resolves don't work for uDNS services
287
288 Revision 1.97 2004/10/13 00:58:35 cheshire
289 <rdar://problem/3832738> Registering a proxy doesn't work
290
291 Revision 1.96 2004/09/30 00:25:00 ksekar
292 <rdar://problem/3695802> Dynamically update default registration domains on config change
293
294 Revision 1.95 2004/09/26 23:20:36 ksekar
295 <rdar://problem/3813108> Allow default registrations in multiple wide-area domains
296
297 Revision 1.94 2004/09/22 18:27:06 ksekar
298 <rdar://problem/3811427> allow DNSServiceAddRecord to pass zero to get
299 default record TTL
300
301 Revision 1.93 2004/09/22 02:39:44 cheshire
302 <rdar://problem/3810757> Allow DNSServiceRegisterRecord to pass zero to get default record TTL
303
304 Revision 1.92 2004/09/22 02:34:04 cheshire
305 Rename parameter "ttl" to "GetTTL" for clarity
306
307 Revision 1.91 2004/09/22 02:25:43 cheshire
308 Fix spelling errors
309
310 Revision 1.90 2004/09/21 23:40:12 ksekar
311 <rdar://problem/3810349> mDNSResponder to return errors on NAT traversal failure
312
313 Revision 1.89 2004/09/21 23:29:51 cheshire
314 <rdar://problem/3680045> DNSServiceResolve should delay sending packets
315
316 Revision 1.88 2004/09/21 23:12:46 cheshire
317 Reorder initialization of question fields to match structure order
318
319 Revision 1.87 2004/09/21 22:18:33 cheshire
320 In SIGINFO output, display a '-' next to records that have the Unique bit set
321
322 Revision 1.86 2004/09/21 21:05:11 cheshire
323 Move duplicate code out of mDNSMacOSX/daemon.c and mDNSPosix/PosixDaemon.c,
324 into mDNSShared/uds_daemon.c
325
326 Revision 1.85 2004/09/18 01:11:58 ksekar
327 <rdar://problem/3806734> Add a user's default domain to empty-string browse list
328
329 Revision 1.84 2004/09/17 01:08:55 cheshire
330 Renamed mDNSClientAPI.h to mDNSEmbeddedAPI.h
331 The name "mDNSClientAPI.h" is misleading to new developers looking at this code. The interfaces
332 declared in that file are ONLY appropriate to single-address-space embedded applications.
333 For clients on general-purpose computers, the interfaces defined in dns_sd.h should be used.
334
335 Revision 1.83 2004/09/16 23:26:33 cheshire
336 Move version check inside preceeding "if" that checks we have a complete header
337
338 Revision 1.82 2004/09/16 23:14:25 cheshire
339 Changes for Windows compatibility
340
341 Revision 1.81 2004/09/16 21:46:38 ksekar
342 <rdar://problem/3665304> Need SPI for LoginWindow to associate a UID with a Wide Area domain
343
344 Revision 1.80 2004/09/16 01:58:23 cheshire
345 Fix compiler warnings
346
347 Revision 1.79 2004/09/16 00:24:49 cheshire
348 <rdar://problem/3803162> Fix unsafe use of mDNSPlatformTimeNow()
349
350 Revision 1.78 2004/09/15 21:44:20 cheshire
351 <rdar://problem/3681031> Randomize initial timenow_adjust value in mDNS_Init
352 Show time value in log to help diagnose errors
353
354 Revision 1.77 2004/09/15 00:19:18 cheshire
355 <rdar://problem/3785823> read_rr_from_ipc_msg should use mDNS_SetupResourceRecord()
356
357 Revision 1.76 2004/09/02 06:39:52 cheshire
358 Minor textual cleanup for clarity
359
360 Revision 1.75 2004/09/02 03:48:47 cheshire
361 <rdar://problem/3709039> Disable targeted unicast query support by default
362 1. New flag kDNSServiceFlagsAllowRemoteQuery to indicate we want to allow remote queries for this record
363 2. New field AllowRemoteQuery in AuthRecord structure
364 3. uds_daemon.c sets AllowRemoteQuery if kDNSServiceFlagsAllowRemoteQuery is set
365 4. mDNS.c only answers remote queries if AllowRemoteQuery is set
366
367 Revision 1.74 2004/08/25 02:32:47 cheshire
368 Minor cleanup: replace "&regtype[0]" with "regtype"
369
370 Revision 1.73 2004/08/25 02:30:40 cheshire
371 <rdar://problem/3588761> Current method of doing subtypes causes name collisions
372
373 Revision 1.72 2004/08/14 03:22:42 cheshire
374 <rdar://problem/3762579> Dynamic DNS UI <-> mDNSResponder glue
375 Add GetUserSpecifiedDDNSName() routine
376 Convert ServiceRegDomain to domainname instead of C string
377 Replace mDNS_GenerateFQDN/mDNS_GenerateGlobalFQDN with mDNS_SetFQDNs
378
379 Revision 1.71 2004/08/11 04:21:21 rpantos
380 Fix Windows build.
381
382 Revision 1.70 2004/08/11 02:07:00 cheshire
383 Remove "mDNS *globalInstance" parameter from udsserver_init()
384 Move CheckForDuplicateRegistrations from daemon.c
385 <rdar://problem/3501938> No warning when accidentally registering the same service multiple times using socket API
386
387 Revision 1.69 2004/08/10 16:14:48 cheshire
388 Fix debug builds (oops)
389
390 Revision 1.68 2004/08/10 06:24:56 cheshire
391 Use types with precisely defined sizes for 'op' and 'reg_index', for better
392 compatibility if the daemon and the client stub are built using different compilers
393
394 Revision 1.67 2004/07/27 07:14:16 shersche
395 make error socket non-blocking after call to connect()
396
397 Revision 1.66 2004/07/13 21:24:25 rpantos
398 Fix for <rdar://problem/3701120>.
399
400 Revision 1.65 2004/06/26 03:17:14 shersche
401 implement cross-platform strerror function
402
403 Submitted by: herscher
404
405 Revision 1.64 2004/06/25 00:26:27 rpantos
406 Changes to fix the Posix build on Solaris.
407
408 Revision 1.63 2004/06/24 03:43:44 rpantos
409 Fix previous checkin so it builds on Windows.
410
411 Revision 1.62 2004/06/24 00:57:08 ksekar
412 Replaced code acccidentally removed in checkin 1.59.
413
414 Revision 1.61 2004/06/19 00:09:39 cheshire
415 Remove unused strsep() implementation
416
417 Revision 1.60 2004/06/18 19:10:00 cheshire
418 <rdar://problem/3588761> Current method of doing subtypes causes name collisions
419
420 Revision 1.59 2004/06/18 05:10:31 rpantos
421 Changes to allow code to be used on Windows
422
423 Revision 1.58 2004/06/15 03:54:08 cheshire
424 Include mDNS_TimeNow(&mDNSStorage) in SIGINFO output
425
426 Revision 1.57 2004/06/12 01:47:27 ksekar
427 <rdar://problem/3690241>: BBEdit crashes when trying to check for newer version
428 udsserver_idle compared time in ticks to interval in seconds.
429
430 Revision 1.56 2004/06/12 01:35:47 cheshire
431 Changes for Windows compatibility
432
433 Revision 1.55 2004/06/05 00:04:27 cheshire
434 <rdar://problem/3668639>: wide-area domains should be returned in reg. domain enumeration
435
436 Revision 1.54 2004/06/01 22:22:52 ksekar
437 <rdar://problem/3668635>: wide-area default registrations should be in
438 .local too
439
440 Revision 1.53 2004/05/28 23:42:37 ksekar
441 <rdar://problem/3258021>: Feature: DNS server->client notification on record changes (#7805)
442
443 Revision 1.52 2004/05/26 00:39:49 ksekar
444 <rdar://problem/3667105>: wide-area DNS-SD servers don't appear in
445 Finder
446 Use local-only InterfaceID for GetDomains calls for sockets-API
447
448 Revision 1.51 2004/05/18 23:51:27 cheshire
449 Tidy up all checkin comments to use consistent "<rdar://problem/xxxxxxx>" format for bug numbers
450
451 Revision 1.50 2004/05/14 16:39:47 ksekar
452 Browse for iChat locally for now.
453
454 Revision 1.49 2004/05/13 21:33:52 ksekar
455 Clean up non-local registration control via config file. Force iChat
456 registrations to be local for now.
457
458 Revision 1.48 2004/05/13 04:13:19 ksekar
459 Updated SIGINFO handler for multi-domain browses
460
461 Revision 1.47 2004/05/12 22:04:01 ksekar
462 Implemented multi-domain browsing by default for uds_daemon.
463
464 Revision 1.46 2004/05/06 18:42:58 ksekar
465 General dns_sd.h API cleanup, including the following radars:
466 <rdar://problem/3592068>: Remove flags with zero value
467 <rdar://problem/3479569>: Passing in NULL causes a crash.
468
469 Revision 1.45 2004/03/12 08:49:28 cheshire
470 #include <sys/socket.h>
471
472 Revision 1.44 2004/02/25 01:25:27 ksekar
473 <rdar://problem/3569212>: DNSServiceRegisterRecord flags not error-checked
474
475 Revision 1.43 2004/02/24 01:46:40 cheshire
476 Manually reinstate lost checkin 1.36
477
478 Revision 1.42 2004/02/05 19:39:29 cheshire
479 Move creation of /var/run/mDNSResponder.pid to uds_daemon.c,
480 so that all platforms get this functionality
481
482 Revision 1.41 2004/02/03 18:59:02 cheshire
483 Change "char *domain" parameter for format_enumeration_reply to "const char *domain"
484
485 Revision 1.40 2004/01/28 03:41:00 cheshire
486 <rdar://problem/3541946>: Need ability to do targeted queries as well as multicast queries
487
488 Revision 1.39 2004/01/25 00:03:21 cheshire
489 Change to use mDNSVal16() instead of private PORT_AS_NUM() macro
490
491 Revision 1.38 2004/01/19 19:51:46 cheshire
492 Fix compiler error (mixed declarations and code) on some versions of Linux
493
494 Revision 1.37 2003/12/08 21:11:42 rpantos
495 Changes necessary to support mDNSResponder on Linux.
496
497 Revision 1.36 2003/12/04 23:40:57 cheshire
498 <rdar://problem/3484766>: Security: Crashing bug in mDNSResponder
499 Fix some more code that should use buffer size MAX_ESCAPED_DOMAIN_NAME (1005) instead of 256-byte buffers.
500
501 Revision 1.35 2003/12/03 19:10:22 ksekar
502 <rdar://problem/3498644>: malloc'd data not zero'd
503
504 Revision 1.34 2003/12/03 02:00:01 ksekar
505 <rdar://problem/3498644>: malloc'd data not zero'd
506
507 Revision 1.33 2003/11/22 01:18:46 ksekar
508 <rdar://problem/3486646>: config change handler not called for dns-sd services
509
510 Revision 1.32 2003/11/20 21:46:12 ksekar
511 <rdar://problem/3486635>: leak: DNSServiceRegisterRecord
512
513 Revision 1.31 2003/11/20 20:33:05 ksekar
514 <rdar://problem/3486635>: leak: DNSServiceRegisterRecord
515
516 Revision 1.30 2003/11/20 02:10:55 ksekar
517 <rdar://problem/3486643>: cleanup DNSServiceAdd/RemoveRecord
518
519 Revision 1.29 2003/11/14 21:18:32 cheshire
520 <rdar://problem/3484766>: Security: Crashing bug in mDNSResponder
521 Fix code that should use buffer size MAX_ESCAPED_DOMAIN_NAME (1005) instead of 256-byte buffers.
522
523 Revision 1.28 2003/11/08 22:18:29 cheshire
524 <rdar://problem/3477870>: Don't need to show process ID in *every* mDNSResponder syslog message
525
526 Revision 1.27 2003/11/05 22:44:57 ksekar
527 <rdar://problem/3335230>: No bounds checking when reading data from client
528 Reviewed by: Stuart Cheshire
529
530 Revision 1.26 2003/10/23 17:51:04 ksekar
531 <rdar://problem/3335216>: handle blocked clients more efficiently
532 Changed gettimeofday() to mDNS_TimeNow(&mDNSStorage);
533
534 Revision 1.25 2003/10/22 23:37:49 ksekar
535 <rdar://problem/3459141>: crash/hang in abort_client
536
537 Revision 1.24 2003/10/21 20:59:40 ksekar
538 <rdar://problem/3335216>: handle blocked clients moreefficiently
539
540 Revision 1.23 2003/09/23 02:12:43 cheshire
541 Also include port number in list of services registered via new UDS API
542
543 Revision 1.22 2003/08/19 16:03:55 ksekar
544 <rdar://problem/3380097>: ER: SIGINFO dump should include resolves started by DNSServiceQueryRecord
545 Check termination_context for NULL before dereferencing.
546
547 Revision 1.21 2003/08/19 05:39:43 cheshire
548 <rdar://problem/3380097> SIGINFO dump should include resolves started by DNSServiceQueryRecord
549
550 Revision 1.20 2003/08/16 03:39:01 cheshire
551 <rdar://problem/3338440> InterfaceID -1 indicates "local only"
552
553 Revision 1.19 2003/08/15 20:16:03 cheshire
554 <rdar://problem/3366590> mDNSResponder takes too much RPRVT
555 We want to avoid touching the rdata pages, so we don't page them in.
556 1. RDLength was stored with the rdata, which meant touching the page just to find the length.
557 Moved this from the RData to the ResourceRecord object.
558 2. To avoid unnecessarily touching the rdata just to compare it,
559 compute a hash of the rdata and store the hash in the ResourceRecord object.
560
561 Revision 1.18 2003/08/15 00:38:00 ksekar
562 <rdar://problem/3377005>: Bug: buffer overrun when reading long rdata from client
563
564 Revision 1.17 2003/08/14 02:18:21 cheshire
565 <rdar://problem/3375491> Split generic ResourceRecord type into two separate types: AuthRecord and CacheRecord
566
567 Revision 1.16 2003/08/13 23:58:52 ksekar
568 <rdar://problem/3374911>: Bug: UDS Sub-type browsing works, but not sub-type registration
569 Fixed pointer increment error, moved subtype reading for-loop for easier error bailout.
570
571 Revision 1.15 2003/08/13 17:30:33 ksekar
572 <rdar://problem/3374671>: DNSServiceAddRecord doesn't work
573 Fixed various problems with handling the AddRecord request and freeing the ExtraResourceRecords.
574
575 Revision 1.14 2003/08/12 19:56:25 cheshire
576 Update to APSL 2.0
577
578 */
579
580 #if defined(_WIN32)
581 #include <process.h>
582 #define dnssd_strerror(X) win32_strerror(X)
583 #define usleep(X) Sleep(((X)+999)/1000)
584 static char * win32_strerror(int inErrorCode);
585 #else
586 #include <fcntl.h>
587 #include <errno.h>
588 #include <sys/ioctl.h>
589 #include <sys/types.h>
590 #include <sys/time.h>
591 #include <sys/resource.h>
592 #define dnssd_strerror(X) strerror(X)
593 #endif
594
595 #include <stdlib.h>
596 #include <stdio.h>
597 #include "mDNSEmbeddedAPI.h"
598 #include "DNSCommon.h"
599 #include "uds_daemon.h"
600 #include "dns_sd.h"
601 #include "dnssd_ipc.h"
602
603 // Apple specific configuration functionality, not required for other platforms
604 #ifdef __MACOSX__
605 #include <sys/ucred.h>
606 #ifndef LOCAL_PEERCRED
607 #define LOCAL_PEERCRED 0x001 /* retrieve peer credentials */
608 #endif // LOCAL_PEERCRED
609 #endif //__MACOSX__
610
611 // Types and Data Structures
612 // ----------------------------------------------------------------------
613
614 typedef enum
615 {
616 t_uninitialized,
617 t_morecoming,
618 t_complete,
619 t_error,
620 t_terminated
621 } transfer_state;
622
623 typedef void (*req_termination_fn)(void *);
624
625 typedef struct registered_record_entry
626 {
627 uint32_t key;
628 AuthRecord *rr;
629 struct registered_record_entry *next;
630 client_context_t client_context;
631 struct request_state *rstate;
632 } registered_record_entry;
633
634 // A single registered service: ServiceRecordSet + bookkeeping
635 // Note that we duplicate some fields from parent service_info object
636 // to facilitate cleanup, when instances and parent may be deallocated at different times.
637 typedef struct service_instance
638 {
639 struct service_instance *next;
640 mDNSBool autoname; // Set if this name is tied to the Computer Name
641 mDNSBool autorename; // Set if this client wants us to automatically rename on conflict
642 mDNSBool allowremotequery; // Respond to unicast queries from outside the local link?
643 mDNSBool rename_on_memfree; // Set on config change when we deregister original name
644 domainlabel name;
645 domainname domain;
646 mDNSBool default_local; // is this the "local." from an empty-string registration?
647 struct request_state *request;
648 int sd;
649 AuthRecord *subtypes;
650 ServiceRecordSet srs; // note - must be last field in struct
651 } service_instance;
652
653 // A client-created service. May reference several service_info objects if default
654 // settings cause registration in multiple domains.
655 typedef struct
656 {
657 uint16_t txtlen;
658 void *txtdata;
659 mDNSIPPort port;
660 domainlabel name;
661 char type_as_string[MAX_ESCAPED_DOMAIN_NAME];
662 domainname type;
663 mDNSBool default_domain;
664 domainname host;
665 mDNSBool autoname; // Set if this name is tied to the Computer Name
666 mDNSBool autorename; // Set if this client wants us to automatically rename on conflict
667 mDNSBool allowremotequery; // Respond to unicast queries from outside the local link?
668 int num_subtypes;
669 mDNSInterfaceID InterfaceID;
670 service_instance *instances;
671 struct request_state *request;
672 } service_info;
673
674 // for multi-domain default browsing
675 typedef struct browser_t
676 {
677 DNSQuestion q;
678 domainname domain;
679 struct browser_t *next;
680 } browser_t;
681
682 // parent struct for browser instances: list pointer plus metadata
683 typedef struct
684 {
685 mDNSBool default_domain;
686 mDNSBool ForceMCast;
687 domainname regtype;
688 mDNSInterfaceID interface_id;
689 struct request_state *rstate;
690 browser_t *browsers;
691 } browser_info_t;
692
693 typedef struct
694 {
695 mStatus err; // Note: This field is in NETWORK byte order
696 int nwritten;
697 dnssd_sock_t sd;
698 } undelivered_error_t;
699
700 typedef struct request_state
701 {
702 // connection structures
703 dnssd_sock_t sd;
704
705 // state of read (in case message is read over several recv() calls)
706 transfer_state ts;
707 uint32_t hdr_bytes; // bytes of header already read
708 ipc_msg_hdr hdr;
709 uint32_t data_bytes; // bytes of message data already read
710 char *msgbuf; // pointer to data storage to pass to free()
711 char *msgdata; // pointer to data to be read from (may be modified)
712 int bufsize; // size of data storage
713
714 // reply, termination, error, and client context info
715 int no_reply; // don't send asynchronous replies to client
716 int time_blocked; // record time of a blocked client
717 void *client_context; // don't touch this - pointer only valid in client's addr space
718 struct reply_state *replies; // corresponding (active) reply list
719 undelivered_error_t *u_err;
720 void *termination_context;
721 req_termination_fn terminate;
722
723 //!!!KRS toss these pointers in a union
724 // registration context associated with this request (null if not applicable)
725 registered_record_entry *reg_recs; // muliple registrations for a connection-oriented request
726 service_info *service_registration;
727 browser_info_t *browser_info;
728 struct request_state *next;
729 } request_state;
730
731 // struct physically sits between ipc message header and call-specific fields in the message buffer
732 typedef struct
733 {
734 DNSServiceFlags flags; // Note: This field is in NETWORK byte order
735 uint32_t ifi; // Note: This field is in NETWORK byte order
736 DNSServiceErrorType error; // Note: This field is in NETWORK byte order
737 } reply_hdr;
738
739 typedef struct reply_state
740 {
741 // state of the transmission
742 dnssd_sock_t sd;
743 transfer_state ts;
744 uint32_t nwriten;
745 uint32_t len;
746 // context of the reply
747 struct request_state *request; // the request that this answers
748 struct reply_state *next; // if there are multiple unsent replies
749 // pointer into message buffer - allows fields to be changed after message is formatted
750 ipc_msg_hdr *mhdr;
751 reply_hdr *rhdr;
752 char *sdata; // pointer to start of call-specific data
753 // pointer to malloc'd buffer
754 char *msgbuf;
755 } reply_state;
756
757 // domain enumeration and resolv calls require 2 mDNSCore calls, so we need separate interconnected
758 // structures to handle callbacks
759 typedef struct
760 {
761 DNSQuestion question;
762 mDNS_DomainType type;
763 request_state *rstate;
764 } domain_enum_t;
765
766 typedef struct
767 {
768 domain_enum_t *all;
769 domain_enum_t *def;
770 request_state *rstate;
771 } enum_termination_t;
772
773 typedef struct
774 {
775 request_state *rstate;
776 DNSQuestion qtxt;
777 DNSQuestion qsrv;
778 // const ResourceRecord *txt;
779 // const ResourceRecord *srv;
780 mDNSBool srv;
781 mDNSBool txt;
782 domainname target;
783 mDNSIPPort port;
784 mDNSu16 txtlen;
785 mDNSu8 txtdata[AbsoluteMaxDNSMessageData];
786 } resolve_termination_t;
787
788 #ifdef _HAVE_SETDOMAIN_SUPPORT_
789 typedef struct default_browse_list_t
790 {
791 struct default_browse_list_t *next;
792 uid_t uid;
793 AuthRecord ptr_rec;
794 } default_browse_list_t;
795
796 static default_browse_list_t *default_browse_list = NULL;
797 #endif // _HAVE_SETDOMAIN_SUPPORT_
798
799 // globals
800 mDNSexport mDNS mDNSStorage;
801 #define gmDNS (&mDNSStorage)
802
803 static dnssd_sock_t listenfd = dnssd_InvalidSocket;
804 static request_state * all_requests = NULL;
805
806 #define MAX_TIME_BLOCKED 60 * mDNSPlatformOneSecond // try to send data to a blocked client for 60 seconds before
807 // terminating connection
808 #define MSG_PAD_BYTES 5 // pad message buffer (read from client) with n zero'd bytes to guarantee
809 // n get_string() calls w/o buffer overrun
810 // private function prototypes
811 static void connect_callback(void *info);
812 static int read_msg(request_state *rs);
813 static int send_msg(reply_state *rs);
814 static void abort_request(request_state *rs);
815 static void request_callback(void *info);
816 static void handle_resolve_request(request_state *rstate);
817 static void question_result_callback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord);
818 static void question_termination_callback(void *context);
819 static void handle_browse_request(request_state *request);
820 static void browse_termination_callback(void *context);
821 static void browse_result_callback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord);
822 static void handle_regservice_request(request_state *request);
823 static void regservice_termination_callback(void *context);
824 static void process_service_registration(ServiceRecordSet *const srs, mDNSBool SuppressError);
825 static void regservice_callback(mDNS *const m, ServiceRecordSet *const srs, mStatus result);
826 static mStatus handle_add_request(request_state *rstate);
827 static mStatus handle_update_request(request_state *rstate);
828 static mStatus gen_rr_response(domainname *servicename, mDNSInterfaceID id, request_state *request, reply_state **rep);
829 static void append_reply(request_state *req, reply_state *rep);
830 static int build_domainname_from_strings(domainname *srv, char *name, char *regtype, char *domain);
831 static void enum_termination_callback(void *context);
832 static void enum_result_callback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord);
833 static void handle_query_request(request_state *rstate);
834 static reply_state *format_enumeration_reply(request_state *rstate, const char *domain, DNSServiceFlags flags, uint32_t ifi, DNSServiceErrorType err);
835 static void handle_enum_request(request_state *rstate);
836 static mStatus handle_regrecord_request(request_state *rstate);
837 static void regrecord_callback(mDNS *const m, AuthRecord *const rr, mStatus result);
838 static void connected_registration_termination(void *context);
839 static void handle_reconfirm_request(request_state *rstate);
840 static AuthRecord *read_rr_from_ipc_msg(char *msgbuf, int ttl, int validate_flags);
841 static mStatus handle_removerecord_request(request_state *rstate);
842 static void reset_connected_rstate(request_state *rstate);
843 static int deliver_error(request_state *rstate, mStatus err);
844 static int deliver_async_error(request_state *rs, reply_op_t op, mStatus err);
845 static transfer_state send_undelivered_error(request_state *rs);
846 static reply_state *create_reply(reply_op_t op, size_t datalen, request_state *request);
847 static void update_callback(mDNS *const m, AuthRecord *const rr, RData *oldrd);
848 static void my_perror(char *errmsg);
849 static void unlink_request(request_state *rs);
850 static void resolve_result_callback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord);
851 static void resolve_termination_callback(void *context);
852 static int validate_message(request_state *rstate);
853 static mStatus remove_extra(request_state *rstate, service_instance *serv);
854 static mStatus remove_record(request_state *rstate);
855 static void free_service_instance(service_instance *srv);
856 static uint32_t dnssd_htonl(uint32_t l);
857 static void handle_setdomain_request(request_state *rstate);
858
859 // initialization, setup/teardown functions
860
861 // If a platform specifies its own PID file name, we use that
862 #ifndef PID_FILE
863 #define PID_FILE "/var/run/mDNSResponder.pid"
864 #endif
865
866 mDNSlocal void LogClientInfo(request_state *req)
867 {
868 void *t = req->termination_context;
869 if (t)
870 {
871 if (req->terminate == regservice_termination_callback)
872 {
873 service_instance *ptr;
874 for (ptr = ((service_info *)t)->instances; ptr; ptr = ptr->next)
875 LogMsgNoIdent("%3d: DNSServiceRegister %##s %u", req->sd, ptr->srs.RR_SRV.resrec.name->c, SRS_PORT(&ptr->srs));
876 }
877 else if (req->terminate == browse_termination_callback)
878 {
879 browser_t *blist;
880 for (blist = req->browser_info->browsers; blist; blist = blist->next)
881 LogMsgNoIdent("%3d: DNSServiceBrowse %##s", req->sd, blist->q.qname.c);
882 }
883 else if (req->terminate == resolve_termination_callback)
884 LogMsgNoIdent("%3d: DNSServiceResolve %##s", req->sd, ((resolve_termination_t *)t)->qsrv.qname.c);
885 else if (req->terminate == question_termination_callback)
886 LogMsgNoIdent("%3d: DNSServiceQueryRecord %##s", req->sd, ((DNSQuestion *) t)->qname.c);
887 else if (req->terminate == enum_termination_callback)
888 LogMsgNoIdent("%3d: DNSServiceEnumerateDomains %##s", req->sd, ((enum_termination_t *) t)->all->question.qname.c);
889 }
890 }
891
892 static void FatalError(char *errmsg)
893 {
894 LogMsg("%s: %s", errmsg, dnssd_strerror(dnssd_errno()));
895 *(long*)0 = 0; // On OS X abort() doesn't generate a crash log, but writing to zero does
896 abort(); // On platforms where writing to zero doesn't generate an exception, abort instead
897 }
898
899 int udsserver_init(void)
900 {
901 dnssd_sockaddr_t laddr;
902 int ret;
903 #if defined(_WIN32)
904 u_long opt = 1;
905 #endif
906
907 // If a particular platform wants to opt out of having a PID file, define PID_FILE to be ""
908 if (PID_FILE[0])
909 {
910 FILE *fp = fopen(PID_FILE, "w");
911 if (fp != NULL)
912 {
913 fprintf(fp, "%d\n", getpid());
914 fclose(fp);
915 }
916 }
917
918 if ((listenfd = socket(AF_DNSSD, SOCK_STREAM, 0)) == dnssd_InvalidSocket)
919 {
920 my_perror("ERROR: socket(AF_DNSSD, SOCK_STREAM, 0); failed");
921 goto error;
922 }
923
924 bzero(&laddr, sizeof(laddr));
925
926 #if defined(USE_TCP_LOOPBACK)
927 {
928 laddr.sin_family = AF_INET;
929 laddr.sin_port = htons(MDNS_TCP_SERVERPORT);
930 laddr.sin_addr.s_addr = inet_addr(MDNS_TCP_SERVERADDR);
931 ret = bind(listenfd, (struct sockaddr *) &laddr, sizeof(laddr));
932 if (ret < 0)
933 {
934 my_perror("ERROR: bind(listenfd, (struct sockaddr *) &laddr, sizeof(laddr)); failed");
935 goto error;
936 }
937 }
938 #else
939 {
940 mode_t mask = umask(0);
941 unlink(MDNS_UDS_SERVERPATH); //OK if this fails
942 laddr.sun_family = AF_LOCAL;
943 #ifndef NOT_HAVE_SA_LEN
944 // According to Stevens (section 3.2), there is no portable way to
945 // determine whether sa_len is defined on a particular platform.
946 laddr.sun_len = sizeof(struct sockaddr_un);
947 #endif
948 strcpy(laddr.sun_path, MDNS_UDS_SERVERPATH);
949 ret = bind(listenfd, (struct sockaddr *) &laddr, sizeof(laddr));
950 umask(mask);
951 if (ret < 0)
952 {
953 my_perror("ERROR: bind(listenfd, (struct sockaddr *) &laddr, sizeof(laddr)); failed");
954 goto error;
955 }
956 }
957 #endif
958
959 #if defined(_WIN32)
960 //
961 // SEH: do we even need to do this on windows? this socket
962 // will be given to WSAEventSelect which will automatically
963 // set it to non-blocking
964 //
965 if (ioctlsocket(listenfd, FIONBIO, &opt) != 0)
966 #else
967 if (fcntl(listenfd, F_SETFL, O_NONBLOCK) != 0)
968 #endif
969 {
970 my_perror("ERROR: could not set listen socket to non-blocking mode");
971 goto error;
972 }
973
974 if (listen(listenfd, LISTENQ) != 0)
975 {
976 my_perror("ERROR: could not listen on listen socket");
977 goto error;
978 }
979
980 if (mStatus_NoError != udsSupportAddFDToEventLoop(listenfd, connect_callback, (void *) NULL))
981 {
982 my_perror("ERROR: could not add listen socket to event loop");
983 goto error;
984 }
985
986 #if !defined(PLATFORM_NO_RLIMIT)
987 {
988 // Set maximum number of open file descriptors
989 #define MIN_OPENFILES 10240
990 struct rlimit maxfds, newfds;
991
992 // Due to bugs in OS X (<rdar://problem/2941095>, <rdar://problem/3342704>, <rdar://problem/3839173>)
993 // you have to get and set rlimits once before getrlimit will return sensible values
994 if (getrlimit(RLIMIT_NOFILE, &maxfds) < 0) { my_perror("ERROR: Unable to get file descriptor limit"); return 0; }
995 if (setrlimit(RLIMIT_NOFILE, &maxfds) < 0) my_perror("ERROR: Unable to set maximum file descriptor limit");
996
997 if (getrlimit(RLIMIT_NOFILE, &maxfds) < 0) { my_perror("ERROR: Unable to get file descriptor limit"); return 0; }
998 newfds.rlim_max = (maxfds.rlim_max > MIN_OPENFILES) ? maxfds.rlim_max : MIN_OPENFILES;
999 newfds.rlim_cur = (maxfds.rlim_cur > MIN_OPENFILES) ? maxfds.rlim_cur : MIN_OPENFILES;
1000 if (newfds.rlim_max != maxfds.rlim_max || newfds.rlim_cur != maxfds.rlim_cur)
1001 if (setrlimit(RLIMIT_NOFILE, &newfds) < 0) my_perror("ERROR: Unable to set maximum file descriptor limit");
1002
1003 if (getrlimit(RLIMIT_NOFILE, &maxfds) < 0) { my_perror("ERROR: Unable to get file descriptor limit"); return 0; }
1004 debugf("maxfds.rlim_max %d", (long)maxfds.rlim_max);
1005 debugf("maxfds.rlim_cur %d", (long)maxfds.rlim_cur);
1006 }
1007 #endif
1008
1009 return 0;
1010
1011 error:
1012
1013 my_perror("ERROR: udsserver_init");
1014 return -1;
1015 }
1016
1017 int udsserver_exit(void)
1018 {
1019 dnssd_close(listenfd);
1020
1021 #if !defined(USE_TCP_LOOPBACK)
1022 // Currently, we're unable to remove /var/run/mdnsd because we've changed to userid "nobody"
1023 // to give up unnecessary privilege, but we need to be root to remove this Unix Domain Socket.
1024 // It would be nice if we could find a solution to this problem
1025 if (unlink(MDNS_UDS_SERVERPATH))
1026 debugf("Unable to remove %s", MDNS_UDS_SERVERPATH);
1027 #endif
1028
1029 return 0;
1030 }
1031
1032 mDNSs32 udsserver_idle(mDNSs32 nextevent)
1033 {
1034 request_state *req = all_requests, *tmp, *prev = NULL;
1035 reply_state *fptr;
1036 transfer_state result;
1037 mDNSs32 now = mDNS_TimeNow(&mDNSStorage);
1038
1039 while(req)
1040 {
1041 result = t_uninitialized;
1042 if (req->u_err)
1043 result = send_undelivered_error(req);
1044 if (result != t_error && result != t_morecoming && // don't try to send msg if send_error failed
1045 (req->ts == t_complete || req->ts == t_morecoming))
1046 {
1047 while(req->replies)
1048 {
1049 if (req->replies->next) req->replies->rhdr->flags |= dnssd_htonl(kDNSServiceFlagsMoreComing);
1050 result = send_msg(req->replies);
1051 if (result == t_complete)
1052 {
1053 fptr = req->replies;
1054 req->replies = req->replies->next;
1055 freeL("udsserver_idle", fptr);
1056 req->time_blocked = 0; // reset failure counter after successful send
1057 }
1058 else if (result == t_terminated || result == t_error)
1059 {
1060 abort_request(req);
1061 break;
1062 }
1063 else if (result == t_morecoming) break; // client's queues are full, move to next
1064 }
1065 }
1066 if (result == t_morecoming)
1067 {
1068 if (!req->time_blocked) req->time_blocked = now;
1069 debugf("udsserver_idle: client has been blocked for %ld seconds", (now - req->time_blocked) / mDNSPlatformOneSecond);
1070 if (now - req->time_blocked >= MAX_TIME_BLOCKED)
1071 {
1072 LogMsg("Could not write data to client %d after %ld seconds - aborting connection", req->sd, MAX_TIME_BLOCKED / mDNSPlatformOneSecond);
1073 LogClientInfo(req);
1074 abort_request(req);
1075 result = t_terminated;
1076 }
1077 else if (nextevent - now > mDNSPlatformOneSecond) nextevent = now + mDNSPlatformOneSecond; // try again in a second
1078 }
1079 if (result == t_terminated || result == t_error)
1080 //since we're already doing a list traversal, we unlink the request manunally instead of calling unlink_request()
1081 {
1082 tmp = req;
1083 if (prev) prev->next = req->next;
1084 if (req == all_requests) all_requests = all_requests->next;
1085 req = req->next;
1086 freeL("udsserver_idle", tmp);
1087 }
1088 else
1089 {
1090 prev = req;
1091 req = req->next;
1092 }
1093 }
1094 return nextevent;
1095 }
1096
1097 void udsserver_info(mDNS *const m)
1098 {
1099 mDNSs32 now = mDNS_TimeNow(m);
1100 mDNSu32 CacheUsed = 0, CacheActive = 0;
1101 mDNSu32 slot;
1102 CacheGroup *cg;
1103 CacheRecord *rr;
1104 request_state *req;
1105
1106 LogMsgNoIdent("Timenow 0x%08lX (%ld)", (mDNSu32)now, now);
1107
1108 for (slot = 0; slot < CACHE_HASH_SLOTS; slot++)
1109 for(cg = m->rrcache_hash[slot]; cg; cg=cg->next)
1110 {
1111 CacheUsed++; // Count one cache entity for the CacheGroup object
1112 for (rr = cg->members; rr; rr=rr->next)
1113 {
1114 mDNSs32 remain = rr->resrec.rroriginalttl - (now - rr->TimeRcvd) / mDNSPlatformOneSecond;
1115 CacheUsed++;
1116 if (rr->CRActiveQuestion) CacheActive++;
1117 LogMsgNoIdent("%s%6ld %s%-6s%-6s%s",
1118 rr->CRActiveQuestion ? "*" : " ", remain,
1119 (rr->resrec.RecordType & kDNSRecordTypePacketUniqueMask) ? "-" : " ", DNSTypeName(rr->resrec.rrtype),
1120 ((NetworkInterfaceInfo *)rr->resrec.InterfaceID)->ifname, CRDisplayString(m, rr));
1121 usleep(1000); // Limit rate a little so we don't flood syslog too fast
1122 }
1123 }
1124
1125 if (m->rrcache_totalused != CacheUsed)
1126 LogMsgNoIdent("Cache use mismatch: rrcache_totalused is %lu, true count %lu", m->rrcache_totalused, CacheUsed);
1127 if (m->rrcache_active != CacheActive)
1128 LogMsgNoIdent("Cache use mismatch: rrcache_active is %lu, true count %lu", m->rrcache_active, CacheActive);
1129 LogMsgNoIdent("Cache currently contains %lu records; %lu referenced by active questions", CacheUsed, CacheActive);
1130
1131 for (req = all_requests; req; req=req->next)
1132 LogClientInfo(req);
1133
1134 now = mDNS_TimeNow(m);
1135 LogMsgNoIdent("Timenow 0x%08lX (%ld)", (mDNSu32)now, now);
1136 }
1137
1138 static void rename_service(service_instance *srv)
1139 {
1140 if (srv->autoname && !SameDomainLabel(srv->name.c, gmDNS->nicelabel.c))
1141 {
1142 srv->rename_on_memfree = 1;
1143 if (mDNS_DeregisterService(gmDNS, &srv->srs)) // If service deregistered already, we can re-register immediately
1144 regservice_callback(gmDNS, &srv->srs, mStatus_MemFree);
1145 }
1146 }
1147
1148 void udsserver_handle_configchange(void)
1149 {
1150 request_state *req;
1151
1152
1153 for (req = all_requests; req; req = req->next)
1154 {
1155 if (req->service_registration)
1156 {
1157 service_instance *ptr;
1158 for (ptr = req->service_registration->instances; ptr; ptr = ptr->next)
1159 rename_service(ptr);
1160 }
1161 }
1162 }
1163
1164 static void connect_callback(void *info)
1165 {
1166 dnssd_sock_t sd;
1167 unsigned int len;
1168 unsigned long optval;
1169 dnssd_sockaddr_t cliaddr;
1170 request_state *rstate;
1171 (void)info; // Unused
1172
1173 len = (int) sizeof(cliaddr);
1174
1175 sd = accept(listenfd, (struct sockaddr*) &cliaddr, &len);
1176
1177 if (sd == dnssd_InvalidSocket)
1178 {
1179 if (dnssd_errno() == dnssd_EWOULDBLOCK) return;
1180 my_perror("ERROR: accept");
1181 return;
1182 }
1183 optval = 1;
1184
1185 #ifdef SO_NOSIGPIPE
1186 // Some environments (e.g. OS X) support turning off SIGPIPE for a socket
1187 if (setsockopt(sd, SOL_SOCKET, SO_NOSIGPIPE, &optval, sizeof(optval)) < 0)
1188 {
1189 my_perror("ERROR: setsockopt - SO_NOSIGPIPE - aborting client");
1190 dnssd_close(sd);
1191 return;
1192 }
1193 #endif
1194
1195 #if defined(_WIN32)
1196 if (ioctlsocket(sd, FIONBIO, &optval) != 0)
1197 #else
1198 if (fcntl(sd, F_SETFL, O_NONBLOCK) != 0)
1199 #endif
1200 {
1201 my_perror("ERROR: fcntl(sd, F_SETFL, O_NONBLOCK) - aborting client");
1202 dnssd_close(sd);
1203 return;
1204 }
1205
1206 // allocate a request_state struct that will live with the socket
1207 rstate = mallocL("connect_callback", sizeof(request_state));
1208 if (!rstate) FatalError("ERROR: malloc");
1209 bzero(rstate, sizeof(request_state));
1210 rstate->ts = t_morecoming;
1211 rstate->sd = sd;
1212
1213 LogOperation("%3d: Adding FD", rstate->sd);
1214 if ( mStatus_NoError != udsSupportAddFDToEventLoop( sd, request_callback, rstate))
1215 return;
1216 rstate->next = all_requests;
1217 all_requests = rstate;
1218 }
1219
1220 // handler
1221 static void request_callback(void *info)
1222 {
1223 request_state *rstate = info;
1224 transfer_state result;
1225 dnssd_sockaddr_t cliaddr;
1226 int dedicated_error_socket;
1227 #if defined(_WIN32)
1228 u_long opt = 1;
1229 #endif
1230
1231 result = read_msg(rstate);
1232 if (result == t_morecoming)
1233 {
1234 return;
1235 }
1236 if (result == t_terminated)
1237 {
1238 abort_request(rstate);
1239 unlink_request(rstate);
1240 return;
1241 }
1242 if (result == t_error)
1243 {
1244 abort_request(rstate);
1245 unlink_request(rstate);
1246 return;
1247 }
1248
1249 if (rstate->hdr.version != VERSION)
1250 {
1251 LogMsg("ERROR: client incompatible with daemon (client version = %d, "
1252 "daemon version = %d)\n", rstate->hdr.version, VERSION);
1253 abort_request(rstate);
1254 unlink_request(rstate);
1255 return;
1256 }
1257
1258 if (validate_message(rstate) < 0)
1259 {
1260 // note that we cannot deliver an error message if validation fails, since the path to the error socket
1261 // may be contained in the (invalid) message body for some message types
1262 abort_request(rstate);
1263 unlink_request(rstate);
1264 LogMsg("Invalid message sent by client - may indicate a malicious program running on this machine!");
1265 return;
1266 }
1267
1268 // check if client wants silent operation
1269 if (rstate->hdr.flags & IPC_FLAGS_NOREPLY) rstate->no_reply = 1;
1270
1271 dedicated_error_socket = (rstate->hdr.op == reg_record_request || rstate->hdr.op == add_record_request ||
1272 rstate->hdr.op == update_record_request || rstate->hdr.op == remove_record_request);
1273
1274 if (((rstate->hdr.flags & IPC_FLAGS_REUSE_SOCKET) == 0) != dedicated_error_socket)
1275 LogMsg("WARNING: client request %d with incorrect flags setting 0x%X", rstate->hdr.op, rstate->hdr.flags);
1276
1277 // check if primary socket is to be used for synchronous errors, else open new socket
1278 if (dedicated_error_socket)
1279 {
1280 mStatus err = 0;
1281 int nwritten;
1282 int errfd = socket(AF_DNSSD, SOCK_STREAM, 0);
1283 if (errfd == dnssd_InvalidSocket)
1284 {
1285 my_perror("ERROR: socket");
1286 abort_request(rstate);
1287 unlink_request(rstate);
1288 return;
1289 }
1290
1291 #if defined(USE_TCP_LOOPBACK)
1292 {
1293 mDNSOpaque16 port;
1294 port.b[0] = rstate->msgdata[0];
1295 port.b[1] = rstate->msgdata[1];
1296 rstate->msgdata += 2;
1297 cliaddr.sin_family = AF_INET;
1298 cliaddr.sin_port = port.NotAnInteger;
1299 cliaddr.sin_addr.s_addr = inet_addr(MDNS_TCP_SERVERADDR);
1300 }
1301 #else
1302 {
1303 char ctrl_path[MAX_CTLPATH];
1304 get_string(&rstate->msgdata, ctrl_path, 256); // path is first element in message buffer
1305 bzero(&cliaddr, sizeof(cliaddr));
1306 cliaddr.sun_family = AF_LOCAL;
1307 strcpy(cliaddr.sun_path, ctrl_path);
1308 }
1309 #endif
1310 if (connect(errfd, (struct sockaddr *)&cliaddr, sizeof(cliaddr)) < 0)
1311 {
1312 my_perror("ERROR: connect");
1313 abort_request(rstate);
1314 unlink_request(rstate);
1315 return;
1316 }
1317 #if defined(_WIN32)
1318 if (ioctlsocket(errfd, FIONBIO, &opt) != 0)
1319 #else
1320 if (fcntl(errfd, F_SETFL, O_NONBLOCK) != 0)
1321 #endif
1322 {
1323 my_perror("ERROR: could not set control socket to non-blocking mode");
1324 abort_request(rstate);
1325 unlink_request(rstate);
1326 return;
1327 }
1328
1329 switch(rstate->hdr.op)
1330 {
1331 case reg_record_request: err = handle_regrecord_request (rstate); break;
1332 case add_record_request: err = handle_add_request (rstate); break;
1333 case update_record_request: err = handle_update_request (rstate); break;
1334 case remove_record_request: err = handle_removerecord_request(rstate); break;
1335 default: LogMsg("%3d: ERROR: udsserver_recv_request - unsupported request type: %d", rstate->sd, rstate->hdr.op);
1336 }
1337
1338 err = dnssd_htonl(err);
1339 nwritten = send(errfd, &err, sizeof(err), 0);
1340 // On a freshly-created Unix Domain Socket, the kernel should *never* fail to buffer a four-byte write for us.
1341 // If not, we don't attempt to handle this failure, but we do log it.
1342 if (nwritten < (int)sizeof(err))
1343 LogMsg("ERROR: failed to write error response back to caller: %d %d %s",
1344 nwritten, dnssd_errno(), dnssd_strerror(dnssd_errno()));
1345 dnssd_close(errfd);
1346 reset_connected_rstate(rstate); // Reset ready to accept the next request on this pipe
1347 }
1348 else
1349 {
1350 switch(rstate->hdr.op)
1351 {
1352 case resolve_request: handle_resolve_request (rstate); break;
1353 case query_request: handle_query_request (rstate); break;
1354 case browse_request: handle_browse_request (rstate); break;
1355 case reg_service_request: handle_regservice_request(rstate); break;
1356 case enumeration_request: handle_enum_request (rstate); break;
1357 case reconfirm_record_request: handle_reconfirm_request (rstate); break;
1358 case setdomain_request: handle_setdomain_request (rstate); break;
1359 default: LogMsg("%3d: ERROR: udsserver_recv_request - unsupported request type: %d", rstate->sd, rstate->hdr.op);
1360 }
1361 }
1362 }
1363
1364 // mDNS operation functions. Each operation has 3 associated functions - a request handler that parses
1365 // the client's request and makes the appropriate mDNSCore call, a result handler (passed as a callback
1366 // to the mDNSCore routine) that sends results back to the client, and a termination routine that aborts
1367 // the mDNSCore operation if the client dies or closes its socket.
1368
1369 // query and resolve calls have separate request handlers that parse the arguments from the client and
1370 // massage the name parameters appropriately, but the rest of the operations (making the query call,
1371 // delivering the result to the client, and termination) are identical.
1372
1373 static void handle_query_request(request_state *rstate)
1374 {
1375 DNSServiceFlags flags;
1376 uint32_t ifi;
1377 char name[256];
1378 uint16_t rrtype, rrclass;
1379 char *ptr;
1380 mStatus result;
1381 mDNSInterfaceID InterfaceID;
1382 DNSQuestion *q;
1383
1384 if (rstate->ts != t_complete)
1385 {
1386 LogMsg("ERROR: handle_query_request - transfer state != t_complete");
1387 goto error;
1388 }
1389 ptr = rstate->msgdata;
1390 if (!ptr)
1391 {
1392 LogMsg("ERROR: handle_query_request - NULL msgdata");
1393 goto error;
1394 }
1395
1396 flags = get_flags(&ptr);
1397 ifi = get_long(&ptr);
1398 if (get_string(&ptr, name, 256) < 0) goto bad_param;
1399 rrtype = get_short(&ptr);
1400 rrclass = get_short(&ptr);
1401 InterfaceID = mDNSPlatformInterfaceIDfromInterfaceIndex(gmDNS, ifi);
1402 if (ifi && !InterfaceID) goto bad_param;
1403
1404 q = mallocL("DNSQuestion", sizeof(DNSQuestion));
1405 if (!q) FatalError("ERROR: handle_query - malloc");
1406 bzero(q, sizeof(DNSQuestion));
1407
1408 q->InterfaceID = InterfaceID;
1409 q->Target = zeroAddr;
1410 if (!MakeDomainNameFromDNSNameString(&q->qname, name)) { freeL("DNSQuestion", q); goto bad_param; }
1411 q->qtype = rrtype;
1412 q->qclass = rrclass;
1413 q->LongLived = (flags & kDNSServiceFlagsLongLivedQuery) != 0;
1414 q->ExpectUnique = mDNSfalse;
1415 q->ForceMCast = (flags & kDNSServiceFlagsForceMulticast) != 0;
1416 q->QuestionCallback = question_result_callback;
1417 q->QuestionContext = rstate;
1418
1419 rstate->termination_context = q;
1420 rstate->terminate = question_termination_callback;
1421
1422 LogOperation("%3d: DNSServiceQueryRecord(%##s, %s) START", rstate->sd, q->qname.c, DNSTypeName(q->qtype));
1423 result = mDNS_StartQuery(gmDNS, q);
1424 if (result != mStatus_NoError) LogMsg("ERROR: mDNS_StartQuery: %d", (int)result);
1425
1426 if (result) rstate->terminate = NULL;
1427 if (deliver_error(rstate, result) < 0) goto error;
1428 return;
1429
1430 bad_param:
1431 deliver_error(rstate, mStatus_BadParamErr);
1432 rstate->terminate = NULL; // don't try to terminate insuccessful Core calls
1433 error:
1434 abort_request(rstate);
1435 unlink_request(rstate);
1436 return;
1437 }
1438
1439 static void handle_resolve_request(request_state *rstate)
1440 {
1441 DNSServiceFlags flags;
1442 uint32_t interfaceIndex;
1443 mDNSInterfaceID InterfaceID;
1444 char name[256], regtype[MAX_ESCAPED_DOMAIN_NAME], domain[MAX_ESCAPED_DOMAIN_NAME];
1445 char *ptr; // message data pointer
1446 domainname fqdn;
1447 resolve_termination_t *term;
1448 mStatus err;
1449
1450 if (rstate->ts != t_complete)
1451 {
1452 LogMsg("ERROR: handle_resolve_request - transfer state != t_complete");
1453 abort_request(rstate);
1454 unlink_request(rstate);
1455 return;
1456 }
1457
1458 // extract the data from the message
1459 ptr = rstate->msgdata;
1460 if (!ptr)
1461 {
1462 LogMsg("ERROR: handle_resolve_request - NULL msgdata");
1463 abort_request(rstate);
1464 unlink_request(rstate);
1465 return;
1466 }
1467 flags = get_flags(&ptr);
1468 interfaceIndex = get_long(&ptr);
1469 InterfaceID = mDNSPlatformInterfaceIDfromInterfaceIndex(gmDNS, interfaceIndex);
1470 if (interfaceIndex && !InterfaceID)
1471 { LogMsg("ERROR: handle_resolve_request - Couldn't find InterfaceID for interfaceIndex %d", interfaceIndex); goto bad_param; }
1472 if (get_string(&ptr, name, 256) < 0 ||
1473 get_string(&ptr, regtype, MAX_ESCAPED_DOMAIN_NAME) < 0 ||
1474 get_string(&ptr, domain, MAX_ESCAPED_DOMAIN_NAME) < 0)
1475 { LogMsg("ERROR: handle_resolve_request - Couldn't read name/regtype/domain"); goto bad_param; }
1476
1477 // free memory in rstate since we don't need it anymore
1478 freeL("handle_resolve_request", rstate->msgbuf);
1479 rstate->msgbuf = NULL;
1480
1481 if (build_domainname_from_strings(&fqdn, name, regtype, domain) < 0)
1482 { LogMsg("ERROR: handle_resolve_request - Couldn't build_domainname_from_strings “%s” “%s” “%s”", name, regtype, domain); goto bad_param; }
1483
1484 // set up termination info
1485 term = mallocL("handle_resolve_request", sizeof(resolve_termination_t));
1486 bzero(term, sizeof(*term));
1487 if (!term) FatalError("ERROR: malloc");
1488
1489 // format questions
1490 term->qsrv.InterfaceID = InterfaceID;
1491 term->qsrv.Target = zeroAddr;
1492 memcpy(&term->qsrv.qname, &fqdn, MAX_DOMAIN_NAME);
1493 term->qsrv.qtype = kDNSType_SRV;
1494 term->qsrv.qclass = kDNSClass_IN;
1495 term->qsrv.LongLived = mDNSfalse;
1496 term->qsrv.ExpectUnique = mDNStrue;
1497 term->qsrv.ForceMCast = mDNSfalse;
1498 term->qsrv.QuestionCallback = resolve_result_callback;
1499 term->qsrv.QuestionContext = rstate;
1500
1501 term->qtxt.InterfaceID = InterfaceID;
1502 term->qtxt.Target = zeroAddr;
1503 memcpy(&term->qtxt.qname, &fqdn, MAX_DOMAIN_NAME);
1504 term->qtxt.qtype = kDNSType_TXT;
1505 term->qtxt.qclass = kDNSClass_IN;
1506 term->qtxt.LongLived = mDNSfalse;
1507 term->qtxt.ExpectUnique = mDNStrue;
1508 term->qtxt.ForceMCast = mDNSfalse;
1509 term->qtxt.QuestionCallback = resolve_result_callback;
1510 term->qtxt.QuestionContext = rstate;
1511
1512 term->rstate = rstate;
1513 rstate->termination_context = term;
1514 rstate->terminate = resolve_termination_callback;
1515
1516 // ask the questions
1517 LogOperation("%3d: DNSServiceResolve(%##s) START", rstate->sd, term->qsrv.qname.c);
1518 err = mDNS_StartQuery(gmDNS, &term->qsrv);
1519 if (!err) err = mDNS_StartQuery(gmDNS, &term->qtxt);
1520
1521 if (err)
1522 {
1523 freeL("handle_resolve_request", term);
1524 rstate->terminate = NULL; // prevent abort_request() from invoking termination callback
1525 }
1526 if (deliver_error(rstate, err) < 0 || err)
1527 {
1528 abort_request(rstate);
1529 unlink_request(rstate);
1530 }
1531 return;
1532
1533 bad_param:
1534 deliver_error(rstate, mStatus_BadParamErr);
1535 abort_request(rstate);
1536 unlink_request(rstate);
1537 }
1538
1539 static void resolve_termination_callback(void *context)
1540 {
1541 resolve_termination_t *term = context;
1542 request_state *rs;
1543
1544 if (!term)
1545 {
1546 LogMsg("ERROR: resolve_termination_callback: double termination");
1547 return;
1548 }
1549 rs = term->rstate;
1550 LogOperation("%3d: DNSServiceResolve(%##s) STOP", rs->sd, term->qtxt.qname.c);
1551
1552 mDNS_StopQuery(gmDNS, &term->qtxt);
1553 mDNS_StopQuery(gmDNS, &term->qsrv);
1554
1555 freeL("resolve_termination_callback", term);
1556 rs->termination_context = NULL;
1557 }
1558
1559 static void resolve_result_callback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord)
1560 {
1561 size_t len = 0;
1562 char fullname[MAX_ESCAPED_DOMAIN_NAME], target[MAX_ESCAPED_DOMAIN_NAME];
1563 char *data;
1564 transfer_state result;
1565 reply_state *rep;
1566 request_state *rs = question->QuestionContext;
1567 resolve_termination_t *res = rs->termination_context;
1568 (void)m; // Unused
1569
1570 LogOperation("%3d: DNSServiceResolve(%##s, %s) RESULT %s", rs->sd, question->qname.c, DNSTypeName(question->qtype), RRDisplayString(m, answer));
1571
1572 // This code used to do this trick of just keeping a copy of the pointer to
1573 // the answer record in the cache, but the unicast query code doesn't currently
1574 // put its answer records in the cache, so for now we can't do this.
1575
1576 if (!AddRecord)
1577 {
1578 // if (answer->rrtype == kDNSType_TXT && res->txt == answer) res->txt = mDNSNULL;
1579 // if (answer->rrtype == kDNSType_SRV && res->srv == answer) res->srv = mDNSNULL;
1580 return;
1581 }
1582
1583 // if (answer->rrtype == kDNSType_TXT) res->txt = answer;
1584 // if (answer->rrtype == kDNSType_SRV) res->srv = answer;
1585
1586 if (answer->rrtype == kDNSType_SRV)
1587 {
1588 AssignDomainName(&res->target, &answer->rdata->u.srv.target);
1589 res->port = answer->rdata->u.srv.port;
1590 res->srv = mDNStrue;
1591 }
1592 if (answer->rrtype == kDNSType_TXT)
1593 {
1594 if (answer->rdlength > AbsoluteMaxDNSMessageData) return;
1595 res->txtlen = answer->rdlength;
1596 mDNSPlatformMemCopy(answer->rdata->u.data, res->txtdata, res->txtlen);
1597 res->txt = mDNStrue;
1598 }
1599
1600 if (!res->txt || !res->srv) return; // only deliver result to client if we have both answers
1601
1602 ConvertDomainNameToCString(answer->name, fullname);
1603 ConvertDomainNameToCString(&res->target, target);
1604
1605 // calculate reply length
1606 len += sizeof(DNSServiceFlags);
1607 len += sizeof(uint32_t); // interface index
1608 len += sizeof(DNSServiceErrorType);
1609 len += strlen(fullname) + 1;
1610 len += strlen(target) + 1;
1611 len += 2 * sizeof(uint16_t); // port, txtLen
1612 len += res->txtlen;
1613
1614 // allocate/init reply header
1615 rep = create_reply(resolve_reply, len, rs);
1616 rep->rhdr->flags = dnssd_htonl(0);
1617 rep->rhdr->ifi = dnssd_htonl(mDNSPlatformInterfaceIndexfromInterfaceID(gmDNS, answer->InterfaceID));
1618 rep->rhdr->error = dnssd_htonl(kDNSServiceErr_NoError);
1619
1620 data = rep->sdata;
1621
1622 // write reply data to message
1623 put_string(fullname, &data);
1624 put_string(target, &data);
1625 *data++ = res->port.b[0];
1626 *data++ = res->port.b[1];
1627 put_short(res->txtlen, &data);
1628 put_rdata(res->txtlen, res->txtdata, &data);
1629
1630 result = send_msg(rep);
1631 if (result == t_error || result == t_terminated)
1632 {
1633 abort_request(rs);
1634 unlink_request(rs);
1635 freeL("resolve_result_callback", rep);
1636 }
1637 else if (result == t_complete) freeL("resolve_result_callback", rep);
1638 else append_reply(rs, rep);
1639 }
1640
1641 // what gets called when a resolve is completed and we need to send the data back to the client
1642 static void question_result_callback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord)
1643 {
1644 char *data;
1645 char name[MAX_ESCAPED_DOMAIN_NAME];
1646 request_state *req = question->QuestionContext;
1647 reply_state *rep;
1648 size_t len;
1649 (void)m; // Unused
1650
1651 LogOperation("%3d: DNSServiceQueryRecord(%##s, %s) RESULT %s", req->sd, question->qname.c, DNSTypeName(question->qtype), RRDisplayString(m, answer));
1652 //mDNS_StopQuery(m, question);
1653
1654 // calculate reply data length
1655 len = sizeof(DNSServiceFlags);
1656 len += 2 * sizeof(uint32_t); // if index + ttl
1657 len += sizeof(DNSServiceErrorType);
1658 len += 3 * sizeof(uint16_t); // type, class, rdlen
1659 len += answer->rdlength;
1660 ConvertDomainNameToCString(answer->name, name);
1661 len += strlen(name) + 1;
1662
1663 rep = create_reply(query_reply, len, req);
1664
1665 rep->rhdr->flags = dnssd_htonl(AddRecord ? kDNSServiceFlagsAdd : 0);
1666 rep->rhdr->ifi = dnssd_htonl(mDNSPlatformInterfaceIndexfromInterfaceID(gmDNS, answer->InterfaceID));
1667 rep->rhdr->error = dnssd_htonl(kDNSServiceErr_NoError);
1668
1669 data = rep->sdata;
1670
1671 put_string(name, &data);
1672 put_short(answer->rrtype, &data);
1673 put_short(answer->rrclass, &data);
1674 put_short(answer->rdlength, &data);
1675 put_rdata(answer->rdlength, answer->rdata->u.data, &data);
1676 put_long(AddRecord ? answer->rroriginalttl : 0, &data);
1677
1678 append_reply(req, rep);
1679 return;
1680 }
1681
1682 static void question_termination_callback(void *context)
1683 {
1684 DNSQuestion *q = context;
1685 LogOperation("%3d: DNSServiceQueryRecord(%##s, %s) STOP", ((request_state *)q->QuestionContext)->sd, q->qname.c, DNSTypeName(q->qtype));
1686 mDNS_StopQuery(gmDNS, q); // no need to error check
1687 freeL("question_termination_callback", q);
1688 }
1689
1690 // If there's a comma followed by another character,
1691 // FindFirstSubType overwrites the comma with a nul and returns the pointer to the next character.
1692 // Otherwise, it returns a pointer to the final nul at the end of the string
1693 static char *FindFirstSubType(char *p)
1694 {
1695 while (*p)
1696 {
1697 if (p[0] == '\\' && p[1]) p += 2;
1698 else if (p[0] == ',' && p[1]) { *p++ = 0; return(p); }
1699 else p++;
1700 }
1701 return(p);
1702 }
1703
1704 // If there's a comma followed by another character,
1705 // FindNextSubType overwrites the comma with a nul and returns the pointer to the next character.
1706 // If it finds an illegal unescaped dot in the subtype name, it returns mDNSNULL
1707 // Otherwise, it returns a pointer to the final nul at the end of the string
1708 static char *FindNextSubType(char *p)
1709 {
1710 while (*p)
1711 {
1712 if (p[0] == '\\' && p[1]) // If escape character
1713 p += 2; // ignore following character
1714 else if (p[0] == ',') // If we found a comma
1715 {
1716 if (p[1]) *p++ = 0;
1717 return(p);
1718 }
1719 else if (p[0] == '.')
1720 return(mDNSNULL);
1721 else p++;
1722 }
1723 return(p);
1724 }
1725
1726 // Returns -1 if illegal subtype found
1727 mDNSexport mDNSs32 ChopSubTypes(char *regtype)
1728 {
1729 mDNSs32 NumSubTypes = 0;
1730 char *stp = FindFirstSubType(regtype);
1731 while (stp && *stp) // If we found a comma...
1732 {
1733 if (*stp == ',') return(-1);
1734 NumSubTypes++;
1735 stp = FindNextSubType(stp);
1736 }
1737 if (!stp) return(-1);
1738 return(NumSubTypes);
1739 }
1740
1741 mDNSexport AuthRecord *AllocateSubTypes(mDNSs32 NumSubTypes, char *p)
1742 {
1743 AuthRecord *st = mDNSNULL;
1744 if (NumSubTypes)
1745 {
1746 mDNSs32 i;
1747 st = mallocL("ServiceSubTypes", NumSubTypes * sizeof(AuthRecord));
1748 if (!st) return(mDNSNULL);
1749 for (i = 0; i < NumSubTypes; i++)
1750 {
1751 mDNS_SetupResourceRecord(&st[i], mDNSNULL, mDNSInterface_Any, kDNSQType_ANY, kStandardTTL, 0, mDNSNULL, mDNSNULL);
1752 while (*p) p++;
1753 p++;
1754 if (!MakeDomainNameFromDNSNameString(st[i].resrec.name, p))
1755 { freeL("ServiceSubTypes", st); return(mDNSNULL); }
1756 }
1757 }
1758 return(st);
1759 }
1760
1761 #ifdef _HAVE_SETDOMAIN_SUPPORT_
1762 static void free_defdomain(mDNS *const m, AuthRecord *const rr, mStatus result)
1763 {
1764 (void)m; // unused
1765 if (result == mStatus_MemFree) free(rr->RecordContext); // context is the enclosing list structure
1766 }
1767 #endif
1768
1769 static void handle_setdomain_request(request_state *request)
1770 {
1771 mStatus err = mStatus_NoError;
1772 char *ptr;
1773 char domainstr[MAX_ESCAPED_DOMAIN_NAME];
1774 domainname domain;
1775 DNSServiceFlags flags;
1776 #ifdef _HAVE_SETDOMAIN_SUPPORT_
1777 struct xucred xuc;
1778 socklen_t xuclen;
1779 #endif
1780
1781 if (request->ts != t_complete)
1782 {
1783 LogMsg("ERROR: handle_setdomain_request - transfer state != t_complete");
1784 abort_request(request);
1785 unlink_request(request);
1786 return;
1787 }
1788
1789 // extract flags/domain from message
1790 ptr = request->msgdata;
1791 flags = get_flags(&ptr);
1792 if (get_string(&ptr, domainstr, MAX_ESCAPED_DOMAIN_NAME) < 0 ||
1793 !MakeDomainNameFromDNSNameString(&domain, domainstr))
1794 { err = mStatus_BadParamErr; goto end; }
1795
1796 freeL("handle_setdomain_request", request->msgbuf);
1797 request->msgbuf = NULL;
1798
1799 debugf("%3d: DNSServiceSetDefaultDomainForUser(%##s)", request->sd, domain.c);
1800
1801 #ifdef _HAVE_SETDOMAIN_SUPPORT_
1802 // this functionality currently only used for Apple-specific configuration, so we don't burned other platforms by mandating
1803 // the existence of this socket option
1804 xuclen = sizeof(xuc);
1805 if (getsockopt(request->sd, 0, LOCAL_PEERCRED, &xuc, &xuclen))
1806 { my_perror("ERROR: getsockopt, LOCAL_PEERCRED"); err = mStatus_UnknownErr; goto end; }
1807 if (xuc.cr_version != XUCRED_VERSION) { LogMsg("getsockopt, LOCAL_PEERCRED - bad version"); err = mStatus_UnknownErr; goto end; }
1808 LogMsg("Default domain %s %s for UID %d", domainstr, flags & kDNSServiceFlagsAdd ? "set" : "removed", xuc.cr_uid);
1809
1810 if (flags & kDNSServiceFlagsAdd)
1811 {
1812 // register a local-only PRT record
1813 default_browse_list_t *newelem = malloc(sizeof(default_browse_list_t));
1814 if (!newelem) { LogMsg("ERROR: malloc"); err = mStatus_NoMemoryErr; goto end; }
1815 mDNS_SetupResourceRecord(&newelem->ptr_rec, mDNSNULL, mDNSInterface_LocalOnly, kDNSType_PTR, 7200, kDNSRecordTypeShared, free_defdomain, newelem);
1816 MakeDomainNameFromDNSNameString(&newelem->ptr_rec.resrec.name, mDNS_DomainTypeNames[mDNS_DomainTypeBrowseDefault]);
1817 AppendDNSNameString (&newelem->ptr_rec.resrec.name, "local");
1818 AssignDomainName(&newelem->ptr_rec.resrec.rdata->u.name, &domain);
1819 newelem->uid = xuc.cr_uid;
1820 err = mDNS_Register(gmDNS, &newelem->ptr_rec);
1821 if (err) free(newelem);
1822 else
1823 {
1824 // link into list
1825 newelem->next = default_browse_list;
1826 default_browse_list = newelem;
1827 }
1828
1829 }
1830 else
1831 {
1832 // remove - find in list, deregister
1833 default_browse_list_t *ptr = default_browse_list, *prev = NULL;
1834 while (ptr)
1835 {
1836 if (SameDomainName(&ptr->ptr_rec.resrec.rdata->u.name, &domain))
1837 {
1838 if (prev) prev->next = ptr->next;
1839 else default_browse_list = ptr->next;
1840 err = mDNS_Deregister(gmDNS, &ptr->ptr_rec);
1841 break;
1842 }
1843 prev = ptr;
1844 ptr = ptr->next;
1845 }
1846 if (!ptr) { LogMsg("Attempt to remove nonexistent domain %s for UID %d", domainstr, xuc.cr_uid); err = mStatus_Invalid; }
1847 }
1848 #else
1849 err = mStatus_NoError;
1850 #endif // _HAVE_SETDOMAIN_SUPPORT_
1851
1852 end:
1853 deliver_error(request, err);
1854 abort_request(request);
1855 unlink_request(request);
1856 }
1857
1858 static mStatus add_domain_to_browser(browser_info_t *info, const domainname *d)
1859 {
1860 browser_t *b, *p;
1861 mStatus err;
1862
1863 for (p = info->browsers; p; p = p->next)
1864 {
1865 if (SameDomainName(&p->domain, d))
1866 { debugf("add_domain_to_browser - attempt to add domain %##d already in list", d->c); return mStatus_AlreadyRegistered; }
1867 }
1868
1869 b = mallocL("browser_t", sizeof(*b));
1870 if (!b) return mStatus_NoMemoryErr;
1871 AssignDomainName(&b->domain, d);
1872 err = mDNS_StartBrowse(gmDNS, &b->q, &info->regtype, d, info->interface_id, info->ForceMCast, browse_result_callback, info->rstate);
1873 if (err)
1874 {
1875 LogMsg("mDNS_StartBrowse returned %d for type %##s domain %##s", err, info->regtype.c, d->c);
1876 freeL("browser_t", b);
1877 }
1878 else
1879 {
1880 b->next = info->browsers;
1881 info->browsers = b;
1882 }
1883 return err;
1884 }
1885
1886 static void handle_browse_request(request_state *request)
1887 {
1888 DNSServiceFlags flags;
1889 uint32_t interfaceIndex;
1890 mDNSInterfaceID InterfaceID;
1891 char regtype[MAX_ESCAPED_DOMAIN_NAME], domain[MAX_ESCAPED_DOMAIN_NAME];
1892 domainname typedn, d, temp;
1893 mDNSs32 NumSubTypes;
1894 char *ptr;
1895 mStatus err = mStatus_NoError;
1896 DNameListElem *search_domain_list, *sdom;
1897 browser_info_t *info = NULL;
1898
1899 if (request->ts != t_complete)
1900 {
1901 LogMsg("ERROR: handle_browse_request - transfer state != t_complete");
1902 abort_request(request);
1903 unlink_request(request);
1904 return;
1905 }
1906
1907 // extract data from message
1908 ptr = request->msgdata;
1909 flags = get_flags(&ptr);
1910 interfaceIndex = get_long(&ptr);
1911 if (get_string(&ptr, regtype, MAX_ESCAPED_DOMAIN_NAME) < 0 ||
1912 get_string(&ptr, domain, MAX_ESCAPED_DOMAIN_NAME) < 0)
1913 { err = mStatus_BadParamErr; goto error; }
1914 freeL("handle_browse_request", request->msgbuf);
1915 request->msgbuf = NULL;
1916
1917 InterfaceID = mDNSPlatformInterfaceIDfromInterfaceIndex(gmDNS, interfaceIndex);
1918 if (interfaceIndex && !InterfaceID) { err = mStatus_BadParamErr; goto error; }
1919
1920 typedn.c[0] = 0;
1921 NumSubTypes = ChopSubTypes(regtype); // Note: Modifies regtype string to remove trailing subtypes
1922 if (NumSubTypes < 0 || NumSubTypes > 1) { err = mStatus_BadParamErr; goto error; }
1923 if (NumSubTypes == 1 && !AppendDNSNameString(&typedn, regtype + strlen(regtype) + 1))
1924 { err = mStatus_BadParamErr; goto error; }
1925
1926 if (!regtype[0] || !AppendDNSNameString(&typedn, regtype)) { err = mStatus_BadParamErr; goto error; }
1927
1928 if (!MakeDomainNameFromDNSNameString(&temp, regtype)) { err = mStatus_BadParamErr; goto error; }
1929 if (temp.c[0] > 15 && domain[0] == 0) strcpy(domain, "local."); // For over-long service types, we only allow domain "local"
1930
1931 // allocate and set up browser info
1932 info = mallocL("browser_info_t", sizeof(*info));
1933 if (!info) { err = mStatus_NoMemoryErr; goto error; }
1934
1935 request->browser_info = info;
1936 info->ForceMCast = (flags & kDNSServiceFlagsForceMulticast) != 0;
1937 info->interface_id = InterfaceID;
1938 AssignDomainName(&info->regtype, &typedn);
1939 info->rstate = request;
1940 info->default_domain = !domain[0];
1941 info->browsers = NULL;
1942
1943 // setup termination context
1944 request->termination_context = info;
1945 request->terminate = browse_termination_callback;
1946
1947 LogOperation("%3d: DNSServiceBrowse(\"%##s\", \"%s\") START", request->sd, info->regtype.c, domain);
1948 if (domain[0])
1949 {
1950 if (!MakeDomainNameFromDNSNameString(&d, domain)) { err = mStatus_BadParamErr; goto error; }
1951 err = add_domain_to_browser(info, &d);
1952 }
1953
1954 else
1955 {
1956 search_domain_list = mDNSPlatformGetSearchDomainList();
1957 for (sdom = search_domain_list; sdom; sdom = sdom->next)
1958 {
1959 err = add_domain_to_browser(info, &sdom->name);
1960 if (err)
1961 {
1962 if (SameDomainName(&sdom->name, &localdomain)) break;
1963 else err = mStatus_NoError; // suppress errors for non-local "default" domains
1964 }
1965
1966 }
1967 mDNS_FreeDNameList(search_domain_list);
1968 }
1969
1970 deliver_error(request, err);
1971 return;
1972
1973 error:
1974 if (info) freeL("browser_info_t", info);
1975 if (request->termination_context) request->termination_context = NULL;
1976 deliver_error(request, err);
1977 abort_request(request);
1978 unlink_request(request);
1979 }
1980
1981 static void browse_result_callback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord)
1982 {
1983 request_state *req = question->QuestionContext;
1984 reply_state *rep;
1985 mStatus err;
1986 (void)m; // Unused
1987 LogOperation("%3d: DNSServiceBrowse(%##s, %s) RESULT %s %s",
1988 req->sd, question->qname.c, DNSTypeName(question->qtype), AddRecord ? "Add" : "Rmv", RRDisplayString(m, answer));
1989
1990 err = gen_rr_response(&answer->rdata->u.name, answer->InterfaceID, req, &rep);
1991 if (err)
1992 {
1993 if (deliver_async_error(req, browse_reply, err) < 0)
1994 {
1995 abort_request(req);
1996 unlink_request(req);
1997 }
1998 return;
1999 }
2000 if (AddRecord) rep->rhdr->flags |= dnssd_htonl(kDNSServiceFlagsAdd); // non-zero TTL indicates add
2001 append_reply(req, rep);
2002 return;
2003 }
2004
2005 static void browse_termination_callback(void *context)
2006 {
2007 browser_info_t *info = context;
2008 browser_t *ptr;
2009
2010 if (!info) return;
2011
2012 while(info->browsers)
2013 {
2014 ptr = info->browsers;
2015 info->browsers = ptr->next;
2016 LogOperation("%3d: DNSServiceBrowse(%##s) STOP", info->rstate->sd, ptr->q.qname.c);
2017 mDNS_StopBrowse(gmDNS, &ptr->q); // no need to error-check result
2018 freeL("browse_termination_callback", ptr);
2019 }
2020
2021 info->rstate->termination_context = NULL;
2022 freeL("browser_info", info);
2023 }
2024
2025 mDNSexport void udsserver_default_browse_domain_changed(const domainname *d, mDNSBool add)
2026 {
2027 request_state *r;
2028
2029 for (r = all_requests; r; r = r->next)
2030 {
2031 browser_info_t *info = r->browser_info;
2032
2033 if (!info || !info->default_domain) continue;
2034 if (add) add_domain_to_browser(info, d);
2035 else
2036 {
2037 browser_t **ptr = &info->browsers;
2038 while (*ptr)
2039 {
2040 if (SameDomainName(&(*ptr)->domain, d))
2041 {
2042 browser_t *remove = *ptr;
2043 *ptr = (*ptr)->next;
2044 if (remove->q.LongLived)
2045 {
2046 // give goodbyes for known answers.
2047 // note that since events are sent to client via udsserver_idle(), we don't need to worry about the question being cancelled mid-loop
2048 CacheRecord *ka = remove->q.uDNS_info.knownAnswers;
2049 while (ka) { remove->q.QuestionCallback(gmDNS, &remove->q, &ka->resrec, mDNSfalse); ka = ka->next; }
2050 }
2051 mDNS_StopBrowse(gmDNS, &remove->q);
2052 freeL("browser_t", remove);
2053 return;
2054 }
2055 ptr = &(*ptr)->next;
2056 }
2057 LogMsg("Requested removal of default domain %##s not in list for sd %d", d->c, r->sd);
2058 }
2059 }
2060 }
2061
2062 // Count how many other service records we have locally with the same name, but different rdata.
2063 // For auto-named services, we can have at most one per machine -- if we allowed two auto-named services of
2064 // the same type on the same machine, we'd get into an infinite autoimmune-response loop of continuous renaming.
2065 mDNSexport int CountPeerRegistrations(mDNS *const m, ServiceRecordSet *const srs)
2066 {
2067 int count = 0;
2068 ResourceRecord *r = &srs->RR_SRV.resrec;
2069 AuthRecord *rr;
2070 ServiceRecordSet *s;
2071
2072 for (rr = m->ResourceRecords; rr; rr=rr->next)
2073 if (rr->resrec.rrtype == kDNSType_SRV && SameDomainName(rr->resrec.name, r->name) && !SameRData(&rr->resrec, r))
2074 count++;
2075
2076 for (rr = m->uDNS_info.RecordRegistrations; rr; rr=rr->next)
2077 if (rr->uDNS_info.state != regState_Unregistered && rr->resrec.rrtype == kDNSType_SRV && SameDomainName(rr->resrec.name, r->name) && !SameRData(&rr->resrec, r))
2078 count++;
2079
2080 for (s = m->uDNS_info.ServiceRegistrations; s; s = s->next)
2081 if (s->uDNS_info.state != regState_Unregistered && SameDomainName(s->RR_SRV.resrec.name, r->name) && !SameRData(&s->RR_SRV.resrec, r))
2082 count++;
2083
2084 verbosedebugf("%d peer registrations for %##s", count, r->name->c);
2085 return(count);
2086 }
2087
2088 mDNSexport int CountExistingRegistrations(domainname *srv, mDNSIPPort port)
2089 {
2090 int count = 0;
2091 AuthRecord *rr;
2092 for (rr = gmDNS->ResourceRecords; rr; rr=rr->next)
2093 if (rr->resrec.rrtype == kDNSType_SRV &&
2094 rr->resrec.rdata->u.srv.port.NotAnInteger == port.NotAnInteger &&
2095 SameDomainName(rr->resrec.name, srv))
2096 count++;
2097 return(count);
2098 }
2099
2100 static mStatus register_service_instance(request_state *request, const domainname *domain)
2101 {
2102 service_info *info = request->service_registration;
2103 service_instance *ptr, *instance;
2104 int instance_size;
2105 mStatus result;
2106
2107 for (ptr = info->instances; ptr; ptr = ptr->next)
2108 {
2109 if (SameDomainName(&ptr->domain, domain))
2110 { LogMsg("register_service_instance: domain %##s already registered", domain->c); return mStatus_AlreadyRegistered; }
2111 }
2112
2113 instance_size = sizeof(*instance);
2114 if (info->txtlen > sizeof(RDataBody)) instance_size += (info->txtlen - sizeof(RDataBody));
2115 instance = mallocL("service_instance", instance_size);
2116 if (!instance) { my_perror("ERROR: malloc"); return mStatus_NoMemoryErr; }
2117
2118 instance->subtypes = AllocateSubTypes(info->num_subtypes, info->type_as_string);
2119 if (info->num_subtypes && !instance->subtypes)
2120 { free_service_instance(instance); instance = NULL; FatalError("ERROR: malloc"); }
2121 instance->request = request;
2122 instance->sd = request->sd;
2123 instance->autoname = info->autoname;
2124 instance->autorename = info->autorename;
2125 instance->allowremotequery = info->allowremotequery;
2126 instance->rename_on_memfree = 0;
2127 instance->name = info->name;
2128 AssignDomainName(&instance->domain, domain);
2129 instance->default_local = (info->default_domain && SameDomainName(domain, &localdomain));
2130 result = mDNS_RegisterService(gmDNS, &instance->srs, &instance->name, &info->type, domain, info->host.c[0] ? &info->host : NULL, info->port,
2131 info->txtdata, info->txtlen, instance->subtypes, info->num_subtypes, info->InterfaceID, regservice_callback, instance);
2132
2133 if (result) free_service_instance(instance);
2134 else
2135 {
2136 instance->next = info->instances;
2137 info->instances = instance;
2138 }
2139 return result;
2140 }
2141
2142 mDNSexport void udsserver_default_reg_domain_changed(const domainname *d, mDNSBool add)
2143 {
2144 request_state *rstate;
2145 service_info *info;
2146
2147 LogMsg("%s registration domain %##s", add ? "Adding" : "Removing", d->c);
2148 for (rstate = all_requests; rstate; rstate = rstate->next)
2149 {
2150 if (rstate->terminate != regservice_termination_callback) continue;
2151 info = rstate->service_registration;
2152 if (!info) { LogMsg("udsserver_default_reg_domain_changed - NULL service info"); continue; } // this should never happen
2153 if (!info->default_domain) continue;
2154
2155 // valid default registration
2156 if (add) register_service_instance(rstate, d);
2157 else
2158 {
2159 // find the instance to remove
2160 service_instance *si = rstate->service_registration->instances, *prev = NULL;
2161 while (si)
2162 {
2163 if (SameDomainName(&si->domain, d))
2164 {
2165 mStatus err;
2166 if (prev) prev->next = si->next;
2167 else info->instances = si->next;
2168 err = mDNS_DeregisterService(gmDNS, &si->srs);
2169 if (err)
2170 {
2171 LogMsg("udsserver_default_reg_domain_changed - mDNS_DeregisterService err %d", err);
2172 free_service_instance(si);
2173 }
2174 break;
2175 }
2176 prev = si;
2177 si = si->next;
2178 }
2179 if (!si) debugf("udsserver_default_reg_domain_changed - domain %##s not registered", d->c); // normal if registration failed
2180 }
2181 }
2182 }
2183
2184 // service registration
2185 static void handle_regservice_request(request_state *request)
2186 {
2187 DNSServiceFlags flags;
2188 uint32_t ifi;
2189 char name[1024]; // Lots of spare space for extra-long names that we'll auto-truncate down to 63 bytes
2190 char domain[MAX_ESCAPED_DOMAIN_NAME], host[MAX_ESCAPED_DOMAIN_NAME];
2191 char *ptr;
2192 domainname d, srv;
2193 mStatus result;
2194 service_info *service = NULL;
2195
2196 if (request->ts != t_complete)
2197 {
2198 LogMsg("ERROR: handle_regservice_request - transfer state != t_complete");
2199 abort_request(request);
2200 unlink_request(request);
2201 return;
2202 }
2203
2204 service = mallocL("service_info", sizeof(*service));
2205 if (!service) { my_perror("ERROR: malloc"); result = mStatus_NoMemoryErr; goto finish; }
2206
2207 service->instances = NULL;
2208 service->request = request;
2209 request->service_registration = service;
2210 request->termination_context = request->service_registration;
2211 request->terminate = regservice_termination_callback;
2212
2213 // extract data from message
2214 ptr = request->msgdata;
2215 flags = get_flags(&ptr);
2216 ifi = get_long(&ptr);
2217 service->InterfaceID = mDNSPlatformInterfaceIDfromInterfaceIndex(gmDNS, ifi);
2218 if (ifi && !service->InterfaceID)
2219 { LogMsg("ERROR: handle_regservice_request - Couldn't find InterfaceID for interfaceIndex %d", ifi); goto bad_param; }
2220 if (get_string(&ptr, name, sizeof(name)) < 0 ||
2221 get_string(&ptr, service->type_as_string, MAX_ESCAPED_DOMAIN_NAME) < 0 ||
2222 get_string(&ptr, domain, MAX_ESCAPED_DOMAIN_NAME) < 0 ||
2223 get_string(&ptr, host, MAX_ESCAPED_DOMAIN_NAME) < 0)
2224 { LogMsg("ERROR: handle_regservice_request - Couldn't read name/regtype/domain"); goto bad_param; }
2225
2226 service->port.b[0] = *ptr++;
2227 service->port.b[1] = *ptr++;
2228
2229 service->txtlen = get_short(&ptr);
2230 if (service->txtlen)
2231 {
2232 service->txtdata = mallocL("txtdata", service->txtlen);
2233 if (!service->txtdata) { my_perror("ERROR: malloc"); result = mStatus_NoMemoryErr; goto finish; }
2234 memcpy(service->txtdata, get_rdata(&ptr, service->txtlen), service->txtlen);
2235 }
2236 else service->txtdata = NULL;
2237
2238 // Check for sub-types after the service type
2239 service->num_subtypes = ChopSubTypes(service->type_as_string); // Note: Modifies regtype string to remove trailing subtypes
2240 if (service->num_subtypes < 0)
2241 { LogMsg("ERROR: handle_regservice_request - ChopSubTypes failed %s", service->type_as_string); goto bad_param; }
2242
2243 // Don't try to construct "domainname t" until *after* ChopSubTypes has worked its magic
2244 if (!*service->type_as_string || !MakeDomainNameFromDNSNameString(&service->type, service->type_as_string))
2245 { LogMsg("ERROR: handle_regservice_request - service->type_as_string bad %s", service->type_as_string); goto bad_param; }
2246
2247 if (!name[0])
2248 {
2249 service->name = (gmDNS)->nicelabel;
2250 service->autoname = mDNStrue;
2251 }
2252 else
2253 {
2254 // If the client is allowing AutoRename, then truncate name to legal length before converting it to a DomainLabel
2255 if ((flags & kDNSServiceFlagsNoAutoRename) == 0)
2256 {
2257 int newlen = TruncateUTF8ToLength((mDNSu8*)name, mDNSPlatformStrLen(name), MAX_DOMAIN_LABEL);
2258 name[newlen] = 0;
2259 }
2260 if (!MakeDomainLabelFromLiteralString(&service->name, name))
2261 { LogMsg("ERROR: handle_regservice_request - name bad %s", name); goto bad_param; }
2262 service->autoname = mDNSfalse;
2263 }
2264
2265 if (*domain)
2266 {
2267 service->default_domain = mDNSfalse;
2268 if (!MakeDomainNameFromDNSNameString(&d, domain))
2269 { LogMsg("ERROR: handle_regservice_request - domain bad %s", domain); goto bad_param; }
2270 }
2271 else
2272 {
2273 service->default_domain = mDNStrue;
2274 MakeDomainNameFromDNSNameString(&d, "local.");
2275 }
2276
2277 if (!ConstructServiceName(&srv, &service->name, &service->type, &d))
2278 { LogMsg("ERROR: handle_regservice_request - Couldn't ConstructServiceName from, “%#s” “%##s” “%##s”", service->name.c, service->type.c, d.c); goto bad_param; }
2279
2280 if (!MakeDomainNameFromDNSNameString(&service->host, host))
2281 { LogMsg("ERROR: handle_regservice_request - host bad %s", host); goto bad_param; }
2282 service->autorename = (flags & kDNSServiceFlagsNoAutoRename ) == 0;
2283 service->allowremotequery = (flags & kDNSServiceFlagsAllowRemoteQuery) != 0;
2284
2285 // Some clients use mDNS for lightweight copy protection, registering a pseudo-service with
2286 // a port number of zero. When two instances of the protected client are allowed to run on one
2287 // machine, we don't want to see misleading "Bogus client" messages in syslog and the console.
2288 if (service->port.NotAnInteger)
2289 {
2290 int count = CountExistingRegistrations(&srv, service->port);
2291 if (count)
2292 LogMsg("Client application registered %d identical instances of service %##s port %u.",
2293 count+1, srv.c, mDNSVal16(service->port));
2294 }
2295
2296 LogOperation("%3d: DNSServiceRegister(\"%s\", \"%s\", \"%s\", \"%s\", %u) START",
2297 request->sd, name, service->type_as_string, domain, host, mDNSVal16(service->port));
2298 result = register_service_instance(request, &d);
2299
2300 if (!result && !*domain)
2301 {
2302 DNameListElem *ptr, *def_domains = mDNSPlatformGetRegDomainList();
2303 for (ptr = def_domains; ptr; ptr = ptr->next)
2304 register_service_instance(request, &ptr->name);
2305 // note that we don't report errors for non-local, non-explicit domains
2306 mDNS_FreeDNameList(def_domains);
2307 }
2308
2309 finish:
2310 deliver_error(request, result);
2311 if (result != mStatus_NoError)
2312 {
2313 abort_request(request);
2314 unlink_request(request);
2315 }
2316 else
2317 reset_connected_rstate(request); // prepare to receive add/remove messages
2318
2319 return;
2320
2321 bad_param:
2322 //if (service) freeL("service_info", service); Don't think we should do this -- abort_request will free it a second time and crash
2323 deliver_error(request, mStatus_BadParamErr);
2324 abort_request(request);
2325 unlink_request(request);
2326 }
2327
2328 // service registration callback performs three duties - frees memory for deregistered services,
2329 // handles name conflicts, and delivers completed registration information to the client (via
2330 // process_service_registraion())
2331
2332 static void regservice_callback(mDNS *const m, ServiceRecordSet *const srs, mStatus result)
2333 {
2334 mStatus err;
2335 mDNSBool SuppressError = mDNSfalse;
2336 service_instance *instance = srs->ServiceContext;
2337 (void)m; // Unused
2338 if (!srs) { LogMsg("regservice_callback: srs is NULL %d", result); return; }
2339 if (!instance) { LogMsg("regservice_callback: srs->ServiceContext is NULL %d", result); return; }
2340
2341 if (instance->request && instance->request->service_registration)
2342 {
2343 service_info *info = instance->request->service_registration;
2344 if (info->default_domain && !instance->default_local) SuppressError = mDNStrue;
2345 // don't send errors up to client for wide-area, empty-string registrations
2346 }
2347
2348 if (result == mStatus_NoError)
2349 LogOperation("%3d: DNSServiceRegister(%##s, %u) REGISTERED ", instance->sd, srs->RR_SRV.resrec.name->c, mDNSVal16(srs->RR_SRV.resrec.rdata->u.srv.port));
2350 else if (result == mStatus_MemFree)
2351 LogOperation("%3d: DNSServiceRegister(%##s, %u) DEREGISTERED", instance->sd, srs->RR_SRV.resrec.name->c, mDNSVal16(srs->RR_SRV.resrec.rdata->u.srv.port));
2352 else if (result == mStatus_NameConflict)
2353 LogOperation("%3d: DNSServiceRegister(%##s, %u) NAME CONFLICT", instance->sd, srs->RR_SRV.resrec.name->c, mDNSVal16(srs->RR_SRV.resrec.rdata->u.srv.port));
2354 else
2355 LogOperation("%3d: DNSServiceRegister(%##s, %u) CALLBACK %d", instance->sd, srs->RR_SRV.resrec.name->c, mDNSVal16(srs->RR_SRV.resrec.rdata->u.srv.port), result);
2356
2357 if (result == mStatus_NoError)
2358 {
2359 if (instance->allowremotequery)
2360 {
2361 ExtraResourceRecord *e;
2362 srs->RR_ADV.AllowRemoteQuery = mDNStrue;
2363 srs->RR_PTR.AllowRemoteQuery = mDNStrue;
2364 srs->RR_SRV.AllowRemoteQuery = mDNStrue;
2365 srs->RR_TXT.AllowRemoteQuery = mDNStrue;
2366 for (e = instance->srs.Extras; e; e = e->next) e->r.AllowRemoteQuery = mDNStrue;
2367 }
2368 process_service_registration(srs, SuppressError);
2369 if (instance->autoname && CountPeerRegistrations(m, srs) == 0)
2370 RecordUpdatedNiceLabel(m, 0); // Successfully got new name, tell user immediately
2371 return;
2372 }
2373 else if (result == mStatus_MemFree)
2374 {
2375 if (instance->rename_on_memfree)
2376 {
2377 instance->rename_on_memfree = 0;
2378 instance->name = gmDNS->nicelabel;
2379 err = mDNS_RenameAndReregisterService(gmDNS, srs, &instance->name);
2380 if (err) LogMsg("ERROR: regservice_callback - RenameAndReregisterService returned %ld", err);
2381 // error should never happen - safest to log and continue
2382 }
2383 else
2384 {
2385 free_service_instance(instance);
2386 return;
2387 }
2388 }
2389 else if (result == mStatus_NameConflict)
2390 {
2391 if (instance->autoname && CountPeerRegistrations(m, srs) == 0)
2392 {
2393 // On conflict for an autoname service, rename and reregister *all* autoname services
2394 IncrementLabelSuffix(&m->nicelabel, mDNStrue);
2395 m->MainCallback(m, mStatus_ConfigChanged);
2396 }
2397 else if (instance->autoname || instance->autorename)
2398 {
2399 mDNS_RenameAndReregisterService(gmDNS, srs, mDNSNULL);
2400 return;
2401 }
2402 else
2403 {
2404 request_state *rs = instance->request;
2405 if (!rs) { LogMsg("ERROR: regservice_callback: received result %ld with a NULL request pointer", result); return; }
2406 free_service_instance(instance);
2407 if (!SuppressError && deliver_async_error(rs, reg_service_reply, result) < 0)
2408 {
2409 abort_request(rs);
2410 unlink_request(rs);
2411 }
2412 return;
2413 }
2414 }
2415 else
2416 {
2417 request_state *rs = instance->request;
2418 if (!rs) { LogMsg("ERROR: regservice_callback: received result %ld with a NULL request pointer", result); return; }
2419 if (result != mStatus_NATTraversal) LogMsg("ERROR: unknown result in regservice_callback: %ld", result);
2420 free_service_instance(instance);
2421 if (!SuppressError && deliver_async_error(rs, reg_service_reply, result) < 0)
2422 {
2423 abort_request(rs);
2424 unlink_request(rs);
2425 }
2426 return;
2427 }
2428 }
2429
2430 mDNSexport void FreeExtraRR(mDNS *const m, AuthRecord *const rr, mStatus result)
2431 {
2432 ExtraResourceRecord *extra = (ExtraResourceRecord *)rr->RecordContext;
2433 (void)m; //unused
2434
2435 if (result != mStatus_MemFree) { LogMsg("Error: FreeExtraRR invoked with unexpected error %d", result); return; }
2436
2437 debugf("%##s: MemFree", rr->resrec.name->c);
2438 if (rr->resrec.rdata != &rr->rdatastorage)
2439 freeL("Extra RData", rr->resrec.rdata);
2440 freeL("ExtraResourceRecord", extra);
2441 }
2442
2443 static mStatus add_record_to_service(request_state *rstate, service_instance *instance, uint16_t rrtype, uint16_t rdlen, char *rdata, uint32_t ttl)
2444 {
2445 ServiceRecordSet *srs = &instance->srs;
2446 ExtraResourceRecord *extra;
2447 mStatus result;
2448 int size;
2449
2450 if (rdlen > sizeof(RDataBody)) size = rdlen;
2451 else size = sizeof(RDataBody);
2452
2453 extra = mallocL("ExtraResourceRecord", sizeof(*extra) - sizeof(RDataBody) + size);
2454 if (!extra)
2455 {
2456 my_perror("ERROR: malloc");
2457 return mStatus_NoMemoryErr;
2458 }
2459
2460 bzero(extra, sizeof(ExtraResourceRecord)); // OK if oversized rdata not zero'd
2461 extra->r.resrec.rrtype = rrtype;
2462 extra->r.rdatastorage.MaxRDLength = (mDNSu16) size;
2463 extra->r.resrec.rdlength = rdlen;
2464 memcpy(&extra->r.rdatastorage.u.data, rdata, rdlen);
2465
2466 result = mDNS_AddRecordToService(gmDNS, srs , extra, &extra->r.rdatastorage, ttl);
2467 if (result) { freeL("ExtraResourceRecord", extra); return result; }
2468
2469 extra->ClientID = rstate->hdr.reg_index;
2470 return result;
2471 }
2472
2473 static mStatus handle_add_request(request_state *rstate)
2474 {
2475 uint32_t ttl;
2476 uint16_t rrtype, rdlen;
2477 char *ptr, *rdata;
2478 mStatus result = mStatus_UnknownErr;
2479 DNSServiceFlags flags;
2480 service_info *srvinfo = rstate->service_registration;
2481 service_instance *i;
2482
2483 if (!srvinfo) { LogMsg("handle_add_request called with NULL service_registration"); return(-1); }
2484
2485 ptr = rstate->msgdata;
2486 flags = get_flags(&ptr);
2487 rrtype = get_short(&ptr);
2488 rdlen = get_short(&ptr);
2489 rdata = get_rdata(&ptr, rdlen);
2490 ttl = get_long(&ptr);
2491
2492 if (!ttl) ttl = DefaultTTLforRRType(rrtype);
2493
2494 LogOperation("%3d: DNSServiceAddRecord(%##s, %s)", rstate->sd,
2495 (srvinfo->instances) ? srvinfo->instances->srs.RR_SRV.resrec.name->c : NULL, DNSTypeName(rrtype));
2496
2497 for (i = srvinfo->instances; i; i = i->next)
2498 {
2499 result = add_record_to_service(rstate, i, rrtype, rdlen, rdata, ttl);
2500 if (result && i->default_local) break;
2501 else result = mStatus_NoError; // suppress non-local default errors
2502 }
2503
2504 return(result);
2505 }
2506
2507 static mStatus update_record(AuthRecord *rr, uint16_t rdlen, char *rdata, uint32_t ttl)
2508 {
2509 int rdsize;
2510 RData *newrd;
2511 mStatus result;
2512
2513 if (rdlen > sizeof(RDataBody)) rdsize = rdlen;
2514 else rdsize = sizeof(RDataBody);
2515 newrd = mallocL("handle_update_request", sizeof(RData) - sizeof(RDataBody) + rdsize);
2516 if (!newrd) FatalError("ERROR: malloc");
2517 newrd->MaxRDLength = (mDNSu16) rdsize;
2518 memcpy(&newrd->u, rdata, rdlen);
2519
2520 // BIND named (name daemon) doesn't allow TXT records with zero-length rdata. This is strictly speaking correct,
2521 // since RFC 1035 specifies a TXT record as "One or more <character-string>s", not "Zero or more <character-string>s".
2522 // Since some legacy apps try to create zero-length TXT records, we'll silently correct it here.
2523 if (rr->resrec.rrtype == kDNSType_TXT && rdlen == 0) { rdlen = 1; newrd->u.txt.c[0] = 0; }
2524
2525 result = mDNS_Update(gmDNS, rr, ttl, rdlen, newrd, update_callback);
2526 if (result) { LogMsg("ERROR: mDNS_Update - %ld", result); freeL("handle_update_request", newrd); }
2527 return result;
2528 }
2529
2530 static mStatus handle_update_request(request_state *rstate)
2531 {
2532 uint16_t rdlen;
2533 char *ptr, *rdata;
2534 uint32_t ttl;
2535 mStatus result = mStatus_BadReferenceErr;
2536 service_info *srvinfo = rstate->service_registration;
2537 service_instance *i;
2538 AuthRecord *rr = NULL;
2539
2540 // get the message data
2541 ptr = rstate->msgdata;
2542 get_flags(&ptr); // flags unused
2543 rdlen = get_short(&ptr);
2544 rdata = get_rdata(&ptr, rdlen);
2545 ttl = get_long(&ptr);
2546
2547 if (rstate->reg_recs)
2548 {
2549 // update an individually registered record
2550 registered_record_entry *reptr;
2551 for (reptr = rstate->reg_recs; reptr; reptr = reptr->next)
2552 {
2553 if (reptr->key == rstate->hdr.reg_index)
2554 {
2555 result = update_record(reptr->rr, rdlen, rdata, ttl);
2556 goto end;
2557 }
2558 }
2559 result = mStatus_BadReferenceErr;
2560 goto end;
2561 }
2562
2563 // update a record from a service record set
2564 if (!srvinfo) { result = mStatus_BadReferenceErr; goto end; }
2565 for (i = srvinfo->instances; i; i = i->next)
2566 {
2567 if (rstate->hdr.reg_index == TXT_RECORD_INDEX) rr = &i->srs.RR_TXT;
2568 else
2569 {
2570 ExtraResourceRecord *e;
2571 for (e = i->srs.Extras; e; e = e->next)
2572 if (e->ClientID == rstate->hdr.reg_index) { rr = &e->r; break; }
2573 }
2574
2575 if (!rr) { result = mStatus_BadReferenceErr; goto end; }
2576 result = update_record(rr, rdlen, rdata, ttl);
2577 if (result && i->default_local) goto end;
2578 else result = mStatus_NoError; // suppress non-local default errors
2579 }
2580
2581 end:
2582 LogOperation("%3d: DNSServiceUpdateRecord(%##s, %s)", rstate->sd,
2583 (srvinfo->instances) ? srvinfo->instances->srs.RR_SRV.resrec.name->c : NULL,
2584 rr ? DNSTypeName(rr->resrec.rrtype) : "<NONE>");
2585
2586 return(result);
2587 }
2588
2589 static void update_callback(mDNS *const m, AuthRecord *const rr, RData *oldrd)
2590 {
2591 (void)m; // Unused
2592 if (oldrd != &rr->rdatastorage) freeL("update_callback", oldrd);
2593 }
2594
2595 static void process_service_registration(ServiceRecordSet *const srs, mDNSBool SuppressError)
2596 {
2597 reply_state *rep;
2598 transfer_state send_result;
2599 mStatus err;
2600 service_instance *instance = srs->ServiceContext;
2601 request_state *req = instance->request;
2602
2603 if (!req) { LogMsg("ERROR: process_service_registration - null request object"); return; }
2604 err = gen_rr_response(srs->RR_SRV.resrec.name, srs->RR_SRV.resrec.InterfaceID, req, &rep);
2605 if (err)
2606 {
2607 if (SuppressError && deliver_async_error(req, reg_service_reply, err) < 0)
2608 {
2609 abort_request(req);
2610 unlink_request(req);
2611 }
2612 return;
2613 }
2614 send_result = send_msg(rep);
2615 if (send_result == t_error || send_result == t_terminated)
2616 {
2617 abort_request(req);
2618 unlink_request(req);
2619 freeL("process_service_registration", rep);
2620 }
2621 else if (send_result == t_complete) freeL("process_service_registration", rep);
2622 else append_reply(req, rep);
2623 }
2624
2625 static void free_service_instance(service_instance *srv)
2626 {
2627 request_state *rstate = srv->request;
2628 ExtraResourceRecord *e = srv->srs.Extras, *tmp;
2629
2630 // clear pointers from parent struct
2631 if (rstate)
2632 {
2633 service_instance *ptr = rstate->service_registration->instances, *prev = NULL;
2634 while (ptr)
2635 {
2636 if (ptr == srv)
2637 {
2638 if (prev) prev->next = ptr->next;
2639 else rstate->service_registration->instances = ptr->next;
2640 break;
2641 }
2642 prev = ptr;
2643 ptr = ptr->next;
2644 }
2645 }
2646
2647 while(e)
2648 {
2649 e->r.RecordContext = e;
2650 tmp = e;
2651 e = e->next;
2652 FreeExtraRR(gmDNS, &tmp->r, mStatus_MemFree);
2653 }
2654
2655 if (srv->subtypes) { freeL("regservice_callback", srv->subtypes); srv->subtypes = NULL; }
2656 freeL("regservice_callback", srv);
2657 }
2658
2659 static void regservice_termination_callback(void *context)
2660 {
2661 service_info *info = context;
2662 service_instance *i, *p;
2663 if (!info) { LogMsg("regservice_termination_callback context is NULL"); return; }
2664 if (!info->request) { LogMsg("regservice_termination_callback info->request is NULL"); return; }
2665 i = info->instances;
2666 while (i)
2667 {
2668 p = i;
2669 i = i->next;
2670 p->request = NULL; // clear back pointer
2671 // only safe to free memory if registration is not valid, i.e. deregister fails (which invalidates p)
2672 LogOperation("%3d: DNSServiceRegister(%##s, %u) STOP", info->request->sd, p->srs.RR_SRV.resrec.name->c, mDNSVal16(p->srs.RR_SRV.resrec.rdata->u.srv.port));
2673 if (mDNS_DeregisterService(gmDNS, &p->srs)) free_service_instance(p);
2674 }
2675 info->request->service_registration = NULL; // clear pointer from request back to info
2676 if (info->txtdata) { freeL("txtdata", info->txtdata); info->txtdata = NULL; }
2677 freeL("service_info", info);
2678 }
2679
2680 static mStatus handle_regrecord_request(request_state *rstate)
2681 {
2682 AuthRecord *rr;
2683 registered_record_entry *re;
2684 mStatus result;
2685
2686 if (rstate->ts != t_complete)
2687 {
2688 LogMsg("ERROR: handle_regrecord_request - transfer state != t_complete");
2689 abort_request(rstate);
2690 unlink_request(rstate);
2691 return(-1);
2692 }
2693
2694 rr = read_rr_from_ipc_msg(rstate->msgdata, 1, 1);
2695 if (!rr) return(mStatus_BadParamErr);
2696
2697 // allocate registration entry, link into list
2698 re = mallocL("handle_regrecord_request", sizeof(registered_record_entry));
2699 if (!re) FatalError("ERROR: malloc");
2700 re->key = rstate->hdr.reg_index;
2701 re->rr = rr;
2702 re->rstate = rstate;
2703 re->client_context = rstate->hdr.client_context;
2704 rr->RecordContext = re;
2705 rr->RecordCallback = regrecord_callback;
2706 re->next = rstate->reg_recs;
2707 rstate->reg_recs = re;
2708
2709 if (!rstate->terminate)
2710 {
2711 rstate->terminate = connected_registration_termination;
2712 rstate->termination_context = rstate;
2713 }
2714
2715 if (rr->resrec.rroriginalttl == 0)
2716 rr->resrec.rroriginalttl = DefaultTTLforRRType(rr->resrec.rrtype);
2717
2718 LogOperation("%3d: DNSServiceRegisterRecord %s", rstate->sd, RRDisplayString(gmDNS, &rr->resrec));
2719 result = mDNS_Register(gmDNS, rr);
2720 return(result);
2721 }
2722
2723 static void regrecord_callback(mDNS *const m, AuthRecord * rr, mStatus result)
2724 {
2725 registered_record_entry *re = rr->RecordContext;
2726 request_state *rstate = re ? re->rstate : NULL;
2727 int len;
2728 reply_state *reply;
2729 transfer_state ts;
2730 (void)m; // Unused
2731
2732 if (!re)
2733 {
2734 // parent struct alreadt freed by termination callback
2735 if (!result) LogMsg("Error: regrecord_callback: successful registration of orphaned record");
2736 else
2737 {
2738 if (result != mStatus_MemFree) LogMsg("regrecord_callback: error %d received after parent termination", result);
2739 freeL("regrecord_callback", rr);
2740 }
2741 return;
2742 }
2743
2744 // format result, add to the list for the request, including the client context in the header
2745 len = sizeof(DNSServiceFlags);
2746 len += sizeof(uint32_t); //interfaceIndex
2747 len += sizeof(DNSServiceErrorType);
2748
2749 reply = create_reply(reg_record_reply, len, rstate);
2750 reply->mhdr->client_context = re->client_context;
2751 reply->rhdr->flags = dnssd_htonl(0);
2752 reply->rhdr->ifi = dnssd_htonl(mDNSPlatformInterfaceIndexfromInterfaceID(gmDNS, rr->resrec.InterfaceID));
2753 reply->rhdr->error = dnssd_htonl(result);
2754
2755 if (result)
2756 {
2757 // unlink from list, free memory
2758 registered_record_entry **ptr = &re->rstate->reg_recs;
2759 while (*ptr && (*ptr) != re) ptr = &(*ptr)->next;
2760 if (!*ptr) { LogMsg("regrecord_callback - record not in list!"); return; }
2761 *ptr = (*ptr)->next;
2762 freeL("regrecord_callback", re->rr);
2763 re->rr = rr = NULL;
2764 freeL("regrecord_callback", re);
2765 re = NULL;
2766 }
2767
2768 ts = send_msg(reply);
2769
2770 if (ts == t_error || ts == t_terminated) { abort_request(rstate); unlink_request(rstate); }
2771 else if (ts == t_complete) freeL("regrecord_callback", reply);
2772 else if (ts == t_morecoming) append_reply(rstate, reply); // client is blocked, link reply into list
2773 }
2774
2775 static void connected_registration_termination(void *context)
2776 {
2777 int shared;
2778 registered_record_entry *fptr, *ptr = ((request_state *)context)->reg_recs;
2779 while(ptr)
2780 {
2781 fptr = ptr;
2782 ptr = ptr->next;
2783 shared = fptr->rr->resrec.RecordType == kDNSRecordTypeShared;
2784 fptr->rr->RecordContext = NULL;
2785 mDNS_Deregister(gmDNS, fptr->rr);
2786 freeL("connected_registration_termination", fptr);
2787 }
2788 }
2789
2790 static mStatus handle_removerecord_request(request_state *rstate)
2791 {
2792 mStatus err = mStatus_BadReferenceErr;
2793 char *ptr;
2794 service_info *srvinfo = rstate->service_registration;
2795
2796 ptr = rstate->msgdata;
2797 get_flags(&ptr); // flags unused
2798
2799 if (rstate->reg_recs) err = remove_record(rstate); // remove individually registered record
2800 else if (!srvinfo) LogOperation("%3d: DNSServiceRemoveRecord (bad ref)", rstate->sd);
2801 else
2802 {
2803 service_instance *i;
2804 LogOperation("%3d: DNSServiceRemoveRecord(%##s)", rstate->sd,
2805 (srvinfo->instances) ? srvinfo->instances->srs.RR_SRV.resrec.name->c : NULL);
2806 for (i = srvinfo->instances; i; i = i->next)
2807 {
2808 err = remove_extra(rstate, i);
2809 if (err && i->default_local) break;
2810 else err = mStatus_NoError; // suppress non-local default errors
2811 }
2812 }
2813
2814 return(err);
2815 }
2816
2817 // remove a resource record registered via DNSServiceRegisterRecord()
2818 static mStatus remove_record(request_state *rstate)
2819 {
2820 int shared;
2821 mStatus err = mStatus_UnknownErr;
2822 registered_record_entry *e, **ptr = &rstate->reg_recs;
2823
2824 while(*ptr && (*ptr)->key != rstate->hdr.reg_index) ptr = &(*ptr)->next;
2825 if (!*ptr) { LogMsg("DNSServiceRemoveRecord - bad reference"); return mStatus_BadReferenceErr; }
2826 e = *ptr;
2827 *ptr = e->next; // unlink
2828
2829 LogOperation("%3d: DNSServiceRemoveRecord(%#s)", rstate->sd, e->rr->resrec.name->c);
2830 shared = e->rr->resrec.RecordType == kDNSRecordTypeShared;
2831 e->rr->RecordContext = NULL;
2832 err = mDNS_Deregister(gmDNS, e->rr);
2833 if (err)
2834 {
2835 LogMsg("ERROR: remove_record, mDNS_Deregister: %ld", err);
2836 freeL("remove_record", e->rr);
2837 freeL("remove_record", e);
2838 }
2839 return err;
2840 }
2841
2842 static mStatus remove_extra(request_state *rstate, service_instance *serv)
2843 {
2844 mStatus err = mStatus_BadReferenceErr;
2845 ExtraResourceRecord *ptr;
2846
2847 for (ptr = serv->srs.Extras; ptr; ptr = ptr->next)
2848 {
2849 if (ptr->ClientID == rstate->hdr.reg_index) // found match
2850 return mDNS_RemoveRecordFromService(gmDNS, &serv->srs, ptr, FreeExtraRR, ptr);
2851 }
2852 return err;
2853 }
2854
2855 // domain enumeration
2856 static void handle_enum_request(request_state *rstate)
2857 {
2858 DNSServiceFlags flags;
2859 uint32_t ifi;
2860 mDNSInterfaceID InterfaceID;
2861 char *ptr = rstate->msgdata;
2862 domain_enum_t *def, *all;
2863 enum_termination_t *term;
2864 mStatus err;
2865 int result;
2866
2867 if (rstate->ts != t_complete)
2868 {
2869 LogMsg("ERROR: handle_enum_request - transfer state != t_complete");
2870 abort_request(rstate);
2871 unlink_request(rstate);
2872 return;
2873 }
2874
2875 flags = get_flags(&ptr);
2876 ifi = get_long(&ptr);
2877 InterfaceID = mDNSPlatformInterfaceIDfromInterfaceIndex(gmDNS, ifi);
2878 if (ifi && !InterfaceID)
2879 {
2880 deliver_error(rstate, mStatus_BadParamErr);
2881 abort_request(rstate);
2882 unlink_request(rstate);
2883 }
2884
2885 // allocate context structures
2886 def = mallocL("handle_enum_request", sizeof(domain_enum_t));
2887 all = mallocL("handle_enum_request", sizeof(domain_enum_t));
2888 term = mallocL("handle_enum_request", sizeof(enum_termination_t));
2889 if (!def || !all || !term) FatalError("ERROR: malloc");
2890
2891 // enumeration requires multiple questions, so we must link all the context pointers so that
2892 // necessary context can be reached from the callbacks
2893 def->rstate = rstate;
2894 all->rstate = rstate;
2895 term->def = def;
2896 term->all = all;
2897 term->rstate = rstate;
2898 rstate->termination_context = term;
2899 rstate->terminate = enum_termination_callback;
2900 def->question.QuestionContext = def;
2901 def->type = (flags & kDNSServiceFlagsRegistrationDomains) ?
2902 mDNS_DomainTypeRegistrationDefault: mDNS_DomainTypeBrowseDefault;
2903 all->question.QuestionContext = all;
2904 all->type = (flags & kDNSServiceFlagsRegistrationDomains) ?
2905 mDNS_DomainTypeRegistration : mDNS_DomainTypeBrowse;
2906
2907 // if the caller hasn't specified an explicit interface, we use local-only to get the system-wide list.
2908 if (!InterfaceID) InterfaceID = mDNSInterface_LocalOnly;
2909
2910 // make the calls
2911 LogOperation("%3d: DNSServiceEnumerateDomains(%X=%s)", rstate->sd, flags,
2912 (flags & kDNSServiceFlagsBrowseDomains ) ? "kDNSServiceFlagsBrowseDomains" :
2913 (flags & kDNSServiceFlagsRegistrationDomains) ? "kDNSServiceFlagsRegistrationDomains" : "<<Unknown>>");
2914 err = mDNS_GetDomains(gmDNS, &all->question, all->type, NULL, InterfaceID, enum_result_callback, all);
2915 if (err == mStatus_NoError)
2916 err = mDNS_GetDomains(gmDNS, &def->question, def->type, NULL, InterfaceID, enum_result_callback, def);
2917 result = deliver_error(rstate, err); // send error *before* returning local domain
2918
2919 if (result < 0 || err)
2920 {
2921 abort_request(rstate);
2922 unlink_request(rstate);
2923 return;
2924 }
2925 }
2926
2927 static void enum_result_callback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord)
2928 {
2929 char domain[MAX_ESCAPED_DOMAIN_NAME];
2930 domain_enum_t *de = question->QuestionContext;
2931 DNSServiceFlags flags = 0;
2932 reply_state *reply;
2933 (void)m; // Unused
2934
2935 if (answer->rrtype != kDNSType_PTR) return;
2936 if (!AddRecord && de->type != mDNS_DomainTypeBrowse) return;
2937
2938 if (AddRecord)
2939 {
2940 flags |= kDNSServiceFlagsAdd;
2941 if (de->type == mDNS_DomainTypeRegistrationDefault || de->type == mDNS_DomainTypeBrowseDefault)
2942 flags |= kDNSServiceFlagsDefault;
2943 }
2944 ConvertDomainNameToCString(&answer->rdata->u.name, domain);
2945 // note that we do NOT propagate specific interface indexes to the client - for example, a domain we learn from
2946 // a machine's system preferences may be discovered on the LocalOnly interface, but should be browsed on the
2947 // network, so we just pass kDNSServiceInterfaceIndexAny
2948 reply = format_enumeration_reply(de->rstate, domain, flags, kDNSServiceInterfaceIndexAny, kDNSServiceErr_NoError);
2949 if (!reply)
2950 {
2951 LogMsg("ERROR: enum_result_callback, format_enumeration_reply");
2952 return;
2953 }
2954 reply->next = NULL;
2955 append_reply(de->rstate, reply);
2956 return;
2957 }
2958
2959 static reply_state *format_enumeration_reply(request_state *rstate, const char *domain, DNSServiceFlags flags, uint32_t ifi, DNSServiceErrorType err)
2960 {
2961 size_t len;
2962 reply_state *reply;
2963 char *data;
2964
2965
2966 len = sizeof(DNSServiceFlags);
2967 len += sizeof(uint32_t);
2968 len += sizeof(DNSServiceErrorType);
2969 len += strlen(domain) + 1;
2970
2971 reply = create_reply(enumeration_reply, len, rstate);
2972 reply->rhdr->flags = dnssd_htonl(flags);
2973 reply->rhdr->ifi = dnssd_htonl(ifi);
2974 reply->rhdr->error = dnssd_htonl(err);
2975 data = reply->sdata;
2976 put_string(domain, &data);
2977 return reply;
2978 }
2979
2980 static void enum_termination_callback(void *context)
2981 {
2982 enum_termination_t *t = context;
2983 mDNS *coredata = gmDNS;
2984
2985 mDNS_StopGetDomains(coredata, &t->all->question);
2986 mDNS_StopGetDomains(coredata, &t->def->question);
2987 freeL("enum_termination_callback", t->all);
2988 freeL("enum_termination_callback", t->def);
2989 t->rstate->termination_context = NULL;
2990 freeL("enum_termination_callback", t);
2991 }
2992
2993 static void handle_reconfirm_request(request_state *rstate)
2994 {
2995 AuthRecord *rr;
2996
2997 rr = read_rr_from_ipc_msg(rstate->msgdata, 0, 1);
2998 if (!rr) return;
2999 LogOperation("%3d: DNSServiceReconfirmRecord(%##s) %s", rstate->sd, RRDisplayString(gmDNS, &rr->resrec));
3000 mDNS_ReconfirmByValue(gmDNS, &rr->resrec);
3001 abort_request(rstate);
3002 unlink_request(rstate);
3003 freeL("handle_reconfirm_request", rr);
3004 }
3005
3006 // setup rstate to accept new reg/dereg requests
3007 static void reset_connected_rstate(request_state *rstate)
3008 {
3009 rstate->ts = t_morecoming;
3010 rstate->hdr_bytes = 0;
3011 rstate->data_bytes = 0;
3012 if (rstate->msgbuf) freeL("reset_connected_rstate", rstate->msgbuf);
3013 rstate->msgbuf = NULL;
3014 rstate->bufsize = 0;
3015 }
3016
3017 // returns a resource record (allocated w/ malloc) containing the data found in an IPC message
3018 // data must be in format flags, interfaceIndex, name, rrtype, rrclass, rdlen, rdata, (optional)ttl
3019 // (ttl only extracted/set if ttl argument is non-zero). returns NULL for a bad-parameter error
3020 static AuthRecord *read_rr_from_ipc_msg(char *msgbuf, int GetTTL, int validate_flags)
3021 {
3022 char *rdata, name[256];
3023 AuthRecord *rr;
3024 DNSServiceFlags flags;
3025 uint32_t interfaceIndex;
3026 uint16_t type, class, rdlen;
3027 int storage_size;
3028
3029 flags = get_flags(&msgbuf);
3030 if (validate_flags &&
3031 !((flags & kDNSServiceFlagsShared) == kDNSServiceFlagsShared) &&
3032 !((flags & kDNSServiceFlagsUnique) == kDNSServiceFlagsUnique))
3033 {
3034 LogMsg("ERROR: Bad resource record flags (must be kDNSServiceFlagsShared or kDNSServiceFlagsUnique)");
3035 return NULL;
3036 }
3037
3038 interfaceIndex = get_long(&msgbuf);
3039 if (get_string(&msgbuf, name, 256) < 0)
3040 {
3041 LogMsg("ERROR: read_rr_from_ipc_msg - get_string");
3042 return NULL;
3043 }
3044 type = get_short(&msgbuf);
3045 class = get_short(&msgbuf);
3046 rdlen = get_short(&msgbuf);
3047
3048 if (rdlen > sizeof(RDataBody)) storage_size = rdlen;
3049 else storage_size = sizeof(RDataBody);
3050
3051 rr = mallocL("read_rr_from_ipc_msg", sizeof(AuthRecord) - sizeof(RDataBody) + storage_size);
3052 if (!rr) FatalError("ERROR: malloc");
3053 bzero(rr, sizeof(AuthRecord)); // ok if oversized rdata not zero'd
3054
3055 mDNS_SetupResourceRecord(rr, mDNSNULL, mDNSPlatformInterfaceIDfromInterfaceIndex(gmDNS, interfaceIndex),
3056 type, 0, (flags & kDNSServiceFlagsShared) ? kDNSRecordTypeShared : kDNSRecordTypeUnique, mDNSNULL, mDNSNULL);
3057
3058 if (!MakeDomainNameFromDNSNameString(rr->resrec.name, name))
3059 {
3060 LogMsg("ERROR: bad name: %s", name);
3061 freeL("read_rr_from_ipc_msg", rr);
3062 return NULL;
3063 }
3064 if (flags & kDNSServiceFlagsAllowRemoteQuery) rr->AllowRemoteQuery = mDNStrue;
3065 rr->resrec.rrclass = class;
3066 rr->resrec.rdlength = rdlen;
3067 rr->resrec.rdata->MaxRDLength = rdlen;
3068 rdata = get_rdata(&msgbuf, rdlen);
3069 memcpy(rr->resrec.rdata->u.data, rdata, rdlen);
3070 if (GetTTL)
3071 {
3072 rr->resrec.rroriginalttl = get_long(&msgbuf);
3073 }
3074 return rr;
3075 }
3076
3077 // generate a response message for a browse result, service registration result, or any other call with the
3078 // identical callback signature. on successful completion rep is set to point to a malloc'd reply_state struct,
3079 // and mStatus_NoError is returned. otherwise the appropriate error is returned.
3080
3081 static mStatus gen_rr_response(domainname *servicename, mDNSInterfaceID id, request_state *request, reply_state **rep)
3082 {
3083 char *data;
3084 int len;
3085 domainlabel name;
3086 domainname type, dom;
3087 char namestr[MAX_DOMAIN_LABEL+1]; // Unescaped name: up to 63 bytes plus C-string terminating NULL.
3088 char typestr[MAX_ESCAPED_DOMAIN_NAME];
3089 char domstr [MAX_ESCAPED_DOMAIN_NAME];
3090
3091 *rep = NULL;
3092
3093 if (!DeconstructServiceName(servicename, &name, &type, &dom))
3094 return kDNSServiceErr_Unknown;
3095
3096 ConvertDomainLabelToCString_unescaped(&name, namestr);
3097 ConvertDomainNameToCString(&type, typestr);
3098 ConvertDomainNameToCString(&dom, domstr);
3099
3100 // calculate reply data length
3101 len = sizeof(DNSServiceFlags);
3102 len += sizeof(uint32_t); // if index
3103 len += sizeof(DNSServiceErrorType);
3104 len += (int) (strlen(namestr) + 1);
3105 len += (int) (strlen(typestr) + 1);
3106 len += (int) (strlen(domstr) + 1);
3107
3108 *rep = create_reply(query_reply, len, request);
3109
3110 (*rep)->rhdr->flags = dnssd_htonl(0);
3111 (*rep)->rhdr->ifi = dnssd_htonl(mDNSPlatformInterfaceIndexfromInterfaceID(gmDNS, id));
3112 (*rep)->rhdr->error = dnssd_htonl(kDNSServiceErr_NoError);
3113
3114 data = (*rep)->sdata;
3115
3116 put_string(namestr, &data);
3117 put_string(typestr, &data);
3118 put_string(domstr, &data);
3119 return mStatus_NoError;
3120 }
3121
3122 static int build_domainname_from_strings(domainname *srv, char *name, char *regtype, char *domain)
3123 {
3124 domainlabel n;
3125 domainname d, t;
3126
3127 if (!MakeDomainLabelFromLiteralString(&n, name)) return -1;
3128 if (!MakeDomainNameFromDNSNameString(&t, regtype)) return -1;
3129 if (!MakeDomainNameFromDNSNameString(&d, domain)) return -1;
3130 if (!ConstructServiceName(srv, &n, &t, &d)) return -1;
3131 return 0;
3132 }
3133
3134 // append a reply to the list in a request object
3135 static void append_reply(request_state *req, reply_state *rep)
3136 {
3137 reply_state *ptr;
3138
3139 if (!req->replies) req->replies = rep;
3140 else
3141 {
3142 ptr = req->replies;
3143 while (ptr->next) ptr = ptr->next;
3144 ptr->next = rep;
3145 }
3146 rep->next = NULL;
3147 }
3148
3149 // read_msg may be called any time when the transfer state (rs->ts) is t_morecoming.
3150 // returns the current state of the request (morecoming, error, complete, terminated.)
3151 // if there is no data on the socket, the socket will be closed and t_terminated will be returned
3152 static int read_msg(request_state *rs)
3153 {
3154 uint32_t nleft;
3155 int nread;
3156 char buf[4]; // dummy for death notification
3157
3158 if (rs->ts == t_terminated || rs->ts == t_error)
3159 {
3160 LogMsg("ERROR: read_msg called with transfer state terminated or error");
3161 rs->ts = t_error;
3162 return t_error;
3163 }
3164
3165 if (rs->ts == t_complete)
3166 { // this must be death or something is wrong
3167 nread = recv(rs->sd, buf, 4, 0);
3168 if (!nread) { rs->ts = t_terminated; return t_terminated; }
3169 if (nread < 0) goto rerror;
3170 LogMsg("ERROR: read data from a completed request.");
3171 rs->ts = t_error;
3172 return t_error;
3173 }
3174
3175 if (rs->ts != t_morecoming)
3176 {
3177 LogMsg("ERROR: read_msg called with invalid transfer state (%d)", rs->ts);
3178 rs->ts = t_error;
3179 return t_error;
3180 }
3181
3182 if (rs->hdr_bytes < sizeof(ipc_msg_hdr))
3183 {
3184 nleft = sizeof(ipc_msg_hdr) - rs->hdr_bytes;
3185 nread = recv(rs->sd, (char *)&rs->hdr + rs->hdr_bytes, nleft, 0);
3186 if (nread == 0) { rs->ts = t_terminated; return t_terminated; }
3187 if (nread < 0) goto rerror;
3188 rs->hdr_bytes += nread;
3189 if (rs->hdr_bytes == sizeof(ipc_msg_hdr))
3190 {
3191 ConvertHeaderBytes(&rs->hdr);
3192 if (rs->hdr.version != VERSION)
3193 {
3194 LogMsg("ERROR: read_msg - client version 0x%08X does not match daemon version 0x%08X", rs->hdr.version, VERSION);
3195 rs->ts = t_error;
3196 return t_error;
3197 }
3198 }
3199 if (rs->hdr_bytes > sizeof(ipc_msg_hdr))
3200 {
3201 LogMsg("ERROR: read_msg - read too many header bytes");
3202 rs->ts = t_error;
3203 return t_error;
3204 }
3205 }
3206
3207 // only read data if header is complete
3208 if (rs->hdr_bytes == sizeof(ipc_msg_hdr))
3209 {
3210 if (rs->hdr.datalen == 0) // ok in removerecord requests
3211 {
3212 rs->ts = t_complete;
3213 rs->msgbuf = NULL;
3214 return t_complete;
3215 }
3216
3217 if (!rs->msgbuf) // allocate the buffer first time through
3218 {
3219 rs->msgbuf = mallocL("read_msg", rs->hdr.datalen + MSG_PAD_BYTES);
3220 if (!rs->msgbuf)
3221 {
3222 my_perror("ERROR: malloc");
3223 rs->ts = t_error;
3224 return t_error;
3225 }
3226 rs->msgdata = rs->msgbuf;
3227 }
3228 bzero(rs->msgbuf, rs->hdr.datalen + MSG_PAD_BYTES);
3229 nleft = rs->hdr.datalen - rs->data_bytes;
3230 nread = recv(rs->sd, rs->msgbuf + rs->data_bytes, nleft, 0);
3231 if (nread == 0) { rs->ts = t_terminated; return t_terminated; }
3232 if (nread < 0) goto rerror;
3233 rs->data_bytes += nread;
3234 if (rs->data_bytes > rs->hdr.datalen)
3235 {
3236 LogMsg("ERROR: read_msg - read too many data bytes");
3237 rs->ts = t_error;
3238 return t_error;
3239 }
3240 }
3241
3242 if (rs->hdr_bytes == sizeof(ipc_msg_hdr) && rs->data_bytes == rs->hdr.datalen)
3243 rs->ts = t_complete;
3244 else rs->ts = t_morecoming;
3245
3246 return rs->ts;
3247
3248 rerror:
3249 if (dnssd_errno() == dnssd_EWOULDBLOCK || dnssd_errno() == dnssd_EINTR) return t_morecoming;
3250 my_perror("ERROR: read_msg");
3251 rs->ts = t_error;
3252 return t_error;
3253 }
3254
3255 static int send_msg(reply_state *rs)
3256 {
3257 ssize_t nwriten;
3258
3259 if (!rs->msgbuf)
3260 {
3261 LogMsg("ERROR: send_msg called with NULL message buffer");
3262 return t_error;
3263 }
3264
3265 if (rs->request->no_reply) //!!!KRS this behavior should be optimized if it becomes more common
3266 {
3267 rs->ts = t_complete;
3268 freeL("send_msg", rs->msgbuf);
3269 return t_complete;
3270 }
3271
3272 ConvertHeaderBytes(rs->mhdr);
3273 nwriten = send(rs->sd, rs->msgbuf + rs->nwriten, rs->len - rs->nwriten, 0);
3274 ConvertHeaderBytes(rs->mhdr);
3275 if (nwriten < 0)
3276 {
3277 if (dnssd_errno() == dnssd_EINTR || dnssd_errno() == dnssd_EWOULDBLOCK) nwriten = 0;
3278 else
3279 {
3280 #if !defined(PLATFORM_NO_EPIPE)
3281 if (dnssd_errno() == EPIPE)
3282 {
3283 debugf("%3d: broken pipe", rs->sd);
3284 rs->ts = t_terminated;
3285 rs->request->ts = t_terminated;
3286 return t_terminated;
3287 }
3288 else
3289 #endif
3290 {
3291 my_perror("ERROR: send\n");
3292 rs->ts = t_error;
3293 return t_error;
3294 }
3295 }
3296 }
3297 rs->nwriten += nwriten;
3298
3299 if (rs->nwriten == rs->len)
3300 {
3301 rs->ts = t_complete;
3302 freeL("send_msg", rs->msgbuf);
3303 }
3304 return rs->ts;
3305 }
3306
3307 static reply_state *create_reply(reply_op_t op, size_t datalen, request_state *request)
3308 {
3309 reply_state *reply;
3310 int totallen;
3311
3312
3313 if ((unsigned)datalen < sizeof(reply_hdr))
3314 {
3315 LogMsg("ERROR: create_reply - data length less than lenght of required fields");
3316 return NULL;
3317 }
3318
3319 totallen = (int) (datalen + sizeof(ipc_msg_hdr));
3320 reply = mallocL("create_reply", sizeof(reply_state));
3321 if (!reply) FatalError("ERROR: malloc");
3322 bzero(reply, sizeof(reply_state));
3323 reply->ts = t_morecoming;
3324 reply->sd = request->sd;
3325 reply->request = request;
3326 reply->len = totallen;
3327 reply->msgbuf = mallocL("create_reply", totallen);
3328 if (!reply->msgbuf) FatalError("ERROR: malloc");
3329 bzero(reply->msgbuf, totallen);
3330 reply->mhdr = (ipc_msg_hdr *)reply->msgbuf;
3331 reply->rhdr = (reply_hdr *)(reply->msgbuf + sizeof(ipc_msg_hdr));
3332 reply->sdata = reply->msgbuf + sizeof(ipc_msg_hdr) + sizeof(reply_hdr);
3333 reply->mhdr->version = VERSION;
3334 reply->mhdr->op = op;
3335 reply->mhdr->datalen = totallen - sizeof(ipc_msg_hdr);
3336 return reply;
3337 }
3338
3339 static int deliver_error(request_state *rstate, mStatus err)
3340 {
3341 int nwritten = -1;
3342 undelivered_error_t *undeliv;
3343
3344 err = dnssd_htonl(err);
3345 nwritten = send(rstate->sd, &err, sizeof(mStatus), 0);
3346 if (nwritten < (int)sizeof(mStatus))
3347 {
3348 if (dnssd_errno() == dnssd_EINTR || dnssd_errno() == dnssd_EWOULDBLOCK)
3349 nwritten = 0;
3350 if (nwritten < 0)
3351 {
3352 my_perror("ERROR: send - unable to deliver error to client");
3353 return(-1);
3354 }
3355 else
3356 {
3357 //client blocked - store result and come backr
3358 undeliv = mallocL("deliver_error", sizeof(undelivered_error_t));
3359 if (!undeliv) FatalError("ERROR: malloc");
3360 undeliv->err = err;
3361 undeliv->nwritten = nwritten;
3362 undeliv->sd = rstate->sd;
3363 rstate->u_err = undeliv;
3364 return 0;
3365 }
3366 }
3367 return 0;
3368 }
3369
3370 // returns 0 on success, -1 if send is incomplete, or on terminal failure (request is aborted)
3371 static transfer_state send_undelivered_error(request_state *rs)
3372 {
3373 int nwritten;
3374
3375 nwritten = send(rs->u_err->sd, (char *)(&rs->u_err->err) + rs->u_err->nwritten, sizeof(mStatus) - rs->u_err->nwritten, 0);
3376 if (nwritten < 0)
3377 {
3378 if (dnssd_errno() == dnssd_EINTR || dnssd_errno() == dnssd_EWOULDBLOCK)
3379 nwritten = 0;
3380 else
3381 {
3382 my_perror("ERROR: send - unable to deliver error to client\n");
3383 return t_error;
3384 }
3385 }
3386 if ((unsigned int)(nwritten + rs->u_err->nwritten) >= sizeof(mStatus))
3387 {
3388 freeL("send_undelivered_error", rs->u_err);
3389 rs->u_err = NULL;
3390 return t_complete;
3391 }
3392 rs->u_err->nwritten += nwritten;
3393 return t_morecoming;
3394 }
3395
3396 // send bogus data along with an error code to the app callback
3397 // returns 0 on success (linking reply into list of not fully delivered),
3398 // -1 on failure (request should be aborted)
3399 static int deliver_async_error(request_state *rs, reply_op_t op, mStatus err)
3400 {
3401 int len;
3402 reply_state *reply;
3403 transfer_state ts;
3404
3405 if (rs->no_reply) return 0;
3406 len = 256; // long enough for any reply handler to read all args w/o buffer overrun
3407 reply = create_reply(op, len, rs);
3408 reply->rhdr->error = dnssd_htonl(err);
3409 ts = send_msg(reply);
3410 if (ts == t_error || ts == t_terminated)
3411 {
3412 freeL("deliver_async_error", reply);
3413 return -1;
3414 }
3415 else if (ts == t_complete) freeL("deliver_async_error", reply);
3416 else if (ts == t_morecoming) append_reply(rs, reply); // client is blocked, link reply into list
3417 return 0;
3418 }
3419
3420 static void abort_request(request_state *rs)
3421 {
3422 reply_state *rep, *ptr;
3423
3424 if (rs->terminate) rs->terminate(rs->termination_context); // terminate field may not be set yet
3425 if (rs->msgbuf) freeL("abort_request", rs->msgbuf);
3426 LogOperation("%3d: Removing FD", rs->sd);
3427 udsSupportRemoveFDFromEventLoop(rs->sd); // Note: This also closes file descriptor rs->sd for us
3428 rs->sd = dnssd_InvalidSocket;
3429
3430 // free pending replies
3431 rep = rs->replies;
3432 while(rep)
3433 {
3434 if (rep->msgbuf) freeL("abort_request", rep->msgbuf);
3435 ptr = rep;
3436 rep = rep->next;
3437 freeL("abort_request", ptr);
3438 }
3439
3440 if (rs->u_err)
3441 {
3442 freeL("abort_request", rs->u_err);
3443 rs->u_err = NULL;
3444 }
3445 }
3446
3447 static void unlink_request(request_state *rs)
3448 {
3449 request_state *ptr;
3450
3451 if (rs == all_requests)
3452 {
3453 all_requests = all_requests->next;
3454 freeL("unlink_request", rs);
3455 return;
3456 }
3457 for(ptr = all_requests; ptr->next; ptr = ptr->next)
3458 if (ptr->next == rs)
3459 {
3460 ptr->next = rs->next;
3461 freeL("unlink_request", rs);
3462 return;
3463 }
3464 }
3465
3466 //hack to search-replace perror's to LogMsg's
3467 static void my_perror(char *errmsg)
3468 {
3469 LogMsg("%s: %s", errmsg, dnssd_strerror(dnssd_errno()));
3470 }
3471
3472 // check that the message delivered by the client is sufficiently long to extract the required data from the buffer
3473 // without overrunning it.
3474 // returns 0 on success, -1 on error.
3475
3476 static int validate_message(request_state *rstate)
3477 {
3478 uint32_t min_size;
3479
3480 switch(rstate->hdr.op)
3481 {
3482 case resolve_request: min_size = sizeof(DNSServiceFlags) + // flags
3483 sizeof(uint32_t) + // interface
3484 (3 * sizeof(char)); // name, regtype, domain
3485 break;
3486 case query_request: min_size = sizeof(DNSServiceFlags) + // flags
3487 sizeof(uint32_t) + // interface
3488 sizeof(char) + // fullname
3489 (2 * sizeof(uint16_t)); // type, class
3490 break;
3491 case browse_request: min_size = sizeof(DNSServiceFlags) + // flags
3492 sizeof(uint32_t) + // interface
3493 (2 * sizeof(char)); // regtype, domain
3494 break;
3495 case reg_service_request: min_size = sizeof(DNSServiceFlags) + // flags
3496 sizeof(uint32_t) + // interface
3497 (4 * sizeof(char)) + // name, type, domain, host
3498 (2 * sizeof(uint16_t)); // port, textlen
3499 break;
3500 case enumeration_request: min_size = sizeof(DNSServiceFlags) + // flags
3501 sizeof(uint32_t); // interface
3502 break;
3503 case reg_record_request: min_size = sizeof(DNSServiceFlags) + // flags
3504 sizeof(uint32_t) + // interface
3505 sizeof(char) + // fullname
3506 (3 * sizeof(uint16_t)) + // type, class, rdlen
3507 sizeof(uint32_t); // ttl
3508 break;
3509 case add_record_request: min_size = sizeof(DNSServiceFlags) + // flags
3510 (2 * sizeof(uint16_t)) + // type, rdlen
3511 sizeof(uint32_t); // ttl
3512 break;
3513 case update_record_request: min_size = sizeof(DNSServiceFlags) + // flags
3514 sizeof(uint16_t) + // rdlen
3515 sizeof(uint32_t); // ttl
3516 break;
3517 case remove_record_request: min_size = sizeof(DNSServiceFlags); // flags
3518 break;
3519 case reconfirm_record_request: min_size=sizeof(DNSServiceFlags) + // flags
3520 sizeof(uint32_t) + // interface
3521 sizeof(char) + // fullname
3522 (3 * sizeof(uint16_t)); // type, class, rdlen
3523 break;
3524 case setdomain_request: min_size = sizeof(DNSServiceFlags) + sizeof(char); // flags + domain
3525 break;
3526 default:
3527 LogMsg("ERROR: validate_message - unsupported request type: %d", rstate->hdr.op);
3528 return -1;
3529 }
3530
3531 return (rstate->data_bytes >= min_size ? 0 : -1);
3532
3533 }
3534
3535 static uint32_t dnssd_htonl(uint32_t l)
3536 {
3537 uint32_t ret;
3538 char * data;
3539
3540 data = (char*) &ret;
3541
3542 put_long(l, &data);
3543
3544 return ret;
3545 }
3546
3547 #if defined(_WIN32)
3548
3549 static char * win32_strerror(int inErrorCode)
3550 {
3551 static char buffer[1024];
3552 DWORD n;
3553
3554 memset(buffer, 0, sizeof(buffer));
3555
3556 n = FormatMessageA(
3557 FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
3558 NULL,
3559 (DWORD) inErrorCode,
3560 MAKELANGID( LANG_NEUTRAL, SUBLANG_DEFAULT ),
3561 buffer,
3562 sizeof( buffer ),
3563 NULL );
3564
3565 if( n > 0 )
3566 {
3567 // Remove any trailing CR's or LF's since some messages have them.
3568
3569 while( ( n > 0 ) && isspace( ( (unsigned char *) buffer)[ n - 1 ] ) )
3570 {
3571 buffer[ --n ] = '\0';
3572 }
3573 }
3574
3575 return buffer;
3576 }
3577
3578 #endif