1 /* -*- Mode: C; tab-width: 4 -*- 2 * 3 * Copyright (c) 2003-2004, Apple Computer, Inc. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are met: 7 * 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. 16 * 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.134 2009/06/19 23:13:24 cheshire 32 <rdar://problem/6990066> Library: crash at handle_resolve_response + 183 33 Added check for NULL after calling get_string 34 35 Revision 1.133 2009/05/27 22:19:12 cheshire 36 Remove questionable uses of errno 37 38 Revision 1.132 2009/05/26 21:31:07 herscher 39 Fix compile errors on Windows 40 41 Revision 1.131 2009/05/26 04:48:19 herscher 42 <rdar://problem/6844819> ExplorerPlugin does not work in B4W 2.0 43 44 Revision 1.130 2009/05/02 01:29:48 mcguire 45 <rdar://problem/6847601> spin calling DNSServiceProcessResult if errno was set to EWOULDBLOCK by an unrelated call 46 47 Revision 1.129 2009/05/01 19:18:50 cheshire 48 <rdar://problem/6843645> Using duplicate DNSServiceRefs when sharing a connection should return an error 49 50 Revision 1.128 2009/04/01 21:09:35 herscher 51 <rdar://problem/5925472> Current Bonjour code does not compile on Windows. 52 53 Revision 1.127 2009/03/03 21:38:19 cheshire 54 Improved "deliver_request ERROR" message 55 56 Revision 1.126 2009/02/12 21:02:22 cheshire 57 Commented out BPF "Sending fd" debugging message 58 59 Revision 1.125 2009/02/12 20:28:32 cheshire 60 Added some missing "const" declarations 61 62 Revision 1.124 2009/02/10 01:44:39 cheshire 63 <rdar://problem/6553729> DNSServiceUpdateRecord fails with kDNSServiceErr_BadReference for otherwise valid reference 64 65 Revision 1.123 2009/01/19 00:49:21 mkrochma 66 Type cast size_t values to unsigned long 67 68 Revision 1.122 2009/01/18 03:51:37 mkrochma 69 Fix warning in deliver_request on Linux 70 71 Revision 1.121 2009/01/16 23:34:37 cheshire 72 <rdar://problem/6504143> Uninitialized error code variable in error handling path in deliver_request 73 74 Revision 1.120 2009/01/13 05:31:35 mkrochma 75 <rdar://problem/6491367> Replace bzero, bcopy with mDNSPlatformMemZero, mDNSPlatformMemCopy, memset, memcpy 76 77 Revision 1.119 2009/01/11 03:45:08 mkrochma 78 Stop type casting num_written and num_read to int 79 80 Revision 1.118 2009/01/11 03:20:06 mkrochma 81 <rdar://problem/5797526> Fixes from Igor Seleznev to get mdnsd working on Solaris 82 83 Revision 1.117 2009/01/10 22:03:43 mkrochma 84 <rdar://problem/5797507> dnsextd fails to build on Linux 85 86 Revision 1.116 2009/01/05 16:55:24 cheshire 87 <rdar://problem/6452199> Stuck in "Examining available disks" 88 ConnectionResponse handler was accidentally matching the parent DNSServiceRef before 89 finding the appropriate subordinate DNSServiceRef for the operation in question. 90 91 Revision 1.115 2008/12/18 00:19:11 mcguire 92 <rdar://problem/6452199> Stuck in "Examining available disks" 93 94 Revision 1.114 2008/12/10 02:11:43 cheshire 95 ARMv5 compiler doesn't like uncommented stuff after #endif 96 97 Revision 1.113 2008/12/04 03:23:05 cheshire 98 Preincrement UID counter before we use it -- it helps with debugging if we know the all-zeroes ID should never appear 99 100 Revision 1.112 2008/11/25 22:56:54 cheshire 101 <rdar://problem/6377257> Make library code more defensive when client calls DNSServiceProcessResult with bad DNSServiceRef repeatedly 102 103 Revision 1.111 2008/10/28 17:58:44 cheshire 104 If client code keeps calling DNSServiceProcessResult repeatedly after an error, rate-limit the 105 "DNSServiceProcessResult called with DNSServiceRef with no ProcessReply function" log messages 106 107 Revision 1.110 2008/10/23 23:38:58 cheshire 108 For Windows compatibility, instead of "strerror(errno)" use "dnssd_strerror(dnssd_errno)" 109 110 Revision 1.109 2008/10/23 23:06:17 cheshire 111 Removed () from dnssd_errno macro definition -- it's not a function and doesn't need any arguments 112 113 Revision 1.108 2008/10/23 22:33:24 cheshire 114 Changed "NOTE:" to "Note:" so that BBEdit 9 stops putting those comment lines into the funtion popup menu 115 116 Revision 1.107 2008/10/20 21:50:11 cheshire 117 Improved /dev/bpf error message 118 119 Revision 1.106 2008/10/20 15:37:18 cheshire 120 Log error message if opening /dev/bpf fails 121 122 Revision 1.105 2008/09/27 01:26:34 cheshire 123 Added handler to pass back BPF fd when requested 124 125 Revision 1.104 2008/09/23 01:36:00 cheshire 126 Updated code to use internalPort/externalPort terminology, instead of the old privatePort/publicPort 127 terms (which could be misleading, because the word "private" suggests security). 128 129 Revision 1.103 2008/07/24 18:51:13 cheshire 130 Removed spurious spaces 131 132 Revision 1.102 2008/02/25 19:16:19 cheshire 133 <rdar://problem/5708953> Problems with DNSServiceGetAddrInfo API 134 Was returning a bogus result (NULL pointer) when following a CNAME referral 135 136 Revision 1.101 2008/02/20 21:18:21 cheshire 137 <rdar://problem/5708953> DNSServiceGetAddrInfo doesn't set the scope ID of returned IPv6 link local addresses 138 139 Revision 1.100 2007/11/02 17:56:37 cheshire 140 <rdar://problem/5565787> Bonjour API broken for 64-bit apps (SCM_RIGHTS sendmsg fails) 141 Wrap hack code in "#if APPLE_OSX_mDNSResponder" since (as far as we know right now) 142 we don't want to do this on 64-bit Linux, Solaris, etc. 143 144 Revision 1.99 2007/11/02 17:29:40 cheshire 145 <rdar://problem/5565787> Bonjour API broken for 64-bit apps (SCM_RIGHTS sendmsg fails) 146 To get 64-bit code that works, we need to NOT use the standard CMSG_* macros 147 148 Revision 1.98 2007/11/01 19:52:43 cheshire 149 Wrap debugging messages in "#if DEBUG_64BIT_SCM_RIGHTS" 150 151 Revision 1.97 2007/11/01 19:45:55 cheshire 152 Added "DEBUG_64BIT_SCM_RIGHTS" debugging code 153 See <rdar://problem/5565787> Bonjour API broken for 64-bit apps (SCM_RIGHTS sendmsg fails) 154 155 Revision 1.96 2007/11/01 15:59:33 cheshire 156 umask not being set and restored properly in USE_NAMED_ERROR_RETURN_SOCKET code 157 (no longer used on OS X, but relevant for other platforms) 158 159 Revision 1.95 2007/10/31 20:07:16 cheshire 160 <rdar://problem/5541498> Set SO_NOSIGPIPE on client socket 161 Refinement: the cleanup code still needs to close listenfd when necesssary 162 163 Revision 1.94 2007/10/15 22:34:27 cheshire 164 <rdar://problem/5541498> Set SO_NOSIGPIPE on client socket 165 166 Revision 1.93 2007/10/10 00:48:54 cheshire 167 <rdar://problem/5526379> Daemon spins in an infinite loop when it doesn't get the control message it's expecting 168 169 Revision 1.92 2007/10/06 03:44:44 cheshire 170 Testing code for <rdar://problem/5526374> kqueue does not get a kevent to wake it up when a control message arrives on a socket 171 172 Revision 1.91 2007/10/04 20:53:59 cheshire 173 Improved debugging message when sendmsg fails 174 175 Revision 1.90 2007/09/30 00:09:27 cheshire 176 <rdar://problem/5492315> Pass socket fd via SCM_RIGHTS sendmsg instead of using named UDS in the filesystem 177 178 Revision 1.89 2007/09/19 23:53:12 cheshire 179 Fixed spelling mistake in comment 180 181 Revision 1.88 2007/09/07 23:18:27 cheshire 182 <rdar://problem/5467542> Change "client_context" to be an incrementing 64-bit counter 183 184 Revision 1.87 2007/09/07 22:50:09 cheshire 185 Added comment explaining moreptr field in DNSServiceOp structure 186 187 Revision 1.86 2007/09/07 20:21:22 cheshire 188 <rdar://problem/5462371> Make DNSSD library more resilient 189 Add more comments explaining the moreptr/morebytes logic; don't allow DNSServiceRefSockFD or 190 DNSServiceProcessResult for subordinate DNSServiceRefs created using kDNSServiceFlagsShareConnection 191 192 Revision 1.85 2007/09/06 21:43:23 cheshire 193 <rdar://problem/5462371> Make DNSSD library more resilient 194 Allow DNSServiceRefDeallocate from within DNSServiceProcessResult callback 195 196 Revision 1.84 2007/09/06 18:31:47 cheshire 197 <rdar://problem/5462371> Make DNSSD library more resilient against client programming errors 198 199 Revision 1.83 2007/08/28 20:45:45 cheshire 200 Typo: ctrl_path needs to be 64 bytes, not 44 bytes 201 202 Revision 1.82 2007/08/28 19:53:52 cheshire 203 <rdar://problem/5437423> Bonjour failures when /tmp is not writable (e.g. when booted from installer disc) 204 205 Revision 1.81 2007/07/27 00:03:20 cheshire 206 Fixed compiler warnings that showed up now we're building optimized ("-Os") 207 208 Revision 1.80 2007/07/23 22:12:53 cheshire 209 <rdar://problem/5352299> Make mDNSResponder more defensive against malicious local clients 210 211 Revision 1.79 2007/07/23 19:58:24 cheshire 212 <rdar://problem/5351640> Library: Leak in DNSServiceRefDeallocate 213 214 Revision 1.78 2007/07/12 20:42:27 cheshire 215 <rdar://problem/5280735> If daemon is killed, return kDNSServiceErr_ServiceNotRunning 216 to clients instead of kDNSServiceErr_Unknown 217 218 Revision 1.77 2007/07/02 23:07:13 cheshire 219 <rdar://problem/5308280> Reduce DNS-SD client syslog error messages 220 221 Revision 1.76 2007/06/22 20:12:18 cheshire 222 <rdar://problem/5277024> Leak in DNSServiceRefDeallocate 223 224 Revision 1.75 2007/05/23 18:59:22 cheshire 225 Remove unnecessary IPC_FLAGS_REUSE_SOCKET 226 227 Revision 1.74 2007/05/22 18:28:38 cheshire 228 Fixed compile errors in posix build 229 230 Revision 1.73 2007/05/22 01:20:47 cheshire 231 To determine current operation, need to check hdr->op, not sdr->op 232 233 Revision 1.72 2007/05/22 01:07:42 cheshire 234 <rdar://problem/3563675> API: Need a way to get version/feature information 235 236 Revision 1.71 2007/05/18 23:55:22 cheshire 237 <rdar://problem/4454655> Allow multiple register/browse/resolve operations to share single Unix Domain Socket 238 239 Revision 1.70 2007/05/17 20:58:22 cheshire 240 <rdar://problem/4647145> DNSServiceQueryRecord should return useful information with NXDOMAIN 241 242 Revision 1.69 2007/05/16 16:58:27 cheshire 243 <rdar://problem/4471320> Improve reliability of kDNSServiceFlagsMoreComing flag on multiprocessor machines 244 As long as select indicates that data is waiting, loop within DNSServiceProcessResult delivering additional results 245 246 Revision 1.68 2007/05/16 01:06:52 cheshire 247 <rdar://problem/4471320> Improve reliability of kDNSServiceFlagsMoreComing flag on multiprocessor machines 248 249 Revision 1.67 2007/05/15 21:57:16 cheshire 250 <rdar://problem/4608220> Use dnssd_SocketValid(x) macro instead of just 251 assuming that all negative values (or zero!) are invalid socket numbers 252 253 Revision 1.66 2007/03/27 22:23:04 cheshire 254 Add "dnssd_clientstub" prefix onto syslog messages 255 256 Revision 1.65 2007/03/21 22:25:23 cheshire 257 <rdar://problem/4172796> Remove client retry logic now that mDNSResponder uses launchd for its Unix Domain Socket 258 259 Revision 1.64 2007/03/21 19:01:56 cheshire 260 <rdar://problem/5078494> IPC code not 64-bit-savvy: assumes long=32bits, and short=16bits 261 262 Revision 1.63 2007/03/12 21:48:21 cheshire 263 <rdar://problem/5000162> Scary unlink errors in system.log 264 Code was using memory after it had been freed 265 266 Revision 1.62 2007/02/28 01:44:30 cheshire 267 <rdar://problem/5027863> Byte order bugs in uDNS.c, uds_daemon.c, dnssd_clientstub.c 268 269 Revision 1.61 2007/02/09 03:09:42 cheshire 270 <rdar://problem/3869251> Cleanup: Stop returning kDNSServiceErr_Unknown so often 271 <rdar://problem/4177924> API: Should return kDNSServiceErr_ServiceNotRunning 272 273 Revision 1.60 2007/02/08 20:33:44 cheshire 274 <rdar://problem/4985095> Leak on error path in DNSServiceProcessResult 275 276 Revision 1.59 2007/01/05 08:30:55 cheshire 277 Trim excessive "Log" checkin history from before 2006 278 (checkin history still available via "cvs log ..." of course) 279 280 Revision 1.58 2006/10/27 00:38:22 cheshire 281 Strip accidental trailing whitespace from lines 282 283 Revision 1.57 2006/09/30 01:06:54 cheshire 284 Protocol field should be uint32_t 285 286 Revision 1.56 2006/09/27 00:44:16 herscher 287 <rdar://problem/4249761> API: Need DNSServiceGetAddrInfo() 288 289 Revision 1.55 2006/09/26 01:52:01 herscher 290 <rdar://problem/4245016> NAT Port Mapping API (for both NAT-PMP and UPnP Gateway Protocol) 291 292 Revision 1.54 2006/09/21 21:34:09 cheshire 293 <rdar://problem/4100000> Allow empty string name when using kDNSServiceFlagsNoAutoRename 294 295 Revision 1.53 2006/09/07 04:43:12 herscher 296 Fix compile error on Win32 platform by moving inclusion of syslog.h 297 298 Revision 1.52 2006/08/15 23:04:21 mkrochma 299 <rdar://problem/4090354> Client should be able to specify service name w/o callback 300 301 Revision 1.51 2006/07/24 23:45:55 cheshire 302 <rdar://problem/4605276> DNSServiceReconfirmRecord() should return error code 303 304 Revision 1.50 2006/06/28 08:22:27 cheshire 305 <rdar://problem/4605264> dnssd_clientstub.c needs to report unlink failures in syslog 306 307 Revision 1.49 2006/06/28 07:58:59 cheshire 308 Minor textual tidying 309 310 */ 311 312 #include <errno.h> 313 #include <stdlib.h> 314 315 #include "dnssd_ipc.h" 316 317 #if defined(_WIN32) 318 319 #define _SSIZE_T 320 #include <CommonServices.h> 321 #include <DebugServices.h> 322 #include <winsock2.h> 323 #include <ws2tcpip.h> 324 #include <windows.h> 325 #include <stdarg.h> 326 327 #define sockaddr_mdns sockaddr_in 328 #define AF_MDNS AF_INET 329 330 // Disable warning: "'type cast' : from data pointer 'void *' to function pointer" 331 #pragma warning(disable:4055) 332 333 // Disable warning: "nonstandard extension, function/data pointer conversion in expression" 334 #pragma warning(disable:4152) 335 336 extern BOOL IsSystemServiceDisabled(); 337 338 #define sleep(X) Sleep((X) * 1000) 339 340 static int g_initWinsock = 0; 341 #define LOG_WARNING kDebugLevelWarning 342 static void syslog( int priority, const char * message, ...) 343 { 344 va_list args; 345 int len; 346 char * buffer; 347 DWORD err = WSAGetLastError(); 348 va_start( args, message ); 349 len = _vscprintf( message, args ) + 1; 350 buffer = malloc( len * sizeof(char) ); 351 if ( buffer ) { vsprintf( buffer, message, args ); OutputDebugString( buffer ); free( buffer ); } 352 WSASetLastError( err ); 353 } 354 #else 355 356 #include <sys/fcntl.h> // For O_RDWR etc. 357 #include <sys/time.h> 358 #include <sys/socket.h> 359 #include <syslog.h> 360 361 #define sockaddr_mdns sockaddr_un 362 #define AF_MDNS AF_LOCAL 363 364 #endif 365 366 // <rdar://problem/4096913> Specifies how many times we'll try and connect to the server. 367 368 #define DNSSD_CLIENT_MAXTRIES 4 369 370 // Uncomment the line below to use the old error return mechanism of creating a temporary named socket (e.g. in /var/tmp) 371 //#define USE_NAMED_ERROR_RETURN_SOCKET 1 372 373 #ifndef CTL_PATH_PREFIX 374 #define CTL_PATH_PREFIX "/var/tmp/dnssd_result_socket." 375 #endif 376 377 typedef struct 378 { 379 ipc_msg_hdr ipc_hdr; 380 DNSServiceFlags cb_flags; 381 uint32_t cb_interface; 382 DNSServiceErrorType cb_err; 383 } CallbackHeader; 384 385 typedef struct _DNSServiceRef_t DNSServiceOp; 386 typedef struct _DNSRecordRef_t DNSRecord; 387 388 // client stub callback to process message from server and deliver results to client application 389 typedef void (*ProcessReplyFn)(DNSServiceOp *const sdr, const CallbackHeader *const cbh, const char *msg, const char *const end); 390 391 #define ValidatorBits 0x12345678 392 #define DNSServiceRefValid(X) (dnssd_SocketValid((X)->sockfd) && (((X)->sockfd ^ (X)->validator) == ValidatorBits)) 393 394 // When using kDNSServiceFlagsShareConnection, there is one primary _DNSServiceOp_t, and zero or more subordinates 395 // For the primary, the 'next' field points to the first subordinate, and its 'next' field points to the next, and so on. 396 // For the primary, the 'primary' field is NULL; for subordinates the 'primary' field points back to the associated primary 397 struct _DNSServiceRef_t 398 { 399 DNSServiceOp *next; // For shared connection 400 DNSServiceOp *primary; // For shared connection 401 dnssd_sock_t sockfd; // Connected socket between client and daemon 402 dnssd_sock_t validator; // Used to detect memory corruption, double disposals, etc. 403 client_context_t uid; // For shared connection requests, each subordinate DNSServiceRef has its own ID, 404 // unique within the scope of the same shared parent DNSServiceRef 405 uint32_t op; // request_op_t or reply_op_t 406 uint32_t max_index; // Largest assigned record index - 0 if no additional records registered 407 uint32_t logcounter; // Counter used to control number of syslog messages we write 408 int *moreptr; // Set while DNSServiceProcessResult working on this particular DNSServiceRef 409 ProcessReplyFn ProcessReply; // Function pointer to the code to handle received messages 410 void *AppCallback; // Client callback function and context 411 void *AppContext; 412 }; 413 414 struct _DNSRecordRef_t 415 { 416 void *AppContext; 417 DNSServiceRegisterRecordReply AppCallback; 418 DNSRecordRef recref; 419 uint32_t record_index; // index is unique to the ServiceDiscoveryRef 420 DNSServiceOp *sdr; 421 }; 422 423 // Write len bytes. Return 0 on success, -1 on error 424 static int write_all(dnssd_sock_t sd, char *buf, int len) 425 { 426 // Don't use "MSG_WAITALL"; it returns "Invalid argument" on some Linux versions; use an explicit while() loop instead. 427 //if (send(sd, buf, len, MSG_WAITALL) != len) return -1; 428 while (len) 429 { 430 ssize_t num_written = send(sd, buf, len, 0); 431 if (num_written < 0 || num_written > len) 432 { 433 // Should never happen. If it does, it indicates some OS bug, 434 // or that the mDNSResponder daemon crashed (which should never happen). 435 syslog(LOG_WARNING, "dnssd_clientstub write_all(%d) failed %zd/%d %d %s", sd, num_written, len, 436 (num_written < 0) ? dnssd_errno : 0, 437 (num_written < 0) ? dnssd_strerror(dnssd_errno) : ""); 438 return -1; 439 } 440 buf += num_written; 441 len -= num_written; 442 } 443 return 0; 444 } 445 446 enum { read_all_success = 0, read_all_fail = -1, read_all_wouldblock = -2 }; 447 448 // Read len bytes. Return 0 on success, read_all_fail on error, or read_all_wouldblock for 449 static int read_all(dnssd_sock_t sd, char *buf, int len) 450 { 451 // Don't use "MSG_WAITALL"; it returns "Invalid argument" on some Linux versions; use an explicit while() loop instead. 452 //if (recv(sd, buf, len, MSG_WAITALL) != len) return -1; 453 454 while (len) 455 { 456 ssize_t num_read = recv(sd, buf, len, 0); 457 if ((num_read == 0) || (num_read < 0) || (num_read > len)) 458 { 459 // Should never happen. If it does, it indicates some OS bug, 460 // or that the mDNSResponder daemon crashed (which should never happen). 461 syslog(LOG_WARNING, "dnssd_clientstub read_all(%d) failed %zd/%d %d %s", sd, num_read, len, 462 (num_read < 0) ? dnssd_errno : 0, 463 (num_read < 0) ? dnssd_strerror(dnssd_errno) : ""); 464 return (num_read < 0 && dnssd_errno == dnssd_EWOULDBLOCK) ? read_all_wouldblock : read_all_fail; 465 } 466 buf += num_read; 467 len -= num_read; 468 } 469 return read_all_success; 470 } 471 472 // Returns 1 if more bytes remain to be read on socket descriptor sd, 0 otherwise 473 static int more_bytes(dnssd_sock_t sd) 474 { 475 struct timeval tv = { 0, 0 }; 476 fd_set readfds; 477 FD_ZERO(&readfds); 478 FD_SET(sd, &readfds); 479 return(select(sd+1, &readfds, (fd_set*)NULL, (fd_set*)NULL, &tv) > 0); 480 } 481 482 /* create_hdr 483 * 484 * allocate and initialize an ipc message header. Value of len should initially be the 485 * length of the data, and is set to the value of the data plus the header. data_start 486 * is set to point to the beginning of the data section. SeparateReturnSocket should be 487 * non-zero for calls that can't receive an immediate error return value on their primary 488 * socket, and therefore require a separate return path for the error code result. 489 * if zero, the path to a control socket is appended at the beginning of the message buffer. 490 * data_start is set past this string. 491 */ 492 static ipc_msg_hdr *create_hdr(uint32_t op, size_t *len, char **data_start, int SeparateReturnSocket, DNSServiceOp *ref) 493 { 494 char *msg = NULL; 495 ipc_msg_hdr *hdr; 496 int datalen; 497 #if !defined(USE_TCP_LOOPBACK) 498 char ctrl_path[64] = ""; // "/var/tmp/dnssd_result_socket.xxxxxxxxxx-xxx-xxxxxx" 499 #endif 500 501 if (SeparateReturnSocket) 502 { 503 #if defined(USE_TCP_LOOPBACK) 504 *len += 2; // Allocate space for two-byte port number 505 #elif defined(USE_NAMED_ERROR_RETURN_SOCKET) 506 struct timeval time; 507 if (gettimeofday(&time, NULL) < 0) 508 { syslog(LOG_WARNING, "dnssd_clientstub create_hdr: gettimeofday failed %d %s", dnssd_errno, dnssd_strerror(dnssd_errno)); return NULL; } 509 sprintf(ctrl_path, "%s%d-%.3lx-%.6lu", CTL_PATH_PREFIX, (int)getpid(), 510 (unsigned long)(time.tv_sec & 0xFFF), (unsigned long)(time.tv_usec)); 511 *len += strlen(ctrl_path) + 1; 512 #else 513 *len += 1; // Allocate space for single zero byte (empty C string) 514 #endif 515 } 516 517 datalen = (int) *len; 518 *len += sizeof(ipc_msg_hdr); 519 520 // Write message to buffer 521 msg = malloc(*len); 522 if (!msg) { syslog(LOG_WARNING, "dnssd_clientstub create_hdr: malloc failed"); return NULL; } 523 524 memset(msg, 0, *len); 525 hdr = (ipc_msg_hdr *)msg; 526 hdr->version = VERSION; 527 hdr->datalen = datalen; 528 hdr->ipc_flags = 0; 529 hdr->op = op; 530 hdr->client_context = ref->uid; 531 hdr->reg_index = 0; 532 *data_start = msg + sizeof(ipc_msg_hdr); 533 #if defined(USE_TCP_LOOPBACK) 534 // Put dummy data in for the port, since we don't know what it is yet. 535 // The data will get filled in before we send the message. This happens in deliver_request(). 536 if (SeparateReturnSocket) put_uint16(0, data_start); 537 #else 538 if (SeparateReturnSocket) put_string(ctrl_path, data_start); 539 #endif 540 return hdr; 541 } 542 543 static void FreeDNSServiceOp(DNSServiceOp *x) 544 { 545 // We don't use our DNSServiceRefValid macro here because if we're cleaning up after a socket() call failed 546 // then sockfd could legitimately contain a failing value (e.g. dnssd_InvalidSocket) 547 if ((x->sockfd ^ x->validator) != ValidatorBits) 548 syslog(LOG_WARNING, "dnssd_clientstub attempt to dispose invalid DNSServiceRef %p %08X %08X", x, x->sockfd, x->validator); 549 else 550 { 551 x->next = NULL; 552 x->primary = NULL; 553 x->sockfd = dnssd_InvalidSocket; 554 x->validator = 0xDDDDDDDD; 555 x->op = request_op_none; 556 x->max_index = 0; 557 x->logcounter = 0; 558 x->moreptr = NULL; 559 x->ProcessReply = NULL; 560 x->AppCallback = NULL; 561 x->AppContext = NULL; 562 free(x); 563 } 564 } 565 566 // Return a connected service ref (deallocate with DNSServiceRefDeallocate) 567 static DNSServiceErrorType ConnectToServer(DNSServiceRef *ref, DNSServiceFlags flags, uint32_t op, ProcessReplyFn ProcessReply, void *AppCallback, void *AppContext) 568 { 569 #if APPLE_OSX_mDNSResponder 570 int NumTries = DNSSD_CLIENT_MAXTRIES; 571 #else 572 int NumTries = 0; 573 #endif 574 575 dnssd_sockaddr_t saddr; 576 DNSServiceOp *sdr; 577 578 if (!ref) { syslog(LOG_WARNING, "dnssd_clientstub DNSService operation with NULL DNSServiceRef"); return kDNSServiceErr_BadParam; } 579 580 if (flags & kDNSServiceFlagsShareConnection) 581 { 582 if (!*ref) 583 { 584 syslog(LOG_WARNING, "dnssd_clientstub kDNSServiceFlagsShareConnection used with NULL DNSServiceRef"); 585 return kDNSServiceErr_BadParam; 586 } 587 if (!DNSServiceRefValid(*ref) || (*ref)->op != connection_request || (*ref)->primary) 588 { 589 syslog(LOG_WARNING, "dnssd_clientstub kDNSServiceFlagsShareConnection used with invalid DNSServiceRef %p %08X %08X", 590 (*ref), (*ref)->sockfd, (*ref)->validator); 591 *ref = NULL; 592 return kDNSServiceErr_BadReference; 593 } 594 } 595 596 #if defined(_WIN32) 597 if (!g_initWinsock) 598 { 599 WSADATA wsaData; 600 g_initWinsock = 1; 601 if (WSAStartup(MAKEWORD(2,2), &wsaData) != 0) { *ref = NULL; return kDNSServiceErr_ServiceNotRunning; } 602 } 603 // <rdar://problem/4096913> If the system service is disabled, we only want to try to connect once 604 if (IsSystemServiceDisabled()) NumTries = DNSSD_CLIENT_MAXTRIES; 605 #endif 606 607 sdr = malloc(sizeof(DNSServiceOp)); 608 if (!sdr) { syslog(LOG_WARNING, "dnssd_clientstub ConnectToServer: malloc failed"); *ref = NULL; return kDNSServiceErr_NoMemory; } 609 sdr->next = NULL; 610 sdr->primary = NULL; 611 sdr->sockfd = dnssd_InvalidSocket; 612 sdr->validator = sdr->sockfd ^ ValidatorBits; 613 sdr->op = op; 614 sdr->max_index = 0; 615 sdr->logcounter = 0; 616 sdr->moreptr = NULL; 617 sdr->uid.u32[0] = 0; 618 sdr->uid.u32[1] = 0; 619 sdr->ProcessReply = ProcessReply; 620 sdr->AppCallback = AppCallback; 621 sdr->AppContext = AppContext; 622 623 if (flags & kDNSServiceFlagsShareConnection) 624 { 625 DNSServiceOp **p = &(*ref)->next; // Append ourselves to end of primary's list 626 while (*p) p = &(*p)->next; 627 *p = sdr; 628 // Preincrement counter before we use it -- it helps with debugging if we know the all-zeroes ID should never appear 629 if (++(*ref)->uid.u32[0] == 0) ++(*ref)->uid.u32[1]; // In parent DNSServiceOp increment UID counter 630 sdr->primary = *ref; // Set our primary pointer 631 sdr->sockfd = (*ref)->sockfd; // Inherit primary's socket 632 sdr->validator = (*ref)->validator; 633 sdr->uid = (*ref)->uid; 634 //printf("ConnectToServer sharing socket %d\n", sdr->sockfd); 635 } 636 else 637 { 638 #ifdef SO_NOSIGPIPE 639 const unsigned long optval = 1; 640 #endif 641 *ref = NULL; 642 sdr->sockfd = socket(AF_DNSSD, SOCK_STREAM, 0); 643 sdr->validator = sdr->sockfd ^ ValidatorBits; 644 if (!dnssd_SocketValid(sdr->sockfd)) 645 { 646 syslog(LOG_WARNING, "dnssd_clientstub ConnectToServer: socket failed %d %s", dnssd_errno, dnssd_strerror(dnssd_errno)); 647 FreeDNSServiceOp(sdr); 648 return kDNSServiceErr_NoMemory; 649 } 650 #ifdef SO_NOSIGPIPE 651 // Some environments (e.g. OS X) support turning off SIGPIPE for a socket 652 if (setsockopt(sdr->sockfd, SOL_SOCKET, SO_NOSIGPIPE, &optval, sizeof(optval)) < 0) 653 syslog(LOG_WARNING, "dnssd_clientstub ConnectToServer: SO_NOSIGPIPE failed %d %s", dnssd_errno, dnssd_strerror(dnssd_errno)); 654 #endif 655 #if defined(USE_TCP_LOOPBACK) 656 saddr.sin_family = AF_INET; 657 saddr.sin_addr.s_addr = inet_addr(MDNS_TCP_SERVERADDR); 658 saddr.sin_port = htons(MDNS_TCP_SERVERPORT); 659 #else 660 saddr.sun_family = AF_LOCAL; 661 strcpy(saddr.sun_path, MDNS_UDS_SERVERPATH); 662 #endif 663 664 while (1) 665 { 666 int err = connect(sdr->sockfd, (struct sockaddr *) &saddr, sizeof(saddr)); 667 if (!err) break; // If we succeeded, return sdr 668 // If we failed, then it may be because the daemon is still launching. 669 // This can happen for processes that launch early in the boot process, while the 670 // daemon is still coming up. Rather than fail here, we'll wait a bit and try again. 671 // If, after four seconds, we still can't connect to the daemon, 672 // then we give up and return a failure code. 673 if (++NumTries < DNSSD_CLIENT_MAXTRIES) sleep(1); // Sleep a bit, then try again 674 else { dnssd_close(sdr->sockfd); FreeDNSServiceOp(sdr); return kDNSServiceErr_ServiceNotRunning; } 675 } 676 //printf("ConnectToServer opened socket %d\n", sdr->sockfd); 677 } 678 679 *ref = sdr; 680 return kDNSServiceErr_NoError; 681 } 682 683 #define deliver_request_bailout(MSG) \ 684 do { syslog(LOG_WARNING, "dnssd_clientstub deliver_request: %s failed %d (%s)", (MSG), dnssd_errno, dnssd_strerror(dnssd_errno)); goto cleanup; } while(0) 685 686 static DNSServiceErrorType deliver_request(ipc_msg_hdr *hdr, DNSServiceOp *sdr) 687 { 688 uint32_t datalen = hdr->datalen; // We take a copy here because we're going to convert hdr->datalen to network byte order 689 #if defined(USE_TCP_LOOPBACK) || defined(USE_NAMED_ERROR_RETURN_SOCKET) 690 char *const data = (char *)hdr + sizeof(ipc_msg_hdr); 691 #endif 692 dnssd_sock_t listenfd = dnssd_InvalidSocket, errsd = dnssd_InvalidSocket; 693 DNSServiceErrorType err = kDNSServiceErr_Unknown; // Default for the "goto cleanup" cases 694 int MakeSeparateReturnSocket = 0; 695 696 // Note: need to check hdr->op, not sdr->op. 697 // hdr->op contains the code for the specific operation we're currently doing, whereas sdr->op 698 // contains the original parent DNSServiceOp (e.g. for an add_record_request, hdr->op will be 699 // add_record_request but the parent sdr->op will be connection_request or reg_service_request) 700 if (sdr->primary || 701 hdr->op == reg_record_request || hdr->op == add_record_request || hdr->op == update_record_request || hdr->op == remove_record_request) 702 MakeSeparateReturnSocket = 1; 703 704 if (!DNSServiceRefValid(sdr)) 705 { 706 syslog(LOG_WARNING, "dnssd_clientstub deliver_request: invalid DNSServiceRef %p %08X %08X", sdr, sdr->sockfd, sdr->validator); 707 return kDNSServiceErr_BadReference; 708 } 709 710 if (!hdr) { syslog(LOG_WARNING, "dnssd_clientstub deliver_request: !hdr"); return kDNSServiceErr_Unknown; } 711 712 if (MakeSeparateReturnSocket) 713 { 714 #if defined(USE_TCP_LOOPBACK) 715 { 716 union { uint16_t s; u_char b[2]; } port; 717 dnssd_sockaddr_t caddr; 718 dnssd_socklen_t len = (dnssd_socklen_t) sizeof(caddr); 719 listenfd = socket(AF_DNSSD, SOCK_STREAM, 0); 720 if (!dnssd_SocketValid(listenfd)) deliver_request_bailout("TCP socket"); 721 722 caddr.sin_family = AF_INET; 723 caddr.sin_port = 0; 724 caddr.sin_addr.s_addr = inet_addr(MDNS_TCP_SERVERADDR); 725 if (bind(listenfd, (struct sockaddr*) &caddr, sizeof(caddr)) < 0) deliver_request_bailout("TCP bind"); 726 if (getsockname(listenfd, (struct sockaddr*) &caddr, &len) < 0) deliver_request_bailout("TCP getsockname"); 727 if (listen(listenfd, 1) < 0) deliver_request_bailout("TCP listen"); 728 port.s = caddr.sin_port; 729 data[0] = port.b[0]; // don't switch the byte order, as the 730 data[1] = port.b[1]; // daemon expects it in network byte order 731 } 732 #elif defined(USE_NAMED_ERROR_RETURN_SOCKET) 733 { 734 mode_t mask; 735 int bindresult; 736 dnssd_sockaddr_t caddr; 737 listenfd = socket(AF_DNSSD, SOCK_STREAM, 0); 738 if (!dnssd_SocketValid(listenfd)) deliver_request_bailout("USE_NAMED_ERROR_RETURN_SOCKET socket"); 739 740 caddr.sun_family = AF_LOCAL; 741 // According to Stevens (section 3.2), there is no portable way to 742 // determine whether sa_len is defined on a particular platform. 743 #ifndef NOT_HAVE_SA_LEN 744 caddr.sun_len = sizeof(struct sockaddr_un); 745 #endif 746 strcpy(caddr.sun_path, data); 747 mask = umask(0); 748 bindresult = bind(listenfd, (struct sockaddr *)&caddr, sizeof(caddr)); 749 umask(mask); 750 if (bindresult < 0) deliver_request_bailout("USE_NAMED_ERROR_RETURN_SOCKET bind"); 751 if (listen(listenfd, 1) < 0) deliver_request_bailout("USE_NAMED_ERROR_RETURN_SOCKET listen"); 752 } 753 #else 754 { 755 dnssd_sock_t sp[2]; 756 if (socketpair(AF_DNSSD, SOCK_STREAM, 0, sp) < 0) deliver_request_bailout("socketpair"); 757 else 758 { 759 errsd = sp[0]; // We'll read our four-byte error code from sp[0] 760 listenfd = sp[1]; // We'll send sp[1] to the daemon 761 } 762 } 763 #endif 764 } 765 766 #if !defined(USE_TCP_LOOPBACK) && !defined(USE_NAMED_ERROR_RETURN_SOCKET) 767 // If we're going to make a separate error return socket, and pass it to the daemon 768 // using sendmsg, then we'll hold back one data byte to go with it. 769 // On some versions of Unix (including Leopard) sending a control message without 770 // any associated data does not work reliably -- e.g. one particular issue we ran 771 // into is that if the receiving program is in a kqueue loop waiting to be notified 772 // of the received message, it doesn't get woken up when the control message arrives. 773 if (MakeSeparateReturnSocket || sdr->op == send_bpf) datalen--; // Okay to use sdr->op when checking for op == send_bpf 774 #endif 775 776 // At this point, our listening socket is set up and waiting, if necessary, for the daemon to connect back to 777 ConvertHeaderBytes(hdr); 778 //syslog(LOG_WARNING, "dnssd_clientstub deliver_request writing %lu bytes", (unsigned long)(datalen + sizeof(ipc_msg_hdr))); 779 //if (MakeSeparateReturnSocket) syslog(LOG_WARNING, "dnssd_clientstub deliver_request name is %s", data); 780 #if TEST_SENDING_ONE_BYTE_AT_A_TIME 781 unsigned int i; 782 for (i=0; i<datalen + sizeof(ipc_msg_hdr); i++) 783 { 784 syslog(LOG_WARNING, "dnssd_clientstub deliver_request writing %d", i); 785 if (write_all(sdr->sockfd, ((char *)hdr)+i, 1) < 0) 786 { syslog(LOG_WARNING, "write_all (byte %u) failed", i); goto cleanup; } 787 usleep(10000); 788 } 789 #else 790 if (write_all(sdr->sockfd, (char *)hdr, datalen + sizeof(ipc_msg_hdr)) < 0) 791 { 792 syslog(LOG_WARNING, "dnssd_clientstub deliver_request ERROR: write_all(%d, %lu bytes) failed", 793 sdr->sockfd, (unsigned long)(datalen + sizeof(ipc_msg_hdr))); 794 goto cleanup; 795 } 796 #endif 797 798 if (!MakeSeparateReturnSocket) errsd = sdr->sockfd; 799 if (MakeSeparateReturnSocket || sdr->op == send_bpf) // Okay to use sdr->op when checking for op == send_bpf 800 { 801 #if defined(USE_TCP_LOOPBACK) || defined(USE_NAMED_ERROR_RETURN_SOCKET) 802 // At this point we may block in accept for a few milliseconds waiting for the daemon to connect back to us, 803 // but that's okay -- the daemon is a trusted service and we know if won't take more than a few milliseconds to respond. 804 dnssd_sockaddr_t daddr; 805 dnssd_socklen_t len = sizeof(daddr); 806 errsd = accept(listenfd, (struct sockaddr *)&daddr, &len); 807 if (!dnssd_SocketValid(errsd)) deliver_request_bailout("accept"); 808 #else 809 810 #if APPLE_OSX_mDNSResponder 811 // On Leopard, the stock definitions of the CMSG_* macros in /usr/include/sys/socket.h, 812 // while arguably correct in theory, nonetheless in practice produce code that doesn't work on 64-bit machines 813 // For details see <rdar://problem/5565787> Bonjour API broken for 64-bit apps (SCM_RIGHTS sendmsg fails) 814 #undef CMSG_DATA 815 #define CMSG_DATA(cmsg) ((unsigned char *)(cmsg) + (sizeof(struct cmsghdr))) 816 #undef CMSG_SPACE 817 #define CMSG_SPACE(l) ((sizeof(struct cmsghdr)) + (l)) 818 #undef CMSG_LEN 819 #define CMSG_LEN(l) ((sizeof(struct cmsghdr)) + (l)) 820 #endif 821 822 struct iovec vec = { ((char *)hdr) + sizeof(ipc_msg_hdr) + datalen, 1 }; // Send the last byte along with the SCM_RIGHTS 823 struct msghdr msg; 824 struct cmsghdr *cmsg; 825 char cbuf[CMSG_SPACE(sizeof(dnssd_sock_t))]; 826 827 if (sdr->op == send_bpf) // Okay to use sdr->op when checking for op == send_bpf 828 { 829 int i; 830 char p[12]; // Room for "/dev/bpf999" with terminating null 831 for (i=0; i<100; i++) 832 { 833 snprintf(p, sizeof(p), "/dev/bpf%d", i); 834 listenfd = open(p, O_RDWR, 0); 835 //if (dnssd_SocketValid(listenfd)) syslog(LOG_WARNING, "Sending fd %d for %s", listenfd, p); 836 if (!dnssd_SocketValid(listenfd) && dnssd_errno != EBUSY) 837 syslog(LOG_WARNING, "Error opening %s %d (%s)", p, dnssd_errno, dnssd_strerror(dnssd_errno)); 838 if (dnssd_SocketValid(listenfd) || dnssd_errno != EBUSY) break; 839 } 840 } 841 842 msg.msg_name = 0; 843 msg.msg_namelen = 0; 844 msg.msg_iov = &vec; 845 msg.msg_iovlen = 1; 846 msg.msg_control = cbuf; 847 msg.msg_controllen = CMSG_LEN(sizeof(dnssd_sock_t)); 848 msg.msg_flags = 0; 849 cmsg = CMSG_FIRSTHDR(&msg); 850 cmsg->cmsg_len = CMSG_LEN(sizeof(dnssd_sock_t)); 851 cmsg->cmsg_level = SOL_SOCKET; 852 cmsg->cmsg_type = SCM_RIGHTS; 853 *((dnssd_sock_t *)CMSG_DATA(cmsg)) = listenfd; 854 855 #if TEST_KQUEUE_CONTROL_MESSAGE_BUG 856 sleep(1); 857 #endif 858 859 #if DEBUG_64BIT_SCM_RIGHTS 860 syslog(LOG_WARNING, "dnssd_clientstub sendmsg read sd=%d write sd=%d %ld %ld %ld/%ld/%ld/%ld", 861 errsd, listenfd, sizeof(dnssd_sock_t), sizeof(void*), 862 sizeof(struct cmsghdr) + sizeof(dnssd_sock_t), 863 CMSG_LEN(sizeof(dnssd_sock_t)), (long)CMSG_SPACE(sizeof(dnssd_sock_t)), 864 (long)((char*)CMSG_DATA(cmsg) + 4 - cbuf)); 865 #endif // DEBUG_64BIT_SCM_RIGHTS 866 867 if (sendmsg(sdr->sockfd, &msg, 0) < 0) 868 { 869 syslog(LOG_WARNING, "dnssd_clientstub deliver_request ERROR: sendmsg failed read sd=%d write sd=%d errno %d (%s)", 870 errsd, listenfd, dnssd_errno, dnssd_strerror(dnssd_errno)); 871 err = kDNSServiceErr_Incompatible; 872 goto cleanup; 873 } 874 875 #if DEBUG_64BIT_SCM_RIGHTS 876 syslog(LOG_WARNING, "dnssd_clientstub sendmsg read sd=%d write sd=%d okay", errsd, listenfd); 877 #endif // DEBUG_64BIT_SCM_RIGHTS 878 879 #endif 880 // Close our end of the socketpair *before* blocking in read_all to get the four-byte error code. 881 // Otherwise, if the daemon closes our socket (or crashes), we block in read_all() forever 882 // because the socket is not closed (we still have an open reference to it ourselves). 883 dnssd_close(listenfd); 884 listenfd = dnssd_InvalidSocket; // Make sure we don't close it a second time in the cleanup handling below 885 } 886 887 // At this point we may block in read_all for a few milliseconds waiting for the daemon to send us the error code, 888 // but that's okay -- the daemon is a trusted service and we know if won't take more than a few milliseconds to respond. 889 if (sdr->op == send_bpf) // Okay to use sdr->op when checking for op == send_bpf 890 err = kDNSServiceErr_NoError; 891 else if (read_all(errsd, (char*)&err, (int)sizeof(err)) < 0) 892 err = kDNSServiceErr_ServiceNotRunning; // On failure read_all will have written a message to syslog for us 893 else 894 err = ntohl(err); 895 896 //syslog(LOG_WARNING, "dnssd_clientstub deliver_request: retrieved error code %d", err); 897 898 cleanup: 899 if (MakeSeparateReturnSocket) 900 { 901 if (dnssd_SocketValid(listenfd)) dnssd_close(listenfd); 902 if (dnssd_SocketValid(errsd)) dnssd_close(errsd); 903 #if defined(USE_NAMED_ERROR_RETURN_SOCKET) 904 // syslog(LOG_WARNING, "dnssd_clientstub deliver_request: removing UDS: %s", data); 905 if (unlink(data) != 0) 906 syslog(LOG_WARNING, "dnssd_clientstub WARNING: unlink(\"%s\") failed errno %d (%s)", data, dnssd_errno, dnssd_strerror(dnssd_errno)); 907 // else syslog(LOG_WARNING, "dnssd_clientstub deliver_request: removed UDS: %s", data); 908 #endif 909 } 910 911 free(hdr); 912 return err; 913 } 914 915 int DNSSD_API DNSServiceRefSockFD(DNSServiceRef sdRef) 916 { 917 if (!sdRef) { syslog(LOG_WARNING, "dnssd_clientstub DNSServiceRefSockFD called with NULL DNSServiceRef"); return dnssd_InvalidSocket; } 918 919 if (!DNSServiceRefValid(sdRef)) 920 { 921 syslog(LOG_WARNING, "dnssd_clientstub DNSServiceRefSockFD called with invalid DNSServiceRef %p %08X %08X", 922 sdRef, sdRef->sockfd, sdRef->validator); 923 return dnssd_InvalidSocket; 924 } 925 926 if (sdRef->primary) 927 { 928 syslog(LOG_WARNING, "dnssd_clientstub DNSServiceRefSockFD undefined for kDNSServiceFlagsShareConnection subordinate DNSServiceRef %p", sdRef); 929 return dnssd_InvalidSocket; 930 } 931 932 return (int) sdRef->sockfd; 933 } 934 935 // Handle reply from server, calling application client callback. If there is no reply 936 // from the daemon on the socket contained in sdRef, the call will block. 937 DNSServiceErrorType DNSSD_API DNSServiceProcessResult(DNSServiceRef sdRef) 938 { 939 int morebytes = 0; 940 941 if (!sdRef) { syslog(LOG_WARNING, "dnssd_clientstub DNSServiceProcessResult called with NULL DNSServiceRef"); return kDNSServiceErr_BadParam; } 942 943 if (!DNSServiceRefValid(sdRef)) 944 { 945 syslog(LOG_WARNING, "dnssd_clientstub DNSServiceProcessResult called with invalid DNSServiceRef %p %08X %08X", sdRef, sdRef->sockfd, sdRef->validator); 946 return kDNSServiceErr_BadReference; 947 } 948 949 if (sdRef->primary) 950 { 951 syslog(LOG_WARNING, "dnssd_clientstub DNSServiceProcessResult undefined for kDNSServiceFlagsShareConnection subordinate DNSServiceRef %p", sdRef); 952 return kDNSServiceErr_BadReference; 953 } 954 955 if (!sdRef->ProcessReply) 956 { 957 static int num_logs = 0; 958 if (num_logs < 10) syslog(LOG_WARNING, "dnssd_clientstub DNSServiceProcessResult called with DNSServiceRef with no ProcessReply function"); 959 if (num_logs < 1000) num_logs++; else sleep(1); 960 return kDNSServiceErr_BadReference; 961 } 962 963 do 964 { 965 CallbackHeader cbh; 966 char *data; 967 968 // return NoError on EWOULDBLOCK. This will handle the case 969 // where a non-blocking socket is told there is data, but it was a false positive. 970 // On error, read_all will write a message to syslog for us, so don't need to duplicate that here 971 // Note: If we want to properly support using non-blocking sockets in the future 972 int result = read_all(sdRef->sockfd, (void *)&cbh.ipc_hdr, sizeof(cbh.ipc_hdr)); 973 if (result == read_all_fail) 974 { 975 sdRef->ProcessReply = NULL; 976 return kDNSServiceErr_ServiceNotRunning; 977 } 978 else if (result == read_all_wouldblock) 979 { 980 if (morebytes && sdRef->logcounter < 100) 981 { 982 sdRef->logcounter++; 983 syslog(LOG_WARNING, "dnssd_clientstub DNSServiceProcessResult error: select indicated data was waiting but read_all returned EWOULDBLOCK"); 984 } 985 return kDNSServiceErr_NoError; 986 } 987 988 ConvertHeaderBytes(&cbh.ipc_hdr); 989 if (cbh.ipc_hdr.version != VERSION) 990 { 991 syslog(LOG_WARNING, "dnssd_clientstub DNSServiceProcessResult daemon version %d does not match client version %d", cbh.ipc_hdr.version, VERSION); 992 sdRef->ProcessReply = NULL; 993 return kDNSServiceErr_Incompatible; 994 } 995 996 data = malloc(cbh.ipc_hdr.datalen); 997 if (!data) return kDNSServiceErr_NoMemory; 998 if (read_all(sdRef->sockfd, data, cbh.ipc_hdr.datalen) < 0) // On error, read_all will write a message to syslog for us 999 { 1000 free(data); 1001 sdRef->ProcessReply = NULL; 1002 return kDNSServiceErr_ServiceNotRunning; 1003 } 1004 else 1005 { 1006 const char *ptr = data; 1007 cbh.cb_flags = get_flags (&ptr, data + cbh.ipc_hdr.datalen); 1008 cbh.cb_interface = get_uint32 (&ptr, data + cbh.ipc_hdr.datalen); 1009 cbh.cb_err = get_error_code(&ptr, data + cbh.ipc_hdr.datalen); 1010 1011 // CAUTION: We have to handle the case where the client calls DNSServiceRefDeallocate from within the callback function. 1012 // To do this we set moreptr to point to morebytes. If the client does call DNSServiceRefDeallocate(), 1013 // then that routine will clear morebytes for us, and cause us to exit our loop. 1014 morebytes = more_bytes(sdRef->sockfd); 1015 if (morebytes) 1016 { 1017 cbh.cb_flags |= kDNSServiceFlagsMoreComing; 1018 sdRef->moreptr = &morebytes; 1019 } 1020 if (ptr) sdRef->ProcessReply(sdRef, &cbh, ptr, data + cbh.ipc_hdr.datalen); 1021 // Careful code here: 1022 // If morebytes is non-zero, that means we set sdRef->moreptr above, and the operation was not 1023 // cancelled out from under us, so now we need to clear sdRef->moreptr so we don't leave a stray 1024 // dangling pointer pointing to a long-gone stack variable. 1025 // If morebytes is zero, then one of two thing happened: 1026 // (a) morebytes was 0 above, so we didn't set sdRef->moreptr, so we don't need to clear it 1027 // (b) morebytes was 1 above, and we set sdRef->moreptr, but the operation was cancelled (with DNSServiceRefDeallocate()), 1028 // so we MUST NOT try to dereference our stale sdRef pointer. 1029 if (morebytes) sdRef->moreptr = NULL; 1030 } 1031 free(data); 1032 } while (morebytes); 1033 1034 return kDNSServiceErr_NoError; 1035 } 1036 1037 void DNSSD_API DNSServiceRefDeallocate(DNSServiceRef sdRef) 1038 { 1039 if (!sdRef) { syslog(LOG_WARNING, "dnssd_clientstub DNSServiceRefDeallocate called with NULL DNSServiceRef"); return; } 1040 1041 if (!DNSServiceRefValid(sdRef)) // Also verifies dnssd_SocketValid(sdRef->sockfd) for us too 1042 { 1043 syslog(LOG_WARNING, "dnssd_clientstub DNSServiceRefDeallocate called with invalid DNSServiceRef %p %08X %08X", sdRef, sdRef->sockfd, sdRef->validator); 1044 return; 1045 } 1046 1047 // If we're in the middle of a DNSServiceProcessResult() invocation for this DNSServiceRef, clear its morebytes flag to break it out of its while loop 1048 if (sdRef->moreptr) *(sdRef->moreptr) = 0; 1049 1050 if (sdRef->primary) // If this is a subordinate DNSServiceOp, just send a 'stop' command 1051 { 1052 DNSServiceOp **p = &sdRef->primary->next; 1053 while (*p && *p != sdRef) p = &(*p)->next; 1054 if (*p) 1055 { 1056 char *ptr; 1057 size_t len = 0; 1058 ipc_msg_hdr *hdr = create_hdr(cancel_request, &len, &ptr, 0, sdRef); 1059 ConvertHeaderBytes(hdr); 1060 write_all(sdRef->sockfd, (char *)hdr, len); 1061 free(hdr); 1062 *p = sdRef->next; 1063 FreeDNSServiceOp(sdRef); 1064 } 1065 } 1066 else // else, make sure to terminate all subordinates as well 1067 { 1068 dnssd_close(sdRef->sockfd); 1069 while (sdRef) 1070 { 1071 DNSServiceOp *p = sdRef; 1072 sdRef = sdRef->next; 1073 FreeDNSServiceOp(p); 1074 } 1075 } 1076 } 1077 1078 DNSServiceErrorType DNSSD_API DNSServiceGetProperty(const char *property, void *result, uint32_t *size) 1079 { 1080 char *ptr; 1081 size_t len = strlen(property) + 1; 1082 ipc_msg_hdr *hdr; 1083 DNSServiceOp *tmp; 1084 uint32_t actualsize; 1085 1086 DNSServiceErrorType err = ConnectToServer(&tmp, 0, getproperty_request, NULL, NULL, NULL); 1087 if (err) return err; 1088 1089 hdr = create_hdr(getproperty_request, &len, &ptr, 0, tmp); 1090 if (!hdr) { DNSServiceRefDeallocate(tmp); return kDNSServiceErr_NoMemory; } 1091 1092 put_string(property, &ptr); 1093 err = deliver_request(hdr, tmp); // Will free hdr for us 1094 if (read_all(tmp->sockfd, (char*)&actualsize, (int)sizeof(actualsize)) < 0) 1095 { DNSServiceRefDeallocate(tmp); return kDNSServiceErr_ServiceNotRunning; } 1096 1097 actualsize = ntohl(actualsize); 1098 if (read_all(tmp->sockfd, (char*)result, actualsize < *size ? actualsize : *size) < 0) 1099 { DNSServiceRefDeallocate(tmp); return kDNSServiceErr_ServiceNotRunning; } 1100 DNSServiceRefDeallocate(tmp); 1101 1102 // Swap version result back to local process byte order 1103 if (!strcmp(property, kDNSServiceProperty_DaemonVersion) && *size >= 4) 1104 *(uint32_t*)result = ntohl(*(uint32_t*)result); 1105 1106 *size = actualsize; 1107 return kDNSServiceErr_NoError; 1108 } 1109 1110 static void handle_resolve_response(DNSServiceOp *const sdr, const CallbackHeader *const cbh, const char *data, const char *end) 1111 { 1112 char fullname[kDNSServiceMaxDomainName]; 1113 char target[kDNSServiceMaxDomainName]; 1114 uint16_t txtlen; 1115 union { uint16_t s; u_char b[2]; } port; 1116 unsigned char *txtrecord; 1117 1118 get_string(&data, end, fullname, kDNSServiceMaxDomainName); 1119 get_string(&data, end, target, kDNSServiceMaxDomainName); 1120 if (!data || data + 2 > end) data = NULL; 1121 else 1122 { 1123 port.b[0] = *data++; 1124 port.b[1] = *data++; 1125 } 1126 txtlen = get_uint16(&data, end); 1127 txtrecord = (unsigned char *)get_rdata(&data, end, txtlen); 1128 1129 if (!data) syslog(LOG_WARNING, "dnssd_clientstub handle_resolve_response: error reading result from daemon"); 1130 else ((DNSServiceResolveReply)sdr->AppCallback)(sdr, cbh->cb_flags, cbh->cb_interface, cbh->cb_err, fullname, target, port.s, txtlen, txtrecord, sdr->AppContext); 1131 // MUST NOT touch sdr after invoking AppCallback -- client is allowed to dispose it from within callback function 1132 } 1133 1134 DNSServiceErrorType DNSSD_API DNSServiceResolve 1135 ( 1136 DNSServiceRef *sdRef, 1137 DNSServiceFlags flags, 1138 uint32_t interfaceIndex, 1139 const char *name, 1140 const char *regtype, 1141 const char *domain, 1142 DNSServiceResolveReply callBack, 1143 void *context 1144 ) 1145 { 1146 char *ptr; 1147 size_t len; 1148 ipc_msg_hdr *hdr; 1149 DNSServiceErrorType err; 1150 1151 if (!name || !regtype || !domain || !callBack) return kDNSServiceErr_BadParam; 1152 1153 err = ConnectToServer(sdRef, flags, resolve_request, handle_resolve_response, callBack, context); 1154 if (err) return err; // On error ConnectToServer leaves *sdRef set to NULL 1155 1156 // Calculate total message length 1157 len = sizeof(flags); 1158 len += sizeof(interfaceIndex); 1159 len += strlen(name) + 1; 1160 len += strlen(regtype) + 1; 1161 len += strlen(domain) + 1; 1162 1163 hdr = create_hdr(resolve_request, &len, &ptr, (*sdRef)->primary ? 1 : 0, *sdRef); 1164 if (!hdr) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; return kDNSServiceErr_NoMemory; } 1165 1166 put_flags(flags, &ptr); 1167 put_uint32(interfaceIndex, &ptr); 1168 put_string(name, &ptr); 1169 put_string(regtype, &ptr); 1170 put_string(domain, &ptr); 1171 1172 err = deliver_request(hdr, *sdRef); // Will free hdr for us 1173 if (err) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; } 1174 return err; 1175 } 1176 1177 static void handle_query_response(DNSServiceOp *const sdr, const CallbackHeader *const cbh, const char *data, const char *const end) 1178 { 1179 uint32_t ttl; 1180 char name[kDNSServiceMaxDomainName]; 1181 uint16_t rrtype, rrclass, rdlen; 1182 const char *rdata; 1183 1184 get_string(&data, end, name, kDNSServiceMaxDomainName); 1185 rrtype = get_uint16(&data, end); 1186 rrclass = get_uint16(&data, end); 1187 rdlen = get_uint16(&data, end); 1188 rdata = get_rdata(&data, end, rdlen); 1189 ttl = get_uint32(&data, end); 1190 1191 if (!data) syslog(LOG_WARNING, "dnssd_clientstub handle_query_response: error reading result from daemon"); 1192 else ((DNSServiceQueryRecordReply)sdr->AppCallback)(sdr, cbh->cb_flags, cbh->cb_interface, cbh->cb_err, name, rrtype, rrclass, rdlen, rdata, ttl, sdr->AppContext); 1193 // MUST NOT touch sdr after invoking AppCallback -- client is allowed to dispose it from within callback function 1194 } 1195 1196 DNSServiceErrorType DNSSD_API DNSServiceQueryRecord 1197 ( 1198 DNSServiceRef *sdRef, 1199 DNSServiceFlags flags, 1200 uint32_t interfaceIndex, 1201 const char *name, 1202 uint16_t rrtype, 1203 uint16_t rrclass, 1204 DNSServiceQueryRecordReply callBack, 1205 void *context 1206 ) 1207 { 1208 char *ptr; 1209 size_t len; 1210 ipc_msg_hdr *hdr; 1211 DNSServiceErrorType err = ConnectToServer(sdRef, flags, query_request, handle_query_response, callBack, context); 1212 if (err) return err; // On error ConnectToServer leaves *sdRef set to NULL 1213 1214 if (!name) name = "\0"; 1215 1216 // Calculate total message length 1217 len = sizeof(flags); 1218 len += sizeof(uint32_t); // interfaceIndex 1219 len += strlen(name) + 1; 1220 len += 2 * sizeof(uint16_t); // rrtype, rrclass 1221 1222 hdr = create_hdr(query_request, &len, &ptr, (*sdRef)->primary ? 1 : 0, *sdRef); 1223 if (!hdr) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; return kDNSServiceErr_NoMemory; } 1224 1225 put_flags(flags, &ptr); 1226 put_uint32(interfaceIndex, &ptr); 1227 put_string(name, &ptr); 1228 put_uint16(rrtype, &ptr); 1229 put_uint16(rrclass, &ptr); 1230 1231 err = deliver_request(hdr, *sdRef); // Will free hdr for us 1232 if (err) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; } 1233 return err; 1234 } 1235 1236 static void handle_addrinfo_response(DNSServiceOp *const sdr, const CallbackHeader *const cbh, const char *data, const char *const end) 1237 { 1238 char hostname[kDNSServiceMaxDomainName]; 1239 uint16_t rrtype, rrclass, rdlen; 1240 const char *rdata; 1241 uint32_t ttl; 1242 1243 get_string(&data, end, hostname, kDNSServiceMaxDomainName); 1244 rrtype = get_uint16(&data, end); 1245 rrclass = get_uint16(&data, end); 1246 rdlen = get_uint16(&data, end); 1247 rdata = get_rdata (&data, end, rdlen); 1248 ttl = get_uint32(&data, end); 1249 1250 // We only generate client callbacks for A and AAAA results (including NXDOMAIN results for 1251 // those types, if the client has requested those with the kDNSServiceFlagsReturnIntermediates). 1252 // Other result types, specifically CNAME referrals, are not communicated to the client, because 1253 // the DNSServiceGetAddrInfoReply interface doesn't have any meaningful way to communiate CNAME referrals. 1254 if (!data) syslog(LOG_WARNING, "dnssd_clientstub handle_addrinfo_response: error reading result from daemon"); 1255 else if (rrtype == kDNSServiceType_A || rrtype == kDNSServiceType_AAAA) 1256 { 1257 struct sockaddr_in sa4; 1258 struct sockaddr_in6 sa6; 1259 const struct sockaddr *const sa = (rrtype == kDNSServiceType_A) ? (struct sockaddr*)&sa4 : (struct sockaddr*)&sa6; 1260 if (rrtype == kDNSServiceType_A) 1261 { 1262 memset(&sa4, 0, sizeof(sa4)); 1263 #ifndef NOT_HAVE_SA_LEN 1264 sa4.sin_len = sizeof(struct sockaddr_in); 1265 #endif 1266 sa4.sin_family = AF_INET; 1267 // sin_port = 0; 1268 if (!cbh->cb_err) memcpy(&sa4.sin_addr, rdata, rdlen); 1269 } 1270 else 1271 { 1272 memset(&sa6, 0, sizeof(sa6)); 1273 #ifndef NOT_HAVE_SA_LEN 1274 sa6.sin6_len = sizeof(struct sockaddr_in6); 1275 #endif 1276 sa6.sin6_family = AF_INET6; 1277 // sin6_port = 0; 1278 // sin6_flowinfo = 0; 1279 // sin6_scope_id = 0; 1280 if (!cbh->cb_err) 1281 { 1282 memcpy(&sa6.sin6_addr, rdata, rdlen); 1283 if (IN6_IS_ADDR_LINKLOCAL(&sa6.sin6_addr)) sa6.sin6_scope_id = cbh->cb_interface; 1284 } 1285 } 1286 ((DNSServiceGetAddrInfoReply)sdr->AppCallback)(sdr, cbh->cb_flags, cbh->cb_interface, cbh->cb_err, hostname, sa, ttl, sdr->AppContext); 1287 // MUST NOT touch sdr after invoking AppCallback -- client is allowed to dispose it from within callback function 1288 } 1289 } 1290 1291 DNSServiceErrorType DNSSD_API DNSServiceGetAddrInfo 1292 ( 1293 DNSServiceRef *sdRef, 1294 DNSServiceFlags flags, 1295 uint32_t interfaceIndex, 1296 uint32_t protocol, 1297 const char *hostname, 1298 DNSServiceGetAddrInfoReply callBack, 1299 void *context /* may be NULL */ 1300 ) 1301 { 1302 char *ptr; 1303 size_t len; 1304 ipc_msg_hdr *hdr; 1305 DNSServiceErrorType err; 1306 1307 if (!hostname) return kDNSServiceErr_BadParam; 1308 1309 err = ConnectToServer(sdRef, flags, addrinfo_request, handle_addrinfo_response, callBack, context); 1310 if (err) return err; // On error ConnectToServer leaves *sdRef set to NULL 1311 1312 // Calculate total message length 1313 len = sizeof(flags); 1314 len += sizeof(uint32_t); // interfaceIndex 1315 len += sizeof(uint32_t); // protocol 1316 len += strlen(hostname) + 1; 1317 1318 hdr = create_hdr(addrinfo_request, &len, &ptr, (*sdRef)->primary ? 1 : 0, *sdRef); 1319 if (!hdr) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; return kDNSServiceErr_NoMemory; } 1320 1321 put_flags(flags, &ptr); 1322 put_uint32(interfaceIndex, &ptr); 1323 put_uint32(protocol, &ptr); 1324 put_string(hostname, &ptr); 1325 1326 err = deliver_request(hdr, *sdRef); // Will free hdr for us 1327 if (err) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; } 1328 return err; 1329 } 1330 1331 static void handle_browse_response(DNSServiceOp *const sdr, const CallbackHeader *const cbh, const char *data, const char *const end) 1332 { 1333 char replyName[256], replyType[kDNSServiceMaxDomainName], replyDomain[kDNSServiceMaxDomainName]; 1334 get_string(&data, end, replyName, 256); 1335 get_string(&data, end, replyType, kDNSServiceMaxDomainName); 1336 get_string(&data, end, replyDomain, kDNSServiceMaxDomainName); 1337 if (!data) syslog(LOG_WARNING, "dnssd_clientstub handle_browse_response: error reading result from daemon"); 1338 else ((DNSServiceBrowseReply)sdr->AppCallback)(sdr, cbh->cb_flags, cbh->cb_interface, cbh->cb_err, replyName, replyType, replyDomain, sdr->AppContext); 1339 // MUST NOT touch sdr after invoking AppCallback -- client is allowed to dispose it from within callback function 1340 } 1341 1342 DNSServiceErrorType DNSSD_API DNSServiceBrowse 1343 ( 1344 DNSServiceRef *sdRef, 1345 DNSServiceFlags flags, 1346 uint32_t interfaceIndex, 1347 const char *regtype, 1348 const char *domain, 1349 DNSServiceBrowseReply callBack, 1350 void *context 1351 ) 1352 { 1353 char *ptr; 1354 size_t len; 1355 ipc_msg_hdr *hdr; 1356 DNSServiceErrorType err = ConnectToServer(sdRef, flags, browse_request, handle_browse_response, callBack, context); 1357 if (err) return err; // On error ConnectToServer leaves *sdRef set to NULL 1358 1359 if (!domain) domain = ""; 1360 len = sizeof(flags); 1361 len += sizeof(interfaceIndex); 1362 len += strlen(regtype) + 1; 1363 len += strlen(domain) + 1; 1364 1365 hdr = create_hdr(browse_request, &len, &ptr, (*sdRef)->primary ? 1 : 0, *sdRef); 1366 if (!hdr) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; return kDNSServiceErr_NoMemory; } 1367 1368 put_flags(flags, &ptr); 1369 put_uint32(interfaceIndex, &ptr); 1370 put_string(regtype, &ptr); 1371 put_string(domain, &ptr); 1372 1373 err = deliver_request(hdr, *sdRef); // Will free hdr for us 1374 if (err) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; } 1375 return err; 1376 } 1377 1378 DNSServiceErrorType DNSSD_API DNSServiceSetDefaultDomainForUser(DNSServiceFlags flags, const char *domain) 1379 { 1380 DNSServiceOp *tmp; 1381 char *ptr; 1382 size_t len = sizeof(flags) + strlen(domain) + 1; 1383 ipc_msg_hdr *hdr; 1384 DNSServiceErrorType err = ConnectToServer(&tmp, 0, setdomain_request, NULL, NULL, NULL); 1385 if (err) return err; 1386 1387 hdr = create_hdr(setdomain_request, &len, &ptr, 0, tmp); 1388 if (!hdr) { DNSServiceRefDeallocate(tmp); return kDNSServiceErr_NoMemory; } 1389 1390 put_flags(flags, &ptr); 1391 put_string(domain, &ptr); 1392 err = deliver_request(hdr, tmp); // Will free hdr for us 1393 DNSServiceRefDeallocate(tmp); 1394 return err; 1395 } 1396 1397 static void handle_regservice_response(DNSServiceOp *const sdr, const CallbackHeader *const cbh, const char *data, const char *const end) 1398 { 1399 char name[256], regtype[kDNSServiceMaxDomainName], domain[kDNSServiceMaxDomainName]; 1400 get_string(&data, end, name, 256); 1401 get_string(&data, end, regtype, kDNSServiceMaxDomainName); 1402 get_string(&data, end, domain, kDNSServiceMaxDomainName); 1403 if (!data) syslog(LOG_WARNING, "dnssd_clientstub handle_regservice_response: error reading result from daemon"); 1404 else ((DNSServiceRegisterReply)sdr->AppCallback)(sdr, cbh->cb_flags, cbh->cb_err, name, regtype, domain, sdr->AppContext); 1405 // MUST NOT touch sdr after invoking AppCallback -- client is allowed to dispose it from within callback function 1406 } 1407 1408 DNSServiceErrorType DNSSD_API DNSServiceRegister 1409 ( 1410 DNSServiceRef *sdRef, 1411 DNSServiceFlags flags, 1412 uint32_t interfaceIndex, 1413 const char *name, 1414 const char *regtype, 1415 const char *domain, 1416 const char *host, 1417 uint16_t PortInNetworkByteOrder, 1418 uint16_t txtLen, 1419 const void *txtRecord, 1420 DNSServiceRegisterReply callBack, 1421 void *context 1422 ) 1423 { 1424 char *ptr; 1425 size_t len; 1426 ipc_msg_hdr *hdr; 1427 DNSServiceErrorType err; 1428 union { uint16_t s; u_char b[2]; } port = { PortInNetworkByteOrder }; 1429 1430 if (!name) name = ""; 1431 if (!regtype) return kDNSServiceErr_BadParam; 1432 if (!domain) domain = ""; 1433 if (!host) host = ""; 1434 if (!txtRecord) txtRecord = (void*)""; 1435 1436 // No callback must have auto-rename 1437 if (!callBack && (flags & kDNSServiceFlagsNoAutoRename)) return kDNSServiceErr_BadParam; 1438 1439 err = ConnectToServer(sdRef, flags, reg_service_request, callBack ? handle_regservice_response : NULL, callBack, context); 1440 if (err) return err; // On error ConnectToServer leaves *sdRef set to NULL 1441 1442 len = sizeof(DNSServiceFlags); 1443 len += sizeof(uint32_t); // interfaceIndex 1444 len += strlen(name) + strlen(regtype) + strlen(domain) + strlen(host) + 4; 1445 len += 2 * sizeof(uint16_t); // port, txtLen 1446 len += txtLen; 1447 1448 hdr = create_hdr(reg_service_request, &len, &ptr, (*sdRef)->primary ? 1 : 0, *sdRef); 1449 if (!hdr) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; return kDNSServiceErr_NoMemory; } 1450 if (!callBack) hdr->ipc_flags |= IPC_FLAGS_NOREPLY; 1451 1452 put_flags(flags, &ptr); 1453 put_uint32(interfaceIndex, &ptr); 1454 put_string(name, &ptr); 1455 put_string(regtype, &ptr); 1456 put_string(domain, &ptr); 1457 put_string(host, &ptr); 1458 *ptr++ = port.b[0]; 1459 *ptr++ = port.b[1]; 1460 put_uint16(txtLen, &ptr); 1461 put_rdata(txtLen, txtRecord, &ptr); 1462 1463 err = deliver_request(hdr, *sdRef); // Will free hdr for us 1464 if (err) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; } 1465 return err; 1466 } 1467 1468 static void handle_enumeration_response(DNSServiceOp *const sdr, const CallbackHeader *const cbh, const char *data, const char *const end) 1469 { 1470 char domain[kDNSServiceMaxDomainName]; 1471 get_string(&data, end, domain, kDNSServiceMaxDomainName); 1472 if (!data) syslog(LOG_WARNING, "dnssd_clientstub handle_enumeration_response: error reading result from daemon"); 1473 else ((DNSServiceDomainEnumReply)sdr->AppCallback)(sdr, cbh->cb_flags, cbh->cb_interface, cbh->cb_err, domain, sdr->AppContext); 1474 // MUST NOT touch sdr after invoking AppCallback -- client is allowed to dispose it from within callback function 1475 } 1476 1477 DNSServiceErrorType DNSSD_API DNSServiceEnumerateDomains 1478 ( 1479 DNSServiceRef *sdRef, 1480 DNSServiceFlags flags, 1481 uint32_t interfaceIndex, 1482 DNSServiceDomainEnumReply callBack, 1483 void *context 1484 ) 1485 { 1486 char *ptr; 1487 size_t len; 1488 ipc_msg_hdr *hdr; 1489 DNSServiceErrorType err; 1490 1491 int f1 = (flags & kDNSServiceFlagsBrowseDomains) != 0; 1492 int f2 = (flags & kDNSServiceFlagsRegistrationDomains) != 0; 1493 if (f1 + f2 != 1) return kDNSServiceErr_BadParam; 1494 1495 err = ConnectToServer(sdRef, flags, enumeration_request, handle_enumeration_response, callBack, context); 1496 if (err) return err; // On error ConnectToServer leaves *sdRef set to NULL 1497 1498 len = sizeof(DNSServiceFlags); 1499 len += sizeof(uint32_t); 1500 1501 hdr = create_hdr(enumeration_request, &len, &ptr, (*sdRef)->primary ? 1 : 0, *sdRef); 1502 if (!hdr) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; return kDNSServiceErr_NoMemory; } 1503 1504 put_flags(flags, &ptr); 1505 put_uint32(interfaceIndex, &ptr); 1506 1507 err = deliver_request(hdr, *sdRef); // Will free hdr for us 1508 if (err) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; } 1509 return err; 1510 } 1511 1512 static void ConnectionResponse(DNSServiceOp *const sdr, const CallbackHeader *const cbh, const char *const data, const char *const end) 1513 { 1514 DNSRecordRef rref = cbh->ipc_hdr.client_context.context; 1515 (void)data; // Unused 1516 1517 //printf("ConnectionResponse got %d\n", cbh->ipc_hdr.op); 1518 if (cbh->ipc_hdr.op != reg_record_reply_op) 1519 { 1520 // When using kDNSServiceFlagsShareConnection, need to search the list of associated DNSServiceOps 1521 // to find the one this response is intended for, and then call through to its ProcessReply handler. 1522 // We start with our first subordinate DNSServiceRef -- don't want to accidentally match the parent DNSServiceRef. 1523 DNSServiceOp *op = sdr->next; 1524 while (op && (op->uid.u32[0] != cbh->ipc_hdr.client_context.u32[0] || op->uid.u32[1] != cbh->ipc_hdr.client_context.u32[1])) 1525 op = op->next; 1526 // Note: We may sometimes not find a matching DNSServiceOp, in the case where the client has 1527 // cancelled the subordinate DNSServiceOp, but there are still messages in the pipeline from the daemon 1528 if (op && op->ProcessReply) op->ProcessReply(op, cbh, data, end); 1529 // WARNING: Don't touch op or sdr after this -- client may have called DNSServiceRefDeallocate 1530 return; 1531 } 1532 1533 if (sdr->op == connection_request) 1534 rref->AppCallback(rref->sdr, rref, cbh->cb_flags, cbh->cb_err, rref->AppContext); 1535 else 1536 { 1537 syslog(LOG_WARNING, "dnssd_clientstub ConnectionResponse: sdr->op != connection_request"); 1538 rref->AppCallback(rref->sdr, rref, 0, kDNSServiceErr_Unknown, rref->AppContext); 1539 } 1540 // MUST NOT touch sdr after invoking AppCallback -- client is allowed to dispose it from within callback function 1541 } 1542 1543 DNSServiceErrorType DNSSD_API DNSServiceCreateConnection(DNSServiceRef *sdRef) 1544 { 1545 char *ptr; 1546 size_t len = 0; 1547 ipc_msg_hdr *hdr; 1548 DNSServiceErrorType err = ConnectToServer(sdRef, 0, connection_request, ConnectionResponse, NULL, NULL); 1549 if (err) return err; // On error ConnectToServer leaves *sdRef set to NULL 1550 1551 hdr = create_hdr(connection_request, &len, &ptr, 0, *sdRef); 1552 if (!hdr) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; return kDNSServiceErr_NoMemory; } 1553 1554 err = deliver_request(hdr, *sdRef); // Will free hdr for us 1555 if (err) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; } 1556 return err; 1557 } 1558 1559 DNSServiceErrorType DNSSD_API DNSServiceRegisterRecord 1560 ( 1561 DNSServiceRef sdRef, 1562 DNSRecordRef *RecordRef, 1563 DNSServiceFlags flags, 1564 uint32_t interfaceIndex, 1565 const char *fullname, 1566 uint16_t rrtype, 1567 uint16_t rrclass, 1568 uint16_t rdlen, 1569 const void *rdata, 1570 uint32_t ttl, 1571 DNSServiceRegisterRecordReply callBack, 1572 void *context 1573 ) 1574 { 1575 char *ptr; 1576 size_t len; 1577 ipc_msg_hdr *hdr = NULL; 1578 DNSRecordRef rref = NULL; 1579 int f1 = (flags & kDNSServiceFlagsShared) != 0; 1580 int f2 = (flags & kDNSServiceFlagsUnique) != 0; 1581 if (f1 + f2 != 1) return kDNSServiceErr_BadParam; 1582 1583 if (!sdRef) { syslog(LOG_WARNING, "dnssd_clientstub DNSServiceRegisterRecord called with NULL DNSServiceRef"); return kDNSServiceErr_BadParam; } 1584 1585 if (!DNSServiceRefValid(sdRef)) 1586 { 1587 syslog(LOG_WARNING, "dnssd_clientstub DNSServiceRegisterRecord called with invalid DNSServiceRef %p %08X %08X", sdRef, sdRef->sockfd, sdRef->validator); 1588 return kDNSServiceErr_BadReference; 1589 } 1590 1591 if (sdRef->op != connection_request) 1592 { 1593 syslog(LOG_WARNING, "dnssd_clientstub DNSServiceRegisterRecord called with non-DNSServiceCreateConnection DNSServiceRef %p %d", sdRef, sdRef->op); 1594 return kDNSServiceErr_BadReference; 1595 } 1596 1597 *RecordRef = NULL; 1598 1599 len = sizeof(DNSServiceFlags); 1600 len += 2 * sizeof(uint32_t); // interfaceIndex, ttl 1601 len += 3 * sizeof(uint16_t); // rrtype, rrclass, rdlen 1602 len += strlen(fullname) + 1; 1603 len += rdlen; 1604 1605 hdr = create_hdr(reg_record_request, &len, &ptr, 1, sdRef); 1606 if (!hdr) return kDNSServiceErr_NoMemory; 1607 1608 put_flags(flags, &ptr); 1609 put_uint32(interfaceIndex, &ptr); 1610 put_string(fullname, &ptr); 1611 put_uint16(rrtype, &ptr); 1612 put_uint16(rrclass, &ptr); 1613 put_uint16(rdlen, &ptr); 1614 put_rdata(rdlen, rdata, &ptr); 1615 put_uint32(ttl, &ptr); 1616 1617 rref = malloc(sizeof(DNSRecord)); 1618 if (!rref) { free(hdr); return kDNSServiceErr_NoMemory; } 1619 rref->AppContext = context; 1620 rref->AppCallback = callBack; 1621 rref->record_index = sdRef->max_index++; 1622 rref->sdr = sdRef; 1623 *RecordRef = rref; 1624 hdr->client_context.context = rref; 1625 hdr->reg_index = rref->record_index; 1626 1627 return deliver_request(hdr, sdRef); // Will free hdr for us 1628 } 1629 1630 // sdRef returned by DNSServiceRegister() 1631 DNSServiceErrorType DNSSD_API DNSServiceAddRecord 1632 ( 1633 DNSServiceRef sdRef, 1634 DNSRecordRef *RecordRef, 1635 DNSServiceFlags flags, 1636 uint16_t rrtype, 1637 uint16_t rdlen, 1638 const void *rdata, 1639 uint32_t ttl 1640 ) 1641 { 1642 ipc_msg_hdr *hdr; 1643 size_t len = 0; 1644 char *ptr; 1645 DNSRecordRef rref; 1646 1647 if (!sdRef) { syslog(LOG_WARNING, "dnssd_clientstub DNSServiceAddRecord called with NULL DNSServiceRef"); return kDNSServiceErr_BadParam; } 1648 if (!RecordRef) { syslog(LOG_WARNING, "dnssd_clientstub DNSServiceAddRecord called with NULL DNSRecordRef pointer"); return kDNSServiceErr_BadParam; } 1649 if (sdRef->op != reg_service_request) 1650 { 1651 syslog(LOG_WARNING, "dnssd_clientstub DNSServiceAddRecord called with non-DNSServiceRegister DNSServiceRef %p %d", sdRef, sdRef->op); 1652 return kDNSServiceErr_BadReference; 1653 } 1654 1655 if (!DNSServiceRefValid(sdRef)) 1656 { 1657 syslog(LOG_WARNING, "dnssd_clientstub DNSServiceAddRecord called with invalid DNSServiceRef %p %08X %08X", sdRef, sdRef->sockfd, sdRef->validator); 1658 return kDNSServiceErr_BadReference; 1659 } 1660 1661 *RecordRef = NULL; 1662 1663 len += 2 * sizeof(uint16_t); // rrtype, rdlen 1664 len += rdlen; 1665 len += sizeof(uint32_t); 1666 len += sizeof(DNSServiceFlags); 1667 1668 hdr = create_hdr(add_record_request, &len, &ptr, 1, sdRef); 1669 if (!hdr) return kDNSServiceErr_NoMemory; 1670 put_flags(flags, &ptr); 1671 put_uint16(rrtype, &ptr); 1672 put_uint16(rdlen, &ptr); 1673 put_rdata(rdlen, rdata, &ptr); 1674 put_uint32(ttl, &ptr); 1675 1676 rref = malloc(sizeof(DNSRecord)); 1677 if (!rref) { free(hdr); return kDNSServiceErr_NoMemory; } 1678 rref->AppContext = NULL; 1679 rref->AppCallback = NULL; 1680 rref->record_index = sdRef->max_index++; 1681 rref->sdr = sdRef; 1682 *RecordRef = rref; 1683 hdr->reg_index = rref->record_index; 1684 1685 return deliver_request(hdr, sdRef); // Will free hdr for us 1686 } 1687 1688 // DNSRecordRef returned by DNSServiceRegisterRecord or DNSServiceAddRecord 1689 DNSServiceErrorType DNSSD_API DNSServiceUpdateRecord 1690 ( 1691 DNSServiceRef sdRef, 1692 DNSRecordRef RecordRef, 1693 DNSServiceFlags flags, 1694 uint16_t rdlen, 1695 const void *rdata, 1696 uint32_t ttl 1697 ) 1698 { 1699 ipc_msg_hdr *hdr; 1700 size_t len = 0; 1701 char *ptr; 1702 1703 if (!sdRef) { syslog(LOG_WARNING, "dnssd_clientstub DNSServiceUpdateRecord called with NULL DNSServiceRef"); return kDNSServiceErr_BadParam; } 1704 1705 if (!DNSServiceRefValid(sdRef)) 1706 { 1707 syslog(LOG_WARNING, "dnssd_clientstub DNSServiceUpdateRecord called with invalid DNSServiceRef %p %08X %08X", sdRef, sdRef->sockfd, sdRef->validator); 1708 return kDNSServiceErr_BadReference; 1709 } 1710 1711 // Note: RecordRef is allowed to be NULL 1712 1713 len += sizeof(uint16_t); 1714 len += rdlen; 1715 len += sizeof(uint32_t); 1716 len += sizeof(DNSServiceFlags); 1717 1718 hdr = create_hdr(update_record_request, &len, &ptr, 1, sdRef); 1719 if (!hdr) return kDNSServiceErr_NoMemory; 1720 hdr->reg_index = RecordRef ? RecordRef->record_index : TXT_RECORD_INDEX; 1721 put_flags(flags, &ptr); 1722 put_uint16(rdlen, &ptr); 1723 put_rdata(rdlen, rdata, &ptr); 1724 put_uint32(ttl, &ptr); 1725 return deliver_request(hdr, sdRef); // Will free hdr for us 1726 } 1727 1728 DNSServiceErrorType DNSSD_API DNSServiceRemoveRecord 1729 ( 1730 DNSServiceRef sdRef, 1731 DNSRecordRef RecordRef, 1732 DNSServiceFlags flags 1733 ) 1734 { 1735 ipc_msg_hdr *hdr; 1736 size_t len = 0; 1737 char *ptr; 1738 DNSServiceErrorType err; 1739 1740 if (!sdRef) { syslog(LOG_WARNING, "dnssd_clientstub DNSServiceRemoveRecord called with NULL DNSServiceRef"); return kDNSServiceErr_BadParam; } 1741 if (!RecordRef) { syslog(LOG_WARNING, "dnssd_clientstub DNSServiceRemoveRecord called with NULL DNSRecordRef"); return kDNSServiceErr_BadParam; } 1742 if (!sdRef->max_index) { syslog(LOG_WARNING, "dnssd_clientstub DNSServiceRemoveRecord called with bad DNSServiceRef"); return kDNSServiceErr_BadReference; } 1743 1744 if (!DNSServiceRefValid(sdRef)) 1745 { 1746 syslog(LOG_WARNING, "dnssd_clientstub DNSServiceRemoveRecord called with invalid DNSServiceRef %p %08X %08X", sdRef, sdRef->sockfd, sdRef->validator); 1747 return kDNSServiceErr_BadReference; 1748 } 1749 1750 len += sizeof(flags); 1751 hdr = create_hdr(remove_record_request, &len, &ptr, 1, sdRef); 1752 if (!hdr) return kDNSServiceErr_NoMemory; 1753 hdr->reg_index = RecordRef->record_index; 1754 put_flags(flags, &ptr); 1755 err = deliver_request(hdr, sdRef); // Will free hdr for us 1756 if (!err) free(RecordRef); 1757 return err; 1758 } 1759 1760 DNSServiceErrorType DNSSD_API DNSServiceReconfirmRecord 1761 ( 1762 DNSServiceFlags flags, 1763 uint32_t interfaceIndex, 1764 const char *fullname, 1765 uint16_t rrtype, 1766 uint16_t rrclass, 1767 uint16_t rdlen, 1768 const void *rdata 1769 ) 1770 { 1771 char *ptr; 1772 size_t len; 1773 ipc_msg_hdr *hdr; 1774 DNSServiceOp *tmp; 1775 1776 DNSServiceErrorType err = ConnectToServer(&tmp, flags, reconfirm_record_request, NULL, NULL, NULL); 1777 if (err) return err; 1778 1779 len = sizeof(DNSServiceFlags); 1780 len += sizeof(uint32_t); 1781 len += strlen(fullname) + 1; 1782 len += 3 * sizeof(uint16_t); 1783 len += rdlen; 1784 hdr = create_hdr(reconfirm_record_request, &len, &ptr, 0, tmp); 1785 if (!hdr) { DNSServiceRefDeallocate(tmp); return kDNSServiceErr_NoMemory; } 1786 1787 put_flags(flags, &ptr); 1788 put_uint32(interfaceIndex, &ptr); 1789 put_string(fullname, &ptr); 1790 put_uint16(rrtype, &ptr); 1791 put_uint16(rrclass, &ptr); 1792 put_uint16(rdlen, &ptr); 1793 put_rdata(rdlen, rdata, &ptr); 1794 1795 err = deliver_request(hdr, tmp); // Will free hdr for us 1796 DNSServiceRefDeallocate(tmp); 1797 return err; 1798 } 1799 1800 static void handle_port_mapping_response(DNSServiceOp *const sdr, const CallbackHeader *const cbh, const char *data, const char *const end) 1801 { 1802 union { uint32_t l; u_char b[4]; } addr; 1803 uint8_t protocol = 0; 1804 union { uint16_t s; u_char b[2]; } internalPort; 1805 union { uint16_t s; u_char b[2]; } externalPort; 1806 uint32_t ttl = 0; 1807 1808 if (!data || data + 13 > end) data = NULL; 1809 else 1810 { 1811 addr .b[0] = *data++; 1812 addr .b[1] = *data++; 1813 addr .b[2] = *data++; 1814 addr .b[3] = *data++; 1815 protocol = *data++; 1816 internalPort.b[0] = *data++; 1817 internalPort.b[1] = *data++; 1818 externalPort.b[0] = *data++; 1819 externalPort.b[1] = *data++; 1820 ttl = get_uint32(&data, end); 1821 } 1822 1823 if (!data) syslog(LOG_WARNING, "dnssd_clientstub handle_port_mapping_response: error reading result from daemon"); 1824 else ((DNSServiceNATPortMappingReply)sdr->AppCallback)(sdr, cbh->cb_flags, cbh->cb_interface, cbh->cb_err, addr.l, protocol, internalPort.s, externalPort.s, ttl, sdr->AppContext); 1825 // MUST NOT touch sdr after invoking AppCallback -- client is allowed to dispose it from within callback function 1826 } 1827 1828 DNSServiceErrorType DNSSD_API DNSServiceNATPortMappingCreate 1829 ( 1830 DNSServiceRef *sdRef, 1831 DNSServiceFlags flags, 1832 uint32_t interfaceIndex, 1833 uint32_t protocol, /* TCP and/or UDP */ 1834 uint16_t internalPortInNetworkByteOrder, 1835 uint16_t externalPortInNetworkByteOrder, 1836 uint32_t ttl, /* time to live in seconds */ 1837 DNSServiceNATPortMappingReply callBack, 1838 void *context /* may be NULL */ 1839 ) 1840 { 1841 char *ptr; 1842 size_t len; 1843 ipc_msg_hdr *hdr; 1844 union { uint16_t s; u_char b[2]; } internalPort = { internalPortInNetworkByteOrder }; 1845 union { uint16_t s; u_char b[2]; } externalPort = { externalPortInNetworkByteOrder }; 1846 1847 DNSServiceErrorType err = ConnectToServer(sdRef, flags, port_mapping_request, handle_port_mapping_response, callBack, context); 1848 if (err) return err; // On error ConnectToServer leaves *sdRef set to NULL 1849 1850 len = sizeof(flags); 1851 len += sizeof(interfaceIndex); 1852 len += sizeof(protocol); 1853 len += sizeof(internalPort); 1854 len += sizeof(externalPort); 1855 len += sizeof(ttl); 1856 1857 hdr = create_hdr(port_mapping_request, &len, &ptr, (*sdRef)->primary ? 1 : 0, *sdRef); 1858 if (!hdr) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; return kDNSServiceErr_NoMemory; } 1859 1860 put_flags(flags, &ptr); 1861 put_uint32(interfaceIndex, &ptr); 1862 put_uint32(protocol, &ptr); 1863 *ptr++ = internalPort.b[0]; 1864 *ptr++ = internalPort.b[1]; 1865 *ptr++ = externalPort.b[0]; 1866 *ptr++ = externalPort.b[1]; 1867 put_uint32(ttl, &ptr); 1868 1869 err = deliver_request(hdr, *sdRef); // Will free hdr for us 1870 if (err) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; } 1871 return err; 1872 } 1873