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