1 /* -*- Mode: C; tab-width: 4 -*- 2 * 3 * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved. 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 * 17 * Formatting notes: 18 * This code follows the "Whitesmiths style" C indentation rules. Plenty of discussion 19 * on C indentation can be found on the web, such as <http://www.kafejo.com/komp/1tbs.htm>, 20 * but for the sake of brevity here I will say just this: Curly braces are not syntactially 21 * part of an "if" statement; they are the beginning and ending markers of a compound statement; 22 * therefore common sense dictates that if they are part of a compound statement then they 23 * should be indented to the same level as everything else in that compound statement. 24 * Indenting curly braces at the same level as the "if" implies that curly braces are 25 * part of the "if", which is false. (This is as misleading as people who write "char* x,y;" 26 * thinking that variables x and y are both of type "char*" -- and anyone who doesn't 27 * understand why variable y is not of type "char*" just proves the point that poor code 28 * layout leads people to unfortunate misunderstandings about how the C language really works.) 29 30 Change History (most recent first): 31 32 $Log: mDNSPosix.c,v $ 33 Revision 1.78.2.1 2006/08/29 06:24:34 cheshire 34 Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0 35 36 Revision 1.78 2006/06/28 09:12:22 cheshire 37 Added debugging message 38 39 Revision 1.77 2006/03/19 02:00:11 cheshire 40 <rdar://problem/4073825> Improve logic for delaying packets after repeated interface transitions 41 42 Revision 1.76 2006/01/09 19:29:16 cheshire 43 <rdar://problem/4403128> Cap number of "sendto failed" messages we allow mDNSResponder to log 44 45 Revision 1.75 2006/01/05 22:04:57 cheshire 46 <rdar://problem/4399479> Log error message when send fails with "operation not permitted" 47 48 Revision 1.74 2006/01/05 21:45:27 cheshire 49 <rdar://problem/4400118> Fix uninitialized structure member in IPv6 code 50 51 Revision 1.73 2005/10/11 21:31:46 cheshire 52 <rdar://problem/4296177> Don't depend on IP_RECVTTL succeeding (not available on all platforms) 53 54 Revision 1.72 2005/09/08 20:45:26 cheshire 55 Default dot-local host name should be "Computer" not "Macintosh", 56 since the machine this is running on is most likely NOT a Mac. 57 58 Revision 1.71 2005/02/26 01:29:12 cheshire 59 Ignore multicasts accidentally delivered to our unicast receiving socket 60 61 Revision 1.70 2005/02/04 00:39:59 cheshire 62 Move ParseDNSServers() from PosixDaemon.c to mDNSPosix.c so all Posix client layers can use it 63 64 Revision 1.69 2004/12/18 02:03:28 cheshire 65 Need to #include "dns_sd.h" 66 67 Revision 1.68 2004/12/18 00:51:52 cheshire 68 Use symbolic constant kDNSServiceInterfaceIndexLocalOnly instead of (mDNSu32) ~0 69 70 Revision 1.67 2004/12/17 23:37:48 cheshire 71 <rdar://problem/3485365> Guard against repeating wireless dissociation/re-association 72 (and other repetitive configuration changes) 73 74 Revision 1.66 2004/12/01 04:27:28 cheshire 75 <rdar://problem/3872803> Darwin patches for Solaris and Suse 76 Don't use uint32_t, etc. -- they require stdint.h, which doesn't exist on FreeBSD 4.x, Solaris, etc. 77 78 Revision 1.65 2004/11/30 22:37:01 cheshire 79 Update copyright dates and add "Mode: C; tab-width: 4" headers 80 81 Revision 1.64 2004/11/23 03:39:47 cheshire 82 Let interface name/index mapping capability live directly in JNISupport.c, 83 instead of having to call through to the daemon via IPC to get this information. 84 85 Revision 1.63 2004/11/12 03:16:43 rpantos 86 rdar://problem/3809541 Add mDNSPlatformGetInterfaceByName, mDNSPlatformGetInterfaceName 87 88 Revision 1.62 2004/10/28 03:24:42 cheshire 89 Rename m->CanReceiveUnicastOn as m->CanReceiveUnicastOn5353 90 91 Revision 1.61 2004/10/16 00:17:01 cheshire 92 <rdar://problem/3770558> Replace IP TTL 255 check with local subnet source address check 93 94 Revision 1.60 2004/09/26 23:20:36 ksekar 95 <rdar://problem/3813108> Allow default registrations in multiple wide-area domains 96 97 Revision 1.59 2004/09/21 21:02:55 cheshire 98 Set up ifname before calling mDNS_RegisterInterface() 99 100 Revision 1.58 2004/09/17 01:08:54 cheshire 101 Renamed mDNSClientAPI.h to mDNSEmbeddedAPI.h 102 The name "mDNSClientAPI.h" is misleading to new developers looking at this code. The interfaces 103 declared in that file are ONLY appropriate to single-address-space embedded applications. 104 For clients on general-purpose computers, the interfaces defined in dns_sd.h should be used. 105 106 Revision 1.57 2004/09/17 00:19:11 cheshire 107 For consistency with AllDNSLinkGroupv6, rename AllDNSLinkGroup to AllDNSLinkGroupv4 108 109 Revision 1.56 2004/09/17 00:15:56 cheshire 110 Rename mDNSPlatformInit_ReceiveUnicast to mDNSPlatformInit_CanReceiveUnicast 111 112 Revision 1.55 2004/09/16 00:24:49 cheshire 113 <rdar://problem/3803162> Fix unsafe use of mDNSPlatformTimeNow() 114 115 Revision 1.54 2004/09/15 23:55:00 ksekar 116 <rdar://problem/3800597> mDNSPosix should #include stdint.h 117 118 Revision 1.53 2004/09/14 23:42:36 cheshire 119 <rdar://problem/3801296> Need to seed random number generator from platform-layer data 120 121 Revision 1.52 2004/08/25 16:42:13 ksekar 122 Fix Posix build - change mDNS_SetFQDNs to mDNS_SetFQDN, remove unicast 123 hostname parameter. 124 125 Revision 1.51 2004/08/14 03:22:42 cheshire 126 <rdar://problem/3762579> Dynamic DNS UI <-> mDNSResponder glue 127 Add GetUserSpecifiedDDNSName() routine 128 Convert ServiceRegDomain to domainname instead of C string 129 Replace mDNS_GenerateFQDN/mDNS_GenerateGlobalFQDN with mDNS_SetFQDNs 130 131 Revision 1.50 2004/08/11 01:20:20 cheshire 132 Declare private local functions using "mDNSlocal" 133 134 Revision 1.49 2004/07/26 22:49:31 ksekar 135 <rdar://problem/3651409>: Feature #9516: Need support for NATPMP in client 136 137 Revision 1.48 2004/07/20 01:47:36 rpantos 138 NOT_HAVE_SA_LEN applies to v6, too. And use more-portable s6_addr. 139 140 Revision 1.47 2004/06/25 00:26:27 rpantos 141 Changes to fix the Posix build on Solaris. 142 143 Revision 1.46 2004/05/13 04:54:20 ksekar 144 Unified list copy/free code. Added symetric list for 145 146 Revision 1.45 2004/05/12 22:03:09 ksekar 147 Made GetSearchDomainList a true platform-layer call (declaration moved 148 from mDNSMacOSX.h to mDNSEmbeddedAPI.h), impelemted to return "local" 149 only on non-OSX platforms. Changed call to return a copy of the list 150 to avoid shared memory issues. Added a routine to free the list. 151 152 Revision 1.44 2004/04/21 02:49:11 cheshire 153 To reduce future confusion, renamed 'TxAndRx' to 'McastTxRx' 154 155 Revision 1.43 2004/04/14 23:09:29 ksekar 156 Support for TSIG signed dynamic updates. 157 158 Revision 1.42 2004/04/09 17:43:04 cheshire 159 Make sure to set the McastTxRx field so that duplicate suppression works correctly 160 161 Revision 1.41 2004/02/06 01:19:51 cheshire 162 Conditionally exclude IPv6 code unless HAVE_IPV6 is set 163 164 Revision 1.40 2004/02/05 01:00:01 rpantos 165 Fix some issues that turned up when building for FreeBSD. 166 167 Revision 1.39 2004/01/28 21:12:15 cheshire 168 Reconcile mDNSIPv6Support & HAVE_IPV6 into a single flag (HAVE_IPV6) 169 170 Revision 1.38 2004/01/27 20:15:23 cheshire 171 <rdar://problem/3541288>: Time to prune obsolete code for listening on port 53 172 173 Revision 1.37 2004/01/24 05:12:03 cheshire 174 <rdar://problem/3534352>: Need separate socket for issuing unicast queries 175 176 Revision 1.36 2004/01/24 04:59:16 cheshire 177 Fixes so that Posix/Linux, OS9, Windows, and VxWorks targets build again 178 179 Revision 1.35 2004/01/23 21:37:08 cheshire 180 For consistency, rename multicastSocket to multicastSocket4, and multicastSocketv6 to multicastSocket6 181 182 Revision 1.34 2004/01/22 03:43:09 cheshire 183 Export constants like mDNSInterface_LocalOnly so that the client layers can use them 184 185 Revision 1.33 2004/01/21 21:54:20 cheshire 186 <rdar://problem/3448144>: Don't try to receive unicast responses if we're not the first to bind to the UDP port 187 188 Revision 1.32 2004/01/20 01:49:28 rpantos 189 Tweak error handling of last checkin a bit. 190 191 Revision 1.31 2004/01/20 01:39:27 rpantos 192 Respond to If changes by rebuilding interface list. 193 194 Revision 1.30 2003/12/11 19:40:36 cheshire 195 Fix 'destAddr.type == senderAddr.type;' that should have said 'destAddr.type = senderAddr.type;' 196 197 Revision 1.29 2003/12/11 18:53:22 cheshire 198 Fix compiler warning reported by Paul Guyot 199 200 Revision 1.28 2003/12/11 03:03:51 rpantos 201 Clean up mDNSPosix so that it builds on OS X again. 202 203 Revision 1.27 2003/12/08 20:47:02 rpantos 204 Add support for mDNSResponder on Linux. 205 206 Revision 1.26 2003/11/14 20:59:09 cheshire 207 Clients can't use AssignDomainName macro because mDNSPlatformMemCopy is defined in mDNSPlatformFunctions.h. 208 Best solution is just to combine mDNSEmbeddedAPI.h and mDNSPlatformFunctions.h into a single file. 209 210 Revision 1.25 2003/10/30 19:25:49 cheshire 211 Fix signed/unsigned warning on certain compilers 212 213 Revision 1.24 2003/08/18 23:12:23 cheshire 214 <rdar://problem/3382647> mDNSResponder divide by zero in mDNSPlatformRawTime() 215 216 Revision 1.23 2003/08/12 19:56:26 cheshire 217 Update to APSL 2.0 218 219 Revision 1.22 2003/08/06 18:46:15 cheshire 220 LogMsg() errors are serious -- always report them to stderr, regardless of debugging level 221 222 Revision 1.21 2003/08/06 18:20:51 cheshire 223 Makefile cleanup 224 225 Revision 1.20 2003/08/05 23:56:26 cheshire 226 Update code to compile with the new mDNSCoreReceive() function that requires a TTL 227 (Right now mDNSPosix.c just reports 255 -- we should fix this) 228 229 Revision 1.19 2003/07/19 03:15:16 cheshire 230 Add generic MemAllocate/MemFree prototypes to mDNSPlatformFunctions.h, 231 and add the obvious trivial implementations to each platform support layer 232 233 Revision 1.18 2003/07/14 18:11:54 cheshire 234 Fix stricter compiler warnings 235 236 Revision 1.17 2003/07/13 01:08:38 cheshire 237 There's not much point running mDNS over a point-to-point link; exclude those 238 239 Revision 1.16 2003/07/02 21:19:59 cheshire 240 <rdar://problem/3313413> Update copyright notices, etc., in source code comments 241 242 Revision 1.15 2003/06/18 05:48:41 cheshire 243 Fix warnings 244 245 Revision 1.14 2003/05/26 03:21:30 cheshire 246 Tidy up address structure naming: 247 mDNSIPAddr => mDNSv4Addr (for consistency with mDNSv6Addr) 248 mDNSAddr.addr.ipv4 => mDNSAddr.ip.v4 249 mDNSAddr.addr.ipv6 => mDNSAddr.ip.v6 250 251 Revision 1.13 2003/05/26 03:01:28 cheshire 252 <rdar://problem/3268904> sprintf/vsprintf-style functions are unsafe; use snprintf/vsnprintf instead 253 254 Revision 1.12 2003/05/21 03:49:18 cheshire 255 Fix warning 256 257 Revision 1.11 2003/05/06 00:00:50 cheshire 258 <rdar://problem/3248914> Rationalize naming of domainname manipulation functions 259 260 Revision 1.10 2003/04/25 01:45:57 cheshire 261 <rdar://problem/3240002> mDNS_RegisterNoSuchService needs to include a host name 262 263 Revision 1.9 2003/03/20 21:10:31 cheshire 264 Fixes done at IETF 56 to make mDNSProxyResponderPosix run on Solaris 265 266 Revision 1.8 2003/03/15 04:40:38 cheshire 267 Change type called "mDNSOpaqueID" to the more descriptive name "mDNSInterfaceID" 268 269 Revision 1.7 2003/03/13 03:46:21 cheshire 270 Fixes to make the code build on Linux 271 272 Revision 1.6 2003/03/08 00:35:56 cheshire 273 Switched to using new "mDNS_Execute" model (see "mDNSCore/Implementer Notes.txt") 274 275 Revision 1.5 2002/12/23 22:13:31 jgraessl 276 Reviewed by: Stuart Cheshire 277 Initial IPv6 support for mDNSResponder. 278 279 Revision 1.4 2002/09/27 01:47:45 cheshire 280 Workaround for Linux 2.0 systems that don't have IP_PKTINFO 281 282 Revision 1.3 2002/09/21 20:44:53 zarzycki 283 Added APSL info 284 285 Revision 1.2 2002/09/19 21:25:36 cheshire 286 mDNS_snprintf() doesn't need to be in a separate file 287 288 Revision 1.1 2002/09/17 06:24:34 cheshire 289 First checkin 290 */ 291 292 #pragma ident "%Z%%M% %I% %E% SMI" 293 294 #include "mDNSEmbeddedAPI.h" // Defines the interface provided to the client layer above 295 #include "mDNSPosix.h" // Defines the specific types needed to run mDNS on this platform 296 #include "dns_sd.h" 297 298 #include <assert.h> 299 #include <stdio.h> 300 #include <stdlib.h> 301 #include <errno.h> 302 #include <string.h> 303 #include <unistd.h> 304 #include <syslog.h> 305 #include <stdarg.h> 306 #include <fcntl.h> 307 #include <sys/types.h> 308 #include <sys/time.h> 309 #include <sys/socket.h> 310 #include <sys/uio.h> 311 #include <sys/select.h> 312 #include <netinet/in.h> 313 #include <arpa/inet.h> 314 #include <time.h> // platform support for UTC time 315 316 #if USES_NETLINK 317 #include <asm/types.h> 318 #include <linux/netlink.h> 319 #include <linux/rtnetlink.h> 320 #else // USES_NETLINK 321 #include <net/route.h> 322 #include <net/if.h> 323 #endif // USES_NETLINK 324 325 #include "mDNSUNP.h" 326 #include "GenLinkedList.h" 327 328 // *************************************************************************** 329 // Structures 330 331 // We keep a list of client-supplied event sources in PosixEventSource records 332 struct PosixEventSource 333 { 334 mDNSPosixEventCallback Callback; 335 void *Context; 336 int fd; 337 struct PosixEventSource *Next; 338 }; 339 typedef struct PosixEventSource PosixEventSource; 340 341 // Context record for interface change callback 342 struct IfChangeRec 343 { 344 int NotifySD; 345 mDNS* mDNS; 346 }; 347 typedef struct IfChangeRec IfChangeRec; 348 349 // Note that static data is initialized to zero in (modern) C. 350 static fd_set gEventFDs; 351 static int gMaxFD; // largest fd in gEventFDs 352 static GenLinkedList gEventSources; // linked list of PosixEventSource's 353 static sigset_t gEventSignalSet; // Signals which event loop listens for 354 static sigset_t gEventSignals; // Signals which were received while inside loop 355 356 // *************************************************************************** 357 // Globals (for debugging) 358 359 static int num_registered_interfaces = 0; 360 static int num_pkts_accepted = 0; 361 static int num_pkts_rejected = 0; 362 363 // *************************************************************************** 364 // Functions 365 366 int gMDNSPlatformPosixVerboseLevel = 0; 367 368 #define PosixErrorToStatus(errNum) ((errNum) == 0 ? mStatus_NoError : mStatus_UnknownErr) 369 370 mDNSlocal void SockAddrTomDNSAddr(const struct sockaddr *const sa, mDNSAddr *ipAddr, mDNSIPPort *ipPort) 371 { 372 switch (sa->sa_family) 373 { 374 case AF_INET: 375 { 376 struct sockaddr_in* sin = (struct sockaddr_in*)sa; 377 ipAddr->type = mDNSAddrType_IPv4; 378 ipAddr->ip.v4.NotAnInteger = sin->sin_addr.s_addr; 379 if (ipPort) ipPort->NotAnInteger = sin->sin_port; 380 break; 381 } 382 383 #if HAVE_IPV6 384 case AF_INET6: 385 { 386 struct sockaddr_in6* sin6 = (struct sockaddr_in6*)sa; 387 #ifndef NOT_HAVE_SA_LEN 388 assert(sin6->sin6_len == sizeof(*sin6)); 389 #endif 390 ipAddr->type = mDNSAddrType_IPv6; 391 ipAddr->ip.v6 = *(mDNSv6Addr*)&sin6->sin6_addr; 392 if (ipPort) ipPort->NotAnInteger = sin6->sin6_port; 393 break; 394 } 395 #endif 396 397 default: 398 verbosedebugf("SockAddrTomDNSAddr: Uknown address family %d\n", sa->sa_family); 399 ipAddr->type = mDNSAddrType_None; 400 if (ipPort) ipPort->NotAnInteger = 0; 401 break; 402 } 403 } 404 405 #if COMPILER_LIKES_PRAGMA_MARK 406 #pragma mark ***** Send and Receive 407 #endif 408 409 // mDNS core calls this routine when it needs to send a packet. 410 mDNSexport mStatus mDNSPlatformSendUDP(const mDNS *const m, const void *const msg, const mDNSu8 *const end, 411 mDNSInterfaceID InterfaceID, const mDNSAddr *dst, mDNSIPPort dstPort) 412 { 413 int err = 0; 414 struct sockaddr_storage to; 415 PosixNetworkInterface * thisIntf = (PosixNetworkInterface *)(InterfaceID); 416 int sendingsocket = -1; 417 418 assert(m != NULL); 419 assert(msg != NULL); 420 assert(end != NULL); 421 assert( (((char *) end) - ((char *) msg)) > 0 ); 422 assert(dstPort.NotAnInteger != 0); 423 424 if (dst->type == mDNSAddrType_IPv4) 425 { 426 struct sockaddr_in *sin = (struct sockaddr_in*)&to; 427 #ifndef NOT_HAVE_SA_LEN 428 sin->sin_len = sizeof(*sin); 429 #endif 430 sin->sin_family = AF_INET; 431 sin->sin_port = dstPort.NotAnInteger; 432 sin->sin_addr.s_addr = dst->ip.v4.NotAnInteger; 433 sendingsocket = thisIntf ? thisIntf->multicastSocket4 : m->p->unicastSocket4; 434 } 435 436 #if HAVE_IPV6 437 else if (dst->type == mDNSAddrType_IPv6) 438 { 439 struct sockaddr_in6 *sin6 = (struct sockaddr_in6*)&to; 440 mDNSPlatformMemZero(sin6, sizeof(*sin6)); 441 #ifndef NOT_HAVE_SA_LEN 442 sin6->sin6_len = sizeof(*sin6); 443 #endif 444 sin6->sin6_family = AF_INET6; 445 sin6->sin6_port = dstPort.NotAnInteger; 446 sin6->sin6_addr = *(struct in6_addr*)&dst->ip.v6; 447 sendingsocket = thisIntf ? thisIntf->multicastSocket6 : m->p->unicastSocket6; 448 } 449 #endif 450 451 if (sendingsocket >= 0) 452 err = sendto(sendingsocket, msg, (char*)end - (char*)msg, 0, (struct sockaddr *)&to, GET_SA_LEN(to)); 453 454 if (err > 0) err = 0; 455 else if (err < 0) 456 { 457 static int MessageCount = 0; 458 // Don't report EHOSTDOWN (i.e. ARP failure), ENETDOWN, or no route to host for unicast destinations 459 if (!mDNSAddressIsAllDNSLinkGroup(dst)) 460 if (errno == EHOSTDOWN || errno == ENETDOWN || errno == EHOSTUNREACH || errno == ENETUNREACH) return(mStatus_TransientErr); 461 462 if (MessageCount < 1000) 463 { 464 MessageCount++; 465 if (thisIntf) 466 LogMsg("mDNSPlatformSendUDP got error %d (%s) sending packet to %#a on interface %#a/%s/%d", 467 errno, strerror(errno), dst, &thisIntf->coreIntf.ip, thisIntf->intfName, thisIntf->index); 468 else 469 LogMsg("mDNSPlatformSendUDP got error %d (%s) sending packet to %#a", errno, strerror(errno), dst); 470 } 471 } 472 473 return PosixErrorToStatus(err); 474 } 475 476 // This routine is called when the main loop detects that data is available on a socket. 477 mDNSlocal void SocketDataReady(mDNS *const m, PosixNetworkInterface *intf, int skt) 478 { 479 mDNSAddr senderAddr, destAddr; 480 mDNSIPPort senderPort; 481 ssize_t packetLen; 482 DNSMessage packet; 483 struct my_in_pktinfo packetInfo; 484 struct sockaddr_storage from; 485 socklen_t fromLen; 486 int flags; 487 mDNSu8 ttl; 488 mDNSBool reject; 489 const mDNSInterfaceID InterfaceID = intf ? intf->coreIntf.InterfaceID : NULL; 490 491 assert(m != NULL); 492 assert(skt >= 0); 493 494 fromLen = sizeof(from); 495 flags = 0; 496 packetLen = recvfrom_flags(skt, &packet, sizeof(packet), &flags, (struct sockaddr *) &from, &fromLen, &packetInfo, &ttl); 497 498 if (packetLen >= 0) 499 { 500 SockAddrTomDNSAddr((struct sockaddr*)&from, &senderAddr, &senderPort); 501 SockAddrTomDNSAddr((struct sockaddr*)&packetInfo.ipi_addr, &destAddr, NULL); 502 503 // If we have broken IP_RECVDSTADDR functionality (so far 504 // I've only seen this on OpenBSD) then apply a hack to 505 // convince mDNS Core that this isn't a spoof packet. 506 // Basically what we do is check to see whether the 507 // packet arrived as a multicast and, if so, set its 508 // destAddr to the mDNS address. 509 // 510 // I must admit that I could just be doing something 511 // wrong on OpenBSD and hence triggering this problem 512 // but I'm at a loss as to how. 513 // 514 // If this platform doesn't have IP_PKTINFO or IP_RECVDSTADDR, then we have 515 // no way to tell the destination address or interface this packet arrived on, 516 // so all we can do is just assume it's a multicast 517 518 #if HAVE_BROKEN_RECVDSTADDR || (!defined(IP_PKTINFO) && !defined(IP_RECVDSTADDR)) 519 if ( (destAddr.NotAnInteger == 0) && (flags & MSG_MCAST) ) 520 { 521 destAddr.type = senderAddr.type; 522 if (senderAddr.type == mDNSAddrType_IPv4) destAddr.ip.v4 = AllDNSLinkGroupv4; 523 else if (senderAddr.type == mDNSAddrType_IPv6) destAddr.ip.v6 = AllDNSLinkGroupv6; 524 } 525 #endif 526 527 // We only accept the packet if the interface on which it came 528 // in matches the interface associated with this socket. 529 // We do this match by name or by index, depending on which 530 // information is available. recvfrom_flags sets the name 531 // to "" if the name isn't available, or the index to -1 532 // if the index is available. This accomodates the various 533 // different capabilities of our target platforms. 534 535 reject = mDNSfalse; 536 if (!intf) 537 { 538 // Ignore multicasts accidentally delivered to our unicast receiving socket 539 if (mDNSAddrIsDNSMulticast(&destAddr)) packetLen = -1; 540 } 541 else 542 { 543 if ( packetInfo.ipi_ifname[0] != 0 ) reject = (strcmp(packetInfo.ipi_ifname, intf->intfName) != 0); 544 else if ( packetInfo.ipi_ifindex != -1 ) reject = (packetInfo.ipi_ifindex != intf->index); 545 546 if (reject) 547 { 548 verbosedebugf("SocketDataReady ignored a packet from %#a to %#a on interface %s/%d expecting %#a/%s/%d/%d", 549 &senderAddr, &destAddr, packetInfo.ipi_ifname, packetInfo.ipi_ifindex, 550 &intf->coreIntf.ip, intf->intfName, intf->index, skt); 551 packetLen = -1; 552 num_pkts_rejected++; 553 if (num_pkts_rejected > (num_pkts_accepted + 1) * (num_registered_interfaces + 1) * 2) 554 { 555 fprintf(stderr, 556 "*** WARNING: Received %d packets; Accepted %d packets; Rejected %d packets because of interface mismatch\n", 557 num_pkts_accepted + num_pkts_rejected, num_pkts_accepted, num_pkts_rejected); 558 num_pkts_accepted = 0; 559 num_pkts_rejected = 0; 560 } 561 } 562 else 563 { 564 verbosedebugf("SocketDataReady got a packet from %#a to %#a on interface %#a/%s/%d/%d", 565 &senderAddr, &destAddr, &intf->coreIntf.ip, intf->intfName, intf->index, skt); 566 num_pkts_accepted++; 567 } 568 } 569 } 570 571 if (packetLen >= 0) 572 mDNSCoreReceive(m, &packet, (mDNSu8 *)&packet + packetLen, 573 &senderAddr, senderPort, &destAddr, MulticastDNSPort, InterfaceID); 574 } 575 576 mDNSexport mStatus mDNSPlatformTCPConnect(const mDNSAddr *dst, mDNSOpaque16 dstport, mDNSInterfaceID InterfaceID, 577 TCPConnectionCallback callback, void *context, int *descriptor) 578 { 579 (void)dst; // Unused 580 (void)dstport; // Unused 581 (void)InterfaceID; // Unused 582 (void)callback; // Unused 583 (void)context; // Unused 584 (void)descriptor; // Unused 585 return(mStatus_UnsupportedErr); 586 } 587 588 mDNSexport void mDNSPlatformTCPCloseConnection(int sd) 589 { 590 (void)sd; // Unused 591 } 592 593 mDNSexport int mDNSPlatformReadTCP(int sd, void *buf, int buflen) 594 { 595 (void)sd; // Unused 596 (void)buf; // Unused 597 (void)buflen; // Unused 598 return(0); 599 } 600 601 mDNSexport int mDNSPlatformWriteTCP(int sd, const char *msg, int len) 602 { 603 (void)sd; // Unused 604 (void)msg; // Unused 605 (void)len; // Unused 606 return(0); 607 } 608 609 #if COMPILER_LIKES_PRAGMA_MARK 610 #pragma mark ***** Get/Free Search Domain List 611 #endif 612 613 mDNSexport DNameListElem *mDNSPlatformGetSearchDomainList(void) 614 { 615 static DNameListElem tmp; 616 static mDNSBool init = mDNSfalse; 617 618 if (!init) 619 { 620 MakeDomainNameFromDNSNameString(&tmp.name, "local."); 621 tmp.next = NULL; 622 init = mDNStrue; 623 } 624 return mDNS_CopyDNameList(&tmp); 625 } 626 627 mDNSexport DNameListElem *mDNSPlatformGetRegDomainList(void) 628 { 629 return NULL; 630 } 631 632 #if COMPILER_LIKES_PRAGMA_MARK 633 #pragma mark ***** Init and Term 634 #endif 635 636 // This gets the current hostname, truncating it at the first dot if necessary 637 mDNSlocal void GetUserSpecifiedRFC1034ComputerName(domainlabel *const namelabel) 638 { 639 int len = 0; 640 gethostname((char *)(&namelabel->c[1]), MAX_DOMAIN_LABEL); 641 while (len < MAX_DOMAIN_LABEL && namelabel->c[len+1] && namelabel->c[len+1] != '.') len++; 642 namelabel->c[0] = len; 643 } 644 645 // On OS X this gets the text of the field labelled "Computer Name" in the Sharing Prefs Control Panel 646 // Other platforms can either get the information from the appropriate place, 647 // or they can alternatively just require all registering services to provide an explicit name 648 mDNSlocal void GetUserSpecifiedFriendlyComputerName(domainlabel *const namelabel) 649 { 650 // On Unix we have no better name than the host name, so we just use that. 651 GetUserSpecifiedRFC1034ComputerName( namelabel); 652 } 653 654 mDNSexport int ParseDNSServers(mDNS *m, const char *filePath) 655 { 656 char line[256]; 657 char nameserver[16]; 658 char keyword[10]; 659 int numOfServers = 0; 660 FILE *fp = fopen(filePath, "r"); 661 if (fp == NULL) return -1; 662 while (fgets(line,sizeof(line),fp)) 663 { 664 struct in_addr ina; 665 line[255]='\0'; // just to be safe 666 if (sscanf(line,"%10s %15s", keyword, nameserver) != 2) continue; // it will skip whitespaces 667 if (strncmp(keyword,"nameserver",10)) continue; 668 if (inet_aton(nameserver, (struct in_addr *)&ina) != 0) 669 { 670 mDNSAddr DNSAddr; 671 DNSAddr.type = mDNSAddrType_IPv4; 672 DNSAddr.ip.v4.NotAnInteger = ina.s_addr; 673 mDNS_AddDNSServer(m, &DNSAddr, NULL); 674 numOfServers++; 675 } 676 } 677 fclose(fp); 678 return (numOfServers > 0) ? 0 : -1; 679 } 680 681 // Searches the interface list looking for the named interface. 682 // Returns a pointer to if it found, or NULL otherwise. 683 mDNSlocal PosixNetworkInterface *SearchForInterfaceByName(mDNS *const m, const char *intfName) 684 { 685 PosixNetworkInterface *intf; 686 687 assert(m != NULL); 688 assert(intfName != NULL); 689 690 intf = (PosixNetworkInterface*)(m->HostInterfaces); 691 while ( (intf != NULL) && (strcmp(intf->intfName, intfName) != 0) ) 692 intf = (PosixNetworkInterface *)(intf->coreIntf.next); 693 694 return intf; 695 } 696 697 mDNSexport mDNSInterfaceID mDNSPlatformInterfaceIDfromInterfaceIndex(mDNS *const m, mDNSu32 index) 698 { 699 PosixNetworkInterface *intf; 700 701 assert(m != NULL); 702 703 if (index == kDNSServiceInterfaceIndexLocalOnly) return(mDNSInterface_LocalOnly); 704 705 intf = (PosixNetworkInterface*)(m->HostInterfaces); 706 while ( (intf != NULL) && (mDNSu32) intf->index != index) 707 intf = (PosixNetworkInterface *)(intf->coreIntf.next); 708 709 return (mDNSInterfaceID) intf; 710 } 711 712 mDNSexport mDNSu32 mDNSPlatformInterfaceIndexfromInterfaceID(mDNS *const m, mDNSInterfaceID id) 713 { 714 PosixNetworkInterface *intf; 715 716 assert(m != NULL); 717 718 if (id == mDNSInterface_LocalOnly) return(kDNSServiceInterfaceIndexLocalOnly); 719 720 intf = (PosixNetworkInterface*)(m->HostInterfaces); 721 while ( (intf != NULL) && (mDNSInterfaceID) intf != id) 722 intf = (PosixNetworkInterface *)(intf->coreIntf.next); 723 724 return intf ? intf->index : 0; 725 } 726 727 // Frees the specified PosixNetworkInterface structure. The underlying 728 // interface must have already been deregistered with the mDNS core. 729 mDNSlocal void FreePosixNetworkInterface(PosixNetworkInterface *intf) 730 { 731 assert(intf != NULL); 732 if (intf->intfName != NULL) free((void *)intf->intfName); 733 if (intf->multicastSocket4 != -1) assert(close(intf->multicastSocket4) == 0); 734 #if HAVE_IPV6 735 if (intf->multicastSocket6 != -1) assert(close(intf->multicastSocket6) == 0); 736 #endif 737 free(intf); 738 } 739 740 // Grab the first interface, deregister it, free it, and repeat until done. 741 mDNSlocal void ClearInterfaceList(mDNS *const m) 742 { 743 assert(m != NULL); 744 745 while (m->HostInterfaces) 746 { 747 PosixNetworkInterface *intf = (PosixNetworkInterface*)(m->HostInterfaces); 748 mDNS_DeregisterInterface(m, &intf->coreIntf, mDNSfalse); 749 if (gMDNSPlatformPosixVerboseLevel > 0) fprintf(stderr, "Deregistered interface %s\n", intf->intfName); 750 FreePosixNetworkInterface(intf); 751 } 752 num_registered_interfaces = 0; 753 num_pkts_accepted = 0; 754 num_pkts_rejected = 0; 755 } 756 757 // Sets up a send/receive socket. 758 // If mDNSIPPort port is non-zero, then it's a multicast socket on the specified interface 759 // If mDNSIPPort port is zero, then it's a randomly assigned port number, used for sending unicast queries 760 mDNSlocal int SetupSocket(struct sockaddr *intfAddr, mDNSIPPort port, int interfaceIndex, int *sktPtr) 761 { 762 int err = 0; 763 static const int kOn = 1; 764 static const int kIntTwoFiveFive = 255; 765 static const unsigned char kByteTwoFiveFive = 255; 766 const mDNSBool JoinMulticastGroup = (port.NotAnInteger != 0); 767 768 (void) interfaceIndex; // This parameter unused on plaforms that don't have IPv6 769 assert(intfAddr != NULL); 770 assert(sktPtr != NULL); 771 assert(*sktPtr == -1); 772 773 // Open the socket... 774 if (intfAddr->sa_family == AF_INET ) *sktPtr = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP); 775 #if HAVE_IPV6 776 else if (intfAddr->sa_family == AF_INET6) *sktPtr = socket(PF_INET6, SOCK_DGRAM, IPPROTO_UDP); 777 #endif 778 else return EINVAL; 779 780 if (*sktPtr < 0) { err = errno; perror("socket"); } 781 782 // ... with a shared UDP port, if it's for multicast receiving 783 if (err == 0 && port.NotAnInteger) 784 { 785 #if defined(SO_REUSEPORT) 786 err = setsockopt(*sktPtr, SOL_SOCKET, SO_REUSEPORT, &kOn, sizeof(kOn)); 787 #elif defined(SO_REUSEADDR) 788 err = setsockopt(*sktPtr, SOL_SOCKET, SO_REUSEADDR, &kOn, sizeof(kOn)); 789 #else 790 #error This platform has no way to avoid address busy errors on multicast. 791 #endif 792 if (err < 0) { err = errno; perror("setsockopt - SO_REUSExxxx"); } 793 } 794 795 // We want to receive destination addresses and interface identifiers. 796 if (intfAddr->sa_family == AF_INET) 797 { 798 struct ip_mreq imr; 799 struct sockaddr_in bindAddr; 800 if (err == 0) 801 { 802 #if defined(IP_PKTINFO) // Linux and Solaris 803 err = setsockopt(*sktPtr, IPPROTO_IP, IP_PKTINFO, &kOn, sizeof(kOn)); 804 if (err < 0) { err = errno; perror("setsockopt - IP_PKTINFO"); } 805 #elif defined(IP_RECVDSTADDR) || defined(IP_RECVIF) // BSD 806 #if defined(IP_RECVDSTADDR) 807 err = setsockopt(*sktPtr, IPPROTO_IP, IP_RECVDSTADDR, &kOn, sizeof(kOn)); 808 if (err < 0) { err = errno; perror("setsockopt - IP_RECVDSTADDR"); } 809 #endif 810 #if defined(IP_RECVIF) 811 if (err == 0) 812 { 813 err = setsockopt(*sktPtr, IPPROTO_IP, IP_RECVIF, &kOn, sizeof(kOn)); 814 if (err < 0) { err = errno; perror("setsockopt - IP_RECVIF"); } 815 } 816 #endif 817 #else 818 #warning This platform has no way to get the destination interface information -- will only work for single-homed hosts 819 #endif 820 } 821 #if defined(IP_RECVTTL) // Linux 822 if (err == 0) 823 { 824 setsockopt(*sktPtr, IPPROTO_IP, IP_RECVTTL, &kOn, sizeof(kOn)); 825 // We no longer depend on being able to get the received TTL, so don't worry if the option fails 826 } 827 #endif 828 829 // Add multicast group membership on this interface 830 if (err == 0 && JoinMulticastGroup) 831 { 832 imr.imr_multiaddr.s_addr = AllDNSLinkGroupv4.NotAnInteger; 833 imr.imr_interface = ((struct sockaddr_in*)intfAddr)->sin_addr; 834 err = setsockopt(*sktPtr, IPPROTO_IP, IP_ADD_MEMBERSHIP, &imr, sizeof(imr)); 835 if (err < 0) { err = errno; perror("setsockopt - IP_ADD_MEMBERSHIP"); } 836 } 837 838 // Specify outgoing interface too 839 if (err == 0 && JoinMulticastGroup) 840 { 841 err = setsockopt(*sktPtr, IPPROTO_IP, IP_MULTICAST_IF, &((struct sockaddr_in*)intfAddr)->sin_addr, sizeof(struct in_addr)); 842 if (err < 0) { err = errno; perror("setsockopt - IP_MULTICAST_IF"); } 843 } 844 845 // Per the mDNS spec, send unicast packets with TTL 255 846 if (err == 0) 847 { 848 err = setsockopt(*sktPtr, IPPROTO_IP, IP_TTL, &kIntTwoFiveFive, sizeof(kIntTwoFiveFive)); 849 if (err < 0) { err = errno; perror("setsockopt - IP_TTL"); } 850 } 851 852 // and multicast packets with TTL 255 too 853 // There's some debate as to whether IP_MULTICAST_TTL is an int or a byte so we just try both. 854 if (err == 0) 855 { 856 err = setsockopt(*sktPtr, IPPROTO_IP, IP_MULTICAST_TTL, &kByteTwoFiveFive, sizeof(kByteTwoFiveFive)); 857 if (err < 0 && errno == EINVAL) 858 err = setsockopt(*sktPtr, IPPROTO_IP, IP_MULTICAST_TTL, &kIntTwoFiveFive, sizeof(kIntTwoFiveFive)); 859 if (err < 0) { err = errno; perror("setsockopt - IP_MULTICAST_TTL"); } 860 } 861 862 // And start listening for packets 863 if (err == 0) 864 { 865 bindAddr.sin_family = AF_INET; 866 bindAddr.sin_port = port.NotAnInteger; 867 bindAddr.sin_addr.s_addr = INADDR_ANY; // Want to receive multicasts AND unicasts on this socket 868 err = bind(*sktPtr, (struct sockaddr *) &bindAddr, sizeof(bindAddr)); 869 if (err < 0) { err = errno; perror("bind"); fflush(stderr); } 870 } 871 } // endif (intfAddr->sa_family == AF_INET) 872 873 #if HAVE_IPV6 874 else if (intfAddr->sa_family == AF_INET6) 875 { 876 struct ipv6_mreq imr6; 877 struct sockaddr_in6 bindAddr6; 878 #if defined(IPV6_RECVPKTINFO) // Solaris 879 if (err == 0) 880 { 881 err = setsockopt(*sktPtr, IPPROTO_IPV6, IPV6_RECVPKTINFO, &kOn, sizeof(kOn)); 882 if (err < 0) { err = errno; perror("setsockopt - IPV6_PKTINFO"); } 883 } 884 885 #elif defined(IPV6_PKTINFO) 886 if (err == 0) 887 { 888 err = setsockopt(*sktPtr, IPPROTO_IPV6, IPV6_PKTINFO, &kOn, sizeof(kOn)); 889 if (err < 0) { err = errno; perror("setsockopt - IPV6_PKTINFO"); } 890 } 891 #else 892 #warning This platform has no way to get the destination interface information for IPv6 -- will only work for single-homed hosts 893 #endif 894 #if defined(IPV6_RECVHOPLIMIT) // Solaris 895 if (err == 0) 896 { 897 err = setsockopt(*sktPtr, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &kOn, sizeof(kOn)); 898 if (err < 0) { err = errno; perror("setsockopt - IPV6_HOPLIMIT"); } 899 } 900 901 #elif defined(IPV6_HOPLIMIT) 902 if (err == 0) 903 { 904 err = setsockopt(*sktPtr, IPPROTO_IPV6, IPV6_HOPLIMIT, &kOn, sizeof(kOn)); 905 if (err < 0) { err = errno; perror("setsockopt - IPV6_HOPLIMIT"); } 906 } 907 #endif 908 909 // Add multicast group membership on this interface 910 if (err == 0 && JoinMulticastGroup) 911 { 912 imr6.ipv6mr_multiaddr = *(const struct in6_addr*)&AllDNSLinkGroupv6; 913 imr6.ipv6mr_interface = interfaceIndex; 914 //LogMsg("Joining %.16a on %d", &imr6.ipv6mr_multiaddr, imr6.ipv6mr_interface); 915 err = setsockopt(*sktPtr, IPPROTO_IPV6, IPV6_JOIN_GROUP, &imr6, sizeof(imr6)); 916 if (err < 0) 917 { 918 err = errno; 919 verbosedebugf("IPV6_JOIN_GROUP %.16a on %d failed.\n", &imr6.ipv6mr_multiaddr, imr6.ipv6mr_interface); 920 perror("setsockopt - IPV6_JOIN_GROUP"); 921 } 922 } 923 924 // Specify outgoing interface too 925 if (err == 0 && JoinMulticastGroup) 926 { 927 u_int multicast_if = interfaceIndex; 928 err = setsockopt(*sktPtr, IPPROTO_IPV6, IPV6_MULTICAST_IF, &multicast_if, sizeof(multicast_if)); 929 if (err < 0) { err = errno; perror("setsockopt - IPV6_MULTICAST_IF"); } 930 } 931 932 // We want to receive only IPv6 packets on this socket. 933 // Without this option, we may get IPv4 addresses as mapped addresses. 934 if (err == 0) 935 { 936 err = setsockopt(*sktPtr, IPPROTO_IPV6, IPV6_V6ONLY, &kOn, sizeof(kOn)); 937 if (err < 0) { err = errno; perror("setsockopt - IPV6_V6ONLY"); } 938 } 939 940 // Per the mDNS spec, send unicast packets with TTL 255 941 if (err == 0) 942 { 943 err = setsockopt(*sktPtr, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &kIntTwoFiveFive, sizeof(kIntTwoFiveFive)); 944 if (err < 0) { err = errno; perror("setsockopt - IPV6_UNICAST_HOPS"); } 945 } 946 947 // and multicast packets with TTL 255 too 948 // There's some debate as to whether IPV6_MULTICAST_HOPS is an int or a byte so we just try both. 949 if (err == 0) 950 { 951 err = setsockopt(*sktPtr, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &kByteTwoFiveFive, sizeof(kByteTwoFiveFive)); 952 if (err < 0 && errno == EINVAL) 953 err = setsockopt(*sktPtr, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &kIntTwoFiveFive, sizeof(kIntTwoFiveFive)); 954 if (err < 0) { err = errno; perror("setsockopt - IPV6_MULTICAST_HOPS"); } 955 } 956 957 // And start listening for packets 958 if (err == 0) 959 { 960 mDNSPlatformMemZero(&bindAddr6, sizeof(bindAddr6)); 961 #ifndef NOT_HAVE_SA_LEN 962 bindAddr6.sin6_len = sizeof(bindAddr6); 963 #endif 964 bindAddr6.sin6_family = AF_INET6; 965 bindAddr6.sin6_port = port.NotAnInteger; 966 bindAddr6.sin6_flowinfo = 0; 967 bindAddr6.sin6_addr = in6addr_any; // Want to receive multicasts AND unicasts on this socket 968 bindAddr6.sin6_scope_id = 0; 969 err = bind(*sktPtr, (struct sockaddr *) &bindAddr6, sizeof(bindAddr6)); 970 if (err < 0) { err = errno; perror("bind"); fflush(stderr); } 971 } 972 } // endif (intfAddr->sa_family == AF_INET6) 973 #endif 974 975 // Set the socket to non-blocking. 976 if (err == 0) 977 { 978 err = fcntl(*sktPtr, F_GETFL, 0); 979 if (err < 0) err = errno; 980 else 981 { 982 err = fcntl(*sktPtr, F_SETFL, err | O_NONBLOCK); 983 if (err < 0) err = errno; 984 } 985 } 986 987 // Clean up 988 if (err != 0 && *sktPtr != -1) { assert(close(*sktPtr) == 0); *sktPtr = -1; } 989 assert( (err == 0) == (*sktPtr != -1) ); 990 return err; 991 } 992 993 // Creates a PosixNetworkInterface for the interface whose IP address is 994 // intfAddr and whose name is intfName and registers it with mDNS core. 995 mDNSlocal int SetupOneInterface(mDNS *const m, struct sockaddr *intfAddr, struct sockaddr *intfMask, const char *intfName, int intfIndex) 996 { 997 int err = 0; 998 PosixNetworkInterface *intf; 999 PosixNetworkInterface *alias = NULL; 1000 1001 assert(m != NULL); 1002 assert(intfAddr != NULL); 1003 assert(intfName != NULL); 1004 assert(intfMask != NULL); 1005 1006 // Allocate the interface structure itself. 1007 intf = (PosixNetworkInterface*)malloc(sizeof(*intf)); 1008 if (intf == NULL) { assert(0); err = ENOMEM; } 1009 1010 // And make a copy of the intfName. 1011 if (err == 0) 1012 { 1013 intf->intfName = strdup(intfName); 1014 if (intf->intfName == NULL) { assert(0); err = ENOMEM; } 1015 } 1016 1017 if (err == 0) 1018 { 1019 // Set up the fields required by the mDNS core. 1020 SockAddrTomDNSAddr(intfAddr, &intf->coreIntf.ip, NULL); 1021 SockAddrTomDNSAddr(intfMask, &intf->coreIntf.mask, NULL); 1022 //LogMsg("SetupOneInterface: %#a %#a", &intf->coreIntf.ip, &intf->coreIntf.mask); 1023 strncpy(intf->coreIntf.ifname, intfName, sizeof(intf->coreIntf.ifname)); 1024 intf->coreIntf.ifname[sizeof(intf->coreIntf.ifname)-1] = 0; 1025 intf->coreIntf.Advertise = m->AdvertiseLocalAddresses; 1026 intf->coreIntf.McastTxRx = mDNStrue; 1027 1028 // Set up the extra fields in PosixNetworkInterface. 1029 assert(intf->intfName != NULL); // intf->intfName already set up above 1030 intf->index = intfIndex; 1031 intf->multicastSocket4 = -1; 1032 #if HAVE_IPV6 1033 intf->multicastSocket6 = -1; 1034 #endif 1035 alias = SearchForInterfaceByName(m, intf->intfName); 1036 if (alias == NULL) alias = intf; 1037 intf->coreIntf.InterfaceID = (mDNSInterfaceID)alias; 1038 1039 if (alias != intf) 1040 debugf("SetupOneInterface: %s %#a is an alias of %#a", intfName, &intf->coreIntf.ip, &alias->coreIntf.ip); 1041 } 1042 1043 // Set up the multicast socket 1044 if (err == 0) 1045 { 1046 if (alias->multicastSocket4 == -1 && intfAddr->sa_family == AF_INET) 1047 err = SetupSocket(intfAddr, MulticastDNSPort, intf->index, &alias->multicastSocket4); 1048 #if HAVE_IPV6 1049 else if (alias->multicastSocket6 == -1 && intfAddr->sa_family == AF_INET6) 1050 err = SetupSocket(intfAddr, MulticastDNSPort, intf->index, &alias->multicastSocket6); 1051 #endif 1052 } 1053 1054 // The interface is all ready to go, let's register it with the mDNS core. 1055 if (err == 0) 1056 err = mDNS_RegisterInterface(m, &intf->coreIntf, mDNSfalse); 1057 1058 // Clean up. 1059 if (err == 0) 1060 { 1061 num_registered_interfaces++; 1062 debugf("SetupOneInterface: %s %#a Registered", intf->intfName, &intf->coreIntf.ip); 1063 if (gMDNSPlatformPosixVerboseLevel > 0) 1064 fprintf(stderr, "Registered interface %s\n", intf->intfName); 1065 } 1066 else 1067 { 1068 // Use intfName instead of intf->intfName in the next line to avoid dereferencing NULL. 1069 debugf("SetupOneInterface: %s %#a failed to register %d", intfName, &intf->coreIntf.ip, err); 1070 if (intf) { FreePosixNetworkInterface(intf); intf = NULL; } 1071 } 1072 1073 assert( (err == 0) == (intf != NULL) ); 1074 1075 return err; 1076 } 1077 1078 // Call get_ifi_info() to obtain a list of active interfaces and call SetupOneInterface() on each one. 1079 mDNSlocal int SetupInterfaceList(mDNS *const m) 1080 { 1081 mDNSBool foundav4 = mDNSfalse; 1082 int err = 0; 1083 struct ifi_info *intfList = get_ifi_info(AF_INET, mDNStrue); 1084 struct ifi_info *firstLoopback = NULL; 1085 1086 assert(m != NULL); 1087 debugf("SetupInterfaceList"); 1088 1089 if (intfList == NULL) err = ENOENT; 1090 1091 #if HAVE_IPV6 1092 if (err == 0) /* Link the IPv6 list to the end of the IPv4 list */ 1093 { 1094 struct ifi_info **p = &intfList; 1095 while (*p) p = &(*p)->ifi_next; 1096 *p = get_ifi_info(AF_INET6, mDNStrue); 1097 } 1098 #endif 1099 1100 if (err == 0) 1101 { 1102 struct ifi_info *i = intfList; 1103 while (i) 1104 { 1105 if ( ((i->ifi_addr->sa_family == AF_INET) 1106 #if HAVE_IPV6 1107 || (i->ifi_addr->sa_family == AF_INET6) 1108 #endif 1109 ) && (i->ifi_flags & IFF_UP) && !(i->ifi_flags & IFF_POINTOPOINT) ) 1110 { 1111 if (i->ifi_flags & IFF_LOOPBACK) 1112 { 1113 if (firstLoopback == NULL) 1114 firstLoopback = i; 1115 } 1116 else 1117 { 1118 if (SetupOneInterface(m, i->ifi_addr, i->ifi_netmask, i->ifi_name, i->ifi_index) == 0) 1119 if (i->ifi_addr->sa_family == AF_INET) 1120 foundav4 = mDNStrue; 1121 } 1122 } 1123 i = i->ifi_next; 1124 } 1125 1126 // If we found no normal interfaces but we did find a loopback interface, register the 1127 // loopback interface. This allows self-discovery if no interfaces are configured. 1128 // Temporary workaround: Multicast loopback on IPv6 interfaces appears not to work. 1129 // In the interim, we skip loopback interface only if we found at least one v4 interface to use 1130 // if ( (m->HostInterfaces == NULL) && (firstLoopback != NULL) ) 1131 if ( !foundav4 && firstLoopback ) 1132 (void) SetupOneInterface(m, firstLoopback->ifi_addr, firstLoopback->ifi_netmask, firstLoopback->ifi_name, firstLoopback->ifi_index); 1133 } 1134 1135 // Clean up. 1136 if (intfList != NULL) free_ifi_info(intfList); 1137 return err; 1138 } 1139 1140 #if USES_NETLINK 1141 1142 // See <http://www.faqs.org/rfcs/rfc3549.html> for a description of NetLink 1143 1144 // Open a socket that will receive interface change notifications 1145 mDNSlocal mStatus OpenIfNotifySocket( int *pFD) 1146 { 1147 mStatus err = mStatus_NoError; 1148 struct sockaddr_nl snl; 1149 int sock; 1150 int ret; 1151 1152 sock = socket( AF_NETLINK, SOCK_RAW, NETLINK_ROUTE); 1153 if (sock < 0) 1154 return errno; 1155 1156 // Configure read to be non-blocking because inbound msg size is not known in advance 1157 (void) fcntl( sock, F_SETFL, O_NONBLOCK); 1158 1159 /* Subscribe the socket to Link & IP addr notifications. */ 1160 bzero( &snl, sizeof snl); 1161 snl.nl_family = AF_NETLINK; 1162 snl.nl_groups = RTMGRP_LINK | RTMGRP_IPV4_IFADDR; 1163 ret = bind( sock, (struct sockaddr *) &snl, sizeof snl); 1164 if ( 0 == ret) 1165 *pFD = sock; 1166 else 1167 err = errno; 1168 1169 return err; 1170 } 1171 1172 #if MDNS_DEBUGMSGS 1173 mDNSlocal void PrintNetLinkMsg( const struct nlmsghdr *pNLMsg) 1174 { 1175 const char *kNLMsgTypes[] = { "", "NLMSG_NOOP", "NLMSG_ERROR", "NLMSG_DONE", "NLMSG_OVERRUN" }; 1176 const char *kNLRtMsgTypes[] = { "RTM_NEWLINK", "RTM_DELLINK", "RTM_GETLINK", "RTM_NEWADDR", "RTM_DELADDR", "RTM_GETADDR" }; 1177 1178 printf( "nlmsghdr len=%d, type=%s, flags=0x%x\n", pNLMsg->nlmsg_len, 1179 pNLMsg->nlmsg_type < RTM_BASE ? kNLMsgTypes[ pNLMsg->nlmsg_type] : kNLRtMsgTypes[ pNLMsg->nlmsg_type - RTM_BASE], 1180 pNLMsg->nlmsg_flags); 1181 1182 if ( RTM_NEWLINK <= pNLMsg->nlmsg_type && pNLMsg->nlmsg_type <= RTM_GETLINK) 1183 { 1184 struct ifinfomsg *pIfInfo = (struct ifinfomsg*) NLMSG_DATA( pNLMsg); 1185 printf( "ifinfomsg family=%d, type=%d, index=%d, flags=0x%x, change=0x%x\n", pIfInfo->ifi_family, 1186 pIfInfo->ifi_type, pIfInfo->ifi_index, pIfInfo->ifi_flags, pIfInfo->ifi_change); 1187 1188 } 1189 else if ( RTM_NEWADDR <= pNLMsg->nlmsg_type && pNLMsg->nlmsg_type <= RTM_GETADDR) 1190 { 1191 struct ifaddrmsg *pIfAddr = (struct ifaddrmsg*) NLMSG_DATA( pNLMsg); 1192 printf( "ifaddrmsg family=%d, index=%d, flags=0x%x\n", pIfAddr->ifa_family, 1193 pIfAddr->ifa_index, pIfAddr->ifa_flags); 1194 } 1195 printf( "\n"); 1196 } 1197 #endif 1198 1199 mDNSlocal mDNSu32 ProcessRoutingNotification( int sd) 1200 // Read through the messages on sd and if any indicate that any interface records should 1201 // be torn down and rebuilt, return affected indices as a bitmask. Otherwise return 0. 1202 { 1203 ssize_t readCount; 1204 char buff[ 4096]; 1205 struct nlmsghdr *pNLMsg = (struct nlmsghdr*) buff; 1206 mDNSu32 result = 0; 1207 1208 // The structure here is more complex than it really ought to be because, 1209 // unfortunately, there's no good way to size a buffer in advance large 1210 // enough to hold all pending data and so avoid message fragmentation. 1211 // (Note that FIONREAD is not supported on AF_NETLINK.) 1212 1213 readCount = read( sd, buff, sizeof buff); 1214 while ( 1) 1215 { 1216 // Make sure we've got an entire nlmsghdr in the buffer, and payload, too. 1217 // If not, discard already-processed messages in buffer and read more data. 1218 if ( ( (char*) &pNLMsg[1] > ( buff + readCount)) || // i.e. *pNLMsg extends off end of buffer 1219 ( (char*) pNLMsg + pNLMsg->nlmsg_len > ( buff + readCount))) 1220 { 1221 if ( buff < (char*) pNLMsg) // we have space to shuffle 1222 { 1223 // discard processed data 1224 readCount -= ( (char*) pNLMsg - buff); 1225 memmove( buff, pNLMsg, readCount); 1226 pNLMsg = (struct nlmsghdr*) buff; 1227 1228 // read more data 1229 readCount += read( sd, buff + readCount, sizeof buff - readCount); 1230 continue; // spin around and revalidate with new readCount 1231 } 1232 else 1233 break; // Otherwise message does not fit in buffer 1234 } 1235 1236 #if MDNS_DEBUGMSGS 1237 PrintNetLinkMsg( pNLMsg); 1238 #endif 1239 1240 // Process the NetLink message 1241 if ( pNLMsg->nlmsg_type == RTM_GETLINK || pNLMsg->nlmsg_type == RTM_NEWLINK) 1242 result |= 1 << ((struct ifinfomsg*) NLMSG_DATA( pNLMsg))->ifi_index; 1243 else if ( pNLMsg->nlmsg_type == RTM_DELADDR || pNLMsg->nlmsg_type == RTM_NEWADDR) 1244 result |= 1 << ((struct ifaddrmsg*) NLMSG_DATA( pNLMsg))->ifa_index; 1245 1246 // Advance pNLMsg to the next message in the buffer 1247 if ( ( pNLMsg->nlmsg_flags & NLM_F_MULTI) != 0 && pNLMsg->nlmsg_type != NLMSG_DONE) 1248 { 1249 ssize_t len = readCount - ( (char*)pNLMsg - buff); 1250 pNLMsg = NLMSG_NEXT( pNLMsg, len); 1251 } 1252 else 1253 break; // all done! 1254 } 1255 1256 return result; 1257 } 1258 1259 #else // USES_NETLINK 1260 1261 // Open a socket that will receive interface change notifications 1262 mDNSlocal mStatus OpenIfNotifySocket( int *pFD) 1263 { 1264 *pFD = socket( AF_ROUTE, SOCK_RAW, 0); 1265 1266 if ( *pFD < 0) 1267 return mStatus_UnknownErr; 1268 1269 // Configure read to be non-blocking because inbound msg size is not known in advance 1270 (void) fcntl( *pFD, F_SETFL, O_NONBLOCK); 1271 1272 return mStatus_NoError; 1273 } 1274 1275 #if MDNS_DEBUGMSGS 1276 mDNSlocal void PrintRoutingSocketMsg( const struct ifa_msghdr *pRSMsg) 1277 { 1278 const char *kRSMsgTypes[] = { "", "RTM_ADD", "RTM_DELETE", "RTM_CHANGE", "RTM_GET", "RTM_LOSING", 1279 "RTM_REDIRECT", "RTM_MISS", "RTM_LOCK", "RTM_OLDADD", "RTM_OLDDEL", "RTM_RESOLVE", 1280 "RTM_NEWADDR", "RTM_DELADDR", "RTM_IFINFO", "RTM_NEWMADDR", "RTM_DELMADDR" }; 1281 1282 int index = pRSMsg->ifam_type == RTM_IFINFO ? ((struct if_msghdr*) pRSMsg)->ifm_index : pRSMsg->ifam_index; 1283 1284 printf( "ifa_msghdr len=%d, type=%s, index=%d\n", pRSMsg->ifam_msglen, kRSMsgTypes[ pRSMsg->ifam_type], index); 1285 } 1286 #endif 1287 1288 mDNSlocal mDNSu32 ProcessRoutingNotification( int sd) 1289 // Read through the messages on sd and if any indicate that any interface records should 1290 // be torn down and rebuilt, return affected indices as a bitmask. Otherwise return 0. 1291 { 1292 ssize_t readCount; 1293 char buff[ 4096]; 1294 struct ifa_msghdr *pRSMsg = (struct ifa_msghdr*) buff; 1295 mDNSu32 result = 0; 1296 1297 readCount = read( sd, buff, sizeof buff); 1298 if ( readCount < (ssize_t) sizeof( struct ifa_msghdr)) 1299 return mStatus_UnsupportedErr; // cannot decipher message 1300 1301 #if MDNS_DEBUGMSGS 1302 PrintRoutingSocketMsg( pRSMsg); 1303 #endif 1304 1305 // Process the message 1306 if ( pRSMsg->ifam_type == RTM_NEWADDR || pRSMsg->ifam_type == RTM_DELADDR || 1307 pRSMsg->ifam_type == RTM_IFINFO) 1308 { 1309 if ( pRSMsg->ifam_type == RTM_IFINFO) 1310 result |= 1 << ((struct if_msghdr*) pRSMsg)->ifm_index; 1311 else 1312 result |= 1 << pRSMsg->ifam_index; 1313 } 1314 1315 return result; 1316 } 1317 1318 #endif // USES_NETLINK 1319 1320 // Called when data appears on interface change notification socket 1321 mDNSlocal void InterfaceChangeCallback( void *context) 1322 { 1323 IfChangeRec *pChgRec = (IfChangeRec*) context; 1324 fd_set readFDs; 1325 mDNSu32 changedInterfaces = 0; 1326 struct timeval zeroTimeout = { 0, 0 }; 1327 1328 FD_ZERO( &readFDs); 1329 FD_SET( pChgRec->NotifySD, &readFDs); 1330 1331 do 1332 { 1333 changedInterfaces |= ProcessRoutingNotification( pChgRec->NotifySD); 1334 } 1335 while ( 0 < select( pChgRec->NotifySD + 1, &readFDs, (fd_set*) NULL, (fd_set*) NULL, &zeroTimeout)); 1336 1337 // Currently we rebuild the entire interface list whenever any interface change is 1338 // detected. If this ever proves to be a performance issue in a multi-homed 1339 // configuration, more care should be paid to changedInterfaces. 1340 if ( changedInterfaces) 1341 mDNSPlatformPosixRefreshInterfaceList( pChgRec->mDNS); 1342 } 1343 1344 // Register with either a Routing Socket or RtNetLink to listen for interface changes. 1345 mDNSlocal mStatus WatchForInterfaceChange(mDNS *const m) 1346 { 1347 mStatus err; 1348 IfChangeRec *pChgRec; 1349 1350 pChgRec = (IfChangeRec*) mDNSPlatformMemAllocate( sizeof *pChgRec); 1351 if ( pChgRec == NULL) 1352 return mStatus_NoMemoryErr; 1353 1354 pChgRec->mDNS = m; 1355 err = OpenIfNotifySocket( &pChgRec->NotifySD); 1356 if ( err == 0) 1357 err = mDNSPosixAddFDToEventLoop( pChgRec->NotifySD, InterfaceChangeCallback, pChgRec); 1358 1359 return err; 1360 } 1361 1362 // Test to see if we're the first client running on UDP port 5353, by trying to bind to 5353 without using SO_REUSEPORT. 1363 // If we fail, someone else got here first. That's not a big problem; we can share the port for multicast responses -- 1364 // we just need to be aware that we shouldn't expect to successfully receive unicast UDP responses. 1365 mDNSlocal mDNSBool mDNSPlatformInit_CanReceiveUnicast(void) 1366 { 1367 int err; 1368 int s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); 1369 struct sockaddr_in s5353; 1370 s5353.sin_family = AF_INET; 1371 s5353.sin_port = MulticastDNSPort.NotAnInteger; 1372 s5353.sin_addr.s_addr = 0; 1373 err = bind(s, (struct sockaddr *)&s5353, sizeof(s5353)); 1374 close(s); 1375 if (err) debugf("No unicast UDP responses"); 1376 else debugf("Unicast UDP responses okay"); 1377 return(err == 0); 1378 } 1379 1380 // mDNS core calls this routine to initialise the platform-specific data. 1381 mDNSexport mStatus mDNSPlatformInit(mDNS *const m) 1382 { 1383 int err = 0; 1384 struct sockaddr sa; 1385 assert(m != NULL); 1386 1387 if (mDNSPlatformInit_CanReceiveUnicast()) m->CanReceiveUnicastOn5353 = mDNStrue; 1388 1389 // Tell mDNS core the names of this machine. 1390 1391 // Set up the nice label 1392 m->nicelabel.c[0] = 0; 1393 GetUserSpecifiedFriendlyComputerName(&m->nicelabel); 1394 if (m->nicelabel.c[0] == 0) MakeDomainLabelFromLiteralString(&m->nicelabel, "Computer"); 1395 1396 // Set up the RFC 1034-compliant label 1397 m->hostlabel.c[0] = 0; 1398 GetUserSpecifiedRFC1034ComputerName(&m->hostlabel); 1399 if (m->hostlabel.c[0] == 0) MakeDomainLabelFromLiteralString(&m->hostlabel, "Computer"); 1400 1401 mDNS_SetFQDN(m); 1402 1403 sa.sa_family = AF_INET; 1404 m->p->unicastSocket4 = -1; 1405 if (err == mStatus_NoError) err = SetupSocket(&sa, zeroIPPort, 0, &m->p->unicastSocket4); 1406 #if HAVE_IPV6 1407 sa.sa_family = AF_INET6; 1408 m->p->unicastSocket6 = -1; 1409 if (err == mStatus_NoError) err = SetupSocket(&sa, zeroIPPort, 0, &m->p->unicastSocket6); 1410 #endif 1411 1412 // Tell mDNS core about the network interfaces on this machine. 1413 if (err == mStatus_NoError) err = SetupInterfaceList(m); 1414 1415 // Tell mDNS core about DNS Servers 1416 if (err == mStatus_NoError) ParseDNSServers(m, uDNS_SERVERS_FILE); 1417 1418 if (err == mStatus_NoError) 1419 { 1420 err = WatchForInterfaceChange(m); 1421 // Failure to observe interface changes is non-fatal. 1422 if ( err != mStatus_NoError) 1423 { 1424 fprintf(stderr, "mDNS(%d) WARNING: Unable to detect interface changes (%d).\n", getpid(), err); 1425 err = mStatus_NoError; 1426 } 1427 } 1428 1429 // We don't do asynchronous initialization on the Posix platform, so by the time 1430 // we get here the setup will already have succeeded or failed. If it succeeded, 1431 // we should just call mDNSCoreInitComplete() immediately. 1432 if (err == mStatus_NoError) 1433 mDNSCoreInitComplete(m, mStatus_NoError); 1434 1435 return PosixErrorToStatus(err); 1436 } 1437 1438 // mDNS core calls this routine to clean up the platform-specific data. 1439 // In our case all we need to do is to tear down every network interface. 1440 mDNSexport void mDNSPlatformClose(mDNS *const m) 1441 { 1442 assert(m != NULL); 1443 ClearInterfaceList(m); 1444 if (m->p->unicastSocket4 != -1) assert(close(m->p->unicastSocket4) == 0); 1445 #if HAVE_IPV6 1446 if (m->p->unicastSocket6 != -1) assert(close(m->p->unicastSocket6) == 0); 1447 #endif 1448 } 1449 1450 mDNSexport mStatus mDNSPlatformPosixRefreshInterfaceList(mDNS *const m) 1451 { 1452 int err; 1453 ClearInterfaceList(m); 1454 err = SetupInterfaceList(m); 1455 return PosixErrorToStatus(err); 1456 } 1457 1458 #if COMPILER_LIKES_PRAGMA_MARK 1459 #pragma mark ***** Locking 1460 #endif 1461 1462 // On the Posix platform, locking is a no-op because we only ever enter 1463 // mDNS core on the main thread. 1464 1465 // mDNS core calls this routine when it wants to prevent 1466 // the platform from reentering mDNS core code. 1467 mDNSexport void mDNSPlatformLock (const mDNS *const m) 1468 { 1469 (void) m; // Unused 1470 } 1471 1472 // mDNS core calls this routine when it release the lock taken by 1473 // mDNSPlatformLock and allow the platform to reenter mDNS core code. 1474 mDNSexport void mDNSPlatformUnlock (const mDNS *const m) 1475 { 1476 (void) m; // Unused 1477 } 1478 1479 #if COMPILER_LIKES_PRAGMA_MARK 1480 #pragma mark ***** Strings 1481 #endif 1482 1483 // mDNS core calls this routine to copy C strings. 1484 // On the Posix platform this maps directly to the ANSI C strcpy. 1485 mDNSexport void mDNSPlatformStrCopy(const void *src, void *dst) 1486 { 1487 strcpy((char *)dst, (char *)src); 1488 } 1489 1490 // mDNS core calls this routine to get the length of a C string. 1491 // On the Posix platform this maps directly to the ANSI C strlen. 1492 mDNSexport mDNSu32 mDNSPlatformStrLen (const void *src) 1493 { 1494 return strlen((char*)src); 1495 } 1496 1497 // mDNS core calls this routine to copy memory. 1498 // On the Posix platform this maps directly to the ANSI C memcpy. 1499 mDNSexport void mDNSPlatformMemCopy(const void *src, void *dst, mDNSu32 len) 1500 { 1501 memcpy(dst, src, len); 1502 } 1503 1504 // mDNS core calls this routine to test whether blocks of memory are byte-for-byte 1505 // identical. On the Posix platform this is a simple wrapper around ANSI C memcmp. 1506 mDNSexport mDNSBool mDNSPlatformMemSame(const void *src, const void *dst, mDNSu32 len) 1507 { 1508 return memcmp(dst, src, len) == 0; 1509 } 1510 1511 // mDNS core calls this routine to clear blocks of memory. 1512 // On the Posix platform this is a simple wrapper around ANSI C memset. 1513 mDNSexport void mDNSPlatformMemZero( void *dst, mDNSu32 len) 1514 { 1515 memset(dst, 0, len); 1516 } 1517 1518 mDNSexport void * mDNSPlatformMemAllocate(mDNSu32 len) { return(malloc(len)); } 1519 mDNSexport void mDNSPlatformMemFree (void *mem) { free(mem); } 1520 1521 mDNSexport mDNSu32 mDNSPlatformRandomSeed(void) 1522 { 1523 struct timeval tv; 1524 gettimeofday(&tv, NULL); 1525 return(tv.tv_usec); 1526 } 1527 1528 mDNSexport mDNSs32 mDNSPlatformOneSecond = 1024; 1529 1530 mDNSexport mStatus mDNSPlatformTimeInit(void) 1531 { 1532 // No special setup is required on Posix -- we just use gettimeofday(); 1533 // This is not really safe, because gettimeofday can go backwards if the user manually changes the date or time 1534 // We should find a better way to do this 1535 return(mStatus_NoError); 1536 } 1537 1538 mDNSexport mDNSs32 mDNSPlatformRawTime() 1539 { 1540 struct timeval tv; 1541 gettimeofday(&tv, NULL); 1542 // tv.tv_sec is seconds since 1st January 1970 (GMT, with no adjustment for daylight savings time) 1543 // tv.tv_usec is microseconds since the start of this second (i.e. values 0 to 999999) 1544 // We use the lower 22 bits of tv.tv_sec for the top 22 bits of our result 1545 // and we multiply tv.tv_usec by 16 / 15625 to get a value in the range 0-1023 to go in the bottom 10 bits. 1546 // This gives us a proper modular (cyclic) counter that has a resolution of roughly 1ms (actually 1/1024 second) 1547 // and correctly cycles every 2^22 seconds (4194304 seconds = approx 48 days). 1548 return( (tv.tv_sec << 10) | (tv.tv_usec * 16 / 15625) ); 1549 } 1550 1551 mDNSexport mDNSs32 mDNSPlatformUTC(void) 1552 { 1553 return time(NULL); 1554 } 1555 1556 mDNSlocal void mDNSPosixAddToFDSet(int *nfds, fd_set *readfds, int s) 1557 { 1558 if (*nfds < s + 1) *nfds = s + 1; 1559 FD_SET(s, readfds); 1560 } 1561 1562 mDNSexport void mDNSPosixGetFDSet(mDNS *m, int *nfds, fd_set *readfds, struct timeval *timeout) 1563 { 1564 mDNSs32 ticks; 1565 struct timeval interval; 1566 1567 // 1. Call mDNS_Execute() to let mDNSCore do what it needs to do 1568 mDNSs32 nextevent = mDNS_Execute(m); 1569 1570 // 2. Build our list of active file descriptors 1571 PosixNetworkInterface *info = (PosixNetworkInterface *)(m->HostInterfaces); 1572 if (m->p->unicastSocket4 != -1) mDNSPosixAddToFDSet(nfds, readfds, m->p->unicastSocket4); 1573 #if HAVE_IPV6 1574 if (m->p->unicastSocket6 != -1) mDNSPosixAddToFDSet(nfds, readfds, m->p->unicastSocket6); 1575 #endif 1576 while (info) 1577 { 1578 if (info->multicastSocket4 != -1) mDNSPosixAddToFDSet(nfds, readfds, info->multicastSocket4); 1579 #if HAVE_IPV6 1580 if (info->multicastSocket6 != -1) mDNSPosixAddToFDSet(nfds, readfds, info->multicastSocket6); 1581 #endif 1582 info = (PosixNetworkInterface *)(info->coreIntf.next); 1583 } 1584 1585 // 3. Calculate the time remaining to the next scheduled event (in struct timeval format) 1586 ticks = nextevent - mDNS_TimeNow(m); 1587 if (ticks < 1) ticks = 1; 1588 interval.tv_sec = ticks >> 10; // The high 22 bits are seconds 1589 interval.tv_usec = ((ticks & 0x3FF) * 15625) / 16; // The low 10 bits are 1024ths 1590 1591 // 4. If client's proposed timeout is more than what we want, then reduce it 1592 if (timeout->tv_sec > interval.tv_sec || 1593 (timeout->tv_sec == interval.tv_sec && timeout->tv_usec > interval.tv_usec)) 1594 *timeout = interval; 1595 } 1596 1597 mDNSexport void mDNSPosixProcessFDSet(mDNS *const m, fd_set *readfds) 1598 { 1599 PosixNetworkInterface *info; 1600 assert(m != NULL); 1601 assert(readfds != NULL); 1602 info = (PosixNetworkInterface *)(m->HostInterfaces); 1603 1604 if (m->p->unicastSocket4 != -1 && FD_ISSET(m->p->unicastSocket4, readfds)) 1605 { 1606 FD_CLR(m->p->unicastSocket4, readfds); 1607 SocketDataReady(m, NULL, m->p->unicastSocket4); 1608 } 1609 #if HAVE_IPV6 1610 if (m->p->unicastSocket6 != -1 && FD_ISSET(m->p->unicastSocket6, readfds)) 1611 { 1612 FD_CLR(m->p->unicastSocket6, readfds); 1613 SocketDataReady(m, NULL, m->p->unicastSocket6); 1614 } 1615 #endif 1616 1617 while (info) 1618 { 1619 if (info->multicastSocket4 != -1 && FD_ISSET(info->multicastSocket4, readfds)) 1620 { 1621 FD_CLR(info->multicastSocket4, readfds); 1622 SocketDataReady(m, info, info->multicastSocket4); 1623 } 1624 #if HAVE_IPV6 1625 if (info->multicastSocket6 != -1 && FD_ISSET(info->multicastSocket6, readfds)) 1626 { 1627 FD_CLR(info->multicastSocket6, readfds); 1628 SocketDataReady(m, info, info->multicastSocket6); 1629 } 1630 #endif 1631 info = (PosixNetworkInterface *)(info->coreIntf.next); 1632 } 1633 } 1634 1635 // update gMaxFD 1636 mDNSlocal void DetermineMaxEventFD( void ) 1637 { 1638 PosixEventSource *iSource; 1639 1640 gMaxFD = 0; 1641 for ( iSource=(PosixEventSource*)gEventSources.Head; iSource; iSource = iSource->Next) 1642 if ( gMaxFD < iSource->fd) 1643 gMaxFD = iSource->fd; 1644 } 1645 1646 // Add a file descriptor to the set that mDNSPosixRunEventLoopOnce() listens to. 1647 mStatus mDNSPosixAddFDToEventLoop( int fd, mDNSPosixEventCallback callback, void *context) 1648 { 1649 PosixEventSource *newSource; 1650 1651 if ( gEventSources.LinkOffset == 0) 1652 InitLinkedList( &gEventSources, offsetof( PosixEventSource, Next)); 1653 1654 if ( fd >= (int) FD_SETSIZE || fd < 0) 1655 return mStatus_UnsupportedErr; 1656 if ( callback == NULL) 1657 return mStatus_BadParamErr; 1658 1659 newSource = (PosixEventSource*) malloc( sizeof *newSource); 1660 if ( NULL == newSource) 1661 return mStatus_NoMemoryErr; 1662 1663 newSource->Callback = callback; 1664 newSource->Context = context; 1665 newSource->fd = fd; 1666 1667 AddToTail( &gEventSources, newSource); 1668 FD_SET( fd, &gEventFDs); 1669 1670 DetermineMaxEventFD(); 1671 1672 return mStatus_NoError; 1673 } 1674 1675 // Remove a file descriptor from the set that mDNSPosixRunEventLoopOnce() listens to. 1676 mStatus mDNSPosixRemoveFDFromEventLoop( int fd) 1677 { 1678 PosixEventSource *iSource; 1679 1680 for ( iSource=(PosixEventSource*)gEventSources.Head; iSource; iSource = iSource->Next) 1681 { 1682 if ( fd == iSource->fd) 1683 { 1684 FD_CLR( fd, &gEventFDs); 1685 RemoveFromList( &gEventSources, iSource); 1686 free( iSource); 1687 DetermineMaxEventFD(); 1688 return mStatus_NoError; 1689 } 1690 } 1691 return mStatus_NoSuchNameErr; 1692 } 1693 1694 // Simply note the received signal in gEventSignals. 1695 mDNSlocal void NoteSignal( int signum) 1696 { 1697 sigaddset( &gEventSignals, signum); 1698 } 1699 1700 // Tell the event package to listen for signal and report it in mDNSPosixRunEventLoopOnce(). 1701 mStatus mDNSPosixListenForSignalInEventLoop( int signum) 1702 { 1703 struct sigaction action; 1704 mStatus err; 1705 1706 bzero( &action, sizeof action); // more portable than member-wise assignment 1707 action.sa_handler = NoteSignal; 1708 err = sigaction( signum, &action, (struct sigaction*) NULL); 1709 1710 sigaddset( &gEventSignalSet, signum); 1711 1712 return err; 1713 } 1714 1715 // Tell the event package to stop listening for signal in mDNSPosixRunEventLoopOnce(). 1716 mStatus mDNSPosixIgnoreSignalInEventLoop( int signum) 1717 { 1718 struct sigaction action; 1719 mStatus err; 1720 1721 bzero( &action, sizeof action); // more portable than member-wise assignment 1722 action.sa_handler = SIG_DFL; 1723 err = sigaction( signum, &action, (struct sigaction*) NULL); 1724 1725 sigdelset( &gEventSignalSet, signum); 1726 1727 return err; 1728 } 1729 1730 // Do a single pass through the attendent event sources and dispatch any found to their callbacks. 1731 // Return as soon as internal timeout expires, or a signal we're listening for is received. 1732 mStatus mDNSPosixRunEventLoopOnce( mDNS *m, const struct timeval *pTimeout, 1733 sigset_t *pSignalsReceived, mDNSBool *pDataDispatched) 1734 { 1735 fd_set listenFDs = gEventFDs; 1736 int fdMax = 0, numReady; 1737 struct timeval timeout = *pTimeout; 1738 1739 // Include the sockets that are listening to the wire in our select() set 1740 mDNSPosixGetFDSet( m, &fdMax, &listenFDs, &timeout); // timeout may get modified 1741 if ( fdMax < gMaxFD) 1742 fdMax = gMaxFD; 1743 1744 numReady = select( fdMax + 1, &listenFDs, (fd_set*) NULL, (fd_set*) NULL, &timeout); 1745 1746 // If any data appeared, invoke its callback 1747 if ( numReady > 0) 1748 { 1749 PosixEventSource *iSource; 1750 1751 (void) mDNSPosixProcessFDSet( m, &listenFDs); // call this first to process wire data for clients 1752 1753 for ( iSource=(PosixEventSource*)gEventSources.Head; iSource; iSource = iSource->Next) 1754 { 1755 if ( FD_ISSET( iSource->fd, &listenFDs)) 1756 { 1757 iSource->Callback( iSource->Context); 1758 break; // in case callback removed elements from gEventSources 1759 } 1760 } 1761 *pDataDispatched = mDNStrue; 1762 } 1763 else 1764 *pDataDispatched = mDNSfalse; 1765 1766 (void) sigprocmask( SIG_BLOCK, &gEventSignalSet, (sigset_t*) NULL); 1767 *pSignalsReceived = gEventSignals; 1768 sigemptyset( &gEventSignals); 1769 (void) sigprocmask( SIG_UNBLOCK, &gEventSignalSet, (sigset_t*) NULL); 1770 1771 return mStatus_NoError; 1772 } 1773