1472cd20dSToomas Soome /* -*- Mode: C; tab-width: 4; c-file-style: "bsd"; c-basic-offset: 4; fill-column: 108; indent-tabs-mode: nil; -*-
24b22b933Srs  *
3472cd20dSToomas Soome  * Copyright (c) 2002-2019 Apple Inc. All rights reserved.
44b22b933Srs  *
54b22b933Srs  * Licensed under the Apache License, Version 2.0 (the "License");
64b22b933Srs  * you may not use this file except in compliance with the License.
74b22b933Srs  * You may obtain a copy of the License at
85ffb0c9bSToomas Soome  *
94b22b933Srs  *     http://www.apache.org/licenses/LICENSE-2.0
105ffb0c9bSToomas Soome  *
114b22b933Srs  * Unless required by applicable law or agreed to in writing, software
124b22b933Srs  * distributed under the License is distributed on an "AS IS" BASIS,
134b22b933Srs  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
144b22b933Srs  * See the License for the specific language governing permissions and
154b22b933Srs  * limitations under the License.
164b22b933Srs  *
175ffb0c9bSToomas Soome  */
184b22b933Srs 
194b22b933Srs #include "mDNSEmbeddedAPI.h"           // Defines the interface provided to the client layer above
205ffb0c9bSToomas Soome #include "DNSCommon.h"
215ffb0c9bSToomas Soome #include "mDNSPosix.h"               // Defines the specific types needed to run mDNS on this platform
22472cd20dSToomas Soome #include "PlatformCommon.h"
234b22b933Srs #include "dns_sd.h"
244b22b933Srs 
254b22b933Srs #include <assert.h>
264b22b933Srs #include <stdio.h>
274b22b933Srs #include <stdlib.h>
284b22b933Srs #include <errno.h>
294b22b933Srs #include <string.h>
304b22b933Srs #include <unistd.h>
314b22b933Srs #include <syslog.h>
324b22b933Srs #include <stdarg.h>
334b22b933Srs #include <fcntl.h>
344b22b933Srs #include <sys/types.h>
354b22b933Srs #include <sys/time.h>
364b22b933Srs #include <sys/socket.h>
374b22b933Srs #include <sys/uio.h>
384b22b933Srs #include <sys/select.h>
394b22b933Srs #include <netinet/in.h>
404b22b933Srs #include <arpa/inet.h>
414b22b933Srs #include <time.h>                   // platform support for UTC time
42472cd20dSToomas Soome #include <ifaddrs.h>
434b22b933Srs 
444b22b933Srs #if USES_NETLINK
454b22b933Srs #include <asm/types.h>
464b22b933Srs #include <linux/netlink.h>
474b22b933Srs #include <linux/rtnetlink.h>
484b22b933Srs #else // USES_NETLINK
494b22b933Srs #include <net/route.h>
504b22b933Srs #include <net/if.h>
514b22b933Srs #endif // USES_NETLINK
524b22b933Srs 
534b22b933Srs #include "mDNSUNP.h"
544b22b933Srs #include "GenLinkedList.h"
55c65ebfc7SToomas Soome #include "dnsproxy.h"
564b22b933Srs 
574b22b933Srs // ***************************************************************************
584b22b933Srs // Structures
594b22b933Srs 
604b22b933Srs // Context record for interface change callback
614b22b933Srs struct IfChangeRec
625ffb0c9bSToomas Soome {
635ffb0c9bSToomas Soome     int NotifySD;
645ffb0c9bSToomas Soome     mDNS *mDNS;
655ffb0c9bSToomas Soome };
665ffb0c9bSToomas Soome typedef struct IfChangeRec IfChangeRec;
674b22b933Srs 
684b22b933Srs // Note that static data is initialized to zero in (modern) C.
69472cd20dSToomas Soome static PosixEventSource *gEventSources;             // linked list of PosixEventSource's
705ffb0c9bSToomas Soome static sigset_t gEventSignalSet;                // Signals which event loop listens for
715ffb0c9bSToomas Soome static sigset_t gEventSignals;                  // Signals which were received while inside loop
725ffb0c9bSToomas Soome 
735ffb0c9bSToomas Soome static PosixNetworkInterface *gRecentInterfaces;
744b22b933Srs 
754b22b933Srs // ***************************************************************************
764b22b933Srs // Globals (for debugging)
774b22b933Srs 
784b22b933Srs static int num_registered_interfaces = 0;
794b22b933Srs static int num_pkts_accepted = 0;
804b22b933Srs static int num_pkts_rejected = 0;
814b22b933Srs 
82472cd20dSToomas Soome // ***************************************************************************
83472cd20dSToomas Soome // Locals
84472cd20dSToomas Soome mDNSlocal void requestReadEvents(PosixEventSource *eventSource,
85472cd20dSToomas Soome                                     const char *taskName, mDNSPosixEventCallback callback, void *context);
86472cd20dSToomas Soome mDNSlocal mStatus stopReadOrWriteEvents(int fd, mDNSBool freeSource, mDNSBool removeSource, int flags);
87472cd20dSToomas Soome mDNSlocal void requestWriteEvents(PosixEventSource *eventSource,
88472cd20dSToomas Soome                                      const char *taskName, mDNSPosixEventCallback callback, void *context);
894b22b933Srs // ***************************************************************************
904b22b933Srs // Functions
914b22b933Srs 
92472cd20dSToomas Soome #if MDNS_MALLOC_DEBUGGING
mDNSPlatformValidateLists(void)93472cd20dSToomas Soome mDNSexport void mDNSPlatformValidateLists(void)
94472cd20dSToomas Soome {
95472cd20dSToomas Soome     // This should validate gEventSources and any other Posix-specific stuff that gets allocated.
96472cd20dSToomas Soome }
97472cd20dSToomas Soome #endif
98472cd20dSToomas Soome 
994b22b933Srs int gMDNSPlatformPosixVerboseLevel = 0;
1004b22b933Srs 
1014b22b933Srs #define PosixErrorToStatus(errNum) ((errNum) == 0 ? mStatus_NoError : mStatus_UnknownErr)
1024b22b933Srs 
SockAddrTomDNSAddr(const struct sockaddr * const sa,mDNSAddr * ipAddr,mDNSIPPort * ipPort)1034b22b933Srs mDNSlocal void SockAddrTomDNSAddr(const struct sockaddr *const sa, mDNSAddr *ipAddr, mDNSIPPort *ipPort)
1045ffb0c9bSToomas Soome {
1055ffb0c9bSToomas Soome     switch (sa->sa_family)
1065ffb0c9bSToomas Soome     {
1075ffb0c9bSToomas Soome     case AF_INET:
1085ffb0c9bSToomas Soome     {
1095ffb0c9bSToomas Soome         struct sockaddr_in *sin          = (struct sockaddr_in*)sa;
1105ffb0c9bSToomas Soome         ipAddr->type                     = mDNSAddrType_IPv4;
1115ffb0c9bSToomas Soome         ipAddr->ip.v4.NotAnInteger       = sin->sin_addr.s_addr;
1125ffb0c9bSToomas Soome         if (ipPort) ipPort->NotAnInteger = sin->sin_port;
1135ffb0c9bSToomas Soome         break;
1145ffb0c9bSToomas Soome     }
1154b22b933Srs 
1164b22b933Srs #if HAVE_IPV6
1175ffb0c9bSToomas Soome     case AF_INET6:
1185ffb0c9bSToomas Soome     {
1195ffb0c9bSToomas Soome         struct sockaddr_in6 *sin6        = (struct sockaddr_in6*)sa;
1204b22b933Srs #ifndef NOT_HAVE_SA_LEN
1215ffb0c9bSToomas Soome         assert(sin6->sin6_len == sizeof(*sin6));
1224b22b933Srs #endif
1235ffb0c9bSToomas Soome         ipAddr->type                     = mDNSAddrType_IPv6;
1245ffb0c9bSToomas Soome         ipAddr->ip.v6                    = *(mDNSv6Addr*)&sin6->sin6_addr;
1255ffb0c9bSToomas Soome         if (ipPort) ipPort->NotAnInteger = sin6->sin6_port;
1265ffb0c9bSToomas Soome         break;
1275ffb0c9bSToomas Soome     }
1284b22b933Srs #endif
1294b22b933Srs 
1305ffb0c9bSToomas Soome     default:
1315ffb0c9bSToomas Soome         verbosedebugf("SockAddrTomDNSAddr: Uknown address family %d\n", sa->sa_family);
1325ffb0c9bSToomas Soome         ipAddr->type = mDNSAddrType_None;
1335ffb0c9bSToomas Soome         if (ipPort) ipPort->NotAnInteger = 0;
1345ffb0c9bSToomas Soome         break;
1355ffb0c9bSToomas Soome     }
1365ffb0c9bSToomas Soome }
1375ffb0c9bSToomas Soome 
1384b22b933Srs #if COMPILER_LIKES_PRAGMA_MARK
1394b22b933Srs #pragma mark ***** Send and Receive
1404b22b933Srs #endif
1414b22b933Srs 
1424b22b933Srs // 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)1434b22b933Srs mDNSexport mStatus mDNSPlatformSendUDP(const mDNS *const m, const void *const msg, const mDNSu8 *const end,
144c65ebfc7SToomas Soome                                        mDNSInterfaceID InterfaceID, UDPSocket *src, const mDNSAddr *dst,
1455ffb0c9bSToomas Soome                                        mDNSIPPort dstPort, mDNSBool useBackgroundTrafficClass)
1465ffb0c9bSToomas Soome {
1475ffb0c9bSToomas Soome     int err = 0;
1485ffb0c9bSToomas Soome     struct sockaddr_storage to;
1495ffb0c9bSToomas Soome     PosixNetworkInterface * thisIntf = (PosixNetworkInterface *)(InterfaceID);
1505ffb0c9bSToomas Soome     int sendingsocket = -1;
1515ffb0c9bSToomas Soome 
1525ffb0c9bSToomas Soome     (void)src;  // Will need to use this parameter once we implement mDNSPlatformUDPSocket/mDNSPlatformUDPClose
1535ffb0c9bSToomas Soome     (void) useBackgroundTrafficClass;
1545ffb0c9bSToomas Soome 
1555ffb0c9bSToomas Soome     assert(m != NULL);
1565ffb0c9bSToomas Soome     assert(msg != NULL);
1575ffb0c9bSToomas Soome     assert(end != NULL);
1585ffb0c9bSToomas Soome     assert((((char *) end) - ((char *) msg)) > 0);
1595ffb0c9bSToomas Soome 
1605ffb0c9bSToomas Soome     if (dstPort.NotAnInteger == 0)
1615ffb0c9bSToomas Soome     {
1625ffb0c9bSToomas Soome         LogMsg("mDNSPlatformSendUDP: Invalid argument -dstPort is set to 0");
1635ffb0c9bSToomas Soome         return PosixErrorToStatus(EINVAL);
1645ffb0c9bSToomas Soome     }
1655ffb0c9bSToomas Soome     if (dst->type == mDNSAddrType_IPv4)
1665ffb0c9bSToomas Soome     {
1675ffb0c9bSToomas Soome         struct sockaddr_in *sin = (struct sockaddr_in*)&to;
1684b22b933Srs #ifndef NOT_HAVE_SA_LEN
1695ffb0c9bSToomas Soome         sin->sin_len            = sizeof(*sin);
1704b22b933Srs #endif
1715ffb0c9bSToomas Soome         sin->sin_family         = AF_INET;
1725ffb0c9bSToomas Soome         sin->sin_port           = dstPort.NotAnInteger;
1735ffb0c9bSToomas Soome         sin->sin_addr.s_addr    = dst->ip.v4.NotAnInteger;
1745ffb0c9bSToomas Soome         sendingsocket           = thisIntf ? thisIntf->multicastSocket4 : m->p->unicastSocket4;
1755ffb0c9bSToomas Soome     }
1764b22b933Srs 
1774b22b933Srs #if HAVE_IPV6
1785ffb0c9bSToomas Soome     else if (dst->type == mDNSAddrType_IPv6)
1795ffb0c9bSToomas Soome     {
1805ffb0c9bSToomas Soome         struct sockaddr_in6 *sin6 = (struct sockaddr_in6*)&to;
1815ffb0c9bSToomas Soome         mDNSPlatformMemZero(sin6, sizeof(*sin6));
1824b22b933Srs #ifndef NOT_HAVE_SA_LEN
1835ffb0c9bSToomas Soome         sin6->sin6_len            = sizeof(*sin6);
1844b22b933Srs #endif
1855ffb0c9bSToomas Soome         sin6->sin6_family         = AF_INET6;
1865ffb0c9bSToomas Soome         sin6->sin6_port           = dstPort.NotAnInteger;
1875ffb0c9bSToomas Soome         sin6->sin6_addr           = *(struct in6_addr*)&dst->ip.v6;
1885ffb0c9bSToomas Soome         sendingsocket             = thisIntf ? thisIntf->multicastSocket6 : m->p->unicastSocket6;
1895ffb0c9bSToomas Soome     }
1904b22b933Srs #endif
1914b22b933Srs 
1925ffb0c9bSToomas Soome     if (sendingsocket >= 0)
1935ffb0c9bSToomas Soome         err = sendto(sendingsocket, msg, (char*)end - (char*)msg, 0, (struct sockaddr *)&to, GET_SA_LEN(to));
1944b22b933Srs 
1955ffb0c9bSToomas Soome     if      (err > 0) err = 0;
1965ffb0c9bSToomas Soome     else if (err < 0)
1975ffb0c9bSToomas Soome     {
1985ffb0c9bSToomas Soome         static int MessageCount = 0;
1994b22b933Srs         // Don't report EHOSTDOWN (i.e. ARP failure), ENETDOWN, or no route to host for unicast destinations
2005ffb0c9bSToomas Soome         if (!mDNSAddressIsAllDNSLinkGroup(dst))
2015ffb0c9bSToomas Soome             if (errno == EHOSTDOWN || errno == ENETDOWN || errno == EHOSTUNREACH || errno == ENETUNREACH) return(mStatus_TransientErr);
2025ffb0c9bSToomas Soome 
2035ffb0c9bSToomas Soome 	/* dont report ENETUNREACH */
204cda73f64SToomas Soome 	if (errno == ENETUNREACH) return(mStatus_TransientErr);
2055ffb0c9bSToomas Soome 
2065ffb0c9bSToomas Soome         if (MessageCount < 1000)
2075ffb0c9bSToomas Soome         {
2085ffb0c9bSToomas Soome             MessageCount++;
2095ffb0c9bSToomas Soome             if (thisIntf)
2105ffb0c9bSToomas Soome                 LogMsg("mDNSPlatformSendUDP got error %d (%s) sending packet to %#a on interface %#a/%s/%d",
2115ffb0c9bSToomas Soome                        errno, strerror(errno), dst, &thisIntf->coreIntf.ip, thisIntf->intfName, thisIntf->index);
2125ffb0c9bSToomas Soome             else
2135ffb0c9bSToomas Soome                 LogMsg("mDNSPlatformSendUDP got error %d (%s) sending packet to %#a", errno, strerror(errno), dst);
2145ffb0c9bSToomas Soome         }
2155ffb0c9bSToomas Soome     }
2165ffb0c9bSToomas Soome 
2175ffb0c9bSToomas Soome     return PosixErrorToStatus(err);
2185ffb0c9bSToomas Soome }
2194b22b933Srs 
TCPReadCallback(int fd,void * context)220472cd20dSToomas Soome mDNSlocal void TCPReadCallback(int fd, void *context)
221472cd20dSToomas Soome {
222472cd20dSToomas Soome     TCPSocket *sock = context;
223472cd20dSToomas Soome     (void)fd;
22419f828dfSToomas Soome 
225472cd20dSToomas Soome     if (sock->flags & kTCPSocketFlags_UseTLS)
226472cd20dSToomas Soome     {
227472cd20dSToomas Soome         // implement
228472cd20dSToomas Soome     }
229472cd20dSToomas Soome     else
230472cd20dSToomas Soome     {
231472cd20dSToomas Soome         sock->callback(sock, sock->context, mDNSfalse, sock->err);
232472cd20dSToomas Soome     }
233472cd20dSToomas Soome }
234472cd20dSToomas Soome 
tcpConnectCallback(int fd,void * context)235472cd20dSToomas Soome mDNSlocal void tcpConnectCallback(int fd, void *context)
236472cd20dSToomas Soome {
237472cd20dSToomas Soome     TCPSocket *sock = context;
238472cd20dSToomas Soome     mDNSBool c = !sock->connected;
239472cd20dSToomas Soome     int result;
240472cd20dSToomas Soome     socklen_t len = sizeof result;
241472cd20dSToomas Soome 
242472cd20dSToomas Soome     sock->connected = mDNStrue;
243472cd20dSToomas Soome 
244472cd20dSToomas Soome     if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &result, &len) < 0)
245472cd20dSToomas Soome     {
246472cd20dSToomas Soome         LogInfo("ERROR: TCPConnectCallback - unable to get connect error: socket %d: Error %d (%s)",
247472cd20dSToomas Soome                sock->events.fd, result, strerror(result));
248472cd20dSToomas Soome         sock->err = mStatus_ConnFailed;
249472cd20dSToomas Soome     }
250472cd20dSToomas Soome     else
251472cd20dSToomas Soome     {
252472cd20dSToomas Soome         if (result != 0)
253472cd20dSToomas Soome         {
254472cd20dSToomas Soome             sock->err = mStatus_ConnFailed;
255472cd20dSToomas Soome             if (result == EHOSTUNREACH || result == EADDRNOTAVAIL || result == ENETDOWN)
256472cd20dSToomas Soome             {
257472cd20dSToomas Soome                 LogInfo("ERROR: TCPConnectCallback - connect failed: socket %d: Error %d (%s)",
258472cd20dSToomas Soome                         sock->events.fd, result, strerror(result));
259472cd20dSToomas Soome             }
260472cd20dSToomas Soome             else
26119f828dfSToomas Soome             {
262472cd20dSToomas Soome                 LogMsg("ERROR: TCPConnectCallback - connect failed: socket %d: Error %d (%s)",
263472cd20dSToomas Soome                        sock->events.fd, result, strerror(result));
264472cd20dSToomas Soome             }
265472cd20dSToomas Soome         }
266472cd20dSToomas Soome         else
267472cd20dSToomas Soome         {
268472cd20dSToomas Soome             // The connection succeeded.
269472cd20dSToomas Soome             sock->connected = mDNStrue;
270472cd20dSToomas Soome             // Select for read events.
271472cd20dSToomas Soome             sock->events.fd = fd;
272472cd20dSToomas Soome             requestReadEvents(&sock->events, "mDNSPosix::tcpConnectCallback", TCPReadCallback, sock);
273472cd20dSToomas Soome         }
274472cd20dSToomas Soome     }
275472cd20dSToomas Soome 
276472cd20dSToomas Soome     if (sock->callback)
277472cd20dSToomas Soome     {
278472cd20dSToomas Soome         sock->callback(sock, sock->context, c, sock->err);
279472cd20dSToomas Soome         // Here sock must be assumed to be invalid, in case the callback freed it.
280472cd20dSToomas Soome         return;
281472cd20dSToomas Soome     }
282472cd20dSToomas Soome }
283472cd20dSToomas Soome 
2844b22b933Srs // This routine is called when the main loop detects that data is available on a socket.
SocketDataReady(mDNS * const m,PosixNetworkInterface * intf,int skt)2854b22b933Srs mDNSlocal void SocketDataReady(mDNS *const m, PosixNetworkInterface *intf, int skt)
2865ffb0c9bSToomas Soome {
2875ffb0c9bSToomas Soome     mDNSAddr senderAddr, destAddr;
2885ffb0c9bSToomas Soome     mDNSIPPort senderPort;
2895ffb0c9bSToomas Soome     ssize_t packetLen;
2905ffb0c9bSToomas Soome     DNSMessage packet;
2915ffb0c9bSToomas Soome     struct my_in_pktinfo packetInfo;
2925ffb0c9bSToomas Soome     struct sockaddr_storage from;
2935ffb0c9bSToomas Soome     socklen_t fromLen;
2945ffb0c9bSToomas Soome     int flags;
2955ffb0c9bSToomas Soome     mDNSu8 ttl;
2965ffb0c9bSToomas Soome     mDNSBool reject;
2975ffb0c9bSToomas Soome     const mDNSInterfaceID InterfaceID = intf ? intf->coreIntf.InterfaceID : NULL;
2985ffb0c9bSToomas Soome 
2995ffb0c9bSToomas Soome     assert(m    != NULL);
3005ffb0c9bSToomas Soome     assert(skt  >= 0);
3015ffb0c9bSToomas Soome 
3025ffb0c9bSToomas Soome     fromLen = sizeof(from);
3035ffb0c9bSToomas Soome     flags   = 0;
3045ffb0c9bSToomas Soome     packetLen = recvfrom_flags(skt, &packet, sizeof(packet), &flags, (struct sockaddr *) &from, &fromLen, &packetInfo, &ttl);
3055ffb0c9bSToomas Soome 
3065ffb0c9bSToomas Soome     if (packetLen >= 0)
3075ffb0c9bSToomas Soome     {
3085ffb0c9bSToomas Soome         SockAddrTomDNSAddr((struct sockaddr*)&from, &senderAddr, &senderPort);
3095ffb0c9bSToomas Soome         SockAddrTomDNSAddr((struct sockaddr*)&packetInfo.ipi_addr, &destAddr, NULL);
3105ffb0c9bSToomas Soome 
3115ffb0c9bSToomas Soome         // If we have broken IP_RECVDSTADDR functionality (so far
3125ffb0c9bSToomas Soome         // I've only seen this on OpenBSD) then apply a hack to
3135ffb0c9bSToomas Soome         // convince mDNS Core that this isn't a spoof packet.
3145ffb0c9bSToomas Soome         // Basically what we do is check to see whether the
3155ffb0c9bSToomas Soome         // packet arrived as a multicast and, if so, set its
3165ffb0c9bSToomas Soome         // destAddr to the mDNS address.
3175ffb0c9bSToomas Soome         //
3185ffb0c9bSToomas Soome         // I must admit that I could just be doing something
3195ffb0c9bSToomas Soome         // wrong on OpenBSD and hence triggering this problem
3205ffb0c9bSToomas Soome         // but I'm at a loss as to how.
3215ffb0c9bSToomas Soome         //
3225ffb0c9bSToomas Soome         // If this platform doesn't have IP_PKTINFO or IP_RECVDSTADDR, then we have
3235ffb0c9bSToomas Soome         // no way to tell the destination address or interface this packet arrived on,
3245ffb0c9bSToomas Soome         // so all we can do is just assume it's a multicast
3255ffb0c9bSToomas Soome 
3265ffb0c9bSToomas Soome         #if HAVE_BROKEN_RECVDSTADDR || (!defined(IP_PKTINFO) && !defined(IP_RECVDSTADDR))
3275ffb0c9bSToomas Soome         if ((destAddr.NotAnInteger == 0) && (flags & MSG_MCAST))
3285ffb0c9bSToomas Soome         {
3295ffb0c9bSToomas Soome             destAddr.type = senderAddr.type;
3305ffb0c9bSToomas Soome             if      (senderAddr.type == mDNSAddrType_IPv4) destAddr.ip.v4 = AllDNSLinkGroup_v4.ip.v4;
3315ffb0c9bSToomas Soome             else if (senderAddr.type == mDNSAddrType_IPv6) destAddr.ip.v6 = AllDNSLinkGroup_v6.ip.v6;
3325ffb0c9bSToomas Soome         }
3335ffb0c9bSToomas Soome         #endif
3345ffb0c9bSToomas Soome 
3355ffb0c9bSToomas Soome         // We only accept the packet if the interface on which it came
3365ffb0c9bSToomas Soome         // in matches the interface associated with this socket.
3375ffb0c9bSToomas Soome         // We do this match by name or by index, depending on which
3385ffb0c9bSToomas Soome         // information is available.  recvfrom_flags sets the name
3395ffb0c9bSToomas Soome         // to "" if the name isn't available, or the index to -1
3405ffb0c9bSToomas Soome         // if the index is available.  This accomodates the various
3415ffb0c9bSToomas Soome         // different capabilities of our target platforms.
3425ffb0c9bSToomas Soome 
3435ffb0c9bSToomas Soome         reject = mDNSfalse;
3445ffb0c9bSToomas Soome         if (!intf)
3455ffb0c9bSToomas Soome         {
3465ffb0c9bSToomas Soome             // Ignore multicasts accidentally delivered to our unicast receiving socket
3475ffb0c9bSToomas Soome             if (mDNSAddrIsDNSMulticast(&destAddr)) packetLen = -1;
3485ffb0c9bSToomas Soome         }
3495ffb0c9bSToomas Soome         else
3505ffb0c9bSToomas Soome         {
3515ffb0c9bSToomas Soome             if      (packetInfo.ipi_ifname[0] != 0) reject = (strcmp(packetInfo.ipi_ifname, intf->intfName) != 0);
3525ffb0c9bSToomas Soome             else if (packetInfo.ipi_ifindex != -1) reject = (packetInfo.ipi_ifindex != intf->index);
3535ffb0c9bSToomas Soome 
3545ffb0c9bSToomas Soome             if (reject)
3555ffb0c9bSToomas Soome             {
3565ffb0c9bSToomas Soome                 verbosedebugf("SocketDataReady ignored a packet from %#a to %#a on interface %s/%d expecting %#a/%s/%d/%d",
3575ffb0c9bSToomas Soome                               &senderAddr, &destAddr, packetInfo.ipi_ifname, packetInfo.ipi_ifindex,
3585ffb0c9bSToomas Soome                               &intf->coreIntf.ip, intf->intfName, intf->index, skt);
3595ffb0c9bSToomas Soome                 packetLen = -1;
3605ffb0c9bSToomas Soome                 num_pkts_rejected++;
3615ffb0c9bSToomas Soome                 if (num_pkts_rejected > (num_pkts_accepted + 1) * (num_registered_interfaces + 1) * 2)
3625ffb0c9bSToomas Soome                 {
3635ffb0c9bSToomas Soome                     fprintf(stderr,
3645ffb0c9bSToomas Soome                             "*** WARNING: Received %d packets; Accepted %d packets; Rejected %d packets because of interface mismatch\n",
3655ffb0c9bSToomas Soome                             num_pkts_accepted + num_pkts_rejected, num_pkts_accepted, num_pkts_rejected);
3665ffb0c9bSToomas Soome                     num_pkts_accepted = 0;
3675ffb0c9bSToomas Soome                     num_pkts_rejected = 0;
3685ffb0c9bSToomas Soome                 }
3695ffb0c9bSToomas Soome             }
3705ffb0c9bSToomas Soome             else
3715ffb0c9bSToomas Soome             {
3725ffb0c9bSToomas Soome                 verbosedebugf("SocketDataReady got a packet from %#a to %#a on interface %#a/%s/%d/%d",
3735ffb0c9bSToomas Soome                               &senderAddr, &destAddr, &intf->coreIntf.ip, intf->intfName, intf->index, skt);
3745ffb0c9bSToomas Soome                 num_pkts_accepted++;
3755ffb0c9bSToomas Soome             }
3765ffb0c9bSToomas Soome         }
3775ffb0c9bSToomas Soome     }
3785ffb0c9bSToomas Soome 
3795ffb0c9bSToomas Soome     if (packetLen >= 0)
3805ffb0c9bSToomas Soome         mDNSCoreReceive(m, &packet, (mDNSu8 *)&packet + packetLen,
3815ffb0c9bSToomas Soome                         &senderAddr, senderPort, &destAddr, MulticastDNSPort, InterfaceID);
3825ffb0c9bSToomas Soome }
3835ffb0c9bSToomas Soome 
mDNSPlatformTCPSocket(TCPSocketFlags flags,mDNSAddr_Type addrType,mDNSIPPort * port,domainname * hostname,mDNSBool useBackgroundTrafficClass)384472cd20dSToomas Soome mDNSexport TCPSocket *mDNSPlatformTCPSocket(TCPSocketFlags flags, mDNSAddr_Type addrType, mDNSIPPort * port,
385472cd20dSToomas Soome                                             domainname *hostname, mDNSBool useBackgroundTrafficClass)
3865ffb0c9bSToomas Soome {
387472cd20dSToomas Soome     TCPSocket *sock;
388472cd20dSToomas Soome     int len = sizeof (TCPSocket);
38919f828dfSToomas Soome 
390472cd20dSToomas Soome     (void)useBackgroundTrafficClass;
391472cd20dSToomas Soome 
392472cd20dSToomas Soome     if (hostname)
393472cd20dSToomas Soome     {
394472cd20dSToomas Soome         len += sizeof (domainname);
395472cd20dSToomas Soome     }
39619f828dfSToomas Soome     sock = malloc(len);
397472cd20dSToomas Soome 
398472cd20dSToomas Soome     if (sock == NULL)
399472cd20dSToomas Soome     {
400472cd20dSToomas Soome         LogMsg("mDNSPlatformTCPSocket: no memory for socket");
401472cd20dSToomas Soome         return NULL;
402472cd20dSToomas Soome     }
403472cd20dSToomas Soome     memset(sock, 0, sizeof *sock);
40419f828dfSToomas Soome 
405472cd20dSToomas Soome     if (hostname)
406472cd20dSToomas Soome     {
407472cd20dSToomas Soome         sock->hostname = (domainname *)(sock + 1);
408472cd20dSToomas Soome         LogMsg("mDNSPlatformTCPSocket: hostname %##s", hostname->c);
409472cd20dSToomas Soome         AssignDomainName(sock->hostname, hostname);
410472cd20dSToomas Soome     }
41119f828dfSToomas Soome 
412472cd20dSToomas Soome     sock->events.fd = -1;
413472cd20dSToomas Soome     if (!mDNSPosixTCPSocketSetup(&sock->events.fd, addrType, port, &sock->port))
414472cd20dSToomas Soome     {
415472cd20dSToomas Soome       if (sock->events.fd != -1) close(sock->events.fd);
416472cd20dSToomas Soome       free(sock);
417472cd20dSToomas Soome       return mDNSNULL;
418472cd20dSToomas Soome     }
419472cd20dSToomas Soome 
420472cd20dSToomas Soome     // Set up the other fields in the structure.
421472cd20dSToomas Soome     sock->flags = flags;
422472cd20dSToomas Soome     sock->err = mStatus_NoError;
423472cd20dSToomas Soome     sock->setup = mDNSfalse;
424472cd20dSToomas Soome     sock->connected = mDNSfalse;
425472cd20dSToomas Soome     return sock;
4265ffb0c9bSToomas Soome }
4275ffb0c9bSToomas Soome 
mDNSPlatformTCPSocketSetCallback(TCPSocket * sock,TCPConnectionCallback callback,void * context)428472cd20dSToomas Soome mDNSexport mStatus mDNSPlatformTCPSocketSetCallback(TCPSocket *sock, TCPConnectionCallback callback, void *context)
4295ffb0c9bSToomas Soome {
430472cd20dSToomas Soome     sock->callback = callback;
431472cd20dSToomas Soome     sock->context = context;
432472cd20dSToomas Soome     return mStatus_NoError;
433472cd20dSToomas Soome }
434472cd20dSToomas Soome 
mDNSPlatformTCPAccept(TCPSocketFlags flags,int fd)435472cd20dSToomas Soome mDNSexport TCPSocket *mDNSPlatformTCPAccept(TCPSocketFlags flags, int fd)
436472cd20dSToomas Soome {
437472cd20dSToomas Soome     TCPSocket *sock;
438472cd20dSToomas Soome 
439472cd20dSToomas Soome     // XXX Add!
440472cd20dSToomas Soome     if (flags & kTCPSocketFlags_UseTLS)
441472cd20dSToomas Soome     {
442472cd20dSToomas Soome     return mDNSNULL; // not supported yet.
443472cd20dSToomas Soome     }
444472cd20dSToomas Soome 
445472cd20dSToomas Soome     sock = (TCPSocket *) mDNSPlatformMemAllocateClear(sizeof *sock);
446472cd20dSToomas Soome     if (!sock)
447472cd20dSToomas Soome     {
448472cd20dSToomas Soome         return mDNSNULL;
449472cd20dSToomas Soome     }
450472cd20dSToomas Soome 
451472cd20dSToomas Soome     sock->events.fd = fd;
452472cd20dSToomas Soome     sock->flags = flags;
453472cd20dSToomas Soome     sock->connected = mDNStrue;
454472cd20dSToomas Soome     return sock;
455472cd20dSToomas Soome }
456472cd20dSToomas Soome 
457472cd20dSToomas Soome 
tcpListenCallback(int fd,void * context)458472cd20dSToomas Soome mDNSlocal void tcpListenCallback(int fd, void *context)
459472cd20dSToomas Soome {
460472cd20dSToomas Soome     TCPListener *listener = context;
461472cd20dSToomas Soome     TCPSocket *sock;
46219f828dfSToomas Soome 
463472cd20dSToomas Soome     sock = mDNSPosixDoTCPListenCallback(fd, listener->addressType, listener->socketFlags,
464472cd20dSToomas Soome                                  listener->callback, listener->context);
465472cd20dSToomas Soome     if (sock != NULL)
466472cd20dSToomas Soome     {
467472cd20dSToomas Soome         requestReadEvents(&sock->events, "mDNSPosix::tcpListenCallback", TCPReadCallback, sock);
468472cd20dSToomas Soome     }
469472cd20dSToomas Soome }
470472cd20dSToomas Soome 
mDNSPlatformTCPListen(mDNSAddr_Type addrType,mDNSIPPort * port,mDNSAddr * addr,TCPSocketFlags socketFlags,mDNSBool reuseAddr,int queueLength,TCPAcceptedCallback callback,void * context)471472cd20dSToomas Soome mDNSexport TCPListener *mDNSPlatformTCPListen(mDNSAddr_Type addrType, mDNSIPPort *port, mDNSAddr *addr,
472472cd20dSToomas Soome                                               TCPSocketFlags socketFlags, mDNSBool reuseAddr, int queueLength,
473472cd20dSToomas Soome                                               TCPAcceptedCallback callback, void *context)
474472cd20dSToomas Soome {
475472cd20dSToomas Soome     TCPListener *ret;
476472cd20dSToomas Soome     int fd = -1;
477472cd20dSToomas Soome 
478472cd20dSToomas Soome     if (!mDNSPosixTCPListen(&fd, addrType, port, addr, reuseAddr, queueLength))
479472cd20dSToomas Soome     {
480472cd20dSToomas Soome         if (fd != -1)
481472cd20dSToomas Soome         {
482472cd20dSToomas Soome             close(fd);
483472cd20dSToomas Soome         }
484472cd20dSToomas Soome         return mDNSNULL;
485472cd20dSToomas Soome     }
48619f828dfSToomas Soome 
487472cd20dSToomas Soome     // Allocate a listener structure
488472cd20dSToomas Soome     ret = (TCPListener *) mDNSPlatformMemAllocateClear(sizeof *ret);
489472cd20dSToomas Soome     if (ret == NULL)
490472cd20dSToomas Soome     {
491472cd20dSToomas Soome         LogMsg("mDNSPlatformTCPListen: no memory for TCPListener struct.");
492472cd20dSToomas Soome         close(fd);
493472cd20dSToomas Soome         return mDNSNULL;
494472cd20dSToomas Soome     }
495472cd20dSToomas Soome     ret->events.fd = fd;
496472cd20dSToomas Soome     ret->callback = callback;
497472cd20dSToomas Soome     ret->context = context;
498472cd20dSToomas Soome     ret->addressType = addrType;
499472cd20dSToomas Soome     ret->socketFlags = socketFlags;
500472cd20dSToomas Soome 
501472cd20dSToomas Soome     // When we get a connection, mDNSPosixListenCallback will be called, and it will invoke the
502472cd20dSToomas Soome     // callback we were passed.
503472cd20dSToomas Soome     requestReadEvents(&ret->events, "tcpListenCallback", tcpListenCallback, ret);
504472cd20dSToomas Soome     return ret;
5055ffb0c9bSToomas Soome }
5065ffb0c9bSToomas Soome 
mDNSPlatformTCPGetFD(TCPSocket * sock)5075ffb0c9bSToomas Soome mDNSexport int mDNSPlatformTCPGetFD(TCPSocket *sock)
5085ffb0c9bSToomas Soome {
509472cd20dSToomas Soome     return sock->events.fd;
5105ffb0c9bSToomas Soome }
5115ffb0c9bSToomas Soome 
mDNSPlatformTCPConnect(TCPSocket * sock,const mDNSAddr * dst,mDNSOpaque16 dstport,mDNSInterfaceID InterfaceID,TCPConnectionCallback callback,void * context)512472cd20dSToomas Soome mDNSexport mStatus mDNSPlatformTCPConnect(TCPSocket *sock, const mDNSAddr *dst, mDNSOpaque16 dstport,
513472cd20dSToomas Soome                                           mDNSInterfaceID InterfaceID, TCPConnectionCallback callback, void *context)
5145ffb0c9bSToomas Soome {
515472cd20dSToomas Soome     int result;
516472cd20dSToomas Soome     union {
517472cd20dSToomas Soome         struct sockaddr sa;
518472cd20dSToomas Soome         struct sockaddr_in sin;
519472cd20dSToomas Soome         struct sockaddr_in6 sin6;
520472cd20dSToomas Soome     } addr;
521472cd20dSToomas Soome     socklen_t len;
522472cd20dSToomas Soome 
523472cd20dSToomas Soome     sock->callback = callback;
524472cd20dSToomas Soome     sock->context = context;
525472cd20dSToomas Soome     sock->setup = mDNSfalse;
526472cd20dSToomas Soome     sock->connected = mDNSfalse;
527472cd20dSToomas Soome     sock->err = mStatus_NoError;
528472cd20dSToomas Soome 
529472cd20dSToomas Soome     result = fcntl(sock->events.fd, F_GETFL, 0);
530472cd20dSToomas Soome     if (result < 0)
531472cd20dSToomas Soome     {
532472cd20dSToomas Soome         LogMsg("mDNSPlatformTCPConnect: F_GETFL failed: %s", strerror(errno));
533472cd20dSToomas Soome         return mStatus_UnknownErr;
534472cd20dSToomas Soome     }
535472cd20dSToomas Soome 
536472cd20dSToomas Soome     result = fcntl(sock->events.fd, F_SETFL, result | O_NONBLOCK);
537472cd20dSToomas Soome     if (result < 0)
538472cd20dSToomas Soome     {
539472cd20dSToomas Soome         LogMsg("mDNSPlatformTCPConnect: F_SETFL failed: %s", strerror(errno));
540472cd20dSToomas Soome         return mStatus_UnknownErr;
541472cd20dSToomas Soome     }
542472cd20dSToomas Soome 
543472cd20dSToomas Soome     // If we've been asked to bind to a single interface, do it.  See comment in mDNSMacOSX.c for more info.
544472cd20dSToomas Soome     if (InterfaceID)
545472cd20dSToomas Soome     {
546472cd20dSToomas Soome         PosixNetworkInterface *iface = (PosixNetworkInterface *)InterfaceID;
547472cd20dSToomas Soome #if defined(SO_BINDTODEVICE)
548472cd20dSToomas Soome         result = setsockopt(sock->events.fd,
549472cd20dSToomas Soome                             SOL_SOCKET, SO_BINDTODEVICE, iface->intfName, strlen(iface->intfName));
550472cd20dSToomas Soome         if (result < 0)
551472cd20dSToomas Soome         {
552472cd20dSToomas Soome             LogMsg("mDNSPlatformTCPConnect: SO_BINDTODEVICE failed on %s: %s", iface->intfName, strerror(errno));
553472cd20dSToomas Soome             return mStatus_BadParamErr;
554472cd20dSToomas Soome         }
555472cd20dSToomas Soome #else
556472cd20dSToomas Soome         if (dst->type == mDNSAddrType_IPv4)
557472cd20dSToomas Soome         {
558472cd20dSToomas Soome #if defined(IP_BOUND_IF)
559472cd20dSToomas Soome             result = setsockopt(sock->events.fd, IPPROTO_IP, IP_BOUND_IF, &iface->index, sizeof iface->index);
560472cd20dSToomas Soome             if (result < 0)
561472cd20dSToomas Soome             {
562472cd20dSToomas Soome                 LogMsg("mDNSPlatformTCPConnect: IP_BOUND_IF failed on %s (%d): %s",
563472cd20dSToomas Soome                        iface->intfName, iface->index, strerror(errno));
564472cd20dSToomas Soome                 return mStatus_BadParamErr;
565472cd20dSToomas Soome             }
566472cd20dSToomas Soome #else
567472cd20dSToomas Soome             (void)iface;
568472cd20dSToomas Soome #endif // IP_BOUND_IF
569472cd20dSToomas Soome         }
570472cd20dSToomas Soome         else
571472cd20dSToomas Soome         { // IPv6
572472cd20dSToomas Soome #if defined(IPV6_BOUND_IF)
573472cd20dSToomas Soome             result = setsockopt(sock->events.fd, IPPROTO_IPV6, IPV6_BOUND_IF, &iface->index, sizeof iface->index);
574472cd20dSToomas Soome             if (result < 0)
575472cd20dSToomas Soome             {
576472cd20dSToomas Soome                 LogMsg("mDNSPlatformTCPConnect: IP_BOUND_IF failed on %s (%d): %s",
577472cd20dSToomas Soome                        iface->intfName, iface->index, strerror(errno));
578472cd20dSToomas Soome                 return mStatus_BadParamErr;
579472cd20dSToomas Soome             }
580472cd20dSToomas Soome #else
581472cd20dSToomas Soome             (void)iface;
582472cd20dSToomas Soome #endif // IPV6_BOUND_IF
58319f828dfSToomas Soome         }
584472cd20dSToomas Soome #endif // SO_BINDTODEVICE
585472cd20dSToomas Soome     }
586472cd20dSToomas Soome 
587472cd20dSToomas Soome     memset(&addr, 0, sizeof addr);
588472cd20dSToomas Soome     if (dst->type == mDNSAddrType_IPv4)
589472cd20dSToomas Soome     {
590472cd20dSToomas Soome         addr.sa.sa_family = AF_INET;
591472cd20dSToomas Soome         addr.sin.sin_port = dstport.NotAnInteger;
592472cd20dSToomas Soome         len = sizeof (struct sockaddr_in);
593472cd20dSToomas Soome         addr.sin.sin_addr.s_addr = dst->ip.v4.NotAnInteger;
594472cd20dSToomas Soome     }
595472cd20dSToomas Soome     else
596472cd20dSToomas Soome     {
597472cd20dSToomas Soome         addr.sa.sa_family = AF_INET6;
598472cd20dSToomas Soome         len = sizeof (struct sockaddr_in6);
599472cd20dSToomas Soome         addr.sin6.sin6_port = dstport.NotAnInteger;
600472cd20dSToomas Soome         memcpy(&addr.sin6.sin6_addr.s6_addr, &dst->ip.v6, sizeof addr.sin6.sin6_addr.s6_addr);
601472cd20dSToomas Soome     }
602472cd20dSToomas Soome #ifndef NOT_HAVE_SA_LEN
603472cd20dSToomas Soome     addr.sa.sa_len = len;
604472cd20dSToomas Soome #endif
605472cd20dSToomas Soome 
606472cd20dSToomas Soome     result = connect(sock->events.fd, (struct sockaddr *)&addr, len);
607472cd20dSToomas Soome     if (result < 0)
608472cd20dSToomas Soome     {
609472cd20dSToomas Soome         if (errno == EINPROGRESS)
610472cd20dSToomas Soome         {
611472cd20dSToomas Soome             requestWriteEvents(&sock->events, "mDNSPlatformConnect", tcpConnectCallback, sock);
612472cd20dSToomas Soome             return mStatus_ConnPending;
613472cd20dSToomas Soome         }
614472cd20dSToomas Soome         if (errno == EHOSTUNREACH || errno == EADDRNOTAVAIL || errno == ENETDOWN)
615472cd20dSToomas Soome         {
616472cd20dSToomas Soome             LogInfo("ERROR: mDNSPlatformTCPConnect - connect failed: socket %d: Error %d (%s)",
617472cd20dSToomas Soome                     sock->events.fd, errno, strerror(errno));
618472cd20dSToomas Soome         }
619472cd20dSToomas Soome         else
62019f828dfSToomas Soome         {
621472cd20dSToomas Soome             LogMsg("ERROR: mDNSPlatformTCPConnect - connect failed: socket %d: Error %d (%s) length %d",
622472cd20dSToomas Soome                    sock->events.fd, errno, strerror(errno), len);
623472cd20dSToomas Soome         }
624472cd20dSToomas Soome         return mStatus_ConnFailed;
62519f828dfSToomas Soome     }
626472cd20dSToomas Soome 
627472cd20dSToomas Soome     LogMsg("NOTE: mDNSPlatformTCPConnect completed synchronously");
628472cd20dSToomas Soome     return mStatus_NoError;
6295ffb0c9bSToomas Soome }
6305ffb0c9bSToomas Soome 
mDNSPlatformTCPCloseConnection(TCPSocket * sock)6315ffb0c9bSToomas Soome mDNSexport void mDNSPlatformTCPCloseConnection(TCPSocket *sock)
6325ffb0c9bSToomas Soome {
633472cd20dSToomas Soome     if (sock)
634472cd20dSToomas Soome     { // can sock really be NULL when this is called?
635472cd20dSToomas Soome         shutdown(sock->events.fd, SHUT_RDWR);
636472cd20dSToomas Soome         stopReadOrWriteEvents(sock->events.fd, mDNSfalse, mDNStrue,
637472cd20dSToomas Soome                               PosixEventFlag_Read | PosixEventFlag_Write);
638472cd20dSToomas Soome         close(sock->events.fd);
639472cd20dSToomas Soome         free(sock);
640472cd20dSToomas Soome     }
6415ffb0c9bSToomas Soome }
6425ffb0c9bSToomas Soome 
mDNSPlatformReadTCP(TCPSocket * sock,void * buf,unsigned long buflen,mDNSBool * closed)6435ffb0c9bSToomas Soome mDNSexport long mDNSPlatformReadTCP(TCPSocket *sock, void *buf, unsigned long buflen, mDNSBool * closed)
6445ffb0c9bSToomas Soome {
645472cd20dSToomas Soome     ssize_t nread;
64619f828dfSToomas Soome 
647472cd20dSToomas Soome     *closed = mDNSfalse;
648472cd20dSToomas Soome     if (sock->flags & kTCPSocketFlags_UseTLS)
649472cd20dSToomas Soome     {
650472cd20dSToomas Soome         // Implement...
651472cd20dSToomas Soome         nread = -1;
652472cd20dSToomas Soome         *closed = mDNStrue;
653472cd20dSToomas Soome     } else {
654472cd20dSToomas Soome         nread = mDNSPosixReadTCP(sock->events.fd, buf, buflen, closed);
655472cd20dSToomas Soome     }
656472cd20dSToomas Soome     return nread;
657472cd20dSToomas Soome }
658472cd20dSToomas Soome 
mDNSPlatformTCPWritable(TCPSocket * sock)659472cd20dSToomas Soome mDNSexport mDNSBool mDNSPlatformTCPWritable(TCPSocket *sock)
660472cd20dSToomas Soome {
661472cd20dSToomas Soome     fd_set w = { 0 };
662472cd20dSToomas Soome     int nfds = sock->events.fd + 1;
663472cd20dSToomas Soome     int count;
664472cd20dSToomas Soome     struct timeval tv;
665472cd20dSToomas Soome 
666472cd20dSToomas Soome     if (nfds > FD_SETSIZE)
667472cd20dSToomas Soome     {
668472cd20dSToomas Soome         LogMsg("ERROR: mDNSPlatformTCPWritable called on an fd that won't fit in an fd_set.");
669472cd20dSToomas Soome         return mDNStrue; // hope for the best?
670472cd20dSToomas Soome     }
671472cd20dSToomas Soome     FD_SET(sock->events.fd, &w);
672472cd20dSToomas Soome     tv.tv_sec = tv.tv_usec = 0;
673472cd20dSToomas Soome     count = select(nfds, NULL, &w, NULL, &tv);
674472cd20dSToomas Soome     if (count > 0)
675472cd20dSToomas Soome     {
676472cd20dSToomas Soome         return mDNStrue;
677472cd20dSToomas Soome     }
678472cd20dSToomas Soome     return mDNSfalse;
6795ffb0c9bSToomas Soome }
6805ffb0c9bSToomas Soome 
mDNSPlatformWriteTCP(TCPSocket * sock,const char * msg,unsigned long len)6815ffb0c9bSToomas Soome mDNSexport long mDNSPlatformWriteTCP(TCPSocket *sock, const char *msg, unsigned long len)
6825ffb0c9bSToomas Soome {
683472cd20dSToomas Soome     if (sock->flags & kTCPSocketFlags_UseTLS)
684472cd20dSToomas Soome     {
685472cd20dSToomas Soome         // implement
686472cd20dSToomas Soome         return -1;
687472cd20dSToomas Soome     }
688472cd20dSToomas Soome     else
689472cd20dSToomas Soome     {
690472cd20dSToomas Soome         return mDNSPosixWriteTCP(sock->events.fd, msg, len);
691472cd20dSToomas Soome     }
6925ffb0c9bSToomas Soome }
6935ffb0c9bSToomas Soome 
mDNSPlatformUDPSocket(mDNSIPPort port)694c65ebfc7SToomas Soome mDNSexport UDPSocket *mDNSPlatformUDPSocket(mDNSIPPort port)
6955ffb0c9bSToomas Soome {
6965ffb0c9bSToomas Soome     (void)port;         // Unused
6975ffb0c9bSToomas Soome     return NULL;
6985ffb0c9bSToomas Soome }
6995ffb0c9bSToomas Soome 
mDNSPlatformUDPClose(UDPSocket * sock)7005ffb0c9bSToomas Soome mDNSexport void           mDNSPlatformUDPClose(UDPSocket *sock)
7015ffb0c9bSToomas Soome {
7025ffb0c9bSToomas Soome     (void)sock;         // Unused
7035ffb0c9bSToomas Soome }
7045ffb0c9bSToomas Soome 
mDNSPlatformUpdateProxyList(const mDNSInterfaceID InterfaceID)705c65ebfc7SToomas Soome mDNSexport void mDNSPlatformUpdateProxyList(const mDNSInterfaceID InterfaceID)
7065ffb0c9bSToomas Soome {
7075ffb0c9bSToomas Soome     (void)InterfaceID;          // Unused
7085ffb0c9bSToomas Soome }
7095ffb0c9bSToomas Soome 
mDNSPlatformSendRawPacket(const void * const msg,const mDNSu8 * const end,mDNSInterfaceID InterfaceID)7105ffb0c9bSToomas Soome mDNSexport void mDNSPlatformSendRawPacket(const void *const msg, const mDNSu8 *const end, mDNSInterfaceID InterfaceID)
7115ffb0c9bSToomas Soome {
7125ffb0c9bSToomas Soome     (void)msg;          // Unused
7135ffb0c9bSToomas Soome     (void)end;          // Unused
7145ffb0c9bSToomas Soome     (void)InterfaceID;          // Unused
7155ffb0c9bSToomas Soome }
7165ffb0c9bSToomas Soome 
mDNSPlatformSetLocalAddressCacheEntry(const mDNSAddr * const tpa,const mDNSEthAddr * const tha,mDNSInterfaceID InterfaceID)717c65ebfc7SToomas Soome mDNSexport void mDNSPlatformSetLocalAddressCacheEntry(const mDNSAddr *const tpa, const mDNSEthAddr *const tha, mDNSInterfaceID InterfaceID)
7185ffb0c9bSToomas Soome {
7195ffb0c9bSToomas Soome     (void)tpa;          // Unused
7205ffb0c9bSToomas Soome     (void)tha;          // Unused
7215ffb0c9bSToomas Soome     (void)InterfaceID;          // Unused
7225ffb0c9bSToomas Soome }
7235ffb0c9bSToomas Soome 
mDNSPlatformTLSSetupCerts(void)7245ffb0c9bSToomas Soome mDNSexport mStatus mDNSPlatformTLSSetupCerts(void)
7255ffb0c9bSToomas Soome {
7265ffb0c9bSToomas Soome     return(mStatus_UnsupportedErr);
7275ffb0c9bSToomas Soome }
7285ffb0c9bSToomas Soome 
mDNSPlatformTLSTearDownCerts(void)7295ffb0c9bSToomas Soome mDNSexport void mDNSPlatformTLSTearDownCerts(void)
7305ffb0c9bSToomas Soome {
7315ffb0c9bSToomas Soome }
7325ffb0c9bSToomas Soome 
mDNSPlatformSetAllowSleep(mDNSBool allowSleep,const char * reason)733c65ebfc7SToomas Soome mDNSexport void mDNSPlatformSetAllowSleep(mDNSBool allowSleep, const char *reason)
7345ffb0c9bSToomas Soome {
7355ffb0c9bSToomas Soome     (void) allowSleep;
7365ffb0c9bSToomas Soome     (void) reason;
7375ffb0c9bSToomas Soome }
7384b22b933Srs 
7394b22b933Srs #if COMPILER_LIKES_PRAGMA_MARK
7405ffb0c9bSToomas Soome #pragma mark -
7415ffb0c9bSToomas Soome #pragma mark - /etc/hosts support
7424b22b933Srs #endif
7434b22b933Srs 
FreeEtcHosts(mDNS * const m,AuthRecord * const rr,mStatus result)7445ffb0c9bSToomas Soome mDNSexport void FreeEtcHosts(mDNS *const m, AuthRecord *const rr, mStatus result)
7455ffb0c9bSToomas Soome {
7465ffb0c9bSToomas Soome     (void)m;  // unused
7475ffb0c9bSToomas Soome     (void)rr;
7485ffb0c9bSToomas Soome     (void)result;
7495ffb0c9bSToomas Soome }
7505ffb0c9bSToomas Soome 
7515ffb0c9bSToomas Soome 
7525ffb0c9bSToomas Soome #if COMPILER_LIKES_PRAGMA_MARK
7535ffb0c9bSToomas Soome #pragma mark ***** DDNS Config Platform Functions
7545ffb0c9bSToomas Soome #endif
7555ffb0c9bSToomas Soome 
mDNSPlatformSetDNSConfig(mDNSBool setservers,mDNSBool setsearch,domainname * const fqdn,DNameListElem ** RegDomains,DNameListElem ** BrowseDomains,mDNSBool ackConfig)756c65ebfc7SToomas Soome mDNSexport mDNSBool mDNSPlatformSetDNSConfig(mDNSBool setservers, mDNSBool setsearch, domainname *const fqdn, DNameListElem **RegDomains,
7575ffb0c9bSToomas Soome     DNameListElem **BrowseDomains, mDNSBool ackConfig)
7585ffb0c9bSToomas Soome {
7595ffb0c9bSToomas Soome     (void) setservers;
7605ffb0c9bSToomas Soome     (void) setsearch;
7615ffb0c9bSToomas Soome     (void) ackConfig;
7625ffb0c9bSToomas Soome 
763472cd20dSToomas Soome     if (fqdn         ) fqdn->c[0]      = 0;
764472cd20dSToomas Soome     if (RegDomains   ) *RegDomains     = NULL;
765472cd20dSToomas Soome     if (BrowseDomains) *BrowseDomains  = NULL;
766472cd20dSToomas Soome 
7675ffb0c9bSToomas Soome     return mDNStrue;
7685ffb0c9bSToomas Soome }
7695ffb0c9bSToomas Soome 
mDNSPlatformGetPrimaryInterface(mDNSAddr * v4,mDNSAddr * v6,mDNSAddr * router)770c65ebfc7SToomas Soome mDNSexport mStatus mDNSPlatformGetPrimaryInterface(mDNSAddr * v4, mDNSAddr * v6, mDNSAddr * router)
7715ffb0c9bSToomas Soome {
7725ffb0c9bSToomas Soome     (void) v4;
7735ffb0c9bSToomas Soome     (void) v6;
7745ffb0c9bSToomas Soome     (void) router;
7755ffb0c9bSToomas Soome 
7765ffb0c9bSToomas Soome     return mStatus_UnsupportedErr;
7775ffb0c9bSToomas Soome }
7785ffb0c9bSToomas Soome 
mDNSPlatformDynDNSHostNameStatusChanged(const domainname * const dname,const mStatus status)7795ffb0c9bSToomas Soome mDNSexport void mDNSPlatformDynDNSHostNameStatusChanged(const domainname *const dname, const mStatus status)
7805ffb0c9bSToomas Soome {
7815ffb0c9bSToomas Soome     (void) dname;
7825ffb0c9bSToomas Soome     (void) status;
7835ffb0c9bSToomas Soome }
7844b22b933Srs 
7854b22b933Srs #if COMPILER_LIKES_PRAGMA_MARK
7864b22b933Srs #pragma mark ***** Init and Term
7874b22b933Srs #endif
7884b22b933Srs 
7894b22b933Srs // This gets the current hostname, truncating it at the first dot if necessary
GetUserSpecifiedRFC1034ComputerName(domainlabel * const namelabel)7904b22b933Srs mDNSlocal void GetUserSpecifiedRFC1034ComputerName(domainlabel *const namelabel)
7915ffb0c9bSToomas Soome {
7925ffb0c9bSToomas Soome     int len = 0;
7935ffb0c9bSToomas Soome     gethostname((char *)(&namelabel->c[1]), MAX_DOMAIN_LABEL);
7945ffb0c9bSToomas Soome     while (len < MAX_DOMAIN_LABEL && namelabel->c[len+1] && namelabel->c[len+1] != '.') len++;
7955ffb0c9bSToomas Soome     namelabel->c[0] = len;
7965ffb0c9bSToomas Soome }
7974b22b933Srs 
7984b22b933Srs // On OS X this gets the text of the field labelled "Computer Name" in the Sharing Prefs Control Panel
7994b22b933Srs // Other platforms can either get the information from the appropriate place,
8004b22b933Srs // or they can alternatively just require all registering services to provide an explicit name
GetUserSpecifiedFriendlyComputerName(domainlabel * const namelabel)8014b22b933Srs mDNSlocal void GetUserSpecifiedFriendlyComputerName(domainlabel *const namelabel)
8025ffb0c9bSToomas Soome {
8035ffb0c9bSToomas Soome     // On Unix we have no better name than the host name, so we just use that.
8045ffb0c9bSToomas Soome     GetUserSpecifiedRFC1034ComputerName(namelabel);
8055ffb0c9bSToomas Soome }
8064b22b933Srs 
ParseDNSServers(mDNS * m,const char * filePath)8074b22b933Srs mDNSexport int ParseDNSServers(mDNS *m, const char *filePath)
8085ffb0c9bSToomas Soome {
8095ffb0c9bSToomas Soome     char line[256];
8105ffb0c9bSToomas Soome     char nameserver[16];
8115ffb0c9bSToomas Soome     char keyword[11];
8125ffb0c9bSToomas Soome     int numOfServers = 0;
8135ffb0c9bSToomas Soome     FILE *fp = fopen(filePath, "r");
8145ffb0c9bSToomas Soome     if (fp == NULL) return -1;
8155ffb0c9bSToomas Soome     while (fgets(line,sizeof(line),fp))
8165ffb0c9bSToomas Soome     {
8175ffb0c9bSToomas Soome         struct in_addr ina;
8185ffb0c9bSToomas Soome         line[255]='\0';     // just to be safe
8195ffb0c9bSToomas Soome         if (sscanf(line,"%10s %15s", keyword, nameserver) != 2) continue;   // it will skip whitespaces
8205ffb0c9bSToomas Soome         if (strncasecmp(keyword,"nameserver",10)) continue;
8215ffb0c9bSToomas Soome         if (inet_aton(nameserver, (struct in_addr *)&ina) != 0)
8225ffb0c9bSToomas Soome         {
8235ffb0c9bSToomas Soome             mDNSAddr DNSAddr;
8245ffb0c9bSToomas Soome             DNSAddr.type = mDNSAddrType_IPv4;
8255ffb0c9bSToomas Soome             DNSAddr.ip.v4.NotAnInteger = ina.s_addr;
826472cd20dSToomas Soome             mDNS_AddDNSServer(m, NULL, mDNSInterface_Any, 0, &DNSAddr, UnicastDNSPort, kScopeNone, 0, mDNSfalse, mDNSfalse, mDNSfalse, mDNSfalse, 0, mDNStrue, mDNStrue, mDNSfalse);
8275ffb0c9bSToomas Soome             numOfServers++;
8285ffb0c9bSToomas Soome         }
8295ffb0c9bSToomas Soome     }
830472cd20dSToomas Soome     fclose(fp);
8315ffb0c9bSToomas Soome     return (numOfServers > 0) ? 0 : -1;
8325ffb0c9bSToomas Soome }
8334b22b933Srs 
8344b22b933Srs // Searches the interface list looking for the named interface.
8354b22b933Srs // Returns a pointer to if it found, or NULL otherwise.
SearchForInterfaceByName(mDNS * const m,const char * intfName)8364b22b933Srs mDNSlocal PosixNetworkInterface *SearchForInterfaceByName(mDNS *const m, const char *intfName)
8375ffb0c9bSToomas Soome {
8385ffb0c9bSToomas Soome     PosixNetworkInterface *intf;
8394b22b933Srs 
8405ffb0c9bSToomas Soome     assert(m != NULL);
8415ffb0c9bSToomas Soome     assert(intfName != NULL);
8424b22b933Srs 
8435ffb0c9bSToomas Soome     intf = (PosixNetworkInterface*)(m->HostInterfaces);
8445ffb0c9bSToomas Soome     while ((intf != NULL) && (strcmp(intf->intfName, intfName) != 0))
8455ffb0c9bSToomas Soome         intf = (PosixNetworkInterface *)(intf->coreIntf.next);
8464b22b933Srs 
8475ffb0c9bSToomas Soome     return intf;
8485ffb0c9bSToomas Soome }
8494b22b933Srs 
mDNSPlatformInterfaceIDfromInterfaceIndex(mDNS * const m,mDNSu32 index)8504b22b933Srs mDNSexport mDNSInterfaceID mDNSPlatformInterfaceIDfromInterfaceIndex(mDNS *const m, mDNSu32 index)
8515ffb0c9bSToomas Soome {
8525ffb0c9bSToomas Soome     PosixNetworkInterface *intf;
8535ffb0c9bSToomas Soome 
8545ffb0c9bSToomas Soome     assert(m != NULL);
8555ffb0c9bSToomas Soome 
8565ffb0c9bSToomas Soome     if (index == kDNSServiceInterfaceIndexLocalOnly) return(mDNSInterface_LocalOnly);
8575ffb0c9bSToomas Soome     if (index == kDNSServiceInterfaceIndexP2P      ) return(mDNSInterface_P2P);
8585ffb0c9bSToomas Soome     if (index == kDNSServiceInterfaceIndexAny      ) return(mDNSInterface_Any);
8594b22b933Srs 
8605ffb0c9bSToomas Soome     intf = (PosixNetworkInterface*)(m->HostInterfaces);
8615ffb0c9bSToomas Soome     while ((intf != NULL) && (mDNSu32) intf->index != index)
8625ffb0c9bSToomas Soome         intf = (PosixNetworkInterface *)(intf->coreIntf.next);
8634b22b933Srs 
8645ffb0c9bSToomas Soome     return (mDNSInterfaceID) intf;
8655ffb0c9bSToomas Soome }
8664b22b933Srs 
mDNSPlatformInterfaceIndexfromInterfaceID(mDNS * const m,mDNSInterfaceID id,mDNSBool suppressNetworkChange)8675ffb0c9bSToomas Soome mDNSexport mDNSu32 mDNSPlatformInterfaceIndexfromInterfaceID(mDNS *const m, mDNSInterfaceID id, mDNSBool suppressNetworkChange)
8685ffb0c9bSToomas Soome {
8695ffb0c9bSToomas Soome     PosixNetworkInterface *intf;
8705ffb0c9bSToomas Soome     (void) suppressNetworkChange; // Unused
8714b22b933Srs 
8725ffb0c9bSToomas Soome     assert(m != NULL);
8734b22b933Srs 
8745ffb0c9bSToomas Soome     if (id == mDNSInterface_LocalOnly) return(kDNSServiceInterfaceIndexLocalOnly);
8755ffb0c9bSToomas Soome     if (id == mDNSInterface_P2P      ) return(kDNSServiceInterfaceIndexP2P);
8765ffb0c9bSToomas Soome     if (id == mDNSInterface_Any      ) return(kDNSServiceInterfaceIndexAny);
8774b22b933Srs 
8785ffb0c9bSToomas Soome     intf = (PosixNetworkInterface*)(m->HostInterfaces);
8795ffb0c9bSToomas Soome     while ((intf != NULL) && (mDNSInterfaceID) intf != id)
8805ffb0c9bSToomas Soome         intf = (PosixNetworkInterface *)(intf->coreIntf.next);
8814b22b933Srs 
8825ffb0c9bSToomas Soome     if (intf) return intf->index;
8834b22b933Srs 
8845ffb0c9bSToomas Soome     // If we didn't find the interface, check the RecentInterfaces list as well
8855ffb0c9bSToomas Soome     intf = gRecentInterfaces;
8865ffb0c9bSToomas Soome     while ((intf != NULL) && (mDNSInterfaceID) intf != id)
8875ffb0c9bSToomas Soome         intf = (PosixNetworkInterface *)(intf->coreIntf.next);
8885ffb0c9bSToomas Soome 
8895ffb0c9bSToomas Soome     return intf ? intf->index : 0;
8905ffb0c9bSToomas Soome }
8914b22b933Srs 
8924b22b933Srs // Frees the specified PosixNetworkInterface structure. The underlying
8934b22b933Srs // interface must have already been deregistered with the mDNS core.
FreePosixNetworkInterface(PosixNetworkInterface * intf)8944b22b933Srs mDNSlocal void FreePosixNetworkInterface(PosixNetworkInterface *intf)
8955ffb0c9bSToomas Soome {
896c65ebfc7SToomas Soome     int rv;
8975ffb0c9bSToomas Soome     assert(intf != NULL);
8985ffb0c9bSToomas Soome     if (intf->intfName != NULL) free((void *)intf->intfName);
899c65ebfc7SToomas Soome     if (intf->multicastSocket4 != -1)
900c65ebfc7SToomas Soome     {
901c65ebfc7SToomas Soome         rv = close(intf->multicastSocket4);
902c65ebfc7SToomas Soome         assert(rv == 0);
903c65ebfc7SToomas Soome     }
9044b22b933Srs #if HAVE_IPV6
905c65ebfc7SToomas Soome     if (intf->multicastSocket6 != -1)
906c65ebfc7SToomas Soome     {
907c65ebfc7SToomas Soome         rv = close(intf->multicastSocket6);
908c65ebfc7SToomas Soome         assert(rv == 0);
909c65ebfc7SToomas Soome     }
9104b22b933Srs #endif
9115ffb0c9bSToomas Soome 
9125ffb0c9bSToomas Soome     // Move interface to the RecentInterfaces list for a minute
9135ffb0c9bSToomas Soome     intf->LastSeen = mDNSPlatformUTC();
9145ffb0c9bSToomas Soome     intf->coreIntf.next = &gRecentInterfaces->coreIntf;
9155ffb0c9bSToomas Soome     gRecentInterfaces = intf;
9165ffb0c9bSToomas Soome }
9174b22b933Srs 
9184b22b933Srs // Grab the first interface, deregister it, free it, and repeat until done.
ClearInterfaceList(mDNS * const m)9194b22b933Srs mDNSlocal void ClearInterfaceList(mDNS *const m)
9205ffb0c9bSToomas Soome {
9215ffb0c9bSToomas Soome     assert(m != NULL);
9225ffb0c9bSToomas Soome 
9235ffb0c9bSToomas Soome     while (m->HostInterfaces)
9245ffb0c9bSToomas Soome     {
9255ffb0c9bSToomas Soome         PosixNetworkInterface *intf = (PosixNetworkInterface*)(m->HostInterfaces);
926c65ebfc7SToomas Soome         mDNS_DeregisterInterface(m, &intf->coreIntf, NormalActivation);
9275ffb0c9bSToomas Soome         if (gMDNSPlatformPosixVerboseLevel > 0) fprintf(stderr, "Deregistered interface %s\n", intf->intfName);
9285ffb0c9bSToomas Soome         FreePosixNetworkInterface(intf);
9295ffb0c9bSToomas Soome     }
9305ffb0c9bSToomas Soome     num_registered_interfaces = 0;
9315ffb0c9bSToomas Soome     num_pkts_accepted = 0;
9325ffb0c9bSToomas Soome     num_pkts_rejected = 0;
9335ffb0c9bSToomas Soome }
9344b22b933Srs 
9354b22b933Srs // Sets up a send/receive socket.
9364b22b933Srs // If mDNSIPPort port is non-zero, then it's a multicast socket on the specified interface
9374b22b933Srs // 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)9384b22b933Srs mDNSlocal int SetupSocket(struct sockaddr *intfAddr, mDNSIPPort port, int interfaceIndex, int *sktPtr)
9395ffb0c9bSToomas Soome {
9405ffb0c9bSToomas Soome     int err = 0;
9415ffb0c9bSToomas Soome     static const int kOn = 1;
9425ffb0c9bSToomas Soome     static const int kIntTwoFiveFive = 255;
9435ffb0c9bSToomas Soome     static const unsigned char kByteTwoFiveFive = 255;
9445ffb0c9bSToomas Soome     const mDNSBool JoinMulticastGroup = (port.NotAnInteger != 0);
9455ffb0c9bSToomas Soome 
9465ffb0c9bSToomas Soome     (void) interfaceIndex;  // This parameter unused on plaforms that don't have IPv6
9475ffb0c9bSToomas Soome     assert(intfAddr != NULL);
9485ffb0c9bSToomas Soome     assert(sktPtr != NULL);
9495ffb0c9bSToomas Soome     assert(*sktPtr == -1);
9505ffb0c9bSToomas Soome 
9515ffb0c9bSToomas Soome     // Open the socket...
9525ffb0c9bSToomas Soome     if      (intfAddr->sa_family == AF_INET) *sktPtr = socket(PF_INET,  SOCK_DGRAM, IPPROTO_UDP);
9534b22b933Srs #if HAVE_IPV6
9545ffb0c9bSToomas Soome     else if (intfAddr->sa_family == AF_INET6) *sktPtr = socket(PF_INET6, SOCK_DGRAM, IPPROTO_UDP);
9554b22b933Srs #endif
9565ffb0c9bSToomas Soome     else return EINVAL;
9575ffb0c9bSToomas Soome 
9585ffb0c9bSToomas Soome     if (*sktPtr < 0) { err = errno; perror((intfAddr->sa_family == AF_INET) ? "socket AF_INET" : "socket AF_INET6"); }
9595ffb0c9bSToomas Soome 
9605ffb0c9bSToomas Soome     // ... with a shared UDP port, if it's for multicast receiving
9615ffb0c9bSToomas Soome     if (err == 0 && port.NotAnInteger)
9625ffb0c9bSToomas Soome     {
963472cd20dSToomas Soome         // <rdar://problem/20946253> Suggestions from Jonny Törnbom at Axis Communications
964cda73f64SToomas Soome         // We test for SO_REUSEADDR first, as suggested by Jonny Törnbom from Axis Communications
965cda73f64SToomas Soome         // Linux kernel versions 3.9 introduces support for socket option
966cda73f64SToomas Soome         // SO_REUSEPORT, however this is not implemented the same as on *BSD
967cda73f64SToomas Soome         // systems. Linux version implements a "port hijacking" prevention
968cda73f64SToomas Soome         // mechanism, limiting processes wanting to bind to an already existing
969cda73f64SToomas Soome         // addr:port to have the same effective UID as the first who bound it. What
970cda73f64SToomas Soome         // this meant for us was that the daemon ran as one user and when for
971cda73f64SToomas Soome         // instance mDNSClientPosix was executed by another user, it wasn't allowed
972cda73f64SToomas Soome         // to bind to the socket. Our suggestion was to switch the order in which
973cda73f64SToomas Soome         // SO_REUSEPORT and SO_REUSEADDR was tested so that SO_REUSEADDR stays on
974cda73f64SToomas Soome         // top and SO_REUSEPORT to be used only if SO_REUSEADDR doesn't exist.
975cda73f64SToomas Soome         #if defined(SO_REUSEADDR) && !defined(__MAC_OS_X_VERSION_MIN_REQUIRED)
9765ffb0c9bSToomas Soome         err = setsockopt(*sktPtr, SOL_SOCKET, SO_REUSEADDR, &kOn, sizeof(kOn));
977cda73f64SToomas Soome         #elif defined(SO_REUSEPORT)
978cda73f64SToomas Soome         err = setsockopt(*sktPtr, SOL_SOCKET, SO_REUSEPORT, &kOn, sizeof(kOn));
9795ffb0c9bSToomas Soome         #else
9805ffb0c9bSToomas Soome             #error This platform has no way to avoid address busy errors on multicast.
9815ffb0c9bSToomas Soome         #endif
9825ffb0c9bSToomas Soome         if (err < 0) { err = errno; perror("setsockopt - SO_REUSExxxx"); }
9835ffb0c9bSToomas Soome 
984472cd20dSToomas Soome #if TARGET_OS_MAC
9855ffb0c9bSToomas Soome         // Enable inbound packets on IFEF_AWDL interface.
9865ffb0c9bSToomas Soome         // Only done for multicast sockets, since we don't expect unicast socket operations
9875ffb0c9bSToomas Soome         // on the IFEF_AWDL interface. Operation is a no-op for other interface types.
988472cd20dSToomas Soome         #ifndef SO_RECV_ANYIF
989472cd20dSToomas Soome         #define SO_RECV_ANYIF   0x1104      /* unrestricted inbound processing */
990472cd20dSToomas Soome         #endif
9915ffb0c9bSToomas Soome         if (setsockopt(*sktPtr, SOL_SOCKET, SO_RECV_ANYIF, &kOn, sizeof(kOn)) < 0) perror("setsockopt - SO_RECV_ANYIF");
992472cd20dSToomas Soome #endif
9935ffb0c9bSToomas Soome     }
9945ffb0c9bSToomas Soome 
9955ffb0c9bSToomas Soome     // We want to receive destination addresses and interface identifiers.
9965ffb0c9bSToomas Soome     if (intfAddr->sa_family == AF_INET)
9975ffb0c9bSToomas Soome     {
9985ffb0c9bSToomas Soome         struct ip_mreq imr;
9995ffb0c9bSToomas Soome         struct sockaddr_in bindAddr;
10005ffb0c9bSToomas Soome         if (err == 0)
10015ffb0c9bSToomas Soome         {
10025ffb0c9bSToomas Soome             #if defined(IP_PKTINFO)                                 // Linux
10035ffb0c9bSToomas Soome             err = setsockopt(*sktPtr, IPPROTO_IP, IP_PKTINFO, &kOn, sizeof(kOn));
10045ffb0c9bSToomas Soome             if (err < 0) { err = errno; perror("setsockopt - IP_PKTINFO"); }
10055ffb0c9bSToomas Soome             #elif defined(IP_RECVDSTADDR) || defined(IP_RECVIF)     // BSD and Solaris
10065ffb0c9bSToomas Soome                 #if defined(IP_RECVDSTADDR)
10075ffb0c9bSToomas Soome             err = setsockopt(*sktPtr, IPPROTO_IP, IP_RECVDSTADDR, &kOn, sizeof(kOn));
10085ffb0c9bSToomas Soome             if (err < 0) { err = errno; perror("setsockopt - IP_RECVDSTADDR"); }
10095ffb0c9bSToomas Soome                 #endif
10105ffb0c9bSToomas Soome                 #if defined(IP_RECVIF)
10115ffb0c9bSToomas Soome             if (err == 0)
10125ffb0c9bSToomas Soome             {
10135ffb0c9bSToomas Soome                 err = setsockopt(*sktPtr, IPPROTO_IP, IP_RECVIF, &kOn, sizeof(kOn));
10145ffb0c9bSToomas Soome                 if (err < 0) { err = errno; perror("setsockopt - IP_RECVIF"); }
10155ffb0c9bSToomas Soome             }
10165ffb0c9bSToomas Soome                 #endif
10175ffb0c9bSToomas Soome             #else
10185ffb0c9bSToomas Soome                 #warning This platform has no way to get the destination interface information -- will only work for single-homed hosts
10195ffb0c9bSToomas Soome             #endif
10205ffb0c9bSToomas Soome         }
10215ffb0c9bSToomas Soome     #if defined(IP_RECVTTL)                                 // Linux
10225ffb0c9bSToomas Soome         if (err == 0)
10235ffb0c9bSToomas Soome         {
10245ffb0c9bSToomas Soome             setsockopt(*sktPtr, IPPROTO_IP, IP_RECVTTL, &kOn, sizeof(kOn));
10255ffb0c9bSToomas Soome             // We no longer depend on being able to get the received TTL, so don't worry if the option fails
10265ffb0c9bSToomas Soome         }
10275ffb0c9bSToomas Soome     #endif
10285ffb0c9bSToomas Soome 
10295ffb0c9bSToomas Soome         // Add multicast group membership on this interface
10305ffb0c9bSToomas Soome         if (err == 0 && JoinMulticastGroup)
10315ffb0c9bSToomas Soome         {
10325ffb0c9bSToomas Soome             imr.imr_multiaddr.s_addr = AllDNSLinkGroup_v4.ip.v4.NotAnInteger;
10335ffb0c9bSToomas Soome             imr.imr_interface        = ((struct sockaddr_in*)intfAddr)->sin_addr;
10345ffb0c9bSToomas Soome             err = setsockopt(*sktPtr, IPPROTO_IP, IP_ADD_MEMBERSHIP, &imr, sizeof(imr));
10355ffb0c9bSToomas Soome             if (err < 0) { err = errno; perror("setsockopt - IP_ADD_MEMBERSHIP"); }
10365ffb0c9bSToomas Soome         }
10375ffb0c9bSToomas Soome 
10385ffb0c9bSToomas Soome         // Specify outgoing interface too
10395ffb0c9bSToomas Soome         if (err == 0 && JoinMulticastGroup)
10405ffb0c9bSToomas Soome         {
10415ffb0c9bSToomas Soome             err = setsockopt(*sktPtr, IPPROTO_IP, IP_MULTICAST_IF, &((struct sockaddr_in*)intfAddr)->sin_addr, sizeof(struct in_addr));
10425ffb0c9bSToomas Soome             if (err < 0) { err = errno; perror("setsockopt - IP_MULTICAST_IF"); }
10435ffb0c9bSToomas Soome         }
10445ffb0c9bSToomas Soome 
10455ffb0c9bSToomas Soome         // Per the mDNS spec, send unicast packets with TTL 255
10465ffb0c9bSToomas Soome         if (err == 0)
10475ffb0c9bSToomas Soome         {
10485ffb0c9bSToomas Soome             err = setsockopt(*sktPtr, IPPROTO_IP, IP_TTL, &kIntTwoFiveFive, sizeof(kIntTwoFiveFive));
10495ffb0c9bSToomas Soome             if (err < 0) { err = errno; perror("setsockopt - IP_TTL"); }
10505ffb0c9bSToomas Soome         }
10515ffb0c9bSToomas Soome 
10525ffb0c9bSToomas Soome         // and multicast packets with TTL 255 too
10535ffb0c9bSToomas Soome         // There's some debate as to whether IP_MULTICAST_TTL is an int or a byte so we just try both.
10545ffb0c9bSToomas Soome         if (err == 0)
10555ffb0c9bSToomas Soome         {
10565ffb0c9bSToomas Soome             err = setsockopt(*sktPtr, IPPROTO_IP, IP_MULTICAST_TTL, &kByteTwoFiveFive, sizeof(kByteTwoFiveFive));
10575ffb0c9bSToomas Soome             if (err < 0 && errno == EINVAL)
10585ffb0c9bSToomas Soome                 err = setsockopt(*sktPtr, IPPROTO_IP, IP_MULTICAST_TTL, &kIntTwoFiveFive, sizeof(kIntTwoFiveFive));
10595ffb0c9bSToomas Soome             if (err < 0) { err = errno; perror("setsockopt - IP_MULTICAST_TTL"); }
10605ffb0c9bSToomas Soome         }
10615ffb0c9bSToomas Soome 
10625ffb0c9bSToomas Soome         // And start listening for packets
10635ffb0c9bSToomas Soome         if (err == 0)
10645ffb0c9bSToomas Soome         {
10655ffb0c9bSToomas Soome             bindAddr.sin_family      = AF_INET;
10665ffb0c9bSToomas Soome             bindAddr.sin_port        = port.NotAnInteger;
10675ffb0c9bSToomas Soome             bindAddr.sin_addr.s_addr = INADDR_ANY; // Want to receive multicasts AND unicasts on this socket
10685ffb0c9bSToomas Soome             err = bind(*sktPtr, (struct sockaddr *) &bindAddr, sizeof(bindAddr));
10695ffb0c9bSToomas Soome             if (err < 0) { err = errno; perror("bind"); fflush(stderr); }
10705ffb0c9bSToomas Soome         }
10715ffb0c9bSToomas Soome     }     // endif (intfAddr->sa_family == AF_INET)
10724b22b933Srs 
10734b22b933Srs #if HAVE_IPV6
10745ffb0c9bSToomas Soome     else if (intfAddr->sa_family == AF_INET6)
10755ffb0c9bSToomas Soome     {
10765ffb0c9bSToomas Soome         struct ipv6_mreq imr6;
10775ffb0c9bSToomas Soome         struct sockaddr_in6 bindAddr6;
10785ffb0c9bSToomas Soome     #if defined(IPV6_RECVPKTINFO) // Solaris
1079cda73f64SToomas Soome 	if (err == 0)
1080cda73f64SToomas Soome 	{
1081cda73f64SToomas Soome 	    err = setsockopt(*sktPtr, IPPROTO_IPV6, IPV6_RECVPKTINFO, &kOn, sizeof(kOn));
1082cda73f64SToomas Soome 	    if (err < 0) { err = errno; perror("setsockopt - IPV6_RECVPKTINFO"); }
1083cda73f64SToomas Soome 	}
10845ffb0c9bSToomas Soome     #elif defined(IPV6_PKTINFO)
10855ffb0c9bSToomas Soome         if (err == 0)
10865ffb0c9bSToomas Soome         {
10875ffb0c9bSToomas Soome             err = setsockopt(*sktPtr, IPPROTO_IPV6, IPV6_2292_PKTINFO, &kOn, sizeof(kOn));
10885ffb0c9bSToomas Soome             if (err < 0) { err = errno; perror("setsockopt - IPV6_PKTINFO"); }
10895ffb0c9bSToomas Soome         }
10905ffb0c9bSToomas Soome     #else
10915ffb0c9bSToomas Soome         #warning This platform has no way to get the destination interface information for IPv6 -- will only work for single-homed hosts
10925ffb0c9bSToomas Soome     #endif
10935ffb0c9bSToomas Soome     #if defined(IPV6_RECVHOPLIMIT)
10943b436d06SToomas Soome 	if (err == 0)
10953b436d06SToomas Soome 	{
10963b436d06SToomas Soome 	    err = setsockopt(*sktPtr, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &kOn, sizeof(kOn));
10973b436d06SToomas Soome 	    if (err < 0) { err = errno; perror("setsockopt - IPV6_RECVHOPLIMIT"); }
10983b436d06SToomas Soome 	}
10995ffb0c9bSToomas Soome     #elif defined(IPV6_HOPLIMIT)
11005ffb0c9bSToomas Soome         if (err == 0)
11015ffb0c9bSToomas Soome         {
11025ffb0c9bSToomas Soome             err = setsockopt(*sktPtr, IPPROTO_IPV6, IPV6_2292_HOPLIMIT, &kOn, sizeof(kOn));
11035ffb0c9bSToomas Soome             if (err < 0) { err = errno; perror("setsockopt - IPV6_HOPLIMIT"); }
11045ffb0c9bSToomas Soome         }
11055ffb0c9bSToomas Soome     #endif
11065ffb0c9bSToomas Soome 
11075ffb0c9bSToomas Soome         // Add multicast group membership on this interface
11085ffb0c9bSToomas Soome         if (err == 0 && JoinMulticastGroup)
11095ffb0c9bSToomas Soome         {
11105ffb0c9bSToomas Soome             imr6.ipv6mr_multiaddr       = *(const struct in6_addr*)&AllDNSLinkGroup_v6.ip.v6;
11115ffb0c9bSToomas Soome             imr6.ipv6mr_interface       = interfaceIndex;
11125ffb0c9bSToomas Soome             //LogMsg("Joining %.16a on %d", &imr6.ipv6mr_multiaddr, imr6.ipv6mr_interface);
11135ffb0c9bSToomas Soome             err = setsockopt(*sktPtr, IPPROTO_IPV6, IPV6_JOIN_GROUP, &imr6, sizeof(imr6));
11145ffb0c9bSToomas Soome             if (err < 0)
11155ffb0c9bSToomas Soome             {
11165ffb0c9bSToomas Soome                 err = errno;
11175ffb0c9bSToomas Soome                 verbosedebugf("IPV6_JOIN_GROUP %.16a on %d failed.\n", &imr6.ipv6mr_multiaddr, imr6.ipv6mr_interface);
11185ffb0c9bSToomas Soome                 perror("setsockopt - IPV6_JOIN_GROUP");
11195ffb0c9bSToomas Soome             }
11205ffb0c9bSToomas Soome         }
11215ffb0c9bSToomas Soome 
11225ffb0c9bSToomas Soome         // Specify outgoing interface too
11235ffb0c9bSToomas Soome         if (err == 0 && JoinMulticastGroup)
11245ffb0c9bSToomas Soome         {
11255ffb0c9bSToomas Soome             u_int multicast_if = interfaceIndex;
11265ffb0c9bSToomas Soome             err = setsockopt(*sktPtr, IPPROTO_IPV6, IPV6_MULTICAST_IF, &multicast_if, sizeof(multicast_if));
11275ffb0c9bSToomas Soome             if (err < 0) { err = errno; perror("setsockopt - IPV6_MULTICAST_IF"); }
11285ffb0c9bSToomas Soome         }
11295ffb0c9bSToomas Soome 
11305ffb0c9bSToomas Soome         // We want to receive only IPv6 packets on this socket.
11315ffb0c9bSToomas Soome         // Without this option, we may get IPv4 addresses as mapped addresses.
11325ffb0c9bSToomas Soome         if (err == 0)
11335ffb0c9bSToomas Soome         {
11345ffb0c9bSToomas Soome             err = setsockopt(*sktPtr, IPPROTO_IPV6, IPV6_V6ONLY, &kOn, sizeof(kOn));
11355ffb0c9bSToomas Soome             if (err < 0) { err = errno; perror("setsockopt - IPV6_V6ONLY"); }
11365ffb0c9bSToomas Soome         }
11375ffb0c9bSToomas Soome 
11385ffb0c9bSToomas Soome         // Per the mDNS spec, send unicast packets with TTL 255
11395ffb0c9bSToomas Soome         if (err == 0)
11405ffb0c9bSToomas Soome         {
11415ffb0c9bSToomas Soome             err = setsockopt(*sktPtr, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &kIntTwoFiveFive, sizeof(kIntTwoFiveFive));
11425ffb0c9bSToomas Soome             if (err < 0) { err = errno; perror("setsockopt - IPV6_UNICAST_HOPS"); }
11435ffb0c9bSToomas Soome         }
11445ffb0c9bSToomas Soome 
11455ffb0c9bSToomas Soome         // and multicast packets with TTL 255 too
11465ffb0c9bSToomas Soome         // There's some debate as to whether IPV6_MULTICAST_HOPS is an int or a byte so we just try both.
11475ffb0c9bSToomas Soome         if (err == 0)
11485ffb0c9bSToomas Soome         {
11495ffb0c9bSToomas Soome             err = setsockopt(*sktPtr, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &kByteTwoFiveFive, sizeof(kByteTwoFiveFive));
11505ffb0c9bSToomas Soome             if (err < 0 && errno == EINVAL)
11515ffb0c9bSToomas Soome                 err = setsockopt(*sktPtr, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &kIntTwoFiveFive, sizeof(kIntTwoFiveFive));
11525ffb0c9bSToomas Soome             if (err < 0) { err = errno; perror("setsockopt - IPV6_MULTICAST_HOPS"); }
11535ffb0c9bSToomas Soome         }
11545ffb0c9bSToomas Soome 
11555ffb0c9bSToomas Soome         // And start listening for packets
11565ffb0c9bSToomas Soome         if (err == 0)
11575ffb0c9bSToomas Soome         {
11585ffb0c9bSToomas Soome             mDNSPlatformMemZero(&bindAddr6, sizeof(bindAddr6));
11594b22b933Srs #ifndef NOT_HAVE_SA_LEN
11605ffb0c9bSToomas Soome             bindAddr6.sin6_len         = sizeof(bindAddr6);
11614b22b933Srs #endif
11625ffb0c9bSToomas Soome             bindAddr6.sin6_family      = AF_INET6;
11635ffb0c9bSToomas Soome             bindAddr6.sin6_port        = port.NotAnInteger;
11645ffb0c9bSToomas Soome             bindAddr6.sin6_flowinfo    = 0;
11655ffb0c9bSToomas Soome             bindAddr6.sin6_addr        = in6addr_any; // Want to receive multicasts AND unicasts on this socket
11665ffb0c9bSToomas Soome             bindAddr6.sin6_scope_id    = 0;
11675ffb0c9bSToomas Soome             err = bind(*sktPtr, (struct sockaddr *) &bindAddr6, sizeof(bindAddr6));
11685ffb0c9bSToomas Soome             if (err < 0) { err = errno; perror("bind"); fflush(stderr); }
11695ffb0c9bSToomas Soome         }
11705ffb0c9bSToomas Soome     }     // endif (intfAddr->sa_family == AF_INET6)
11714b22b933Srs #endif
11724b22b933Srs 
11735ffb0c9bSToomas Soome     // Set the socket to non-blocking.
11745ffb0c9bSToomas Soome     if (err == 0)
11755ffb0c9bSToomas Soome     {
11765ffb0c9bSToomas Soome         err = fcntl(*sktPtr, F_GETFL, 0);
11775ffb0c9bSToomas Soome         if (err < 0) err = errno;
11785ffb0c9bSToomas Soome         else
11795ffb0c9bSToomas Soome         {
11805ffb0c9bSToomas Soome             err = fcntl(*sktPtr, F_SETFL, err | O_NONBLOCK);
11815ffb0c9bSToomas Soome             if (err < 0) err = errno;
11825ffb0c9bSToomas Soome         }
11835ffb0c9bSToomas Soome     }
11845ffb0c9bSToomas Soome 
11855ffb0c9bSToomas Soome     // Clean up
1186c65ebfc7SToomas Soome     if (err != 0 && *sktPtr != -1)
1187c65ebfc7SToomas Soome     {
1188c65ebfc7SToomas Soome         int rv;
1189c65ebfc7SToomas Soome         rv = close(*sktPtr);
1190c65ebfc7SToomas Soome         assert(rv == 0);
1191c65ebfc7SToomas Soome         *sktPtr = -1;
1192c65ebfc7SToomas Soome     }
11935ffb0c9bSToomas Soome     assert((err == 0) == (*sktPtr != -1));
11945ffb0c9bSToomas Soome     return err;
11955ffb0c9bSToomas Soome }
11964b22b933Srs 
11974b22b933Srs // Creates a PosixNetworkInterface for the interface whose IP address is
11984b22b933Srs // 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)11994b22b933Srs mDNSlocal int SetupOneInterface(mDNS *const m, struct sockaddr *intfAddr, struct sockaddr *intfMask, const char *intfName, int intfIndex)
12005ffb0c9bSToomas Soome {
12015ffb0c9bSToomas Soome     int err = 0;
12025ffb0c9bSToomas Soome     PosixNetworkInterface *intf;
12035ffb0c9bSToomas Soome     PosixNetworkInterface *alias = NULL;
12045ffb0c9bSToomas Soome 
12055ffb0c9bSToomas Soome     assert(m != NULL);
12065ffb0c9bSToomas Soome     assert(intfAddr != NULL);
12075ffb0c9bSToomas Soome     assert(intfName != NULL);
12085ffb0c9bSToomas Soome     assert(intfMask != NULL);
12095ffb0c9bSToomas Soome 
12105ffb0c9bSToomas Soome     // Allocate the interface structure itself.
1211cda73f64SToomas Soome     intf = (PosixNetworkInterface*)calloc(1, sizeof(*intf));
12125ffb0c9bSToomas Soome     if (intf == NULL) { assert(0); err = ENOMEM; }
12135ffb0c9bSToomas Soome 
12145ffb0c9bSToomas Soome     // And make a copy of the intfName.
12155ffb0c9bSToomas Soome     if (err == 0)
12165ffb0c9bSToomas Soome     {
1217472cd20dSToomas Soome #ifdef LINUX
1218472cd20dSToomas Soome         char *s;
1219472cd20dSToomas Soome         int len;
1220472cd20dSToomas Soome         s = strchr(intfName, ':');
1221472cd20dSToomas Soome         if (s != NULL)
1222472cd20dSToomas Soome         {
1223472cd20dSToomas Soome             len = (s - intfName) + 1;
1224472cd20dSToomas Soome         }
1225472cd20dSToomas Soome         else
1226472cd20dSToomas Soome         {
1227472cd20dSToomas Soome             len = strlen(intfName) + 1;
1228472cd20dSToomas Soome         }
1229472cd20dSToomas Soome         intf->intfName = malloc(len);
1230472cd20dSToomas Soome         if (intf->intfName == NULL) { assert(0); err = ENOMEM; }
1231472cd20dSToomas Soome         memcpy(intf->intfName, intfName, len - 1);
1232472cd20dSToomas Soome         intfName[len - 1] = 0;
1233472cd20dSToomas Soome #else
12345ffb0c9bSToomas Soome         intf->intfName = strdup(intfName);
12355ffb0c9bSToomas Soome         if (intf->intfName == NULL) { assert(0); err = ENOMEM; }
1236472cd20dSToomas Soome #endif
12375ffb0c9bSToomas Soome     }
12385ffb0c9bSToomas Soome 
12395ffb0c9bSToomas Soome     if (err == 0)
12405ffb0c9bSToomas Soome     {
12415ffb0c9bSToomas Soome         // Set up the fields required by the mDNS core.
12425ffb0c9bSToomas Soome         SockAddrTomDNSAddr(intfAddr, &intf->coreIntf.ip, NULL);
12435ffb0c9bSToomas Soome         SockAddrTomDNSAddr(intfMask, &intf->coreIntf.mask, NULL);
12445ffb0c9bSToomas Soome 
12455ffb0c9bSToomas Soome         //LogMsg("SetupOneInterface: %#a %#a",  &intf->coreIntf.ip,  &intf->coreIntf.mask);
12465ffb0c9bSToomas Soome         strncpy(intf->coreIntf.ifname, intfName, sizeof(intf->coreIntf.ifname));
12475ffb0c9bSToomas Soome         intf->coreIntf.ifname[sizeof(intf->coreIntf.ifname)-1] = 0;
1248472cd20dSToomas Soome 
12495ffb0c9bSToomas Soome         intf->coreIntf.Advertise = m->AdvertiseLocalAddresses;
12505ffb0c9bSToomas Soome         intf->coreIntf.McastTxRx = mDNStrue;
12515ffb0c9bSToomas Soome 
12525ffb0c9bSToomas Soome         // Set up the extra fields in PosixNetworkInterface.
12535ffb0c9bSToomas Soome         assert(intf->intfName != NULL);         // intf->intfName already set up above
12545ffb0c9bSToomas Soome         intf->index                = intfIndex;
12555ffb0c9bSToomas Soome         intf->multicastSocket4     = -1;
12564b22b933Srs #if HAVE_IPV6
12575ffb0c9bSToomas Soome         intf->multicastSocket6     = -1;
12584b22b933Srs #endif
12595ffb0c9bSToomas Soome         alias                      = SearchForInterfaceByName(m, intf->intfName);
12605ffb0c9bSToomas Soome         if (alias == NULL) alias   = intf;
12615ffb0c9bSToomas Soome         intf->coreIntf.InterfaceID = (mDNSInterfaceID)alias;
12625ffb0c9bSToomas Soome 
12635ffb0c9bSToomas Soome         if (alias != intf)
12645ffb0c9bSToomas Soome             debugf("SetupOneInterface: %s %#a is an alias of %#a", intfName, &intf->coreIntf.ip, &alias->coreIntf.ip);
12655ffb0c9bSToomas Soome     }
12665ffb0c9bSToomas Soome 
12675ffb0c9bSToomas Soome     // Set up the multicast socket
12685ffb0c9bSToomas Soome     if (err == 0)
12695ffb0c9bSToomas Soome     {
12705ffb0c9bSToomas Soome         if (alias->multicastSocket4 == -1 && intfAddr->sa_family == AF_INET)
12715ffb0c9bSToomas Soome             err = SetupSocket(intfAddr, MulticastDNSPort, intf->index, &alias->multicastSocket4);
12724b22b933Srs #if HAVE_IPV6
12735ffb0c9bSToomas Soome         else if (alias->multicastSocket6 == -1 && intfAddr->sa_family == AF_INET6)
12745ffb0c9bSToomas Soome             err = SetupSocket(intfAddr, MulticastDNSPort, intf->index, &alias->multicastSocket6);
12754b22b933Srs #endif
12765ffb0c9bSToomas Soome     }
12775ffb0c9bSToomas Soome 
12785ffb0c9bSToomas Soome     // If interface is a direct link, address record will be marked as kDNSRecordTypeKnownUnique
12795ffb0c9bSToomas Soome     // and skip the probe phase of the probe/announce packet sequence.
12805ffb0c9bSToomas Soome     intf->coreIntf.DirectLink = mDNSfalse;
12815ffb0c9bSToomas Soome #ifdef DIRECTLINK_INTERFACE_NAME
1282c65ebfc7SToomas Soome     if (strcmp(intfName, STRINGIFY(DIRECTLINK_INTERFACE_NAME)) == 0)
1283c65ebfc7SToomas Soome         intf->coreIntf.DirectLink = mDNStrue;
12845ffb0c9bSToomas Soome #endif
1285cda73f64SToomas Soome     intf->coreIntf.SupportsUnicastMDNSResponse = mDNStrue;
12865ffb0c9bSToomas Soome 
12875ffb0c9bSToomas Soome     // The interface is all ready to go, let's register it with the mDNS core.
12885ffb0c9bSToomas Soome     if (err == 0)
1289c65ebfc7SToomas Soome         err = mDNS_RegisterInterface(m, &intf->coreIntf, NormalActivation);
12905ffb0c9bSToomas Soome 
12915ffb0c9bSToomas Soome     // Clean up.
12925ffb0c9bSToomas Soome     if (err == 0)
12935ffb0c9bSToomas Soome     {
12945ffb0c9bSToomas Soome         num_registered_interfaces++;
12955ffb0c9bSToomas Soome         debugf("SetupOneInterface: %s %#a Registered", intf->intfName, &intf->coreIntf.ip);
12965ffb0c9bSToomas Soome         if (gMDNSPlatformPosixVerboseLevel > 0)
12975ffb0c9bSToomas Soome             fprintf(stderr, "Registered interface %s\n", intf->intfName);
12985ffb0c9bSToomas Soome     }
12995ffb0c9bSToomas Soome     else
13005ffb0c9bSToomas Soome     {
13015ffb0c9bSToomas Soome         // Use intfName instead of intf->intfName in the next line to avoid dereferencing NULL.
13025ffb0c9bSToomas Soome         debugf("SetupOneInterface: %s %#a failed to register %d", intfName, &intf->coreIntf.ip, err);
13035ffb0c9bSToomas Soome         if (intf) { FreePosixNetworkInterface(intf); intf = NULL; }
13045ffb0c9bSToomas Soome     }
13055ffb0c9bSToomas Soome 
13065ffb0c9bSToomas Soome     assert((err == 0) == (intf != NULL));
13075ffb0c9bSToomas Soome 
13085ffb0c9bSToomas Soome     return err;
13095ffb0c9bSToomas Soome }
13104b22b933Srs 
13114b22b933Srs // Call get_ifi_info() to obtain a list of active interfaces and call SetupOneInterface() on each one.
SetupInterfaceList(mDNS * const m)13124b22b933Srs mDNSlocal int SetupInterfaceList(mDNS *const m)
13135ffb0c9bSToomas Soome {
13145ffb0c9bSToomas Soome     mDNSBool foundav4       = mDNSfalse;
13155ffb0c9bSToomas Soome     int err            = 0;
1316472cd20dSToomas Soome     struct ifaddrs *intfList;
1317472cd20dSToomas Soome     struct ifaddrs *firstLoopback = NULL;
1318472cd20dSToomas Soome     int firstLoopbackIndex = 0;
13194b22b933Srs 
13205ffb0c9bSToomas Soome     assert(m != NULL);
13215ffb0c9bSToomas Soome     debugf("SetupInterfaceList");
13224b22b933Srs 
1323472cd20dSToomas Soome     if (getifaddrs(&intfList) < 0)
13245ffb0c9bSToomas Soome     {
1325472cd20dSToomas Soome         err = errno;
13265ffb0c9bSToomas Soome     }
1327472cd20dSToomas Soome     if (intfList == NULL) err = ENOENT;
13284b22b933Srs 
13295ffb0c9bSToomas Soome     if (err == 0)
13305ffb0c9bSToomas Soome     {
1331472cd20dSToomas Soome         struct ifaddrs *i = intfList;
13325ffb0c9bSToomas Soome         while (i)
13335ffb0c9bSToomas Soome         {
1334472cd20dSToomas Soome             if (     i->ifa_addr != NULL &&
1335472cd20dSToomas Soome                      ((i->ifa_addr->sa_family == AF_INET)
13364b22b933Srs #if HAVE_IPV6
1337472cd20dSToomas Soome                       || (i->ifa_addr->sa_family == AF_INET6)
13384b22b933Srs #endif
1339472cd20dSToomas Soome                       ) &&  (i->ifa_flags & IFF_UP) && !(i->ifa_flags & IFF_POINTOPOINT))
13405ffb0c9bSToomas Soome             {
1341472cd20dSToomas Soome                 int ifIndex = if_nametoindex(i->ifa_name);
1342472cd20dSToomas Soome                 if (ifIndex == 0)
1343472cd20dSToomas Soome                 {
1344*dc5774e5SHans Rosenfeld                     i = i->ifa_next;
1345472cd20dSToomas Soome                     continue;
1346472cd20dSToomas Soome                 }
1347472cd20dSToomas Soome                 if (i->ifa_flags & IFF_LOOPBACK)
13485ffb0c9bSToomas Soome                 {
13495ffb0c9bSToomas Soome                     if (firstLoopback == NULL)
1350472cd20dSToomas Soome                     {
13515ffb0c9bSToomas Soome                         firstLoopback = i;
1352472cd20dSToomas Soome                         firstLoopbackIndex = ifIndex;
1353472cd20dSToomas Soome                     }
13545ffb0c9bSToomas Soome                 }
13555ffb0c9bSToomas Soome                 else
13565ffb0c9bSToomas Soome                 {
1357472cd20dSToomas Soome                     if (SetupOneInterface(m, i->ifa_addr, i->ifa_netmask, i->ifa_name, ifIndex) == 0)
1358472cd20dSToomas Soome                     {
1359472cd20dSToomas Soome                         if (i->ifa_addr->sa_family == AF_INET)
1360472cd20dSToomas Soome                         {
13615ffb0c9bSToomas Soome                             foundav4 = mDNStrue;
1362472cd20dSToomas Soome                         }
1363472cd20dSToomas Soome                     }
13645ffb0c9bSToomas Soome                 }
13655ffb0c9bSToomas Soome             }
1366472cd20dSToomas Soome             i = i->ifa_next;
13675ffb0c9bSToomas Soome         }
13685ffb0c9bSToomas Soome 
13695ffb0c9bSToomas Soome         // If we found no normal interfaces but we did find a loopback interface, register the
13705ffb0c9bSToomas Soome         // loopback interface.  This allows self-discovery if no interfaces are configured.
13715ffb0c9bSToomas Soome         // Temporary workaround: Multicast loopback on IPv6 interfaces appears not to work.
13725ffb0c9bSToomas Soome         // In the interim, we skip loopback interface only if we found at least one v4 interface to use
13735ffb0c9bSToomas Soome         // if ((m->HostInterfaces == NULL) && (firstLoopback != NULL))
13745ffb0c9bSToomas Soome         if (!foundav4 && firstLoopback)
1375472cd20dSToomas Soome         {
1376472cd20dSToomas Soome             (void)SetupOneInterface(m, firstLoopback->ifa_addr, firstLoopback->ifa_netmask, firstLoopback->ifa_name,
1377472cd20dSToomas Soome                                     firstLoopbackIndex);
1378472cd20dSToomas Soome         }
13795ffb0c9bSToomas Soome     }
13805ffb0c9bSToomas Soome 
13815ffb0c9bSToomas Soome     // Clean up.
1382472cd20dSToomas Soome     if (intfList != NULL) freeifaddrs(intfList);
13835ffb0c9bSToomas Soome 
13845ffb0c9bSToomas Soome     // Clean up any interfaces that have been hanging around on the RecentInterfaces list for more than a minute
13855ffb0c9bSToomas Soome     PosixNetworkInterface **ri = &gRecentInterfaces;
13865ffb0c9bSToomas Soome     const mDNSs32 utc = mDNSPlatformUTC();
13875ffb0c9bSToomas Soome     while (*ri)
13885ffb0c9bSToomas Soome     {
13895ffb0c9bSToomas Soome         PosixNetworkInterface *pi = *ri;
13905ffb0c9bSToomas Soome         if (utc - pi->LastSeen < 60) ri = (PosixNetworkInterface **)&pi->coreIntf.next;
13915ffb0c9bSToomas Soome         else { *ri = (PosixNetworkInterface *)pi->coreIntf.next; free(pi); }
13925ffb0c9bSToomas Soome     }
13935ffb0c9bSToomas Soome 
13945ffb0c9bSToomas Soome     return err;
13955ffb0c9bSToomas Soome }
13964b22b933Srs 
13974b22b933Srs #if USES_NETLINK
13984b22b933Srs 
13994b22b933Srs // See <http://www.faqs.org/rfcs/rfc3549.html> for a description of NetLink
14004b22b933Srs 
14014b22b933Srs // Open a socket that will receive interface change notifications
OpenIfNotifySocket(int * pFD)14025ffb0c9bSToomas Soome mDNSlocal mStatus OpenIfNotifySocket(int *pFD)
14035ffb0c9bSToomas Soome {
14045ffb0c9bSToomas Soome     mStatus err = mStatus_NoError;
14055ffb0c9bSToomas Soome     struct sockaddr_nl snl;
14065ffb0c9bSToomas Soome     int sock;
14075ffb0c9bSToomas Soome     int ret;
14085ffb0c9bSToomas Soome 
14095ffb0c9bSToomas Soome     sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
14105ffb0c9bSToomas Soome     if (sock < 0)
14115ffb0c9bSToomas Soome         return errno;
14125ffb0c9bSToomas Soome 
14135ffb0c9bSToomas Soome     // Configure read to be non-blocking because inbound msg size is not known in advance
14145ffb0c9bSToomas Soome     (void) fcntl(sock, F_SETFL, O_NONBLOCK);
14155ffb0c9bSToomas Soome 
14165ffb0c9bSToomas Soome     /* Subscribe the socket to Link & IP addr notifications. */
14175ffb0c9bSToomas Soome     mDNSPlatformMemZero(&snl, sizeof snl);
14185ffb0c9bSToomas Soome     snl.nl_family = AF_NETLINK;
14195ffb0c9bSToomas Soome     snl.nl_groups = RTMGRP_LINK | RTMGRP_IPV4_IFADDR;
14205ffb0c9bSToomas Soome     ret = bind(sock, (struct sockaddr *) &snl, sizeof snl);
14215ffb0c9bSToomas Soome     if (0 == ret)
14225ffb0c9bSToomas Soome         *pFD = sock;
14235ffb0c9bSToomas Soome     else
14245ffb0c9bSToomas Soome         err = errno;
14255ffb0c9bSToomas Soome 
14265ffb0c9bSToomas Soome     return err;
14275ffb0c9bSToomas Soome }
14284b22b933Srs 
14294b22b933Srs #if MDNS_DEBUGMSGS
PrintNetLinkMsg(const struct nlmsghdr * pNLMsg)14305ffb0c9bSToomas Soome mDNSlocal void      PrintNetLinkMsg(const struct nlmsghdr *pNLMsg)
14315ffb0c9bSToomas Soome {
14325ffb0c9bSToomas Soome     const char *kNLMsgTypes[] = { "", "NLMSG_NOOP", "NLMSG_ERROR", "NLMSG_DONE", "NLMSG_OVERRUN" };
14335ffb0c9bSToomas Soome     const char *kNLRtMsgTypes[] = { "RTM_NEWLINK", "RTM_DELLINK", "RTM_GETLINK", "RTM_NEWADDR", "RTM_DELADDR", "RTM_GETADDR" };
14345ffb0c9bSToomas Soome 
14355ffb0c9bSToomas Soome     printf("nlmsghdr len=%d, type=%s, flags=0x%x\n", pNLMsg->nlmsg_len,
14365ffb0c9bSToomas Soome            pNLMsg->nlmsg_type < RTM_BASE ? kNLMsgTypes[pNLMsg->nlmsg_type] : kNLRtMsgTypes[pNLMsg->nlmsg_type - RTM_BASE],
14375ffb0c9bSToomas Soome            pNLMsg->nlmsg_flags);
14385ffb0c9bSToomas Soome 
14395ffb0c9bSToomas Soome     if (RTM_NEWLINK <= pNLMsg->nlmsg_type && pNLMsg->nlmsg_type <= RTM_GETLINK)
14405ffb0c9bSToomas Soome     {
14415ffb0c9bSToomas Soome         struct ifinfomsg    *pIfInfo = (struct ifinfomsg*) NLMSG_DATA(pNLMsg);
14425ffb0c9bSToomas Soome         printf("ifinfomsg family=%d, type=%d, index=%d, flags=0x%x, change=0x%x\n", pIfInfo->ifi_family,
14435ffb0c9bSToomas Soome                pIfInfo->ifi_type, pIfInfo->ifi_index, pIfInfo->ifi_flags, pIfInfo->ifi_change);
14445ffb0c9bSToomas Soome 
14455ffb0c9bSToomas Soome     }
14465ffb0c9bSToomas Soome     else if (RTM_NEWADDR <= pNLMsg->nlmsg_type && pNLMsg->nlmsg_type <= RTM_GETADDR)
14475ffb0c9bSToomas Soome     {
14485ffb0c9bSToomas Soome         struct ifaddrmsg    *pIfAddr = (struct ifaddrmsg*) NLMSG_DATA(pNLMsg);
14495ffb0c9bSToomas Soome         printf("ifaddrmsg family=%d, index=%d, flags=0x%x\n", pIfAddr->ifa_family,
14505ffb0c9bSToomas Soome                pIfAddr->ifa_index, pIfAddr->ifa_flags);
14515ffb0c9bSToomas Soome     }
14525ffb0c9bSToomas Soome     printf("\n");
14535ffb0c9bSToomas Soome }
14544b22b933Srs #endif
14554b22b933Srs 
ProcessRoutingNotification(int sd)14565ffb0c9bSToomas Soome mDNSlocal mDNSu32       ProcessRoutingNotification(int sd)
14574b22b933Srs // Read through the messages on sd and if any indicate that any interface records should
14584b22b933Srs // be torn down and rebuilt, return affected indices as a bitmask. Otherwise return 0.
14595ffb0c9bSToomas Soome {
14605ffb0c9bSToomas Soome     ssize_t readCount;
14615ffb0c9bSToomas Soome     char buff[4096];
14625ffb0c9bSToomas Soome     struct nlmsghdr         *pNLMsg = (struct nlmsghdr*) buff;
14635ffb0c9bSToomas Soome     mDNSu32 result = 0;
14645ffb0c9bSToomas Soome 
14655ffb0c9bSToomas Soome     // The structure here is more complex than it really ought to be because,
14665ffb0c9bSToomas Soome     // unfortunately, there's no good way to size a buffer in advance large
14675ffb0c9bSToomas Soome     // enough to hold all pending data and so avoid message fragmentation.
14685ffb0c9bSToomas Soome     // (Note that FIONREAD is not supported on AF_NETLINK.)
14695ffb0c9bSToomas Soome 
14705ffb0c9bSToomas Soome     readCount = read(sd, buff, sizeof buff);
14715ffb0c9bSToomas Soome     while (1)
14725ffb0c9bSToomas Soome     {
14735ffb0c9bSToomas Soome         // Make sure we've got an entire nlmsghdr in the buffer, and payload, too.
14745ffb0c9bSToomas Soome         // If not, discard already-processed messages in buffer and read more data.
14755ffb0c9bSToomas Soome         if (((char*) &pNLMsg[1] > (buff + readCount)) ||    // i.e. *pNLMsg extends off end of buffer
14765ffb0c9bSToomas Soome             ((char*) pNLMsg + pNLMsg->nlmsg_len > (buff + readCount)))
14775ffb0c9bSToomas Soome         {
14785ffb0c9bSToomas Soome             if (buff < (char*) pNLMsg)      // we have space to shuffle
14795ffb0c9bSToomas Soome             {
14805ffb0c9bSToomas Soome                 // discard processed data
14815ffb0c9bSToomas Soome                 readCount -= ((char*) pNLMsg - buff);
14825ffb0c9bSToomas Soome                 memmove(buff, pNLMsg, readCount);
14835ffb0c9bSToomas Soome                 pNLMsg = (struct nlmsghdr*) buff;
14845ffb0c9bSToomas Soome 
14855ffb0c9bSToomas Soome                 // read more data
14865ffb0c9bSToomas Soome                 readCount += read(sd, buff + readCount, sizeof buff - readCount);
14875ffb0c9bSToomas Soome                 continue;                   // spin around and revalidate with new readCount
14885ffb0c9bSToomas Soome             }
14895ffb0c9bSToomas Soome             else
14905ffb0c9bSToomas Soome                 break;  // Otherwise message does not fit in buffer
14915ffb0c9bSToomas Soome         }
14924b22b933Srs 
14934b22b933Srs #if MDNS_DEBUGMSGS
14945ffb0c9bSToomas Soome         PrintNetLinkMsg(pNLMsg);
14954b22b933Srs #endif
14964b22b933Srs 
14975ffb0c9bSToomas Soome         // Process the NetLink message
14985ffb0c9bSToomas Soome         if (pNLMsg->nlmsg_type == RTM_GETLINK || pNLMsg->nlmsg_type == RTM_NEWLINK)
14995ffb0c9bSToomas Soome             result |= 1 << ((struct ifinfomsg*) NLMSG_DATA(pNLMsg))->ifi_index;
15005ffb0c9bSToomas Soome         else if (pNLMsg->nlmsg_type == RTM_DELADDR || pNLMsg->nlmsg_type == RTM_NEWADDR)
15015ffb0c9bSToomas Soome             result |= 1 << ((struct ifaddrmsg*) NLMSG_DATA(pNLMsg))->ifa_index;
15025ffb0c9bSToomas Soome 
15035ffb0c9bSToomas Soome         // Advance pNLMsg to the next message in the buffer
15045ffb0c9bSToomas Soome         if ((pNLMsg->nlmsg_flags & NLM_F_MULTI) != 0 && pNLMsg->nlmsg_type != NLMSG_DONE)
15055ffb0c9bSToomas Soome         {
15065ffb0c9bSToomas Soome             ssize_t len = readCount - ((char*)pNLMsg - buff);
15075ffb0c9bSToomas Soome             pNLMsg = NLMSG_NEXT(pNLMsg, len);
15085ffb0c9bSToomas Soome         }
15095ffb0c9bSToomas Soome         else
15105ffb0c9bSToomas Soome             break;  // all done!
15115ffb0c9bSToomas Soome     }
15125ffb0c9bSToomas Soome 
15135ffb0c9bSToomas Soome     return result;
15145ffb0c9bSToomas Soome }
15154b22b933Srs 
15164b22b933Srs #else // USES_NETLINK
15174b22b933Srs 
15184b22b933Srs // Open a socket that will receive interface change notifications
OpenIfNotifySocket(int * pFD)15195ffb0c9bSToomas Soome mDNSlocal mStatus OpenIfNotifySocket(int *pFD)
15205ffb0c9bSToomas Soome {
15215ffb0c9bSToomas Soome     *pFD = socket(AF_ROUTE, SOCK_RAW, 0);
15224b22b933Srs 
15235ffb0c9bSToomas Soome     if (*pFD < 0)
15245ffb0c9bSToomas Soome         return mStatus_UnknownErr;
15254b22b933Srs 
15265ffb0c9bSToomas Soome     // Configure read to be non-blocking because inbound msg size is not known in advance
15275ffb0c9bSToomas Soome     (void) fcntl(*pFD, F_SETFL, O_NONBLOCK);
15284b22b933Srs 
15295ffb0c9bSToomas Soome     return mStatus_NoError;
15305ffb0c9bSToomas Soome }
15314b22b933Srs 
15324b22b933Srs #if MDNS_DEBUGMSGS
PrintRoutingSocketMsg(const struct ifa_msghdr * pRSMsg)15335ffb0c9bSToomas Soome mDNSlocal void      PrintRoutingSocketMsg(const struct ifa_msghdr *pRSMsg)
15345ffb0c9bSToomas Soome {
15355ffb0c9bSToomas Soome     const char *kRSMsgTypes[] = { "", "RTM_ADD", "RTM_DELETE", "RTM_CHANGE", "RTM_GET", "RTM_LOSING",
15365ffb0c9bSToomas Soome                                   "RTM_REDIRECT", "RTM_MISS", "RTM_LOCK", "RTM_OLDADD", "RTM_OLDDEL", "RTM_RESOLVE",
15375ffb0c9bSToomas Soome                                   "RTM_NEWADDR", "RTM_DELADDR", "RTM_IFINFO", "RTM_NEWMADDR", "RTM_DELMADDR" };
15384b22b933Srs 
15395ffb0c9bSToomas Soome     int index = pRSMsg->ifam_type == RTM_IFINFO ? ((struct if_msghdr*) pRSMsg)->ifm_index : pRSMsg->ifam_index;
15404b22b933Srs 
15415ffb0c9bSToomas Soome     printf("ifa_msghdr len=%d, type=%s, index=%d\n", pRSMsg->ifam_msglen, kRSMsgTypes[pRSMsg->ifam_type], index);
15425ffb0c9bSToomas Soome }
15434b22b933Srs #endif
15444b22b933Srs 
ProcessRoutingNotification(int sd)15455ffb0c9bSToomas Soome mDNSlocal mDNSu32       ProcessRoutingNotification(int sd)
15464b22b933Srs // Read through the messages on sd and if any indicate that any interface records should
15474b22b933Srs // be torn down and rebuilt, return affected indices as a bitmask. Otherwise return 0.
15485ffb0c9bSToomas Soome {
15495ffb0c9bSToomas Soome     ssize_t readCount;
15505ffb0c9bSToomas Soome     char buff[4096];
15515ffb0c9bSToomas Soome     struct ifa_msghdr       *pRSMsg = (struct ifa_msghdr*) buff;
15525ffb0c9bSToomas Soome     mDNSu32 result = 0;
15534b22b933Srs 
15545ffb0c9bSToomas Soome     readCount = read(sd, buff, sizeof buff);
15555ffb0c9bSToomas Soome     if (readCount < (ssize_t) sizeof(struct ifa_msghdr))
15565ffb0c9bSToomas Soome         return mStatus_UnsupportedErr;      // cannot decipher message
15574b22b933Srs 
15584b22b933Srs #if MDNS_DEBUGMSGS
15595ffb0c9bSToomas Soome     PrintRoutingSocketMsg(pRSMsg);
15604b22b933Srs #endif
15614b22b933Srs 
15625ffb0c9bSToomas Soome     // Process the message
15635ffb0c9bSToomas Soome     switch (pRSMsg->ifam_type)
15645ffb0c9bSToomas Soome     {
15655ffb0c9bSToomas Soome     case RTM_NEWADDR:
15665ffb0c9bSToomas Soome     case RTM_DELADDR:
15675ffb0c9bSToomas Soome     case RTM_IFINFO:
15685ffb0c9bSToomas Soome     /*
15695ffb0c9bSToomas Soome      * ADD & DELETE are happening when IPv6 announces are changing,
15705ffb0c9bSToomas Soome      * and for some reason it will stop mdnsd to announce IPv6
15715ffb0c9bSToomas Soome      * addresses. So we force mdnsd to check interfaces.
15725ffb0c9bSToomas Soome      */
15735ffb0c9bSToomas Soome     case RTM_ADD:
15745ffb0c9bSToomas Soome     case RTM_DELETE:
15753b436d06SToomas Soome         if (pRSMsg->ifam_type == RTM_IFINFO)
15763b436d06SToomas Soome             result |= 1 << ((struct if_msghdr*) pRSMsg)->ifm_index;
15773b436d06SToomas Soome         else
15783b436d06SToomas Soome             result |= 1 << pRSMsg->ifam_index;
1579cda73f64SToomas Soome     break;
15805ffb0c9bSToomas Soome     }
15815ffb0c9bSToomas Soome 
15825ffb0c9bSToomas Soome     return result;
15835ffb0c9bSToomas Soome }
15844b22b933Srs 
15854b22b933Srs #endif // USES_NETLINK
15864b22b933Srs 
15874b22b933Srs // Called when data appears on interface change notification socket
InterfaceChangeCallback(int fd,void * context)1588472cd20dSToomas Soome mDNSlocal void InterfaceChangeCallback(int fd, void *context)
15895ffb0c9bSToomas Soome {
15905ffb0c9bSToomas Soome     IfChangeRec     *pChgRec = (IfChangeRec*) context;
15915ffb0c9bSToomas Soome     fd_set readFDs;
15925ffb0c9bSToomas Soome     mDNSu32 changedInterfaces = 0;
15935ffb0c9bSToomas Soome     struct timeval zeroTimeout = { 0, 0 };
15945ffb0c9bSToomas Soome 
15955ffb0c9bSToomas Soome     (void)fd; // Unused
15965ffb0c9bSToomas Soome 
15975ffb0c9bSToomas Soome     FD_ZERO(&readFDs);
15985ffb0c9bSToomas Soome     FD_SET(pChgRec->NotifySD, &readFDs);
15995ffb0c9bSToomas Soome 
16005ffb0c9bSToomas Soome     do
16015ffb0c9bSToomas Soome     {
16025ffb0c9bSToomas Soome         changedInterfaces |= ProcessRoutingNotification(pChgRec->NotifySD);
16035ffb0c9bSToomas Soome     }
16045ffb0c9bSToomas Soome     while (0 < select(pChgRec->NotifySD + 1, &readFDs, (fd_set*) NULL, (fd_set*) NULL, &zeroTimeout));
16055ffb0c9bSToomas Soome 
16065ffb0c9bSToomas Soome     // Currently we rebuild the entire interface list whenever any interface change is
16075ffb0c9bSToomas Soome     // detected. If this ever proves to be a performance issue in a multi-homed
16085ffb0c9bSToomas Soome     // configuration, more care should be paid to changedInterfaces.
16095ffb0c9bSToomas Soome     if (changedInterfaces)
16105ffb0c9bSToomas Soome         mDNSPlatformPosixRefreshInterfaceList(pChgRec->mDNS);
16115ffb0c9bSToomas Soome }
16124b22b933Srs 
16134b22b933Srs // Register with either a Routing Socket or RtNetLink to listen for interface changes.
WatchForInterfaceChange(mDNS * const m)16144b22b933Srs mDNSlocal mStatus WatchForInterfaceChange(mDNS *const m)
16155ffb0c9bSToomas Soome {
16165ffb0c9bSToomas Soome     mStatus err;
16175ffb0c9bSToomas Soome     IfChangeRec *pChgRec;
16184b22b933Srs 
1619472cd20dSToomas Soome     pChgRec = (IfChangeRec*) mDNSPlatformMemAllocateClear(sizeof *pChgRec);
16205ffb0c9bSToomas Soome     if (pChgRec == NULL)
16215ffb0c9bSToomas Soome         return mStatus_NoMemoryErr;
16224b22b933Srs 
16235ffb0c9bSToomas Soome     pChgRec->mDNS = m;
16245ffb0c9bSToomas Soome     err = OpenIfNotifySocket(&pChgRec->NotifySD);
16255ffb0c9bSToomas Soome     if (err == 0)
16265ffb0c9bSToomas Soome         err = mDNSPosixAddFDToEventLoop(pChgRec->NotifySD, InterfaceChangeCallback, pChgRec);
1627472cd20dSToomas Soome     if (err)
1628472cd20dSToomas Soome         mDNSPlatformMemFree(pChgRec);
16294b22b933Srs 
16305ffb0c9bSToomas Soome     return err;
16315ffb0c9bSToomas Soome }
16324b22b933Srs 
16334b22b933Srs // Test to see if we're the first client running on UDP port 5353, by trying to bind to 5353 without using SO_REUSEPORT.
16344b22b933Srs // If we fail, someone else got here first. That's not a big problem; we can share the port for multicast responses --
16354b22b933Srs // we just need to be aware that we shouldn't expect to successfully receive unicast UDP responses.
mDNSPlatformInit_CanReceiveUnicast(void)16364b22b933Srs mDNSlocal mDNSBool mDNSPlatformInit_CanReceiveUnicast(void)
16375ffb0c9bSToomas Soome {
16385ffb0c9bSToomas Soome     int err;
16395ffb0c9bSToomas Soome     int s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
16405ffb0c9bSToomas Soome     struct sockaddr_in s5353;
16415ffb0c9bSToomas Soome     s5353.sin_family      = AF_INET;
16425ffb0c9bSToomas Soome     s5353.sin_port        = MulticastDNSPort.NotAnInteger;
16435ffb0c9bSToomas Soome     s5353.sin_addr.s_addr = 0;
16445ffb0c9bSToomas Soome     err = bind(s, (struct sockaddr *)&s5353, sizeof(s5353));
16455ffb0c9bSToomas Soome     close(s);
16465ffb0c9bSToomas Soome     if (err) debugf("No unicast UDP responses");
16475ffb0c9bSToomas Soome     else debugf("Unicast UDP responses okay");
16485ffb0c9bSToomas Soome     return(err == 0);
16495ffb0c9bSToomas Soome }
16504b22b933Srs 
16514b22b933Srs // mDNS core calls this routine to initialise the platform-specific data.
mDNSPlatformInit(mDNS * const m)16524b22b933Srs mDNSexport mStatus mDNSPlatformInit(mDNS *const m)
16535ffb0c9bSToomas Soome {
16545ffb0c9bSToomas Soome     int err = 0;
16555ffb0c9bSToomas Soome     struct sockaddr sa;
16565ffb0c9bSToomas Soome     assert(m != NULL);
16574b22b933Srs 
16585ffb0c9bSToomas Soome     if (mDNSPlatformInit_CanReceiveUnicast()) m->CanReceiveUnicastOn5353 = mDNStrue;
16594b22b933Srs 
16605ffb0c9bSToomas Soome     // Tell mDNS core the names of this machine.
16614b22b933Srs 
16625ffb0c9bSToomas Soome     // Set up the nice label
16635ffb0c9bSToomas Soome     m->nicelabel.c[0] = 0;
16645ffb0c9bSToomas Soome     GetUserSpecifiedFriendlyComputerName(&m->nicelabel);
16655ffb0c9bSToomas Soome     if (m->nicelabel.c[0] == 0) MakeDomainLabelFromLiteralString(&m->nicelabel, "Computer");
16664b22b933Srs 
16675ffb0c9bSToomas Soome     // Set up the RFC 1034-compliant label
16685ffb0c9bSToomas Soome     m->hostlabel.c[0] = 0;
16695ffb0c9bSToomas Soome     GetUserSpecifiedRFC1034ComputerName(&m->hostlabel);
16705ffb0c9bSToomas Soome     if (m->hostlabel.c[0] == 0) MakeDomainLabelFromLiteralString(&m->hostlabel, "Computer");
16714b22b933Srs 
16725ffb0c9bSToomas Soome     mDNS_SetFQDN(m);
16734b22b933Srs 
16745ffb0c9bSToomas Soome     sa.sa_family = AF_INET;
16755ffb0c9bSToomas Soome     m->p->unicastSocket4 = -1;
16765ffb0c9bSToomas Soome     if (err == mStatus_NoError) err = SetupSocket(&sa, zeroIPPort, 0, &m->p->unicastSocket4);
16774b22b933Srs #if HAVE_IPV6
16785ffb0c9bSToomas Soome     sa.sa_family = AF_INET6;
16795ffb0c9bSToomas Soome     m->p->unicastSocket6 = -1;
16805ffb0c9bSToomas Soome     if (err == mStatus_NoError) err = SetupSocket(&sa, zeroIPPort, 0, &m->p->unicastSocket6);
16814b22b933Srs #endif
16824b22b933Srs 
16835ffb0c9bSToomas Soome     // Tell mDNS core about the network interfaces on this machine.
16845ffb0c9bSToomas Soome     if (err == mStatus_NoError) err = SetupInterfaceList(m);
16855ffb0c9bSToomas Soome 
16865ffb0c9bSToomas Soome     // Tell mDNS core about DNS Servers
16875ffb0c9bSToomas Soome     mDNS_Lock(m);
16885ffb0c9bSToomas Soome     if (err == mStatus_NoError) ParseDNSServers(m, uDNS_SERVERS_FILE);
16895ffb0c9bSToomas Soome     mDNS_Unlock(m);
16905ffb0c9bSToomas Soome 
16915ffb0c9bSToomas Soome     if (err == mStatus_NoError)
16925ffb0c9bSToomas Soome     {
16935ffb0c9bSToomas Soome         err = WatchForInterfaceChange(m);
16945ffb0c9bSToomas Soome         // Failure to observe interface changes is non-fatal.
16955ffb0c9bSToomas Soome         if (err != mStatus_NoError)
16965ffb0c9bSToomas Soome         {
16973b436d06SToomas Soome             fprintf(stderr, "mDNS(%d) WARNING: Unable to detect interface changes (%d).\n",
16983b436d06SToomas Soome 		(int)getpid(), err);
16995ffb0c9bSToomas Soome             err = mStatus_NoError;
17005ffb0c9bSToomas Soome         }
17015ffb0c9bSToomas Soome     }
17025ffb0c9bSToomas Soome 
17035ffb0c9bSToomas Soome     // We don't do asynchronous initialization on the Posix platform, so by the time
17045ffb0c9bSToomas Soome     // we get here the setup will already have succeeded or failed.  If it succeeded,
17055ffb0c9bSToomas Soome     // we should just call mDNSCoreInitComplete() immediately.
17065ffb0c9bSToomas Soome     if (err == mStatus_NoError)
17075ffb0c9bSToomas Soome         mDNSCoreInitComplete(m, mStatus_NoError);
17085ffb0c9bSToomas Soome 
17095ffb0c9bSToomas Soome     return PosixErrorToStatus(err);
17105ffb0c9bSToomas Soome }
17114b22b933Srs 
17124b22b933Srs // mDNS core calls this routine to clean up the platform-specific data.
17134b22b933Srs // In our case all we need to do is to tear down every network interface.
mDNSPlatformClose(mDNS * const m)17144b22b933Srs mDNSexport void mDNSPlatformClose(mDNS *const m)
17155ffb0c9bSToomas Soome {
1716c65ebfc7SToomas Soome     int rv;
17175ffb0c9bSToomas Soome     assert(m != NULL);
17185ffb0c9bSToomas Soome     ClearInterfaceList(m);
1719c65ebfc7SToomas Soome     if (m->p->unicastSocket4 != -1)
1720c65ebfc7SToomas Soome     {
1721c65ebfc7SToomas Soome         rv = close(m->p->unicastSocket4);
1722c65ebfc7SToomas Soome         assert(rv == 0);
1723c65ebfc7SToomas Soome     }
17244b22b933Srs #if HAVE_IPV6
1725c65ebfc7SToomas Soome     if (m->p->unicastSocket6 != -1)
1726c65ebfc7SToomas Soome     {
1727c65ebfc7SToomas Soome         rv = close(m->p->unicastSocket6);
1728c65ebfc7SToomas Soome         assert(rv == 0);
1729c65ebfc7SToomas Soome     }
17304b22b933Srs #endif
17315ffb0c9bSToomas Soome }
17324b22b933Srs 
17335ffb0c9bSToomas Soome // This is used internally by InterfaceChangeCallback.
17345ffb0c9bSToomas Soome // It's also exported so that the Standalone Responder (mDNSResponderPosix)
17355ffb0c9bSToomas Soome // can call it in response to a SIGHUP (mainly for debugging purposes).
mDNSPlatformPosixRefreshInterfaceList(mDNS * const m)17364b22b933Srs mDNSexport mStatus mDNSPlatformPosixRefreshInterfaceList(mDNS *const m)
17375ffb0c9bSToomas Soome {
17385ffb0c9bSToomas Soome     int err;
17395ffb0c9bSToomas Soome     // This is a pretty heavyweight way to process interface changes --
17405ffb0c9bSToomas Soome     // destroying the entire interface list and then making fresh one from scratch.
17415ffb0c9bSToomas Soome     // We should make it like the OS X version, which leaves unchanged interfaces alone.
17425ffb0c9bSToomas Soome     ClearInterfaceList(m);
17435ffb0c9bSToomas Soome     err = SetupInterfaceList(m);
17445ffb0c9bSToomas Soome     return PosixErrorToStatus(err);
17455ffb0c9bSToomas Soome }
17464b22b933Srs 
17474b22b933Srs #if COMPILER_LIKES_PRAGMA_MARK
17484b22b933Srs #pragma mark ***** Locking
17494b22b933Srs #endif
17504b22b933Srs 
17514b22b933Srs // On the Posix platform, locking is a no-op because we only ever enter
17524b22b933Srs // mDNS core on the main thread.
17534b22b933Srs 
17544b22b933Srs // mDNS core calls this routine when it wants to prevent
17554b22b933Srs // the platform from reentering mDNS core code.
mDNSPlatformLock(const mDNS * const m)17564b22b933Srs mDNSexport void    mDNSPlatformLock   (const mDNS *const m)
17575ffb0c9bSToomas Soome {
17585ffb0c9bSToomas Soome     (void) m;   // Unused
17595ffb0c9bSToomas Soome }
17604b22b933Srs 
17614b22b933Srs // mDNS core calls this routine when it release the lock taken by
17624b22b933Srs // mDNSPlatformLock and allow the platform to reenter mDNS core code.
mDNSPlatformUnlock(const mDNS * const m)17634b22b933Srs mDNSexport void    mDNSPlatformUnlock (const mDNS *const m)
17645ffb0c9bSToomas Soome {
17655ffb0c9bSToomas Soome     (void) m;   // Unused
17665ffb0c9bSToomas Soome }
17674b22b933Srs 
17684b22b933Srs #if COMPILER_LIKES_PRAGMA_MARK
17694b22b933Srs #pragma mark ***** Strings
17704b22b933Srs #endif
17714b22b933Srs 
mDNSPlatformStrLCopy(void * dst,const void * src,mDNSu32 len)1772c65ebfc7SToomas Soome mDNSexport mDNSu32  mDNSPlatformStrLCopy(void *dst, const void *src, mDNSu32 len)
1773c65ebfc7SToomas Soome {
1774c65ebfc7SToomas Soome #if HAVE_STRLCPY
1775c65ebfc7SToomas Soome     return ((mDNSu32)strlcpy((char *)dst, (const char *)src, len));
1776c65ebfc7SToomas Soome #else
1777c65ebfc7SToomas Soome     size_t srcLen;
1778c65ebfc7SToomas Soome 
1779c65ebfc7SToomas Soome     srcLen = strlen((const char *)src);
1780c65ebfc7SToomas Soome     if (srcLen < len)
1781c65ebfc7SToomas Soome     {
1782c65ebfc7SToomas Soome         memcpy(dst, src, srcLen + 1);
1783c65ebfc7SToomas Soome     }
1784c65ebfc7SToomas Soome     else if (len > 0)
1785c65ebfc7SToomas Soome     {
1786c65ebfc7SToomas Soome         memcpy(dst, src, len - 1);
1787c65ebfc7SToomas Soome         ((char *)dst)[len - 1] = '\0';
1788c65ebfc7SToomas Soome     }
1789c65ebfc7SToomas Soome 
1790c65ebfc7SToomas Soome     return ((mDNSu32)srcLen);
1791c65ebfc7SToomas Soome #endif
17925ffb0c9bSToomas Soome }
17934b22b933Srs 
17944b22b933Srs // mDNS core calls this routine to get the length of a C string.
17954b22b933Srs // On the Posix platform this maps directly to the ANSI C strlen.
mDNSPlatformStrLen(const void * src)17964b22b933Srs mDNSexport mDNSu32  mDNSPlatformStrLen (const void *src)
17975ffb0c9bSToomas Soome {
1798c65ebfc7SToomas Soome     return strlen((const char*)src);
17995ffb0c9bSToomas Soome }
18004b22b933Srs 
18014b22b933Srs // mDNS core calls this routine to copy memory.
18024b22b933Srs // On the Posix platform this maps directly to the ANSI C memcpy.
mDNSPlatformMemCopy(void * dst,const void * src,mDNSu32 len)18035ffb0c9bSToomas Soome mDNSexport void    mDNSPlatformMemCopy(void *dst, const void *src, mDNSu32 len)
18045ffb0c9bSToomas Soome {
18055ffb0c9bSToomas Soome     memcpy(dst, src, len);
18065ffb0c9bSToomas Soome }
18074b22b933Srs 
18084b22b933Srs // mDNS core calls this routine to test whether blocks of memory are byte-for-byte
18094b22b933Srs // identical. On the Posix platform this is a simple wrapper around ANSI C memcmp.
mDNSPlatformMemSame(const void * dst,const void * src,mDNSu32 len)18105ffb0c9bSToomas Soome mDNSexport mDNSBool mDNSPlatformMemSame(const void *dst, const void *src, mDNSu32 len)
18115ffb0c9bSToomas Soome {
18125ffb0c9bSToomas Soome     return memcmp(dst, src, len) == 0;
18135ffb0c9bSToomas Soome }
18145ffb0c9bSToomas Soome 
18155ffb0c9bSToomas Soome // If the caller wants to know the exact return of memcmp, then use this instead
18165ffb0c9bSToomas Soome // of mDNSPlatformMemSame
mDNSPlatformMemCmp(const void * dst,const void * src,mDNSu32 len)18175ffb0c9bSToomas Soome mDNSexport int mDNSPlatformMemCmp(const void *dst, const void *src, mDNSu32 len)
18185ffb0c9bSToomas Soome {
18195ffb0c9bSToomas Soome     return (memcmp(dst, src, len));
18205ffb0c9bSToomas Soome }
18215ffb0c9bSToomas Soome 
mDNSPlatformQsort(void * base,int nel,int width,int (* compar)(const void *,const void *))18225ffb0c9bSToomas Soome mDNSexport void mDNSPlatformQsort(void *base, int nel, int width, int (*compar)(const void *, const void *))
18235ffb0c9bSToomas Soome {
18245ffb0c9bSToomas Soome     (void)qsort(base, nel, width, compar);
18255ffb0c9bSToomas Soome }
18265ffb0c9bSToomas Soome 
18275ffb0c9bSToomas Soome // Proxy stub functions
DNSProxySetAttributes(DNSQuestion * q,DNSMessageHeader * h,DNSMessage * msg,mDNSu8 * ptr,mDNSu8 * limit)18285ffb0c9bSToomas Soome mDNSexport mDNSu8 *DNSProxySetAttributes(DNSQuestion *q, DNSMessageHeader *h, DNSMessage *msg, mDNSu8 *ptr, mDNSu8 *limit)
18295ffb0c9bSToomas Soome {
18305ffb0c9bSToomas Soome     (void) q;
18315ffb0c9bSToomas Soome     (void) h;
18325ffb0c9bSToomas Soome     (void) msg;
18335ffb0c9bSToomas Soome     (void) ptr;
18345ffb0c9bSToomas Soome     (void) limit;
18355ffb0c9bSToomas Soome 
18365ffb0c9bSToomas Soome     return ptr;
18375ffb0c9bSToomas Soome }
18385ffb0c9bSToomas Soome 
DNSProxyInit(mDNSu32 IpIfArr[MaxIp],mDNSu32 OpIf)183919f828dfSToomas Soome mDNSexport void DNSProxyInit(mDNSu32 IpIfArr[MaxIp], mDNSu32 OpIf)
18405ffb0c9bSToomas Soome {
18415ffb0c9bSToomas Soome     (void) IpIfArr;
18425ffb0c9bSToomas Soome     (void) OpIf;
18435ffb0c9bSToomas Soome }
18445ffb0c9bSToomas Soome 
DNSProxyTerminate(void)1845c65ebfc7SToomas Soome mDNSexport void DNSProxyTerminate(void)
18465ffb0c9bSToomas Soome {
18475ffb0c9bSToomas Soome }
18484b22b933Srs 
18494b22b933Srs // mDNS core calls this routine to clear blocks of memory.
18504b22b933Srs // On the Posix platform this is a simple wrapper around ANSI C memset.
mDNSPlatformMemZero(void * dst,mDNSu32 len)1851472cd20dSToomas Soome mDNSexport void  mDNSPlatformMemZero(void *dst, mDNSu32 len)
18525ffb0c9bSToomas Soome {
18535ffb0c9bSToomas Soome     memset(dst, 0, len);
18545ffb0c9bSToomas Soome }
18554b22b933Srs 
1856472cd20dSToomas Soome #if !MDNS_MALLOC_DEBUGGING
mDNSPlatformMemAllocate(mDNSu32 len)1857472cd20dSToomas Soome mDNSexport void *mDNSPlatformMemAllocate(mDNSu32 len)      { return(mallocL("mDNSPlatformMemAllocate", len)); }
mDNSPlatformMemAllocateClear(mDNSu32 len)1858472cd20dSToomas Soome mDNSexport void *mDNSPlatformMemAllocateClear(mDNSu32 len) { return(callocL(name, len)); }
mDNSPlatformMemFree(void * mem)1859472cd20dSToomas Soome mDNSexport void  mDNSPlatformMemFree    (void *mem)        {          freeL("mDNSPlatformMemFree", mem); }
1860472cd20dSToomas Soome #endif
18614b22b933Srs 
1862c65ebfc7SToomas Soome #if _PLATFORM_HAS_STRONG_PRNG_
mDNSPlatformRandomNumber(void)1863c65ebfc7SToomas Soome mDNSexport mDNSu32 mDNSPlatformRandomNumber(void)
1864c65ebfc7SToomas Soome {
1865472cd20dSToomas Soome     return(arc4random());
1866c65ebfc7SToomas Soome }
1867c65ebfc7SToomas Soome #else
mDNSPlatformRandomSeed(void)18684b22b933Srs mDNSexport mDNSu32 mDNSPlatformRandomSeed(void)
18695ffb0c9bSToomas Soome {
18705ffb0c9bSToomas Soome     struct timeval tv;
18715ffb0c9bSToomas Soome     gettimeofday(&tv, NULL);
18725ffb0c9bSToomas Soome     return(tv.tv_usec);
18735ffb0c9bSToomas Soome }
1874c65ebfc7SToomas Soome #endif
18754b22b933Srs 
18765ffb0c9bSToomas Soome mDNSexport mDNSs32 mDNSPlatformOneSecond = 1024;
18774b22b933Srs 
mDNSPlatformTimeInit(void)18784b22b933Srs mDNSexport mStatus mDNSPlatformTimeInit(void)
18795ffb0c9bSToomas Soome {
18805ffb0c9bSToomas Soome     // No special setup is required on Posix -- we just use gettimeofday();
18815ffb0c9bSToomas Soome     // This is not really safe, because gettimeofday can go backwards if the user manually changes the date or time
18825ffb0c9bSToomas Soome     // We should find a better way to do this
18835ffb0c9bSToomas Soome     return(mStatus_NoError);
18845ffb0c9bSToomas Soome }
18854b22b933Srs 
mDNSPlatformRawTime()18864b22b933Srs mDNSexport mDNSs32  mDNSPlatformRawTime()
18875ffb0c9bSToomas Soome {
1888472cd20dSToomas Soome     struct timespec tm;
1889472cd20dSToomas Soome     int ret = clock_gettime(CLOCK_MONOTONIC, &tm);
1890472cd20dSToomas Soome     assert(ret == 0); // This call will only fail if the number of seconds does not fit in an object of type time_t.
1891472cd20dSToomas Soome 
1892472cd20dSToomas Soome     // tm.tv_sec is seconds since some unspecified starting point (it is usually the system start up time)
1893472cd20dSToomas Soome     // tm.tv_nsec is nanoseconds since the start of this second (i.e. values 0 to 999999999)
1894472cd20dSToomas Soome     // We use the lower 22 bits of tm.tv_sec for the top 22 bits of our result
1895472cd20dSToomas Soome     // and we multiply tm.tv_nsec by 2 / 1953125 to get a value in the range 0-1023 to go in the bottom 10 bits.
18965ffb0c9bSToomas Soome     // This gives us a proper modular (cyclic) counter that has a resolution of roughly 1ms (actually 1/1024 second)
18975ffb0c9bSToomas Soome     // and correctly cycles every 2^22 seconds (4194304 seconds = approx 48 days).
1898472cd20dSToomas Soome 
1899472cd20dSToomas Soome     return ((tm.tv_sec << 10) | (tm.tv_nsec * 2 / 1953125));
19005ffb0c9bSToomas Soome }
19014b22b933Srs 
mDNSPlatformUTC(void)19024b22b933Srs mDNSexport mDNSs32 mDNSPlatformUTC(void)
19035ffb0c9bSToomas Soome {
19045ffb0c9bSToomas Soome     return time(NULL);
19055ffb0c9bSToomas Soome }
19065ffb0c9bSToomas Soome 
mDNSPlatformSendWakeupPacket(mDNSInterfaceID InterfaceID,char * EthAddr,char * IPAddr,int iteration)1907c65ebfc7SToomas Soome mDNSexport void mDNSPlatformSendWakeupPacket(mDNSInterfaceID InterfaceID, char *EthAddr, char *IPAddr, int iteration)
19085ffb0c9bSToomas Soome {
19095ffb0c9bSToomas Soome     (void) InterfaceID;
19105ffb0c9bSToomas Soome     (void) EthAddr;
19115ffb0c9bSToomas Soome     (void) IPAddr;
19125ffb0c9bSToomas Soome     (void) iteration;
19135ffb0c9bSToomas Soome }
19145ffb0c9bSToomas Soome 
mDNSPlatformValidRecordForInterface(const AuthRecord * rr,mDNSInterfaceID InterfaceID)1915c65ebfc7SToomas Soome mDNSexport mDNSBool mDNSPlatformValidRecordForInterface(const AuthRecord *rr, mDNSInterfaceID InterfaceID)
19165ffb0c9bSToomas Soome {
19175ffb0c9bSToomas Soome     (void) rr;
1918c65ebfc7SToomas Soome     (void) InterfaceID;
19195ffb0c9bSToomas Soome 
19205ffb0c9bSToomas Soome     return 1;
19215ffb0c9bSToomas Soome }
19225ffb0c9bSToomas Soome 
mDNSPlatformValidQuestionForInterface(DNSQuestion * q,const NetworkInterfaceInfo * intf)19235ffb0c9bSToomas Soome mDNSexport mDNSBool mDNSPlatformValidQuestionForInterface(DNSQuestion *q, const NetworkInterfaceInfo *intf)
19245ffb0c9bSToomas Soome {
19255ffb0c9bSToomas Soome     (void) q;
19265ffb0c9bSToomas Soome     (void) intf;
19275ffb0c9bSToomas Soome 
19285ffb0c9bSToomas Soome     return 1;
19295ffb0c9bSToomas Soome }
19305ffb0c9bSToomas Soome 
19315ffb0c9bSToomas Soome // Used for debugging purposes. For now, just set the buffer to zero
mDNSPlatformFormatTime(unsigned long te,mDNSu8 * buf,int bufsize)19325ffb0c9bSToomas Soome mDNSexport void mDNSPlatformFormatTime(unsigned long te, mDNSu8 *buf, int bufsize)
19335ffb0c9bSToomas Soome {
19345ffb0c9bSToomas Soome     (void) te;
19355ffb0c9bSToomas Soome     if (bufsize) buf[0] = 0;
19365ffb0c9bSToomas Soome }
19375ffb0c9bSToomas Soome 
mDNSPlatformSendKeepalive(mDNSAddr * sadd,mDNSAddr * dadd,mDNSIPPort * lport,mDNSIPPort * rport,mDNSu32 seq,mDNSu32 ack,mDNSu16 win)19385ffb0c9bSToomas Soome mDNSexport void mDNSPlatformSendKeepalive(mDNSAddr *sadd, mDNSAddr *dadd, mDNSIPPort *lport, mDNSIPPort *rport, mDNSu32 seq, mDNSu32 ack, mDNSu16 win)
19395ffb0c9bSToomas Soome {
19405ffb0c9bSToomas Soome     (void) sadd;    // Unused
19415ffb0c9bSToomas Soome     (void) dadd;    // Unused
19425ffb0c9bSToomas Soome     (void) lport;   // Unused
19435ffb0c9bSToomas Soome     (void) rport;   // Unused
19445ffb0c9bSToomas Soome     (void) seq;     // Unused
19455ffb0c9bSToomas Soome     (void) ack;     // Unused
19465ffb0c9bSToomas Soome     (void) win;     // Unused
19475ffb0c9bSToomas Soome }
19485ffb0c9bSToomas Soome 
mDNSPlatformRetrieveTCPInfo(mDNSAddr * laddr,mDNSIPPort * lport,mDNSAddr * raddr,mDNSIPPort * rport,mDNSTCPInfo * mti)1949c65ebfc7SToomas Soome mDNSexport mStatus mDNSPlatformRetrieveTCPInfo(mDNSAddr *laddr, mDNSIPPort *lport, mDNSAddr *raddr, mDNSIPPort *rport, mDNSTCPInfo *mti)
19505ffb0c9bSToomas Soome {
19515ffb0c9bSToomas Soome     (void) laddr;   // Unused
19525ffb0c9bSToomas Soome     (void) raddr;   // Unused
19535ffb0c9bSToomas Soome     (void) lport;   // Unused
19545ffb0c9bSToomas Soome     (void) rport;   // Unused
19555ffb0c9bSToomas Soome     (void) mti;     // Unused
19565ffb0c9bSToomas Soome 
19575ffb0c9bSToomas Soome     return mStatus_NoError;
19585ffb0c9bSToomas Soome }
19595ffb0c9bSToomas Soome 
mDNSPlatformGetRemoteMacAddr(mDNSAddr * raddr)1960c65ebfc7SToomas Soome mDNSexport mStatus mDNSPlatformGetRemoteMacAddr(mDNSAddr *raddr)
19615ffb0c9bSToomas Soome {
19625ffb0c9bSToomas Soome     (void) raddr; // Unused
19635ffb0c9bSToomas Soome 
19645ffb0c9bSToomas Soome     return mStatus_NoError;
19655ffb0c9bSToomas Soome }
19665ffb0c9bSToomas Soome 
mDNSPlatformStoreSPSMACAddr(mDNSAddr * spsaddr,char * ifname)19675ffb0c9bSToomas Soome mDNSexport mStatus    mDNSPlatformStoreSPSMACAddr(mDNSAddr *spsaddr, char *ifname)
19685ffb0c9bSToomas Soome {
19695ffb0c9bSToomas Soome     (void) spsaddr; // Unused
19705ffb0c9bSToomas Soome     (void) ifname;  // Unused
19715ffb0c9bSToomas Soome 
19725ffb0c9bSToomas Soome     return mStatus_NoError;
19735ffb0c9bSToomas Soome }
19745ffb0c9bSToomas Soome 
mDNSPlatformClearSPSData(void)1975c65ebfc7SToomas Soome mDNSexport mStatus    mDNSPlatformClearSPSData(void)
19765ffb0c9bSToomas Soome {
19775ffb0c9bSToomas Soome     return mStatus_NoError;
19785ffb0c9bSToomas Soome }
19795ffb0c9bSToomas Soome 
mDNSPlatformStoreOwnerOptRecord(char * ifname,DNSMessage * msg,int length)1980c65ebfc7SToomas Soome mDNSexport mStatus mDNSPlatformStoreOwnerOptRecord(char *ifname, DNSMessage *msg, int length)
1981c65ebfc7SToomas Soome {
1982c65ebfc7SToomas Soome     (void) ifname; // Unused
1983c65ebfc7SToomas Soome     (void) msg;    // Unused
1984c65ebfc7SToomas Soome     (void) length; // Unused
1985c65ebfc7SToomas Soome     return mStatus_UnsupportedErr;
1986c65ebfc7SToomas Soome }
1987c65ebfc7SToomas Soome 
mDNSPlatformGetUDPPort(UDPSocket * sock)19885ffb0c9bSToomas Soome mDNSexport mDNSu16 mDNSPlatformGetUDPPort(UDPSocket *sock)
19895ffb0c9bSToomas Soome {
19905ffb0c9bSToomas Soome     (void) sock; // unused
1991c65ebfc7SToomas Soome 
19925ffb0c9bSToomas Soome     return (mDNSu16)-1;
19935ffb0c9bSToomas Soome }
19945ffb0c9bSToomas Soome 
mDNSPlatformInterfaceIsD2D(mDNSInterfaceID InterfaceID)19955ffb0c9bSToomas Soome mDNSexport mDNSBool mDNSPlatformInterfaceIsD2D(mDNSInterfaceID InterfaceID)
19965ffb0c9bSToomas Soome {
19975ffb0c9bSToomas Soome     (void) InterfaceID; // unused
19985ffb0c9bSToomas Soome 
1999c65ebfc7SToomas Soome     return mDNSfalse;
20005ffb0c9bSToomas Soome }
20015ffb0c9bSToomas Soome 
mDNSPlatformSetSocktOpt(void * sock,mDNSTransport_Type transType,mDNSAddr_Type addrType,const DNSQuestion * q)2002c65ebfc7SToomas Soome mDNSexport void mDNSPlatformSetSocktOpt(void *sock, mDNSTransport_Type transType, mDNSAddr_Type addrType, const DNSQuestion *q)
20035ffb0c9bSToomas Soome {
2004c65ebfc7SToomas Soome     (void) sock;
2005c65ebfc7SToomas Soome     (void) transType;
2006c65ebfc7SToomas Soome     (void) addrType;
20075ffb0c9bSToomas Soome     (void) q;
20085ffb0c9bSToomas Soome }
20095ffb0c9bSToomas Soome 
mDNSPlatformGetPID()20105ffb0c9bSToomas Soome mDNSexport mDNSs32 mDNSPlatformGetPID()
20115ffb0c9bSToomas Soome {
20125ffb0c9bSToomas Soome     return 0;
20135ffb0c9bSToomas Soome }
20144b22b933Srs 
mDNSPosixAddToFDSet(int * nfds,fd_set * readfds,int s)20154b22b933Srs mDNSlocal void mDNSPosixAddToFDSet(int *nfds, fd_set *readfds, int s)
20165ffb0c9bSToomas Soome {
20175ffb0c9bSToomas Soome     if (*nfds < s + 1) *nfds = s + 1;
20185ffb0c9bSToomas Soome     FD_SET(s, readfds);
20195ffb0c9bSToomas Soome }
20204b22b933Srs 
mDNSPosixGetFDSetForSelect(mDNS * m,int * nfds,fd_set * readfds,fd_set * writefds)2021472cd20dSToomas Soome mDNSexport void mDNSPosixGetFDSetForSelect(mDNS *m, int *nfds, fd_set *readfds, fd_set *writefds)
20225ffb0c9bSToomas Soome {
2023472cd20dSToomas Soome     int numFDs = *nfds;
2024472cd20dSToomas Soome     PosixEventSource *iSource;
20254b22b933Srs 
20265ffb0c9bSToomas Soome     // 2. Build our list of active file descriptors
20275ffb0c9bSToomas Soome     PosixNetworkInterface *info = (PosixNetworkInterface *)(m->HostInterfaces);
2028472cd20dSToomas Soome     if (m->p->unicastSocket4 != -1) mDNSPosixAddToFDSet(&numFDs, readfds, m->p->unicastSocket4);
20294b22b933Srs #if HAVE_IPV6
2030472cd20dSToomas Soome     if (m->p->unicastSocket6 != -1) mDNSPosixAddToFDSet(&numFDs, readfds, m->p->unicastSocket6);
20314b22b933Srs #endif
20325ffb0c9bSToomas Soome     while (info)
20335ffb0c9bSToomas Soome     {
2034472cd20dSToomas Soome         if (info->multicastSocket4 != -1) mDNSPosixAddToFDSet(&numFDs, readfds, info->multicastSocket4);
20354b22b933Srs #if HAVE_IPV6
2036472cd20dSToomas Soome         if (info->multicastSocket6 != -1) mDNSPosixAddToFDSet(&numFDs, readfds, info->multicastSocket6);
20374b22b933Srs #endif
20385ffb0c9bSToomas Soome         info = (PosixNetworkInterface *)(info->coreIntf.next);
20395ffb0c9bSToomas Soome     }
20404b22b933Srs 
2041472cd20dSToomas Soome     // Copy over the event fds.   We have to do it this way because client-provided event loops expect
2042472cd20dSToomas Soome     // to initialize their FD sets first and then call mDNSPosixGetFDSet()
2043472cd20dSToomas Soome     for (iSource = gEventSources; iSource; iSource = iSource->next)
2044472cd20dSToomas Soome     {
2045472cd20dSToomas Soome         if (iSource->readCallback != NULL)
2046472cd20dSToomas Soome             FD_SET(iSource->fd, readfds);
2047472cd20dSToomas Soome         if (iSource->writeCallback != NULL)
2048472cd20dSToomas Soome             FD_SET(iSource->fd, writefds);
2049472cd20dSToomas Soome         if (numFDs <= iSource->fd)
2050472cd20dSToomas Soome             numFDs = iSource->fd + 1;
2051472cd20dSToomas Soome     }
2052472cd20dSToomas Soome     *nfds = numFDs;
2053472cd20dSToomas Soome }
2054472cd20dSToomas Soome 
mDNSPosixGetNextDNSEventTime(mDNS * m,struct timeval * timeout)2055472cd20dSToomas Soome mDNSexport void mDNSPosixGetNextDNSEventTime(mDNS *m, struct timeval *timeout)
2056472cd20dSToomas Soome {
2057472cd20dSToomas Soome     mDNSs32 ticks;
2058472cd20dSToomas Soome     struct timeval interval;
2059472cd20dSToomas Soome 
2060472cd20dSToomas Soome     // 1. Call mDNS_Execute() to let mDNSCore do what it needs to do
2061472cd20dSToomas Soome     mDNSs32 nextevent = mDNS_Execute(m);
2062472cd20dSToomas Soome 
20635ffb0c9bSToomas Soome     // 3. Calculate the time remaining to the next scheduled event (in struct timeval format)
20645ffb0c9bSToomas Soome     ticks = nextevent - mDNS_TimeNow(m);
20655ffb0c9bSToomas Soome     if (ticks < 1) ticks = 1;
20665ffb0c9bSToomas Soome     interval.tv_sec  = ticks >> 10;                     // The high 22 bits are seconds
20675ffb0c9bSToomas Soome     interval.tv_usec = ((ticks & 0x3FF) * 15625) / 16;  // The low 10 bits are 1024ths
20684b22b933Srs 
20695ffb0c9bSToomas Soome     // 4. If client's proposed timeout is more than what we want, then reduce it
20705ffb0c9bSToomas Soome     if (timeout->tv_sec > interval.tv_sec ||
20715ffb0c9bSToomas Soome         (timeout->tv_sec == interval.tv_sec && timeout->tv_usec > interval.tv_usec))
20725ffb0c9bSToomas Soome         *timeout = interval;
20735ffb0c9bSToomas Soome }
20744b22b933Srs 
mDNSPosixGetFDSet(mDNS * m,int * nfds,fd_set * readfds,fd_set * writefds,struct timeval * timeout)2075472cd20dSToomas Soome mDNSexport void mDNSPosixGetFDSet(mDNS *m, int *nfds, fd_set *readfds, fd_set *writefds, struct timeval *timeout)
2076472cd20dSToomas Soome {
2077472cd20dSToomas Soome     mDNSPosixGetNextDNSEventTime(m, timeout);
2078472cd20dSToomas Soome     mDNSPosixGetFDSetForSelect(m, nfds, readfds, writefds);
2079472cd20dSToomas Soome }
2080472cd20dSToomas Soome 
mDNSPosixProcessFDSet(mDNS * const m,fd_set * readfds,fd_set * writefds)2081472cd20dSToomas Soome mDNSexport void mDNSPosixProcessFDSet(mDNS *const m, fd_set *readfds, fd_set *writefds)
20825ffb0c9bSToomas Soome {
20835ffb0c9bSToomas Soome     PosixNetworkInterface *info;
2084472cd20dSToomas Soome     PosixEventSource    *iSource;
20855ffb0c9bSToomas Soome     assert(m       != NULL);
20865ffb0c9bSToomas Soome     assert(readfds != NULL);
20875ffb0c9bSToomas Soome     info = (PosixNetworkInterface *)(m->HostInterfaces);
20885ffb0c9bSToomas Soome 
20895ffb0c9bSToomas Soome     if (m->p->unicastSocket4 != -1 && FD_ISSET(m->p->unicastSocket4, readfds))
20905ffb0c9bSToomas Soome     {
20915ffb0c9bSToomas Soome         FD_CLR(m->p->unicastSocket4, readfds);
20925ffb0c9bSToomas Soome         SocketDataReady(m, NULL, m->p->unicastSocket4);
20935ffb0c9bSToomas Soome     }
20944b22b933Srs #if HAVE_IPV6
20955ffb0c9bSToomas Soome     if (m->p->unicastSocket6 != -1 && FD_ISSET(m->p->unicastSocket6, readfds))
20965ffb0c9bSToomas Soome     {
20975ffb0c9bSToomas Soome         FD_CLR(m->p->unicastSocket6, readfds);
20985ffb0c9bSToomas Soome         SocketDataReady(m, NULL, m->p->unicastSocket6);
20995ffb0c9bSToomas Soome     }
21004b22b933Srs #endif
21014b22b933Srs 
21025ffb0c9bSToomas Soome     while (info)
21035ffb0c9bSToomas Soome     {
21045ffb0c9bSToomas Soome         if (info->multicastSocket4 != -1 && FD_ISSET(info->multicastSocket4, readfds))
21055ffb0c9bSToomas Soome         {
21065ffb0c9bSToomas Soome             FD_CLR(info->multicastSocket4, readfds);
21075ffb0c9bSToomas Soome             SocketDataReady(m, info, info->multicastSocket4);
21085ffb0c9bSToomas Soome         }
21094b22b933Srs #if HAVE_IPV6
21105ffb0c9bSToomas Soome         if (info->multicastSocket6 != -1 && FD_ISSET(info->multicastSocket6, readfds))
21115ffb0c9bSToomas Soome         {
21125ffb0c9bSToomas Soome             FD_CLR(info->multicastSocket6, readfds);
21135ffb0c9bSToomas Soome             SocketDataReady(m, info, info->multicastSocket6);
21145ffb0c9bSToomas Soome         }
21154b22b933Srs #endif
21165ffb0c9bSToomas Soome         info = (PosixNetworkInterface *)(info->coreIntf.next);
21175ffb0c9bSToomas Soome     }
21185ffb0c9bSToomas Soome 
2119472cd20dSToomas Soome     // Now process routing socket events, discovery relay events and anything else of that ilk.
2120472cd20dSToomas Soome     for (iSource = gEventSources; iSource; iSource = iSource->next)
2121472cd20dSToomas Soome     {
2122472cd20dSToomas Soome         if (iSource->readCallback != NULL && FD_ISSET(iSource->fd, readfds))
2123472cd20dSToomas Soome         {
2124472cd20dSToomas Soome             iSource->readCallback(iSource->fd, iSource->readContext);
2125472cd20dSToomas Soome             break;  // in case callback removed elements from gEventSources
2126472cd20dSToomas Soome         }
2127472cd20dSToomas Soome         else if (iSource->writeCallback != NULL && FD_ISSET(iSource->fd, writefds))
2128472cd20dSToomas Soome         {
2129472cd20dSToomas Soome             mDNSPosixEventCallback writeCallback = iSource->writeCallback;
2130472cd20dSToomas Soome             // Write events are one-shot: to get another event, the consumer has to put in a new request.
2131472cd20dSToomas Soome             // We reset this before calling the callback just in case the callback requests another write
2132472cd20dSToomas Soome             // callback, or deletes the event context from the list.
2133472cd20dSToomas Soome             iSource->writeCallback = NULL;
2134472cd20dSToomas Soome             writeCallback(iSource->fd, iSource->writeContext);
2135472cd20dSToomas Soome             break;  // in case callback removed elements from gEventSources
2136472cd20dSToomas Soome         }
2137472cd20dSToomas Soome     }
21385ffb0c9bSToomas Soome }
21394b22b933Srs 
2140472cd20dSToomas Soome mDNSu32 mDNSPlatformEventContextSize = sizeof (PosixEventSource);
21414b22b933Srs 
requestIOEvents(PosixEventSource * newSource,const char * taskName,mDNSPosixEventCallback callback,void * context,int flag)2142472cd20dSToomas Soome mDNSlocal void requestIOEvents(PosixEventSource *newSource, const char *taskName,
2143472cd20dSToomas Soome                                   mDNSPosixEventCallback callback, void *context, int flag)
2144472cd20dSToomas Soome {
2145472cd20dSToomas Soome     PosixEventSource **epp = &gEventSources;
21464b22b933Srs 
2147472cd20dSToomas Soome     if (newSource->fd >= (int) FD_SETSIZE || newSource->fd < 0)
2148472cd20dSToomas Soome     {
2149472cd20dSToomas Soome         LogMsg("requestIOEvents called with fd %d > FD_SETSIZE %d.", newSource->fd, FD_SETSIZE);
2150472cd20dSToomas Soome         assert(0);
2151472cd20dSToomas Soome     }
21525ffb0c9bSToomas Soome     if (callback == NULL)
2153472cd20dSToomas Soome     {
2154472cd20dSToomas Soome         LogMsg("requestIOEvents called no callback.", newSource->fd, FD_SETSIZE);
2155472cd20dSToomas Soome         assert(0);
2156472cd20dSToomas Soome     }
21574b22b933Srs 
2158472cd20dSToomas Soome     // See if this event context is already on the list; if it is, no need to scan the list.
2159472cd20dSToomas Soome     if (!(newSource->flags & PosixEventFlag_OnList))
2160472cd20dSToomas Soome     {
2161472cd20dSToomas Soome         while (*epp)
2162472cd20dSToomas Soome         {
2163472cd20dSToomas Soome             // This should never happen.
2164472cd20dSToomas Soome             if (newSource == *epp)
2165472cd20dSToomas Soome             {
2166472cd20dSToomas Soome                 LogMsg("Event context marked not on list but is on list.");
2167472cd20dSToomas Soome                 assert(0);
2168472cd20dSToomas Soome             }
2169472cd20dSToomas Soome             epp = &(*epp)->next;
2170472cd20dSToomas Soome         }
2171472cd20dSToomas Soome         if (*epp == NULL)
2172472cd20dSToomas Soome         {
2173472cd20dSToomas Soome             *epp = newSource;
2174472cd20dSToomas Soome             newSource->next = NULL;
2175472cd20dSToomas Soome             newSource->flags = PosixEventFlag_OnList;
2176472cd20dSToomas Soome         }
2177472cd20dSToomas Soome     }
21784b22b933Srs 
2179472cd20dSToomas Soome     if (flag & PosixEventFlag_Read)
2180472cd20dSToomas Soome     {
2181472cd20dSToomas Soome         newSource->readCallback = callback;
2182472cd20dSToomas Soome         newSource->readContext = context;
2183472cd20dSToomas Soome         newSource->flags |= PosixEventFlag_Read;
2184472cd20dSToomas Soome         newSource->readTaskName = taskName;
2185472cd20dSToomas Soome     }
2186472cd20dSToomas Soome     if (flag & PosixEventFlag_Write)
2187472cd20dSToomas Soome     {
2188472cd20dSToomas Soome         newSource->writeCallback = callback;
2189472cd20dSToomas Soome         newSource->writeContext = context;
2190472cd20dSToomas Soome         newSource->flags |= PosixEventFlag_Write;
2191472cd20dSToomas Soome         newSource->writeTaskName = taskName;
2192472cd20dSToomas Soome     }
2193472cd20dSToomas Soome }
21944b22b933Srs 
requestReadEvents(PosixEventSource * eventSource,const char * taskName,mDNSPosixEventCallback callback,void * context)2195472cd20dSToomas Soome mDNSlocal void requestReadEvents(PosixEventSource *eventSource,
2196472cd20dSToomas Soome                                     const char *taskName, mDNSPosixEventCallback callback, void *context)
2197472cd20dSToomas Soome {
2198472cd20dSToomas Soome     requestIOEvents(eventSource, taskName, callback, context, PosixEventFlag_Read);
2199472cd20dSToomas Soome }
22005ffb0c9bSToomas Soome 
requestWriteEvents(PosixEventSource * eventSource,const char * taskName,mDNSPosixEventCallback callback,void * context)2201472cd20dSToomas Soome mDNSlocal void requestWriteEvents(PosixEventSource *eventSource,
2202472cd20dSToomas Soome                                      const char *taskName, mDNSPosixEventCallback callback, void *context)
2203472cd20dSToomas Soome {
2204472cd20dSToomas Soome     requestIOEvents(eventSource, taskName, callback, context, PosixEventFlag_Write);
22055ffb0c9bSToomas Soome }
22064b22b933Srs 
22074b22b933Srs // Remove a file descriptor from the set that mDNSPosixRunEventLoopOnce() listens to.
stopReadOrWriteEvents(int fd,mDNSBool freeContext,mDNSBool removeContext,int flags)2208472cd20dSToomas Soome mDNSlocal mStatus stopReadOrWriteEvents(int fd, mDNSBool freeContext, mDNSBool removeContext, int flags)
22095ffb0c9bSToomas Soome {
2210472cd20dSToomas Soome     PosixEventSource *iSource, **epp = &gEventSources;
22115ffb0c9bSToomas Soome 
2212472cd20dSToomas Soome     while (*epp)
22135ffb0c9bSToomas Soome     {
2214472cd20dSToomas Soome         iSource = *epp;
22155ffb0c9bSToomas Soome         if (fd == iSource->fd)
22165ffb0c9bSToomas Soome         {
2217472cd20dSToomas Soome             if (flags & PosixEventFlag_Read)
2218472cd20dSToomas Soome             {
2219472cd20dSToomas Soome                 iSource->readCallback = NULL;
2220472cd20dSToomas Soome                 iSource->readContext = NULL;
2221472cd20dSToomas Soome             }
2222472cd20dSToomas Soome             if (flags & PosixEventFlag_Write)
2223472cd20dSToomas Soome             {
2224472cd20dSToomas Soome                 iSource->writeCallback = NULL;
2225472cd20dSToomas Soome                 iSource->writeContext = NULL;
2226472cd20dSToomas Soome             }
2227472cd20dSToomas Soome             if (iSource->writeCallback == NULL && iSource->readCallback == NULL)
2228472cd20dSToomas Soome             {
2229472cd20dSToomas Soome                 if (removeContext || freeContext)
2230472cd20dSToomas Soome                     *epp = iSource->next;
2231472cd20dSToomas Soome                 if (freeContext)
2232472cd20dSToomas Soome                     free(iSource);
2233472cd20dSToomas Soome             }
22345ffb0c9bSToomas Soome             return mStatus_NoError;
22355ffb0c9bSToomas Soome         }
2236472cd20dSToomas Soome         epp = &(*epp)->next;
22375ffb0c9bSToomas Soome     }
22385ffb0c9bSToomas Soome     return mStatus_NoSuchNameErr;
22395ffb0c9bSToomas Soome }
22404b22b933Srs 
2241472cd20dSToomas Soome // Some of the mDNSPosix client code relies on being able to add FDs to the event loop without
2242472cd20dSToomas Soome // providing storage for the event-related info.   mDNSPosixAddFDToEventLoop and
2243472cd20dSToomas Soome // mDNSPosixRemoveFDFromEventLoop handle the event structure storage automatically.
mDNSPosixAddFDToEventLoop(int fd,mDNSPosixEventCallback callback,void * context)2244472cd20dSToomas Soome mStatus mDNSPosixAddFDToEventLoop(int fd, mDNSPosixEventCallback callback, void *context)
2245472cd20dSToomas Soome {
2246472cd20dSToomas Soome     PosixEventSource *newSource;
2247472cd20dSToomas Soome 
2248472cd20dSToomas Soome     newSource = (PosixEventSource*) malloc(sizeof *newSource);
2249472cd20dSToomas Soome     if (NULL == newSource)
2250472cd20dSToomas Soome         return mStatus_NoMemoryErr;
2251472cd20dSToomas Soome     memset(newSource, 0, sizeof *newSource);
2252472cd20dSToomas Soome     newSource->fd = fd;
2253472cd20dSToomas Soome 
2254472cd20dSToomas Soome     requestReadEvents(newSource, "mDNSPosixAddFDToEventLoop", callback, context);
2255472cd20dSToomas Soome     return mStatus_NoError;
2256472cd20dSToomas Soome }
2257472cd20dSToomas Soome 
mDNSPosixRemoveFDFromEventLoop(int fd)2258472cd20dSToomas Soome mStatus mDNSPosixRemoveFDFromEventLoop(int fd)
2259472cd20dSToomas Soome {
2260472cd20dSToomas Soome     return stopReadOrWriteEvents(fd, mDNStrue, mDNStrue, PosixEventFlag_Read | PosixEventFlag_Write);
2261472cd20dSToomas Soome }
2262472cd20dSToomas Soome 
22634b22b933Srs // Simply note the received signal in gEventSignals.
NoteSignal(int signum)22645ffb0c9bSToomas Soome mDNSlocal void  NoteSignal(int signum)
22655ffb0c9bSToomas Soome {
22665ffb0c9bSToomas Soome     sigaddset(&gEventSignals, signum);
22675ffb0c9bSToomas Soome }
22684b22b933Srs 
22694b22b933Srs // Tell the event package to listen for signal and report it in mDNSPosixRunEventLoopOnce().
mDNSPosixListenForSignalInEventLoop(int signum)22705ffb0c9bSToomas Soome mStatus mDNSPosixListenForSignalInEventLoop(int signum)
22715ffb0c9bSToomas Soome {
22725ffb0c9bSToomas Soome     struct sigaction action;
22735ffb0c9bSToomas Soome     mStatus err;
22745ffb0c9bSToomas Soome 
22755ffb0c9bSToomas Soome     mDNSPlatformMemZero(&action, sizeof action);        // more portable than member-wise assignment
22765ffb0c9bSToomas Soome     action.sa_handler = NoteSignal;
22775ffb0c9bSToomas Soome     err = sigaction(signum, &action, (struct sigaction*) NULL);
22784b22b933Srs 
22795ffb0c9bSToomas Soome     sigaddset(&gEventSignalSet, signum);
22804b22b933Srs 
22815ffb0c9bSToomas Soome     return err;
22825ffb0c9bSToomas Soome }
22834b22b933Srs 
22844b22b933Srs // Tell the event package to stop listening for signal in mDNSPosixRunEventLoopOnce().
mDNSPosixIgnoreSignalInEventLoop(int signum)22855ffb0c9bSToomas Soome mStatus mDNSPosixIgnoreSignalInEventLoop(int signum)
22865ffb0c9bSToomas Soome {
22875ffb0c9bSToomas Soome     struct sigaction action;
22885ffb0c9bSToomas Soome     mStatus err;
22895ffb0c9bSToomas Soome 
22905ffb0c9bSToomas Soome     mDNSPlatformMemZero(&action, sizeof action);        // more portable than member-wise assignment
22915ffb0c9bSToomas Soome     action.sa_handler = SIG_DFL;
22925ffb0c9bSToomas Soome     err = sigaction(signum, &action, (struct sigaction*) NULL);
22934b22b933Srs 
22945ffb0c9bSToomas Soome     sigdelset(&gEventSignalSet, signum);
22954b22b933Srs 
22965ffb0c9bSToomas Soome     return err;
22975ffb0c9bSToomas Soome }
22984b22b933Srs 
22994b22b933Srs // Do a single pass through the attendent event sources and dispatch any found to their callbacks.
23004b22b933Srs // 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)23015ffb0c9bSToomas Soome mStatus mDNSPosixRunEventLoopOnce(mDNS *m, const struct timeval *pTimeout,
23025ffb0c9bSToomas Soome                                   sigset_t *pSignalsReceived, mDNSBool *pDataDispatched)
23035ffb0c9bSToomas Soome {
2304472cd20dSToomas Soome     fd_set listenFDs;
2305472cd20dSToomas Soome     fd_set writeFDs;
2306472cd20dSToomas Soome     int numFDs = 0, numReady;
23075ffb0c9bSToomas Soome     struct timeval timeout = *pTimeout;
23085ffb0c9bSToomas Soome 
2309472cd20dSToomas Soome     // 1. Set up the fd_set as usual here.
2310472cd20dSToomas Soome     // This example client has no file descriptors of its own,
2311472cd20dSToomas Soome     // but a real application would call FD_SET to add them to the set here
2312472cd20dSToomas Soome     FD_ZERO(&listenFDs);
2313472cd20dSToomas Soome     FD_ZERO(&writeFDs);
2314472cd20dSToomas Soome 
2315472cd20dSToomas Soome     // 2. Set up the timeout.
2316472cd20dSToomas Soome     mDNSPosixGetNextDNSEventTime(m, &timeout);
23175ffb0c9bSToomas Soome 
2318472cd20dSToomas Soome     // Include the sockets that are listening to the wire in our select() set
2319472cd20dSToomas Soome     mDNSPosixGetFDSetForSelect(m, &numFDs, &listenFDs, &writeFDs);
2320472cd20dSToomas Soome     numReady = select(numFDs, &listenFDs, &writeFDs, (fd_set*) NULL, &timeout);
23215ffb0c9bSToomas Soome 
23225ffb0c9bSToomas Soome     if (numReady > 0)
23235ffb0c9bSToomas Soome     {
2324472cd20dSToomas Soome         mDNSPosixProcessFDSet(m, &listenFDs, &writeFDs);
23255ffb0c9bSToomas Soome         *pDataDispatched = mDNStrue;
23265ffb0c9bSToomas Soome     }
2327472cd20dSToomas Soome     else if (numReady < 0)
2328472cd20dSToomas Soome     {
2329472cd20dSToomas Soome 	if (errno != EINTR) {
2330472cd20dSToomas Soome             // This should never happen, represents a coding error, and is not recoverable, since
2331472cd20dSToomas Soome             // we'll just sit here spinning and never receive another event.   The usual reason for
2332472cd20dSToomas Soome             // it to happen is that an FD was closed but not removed from the event list.
2333472cd20dSToomas Soome             LogMsg("select failed: %s", strerror(errno));
2334472cd20dSToomas Soome             abort();
2335472cd20dSToomas Soome         }
2336472cd20dSToomas Soome     }
23375ffb0c9bSToomas Soome     else
23385ffb0c9bSToomas Soome         *pDataDispatched = mDNSfalse;
23395ffb0c9bSToomas Soome 
23405ffb0c9bSToomas Soome     (void) sigprocmask(SIG_BLOCK, &gEventSignalSet, (sigset_t*) NULL);
23415ffb0c9bSToomas Soome     *pSignalsReceived = gEventSignals;
23425ffb0c9bSToomas Soome     sigemptyset(&gEventSignals);
23435ffb0c9bSToomas Soome     (void) sigprocmask(SIG_UNBLOCK, &gEventSignalSet, (sigset_t*) NULL);
23445ffb0c9bSToomas Soome 
23455ffb0c9bSToomas Soome     return mStatus_NoError;
23465ffb0c9bSToomas Soome }
2347