]> git.saurik.com Git - apple/mdnsresponder.git/blob - mDNSPosix/mDNSPosix.c
mDNSResponder-108.4.tar.gz
[apple/mdnsresponder.git] / mDNSPosix / mDNSPosix.c
1 /* -*- Mode: C; tab-width: 4 -*-
2 *
3 * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
4 *
5 * @APPLE_LICENSE_HEADER_START@
6 *
7 * This file contains Original Code and/or Modifications of Original Code
8 * as defined in and that are subject to the Apple Public Source License
9 * Version 2.0 (the 'License'). You may not use this file except in
10 * compliance with the License. Please obtain a copy of the License at
11 * http://www.opensource.apple.com/apsl/ and read it before using this
12 * file.
13 *
14 * The Original Code and all software distributed under the License are
15 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
19 * Please see the License for the specific language governing rights and
20 * limitations under the License.
21 *
22 * @APPLE_LICENSE_HEADER_END@
23 *
24 * Formatting notes:
25 * This code follows the "Whitesmiths style" C indentation rules. Plenty of discussion
26 * on C indentation can be found on the web, such as <http://www.kafejo.com/komp/1tbs.htm>,
27 * but for the sake of brevity here I will say just this: Curly braces are not syntactially
28 * part of an "if" statement; they are the beginning and ending markers of a compound statement;
29 * therefore common sense dictates that if they are part of a compound statement then they
30 * should be indented to the same level as everything else in that compound statement.
31 * Indenting curly braces at the same level as the "if" implies that curly braces are
32 * part of the "if", which is false. (This is as misleading as people who write "char* x,y;"
33 * thinking that variables x and y are both of type "char*" -- and anyone who doesn't
34 * understand why variable y is not of type "char*" just proves the point that poor code
35 * layout leads people to unfortunate misunderstandings about how the C language really works.)
36
37 Change History (most recent first):
38
39 $Log: mDNSPosix.c,v $
40 Revision 1.73 2005/10/11 21:31:46 cheshire
41 <rdar://problem/4296177> Don't depend on IP_RECVTTL succeeding (not available on all platforms)
42
43 Revision 1.72 2005/09/08 20:45:26 cheshire
44 Default dot-local host name should be "Computer" not "Macintosh",
45 since the machine this is running on is most likely NOT a Mac.
46
47 Revision 1.71 2005/02/26 01:29:12 cheshire
48 Ignore multicasts accidentally delivered to our unicast receiving socket
49
50 Revision 1.70 2005/02/04 00:39:59 cheshire
51 Move ParseDNSServers() from PosixDaemon.c to mDNSPosix.c so all Posix client layers can use it
52
53 Revision 1.69 2004/12/18 02:03:28 cheshire
54 Need to #include "dns_sd.h"
55
56 Revision 1.68 2004/12/18 00:51:52 cheshire
57 Use symbolic constant kDNSServiceInterfaceIndexLocalOnly instead of (mDNSu32) ~0
58
59 Revision 1.67 2004/12/17 23:37:48 cheshire
60 <rdar://problem/3485365> Guard against repeating wireless dissociation/re-association
61 (and other repetitive configuration changes)
62
63 Revision 1.66 2004/12/01 04:27:28 cheshire
64 <rdar://problem/3872803> Darwin patches for Solaris and Suse
65 Don't use uint32_t, etc. -- they require stdint.h, which doesn't exist on FreeBSD 4.x, Solaris, etc.
66
67 Revision 1.65 2004/11/30 22:37:01 cheshire
68 Update copyright dates and add "Mode: C; tab-width: 4" headers
69
70 Revision 1.64 2004/11/23 03:39:47 cheshire
71 Let interface name/index mapping capability live directly in JNISupport.c,
72 instead of having to call through to the daemon via IPC to get this information.
73
74 Revision 1.63 2004/11/12 03:16:43 rpantos
75 rdar://problem/3809541 Add mDNSPlatformGetInterfaceByName, mDNSPlatformGetInterfaceName
76
77 Revision 1.62 2004/10/28 03:24:42 cheshire
78 Rename m->CanReceiveUnicastOn as m->CanReceiveUnicastOn5353
79
80 Revision 1.61 2004/10/16 00:17:01 cheshire
81 <rdar://problem/3770558> Replace IP TTL 255 check with local subnet source address check
82
83 Revision 1.60 2004/09/26 23:20:36 ksekar
84 <rdar://problem/3813108> Allow default registrations in multiple wide-area domains
85
86 Revision 1.59 2004/09/21 21:02:55 cheshire
87 Set up ifname before calling mDNS_RegisterInterface()
88
89 Revision 1.58 2004/09/17 01:08:54 cheshire
90 Renamed mDNSClientAPI.h to mDNSEmbeddedAPI.h
91 The name "mDNSClientAPI.h" is misleading to new developers looking at this code. The interfaces
92 declared in that file are ONLY appropriate to single-address-space embedded applications.
93 For clients on general-purpose computers, the interfaces defined in dns_sd.h should be used.
94
95 Revision 1.57 2004/09/17 00:19:11 cheshire
96 For consistency with AllDNSLinkGroupv6, rename AllDNSLinkGroup to AllDNSLinkGroupv4
97
98 Revision 1.56 2004/09/17 00:15:56 cheshire
99 Rename mDNSPlatformInit_ReceiveUnicast to mDNSPlatformInit_CanReceiveUnicast
100
101 Revision 1.55 2004/09/16 00:24:49 cheshire
102 <rdar://problem/3803162> Fix unsafe use of mDNSPlatformTimeNow()
103
104 Revision 1.54 2004/09/15 23:55:00 ksekar
105 <rdar://problem/3800597> mDNSPosix should #include stdint.h
106
107 Revision 1.53 2004/09/14 23:42:36 cheshire
108 <rdar://problem/3801296> Need to seed random number generator from platform-layer data
109
110 Revision 1.52 2004/08/25 16:42:13 ksekar
111 Fix Posix build - change mDNS_SetFQDNs to mDNS_SetFQDN, remove unicast
112 hostname parameter.
113
114 Revision 1.51 2004/08/14 03:22:42 cheshire
115 <rdar://problem/3762579> Dynamic DNS UI <-> mDNSResponder glue
116 Add GetUserSpecifiedDDNSName() routine
117 Convert ServiceRegDomain to domainname instead of C string
118 Replace mDNS_GenerateFQDN/mDNS_GenerateGlobalFQDN with mDNS_SetFQDNs
119
120 Revision 1.50 2004/08/11 01:20:20 cheshire
121 Declare private local functions using "mDNSlocal"
122
123 Revision 1.49 2004/07/26 22:49:31 ksekar
124 <rdar://problem/3651409>: Feature #9516: Need support for NAT-PMP in client
125
126 Revision 1.48 2004/07/20 01:47:36 rpantos
127 NOT_HAVE_SA_LEN applies to v6, too. And use more-portable s6_addr.
128
129 Revision 1.47 2004/06/25 00:26:27 rpantos
130 Changes to fix the Posix build on Solaris.
131
132 Revision 1.46 2004/05/13 04:54:20 ksekar
133 Unified list copy/free code. Added symetric list for
134
135 Revision 1.45 2004/05/12 22:03:09 ksekar
136 Made GetSearchDomainList a true platform-layer call (declaration moved
137 from mDNSMacOSX.h to mDNSEmbeddedAPI.h), impelemted to return "local"
138 only on non-OSX platforms. Changed call to return a copy of the list
139 to avoid shared memory issues. Added a routine to free the list.
140
141 Revision 1.44 2004/04/21 02:49:11 cheshire
142 To reduce future confusion, renamed 'TxAndRx' to 'McastTxRx'
143
144 Revision 1.43 2004/04/14 23:09:29 ksekar
145 Support for TSIG signed dynamic updates.
146
147 Revision 1.42 2004/04/09 17:43:04 cheshire
148 Make sure to set the McastTxRx field so that duplicate suppression works correctly
149
150 Revision 1.41 2004/02/06 01:19:51 cheshire
151 Conditionally exclude IPv6 code unless HAVE_IPV6 is set
152
153 Revision 1.40 2004/02/05 01:00:01 rpantos
154 Fix some issues that turned up when building for FreeBSD.
155
156 Revision 1.39 2004/01/28 21:12:15 cheshire
157 Reconcile mDNSIPv6Support & HAVE_IPV6 into a single flag (HAVE_IPV6)
158
159 Revision 1.38 2004/01/27 20:15:23 cheshire
160 <rdar://problem/3541288>: Time to prune obsolete code for listening on port 53
161
162 Revision 1.37 2004/01/24 05:12:03 cheshire
163 <rdar://problem/3534352>: Need separate socket for issuing unicast queries
164
165 Revision 1.36 2004/01/24 04:59:16 cheshire
166 Fixes so that Posix/Linux, OS9, Windows, and VxWorks targets build again
167
168 Revision 1.35 2004/01/23 21:37:08 cheshire
169 For consistency, rename multicastSocket to multicastSocket4, and multicastSocketv6 to multicastSocket6
170
171 Revision 1.34 2004/01/22 03:43:09 cheshire
172 Export constants like mDNSInterface_LocalOnly so that the client layers can use them
173
174 Revision 1.33 2004/01/21 21:54:20 cheshire
175 <rdar://problem/3448144>: Don't try to receive unicast responses if we're not the first to bind to the UDP port
176
177 Revision 1.32 2004/01/20 01:49:28 rpantos
178 Tweak error handling of last checkin a bit.
179
180 Revision 1.31 2004/01/20 01:39:27 rpantos
181 Respond to If changes by rebuilding interface list.
182
183 Revision 1.30 2003/12/11 19:40:36 cheshire
184 Fix 'destAddr.type == senderAddr.type;' that should have said 'destAddr.type = senderAddr.type;'
185
186 Revision 1.29 2003/12/11 18:53:22 cheshire
187 Fix compiler warning reported by Paul Guyot
188
189 Revision 1.28 2003/12/11 03:03:51 rpantos
190 Clean up mDNSPosix so that it builds on OS X again.
191
192 Revision 1.27 2003/12/08 20:47:02 rpantos
193 Add support for mDNSResponder on Linux.
194
195 Revision 1.26 2003/11/14 20:59:09 cheshire
196 Clients can't use AssignDomainName macro because mDNSPlatformMemCopy is defined in mDNSPlatformFunctions.h.
197 Best solution is just to combine mDNSEmbeddedAPI.h and mDNSPlatformFunctions.h into a single file.
198
199 Revision 1.25 2003/10/30 19:25:49 cheshire
200 Fix signed/unsigned warning on certain compilers
201
202 Revision 1.24 2003/08/18 23:12:23 cheshire
203 <rdar://problem/3382647> mDNSResponder divide by zero in mDNSPlatformRawTime()
204
205 Revision 1.23 2003/08/12 19:56:26 cheshire
206 Update to APSL 2.0
207
208 Revision 1.22 2003/08/06 18:46:15 cheshire
209 LogMsg() errors are serious -- always report them to stderr, regardless of debugging level
210
211 Revision 1.21 2003/08/06 18:20:51 cheshire
212 Makefile cleanup
213
214 Revision 1.20 2003/08/05 23:56:26 cheshire
215 Update code to compile with the new mDNSCoreReceive() function that requires a TTL
216 (Right now mDNSPosix.c just reports 255 -- we should fix this)
217
218 Revision 1.19 2003/07/19 03:15:16 cheshire
219 Add generic MemAllocate/MemFree prototypes to mDNSPlatformFunctions.h,
220 and add the obvious trivial implementations to each platform support layer
221
222 Revision 1.18 2003/07/14 18:11:54 cheshire
223 Fix stricter compiler warnings
224
225 Revision 1.17 2003/07/13 01:08:38 cheshire
226 There's not much point running mDNS over a point-to-point link; exclude those
227
228 Revision 1.16 2003/07/02 21:19:59 cheshire
229 <rdar://problem/3313413> Update copyright notices, etc., in source code comments
230
231 Revision 1.15 2003/06/18 05:48:41 cheshire
232 Fix warnings
233
234 Revision 1.14 2003/05/26 03:21:30 cheshire
235 Tidy up address structure naming:
236 mDNSIPAddr => mDNSv4Addr (for consistency with mDNSv6Addr)
237 mDNSAddr.addr.ipv4 => mDNSAddr.ip.v4
238 mDNSAddr.addr.ipv6 => mDNSAddr.ip.v6
239
240 Revision 1.13 2003/05/26 03:01:28 cheshire
241 <rdar://problem/3268904> sprintf/vsprintf-style functions are unsafe; use snprintf/vsnprintf instead
242
243 Revision 1.12 2003/05/21 03:49:18 cheshire
244 Fix warning
245
246 Revision 1.11 2003/05/06 00:00:50 cheshire
247 <rdar://problem/3248914> Rationalize naming of domainname manipulation functions
248
249 Revision 1.10 2003/04/25 01:45:57 cheshire
250 <rdar://problem/3240002> mDNS_RegisterNoSuchService needs to include a host name
251
252 Revision 1.9 2003/03/20 21:10:31 cheshire
253 Fixes done at IETF 56 to make mDNSProxyResponderPosix run on Solaris
254
255 Revision 1.8 2003/03/15 04:40:38 cheshire
256 Change type called "mDNSOpaqueID" to the more descriptive name "mDNSInterfaceID"
257
258 Revision 1.7 2003/03/13 03:46:21 cheshire
259 Fixes to make the code build on Linux
260
261 Revision 1.6 2003/03/08 00:35:56 cheshire
262 Switched to using new "mDNS_Execute" model (see "mDNSCore/Implementer Notes.txt")
263
264 Revision 1.5 2002/12/23 22:13:31 jgraessl
265 Reviewed by: Stuart Cheshire
266 Initial IPv6 support for mDNSResponder.
267
268 Revision 1.4 2002/09/27 01:47:45 cheshire
269 Workaround for Linux 2.0 systems that don't have IP_PKTINFO
270
271 Revision 1.3 2002/09/21 20:44:53 zarzycki
272 Added APSL info
273
274 Revision 1.2 2002/09/19 21:25:36 cheshire
275 mDNS_snprintf() doesn't need to be in a separate file
276
277 Revision 1.1 2002/09/17 06:24:34 cheshire
278 First checkin
279 */
280
281 #include "mDNSEmbeddedAPI.h" // Defines the interface provided to the client layer above
282 #include "mDNSPosix.h" // Defines the specific types needed to run mDNS on this platform
283 #include "dns_sd.h"
284
285 #include <assert.h>
286 #include <stdio.h>
287 #include <stdlib.h>
288 #include <errno.h>
289 #include <string.h>
290 #include <unistd.h>
291 #include <syslog.h>
292 #include <stdarg.h>
293 #include <fcntl.h>
294 #include <sys/types.h>
295 #include <sys/time.h>
296 #include <sys/socket.h>
297 #include <sys/uio.h>
298 #include <sys/select.h>
299 #include <netinet/in.h>
300 #include <arpa/inet.h>
301 #include <time.h> // platform support for UTC time
302
303 #if USES_NETLINK
304 #include <asm/types.h>
305 #include <linux/netlink.h>
306 #include <linux/rtnetlink.h>
307 #else // USES_NETLINK
308 #include <net/route.h>
309 #include <net/if.h>
310 #endif // USES_NETLINK
311
312 #include "mDNSUNP.h"
313 #include "GenLinkedList.h"
314
315 // ***************************************************************************
316 // Structures
317
318 // We keep a list of client-supplied event sources in PosixEventSource records
319 struct PosixEventSource
320 {
321 mDNSPosixEventCallback Callback;
322 void *Context;
323 int fd;
324 struct PosixEventSource *Next;
325 };
326 typedef struct PosixEventSource PosixEventSource;
327
328 // Context record for interface change callback
329 struct IfChangeRec
330 {
331 int NotifySD;
332 mDNS* mDNS;
333 };
334 typedef struct IfChangeRec IfChangeRec;
335
336 // Note that static data is initialized to zero in (modern) C.
337 static fd_set gEventFDs;
338 static int gMaxFD; // largest fd in gEventFDs
339 static GenLinkedList gEventSources; // linked list of PosixEventSource's
340 static sigset_t gEventSignalSet; // Signals which event loop listens for
341 static sigset_t gEventSignals; // Signals which were received while inside loop
342
343 // ***************************************************************************
344 // Globals (for debugging)
345
346 static int num_registered_interfaces = 0;
347 static int num_pkts_accepted = 0;
348 static int num_pkts_rejected = 0;
349
350 // ***************************************************************************
351 // Functions
352
353 int gMDNSPlatformPosixVerboseLevel = 0;
354
355 #define PosixErrorToStatus(errNum) ((errNum) == 0 ? mStatus_NoError : mStatus_UnknownErr)
356
357 mDNSlocal void SockAddrTomDNSAddr(const struct sockaddr *const sa, mDNSAddr *ipAddr, mDNSIPPort *ipPort)
358 {
359 switch (sa->sa_family)
360 {
361 case AF_INET:
362 {
363 struct sockaddr_in* sin = (struct sockaddr_in*)sa;
364 ipAddr->type = mDNSAddrType_IPv4;
365 ipAddr->ip.v4.NotAnInteger = sin->sin_addr.s_addr;
366 if (ipPort) ipPort->NotAnInteger = sin->sin_port;
367 break;
368 }
369
370 #if HAVE_IPV6
371 case AF_INET6:
372 {
373 struct sockaddr_in6* sin6 = (struct sockaddr_in6*)sa;
374 #ifndef NOT_HAVE_SA_LEN
375 assert(sin6->sin6_len == sizeof(*sin6));
376 #endif
377 ipAddr->type = mDNSAddrType_IPv6;
378 ipAddr->ip.v6 = *(mDNSv6Addr*)&sin6->sin6_addr;
379 if (ipPort) ipPort->NotAnInteger = sin6->sin6_port;
380 break;
381 }
382 #endif
383
384 default:
385 verbosedebugf("SockAddrTomDNSAddr: Uknown address family %d\n", sa->sa_family);
386 ipAddr->type = mDNSAddrType_None;
387 if (ipPort) ipPort->NotAnInteger = 0;
388 break;
389 }
390 }
391
392 #if COMPILER_LIKES_PRAGMA_MARK
393 #pragma mark ***** Send and Receive
394 #endif
395
396 // mDNS core calls this routine when it needs to send a packet.
397 mDNSexport mStatus mDNSPlatformSendUDP(const mDNS *const m, const void *const msg, const mDNSu8 *const end,
398 mDNSInterfaceID InterfaceID, const mDNSAddr *dst, mDNSIPPort dstPort)
399 {
400 int err = 0;
401 struct sockaddr_storage to;
402 PosixNetworkInterface * thisIntf = (PosixNetworkInterface *)(InterfaceID);
403 int sendingsocket = -1;
404
405 assert(m != NULL);
406 assert(msg != NULL);
407 assert(end != NULL);
408 assert( (((char *) end) - ((char *) msg)) > 0 );
409 assert(dstPort.NotAnInteger != 0);
410
411 if (dst->type == mDNSAddrType_IPv4)
412 {
413 struct sockaddr_in *sin = (struct sockaddr_in*)&to;
414 #ifndef NOT_HAVE_SA_LEN
415 sin->sin_len = sizeof(*sin);
416 #endif
417 sin->sin_family = AF_INET;
418 sin->sin_port = dstPort.NotAnInteger;
419 sin->sin_addr.s_addr = dst->ip.v4.NotAnInteger;
420 sendingsocket = thisIntf ? thisIntf->multicastSocket4 : m->p->unicastSocket4;
421 }
422
423 #if HAVE_IPV6
424 else if (dst->type == mDNSAddrType_IPv6)
425 {
426 struct sockaddr_in6 *sin6 = (struct sockaddr_in6*)&to;
427 mDNSPlatformMemZero(sin6, sizeof(*sin6));
428 #ifndef NOT_HAVE_SA_LEN
429 sin6->sin6_len = sizeof(*sin6);
430 #endif
431 sin6->sin6_family = AF_INET6;
432 sin6->sin6_port = dstPort.NotAnInteger;
433 sin6->sin6_addr = *(struct in6_addr*)&dst->ip.v6;
434 sendingsocket = thisIntf ? thisIntf->multicastSocket6 : m->p->unicastSocket6;
435 }
436 #endif
437
438 if (sendingsocket >= 0)
439 err = sendto(sendingsocket, msg, (char*)end - (char*)msg, 0, (struct sockaddr *)&to, GET_SA_LEN(to));
440
441 if (err > 0) err = 0;
442 else if (err < 0)
443 {
444 if (thisIntf)
445 verbosedebugf("mDNSPlatformSendUDP got error %d (%s) sending packet to %#a on interface %#a/%s/%d",
446 errno, strerror(errno), dst, &thisIntf->coreIntf.ip, thisIntf->intfName, thisIntf->index);
447 else
448 verbosedebugf("mDNSPlatformSendUDP got error %d (%s) sending packet to %#a", errno, strerror(errno), dst);
449 }
450
451 return PosixErrorToStatus(err);
452 }
453
454 // This routine is called when the main loop detects that data is available on a socket.
455 mDNSlocal void SocketDataReady(mDNS *const m, PosixNetworkInterface *intf, int skt)
456 {
457 mDNSAddr senderAddr, destAddr;
458 mDNSIPPort senderPort;
459 ssize_t packetLen;
460 DNSMessage packet;
461 struct my_in_pktinfo packetInfo;
462 struct sockaddr_storage from;
463 socklen_t fromLen;
464 int flags;
465 mDNSu8 ttl;
466 mDNSBool reject;
467 const mDNSInterfaceID InterfaceID = intf ? intf->coreIntf.InterfaceID : NULL;
468
469 assert(m != NULL);
470 assert(skt >= 0);
471
472 fromLen = sizeof(from);
473 flags = 0;
474 packetLen = recvfrom_flags(skt, &packet, sizeof(packet), &flags, (struct sockaddr *) &from, &fromLen, &packetInfo, &ttl);
475
476 if (packetLen >= 0)
477 {
478 SockAddrTomDNSAddr((struct sockaddr*)&from, &senderAddr, &senderPort);
479 SockAddrTomDNSAddr((struct sockaddr*)&packetInfo.ipi_addr, &destAddr, NULL);
480
481 // If we have broken IP_RECVDSTADDR functionality (so far
482 // I've only seen this on OpenBSD) then apply a hack to
483 // convince mDNS Core that this isn't a spoof packet.
484 // Basically what we do is check to see whether the
485 // packet arrived as a multicast and, if so, set its
486 // destAddr to the mDNS address.
487 //
488 // I must admit that I could just be doing something
489 // wrong on OpenBSD and hence triggering this problem
490 // but I'm at a loss as to how.
491 //
492 // If this platform doesn't have IP_PKTINFO or IP_RECVDSTADDR, then we have
493 // no way to tell the destination address or interface this packet arrived on,
494 // so all we can do is just assume it's a multicast
495
496 #if HAVE_BROKEN_RECVDSTADDR || (!defined(IP_PKTINFO) && !defined(IP_RECVDSTADDR))
497 if ( (destAddr.NotAnInteger == 0) && (flags & MSG_MCAST) )
498 {
499 destAddr.type = senderAddr.type;
500 if (senderAddr.type == mDNSAddrType_IPv4) destAddr.ip.v4 = AllDNSLinkGroupv4;
501 else if (senderAddr.type == mDNSAddrType_IPv6) destAddr.ip.v6 = AllDNSLinkGroupv6;
502 }
503 #endif
504
505 // We only accept the packet if the interface on which it came
506 // in matches the interface associated with this socket.
507 // We do this match by name or by index, depending on which
508 // information is available. recvfrom_flags sets the name
509 // to "" if the name isn't available, or the index to -1
510 // if the index is available. This accomodates the various
511 // different capabilities of our target platforms.
512
513 reject = mDNSfalse;
514 if (!intf)
515 {
516 // Ignore multicasts accidentally delivered to our unicast receiving socket
517 if (mDNSAddrIsDNSMulticast(&destAddr)) packetLen = -1;
518 }
519 else
520 {
521 if ( packetInfo.ipi_ifname[0] != 0 ) reject = (strcmp(packetInfo.ipi_ifname, intf->intfName) != 0);
522 else if ( packetInfo.ipi_ifindex != -1 ) reject = (packetInfo.ipi_ifindex != intf->index);
523
524 if (reject)
525 {
526 verbosedebugf("SocketDataReady ignored a packet from %#a to %#a on interface %s/%d expecting %#a/%s/%d/%d",
527 &senderAddr, &destAddr, packetInfo.ipi_ifname, packetInfo.ipi_ifindex,
528 &intf->coreIntf.ip, intf->intfName, intf->index, skt);
529 packetLen = -1;
530 num_pkts_rejected++;
531 if (num_pkts_rejected > (num_pkts_accepted + 1) * (num_registered_interfaces + 1) * 2)
532 {
533 fprintf(stderr,
534 "*** WARNING: Received %d packets; Accepted %d packets; Rejected %d packets because of interface mismatch\n",
535 num_pkts_accepted + num_pkts_rejected, num_pkts_accepted, num_pkts_rejected);
536 num_pkts_accepted = 0;
537 num_pkts_rejected = 0;
538 }
539 }
540 else
541 {
542 verbosedebugf("SocketDataReady got a packet from %#a to %#a on interface %#a/%s/%d/%d",
543 &senderAddr, &destAddr, &intf->coreIntf.ip, intf->intfName, intf->index, skt);
544 num_pkts_accepted++;
545 }
546 }
547 }
548
549 if (packetLen >= 0)
550 mDNSCoreReceive(m, &packet, (mDNSu8 *)&packet + packetLen,
551 &senderAddr, senderPort, &destAddr, MulticastDNSPort, InterfaceID);
552 }
553
554 mDNSexport mStatus mDNSPlatformTCPConnect(const mDNSAddr *dst, mDNSOpaque16 dstport, mDNSInterfaceID InterfaceID,
555 TCPConnectionCallback callback, void *context, int *descriptor)
556 {
557 (void)dst; // Unused
558 (void)dstport; // Unused
559 (void)InterfaceID; // Unused
560 (void)callback; // Unused
561 (void)context; // Unused
562 (void)descriptor; // Unused
563 return(mStatus_UnsupportedErr);
564 }
565
566 mDNSexport void mDNSPlatformTCPCloseConnection(int sd)
567 {
568 (void)sd; // Unused
569 }
570
571 mDNSexport int mDNSPlatformReadTCP(int sd, void *buf, int buflen)
572 {
573 (void)sd; // Unused
574 (void)buf; // Unused
575 (void)buflen; // Unused
576 return(0);
577 }
578
579 mDNSexport int mDNSPlatformWriteTCP(int sd, const char *msg, int len)
580 {
581 (void)sd; // Unused
582 (void)msg; // Unused
583 (void)len; // Unused
584 return(0);
585 }
586
587 #if COMPILER_LIKES_PRAGMA_MARK
588 #pragma mark ***** Get/Free Search Domain List
589 #endif
590
591 mDNSexport DNameListElem *mDNSPlatformGetSearchDomainList(void)
592 {
593 static DNameListElem tmp;
594 static mDNSBool init = mDNSfalse;
595
596 if (!init)
597 {
598 MakeDomainNameFromDNSNameString(&tmp.name, "local.");
599 tmp.next = NULL;
600 init = mDNStrue;
601 }
602 return mDNS_CopyDNameList(&tmp);
603 }
604
605 mDNSexport DNameListElem *mDNSPlatformGetRegDomainList(void)
606 {
607 return NULL;
608 }
609
610 #if COMPILER_LIKES_PRAGMA_MARK
611 #pragma mark ***** Init and Term
612 #endif
613
614 // This gets the current hostname, truncating it at the first dot if necessary
615 mDNSlocal void GetUserSpecifiedRFC1034ComputerName(domainlabel *const namelabel)
616 {
617 int len = 0;
618 gethostname((char *)(&namelabel->c[1]), MAX_DOMAIN_LABEL);
619 while (len < MAX_DOMAIN_LABEL && namelabel->c[len+1] && namelabel->c[len+1] != '.') len++;
620 namelabel->c[0] = len;
621 }
622
623 // On OS X this gets the text of the field labelled "Computer Name" in the Sharing Prefs Control Panel
624 // Other platforms can either get the information from the appropriate place,
625 // or they can alternatively just require all registering services to provide an explicit name
626 mDNSlocal void GetUserSpecifiedFriendlyComputerName(domainlabel *const namelabel)
627 {
628 // On Unix we have no better name than the host name, so we just use that.
629 GetUserSpecifiedRFC1034ComputerName( namelabel);
630 }
631
632 mDNSexport int ParseDNSServers(mDNS *m, const char *filePath)
633 {
634 char line[256];
635 char nameserver[16];
636 char keyword[10];
637 int numOfServers = 0;
638 FILE *fp = fopen(filePath, "r");
639 if (fp == NULL) return -1;
640 while (fgets(line,sizeof(line),fp))
641 {
642 struct in_addr ina;
643 line[255]='\0'; // just to be safe
644 if (sscanf(line,"%10s %15s", keyword, nameserver) != 2) continue; // it will skip whitespaces
645 if (strncmp(keyword,"nameserver",10)) continue;
646 if (inet_aton(nameserver, (struct in_addr *)&ina) != 0)
647 {
648 mDNSAddr DNSAddr;
649 DNSAddr.type = mDNSAddrType_IPv4;
650 DNSAddr.ip.v4.NotAnInteger = ina.s_addr;
651 mDNS_AddDNSServer(m, &DNSAddr, NULL);
652 numOfServers++;
653 }
654 }
655 return (numOfServers > 0) ? 0 : -1;
656 }
657
658 // Searches the interface list looking for the named interface.
659 // Returns a pointer to if it found, or NULL otherwise.
660 mDNSlocal PosixNetworkInterface *SearchForInterfaceByName(mDNS *const m, const char *intfName)
661 {
662 PosixNetworkInterface *intf;
663
664 assert(m != NULL);
665 assert(intfName != NULL);
666
667 intf = (PosixNetworkInterface*)(m->HostInterfaces);
668 while ( (intf != NULL) && (strcmp(intf->intfName, intfName) != 0) )
669 intf = (PosixNetworkInterface *)(intf->coreIntf.next);
670
671 return intf;
672 }
673
674 mDNSexport mDNSInterfaceID mDNSPlatformInterfaceIDfromInterfaceIndex(const mDNS *const m, mDNSu32 index)
675 {
676 PosixNetworkInterface *intf;
677
678 assert(m != NULL);
679
680 if (index == kDNSServiceInterfaceIndexLocalOnly) return(mDNSInterface_LocalOnly);
681
682 intf = (PosixNetworkInterface*)(m->HostInterfaces);
683 while ( (intf != NULL) && (mDNSu32) intf->index != index)
684 intf = (PosixNetworkInterface *)(intf->coreIntf.next);
685
686 return (mDNSInterfaceID) intf;
687 }
688
689 mDNSexport mDNSu32 mDNSPlatformInterfaceIndexfromInterfaceID(const mDNS *const m, mDNSInterfaceID id)
690 {
691 PosixNetworkInterface *intf;
692
693 assert(m != NULL);
694
695 if (id == mDNSInterface_LocalOnly) return(kDNSServiceInterfaceIndexLocalOnly);
696
697 intf = (PosixNetworkInterface*)(m->HostInterfaces);
698 while ( (intf != NULL) && (mDNSInterfaceID) intf != id)
699 intf = (PosixNetworkInterface *)(intf->coreIntf.next);
700
701 return intf ? intf->index : 0;
702 }
703
704 // Frees the specified PosixNetworkInterface structure. The underlying
705 // interface must have already been deregistered with the mDNS core.
706 mDNSlocal void FreePosixNetworkInterface(PosixNetworkInterface *intf)
707 {
708 assert(intf != NULL);
709 if (intf->intfName != NULL) free((void *)intf->intfName);
710 if (intf->multicastSocket4 != -1) assert(close(intf->multicastSocket4) == 0);
711 #if HAVE_IPV6
712 if (intf->multicastSocket6 != -1) assert(close(intf->multicastSocket6) == 0);
713 #endif
714 free(intf);
715 }
716
717 // Grab the first interface, deregister it, free it, and repeat until done.
718 mDNSlocal void ClearInterfaceList(mDNS *const m)
719 {
720 assert(m != NULL);
721
722 while (m->HostInterfaces)
723 {
724 PosixNetworkInterface *intf = (PosixNetworkInterface*)(m->HostInterfaces);
725 mDNS_DeregisterInterface(m, &intf->coreIntf);
726 if (gMDNSPlatformPosixVerboseLevel > 0) fprintf(stderr, "Deregistered interface %s\n", intf->intfName);
727 FreePosixNetworkInterface(intf);
728 }
729 num_registered_interfaces = 0;
730 num_pkts_accepted = 0;
731 num_pkts_rejected = 0;
732 }
733
734 // Sets up a send/receive socket.
735 // If mDNSIPPort port is non-zero, then it's a multicast socket on the specified interface
736 // If mDNSIPPort port is zero, then it's a randomly assigned port number, used for sending unicast queries
737 mDNSlocal int SetupSocket(struct sockaddr *intfAddr, mDNSIPPort port, int interfaceIndex, int *sktPtr)
738 {
739 int err = 0;
740 static const int kOn = 1;
741 static const int kIntTwoFiveFive = 255;
742 static const unsigned char kByteTwoFiveFive = 255;
743 const mDNSBool JoinMulticastGroup = (port.NotAnInteger != 0);
744
745 (void) interfaceIndex; // This parameter unused on plaforms that don't have IPv6
746 assert(intfAddr != NULL);
747 assert(sktPtr != NULL);
748 assert(*sktPtr == -1);
749
750 // Open the socket...
751 if (intfAddr->sa_family == AF_INET ) *sktPtr = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
752 #if HAVE_IPV6
753 else if (intfAddr->sa_family == AF_INET6) *sktPtr = socket(PF_INET6, SOCK_DGRAM, IPPROTO_UDP);
754 #endif
755 else return EINVAL;
756
757 if (*sktPtr < 0) { err = errno; perror("socket"); }
758
759 // ... with a shared UDP port, if it's for multicast receiving
760 if (err == 0 && port.NotAnInteger)
761 {
762 #if defined(SO_REUSEPORT)
763 err = setsockopt(*sktPtr, SOL_SOCKET, SO_REUSEPORT, &kOn, sizeof(kOn));
764 #elif defined(SO_REUSEADDR)
765 err = setsockopt(*sktPtr, SOL_SOCKET, SO_REUSEADDR, &kOn, sizeof(kOn));
766 #else
767 #error This platform has no way to avoid address busy errors on multicast.
768 #endif
769 if (err < 0) { err = errno; perror("setsockopt - SO_REUSExxxx"); }
770 }
771
772 // We want to receive destination addresses and interface identifiers.
773 if (intfAddr->sa_family == AF_INET)
774 {
775 struct ip_mreq imr;
776 struct sockaddr_in bindAddr;
777 if (err == 0)
778 {
779 #if defined(IP_PKTINFO) // Linux
780 err = setsockopt(*sktPtr, IPPROTO_IP, IP_PKTINFO, &kOn, sizeof(kOn));
781 if (err < 0) { err = errno; perror("setsockopt - IP_PKTINFO"); }
782 #elif defined(IP_RECVDSTADDR) || defined(IP_RECVIF) // BSD and Solaris
783 #if defined(IP_RECVDSTADDR)
784 err = setsockopt(*sktPtr, IPPROTO_IP, IP_RECVDSTADDR, &kOn, sizeof(kOn));
785 if (err < 0) { err = errno; perror("setsockopt - IP_RECVDSTADDR"); }
786 #endif
787 #if defined(IP_RECVIF)
788 if (err == 0)
789 {
790 err = setsockopt(*sktPtr, IPPROTO_IP, IP_RECVIF, &kOn, sizeof(kOn));
791 if (err < 0) { err = errno; perror("setsockopt - IP_RECVIF"); }
792 }
793 #endif
794 #else
795 #warning This platform has no way to get the destination interface information -- will only work for single-homed hosts
796 #endif
797 }
798 #if defined(IP_RECVTTL) // Linux
799 if (err == 0)
800 {
801 setsockopt(*sktPtr, IPPROTO_IP, IP_RECVTTL, &kOn, sizeof(kOn));
802 // We no longer depend on being able to get the received TTL, so don't worry if the option fails
803 }
804 #endif
805
806 // Add multicast group membership on this interface
807 if (err == 0 && JoinMulticastGroup)
808 {
809 imr.imr_multiaddr.s_addr = AllDNSLinkGroupv4.NotAnInteger;
810 imr.imr_interface = ((struct sockaddr_in*)intfAddr)->sin_addr;
811 err = setsockopt(*sktPtr, IPPROTO_IP, IP_ADD_MEMBERSHIP, &imr, sizeof(imr));
812 if (err < 0) { err = errno; perror("setsockopt - IP_ADD_MEMBERSHIP"); }
813 }
814
815 // Specify outgoing interface too
816 if (err == 0 && JoinMulticastGroup)
817 {
818 err = setsockopt(*sktPtr, IPPROTO_IP, IP_MULTICAST_IF, &((struct sockaddr_in*)intfAddr)->sin_addr, sizeof(struct in_addr));
819 if (err < 0) { err = errno; perror("setsockopt - IP_MULTICAST_IF"); }
820 }
821
822 // Per the mDNS spec, send unicast packets with TTL 255
823 if (err == 0)
824 {
825 err = setsockopt(*sktPtr, IPPROTO_IP, IP_TTL, &kIntTwoFiveFive, sizeof(kIntTwoFiveFive));
826 if (err < 0) { err = errno; perror("setsockopt - IP_TTL"); }
827 }
828
829 // and multicast packets with TTL 255 too
830 // There's some debate as to whether IP_MULTICAST_TTL is an int or a byte so we just try both.
831 if (err == 0)
832 {
833 err = setsockopt(*sktPtr, IPPROTO_IP, IP_MULTICAST_TTL, &kByteTwoFiveFive, sizeof(kByteTwoFiveFive));
834 if (err < 0 && errno == EINVAL)
835 err = setsockopt(*sktPtr, IPPROTO_IP, IP_MULTICAST_TTL, &kIntTwoFiveFive, sizeof(kIntTwoFiveFive));
836 if (err < 0) { err = errno; perror("setsockopt - IP_MULTICAST_TTL"); }
837 }
838
839 // And start listening for packets
840 if (err == 0)
841 {
842 bindAddr.sin_family = AF_INET;
843 bindAddr.sin_port = port.NotAnInteger;
844 bindAddr.sin_addr.s_addr = INADDR_ANY; // Want to receive multicasts AND unicasts on this socket
845 err = bind(*sktPtr, (struct sockaddr *) &bindAddr, sizeof(bindAddr));
846 if (err < 0) { err = errno; perror("bind"); fflush(stderr); }
847 }
848 } // endif (intfAddr->sa_family == AF_INET)
849
850 #if HAVE_IPV6
851 else if (intfAddr->sa_family == AF_INET6)
852 {
853 struct ipv6_mreq imr6;
854 struct sockaddr_in6 bindAddr6;
855 #if defined(IPV6_PKTINFO)
856 if (err == 0)
857 {
858 err = setsockopt(*sktPtr, IPPROTO_IPV6, IPV6_PKTINFO, &kOn, sizeof(kOn));
859 if (err < 0) { err = errno; perror("setsockopt - IPV6_PKTINFO"); }
860 }
861 #else
862 #warning This platform has no way to get the destination interface information for IPv6 -- will only work for single-homed hosts
863 #endif
864 #if defined(IPV6_HOPLIMIT)
865 if (err == 0)
866 {
867 err = setsockopt(*sktPtr, IPPROTO_IPV6, IPV6_HOPLIMIT, &kOn, sizeof(kOn));
868 if (err < 0) { err = errno; perror("setsockopt - IPV6_HOPLIMIT"); }
869 }
870 #endif
871
872 // Add multicast group membership on this interface
873 if (err == 0 && JoinMulticastGroup)
874 {
875 imr6.ipv6mr_multiaddr = *(const struct in6_addr*)&AllDNSLinkGroupv6;
876 imr6.ipv6mr_interface = interfaceIndex;
877 err = setsockopt(*sktPtr, IPPROTO_IPV6, IPV6_JOIN_GROUP, &imr6, sizeof(imr6));
878 if (err < 0)
879 {
880 err = errno;
881 verbosedebugf("IPV6_JOIN_GROUP %.16a on %d failed.\n", &imr6.ipv6mr_multiaddr, imr6.ipv6mr_interface);
882 perror("setsockopt - IPV6_JOIN_GROUP");
883 }
884 }
885
886 // Specify outgoing interface too
887 if (err == 0 && JoinMulticastGroup)
888 {
889 u_int multicast_if = interfaceIndex;
890 err = setsockopt(*sktPtr, IPPROTO_IPV6, IPV6_MULTICAST_IF, &multicast_if, sizeof(multicast_if));
891 if (err < 0) { err = errno; perror("setsockopt - IPV6_MULTICAST_IF"); }
892 }
893
894 // We want to receive only IPv6 packets on this socket.
895 // Without this option, we may get IPv4 addresses as mapped addresses.
896 if (err == 0)
897 {
898 err = setsockopt(*sktPtr, IPPROTO_IPV6, IPV6_V6ONLY, &kOn, sizeof(kOn));
899 if (err < 0) { err = errno; perror("setsockopt - IPV6_V6ONLY"); }
900 }
901
902 // Per the mDNS spec, send unicast packets with TTL 255
903 if (err == 0)
904 {
905 err = setsockopt(*sktPtr, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &kIntTwoFiveFive, sizeof(kIntTwoFiveFive));
906 if (err < 0) { err = errno; perror("setsockopt - IPV6_UNICAST_HOPS"); }
907 }
908
909 // and multicast packets with TTL 255 too
910 // There's some debate as to whether IPV6_MULTICAST_HOPS is an int or a byte so we just try both.
911 if (err == 0)
912 {
913 err = setsockopt(*sktPtr, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &kByteTwoFiveFive, sizeof(kByteTwoFiveFive));
914 if (err < 0 && errno == EINVAL)
915 err = setsockopt(*sktPtr, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &kIntTwoFiveFive, sizeof(kIntTwoFiveFive));
916 if (err < 0) { err = errno; perror("setsockopt - IPV6_MULTICAST_HOPS"); }
917 }
918
919 // And start listening for packets
920 if (err == 0)
921 {
922 mDNSPlatformMemZero(&bindAddr6, sizeof(bindAddr6));
923 #ifndef NOT_HAVE_SA_LEN
924 bindAddr6.sin6_len = sizeof(bindAddr6);
925 #endif
926 bindAddr6.sin6_family = AF_INET6;
927 bindAddr6.sin6_port = port.NotAnInteger;
928 bindAddr6.sin6_flowinfo = 0;
929 // bindAddr6.sin6_addr.s_addr = IN6ADDR_ANY_INIT; // Want to receive multicasts AND unicasts on this socket
930 bindAddr6.sin6_scope_id = 0;
931 err = bind(*sktPtr, (struct sockaddr *) &bindAddr6, sizeof(bindAddr6));
932 if (err < 0) { err = errno; perror("bind"); fflush(stderr); }
933 }
934 } // endif (intfAddr->sa_family == AF_INET6)
935 #endif
936
937 // Set the socket to non-blocking.
938 if (err == 0)
939 {
940 err = fcntl(*sktPtr, F_GETFL, 0);
941 if (err < 0) err = errno;
942 else
943 {
944 err = fcntl(*sktPtr, F_SETFL, err | O_NONBLOCK);
945 if (err < 0) err = errno;
946 }
947 }
948
949 // Clean up
950 if (err != 0 && *sktPtr != -1) { assert(close(*sktPtr) == 0); *sktPtr = -1; }
951 assert( (err == 0) == (*sktPtr != -1) );
952 return err;
953 }
954
955 // Creates a PosixNetworkInterface for the interface whose IP address is
956 // intfAddr and whose name is intfName and registers it with mDNS core.
957 mDNSlocal int SetupOneInterface(mDNS *const m, struct sockaddr *intfAddr, struct sockaddr *intfMask, const char *intfName, int intfIndex)
958 {
959 int err = 0;
960 PosixNetworkInterface *intf;
961 PosixNetworkInterface *alias = NULL;
962
963 assert(m != NULL);
964 assert(intfAddr != NULL);
965 assert(intfName != NULL);
966 assert(intfMask != NULL);
967
968 // Allocate the interface structure itself.
969 intf = (PosixNetworkInterface*)malloc(sizeof(*intf));
970 if (intf == NULL) { assert(0); err = ENOMEM; }
971
972 // And make a copy of the intfName.
973 if (err == 0)
974 {
975 intf->intfName = strdup(intfName);
976 if (intf->intfName == NULL) { assert(0); err = ENOMEM; }
977 }
978
979 if (err == 0)
980 {
981 // Set up the fields required by the mDNS core.
982 SockAddrTomDNSAddr(intfAddr, &intf->coreIntf.ip, NULL);
983 SockAddrTomDNSAddr(intfMask, &intf->coreIntf.mask, NULL);
984 //LogMsg("SetupOneInterface: %#a %#a", &intf->coreIntf.ip, &intf->coreIntf.mask);
985 strncpy(intf->coreIntf.ifname, intfName, sizeof(intf->coreIntf.ifname));
986 intf->coreIntf.ifname[sizeof(intf->coreIntf.ifname)-1] = 0;
987 intf->coreIntf.Advertise = m->AdvertiseLocalAddresses;
988 intf->coreIntf.McastTxRx = mDNStrue;
989
990 // Set up the extra fields in PosixNetworkInterface.
991 assert(intf->intfName != NULL); // intf->intfName already set up above
992 intf->index = intfIndex;
993 intf->multicastSocket4 = -1;
994 #if HAVE_IPV6
995 intf->multicastSocket6 = -1;
996 #endif
997 alias = SearchForInterfaceByName(m, intf->intfName);
998 if (alias == NULL) alias = intf;
999 intf->coreIntf.InterfaceID = (mDNSInterfaceID)alias;
1000
1001 if (alias != intf)
1002 debugf("SetupOneInterface: %s %#a is an alias of %#a", intfName, &intf->coreIntf.ip, &alias->coreIntf.ip);
1003 }
1004
1005 // Set up the multicast socket
1006 if (err == 0)
1007 {
1008 if (alias->multicastSocket4 == -1 && intfAddr->sa_family == AF_INET)
1009 err = SetupSocket(intfAddr, MulticastDNSPort, intf->index, &alias->multicastSocket4);
1010 #if HAVE_IPV6
1011 else if (alias->multicastSocket6 == -1 && intfAddr->sa_family == AF_INET6)
1012 err = SetupSocket(intfAddr, MulticastDNSPort, intf->index, &alias->multicastSocket6);
1013 #endif
1014 }
1015
1016 // The interface is all ready to go, let's register it with the mDNS core.
1017 if (err == 0)
1018 err = mDNS_RegisterInterface(m, &intf->coreIntf, 0);
1019
1020 // Clean up.
1021 if (err == 0)
1022 {
1023 num_registered_interfaces++;
1024 debugf("SetupOneInterface: %s %#a Registered", intf->intfName, &intf->coreIntf.ip);
1025 if (gMDNSPlatformPosixVerboseLevel > 0)
1026 fprintf(stderr, "Registered interface %s\n", intf->intfName);
1027 }
1028 else
1029 {
1030 // Use intfName instead of intf->intfName in the next line to avoid dereferencing NULL.
1031 debugf("SetupOneInterface: %s %#a failed to register %d", intfName, &intf->coreIntf.ip, err);
1032 if (intf) { FreePosixNetworkInterface(intf); intf = NULL; }
1033 }
1034
1035 assert( (err == 0) == (intf != NULL) );
1036
1037 return err;
1038 }
1039
1040 // Call get_ifi_info() to obtain a list of active interfaces and call SetupOneInterface() on each one.
1041 mDNSlocal int SetupInterfaceList(mDNS *const m)
1042 {
1043 mDNSBool foundav4 = mDNSfalse;
1044 int err = 0;
1045 struct ifi_info *intfList = get_ifi_info(AF_INET, mDNStrue);
1046 struct ifi_info *firstLoopback = NULL;
1047
1048 assert(m != NULL);
1049 debugf("SetupInterfaceList");
1050
1051 if (intfList == NULL) err = ENOENT;
1052
1053 #if HAVE_IPV6
1054 if (err == 0) /* Link the IPv6 list to the end of the IPv4 list */
1055 {
1056 struct ifi_info **p = &intfList;
1057 while (*p) p = &(*p)->ifi_next;
1058 *p = get_ifi_info(AF_INET6, mDNStrue);
1059 }
1060 #endif
1061
1062 if (err == 0)
1063 {
1064 struct ifi_info *i = intfList;
1065 while (i)
1066 {
1067 if ( ((i->ifi_addr->sa_family == AF_INET)
1068 #if HAVE_IPV6
1069 || (i->ifi_addr->sa_family == AF_INET6)
1070 #endif
1071 ) && (i->ifi_flags & IFF_UP) && !(i->ifi_flags & IFF_POINTOPOINT) )
1072 {
1073 if (i->ifi_flags & IFF_LOOPBACK)
1074 {
1075 if (firstLoopback == NULL)
1076 firstLoopback = i;
1077 }
1078 else
1079 {
1080 if (SetupOneInterface(m, i->ifi_addr, i->ifi_netmask, i->ifi_name, i->ifi_index) == 0)
1081 if (i->ifi_addr->sa_family == AF_INET)
1082 foundav4 = mDNStrue;
1083 }
1084 }
1085 i = i->ifi_next;
1086 }
1087
1088 // If we found no normal interfaces but we did find a loopback interface, register the
1089 // loopback interface. This allows self-discovery if no interfaces are configured.
1090 // Temporary workaround: Multicast loopback on IPv6 interfaces appears not to work.
1091 // In the interim, we skip loopback interface only if we found at least one v4 interface to use
1092 // if ( (m->HostInterfaces == NULL) && (firstLoopback != NULL) )
1093 if ( !foundav4 && firstLoopback )
1094 (void) SetupOneInterface(m, firstLoopback->ifi_addr, firstLoopback->ifi_netmask, firstLoopback->ifi_name, firstLoopback->ifi_index);
1095 }
1096
1097 // Clean up.
1098 if (intfList != NULL) free_ifi_info(intfList);
1099 return err;
1100 }
1101
1102 #if USES_NETLINK
1103
1104 // See <http://www.faqs.org/rfcs/rfc3549.html> for a description of NetLink
1105
1106 // Open a socket that will receive interface change notifications
1107 mDNSlocal mStatus OpenIfNotifySocket( int *pFD)
1108 {
1109 mStatus err = mStatus_NoError;
1110 struct sockaddr_nl snl;
1111 int sock;
1112 int ret;
1113
1114 sock = socket( AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
1115 if (sock < 0)
1116 return errno;
1117
1118 // Configure read to be non-blocking because inbound msg size is not known in advance
1119 (void) fcntl( sock, F_SETFL, O_NONBLOCK);
1120
1121 /* Subscribe the socket to Link & IP addr notifications. */
1122 bzero( &snl, sizeof snl);
1123 snl.nl_family = AF_NETLINK;
1124 snl.nl_groups = RTMGRP_LINK | RTMGRP_IPV4_IFADDR;
1125 ret = bind( sock, (struct sockaddr *) &snl, sizeof snl);
1126 if ( 0 == ret)
1127 *pFD = sock;
1128 else
1129 err = errno;
1130
1131 return err;
1132 }
1133
1134 #if MDNS_DEBUGMSGS
1135 mDNSlocal void PrintNetLinkMsg( const struct nlmsghdr *pNLMsg)
1136 {
1137 const char *kNLMsgTypes[] = { "", "NLMSG_NOOP", "NLMSG_ERROR", "NLMSG_DONE", "NLMSG_OVERRUN" };
1138 const char *kNLRtMsgTypes[] = { "RTM_NEWLINK", "RTM_DELLINK", "RTM_GETLINK", "RTM_NEWADDR", "RTM_DELADDR", "RTM_GETADDR" };
1139
1140 printf( "nlmsghdr len=%d, type=%s, flags=0x%x\n", pNLMsg->nlmsg_len,
1141 pNLMsg->nlmsg_type < RTM_BASE ? kNLMsgTypes[ pNLMsg->nlmsg_type] : kNLRtMsgTypes[ pNLMsg->nlmsg_type - RTM_BASE],
1142 pNLMsg->nlmsg_flags);
1143
1144 if ( RTM_NEWLINK <= pNLMsg->nlmsg_type && pNLMsg->nlmsg_type <= RTM_GETLINK)
1145 {
1146 struct ifinfomsg *pIfInfo = (struct ifinfomsg*) NLMSG_DATA( pNLMsg);
1147 printf( "ifinfomsg family=%d, type=%d, index=%d, flags=0x%x, change=0x%x\n", pIfInfo->ifi_family,
1148 pIfInfo->ifi_type, pIfInfo->ifi_index, pIfInfo->ifi_flags, pIfInfo->ifi_change);
1149
1150 }
1151 else if ( RTM_NEWADDR <= pNLMsg->nlmsg_type && pNLMsg->nlmsg_type <= RTM_GETADDR)
1152 {
1153 struct ifaddrmsg *pIfAddr = (struct ifaddrmsg*) NLMSG_DATA( pNLMsg);
1154 printf( "ifaddrmsg family=%d, index=%d, flags=0x%x\n", pIfAddr->ifa_family,
1155 pIfAddr->ifa_index, pIfAddr->ifa_flags);
1156 }
1157 printf( "\n");
1158 }
1159 #endif
1160
1161 mDNSlocal mDNSu32 ProcessRoutingNotification( int sd)
1162 // Read through the messages on sd and if any indicate that any interface records should
1163 // be torn down and rebuilt, return affected indices as a bitmask. Otherwise return 0.
1164 {
1165 ssize_t readCount;
1166 char buff[ 4096];
1167 struct nlmsghdr *pNLMsg = (struct nlmsghdr*) buff;
1168 mDNSu32 result = 0;
1169
1170 // The structure here is more complex than it really ought to be because,
1171 // unfortunately, there's no good way to size a buffer in advance large
1172 // enough to hold all pending data and so avoid message fragmentation.
1173 // (Note that FIONREAD is not supported on AF_NETLINK.)
1174
1175 readCount = read( sd, buff, sizeof buff);
1176 while ( 1)
1177 {
1178 // Make sure we've got an entire nlmsghdr in the buffer, and payload, too.
1179 // If not, discard already-processed messages in buffer and read more data.
1180 if ( ( (char*) &pNLMsg[1] > ( buff + readCount)) || // i.e. *pNLMsg extends off end of buffer
1181 ( (char*) pNLMsg + pNLMsg->nlmsg_len > ( buff + readCount)))
1182 {
1183 if ( buff < (char*) pNLMsg) // we have space to shuffle
1184 {
1185 // discard processed data
1186 readCount -= ( (char*) pNLMsg - buff);
1187 memmove( buff, pNLMsg, readCount);
1188 pNLMsg = (struct nlmsghdr*) buff;
1189
1190 // read more data
1191 readCount += read( sd, buff + readCount, sizeof buff - readCount);
1192 continue; // spin around and revalidate with new readCount
1193 }
1194 else
1195 break; // Otherwise message does not fit in buffer
1196 }
1197
1198 #if MDNS_DEBUGMSGS
1199 PrintNetLinkMsg( pNLMsg);
1200 #endif
1201
1202 // Process the NetLink message
1203 if ( pNLMsg->nlmsg_type == RTM_GETLINK || pNLMsg->nlmsg_type == RTM_NEWLINK)
1204 result |= 1 << ((struct ifinfomsg*) NLMSG_DATA( pNLMsg))->ifi_index;
1205 else if ( pNLMsg->nlmsg_type == RTM_DELADDR || pNLMsg->nlmsg_type == RTM_NEWADDR)
1206 result |= 1 << ((struct ifaddrmsg*) NLMSG_DATA( pNLMsg))->ifa_index;
1207
1208 // Advance pNLMsg to the next message in the buffer
1209 if ( ( pNLMsg->nlmsg_flags & NLM_F_MULTI) != 0 && pNLMsg->nlmsg_type != NLMSG_DONE)
1210 {
1211 ssize_t len = readCount - ( (char*)pNLMsg - buff);
1212 pNLMsg = NLMSG_NEXT( pNLMsg, len);
1213 }
1214 else
1215 break; // all done!
1216 }
1217
1218 return result;
1219 }
1220
1221 #else // USES_NETLINK
1222
1223 // Open a socket that will receive interface change notifications
1224 mDNSlocal mStatus OpenIfNotifySocket( int *pFD)
1225 {
1226 *pFD = socket( AF_ROUTE, SOCK_RAW, 0);
1227
1228 if ( *pFD < 0)
1229 return mStatus_UnknownErr;
1230
1231 // Configure read to be non-blocking because inbound msg size is not known in advance
1232 (void) fcntl( *pFD, F_SETFL, O_NONBLOCK);
1233
1234 return mStatus_NoError;
1235 }
1236
1237 #if MDNS_DEBUGMSGS
1238 mDNSlocal void PrintRoutingSocketMsg( const struct ifa_msghdr *pRSMsg)
1239 {
1240 const char *kRSMsgTypes[] = { "", "RTM_ADD", "RTM_DELETE", "RTM_CHANGE", "RTM_GET", "RTM_LOSING",
1241 "RTM_REDIRECT", "RTM_MISS", "RTM_LOCK", "RTM_OLDADD", "RTM_OLDDEL", "RTM_RESOLVE",
1242 "RTM_NEWADDR", "RTM_DELADDR", "RTM_IFINFO", "RTM_NEWMADDR", "RTM_DELMADDR" };
1243
1244 int index = pRSMsg->ifam_type == RTM_IFINFO ? ((struct if_msghdr*) pRSMsg)->ifm_index : pRSMsg->ifam_index;
1245
1246 printf( "ifa_msghdr len=%d, type=%s, index=%d\n", pRSMsg->ifam_msglen, kRSMsgTypes[ pRSMsg->ifam_type], index);
1247 }
1248 #endif
1249
1250 mDNSlocal mDNSu32 ProcessRoutingNotification( int sd)
1251 // Read through the messages on sd and if any indicate that any interface records should
1252 // be torn down and rebuilt, return affected indices as a bitmask. Otherwise return 0.
1253 {
1254 ssize_t readCount;
1255 char buff[ 4096];
1256 struct ifa_msghdr *pRSMsg = (struct ifa_msghdr*) buff;
1257 mDNSu32 result = 0;
1258
1259 readCount = read( sd, buff, sizeof buff);
1260 if ( readCount < (ssize_t) sizeof( struct ifa_msghdr))
1261 return mStatus_UnsupportedErr; // cannot decipher message
1262
1263 #if MDNS_DEBUGMSGS
1264 PrintRoutingSocketMsg( pRSMsg);
1265 #endif
1266
1267 // Process the message
1268 if ( pRSMsg->ifam_type == RTM_NEWADDR || pRSMsg->ifam_type == RTM_DELADDR ||
1269 pRSMsg->ifam_type == RTM_IFINFO)
1270 {
1271 if ( pRSMsg->ifam_type == RTM_IFINFO)
1272 result |= 1 << ((struct if_msghdr*) pRSMsg)->ifm_index;
1273 else
1274 result |= 1 << pRSMsg->ifam_index;
1275 }
1276
1277 return result;
1278 }
1279
1280 #endif // USES_NETLINK
1281
1282 // Called when data appears on interface change notification socket
1283 mDNSlocal void InterfaceChangeCallback( void *context)
1284 {
1285 IfChangeRec *pChgRec = (IfChangeRec*) context;
1286 fd_set readFDs;
1287 mDNSu32 changedInterfaces = 0;
1288 struct timeval zeroTimeout = { 0, 0 };
1289
1290 FD_ZERO( &readFDs);
1291 FD_SET( pChgRec->NotifySD, &readFDs);
1292
1293 do
1294 {
1295 changedInterfaces |= ProcessRoutingNotification( pChgRec->NotifySD);
1296 }
1297 while ( 0 < select( pChgRec->NotifySD + 1, &readFDs, (fd_set*) NULL, (fd_set*) NULL, &zeroTimeout));
1298
1299 // Currently we rebuild the entire interface list whenever any interface change is
1300 // detected. If this ever proves to be a performance issue in a multi-homed
1301 // configuration, more care should be paid to changedInterfaces.
1302 if ( changedInterfaces)
1303 mDNSPlatformPosixRefreshInterfaceList( pChgRec->mDNS);
1304 }
1305
1306 // Register with either a Routing Socket or RtNetLink to listen for interface changes.
1307 mDNSlocal mStatus WatchForInterfaceChange(mDNS *const m)
1308 {
1309 mStatus err;
1310 IfChangeRec *pChgRec;
1311
1312 pChgRec = (IfChangeRec*) mDNSPlatformMemAllocate( sizeof *pChgRec);
1313 if ( pChgRec == NULL)
1314 return mStatus_NoMemoryErr;
1315
1316 pChgRec->mDNS = m;
1317 err = OpenIfNotifySocket( &pChgRec->NotifySD);
1318 if ( err == 0)
1319 err = mDNSPosixAddFDToEventLoop( pChgRec->NotifySD, InterfaceChangeCallback, pChgRec);
1320
1321 return err;
1322 }
1323
1324 // Test to see if we're the first client running on UDP port 5353, by trying to bind to 5353 without using SO_REUSEPORT.
1325 // If we fail, someone else got here first. That's not a big problem; we can share the port for multicast responses --
1326 // we just need to be aware that we shouldn't expect to successfully receive unicast UDP responses.
1327 mDNSlocal mDNSBool mDNSPlatformInit_CanReceiveUnicast(void)
1328 {
1329 int err;
1330 int s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
1331 struct sockaddr_in s5353;
1332 s5353.sin_family = AF_INET;
1333 s5353.sin_port = MulticastDNSPort.NotAnInteger;
1334 s5353.sin_addr.s_addr = 0;
1335 err = bind(s, (struct sockaddr *)&s5353, sizeof(s5353));
1336 close(s);
1337 if (err) debugf("No unicast UDP responses");
1338 else debugf("Unicast UDP responses okay");
1339 return(err == 0);
1340 }
1341
1342 // mDNS core calls this routine to initialise the platform-specific data.
1343 mDNSexport mStatus mDNSPlatformInit(mDNS *const m)
1344 {
1345 int err = 0;
1346 struct sockaddr sa;
1347 assert(m != NULL);
1348
1349 if (mDNSPlatformInit_CanReceiveUnicast()) m->CanReceiveUnicastOn5353 = mDNStrue;
1350
1351 // Tell mDNS core the names of this machine.
1352
1353 // Set up the nice label
1354 m->nicelabel.c[0] = 0;
1355 GetUserSpecifiedFriendlyComputerName(&m->nicelabel);
1356 if (m->nicelabel.c[0] == 0) MakeDomainLabelFromLiteralString(&m->nicelabel, "Computer");
1357
1358 // Set up the RFC 1034-compliant label
1359 m->hostlabel.c[0] = 0;
1360 GetUserSpecifiedRFC1034ComputerName(&m->hostlabel);
1361 if (m->hostlabel.c[0] == 0) MakeDomainLabelFromLiteralString(&m->hostlabel, "Computer");
1362
1363 mDNS_SetFQDN(m);
1364
1365 sa.sa_family = AF_INET;
1366 m->p->unicastSocket4 = -1;
1367 if (err == mStatus_NoError) err = SetupSocket(&sa, zeroIPPort, 0, &m->p->unicastSocket4);
1368 #if HAVE_IPV6
1369 sa.sa_family = AF_INET6;
1370 m->p->unicastSocket6 = -1;
1371 if (err == mStatus_NoError) err = SetupSocket(&sa, zeroIPPort, 0, &m->p->unicastSocket6);
1372 #endif
1373
1374 // Tell mDNS core about the network interfaces on this machine.
1375 if (err == mStatus_NoError) err = SetupInterfaceList(m);
1376
1377 // Tell mDNS core about DNS Servers
1378 if (err == mStatus_NoError) ParseDNSServers(m, uDNS_SERVERS_FILE);
1379
1380 if (err == mStatus_NoError)
1381 {
1382 err = WatchForInterfaceChange(m);
1383 // Failure to observe interface changes is non-fatal.
1384 if ( err != mStatus_NoError)
1385 {
1386 fprintf(stderr, "mDNS(%d) WARNING: Unable to detect interface changes (%d).\n", getpid(), err);
1387 err = mStatus_NoError;
1388 }
1389 }
1390
1391 // We don't do asynchronous initialization on the Posix platform, so by the time
1392 // we get here the setup will already have succeeded or failed. If it succeeded,
1393 // we should just call mDNSCoreInitComplete() immediately.
1394 if (err == mStatus_NoError)
1395 mDNSCoreInitComplete(m, mStatus_NoError);
1396
1397 return PosixErrorToStatus(err);
1398 }
1399
1400 // mDNS core calls this routine to clean up the platform-specific data.
1401 // In our case all we need to do is to tear down every network interface.
1402 mDNSexport void mDNSPlatformClose(mDNS *const m)
1403 {
1404 assert(m != NULL);
1405 ClearInterfaceList(m);
1406 if (m->p->unicastSocket4 != -1) assert(close(m->p->unicastSocket4) == 0);
1407 #if HAVE_IPV6
1408 if (m->p->unicastSocket6 != -1) assert(close(m->p->unicastSocket6) == 0);
1409 #endif
1410 }
1411
1412 mDNSexport mStatus mDNSPlatformPosixRefreshInterfaceList(mDNS *const m)
1413 {
1414 int err;
1415 ClearInterfaceList(m);
1416 err = SetupInterfaceList(m);
1417 return PosixErrorToStatus(err);
1418 }
1419
1420 #if COMPILER_LIKES_PRAGMA_MARK
1421 #pragma mark ***** Locking
1422 #endif
1423
1424 // On the Posix platform, locking is a no-op because we only ever enter
1425 // mDNS core on the main thread.
1426
1427 // mDNS core calls this routine when it wants to prevent
1428 // the platform from reentering mDNS core code.
1429 mDNSexport void mDNSPlatformLock (const mDNS *const m)
1430 {
1431 (void) m; // Unused
1432 }
1433
1434 // mDNS core calls this routine when it release the lock taken by
1435 // mDNSPlatformLock and allow the platform to reenter mDNS core code.
1436 mDNSexport void mDNSPlatformUnlock (const mDNS *const m)
1437 {
1438 (void) m; // Unused
1439 }
1440
1441 #if COMPILER_LIKES_PRAGMA_MARK
1442 #pragma mark ***** Strings
1443 #endif
1444
1445 // mDNS core calls this routine to copy C strings.
1446 // On the Posix platform this maps directly to the ANSI C strcpy.
1447 mDNSexport void mDNSPlatformStrCopy(const void *src, void *dst)
1448 {
1449 strcpy((char *)dst, (char *)src);
1450 }
1451
1452 // mDNS core calls this routine to get the length of a C string.
1453 // On the Posix platform this maps directly to the ANSI C strlen.
1454 mDNSexport mDNSu32 mDNSPlatformStrLen (const void *src)
1455 {
1456 return strlen((char*)src);
1457 }
1458
1459 // mDNS core calls this routine to copy memory.
1460 // On the Posix platform this maps directly to the ANSI C memcpy.
1461 mDNSexport void mDNSPlatformMemCopy(const void *src, void *dst, mDNSu32 len)
1462 {
1463 memcpy(dst, src, len);
1464 }
1465
1466 // mDNS core calls this routine to test whether blocks of memory are byte-for-byte
1467 // identical. On the Posix platform this is a simple wrapper around ANSI C memcmp.
1468 mDNSexport mDNSBool mDNSPlatformMemSame(const void *src, const void *dst, mDNSu32 len)
1469 {
1470 return memcmp(dst, src, len) == 0;
1471 }
1472
1473 // mDNS core calls this routine to clear blocks of memory.
1474 // On the Posix platform this is a simple wrapper around ANSI C memset.
1475 mDNSexport void mDNSPlatformMemZero( void *dst, mDNSu32 len)
1476 {
1477 memset(dst, 0, len);
1478 }
1479
1480 mDNSexport void * mDNSPlatformMemAllocate(mDNSu32 len) { return(malloc(len)); }
1481 mDNSexport void mDNSPlatformMemFree (void *mem) { free(mem); }
1482
1483 mDNSexport mDNSu32 mDNSPlatformRandomSeed(void)
1484 {
1485 struct timeval tv;
1486 gettimeofday(&tv, NULL);
1487 return(tv.tv_usec);
1488 }
1489
1490 mDNSexport mDNSs32 mDNSPlatformOneSecond = 1024;
1491
1492 mDNSexport mStatus mDNSPlatformTimeInit(void)
1493 {
1494 // No special setup is required on Posix -- we just use gettimeofday();
1495 // This is not really safe, because gettimeofday can go backwards if the user manually changes the date or time
1496 // We should find a better way to do this
1497 return(mStatus_NoError);
1498 }
1499
1500 mDNSexport mDNSs32 mDNSPlatformRawTime()
1501 {
1502 struct timeval tv;
1503 gettimeofday(&tv, NULL);
1504 // tv.tv_sec is seconds since 1st January 1970 (GMT, with no adjustment for daylight savings time)
1505 // tv.tv_usec is microseconds since the start of this second (i.e. values 0 to 999999)
1506 // We use the lower 22 bits of tv.tv_sec for the top 22 bits of our result
1507 // and we multiply tv.tv_usec by 16 / 15625 to get a value in the range 0-1023 to go in the bottom 10 bits.
1508 // This gives us a proper modular (cyclic) counter that has a resolution of roughly 1ms (actually 1/1024 second)
1509 // and correctly cycles every 2^22 seconds (4194304 seconds = approx 48 days).
1510 return( (tv.tv_sec << 10) | (tv.tv_usec * 16 / 15625) );
1511 }
1512
1513 mDNSexport mDNSs32 mDNSPlatformUTC(void)
1514 {
1515 return time(NULL);
1516 }
1517
1518 mDNSlocal void mDNSPosixAddToFDSet(int *nfds, fd_set *readfds, int s)
1519 {
1520 if (*nfds < s + 1) *nfds = s + 1;
1521 FD_SET(s, readfds);
1522 }
1523
1524 mDNSexport void mDNSPosixGetFDSet(mDNS *m, int *nfds, fd_set *readfds, struct timeval *timeout)
1525 {
1526 mDNSs32 ticks;
1527 struct timeval interval;
1528
1529 // 1. Call mDNS_Execute() to let mDNSCore do what it needs to do
1530 mDNSs32 nextevent = mDNS_Execute(m);
1531
1532 // 2. Build our list of active file descriptors
1533 PosixNetworkInterface *info = (PosixNetworkInterface *)(m->HostInterfaces);
1534 if (m->p->unicastSocket4 != -1) mDNSPosixAddToFDSet(nfds, readfds, m->p->unicastSocket4);
1535 #if HAVE_IPV6
1536 if (m->p->unicastSocket6 != -1) mDNSPosixAddToFDSet(nfds, readfds, m->p->unicastSocket6);
1537 #endif
1538 while (info)
1539 {
1540 if (info->multicastSocket4 != -1) mDNSPosixAddToFDSet(nfds, readfds, info->multicastSocket4);
1541 #if HAVE_IPV6
1542 if (info->multicastSocket6 != -1) mDNSPosixAddToFDSet(nfds, readfds, info->multicastSocket6);
1543 #endif
1544 info = (PosixNetworkInterface *)(info->coreIntf.next);
1545 }
1546
1547 // 3. Calculate the time remaining to the next scheduled event (in struct timeval format)
1548 ticks = nextevent - mDNS_TimeNow(m);
1549 if (ticks < 1) ticks = 1;
1550 interval.tv_sec = ticks >> 10; // The high 22 bits are seconds
1551 interval.tv_usec = ((ticks & 0x3FF) * 15625) / 16; // The low 10 bits are 1024ths
1552
1553 // 4. If client's proposed timeout is more than what we want, then reduce it
1554 if (timeout->tv_sec > interval.tv_sec ||
1555 (timeout->tv_sec == interval.tv_sec && timeout->tv_usec > interval.tv_usec))
1556 *timeout = interval;
1557 }
1558
1559 mDNSexport void mDNSPosixProcessFDSet(mDNS *const m, fd_set *readfds)
1560 {
1561 PosixNetworkInterface *info;
1562 assert(m != NULL);
1563 assert(readfds != NULL);
1564 info = (PosixNetworkInterface *)(m->HostInterfaces);
1565
1566 if (m->p->unicastSocket4 != -1 && FD_ISSET(m->p->unicastSocket4, readfds))
1567 {
1568 FD_CLR(m->p->unicastSocket4, readfds);
1569 SocketDataReady(m, NULL, m->p->unicastSocket4);
1570 }
1571 #if HAVE_IPV6
1572 if (m->p->unicastSocket6 != -1 && FD_ISSET(m->p->unicastSocket6, readfds))
1573 {
1574 FD_CLR(m->p->unicastSocket6, readfds);
1575 SocketDataReady(m, NULL, m->p->unicastSocket6);
1576 }
1577 #endif
1578
1579 while (info)
1580 {
1581 if (info->multicastSocket4 != -1 && FD_ISSET(info->multicastSocket4, readfds))
1582 {
1583 FD_CLR(info->multicastSocket4, readfds);
1584 SocketDataReady(m, info, info->multicastSocket4);
1585 }
1586 #if HAVE_IPV6
1587 if (info->multicastSocket6 != -1 && FD_ISSET(info->multicastSocket6, readfds))
1588 {
1589 FD_CLR(info->multicastSocket6, readfds);
1590 SocketDataReady(m, info, info->multicastSocket6);
1591 }
1592 #endif
1593 info = (PosixNetworkInterface *)(info->coreIntf.next);
1594 }
1595 }
1596
1597 // update gMaxFD
1598 mDNSlocal void DetermineMaxEventFD( void )
1599 {
1600 PosixEventSource *iSource;
1601
1602 gMaxFD = 0;
1603 for ( iSource=(PosixEventSource*)gEventSources.Head; iSource; iSource = iSource->Next)
1604 if ( gMaxFD < iSource->fd)
1605 gMaxFD = iSource->fd;
1606 }
1607
1608 // Add a file descriptor to the set that mDNSPosixRunEventLoopOnce() listens to.
1609 mStatus mDNSPosixAddFDToEventLoop( int fd, mDNSPosixEventCallback callback, void *context)
1610 {
1611 PosixEventSource *newSource;
1612
1613 if ( gEventSources.LinkOffset == 0)
1614 InitLinkedList( &gEventSources, offsetof( PosixEventSource, Next));
1615
1616 if ( fd >= (int) FD_SETSIZE || fd < 0)
1617 return mStatus_UnsupportedErr;
1618 if ( callback == NULL)
1619 return mStatus_BadParamErr;
1620
1621 newSource = (PosixEventSource*) malloc( sizeof *newSource);
1622 if ( NULL == newSource)
1623 return mStatus_NoMemoryErr;
1624
1625 newSource->Callback = callback;
1626 newSource->Context = context;
1627 newSource->fd = fd;
1628
1629 AddToTail( &gEventSources, newSource);
1630 FD_SET( fd, &gEventFDs);
1631
1632 DetermineMaxEventFD();
1633
1634 return mStatus_NoError;
1635 }
1636
1637 // Remove a file descriptor from the set that mDNSPosixRunEventLoopOnce() listens to.
1638 mStatus mDNSPosixRemoveFDFromEventLoop( int fd)
1639 {
1640 PosixEventSource *iSource;
1641
1642 for ( iSource=(PosixEventSource*)gEventSources.Head; iSource; iSource = iSource->Next)
1643 {
1644 if ( fd == iSource->fd)
1645 {
1646 FD_CLR( fd, &gEventFDs);
1647 RemoveFromList( &gEventSources, iSource);
1648 free( iSource);
1649 DetermineMaxEventFD();
1650 return mStatus_NoError;
1651 }
1652 }
1653 return mStatus_NoSuchNameErr;
1654 }
1655
1656 // Simply note the received signal in gEventSignals.
1657 mDNSlocal void NoteSignal( int signum)
1658 {
1659 sigaddset( &gEventSignals, signum);
1660 }
1661
1662 // Tell the event package to listen for signal and report it in mDNSPosixRunEventLoopOnce().
1663 mStatus mDNSPosixListenForSignalInEventLoop( int signum)
1664 {
1665 struct sigaction action;
1666 mStatus err;
1667
1668 bzero( &action, sizeof action); // more portable than member-wise assignment
1669 action.sa_handler = NoteSignal;
1670 err = sigaction( signum, &action, (struct sigaction*) NULL);
1671
1672 sigaddset( &gEventSignalSet, signum);
1673
1674 return err;
1675 }
1676
1677 // Tell the event package to stop listening for signal in mDNSPosixRunEventLoopOnce().
1678 mStatus mDNSPosixIgnoreSignalInEventLoop( int signum)
1679 {
1680 struct sigaction action;
1681 mStatus err;
1682
1683 bzero( &action, sizeof action); // more portable than member-wise assignment
1684 action.sa_handler = SIG_DFL;
1685 err = sigaction( signum, &action, (struct sigaction*) NULL);
1686
1687 sigdelset( &gEventSignalSet, signum);
1688
1689 return err;
1690 }
1691
1692 // Do a single pass through the attendent event sources and dispatch any found to their callbacks.
1693 // Return as soon as internal timeout expires, or a signal we're listening for is received.
1694 mStatus mDNSPosixRunEventLoopOnce( mDNS *m, const struct timeval *pTimeout,
1695 sigset_t *pSignalsReceived, mDNSBool *pDataDispatched)
1696 {
1697 fd_set listenFDs = gEventFDs;
1698 int fdMax = 0, numReady;
1699 struct timeval timeout = *pTimeout;
1700
1701 // Include the sockets that are listening to the wire in our select() set
1702 mDNSPosixGetFDSet( m, &fdMax, &listenFDs, &timeout); // timeout may get modified
1703 if ( fdMax < gMaxFD)
1704 fdMax = gMaxFD;
1705
1706 numReady = select( fdMax + 1, &listenFDs, (fd_set*) NULL, (fd_set*) NULL, &timeout);
1707
1708 // If any data appeared, invoke its callback
1709 if ( numReady > 0)
1710 {
1711 PosixEventSource *iSource;
1712
1713 (void) mDNSPosixProcessFDSet( m, &listenFDs); // call this first to process wire data for clients
1714
1715 for ( iSource=(PosixEventSource*)gEventSources.Head; iSource; iSource = iSource->Next)
1716 {
1717 if ( FD_ISSET( iSource->fd, &listenFDs))
1718 {
1719 iSource->Callback( iSource->Context);
1720 break; // in case callback removed elements from gEventSources
1721 }
1722 }
1723 *pDataDispatched = mDNStrue;
1724 }
1725 else
1726 *pDataDispatched = mDNSfalse;
1727
1728 (void) sigprocmask( SIG_BLOCK, &gEventSignalSet, (sigset_t*) NULL);
1729 *pSignalsReceived = gEventSignals;
1730 sigemptyset( &gEventSignals);
1731 (void) sigprocmask( SIG_UNBLOCK, &gEventSignalSet, (sigset_t*) NULL);
1732
1733 return mStatus_NoError;
1734 }