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