2 * Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
23 Change History (most recent first):
26 Revision 1.115 2003/09/10 00:45:55 cheshire
27 <rdar://problem/3412328> Don't log "sendto failed" errors during the first two minutes of startup
29 Revision 1.114 2003/08/27 02:55:13 cheshire
30 <rdar://problem/3387910>: Bug: Don't report mDNSPlatformSendUDP sendto errno 64 (Host is down)
32 Revision 1.113 2003/08/19 22:20:00 cheshire
33 <rdar://problem/3376721> Don't use IPv6 on interfaces that have a routable IPv4 address configured
34 More minor refinements
36 Revision 1.112 2003/08/19 03:04:43 cheshire
37 <rdar://problem/3376721> Don't use IPv6 on interfaces that have a routable IPv4 address configured
39 Revision 1.111 2003/08/18 22:53:37 cheshire
40 <rdar://problem/3382647> mDNSResponder divide by zero in mDNSPlatformTimeNow()
42 Revision 1.110 2003/08/16 03:39:00 cheshire
43 <rdar://problem/3338440> InterfaceID -1 indicates "local only"
45 Revision 1.109 2003/08/15 02:19:49 cheshire
46 <rdar://problem/3375225> syslog messages: myCFSocketCallBack recvfrom skt 6 error -1 errno 35
47 Also limit number of messages to at most 100
49 Revision 1.108 2003/08/12 22:24:52 cheshire
50 <rdar://problem/3375225> syslog messages: myCFSocketCallBack recvfrom skt 6 error -1 errno 35
51 This message indicates a kernel bug, but still we don't want to flood syslog.
52 Do a sleep(1) after writing this log message, to limit the rate.
54 Revision 1.107 2003/08/12 19:56:25 cheshire
57 Revision 1.106 2003/08/12 13:48:32 cheshire
58 Add comment explaining clockdivisor calculation
60 Revision 1.105 2003/08/12 13:44:14 cheshire
61 <rdar://problem/3370229> mDNSResponder *VERY* unhappy if time goes backwards
62 Use mach_absolute_time() (which is guaranteed to always go forwards, resetting only on reboot)
63 instead of gettimeofday() (which can jump back if the user manually changes their time/date)
65 Revision 1.104 2003/08/12 13:12:07 cheshire
66 Textual search/replace: Indicate local functions using "mDNSlocal" instead of "static"
68 Revision 1.103 2003/08/08 18:36:04 cheshire
69 <rdar://problem/3344154> Only need to revalidate on interface removal on platforms that have the PhantomInterfaces bug
71 Revision 1.102 2003/08/06 00:14:52 cheshire
72 <rdar://problem/3330324> Need to check IP TTL on responses
73 Also add corresponding checks in the IPv6 code path
75 Revision 1.101 2003/08/05 22:20:16 cheshire
76 <rdar://problem/3330324> Need to check IP TTL on responses
78 Revision 1.100 2003/08/05 21:18:50 cheshire
79 <rdar://problem/3363185> mDNSResponder should ignore 6to4
80 Only use interfaces that are marked as multicast-capable (IFF_MULTICAST)
82 Revision 1.99 2003/08/05 20:13:52 cheshire
83 <rdar://problem/3294080> mDNSResponder using IPv6 interfaces before they are ready
84 Ignore interfaces with the IN6_IFF_NOTREADY flag set
86 Revision 1.98 2003/07/20 03:38:51 ksekar
88 Completed support for Unix-domain socket based API.
90 Revision 1.97 2003/07/19 03:15:16 cheshire
91 Add generic MemAllocate/MemFree prototypes to mDNSPlatformFunctions.h,
92 and add the obvious trivial implementations to each platform support layer
94 Revision 1.96 2003/07/18 00:30:00 cheshire
95 <rdar://problem/3268878> Remove mDNSResponder version from packet header and use HINFO record instead
97 Revision 1.95 2003/07/12 03:15:20 cheshire
98 <rdar://problem/3324848> After SCDynamicStore notification, mDNSResponder updates
99 m->hostlabel even if user hasn't actually actually changed their dot-local hostname
101 Revision 1.94 2003/07/03 00:51:54 cheshire
102 <rdar://problem/3287213> When select() and recvmgs() disagree, get more info from kernel about the socket state
104 Revision 1.93 2003/07/03 00:09:14 cheshire
105 <rdar://problem/3286004> New APIs require a mDNSPlatformInterfaceIDfromInterfaceIndex() call
106 Additional refinement suggested by Josh: Use info->scope_id instead of if_nametoindex(info->ifa_name);
108 Revision 1.92 2003/07/02 21:19:51 cheshire
109 <rdar://problem/3313413> Update copyright notices, etc., in source code comments
111 Revision 1.91 2003/06/24 01:53:51 cheshire
112 Minor update to comments
114 Revision 1.90 2003/06/24 01:51:47 cheshire
115 <rdar://problem/3303118> Oops: Double-dispose of sockets
116 Don't need to close sockets: CFSocketInvalidate() does that for us
118 Revision 1.89 2003/06/21 18:12:47 cheshire
119 <rdar://problem/3296061> Rendezvous cannot handle interfaces whose total name is >3 chars
120 One-line change: should say "IF_NAMESIZE", not sizeof(ifname)
122 Revision 1.88 2003/06/12 23:38:37 cheshire
123 <rdar://problem/3291162> mDNSResponder doesn't detect some configuration changes
124 Also check that scope_id matches before concluding that two interfaces are the same
126 Revision 1.87 2003/06/10 01:14:11 cheshire
127 <rdar://problem/3286004> New APIs require a mDNSPlatformInterfaceIDfromInterfaceIndex() call
129 Revision 1.86 2003/05/28 02:41:52 cheshire
130 <rdar://problem/3034346> Time to remove Mac OS 9 UDP Port 53 legacy support
132 Revision 1.85 2003/05/28 02:39:47 cheshire
133 Minor change to debugging messages
135 Revision 1.84 2003/05/27 22:29:40 cheshire
136 Remove out-dated comment
138 Revision 1.83 2003/05/26 03:21:29 cheshire
139 Tidy up address structure naming:
140 mDNSIPAddr => mDNSv4Addr (for consistency with mDNSv6Addr)
141 mDNSAddr.addr.ipv4 => mDNSAddr.ip.v4
142 mDNSAddr.addr.ipv6 => mDNSAddr.ip.v6
144 Revision 1.82 2003/05/26 03:01:27 cheshire
145 <rdar://problem/3268904> sprintf/vsprintf-style functions are unsafe; use snprintf/vsnprintf instead
147 Revision 1.81 2003/05/24 02:06:42 cheshire
148 <rdar://problem/3268480> IPv6 Multicast Loopback doesn't work
149 Tried setting IPV6_MULTICAST_LOOP; it doesn't help.
150 However, it is probably wise to have the code explicitly set this socket
151 option anyway, in case the default changes in later versions of Unix.
153 Revision 1.80 2003/05/24 02:02:24 cheshire
154 <rdar://problem/3221880> if_indextoname consumes a lot of CPU
155 Fix error in myIfIndexToName; was returning prematurely
157 Revision 1.79 2003/05/23 23:07:44 cheshire
158 <rdar://problem/3268199> Must not write to stderr when running as daemon
160 Revision 1.78 2003/05/23 01:19:04 cheshire
161 <rdar://problem/3267085> mDNSResponder needs to signal type of service to AirPort
162 Mark packets as high-throughput/low-delay (i.e. lowest reliability) to get maximum 802.11 multicast rate
164 Revision 1.77 2003/05/23 01:12:05 cheshire
167 Revision 1.76 2003/05/22 01:26:01 cheshire
170 Revision 1.75 2003/05/22 00:07:09 cheshire
171 <rdar://problem/3264366> myCFSocketCallBack recvfrom(5) error 1, errno 35
172 Extra logging to determine whether there is a bug in CFSocket
174 Revision 1.74 2003/05/21 20:20:12 cheshire
175 Fix warnings (mainly printf format string warnings, like using "%d" where
176 it should say "%lu", etc.) and improve error logging (use strerror()
177 to include textual error message as well as numeric error in log messages).
179 Revision 1.73 2003/05/21 17:56:29 ksekar
180 Bug #: <rdar://problem/3191277>: mDNSResponder doesn't watch for IPv6 address changes
182 Revision 1.72 2003/05/14 18:48:41 cheshire
183 <rdar://problem/3159272> mDNSResponder should be smarter about reconfigurations
184 More minor refinements:
185 CFSocket.c needs to do *all* its mDNS_DeregisterInterface calls before freeing memory
186 mDNS_DeregisterInterface revalidates cache record when *any* representative of an interface goes away
188 Revision 1.71 2003/05/14 07:08:37 cheshire
189 <rdar://problem/3159272> mDNSResponder should be smarter about reconfigurations
190 Previously, when there was any network configuration change, mDNSResponder
191 would tear down the entire list of active interfaces and start again.
192 That was very disruptive, and caused the entire cache to be flushed,
193 and caused lots of extra network traffic. Now it only removes interfaces
194 that have really gone, and only adds new ones that weren't there before.
196 Revision 1.70 2003/05/07 18:30:24 cheshire
197 Fix signed/unsigned comparison warning
199 Revision 1.69 2003/05/06 20:14:44 cheshire
202 Revision 1.68 2003/05/06 00:00:49 cheshire
203 <rdar://problem/3248914> Rationalize naming of domainname manipulation functions
205 Revision 1.67 2003/04/29 00:43:44 cheshire
206 Fix compiler warnings
208 Revision 1.66 2003/04/26 02:41:58 cheshire
209 <rdar://problem/3241281> Change timenow from a local variable to a structure member
211 Revision 1.65 2003/04/26 02:34:01 cheshire
212 Add missing mDNSexport
214 Revision 1.64 2003/04/15 16:48:06 jgraessl
216 Modified code in CFSocket notifier function to read all packets on the socket
217 instead of reading only one packet every time the notifier was called.
219 Revision 1.63 2003/04/15 16:33:50 jgraessl
221 Switched to our own copy of if_indextoname to improve performance.
223 Revision 1.62 2003/03/28 01:55:44 cheshire
224 Minor improvements to debugging messages
226 Revision 1.61 2003/03/27 03:30:56 cheshire
227 <rdar://problem/3210018> Name conflicts not handled properly, resulting in memory corruption, and eventual crash
228 Problem was that HostNameCallback() was calling mDNS_DeregisterInterface(), which is not safe in a callback
230 1. Make mDNS_DeregisterInterface() safe to call from a callback
231 2. Make HostNameCallback() use mDNS_DeadvertiseInterface() instead
232 (it never really needed to deregister the interface at all)
234 Revision 1.60 2003/03/15 04:40:38 cheshire
235 Change type called "mDNSOpaqueID" to the more descriptive name "mDNSInterfaceID"
237 Revision 1.59 2003/03/11 01:23:26 cheshire
238 Bug #: 3194246 mDNSResponder socket problems
240 Revision 1.58 2003/03/06 01:43:04 cheshire
241 Bug #: 3189097 Additional debugging code in mDNSResponder
242 Improve "LIST_ALL_INTERFACES" output
244 Revision 1.57 2003/03/05 22:36:27 cheshire
245 Bug #: 3186338 Loopback doesn't work with mDNSResponder-27
246 Temporary workaround: Skip loopback interface *only* if we found at least one v4 interface to use
248 Revision 1.56 2003/03/05 01:50:38 cheshire
249 Bug #: 3189097 Additional debugging code in mDNSResponder
251 Revision 1.55 2003/02/21 01:54:09 cheshire
252 Bug #: 3099194 mDNSResponder needs performance improvements
253 Switched to using new "mDNS_Execute" model (see "Implementer Notes.txt")
255 Revision 1.54 2003/02/20 06:48:35 cheshire
256 Bug #: 3169535 Xserve RAID needs to do interface-specific registrations
257 Reviewed by: Josh Graessley, Bob Bradley
259 Revision 1.53 2003/01/29 02:21:23 cheshire
260 Return mStatus_Invalid if can't send packet because socket not available
262 Revision 1.52 2003/01/28 19:39:43 jgraessl
263 Enabling AAAA over IPv4 support.
265 Revision 1.51 2003/01/28 05:11:23 cheshire
266 Fixed backwards comparison in SearchForInterfaceByName
268 Revision 1.50 2003/01/13 23:49:44 jgraessl
269 Merged changes for the following fixes in to top of tree:
270 3086540 computer name changes not handled properly
271 3124348 service name changes are not properly handled
272 3124352 announcements sent in pairs, failing chattiness test
274 Revision 1.49 2002/12/23 22:13:30 jgraessl
275 Reviewed by: Stuart Cheshire
276 Initial IPv6 support for mDNSResponder.
278 Revision 1.48 2002/11/22 01:37:52 cheshire
279 Bug #: 3108426 mDNSResponder is monitoring ServiceEntities instead of InterfaceEntities
281 Revision 1.47 2002/09/21 20:44:51 zarzycki
284 Revision 1.46 2002/09/19 21:25:35 cheshire
285 mDNS_snprintf() doesn't need to be in a separate file
287 Revision 1.45 2002/09/17 01:45:13 cheshire
288 Add LIST_ALL_INTERFACES symbol for debugging
290 Revision 1.44 2002/09/17 01:36:23 cheshire
291 Move Puma support to CFSocketPuma.c
293 Revision 1.43 2002/09/17 01:05:28 cheshire
294 Change mDNS_AdvertiseLocalAddresses to be an Init parameter instead of a global
296 Revision 1.42 2002/09/16 23:13:50 cheshire
301 // ***************************************************************************
303 // Supporting routines to run mDNS on a CFRunLoop platform
304 // ***************************************************************************
306 // Open Transport 2.7.x on Mac OS 9 used to send Multicast DNS queries to UDP port 53,
307 // before the Multicast DNS port was changed to 5353. For this reason, the mDNSResponder
308 // in earlier versions of Mac OS X 10.2 Jaguar used to set mDNS_AllowPort53 to 1 to allow
309 // it to also listen and answer queries on UDP port 53. Now that Transport 2.8 (included in
310 // the Classic subsystem of Mac OS X 10.2 Jaguar) has been corrected to issue Multicast DNS
311 // queries on UDP port 5353, this backwards-compatibility legacy support is no longer needed.
312 #define mDNS_AllowPort53 0
314 // For debugging, set LIST_ALL_INTERFACES to 1 to display all found interfaces,
315 // including ones that mDNSResponder chooses not to use.
316 #define LIST_ALL_INTERFACES 0
318 // For enabling AAAA records over IPv4. Setting this to 0 sends only
319 // A records over IPv4 and AAAA over IPv6. Setting this to 1 sends both
320 // AAAA and A records over both IPv4 and IPv6.
321 #define AAAA_OVER_V4 1
323 #include "mDNSClientAPI.h" // Defines the interface provided to the client layer above
324 #include "mDNSPlatformFunctions.h" // Defines the interface to the supporting layer below
325 #include "mDNSMacOSX.h" // Defines the specific types needed to run mDNS on this platform
328 #include <unistd.h> // For select() and close()
329 #include <stdarg.h> // For va_list support
331 #include <net/if_dl.h>
333 #include <sys/param.h>
334 #include <sys/socket.h>
335 #include <sys/sysctl.h>
337 #include <sys/ioctl.h>
339 #include <netinet/in.h> // For IP_RECVTTL
341 #define IP_RECVTTL 24 /* bool; receive reception TTL w/dgram */
344 #include <netinet/in_systm.h> // For n_long, required by <netinet/ip.h> below
345 #include <netinet/ip.h> // For IPTOS_LOWDELAY etc.
346 #include <netinet6/in6_var.h> // For IN6_IFF_NOTREADY etc.
348 // Code contributed by Dave Heller:
349 // Define RUN_ON_PUMA_WITHOUT_IFADDRS to compile code that will
350 // work on Mac OS X 10.1, which does not have the getifaddrs call.
351 #define RUN_ON_PUMA_WITHOUT_IFADDRS 0
352 #if RUN_ON_PUMA_WITHOUT_IFADDRS
353 #include "CFSocketPuma.c"
358 #include <IOKit/IOKitLib.h>
359 #include <IOKit/IOMessage.h>
360 #include <mach/mach_time.h>
362 // ***************************************************************************
365 static mDNSu32 clockdivisor
= 0;
367 // ***************************************************************************
370 #define mDNSSameIPv4Address(A,B) ((A).NotAnInteger == (B).NotAnInteger)
371 #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])
373 #define mDNSAddressIsAllDNSLinkGroup(X) ( \
374 ((X)->type == mDNSAddrType_IPv4 && mDNSSameIPv4Address((X)->ip.v4, AllDNSLinkGroup )) || \
375 ((X)->type == mDNSAddrType_IPv6 && mDNSSameIPv6Address((X)->ip.v6, AllDNSLinkGroupv6)) )
377 // ***************************************************************************
380 // Note, this uses mDNS_vsnprintf instead of standard "vsnprintf", because mDNS_vsnprintf knows
381 // how to print special data types like IP addresses and length-prefixed domain names
383 mDNSexport
void debugf_(const char *format
, ...)
385 unsigned char buffer
[512];
387 va_start(ptr
,format
);
388 buffer
[mDNS_vsnprintf((char *)buffer
, sizeof(buffer
), format
, ptr
)] = 0;
390 fprintf(stderr
,"%s\n", buffer
);
395 #if MDNS_DEBUGMSGS > 1
396 mDNSexport
void verbosedebugf_(const char *format
, ...)
398 unsigned char buffer
[512];
400 va_start(ptr
,format
);
401 buffer
[mDNS_vsnprintf((char *)buffer
, sizeof(buffer
), format
, ptr
)] = 0;
403 fprintf(stderr
,"%s\n", buffer
);
408 mDNSexport
void LogMsg(const char *format
, ...)
410 unsigned char buffer
[512];
412 va_start(ptr
,format
);
413 buffer
[mDNS_vsnprintf((char *)buffer
, sizeof(buffer
), format
, ptr
)] = 0;
416 extern int debug_mode
;
417 if (debug_mode
) // In debug_mode we write to stderr
419 fprintf(stderr
,"%s\n", buffer
);
422 else // else, in production mode, we write to syslog
424 openlog("mDNSResponder", LOG_CONS
| LOG_PERROR
| LOG_PID
, LOG_DAEMON
);
425 syslog(LOG_ERR
, "%s", buffer
);
430 mDNSlocal
struct ifaddrs
* myGetIfAddrs(int refresh
)
432 static struct ifaddrs
*ifa
= NULL
;
440 if (ifa
== NULL
) getifaddrs(&ifa
);
445 mDNSlocal
int myIfIndexToName(u_short index
, char* name
)
448 for (ifa
= myGetIfAddrs(0); ifa
; ifa
= ifa
->ifa_next
)
449 if (ifa
->ifa_addr
->sa_family
== AF_LINK
)
450 if (((struct sockaddr_dl
*)ifa
->ifa_addr
)->sdl_index
== index
)
451 { strncpy(name
, ifa
->ifa_name
, IF_NAMESIZE
); return 0; }
455 mDNSexport mDNSInterfaceID
mDNSPlatformInterfaceIDfromInterfaceIndex(const mDNS
*const m
, mDNSu32 index
)
457 NetworkInterfaceInfoOSX
*i
;
458 if (index
== (uint32_t)~0) return((mDNSInterfaceID
)~0);
460 for (i
= m
->p
->InterfaceList
; i
; i
= i
->next
)
461 if (i
->scope_id
== index
)
462 return(i
->ifinfo
.InterfaceID
);
466 mDNSexport mDNSu32
mDNSPlatformInterfaceIndexfromInterfaceID(const mDNS
*const m
, mDNSInterfaceID id
)
468 NetworkInterfaceInfoOSX
*i
;
469 if (id
== (mDNSInterfaceID
)~0) return((mDNSu32
)~0);
471 for (i
= m
->p
->InterfaceList
; i
; i
= i
->next
)
472 if (i
->ifinfo
.InterfaceID
== id
)
477 mDNSexport mStatus
mDNSPlatformSendUDP(const mDNS
*const m
, const DNSMessage
*const msg
, const mDNSu8
*const end
,
478 mDNSInterfaceID InterfaceID
, mDNSIPPort srcPort
, const mDNSAddr
*dst
, mDNSIPPort dstPort
)
481 NetworkInterfaceInfoOSX
*info
= (NetworkInterfaceInfoOSX
*)InterfaceID
;
482 struct sockaddr_storage to
;
485 if (!InterfaceID
) { LogMsg("mDNSPlatformSendUDP ERROR! Cannot send from zero InterfaceID"); return mStatus_BadParamErr
; }
487 if (dst
->type
== mDNSAddrType_IPv4
)
489 struct sockaddr_in
* sin_to
= (struct sockaddr_in
*)&to
;
490 sin_to
->sin_len
= sizeof(*sin_to
);
491 sin_to
->sin_family
= AF_INET
;
492 sin_to
->sin_port
= dstPort
.NotAnInteger
;
493 sin_to
->sin_addr
.s_addr
= dst
->ip
.v4
.NotAnInteger
;
495 else if (dst
->type
== mDNSAddrType_IPv6
)
497 struct sockaddr_in6
* sin6_to
= (struct sockaddr_in6
*)&to
;
498 sin6_to
->sin6_len
= sizeof(*sin6_to
);
499 sin6_to
->sin6_family
= AF_INET6
;
500 sin6_to
->sin6_port
= dstPort
.NotAnInteger
;
501 sin6_to
->sin6_flowinfo
= 0;
502 sin6_to
->sin6_addr
= *(struct in6_addr
*)&dst
->ip
.v6
;
503 sin6_to
->sin6_scope_id
= info
->scope_id
;
507 LogMsg("mDNSPlatformSendUDP: dst is not an IPv4 or IPv6 address!\n");
508 return mStatus_BadParamErr
;
511 if (srcPort
.NotAnInteger
== MulticastDNSPort
.NotAnInteger
)
513 if (dst
->type
== mDNSAddrType_IPv4
) s
= info
->sktv4
;
514 else if (dst
->type
== mDNSAddrType_IPv6
) s
= info
->sktv6
;
518 else if (srcPort
.NotAnInteger
== UnicastDNSPort
.NotAnInteger
&& dst
->type
== mDNSAddrType_IPv4
)
521 else { LogMsg("Source port %d not allowed", (mDNSu16
)srcPort
.b
[0]<<8 | srcPort
.b
[1]); return(-1); }
524 verbosedebugf("mDNSPlatformSendUDP: sending on InterfaceID %X %s/%d to %#a:%d skt %d",
525 InterfaceID
, info
->ifa_name
, dst
->type
, dst
, (mDNSu16
)dstPort
.b
[0]<<8 | dstPort
.b
[1], s
);
527 verbosedebugf("mDNSPlatformSendUDP: NOT sending on InterfaceID %X %s/%d (socket of this type not available)",
528 InterfaceID
, info
->ifa_name
, dst
->type
, dst
, (mDNSu16
)dstPort
.b
[0]<<8 | dstPort
.b
[1]);
530 // Note: When sending, mDNSCore may often ask us to send both a v4 multicast packet and then a v6 multicast packet
531 // If we don't have the corresponding type of socket available, then return mStatus_Invalid
532 if (s
< 0) return(mStatus_Invalid
);
534 err
= sendto(s
, msg
, (UInt8
*)end
- (UInt8
*)msg
, 0, (struct sockaddr
*)&to
, to
.ss_len
);
537 // Don't report EHOSTDOWN (i.e. ARP failure) to unicast destinations
538 if (errno
== EHOSTDOWN
&& !mDNSAddressIsAllDNSLinkGroup(dst
)) return(err
);
539 // Don't report EHOSTUNREACH in the first two minutes after boot
540 // This is because mDNSResponder intentionally starts up early in the boot process (See <rdar://problem/3409090>)
541 // but this means that sometimes it starts before configd has finished setting up the multicast routing entries.
542 if (errno
== EHOSTUNREACH
&& (mDNSu32
)(m
->timenow
) < (mDNSu32
)(mDNSPlatformOneSecond
* 120)) return(err
);
543 LogMsg("mDNSPlatformSendUDP sendto failed to send packet on InterfaceID %p %s/%ld to %#a:%d skt %d error %d errno %d (%s)",
544 InterfaceID
, info
->ifa_name
, dst
->type
, dst
, (mDNSu16
)dstPort
.b
[0]<<8 | dstPort
.b
[1], s
, err
, errno
, strerror(errno
));
548 return(mStatus_NoError
);
551 mDNSlocal ssize_t
myrecvfrom(const int s
, void *const buffer
, const size_t max
,
552 struct sockaddr
*const from
, size_t *const fromlen
, mDNSAddr
*dstaddr
, char ifname
[IF_NAMESIZE
], mDNSu8
*ttl
)
554 static unsigned int numLogMessages
= 0;
555 struct iovec databuffers
= { (char *)buffer
, max
};
558 struct cmsghdr
*cmPtr
;
559 char ancillary
[1024];
561 *ttl
= 255; // If kernel fails to provide TTL data (e.g. Jaguar doesn't) then assume the TTL was 255 as it should be
563 // Set up the message
564 msg
.msg_name
= (caddr_t
)from
;
565 msg
.msg_namelen
= *fromlen
;
566 msg
.msg_iov
= &databuffers
;
568 msg
.msg_control
= (caddr_t
)&ancillary
;
569 msg
.msg_controllen
= sizeof(ancillary
);
573 n
= recvmsg(s
, &msg
, 0);
576 if (errno
!= EWOULDBLOCK
&& numLogMessages
++ < 100) LogMsg("CFSocket.c: recvmsg(%d) returned error %d errno %d", s
, n
, errno
);
579 if (msg
.msg_controllen
< (int)sizeof(struct cmsghdr
))
581 if (numLogMessages
++ < 100) LogMsg("CFSocket.c: recvmsg(%d) msg.msg_controllen %d < sizeof(struct cmsghdr) %lu",
582 s
, msg
.msg_controllen
, sizeof(struct cmsghdr
));
585 if (msg
.msg_flags
& MSG_CTRUNC
)
587 if (numLogMessages
++ < 100) LogMsg("CFSocket.c: recvmsg(%d) msg.msg_flags & MSG_CTRUNC", s
);
591 *fromlen
= msg
.msg_namelen
;
593 // Parse each option out of the ancillary data.
594 for (cmPtr
= CMSG_FIRSTHDR(&msg
); cmPtr
; cmPtr
= CMSG_NXTHDR(&msg
, cmPtr
))
596 // debugf("myrecvfrom cmsg_level %d cmsg_type %d", cmPtr->cmsg_level, cmPtr->cmsg_type);
597 if (cmPtr
->cmsg_level
== IPPROTO_IP
&& cmPtr
->cmsg_type
== IP_RECVDSTADDR
)
599 dstaddr
->type
= mDNSAddrType_IPv4
;
600 dstaddr
->ip
.v4
.NotAnInteger
= *(u_int32_t
*)CMSG_DATA(cmPtr
);
602 if (cmPtr
->cmsg_level
== IPPROTO_IP
&& cmPtr
->cmsg_type
== IP_RECVIF
)
604 struct sockaddr_dl
*sdl
= (struct sockaddr_dl
*)CMSG_DATA(cmPtr
);
605 if (sdl
->sdl_nlen
< IF_NAMESIZE
)
607 mDNSPlatformMemCopy(sdl
->sdl_data
, ifname
, sdl
->sdl_nlen
);
608 ifname
[sdl
->sdl_nlen
] = 0;
609 // debugf("IP_RECVIF sdl_index %d, sdl_data %s len %d", sdl->sdl_index, ifname, sdl->sdl_nlen);
612 if (cmPtr
->cmsg_level
== IPPROTO_IP
&& cmPtr
->cmsg_type
== IP_RECVTTL
)
614 *ttl
= *(u_char
*)CMSG_DATA(cmPtr
);
616 if (cmPtr
->cmsg_level
== IPPROTO_IPV6
&& cmPtr
->cmsg_type
== IPV6_PKTINFO
)
618 struct in6_pktinfo
*ip6_info
= (struct in6_pktinfo
*)CMSG_DATA(cmPtr
);
619 dstaddr
->type
= mDNSAddrType_IPv6
;
620 dstaddr
->ip
.v6
= *(mDNSv6Addr
*)&ip6_info
->ipi6_addr
;
621 myIfIndexToName(ip6_info
->ipi6_ifindex
, ifname
);
623 if (cmPtr
->cmsg_level
== IPPROTO_IPV6
&& cmPtr
->cmsg_type
== IPV6_HOPLIMIT
)
625 *ttl
= *(int*)CMSG_DATA(cmPtr
);
632 mDNSlocal
void myCFSocketCallBack(CFSocketRef cfs
, CFSocketCallBackType CallBackType
, CFDataRef address
, const void *data
, void *context
)
634 mDNSAddr senderAddr
, destAddr
;
635 mDNSIPPort senderPort
, destPort
= MulticastDNSPort
;
636 NetworkInterfaceInfoOSX
*info
= (NetworkInterfaceInfoOSX
*)context
;
637 mDNS
*const m
= info
->m
;
639 struct sockaddr_storage from
;
640 size_t fromlen
= sizeof(from
);
641 char packetifname
[IF_NAMESIZE
] = "";
642 int err
, s1
= -1, skt
= CFSocketGetNative(cfs
);
645 (void)address
; // Parameter not used
646 (void)data
; // Parameter not used
648 if (CallBackType
!= kCFSocketReadCallBack
) LogMsg("myCFSocketCallBack: Why is CallBackType %d not kCFSocketReadCallBack?", CallBackType
);
651 if (cfs
== info
->cfs53
) { s1
= info
->skt53
; destPort
= UnicastDNSPort
; }
654 if (cfs
== info
->cfsv4
) s1
= info
->sktv4
;
655 else if (cfs
== info
->cfsv6
) s1
= info
->sktv6
;
657 if (s1
< 0 || s1
!= skt
)
659 LogMsg("myCFSocketCallBack: s1 %d native socket %d, cfs %p", s1
, skt
, cfs
);
661 LogMsg("myCFSocketCallBack: cfs53 %p, skt53 %d", info
->cfs53
, info
->skt53
);
663 LogMsg("myCFSocketCallBack: cfsv4 %p, sktv4 %d", info
->cfsv4
, info
->sktv4
);
664 LogMsg("myCFSocketCallBack: cfsv6 %p, sktv6 %d", info
->cfsv6
, info
->sktv6
);
668 while ((err
= myrecvfrom(s1
, &packet
, sizeof(packet
), (struct sockaddr
*)&from
, &fromlen
, &destAddr
, packetifname
, &ttl
)) >= 0)
671 if (from
.ss_family
== AF_INET
)
673 struct sockaddr_in
*sin
= (struct sockaddr_in
*)&from
;
674 senderAddr
.type
= mDNSAddrType_IPv4
;
675 senderAddr
.ip
.v4
.NotAnInteger
= sin
->sin_addr
.s_addr
;
676 senderPort
.NotAnInteger
= sin
->sin_port
;
678 else if (from
.ss_family
== AF_INET6
)
680 struct sockaddr_in6
*sin6
= (struct sockaddr_in6
*)&from
;
681 senderAddr
.type
= mDNSAddrType_IPv6
;
682 senderAddr
.ip
.v6
= *(mDNSv6Addr
*)&sin6
->sin6_addr
;
683 senderPort
.NotAnInteger
= sin6
->sin6_port
;
687 LogMsg("myCFSocketCallBack from is unknown address family %d", from
.ss_family
);
691 // Even though we indicated a specific interface in the IP_ADD_MEMBERSHIP call, a weirdness of the
692 // sockets API means that even though this socket has only officially joined the multicast group
693 // on one specific interface, the kernel will still deliver multicast packets to it no matter which
694 // interface they arrive on. According to the official Unix Powers That Be, this is Not A Bug.
695 // To work around this weirdness, we use the IP_RECVIF option to find the name of the interface
696 // on which the packet arrived, and ignore the packet if it really arrived on some other interface.
697 if (strcmp(info
->ifa_name
, packetifname
))
699 verbosedebugf("myCFSocketCallBack got a packet from %#a to %#a on interface %#a/%s (Ignored -- really arrived on interface %s)",
700 &senderAddr
, &destAddr
, &info
->ifinfo
.ip
, info
->ifa_name
, packetifname
);
704 verbosedebugf("myCFSocketCallBack got a packet from %#a to %#a on interface %#a/%s",
705 &senderAddr
, &destAddr
, &info
->ifinfo
.ip
, info
->ifa_name
);
707 if (err
< (int)sizeof(DNSMessageHeader
)) { debugf("myCFSocketCallBack packet length (%d) too short", err
); return; }
709 mDNSCoreReceive(m
, &packet
, (unsigned char*)&packet
+ err
, &senderAddr
, senderPort
, &destAddr
, destPort
, info
->ifinfo
.InterfaceID
, ttl
);
712 if (err
< 0 && (errno
!= EWOULDBLOCK
|| count
== 0))
714 // Something is busted here.
715 // CFSocket says there is a packet, but myrecvfrom says there is not.
716 // Try calling select() to get another opinion.
717 // Find out about other socket parameter that can help understand why select() says the socket is ready for read
718 // All of this is racy, as data may have arrived after the call to select()
719 int save_errno
= errno
;
723 int solen
= sizeof(int);
726 FD_SET(s1
, &readfds
);
727 struct timeval timeout
;
730 int selectresult
= select(s1
+1, &readfds
, NULL
, NULL
, &timeout
);
731 if (getsockopt(s1
, SOL_SOCKET
, SO_ERROR
, &so_error
, &solen
) == -1)
732 LogMsg("myCFSocketCallBack getsockopt(SO_ERROR) error %d", errno
);
733 if (getsockopt(s1
, SOL_SOCKET
, SO_NREAD
, &so_nread
, &solen
) == -1)
734 LogMsg("myCFSocketCallBack getsockopt(SO_NREAD) error %d", errno
);
735 if (ioctl(s1
, FIONREAD
, &fionread
) == -1)
736 LogMsg("myCFSocketCallBack ioctl(FIONREAD) error %d", errno
);
737 static unsigned int numLogMessages
= 0;
738 if (numLogMessages
++ < 100)
739 LogMsg("myCFSocketCallBack recvfrom skt %d error %d errno %d (%s) select %d (%spackets waiting) so_error %d so_nread %d fionread %d count %d",
740 s1
, err
, save_errno
, strerror(save_errno
), selectresult
, FD_ISSET(s1
, &readfds
) ? "" : "*NO* ", so_error
, so_nread
, fionread
, count
);
741 sleep(1); // After logging this error, rate limit so we don't flood syslog
745 // This gets the text of the field currently labelled "Computer Name" in the Sharing Prefs Control Panel
746 mDNSlocal
void GetUserSpecifiedFriendlyComputerName(domainlabel
*const namelabel
)
748 CFStringEncoding encoding
= kCFStringEncodingUTF8
;
749 CFStringRef cfs
= SCDynamicStoreCopyComputerName(NULL
, &encoding
);
752 CFStringGetPascalString(cfs
, namelabel
->c
, sizeof(*namelabel
), kCFStringEncodingUTF8
);
757 // This gets the text of the field currently labelled "Rendezvous Name" in the Sharing Prefs Control Panel
758 mDNSlocal
void GetUserSpecifiedRFC1034ComputerName(domainlabel
*const namelabel
)
760 CFStringRef cfs
= SCDynamicStoreCopyLocalHostName(NULL
);
763 CFStringGetPascalString(cfs
, namelabel
->c
, sizeof(*namelabel
), kCFStringEncodingUTF8
);
768 mDNSlocal mStatus
SetupSocket(NetworkInterfaceInfoOSX
*i
, mDNSIPPort port
, int *s
, CFSocketRef
*c
)
771 const int twofivefive
= 255;
773 if (*s
>= 0) { LogMsg("SetupSocket ERROR: socket %d is already set", *s
); return(-1); }
774 if (*c
) { LogMsg("SetupSocket ERROR: CFSocketRef %p is already set", *c
); return(-1); }
776 // Open the socket...
777 int skt
= socket(i
->sa_family
, SOCK_DGRAM
, IPPROTO_UDP
);
778 if (skt
< 0) { LogMsg("socket error %d errno %d (%s)", skt
, errno
, strerror(errno
)); return(skt
); }
780 // ... with a shared UDP port
781 mStatus err
= setsockopt(skt
, SOL_SOCKET
, SO_REUSEPORT
, &on
, sizeof(on
));
782 if (err
< 0) { LogMsg("setsockopt - SO_REUSEPORT error %ld errno %d (%s)", err
, errno
, strerror(errno
)); return(err
); }
784 if (i
->sa_family
== AF_INET
)
786 // We want to receive destination addresses
787 err
= setsockopt(skt
, IPPROTO_IP
, IP_RECVDSTADDR
, &on
, sizeof(on
));
788 if (err
< 0) { LogMsg("setsockopt - IP_RECVDSTADDR error %ld errno %d (%s)", err
, errno
, strerror(errno
)); return(err
); }
790 // We want to receive interface identifiers
791 err
= setsockopt(skt
, IPPROTO_IP
, IP_RECVIF
, &on
, sizeof(on
));
792 if (err
< 0) { LogMsg("setsockopt - IP_RECVIF error %ld errno %d (%s)", err
, errno
, strerror(errno
)); return(err
); }
794 // We want to receive packet TTL value so we can check it
795 err
= setsockopt(skt
, IPPROTO_IP
, IP_RECVTTL
, &on
, sizeof(on
));
796 // We ignore errors here -- we already know Jaguar doesn't support this, but we can get by without it
798 // Add multicast group membership on this interface
799 struct in_addr addr
= { i
->ifinfo
.ip
.ip
.v4
.NotAnInteger
};
801 imr
.imr_multiaddr
.s_addr
= AllDNSLinkGroup
.NotAnInteger
;
802 imr
.imr_interface
= addr
;
803 err
= setsockopt(skt
, IPPROTO_IP
, IP_ADD_MEMBERSHIP
, &imr
, sizeof(imr
));
804 if (err
< 0) { LogMsg("setsockopt - IP_ADD_MEMBERSHIP error %ld errno %d (%s)", err
, errno
, strerror(errno
)); return(err
); }
806 // Specify outgoing interface too
807 err
= setsockopt(skt
, IPPROTO_IP
, IP_MULTICAST_IF
, &addr
, sizeof(addr
));
808 if (err
< 0) { LogMsg("setsockopt - IP_MULTICAST_IF error %ld errno %d (%s)", err
, errno
, strerror(errno
)); return(err
); }
810 // Send unicast packets with TTL 255
811 err
= setsockopt(skt
, IPPROTO_IP
, IP_TTL
, &twofivefive
, sizeof(twofivefive
));
812 if (err
< 0) { LogMsg("setsockopt - IP_TTL error %ld errno %d (%s)", err
, errno
, strerror(errno
)); return(err
); }
814 // And multicast packets with TTL 255 too
815 err
= setsockopt(skt
, IPPROTO_IP
, IP_MULTICAST_TTL
, &twofivefive
, sizeof(twofivefive
));
816 if (err
< 0) { LogMsg("setsockopt - IP_MULTICAST_TTL error %ld errno %d (%s)", err
, errno
, strerror(errno
)); return(err
); }
818 // Mark packets as high-throughput/low-delay (i.e. lowest reliability) to get maximum 802.11 multicast rate
819 const int ip_tosbits
= IPTOS_LOWDELAY
| IPTOS_THROUGHPUT
;
820 err
= setsockopt(skt
, IPPROTO_IP
, IP_TOS
, &ip_tosbits
, sizeof(ip_tosbits
));
821 if (err
< 0) { LogMsg("setsockopt - IP_TOS error %ld errno %d (%s)", err
, errno
, strerror(errno
)); return(err
); }
823 // And start listening for packets
824 struct sockaddr_in listening_sockaddr
;
825 listening_sockaddr
.sin_family
= AF_INET
;
826 listening_sockaddr
.sin_port
= port
.NotAnInteger
;
827 listening_sockaddr
.sin_addr
.s_addr
= 0; // Want to receive multicasts AND unicasts on this socket
828 err
= bind(skt
, (struct sockaddr
*) &listening_sockaddr
, sizeof(listening_sockaddr
));
831 // If we fail to bind to port 53 (because we're not root), that's okay, just tidy up and silently continue
832 if (port
.NotAnInteger
== UnicastDNSPort
.NotAnInteger
) { close(skt
); err
= 0; }
833 else LogMsg("bind error %ld errno %d (%s)", err
, errno
, strerror(errno
));
837 else if (i
->sa_family
== AF_INET6
)
839 // We want to receive destination addresses and receive interface identifiers
840 err
= setsockopt(skt
, IPPROTO_IPV6
, IPV6_PKTINFO
, &on
, sizeof(on
));
841 if (err
< 0) { LogMsg("setsockopt - IPV6_PKTINFO error %ld errno %d (%s)", err
, errno
, strerror(errno
)); return(err
); }
843 // We want to receive packet hop count value so we can check it
844 err
= setsockopt(skt
, IPPROTO_IPV6
, IPV6_HOPLIMIT
, &on
, sizeof(on
));
845 if (err
< 0) { LogMsg("setsockopt - IPV6_HOPLIMIT error %ld errno %d (%s)", err
, errno
, strerror(errno
)); return(err
); }
847 // We want to receive only IPv6 packets, without this option, we may
848 // get IPv4 addresses as mapped addresses.
849 err
= setsockopt(skt
, IPPROTO_IPV6
, IPV6_V6ONLY
, &on
, sizeof(on
));
850 if (err
< 0) { LogMsg("setsockopt - IPV6_V6ONLY error %ld errno %d (%s)", err
, errno
, strerror(errno
)); return(err
); }
852 // Add multicast group membership on this interface
853 int interface_id
= if_nametoindex(i
->ifa_name
);
854 struct ipv6_mreq i6mr
;
855 i6mr
.ipv6mr_interface
= interface_id
;
856 i6mr
.ipv6mr_multiaddr
= *(struct in6_addr
*)&AllDNSLinkGroupv6
;
857 err
= setsockopt(skt
, IPPROTO_IPV6
, IPV6_JOIN_GROUP
, &i6mr
, sizeof(i6mr
));
858 if (err
< 0) { LogMsg("setsockopt - IPV6_JOIN_GROUP error %ld errno %d (%s)", err
, errno
, strerror(errno
)); return(err
); }
860 // Specify outgoing interface too
861 err
= setsockopt(skt
, IPPROTO_IPV6
, IPV6_MULTICAST_IF
, &interface_id
, sizeof(interface_id
));
862 if (err
< 0) { LogMsg("setsockopt - IPV6_MULTICAST_IF error %ld errno %d (%s)", err
, errno
, strerror(errno
)); return(err
); }
864 // Send unicast packets with TTL 255
865 err
= setsockopt(skt
, IPPROTO_IPV6
, IPV6_UNICAST_HOPS
, &twofivefive
, sizeof(twofivefive
));
866 if (err
< 0) { LogMsg("setsockopt - IPV6_UNICAST_HOPS error %ld errno %d (%s)", err
, errno
, strerror(errno
)); return(err
); }
868 // And multicast packets with TTL 255 too
869 err
= setsockopt(skt
, IPPROTO_IPV6
, IPV6_MULTICAST_HOPS
, &twofivefive
, sizeof(twofivefive
));
870 if (err
< 0) { LogMsg("setsockopt - IPV6_MULTICAST_HOPS error %ld errno %d (%s)", err
, errno
, strerror(errno
)); return(err
); }
872 // Note: IPV6_TCLASS appears not to be implemented on OS X right now (or indeed on ANY version of Unix?)
874 // Mark packets as high-throughput/low-delay (i.e. lowest reliability) to get maximum 802.11 multicast rate
875 int tclass
= IPTOS_LOWDELAY
| IPTOS_THROUGHPUT
; // This may not be right (since tclass is not implemented on OS X, I can't test it)
876 err
= setsockopt(skt
, IPPROTO_IPV6
, IPV6_TCLASS
, &tclass
, sizeof(tclass
));
877 if (err
< 0) { LogMsg("setsockopt - IPV6_TCLASS error %ld errno %d (%s)", err
, errno
, strerror(errno
)); return(err
); }
880 // Want to receive our own packets
881 err
= setsockopt(skt
, IPPROTO_IPV6
, IPV6_MULTICAST_LOOP
, &on
, sizeof(on
));
882 if (err
< 0) { LogMsg("setsockopt - IPV6_MULTICAST_LOOP error %ld errno %d (%s)", err
, errno
, strerror(errno
)); return(err
); }
884 // And start listening for packets
885 struct sockaddr_in6 listening_sockaddr6
;
886 bzero(&listening_sockaddr6
, sizeof(listening_sockaddr6
));
887 listening_sockaddr6
.sin6_len
= sizeof(listening_sockaddr6
);
888 listening_sockaddr6
.sin6_family
= AF_INET6
;
889 listening_sockaddr6
.sin6_port
= port
.NotAnInteger
;
890 listening_sockaddr6
.sin6_flowinfo
= 0;
891 // listening_sockaddr6.sin6_addr = IN6ADDR_ANY_INIT; // Want to receive multicasts AND unicasts on this socket
892 listening_sockaddr6
.sin6_scope_id
= 0;
893 err
= bind(skt
, (struct sockaddr
*) &listening_sockaddr6
, sizeof(listening_sockaddr6
));
894 if (err
) { LogMsg("bind error %ld errno %d (%s)", err
, errno
, strerror(errno
)); return(err
); }
897 fcntl(skt
, F_SETFL
, fcntl(skt
, F_GETFL
, 0) | O_NONBLOCK
); // set non-blocking
899 CFSocketContext myCFSocketContext
= { 0, i
->ifinfo
.InterfaceID
, NULL
, NULL
, NULL
};
900 *c
= CFSocketCreateWithNative(kCFAllocatorDefault
, *s
, kCFSocketReadCallBack
, myCFSocketCallBack
, &myCFSocketContext
);
901 CFRunLoopSourceRef rls
= CFSocketCreateRunLoopSource(kCFAllocatorDefault
, *c
, 0);
902 CFRunLoopAddSource(CFRunLoopGetCurrent(), rls
, kCFRunLoopDefaultMode
);
908 mDNSlocal mStatus
SetupAddr(mDNSAddr
*ip
, const struct sockaddr
*const sa
)
910 if (sa
->sa_family
== AF_INET
)
912 struct sockaddr_in
*ifa_addr
= (struct sockaddr_in
*)sa
;
913 ip
->type
= mDNSAddrType_IPv4
;
914 ip
->ip
.v4
.NotAnInteger
= ifa_addr
->sin_addr
.s_addr
;
917 else if (sa
->sa_family
== AF_INET6
)
919 struct sockaddr_in6
*ifa_addr
= (struct sockaddr_in6
*)sa
;
920 ip
->type
= mDNSAddrType_IPv6
;
921 if (IN6_IS_ADDR_LINKLOCAL(&ifa_addr
->sin6_addr
)) ifa_addr
->sin6_addr
.__u6_addr
.__u6_addr16
[1] = 0;
922 ip
->ip
.v6
= *(mDNSv6Addr
*)&ifa_addr
->sin6_addr
;
927 LogMsg("SetupAddr invalid sa_family %d", sa
->sa_family
);
932 mDNSlocal mStatus
AddInterfaceToList(mDNS
*const m
, struct ifaddrs
*ifa
)
934 mDNSu32 scope_id
= if_nametoindex(ifa
->ifa_name
);
936 SetupAddr(&ip
, ifa
->ifa_addr
);
937 NetworkInterfaceInfoOSX
**p
;
938 for (p
= &m
->p
->InterfaceList
; *p
; p
= &(*p
)->next
)
939 if (scope_id
== (*p
)->scope_id
&& mDNSSameAddress(&ip
, &(*p
)->ifinfo
.ip
))
941 debugf("AddInterfaceToList: Found existing interface %u with address %#a", scope_id
, &ip
);
942 (*p
)->CurrentlyActive
= mDNStrue
;
946 debugf("AddInterfaceToList: Making new interface %u with address %#a", scope_id
, &ip
);
947 NetworkInterfaceInfoOSX
*i
= (NetworkInterfaceInfoOSX
*)mallocL("NetworkInterfaceInfoOSX", sizeof(*i
));
949 i
->ifa_name
= (char *)mallocL("NetworkInterfaceInfoOSX name", strlen(ifa
->ifa_name
) + 1);
950 if (!i
->ifa_name
) { freeL("NetworkInterfaceInfoOSX", i
); return(-1); }
951 strcpy(i
->ifa_name
, ifa
->ifa_name
);
953 i
->ifinfo
.InterfaceID
= mDNSNULL
;
955 i
->ifinfo
.Advertise
= m
->AdvertiseLocalAddresses
;
956 i
->ifinfo
.TxAndRx
= mDNSfalse
; // For now; will be set up later at the end of UpdateInterfaceList
960 i
->scope_id
= scope_id
;
961 i
->CurrentlyActive
= mDNStrue
;
962 i
->sa_family
= ifa
->ifa_addr
->sa_family
;
972 if (!i
->ifa_name
) return(-1);
977 mDNSlocal NetworkInterfaceInfoOSX
*FindRoutableIPv4(mDNS
*const m
, mDNSu32 scope_id
)
979 NetworkInterfaceInfoOSX
*i
;
980 for (i
= m
->p
->InterfaceList
; i
; i
= i
->next
)
981 if (i
->CurrentlyActive
&& i
->scope_id
== scope_id
&& i
->ifinfo
.ip
.type
== mDNSAddrType_IPv4
)
982 if (!(i
->ifinfo
.ip
.ip
.v4
.b
[0] == 169 && i
->ifinfo
.ip
.ip
.v4
.b
[1] == 254))
987 mDNSlocal mStatus
UpdateInterfaceList(mDNS
*const m
)
989 mDNSBool foundav4
= mDNSfalse
;
990 struct ifaddrs
*ifa
= myGetIfAddrs(1);
991 struct ifaddrs
*theLoopback
= NULL
;
992 int err
= (ifa
!= NULL
) ? 0 : (errno
!= 0 ? errno
: -1);
993 int InfoSocket
= err
? -1 : socket(AF_INET6
, SOCK_DGRAM
, 0);
994 if (err
) return(err
);
996 // Set up the nice label
997 m
->nicelabel
.c
[0] = 0;
998 GetUserSpecifiedFriendlyComputerName(&m
->nicelabel
);
999 if (m
->nicelabel
.c
[0] == 0) MakeDomainLabelFromLiteralString(&m
->nicelabel
, "Macintosh");
1001 // Set up the RFC 1034-compliant label
1002 domainlabel hostlabel
;
1004 GetUserSpecifiedRFC1034ComputerName(&hostlabel
);
1005 if (hostlabel
.c
[0] == 0) MakeDomainLabelFromLiteralString(&hostlabel
, "Macintosh");
1006 // If the user has changed their dot-local host name since the last time we checked, then update our local copy.
1007 // If the user has not changed their dot-local host name, then leave ours alone (m->hostlabel may have gone through
1008 // repeated conflict resolution to get to its current value, and if we reset it, we'll have to go through all that again.)
1009 if (SameDomainLabel(m
->p
->userhostlabel
.c
, hostlabel
.c
))
1010 debugf("Userhostlabel (%#s) unchanged since last time; not changing m->hostlabel (%#s)", m
->p
->userhostlabel
.c
, m
->hostlabel
.c
);
1013 debugf("Updating m->hostlabel to %#s", hostlabel
.c
);
1014 m
->p
->userhostlabel
= m
->hostlabel
= hostlabel
;
1015 mDNS_GenerateFQDN(m
);
1020 #if LIST_ALL_INTERFACES
1021 if (ifa
->ifa_addr
->sa_family
== AF_APPLETALK
)
1022 debugf("UpdateInterfaceList: %4s(%d) Flags %04X Family %2d is AF_APPLETALK",
1023 ifa
->ifa_name
, if_nametoindex(ifa
->ifa_name
), ifa
->ifa_flags
, ifa
->ifa_addr
->sa_family
);
1024 else if (ifa
->ifa_addr
->sa_family
== AF_LINK
)
1025 debugf("UpdateInterfaceList: %4s(%d) Flags %04X Family %2d is AF_LINK",
1026 ifa
->ifa_name
, if_nametoindex(ifa
->ifa_name
), ifa
->ifa_flags
, ifa
->ifa_addr
->sa_family
);
1027 else if (ifa
->ifa_addr
->sa_family
!= AF_INET
&& ifa
->ifa_addr
->sa_family
!= AF_INET6
)
1028 debugf("UpdateInterfaceList: %4s(%d) Flags %04X Family %2d not AF_INET (2) or AF_INET6 (30)",
1029 ifa
->ifa_name
, if_nametoindex(ifa
->ifa_name
), ifa
->ifa_flags
, ifa
->ifa_addr
->sa_family
);
1030 if (!(ifa
->ifa_flags
& IFF_UP
))
1031 debugf("UpdateInterfaceList: %4s(%d) Flags %04X Family %2d Interface not IFF_UP",
1032 ifa
->ifa_name
, if_nametoindex(ifa
->ifa_name
), ifa
->ifa_flags
, ifa
->ifa_addr
->sa_family
);
1033 if (ifa
->ifa_flags
& IFF_POINTOPOINT
)
1034 debugf("UpdateInterfaceList: %4s(%d) Flags %04X Family %2d Interface IFF_POINTOPOINT",
1035 ifa
->ifa_name
, if_nametoindex(ifa
->ifa_name
), ifa
->ifa_flags
, ifa
->ifa_addr
->sa_family
);
1036 if (ifa
->ifa_flags
& IFF_LOOPBACK
)
1037 debugf("UpdateInterfaceList: %4s(%d) Flags %04X Family %2d Interface IFF_LOOPBACK",
1038 ifa
->ifa_name
, if_nametoindex(ifa
->ifa_name
), ifa
->ifa_flags
, ifa
->ifa_addr
->sa_family
);
1040 if ((ifa
->ifa_addr
->sa_family
== AF_INET
|| ifa
->ifa_addr
->sa_family
== AF_INET6
) &&
1041 (ifa
->ifa_flags
& IFF_MULTICAST
) &&
1042 (ifa
->ifa_flags
& IFF_UP
) && !(ifa
->ifa_flags
& IFF_POINTOPOINT
))
1044 int ifru_flags6
= 0;
1045 if (ifa
->ifa_addr
->sa_family
== AF_INET6
&& InfoSocket
>= 0)
1047 struct sockaddr_in6
*sin6
= (struct sockaddr_in6
*)ifa
->ifa_addr
;
1048 struct in6_ifreq ifr6
;
1049 bzero((char *)&ifr6
, sizeof(ifr6
));
1050 strncpy(ifr6
.ifr_name
, ifa
->ifa_name
, sizeof(ifr6
.ifr_name
));
1051 ifr6
.ifr_addr
= *sin6
;
1052 if (ioctl(InfoSocket
, SIOCGIFAFLAG_IN6
, &ifr6
) != -1)
1053 ifru_flags6
= ifr6
.ifr_ifru
.ifru_flags6
;
1054 verbosedebugf("%s %.16a %04X %04X", ifa
->ifa_name
, &sin6
->sin6_addr
, ifa
->ifa_flags
, ifru_flags6
);
1056 if (!(ifru_flags6
& (IN6_IFF_NOTREADY
| IN6_IFF_DETACHED
| IN6_IFF_DEPRECATED
| IN6_IFF_TEMPORARY
)))
1058 if (ifa
->ifa_flags
& IFF_LOOPBACK
)
1062 AddInterfaceToList(m
, ifa
);
1063 if (ifa
->ifa_addr
->sa_family
== AF_INET
)
1064 foundav4
= mDNStrue
;
1068 ifa
= ifa
->ifa_next
;
1071 // Temporary workaround: Multicast loopback on IPv6 interfaces appears not to work.
1072 // In the interim, we skip loopback interface only if we found at least one v4 interface to use
1073 if (!foundav4
&& theLoopback
)
1074 AddInterfaceToList(m
, theLoopback
);
1076 // Now the list is complete, set the TxAndRx setting for each interface.
1077 // We always send and receive using IPv4.
1078 // To reduce traffic, we send and receive using IPv6 only on interfaces that have no routable IPv4 address.
1079 // Having a routable IPv4 address assigned is a reasonable indicator of being on a large configured network,
1080 // which means there's a good chance that most or all the other devices on that network should also have v4.
1081 // 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.
1082 // At this time, reducing the packet rate is more important than v6-only devices on a large configured network,
1083 // so we are willing to make that sacrifice.
1084 NetworkInterfaceInfoOSX
*i
;
1085 for (i
= m
->p
->InterfaceList
; i
; i
= i
->next
)
1086 if (i
->CurrentlyActive
)
1088 mDNSBool txrx
= ((i
->ifinfo
.ip
.type
== mDNSAddrType_IPv4
) || !FindRoutableIPv4(m
, i
->scope_id
));
1089 if (i
->ifinfo
.TxAndRx
!= txrx
)
1091 i
->ifinfo
.TxAndRx
= txrx
;
1092 i
->CurrentlyActive
= 2; // State change; need to deregister and reregister this interface
1096 if (InfoSocket
>= 0) close(InfoSocket
);
1100 mDNSlocal NetworkInterfaceInfoOSX
*SearchForInterfaceByName(mDNS
*const m
, char *ifname
, int type
)
1102 NetworkInterfaceInfoOSX
*i
;
1103 for (i
= m
->p
->InterfaceList
; i
; i
= i
->next
)
1104 if (!strcmp(i
->ifa_name
, ifname
) &&
1106 (type
== AF_INET
&& i
->ifinfo
.ip
.type
== mDNSAddrType_IPv4
) ||
1107 (type
== AF_INET6
&& i
->ifinfo
.ip
.type
== mDNSAddrType_IPv6
) )) return(i
);
1111 mDNSlocal
void SetupActiveInterfaces(mDNS
*const m
)
1113 NetworkInterfaceInfoOSX
*i
;
1114 for (i
= m
->p
->InterfaceList
; i
; i
= i
->next
)
1117 NetworkInterfaceInfo
*n
= &i
->ifinfo
;
1118 NetworkInterfaceInfoOSX
*alias
= SearchForInterfaceByName(m
, i
->ifa_name
, i
->sa_family
);
1119 if (!alias
) alias
= i
;
1121 if (n
->InterfaceID
&& n
->InterfaceID
!= (mDNSInterfaceID
)alias
)
1123 LogMsg("SetupActiveInterfaces ERROR! n->InterfaceID %p != alias %p", n
->InterfaceID
, alias
);
1124 n
->InterfaceID
= mDNSNULL
;
1127 if (!n
->InterfaceID
)
1129 n
->InterfaceID
= (mDNSInterfaceID
)alias
;
1130 mDNS_RegisterInterface(m
, n
);
1131 debugf("SetupActiveInterfaces: Registered %s(%lu) InterfaceID %p %#a%s",
1132 i
->ifa_name
, i
->scope_id
, alias
, &n
->ip
, n
->InterfaceActive
? " (Primary)" : "");
1136 debugf("SetupActiveInterfaces: No TX/Rx on %s(%lu) InterfaceID %p %#a", i
->ifa_name
, i
->scope_id
, alias
, &n
->ip
);
1139 if (i
->sa_family
== AF_INET
&& alias
->sktv4
== -1)
1141 #if mDNS_AllowPort53
1142 err
= SetupSocket(i
, UnicastDNSPort
, &alias
->skt53
, &alias
->cfs53
);
1144 if (!err
) err
= SetupSocket(i
, MulticastDNSPort
, &alias
->sktv4
, &alias
->cfsv4
);
1145 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
);
1146 else LogMsg("SetupActiveInterfaces: v4 socket%2d %s(%lu) InterfaceID %p %#a FAILED", alias
->sktv4
, i
->ifa_name
, i
->scope_id
, n
->InterfaceID
, &n
->ip
);
1149 if (i
->sa_family
== AF_INET6
&& alias
->sktv6
== -1)
1151 err
= SetupSocket(i
, MulticastDNSPort
, &alias
->sktv6
, &alias
->cfsv6
);
1152 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
);
1153 else LogMsg("SetupActiveInterfaces: v6 socket%2d %s(%lu) InterfaceID %p %#a FAILED", alias
->sktv6
, i
->ifa_name
, i
->scope_id
, n
->InterfaceID
, &n
->ip
);
1159 mDNSlocal
void MarkAllInterfacesInactive(mDNS
*const m
)
1161 NetworkInterfaceInfoOSX
*i
;
1162 for (i
= m
->p
->InterfaceList
; i
; i
= i
->next
)
1163 i
->CurrentlyActive
= mDNSfalse
;
1166 mDNSlocal
void ClearInactiveInterfaces(mDNS
*const m
)
1169 // If an interface is going away, then deregister this from the mDNSCore.
1170 // We also have to deregister it if the alias interface that it's using for its InterfaceID is going away.
1171 // We have to do this because mDNSCore will use that InterfaceID when sending packets, and if the memory
1172 // it refers to has gone away we'll crash.
1173 // Don't actually close the sockets or free the memory yet: When the last representative of an interface goes away
1174 // mDNSCore may want to send goodbye packets on that interface. (Not yet implemented, but a good idea anyway.)
1175 NetworkInterfaceInfoOSX
*i
;
1176 for (i
= m
->p
->InterfaceList
; i
; i
= i
->next
)
1178 // 1. If this interface is no longer active, or it's InterfaceID is changing, deregister it
1179 NetworkInterfaceInfoOSX
*alias
= (NetworkInterfaceInfoOSX
*)(i
->ifinfo
.InterfaceID
);
1180 if (i
->ifinfo
.InterfaceID
&& (!i
->CurrentlyActive
|| (alias
&& !alias
->CurrentlyActive
) || i
->CurrentlyActive
== 2))
1182 debugf("ClearInactiveInterfaces: Deregistering %#a", &i
->ifinfo
.ip
);
1183 mDNS_DeregisterInterface(m
, &i
->ifinfo
);
1184 i
->ifinfo
.InterfaceID
= mDNSNULL
;
1189 // Now that everything that's going to deregister has done so, we can close sockets and free the memory
1190 NetworkInterfaceInfoOSX
**p
= &m
->p
->InterfaceList
;
1194 // 2. Close all our CFSockets. We'll recreate them later as necessary.
1195 // (We may have previously had both v4 and v6, and we may not need both any more.)
1196 // Note: MUST NOT close the underlying native BSD sockets.
1197 // CFSocketInvalidate() will do that for us, in its own good time, which may not necessarily be immediately,
1198 // because it first has to unhook the sockets from its select() call, before it can safely close them.
1199 #if mDNS_AllowPort53
1200 if (i
->cfs53
) { CFSocketInvalidate(i
->cfs53
); CFRelease(i
->cfs53
); }
1204 if (i
->cfsv4
) { CFSocketInvalidate(i
->cfsv4
); CFRelease(i
->cfsv4
); }
1205 if (i
->cfsv6
) { CFSocketInvalidate(i
->cfsv6
); CFRelease(i
->cfsv6
); }
1206 i
->sktv4
= i
->sktv6
= -1;
1207 i
->cfsv4
= i
->cfsv6
= NULL
;
1209 // 3. If no longer active, delete interface from list and free memory
1210 if (!i
->CurrentlyActive
)
1212 debugf("ClearInactiveInterfaces: Deleting %#a", &i
->ifinfo
.ip
);
1214 if (i
->ifa_name
) freeL("NetworkInterfaceInfoOSX name", i
->ifa_name
);
1215 freeL("NetworkInterfaceInfoOSX", i
);
1222 mDNSlocal
void NetworkChanged(SCDynamicStoreRef store
, CFArrayRef changedKeys
, void *context
)
1224 (void)store
; // Parameter not used
1225 (void)changedKeys
; // Parameter not used
1226 debugf("*** Network Configuration Change ***");
1228 mDNS
*const m
= (mDNS
*const)context
;
1229 MarkAllInterfacesInactive(m
);
1230 UpdateInterfaceList(m
);
1231 ClearInactiveInterfaces(m
);
1232 SetupActiveInterfaces(m
);
1234 if (m
->MainCallback
)
1235 m
->MainCallback(m
, mStatus_ConfigChanged
);
1238 mDNSlocal mStatus
WatchForNetworkChanges(mDNS
*const m
)
1241 SCDynamicStoreContext context
= { 0, m
, NULL
, NULL
, NULL
};
1242 SCDynamicStoreRef store
= SCDynamicStoreCreate(NULL
, CFSTR("mDNSResponder"), NetworkChanged
, &context
);
1243 CFStringRef key1
= SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL
, kSCDynamicStoreDomainState
, kSCEntNetIPv4
);
1244 CFStringRef key2
= SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL
, kSCDynamicStoreDomainState
, kSCEntNetIPv6
);
1245 CFStringRef key3
= SCDynamicStoreKeyCreateComputerName(NULL
);
1246 CFStringRef key4
= SCDynamicStoreKeyCreateHostNames(NULL
);
1247 CFStringRef pattern1
= SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL
, kSCDynamicStoreDomainState
, kSCCompAnyRegex
, kSCEntNetIPv4
);
1248 CFStringRef pattern2
= SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL
, kSCDynamicStoreDomainState
, kSCCompAnyRegex
, kSCEntNetIPv6
);
1250 CFMutableArrayRef keys
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
1251 CFMutableArrayRef patterns
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
1253 if (!store
) { LogMsg("SCDynamicStoreCreate failed: %s\n", SCErrorString(SCError())); goto error
; }
1254 if (!key1
|| !key2
|| !key3
|| !key4
|| !keys
|| !pattern1
|| !pattern2
|| !patterns
) goto error
;
1256 CFArrayAppendValue(keys
, key1
);
1257 CFArrayAppendValue(keys
, key2
);
1258 CFArrayAppendValue(keys
, key3
);
1259 CFArrayAppendValue(keys
, key4
);
1260 CFArrayAppendValue(patterns
, pattern1
);
1261 CFArrayAppendValue(patterns
, pattern2
);
1262 if (!SCDynamicStoreSetNotificationKeys(store
, keys
, patterns
))
1263 { LogMsg("SCDynamicStoreSetNotificationKeys failed: %s\n", SCErrorString(SCError())); goto error
; }
1265 m
->p
->StoreRLS
= SCDynamicStoreCreateRunLoopSource(NULL
, store
, 0);
1266 if (!m
->p
->StoreRLS
) { LogMsg("SCDynamicStoreCreateRunLoopSource failed: %s\n", SCErrorString(SCError())); goto error
; }
1268 CFRunLoopAddSource(CFRunLoopGetCurrent(), m
->p
->StoreRLS
, kCFRunLoopDefaultMode
);
1269 m
->p
->Store
= store
;
1274 if (store
) CFRelease(store
);
1277 if (key1
) CFRelease(key1
);
1278 if (key2
) CFRelease(key2
);
1279 if (key3
) CFRelease(key3
);
1280 if (key4
) CFRelease(key4
);
1281 if (pattern1
) CFRelease(pattern1
);
1282 if (pattern2
) CFRelease(pattern2
);
1283 if (keys
) CFRelease(keys
);
1284 if (patterns
) CFRelease(patterns
);
1289 mDNSlocal
void PowerChanged(void *refcon
, io_service_t service
, natural_t messageType
, void *messageArgument
)
1291 mDNS
*const m
= (mDNS
*const)refcon
;
1292 (void)service
; // Parameter not used
1295 case kIOMessageCanSystemPowerOff
: debugf("PowerChanged kIOMessageCanSystemPowerOff (no action)"); break; // E0000240
1296 case kIOMessageSystemWillPowerOff
: debugf("PowerChanged kIOMessageSystemWillPowerOff"); mDNSCoreMachineSleep(m
, true); break; // E0000250
1297 case kIOMessageSystemWillNotPowerOff
: debugf("PowerChanged kIOMessageSystemWillNotPowerOff (no action)"); break; // E0000260
1298 case kIOMessageCanSystemSleep
: debugf("PowerChanged kIOMessageCanSystemSleep (no action)"); break; // E0000270
1299 case kIOMessageSystemWillSleep
: debugf("PowerChanged kIOMessageSystemWillSleep"); mDNSCoreMachineSleep(m
, true); break; // E0000280
1300 case kIOMessageSystemWillNotSleep
: debugf("PowerChanged kIOMessageSystemWillNotSleep (no action)"); break; // E0000290
1301 case kIOMessageSystemHasPoweredOn
: debugf("PowerChanged kIOMessageSystemHasPoweredOn"); mDNSCoreMachineSleep(m
, false); break; // E0000300
1302 default: debugf("PowerChanged unknown message %X", messageType
); break;
1304 IOAllowPowerChange(m
->p
->PowerConnection
, (long)messageArgument
);
1307 mDNSlocal mStatus
WatchForPowerChanges(mDNS
*const m
)
1309 IONotificationPortRef thePortRef
;
1310 m
->p
->PowerConnection
= IORegisterForSystemPower(m
, &thePortRef
, PowerChanged
, &m
->p
->PowerNotifier
);
1311 if (m
->p
->PowerConnection
)
1313 m
->p
->PowerRLS
= IONotificationPortGetRunLoopSource(thePortRef
);
1314 CFRunLoopAddSource(CFRunLoopGetCurrent(), m
->p
->PowerRLS
, kCFRunLoopDefaultMode
);
1315 return(mStatus_NoError
);
1320 CF_EXPORT CFDictionaryRef
_CFCopySystemVersionDictionary(void);
1321 CF_EXPORT
const CFStringRef _kCFSystemVersionProductNameKey
;
1322 CF_EXPORT
const CFStringRef _kCFSystemVersionProductVersionKey
;
1323 CF_EXPORT
const CFStringRef _kCFSystemVersionBuildVersionKey
;
1325 mDNSexport mDNSBool
mDNSMacOSXSystemBuildNumber(char *HINFO_SWstring
)
1327 int major
= 0, minor
= 0;
1328 char letter
= 0, prodname
[256]="Mac OS X", prodvers
[256]="", buildver
[256]="?";
1329 CFDictionaryRef vers
= _CFCopySystemVersionDictionary();
1332 CFStringRef cfprodname
= CFDictionaryGetValue(vers
, _kCFSystemVersionProductNameKey
);
1333 CFStringRef cfprodvers
= CFDictionaryGetValue(vers
, _kCFSystemVersionProductVersionKey
);
1334 CFStringRef cfbuildver
= CFDictionaryGetValue(vers
, _kCFSystemVersionBuildVersionKey
);
1335 if (cfprodname
) CFStringGetCString(cfprodname
, prodname
, sizeof(prodname
), kCFStringEncodingUTF8
);
1336 if (cfprodvers
) CFStringGetCString(cfprodvers
, prodvers
, sizeof(prodvers
), kCFStringEncodingUTF8
);
1337 if (cfbuildver
) CFStringGetCString(cfbuildver
, buildver
, sizeof(buildver
), kCFStringEncodingUTF8
);
1338 sscanf(buildver
, "%d%c%d", &major
, &letter
, &minor
);
1341 if (HINFO_SWstring
) mDNS_snprintf(HINFO_SWstring
, 256, "%s %s (%s), %s", prodname
, prodvers
, buildver
, mDNSResponderVersionString
);
1345 mDNSlocal mStatus
mDNSPlatformInit_setup(mDNS
*const m
)
1349 m
->hostlabel
.c
[0] = 0;
1351 char *HINFO_HWstring
= "Macintosh";
1352 char HINFO_HWstring_buffer
[256];
1353 int get_model
[2] = { CTL_HW
, HW_MODEL
};
1354 size_t len_model
= sizeof(HINFO_HWstring_buffer
);
1355 if (sysctl(get_model
, 2, HINFO_HWstring_buffer
, &len_model
, NULL
, 0) == 0)
1356 HINFO_HWstring
= HINFO_HWstring_buffer
;
1358 char HINFO_SWstring
[256] = "";
1359 if (mDNSMacOSXSystemBuildNumber(HINFO_SWstring
) < 7) m
->KnownBugs
= mDNS_KnownBug_PhantomInterfaces
;
1361 mDNSu32 hlen
= mDNSPlatformStrLen(HINFO_HWstring
);
1362 mDNSu32 slen
= mDNSPlatformStrLen(HINFO_SWstring
);
1363 if (hlen
+ slen
< 254)
1365 m
->HIHardware
.c
[0] = hlen
;
1366 m
->HISoftware
.c
[0] = slen
;
1367 mDNSPlatformMemCopy(HINFO_HWstring
, &m
->HIHardware
.c
[1], hlen
);
1368 mDNSPlatformMemCopy(HINFO_SWstring
, &m
->HISoftware
.c
[1], slen
);
1371 m
->p
->InterfaceList
= mDNSNULL
;
1372 m
->p
->userhostlabel
.c
[0] = 0;
1373 UpdateInterfaceList(m
);
1374 SetupActiveInterfaces(m
);
1376 err
= WatchForNetworkChanges(m
);
1377 if (err
) return(err
);
1379 err
= WatchForPowerChanges(m
);
1383 mDNSexport mStatus
mDNSPlatformInit(mDNS
*const m
)
1385 mStatus result
= mDNSPlatformInit_setup(m
);
1386 // We don't do asynchronous initialization on OS X, so by the time we get here the setup will already
1387 // have succeeded or failed -- so if it succeeded, we should just call mDNSCoreInitComplete() immediately
1388 if (result
== mStatus_NoError
) mDNSCoreInitComplete(m
, mStatus_NoError
);
1392 mDNSexport
void mDNSPlatformClose(mDNS
*const m
)
1394 if (m
->p
->PowerConnection
)
1396 CFRunLoopRemoveSource(CFRunLoopGetCurrent(), m
->p
->PowerRLS
, kCFRunLoopDefaultMode
);
1397 CFRunLoopSourceInvalidate(m
->p
->PowerRLS
);
1398 CFRelease(m
->p
->PowerRLS
);
1399 IODeregisterForSystemPower(&m
->p
->PowerNotifier
);
1400 m
->p
->PowerConnection
= NULL
;
1401 m
->p
->PowerNotifier
= NULL
;
1402 m
->p
->PowerRLS
= NULL
;
1407 CFRunLoopRemoveSource(CFRunLoopGetCurrent(), m
->p
->StoreRLS
, kCFRunLoopDefaultMode
);
1408 CFRunLoopSourceInvalidate(m
->p
->StoreRLS
);
1409 CFRelease(m
->p
->StoreRLS
);
1410 CFRelease(m
->p
->Store
);
1412 m
->p
->StoreRLS
= NULL
;
1415 MarkAllInterfacesInactive(m
);
1416 ClearInactiveInterfaces(m
);
1419 mDNSexport mDNSs32 mDNSPlatformOneSecond
= 1000;
1421 mDNSexport mStatus
mDNSPlatformTimeInit(mDNSs32
*timenow
)
1423 // Notes: Typical values for mach_timebase_info:
1424 // tbi.numer = 1000 million
1425 // tbi.denom = 33 million
1426 // These are set such that (mach_absolute_time() * numer/denom) gives us nanoseconds;
1427 // numer / denom = nanoseconds per hardware clock tick (e.g. 30);
1428 // denom / numer = hardware clock ticks per nanosecond (e.g. 0.033)
1429 // (denom*1000000) / numer = hardware clock ticks per millisecond (e.g. 33333)
1430 // So: mach_absolute_time() / ((denom*1000000)/numer) = milliseconds
1432 // Arithmetic notes:
1433 // tbi.denom is at least 1, and not more than 2^32-1.
1434 // Therefore (tbi.denom * 1000000) is at least one million, but cannot overflow a uint64_t.
1435 // tbi.denom is at least 1, and not more than 2^32-1.
1436 // Therefore clockdivisor should end up being a number roughly in the range 10^3 - 10^9.
1437 // If clockdivisor is less than 10^3 then that means that the native clock frequency is less than 1MHz,
1438 // which is unlikely on any current or future Macintosh.
1439 // If clockdivisor is greater than 10^9 then that means the native clock frequency is greater than 1000GHz.
1440 // When we ship Macs with clock frequencies above 1000GHz, we may have to update this code.
1441 struct mach_timebase_info tbi
;
1442 kern_return_t result
= mach_timebase_info(&tbi
);
1443 if (result
!= KERN_SUCCESS
) return(result
);
1444 clockdivisor
= ((uint64_t)tbi
.denom
* 1000000) / tbi
.numer
;
1445 *timenow
= mDNSPlatformTimeNow();
1446 return(mStatus_NoError
);
1449 mDNSexport mDNSs32
mDNSPlatformTimeNow(void)
1451 if (clockdivisor
== 0) { LogMsg("mDNSPlatformTimeNow called before mDNSPlatformTimeInit"); return(0); }
1452 return((mDNSs32
)(mach_absolute_time() / clockdivisor
));
1455 // Locking is a no-op here, because we're single-threaded with a CFRunLoop, so we can never interrupt ourselves
1456 mDNSexport
void mDNSPlatformLock (const mDNS
*const m
) { (void)m
; }
1457 mDNSexport
void mDNSPlatformUnlock (const mDNS
*const m
) { (void)m
; }
1458 mDNSexport
void mDNSPlatformStrCopy(const void *src
, void *dst
) { strcpy((char *)dst
, (char *)src
); }
1459 mDNSexport mDNSu32
mDNSPlatformStrLen (const void *src
) { return(strlen((char*)src
)); }
1460 mDNSexport
void mDNSPlatformMemCopy(const void *src
, void *dst
, mDNSu32 len
) { memcpy(dst
, src
, len
); }
1461 mDNSexport mDNSBool
mDNSPlatformMemSame(const void *src
, const void *dst
, mDNSu32 len
) { return(memcmp(dst
, src
, len
) == 0); }
1462 mDNSexport
void mDNSPlatformMemZero( void *dst
, mDNSu32 len
) { bzero(dst
, len
); }
1463 mDNSexport
void * mDNSPlatformMemAllocate(mDNSu32 len
) { return(mallocL("mDNSPlatformMemAllocate", len
)); }
1464 mDNSexport
void mDNSPlatformMemFree (void *mem
) { freeL("mDNSPlatformMemFree", mem
); }