]>
Commit | Line | Data |
---|---|---|
c29f2fcc | 1 | /* -*- Mode: C; tab-width: 4 -*- |
ccd4a120 | 2 | * |
c29f2fcc | 3 | * Copyright (c) 2003-2004, Apple Computer, Inc. All rights reserved. |
ad21edcc | 4 | * |
c29f2fcc A |
5 | * Redistribution and use in source and binary forms, with or without |
6 | * modification, are permitted provided that the following conditions are met: | |
ad21edcc | 7 | * |
c29f2fcc A |
8 | * 1. Redistributions of source code must retain the above copyright notice, |
9 | * this list of conditions and the following disclaimer. | |
10 | * 2. Redistributions in binary form must reproduce the above copyright notice, | |
11 | * this list of conditions and the following disclaimer in the documentation | |
12 | * and/or other materials provided with the distribution. | |
13 | * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of its | |
14 | * contributors may be used to endorse or promote products derived from this | |
15 | * software without specific prior written permission. | |
ad21edcc | 16 | * |
c29f2fcc A |
17 | * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY |
18 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | |
19 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | |
20 | * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY | |
21 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | |
22 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | |
23 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | |
24 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
25 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | |
26 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
27 | ||
28 | Change History (most recent first): | |
29 | ||
30 | $Log: dnssd_clientstub.c,v $ | |
31 | Revision 1.20 2005/02/03 00:39:05 majka | |
32 | Integrated 3942900 | |
33 | ||
34 | Revision 1.19.4.1 2005/02/02 00:47:40 ksekar | |
35 | <rdar://problem/3942900> dnd-sd shows the wrong port numbers | |
36 | ||
37 | Revision 1.19 2004/12/23 23:10:59 majka | |
38 | *** empty log message *** | |
39 | ||
40 | Revision 1.18.8.1 2004/12/23 17:32:56 ksekar | |
41 | <rdar://problem/3931319> Rendevzous calls leak sockets if mDNSResponder is not running | |
42 | ||
43 | Revision 1.18 2004/12/14 18:02:00 majka | |
44 | *** empty log message *** | |
45 | ||
46 | Revision 1.17.36.1 2004/12/13 17:22:39 ksekar | |
47 | <rdar://problem/3656389> Deprecate the DNSServiceDiscovery.h API in Tiger | |
48 | <rdar://problem/3873869> Add kDNSServiceInterfaceForceMulticast to header | |
49 | <rdar://problem/3526342> Remove overly-restrictive flag checks | |
50 | ||
51 | Revision 1.17 2004/09/22 20:05:38 majka | |
52 | Integrated | |
53 | 3725573 - Need Error Codes for handling Lighthouse setup failure on NAT | |
54 | 3805822 - Socket-based APIs aren't endian-safe | |
55 | 3806739 - DNSServiceSetDefaultDomainForUser header comments incorrect | |
56 | ||
57 | Revision 1.16.2.1 2004/09/20 21:54:33 ksekar | |
58 | <rdar://problem/3805822> Socket-based APIs aren't endian-safe | |
59 | ||
60 | Revision 1.16 2004/09/17 20:19:00 majka | |
61 | Integrated 3804522 | |
62 | ||
63 | Revision 1.15.2.1 2004/09/17 20:15:30 ksekar | |
64 | *** empty log message *** | |
65 | ||
66 | Revision 1.15 2004/09/16 23:45:24 majka | |
67 | Integrated 3775315 and 3765280. | |
68 | ||
69 | Revision 1.14.4.1 2004/09/02 19:43:41 ksekar | |
70 | <rdar://problem/3775315>: Sync dns-sd client files between Libinfo and | |
71 | mDNSResponder projects | |
72 | ||
73 | Revision 1.28 2004/08/11 17:10:04 cheshire | |
74 | Fix signed/unsigned warnings | |
75 | ||
76 | Revision 1.27 2004/08/11 00:54:16 cheshire | |
77 | Change "hdr->op.request_op" to just "hdr->op" | |
78 | ||
79 | Revision 1.26 2004/07/26 06:07:27 shersche | |
80 | fix bugs when using an error socket to communicate with the daemon | |
81 | ||
82 | Revision 1.25 2004/07/26 05:54:02 shersche | |
83 | DNSServiceProcessResult() returns NoError if socket read returns EWOULDBLOCK | |
84 | ||
85 | Revision 1.24 2004/07/20 06:46:21 shersche | |
86 | <rdar://problem/3730123> fix endless loop in my_read() if recv returns 0 | |
87 | Bug #: 3730123 | |
88 | ||
89 | Revision 1.23 2004/06/29 00:48:38 cheshire | |
90 | Don't use "MSG_WAITALL"; it returns "Invalid argument" on some Linux versions; | |
91 | use an explicit while() loop instead. | |
92 | ||
93 | Revision 1.22 2004/06/26 03:16:34 shersche | |
94 | clean up warning messages on Win32 platform | |
95 | ||
96 | Submitted by: herscher | |
97 | ||
98 | Revision 1.21 2004/06/18 04:53:56 rpantos | |
99 | Use platform layer for socket types. Introduce USE_TCP_LOOPBACK. Remove dependency on mDNSClientAPI.h. | |
100 | ||
101 | Revision 1.20 2004/06/12 00:50:22 cheshire | |
102 | Changes for Windows compatibility | |
103 | ||
104 | Revision 1.19 2004/05/25 18:29:33 cheshire | |
105 | Move DNSServiceConstructFullName() from dnssd_clientstub.c to dnssd_clientlib.c, | |
106 | so that it's also accessible to dnssd_clientshim.c (single address space) clients. | |
107 | ||
108 | Revision 1.18 2004/05/18 23:51:27 cheshire | |
109 | Tidy up all checkin comments to use consistent "<rdar://problem/xxxxxxx>" format for bug numbers | |
110 | ||
111 | Revision 1.17 2004/05/06 18:42:58 ksekar | |
112 | General dns_sd.h API cleanup, including the following radars: | |
113 | <rdar://problem/3592068>: Remove flags with zero value | |
114 | <rdar://problem/3479569>: Passing in NULL causes a crash. | |
115 | ||
116 | Revision 1.16 2004/03/12 22:00:37 cheshire | |
117 | Added: #include <sys/socket.h> | |
118 | ||
119 | Revision 1.15 2004/01/20 18:36:29 ksekar | |
120 | Propagated Libinfo fix for <rdar://problem/3483971>: SU: | |
121 | DNSServiceUpdateRecord() doesn't allow you to update the TXT record | |
122 | into TOT mDNSResponder. | |
123 | ||
124 | Revision 1.14 2004/01/19 22:39:17 cheshire | |
125 | Don't use "MSG_WAITALL"; it makes send() return "Invalid argument" on Linux; | |
126 | use an explicit while() loop instead. (In any case, this should only make a difference | |
127 | with non-blocking sockets, which we don't use on the client side right now.) | |
128 | ||
129 | Revision 1.13 2004/01/19 21:46:52 cheshire | |
130 | Fix compiler warning | |
131 | ||
132 | Revision 1.12 2003/12/23 20:46:47 ksekar | |
133 | <rdar://problem/3497428>: sync dnssd files between libinfo & mDNSResponder | |
134 | ||
135 | Revision 1.11 2003/12/08 21:11:42 rpantos | |
136 | Changes necessary to support mDNSResponder on Linux. | |
137 | ||
138 | Revision 1.10 2003/10/13 23:50:53 ksekar | |
139 | Updated dns_sd clientstub files to bring copies in synch with | |
140 | top-of-tree Libinfo: A memory leak in dnssd_clientstub.c is fixed, | |
141 | and comments in dns_sd.h are improved. | |
142 | ||
143 | Revision 1.9 2003/08/15 21:30:39 cheshire | |
144 | Bring up to date with LibInfo version | |
145 | ||
146 | Revision 1.8 2003/08/13 23:54:52 ksekar | |
147 | Bringing dnssd_clientstub.c up to date with Libinfo, per radar 3376640 | |
148 | ||
149 | Revision 1.7 2003/08/12 19:56:25 cheshire | |
150 | Update to APSL 2.0 | |
151 | ||
ccd4a120 A |
152 | */ |
153 | ||
ccd4a120 | 154 | #include <errno.h> |
c29f2fcc A |
155 | #include <stdlib.h> |
156 | #if defined(_WIN32) | |
157 | #include <winsock2.h> | |
158 | #include <windows.h> | |
159 | #define sockaddr_mdns sockaddr_in | |
160 | #define AF_MDNS AF_INET | |
161 | #else | |
ccd4a120 | 162 | #include <sys/time.h> |
c29f2fcc A |
163 | #include <sys/socket.h> |
164 | #define sockaddr_mdns sockaddr_un | |
165 | #define AF_MDNS AF_LOCAL | |
166 | #endif | |
167 | ||
168 | #include "dnssd_ipc.h" | |
169 | ||
170 | #if defined(_WIN32) | |
171 | // disable warning: "'type cast' : from data pointer 'void *' to | |
172 | // function pointer" | |
173 | #pragma warning(disable:4055) | |
174 | ||
175 | // disable warning: "nonstandard extension, function/data pointer | |
176 | // conversion in expression" | |
177 | #pragma warning(disable:4152) | |
ccd4a120 | 178 | |
c29f2fcc A |
179 | #define sleep(X) Sleep((X) * 1000) |
180 | ||
181 | static int g_initWinsock = 0; | |
182 | #endif | |
ccd4a120 A |
183 | |
184 | ||
185 | #define CTL_PATH_PREFIX "/tmp/dnssd_clippath." | |
186 | // error socket (if needed) is named "dnssd_clipath.[pid].xxx:n" where xxx are the | |
187 | // last 3 digits of the time (in seconds) and n is the 6-digit microsecond time | |
188 | ||
189 | // general utility functions | |
ccd4a120 A |
190 | typedef struct _DNSServiceRef_t |
191 | { | |
c29f2fcc A |
192 | dnssd_sock_t sockfd; // connected socket between client and daemon |
193 | uint32_t op; // request_op_t or reply_op_t | |
ccd4a120 A |
194 | process_reply_callback process_reply; |
195 | void *app_callback; | |
196 | void *app_context; | |
197 | uint32_t max_index; //largest assigned record index - 0 if no additl. recs registered | |
c29f2fcc | 198 | } _DNSServiceRef_t; |
ccd4a120 A |
199 | |
200 | typedef struct _DNSRecordRef_t | |
201 | { | |
202 | void *app_context; | |
203 | DNSServiceRegisterRecordReply app_callback; | |
204 | DNSRecordRef recref; | |
c29f2fcc | 205 | uint32_t record_index; // index is unique to the ServiceDiscoveryRef |
ccd4a120 A |
206 | DNSServiceRef sdr; |
207 | } _DNSRecordRef_t; | |
208 | ||
ccd4a120 A |
209 | // exported functions |
210 | ||
c29f2fcc A |
211 | // write len bytes. return 0 on success, -1 on error |
212 | static int my_write(dnssd_sock_t sd, char *buf, int len) | |
213 | { | |
214 | // Don't use "MSG_WAITALL"; it returns "Invalid argument" on some Linux versions; use an explicit while() loop instead. | |
215 | //if (send(sd, buf, len, MSG_WAITALL) != len) return -1; | |
216 | while (len) | |
217 | { | |
218 | ssize_t num_written = send(sd, buf, len, 0); | |
219 | if (num_written < 0 || num_written > len) return -1; | |
220 | buf += num_written; | |
221 | len -= num_written; | |
222 | } | |
223 | return 0; | |
224 | } | |
225 | ||
226 | // read len bytes. return 0 on success, -1 on error | |
227 | static int my_read(dnssd_sock_t sd, char *buf, int len) | |
228 | { | |
229 | // Don't use "MSG_WAITALL"; it returns "Invalid argument" on some Linux versions; use an explicit while() loop instead. | |
230 | //if (recv(sd, buf, len, MSG_WAITALL) != len) return -1; | |
231 | while (len) | |
232 | { | |
233 | ssize_t num_read = recv(sd, buf, len, 0); | |
234 | if ((num_read == 0) || (num_read < 0) || (num_read > len)) return -1; | |
235 | buf += num_read; | |
236 | len -= num_read; | |
237 | } | |
238 | return 0; | |
239 | } | |
240 | ||
241 | /* create_hdr | |
242 | * | |
243 | * allocate and initialize an ipc message header. value of len should initially be the | |
244 | * length of the data, and is set to the value of the data plus the header. data_start | |
245 | * is set to point to the beginning of the data section. reuse_socket should be non-zero | |
246 | * for calls that can receive an immediate error return value on their primary socket. | |
247 | * if zero, the path to a control socket is appended at the beginning of the message buffer. | |
248 | * data_start is set past this string. | |
249 | */ | |
250 | ||
251 | static ipc_msg_hdr *create_hdr(uint32_t op, size_t *len, char **data_start, int reuse_socket) | |
252 | { | |
253 | char *msg = NULL; | |
254 | ipc_msg_hdr *hdr; | |
255 | int datalen; | |
256 | char ctrl_path[256]; | |
257 | ||
258 | if (!reuse_socket) | |
259 | { | |
260 | #if defined(USE_TCP_LOOPBACK) | |
261 | *len += 2; // Allocate space for two-byte port number | |
262 | #else | |
263 | struct timeval time; | |
264 | if (gettimeofday(&time, NULL) < 0) return NULL; | |
265 | sprintf(ctrl_path, "%s%d-%.3lx-%.6lu", CTL_PATH_PREFIX, (int)getpid(), | |
266 | (unsigned long)(time.tv_sec & 0xFFF), (unsigned long)(time.tv_usec)); | |
267 | *len += strlen(ctrl_path) + 1; | |
268 | #endif | |
269 | } | |
270 | ||
271 | datalen = (int) *len; | |
272 | *len += sizeof(ipc_msg_hdr); | |
273 | ||
274 | // write message to buffer | |
275 | msg = malloc(*len); | |
276 | if (!msg) return NULL; | |
277 | ||
278 | bzero(msg, *len); | |
279 | hdr = (void *)msg; | |
280 | hdr->datalen = datalen; | |
281 | hdr->version = VERSION; | |
282 | hdr->op = op; | |
283 | if (reuse_socket) hdr->flags |= IPC_FLAGS_REUSE_SOCKET; | |
284 | *data_start = msg + sizeof(ipc_msg_hdr); | |
285 | #if defined(USE_TCP_LOOPBACK) | |
286 | // Put dummy data in for the port, since we don't know what | |
287 | // it is yet. The data will get filled in before we | |
288 | // send the message. This happens in deliver_request(). | |
289 | if (!reuse_socket) put_short(0, data_start); | |
290 | #else | |
291 | if (!reuse_socket) put_string(ctrl_path, data_start); | |
292 | #endif | |
293 | return hdr; | |
294 | } | |
295 | ||
296 | // return a connected service ref (deallocate with DNSServiceRefDeallocate) | |
297 | static DNSServiceRef connect_to_server(void) | |
298 | { | |
299 | dnssd_sockaddr_t saddr; | |
300 | DNSServiceRef sdr; | |
301 | int NumTries = 0; | |
302 | ||
303 | #if defined(_WIN32) | |
304 | if (!g_initWinsock) | |
305 | { | |
306 | WSADATA wsaData; | |
307 | DNSServiceErrorType err; | |
308 | ||
309 | g_initWinsock = 1; | |
310 | ||
311 | err = WSAStartup( MAKEWORD( 2, 2 ), &wsaData ); | |
312 | ||
313 | if (err != 0) return NULL; | |
314 | } | |
315 | #endif | |
316 | ||
317 | sdr = malloc(sizeof(_DNSServiceRef_t)); | |
318 | if (!sdr) return(NULL); | |
319 | sdr->sockfd = socket(AF_DNSSD, SOCK_STREAM, 0); | |
320 | if (sdr->sockfd == dnssd_InvalidSocket) { free(sdr); return NULL; } | |
321 | #if defined(USE_TCP_LOOPBACK) | |
322 | saddr.sin_family = AF_INET; | |
323 | saddr.sin_addr.s_addr = inet_addr(MDNS_TCP_SERVERADDR); | |
324 | saddr.sin_port = htons(MDNS_TCP_SERVERPORT); | |
325 | #else | |
326 | saddr.sun_family = AF_LOCAL; | |
327 | strcpy(saddr.sun_path, MDNS_UDS_SERVERPATH); | |
328 | #endif | |
329 | while (1) | |
330 | { | |
331 | int err = connect(sdr->sockfd, (struct sockaddr *) &saddr, sizeof(saddr)); | |
332 | if (!err) break; // If we succeeded, return sdr | |
333 | // If we failed, then it may be because the daemon is still launching. | |
334 | // This can happen for processes that launch early in the boot process, while the | |
335 | // daemon is still coming up. Rather than fail here, we'll wait a bit and try again. | |
336 | // If, after ten seconds, we still can't connect to the daemon, | |
337 | // then we give up and return a failure code. | |
338 | if (++NumTries < 10) | |
339 | sleep(1); // Sleep a bit, then try again | |
340 | else | |
341 | { | |
342 | dnssd_close(sdr->sockfd); | |
343 | sdr->sockfd = dnssd_InvalidSocket; | |
344 | free(sdr); | |
345 | return NULL; | |
346 | } | |
347 | } | |
348 | return sdr; | |
349 | } | |
350 | ||
351 | static DNSServiceErrorType deliver_request(void *msg, DNSServiceRef sdr, int reuse_sd) | |
352 | { | |
353 | ipc_msg_hdr *hdr = msg; | |
354 | uint32_t datalen = hdr->datalen; | |
355 | dnssd_sockaddr_t caddr, daddr; // (client and daemon address structs) | |
356 | char *data = (char *)msg + sizeof(ipc_msg_hdr); | |
357 | dnssd_sock_t listenfd = dnssd_InvalidSocket, errsd = dnssd_InvalidSocket; | |
358 | int ret; | |
359 | unsigned int len = sizeof(caddr); | |
360 | DNSServiceErrorType err = kDNSServiceErr_Unknown; | |
361 | ||
362 | if (!hdr || sdr->sockfd < 0) return kDNSServiceErr_Unknown; | |
363 | ||
364 | if (!reuse_sd) | |
365 | { | |
366 | // setup temporary error socket | |
367 | if ((listenfd = socket(AF_DNSSD, SOCK_STREAM, 0)) < 0) | |
368 | goto cleanup; | |
369 | bzero(&caddr, sizeof(caddr)); | |
370 | ||
371 | #if defined(USE_TCP_LOOPBACK) | |
372 | { | |
373 | union { uint16_t s; u_char b[2]; } port; | |
374 | caddr.sin_family = AF_INET; | |
375 | caddr.sin_port = 0; | |
376 | caddr.sin_addr.s_addr = inet_addr(MDNS_TCP_SERVERADDR); | |
377 | ret = bind(listenfd, (struct sockaddr*) &caddr, sizeof(caddr)); | |
378 | if (ret < 0) goto cleanup; | |
379 | if (getsockname(listenfd, (struct sockaddr*) &caddr, &len) < 0) goto cleanup; | |
380 | listen(listenfd, 1); | |
381 | port.s = caddr.sin_port; | |
382 | data[0] = port.b[0]; // don't switch the byte order, as the | |
383 | data[1] = port.b[1]; // daemon expects it in network byte order | |
384 | } | |
385 | #else | |
386 | { | |
387 | mode_t mask = umask(0); | |
388 | caddr.sun_family = AF_LOCAL; | |
389 | #ifndef NOT_HAVE_SA_LEN // According to Stevens (section 3.2), there is no portable way to | |
390 | // determine whether sa_len is defined on a particular platform. | |
391 | caddr.sun_len = sizeof(struct sockaddr_un); | |
392 | #endif | |
393 | strcpy(caddr.sun_path, data); | |
394 | ret = bind(listenfd, (struct sockaddr *)&caddr, sizeof(caddr)); | |
395 | umask(mask); | |
396 | if (ret < 0) goto cleanup; | |
397 | listen(listenfd, 1); | |
398 | } | |
399 | #endif | |
400 | } | |
401 | ||
402 | ConvertHeaderBytes(hdr); | |
403 | if (my_write(sdr->sockfd, msg, datalen + sizeof(ipc_msg_hdr)) < 0) | |
404 | goto cleanup; | |
405 | free(msg); | |
406 | msg = NULL; | |
407 | ||
408 | if (reuse_sd) errsd = sdr->sockfd; | |
409 | else | |
410 | { | |
411 | len = sizeof(daddr); | |
412 | errsd = accept(listenfd, (struct sockaddr *)&daddr, &len); | |
413 | if (errsd < 0) goto cleanup; | |
414 | } | |
415 | ||
416 | if (my_read(errsd, (char*)&err, (int)sizeof(err)) < 0) | |
417 | err = kDNSServiceErr_Unknown; | |
418 | else | |
419 | err = ntohl(err); | |
420 | ||
421 | cleanup: | |
422 | if (!reuse_sd && listenfd > 0) dnssd_close(listenfd); | |
423 | if (!reuse_sd && errsd > 0) dnssd_close(errsd); | |
424 | #if !defined(USE_TCP_LOOPBACK) | |
425 | if (!reuse_sd && data) unlink(data); | |
426 | #endif | |
427 | if (msg) free(msg); | |
428 | return err; | |
429 | } | |
430 | ||
431 | int DNSSD_API DNSServiceRefSockFD(DNSServiceRef sdRef) | |
ccd4a120 A |
432 | { |
433 | if (!sdRef) return -1; | |
c29f2fcc | 434 | return (int) sdRef->sockfd; |
ccd4a120 A |
435 | } |
436 | ||
437 | // handle reply from server, calling application client callback. If there is no reply | |
438 | // from the daemon on the socket contained in sdRef, the call will block. | |
c29f2fcc | 439 | DNSServiceErrorType DNSSD_API DNSServiceProcessResult(DNSServiceRef sdRef) |
ccd4a120 A |
440 | { |
441 | ipc_msg_hdr hdr; | |
442 | char *data; | |
443 | ||
c29f2fcc | 444 | if (!sdRef || sdRef->sockfd < 0 || !sdRef->process_reply) |
ccd4a120 A |
445 | return kDNSServiceErr_BadReference; |
446 | ||
c29f2fcc A |
447 | if (my_read(sdRef->sockfd, (void *)&hdr, sizeof(hdr)) < 0) |
448 | // return NoError on EWOULDBLOCK. This will handle the case | |
449 | // where a non-blocking socket is told there is data, but | |
450 | // it was a false positive. | |
451 | return (dnssd_errno() == dnssd_EWOULDBLOCK) ? kDNSServiceErr_NoError : kDNSServiceErr_Unknown; | |
452 | ConvertHeaderBytes(&hdr); | |
ccd4a120 A |
453 | if (hdr.version != VERSION) |
454 | return kDNSServiceErr_Incompatible; | |
455 | data = malloc(hdr.datalen); | |
456 | if (!data) return kDNSServiceErr_NoMemory; | |
c29f2fcc | 457 | if (my_read(sdRef->sockfd, data, hdr.datalen) < 0) |
ccd4a120 A |
458 | return kDNSServiceErr_Unknown; |
459 | sdRef->process_reply(sdRef, &hdr, data); | |
460 | free(data); | |
461 | return kDNSServiceErr_NoError; | |
462 | } | |
463 | ||
c29f2fcc | 464 | void DNSSD_API DNSServiceRefDeallocate(DNSServiceRef sdRef) |
ccd4a120 A |
465 | { |
466 | if (!sdRef) return; | |
c29f2fcc | 467 | if (sdRef->sockfd > 0) dnssd_close(sdRef->sockfd); |
ccd4a120 A |
468 | free(sdRef); |
469 | } | |
470 | ||
c29f2fcc A |
471 | static void handle_resolve_response(DNSServiceRef sdr, ipc_msg_hdr *hdr, char *data) |
472 | { | |
473 | DNSServiceFlags flags; | |
474 | char fullname[kDNSServiceMaxDomainName]; | |
475 | char target[kDNSServiceMaxDomainName]; | |
476 | uint16_t txtlen; | |
477 | union { uint16_t s; u_char b[2]; } port; | |
478 | uint32_t ifi; | |
479 | DNSServiceErrorType err; | |
480 | char *txtrecord; | |
481 | int str_error = 0; | |
482 | (void)hdr; //unused | |
483 | ||
484 | flags = get_flags(&data); | |
485 | ifi = get_long(&data); | |
486 | err = get_error_code(&data); | |
487 | if (get_string(&data, fullname, kDNSServiceMaxDomainName) < 0) str_error = 1; | |
488 | if (get_string(&data, target, kDNSServiceMaxDomainName) < 0) str_error = 1; | |
489 | port.b[0] = *data++; | |
490 | port.b[1] = *data++; | |
491 | txtlen = get_short(&data); | |
492 | txtrecord = get_rdata(&data, txtlen); | |
493 | ||
494 | if (!err && str_error) err = kDNSServiceErr_Unknown; | |
495 | ((DNSServiceResolveReply)sdr->app_callback)(sdr, flags, ifi, err, fullname, target, port.s, txtlen, txtrecord, sdr->app_context); | |
496 | } | |
ccd4a120 | 497 | |
c29f2fcc | 498 | DNSServiceErrorType DNSSD_API DNSServiceResolve |
ccd4a120 A |
499 | ( |
500 | DNSServiceRef *sdRef, | |
c29f2fcc A |
501 | DNSServiceFlags flags, |
502 | uint32_t interfaceIndex, | |
ccd4a120 A |
503 | const char *name, |
504 | const char *regtype, | |
505 | const char *domain, | |
c29f2fcc | 506 | DNSServiceResolveReply callBack, |
ccd4a120 A |
507 | void *context |
508 | ) | |
509 | { | |
510 | char *msg = NULL, *ptr; | |
c29f2fcc | 511 | size_t len; |
ccd4a120 A |
512 | ipc_msg_hdr *hdr; |
513 | DNSServiceRef sdr; | |
514 | DNSServiceErrorType err; | |
c29f2fcc | 515 | |
ccd4a120 A |
516 | if (!sdRef) return kDNSServiceErr_BadParam; |
517 | *sdRef = NULL; | |
c29f2fcc A |
518 | |
519 | if (!name || !regtype || !domain || !callBack) return kDNSServiceErr_BadParam; | |
520 | ||
ccd4a120 A |
521 | // calculate total message length |
522 | len = sizeof(flags); | |
523 | len += sizeof(interfaceIndex); | |
524 | len += strlen(name) + 1; | |
525 | len += strlen(regtype) + 1; | |
526 | len += strlen(domain) + 1; | |
527 | ||
528 | hdr = create_hdr(resolve_request, &len, &ptr, 1); | |
529 | if (!hdr) goto error; | |
530 | msg = (void *)hdr; | |
531 | ||
532 | put_flags(flags, &ptr); | |
533 | put_long(interfaceIndex, &ptr); | |
534 | put_string(name, &ptr); | |
535 | put_string(regtype, &ptr); | |
536 | put_string(domain, &ptr); | |
c29f2fcc | 537 | |
ccd4a120 A |
538 | sdr = connect_to_server(); |
539 | if (!sdr) goto error; | |
540 | err = deliver_request(msg, sdr, 1); | |
541 | if (err) | |
542 | { | |
543 | DNSServiceRefDeallocate(sdr); | |
544 | return err; | |
545 | } | |
546 | sdr->op = resolve_request; | |
547 | sdr->process_reply = handle_resolve_response; | |
548 | sdr->app_callback = callBack; | |
549 | sdr->app_context = context; | |
550 | *sdRef = sdr; | |
c29f2fcc | 551 | |
ccd4a120 A |
552 | return err; |
553 | ||
554 | error: | |
555 | if (msg) free(msg); | |
556 | if (*sdRef) { free(*sdRef); *sdRef = NULL; } | |
557 | return kDNSServiceErr_Unknown; | |
558 | } | |
c29f2fcc A |
559 | |
560 | static void handle_query_response(DNSServiceRef sdr, ipc_msg_hdr *hdr, char *data) | |
ccd4a120 A |
561 | { |
562 | DNSServiceFlags flags; | |
c29f2fcc A |
563 | uint32_t interfaceIndex, ttl; |
564 | DNSServiceErrorType errorCode; | |
565 | char name[kDNSServiceMaxDomainName]; | |
566 | uint16_t rrtype, rrclass, rdlen; | |
567 | char *rdata; | |
568 | int str_error = 0; | |
569 | (void)hdr;//Unused | |
570 | ||
ccd4a120 | 571 | flags = get_flags(&data); |
c29f2fcc A |
572 | interfaceIndex = get_long(&data); |
573 | errorCode = get_error_code(&data); | |
574 | if (get_string(&data, name, kDNSServiceMaxDomainName) < 0) str_error = 1; | |
575 | rrtype = get_short(&data); | |
576 | rrclass = get_short(&data); | |
577 | rdlen = get_short(&data); | |
578 | rdata = get_rdata(&data, rdlen); | |
579 | ttl = get_long(&data); | |
ccd4a120 | 580 | |
c29f2fcc A |
581 | if (!errorCode && str_error) errorCode = kDNSServiceErr_Unknown; |
582 | ((DNSServiceQueryRecordReply)sdr->app_callback)(sdr, flags, interfaceIndex, errorCode, name, rrtype, rrclass, | |
583 | rdlen, rdata, ttl, sdr->app_context); | |
584 | return; | |
585 | } | |
ccd4a120 | 586 | |
c29f2fcc | 587 | DNSServiceErrorType DNSSD_API DNSServiceQueryRecord |
ccd4a120 A |
588 | ( |
589 | DNSServiceRef *sdRef, | |
c29f2fcc A |
590 | DNSServiceFlags flags, |
591 | uint32_t interfaceIndex, | |
ccd4a120 | 592 | const char *name, |
c29f2fcc A |
593 | uint16_t rrtype, |
594 | uint16_t rrclass, | |
595 | DNSServiceQueryRecordReply callBack, | |
ccd4a120 A |
596 | void *context |
597 | ) | |
598 | { | |
599 | char *msg = NULL, *ptr; | |
c29f2fcc | 600 | size_t len; |
ccd4a120 A |
601 | ipc_msg_hdr *hdr; |
602 | DNSServiceRef sdr; | |
603 | DNSServiceErrorType err; | |
c29f2fcc | 604 | |
ccd4a120 A |
605 | if (!sdRef) return kDNSServiceErr_BadParam; |
606 | *sdRef = NULL; | |
607 | ||
608 | if (!name) name = "\0"; | |
609 | ||
610 | // calculate total message length | |
611 | len = sizeof(flags); | |
612 | len += sizeof(uint32_t); //interfaceIndex | |
613 | len += strlen(name) + 1; | |
614 | len += 2 * sizeof(uint16_t); // rrtype, rrclass | |
615 | ||
616 | hdr = create_hdr(query_request, &len, &ptr, 1); | |
617 | if (!hdr) goto error; | |
618 | msg = (void *)hdr; | |
619 | ||
620 | put_flags(flags, &ptr); | |
621 | put_long(interfaceIndex, &ptr); | |
622 | put_string(name, &ptr); | |
623 | put_short(rrtype, &ptr); | |
624 | put_short(rrclass, &ptr); | |
625 | ||
626 | sdr = connect_to_server(); | |
627 | if (!sdr) goto error; | |
628 | err = deliver_request(msg, sdr, 1); | |
629 | if (err) | |
630 | { | |
631 | DNSServiceRefDeallocate(sdr); | |
632 | return err; | |
633 | } | |
634 | ||
635 | sdr->op = query_request; | |
636 | sdr->process_reply = handle_query_response; | |
637 | sdr->app_callback = callBack; | |
638 | sdr->app_context = context; | |
639 | *sdRef = sdr; | |
640 | return err; | |
641 | ||
642 | error: | |
643 | if (msg) free(msg); | |
644 | if (*sdRef) { free(*sdRef); *sdRef = NULL; } | |
645 | return kDNSServiceErr_Unknown; | |
646 | } | |
647 | ||
c29f2fcc | 648 | static void handle_browse_response(DNSServiceRef sdr, ipc_msg_hdr *hdr, char *data) |
ccd4a120 | 649 | { |
c29f2fcc A |
650 | DNSServiceFlags flags; |
651 | uint32_t interfaceIndex; | |
652 | DNSServiceErrorType errorCode; | |
653 | char replyName[256], replyType[kDNSServiceMaxDomainName], | |
654 | replyDomain[kDNSServiceMaxDomainName]; | |
655 | int str_error = 0; | |
656 | (void)hdr;//Unused | |
ccd4a120 A |
657 | |
658 | flags = get_flags(&data); | |
659 | interfaceIndex = get_long(&data); | |
660 | errorCode = get_error_code(&data); | |
c29f2fcc A |
661 | if (get_string(&data, replyName, 256) < 0) str_error = 1; |
662 | if (get_string(&data, replyType, kDNSServiceMaxDomainName) < 0) str_error = 1; | |
663 | if (get_string(&data, replyDomain, kDNSServiceMaxDomainName) < 0) str_error = 1; | |
664 | if (!errorCode && str_error) errorCode = kDNSServiceErr_Unknown; | |
665 | ((DNSServiceBrowseReply)sdr->app_callback)(sdr, flags, interfaceIndex, errorCode, replyName, replyType, replyDomain, sdr->app_context); | |
ccd4a120 A |
666 | } |
667 | ||
c29f2fcc | 668 | DNSServiceErrorType DNSSD_API DNSServiceBrowse |
ccd4a120 A |
669 | ( |
670 | DNSServiceRef *sdRef, | |
c29f2fcc A |
671 | DNSServiceFlags flags, |
672 | uint32_t interfaceIndex, | |
ccd4a120 A |
673 | const char *regtype, |
674 | const char *domain, | |
c29f2fcc | 675 | DNSServiceBrowseReply callBack, |
ccd4a120 A |
676 | void *context |
677 | ) | |
678 | { | |
679 | char *msg = NULL, *ptr; | |
c29f2fcc | 680 | size_t len; |
ccd4a120 A |
681 | ipc_msg_hdr *hdr; |
682 | DNSServiceRef sdr; | |
683 | DNSServiceErrorType err; | |
684 | ||
685 | if (!sdRef) return kDNSServiceErr_BadParam; | |
686 | *sdRef = NULL; | |
687 | ||
688 | if (!domain) domain = ""; | |
689 | ||
690 | len = sizeof(flags); | |
691 | len += sizeof(interfaceIndex); | |
692 | len += strlen(regtype) + 1; | |
693 | len += strlen(domain) + 1; | |
694 | ||
695 | hdr = create_hdr(browse_request, &len, &ptr, 1); | |
696 | if (!hdr) goto error; | |
697 | msg = (char *)hdr; | |
698 | put_flags(flags, &ptr); | |
699 | put_long(interfaceIndex, &ptr); | |
700 | put_string(regtype, &ptr); | |
701 | put_string(domain, &ptr); | |
702 | ||
703 | sdr = connect_to_server(); | |
704 | if (!sdr) goto error; | |
705 | err = deliver_request(msg, sdr, 1); | |
706 | if (err) | |
707 | { | |
708 | DNSServiceRefDeallocate(sdr); | |
709 | return err; | |
710 | } | |
711 | sdr->op = browse_request; | |
712 | sdr->process_reply = handle_browse_response; | |
713 | sdr->app_callback = callBack; | |
714 | sdr->app_context = context; | |
715 | *sdRef = sdr; | |
716 | return err; | |
717 | ||
718 | error: | |
719 | if (msg) free(msg); | |
720 | if (*sdRef) { free(*sdRef); *sdRef = NULL; } | |
721 | return kDNSServiceErr_Unknown; | |
722 | } | |
723 | ||
c29f2fcc A |
724 | DNSServiceErrorType DNSSD_API DNSServiceSetDefaultDomainForUser |
725 | ( | |
726 | DNSServiceFlags flags, | |
727 | const char *domain | |
728 | ) | |
729 | { | |
730 | DNSServiceRef sdr; | |
731 | DNSServiceErrorType err; | |
732 | char *ptr = NULL; | |
733 | size_t len = sizeof(flags) + strlen(domain) + 1; | |
734 | ipc_msg_hdr *hdr = create_hdr(setdomain_request, &len, &ptr, 1); | |
735 | ||
736 | if (!hdr) return kDNSServiceErr_Unknown; | |
737 | put_flags(flags, &ptr); | |
738 | put_string(domain, &ptr); | |
ccd4a120 | 739 | |
c29f2fcc A |
740 | sdr = connect_to_server(); |
741 | if (!sdr) { free(hdr); return kDNSServiceErr_Unknown; } | |
742 | err = deliver_request((char *)hdr, sdr, 1); // deliver_request frees the message for us | |
743 | DNSServiceRefDeallocate(sdr); | |
744 | return err; | |
745 | } | |
ccd4a120 A |
746 | |
747 | ||
c29f2fcc | 748 | static void handle_regservice_response(DNSServiceRef sdr, ipc_msg_hdr *hdr, char *data) |
ccd4a120 | 749 | { |
c29f2fcc A |
750 | DNSServiceFlags flags; |
751 | uint32_t interfaceIndex; | |
752 | DNSServiceErrorType errorCode; | |
753 | char name[256], regtype[kDNSServiceMaxDomainName], domain[kDNSServiceMaxDomainName]; | |
754 | int str_error = 0; | |
ccd4a120 A |
755 | (void)hdr;//Unused |
756 | ||
757 | flags = get_flags(&data); | |
758 | interfaceIndex = get_long(&data); | |
759 | errorCode = get_error_code(&data); | |
c29f2fcc A |
760 | if (get_string(&data, name, 256) < 0) str_error = 1; |
761 | if (get_string(&data, regtype, kDNSServiceMaxDomainName) < 0) str_error = 1; | |
762 | if (get_string(&data, domain, kDNSServiceMaxDomainName) < 0) str_error = 1; | |
763 | if (!errorCode && str_error) errorCode = kDNSServiceErr_Unknown; | |
764 | ((DNSServiceRegisterReply)sdr->app_callback)(sdr, flags, errorCode, name, regtype, domain, sdr->app_context); | |
ccd4a120 A |
765 | } |
766 | ||
c29f2fcc | 767 | DNSServiceErrorType DNSSD_API DNSServiceRegister |
ccd4a120 A |
768 | ( |
769 | DNSServiceRef *sdRef, | |
c29f2fcc A |
770 | DNSServiceFlags flags, |
771 | uint32_t interfaceIndex, | |
772 | const char *name, | |
773 | const char *regtype, | |
774 | const char *domain, | |
775 | const char *host, | |
776 | uint16_t PortInNetworkByteOrder, | |
777 | uint16_t txtLen, | |
778 | const void *txtRecord, | |
779 | DNSServiceRegisterReply callBack, | |
780 | void *context | |
ccd4a120 A |
781 | ) |
782 | { | |
783 | char *msg = NULL, *ptr; | |
c29f2fcc | 784 | size_t len; |
ccd4a120 A |
785 | ipc_msg_hdr *hdr; |
786 | DNSServiceRef sdr; | |
787 | DNSServiceErrorType err; | |
c29f2fcc | 788 | union { uint16_t s; u_char b[2]; } port = { PortInNetworkByteOrder }; |
ccd4a120 A |
789 | |
790 | if (!sdRef) return kDNSServiceErr_BadParam; | |
791 | *sdRef = NULL; | |
792 | ||
793 | if (!name) name = ""; | |
794 | if (!regtype) return kDNSServiceErr_BadParam; | |
795 | if (!domain) domain = ""; | |
796 | if (!host) host = ""; | |
c29f2fcc A |
797 | if (!txtRecord) txtRecord = (void*)""; |
798 | ||
ccd4a120 A |
799 | // auto-name must also have auto-rename |
800 | if (!name[0] && (flags & kDNSServiceFlagsNoAutoRename)) | |
801 | return kDNSServiceErr_BadParam; | |
802 | ||
803 | // no callback must have auto-name | |
804 | if (!callBack && name[0]) return kDNSServiceErr_BadParam; | |
805 | ||
806 | len = sizeof(DNSServiceFlags); | |
807 | len += sizeof(uint32_t); // interfaceIndex | |
808 | len += strlen(name) + strlen(regtype) + strlen(domain) + strlen(host) + 4; | |
809 | len += 2 * sizeof(uint16_t); // port, txtLen | |
810 | len += txtLen; | |
811 | ||
812 | hdr = create_hdr(reg_service_request, &len, &ptr, 1); | |
813 | if (!hdr) goto error; | |
814 | if (!callBack) hdr->flags |= IPC_FLAGS_NOREPLY; | |
815 | msg = (char *)hdr; | |
816 | put_flags(flags, &ptr); | |
817 | put_long(interfaceIndex, &ptr); | |
818 | put_string(name, &ptr); | |
819 | put_string(regtype, &ptr); | |
820 | put_string(domain, &ptr); | |
821 | put_string(host, &ptr); | |
c29f2fcc A |
822 | *ptr++ = port.b[0]; |
823 | *ptr++ = port.b[1]; | |
ccd4a120 A |
824 | put_short(txtLen, &ptr); |
825 | put_rdata(txtLen, txtRecord, &ptr); | |
826 | ||
827 | sdr = connect_to_server(); | |
828 | if (!sdr) goto error; | |
829 | err = deliver_request(msg, sdr, 1); | |
830 | if (err) | |
831 | { | |
832 | DNSServiceRefDeallocate(sdr); | |
833 | return err; | |
834 | } | |
c29f2fcc | 835 | |
ccd4a120 A |
836 | sdr->op = reg_service_request; |
837 | sdr->process_reply = callBack ? handle_regservice_response : NULL; | |
838 | sdr->app_callback = callBack; | |
839 | sdr->app_context = context; | |
840 | *sdRef = sdr; | |
841 | ||
842 | return err; | |
c29f2fcc | 843 | |
ccd4a120 A |
844 | error: |
845 | if (msg) free(msg); | |
846 | if (*sdRef) { free(*sdRef); *sdRef = NULL; } | |
847 | return kDNSServiceErr_Unknown; | |
848 | } | |
849 | ||
c29f2fcc | 850 | static void handle_enumeration_response(DNSServiceRef sdr, ipc_msg_hdr *hdr, char *data) |
ccd4a120 A |
851 | { |
852 | DNSServiceFlags flags; | |
853 | uint32_t interfaceIndex; | |
c29f2fcc A |
854 | DNSServiceErrorType err; |
855 | char domain[kDNSServiceMaxDomainName]; | |
856 | int str_error = 0; | |
ccd4a120 A |
857 | (void)hdr;//Unused |
858 | ||
859 | flags = get_flags(&data); | |
860 | interfaceIndex = get_long(&data); | |
c29f2fcc A |
861 | err = get_error_code(&data); |
862 | if (get_string(&data, domain, kDNSServiceMaxDomainName) < 0) str_error = 1; | |
863 | if (!err && str_error) err = kDNSServiceErr_Unknown; | |
864 | ((DNSServiceDomainEnumReply)sdr->app_callback)(sdr, flags, interfaceIndex, err, domain, sdr->app_context); | |
ccd4a120 A |
865 | } |
866 | ||
c29f2fcc | 867 | DNSServiceErrorType DNSSD_API DNSServiceEnumerateDomains |
ccd4a120 A |
868 | ( |
869 | DNSServiceRef *sdRef, | |
c29f2fcc A |
870 | DNSServiceFlags flags, |
871 | uint32_t interfaceIndex, | |
872 | DNSServiceDomainEnumReply callBack, | |
ccd4a120 A |
873 | void *context |
874 | ) | |
875 | { | |
876 | char *msg = NULL, *ptr; | |
c29f2fcc | 877 | size_t len; |
ccd4a120 A |
878 | ipc_msg_hdr *hdr; |
879 | DNSServiceRef sdr; | |
880 | DNSServiceErrorType err; | |
c29f2fcc A |
881 | int f1 = (flags & kDNSServiceFlagsBrowseDomains) != 0; |
882 | int f2 = (flags & kDNSServiceFlagsRegistrationDomains) != 0; | |
883 | if (f1 + f2 != 1) return kDNSServiceErr_BadParam; | |
ccd4a120 A |
884 | |
885 | if (!sdRef) return kDNSServiceErr_BadParam; | |
886 | *sdRef = NULL; | |
887 | ||
c29f2fcc | 888 | len = sizeof(DNSServiceFlags); |
ccd4a120 A |
889 | len += sizeof(uint32_t); |
890 | ||
891 | hdr = create_hdr(enumeration_request, &len, &ptr, 1); | |
892 | if (!hdr) goto error; | |
893 | msg = (void *)hdr; | |
894 | ||
895 | put_flags(flags, &ptr); | |
896 | put_long(interfaceIndex, &ptr); | |
897 | ||
898 | sdr = connect_to_server(); | |
899 | if (!sdr) goto error; | |
900 | err = deliver_request(msg, sdr, 1); | |
901 | if (err) | |
902 | { | |
903 | DNSServiceRefDeallocate(sdr); | |
904 | return err; | |
905 | } | |
906 | ||
907 | sdr->op = enumeration_request; | |
908 | sdr->process_reply = handle_enumeration_response; | |
909 | sdr->app_callback = callBack; | |
910 | sdr->app_context = context; | |
911 | *sdRef = sdr; | |
912 | return err; | |
913 | ||
914 | error: | |
915 | if (msg) free(msg); | |
916 | if (*sdRef) { free(*sdRef); *sdRef = NULL; } | |
917 | return kDNSServiceErr_Unknown; | |
918 | } | |
919 | ||
c29f2fcc | 920 | static void handle_regrecord_response(DNSServiceRef sdr, ipc_msg_hdr *hdr, char *data) |
ccd4a120 A |
921 | { |
922 | DNSServiceFlags flags; | |
923 | uint32_t interfaceIndex; | |
c29f2fcc A |
924 | DNSServiceErrorType errorCode; |
925 | DNSRecordRef rref = hdr->client_context.context; | |
ccd4a120 | 926 | |
c29f2fcc A |
927 | if (sdr->op != connection) |
928 | { | |
929 | rref->app_callback(rref->sdr, rref, 0, kDNSServiceErr_Unknown, rref->app_context); | |
930 | return; | |
931 | } | |
ccd4a120 A |
932 | flags = get_flags(&data); |
933 | interfaceIndex = get_long(&data); | |
c29f2fcc | 934 | errorCode = get_error_code(&data); |
ccd4a120 | 935 | |
c29f2fcc A |
936 | rref->app_callback(rref->sdr, rref, flags, errorCode, rref->app_context); |
937 | } | |
ccd4a120 | 938 | |
c29f2fcc | 939 | DNSServiceErrorType DNSSD_API DNSServiceCreateConnection(DNSServiceRef *sdRef) |
ccd4a120 A |
940 | { |
941 | if (!sdRef) return kDNSServiceErr_BadParam; | |
942 | *sdRef = connect_to_server(); | |
943 | if (!*sdRef) | |
944 | return kDNSServiceErr_Unknown; | |
945 | (*sdRef)->op = connection; | |
946 | (*sdRef)->process_reply = handle_regrecord_response; | |
947 | return 0; | |
948 | } | |
949 | ||
c29f2fcc | 950 | DNSServiceErrorType DNSSD_API DNSServiceRegisterRecord |
ccd4a120 | 951 | ( |
c29f2fcc A |
952 | DNSServiceRef sdRef, |
953 | DNSRecordRef *RecordRef, | |
954 | DNSServiceFlags flags, | |
955 | uint32_t interfaceIndex, | |
ccd4a120 | 956 | const char *fullname, |
c29f2fcc A |
957 | uint16_t rrtype, |
958 | uint16_t rrclass, | |
959 | uint16_t rdlen, | |
ccd4a120 | 960 | const void *rdata, |
c29f2fcc A |
961 | uint32_t ttl, |
962 | DNSServiceRegisterRecordReply callBack, | |
ccd4a120 A |
963 | void *context |
964 | ) | |
965 | { | |
966 | char *msg = NULL, *ptr; | |
c29f2fcc | 967 | size_t len; |
ccd4a120 A |
968 | ipc_msg_hdr *hdr = NULL; |
969 | DNSServiceRef tmp = NULL; | |
970 | DNSRecordRef rref = NULL; | |
c29f2fcc A |
971 | int f1 = (flags & kDNSServiceFlagsShared) != 0; |
972 | int f2 = (flags & kDNSServiceFlagsUnique) != 0; | |
973 | if (f1 + f2 != 1) return kDNSServiceErr_BadParam; | |
974 | ||
975 | if (!sdRef || sdRef->op != connection || sdRef->sockfd < 0) | |
ccd4a120 A |
976 | return kDNSServiceErr_BadReference; |
977 | *RecordRef = NULL; | |
c29f2fcc A |
978 | |
979 | len = sizeof(DNSServiceFlags); | |
ccd4a120 A |
980 | len += 2 * sizeof(uint32_t); // interfaceIndex, ttl |
981 | len += 3 * sizeof(uint16_t); // rrtype, rrclass, rdlen | |
982 | len += strlen(fullname) + 1; | |
983 | len += rdlen; | |
984 | ||
985 | hdr = create_hdr(reg_record_request, &len, &ptr, 0); | |
986 | if (!hdr) goto error; | |
987 | msg = (char *)hdr; | |
988 | put_flags(flags, &ptr); | |
989 | put_long(interfaceIndex, &ptr); | |
990 | put_string(fullname, &ptr); | |
991 | put_short(rrtype, &ptr); | |
992 | put_short(rrclass, &ptr); | |
993 | put_short(rdlen, &ptr); | |
994 | put_rdata(rdlen, rdata, &ptr); | |
995 | put_long(ttl, &ptr); | |
996 | ||
997 | rref = malloc(sizeof(_DNSRecordRef_t)); | |
998 | if (!rref) goto error; | |
999 | rref->app_context = context; | |
1000 | rref->app_callback = callBack; | |
1001 | rref->record_index = sdRef->max_index++; | |
1002 | rref->sdr = sdRef; | |
1003 | *RecordRef = rref; | |
1004 | hdr->client_context.context = rref; | |
c29f2fcc A |
1005 | hdr->reg_index = rref->record_index; |
1006 | ||
ccd4a120 A |
1007 | return deliver_request(msg, sdRef, 0); |
1008 | ||
1009 | error: | |
1010 | if (rref) free(rref); | |
1011 | if (tmp) free(tmp); | |
1012 | if (hdr) free(hdr); | |
1013 | return kDNSServiceErr_Unknown; | |
1014 | } | |
1015 | ||
1016 | //sdRef returned by DNSServiceRegister() | |
c29f2fcc | 1017 | DNSServiceErrorType DNSSD_API DNSServiceAddRecord |
ccd4a120 | 1018 | ( |
c29f2fcc | 1019 | DNSServiceRef sdRef, |
ccd4a120 | 1020 | DNSRecordRef *RecordRef, |
c29f2fcc A |
1021 | DNSServiceFlags flags, |
1022 | uint16_t rrtype, | |
1023 | uint16_t rdlen, | |
ccd4a120 | 1024 | const void *rdata, |
c29f2fcc | 1025 | uint32_t ttl |
ccd4a120 A |
1026 | ) |
1027 | { | |
1028 | ipc_msg_hdr *hdr; | |
c29f2fcc | 1029 | size_t len = 0; |
ccd4a120 A |
1030 | char *ptr; |
1031 | DNSRecordRef rref; | |
1032 | ||
c29f2fcc | 1033 | if (!sdRef || (sdRef->op != reg_service_request) || !RecordRef) |
ccd4a120 A |
1034 | return kDNSServiceErr_BadReference; |
1035 | *RecordRef = NULL; | |
c29f2fcc | 1036 | |
ccd4a120 A |
1037 | len += 2 * sizeof(uint16_t); //rrtype, rdlen |
1038 | len += rdlen; | |
1039 | len += sizeof(uint32_t); | |
1040 | len += sizeof(DNSServiceFlags); | |
1041 | ||
1042 | hdr = create_hdr(add_record_request, &len, &ptr, 0); | |
1043 | if (!hdr) return kDNSServiceErr_Unknown; | |
1044 | put_flags(flags, &ptr); | |
1045 | put_short(rrtype, &ptr); | |
1046 | put_short(rdlen, &ptr); | |
1047 | put_rdata(rdlen, rdata, &ptr); | |
1048 | put_long(ttl, &ptr); | |
1049 | ||
1050 | rref = malloc(sizeof(_DNSRecordRef_t)); | |
1051 | if (!rref) goto error; | |
1052 | rref->app_context = NULL; | |
1053 | rref->app_callback = NULL; | |
1054 | rref->record_index = sdRef->max_index++; | |
1055 | rref->sdr = sdRef; | |
1056 | *RecordRef = rref; | |
1057 | hdr->client_context.context = rref; | |
c29f2fcc | 1058 | hdr->reg_index = rref->record_index; |
ccd4a120 A |
1059 | return deliver_request((char *)hdr, sdRef, 0); |
1060 | ||
1061 | error: | |
1062 | if (hdr) free(hdr); | |
1063 | if (rref) free(rref); | |
1064 | if (*RecordRef) *RecordRef = NULL; | |
1065 | return kDNSServiceErr_Unknown; | |
1066 | } | |
ccd4a120 A |
1067 | |
1068 | //DNSRecordRef returned by DNSServiceRegisterRecord or DNSServiceAddRecord | |
c29f2fcc | 1069 | DNSServiceErrorType DNSSD_API DNSServiceUpdateRecord |
ccd4a120 | 1070 | ( |
c29f2fcc | 1071 | DNSServiceRef sdRef, |
ccd4a120 | 1072 | DNSRecordRef RecordRef, |
c29f2fcc A |
1073 | DNSServiceFlags flags, |
1074 | uint16_t rdlen, | |
ccd4a120 | 1075 | const void *rdata, |
c29f2fcc | 1076 | uint32_t ttl |
ccd4a120 A |
1077 | ) |
1078 | { | |
1079 | ipc_msg_hdr *hdr; | |
c29f2fcc | 1080 | size_t len = 0; |
ccd4a120 A |
1081 | char *ptr; |
1082 | ||
c29f2fcc A |
1083 | if (!sdRef) return kDNSServiceErr_BadReference; |
1084 | ||
ccd4a120 A |
1085 | len += sizeof(uint16_t); |
1086 | len += rdlen; | |
1087 | len += sizeof(uint32_t); | |
1088 | len += sizeof(DNSServiceFlags); | |
1089 | ||
1090 | hdr = create_hdr(update_record_request, &len, &ptr, 0); | |
1091 | if (!hdr) return kDNSServiceErr_Unknown; | |
1092 | hdr->reg_index = RecordRef ? RecordRef->record_index : TXT_RECORD_INDEX; | |
1093 | put_flags(flags, &ptr); | |
1094 | put_short(rdlen, &ptr); | |
1095 | put_rdata(rdlen, rdata, &ptr); | |
1096 | put_long(ttl, &ptr); | |
1097 | return deliver_request((char *)hdr, sdRef, 0); | |
1098 | } | |
ccd4a120 | 1099 | |
c29f2fcc | 1100 | DNSServiceErrorType DNSSD_API DNSServiceRemoveRecord |
ccd4a120 | 1101 | ( |
c29f2fcc A |
1102 | DNSServiceRef sdRef, |
1103 | DNSRecordRef RecordRef, | |
1104 | DNSServiceFlags flags | |
ccd4a120 A |
1105 | ) |
1106 | { | |
1107 | ipc_msg_hdr *hdr; | |
c29f2fcc | 1108 | size_t len = 0; |
ccd4a120 A |
1109 | char *ptr; |
1110 | DNSServiceErrorType err; | |
1111 | ||
c29f2fcc | 1112 | if (!sdRef || !RecordRef || !sdRef->max_index) |
ccd4a120 | 1113 | return kDNSServiceErr_BadReference; |
c29f2fcc | 1114 | |
ccd4a120 A |
1115 | len += sizeof(flags); |
1116 | hdr = create_hdr(remove_record_request, &len, &ptr, 0); | |
1117 | if (!hdr) return kDNSServiceErr_Unknown; | |
1118 | hdr->reg_index = RecordRef->record_index; | |
1119 | put_flags(flags, &ptr); | |
1120 | err = deliver_request((char *)hdr, sdRef, 0); | |
1121 | if (!err) free(RecordRef); | |
1122 | return err; | |
1123 | } | |
1124 | ||
c29f2fcc | 1125 | void DNSSD_API DNSServiceReconfirmRecord |
ccd4a120 | 1126 | ( |
c29f2fcc A |
1127 | DNSServiceFlags flags, |
1128 | uint32_t interfaceIndex, | |
ccd4a120 | 1129 | const char *fullname, |
c29f2fcc A |
1130 | uint16_t rrtype, |
1131 | uint16_t rrclass, | |
1132 | uint16_t rdlen, | |
ccd4a120 A |
1133 | const void *rdata |
1134 | ) | |
1135 | { | |
1136 | char *ptr; | |
c29f2fcc | 1137 | size_t len; |
ccd4a120 A |
1138 | ipc_msg_hdr *hdr; |
1139 | DNSServiceRef tmp; | |
1140 | ||
1141 | len = sizeof(DNSServiceFlags); | |
1142 | len += sizeof(uint32_t); | |
1143 | len += strlen(fullname) + 1; | |
1144 | len += 3 * sizeof(uint16_t); | |
1145 | len += rdlen; | |
1146 | tmp = connect_to_server(); | |
1147 | if (!tmp) return; | |
1148 | hdr = create_hdr(reconfirm_record_request, &len, &ptr, 1); | |
1149 | if (!hdr) return; | |
1150 | ||
1151 | put_flags(flags, &ptr); | |
1152 | put_long(interfaceIndex, &ptr); | |
1153 | put_string(fullname, &ptr); | |
1154 | put_short(rrtype, &ptr); | |
1155 | put_short(rrclass, &ptr); | |
1156 | put_short(rdlen, &ptr); | |
1157 | put_rdata(rdlen, rdata, &ptr); | |
c29f2fcc A |
1158 | ConvertHeaderBytes(hdr); |
1159 | my_write(tmp->sockfd, (char *)hdr, (int) len); | |
1160 | free(hdr); | |
ccd4a120 A |
1161 | DNSServiceRefDeallocate(tmp); |
1162 | } | |
ccd4a120 | 1163 |