]> git.saurik.com Git - apple/mdnsresponder.git/blob - mDNSMacOSX/uds_daemon.c
mDNSResponder-58.1.tar.gz
[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 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
7 *
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
13 * file.
14 *
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.
22 *
23 * @APPLE_LICENSE_HEADER_END@
24
25 Change History (most recent first):
26
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
30
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.
34
35 Revision 1.21 2003/08/19 05:39:43 cheshire
36 <rdar://problem/3380097> SIGINFO dump should include resolves started by DNSServiceQueryRecord
37
38 Revision 1.20 2003/08/16 03:39:01 cheshire
39 <rdar://problem/3338440> InterfaceID -1 indicates "local only"
40
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.
48
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
51
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
54
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.
58
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.
62
63 Revision 1.14 2003/08/12 19:56:25 cheshire
64 Update to APSL 2.0
65
66 */
67
68 #include "mDNSClientAPI.h"
69 #include "mDNSMacOSX.h"
70 #include "dns_sd.h"
71 #include "dnssd_ipc.h"
72 #include <fcntl.h>
73 #include <sys/ioctl.h>
74 #include <sys/types.h>
75 #include <sys/time.h>
76 #include <sys/resource.h>
77
78 // Types and Data Structures
79 // ----------------------------------------------------------------------
80
81 typedef enum
82 {
83 t_uninitialized,
84 t_morecoming,
85 t_complete,
86 t_error,
87 t_terminated
88 } transfer_state;
89
90 typedef void (*req_termination_fn)(void *);
91
92
93 typedef struct registered_record_entry
94 {
95 int key;
96 AuthRecord *rr;
97 struct registered_record_entry *next;
98 } registered_record_entry;
99
100 typedef struct registered_service
101 {
102 //struct registered_service *next;
103 int autoname;
104 int renameonconflict;
105 int rename_on_memfree; // set flag on config change when we deregister original name
106 domainlabel name;
107 ServiceRecordSet *srs;
108 struct request_state *request;
109 AuthRecord *subtypes;
110 } registered_service;
111
112 typedef struct
113 {
114 mStatus err;
115 int nwritten;
116 int sd;
117 } undelivered_error_t;
118
119 typedef struct request_state
120 {
121 // connection structures
122 CFRunLoopSourceRef rls;
123 CFSocketRef sr;
124 int sd;
125 int errfd;
126
127 // state of read (in case message is read over several recv() calls)
128 transfer_state ts;
129 uint32_t hdr_bytes; // bytes of header already read
130 ipc_msg_hdr hdr;
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
135
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;
143
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;
149
150 struct request_state *next;
151 } request_state;
152
153 // struct physically sits between ipc message header and call-specific fields in the message buffer
154 typedef struct
155 {
156 DNSServiceFlags flags;
157 uint32_t ifi;
158 DNSServiceErrorType error;
159 } reply_hdr;
160
161
162 typedef struct reply_state
163 {
164 // state of the transmission
165 int sd;
166 transfer_state ts;
167 uint32_t nwriten;
168 uint32_t len;
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
173 ipc_msg_hdr *mhdr;
174 reply_hdr *rhdr;
175 char *sdata; // pointer to start of call-specific data
176 // pointer to malloc'd buffer
177 char *msgbuf;
178 } reply_state;
179
180
181 // domain enumeration and resolv calls require 2 mDNSCore calls, so we need separate interconnected
182 // structures to handle callbacks
183 typedef struct
184 {
185 DNSQuestion question;
186 mDNS_DomainType type;
187 request_state *rstate;
188 } domain_enum_t;
189
190 typedef struct
191 {
192 domain_enum_t *all;
193 domain_enum_t *def;
194 request_state *rstate;
195 } enum_termination_t;
196
197 typedef struct
198 {
199 DNSQuestion question;
200 uint16_t qtype;
201 request_state *rstate;
202 } resolve_t;
203
204 typedef struct
205 {
206 resolve_t *txt;
207 resolve_t *srv;
208 request_state *rstate;
209 } resolve_termination_t;
210
211 typedef struct resolve_result_t
212 {
213 const ResourceRecord *txt;
214 const ResourceRecord *srv;
215 } resolve_result_t;
216
217 typedef struct
218 {
219 request_state *rstate;
220 client_context_t client_context;
221 } regrecord_callback_context;
222
223
224
225
226 // globals
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.
231
232
233 #define MAX_OPENFILES 1024
234
235
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);
279
280 // initialization, setup/teardown functions
281
282 int udsserver_init(void)
283 {
284 mode_t mask;
285 struct sockaddr_un laddr;
286 struct rlimit maxfds;
287
288 if ((listenfd = socket(AF_LOCAL, SOCK_STREAM, 0)) < 0)
289 goto error;
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);
295 mask = umask(0);
296 if (bind(listenfd, (struct sockaddr *)&laddr, sizeof(laddr)) < 0)
297 goto error;
298 umask(mask);
299
300 if (fcntl(listenfd, F_SETFL, O_NONBLOCK) < 0)
301 {
302 my_perror("ERROR: could not set listen socket to non-blocking mode");
303 goto error;
304 }
305 listen(listenfd, LISTENQ);
306
307
308 // set maximum file descriptor to 1024
309 if (getrlimit(RLIMIT_NOFILE, &maxfds) < 0)
310 {
311 my_perror("ERROR: Unable to get file descriptor limit");
312 return 0;
313 }
314 if (maxfds.rlim_max >= MAX_OPENFILES && maxfds.rlim_cur == maxfds.rlim_max)
315 {
316 // proper values already set
317 return 0;
318 }
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");
323 return 0;
324
325 error:
326 my_perror("ERROR: udsserver_init");
327 return -1;
328 }
329
330 int udsserver_exit(void)
331 {
332 close(listenfd);
333 unlink(MDNS_UDS_SERVERPATH);
334 return 0;
335 }
336
337
338 // add the named socket as a runloop source
339 int udsserver_add_rl_source(void)
340 {
341 CFSocketContext context = { 0, NULL, NULL, NULL, NULL };
342 CFSocketRef sr = CFSocketCreateWithNative(kCFAllocatorDefault, listenfd, kCFSocketReadCallBack, connect_callback, &context);
343 if (!sr)
344 {
345 debugf("ERROR: udsserver_add_rl_source - CFSocketCreateWithNative");
346 return -1;
347 }
348 CFRunLoopSourceRef rls = CFSocketCreateRunLoopSource(kCFAllocatorDefault, sr, 0);
349
350 if (!rls)
351 {
352 debugf("ERROR: udsserver_add_rl_source - CFSocketCreateRunLoopSource");
353 return -1;
354 }
355 CFRunLoopAddSource(CFRunLoopGetCurrent(), rls, kCFRunLoopDefaultMode);
356 return 0;
357 }
358
359 mDNSs32 udsserver_idle(mDNSs32 nextevent)
360 {
361 request_state *req = all_requests, *tmp, *prev = NULL;
362 reply_state *fptr;
363 transfer_state result;
364 mDNSs32 now = mDNSPlatformTimeNow();
365
366
367 while(req)
368 {
369 result = t_uninitialized;
370 if (req->u_err)
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))
374 {
375 while(req->replies)
376 {
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)
381 {
382 fptr = req->replies;
383 req->replies = req->replies->next;
384 freeL("udsserver_idle", fptr);
385 }
386 else if (result == t_terminated || result == t_error)
387 {
388 abort_request(req);
389 break;
390 }
391 else if (result == t_morecoming) // client's queues are full, move to next
392 {
393 if (nextevent - now > mDNSPlatformOneSecond)
394 nextevent = now + mDNSPlatformOneSecond;
395 break; // start where we left off in a second
396 }
397 }
398 }
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()
401 {
402 tmp = req;
403 if (prev) prev->next = req->next;
404 if (req == all_requests) all_requests = all_requests->next;
405 req = req->next;
406 freeL("udsserver_idle", tmp);
407 }
408 else
409 {
410 prev = req;
411 req = req->next;
412 }
413 }
414 return nextevent;
415 }
416
417 void udsserver_info(void)
418 {
419 request_state *req;
420 for (req = all_requests; req; req=req->next)
421 {
422 void *t = req->termination_context;
423 if (!t) continue;
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);
434 }
435 }
436
437 void udsserver_handle_configchange(void)
438 {
439 registered_service *srv;
440 request_state *req;
441 mStatus err;
442
443 for (req = all_requests; req; req = req->next)
444 {
445 srv = req->service;
446 if (srv->autoname && !SameDomainLabel(srv->name.c, mDNSStorage.nicelabel.c))
447 {
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
452 }
453 }
454 }
455
456
457
458
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)
462 {
463 int sd, clilen, optval;
464 struct sockaddr_un cliaddr;
465 CFSocketContext context = { 0, NULL, NULL, NULL, NULL };
466 request_state *rstate;
467 // int errpipe[2];
468
469 #pragma unused(s, t, dr, c, i)
470
471 clilen = sizeof(cliaddr);
472 sd = accept(listenfd, (struct sockaddr *)&cliaddr, &clilen);
473
474 if (sd < 0)
475 {
476 if (errno == EWOULDBLOCK) return;
477 my_perror("ERROR: accept");
478 return;
479 }
480 optval = 1;
481 if (setsockopt(sd, SOL_SOCKET, SO_NOSIGPIPE, &optval, sizeof(optval)) < 0)
482 {
483 my_perror("ERROR: setsockopt - SOL_NOSIGPIPE - aborting client");
484 close(sd);
485 return;
486 }
487
488 if (fcntl(sd, F_SETFL, O_NONBLOCK) < 0)
489 {
490 my_perror("ERROR: could not set connected socket to non-blocking mode - aborting client");
491 close(sd);
492 return;
493 }
494
495 /*
496 // open a pipe to deliver error messages, pass descriptor to client
497 if (pipe(errpipe) < 0)
498 {
499 my_perror("ERROR: could not create pipe");
500 exit(1);
501 }
502
503 if (ioctl(sd, I_SENDFD, errpipe[0]) < 0)
504 {
505 my_perror("ERROR: could not pass pipe descriptor to client. Aborting client.\n");
506 close(sd);
507 return;
508 }
509 if (fcntl(errpipe[1], F_SETFL, O_NONBLOCK) < 0)
510 {
511 my_perror("ERROR: could not set error pipe to non-blocking mode - aborting client");
512 close(sd);
513 close(errpipe[1]);
514 return;
515 }
516 */
517
518 // allocate a request_state struct that will live with the socket
519 rstate = mallocL("connect_callback", sizeof(request_state));
520 if (!rstate)
521 {
522 my_perror("ERROR: malloc");
523 exit(1);
524 }
525 bzero(rstate, sizeof(request_state));
526 rstate->ts = t_morecoming;
527 rstate->sd = sd;
528 //rstate->errfd = errpipe[1];
529
530 //now create CFSocket wrapper and add to run loop
531 context.info = rstate;
532 rstate->sr = CFSocketCreateWithNative(kCFAllocatorDefault, sd, kCFSocketReadCallBack, request_callback, &context);
533 if (!rstate->sr)
534 {
535 debugf("ERROR: connect_callback - CFSocketCreateWithNative");
536 freeL("connect_callback", rstate);
537 close(sd);
538 return;
539 }
540 rstate->rls = CFSocketCreateRunLoopSource(kCFAllocatorDefault, rstate->sr, 0);
541 if (!rstate->rls)
542 {
543 debugf("ERROR: connect_callback - CFSocketCreateRunLoopSource");
544 CFSocketInvalidate(rstate->sr); // automatically closes socket
545 CFRelease(rstate->sr);
546 freeL("connect_callback", rstate);
547 return;
548 }
549 CFRunLoopAddSource(CFRunLoopGetCurrent(), rstate->rls, kCFRunLoopDefaultMode);
550 if (!CFRunLoopContainsSource(CFRunLoopGetCurrent(), rstate->rls, kCFRunLoopDefaultMode))
551 {
552 LogMsg("ERROR: connect_callback, CFRunLoopAddSource");
553 abort_request(rstate);
554 return;
555 }
556 rstate->next = all_requests;
557 all_requests = rstate;
558 }
559
560
561 // main client request handling routine. reads request and calls the appropriate request-specific
562 // handler
563 static void request_callback(CFSocketRef sr, CFSocketCallBackType t, CFDataRef dr, const void *context, void *info)
564 {
565 request_state *rstate = info;
566 transfer_state result;
567 struct sockaddr_un cliaddr;
568 char ctrl_path[MAX_CTLPATH];
569
570 #pragma unused(sr, t, dr, context)
571
572 int native = CFSocketGetNative(sr);
573 if (native != rstate->sd)
574 {
575 LogMsg("ERROR: request_callback - CFSocket's native descriptor does not match rstate member descriptor.");
576 abort_request(rstate);
577 unlink_request(rstate);
578 return;
579 }
580
581 result = read_msg(rstate);
582 if (result == t_morecoming)
583 {
584 return;
585 }
586 if (result == t_terminated)
587 {
588 abort_request(rstate);
589 unlink_request(rstate);
590 return;
591 }
592 if (result == t_error)
593 {
594 abort_request(rstate);
595 unlink_request(rstate);
596 return;
597 }
598
599 if (rstate->hdr.version != VERSION)
600 {
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);
605 return;
606 }
607
608 // check if client wants silent operation
609 if (rstate->hdr.flags & IPC_FLAGS_NOREPLY) rstate->no_reply = 1;
610
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;
614 else
615 {
616 if ((rstate->errfd = socket(AF_LOCAL, SOCK_STREAM, 0)) < 0)
617 {
618 my_perror("ERROR: socket");
619 exit(1);
620 }
621 if (fcntl(rstate->errfd, F_SETFL, O_NONBLOCK) < 0)
622 {
623 my_perror("ERROR: could not set control socket to non-blocking mode");
624 abort_request(rstate);
625 unlink_request(rstate);
626 return;
627 }
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)
633 {
634 my_perror("ERROR: connect");
635 abort_request(rstate);
636 unlink_request(rstate);
637 }
638 }
639
640
641
642
643 switch(rstate->hdr.op.request_op)
644 {
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;
655 default:
656 debugf("ERROR: udsserver_recv_request - unsupported request type: %d", rstate->hdr.op.request_op);
657 }
658 }
659
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.
664
665
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.
669
670 static void handle_query_request(request_state *rstate)
671 {
672 DNSServiceFlags flags;
673 uint32_t interfaceIndex;
674 char name[256];
675 uint16_t rrtype, rrclass;
676 char *ptr;
677 domainname dname;
678 mStatus result;
679
680 if (rstate->ts != t_complete)
681 {
682 LogMsg("ERROR: handle_query_request - transfer state != t_complete");
683 goto error;
684 }
685 ptr = rstate->msgdata;
686 if (!ptr)
687 {
688 LogMsg("ERROR: handle_query_request - NULL msgdata");
689 goto error;
690 }
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;
700 return;
701
702 bad_param:
703 deliver_error(rstate, mStatus_BadParamErr);
704 rstate->terminate = NULL; // don't try to terminate insuccessful Core calls
705 error:
706 abort_request(rstate);
707 unlink_request(rstate);
708 return;
709 }
710
711 static void handle_resolve_request(request_state *rstate)
712 {
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
717 domainname fqdn;
718 resolve_t *srv, *txt;
719 resolve_termination_t *term;
720 mStatus err;
721
722 if (rstate->ts != t_complete)
723 {
724 LogMsg("ERROR: handle_resolve_request - transfer state != t_complete");
725 abort_request(rstate);
726 unlink_request(rstate);
727 return;
728 }
729
730 // extract the data from the message
731 ptr = rstate->msgdata;
732 if (!ptr)
733 {
734 LogMsg("ERROR: handle_resolve_request - NULL msgdata");
735 abort_request(rstate);
736 unlink_request(rstate);
737 return;
738 }
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)
746 goto bad_param;
747
748 // free memory in rstate since we don't need it anymore
749 freeL("handle_resolve_request", rstate->msgbuf);
750 rstate->msgbuf = NULL;
751
752 if (build_domainname_from_strings(&fqdn, name, regtype, domain) < 0)
753 goto bad_param;
754
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;
763
764 // format questions
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;
771
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;
778
779 // set up termination info
780 term = mallocL("handle_resolve_request", sizeof(resolve_termination_t));
781 if (!term) goto malloc_error;
782 term->srv = srv;
783 term->txt = txt;
784 term->rstate = rstate;
785 rstate->termination_context = term;
786 rstate->terminate = resolve_termination_callback;
787
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));
792
793 // ask the questions
794 err = mDNS_StartQuery(&mDNSStorage, &srv->question);
795 if (!err) err = mDNS_StartQuery(&mDNSStorage, &txt->question);
796
797 if (err)
798 {
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
804 }
805 if (deliver_error(rstate, err) < 0 || err)
806 {
807 abort_request(rstate);
808 unlink_request(rstate);
809 }
810 return;
811
812 bad_param:
813 deliver_error(rstate, mStatus_BadParamErr);
814 abort_request(rstate);
815 unlink_request(rstate);
816 return;
817
818 malloc_error:
819 my_perror("ERROR: malloc");
820 exit(1);
821 }
822
823 static void resolve_termination_callback(void *context)
824 {
825 resolve_termination_t *term = context;
826 request_state *rs;
827
828 if (!term)
829 {
830 LogMsg("ERROR: resolve_termination_callback: double termination");
831 return;
832 }
833 rs = term->rstate;
834
835 mDNS_StopQuery(&mDNSStorage, &term->txt->question);
836 mDNS_StopQuery(&mDNSStorage, &term->srv->question);
837
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;
844 }
845
846
847
848 static void resolve_result_callback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord)
849 {
850 int len = 0;
851 char fullname[MAX_ESCAPED_DOMAIN_NAME], target[MAX_ESCAPED_DOMAIN_NAME];
852 char *data;
853 transfer_state result;
854 reply_state *rep;
855 request_state *rs = question->QuestionContext;
856 resolve_result_t *res = rs->resolve_results;
857 #pragma unused(m)
858
859 if (!AddRecord)
860 {
861 if (answer->rrtype == kDNSType_TXT && res->txt == answer) res->txt = mDNSNULL;
862 if (answer->rrtype == kDNSType_SRV && res->srv == answer) res->srv = mDNSNULL;
863 return;
864 }
865
866 if (answer->rrtype == kDNSType_TXT) res->txt = answer;
867 if (answer->rrtype == kDNSType_SRV) res->srv = answer;
868
869 if (!res->txt || !res->srv) return; // only deliver result to client if we have both answers
870
871 ConvertDomainNameToCString(&answer->name, fullname);
872 ConvertDomainNameToCString(&res->srv->rdata->u.srv.target, target);
873
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;
882
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;
888 data = rep->sdata;
889
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);
896
897 result = send_msg(rep);
898 if (result == t_error || result == t_terminated)
899 {
900 abort_request(rs);
901 unlink_request(rs);
902 freeL("resolve_result_callback", rep);
903 }
904 else if (result == t_complete) freeL("resolve_result_callback", rep);
905 else append_reply(rs, rep);
906 }
907
908
909
910
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)
913 {
914 DNSQuestion *q;
915 mStatus result;
916 mDNSInterfaceID InterfaceID = mDNSPlatformInterfaceIDfromInterfaceIndex(&mDNSStorage, ifi);
917 if (ifi && !InterfaceID) return(mStatus_BadParamErr);
918
919 q = mallocL("do_question", sizeof(DNSQuestion));
920 if (!q)
921 {
922 my_perror("ERROR: do_question - malloc");
923 exit(1);
924 }
925 bzero(q, sizeof(DNSQuestion));
926
927 q->QuestionContext = rstate;
928 q->QuestionCallback = question_result_callback;
929 memcpy(&q->qname, name, MAX_DOMAIN_NAME);
930 q->qtype = rrtype;
931 q->qclass = rrclass;
932 q->InterfaceID = InterfaceID;
933
934
935 rstate->termination_context = q;
936 rstate->terminate = question_termination_callback;
937
938 result = mDNS_StartQuery(&mDNSStorage, q);
939 if (result != mStatus_NoError) LogMsg("ERROR: mDNS_StartQuery: %d", (int)result);
940 return result;
941 }
942
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)
945 {
946 char *data;
947 char name[MAX_ESCAPED_DOMAIN_NAME];
948 request_state *req;
949 reply_state *rep;
950 int len;
951
952 #pragma unused(m)
953 //mDNS_StopQuery(m, question);
954 req = question->QuestionContext;
955
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;
964
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;
969 data = rep->sdata;
970
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);
977
978 append_reply(req, rep);
979 return;
980 }
981
982 static void question_termination_callback(void *context)
983 {
984 DNSQuestion *q = context;
985
986
987 mDNS_StopQuery(&mDNSStorage, q); // no need to error check
988 freeL("question_termination_callback", q);
989 }
990
991
992 static void handle_browse_request(request_state *request)
993 {
994 DNSServiceFlags flags;
995 uint32_t interfaceIndex;
996 char regtype[MAX_ESCAPED_DOMAIN_NAME], domain[MAX_ESCAPED_DOMAIN_NAME];
997 DNSQuestion *q;
998 domainname typedn, domdn;
999 char *ptr;
1000 mStatus result;
1001
1002 if (request->ts != t_complete)
1003 {
1004 LogMsg("ERROR: handle_browse_request - transfer state != t_complete");
1005 abort_request(request);
1006 unlink_request(request);
1007 return;
1008 }
1009 q = mallocL("handle_browse_request", sizeof(DNSQuestion));
1010 if (!q)
1011 {
1012 my_perror("ERROR: handle_browse_request - malloc");
1013 exit(1);
1014 }
1015 bzero(q, sizeof(DNSQuestion));
1016
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)
1023 goto bad_param;
1024
1025 freeL("handle_browse_request", request->msgbuf);
1026 request->msgbuf = NULL;
1027
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."))
1034 goto bad_param;
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);
1039 return;
1040
1041 bad_param:
1042 deliver_error(request, mStatus_BadParamErr);
1043 abort_request(request);
1044 unlink_request(request);
1045 }
1046
1047 static void browse_result_callback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord)
1048 {
1049 request_state *req;
1050 reply_state *rep;
1051 mStatus err;
1052
1053 #pragma unused(m)
1054 req = question->QuestionContext;
1055
1056 err = gen_rr_response(&answer->rdata->u.name, answer->InterfaceID, req, &rep);
1057 if (err)
1058 {
1059 if (deliver_async_error(req, browse_reply, err) < 0)
1060 {
1061 abort_request(req);
1062 unlink_request(req);
1063 }
1064 return;
1065 }
1066 if (AddRecord) rep->rhdr->flags |= kDNSServiceFlagsAdd; // non-zero TTL indicates add
1067 append_reply(req, rep);
1068 return;
1069 }
1070
1071 static void browse_termination_callback(void *context)
1072 {
1073 DNSQuestion *q = context;
1074
1075 mDNS_StopBrowse(&mDNSStorage, q); // no need to error-check result
1076 freeL("browse_termination_callback", q);
1077 }
1078
1079 // service registration
1080 static void handle_regservice_request(request_state *request)
1081 {
1082 DNSServiceFlags flags;
1083 uint32_t ifi;
1084 char name[256], regtype[MAX_ESCAPED_DOMAIN_NAME], domain[MAX_ESCAPED_DOMAIN_NAME], host[MAX_ESCAPED_DOMAIN_NAME];
1085 uint16_t txtlen;
1086 mDNSIPPort port;
1087 void *txtdata;
1088 char *ptr;
1089 domainlabel n;
1090 domainname t, d, h, srv;
1091 registered_service *r_srv;
1092 int srs_size;
1093 mStatus result;
1094
1095 char *sub, *rtype_ptr;
1096 int i, num_subtypes;
1097
1098
1099 if (request->ts != t_complete)
1100 {
1101 LogMsg("ERROR: handle_regservice_request - transfer state != t_complete");
1102 abort_request(request);
1103 unlink_request(request);
1104 return;
1105 }
1106
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)
1117 goto bad_param;
1118
1119 port.NotAnInteger = get_short(&ptr);
1120 txtlen = get_short(&ptr);
1121 txtdata = get_rdata(&ptr, txtlen);
1122
1123 // count subtypes, replacing commas w/ whitespace
1124 rtype_ptr = regtype;
1125 num_subtypes = -1;
1126 while((sub = strsep(&rtype_ptr, ",")))
1127 if (*sub) num_subtypes++;
1128
1129 if (!name[0]) n = (&mDNSStorage)->nicelabel;
1130 else if (!MakeDomainLabelFromLiteralString(&n, name))
1131 goto bad_param;
1132 if ((!regtype[0] || !MakeDomainNameFromDNSNameString(&t, regtype)) ||
1133 (!MakeDomainNameFromDNSNameString(&d, *domain ? domain : "local.")) ||
1134 (!ConstructServiceName(&srv, &n, &t, &d)))
1135 goto bad_param;
1136 if (host[0] && !MakeDomainNameFromDNSNameString(&h, host)) goto bad_param;
1137
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)
1144 {
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++)
1149 {
1150 if (!MakeDomainNameFromDNSNameString(&(r_srv->subtypes + i)->resrec.name, sub))
1151 {
1152 freeL("handle_regservice_request", r_srv->subtypes);
1153 freeL("handle_regservice_request", r_srv);
1154 r_srv = NULL;
1155 goto bad_param;
1156 }
1157 sub += strlen(sub) + 1;
1158 }
1159 }
1160 else r_srv->subtypes = NULL;
1161 r_srv->request = request;
1162
1163 r_srv->autoname = (!name[0]);
1164 r_srv->rename_on_memfree = 0;
1165 r_srv->renameonconflict = !(flags & kDNSServiceFlagsNoAutoRename);
1166 r_srv->name = n;
1167 request->termination_context = r_srv;
1168 request->terminate = regservice_termination_callback;
1169 request->service = r_srv;
1170
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)
1175 {
1176 abort_request(request);
1177 unlink_request(request);
1178 }
1179 else
1180 {
1181 reset_connected_rstate(request); // reset to receive add/remove messages
1182 }
1183 return;
1184
1185 bad_param:
1186 deliver_error(request, mStatus_BadParamErr);
1187 abort_request(request);
1188 unlink_request(request);
1189 return;
1190
1191 malloc_error:
1192 my_perror("ERROR: malloc");
1193 exit(1);
1194 }
1195
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())
1199
1200 static void regservice_callback(mDNS *const m, ServiceRecordSet *const srs, mStatus result)
1201 {
1202 mStatus err;
1203 ExtraResourceRecord *extra;
1204 registered_service *r_srv = srs->ServiceContext;
1205 request_state *rs = r_srv->request;
1206
1207 #pragma unused(m)
1208
1209 if (!rs && (result != mStatus_MemFree && !r_srv->rename_on_memfree))
1210 {
1211 // error should never happen - safest to log and continue
1212 LogMsg("ERROR: regservice_callback: received result %d with a NULL request pointer\n");
1213 return;
1214 }
1215
1216 if (result == mStatus_NoError)
1217 return process_service_registration(srs);
1218 else if (result == mStatus_MemFree)
1219 {
1220 if (r_srv->rename_on_memfree)
1221 {
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
1227 }
1228 else
1229 {
1230 while (r_srv->srs->Extras)
1231 {
1232 extra = r_srv->srs->Extras;
1233 r_srv->srs->Extras = r_srv->srs->Extras->next;
1234 freeL("regservice_callback", extra);
1235 }
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);
1240 return;
1241 }
1242 }
1243 else if (result == mStatus_NameConflict)
1244 {
1245 if (r_srv->autoname || r_srv->renameonconflict)
1246 {
1247 mDNS_RenameAndReregisterService(&mDNSStorage, srs, mDNSNULL);
1248 return;
1249 }
1250 else
1251 {
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)
1258 {
1259 abort_request(rs);
1260 unlink_request(rs);
1261 }
1262 return;
1263 }
1264 }
1265 else
1266 {
1267 LogMsg("ERROR: unknown result in regservice_callback");
1268 if (deliver_async_error(rs, reg_service_reply, result) < 0)
1269 {
1270 abort_request(rs);
1271 unlink_request(rs);
1272 }
1273 return;
1274 }
1275 }
1276
1277 static void handle_add_request(request_state *rstate)
1278 {
1279 registered_record_entry *re;
1280 ExtraResourceRecord *extra;
1281 uint32_t size, ttl;
1282 uint16_t rrtype, rdlen;
1283 char *ptr, *rdata;
1284 mStatus result;
1285 DNSServiceFlags flags;
1286 ServiceRecordSet *srs = rstate->service->srs;
1287
1288 if (!srs)
1289 {
1290 LogMsg("ERROR: handle_add_request - no service record set in request state");
1291 deliver_error(rstate, mStatus_UnknownErr);
1292 return;
1293 }
1294
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);
1301
1302 if (rdlen > sizeof(RDataBody)) size = rdlen;
1303 else size = sizeof(RDataBody);
1304
1305 extra = mallocL("hanle_add_request", sizeof(ExtraResourceRecord) - sizeof(RDataBody) + size);
1306 if (!extra)
1307 {
1308 my_perror("ERROR: malloc");
1309 exit(1);
1310 }
1311
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);
1320 if (result)
1321 {
1322 freeL("handle_add_request", rstate->msgbuf);
1323 rstate->msgbuf = NULL;
1324 freeL("handle_add_request", extra);
1325 return;
1326 }
1327 re = mallocL("handle_add_request", sizeof(registered_record_entry));
1328 if (!re)
1329 {
1330 my_perror("ERROR: malloc");
1331 exit(1);
1332 }
1333 re->key = rstate->hdr.reg_index;
1334 re->rr = &extra->r;
1335 re->next = rstate->reg_recs;
1336 rstate->reg_recs = re;
1337 }
1338
1339 static void handle_update_request(request_state *rstate)
1340 {
1341 registered_record_entry *reptr;
1342 AuthRecord *rr;
1343 RData *newrd;
1344 uint16_t rdlen, rdsize;
1345 char *ptr, *rdata;
1346 uint32_t ttl;
1347 mStatus result;
1348
1349 if (rstate->hdr.reg_index == TXT_RECORD_INDEX)
1350 {
1351 if (!rstate->service)
1352 {
1353 deliver_error(rstate, mStatus_BadParamErr);
1354 return;
1355 }
1356 rr = &rstate->service->srs->RR_TXT;
1357 }
1358 else
1359 {
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);
1363 rr = reptr->rr;
1364 }
1365
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);
1371
1372 if (rdlen > sizeof(RDataBody)) rdsize = rdlen;
1373 else rdsize = sizeof(RDataBody);
1374 newrd = mallocL("handle_update_request", sizeof(RData) - sizeof(RDataBody) + rdsize);
1375 if (!newrd)
1376 {
1377 my_perror("ERROR: malloc");
1378 exit(1);
1379 }
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);
1385 }
1386
1387 static void update_callback(mDNS *const m, AuthRecord *const rr, RData *oldrd)
1388 {
1389 #pragma unused(m)
1390
1391 if (oldrd != &rr->rdatastorage) freeL("update_callback", oldrd);
1392 }
1393
1394 static void process_service_registration(ServiceRecordSet *const srs)
1395 {
1396 reply_state *rep;
1397 transfer_state send_result;
1398 mStatus err;
1399 registered_service *r_srv = srs->ServiceContext;
1400 request_state *req = r_srv->request;
1401
1402
1403 err = gen_rr_response(&srs->RR_SRV.resrec.name, srs->RR_SRV.resrec.InterfaceID, req, &rep);
1404 if (err)
1405 {
1406 if (deliver_async_error(req, reg_service_reply, err) < 0)
1407 {
1408 abort_request(req);
1409 unlink_request(req);
1410 }
1411 return;
1412 }
1413 send_result = send_msg(rep);
1414 if (send_result == t_error || send_result == t_terminated)
1415 {
1416 abort_request(req);
1417 unlink_request(req);
1418 freeL("process_service_registration", rep);
1419 }
1420 else if (send_result == t_complete) freeL("process_service_registration", rep);
1421 else append_reply(req, rep);
1422 }
1423
1424 static void regservice_termination_callback(void *context)
1425 {
1426 registered_service *srv = context;
1427
1428 // only safe to free memory if registration is not valid, ie deregister fails
1429 if (mDNS_DeregisterService(&mDNSStorage, srv->srs) != mStatus_NoError)
1430 {
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);
1435 }
1436 }
1437
1438
1439 static void handle_regrecord_request(request_state *rstate)
1440 {
1441 AuthRecord *rr;
1442 regrecord_callback_context *rcc;
1443 registered_record_entry *re;
1444 mStatus result;
1445
1446 if (rstate->ts != t_complete)
1447 {
1448 LogMsg("ERROR: handle_regrecord_request - transfer state != t_complete");
1449 abort_request(rstate);
1450 unlink_request(rstate);
1451 return;
1452 }
1453
1454 rr = read_rr_from_ipc_msg(rstate->msgdata, 1);
1455 if (!rr)
1456 {
1457 deliver_error(rstate, mStatus_BadParamErr);
1458 return;
1459 }
1460
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;
1467
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;
1472 re->rr = rr;
1473 re->next = rstate->reg_recs;
1474 rstate->reg_recs = re;
1475
1476 if (!rstate->terminate)
1477 {
1478 rstate->terminate = connected_registration_termination;
1479 rstate->termination_context = rstate;
1480 }
1481
1482 result = mDNS_Register(&mDNSStorage, rr);
1483 deliver_error(rstate, result);
1484 reset_connected_rstate(rstate);
1485 return;
1486
1487 malloc_error:
1488 my_perror("ERROR: malloc");
1489 return;
1490 }
1491
1492 static void regrecord_callback(mDNS *const m, AuthRecord *const rr, mStatus result)
1493 {
1494 regrecord_callback_context *rcc;
1495 int len;
1496 reply_state *reply;
1497 transfer_state ts;
1498
1499 #pragma unused(m)
1500
1501 if (result == mStatus_MemFree) { freeL("regrecord_callback", rr); return; }
1502 rcc = rr->RecordContext;
1503
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);
1508
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;
1514
1515 ts = send_msg(reply);
1516 if (ts == t_error || ts == t_terminated)
1517 {
1518 abort_request(rcc->rstate);
1519 unlink_request(rcc->rstate);
1520 }
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
1523 }
1524
1525 static void connected_registration_termination(void *context)
1526 {
1527 registered_record_entry *fptr, *ptr = ((request_state *)context)->reg_recs;
1528 while(ptr)
1529 {
1530 mDNS_Deregister(&mDNSStorage, ptr->rr);
1531 fptr = ptr;
1532 ptr = ptr->next;
1533 freeL("connected_registration_termination", fptr);
1534 }
1535 }
1536
1537
1538
1539 static void handle_removerecord_request(request_state *rstate)
1540 {
1541 registered_record_entry *reptr, *prev = NULL;
1542 mStatus err = mStatus_UnknownErr;
1543 char *ptr;
1544 reptr = rstate->reg_recs;
1545
1546 ptr = rstate->msgdata;
1547 get_flags(&ptr); // flags unused
1548
1549 while(reptr)
1550 {
1551 if (reptr->key == rstate->hdr.reg_index) // found match
1552 {
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
1557 break;
1558 }
1559 prev = reptr;
1560 reptr = reptr->next;
1561 }
1562 reset_connected_rstate(rstate);
1563 if (deliver_error(rstate, err) < 0)
1564 {
1565 abort_request(rstate);
1566 unlink_request(rstate);
1567 }
1568 }
1569
1570
1571 // domain enumeration
1572 static void handle_enum_request(request_state *rstate)
1573 {
1574 DNSServiceFlags flags, add_default;
1575 uint32_t ifi;
1576 char *ptr = rstate->msgdata;
1577 domain_enum_t *def, *all;
1578 enum_termination_t *term;
1579 reply_state *reply; // initial default reply
1580 transfer_state tr;
1581 mStatus err;
1582 int result;
1583
1584 if (rstate->ts != t_complete)
1585 {
1586 LogMsg("ERROR: handle_enum_request - transfer state != t_complete");
1587 abort_request(rstate);
1588 unlink_request(rstate);
1589 return;
1590 }
1591
1592 flags = get_flags(&ptr);
1593 ifi = get_long(&ptr);
1594 mDNSInterfaceID InterfaceID = mDNSPlatformInterfaceIDfromInterfaceIndex(&mDNSStorage, ifi);
1595 if (ifi && !InterfaceID)
1596 {
1597 deliver_error(rstate, mStatus_BadParamErr);
1598 abort_request(rstate);
1599 unlink_request(rstate);
1600 }
1601
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)
1607 {
1608 my_perror("ERROR: malloc");
1609 exit(1);
1610 }
1611
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;
1616 term->def = def;
1617 term->all = all;
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;
1627
1628 // make the calls
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
1633
1634 if (result < 0 || err)
1635 {
1636 abort_request(rstate);
1637 unlink_request(rstate);
1638 return;
1639 }
1640
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)
1646 {
1647 freeL("handle_enum_request", def);
1648 freeL("handle_enum_request", all);
1649 abort_request(rstate);
1650 unlink_request(rstate);
1651 return;
1652 }
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
1655 }
1656
1657 static void enum_result_callback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord)
1658 {
1659 char domain[MAX_ESCAPED_DOMAIN_NAME];
1660 domain_enum_t *de = question->QuestionContext;
1661 DNSServiceFlags flags = 0;
1662 reply_state *reply;
1663
1664 #pragma unused(m)
1665 if (answer->rrtype != kDNSType_PTR) return;
1666 if (AddRecord)
1667 {
1668 flags |= kDNSServiceFlagsAdd;
1669 if (de->type == mDNS_DomainTypeRegistrationDefault || de->type == mDNS_DomainTypeBrowseDefault)
1670 flags |= kDNSServiceFlagsDefault;
1671 }
1672 else
1673 {
1674 flags |= kDNSServiceFlagsRemove;
1675 }
1676 ConvertDomainNameToCString(&answer->rdata->u.name, domain);
1677 reply = format_enumeration_reply(de->rstate, domain, flags, mDNSPlatformInterfaceIndexfromInterfaceID(&mDNSStorage, answer->InterfaceID), kDNSServiceErr_NoError);
1678 if (!reply)
1679 {
1680 LogMsg("ERROR: enum_result_callback, format_enumeration_reply");
1681 return;
1682 }
1683 reply->next = NULL;
1684 append_reply(de->rstate, reply);
1685 return;
1686 }
1687
1688 static reply_state *format_enumeration_reply(request_state *rstate, char *domain, DNSServiceFlags flags, uint32_t ifi, DNSServiceErrorType err)
1689 {
1690 int len;
1691 reply_state *reply;
1692 char *data;
1693
1694
1695 len = sizeof(DNSServiceFlags);
1696 len += sizeof(uint32_t);
1697 len += sizeof(DNSServiceErrorType);
1698 len += strlen(domain) + 1;
1699
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);
1706 return reply;
1707 }
1708
1709 static void enum_termination_callback(void *context)
1710 {
1711 enum_termination_t *t = context;
1712 mDNS *coredata = &mDNSStorage;
1713
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);
1720 }
1721
1722 static void handle_reconfirm_request(request_state *rstate)
1723 {
1724 AuthRecord *rr;
1725
1726 rr = read_rr_from_ipc_msg(rstate->msgdata, 0);
1727 if (!rr) return;
1728 mDNS_ReconfirmByValue(&mDNSStorage, &rr->resrec);
1729 abort_request(rstate);
1730 unlink_request(rstate);
1731 freeL("handle_reconfirm_request", rr);
1732 }
1733
1734
1735 // setup rstate to accept new reg/dereg requests
1736 static void reset_connected_rstate(request_state *rstate)
1737 {
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;
1744 }
1745
1746
1747
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)
1752 {
1753 char *rdata, name[256];
1754 AuthRecord *rr;
1755 DNSServiceFlags flags;
1756 uint32_t interfaceIndex;
1757 uint16_t type, class, rdlen;
1758 int storage_size;
1759
1760 flags = get_flags(&msgbuf);
1761 interfaceIndex = get_long(&msgbuf);
1762 if (get_string(&msgbuf, name, 256) < 0)
1763 {
1764 LogMsg("ERROR: read_rr_from_ipc_msg - get_string");
1765 return NULL;
1766 }
1767 type = get_short(&msgbuf);
1768 class = get_short(&msgbuf);
1769 rdlen = get_short(&msgbuf);
1770
1771 if (rdlen > sizeof(RDataBody)) storage_size = rdlen;
1772 else storage_size = sizeof(RDataBody);
1773
1774 rr = mallocL("read_rr_from_ipc_msg", sizeof(AuthRecord) - sizeof(RDataBody) + storage_size);
1775 if (!rr)
1776 {
1777 my_perror("ERROR: malloc");
1778 exit(1);
1779 }
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))
1784 {
1785 LogMsg("ERROR: bad name: %s", name);
1786 freeL("read_rr_from_ipc_msg", rr);
1787 return NULL;
1788 }
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);
1799 if (ttl)
1800 {
1801 rr->resrec.rroriginalttl = get_long(&msgbuf);
1802 }
1803 return rr;
1804 }
1805
1806
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.
1810
1811 static mStatus gen_rr_response(domainname *servicename, mDNSInterfaceID id, request_state *request, reply_state **rep)
1812 {
1813 char *data;
1814 int len;
1815 domainlabel name;
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];
1820
1821 *rep = NULL;
1822
1823 if (!DeconstructServiceName(servicename, &name, &type, &dom))
1824 return kDNSServiceErr_Unknown;
1825
1826 ConvertDomainLabelToCString_unescaped(&name, namestr);
1827 ConvertDomainNameToCString(&type, typestr);
1828 ConvertDomainNameToCString(&dom, domstr);
1829
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;
1837
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;
1843
1844 put_string(namestr, &data);
1845 put_string(typestr, &data);
1846 put_string(domstr, &data);
1847 return mStatus_NoError;
1848 }
1849
1850
1851 static int build_domainname_from_strings(domainname *srv, char *name, char *regtype, char *domain)
1852 {
1853 domainlabel n;
1854 domainname d, t;
1855
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;
1860 return 0;
1861 }
1862
1863
1864 // append a reply to the list in a request object
1865 static void append_reply(request_state *req, reply_state *rep)
1866 {
1867 reply_state *ptr;
1868
1869 if (!req->replies) req->replies = rep;
1870 else
1871 {
1872 ptr = req->replies;
1873 while (ptr->next) ptr = ptr->next;
1874 ptr->next = rep;
1875 }
1876 rep->next = NULL;
1877 }
1878
1879
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)
1884 {
1885 uint32_t nleft;
1886 int nread;
1887 char buf[4]; // dummy for death notification
1888
1889 if (rs->ts == t_terminated || rs->ts == t_error)
1890 {
1891 LogMsg("ERROR: read_msg called with transfer state terminated or error");
1892 rs->ts = t_error;
1893 return t_error;
1894 }
1895
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.");
1902 rs->ts = t_error;
1903 return t_error;
1904 }
1905
1906 if (rs->ts != t_morecoming)
1907 {
1908 LogMsg("ERROR: read_msg called with invalid transfer state (%d)", rs->ts);
1909 rs->ts = t_error;
1910 return t_error;
1911 }
1912
1913 if (rs->hdr_bytes < sizeof(ipc_msg_hdr))
1914 {
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))
1921 {
1922 LogMsg("ERROR: read_msg - read too many header bytes");
1923 rs->ts = t_error;
1924 return t_error;
1925 }
1926 }
1927
1928 // only read data if header is complete
1929 if (rs->hdr_bytes == sizeof(ipc_msg_hdr))
1930 {
1931 if (rs->hdr.datalen == 0) // ok in removerecord requests
1932 {
1933 rs->ts = t_complete;
1934 rs->msgbuf = NULL;
1935 return t_complete;
1936 }
1937
1938 if (!rs->msgbuf) // allocate the buffer first time through
1939 {
1940 rs->msgbuf = mallocL("read_msg", rs->hdr.datalen);
1941 if (!rs->msgbuf)
1942 {
1943 my_perror("ERROR: malloc");
1944 rs->ts = t_error;
1945 return t_error;
1946 }
1947 rs->msgdata = rs->msgbuf;
1948 }
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)
1955 {
1956 LogMsg("ERROR: read_msg - read too many data bytes");
1957 rs->ts = t_error;
1958 return t_error;
1959 }
1960 }
1961
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;
1965
1966 return rs->ts;
1967
1968 rerror:
1969 if (errno == EAGAIN || errno == EINTR) return rs->ts;
1970 my_perror("ERROR: read_msg");
1971 rs->ts = t_error;
1972 return t_error;
1973 }
1974
1975
1976 static int send_msg(reply_state *rs)
1977 {
1978 ssize_t nwriten;
1979
1980 if (!rs->msgbuf)
1981 {
1982 LogMsg("ERROR: send_msg called with NULL message buffer");
1983 return t_error;
1984 }
1985
1986 if (rs->request->no_reply) //!!!KRS this behavior should be optimized if it becomes more common
1987 {
1988 rs->ts = t_complete;
1989 freeL("send_msg", rs->msgbuf);
1990 return t_complete;
1991 }
1992
1993 nwriten = send(rs->sd, rs->msgbuf + rs->nwriten, rs->len - rs->nwriten, 0);
1994 if (nwriten < 0)
1995 {
1996 if (errno == EINTR || errno == EAGAIN) nwriten = 0;
1997 else
1998 {
1999 if (errno == EPIPE)
2000 {
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;
2005 }
2006 else
2007 {
2008 my_perror("ERROR: send\n");
2009 rs->ts = t_error;
2010 return t_error;
2011 }
2012 }
2013 }
2014 rs->nwriten += nwriten;
2015
2016 if (rs->nwriten == rs->len)
2017 {
2018 rs->ts = t_complete;
2019 freeL("send_msg", rs->msgbuf);
2020 }
2021 return rs->ts;
2022 }
2023
2024
2025
2026 static reply_state *create_reply(reply_op_t op, int datalen, request_state *request)
2027 {
2028 reply_state *reply;
2029 int totallen;
2030
2031
2032 if ((unsigned)datalen < sizeof(reply_hdr))
2033 {
2034 LogMsg("ERROR: create_reply - data length less than lenght of required fields");
2035 return NULL;
2036 }
2037
2038 totallen = datalen + sizeof(ipc_msg_hdr);
2039 reply = mallocL("create_reply", sizeof(reply_state));
2040 if (!reply)
2041 {
2042 my_perror("ERROR: malloc");
2043 exit(1);
2044 }
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);
2051 if (!reply->msgbuf)
2052 {
2053 my_perror("ERROR: malloc");
2054 exit(1);
2055 }
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);
2063 return reply;
2064 }
2065
2066
2067 static int deliver_error(request_state *rstate, mStatus err)
2068 {
2069 int nwritten = -1;
2070 undelivered_error_t *undeliv;
2071
2072 nwritten = send(rstate->errfd, &err, sizeof(mStatus), 0);
2073 if (nwritten < (int)sizeof(mStatus))
2074 {
2075 if (errno == EINTR || errno == EAGAIN)
2076 nwritten = 0;
2077 if (nwritten < 0)
2078 {
2079 my_perror("ERROR: send - unable to deliver error to client");
2080 goto error;
2081 }
2082 //client blocked - store result and come backr
2083 undeliv = mallocL("deliver_error", sizeof(undelivered_error_t));
2084 if (!undeliv)
2085 {
2086 my_perror("ERROR: malloc");
2087 exit(1);
2088 }
2089 undeliv->err = err;
2090 undeliv->nwritten = nwritten;
2091 undeliv->sd = rstate->errfd;
2092 rstate->u_err = undeliv;
2093 return 0;
2094 }
2095 if (rstate->errfd != rstate->sd) close(rstate->errfd);
2096 return 0;
2097
2098 error:
2099 if (rstate->errfd != rstate->sd) close(rstate->errfd);
2100 return -1;
2101
2102 }
2103
2104
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)
2107 {
2108 int nwritten;
2109
2110 nwritten = send(rs->u_err->sd, (char *)(&rs->u_err) + rs->u_err->nwritten, sizeof(mStatus) - rs->u_err->nwritten, 0);
2111 if (nwritten < 0)
2112 {
2113 if (errno == EINTR || errno == EAGAIN)
2114 nwritten = 0;
2115 else
2116 {
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);
2119 return t_error;
2120 }
2121 }
2122 if (nwritten + rs->u_err->nwritten == sizeof(mStatus))
2123 {
2124 if (rs->u_err->sd == rs->sd) close(rs->u_err->sd);
2125 freeL("send_undelivered_error", rs->u_err);
2126 rs->u_err = NULL;
2127 return t_complete;
2128 }
2129 rs->u_err->nwritten += nwritten;
2130 return t_morecoming;
2131 }
2132
2133
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)
2138 {
2139 int len;
2140 reply_state *reply;
2141 transfer_state ts;
2142
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)
2149 {
2150 freeL("deliver_async_error", reply);
2151 return -1;
2152 }
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
2155 return 0;
2156 }
2157
2158
2159 static void abort_request(request_state *rs)
2160 {
2161 reply_state *rep, *ptr;
2162
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);
2167 CFRelease(rs->rls);
2168 CFSocketInvalidate(rs->sr);
2169 CFRelease(rs->sr);
2170 rs->sd = -1;
2171 if (rs->errfd >= 0) close(rs->errfd);
2172 rs->errfd = -1;
2173
2174 // free pending replies
2175 rep = rs->replies;
2176 while(rep)
2177 {
2178 if (rep->msgbuf) freeL("abort_request", rep->msgbuf);
2179 ptr = rep;
2180 rep = rep->next;
2181 freeL("abort_request", ptr);
2182 }
2183
2184 if (rs->u_err)
2185 {
2186 freeL("abort_request", rs->u_err);
2187 rs->u_err = NULL;
2188 }
2189 }
2190
2191
2192 static void unlink_request(request_state *rs)
2193 {
2194 request_state *ptr;
2195
2196 if (rs == all_requests)
2197 {
2198 all_requests = all_requests->next;
2199 freeL("unlink_request", rs);
2200 return;
2201 }
2202 for(ptr = all_requests; ptr->next; ptr = ptr->next)
2203 if (ptr->next == rs)
2204 {
2205 ptr->next = rs->next;
2206 freeL("unlink_request", rs);
2207 return;
2208 }
2209 }
2210
2211
2212
2213 //hack to search-replace perror's to LogMsg's
2214 static void my_perror(char *errmsg)
2215 {
2216 LogMsg("%s: %s", errmsg, strerror(errno));
2217 }
2218
2219