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