xref: /titanic_51/usr/src/cmd/cmd-inet/usr.lib/mdnsd/mDNSPosix.c (revision fc80c0dfb0c877aee828d778ea32b77fcf7b1ef4)
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 #pragma ident	"%Z%%M%	%I%	%E% SMI"
293 
294 #include "mDNSEmbeddedAPI.h"           // Defines the interface provided to the client layer above
295 #include "mDNSPosix.h"				 // Defines the specific types needed to run mDNS on this platform
296 #include "dns_sd.h"
297 
298 #include <assert.h>
299 #include <stdio.h>
300 #include <stdlib.h>
301 #include <errno.h>
302 #include <string.h>
303 #include <unistd.h>
304 #include <syslog.h>
305 #include <stdarg.h>
306 #include <fcntl.h>
307 #include <sys/types.h>
308 #include <sys/time.h>
309 #include <sys/socket.h>
310 #include <sys/uio.h>
311 #include <sys/select.h>
312 #include <netinet/in.h>
313 #include <arpa/inet.h>
314 #include <time.h>                   // platform support for UTC time
315 
316 #if USES_NETLINK
317 #include <asm/types.h>
318 #include <linux/netlink.h>
319 #include <linux/rtnetlink.h>
320 #else // USES_NETLINK
321 #include <net/route.h>
322 #include <net/if.h>
323 #endif // USES_NETLINK
324 
325 #include "mDNSUNP.h"
326 #include "GenLinkedList.h"
327 
328 // ***************************************************************************
329 // Structures
330 
331 // We keep a list of client-supplied event sources in PosixEventSource records
332 struct PosixEventSource
333 	{
334 	mDNSPosixEventCallback		Callback;
335 	void						*Context;
336 	int							fd;
337 	struct  PosixEventSource	*Next;
338 	};
339 typedef struct PosixEventSource	PosixEventSource;
340 
341 // Context record for interface change callback
342 struct IfChangeRec
343 	{
344 	int			NotifySD;
345 	mDNS*		mDNS;
346 	};
347 typedef struct IfChangeRec	IfChangeRec;
348 
349 // Note that static data is initialized to zero in (modern) C.
350 static fd_set			gEventFDs;
351 static int				gMaxFD;					// largest fd in gEventFDs
352 static GenLinkedList	gEventSources;			// linked list of PosixEventSource's
353 static sigset_t			gEventSignalSet;		// Signals which event loop listens for
354 static sigset_t			gEventSignals;			// Signals which were received while inside loop
355 
356 // ***************************************************************************
357 // Globals (for debugging)
358 
359 static int num_registered_interfaces = 0;
360 static int num_pkts_accepted = 0;
361 static int num_pkts_rejected = 0;
362 
363 // ***************************************************************************
364 // Functions
365 
366 int gMDNSPlatformPosixVerboseLevel = 0;
367 
368 #define PosixErrorToStatus(errNum) ((errNum) == 0 ? mStatus_NoError : mStatus_UnknownErr)
369 
370 mDNSlocal void SockAddrTomDNSAddr(const struct sockaddr *const sa, mDNSAddr *ipAddr, mDNSIPPort *ipPort)
371 	{
372 	switch (sa->sa_family)
373 		{
374 		case AF_INET:
375 			{
376 			struct sockaddr_in* sin          = (struct sockaddr_in*)sa;
377 			ipAddr->type                     = mDNSAddrType_IPv4;
378 			ipAddr->ip.v4.NotAnInteger       = sin->sin_addr.s_addr;
379 			if (ipPort) ipPort->NotAnInteger = sin->sin_port;
380 			break;
381 			}
382 
383 #if HAVE_IPV6
384 		case AF_INET6:
385 			{
386 			struct sockaddr_in6* sin6        = (struct sockaddr_in6*)sa;
387 #ifndef NOT_HAVE_SA_LEN
388 			assert(sin6->sin6_len == sizeof(*sin6));
389 #endif
390 			ipAddr->type                     = mDNSAddrType_IPv6;
391 			ipAddr->ip.v6                    = *(mDNSv6Addr*)&sin6->sin6_addr;
392 			if (ipPort) ipPort->NotAnInteger = sin6->sin6_port;
393 			break;
394 			}
395 #endif
396 
397 		default:
398 			verbosedebugf("SockAddrTomDNSAddr: Uknown address family %d\n", sa->sa_family);
399 			ipAddr->type = mDNSAddrType_None;
400 			if (ipPort) ipPort->NotAnInteger = 0;
401 			break;
402 		}
403 	}
404 
405 #if COMPILER_LIKES_PRAGMA_MARK
406 #pragma mark ***** Send and Receive
407 #endif
408 
409 // mDNS core calls this routine when it needs to send a packet.
410 mDNSexport mStatus mDNSPlatformSendUDP(const mDNS *const m, const void *const msg, const mDNSu8 *const end,
411 	mDNSInterfaceID InterfaceID, const mDNSAddr *dst, mDNSIPPort dstPort)
412 	{
413 	int                     err = 0;
414 	struct sockaddr_storage to;
415 	PosixNetworkInterface * thisIntf = (PosixNetworkInterface *)(InterfaceID);
416 	int sendingsocket = -1;
417 
418 	assert(m != NULL);
419 	assert(msg != NULL);
420 	assert(end != NULL);
421 	assert( (((char *) end) - ((char *) msg)) > 0 );
422 	assert(dstPort.NotAnInteger != 0);
423 
424 	if (dst->type == mDNSAddrType_IPv4)
425 		{
426 		struct sockaddr_in *sin = (struct sockaddr_in*)&to;
427 #ifndef NOT_HAVE_SA_LEN
428 		sin->sin_len            = sizeof(*sin);
429 #endif
430 		sin->sin_family         = AF_INET;
431 		sin->sin_port           = dstPort.NotAnInteger;
432 		sin->sin_addr.s_addr    = dst->ip.v4.NotAnInteger;
433 		sendingsocket           = thisIntf ? thisIntf->multicastSocket4 : m->p->unicastSocket4;
434 		}
435 
436 #if HAVE_IPV6
437 	else if (dst->type == mDNSAddrType_IPv6)
438 		{
439 		struct sockaddr_in6 *sin6 = (struct sockaddr_in6*)&to;
440 		mDNSPlatformMemZero(sin6, sizeof(*sin6));
441 #ifndef NOT_HAVE_SA_LEN
442 		sin6->sin6_len            = sizeof(*sin6);
443 #endif
444 		sin6->sin6_family         = AF_INET6;
445 		sin6->sin6_port           = dstPort.NotAnInteger;
446 		sin6->sin6_addr           = *(struct in6_addr*)&dst->ip.v6;
447 		sendingsocket             = thisIntf ? thisIntf->multicastSocket6 : m->p->unicastSocket6;
448 		}
449 #endif
450 
451 	if (sendingsocket >= 0)
452 		err = sendto(sendingsocket, msg, (char*)end - (char*)msg, 0, (struct sockaddr *)&to, GET_SA_LEN(to));
453 
454 	if      (err > 0) err = 0;
455 	else if (err < 0)
456 		{
457 		static int MessageCount = 0;
458         // Don't report EHOSTDOWN (i.e. ARP failure), ENETDOWN, or no route to host for unicast destinations
459 		if (!mDNSAddressIsAllDNSLinkGroup(dst))
460 			if (errno == EHOSTDOWN || errno == ENETDOWN || errno == EHOSTUNREACH || errno == ENETUNREACH) return(mStatus_TransientErr);
461 
462 		if (MessageCount < 1000)
463 			{
464 			MessageCount++;
465 			if (thisIntf)
466 				LogMsg("mDNSPlatformSendUDP got error %d (%s) sending packet to %#a on interface %#a/%s/%d",
467 							  errno, strerror(errno), dst, &thisIntf->coreIntf.ip, thisIntf->intfName, thisIntf->index);
468 			else
469 				LogMsg("mDNSPlatformSendUDP got error %d (%s) sending packet to %#a", errno, strerror(errno), dst);
470 			}
471 		}
472 
473 	return PosixErrorToStatus(err);
474 	}
475 
476 // This routine is called when the main loop detects that data is available on a socket.
477 mDNSlocal void SocketDataReady(mDNS *const m, PosixNetworkInterface *intf, int skt)
478 	{
479 	mDNSAddr   senderAddr, destAddr;
480 	mDNSIPPort senderPort;
481 	ssize_t                 packetLen;
482 	DNSMessage              packet;
483 	struct my_in_pktinfo    packetInfo;
484 	struct sockaddr_storage from;
485 	socklen_t               fromLen;
486 	int                     flags;
487 	mDNSu8					ttl;
488 	mDNSBool                reject;
489 	const mDNSInterfaceID InterfaceID = intf ? intf->coreIntf.InterfaceID : NULL;
490 
491 	assert(m    != NULL);
492 	assert(skt  >= 0);
493 
494 	fromLen = sizeof(from);
495 	flags   = 0;
496 	packetLen = recvfrom_flags(skt, &packet, sizeof(packet), &flags, (struct sockaddr *) &from, &fromLen, &packetInfo, &ttl);
497 
498 	if (packetLen >= 0)
499 		{
500 		SockAddrTomDNSAddr((struct sockaddr*)&from, &senderAddr, &senderPort);
501 		SockAddrTomDNSAddr((struct sockaddr*)&packetInfo.ipi_addr, &destAddr, NULL);
502 
503 		// If we have broken IP_RECVDSTADDR functionality (so far
504 		// I've only seen this on OpenBSD) then apply a hack to
505 		// convince mDNS Core that this isn't a spoof packet.
506 		// Basically what we do is check to see whether the
507 		// packet arrived as a multicast and, if so, set its
508 		// destAddr to the mDNS address.
509 		//
510 		// I must admit that I could just be doing something
511 		// wrong on OpenBSD and hence triggering this problem
512 		// but I'm at a loss as to how.
513 		//
514 		// If this platform doesn't have IP_PKTINFO or IP_RECVDSTADDR, then we have
515 		// no way to tell the destination address or interface this packet arrived on,
516 		// so all we can do is just assume it's a multicast
517 
518 		#if HAVE_BROKEN_RECVDSTADDR || (!defined(IP_PKTINFO) && !defined(IP_RECVDSTADDR))
519 			if ( (destAddr.NotAnInteger == 0) && (flags & MSG_MCAST) )
520 				{
521 				destAddr.type = senderAddr.type;
522 				if      (senderAddr.type == mDNSAddrType_IPv4) destAddr.ip.v4 = AllDNSLinkGroupv4;
523 				else if (senderAddr.type == mDNSAddrType_IPv6) destAddr.ip.v6 = AllDNSLinkGroupv6;
524 				}
525 		#endif
526 
527 		// We only accept the packet if the interface on which it came
528 		// in matches the interface associated with this socket.
529 		// We do this match by name or by index, depending on which
530 		// information is available.  recvfrom_flags sets the name
531 		// to "" if the name isn't available, or the index to -1
532 		// if the index is available.  This accomodates the various
533 		// different capabilities of our target platforms.
534 
535 		reject = mDNSfalse;
536 		if (!intf)
537 			{
538 			// Ignore multicasts accidentally delivered to our unicast receiving socket
539 			if (mDNSAddrIsDNSMulticast(&destAddr)) packetLen = -1;
540 			}
541 		else
542 			{
543 			if      ( packetInfo.ipi_ifname[0] != 0 ) reject = (strcmp(packetInfo.ipi_ifname, intf->intfName) != 0);
544 			else if ( packetInfo.ipi_ifindex != -1 )  reject = (packetInfo.ipi_ifindex != intf->index);
545 
546 			if (reject)
547 				{
548 				verbosedebugf("SocketDataReady ignored a packet from %#a to %#a on interface %s/%d expecting %#a/%s/%d/%d",
549 					&senderAddr, &destAddr, packetInfo.ipi_ifname, packetInfo.ipi_ifindex,
550 					&intf->coreIntf.ip, intf->intfName, intf->index, skt);
551 				packetLen = -1;
552 				num_pkts_rejected++;
553 				if (num_pkts_rejected > (num_pkts_accepted + 1) * (num_registered_interfaces + 1) * 2)
554 					{
555 					fprintf(stderr,
556 						"*** WARNING: Received %d packets; Accepted %d packets; Rejected %d packets because of interface mismatch\n",
557 						num_pkts_accepted + num_pkts_rejected, num_pkts_accepted, num_pkts_rejected);
558 					num_pkts_accepted = 0;
559 					num_pkts_rejected = 0;
560 					}
561 				}
562 			else
563 				{
564 				verbosedebugf("SocketDataReady got a packet from %#a to %#a on interface %#a/%s/%d/%d",
565 					&senderAddr, &destAddr, &intf->coreIntf.ip, intf->intfName, intf->index, skt);
566 				num_pkts_accepted++;
567 				}
568 			}
569 		}
570 
571 	if (packetLen >= 0)
572 		mDNSCoreReceive(m, &packet, (mDNSu8 *)&packet + packetLen,
573 			&senderAddr, senderPort, &destAddr, MulticastDNSPort, InterfaceID);
574 	}
575 
576 mDNSexport mStatus mDNSPlatformTCPConnect(const mDNSAddr *dst, mDNSOpaque16 dstport, mDNSInterfaceID InterfaceID,
577 										  TCPConnectionCallback callback, void *context, int *descriptor)
578 	{
579 	(void)dst;			// Unused
580 	(void)dstport;		// Unused
581 	(void)InterfaceID;	// Unused
582 	(void)callback;		// Unused
583 	(void)context;		// Unused
584 	(void)descriptor;	// Unused
585 	return(mStatus_UnsupportedErr);
586 	}
587 
588 mDNSexport void mDNSPlatformTCPCloseConnection(int sd)
589 	{
590 	(void)sd;			// Unused
591 	}
592 
593 mDNSexport int mDNSPlatformReadTCP(int sd, void *buf, int buflen)
594 	{
595 	(void)sd;			// Unused
596 	(void)buf;			// Unused
597 	(void)buflen;			// Unused
598 	return(0);
599 	}
600 
601 mDNSexport int mDNSPlatformWriteTCP(int sd, const char *msg, int len)
602 	{
603 	(void)sd;			// Unused
604 	(void)msg;			// Unused
605 	(void)len;			// Unused
606 	return(0);
607 	}
608 
609 #if COMPILER_LIKES_PRAGMA_MARK
610 #pragma mark ***** Get/Free Search Domain List
611 #endif
612 
613 mDNSexport DNameListElem *mDNSPlatformGetSearchDomainList(void)
614 	{
615 	static DNameListElem tmp;
616 	static mDNSBool init = mDNSfalse;
617 
618 	if (!init)
619 		{
620 		MakeDomainNameFromDNSNameString(&tmp.name, "local.");
621 		tmp.next = NULL;
622 		init = mDNStrue;
623 		}
624 	return mDNS_CopyDNameList(&tmp);
625 	}
626 
627 mDNSexport DNameListElem *mDNSPlatformGetRegDomainList(void)
628 	{
629 	return NULL;
630 	}
631 
632 #if COMPILER_LIKES_PRAGMA_MARK
633 #pragma mark ***** Init and Term
634 #endif
635 
636 // This gets the current hostname, truncating it at the first dot if necessary
637 mDNSlocal void GetUserSpecifiedRFC1034ComputerName(domainlabel *const namelabel)
638 	{
639 	int len = 0;
640 	gethostname((char *)(&namelabel->c[1]), MAX_DOMAIN_LABEL);
641 	while (len < MAX_DOMAIN_LABEL && namelabel->c[len+1] && namelabel->c[len+1] != '.') len++;
642 	namelabel->c[0] = len;
643 	}
644 
645 // On OS X this gets the text of the field labelled "Computer Name" in the Sharing Prefs Control Panel
646 // Other platforms can either get the information from the appropriate place,
647 // or they can alternatively just require all registering services to provide an explicit name
648 mDNSlocal void GetUserSpecifiedFriendlyComputerName(domainlabel *const namelabel)
649 	{
650 	// On Unix we have no better name than the host name, so we just use that.
651 	GetUserSpecifiedRFC1034ComputerName( namelabel);
652 	}
653 
654 mDNSexport int ParseDNSServers(mDNS *m, const char *filePath)
655 	{
656 	char line[256];
657 	char nameserver[16];
658 	char keyword[10];
659 	int  numOfServers = 0;
660 	FILE *fp = fopen(filePath, "r");
661 	if (fp == NULL) return -1;
662 	while (fgets(line,sizeof(line),fp))
663 		{
664 		struct in_addr ina;
665 		line[255]='\0';		// just to be safe
666 		if (sscanf(line,"%10s %15s", keyword, nameserver) != 2) continue;	// it will skip whitespaces
667 		if (strncmp(keyword,"nameserver",10)) continue;
668 		if (inet_aton(nameserver, (struct in_addr *)&ina) != 0)
669 			{
670 			mDNSAddr DNSAddr;
671 			DNSAddr.type = mDNSAddrType_IPv4;
672 			DNSAddr.ip.v4.NotAnInteger = ina.s_addr;
673 			mDNS_AddDNSServer(m, &DNSAddr, NULL);
674 			numOfServers++;
675 			}
676 		}
677 	return (numOfServers > 0) ? 0 : -1;
678 	}
679 
680 // Searches the interface list looking for the named interface.
681 // Returns a pointer to if it found, or NULL otherwise.
682 mDNSlocal PosixNetworkInterface *SearchForInterfaceByName(mDNS *const m, const char *intfName)
683 	{
684 	PosixNetworkInterface *intf;
685 
686 	assert(m != NULL);
687 	assert(intfName != NULL);
688 
689 	intf = (PosixNetworkInterface*)(m->HostInterfaces);
690 	while ( (intf != NULL) && (strcmp(intf->intfName, intfName) != 0) )
691 		intf = (PosixNetworkInterface *)(intf->coreIntf.next);
692 
693 	return intf;
694 	}
695 
696 mDNSexport mDNSInterfaceID mDNSPlatformInterfaceIDfromInterfaceIndex(mDNS *const m, mDNSu32 index)
697 	{
698 	PosixNetworkInterface *intf;
699 
700 	assert(m != NULL);
701 
702 	if (index == kDNSServiceInterfaceIndexLocalOnly) return(mDNSInterface_LocalOnly);
703 
704 	intf = (PosixNetworkInterface*)(m->HostInterfaces);
705 	while ( (intf != NULL) && (mDNSu32) intf->index != index)
706 		intf = (PosixNetworkInterface *)(intf->coreIntf.next);
707 
708 	return (mDNSInterfaceID) intf;
709 	}
710 
711 mDNSexport mDNSu32 mDNSPlatformInterfaceIndexfromInterfaceID(mDNS *const m, mDNSInterfaceID id)
712 	{
713 	PosixNetworkInterface *intf;
714 
715 	assert(m != NULL);
716 
717 	if (id == mDNSInterface_LocalOnly) return(kDNSServiceInterfaceIndexLocalOnly);
718 
719 	intf = (PosixNetworkInterface*)(m->HostInterfaces);
720 	while ( (intf != NULL) && (mDNSInterfaceID) intf != id)
721 		intf = (PosixNetworkInterface *)(intf->coreIntf.next);
722 
723 	return intf ? intf->index : 0;
724 	}
725 
726 // Frees the specified PosixNetworkInterface structure. The underlying
727 // interface must have already been deregistered with the mDNS core.
728 mDNSlocal void FreePosixNetworkInterface(PosixNetworkInterface *intf)
729 	{
730 	assert(intf != NULL);
731 	if (intf->intfName != NULL)        free((void *)intf->intfName);
732 	if (intf->multicastSocket4 != -1) assert(close(intf->multicastSocket4) == 0);
733 #if HAVE_IPV6
734 	if (intf->multicastSocket6 != -1) assert(close(intf->multicastSocket6) == 0);
735 #endif
736 	free(intf);
737 	}
738 
739 // Grab the first interface, deregister it, free it, and repeat until done.
740 mDNSlocal void ClearInterfaceList(mDNS *const m)
741 	{
742 	assert(m != NULL);
743 
744 	while (m->HostInterfaces)
745 		{
746 		PosixNetworkInterface *intf = (PosixNetworkInterface*)(m->HostInterfaces);
747 		mDNS_DeregisterInterface(m, &intf->coreIntf, mDNSfalse);
748 		if (gMDNSPlatformPosixVerboseLevel > 0) fprintf(stderr, "Deregistered interface %s\n", intf->intfName);
749 		FreePosixNetworkInterface(intf);
750 		}
751 	num_registered_interfaces = 0;
752 	num_pkts_accepted = 0;
753 	num_pkts_rejected = 0;
754 	}
755 
756 // Sets up a send/receive socket.
757 // If mDNSIPPort port is non-zero, then it's a multicast socket on the specified interface
758 // If mDNSIPPort port is zero, then it's a randomly assigned port number, used for sending unicast queries
759 mDNSlocal int SetupSocket(struct sockaddr *intfAddr, mDNSIPPort port, int interfaceIndex, int *sktPtr)
760 	{
761 	int err = 0;
762 	static const int kOn = 1;
763 	static const int kIntTwoFiveFive = 255;
764 	static const unsigned char kByteTwoFiveFive = 255;
765 	const mDNSBool JoinMulticastGroup = (port.NotAnInteger != 0);
766 
767 	(void) interfaceIndex;	// This parameter unused on plaforms that don't have IPv6
768 	assert(intfAddr != NULL);
769 	assert(sktPtr != NULL);
770 	assert(*sktPtr == -1);
771 
772 	// Open the socket...
773 	if      (intfAddr->sa_family == AF_INET ) *sktPtr = socket(PF_INET,  SOCK_DGRAM, IPPROTO_UDP);
774 #if HAVE_IPV6
775 	else if (intfAddr->sa_family == AF_INET6) *sktPtr = socket(PF_INET6, SOCK_DGRAM, IPPROTO_UDP);
776 #endif
777 	else return EINVAL;
778 
779 	if (*sktPtr < 0) { err = errno; perror("socket"); }
780 
781 	// ... with a shared UDP port, if it's for multicast receiving
782 	if (err == 0 && port.NotAnInteger)
783 		{
784 		#if defined(SO_REUSEPORT)
785 			err = setsockopt(*sktPtr, SOL_SOCKET, SO_REUSEPORT, &kOn, sizeof(kOn));
786 		#elif defined(SO_REUSEADDR)
787 			err = setsockopt(*sktPtr, SOL_SOCKET, SO_REUSEADDR, &kOn, sizeof(kOn));
788 		#else
789 			#error This platform has no way to avoid address busy errors on multicast.
790 		#endif
791 		if (err < 0) { err = errno; perror("setsockopt - SO_REUSExxxx"); }
792 		}
793 
794 	// We want to receive destination addresses and interface identifiers.
795 	if (intfAddr->sa_family == AF_INET)
796 		{
797 		struct ip_mreq imr;
798 		struct sockaddr_in bindAddr;
799 		if (err == 0)
800 			{
801 			#if defined(IP_PKTINFO)						// Linux and Solaris
802 				err = setsockopt(*sktPtr, IPPROTO_IP, IP_PKTINFO, &kOn, sizeof(kOn));
803 				if (err < 0) { err = errno; perror("setsockopt - IP_PKTINFO"); }
804 			#elif defined(IP_RECVDSTADDR) || defined(IP_RECVIF)		// BSD
805 				#if defined(IP_RECVDSTADDR)
806 					err = setsockopt(*sktPtr, IPPROTO_IP, IP_RECVDSTADDR, &kOn, sizeof(kOn));
807 					if (err < 0) { err = errno; perror("setsockopt - IP_RECVDSTADDR"); }
808 				#endif
809 				#if defined(IP_RECVIF)
810 					if (err == 0)
811 						{
812 						err = setsockopt(*sktPtr, IPPROTO_IP, IP_RECVIF, &kOn, sizeof(kOn));
813 						if (err < 0) { err = errno; perror("setsockopt - IP_RECVIF"); }
814 						}
815 				#endif
816 			#else
817 				#warning This platform has no way to get the destination interface information -- will only work for single-homed hosts
818 			#endif
819 			}
820 	#if defined(IP_RECVTTL)									// Linux
821 		if (err == 0)
822 			{
823 			setsockopt(*sktPtr, IPPROTO_IP, IP_RECVTTL, &kOn, sizeof(kOn));
824 			// We no longer depend on being able to get the received TTL, so don't worry if the option fails
825 			}
826 	#endif
827 
828 		// Add multicast group membership on this interface
829 		if (err == 0 && JoinMulticastGroup)
830 			{
831 			imr.imr_multiaddr.s_addr = AllDNSLinkGroupv4.NotAnInteger;
832 			imr.imr_interface        = ((struct sockaddr_in*)intfAddr)->sin_addr;
833 			err = setsockopt(*sktPtr, IPPROTO_IP, IP_ADD_MEMBERSHIP, &imr, sizeof(imr));
834 			if (err < 0) { err = errno; perror("setsockopt - IP_ADD_MEMBERSHIP"); }
835 			}
836 
837 		// Specify outgoing interface too
838 		if (err == 0 && JoinMulticastGroup)
839 			{
840 			err = setsockopt(*sktPtr, IPPROTO_IP, IP_MULTICAST_IF, &((struct sockaddr_in*)intfAddr)->sin_addr, sizeof(struct in_addr));
841 			if (err < 0) { err = errno; perror("setsockopt - IP_MULTICAST_IF"); }
842 			}
843 
844 		// Per the mDNS spec, send unicast packets with TTL 255
845 		if (err == 0)
846 			{
847 			err = setsockopt(*sktPtr, IPPROTO_IP, IP_TTL, &kIntTwoFiveFive, sizeof(kIntTwoFiveFive));
848 			if (err < 0) { err = errno; perror("setsockopt - IP_TTL"); }
849 			}
850 
851 		// and multicast packets with TTL 255 too
852 		// There's some debate as to whether IP_MULTICAST_TTL is an int or a byte so we just try both.
853 		if (err == 0)
854 			{
855 			err = setsockopt(*sktPtr, IPPROTO_IP, IP_MULTICAST_TTL, &kByteTwoFiveFive, sizeof(kByteTwoFiveFive));
856 			if (err < 0 && errno == EINVAL)
857 				err = setsockopt(*sktPtr, IPPROTO_IP, IP_MULTICAST_TTL, &kIntTwoFiveFive, sizeof(kIntTwoFiveFive));
858 			if (err < 0) { err = errno; perror("setsockopt - IP_MULTICAST_TTL"); }
859 			}
860 
861 		// And start listening for packets
862 		if (err == 0)
863 			{
864 			bindAddr.sin_family      = AF_INET;
865 			bindAddr.sin_port        = port.NotAnInteger;
866 			bindAddr.sin_addr.s_addr = INADDR_ANY; // Want to receive multicasts AND unicasts on this socket
867 			err = bind(*sktPtr, (struct sockaddr *) &bindAddr, sizeof(bindAddr));
868 			if (err < 0) { err = errno; perror("bind"); fflush(stderr); }
869 			}
870 		} // endif (intfAddr->sa_family == AF_INET)
871 
872 #if HAVE_IPV6
873 	else if (intfAddr->sa_family == AF_INET6)
874 		{
875 		struct ipv6_mreq imr6;
876 		struct sockaddr_in6 bindAddr6;
877 	#if defined(IPV6_RECVPKTINFO) 	// Solaris
878 		if (err == 0)
879 			{
880 				err = setsockopt(*sktPtr, IPPROTO_IPV6, IPV6_RECVPKTINFO, &kOn, sizeof(kOn));
881 				if (err < 0) { err = errno; perror("setsockopt - IPV6_PKTINFO"); }
882 			}
883 
884 	#elif defined(IPV6_PKTINFO)
885 		if (err == 0)
886 			{
887 				err = setsockopt(*sktPtr, IPPROTO_IPV6, IPV6_PKTINFO, &kOn, sizeof(kOn));
888 				if (err < 0) { err = errno; perror("setsockopt - IPV6_PKTINFO"); }
889 			}
890 	#else
891 		#warning This platform has no way to get the destination interface information for IPv6 -- will only work for single-homed hosts
892 	#endif
893 	#if defined(IPV6_RECVHOPLIMIT) // Solaris
894 		if (err == 0)
895 			{
896 				err = setsockopt(*sktPtr, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &kOn, sizeof(kOn));
897 				if (err < 0) { err = errno; perror("setsockopt - IPV6_HOPLIMIT"); }
898 			}
899 
900 	#elif defined(IPV6_HOPLIMIT)
901 		if (err == 0)
902 			{
903 				err = setsockopt(*sktPtr, IPPROTO_IPV6, IPV6_HOPLIMIT, &kOn, sizeof(kOn));
904 				if (err < 0) { err = errno; perror("setsockopt - IPV6_HOPLIMIT"); }
905 			}
906 	#endif
907 
908 		// Add multicast group membership on this interface
909 		if (err == 0 && JoinMulticastGroup)
910 			{
911 			imr6.ipv6mr_multiaddr       = *(const struct in6_addr*)&AllDNSLinkGroupv6;
912 			imr6.ipv6mr_interface       = interfaceIndex;
913 			//LogMsg("Joining %.16a on %d", &imr6.ipv6mr_multiaddr, imr6.ipv6mr_interface);
914 			err = setsockopt(*sktPtr, IPPROTO_IPV6, IPV6_JOIN_GROUP, &imr6, sizeof(imr6));
915 			if (err < 0)
916 				{
917 				err = errno;
918 				verbosedebugf("IPV6_JOIN_GROUP %.16a on %d failed.\n", &imr6.ipv6mr_multiaddr, imr6.ipv6mr_interface);
919 				perror("setsockopt - IPV6_JOIN_GROUP");
920 				}
921 			}
922 
923 		// Specify outgoing interface too
924 		if (err == 0 && JoinMulticastGroup)
925 			{
926 			u_int	multicast_if = interfaceIndex;
927 			err = setsockopt(*sktPtr, IPPROTO_IPV6, IPV6_MULTICAST_IF, &multicast_if, sizeof(multicast_if));
928 			if (err < 0) { err = errno; perror("setsockopt - IPV6_MULTICAST_IF"); }
929 			}
930 
931 		// We want to receive only IPv6 packets on this socket.
932 		// Without this option, we may get IPv4 addresses as mapped addresses.
933 		if (err == 0)
934 			{
935 			err = setsockopt(*sktPtr, IPPROTO_IPV6, IPV6_V6ONLY, &kOn, sizeof(kOn));
936 			if (err < 0) { err = errno; perror("setsockopt - IPV6_V6ONLY"); }
937 			}
938 
939 		// Per the mDNS spec, send unicast packets with TTL 255
940 		if (err == 0)
941 			{
942 			err = setsockopt(*sktPtr, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &kIntTwoFiveFive, sizeof(kIntTwoFiveFive));
943 			if (err < 0) { err = errno; perror("setsockopt - IPV6_UNICAST_HOPS"); }
944 			}
945 
946 		// and multicast packets with TTL 255 too
947 		// There's some debate as to whether IPV6_MULTICAST_HOPS is an int or a byte so we just try both.
948 		if (err == 0)
949 			{
950 			err = setsockopt(*sktPtr, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &kByteTwoFiveFive, sizeof(kByteTwoFiveFive));
951 			if (err < 0 && errno == EINVAL)
952 				err = setsockopt(*sktPtr, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &kIntTwoFiveFive, sizeof(kIntTwoFiveFive));
953 			if (err < 0) { err = errno; perror("setsockopt - IPV6_MULTICAST_HOPS"); }
954 			}
955 
956 		// And start listening for packets
957 		if (err == 0)
958 			{
959 			mDNSPlatformMemZero(&bindAddr6, sizeof(bindAddr6));
960 #ifndef NOT_HAVE_SA_LEN
961 			bindAddr6.sin6_len         = sizeof(bindAddr6);
962 #endif
963 			bindAddr6.sin6_family      = AF_INET6;
964 			bindAddr6.sin6_port        = port.NotAnInteger;
965 			bindAddr6.sin6_flowinfo    = 0;
966 			bindAddr6.sin6_addr        = in6addr_any; // Want to receive multicasts AND unicasts on this socket
967 			bindAddr6.sin6_scope_id    = 0;
968 			err = bind(*sktPtr, (struct sockaddr *) &bindAddr6, sizeof(bindAddr6));
969 			if (err < 0) { err = errno; perror("bind"); fflush(stderr); }
970 			}
971 		} // endif (intfAddr->sa_family == AF_INET6)
972 #endif
973 
974 	// Set the socket to non-blocking.
975 	if (err == 0)
976 		{
977 		err = fcntl(*sktPtr, F_GETFL, 0);
978 		if (err < 0) err = errno;
979 		else
980 			{
981 			err = fcntl(*sktPtr, F_SETFL, err | O_NONBLOCK);
982 			if (err < 0) err = errno;
983 			}
984 		}
985 
986 	// Clean up
987 	if (err != 0 && *sktPtr != -1) { assert(close(*sktPtr) == 0); *sktPtr = -1; }
988 	assert( (err == 0) == (*sktPtr != -1) );
989 	return err;
990 	}
991 
992 // Creates a PosixNetworkInterface for the interface whose IP address is
993 // intfAddr and whose name is intfName and registers it with mDNS core.
994 mDNSlocal int SetupOneInterface(mDNS *const m, struct sockaddr *intfAddr, struct sockaddr *intfMask, const char *intfName, int intfIndex)
995 	{
996 	int err = 0;
997 	PosixNetworkInterface *intf;
998 	PosixNetworkInterface *alias = NULL;
999 
1000 	assert(m != NULL);
1001 	assert(intfAddr != NULL);
1002 	assert(intfName != NULL);
1003 	assert(intfMask != NULL);
1004 
1005 	// Allocate the interface structure itself.
1006 	intf = (PosixNetworkInterface*)malloc(sizeof(*intf));
1007 	if (intf == NULL) { assert(0); err = ENOMEM; }
1008 
1009 	// And make a copy of the intfName.
1010 	if (err == 0)
1011 		{
1012 		intf->intfName = strdup(intfName);
1013 		if (intf->intfName == NULL) { assert(0); err = ENOMEM; }
1014 		}
1015 
1016 	if (err == 0)
1017 		{
1018 		// Set up the fields required by the mDNS core.
1019 		SockAddrTomDNSAddr(intfAddr, &intf->coreIntf.ip, NULL);
1020 		SockAddrTomDNSAddr(intfMask, &intf->coreIntf.mask, NULL);
1021 		//LogMsg("SetupOneInterface: %#a %#a",  &intf->coreIntf.ip,  &intf->coreIntf.mask);
1022 		strncpy(intf->coreIntf.ifname, intfName, sizeof(intf->coreIntf.ifname));
1023 		intf->coreIntf.ifname[sizeof(intf->coreIntf.ifname)-1] = 0;
1024 		intf->coreIntf.Advertise = m->AdvertiseLocalAddresses;
1025 		intf->coreIntf.McastTxRx = mDNStrue;
1026 
1027 		// Set up the extra fields in PosixNetworkInterface.
1028 		assert(intf->intfName != NULL);         // intf->intfName already set up above
1029 		intf->index                = intfIndex;
1030 		intf->multicastSocket4     = -1;
1031 #if HAVE_IPV6
1032 		intf->multicastSocket6     = -1;
1033 #endif
1034 		alias                      = SearchForInterfaceByName(m, intf->intfName);
1035 		if (alias == NULL) alias   = intf;
1036 		intf->coreIntf.InterfaceID = (mDNSInterfaceID)alias;
1037 
1038 		if (alias != intf)
1039 			debugf("SetupOneInterface: %s %#a is an alias of %#a", intfName, &intf->coreIntf.ip, &alias->coreIntf.ip);
1040 		}
1041 
1042 	// Set up the multicast socket
1043 	if (err == 0)
1044 		{
1045 		if (alias->multicastSocket4 == -1 && intfAddr->sa_family == AF_INET)
1046 			err = SetupSocket(intfAddr, MulticastDNSPort, intf->index, &alias->multicastSocket4);
1047 #if HAVE_IPV6
1048 		else if (alias->multicastSocket6 == -1 && intfAddr->sa_family == AF_INET6)
1049 			err = SetupSocket(intfAddr, MulticastDNSPort, intf->index, &alias->multicastSocket6);
1050 #endif
1051 		}
1052 
1053 	// The interface is all ready to go, let's register it with the mDNS core.
1054 	if (err == 0)
1055 		err = mDNS_RegisterInterface(m, &intf->coreIntf, mDNSfalse);
1056 
1057 	// Clean up.
1058 	if (err == 0)
1059 		{
1060 		num_registered_interfaces++;
1061 		debugf("SetupOneInterface: %s %#a Registered", intf->intfName, &intf->coreIntf.ip);
1062 		if (gMDNSPlatformPosixVerboseLevel > 0)
1063 			fprintf(stderr, "Registered interface %s\n", intf->intfName);
1064 		}
1065 	else
1066 		{
1067 		// Use intfName instead of intf->intfName in the next line to avoid dereferencing NULL.
1068 		debugf("SetupOneInterface: %s %#a failed to register %d", intfName, &intf->coreIntf.ip, err);
1069 		if (intf) { FreePosixNetworkInterface(intf); intf = NULL; }
1070 		}
1071 
1072 	assert( (err == 0) == (intf != NULL) );
1073 
1074 	return err;
1075 	}
1076 
1077 // Call get_ifi_info() to obtain a list of active interfaces and call SetupOneInterface() on each one.
1078 mDNSlocal int SetupInterfaceList(mDNS *const m)
1079 	{
1080 	mDNSBool        foundav4       = mDNSfalse;
1081 	int             err            = 0;
1082 	struct ifi_info *intfList      = get_ifi_info(AF_INET, mDNStrue);
1083 	struct ifi_info *firstLoopback = NULL;
1084 
1085 	assert(m != NULL);
1086 	debugf("SetupInterfaceList");
1087 
1088 	if (intfList == NULL) err = ENOENT;
1089 
1090 #if HAVE_IPV6
1091 	if (err == 0)		/* Link the IPv6 list to the end of the IPv4 list */
1092 		{
1093 		struct ifi_info **p = &intfList;
1094 		while (*p) p = &(*p)->ifi_next;
1095 		*p = get_ifi_info(AF_INET6, mDNStrue);
1096 		}
1097 #endif
1098 
1099 	if (err == 0)
1100 		{
1101 		struct ifi_info *i = intfList;
1102 		while (i)
1103 			{
1104 			if (     ((i->ifi_addr->sa_family == AF_INET)
1105 #if HAVE_IPV6
1106 					  || (i->ifi_addr->sa_family == AF_INET6)
1107 #endif
1108 				) &&  (i->ifi_flags & IFF_UP) && !(i->ifi_flags & IFF_POINTOPOINT) )
1109 				{
1110 				if (i->ifi_flags & IFF_LOOPBACK)
1111 					{
1112 					if (firstLoopback == NULL)
1113 						firstLoopback = i;
1114 					}
1115 				else
1116 					{
1117 					if (SetupOneInterface(m, i->ifi_addr, i->ifi_netmask, i->ifi_name, i->ifi_index) == 0)
1118 						if (i->ifi_addr->sa_family == AF_INET)
1119 							foundav4 = mDNStrue;
1120 					}
1121 				}
1122 			i = i->ifi_next;
1123 			}
1124 
1125 		// If we found no normal interfaces but we did find a loopback interface, register the
1126 		// loopback interface.  This allows self-discovery if no interfaces are configured.
1127 		// Temporary workaround: Multicast loopback on IPv6 interfaces appears not to work.
1128 		// In the interim, we skip loopback interface only if we found at least one v4 interface to use
1129 		// if ( (m->HostInterfaces == NULL) && (firstLoopback != NULL) )
1130 		if ( !foundav4 && firstLoopback )
1131 			(void) SetupOneInterface(m, firstLoopback->ifi_addr, firstLoopback->ifi_netmask, firstLoopback->ifi_name, firstLoopback->ifi_index);
1132 		}
1133 
1134 	// Clean up.
1135 	if (intfList != NULL) free_ifi_info(intfList);
1136 	return err;
1137 	}
1138 
1139 #if USES_NETLINK
1140 
1141 // See <http://www.faqs.org/rfcs/rfc3549.html> for a description of NetLink
1142 
1143 // Open a socket that will receive interface change notifications
1144 mDNSlocal mStatus OpenIfNotifySocket( int *pFD)
1145 	{
1146 	mStatus					err = mStatus_NoError;
1147 	struct sockaddr_nl		snl;
1148 	int sock;
1149 	int ret;
1150 
1151 	sock = socket( AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
1152 	if (sock < 0)
1153 		return errno;
1154 
1155 	// Configure read to be non-blocking because inbound msg size is not known in advance
1156 	(void) fcntl( sock, F_SETFL, O_NONBLOCK);
1157 
1158 	/* Subscribe the socket to Link & IP addr notifications. */
1159 	bzero( &snl, sizeof snl);
1160 	snl.nl_family = AF_NETLINK;
1161 	snl.nl_groups = RTMGRP_LINK | RTMGRP_IPV4_IFADDR;
1162 	ret = bind( sock, (struct sockaddr *) &snl, sizeof snl);
1163 	if ( 0 == ret)
1164 		*pFD = sock;
1165 	else
1166 		err = errno;
1167 
1168 	return err;
1169 	}
1170 
1171 #if MDNS_DEBUGMSGS
1172 mDNSlocal void		PrintNetLinkMsg( const struct nlmsghdr *pNLMsg)
1173 	{
1174 	const char *kNLMsgTypes[] = { "", "NLMSG_NOOP", "NLMSG_ERROR", "NLMSG_DONE", "NLMSG_OVERRUN" };
1175 	const char *kNLRtMsgTypes[] = { "RTM_NEWLINK", "RTM_DELLINK", "RTM_GETLINK", "RTM_NEWADDR", "RTM_DELADDR", "RTM_GETADDR" };
1176 
1177 	printf( "nlmsghdr len=%d, type=%s, flags=0x%x\n", pNLMsg->nlmsg_len,
1178 			pNLMsg->nlmsg_type < RTM_BASE ? kNLMsgTypes[ pNLMsg->nlmsg_type] : kNLRtMsgTypes[ pNLMsg->nlmsg_type - RTM_BASE],
1179 			pNLMsg->nlmsg_flags);
1180 
1181 	if ( RTM_NEWLINK <= pNLMsg->nlmsg_type && pNLMsg->nlmsg_type <= RTM_GETLINK)
1182 		{
1183 		struct ifinfomsg	*pIfInfo = (struct ifinfomsg*) NLMSG_DATA( pNLMsg);
1184 		printf( "ifinfomsg family=%d, type=%d, index=%d, flags=0x%x, change=0x%x\n", pIfInfo->ifi_family,
1185 				pIfInfo->ifi_type, pIfInfo->ifi_index, pIfInfo->ifi_flags, pIfInfo->ifi_change);
1186 
1187 		}
1188 	else if ( RTM_NEWADDR <= pNLMsg->nlmsg_type && pNLMsg->nlmsg_type <= RTM_GETADDR)
1189 		{
1190 		struct ifaddrmsg	*pIfAddr = (struct ifaddrmsg*) NLMSG_DATA( pNLMsg);
1191 		printf( "ifaddrmsg family=%d, index=%d, flags=0x%x\n", pIfAddr->ifa_family,
1192 				pIfAddr->ifa_index, pIfAddr->ifa_flags);
1193 		}
1194 	printf( "\n");
1195 	}
1196 #endif
1197 
1198 mDNSlocal mDNSu32		ProcessRoutingNotification( int sd)
1199 // Read through the messages on sd and if any indicate that any interface records should
1200 // be torn down and rebuilt, return affected indices as a bitmask. Otherwise return 0.
1201 	{
1202 	ssize_t					readCount;
1203 	char					buff[ 4096];
1204 	struct nlmsghdr			*pNLMsg = (struct nlmsghdr*) buff;
1205 	mDNSu32				result = 0;
1206 
1207 	// The structure here is more complex than it really ought to be because,
1208 	// unfortunately, there's no good way to size a buffer in advance large
1209 	// enough to hold all pending data and so avoid message fragmentation.
1210 	// (Note that FIONREAD is not supported on AF_NETLINK.)
1211 
1212 	readCount = read( sd, buff, sizeof buff);
1213 	while ( 1)
1214 		{
1215 		// Make sure we've got an entire nlmsghdr in the buffer, and payload, too.
1216 		// If not, discard already-processed messages in buffer and read more data.
1217 		if ( ( (char*) &pNLMsg[1] > ( buff + readCount)) ||	// i.e. *pNLMsg extends off end of buffer
1218 			 ( (char*) pNLMsg + pNLMsg->nlmsg_len > ( buff + readCount)))
1219 			{
1220 			if ( buff < (char*) pNLMsg)		// we have space to shuffle
1221 				{
1222 				// discard processed data
1223 				readCount -= ( (char*) pNLMsg - buff);
1224 				memmove( buff, pNLMsg, readCount);
1225 				pNLMsg = (struct nlmsghdr*) buff;
1226 
1227 				// read more data
1228 				readCount += read( sd, buff + readCount, sizeof buff - readCount);
1229 				continue;					// spin around and revalidate with new readCount
1230 				}
1231 			else
1232 				break;	// Otherwise message does not fit in buffer
1233 			}
1234 
1235 #if MDNS_DEBUGMSGS
1236 		PrintNetLinkMsg( pNLMsg);
1237 #endif
1238 
1239 		// Process the NetLink message
1240 		if ( pNLMsg->nlmsg_type == RTM_GETLINK || pNLMsg->nlmsg_type == RTM_NEWLINK)
1241 			result |= 1 << ((struct ifinfomsg*) NLMSG_DATA( pNLMsg))->ifi_index;
1242 		else if ( pNLMsg->nlmsg_type == RTM_DELADDR || pNLMsg->nlmsg_type == RTM_NEWADDR)
1243 			result |= 1 << ((struct ifaddrmsg*) NLMSG_DATA( pNLMsg))->ifa_index;
1244 
1245 		// Advance pNLMsg to the next message in the buffer
1246 		if ( ( pNLMsg->nlmsg_flags & NLM_F_MULTI) != 0 && pNLMsg->nlmsg_type != NLMSG_DONE)
1247 			{
1248 			ssize_t	len = readCount - ( (char*)pNLMsg - buff);
1249 			pNLMsg = NLMSG_NEXT( pNLMsg, len);
1250 			}
1251 		else
1252 			break;	// all done!
1253 		}
1254 
1255 	return result;
1256 	}
1257 
1258 #else // USES_NETLINK
1259 
1260 // Open a socket that will receive interface change notifications
1261 mDNSlocal mStatus OpenIfNotifySocket( int *pFD)
1262 	{
1263 	*pFD = socket( AF_ROUTE, SOCK_RAW, 0);
1264 
1265 	if ( *pFD < 0)
1266 		return mStatus_UnknownErr;
1267 
1268 	// Configure read to be non-blocking because inbound msg size is not known in advance
1269 	(void) fcntl( *pFD, F_SETFL, O_NONBLOCK);
1270 
1271 	return mStatus_NoError;
1272 	}
1273 
1274 #if MDNS_DEBUGMSGS
1275 mDNSlocal void		PrintRoutingSocketMsg( const struct ifa_msghdr *pRSMsg)
1276 	{
1277 	const char *kRSMsgTypes[] = { "", "RTM_ADD", "RTM_DELETE", "RTM_CHANGE", "RTM_GET", "RTM_LOSING",
1278 					"RTM_REDIRECT", "RTM_MISS", "RTM_LOCK", "RTM_OLDADD", "RTM_OLDDEL", "RTM_RESOLVE",
1279 					"RTM_NEWADDR", "RTM_DELADDR", "RTM_IFINFO", "RTM_NEWMADDR", "RTM_DELMADDR" };
1280 
1281 	int		index = pRSMsg->ifam_type == RTM_IFINFO ? ((struct if_msghdr*) pRSMsg)->ifm_index : pRSMsg->ifam_index;
1282 
1283 	printf( "ifa_msghdr len=%d, type=%s, index=%d\n", pRSMsg->ifam_msglen, kRSMsgTypes[ pRSMsg->ifam_type], index);
1284 	}
1285 #endif
1286 
1287 mDNSlocal mDNSu32		ProcessRoutingNotification( int sd)
1288 // Read through the messages on sd and if any indicate that any interface records should
1289 // be torn down and rebuilt, return affected indices as a bitmask. Otherwise return 0.
1290 	{
1291 	ssize_t					readCount;
1292 	char					buff[ 4096];
1293 	struct ifa_msghdr		*pRSMsg = (struct ifa_msghdr*) buff;
1294 	mDNSu32				result = 0;
1295 
1296 	readCount = read( sd, buff, sizeof buff);
1297 	if ( readCount < (ssize_t) sizeof( struct ifa_msghdr))
1298 		return mStatus_UnsupportedErr;		// cannot decipher message
1299 
1300 #if MDNS_DEBUGMSGS
1301 	PrintRoutingSocketMsg( pRSMsg);
1302 #endif
1303 
1304 	// Process the message
1305 	if ( pRSMsg->ifam_type == RTM_NEWADDR || pRSMsg->ifam_type == RTM_DELADDR ||
1306 		 pRSMsg->ifam_type == RTM_IFINFO)
1307 		{
1308 		if ( pRSMsg->ifam_type == RTM_IFINFO)
1309 			result |= 1 << ((struct if_msghdr*) pRSMsg)->ifm_index;
1310 		else
1311 			result |= 1 << pRSMsg->ifam_index;
1312 		}
1313 
1314 	return result;
1315 	}
1316 
1317 #endif // USES_NETLINK
1318 
1319 // Called when data appears on interface change notification socket
1320 mDNSlocal void InterfaceChangeCallback( void *context)
1321 	{
1322 	IfChangeRec		*pChgRec = (IfChangeRec*) context;
1323 	fd_set			readFDs;
1324 	mDNSu32		changedInterfaces = 0;
1325 	struct timeval	zeroTimeout = { 0, 0 };
1326 
1327 	FD_ZERO( &readFDs);
1328 	FD_SET( pChgRec->NotifySD, &readFDs);
1329 
1330 	do
1331 	{
1332 		changedInterfaces |= ProcessRoutingNotification( pChgRec->NotifySD);
1333 	}
1334 	while ( 0 < select( pChgRec->NotifySD + 1, &readFDs, (fd_set*) NULL, (fd_set*) NULL, &zeroTimeout));
1335 
1336 	// Currently we rebuild the entire interface list whenever any interface change is
1337 	// detected. If this ever proves to be a performance issue in a multi-homed
1338 	// configuration, more care should be paid to changedInterfaces.
1339 	if ( changedInterfaces)
1340 		mDNSPlatformPosixRefreshInterfaceList( pChgRec->mDNS);
1341 	}
1342 
1343 // Register with either a Routing Socket or RtNetLink to listen for interface changes.
1344 mDNSlocal mStatus WatchForInterfaceChange(mDNS *const m)
1345 	{
1346 	mStatus		err;
1347 	IfChangeRec	*pChgRec;
1348 
1349 	pChgRec = (IfChangeRec*) mDNSPlatformMemAllocate( sizeof *pChgRec);
1350 	if ( pChgRec == NULL)
1351 		return mStatus_NoMemoryErr;
1352 
1353 	pChgRec->mDNS = m;
1354 	err = OpenIfNotifySocket( &pChgRec->NotifySD);
1355 	if ( err == 0)
1356 		err = mDNSPosixAddFDToEventLoop( pChgRec->NotifySD, InterfaceChangeCallback, pChgRec);
1357 
1358 	return err;
1359 	}
1360 
1361 // Test to see if we're the first client running on UDP port 5353, by trying to bind to 5353 without using SO_REUSEPORT.
1362 // If we fail, someone else got here first. That's not a big problem; we can share the port for multicast responses --
1363 // we just need to be aware that we shouldn't expect to successfully receive unicast UDP responses.
1364 mDNSlocal mDNSBool mDNSPlatformInit_CanReceiveUnicast(void)
1365 	{
1366 	int err;
1367 	int s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
1368 	struct sockaddr_in s5353;
1369 	s5353.sin_family      = AF_INET;
1370 	s5353.sin_port        = MulticastDNSPort.NotAnInteger;
1371 	s5353.sin_addr.s_addr = 0;
1372 	err = bind(s, (struct sockaddr *)&s5353, sizeof(s5353));
1373 	close(s);
1374 	if (err) debugf("No unicast UDP responses");
1375 	else     debugf("Unicast UDP responses okay");
1376 	return(err == 0);
1377 	}
1378 
1379 // mDNS core calls this routine to initialise the platform-specific data.
1380 mDNSexport mStatus mDNSPlatformInit(mDNS *const m)
1381 	{
1382 	int err = 0;
1383 	struct sockaddr sa;
1384 	assert(m != NULL);
1385 
1386 	if (mDNSPlatformInit_CanReceiveUnicast()) m->CanReceiveUnicastOn5353 = mDNStrue;
1387 
1388 	// Tell mDNS core the names of this machine.
1389 
1390 	// Set up the nice label
1391 	m->nicelabel.c[0] = 0;
1392 	GetUserSpecifiedFriendlyComputerName(&m->nicelabel);
1393 	if (m->nicelabel.c[0] == 0) MakeDomainLabelFromLiteralString(&m->nicelabel, "Computer");
1394 
1395 	// Set up the RFC 1034-compliant label
1396 	m->hostlabel.c[0] = 0;
1397 	GetUserSpecifiedRFC1034ComputerName(&m->hostlabel);
1398 	if (m->hostlabel.c[0] == 0) MakeDomainLabelFromLiteralString(&m->hostlabel, "Computer");
1399 
1400 	mDNS_SetFQDN(m);
1401 
1402 	sa.sa_family = AF_INET;
1403 	m->p->unicastSocket4 = -1;
1404 	if (err == mStatus_NoError) err = SetupSocket(&sa, zeroIPPort, 0, &m->p->unicastSocket4);
1405 #if HAVE_IPV6
1406 	sa.sa_family = AF_INET6;
1407 	m->p->unicastSocket6 = -1;
1408 	if (err == mStatus_NoError) err = SetupSocket(&sa, zeroIPPort, 0, &m->p->unicastSocket6);
1409 #endif
1410 
1411 	// Tell mDNS core about the network interfaces on this machine.
1412 	if (err == mStatus_NoError) err = SetupInterfaceList(m);
1413 
1414 	// Tell mDNS core about DNS Servers
1415 	if (err == mStatus_NoError) ParseDNSServers(m, uDNS_SERVERS_FILE);
1416 
1417 	if (err == mStatus_NoError)
1418 		{
1419 		err = WatchForInterfaceChange(m);
1420 		// Failure to observe interface changes is non-fatal.
1421 		if ( err != mStatus_NoError)
1422 			{
1423 			fprintf(stderr, "mDNS(%d) WARNING: Unable to detect interface changes (%d).\n", getpid(), err);
1424 			err = mStatus_NoError;
1425 			}
1426 		}
1427 
1428 	// We don't do asynchronous initialization on the Posix platform, so by the time
1429 	// we get here the setup will already have succeeded or failed.  If it succeeded,
1430 	// we should just call mDNSCoreInitComplete() immediately.
1431 	if (err == mStatus_NoError)
1432 		mDNSCoreInitComplete(m, mStatus_NoError);
1433 
1434 	return PosixErrorToStatus(err);
1435 	}
1436 
1437 // mDNS core calls this routine to clean up the platform-specific data.
1438 // In our case all we need to do is to tear down every network interface.
1439 mDNSexport void mDNSPlatformClose(mDNS *const m)
1440 	{
1441 	assert(m != NULL);
1442 	ClearInterfaceList(m);
1443 	if (m->p->unicastSocket4 != -1) assert(close(m->p->unicastSocket4) == 0);
1444 #if HAVE_IPV6
1445 	if (m->p->unicastSocket6 != -1) assert(close(m->p->unicastSocket6) == 0);
1446 #endif
1447 	}
1448 
1449 mDNSexport mStatus mDNSPlatformPosixRefreshInterfaceList(mDNS *const m)
1450 	{
1451 	int err;
1452 	ClearInterfaceList(m);
1453 	err = SetupInterfaceList(m);
1454 	return PosixErrorToStatus(err);
1455 	}
1456 
1457 #if COMPILER_LIKES_PRAGMA_MARK
1458 #pragma mark ***** Locking
1459 #endif
1460 
1461 // On the Posix platform, locking is a no-op because we only ever enter
1462 // mDNS core on the main thread.
1463 
1464 // mDNS core calls this routine when it wants to prevent
1465 // the platform from reentering mDNS core code.
1466 mDNSexport void    mDNSPlatformLock   (const mDNS *const m)
1467 	{
1468 	(void) m;	// Unused
1469 	}
1470 
1471 // mDNS core calls this routine when it release the lock taken by
1472 // mDNSPlatformLock and allow the platform to reenter mDNS core code.
1473 mDNSexport void    mDNSPlatformUnlock (const mDNS *const m)
1474 	{
1475 	(void) m;	// Unused
1476 	}
1477 
1478 #if COMPILER_LIKES_PRAGMA_MARK
1479 #pragma mark ***** Strings
1480 #endif
1481 
1482 // mDNS core calls this routine to copy C strings.
1483 // On the Posix platform this maps directly to the ANSI C strcpy.
1484 mDNSexport void    mDNSPlatformStrCopy(const void *src,       void *dst)
1485 	{
1486 	strcpy((char *)dst, (char *)src);
1487 	}
1488 
1489 // mDNS core calls this routine to get the length of a C string.
1490 // On the Posix platform this maps directly to the ANSI C strlen.
1491 mDNSexport mDNSu32  mDNSPlatformStrLen (const void *src)
1492 	{
1493 	return strlen((char*)src);
1494 	}
1495 
1496 // mDNS core calls this routine to copy memory.
1497 // On the Posix platform this maps directly to the ANSI C memcpy.
1498 mDNSexport void    mDNSPlatformMemCopy(const void *src,       void *dst, mDNSu32 len)
1499 	{
1500 	memcpy(dst, src, len);
1501 	}
1502 
1503 // mDNS core calls this routine to test whether blocks of memory are byte-for-byte
1504 // identical. On the Posix platform this is a simple wrapper around ANSI C memcmp.
1505 mDNSexport mDNSBool mDNSPlatformMemSame(const void *src, const void *dst, mDNSu32 len)
1506 	{
1507 	return memcmp(dst, src, len) == 0;
1508 	}
1509 
1510 // mDNS core calls this routine to clear blocks of memory.
1511 // On the Posix platform this is a simple wrapper around ANSI C memset.
1512 mDNSexport void    mDNSPlatformMemZero(                       void *dst, mDNSu32 len)
1513 	{
1514 	memset(dst, 0, len);
1515 	}
1516 
1517 mDNSexport void *  mDNSPlatformMemAllocate(mDNSu32 len) { return(malloc(len)); }
1518 mDNSexport void    mDNSPlatformMemFree    (void *mem)   { free(mem); }
1519 
1520 mDNSexport mDNSu32 mDNSPlatformRandomSeed(void)
1521 	{
1522 	struct timeval tv;
1523 	gettimeofday(&tv, NULL);
1524 	return(tv.tv_usec);
1525 	}
1526 
1527 mDNSexport mDNSs32  mDNSPlatformOneSecond = 1024;
1528 
1529 mDNSexport mStatus mDNSPlatformTimeInit(void)
1530 	{
1531 	// No special setup is required on Posix -- we just use gettimeofday();
1532 	// This is not really safe, because gettimeofday can go backwards if the user manually changes the date or time
1533 	// We should find a better way to do this
1534 	return(mStatus_NoError);
1535 	}
1536 
1537 mDNSexport mDNSs32  mDNSPlatformRawTime()
1538 	{
1539 	struct timeval tv;
1540 	gettimeofday(&tv, NULL);
1541 	// tv.tv_sec is seconds since 1st January 1970 (GMT, with no adjustment for daylight savings time)
1542 	// tv.tv_usec is microseconds since the start of this second (i.e. values 0 to 999999)
1543 	// We use the lower 22 bits of tv.tv_sec for the top 22 bits of our result
1544 	// 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.
1545 	// This gives us a proper modular (cyclic) counter that has a resolution of roughly 1ms (actually 1/1024 second)
1546 	// and correctly cycles every 2^22 seconds (4194304 seconds = approx 48 days).
1547 	return( (tv.tv_sec << 10) | (tv.tv_usec * 16 / 15625) );
1548 	}
1549 
1550 mDNSexport mDNSs32 mDNSPlatformUTC(void)
1551 	{
1552 	return time(NULL);
1553 	}
1554 
1555 mDNSlocal void mDNSPosixAddToFDSet(int *nfds, fd_set *readfds, int s)
1556 	{
1557 	if (*nfds < s + 1) *nfds = s + 1;
1558 	FD_SET(s, readfds);
1559 	}
1560 
1561 mDNSexport void mDNSPosixGetFDSet(mDNS *m, int *nfds, fd_set *readfds, struct timeval *timeout)
1562 	{
1563 	mDNSs32 ticks;
1564 	struct timeval interval;
1565 
1566 	// 1. Call mDNS_Execute() to let mDNSCore do what it needs to do
1567 	mDNSs32 nextevent = mDNS_Execute(m);
1568 
1569 	// 2. Build our list of active file descriptors
1570 	PosixNetworkInterface *info = (PosixNetworkInterface *)(m->HostInterfaces);
1571 	if (m->p->unicastSocket4 != -1) mDNSPosixAddToFDSet(nfds, readfds, m->p->unicastSocket4);
1572 #if HAVE_IPV6
1573 	if (m->p->unicastSocket6 != -1) mDNSPosixAddToFDSet(nfds, readfds, m->p->unicastSocket6);
1574 #endif
1575 	while (info)
1576 		{
1577 		if (info->multicastSocket4 != -1) mDNSPosixAddToFDSet(nfds, readfds, info->multicastSocket4);
1578 #if HAVE_IPV6
1579 		if (info->multicastSocket6 != -1) mDNSPosixAddToFDSet(nfds, readfds, info->multicastSocket6);
1580 #endif
1581 		info = (PosixNetworkInterface *)(info->coreIntf.next);
1582 		}
1583 
1584 	// 3. Calculate the time remaining to the next scheduled event (in struct timeval format)
1585 	ticks = nextevent - mDNS_TimeNow(m);
1586 	if (ticks < 1) ticks = 1;
1587 	interval.tv_sec  = ticks >> 10;						// The high 22 bits are seconds
1588 	interval.tv_usec = ((ticks & 0x3FF) * 15625) / 16;	// The low 10 bits are 1024ths
1589 
1590 	// 4. If client's proposed timeout is more than what we want, then reduce it
1591 	if (timeout->tv_sec > interval.tv_sec ||
1592 		(timeout->tv_sec == interval.tv_sec && timeout->tv_usec > interval.tv_usec))
1593 		*timeout = interval;
1594 	}
1595 
1596 mDNSexport void mDNSPosixProcessFDSet(mDNS *const m, fd_set *readfds)
1597 	{
1598 	PosixNetworkInterface *info;
1599 	assert(m       != NULL);
1600 	assert(readfds != NULL);
1601 	info = (PosixNetworkInterface *)(m->HostInterfaces);
1602 
1603 	if (m->p->unicastSocket4 != -1 && FD_ISSET(m->p->unicastSocket4, readfds))
1604 		{
1605 		FD_CLR(m->p->unicastSocket4, readfds);
1606 		SocketDataReady(m, NULL, m->p->unicastSocket4);
1607 		}
1608 #if HAVE_IPV6
1609 	if (m->p->unicastSocket6 != -1 && FD_ISSET(m->p->unicastSocket6, readfds))
1610 		{
1611 		FD_CLR(m->p->unicastSocket6, readfds);
1612 		SocketDataReady(m, NULL, m->p->unicastSocket6);
1613 		}
1614 #endif
1615 
1616 	while (info)
1617 		{
1618 		if (info->multicastSocket4 != -1 && FD_ISSET(info->multicastSocket4, readfds))
1619 			{
1620 			FD_CLR(info->multicastSocket4, readfds);
1621 			SocketDataReady(m, info, info->multicastSocket4);
1622 			}
1623 #if HAVE_IPV6
1624 		if (info->multicastSocket6 != -1 && FD_ISSET(info->multicastSocket6, readfds))
1625 			{
1626 			FD_CLR(info->multicastSocket6, readfds);
1627 			SocketDataReady(m, info, info->multicastSocket6);
1628 			}
1629 #endif
1630 		info = (PosixNetworkInterface *)(info->coreIntf.next);
1631 		}
1632 	}
1633 
1634 // update gMaxFD
1635 mDNSlocal void	DetermineMaxEventFD( void )
1636 	{
1637 	PosixEventSource	*iSource;
1638 
1639 	gMaxFD = 0;
1640 	for ( iSource=(PosixEventSource*)gEventSources.Head; iSource; iSource = iSource->Next)
1641 		if ( gMaxFD < iSource->fd)
1642 			gMaxFD = iSource->fd;
1643 	}
1644 
1645 // Add a file descriptor to the set that mDNSPosixRunEventLoopOnce() listens to.
1646 mStatus mDNSPosixAddFDToEventLoop( int fd, mDNSPosixEventCallback callback, void *context)
1647 	{
1648 	PosixEventSource	*newSource;
1649 
1650 	if ( gEventSources.LinkOffset == 0)
1651 		InitLinkedList( &gEventSources, offsetof( PosixEventSource, Next));
1652 
1653 	if ( fd >= (int) FD_SETSIZE || fd < 0)
1654 		return mStatus_UnsupportedErr;
1655 	if ( callback == NULL)
1656 		return mStatus_BadParamErr;
1657 
1658 	newSource = (PosixEventSource*) malloc( sizeof *newSource);
1659 	if ( NULL == newSource)
1660 		return mStatus_NoMemoryErr;
1661 
1662 	newSource->Callback = callback;
1663 	newSource->Context = context;
1664 	newSource->fd = fd;
1665 
1666 	AddToTail( &gEventSources, newSource);
1667 	FD_SET( fd, &gEventFDs);
1668 
1669 	DetermineMaxEventFD();
1670 
1671 	return mStatus_NoError;
1672 	}
1673 
1674 // Remove a file descriptor from the set that mDNSPosixRunEventLoopOnce() listens to.
1675 mStatus mDNSPosixRemoveFDFromEventLoop( int fd)
1676 	{
1677 	PosixEventSource	*iSource;
1678 
1679 	for ( iSource=(PosixEventSource*)gEventSources.Head; iSource; iSource = iSource->Next)
1680 		{
1681 		if ( fd == iSource->fd)
1682 			{
1683 			FD_CLR( fd, &gEventFDs);
1684 			RemoveFromList( &gEventSources, iSource);
1685 			free( iSource);
1686 			DetermineMaxEventFD();
1687 			return mStatus_NoError;
1688 			}
1689 		}
1690 	return mStatus_NoSuchNameErr;
1691 	}
1692 
1693 // Simply note the received signal in gEventSignals.
1694 mDNSlocal void	NoteSignal( int signum)
1695 	{
1696 	sigaddset( &gEventSignals, signum);
1697 	}
1698 
1699 // Tell the event package to listen for signal and report it in mDNSPosixRunEventLoopOnce().
1700 mStatus mDNSPosixListenForSignalInEventLoop( int signum)
1701 	{
1702 	struct sigaction	action;
1703 	mStatus				err;
1704 
1705 	bzero( &action, sizeof action);		// more portable than member-wise assignment
1706 	action.sa_handler = NoteSignal;
1707 	err = sigaction( signum, &action, (struct sigaction*) NULL);
1708 
1709 	sigaddset( &gEventSignalSet, signum);
1710 
1711 	return err;
1712 	}
1713 
1714 // Tell the event package to stop listening for signal in mDNSPosixRunEventLoopOnce().
1715 mStatus mDNSPosixIgnoreSignalInEventLoop( int signum)
1716 	{
1717 	struct sigaction	action;
1718 	mStatus				err;
1719 
1720 	bzero( &action, sizeof action);		// more portable than member-wise assignment
1721 	action.sa_handler = SIG_DFL;
1722 	err = sigaction( signum, &action, (struct sigaction*) NULL);
1723 
1724 	sigdelset( &gEventSignalSet, signum);
1725 
1726 	return err;
1727 	}
1728 
1729 // Do a single pass through the attendent event sources and dispatch any found to their callbacks.
1730 // Return as soon as internal timeout expires, or a signal we're listening for is received.
1731 mStatus mDNSPosixRunEventLoopOnce( mDNS *m, const struct timeval *pTimeout,
1732 									sigset_t *pSignalsReceived, mDNSBool *pDataDispatched)
1733 	{
1734 	fd_set			listenFDs = gEventFDs;
1735 	int				fdMax = 0, numReady;
1736 	struct timeval	timeout = *pTimeout;
1737 
1738 	// Include the sockets that are listening to the wire in our select() set
1739 	mDNSPosixGetFDSet( m, &fdMax, &listenFDs, &timeout);	// timeout may get modified
1740 	if ( fdMax < gMaxFD)
1741 		fdMax = gMaxFD;
1742 
1743 	numReady = select( fdMax + 1, &listenFDs, (fd_set*) NULL, (fd_set*) NULL, &timeout);
1744 
1745 	// If any data appeared, invoke its callback
1746 	if ( numReady > 0)
1747 		{
1748 		PosixEventSource	*iSource;
1749 
1750 		(void) mDNSPosixProcessFDSet( m, &listenFDs);	// call this first to process wire data for clients
1751 
1752 		for ( iSource=(PosixEventSource*)gEventSources.Head; iSource; iSource = iSource->Next)
1753 			{
1754 			if ( FD_ISSET( iSource->fd, &listenFDs))
1755 				{
1756 				iSource->Callback( iSource->Context);
1757 				break;	// in case callback removed elements from gEventSources
1758 				}
1759 			}
1760 		*pDataDispatched = mDNStrue;
1761 		}
1762 	else
1763 		*pDataDispatched = mDNSfalse;
1764 
1765 	(void) sigprocmask( SIG_BLOCK, &gEventSignalSet, (sigset_t*) NULL);
1766 	*pSignalsReceived = gEventSignals;
1767 	sigemptyset( &gEventSignals);
1768 	(void) sigprocmask( SIG_UNBLOCK, &gEventSignalSet, (sigset_t*) NULL);
1769 
1770 	return mStatus_NoError;
1771 	}
1772