2 * Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
23 * @APPLE_LICENSE_HEADER_END@
25 Change History (most recent first):
28 Revision 1.115 2003/09/10 00:45:55 cheshire
29 <rdar://problem/3412328> Don't log "sendto failed" errors during the first two minutes of startup
31 Revision 1.114 2003/08/27 02:55:13 cheshire
32 <rdar://problem/3387910>: Bug: Don't report mDNSPlatformSendUDP sendto errno 64 (Host is down)
34 Revision 1.113 2003/08/19 22:20:00 cheshire
35 <rdar://problem/3376721> Don't use IPv6 on interfaces that have a routable IPv4 address configured
36 More minor refinements
38 Revision 1.112 2003/08/19 03:04:43 cheshire
39 <rdar://problem/3376721> Don't use IPv6 on interfaces that have a routable IPv4 address configured
41 Revision 1.111 2003/08/18 22:53:37 cheshire
42 <rdar://problem/3382647> mDNSResponder divide by zero in mDNSPlatformTimeNow()
44 Revision 1.110 2003/08/16 03:39:00 cheshire
45 <rdar://problem/3338440> InterfaceID -1 indicates "local only"
47 Revision 1.109 2003/08/15 02:19:49 cheshire
48 <rdar://problem/3375225> syslog messages: myCFSocketCallBack recvfrom skt 6 error -1 errno 35
49 Also limit number of messages to at most 100
51 Revision 1.108 2003/08/12 22:24:52 cheshire
52 <rdar://problem/3375225> syslog messages: myCFSocketCallBack recvfrom skt 6 error -1 errno 35
53 This message indicates a kernel bug, but still we don't want to flood syslog.
54 Do a sleep(1) after writing this log message, to limit the rate.
56 Revision 1.107 2003/08/12 19:56:25 cheshire
59 Revision 1.106 2003/08/12 13:48:32 cheshire
60 Add comment explaining clockdivisor calculation
62 Revision 1.105 2003/08/12 13:44:14 cheshire
63 <rdar://problem/3370229> mDNSResponder *VERY* unhappy if time goes backwards
64 Use mach_absolute_time() (which is guaranteed to always go forwards, resetting only on reboot)
65 instead of gettimeofday() (which can jump back if the user manually changes their time/date)
67 Revision 1.104 2003/08/12 13:12:07 cheshire
68 Textual search/replace: Indicate local functions using "mDNSlocal" instead of "static"
70 Revision 1.103 2003/08/08 18:36:04 cheshire
71 <rdar://problem/3344154> Only need to revalidate on interface removal on platforms that have the PhantomInterfaces bug
73 Revision 1.102 2003/08/06 00:14:52 cheshire
74 <rdar://problem/3330324> Need to check IP TTL on responses
75 Also add corresponding checks in the IPv6 code path
77 Revision 1.101 2003/08/05 22:20:16 cheshire
78 <rdar://problem/3330324> Need to check IP TTL on responses
80 Revision 1.100 2003/08/05 21:18:50 cheshire
81 <rdar://problem/3363185> mDNSResponder should ignore 6to4
82 Only use interfaces that are marked as multicast-capable (IFF_MULTICAST)
84 Revision 1.99 2003/08/05 20:13:52 cheshire
85 <rdar://problem/3294080> mDNSResponder using IPv6 interfaces before they are ready
86 Ignore interfaces with the IN6_IFF_NOTREADY flag set
88 Revision 1.98 2003/07/20 03:38:51 ksekar
90 Completed support for Unix-domain socket based API.
92 Revision 1.97 2003/07/19 03:15:16 cheshire
93 Add generic MemAllocate/MemFree prototypes to mDNSPlatformFunctions.h,
94 and add the obvious trivial implementations to each platform support layer
96 Revision 1.96 2003/07/18 00:30:00 cheshire
97 <rdar://problem/3268878> Remove mDNSResponder version from packet header and use HINFO record instead
99 Revision 1.95 2003/07/12 03:15:20 cheshire
100 <rdar://problem/3324848> After SCDynamicStore notification, mDNSResponder updates
101 m->hostlabel even if user hasn't actually actually changed their dot-local hostname
103 Revision 1.94 2003/07/03 00:51:54 cheshire
104 <rdar://problem/3287213> When select() and recvmgs() disagree, get more info from kernel about the socket state
106 Revision 1.93 2003/07/03 00:09:14 cheshire
107 <rdar://problem/3286004> New APIs require a mDNSPlatformInterfaceIDfromInterfaceIndex() call
108 Additional refinement suggested by Josh: Use info->scope_id instead of if_nametoindex(info->ifa_name);
110 Revision 1.92 2003/07/02 21:19:51 cheshire
111 <rdar://problem/3313413> Update copyright notices, etc., in source code comments
113 Revision 1.91 2003/06/24 01:53:51 cheshire
114 Minor update to comments
116 Revision 1.90 2003/06/24 01:51:47 cheshire
117 <rdar://problem/3303118> Oops: Double-dispose of sockets
118 Don't need to close sockets: CFSocketInvalidate() does that for us
120 Revision 1.89 2003/06/21 18:12:47 cheshire
121 <rdar://problem/3296061> Rendezvous cannot handle interfaces whose total name is >3 chars
122 One-line change: should say "IF_NAMESIZE", not sizeof(ifname)
124 Revision 1.88 2003/06/12 23:38:37 cheshire
125 <rdar://problem/3291162> mDNSResponder doesn't detect some configuration changes
126 Also check that scope_id matches before concluding that two interfaces are the same
128 Revision 1.87 2003/06/10 01:14:11 cheshire
129 <rdar://problem/3286004> New APIs require a mDNSPlatformInterfaceIDfromInterfaceIndex() call
131 Revision 1.86 2003/05/28 02:41:52 cheshire
132 <rdar://problem/3034346> Time to remove Mac OS 9 UDP Port 53 legacy support
134 Revision 1.85 2003/05/28 02:39:47 cheshire
135 Minor change to debugging messages
137 Revision 1.84 2003/05/27 22:29:40 cheshire
138 Remove out-dated comment
140 Revision 1.83 2003/05/26 03:21:29 cheshire
141 Tidy up address structure naming:
142 mDNSIPAddr => mDNSv4Addr (for consistency with mDNSv6Addr)
143 mDNSAddr.addr.ipv4 => mDNSAddr.ip.v4
144 mDNSAddr.addr.ipv6 => mDNSAddr.ip.v6
146 Revision 1.82 2003/05/26 03:01:27 cheshire
147 <rdar://problem/3268904> sprintf/vsprintf-style functions are unsafe; use snprintf/vsnprintf instead
149 Revision 1.81 2003/05/24 02:06:42 cheshire
150 <rdar://problem/3268480> IPv6 Multicast Loopback doesn't work
151 Tried setting IPV6_MULTICAST_LOOP; it doesn't help.
152 However, it is probably wise to have the code explicitly set this socket
153 option anyway, in case the default changes in later versions of Unix.
155 Revision 1.80 2003/05/24 02:02:24 cheshire
156 <rdar://problem/3221880> if_indextoname consumes a lot of CPU
157 Fix error in myIfIndexToName; was returning prematurely
159 Revision 1.79 2003/05/23 23:07:44 cheshire
160 <rdar://problem/3268199> Must not write to stderr when running as daemon
162 Revision 1.78 2003/05/23 01:19:04 cheshire
163 <rdar://problem/3267085> mDNSResponder needs to signal type of service to AirPort
164 Mark packets as high-throughput/low-delay (i.e. lowest reliability) to get maximum 802.11 multicast rate
166 Revision 1.77 2003/05/23 01:12:05 cheshire
169 Revision 1.76 2003/05/22 01:26:01 cheshire
172 Revision 1.75 2003/05/22 00:07:09 cheshire
173 <rdar://problem/3264366> myCFSocketCallBack recvfrom(5) error 1, errno 35
174 Extra logging to determine whether there is a bug in CFSocket
176 Revision 1.74 2003/05/21 20:20:12 cheshire
177 Fix warnings (mainly printf format string warnings, like using "%d" where
178 it should say "%lu", etc.) and improve error logging (use strerror()
179 to include textual error message as well as numeric error in log messages).
181 Revision 1.73 2003/05/21 17:56:29 ksekar
182 Bug #: <rdar://problem/3191277>: mDNSResponder doesn't watch for IPv6 address changes
184 Revision 1.72 2003/05/14 18:48:41 cheshire
185 <rdar://problem/3159272> mDNSResponder should be smarter about reconfigurations
186 More minor refinements:
187 CFSocket.c needs to do *all* its mDNS_DeregisterInterface calls before freeing memory
188 mDNS_DeregisterInterface revalidates cache record when *any* representative of an interface goes away
190 Revision 1.71 2003/05/14 07:08:37 cheshire
191 <rdar://problem/3159272> mDNSResponder should be smarter about reconfigurations
192 Previously, when there was any network configuration change, mDNSResponder
193 would tear down the entire list of active interfaces and start again.
194 That was very disruptive, and caused the entire cache to be flushed,
195 and caused lots of extra network traffic. Now it only removes interfaces
196 that have really gone, and only adds new ones that weren't there before.
198 Revision 1.70 2003/05/07 18:30:24 cheshire
199 Fix signed/unsigned comparison warning
201 Revision 1.69 2003/05/06 20:14:44 cheshire
204 Revision 1.68 2003/05/06 00:00:49 cheshire
205 <rdar://problem/3248914> Rationalize naming of domainname manipulation functions
207 Revision 1.67 2003/04/29 00:43:44 cheshire
208 Fix compiler warnings
210 Revision 1.66 2003/04/26 02:41:58 cheshire
211 <rdar://problem/3241281> Change timenow from a local variable to a structure member
213 Revision 1.65 2003/04/26 02:34:01 cheshire
214 Add missing mDNSexport
216 Revision 1.64 2003/04/15 16:48:06 jgraessl
218 Modified code in CFSocket notifier function to read all packets on the socket
219 instead of reading only one packet every time the notifier was called.
221 Revision 1.63 2003/04/15 16:33:50 jgraessl
223 Switched to our own copy of if_indextoname to improve performance.
225 Revision 1.62 2003/03/28 01:55:44 cheshire
226 Minor improvements to debugging messages
228 Revision 1.61 2003/03/27 03:30:56 cheshire
229 <rdar://problem/3210018> Name conflicts not handled properly, resulting in memory corruption, and eventual crash
230 Problem was that HostNameCallback() was calling mDNS_DeregisterInterface(), which is not safe in a callback
232 1. Make mDNS_DeregisterInterface() safe to call from a callback
233 2. Make HostNameCallback() use mDNS_DeadvertiseInterface() instead
234 (it never really needed to deregister the interface at all)
236 Revision 1.60 2003/03/15 04:40:38 cheshire
237 Change type called "mDNSOpaqueID" to the more descriptive name "mDNSInterfaceID"
239 Revision 1.59 2003/03/11 01:23:26 cheshire
240 Bug #: 3194246 mDNSResponder socket problems
242 Revision 1.58 2003/03/06 01:43:04 cheshire
243 Bug #: 3189097 Additional debugging code in mDNSResponder
244 Improve "LIST_ALL_INTERFACES" output
246 Revision 1.57 2003/03/05 22:36:27 cheshire
247 Bug #: 3186338 Loopback doesn't work with mDNSResponder-27
248 Temporary workaround: Skip loopback interface *only* if we found at least one v4 interface to use
250 Revision 1.56 2003/03/05 01:50:38 cheshire
251 Bug #: 3189097 Additional debugging code in mDNSResponder
253 Revision 1.55 2003/02/21 01:54:09 cheshire
254 Bug #: 3099194 mDNSResponder needs performance improvements
255 Switched to using new "mDNS_Execute" model (see "Implementer Notes.txt")
257 Revision 1.54 2003/02/20 06:48:35 cheshire
258 Bug #: 3169535 Xserve RAID needs to do interface-specific registrations
259 Reviewed by: Josh Graessley, Bob Bradley
261 Revision 1.53 2003/01/29 02:21:23 cheshire
262 Return mStatus_Invalid if can't send packet because socket not available
264 Revision 1.52 2003/01/28 19:39:43 jgraessl
265 Enabling AAAA over IPv4 support.
267 Revision 1.51 2003/01/28 05:11:23 cheshire
268 Fixed backwards comparison in SearchForInterfaceByName
270 Revision 1.50 2003/01/13 23:49:44 jgraessl
271 Merged changes for the following fixes in to top of tree:
272 3086540 computer name changes not handled properly
273 3124348 service name changes are not properly handled
274 3124352 announcements sent in pairs, failing chattiness test
276 Revision 1.49 2002/12/23 22:13:30 jgraessl
277 Reviewed by: Stuart Cheshire
278 Initial IPv6 support for mDNSResponder.
280 Revision 1.48 2002/11/22 01:37:52 cheshire
281 Bug #: 3108426 mDNSResponder is monitoring ServiceEntities instead of InterfaceEntities
283 Revision 1.47 2002/09/21 20:44:51 zarzycki
286 Revision 1.46 2002/09/19 21:25:35 cheshire
287 mDNS_snprintf() doesn't need to be in a separate file
289 Revision 1.45 2002/09/17 01:45:13 cheshire
290 Add LIST_ALL_INTERFACES symbol for debugging
292 Revision 1.44 2002/09/17 01:36:23 cheshire
293 Move Puma support to CFSocketPuma.c
295 Revision 1.43 2002/09/17 01:05:28 cheshire
296 Change mDNS_AdvertiseLocalAddresses to be an Init parameter instead of a global
298 Revision 1.42 2002/09/16 23:13:50 cheshire
303 // ***************************************************************************
305 // Supporting routines to run mDNS on a CFRunLoop platform
306 // ***************************************************************************
308 // Open Transport 2.7.x on Mac OS 9 used to send Multicast DNS queries to UDP port 53,
309 // before the Multicast DNS port was changed to 5353. For this reason, the mDNSResponder
310 // in earlier versions of Mac OS X 10.2 Jaguar used to set mDNS_AllowPort53 to 1 to allow
311 // it to also listen and answer queries on UDP port 53. Now that Transport 2.8 (included in
312 // the Classic subsystem of Mac OS X 10.2 Jaguar) has been corrected to issue Multicast DNS
313 // queries on UDP port 5353, this backwards-compatibility legacy support is no longer needed.
314 #define mDNS_AllowPort53 0
316 // For debugging, set LIST_ALL_INTERFACES to 1 to display all found interfaces,
317 // including ones that mDNSResponder chooses not to use.
318 #define LIST_ALL_INTERFACES 0
320 // For enabling AAAA records over IPv4. Setting this to 0 sends only
321 // A records over IPv4 and AAAA over IPv6. Setting this to 1 sends both
322 // AAAA and A records over both IPv4 and IPv6.
323 #define AAAA_OVER_V4 1
325 #include "mDNSClientAPI.h" // Defines the interface provided to the client layer above
326 #include "mDNSPlatformFunctions.h" // Defines the interface to the supporting layer below
327 #include "mDNSMacOSX.h" // Defines the specific types needed to run mDNS on this platform
330 #include <unistd.h> // For select() and close()
331 #include <stdarg.h> // For va_list support
333 #include <net/if_dl.h>
335 #include <sys/param.h>
336 #include <sys/socket.h>
337 #include <sys/sysctl.h>
339 #include <sys/ioctl.h>
341 #include <netinet/in.h> // For IP_RECVTTL
343 #define IP_RECVTTL 24 /* bool; receive reception TTL w/dgram */
346 #include <netinet/in_systm.h> // For n_long, required by <netinet/ip.h> below
347 #include <netinet/ip.h> // For IPTOS_LOWDELAY etc.
348 #include <netinet6/in6_var.h> // For IN6_IFF_NOTREADY etc.
350 // Code contributed by Dave Heller:
351 // Define RUN_ON_PUMA_WITHOUT_IFADDRS to compile code that will
352 // work on Mac OS X 10.1, which does not have the getifaddrs call.
353 #define RUN_ON_PUMA_WITHOUT_IFADDRS 0
354 #if RUN_ON_PUMA_WITHOUT_IFADDRS
355 #include "CFSocketPuma.c"
360 #include <IOKit/IOKitLib.h>
361 #include <IOKit/IOMessage.h>
362 #include <mach/mach_time.h>
364 // ***************************************************************************
367 static mDNSu32 clockdivisor
= 0;
369 // ***************************************************************************
372 #define mDNSSameIPv4Address(A,B) ((A).NotAnInteger == (B).NotAnInteger)
373 #define mDNSSameIPv6Address(A,B) ((A).l[0] == (B).l[0] && (A).l[1] == (B).l[1] && (A).l[2] == (B).l[2] && (A).l[3] == (B).l[3])
375 #define mDNSAddressIsAllDNSLinkGroup(X) ( \
376 ((X)->type == mDNSAddrType_IPv4 && mDNSSameIPv4Address((X)->ip.v4, AllDNSLinkGroup )) || \
377 ((X)->type == mDNSAddrType_IPv6 && mDNSSameIPv6Address((X)->ip.v6, AllDNSLinkGroupv6)) )
379 // ***************************************************************************
382 // Note, this uses mDNS_vsnprintf instead of standard "vsnprintf", because mDNS_vsnprintf knows
383 // how to print special data types like IP addresses and length-prefixed domain names
385 mDNSexport
void debugf_(const char *format
, ...)
387 unsigned char buffer
[512];
389 va_start(ptr
,format
);
390 buffer
[mDNS_vsnprintf((char *)buffer
, sizeof(buffer
), format
, ptr
)] = 0;
392 fprintf(stderr
,"%s\n", buffer
);
397 #if MDNS_DEBUGMSGS > 1
398 mDNSexport
void verbosedebugf_(const char *format
, ...)
400 unsigned char buffer
[512];
402 va_start(ptr
,format
);
403 buffer
[mDNS_vsnprintf((char *)buffer
, sizeof(buffer
), format
, ptr
)] = 0;
405 fprintf(stderr
,"%s\n", buffer
);
410 mDNSexport
void LogMsg(const char *format
, ...)
412 unsigned char buffer
[512];
414 va_start(ptr
,format
);
415 buffer
[mDNS_vsnprintf((char *)buffer
, sizeof(buffer
), format
, ptr
)] = 0;
418 extern int debug_mode
;
419 if (debug_mode
) // In debug_mode we write to stderr
421 fprintf(stderr
,"%s\n", buffer
);
424 else // else, in production mode, we write to syslog
426 openlog("mDNSResponder", LOG_CONS
| LOG_PERROR
| LOG_PID
, LOG_DAEMON
);
427 syslog(LOG_ERR
, "%s", buffer
);
432 mDNSlocal
struct ifaddrs
* myGetIfAddrs(int refresh
)
434 static struct ifaddrs
*ifa
= NULL
;
442 if (ifa
== NULL
) getifaddrs(&ifa
);
447 mDNSlocal
int myIfIndexToName(u_short index
, char* name
)
450 for (ifa
= myGetIfAddrs(0); ifa
; ifa
= ifa
->ifa_next
)
451 if (ifa
->ifa_addr
->sa_family
== AF_LINK
)
452 if (((struct sockaddr_dl
*)ifa
->ifa_addr
)->sdl_index
== index
)
453 { strncpy(name
, ifa
->ifa_name
, IF_NAMESIZE
); return 0; }
457 mDNSexport mDNSInterfaceID
mDNSPlatformInterfaceIDfromInterfaceIndex(const mDNS
*const m
, mDNSu32 index
)
459 NetworkInterfaceInfoOSX
*i
;
460 if (index
== (uint32_t)~0) return((mDNSInterfaceID
)~0);
462 for (i
= m
->p
->InterfaceList
; i
; i
= i
->next
)
463 if (i
->scope_id
== index
)
464 return(i
->ifinfo
.InterfaceID
);
468 mDNSexport mDNSu32
mDNSPlatformInterfaceIndexfromInterfaceID(const mDNS
*const m
, mDNSInterfaceID id
)
470 NetworkInterfaceInfoOSX
*i
;
471 if (id
== (mDNSInterfaceID
)~0) return((mDNSu32
)~0);
473 for (i
= m
->p
->InterfaceList
; i
; i
= i
->next
)
474 if (i
->ifinfo
.InterfaceID
== id
)
479 mDNSexport mStatus
mDNSPlatformSendUDP(const mDNS
*const m
, const DNSMessage
*const msg
, const mDNSu8
*const end
,
480 mDNSInterfaceID InterfaceID
, mDNSIPPort srcPort
, const mDNSAddr
*dst
, mDNSIPPort dstPort
)
483 NetworkInterfaceInfoOSX
*info
= (NetworkInterfaceInfoOSX
*)InterfaceID
;
484 struct sockaddr_storage to
;
487 if (!InterfaceID
) { LogMsg("mDNSPlatformSendUDP ERROR! Cannot send from zero InterfaceID"); return mStatus_BadParamErr
; }
489 if (dst
->type
== mDNSAddrType_IPv4
)
491 struct sockaddr_in
* sin_to
= (struct sockaddr_in
*)&to
;
492 sin_to
->sin_len
= sizeof(*sin_to
);
493 sin_to
->sin_family
= AF_INET
;
494 sin_to
->sin_port
= dstPort
.NotAnInteger
;
495 sin_to
->sin_addr
.s_addr
= dst
->ip
.v4
.NotAnInteger
;
497 else if (dst
->type
== mDNSAddrType_IPv6
)
499 struct sockaddr_in6
* sin6_to
= (struct sockaddr_in6
*)&to
;
500 sin6_to
->sin6_len
= sizeof(*sin6_to
);
501 sin6_to
->sin6_family
= AF_INET6
;
502 sin6_to
->sin6_port
= dstPort
.NotAnInteger
;
503 sin6_to
->sin6_flowinfo
= 0;
504 sin6_to
->sin6_addr
= *(struct in6_addr
*)&dst
->ip
.v6
;
505 sin6_to
->sin6_scope_id
= info
->scope_id
;
509 LogMsg("mDNSPlatformSendUDP: dst is not an IPv4 or IPv6 address!\n");
510 return mStatus_BadParamErr
;
513 if (srcPort
.NotAnInteger
== MulticastDNSPort
.NotAnInteger
)
515 if (dst
->type
== mDNSAddrType_IPv4
) s
= info
->sktv4
;
516 else if (dst
->type
== mDNSAddrType_IPv6
) s
= info
->sktv6
;
520 else if (srcPort
.NotAnInteger
== UnicastDNSPort
.NotAnInteger
&& dst
->type
== mDNSAddrType_IPv4
)
523 else { LogMsg("Source port %d not allowed", (mDNSu16
)srcPort
.b
[0]<<8 | srcPort
.b
[1]); return(-1); }
526 verbosedebugf("mDNSPlatformSendUDP: sending on InterfaceID %X %s/%d to %#a:%d skt %d",
527 InterfaceID
, info
->ifa_name
, dst
->type
, dst
, (mDNSu16
)dstPort
.b
[0]<<8 | dstPort
.b
[1], s
);
529 verbosedebugf("mDNSPlatformSendUDP: NOT sending on InterfaceID %X %s/%d (socket of this type not available)",
530 InterfaceID
, info
->ifa_name
, dst
->type
, dst
, (mDNSu16
)dstPort
.b
[0]<<8 | dstPort
.b
[1]);
532 // Note: When sending, mDNSCore may often ask us to send both a v4 multicast packet and then a v6 multicast packet
533 // If we don't have the corresponding type of socket available, then return mStatus_Invalid
534 if (s
< 0) return(mStatus_Invalid
);
536 err
= sendto(s
, msg
, (UInt8
*)end
- (UInt8
*)msg
, 0, (struct sockaddr
*)&to
, to
.ss_len
);
539 // Don't report EHOSTDOWN (i.e. ARP failure) to unicast destinations
540 if (errno
== EHOSTDOWN
&& !mDNSAddressIsAllDNSLinkGroup(dst
)) return(err
);
541 // Don't report EHOSTUNREACH in the first two minutes after boot
542 // This is because mDNSResponder intentionally starts up early in the boot process (See <rdar://problem/3409090>)
543 // but this means that sometimes it starts before configd has finished setting up the multicast routing entries.
544 if (errno
== EHOSTUNREACH
&& (mDNSu32
)(m
->timenow
) < (mDNSu32
)(mDNSPlatformOneSecond
* 120)) return(err
);
545 LogMsg("mDNSPlatformSendUDP sendto failed to send packet on InterfaceID %p %s/%ld to %#a:%d skt %d error %d errno %d (%s)",
546 InterfaceID
, info
->ifa_name
, dst
->type
, dst
, (mDNSu16
)dstPort
.b
[0]<<8 | dstPort
.b
[1], s
, err
, errno
, strerror(errno
));
550 return(mStatus_NoError
);
553 mDNSlocal ssize_t
myrecvfrom(const int s
, void *const buffer
, const size_t max
,
554 struct sockaddr
*const from
, size_t *const fromlen
, mDNSAddr
*dstaddr
, char ifname
[IF_NAMESIZE
], mDNSu8
*ttl
)
556 static unsigned int numLogMessages
= 0;
557 struct iovec databuffers
= { (char *)buffer
, max
};
560 struct cmsghdr
*cmPtr
;
561 char ancillary
[1024];
563 *ttl
= 255; // If kernel fails to provide TTL data (e.g. Jaguar doesn't) then assume the TTL was 255 as it should be
565 // Set up the message
566 msg
.msg_name
= (caddr_t
)from
;
567 msg
.msg_namelen
= *fromlen
;
568 msg
.msg_iov
= &databuffers
;
570 msg
.msg_control
= (caddr_t
)&ancillary
;
571 msg
.msg_controllen
= sizeof(ancillary
);
575 n
= recvmsg(s
, &msg
, 0);
578 if (errno
!= EWOULDBLOCK
&& numLogMessages
++ < 100) LogMsg("CFSocket.c: recvmsg(%d) returned error %d errno %d", s
, n
, errno
);
581 if (msg
.msg_controllen
< (int)sizeof(struct cmsghdr
))
583 if (numLogMessages
++ < 100) LogMsg("CFSocket.c: recvmsg(%d) msg.msg_controllen %d < sizeof(struct cmsghdr) %lu",
584 s
, msg
.msg_controllen
, sizeof(struct cmsghdr
));
587 if (msg
.msg_flags
& MSG_CTRUNC
)
589 if (numLogMessages
++ < 100) LogMsg("CFSocket.c: recvmsg(%d) msg.msg_flags & MSG_CTRUNC", s
);
593 *fromlen
= msg
.msg_namelen
;
595 // Parse each option out of the ancillary data.
596 for (cmPtr
= CMSG_FIRSTHDR(&msg
); cmPtr
; cmPtr
= CMSG_NXTHDR(&msg
, cmPtr
))
598 // debugf("myrecvfrom cmsg_level %d cmsg_type %d", cmPtr->cmsg_level, cmPtr->cmsg_type);
599 if (cmPtr
->cmsg_level
== IPPROTO_IP
&& cmPtr
->cmsg_type
== IP_RECVDSTADDR
)
601 dstaddr
->type
= mDNSAddrType_IPv4
;
602 dstaddr
->ip
.v4
.NotAnInteger
= *(u_int32_t
*)CMSG_DATA(cmPtr
);
604 if (cmPtr
->cmsg_level
== IPPROTO_IP
&& cmPtr
->cmsg_type
== IP_RECVIF
)
606 struct sockaddr_dl
*sdl
= (struct sockaddr_dl
*)CMSG_DATA(cmPtr
);
607 if (sdl
->sdl_nlen
< IF_NAMESIZE
)
609 mDNSPlatformMemCopy(sdl
->sdl_data
, ifname
, sdl
->sdl_nlen
);
610 ifname
[sdl
->sdl_nlen
] = 0;
611 // debugf("IP_RECVIF sdl_index %d, sdl_data %s len %d", sdl->sdl_index, ifname, sdl->sdl_nlen);
614 if (cmPtr
->cmsg_level
== IPPROTO_IP
&& cmPtr
->cmsg_type
== IP_RECVTTL
)
616 *ttl
= *(u_char
*)CMSG_DATA(cmPtr
);
618 if (cmPtr
->cmsg_level
== IPPROTO_IPV6
&& cmPtr
->cmsg_type
== IPV6_PKTINFO
)
620 struct in6_pktinfo
*ip6_info
= (struct in6_pktinfo
*)CMSG_DATA(cmPtr
);
621 dstaddr
->type
= mDNSAddrType_IPv6
;
622 dstaddr
->ip
.v6
= *(mDNSv6Addr
*)&ip6_info
->ipi6_addr
;
623 myIfIndexToName(ip6_info
->ipi6_ifindex
, ifname
);
625 if (cmPtr
->cmsg_level
== IPPROTO_IPV6
&& cmPtr
->cmsg_type
== IPV6_HOPLIMIT
)
627 *ttl
= *(int*)CMSG_DATA(cmPtr
);
634 mDNSlocal
void myCFSocketCallBack(CFSocketRef cfs
, CFSocketCallBackType CallBackType
, CFDataRef address
, const void *data
, void *context
)
636 mDNSAddr senderAddr
, destAddr
;
637 mDNSIPPort senderPort
, destPort
= MulticastDNSPort
;
638 NetworkInterfaceInfoOSX
*info
= (NetworkInterfaceInfoOSX
*)context
;
639 mDNS
*const m
= info
->m
;
641 struct sockaddr_storage from
;
642 size_t fromlen
= sizeof(from
);
643 char packetifname
[IF_NAMESIZE
] = "";
644 int err
, s1
= -1, skt
= CFSocketGetNative(cfs
);
647 (void)address
; // Parameter not used
648 (void)data
; // Parameter not used
650 if (CallBackType
!= kCFSocketReadCallBack
) LogMsg("myCFSocketCallBack: Why is CallBackType %d not kCFSocketReadCallBack?", CallBackType
);
653 if (cfs
== info
->cfs53
) { s1
= info
->skt53
; destPort
= UnicastDNSPort
; }
656 if (cfs
== info
->cfsv4
) s1
= info
->sktv4
;
657 else if (cfs
== info
->cfsv6
) s1
= info
->sktv6
;
659 if (s1
< 0 || s1
!= skt
)
661 LogMsg("myCFSocketCallBack: s1 %d native socket %d, cfs %p", s1
, skt
, cfs
);
663 LogMsg("myCFSocketCallBack: cfs53 %p, skt53 %d", info
->cfs53
, info
->skt53
);
665 LogMsg("myCFSocketCallBack: cfsv4 %p, sktv4 %d", info
->cfsv4
, info
->sktv4
);
666 LogMsg("myCFSocketCallBack: cfsv6 %p, sktv6 %d", info
->cfsv6
, info
->sktv6
);
670 while ((err
= myrecvfrom(s1
, &packet
, sizeof(packet
), (struct sockaddr
*)&from
, &fromlen
, &destAddr
, packetifname
, &ttl
)) >= 0)
673 if (from
.ss_family
== AF_INET
)
675 struct sockaddr_in
*sin
= (struct sockaddr_in
*)&from
;
676 senderAddr
.type
= mDNSAddrType_IPv4
;
677 senderAddr
.ip
.v4
.NotAnInteger
= sin
->sin_addr
.s_addr
;
678 senderPort
.NotAnInteger
= sin
->sin_port
;
680 else if (from
.ss_family
== AF_INET6
)
682 struct sockaddr_in6
*sin6
= (struct sockaddr_in6
*)&from
;
683 senderAddr
.type
= mDNSAddrType_IPv6
;
684 senderAddr
.ip
.v6
= *(mDNSv6Addr
*)&sin6
->sin6_addr
;
685 senderPort
.NotAnInteger
= sin6
->sin6_port
;
689 LogMsg("myCFSocketCallBack from is unknown address family %d", from
.ss_family
);
693 // Even though we indicated a specific interface in the IP_ADD_MEMBERSHIP call, a weirdness of the
694 // sockets API means that even though this socket has only officially joined the multicast group
695 // on one specific interface, the kernel will still deliver multicast packets to it no matter which
696 // interface they arrive on. According to the official Unix Powers That Be, this is Not A Bug.
697 // To work around this weirdness, we use the IP_RECVIF option to find the name of the interface
698 // on which the packet arrived, and ignore the packet if it really arrived on some other interface.
699 if (strcmp(info
->ifa_name
, packetifname
))
701 verbosedebugf("myCFSocketCallBack got a packet from %#a to %#a on interface %#a/%s (Ignored -- really arrived on interface %s)",
702 &senderAddr
, &destAddr
, &info
->ifinfo
.ip
, info
->ifa_name
, packetifname
);
706 verbosedebugf("myCFSocketCallBack got a packet from %#a to %#a on interface %#a/%s",
707 &senderAddr
, &destAddr
, &info
->ifinfo
.ip
, info
->ifa_name
);
709 if (err
< (int)sizeof(DNSMessageHeader
)) { debugf("myCFSocketCallBack packet length (%d) too short", err
); return; }
711 mDNSCoreReceive(m
, &packet
, (unsigned char*)&packet
+ err
, &senderAddr
, senderPort
, &destAddr
, destPort
, info
->ifinfo
.InterfaceID
, ttl
);
714 if (err
< 0 && (errno
!= EWOULDBLOCK
|| count
== 0))
716 // Something is busted here.
717 // CFSocket says there is a packet, but myrecvfrom says there is not.
718 // Try calling select() to get another opinion.
719 // Find out about other socket parameter that can help understand why select() says the socket is ready for read
720 // All of this is racy, as data may have arrived after the call to select()
721 int save_errno
= errno
;
725 int solen
= sizeof(int);
728 FD_SET(s1
, &readfds
);
729 struct timeval timeout
;
732 int selectresult
= select(s1
+1, &readfds
, NULL
, NULL
, &timeout
);
733 if (getsockopt(s1
, SOL_SOCKET
, SO_ERROR
, &so_error
, &solen
) == -1)
734 LogMsg("myCFSocketCallBack getsockopt(SO_ERROR) error %d", errno
);
735 if (getsockopt(s1
, SOL_SOCKET
, SO_NREAD
, &so_nread
, &solen
) == -1)
736 LogMsg("myCFSocketCallBack getsockopt(SO_NREAD) error %d", errno
);
737 if (ioctl(s1
, FIONREAD
, &fionread
) == -1)
738 LogMsg("myCFSocketCallBack ioctl(FIONREAD) error %d", errno
);
739 static unsigned int numLogMessages
= 0;
740 if (numLogMessages
++ < 100)
741 LogMsg("myCFSocketCallBack recvfrom skt %d error %d errno %d (%s) select %d (%spackets waiting) so_error %d so_nread %d fionread %d count %d",
742 s1
, err
, save_errno
, strerror(save_errno
), selectresult
, FD_ISSET(s1
, &readfds
) ? "" : "*NO* ", so_error
, so_nread
, fionread
, count
);
743 sleep(1); // After logging this error, rate limit so we don't flood syslog
747 // This gets the text of the field currently labelled "Computer Name" in the Sharing Prefs Control Panel
748 mDNSlocal
void GetUserSpecifiedFriendlyComputerName(domainlabel
*const namelabel
)
750 CFStringEncoding encoding
= kCFStringEncodingUTF8
;
751 CFStringRef cfs
= SCDynamicStoreCopyComputerName(NULL
, &encoding
);
754 CFStringGetPascalString(cfs
, namelabel
->c
, sizeof(*namelabel
), kCFStringEncodingUTF8
);
759 // This gets the text of the field currently labelled "Rendezvous Name" in the Sharing Prefs Control Panel
760 mDNSlocal
void GetUserSpecifiedRFC1034ComputerName(domainlabel
*const namelabel
)
762 CFStringRef cfs
= SCDynamicStoreCopyLocalHostName(NULL
);
765 CFStringGetPascalString(cfs
, namelabel
->c
, sizeof(*namelabel
), kCFStringEncodingUTF8
);
770 mDNSlocal mStatus
SetupSocket(NetworkInterfaceInfoOSX
*i
, mDNSIPPort port
, int *s
, CFSocketRef
*c
)
773 const int twofivefive
= 255;
775 if (*s
>= 0) { LogMsg("SetupSocket ERROR: socket %d is already set", *s
); return(-1); }
776 if (*c
) { LogMsg("SetupSocket ERROR: CFSocketRef %p is already set", *c
); return(-1); }
778 // Open the socket...
779 int skt
= socket(i
->sa_family
, SOCK_DGRAM
, IPPROTO_UDP
);
780 if (skt
< 0) { LogMsg("socket error %d errno %d (%s)", skt
, errno
, strerror(errno
)); return(skt
); }
782 // ... with a shared UDP port
783 mStatus err
= setsockopt(skt
, SOL_SOCKET
, SO_REUSEPORT
, &on
, sizeof(on
));
784 if (err
< 0) { LogMsg("setsockopt - SO_REUSEPORT error %ld errno %d (%s)", err
, errno
, strerror(errno
)); return(err
); }
786 if (i
->sa_family
== AF_INET
)
788 // We want to receive destination addresses
789 err
= setsockopt(skt
, IPPROTO_IP
, IP_RECVDSTADDR
, &on
, sizeof(on
));
790 if (err
< 0) { LogMsg("setsockopt - IP_RECVDSTADDR error %ld errno %d (%s)", err
, errno
, strerror(errno
)); return(err
); }
792 // We want to receive interface identifiers
793 err
= setsockopt(skt
, IPPROTO_IP
, IP_RECVIF
, &on
, sizeof(on
));
794 if (err
< 0) { LogMsg("setsockopt - IP_RECVIF error %ld errno %d (%s)", err
, errno
, strerror(errno
)); return(err
); }
796 // We want to receive packet TTL value so we can check it
797 err
= setsockopt(skt
, IPPROTO_IP
, IP_RECVTTL
, &on
, sizeof(on
));
798 // We ignore errors here -- we already know Jaguar doesn't support this, but we can get by without it
800 // Add multicast group membership on this interface
801 struct in_addr addr
= { i
->ifinfo
.ip
.ip
.v4
.NotAnInteger
};
803 imr
.imr_multiaddr
.s_addr
= AllDNSLinkGroup
.NotAnInteger
;
804 imr
.imr_interface
= addr
;
805 err
= setsockopt(skt
, IPPROTO_IP
, IP_ADD_MEMBERSHIP
, &imr
, sizeof(imr
));
806 if (err
< 0) { LogMsg("setsockopt - IP_ADD_MEMBERSHIP error %ld errno %d (%s)", err
, errno
, strerror(errno
)); return(err
); }
808 // Specify outgoing interface too
809 err
= setsockopt(skt
, IPPROTO_IP
, IP_MULTICAST_IF
, &addr
, sizeof(addr
));
810 if (err
< 0) { LogMsg("setsockopt - IP_MULTICAST_IF error %ld errno %d (%s)", err
, errno
, strerror(errno
)); return(err
); }
812 // Send unicast packets with TTL 255
813 err
= setsockopt(skt
, IPPROTO_IP
, IP_TTL
, &twofivefive
, sizeof(twofivefive
));
814 if (err
< 0) { LogMsg("setsockopt - IP_TTL error %ld errno %d (%s)", err
, errno
, strerror(errno
)); return(err
); }
816 // And multicast packets with TTL 255 too
817 err
= setsockopt(skt
, IPPROTO_IP
, IP_MULTICAST_TTL
, &twofivefive
, sizeof(twofivefive
));
818 if (err
< 0) { LogMsg("setsockopt - IP_MULTICAST_TTL error %ld errno %d (%s)", err
, errno
, strerror(errno
)); return(err
); }
820 // Mark packets as high-throughput/low-delay (i.e. lowest reliability) to get maximum 802.11 multicast rate
821 const int ip_tosbits
= IPTOS_LOWDELAY
| IPTOS_THROUGHPUT
;
822 err
= setsockopt(skt
, IPPROTO_IP
, IP_TOS
, &ip_tosbits
, sizeof(ip_tosbits
));
823 if (err
< 0) { LogMsg("setsockopt - IP_TOS error %ld errno %d (%s)", err
, errno
, strerror(errno
)); return(err
); }
825 // And start listening for packets
826 struct sockaddr_in listening_sockaddr
;
827 listening_sockaddr
.sin_family
= AF_INET
;
828 listening_sockaddr
.sin_port
= port
.NotAnInteger
;
829 listening_sockaddr
.sin_addr
.s_addr
= 0; // Want to receive multicasts AND unicasts on this socket
830 err
= bind(skt
, (struct sockaddr
*) &listening_sockaddr
, sizeof(listening_sockaddr
));
833 // If we fail to bind to port 53 (because we're not root), that's okay, just tidy up and silently continue
834 if (port
.NotAnInteger
== UnicastDNSPort
.NotAnInteger
) { close(skt
); err
= 0; }
835 else LogMsg("bind error %ld errno %d (%s)", err
, errno
, strerror(errno
));
839 else if (i
->sa_family
== AF_INET6
)
841 // We want to receive destination addresses and receive interface identifiers
842 err
= setsockopt(skt
, IPPROTO_IPV6
, IPV6_PKTINFO
, &on
, sizeof(on
));
843 if (err
< 0) { LogMsg("setsockopt - IPV6_PKTINFO error %ld errno %d (%s)", err
, errno
, strerror(errno
)); return(err
); }
845 // We want to receive packet hop count value so we can check it
846 err
= setsockopt(skt
, IPPROTO_IPV6
, IPV6_HOPLIMIT
, &on
, sizeof(on
));
847 if (err
< 0) { LogMsg("setsockopt - IPV6_HOPLIMIT error %ld errno %d (%s)", err
, errno
, strerror(errno
)); return(err
); }
849 // We want to receive only IPv6 packets, without this option, we may
850 // get IPv4 addresses as mapped addresses.
851 err
= setsockopt(skt
, IPPROTO_IPV6
, IPV6_V6ONLY
, &on
, sizeof(on
));
852 if (err
< 0) { LogMsg("setsockopt - IPV6_V6ONLY error %ld errno %d (%s)", err
, errno
, strerror(errno
)); return(err
); }
854 // Add multicast group membership on this interface
855 int interface_id
= if_nametoindex(i
->ifa_name
);
856 struct ipv6_mreq i6mr
;
857 i6mr
.ipv6mr_interface
= interface_id
;
858 i6mr
.ipv6mr_multiaddr
= *(struct in6_addr
*)&AllDNSLinkGroupv6
;
859 err
= setsockopt(skt
, IPPROTO_IPV6
, IPV6_JOIN_GROUP
, &i6mr
, sizeof(i6mr
));
860 if (err
< 0) { LogMsg("setsockopt - IPV6_JOIN_GROUP error %ld errno %d (%s)", err
, errno
, strerror(errno
)); return(err
); }
862 // Specify outgoing interface too
863 err
= setsockopt(skt
, IPPROTO_IPV6
, IPV6_MULTICAST_IF
, &interface_id
, sizeof(interface_id
));
864 if (err
< 0) { LogMsg("setsockopt - IPV6_MULTICAST_IF error %ld errno %d (%s)", err
, errno
, strerror(errno
)); return(err
); }
866 // Send unicast packets with TTL 255
867 err
= setsockopt(skt
, IPPROTO_IPV6
, IPV6_UNICAST_HOPS
, &twofivefive
, sizeof(twofivefive
));
868 if (err
< 0) { LogMsg("setsockopt - IPV6_UNICAST_HOPS error %ld errno %d (%s)", err
, errno
, strerror(errno
)); return(err
); }
870 // And multicast packets with TTL 255 too
871 err
= setsockopt(skt
, IPPROTO_IPV6
, IPV6_MULTICAST_HOPS
, &twofivefive
, sizeof(twofivefive
));
872 if (err
< 0) { LogMsg("setsockopt - IPV6_MULTICAST_HOPS error %ld errno %d (%s)", err
, errno
, strerror(errno
)); return(err
); }
874 // Note: IPV6_TCLASS appears not to be implemented on OS X right now (or indeed on ANY version of Unix?)
876 // Mark packets as high-throughput/low-delay (i.e. lowest reliability) to get maximum 802.11 multicast rate
877 int tclass
= IPTOS_LOWDELAY
| IPTOS_THROUGHPUT
; // This may not be right (since tclass is not implemented on OS X, I can't test it)
878 err
= setsockopt(skt
, IPPROTO_IPV6
, IPV6_TCLASS
, &tclass
, sizeof(tclass
));
879 if (err
< 0) { LogMsg("setsockopt - IPV6_TCLASS error %ld errno %d (%s)", err
, errno
, strerror(errno
)); return(err
); }
882 // Want to receive our own packets
883 err
= setsockopt(skt
, IPPROTO_IPV6
, IPV6_MULTICAST_LOOP
, &on
, sizeof(on
));
884 if (err
< 0) { LogMsg("setsockopt - IPV6_MULTICAST_LOOP error %ld errno %d (%s)", err
, errno
, strerror(errno
)); return(err
); }
886 // And start listening for packets
887 struct sockaddr_in6 listening_sockaddr6
;
888 bzero(&listening_sockaddr6
, sizeof(listening_sockaddr6
));
889 listening_sockaddr6
.sin6_len
= sizeof(listening_sockaddr6
);
890 listening_sockaddr6
.sin6_family
= AF_INET6
;
891 listening_sockaddr6
.sin6_port
= port
.NotAnInteger
;
892 listening_sockaddr6
.sin6_flowinfo
= 0;
893 // listening_sockaddr6.sin6_addr = IN6ADDR_ANY_INIT; // Want to receive multicasts AND unicasts on this socket
894 listening_sockaddr6
.sin6_scope_id
= 0;
895 err
= bind(skt
, (struct sockaddr
*) &listening_sockaddr6
, sizeof(listening_sockaddr6
));
896 if (err
) { LogMsg("bind error %ld errno %d (%s)", err
, errno
, strerror(errno
)); return(err
); }
899 fcntl(skt
, F_SETFL
, fcntl(skt
, F_GETFL
, 0) | O_NONBLOCK
); // set non-blocking
901 CFSocketContext myCFSocketContext
= { 0, i
->ifinfo
.InterfaceID
, NULL
, NULL
, NULL
};
902 *c
= CFSocketCreateWithNative(kCFAllocatorDefault
, *s
, kCFSocketReadCallBack
, myCFSocketCallBack
, &myCFSocketContext
);
903 CFRunLoopSourceRef rls
= CFSocketCreateRunLoopSource(kCFAllocatorDefault
, *c
, 0);
904 CFRunLoopAddSource(CFRunLoopGetCurrent(), rls
, kCFRunLoopDefaultMode
);
910 mDNSlocal mStatus
SetupAddr(mDNSAddr
*ip
, const struct sockaddr
*const sa
)
912 if (sa
->sa_family
== AF_INET
)
914 struct sockaddr_in
*ifa_addr
= (struct sockaddr_in
*)sa
;
915 ip
->type
= mDNSAddrType_IPv4
;
916 ip
->ip
.v4
.NotAnInteger
= ifa_addr
->sin_addr
.s_addr
;
919 else if (sa
->sa_family
== AF_INET6
)
921 struct sockaddr_in6
*ifa_addr
= (struct sockaddr_in6
*)sa
;
922 ip
->type
= mDNSAddrType_IPv6
;
923 if (IN6_IS_ADDR_LINKLOCAL(&ifa_addr
->sin6_addr
)) ifa_addr
->sin6_addr
.__u6_addr
.__u6_addr16
[1] = 0;
924 ip
->ip
.v6
= *(mDNSv6Addr
*)&ifa_addr
->sin6_addr
;
929 LogMsg("SetupAddr invalid sa_family %d", sa
->sa_family
);
934 mDNSlocal mStatus
AddInterfaceToList(mDNS
*const m
, struct ifaddrs
*ifa
)
936 mDNSu32 scope_id
= if_nametoindex(ifa
->ifa_name
);
938 SetupAddr(&ip
, ifa
->ifa_addr
);
939 NetworkInterfaceInfoOSX
**p
;
940 for (p
= &m
->p
->InterfaceList
; *p
; p
= &(*p
)->next
)
941 if (scope_id
== (*p
)->scope_id
&& mDNSSameAddress(&ip
, &(*p
)->ifinfo
.ip
))
943 debugf("AddInterfaceToList: Found existing interface %u with address %#a", scope_id
, &ip
);
944 (*p
)->CurrentlyActive
= mDNStrue
;
948 debugf("AddInterfaceToList: Making new interface %u with address %#a", scope_id
, &ip
);
949 NetworkInterfaceInfoOSX
*i
= (NetworkInterfaceInfoOSX
*)mallocL("NetworkInterfaceInfoOSX", sizeof(*i
));
951 i
->ifa_name
= (char *)mallocL("NetworkInterfaceInfoOSX name", strlen(ifa
->ifa_name
) + 1);
952 if (!i
->ifa_name
) { freeL("NetworkInterfaceInfoOSX", i
); return(-1); }
953 strcpy(i
->ifa_name
, ifa
->ifa_name
);
955 i
->ifinfo
.InterfaceID
= mDNSNULL
;
957 i
->ifinfo
.Advertise
= m
->AdvertiseLocalAddresses
;
958 i
->ifinfo
.TxAndRx
= mDNSfalse
; // For now; will be set up later at the end of UpdateInterfaceList
962 i
->scope_id
= scope_id
;
963 i
->CurrentlyActive
= mDNStrue
;
964 i
->sa_family
= ifa
->ifa_addr
->sa_family
;
974 if (!i
->ifa_name
) return(-1);
979 mDNSlocal NetworkInterfaceInfoOSX
*FindRoutableIPv4(mDNS
*const m
, mDNSu32 scope_id
)
981 NetworkInterfaceInfoOSX
*i
;
982 for (i
= m
->p
->InterfaceList
; i
; i
= i
->next
)
983 if (i
->CurrentlyActive
&& i
->scope_id
== scope_id
&& i
->ifinfo
.ip
.type
== mDNSAddrType_IPv4
)
984 if (!(i
->ifinfo
.ip
.ip
.v4
.b
[0] == 169 && i
->ifinfo
.ip
.ip
.v4
.b
[1] == 254))
989 mDNSlocal mStatus
UpdateInterfaceList(mDNS
*const m
)
991 mDNSBool foundav4
= mDNSfalse
;
992 struct ifaddrs
*ifa
= myGetIfAddrs(1);
993 struct ifaddrs
*theLoopback
= NULL
;
994 int err
= (ifa
!= NULL
) ? 0 : (errno
!= 0 ? errno
: -1);
995 int InfoSocket
= err
? -1 : socket(AF_INET6
, SOCK_DGRAM
, 0);
996 if (err
) return(err
);
998 // Set up the nice label
999 m
->nicelabel
.c
[0] = 0;
1000 GetUserSpecifiedFriendlyComputerName(&m
->nicelabel
);
1001 if (m
->nicelabel
.c
[0] == 0) MakeDomainLabelFromLiteralString(&m
->nicelabel
, "Macintosh");
1003 // Set up the RFC 1034-compliant label
1004 domainlabel hostlabel
;
1006 GetUserSpecifiedRFC1034ComputerName(&hostlabel
);
1007 if (hostlabel
.c
[0] == 0) MakeDomainLabelFromLiteralString(&hostlabel
, "Macintosh");
1008 // If the user has changed their dot-local host name since the last time we checked, then update our local copy.
1009 // If the user has not changed their dot-local host name, then leave ours alone (m->hostlabel may have gone through
1010 // repeated conflict resolution to get to its current value, and if we reset it, we'll have to go through all that again.)
1011 if (SameDomainLabel(m
->p
->userhostlabel
.c
, hostlabel
.c
))
1012 debugf("Userhostlabel (%#s) unchanged since last time; not changing m->hostlabel (%#s)", m
->p
->userhostlabel
.c
, m
->hostlabel
.c
);
1015 debugf("Updating m->hostlabel to %#s", hostlabel
.c
);
1016 m
->p
->userhostlabel
= m
->hostlabel
= hostlabel
;
1017 mDNS_GenerateFQDN(m
);
1022 #if LIST_ALL_INTERFACES
1023 if (ifa
->ifa_addr
->sa_family
== AF_APPLETALK
)
1024 debugf("UpdateInterfaceList: %4s(%d) Flags %04X Family %2d is AF_APPLETALK",
1025 ifa
->ifa_name
, if_nametoindex(ifa
->ifa_name
), ifa
->ifa_flags
, ifa
->ifa_addr
->sa_family
);
1026 else if (ifa
->ifa_addr
->sa_family
== AF_LINK
)
1027 debugf("UpdateInterfaceList: %4s(%d) Flags %04X Family %2d is AF_LINK",
1028 ifa
->ifa_name
, if_nametoindex(ifa
->ifa_name
), ifa
->ifa_flags
, ifa
->ifa_addr
->sa_family
);
1029 else if (ifa
->ifa_addr
->sa_family
!= AF_INET
&& ifa
->ifa_addr
->sa_family
!= AF_INET6
)
1030 debugf("UpdateInterfaceList: %4s(%d) Flags %04X Family %2d not AF_INET (2) or AF_INET6 (30)",
1031 ifa
->ifa_name
, if_nametoindex(ifa
->ifa_name
), ifa
->ifa_flags
, ifa
->ifa_addr
->sa_family
);
1032 if (!(ifa
->ifa_flags
& IFF_UP
))
1033 debugf("UpdateInterfaceList: %4s(%d) Flags %04X Family %2d Interface not IFF_UP",
1034 ifa
->ifa_name
, if_nametoindex(ifa
->ifa_name
), ifa
->ifa_flags
, ifa
->ifa_addr
->sa_family
);
1035 if (ifa
->ifa_flags
& IFF_POINTOPOINT
)
1036 debugf("UpdateInterfaceList: %4s(%d) Flags %04X Family %2d Interface IFF_POINTOPOINT",
1037 ifa
->ifa_name
, if_nametoindex(ifa
->ifa_name
), ifa
->ifa_flags
, ifa
->ifa_addr
->sa_family
);
1038 if (ifa
->ifa_flags
& IFF_LOOPBACK
)
1039 debugf("UpdateInterfaceList: %4s(%d) Flags %04X Family %2d Interface IFF_LOOPBACK",
1040 ifa
->ifa_name
, if_nametoindex(ifa
->ifa_name
), ifa
->ifa_flags
, ifa
->ifa_addr
->sa_family
);
1042 if ((ifa
->ifa_addr
->sa_family
== AF_INET
|| ifa
->ifa_addr
->sa_family
== AF_INET6
) &&
1043 (ifa
->ifa_flags
& IFF_MULTICAST
) &&
1044 (ifa
->ifa_flags
& IFF_UP
) && !(ifa
->ifa_flags
& IFF_POINTOPOINT
))
1046 int ifru_flags6
= 0;
1047 if (ifa
->ifa_addr
->sa_family
== AF_INET6
&& InfoSocket
>= 0)
1049 struct sockaddr_in6
*sin6
= (struct sockaddr_in6
*)ifa
->ifa_addr
;
1050 struct in6_ifreq ifr6
;
1051 bzero((char *)&ifr6
, sizeof(ifr6
));
1052 strncpy(ifr6
.ifr_name
, ifa
->ifa_name
, sizeof(ifr6
.ifr_name
));
1053 ifr6
.ifr_addr
= *sin6
;
1054 if (ioctl(InfoSocket
, SIOCGIFAFLAG_IN6
, &ifr6
) != -1)
1055 ifru_flags6
= ifr6
.ifr_ifru
.ifru_flags6
;
1056 verbosedebugf("%s %.16a %04X %04X", ifa
->ifa_name
, &sin6
->sin6_addr
, ifa
->ifa_flags
, ifru_flags6
);
1058 if (!(ifru_flags6
& (IN6_IFF_NOTREADY
| IN6_IFF_DETACHED
| IN6_IFF_DEPRECATED
| IN6_IFF_TEMPORARY
)))
1060 if (ifa
->ifa_flags
& IFF_LOOPBACK
)
1064 AddInterfaceToList(m
, ifa
);
1065 if (ifa
->ifa_addr
->sa_family
== AF_INET
)
1066 foundav4
= mDNStrue
;
1070 ifa
= ifa
->ifa_next
;
1073 // Temporary workaround: Multicast loopback on IPv6 interfaces appears not to work.
1074 // In the interim, we skip loopback interface only if we found at least one v4 interface to use
1075 if (!foundav4
&& theLoopback
)
1076 AddInterfaceToList(m
, theLoopback
);
1078 // Now the list is complete, set the TxAndRx setting for each interface.
1079 // We always send and receive using IPv4.
1080 // To reduce traffic, we send and receive using IPv6 only on interfaces that have no routable IPv4 address.
1081 // Having a routable IPv4 address assigned is a reasonable indicator of being on a large configured network,
1082 // which means there's a good chance that most or all the other devices on that network should also have v4.
1083 // By doing this we lose the ability to talk to true v6-only devices on that link, but we cut the packet rate in half.
1084 // At this time, reducing the packet rate is more important than v6-only devices on a large configured network,
1085 // so we are willing to make that sacrifice.
1086 NetworkInterfaceInfoOSX
*i
;
1087 for (i
= m
->p
->InterfaceList
; i
; i
= i
->next
)
1088 if (i
->CurrentlyActive
)
1090 mDNSBool txrx
= ((i
->ifinfo
.ip
.type
== mDNSAddrType_IPv4
) || !FindRoutableIPv4(m
, i
->scope_id
));
1091 if (i
->ifinfo
.TxAndRx
!= txrx
)
1093 i
->ifinfo
.TxAndRx
= txrx
;
1094 i
->CurrentlyActive
= 2; // State change; need to deregister and reregister this interface
1098 if (InfoSocket
>= 0) close(InfoSocket
);
1102 mDNSlocal NetworkInterfaceInfoOSX
*SearchForInterfaceByName(mDNS
*const m
, char *ifname
, int type
)
1104 NetworkInterfaceInfoOSX
*i
;
1105 for (i
= m
->p
->InterfaceList
; i
; i
= i
->next
)
1106 if (!strcmp(i
->ifa_name
, ifname
) &&
1108 (type
== AF_INET
&& i
->ifinfo
.ip
.type
== mDNSAddrType_IPv4
) ||
1109 (type
== AF_INET6
&& i
->ifinfo
.ip
.type
== mDNSAddrType_IPv6
) )) return(i
);
1113 mDNSlocal
void SetupActiveInterfaces(mDNS
*const m
)
1115 NetworkInterfaceInfoOSX
*i
;
1116 for (i
= m
->p
->InterfaceList
; i
; i
= i
->next
)
1119 NetworkInterfaceInfo
*n
= &i
->ifinfo
;
1120 NetworkInterfaceInfoOSX
*alias
= SearchForInterfaceByName(m
, i
->ifa_name
, i
->sa_family
);
1121 if (!alias
) alias
= i
;
1123 if (n
->InterfaceID
&& n
->InterfaceID
!= (mDNSInterfaceID
)alias
)
1125 LogMsg("SetupActiveInterfaces ERROR! n->InterfaceID %p != alias %p", n
->InterfaceID
, alias
);
1126 n
->InterfaceID
= mDNSNULL
;
1129 if (!n
->InterfaceID
)
1131 n
->InterfaceID
= (mDNSInterfaceID
)alias
;
1132 mDNS_RegisterInterface(m
, n
);
1133 debugf("SetupActiveInterfaces: Registered %s(%lu) InterfaceID %p %#a%s",
1134 i
->ifa_name
, i
->scope_id
, alias
, &n
->ip
, n
->InterfaceActive
? " (Primary)" : "");
1138 debugf("SetupActiveInterfaces: No TX/Rx on %s(%lu) InterfaceID %p %#a", i
->ifa_name
, i
->scope_id
, alias
, &n
->ip
);
1141 if (i
->sa_family
== AF_INET
&& alias
->sktv4
== -1)
1143 #if mDNS_AllowPort53
1144 err
= SetupSocket(i
, UnicastDNSPort
, &alias
->skt53
, &alias
->cfs53
);
1146 if (!err
) err
= SetupSocket(i
, MulticastDNSPort
, &alias
->sktv4
, &alias
->cfsv4
);
1147 if (err
== 0) debugf("SetupActiveInterfaces: v4 socket%2d %s(%lu) InterfaceID %p %#a", alias
->sktv4
, i
->ifa_name
, i
->scope_id
, n
->InterfaceID
, &n
->ip
);
1148 else LogMsg("SetupActiveInterfaces: v4 socket%2d %s(%lu) InterfaceID %p %#a FAILED", alias
->sktv4
, i
->ifa_name
, i
->scope_id
, n
->InterfaceID
, &n
->ip
);
1151 if (i
->sa_family
== AF_INET6
&& alias
->sktv6
== -1)
1153 err
= SetupSocket(i
, MulticastDNSPort
, &alias
->sktv6
, &alias
->cfsv6
);
1154 if (err
== 0) debugf("SetupActiveInterfaces: v6 socket%2d %s(%lu) InterfaceID %p %#a", alias
->sktv6
, i
->ifa_name
, i
->scope_id
, n
->InterfaceID
, &n
->ip
);
1155 else LogMsg("SetupActiveInterfaces: v6 socket%2d %s(%lu) InterfaceID %p %#a FAILED", alias
->sktv6
, i
->ifa_name
, i
->scope_id
, n
->InterfaceID
, &n
->ip
);
1161 mDNSlocal
void MarkAllInterfacesInactive(mDNS
*const m
)
1163 NetworkInterfaceInfoOSX
*i
;
1164 for (i
= m
->p
->InterfaceList
; i
; i
= i
->next
)
1165 i
->CurrentlyActive
= mDNSfalse
;
1168 mDNSlocal
void ClearInactiveInterfaces(mDNS
*const m
)
1171 // If an interface is going away, then deregister this from the mDNSCore.
1172 // We also have to deregister it if the alias interface that it's using for its InterfaceID is going away.
1173 // We have to do this because mDNSCore will use that InterfaceID when sending packets, and if the memory
1174 // it refers to has gone away we'll crash.
1175 // Don't actually close the sockets or free the memory yet: When the last representative of an interface goes away
1176 // mDNSCore may want to send goodbye packets on that interface. (Not yet implemented, but a good idea anyway.)
1177 NetworkInterfaceInfoOSX
*i
;
1178 for (i
= m
->p
->InterfaceList
; i
; i
= i
->next
)
1180 // 1. If this interface is no longer active, or it's InterfaceID is changing, deregister it
1181 NetworkInterfaceInfoOSX
*alias
= (NetworkInterfaceInfoOSX
*)(i
->ifinfo
.InterfaceID
);
1182 if (i
->ifinfo
.InterfaceID
&& (!i
->CurrentlyActive
|| (alias
&& !alias
->CurrentlyActive
) || i
->CurrentlyActive
== 2))
1184 debugf("ClearInactiveInterfaces: Deregistering %#a", &i
->ifinfo
.ip
);
1185 mDNS_DeregisterInterface(m
, &i
->ifinfo
);
1186 i
->ifinfo
.InterfaceID
= mDNSNULL
;
1191 // Now that everything that's going to deregister has done so, we can close sockets and free the memory
1192 NetworkInterfaceInfoOSX
**p
= &m
->p
->InterfaceList
;
1196 // 2. Close all our CFSockets. We'll recreate them later as necessary.
1197 // (We may have previously had both v4 and v6, and we may not need both any more.)
1198 // Note: MUST NOT close the underlying native BSD sockets.
1199 // CFSocketInvalidate() will do that for us, in its own good time, which may not necessarily be immediately,
1200 // because it first has to unhook the sockets from its select() call, before it can safely close them.
1201 #if mDNS_AllowPort53
1202 if (i
->cfs53
) { CFSocketInvalidate(i
->cfs53
); CFRelease(i
->cfs53
); }
1206 if (i
->cfsv4
) { CFSocketInvalidate(i
->cfsv4
); CFRelease(i
->cfsv4
); }
1207 if (i
->cfsv6
) { CFSocketInvalidate(i
->cfsv6
); CFRelease(i
->cfsv6
); }
1208 i
->sktv4
= i
->sktv6
= -1;
1209 i
->cfsv4
= i
->cfsv6
= NULL
;
1211 // 3. If no longer active, delete interface from list and free memory
1212 if (!i
->CurrentlyActive
)
1214 debugf("ClearInactiveInterfaces: Deleting %#a", &i
->ifinfo
.ip
);
1216 if (i
->ifa_name
) freeL("NetworkInterfaceInfoOSX name", i
->ifa_name
);
1217 freeL("NetworkInterfaceInfoOSX", i
);
1224 mDNSlocal
void NetworkChanged(SCDynamicStoreRef store
, CFArrayRef changedKeys
, void *context
)
1226 (void)store
; // Parameter not used
1227 (void)changedKeys
; // Parameter not used
1228 debugf("*** Network Configuration Change ***");
1230 mDNS
*const m
= (mDNS
*const)context
;
1231 MarkAllInterfacesInactive(m
);
1232 UpdateInterfaceList(m
);
1233 ClearInactiveInterfaces(m
);
1234 SetupActiveInterfaces(m
);
1236 if (m
->MainCallback
)
1237 m
->MainCallback(m
, mStatus_ConfigChanged
);
1240 mDNSlocal mStatus
WatchForNetworkChanges(mDNS
*const m
)
1243 SCDynamicStoreContext context
= { 0, m
, NULL
, NULL
, NULL
};
1244 SCDynamicStoreRef store
= SCDynamicStoreCreate(NULL
, CFSTR("mDNSResponder"), NetworkChanged
, &context
);
1245 CFStringRef key1
= SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL
, kSCDynamicStoreDomainState
, kSCEntNetIPv4
);
1246 CFStringRef key2
= SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL
, kSCDynamicStoreDomainState
, kSCEntNetIPv6
);
1247 CFStringRef key3
= SCDynamicStoreKeyCreateComputerName(NULL
);
1248 CFStringRef key4
= SCDynamicStoreKeyCreateHostNames(NULL
);
1249 CFStringRef pattern1
= SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL
, kSCDynamicStoreDomainState
, kSCCompAnyRegex
, kSCEntNetIPv4
);
1250 CFStringRef pattern2
= SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL
, kSCDynamicStoreDomainState
, kSCCompAnyRegex
, kSCEntNetIPv6
);
1252 CFMutableArrayRef keys
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
1253 CFMutableArrayRef patterns
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
1255 if (!store
) { LogMsg("SCDynamicStoreCreate failed: %s\n", SCErrorString(SCError())); goto error
; }
1256 if (!key1
|| !key2
|| !key3
|| !key4
|| !keys
|| !pattern1
|| !pattern2
|| !patterns
) goto error
;
1258 CFArrayAppendValue(keys
, key1
);
1259 CFArrayAppendValue(keys
, key2
);
1260 CFArrayAppendValue(keys
, key3
);
1261 CFArrayAppendValue(keys
, key4
);
1262 CFArrayAppendValue(patterns
, pattern1
);
1263 CFArrayAppendValue(patterns
, pattern2
);
1264 if (!SCDynamicStoreSetNotificationKeys(store
, keys
, patterns
))
1265 { LogMsg("SCDynamicStoreSetNotificationKeys failed: %s\n", SCErrorString(SCError())); goto error
; }
1267 m
->p
->StoreRLS
= SCDynamicStoreCreateRunLoopSource(NULL
, store
, 0);
1268 if (!m
->p
->StoreRLS
) { LogMsg("SCDynamicStoreCreateRunLoopSource failed: %s\n", SCErrorString(SCError())); goto error
; }
1270 CFRunLoopAddSource(CFRunLoopGetCurrent(), m
->p
->StoreRLS
, kCFRunLoopDefaultMode
);
1271 m
->p
->Store
= store
;
1276 if (store
) CFRelease(store
);
1279 if (key1
) CFRelease(key1
);
1280 if (key2
) CFRelease(key2
);
1281 if (key3
) CFRelease(key3
);
1282 if (key4
) CFRelease(key4
);
1283 if (pattern1
) CFRelease(pattern1
);
1284 if (pattern2
) CFRelease(pattern2
);
1285 if (keys
) CFRelease(keys
);
1286 if (patterns
) CFRelease(patterns
);
1291 mDNSlocal
void PowerChanged(void *refcon
, io_service_t service
, natural_t messageType
, void *messageArgument
)
1293 mDNS
*const m
= (mDNS
*const)refcon
;
1294 (void)service
; // Parameter not used
1297 case kIOMessageCanSystemPowerOff
: debugf("PowerChanged kIOMessageCanSystemPowerOff (no action)"); break; // E0000240
1298 case kIOMessageSystemWillPowerOff
: debugf("PowerChanged kIOMessageSystemWillPowerOff"); mDNSCoreMachineSleep(m
, true); break; // E0000250
1299 case kIOMessageSystemWillNotPowerOff
: debugf("PowerChanged kIOMessageSystemWillNotPowerOff (no action)"); break; // E0000260
1300 case kIOMessageCanSystemSleep
: debugf("PowerChanged kIOMessageCanSystemSleep (no action)"); break; // E0000270
1301 case kIOMessageSystemWillSleep
: debugf("PowerChanged kIOMessageSystemWillSleep"); mDNSCoreMachineSleep(m
, true); break; // E0000280
1302 case kIOMessageSystemWillNotSleep
: debugf("PowerChanged kIOMessageSystemWillNotSleep (no action)"); break; // E0000290
1303 case kIOMessageSystemHasPoweredOn
: debugf("PowerChanged kIOMessageSystemHasPoweredOn"); mDNSCoreMachineSleep(m
, false); break; // E0000300
1304 default: debugf("PowerChanged unknown message %X", messageType
); break;
1306 IOAllowPowerChange(m
->p
->PowerConnection
, (long)messageArgument
);
1309 mDNSlocal mStatus
WatchForPowerChanges(mDNS
*const m
)
1311 IONotificationPortRef thePortRef
;
1312 m
->p
->PowerConnection
= IORegisterForSystemPower(m
, &thePortRef
, PowerChanged
, &m
->p
->PowerNotifier
);
1313 if (m
->p
->PowerConnection
)
1315 m
->p
->PowerRLS
= IONotificationPortGetRunLoopSource(thePortRef
);
1316 CFRunLoopAddSource(CFRunLoopGetCurrent(), m
->p
->PowerRLS
, kCFRunLoopDefaultMode
);
1317 return(mStatus_NoError
);
1322 CF_EXPORT CFDictionaryRef
_CFCopySystemVersionDictionary(void);
1323 CF_EXPORT
const CFStringRef _kCFSystemVersionProductNameKey
;
1324 CF_EXPORT
const CFStringRef _kCFSystemVersionProductVersionKey
;
1325 CF_EXPORT
const CFStringRef _kCFSystemVersionBuildVersionKey
;
1327 mDNSexport mDNSBool
mDNSMacOSXSystemBuildNumber(char *HINFO_SWstring
)
1329 int major
= 0, minor
= 0;
1330 char letter
= 0, prodname
[256]="Mac OS X", prodvers
[256]="", buildver
[256]="?";
1331 CFDictionaryRef vers
= _CFCopySystemVersionDictionary();
1334 CFStringRef cfprodname
= CFDictionaryGetValue(vers
, _kCFSystemVersionProductNameKey
);
1335 CFStringRef cfprodvers
= CFDictionaryGetValue(vers
, _kCFSystemVersionProductVersionKey
);
1336 CFStringRef cfbuildver
= CFDictionaryGetValue(vers
, _kCFSystemVersionBuildVersionKey
);
1337 if (cfprodname
) CFStringGetCString(cfprodname
, prodname
, sizeof(prodname
), kCFStringEncodingUTF8
);
1338 if (cfprodvers
) CFStringGetCString(cfprodvers
, prodvers
, sizeof(prodvers
), kCFStringEncodingUTF8
);
1339 if (cfbuildver
) CFStringGetCString(cfbuildver
, buildver
, sizeof(buildver
), kCFStringEncodingUTF8
);
1340 sscanf(buildver
, "%d%c%d", &major
, &letter
, &minor
);
1343 if (HINFO_SWstring
) mDNS_snprintf(HINFO_SWstring
, 256, "%s %s (%s), %s", prodname
, prodvers
, buildver
, mDNSResponderVersionString
);
1347 mDNSlocal mStatus
mDNSPlatformInit_setup(mDNS
*const m
)
1351 m
->hostlabel
.c
[0] = 0;
1353 char *HINFO_HWstring
= "Macintosh";
1354 char HINFO_HWstring_buffer
[256];
1355 int get_model
[2] = { CTL_HW
, HW_MODEL
};
1356 size_t len_model
= sizeof(HINFO_HWstring_buffer
);
1357 if (sysctl(get_model
, 2, HINFO_HWstring_buffer
, &len_model
, NULL
, 0) == 0)
1358 HINFO_HWstring
= HINFO_HWstring_buffer
;
1360 char HINFO_SWstring
[256] = "";
1361 if (mDNSMacOSXSystemBuildNumber(HINFO_SWstring
) < 7) m
->KnownBugs
= mDNS_KnownBug_PhantomInterfaces
;
1363 mDNSu32 hlen
= mDNSPlatformStrLen(HINFO_HWstring
);
1364 mDNSu32 slen
= mDNSPlatformStrLen(HINFO_SWstring
);
1365 if (hlen
+ slen
< 254)
1367 m
->HIHardware
.c
[0] = hlen
;
1368 m
->HISoftware
.c
[0] = slen
;
1369 mDNSPlatformMemCopy(HINFO_HWstring
, &m
->HIHardware
.c
[1], hlen
);
1370 mDNSPlatformMemCopy(HINFO_SWstring
, &m
->HISoftware
.c
[1], slen
);
1373 m
->p
->InterfaceList
= mDNSNULL
;
1374 m
->p
->userhostlabel
.c
[0] = 0;
1375 UpdateInterfaceList(m
);
1376 SetupActiveInterfaces(m
);
1378 err
= WatchForNetworkChanges(m
);
1379 if (err
) return(err
);
1381 err
= WatchForPowerChanges(m
);
1385 mDNSexport mStatus
mDNSPlatformInit(mDNS
*const m
)
1387 mStatus result
= mDNSPlatformInit_setup(m
);
1388 // We don't do asynchronous initialization on OS X, so by the time we get here the setup will already
1389 // have succeeded or failed -- so if it succeeded, we should just call mDNSCoreInitComplete() immediately
1390 if (result
== mStatus_NoError
) mDNSCoreInitComplete(m
, mStatus_NoError
);
1394 mDNSexport
void mDNSPlatformClose(mDNS
*const m
)
1396 if (m
->p
->PowerConnection
)
1398 CFRunLoopRemoveSource(CFRunLoopGetCurrent(), m
->p
->PowerRLS
, kCFRunLoopDefaultMode
);
1399 CFRunLoopSourceInvalidate(m
->p
->PowerRLS
);
1400 CFRelease(m
->p
->PowerRLS
);
1401 IODeregisterForSystemPower(&m
->p
->PowerNotifier
);
1402 m
->p
->PowerConnection
= NULL
;
1403 m
->p
->PowerNotifier
= NULL
;
1404 m
->p
->PowerRLS
= NULL
;
1409 CFRunLoopRemoveSource(CFRunLoopGetCurrent(), m
->p
->StoreRLS
, kCFRunLoopDefaultMode
);
1410 CFRunLoopSourceInvalidate(m
->p
->StoreRLS
);
1411 CFRelease(m
->p
->StoreRLS
);
1412 CFRelease(m
->p
->Store
);
1414 m
->p
->StoreRLS
= NULL
;
1417 MarkAllInterfacesInactive(m
);
1418 ClearInactiveInterfaces(m
);
1421 mDNSexport mDNSs32 mDNSPlatformOneSecond
= 1000;
1423 mDNSexport mStatus
mDNSPlatformTimeInit(mDNSs32
*timenow
)
1425 // Notes: Typical values for mach_timebase_info:
1426 // tbi.numer = 1000 million
1427 // tbi.denom = 33 million
1428 // These are set such that (mach_absolute_time() * numer/denom) gives us nanoseconds;
1429 // numer / denom = nanoseconds per hardware clock tick (e.g. 30);
1430 // denom / numer = hardware clock ticks per nanosecond (e.g. 0.033)
1431 // (denom*1000000) / numer = hardware clock ticks per millisecond (e.g. 33333)
1432 // So: mach_absolute_time() / ((denom*1000000)/numer) = milliseconds
1434 // Arithmetic notes:
1435 // tbi.denom is at least 1, and not more than 2^32-1.
1436 // Therefore (tbi.denom * 1000000) is at least one million, but cannot overflow a uint64_t.
1437 // tbi.denom is at least 1, and not more than 2^32-1.
1438 // Therefore clockdivisor should end up being a number roughly in the range 10^3 - 10^9.
1439 // If clockdivisor is less than 10^3 then that means that the native clock frequency is less than 1MHz,
1440 // which is unlikely on any current or future Macintosh.
1441 // If clockdivisor is greater than 10^9 then that means the native clock frequency is greater than 1000GHz.
1442 // When we ship Macs with clock frequencies above 1000GHz, we may have to update this code.
1443 struct mach_timebase_info tbi
;
1444 kern_return_t result
= mach_timebase_info(&tbi
);
1445 if (result
!= KERN_SUCCESS
) return(result
);
1446 clockdivisor
= ((uint64_t)tbi
.denom
* 1000000) / tbi
.numer
;
1447 *timenow
= mDNSPlatformTimeNow();
1448 return(mStatus_NoError
);
1451 mDNSexport mDNSs32
mDNSPlatformTimeNow(void)
1453 if (clockdivisor
== 0) { LogMsg("mDNSPlatformTimeNow called before mDNSPlatformTimeInit"); return(0); }
1454 return((mDNSs32
)(mach_absolute_time() / clockdivisor
));
1457 // Locking is a no-op here, because we're single-threaded with a CFRunLoop, so we can never interrupt ourselves
1458 mDNSexport
void mDNSPlatformLock (const mDNS
*const m
) { (void)m
; }
1459 mDNSexport
void mDNSPlatformUnlock (const mDNS
*const m
) { (void)m
; }
1460 mDNSexport
void mDNSPlatformStrCopy(const void *src
, void *dst
) { strcpy((char *)dst
, (char *)src
); }
1461 mDNSexport mDNSu32
mDNSPlatformStrLen (const void *src
) { return(strlen((char*)src
)); }
1462 mDNSexport
void mDNSPlatformMemCopy(const void *src
, void *dst
, mDNSu32 len
) { memcpy(dst
, src
, len
); }
1463 mDNSexport mDNSBool
mDNSPlatformMemSame(const void *src
, const void *dst
, mDNSu32 len
) { return(memcmp(dst
, src
, len
) == 0); }
1464 mDNSexport
void mDNSPlatformMemZero( void *dst
, mDNSu32 len
) { bzero(dst
, len
); }
1465 mDNSexport
void * mDNSPlatformMemAllocate(mDNSu32 len
) { return(mallocL("mDNSPlatformMemAllocate", len
)); }
1466 mDNSexport
void mDNSPlatformMemFree (void *mem
) { freeL("mDNSPlatformMemFree", mem
); }