]> git.saurik.com Git - apple/mdnsresponder.git/blob - mDNSShared/dnssd_clientstub.c
mDNSResponder-58.8.1.tar.gz
[apple/mdnsresponder.git] / mDNSShared / dnssd_clientstub.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: dnssd_clientstub.c,v $
26 Revision 1.9 2003/08/15 21:30:39 cheshire
27 Bring up to date with LibInfo version
28
29 Revision 1.8 2003/08/13 23:54:52 ksekar
30 Bringing dnssd_clientstub.c up to date with Libinfo, per radar 3376640
31
32 Revision 1.7 2003/08/12 19:56:25 cheshire
33 Update to APSL 2.0
34
35 */
36
37 #include "dnssd_ipc.h"
38
39 #define CTL_PATH_PREFIX "/tmp/dnssd_clippath."
40 // error socket (if needed) is named "dnssd_clipath.[pid].xxx:n" where xxx are the
41 // last 3 digits of the time (in seconds) and n is the 6-digit microsecond time
42
43 // general utility functions
44 static DNSServiceRef connect_to_server(void);
45 DNSServiceErrorType deliver_request(void *msg, DNSServiceRef sdr, int reuse_sd);
46 static ipc_msg_hdr *create_hdr(int op, int *len, char **data_start, int reuse_socket);
47 static int my_read(int sd, char *buf, int len);
48 static int my_write(int sd, char *buf, int len);
49 static int domain_ends_in_dot(const char *dom);
50 // server response handlers
51 static void handle_query_response(DNSServiceRef sdr, ipc_msg_hdr *hdr, char *msg);
52 static void handle_browse_response(DNSServiceRef sdr, ipc_msg_hdr *hdr, char *data);
53 static void handle_regservice_response(DNSServiceRef sdr, ipc_msg_hdr *hdr, char *data);
54 static void handle_regrecord_response(DNSServiceRef sdr, ipc_msg_hdr *hdr, char *data);
55 static void handle_enumeration_response(DNSServiceRef sdr, ipc_msg_hdr *hdr, char *data);
56 static void handle_resolve_response(DNSServiceRef sdr, ipc_msg_hdr *hdr, char *data);
57
58 typedef struct _DNSServiceRef_t
59 {
60 int sockfd; // connected socket between client and daemon
61 int op; // request/reply_op_t
62 process_reply_callback process_reply;
63 void *app_callback;
64 void *app_context;
65 uint32_t max_index; //largest assigned record index - 0 if no additl. recs registered
66 } _DNSServiceRef_t;
67
68 typedef struct _DNSRecordRef_t
69 {
70 void *app_context;
71 DNSServiceRegisterRecordReply app_callback;
72 DNSRecordRef recref;
73 int record_index; // index is unique to the ServiceDiscoveryRef
74 DNSServiceRef sdr;
75 } _DNSRecordRef_t;
76
77
78 // exported functions
79
80 int DNSServiceRefSockFD(DNSServiceRef sdRef)
81 {
82 if (!sdRef) return -1;
83 return sdRef->sockfd;
84 }
85
86 // handle reply from server, calling application client callback. If there is no reply
87 // from the daemon on the socket contained in sdRef, the call will block.
88 DNSServiceErrorType DNSServiceProcessResult(DNSServiceRef sdRef)
89 {
90 ipc_msg_hdr hdr;
91 char *data;
92
93 if (!sdRef || sdRef->sockfd < 0 || !sdRef->process_reply)
94 return kDNSServiceErr_BadReference;
95
96 if (my_read(sdRef->sockfd, (void *)&hdr, sizeof(hdr)) < 0)
97 return kDNSServiceErr_Unknown;
98 if (hdr.version != VERSION)
99 return kDNSServiceErr_Incompatible;
100 data = malloc(hdr.datalen);
101 if (!data) return kDNSServiceErr_NoMemory;
102 if (my_read(sdRef->sockfd, data, hdr.datalen) < 0)
103 return kDNSServiceErr_Unknown;
104 sdRef->process_reply(sdRef, &hdr, data);
105 return kDNSServiceErr_Unknown;
106 }
107
108
109 void DNSServiceRefDeallocate(DNSServiceRef sdRef)
110 {
111 if (!sdRef) return;
112 if (sdRef->sockfd > 0) close(sdRef->sockfd);
113 free(sdRef);
114 }
115
116
117 DNSServiceErrorType DNSServiceResolve
118 (
119 DNSServiceRef *sdRef,
120 const DNSServiceFlags flags,
121 const uint32_t interfaceIndex,
122 const char *name,
123 const char *regtype,
124 const char *domain,
125 const DNSServiceResolveReply callBack,
126 void *context
127 )
128 {
129 char *msg = NULL, *ptr;
130 int len;
131 ipc_msg_hdr *hdr;
132 DNSServiceRef sdr;
133 DNSServiceErrorType err;
134
135 if (!sdRef) return kDNSServiceErr_BadParam;
136 *sdRef = NULL;
137
138 // calculate total message length
139 len = sizeof(flags);
140 len += sizeof(interfaceIndex);
141 len += strlen(name) + 1;
142 len += strlen(regtype) + 1;
143 len += strlen(domain) + 1;
144
145 hdr = create_hdr(resolve_request, &len, &ptr, 1);
146 if (!hdr) goto error;
147 msg = (void *)hdr;
148
149 put_flags(flags, &ptr);
150 put_long(interfaceIndex, &ptr);
151 put_string(name, &ptr);
152 put_string(regtype, &ptr);
153 put_string(domain, &ptr);
154
155 sdr = connect_to_server();
156 if (!sdr) goto error;
157 err = deliver_request(msg, sdr, 1);
158 if (err)
159 {
160 DNSServiceRefDeallocate(sdr);
161 return err;
162 }
163 sdr->op = resolve_request;
164 sdr->process_reply = handle_resolve_response;
165 sdr->app_callback = callBack;
166 sdr->app_context = context;
167 *sdRef = sdr;
168
169 return err;
170
171 error:
172 if (msg) free(msg);
173 if (*sdRef) { free(*sdRef); *sdRef = NULL; }
174 return kDNSServiceErr_Unknown;
175 }
176
177
178 static void handle_resolve_response(DNSServiceRef sdr, ipc_msg_hdr *hdr, char *data)
179 {
180 DNSServiceFlags flags;
181 char fullname[kDNSServiceMaxDomainName];
182 char target[kDNSServiceMaxDomainName];
183 uint16_t port, txtlen;
184 uint32_t ifi;
185 DNSServiceErrorType err;
186 char *txtrecord;
187
188 (void)hdr; //unused
189
190 flags = get_flags(&data);
191 ifi = get_long(&data);
192 err = get_error_code(&data);
193 get_string(&data, fullname, kDNSServiceMaxDomainName);
194 get_string(&data, target, kDNSServiceMaxDomainName);
195 port = get_short(&data);
196 txtlen = get_short(&data);
197 txtrecord = get_rdata(&data, txtlen);
198
199 ((DNSServiceResolveReply)sdr->app_callback)(sdr, flags, ifi, err, fullname, target, port, txtlen, txtrecord, sdr->app_context);
200 }
201
202
203
204
205 DNSServiceErrorType DNSServiceQueryRecord
206 (
207 DNSServiceRef *sdRef,
208 const DNSServiceFlags flags,
209 const uint32_t interfaceIndex,
210 const char *name,
211 const uint16_t rrtype,
212 const uint16_t rrclass,
213 const DNSServiceQueryRecordReply callBack,
214 void *context
215 )
216 {
217 char *msg = NULL, *ptr;
218 int len;
219 ipc_msg_hdr *hdr;
220 DNSServiceRef sdr;
221 DNSServiceErrorType err;
222
223 if (!sdRef) return kDNSServiceErr_BadParam;
224 *sdRef = NULL;
225
226 if (!name) name = "\0";
227
228 // calculate total message length
229 len = sizeof(flags);
230 len += sizeof(uint32_t); //interfaceIndex
231 len += strlen(name) + 1;
232 len += 2 * sizeof(uint16_t); // rrtype, rrclass
233
234 hdr = create_hdr(query_request, &len, &ptr, 1);
235 if (!hdr) goto error;
236 msg = (void *)hdr;
237
238 put_flags(flags, &ptr);
239 put_long(interfaceIndex, &ptr);
240 put_string(name, &ptr);
241 put_short(rrtype, &ptr);
242 put_short(rrclass, &ptr);
243
244 sdr = connect_to_server();
245 if (!sdr) goto error;
246 err = deliver_request(msg, sdr, 1);
247 if (err)
248 {
249 DNSServiceRefDeallocate(sdr);
250 return err;
251 }
252
253 sdr->op = query_request;
254 sdr->process_reply = handle_query_response;
255 sdr->app_callback = callBack;
256 sdr->app_context = context;
257 *sdRef = sdr;
258 return err;
259
260 error:
261 if (msg) free(msg);
262 if (*sdRef) { free(*sdRef); *sdRef = NULL; }
263 return kDNSServiceErr_Unknown;
264 }
265
266
267 static void handle_query_response(DNSServiceRef sdr, ipc_msg_hdr *hdr, char *data)
268 {
269 DNSServiceFlags flags;
270 uint32_t interfaceIndex, ttl;
271 DNSServiceErrorType errorCode;
272 char name[256];
273 uint16_t rrtype, rrclass, rdlen;
274 char *rdata;
275 (void)hdr;//Unused
276
277 flags = get_flags(&data);
278 interfaceIndex = get_long(&data);
279 errorCode = get_error_code(&data);
280 (get_string(&data, name, 256) < 0);
281 rrtype = get_short(&data);
282 rrclass = get_short(&data);
283 rdlen = get_short(&data);
284 rdata = get_rdata(&data, rdlen);
285 ttl = get_long(&data);
286 if (!rdata) return;
287 ((DNSServiceQueryRecordReply)sdr->app_callback)(sdr, flags, interfaceIndex, errorCode, name, rrtype, rrclass,
288 rdlen, rdata, ttl, sdr->app_context);
289 return;
290 }
291
292 DNSServiceErrorType DNSServiceBrowse
293 (
294 DNSServiceRef *sdRef,
295 const DNSServiceFlags flags,
296 const uint32_t interfaceIndex,
297 const char *regtype,
298 const char *domain,
299 const DNSServiceBrowseReply callBack,
300 void *context
301 )
302 {
303 char *msg = NULL, *ptr;
304 int len;
305 ipc_msg_hdr *hdr;
306 DNSServiceRef sdr;
307 DNSServiceErrorType err;
308
309 if (!sdRef) return kDNSServiceErr_BadParam;
310 *sdRef = NULL;
311
312 if (!domain) domain = "";
313
314 len = sizeof(flags);
315 len += sizeof(interfaceIndex);
316 len += strlen(regtype) + 1;
317 len += strlen(domain) + 1;
318
319 hdr = create_hdr(browse_request, &len, &ptr, 1);
320 if (!hdr) goto error;
321 msg = (char *)hdr;
322 put_flags(flags, &ptr);
323 put_long(interfaceIndex, &ptr);
324 put_string(regtype, &ptr);
325 put_string(domain, &ptr);
326
327 sdr = connect_to_server();
328 if (!sdr) goto error;
329 err = deliver_request(msg, sdr, 1);
330 if (err)
331 {
332 DNSServiceRefDeallocate(sdr);
333 return err;
334 }
335 sdr->op = browse_request;
336 sdr->process_reply = handle_browse_response;
337 sdr->app_callback = callBack;
338 sdr->app_context = context;
339 *sdRef = sdr;
340 return err;
341
342 error:
343 if (msg) free(msg);
344 if (*sdRef) { free(*sdRef); *sdRef = NULL; }
345 return kDNSServiceErr_Unknown;
346 }
347
348
349
350
351 static void handle_browse_response(DNSServiceRef sdr, ipc_msg_hdr *hdr, char *data)
352 {
353 DNSServiceFlags flags;
354 uint32_t interfaceIndex;
355 DNSServiceErrorType errorCode;
356 char replyName[256], replyType[256], replyDomain[256];
357 (void)hdr;//Unused
358
359 flags = get_flags(&data);
360 interfaceIndex = get_long(&data);
361 errorCode = get_error_code(&data);
362 get_string(&data, replyName, 256);
363 get_string(&data, replyType, 256);
364 get_string(&data, replyDomain, 256);
365 ((DNSServiceBrowseReply)sdr->app_callback)(sdr, flags, interfaceIndex, errorCode, replyName, replyType, replyDomain, sdr->app_context);
366 }
367
368
369 DNSServiceErrorType DNSServiceRegister
370 (
371 DNSServiceRef *sdRef,
372 const DNSServiceFlags flags,
373 const uint32_t interfaceIndex,
374 const char *name,
375 const char *regtype,
376 const char *domain,
377 const char *host,
378 const uint16_t port,
379 const uint16_t txtLen,
380 const void *txtRecord,
381 const DNSServiceRegisterReply callBack,
382 void *context
383 )
384 {
385 char *msg = NULL, *ptr;
386 int len;
387 ipc_msg_hdr *hdr;
388 DNSServiceRef sdr;
389 DNSServiceErrorType err;
390
391 if (!sdRef) return kDNSServiceErr_BadParam;
392 *sdRef = NULL;
393
394 if (!name) name = "";
395 if (!regtype) return kDNSServiceErr_BadParam;
396 if (!domain) domain = "";
397 if (!host) host = "";
398 if (!txtRecord) (char *)txtRecord = "";
399
400 // auto-name must also have auto-rename
401 if (!name[0] && (flags & kDNSServiceFlagsNoAutoRename))
402 return kDNSServiceErr_BadParam;
403
404 // no callback must have auto-name
405 if (!callBack && name[0]) return kDNSServiceErr_BadParam;
406
407 len = sizeof(DNSServiceFlags);
408 len += sizeof(uint32_t); // interfaceIndex
409 len += strlen(name) + strlen(regtype) + strlen(domain) + strlen(host) + 4;
410 len += 2 * sizeof(uint16_t); // port, txtLen
411 len += txtLen;
412
413 hdr = create_hdr(reg_service_request, &len, &ptr, 1);
414 if (!hdr) goto error;
415 if (!callBack) hdr->flags |= IPC_FLAGS_NOREPLY;
416 msg = (char *)hdr;
417 put_flags(flags, &ptr);
418 put_long(interfaceIndex, &ptr);
419 put_string(name, &ptr);
420 put_string(regtype, &ptr);
421 put_string(domain, &ptr);
422 put_string(host, &ptr);
423 put_short(port, &ptr);
424 put_short(txtLen, &ptr);
425 put_rdata(txtLen, txtRecord, &ptr);
426
427 sdr = connect_to_server();
428 if (!sdr) goto error;
429 err = deliver_request(msg, sdr, 1);
430 if (err)
431 {
432 DNSServiceRefDeallocate(sdr);
433 return err;
434 }
435
436 sdr->op = reg_service_request;
437 sdr->process_reply = callBack ? handle_regservice_response : NULL;
438 sdr->app_callback = callBack;
439 sdr->app_context = context;
440 *sdRef = sdr;
441
442 return err;
443
444 error:
445 if (msg) free(msg);
446 if (*sdRef) { free(*sdRef); *sdRef = NULL; }
447 return kDNSServiceErr_Unknown;
448 }
449
450
451 static void handle_regservice_response(DNSServiceRef sdr, ipc_msg_hdr *hdr, char *data)
452 {
453 DNSServiceFlags flags;
454 uint32_t interfaceIndex;
455 DNSServiceErrorType errorCode;
456 char name[256], regtype[256], domain[256];
457 (void)hdr;//Unused
458
459 flags = get_flags(&data);
460 interfaceIndex = get_long(&data);
461 errorCode = get_error_code(&data);
462 get_string(&data, name, 256);
463 get_string(&data, regtype, 256);
464 get_string(&data, domain, 256);
465 ((DNSServiceRegisterReply)sdr->app_callback)(sdr, flags, errorCode, name, regtype, domain, sdr->app_context);
466 }
467
468 DNSServiceErrorType DNSServiceEnumerateDomains
469 (
470 DNSServiceRef *sdRef,
471 const DNSServiceFlags flags,
472 const uint32_t interfaceIndex,
473 const DNSServiceDomainEnumReply callBack,
474 void *context
475 )
476 {
477 char *msg = NULL, *ptr;
478 int len;
479 ipc_msg_hdr *hdr;
480 DNSServiceRef sdr;
481 DNSServiceErrorType err;
482
483
484 if (!sdRef) return kDNSServiceErr_BadParam;
485 *sdRef = NULL;
486
487 len = sizeof(DNSServiceFlags);
488 len += sizeof(uint32_t);
489
490 hdr = create_hdr(enumeration_request, &len, &ptr, 1);
491 if (!hdr) goto error;
492 msg = (void *)hdr;
493
494 put_flags(flags, &ptr);
495 put_long(interfaceIndex, &ptr);
496
497 sdr = connect_to_server();
498 if (!sdr) goto error;
499 err = deliver_request(msg, sdr, 1);
500 if (err)
501 {
502 DNSServiceRefDeallocate(sdr);
503 return err;
504 }
505
506 sdr->op = enumeration_request;
507 sdr->process_reply = handle_enumeration_response;
508 sdr->app_callback = callBack;
509 sdr->app_context = context;
510 *sdRef = sdr;
511 return err;
512
513 error:
514 if (msg) free(msg);
515 if (*sdRef) { free(*sdRef); *sdRef = NULL; }
516 return kDNSServiceErr_Unknown;
517 }
518
519
520 static void handle_enumeration_response(DNSServiceRef sdr, ipc_msg_hdr *hdr, char *data)
521 {
522 DNSServiceFlags flags;
523 uint32_t interfaceIndex;
524 DNSServiceErrorType err;
525 char domain[256];
526 (void)hdr;//Unused
527
528 flags = get_flags(&data);
529 interfaceIndex = get_long(&data);
530 err = get_error_code(&data);
531 get_string(&data, domain, 256);
532 ((DNSServiceDomainEnumReply)sdr->app_callback)(sdr, flags, interfaceIndex, err, domain, sdr->app_context);
533 }
534
535
536 DNSServiceErrorType DNSServiceCreateConnection(DNSServiceRef *sdRef)
537 {
538 if (!sdRef) return kDNSServiceErr_BadParam;
539 *sdRef = connect_to_server();
540 if (!*sdRef)
541 return kDNSServiceErr_Unknown;
542 (*sdRef)->op = connection;
543 (*sdRef)->process_reply = handle_regrecord_response;
544 return 0;
545 }
546
547
548
549 static void handle_regrecord_response(DNSServiceRef sdr, ipc_msg_hdr *hdr, char *data)
550 {
551 DNSServiceFlags flags;
552 uint32_t interfaceIndex;
553 DNSServiceErrorType errorCode;
554 DNSRecordRef rref = hdr->client_context.context;
555
556 if (sdr->op != connection)
557 {
558 rref->app_callback(rref->sdr, rref, 0, kDNSServiceErr_Unknown, rref->app_context);
559 return;
560 }
561 flags = get_flags(&data);
562 interfaceIndex = get_long(&data);
563 errorCode = get_error_code(&data);
564
565 rref->app_callback(rref->sdr, rref, flags, errorCode, rref->app_context);
566 }
567
568 DNSServiceErrorType DNSServiceRegisterRecord
569 (
570 const DNSServiceRef sdRef,
571 DNSRecordRef *RecordRef,
572 const DNSServiceFlags flags,
573 const uint32_t interfaceIndex,
574 const char *fullname,
575 const uint16_t rrtype,
576 const uint16_t rrclass,
577 const uint16_t rdlen,
578 const void *rdata,
579 const uint32_t ttl,
580 const DNSServiceRegisterRecordReply callBack,
581 void *context
582 )
583 {
584 char *msg = NULL, *ptr;
585 int len;
586 ipc_msg_hdr *hdr = NULL;
587 DNSServiceRef tmp = NULL;
588 DNSRecordRef rref = NULL;
589
590 if (!sdRef || sdRef->op != connection || sdRef->sockfd < 0)
591 return kDNSServiceErr_BadReference;
592 *RecordRef = NULL;
593
594 len = sizeof(DNSServiceFlags);
595 len += 2 * sizeof(uint32_t); // interfaceIndex, ttl
596 len += 3 * sizeof(uint16_t); // rrtype, rrclass, rdlen
597 len += strlen(fullname) + 1;
598 len += rdlen;
599
600 hdr = create_hdr(reg_record_request, &len, &ptr, 0);
601 if (!hdr) goto error;
602 msg = (char *)hdr;
603 put_flags(flags, &ptr);
604 put_long(interfaceIndex, &ptr);
605 put_string(fullname, &ptr);
606 put_short(rrtype, &ptr);
607 put_short(rrclass, &ptr);
608 put_short(rdlen, &ptr);
609 put_rdata(rdlen, rdata, &ptr);
610 put_long(ttl, &ptr);
611
612 rref = malloc(sizeof(_DNSRecordRef_t));
613 if (!rref) goto error;
614 rref->app_context = context;
615 rref->app_callback = callBack;
616 rref->record_index = sdRef->max_index++;
617 rref->sdr = sdRef;
618 *RecordRef = rref;
619 hdr->client_context.context = rref;
620 hdr->reg_index = rref->record_index;
621
622 return deliver_request(msg, sdRef, 0);
623
624 error:
625 if (rref) free(rref);
626 if (tmp) free(tmp);
627 if (hdr) free(hdr);
628 return kDNSServiceErr_Unknown;
629 }
630
631 //sdRef returned by DNSServiceRegister()
632 DNSServiceErrorType DNSServiceAddRecord
633 (
634 const DNSServiceRef sdRef,
635 DNSRecordRef *RecordRef,
636 const DNSServiceFlags flags,
637 const uint16_t rrtype,
638 const uint16_t rdlen,
639 const void *rdata,
640 const uint32_t ttl
641 )
642 {
643 ipc_msg_hdr *hdr;
644 int len = 0;
645 char *ptr;
646 DNSRecordRef rref;
647
648 if (!sdRef || (sdRef->op != reg_service_request) || !RecordRef)
649 return kDNSServiceErr_BadReference;
650 *RecordRef = NULL;
651
652 len += 2 * sizeof(uint16_t); //rrtype, rdlen
653 len += rdlen;
654 len += sizeof(uint32_t);
655 len += sizeof(DNSServiceFlags);
656
657 hdr = create_hdr(add_record_request, &len, &ptr, 0);
658 if (!hdr) return kDNSServiceErr_Unknown;
659 put_flags(flags, &ptr);
660 put_short(rrtype, &ptr);
661 put_short(rdlen, &ptr);
662 put_rdata(rdlen, rdata, &ptr);
663 put_long(ttl, &ptr);
664
665 rref = malloc(sizeof(_DNSRecordRef_t));
666 if (!rref) goto error;
667 rref->app_context = NULL;
668 rref->app_callback = NULL;
669 rref->record_index = sdRef->max_index++;
670 rref->sdr = sdRef;
671 *RecordRef = rref;
672 hdr->client_context.context = rref;
673 hdr->reg_index = rref->record_index;
674 return deliver_request((char *)hdr, sdRef, 0);
675
676 error:
677 if (hdr) free(hdr);
678 if (rref) free(rref);
679 if (*RecordRef) *RecordRef = NULL;
680 return kDNSServiceErr_Unknown;
681 }
682
683
684 //DNSRecordRef returned by DNSServiceRegisterRecord or DNSServiceAddRecord
685 DNSServiceErrorType DNSServiceUpdateRecord
686 (
687 const DNSServiceRef sdRef,
688 DNSRecordRef RecordRef,
689 const DNSServiceFlags flags,
690 const uint16_t rdlen,
691 const void *rdata,
692 const uint32_t ttl
693 )
694 {
695 ipc_msg_hdr *hdr;
696 int len = 0;
697 char *ptr;
698
699 if (!sdRef || !RecordRef || !sdRef->max_index)
700 return kDNSServiceErr_BadReference;
701
702 len += sizeof(uint16_t);
703 len += rdlen;
704 len += sizeof(uint32_t);
705 len += sizeof(DNSServiceFlags);
706
707 hdr = create_hdr(update_record_request, &len, &ptr, 0);
708 if (!hdr) return kDNSServiceErr_Unknown;
709 hdr->reg_index = RecordRef ? RecordRef->record_index : TXT_RECORD_INDEX;
710 put_flags(flags, &ptr);
711 put_short(rdlen, &ptr);
712 put_rdata(rdlen, rdata, &ptr);
713 put_long(ttl, &ptr);
714 return deliver_request((char *)hdr, sdRef, 0);
715 }
716
717
718
719 DNSServiceErrorType DNSServiceRemoveRecord
720 (
721 const DNSServiceRef sdRef,
722 const DNSRecordRef RecordRef,
723 const DNSServiceFlags flags
724 )
725 {
726 ipc_msg_hdr *hdr;
727 int len = 0;
728 char *ptr;
729 DNSServiceErrorType err;
730
731 if (!sdRef || !RecordRef || !sdRef->max_index)
732 return kDNSServiceErr_BadReference;
733
734 len += sizeof(flags);
735 hdr = create_hdr(remove_record_request, &len, &ptr, 0);
736 if (!hdr) return kDNSServiceErr_Unknown;
737 hdr->reg_index = RecordRef->record_index;
738 put_flags(flags, &ptr);
739 err = deliver_request((char *)hdr, sdRef, 0);
740 if (!err) free(RecordRef);
741 return err;
742 }
743
744
745 void DNSServiceReconfirmRecord
746 (
747 const DNSServiceFlags flags,
748 const uint32_t interfaceIndex,
749 const char *fullname,
750 const uint16_t rrtype,
751 const uint16_t rrclass,
752 const uint16_t rdlen,
753 const void *rdata
754 )
755 {
756 char *ptr;
757 int len;
758 ipc_msg_hdr *hdr;
759 DNSServiceRef tmp;
760
761 len = sizeof(DNSServiceFlags);
762 len += sizeof(uint32_t);
763 len += strlen(fullname) + 1;
764 len += 3 * sizeof(uint16_t);
765 len += rdlen;
766 tmp = connect_to_server();
767 if (!tmp) return;
768 hdr = create_hdr(reconfirm_record_request, &len, &ptr, 1);
769 if (!hdr) return;
770
771 put_flags(flags, &ptr);
772 put_long(interfaceIndex, &ptr);
773 put_string(fullname, &ptr);
774 put_short(rrtype, &ptr);
775 put_short(rrclass, &ptr);
776 put_short(rdlen, &ptr);
777 put_rdata(rdlen, rdata, &ptr);
778 my_write(tmp->sockfd, (char *)hdr, len);
779 DNSServiceRefDeallocate(tmp);
780 }
781
782
783 int DNSServiceConstructFullName
784 (
785 char *fullName,
786 const char *service, /* may be NULL */
787 const char *regtype,
788 const char *domain
789 )
790 {
791 int len;
792 u_char c;
793 char *fn = fullName;
794 const char *s = service;
795 const char *r = regtype;
796 const char *d = domain;
797
798 if (service)
799 {
800 while(*s)
801 {
802 c = *s++;
803 if (c == '.' || (c == '\\')) *fn++ = '\\'; // escape dot and backslash literals
804 else if (c <= ' ') // escape non-printable characters
805 {
806 *fn++ = '\\';
807 *fn++ = (char) ('0' + (c / 100));
808 *fn++ = (char) ('0' + (c / 10) % 10);
809 c = (u_char)('0' + (c % 10));
810 }
811 *fn++ = c;
812 }
813 *fn++ = '.';
814 }
815
816 if (!regtype) return -1;
817 len = strlen(regtype);
818 if (domain_ends_in_dot(regtype)) len--;
819 if (len < 4) return -1; // regtype must end in _udp or _tcp
820 if (strncmp((regtype + len - 4), "_tcp", 4) && strncmp((regtype + len - 4), "_udp", 4)) return -1;
821 while(*r)
822 *fn++ = *r++;
823 if (!domain_ends_in_dot(regtype)) *fn++ = '.';
824
825 if (!domain) return -1;
826 len = strlen(domain);
827 if (!len) return -1;
828 while(*d)
829 *fn++ = *d++;
830 if (!domain_ends_in_dot(domain)) *fn++ = '.';
831 *fn = '\0';
832 return 0;
833 }
834
835 static int domain_ends_in_dot(const char *dom)
836 {
837 while(*dom && *(dom + 1))
838 {
839 if (*dom == '\\') // advance past escaped byte sequence
840 {
841 if (*(dom + 1) >= '0' && *(dom + 1) <= '9') dom += 4;
842 else dom += 2;
843 }
844 else dom++; // else read one character
845 }
846 return (*dom == '.');
847 }
848
849
850
851 // return a connected service ref (deallocate with DNSServiceRefDeallocate)
852 static DNSServiceRef connect_to_server(void)
853 {
854 struct sockaddr_un saddr;
855 DNSServiceRef sdr;
856
857 sdr = malloc(sizeof(_DNSServiceRef_t));
858 if (!sdr) return NULL;
859
860 if ((sdr->sockfd = socket(AF_LOCAL, SOCK_STREAM, 0)) < 0)
861 {
862 free(sdr);
863 return NULL;
864 }
865
866 saddr.sun_family = AF_LOCAL;
867 strcpy(saddr.sun_path, MDNS_UDS_SERVERPATH);
868 if (connect(sdr->sockfd, (struct sockaddr *)&saddr, sizeof(saddr)) < 0)
869 {
870 free(sdr);
871 return NULL;
872 }
873 return sdr;
874 }
875
876
877
878
879 int my_write(int sd, char *buf, int len)
880 {
881 if (send(sd, buf, len, MSG_WAITALL) != len) return -1;
882 return 0;
883 }
884
885
886 // read len bytes. return 0 on success, -1 on error
887 int my_read(int sd, char *buf, int len)
888 {
889 if (recv(sd, buf, len, MSG_WAITALL) != len) return -1;
890 return 0;
891 }
892
893
894 DNSServiceErrorType deliver_request(void *msg, DNSServiceRef sdr, int reuse_sd)
895 {
896 ipc_msg_hdr *hdr = msg;
897 mode_t mask;
898 struct sockaddr_un caddr, daddr; // (client and daemon address structs)
899 char *path = NULL;
900 int listenfd = -1, errsd = -1, len;
901 DNSServiceErrorType err = kDNSServiceErr_Unknown;
902
903 if (!hdr || sdr->sockfd < 0) return kDNSServiceErr_Unknown;
904
905 if (!reuse_sd)
906 {
907 // setup temporary error socket
908 if ((listenfd = socket(AF_LOCAL, SOCK_STREAM, 0)) < 0)
909 goto cleanup;
910
911 bzero(&caddr, sizeof(caddr));
912 caddr.sun_family = AF_LOCAL;
913 caddr.sun_len = sizeof(struct sockaddr_un);
914 path = (char *)msg + sizeof(ipc_msg_hdr);
915 strcpy(caddr.sun_path, path);
916 mask = umask(0);
917 if (bind(listenfd, (struct sockaddr *)&caddr, sizeof(caddr)) < 0)
918 {
919 umask(mask);
920 goto cleanup;
921 }
922 umask(mask);
923 listen(listenfd, 1);
924 }
925
926 if (my_write(sdr->sockfd, msg, hdr->datalen + sizeof(ipc_msg_hdr)) < 0)
927 goto cleanup;
928 free(msg);
929 msg = NULL;
930
931 if (reuse_sd) errsd = sdr->sockfd;
932 else
933 {
934 len = sizeof(daddr);
935 errsd = accept(listenfd, (struct sockaddr *)&daddr, &len);
936 if (errsd < 0) goto cleanup;
937 }
938
939 len = recv(errsd, &err, sizeof(err), MSG_WAITALL);
940 if (len != sizeof(err))
941 {
942 err = kDNSServiceErr_Unknown;
943 }
944 cleanup:
945 if (!reuse_sd && listenfd > 0) close(listenfd);
946 if (!reuse_sd && errsd > 0) close(errsd);
947 if (!reuse_sd && path) unlink(path);
948 if (msg) free(msg);
949 return err;
950 }
951
952
953
954 /* create_hdr
955 *
956 * allocate and initialize an ipc message header. value of len should initially be the
957 * length of the data, and is set to the value of the data plus the header. data_start
958 * is set to point to the beginning of the data section. reuse_socket should be non-zero
959 * for calls that can receive an immediate error return value on their primary socket.
960 * if zero, the path to a control socket is appended at the beginning of the message buffer.
961 * data_start is set past this string.
962 */
963
964 static ipc_msg_hdr *create_hdr(int op, int *len, char **data_start, int reuse_socket)
965 {
966 char *msg = NULL;
967 ipc_msg_hdr *hdr;
968 int datalen;
969 char ctrl_path[256];
970 struct timeval time;
971
972 if (!reuse_socket)
973 {
974 if (gettimeofday(&time, NULL) < 0) return NULL;
975 sprintf(ctrl_path, "%s%d-%.3x-%.6u", CTL_PATH_PREFIX, (int)getpid(),
976 time.tv_sec & 0xFFF, time.tv_usec);
977
978 *len += strlen(ctrl_path) + 1;
979 }
980
981
982 datalen = *len;
983 *len += sizeof(ipc_msg_hdr);
984
985 // write message to buffer
986 msg = malloc(*len);
987 if (!msg) return NULL;
988
989 bzero(msg, *len);
990 hdr = (void *)msg;
991 hdr->datalen = datalen;
992 hdr->version = VERSION;
993 hdr->op.request_op = op;
994 if (reuse_socket) hdr->flags |= IPC_FLAGS_REUSE_SOCKET;
995 *data_start = msg + sizeof(ipc_msg_hdr);
996 if (!reuse_socket) put_string(ctrl_path, data_start);
997 return hdr;
998 }