xref: /illumos-gate/usr/src/contrib/mDNSResponder/mDNSPosix/mDNSPosix.c (revision 1a065e93eee983124652c3eb0cfdcb4776cd89ab)
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                     continue;
1345                 }
1346                 if (i->ifa_flags & IFF_LOOPBACK)
1347                 {
1348                     if (firstLoopback == NULL)
1349                     {
1350                         firstLoopback = i;
1351                         firstLoopbackIndex = ifIndex;
1352                     }
1353                 }
1354                 else
1355                 {
1356                     if (SetupOneInterface(m, i->ifa_addr, i->ifa_netmask, i->ifa_name, ifIndex) == 0)
1357                     {
1358                         if (i->ifa_addr->sa_family == AF_INET)
1359                         {
1360                             foundav4 = mDNStrue;
1361                         }
1362                     }
1363                 }
1364             }
1365             i = i->ifa_next;
1366         }
1367 
1368         // If we found no normal interfaces but we did find a loopback interface, register the
1369         // loopback interface.  This allows self-discovery if no interfaces are configured.
1370         // Temporary workaround: Multicast loopback on IPv6 interfaces appears not to work.
1371         // In the interim, we skip loopback interface only if we found at least one v4 interface to use
1372         // if ((m->HostInterfaces == NULL) && (firstLoopback != NULL))
1373         if (!foundav4 && firstLoopback)
1374         {
1375             (void)SetupOneInterface(m, firstLoopback->ifa_addr, firstLoopback->ifa_netmask, firstLoopback->ifa_name,
1376                                     firstLoopbackIndex);
1377         }
1378     }
1379 
1380     // Clean up.
1381     if (intfList != NULL) freeifaddrs(intfList);
1382 
1383     // Clean up any interfaces that have been hanging around on the RecentInterfaces list for more than a minute
1384     PosixNetworkInterface **ri = &gRecentInterfaces;
1385     const mDNSs32 utc = mDNSPlatformUTC();
1386     while (*ri)
1387     {
1388         PosixNetworkInterface *pi = *ri;
1389         if (utc - pi->LastSeen < 60) ri = (PosixNetworkInterface **)&pi->coreIntf.next;
1390         else { *ri = (PosixNetworkInterface *)pi->coreIntf.next; free(pi); }
1391     }
1392 
1393     return err;
1394 }
1395 
1396 #if USES_NETLINK
1397 
1398 // See <http://www.faqs.org/rfcs/rfc3549.html> for a description of NetLink
1399 
1400 // Open a socket that will receive interface change notifications
1401 mDNSlocal mStatus OpenIfNotifySocket(int *pFD)
1402 {
1403     mStatus err = mStatus_NoError;
1404     struct sockaddr_nl snl;
1405     int sock;
1406     int ret;
1407 
1408     sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
1409     if (sock < 0)
1410         return errno;
1411 
1412     // Configure read to be non-blocking because inbound msg size is not known in advance
1413     (void) fcntl(sock, F_SETFL, O_NONBLOCK);
1414 
1415     /* Subscribe the socket to Link & IP addr notifications. */
1416     mDNSPlatformMemZero(&snl, sizeof snl);
1417     snl.nl_family = AF_NETLINK;
1418     snl.nl_groups = RTMGRP_LINK | RTMGRP_IPV4_IFADDR;
1419     ret = bind(sock, (struct sockaddr *) &snl, sizeof snl);
1420     if (0 == ret)
1421         *pFD = sock;
1422     else
1423         err = errno;
1424 
1425     return err;
1426 }
1427 
1428 #if MDNS_DEBUGMSGS
1429 mDNSlocal void      PrintNetLinkMsg(const struct nlmsghdr *pNLMsg)
1430 {
1431     const char *kNLMsgTypes[] = { "", "NLMSG_NOOP", "NLMSG_ERROR", "NLMSG_DONE", "NLMSG_OVERRUN" };
1432     const char *kNLRtMsgTypes[] = { "RTM_NEWLINK", "RTM_DELLINK", "RTM_GETLINK", "RTM_NEWADDR", "RTM_DELADDR", "RTM_GETADDR" };
1433 
1434     printf("nlmsghdr len=%d, type=%s, flags=0x%x\n", pNLMsg->nlmsg_len,
1435            pNLMsg->nlmsg_type < RTM_BASE ? kNLMsgTypes[pNLMsg->nlmsg_type] : kNLRtMsgTypes[pNLMsg->nlmsg_type - RTM_BASE],
1436            pNLMsg->nlmsg_flags);
1437 
1438     if (RTM_NEWLINK <= pNLMsg->nlmsg_type && pNLMsg->nlmsg_type <= RTM_GETLINK)
1439     {
1440         struct ifinfomsg    *pIfInfo = (struct ifinfomsg*) NLMSG_DATA(pNLMsg);
1441         printf("ifinfomsg family=%d, type=%d, index=%d, flags=0x%x, change=0x%x\n", pIfInfo->ifi_family,
1442                pIfInfo->ifi_type, pIfInfo->ifi_index, pIfInfo->ifi_flags, pIfInfo->ifi_change);
1443 
1444     }
1445     else if (RTM_NEWADDR <= pNLMsg->nlmsg_type && pNLMsg->nlmsg_type <= RTM_GETADDR)
1446     {
1447         struct ifaddrmsg    *pIfAddr = (struct ifaddrmsg*) NLMSG_DATA(pNLMsg);
1448         printf("ifaddrmsg family=%d, index=%d, flags=0x%x\n", pIfAddr->ifa_family,
1449                pIfAddr->ifa_index, pIfAddr->ifa_flags);
1450     }
1451     printf("\n");
1452 }
1453 #endif
1454 
1455 mDNSlocal mDNSu32       ProcessRoutingNotification(int sd)
1456 // Read through the messages on sd and if any indicate that any interface records should
1457 // be torn down and rebuilt, return affected indices as a bitmask. Otherwise return 0.
1458 {
1459     ssize_t readCount;
1460     char buff[4096];
1461     struct nlmsghdr         *pNLMsg = (struct nlmsghdr*) buff;
1462     mDNSu32 result = 0;
1463 
1464     // The structure here is more complex than it really ought to be because,
1465     // unfortunately, there's no good way to size a buffer in advance large
1466     // enough to hold all pending data and so avoid message fragmentation.
1467     // (Note that FIONREAD is not supported on AF_NETLINK.)
1468 
1469     readCount = read(sd, buff, sizeof buff);
1470     while (1)
1471     {
1472         // Make sure we've got an entire nlmsghdr in the buffer, and payload, too.
1473         // If not, discard already-processed messages in buffer and read more data.
1474         if (((char*) &pNLMsg[1] > (buff + readCount)) ||    // i.e. *pNLMsg extends off end of buffer
1475             ((char*) pNLMsg + pNLMsg->nlmsg_len > (buff + readCount)))
1476         {
1477             if (buff < (char*) pNLMsg)      // we have space to shuffle
1478             {
1479                 // discard processed data
1480                 readCount -= ((char*) pNLMsg - buff);
1481                 memmove(buff, pNLMsg, readCount);
1482                 pNLMsg = (struct nlmsghdr*) buff;
1483 
1484                 // read more data
1485                 readCount += read(sd, buff + readCount, sizeof buff - readCount);
1486                 continue;                   // spin around and revalidate with new readCount
1487             }
1488             else
1489                 break;  // Otherwise message does not fit in buffer
1490         }
1491 
1492 #if MDNS_DEBUGMSGS
1493         PrintNetLinkMsg(pNLMsg);
1494 #endif
1495 
1496         // Process the NetLink message
1497         if (pNLMsg->nlmsg_type == RTM_GETLINK || pNLMsg->nlmsg_type == RTM_NEWLINK)
1498             result |= 1 << ((struct ifinfomsg*) NLMSG_DATA(pNLMsg))->ifi_index;
1499         else if (pNLMsg->nlmsg_type == RTM_DELADDR || pNLMsg->nlmsg_type == RTM_NEWADDR)
1500             result |= 1 << ((struct ifaddrmsg*) NLMSG_DATA(pNLMsg))->ifa_index;
1501 
1502         // Advance pNLMsg to the next message in the buffer
1503         if ((pNLMsg->nlmsg_flags & NLM_F_MULTI) != 0 && pNLMsg->nlmsg_type != NLMSG_DONE)
1504         {
1505             ssize_t len = readCount - ((char*)pNLMsg - buff);
1506             pNLMsg = NLMSG_NEXT(pNLMsg, len);
1507         }
1508         else
1509             break;  // all done!
1510     }
1511 
1512     return result;
1513 }
1514 
1515 #else // USES_NETLINK
1516 
1517 // Open a socket that will receive interface change notifications
1518 mDNSlocal mStatus OpenIfNotifySocket(int *pFD)
1519 {
1520     *pFD = socket(AF_ROUTE, SOCK_RAW, 0);
1521 
1522     if (*pFD < 0)
1523         return mStatus_UnknownErr;
1524 
1525     // Configure read to be non-blocking because inbound msg size is not known in advance
1526     (void) fcntl(*pFD, F_SETFL, O_NONBLOCK);
1527 
1528     return mStatus_NoError;
1529 }
1530 
1531 #if MDNS_DEBUGMSGS
1532 mDNSlocal void      PrintRoutingSocketMsg(const struct ifa_msghdr *pRSMsg)
1533 {
1534     const char *kRSMsgTypes[] = { "", "RTM_ADD", "RTM_DELETE", "RTM_CHANGE", "RTM_GET", "RTM_LOSING",
1535                                   "RTM_REDIRECT", "RTM_MISS", "RTM_LOCK", "RTM_OLDADD", "RTM_OLDDEL", "RTM_RESOLVE",
1536                                   "RTM_NEWADDR", "RTM_DELADDR", "RTM_IFINFO", "RTM_NEWMADDR", "RTM_DELMADDR" };
1537 
1538     int index = pRSMsg->ifam_type == RTM_IFINFO ? ((struct if_msghdr*) pRSMsg)->ifm_index : pRSMsg->ifam_index;
1539 
1540     printf("ifa_msghdr len=%d, type=%s, index=%d\n", pRSMsg->ifam_msglen, kRSMsgTypes[pRSMsg->ifam_type], index);
1541 }
1542 #endif
1543 
1544 mDNSlocal mDNSu32       ProcessRoutingNotification(int sd)
1545 // Read through the messages on sd and if any indicate that any interface records should
1546 // be torn down and rebuilt, return affected indices as a bitmask. Otherwise return 0.
1547 {
1548     ssize_t readCount;
1549     char buff[4096];
1550     struct ifa_msghdr       *pRSMsg = (struct ifa_msghdr*) buff;
1551     mDNSu32 result = 0;
1552 
1553     readCount = read(sd, buff, sizeof buff);
1554     if (readCount < (ssize_t) sizeof(struct ifa_msghdr))
1555         return mStatus_UnsupportedErr;      // cannot decipher message
1556 
1557 #if MDNS_DEBUGMSGS
1558     PrintRoutingSocketMsg(pRSMsg);
1559 #endif
1560 
1561     // Process the message
1562     switch (pRSMsg->ifam_type)
1563     {
1564     case RTM_NEWADDR:
1565     case RTM_DELADDR:
1566     case RTM_IFINFO:
1567     /*
1568      * ADD & DELETE are happening when IPv6 announces are changing,
1569      * and for some reason it will stop mdnsd to announce IPv6
1570      * addresses. So we force mdnsd to check interfaces.
1571      */
1572     case RTM_ADD:
1573     case RTM_DELETE:
1574         if (pRSMsg->ifam_type == RTM_IFINFO)
1575             result |= 1 << ((struct if_msghdr*) pRSMsg)->ifm_index;
1576         else
1577             result |= 1 << pRSMsg->ifam_index;
1578     break;
1579     }
1580 
1581     return result;
1582 }
1583 
1584 #endif // USES_NETLINK
1585 
1586 // Called when data appears on interface change notification socket
1587 mDNSlocal void InterfaceChangeCallback(int fd, void *context)
1588 {
1589     IfChangeRec     *pChgRec = (IfChangeRec*) context;
1590     fd_set readFDs;
1591     mDNSu32 changedInterfaces = 0;
1592     struct timeval zeroTimeout = { 0, 0 };
1593 
1594     (void)fd; // Unused
1595 
1596     FD_ZERO(&readFDs);
1597     FD_SET(pChgRec->NotifySD, &readFDs);
1598 
1599     do
1600     {
1601         changedInterfaces |= ProcessRoutingNotification(pChgRec->NotifySD);
1602     }
1603     while (0 < select(pChgRec->NotifySD + 1, &readFDs, (fd_set*) NULL, (fd_set*) NULL, &zeroTimeout));
1604 
1605     // Currently we rebuild the entire interface list whenever any interface change is
1606     // detected. If this ever proves to be a performance issue in a multi-homed
1607     // configuration, more care should be paid to changedInterfaces.
1608     if (changedInterfaces)
1609         mDNSPlatformPosixRefreshInterfaceList(pChgRec->mDNS);
1610 }
1611 
1612 // Register with either a Routing Socket or RtNetLink to listen for interface changes.
1613 mDNSlocal mStatus WatchForInterfaceChange(mDNS *const m)
1614 {
1615     mStatus err;
1616     IfChangeRec *pChgRec;
1617 
1618     pChgRec = (IfChangeRec*) mDNSPlatformMemAllocateClear(sizeof *pChgRec);
1619     if (pChgRec == NULL)
1620         return mStatus_NoMemoryErr;
1621 
1622     pChgRec->mDNS = m;
1623     err = OpenIfNotifySocket(&pChgRec->NotifySD);
1624     if (err == 0)
1625         err = mDNSPosixAddFDToEventLoop(pChgRec->NotifySD, InterfaceChangeCallback, pChgRec);
1626     if (err)
1627         mDNSPlatformMemFree(pChgRec);
1628 
1629     return err;
1630 }
1631 
1632 // Test to see if we're the first client running on UDP port 5353, by trying to bind to 5353 without using SO_REUSEPORT.
1633 // If we fail, someone else got here first. That's not a big problem; we can share the port for multicast responses --
1634 // we just need to be aware that we shouldn't expect to successfully receive unicast UDP responses.
1635 mDNSlocal mDNSBool mDNSPlatformInit_CanReceiveUnicast(void)
1636 {
1637     int err;
1638     int s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
1639     struct sockaddr_in s5353;
1640     s5353.sin_family      = AF_INET;
1641     s5353.sin_port        = MulticastDNSPort.NotAnInteger;
1642     s5353.sin_addr.s_addr = 0;
1643     err = bind(s, (struct sockaddr *)&s5353, sizeof(s5353));
1644     close(s);
1645     if (err) debugf("No unicast UDP responses");
1646     else debugf("Unicast UDP responses okay");
1647     return(err == 0);
1648 }
1649 
1650 // mDNS core calls this routine to initialise the platform-specific data.
1651 mDNSexport mStatus mDNSPlatformInit(mDNS *const m)
1652 {
1653     int err = 0;
1654     struct sockaddr sa;
1655     assert(m != NULL);
1656 
1657     if (mDNSPlatformInit_CanReceiveUnicast()) m->CanReceiveUnicastOn5353 = mDNStrue;
1658 
1659     // Tell mDNS core the names of this machine.
1660 
1661     // Set up the nice label
1662     m->nicelabel.c[0] = 0;
1663     GetUserSpecifiedFriendlyComputerName(&m->nicelabel);
1664     if (m->nicelabel.c[0] == 0) MakeDomainLabelFromLiteralString(&m->nicelabel, "Computer");
1665 
1666     // Set up the RFC 1034-compliant label
1667     m->hostlabel.c[0] = 0;
1668     GetUserSpecifiedRFC1034ComputerName(&m->hostlabel);
1669     if (m->hostlabel.c[0] == 0) MakeDomainLabelFromLiteralString(&m->hostlabel, "Computer");
1670 
1671     mDNS_SetFQDN(m);
1672 
1673     sa.sa_family = AF_INET;
1674     m->p->unicastSocket4 = -1;
1675     if (err == mStatus_NoError) err = SetupSocket(&sa, zeroIPPort, 0, &m->p->unicastSocket4);
1676 #if HAVE_IPV6
1677     sa.sa_family = AF_INET6;
1678     m->p->unicastSocket6 = -1;
1679     if (err == mStatus_NoError) err = SetupSocket(&sa, zeroIPPort, 0, &m->p->unicastSocket6);
1680 #endif
1681 
1682     // Tell mDNS core about the network interfaces on this machine.
1683     if (err == mStatus_NoError) err = SetupInterfaceList(m);
1684 
1685     // Tell mDNS core about DNS Servers
1686     mDNS_Lock(m);
1687     if (err == mStatus_NoError) ParseDNSServers(m, uDNS_SERVERS_FILE);
1688     mDNS_Unlock(m);
1689 
1690     if (err == mStatus_NoError)
1691     {
1692         err = WatchForInterfaceChange(m);
1693         // Failure to observe interface changes is non-fatal.
1694         if (err != mStatus_NoError)
1695         {
1696             fprintf(stderr, "mDNS(%d) WARNING: Unable to detect interface changes (%d).\n",
1697 		(int)getpid(), err);
1698             err = mStatus_NoError;
1699         }
1700     }
1701 
1702     // We don't do asynchronous initialization on the Posix platform, so by the time
1703     // we get here the setup will already have succeeded or failed.  If it succeeded,
1704     // we should just call mDNSCoreInitComplete() immediately.
1705     if (err == mStatus_NoError)
1706         mDNSCoreInitComplete(m, mStatus_NoError);
1707 
1708     return PosixErrorToStatus(err);
1709 }
1710 
1711 // mDNS core calls this routine to clean up the platform-specific data.
1712 // In our case all we need to do is to tear down every network interface.
1713 mDNSexport void mDNSPlatformClose(mDNS *const m)
1714 {
1715     int rv;
1716     assert(m != NULL);
1717     ClearInterfaceList(m);
1718     if (m->p->unicastSocket4 != -1)
1719     {
1720         rv = close(m->p->unicastSocket4);
1721         assert(rv == 0);
1722     }
1723 #if HAVE_IPV6
1724     if (m->p->unicastSocket6 != -1)
1725     {
1726         rv = close(m->p->unicastSocket6);
1727         assert(rv == 0);
1728     }
1729 #endif
1730 }
1731 
1732 // This is used internally by InterfaceChangeCallback.
1733 // It's also exported so that the Standalone Responder (mDNSResponderPosix)
1734 // can call it in response to a SIGHUP (mainly for debugging purposes).
1735 mDNSexport mStatus mDNSPlatformPosixRefreshInterfaceList(mDNS *const m)
1736 {
1737     int err;
1738     // This is a pretty heavyweight way to process interface changes --
1739     // destroying the entire interface list and then making fresh one from scratch.
1740     // We should make it like the OS X version, which leaves unchanged interfaces alone.
1741     ClearInterfaceList(m);
1742     err = SetupInterfaceList(m);
1743     return PosixErrorToStatus(err);
1744 }
1745 
1746 #if COMPILER_LIKES_PRAGMA_MARK
1747 #pragma mark ***** Locking
1748 #endif
1749 
1750 // On the Posix platform, locking is a no-op because we only ever enter
1751 // mDNS core on the main thread.
1752 
1753 // mDNS core calls this routine when it wants to prevent
1754 // the platform from reentering mDNS core code.
1755 mDNSexport void    mDNSPlatformLock   (const mDNS *const m)
1756 {
1757     (void) m;   // Unused
1758 }
1759 
1760 // mDNS core calls this routine when it release the lock taken by
1761 // mDNSPlatformLock and allow the platform to reenter mDNS core code.
1762 mDNSexport void    mDNSPlatformUnlock (const mDNS *const m)
1763 {
1764     (void) m;   // Unused
1765 }
1766 
1767 #if COMPILER_LIKES_PRAGMA_MARK
1768 #pragma mark ***** Strings
1769 #endif
1770 
1771 mDNSexport mDNSu32  mDNSPlatformStrLCopy(void *dst, const void *src, mDNSu32 len)
1772 {
1773 #if HAVE_STRLCPY
1774     return ((mDNSu32)strlcpy((char *)dst, (const char *)src, len));
1775 #else
1776     size_t srcLen;
1777 
1778     srcLen = strlen((const char *)src);
1779     if (srcLen < len)
1780     {
1781         memcpy(dst, src, srcLen + 1);
1782     }
1783     else if (len > 0)
1784     {
1785         memcpy(dst, src, len - 1);
1786         ((char *)dst)[len - 1] = '\0';
1787     }
1788 
1789     return ((mDNSu32)srcLen);
1790 #endif
1791 }
1792 
1793 // mDNS core calls this routine to get the length of a C string.
1794 // On the Posix platform this maps directly to the ANSI C strlen.
1795 mDNSexport mDNSu32  mDNSPlatformStrLen (const void *src)
1796 {
1797     return strlen((const char*)src);
1798 }
1799 
1800 // mDNS core calls this routine to copy memory.
1801 // On the Posix platform this maps directly to the ANSI C memcpy.
1802 mDNSexport void    mDNSPlatformMemCopy(void *dst, const void *src, mDNSu32 len)
1803 {
1804     memcpy(dst, src, len);
1805 }
1806 
1807 // mDNS core calls this routine to test whether blocks of memory are byte-for-byte
1808 // identical. On the Posix platform this is a simple wrapper around ANSI C memcmp.
1809 mDNSexport mDNSBool mDNSPlatformMemSame(const void *dst, const void *src, mDNSu32 len)
1810 {
1811     return memcmp(dst, src, len) == 0;
1812 }
1813 
1814 // If the caller wants to know the exact return of memcmp, then use this instead
1815 // of mDNSPlatformMemSame
1816 mDNSexport int mDNSPlatformMemCmp(const void *dst, const void *src, mDNSu32 len)
1817 {
1818     return (memcmp(dst, src, len));
1819 }
1820 
1821 mDNSexport void mDNSPlatformQsort(void *base, int nel, int width, int (*compar)(const void *, const void *))
1822 {
1823     (void)qsort(base, nel, width, compar);
1824 }
1825 
1826 // Proxy stub functions
1827 mDNSexport mDNSu8 *DNSProxySetAttributes(DNSQuestion *q, DNSMessageHeader *h, DNSMessage *msg, mDNSu8 *ptr, mDNSu8 *limit)
1828 {
1829     (void) q;
1830     (void) h;
1831     (void) msg;
1832     (void) ptr;
1833     (void) limit;
1834 
1835     return ptr;
1836 }
1837 
1838 mDNSexport void DNSProxyInit(mDNSu32 IpIfArr[], mDNSu32 OpIf)
1839 {
1840     (void) IpIfArr;
1841     (void) OpIf;
1842 }
1843 
1844 mDNSexport void DNSProxyTerminate(void)
1845 {
1846 }
1847 
1848 // mDNS core calls this routine to clear blocks of memory.
1849 // On the Posix platform this is a simple wrapper around ANSI C memset.
1850 mDNSexport void  mDNSPlatformMemZero(void *dst, mDNSu32 len)
1851 {
1852     memset(dst, 0, len);
1853 }
1854 
1855 #if !MDNS_MALLOC_DEBUGGING
1856 mDNSexport void *mDNSPlatformMemAllocate(mDNSu32 len)      { return(mallocL("mDNSPlatformMemAllocate", len)); }
1857 mDNSexport void *mDNSPlatformMemAllocateClear(mDNSu32 len) { return(callocL(name, len)); }
1858 mDNSexport void  mDNSPlatformMemFree    (void *mem)        {          freeL("mDNSPlatformMemFree", mem); }
1859 #endif
1860 
1861 #if _PLATFORM_HAS_STRONG_PRNG_
1862 mDNSexport mDNSu32 mDNSPlatformRandomNumber(void)
1863 {
1864     return(arc4random());
1865 }
1866 #else
1867 mDNSexport mDNSu32 mDNSPlatformRandomSeed(void)
1868 {
1869     struct timeval tv;
1870     gettimeofday(&tv, NULL);
1871     return(tv.tv_usec);
1872 }
1873 #endif
1874 
1875 mDNSexport mDNSs32 mDNSPlatformOneSecond = 1024;
1876 
1877 mDNSexport mStatus mDNSPlatformTimeInit(void)
1878 {
1879     // No special setup is required on Posix -- we just use gettimeofday();
1880     // This is not really safe, because gettimeofday can go backwards if the user manually changes the date or time
1881     // We should find a better way to do this
1882     return(mStatus_NoError);
1883 }
1884 
1885 mDNSexport mDNSs32  mDNSPlatformRawTime()
1886 {
1887     struct timespec tm;
1888     int ret = clock_gettime(CLOCK_MONOTONIC, &tm);
1889     assert(ret == 0); // This call will only fail if the number of seconds does not fit in an object of type time_t.
1890 
1891     // tm.tv_sec is seconds since some unspecified starting point (it is usually the system start up time)
1892     // tm.tv_nsec is nanoseconds since the start of this second (i.e. values 0 to 999999999)
1893     // We use the lower 22 bits of tm.tv_sec for the top 22 bits of our result
1894     // 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.
1895     // This gives us a proper modular (cyclic) counter that has a resolution of roughly 1ms (actually 1/1024 second)
1896     // and correctly cycles every 2^22 seconds (4194304 seconds = approx 48 days).
1897 
1898     return ((tm.tv_sec << 10) | (tm.tv_nsec * 2 / 1953125));
1899 }
1900 
1901 mDNSexport mDNSs32 mDNSPlatformUTC(void)
1902 {
1903     return time(NULL);
1904 }
1905 
1906 mDNSexport void mDNSPlatformSendWakeupPacket(mDNSInterfaceID InterfaceID, char *EthAddr, char *IPAddr, int iteration)
1907 {
1908     (void) InterfaceID;
1909     (void) EthAddr;
1910     (void) IPAddr;
1911     (void) iteration;
1912 }
1913 
1914 mDNSexport mDNSBool mDNSPlatformValidRecordForInterface(const AuthRecord *rr, mDNSInterfaceID InterfaceID)
1915 {
1916     (void) rr;
1917     (void) InterfaceID;
1918 
1919     return 1;
1920 }
1921 
1922 mDNSexport mDNSBool mDNSPlatformValidQuestionForInterface(DNSQuestion *q, const NetworkInterfaceInfo *intf)
1923 {
1924     (void) q;
1925     (void) intf;
1926 
1927     return 1;
1928 }
1929 
1930 // Used for debugging purposes. For now, just set the buffer to zero
1931 mDNSexport void mDNSPlatformFormatTime(unsigned long te, mDNSu8 *buf, int bufsize)
1932 {
1933     (void) te;
1934     if (bufsize) buf[0] = 0;
1935 }
1936 
1937 mDNSexport void mDNSPlatformSendKeepalive(mDNSAddr *sadd, mDNSAddr *dadd, mDNSIPPort *lport, mDNSIPPort *rport, mDNSu32 seq, mDNSu32 ack, mDNSu16 win)
1938 {
1939     (void) sadd;    // Unused
1940     (void) dadd;    // Unused
1941     (void) lport;   // Unused
1942     (void) rport;   // Unused
1943     (void) seq;     // Unused
1944     (void) ack;     // Unused
1945     (void) win;     // Unused
1946 }
1947 
1948 mDNSexport mStatus mDNSPlatformRetrieveTCPInfo(mDNSAddr *laddr, mDNSIPPort *lport, mDNSAddr *raddr, mDNSIPPort *rport, mDNSTCPInfo *mti)
1949 {
1950     (void) laddr;   // Unused
1951     (void) raddr;   // Unused
1952     (void) lport;   // Unused
1953     (void) rport;   // Unused
1954     (void) mti;     // Unused
1955 
1956     return mStatus_NoError;
1957 }
1958 
1959 mDNSexport mStatus mDNSPlatformGetRemoteMacAddr(mDNSAddr *raddr)
1960 {
1961     (void) raddr; // Unused
1962 
1963     return mStatus_NoError;
1964 }
1965 
1966 mDNSexport mStatus    mDNSPlatformStoreSPSMACAddr(mDNSAddr *spsaddr, char *ifname)
1967 {
1968     (void) spsaddr; // Unused
1969     (void) ifname;  // Unused
1970 
1971     return mStatus_NoError;
1972 }
1973 
1974 mDNSexport mStatus    mDNSPlatformClearSPSData(void)
1975 {
1976     return mStatus_NoError;
1977 }
1978 
1979 mDNSexport mStatus mDNSPlatformStoreOwnerOptRecord(char *ifname, DNSMessage *msg, int length)
1980 {
1981     (void) ifname; // Unused
1982     (void) msg;    // Unused
1983     (void) length; // Unused
1984     return mStatus_UnsupportedErr;
1985 }
1986 
1987 mDNSexport mDNSu16 mDNSPlatformGetUDPPort(UDPSocket *sock)
1988 {
1989     (void) sock; // unused
1990 
1991     return (mDNSu16)-1;
1992 }
1993 
1994 mDNSexport mDNSBool mDNSPlatformInterfaceIsD2D(mDNSInterfaceID InterfaceID)
1995 {
1996     (void) InterfaceID; // unused
1997 
1998     return mDNSfalse;
1999 }
2000 
2001 mDNSexport void mDNSPlatformSetSocktOpt(void *sock, mDNSTransport_Type transType, mDNSAddr_Type addrType, const DNSQuestion *q)
2002 {
2003     (void) sock;
2004     (void) transType;
2005     (void) addrType;
2006     (void) q;
2007 }
2008 
2009 mDNSexport mDNSs32 mDNSPlatformGetPID()
2010 {
2011     return 0;
2012 }
2013 
2014 mDNSlocal void mDNSPosixAddToFDSet(int *nfds, fd_set *readfds, int s)
2015 {
2016     if (*nfds < s + 1) *nfds = s + 1;
2017     FD_SET(s, readfds);
2018 }
2019 
2020 mDNSexport void mDNSPosixGetFDSetForSelect(mDNS *m, int *nfds, fd_set *readfds, fd_set *writefds)
2021 {
2022     int numFDs = *nfds;
2023     PosixEventSource *iSource;
2024 
2025     // 2. Build our list of active file descriptors
2026     PosixNetworkInterface *info = (PosixNetworkInterface *)(m->HostInterfaces);
2027     if (m->p->unicastSocket4 != -1) mDNSPosixAddToFDSet(&numFDs, readfds, m->p->unicastSocket4);
2028 #if HAVE_IPV6
2029     if (m->p->unicastSocket6 != -1) mDNSPosixAddToFDSet(&numFDs, readfds, m->p->unicastSocket6);
2030 #endif
2031     while (info)
2032     {
2033         if (info->multicastSocket4 != -1) mDNSPosixAddToFDSet(&numFDs, readfds, info->multicastSocket4);
2034 #if HAVE_IPV6
2035         if (info->multicastSocket6 != -1) mDNSPosixAddToFDSet(&numFDs, readfds, info->multicastSocket6);
2036 #endif
2037         info = (PosixNetworkInterface *)(info->coreIntf.next);
2038     }
2039 
2040     // Copy over the event fds.   We have to do it this way because client-provided event loops expect
2041     // to initialize their FD sets first and then call mDNSPosixGetFDSet()
2042     for (iSource = gEventSources; iSource; iSource = iSource->next)
2043     {
2044         if (iSource->readCallback != NULL)
2045             FD_SET(iSource->fd, readfds);
2046         if (iSource->writeCallback != NULL)
2047             FD_SET(iSource->fd, writefds);
2048         if (numFDs <= iSource->fd)
2049             numFDs = iSource->fd + 1;
2050     }
2051     *nfds = numFDs;
2052 }
2053 
2054 mDNSexport void mDNSPosixGetNextDNSEventTime(mDNS *m, struct timeval *timeout)
2055 {
2056     mDNSs32 ticks;
2057     struct timeval interval;
2058 
2059     // 1. Call mDNS_Execute() to let mDNSCore do what it needs to do
2060     mDNSs32 nextevent = mDNS_Execute(m);
2061 
2062     // 3. Calculate the time remaining to the next scheduled event (in struct timeval format)
2063     ticks = nextevent - mDNS_TimeNow(m);
2064     if (ticks < 1) ticks = 1;
2065     interval.tv_sec  = ticks >> 10;                     // The high 22 bits are seconds
2066     interval.tv_usec = ((ticks & 0x3FF) * 15625) / 16;  // The low 10 bits are 1024ths
2067 
2068     // 4. If client's proposed timeout is more than what we want, then reduce it
2069     if (timeout->tv_sec > interval.tv_sec ||
2070         (timeout->tv_sec == interval.tv_sec && timeout->tv_usec > interval.tv_usec))
2071         *timeout = interval;
2072 }
2073 
2074 mDNSexport void mDNSPosixGetFDSet(mDNS *m, int *nfds, fd_set *readfds, fd_set *writefds, struct timeval *timeout)
2075 {
2076     mDNSPosixGetNextDNSEventTime(m, timeout);
2077     mDNSPosixGetFDSetForSelect(m, nfds, readfds, writefds);
2078 }
2079 
2080 mDNSexport void mDNSPosixProcessFDSet(mDNS *const m, fd_set *readfds, fd_set *writefds)
2081 {
2082     PosixNetworkInterface *info;
2083     PosixEventSource    *iSource;
2084     assert(m       != NULL);
2085     assert(readfds != NULL);
2086     info = (PosixNetworkInterface *)(m->HostInterfaces);
2087 
2088     if (m->p->unicastSocket4 != -1 && FD_ISSET(m->p->unicastSocket4, readfds))
2089     {
2090         FD_CLR(m->p->unicastSocket4, readfds);
2091         SocketDataReady(m, NULL, m->p->unicastSocket4);
2092     }
2093 #if HAVE_IPV6
2094     if (m->p->unicastSocket6 != -1 && FD_ISSET(m->p->unicastSocket6, readfds))
2095     {
2096         FD_CLR(m->p->unicastSocket6, readfds);
2097         SocketDataReady(m, NULL, m->p->unicastSocket6);
2098     }
2099 #endif
2100 
2101     while (info)
2102     {
2103         if (info->multicastSocket4 != -1 && FD_ISSET(info->multicastSocket4, readfds))
2104         {
2105             FD_CLR(info->multicastSocket4, readfds);
2106             SocketDataReady(m, info, info->multicastSocket4);
2107         }
2108 #if HAVE_IPV6
2109         if (info->multicastSocket6 != -1 && FD_ISSET(info->multicastSocket6, readfds))
2110         {
2111             FD_CLR(info->multicastSocket6, readfds);
2112             SocketDataReady(m, info, info->multicastSocket6);
2113         }
2114 #endif
2115         info = (PosixNetworkInterface *)(info->coreIntf.next);
2116     }
2117 
2118     // Now process routing socket events, discovery relay events and anything else of that ilk.
2119     for (iSource = gEventSources; iSource; iSource = iSource->next)
2120     {
2121         if (iSource->readCallback != NULL && FD_ISSET(iSource->fd, readfds))
2122         {
2123             iSource->readCallback(iSource->fd, iSource->readContext);
2124             break;  // in case callback removed elements from gEventSources
2125         }
2126         else if (iSource->writeCallback != NULL && FD_ISSET(iSource->fd, writefds))
2127         {
2128             mDNSPosixEventCallback writeCallback = iSource->writeCallback;
2129             // Write events are one-shot: to get another event, the consumer has to put in a new request.
2130             // We reset this before calling the callback just in case the callback requests another write
2131             // callback, or deletes the event context from the list.
2132             iSource->writeCallback = NULL;
2133             writeCallback(iSource->fd, iSource->writeContext);
2134             break;  // in case callback removed elements from gEventSources
2135         }
2136     }
2137 }
2138 
2139 mDNSu32 mDNSPlatformEventContextSize = sizeof (PosixEventSource);
2140 
2141 mDNSlocal void requestIOEvents(PosixEventSource *newSource, const char *taskName,
2142                                   mDNSPosixEventCallback callback, void *context, int flag)
2143 {
2144     PosixEventSource **epp = &gEventSources;
2145 
2146     if (newSource->fd >= (int) FD_SETSIZE || newSource->fd < 0)
2147     {
2148         LogMsg("requestIOEvents called with fd %d > FD_SETSIZE %d.", newSource->fd, FD_SETSIZE);
2149         assert(0);
2150     }
2151     if (callback == NULL)
2152     {
2153         LogMsg("requestIOEvents called no callback.", newSource->fd, FD_SETSIZE);
2154         assert(0);
2155     }
2156 
2157     // See if this event context is already on the list; if it is, no need to scan the list.
2158     if (!(newSource->flags & PosixEventFlag_OnList))
2159     {
2160         while (*epp)
2161         {
2162             // This should never happen.
2163             if (newSource == *epp)
2164             {
2165                 LogMsg("Event context marked not on list but is on list.");
2166                 assert(0);
2167             }
2168             epp = &(*epp)->next;
2169         }
2170         if (*epp == NULL)
2171         {
2172             *epp = newSource;
2173             newSource->next = NULL;
2174             newSource->flags = PosixEventFlag_OnList;
2175         }
2176     }
2177 
2178     if (flag & PosixEventFlag_Read)
2179     {
2180         newSource->readCallback = callback;
2181         newSource->readContext = context;
2182         newSource->flags |= PosixEventFlag_Read;
2183         newSource->readTaskName = taskName;
2184     }
2185     if (flag & PosixEventFlag_Write)
2186     {
2187         newSource->writeCallback = callback;
2188         newSource->writeContext = context;
2189         newSource->flags |= PosixEventFlag_Write;
2190         newSource->writeTaskName = taskName;
2191     }
2192 }
2193 
2194 mDNSlocal void requestReadEvents(PosixEventSource *eventSource,
2195                                     const char *taskName, mDNSPosixEventCallback callback, void *context)
2196 {
2197     requestIOEvents(eventSource, taskName, callback, context, PosixEventFlag_Read);
2198 }
2199 
2200 mDNSlocal void requestWriteEvents(PosixEventSource *eventSource,
2201                                      const char *taskName, mDNSPosixEventCallback callback, void *context)
2202 {
2203     requestIOEvents(eventSource, taskName, callback, context, PosixEventFlag_Write);
2204 }
2205 
2206 // Remove a file descriptor from the set that mDNSPosixRunEventLoopOnce() listens to.
2207 mDNSlocal mStatus stopReadOrWriteEvents(int fd, mDNSBool freeContext, mDNSBool removeContext, int flags)
2208 {
2209     PosixEventSource *iSource, **epp = &gEventSources;
2210 
2211     while (*epp)
2212     {
2213         iSource = *epp;
2214         if (fd == iSource->fd)
2215         {
2216             if (flags & PosixEventFlag_Read)
2217             {
2218                 iSource->readCallback = NULL;
2219                 iSource->readContext = NULL;
2220             }
2221             if (flags & PosixEventFlag_Write)
2222             {
2223                 iSource->writeCallback = NULL;
2224                 iSource->writeContext = NULL;
2225             }
2226             if (iSource->writeCallback == NULL && iSource->readCallback == NULL)
2227             {
2228                 if (removeContext || freeContext)
2229                     *epp = iSource->next;
2230                 if (freeContext)
2231                     free(iSource);
2232             }
2233             return mStatus_NoError;
2234         }
2235         epp = &(*epp)->next;
2236     }
2237     return mStatus_NoSuchNameErr;
2238 }
2239 
2240 // Some of the mDNSPosix client code relies on being able to add FDs to the event loop without
2241 // providing storage for the event-related info.   mDNSPosixAddFDToEventLoop and
2242 // mDNSPosixRemoveFDFromEventLoop handle the event structure storage automatically.
2243 mStatus mDNSPosixAddFDToEventLoop(int fd, mDNSPosixEventCallback callback, void *context)
2244 {
2245     PosixEventSource *newSource;
2246 
2247     newSource = (PosixEventSource*) malloc(sizeof *newSource);
2248     if (NULL == newSource)
2249         return mStatus_NoMemoryErr;
2250     memset(newSource, 0, sizeof *newSource);
2251     newSource->fd = fd;
2252 
2253     requestReadEvents(newSource, "mDNSPosixAddFDToEventLoop", callback, context);
2254     return mStatus_NoError;
2255 }
2256 
2257 mStatus mDNSPosixRemoveFDFromEventLoop(int fd)
2258 {
2259     return stopReadOrWriteEvents(fd, mDNStrue, mDNStrue, PosixEventFlag_Read | PosixEventFlag_Write);
2260 }
2261 
2262 // Simply note the received signal in gEventSignals.
2263 mDNSlocal void  NoteSignal(int signum)
2264 {
2265     sigaddset(&gEventSignals, signum);
2266 }
2267 
2268 // Tell the event package to listen for signal and report it in mDNSPosixRunEventLoopOnce().
2269 mStatus mDNSPosixListenForSignalInEventLoop(int signum)
2270 {
2271     struct sigaction action;
2272     mStatus err;
2273 
2274     mDNSPlatformMemZero(&action, sizeof action);        // more portable than member-wise assignment
2275     action.sa_handler = NoteSignal;
2276     err = sigaction(signum, &action, (struct sigaction*) NULL);
2277 
2278     sigaddset(&gEventSignalSet, signum);
2279 
2280     return err;
2281 }
2282 
2283 // Tell the event package to stop listening for signal in mDNSPosixRunEventLoopOnce().
2284 mStatus mDNSPosixIgnoreSignalInEventLoop(int signum)
2285 {
2286     struct sigaction action;
2287     mStatus err;
2288 
2289     mDNSPlatformMemZero(&action, sizeof action);        // more portable than member-wise assignment
2290     action.sa_handler = SIG_DFL;
2291     err = sigaction(signum, &action, (struct sigaction*) NULL);
2292 
2293     sigdelset(&gEventSignalSet, signum);
2294 
2295     return err;
2296 }
2297 
2298 // Do a single pass through the attendent event sources and dispatch any found to their callbacks.
2299 // Return as soon as internal timeout expires, or a signal we're listening for is received.
2300 mStatus mDNSPosixRunEventLoopOnce(mDNS *m, const struct timeval *pTimeout,
2301                                   sigset_t *pSignalsReceived, mDNSBool *pDataDispatched)
2302 {
2303     fd_set listenFDs;
2304     fd_set writeFDs;
2305     int numFDs = 0, numReady;
2306     struct timeval timeout = *pTimeout;
2307 
2308     // 1. Set up the fd_set as usual here.
2309     // This example client has no file descriptors of its own,
2310     // but a real application would call FD_SET to add them to the set here
2311     FD_ZERO(&listenFDs);
2312     FD_ZERO(&writeFDs);
2313 
2314     // 2. Set up the timeout.
2315     mDNSPosixGetNextDNSEventTime(m, &timeout);
2316 
2317     // Include the sockets that are listening to the wire in our select() set
2318     mDNSPosixGetFDSetForSelect(m, &numFDs, &listenFDs, &writeFDs);
2319     numReady = select(numFDs, &listenFDs, &writeFDs, (fd_set*) NULL, &timeout);
2320 
2321     if (numReady > 0)
2322     {
2323         mDNSPosixProcessFDSet(m, &listenFDs, &writeFDs);
2324         *pDataDispatched = mDNStrue;
2325     }
2326     else if (numReady < 0)
2327     {
2328 	if (errno != EINTR) {
2329             // This should never happen, represents a coding error, and is not recoverable, since
2330             // we'll just sit here spinning and never receive another event.   The usual reason for
2331             // it to happen is that an FD was closed but not removed from the event list.
2332             LogMsg("select failed: %s", strerror(errno));
2333             abort();
2334         }
2335     }
2336     else
2337         *pDataDispatched = mDNSfalse;
2338 
2339     (void) sigprocmask(SIG_BLOCK, &gEventSignalSet, (sigset_t*) NULL);
2340     *pSignalsReceived = gEventSignals;
2341     sigemptyset(&gEventSignals);
2342     (void) sigprocmask(SIG_UNBLOCK, &gEventSignalSet, (sigset_t*) NULL);
2343 
2344     return mStatus_NoError;
2345 }
2346