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