xref: /illumos-gate/usr/src/contrib/mDNSResponder/mDNSPosix/mDNSPosix.c (revision dd72704bd9e794056c558153663c739e2012d721)
1 /* -*- Mode: C; tab-width: 4; c-file-style: "bsd"; c-basic-offset: 4; fill-column: 108; indent-tabs-mode: nil; -*-
2  *
3  * Copyright (c) 2002-2019 Apple Inc. All rights reserved.
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  *     http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  *
17  */
18 
19 #include "mDNSEmbeddedAPI.h"           // Defines the interface provided to the client layer above
20 #include "DNSCommon.h"
21 #include "mDNSPosix.h"               // Defines the specific types needed to run mDNS on this platform
22 #include "PlatformCommon.h"
23 #include "dns_sd.h"
24 
25 #include <assert.h>
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <errno.h>
29 #include <string.h>
30 #include <unistd.h>
31 #include <syslog.h>
32 #include <stdarg.h>
33 #include <fcntl.h>
34 #include <sys/types.h>
35 #include <sys/time.h>
36 #include <sys/socket.h>
37 #include <sys/uio.h>
38 #include <sys/select.h>
39 #include <netinet/in.h>
40 #include <arpa/inet.h>
41 #include <time.h>                   // platform support for UTC time
42 #include <ifaddrs.h>
43 
44 #if USES_NETLINK
45 #include <asm/types.h>
46 #include <linux/netlink.h>
47 #include <linux/rtnetlink.h>
48 #else // USES_NETLINK
49 #include <net/route.h>
50 #include <net/if.h>
51 #endif // USES_NETLINK
52 
53 #include "mDNSUNP.h"
54 #include "GenLinkedList.h"
55 #include "dnsproxy.h"
56 
57 // ***************************************************************************
58 // Structures
59 
60 // Context record for interface change callback
61 struct IfChangeRec
62 {
63     int NotifySD;
64     mDNS *mDNS;
65 };
66 typedef struct IfChangeRec IfChangeRec;
67 
68 // Note that static data is initialized to zero in (modern) C.
69 static PosixEventSource *gEventSources;             // linked list of PosixEventSource's
70 static sigset_t gEventSignalSet;                // Signals which event loop listens for
71 static sigset_t gEventSignals;                  // Signals which were received while inside loop
72 
73 static PosixNetworkInterface *gRecentInterfaces;
74 
75 // ***************************************************************************
76 // Globals (for debugging)
77 
78 static int num_registered_interfaces = 0;
79 static int num_pkts_accepted = 0;
80 static int num_pkts_rejected = 0;
81 
82 // ***************************************************************************
83 // Locals
84 mDNSlocal void requestReadEvents(PosixEventSource *eventSource,
85                                     const char *taskName, mDNSPosixEventCallback callback, void *context);
86 mDNSlocal mStatus stopReadOrWriteEvents(int fd, mDNSBool freeSource, mDNSBool removeSource, int flags);
87 mDNSlocal void requestWriteEvents(PosixEventSource *eventSource,
88                                      const char *taskName, mDNSPosixEventCallback callback, void *context);
89 // ***************************************************************************
90 // Functions
91 
92 #if MDNS_MALLOC_DEBUGGING
93 mDNSexport void mDNSPlatformValidateLists(void)
94 {
95     // This should validate gEventSources and any other Posix-specific stuff that gets allocated.
96 }
97 #endif
98 
99 int gMDNSPlatformPosixVerboseLevel = 0;
100 
101 #define PosixErrorToStatus(errNum) ((errNum) == 0 ? mStatus_NoError : mStatus_UnknownErr)
102 
103 mDNSlocal void SockAddrTomDNSAddr(const struct sockaddr *const sa, mDNSAddr *ipAddr, mDNSIPPort *ipPort)
104 {
105     switch (sa->sa_family)
106     {
107     case AF_INET:
108     {
109         struct sockaddr_in *sin          = (struct sockaddr_in*)sa;
110         ipAddr->type                     = mDNSAddrType_IPv4;
111         ipAddr->ip.v4.NotAnInteger       = sin->sin_addr.s_addr;
112         if (ipPort) ipPort->NotAnInteger = sin->sin_port;
113         break;
114     }
115 
116 #if HAVE_IPV6
117     case AF_INET6:
118     {
119         struct sockaddr_in6 *sin6        = (struct sockaddr_in6*)sa;
120 #ifndef NOT_HAVE_SA_LEN
121         assert(sin6->sin6_len == sizeof(*sin6));
122 #endif
123         ipAddr->type                     = mDNSAddrType_IPv6;
124         ipAddr->ip.v6                    = *(mDNSv6Addr*)&sin6->sin6_addr;
125         if (ipPort) ipPort->NotAnInteger = sin6->sin6_port;
126         break;
127     }
128 #endif
129 
130     default:
131         verbosedebugf("SockAddrTomDNSAddr: Uknown address family %d\n", sa->sa_family);
132         ipAddr->type = mDNSAddrType_None;
133         if (ipPort) ipPort->NotAnInteger = 0;
134         break;
135     }
136 }
137 
138 #if COMPILER_LIKES_PRAGMA_MARK
139 #pragma mark ***** Send and Receive
140 #endif
141 
142 // mDNS core calls this routine when it needs to send a packet.
143 mDNSexport mStatus mDNSPlatformSendUDP(const mDNS *const m, const void *const msg, const mDNSu8 *const end,
144                                        mDNSInterfaceID InterfaceID, UDPSocket *src, const mDNSAddr *dst,
145                                        mDNSIPPort dstPort, mDNSBool useBackgroundTrafficClass)
146 {
147     int err = 0;
148     struct sockaddr_storage to;
149     PosixNetworkInterface * thisIntf = (PosixNetworkInterface *)(InterfaceID);
150     int sendingsocket = -1;
151 
152     (void)src;  // Will need to use this parameter once we implement mDNSPlatformUDPSocket/mDNSPlatformUDPClose
153     (void) useBackgroundTrafficClass;
154 
155     assert(m != NULL);
156     assert(msg != NULL);
157     assert(end != NULL);
158     assert((((char *) end) - ((char *) msg)) > 0);
159 
160     if (dstPort.NotAnInteger == 0)
161     {
162         LogMsg("mDNSPlatformSendUDP: Invalid argument -dstPort is set to 0");
163         return PosixErrorToStatus(EINVAL);
164     }
165     if (dst->type == mDNSAddrType_IPv4)
166     {
167         struct sockaddr_in *sin = (struct sockaddr_in*)&to;
168 #ifndef NOT_HAVE_SA_LEN
169         sin->sin_len            = sizeof(*sin);
170 #endif
171         sin->sin_family         = AF_INET;
172         sin->sin_port           = dstPort.NotAnInteger;
173         sin->sin_addr.s_addr    = dst->ip.v4.NotAnInteger;
174         sendingsocket           = thisIntf ? thisIntf->multicastSocket4 : m->p->unicastSocket4;
175     }
176 
177 #if HAVE_IPV6
178     else if (dst->type == mDNSAddrType_IPv6)
179     {
180         struct sockaddr_in6 *sin6 = (struct sockaddr_in6*)&to;
181         mDNSPlatformMemZero(sin6, sizeof(*sin6));
182 #ifndef NOT_HAVE_SA_LEN
183         sin6->sin6_len            = sizeof(*sin6);
184 #endif
185         sin6->sin6_family         = AF_INET6;
186         sin6->sin6_port           = dstPort.NotAnInteger;
187         sin6->sin6_addr           = *(struct in6_addr*)&dst->ip.v6;
188         sendingsocket             = thisIntf ? thisIntf->multicastSocket6 : m->p->unicastSocket6;
189     }
190 #endif
191 
192     if (sendingsocket >= 0)
193         err = sendto(sendingsocket, msg, (char*)end - (char*)msg, 0, (struct sockaddr *)&to, GET_SA_LEN(to));
194 
195     if      (err > 0) err = 0;
196     else if (err < 0)
197     {
198         static int MessageCount = 0;
199         // Don't report EHOSTDOWN (i.e. ARP failure), ENETDOWN, or no route to host for unicast destinations
200         if (!mDNSAddressIsAllDNSLinkGroup(dst))
201             if (errno == EHOSTDOWN || errno == ENETDOWN || errno == EHOSTUNREACH || errno == ENETUNREACH) return(mStatus_TransientErr);
202 
203 	/* dont report ENETUNREACH */
204 	if (errno == ENETUNREACH) return(mStatus_TransientErr);
205 
206         if (MessageCount < 1000)
207         {
208             MessageCount++;
209             if (thisIntf)
210                 LogMsg("mDNSPlatformSendUDP got error %d (%s) sending packet to %#a on interface %#a/%s/%d",
211                        errno, strerror(errno), dst, &thisIntf->coreIntf.ip, thisIntf->intfName, thisIntf->index);
212             else
213                 LogMsg("mDNSPlatformSendUDP got error %d (%s) sending packet to %#a", errno, strerror(errno), dst);
214         }
215     }
216 
217     return PosixErrorToStatus(err);
218 }
219 
220 mDNSlocal void TCPReadCallback(int fd, void *context)
221 {
222     TCPSocket *sock = context;
223     (void)fd;
224 
225     if (sock->flags & kTCPSocketFlags_UseTLS)
226     {
227         // implement
228     }
229     else
230     {
231         sock->callback(sock, sock->context, mDNSfalse, sock->err);
232     }
233 }
234 
235 mDNSlocal void tcpConnectCallback(int fd, void *context)
236 {
237     TCPSocket *sock = context;
238     mDNSBool c = !sock->connected;
239     int result;
240     socklen_t len = sizeof result;
241 
242     sock->connected = mDNStrue;
243 
244     if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &result, &len) < 0)
245     {
246         LogInfo("ERROR: TCPConnectCallback - unable to get connect error: socket %d: Error %d (%s)",
247                sock->events.fd, result, strerror(result));
248         sock->err = mStatus_ConnFailed;
249     }
250     else
251     {
252         if (result != 0)
253         {
254             sock->err = mStatus_ConnFailed;
255             if (result == EHOSTUNREACH || result == EADDRNOTAVAIL || result == ENETDOWN)
256             {
257                 LogInfo("ERROR: TCPConnectCallback - connect failed: socket %d: Error %d (%s)",
258                         sock->events.fd, result, strerror(result));
259             }
260             else
261             {
262                 LogMsg("ERROR: TCPConnectCallback - connect failed: socket %d: Error %d (%s)",
263                        sock->events.fd, result, strerror(result));
264             }
265         }
266         else
267         {
268             // The connection succeeded.
269             sock->connected = mDNStrue;
270             // Select for read events.
271             sock->events.fd = fd;
272             requestReadEvents(&sock->events, "mDNSPosix::tcpConnectCallback", TCPReadCallback, sock);
273         }
274     }
275 
276     if (sock->callback)
277     {
278         sock->callback(sock, sock->context, c, sock->err);
279         // Here sock must be assumed to be invalid, in case the callback freed it.
280         return;
281     }
282 }
283 
284 // This routine is called when the main loop detects that data is available on a socket.
285 mDNSlocal void SocketDataReady(mDNS *const m, PosixNetworkInterface *intf, int skt)
286 {
287     mDNSAddr senderAddr, destAddr;
288     mDNSIPPort senderPort;
289     ssize_t packetLen;
290     DNSMessage packet;
291     struct my_in_pktinfo packetInfo;
292     struct sockaddr_storage from;
293     socklen_t fromLen;
294     int flags;
295     mDNSu8 ttl;
296     mDNSBool reject;
297     const mDNSInterfaceID InterfaceID = intf ? intf->coreIntf.InterfaceID : NULL;
298 
299     assert(m    != NULL);
300     assert(skt  >= 0);
301 
302     fromLen = sizeof(from);
303     flags   = 0;
304     packetLen = recvfrom_flags(skt, &packet, sizeof(packet), &flags, (struct sockaddr *) &from, &fromLen, &packetInfo, &ttl);
305 
306     if (packetLen >= 0)
307     {
308         SockAddrTomDNSAddr((struct sockaddr*)&from, &senderAddr, &senderPort);
309         SockAddrTomDNSAddr((struct sockaddr*)&packetInfo.ipi_addr, &destAddr, NULL);
310 
311         // If we have broken IP_RECVDSTADDR functionality (so far
312         // I've only seen this on OpenBSD) then apply a hack to
313         // convince mDNS Core that this isn't a spoof packet.
314         // Basically what we do is check to see whether the
315         // packet arrived as a multicast and, if so, set its
316         // destAddr to the mDNS address.
317         //
318         // I must admit that I could just be doing something
319         // wrong on OpenBSD and hence triggering this problem
320         // but I'm at a loss as to how.
321         //
322         // If this platform doesn't have IP_PKTINFO or IP_RECVDSTADDR, then we have
323         // no way to tell the destination address or interface this packet arrived on,
324         // so all we can do is just assume it's a multicast
325 
326         #if HAVE_BROKEN_RECVDSTADDR || (!defined(IP_PKTINFO) && !defined(IP_RECVDSTADDR))
327         if ((destAddr.NotAnInteger == 0) && (flags & MSG_MCAST))
328         {
329             destAddr.type = senderAddr.type;
330             if      (senderAddr.type == mDNSAddrType_IPv4) destAddr.ip.v4 = AllDNSLinkGroup_v4.ip.v4;
331             else if (senderAddr.type == mDNSAddrType_IPv6) destAddr.ip.v6 = AllDNSLinkGroup_v6.ip.v6;
332         }
333         #endif
334 
335         // We only accept the packet if the interface on which it came
336         // in matches the interface associated with this socket.
337         // We do this match by name or by index, depending on which
338         // information is available.  recvfrom_flags sets the name
339         // to "" if the name isn't available, or the index to -1
340         // if the index is available.  This accomodates the various
341         // different capabilities of our target platforms.
342 
343         reject = mDNSfalse;
344         if (!intf)
345         {
346             // Ignore multicasts accidentally delivered to our unicast receiving socket
347             if (mDNSAddrIsDNSMulticast(&destAddr)) packetLen = -1;
348         }
349         else
350         {
351             if      (packetInfo.ipi_ifname[0] != 0) reject = (strcmp(packetInfo.ipi_ifname, intf->intfName) != 0);
352             else if (packetInfo.ipi_ifindex != -1) reject = (packetInfo.ipi_ifindex != intf->index);
353 
354             if (reject)
355             {
356                 verbosedebugf("SocketDataReady ignored a packet from %#a to %#a on interface %s/%d expecting %#a/%s/%d/%d",
357                               &senderAddr, &destAddr, packetInfo.ipi_ifname, packetInfo.ipi_ifindex,
358                               &intf->coreIntf.ip, intf->intfName, intf->index, skt);
359                 packetLen = -1;
360                 num_pkts_rejected++;
361                 if (num_pkts_rejected > (num_pkts_accepted + 1) * (num_registered_interfaces + 1) * 2)
362                 {
363                     fprintf(stderr,
364                             "*** WARNING: Received %d packets; Accepted %d packets; Rejected %d packets because of interface mismatch\n",
365                             num_pkts_accepted + num_pkts_rejected, num_pkts_accepted, num_pkts_rejected);
366                     num_pkts_accepted = 0;
367                     num_pkts_rejected = 0;
368                 }
369             }
370             else
371             {
372                 verbosedebugf("SocketDataReady got a packet from %#a to %#a on interface %#a/%s/%d/%d",
373                               &senderAddr, &destAddr, &intf->coreIntf.ip, intf->intfName, intf->index, skt);
374                 num_pkts_accepted++;
375             }
376         }
377     }
378 
379     if (packetLen >= 0)
380         mDNSCoreReceive(m, &packet, (mDNSu8 *)&packet + packetLen,
381                         &senderAddr, senderPort, &destAddr, MulticastDNSPort, InterfaceID);
382 }
383 
384 mDNSexport TCPSocket *mDNSPlatformTCPSocket(TCPSocketFlags flags, mDNSAddr_Type addrType, mDNSIPPort * port,
385                                             domainname *hostname, mDNSBool useBackgroundTrafficClass)
386 {
387     TCPSocket *sock;
388     int len = sizeof (TCPSocket);
389 
390     (void)useBackgroundTrafficClass;
391 
392     if (hostname)
393     {
394         len += sizeof (domainname);
395     }
396     sock = malloc(len);
397 
398     if (sock == NULL)
399     {
400         LogMsg("mDNSPlatformTCPSocket: no memory for socket");
401         return NULL;
402     }
403     memset(sock, 0, sizeof *sock);
404 
405     if (hostname)
406     {
407         sock->hostname = (domainname *)(sock + 1);
408         LogMsg("mDNSPlatformTCPSocket: hostname %##s", hostname->c);
409         AssignDomainName(sock->hostname, hostname);
410     }
411 
412     sock->events.fd = -1;
413     if (!mDNSPosixTCPSocketSetup(&sock->events.fd, addrType, port, &sock->port))
414     {
415       if (sock->events.fd != -1) close(sock->events.fd);
416       free(sock);
417       return mDNSNULL;
418     }
419 
420     // Set up the other fields in the structure.
421     sock->flags = flags;
422     sock->err = mStatus_NoError;
423     sock->setup = mDNSfalse;
424     sock->connected = mDNSfalse;
425     return sock;
426 }
427 
428 mDNSexport mStatus mDNSPlatformTCPSocketSetCallback(TCPSocket *sock, TCPConnectionCallback callback, void *context)
429 {
430     sock->callback = callback;
431     sock->context = context;
432     return mStatus_NoError;
433 }
434 
435 mDNSexport TCPSocket *mDNSPlatformTCPAccept(TCPSocketFlags flags, int fd)
436 {
437     TCPSocket *sock;
438 
439     // XXX Add!
440     if (flags & kTCPSocketFlags_UseTLS)
441     {
442     return mDNSNULL; // not supported yet.
443     }
444 
445     sock = (TCPSocket *) mDNSPlatformMemAllocateClear(sizeof *sock);
446     if (!sock)
447     {
448         return mDNSNULL;
449     }
450 
451     sock->events.fd = fd;
452     sock->flags = flags;
453     sock->connected = mDNStrue;
454     return sock;
455 }
456 
457 
458 mDNSlocal void tcpListenCallback(int fd, void *context)
459 {
460     TCPListener *listener = context;
461     TCPSocket *sock;
462 
463     sock = mDNSPosixDoTCPListenCallback(fd, listener->addressType, listener->socketFlags,
464                                  listener->callback, listener->context);
465     if (sock != NULL)
466     {
467         requestReadEvents(&sock->events, "mDNSPosix::tcpListenCallback", TCPReadCallback, sock);
468     }
469 }
470 
471 mDNSexport TCPListener *mDNSPlatformTCPListen(mDNSAddr_Type addrType, mDNSIPPort *port, mDNSAddr *addr,
472                                               TCPSocketFlags socketFlags, mDNSBool reuseAddr, int queueLength,
473                                               TCPAcceptedCallback callback, void *context)
474 {
475     TCPListener *ret;
476     int fd = -1;
477 
478     if (!mDNSPosixTCPListen(&fd, addrType, port, addr, reuseAddr, queueLength))
479     {
480         if (fd != -1)
481         {
482             close(fd);
483         }
484         return mDNSNULL;
485     }
486 
487     // Allocate a listener structure
488     ret = (TCPListener *) mDNSPlatformMemAllocateClear(sizeof *ret);
489     if (ret == NULL)
490     {
491         LogMsg("mDNSPlatformTCPListen: no memory for TCPListener struct.");
492         close(fd);
493         return mDNSNULL;
494     }
495     ret->events.fd = fd;
496     ret->callback = callback;
497     ret->context = context;
498     ret->addressType = addrType;
499     ret->socketFlags = socketFlags;
500 
501     // When we get a connection, mDNSPosixListenCallback will be called, and it will invoke the
502     // callback we were passed.
503     requestReadEvents(&ret->events, "tcpListenCallback", tcpListenCallback, ret);
504     return ret;
505 }
506 
507 mDNSexport int mDNSPlatformTCPGetFD(TCPSocket *sock)
508 {
509     return sock->events.fd;
510 }
511 
512 mDNSexport mStatus mDNSPlatformTCPConnect(TCPSocket *sock, const mDNSAddr *dst, mDNSOpaque16 dstport,
513                                           mDNSInterfaceID InterfaceID, TCPConnectionCallback callback, void *context)
514 {
515     int result;
516     union {
517         struct sockaddr sa;
518         struct sockaddr_in sin;
519         struct sockaddr_in6 sin6;
520     } addr;
521     socklen_t len;
522 
523     sock->callback = callback;
524     sock->context = context;
525     sock->setup = mDNSfalse;
526     sock->connected = mDNSfalse;
527     sock->err = mStatus_NoError;
528 
529     result = fcntl(sock->events.fd, F_GETFL, 0);
530     if (result < 0)
531     {
532         LogMsg("mDNSPlatformTCPConnect: F_GETFL failed: %s", strerror(errno));
533         return mStatus_UnknownErr;
534     }
535 
536     result = fcntl(sock->events.fd, F_SETFL, result | O_NONBLOCK);
537     if (result < 0)
538     {
539         LogMsg("mDNSPlatformTCPConnect: F_SETFL failed: %s", strerror(errno));
540         return mStatus_UnknownErr;
541     }
542 
543     // If we've been asked to bind to a single interface, do it.  See comment in mDNSMacOSX.c for more info.
544     if (InterfaceID)
545     {
546         PosixNetworkInterface *iface = (PosixNetworkInterface *)InterfaceID;
547 #if defined(SO_BINDTODEVICE)
548         result = setsockopt(sock->events.fd,
549                             SOL_SOCKET, SO_BINDTODEVICE, iface->intfName, strlen(iface->intfName));
550         if (result < 0)
551         {
552             LogMsg("mDNSPlatformTCPConnect: SO_BINDTODEVICE failed on %s: %s", iface->intfName, strerror(errno));
553             return mStatus_BadParamErr;
554         }
555 #else
556         if (dst->type == mDNSAddrType_IPv4)
557         {
558 #if defined(IP_BOUND_IF)
559             result = setsockopt(sock->events.fd, IPPROTO_IP, IP_BOUND_IF, &iface->index, sizeof iface->index);
560             if (result < 0)
561             {
562                 LogMsg("mDNSPlatformTCPConnect: IP_BOUND_IF failed on %s (%d): %s",
563                        iface->intfName, iface->index, strerror(errno));
564                 return mStatus_BadParamErr;
565             }
566 #else
567             (void)iface;
568 #endif // IP_BOUND_IF
569         }
570         else
571         { // IPv6
572 #if defined(IPV6_BOUND_IF)
573             result = setsockopt(sock->events.fd, IPPROTO_IPV6, IPV6_BOUND_IF, &iface->index, sizeof iface->index);
574             if (result < 0)
575             {
576                 LogMsg("mDNSPlatformTCPConnect: IP_BOUND_IF failed on %s (%d): %s",
577                        iface->intfName, iface->index, strerror(errno));
578                 return mStatus_BadParamErr;
579             }
580 #else
581             (void)iface;
582 #endif // IPV6_BOUND_IF
583         }
584 #endif // SO_BINDTODEVICE
585     }
586 
587     memset(&addr, 0, sizeof addr);
588     if (dst->type == mDNSAddrType_IPv4)
589     {
590         addr.sa.sa_family = AF_INET;
591         addr.sin.sin_port = dstport.NotAnInteger;
592         len = sizeof (struct sockaddr_in);
593         addr.sin.sin_addr.s_addr = dst->ip.v4.NotAnInteger;
594     }
595     else
596     {
597         addr.sa.sa_family = AF_INET6;
598         len = sizeof (struct sockaddr_in6);
599         addr.sin6.sin6_port = dstport.NotAnInteger;
600         memcpy(&addr.sin6.sin6_addr.s6_addr, &dst->ip.v6, sizeof addr.sin6.sin6_addr.s6_addr);
601     }
602 #ifndef NOT_HAVE_SA_LEN
603     addr.sa.sa_len = len;
604 #endif
605 
606     result = connect(sock->events.fd, (struct sockaddr *)&addr, len);
607     if (result < 0)
608     {
609         if (errno == EINPROGRESS)
610         {
611             requestWriteEvents(&sock->events, "mDNSPlatformConnect", tcpConnectCallback, sock);
612             return mStatus_ConnPending;
613         }
614         if (errno == EHOSTUNREACH || errno == EADDRNOTAVAIL || errno == ENETDOWN)
615         {
616             LogInfo("ERROR: mDNSPlatformTCPConnect - connect failed: socket %d: Error %d (%s)",
617                     sock->events.fd, errno, strerror(errno));
618         }
619         else
620         {
621             LogMsg("ERROR: mDNSPlatformTCPConnect - connect failed: socket %d: Error %d (%s) length %d",
622                    sock->events.fd, errno, strerror(errno), len);
623         }
624         return mStatus_ConnFailed;
625     }
626 
627     LogMsg("NOTE: mDNSPlatformTCPConnect completed synchronously");
628     return mStatus_NoError;
629 }
630 
631 mDNSexport void mDNSPlatformTCPCloseConnection(TCPSocket *sock)
632 {
633     if (sock)
634     { // can sock really be NULL when this is called?
635         shutdown(sock->events.fd, SHUT_RDWR);
636         stopReadOrWriteEvents(sock->events.fd, mDNSfalse, mDNStrue,
637                               PosixEventFlag_Read | PosixEventFlag_Write);
638         close(sock->events.fd);
639         free(sock);
640     }
641 }
642 
643 mDNSexport long mDNSPlatformReadTCP(TCPSocket *sock, void *buf, unsigned long buflen, mDNSBool * closed)
644 {
645     ssize_t nread;
646 
647     *closed = mDNSfalse;
648     if (sock->flags & kTCPSocketFlags_UseTLS)
649     {
650         // Implement...
651         nread = -1;
652         *closed = mDNStrue;
653     } else {
654         nread = mDNSPosixReadTCP(sock->events.fd, buf, buflen, closed);
655     }
656     return nread;
657 }
658 
659 mDNSexport mDNSBool mDNSPlatformTCPWritable(TCPSocket *sock)
660 {
661     fd_set w = { 0 };
662     int nfds = sock->events.fd + 1;
663     int count;
664     struct timeval tv;
665 
666     if (nfds > FD_SETSIZE)
667     {
668         LogMsg("ERROR: mDNSPlatformTCPWritable called on an fd that won't fit in an fd_set.");
669         return mDNStrue; // hope for the best?
670     }
671     FD_SET(sock->events.fd, &w);
672     tv.tv_sec = tv.tv_usec = 0;
673     count = select(nfds, NULL, &w, NULL, &tv);
674     if (count > 0)
675     {
676         return mDNStrue;
677     }
678     return mDNSfalse;
679 }
680 
681 mDNSexport long mDNSPlatformWriteTCP(TCPSocket *sock, const char *msg, unsigned long len)
682 {
683     if (sock->flags & kTCPSocketFlags_UseTLS)
684     {
685         // implement
686         return -1;
687     }
688     else
689     {
690         return mDNSPosixWriteTCP(sock->events.fd, msg, len);
691     }
692 }
693 
694 mDNSexport UDPSocket *mDNSPlatformUDPSocket(mDNSIPPort port)
695 {
696     (void)port;         // Unused
697     return NULL;
698 }
699 
700 mDNSexport void           mDNSPlatformUDPClose(UDPSocket *sock)
701 {
702     (void)sock;         // Unused
703 }
704 
705 mDNSexport void mDNSPlatformUpdateProxyList(const mDNSInterfaceID InterfaceID)
706 {
707     (void)InterfaceID;          // Unused
708 }
709 
710 mDNSexport void mDNSPlatformSendRawPacket(const void *const msg, const mDNSu8 *const end, mDNSInterfaceID InterfaceID)
711 {
712     (void)msg;          // Unused
713     (void)end;          // Unused
714     (void)InterfaceID;          // Unused
715 }
716 
717 mDNSexport void mDNSPlatformSetLocalAddressCacheEntry(const mDNSAddr *const tpa, const mDNSEthAddr *const tha, mDNSInterfaceID InterfaceID)
718 {
719     (void)tpa;          // Unused
720     (void)tha;          // Unused
721     (void)InterfaceID;          // Unused
722 }
723 
724 mDNSexport mStatus mDNSPlatformTLSSetupCerts(void)
725 {
726     return(mStatus_UnsupportedErr);
727 }
728 
729 mDNSexport void mDNSPlatformTLSTearDownCerts(void)
730 {
731 }
732 
733 mDNSexport void mDNSPlatformSetAllowSleep(mDNSBool allowSleep, const char *reason)
734 {
735     (void) allowSleep;
736     (void) reason;
737 }
738 
739 #if COMPILER_LIKES_PRAGMA_MARK
740 #pragma mark -
741 #pragma mark - /etc/hosts support
742 #endif
743 
744 mDNSexport void FreeEtcHosts(mDNS *const m, AuthRecord *const rr, mStatus result)
745 {
746     (void)m;  // unused
747     (void)rr;
748     (void)result;
749 }
750 
751 
752 #if COMPILER_LIKES_PRAGMA_MARK
753 #pragma mark ***** DDNS Config Platform Functions
754 #endif
755 
756 mDNSexport mDNSBool mDNSPlatformSetDNSConfig(mDNSBool setservers, mDNSBool setsearch, domainname *const fqdn, DNameListElem **RegDomains,
757     DNameListElem **BrowseDomains, mDNSBool ackConfig)
758 {
759     (void) setservers;
760     (void) setsearch;
761     (void) ackConfig;
762 
763     if (fqdn         ) fqdn->c[0]      = 0;
764     if (RegDomains   ) *RegDomains     = NULL;
765     if (BrowseDomains) *BrowseDomains  = NULL;
766 
767     return mDNStrue;
768 }
769 
770 mDNSexport mStatus mDNSPlatformGetPrimaryInterface(mDNSAddr * v4, mDNSAddr * v6, mDNSAddr * router)
771 {
772     (void) v4;
773     (void) v6;
774     (void) router;
775 
776     return mStatus_UnsupportedErr;
777 }
778 
779 mDNSexport void mDNSPlatformDynDNSHostNameStatusChanged(const domainname *const dname, const mStatus status)
780 {
781     (void) dname;
782     (void) status;
783 }
784 
785 #if COMPILER_LIKES_PRAGMA_MARK
786 #pragma mark ***** Init and Term
787 #endif
788 
789 // This gets the current hostname, truncating it at the first dot if necessary
790 mDNSlocal void GetUserSpecifiedRFC1034ComputerName(domainlabel *const namelabel)
791 {
792     int len = 0;
793     gethostname((char *)(&namelabel->c[1]), MAX_DOMAIN_LABEL);
794     while (len < MAX_DOMAIN_LABEL && namelabel->c[len+1] && namelabel->c[len+1] != '.') len++;
795     namelabel->c[0] = len;
796 }
797 
798 // On OS X this gets the text of the field labelled "Computer Name" in the Sharing Prefs Control Panel
799 // Other platforms can either get the information from the appropriate place,
800 // or they can alternatively just require all registering services to provide an explicit name
801 mDNSlocal void GetUserSpecifiedFriendlyComputerName(domainlabel *const namelabel)
802 {
803     // On Unix we have no better name than the host name, so we just use that.
804     GetUserSpecifiedRFC1034ComputerName(namelabel);
805 }
806 
807 mDNSexport int ParseDNSServers(mDNS *m, const char *filePath)
808 {
809     char line[256];
810     char nameserver[16];
811     char keyword[11];
812     int numOfServers = 0;
813     FILE *fp = fopen(filePath, "r");
814     if (fp == NULL) return -1;
815     while (fgets(line,sizeof(line),fp))
816     {
817         struct in_addr ina;
818         line[255]='\0';     // just to be safe
819         if (sscanf(line,"%10s %15s", keyword, nameserver) != 2) continue;   // it will skip whitespaces
820         if (strncasecmp(keyword,"nameserver",10)) continue;
821         if (inet_aton(nameserver, (struct in_addr *)&ina) != 0)
822         {
823             mDNSAddr DNSAddr;
824             DNSAddr.type = mDNSAddrType_IPv4;
825             DNSAddr.ip.v4.NotAnInteger = ina.s_addr;
826             mDNS_AddDNSServer(m, NULL, mDNSInterface_Any, 0, &DNSAddr, UnicastDNSPort, kScopeNone, 0, mDNSfalse, mDNSfalse, mDNSfalse, mDNSfalse, 0, mDNStrue, mDNStrue, mDNSfalse);
827             numOfServers++;
828         }
829     }
830     fclose(fp);
831     return (numOfServers > 0) ? 0 : -1;
832 }
833 
834 // Searches the interface list looking for the named interface.
835 // Returns a pointer to if it found, or NULL otherwise.
836 mDNSlocal PosixNetworkInterface *SearchForInterfaceByName(mDNS *const m, const char *intfName)
837 {
838     PosixNetworkInterface *intf;
839 
840     assert(m != NULL);
841     assert(intfName != NULL);
842 
843     intf = (PosixNetworkInterface*)(m->HostInterfaces);
844     while ((intf != NULL) && (strcmp(intf->intfName, intfName) != 0))
845         intf = (PosixNetworkInterface *)(intf->coreIntf.next);
846 
847     return intf;
848 }
849 
850 mDNSexport mDNSInterfaceID mDNSPlatformInterfaceIDfromInterfaceIndex(mDNS *const m, mDNSu32 index)
851 {
852     PosixNetworkInterface *intf;
853 
854     assert(m != NULL);
855 
856     if (index == kDNSServiceInterfaceIndexLocalOnly) return(mDNSInterface_LocalOnly);
857     if (index == kDNSServiceInterfaceIndexP2P      ) return(mDNSInterface_P2P);
858     if (index == kDNSServiceInterfaceIndexAny      ) return(mDNSInterface_Any);
859 
860     intf = (PosixNetworkInterface*)(m->HostInterfaces);
861     while ((intf != NULL) && (mDNSu32) intf->index != index)
862         intf = (PosixNetworkInterface *)(intf->coreIntf.next);
863 
864     return (mDNSInterfaceID) intf;
865 }
866 
867 mDNSexport mDNSu32 mDNSPlatformInterfaceIndexfromInterfaceID(mDNS *const m, mDNSInterfaceID id, mDNSBool suppressNetworkChange)
868 {
869     PosixNetworkInterface *intf;
870     (void) suppressNetworkChange; // Unused
871 
872     assert(m != NULL);
873 
874     if (id == mDNSInterface_LocalOnly) return(kDNSServiceInterfaceIndexLocalOnly);
875     if (id == mDNSInterface_P2P      ) return(kDNSServiceInterfaceIndexP2P);
876     if (id == mDNSInterface_Any      ) return(kDNSServiceInterfaceIndexAny);
877 
878     intf = (PosixNetworkInterface*)(m->HostInterfaces);
879     while ((intf != NULL) && (mDNSInterfaceID) intf != id)
880         intf = (PosixNetworkInterface *)(intf->coreIntf.next);
881 
882     if (intf) return intf->index;
883 
884     // If we didn't find the interface, check the RecentInterfaces list as well
885     intf = gRecentInterfaces;
886     while ((intf != NULL) && (mDNSInterfaceID) intf != id)
887         intf = (PosixNetworkInterface *)(intf->coreIntf.next);
888 
889     return intf ? intf->index : 0;
890 }
891 
892 // Frees the specified PosixNetworkInterface structure. The underlying
893 // interface must have already been deregistered with the mDNS core.
894 mDNSlocal void FreePosixNetworkInterface(PosixNetworkInterface *intf)
895 {
896     int rv;
897     assert(intf != NULL);
898     if (intf->intfName != NULL) free((void *)intf->intfName);
899     if (intf->multicastSocket4 != -1)
900     {
901         rv = close(intf->multicastSocket4);
902         assert(rv == 0);
903     }
904 #if HAVE_IPV6
905     if (intf->multicastSocket6 != -1)
906     {
907         rv = close(intf->multicastSocket6);
908         assert(rv == 0);
909     }
910 #endif
911 
912     // Move interface to the RecentInterfaces list for a minute
913     intf->LastSeen = mDNSPlatformUTC();
914     intf->coreIntf.next = &gRecentInterfaces->coreIntf;
915     gRecentInterfaces = intf;
916 }
917 
918 // Grab the first interface, deregister it, free it, and repeat until done.
919 mDNSlocal void ClearInterfaceList(mDNS *const m)
920 {
921     assert(m != NULL);
922 
923     while (m->HostInterfaces)
924     {
925         PosixNetworkInterface *intf = (PosixNetworkInterface*)(m->HostInterfaces);
926         mDNS_DeregisterInterface(m, &intf->coreIntf, NormalActivation);
927         if (gMDNSPlatformPosixVerboseLevel > 0) fprintf(stderr, "Deregistered interface %s\n", intf->intfName);
928         FreePosixNetworkInterface(intf);
929     }
930     num_registered_interfaces = 0;
931     num_pkts_accepted = 0;
932     num_pkts_rejected = 0;
933 }
934 
935 // Sets up a send/receive socket.
936 // If mDNSIPPort port is non-zero, then it's a multicast socket on the specified interface
937 // If mDNSIPPort port is zero, then it's a randomly assigned port number, used for sending unicast queries
938 mDNSlocal int SetupSocket(struct sockaddr *intfAddr, mDNSIPPort port, int interfaceIndex, int *sktPtr)
939 {
940     int err = 0;
941     static const int kOn = 1;
942     static const int kIntTwoFiveFive = 255;
943     static const unsigned char kByteTwoFiveFive = 255;
944     const mDNSBool JoinMulticastGroup = (port.NotAnInteger != 0);
945 
946     (void) interfaceIndex;  // This parameter unused on plaforms that don't have IPv6
947     assert(intfAddr != NULL);
948     assert(sktPtr != NULL);
949     assert(*sktPtr == -1);
950 
951     // Open the socket...
952     if      (intfAddr->sa_family == AF_INET) *sktPtr = socket(PF_INET,  SOCK_DGRAM, IPPROTO_UDP);
953 #if HAVE_IPV6
954     else if (intfAddr->sa_family == AF_INET6) *sktPtr = socket(PF_INET6, SOCK_DGRAM, IPPROTO_UDP);
955 #endif
956     else return EINVAL;
957 
958     if (*sktPtr < 0) { err = errno; perror((intfAddr->sa_family == AF_INET) ? "socket AF_INET" : "socket AF_INET6"); }
959 
960     // ... with a shared UDP port, if it's for multicast receiving
961     if (err == 0 && port.NotAnInteger)
962     {
963         // <rdar://problem/20946253> Suggestions from Jonny Törnbom at Axis Communications
964         // We test for SO_REUSEADDR first, as suggested by Jonny Törnbom from Axis Communications
965         // Linux kernel versions 3.9 introduces support for socket option
966         // SO_REUSEPORT, however this is not implemented the same as on *BSD
967         // systems. Linux version implements a "port hijacking" prevention
968         // mechanism, limiting processes wanting to bind to an already existing
969         // addr:port to have the same effective UID as the first who bound it. What
970         // this meant for us was that the daemon ran as one user and when for
971         // instance mDNSClientPosix was executed by another user, it wasn't allowed
972         // to bind to the socket. Our suggestion was to switch the order in which
973         // SO_REUSEPORT and SO_REUSEADDR was tested so that SO_REUSEADDR stays on
974         // top and SO_REUSEPORT to be used only if SO_REUSEADDR doesn't exist.
975         #if defined(SO_REUSEADDR) && !defined(__MAC_OS_X_VERSION_MIN_REQUIRED)
976         err = setsockopt(*sktPtr, SOL_SOCKET, SO_REUSEADDR, &kOn, sizeof(kOn));
977         #elif defined(SO_REUSEPORT)
978         err = setsockopt(*sktPtr, SOL_SOCKET, SO_REUSEPORT, &kOn, sizeof(kOn));
979         #else
980             #error This platform has no way to avoid address busy errors on multicast.
981         #endif
982         if (err < 0) { err = errno; perror("setsockopt - SO_REUSExxxx"); }
983 
984 #if TARGET_OS_MAC
985         // Enable inbound packets on IFEF_AWDL interface.
986         // Only done for multicast sockets, since we don't expect unicast socket operations
987         // on the IFEF_AWDL interface. Operation is a no-op for other interface types.
988         #ifndef SO_RECV_ANYIF
989         #define SO_RECV_ANYIF   0x1104      /* unrestricted inbound processing */
990         #endif
991         if (setsockopt(*sktPtr, SOL_SOCKET, SO_RECV_ANYIF, &kOn, sizeof(kOn)) < 0) perror("setsockopt - SO_RECV_ANYIF");
992 #endif
993     }
994 
995     // We want to receive destination addresses and interface identifiers.
996     if (intfAddr->sa_family == AF_INET)
997     {
998         struct ip_mreq imr;
999         struct sockaddr_in bindAddr;
1000         if (err == 0)
1001         {
1002             #if defined(IP_PKTINFO)                                 // Linux
1003             err = setsockopt(*sktPtr, IPPROTO_IP, IP_PKTINFO, &kOn, sizeof(kOn));
1004             if (err < 0) { err = errno; perror("setsockopt - IP_PKTINFO"); }
1005             #elif defined(IP_RECVDSTADDR) || defined(IP_RECVIF)     // BSD and Solaris
1006                 #if defined(IP_RECVDSTADDR)
1007             err = setsockopt(*sktPtr, IPPROTO_IP, IP_RECVDSTADDR, &kOn, sizeof(kOn));
1008             if (err < 0) { err = errno; perror("setsockopt - IP_RECVDSTADDR"); }
1009                 #endif
1010                 #if defined(IP_RECVIF)
1011             if (err == 0)
1012             {
1013                 err = setsockopt(*sktPtr, IPPROTO_IP, IP_RECVIF, &kOn, sizeof(kOn));
1014                 if (err < 0) { err = errno; perror("setsockopt - IP_RECVIF"); }
1015             }
1016                 #endif
1017             #else
1018                 #warning This platform has no way to get the destination interface information -- will only work for single-homed hosts
1019             #endif
1020         }
1021     #if defined(IP_RECVTTL)                                 // Linux
1022         if (err == 0)
1023         {
1024             setsockopt(*sktPtr, IPPROTO_IP, IP_RECVTTL, &kOn, sizeof(kOn));
1025             // We no longer depend on being able to get the received TTL, so don't worry if the option fails
1026         }
1027     #endif
1028 
1029         // Add multicast group membership on this interface
1030         if (err == 0 && JoinMulticastGroup)
1031         {
1032             imr.imr_multiaddr.s_addr = AllDNSLinkGroup_v4.ip.v4.NotAnInteger;
1033             imr.imr_interface        = ((struct sockaddr_in*)intfAddr)->sin_addr;
1034             err = setsockopt(*sktPtr, IPPROTO_IP, IP_ADD_MEMBERSHIP, &imr, sizeof(imr));
1035             if (err < 0) { err = errno; perror("setsockopt - IP_ADD_MEMBERSHIP"); }
1036         }
1037 
1038         // Specify outgoing interface too
1039         if (err == 0 && JoinMulticastGroup)
1040         {
1041             err = setsockopt(*sktPtr, IPPROTO_IP, IP_MULTICAST_IF, &((struct sockaddr_in*)intfAddr)->sin_addr, sizeof(struct in_addr));
1042             if (err < 0) { err = errno; perror("setsockopt - IP_MULTICAST_IF"); }
1043         }
1044 
1045         // Per the mDNS spec, send unicast packets with TTL 255
1046         if (err == 0)
1047         {
1048             err = setsockopt(*sktPtr, IPPROTO_IP, IP_TTL, &kIntTwoFiveFive, sizeof(kIntTwoFiveFive));
1049             if (err < 0) { err = errno; perror("setsockopt - IP_TTL"); }
1050         }
1051 
1052         // and multicast packets with TTL 255 too
1053         // There's some debate as to whether IP_MULTICAST_TTL is an int or a byte so we just try both.
1054         if (err == 0)
1055         {
1056             err = setsockopt(*sktPtr, IPPROTO_IP, IP_MULTICAST_TTL, &kByteTwoFiveFive, sizeof(kByteTwoFiveFive));
1057             if (err < 0 && errno == EINVAL)
1058                 err = setsockopt(*sktPtr, IPPROTO_IP, IP_MULTICAST_TTL, &kIntTwoFiveFive, sizeof(kIntTwoFiveFive));
1059             if (err < 0) { err = errno; perror("setsockopt - IP_MULTICAST_TTL"); }
1060         }
1061 
1062         // And start listening for packets
1063         if (err == 0)
1064         {
1065             bindAddr.sin_family      = AF_INET;
1066             bindAddr.sin_port        = port.NotAnInteger;
1067             bindAddr.sin_addr.s_addr = INADDR_ANY; // Want to receive multicasts AND unicasts on this socket
1068             err = bind(*sktPtr, (struct sockaddr *) &bindAddr, sizeof(bindAddr));
1069             if (err < 0) { err = errno; perror("bind"); fflush(stderr); }
1070         }
1071     }     // endif (intfAddr->sa_family == AF_INET)
1072 
1073 #if HAVE_IPV6
1074     else if (intfAddr->sa_family == AF_INET6)
1075     {
1076         struct ipv6_mreq imr6;
1077         struct sockaddr_in6 bindAddr6;
1078     #if defined(IPV6_RECVPKTINFO) // Solaris
1079 	if (err == 0)
1080 	{
1081 	    err = setsockopt(*sktPtr, IPPROTO_IPV6, IPV6_RECVPKTINFO, &kOn, sizeof(kOn));
1082 	    if (err < 0) { err = errno; perror("setsockopt - IPV6_RECVPKTINFO"); }
1083 	}
1084     #elif defined(IPV6_PKTINFO)
1085         if (err == 0)
1086         {
1087             err = setsockopt(*sktPtr, IPPROTO_IPV6, IPV6_2292_PKTINFO, &kOn, sizeof(kOn));
1088             if (err < 0) { err = errno; perror("setsockopt - IPV6_PKTINFO"); }
1089         }
1090     #else
1091         #warning This platform has no way to get the destination interface information for IPv6 -- will only work for single-homed hosts
1092     #endif
1093     #if defined(IPV6_RECVHOPLIMIT)
1094 	if (err == 0)
1095 	{
1096 	    err = setsockopt(*sktPtr, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &kOn, sizeof(kOn));
1097 	    if (err < 0) { err = errno; perror("setsockopt - IPV6_RECVHOPLIMIT"); }
1098 	}
1099     #elif defined(IPV6_HOPLIMIT)
1100         if (err == 0)
1101         {
1102             err = setsockopt(*sktPtr, IPPROTO_IPV6, IPV6_2292_HOPLIMIT, &kOn, sizeof(kOn));
1103             if (err < 0) { err = errno; perror("setsockopt - IPV6_HOPLIMIT"); }
1104         }
1105     #endif
1106 
1107         // Add multicast group membership on this interface
1108         if (err == 0 && JoinMulticastGroup)
1109         {
1110             imr6.ipv6mr_multiaddr       = *(const struct in6_addr*)&AllDNSLinkGroup_v6.ip.v6;
1111             imr6.ipv6mr_interface       = interfaceIndex;
1112             //LogMsg("Joining %.16a on %d", &imr6.ipv6mr_multiaddr, imr6.ipv6mr_interface);
1113             err = setsockopt(*sktPtr, IPPROTO_IPV6, IPV6_JOIN_GROUP, &imr6, sizeof(imr6));
1114             if (err < 0)
1115             {
1116                 err = errno;
1117                 verbosedebugf("IPV6_JOIN_GROUP %.16a on %d failed.\n", &imr6.ipv6mr_multiaddr, imr6.ipv6mr_interface);
1118                 perror("setsockopt - IPV6_JOIN_GROUP");
1119             }
1120         }
1121 
1122         // Specify outgoing interface too
1123         if (err == 0 && JoinMulticastGroup)
1124         {
1125             u_int multicast_if = interfaceIndex;
1126             err = setsockopt(*sktPtr, IPPROTO_IPV6, IPV6_MULTICAST_IF, &multicast_if, sizeof(multicast_if));
1127             if (err < 0) { err = errno; perror("setsockopt - IPV6_MULTICAST_IF"); }
1128         }
1129 
1130         // We want to receive only IPv6 packets on this socket.
1131         // Without this option, we may get IPv4 addresses as mapped addresses.
1132         if (err == 0)
1133         {
1134             err = setsockopt(*sktPtr, IPPROTO_IPV6, IPV6_V6ONLY, &kOn, sizeof(kOn));
1135             if (err < 0) { err = errno; perror("setsockopt - IPV6_V6ONLY"); }
1136         }
1137 
1138         // Per the mDNS spec, send unicast packets with TTL 255
1139         if (err == 0)
1140         {
1141             err = setsockopt(*sktPtr, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &kIntTwoFiveFive, sizeof(kIntTwoFiveFive));
1142             if (err < 0) { err = errno; perror("setsockopt - IPV6_UNICAST_HOPS"); }
1143         }
1144 
1145         // and multicast packets with TTL 255 too
1146         // There's some debate as to whether IPV6_MULTICAST_HOPS is an int or a byte so we just try both.
1147         if (err == 0)
1148         {
1149             err = setsockopt(*sktPtr, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &kByteTwoFiveFive, sizeof(kByteTwoFiveFive));
1150             if (err < 0 && errno == EINVAL)
1151                 err = setsockopt(*sktPtr, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &kIntTwoFiveFive, sizeof(kIntTwoFiveFive));
1152             if (err < 0) { err = errno; perror("setsockopt - IPV6_MULTICAST_HOPS"); }
1153         }
1154 
1155         // And start listening for packets
1156         if (err == 0)
1157         {
1158             mDNSPlatformMemZero(&bindAddr6, sizeof(bindAddr6));
1159 #ifndef NOT_HAVE_SA_LEN
1160             bindAddr6.sin6_len         = sizeof(bindAddr6);
1161 #endif
1162             bindAddr6.sin6_family      = AF_INET6;
1163             bindAddr6.sin6_port        = port.NotAnInteger;
1164             bindAddr6.sin6_flowinfo    = 0;
1165             bindAddr6.sin6_addr        = in6addr_any; // Want to receive multicasts AND unicasts on this socket
1166             bindAddr6.sin6_scope_id    = 0;
1167             err = bind(*sktPtr, (struct sockaddr *) &bindAddr6, sizeof(bindAddr6));
1168             if (err < 0) { err = errno; perror("bind"); fflush(stderr); }
1169         }
1170     }     // endif (intfAddr->sa_family == AF_INET6)
1171 #endif
1172 
1173     // Set the socket to non-blocking.
1174     if (err == 0)
1175     {
1176         err = fcntl(*sktPtr, F_GETFL, 0);
1177         if (err < 0) err = errno;
1178         else
1179         {
1180             err = fcntl(*sktPtr, F_SETFL, err | O_NONBLOCK);
1181             if (err < 0) err = errno;
1182         }
1183     }
1184 
1185     // Clean up
1186     if (err != 0 && *sktPtr != -1)
1187     {
1188         int rv;
1189         rv = close(*sktPtr);
1190         assert(rv == 0);
1191         *sktPtr = -1;
1192     }
1193     assert((err == 0) == (*sktPtr != -1));
1194     return err;
1195 }
1196 
1197 // Creates a PosixNetworkInterface for the interface whose IP address is
1198 // intfAddr and whose name is intfName and registers it with mDNS core.
1199 mDNSlocal int SetupOneInterface(mDNS *const m, struct sockaddr *intfAddr, struct sockaddr *intfMask, const char *intfName, int intfIndex)
1200 {
1201     int err = 0;
1202     PosixNetworkInterface *intf;
1203     PosixNetworkInterface *alias = NULL;
1204 
1205     assert(m != NULL);
1206     assert(intfAddr != NULL);
1207     assert(intfName != NULL);
1208     assert(intfMask != NULL);
1209 
1210     // Allocate the interface structure itself.
1211     intf = (PosixNetworkInterface*)calloc(1, sizeof(*intf));
1212     if (intf == NULL) { assert(0); err = ENOMEM; }
1213 
1214     // And make a copy of the intfName.
1215     if (err == 0)
1216     {
1217 #ifdef LINUX
1218         char *s;
1219         int len;
1220         s = strchr(intfName, ':');
1221         if (s != NULL)
1222         {
1223             len = (s - intfName) + 1;
1224         }
1225         else
1226         {
1227             len = strlen(intfName) + 1;
1228         }
1229         intf->intfName = malloc(len);
1230         if (intf->intfName == NULL) { assert(0); err = ENOMEM; }
1231         memcpy(intf->intfName, intfName, len - 1);
1232         intfName[len - 1] = 0;
1233 #else
1234         intf->intfName = strdup(intfName);
1235         if (intf->intfName == NULL) { assert(0); err = ENOMEM; }
1236 #endif
1237     }
1238 
1239     if (err == 0)
1240     {
1241         // Set up the fields required by the mDNS core.
1242         SockAddrTomDNSAddr(intfAddr, &intf->coreIntf.ip, NULL);
1243         SockAddrTomDNSAddr(intfMask, &intf->coreIntf.mask, NULL);
1244 
1245         //LogMsg("SetupOneInterface: %#a %#a",  &intf->coreIntf.ip,  &intf->coreIntf.mask);
1246         strncpy(intf->coreIntf.ifname, intfName, sizeof(intf->coreIntf.ifname));
1247         intf->coreIntf.ifname[sizeof(intf->coreIntf.ifname)-1] = 0;
1248 
1249         intf->coreIntf.Advertise = m->AdvertiseLocalAddresses;
1250         intf->coreIntf.McastTxRx = mDNStrue;
1251 
1252         // Set up the extra fields in PosixNetworkInterface.
1253         assert(intf->intfName != NULL);         // intf->intfName already set up above
1254         intf->index                = intfIndex;
1255         intf->multicastSocket4     = -1;
1256 #if HAVE_IPV6
1257         intf->multicastSocket6     = -1;
1258 #endif
1259         alias                      = SearchForInterfaceByName(m, intf->intfName);
1260         if (alias == NULL) alias   = intf;
1261         intf->coreIntf.InterfaceID = (mDNSInterfaceID)alias;
1262 
1263         if (alias != intf)
1264             debugf("SetupOneInterface: %s %#a is an alias of %#a", intfName, &intf->coreIntf.ip, &alias->coreIntf.ip);
1265     }
1266 
1267     // Set up the multicast socket
1268     if (err == 0)
1269     {
1270         if (alias->multicastSocket4 == -1 && intfAddr->sa_family == AF_INET)
1271             err = SetupSocket(intfAddr, MulticastDNSPort, intf->index, &alias->multicastSocket4);
1272 #if HAVE_IPV6
1273         else if (alias->multicastSocket6 == -1 && intfAddr->sa_family == AF_INET6)
1274             err = SetupSocket(intfAddr, MulticastDNSPort, intf->index, &alias->multicastSocket6);
1275 #endif
1276     }
1277 
1278     // If interface is a direct link, address record will be marked as kDNSRecordTypeKnownUnique
1279     // and skip the probe phase of the probe/announce packet sequence.
1280     intf->coreIntf.DirectLink = mDNSfalse;
1281 #ifdef DIRECTLINK_INTERFACE_NAME
1282     if (strcmp(intfName, STRINGIFY(DIRECTLINK_INTERFACE_NAME)) == 0)
1283         intf->coreIntf.DirectLink = mDNStrue;
1284 #endif
1285     intf->coreIntf.SupportsUnicastMDNSResponse = mDNStrue;
1286 
1287     // The interface is all ready to go, let's register it with the mDNS core.
1288     if (err == 0)
1289         err = mDNS_RegisterInterface(m, &intf->coreIntf, NormalActivation);
1290 
1291     // Clean up.
1292     if (err == 0)
1293     {
1294         num_registered_interfaces++;
1295         debugf("SetupOneInterface: %s %#a Registered", intf->intfName, &intf->coreIntf.ip);
1296         if (gMDNSPlatformPosixVerboseLevel > 0)
1297             fprintf(stderr, "Registered interface %s\n", intf->intfName);
1298     }
1299     else
1300     {
1301         // Use intfName instead of intf->intfName in the next line to avoid dereferencing NULL.
1302         debugf("SetupOneInterface: %s %#a failed to register %d", intfName, &intf->coreIntf.ip, err);
1303         if (intf) { FreePosixNetworkInterface(intf); intf = NULL; }
1304     }
1305 
1306     assert((err == 0) == (intf != NULL));
1307 
1308     return err;
1309 }
1310 
1311 // Call get_ifi_info() to obtain a list of active interfaces and call SetupOneInterface() on each one.
1312 mDNSlocal int SetupInterfaceList(mDNS *const m)
1313 {
1314     mDNSBool foundav4       = mDNSfalse;
1315     int err            = 0;
1316     struct ifaddrs *intfList;
1317     struct ifaddrs *firstLoopback = NULL;
1318     int firstLoopbackIndex = 0;
1319 
1320     assert(m != NULL);
1321     debugf("SetupInterfaceList");
1322 
1323     if (getifaddrs(&intfList) < 0)
1324     {
1325         err = errno;
1326     }
1327     if (intfList == NULL) err = ENOENT;
1328 
1329     if (err == 0)
1330     {
1331         struct ifaddrs *i = intfList;
1332         while (i)
1333         {
1334             if (     i->ifa_addr != NULL &&
1335                      ((i->ifa_addr->sa_family == AF_INET)
1336 #if HAVE_IPV6
1337                       || (i->ifa_addr->sa_family == AF_INET6)
1338 #endif
1339                       ) &&  (i->ifa_flags & IFF_UP) && !(i->ifa_flags & IFF_POINTOPOINT))
1340             {
1341                 int ifIndex = if_nametoindex(i->ifa_name);
1342                 if (ifIndex == 0)
1343                 {
1344                     i = i->ifa_next;
1345                     continue;
1346                 }
1347                 if (i->ifa_flags & IFF_LOOPBACK)
1348                 {
1349                     if (firstLoopback == NULL)
1350                     {
1351                         firstLoopback = i;
1352                         firstLoopbackIndex = ifIndex;
1353                     }
1354                 }
1355                 else
1356                 {
1357                     if (SetupOneInterface(m, i->ifa_addr, i->ifa_netmask, i->ifa_name, ifIndex) == 0)
1358                     {
1359                         if (i->ifa_addr->sa_family == AF_INET)
1360                         {
1361                             foundav4 = mDNStrue;
1362                         }
1363                     }
1364                 }
1365             }
1366             i = i->ifa_next;
1367         }
1368 
1369         // If we found no normal interfaces but we did find a loopback interface, register the
1370         // loopback interface.  This allows self-discovery if no interfaces are configured.
1371         // Temporary workaround: Multicast loopback on IPv6 interfaces appears not to work.
1372         // In the interim, we skip loopback interface only if we found at least one v4 interface to use
1373         // if ((m->HostInterfaces == NULL) && (firstLoopback != NULL))
1374         if (!foundav4 && firstLoopback)
1375         {
1376             (void)SetupOneInterface(m, firstLoopback->ifa_addr, firstLoopback->ifa_netmask, firstLoopback->ifa_name,
1377                                     firstLoopbackIndex);
1378         }
1379     }
1380 
1381     // Clean up.
1382     if (intfList != NULL) freeifaddrs(intfList);
1383 
1384     // Clean up any interfaces that have been hanging around on the RecentInterfaces list for more than a minute
1385     PosixNetworkInterface **ri = &gRecentInterfaces;
1386     const mDNSs32 utc = mDNSPlatformUTC();
1387     while (*ri)
1388     {
1389         PosixNetworkInterface *pi = *ri;
1390         if (utc - pi->LastSeen < 60) ri = (PosixNetworkInterface **)&pi->coreIntf.next;
1391         else { *ri = (PosixNetworkInterface *)pi->coreIntf.next; free(pi); }
1392     }
1393 
1394     return err;
1395 }
1396 
1397 #if USES_NETLINK
1398 
1399 // See <http://www.faqs.org/rfcs/rfc3549.html> for a description of NetLink
1400 
1401 // Open a socket that will receive interface change notifications
1402 mDNSlocal mStatus OpenIfNotifySocket(int *pFD)
1403 {
1404     mStatus err = mStatus_NoError;
1405     struct sockaddr_nl snl;
1406     int sock;
1407     int ret;
1408 
1409     sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
1410     if (sock < 0)
1411         return errno;
1412 
1413     // Configure read to be non-blocking because inbound msg size is not known in advance
1414     (void) fcntl(sock, F_SETFL, O_NONBLOCK);
1415 
1416     /* Subscribe the socket to Link & IP addr notifications. */
1417     mDNSPlatformMemZero(&snl, sizeof snl);
1418     snl.nl_family = AF_NETLINK;
1419     snl.nl_groups = RTMGRP_LINK | RTMGRP_IPV4_IFADDR;
1420     ret = bind(sock, (struct sockaddr *) &snl, sizeof snl);
1421     if (0 == ret)
1422         *pFD = sock;
1423     else
1424         err = errno;
1425 
1426     return err;
1427 }
1428 
1429 #if MDNS_DEBUGMSGS
1430 mDNSlocal void      PrintNetLinkMsg(const struct nlmsghdr *pNLMsg)
1431 {
1432     const char *kNLMsgTypes[] = { "", "NLMSG_NOOP", "NLMSG_ERROR", "NLMSG_DONE", "NLMSG_OVERRUN" };
1433     const char *kNLRtMsgTypes[] = { "RTM_NEWLINK", "RTM_DELLINK", "RTM_GETLINK", "RTM_NEWADDR", "RTM_DELADDR", "RTM_GETADDR" };
1434 
1435     printf("nlmsghdr len=%d, type=%s, flags=0x%x\n", pNLMsg->nlmsg_len,
1436            pNLMsg->nlmsg_type < RTM_BASE ? kNLMsgTypes[pNLMsg->nlmsg_type] : kNLRtMsgTypes[pNLMsg->nlmsg_type - RTM_BASE],
1437            pNLMsg->nlmsg_flags);
1438 
1439     if (RTM_NEWLINK <= pNLMsg->nlmsg_type && pNLMsg->nlmsg_type <= RTM_GETLINK)
1440     {
1441         struct ifinfomsg    *pIfInfo = (struct ifinfomsg*) NLMSG_DATA(pNLMsg);
1442         printf("ifinfomsg family=%d, type=%d, index=%d, flags=0x%x, change=0x%x\n", pIfInfo->ifi_family,
1443                pIfInfo->ifi_type, pIfInfo->ifi_index, pIfInfo->ifi_flags, pIfInfo->ifi_change);
1444 
1445     }
1446     else if (RTM_NEWADDR <= pNLMsg->nlmsg_type && pNLMsg->nlmsg_type <= RTM_GETADDR)
1447     {
1448         struct ifaddrmsg    *pIfAddr = (struct ifaddrmsg*) NLMSG_DATA(pNLMsg);
1449         printf("ifaddrmsg family=%d, index=%d, flags=0x%x\n", pIfAddr->ifa_family,
1450                pIfAddr->ifa_index, pIfAddr->ifa_flags);
1451     }
1452     printf("\n");
1453 }
1454 #endif
1455 
1456 mDNSlocal mDNSu32       ProcessRoutingNotification(int sd)
1457 // Read through the messages on sd and if any indicate that any interface records should
1458 // be torn down and rebuilt, return affected indices as a bitmask. Otherwise return 0.
1459 {
1460     ssize_t readCount;
1461     char buff[4096];
1462     struct nlmsghdr         *pNLMsg = (struct nlmsghdr*) buff;
1463     mDNSu32 result = 0;
1464 
1465     // The structure here is more complex than it really ought to be because,
1466     // unfortunately, there's no good way to size a buffer in advance large
1467     // enough to hold all pending data and so avoid message fragmentation.
1468     // (Note that FIONREAD is not supported on AF_NETLINK.)
1469 
1470     readCount = read(sd, buff, sizeof buff);
1471     while (1)
1472     {
1473         // Make sure we've got an entire nlmsghdr in the buffer, and payload, too.
1474         // If not, discard already-processed messages in buffer and read more data.
1475         if (((char*) &pNLMsg[1] > (buff + readCount)) ||    // i.e. *pNLMsg extends off end of buffer
1476             ((char*) pNLMsg + pNLMsg->nlmsg_len > (buff + readCount)))
1477         {
1478             if (buff < (char*) pNLMsg)      // we have space to shuffle
1479             {
1480                 // discard processed data
1481                 readCount -= ((char*) pNLMsg - buff);
1482                 memmove(buff, pNLMsg, readCount);
1483                 pNLMsg = (struct nlmsghdr*) buff;
1484 
1485                 // read more data
1486                 readCount += read(sd, buff + readCount, sizeof buff - readCount);
1487                 continue;                   // spin around and revalidate with new readCount
1488             }
1489             else
1490                 break;  // Otherwise message does not fit in buffer
1491         }
1492 
1493 #if MDNS_DEBUGMSGS
1494         PrintNetLinkMsg(pNLMsg);
1495 #endif
1496 
1497         // Process the NetLink message
1498         if (pNLMsg->nlmsg_type == RTM_GETLINK || pNLMsg->nlmsg_type == RTM_NEWLINK)
1499             result |= 1 << ((struct ifinfomsg*) NLMSG_DATA(pNLMsg))->ifi_index;
1500         else if (pNLMsg->nlmsg_type == RTM_DELADDR || pNLMsg->nlmsg_type == RTM_NEWADDR)
1501             result |= 1 << ((struct ifaddrmsg*) NLMSG_DATA(pNLMsg))->ifa_index;
1502 
1503         // Advance pNLMsg to the next message in the buffer
1504         if ((pNLMsg->nlmsg_flags & NLM_F_MULTI) != 0 && pNLMsg->nlmsg_type != NLMSG_DONE)
1505         {
1506             ssize_t len = readCount - ((char*)pNLMsg - buff);
1507             pNLMsg = NLMSG_NEXT(pNLMsg, len);
1508         }
1509         else
1510             break;  // all done!
1511     }
1512 
1513     return result;
1514 }
1515 
1516 #else // USES_NETLINK
1517 
1518 // Open a socket that will receive interface change notifications
1519 mDNSlocal mStatus OpenIfNotifySocket(int *pFD)
1520 {
1521     *pFD = socket(AF_ROUTE, SOCK_RAW, 0);
1522 
1523     if (*pFD < 0)
1524         return mStatus_UnknownErr;
1525 
1526     // Configure read to be non-blocking because inbound msg size is not known in advance
1527     (void) fcntl(*pFD, F_SETFL, O_NONBLOCK);
1528 
1529     return mStatus_NoError;
1530 }
1531 
1532 #if MDNS_DEBUGMSGS
1533 mDNSlocal void      PrintRoutingSocketMsg(const struct ifa_msghdr *pRSMsg)
1534 {
1535     const char *kRSMsgTypes[] = { "", "RTM_ADD", "RTM_DELETE", "RTM_CHANGE", "RTM_GET", "RTM_LOSING",
1536                                   "RTM_REDIRECT", "RTM_MISS", "RTM_LOCK", "RTM_OLDADD", "RTM_OLDDEL", "RTM_RESOLVE",
1537                                   "RTM_NEWADDR", "RTM_DELADDR", "RTM_IFINFO", "RTM_NEWMADDR", "RTM_DELMADDR" };
1538 
1539     int index = pRSMsg->ifam_type == RTM_IFINFO ? ((struct if_msghdr*) pRSMsg)->ifm_index : pRSMsg->ifam_index;
1540 
1541     printf("ifa_msghdr len=%d, type=%s, index=%d\n", pRSMsg->ifam_msglen, kRSMsgTypes[pRSMsg->ifam_type], index);
1542 }
1543 #endif
1544 
1545 mDNSlocal mDNSu32       ProcessRoutingNotification(int sd)
1546 // Read through the messages on sd and if any indicate that any interface records should
1547 // be torn down and rebuilt, return affected indices as a bitmask. Otherwise return 0.
1548 {
1549     ssize_t readCount;
1550     char buff[4096];
1551     struct ifa_msghdr       *pRSMsg = (struct ifa_msghdr*) buff;
1552     mDNSu32 result = 0;
1553 
1554     readCount = read(sd, buff, sizeof buff);
1555     if (readCount < (ssize_t) sizeof(struct ifa_msghdr))
1556         return mStatus_UnsupportedErr;      // cannot decipher message
1557 
1558 #if MDNS_DEBUGMSGS
1559     PrintRoutingSocketMsg(pRSMsg);
1560 #endif
1561 
1562     // Process the message
1563     switch (pRSMsg->ifam_type)
1564     {
1565     case RTM_NEWADDR:
1566     case RTM_DELADDR:
1567     case RTM_IFINFO:
1568     /*
1569      * ADD & DELETE are happening when IPv6 announces are changing,
1570      * and for some reason it will stop mdnsd to announce IPv6
1571      * addresses. So we force mdnsd to check interfaces.
1572      */
1573     case RTM_ADD:
1574     case RTM_DELETE:
1575         if (pRSMsg->ifam_type == RTM_IFINFO)
1576             result |= 1 << ((struct if_msghdr*) pRSMsg)->ifm_index;
1577         else
1578             result |= 1 << pRSMsg->ifam_index;
1579     break;
1580     }
1581 
1582     return result;
1583 }
1584 
1585 #endif // USES_NETLINK
1586 
1587 // Called when data appears on interface change notification socket
1588 mDNSlocal void InterfaceChangeCallback(int fd, void *context)
1589 {
1590     IfChangeRec     *pChgRec = (IfChangeRec*) context;
1591     fd_set readFDs;
1592     mDNSu32 changedInterfaces = 0;
1593     struct timeval zeroTimeout = { 0, 0 };
1594 
1595     (void)fd; // Unused
1596 
1597     FD_ZERO(&readFDs);
1598     FD_SET(pChgRec->NotifySD, &readFDs);
1599 
1600     do
1601     {
1602         changedInterfaces |= ProcessRoutingNotification(pChgRec->NotifySD);
1603     }
1604     while (0 < select(pChgRec->NotifySD + 1, &readFDs, (fd_set*) NULL, (fd_set*) NULL, &zeroTimeout));
1605 
1606     // Currently we rebuild the entire interface list whenever any interface change is
1607     // detected. If this ever proves to be a performance issue in a multi-homed
1608     // configuration, more care should be paid to changedInterfaces.
1609     if (changedInterfaces)
1610         mDNSPlatformPosixRefreshInterfaceList(pChgRec->mDNS);
1611 }
1612 
1613 // Register with either a Routing Socket or RtNetLink to listen for interface changes.
1614 mDNSlocal mStatus WatchForInterfaceChange(mDNS *const m)
1615 {
1616     mStatus err;
1617     IfChangeRec *pChgRec;
1618 
1619     pChgRec = (IfChangeRec*) mDNSPlatformMemAllocateClear(sizeof *pChgRec);
1620     if (pChgRec == NULL)
1621         return mStatus_NoMemoryErr;
1622 
1623     pChgRec->mDNS = m;
1624     err = OpenIfNotifySocket(&pChgRec->NotifySD);
1625     if (err == 0)
1626         err = mDNSPosixAddFDToEventLoop(pChgRec->NotifySD, InterfaceChangeCallback, pChgRec);
1627     if (err)
1628         mDNSPlatformMemFree(pChgRec);
1629 
1630     return err;
1631 }
1632 
1633 // Test to see if we're the first client running on UDP port 5353, by trying to bind to 5353 without using SO_REUSEPORT.
1634 // If we fail, someone else got here first. That's not a big problem; we can share the port for multicast responses --
1635 // we just need to be aware that we shouldn't expect to successfully receive unicast UDP responses.
1636 mDNSlocal mDNSBool mDNSPlatformInit_CanReceiveUnicast(void)
1637 {
1638     int err;
1639     int s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
1640     struct sockaddr_in s5353;
1641     s5353.sin_family      = AF_INET;
1642     s5353.sin_port        = MulticastDNSPort.NotAnInteger;
1643     s5353.sin_addr.s_addr = 0;
1644     err = bind(s, (struct sockaddr *)&s5353, sizeof(s5353));
1645     close(s);
1646     if (err) debugf("No unicast UDP responses");
1647     else debugf("Unicast UDP responses okay");
1648     return(err == 0);
1649 }
1650 
1651 // mDNS core calls this routine to initialise the platform-specific data.
1652 mDNSexport mStatus mDNSPlatformInit(mDNS *const m)
1653 {
1654     int err = 0;
1655     struct sockaddr sa;
1656     assert(m != NULL);
1657 
1658     if (mDNSPlatformInit_CanReceiveUnicast()) m->CanReceiveUnicastOn5353 = mDNStrue;
1659 
1660     // Tell mDNS core the names of this machine.
1661 
1662     // Set up the nice label
1663     m->nicelabel.c[0] = 0;
1664     GetUserSpecifiedFriendlyComputerName(&m->nicelabel);
1665     if (m->nicelabel.c[0] == 0) MakeDomainLabelFromLiteralString(&m->nicelabel, "Computer");
1666 
1667     // Set up the RFC 1034-compliant label
1668     m->hostlabel.c[0] = 0;
1669     GetUserSpecifiedRFC1034ComputerName(&m->hostlabel);
1670     if (m->hostlabel.c[0] == 0) MakeDomainLabelFromLiteralString(&m->hostlabel, "Computer");
1671 
1672     mDNS_SetFQDN(m);
1673 
1674     sa.sa_family = AF_INET;
1675     m->p->unicastSocket4 = -1;
1676     if (err == mStatus_NoError) err = SetupSocket(&sa, zeroIPPort, 0, &m->p->unicastSocket4);
1677 #if HAVE_IPV6
1678     sa.sa_family = AF_INET6;
1679     m->p->unicastSocket6 = -1;
1680     if (err == mStatus_NoError) err = SetupSocket(&sa, zeroIPPort, 0, &m->p->unicastSocket6);
1681 #endif
1682 
1683     // Tell mDNS core about the network interfaces on this machine.
1684     if (err == mStatus_NoError) err = SetupInterfaceList(m);
1685 
1686     // Tell mDNS core about DNS Servers
1687     mDNS_Lock(m);
1688     if (err == mStatus_NoError) ParseDNSServers(m, uDNS_SERVERS_FILE);
1689     mDNS_Unlock(m);
1690 
1691     if (err == mStatus_NoError)
1692     {
1693         err = WatchForInterfaceChange(m);
1694         // Failure to observe interface changes is non-fatal.
1695         if (err != mStatus_NoError)
1696         {
1697             fprintf(stderr, "mDNS(%d) WARNING: Unable to detect interface changes (%d).\n",
1698 		(int)getpid(), err);
1699             err = mStatus_NoError;
1700         }
1701     }
1702 
1703     // We don't do asynchronous initialization on the Posix platform, so by the time
1704     // we get here the setup will already have succeeded or failed.  If it succeeded,
1705     // we should just call mDNSCoreInitComplete() immediately.
1706     if (err == mStatus_NoError)
1707         mDNSCoreInitComplete(m, mStatus_NoError);
1708 
1709     return PosixErrorToStatus(err);
1710 }
1711 
1712 // mDNS core calls this routine to clean up the platform-specific data.
1713 // In our case all we need to do is to tear down every network interface.
1714 mDNSexport void mDNSPlatformClose(mDNS *const m)
1715 {
1716     int rv;
1717     assert(m != NULL);
1718     ClearInterfaceList(m);
1719     if (m->p->unicastSocket4 != -1)
1720     {
1721         rv = close(m->p->unicastSocket4);
1722         assert(rv == 0);
1723     }
1724 #if HAVE_IPV6
1725     if (m->p->unicastSocket6 != -1)
1726     {
1727         rv = close(m->p->unicastSocket6);
1728         assert(rv == 0);
1729     }
1730 #endif
1731 }
1732 
1733 // This is used internally by InterfaceChangeCallback.
1734 // It's also exported so that the Standalone Responder (mDNSResponderPosix)
1735 // can call it in response to a SIGHUP (mainly for debugging purposes).
1736 mDNSexport mStatus mDNSPlatformPosixRefreshInterfaceList(mDNS *const m)
1737 {
1738     int err;
1739     // This is a pretty heavyweight way to process interface changes --
1740     // destroying the entire interface list and then making fresh one from scratch.
1741     // We should make it like the OS X version, which leaves unchanged interfaces alone.
1742     ClearInterfaceList(m);
1743     err = SetupInterfaceList(m);
1744     return PosixErrorToStatus(err);
1745 }
1746 
1747 #if COMPILER_LIKES_PRAGMA_MARK
1748 #pragma mark ***** Locking
1749 #endif
1750 
1751 // On the Posix platform, locking is a no-op because we only ever enter
1752 // mDNS core on the main thread.
1753 
1754 // mDNS core calls this routine when it wants to prevent
1755 // the platform from reentering mDNS core code.
1756 mDNSexport void    mDNSPlatformLock   (const mDNS *const m)
1757 {
1758     (void) m;   // Unused
1759 }
1760 
1761 // mDNS core calls this routine when it release the lock taken by
1762 // mDNSPlatformLock and allow the platform to reenter mDNS core code.
1763 mDNSexport void    mDNSPlatformUnlock (const mDNS *const m)
1764 {
1765     (void) m;   // Unused
1766 }
1767 
1768 #if COMPILER_LIKES_PRAGMA_MARK
1769 #pragma mark ***** Strings
1770 #endif
1771 
1772 mDNSexport mDNSu32  mDNSPlatformStrLCopy(void *dst, const void *src, mDNSu32 len)
1773 {
1774 #if HAVE_STRLCPY
1775     return ((mDNSu32)strlcpy((char *)dst, (const char *)src, len));
1776 #else
1777     size_t srcLen;
1778 
1779     srcLen = strlen((const char *)src);
1780     if (srcLen < len)
1781     {
1782         memcpy(dst, src, srcLen + 1);
1783     }
1784     else if (len > 0)
1785     {
1786         memcpy(dst, src, len - 1);
1787         ((char *)dst)[len - 1] = '\0';
1788     }
1789 
1790     return ((mDNSu32)srcLen);
1791 #endif
1792 }
1793 
1794 // mDNS core calls this routine to get the length of a C string.
1795 // On the Posix platform this maps directly to the ANSI C strlen.
1796 mDNSexport mDNSu32  mDNSPlatformStrLen (const void *src)
1797 {
1798     return strlen((const char*)src);
1799 }
1800 
1801 // mDNS core calls this routine to copy memory.
1802 // On the Posix platform this maps directly to the ANSI C memcpy.
1803 mDNSexport void    mDNSPlatformMemCopy(void *dst, const void *src, mDNSu32 len)
1804 {
1805     memcpy(dst, src, len);
1806 }
1807 
1808 // mDNS core calls this routine to test whether blocks of memory are byte-for-byte
1809 // identical. On the Posix platform this is a simple wrapper around ANSI C memcmp.
1810 mDNSexport mDNSBool mDNSPlatformMemSame(const void *dst, const void *src, mDNSu32 len)
1811 {
1812     return memcmp(dst, src, len) == 0;
1813 }
1814 
1815 // If the caller wants to know the exact return of memcmp, then use this instead
1816 // of mDNSPlatformMemSame
1817 mDNSexport int mDNSPlatformMemCmp(const void *dst, const void *src, mDNSu32 len)
1818 {
1819     return (memcmp(dst, src, len));
1820 }
1821 
1822 mDNSexport void mDNSPlatformQsort(void *base, int nel, int width, int (*compar)(const void *, const void *))
1823 {
1824     (void)qsort(base, nel, width, compar);
1825 }
1826 
1827 // Proxy stub functions
1828 mDNSexport mDNSu8 *DNSProxySetAttributes(DNSQuestion *q, DNSMessageHeader *h, DNSMessage *msg, mDNSu8 *ptr, mDNSu8 *limit)
1829 {
1830     (void) q;
1831     (void) h;
1832     (void) msg;
1833     (void) ptr;
1834     (void) limit;
1835 
1836     return ptr;
1837 }
1838 
1839 mDNSexport void DNSProxyInit(mDNSu32 IpIfArr[MaxIp], mDNSu32 OpIf)
1840 {
1841     (void) IpIfArr;
1842     (void) OpIf;
1843 }
1844 
1845 mDNSexport void DNSProxyTerminate(void)
1846 {
1847 }
1848 
1849 // mDNS core calls this routine to clear blocks of memory.
1850 // On the Posix platform this is a simple wrapper around ANSI C memset.
1851 mDNSexport void  mDNSPlatformMemZero(void *dst, mDNSu32 len)
1852 {
1853     memset(dst, 0, len);
1854 }
1855 
1856 #if !MDNS_MALLOC_DEBUGGING
1857 mDNSexport void *mDNSPlatformMemAllocate(mDNSu32 len)      { return(mallocL("mDNSPlatformMemAllocate", len)); }
1858 mDNSexport void *mDNSPlatformMemAllocateClear(mDNSu32 len) { return(callocL(name, len)); }
1859 mDNSexport void  mDNSPlatformMemFree    (void *mem)        {          freeL("mDNSPlatformMemFree", mem); }
1860 #endif
1861 
1862 #if _PLATFORM_HAS_STRONG_PRNG_
1863 mDNSexport mDNSu32 mDNSPlatformRandomNumber(void)
1864 {
1865     return(arc4random());
1866 }
1867 #else
1868 mDNSexport mDNSu32 mDNSPlatformRandomSeed(void)
1869 {
1870     struct timeval tv;
1871     gettimeofday(&tv, NULL);
1872     return(tv.tv_usec);
1873 }
1874 #endif
1875 
1876 mDNSexport mDNSs32 mDNSPlatformOneSecond = 1024;
1877 
1878 mDNSexport mStatus mDNSPlatformTimeInit(void)
1879 {
1880     // No special setup is required on Posix -- we just use gettimeofday();
1881     // This is not really safe, because gettimeofday can go backwards if the user manually changes the date or time
1882     // We should find a better way to do this
1883     return(mStatus_NoError);
1884 }
1885 
1886 mDNSexport mDNSs32  mDNSPlatformRawTime()
1887 {
1888     struct timespec tm;
1889     int ret = clock_gettime(CLOCK_MONOTONIC, &tm);
1890     assert(ret == 0); // This call will only fail if the number of seconds does not fit in an object of type time_t.
1891 
1892     // tm.tv_sec is seconds since some unspecified starting point (it is usually the system start up time)
1893     // tm.tv_nsec is nanoseconds since the start of this second (i.e. values 0 to 999999999)
1894     // We use the lower 22 bits of tm.tv_sec for the top 22 bits of our result
1895     // 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.
1896     // This gives us a proper modular (cyclic) counter that has a resolution of roughly 1ms (actually 1/1024 second)
1897     // and correctly cycles every 2^22 seconds (4194304 seconds = approx 48 days).
1898 
1899     return ((tm.tv_sec << 10) | (tm.tv_nsec * 2 / 1953125));
1900 }
1901 
1902 mDNSexport mDNSs32 mDNSPlatformUTC(void)
1903 {
1904     return time(NULL);
1905 }
1906 
1907 mDNSexport void mDNSPlatformSendWakeupPacket(mDNSInterfaceID InterfaceID, char *EthAddr, char *IPAddr, int iteration)
1908 {
1909     (void) InterfaceID;
1910     (void) EthAddr;
1911     (void) IPAddr;
1912     (void) iteration;
1913 }
1914 
1915 mDNSexport mDNSBool mDNSPlatformValidRecordForInterface(const AuthRecord *rr, mDNSInterfaceID InterfaceID)
1916 {
1917     (void) rr;
1918     (void) InterfaceID;
1919 
1920     return 1;
1921 }
1922 
1923 mDNSexport mDNSBool mDNSPlatformValidQuestionForInterface(DNSQuestion *q, const NetworkInterfaceInfo *intf)
1924 {
1925     (void) q;
1926     (void) intf;
1927 
1928     return 1;
1929 }
1930 
1931 // Used for debugging purposes. For now, just set the buffer to zero
1932 mDNSexport void mDNSPlatformFormatTime(unsigned long te, mDNSu8 *buf, int bufsize)
1933 {
1934     (void) te;
1935     if (bufsize) buf[0] = 0;
1936 }
1937 
1938 mDNSexport void mDNSPlatformSendKeepalive(mDNSAddr *sadd, mDNSAddr *dadd, mDNSIPPort *lport, mDNSIPPort *rport, mDNSu32 seq, mDNSu32 ack, mDNSu16 win)
1939 {
1940     (void) sadd;    // Unused
1941     (void) dadd;    // Unused
1942     (void) lport;   // Unused
1943     (void) rport;   // Unused
1944     (void) seq;     // Unused
1945     (void) ack;     // Unused
1946     (void) win;     // Unused
1947 }
1948 
1949 mDNSexport mStatus mDNSPlatformRetrieveTCPInfo(mDNSAddr *laddr, mDNSIPPort *lport, mDNSAddr *raddr, mDNSIPPort *rport, mDNSTCPInfo *mti)
1950 {
1951     (void) laddr;   // Unused
1952     (void) raddr;   // Unused
1953     (void) lport;   // Unused
1954     (void) rport;   // Unused
1955     (void) mti;     // Unused
1956 
1957     return mStatus_NoError;
1958 }
1959 
1960 mDNSexport mStatus mDNSPlatformGetRemoteMacAddr(mDNSAddr *raddr)
1961 {
1962     (void) raddr; // Unused
1963 
1964     return mStatus_NoError;
1965 }
1966 
1967 mDNSexport mStatus    mDNSPlatformStoreSPSMACAddr(mDNSAddr *spsaddr, char *ifname)
1968 {
1969     (void) spsaddr; // Unused
1970     (void) ifname;  // Unused
1971 
1972     return mStatus_NoError;
1973 }
1974 
1975 mDNSexport mStatus    mDNSPlatformClearSPSData(void)
1976 {
1977     return mStatus_NoError;
1978 }
1979 
1980 mDNSexport mStatus mDNSPlatformStoreOwnerOptRecord(char *ifname, DNSMessage *msg, int length)
1981 {
1982     (void) ifname; // Unused
1983     (void) msg;    // Unused
1984     (void) length; // Unused
1985     return mStatus_UnsupportedErr;
1986 }
1987 
1988 mDNSexport mDNSu16 mDNSPlatformGetUDPPort(UDPSocket *sock)
1989 {
1990     (void) sock; // unused
1991 
1992     return (mDNSu16)-1;
1993 }
1994 
1995 mDNSexport mDNSBool mDNSPlatformInterfaceIsD2D(mDNSInterfaceID InterfaceID)
1996 {
1997     (void) InterfaceID; // unused
1998 
1999     return mDNSfalse;
2000 }
2001 
2002 mDNSexport void mDNSPlatformSetSocktOpt(void *sock, mDNSTransport_Type transType, mDNSAddr_Type addrType, const DNSQuestion *q)
2003 {
2004     (void) sock;
2005     (void) transType;
2006     (void) addrType;
2007     (void) q;
2008 }
2009 
2010 mDNSexport mDNSs32 mDNSPlatformGetPID()
2011 {
2012     return 0;
2013 }
2014 
2015 mDNSlocal void mDNSPosixAddToFDSet(int *nfds, fd_set *readfds, int s)
2016 {
2017     if (*nfds < s + 1) *nfds = s + 1;
2018     FD_SET(s, readfds);
2019 }
2020 
2021 mDNSexport void mDNSPosixGetFDSetForSelect(mDNS *m, int *nfds, fd_set *readfds, fd_set *writefds)
2022 {
2023     int numFDs = *nfds;
2024     PosixEventSource *iSource;
2025 
2026     // 2. Build our list of active file descriptors
2027     PosixNetworkInterface *info = (PosixNetworkInterface *)(m->HostInterfaces);
2028     if (m->p->unicastSocket4 != -1) mDNSPosixAddToFDSet(&numFDs, readfds, m->p->unicastSocket4);
2029 #if HAVE_IPV6
2030     if (m->p->unicastSocket6 != -1) mDNSPosixAddToFDSet(&numFDs, readfds, m->p->unicastSocket6);
2031 #endif
2032     while (info)
2033     {
2034         if (info->multicastSocket4 != -1) mDNSPosixAddToFDSet(&numFDs, readfds, info->multicastSocket4);
2035 #if HAVE_IPV6
2036         if (info->multicastSocket6 != -1) mDNSPosixAddToFDSet(&numFDs, readfds, info->multicastSocket6);
2037 #endif
2038         info = (PosixNetworkInterface *)(info->coreIntf.next);
2039     }
2040 
2041     // Copy over the event fds.   We have to do it this way because client-provided event loops expect
2042     // to initialize their FD sets first and then call mDNSPosixGetFDSet()
2043     for (iSource = gEventSources; iSource; iSource = iSource->next)
2044     {
2045         if (iSource->readCallback != NULL)
2046             FD_SET(iSource->fd, readfds);
2047         if (iSource->writeCallback != NULL)
2048             FD_SET(iSource->fd, writefds);
2049         if (numFDs <= iSource->fd)
2050             numFDs = iSource->fd + 1;
2051     }
2052     *nfds = numFDs;
2053 }
2054 
2055 mDNSexport void mDNSPosixGetNextDNSEventTime(mDNS *m, struct timeval *timeout)
2056 {
2057     mDNSs32 ticks;
2058     struct timeval interval;
2059 
2060     // 1. Call mDNS_Execute() to let mDNSCore do what it needs to do
2061     mDNSs32 nextevent = mDNS_Execute(m);
2062 
2063     // 3. Calculate the time remaining to the next scheduled event (in struct timeval format)
2064     ticks = nextevent - mDNS_TimeNow(m);
2065     if (ticks < 1) ticks = 1;
2066     interval.tv_sec  = ticks >> 10;                     // The high 22 bits are seconds
2067     interval.tv_usec = ((ticks & 0x3FF) * 15625) / 16;  // The low 10 bits are 1024ths
2068 
2069     // 4. If client's proposed timeout is more than what we want, then reduce it
2070     if (timeout->tv_sec > interval.tv_sec ||
2071         (timeout->tv_sec == interval.tv_sec && timeout->tv_usec > interval.tv_usec))
2072         *timeout = interval;
2073 }
2074 
2075 mDNSexport void mDNSPosixGetFDSet(mDNS *m, int *nfds, fd_set *readfds, fd_set *writefds, struct timeval *timeout)
2076 {
2077     mDNSPosixGetNextDNSEventTime(m, timeout);
2078     mDNSPosixGetFDSetForSelect(m, nfds, readfds, writefds);
2079 }
2080 
2081 mDNSexport void mDNSPosixProcessFDSet(mDNS *const m, fd_set *readfds, fd_set *writefds)
2082 {
2083     PosixNetworkInterface *info;
2084     PosixEventSource    *iSource;
2085     assert(m       != NULL);
2086     assert(readfds != NULL);
2087     info = (PosixNetworkInterface *)(m->HostInterfaces);
2088 
2089     if (m->p->unicastSocket4 != -1 && FD_ISSET(m->p->unicastSocket4, readfds))
2090     {
2091         FD_CLR(m->p->unicastSocket4, readfds);
2092         SocketDataReady(m, NULL, m->p->unicastSocket4);
2093     }
2094 #if HAVE_IPV6
2095     if (m->p->unicastSocket6 != -1 && FD_ISSET(m->p->unicastSocket6, readfds))
2096     {
2097         FD_CLR(m->p->unicastSocket6, readfds);
2098         SocketDataReady(m, NULL, m->p->unicastSocket6);
2099     }
2100 #endif
2101 
2102     while (info)
2103     {
2104         if (info->multicastSocket4 != -1 && FD_ISSET(info->multicastSocket4, readfds))
2105         {
2106             FD_CLR(info->multicastSocket4, readfds);
2107             SocketDataReady(m, info, info->multicastSocket4);
2108         }
2109 #if HAVE_IPV6
2110         if (info->multicastSocket6 != -1 && FD_ISSET(info->multicastSocket6, readfds))
2111         {
2112             FD_CLR(info->multicastSocket6, readfds);
2113             SocketDataReady(m, info, info->multicastSocket6);
2114         }
2115 #endif
2116         info = (PosixNetworkInterface *)(info->coreIntf.next);
2117     }
2118 
2119     // Now process routing socket events, discovery relay events and anything else of that ilk.
2120     for (iSource = gEventSources; iSource; iSource = iSource->next)
2121     {
2122         if (iSource->readCallback != NULL && FD_ISSET(iSource->fd, readfds))
2123         {
2124             iSource->readCallback(iSource->fd, iSource->readContext);
2125             break;  // in case callback removed elements from gEventSources
2126         }
2127         else if (iSource->writeCallback != NULL && FD_ISSET(iSource->fd, writefds))
2128         {
2129             mDNSPosixEventCallback writeCallback = iSource->writeCallback;
2130             // Write events are one-shot: to get another event, the consumer has to put in a new request.
2131             // We reset this before calling the callback just in case the callback requests another write
2132             // callback, or deletes the event context from the list.
2133             iSource->writeCallback = NULL;
2134             writeCallback(iSource->fd, iSource->writeContext);
2135             break;  // in case callback removed elements from gEventSources
2136         }
2137     }
2138 }
2139 
2140 mDNSu32 mDNSPlatformEventContextSize = sizeof (PosixEventSource);
2141 
2142 mDNSlocal void requestIOEvents(PosixEventSource *newSource, const char *taskName,
2143                                   mDNSPosixEventCallback callback, void *context, int flag)
2144 {
2145     PosixEventSource **epp = &gEventSources;
2146 
2147     if (newSource->fd >= (int) FD_SETSIZE || newSource->fd < 0)
2148     {
2149         LogMsg("requestIOEvents called with fd %d > FD_SETSIZE %d.", newSource->fd, FD_SETSIZE);
2150         assert(0);
2151     }
2152     if (callback == NULL)
2153     {
2154         LogMsg("requestIOEvents called no callback.", newSource->fd, FD_SETSIZE);
2155         assert(0);
2156     }
2157 
2158     // See if this event context is already on the list; if it is, no need to scan the list.
2159     if (!(newSource->flags & PosixEventFlag_OnList))
2160     {
2161         while (*epp)
2162         {
2163             // This should never happen.
2164             if (newSource == *epp)
2165             {
2166                 LogMsg("Event context marked not on list but is on list.");
2167                 assert(0);
2168             }
2169             epp = &(*epp)->next;
2170         }
2171         if (*epp == NULL)
2172         {
2173             *epp = newSource;
2174             newSource->next = NULL;
2175             newSource->flags = PosixEventFlag_OnList;
2176         }
2177     }
2178 
2179     if (flag & PosixEventFlag_Read)
2180     {
2181         newSource->readCallback = callback;
2182         newSource->readContext = context;
2183         newSource->flags |= PosixEventFlag_Read;
2184         newSource->readTaskName = taskName;
2185     }
2186     if (flag & PosixEventFlag_Write)
2187     {
2188         newSource->writeCallback = callback;
2189         newSource->writeContext = context;
2190         newSource->flags |= PosixEventFlag_Write;
2191         newSource->writeTaskName = taskName;
2192     }
2193 }
2194 
2195 mDNSlocal void requestReadEvents(PosixEventSource *eventSource,
2196                                     const char *taskName, mDNSPosixEventCallback callback, void *context)
2197 {
2198     requestIOEvents(eventSource, taskName, callback, context, PosixEventFlag_Read);
2199 }
2200 
2201 mDNSlocal void requestWriteEvents(PosixEventSource *eventSource,
2202                                      const char *taskName, mDNSPosixEventCallback callback, void *context)
2203 {
2204     requestIOEvents(eventSource, taskName, callback, context, PosixEventFlag_Write);
2205 }
2206 
2207 // Remove a file descriptor from the set that mDNSPosixRunEventLoopOnce() listens to.
2208 mDNSlocal mStatus stopReadOrWriteEvents(int fd, mDNSBool freeContext, mDNSBool removeContext, int flags)
2209 {
2210     PosixEventSource *iSource, **epp = &gEventSources;
2211 
2212     while (*epp)
2213     {
2214         iSource = *epp;
2215         if (fd == iSource->fd)
2216         {
2217             if (flags & PosixEventFlag_Read)
2218             {
2219                 iSource->readCallback = NULL;
2220                 iSource->readContext = NULL;
2221             }
2222             if (flags & PosixEventFlag_Write)
2223             {
2224                 iSource->writeCallback = NULL;
2225                 iSource->writeContext = NULL;
2226             }
2227             if (iSource->writeCallback == NULL && iSource->readCallback == NULL)
2228             {
2229                 if (removeContext || freeContext)
2230                     *epp = iSource->next;
2231                 if (freeContext)
2232                     free(iSource);
2233             }
2234             return mStatus_NoError;
2235         }
2236         epp = &(*epp)->next;
2237     }
2238     return mStatus_NoSuchNameErr;
2239 }
2240 
2241 // Some of the mDNSPosix client code relies on being able to add FDs to the event loop without
2242 // providing storage for the event-related info.   mDNSPosixAddFDToEventLoop and
2243 // mDNSPosixRemoveFDFromEventLoop handle the event structure storage automatically.
2244 mStatus mDNSPosixAddFDToEventLoop(int fd, mDNSPosixEventCallback callback, void *context)
2245 {
2246     PosixEventSource *newSource;
2247 
2248     newSource = (PosixEventSource*) malloc(sizeof *newSource);
2249     if (NULL == newSource)
2250         return mStatus_NoMemoryErr;
2251     memset(newSource, 0, sizeof *newSource);
2252     newSource->fd = fd;
2253 
2254     requestReadEvents(newSource, "mDNSPosixAddFDToEventLoop", callback, context);
2255     return mStatus_NoError;
2256 }
2257 
2258 mStatus mDNSPosixRemoveFDFromEventLoop(int fd)
2259 {
2260     return stopReadOrWriteEvents(fd, mDNStrue, mDNStrue, PosixEventFlag_Read | PosixEventFlag_Write);
2261 }
2262 
2263 // Simply note the received signal in gEventSignals.
2264 mDNSlocal void  NoteSignal(int signum)
2265 {
2266     sigaddset(&gEventSignals, signum);
2267 }
2268 
2269 // Tell the event package to listen for signal and report it in mDNSPosixRunEventLoopOnce().
2270 mStatus mDNSPosixListenForSignalInEventLoop(int signum)
2271 {
2272     struct sigaction action;
2273     mStatus err;
2274 
2275     mDNSPlatformMemZero(&action, sizeof action);        // more portable than member-wise assignment
2276     action.sa_handler = NoteSignal;
2277     err = sigaction(signum, &action, (struct sigaction*) NULL);
2278 
2279     sigaddset(&gEventSignalSet, signum);
2280 
2281     return err;
2282 }
2283 
2284 // Tell the event package to stop listening for signal in mDNSPosixRunEventLoopOnce().
2285 mStatus mDNSPosixIgnoreSignalInEventLoop(int signum)
2286 {
2287     struct sigaction action;
2288     mStatus err;
2289 
2290     mDNSPlatformMemZero(&action, sizeof action);        // more portable than member-wise assignment
2291     action.sa_handler = SIG_DFL;
2292     err = sigaction(signum, &action, (struct sigaction*) NULL);
2293 
2294     sigdelset(&gEventSignalSet, signum);
2295 
2296     return err;
2297 }
2298 
2299 // Do a single pass through the attendent event sources and dispatch any found to their callbacks.
2300 // Return as soon as internal timeout expires, or a signal we're listening for is received.
2301 mStatus mDNSPosixRunEventLoopOnce(mDNS *m, const struct timeval *pTimeout,
2302                                   sigset_t *pSignalsReceived, mDNSBool *pDataDispatched)
2303 {
2304     fd_set listenFDs;
2305     fd_set writeFDs;
2306     int numFDs = 0, numReady;
2307     struct timeval timeout = *pTimeout;
2308 
2309     // 1. Set up the fd_set as usual here.
2310     // This example client has no file descriptors of its own,
2311     // but a real application would call FD_SET to add them to the set here
2312     FD_ZERO(&listenFDs);
2313     FD_ZERO(&writeFDs);
2314 
2315     // 2. Set up the timeout.
2316     mDNSPosixGetNextDNSEventTime(m, &timeout);
2317 
2318     // Include the sockets that are listening to the wire in our select() set
2319     mDNSPosixGetFDSetForSelect(m, &numFDs, &listenFDs, &writeFDs);
2320     numReady = select(numFDs, &listenFDs, &writeFDs, (fd_set*) NULL, &timeout);
2321 
2322     if (numReady > 0)
2323     {
2324         mDNSPosixProcessFDSet(m, &listenFDs, &writeFDs);
2325         *pDataDispatched = mDNStrue;
2326     }
2327     else if (numReady < 0)
2328     {
2329 	if (errno != EINTR) {
2330             // This should never happen, represents a coding error, and is not recoverable, since
2331             // we'll just sit here spinning and never receive another event.   The usual reason for
2332             // it to happen is that an FD was closed but not removed from the event list.
2333             LogMsg("select failed: %s", strerror(errno));
2334             abort();
2335         }
2336     }
2337     else
2338         *pDataDispatched = mDNSfalse;
2339 
2340     (void) sigprocmask(SIG_BLOCK, &gEventSignalSet, (sigset_t*) NULL);
2341     *pSignalsReceived = gEventSignals;
2342     sigemptyset(&gEventSignals);
2343     (void) sigprocmask(SIG_UNBLOCK, &gEventSignalSet, (sigset_t*) NULL);
2344 
2345     return mStatus_NoError;
2346 }
2347