]> git.saurik.com Git - apple/mdnsresponder.git/blob - mDNSMacOSX/uds_daemon.c
c7df012fe47772d22f31b0a26b0054151819eea8
[apple/mdnsresponder.git] / mDNSMacOSX / uds_daemon.c
1 /*
2 * Copyright (c) 2003 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
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
11 * file.
12 *
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.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22
23 Change History (most recent first):
24
25 $Log: uds_daemon.c,v $
26 Revision 1.22 2003/08/19 16:03:55 ksekar
27 Bug #: <rdar://problem/3380097>: ER: SIGINFO dump should include resolves started by DNSServiceQueryRecord
28 Check termination_context for NULL before dereferencing.
29
30 Revision 1.21 2003/08/19 05:39:43 cheshire
31 <rdar://problem/3380097> SIGINFO dump should include resolves started by DNSServiceQueryRecord
32
33 Revision 1.20 2003/08/16 03:39:01 cheshire
34 <rdar://problem/3338440> InterfaceID -1 indicates "local only"
35
36 Revision 1.19 2003/08/15 20:16:03 cheshire
37 <rdar://problem/3366590> mDNSResponder takes too much RPRVT
38 We want to avoid touching the rdata pages, so we don't page them in.
39 1. RDLength was stored with the rdata, which meant touching the page just to find the length.
40 Moved this from the RData to the ResourceRecord object.
41 2. To avoid unnecessarily touching the rdata just to compare it,
42 compute a hash of the rdata and store the hash in the ResourceRecord object.
43
44 Revision 1.18 2003/08/15 00:38:00 ksekar
45 Bug #: <rdar://problem/3377005>: Bug: buffer overrun when reading long rdata from client
46
47 Revision 1.17 2003/08/14 02:18:21 cheshire
48 <rdar://problem/3375491> Split generic ResourceRecord type into two separate types: AuthRecord and CacheRecord
49
50 Revision 1.16 2003/08/13 23:58:52 ksekar
51 Bug #: <rdar://problem/3374911>: Bug: UDS Sub-type browsing works, but not sub-type registration
52 Fixed pointer increment error, moved subtype reading for-loop for easier error bailout.
53
54 Revision 1.15 2003/08/13 17:30:33 ksekar
55 Bug #: <rdar://problem/3374671>: DNSServiceAddRecord doesn't work
56 Fixed various problems with handling the AddRecord request and freeing the ExtraResourceRecords.
57
58 Revision 1.14 2003/08/12 19:56:25 cheshire
59 Update to APSL 2.0
60
61 */
62
63 #include "mDNSClientAPI.h"
64 #include "mDNSMacOSX.h"
65 #include "dns_sd.h"
66 #include "dnssd_ipc.h"
67 #include <fcntl.h>
68 #include <sys/ioctl.h>
69 #include <sys/types.h>
70 #include <sys/time.h>
71 #include <sys/resource.h>
72
73 // Types and Data Structures
74 // ----------------------------------------------------------------------
75
76 typedef enum
77 {
78 t_uninitialized,
79 t_morecoming,
80 t_complete,
81 t_error,
82 t_terminated
83 } transfer_state;
84
85 typedef void (*req_termination_fn)(void *);
86
87
88 typedef struct registered_record_entry
89 {
90 int key;
91 AuthRecord *rr;
92 struct registered_record_entry *next;
93 } registered_record_entry;
94
95 typedef struct registered_service
96 {
97 //struct registered_service *next;
98 int autoname;
99 int renameonconflict;
100 int rename_on_memfree; // set flag on config change when we deregister original name
101 domainlabel name;
102 ServiceRecordSet *srs;
103 struct request_state *request;
104 AuthRecord *subtypes;
105 } registered_service;
106
107 typedef struct
108 {
109 mStatus err;
110 int nwritten;
111 int sd;
112 } undelivered_error_t;
113
114 typedef struct request_state
115 {
116 // connection structures
117 CFRunLoopSourceRef rls;
118 CFSocketRef sr;
119 int sd;
120 int errfd;
121
122 // state of read (in case message is read over several recv() calls)
123 transfer_state ts;
124 uint32_t hdr_bytes; // bytes of header already read
125 ipc_msg_hdr hdr;
126 uint32_t data_bytes; // bytes of message data already read
127 char *msgbuf; // pointer to data storage to pass to free()
128 char *msgdata; // pointer to data to be read from (may be modified)
129 int bufsize; // size of data storage
130
131 // reply, termination, error, and client context info
132 int no_reply; // don't send asynchronous replies to client
133 void *client_context; // don't touch this - pointer only valid in client's addr space
134 struct reply_state *replies; // corresponding (active) reply list
135 undelivered_error_t *u_err;
136 void *termination_context;
137 req_termination_fn terminate;
138
139 //!!!KRS toss these pointers in a union
140 // registration context associated with this request (null if not applicable)
141 registered_record_entry *reg_recs; // muliple registrations for a connection-oriented request
142 registered_service *service; // service record set and flags
143 struct resolve_result_t *resolve_results;
144
145 struct request_state *next;
146 } request_state;
147
148 // struct physically sits between ipc message header and call-specific fields in the message buffer
149 typedef struct
150 {
151 DNSServiceFlags flags;
152 uint32_t ifi;
153 DNSServiceErrorType error;
154 } reply_hdr;
155
156
157 typedef struct reply_state
158 {
159 // state of the transmission
160 int sd;
161 transfer_state ts;
162 uint32_t nwriten;
163 uint32_t len;
164 // context of the reply
165 struct request_state *request; // the request that this answers
166 struct reply_state *next; // if there are multiple unsent replies
167 // pointer into message buffer - allows fields to be changed after message is formatted
168 ipc_msg_hdr *mhdr;
169 reply_hdr *rhdr;
170 char *sdata; // pointer to start of call-specific data
171 // pointer to malloc'd buffer
172 char *msgbuf;
173 } reply_state;
174
175
176 // domain enumeration and resolv calls require 2 mDNSCore calls, so we need separate interconnected
177 // structures to handle callbacks
178 typedef struct
179 {
180 DNSQuestion question;
181 mDNS_DomainType type;
182 request_state *rstate;
183 } domain_enum_t;
184
185 typedef struct
186 {
187 domain_enum_t *all;
188 domain_enum_t *def;
189 request_state *rstate;
190 } enum_termination_t;
191
192 typedef struct
193 {
194 DNSQuestion question;
195 uint16_t qtype;
196 request_state *rstate;
197 } resolve_t;
198
199 typedef struct
200 {
201 resolve_t *txt;
202 resolve_t *srv;
203 request_state *rstate;
204 } resolve_termination_t;
205
206 typedef struct resolve_result_t
207 {
208 const ResourceRecord *txt;
209 const ResourceRecord *srv;
210 } resolve_result_t;
211
212 typedef struct
213 {
214 request_state *rstate;
215 client_context_t client_context;
216 } regrecord_callback_context;
217
218
219
220
221 // globals
222 static int listenfd = -1;
223 static request_state *all_requests = NULL;
224 //!!!KRS we should keep a separate list containing only the requests that need to be examined
225 //in the idle() routine.
226
227
228 #define MAX_OPENFILES 1024
229
230
231 // private function prototypes
232 static void connect_callback(CFSocketRef sr, CFSocketCallBackType t, CFDataRef dr, const void *c, void *i);
233 static int read_msg(request_state *rs);
234 static int send_msg(reply_state *rs);
235 static void abort_request(request_state *rs);
236 static void request_callback(CFSocketRef sr, CFSocketCallBackType t, CFDataRef dr, const void *c, void *i);
237 static void handle_resolve_request(request_state *rstate);
238 static void question_result_callback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord);
239 static void question_termination_callback(void *context);
240 static void handle_browse_request(request_state *request);
241 static void browse_termination_callback(void *context);
242 static void browse_result_callback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord);
243 static void handle_regservice_request(request_state *request);
244 static void regservice_termination_callback(void *context);
245 static void process_service_registration(ServiceRecordSet *const srs);
246 static void regservice_callback(mDNS *const m, ServiceRecordSet *const srs, mStatus result);
247 static void handle_add_request(request_state *rstate);
248 static void handle_update_request(request_state *rstate);
249 static mStatus gen_rr_response(domainname *servicename, mDNSInterfaceID id, request_state *request, reply_state **rep);
250 static void append_reply(request_state *req, reply_state *rep);
251 static int build_domainname_from_strings(domainname *srv, char *name, char *regtype, char *domain);
252 static void enum_termination_callback(void *context);
253 static void enum_result_callback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord);
254 static void handle_query_request(request_state *rstate);
255 static mStatus do_question(request_state *rstate, domainname *name, uint32_t ifi, uint16_t rrtype, int16_t rrclass);
256 static reply_state *format_enumeration_reply(request_state *rstate, char *domain, DNSServiceFlags flags, uint32_t ifi, DNSServiceErrorType err);
257 static void handle_enum_request(request_state *rstate);
258 static void handle_regrecord_request(request_state *rstate);
259 static void regrecord_callback(mDNS *const m, AuthRecord *const rr, mStatus result);
260 static void connected_registration_termination(void *context);
261 static void handle_reconfirm_request(request_state *rstate);
262 static AuthRecord *read_rr_from_ipc_msg(char *msgbuf, int ttl);
263 static void handle_removerecord_request(request_state *rstate);
264 static void reset_connected_rstate(request_state *rstate);
265 static int deliver_error(request_state *rstate, mStatus err);
266 static int deliver_async_error(request_state *rs, reply_op_t op, mStatus err);
267 static transfer_state send_undelivered_error(request_state *rs);
268 static reply_state *create_reply(reply_op_t op, int datalen, request_state *request);
269 static void update_callback(mDNS *const m, AuthRecord *const rr, RData *oldrd);
270 static void my_perror(char *errmsg);
271 static void unlink_request(request_state *rs);
272 static void resolve_result_callback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord);
273 static void resolve_termination_callback(void *context);
274
275 // initialization, setup/teardown functions
276
277 int udsserver_init(void)
278 {
279 mode_t mask;
280 struct sockaddr_un laddr;
281 struct rlimit maxfds;
282
283 if ((listenfd = socket(AF_LOCAL, SOCK_STREAM, 0)) < 0)
284 goto error;
285 unlink(MDNS_UDS_SERVERPATH); //OK if this fails
286 bzero(&laddr, sizeof(laddr));
287 laddr.sun_family = AF_LOCAL;
288 laddr.sun_len = sizeof(struct sockaddr_un);
289 strcpy(laddr.sun_path, MDNS_UDS_SERVERPATH);
290 mask = umask(0);
291 if (bind(listenfd, (struct sockaddr *)&laddr, sizeof(laddr)) < 0)
292 goto error;
293 umask(mask);
294
295 if (fcntl(listenfd, F_SETFL, O_NONBLOCK) < 0)
296 {
297 my_perror("ERROR: could not set listen socket to non-blocking mode");
298 goto error;
299 }
300 listen(listenfd, LISTENQ);
301
302
303 // set maximum file descriptor to 1024
304 if (getrlimit(RLIMIT_NOFILE, &maxfds) < 0)
305 {
306 my_perror("ERROR: Unable to get file descriptor limit");
307 return 0;
308 }
309 if (maxfds.rlim_max >= MAX_OPENFILES && maxfds.rlim_cur == maxfds.rlim_max)
310 {
311 // proper values already set
312 return 0;
313 }
314 maxfds.rlim_max = MAX_OPENFILES;
315 maxfds.rlim_cur = MAX_OPENFILES;
316 if (setrlimit(RLIMIT_NOFILE, &maxfds) < 0)
317 my_perror("ERROR: Unable to set maximum file descriptor limit");
318 return 0;
319
320 error:
321 my_perror("ERROR: udsserver_init");
322 return -1;
323 }
324
325 int udsserver_exit(void)
326 {
327 close(listenfd);
328 unlink(MDNS_UDS_SERVERPATH);
329 return 0;
330 }
331
332
333 // add the named socket as a runloop source
334 int udsserver_add_rl_source(void)
335 {
336 CFSocketContext context = { 0, NULL, NULL, NULL, NULL };
337 CFSocketRef sr = CFSocketCreateWithNative(kCFAllocatorDefault, listenfd, kCFSocketReadCallBack, connect_callback, &context);
338 if (!sr)
339 {
340 debugf("ERROR: udsserver_add_rl_source - CFSocketCreateWithNative");
341 return -1;
342 }
343 CFRunLoopSourceRef rls = CFSocketCreateRunLoopSource(kCFAllocatorDefault, sr, 0);
344
345 if (!rls)
346 {
347 debugf("ERROR: udsserver_add_rl_source - CFSocketCreateRunLoopSource");
348 return -1;
349 }
350 CFRunLoopAddSource(CFRunLoopGetCurrent(), rls, kCFRunLoopDefaultMode);
351 return 0;
352 }
353
354 mDNSs32 udsserver_idle(mDNSs32 nextevent)
355 {
356 request_state *req = all_requests, *tmp, *prev = NULL;
357 reply_state *fptr;
358 transfer_state result;
359 mDNSs32 now = mDNSPlatformTimeNow();
360
361
362 while(req)
363 {
364 result = t_uninitialized;
365 if (req->u_err)
366 result = send_undelivered_error(req);
367 if (result != t_error && result != t_morecoming && // don't try to send msg if send_error failed
368 (req->ts == t_complete || req->ts == t_morecoming))
369 {
370 while(req->replies)
371 {
372 if (req->replies->next) req->replies->rhdr->flags |= kDNSServiceFlagsMoreComing;
373 else req->replies->rhdr->flags |= kDNSServiceFlagsFinished;
374 result = send_msg(req->replies);
375 if (result == t_complete)
376 {
377 fptr = req->replies;
378 req->replies = req->replies->next;
379 freeL("udsserver_idle", fptr);
380 }
381 else if (result == t_terminated || result == t_error)
382 {
383 abort_request(req);
384 break;
385 }
386 else if (result == t_morecoming) // client's queues are full, move to next
387 {
388 if (nextevent - now > mDNSPlatformOneSecond)
389 nextevent = now + mDNSPlatformOneSecond;
390 break; // start where we left off in a second
391 }
392 }
393 }
394 if (result == t_terminated || result == t_error)
395 //since we're already doing a list traversal, we unlink the request manunally instead of calling unlink_request()
396 {
397 tmp = req;
398 if (prev) prev->next = req->next;
399 if (req == all_requests) all_requests = all_requests->next;
400 req = req->next;
401 freeL("udsserver_idle", tmp);
402 }
403 else
404 {
405 prev = req;
406 req = req->next;
407 }
408 }
409 return nextevent;
410 }
411
412 void udsserver_info(void)
413 {
414 request_state *req;
415 for (req = all_requests; req; req=req->next)
416 {
417 void *t = req->termination_context;
418 if (!t) continue;
419 if (req->terminate == regservice_termination_callback)
420 LogMsg("DNSServiceRegister %##s", ((registered_service *) t)->srs->RR_SRV.resrec.name.c);
421 else if (req->terminate == browse_termination_callback)
422 LogMsg("DNSServiceBrowse %##s", ((DNSQuestion *) t)->qname.c);
423 else if (req->terminate == resolve_termination_callback)
424 LogMsg("DNSServiceResolve %##s", ((resolve_termination_t *)t)->srv->question.qname.c);
425 else if (req->terminate == question_termination_callback)
426 LogMsg("DNSServiceQueryRecord %##s", ((DNSQuestion *) t)->qname.c);
427 else if (req->terminate == enum_termination_callback)
428 LogMsg("DNSServiceEnumerateDomains %##s", ((enum_termination_t *) t)->all->question.qname.c);
429 }
430 }
431
432 void udsserver_handle_configchange(void)
433 {
434 registered_service *srv;
435 request_state *req;
436 mStatus err;
437
438 for (req = all_requests; req; req = req->next)
439 {
440 srv = req->service;
441 if (srv->autoname && !SameDomainLabel(srv->name.c, mDNSStorage.nicelabel.c))
442 {
443 srv->rename_on_memfree = 1;
444 err = mDNS_DeregisterService(&mDNSStorage, srv->srs);
445 if (err) LogMsg("ERROR: udsserver_handle_configchange: DeregisterService returned error %d. Continuing.", err);
446 // error should never occur - safest to log and continue
447 }
448 }
449 }
450
451
452
453
454 // accept a connection on the named socket, adding the new descriptor to the runloop and passing the error
455 // descriptor to the client
456 static void connect_callback(CFSocketRef s, CFSocketCallBackType t, CFDataRef dr, const void *c, void *i)
457 {
458 int sd, clilen, optval;
459 struct sockaddr_un cliaddr;
460 CFSocketContext context = { 0, NULL, NULL, NULL, NULL };
461 request_state *rstate;
462 // int errpipe[2];
463
464 #pragma unused(s, t, dr, c, i)
465
466 clilen = sizeof(cliaddr);
467 sd = accept(listenfd, (struct sockaddr *)&cliaddr, &clilen);
468
469 if (sd < 0)
470 {
471 if (errno == EWOULDBLOCK) return;
472 my_perror("ERROR: accept");
473 return;
474 }
475 optval = 1;
476 if (setsockopt(sd, SOL_SOCKET, SO_NOSIGPIPE, &optval, sizeof(optval)) < 0)
477 {
478 my_perror("ERROR: setsockopt - SOL_NOSIGPIPE - aborting client");
479 close(sd);
480 return;
481 }
482
483 if (fcntl(sd, F_SETFL, O_NONBLOCK) < 0)
484 {
485 my_perror("ERROR: could not set connected socket to non-blocking mode - aborting client");
486 close(sd);
487 return;
488 }
489
490 /*
491 // open a pipe to deliver error messages, pass descriptor to client
492 if (pipe(errpipe) < 0)
493 {
494 my_perror("ERROR: could not create pipe");
495 exit(1);
496 }
497
498 if (ioctl(sd, I_SENDFD, errpipe[0]) < 0)
499 {
500 my_perror("ERROR: could not pass pipe descriptor to client. Aborting client.\n");
501 close(sd);
502 return;
503 }
504 if (fcntl(errpipe[1], F_SETFL, O_NONBLOCK) < 0)
505 {
506 my_perror("ERROR: could not set error pipe to non-blocking mode - aborting client");
507 close(sd);
508 close(errpipe[1]);
509 return;
510 }
511 */
512
513 // allocate a request_state struct that will live with the socket
514 rstate = mallocL("connect_callback", sizeof(request_state));
515 if (!rstate)
516 {
517 my_perror("ERROR: malloc");
518 exit(1);
519 }
520 bzero(rstate, sizeof(request_state));
521 rstate->ts = t_morecoming;
522 rstate->sd = sd;
523 //rstate->errfd = errpipe[1];
524
525 //now create CFSocket wrapper and add to run loop
526 context.info = rstate;
527 rstate->sr = CFSocketCreateWithNative(kCFAllocatorDefault, sd, kCFSocketReadCallBack, request_callback, &context);
528 if (!rstate->sr)
529 {
530 debugf("ERROR: connect_callback - CFSocketCreateWithNative");
531 freeL("connect_callback", rstate);
532 close(sd);
533 return;
534 }
535 rstate->rls = CFSocketCreateRunLoopSource(kCFAllocatorDefault, rstate->sr, 0);
536 if (!rstate->rls)
537 {
538 debugf("ERROR: connect_callback - CFSocketCreateRunLoopSource");
539 CFSocketInvalidate(rstate->sr); // automatically closes socket
540 CFRelease(rstate->sr);
541 freeL("connect_callback", rstate);
542 return;
543 }
544 CFRunLoopAddSource(CFRunLoopGetCurrent(), rstate->rls, kCFRunLoopDefaultMode);
545 if (!CFRunLoopContainsSource(CFRunLoopGetCurrent(), rstate->rls, kCFRunLoopDefaultMode))
546 {
547 LogMsg("ERROR: connect_callback, CFRunLoopAddSource");
548 abort_request(rstate);
549 return;
550 }
551 rstate->next = all_requests;
552 all_requests = rstate;
553 }
554
555
556 // main client request handling routine. reads request and calls the appropriate request-specific
557 // handler
558 static void request_callback(CFSocketRef sr, CFSocketCallBackType t, CFDataRef dr, const void *context, void *info)
559 {
560 request_state *rstate = info;
561 transfer_state result;
562 struct sockaddr_un cliaddr;
563 char ctrl_path[MAX_CTLPATH];
564
565 #pragma unused(sr, t, dr, context)
566
567 int native = CFSocketGetNative(sr);
568 if (native != rstate->sd)
569 {
570 LogMsg("ERROR: request_callback - CFSocket's native descriptor does not match rstate member descriptor.");
571 abort_request(rstate);
572 unlink_request(rstate);
573 return;
574 }
575
576 result = read_msg(rstate);
577 if (result == t_morecoming)
578 {
579 return;
580 }
581 if (result == t_terminated)
582 {
583 abort_request(rstate);
584 unlink_request(rstate);
585 return;
586 }
587 if (result == t_error)
588 {
589 abort_request(rstate);
590 unlink_request(rstate);
591 return;
592 }
593
594 if (rstate->hdr.version != VERSION)
595 {
596 LogMsg("ERROR: client incompatible with daemon (client version = %d, "
597 "daemon version = %d)\n", rstate->hdr.version, VERSION);
598 abort_request(rstate);
599 unlink_request(rstate);
600 return;
601 }
602
603 // check if client wants silent operation
604 if (rstate->hdr.flags & IPC_FLAGS_NOREPLY) rstate->no_reply = 1;
605
606 // check if primary socket is to be used for synchronous errors, else open new socket
607 if (rstate->hdr.flags & IPC_FLAGS_REUSE_SOCKET)
608 rstate->errfd = rstate->sd;
609 else
610 {
611 if ((rstate->errfd = socket(AF_LOCAL, SOCK_STREAM, 0)) < 0)
612 {
613 my_perror("ERROR: socket");
614 exit(1);
615 }
616 if (fcntl(rstate->errfd, F_SETFL, O_NONBLOCK) < 0)
617 {
618 my_perror("ERROR: could not set control socket to non-blocking mode");
619 abort_request(rstate);
620 unlink_request(rstate);
621 return;
622 }
623 get_string(&rstate->msgdata, ctrl_path, 256); // path is first element in message buffer
624 bzero(&cliaddr, sizeof(cliaddr));
625 cliaddr.sun_family = AF_LOCAL;
626 strcpy(cliaddr.sun_path, ctrl_path);
627 if (connect(rstate->errfd, (struct sockaddr *)&cliaddr, sizeof(cliaddr)) < 0)
628 {
629 my_perror("ERROR: connect");
630 abort_request(rstate);
631 unlink_request(rstate);
632 }
633 }
634
635
636
637
638 switch(rstate->hdr.op.request_op)
639 {
640 case resolve_request: handle_resolve_request(rstate); break;
641 case query_request: handle_query_request(rstate); break;
642 case browse_request: handle_browse_request(rstate); break;
643 case reg_service_request: handle_regservice_request(rstate); break;
644 case enumeration_request: handle_enum_request(rstate); break;
645 case reg_record_request: handle_regrecord_request(rstate); break;
646 case add_record_request: handle_add_request(rstate); break;
647 case update_record_request: handle_update_request(rstate); break;
648 case remove_record_request: handle_removerecord_request(rstate); break;
649 case reconfirm_record_request: handle_reconfirm_request(rstate); break;
650 default:
651 debugf("ERROR: udsserver_recv_request - unsupported request type: %d", rstate->hdr.op.request_op);
652 }
653 }
654
655 // mDNS operation functions. Each operation has 3 associated functions - a request handler that parses
656 // the client's request and makes the appropriate mDNSCore call, a result handler (passed as a callback
657 // to the mDNSCore routine) that sends results back to the client, and a termination routine that aborts
658 // the mDNSCore operation if the client dies or closes its socket.
659
660
661 // query and resolve calls have separate request handlers that parse the arguments from the client and
662 // massage the name parameters appropriately, but the rest of the operations (making the query call,
663 // delivering the result to the client, and termination) are identical.
664
665 static void handle_query_request(request_state *rstate)
666 {
667 DNSServiceFlags flags;
668 uint32_t interfaceIndex;
669 char name[256];
670 uint16_t rrtype, rrclass;
671 char *ptr;
672 domainname dname;
673 mStatus result;
674
675 if (rstate->ts != t_complete)
676 {
677 LogMsg("ERROR: handle_query_request - transfer state != t_complete");
678 goto error;
679 }
680 ptr = rstate->msgdata;
681 if (!ptr)
682 {
683 LogMsg("ERROR: handle_query_request - NULL msgdata");
684 goto error;
685 }
686 flags = get_flags(&ptr);
687 interfaceIndex = get_long(&ptr);
688 if (get_string(&ptr, name, 256) < 0) goto bad_param;
689 rrtype = get_short(&ptr);
690 rrclass = get_short(&ptr);
691 if (!MakeDomainNameFromDNSNameString(&dname, name)) goto bad_param;
692 result = do_question(rstate, &dname, interfaceIndex, rrtype, rrclass);
693 if (result) rstate->terminate = NULL;
694 if (deliver_error(rstate, result) < 0) goto error;
695 return;
696
697 bad_param:
698 deliver_error(rstate, mStatus_BadParamErr);
699 rstate->terminate = NULL; // don't try to terminate insuccessful Core calls
700 error:
701 abort_request(rstate);
702 unlink_request(rstate);
703 return;
704 }
705
706 static void handle_resolve_request(request_state *rstate)
707 {
708 DNSServiceFlags flags;
709 uint32_t interfaceIndex;
710 char name[256], regtype[256], domain[256];
711 char *ptr; // message data pointer
712 domainname fqdn;
713 resolve_t *srv, *txt;
714 resolve_termination_t *term;
715 mStatus err;
716
717 if (rstate->ts != t_complete)
718 {
719 LogMsg("ERROR: handle_resolve_request - transfer state != t_complete");
720 abort_request(rstate);
721 unlink_request(rstate);
722 return;
723 }
724
725 // extract the data from the message
726 ptr = rstate->msgdata;
727 if (!ptr)
728 {
729 LogMsg("ERROR: handle_resolve_request - NULL msgdata");
730 abort_request(rstate);
731 unlink_request(rstate);
732 return;
733 }
734 flags = get_flags(&ptr);
735 interfaceIndex = get_long(&ptr);
736 mDNSInterfaceID InterfaceID = mDNSPlatformInterfaceIDfromInterfaceIndex(&mDNSStorage, interfaceIndex);
737 if (interfaceIndex && !InterfaceID) goto bad_param;
738 if (get_string(&ptr, name, 256) < 0 ||
739 get_string(&ptr, regtype, 256) < 0 ||
740 get_string(&ptr, domain, 256) < 0)
741 goto bad_param;
742
743 // free memory in rstate since we don't need it anymore
744 freeL("handle_resolve_request", rstate->msgbuf);
745 rstate->msgbuf = NULL;
746
747 if (build_domainname_from_strings(&fqdn, name, regtype, domain) < 0)
748 goto bad_param;
749
750 // allocate question wrapper structs
751 srv = mallocL("handle_resolve_request", sizeof(resolve_t));
752 txt = mallocL("handle_resolve_request", sizeof(resolve_t));
753 if (!srv || !txt) goto malloc_error;
754 srv->qtype = kDNSType_SRV;
755 txt->qtype = kDNSType_TXT;
756 srv->rstate = rstate;
757 txt->rstate = rstate;
758
759 // format questions
760 srv->question.QuestionContext = rstate;
761 srv->question.QuestionCallback = resolve_result_callback;
762 memcpy(&srv->question.qname, &fqdn, MAX_DOMAIN_NAME);
763 srv->question.qtype = kDNSType_SRV;
764 srv->question.qclass = kDNSClass_IN;
765 srv->question.InterfaceID = InterfaceID;
766
767 txt->question.QuestionContext = rstate;
768 txt->question.QuestionCallback = resolve_result_callback;
769 memcpy(&txt->question.qname, &fqdn, MAX_DOMAIN_NAME);
770 txt->question.qtype = kDNSType_TXT;
771 txt->question.qclass = kDNSClass_IN;
772 txt->question.InterfaceID = InterfaceID;
773
774 // set up termination info
775 term = mallocL("handle_resolve_request", sizeof(resolve_termination_t));
776 if (!term) goto malloc_error;
777 term->srv = srv;
778 term->txt = txt;
779 term->rstate = rstate;
780 rstate->termination_context = term;
781 rstate->terminate = resolve_termination_callback;
782
783 // set up reply wrapper struct (since answer will come via 2 callbacks)
784 rstate->resolve_results = mallocL("handle_resolve_response", sizeof(resolve_result_t));
785 if (!rstate->resolve_results) goto malloc_error;
786 bzero(rstate->resolve_results, sizeof(resolve_result_t));
787
788 // ask the questions
789 err = mDNS_StartQuery(&mDNSStorage, &srv->question);
790 if (!err) err = mDNS_StartQuery(&mDNSStorage, &txt->question);
791
792 if (err)
793 {
794 freeL("handle_resolve_request", txt);
795 freeL("handle_resolve_request", srv);
796 freeL("handle_resolve_request", term);
797 freeL("handle_resolve_request", rstate->resolve_results);
798 rstate->terminate = NULL; // prevent abort_request() from invoking termination callback
799 }
800 if (deliver_error(rstate, err) < 0 || err)
801 {
802 abort_request(rstate);
803 unlink_request(rstate);
804 }
805 return;
806
807 bad_param:
808 deliver_error(rstate, mStatus_BadParamErr);
809 abort_request(rstate);
810 unlink_request(rstate);
811 return;
812
813 malloc_error:
814 my_perror("ERROR: malloc");
815 exit(1);
816 }
817
818 static void resolve_termination_callback(void *context)
819 {
820 resolve_termination_t *term = context;
821 request_state *rs;
822
823 if (!term)
824 {
825 LogMsg("ERROR: resolve_termination_callback: double termination");
826 return;
827 }
828 rs = term->rstate;
829
830 mDNS_StopQuery(&mDNSStorage, &term->txt->question);
831 mDNS_StopQuery(&mDNSStorage, &term->srv->question);
832
833 freeL("resolve_termination_callback", term->txt);
834 freeL("resolve_termination_callback", term->srv);
835 freeL("resolve_termination_callback", term);
836 rs->termination_context = NULL;
837 freeL("resolve_termination_callback", rs->resolve_results);
838 rs->resolve_results = NULL;
839 }
840
841
842
843 static void resolve_result_callback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord)
844 {
845 int len = 0;
846 char fullname[MAX_DOMAIN_NAME], target[MAX_DOMAIN_NAME];
847 char *data;
848 transfer_state result;
849 reply_state *rep;
850 request_state *rs = question->QuestionContext;
851 resolve_result_t *res = rs->resolve_results;
852 #pragma unused(m)
853
854 if (!AddRecord)
855 {
856 if (answer->rrtype == kDNSType_TXT && res->txt == answer) res->txt = mDNSNULL;
857 if (answer->rrtype == kDNSType_SRV && res->srv == answer) res->srv = mDNSNULL;
858 return;
859 }
860
861 if (answer->rrtype == kDNSType_TXT) res->txt = answer;
862 if (answer->rrtype == kDNSType_SRV) res->srv = answer;
863
864 if (!res->txt || !res->srv) return; // only deliver result to client if we have both answers
865
866 ConvertDomainNameToCString(&answer->name, fullname);
867 ConvertDomainNameToCString(&res->srv->rdata->u.srv.target, target);
868
869 // calculate reply length
870 len += sizeof(DNSServiceFlags);
871 len += sizeof(uint32_t); // interface index
872 len += sizeof(DNSServiceErrorType);
873 len += strlen(fullname) + 1;
874 len += strlen(target) + 1;
875 len += 2 * sizeof(uint16_t); // port, txtLen
876 len += res->txt->rdlength;
877
878 // allocate/init reply header
879 rep = create_reply(resolve_reply, len, rs);
880 rep->rhdr->flags = 0;
881 rep->rhdr->ifi = mDNSPlatformInterfaceIndexfromInterfaceID(&mDNSStorage, answer->InterfaceID);
882 rep->rhdr->error = kDNSServiceErr_NoError;
883 data = rep->sdata;
884
885 // write reply data to message
886 put_string(fullname, &data);
887 put_string(target, &data);
888 put_short(res->srv->rdata->u.srv.port.NotAnInteger, &data);
889 put_short(res->txt->rdlength, &data);
890 put_rdata(res->txt->rdlength, res->txt->rdata->u.txt.c, &data);
891
892 result = send_msg(rep);
893 if (result == t_error || result == t_terminated)
894 {
895 abort_request(rs);
896 unlink_request(rs);
897 freeL("resolve_result_callback", rep);
898 }
899 else if (result == t_complete) freeL("resolve_result_callback", rep);
900 else append_reply(rs, rep);
901 }
902
903
904
905
906 // common query issuing routine for resolve and query requests
907 static mStatus do_question(request_state *rstate, domainname *name, uint32_t ifi, uint16_t rrtype, int16_t rrclass)
908 {
909 DNSQuestion *q;
910 mStatus result;
911 mDNSInterfaceID InterfaceID = mDNSPlatformInterfaceIDfromInterfaceIndex(&mDNSStorage, ifi);
912 if (ifi && !InterfaceID) return(mStatus_BadParamErr);
913
914 q = mallocL("do_question", sizeof(DNSQuestion));
915 if (!q)
916 {
917 my_perror("ERROR: do_question - malloc");
918 exit(1);
919 }
920 bzero(q, sizeof(DNSQuestion));
921
922 q->QuestionContext = rstate;
923 q->QuestionCallback = question_result_callback;
924 memcpy(&q->qname, name, MAX_DOMAIN_NAME);
925 q->qtype = rrtype;
926 q->qclass = rrclass;
927 q->InterfaceID = InterfaceID;
928
929
930 rstate->termination_context = q;
931 rstate->terminate = question_termination_callback;
932
933 result = mDNS_StartQuery(&mDNSStorage, q);
934 if (result != mStatus_NoError) LogMsg("ERROR: mDNS_StartQuery: %d", (int)result);
935 return result;
936 }
937
938 // what gets called when a resolve is completed and we need to send the data back to the client
939 static void question_result_callback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord)
940 {
941 char *data;
942 char name[256];
943 request_state *req;
944 reply_state *rep;
945 int len;
946
947 #pragma unused(m)
948 //mDNS_StopQuery(m, question);
949 req = question->QuestionContext;
950
951 // calculate reply data length
952 len = sizeof(DNSServiceFlags);
953 len += 2 * sizeof(uint32_t); // if index + ttl
954 len += sizeof(DNSServiceErrorType);
955 len += 3 * sizeof(uint16_t); // type, class, rdlen
956 len += answer->rdlength;
957 ConvertDomainNameToCString(&answer->name, name);
958 len += strlen(name) + 1;
959
960 rep = create_reply(query_reply, len, req);
961 rep->rhdr->flags = AddRecord ? kDNSServiceFlagsAdd : kDNSServiceFlagsRemove;
962 rep->rhdr->ifi = mDNSPlatformInterfaceIndexfromInterfaceID(&mDNSStorage, answer->InterfaceID);
963 rep->rhdr->error = kDNSServiceErr_NoError;
964 data = rep->sdata;
965
966 put_string(name, &data);
967 put_short(answer->rrtype, &data);
968 put_short(answer->rrclass, &data);
969 put_short(answer->rdlength, &data);
970 put_rdata(answer->rdlength, (char *)&answer->rdata->u, &data);
971 put_long(AddRecord ? answer->rroriginalttl : 0, &data);
972
973 append_reply(req, rep);
974 return;
975 }
976
977 static void question_termination_callback(void *context)
978 {
979 DNSQuestion *q = context;
980
981
982 mDNS_StopQuery(&mDNSStorage, q); // no need to error check
983 freeL("question_termination_callback", q);
984 }
985
986
987 static void handle_browse_request(request_state *request)
988 {
989 DNSServiceFlags flags;
990 uint32_t interfaceIndex;
991 char regtype[256], domain[256];
992 DNSQuestion *q;
993 domainname typedn, domdn;
994 char *ptr;
995 mStatus result;
996
997 if (request->ts != t_complete)
998 {
999 LogMsg("ERROR: handle_browse_request - transfer state != t_complete");
1000 abort_request(request);
1001 unlink_request(request);
1002 return;
1003 }
1004 q = mallocL("handle_browse_request", sizeof(DNSQuestion));
1005 if (!q)
1006 {
1007 my_perror("ERROR: handle_browse_request - malloc");
1008 exit(1);
1009 }
1010 bzero(q, sizeof(DNSQuestion));
1011
1012 // extract data from message
1013 ptr = request->msgdata;
1014 flags = get_flags(&ptr);
1015 interfaceIndex = get_long(&ptr);
1016 if (get_string(&ptr, regtype, 256) < 0 ||
1017 get_string(&ptr, domain, 256) < 0)
1018 goto bad_param;
1019
1020 freeL("handle_browse_request", request->msgbuf);
1021 request->msgbuf = NULL;
1022
1023 mDNSInterfaceID InterfaceID = mDNSPlatformInterfaceIDfromInterfaceIndex(&mDNSStorage, interfaceIndex);
1024 if (interfaceIndex && !InterfaceID) goto bad_param;
1025 q->QuestionContext = request;
1026 q->QuestionCallback = browse_result_callback;
1027 if (!MakeDomainNameFromDNSNameString(&typedn, regtype) ||
1028 !MakeDomainNameFromDNSNameString(&domdn, domain[0] ? domain : "local."))
1029 goto bad_param;
1030 request->termination_context = q;
1031 request->terminate = browse_termination_callback;
1032 result = mDNS_StartBrowse(&mDNSStorage, q, &typedn, &domdn, InterfaceID, browse_result_callback, request);
1033 deliver_error(request, result);
1034 return;
1035
1036 bad_param:
1037 deliver_error(request, mStatus_BadParamErr);
1038 abort_request(request);
1039 unlink_request(request);
1040 }
1041
1042 static void browse_result_callback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord)
1043 {
1044 request_state *req;
1045 reply_state *rep;
1046 mStatus err;
1047
1048 #pragma unused(m)
1049 req = question->QuestionContext;
1050
1051 err = gen_rr_response(&answer->rdata->u.name, answer->InterfaceID, req, &rep);
1052 if (err)
1053 {
1054 if (deliver_async_error(req, browse_reply, err) < 0)
1055 {
1056 abort_request(req);
1057 unlink_request(req);
1058 }
1059 return;
1060 }
1061 if (AddRecord) rep->rhdr->flags |= kDNSServiceFlagsAdd; // non-zero TTL indicates add
1062 append_reply(req, rep);
1063 return;
1064 }
1065
1066 static void browse_termination_callback(void *context)
1067 {
1068 DNSQuestion *q = context;
1069
1070 mDNS_StopBrowse(&mDNSStorage, q); // no need to error-check result
1071 freeL("browse_termination_callback", q);
1072 }
1073
1074 // service registration
1075 static void handle_regservice_request(request_state *request)
1076 {
1077 DNSServiceFlags flags;
1078 uint32_t ifi;
1079 char name[256], regtype[256], domain[256], host[256];
1080 uint16_t txtlen;
1081 mDNSIPPort port;
1082 void *txtdata;
1083 char *ptr;
1084 domainlabel n;
1085 domainname t, d, h, srv;
1086 registered_service *r_srv;
1087 int srs_size;
1088 mStatus result;
1089
1090 char *sub, *rtype_ptr;
1091 int i, num_subtypes;
1092
1093
1094 if (request->ts != t_complete)
1095 {
1096 LogMsg("ERROR: handle_regservice_request - transfer state != t_complete");
1097 abort_request(request);
1098 unlink_request(request);
1099 return;
1100 }
1101
1102 // extract data from message
1103 ptr = request->msgdata;
1104 flags = get_flags(&ptr);
1105 ifi = get_long(&ptr);
1106 mDNSInterfaceID InterfaceID = mDNSPlatformInterfaceIDfromInterfaceIndex(&mDNSStorage, ifi);
1107 if (ifi && !InterfaceID) goto bad_param;
1108 if (get_string(&ptr, name, 256) < 0 ||
1109 get_string(&ptr, regtype, 256) < 0 ||
1110 get_string(&ptr, domain, 256) < 0 ||
1111 get_string(&ptr, host, 256) < 0)
1112 goto bad_param;
1113
1114 port.NotAnInteger = get_short(&ptr);
1115 txtlen = get_short(&ptr);
1116 txtdata = get_rdata(&ptr, txtlen);
1117
1118 // count subtypes, replacing commas w/ whitespace
1119 rtype_ptr = regtype;
1120 num_subtypes = -1;
1121 while((sub = strsep(&rtype_ptr, ",")))
1122 if (*sub) num_subtypes++;
1123
1124 if (!name[0]) n = (&mDNSStorage)->nicelabel;
1125 else if (!MakeDomainLabelFromLiteralString(&n, name))
1126 goto bad_param;
1127 if ((!regtype[0] || !MakeDomainNameFromDNSNameString(&t, regtype)) ||
1128 (!MakeDomainNameFromDNSNameString(&d, *domain ? domain : "local.")) ||
1129 (!ConstructServiceName(&srv, &n, &t, &d)))
1130 goto bad_param;
1131 if (host[0] && !MakeDomainNameFromDNSNameString(&h, host)) goto bad_param;
1132
1133 r_srv = mallocL("handle_regservice_request", sizeof(registered_service));
1134 if (!r_srv) goto malloc_error;
1135 srs_size = sizeof(ServiceRecordSet) + (sizeof(RDataBody) > txtlen ? 0 : txtlen - sizeof(RDataBody));
1136 r_srv->srs = mallocL("handle_regservice_request", srs_size);
1137 if (!r_srv->srs) goto malloc_error;
1138 if (num_subtypes > 0)
1139 {
1140 r_srv->subtypes = mallocL("handle_regservice_request", num_subtypes * sizeof(AuthRecord));
1141 if (!r_srv->subtypes) goto malloc_error;
1142 sub = regtype + strlen(regtype) + 1;
1143 for (i = 0; i < num_subtypes; i++)
1144 {
1145 if (!MakeDomainNameFromDNSNameString(&(r_srv->subtypes + i)->resrec.name, sub))
1146 {
1147 freeL("handle_regservice_request", r_srv->subtypes);
1148 freeL("handle_regservice_request", r_srv);
1149 r_srv = NULL;
1150 goto bad_param;
1151 }
1152 sub += strlen(sub) + 1;
1153 }
1154 }
1155 else r_srv->subtypes = NULL;
1156 r_srv->request = request;
1157
1158 r_srv->autoname = (!name[0]);
1159 r_srv->rename_on_memfree = 0;
1160 r_srv->renameonconflict = !(flags & kDNSServiceFlagsNoAutoRename);
1161 r_srv->name = n;
1162 request->termination_context = r_srv;
1163 request->terminate = regservice_termination_callback;
1164 request->service = r_srv;
1165
1166 result = mDNS_RegisterService(&mDNSStorage, r_srv->srs, &n, &t, &d, host[0] ? &h : NULL, port,
1167 txtdata, txtlen, r_srv->subtypes, num_subtypes, InterfaceID, regservice_callback, r_srv);
1168 deliver_error(request, result);
1169 if (result != mStatus_NoError)
1170 {
1171 abort_request(request);
1172 unlink_request(request);
1173 }
1174 else
1175 {
1176 reset_connected_rstate(request); // reset to receive add/remove messages
1177 }
1178 return;
1179
1180 bad_param:
1181 deliver_error(request, mStatus_BadParamErr);
1182 abort_request(request);
1183 unlink_request(request);
1184 return;
1185
1186 malloc_error:
1187 my_perror("ERROR: malloc");
1188 exit(1);
1189 }
1190
1191 // service registration callback performs three duties - frees memory for deregistered services,
1192 // handles name conflicts, and delivers completed registration information to the client (via
1193 // process_service_registraion())
1194
1195 static void regservice_callback(mDNS *const m, ServiceRecordSet *const srs, mStatus result)
1196 {
1197 mStatus err;
1198 ExtraResourceRecord *extra;
1199 registered_service *r_srv = srs->ServiceContext;
1200 request_state *rs = r_srv->request;
1201
1202 #pragma unused(m)
1203
1204 if (!rs && (result != mStatus_MemFree && !r_srv->rename_on_memfree))
1205 {
1206 // error should never happen - safest to log and continue
1207 LogMsg("ERROR: regservice_callback: received result %d with a NULL request pointer\n");
1208 return;
1209 }
1210
1211 if (result == mStatus_NoError)
1212 return process_service_registration(srs);
1213 else if (result == mStatus_MemFree)
1214 {
1215 if (r_srv->rename_on_memfree)
1216 {
1217 r_srv->rename_on_memfree = 0;
1218 r_srv->name = mDNSStorage.nicelabel;
1219 err = mDNS_RenameAndReregisterService(&mDNSStorage, srs, &r_srv->name);
1220 if (err) LogMsg("ERROR: regservice_callback - RenameAndReregisterService returned %d", err);
1221 // error should never happen - safest to log and continue
1222 }
1223 else
1224 {
1225 while (r_srv->srs->Extras)
1226 {
1227 extra = r_srv->srs->Extras;
1228 r_srv->srs->Extras = r_srv->srs->Extras->next;
1229 freeL("regservice_callback", extra);
1230 }
1231 freeL("regservice_callback", r_srv->srs);
1232 if (r_srv->subtypes) freeL("regservice_callback", r_srv->subtypes);
1233 if (r_srv->request) r_srv->request->service = NULL;
1234 freeL("regservice_callback", r_srv);
1235 return;
1236 }
1237 }
1238 else if (result == mStatus_NameConflict)
1239 {
1240 if (r_srv->autoname || r_srv->renameonconflict)
1241 {
1242 mDNS_RenameAndReregisterService(&mDNSStorage, srs, mDNSNULL);
1243 return;
1244 }
1245 else
1246 {
1247 freeL("regservice_callback", r_srv);
1248 freeL("regservice_callback", r_srv->srs);
1249 if (r_srv->subtypes) freeL("regservice_callback", r_srv->subtypes);
1250 if (r_srv->request) r_srv->request->service = NULL;
1251 freeL("regservice_callback", r_srv);
1252 if (deliver_async_error(rs, reg_service_reply, result) < 0)
1253 {
1254 abort_request(rs);
1255 unlink_request(rs);
1256 }
1257 return;
1258 }
1259 }
1260 else
1261 {
1262 LogMsg("ERROR: unknown result in regservice_callback");
1263 if (deliver_async_error(rs, reg_service_reply, result) < 0)
1264 {
1265 abort_request(rs);
1266 unlink_request(rs);
1267 }
1268 return;
1269 }
1270 }
1271
1272 static void handle_add_request(request_state *rstate)
1273 {
1274 registered_record_entry *re;
1275 ExtraResourceRecord *extra;
1276 uint32_t size, ttl;
1277 uint16_t rrtype, rdlen;
1278 char *ptr, *rdata;
1279 mStatus result;
1280 DNSServiceFlags flags;
1281 ServiceRecordSet *srs = rstate->service->srs;
1282
1283 if (!srs)
1284 {
1285 LogMsg("ERROR: handle_add_request - no service record set in request state");
1286 deliver_error(rstate, mStatus_UnknownErr);
1287 return;
1288 }
1289
1290 ptr = rstate->msgdata;
1291 flags = get_flags(&ptr);
1292 rrtype = get_short(&ptr);
1293 rdlen = get_short(&ptr);
1294 rdata = get_rdata(&ptr, rdlen);
1295 ttl = get_long(&ptr);
1296
1297 if (rdlen > sizeof(RDataBody)) size = rdlen;
1298 else size = sizeof(RDataBody);
1299
1300 extra = mallocL("hanle_add_request", sizeof(ExtraResourceRecord) - sizeof(RDataBody) + size);
1301 if (!extra)
1302 {
1303 my_perror("ERROR: malloc");
1304 exit(1);
1305 }
1306
1307 bzero(extra, sizeof(ExtraResourceRecord)); // OK if oversized rdata not zero'd
1308 extra->r.resrec.rrtype = rrtype;
1309 extra->r.rdatastorage.MaxRDLength = size;
1310 extra->r.resrec.rdlength = rdlen;
1311 memcpy(&extra->r.rdatastorage.u.data, rdata, rdlen);
1312 result = mDNS_AddRecordToService(&mDNSStorage, srs , extra, &extra->r.rdatastorage, ttl);
1313 deliver_error(rstate, result);
1314 reset_connected_rstate(rstate);
1315 if (result)
1316 {
1317 freeL("handle_add_request", rstate->msgbuf);
1318 rstate->msgbuf = NULL;
1319 freeL("handle_add_request", extra);
1320 return;
1321 }
1322 re = mallocL("handle_add_request", sizeof(registered_record_entry));
1323 if (!re)
1324 {
1325 my_perror("ERROR: malloc");
1326 exit(1);
1327 }
1328 re->key = rstate->hdr.reg_index;
1329 re->rr = &extra->r;
1330 re->next = rstate->reg_recs;
1331 rstate->reg_recs = re;
1332 }
1333
1334 static void handle_update_request(request_state *rstate)
1335 {
1336 registered_record_entry *reptr;
1337 AuthRecord *rr;
1338 RData *newrd;
1339 uint16_t rdlen, rdsize;
1340 char *ptr, *rdata;
1341 uint32_t ttl;
1342 mStatus result;
1343
1344 if (rstate->hdr.reg_index == TXT_RECORD_INDEX)
1345 {
1346 if (!rstate->service)
1347 {
1348 deliver_error(rstate, mStatus_BadParamErr);
1349 return;
1350 }
1351 rr = &rstate->service->srs->RR_TXT;
1352 }
1353 else
1354 {
1355 reptr = rstate->reg_recs;
1356 while(reptr && reptr->key != rstate->hdr.reg_index) reptr = reptr->next;
1357 if (!reptr) deliver_error(rstate, mStatus_BadReferenceErr);
1358 rr = reptr->rr;
1359 }
1360
1361 ptr = rstate->msgdata;
1362 get_flags(&ptr); // flags unused
1363 rdlen = get_short(&ptr);
1364 rdata = get_rdata(&ptr, rdlen);
1365 ttl = get_long(&ptr);
1366
1367 if (rdlen > sizeof(RDataBody)) rdsize = rdlen;
1368 else rdsize = sizeof(RDataBody);
1369 newrd = mallocL("handle_update_request", sizeof(RData) - sizeof(RDataBody) + rdsize);
1370 if (!newrd)
1371 {
1372 my_perror("ERROR: malloc");
1373 exit(1);
1374 }
1375 newrd->MaxRDLength = rdsize;
1376 memcpy(&newrd->u, rdata, rdlen);
1377 result = mDNS_Update(&mDNSStorage, rr, ttl, rdlen, newrd, update_callback);
1378 deliver_error(rstate, result);
1379 reset_connected_rstate(rstate);
1380 }
1381
1382 static void update_callback(mDNS *const m, AuthRecord *const rr, RData *oldrd)
1383 {
1384 #pragma unused(m)
1385
1386 if (oldrd != &rr->rdatastorage) freeL("update_callback", oldrd);
1387 }
1388
1389 static void process_service_registration(ServiceRecordSet *const srs)
1390 {
1391 reply_state *rep;
1392 transfer_state send_result;
1393 mStatus err;
1394 registered_service *r_srv = srs->ServiceContext;
1395 request_state *req = r_srv->request;
1396
1397
1398 err = gen_rr_response(&srs->RR_SRV.resrec.name, srs->RR_SRV.resrec.InterfaceID, req, &rep);
1399 if (err)
1400 {
1401 if (deliver_async_error(req, reg_service_reply, err) < 0)
1402 {
1403 abort_request(req);
1404 unlink_request(req);
1405 }
1406 return;
1407 }
1408 send_result = send_msg(rep);
1409 if (send_result == t_error || send_result == t_terminated)
1410 {
1411 abort_request(req);
1412 unlink_request(req);
1413 freeL("process_service_registration", rep);
1414 }
1415 else if (send_result == t_complete) freeL("process_service_registration", rep);
1416 else append_reply(req, rep);
1417 }
1418
1419 static void regservice_termination_callback(void *context)
1420 {
1421 registered_service *srv = context;
1422
1423 // only safe to free memory if registration is not valid, ie deregister fails
1424 if (mDNS_DeregisterService(&mDNSStorage, srv->srs) != mStatus_NoError)
1425 {
1426 freeL("regservice_callback", srv->srs);
1427 if (srv->subtypes) freeL("regservice_callback", srv->subtypes);
1428 freeL("regservice_callback", srv);
1429 freeL("regservice_termination_callback", srv);
1430 }
1431 }
1432
1433
1434 static void handle_regrecord_request(request_state *rstate)
1435 {
1436 AuthRecord *rr;
1437 regrecord_callback_context *rcc;
1438 registered_record_entry *re;
1439 mStatus result;
1440
1441 if (rstate->ts != t_complete)
1442 {
1443 LogMsg("ERROR: handle_regrecord_request - transfer state != t_complete");
1444 abort_request(rstate);
1445 unlink_request(rstate);
1446 return;
1447 }
1448
1449 rr = read_rr_from_ipc_msg(rstate->msgdata, 1);
1450 if (!rr)
1451 {
1452 deliver_error(rstate, mStatus_BadParamErr);
1453 return;
1454 }
1455
1456 rcc = mallocL("hanlde_regrecord_request", sizeof(regrecord_callback_context));
1457 if (!rcc) goto malloc_error;
1458 rcc->rstate = rstate;
1459 rcc->client_context = rstate->hdr.client_context;
1460 rr->RecordContext = rcc;
1461 rr->RecordCallback = regrecord_callback;
1462
1463 // allocate registration entry, link into list
1464 re = mallocL("hanlde_regrecord_request", sizeof(registered_record_entry));
1465 if (!re) goto malloc_error;
1466 re->key = rstate->hdr.reg_index;
1467 re->rr = rr;
1468 re->next = rstate->reg_recs;
1469 rstate->reg_recs = re;
1470
1471 if (!rstate->terminate)
1472 {
1473 rstate->terminate = connected_registration_termination;
1474 rstate->termination_context = rstate;
1475 }
1476
1477 result = mDNS_Register(&mDNSStorage, rr);
1478 deliver_error(rstate, result);
1479 reset_connected_rstate(rstate);
1480 return;
1481
1482 malloc_error:
1483 my_perror("ERROR: malloc");
1484 return;
1485 }
1486
1487 static void regrecord_callback(mDNS *const m, AuthRecord *const rr, mStatus result)
1488 {
1489 regrecord_callback_context *rcc;
1490 int len;
1491 reply_state *reply;
1492 transfer_state ts;
1493
1494 #pragma unused(m)
1495
1496 if (result == mStatus_MemFree) { freeL("regrecord_callback", rr); return; }
1497 rcc = rr->RecordContext;
1498
1499 // format result, add to the list for the request, including the client context in the header
1500 len = sizeof(DNSServiceFlags);
1501 len += sizeof(uint32_t); //interfaceIndex
1502 len += sizeof(DNSServiceErrorType);
1503
1504 reply = create_reply(reg_record_reply, len, rcc->rstate);
1505 reply->mhdr->client_context = rcc->client_context;
1506 reply->rhdr->flags = 0;
1507 reply->rhdr->ifi = mDNSPlatformInterfaceIndexfromInterfaceID(&mDNSStorage, rr->resrec.InterfaceID);
1508 reply->rhdr->error = result;
1509
1510 ts = send_msg(reply);
1511 if (ts == t_error || ts == t_terminated)
1512 {
1513 abort_request(rcc->rstate);
1514 unlink_request(rcc->rstate);
1515 }
1516 else if (ts == t_complete) freeL("regrecord_callback", reply);
1517 else if (ts == t_morecoming) append_reply(rcc->rstate, reply); // client is blocked, link reply into list
1518 }
1519
1520 static void connected_registration_termination(void *context)
1521 {
1522 registered_record_entry *fptr, *ptr = ((request_state *)context)->reg_recs;
1523 while(ptr)
1524 {
1525 mDNS_Deregister(&mDNSStorage, ptr->rr);
1526 fptr = ptr;
1527 ptr = ptr->next;
1528 freeL("connected_registration_termination", fptr);
1529 }
1530 }
1531
1532
1533
1534 static void handle_removerecord_request(request_state *rstate)
1535 {
1536 registered_record_entry *reptr, *prev = NULL;
1537 mStatus err = mStatus_UnknownErr;
1538 char *ptr;
1539 reptr = rstate->reg_recs;
1540
1541 ptr = rstate->msgdata;
1542 get_flags(&ptr); // flags unused
1543
1544 while(reptr)
1545 {
1546 if (reptr->key == rstate->hdr.reg_index) // found match
1547 {
1548 if (prev) prev->next = reptr->next;
1549 else rstate->reg_recs = reptr->next;
1550 err = mDNS_Deregister(&mDNSStorage, reptr->rr);
1551 freeL("handle_removerecord_request", reptr); //rr gets freed by callback
1552 break;
1553 }
1554 prev = reptr;
1555 reptr = reptr->next;
1556 }
1557 reset_connected_rstate(rstate);
1558 if (deliver_error(rstate, err) < 0)
1559 {
1560 abort_request(rstate);
1561 unlink_request(rstate);
1562 }
1563 }
1564
1565
1566 // domain enumeration
1567 static void handle_enum_request(request_state *rstate)
1568 {
1569 DNSServiceFlags flags, add_default;
1570 uint32_t ifi;
1571 char *ptr = rstate->msgdata;
1572 domain_enum_t *def, *all;
1573 enum_termination_t *term;
1574 reply_state *reply; // initial default reply
1575 transfer_state tr;
1576 mStatus err;
1577 int result;
1578
1579 if (rstate->ts != t_complete)
1580 {
1581 LogMsg("ERROR: handle_enum_request - transfer state != t_complete");
1582 abort_request(rstate);
1583 unlink_request(rstate);
1584 return;
1585 }
1586
1587 flags = get_flags(&ptr);
1588 ifi = get_long(&ptr);
1589 mDNSInterfaceID InterfaceID = mDNSPlatformInterfaceIDfromInterfaceIndex(&mDNSStorage, ifi);
1590 if (ifi && !InterfaceID)
1591 {
1592 deliver_error(rstate, mStatus_BadParamErr);
1593 abort_request(rstate);
1594 unlink_request(rstate);
1595 }
1596
1597 // allocate context structures
1598 def = mallocL("hanlde_enum_request", sizeof(domain_enum_t));
1599 all = mallocL("handle_enum_request", sizeof(domain_enum_t));
1600 term = mallocL("handle_enum_request", sizeof(enum_termination_t));
1601 if (!def || !all || !term)
1602 {
1603 my_perror("ERROR: malloc");
1604 exit(1);
1605 }
1606
1607 // enumeration requires multiple questions, so we must link all the context pointers so that
1608 // necessary context can be reached from the callbacks
1609 def->rstate = rstate;
1610 all->rstate = rstate;
1611 term->def = def;
1612 term->all = all;
1613 term->rstate = rstate;
1614 rstate->termination_context = term;
1615 rstate->terminate = enum_termination_callback;
1616 def->question.QuestionContext = def;
1617 def->type = (flags & kDNSServiceFlagsRegistrationDomains) ?
1618 mDNS_DomainTypeRegistrationDefault: mDNS_DomainTypeBrowseDefault;
1619 all->question.QuestionContext = all;
1620 all->type = (flags & kDNSServiceFlagsRegistrationDomains) ?
1621 mDNS_DomainTypeRegistration : mDNS_DomainTypeBrowse;
1622
1623 // make the calls
1624 err = mDNS_GetDomains(&mDNSStorage, &all->question, all->type, InterfaceID, enum_result_callback, all);
1625 if (err == mStatus_NoError)
1626 err = mDNS_GetDomains(&mDNSStorage, &def->question, def->type, InterfaceID, enum_result_callback, def);
1627 result = deliver_error(rstate, err); // send error *before* returning local domain
1628
1629 if (result < 0 || err)
1630 {
1631 abort_request(rstate);
1632 unlink_request(rstate);
1633 return;
1634 }
1635
1636 // provide local. as the first domain automatically
1637 add_default = kDNSServiceFlagsDefault | kDNSServiceFlagsAdd | kDNSServiceFlagsFinished;
1638 reply = format_enumeration_reply(rstate, "local.", add_default, ifi, 0);
1639 tr = send_msg(reply);
1640 if (tr == t_error || tr == t_terminated)
1641 {
1642 freeL("handle_enum_request", def);
1643 freeL("handle_enum_request", all);
1644 abort_request(rstate);
1645 unlink_request(rstate);
1646 return;
1647 }
1648 if (tr == t_complete) freeL("handle_enum_request", reply);
1649 if (tr == t_morecoming) append_reply(rstate, reply); // couldn't send whole reply because client is blocked - link into list
1650 }
1651
1652 static void enum_result_callback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord)
1653 {
1654 char domain[256];
1655 domain_enum_t *de = question->QuestionContext;
1656 DNSServiceFlags flags = 0;
1657 reply_state *reply;
1658
1659 #pragma unused(m)
1660 if (answer->rrtype != kDNSType_PTR) return;
1661 if (AddRecord)
1662 {
1663 flags |= kDNSServiceFlagsAdd;
1664 if (de->type == mDNS_DomainTypeRegistrationDefault || de->type == mDNS_DomainTypeBrowseDefault)
1665 flags |= kDNSServiceFlagsDefault;
1666 }
1667 else
1668 {
1669 flags |= kDNSServiceFlagsRemove;
1670 }
1671 ConvertDomainNameToCString(&answer->rdata->u.name, domain);
1672 reply = format_enumeration_reply(de->rstate, domain, flags, mDNSPlatformInterfaceIndexfromInterfaceID(&mDNSStorage, answer->InterfaceID), kDNSServiceErr_NoError);
1673 if (!reply)
1674 {
1675 LogMsg("ERROR: enum_result_callback, format_enumeration_reply");
1676 return;
1677 }
1678 reply->next = NULL;
1679 append_reply(de->rstate, reply);
1680 return;
1681 }
1682
1683 static reply_state *format_enumeration_reply(request_state *rstate, char *domain, DNSServiceFlags flags, uint32_t ifi, DNSServiceErrorType err)
1684 {
1685 int len;
1686 reply_state *reply;
1687 char *data;
1688
1689
1690 len = sizeof(DNSServiceFlags);
1691 len += sizeof(uint32_t);
1692 len += sizeof(DNSServiceErrorType);
1693 len += strlen(domain) + 1;
1694
1695 reply = create_reply(enumeration_reply, len, rstate);
1696 reply->rhdr->flags = flags;
1697 reply->rhdr->ifi = ifi;
1698 reply->rhdr->error = err;
1699 data = reply->sdata;
1700 put_string(domain, &data);
1701 return reply;
1702 }
1703
1704 static void enum_termination_callback(void *context)
1705 {
1706 enum_termination_t *t = context;
1707 mDNS *coredata = &mDNSStorage;
1708
1709 mDNS_StopGetDomains(coredata, &t->all->question);
1710 mDNS_StopGetDomains(coredata, &t->def->question);
1711 freeL("enum_termination_callback", t->all);
1712 freeL("enum_termination_callback", t->def);
1713 t->rstate->termination_context = NULL;
1714 freeL("enum_termination_callback", t);
1715 }
1716
1717 static void handle_reconfirm_request(request_state *rstate)
1718 {
1719 AuthRecord *rr;
1720
1721 rr = read_rr_from_ipc_msg(rstate->msgdata, 0);
1722 if (!rr) return;
1723 mDNS_ReconfirmByValue(&mDNSStorage, &rr->resrec);
1724 abort_request(rstate);
1725 unlink_request(rstate);
1726 freeL("handle_reconfirm_request", rr);
1727 }
1728
1729
1730 // setup rstate to accept new reg/dereg requests
1731 static void reset_connected_rstate(request_state *rstate)
1732 {
1733 rstate->ts = t_morecoming;
1734 rstate->hdr_bytes = 0;
1735 rstate->data_bytes = 0;
1736 if (rstate->msgbuf) freeL("reset_connected_rstate", rstate->msgbuf);
1737 rstate->msgbuf = NULL;
1738 rstate->bufsize = 0;
1739 }
1740
1741
1742
1743 // returns a resource record (allocated w/ malloc) containing the data found in an IPC message
1744 // data must be in format flags, interfaceIndex, name, rrtype, rrclass, rdlen, rdata, (optional)ttl
1745 // (ttl only extracted/set if ttl argument is non-zero). returns NULL for a bad-parameter error
1746 static AuthRecord *read_rr_from_ipc_msg(char *msgbuf, int ttl)
1747 {
1748 char *rdata, name[256];
1749 AuthRecord *rr;
1750 DNSServiceFlags flags;
1751 uint32_t interfaceIndex;
1752 uint16_t type, class, rdlen;
1753 int storage_size;
1754
1755 flags = get_flags(&msgbuf);
1756 interfaceIndex = get_long(&msgbuf);
1757 if (get_string(&msgbuf, name, 256) < 0)
1758 {
1759 LogMsg("ERROR: read_rr_from_ipc_msg - get_string");
1760 return NULL;
1761 }
1762 type = get_short(&msgbuf);
1763 class = get_short(&msgbuf);
1764 rdlen = get_short(&msgbuf);
1765
1766 if (rdlen > sizeof(RDataBody)) storage_size = rdlen;
1767 else storage_size = sizeof(RDataBody);
1768
1769 rr = mallocL("read_rr_from_ipc_msg", sizeof(AuthRecord) - sizeof(RDataBody) + storage_size);
1770 if (!rr)
1771 {
1772 my_perror("ERROR: malloc");
1773 exit(1);
1774 }
1775 bzero(rr, sizeof(AuthRecord)); // ok if oversized rdata not zero'd
1776 rr->resrec.rdata = &rr->rdatastorage;
1777 rr->resrec.InterfaceID = mDNSPlatformInterfaceIDfromInterfaceIndex(&mDNSStorage, interfaceIndex);
1778 if (!MakeDomainNameFromDNSNameString(&rr->resrec.name, name))
1779 {
1780 LogMsg("ERROR: bad name: %s", name);
1781 freeL("read_rr_from_ipc_msg", rr);
1782 return NULL;
1783 }
1784 rr->resrec.rrtype = type;
1785 if ((flags & kDNSServiceFlagsShared) == kDNSServiceFlagsShared)
1786 rr->resrec.RecordType = kDNSRecordTypeShared;
1787 if ((flags & kDNSServiceFlagsUnique) == kDNSServiceFlagsUnique)
1788 rr->resrec.RecordType = kDNSRecordTypeUnique;
1789 rr->resrec.rrclass = class;
1790 rr->resrec.rdlength = rdlen;
1791 rr->resrec.rdata->MaxRDLength = rdlen;
1792 rdata = get_rdata(&msgbuf, rdlen);
1793 memcpy(rr->resrec.rdata->u.data, rdata, rdlen);
1794 if (ttl)
1795 {
1796 rr->resrec.rroriginalttl = get_long(&msgbuf);
1797 }
1798 return rr;
1799 }
1800
1801
1802 // generate a response message for a browse result, service registration result, or any other call with the
1803 // identical callback signature. on successful completion rep is set to point to a malloc'd reply_state struct,
1804 // and mStatus_NoError is returned. otherwise the appropriate error is returned.
1805
1806 static mStatus gen_rr_response(domainname *servicename, mDNSInterfaceID id, request_state *request, reply_state **rep)
1807 {
1808 char *data;
1809 int len;
1810 domainlabel name;
1811 domainname type, dom;
1812 char namestr[256], typestr[256], domstr[256];
1813
1814 *rep = NULL;
1815
1816 if (!DeconstructServiceName(servicename, &name, &type, &dom))
1817 return kDNSServiceErr_Unknown;
1818
1819 ConvertDomainLabelToCString_unescaped(&name, namestr);
1820 ConvertDomainNameToCString(&type, typestr);
1821 ConvertDomainNameToCString(&dom, domstr);
1822
1823 // calculate reply data length
1824 len = sizeof(DNSServiceFlags);
1825 len += sizeof(uint32_t); // if index
1826 len += sizeof(DNSServiceErrorType);
1827 len += strlen(namestr) + 1;
1828 len += strlen(typestr) + 1;
1829 len += strlen(domstr) + 1;
1830
1831 *rep = create_reply(query_reply, len, request);
1832 (*rep)->rhdr->flags = 0;
1833 (*rep)->rhdr->ifi = mDNSPlatformInterfaceIndexfromInterfaceID(&mDNSStorage, id);
1834 (*rep)->rhdr->error = kDNSServiceErr_NoError;
1835 data = (*rep)->sdata;
1836
1837 put_string(namestr, &data);
1838 put_string(typestr, &data);
1839 put_string(domstr, &data);
1840 return mStatus_NoError;
1841 }
1842
1843
1844 static int build_domainname_from_strings(domainname *srv, char *name, char *regtype, char *domain)
1845 {
1846 domainlabel n;
1847 domainname d, t;
1848
1849 if (!MakeDomainLabelFromLiteralString(&n, name)) return -1;
1850 if (!MakeDomainNameFromDNSNameString(&t, regtype)) return -1;
1851 if (!MakeDomainNameFromDNSNameString(&d, domain)) return -1;
1852 if (!ConstructServiceName(srv, &n, &t, &d)) return -1;
1853 return 0;
1854 }
1855
1856
1857 // append a reply to the list in a request object
1858 static void append_reply(request_state *req, reply_state *rep)
1859 {
1860 reply_state *ptr;
1861
1862 if (!req->replies) req->replies = rep;
1863 else
1864 {
1865 ptr = req->replies;
1866 while (ptr->next) ptr = ptr->next;
1867 ptr->next = rep;
1868 }
1869 rep->next = NULL;
1870 }
1871
1872
1873 // read_msg may be called any time when the transfer state (rs->ts) is t_morecoming.
1874 // returns the current state of the request (morecoming, error, complete, terminated.)
1875 // if there is no data on the socket, the socket will be closed and t_terminated will be returned
1876 static int read_msg(request_state *rs)
1877 {
1878 uint32_t nleft;
1879 int nread;
1880 char buf[4]; // dummy for death notification
1881
1882 if (rs->ts == t_terminated || rs->ts == t_error)
1883 {
1884 LogMsg("ERROR: read_msg called with transfer state terminated or error");
1885 rs->ts = t_error;
1886 return t_error;
1887 }
1888
1889 if (rs->ts == t_complete)
1890 { // this must be death or something is wrong
1891 nread = recv(rs->sd, buf, 4, 0);
1892 if (!nread) { rs->ts = t_terminated; return t_terminated; }
1893 if (nread < 0) goto rerror;
1894 LogMsg("ERROR: read data from a completed request.");
1895 rs->ts = t_error;
1896 return t_error;
1897 }
1898
1899 if (rs->ts != t_morecoming)
1900 {
1901 LogMsg("ERROR: read_msg called with invalid transfer state (%d)", rs->ts);
1902 rs->ts = t_error;
1903 return t_error;
1904 }
1905
1906 if (rs->hdr_bytes < sizeof(ipc_msg_hdr))
1907 {
1908 nleft = sizeof(ipc_msg_hdr) - rs->hdr_bytes;
1909 nread = recv(rs->sd, (char *)&rs->hdr + rs->hdr_bytes, nleft, 0);
1910 if (nread == 0) { rs->ts = t_terminated; return t_terminated; }
1911 if (nread < 0) goto rerror;
1912 rs->hdr_bytes += nread;
1913 if (rs->hdr_bytes > sizeof(ipc_msg_hdr))
1914 {
1915 LogMsg("ERROR: read_msg - read too many header bytes");
1916 rs->ts = t_error;
1917 return t_error;
1918 }
1919 }
1920
1921 // only read data if header is complete
1922 if (rs->hdr_bytes == sizeof(ipc_msg_hdr))
1923 {
1924 if (rs->hdr.datalen == 0) // ok in removerecord requests
1925 {
1926 rs->ts = t_complete;
1927 rs->msgbuf = NULL;
1928 return t_complete;
1929 }
1930
1931 if (!rs->msgbuf) // allocate the buffer first time through
1932 {
1933 rs->msgbuf = mallocL("read_msg", rs->hdr.datalen);
1934 if (!rs->msgbuf)
1935 {
1936 my_perror("ERROR: malloc");
1937 rs->ts = t_error;
1938 return t_error;
1939 }
1940 rs->msgdata = rs->msgbuf;
1941 }
1942 nleft = rs->hdr.datalen - rs->data_bytes;
1943 nread = recv(rs->sd, rs->msgbuf + rs->data_bytes, nleft, 0);
1944 if (nread == 0) { rs->ts = t_terminated; return t_terminated; }
1945 if (nread < 0) goto rerror;
1946 rs->data_bytes += nread;
1947 if (rs->data_bytes > rs->hdr.datalen)
1948 {
1949 LogMsg("ERROR: read_msg - read too many data bytes");
1950 rs->ts = t_error;
1951 return t_error;
1952 }
1953 }
1954
1955 if (rs->hdr_bytes == sizeof(ipc_msg_hdr) && rs->data_bytes == rs->hdr.datalen)
1956 rs->ts = t_complete;
1957 else rs->ts = t_morecoming;
1958
1959 return rs->ts;
1960
1961 rerror:
1962 if (errno == EAGAIN || errno == EINTR) return rs->ts;
1963 my_perror("ERROR: read_msg");
1964 rs->ts = t_error;
1965 return t_error;
1966 }
1967
1968
1969 static int send_msg(reply_state *rs)
1970 {
1971 ssize_t nwriten;
1972
1973 if (!rs->msgbuf)
1974 {
1975 LogMsg("ERROR: send_msg called with NULL message buffer");
1976 return t_error;
1977 }
1978
1979 if (rs->request->no_reply) //!!!KRS this behavior should be optimized if it becomes more common
1980 {
1981 rs->ts = t_complete;
1982 freeL("send_msg", rs->msgbuf);
1983 return t_complete;
1984 }
1985
1986 nwriten = send(rs->sd, rs->msgbuf + rs->nwriten, rs->len - rs->nwriten, 0);
1987 if (nwriten < 0)
1988 {
1989 if (errno == EINTR || errno == EAGAIN) nwriten = 0;
1990 else
1991 {
1992 if (errno == EPIPE)
1993 {
1994 LogMsg("broken pipe - cleanup should be handled by run-loop read wakeup");
1995 rs->ts = t_terminated;
1996 rs->request->ts = t_terminated;
1997 return t_terminated;
1998 }
1999 else
2000 {
2001 my_perror("ERROR: send\n");
2002 rs->ts = t_error;
2003 return t_error;
2004 }
2005 }
2006 }
2007 rs->nwriten += nwriten;
2008
2009 if (rs->nwriten == rs->len)
2010 {
2011 rs->ts = t_complete;
2012 freeL("send_msg", rs->msgbuf);
2013 }
2014 return rs->ts;
2015 }
2016
2017
2018
2019 static reply_state *create_reply(reply_op_t op, int datalen, request_state *request)
2020 {
2021 reply_state *reply;
2022 int totallen;
2023
2024
2025 if ((unsigned)datalen < sizeof(reply_hdr))
2026 {
2027 LogMsg("ERROR: create_reply - data length less than lenght of required fields");
2028 return NULL;
2029 }
2030
2031 totallen = datalen + sizeof(ipc_msg_hdr);
2032 reply = mallocL("create_reply", sizeof(reply_state));
2033 if (!reply)
2034 {
2035 my_perror("ERROR: malloc");
2036 exit(1);
2037 }
2038 bzero(reply, sizeof(reply_state));
2039 reply->ts = t_morecoming;
2040 reply->sd = request->sd;
2041 reply->request = request;
2042 reply->len = totallen;
2043 reply->msgbuf = mallocL("create_reply", totallen);
2044 if (!reply->msgbuf)
2045 {
2046 my_perror("ERROR: malloc");
2047 exit(1);
2048 }
2049 bzero(reply->msgbuf, totallen);
2050 reply->mhdr = (ipc_msg_hdr *)reply->msgbuf;
2051 reply->rhdr = (reply_hdr *)(reply->msgbuf + sizeof(ipc_msg_hdr));
2052 reply->sdata = reply->msgbuf + sizeof(ipc_msg_hdr) + sizeof(reply_hdr);
2053 reply->mhdr->version = VERSION;
2054 reply->mhdr->op.reply_op = op;
2055 reply->mhdr->datalen = totallen - sizeof(ipc_msg_hdr);
2056 return reply;
2057 }
2058
2059
2060 static int deliver_error(request_state *rstate, mStatus err)
2061 {
2062 int nwritten = -1;
2063 undelivered_error_t *undeliv;
2064
2065 nwritten = send(rstate->errfd, &err, sizeof(mStatus), 0);
2066 if (nwritten < (int)sizeof(mStatus))
2067 {
2068 if (errno == EINTR || errno == EAGAIN)
2069 nwritten = 0;
2070 if (nwritten < 0)
2071 {
2072 my_perror("ERROR: send - unable to deliver error to client");
2073 goto error;
2074 }
2075 //client blocked - store result and come backr
2076 undeliv = mallocL("deliver_error", sizeof(undelivered_error_t));
2077 if (!undeliv)
2078 {
2079 my_perror("ERROR: malloc");
2080 exit(1);
2081 }
2082 undeliv->err = err;
2083 undeliv->nwritten = nwritten;
2084 undeliv->sd = rstate->errfd;
2085 rstate->u_err = undeliv;
2086 return 0;
2087 }
2088 if (rstate->errfd != rstate->sd) close(rstate->errfd);
2089 return 0;
2090
2091 error:
2092 if (rstate->errfd != rstate->sd) close(rstate->errfd);
2093 return -1;
2094
2095 }
2096
2097
2098 // returns 0 on success, -1 if send is incomplete, or on terminal failre (request is aborted)
2099 static transfer_state send_undelivered_error(request_state *rs)
2100 {
2101 int nwritten;
2102
2103 nwritten = send(rs->u_err->sd, (char *)(&rs->u_err) + rs->u_err->nwritten, sizeof(mStatus) - rs->u_err->nwritten, 0);
2104 if (nwritten < 0)
2105 {
2106 if (errno == EINTR || errno == EAGAIN)
2107 nwritten = 0;
2108 else
2109 {
2110 my_perror("ERROR: send - unable to deliver error to client\n");
2111 if (rs->u_err->sd == rs->sd) close (rs->u_err->sd);
2112 return t_error;
2113 }
2114 }
2115 if (nwritten + rs->u_err->nwritten == sizeof(mStatus))
2116 {
2117 if (rs->u_err->sd == rs->sd) close(rs->u_err->sd);
2118 freeL("send_undelivered_error", rs->u_err);
2119 rs->u_err = NULL;
2120 return t_complete;
2121 }
2122 rs->u_err->nwritten += nwritten;
2123 return t_morecoming;
2124 }
2125
2126
2127 // send bogus data along with an error code to the app callback
2128 // returns 0 on success (linking reply into list of not fully delivered),
2129 // -1 on failure (request should be aborted)
2130 static int deliver_async_error(request_state *rs, reply_op_t op, mStatus err)
2131 {
2132 int len;
2133 reply_state *reply;
2134 transfer_state ts;
2135
2136 if (rs->no_reply) return 0;
2137 len = 256; // long enough for any reply handler to read all args w/o buffer overrun
2138 reply = create_reply(op, len, rs);
2139 reply->rhdr->error = err;
2140 ts = send_msg(reply);
2141 if (ts == t_error || ts == t_terminated)
2142 {
2143 freeL("deliver_async_error", reply);
2144 return -1;
2145 }
2146 else if (ts == t_complete) freeL("deliver_async_error", reply);
2147 else if (ts == t_morecoming) append_reply(rs, reply); // client is blocked, link reply into list
2148 return 0;
2149 }
2150
2151
2152 static void abort_request(request_state *rs)
2153 {
2154 reply_state *rep, *ptr;
2155
2156 if (rs->terminate) rs->terminate(rs->termination_context); // terminate field may not be set yet
2157 if (rs->msgbuf) freeL("abort_request", rs->msgbuf);
2158 CFRunLoopRemoveSource(CFRunLoopGetCurrent(), rs->rls, kCFRunLoopDefaultMode);
2159 CFRunLoopSourceInvalidate(rs->rls);
2160 CFRelease(rs->rls);
2161 CFSocketInvalidate(rs->sr);
2162 CFRelease(rs->sr);
2163 rs->sd = -1;
2164 if (rs->errfd >= 0) close(rs->errfd);
2165 rs->errfd = -1;
2166
2167 // free pending replies
2168 rep = rs->replies;
2169 while(rep)
2170 {
2171 if (rep->msgbuf) freeL("abort_request", rep->msgbuf);
2172 ptr = rep;
2173 rep = rep->next;
2174 freeL("abort_request", ptr);
2175 }
2176
2177 if (rs->u_err)
2178 {
2179 freeL("abort_request", rs->u_err);
2180 rs->u_err = NULL;
2181 }
2182 }
2183
2184
2185 static void unlink_request(request_state *rs)
2186 {
2187 request_state *ptr;
2188
2189 if (rs == all_requests)
2190 {
2191 all_requests = all_requests->next;
2192 freeL("unlink_request", rs);
2193 return;
2194 }
2195 for(ptr = all_requests; ptr->next; ptr = ptr->next)
2196 if (ptr->next == rs)
2197 {
2198 ptr->next = rs->next;
2199 freeL("unlink_request", rs);
2200 return;
2201 }
2202 }
2203
2204
2205
2206 //hack to search-replace perror's to LogMsg's
2207 static void my_perror(char *errmsg)
2208 {
2209 LogMsg("%s: %s", errmsg, strerror(errno));
2210 }
2211
2212