2 * Copyright (c) 2003 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
23 * @APPLE_LICENSE_HEADER_END@
25 Change History (most recent first):
27 $Log: uds_daemon.c,v $
28 Revision 1.55.2.1 2004/06/13 22:32:24 ksekar
31 Revision 1.55 2004/06/05 00:04:27 cheshire
32 <rdar://problem/3668639>: wide-area domains should be returned in reg. domain enumeration
34 Revision 1.54 2004/06/01 22:22:52 ksekar
35 <rdar://problem/3668635>: wide-area default registrations should be in
38 Revision 1.53 2004/05/28 23:42:37 ksekar
39 <rdar://problem/3258021>: Feature: DNS server->client notification on record changes (#7805)
41 Revision 1.52 2004/05/26 00:39:49 ksekar
42 <rdar://problem/3667105>: wide-area rendezvous servers don't appear in
44 Use local-only InterfaceID for GetDomains calls for sockets-API
46 Revision 1.51 2004/05/18 23:51:27 cheshire
47 Tidy up all checkin comments to use consistent "<rdar://problem/xxxxxxx>" format for bug numbers
49 Revision 1.50 2004/05/14 16:39:47 ksekar
50 Browse for iChat locally for now.
52 Revision 1.49 2004/05/13 21:33:52 ksekar
53 Clean up non-local registration control via config file. Force iChat
54 registrations to be local for now.
56 Revision 1.48 2004/05/13 04:13:19 ksekar
57 Updated SIGINFO handler for multi-domain browses
59 Revision 1.47 2004/05/12 22:04:01 ksekar
60 Implemented multi-domain browsing by default for uds_daemon.
62 Revision 1.46 2004/05/06 18:42:58 ksekar
63 General dns_sd.h API cleanup, including the following radars:
64 <rdar://problem/3592068>: Remove flags with zero value
65 <rdar://problem/3479569>: Passing in NULL causes a crash.
67 Revision 1.45 2004/03/12 08:49:28 cheshire
68 #include <sys/socket.h>
70 Revision 1.44 2004/02/25 01:25:27 ksekar
71 <rdar://problem/3569212>: DNSServiceRegisterRecord flags not error-checked
73 Revision 1.43 2004/02/24 01:46:40 cheshire
74 Manually reinstate lost checkin 1.36
76 Revision 1.42 2004/02/05 19:39:29 cheshire
77 Move creation of /var/run/mDNSResponder.pid to uds_daemon.c,
78 so that all platforms get this functionality
80 Revision 1.41 2004/02/03 18:59:02 cheshire
81 Change "char *domain" parameter for format_enumeration_reply to "const char *domain"
83 Revision 1.40 2004/01/28 03:41:00 cheshire
84 <rdar://problem/3541946>: Need ability to do targeted queries as well as multicast queries
86 Revision 1.39 2004/01/25 00:03:21 cheshire
87 Change to use mDNSVal16() instead of private PORT_AS_NUM() macro
89 Revision 1.38 2004/01/19 19:51:46 cheshire
90 Fix compiler error (mixed declarations and code) on some versions of Linux
92 Revision 1.37 2003/12/08 21:11:42 rpantos
93 Changes necessary to support mDNSResponder on Linux.
95 Revision 1.36 2003/12/04 23:40:57 cheshire
96 <rdar://problem/3484766>: Security: Crashing bug in mDNSResponder
97 Fix some more code that should use buffer size MAX_ESCAPED_DOMAIN_NAME (1005) instead of 256-byte buffers.
99 Revision 1.35 2003/12/03 19:10:22 ksekar
100 <rdar://problem/3498644>: malloc'd data not zero'd
102 Revision 1.34 2003/12/03 02:00:01 ksekar
103 <rdar://problem/3498644>: malloc'd data not zero'd
105 Revision 1.33 2003/11/22 01:18:46 ksekar
106 <rdar://problem/3486646>: config change handler not called for dns-sd services
108 Revision 1.32 2003/11/20 21:46:12 ksekar
109 <rdar://problem/3486635>: leak: DNSServiceRegisterRecord
111 Revision 1.31 2003/11/20 20:33:05 ksekar
112 <rdar://problem/3486635>: leak: DNSServiceRegisterRecord
114 Revision 1.30 2003/11/20 02:10:55 ksekar
115 <rdar://problem/3486643>: cleanup DNSServiceAdd/RemoveRecord
117 Revision 1.29 2003/11/14 21:18:32 cheshire
118 <rdar://problem/3484766>: Security: Crashing bug in mDNSResponder
119 Fix code that should use buffer size MAX_ESCAPED_DOMAIN_NAME (1005) instead of 256-byte buffers.
121 Revision 1.28 2003/11/08 22:18:29 cheshire
122 <rdar://problem/3477870>: Don't need to show process ID in *every* mDNSResponder syslog message
124 Revision 1.27 2003/11/05 22:44:57 ksekar
125 <rdar://problem/3335230>: No bounds checking when reading data from client
126 Reviewed by: Stuart Cheshire
128 Revision 1.26 2003/10/23 17:51:04 ksekar
129 <rdar://problem/3335216>: handle blocked clients more efficiently
130 Changed gettimeofday() to mDNSPlatformTimeNow()
132 Revision 1.25 2003/10/22 23:37:49 ksekar
133 <rdar://problem/3459141>: crash/hang in abort_client
135 Revision 1.24 2003/10/21 20:59:40 ksekar
136 <rdar://problem/3335216>: handle blocked clients moreefficiently
138 Revision 1.23 2003/09/23 02:12:43 cheshire
139 Also include port number in list of services registered via new UDS API
141 Revision 1.22 2003/08/19 16:03:55 ksekar
142 <rdar://problem/3380097>: ER: SIGINFO dump should include resolves started by DNSServiceQueryRecord
143 Check termination_context for NULL before dereferencing.
145 Revision 1.21 2003/08/19 05:39:43 cheshire
146 <rdar://problem/3380097> SIGINFO dump should include resolves started by DNSServiceQueryRecord
148 Revision 1.20 2003/08/16 03:39:01 cheshire
149 <rdar://problem/3338440> InterfaceID -1 indicates "local only"
151 Revision 1.19 2003/08/15 20:16:03 cheshire
152 <rdar://problem/3366590> mDNSResponder takes too much RPRVT
153 We want to avoid touching the rdata pages, so we don't page them in.
154 1. RDLength was stored with the rdata, which meant touching the page just to find the length.
155 Moved this from the RData to the ResourceRecord object.
156 2. To avoid unnecessarily touching the rdata just to compare it,
157 compute a hash of the rdata and store the hash in the ResourceRecord object.
159 Revision 1.18 2003/08/15 00:38:00 ksekar
160 <rdar://problem/3377005>: Bug: buffer overrun when reading long rdata from client
162 Revision 1.17 2003/08/14 02:18:21 cheshire
163 <rdar://problem/3375491> Split generic ResourceRecord type into two separate types: AuthRecord and CacheRecord
165 Revision 1.16 2003/08/13 23:58:52 ksekar
166 <rdar://problem/3374911>: Bug: UDS Sub-type browsing works, but not sub-type registration
167 Fixed pointer increment error, moved subtype reading for-loop for easier error bailout.
169 Revision 1.15 2003/08/13 17:30:33 ksekar
170 <rdar://problem/3374671>: DNSServiceAddRecord doesn't work
171 Fixed various problems with handling the AddRecord request and freeing the ExtraResourceRecords.
173 Revision 1.14 2003/08/12 19:56:25 cheshire
180 #include <sys/ioctl.h>
181 #include <sys/types.h>
182 #include <sys/time.h>
183 #include <sys/resource.h>
184 #include <sys/socket.h>
186 #include "mDNSClientAPI.h"
187 #include "uds_daemon.h"
189 #include "dnssd_ipc.h"
191 // convenience definition
192 #define _UNUSED __attribute__ ((unused))
193 // Types and Data Structures
194 // ----------------------------------------------------------------------
205 typedef void (*req_termination_fn
)(void *);
208 typedef struct registered_record_entry
212 struct registered_record_entry
*next
;
213 } registered_record_entry
;
215 typedef struct extra_record_entry
218 struct extra_record_entry
*next
;
219 ExtraResourceRecord e
;
220 } extra_record_entry
;
222 typedef struct registered_service
225 int renameonconflict
;
226 int rename_on_memfree
; // set flag on config change when we deregister original name
228 ServiceRecordSet
*srs
;
229 struct request_state
*request
;
230 AuthRecord
*subtypes
;
231 extra_record_entry
*extras
;
232 } registered_service
;
236 registered_service
*local
;
237 registered_service
*global
;
245 } undelivered_error_t
;
247 typedef struct request_state
249 // connection structures
253 // state of read (in case message is read over several recv() calls)
255 uint32_t hdr_bytes
; // bytes of header already read
257 uint32_t data_bytes
; // bytes of message data already read
258 char *msgbuf
; // pointer to data storage to pass to free()
259 char *msgdata
; // pointer to data to be read from (may be modified)
260 int bufsize
; // size of data storage
262 // reply, termination, error, and client context info
263 int no_reply
; // don't send asynchronous replies to client
264 int time_blocked
; // record time of a blocked client
265 void *client_context
; // don't touch this - pointer only valid in client's addr space
266 struct reply_state
*replies
; // corresponding (active) reply list
267 undelivered_error_t
*u_err
;
268 void *termination_context
;
269 req_termination_fn terminate
;
271 //!!!KRS toss these pointers in a union
272 // registration context associated with this request (null if not applicable)
273 registered_record_entry
*reg_recs
; // muliple registrations for a connection-oriented request
274 servicepair_t servicepair
;
275 struct resolve_result_t
*resolve_results
;
277 struct request_state
*next
;
280 // struct physically sits between ipc message header and call-specific fields in the message buffer
283 DNSServiceFlags flags
;
285 DNSServiceErrorType error
;
289 typedef struct reply_state
291 // state of the transmission
296 // context of the reply
297 struct request_state
*request
; // the request that this answers
298 struct reply_state
*next
; // if there are multiple unsent replies
299 // pointer into message buffer - allows fields to be changed after message is formatted
302 char *sdata
; // pointer to start of call-specific data
303 // pointer to malloc'd buffer
308 // domain enumeration and resolv calls require 2 mDNSCore calls, so we need separate interconnected
309 // structures to handle callbacks
312 DNSQuestion question
;
313 mDNS_DomainType type
;
314 request_state
*rstate
;
321 request_state
*rstate
;
322 } enum_termination_t
;
326 DNSQuestion question
;
328 request_state
*rstate
;
335 request_state
*rstate
;
336 } resolve_termination_t
;
338 typedef struct resolve_result_t
340 const ResourceRecord
*txt
;
341 const ResourceRecord
*srv
;
346 request_state
*rstate
;
347 client_context_t client_context
;
348 } regrecord_callback_context
;
350 // for multi-domain browsing
351 typedef struct qlist_t
354 struct qlist_t
*next
;
360 request_state
*rstate
;
361 } browse_termination_context
;
365 static mDNS
*gmDNS
= NULL
;
366 static int listenfd
= -1;
367 static request_state
*all_requests
= NULL
;
368 //!!!KRS we should keep a separate list containing only the requests that need to be examined
369 //in the idle() routine.
372 #define MAX_OPENFILES 1024
373 #define MAX_TIME_BLOCKED 60 * mDNSPlatformOneSecond // try to send data to a blocked client for 60 seconds before
374 // terminating connection
375 #define MSG_PAD_BYTES 5 // pad message buffer (read from client) with n zero'd bytes to guarantee
376 // n get_string() calls w/o buffer overrun
377 // private function prototypes
378 static void connect_callback(void *info
);
379 static int read_msg(request_state
*rs
);
380 static int send_msg(reply_state
*rs
);
381 static void abort_request(request_state
*rs
);
382 static void request_callback(void *info
);
383 static void handle_resolve_request(request_state
*rstate
);
384 static void question_result_callback(mDNS
*const m
, DNSQuestion
*question
, const ResourceRecord
*const answer
, mDNSBool AddRecord
);
385 static void question_termination_callback(void *context
);
386 static void handle_browse_request(request_state
*request
);
387 static void browse_termination_callback(void *context
);
388 static void browse_result_callback(mDNS
*const m
, DNSQuestion
*question
, const ResourceRecord
*const answer
, mDNSBool AddRecord
);
389 static void handle_regservice_request(request_state
*request
);
390 static void regservice_termination_callback(void *context
);
391 static void process_service_registration(ServiceRecordSet
*const srs
);
392 static void regservice_callback(mDNS
*const m
, ServiceRecordSet
*const srs
, mStatus result
);
393 static void handle_add_request(request_state
*rstate
);
394 static void handle_update_request(request_state
*rstate
);
395 static mStatus
gen_rr_response(domainname
*servicename
, mDNSInterfaceID id
, request_state
*request
, reply_state
**rep
);
396 static void append_reply(request_state
*req
, reply_state
*rep
);
397 static int build_domainname_from_strings(domainname
*srv
, char *name
, char *regtype
, char *domain
);
398 static void enum_termination_callback(void *context
);
399 static void enum_result_callback(mDNS
*const m
, DNSQuestion
*question
, const ResourceRecord
*const answer
, mDNSBool AddRecord
);
400 static void handle_query_request(request_state
*rstate
);
401 static reply_state
*format_enumeration_reply(request_state
*rstate
, const char *domain
, DNSServiceFlags flags
, uint32_t ifi
, DNSServiceErrorType err
);
402 static void handle_enum_request(request_state
*rstate
);
403 static void handle_regrecord_request(request_state
*rstate
);
404 static void regrecord_callback(mDNS
*const m
, AuthRecord
*const rr
, mStatus result
);
405 static void connected_registration_termination(void *context
);
406 static void handle_reconfirm_request(request_state
*rstate
);
407 static AuthRecord
*read_rr_from_ipc_msg(char *msgbuf
, int ttl
, int validate_flags
);
408 static void handle_removerecord_request(request_state
*rstate
);
409 static void reset_connected_rstate(request_state
*rstate
);
410 static int deliver_error(request_state
*rstate
, mStatus err
);
411 static int deliver_async_error(request_state
*rs
, reply_op_t op
, mStatus err
);
412 static transfer_state
send_undelivered_error(request_state
*rs
);
413 static reply_state
*create_reply(reply_op_t op
, int datalen
, request_state
*request
);
414 static void update_callback(mDNS
*const m
, AuthRecord
*const rr
, RData
*oldrd
);
415 static void my_perror(char *errmsg
);
416 static void unlink_request(request_state
*rs
);
417 static void resolve_result_callback(mDNS
*const m
, DNSQuestion
*question
, const ResourceRecord
*const answer
, mDNSBool AddRecord
);
418 static void resolve_termination_callback(void *context
);
419 static int validate_message(request_state
*rstate
);
420 static mStatus
remove_extra_rr_from_service(request_state
*rstate
);
421 static mStatus
remove_record(request_state
*rstate
);
422 static void free_service_registration(registered_service
*srv
);
424 // initialization, setup/teardown functions
426 // If a platform specifies its own PID file name, we use that
428 #define PID_FILE "/var/run/mDNSResponder.pid"
431 int udsserver_init( mDNS
*globalInstance
)
434 struct sockaddr_un laddr
;
435 struct rlimit maxfds
;
437 if ( !globalInstance
)
439 gmDNS
= globalInstance
;
441 // If a particular platform wants to opt out of having a PID file, define PID_FILE to be ""
444 FILE *fp
= fopen(PID_FILE
, "w");
447 fprintf(fp
, "%d\n", getpid());
452 if ((listenfd
= socket(AF_LOCAL
, SOCK_STREAM
, 0)) < 0)
454 unlink(MDNS_UDS_SERVERPATH
); //OK if this fails
455 bzero(&laddr
, sizeof(laddr
));
456 laddr
.sun_family
= AF_LOCAL
;
457 #ifndef NOT_HAVE_SA_LEN // According to Stevens (section 3.2), there is no portable way to
458 // determine whether sa_len is defined on a particular platform.
459 laddr
.sun_len
= sizeof(struct sockaddr_un
);
461 strcpy(laddr
.sun_path
, MDNS_UDS_SERVERPATH
);
463 if (bind(listenfd
, (struct sockaddr
*)&laddr
, sizeof(laddr
)) < 0)
467 if (fcntl(listenfd
, F_SETFL
, O_NONBLOCK
) < 0)
469 my_perror("ERROR: could not set listen socket to non-blocking mode");
472 listen(listenfd
, LISTENQ
);
474 if (mStatus_NoError
!= udsSupportAddFDToEventLoop(listenfd
, connect_callback
, (void *) NULL
))
476 my_perror("ERROR: could not add listen socket to event loop");
480 // set maximum file descriptor to 1024
481 if (getrlimit(RLIMIT_NOFILE
, &maxfds
) < 0)
483 my_perror("ERROR: Unable to get file descriptor limit");
486 if (maxfds
.rlim_max
>= MAX_OPENFILES
&& maxfds
.rlim_cur
== maxfds
.rlim_max
)
488 // proper values already set
491 maxfds
.rlim_max
= MAX_OPENFILES
;
492 maxfds
.rlim_cur
= MAX_OPENFILES
;
493 if (setrlimit(RLIMIT_NOFILE
, &maxfds
) < 0)
494 my_perror("ERROR: Unable to set maximum file descriptor limit");
498 my_perror("ERROR: udsserver_init");
502 int udsserver_exit(void)
505 unlink(MDNS_UDS_SERVERPATH
);
510 mDNSs32
udsserver_idle(mDNSs32 nextevent
)
512 request_state
*req
= all_requests
, *tmp
, *prev
= NULL
;
514 transfer_state result
;
515 mDNSs32 now
= mDNSPlatformTimeNow();
519 result
= t_uninitialized
;
521 result
= send_undelivered_error(req
);
522 if (result
!= t_error
&& result
!= t_morecoming
&& // don't try to send msg if send_error failed
523 (req
->ts
== t_complete
|| req
->ts
== t_morecoming
))
527 if (req
->replies
->next
) req
->replies
->rhdr
->flags
|= kDNSServiceFlagsMoreComing
;
528 result
= send_msg(req
->replies
);
529 if (result
== t_complete
)
532 req
->replies
= req
->replies
->next
;
533 freeL("udsserver_idle", fptr
);
534 req
->time_blocked
= 0; // reset failure counter after successful send
536 else if (result
== t_terminated
|| result
== t_error
)
541 else if (result
== t_morecoming
) break; // client's queues are full, move to next
544 if (result
== t_morecoming
)
546 if (!req
->time_blocked
) req
->time_blocked
= now
;
547 debugf("udsserver_idle: client has been blocked for %d seconds", now
- req
->time_blocked
);
548 if (now
- req
->time_blocked
>= MAX_TIME_BLOCKED
)
550 LogMsg("Could not write data to client after %d seconds - aborting connection", MAX_TIME_BLOCKED
/ mDNSPlatformOneSecond
);
552 result
= t_terminated
;
554 else if (nextevent
- now
> mDNSPlatformOneSecond
) nextevent
= now
+ mDNSPlatformOneSecond
; // try again in a second
556 if (result
== t_terminated
|| result
== t_error
)
557 //since we're already doing a list traversal, we unlink the request manunally instead of calling unlink_request()
560 if (prev
) prev
->next
= req
->next
;
561 if (req
== all_requests
) all_requests
= all_requests
->next
;
563 freeL("udsserver_idle", tmp
);
574 void udsserver_info(void)
578 for (req
= all_requests
; req
; req
=req
->next
)
580 void *t
= req
->termination_context
;
582 if (req
->terminate
== regservice_termination_callback
)
583 LogMsgNoIdent("DNSServiceRegister %##s %u", ((registered_service
*)t
)->srs
->RR_SRV
.resrec
.name
.c
, SRS_PORT(((registered_service
*)t
)->srs
));
584 else if (req
->terminate
== browse_termination_callback
)
586 for (qlist
= ((browse_termination_context
*)t
)->qlist
; qlist
; qlist
= qlist
->next
)
587 LogMsgNoIdent("DNSServiceBrowse %##s", qlist
->q
.qname
.c
);
589 else if (req
->terminate
== resolve_termination_callback
)
590 LogMsgNoIdent("DNSServiceResolve %##s", ((resolve_termination_t
*)t
)->srv
->question
.qname
.c
);
591 else if (req
->terminate
== question_termination_callback
)
592 LogMsgNoIdent("DNSServiceQueryRecord %##s", ((DNSQuestion
*) t
)->qname
.c
);
593 else if (req
->terminate
== enum_termination_callback
)
594 LogMsgNoIdent("DNSServiceEnumerateDomains %##s", ((enum_termination_t
*) t
)->all
->question
.qname
.c
);
599 static void rename_service(registered_service
*srv
)
603 if (srv
->autoname
&& !SameDomainLabel(srv
->name
.c
, gmDNS
->nicelabel
.c
))
605 srv
->rename_on_memfree
= 1;
606 err
= mDNS_DeregisterService(gmDNS
, srv
->srs
);
607 if (err
) LogMsg("ERROR: udsserver_handle_configchange: DeregisterService returned error %d. Continuing.", err
);
608 // error should never occur - safest to log and continue
612 void udsserver_handle_configchange(void)
617 for (req
= all_requests
; req
; req
= req
->next
)
619 if (req
->servicepair
.local
) rename_service(req
->servicepair
.local
);
620 if (req
->servicepair
.global
) rename_service(req
->servicepair
.global
);
624 static void connect_callback(void *info _UNUSED
)
626 int sd
, clilen
, optval
;
627 struct sockaddr_un cliaddr
;
628 request_state
*rstate
;
631 clilen
= sizeof(cliaddr
);
632 sd
= accept(listenfd
, (struct sockaddr
*)&cliaddr
, &clilen
);
636 if (errno
== EWOULDBLOCK
) return;
637 my_perror("ERROR: accept");
642 // Some environments (e.g. OS X) support turning off SIGPIPE for a socket
643 if (setsockopt(sd
, SOL_SOCKET
, SO_NOSIGPIPE
, &optval
, sizeof(optval
)) < 0)
645 my_perror("ERROR: setsockopt - SOL_NOSIGPIPE - aborting client");
651 if (fcntl(sd
, F_SETFL
, O_NONBLOCK
) < 0)
653 my_perror("ERROR: could not set connected socket to non-blocking mode - aborting client");
659 // open a pipe to deliver error messages, pass descriptor to client
660 if (pipe(errpipe) < 0)
662 my_perror("ERROR: could not create pipe");
666 if (ioctl(sd, I_SENDFD, errpipe[0]) < 0)
668 my_perror("ERROR: could not pass pipe descriptor to client. Aborting client.\n");
672 if (fcntl(errpipe[1], F_SETFL, O_NONBLOCK) < 0)
674 my_perror("ERROR: could not set error pipe to non-blocking mode - aborting client");
681 // allocate a request_state struct that will live with the socket
682 rstate
= mallocL("connect_callback", sizeof(request_state
));
685 my_perror("ERROR: malloc");
688 bzero(rstate
, sizeof(request_state
));
689 rstate
->ts
= t_morecoming
;
691 //rstate->errfd = errpipe[1];
693 if ( mStatus_NoError
!= udsSupportAddFDToEventLoop( sd
, request_callback
, rstate
))
695 rstate
->next
= all_requests
;
696 all_requests
= rstate
;
701 static void request_callback(void *info
)
703 request_state
*rstate
= info
;
704 transfer_state result
;
705 struct sockaddr_un cliaddr
;
706 char ctrl_path
[MAX_CTLPATH
];
708 result
= read_msg(rstate
);
709 if (result
== t_morecoming
)
713 if (result
== t_terminated
)
715 abort_request(rstate
);
716 unlink_request(rstate
);
719 if (result
== t_error
)
721 abort_request(rstate
);
722 unlink_request(rstate
);
726 if (rstate
->hdr
.version
!= VERSION
)
728 LogMsg("ERROR: client incompatible with daemon (client version = %d, "
729 "daemon version = %d)\n", rstate
->hdr
.version
, VERSION
);
730 abort_request(rstate
);
731 unlink_request(rstate
);
735 if (validate_message(rstate
) < 0)
737 // note that we cannot deliver an error message if validation fails, since the path to the error socket
738 // may be contained in the (invalid) message body for some message types
739 abort_request(rstate
);
740 unlink_request(rstate
);
741 LogMsg("Invalid message sent by client - may indicate a malicious program running on this machine!");
745 // check if client wants silent operation
746 if (rstate
->hdr
.flags
& IPC_FLAGS_NOREPLY
) rstate
->no_reply
= 1;
748 // check if primary socket is to be used for synchronous errors, else open new socket
749 if (rstate
->hdr
.flags
& IPC_FLAGS_REUSE_SOCKET
)
750 rstate
->errfd
= rstate
->sd
;
753 if ((rstate
->errfd
= socket(AF_LOCAL
, SOCK_STREAM
, 0)) < 0)
755 my_perror("ERROR: socket");
758 if (fcntl(rstate
->errfd
, F_SETFL
, O_NONBLOCK
) < 0)
760 my_perror("ERROR: could not set control socket to non-blocking mode");
761 abort_request(rstate
);
762 unlink_request(rstate
);
765 get_string(&rstate
->msgdata
, ctrl_path
, 256); // path is first element in message buffer
766 bzero(&cliaddr
, sizeof(cliaddr
));
767 cliaddr
.sun_family
= AF_LOCAL
;
768 strcpy(cliaddr
.sun_path
, ctrl_path
);
769 if (connect(rstate
->errfd
, (struct sockaddr
*)&cliaddr
, sizeof(cliaddr
)) < 0)
771 my_perror("ERROR: connect");
772 abort_request(rstate
);
773 unlink_request(rstate
);
780 switch(rstate
->hdr
.op
.request_op
)
782 case resolve_request
: handle_resolve_request(rstate
); break;
783 case query_request
: handle_query_request(rstate
); break;
784 case browse_request
: handle_browse_request(rstate
); break;
785 case reg_service_request
: handle_regservice_request(rstate
); break;
786 case enumeration_request
: handle_enum_request(rstate
); break;
787 case reg_record_request
: handle_regrecord_request(rstate
); break;
788 case add_record_request
: handle_add_request(rstate
); break;
789 case update_record_request
: handle_update_request(rstate
); break;
790 case remove_record_request
: handle_removerecord_request(rstate
); break;
791 case reconfirm_record_request
: handle_reconfirm_request(rstate
); break;
793 debugf("ERROR: udsserver_recv_request - unsupported request type: %d", rstate
->hdr
.op
.request_op
);
797 // mDNS operation functions. Each operation has 3 associated functions - a request handler that parses
798 // the client's request and makes the appropriate mDNSCore call, a result handler (passed as a callback
799 // to the mDNSCore routine) that sends results back to the client, and a termination routine that aborts
800 // the mDNSCore operation if the client dies or closes its socket.
803 // query and resolve calls have separate request handlers that parse the arguments from the client and
804 // massage the name parameters appropriately, but the rest of the operations (making the query call,
805 // delivering the result to the client, and termination) are identical.
807 static void handle_query_request(request_state
*rstate
)
809 DNSServiceFlags flags
;
812 uint16_t rrtype
, rrclass
;
815 mDNSInterfaceID InterfaceID
;
818 if (rstate
->ts
!= t_complete
)
820 LogMsg("ERROR: handle_query_request - transfer state != t_complete");
823 ptr
= rstate
->msgdata
;
826 LogMsg("ERROR: handle_query_request - NULL msgdata");
830 flags
= get_flags(&ptr
);
831 ifi
= get_long(&ptr
);
832 if (get_string(&ptr
, name
, 256) < 0) goto bad_param
;
833 rrtype
= get_short(&ptr
);
834 rrclass
= get_short(&ptr
);
835 InterfaceID
= mDNSPlatformInterfaceIDfromInterfaceIndex(gmDNS
, ifi
);
836 if (ifi
&& !InterfaceID
) goto bad_param
;
838 q
= mallocL("DNSQuestion", sizeof(DNSQuestion
));
841 my_perror("ERROR: handle_query - malloc");
844 bzero(q
, sizeof(DNSQuestion
));
846 if (!MakeDomainNameFromDNSNameString(&q
->qname
, name
)) { freeL("DNSQuestion", q
); goto bad_param
; }
847 q
->QuestionContext
= rstate
;
848 q
->QuestionCallback
= question_result_callback
;
851 q
->InterfaceID
= InterfaceID
;
852 q
->Target
= zeroAddr
;
853 if (flags
& kDNSServiceFlagsLongLivedQuery
) q
->LongLived
= mDNStrue
;
854 rstate
->termination_context
= q
;
855 rstate
->terminate
= question_termination_callback
;
857 result
= mDNS_StartQuery(gmDNS
, q
);
858 if (result
!= mStatus_NoError
) LogMsg("ERROR: mDNS_StartQuery: %d", (int)result
);
860 if (result
) rstate
->terminate
= NULL
;
861 if (deliver_error(rstate
, result
) < 0) goto error
;
865 deliver_error(rstate
, mStatus_BadParamErr
);
866 rstate
->terminate
= NULL
; // don't try to terminate insuccessful Core calls
868 abort_request(rstate
);
869 unlink_request(rstate
);
873 static void handle_resolve_request(request_state
*rstate
)
875 DNSServiceFlags flags
;
876 uint32_t interfaceIndex
;
877 mDNSInterfaceID InterfaceID
;
878 char name
[256], regtype
[MAX_ESCAPED_DOMAIN_NAME
], domain
[MAX_ESCAPED_DOMAIN_NAME
];
879 char *ptr
; // message data pointer
881 resolve_t
*srv
, *txt
;
882 resolve_termination_t
*term
;
885 if (rstate
->ts
!= t_complete
)
887 LogMsg("ERROR: handle_resolve_request - transfer state != t_complete");
888 abort_request(rstate
);
889 unlink_request(rstate
);
893 // extract the data from the message
894 ptr
= rstate
->msgdata
;
897 LogMsg("ERROR: handle_resolve_request - NULL msgdata");
898 abort_request(rstate
);
899 unlink_request(rstate
);
902 flags
= get_flags(&ptr
);
903 interfaceIndex
= get_long(&ptr
);
904 InterfaceID
= mDNSPlatformInterfaceIDfromInterfaceIndex(gmDNS
, interfaceIndex
);
905 if (interfaceIndex
&& !InterfaceID
) goto bad_param
;
906 if (get_string(&ptr
, name
, 256) < 0 ||
907 get_string(&ptr
, regtype
, MAX_ESCAPED_DOMAIN_NAME
) < 0 ||
908 get_string(&ptr
, domain
, MAX_ESCAPED_DOMAIN_NAME
) < 0)
911 // free memory in rstate since we don't need it anymore
912 freeL("handle_resolve_request", rstate
->msgbuf
);
913 rstate
->msgbuf
= NULL
;
915 if (build_domainname_from_strings(&fqdn
, name
, regtype
, domain
) < 0)
918 // allocate question wrapper structs
919 srv
= mallocL("handle_resolve_request", sizeof(resolve_t
));
920 txt
= mallocL("handle_resolve_request", sizeof(resolve_t
));
921 if (!srv
|| !txt
) goto malloc_error
;
922 srv
->qtype
= kDNSType_SRV
;
923 txt
->qtype
= kDNSType_TXT
;
924 srv
->rstate
= rstate
;
925 txt
->rstate
= rstate
;
928 srv
->question
.QuestionContext
= rstate
;
929 srv
->question
.QuestionCallback
= resolve_result_callback
;
930 memcpy(&srv
->question
.qname
, &fqdn
, MAX_DOMAIN_NAME
);
931 srv
->question
.qtype
= kDNSType_SRV
;
932 srv
->question
.qclass
= kDNSClass_IN
;
933 srv
->question
.InterfaceID
= InterfaceID
;
934 srv
->question
.Target
= zeroAddr
;
936 txt
->question
.QuestionContext
= rstate
;
937 txt
->question
.QuestionCallback
= resolve_result_callback
;
938 memcpy(&txt
->question
.qname
, &fqdn
, MAX_DOMAIN_NAME
);
939 txt
->question
.qtype
= kDNSType_TXT
;
940 txt
->question
.qclass
= kDNSClass_IN
;
941 txt
->question
.InterfaceID
= InterfaceID
;
942 txt
->question
.Target
= zeroAddr
;
944 // set up termination info
945 term
= mallocL("handle_resolve_request", sizeof(resolve_termination_t
));
946 if (!term
) goto malloc_error
;
949 term
->rstate
= rstate
;
950 rstate
->termination_context
= term
;
951 rstate
->terminate
= resolve_termination_callback
;
953 // set up reply wrapper struct (since answer will come via 2 callbacks)
954 rstate
->resolve_results
= mallocL("handle_resolve_response", sizeof(resolve_result_t
));
955 if (!rstate
->resolve_results
) goto malloc_error
;
956 bzero(rstate
->resolve_results
, sizeof(resolve_result_t
));
959 err
= mDNS_StartQuery(gmDNS
, &srv
->question
);
960 if (!err
) err
= mDNS_StartQuery(gmDNS
, &txt
->question
);
964 freeL("handle_resolve_request", txt
);
965 freeL("handle_resolve_request", srv
);
966 freeL("handle_resolve_request", term
);
967 freeL("handle_resolve_request", rstate
->resolve_results
);
968 rstate
->terminate
= NULL
; // prevent abort_request() from invoking termination callback
970 if (deliver_error(rstate
, err
) < 0 || err
)
972 abort_request(rstate
);
973 unlink_request(rstate
);
978 deliver_error(rstate
, mStatus_BadParamErr
);
979 abort_request(rstate
);
980 unlink_request(rstate
);
984 my_perror("ERROR: malloc");
988 static void resolve_termination_callback(void *context
)
990 resolve_termination_t
*term
= context
;
995 LogMsg("ERROR: resolve_termination_callback: double termination");
1000 mDNS_StopQuery(gmDNS
, &term
->txt
->question
);
1001 mDNS_StopQuery(gmDNS
, &term
->srv
->question
);
1003 freeL("resolve_termination_callback", term
->txt
);
1004 freeL("resolve_termination_callback", term
->srv
);
1005 freeL("resolve_termination_callback", term
);
1006 rs
->termination_context
= NULL
;
1007 freeL("resolve_termination_callback", rs
->resolve_results
);
1008 rs
->resolve_results
= NULL
;
1013 static void resolve_result_callback(mDNS
*const m _UNUSED
, DNSQuestion
*question
, const ResourceRecord
*const answer
, mDNSBool AddRecord
)
1016 char fullname
[MAX_ESCAPED_DOMAIN_NAME
], target
[MAX_ESCAPED_DOMAIN_NAME
];
1018 transfer_state result
;
1020 request_state
*rs
= question
->QuestionContext
;
1021 resolve_result_t
*res
= rs
->resolve_results
;
1025 if (answer
->rrtype
== kDNSType_TXT
&& res
->txt
== answer
) res
->txt
= mDNSNULL
;
1026 if (answer
->rrtype
== kDNSType_SRV
&& res
->srv
== answer
) res
->srv
= mDNSNULL
;
1030 if (answer
->rrtype
== kDNSType_TXT
) res
->txt
= answer
;
1031 if (answer
->rrtype
== kDNSType_SRV
) res
->srv
= answer
;
1033 if (!res
->txt
|| !res
->srv
) return; // only deliver result to client if we have both answers
1035 ConvertDomainNameToCString(&answer
->name
, fullname
);
1036 ConvertDomainNameToCString(&res
->srv
->rdata
->u
.srv
.target
, target
);
1038 // calculate reply length
1039 len
+= sizeof(DNSServiceFlags
);
1040 len
+= sizeof(uint32_t); // interface index
1041 len
+= sizeof(DNSServiceErrorType
);
1042 len
+= strlen(fullname
) + 1;
1043 len
+= strlen(target
) + 1;
1044 len
+= 2 * sizeof(uint16_t); // port, txtLen
1045 len
+= res
->txt
->rdlength
;
1047 // allocate/init reply header
1048 rep
= create_reply(resolve_reply
, len
, rs
);
1049 rep
->rhdr
->flags
= 0;
1050 rep
->rhdr
->ifi
= mDNSPlatformInterfaceIndexfromInterfaceID(gmDNS
, answer
->InterfaceID
);
1051 rep
->rhdr
->error
= kDNSServiceErr_NoError
;
1054 // write reply data to message
1055 put_string(fullname
, &data
);
1056 put_string(target
, &data
);
1057 put_short(res
->srv
->rdata
->u
.srv
.port
.NotAnInteger
, &data
);
1058 put_short(res
->txt
->rdlength
, &data
);
1059 put_rdata(res
->txt
->rdlength
, res
->txt
->rdata
->u
.txt
.c
, &data
);
1061 result
= send_msg(rep
);
1062 if (result
== t_error
|| result
== t_terminated
)
1066 freeL("resolve_result_callback", rep
);
1068 else if (result
== t_complete
) freeL("resolve_result_callback", rep
);
1069 else append_reply(rs
, rep
);
1072 // what gets called when a resolve is completed and we need to send the data back to the client
1073 static void question_result_callback(mDNS
*const m _UNUSED
, DNSQuestion
*question
, const ResourceRecord
*const answer
, mDNSBool AddRecord
)
1076 char name
[MAX_ESCAPED_DOMAIN_NAME
];
1081 //mDNS_StopQuery(m, question);
1082 req
= question
->QuestionContext
;
1084 // calculate reply data length
1085 len
= sizeof(DNSServiceFlags
);
1086 len
+= 2 * sizeof(uint32_t); // if index + ttl
1087 len
+= sizeof(DNSServiceErrorType
);
1088 len
+= 3 * sizeof(uint16_t); // type, class, rdlen
1089 len
+= answer
->rdlength
;
1090 ConvertDomainNameToCString(&answer
->name
, name
);
1091 len
+= strlen(name
) + 1;
1093 rep
= create_reply(query_reply
, len
, req
);
1094 rep
->rhdr
->flags
= AddRecord
? kDNSServiceFlagsAdd
: 0;
1095 rep
->rhdr
->ifi
= mDNSPlatformInterfaceIndexfromInterfaceID(gmDNS
, answer
->InterfaceID
);
1096 rep
->rhdr
->error
= kDNSServiceErr_NoError
;
1099 put_string(name
, &data
);
1100 put_short(answer
->rrtype
, &data
);
1101 put_short(answer
->rrclass
, &data
);
1102 put_short(answer
->rdlength
, &data
);
1103 put_rdata(answer
->rdlength
, (char *)&answer
->rdata
->u
, &data
);
1104 put_long(AddRecord
? answer
->rroriginalttl
: 0, &data
);
1106 append_reply(req
, rep
);
1110 static void question_termination_callback(void *context
)
1112 DNSQuestion
*q
= context
;
1115 mDNS_StopQuery(gmDNS
, q
); // no need to error check
1116 freeL("question_termination_callback", q
);
1120 static void handle_browse_request(request_state
*request
)
1122 DNSServiceFlags flags
;
1123 uint32_t interfaceIndex
;
1124 mDNSInterfaceID InterfaceID
;
1125 char regtype
[MAX_ESCAPED_DOMAIN_NAME
], domain
[MAX_ESCAPED_DOMAIN_NAME
];
1126 qlist_t
*qlist
= NULL
, *qlist_elem
;
1130 DNameListElem
*search_domain_list
, *sdom
, tmp
;
1131 browse_termination_context
*term
;
1133 if (request
->ts
!= t_complete
)
1135 LogMsg("ERROR: handle_browse_request - transfer state != t_complete");
1136 abort_request(request
);
1137 unlink_request(request
);
1141 // extract data from message
1142 ptr
= request
->msgdata
;
1143 flags
= get_flags(&ptr
);
1144 interfaceIndex
= get_long(&ptr
);
1145 if (get_string(&ptr
, regtype
, MAX_ESCAPED_DOMAIN_NAME
) < 0 ||
1146 get_string(&ptr
, domain
, MAX_ESCAPED_DOMAIN_NAME
) < 0)
1148 freeL("handle_browse_request", request
->msgbuf
);
1149 request
->msgbuf
= NULL
;
1151 InterfaceID
= mDNSPlatformInterfaceIDfromInterfaceIndex(gmDNS
, interfaceIndex
);
1152 if (interfaceIndex
&& !InterfaceID
) goto bad_param
;
1154 if (!MakeDomainNameFromDNSNameString(&typedn
, regtype
)) goto bad_param
;
1156 //!!!KRS browse locally for ichat
1157 if (!domain
[0] && (!strcmp(regtype
, "_ichat._tcp.") || !strcmp(regtype
, "_presence._tcp.")))
1158 strcpy(domain
,"local.");
1162 // generate a fake list of one elem to reduce number of code paths
1163 if (!MakeDomainNameFromDNSNameString(&tmp
.name
, domain
)) goto bad_param
;
1165 search_domain_list
= &tmp
;
1167 else search_domain_list
= mDNSPlatformGetSearchDomainList();
1169 for (sdom
= search_domain_list
; sdom
; sdom
= sdom
->next
)
1171 qlist_elem
= mallocL("handle_browse_request", sizeof(qlist_t
));
1174 my_perror("ERROR: handle_browse_request - malloc");
1177 bzero(qlist_elem
, sizeof(qlist_t
));
1178 qlist_elem
->q
.QuestionContext
= request
;
1179 qlist_elem
->q
.QuestionCallback
= browse_result_callback
;
1180 qlist_elem
->next
= qlist
;
1184 // setup termination context
1185 term
= (browse_termination_context
*)mallocL("handle_browse_request", sizeof(browse_termination_context
));
1188 my_perror("ERROR: handle_browse_request - malloc");
1191 term
->qlist
= qlist
;
1192 term
->rstate
= request
;
1193 request
->termination_context
= term
;
1194 request
->terminate
= browse_termination_callback
;
1196 // start the browses
1197 sdom
= search_domain_list
;
1198 for (qlist_elem
= qlist
; qlist_elem
; qlist_elem
= qlist_elem
->next
)
1200 result
= mDNS_StartBrowse(gmDNS
, &qlist_elem
->q
, &typedn
, &sdom
->name
, InterfaceID
, browse_result_callback
, request
);
1203 // bail here on error. questions not yet issued are in no core lists, so they can be deallocated lazily
1204 if (search_domain_list
!= &tmp
) mDNS_FreeDNameList(search_domain_list
);
1205 deliver_error(request
, result
);
1210 if (search_domain_list
!= &tmp
) mDNS_FreeDNameList(search_domain_list
);
1211 deliver_error(request
, mStatus_NoError
);
1215 deliver_error(request
, mStatus_BadParamErr
);
1216 abort_request(request
);
1217 unlink_request(request
);
1220 static void browse_result_callback(mDNS
*const m _UNUSED
, DNSQuestion
*question
, const ResourceRecord
*const answer
, mDNSBool AddRecord
)
1226 req
= question
->QuestionContext
;
1228 err
= gen_rr_response(&answer
->rdata
->u
.name
, answer
->InterfaceID
, req
, &rep
);
1231 if (deliver_async_error(req
, browse_reply
, err
) < 0)
1234 unlink_request(req
);
1238 if (AddRecord
) rep
->rhdr
->flags
|= kDNSServiceFlagsAdd
; // non-zero TTL indicates add
1239 append_reply(req
, rep
);
1243 static void browse_termination_callback(void *context
)
1245 browse_termination_context
*t
= context
;
1246 qlist_t
*ptr
, *fptr
;
1255 mDNS_StopBrowse(gmDNS
, &ptr
->q
); // no need to error-check result
1258 freeL("browse_termination_callback", fptr
);
1260 t
->rstate
->termination_context
= NULL
;
1261 freeL("browse_termination_callback", t
);
1264 static mStatus
register_service(request_state
*request
, registered_service
**srv_ptr
, DNSServiceFlags flags
,
1265 uint16_t txtlen
, void *txtdata
, mDNSIPPort port
, domainlabel
*n
, char *type_as_string
,
1266 domainname
*t
, domainname
*d
, domainname
*h
, mDNSBool autoname
, int num_subtypes
, mDNSInterfaceID InterfaceID
)
1268 registered_service
*r_srv
;
1274 r_srv
= mallocL("handle_regservice_request", sizeof(registered_service
));
1275 if (!r_srv
) goto malloc_error
;
1276 srs_size
= sizeof(ServiceRecordSet
) + (sizeof(RDataBody
) > txtlen
? 0 : txtlen
- sizeof(RDataBody
));
1277 r_srv
->srs
= mallocL("handle_regservice_request", srs_size
);
1278 if (!r_srv
->srs
) goto malloc_error
;
1279 if (num_subtypes
> 0)
1281 r_srv
->subtypes
= mallocL("handle_regservice_request", num_subtypes
* sizeof(AuthRecord
));
1282 if (!r_srv
->subtypes
) goto malloc_error
;
1283 sub
= type_as_string
+ strlen(type_as_string
) + 1;
1284 for (i
= 0; i
< num_subtypes
; i
++)
1286 if (!MakeDomainNameFromDNSNameString(&(r_srv
->subtypes
+ i
)->resrec
.name
, sub
))
1288 free_service_registration(r_srv
);
1289 return mStatus_BadParamErr
;
1291 sub
+= strlen(sub
) + 1;
1294 else r_srv
->subtypes
= NULL
;
1295 r_srv
->request
= request
;
1297 r_srv
->extras
= NULL
;
1298 r_srv
->autoname
= autoname
;
1299 r_srv
->rename_on_memfree
= 0;
1300 r_srv
->renameonconflict
= !(flags
& kDNSServiceFlagsNoAutoRename
);
1301 memcpy(r_srv
->name
.c
, n
->c
, n
->c
[0]);
1303 result
= mDNS_RegisterService(gmDNS
, r_srv
->srs
, n
, t
, d
, h
, port
,
1304 txtdata
, txtlen
, r_srv
->subtypes
, num_subtypes
, InterfaceID
, regservice_callback
, r_srv
);
1307 free_service_registration(r_srv
);
1308 else *srv_ptr
= r_srv
;
1313 my_perror("ERROR: malloc");
1318 // service registration
1319 static void handle_regservice_request(request_state
*request
)
1321 DNSServiceFlags flags
;
1323 char name
[256], regtype
[MAX_ESCAPED_DOMAIN_NAME
], domain
[MAX_ESCAPED_DOMAIN_NAME
], host
[MAX_ESCAPED_DOMAIN_NAME
];
1329 domainname d
, h
, t
, srv
;
1331 mDNSInterfaceID InterfaceID
;
1335 if (request
->ts
!= t_complete
)
1337 LogMsg("ERROR: handle_regservice_request - transfer state != t_complete");
1338 abort_request(request
);
1339 unlink_request(request
);
1343 // extract data from message
1344 ptr
= request
->msgdata
;
1345 flags
= get_flags(&ptr
);
1346 ifi
= get_long(&ptr
);
1347 InterfaceID
= mDNSPlatformInterfaceIDfromInterfaceIndex(gmDNS
, ifi
);
1348 if (ifi
&& !InterfaceID
) goto bad_param
;
1349 if (get_string(&ptr
, name
, 256) < 0 ||
1350 get_string(&ptr
, regtype
, MAX_ESCAPED_DOMAIN_NAME
) < 0 ||
1351 get_string(&ptr
, domain
, MAX_ESCAPED_DOMAIN_NAME
) < 0 ||
1352 get_string(&ptr
, host
, MAX_ESCAPED_DOMAIN_NAME
) < 0)
1355 port
.NotAnInteger
= get_short(&ptr
);
1356 txtlen
= get_short(&ptr
);
1357 txtdata
= get_rdata(&ptr
, txtlen
);
1359 if (!*regtype
|| !MakeDomainNameFromDNSNameString(&t
, regtype
)) goto bad_param
;
1361 // count subtypes, replacing commas w/ whitespace
1362 rtype_ptr
= regtype
;
1364 while((sub
= strsep(&rtype_ptr
, ",")))
1365 if (*sub
) num_subtypes
++;
1367 if (!name
[0]) n
= (gmDNS
)->nicelabel
;
1368 else if (!MakeDomainLabelFromLiteralString(&n
, name
))
1371 if ((!MakeDomainNameFromDNSNameString(&d
, *domain
? domain
: "local.")) ||
1372 (!ConstructServiceName(&srv
, &n
, &t
, &d
)))
1375 if (host
[0] && !MakeDomainNameFromDNSNameString(&h
, host
)) goto bad_param
;
1377 result
= register_service(request
, &request
->servicepair
.local
, flags
, txtlen
, txtdata
, port
, &n
, ®type
[0], &t
, &d
, host
[0] ? &h
: NULL
, !name
[0], num_subtypes
, InterfaceID
);
1379 //!!!KRS if we got a dynamic reg domain from the config file, use it for default (except for iChat)
1380 if (!domain
[0] && gmDNS
->uDNS_info
.ServiceRegDomain
[0] && strcmp(regtype
, "_presence._tcp.") && strcmp(regtype
, "_ichat._tcp."))
1382 MakeDomainNameFromDNSNameString(&d
, gmDNS
->uDNS_info
.ServiceRegDomain
);
1383 register_service(request
, &request
->servicepair
.global
, flags
, txtlen
, txtdata
, port
, &n
, ®type
[0], &t
, &d
, host
[0] ? &h
: NULL
, !name
[0], num_subtypes
, InterfaceID
);
1384 // don't return default global errors - it will confuse legacy clients, and we want .local to still work for them
1387 request
->termination_context
= &request
->servicepair
;
1388 request
->terminate
= regservice_termination_callback
;
1390 deliver_error(request
, result
);
1391 if (result
!= mStatus_NoError
)
1393 abort_request(request
);
1394 unlink_request(request
);
1397 reset_connected_rstate(request
); // reset to receive add/remove messages
1402 deliver_error(request
, mStatus_BadParamErr
);
1403 abort_request(request
);
1404 unlink_request(request
);
1410 // service registration callback performs three duties - frees memory for deregistered services,
1411 // handles name conflicts, and delivers completed registration information to the client (via
1412 // process_service_registraion())
1414 static void regservice_callback(mDNS
*const m _UNUSED
, ServiceRecordSet
*const srs
, mStatus result
)
1417 registered_service
*r_srv
= srs
->ServiceContext
;
1418 request_state
*rs
= r_srv
->request
;
1420 if (!rs
&& (result
!= mStatus_MemFree
&& !r_srv
->rename_on_memfree
))
1422 // error should never happen - safest to log and continue
1423 LogMsg("ERROR: regservice_callback: received result %d with a NULL request pointer\n");
1427 if (result
== mStatus_NoError
)
1428 return process_service_registration(srs
);
1429 else if (result
== mStatus_MemFree
)
1431 if (r_srv
->rename_on_memfree
)
1433 r_srv
->rename_on_memfree
= 0;
1434 r_srv
->name
= gmDNS
->nicelabel
;
1435 err
= mDNS_RenameAndReregisterService(gmDNS
, srs
, &r_srv
->name
);
1436 if (err
) LogMsg("ERROR: regservice_callback - RenameAndReregisterService returned %d", err
);
1437 // error should never happen - safest to log and continue
1441 free_service_registration(r_srv
);
1445 else if (result
== mStatus_NameConflict
)
1447 if (r_srv
->autoname
|| r_srv
->renameonconflict
)
1449 mDNS_RenameAndReregisterService(gmDNS
, srs
, mDNSNULL
);
1454 free_service_registration(r_srv
);
1455 if (deliver_async_error(rs
, reg_service_reply
, result
) < 0)
1465 LogMsg("ERROR: unknown result in regservice_callback: %d", result
);
1466 if (deliver_async_error(rs
, reg_service_reply
, result
) < 0)
1475 static mStatus
add_record_to_service(request_state
*rstate
, registered_service
*r_srv
, uint16_t rrtype
, uint16_t rdlen
, char *rdata
, uint32_t ttl
)
1477 ServiceRecordSet
*srs
= r_srv
->srs
;
1478 ExtraResourceRecord
*extra
;
1479 extra_record_entry
*ere
;
1483 if (rdlen
> sizeof(RDataBody
)) size
= rdlen
;
1484 else size
= sizeof(RDataBody
);
1486 ere
= mallocL("hanle_add_request", sizeof(extra_record_entry
) - sizeof(RDataBody
) + size
);
1489 my_perror("ERROR: malloc");
1493 bzero(ere
, sizeof(ExtraResourceRecord
)); // OK if oversized rdata not zero'd
1495 extra
->r
.resrec
.rrtype
= rrtype
;
1496 extra
->r
.rdatastorage
.MaxRDLength
= size
;
1497 extra
->r
.resrec
.rdlength
= rdlen
;
1498 memcpy(&extra
->r
.rdatastorage
.u
.data
, rdata
, rdlen
);
1500 result
= mDNS_AddRecordToService(gmDNS
, srs
, extra
, &extra
->r
.rdatastorage
, ttl
);
1501 if (result
) { freeL("handle_add_request", ere
); return result
; }
1503 ere
->key
= rstate
->hdr
.reg_index
;
1504 ere
->next
= r_srv
->extras
;
1505 r_srv
->extras
= ere
;
1510 static void handle_add_request(request_state
*rstate
)
1513 uint16_t rrtype
, rdlen
;
1516 DNSServiceFlags flags
;
1517 registered_service
*local
, *global
;
1519 local
= rstate
->servicepair
.local
;
1520 global
= rstate
->servicepair
.global
;
1524 LogMsg("ERROR: handle_add_request - no service registered");
1525 deliver_error(rstate
, mStatus_UnknownErr
);
1529 ptr
= rstate
->msgdata
;
1530 flags
= get_flags(&ptr
);
1531 rrtype
= get_short(&ptr
);
1532 rdlen
= get_short(&ptr
);
1533 rdata
= get_rdata(&ptr
, rdlen
);
1534 ttl
= get_long(&ptr
);
1536 result
= add_record_to_service(rstate
, local
, rrtype
, rdlen
, rdata
, ttl
);
1537 if (global
) add_record_to_service(rstate
, global
, rrtype
, rdlen
, rdata
, ttl
); // don't report global errors to client
1539 deliver_error(rstate
, result
);
1540 reset_connected_rstate(rstate
);
1543 static mStatus
update_record(AuthRecord
*rr
, uint16_t rdlen
, char *rdata
, uint32_t ttl
)
1549 if (rdlen
> sizeof(RDataBody
)) rdsize
= rdlen
;
1550 else rdsize
= sizeof(RDataBody
);
1551 newrd
= mallocL("handle_update_request", sizeof(RData
) - sizeof(RDataBody
) + rdsize
);
1554 my_perror("ERROR: malloc");
1557 newrd
->MaxRDLength
= rdsize
;
1558 memcpy(&newrd
->u
, rdata
, rdlen
);
1559 result
= mDNS_Update(gmDNS
, rr
, ttl
, rdlen
, newrd
, update_callback
);
1560 if (result
) { LogMsg("ERROR: mDNS_Update - %d", result
); freeL("handle_update_request", newrd
); }
1564 static mStatus
find_extras_by_key(request_state
*rstate
, AuthRecord
**lRR
, AuthRecord
**gRR
)
1566 extra_record_entry
*e
;
1568 // find the extra record for the local service
1569 for (e
= rstate
->servicepair
.local
->extras
; e
; e
= e
->next
)
1570 if (e
->key
== rstate
->hdr
.reg_index
) break;
1571 if (!e
) return mStatus_BadReferenceErr
;
1575 // find the corresponding global record, if it exists
1576 if (rstate
->servicepair
.global
)
1578 for (e
= rstate
->servicepair
.global
->extras
; e
; e
= e
->next
)
1579 if (e
->key
== rstate
->hdr
.reg_index
) break;
1580 if (e
) *gRR
= &e
->e
.r
;
1583 return mStatus_NoError
;
1586 static void handle_update_request(request_state
*rstate
)
1588 registered_record_entry
*reptr
;
1589 AuthRecord
*lRR
, *gRR
= NULL
;
1595 if (rstate
->hdr
.reg_index
== TXT_RECORD_INDEX
)
1597 if (!rstate
->servicepair
.local
)
1599 deliver_error(rstate
, mStatus_BadParamErr
);
1602 lRR
= &rstate
->servicepair
.local
->srs
->RR_TXT
;
1603 if (rstate
->servicepair
.global
) gRR
= &rstate
->servicepair
.global
->srs
->RR_TXT
;
1607 if (rstate
->servicepair
.local
) // registered service
1609 if (find_extras_by_key(rstate
, &lRR
, &gRR
))
1610 { deliver_error(rstate
, mStatus_BadReferenceErr
); return; }
1614 // record created via RegisterRecord
1615 reptr
= rstate
->reg_recs
;
1616 while(reptr
&& reptr
->key
!= rstate
->hdr
.reg_index
) reptr
= reptr
->next
;
1617 if (!reptr
) { deliver_error(rstate
, mStatus_BadReferenceErr
); return; }
1622 // get the message data
1623 ptr
= rstate
->msgdata
;
1624 get_flags(&ptr
); // flags unused
1625 rdlen
= get_short(&ptr
);
1626 rdata
= get_rdata(&ptr
, rdlen
);
1627 ttl
= get_long(&ptr
);
1629 result
= update_record(lRR
, rdlen
, rdata
, ttl
);
1630 if (gRR
) update_record(gRR
, rdlen
, rdata
, ttl
); // don't report errors for global registration
1632 deliver_error(rstate
, result
);
1633 reset_connected_rstate(rstate
);
1636 static void update_callback(mDNS
*const m _UNUSED
, AuthRecord
*const rr
, RData
*oldrd
)
1638 if (oldrd
!= &rr
->rdatastorage
) freeL("update_callback", oldrd
);
1641 static void process_service_registration(ServiceRecordSet
*const srs
)
1644 transfer_state send_result
;
1646 registered_service
*r_srv
= srs
->ServiceContext
;
1647 request_state
*req
= r_srv
->request
;
1650 err
= gen_rr_response(&srs
->RR_SRV
.resrec
.name
, srs
->RR_SRV
.resrec
.InterfaceID
, req
, &rep
);
1653 if (deliver_async_error(req
, reg_service_reply
, err
) < 0)
1656 unlink_request(req
);
1660 send_result
= send_msg(rep
);
1661 if (send_result
== t_error
|| send_result
== t_terminated
)
1664 unlink_request(req
);
1665 freeL("process_service_registration", rep
);
1667 else if (send_result
== t_complete
) freeL("process_service_registration", rep
);
1668 else append_reply(req
, rep
);
1671 static void free_service_registration(registered_service
*srv
)
1673 request_state
*rstate
= srv
->request
;
1674 extra_record_entry
*extra
;
1676 // clear pointers from parent struct
1679 if (rstate
->servicepair
.local
== srv
) rstate
->servicepair
.local
= NULL
;
1680 else if (rstate
->servicepair
.global
== srv
) rstate
->servicepair
.global
= NULL
;
1685 extra
= srv
->extras
;
1686 srv
->extras
= srv
->extras
->next
;
1687 if (extra
->e
.r
.resrec
.rdata
!= &extra
->e
.r
.rdatastorage
)
1688 freeL("free_service_registration", extra
->e
.r
.resrec
.rdata
);
1689 freeL("regservice_callback", extra
);
1692 if (srv
->subtypes
) { freeL("regservice_callback", srv
->subtypes
); srv
->subtypes
= NULL
; }
1693 freeL("regservice_callback", srv
->srs
);
1695 freeL("regservice_callback", srv
);
1698 static void regservice_termination_callback(void *context
)
1700 servicepair_t
*pair
= context
;
1702 if (!pair
->local
&& !pair
->global
) { LogMsg("ERROR: regservice_termination_callback called with null services"); return; }
1704 // clear service pointers to parent request state
1705 if (pair
->local
) pair
->local
->request
= NULL
;
1706 if (pair
->global
) pair
->global
->request
= NULL
;
1708 // only safe to free memory if registration is not valid, ie deregister fails
1709 if (pair
->local
&& mDNS_DeregisterService(gmDNS
, pair
->local
->srs
) != mStatus_NoError
)
1710 free_service_registration(pair
->local
);
1711 if (pair
->global
&& mDNS_DeregisterService(gmDNS
, pair
->global
->srs
) != mStatus_NoError
)
1712 free_service_registration(pair
->global
);
1714 // clear pointers to services - they'll get cleaned by MemFree callback
1716 pair
->global
= NULL
;
1720 static void handle_regrecord_request(request_state
*rstate
)
1723 regrecord_callback_context
*rcc
;
1724 registered_record_entry
*re
;
1727 if (rstate
->ts
!= t_complete
)
1729 LogMsg("ERROR: handle_regrecord_request - transfer state != t_complete");
1730 abort_request(rstate
);
1731 unlink_request(rstate
);
1735 rr
= read_rr_from_ipc_msg(rstate
->msgdata
, 1, 1);
1738 deliver_error(rstate
, mStatus_BadParamErr
);
1742 rcc
= mallocL("hanlde_regrecord_request", sizeof(regrecord_callback_context
));
1743 if (!rcc
) goto malloc_error
;
1744 rcc
->rstate
= rstate
;
1745 rcc
->client_context
= rstate
->hdr
.client_context
;
1746 rr
->RecordContext
= rcc
;
1747 rr
->RecordCallback
= regrecord_callback
;
1749 // allocate registration entry, link into list
1750 re
= mallocL("hanlde_regrecord_request", sizeof(registered_record_entry
));
1751 if (!re
) goto malloc_error
;
1752 re
->key
= rstate
->hdr
.reg_index
;
1754 re
->next
= rstate
->reg_recs
;
1755 rstate
->reg_recs
= re
;
1757 if (!rstate
->terminate
)
1759 rstate
->terminate
= connected_registration_termination
;
1760 rstate
->termination_context
= rstate
;
1763 result
= mDNS_Register(gmDNS
, rr
);
1764 deliver_error(rstate
, result
);
1765 reset_connected_rstate(rstate
);
1769 my_perror("ERROR: malloc");
1773 static void regrecord_callback(mDNS
*const m _UNUSED
, AuthRecord
*const rr
, mStatus result
)
1775 regrecord_callback_context
*rcc
= rr
->RecordContext
;
1780 if (result
== mStatus_MemFree
)
1782 freeL("regrecord_callback", rcc
);
1783 rr
->RecordContext
= NULL
;
1784 freeL("regrecord_callback", rr
);
1788 // format result, add to the list for the request, including the client context in the header
1789 len
= sizeof(DNSServiceFlags
);
1790 len
+= sizeof(uint32_t); //interfaceIndex
1791 len
+= sizeof(DNSServiceErrorType
);
1793 reply
= create_reply(reg_record_reply
, len
, rcc
->rstate
);
1794 reply
->mhdr
->client_context
= rcc
->client_context
;
1795 reply
->rhdr
->flags
= 0;
1796 reply
->rhdr
->ifi
= mDNSPlatformInterfaceIndexfromInterfaceID(gmDNS
, rr
->resrec
.InterfaceID
);
1797 reply
->rhdr
->error
= result
;
1799 ts
= send_msg(reply
);
1800 if (ts
== t_error
|| ts
== t_terminated
)
1802 abort_request(rcc
->rstate
);
1803 unlink_request(rcc
->rstate
);
1805 else if (ts
== t_complete
) freeL("regrecord_callback", reply
);
1806 else if (ts
== t_morecoming
) append_reply(rcc
->rstate
, reply
); // client is blocked, link reply into list
1809 static void connected_registration_termination(void *context
)
1812 registered_record_entry
*fptr
, *ptr
= ((request_state
*)context
)->reg_recs
;
1817 shared
= fptr
->rr
->resrec
.RecordType
== kDNSRecordTypeShared
;
1818 mDNS_Deregister(gmDNS
, fptr
->rr
);
1820 // shared records free'd via callback w/ mStatus_MemFree
1822 freeL("connected_registration_termination", fptr
->rr
->RecordContext
);
1823 fptr
->rr
->RecordContext
= NULL
;
1824 freeL("connected_registration_termination", fptr
->rr
);
1827 freeL("connected_registration_termination", fptr
);
1833 static void handle_removerecord_request(request_state
*rstate
)
1838 ptr
= rstate
->msgdata
;
1839 get_flags(&ptr
); // flags unused
1841 if (rstate
->servicepair
.local
) err
= remove_extra_rr_from_service(rstate
);
1842 else err
= remove_record(rstate
);
1844 reset_connected_rstate(rstate
);
1845 if (deliver_error(rstate
, err
) < 0)
1847 abort_request(rstate
);
1848 unlink_request(rstate
);
1852 // remove a resource record registered via DNSServiceRegisterRecord()
1853 static mStatus
remove_record(request_state
*rstate
)
1856 registered_record_entry
*reptr
, *prev
= NULL
;
1857 mStatus err
= mStatus_UnknownErr
;
1858 reptr
= rstate
->reg_recs
;
1862 if (reptr
->key
== rstate
->hdr
.reg_index
) // found match
1864 if (prev
) prev
->next
= reptr
->next
;
1865 else rstate
->reg_recs
= reptr
->next
;
1866 shared
= reptr
->rr
->resrec
.RecordType
== kDNSRecordTypeShared
;
1867 err
= mDNS_Deregister(gmDNS
, reptr
->rr
);
1870 LogMsg("ERROR: remove_record, mDNS_Deregister: %d", err
);
1871 return err
; // this should not happen. don't try to free memory if there's an error
1874 // shared records free'd via callback w/ mStatus_MemFree
1876 freeL("remove_record", reptr
->rr
->RecordContext
);
1877 reptr
->rr
->RecordContext
= NULL
;
1878 freeL("remove_record", reptr
->rr
);
1881 freeL("remove_record", reptr
);
1885 reptr
= reptr
->next
;
1891 static mStatus
remove_extra(request_state
*rstate
, registered_service
*serv
)
1893 mStatus err
= mStatus_BadReferenceErr
;
1894 extra_record_entry
*ptr
, *prev
= NULL
;
1899 if (ptr
->key
== rstate
->hdr
.reg_index
) // found match
1901 if (prev
) prev
->next
= ptr
->next
;
1902 else serv
->extras
= ptr
->next
;
1903 err
= mDNS_RemoveRecordFromService(gmDNS
, serv
->srs
, &ptr
->e
);
1904 if (err
) return err
;
1905 freeL("remove_extra_rr_from_service", ptr
);
1914 static mStatus
remove_extra_rr_from_service(request_state
*rstate
)
1916 mStatus err
= mStatus_UnknownErr
;
1918 err
= remove_extra(rstate
, rstate
->servicepair
.local
);
1919 if (rstate
->servicepair
.global
) remove_extra(rstate
, rstate
->servicepair
.global
); // don't return error for global
1926 // domain enumeration
1927 static void handle_enum_request(request_state
*rstate
)
1929 DNSServiceFlags flags
, add_default
;
1931 mDNSInterfaceID InterfaceID
;
1932 char *ptr
= rstate
->msgdata
;
1933 domain_enum_t
*def
, *all
;
1934 enum_termination_t
*term
;
1935 reply_state
*reply
; // initial default reply
1940 if (rstate
->ts
!= t_complete
)
1942 LogMsg("ERROR: handle_enum_request - transfer state != t_complete");
1943 abort_request(rstate
);
1944 unlink_request(rstate
);
1948 flags
= get_flags(&ptr
);
1949 ifi
= get_long(&ptr
);
1950 InterfaceID
= mDNSPlatformInterfaceIDfromInterfaceIndex(gmDNS
, ifi
);
1951 if (ifi
&& !InterfaceID
)
1953 deliver_error(rstate
, mStatus_BadParamErr
);
1954 abort_request(rstate
);
1955 unlink_request(rstate
);
1958 // allocate context structures
1959 def
= mallocL("hanlde_enum_request", sizeof(domain_enum_t
));
1960 all
= mallocL("handle_enum_request", sizeof(domain_enum_t
));
1961 term
= mallocL("handle_enum_request", sizeof(enum_termination_t
));
1962 if (!def
|| !all
|| !term
)
1964 my_perror("ERROR: malloc");
1968 // enumeration requires multiple questions, so we must link all the context pointers so that
1969 // necessary context can be reached from the callbacks
1970 def
->rstate
= rstate
;
1971 all
->rstate
= rstate
;
1974 term
->rstate
= rstate
;
1975 rstate
->termination_context
= term
;
1976 rstate
->terminate
= enum_termination_callback
;
1977 def
->question
.QuestionContext
= def
;
1978 def
->type
= (flags
& kDNSServiceFlagsRegistrationDomains
) ?
1979 mDNS_DomainTypeRegistrationDefault
: mDNS_DomainTypeBrowseDefault
;
1980 all
->question
.QuestionContext
= all
;
1981 all
->type
= (flags
& kDNSServiceFlagsRegistrationDomains
) ?
1982 mDNS_DomainTypeRegistration
: mDNS_DomainTypeBrowse
;
1984 // if the caller hasn't specified an explicit interface, we use local-only to get the system-wide list.
1985 if (!InterfaceID
) InterfaceID
= mDNSInterface_LocalOnly
;
1988 err
= mDNS_GetDomains(gmDNS
, &all
->question
, all
->type
, NULL
, InterfaceID
, enum_result_callback
, all
);
1989 if (err
== mStatus_NoError
)
1990 err
= mDNS_GetDomains(gmDNS
, &def
->question
, def
->type
, NULL
, InterfaceID
, enum_result_callback
, def
);
1991 result
= deliver_error(rstate
, err
); // send error *before* returning local domain
1993 if (result
< 0 || err
)
1995 abort_request(rstate
);
1996 unlink_request(rstate
);
2000 // provide local. as the first domain automatically
2001 add_default
= kDNSServiceFlagsDefault
| kDNSServiceFlagsAdd
;
2002 reply
= format_enumeration_reply(rstate
, "local.", add_default
, ifi
, 0);
2003 tr
= send_msg(reply
);
2004 if (tr
== t_error
|| tr
== t_terminated
)
2006 freeL("handle_enum_request", def
);
2007 freeL("handle_enum_request", all
);
2008 abort_request(rstate
);
2009 unlink_request(rstate
);
2012 if (tr
== t_complete
) freeL("handle_enum_request", reply
);
2013 if (tr
== t_morecoming
) append_reply(rstate
, reply
); // couldn't send whole reply because client is blocked - link into list
2016 static void enum_result_callback(mDNS
*const m _UNUSED
, DNSQuestion
*question
, const ResourceRecord
*const answer
, mDNSBool AddRecord
)
2018 char domain
[MAX_ESCAPED_DOMAIN_NAME
];
2019 domain_enum_t
*de
= question
->QuestionContext
;
2020 DNSServiceFlags flags
= 0;
2023 if (answer
->rrtype
!= kDNSType_PTR
) return;
2026 flags
|= kDNSServiceFlagsAdd
;
2027 if (de
->type
== mDNS_DomainTypeRegistrationDefault
|| de
->type
== mDNS_DomainTypeBrowseDefault
)
2028 flags
|= kDNSServiceFlagsDefault
;
2030 ConvertDomainNameToCString(&answer
->rdata
->u
.name
, domain
);
2031 reply
= format_enumeration_reply(de
->rstate
, domain
, flags
, mDNSPlatformInterfaceIndexfromInterfaceID(gmDNS
, answer
->InterfaceID
), kDNSServiceErr_NoError
);
2034 LogMsg("ERROR: enum_result_callback, format_enumeration_reply");
2038 append_reply(de
->rstate
, reply
);
2042 static reply_state
*format_enumeration_reply(request_state
*rstate
, const char *domain
, DNSServiceFlags flags
, uint32_t ifi
, DNSServiceErrorType err
)
2049 len
= sizeof(DNSServiceFlags
);
2050 len
+= sizeof(uint32_t);
2051 len
+= sizeof(DNSServiceErrorType
);
2052 len
+= strlen(domain
) + 1;
2054 reply
= create_reply(enumeration_reply
, len
, rstate
);
2055 reply
->rhdr
->flags
= flags
;
2056 reply
->rhdr
->ifi
= ifi
;
2057 reply
->rhdr
->error
= err
;
2058 data
= reply
->sdata
;
2059 put_string(domain
, &data
);
2063 static void enum_termination_callback(void *context
)
2065 enum_termination_t
*t
= context
;
2066 mDNS
*coredata
= gmDNS
;
2068 mDNS_StopGetDomains(coredata
, &t
->all
->question
);
2069 mDNS_StopGetDomains(coredata
, &t
->def
->question
);
2070 freeL("enum_termination_callback", t
->all
);
2071 freeL("enum_termination_callback", t
->def
);
2072 t
->rstate
->termination_context
= NULL
;
2073 freeL("enum_termination_callback", t
);
2076 static void handle_reconfirm_request(request_state
*rstate
)
2080 rr
= read_rr_from_ipc_msg(rstate
->msgdata
, 0, 1);
2082 mDNS_ReconfirmByValue(gmDNS
, &rr
->resrec
);
2083 abort_request(rstate
);
2084 unlink_request(rstate
);
2085 freeL("handle_reconfirm_request", rr
);
2089 // setup rstate to accept new reg/dereg requests
2090 static void reset_connected_rstate(request_state
*rstate
)
2092 rstate
->ts
= t_morecoming
;
2093 rstate
->hdr_bytes
= 0;
2094 rstate
->data_bytes
= 0;
2095 if (rstate
->msgbuf
) freeL("reset_connected_rstate", rstate
->msgbuf
);
2096 rstate
->msgbuf
= NULL
;
2097 rstate
->bufsize
= 0;
2102 // returns a resource record (allocated w/ malloc) containing the data found in an IPC message
2103 // data must be in format flags, interfaceIndex, name, rrtype, rrclass, rdlen, rdata, (optional)ttl
2104 // (ttl only extracted/set if ttl argument is non-zero). returns NULL for a bad-parameter error
2105 static AuthRecord
*read_rr_from_ipc_msg(char *msgbuf
, int ttl
, int validate_flags
)
2107 char *rdata
, name
[256];
2109 DNSServiceFlags flags
;
2110 uint32_t interfaceIndex
;
2111 uint16_t type
, class, rdlen
;
2114 flags
= get_flags(&msgbuf
);
2115 if (validate_flags
&&
2116 !((flags
& kDNSServiceFlagsShared
) == kDNSServiceFlagsShared
) &&
2117 !((flags
& kDNSServiceFlagsUnique
) == kDNSServiceFlagsUnique
))
2119 LogMsg("ERROR: Bad resource record flags (must be kDNSServiceFlagsShared or kDNSServiceFlagsUnique)");
2123 interfaceIndex
= get_long(&msgbuf
);
2124 if (get_string(&msgbuf
, name
, 256) < 0)
2126 LogMsg("ERROR: read_rr_from_ipc_msg - get_string");
2129 type
= get_short(&msgbuf
);
2130 class = get_short(&msgbuf
);
2131 rdlen
= get_short(&msgbuf
);
2133 if (rdlen
> sizeof(RDataBody
)) storage_size
= rdlen
;
2134 else storage_size
= sizeof(RDataBody
);
2136 rr
= mallocL("read_rr_from_ipc_msg", sizeof(AuthRecord
) - sizeof(RDataBody
) + storage_size
);
2139 my_perror("ERROR: malloc");
2142 bzero(rr
, sizeof(AuthRecord
)); // ok if oversized rdata not zero'd
2143 rr
->resrec
.rdata
= &rr
->rdatastorage
;
2144 rr
->resrec
.InterfaceID
= mDNSPlatformInterfaceIDfromInterfaceIndex(gmDNS
, interfaceIndex
);
2145 if (!MakeDomainNameFromDNSNameString(&rr
->resrec
.name
, name
))
2147 LogMsg("ERROR: bad name: %s", name
);
2148 freeL("read_rr_from_ipc_msg", rr
);
2151 rr
->resrec
.rrtype
= type
;
2152 if ((flags
& kDNSServiceFlagsShared
) == kDNSServiceFlagsShared
)
2153 rr
->resrec
.RecordType
= kDNSRecordTypeShared
;
2154 if ((flags
& kDNSServiceFlagsUnique
) == kDNSServiceFlagsUnique
)
2155 rr
->resrec
.RecordType
= kDNSRecordTypeUnique
;
2156 rr
->resrec
.rrclass
= class;
2157 rr
->resrec
.rdlength
= rdlen
;
2158 rr
->resrec
.rdata
->MaxRDLength
= rdlen
;
2159 rdata
= get_rdata(&msgbuf
, rdlen
);
2160 memcpy(rr
->resrec
.rdata
->u
.data
, rdata
, rdlen
);
2163 rr
->resrec
.rroriginalttl
= get_long(&msgbuf
);
2169 // generate a response message for a browse result, service registration result, or any other call with the
2170 // identical callback signature. on successful completion rep is set to point to a malloc'd reply_state struct,
2171 // and mStatus_NoError is returned. otherwise the appropriate error is returned.
2173 static mStatus
gen_rr_response(domainname
*servicename
, mDNSInterfaceID id
, request_state
*request
, reply_state
**rep
)
2178 domainname type
, dom
;
2179 char namestr
[MAX_DOMAIN_LABEL
+1]; // Unescaped name: up to 63 bytes plus C-string terminating NULL.
2180 char typestr
[MAX_ESCAPED_DOMAIN_NAME
];
2181 char domstr
[MAX_ESCAPED_DOMAIN_NAME
];
2185 if (!DeconstructServiceName(servicename
, &name
, &type
, &dom
))
2186 return kDNSServiceErr_Unknown
;
2188 ConvertDomainLabelToCString_unescaped(&name
, namestr
);
2189 ConvertDomainNameToCString(&type
, typestr
);
2190 ConvertDomainNameToCString(&dom
, domstr
);
2192 // calculate reply data length
2193 len
= sizeof(DNSServiceFlags
);
2194 len
+= sizeof(uint32_t); // if index
2195 len
+= sizeof(DNSServiceErrorType
);
2196 len
+= strlen(namestr
) + 1;
2197 len
+= strlen(typestr
) + 1;
2198 len
+= strlen(domstr
) + 1;
2200 *rep
= create_reply(query_reply
, len
, request
);
2201 (*rep
)->rhdr
->flags
= 0;
2202 (*rep
)->rhdr
->ifi
= mDNSPlatformInterfaceIndexfromInterfaceID(gmDNS
, id
);
2203 (*rep
)->rhdr
->error
= kDNSServiceErr_NoError
;
2204 data
= (*rep
)->sdata
;
2206 put_string(namestr
, &data
);
2207 put_string(typestr
, &data
);
2208 put_string(domstr
, &data
);
2209 return mStatus_NoError
;
2213 static int build_domainname_from_strings(domainname
*srv
, char *name
, char *regtype
, char *domain
)
2218 if (!MakeDomainLabelFromLiteralString(&n
, name
)) return -1;
2219 if (!MakeDomainNameFromDNSNameString(&t
, regtype
)) return -1;
2220 if (!MakeDomainNameFromDNSNameString(&d
, domain
)) return -1;
2221 if (!ConstructServiceName(srv
, &n
, &t
, &d
)) return -1;
2226 // append a reply to the list in a request object
2227 static void append_reply(request_state
*req
, reply_state
*rep
)
2231 if (!req
->replies
) req
->replies
= rep
;
2235 while (ptr
->next
) ptr
= ptr
->next
;
2242 // read_msg may be called any time when the transfer state (rs->ts) is t_morecoming.
2243 // returns the current state of the request (morecoming, error, complete, terminated.)
2244 // if there is no data on the socket, the socket will be closed and t_terminated will be returned
2245 static int read_msg(request_state
*rs
)
2249 char buf
[4]; // dummy for death notification
2251 if (rs
->ts
== t_terminated
|| rs
->ts
== t_error
)
2253 LogMsg("ERROR: read_msg called with transfer state terminated or error");
2258 if (rs
->ts
== t_complete
)
2259 { // this must be death or something is wrong
2260 nread
= recv(rs
->sd
, buf
, 4, 0);
2261 if (!nread
) { rs
->ts
= t_terminated
; return t_terminated
; }
2262 if (nread
< 0) goto rerror
;
2263 LogMsg("ERROR: read data from a completed request.");
2268 if (rs
->ts
!= t_morecoming
)
2270 LogMsg("ERROR: read_msg called with invalid transfer state (%d)", rs
->ts
);
2275 if (rs
->hdr_bytes
< sizeof(ipc_msg_hdr
))
2277 nleft
= sizeof(ipc_msg_hdr
) - rs
->hdr_bytes
;
2278 nread
= recv(rs
->sd
, (char *)&rs
->hdr
+ rs
->hdr_bytes
, nleft
, 0);
2279 if (nread
== 0) { rs
->ts
= t_terminated
; return t_terminated
; }
2280 if (nread
< 0) goto rerror
;
2281 rs
->hdr_bytes
+= nread
;
2282 if (rs
->hdr_bytes
> sizeof(ipc_msg_hdr
))
2284 LogMsg("ERROR: read_msg - read too many header bytes");
2290 // only read data if header is complete
2291 if (rs
->hdr_bytes
== sizeof(ipc_msg_hdr
))
2293 if (rs
->hdr
.datalen
== 0) // ok in removerecord requests
2295 rs
->ts
= t_complete
;
2300 if (!rs
->msgbuf
) // allocate the buffer first time through
2302 rs
->msgbuf
= mallocL("read_msg", rs
->hdr
.datalen
+ MSG_PAD_BYTES
);
2305 my_perror("ERROR: malloc");
2309 rs
->msgdata
= rs
->msgbuf
;
2311 bzero(rs
->msgbuf
, rs
->hdr
.datalen
+ MSG_PAD_BYTES
);
2312 nleft
= rs
->hdr
.datalen
- rs
->data_bytes
;
2313 nread
= recv(rs
->sd
, rs
->msgbuf
+ rs
->data_bytes
, nleft
, 0);
2314 if (nread
== 0) { rs
->ts
= t_terminated
; return t_terminated
; }
2315 if (nread
< 0) goto rerror
;
2316 rs
->data_bytes
+= nread
;
2317 if (rs
->data_bytes
> rs
->hdr
.datalen
)
2319 LogMsg("ERROR: read_msg - read too many data bytes");
2325 if (rs
->hdr_bytes
== sizeof(ipc_msg_hdr
) && rs
->data_bytes
== rs
->hdr
.datalen
)
2326 rs
->ts
= t_complete
;
2327 else rs
->ts
= t_morecoming
;
2332 if (errno
== EAGAIN
|| errno
== EINTR
) return rs
->ts
;
2333 my_perror("ERROR: read_msg");
2339 static int send_msg(reply_state
*rs
)
2345 LogMsg("ERROR: send_msg called with NULL message buffer");
2349 if (rs
->request
->no_reply
) //!!!KRS this behavior should be optimized if it becomes more common
2351 rs
->ts
= t_complete
;
2352 freeL("send_msg", rs
->msgbuf
);
2356 nwriten
= send(rs
->sd
, rs
->msgbuf
+ rs
->nwriten
, rs
->len
- rs
->nwriten
, 0);
2359 if (errno
== EINTR
|| errno
== EAGAIN
) nwriten
= 0;
2364 LogMsg("broken pipe - cleanup should be handled by run-loop read wakeup");
2365 rs
->ts
= t_terminated
;
2366 rs
->request
->ts
= t_terminated
;
2367 return t_terminated
;
2371 my_perror("ERROR: send\n");
2377 rs
->nwriten
+= nwriten
;
2379 if (rs
->nwriten
== rs
->len
)
2381 rs
->ts
= t_complete
;
2382 freeL("send_msg", rs
->msgbuf
);
2389 static reply_state
*create_reply(reply_op_t op
, int datalen
, request_state
*request
)
2395 if ((unsigned)datalen
< sizeof(reply_hdr
))
2397 LogMsg("ERROR: create_reply - data length less than lenght of required fields");
2401 totallen
= datalen
+ sizeof(ipc_msg_hdr
);
2402 reply
= mallocL("create_reply", sizeof(reply_state
));
2405 my_perror("ERROR: malloc");
2408 bzero(reply
, sizeof(reply_state
));
2409 reply
->ts
= t_morecoming
;
2410 reply
->sd
= request
->sd
;
2411 reply
->request
= request
;
2412 reply
->len
= totallen
;
2413 reply
->msgbuf
= mallocL("create_reply", totallen
);
2416 my_perror("ERROR: malloc");
2419 bzero(reply
->msgbuf
, totallen
);
2420 reply
->mhdr
= (ipc_msg_hdr
*)reply
->msgbuf
;
2421 reply
->rhdr
= (reply_hdr
*)(reply
->msgbuf
+ sizeof(ipc_msg_hdr
));
2422 reply
->sdata
= reply
->msgbuf
+ sizeof(ipc_msg_hdr
) + sizeof(reply_hdr
);
2423 reply
->mhdr
->version
= VERSION
;
2424 reply
->mhdr
->op
.reply_op
= op
;
2425 reply
->mhdr
->datalen
= totallen
- sizeof(ipc_msg_hdr
);
2430 static int deliver_error(request_state
*rstate
, mStatus err
)
2433 undelivered_error_t
*undeliv
;
2435 nwritten
= send(rstate
->errfd
, &err
, sizeof(mStatus
), 0);
2436 if (nwritten
< (int)sizeof(mStatus
))
2438 if (errno
== EINTR
|| errno
== EAGAIN
)
2442 my_perror("ERROR: send - unable to deliver error to client");
2445 //client blocked - store result and come backr
2446 undeliv
= mallocL("deliver_error", sizeof(undelivered_error_t
));
2449 my_perror("ERROR: malloc");
2453 undeliv
->nwritten
= nwritten
;
2454 undeliv
->sd
= rstate
->errfd
;
2455 rstate
->u_err
= undeliv
;
2458 if (rstate
->errfd
!= rstate
->sd
) close(rstate
->errfd
);
2462 if (rstate
->errfd
!= rstate
->sd
) close(rstate
->errfd
);
2468 // returns 0 on success, -1 if send is incomplete, or on terminal failre (request is aborted)
2469 static transfer_state
send_undelivered_error(request_state
*rs
)
2473 nwritten
= send(rs
->u_err
->sd
, (char *)(&rs
->u_err
) + rs
->u_err
->nwritten
, sizeof(mStatus
) - rs
->u_err
->nwritten
, 0);
2476 if (errno
== EINTR
|| errno
== EAGAIN
)
2480 my_perror("ERROR: send - unable to deliver error to client\n");
2481 if (rs
->u_err
->sd
== rs
->sd
) close (rs
->u_err
->sd
);
2485 if (nwritten
+ rs
->u_err
->nwritten
== sizeof(mStatus
))
2487 if (rs
->u_err
->sd
== rs
->sd
) close(rs
->u_err
->sd
);
2488 freeL("send_undelivered_error", rs
->u_err
);
2492 rs
->u_err
->nwritten
+= nwritten
;
2493 return t_morecoming
;
2497 // send bogus data along with an error code to the app callback
2498 // returns 0 on success (linking reply into list of not fully delivered),
2499 // -1 on failure (request should be aborted)
2500 static int deliver_async_error(request_state
*rs
, reply_op_t op
, mStatus err
)
2506 if (rs
->no_reply
) return 0;
2507 len
= 256; // long enough for any reply handler to read all args w/o buffer overrun
2508 reply
= create_reply(op
, len
, rs
);
2509 reply
->rhdr
->error
= err
;
2510 ts
= send_msg(reply
);
2511 if (ts
== t_error
|| ts
== t_terminated
)
2513 freeL("deliver_async_error", reply
);
2516 else if (ts
== t_complete
) freeL("deliver_async_error", reply
);
2517 else if (ts
== t_morecoming
) append_reply(rs
, reply
); // client is blocked, link reply into list
2522 static void abort_request(request_state
*rs
)
2524 reply_state
*rep
, *ptr
;
2526 if (rs
->terminate
) rs
->terminate(rs
->termination_context
); // terminate field may not be set yet
2527 if (rs
->msgbuf
) freeL("abort_request", rs
->msgbuf
);
2528 udsSupportRemoveFDFromEventLoop(rs
->sd
);
2530 if (rs
->errfd
>= 0) close(rs
->errfd
);
2533 // free pending replies
2537 if (rep
->msgbuf
) freeL("abort_request", rep
->msgbuf
);
2540 freeL("abort_request", ptr
);
2545 freeL("abort_request", rs
->u_err
);
2551 static void unlink_request(request_state
*rs
)
2555 if (rs
== all_requests
)
2557 all_requests
= all_requests
->next
;
2558 freeL("unlink_request", rs
);
2561 for(ptr
= all_requests
; ptr
->next
; ptr
= ptr
->next
)
2562 if (ptr
->next
== rs
)
2564 ptr
->next
= rs
->next
;
2565 freeL("unlink_request", rs
);
2572 //hack to search-replace perror's to LogMsg's
2573 static void my_perror(char *errmsg
)
2575 LogMsg("%s: %s", errmsg
, strerror(errno
));
2578 // check that the message delivered by the client is sufficiently long to extract the required data from the buffer
2579 // without overrunning it.
2580 // returns 0 on success, -1 on error.
2582 static int validate_message(request_state
*rstate
)
2586 switch(rstate
->hdr
.op
.request_op
)
2588 case resolve_request
: min_size
= sizeof(DNSServiceFlags
) + // flags
2589 sizeof(uint32_t) + // interface
2590 (3 * sizeof(char)); // name, regtype, domain
2592 case query_request
: min_size
= sizeof(DNSServiceFlags
) + // flags
2593 sizeof(uint32_t) + // interface
2594 sizeof(char) + // fullname
2595 (2 * sizeof(uint16_t)); // type, class
2597 case browse_request
: min_size
= sizeof(DNSServiceFlags
) + // flags
2598 sizeof(uint32_t) + // interface
2599 (2 * sizeof(char)); // regtype, domain
2601 case reg_service_request
: min_size
= sizeof(DNSServiceFlags
) + // flags
2602 sizeof(uint32_t) + // interface
2603 (4 * sizeof(char)) + // name, type, domain, host
2604 (2 * sizeof(uint16_t)); // port, textlen
2606 case enumeration_request
: min_size
= sizeof(DNSServiceFlags
) + // flags
2607 sizeof(uint32_t); // interface
2609 case reg_record_request
: min_size
= sizeof(DNSServiceFlags
) + // flags
2610 sizeof(uint32_t) + // interface
2611 sizeof(char) + // fullname
2612 (3 * sizeof(uint16_t)) + // type, class, rdlen
2613 sizeof(uint32_t); // ttl
2615 case add_record_request
: min_size
= sizeof(DNSServiceFlags
) + // flags
2616 (2 * sizeof(uint16_t)) + // type, rdlen
2617 sizeof(uint32_t); // ttl
2619 case update_record_request
: min_size
= sizeof(DNSServiceFlags
) + // flags
2620 sizeof(uint16_t) + // rdlen
2621 sizeof(uint32_t); // ttl
2623 case remove_record_request
: min_size
= sizeof(DNSServiceFlags
); // flags
2625 case reconfirm_record_request
: min_size
=sizeof(DNSServiceFlags
) + // flags
2626 sizeof(uint32_t) + // interface
2627 sizeof(char) + // fullname
2628 (3 * sizeof(uint16_t)); // type, class, rdlen
2630 LogMsg("ERROR: validate_message - unsupported request type: %d", rstate
->hdr
.op
.request_op
);
2634 return (rstate
->data_bytes
>= min_size
? 0 : -1);