2 * Copyright (c) 2003 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
23 Change History (most recent first):
25 $Log: uds_daemon.c,v $
26 Revision 1.22.2.1 2003/12/05 00:03:35 cheshire
27 <rdar://problem/3487869> Use buffer size MAX_ESCAPED_DOMAIN_NAME instead of 256
29 Revision 1.22 2003/08/19 16:03:55 ksekar
30 Bug #: <rdar://problem/3380097>: ER: SIGINFO dump should include resolves started by DNSServiceQueryRecord
31 Check termination_context for NULL before dereferencing.
33 Revision 1.21 2003/08/19 05:39:43 cheshire
34 <rdar://problem/3380097> SIGINFO dump should include resolves started by DNSServiceQueryRecord
36 Revision 1.20 2003/08/16 03:39:01 cheshire
37 <rdar://problem/3338440> InterfaceID -1 indicates "local only"
39 Revision 1.19 2003/08/15 20:16:03 cheshire
40 <rdar://problem/3366590> mDNSResponder takes too much RPRVT
41 We want to avoid touching the rdata pages, so we don't page them in.
42 1. RDLength was stored with the rdata, which meant touching the page just to find the length.
43 Moved this from the RData to the ResourceRecord object.
44 2. To avoid unnecessarily touching the rdata just to compare it,
45 compute a hash of the rdata and store the hash in the ResourceRecord object.
47 Revision 1.18 2003/08/15 00:38:00 ksekar
48 Bug #: <rdar://problem/3377005>: Bug: buffer overrun when reading long rdata from client
50 Revision 1.17 2003/08/14 02:18:21 cheshire
51 <rdar://problem/3375491> Split generic ResourceRecord type into two separate types: AuthRecord and CacheRecord
53 Revision 1.16 2003/08/13 23:58:52 ksekar
54 Bug #: <rdar://problem/3374911>: Bug: UDS Sub-type browsing works, but not sub-type registration
55 Fixed pointer increment error, moved subtype reading for-loop for easier error bailout.
57 Revision 1.15 2003/08/13 17:30:33 ksekar
58 Bug #: <rdar://problem/3374671>: DNSServiceAddRecord doesn't work
59 Fixed various problems with handling the AddRecord request and freeing the ExtraResourceRecords.
61 Revision 1.14 2003/08/12 19:56:25 cheshire
66 #include "mDNSClientAPI.h"
67 #include "mDNSMacOSX.h"
69 #include "dnssd_ipc.h"
71 #include <sys/ioctl.h>
72 #include <sys/types.h>
74 #include <sys/resource.h>
76 // Types and Data Structures
77 // ----------------------------------------------------------------------
88 typedef void (*req_termination_fn
)(void *);
91 typedef struct registered_record_entry
95 struct registered_record_entry
*next
;
96 } registered_record_entry
;
98 typedef struct registered_service
100 //struct registered_service *next;
102 int renameonconflict
;
103 int rename_on_memfree
; // set flag on config change when we deregister original name
105 ServiceRecordSet
*srs
;
106 struct request_state
*request
;
107 AuthRecord
*subtypes
;
108 } registered_service
;
115 } undelivered_error_t
;
117 typedef struct request_state
119 // connection structures
120 CFRunLoopSourceRef rls
;
125 // state of read (in case message is read over several recv() calls)
127 uint32_t hdr_bytes
; // bytes of header already read
129 uint32_t data_bytes
; // bytes of message data already read
130 char *msgbuf
; // pointer to data storage to pass to free()
131 char *msgdata
; // pointer to data to be read from (may be modified)
132 int bufsize
; // size of data storage
134 // reply, termination, error, and client context info
135 int no_reply
; // don't send asynchronous replies to client
136 void *client_context
; // don't touch this - pointer only valid in client's addr space
137 struct reply_state
*replies
; // corresponding (active) reply list
138 undelivered_error_t
*u_err
;
139 void *termination_context
;
140 req_termination_fn terminate
;
142 //!!!KRS toss these pointers in a union
143 // registration context associated with this request (null if not applicable)
144 registered_record_entry
*reg_recs
; // muliple registrations for a connection-oriented request
145 registered_service
*service
; // service record set and flags
146 struct resolve_result_t
*resolve_results
;
148 struct request_state
*next
;
151 // struct physically sits between ipc message header and call-specific fields in the message buffer
154 DNSServiceFlags flags
;
156 DNSServiceErrorType error
;
160 typedef struct reply_state
162 // state of the transmission
167 // context of the reply
168 struct request_state
*request
; // the request that this answers
169 struct reply_state
*next
; // if there are multiple unsent replies
170 // pointer into message buffer - allows fields to be changed after message is formatted
173 char *sdata
; // pointer to start of call-specific data
174 // pointer to malloc'd buffer
179 // domain enumeration and resolv calls require 2 mDNSCore calls, so we need separate interconnected
180 // structures to handle callbacks
183 DNSQuestion question
;
184 mDNS_DomainType type
;
185 request_state
*rstate
;
192 request_state
*rstate
;
193 } enum_termination_t
;
197 DNSQuestion question
;
199 request_state
*rstate
;
206 request_state
*rstate
;
207 } resolve_termination_t
;
209 typedef struct resolve_result_t
211 const ResourceRecord
*txt
;
212 const ResourceRecord
*srv
;
217 request_state
*rstate
;
218 client_context_t client_context
;
219 } regrecord_callback_context
;
225 static int listenfd
= -1;
226 static request_state
*all_requests
= NULL
;
227 //!!!KRS we should keep a separate list containing only the requests that need to be examined
228 //in the idle() routine.
231 #define MAX_OPENFILES 1024
234 // private function prototypes
235 static void connect_callback(CFSocketRef sr
, CFSocketCallBackType t
, CFDataRef dr
, const void *c
, void *i
);
236 static int read_msg(request_state
*rs
);
237 static int send_msg(reply_state
*rs
);
238 static void abort_request(request_state
*rs
);
239 static void request_callback(CFSocketRef sr
, CFSocketCallBackType t
, CFDataRef dr
, const void *c
, void *i
);
240 static void handle_resolve_request(request_state
*rstate
);
241 static void question_result_callback(mDNS
*const m
, DNSQuestion
*question
, const ResourceRecord
*const answer
, mDNSBool AddRecord
);
242 static void question_termination_callback(void *context
);
243 static void handle_browse_request(request_state
*request
);
244 static void browse_termination_callback(void *context
);
245 static void browse_result_callback(mDNS
*const m
, DNSQuestion
*question
, const ResourceRecord
*const answer
, mDNSBool AddRecord
);
246 static void handle_regservice_request(request_state
*request
);
247 static void regservice_termination_callback(void *context
);
248 static void process_service_registration(ServiceRecordSet
*const srs
);
249 static void regservice_callback(mDNS
*const m
, ServiceRecordSet
*const srs
, mStatus result
);
250 static void handle_add_request(request_state
*rstate
);
251 static void handle_update_request(request_state
*rstate
);
252 static mStatus
gen_rr_response(domainname
*servicename
, mDNSInterfaceID id
, request_state
*request
, reply_state
**rep
);
253 static void append_reply(request_state
*req
, reply_state
*rep
);
254 static int build_domainname_from_strings(domainname
*srv
, char *name
, char *regtype
, char *domain
);
255 static void enum_termination_callback(void *context
);
256 static void enum_result_callback(mDNS
*const m
, DNSQuestion
*question
, const ResourceRecord
*const answer
, mDNSBool AddRecord
);
257 static void handle_query_request(request_state
*rstate
);
258 static mStatus
do_question(request_state
*rstate
, domainname
*name
, uint32_t ifi
, uint16_t rrtype
, int16_t rrclass
);
259 static reply_state
*format_enumeration_reply(request_state
*rstate
, char *domain
, DNSServiceFlags flags
, uint32_t ifi
, DNSServiceErrorType err
);
260 static void handle_enum_request(request_state
*rstate
);
261 static void handle_regrecord_request(request_state
*rstate
);
262 static void regrecord_callback(mDNS
*const m
, AuthRecord
*const rr
, mStatus result
);
263 static void connected_registration_termination(void *context
);
264 static void handle_reconfirm_request(request_state
*rstate
);
265 static AuthRecord
*read_rr_from_ipc_msg(char *msgbuf
, int ttl
);
266 static void handle_removerecord_request(request_state
*rstate
);
267 static void reset_connected_rstate(request_state
*rstate
);
268 static int deliver_error(request_state
*rstate
, mStatus err
);
269 static int deliver_async_error(request_state
*rs
, reply_op_t op
, mStatus err
);
270 static transfer_state
send_undelivered_error(request_state
*rs
);
271 static reply_state
*create_reply(reply_op_t op
, int datalen
, request_state
*request
);
272 static void update_callback(mDNS
*const m
, AuthRecord
*const rr
, RData
*oldrd
);
273 static void my_perror(char *errmsg
);
274 static void unlink_request(request_state
*rs
);
275 static void resolve_result_callback(mDNS
*const m
, DNSQuestion
*question
, const ResourceRecord
*const answer
, mDNSBool AddRecord
);
276 static void resolve_termination_callback(void *context
);
278 // initialization, setup/teardown functions
280 int udsserver_init(void)
283 struct sockaddr_un laddr
;
284 struct rlimit maxfds
;
286 if ((listenfd
= socket(AF_LOCAL
, SOCK_STREAM
, 0)) < 0)
288 unlink(MDNS_UDS_SERVERPATH
); //OK if this fails
289 bzero(&laddr
, sizeof(laddr
));
290 laddr
.sun_family
= AF_LOCAL
;
291 laddr
.sun_len
= sizeof(struct sockaddr_un
);
292 strcpy(laddr
.sun_path
, MDNS_UDS_SERVERPATH
);
294 if (bind(listenfd
, (struct sockaddr
*)&laddr
, sizeof(laddr
)) < 0)
298 if (fcntl(listenfd
, F_SETFL
, O_NONBLOCK
) < 0)
300 my_perror("ERROR: could not set listen socket to non-blocking mode");
303 listen(listenfd
, LISTENQ
);
306 // set maximum file descriptor to 1024
307 if (getrlimit(RLIMIT_NOFILE
, &maxfds
) < 0)
309 my_perror("ERROR: Unable to get file descriptor limit");
312 if (maxfds
.rlim_max
>= MAX_OPENFILES
&& maxfds
.rlim_cur
== maxfds
.rlim_max
)
314 // proper values already set
317 maxfds
.rlim_max
= MAX_OPENFILES
;
318 maxfds
.rlim_cur
= MAX_OPENFILES
;
319 if (setrlimit(RLIMIT_NOFILE
, &maxfds
) < 0)
320 my_perror("ERROR: Unable to set maximum file descriptor limit");
324 my_perror("ERROR: udsserver_init");
328 int udsserver_exit(void)
331 unlink(MDNS_UDS_SERVERPATH
);
336 // add the named socket as a runloop source
337 int udsserver_add_rl_source(void)
339 CFSocketContext context
= { 0, NULL
, NULL
, NULL
, NULL
};
340 CFSocketRef sr
= CFSocketCreateWithNative(kCFAllocatorDefault
, listenfd
, kCFSocketReadCallBack
, connect_callback
, &context
);
343 debugf("ERROR: udsserver_add_rl_source - CFSocketCreateWithNative");
346 CFRunLoopSourceRef rls
= CFSocketCreateRunLoopSource(kCFAllocatorDefault
, sr
, 0);
350 debugf("ERROR: udsserver_add_rl_source - CFSocketCreateRunLoopSource");
353 CFRunLoopAddSource(CFRunLoopGetCurrent(), rls
, kCFRunLoopDefaultMode
);
357 mDNSs32
udsserver_idle(mDNSs32 nextevent
)
359 request_state
*req
= all_requests
, *tmp
, *prev
= NULL
;
361 transfer_state result
;
362 mDNSs32 now
= mDNSPlatformTimeNow();
367 result
= t_uninitialized
;
369 result
= send_undelivered_error(req
);
370 if (result
!= t_error
&& result
!= t_morecoming
&& // don't try to send msg if send_error failed
371 (req
->ts
== t_complete
|| req
->ts
== t_morecoming
))
375 if (req
->replies
->next
) req
->replies
->rhdr
->flags
|= kDNSServiceFlagsMoreComing
;
376 else req
->replies
->rhdr
->flags
|= kDNSServiceFlagsFinished
;
377 result
= send_msg(req
->replies
);
378 if (result
== t_complete
)
381 req
->replies
= req
->replies
->next
;
382 freeL("udsserver_idle", fptr
);
384 else if (result
== t_terminated
|| result
== t_error
)
389 else if (result
== t_morecoming
) // client's queues are full, move to next
391 if (nextevent
- now
> mDNSPlatformOneSecond
)
392 nextevent
= now
+ mDNSPlatformOneSecond
;
393 break; // start where we left off in a second
397 if (result
== t_terminated
|| result
== t_error
)
398 //since we're already doing a list traversal, we unlink the request manunally instead of calling unlink_request()
401 if (prev
) prev
->next
= req
->next
;
402 if (req
== all_requests
) all_requests
= all_requests
->next
;
404 freeL("udsserver_idle", tmp
);
415 void udsserver_info(void)
418 for (req
= all_requests
; req
; req
=req
->next
)
420 void *t
= req
->termination_context
;
422 if (req
->terminate
== regservice_termination_callback
)
423 LogMsg("DNSServiceRegister %##s", ((registered_service
*) t
)->srs
->RR_SRV
.resrec
.name
.c
);
424 else if (req
->terminate
== browse_termination_callback
)
425 LogMsg("DNSServiceBrowse %##s", ((DNSQuestion
*) t
)->qname
.c
);
426 else if (req
->terminate
== resolve_termination_callback
)
427 LogMsg("DNSServiceResolve %##s", ((resolve_termination_t
*)t
)->srv
->question
.qname
.c
);
428 else if (req
->terminate
== question_termination_callback
)
429 LogMsg("DNSServiceQueryRecord %##s", ((DNSQuestion
*) t
)->qname
.c
);
430 else if (req
->terminate
== enum_termination_callback
)
431 LogMsg("DNSServiceEnumerateDomains %##s", ((enum_termination_t
*) t
)->all
->question
.qname
.c
);
435 void udsserver_handle_configchange(void)
437 registered_service
*srv
;
441 for (req
= all_requests
; req
; req
= req
->next
)
444 if (srv
->autoname
&& !SameDomainLabel(srv
->name
.c
, mDNSStorage
.nicelabel
.c
))
446 srv
->rename_on_memfree
= 1;
447 err
= mDNS_DeregisterService(&mDNSStorage
, srv
->srs
);
448 if (err
) LogMsg("ERROR: udsserver_handle_configchange: DeregisterService returned error %d. Continuing.", err
);
449 // error should never occur - safest to log and continue
457 // accept a connection on the named socket, adding the new descriptor to the runloop and passing the error
458 // descriptor to the client
459 static void connect_callback(CFSocketRef s
, CFSocketCallBackType t
, CFDataRef dr
, const void *c
, void *i
)
461 int sd
, clilen
, optval
;
462 struct sockaddr_un cliaddr
;
463 CFSocketContext context
= { 0, NULL
, NULL
, NULL
, NULL
};
464 request_state
*rstate
;
467 #pragma unused(s, t, dr, c, i)
469 clilen
= sizeof(cliaddr
);
470 sd
= accept(listenfd
, (struct sockaddr
*)&cliaddr
, &clilen
);
474 if (errno
== EWOULDBLOCK
) return;
475 my_perror("ERROR: accept");
479 if (setsockopt(sd
, SOL_SOCKET
, SO_NOSIGPIPE
, &optval
, sizeof(optval
)) < 0)
481 my_perror("ERROR: setsockopt - SOL_NOSIGPIPE - aborting client");
486 if (fcntl(sd
, F_SETFL
, O_NONBLOCK
) < 0)
488 my_perror("ERROR: could not set connected socket to non-blocking mode - aborting client");
494 // open a pipe to deliver error messages, pass descriptor to client
495 if (pipe(errpipe) < 0)
497 my_perror("ERROR: could not create pipe");
501 if (ioctl(sd, I_SENDFD, errpipe[0]) < 0)
503 my_perror("ERROR: could not pass pipe descriptor to client. Aborting client.\n");
507 if (fcntl(errpipe[1], F_SETFL, O_NONBLOCK) < 0)
509 my_perror("ERROR: could not set error pipe to non-blocking mode - aborting client");
516 // allocate a request_state struct that will live with the socket
517 rstate
= mallocL("connect_callback", sizeof(request_state
));
520 my_perror("ERROR: malloc");
523 bzero(rstate
, sizeof(request_state
));
524 rstate
->ts
= t_morecoming
;
526 //rstate->errfd = errpipe[1];
528 //now create CFSocket wrapper and add to run loop
529 context
.info
= rstate
;
530 rstate
->sr
= CFSocketCreateWithNative(kCFAllocatorDefault
, sd
, kCFSocketReadCallBack
, request_callback
, &context
);
533 debugf("ERROR: connect_callback - CFSocketCreateWithNative");
534 freeL("connect_callback", rstate
);
538 rstate
->rls
= CFSocketCreateRunLoopSource(kCFAllocatorDefault
, rstate
->sr
, 0);
541 debugf("ERROR: connect_callback - CFSocketCreateRunLoopSource");
542 CFSocketInvalidate(rstate
->sr
); // automatically closes socket
543 CFRelease(rstate
->sr
);
544 freeL("connect_callback", rstate
);
547 CFRunLoopAddSource(CFRunLoopGetCurrent(), rstate
->rls
, kCFRunLoopDefaultMode
);
548 if (!CFRunLoopContainsSource(CFRunLoopGetCurrent(), rstate
->rls
, kCFRunLoopDefaultMode
))
550 LogMsg("ERROR: connect_callback, CFRunLoopAddSource");
551 abort_request(rstate
);
554 rstate
->next
= all_requests
;
555 all_requests
= rstate
;
559 // main client request handling routine. reads request and calls the appropriate request-specific
561 static void request_callback(CFSocketRef sr
, CFSocketCallBackType t
, CFDataRef dr
, const void *context
, void *info
)
563 request_state
*rstate
= info
;
564 transfer_state result
;
565 struct sockaddr_un cliaddr
;
566 char ctrl_path
[MAX_CTLPATH
];
568 #pragma unused(sr, t, dr, context)
570 int native
= CFSocketGetNative(sr
);
571 if (native
!= rstate
->sd
)
573 LogMsg("ERROR: request_callback - CFSocket's native descriptor does not match rstate member descriptor.");
574 abort_request(rstate
);
575 unlink_request(rstate
);
579 result
= read_msg(rstate
);
580 if (result
== t_morecoming
)
584 if (result
== t_terminated
)
586 abort_request(rstate
);
587 unlink_request(rstate
);
590 if (result
== t_error
)
592 abort_request(rstate
);
593 unlink_request(rstate
);
597 if (rstate
->hdr
.version
!= VERSION
)
599 LogMsg("ERROR: client incompatible with daemon (client version = %d, "
600 "daemon version = %d)\n", rstate
->hdr
.version
, VERSION
);
601 abort_request(rstate
);
602 unlink_request(rstate
);
606 // check if client wants silent operation
607 if (rstate
->hdr
.flags
& IPC_FLAGS_NOREPLY
) rstate
->no_reply
= 1;
609 // check if primary socket is to be used for synchronous errors, else open new socket
610 if (rstate
->hdr
.flags
& IPC_FLAGS_REUSE_SOCKET
)
611 rstate
->errfd
= rstate
->sd
;
614 if ((rstate
->errfd
= socket(AF_LOCAL
, SOCK_STREAM
, 0)) < 0)
616 my_perror("ERROR: socket");
619 if (fcntl(rstate
->errfd
, F_SETFL
, O_NONBLOCK
) < 0)
621 my_perror("ERROR: could not set control socket to non-blocking mode");
622 abort_request(rstate
);
623 unlink_request(rstate
);
626 get_string(&rstate
->msgdata
, ctrl_path
, 256); // path is first element in message buffer
627 bzero(&cliaddr
, sizeof(cliaddr
));
628 cliaddr
.sun_family
= AF_LOCAL
;
629 strcpy(cliaddr
.sun_path
, ctrl_path
);
630 if (connect(rstate
->errfd
, (struct sockaddr
*)&cliaddr
, sizeof(cliaddr
)) < 0)
632 my_perror("ERROR: connect");
633 abort_request(rstate
);
634 unlink_request(rstate
);
641 switch(rstate
->hdr
.op
.request_op
)
643 case resolve_request
: handle_resolve_request(rstate
); break;
644 case query_request
: handle_query_request(rstate
); break;
645 case browse_request
: handle_browse_request(rstate
); break;
646 case reg_service_request
: handle_regservice_request(rstate
); break;
647 case enumeration_request
: handle_enum_request(rstate
); break;
648 case reg_record_request
: handle_regrecord_request(rstate
); break;
649 case add_record_request
: handle_add_request(rstate
); break;
650 case update_record_request
: handle_update_request(rstate
); break;
651 case remove_record_request
: handle_removerecord_request(rstate
); break;
652 case reconfirm_record_request
: handle_reconfirm_request(rstate
); break;
654 debugf("ERROR: udsserver_recv_request - unsupported request type: %d", rstate
->hdr
.op
.request_op
);
658 // mDNS operation functions. Each operation has 3 associated functions - a request handler that parses
659 // the client's request and makes the appropriate mDNSCore call, a result handler (passed as a callback
660 // to the mDNSCore routine) that sends results back to the client, and a termination routine that aborts
661 // the mDNSCore operation if the client dies or closes its socket.
664 // query and resolve calls have separate request handlers that parse the arguments from the client and
665 // massage the name parameters appropriately, but the rest of the operations (making the query call,
666 // delivering the result to the client, and termination) are identical.
668 static void handle_query_request(request_state
*rstate
)
670 DNSServiceFlags flags
;
671 uint32_t interfaceIndex
;
673 uint16_t rrtype
, rrclass
;
678 if (rstate
->ts
!= t_complete
)
680 LogMsg("ERROR: handle_query_request - transfer state != t_complete");
683 ptr
= rstate
->msgdata
;
686 LogMsg("ERROR: handle_query_request - NULL msgdata");
689 flags
= get_flags(&ptr
);
690 interfaceIndex
= get_long(&ptr
);
691 if (get_string(&ptr
, name
, 256) < 0) goto bad_param
;
692 rrtype
= get_short(&ptr
);
693 rrclass
= get_short(&ptr
);
694 if (!MakeDomainNameFromDNSNameString(&dname
, name
)) goto bad_param
;
695 result
= do_question(rstate
, &dname
, interfaceIndex
, rrtype
, rrclass
);
696 if (result
) rstate
->terminate
= NULL
;
697 if (deliver_error(rstate
, result
) < 0) goto error
;
701 deliver_error(rstate
, mStatus_BadParamErr
);
702 rstate
->terminate
= NULL
; // don't try to terminate insuccessful Core calls
704 abort_request(rstate
);
705 unlink_request(rstate
);
709 static void handle_resolve_request(request_state
*rstate
)
711 DNSServiceFlags flags
;
712 uint32_t interfaceIndex
;
713 char name
[256], regtype
[MAX_ESCAPED_DOMAIN_NAME
], domain
[MAX_ESCAPED_DOMAIN_NAME
];
714 char *ptr
; // message data pointer
716 resolve_t
*srv
, *txt
;
717 resolve_termination_t
*term
;
720 if (rstate
->ts
!= t_complete
)
722 LogMsg("ERROR: handle_resolve_request - transfer state != t_complete");
723 abort_request(rstate
);
724 unlink_request(rstate
);
728 // extract the data from the message
729 ptr
= rstate
->msgdata
;
732 LogMsg("ERROR: handle_resolve_request - NULL msgdata");
733 abort_request(rstate
);
734 unlink_request(rstate
);
737 flags
= get_flags(&ptr
);
738 interfaceIndex
= get_long(&ptr
);
739 mDNSInterfaceID InterfaceID
= mDNSPlatformInterfaceIDfromInterfaceIndex(&mDNSStorage
, interfaceIndex
);
740 if (interfaceIndex
&& !InterfaceID
) goto bad_param
;
741 if (get_string(&ptr
, name
, 256) < 0 ||
742 get_string(&ptr
, regtype
, MAX_ESCAPED_DOMAIN_NAME
) < 0 ||
743 get_string(&ptr
, domain
, MAX_ESCAPED_DOMAIN_NAME
) < 0)
746 // free memory in rstate since we don't need it anymore
747 freeL("handle_resolve_request", rstate
->msgbuf
);
748 rstate
->msgbuf
= NULL
;
750 if (build_domainname_from_strings(&fqdn
, name
, regtype
, domain
) < 0)
753 // allocate question wrapper structs
754 srv
= mallocL("handle_resolve_request", sizeof(resolve_t
));
755 txt
= mallocL("handle_resolve_request", sizeof(resolve_t
));
756 if (!srv
|| !txt
) goto malloc_error
;
757 srv
->qtype
= kDNSType_SRV
;
758 txt
->qtype
= kDNSType_TXT
;
759 srv
->rstate
= rstate
;
760 txt
->rstate
= rstate
;
763 srv
->question
.QuestionContext
= rstate
;
764 srv
->question
.QuestionCallback
= resolve_result_callback
;
765 memcpy(&srv
->question
.qname
, &fqdn
, MAX_DOMAIN_NAME
);
766 srv
->question
.qtype
= kDNSType_SRV
;
767 srv
->question
.qclass
= kDNSClass_IN
;
768 srv
->question
.InterfaceID
= InterfaceID
;
770 txt
->question
.QuestionContext
= rstate
;
771 txt
->question
.QuestionCallback
= resolve_result_callback
;
772 memcpy(&txt
->question
.qname
, &fqdn
, MAX_DOMAIN_NAME
);
773 txt
->question
.qtype
= kDNSType_TXT
;
774 txt
->question
.qclass
= kDNSClass_IN
;
775 txt
->question
.InterfaceID
= InterfaceID
;
777 // set up termination info
778 term
= mallocL("handle_resolve_request", sizeof(resolve_termination_t
));
779 if (!term
) goto malloc_error
;
782 term
->rstate
= rstate
;
783 rstate
->termination_context
= term
;
784 rstate
->terminate
= resolve_termination_callback
;
786 // set up reply wrapper struct (since answer will come via 2 callbacks)
787 rstate
->resolve_results
= mallocL("handle_resolve_response", sizeof(resolve_result_t
));
788 if (!rstate
->resolve_results
) goto malloc_error
;
789 bzero(rstate
->resolve_results
, sizeof(resolve_result_t
));
792 err
= mDNS_StartQuery(&mDNSStorage
, &srv
->question
);
793 if (!err
) err
= mDNS_StartQuery(&mDNSStorage
, &txt
->question
);
797 freeL("handle_resolve_request", txt
);
798 freeL("handle_resolve_request", srv
);
799 freeL("handle_resolve_request", term
);
800 freeL("handle_resolve_request", rstate
->resolve_results
);
801 rstate
->terminate
= NULL
; // prevent abort_request() from invoking termination callback
803 if (deliver_error(rstate
, err
) < 0 || err
)
805 abort_request(rstate
);
806 unlink_request(rstate
);
811 deliver_error(rstate
, mStatus_BadParamErr
);
812 abort_request(rstate
);
813 unlink_request(rstate
);
817 my_perror("ERROR: malloc");
821 static void resolve_termination_callback(void *context
)
823 resolve_termination_t
*term
= context
;
828 LogMsg("ERROR: resolve_termination_callback: double termination");
833 mDNS_StopQuery(&mDNSStorage
, &term
->txt
->question
);
834 mDNS_StopQuery(&mDNSStorage
, &term
->srv
->question
);
836 freeL("resolve_termination_callback", term
->txt
);
837 freeL("resolve_termination_callback", term
->srv
);
838 freeL("resolve_termination_callback", term
);
839 rs
->termination_context
= NULL
;
840 freeL("resolve_termination_callback", rs
->resolve_results
);
841 rs
->resolve_results
= NULL
;
846 static void resolve_result_callback(mDNS
*const m
, DNSQuestion
*question
, const ResourceRecord
*const answer
, mDNSBool AddRecord
)
849 char fullname
[MAX_ESCAPED_DOMAIN_NAME
], target
[MAX_ESCAPED_DOMAIN_NAME
];
851 transfer_state result
;
853 request_state
*rs
= question
->QuestionContext
;
854 resolve_result_t
*res
= rs
->resolve_results
;
859 if (answer
->rrtype
== kDNSType_TXT
&& res
->txt
== answer
) res
->txt
= mDNSNULL
;
860 if (answer
->rrtype
== kDNSType_SRV
&& res
->srv
== answer
) res
->srv
= mDNSNULL
;
864 if (answer
->rrtype
== kDNSType_TXT
) res
->txt
= answer
;
865 if (answer
->rrtype
== kDNSType_SRV
) res
->srv
= answer
;
867 if (!res
->txt
|| !res
->srv
) return; // only deliver result to client if we have both answers
869 ConvertDomainNameToCString(&answer
->name
, fullname
);
870 ConvertDomainNameToCString(&res
->srv
->rdata
->u
.srv
.target
, target
);
872 // calculate reply length
873 len
+= sizeof(DNSServiceFlags
);
874 len
+= sizeof(uint32_t); // interface index
875 len
+= sizeof(DNSServiceErrorType
);
876 len
+= strlen(fullname
) + 1;
877 len
+= strlen(target
) + 1;
878 len
+= 2 * sizeof(uint16_t); // port, txtLen
879 len
+= res
->txt
->rdlength
;
881 // allocate/init reply header
882 rep
= create_reply(resolve_reply
, len
, rs
);
883 rep
->rhdr
->flags
= 0;
884 rep
->rhdr
->ifi
= mDNSPlatformInterfaceIndexfromInterfaceID(&mDNSStorage
, answer
->InterfaceID
);
885 rep
->rhdr
->error
= kDNSServiceErr_NoError
;
888 // write reply data to message
889 put_string(fullname
, &data
);
890 put_string(target
, &data
);
891 put_short(res
->srv
->rdata
->u
.srv
.port
.NotAnInteger
, &data
);
892 put_short(res
->txt
->rdlength
, &data
);
893 put_rdata(res
->txt
->rdlength
, res
->txt
->rdata
->u
.txt
.c
, &data
);
895 result
= send_msg(rep
);
896 if (result
== t_error
|| result
== t_terminated
)
900 freeL("resolve_result_callback", rep
);
902 else if (result
== t_complete
) freeL("resolve_result_callback", rep
);
903 else append_reply(rs
, rep
);
909 // common query issuing routine for resolve and query requests
910 static mStatus
do_question(request_state
*rstate
, domainname
*name
, uint32_t ifi
, uint16_t rrtype
, int16_t rrclass
)
914 mDNSInterfaceID InterfaceID
= mDNSPlatformInterfaceIDfromInterfaceIndex(&mDNSStorage
, ifi
);
915 if (ifi
&& !InterfaceID
) return(mStatus_BadParamErr
);
917 q
= mallocL("do_question", sizeof(DNSQuestion
));
920 my_perror("ERROR: do_question - malloc");
923 bzero(q
, sizeof(DNSQuestion
));
925 q
->QuestionContext
= rstate
;
926 q
->QuestionCallback
= question_result_callback
;
927 memcpy(&q
->qname
, name
, MAX_DOMAIN_NAME
);
930 q
->InterfaceID
= InterfaceID
;
933 rstate
->termination_context
= q
;
934 rstate
->terminate
= question_termination_callback
;
936 result
= mDNS_StartQuery(&mDNSStorage
, q
);
937 if (result
!= mStatus_NoError
) LogMsg("ERROR: mDNS_StartQuery: %d", (int)result
);
941 // what gets called when a resolve is completed and we need to send the data back to the client
942 static void question_result_callback(mDNS
*const m
, DNSQuestion
*question
, const ResourceRecord
*const answer
, mDNSBool AddRecord
)
945 char name
[MAX_ESCAPED_DOMAIN_NAME
];
951 //mDNS_StopQuery(m, question);
952 req
= question
->QuestionContext
;
954 // calculate reply data length
955 len
= sizeof(DNSServiceFlags
);
956 len
+= 2 * sizeof(uint32_t); // if index + ttl
957 len
+= sizeof(DNSServiceErrorType
);
958 len
+= 3 * sizeof(uint16_t); // type, class, rdlen
959 len
+= answer
->rdlength
;
960 ConvertDomainNameToCString(&answer
->name
, name
);
961 len
+= strlen(name
) + 1;
963 rep
= create_reply(query_reply
, len
, req
);
964 rep
->rhdr
->flags
= AddRecord
? kDNSServiceFlagsAdd
: kDNSServiceFlagsRemove
;
965 rep
->rhdr
->ifi
= mDNSPlatformInterfaceIndexfromInterfaceID(&mDNSStorage
, answer
->InterfaceID
);
966 rep
->rhdr
->error
= kDNSServiceErr_NoError
;
969 put_string(name
, &data
);
970 put_short(answer
->rrtype
, &data
);
971 put_short(answer
->rrclass
, &data
);
972 put_short(answer
->rdlength
, &data
);
973 put_rdata(answer
->rdlength
, (char *)&answer
->rdata
->u
, &data
);
974 put_long(AddRecord
? answer
->rroriginalttl
: 0, &data
);
976 append_reply(req
, rep
);
980 static void question_termination_callback(void *context
)
982 DNSQuestion
*q
= context
;
985 mDNS_StopQuery(&mDNSStorage
, q
); // no need to error check
986 freeL("question_termination_callback", q
);
990 static void handle_browse_request(request_state
*request
)
992 DNSServiceFlags flags
;
993 uint32_t interfaceIndex
;
994 char regtype
[MAX_ESCAPED_DOMAIN_NAME
], domain
[MAX_ESCAPED_DOMAIN_NAME
];
996 domainname typedn
, domdn
;
1000 if (request
->ts
!= t_complete
)
1002 LogMsg("ERROR: handle_browse_request - transfer state != t_complete");
1003 abort_request(request
);
1004 unlink_request(request
);
1007 q
= mallocL("handle_browse_request", sizeof(DNSQuestion
));
1010 my_perror("ERROR: handle_browse_request - malloc");
1013 bzero(q
, sizeof(DNSQuestion
));
1015 // extract data from message
1016 ptr
= request
->msgdata
;
1017 flags
= get_flags(&ptr
);
1018 interfaceIndex
= get_long(&ptr
);
1019 if (get_string(&ptr
, regtype
, MAX_ESCAPED_DOMAIN_NAME
) < 0 ||
1020 get_string(&ptr
, domain
, MAX_ESCAPED_DOMAIN_NAME
) < 0)
1023 freeL("handle_browse_request", request
->msgbuf
);
1024 request
->msgbuf
= NULL
;
1026 mDNSInterfaceID InterfaceID
= mDNSPlatformInterfaceIDfromInterfaceIndex(&mDNSStorage
, interfaceIndex
);
1027 if (interfaceIndex
&& !InterfaceID
) goto bad_param
;
1028 q
->QuestionContext
= request
;
1029 q
->QuestionCallback
= browse_result_callback
;
1030 if (!MakeDomainNameFromDNSNameString(&typedn
, regtype
) ||
1031 !MakeDomainNameFromDNSNameString(&domdn
, domain
[0] ? domain
: "local."))
1033 request
->termination_context
= q
;
1034 request
->terminate
= browse_termination_callback
;
1035 result
= mDNS_StartBrowse(&mDNSStorage
, q
, &typedn
, &domdn
, InterfaceID
, browse_result_callback
, request
);
1036 deliver_error(request
, result
);
1040 deliver_error(request
, mStatus_BadParamErr
);
1041 abort_request(request
);
1042 unlink_request(request
);
1045 static void browse_result_callback(mDNS
*const m
, DNSQuestion
*question
, const ResourceRecord
*const answer
, mDNSBool AddRecord
)
1052 req
= question
->QuestionContext
;
1054 err
= gen_rr_response(&answer
->rdata
->u
.name
, answer
->InterfaceID
, req
, &rep
);
1057 if (deliver_async_error(req
, browse_reply
, err
) < 0)
1060 unlink_request(req
);
1064 if (AddRecord
) rep
->rhdr
->flags
|= kDNSServiceFlagsAdd
; // non-zero TTL indicates add
1065 append_reply(req
, rep
);
1069 static void browse_termination_callback(void *context
)
1071 DNSQuestion
*q
= context
;
1073 mDNS_StopBrowse(&mDNSStorage
, q
); // no need to error-check result
1074 freeL("browse_termination_callback", q
);
1077 // service registration
1078 static void handle_regservice_request(request_state
*request
)
1080 DNSServiceFlags flags
;
1082 char name
[256], regtype
[MAX_ESCAPED_DOMAIN_NAME
], domain
[MAX_ESCAPED_DOMAIN_NAME
], host
[MAX_ESCAPED_DOMAIN_NAME
];
1088 domainname t
, d
, h
, srv
;
1089 registered_service
*r_srv
;
1093 char *sub
, *rtype_ptr
;
1094 int i
, num_subtypes
;
1097 if (request
->ts
!= t_complete
)
1099 LogMsg("ERROR: handle_regservice_request - transfer state != t_complete");
1100 abort_request(request
);
1101 unlink_request(request
);
1105 // extract data from message
1106 ptr
= request
->msgdata
;
1107 flags
= get_flags(&ptr
);
1108 ifi
= get_long(&ptr
);
1109 mDNSInterfaceID InterfaceID
= mDNSPlatformInterfaceIDfromInterfaceIndex(&mDNSStorage
, ifi
);
1110 if (ifi
&& !InterfaceID
) goto bad_param
;
1111 if (get_string(&ptr
, name
, 256) < 0 ||
1112 get_string(&ptr
, regtype
, MAX_ESCAPED_DOMAIN_NAME
) < 0 ||
1113 get_string(&ptr
, domain
, MAX_ESCAPED_DOMAIN_NAME
) < 0 ||
1114 get_string(&ptr
, host
, MAX_ESCAPED_DOMAIN_NAME
) < 0)
1117 port
.NotAnInteger
= get_short(&ptr
);
1118 txtlen
= get_short(&ptr
);
1119 txtdata
= get_rdata(&ptr
, txtlen
);
1121 // count subtypes, replacing commas w/ whitespace
1122 rtype_ptr
= regtype
;
1124 while((sub
= strsep(&rtype_ptr
, ",")))
1125 if (*sub
) num_subtypes
++;
1127 if (!name
[0]) n
= (&mDNSStorage
)->nicelabel
;
1128 else if (!MakeDomainLabelFromLiteralString(&n
, name
))
1130 if ((!regtype
[0] || !MakeDomainNameFromDNSNameString(&t
, regtype
)) ||
1131 (!MakeDomainNameFromDNSNameString(&d
, *domain
? domain
: "local.")) ||
1132 (!ConstructServiceName(&srv
, &n
, &t
, &d
)))
1134 if (host
[0] && !MakeDomainNameFromDNSNameString(&h
, host
)) goto bad_param
;
1136 r_srv
= mallocL("handle_regservice_request", sizeof(registered_service
));
1137 if (!r_srv
) goto malloc_error
;
1138 srs_size
= sizeof(ServiceRecordSet
) + (sizeof(RDataBody
) > txtlen
? 0 : txtlen
- sizeof(RDataBody
));
1139 r_srv
->srs
= mallocL("handle_regservice_request", srs_size
);
1140 if (!r_srv
->srs
) goto malloc_error
;
1141 if (num_subtypes
> 0)
1143 r_srv
->subtypes
= mallocL("handle_regservice_request", num_subtypes
* sizeof(AuthRecord
));
1144 if (!r_srv
->subtypes
) goto malloc_error
;
1145 sub
= regtype
+ strlen(regtype
) + 1;
1146 for (i
= 0; i
< num_subtypes
; i
++)
1148 if (!MakeDomainNameFromDNSNameString(&(r_srv
->subtypes
+ i
)->resrec
.name
, sub
))
1150 freeL("handle_regservice_request", r_srv
->subtypes
);
1151 freeL("handle_regservice_request", r_srv
);
1155 sub
+= strlen(sub
) + 1;
1158 else r_srv
->subtypes
= NULL
;
1159 r_srv
->request
= request
;
1161 r_srv
->autoname
= (!name
[0]);
1162 r_srv
->rename_on_memfree
= 0;
1163 r_srv
->renameonconflict
= !(flags
& kDNSServiceFlagsNoAutoRename
);
1165 request
->termination_context
= r_srv
;
1166 request
->terminate
= regservice_termination_callback
;
1167 request
->service
= r_srv
;
1169 result
= mDNS_RegisterService(&mDNSStorage
, r_srv
->srs
, &n
, &t
, &d
, host
[0] ? &h
: NULL
, port
,
1170 txtdata
, txtlen
, r_srv
->subtypes
, num_subtypes
, InterfaceID
, regservice_callback
, r_srv
);
1171 deliver_error(request
, result
);
1172 if (result
!= mStatus_NoError
)
1174 abort_request(request
);
1175 unlink_request(request
);
1179 reset_connected_rstate(request
); // reset to receive add/remove messages
1184 deliver_error(request
, mStatus_BadParamErr
);
1185 abort_request(request
);
1186 unlink_request(request
);
1190 my_perror("ERROR: malloc");
1194 // service registration callback performs three duties - frees memory for deregistered services,
1195 // handles name conflicts, and delivers completed registration information to the client (via
1196 // process_service_registraion())
1198 static void regservice_callback(mDNS
*const m
, ServiceRecordSet
*const srs
, mStatus result
)
1201 ExtraResourceRecord
*extra
;
1202 registered_service
*r_srv
= srs
->ServiceContext
;
1203 request_state
*rs
= r_srv
->request
;
1207 if (!rs
&& (result
!= mStatus_MemFree
&& !r_srv
->rename_on_memfree
))
1209 // error should never happen - safest to log and continue
1210 LogMsg("ERROR: regservice_callback: received result %d with a NULL request pointer\n");
1214 if (result
== mStatus_NoError
)
1215 return process_service_registration(srs
);
1216 else if (result
== mStatus_MemFree
)
1218 if (r_srv
->rename_on_memfree
)
1220 r_srv
->rename_on_memfree
= 0;
1221 r_srv
->name
= mDNSStorage
.nicelabel
;
1222 err
= mDNS_RenameAndReregisterService(&mDNSStorage
, srs
, &r_srv
->name
);
1223 if (err
) LogMsg("ERROR: regservice_callback - RenameAndReregisterService returned %d", err
);
1224 // error should never happen - safest to log and continue
1228 while (r_srv
->srs
->Extras
)
1230 extra
= r_srv
->srs
->Extras
;
1231 r_srv
->srs
->Extras
= r_srv
->srs
->Extras
->next
;
1232 freeL("regservice_callback", extra
);
1234 freeL("regservice_callback", r_srv
->srs
);
1235 if (r_srv
->subtypes
) freeL("regservice_callback", r_srv
->subtypes
);
1236 if (r_srv
->request
) r_srv
->request
->service
= NULL
;
1237 freeL("regservice_callback", r_srv
);
1241 else if (result
== mStatus_NameConflict
)
1243 if (r_srv
->autoname
|| r_srv
->renameonconflict
)
1245 mDNS_RenameAndReregisterService(&mDNSStorage
, srs
, mDNSNULL
);
1250 freeL("regservice_callback", r_srv
);
1251 freeL("regservice_callback", r_srv
->srs
);
1252 if (r_srv
->subtypes
) freeL("regservice_callback", r_srv
->subtypes
);
1253 if (r_srv
->request
) r_srv
->request
->service
= NULL
;
1254 freeL("regservice_callback", r_srv
);
1255 if (deliver_async_error(rs
, reg_service_reply
, result
) < 0)
1265 LogMsg("ERROR: unknown result in regservice_callback");
1266 if (deliver_async_error(rs
, reg_service_reply
, result
) < 0)
1275 static void handle_add_request(request_state
*rstate
)
1277 registered_record_entry
*re
;
1278 ExtraResourceRecord
*extra
;
1280 uint16_t rrtype
, rdlen
;
1283 DNSServiceFlags flags
;
1284 ServiceRecordSet
*srs
= rstate
->service
->srs
;
1288 LogMsg("ERROR: handle_add_request - no service record set in request state");
1289 deliver_error(rstate
, mStatus_UnknownErr
);
1293 ptr
= rstate
->msgdata
;
1294 flags
= get_flags(&ptr
);
1295 rrtype
= get_short(&ptr
);
1296 rdlen
= get_short(&ptr
);
1297 rdata
= get_rdata(&ptr
, rdlen
);
1298 ttl
= get_long(&ptr
);
1300 if (rdlen
> sizeof(RDataBody
)) size
= rdlen
;
1301 else size
= sizeof(RDataBody
);
1303 extra
= mallocL("hanle_add_request", sizeof(ExtraResourceRecord
) - sizeof(RDataBody
) + size
);
1306 my_perror("ERROR: malloc");
1310 bzero(extra
, sizeof(ExtraResourceRecord
)); // OK if oversized rdata not zero'd
1311 extra
->r
.resrec
.rrtype
= rrtype
;
1312 extra
->r
.rdatastorage
.MaxRDLength
= size
;
1313 extra
->r
.resrec
.rdlength
= rdlen
;
1314 memcpy(&extra
->r
.rdatastorage
.u
.data
, rdata
, rdlen
);
1315 result
= mDNS_AddRecordToService(&mDNSStorage
, srs
, extra
, &extra
->r
.rdatastorage
, ttl
);
1316 deliver_error(rstate
, result
);
1317 reset_connected_rstate(rstate
);
1320 freeL("handle_add_request", rstate
->msgbuf
);
1321 rstate
->msgbuf
= NULL
;
1322 freeL("handle_add_request", extra
);
1325 re
= mallocL("handle_add_request", sizeof(registered_record_entry
));
1328 my_perror("ERROR: malloc");
1331 re
->key
= rstate
->hdr
.reg_index
;
1333 re
->next
= rstate
->reg_recs
;
1334 rstate
->reg_recs
= re
;
1337 static void handle_update_request(request_state
*rstate
)
1339 registered_record_entry
*reptr
;
1342 uint16_t rdlen
, rdsize
;
1347 if (rstate
->hdr
.reg_index
== TXT_RECORD_INDEX
)
1349 if (!rstate
->service
)
1351 deliver_error(rstate
, mStatus_BadParamErr
);
1354 rr
= &rstate
->service
->srs
->RR_TXT
;
1358 reptr
= rstate
->reg_recs
;
1359 while(reptr
&& reptr
->key
!= rstate
->hdr
.reg_index
) reptr
= reptr
->next
;
1360 if (!reptr
) deliver_error(rstate
, mStatus_BadReferenceErr
);
1364 ptr
= rstate
->msgdata
;
1365 get_flags(&ptr
); // flags unused
1366 rdlen
= get_short(&ptr
);
1367 rdata
= get_rdata(&ptr
, rdlen
);
1368 ttl
= get_long(&ptr
);
1370 if (rdlen
> sizeof(RDataBody
)) rdsize
= rdlen
;
1371 else rdsize
= sizeof(RDataBody
);
1372 newrd
= mallocL("handle_update_request", sizeof(RData
) - sizeof(RDataBody
) + rdsize
);
1375 my_perror("ERROR: malloc");
1378 newrd
->MaxRDLength
= rdsize
;
1379 memcpy(&newrd
->u
, rdata
, rdlen
);
1380 result
= mDNS_Update(&mDNSStorage
, rr
, ttl
, rdlen
, newrd
, update_callback
);
1381 deliver_error(rstate
, result
);
1382 reset_connected_rstate(rstate
);
1385 static void update_callback(mDNS
*const m
, AuthRecord
*const rr
, RData
*oldrd
)
1389 if (oldrd
!= &rr
->rdatastorage
) freeL("update_callback", oldrd
);
1392 static void process_service_registration(ServiceRecordSet
*const srs
)
1395 transfer_state send_result
;
1397 registered_service
*r_srv
= srs
->ServiceContext
;
1398 request_state
*req
= r_srv
->request
;
1401 err
= gen_rr_response(&srs
->RR_SRV
.resrec
.name
, srs
->RR_SRV
.resrec
.InterfaceID
, req
, &rep
);
1404 if (deliver_async_error(req
, reg_service_reply
, err
) < 0)
1407 unlink_request(req
);
1411 send_result
= send_msg(rep
);
1412 if (send_result
== t_error
|| send_result
== t_terminated
)
1415 unlink_request(req
);
1416 freeL("process_service_registration", rep
);
1418 else if (send_result
== t_complete
) freeL("process_service_registration", rep
);
1419 else append_reply(req
, rep
);
1422 static void regservice_termination_callback(void *context
)
1424 registered_service
*srv
= context
;
1426 // only safe to free memory if registration is not valid, ie deregister fails
1427 if (mDNS_DeregisterService(&mDNSStorage
, srv
->srs
) != mStatus_NoError
)
1429 freeL("regservice_callback", srv
->srs
);
1430 if (srv
->subtypes
) freeL("regservice_callback", srv
->subtypes
);
1431 freeL("regservice_callback", srv
);
1432 freeL("regservice_termination_callback", srv
);
1437 static void handle_regrecord_request(request_state
*rstate
)
1440 regrecord_callback_context
*rcc
;
1441 registered_record_entry
*re
;
1444 if (rstate
->ts
!= t_complete
)
1446 LogMsg("ERROR: handle_regrecord_request - transfer state != t_complete");
1447 abort_request(rstate
);
1448 unlink_request(rstate
);
1452 rr
= read_rr_from_ipc_msg(rstate
->msgdata
, 1);
1455 deliver_error(rstate
, mStatus_BadParamErr
);
1459 rcc
= mallocL("hanlde_regrecord_request", sizeof(regrecord_callback_context
));
1460 if (!rcc
) goto malloc_error
;
1461 rcc
->rstate
= rstate
;
1462 rcc
->client_context
= rstate
->hdr
.client_context
;
1463 rr
->RecordContext
= rcc
;
1464 rr
->RecordCallback
= regrecord_callback
;
1466 // allocate registration entry, link into list
1467 re
= mallocL("hanlde_regrecord_request", sizeof(registered_record_entry
));
1468 if (!re
) goto malloc_error
;
1469 re
->key
= rstate
->hdr
.reg_index
;
1471 re
->next
= rstate
->reg_recs
;
1472 rstate
->reg_recs
= re
;
1474 if (!rstate
->terminate
)
1476 rstate
->terminate
= connected_registration_termination
;
1477 rstate
->termination_context
= rstate
;
1480 result
= mDNS_Register(&mDNSStorage
, rr
);
1481 deliver_error(rstate
, result
);
1482 reset_connected_rstate(rstate
);
1486 my_perror("ERROR: malloc");
1490 static void regrecord_callback(mDNS
*const m
, AuthRecord
*const rr
, mStatus result
)
1492 regrecord_callback_context
*rcc
;
1499 if (result
== mStatus_MemFree
) { freeL("regrecord_callback", rr
); return; }
1500 rcc
= rr
->RecordContext
;
1502 // format result, add to the list for the request, including the client context in the header
1503 len
= sizeof(DNSServiceFlags
);
1504 len
+= sizeof(uint32_t); //interfaceIndex
1505 len
+= sizeof(DNSServiceErrorType
);
1507 reply
= create_reply(reg_record_reply
, len
, rcc
->rstate
);
1508 reply
->mhdr
->client_context
= rcc
->client_context
;
1509 reply
->rhdr
->flags
= 0;
1510 reply
->rhdr
->ifi
= mDNSPlatformInterfaceIndexfromInterfaceID(&mDNSStorage
, rr
->resrec
.InterfaceID
);
1511 reply
->rhdr
->error
= result
;
1513 ts
= send_msg(reply
);
1514 if (ts
== t_error
|| ts
== t_terminated
)
1516 abort_request(rcc
->rstate
);
1517 unlink_request(rcc
->rstate
);
1519 else if (ts
== t_complete
) freeL("regrecord_callback", reply
);
1520 else if (ts
== t_morecoming
) append_reply(rcc
->rstate
, reply
); // client is blocked, link reply into list
1523 static void connected_registration_termination(void *context
)
1525 registered_record_entry
*fptr
, *ptr
= ((request_state
*)context
)->reg_recs
;
1528 mDNS_Deregister(&mDNSStorage
, ptr
->rr
);
1531 freeL("connected_registration_termination", fptr
);
1537 static void handle_removerecord_request(request_state
*rstate
)
1539 registered_record_entry
*reptr
, *prev
= NULL
;
1540 mStatus err
= mStatus_UnknownErr
;
1542 reptr
= rstate
->reg_recs
;
1544 ptr
= rstate
->msgdata
;
1545 get_flags(&ptr
); // flags unused
1549 if (reptr
->key
== rstate
->hdr
.reg_index
) // found match
1551 if (prev
) prev
->next
= reptr
->next
;
1552 else rstate
->reg_recs
= reptr
->next
;
1553 err
= mDNS_Deregister(&mDNSStorage
, reptr
->rr
);
1554 freeL("handle_removerecord_request", reptr
); //rr gets freed by callback
1558 reptr
= reptr
->next
;
1560 reset_connected_rstate(rstate
);
1561 if (deliver_error(rstate
, err
) < 0)
1563 abort_request(rstate
);
1564 unlink_request(rstate
);
1569 // domain enumeration
1570 static void handle_enum_request(request_state
*rstate
)
1572 DNSServiceFlags flags
, add_default
;
1574 char *ptr
= rstate
->msgdata
;
1575 domain_enum_t
*def
, *all
;
1576 enum_termination_t
*term
;
1577 reply_state
*reply
; // initial default reply
1582 if (rstate
->ts
!= t_complete
)
1584 LogMsg("ERROR: handle_enum_request - transfer state != t_complete");
1585 abort_request(rstate
);
1586 unlink_request(rstate
);
1590 flags
= get_flags(&ptr
);
1591 ifi
= get_long(&ptr
);
1592 mDNSInterfaceID InterfaceID
= mDNSPlatformInterfaceIDfromInterfaceIndex(&mDNSStorage
, ifi
);
1593 if (ifi
&& !InterfaceID
)
1595 deliver_error(rstate
, mStatus_BadParamErr
);
1596 abort_request(rstate
);
1597 unlink_request(rstate
);
1600 // allocate context structures
1601 def
= mallocL("hanlde_enum_request", sizeof(domain_enum_t
));
1602 all
= mallocL("handle_enum_request", sizeof(domain_enum_t
));
1603 term
= mallocL("handle_enum_request", sizeof(enum_termination_t
));
1604 if (!def
|| !all
|| !term
)
1606 my_perror("ERROR: malloc");
1610 // enumeration requires multiple questions, so we must link all the context pointers so that
1611 // necessary context can be reached from the callbacks
1612 def
->rstate
= rstate
;
1613 all
->rstate
= rstate
;
1616 term
->rstate
= rstate
;
1617 rstate
->termination_context
= term
;
1618 rstate
->terminate
= enum_termination_callback
;
1619 def
->question
.QuestionContext
= def
;
1620 def
->type
= (flags
& kDNSServiceFlagsRegistrationDomains
) ?
1621 mDNS_DomainTypeRegistrationDefault
: mDNS_DomainTypeBrowseDefault
;
1622 all
->question
.QuestionContext
= all
;
1623 all
->type
= (flags
& kDNSServiceFlagsRegistrationDomains
) ?
1624 mDNS_DomainTypeRegistration
: mDNS_DomainTypeBrowse
;
1627 err
= mDNS_GetDomains(&mDNSStorage
, &all
->question
, all
->type
, InterfaceID
, enum_result_callback
, all
);
1628 if (err
== mStatus_NoError
)
1629 err
= mDNS_GetDomains(&mDNSStorage
, &def
->question
, def
->type
, InterfaceID
, enum_result_callback
, def
);
1630 result
= deliver_error(rstate
, err
); // send error *before* returning local domain
1632 if (result
< 0 || err
)
1634 abort_request(rstate
);
1635 unlink_request(rstate
);
1639 // provide local. as the first domain automatically
1640 add_default
= kDNSServiceFlagsDefault
| kDNSServiceFlagsAdd
| kDNSServiceFlagsFinished
;
1641 reply
= format_enumeration_reply(rstate
, "local.", add_default
, ifi
, 0);
1642 tr
= send_msg(reply
);
1643 if (tr
== t_error
|| tr
== t_terminated
)
1645 freeL("handle_enum_request", def
);
1646 freeL("handle_enum_request", all
);
1647 abort_request(rstate
);
1648 unlink_request(rstate
);
1651 if (tr
== t_complete
) freeL("handle_enum_request", reply
);
1652 if (tr
== t_morecoming
) append_reply(rstate
, reply
); // couldn't send whole reply because client is blocked - link into list
1655 static void enum_result_callback(mDNS
*const m
, DNSQuestion
*question
, const ResourceRecord
*const answer
, mDNSBool AddRecord
)
1657 char domain
[MAX_ESCAPED_DOMAIN_NAME
];
1658 domain_enum_t
*de
= question
->QuestionContext
;
1659 DNSServiceFlags flags
= 0;
1663 if (answer
->rrtype
!= kDNSType_PTR
) return;
1666 flags
|= kDNSServiceFlagsAdd
;
1667 if (de
->type
== mDNS_DomainTypeRegistrationDefault
|| de
->type
== mDNS_DomainTypeBrowseDefault
)
1668 flags
|= kDNSServiceFlagsDefault
;
1672 flags
|= kDNSServiceFlagsRemove
;
1674 ConvertDomainNameToCString(&answer
->rdata
->u
.name
, domain
);
1675 reply
= format_enumeration_reply(de
->rstate
, domain
, flags
, mDNSPlatformInterfaceIndexfromInterfaceID(&mDNSStorage
, answer
->InterfaceID
), kDNSServiceErr_NoError
);
1678 LogMsg("ERROR: enum_result_callback, format_enumeration_reply");
1682 append_reply(de
->rstate
, reply
);
1686 static reply_state
*format_enumeration_reply(request_state
*rstate
, char *domain
, DNSServiceFlags flags
, uint32_t ifi
, DNSServiceErrorType err
)
1693 len
= sizeof(DNSServiceFlags
);
1694 len
+= sizeof(uint32_t);
1695 len
+= sizeof(DNSServiceErrorType
);
1696 len
+= strlen(domain
) + 1;
1698 reply
= create_reply(enumeration_reply
, len
, rstate
);
1699 reply
->rhdr
->flags
= flags
;
1700 reply
->rhdr
->ifi
= ifi
;
1701 reply
->rhdr
->error
= err
;
1702 data
= reply
->sdata
;
1703 put_string(domain
, &data
);
1707 static void enum_termination_callback(void *context
)
1709 enum_termination_t
*t
= context
;
1710 mDNS
*coredata
= &mDNSStorage
;
1712 mDNS_StopGetDomains(coredata
, &t
->all
->question
);
1713 mDNS_StopGetDomains(coredata
, &t
->def
->question
);
1714 freeL("enum_termination_callback", t
->all
);
1715 freeL("enum_termination_callback", t
->def
);
1716 t
->rstate
->termination_context
= NULL
;
1717 freeL("enum_termination_callback", t
);
1720 static void handle_reconfirm_request(request_state
*rstate
)
1724 rr
= read_rr_from_ipc_msg(rstate
->msgdata
, 0);
1726 mDNS_ReconfirmByValue(&mDNSStorage
, &rr
->resrec
);
1727 abort_request(rstate
);
1728 unlink_request(rstate
);
1729 freeL("handle_reconfirm_request", rr
);
1733 // setup rstate to accept new reg/dereg requests
1734 static void reset_connected_rstate(request_state
*rstate
)
1736 rstate
->ts
= t_morecoming
;
1737 rstate
->hdr_bytes
= 0;
1738 rstate
->data_bytes
= 0;
1739 if (rstate
->msgbuf
) freeL("reset_connected_rstate", rstate
->msgbuf
);
1740 rstate
->msgbuf
= NULL
;
1741 rstate
->bufsize
= 0;
1746 // returns a resource record (allocated w/ malloc) containing the data found in an IPC message
1747 // data must be in format flags, interfaceIndex, name, rrtype, rrclass, rdlen, rdata, (optional)ttl
1748 // (ttl only extracted/set if ttl argument is non-zero). returns NULL for a bad-parameter error
1749 static AuthRecord
*read_rr_from_ipc_msg(char *msgbuf
, int ttl
)
1751 char *rdata
, name
[256];
1753 DNSServiceFlags flags
;
1754 uint32_t interfaceIndex
;
1755 uint16_t type
, class, rdlen
;
1758 flags
= get_flags(&msgbuf
);
1759 interfaceIndex
= get_long(&msgbuf
);
1760 if (get_string(&msgbuf
, name
, 256) < 0)
1762 LogMsg("ERROR: read_rr_from_ipc_msg - get_string");
1765 type
= get_short(&msgbuf
);
1766 class = get_short(&msgbuf
);
1767 rdlen
= get_short(&msgbuf
);
1769 if (rdlen
> sizeof(RDataBody
)) storage_size
= rdlen
;
1770 else storage_size
= sizeof(RDataBody
);
1772 rr
= mallocL("read_rr_from_ipc_msg", sizeof(AuthRecord
) - sizeof(RDataBody
) + storage_size
);
1775 my_perror("ERROR: malloc");
1778 bzero(rr
, sizeof(AuthRecord
)); // ok if oversized rdata not zero'd
1779 rr
->resrec
.rdata
= &rr
->rdatastorage
;
1780 rr
->resrec
.InterfaceID
= mDNSPlatformInterfaceIDfromInterfaceIndex(&mDNSStorage
, interfaceIndex
);
1781 if (!MakeDomainNameFromDNSNameString(&rr
->resrec
.name
, name
))
1783 LogMsg("ERROR: bad name: %s", name
);
1784 freeL("read_rr_from_ipc_msg", rr
);
1787 rr
->resrec
.rrtype
= type
;
1788 if ((flags
& kDNSServiceFlagsShared
) == kDNSServiceFlagsShared
)
1789 rr
->resrec
.RecordType
= kDNSRecordTypeShared
;
1790 if ((flags
& kDNSServiceFlagsUnique
) == kDNSServiceFlagsUnique
)
1791 rr
->resrec
.RecordType
= kDNSRecordTypeUnique
;
1792 rr
->resrec
.rrclass
= class;
1793 rr
->resrec
.rdlength
= rdlen
;
1794 rr
->resrec
.rdata
->MaxRDLength
= rdlen
;
1795 rdata
= get_rdata(&msgbuf
, rdlen
);
1796 memcpy(rr
->resrec
.rdata
->u
.data
, rdata
, rdlen
);
1799 rr
->resrec
.rroriginalttl
= get_long(&msgbuf
);
1805 // generate a response message for a browse result, service registration result, or any other call with the
1806 // identical callback signature. on successful completion rep is set to point to a malloc'd reply_state struct,
1807 // and mStatus_NoError is returned. otherwise the appropriate error is returned.
1809 static mStatus
gen_rr_response(domainname
*servicename
, mDNSInterfaceID id
, request_state
*request
, reply_state
**rep
)
1814 domainname type
, dom
;
1815 char namestr
[MAX_DOMAIN_LABEL
+1]; // Unescaped name: up to 63 bytes plus C-string terminating NULL.
1816 char typestr
[MAX_ESCAPED_DOMAIN_NAME
];
1817 char domstr
[MAX_ESCAPED_DOMAIN_NAME
];
1821 if (!DeconstructServiceName(servicename
, &name
, &type
, &dom
))
1822 return kDNSServiceErr_Unknown
;
1824 ConvertDomainLabelToCString_unescaped(&name
, namestr
);
1825 ConvertDomainNameToCString(&type
, typestr
);
1826 ConvertDomainNameToCString(&dom
, domstr
);
1828 // calculate reply data length
1829 len
= sizeof(DNSServiceFlags
);
1830 len
+= sizeof(uint32_t); // if index
1831 len
+= sizeof(DNSServiceErrorType
);
1832 len
+= strlen(namestr
) + 1;
1833 len
+= strlen(typestr
) + 1;
1834 len
+= strlen(domstr
) + 1;
1836 *rep
= create_reply(query_reply
, len
, request
);
1837 (*rep
)->rhdr
->flags
= 0;
1838 (*rep
)->rhdr
->ifi
= mDNSPlatformInterfaceIndexfromInterfaceID(&mDNSStorage
, id
);
1839 (*rep
)->rhdr
->error
= kDNSServiceErr_NoError
;
1840 data
= (*rep
)->sdata
;
1842 put_string(namestr
, &data
);
1843 put_string(typestr
, &data
);
1844 put_string(domstr
, &data
);
1845 return mStatus_NoError
;
1849 static int build_domainname_from_strings(domainname
*srv
, char *name
, char *regtype
, char *domain
)
1854 if (!MakeDomainLabelFromLiteralString(&n
, name
)) return -1;
1855 if (!MakeDomainNameFromDNSNameString(&t
, regtype
)) return -1;
1856 if (!MakeDomainNameFromDNSNameString(&d
, domain
)) return -1;
1857 if (!ConstructServiceName(srv
, &n
, &t
, &d
)) return -1;
1862 // append a reply to the list in a request object
1863 static void append_reply(request_state
*req
, reply_state
*rep
)
1867 if (!req
->replies
) req
->replies
= rep
;
1871 while (ptr
->next
) ptr
= ptr
->next
;
1878 // read_msg may be called any time when the transfer state (rs->ts) is t_morecoming.
1879 // returns the current state of the request (morecoming, error, complete, terminated.)
1880 // if there is no data on the socket, the socket will be closed and t_terminated will be returned
1881 static int read_msg(request_state
*rs
)
1885 char buf
[4]; // dummy for death notification
1887 if (rs
->ts
== t_terminated
|| rs
->ts
== t_error
)
1889 LogMsg("ERROR: read_msg called with transfer state terminated or error");
1894 if (rs
->ts
== t_complete
)
1895 { // this must be death or something is wrong
1896 nread
= recv(rs
->sd
, buf
, 4, 0);
1897 if (!nread
) { rs
->ts
= t_terminated
; return t_terminated
; }
1898 if (nread
< 0) goto rerror
;
1899 LogMsg("ERROR: read data from a completed request.");
1904 if (rs
->ts
!= t_morecoming
)
1906 LogMsg("ERROR: read_msg called with invalid transfer state (%d)", rs
->ts
);
1911 if (rs
->hdr_bytes
< sizeof(ipc_msg_hdr
))
1913 nleft
= sizeof(ipc_msg_hdr
) - rs
->hdr_bytes
;
1914 nread
= recv(rs
->sd
, (char *)&rs
->hdr
+ rs
->hdr_bytes
, nleft
, 0);
1915 if (nread
== 0) { rs
->ts
= t_terminated
; return t_terminated
; }
1916 if (nread
< 0) goto rerror
;
1917 rs
->hdr_bytes
+= nread
;
1918 if (rs
->hdr_bytes
> sizeof(ipc_msg_hdr
))
1920 LogMsg("ERROR: read_msg - read too many header bytes");
1926 // only read data if header is complete
1927 if (rs
->hdr_bytes
== sizeof(ipc_msg_hdr
))
1929 if (rs
->hdr
.datalen
== 0) // ok in removerecord requests
1931 rs
->ts
= t_complete
;
1936 if (!rs
->msgbuf
) // allocate the buffer first time through
1938 rs
->msgbuf
= mallocL("read_msg", rs
->hdr
.datalen
);
1941 my_perror("ERROR: malloc");
1945 rs
->msgdata
= rs
->msgbuf
;
1947 nleft
= rs
->hdr
.datalen
- rs
->data_bytes
;
1948 nread
= recv(rs
->sd
, rs
->msgbuf
+ rs
->data_bytes
, nleft
, 0);
1949 if (nread
== 0) { rs
->ts
= t_terminated
; return t_terminated
; }
1950 if (nread
< 0) goto rerror
;
1951 rs
->data_bytes
+= nread
;
1952 if (rs
->data_bytes
> rs
->hdr
.datalen
)
1954 LogMsg("ERROR: read_msg - read too many data bytes");
1960 if (rs
->hdr_bytes
== sizeof(ipc_msg_hdr
) && rs
->data_bytes
== rs
->hdr
.datalen
)
1961 rs
->ts
= t_complete
;
1962 else rs
->ts
= t_morecoming
;
1967 if (errno
== EAGAIN
|| errno
== EINTR
) return rs
->ts
;
1968 my_perror("ERROR: read_msg");
1974 static int send_msg(reply_state
*rs
)
1980 LogMsg("ERROR: send_msg called with NULL message buffer");
1984 if (rs
->request
->no_reply
) //!!!KRS this behavior should be optimized if it becomes more common
1986 rs
->ts
= t_complete
;
1987 freeL("send_msg", rs
->msgbuf
);
1991 nwriten
= send(rs
->sd
, rs
->msgbuf
+ rs
->nwriten
, rs
->len
- rs
->nwriten
, 0);
1994 if (errno
== EINTR
|| errno
== EAGAIN
) nwriten
= 0;
1999 LogMsg("broken pipe - cleanup should be handled by run-loop read wakeup");
2000 rs
->ts
= t_terminated
;
2001 rs
->request
->ts
= t_terminated
;
2002 return t_terminated
;
2006 my_perror("ERROR: send\n");
2012 rs
->nwriten
+= nwriten
;
2014 if (rs
->nwriten
== rs
->len
)
2016 rs
->ts
= t_complete
;
2017 freeL("send_msg", rs
->msgbuf
);
2024 static reply_state
*create_reply(reply_op_t op
, int datalen
, request_state
*request
)
2030 if ((unsigned)datalen
< sizeof(reply_hdr
))
2032 LogMsg("ERROR: create_reply - data length less than lenght of required fields");
2036 totallen
= datalen
+ sizeof(ipc_msg_hdr
);
2037 reply
= mallocL("create_reply", sizeof(reply_state
));
2040 my_perror("ERROR: malloc");
2043 bzero(reply
, sizeof(reply_state
));
2044 reply
->ts
= t_morecoming
;
2045 reply
->sd
= request
->sd
;
2046 reply
->request
= request
;
2047 reply
->len
= totallen
;
2048 reply
->msgbuf
= mallocL("create_reply", totallen
);
2051 my_perror("ERROR: malloc");
2054 bzero(reply
->msgbuf
, totallen
);
2055 reply
->mhdr
= (ipc_msg_hdr
*)reply
->msgbuf
;
2056 reply
->rhdr
= (reply_hdr
*)(reply
->msgbuf
+ sizeof(ipc_msg_hdr
));
2057 reply
->sdata
= reply
->msgbuf
+ sizeof(ipc_msg_hdr
) + sizeof(reply_hdr
);
2058 reply
->mhdr
->version
= VERSION
;
2059 reply
->mhdr
->op
.reply_op
= op
;
2060 reply
->mhdr
->datalen
= totallen
- sizeof(ipc_msg_hdr
);
2065 static int deliver_error(request_state
*rstate
, mStatus err
)
2068 undelivered_error_t
*undeliv
;
2070 nwritten
= send(rstate
->errfd
, &err
, sizeof(mStatus
), 0);
2071 if (nwritten
< (int)sizeof(mStatus
))
2073 if (errno
== EINTR
|| errno
== EAGAIN
)
2077 my_perror("ERROR: send - unable to deliver error to client");
2080 //client blocked - store result and come backr
2081 undeliv
= mallocL("deliver_error", sizeof(undelivered_error_t
));
2084 my_perror("ERROR: malloc");
2088 undeliv
->nwritten
= nwritten
;
2089 undeliv
->sd
= rstate
->errfd
;
2090 rstate
->u_err
= undeliv
;
2093 if (rstate
->errfd
!= rstate
->sd
) close(rstate
->errfd
);
2097 if (rstate
->errfd
!= rstate
->sd
) close(rstate
->errfd
);
2103 // returns 0 on success, -1 if send is incomplete, or on terminal failre (request is aborted)
2104 static transfer_state
send_undelivered_error(request_state
*rs
)
2108 nwritten
= send(rs
->u_err
->sd
, (char *)(&rs
->u_err
) + rs
->u_err
->nwritten
, sizeof(mStatus
) - rs
->u_err
->nwritten
, 0);
2111 if (errno
== EINTR
|| errno
== EAGAIN
)
2115 my_perror("ERROR: send - unable to deliver error to client\n");
2116 if (rs
->u_err
->sd
== rs
->sd
) close (rs
->u_err
->sd
);
2120 if (nwritten
+ rs
->u_err
->nwritten
== sizeof(mStatus
))
2122 if (rs
->u_err
->sd
== rs
->sd
) close(rs
->u_err
->sd
);
2123 freeL("send_undelivered_error", rs
->u_err
);
2127 rs
->u_err
->nwritten
+= nwritten
;
2128 return t_morecoming
;
2132 // send bogus data along with an error code to the app callback
2133 // returns 0 on success (linking reply into list of not fully delivered),
2134 // -1 on failure (request should be aborted)
2135 static int deliver_async_error(request_state
*rs
, reply_op_t op
, mStatus err
)
2141 if (rs
->no_reply
) return 0;
2142 len
= 256; // long enough for any reply handler to read all args w/o buffer overrun
2143 reply
= create_reply(op
, len
, rs
);
2144 reply
->rhdr
->error
= err
;
2145 ts
= send_msg(reply
);
2146 if (ts
== t_error
|| ts
== t_terminated
)
2148 freeL("deliver_async_error", reply
);
2151 else if (ts
== t_complete
) freeL("deliver_async_error", reply
);
2152 else if (ts
== t_morecoming
) append_reply(rs
, reply
); // client is blocked, link reply into list
2157 static void abort_request(request_state
*rs
)
2159 reply_state
*rep
, *ptr
;
2161 if (rs
->terminate
) rs
->terminate(rs
->termination_context
); // terminate field may not be set yet
2162 if (rs
->msgbuf
) freeL("abort_request", rs
->msgbuf
);
2163 CFRunLoopRemoveSource(CFRunLoopGetCurrent(), rs
->rls
, kCFRunLoopDefaultMode
);
2164 CFRunLoopSourceInvalidate(rs
->rls
);
2166 CFSocketInvalidate(rs
->sr
);
2169 if (rs
->errfd
>= 0) close(rs
->errfd
);
2172 // free pending replies
2176 if (rep
->msgbuf
) freeL("abort_request", rep
->msgbuf
);
2179 freeL("abort_request", ptr
);
2184 freeL("abort_request", rs
->u_err
);
2190 static void unlink_request(request_state
*rs
)
2194 if (rs
== all_requests
)
2196 all_requests
= all_requests
->next
;
2197 freeL("unlink_request", rs
);
2200 for(ptr
= all_requests
; ptr
->next
; ptr
= ptr
->next
)
2201 if (ptr
->next
== rs
)
2203 ptr
->next
= rs
->next
;
2204 freeL("unlink_request", rs
);
2211 //hack to search-replace perror's to LogMsg's
2212 static void my_perror(char *errmsg
)
2214 LogMsg("%s: %s", errmsg
, strerror(errno
));