xref: /titanic_50/usr/src/cmd/cmd-inet/usr.lib/mdnsd/mDNSPosix.c (revision 5ffb0c9b03b5149ff4f5821a62be4a52408ada2a)
14b22b933Srs200217 /* -*- Mode: C; tab-width: 4 -*-
24b22b933Srs200217  *
34b22b933Srs200217  * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
44b22b933Srs200217  *
54b22b933Srs200217  * Licensed under the Apache License, Version 2.0 (the "License");
64b22b933Srs200217  * you may not use this file except in compliance with the License.
74b22b933Srs200217  * You may obtain a copy of the License at
84b22b933Srs200217  *
94b22b933Srs200217  *     http://www.apache.org/licenses/LICENSE-2.0
104b22b933Srs200217  *
114b22b933Srs200217  * Unless required by applicable law or agreed to in writing, software
124b22b933Srs200217  * distributed under the License is distributed on an "AS IS" BASIS,
134b22b933Srs200217  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
144b22b933Srs200217  * See the License for the specific language governing permissions and
154b22b933Srs200217  * limitations under the License.
164b22b933Srs200217  *
174b22b933Srs200217  */
184b22b933Srs200217 
194b22b933Srs200217 #include "mDNSEmbeddedAPI.h"           // Defines the interface provided to the client layer above
20*5ffb0c9bSToomas Soome #include "DNSCommon.h"
214b22b933Srs200217 #include "mDNSPosix.h"               // Defines the specific types needed to run mDNS on this platform
224b22b933Srs200217 #include "dns_sd.h"
23*5ffb0c9bSToomas Soome #include "dnssec.h"
24*5ffb0c9bSToomas Soome #include "nsec.h"
254b22b933Srs200217 
264b22b933Srs200217 #include <assert.h>
274b22b933Srs200217 #include <stdio.h>
284b22b933Srs200217 #include <stdlib.h>
294b22b933Srs200217 #include <errno.h>
304b22b933Srs200217 #include <string.h>
314b22b933Srs200217 #include <unistd.h>
324b22b933Srs200217 #include <syslog.h>
334b22b933Srs200217 #include <stdarg.h>
344b22b933Srs200217 #include <fcntl.h>
354b22b933Srs200217 #include <sys/types.h>
364b22b933Srs200217 #include <sys/time.h>
374b22b933Srs200217 #include <sys/socket.h>
384b22b933Srs200217 #include <sys/uio.h>
394b22b933Srs200217 #include <sys/select.h>
404b22b933Srs200217 #include <netinet/in.h>
414b22b933Srs200217 #include <arpa/inet.h>
424b22b933Srs200217 #include <time.h>                   // platform support for UTC time
434b22b933Srs200217 
444b22b933Srs200217 #if USES_NETLINK
454b22b933Srs200217 #include <asm/types.h>
464b22b933Srs200217 #include <linux/netlink.h>
474b22b933Srs200217 #include <linux/rtnetlink.h>
484b22b933Srs200217 #else // USES_NETLINK
494b22b933Srs200217 #include <net/route.h>
504b22b933Srs200217 #include <net/if.h>
514b22b933Srs200217 #endif // USES_NETLINK
524b22b933Srs200217 
534b22b933Srs200217 #include "mDNSUNP.h"
544b22b933Srs200217 #include "GenLinkedList.h"
554b22b933Srs200217 
564b22b933Srs200217 // ***************************************************************************
574b22b933Srs200217 // Structures
584b22b933Srs200217 
594b22b933Srs200217 // We keep a list of client-supplied event sources in PosixEventSource records
604b22b933Srs200217 struct PosixEventSource
614b22b933Srs200217 {
624b22b933Srs200217     mDNSPosixEventCallback Callback;
634b22b933Srs200217     void                        *Context;
644b22b933Srs200217     int fd;
654b22b933Srs200217     struct  PosixEventSource    *Next;
664b22b933Srs200217 };
674b22b933Srs200217 typedef struct PosixEventSource PosixEventSource;
684b22b933Srs200217 
694b22b933Srs200217 // Context record for interface change callback
704b22b933Srs200217 struct IfChangeRec
714b22b933Srs200217 {
724b22b933Srs200217     int NotifySD;
734b22b933Srs200217     mDNS *mDNS;
744b22b933Srs200217 };
754b22b933Srs200217 typedef struct IfChangeRec IfChangeRec;
764b22b933Srs200217 
774b22b933Srs200217 // Note that static data is initialized to zero in (modern) C.
784b22b933Srs200217 static fd_set gEventFDs;
794b22b933Srs200217 static int gMaxFD;                              // largest fd in gEventFDs
804b22b933Srs200217 static GenLinkedList gEventSources;             // linked list of PosixEventSource's
814b22b933Srs200217 static sigset_t gEventSignalSet;                // Signals which event loop listens for
824b22b933Srs200217 static sigset_t gEventSignals;                  // Signals which were received while inside loop
834b22b933Srs200217 
84*5ffb0c9bSToomas Soome static PosixNetworkInterface *gRecentInterfaces;
85*5ffb0c9bSToomas Soome 
864b22b933Srs200217 // ***************************************************************************
874b22b933Srs200217 // Globals (for debugging)
884b22b933Srs200217 
894b22b933Srs200217 static int num_registered_interfaces = 0;
904b22b933Srs200217 static int num_pkts_accepted = 0;
914b22b933Srs200217 static int num_pkts_rejected = 0;
924b22b933Srs200217 
934b22b933Srs200217 // ***************************************************************************
944b22b933Srs200217 // Functions
954b22b933Srs200217 
964b22b933Srs200217 int gMDNSPlatformPosixVerboseLevel = 0;
974b22b933Srs200217 
984b22b933Srs200217 #define PosixErrorToStatus(errNum) ((errNum) == 0 ? mStatus_NoError : mStatus_UnknownErr)
994b22b933Srs200217 
SockAddrTomDNSAddr(const struct sockaddr * const sa,mDNSAddr * ipAddr,mDNSIPPort * ipPort)1004b22b933Srs200217 mDNSlocal void SockAddrTomDNSAddr(const struct sockaddr *const sa, mDNSAddr *ipAddr, mDNSIPPort *ipPort)
1014b22b933Srs200217 {
1024b22b933Srs200217     switch (sa->sa_family)
1034b22b933Srs200217     {
1044b22b933Srs200217     case AF_INET:
1054b22b933Srs200217     {
1064b22b933Srs200217         struct sockaddr_in *sin          = (struct sockaddr_in*)sa;
1074b22b933Srs200217         ipAddr->type                     = mDNSAddrType_IPv4;
1084b22b933Srs200217         ipAddr->ip.v4.NotAnInteger       = sin->sin_addr.s_addr;
1094b22b933Srs200217         if (ipPort) ipPort->NotAnInteger = sin->sin_port;
1104b22b933Srs200217         break;
1114b22b933Srs200217     }
1124b22b933Srs200217 
1134b22b933Srs200217 #if HAVE_IPV6
1144b22b933Srs200217     case AF_INET6:
1154b22b933Srs200217     {
1164b22b933Srs200217         struct sockaddr_in6 *sin6        = (struct sockaddr_in6*)sa;
1174b22b933Srs200217 #ifndef NOT_HAVE_SA_LEN
1184b22b933Srs200217         assert(sin6->sin6_len == sizeof(*sin6));
1194b22b933Srs200217 #endif
1204b22b933Srs200217         ipAddr->type                     = mDNSAddrType_IPv6;
1214b22b933Srs200217         ipAddr->ip.v6                    = *(mDNSv6Addr*)&sin6->sin6_addr;
1224b22b933Srs200217         if (ipPort) ipPort->NotAnInteger = sin6->sin6_port;
1234b22b933Srs200217         break;
1244b22b933Srs200217     }
1254b22b933Srs200217 #endif
1264b22b933Srs200217 
1274b22b933Srs200217     default:
1284b22b933Srs200217         verbosedebugf("SockAddrTomDNSAddr: Uknown address family %d\n", sa->sa_family);
1294b22b933Srs200217         ipAddr->type = mDNSAddrType_None;
1304b22b933Srs200217         if (ipPort) ipPort->NotAnInteger = 0;
1314b22b933Srs200217         break;
1324b22b933Srs200217     }
1334b22b933Srs200217 }
1344b22b933Srs200217 
135*5ffb0c9bSToomas Soome /*
136*5ffb0c9bSToomas Soome  * Apple source is using this to set mobile platform
137*5ffb0c9bSToomas Soome  * specific options.
138*5ffb0c9bSToomas Soome  */
139*5ffb0c9bSToomas Soome /*ARGSUSED*/
mDNSPlatformSetuDNSSocktOpt(UDPSocket * src,const mDNSAddr * dst,DNSQuestion * q)140*5ffb0c9bSToomas Soome mDNSexport void mDNSPlatformSetuDNSSocktOpt(UDPSocket *src, const mDNSAddr *dst, DNSQuestion *q)
141*5ffb0c9bSToomas Soome {
142*5ffb0c9bSToomas Soome 	(void)src;	/* unused */
143*5ffb0c9bSToomas Soome 	(void)dst;	/* unused */
144*5ffb0c9bSToomas Soome 	(void)q;	/* unused */
145*5ffb0c9bSToomas Soome }
146*5ffb0c9bSToomas Soome 
1474b22b933Srs200217 #if COMPILER_LIKES_PRAGMA_MARK
1484b22b933Srs200217 #pragma mark ***** Send and Receive
1494b22b933Srs200217 #endif
1504b22b933Srs200217 
1514b22b933Srs200217 // mDNS core calls this routine when it needs to send a packet.
mDNSPlatformSendUDP(const mDNS * const m,const void * const msg,const mDNSu8 * const end,mDNSInterfaceID InterfaceID,UDPSocket * src,const mDNSAddr * dst,mDNSIPPort dstPort,mDNSBool useBackgroundTrafficClass)1524b22b933Srs200217 mDNSexport mStatus mDNSPlatformSendUDP(const mDNS *const m, const void *const msg, const mDNSu8 *const end,
153*5ffb0c9bSToomas Soome                                        mDNSInterfaceID InterfaceID, UDPSocket *src, const mDNSAddr *dst,
154*5ffb0c9bSToomas Soome                                        mDNSIPPort dstPort, mDNSBool useBackgroundTrafficClass)
1554b22b933Srs200217 {
1564b22b933Srs200217     int err = 0;
1574b22b933Srs200217     struct sockaddr_storage to;
1584b22b933Srs200217     PosixNetworkInterface * thisIntf = (PosixNetworkInterface *)(InterfaceID);
1594b22b933Srs200217     int sendingsocket = -1;
1604b22b933Srs200217 
161*5ffb0c9bSToomas Soome     (void)src;  // Will need to use this parameter once we implement mDNSPlatformUDPSocket/mDNSPlatformUDPClose
162*5ffb0c9bSToomas Soome     (void) useBackgroundTrafficClass;
163*5ffb0c9bSToomas Soome 
1644b22b933Srs200217     assert(m != NULL);
1654b22b933Srs200217     assert(msg != NULL);
1664b22b933Srs200217     assert(end != NULL);
1674b22b933Srs200217     assert((((char *) end) - ((char *) msg)) > 0);
1684b22b933Srs200217 
169*5ffb0c9bSToomas Soome     if (dstPort.NotAnInteger == 0)
170*5ffb0c9bSToomas Soome     {
171*5ffb0c9bSToomas Soome         LogMsg("mDNSPlatformSendUDP: Invalid argument -dstPort is set to 0");
172*5ffb0c9bSToomas Soome         return PosixErrorToStatus(EINVAL);
173*5ffb0c9bSToomas Soome     }
1744b22b933Srs200217     if (dst->type == mDNSAddrType_IPv4)
1754b22b933Srs200217     {
1764b22b933Srs200217         struct sockaddr_in *sin = (struct sockaddr_in*)&to;
1774b22b933Srs200217 #ifndef NOT_HAVE_SA_LEN
1784b22b933Srs200217         sin->sin_len            = sizeof(*sin);
1794b22b933Srs200217 #endif
1804b22b933Srs200217         sin->sin_family         = AF_INET;
1814b22b933Srs200217         sin->sin_port           = dstPort.NotAnInteger;
1824b22b933Srs200217         sin->sin_addr.s_addr    = dst->ip.v4.NotAnInteger;
1834b22b933Srs200217         sendingsocket           = thisIntf ? thisIntf->multicastSocket4 : m->p->unicastSocket4;
1844b22b933Srs200217     }
1854b22b933Srs200217 
1864b22b933Srs200217 #if HAVE_IPV6
1874b22b933Srs200217     else if (dst->type == mDNSAddrType_IPv6)
1884b22b933Srs200217     {
1894b22b933Srs200217         struct sockaddr_in6 *sin6 = (struct sockaddr_in6*)&to;
1904b22b933Srs200217         mDNSPlatformMemZero(sin6, sizeof(*sin6));
1914b22b933Srs200217 #ifndef NOT_HAVE_SA_LEN
1924b22b933Srs200217         sin6->sin6_len            = sizeof(*sin6);
1934b22b933Srs200217 #endif
1944b22b933Srs200217         sin6->sin6_family         = AF_INET6;
1954b22b933Srs200217         sin6->sin6_port           = dstPort.NotAnInteger;
1964b22b933Srs200217         sin6->sin6_addr           = *(struct in6_addr*)&dst->ip.v6;
1974b22b933Srs200217         sendingsocket             = thisIntf ? thisIntf->multicastSocket6 : m->p->unicastSocket6;
1984b22b933Srs200217     }
1994b22b933Srs200217 #endif
2004b22b933Srs200217 
2014b22b933Srs200217     if (sendingsocket >= 0)
2024b22b933Srs200217         err = sendto(sendingsocket, msg, (char*)end - (char*)msg, 0, (struct sockaddr *)&to, GET_SA_LEN(to));
2034b22b933Srs200217 
2044b22b933Srs200217     if      (err > 0) err = 0;
2054b22b933Srs200217     else if (err < 0)
2064b22b933Srs200217     {
2074b22b933Srs200217         static int MessageCount = 0;
2084b22b933Srs200217         // Don't report EHOSTDOWN (i.e. ARP failure), ENETDOWN, or no route to host for unicast destinations
2094b22b933Srs200217         if (!mDNSAddressIsAllDNSLinkGroup(dst))
2104b22b933Srs200217             if (errno == EHOSTDOWN || errno == ENETDOWN || errno == EHOSTUNREACH || errno == ENETUNREACH) return(mStatus_TransientErr);
2114b22b933Srs200217 
212*5ffb0c9bSToomas Soome 	/* dont report ENETUNREACH */
213*5ffb0c9bSToomas Soome         if (errno == ENETUNREACH) return(mStatus_TransientErr);
214*5ffb0c9bSToomas Soome 
2154b22b933Srs200217         if (MessageCount < 1000)
2164b22b933Srs200217         {
2174b22b933Srs200217             MessageCount++;
2184b22b933Srs200217             if (thisIntf)
2194b22b933Srs200217                 LogMsg("mDNSPlatformSendUDP got error %d (%s) sending packet to %#a on interface %#a/%s/%d",
2204b22b933Srs200217                        errno, strerror(errno), dst, &thisIntf->coreIntf.ip, thisIntf->intfName, thisIntf->index);
2214b22b933Srs200217             else
2224b22b933Srs200217                 LogMsg("mDNSPlatformSendUDP got error %d (%s) sending packet to %#a", errno, strerror(errno), dst);
2234b22b933Srs200217         }
2244b22b933Srs200217     }
2254b22b933Srs200217 
2264b22b933Srs200217     return PosixErrorToStatus(err);
2274b22b933Srs200217 }
2284b22b933Srs200217 
2294b22b933Srs200217 // This routine is called when the main loop detects that data is available on a socket.
SocketDataReady(mDNS * const m,PosixNetworkInterface * intf,int skt)2304b22b933Srs200217 mDNSlocal void SocketDataReady(mDNS *const m, PosixNetworkInterface *intf, int skt)
2314b22b933Srs200217 {
2324b22b933Srs200217     mDNSAddr senderAddr, destAddr;
2334b22b933Srs200217     mDNSIPPort senderPort;
2344b22b933Srs200217     ssize_t packetLen;
2354b22b933Srs200217     DNSMessage packet;
2364b22b933Srs200217     struct my_in_pktinfo packetInfo;
2374b22b933Srs200217     struct sockaddr_storage from;
2384b22b933Srs200217     socklen_t fromLen;
2394b22b933Srs200217     int flags;
2404b22b933Srs200217     mDNSu8 ttl;
2414b22b933Srs200217     mDNSBool reject;
2424b22b933Srs200217     const mDNSInterfaceID InterfaceID = intf ? intf->coreIntf.InterfaceID : NULL;
2434b22b933Srs200217 
2444b22b933Srs200217     assert(m    != NULL);
2454b22b933Srs200217     assert(skt  >= 0);
2464b22b933Srs200217 
2474b22b933Srs200217     fromLen = sizeof(from);
2484b22b933Srs200217     flags   = 0;
2494b22b933Srs200217     packetLen = recvfrom_flags(skt, &packet, sizeof(packet), &flags, (struct sockaddr *) &from, &fromLen, &packetInfo, &ttl);
2504b22b933Srs200217 
2514b22b933Srs200217     if (packetLen >= 0)
2524b22b933Srs200217     {
2534b22b933Srs200217         SockAddrTomDNSAddr((struct sockaddr*)&from, &senderAddr, &senderPort);
2544b22b933Srs200217         SockAddrTomDNSAddr((struct sockaddr*)&packetInfo.ipi_addr, &destAddr, NULL);
2554b22b933Srs200217 
2564b22b933Srs200217         // If we have broken IP_RECVDSTADDR functionality (so far
2574b22b933Srs200217         // I've only seen this on OpenBSD) then apply a hack to
2584b22b933Srs200217         // convince mDNS Core that this isn't a spoof packet.
2594b22b933Srs200217         // Basically what we do is check to see whether the
2604b22b933Srs200217         // packet arrived as a multicast and, if so, set its
2614b22b933Srs200217         // destAddr to the mDNS address.
2624b22b933Srs200217         //
2634b22b933Srs200217         // I must admit that I could just be doing something
2644b22b933Srs200217         // wrong on OpenBSD and hence triggering this problem
2654b22b933Srs200217         // but I'm at a loss as to how.
2664b22b933Srs200217         //
2674b22b933Srs200217         // If this platform doesn't have IP_PKTINFO or IP_RECVDSTADDR, then we have
2684b22b933Srs200217         // no way to tell the destination address or interface this packet arrived on,
2694b22b933Srs200217         // so all we can do is just assume it's a multicast
2704b22b933Srs200217 
2714b22b933Srs200217         #if HAVE_BROKEN_RECVDSTADDR || (!defined(IP_PKTINFO) && !defined(IP_RECVDSTADDR))
2724b22b933Srs200217         if ((destAddr.NotAnInteger == 0) && (flags & MSG_MCAST))
2734b22b933Srs200217         {
2744b22b933Srs200217             destAddr.type = senderAddr.type;
275*5ffb0c9bSToomas Soome             if      (senderAddr.type == mDNSAddrType_IPv4) destAddr.ip.v4 = AllDNSLinkGroup_v4.ip.v4;
276*5ffb0c9bSToomas Soome             else if (senderAddr.type == mDNSAddrType_IPv6) destAddr.ip.v6 = AllDNSLinkGroup_v6.ip.v6;
2774b22b933Srs200217         }
2784b22b933Srs200217         #endif
2794b22b933Srs200217 
2804b22b933Srs200217         // We only accept the packet if the interface on which it came
2814b22b933Srs200217         // in matches the interface associated with this socket.
2824b22b933Srs200217         // We do this match by name or by index, depending on which
2834b22b933Srs200217         // information is available.  recvfrom_flags sets the name
2844b22b933Srs200217         // to "" if the name isn't available, or the index to -1
2854b22b933Srs200217         // if the index is available.  This accomodates the various
2864b22b933Srs200217         // different capabilities of our target platforms.
2874b22b933Srs200217 
2884b22b933Srs200217         reject = mDNSfalse;
2894b22b933Srs200217         if (!intf)
2904b22b933Srs200217         {
2914b22b933Srs200217             // Ignore multicasts accidentally delivered to our unicast receiving socket
2924b22b933Srs200217             if (mDNSAddrIsDNSMulticast(&destAddr)) packetLen = -1;
2934b22b933Srs200217         }
2944b22b933Srs200217         else
2954b22b933Srs200217         {
2964b22b933Srs200217             if      (packetInfo.ipi_ifname[0] != 0) reject = (strcmp(packetInfo.ipi_ifname, intf->intfName) != 0);
2974b22b933Srs200217             else if (packetInfo.ipi_ifindex != -1) reject = (packetInfo.ipi_ifindex != intf->index);
2984b22b933Srs200217 
2994b22b933Srs200217             if (reject)
3004b22b933Srs200217             {
3014b22b933Srs200217                 verbosedebugf("SocketDataReady ignored a packet from %#a to %#a on interface %s/%d expecting %#a/%s/%d/%d",
3024b22b933Srs200217                               &senderAddr, &destAddr, packetInfo.ipi_ifname, packetInfo.ipi_ifindex,
3034b22b933Srs200217                               &intf->coreIntf.ip, intf->intfName, intf->index, skt);
3044b22b933Srs200217                 packetLen = -1;
3054b22b933Srs200217                 num_pkts_rejected++;
3064b22b933Srs200217                 if (num_pkts_rejected > (num_pkts_accepted + 1) * (num_registered_interfaces + 1) * 2)
3074b22b933Srs200217                 {
3084b22b933Srs200217                     fprintf(stderr,
3094b22b933Srs200217                             "*** WARNING: Received %d packets; Accepted %d packets; Rejected %d packets because of interface mismatch\n",
3104b22b933Srs200217                             num_pkts_accepted + num_pkts_rejected, num_pkts_accepted, num_pkts_rejected);
3114b22b933Srs200217                     num_pkts_accepted = 0;
3124b22b933Srs200217                     num_pkts_rejected = 0;
3134b22b933Srs200217                 }
3144b22b933Srs200217             }
3154b22b933Srs200217             else
3164b22b933Srs200217             {
3174b22b933Srs200217                 verbosedebugf("SocketDataReady got a packet from %#a to %#a on interface %#a/%s/%d/%d",
3184b22b933Srs200217                               &senderAddr, &destAddr, &intf->coreIntf.ip, intf->intfName, intf->index, skt);
3194b22b933Srs200217                 num_pkts_accepted++;
3204b22b933Srs200217             }
3214b22b933Srs200217         }
3224b22b933Srs200217     }
3234b22b933Srs200217 
3244b22b933Srs200217     if (packetLen >= 0)
3254b22b933Srs200217         mDNSCoreReceive(m, &packet, (mDNSu8 *)&packet + packetLen,
3264b22b933Srs200217                         &senderAddr, senderPort, &destAddr, MulticastDNSPort, InterfaceID);
3274b22b933Srs200217 }
3284b22b933Srs200217 
mDNSPlatformPeekUDP(mDNS * const m,UDPSocket * src)329*5ffb0c9bSToomas Soome mDNSexport mDNSBool mDNSPlatformPeekUDP(mDNS *const m, UDPSocket *src)
3304b22b933Srs200217 {
331*5ffb0c9bSToomas Soome     (void)m;    // unused
332*5ffb0c9bSToomas Soome     (void)src;  // unused
333*5ffb0c9bSToomas Soome     return mDNSfalse;
334*5ffb0c9bSToomas Soome }
335*5ffb0c9bSToomas Soome 
mDNSPlatformTCPSocket(mDNS * const m,TCPSocketFlags flags,mDNSIPPort * port,mDNSBool useBackgroundTrafficClass)336*5ffb0c9bSToomas Soome mDNSexport TCPSocket *mDNSPlatformTCPSocket(mDNS * const m, TCPSocketFlags flags, mDNSIPPort * port, mDNSBool useBackgroundTrafficClass)
337*5ffb0c9bSToomas Soome {
338*5ffb0c9bSToomas Soome     (void)m;            // Unused
339*5ffb0c9bSToomas Soome     (void)flags;        // Unused
340*5ffb0c9bSToomas Soome     (void)port;         // Unused
341*5ffb0c9bSToomas Soome     (void)useBackgroundTrafficClass; // Unused
342*5ffb0c9bSToomas Soome     return NULL;
343*5ffb0c9bSToomas Soome }
344*5ffb0c9bSToomas Soome 
mDNSPlatformTCPAccept(TCPSocketFlags flags,int sd)345*5ffb0c9bSToomas Soome mDNSexport TCPSocket *mDNSPlatformTCPAccept(TCPSocketFlags flags, int sd)
346*5ffb0c9bSToomas Soome {
347*5ffb0c9bSToomas Soome     (void)flags;        // Unused
348*5ffb0c9bSToomas Soome     (void)sd;           // Unused
349*5ffb0c9bSToomas Soome     return NULL;
350*5ffb0c9bSToomas Soome }
351*5ffb0c9bSToomas Soome 
mDNSPlatformTCPGetFD(TCPSocket * sock)352*5ffb0c9bSToomas Soome mDNSexport int mDNSPlatformTCPGetFD(TCPSocket *sock)
353*5ffb0c9bSToomas Soome {
354*5ffb0c9bSToomas Soome     (void)sock;         // Unused
355*5ffb0c9bSToomas Soome     return -1;
356*5ffb0c9bSToomas Soome }
357*5ffb0c9bSToomas Soome 
mDNSPlatformTCPConnect(TCPSocket * sock,const mDNSAddr * dst,mDNSOpaque16 dstport,domainname * hostname,mDNSInterfaceID InterfaceID,TCPConnectionCallback callback,void * context)358*5ffb0c9bSToomas Soome mDNSexport mStatus mDNSPlatformTCPConnect(TCPSocket *sock, const mDNSAddr *dst, mDNSOpaque16 dstport, domainname *hostname, mDNSInterfaceID InterfaceID,
359*5ffb0c9bSToomas Soome                                           TCPConnectionCallback callback, void *context)
360*5ffb0c9bSToomas Soome {
361*5ffb0c9bSToomas Soome     (void)sock;         // Unused
3624b22b933Srs200217     (void)dst;          // Unused
3634b22b933Srs200217     (void)dstport;      // Unused
364*5ffb0c9bSToomas Soome     (void)hostname;     // Unused
3654b22b933Srs200217     (void)InterfaceID;  // Unused
3664b22b933Srs200217     (void)callback;     // Unused
3674b22b933Srs200217     (void)context;      // Unused
3684b22b933Srs200217     return(mStatus_UnsupportedErr);
3694b22b933Srs200217 }
3704b22b933Srs200217 
mDNSPlatformTCPCloseConnection(TCPSocket * sock)371*5ffb0c9bSToomas Soome mDNSexport void mDNSPlatformTCPCloseConnection(TCPSocket *sock)
3724b22b933Srs200217 {
373*5ffb0c9bSToomas Soome     (void)sock;         // Unused
3744b22b933Srs200217 }
3754b22b933Srs200217 
mDNSPlatformReadTCP(TCPSocket * sock,void * buf,unsigned long buflen,mDNSBool * closed)376*5ffb0c9bSToomas Soome mDNSexport long mDNSPlatformReadTCP(TCPSocket *sock, void *buf, unsigned long buflen, mDNSBool * closed)
3774b22b933Srs200217 {
378*5ffb0c9bSToomas Soome     (void)sock;         // Unused
3794b22b933Srs200217     (void)buf;          // Unused
3804b22b933Srs200217     (void)buflen;       // Unused
381*5ffb0c9bSToomas Soome     (void)closed;       // Unused
382*5ffb0c9bSToomas Soome     return 0;
3834b22b933Srs200217 }
3844b22b933Srs200217 
mDNSPlatformWriteTCP(TCPSocket * sock,const char * msg,unsigned long len)385*5ffb0c9bSToomas Soome mDNSexport long mDNSPlatformWriteTCP(TCPSocket *sock, const char *msg, unsigned long len)
3864b22b933Srs200217 {
387*5ffb0c9bSToomas Soome     (void)sock;         // Unused
3884b22b933Srs200217     (void)msg;          // Unused
3894b22b933Srs200217     (void)len;          // Unused
390*5ffb0c9bSToomas Soome     return 0;
391*5ffb0c9bSToomas Soome }
392*5ffb0c9bSToomas Soome 
mDNSPlatformUDPSocket(mDNS * const m,mDNSIPPort port)393*5ffb0c9bSToomas Soome mDNSexport UDPSocket *mDNSPlatformUDPSocket(mDNS * const m, mDNSIPPort port)
394*5ffb0c9bSToomas Soome {
395*5ffb0c9bSToomas Soome     (void)m;            // Unused
396*5ffb0c9bSToomas Soome     (void)port;         // Unused
397*5ffb0c9bSToomas Soome     return NULL;
398*5ffb0c9bSToomas Soome }
399*5ffb0c9bSToomas Soome 
mDNSPlatformUDPClose(UDPSocket * sock)400*5ffb0c9bSToomas Soome mDNSexport void           mDNSPlatformUDPClose(UDPSocket *sock)
401*5ffb0c9bSToomas Soome {
402*5ffb0c9bSToomas Soome     (void)sock;         // Unused
403*5ffb0c9bSToomas Soome }
404*5ffb0c9bSToomas Soome 
mDNSPlatformUpdateProxyList(mDNS * const m,const mDNSInterfaceID InterfaceID)405*5ffb0c9bSToomas Soome mDNSexport void mDNSPlatformUpdateProxyList(mDNS *const m, const mDNSInterfaceID InterfaceID)
406*5ffb0c9bSToomas Soome {
407*5ffb0c9bSToomas Soome     (void)m;            // Unused
408*5ffb0c9bSToomas Soome     (void)InterfaceID;          // Unused
409*5ffb0c9bSToomas Soome }
410*5ffb0c9bSToomas Soome 
mDNSPlatformSendRawPacket(const void * const msg,const mDNSu8 * const end,mDNSInterfaceID InterfaceID)411*5ffb0c9bSToomas Soome mDNSexport void mDNSPlatformSendRawPacket(const void *const msg, const mDNSu8 *const end, mDNSInterfaceID InterfaceID)
412*5ffb0c9bSToomas Soome {
413*5ffb0c9bSToomas Soome     (void)msg;          // Unused
414*5ffb0c9bSToomas Soome     (void)end;          // Unused
415*5ffb0c9bSToomas Soome     (void)InterfaceID;          // Unused
416*5ffb0c9bSToomas Soome }
417*5ffb0c9bSToomas Soome 
mDNSPlatformSetLocalAddressCacheEntry(mDNS * const m,const mDNSAddr * const tpa,const mDNSEthAddr * const tha,mDNSInterfaceID InterfaceID)418*5ffb0c9bSToomas Soome mDNSexport void mDNSPlatformSetLocalAddressCacheEntry(mDNS *const m, const mDNSAddr *const tpa, const mDNSEthAddr *const tha, mDNSInterfaceID InterfaceID)
419*5ffb0c9bSToomas Soome {
420*5ffb0c9bSToomas Soome     (void)m;            // Unused
421*5ffb0c9bSToomas Soome     (void)tpa;          // Unused
422*5ffb0c9bSToomas Soome     (void)tha;          // Unused
423*5ffb0c9bSToomas Soome     (void)InterfaceID;          // Unused
424*5ffb0c9bSToomas Soome }
425*5ffb0c9bSToomas Soome 
mDNSPlatformTLSSetupCerts(void)426*5ffb0c9bSToomas Soome mDNSexport mStatus mDNSPlatformTLSSetupCerts(void)
427*5ffb0c9bSToomas Soome {
428*5ffb0c9bSToomas Soome     return(mStatus_UnsupportedErr);
429*5ffb0c9bSToomas Soome }
430*5ffb0c9bSToomas Soome 
mDNSPlatformTLSTearDownCerts(void)431*5ffb0c9bSToomas Soome mDNSexport void mDNSPlatformTLSTearDownCerts(void)
432*5ffb0c9bSToomas Soome {
433*5ffb0c9bSToomas Soome }
434*5ffb0c9bSToomas Soome 
mDNSPlatformSetAllowSleep(mDNS * const m,mDNSBool allowSleep,const char * reason)435*5ffb0c9bSToomas Soome mDNSexport void mDNSPlatformSetAllowSleep(mDNS *const m, mDNSBool allowSleep, const char *reason)
436*5ffb0c9bSToomas Soome {
437*5ffb0c9bSToomas Soome     (void) m;
438*5ffb0c9bSToomas Soome     (void) allowSleep;
439*5ffb0c9bSToomas Soome     (void) reason;
4404b22b933Srs200217 }
4414b22b933Srs200217 
4424b22b933Srs200217 #if COMPILER_LIKES_PRAGMA_MARK
443*5ffb0c9bSToomas Soome #pragma mark -
444*5ffb0c9bSToomas Soome #pragma mark - /etc/hosts support
4454b22b933Srs200217 #endif
4464b22b933Srs200217 
FreeEtcHosts(mDNS * const m,AuthRecord * const rr,mStatus result)447*5ffb0c9bSToomas Soome mDNSexport void FreeEtcHosts(mDNS *const m, AuthRecord *const rr, mStatus result)
4484b22b933Srs200217 {
449*5ffb0c9bSToomas Soome     (void)m;  // unused
450*5ffb0c9bSToomas Soome     (void)rr;
451*5ffb0c9bSToomas Soome     (void)result;
4524b22b933Srs200217 }
4534b22b933Srs200217 
454*5ffb0c9bSToomas Soome 
455*5ffb0c9bSToomas Soome #if COMPILER_LIKES_PRAGMA_MARK
456*5ffb0c9bSToomas Soome #pragma mark ***** DDNS Config Platform Functions
457*5ffb0c9bSToomas Soome #endif
458*5ffb0c9bSToomas Soome 
mDNSPlatformSetDNSConfig(mDNS * const m,mDNSBool setservers,mDNSBool setsearch,domainname * const fqdn,DNameListElem ** RegDomains,DNameListElem ** BrowseDomains,mDNSBool ackConfig)459*5ffb0c9bSToomas Soome mDNSexport mDNSBool mDNSPlatformSetDNSConfig(mDNS *const m, mDNSBool setservers, mDNSBool setsearch, domainname *const fqdn, DNameListElem **RegDomains,
460*5ffb0c9bSToomas Soome     DNameListElem **BrowseDomains, mDNSBool ackConfig)
4614b22b933Srs200217 {
462*5ffb0c9bSToomas Soome     (void) m;
463*5ffb0c9bSToomas Soome     (void) setservers;
464*5ffb0c9bSToomas Soome     (void) fqdn;
465*5ffb0c9bSToomas Soome     (void) setsearch;
466*5ffb0c9bSToomas Soome     (void) RegDomains;
467*5ffb0c9bSToomas Soome     (void) BrowseDomains;
468*5ffb0c9bSToomas Soome     (void) ackConfig;
469*5ffb0c9bSToomas Soome 
470*5ffb0c9bSToomas Soome     return mDNStrue;
471*5ffb0c9bSToomas Soome }
472*5ffb0c9bSToomas Soome 
mDNSPlatformGetPrimaryInterface(mDNS * const m,mDNSAddr * v4,mDNSAddr * v6,mDNSAddr * router)473*5ffb0c9bSToomas Soome mDNSexport mStatus mDNSPlatformGetPrimaryInterface(mDNS * const m, mDNSAddr * v4, mDNSAddr * v6, mDNSAddr * router)
474*5ffb0c9bSToomas Soome {
475*5ffb0c9bSToomas Soome     (void) m;
476*5ffb0c9bSToomas Soome     (void) v4;
477*5ffb0c9bSToomas Soome     (void) v6;
478*5ffb0c9bSToomas Soome     (void) router;
479*5ffb0c9bSToomas Soome 
480*5ffb0c9bSToomas Soome     return mStatus_UnsupportedErr;
481*5ffb0c9bSToomas Soome }
482*5ffb0c9bSToomas Soome 
mDNSPlatformDynDNSHostNameStatusChanged(const domainname * const dname,const mStatus status)483*5ffb0c9bSToomas Soome mDNSexport void mDNSPlatformDynDNSHostNameStatusChanged(const domainname *const dname, const mStatus status)
484*5ffb0c9bSToomas Soome {
485*5ffb0c9bSToomas Soome     (void) dname;
486*5ffb0c9bSToomas Soome     (void) status;
4874b22b933Srs200217 }
4884b22b933Srs200217 
4894b22b933Srs200217 #if COMPILER_LIKES_PRAGMA_MARK
4904b22b933Srs200217 #pragma mark ***** Init and Term
4914b22b933Srs200217 #endif
4924b22b933Srs200217 
4934b22b933Srs200217 // This gets the current hostname, truncating it at the first dot if necessary
GetUserSpecifiedRFC1034ComputerName(domainlabel * const namelabel)4944b22b933Srs200217 mDNSlocal void GetUserSpecifiedRFC1034ComputerName(domainlabel *const namelabel)
4954b22b933Srs200217 {
4964b22b933Srs200217     int len = 0;
4974b22b933Srs200217     gethostname((char *)(&namelabel->c[1]), MAX_DOMAIN_LABEL);
4984b22b933Srs200217     while (len < MAX_DOMAIN_LABEL && namelabel->c[len+1] && namelabel->c[len+1] != '.') len++;
4994b22b933Srs200217     namelabel->c[0] = len;
5004b22b933Srs200217 }
5014b22b933Srs200217 
5024b22b933Srs200217 // On OS X this gets the text of the field labelled "Computer Name" in the Sharing Prefs Control Panel
5034b22b933Srs200217 // Other platforms can either get the information from the appropriate place,
5044b22b933Srs200217 // or they can alternatively just require all registering services to provide an explicit name
GetUserSpecifiedFriendlyComputerName(domainlabel * const namelabel)5054b22b933Srs200217 mDNSlocal void GetUserSpecifiedFriendlyComputerName(domainlabel *const namelabel)
5064b22b933Srs200217 {
5074b22b933Srs200217     // On Unix we have no better name than the host name, so we just use that.
5084b22b933Srs200217     GetUserSpecifiedRFC1034ComputerName(namelabel);
5094b22b933Srs200217 }
5104b22b933Srs200217 
ParseDNSServers(mDNS * m,const char * filePath)5114b22b933Srs200217 mDNSexport int ParseDNSServers(mDNS *m, const char *filePath)
5124b22b933Srs200217 {
5134b22b933Srs200217     char line[256];
5144b22b933Srs200217     char nameserver[16];
515*5ffb0c9bSToomas Soome     char keyword[11];
5164b22b933Srs200217     int numOfServers = 0;
5174b22b933Srs200217     FILE *fp = fopen(filePath, "r");
5184b22b933Srs200217     if (fp == NULL) return -1;
5194b22b933Srs200217     while (fgets(line,sizeof(line),fp))
5204b22b933Srs200217     {
5214b22b933Srs200217         struct in_addr ina;
5224b22b933Srs200217         line[255]='\0';     // just to be safe
5234b22b933Srs200217         if (sscanf(line,"%10s %15s", keyword, nameserver) != 2) continue;   // it will skip whitespaces
524*5ffb0c9bSToomas Soome         if (strncasecmp(keyword,"nameserver",10)) continue;
5254b22b933Srs200217         if (inet_aton(nameserver, (struct in_addr *)&ina) != 0)
5264b22b933Srs200217         {
5274b22b933Srs200217             mDNSAddr DNSAddr;
5284b22b933Srs200217             DNSAddr.type = mDNSAddrType_IPv4;
5294b22b933Srs200217             DNSAddr.ip.v4.NotAnInteger = ina.s_addr;
530*5ffb0c9bSToomas Soome             mDNS_AddDNSServer(m, NULL, mDNSInterface_Any, 0, &DNSAddr, UnicastDNSPort, kScopeNone, 0, mDNSfalse, 0, mDNStrue, mDNStrue, mDNSfalse);
5314b22b933Srs200217             numOfServers++;
5324b22b933Srs200217         }
5334b22b933Srs200217     }
534180be2b7SRishi Srivatsavai     fclose(fp);
5354b22b933Srs200217     return (numOfServers > 0) ? 0 : -1;
5364b22b933Srs200217 }
5374b22b933Srs200217 
5384b22b933Srs200217 // Searches the interface list looking for the named interface.
5394b22b933Srs200217 // Returns a pointer to if it found, or NULL otherwise.
SearchForInterfaceByName(mDNS * const m,const char * intfName)5404b22b933Srs200217 mDNSlocal PosixNetworkInterface *SearchForInterfaceByName(mDNS *const m, const char *intfName)
5414b22b933Srs200217 {
5424b22b933Srs200217     PosixNetworkInterface *intf;
5434b22b933Srs200217 
5444b22b933Srs200217     assert(m != NULL);
5454b22b933Srs200217     assert(intfName != NULL);
5464b22b933Srs200217 
5474b22b933Srs200217     intf = (PosixNetworkInterface*)(m->HostInterfaces);
5484b22b933Srs200217     while ((intf != NULL) && (strcmp(intf->intfName, intfName) != 0))
5494b22b933Srs200217         intf = (PosixNetworkInterface *)(intf->coreIntf.next);
5504b22b933Srs200217 
5514b22b933Srs200217     return intf;
5524b22b933Srs200217 }
5534b22b933Srs200217 
mDNSPlatformInterfaceIDfromInterfaceIndex(mDNS * const m,mDNSu32 index)5544b22b933Srs200217 mDNSexport mDNSInterfaceID mDNSPlatformInterfaceIDfromInterfaceIndex(mDNS *const m, mDNSu32 index)
5554b22b933Srs200217 {
5564b22b933Srs200217     PosixNetworkInterface *intf;
5574b22b933Srs200217 
5584b22b933Srs200217     assert(m != NULL);
5594b22b933Srs200217 
5604b22b933Srs200217     if (index == kDNSServiceInterfaceIndexLocalOnly) return(mDNSInterface_LocalOnly);
561*5ffb0c9bSToomas Soome     if (index == kDNSServiceInterfaceIndexP2P      ) return(mDNSInterface_P2P);
562*5ffb0c9bSToomas Soome     if (index == kDNSServiceInterfaceIndexAny      ) return(mDNSInterface_Any);
5634b22b933Srs200217 
5644b22b933Srs200217     intf = (PosixNetworkInterface*)(m->HostInterfaces);
5654b22b933Srs200217     while ((intf != NULL) && (mDNSu32) intf->index != index)
5664b22b933Srs200217         intf = (PosixNetworkInterface *)(intf->coreIntf.next);
5674b22b933Srs200217 
5684b22b933Srs200217     return (mDNSInterfaceID) intf;
5694b22b933Srs200217 }
5704b22b933Srs200217 
mDNSPlatformInterfaceIndexfromInterfaceID(mDNS * const m,mDNSInterfaceID id,mDNSBool suppressNetworkChange)571*5ffb0c9bSToomas Soome mDNSexport mDNSu32 mDNSPlatformInterfaceIndexfromInterfaceID(mDNS *const m, mDNSInterfaceID id, mDNSBool suppressNetworkChange)
5724b22b933Srs200217 {
5734b22b933Srs200217     PosixNetworkInterface *intf;
574*5ffb0c9bSToomas Soome     (void) suppressNetworkChange; // Unused
5754b22b933Srs200217 
5764b22b933Srs200217     assert(m != NULL);
5774b22b933Srs200217 
5784b22b933Srs200217     if (id == mDNSInterface_LocalOnly) return(kDNSServiceInterfaceIndexLocalOnly);
579*5ffb0c9bSToomas Soome     if (id == mDNSInterface_P2P      ) return(kDNSServiceInterfaceIndexP2P);
580*5ffb0c9bSToomas Soome     if (id == mDNSInterface_Any      ) return(kDNSServiceInterfaceIndexAny);
5814b22b933Srs200217 
5824b22b933Srs200217     intf = (PosixNetworkInterface*)(m->HostInterfaces);
5834b22b933Srs200217     while ((intf != NULL) && (mDNSInterfaceID) intf != id)
5844b22b933Srs200217         intf = (PosixNetworkInterface *)(intf->coreIntf.next);
5854b22b933Srs200217 
586*5ffb0c9bSToomas Soome     if (intf) return intf->index;
587*5ffb0c9bSToomas Soome 
588*5ffb0c9bSToomas Soome     // If we didn't find the interface, check the RecentInterfaces list as well
589*5ffb0c9bSToomas Soome     intf = gRecentInterfaces;
590*5ffb0c9bSToomas Soome     while ((intf != NULL) && (mDNSInterfaceID) intf != id)
591*5ffb0c9bSToomas Soome         intf = (PosixNetworkInterface *)(intf->coreIntf.next);
592*5ffb0c9bSToomas Soome 
5934b22b933Srs200217     return intf ? intf->index : 0;
5944b22b933Srs200217 }
5954b22b933Srs200217 
5964b22b933Srs200217 // Frees the specified PosixNetworkInterface structure. The underlying
5974b22b933Srs200217 // interface must have already been deregistered with the mDNS core.
FreePosixNetworkInterface(PosixNetworkInterface * intf)5984b22b933Srs200217 mDNSlocal void FreePosixNetworkInterface(PosixNetworkInterface *intf)
5994b22b933Srs200217 {
6004b22b933Srs200217     assert(intf != NULL);
6014b22b933Srs200217     if (intf->intfName != NULL) free((void *)intf->intfName);
6024b22b933Srs200217     if (intf->multicastSocket4 != -1) assert(close(intf->multicastSocket4) == 0);
6034b22b933Srs200217 #if HAVE_IPV6
6044b22b933Srs200217     if (intf->multicastSocket6 != -1) assert(close(intf->multicastSocket6) == 0);
6054b22b933Srs200217 #endif
606*5ffb0c9bSToomas Soome 
607*5ffb0c9bSToomas Soome     // Move interface to the RecentInterfaces list for a minute
608*5ffb0c9bSToomas Soome     intf->LastSeen = mDNSPlatformUTC();
609*5ffb0c9bSToomas Soome     intf->coreIntf.next = &gRecentInterfaces->coreIntf;
610*5ffb0c9bSToomas Soome     gRecentInterfaces = intf;
6114b22b933Srs200217 }
6124b22b933Srs200217 
6134b22b933Srs200217 // Grab the first interface, deregister it, free it, and repeat until done.
ClearInterfaceList(mDNS * const m)6144b22b933Srs200217 mDNSlocal void ClearInterfaceList(mDNS *const m)
6154b22b933Srs200217 {
6164b22b933Srs200217     assert(m != NULL);
6174b22b933Srs200217 
6184b22b933Srs200217     while (m->HostInterfaces)
6194b22b933Srs200217     {
6204b22b933Srs200217         PosixNetworkInterface *intf = (PosixNetworkInterface*)(m->HostInterfaces);
6214b22b933Srs200217         mDNS_DeregisterInterface(m, &intf->coreIntf, mDNSfalse);
6224b22b933Srs200217         if (gMDNSPlatformPosixVerboseLevel > 0) fprintf(stderr, "Deregistered interface %s\n", intf->intfName);
6234b22b933Srs200217         FreePosixNetworkInterface(intf);
6244b22b933Srs200217     }
6254b22b933Srs200217     num_registered_interfaces = 0;
6264b22b933Srs200217     num_pkts_accepted = 0;
6274b22b933Srs200217     num_pkts_rejected = 0;
6284b22b933Srs200217 }
6294b22b933Srs200217 
6304b22b933Srs200217 // Sets up a send/receive socket.
6314b22b933Srs200217 // If mDNSIPPort port is non-zero, then it's a multicast socket on the specified interface
6324b22b933Srs200217 // If mDNSIPPort port is zero, then it's a randomly assigned port number, used for sending unicast queries
SetupSocket(struct sockaddr * intfAddr,mDNSIPPort port,int interfaceIndex,int * sktPtr)6334b22b933Srs200217 mDNSlocal int SetupSocket(struct sockaddr *intfAddr, mDNSIPPort port, int interfaceIndex, int *sktPtr)
6344b22b933Srs200217 {
6354b22b933Srs200217     int err = 0;
6364b22b933Srs200217     static const int kOn = 1;
6374b22b933Srs200217     static const int kIntTwoFiveFive = 255;
6384b22b933Srs200217     static const unsigned char kByteTwoFiveFive = 255;
6394b22b933Srs200217     const mDNSBool JoinMulticastGroup = (port.NotAnInteger != 0);
6404b22b933Srs200217 
6414b22b933Srs200217     (void) interfaceIndex;  // This parameter unused on plaforms that don't have IPv6
6424b22b933Srs200217     assert(intfAddr != NULL);
6434b22b933Srs200217     assert(sktPtr != NULL);
6444b22b933Srs200217     assert(*sktPtr == -1);
6454b22b933Srs200217 
6464b22b933Srs200217     // Open the socket...
6474b22b933Srs200217     if      (intfAddr->sa_family == AF_INET) *sktPtr = socket(PF_INET,  SOCK_DGRAM, IPPROTO_UDP);
6484b22b933Srs200217 #if HAVE_IPV6
6494b22b933Srs200217     else if (intfAddr->sa_family == AF_INET6) *sktPtr = socket(PF_INET6, SOCK_DGRAM, IPPROTO_UDP);
6504b22b933Srs200217 #endif
6514b22b933Srs200217     else return EINVAL;
6524b22b933Srs200217 
653*5ffb0c9bSToomas Soome     if (*sktPtr < 0) { err = errno; perror((intfAddr->sa_family == AF_INET) ? "socket AF_INET" : "socket AF_INET6"); }
6544b22b933Srs200217 
6554b22b933Srs200217     // ... with a shared UDP port, if it's for multicast receiving
6564b22b933Srs200217     if (err == 0 && port.NotAnInteger)
6574b22b933Srs200217     {
6584b22b933Srs200217         #if defined(SO_REUSEPORT)
6594b22b933Srs200217         err = setsockopt(*sktPtr, SOL_SOCKET, SO_REUSEPORT, &kOn, sizeof(kOn));
6604b22b933Srs200217         #elif defined(SO_REUSEADDR)
6614b22b933Srs200217         err = setsockopt(*sktPtr, SOL_SOCKET, SO_REUSEADDR, &kOn, sizeof(kOn));
6624b22b933Srs200217         #else
6634b22b933Srs200217             #error This platform has no way to avoid address busy errors on multicast.
6644b22b933Srs200217         #endif
6654b22b933Srs200217         if (err < 0) { err = errno; perror("setsockopt - SO_REUSExxxx"); }
666*5ffb0c9bSToomas Soome 
667*5ffb0c9bSToomas Soome         // Enable inbound packets on IFEF_AWDL interface.
668*5ffb0c9bSToomas Soome         // Only done for multicast sockets, since we don't expect unicast socket operations
669*5ffb0c9bSToomas Soome         // on the IFEF_AWDL interface. Operation is a no-op for other interface types.
670*5ffb0c9bSToomas Soome         #ifdef SO_RECV_ANYIF
671*5ffb0c9bSToomas Soome         if (setsockopt(*sktPtr, SOL_SOCKET, SO_RECV_ANYIF, &kOn, sizeof(kOn)) < 0) perror("setsockopt - SO_RECV_ANYIF");
672*5ffb0c9bSToomas Soome         #endif
6734b22b933Srs200217     }
6744b22b933Srs200217 
6754b22b933Srs200217     // We want to receive destination addresses and interface identifiers.
6764b22b933Srs200217     if (intfAddr->sa_family == AF_INET)
6774b22b933Srs200217     {
6784b22b933Srs200217         struct ip_mreq imr;
6794b22b933Srs200217         struct sockaddr_in bindAddr;
6804b22b933Srs200217         if (err == 0)
6814b22b933Srs200217         {
682*5ffb0c9bSToomas Soome             #if defined(IP_PKTINFO)                                 // Linux
6834b22b933Srs200217             err = setsockopt(*sktPtr, IPPROTO_IP, IP_PKTINFO, &kOn, sizeof(kOn));
6844b22b933Srs200217             if (err < 0) { err = errno; perror("setsockopt - IP_PKTINFO"); }
685*5ffb0c9bSToomas Soome             #elif defined(IP_RECVDSTADDR) || defined(IP_RECVIF)     // BSD and Solaris
6864b22b933Srs200217                 #if defined(IP_RECVDSTADDR)
6874b22b933Srs200217             err = setsockopt(*sktPtr, IPPROTO_IP, IP_RECVDSTADDR, &kOn, sizeof(kOn));
6884b22b933Srs200217             if (err < 0) { err = errno; perror("setsockopt - IP_RECVDSTADDR"); }
6894b22b933Srs200217                 #endif
6904b22b933Srs200217                 #if defined(IP_RECVIF)
6914b22b933Srs200217             if (err == 0)
6924b22b933Srs200217             {
6934b22b933Srs200217                 err = setsockopt(*sktPtr, IPPROTO_IP, IP_RECVIF, &kOn, sizeof(kOn));
6944b22b933Srs200217                 if (err < 0) { err = errno; perror("setsockopt - IP_RECVIF"); }
6954b22b933Srs200217             }
6964b22b933Srs200217                 #endif
6974b22b933Srs200217             #else
6984b22b933Srs200217                 #warning This platform has no way to get the destination interface information -- will only work for single-homed hosts
6994b22b933Srs200217             #endif
7004b22b933Srs200217         }
7014b22b933Srs200217     #if defined(IP_RECVTTL)                                 // Linux
7024b22b933Srs200217         if (err == 0)
7034b22b933Srs200217         {
7044b22b933Srs200217             setsockopt(*sktPtr, IPPROTO_IP, IP_RECVTTL, &kOn, sizeof(kOn));
7054b22b933Srs200217             // We no longer depend on being able to get the received TTL, so don't worry if the option fails
7064b22b933Srs200217         }
7074b22b933Srs200217     #endif
7084b22b933Srs200217 
7094b22b933Srs200217         // Add multicast group membership on this interface
7104b22b933Srs200217         if (err == 0 && JoinMulticastGroup)
7114b22b933Srs200217         {
712*5ffb0c9bSToomas Soome             imr.imr_multiaddr.s_addr = AllDNSLinkGroup_v4.ip.v4.NotAnInteger;
7134b22b933Srs200217             imr.imr_interface        = ((struct sockaddr_in*)intfAddr)->sin_addr;
7144b22b933Srs200217             err = setsockopt(*sktPtr, IPPROTO_IP, IP_ADD_MEMBERSHIP, &imr, sizeof(imr));
7154b22b933Srs200217             if (err < 0) { err = errno; perror("setsockopt - IP_ADD_MEMBERSHIP"); }
7164b22b933Srs200217         }
7174b22b933Srs200217 
7184b22b933Srs200217         // Specify outgoing interface too
7194b22b933Srs200217         if (err == 0 && JoinMulticastGroup)
7204b22b933Srs200217         {
7214b22b933Srs200217             err = setsockopt(*sktPtr, IPPROTO_IP, IP_MULTICAST_IF, &((struct sockaddr_in*)intfAddr)->sin_addr, sizeof(struct in_addr));
7224b22b933Srs200217             if (err < 0) { err = errno; perror("setsockopt - IP_MULTICAST_IF"); }
7234b22b933Srs200217         }
7244b22b933Srs200217 
7254b22b933Srs200217         // Per the mDNS spec, send unicast packets with TTL 255
7264b22b933Srs200217         if (err == 0)
7274b22b933Srs200217         {
7284b22b933Srs200217             err = setsockopt(*sktPtr, IPPROTO_IP, IP_TTL, &kIntTwoFiveFive, sizeof(kIntTwoFiveFive));
7294b22b933Srs200217             if (err < 0) { err = errno; perror("setsockopt - IP_TTL"); }
7304b22b933Srs200217         }
7314b22b933Srs200217 
7324b22b933Srs200217         // and multicast packets with TTL 255 too
7334b22b933Srs200217         // There's some debate as to whether IP_MULTICAST_TTL is an int or a byte so we just try both.
7344b22b933Srs200217         if (err == 0)
7354b22b933Srs200217         {
7364b22b933Srs200217             err = setsockopt(*sktPtr, IPPROTO_IP, IP_MULTICAST_TTL, &kByteTwoFiveFive, sizeof(kByteTwoFiveFive));
7374b22b933Srs200217             if (err < 0 && errno == EINVAL)
7384b22b933Srs200217                 err = setsockopt(*sktPtr, IPPROTO_IP, IP_MULTICAST_TTL, &kIntTwoFiveFive, sizeof(kIntTwoFiveFive));
7394b22b933Srs200217             if (err < 0) { err = errno; perror("setsockopt - IP_MULTICAST_TTL"); }
7404b22b933Srs200217         }
7414b22b933Srs200217 
7424b22b933Srs200217         // And start listening for packets
7434b22b933Srs200217         if (err == 0)
7444b22b933Srs200217         {
7454b22b933Srs200217             bindAddr.sin_family      = AF_INET;
7464b22b933Srs200217             bindAddr.sin_port        = port.NotAnInteger;
7474b22b933Srs200217             bindAddr.sin_addr.s_addr = INADDR_ANY; // Want to receive multicasts AND unicasts on this socket
7484b22b933Srs200217             err = bind(*sktPtr, (struct sockaddr *) &bindAddr, sizeof(bindAddr));
7494b22b933Srs200217             if (err < 0) { err = errno; perror("bind"); fflush(stderr); }
7504b22b933Srs200217         }
7514b22b933Srs200217     }     // endif (intfAddr->sa_family == AF_INET)
7524b22b933Srs200217 
7534b22b933Srs200217 #if HAVE_IPV6
7544b22b933Srs200217     else if (intfAddr->sa_family == AF_INET6)
7554b22b933Srs200217     {
7564b22b933Srs200217         struct ipv6_mreq imr6;
7574b22b933Srs200217         struct sockaddr_in6 bindAddr6;
7584b22b933Srs200217     #if defined(IPV6_RECVPKTINFO) // Solaris
7594b22b933Srs200217         if (err == 0)
7604b22b933Srs200217         {
7614b22b933Srs200217             err = setsockopt(*sktPtr, IPPROTO_IPV6, IPV6_RECVPKTINFO, &kOn, sizeof(kOn));
762*5ffb0c9bSToomas Soome             if (err < 0) { err = errno; perror("setsockopt - IPV6_RECVPKTINFO"); }
7634b22b933Srs200217         }
7644b22b933Srs200217     #elif defined(IPV6_PKTINFO)
7654b22b933Srs200217         if (err == 0)
7664b22b933Srs200217         {
767*5ffb0c9bSToomas Soome             err = setsockopt(*sktPtr, IPPROTO_IPV6, IPV6_2292_PKTINFO, &kOn, sizeof(kOn));
7684b22b933Srs200217             if (err < 0) { err = errno; perror("setsockopt - IPV6_PKTINFO"); }
7694b22b933Srs200217         }
7704b22b933Srs200217     #else
7714b22b933Srs200217         #warning This platform has no way to get the destination interface information for IPv6 -- will only work for single-homed hosts
7724b22b933Srs200217     #endif
773*5ffb0c9bSToomas Soome     #if defined(IPV6_RECVHOPLIMIT)
7744b22b933Srs200217         if (err == 0)
7754b22b933Srs200217         {
7764b22b933Srs200217             err = setsockopt(*sktPtr, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &kOn, sizeof(kOn));
777*5ffb0c9bSToomas Soome             if (err < 0) { err = errno; perror("setsockopt - IPV6_RECVHOPLIMIT"); }
7784b22b933Srs200217         }
7794b22b933Srs200217     #elif defined(IPV6_HOPLIMIT)
7804b22b933Srs200217         if (err == 0)
7814b22b933Srs200217         {
782*5ffb0c9bSToomas Soome             err = setsockopt(*sktPtr, IPPROTO_IPV6, IPV6_2292_HOPLIMIT, &kOn, sizeof(kOn));
7834b22b933Srs200217             if (err < 0) { err = errno; perror("setsockopt - IPV6_HOPLIMIT"); }
7844b22b933Srs200217         }
7854b22b933Srs200217     #endif
7864b22b933Srs200217 
7874b22b933Srs200217         // Add multicast group membership on this interface
7884b22b933Srs200217         if (err == 0 && JoinMulticastGroup)
7894b22b933Srs200217         {
790*5ffb0c9bSToomas Soome             imr6.ipv6mr_multiaddr       = *(const struct in6_addr*)&AllDNSLinkGroup_v6.ip.v6;
7914b22b933Srs200217             imr6.ipv6mr_interface       = interfaceIndex;
7924b22b933Srs200217             //LogMsg("Joining %.16a on %d", &imr6.ipv6mr_multiaddr, imr6.ipv6mr_interface);
7934b22b933Srs200217             err = setsockopt(*sktPtr, IPPROTO_IPV6, IPV6_JOIN_GROUP, &imr6, sizeof(imr6));
7944b22b933Srs200217             if (err < 0)
7954b22b933Srs200217             {
7964b22b933Srs200217                 err = errno;
7974b22b933Srs200217                 verbosedebugf("IPV6_JOIN_GROUP %.16a on %d failed.\n", &imr6.ipv6mr_multiaddr, imr6.ipv6mr_interface);
7984b22b933Srs200217                 perror("setsockopt - IPV6_JOIN_GROUP");
7994b22b933Srs200217             }
8004b22b933Srs200217         }
8014b22b933Srs200217 
8024b22b933Srs200217         // Specify outgoing interface too
8034b22b933Srs200217         if (err == 0 && JoinMulticastGroup)
8044b22b933Srs200217         {
8054b22b933Srs200217             u_int multicast_if = interfaceIndex;
8064b22b933Srs200217             err = setsockopt(*sktPtr, IPPROTO_IPV6, IPV6_MULTICAST_IF, &multicast_if, sizeof(multicast_if));
8074b22b933Srs200217             if (err < 0) { err = errno; perror("setsockopt - IPV6_MULTICAST_IF"); }
8084b22b933Srs200217         }
8094b22b933Srs200217 
8104b22b933Srs200217         // We want to receive only IPv6 packets on this socket.
8114b22b933Srs200217         // Without this option, we may get IPv4 addresses as mapped addresses.
8124b22b933Srs200217         if (err == 0)
8134b22b933Srs200217         {
8144b22b933Srs200217             err = setsockopt(*sktPtr, IPPROTO_IPV6, IPV6_V6ONLY, &kOn, sizeof(kOn));
8154b22b933Srs200217             if (err < 0) { err = errno; perror("setsockopt - IPV6_V6ONLY"); }
8164b22b933Srs200217         }
8174b22b933Srs200217 
8184b22b933Srs200217         // Per the mDNS spec, send unicast packets with TTL 255
8194b22b933Srs200217         if (err == 0)
8204b22b933Srs200217         {
8214b22b933Srs200217             err = setsockopt(*sktPtr, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &kIntTwoFiveFive, sizeof(kIntTwoFiveFive));
8224b22b933Srs200217             if (err < 0) { err = errno; perror("setsockopt - IPV6_UNICAST_HOPS"); }
8234b22b933Srs200217         }
8244b22b933Srs200217 
8254b22b933Srs200217         // and multicast packets with TTL 255 too
8264b22b933Srs200217         // There's some debate as to whether IPV6_MULTICAST_HOPS is an int or a byte so we just try both.
8274b22b933Srs200217         if (err == 0)
8284b22b933Srs200217         {
8294b22b933Srs200217             err = setsockopt(*sktPtr, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &kByteTwoFiveFive, sizeof(kByteTwoFiveFive));
8304b22b933Srs200217             if (err < 0 && errno == EINVAL)
8314b22b933Srs200217                 err = setsockopt(*sktPtr, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &kIntTwoFiveFive, sizeof(kIntTwoFiveFive));
8324b22b933Srs200217             if (err < 0) { err = errno; perror("setsockopt - IPV6_MULTICAST_HOPS"); }
8334b22b933Srs200217         }
8344b22b933Srs200217 
8354b22b933Srs200217         // And start listening for packets
8364b22b933Srs200217         if (err == 0)
8374b22b933Srs200217         {
8384b22b933Srs200217             mDNSPlatformMemZero(&bindAddr6, sizeof(bindAddr6));
8394b22b933Srs200217 #ifndef NOT_HAVE_SA_LEN
8404b22b933Srs200217             bindAddr6.sin6_len         = sizeof(bindAddr6);
8414b22b933Srs200217 #endif
8424b22b933Srs200217             bindAddr6.sin6_family      = AF_INET6;
8434b22b933Srs200217             bindAddr6.sin6_port        = port.NotAnInteger;
8444b22b933Srs200217             bindAddr6.sin6_flowinfo    = 0;
8454b22b933Srs200217             bindAddr6.sin6_addr        = in6addr_any; // Want to receive multicasts AND unicasts on this socket
8464b22b933Srs200217             bindAddr6.sin6_scope_id    = 0;
8474b22b933Srs200217             err = bind(*sktPtr, (struct sockaddr *) &bindAddr6, sizeof(bindAddr6));
8484b22b933Srs200217             if (err < 0) { err = errno; perror("bind"); fflush(stderr); }
8494b22b933Srs200217         }
8504b22b933Srs200217     }     // endif (intfAddr->sa_family == AF_INET6)
8514b22b933Srs200217 #endif
8524b22b933Srs200217 
8534b22b933Srs200217     // Set the socket to non-blocking.
8544b22b933Srs200217     if (err == 0)
8554b22b933Srs200217     {
8564b22b933Srs200217         err = fcntl(*sktPtr, F_GETFL, 0);
8574b22b933Srs200217         if (err < 0) err = errno;
8584b22b933Srs200217         else
8594b22b933Srs200217         {
8604b22b933Srs200217             err = fcntl(*sktPtr, F_SETFL, err | O_NONBLOCK);
8614b22b933Srs200217             if (err < 0) err = errno;
8624b22b933Srs200217         }
8634b22b933Srs200217     }
8644b22b933Srs200217 
8654b22b933Srs200217     // Clean up
8664b22b933Srs200217     if (err != 0 && *sktPtr != -1) { assert(close(*sktPtr) == 0); *sktPtr = -1; }
8674b22b933Srs200217     assert((err == 0) == (*sktPtr != -1));
8684b22b933Srs200217     return err;
8694b22b933Srs200217 }
8704b22b933Srs200217 
8714b22b933Srs200217 // Creates a PosixNetworkInterface for the interface whose IP address is
8724b22b933Srs200217 // intfAddr and whose name is intfName and registers it with mDNS core.
SetupOneInterface(mDNS * const m,struct sockaddr * intfAddr,struct sockaddr * intfMask,const char * intfName,int intfIndex)8734b22b933Srs200217 mDNSlocal int SetupOneInterface(mDNS *const m, struct sockaddr *intfAddr, struct sockaddr *intfMask, const char *intfName, int intfIndex)
8744b22b933Srs200217 {
8754b22b933Srs200217     int err = 0;
8764b22b933Srs200217     PosixNetworkInterface *intf;
8774b22b933Srs200217     PosixNetworkInterface *alias = NULL;
8784b22b933Srs200217 
8794b22b933Srs200217     assert(m != NULL);
8804b22b933Srs200217     assert(intfAddr != NULL);
8814b22b933Srs200217     assert(intfName != NULL);
8824b22b933Srs200217     assert(intfMask != NULL);
8834b22b933Srs200217 
8844b22b933Srs200217     // Allocate the interface structure itself.
8854b22b933Srs200217     intf = (PosixNetworkInterface*)malloc(sizeof(*intf));
8864b22b933Srs200217     if (intf == NULL) { assert(0); err = ENOMEM; }
8874b22b933Srs200217 
8884b22b933Srs200217     // And make a copy of the intfName.
8894b22b933Srs200217     if (err == 0)
8904b22b933Srs200217     {
8914b22b933Srs200217         intf->intfName = strdup(intfName);
8924b22b933Srs200217         if (intf->intfName == NULL) { assert(0); err = ENOMEM; }
8934b22b933Srs200217     }
8944b22b933Srs200217 
8954b22b933Srs200217     if (err == 0)
8964b22b933Srs200217     {
8974b22b933Srs200217         // Set up the fields required by the mDNS core.
8984b22b933Srs200217         SockAddrTomDNSAddr(intfAddr, &intf->coreIntf.ip, NULL);
8994b22b933Srs200217         SockAddrTomDNSAddr(intfMask, &intf->coreIntf.mask, NULL);
900*5ffb0c9bSToomas Soome 
9014b22b933Srs200217         //LogMsg("SetupOneInterface: %#a %#a",  &intf->coreIntf.ip,  &intf->coreIntf.mask);
9024b22b933Srs200217         strncpy(intf->coreIntf.ifname, intfName, sizeof(intf->coreIntf.ifname));
9034b22b933Srs200217         intf->coreIntf.ifname[sizeof(intf->coreIntf.ifname)-1] = 0;
9044b22b933Srs200217         intf->coreIntf.Advertise = m->AdvertiseLocalAddresses;
9054b22b933Srs200217         intf->coreIntf.McastTxRx = mDNStrue;
9064b22b933Srs200217 
9074b22b933Srs200217         // Set up the extra fields in PosixNetworkInterface.
9084b22b933Srs200217         assert(intf->intfName != NULL);         // intf->intfName already set up above
9094b22b933Srs200217         intf->index                = intfIndex;
9104b22b933Srs200217         intf->multicastSocket4     = -1;
9114b22b933Srs200217 #if HAVE_IPV6
9124b22b933Srs200217         intf->multicastSocket6     = -1;
9134b22b933Srs200217 #endif
9144b22b933Srs200217         alias                      = SearchForInterfaceByName(m, intf->intfName);
9154b22b933Srs200217         if (alias == NULL) alias   = intf;
9164b22b933Srs200217         intf->coreIntf.InterfaceID = (mDNSInterfaceID)alias;
9174b22b933Srs200217 
9184b22b933Srs200217         if (alias != intf)
9194b22b933Srs200217             debugf("SetupOneInterface: %s %#a is an alias of %#a", intfName, &intf->coreIntf.ip, &alias->coreIntf.ip);
9204b22b933Srs200217     }
9214b22b933Srs200217 
9224b22b933Srs200217     // Set up the multicast socket
9234b22b933Srs200217     if (err == 0)
9244b22b933Srs200217     {
9254b22b933Srs200217         if (alias->multicastSocket4 == -1 && intfAddr->sa_family == AF_INET)
9264b22b933Srs200217             err = SetupSocket(intfAddr, MulticastDNSPort, intf->index, &alias->multicastSocket4);
9274b22b933Srs200217 #if HAVE_IPV6
9284b22b933Srs200217         else if (alias->multicastSocket6 == -1 && intfAddr->sa_family == AF_INET6)
9294b22b933Srs200217             err = SetupSocket(intfAddr, MulticastDNSPort, intf->index, &alias->multicastSocket6);
9304b22b933Srs200217 #endif
9314b22b933Srs200217     }
9324b22b933Srs200217 
933*5ffb0c9bSToomas Soome     // If interface is a direct link, address record will be marked as kDNSRecordTypeKnownUnique
934*5ffb0c9bSToomas Soome     // and skip the probe phase of the probe/announce packet sequence.
935*5ffb0c9bSToomas Soome     intf->coreIntf.DirectLink = mDNSfalse;
936*5ffb0c9bSToomas Soome #ifdef DIRECTLINK_INTERFACE_NAME
937*5ffb0c9bSToomas Soome 	if (strcmp(intfName, STRINGIFY(DIRECTLINK_INTERFACE_NAME)) == 0)
938*5ffb0c9bSToomas Soome 		intf->coreIntf.DirectLink = mDNStrue;
939*5ffb0c9bSToomas Soome #endif
940*5ffb0c9bSToomas Soome 
9414b22b933Srs200217     // The interface is all ready to go, let's register it with the mDNS core.
9424b22b933Srs200217     if (err == 0)
9434b22b933Srs200217         err = mDNS_RegisterInterface(m, &intf->coreIntf, mDNSfalse);
9444b22b933Srs200217 
9454b22b933Srs200217     // Clean up.
9464b22b933Srs200217     if (err == 0)
9474b22b933Srs200217     {
9484b22b933Srs200217         num_registered_interfaces++;
9494b22b933Srs200217         debugf("SetupOneInterface: %s %#a Registered", intf->intfName, &intf->coreIntf.ip);
9504b22b933Srs200217         if (gMDNSPlatformPosixVerboseLevel > 0)
9514b22b933Srs200217             fprintf(stderr, "Registered interface %s\n", intf->intfName);
9524b22b933Srs200217     }
9534b22b933Srs200217     else
9544b22b933Srs200217     {
9554b22b933Srs200217         // Use intfName instead of intf->intfName in the next line to avoid dereferencing NULL.
9564b22b933Srs200217         debugf("SetupOneInterface: %s %#a failed to register %d", intfName, &intf->coreIntf.ip, err);
9574b22b933Srs200217         if (intf) { FreePosixNetworkInterface(intf); intf = NULL; }
9584b22b933Srs200217     }
9594b22b933Srs200217 
9604b22b933Srs200217     assert((err == 0) == (intf != NULL));
9614b22b933Srs200217 
9624b22b933Srs200217     return err;
9634b22b933Srs200217 }
9644b22b933Srs200217 
9654b22b933Srs200217 // Call get_ifi_info() to obtain a list of active interfaces and call SetupOneInterface() on each one.
SetupInterfaceList(mDNS * const m)9664b22b933Srs200217 mDNSlocal int SetupInterfaceList(mDNS *const m)
9674b22b933Srs200217 {
9684b22b933Srs200217     mDNSBool foundav4       = mDNSfalse;
9694b22b933Srs200217     int err            = 0;
9704b22b933Srs200217     struct ifi_info *intfList      = get_ifi_info(AF_INET, mDNStrue);
9714b22b933Srs200217     struct ifi_info *firstLoopback = NULL;
9724b22b933Srs200217 
9734b22b933Srs200217     assert(m != NULL);
9744b22b933Srs200217     debugf("SetupInterfaceList");
9754b22b933Srs200217 
9764b22b933Srs200217     if (intfList == NULL) err = ENOENT;
9774b22b933Srs200217 
9784b22b933Srs200217 #if HAVE_IPV6
9794b22b933Srs200217     if (err == 0)       /* Link the IPv6 list to the end of the IPv4 list */
9804b22b933Srs200217     {
9814b22b933Srs200217         struct ifi_info **p = &intfList;
9824b22b933Srs200217         while (*p) p = &(*p)->ifi_next;
9834b22b933Srs200217         *p = get_ifi_info(AF_INET6, mDNStrue);
9844b22b933Srs200217     }
9854b22b933Srs200217 #endif
9864b22b933Srs200217 
9874b22b933Srs200217     if (err == 0)
9884b22b933Srs200217     {
9894b22b933Srs200217         struct ifi_info *i = intfList;
9904b22b933Srs200217         while (i)
9914b22b933Srs200217         {
9924b22b933Srs200217             if (     ((i->ifi_addr->sa_family == AF_INET)
9934b22b933Srs200217 #if HAVE_IPV6
9944b22b933Srs200217                       || (i->ifi_addr->sa_family == AF_INET6)
9954b22b933Srs200217 #endif
9964b22b933Srs200217                       ) &&  (i->ifi_flags & IFF_UP) && !(i->ifi_flags & IFF_POINTOPOINT))
9974b22b933Srs200217             {
9984b22b933Srs200217                 if (i->ifi_flags & IFF_LOOPBACK)
9994b22b933Srs200217                 {
10004b22b933Srs200217                     if (firstLoopback == NULL)
10014b22b933Srs200217                         firstLoopback = i;
10024b22b933Srs200217                 }
10034b22b933Srs200217                 else
10044b22b933Srs200217                 {
10054b22b933Srs200217                     if (SetupOneInterface(m, i->ifi_addr, i->ifi_netmask, i->ifi_name, i->ifi_index) == 0)
10064b22b933Srs200217                         if (i->ifi_addr->sa_family == AF_INET)
10074b22b933Srs200217                             foundav4 = mDNStrue;
10084b22b933Srs200217                 }
10094b22b933Srs200217             }
10104b22b933Srs200217             i = i->ifi_next;
10114b22b933Srs200217         }
10124b22b933Srs200217 
10134b22b933Srs200217         // If we found no normal interfaces but we did find a loopback interface, register the
10144b22b933Srs200217         // loopback interface.  This allows self-discovery if no interfaces are configured.
10154b22b933Srs200217         // Temporary workaround: Multicast loopback on IPv6 interfaces appears not to work.
10164b22b933Srs200217         // In the interim, we skip loopback interface only if we found at least one v4 interface to use
10174b22b933Srs200217         // if ((m->HostInterfaces == NULL) && (firstLoopback != NULL))
10184b22b933Srs200217         if (!foundav4 && firstLoopback)
10194b22b933Srs200217             (void) SetupOneInterface(m, firstLoopback->ifi_addr, firstLoopback->ifi_netmask, firstLoopback->ifi_name, firstLoopback->ifi_index);
10204b22b933Srs200217     }
10214b22b933Srs200217 
10224b22b933Srs200217     // Clean up.
10234b22b933Srs200217     if (intfList != NULL) free_ifi_info(intfList);
1024*5ffb0c9bSToomas Soome 
1025*5ffb0c9bSToomas Soome     // Clean up any interfaces that have been hanging around on the RecentInterfaces list for more than a minute
1026*5ffb0c9bSToomas Soome     PosixNetworkInterface **ri = &gRecentInterfaces;
1027*5ffb0c9bSToomas Soome     const mDNSs32 utc = mDNSPlatformUTC();
1028*5ffb0c9bSToomas Soome     while (*ri)
1029*5ffb0c9bSToomas Soome     {
1030*5ffb0c9bSToomas Soome         PosixNetworkInterface *pi = *ri;
1031*5ffb0c9bSToomas Soome         if (utc - pi->LastSeen < 60) ri = (PosixNetworkInterface **)&pi->coreIntf.next;
1032*5ffb0c9bSToomas Soome         else { *ri = (PosixNetworkInterface *)pi->coreIntf.next; free(pi); }
1033*5ffb0c9bSToomas Soome     }
1034*5ffb0c9bSToomas Soome 
10354b22b933Srs200217     return err;
10364b22b933Srs200217 }
10374b22b933Srs200217 
10384b22b933Srs200217 #if USES_NETLINK
10394b22b933Srs200217 
10404b22b933Srs200217 // See <http://www.faqs.org/rfcs/rfc3549.html> for a description of NetLink
10414b22b933Srs200217 
10424b22b933Srs200217 // Open a socket that will receive interface change notifications
OpenIfNotifySocket(int * pFD)10434b22b933Srs200217 mDNSlocal mStatus OpenIfNotifySocket(int *pFD)
10444b22b933Srs200217 {
10454b22b933Srs200217     mStatus err = mStatus_NoError;
10464b22b933Srs200217     struct sockaddr_nl snl;
10474b22b933Srs200217     int sock;
10484b22b933Srs200217     int ret;
10494b22b933Srs200217 
10504b22b933Srs200217     sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
10514b22b933Srs200217     if (sock < 0)
10524b22b933Srs200217         return errno;
10534b22b933Srs200217 
10544b22b933Srs200217     // Configure read to be non-blocking because inbound msg size is not known in advance
10554b22b933Srs200217     (void) fcntl(sock, F_SETFL, O_NONBLOCK);
10564b22b933Srs200217 
10574b22b933Srs200217     /* Subscribe the socket to Link & IP addr notifications. */
1058*5ffb0c9bSToomas Soome     mDNSPlatformMemZero(&snl, sizeof snl);
10594b22b933Srs200217     snl.nl_family = AF_NETLINK;
10604b22b933Srs200217     snl.nl_groups = RTMGRP_LINK | RTMGRP_IPV4_IFADDR;
10614b22b933Srs200217     ret = bind(sock, (struct sockaddr *) &snl, sizeof snl);
10624b22b933Srs200217     if (0 == ret)
10634b22b933Srs200217         *pFD = sock;
10644b22b933Srs200217     else
10654b22b933Srs200217         err = errno;
10664b22b933Srs200217 
10674b22b933Srs200217     return err;
10684b22b933Srs200217 }
10694b22b933Srs200217 
10704b22b933Srs200217 #if MDNS_DEBUGMSGS
PrintNetLinkMsg(const struct nlmsghdr * pNLMsg)10714b22b933Srs200217 mDNSlocal void      PrintNetLinkMsg(const struct nlmsghdr *pNLMsg)
10724b22b933Srs200217 {
10734b22b933Srs200217     const char *kNLMsgTypes[] = { "", "NLMSG_NOOP", "NLMSG_ERROR", "NLMSG_DONE", "NLMSG_OVERRUN" };
10744b22b933Srs200217     const char *kNLRtMsgTypes[] = { "RTM_NEWLINK", "RTM_DELLINK", "RTM_GETLINK", "RTM_NEWADDR", "RTM_DELADDR", "RTM_GETADDR" };
10754b22b933Srs200217 
10764b22b933Srs200217     printf("nlmsghdr len=%d, type=%s, flags=0x%x\n", pNLMsg->nlmsg_len,
10774b22b933Srs200217            pNLMsg->nlmsg_type < RTM_BASE ? kNLMsgTypes[pNLMsg->nlmsg_type] : kNLRtMsgTypes[pNLMsg->nlmsg_type - RTM_BASE],
10784b22b933Srs200217            pNLMsg->nlmsg_flags);
10794b22b933Srs200217 
10804b22b933Srs200217     if (RTM_NEWLINK <= pNLMsg->nlmsg_type && pNLMsg->nlmsg_type <= RTM_GETLINK)
10814b22b933Srs200217     {
10824b22b933Srs200217         struct ifinfomsg    *pIfInfo = (struct ifinfomsg*) NLMSG_DATA(pNLMsg);
10834b22b933Srs200217         printf("ifinfomsg family=%d, type=%d, index=%d, flags=0x%x, change=0x%x\n", pIfInfo->ifi_family,
10844b22b933Srs200217                pIfInfo->ifi_type, pIfInfo->ifi_index, pIfInfo->ifi_flags, pIfInfo->ifi_change);
10854b22b933Srs200217 
10864b22b933Srs200217     }
10874b22b933Srs200217     else if (RTM_NEWADDR <= pNLMsg->nlmsg_type && pNLMsg->nlmsg_type <= RTM_GETADDR)
10884b22b933Srs200217     {
10894b22b933Srs200217         struct ifaddrmsg    *pIfAddr = (struct ifaddrmsg*) NLMSG_DATA(pNLMsg);
10904b22b933Srs200217         printf("ifaddrmsg family=%d, index=%d, flags=0x%x\n", pIfAddr->ifa_family,
10914b22b933Srs200217                pIfAddr->ifa_index, pIfAddr->ifa_flags);
10924b22b933Srs200217     }
10934b22b933Srs200217     printf("\n");
10944b22b933Srs200217 }
10954b22b933Srs200217 #endif
10964b22b933Srs200217 
ProcessRoutingNotification(int sd)10974b22b933Srs200217 mDNSlocal mDNSu32       ProcessRoutingNotification(int sd)
10984b22b933Srs200217 // Read through the messages on sd and if any indicate that any interface records should
10994b22b933Srs200217 // be torn down and rebuilt, return affected indices as a bitmask. Otherwise return 0.
11004b22b933Srs200217 {
11014b22b933Srs200217     ssize_t readCount;
11024b22b933Srs200217     char buff[4096];
11034b22b933Srs200217     struct nlmsghdr         *pNLMsg = (struct nlmsghdr*) buff;
11044b22b933Srs200217     mDNSu32 result = 0;
11054b22b933Srs200217 
11064b22b933Srs200217     // The structure here is more complex than it really ought to be because,
11074b22b933Srs200217     // unfortunately, there's no good way to size a buffer in advance large
11084b22b933Srs200217     // enough to hold all pending data and so avoid message fragmentation.
11094b22b933Srs200217     // (Note that FIONREAD is not supported on AF_NETLINK.)
11104b22b933Srs200217 
11114b22b933Srs200217     readCount = read(sd, buff, sizeof buff);
11124b22b933Srs200217     while (1)
11134b22b933Srs200217     {
11144b22b933Srs200217         // Make sure we've got an entire nlmsghdr in the buffer, and payload, too.
11154b22b933Srs200217         // If not, discard already-processed messages in buffer and read more data.
11164b22b933Srs200217         if (((char*) &pNLMsg[1] > (buff + readCount)) ||    // i.e. *pNLMsg extends off end of buffer
11174b22b933Srs200217             ((char*) pNLMsg + pNLMsg->nlmsg_len > (buff + readCount)))
11184b22b933Srs200217         {
11194b22b933Srs200217             if (buff < (char*) pNLMsg)      // we have space to shuffle
11204b22b933Srs200217             {
11214b22b933Srs200217                 // discard processed data
11224b22b933Srs200217                 readCount -= ((char*) pNLMsg - buff);
11234b22b933Srs200217                 memmove(buff, pNLMsg, readCount);
11244b22b933Srs200217                 pNLMsg = (struct nlmsghdr*) buff;
11254b22b933Srs200217 
11264b22b933Srs200217                 // read more data
11274b22b933Srs200217                 readCount += read(sd, buff + readCount, sizeof buff - readCount);
11284b22b933Srs200217                 continue;                   // spin around and revalidate with new readCount
11294b22b933Srs200217             }
11304b22b933Srs200217             else
11314b22b933Srs200217                 break;  // Otherwise message does not fit in buffer
11324b22b933Srs200217         }
11334b22b933Srs200217 
11344b22b933Srs200217 #if MDNS_DEBUGMSGS
11354b22b933Srs200217         PrintNetLinkMsg(pNLMsg);
11364b22b933Srs200217 #endif
11374b22b933Srs200217 
11384b22b933Srs200217         // Process the NetLink message
11394b22b933Srs200217         if (pNLMsg->nlmsg_type == RTM_GETLINK || pNLMsg->nlmsg_type == RTM_NEWLINK)
11404b22b933Srs200217             result |= 1 << ((struct ifinfomsg*) NLMSG_DATA(pNLMsg))->ifi_index;
11414b22b933Srs200217         else if (pNLMsg->nlmsg_type == RTM_DELADDR || pNLMsg->nlmsg_type == RTM_NEWADDR)
11424b22b933Srs200217             result |= 1 << ((struct ifaddrmsg*) NLMSG_DATA(pNLMsg))->ifa_index;
11434b22b933Srs200217 
11444b22b933Srs200217         // Advance pNLMsg to the next message in the buffer
11454b22b933Srs200217         if ((pNLMsg->nlmsg_flags & NLM_F_MULTI) != 0 && pNLMsg->nlmsg_type != NLMSG_DONE)
11464b22b933Srs200217         {
11474b22b933Srs200217             ssize_t len = readCount - ((char*)pNLMsg - buff);
11484b22b933Srs200217             pNLMsg = NLMSG_NEXT(pNLMsg, len);
11494b22b933Srs200217         }
11504b22b933Srs200217         else
11514b22b933Srs200217             break;  // all done!
11524b22b933Srs200217     }
11534b22b933Srs200217 
11544b22b933Srs200217     return result;
11554b22b933Srs200217 }
11564b22b933Srs200217 
11574b22b933Srs200217 #else // USES_NETLINK
11584b22b933Srs200217 
11594b22b933Srs200217 // Open a socket that will receive interface change notifications
OpenIfNotifySocket(int * pFD)11604b22b933Srs200217 mDNSlocal mStatus OpenIfNotifySocket(int *pFD)
11614b22b933Srs200217 {
11624b22b933Srs200217     *pFD = socket(AF_ROUTE, SOCK_RAW, 0);
11634b22b933Srs200217 
11644b22b933Srs200217     if (*pFD < 0)
11654b22b933Srs200217         return mStatus_UnknownErr;
11664b22b933Srs200217 
11674b22b933Srs200217     // Configure read to be non-blocking because inbound msg size is not known in advance
11684b22b933Srs200217     (void) fcntl(*pFD, F_SETFL, O_NONBLOCK);
11694b22b933Srs200217 
11704b22b933Srs200217     return mStatus_NoError;
11714b22b933Srs200217 }
11724b22b933Srs200217 
11734b22b933Srs200217 #if MDNS_DEBUGMSGS
PrintRoutingSocketMsg(const struct ifa_msghdr * pRSMsg)11744b22b933Srs200217 mDNSlocal void      PrintRoutingSocketMsg(const struct ifa_msghdr *pRSMsg)
11754b22b933Srs200217 {
11764b22b933Srs200217     const char *kRSMsgTypes[] = { "", "RTM_ADD", "RTM_DELETE", "RTM_CHANGE", "RTM_GET", "RTM_LOSING",
11774b22b933Srs200217                                   "RTM_REDIRECT", "RTM_MISS", "RTM_LOCK", "RTM_OLDADD", "RTM_OLDDEL", "RTM_RESOLVE",
11784b22b933Srs200217                                   "RTM_NEWADDR", "RTM_DELADDR", "RTM_IFINFO", "RTM_NEWMADDR", "RTM_DELMADDR" };
11794b22b933Srs200217 
11804b22b933Srs200217     int index = pRSMsg->ifam_type == RTM_IFINFO ? ((struct if_msghdr*) pRSMsg)->ifm_index : pRSMsg->ifam_index;
11814b22b933Srs200217 
11824b22b933Srs200217     printf("ifa_msghdr len=%d, type=%s, index=%d\n", pRSMsg->ifam_msglen, kRSMsgTypes[pRSMsg->ifam_type], index);
11834b22b933Srs200217 }
11844b22b933Srs200217 #endif
11854b22b933Srs200217 
ProcessRoutingNotification(int sd)11864b22b933Srs200217 mDNSlocal mDNSu32       ProcessRoutingNotification(int sd)
11874b22b933Srs200217 // Read through the messages on sd and if any indicate that any interface records should
11884b22b933Srs200217 // be torn down and rebuilt, return affected indices as a bitmask. Otherwise return 0.
11894b22b933Srs200217 {
11904b22b933Srs200217     ssize_t readCount;
11914b22b933Srs200217     char buff[4096];
11924b22b933Srs200217     struct ifa_msghdr       *pRSMsg = (struct ifa_msghdr*) buff;
11934b22b933Srs200217     mDNSu32 result = 0;
11944b22b933Srs200217 
11954b22b933Srs200217     readCount = read(sd, buff, sizeof buff);
11964b22b933Srs200217     if (readCount < (ssize_t) sizeof(struct ifa_msghdr))
11974b22b933Srs200217         return mStatus_UnsupportedErr;      // cannot decipher message
11984b22b933Srs200217 
11994b22b933Srs200217 #if MDNS_DEBUGMSGS
12004b22b933Srs200217     PrintRoutingSocketMsg(pRSMsg);
12014b22b933Srs200217 #endif
12024b22b933Srs200217 
12034b22b933Srs200217     // Process the message
1204*5ffb0c9bSToomas Soome     switch (pRSMsg->ifam_type)
12054b22b933Srs200217     {
1206*5ffb0c9bSToomas Soome     case RTM_NEWADDR:
1207*5ffb0c9bSToomas Soome     case RTM_DELADDR:
1208*5ffb0c9bSToomas Soome     case RTM_IFINFO:
12094b22b933Srs200217         if (pRSMsg->ifam_type == RTM_IFINFO)
12104b22b933Srs200217             result |= 1 << ((struct if_msghdr*) pRSMsg)->ifm_index;
12114b22b933Srs200217         else
12124b22b933Srs200217             result |= 1 << pRSMsg->ifam_index;
1213*5ffb0c9bSToomas Soome     break;
1214*5ffb0c9bSToomas Soome     /*
1215*5ffb0c9bSToomas Soome      * ADD & DELETE are happening when IPv6 announces are changing,
1216*5ffb0c9bSToomas Soome      * and for some reason it will stop mdnsd to announce IPv6
1217*5ffb0c9bSToomas Soome      * addresses. So we force mdnsd to check interfaces.
1218*5ffb0c9bSToomas Soome      */
1219*5ffb0c9bSToomas Soome     case RTM_ADD:
1220*5ffb0c9bSToomas Soome     case RTM_DELETE:
1221*5ffb0c9bSToomas Soome             result |= 1;
12224b22b933Srs200217     }
12234b22b933Srs200217 
12244b22b933Srs200217     return result;
12254b22b933Srs200217 }
12264b22b933Srs200217 
12274b22b933Srs200217 #endif // USES_NETLINK
12284b22b933Srs200217 
12294b22b933Srs200217 // Called when data appears on interface change notification socket
InterfaceChangeCallback(int fd,short filter,void * context)1230*5ffb0c9bSToomas Soome mDNSlocal void InterfaceChangeCallback(int fd, short filter, void *context)
12314b22b933Srs200217 {
12324b22b933Srs200217     IfChangeRec     *pChgRec = (IfChangeRec*) context;
12334b22b933Srs200217     fd_set readFDs;
12344b22b933Srs200217     mDNSu32 changedInterfaces = 0;
12354b22b933Srs200217     struct timeval zeroTimeout = { 0, 0 };
12364b22b933Srs200217 
1237*5ffb0c9bSToomas Soome     (void)fd; // Unused
1238*5ffb0c9bSToomas Soome     (void)filter; // Unused
1239*5ffb0c9bSToomas Soome 
12404b22b933Srs200217     FD_ZERO(&readFDs);
12414b22b933Srs200217     FD_SET(pChgRec->NotifySD, &readFDs);
12424b22b933Srs200217 
12434b22b933Srs200217     do
12444b22b933Srs200217     {
12454b22b933Srs200217         changedInterfaces |= ProcessRoutingNotification(pChgRec->NotifySD);
12464b22b933Srs200217     }
12474b22b933Srs200217     while (0 < select(pChgRec->NotifySD + 1, &readFDs, (fd_set*) NULL, (fd_set*) NULL, &zeroTimeout));
12484b22b933Srs200217 
12494b22b933Srs200217     // Currently we rebuild the entire interface list whenever any interface change is
12504b22b933Srs200217     // detected. If this ever proves to be a performance issue in a multi-homed
12514b22b933Srs200217     // configuration, more care should be paid to changedInterfaces.
12524b22b933Srs200217     if (changedInterfaces)
12534b22b933Srs200217         mDNSPlatformPosixRefreshInterfaceList(pChgRec->mDNS);
12544b22b933Srs200217 }
12554b22b933Srs200217 
12564b22b933Srs200217 // Register with either a Routing Socket or RtNetLink to listen for interface changes.
WatchForInterfaceChange(mDNS * const m)12574b22b933Srs200217 mDNSlocal mStatus WatchForInterfaceChange(mDNS *const m)
12584b22b933Srs200217 {
12594b22b933Srs200217     mStatus err;
12604b22b933Srs200217     IfChangeRec *pChgRec;
12614b22b933Srs200217 
12624b22b933Srs200217     pChgRec = (IfChangeRec*) mDNSPlatformMemAllocate(sizeof *pChgRec);
12634b22b933Srs200217     if (pChgRec == NULL)
12644b22b933Srs200217         return mStatus_NoMemoryErr;
12654b22b933Srs200217 
12664b22b933Srs200217     pChgRec->mDNS = m;
12674b22b933Srs200217     err = OpenIfNotifySocket(&pChgRec->NotifySD);
12684b22b933Srs200217     if (err == 0)
12694b22b933Srs200217         err = mDNSPosixAddFDToEventLoop(pChgRec->NotifySD, InterfaceChangeCallback, pChgRec);
12704b22b933Srs200217 
12714b22b933Srs200217     return err;
12724b22b933Srs200217 }
12734b22b933Srs200217 
12744b22b933Srs200217 // Test to see if we're the first client running on UDP port 5353, by trying to bind to 5353 without using SO_REUSEPORT.
12754b22b933Srs200217 // If we fail, someone else got here first. That's not a big problem; we can share the port for multicast responses --
12764b22b933Srs200217 // we just need to be aware that we shouldn't expect to successfully receive unicast UDP responses.
mDNSPlatformInit_CanReceiveUnicast(void)12774b22b933Srs200217 mDNSlocal mDNSBool mDNSPlatformInit_CanReceiveUnicast(void)
12784b22b933Srs200217 {
12794b22b933Srs200217     int err;
12804b22b933Srs200217     int s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
12814b22b933Srs200217     struct sockaddr_in s5353;
12824b22b933Srs200217     s5353.sin_family      = AF_INET;
12834b22b933Srs200217     s5353.sin_port        = MulticastDNSPort.NotAnInteger;
12844b22b933Srs200217     s5353.sin_addr.s_addr = 0;
12854b22b933Srs200217     err = bind(s, (struct sockaddr *)&s5353, sizeof(s5353));
12864b22b933Srs200217     close(s);
12874b22b933Srs200217     if (err) debugf("No unicast UDP responses");
12884b22b933Srs200217     else debugf("Unicast UDP responses okay");
12894b22b933Srs200217     return(err == 0);
12904b22b933Srs200217 }
12914b22b933Srs200217 
12924b22b933Srs200217 // mDNS core calls this routine to initialise the platform-specific data.
mDNSPlatformInit(mDNS * const m)12934b22b933Srs200217 mDNSexport mStatus mDNSPlatformInit(mDNS *const m)
12944b22b933Srs200217 {
12954b22b933Srs200217     int err = 0;
12964b22b933Srs200217     struct sockaddr sa;
12974b22b933Srs200217     assert(m != NULL);
12984b22b933Srs200217 
12994b22b933Srs200217     if (mDNSPlatformInit_CanReceiveUnicast()) m->CanReceiveUnicastOn5353 = mDNStrue;
13004b22b933Srs200217 
13014b22b933Srs200217     // Tell mDNS core the names of this machine.
13024b22b933Srs200217 
13034b22b933Srs200217     // Set up the nice label
13044b22b933Srs200217     m->nicelabel.c[0] = 0;
13054b22b933Srs200217     GetUserSpecifiedFriendlyComputerName(&m->nicelabel);
13064b22b933Srs200217     if (m->nicelabel.c[0] == 0) MakeDomainLabelFromLiteralString(&m->nicelabel, "Computer");
13074b22b933Srs200217 
13084b22b933Srs200217     // Set up the RFC 1034-compliant label
13094b22b933Srs200217     m->hostlabel.c[0] = 0;
13104b22b933Srs200217     GetUserSpecifiedRFC1034ComputerName(&m->hostlabel);
13114b22b933Srs200217     if (m->hostlabel.c[0] == 0) MakeDomainLabelFromLiteralString(&m->hostlabel, "Computer");
13124b22b933Srs200217 
13134b22b933Srs200217     mDNS_SetFQDN(m);
13144b22b933Srs200217 
13154b22b933Srs200217     sa.sa_family = AF_INET;
13164b22b933Srs200217     m->p->unicastSocket4 = -1;
13174b22b933Srs200217     if (err == mStatus_NoError) err = SetupSocket(&sa, zeroIPPort, 0, &m->p->unicastSocket4);
13184b22b933Srs200217 #if HAVE_IPV6
13194b22b933Srs200217     sa.sa_family = AF_INET6;
13204b22b933Srs200217     m->p->unicastSocket6 = -1;
13214b22b933Srs200217     if (err == mStatus_NoError) err = SetupSocket(&sa, zeroIPPort, 0, &m->p->unicastSocket6);
13224b22b933Srs200217 #endif
13234b22b933Srs200217 
13244b22b933Srs200217     // Tell mDNS core about the network interfaces on this machine.
13254b22b933Srs200217     if (err == mStatus_NoError) err = SetupInterfaceList(m);
13264b22b933Srs200217 
13274b22b933Srs200217     // Tell mDNS core about DNS Servers
1328*5ffb0c9bSToomas Soome     mDNS_Lock(m);
13294b22b933Srs200217     if (err == mStatus_NoError) ParseDNSServers(m, uDNS_SERVERS_FILE);
1330*5ffb0c9bSToomas Soome     mDNS_Unlock(m);
13314b22b933Srs200217 
13324b22b933Srs200217     if (err == mStatus_NoError)
13334b22b933Srs200217     {
13344b22b933Srs200217         err = WatchForInterfaceChange(m);
13354b22b933Srs200217         // Failure to observe interface changes is non-fatal.
13364b22b933Srs200217         if (err != mStatus_NoError)
13374b22b933Srs200217         {
1338*5ffb0c9bSToomas Soome             fprintf(stderr, "mDNS(%d) WARNING: Unable to detect interface changes (%d).\n", (int)getpid(), err);
13394b22b933Srs200217             err = mStatus_NoError;
13404b22b933Srs200217         }
13414b22b933Srs200217     }
13424b22b933Srs200217 
13434b22b933Srs200217     // We don't do asynchronous initialization on the Posix platform, so by the time
13444b22b933Srs200217     // we get here the setup will already have succeeded or failed.  If it succeeded,
13454b22b933Srs200217     // we should just call mDNSCoreInitComplete() immediately.
13464b22b933Srs200217     if (err == mStatus_NoError)
13474b22b933Srs200217         mDNSCoreInitComplete(m, mStatus_NoError);
13484b22b933Srs200217 
13494b22b933Srs200217     return PosixErrorToStatus(err);
13504b22b933Srs200217 }
13514b22b933Srs200217 
13524b22b933Srs200217 // mDNS core calls this routine to clean up the platform-specific data.
13534b22b933Srs200217 // In our case all we need to do is to tear down every network interface.
mDNSPlatformClose(mDNS * const m)13544b22b933Srs200217 mDNSexport void mDNSPlatformClose(mDNS *const m)
13554b22b933Srs200217 {
13564b22b933Srs200217     assert(m != NULL);
13574b22b933Srs200217     ClearInterfaceList(m);
13584b22b933Srs200217     if (m->p->unicastSocket4 != -1) assert(close(m->p->unicastSocket4) == 0);
13594b22b933Srs200217 #if HAVE_IPV6
13604b22b933Srs200217     if (m->p->unicastSocket6 != -1) assert(close(m->p->unicastSocket6) == 0);
13614b22b933Srs200217 #endif
13624b22b933Srs200217 }
13634b22b933Srs200217 
1364*5ffb0c9bSToomas Soome // This is used internally by InterfaceChangeCallback.
1365*5ffb0c9bSToomas Soome // It's also exported so that the Standalone Responder (mDNSResponderPosix)
1366*5ffb0c9bSToomas Soome // can call it in response to a SIGHUP (mainly for debugging purposes).
mDNSPlatformPosixRefreshInterfaceList(mDNS * const m)13674b22b933Srs200217 mDNSexport mStatus mDNSPlatformPosixRefreshInterfaceList(mDNS *const m)
13684b22b933Srs200217 {
13694b22b933Srs200217     int err;
1370*5ffb0c9bSToomas Soome     // This is a pretty heavyweight way to process interface changes --
1371*5ffb0c9bSToomas Soome     // destroying the entire interface list and then making fresh one from scratch.
1372*5ffb0c9bSToomas Soome     // We should make it like the OS X version, which leaves unchanged interfaces alone.
13734b22b933Srs200217     ClearInterfaceList(m);
13744b22b933Srs200217     err = SetupInterfaceList(m);
13754b22b933Srs200217     return PosixErrorToStatus(err);
13764b22b933Srs200217 }
13774b22b933Srs200217 
13784b22b933Srs200217 #if COMPILER_LIKES_PRAGMA_MARK
13794b22b933Srs200217 #pragma mark ***** Locking
13804b22b933Srs200217 #endif
13814b22b933Srs200217 
13824b22b933Srs200217 // On the Posix platform, locking is a no-op because we only ever enter
13834b22b933Srs200217 // mDNS core on the main thread.
13844b22b933Srs200217 
13854b22b933Srs200217 // mDNS core calls this routine when it wants to prevent
13864b22b933Srs200217 // the platform from reentering mDNS core code.
mDNSPlatformLock(const mDNS * const m)13874b22b933Srs200217 mDNSexport void    mDNSPlatformLock   (const mDNS *const m)
13884b22b933Srs200217 {
13894b22b933Srs200217     (void) m;   // Unused
13904b22b933Srs200217 }
13914b22b933Srs200217 
13924b22b933Srs200217 // mDNS core calls this routine when it release the lock taken by
13934b22b933Srs200217 // mDNSPlatformLock and allow the platform to reenter mDNS core code.
mDNSPlatformUnlock(const mDNS * const m)13944b22b933Srs200217 mDNSexport void    mDNSPlatformUnlock (const mDNS *const m)
13954b22b933Srs200217 {
13964b22b933Srs200217     (void) m;   // Unused
13974b22b933Srs200217 }
13984b22b933Srs200217 
13994b22b933Srs200217 #if COMPILER_LIKES_PRAGMA_MARK
14004b22b933Srs200217 #pragma mark ***** Strings
14014b22b933Srs200217 #endif
14024b22b933Srs200217 
14034b22b933Srs200217 // mDNS core calls this routine to copy C strings.
14044b22b933Srs200217 // On the Posix platform this maps directly to the ANSI C strcpy.
mDNSPlatformStrCopy(void * dst,const void * src)1405*5ffb0c9bSToomas Soome mDNSexport void    mDNSPlatformStrCopy(void *dst, const void *src)
14064b22b933Srs200217 {
14074b22b933Srs200217     strcpy((char *)dst, (char *)src);
14084b22b933Srs200217 }
14094b22b933Srs200217 
14104b22b933Srs200217 // mDNS core calls this routine to get the length of a C string.
14114b22b933Srs200217 // On the Posix platform this maps directly to the ANSI C strlen.
mDNSPlatformStrLen(const void * src)14124b22b933Srs200217 mDNSexport mDNSu32  mDNSPlatformStrLen (const void *src)
14134b22b933Srs200217 {
14144b22b933Srs200217     return strlen((char*)src);
14154b22b933Srs200217 }
14164b22b933Srs200217 
14174b22b933Srs200217 // mDNS core calls this routine to copy memory.
14184b22b933Srs200217 // On the Posix platform this maps directly to the ANSI C memcpy.
mDNSPlatformMemCopy(void * dst,const void * src,mDNSu32 len)1419*5ffb0c9bSToomas Soome mDNSexport void    mDNSPlatformMemCopy(void *dst, const void *src, mDNSu32 len)
14204b22b933Srs200217 {
14214b22b933Srs200217     memcpy(dst, src, len);
14224b22b933Srs200217 }
14234b22b933Srs200217 
14244b22b933Srs200217 // mDNS core calls this routine to test whether blocks of memory are byte-for-byte
14254b22b933Srs200217 // identical. On the Posix platform this is a simple wrapper around ANSI C memcmp.
mDNSPlatformMemSame(const void * dst,const void * src,mDNSu32 len)1426*5ffb0c9bSToomas Soome mDNSexport mDNSBool mDNSPlatformMemSame(const void *dst, const void *src, mDNSu32 len)
14274b22b933Srs200217 {
14284b22b933Srs200217     return memcmp(dst, src, len) == 0;
14294b22b933Srs200217 }
14304b22b933Srs200217 
1431*5ffb0c9bSToomas Soome // If the caller wants to know the exact return of memcmp, then use this instead
1432*5ffb0c9bSToomas Soome // of mDNSPlatformMemSame
mDNSPlatformMemCmp(const void * dst,const void * src,mDNSu32 len)1433*5ffb0c9bSToomas Soome mDNSexport int mDNSPlatformMemCmp(const void *dst, const void *src, mDNSu32 len)
1434*5ffb0c9bSToomas Soome {
1435*5ffb0c9bSToomas Soome     return (memcmp(dst, src, len));
1436*5ffb0c9bSToomas Soome }
1437*5ffb0c9bSToomas Soome 
mDNSPlatformQsort(void * base,int nel,int width,int (* compar)(const void *,const void *))1438*5ffb0c9bSToomas Soome mDNSexport void mDNSPlatformQsort(void *base, int nel, int width, int (*compar)(const void *, const void *))
1439*5ffb0c9bSToomas Soome {
1440*5ffb0c9bSToomas Soome     (void)qsort(base, nel, width, compar);
1441*5ffb0c9bSToomas Soome }
1442*5ffb0c9bSToomas Soome 
1443*5ffb0c9bSToomas Soome // DNSSEC stub functions
VerifySignature(mDNS * const m,DNSSECVerifier * dv,DNSQuestion * q)1444*5ffb0c9bSToomas Soome mDNSexport void VerifySignature(mDNS *const m, DNSSECVerifier *dv, DNSQuestion *q)
1445*5ffb0c9bSToomas Soome {
1446*5ffb0c9bSToomas Soome     (void)m;
1447*5ffb0c9bSToomas Soome     (void)dv;
1448*5ffb0c9bSToomas Soome     (void)q;
1449*5ffb0c9bSToomas Soome }
1450*5ffb0c9bSToomas Soome 
AddNSECSForCacheRecord(mDNS * const m,CacheRecord * crlist,CacheRecord * negcr,mDNSu8 rcode)1451*5ffb0c9bSToomas Soome mDNSexport mDNSBool AddNSECSForCacheRecord(mDNS *const m, CacheRecord *crlist, CacheRecord *negcr, mDNSu8 rcode)
1452*5ffb0c9bSToomas Soome {
1453*5ffb0c9bSToomas Soome     (void)m;
1454*5ffb0c9bSToomas Soome     (void)crlist;
1455*5ffb0c9bSToomas Soome     (void)negcr;
1456*5ffb0c9bSToomas Soome     (void)rcode;
1457*5ffb0c9bSToomas Soome     return mDNSfalse;
1458*5ffb0c9bSToomas Soome }
1459*5ffb0c9bSToomas Soome 
BumpDNSSECStats(mDNS * const m,DNSSECStatsAction action,DNSSECStatsType type,mDNSu32 value)1460*5ffb0c9bSToomas Soome mDNSexport void BumpDNSSECStats(mDNS *const m, DNSSECStatsAction action, DNSSECStatsType type, mDNSu32 value)
1461*5ffb0c9bSToomas Soome {
1462*5ffb0c9bSToomas Soome     (void)m;
1463*5ffb0c9bSToomas Soome     (void)action;
1464*5ffb0c9bSToomas Soome     (void)type;
1465*5ffb0c9bSToomas Soome     (void)value;
1466*5ffb0c9bSToomas Soome }
1467*5ffb0c9bSToomas Soome 
1468*5ffb0c9bSToomas Soome // Proxy stub functions
DNSProxySetAttributes(DNSQuestion * q,DNSMessageHeader * h,DNSMessage * msg,mDNSu8 * ptr,mDNSu8 * limit)1469*5ffb0c9bSToomas Soome mDNSexport mDNSu8 *DNSProxySetAttributes(DNSQuestion *q, DNSMessageHeader *h, DNSMessage *msg, mDNSu8 *ptr, mDNSu8 *limit)
1470*5ffb0c9bSToomas Soome {
1471*5ffb0c9bSToomas Soome     (void) q;
1472*5ffb0c9bSToomas Soome     (void) h;
1473*5ffb0c9bSToomas Soome     (void) msg;
1474*5ffb0c9bSToomas Soome     (void) ptr;
1475*5ffb0c9bSToomas Soome     (void) limit;
1476*5ffb0c9bSToomas Soome 
1477*5ffb0c9bSToomas Soome     return ptr;
1478*5ffb0c9bSToomas Soome }
1479*5ffb0c9bSToomas Soome 
DNSProxyInit(mDNS * const m,mDNSu32 IpIfArr[],mDNSu32 OpIf)1480*5ffb0c9bSToomas Soome mDNSexport void DNSProxyInit(mDNS *const m, mDNSu32 IpIfArr[], mDNSu32 OpIf)
1481*5ffb0c9bSToomas Soome {
1482*5ffb0c9bSToomas Soome     (void) m;
1483*5ffb0c9bSToomas Soome     (void) IpIfArr;
1484*5ffb0c9bSToomas Soome     (void) OpIf;
1485*5ffb0c9bSToomas Soome }
1486*5ffb0c9bSToomas Soome 
DNSProxyTerminate(mDNS * const m)1487*5ffb0c9bSToomas Soome mDNSexport void DNSProxyTerminate(mDNS *const m)
1488*5ffb0c9bSToomas Soome {
1489*5ffb0c9bSToomas Soome     (void) m;
1490*5ffb0c9bSToomas Soome }
1491*5ffb0c9bSToomas Soome 
14924b22b933Srs200217 // mDNS core calls this routine to clear blocks of memory.
14934b22b933Srs200217 // On the Posix platform this is a simple wrapper around ANSI C memset.
mDNSPlatformMemZero(void * dst,mDNSu32 len)14944b22b933Srs200217 mDNSexport void    mDNSPlatformMemZero(void *dst, mDNSu32 len)
14954b22b933Srs200217 {
14964b22b933Srs200217     memset(dst, 0, len);
14974b22b933Srs200217 }
14984b22b933Srs200217 
mDNSPlatformMemAllocate(mDNSu32 len)14994b22b933Srs200217 mDNSexport void *  mDNSPlatformMemAllocate(mDNSu32 len) { return(malloc(len)); }
mDNSPlatformMemFree(void * mem)15004b22b933Srs200217 mDNSexport void    mDNSPlatformMemFree    (void *mem)   { free(mem); }
15014b22b933Srs200217 
mDNSPlatformRandomSeed(void)15024b22b933Srs200217 mDNSexport mDNSu32 mDNSPlatformRandomSeed(void)
15034b22b933Srs200217 {
15044b22b933Srs200217     struct timeval tv;
15054b22b933Srs200217     gettimeofday(&tv, NULL);
15064b22b933Srs200217     return(tv.tv_usec);
15074b22b933Srs200217 }
15084b22b933Srs200217 
15094b22b933Srs200217 mDNSexport mDNSs32 mDNSPlatformOneSecond = 1024;
15104b22b933Srs200217 
mDNSPlatformTimeInit(void)15114b22b933Srs200217 mDNSexport mStatus mDNSPlatformTimeInit(void)
15124b22b933Srs200217 {
15134b22b933Srs200217     // No special setup is required on Posix -- we just use gettimeofday();
15144b22b933Srs200217     // This is not really safe, because gettimeofday can go backwards if the user manually changes the date or time
15154b22b933Srs200217     // We should find a better way to do this
15164b22b933Srs200217     return(mStatus_NoError);
15174b22b933Srs200217 }
15184b22b933Srs200217 
mDNSPlatformRawTime()15194b22b933Srs200217 mDNSexport mDNSs32  mDNSPlatformRawTime()
15204b22b933Srs200217 {
15214b22b933Srs200217     struct timeval tv;
15224b22b933Srs200217     gettimeofday(&tv, NULL);
15234b22b933Srs200217     // tv.tv_sec is seconds since 1st January 1970 (GMT, with no adjustment for daylight savings time)
15244b22b933Srs200217     // tv.tv_usec is microseconds since the start of this second (i.e. values 0 to 999999)
15254b22b933Srs200217     // We use the lower 22 bits of tv.tv_sec for the top 22 bits of our result
15264b22b933Srs200217     // 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.
15274b22b933Srs200217     // This gives us a proper modular (cyclic) counter that has a resolution of roughly 1ms (actually 1/1024 second)
15284b22b933Srs200217     // and correctly cycles every 2^22 seconds (4194304 seconds = approx 48 days).
15294b22b933Srs200217     return((tv.tv_sec << 10) | (tv.tv_usec * 16 / 15625));
15304b22b933Srs200217 }
15314b22b933Srs200217 
mDNSPlatformUTC(void)15324b22b933Srs200217 mDNSexport mDNSs32 mDNSPlatformUTC(void)
15334b22b933Srs200217 {
15344b22b933Srs200217     return time(NULL);
15354b22b933Srs200217 }
15364b22b933Srs200217 
mDNSPlatformSendWakeupPacket(mDNS * const m,mDNSInterfaceID InterfaceID,char * EthAddr,char * IPAddr,int iteration)1537*5ffb0c9bSToomas Soome mDNSexport void mDNSPlatformSendWakeupPacket(mDNS *const m, mDNSInterfaceID InterfaceID, char *EthAddr, char *IPAddr, int iteration)
1538*5ffb0c9bSToomas Soome {
1539*5ffb0c9bSToomas Soome     (void) m;
1540*5ffb0c9bSToomas Soome     (void) InterfaceID;
1541*5ffb0c9bSToomas Soome     (void) EthAddr;
1542*5ffb0c9bSToomas Soome     (void) IPAddr;
1543*5ffb0c9bSToomas Soome     (void) iteration;
1544*5ffb0c9bSToomas Soome }
1545*5ffb0c9bSToomas Soome 
mDNSPlatformValidRecordForInterface(AuthRecord * rr,const NetworkInterfaceInfo * intf)1546*5ffb0c9bSToomas Soome mDNSexport mDNSBool mDNSPlatformValidRecordForInterface(AuthRecord *rr, const NetworkInterfaceInfo *intf)
1547*5ffb0c9bSToomas Soome {
1548*5ffb0c9bSToomas Soome     (void) rr;
1549*5ffb0c9bSToomas Soome     (void) intf;
1550*5ffb0c9bSToomas Soome 
1551*5ffb0c9bSToomas Soome     return 1;
1552*5ffb0c9bSToomas Soome }
1553*5ffb0c9bSToomas Soome 
mDNSPlatformValidQuestionForInterface(DNSQuestion * q,const NetworkInterfaceInfo * intf)1554*5ffb0c9bSToomas Soome mDNSexport mDNSBool mDNSPlatformValidQuestionForInterface(DNSQuestion *q, const NetworkInterfaceInfo *intf)
1555*5ffb0c9bSToomas Soome {
1556*5ffb0c9bSToomas Soome     (void) q;
1557*5ffb0c9bSToomas Soome     (void) intf;
1558*5ffb0c9bSToomas Soome 
1559*5ffb0c9bSToomas Soome     return 1;
1560*5ffb0c9bSToomas Soome }
1561*5ffb0c9bSToomas Soome 
1562*5ffb0c9bSToomas Soome // Used for debugging purposes. For now, just set the buffer to zero
mDNSPlatformFormatTime(unsigned long te,mDNSu8 * buf,int bufsize)1563*5ffb0c9bSToomas Soome mDNSexport void mDNSPlatformFormatTime(unsigned long te, mDNSu8 *buf, int bufsize)
1564*5ffb0c9bSToomas Soome {
1565*5ffb0c9bSToomas Soome     (void) te;
1566*5ffb0c9bSToomas Soome     if (bufsize) buf[0] = 0;
1567*5ffb0c9bSToomas Soome }
1568*5ffb0c9bSToomas Soome 
mDNSPlatformSendKeepalive(mDNSAddr * sadd,mDNSAddr * dadd,mDNSIPPort * lport,mDNSIPPort * rport,mDNSu32 seq,mDNSu32 ack,mDNSu16 win)1569*5ffb0c9bSToomas Soome mDNSexport void mDNSPlatformSendKeepalive(mDNSAddr *sadd, mDNSAddr *dadd, mDNSIPPort *lport, mDNSIPPort *rport, mDNSu32 seq, mDNSu32 ack, mDNSu16 win)
1570*5ffb0c9bSToomas Soome {
1571*5ffb0c9bSToomas Soome     (void) sadd;    // Unused
1572*5ffb0c9bSToomas Soome     (void) dadd;    // Unused
1573*5ffb0c9bSToomas Soome     (void) lport;   // Unused
1574*5ffb0c9bSToomas Soome     (void) rport;   // Unused
1575*5ffb0c9bSToomas Soome     (void) seq;     // Unused
1576*5ffb0c9bSToomas Soome     (void) ack;     // Unused
1577*5ffb0c9bSToomas Soome     (void) win;     // Unused
1578*5ffb0c9bSToomas Soome }
1579*5ffb0c9bSToomas Soome 
mDNSPlatformRetrieveTCPInfo(mDNS * const m,mDNSAddr * laddr,mDNSIPPort * lport,mDNSAddr * raddr,mDNSIPPort * rport,mDNSTCPInfo * mti)1580*5ffb0c9bSToomas Soome mDNSexport mStatus mDNSPlatformRetrieveTCPInfo(mDNS *const m, mDNSAddr *laddr, mDNSIPPort *lport, mDNSAddr *raddr, mDNSIPPort *rport, mDNSTCPInfo *mti)
1581*5ffb0c9bSToomas Soome {
1582*5ffb0c9bSToomas Soome     (void) m;       // Unused
1583*5ffb0c9bSToomas Soome     (void) laddr;   // Unused
1584*5ffb0c9bSToomas Soome     (void) raddr;   // Unused
1585*5ffb0c9bSToomas Soome     (void) lport;   // Unused
1586*5ffb0c9bSToomas Soome     (void) rport;   // Unused
1587*5ffb0c9bSToomas Soome     (void) mti;     // Unused
1588*5ffb0c9bSToomas Soome 
1589*5ffb0c9bSToomas Soome     return mStatus_NoError;
1590*5ffb0c9bSToomas Soome }
1591*5ffb0c9bSToomas Soome 
mDNSPlatformGetRemoteMacAddr(mDNS * const m,mDNSAddr * raddr)1592*5ffb0c9bSToomas Soome mDNSexport mStatus mDNSPlatformGetRemoteMacAddr(mDNS *const m, mDNSAddr *raddr)
1593*5ffb0c9bSToomas Soome {
1594*5ffb0c9bSToomas Soome     (void) raddr; // Unused
1595*5ffb0c9bSToomas Soome     (void) m;     // Unused
1596*5ffb0c9bSToomas Soome 
1597*5ffb0c9bSToomas Soome     return mStatus_NoError;
1598*5ffb0c9bSToomas Soome }
1599*5ffb0c9bSToomas Soome 
mDNSPlatformStoreSPSMACAddr(mDNSAddr * spsaddr,char * ifname)1600*5ffb0c9bSToomas Soome mDNSexport mStatus    mDNSPlatformStoreSPSMACAddr(mDNSAddr *spsaddr, char *ifname)
1601*5ffb0c9bSToomas Soome {
1602*5ffb0c9bSToomas Soome     (void) spsaddr; // Unused
1603*5ffb0c9bSToomas Soome     (void) ifname;  // Unused
1604*5ffb0c9bSToomas Soome 
1605*5ffb0c9bSToomas Soome     return mStatus_NoError;
1606*5ffb0c9bSToomas Soome }
1607*5ffb0c9bSToomas Soome 
mDNSPlatformClearSPSMACAddr(void)1608*5ffb0c9bSToomas Soome mDNSexport mStatus    mDNSPlatformClearSPSMACAddr(void)
1609*5ffb0c9bSToomas Soome {
1610*5ffb0c9bSToomas Soome     return mStatus_NoError;
1611*5ffb0c9bSToomas Soome }
1612*5ffb0c9bSToomas Soome 
mDNSPlatformGetUDPPort(UDPSocket * sock)1613*5ffb0c9bSToomas Soome mDNSexport mDNSu16 mDNSPlatformGetUDPPort(UDPSocket *sock)
1614*5ffb0c9bSToomas Soome {
1615*5ffb0c9bSToomas Soome     (void) sock; // unused
1616*5ffb0c9bSToomas Soome 
1617*5ffb0c9bSToomas Soome     return (mDNSu16)-1;
1618*5ffb0c9bSToomas Soome }
1619*5ffb0c9bSToomas Soome 
mDNSPlatformInterfaceIsD2D(mDNSInterfaceID InterfaceID)1620*5ffb0c9bSToomas Soome mDNSexport mDNSBool mDNSPlatformInterfaceIsD2D(mDNSInterfaceID InterfaceID)
1621*5ffb0c9bSToomas Soome {
1622*5ffb0c9bSToomas Soome     (void) InterfaceID; // unused
1623*5ffb0c9bSToomas Soome 
1624*5ffb0c9bSToomas Soome     return mDNSfalse;
1625*5ffb0c9bSToomas Soome }
1626*5ffb0c9bSToomas Soome 
mDNSPlatformAllowPID(mDNS * const m,DNSQuestion * q)1627*5ffb0c9bSToomas Soome mDNSexport mDNSBool mDNSPlatformAllowPID(mDNS *const m, DNSQuestion *q)
1628*5ffb0c9bSToomas Soome {
1629*5ffb0c9bSToomas Soome     (void) m;
1630*5ffb0c9bSToomas Soome     (void) q;
1631*5ffb0c9bSToomas Soome     return mDNStrue;
1632*5ffb0c9bSToomas Soome }
1633*5ffb0c9bSToomas Soome 
mDNSPlatformGetServiceID(mDNS * const m,DNSQuestion * q)1634*5ffb0c9bSToomas Soome mDNSexport mDNSs32 mDNSPlatformGetServiceID(mDNS *const m, DNSQuestion *q)
1635*5ffb0c9bSToomas Soome {
1636*5ffb0c9bSToomas Soome     (void) m;
1637*5ffb0c9bSToomas Soome     (void) q;
1638*5ffb0c9bSToomas Soome     return -1;
1639*5ffb0c9bSToomas Soome }
1640*5ffb0c9bSToomas Soome 
mDNSPlatformSetDelegatePID(UDPSocket * src,const mDNSAddr * dst,DNSQuestion * q)1641*5ffb0c9bSToomas Soome mDNSexport void mDNSPlatformSetDelegatePID(UDPSocket *src, const mDNSAddr *dst, DNSQuestion *q)
1642*5ffb0c9bSToomas Soome {
1643*5ffb0c9bSToomas Soome     (void) src;
1644*5ffb0c9bSToomas Soome     (void) dst;
1645*5ffb0c9bSToomas Soome     (void) q;
1646*5ffb0c9bSToomas Soome }
1647*5ffb0c9bSToomas Soome 
mDNSPlatformGetPID()1648*5ffb0c9bSToomas Soome mDNSexport mDNSs32 mDNSPlatformGetPID()
1649*5ffb0c9bSToomas Soome {
1650*5ffb0c9bSToomas Soome     return 0;
1651*5ffb0c9bSToomas Soome }
1652*5ffb0c9bSToomas Soome 
mDNSPosixAddToFDSet(int * nfds,fd_set * readfds,int s)16534b22b933Srs200217 mDNSlocal void mDNSPosixAddToFDSet(int *nfds, fd_set *readfds, int s)
16544b22b933Srs200217 {
16554b22b933Srs200217     if (*nfds < s + 1) *nfds = s + 1;
16564b22b933Srs200217     FD_SET(s, readfds);
16574b22b933Srs200217 }
16584b22b933Srs200217 
mDNSPosixGetFDSet(mDNS * m,int * nfds,fd_set * readfds,struct timeval * timeout)16594b22b933Srs200217 mDNSexport void mDNSPosixGetFDSet(mDNS *m, int *nfds, fd_set *readfds, struct timeval *timeout)
16604b22b933Srs200217 {
16614b22b933Srs200217     mDNSs32 ticks;
16624b22b933Srs200217     struct timeval interval;
16634b22b933Srs200217 
16644b22b933Srs200217     // 1. Call mDNS_Execute() to let mDNSCore do what it needs to do
16654b22b933Srs200217     mDNSs32 nextevent = mDNS_Execute(m);
16664b22b933Srs200217 
16674b22b933Srs200217     // 2. Build our list of active file descriptors
16684b22b933Srs200217     PosixNetworkInterface *info = (PosixNetworkInterface *)(m->HostInterfaces);
16694b22b933Srs200217     if (m->p->unicastSocket4 != -1) mDNSPosixAddToFDSet(nfds, readfds, m->p->unicastSocket4);
16704b22b933Srs200217 #if HAVE_IPV6
16714b22b933Srs200217     if (m->p->unicastSocket6 != -1) mDNSPosixAddToFDSet(nfds, readfds, m->p->unicastSocket6);
16724b22b933Srs200217 #endif
16734b22b933Srs200217     while (info)
16744b22b933Srs200217     {
16754b22b933Srs200217         if (info->multicastSocket4 != -1) mDNSPosixAddToFDSet(nfds, readfds, info->multicastSocket4);
16764b22b933Srs200217 #if HAVE_IPV6
16774b22b933Srs200217         if (info->multicastSocket6 != -1) mDNSPosixAddToFDSet(nfds, readfds, info->multicastSocket6);
16784b22b933Srs200217 #endif
16794b22b933Srs200217         info = (PosixNetworkInterface *)(info->coreIntf.next);
16804b22b933Srs200217     }
16814b22b933Srs200217 
16824b22b933Srs200217     // 3. Calculate the time remaining to the next scheduled event (in struct timeval format)
16834b22b933Srs200217     ticks = nextevent - mDNS_TimeNow(m);
16844b22b933Srs200217     if (ticks < 1) ticks = 1;
16854b22b933Srs200217     interval.tv_sec  = ticks >> 10;                     // The high 22 bits are seconds
16864b22b933Srs200217     interval.tv_usec = ((ticks & 0x3FF) * 15625) / 16;  // The low 10 bits are 1024ths
16874b22b933Srs200217 
16884b22b933Srs200217     // 4. If client's proposed timeout is more than what we want, then reduce it
16894b22b933Srs200217     if (timeout->tv_sec > interval.tv_sec ||
16904b22b933Srs200217         (timeout->tv_sec == interval.tv_sec && timeout->tv_usec > interval.tv_usec))
16914b22b933Srs200217         *timeout = interval;
16924b22b933Srs200217 }
16934b22b933Srs200217 
mDNSPosixProcessFDSet(mDNS * const m,fd_set * readfds)16944b22b933Srs200217 mDNSexport void mDNSPosixProcessFDSet(mDNS *const m, fd_set *readfds)
16954b22b933Srs200217 {
16964b22b933Srs200217     PosixNetworkInterface *info;
16974b22b933Srs200217     assert(m       != NULL);
16984b22b933Srs200217     assert(readfds != NULL);
16994b22b933Srs200217     info = (PosixNetworkInterface *)(m->HostInterfaces);
17004b22b933Srs200217 
17014b22b933Srs200217     if (m->p->unicastSocket4 != -1 && FD_ISSET(m->p->unicastSocket4, readfds))
17024b22b933Srs200217     {
17034b22b933Srs200217         FD_CLR(m->p->unicastSocket4, readfds);
17044b22b933Srs200217         SocketDataReady(m, NULL, m->p->unicastSocket4);
17054b22b933Srs200217     }
17064b22b933Srs200217 #if HAVE_IPV6
17074b22b933Srs200217     if (m->p->unicastSocket6 != -1 && FD_ISSET(m->p->unicastSocket6, readfds))
17084b22b933Srs200217     {
17094b22b933Srs200217         FD_CLR(m->p->unicastSocket6, readfds);
17104b22b933Srs200217         SocketDataReady(m, NULL, m->p->unicastSocket6);
17114b22b933Srs200217     }
17124b22b933Srs200217 #endif
17134b22b933Srs200217 
17144b22b933Srs200217     while (info)
17154b22b933Srs200217     {
17164b22b933Srs200217         if (info->multicastSocket4 != -1 && FD_ISSET(info->multicastSocket4, readfds))
17174b22b933Srs200217         {
17184b22b933Srs200217             FD_CLR(info->multicastSocket4, readfds);
17194b22b933Srs200217             SocketDataReady(m, info, info->multicastSocket4);
17204b22b933Srs200217         }
17214b22b933Srs200217 #if HAVE_IPV6
17224b22b933Srs200217         if (info->multicastSocket6 != -1 && FD_ISSET(info->multicastSocket6, readfds))
17234b22b933Srs200217         {
17244b22b933Srs200217             FD_CLR(info->multicastSocket6, readfds);
17254b22b933Srs200217             SocketDataReady(m, info, info->multicastSocket6);
17264b22b933Srs200217         }
17274b22b933Srs200217 #endif
17284b22b933Srs200217         info = (PosixNetworkInterface *)(info->coreIntf.next);
17294b22b933Srs200217     }
17304b22b933Srs200217 }
17314b22b933Srs200217 
17324b22b933Srs200217 // update gMaxFD
DetermineMaxEventFD(void)17334b22b933Srs200217 mDNSlocal void  DetermineMaxEventFD(void)
17344b22b933Srs200217 {
17354b22b933Srs200217     PosixEventSource    *iSource;
17364b22b933Srs200217 
17374b22b933Srs200217     gMaxFD = 0;
17384b22b933Srs200217     for (iSource=(PosixEventSource*)gEventSources.Head; iSource; iSource = iSource->Next)
17394b22b933Srs200217         if (gMaxFD < iSource->fd)
17404b22b933Srs200217             gMaxFD = iSource->fd;
17414b22b933Srs200217 }
17424b22b933Srs200217 
17434b22b933Srs200217 // Add a file descriptor to the set that mDNSPosixRunEventLoopOnce() listens to.
mDNSPosixAddFDToEventLoop(int fd,mDNSPosixEventCallback callback,void * context)17444b22b933Srs200217 mStatus mDNSPosixAddFDToEventLoop(int fd, mDNSPosixEventCallback callback, void *context)
17454b22b933Srs200217 {
17464b22b933Srs200217     PosixEventSource    *newSource;
17474b22b933Srs200217 
17484b22b933Srs200217     if (gEventSources.LinkOffset == 0)
17494b22b933Srs200217         InitLinkedList(&gEventSources, offsetof(PosixEventSource, Next));
17504b22b933Srs200217 
17514b22b933Srs200217     if (fd >= (int) FD_SETSIZE || fd < 0)
17524b22b933Srs200217         return mStatus_UnsupportedErr;
17534b22b933Srs200217     if (callback == NULL)
17544b22b933Srs200217         return mStatus_BadParamErr;
17554b22b933Srs200217 
17564b22b933Srs200217     newSource = (PosixEventSource*) malloc(sizeof *newSource);
17574b22b933Srs200217     if (NULL == newSource)
17584b22b933Srs200217         return mStatus_NoMemoryErr;
17594b22b933Srs200217 
17604b22b933Srs200217     newSource->Callback = callback;
17614b22b933Srs200217     newSource->Context = context;
17624b22b933Srs200217     newSource->fd = fd;
17634b22b933Srs200217 
17644b22b933Srs200217     AddToTail(&gEventSources, newSource);
17654b22b933Srs200217     FD_SET(fd, &gEventFDs);
17664b22b933Srs200217 
17674b22b933Srs200217     DetermineMaxEventFD();
17684b22b933Srs200217 
17694b22b933Srs200217     return mStatus_NoError;
17704b22b933Srs200217 }
17714b22b933Srs200217 
17724b22b933Srs200217 // Remove a file descriptor from the set that mDNSPosixRunEventLoopOnce() listens to.
mDNSPosixRemoveFDFromEventLoop(int fd)17734b22b933Srs200217 mStatus mDNSPosixRemoveFDFromEventLoop(int fd)
17744b22b933Srs200217 {
17754b22b933Srs200217     PosixEventSource    *iSource;
17764b22b933Srs200217 
17774b22b933Srs200217     for (iSource=(PosixEventSource*)gEventSources.Head; iSource; iSource = iSource->Next)
17784b22b933Srs200217     {
17794b22b933Srs200217         if (fd == iSource->fd)
17804b22b933Srs200217         {
17814b22b933Srs200217             FD_CLR(fd, &gEventFDs);
17824b22b933Srs200217             RemoveFromList(&gEventSources, iSource);
17834b22b933Srs200217             free(iSource);
17844b22b933Srs200217             DetermineMaxEventFD();
17854b22b933Srs200217             return mStatus_NoError;
17864b22b933Srs200217         }
17874b22b933Srs200217     }
17884b22b933Srs200217     return mStatus_NoSuchNameErr;
17894b22b933Srs200217 }
17904b22b933Srs200217 
17914b22b933Srs200217 // Simply note the received signal in gEventSignals.
NoteSignal(int signum)17924b22b933Srs200217 mDNSlocal void  NoteSignal(int signum)
17934b22b933Srs200217 {
17944b22b933Srs200217     sigaddset(&gEventSignals, signum);
17954b22b933Srs200217 }
17964b22b933Srs200217 
17974b22b933Srs200217 // Tell the event package to listen for signal and report it in mDNSPosixRunEventLoopOnce().
mDNSPosixListenForSignalInEventLoop(int signum)17984b22b933Srs200217 mStatus mDNSPosixListenForSignalInEventLoop(int signum)
17994b22b933Srs200217 {
18004b22b933Srs200217     struct sigaction action;
18014b22b933Srs200217     mStatus err;
18024b22b933Srs200217 
1803*5ffb0c9bSToomas Soome     mDNSPlatformMemZero(&action, sizeof action);        // more portable than member-wise assignment
18044b22b933Srs200217     action.sa_handler = NoteSignal;
18054b22b933Srs200217     err = sigaction(signum, &action, (struct sigaction*) NULL);
18064b22b933Srs200217 
18074b22b933Srs200217     sigaddset(&gEventSignalSet, signum);
18084b22b933Srs200217 
18094b22b933Srs200217     return err;
18104b22b933Srs200217 }
18114b22b933Srs200217 
18124b22b933Srs200217 // Tell the event package to stop listening for signal in mDNSPosixRunEventLoopOnce().
mDNSPosixIgnoreSignalInEventLoop(int signum)18134b22b933Srs200217 mStatus mDNSPosixIgnoreSignalInEventLoop(int signum)
18144b22b933Srs200217 {
18154b22b933Srs200217     struct sigaction action;
18164b22b933Srs200217     mStatus err;
18174b22b933Srs200217 
1818*5ffb0c9bSToomas Soome     mDNSPlatformMemZero(&action, sizeof action);        // more portable than member-wise assignment
18194b22b933Srs200217     action.sa_handler = SIG_DFL;
18204b22b933Srs200217     err = sigaction(signum, &action, (struct sigaction*) NULL);
18214b22b933Srs200217 
18224b22b933Srs200217     sigdelset(&gEventSignalSet, signum);
18234b22b933Srs200217 
18244b22b933Srs200217     return err;
18254b22b933Srs200217 }
18264b22b933Srs200217 
18274b22b933Srs200217 // Do a single pass through the attendent event sources and dispatch any found to their callbacks.
18284b22b933Srs200217 // Return as soon as internal timeout expires, or a signal we're listening for is received.
mDNSPosixRunEventLoopOnce(mDNS * m,const struct timeval * pTimeout,sigset_t * pSignalsReceived,mDNSBool * pDataDispatched)18294b22b933Srs200217 mStatus mDNSPosixRunEventLoopOnce(mDNS *m, const struct timeval *pTimeout,
18304b22b933Srs200217                                   sigset_t *pSignalsReceived, mDNSBool *pDataDispatched)
18314b22b933Srs200217 {
18324b22b933Srs200217     fd_set listenFDs = gEventFDs;
18334b22b933Srs200217     int fdMax = 0, numReady;
18344b22b933Srs200217     struct timeval timeout = *pTimeout;
18354b22b933Srs200217 
18364b22b933Srs200217     // Include the sockets that are listening to the wire in our select() set
18374b22b933Srs200217     mDNSPosixGetFDSet(m, &fdMax, &listenFDs, &timeout); // timeout may get modified
18384b22b933Srs200217     if (fdMax < gMaxFD)
18394b22b933Srs200217         fdMax = gMaxFD;
18404b22b933Srs200217 
18414b22b933Srs200217     numReady = select(fdMax + 1, &listenFDs, (fd_set*) NULL, (fd_set*) NULL, &timeout);
18424b22b933Srs200217 
18434b22b933Srs200217     // If any data appeared, invoke its callback
18444b22b933Srs200217     if (numReady > 0)
18454b22b933Srs200217     {
18464b22b933Srs200217         PosixEventSource    *iSource;
18474b22b933Srs200217 
18484b22b933Srs200217         (void) mDNSPosixProcessFDSet(m, &listenFDs);    // call this first to process wire data for clients
18494b22b933Srs200217 
18504b22b933Srs200217         for (iSource=(PosixEventSource*)gEventSources.Head; iSource; iSource = iSource->Next)
18514b22b933Srs200217         {
18524b22b933Srs200217             if (FD_ISSET(iSource->fd, &listenFDs))
18534b22b933Srs200217             {
1854*5ffb0c9bSToomas Soome                 iSource->Callback(iSource->fd, 0, iSource->Context);
18554b22b933Srs200217                 break;  // in case callback removed elements from gEventSources
18564b22b933Srs200217             }
18574b22b933Srs200217         }
18584b22b933Srs200217         *pDataDispatched = mDNStrue;
18594b22b933Srs200217     }
18604b22b933Srs200217     else
18614b22b933Srs200217         *pDataDispatched = mDNSfalse;
18624b22b933Srs200217 
18634b22b933Srs200217     (void) sigprocmask(SIG_BLOCK, &gEventSignalSet, (sigset_t*) NULL);
18644b22b933Srs200217     *pSignalsReceived = gEventSignals;
18654b22b933Srs200217     sigemptyset(&gEventSignals);
18664b22b933Srs200217     (void) sigprocmask(SIG_UNBLOCK, &gEventSignalSet, (sigset_t*) NULL);
18674b22b933Srs200217 
18684b22b933Srs200217     return mStatus_NoError;
18694b22b933Srs200217 }
1870