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.22.2.1 2003/12/05 00:03:35 cheshire
29 <rdar://problem/3487869> Use buffer size MAX_ESCAPED_DOMAIN_NAME instead of 256
31 Revision 1.22 2003/08/19 16:03:55 ksekar
32 Bug #: <rdar://problem/3380097>: ER: SIGINFO dump should include resolves started by DNSServiceQueryRecord
33 Check termination_context for NULL before dereferencing.
35 Revision 1.21 2003/08/19 05:39:43 cheshire
36 <rdar://problem/3380097> SIGINFO dump should include resolves started by DNSServiceQueryRecord
38 Revision 1.20 2003/08/16 03:39:01 cheshire
39 <rdar://problem/3338440> InterfaceID -1 indicates "local only"
41 Revision 1.19 2003/08/15 20:16:03 cheshire
42 <rdar://problem/3366590> mDNSResponder takes too much RPRVT
43 We want to avoid touching the rdata pages, so we don't page them in.
44 1. RDLength was stored with the rdata, which meant touching the page just to find the length.
45 Moved this from the RData to the ResourceRecord object.
46 2. To avoid unnecessarily touching the rdata just to compare it,
47 compute a hash of the rdata and store the hash in the ResourceRecord object.
49 Revision 1.18 2003/08/15 00:38:00 ksekar
50 Bug #: <rdar://problem/3377005>: Bug: buffer overrun when reading long rdata from client
52 Revision 1.17 2003/08/14 02:18:21 cheshire
53 <rdar://problem/3375491> Split generic ResourceRecord type into two separate types: AuthRecord and CacheRecord
55 Revision 1.16 2003/08/13 23:58:52 ksekar
56 Bug #: <rdar://problem/3374911>: Bug: UDS Sub-type browsing works, but not sub-type registration
57 Fixed pointer increment error, moved subtype reading for-loop for easier error bailout.
59 Revision 1.15 2003/08/13 17:30:33 ksekar
60 Bug #: <rdar://problem/3374671>: DNSServiceAddRecord doesn't work
61 Fixed various problems with handling the AddRecord request and freeing the ExtraResourceRecords.
63 Revision 1.14 2003/08/12 19:56:25 cheshire
68 #include "mDNSClientAPI.h"
69 #include "mDNSMacOSX.h"
71 #include "dnssd_ipc.h"
73 #include <sys/ioctl.h>
74 #include <sys/types.h>
76 #include <sys/resource.h>
78 // Types and Data Structures
79 // ----------------------------------------------------------------------
90 typedef void (*req_termination_fn
)(void *);
93 typedef struct registered_record_entry
97 struct registered_record_entry
*next
;
98 } registered_record_entry
;
100 typedef struct registered_service
102 //struct registered_service *next;
104 int renameonconflict
;
105 int rename_on_memfree
; // set flag on config change when we deregister original name
107 ServiceRecordSet
*srs
;
108 struct request_state
*request
;
109 AuthRecord
*subtypes
;
110 } registered_service
;
117 } undelivered_error_t
;
119 typedef struct request_state
121 // connection structures
122 CFRunLoopSourceRef rls
;
127 // state of read (in case message is read over several recv() calls)
129 uint32_t hdr_bytes
; // bytes of header already read
131 uint32_t data_bytes
; // bytes of message data already read
132 char *msgbuf
; // pointer to data storage to pass to free()
133 char *msgdata
; // pointer to data to be read from (may be modified)
134 int bufsize
; // size of data storage
136 // reply, termination, error, and client context info
137 int no_reply
; // don't send asynchronous replies to client
138 void *client_context
; // don't touch this - pointer only valid in client's addr space
139 struct reply_state
*replies
; // corresponding (active) reply list
140 undelivered_error_t
*u_err
;
141 void *termination_context
;
142 req_termination_fn terminate
;
144 //!!!KRS toss these pointers in a union
145 // registration context associated with this request (null if not applicable)
146 registered_record_entry
*reg_recs
; // muliple registrations for a connection-oriented request
147 registered_service
*service
; // service record set and flags
148 struct resolve_result_t
*resolve_results
;
150 struct request_state
*next
;
153 // struct physically sits between ipc message header and call-specific fields in the message buffer
156 DNSServiceFlags flags
;
158 DNSServiceErrorType error
;
162 typedef struct reply_state
164 // state of the transmission
169 // context of the reply
170 struct request_state
*request
; // the request that this answers
171 struct reply_state
*next
; // if there are multiple unsent replies
172 // pointer into message buffer - allows fields to be changed after message is formatted
175 char *sdata
; // pointer to start of call-specific data
176 // pointer to malloc'd buffer
181 // domain enumeration and resolv calls require 2 mDNSCore calls, so we need separate interconnected
182 // structures to handle callbacks
185 DNSQuestion question
;
186 mDNS_DomainType type
;
187 request_state
*rstate
;
194 request_state
*rstate
;
195 } enum_termination_t
;
199 DNSQuestion question
;
201 request_state
*rstate
;
208 request_state
*rstate
;
209 } resolve_termination_t
;
211 typedef struct resolve_result_t
213 const ResourceRecord
*txt
;
214 const ResourceRecord
*srv
;
219 request_state
*rstate
;
220 client_context_t client_context
;
221 } regrecord_callback_context
;
227 static int listenfd
= -1;
228 static request_state
*all_requests
= NULL
;
229 //!!!KRS we should keep a separate list containing only the requests that need to be examined
230 //in the idle() routine.
233 #define MAX_OPENFILES 1024
236 // private function prototypes
237 static void connect_callback(CFSocketRef sr
, CFSocketCallBackType t
, CFDataRef dr
, const void *c
, void *i
);
238 static int read_msg(request_state
*rs
);
239 static int send_msg(reply_state
*rs
);
240 static void abort_request(request_state
*rs
);
241 static void request_callback(CFSocketRef sr
, CFSocketCallBackType t
, CFDataRef dr
, const void *c
, void *i
);
242 static void handle_resolve_request(request_state
*rstate
);
243 static void question_result_callback(mDNS
*const m
, DNSQuestion
*question
, const ResourceRecord
*const answer
, mDNSBool AddRecord
);
244 static void question_termination_callback(void *context
);
245 static void handle_browse_request(request_state
*request
);
246 static void browse_termination_callback(void *context
);
247 static void browse_result_callback(mDNS
*const m
, DNSQuestion
*question
, const ResourceRecord
*const answer
, mDNSBool AddRecord
);
248 static void handle_regservice_request(request_state
*request
);
249 static void regservice_termination_callback(void *context
);
250 static void process_service_registration(ServiceRecordSet
*const srs
);
251 static void regservice_callback(mDNS
*const m
, ServiceRecordSet
*const srs
, mStatus result
);
252 static void handle_add_request(request_state
*rstate
);
253 static void handle_update_request(request_state
*rstate
);
254 static mStatus
gen_rr_response(domainname
*servicename
, mDNSInterfaceID id
, request_state
*request
, reply_state
**rep
);
255 static void append_reply(request_state
*req
, reply_state
*rep
);
256 static int build_domainname_from_strings(domainname
*srv
, char *name
, char *regtype
, char *domain
);
257 static void enum_termination_callback(void *context
);
258 static void enum_result_callback(mDNS
*const m
, DNSQuestion
*question
, const ResourceRecord
*const answer
, mDNSBool AddRecord
);
259 static void handle_query_request(request_state
*rstate
);
260 static mStatus
do_question(request_state
*rstate
, domainname
*name
, uint32_t ifi
, uint16_t rrtype
, int16_t rrclass
);
261 static reply_state
*format_enumeration_reply(request_state
*rstate
, char *domain
, DNSServiceFlags flags
, uint32_t ifi
, DNSServiceErrorType err
);
262 static void handle_enum_request(request_state
*rstate
);
263 static void handle_regrecord_request(request_state
*rstate
);
264 static void regrecord_callback(mDNS
*const m
, AuthRecord
*const rr
, mStatus result
);
265 static void connected_registration_termination(void *context
);
266 static void handle_reconfirm_request(request_state
*rstate
);
267 static AuthRecord
*read_rr_from_ipc_msg(char *msgbuf
, int ttl
);
268 static void handle_removerecord_request(request_state
*rstate
);
269 static void reset_connected_rstate(request_state
*rstate
);
270 static int deliver_error(request_state
*rstate
, mStatus err
);
271 static int deliver_async_error(request_state
*rs
, reply_op_t op
, mStatus err
);
272 static transfer_state
send_undelivered_error(request_state
*rs
);
273 static reply_state
*create_reply(reply_op_t op
, int datalen
, request_state
*request
);
274 static void update_callback(mDNS
*const m
, AuthRecord
*const rr
, RData
*oldrd
);
275 static void my_perror(char *errmsg
);
276 static void unlink_request(request_state
*rs
);
277 static void resolve_result_callback(mDNS
*const m
, DNSQuestion
*question
, const ResourceRecord
*const answer
, mDNSBool AddRecord
);
278 static void resolve_termination_callback(void *context
);
280 // initialization, setup/teardown functions
282 int udsserver_init(void)
285 struct sockaddr_un laddr
;
286 struct rlimit maxfds
;
288 if ((listenfd
= socket(AF_LOCAL
, SOCK_STREAM
, 0)) < 0)
290 unlink(MDNS_UDS_SERVERPATH
); //OK if this fails
291 bzero(&laddr
, sizeof(laddr
));
292 laddr
.sun_family
= AF_LOCAL
;
293 laddr
.sun_len
= sizeof(struct sockaddr_un
);
294 strcpy(laddr
.sun_path
, MDNS_UDS_SERVERPATH
);
296 if (bind(listenfd
, (struct sockaddr
*)&laddr
, sizeof(laddr
)) < 0)
300 if (fcntl(listenfd
, F_SETFL
, O_NONBLOCK
) < 0)
302 my_perror("ERROR: could not set listen socket to non-blocking mode");
305 listen(listenfd
, LISTENQ
);
308 // set maximum file descriptor to 1024
309 if (getrlimit(RLIMIT_NOFILE
, &maxfds
) < 0)
311 my_perror("ERROR: Unable to get file descriptor limit");
314 if (maxfds
.rlim_max
>= MAX_OPENFILES
&& maxfds
.rlim_cur
== maxfds
.rlim_max
)
316 // proper values already set
319 maxfds
.rlim_max
= MAX_OPENFILES
;
320 maxfds
.rlim_cur
= MAX_OPENFILES
;
321 if (setrlimit(RLIMIT_NOFILE
, &maxfds
) < 0)
322 my_perror("ERROR: Unable to set maximum file descriptor limit");
326 my_perror("ERROR: udsserver_init");
330 int udsserver_exit(void)
333 unlink(MDNS_UDS_SERVERPATH
);
338 // add the named socket as a runloop source
339 int udsserver_add_rl_source(void)
341 CFSocketContext context
= { 0, NULL
, NULL
, NULL
, NULL
};
342 CFSocketRef sr
= CFSocketCreateWithNative(kCFAllocatorDefault
, listenfd
, kCFSocketReadCallBack
, connect_callback
, &context
);
345 debugf("ERROR: udsserver_add_rl_source - CFSocketCreateWithNative");
348 CFRunLoopSourceRef rls
= CFSocketCreateRunLoopSource(kCFAllocatorDefault
, sr
, 0);
352 debugf("ERROR: udsserver_add_rl_source - CFSocketCreateRunLoopSource");
355 CFRunLoopAddSource(CFRunLoopGetCurrent(), rls
, kCFRunLoopDefaultMode
);
359 mDNSs32
udsserver_idle(mDNSs32 nextevent
)
361 request_state
*req
= all_requests
, *tmp
, *prev
= NULL
;
363 transfer_state result
;
364 mDNSs32 now
= mDNSPlatformTimeNow();
369 result
= t_uninitialized
;
371 result
= send_undelivered_error(req
);
372 if (result
!= t_error
&& result
!= t_morecoming
&& // don't try to send msg if send_error failed
373 (req
->ts
== t_complete
|| req
->ts
== t_morecoming
))
377 if (req
->replies
->next
) req
->replies
->rhdr
->flags
|= kDNSServiceFlagsMoreComing
;
378 else req
->replies
->rhdr
->flags
|= kDNSServiceFlagsFinished
;
379 result
= send_msg(req
->replies
);
380 if (result
== t_complete
)
383 req
->replies
= req
->replies
->next
;
384 freeL("udsserver_idle", fptr
);
386 else if (result
== t_terminated
|| result
== t_error
)
391 else if (result
== t_morecoming
) // client's queues are full, move to next
393 if (nextevent
- now
> mDNSPlatformOneSecond
)
394 nextevent
= now
+ mDNSPlatformOneSecond
;
395 break; // start where we left off in a second
399 if (result
== t_terminated
|| result
== t_error
)
400 //since we're already doing a list traversal, we unlink the request manunally instead of calling unlink_request()
403 if (prev
) prev
->next
= req
->next
;
404 if (req
== all_requests
) all_requests
= all_requests
->next
;
406 freeL("udsserver_idle", tmp
);
417 void udsserver_info(void)
420 for (req
= all_requests
; req
; req
=req
->next
)
422 void *t
= req
->termination_context
;
424 if (req
->terminate
== regservice_termination_callback
)
425 LogMsg("DNSServiceRegister %##s", ((registered_service
*) t
)->srs
->RR_SRV
.resrec
.name
.c
);
426 else if (req
->terminate
== browse_termination_callback
)
427 LogMsg("DNSServiceBrowse %##s", ((DNSQuestion
*) t
)->qname
.c
);
428 else if (req
->terminate
== resolve_termination_callback
)
429 LogMsg("DNSServiceResolve %##s", ((resolve_termination_t
*)t
)->srv
->question
.qname
.c
);
430 else if (req
->terminate
== question_termination_callback
)
431 LogMsg("DNSServiceQueryRecord %##s", ((DNSQuestion
*) t
)->qname
.c
);
432 else if (req
->terminate
== enum_termination_callback
)
433 LogMsg("DNSServiceEnumerateDomains %##s", ((enum_termination_t
*) t
)->all
->question
.qname
.c
);
437 void udsserver_handle_configchange(void)
439 registered_service
*srv
;
443 for (req
= all_requests
; req
; req
= req
->next
)
446 if (srv
->autoname
&& !SameDomainLabel(srv
->name
.c
, mDNSStorage
.nicelabel
.c
))
448 srv
->rename_on_memfree
= 1;
449 err
= mDNS_DeregisterService(&mDNSStorage
, srv
->srs
);
450 if (err
) LogMsg("ERROR: udsserver_handle_configchange: DeregisterService returned error %d. Continuing.", err
);
451 // error should never occur - safest to log and continue
459 // accept a connection on the named socket, adding the new descriptor to the runloop and passing the error
460 // descriptor to the client
461 static void connect_callback(CFSocketRef s
, CFSocketCallBackType t
, CFDataRef dr
, const void *c
, void *i
)
463 int sd
, clilen
, optval
;
464 struct sockaddr_un cliaddr
;
465 CFSocketContext context
= { 0, NULL
, NULL
, NULL
, NULL
};
466 request_state
*rstate
;
469 #pragma unused(s, t, dr, c, i)
471 clilen
= sizeof(cliaddr
);
472 sd
= accept(listenfd
, (struct sockaddr
*)&cliaddr
, &clilen
);
476 if (errno
== EWOULDBLOCK
) return;
477 my_perror("ERROR: accept");
481 if (setsockopt(sd
, SOL_SOCKET
, SO_NOSIGPIPE
, &optval
, sizeof(optval
)) < 0)
483 my_perror("ERROR: setsockopt - SOL_NOSIGPIPE - aborting client");
488 if (fcntl(sd
, F_SETFL
, O_NONBLOCK
) < 0)
490 my_perror("ERROR: could not set connected socket to non-blocking mode - aborting client");
496 // open a pipe to deliver error messages, pass descriptor to client
497 if (pipe(errpipe) < 0)
499 my_perror("ERROR: could not create pipe");
503 if (ioctl(sd, I_SENDFD, errpipe[0]) < 0)
505 my_perror("ERROR: could not pass pipe descriptor to client. Aborting client.\n");
509 if (fcntl(errpipe[1], F_SETFL, O_NONBLOCK) < 0)
511 my_perror("ERROR: could not set error pipe to non-blocking mode - aborting client");
518 // allocate a request_state struct that will live with the socket
519 rstate
= mallocL("connect_callback", sizeof(request_state
));
522 my_perror("ERROR: malloc");
525 bzero(rstate
, sizeof(request_state
));
526 rstate
->ts
= t_morecoming
;
528 //rstate->errfd = errpipe[1];
530 //now create CFSocket wrapper and add to run loop
531 context
.info
= rstate
;
532 rstate
->sr
= CFSocketCreateWithNative(kCFAllocatorDefault
, sd
, kCFSocketReadCallBack
, request_callback
, &context
);
535 debugf("ERROR: connect_callback - CFSocketCreateWithNative");
536 freeL("connect_callback", rstate
);
540 rstate
->rls
= CFSocketCreateRunLoopSource(kCFAllocatorDefault
, rstate
->sr
, 0);
543 debugf("ERROR: connect_callback - CFSocketCreateRunLoopSource");
544 CFSocketInvalidate(rstate
->sr
); // automatically closes socket
545 CFRelease(rstate
->sr
);
546 freeL("connect_callback", rstate
);
549 CFRunLoopAddSource(CFRunLoopGetCurrent(), rstate
->rls
, kCFRunLoopDefaultMode
);
550 if (!CFRunLoopContainsSource(CFRunLoopGetCurrent(), rstate
->rls
, kCFRunLoopDefaultMode
))
552 LogMsg("ERROR: connect_callback, CFRunLoopAddSource");
553 abort_request(rstate
);
556 rstate
->next
= all_requests
;
557 all_requests
= rstate
;
561 // main client request handling routine. reads request and calls the appropriate request-specific
563 static void request_callback(CFSocketRef sr
, CFSocketCallBackType t
, CFDataRef dr
, const void *context
, void *info
)
565 request_state
*rstate
= info
;
566 transfer_state result
;
567 struct sockaddr_un cliaddr
;
568 char ctrl_path
[MAX_CTLPATH
];
570 #pragma unused(sr, t, dr, context)
572 int native
= CFSocketGetNative(sr
);
573 if (native
!= rstate
->sd
)
575 LogMsg("ERROR: request_callback - CFSocket's native descriptor does not match rstate member descriptor.");
576 abort_request(rstate
);
577 unlink_request(rstate
);
581 result
= read_msg(rstate
);
582 if (result
== t_morecoming
)
586 if (result
== t_terminated
)
588 abort_request(rstate
);
589 unlink_request(rstate
);
592 if (result
== t_error
)
594 abort_request(rstate
);
595 unlink_request(rstate
);
599 if (rstate
->hdr
.version
!= VERSION
)
601 LogMsg("ERROR: client incompatible with daemon (client version = %d, "
602 "daemon version = %d)\n", rstate
->hdr
.version
, VERSION
);
603 abort_request(rstate
);
604 unlink_request(rstate
);
608 // check if client wants silent operation
609 if (rstate
->hdr
.flags
& IPC_FLAGS_NOREPLY
) rstate
->no_reply
= 1;
611 // check if primary socket is to be used for synchronous errors, else open new socket
612 if (rstate
->hdr
.flags
& IPC_FLAGS_REUSE_SOCKET
)
613 rstate
->errfd
= rstate
->sd
;
616 if ((rstate
->errfd
= socket(AF_LOCAL
, SOCK_STREAM
, 0)) < 0)
618 my_perror("ERROR: socket");
621 if (fcntl(rstate
->errfd
, F_SETFL
, O_NONBLOCK
) < 0)
623 my_perror("ERROR: could not set control socket to non-blocking mode");
624 abort_request(rstate
);
625 unlink_request(rstate
);
628 get_string(&rstate
->msgdata
, ctrl_path
, 256); // path is first element in message buffer
629 bzero(&cliaddr
, sizeof(cliaddr
));
630 cliaddr
.sun_family
= AF_LOCAL
;
631 strcpy(cliaddr
.sun_path
, ctrl_path
);
632 if (connect(rstate
->errfd
, (struct sockaddr
*)&cliaddr
, sizeof(cliaddr
)) < 0)
634 my_perror("ERROR: connect");
635 abort_request(rstate
);
636 unlink_request(rstate
);
643 switch(rstate
->hdr
.op
.request_op
)
645 case resolve_request
: handle_resolve_request(rstate
); break;
646 case query_request
: handle_query_request(rstate
); break;
647 case browse_request
: handle_browse_request(rstate
); break;
648 case reg_service_request
: handle_regservice_request(rstate
); break;
649 case enumeration_request
: handle_enum_request(rstate
); break;
650 case reg_record_request
: handle_regrecord_request(rstate
); break;
651 case add_record_request
: handle_add_request(rstate
); break;
652 case update_record_request
: handle_update_request(rstate
); break;
653 case remove_record_request
: handle_removerecord_request(rstate
); break;
654 case reconfirm_record_request
: handle_reconfirm_request(rstate
); break;
656 debugf("ERROR: udsserver_recv_request - unsupported request type: %d", rstate
->hdr
.op
.request_op
);
660 // mDNS operation functions. Each operation has 3 associated functions - a request handler that parses
661 // the client's request and makes the appropriate mDNSCore call, a result handler (passed as a callback
662 // to the mDNSCore routine) that sends results back to the client, and a termination routine that aborts
663 // the mDNSCore operation if the client dies or closes its socket.
666 // query and resolve calls have separate request handlers that parse the arguments from the client and
667 // massage the name parameters appropriately, but the rest of the operations (making the query call,
668 // delivering the result to the client, and termination) are identical.
670 static void handle_query_request(request_state
*rstate
)
672 DNSServiceFlags flags
;
673 uint32_t interfaceIndex
;
675 uint16_t rrtype
, rrclass
;
680 if (rstate
->ts
!= t_complete
)
682 LogMsg("ERROR: handle_query_request - transfer state != t_complete");
685 ptr
= rstate
->msgdata
;
688 LogMsg("ERROR: handle_query_request - NULL msgdata");
691 flags
= get_flags(&ptr
);
692 interfaceIndex
= get_long(&ptr
);
693 if (get_string(&ptr
, name
, 256) < 0) goto bad_param
;
694 rrtype
= get_short(&ptr
);
695 rrclass
= get_short(&ptr
);
696 if (!MakeDomainNameFromDNSNameString(&dname
, name
)) goto bad_param
;
697 result
= do_question(rstate
, &dname
, interfaceIndex
, rrtype
, rrclass
);
698 if (result
) rstate
->terminate
= NULL
;
699 if (deliver_error(rstate
, result
) < 0) goto error
;
703 deliver_error(rstate
, mStatus_BadParamErr
);
704 rstate
->terminate
= NULL
; // don't try to terminate insuccessful Core calls
706 abort_request(rstate
);
707 unlink_request(rstate
);
711 static void handle_resolve_request(request_state
*rstate
)
713 DNSServiceFlags flags
;
714 uint32_t interfaceIndex
;
715 char name
[256], regtype
[MAX_ESCAPED_DOMAIN_NAME
], domain
[MAX_ESCAPED_DOMAIN_NAME
];
716 char *ptr
; // message data pointer
718 resolve_t
*srv
, *txt
;
719 resolve_termination_t
*term
;
722 if (rstate
->ts
!= t_complete
)
724 LogMsg("ERROR: handle_resolve_request - transfer state != t_complete");
725 abort_request(rstate
);
726 unlink_request(rstate
);
730 // extract the data from the message
731 ptr
= rstate
->msgdata
;
734 LogMsg("ERROR: handle_resolve_request - NULL msgdata");
735 abort_request(rstate
);
736 unlink_request(rstate
);
739 flags
= get_flags(&ptr
);
740 interfaceIndex
= get_long(&ptr
);
741 mDNSInterfaceID InterfaceID
= mDNSPlatformInterfaceIDfromInterfaceIndex(&mDNSStorage
, interfaceIndex
);
742 if (interfaceIndex
&& !InterfaceID
) goto bad_param
;
743 if (get_string(&ptr
, name
, 256) < 0 ||
744 get_string(&ptr
, regtype
, MAX_ESCAPED_DOMAIN_NAME
) < 0 ||
745 get_string(&ptr
, domain
, MAX_ESCAPED_DOMAIN_NAME
) < 0)
748 // free memory in rstate since we don't need it anymore
749 freeL("handle_resolve_request", rstate
->msgbuf
);
750 rstate
->msgbuf
= NULL
;
752 if (build_domainname_from_strings(&fqdn
, name
, regtype
, domain
) < 0)
755 // allocate question wrapper structs
756 srv
= mallocL("handle_resolve_request", sizeof(resolve_t
));
757 txt
= mallocL("handle_resolve_request", sizeof(resolve_t
));
758 if (!srv
|| !txt
) goto malloc_error
;
759 srv
->qtype
= kDNSType_SRV
;
760 txt
->qtype
= kDNSType_TXT
;
761 srv
->rstate
= rstate
;
762 txt
->rstate
= rstate
;
765 srv
->question
.QuestionContext
= rstate
;
766 srv
->question
.QuestionCallback
= resolve_result_callback
;
767 memcpy(&srv
->question
.qname
, &fqdn
, MAX_DOMAIN_NAME
);
768 srv
->question
.qtype
= kDNSType_SRV
;
769 srv
->question
.qclass
= kDNSClass_IN
;
770 srv
->question
.InterfaceID
= InterfaceID
;
772 txt
->question
.QuestionContext
= rstate
;
773 txt
->question
.QuestionCallback
= resolve_result_callback
;
774 memcpy(&txt
->question
.qname
, &fqdn
, MAX_DOMAIN_NAME
);
775 txt
->question
.qtype
= kDNSType_TXT
;
776 txt
->question
.qclass
= kDNSClass_IN
;
777 txt
->question
.InterfaceID
= InterfaceID
;
779 // set up termination info
780 term
= mallocL("handle_resolve_request", sizeof(resolve_termination_t
));
781 if (!term
) goto malloc_error
;
784 term
->rstate
= rstate
;
785 rstate
->termination_context
= term
;
786 rstate
->terminate
= resolve_termination_callback
;
788 // set up reply wrapper struct (since answer will come via 2 callbacks)
789 rstate
->resolve_results
= mallocL("handle_resolve_response", sizeof(resolve_result_t
));
790 if (!rstate
->resolve_results
) goto malloc_error
;
791 bzero(rstate
->resolve_results
, sizeof(resolve_result_t
));
794 err
= mDNS_StartQuery(&mDNSStorage
, &srv
->question
);
795 if (!err
) err
= mDNS_StartQuery(&mDNSStorage
, &txt
->question
);
799 freeL("handle_resolve_request", txt
);
800 freeL("handle_resolve_request", srv
);
801 freeL("handle_resolve_request", term
);
802 freeL("handle_resolve_request", rstate
->resolve_results
);
803 rstate
->terminate
= NULL
; // prevent abort_request() from invoking termination callback
805 if (deliver_error(rstate
, err
) < 0 || err
)
807 abort_request(rstate
);
808 unlink_request(rstate
);
813 deliver_error(rstate
, mStatus_BadParamErr
);
814 abort_request(rstate
);
815 unlink_request(rstate
);
819 my_perror("ERROR: malloc");
823 static void resolve_termination_callback(void *context
)
825 resolve_termination_t
*term
= context
;
830 LogMsg("ERROR: resolve_termination_callback: double termination");
835 mDNS_StopQuery(&mDNSStorage
, &term
->txt
->question
);
836 mDNS_StopQuery(&mDNSStorage
, &term
->srv
->question
);
838 freeL("resolve_termination_callback", term
->txt
);
839 freeL("resolve_termination_callback", term
->srv
);
840 freeL("resolve_termination_callback", term
);
841 rs
->termination_context
= NULL
;
842 freeL("resolve_termination_callback", rs
->resolve_results
);
843 rs
->resolve_results
= NULL
;
848 static void resolve_result_callback(mDNS
*const m
, DNSQuestion
*question
, const ResourceRecord
*const answer
, mDNSBool AddRecord
)
851 char fullname
[MAX_ESCAPED_DOMAIN_NAME
], target
[MAX_ESCAPED_DOMAIN_NAME
];
853 transfer_state result
;
855 request_state
*rs
= question
->QuestionContext
;
856 resolve_result_t
*res
= rs
->resolve_results
;
861 if (answer
->rrtype
== kDNSType_TXT
&& res
->txt
== answer
) res
->txt
= mDNSNULL
;
862 if (answer
->rrtype
== kDNSType_SRV
&& res
->srv
== answer
) res
->srv
= mDNSNULL
;
866 if (answer
->rrtype
== kDNSType_TXT
) res
->txt
= answer
;
867 if (answer
->rrtype
== kDNSType_SRV
) res
->srv
= answer
;
869 if (!res
->txt
|| !res
->srv
) return; // only deliver result to client if we have both answers
871 ConvertDomainNameToCString(&answer
->name
, fullname
);
872 ConvertDomainNameToCString(&res
->srv
->rdata
->u
.srv
.target
, target
);
874 // calculate reply length
875 len
+= sizeof(DNSServiceFlags
);
876 len
+= sizeof(uint32_t); // interface index
877 len
+= sizeof(DNSServiceErrorType
);
878 len
+= strlen(fullname
) + 1;
879 len
+= strlen(target
) + 1;
880 len
+= 2 * sizeof(uint16_t); // port, txtLen
881 len
+= res
->txt
->rdlength
;
883 // allocate/init reply header
884 rep
= create_reply(resolve_reply
, len
, rs
);
885 rep
->rhdr
->flags
= 0;
886 rep
->rhdr
->ifi
= mDNSPlatformInterfaceIndexfromInterfaceID(&mDNSStorage
, answer
->InterfaceID
);
887 rep
->rhdr
->error
= kDNSServiceErr_NoError
;
890 // write reply data to message
891 put_string(fullname
, &data
);
892 put_string(target
, &data
);
893 put_short(res
->srv
->rdata
->u
.srv
.port
.NotAnInteger
, &data
);
894 put_short(res
->txt
->rdlength
, &data
);
895 put_rdata(res
->txt
->rdlength
, res
->txt
->rdata
->u
.txt
.c
, &data
);
897 result
= send_msg(rep
);
898 if (result
== t_error
|| result
== t_terminated
)
902 freeL("resolve_result_callback", rep
);
904 else if (result
== t_complete
) freeL("resolve_result_callback", rep
);
905 else append_reply(rs
, rep
);
911 // common query issuing routine for resolve and query requests
912 static mStatus
do_question(request_state
*rstate
, domainname
*name
, uint32_t ifi
, uint16_t rrtype
, int16_t rrclass
)
916 mDNSInterfaceID InterfaceID
= mDNSPlatformInterfaceIDfromInterfaceIndex(&mDNSStorage
, ifi
);
917 if (ifi
&& !InterfaceID
) return(mStatus_BadParamErr
);
919 q
= mallocL("do_question", sizeof(DNSQuestion
));
922 my_perror("ERROR: do_question - malloc");
925 bzero(q
, sizeof(DNSQuestion
));
927 q
->QuestionContext
= rstate
;
928 q
->QuestionCallback
= question_result_callback
;
929 memcpy(&q
->qname
, name
, MAX_DOMAIN_NAME
);
932 q
->InterfaceID
= InterfaceID
;
935 rstate
->termination_context
= q
;
936 rstate
->terminate
= question_termination_callback
;
938 result
= mDNS_StartQuery(&mDNSStorage
, q
);
939 if (result
!= mStatus_NoError
) LogMsg("ERROR: mDNS_StartQuery: %d", (int)result
);
943 // what gets called when a resolve is completed and we need to send the data back to the client
944 static void question_result_callback(mDNS
*const m
, DNSQuestion
*question
, const ResourceRecord
*const answer
, mDNSBool AddRecord
)
947 char name
[MAX_ESCAPED_DOMAIN_NAME
];
953 //mDNS_StopQuery(m, question);
954 req
= question
->QuestionContext
;
956 // calculate reply data length
957 len
= sizeof(DNSServiceFlags
);
958 len
+= 2 * sizeof(uint32_t); // if index + ttl
959 len
+= sizeof(DNSServiceErrorType
);
960 len
+= 3 * sizeof(uint16_t); // type, class, rdlen
961 len
+= answer
->rdlength
;
962 ConvertDomainNameToCString(&answer
->name
, name
);
963 len
+= strlen(name
) + 1;
965 rep
= create_reply(query_reply
, len
, req
);
966 rep
->rhdr
->flags
= AddRecord
? kDNSServiceFlagsAdd
: kDNSServiceFlagsRemove
;
967 rep
->rhdr
->ifi
= mDNSPlatformInterfaceIndexfromInterfaceID(&mDNSStorage
, answer
->InterfaceID
);
968 rep
->rhdr
->error
= kDNSServiceErr_NoError
;
971 put_string(name
, &data
);
972 put_short(answer
->rrtype
, &data
);
973 put_short(answer
->rrclass
, &data
);
974 put_short(answer
->rdlength
, &data
);
975 put_rdata(answer
->rdlength
, (char *)&answer
->rdata
->u
, &data
);
976 put_long(AddRecord
? answer
->rroriginalttl
: 0, &data
);
978 append_reply(req
, rep
);
982 static void question_termination_callback(void *context
)
984 DNSQuestion
*q
= context
;
987 mDNS_StopQuery(&mDNSStorage
, q
); // no need to error check
988 freeL("question_termination_callback", q
);
992 static void handle_browse_request(request_state
*request
)
994 DNSServiceFlags flags
;
995 uint32_t interfaceIndex
;
996 char regtype
[MAX_ESCAPED_DOMAIN_NAME
], domain
[MAX_ESCAPED_DOMAIN_NAME
];
998 domainname typedn
, domdn
;
1002 if (request
->ts
!= t_complete
)
1004 LogMsg("ERROR: handle_browse_request - transfer state != t_complete");
1005 abort_request(request
);
1006 unlink_request(request
);
1009 q
= mallocL("handle_browse_request", sizeof(DNSQuestion
));
1012 my_perror("ERROR: handle_browse_request - malloc");
1015 bzero(q
, sizeof(DNSQuestion
));
1017 // extract data from message
1018 ptr
= request
->msgdata
;
1019 flags
= get_flags(&ptr
);
1020 interfaceIndex
= get_long(&ptr
);
1021 if (get_string(&ptr
, regtype
, MAX_ESCAPED_DOMAIN_NAME
) < 0 ||
1022 get_string(&ptr
, domain
, MAX_ESCAPED_DOMAIN_NAME
) < 0)
1025 freeL("handle_browse_request", request
->msgbuf
);
1026 request
->msgbuf
= NULL
;
1028 mDNSInterfaceID InterfaceID
= mDNSPlatformInterfaceIDfromInterfaceIndex(&mDNSStorage
, interfaceIndex
);
1029 if (interfaceIndex
&& !InterfaceID
) goto bad_param
;
1030 q
->QuestionContext
= request
;
1031 q
->QuestionCallback
= browse_result_callback
;
1032 if (!MakeDomainNameFromDNSNameString(&typedn
, regtype
) ||
1033 !MakeDomainNameFromDNSNameString(&domdn
, domain
[0] ? domain
: "local."))
1035 request
->termination_context
= q
;
1036 request
->terminate
= browse_termination_callback
;
1037 result
= mDNS_StartBrowse(&mDNSStorage
, q
, &typedn
, &domdn
, InterfaceID
, browse_result_callback
, request
);
1038 deliver_error(request
, result
);
1042 deliver_error(request
, mStatus_BadParamErr
);
1043 abort_request(request
);
1044 unlink_request(request
);
1047 static void browse_result_callback(mDNS
*const m
, DNSQuestion
*question
, const ResourceRecord
*const answer
, mDNSBool AddRecord
)
1054 req
= question
->QuestionContext
;
1056 err
= gen_rr_response(&answer
->rdata
->u
.name
, answer
->InterfaceID
, req
, &rep
);
1059 if (deliver_async_error(req
, browse_reply
, err
) < 0)
1062 unlink_request(req
);
1066 if (AddRecord
) rep
->rhdr
->flags
|= kDNSServiceFlagsAdd
; // non-zero TTL indicates add
1067 append_reply(req
, rep
);
1071 static void browse_termination_callback(void *context
)
1073 DNSQuestion
*q
= context
;
1075 mDNS_StopBrowse(&mDNSStorage
, q
); // no need to error-check result
1076 freeL("browse_termination_callback", q
);
1079 // service registration
1080 static void handle_regservice_request(request_state
*request
)
1082 DNSServiceFlags flags
;
1084 char name
[256], regtype
[MAX_ESCAPED_DOMAIN_NAME
], domain
[MAX_ESCAPED_DOMAIN_NAME
], host
[MAX_ESCAPED_DOMAIN_NAME
];
1090 domainname t
, d
, h
, srv
;
1091 registered_service
*r_srv
;
1095 char *sub
, *rtype_ptr
;
1096 int i
, num_subtypes
;
1099 if (request
->ts
!= t_complete
)
1101 LogMsg("ERROR: handle_regservice_request - transfer state != t_complete");
1102 abort_request(request
);
1103 unlink_request(request
);
1107 // extract data from message
1108 ptr
= request
->msgdata
;
1109 flags
= get_flags(&ptr
);
1110 ifi
= get_long(&ptr
);
1111 mDNSInterfaceID InterfaceID
= mDNSPlatformInterfaceIDfromInterfaceIndex(&mDNSStorage
, ifi
);
1112 if (ifi
&& !InterfaceID
) goto bad_param
;
1113 if (get_string(&ptr
, name
, 256) < 0 ||
1114 get_string(&ptr
, regtype
, MAX_ESCAPED_DOMAIN_NAME
) < 0 ||
1115 get_string(&ptr
, domain
, MAX_ESCAPED_DOMAIN_NAME
) < 0 ||
1116 get_string(&ptr
, host
, MAX_ESCAPED_DOMAIN_NAME
) < 0)
1119 port
.NotAnInteger
= get_short(&ptr
);
1120 txtlen
= get_short(&ptr
);
1121 txtdata
= get_rdata(&ptr
, txtlen
);
1123 // count subtypes, replacing commas w/ whitespace
1124 rtype_ptr
= regtype
;
1126 while((sub
= strsep(&rtype_ptr
, ",")))
1127 if (*sub
) num_subtypes
++;
1129 if (!name
[0]) n
= (&mDNSStorage
)->nicelabel
;
1130 else if (!MakeDomainLabelFromLiteralString(&n
, name
))
1132 if ((!regtype
[0] || !MakeDomainNameFromDNSNameString(&t
, regtype
)) ||
1133 (!MakeDomainNameFromDNSNameString(&d
, *domain
? domain
: "local.")) ||
1134 (!ConstructServiceName(&srv
, &n
, &t
, &d
)))
1136 if (host
[0] && !MakeDomainNameFromDNSNameString(&h
, host
)) goto bad_param
;
1138 r_srv
= mallocL("handle_regservice_request", sizeof(registered_service
));
1139 if (!r_srv
) goto malloc_error
;
1140 srs_size
= sizeof(ServiceRecordSet
) + (sizeof(RDataBody
) > txtlen
? 0 : txtlen
- sizeof(RDataBody
));
1141 r_srv
->srs
= mallocL("handle_regservice_request", srs_size
);
1142 if (!r_srv
->srs
) goto malloc_error
;
1143 if (num_subtypes
> 0)
1145 r_srv
->subtypes
= mallocL("handle_regservice_request", num_subtypes
* sizeof(AuthRecord
));
1146 if (!r_srv
->subtypes
) goto malloc_error
;
1147 sub
= regtype
+ strlen(regtype
) + 1;
1148 for (i
= 0; i
< num_subtypes
; i
++)
1150 if (!MakeDomainNameFromDNSNameString(&(r_srv
->subtypes
+ i
)->resrec
.name
, sub
))
1152 freeL("handle_regservice_request", r_srv
->subtypes
);
1153 freeL("handle_regservice_request", r_srv
);
1157 sub
+= strlen(sub
) + 1;
1160 else r_srv
->subtypes
= NULL
;
1161 r_srv
->request
= request
;
1163 r_srv
->autoname
= (!name
[0]);
1164 r_srv
->rename_on_memfree
= 0;
1165 r_srv
->renameonconflict
= !(flags
& kDNSServiceFlagsNoAutoRename
);
1167 request
->termination_context
= r_srv
;
1168 request
->terminate
= regservice_termination_callback
;
1169 request
->service
= r_srv
;
1171 result
= mDNS_RegisterService(&mDNSStorage
, r_srv
->srs
, &n
, &t
, &d
, host
[0] ? &h
: NULL
, port
,
1172 txtdata
, txtlen
, r_srv
->subtypes
, num_subtypes
, InterfaceID
, regservice_callback
, r_srv
);
1173 deliver_error(request
, result
);
1174 if (result
!= mStatus_NoError
)
1176 abort_request(request
);
1177 unlink_request(request
);
1181 reset_connected_rstate(request
); // reset to receive add/remove messages
1186 deliver_error(request
, mStatus_BadParamErr
);
1187 abort_request(request
);
1188 unlink_request(request
);
1192 my_perror("ERROR: malloc");
1196 // service registration callback performs three duties - frees memory for deregistered services,
1197 // handles name conflicts, and delivers completed registration information to the client (via
1198 // process_service_registraion())
1200 static void regservice_callback(mDNS
*const m
, ServiceRecordSet
*const srs
, mStatus result
)
1203 ExtraResourceRecord
*extra
;
1204 registered_service
*r_srv
= srs
->ServiceContext
;
1205 request_state
*rs
= r_srv
->request
;
1209 if (!rs
&& (result
!= mStatus_MemFree
&& !r_srv
->rename_on_memfree
))
1211 // error should never happen - safest to log and continue
1212 LogMsg("ERROR: regservice_callback: received result %d with a NULL request pointer\n");
1216 if (result
== mStatus_NoError
)
1217 return process_service_registration(srs
);
1218 else if (result
== mStatus_MemFree
)
1220 if (r_srv
->rename_on_memfree
)
1222 r_srv
->rename_on_memfree
= 0;
1223 r_srv
->name
= mDNSStorage
.nicelabel
;
1224 err
= mDNS_RenameAndReregisterService(&mDNSStorage
, srs
, &r_srv
->name
);
1225 if (err
) LogMsg("ERROR: regservice_callback - RenameAndReregisterService returned %d", err
);
1226 // error should never happen - safest to log and continue
1230 while (r_srv
->srs
->Extras
)
1232 extra
= r_srv
->srs
->Extras
;
1233 r_srv
->srs
->Extras
= r_srv
->srs
->Extras
->next
;
1234 freeL("regservice_callback", extra
);
1236 freeL("regservice_callback", r_srv
->srs
);
1237 if (r_srv
->subtypes
) freeL("regservice_callback", r_srv
->subtypes
);
1238 if (r_srv
->request
) r_srv
->request
->service
= NULL
;
1239 freeL("regservice_callback", r_srv
);
1243 else if (result
== mStatus_NameConflict
)
1245 if (r_srv
->autoname
|| r_srv
->renameonconflict
)
1247 mDNS_RenameAndReregisterService(&mDNSStorage
, srs
, mDNSNULL
);
1252 freeL("regservice_callback", r_srv
);
1253 freeL("regservice_callback", r_srv
->srs
);
1254 if (r_srv
->subtypes
) freeL("regservice_callback", r_srv
->subtypes
);
1255 if (r_srv
->request
) r_srv
->request
->service
= NULL
;
1256 freeL("regservice_callback", r_srv
);
1257 if (deliver_async_error(rs
, reg_service_reply
, result
) < 0)
1267 LogMsg("ERROR: unknown result in regservice_callback");
1268 if (deliver_async_error(rs
, reg_service_reply
, result
) < 0)
1277 static void handle_add_request(request_state
*rstate
)
1279 registered_record_entry
*re
;
1280 ExtraResourceRecord
*extra
;
1282 uint16_t rrtype
, rdlen
;
1285 DNSServiceFlags flags
;
1286 ServiceRecordSet
*srs
= rstate
->service
->srs
;
1290 LogMsg("ERROR: handle_add_request - no service record set in request state");
1291 deliver_error(rstate
, mStatus_UnknownErr
);
1295 ptr
= rstate
->msgdata
;
1296 flags
= get_flags(&ptr
);
1297 rrtype
= get_short(&ptr
);
1298 rdlen
= get_short(&ptr
);
1299 rdata
= get_rdata(&ptr
, rdlen
);
1300 ttl
= get_long(&ptr
);
1302 if (rdlen
> sizeof(RDataBody
)) size
= rdlen
;
1303 else size
= sizeof(RDataBody
);
1305 extra
= mallocL("hanle_add_request", sizeof(ExtraResourceRecord
) - sizeof(RDataBody
) + size
);
1308 my_perror("ERROR: malloc");
1312 bzero(extra
, sizeof(ExtraResourceRecord
)); // OK if oversized rdata not zero'd
1313 extra
->r
.resrec
.rrtype
= rrtype
;
1314 extra
->r
.rdatastorage
.MaxRDLength
= size
;
1315 extra
->r
.resrec
.rdlength
= rdlen
;
1316 memcpy(&extra
->r
.rdatastorage
.u
.data
, rdata
, rdlen
);
1317 result
= mDNS_AddRecordToService(&mDNSStorage
, srs
, extra
, &extra
->r
.rdatastorage
, ttl
);
1318 deliver_error(rstate
, result
);
1319 reset_connected_rstate(rstate
);
1322 freeL("handle_add_request", rstate
->msgbuf
);
1323 rstate
->msgbuf
= NULL
;
1324 freeL("handle_add_request", extra
);
1327 re
= mallocL("handle_add_request", sizeof(registered_record_entry
));
1330 my_perror("ERROR: malloc");
1333 re
->key
= rstate
->hdr
.reg_index
;
1335 re
->next
= rstate
->reg_recs
;
1336 rstate
->reg_recs
= re
;
1339 static void handle_update_request(request_state
*rstate
)
1341 registered_record_entry
*reptr
;
1344 uint16_t rdlen
, rdsize
;
1349 if (rstate
->hdr
.reg_index
== TXT_RECORD_INDEX
)
1351 if (!rstate
->service
)
1353 deliver_error(rstate
, mStatus_BadParamErr
);
1356 rr
= &rstate
->service
->srs
->RR_TXT
;
1360 reptr
= rstate
->reg_recs
;
1361 while(reptr
&& reptr
->key
!= rstate
->hdr
.reg_index
) reptr
= reptr
->next
;
1362 if (!reptr
) deliver_error(rstate
, mStatus_BadReferenceErr
);
1366 ptr
= rstate
->msgdata
;
1367 get_flags(&ptr
); // flags unused
1368 rdlen
= get_short(&ptr
);
1369 rdata
= get_rdata(&ptr
, rdlen
);
1370 ttl
= get_long(&ptr
);
1372 if (rdlen
> sizeof(RDataBody
)) rdsize
= rdlen
;
1373 else rdsize
= sizeof(RDataBody
);
1374 newrd
= mallocL("handle_update_request", sizeof(RData
) - sizeof(RDataBody
) + rdsize
);
1377 my_perror("ERROR: malloc");
1380 newrd
->MaxRDLength
= rdsize
;
1381 memcpy(&newrd
->u
, rdata
, rdlen
);
1382 result
= mDNS_Update(&mDNSStorage
, rr
, ttl
, rdlen
, newrd
, update_callback
);
1383 deliver_error(rstate
, result
);
1384 reset_connected_rstate(rstate
);
1387 static void update_callback(mDNS
*const m
, AuthRecord
*const rr
, RData
*oldrd
)
1391 if (oldrd
!= &rr
->rdatastorage
) freeL("update_callback", oldrd
);
1394 static void process_service_registration(ServiceRecordSet
*const srs
)
1397 transfer_state send_result
;
1399 registered_service
*r_srv
= srs
->ServiceContext
;
1400 request_state
*req
= r_srv
->request
;
1403 err
= gen_rr_response(&srs
->RR_SRV
.resrec
.name
, srs
->RR_SRV
.resrec
.InterfaceID
, req
, &rep
);
1406 if (deliver_async_error(req
, reg_service_reply
, err
) < 0)
1409 unlink_request(req
);
1413 send_result
= send_msg(rep
);
1414 if (send_result
== t_error
|| send_result
== t_terminated
)
1417 unlink_request(req
);
1418 freeL("process_service_registration", rep
);
1420 else if (send_result
== t_complete
) freeL("process_service_registration", rep
);
1421 else append_reply(req
, rep
);
1424 static void regservice_termination_callback(void *context
)
1426 registered_service
*srv
= context
;
1428 // only safe to free memory if registration is not valid, ie deregister fails
1429 if (mDNS_DeregisterService(&mDNSStorage
, srv
->srs
) != mStatus_NoError
)
1431 freeL("regservice_callback", srv
->srs
);
1432 if (srv
->subtypes
) freeL("regservice_callback", srv
->subtypes
);
1433 freeL("regservice_callback", srv
);
1434 freeL("regservice_termination_callback", srv
);
1439 static void handle_regrecord_request(request_state
*rstate
)
1442 regrecord_callback_context
*rcc
;
1443 registered_record_entry
*re
;
1446 if (rstate
->ts
!= t_complete
)
1448 LogMsg("ERROR: handle_regrecord_request - transfer state != t_complete");
1449 abort_request(rstate
);
1450 unlink_request(rstate
);
1454 rr
= read_rr_from_ipc_msg(rstate
->msgdata
, 1);
1457 deliver_error(rstate
, mStatus_BadParamErr
);
1461 rcc
= mallocL("hanlde_regrecord_request", sizeof(regrecord_callback_context
));
1462 if (!rcc
) goto malloc_error
;
1463 rcc
->rstate
= rstate
;
1464 rcc
->client_context
= rstate
->hdr
.client_context
;
1465 rr
->RecordContext
= rcc
;
1466 rr
->RecordCallback
= regrecord_callback
;
1468 // allocate registration entry, link into list
1469 re
= mallocL("hanlde_regrecord_request", sizeof(registered_record_entry
));
1470 if (!re
) goto malloc_error
;
1471 re
->key
= rstate
->hdr
.reg_index
;
1473 re
->next
= rstate
->reg_recs
;
1474 rstate
->reg_recs
= re
;
1476 if (!rstate
->terminate
)
1478 rstate
->terminate
= connected_registration_termination
;
1479 rstate
->termination_context
= rstate
;
1482 result
= mDNS_Register(&mDNSStorage
, rr
);
1483 deliver_error(rstate
, result
);
1484 reset_connected_rstate(rstate
);
1488 my_perror("ERROR: malloc");
1492 static void regrecord_callback(mDNS
*const m
, AuthRecord
*const rr
, mStatus result
)
1494 regrecord_callback_context
*rcc
;
1501 if (result
== mStatus_MemFree
) { freeL("regrecord_callback", rr
); return; }
1502 rcc
= rr
->RecordContext
;
1504 // format result, add to the list for the request, including the client context in the header
1505 len
= sizeof(DNSServiceFlags
);
1506 len
+= sizeof(uint32_t); //interfaceIndex
1507 len
+= sizeof(DNSServiceErrorType
);
1509 reply
= create_reply(reg_record_reply
, len
, rcc
->rstate
);
1510 reply
->mhdr
->client_context
= rcc
->client_context
;
1511 reply
->rhdr
->flags
= 0;
1512 reply
->rhdr
->ifi
= mDNSPlatformInterfaceIndexfromInterfaceID(&mDNSStorage
, rr
->resrec
.InterfaceID
);
1513 reply
->rhdr
->error
= result
;
1515 ts
= send_msg(reply
);
1516 if (ts
== t_error
|| ts
== t_terminated
)
1518 abort_request(rcc
->rstate
);
1519 unlink_request(rcc
->rstate
);
1521 else if (ts
== t_complete
) freeL("regrecord_callback", reply
);
1522 else if (ts
== t_morecoming
) append_reply(rcc
->rstate
, reply
); // client is blocked, link reply into list
1525 static void connected_registration_termination(void *context
)
1527 registered_record_entry
*fptr
, *ptr
= ((request_state
*)context
)->reg_recs
;
1530 mDNS_Deregister(&mDNSStorage
, ptr
->rr
);
1533 freeL("connected_registration_termination", fptr
);
1539 static void handle_removerecord_request(request_state
*rstate
)
1541 registered_record_entry
*reptr
, *prev
= NULL
;
1542 mStatus err
= mStatus_UnknownErr
;
1544 reptr
= rstate
->reg_recs
;
1546 ptr
= rstate
->msgdata
;
1547 get_flags(&ptr
); // flags unused
1551 if (reptr
->key
== rstate
->hdr
.reg_index
) // found match
1553 if (prev
) prev
->next
= reptr
->next
;
1554 else rstate
->reg_recs
= reptr
->next
;
1555 err
= mDNS_Deregister(&mDNSStorage
, reptr
->rr
);
1556 freeL("handle_removerecord_request", reptr
); //rr gets freed by callback
1560 reptr
= reptr
->next
;
1562 reset_connected_rstate(rstate
);
1563 if (deliver_error(rstate
, err
) < 0)
1565 abort_request(rstate
);
1566 unlink_request(rstate
);
1571 // domain enumeration
1572 static void handle_enum_request(request_state
*rstate
)
1574 DNSServiceFlags flags
, add_default
;
1576 char *ptr
= rstate
->msgdata
;
1577 domain_enum_t
*def
, *all
;
1578 enum_termination_t
*term
;
1579 reply_state
*reply
; // initial default reply
1584 if (rstate
->ts
!= t_complete
)
1586 LogMsg("ERROR: handle_enum_request - transfer state != t_complete");
1587 abort_request(rstate
);
1588 unlink_request(rstate
);
1592 flags
= get_flags(&ptr
);
1593 ifi
= get_long(&ptr
);
1594 mDNSInterfaceID InterfaceID
= mDNSPlatformInterfaceIDfromInterfaceIndex(&mDNSStorage
, ifi
);
1595 if (ifi
&& !InterfaceID
)
1597 deliver_error(rstate
, mStatus_BadParamErr
);
1598 abort_request(rstate
);
1599 unlink_request(rstate
);
1602 // allocate context structures
1603 def
= mallocL("hanlde_enum_request", sizeof(domain_enum_t
));
1604 all
= mallocL("handle_enum_request", sizeof(domain_enum_t
));
1605 term
= mallocL("handle_enum_request", sizeof(enum_termination_t
));
1606 if (!def
|| !all
|| !term
)
1608 my_perror("ERROR: malloc");
1612 // enumeration requires multiple questions, so we must link all the context pointers so that
1613 // necessary context can be reached from the callbacks
1614 def
->rstate
= rstate
;
1615 all
->rstate
= rstate
;
1618 term
->rstate
= rstate
;
1619 rstate
->termination_context
= term
;
1620 rstate
->terminate
= enum_termination_callback
;
1621 def
->question
.QuestionContext
= def
;
1622 def
->type
= (flags
& kDNSServiceFlagsRegistrationDomains
) ?
1623 mDNS_DomainTypeRegistrationDefault
: mDNS_DomainTypeBrowseDefault
;
1624 all
->question
.QuestionContext
= all
;
1625 all
->type
= (flags
& kDNSServiceFlagsRegistrationDomains
) ?
1626 mDNS_DomainTypeRegistration
: mDNS_DomainTypeBrowse
;
1629 err
= mDNS_GetDomains(&mDNSStorage
, &all
->question
, all
->type
, InterfaceID
, enum_result_callback
, all
);
1630 if (err
== mStatus_NoError
)
1631 err
= mDNS_GetDomains(&mDNSStorage
, &def
->question
, def
->type
, InterfaceID
, enum_result_callback
, def
);
1632 result
= deliver_error(rstate
, err
); // send error *before* returning local domain
1634 if (result
< 0 || err
)
1636 abort_request(rstate
);
1637 unlink_request(rstate
);
1641 // provide local. as the first domain automatically
1642 add_default
= kDNSServiceFlagsDefault
| kDNSServiceFlagsAdd
| kDNSServiceFlagsFinished
;
1643 reply
= format_enumeration_reply(rstate
, "local.", add_default
, ifi
, 0);
1644 tr
= send_msg(reply
);
1645 if (tr
== t_error
|| tr
== t_terminated
)
1647 freeL("handle_enum_request", def
);
1648 freeL("handle_enum_request", all
);
1649 abort_request(rstate
);
1650 unlink_request(rstate
);
1653 if (tr
== t_complete
) freeL("handle_enum_request", reply
);
1654 if (tr
== t_morecoming
) append_reply(rstate
, reply
); // couldn't send whole reply because client is blocked - link into list
1657 static void enum_result_callback(mDNS
*const m
, DNSQuestion
*question
, const ResourceRecord
*const answer
, mDNSBool AddRecord
)
1659 char domain
[MAX_ESCAPED_DOMAIN_NAME
];
1660 domain_enum_t
*de
= question
->QuestionContext
;
1661 DNSServiceFlags flags
= 0;
1665 if (answer
->rrtype
!= kDNSType_PTR
) return;
1668 flags
|= kDNSServiceFlagsAdd
;
1669 if (de
->type
== mDNS_DomainTypeRegistrationDefault
|| de
->type
== mDNS_DomainTypeBrowseDefault
)
1670 flags
|= kDNSServiceFlagsDefault
;
1674 flags
|= kDNSServiceFlagsRemove
;
1676 ConvertDomainNameToCString(&answer
->rdata
->u
.name
, domain
);
1677 reply
= format_enumeration_reply(de
->rstate
, domain
, flags
, mDNSPlatformInterfaceIndexfromInterfaceID(&mDNSStorage
, answer
->InterfaceID
), kDNSServiceErr_NoError
);
1680 LogMsg("ERROR: enum_result_callback, format_enumeration_reply");
1684 append_reply(de
->rstate
, reply
);
1688 static reply_state
*format_enumeration_reply(request_state
*rstate
, char *domain
, DNSServiceFlags flags
, uint32_t ifi
, DNSServiceErrorType err
)
1695 len
= sizeof(DNSServiceFlags
);
1696 len
+= sizeof(uint32_t);
1697 len
+= sizeof(DNSServiceErrorType
);
1698 len
+= strlen(domain
) + 1;
1700 reply
= create_reply(enumeration_reply
, len
, rstate
);
1701 reply
->rhdr
->flags
= flags
;
1702 reply
->rhdr
->ifi
= ifi
;
1703 reply
->rhdr
->error
= err
;
1704 data
= reply
->sdata
;
1705 put_string(domain
, &data
);
1709 static void enum_termination_callback(void *context
)
1711 enum_termination_t
*t
= context
;
1712 mDNS
*coredata
= &mDNSStorage
;
1714 mDNS_StopGetDomains(coredata
, &t
->all
->question
);
1715 mDNS_StopGetDomains(coredata
, &t
->def
->question
);
1716 freeL("enum_termination_callback", t
->all
);
1717 freeL("enum_termination_callback", t
->def
);
1718 t
->rstate
->termination_context
= NULL
;
1719 freeL("enum_termination_callback", t
);
1722 static void handle_reconfirm_request(request_state
*rstate
)
1726 rr
= read_rr_from_ipc_msg(rstate
->msgdata
, 0);
1728 mDNS_ReconfirmByValue(&mDNSStorage
, &rr
->resrec
);
1729 abort_request(rstate
);
1730 unlink_request(rstate
);
1731 freeL("handle_reconfirm_request", rr
);
1735 // setup rstate to accept new reg/dereg requests
1736 static void reset_connected_rstate(request_state
*rstate
)
1738 rstate
->ts
= t_morecoming
;
1739 rstate
->hdr_bytes
= 0;
1740 rstate
->data_bytes
= 0;
1741 if (rstate
->msgbuf
) freeL("reset_connected_rstate", rstate
->msgbuf
);
1742 rstate
->msgbuf
= NULL
;
1743 rstate
->bufsize
= 0;
1748 // returns a resource record (allocated w/ malloc) containing the data found in an IPC message
1749 // data must be in format flags, interfaceIndex, name, rrtype, rrclass, rdlen, rdata, (optional)ttl
1750 // (ttl only extracted/set if ttl argument is non-zero). returns NULL for a bad-parameter error
1751 static AuthRecord
*read_rr_from_ipc_msg(char *msgbuf
, int ttl
)
1753 char *rdata
, name
[256];
1755 DNSServiceFlags flags
;
1756 uint32_t interfaceIndex
;
1757 uint16_t type
, class, rdlen
;
1760 flags
= get_flags(&msgbuf
);
1761 interfaceIndex
= get_long(&msgbuf
);
1762 if (get_string(&msgbuf
, name
, 256) < 0)
1764 LogMsg("ERROR: read_rr_from_ipc_msg - get_string");
1767 type
= get_short(&msgbuf
);
1768 class = get_short(&msgbuf
);
1769 rdlen
= get_short(&msgbuf
);
1771 if (rdlen
> sizeof(RDataBody
)) storage_size
= rdlen
;
1772 else storage_size
= sizeof(RDataBody
);
1774 rr
= mallocL("read_rr_from_ipc_msg", sizeof(AuthRecord
) - sizeof(RDataBody
) + storage_size
);
1777 my_perror("ERROR: malloc");
1780 bzero(rr
, sizeof(AuthRecord
)); // ok if oversized rdata not zero'd
1781 rr
->resrec
.rdata
= &rr
->rdatastorage
;
1782 rr
->resrec
.InterfaceID
= mDNSPlatformInterfaceIDfromInterfaceIndex(&mDNSStorage
, interfaceIndex
);
1783 if (!MakeDomainNameFromDNSNameString(&rr
->resrec
.name
, name
))
1785 LogMsg("ERROR: bad name: %s", name
);
1786 freeL("read_rr_from_ipc_msg", rr
);
1789 rr
->resrec
.rrtype
= type
;
1790 if ((flags
& kDNSServiceFlagsShared
) == kDNSServiceFlagsShared
)
1791 rr
->resrec
.RecordType
= kDNSRecordTypeShared
;
1792 if ((flags
& kDNSServiceFlagsUnique
) == kDNSServiceFlagsUnique
)
1793 rr
->resrec
.RecordType
= kDNSRecordTypeUnique
;
1794 rr
->resrec
.rrclass
= class;
1795 rr
->resrec
.rdlength
= rdlen
;
1796 rr
->resrec
.rdata
->MaxRDLength
= rdlen
;
1797 rdata
= get_rdata(&msgbuf
, rdlen
);
1798 memcpy(rr
->resrec
.rdata
->u
.data
, rdata
, rdlen
);
1801 rr
->resrec
.rroriginalttl
= get_long(&msgbuf
);
1807 // generate a response message for a browse result, service registration result, or any other call with the
1808 // identical callback signature. on successful completion rep is set to point to a malloc'd reply_state struct,
1809 // and mStatus_NoError is returned. otherwise the appropriate error is returned.
1811 static mStatus
gen_rr_response(domainname
*servicename
, mDNSInterfaceID id
, request_state
*request
, reply_state
**rep
)
1816 domainname type
, dom
;
1817 char namestr
[MAX_DOMAIN_LABEL
+1]; // Unescaped name: up to 63 bytes plus C-string terminating NULL.
1818 char typestr
[MAX_ESCAPED_DOMAIN_NAME
];
1819 char domstr
[MAX_ESCAPED_DOMAIN_NAME
];
1823 if (!DeconstructServiceName(servicename
, &name
, &type
, &dom
))
1824 return kDNSServiceErr_Unknown
;
1826 ConvertDomainLabelToCString_unescaped(&name
, namestr
);
1827 ConvertDomainNameToCString(&type
, typestr
);
1828 ConvertDomainNameToCString(&dom
, domstr
);
1830 // calculate reply data length
1831 len
= sizeof(DNSServiceFlags
);
1832 len
+= sizeof(uint32_t); // if index
1833 len
+= sizeof(DNSServiceErrorType
);
1834 len
+= strlen(namestr
) + 1;
1835 len
+= strlen(typestr
) + 1;
1836 len
+= strlen(domstr
) + 1;
1838 *rep
= create_reply(query_reply
, len
, request
);
1839 (*rep
)->rhdr
->flags
= 0;
1840 (*rep
)->rhdr
->ifi
= mDNSPlatformInterfaceIndexfromInterfaceID(&mDNSStorage
, id
);
1841 (*rep
)->rhdr
->error
= kDNSServiceErr_NoError
;
1842 data
= (*rep
)->sdata
;
1844 put_string(namestr
, &data
);
1845 put_string(typestr
, &data
);
1846 put_string(domstr
, &data
);
1847 return mStatus_NoError
;
1851 static int build_domainname_from_strings(domainname
*srv
, char *name
, char *regtype
, char *domain
)
1856 if (!MakeDomainLabelFromLiteralString(&n
, name
)) return -1;
1857 if (!MakeDomainNameFromDNSNameString(&t
, regtype
)) return -1;
1858 if (!MakeDomainNameFromDNSNameString(&d
, domain
)) return -1;
1859 if (!ConstructServiceName(srv
, &n
, &t
, &d
)) return -1;
1864 // append a reply to the list in a request object
1865 static void append_reply(request_state
*req
, reply_state
*rep
)
1869 if (!req
->replies
) req
->replies
= rep
;
1873 while (ptr
->next
) ptr
= ptr
->next
;
1880 // read_msg may be called any time when the transfer state (rs->ts) is t_morecoming.
1881 // returns the current state of the request (morecoming, error, complete, terminated.)
1882 // if there is no data on the socket, the socket will be closed and t_terminated will be returned
1883 static int read_msg(request_state
*rs
)
1887 char buf
[4]; // dummy for death notification
1889 if (rs
->ts
== t_terminated
|| rs
->ts
== t_error
)
1891 LogMsg("ERROR: read_msg called with transfer state terminated or error");
1896 if (rs
->ts
== t_complete
)
1897 { // this must be death or something is wrong
1898 nread
= recv(rs
->sd
, buf
, 4, 0);
1899 if (!nread
) { rs
->ts
= t_terminated
; return t_terminated
; }
1900 if (nread
< 0) goto rerror
;
1901 LogMsg("ERROR: read data from a completed request.");
1906 if (rs
->ts
!= t_morecoming
)
1908 LogMsg("ERROR: read_msg called with invalid transfer state (%d)", rs
->ts
);
1913 if (rs
->hdr_bytes
< sizeof(ipc_msg_hdr
))
1915 nleft
= sizeof(ipc_msg_hdr
) - rs
->hdr_bytes
;
1916 nread
= recv(rs
->sd
, (char *)&rs
->hdr
+ rs
->hdr_bytes
, nleft
, 0);
1917 if (nread
== 0) { rs
->ts
= t_terminated
; return t_terminated
; }
1918 if (nread
< 0) goto rerror
;
1919 rs
->hdr_bytes
+= nread
;
1920 if (rs
->hdr_bytes
> sizeof(ipc_msg_hdr
))
1922 LogMsg("ERROR: read_msg - read too many header bytes");
1928 // only read data if header is complete
1929 if (rs
->hdr_bytes
== sizeof(ipc_msg_hdr
))
1931 if (rs
->hdr
.datalen
== 0) // ok in removerecord requests
1933 rs
->ts
= t_complete
;
1938 if (!rs
->msgbuf
) // allocate the buffer first time through
1940 rs
->msgbuf
= mallocL("read_msg", rs
->hdr
.datalen
);
1943 my_perror("ERROR: malloc");
1947 rs
->msgdata
= rs
->msgbuf
;
1949 nleft
= rs
->hdr
.datalen
- rs
->data_bytes
;
1950 nread
= recv(rs
->sd
, rs
->msgbuf
+ rs
->data_bytes
, nleft
, 0);
1951 if (nread
== 0) { rs
->ts
= t_terminated
; return t_terminated
; }
1952 if (nread
< 0) goto rerror
;
1953 rs
->data_bytes
+= nread
;
1954 if (rs
->data_bytes
> rs
->hdr
.datalen
)
1956 LogMsg("ERROR: read_msg - read too many data bytes");
1962 if (rs
->hdr_bytes
== sizeof(ipc_msg_hdr
) && rs
->data_bytes
== rs
->hdr
.datalen
)
1963 rs
->ts
= t_complete
;
1964 else rs
->ts
= t_morecoming
;
1969 if (errno
== EAGAIN
|| errno
== EINTR
) return rs
->ts
;
1970 my_perror("ERROR: read_msg");
1976 static int send_msg(reply_state
*rs
)
1982 LogMsg("ERROR: send_msg called with NULL message buffer");
1986 if (rs
->request
->no_reply
) //!!!KRS this behavior should be optimized if it becomes more common
1988 rs
->ts
= t_complete
;
1989 freeL("send_msg", rs
->msgbuf
);
1993 nwriten
= send(rs
->sd
, rs
->msgbuf
+ rs
->nwriten
, rs
->len
- rs
->nwriten
, 0);
1996 if (errno
== EINTR
|| errno
== EAGAIN
) nwriten
= 0;
2001 LogMsg("broken pipe - cleanup should be handled by run-loop read wakeup");
2002 rs
->ts
= t_terminated
;
2003 rs
->request
->ts
= t_terminated
;
2004 return t_terminated
;
2008 my_perror("ERROR: send\n");
2014 rs
->nwriten
+= nwriten
;
2016 if (rs
->nwriten
== rs
->len
)
2018 rs
->ts
= t_complete
;
2019 freeL("send_msg", rs
->msgbuf
);
2026 static reply_state
*create_reply(reply_op_t op
, int datalen
, request_state
*request
)
2032 if ((unsigned)datalen
< sizeof(reply_hdr
))
2034 LogMsg("ERROR: create_reply - data length less than lenght of required fields");
2038 totallen
= datalen
+ sizeof(ipc_msg_hdr
);
2039 reply
= mallocL("create_reply", sizeof(reply_state
));
2042 my_perror("ERROR: malloc");
2045 bzero(reply
, sizeof(reply_state
));
2046 reply
->ts
= t_morecoming
;
2047 reply
->sd
= request
->sd
;
2048 reply
->request
= request
;
2049 reply
->len
= totallen
;
2050 reply
->msgbuf
= mallocL("create_reply", totallen
);
2053 my_perror("ERROR: malloc");
2056 bzero(reply
->msgbuf
, totallen
);
2057 reply
->mhdr
= (ipc_msg_hdr
*)reply
->msgbuf
;
2058 reply
->rhdr
= (reply_hdr
*)(reply
->msgbuf
+ sizeof(ipc_msg_hdr
));
2059 reply
->sdata
= reply
->msgbuf
+ sizeof(ipc_msg_hdr
) + sizeof(reply_hdr
);
2060 reply
->mhdr
->version
= VERSION
;
2061 reply
->mhdr
->op
.reply_op
= op
;
2062 reply
->mhdr
->datalen
= totallen
- sizeof(ipc_msg_hdr
);
2067 static int deliver_error(request_state
*rstate
, mStatus err
)
2070 undelivered_error_t
*undeliv
;
2072 nwritten
= send(rstate
->errfd
, &err
, sizeof(mStatus
), 0);
2073 if (nwritten
< (int)sizeof(mStatus
))
2075 if (errno
== EINTR
|| errno
== EAGAIN
)
2079 my_perror("ERROR: send - unable to deliver error to client");
2082 //client blocked - store result and come backr
2083 undeliv
= mallocL("deliver_error", sizeof(undelivered_error_t
));
2086 my_perror("ERROR: malloc");
2090 undeliv
->nwritten
= nwritten
;
2091 undeliv
->sd
= rstate
->errfd
;
2092 rstate
->u_err
= undeliv
;
2095 if (rstate
->errfd
!= rstate
->sd
) close(rstate
->errfd
);
2099 if (rstate
->errfd
!= rstate
->sd
) close(rstate
->errfd
);
2105 // returns 0 on success, -1 if send is incomplete, or on terminal failre (request is aborted)
2106 static transfer_state
send_undelivered_error(request_state
*rs
)
2110 nwritten
= send(rs
->u_err
->sd
, (char *)(&rs
->u_err
) + rs
->u_err
->nwritten
, sizeof(mStatus
) - rs
->u_err
->nwritten
, 0);
2113 if (errno
== EINTR
|| errno
== EAGAIN
)
2117 my_perror("ERROR: send - unable to deliver error to client\n");
2118 if (rs
->u_err
->sd
== rs
->sd
) close (rs
->u_err
->sd
);
2122 if (nwritten
+ rs
->u_err
->nwritten
== sizeof(mStatus
))
2124 if (rs
->u_err
->sd
== rs
->sd
) close(rs
->u_err
->sd
);
2125 freeL("send_undelivered_error", rs
->u_err
);
2129 rs
->u_err
->nwritten
+= nwritten
;
2130 return t_morecoming
;
2134 // send bogus data along with an error code to the app callback
2135 // returns 0 on success (linking reply into list of not fully delivered),
2136 // -1 on failure (request should be aborted)
2137 static int deliver_async_error(request_state
*rs
, reply_op_t op
, mStatus err
)
2143 if (rs
->no_reply
) return 0;
2144 len
= 256; // long enough for any reply handler to read all args w/o buffer overrun
2145 reply
= create_reply(op
, len
, rs
);
2146 reply
->rhdr
->error
= err
;
2147 ts
= send_msg(reply
);
2148 if (ts
== t_error
|| ts
== t_terminated
)
2150 freeL("deliver_async_error", reply
);
2153 else if (ts
== t_complete
) freeL("deliver_async_error", reply
);
2154 else if (ts
== t_morecoming
) append_reply(rs
, reply
); // client is blocked, link reply into list
2159 static void abort_request(request_state
*rs
)
2161 reply_state
*rep
, *ptr
;
2163 if (rs
->terminate
) rs
->terminate(rs
->termination_context
); // terminate field may not be set yet
2164 if (rs
->msgbuf
) freeL("abort_request", rs
->msgbuf
);
2165 CFRunLoopRemoveSource(CFRunLoopGetCurrent(), rs
->rls
, kCFRunLoopDefaultMode
);
2166 CFRunLoopSourceInvalidate(rs
->rls
);
2168 CFSocketInvalidate(rs
->sr
);
2171 if (rs
->errfd
>= 0) close(rs
->errfd
);
2174 // free pending replies
2178 if (rep
->msgbuf
) freeL("abort_request", rep
->msgbuf
);
2181 freeL("abort_request", ptr
);
2186 freeL("abort_request", rs
->u_err
);
2192 static void unlink_request(request_state
*rs
)
2196 if (rs
== all_requests
)
2198 all_requests
= all_requests
->next
;
2199 freeL("unlink_request", rs
);
2202 for(ptr
= all_requests
; ptr
->next
; ptr
= ptr
->next
)
2203 if (ptr
->next
== rs
)
2205 ptr
->next
= rs
->next
;
2206 freeL("unlink_request", rs
);
2213 //hack to search-replace perror's to LogMsg's
2214 static void my_perror(char *errmsg
)
2216 LogMsg("%s: %s", errmsg
, strerror(errno
));