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