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