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