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