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 return (numOfServers > 0) ? 0 : -1; 678 } 679 680 // Searches the interface list looking for the named interface. 681 // Returns a pointer to if it found, or NULL otherwise. 682 mDNSlocal PosixNetworkInterface *SearchForInterfaceByName(mDNS *const m, const char *intfName) 683 { 684 PosixNetworkInterface *intf; 685 686 assert(m != NULL); 687 assert(intfName != NULL); 688 689 intf = (PosixNetworkInterface*)(m->HostInterfaces); 690 while ( (intf != NULL) && (strcmp(intf->intfName, intfName) != 0) ) 691 intf = (PosixNetworkInterface *)(intf->coreIntf.next); 692 693 return intf; 694 } 695 696 mDNSexport mDNSInterfaceID mDNSPlatformInterfaceIDfromInterfaceIndex(mDNS *const m, mDNSu32 index) 697 { 698 PosixNetworkInterface *intf; 699 700 assert(m != NULL); 701 702 if (index == kDNSServiceInterfaceIndexLocalOnly) return(mDNSInterface_LocalOnly); 703 704 intf = (PosixNetworkInterface*)(m->HostInterfaces); 705 while ( (intf != NULL) && (mDNSu32) intf->index != index) 706 intf = (PosixNetworkInterface *)(intf->coreIntf.next); 707 708 return (mDNSInterfaceID) intf; 709 } 710 711 mDNSexport mDNSu32 mDNSPlatformInterfaceIndexfromInterfaceID(mDNS *const m, mDNSInterfaceID id) 712 { 713 PosixNetworkInterface *intf; 714 715 assert(m != NULL); 716 717 if (id == mDNSInterface_LocalOnly) return(kDNSServiceInterfaceIndexLocalOnly); 718 719 intf = (PosixNetworkInterface*)(m->HostInterfaces); 720 while ( (intf != NULL) && (mDNSInterfaceID) intf != id) 721 intf = (PosixNetworkInterface *)(intf->coreIntf.next); 722 723 return intf ? intf->index : 0; 724 } 725 726 // Frees the specified PosixNetworkInterface structure. The underlying 727 // interface must have already been deregistered with the mDNS core. 728 mDNSlocal void FreePosixNetworkInterface(PosixNetworkInterface *intf) 729 { 730 assert(intf != NULL); 731 if (intf->intfName != NULL) free((void *)intf->intfName); 732 if (intf->multicastSocket4 != -1) assert(close(intf->multicastSocket4) == 0); 733 #if HAVE_IPV6 734 if (intf->multicastSocket6 != -1) assert(close(intf->multicastSocket6) == 0); 735 #endif 736 free(intf); 737 } 738 739 // Grab the first interface, deregister it, free it, and repeat until done. 740 mDNSlocal void ClearInterfaceList(mDNS *const m) 741 { 742 assert(m != NULL); 743 744 while (m->HostInterfaces) 745 { 746 PosixNetworkInterface *intf = (PosixNetworkInterface*)(m->HostInterfaces); 747 mDNS_DeregisterInterface(m, &intf->coreIntf, mDNSfalse); 748 if (gMDNSPlatformPosixVerboseLevel > 0) fprintf(stderr, "Deregistered interface %s\n", intf->intfName); 749 FreePosixNetworkInterface(intf); 750 } 751 num_registered_interfaces = 0; 752 num_pkts_accepted = 0; 753 num_pkts_rejected = 0; 754 } 755 756 // Sets up a send/receive socket. 757 // If mDNSIPPort port is non-zero, then it's a multicast socket on the specified interface 758 // If mDNSIPPort port is zero, then it's a randomly assigned port number, used for sending unicast queries 759 mDNSlocal int SetupSocket(struct sockaddr *intfAddr, mDNSIPPort port, int interfaceIndex, int *sktPtr) 760 { 761 int err = 0; 762 static const int kOn = 1; 763 static const int kIntTwoFiveFive = 255; 764 static const unsigned char kByteTwoFiveFive = 255; 765 const mDNSBool JoinMulticastGroup = (port.NotAnInteger != 0); 766 767 (void) interfaceIndex; // This parameter unused on plaforms that don't have IPv6 768 assert(intfAddr != NULL); 769 assert(sktPtr != NULL); 770 assert(*sktPtr == -1); 771 772 // Open the socket... 773 if (intfAddr->sa_family == AF_INET ) *sktPtr = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP); 774 #if HAVE_IPV6 775 else if (intfAddr->sa_family == AF_INET6) *sktPtr = socket(PF_INET6, SOCK_DGRAM, IPPROTO_UDP); 776 #endif 777 else return EINVAL; 778 779 if (*sktPtr < 0) { err = errno; perror("socket"); } 780 781 // ... with a shared UDP port, if it's for multicast receiving 782 if (err == 0 && port.NotAnInteger) 783 { 784 #if defined(SO_REUSEPORT) 785 err = setsockopt(*sktPtr, SOL_SOCKET, SO_REUSEPORT, &kOn, sizeof(kOn)); 786 #elif defined(SO_REUSEADDR) 787 err = setsockopt(*sktPtr, SOL_SOCKET, SO_REUSEADDR, &kOn, sizeof(kOn)); 788 #else 789 #error This platform has no way to avoid address busy errors on multicast. 790 #endif 791 if (err < 0) { err = errno; perror("setsockopt - SO_REUSExxxx"); } 792 } 793 794 // We want to receive destination addresses and interface identifiers. 795 if (intfAddr->sa_family == AF_INET) 796 { 797 struct ip_mreq imr; 798 struct sockaddr_in bindAddr; 799 if (err == 0) 800 { 801 #if defined(IP_PKTINFO) // Linux and Solaris 802 err = setsockopt(*sktPtr, IPPROTO_IP, IP_PKTINFO, &kOn, sizeof(kOn)); 803 if (err < 0) { err = errno; perror("setsockopt - IP_PKTINFO"); } 804 #elif defined(IP_RECVDSTADDR) || defined(IP_RECVIF) // BSD 805 #if defined(IP_RECVDSTADDR) 806 err = setsockopt(*sktPtr, IPPROTO_IP, IP_RECVDSTADDR, &kOn, sizeof(kOn)); 807 if (err < 0) { err = errno; perror("setsockopt - IP_RECVDSTADDR"); } 808 #endif 809 #if defined(IP_RECVIF) 810 if (err == 0) 811 { 812 err = setsockopt(*sktPtr, IPPROTO_IP, IP_RECVIF, &kOn, sizeof(kOn)); 813 if (err < 0) { err = errno; perror("setsockopt - IP_RECVIF"); } 814 } 815 #endif 816 #else 817 #warning This platform has no way to get the destination interface information -- will only work for single-homed hosts 818 #endif 819 } 820 #if defined(IP_RECVTTL) // Linux 821 if (err == 0) 822 { 823 setsockopt(*sktPtr, IPPROTO_IP, IP_RECVTTL, &kOn, sizeof(kOn)); 824 // We no longer depend on being able to get the received TTL, so don't worry if the option fails 825 } 826 #endif 827 828 // Add multicast group membership on this interface 829 if (err == 0 && JoinMulticastGroup) 830 { 831 imr.imr_multiaddr.s_addr = AllDNSLinkGroupv4.NotAnInteger; 832 imr.imr_interface = ((struct sockaddr_in*)intfAddr)->sin_addr; 833 err = setsockopt(*sktPtr, IPPROTO_IP, IP_ADD_MEMBERSHIP, &imr, sizeof(imr)); 834 if (err < 0) { err = errno; perror("setsockopt - IP_ADD_MEMBERSHIP"); } 835 } 836 837 // Specify outgoing interface too 838 if (err == 0 && JoinMulticastGroup) 839 { 840 err = setsockopt(*sktPtr, IPPROTO_IP, IP_MULTICAST_IF, &((struct sockaddr_in*)intfAddr)->sin_addr, sizeof(struct in_addr)); 841 if (err < 0) { err = errno; perror("setsockopt - IP_MULTICAST_IF"); } 842 } 843 844 // Per the mDNS spec, send unicast packets with TTL 255 845 if (err == 0) 846 { 847 err = setsockopt(*sktPtr, IPPROTO_IP, IP_TTL, &kIntTwoFiveFive, sizeof(kIntTwoFiveFive)); 848 if (err < 0) { err = errno; perror("setsockopt - IP_TTL"); } 849 } 850 851 // and multicast packets with TTL 255 too 852 // There's some debate as to whether IP_MULTICAST_TTL is an int or a byte so we just try both. 853 if (err == 0) 854 { 855 err = setsockopt(*sktPtr, IPPROTO_IP, IP_MULTICAST_TTL, &kByteTwoFiveFive, sizeof(kByteTwoFiveFive)); 856 if (err < 0 && errno == EINVAL) 857 err = setsockopt(*sktPtr, IPPROTO_IP, IP_MULTICAST_TTL, &kIntTwoFiveFive, sizeof(kIntTwoFiveFive)); 858 if (err < 0) { err = errno; perror("setsockopt - IP_MULTICAST_TTL"); } 859 } 860 861 // And start listening for packets 862 if (err == 0) 863 { 864 bindAddr.sin_family = AF_INET; 865 bindAddr.sin_port = port.NotAnInteger; 866 bindAddr.sin_addr.s_addr = INADDR_ANY; // Want to receive multicasts AND unicasts on this socket 867 err = bind(*sktPtr, (struct sockaddr *) &bindAddr, sizeof(bindAddr)); 868 if (err < 0) { err = errno; perror("bind"); fflush(stderr); } 869 } 870 } // endif (intfAddr->sa_family == AF_INET) 871 872 #if HAVE_IPV6 873 else if (intfAddr->sa_family == AF_INET6) 874 { 875 struct ipv6_mreq imr6; 876 struct sockaddr_in6 bindAddr6; 877 #if defined(IPV6_RECVPKTINFO) // Solaris 878 if (err == 0) 879 { 880 err = setsockopt(*sktPtr, IPPROTO_IPV6, IPV6_RECVPKTINFO, &kOn, sizeof(kOn)); 881 if (err < 0) { err = errno; perror("setsockopt - IPV6_PKTINFO"); } 882 } 883 884 #elif defined(IPV6_PKTINFO) 885 if (err == 0) 886 { 887 err = setsockopt(*sktPtr, IPPROTO_IPV6, IPV6_PKTINFO, &kOn, sizeof(kOn)); 888 if (err < 0) { err = errno; perror("setsockopt - IPV6_PKTINFO"); } 889 } 890 #else 891 #warning This platform has no way to get the destination interface information for IPv6 -- will only work for single-homed hosts 892 #endif 893 #if defined(IPV6_RECVHOPLIMIT) // Solaris 894 if (err == 0) 895 { 896 err = setsockopt(*sktPtr, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &kOn, sizeof(kOn)); 897 if (err < 0) { err = errno; perror("setsockopt - IPV6_HOPLIMIT"); } 898 } 899 900 #elif defined(IPV6_HOPLIMIT) 901 if (err == 0) 902 { 903 err = setsockopt(*sktPtr, IPPROTO_IPV6, IPV6_HOPLIMIT, &kOn, sizeof(kOn)); 904 if (err < 0) { err = errno; perror("setsockopt - IPV6_HOPLIMIT"); } 905 } 906 #endif 907 908 // Add multicast group membership on this interface 909 if (err == 0 && JoinMulticastGroup) 910 { 911 imr6.ipv6mr_multiaddr = *(const struct in6_addr*)&AllDNSLinkGroupv6; 912 imr6.ipv6mr_interface = interfaceIndex; 913 //LogMsg("Joining %.16a on %d", &imr6.ipv6mr_multiaddr, imr6.ipv6mr_interface); 914 err = setsockopt(*sktPtr, IPPROTO_IPV6, IPV6_JOIN_GROUP, &imr6, sizeof(imr6)); 915 if (err < 0) 916 { 917 err = errno; 918 verbosedebugf("IPV6_JOIN_GROUP %.16a on %d failed.\n", &imr6.ipv6mr_multiaddr, imr6.ipv6mr_interface); 919 perror("setsockopt - IPV6_JOIN_GROUP"); 920 } 921 } 922 923 // Specify outgoing interface too 924 if (err == 0 && JoinMulticastGroup) 925 { 926 u_int multicast_if = interfaceIndex; 927 err = setsockopt(*sktPtr, IPPROTO_IPV6, IPV6_MULTICAST_IF, &multicast_if, sizeof(multicast_if)); 928 if (err < 0) { err = errno; perror("setsockopt - IPV6_MULTICAST_IF"); } 929 } 930 931 // We want to receive only IPv6 packets on this socket. 932 // Without this option, we may get IPv4 addresses as mapped addresses. 933 if (err == 0) 934 { 935 err = setsockopt(*sktPtr, IPPROTO_IPV6, IPV6_V6ONLY, &kOn, sizeof(kOn)); 936 if (err < 0) { err = errno; perror("setsockopt - IPV6_V6ONLY"); } 937 } 938 939 // Per the mDNS spec, send unicast packets with TTL 255 940 if (err == 0) 941 { 942 err = setsockopt(*sktPtr, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &kIntTwoFiveFive, sizeof(kIntTwoFiveFive)); 943 if (err < 0) { err = errno; perror("setsockopt - IPV6_UNICAST_HOPS"); } 944 } 945 946 // and multicast packets with TTL 255 too 947 // There's some debate as to whether IPV6_MULTICAST_HOPS is an int or a byte so we just try both. 948 if (err == 0) 949 { 950 err = setsockopt(*sktPtr, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &kByteTwoFiveFive, sizeof(kByteTwoFiveFive)); 951 if (err < 0 && errno == EINVAL) 952 err = setsockopt(*sktPtr, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &kIntTwoFiveFive, sizeof(kIntTwoFiveFive)); 953 if (err < 0) { err = errno; perror("setsockopt - IPV6_MULTICAST_HOPS"); } 954 } 955 956 // And start listening for packets 957 if (err == 0) 958 { 959 mDNSPlatformMemZero(&bindAddr6, sizeof(bindAddr6)); 960 #ifndef NOT_HAVE_SA_LEN 961 bindAddr6.sin6_len = sizeof(bindAddr6); 962 #endif 963 bindAddr6.sin6_family = AF_INET6; 964 bindAddr6.sin6_port = port.NotAnInteger; 965 bindAddr6.sin6_flowinfo = 0; 966 bindAddr6.sin6_addr = in6addr_any; // Want to receive multicasts AND unicasts on this socket 967 bindAddr6.sin6_scope_id = 0; 968 err = bind(*sktPtr, (struct sockaddr *) &bindAddr6, sizeof(bindAddr6)); 969 if (err < 0) { err = errno; perror("bind"); fflush(stderr); } 970 } 971 } // endif (intfAddr->sa_family == AF_INET6) 972 #endif 973 974 // Set the socket to non-blocking. 975 if (err == 0) 976 { 977 err = fcntl(*sktPtr, F_GETFL, 0); 978 if (err < 0) err = errno; 979 else 980 { 981 err = fcntl(*sktPtr, F_SETFL, err | O_NONBLOCK); 982 if (err < 0) err = errno; 983 } 984 } 985 986 // Clean up 987 if (err != 0 && *sktPtr != -1) { assert(close(*sktPtr) == 0); *sktPtr = -1; } 988 assert( (err == 0) == (*sktPtr != -1) ); 989 return err; 990 } 991 992 // Creates a PosixNetworkInterface for the interface whose IP address is 993 // intfAddr and whose name is intfName and registers it with mDNS core. 994 mDNSlocal int SetupOneInterface(mDNS *const m, struct sockaddr *intfAddr, struct sockaddr *intfMask, const char *intfName, int intfIndex) 995 { 996 int err = 0; 997 PosixNetworkInterface *intf; 998 PosixNetworkInterface *alias = NULL; 999 1000 assert(m != NULL); 1001 assert(intfAddr != NULL); 1002 assert(intfName != NULL); 1003 assert(intfMask != NULL); 1004 1005 // Allocate the interface structure itself. 1006 intf = (PosixNetworkInterface*)malloc(sizeof(*intf)); 1007 if (intf == NULL) { assert(0); err = ENOMEM; } 1008 1009 // And make a copy of the intfName. 1010 if (err == 0) 1011 { 1012 intf->intfName = strdup(intfName); 1013 if (intf->intfName == NULL) { assert(0); err = ENOMEM; } 1014 } 1015 1016 if (err == 0) 1017 { 1018 // Set up the fields required by the mDNS core. 1019 SockAddrTomDNSAddr(intfAddr, &intf->coreIntf.ip, NULL); 1020 SockAddrTomDNSAddr(intfMask, &intf->coreIntf.mask, NULL); 1021 //LogMsg("SetupOneInterface: %#a %#a", &intf->coreIntf.ip, &intf->coreIntf.mask); 1022 strncpy(intf->coreIntf.ifname, intfName, sizeof(intf->coreIntf.ifname)); 1023 intf->coreIntf.ifname[sizeof(intf->coreIntf.ifname)-1] = 0; 1024 intf->coreIntf.Advertise = m->AdvertiseLocalAddresses; 1025 intf->coreIntf.McastTxRx = mDNStrue; 1026 1027 // Set up the extra fields in PosixNetworkInterface. 1028 assert(intf->intfName != NULL); // intf->intfName already set up above 1029 intf->index = intfIndex; 1030 intf->multicastSocket4 = -1; 1031 #if HAVE_IPV6 1032 intf->multicastSocket6 = -1; 1033 #endif 1034 alias = SearchForInterfaceByName(m, intf->intfName); 1035 if (alias == NULL) alias = intf; 1036 intf->coreIntf.InterfaceID = (mDNSInterfaceID)alias; 1037 1038 if (alias != intf) 1039 debugf("SetupOneInterface: %s %#a is an alias of %#a", intfName, &intf->coreIntf.ip, &alias->coreIntf.ip); 1040 } 1041 1042 // Set up the multicast socket 1043 if (err == 0) 1044 { 1045 if (alias->multicastSocket4 == -1 && intfAddr->sa_family == AF_INET) 1046 err = SetupSocket(intfAddr, MulticastDNSPort, intf->index, &alias->multicastSocket4); 1047 #if HAVE_IPV6 1048 else if (alias->multicastSocket6 == -1 && intfAddr->sa_family == AF_INET6) 1049 err = SetupSocket(intfAddr, MulticastDNSPort, intf->index, &alias->multicastSocket6); 1050 #endif 1051 } 1052 1053 // The interface is all ready to go, let's register it with the mDNS core. 1054 if (err == 0) 1055 err = mDNS_RegisterInterface(m, &intf->coreIntf, mDNSfalse); 1056 1057 // Clean up. 1058 if (err == 0) 1059 { 1060 num_registered_interfaces++; 1061 debugf("SetupOneInterface: %s %#a Registered", intf->intfName, &intf->coreIntf.ip); 1062 if (gMDNSPlatformPosixVerboseLevel > 0) 1063 fprintf(stderr, "Registered interface %s\n", intf->intfName); 1064 } 1065 else 1066 { 1067 // Use intfName instead of intf->intfName in the next line to avoid dereferencing NULL. 1068 debugf("SetupOneInterface: %s %#a failed to register %d", intfName, &intf->coreIntf.ip, err); 1069 if (intf) { FreePosixNetworkInterface(intf); intf = NULL; } 1070 } 1071 1072 assert( (err == 0) == (intf != NULL) ); 1073 1074 return err; 1075 } 1076 1077 // Call get_ifi_info() to obtain a list of active interfaces and call SetupOneInterface() on each one. 1078 mDNSlocal int SetupInterfaceList(mDNS *const m) 1079 { 1080 mDNSBool foundav4 = mDNSfalse; 1081 int err = 0; 1082 struct ifi_info *intfList = get_ifi_info(AF_INET, mDNStrue); 1083 struct ifi_info *firstLoopback = NULL; 1084 1085 assert(m != NULL); 1086 debugf("SetupInterfaceList"); 1087 1088 if (intfList == NULL) err = ENOENT; 1089 1090 #if HAVE_IPV6 1091 if (err == 0) /* Link the IPv6 list to the end of the IPv4 list */ 1092 { 1093 struct ifi_info **p = &intfList; 1094 while (*p) p = &(*p)->ifi_next; 1095 *p = get_ifi_info(AF_INET6, mDNStrue); 1096 } 1097 #endif 1098 1099 if (err == 0) 1100 { 1101 struct ifi_info *i = intfList; 1102 while (i) 1103 { 1104 if ( ((i->ifi_addr->sa_family == AF_INET) 1105 #if HAVE_IPV6 1106 || (i->ifi_addr->sa_family == AF_INET6) 1107 #endif 1108 ) && (i->ifi_flags & IFF_UP) && !(i->ifi_flags & IFF_POINTOPOINT) ) 1109 { 1110 if (i->ifi_flags & IFF_LOOPBACK) 1111 { 1112 if (firstLoopback == NULL) 1113 firstLoopback = i; 1114 } 1115 else 1116 { 1117 if (SetupOneInterface(m, i->ifi_addr, i->ifi_netmask, i->ifi_name, i->ifi_index) == 0) 1118 if (i->ifi_addr->sa_family == AF_INET) 1119 foundav4 = mDNStrue; 1120 } 1121 } 1122 i = i->ifi_next; 1123 } 1124 1125 // If we found no normal interfaces but we did find a loopback interface, register the 1126 // loopback interface. This allows self-discovery if no interfaces are configured. 1127 // Temporary workaround: Multicast loopback on IPv6 interfaces appears not to work. 1128 // In the interim, we skip loopback interface only if we found at least one v4 interface to use 1129 // if ( (m->HostInterfaces == NULL) && (firstLoopback != NULL) ) 1130 if ( !foundav4 && firstLoopback ) 1131 (void) SetupOneInterface(m, firstLoopback->ifi_addr, firstLoopback->ifi_netmask, firstLoopback->ifi_name, firstLoopback->ifi_index); 1132 } 1133 1134 // Clean up. 1135 if (intfList != NULL) free_ifi_info(intfList); 1136 return err; 1137 } 1138 1139 #if USES_NETLINK 1140 1141 // See <http://www.faqs.org/rfcs/rfc3549.html> for a description of NetLink 1142 1143 // Open a socket that will receive interface change notifications 1144 mDNSlocal mStatus OpenIfNotifySocket( int *pFD) 1145 { 1146 mStatus err = mStatus_NoError; 1147 struct sockaddr_nl snl; 1148 int sock; 1149 int ret; 1150 1151 sock = socket( AF_NETLINK, SOCK_RAW, NETLINK_ROUTE); 1152 if (sock < 0) 1153 return errno; 1154 1155 // Configure read to be non-blocking because inbound msg size is not known in advance 1156 (void) fcntl( sock, F_SETFL, O_NONBLOCK); 1157 1158 /* Subscribe the socket to Link & IP addr notifications. */ 1159 bzero( &snl, sizeof snl); 1160 snl.nl_family = AF_NETLINK; 1161 snl.nl_groups = RTMGRP_LINK | RTMGRP_IPV4_IFADDR; 1162 ret = bind( sock, (struct sockaddr *) &snl, sizeof snl); 1163 if ( 0 == ret) 1164 *pFD = sock; 1165 else 1166 err = errno; 1167 1168 return err; 1169 } 1170 1171 #if MDNS_DEBUGMSGS 1172 mDNSlocal void PrintNetLinkMsg( const struct nlmsghdr *pNLMsg) 1173 { 1174 const char *kNLMsgTypes[] = { "", "NLMSG_NOOP", "NLMSG_ERROR", "NLMSG_DONE", "NLMSG_OVERRUN" }; 1175 const char *kNLRtMsgTypes[] = { "RTM_NEWLINK", "RTM_DELLINK", "RTM_GETLINK", "RTM_NEWADDR", "RTM_DELADDR", "RTM_GETADDR" }; 1176 1177 printf( "nlmsghdr len=%d, type=%s, flags=0x%x\n", pNLMsg->nlmsg_len, 1178 pNLMsg->nlmsg_type < RTM_BASE ? kNLMsgTypes[ pNLMsg->nlmsg_type] : kNLRtMsgTypes[ pNLMsg->nlmsg_type - RTM_BASE], 1179 pNLMsg->nlmsg_flags); 1180 1181 if ( RTM_NEWLINK <= pNLMsg->nlmsg_type && pNLMsg->nlmsg_type <= RTM_GETLINK) 1182 { 1183 struct ifinfomsg *pIfInfo = (struct ifinfomsg*) NLMSG_DATA( pNLMsg); 1184 printf( "ifinfomsg family=%d, type=%d, index=%d, flags=0x%x, change=0x%x\n", pIfInfo->ifi_family, 1185 pIfInfo->ifi_type, pIfInfo->ifi_index, pIfInfo->ifi_flags, pIfInfo->ifi_change); 1186 1187 } 1188 else if ( RTM_NEWADDR <= pNLMsg->nlmsg_type && pNLMsg->nlmsg_type <= RTM_GETADDR) 1189 { 1190 struct ifaddrmsg *pIfAddr = (struct ifaddrmsg*) NLMSG_DATA( pNLMsg); 1191 printf( "ifaddrmsg family=%d, index=%d, flags=0x%x\n", pIfAddr->ifa_family, 1192 pIfAddr->ifa_index, pIfAddr->ifa_flags); 1193 } 1194 printf( "\n"); 1195 } 1196 #endif 1197 1198 mDNSlocal mDNSu32 ProcessRoutingNotification( int sd) 1199 // Read through the messages on sd and if any indicate that any interface records should 1200 // be torn down and rebuilt, return affected indices as a bitmask. Otherwise return 0. 1201 { 1202 ssize_t readCount; 1203 char buff[ 4096]; 1204 struct nlmsghdr *pNLMsg = (struct nlmsghdr*) buff; 1205 mDNSu32 result = 0; 1206 1207 // The structure here is more complex than it really ought to be because, 1208 // unfortunately, there's no good way to size a buffer in advance large 1209 // enough to hold all pending data and so avoid message fragmentation. 1210 // (Note that FIONREAD is not supported on AF_NETLINK.) 1211 1212 readCount = read( sd, buff, sizeof buff); 1213 while ( 1) 1214 { 1215 // Make sure we've got an entire nlmsghdr in the buffer, and payload, too. 1216 // If not, discard already-processed messages in buffer and read more data. 1217 if ( ( (char*) &pNLMsg[1] > ( buff + readCount)) || // i.e. *pNLMsg extends off end of buffer 1218 ( (char*) pNLMsg + pNLMsg->nlmsg_len > ( buff + readCount))) 1219 { 1220 if ( buff < (char*) pNLMsg) // we have space to shuffle 1221 { 1222 // discard processed data 1223 readCount -= ( (char*) pNLMsg - buff); 1224 memmove( buff, pNLMsg, readCount); 1225 pNLMsg = (struct nlmsghdr*) buff; 1226 1227 // read more data 1228 readCount += read( sd, buff + readCount, sizeof buff - readCount); 1229 continue; // spin around and revalidate with new readCount 1230 } 1231 else 1232 break; // Otherwise message does not fit in buffer 1233 } 1234 1235 #if MDNS_DEBUGMSGS 1236 PrintNetLinkMsg( pNLMsg); 1237 #endif 1238 1239 // Process the NetLink message 1240 if ( pNLMsg->nlmsg_type == RTM_GETLINK || pNLMsg->nlmsg_type == RTM_NEWLINK) 1241 result |= 1 << ((struct ifinfomsg*) NLMSG_DATA( pNLMsg))->ifi_index; 1242 else if ( pNLMsg->nlmsg_type == RTM_DELADDR || pNLMsg->nlmsg_type == RTM_NEWADDR) 1243 result |= 1 << ((struct ifaddrmsg*) NLMSG_DATA( pNLMsg))->ifa_index; 1244 1245 // Advance pNLMsg to the next message in the buffer 1246 if ( ( pNLMsg->nlmsg_flags & NLM_F_MULTI) != 0 && pNLMsg->nlmsg_type != NLMSG_DONE) 1247 { 1248 ssize_t len = readCount - ( (char*)pNLMsg - buff); 1249 pNLMsg = NLMSG_NEXT( pNLMsg, len); 1250 } 1251 else 1252 break; // all done! 1253 } 1254 1255 return result; 1256 } 1257 1258 #else // USES_NETLINK 1259 1260 // Open a socket that will receive interface change notifications 1261 mDNSlocal mStatus OpenIfNotifySocket( int *pFD) 1262 { 1263 *pFD = socket( AF_ROUTE, SOCK_RAW, 0); 1264 1265 if ( *pFD < 0) 1266 return mStatus_UnknownErr; 1267 1268 // Configure read to be non-blocking because inbound msg size is not known in advance 1269 (void) fcntl( *pFD, F_SETFL, O_NONBLOCK); 1270 1271 return mStatus_NoError; 1272 } 1273 1274 #if MDNS_DEBUGMSGS 1275 mDNSlocal void PrintRoutingSocketMsg( const struct ifa_msghdr *pRSMsg) 1276 { 1277 const char *kRSMsgTypes[] = { "", "RTM_ADD", "RTM_DELETE", "RTM_CHANGE", "RTM_GET", "RTM_LOSING", 1278 "RTM_REDIRECT", "RTM_MISS", "RTM_LOCK", "RTM_OLDADD", "RTM_OLDDEL", "RTM_RESOLVE", 1279 "RTM_NEWADDR", "RTM_DELADDR", "RTM_IFINFO", "RTM_NEWMADDR", "RTM_DELMADDR" }; 1280 1281 int index = pRSMsg->ifam_type == RTM_IFINFO ? ((struct if_msghdr*) pRSMsg)->ifm_index : pRSMsg->ifam_index; 1282 1283 printf( "ifa_msghdr len=%d, type=%s, index=%d\n", pRSMsg->ifam_msglen, kRSMsgTypes[ pRSMsg->ifam_type], index); 1284 } 1285 #endif 1286 1287 mDNSlocal mDNSu32 ProcessRoutingNotification( int sd) 1288 // Read through the messages on sd and if any indicate that any interface records should 1289 // be torn down and rebuilt, return affected indices as a bitmask. Otherwise return 0. 1290 { 1291 ssize_t readCount; 1292 char buff[ 4096]; 1293 struct ifa_msghdr *pRSMsg = (struct ifa_msghdr*) buff; 1294 mDNSu32 result = 0; 1295 1296 readCount = read( sd, buff, sizeof buff); 1297 if ( readCount < (ssize_t) sizeof( struct ifa_msghdr)) 1298 return mStatus_UnsupportedErr; // cannot decipher message 1299 1300 #if MDNS_DEBUGMSGS 1301 PrintRoutingSocketMsg( pRSMsg); 1302 #endif 1303 1304 // Process the message 1305 if ( pRSMsg->ifam_type == RTM_NEWADDR || pRSMsg->ifam_type == RTM_DELADDR || 1306 pRSMsg->ifam_type == RTM_IFINFO) 1307 { 1308 if ( pRSMsg->ifam_type == RTM_IFINFO) 1309 result |= 1 << ((struct if_msghdr*) pRSMsg)->ifm_index; 1310 else 1311 result |= 1 << pRSMsg->ifam_index; 1312 } 1313 1314 return result; 1315 } 1316 1317 #endif // USES_NETLINK 1318 1319 // Called when data appears on interface change notification socket 1320 mDNSlocal void InterfaceChangeCallback( void *context) 1321 { 1322 IfChangeRec *pChgRec = (IfChangeRec*) context; 1323 fd_set readFDs; 1324 mDNSu32 changedInterfaces = 0; 1325 struct timeval zeroTimeout = { 0, 0 }; 1326 1327 FD_ZERO( &readFDs); 1328 FD_SET( pChgRec->NotifySD, &readFDs); 1329 1330 do 1331 { 1332 changedInterfaces |= ProcessRoutingNotification( pChgRec->NotifySD); 1333 } 1334 while ( 0 < select( pChgRec->NotifySD + 1, &readFDs, (fd_set*) NULL, (fd_set*) NULL, &zeroTimeout)); 1335 1336 // Currently we rebuild the entire interface list whenever any interface change is 1337 // detected. If this ever proves to be a performance issue in a multi-homed 1338 // configuration, more care should be paid to changedInterfaces. 1339 if ( changedInterfaces) 1340 mDNSPlatformPosixRefreshInterfaceList( pChgRec->mDNS); 1341 } 1342 1343 // Register with either a Routing Socket or RtNetLink to listen for interface changes. 1344 mDNSlocal mStatus WatchForInterfaceChange(mDNS *const m) 1345 { 1346 mStatus err; 1347 IfChangeRec *pChgRec; 1348 1349 pChgRec = (IfChangeRec*) mDNSPlatformMemAllocate( sizeof *pChgRec); 1350 if ( pChgRec == NULL) 1351 return mStatus_NoMemoryErr; 1352 1353 pChgRec->mDNS = m; 1354 err = OpenIfNotifySocket( &pChgRec->NotifySD); 1355 if ( err == 0) 1356 err = mDNSPosixAddFDToEventLoop( pChgRec->NotifySD, InterfaceChangeCallback, pChgRec); 1357 1358 return err; 1359 } 1360 1361 // Test to see if we're the first client running on UDP port 5353, by trying to bind to 5353 without using SO_REUSEPORT. 1362 // If we fail, someone else got here first. That's not a big problem; we can share the port for multicast responses -- 1363 // we just need to be aware that we shouldn't expect to successfully receive unicast UDP responses. 1364 mDNSlocal mDNSBool mDNSPlatformInit_CanReceiveUnicast(void) 1365 { 1366 int err; 1367 int s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); 1368 struct sockaddr_in s5353; 1369 s5353.sin_family = AF_INET; 1370 s5353.sin_port = MulticastDNSPort.NotAnInteger; 1371 s5353.sin_addr.s_addr = 0; 1372 err = bind(s, (struct sockaddr *)&s5353, sizeof(s5353)); 1373 close(s); 1374 if (err) debugf("No unicast UDP responses"); 1375 else debugf("Unicast UDP responses okay"); 1376 return(err == 0); 1377 } 1378 1379 // mDNS core calls this routine to initialise the platform-specific data. 1380 mDNSexport mStatus mDNSPlatformInit(mDNS *const m) 1381 { 1382 int err = 0; 1383 struct sockaddr sa; 1384 assert(m != NULL); 1385 1386 if (mDNSPlatformInit_CanReceiveUnicast()) m->CanReceiveUnicastOn5353 = mDNStrue; 1387 1388 // Tell mDNS core the names of this machine. 1389 1390 // Set up the nice label 1391 m->nicelabel.c[0] = 0; 1392 GetUserSpecifiedFriendlyComputerName(&m->nicelabel); 1393 if (m->nicelabel.c[0] == 0) MakeDomainLabelFromLiteralString(&m->nicelabel, "Computer"); 1394 1395 // Set up the RFC 1034-compliant label 1396 m->hostlabel.c[0] = 0; 1397 GetUserSpecifiedRFC1034ComputerName(&m->hostlabel); 1398 if (m->hostlabel.c[0] == 0) MakeDomainLabelFromLiteralString(&m->hostlabel, "Computer"); 1399 1400 mDNS_SetFQDN(m); 1401 1402 sa.sa_family = AF_INET; 1403 m->p->unicastSocket4 = -1; 1404 if (err == mStatus_NoError) err = SetupSocket(&sa, zeroIPPort, 0, &m->p->unicastSocket4); 1405 #if HAVE_IPV6 1406 sa.sa_family = AF_INET6; 1407 m->p->unicastSocket6 = -1; 1408 if (err == mStatus_NoError) err = SetupSocket(&sa, zeroIPPort, 0, &m->p->unicastSocket6); 1409 #endif 1410 1411 // Tell mDNS core about the network interfaces on this machine. 1412 if (err == mStatus_NoError) err = SetupInterfaceList(m); 1413 1414 // Tell mDNS core about DNS Servers 1415 if (err == mStatus_NoError) ParseDNSServers(m, uDNS_SERVERS_FILE); 1416 1417 if (err == mStatus_NoError) 1418 { 1419 err = WatchForInterfaceChange(m); 1420 // Failure to observe interface changes is non-fatal. 1421 if ( err != mStatus_NoError) 1422 { 1423 fprintf(stderr, "mDNS(%d) WARNING: Unable to detect interface changes (%d).\n", getpid(), err); 1424 err = mStatus_NoError; 1425 } 1426 } 1427 1428 // We don't do asynchronous initialization on the Posix platform, so by the time 1429 // we get here the setup will already have succeeded or failed. If it succeeded, 1430 // we should just call mDNSCoreInitComplete() immediately. 1431 if (err == mStatus_NoError) 1432 mDNSCoreInitComplete(m, mStatus_NoError); 1433 1434 return PosixErrorToStatus(err); 1435 } 1436 1437 // mDNS core calls this routine to clean up the platform-specific data. 1438 // In our case all we need to do is to tear down every network interface. 1439 mDNSexport void mDNSPlatformClose(mDNS *const m) 1440 { 1441 assert(m != NULL); 1442 ClearInterfaceList(m); 1443 if (m->p->unicastSocket4 != -1) assert(close(m->p->unicastSocket4) == 0); 1444 #if HAVE_IPV6 1445 if (m->p->unicastSocket6 != -1) assert(close(m->p->unicastSocket6) == 0); 1446 #endif 1447 } 1448 1449 mDNSexport mStatus mDNSPlatformPosixRefreshInterfaceList(mDNS *const m) 1450 { 1451 int err; 1452 ClearInterfaceList(m); 1453 err = SetupInterfaceList(m); 1454 return PosixErrorToStatus(err); 1455 } 1456 1457 #if COMPILER_LIKES_PRAGMA_MARK 1458 #pragma mark ***** Locking 1459 #endif 1460 1461 // On the Posix platform, locking is a no-op because we only ever enter 1462 // mDNS core on the main thread. 1463 1464 // mDNS core calls this routine when it wants to prevent 1465 // the platform from reentering mDNS core code. 1466 mDNSexport void mDNSPlatformLock (const mDNS *const m) 1467 { 1468 (void) m; // Unused 1469 } 1470 1471 // mDNS core calls this routine when it release the lock taken by 1472 // mDNSPlatformLock and allow the platform to reenter mDNS core code. 1473 mDNSexport void mDNSPlatformUnlock (const mDNS *const m) 1474 { 1475 (void) m; // Unused 1476 } 1477 1478 #if COMPILER_LIKES_PRAGMA_MARK 1479 #pragma mark ***** Strings 1480 #endif 1481 1482 // mDNS core calls this routine to copy C strings. 1483 // On the Posix platform this maps directly to the ANSI C strcpy. 1484 mDNSexport void mDNSPlatformStrCopy(const void *src, void *dst) 1485 { 1486 strcpy((char *)dst, (char *)src); 1487 } 1488 1489 // mDNS core calls this routine to get the length of a C string. 1490 // On the Posix platform this maps directly to the ANSI C strlen. 1491 mDNSexport mDNSu32 mDNSPlatformStrLen (const void *src) 1492 { 1493 return strlen((char*)src); 1494 } 1495 1496 // mDNS core calls this routine to copy memory. 1497 // On the Posix platform this maps directly to the ANSI C memcpy. 1498 mDNSexport void mDNSPlatformMemCopy(const void *src, void *dst, mDNSu32 len) 1499 { 1500 memcpy(dst, src, len); 1501 } 1502 1503 // mDNS core calls this routine to test whether blocks of memory are byte-for-byte 1504 // identical. On the Posix platform this is a simple wrapper around ANSI C memcmp. 1505 mDNSexport mDNSBool mDNSPlatformMemSame(const void *src, const void *dst, mDNSu32 len) 1506 { 1507 return memcmp(dst, src, len) == 0; 1508 } 1509 1510 // mDNS core calls this routine to clear blocks of memory. 1511 // On the Posix platform this is a simple wrapper around ANSI C memset. 1512 mDNSexport void mDNSPlatformMemZero( void *dst, mDNSu32 len) 1513 { 1514 memset(dst, 0, len); 1515 } 1516 1517 mDNSexport void * mDNSPlatformMemAllocate(mDNSu32 len) { return(malloc(len)); } 1518 mDNSexport void mDNSPlatformMemFree (void *mem) { free(mem); } 1519 1520 mDNSexport mDNSu32 mDNSPlatformRandomSeed(void) 1521 { 1522 struct timeval tv; 1523 gettimeofday(&tv, NULL); 1524 return(tv.tv_usec); 1525 } 1526 1527 mDNSexport mDNSs32 mDNSPlatformOneSecond = 1024; 1528 1529 mDNSexport mStatus mDNSPlatformTimeInit(void) 1530 { 1531 // No special setup is required on Posix -- we just use gettimeofday(); 1532 // This is not really safe, because gettimeofday can go backwards if the user manually changes the date or time 1533 // We should find a better way to do this 1534 return(mStatus_NoError); 1535 } 1536 1537 mDNSexport mDNSs32 mDNSPlatformRawTime() 1538 { 1539 struct timeval tv; 1540 gettimeofday(&tv, NULL); 1541 // tv.tv_sec is seconds since 1st January 1970 (GMT, with no adjustment for daylight savings time) 1542 // tv.tv_usec is microseconds since the start of this second (i.e. values 0 to 999999) 1543 // We use the lower 22 bits of tv.tv_sec for the top 22 bits of our result 1544 // 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. 1545 // This gives us a proper modular (cyclic) counter that has a resolution of roughly 1ms (actually 1/1024 second) 1546 // and correctly cycles every 2^22 seconds (4194304 seconds = approx 48 days). 1547 return( (tv.tv_sec << 10) | (tv.tv_usec * 16 / 15625) ); 1548 } 1549 1550 mDNSexport mDNSs32 mDNSPlatformUTC(void) 1551 { 1552 return time(NULL); 1553 } 1554 1555 mDNSlocal void mDNSPosixAddToFDSet(int *nfds, fd_set *readfds, int s) 1556 { 1557 if (*nfds < s + 1) *nfds = s + 1; 1558 FD_SET(s, readfds); 1559 } 1560 1561 mDNSexport void mDNSPosixGetFDSet(mDNS *m, int *nfds, fd_set *readfds, struct timeval *timeout) 1562 { 1563 mDNSs32 ticks; 1564 struct timeval interval; 1565 1566 // 1. Call mDNS_Execute() to let mDNSCore do what it needs to do 1567 mDNSs32 nextevent = mDNS_Execute(m); 1568 1569 // 2. Build our list of active file descriptors 1570 PosixNetworkInterface *info = (PosixNetworkInterface *)(m->HostInterfaces); 1571 if (m->p->unicastSocket4 != -1) mDNSPosixAddToFDSet(nfds, readfds, m->p->unicastSocket4); 1572 #if HAVE_IPV6 1573 if (m->p->unicastSocket6 != -1) mDNSPosixAddToFDSet(nfds, readfds, m->p->unicastSocket6); 1574 #endif 1575 while (info) 1576 { 1577 if (info->multicastSocket4 != -1) mDNSPosixAddToFDSet(nfds, readfds, info->multicastSocket4); 1578 #if HAVE_IPV6 1579 if (info->multicastSocket6 != -1) mDNSPosixAddToFDSet(nfds, readfds, info->multicastSocket6); 1580 #endif 1581 info = (PosixNetworkInterface *)(info->coreIntf.next); 1582 } 1583 1584 // 3. Calculate the time remaining to the next scheduled event (in struct timeval format) 1585 ticks = nextevent - mDNS_TimeNow(m); 1586 if (ticks < 1) ticks = 1; 1587 interval.tv_sec = ticks >> 10; // The high 22 bits are seconds 1588 interval.tv_usec = ((ticks & 0x3FF) * 15625) / 16; // The low 10 bits are 1024ths 1589 1590 // 4. If client's proposed timeout is more than what we want, then reduce it 1591 if (timeout->tv_sec > interval.tv_sec || 1592 (timeout->tv_sec == interval.tv_sec && timeout->tv_usec > interval.tv_usec)) 1593 *timeout = interval; 1594 } 1595 1596 mDNSexport void mDNSPosixProcessFDSet(mDNS *const m, fd_set *readfds) 1597 { 1598 PosixNetworkInterface *info; 1599 assert(m != NULL); 1600 assert(readfds != NULL); 1601 info = (PosixNetworkInterface *)(m->HostInterfaces); 1602 1603 if (m->p->unicastSocket4 != -1 && FD_ISSET(m->p->unicastSocket4, readfds)) 1604 { 1605 FD_CLR(m->p->unicastSocket4, readfds); 1606 SocketDataReady(m, NULL, m->p->unicastSocket4); 1607 } 1608 #if HAVE_IPV6 1609 if (m->p->unicastSocket6 != -1 && FD_ISSET(m->p->unicastSocket6, readfds)) 1610 { 1611 FD_CLR(m->p->unicastSocket6, readfds); 1612 SocketDataReady(m, NULL, m->p->unicastSocket6); 1613 } 1614 #endif 1615 1616 while (info) 1617 { 1618 if (info->multicastSocket4 != -1 && FD_ISSET(info->multicastSocket4, readfds)) 1619 { 1620 FD_CLR(info->multicastSocket4, readfds); 1621 SocketDataReady(m, info, info->multicastSocket4); 1622 } 1623 #if HAVE_IPV6 1624 if (info->multicastSocket6 != -1 && FD_ISSET(info->multicastSocket6, readfds)) 1625 { 1626 FD_CLR(info->multicastSocket6, readfds); 1627 SocketDataReady(m, info, info->multicastSocket6); 1628 } 1629 #endif 1630 info = (PosixNetworkInterface *)(info->coreIntf.next); 1631 } 1632 } 1633 1634 // update gMaxFD 1635 mDNSlocal void DetermineMaxEventFD( void ) 1636 { 1637 PosixEventSource *iSource; 1638 1639 gMaxFD = 0; 1640 for ( iSource=(PosixEventSource*)gEventSources.Head; iSource; iSource = iSource->Next) 1641 if ( gMaxFD < iSource->fd) 1642 gMaxFD = iSource->fd; 1643 } 1644 1645 // Add a file descriptor to the set that mDNSPosixRunEventLoopOnce() listens to. 1646 mStatus mDNSPosixAddFDToEventLoop( int fd, mDNSPosixEventCallback callback, void *context) 1647 { 1648 PosixEventSource *newSource; 1649 1650 if ( gEventSources.LinkOffset == 0) 1651 InitLinkedList( &gEventSources, offsetof( PosixEventSource, Next)); 1652 1653 if ( fd >= (int) FD_SETSIZE || fd < 0) 1654 return mStatus_UnsupportedErr; 1655 if ( callback == NULL) 1656 return mStatus_BadParamErr; 1657 1658 newSource = (PosixEventSource*) malloc( sizeof *newSource); 1659 if ( NULL == newSource) 1660 return mStatus_NoMemoryErr; 1661 1662 newSource->Callback = callback; 1663 newSource->Context = context; 1664 newSource->fd = fd; 1665 1666 AddToTail( &gEventSources, newSource); 1667 FD_SET( fd, &gEventFDs); 1668 1669 DetermineMaxEventFD(); 1670 1671 return mStatus_NoError; 1672 } 1673 1674 // Remove a file descriptor from the set that mDNSPosixRunEventLoopOnce() listens to. 1675 mStatus mDNSPosixRemoveFDFromEventLoop( int fd) 1676 { 1677 PosixEventSource *iSource; 1678 1679 for ( iSource=(PosixEventSource*)gEventSources.Head; iSource; iSource = iSource->Next) 1680 { 1681 if ( fd == iSource->fd) 1682 { 1683 FD_CLR( fd, &gEventFDs); 1684 RemoveFromList( &gEventSources, iSource); 1685 free( iSource); 1686 DetermineMaxEventFD(); 1687 return mStatus_NoError; 1688 } 1689 } 1690 return mStatus_NoSuchNameErr; 1691 } 1692 1693 // Simply note the received signal in gEventSignals. 1694 mDNSlocal void NoteSignal( int signum) 1695 { 1696 sigaddset( &gEventSignals, signum); 1697 } 1698 1699 // Tell the event package to listen for signal and report it in mDNSPosixRunEventLoopOnce(). 1700 mStatus mDNSPosixListenForSignalInEventLoop( int signum) 1701 { 1702 struct sigaction action; 1703 mStatus err; 1704 1705 bzero( &action, sizeof action); // more portable than member-wise assignment 1706 action.sa_handler = NoteSignal; 1707 err = sigaction( signum, &action, (struct sigaction*) NULL); 1708 1709 sigaddset( &gEventSignalSet, signum); 1710 1711 return err; 1712 } 1713 1714 // Tell the event package to stop listening for signal in mDNSPosixRunEventLoopOnce(). 1715 mStatus mDNSPosixIgnoreSignalInEventLoop( int signum) 1716 { 1717 struct sigaction action; 1718 mStatus err; 1719 1720 bzero( &action, sizeof action); // more portable than member-wise assignment 1721 action.sa_handler = SIG_DFL; 1722 err = sigaction( signum, &action, (struct sigaction*) NULL); 1723 1724 sigdelset( &gEventSignalSet, signum); 1725 1726 return err; 1727 } 1728 1729 // Do a single pass through the attendent event sources and dispatch any found to their callbacks. 1730 // Return as soon as internal timeout expires, or a signal we're listening for is received. 1731 mStatus mDNSPosixRunEventLoopOnce( mDNS *m, const struct timeval *pTimeout, 1732 sigset_t *pSignalsReceived, mDNSBool *pDataDispatched) 1733 { 1734 fd_set listenFDs = gEventFDs; 1735 int fdMax = 0, numReady; 1736 struct timeval timeout = *pTimeout; 1737 1738 // Include the sockets that are listening to the wire in our select() set 1739 mDNSPosixGetFDSet( m, &fdMax, &listenFDs, &timeout); // timeout may get modified 1740 if ( fdMax < gMaxFD) 1741 fdMax = gMaxFD; 1742 1743 numReady = select( fdMax + 1, &listenFDs, (fd_set*) NULL, (fd_set*) NULL, &timeout); 1744 1745 // If any data appeared, invoke its callback 1746 if ( numReady > 0) 1747 { 1748 PosixEventSource *iSource; 1749 1750 (void) mDNSPosixProcessFDSet( m, &listenFDs); // call this first to process wire data for clients 1751 1752 for ( iSource=(PosixEventSource*)gEventSources.Head; iSource; iSource = iSource->Next) 1753 { 1754 if ( FD_ISSET( iSource->fd, &listenFDs)) 1755 { 1756 iSource->Callback( iSource->Context); 1757 break; // in case callback removed elements from gEventSources 1758 } 1759 } 1760 *pDataDispatched = mDNStrue; 1761 } 1762 else 1763 *pDataDispatched = mDNSfalse; 1764 1765 (void) sigprocmask( SIG_BLOCK, &gEventSignalSet, (sigset_t*) NULL); 1766 *pSignalsReceived = gEventSignals; 1767 sigemptyset( &gEventSignals); 1768 (void) sigprocmask( SIG_UNBLOCK, &gEventSignalSet, (sigset_t*) NULL); 1769 1770 return mStatus_NoError; 1771 } 1772