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