2 * Copyright (c) 2002 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * The contents of this file constitute Original Code as defined in
7 * and are subject to the Apple Public Source License Version 1.1
8 * (the "License"). You may not use this file except in compliance
9 * with the License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
20 * @APPLE_LICENSE_HEADER_END@
23 // ***************************************************************************
25 // Supporting routines to run mDNS on a CFRunLoop platform
26 // ***************************************************************************
28 // Open Transport 2.7.x on Mac OS 9 used to send Multicast DNS queries to UDP port 53,
29 // before the Multicast DNS port was changed to 5353. For this reason, the mDNSResponder
30 // in earlier versions of Mac OS X 10.2 Jaguar used to set mDNS_AllowPort53 to 1 to allow
31 // it to also listen and answer queries on UDP port 53. Now that Transport 2.8 (included in
32 // the Classic subsystem of Mac OS X 10.2 Jaguar) has been corrected to issue Multicast DNS
33 // queries on UDP port 5353, this backwards-compatibility legacy support is no longer needed.
34 #define mDNS_AllowPort53 1
36 // Normally mDNSResponder is advertising local services on all active interfaces.
37 // However, should you wish to build a query-only mDNS client, setting mDNS_AdvertiseLocalAddresses
38 // to zero will cause CFSocket.c to not set the Advertise flag in its mDNS_RegisterInterface calls.
39 int mDNS_AdvertiseLocalAddresses
= 1;
41 void (*NotifyClientNetworkChanged
)(void);
43 #include "mDNSClientAPI.h" // Defines the interface provided to the client layer above
44 #include "mDNSPlatformFunctions.h" // Defines the interface to the supporting layer below
45 #include "mDNSPlatformEnvironment.h" // Defines the specific types needed to run mDNS on this platform
46 #include "mDNSvsprintf.h" // Used to implement debugf_();
49 #include <stdarg.h> // For va_list support
51 #include <net/if_dl.h>
53 #include <sys/param.h>
54 #include <sys/socket.h>
56 // Code contributed by Dave Heller:
57 // Define RUN_ON_PUMA_WITHOUT_IFADDRS to compile code that will
58 // work on Mac OS X 10.1, which does not have the getifaddrs call.
59 #define RUN_ON_PUMA_WITHOUT_IFADDRS 0
61 #if RUN_ON_PUMA_WITHOUT_IFADDRS
63 #include <sys/ioctl.h>
64 #include <sys/sockio.h>
65 #define ifaddrs ifa_info
67 #define ifa_broadaddr ifa_dstaddr /* broadcast address interface */
69 #include <sys/cdefs.h>
77 #include <IOKit/IOKitLib.h>
78 #include <IOKit/IOMessage.h>
80 // ***************************************************************************
83 typedef struct NetworkInterfaceInfo2_struct NetworkInterfaceInfo2
;
84 struct NetworkInterfaceInfo2_struct
86 NetworkInterfaceInfo ifinfo
;
89 NetworkInterfaceInfo2
*alias
;
94 CFSocketRef cfsocket53
;
98 // ***************************************************************************
101 mDNSexport
void debugf_(const char *format
, ...)
103 unsigned char buffer
[512];
105 va_start(ptr
,format
);
106 buffer
[mDNS_vsprintf((char *)buffer
, format
, ptr
)] = 0;
108 fprintf(stderr
, "%s\n", buffer
);
112 mDNSexport mStatus
mDNSPlatformSendUDP(const mDNS
*const m
, const DNSMessage
*const msg
, const mDNSu8
*const end
,
113 mDNSIPAddr src
, mDNSIPPort srcport
, mDNSIPAddr dst
, mDNSIPPort dstport
)
115 NetworkInterfaceInfo2
*info
= (NetworkInterfaceInfo2
*)(m
->HostInterfaces
);
116 struct sockaddr_in to
;
117 to
.sin_family
= AF_INET
;
118 to
.sin_port
= dstport
.NotAnInteger
;
119 to
.sin_addr
.s_addr
= dst
. NotAnInteger
;
121 if (src
.NotAnInteger
== 0) debugf("mDNSPlatformSendUDP ERROR! Cannot send from zero source address");
125 if (info
->ifinfo
.ip
.NotAnInteger
== src
.NotAnInteger
)
128 if (srcport
.NotAnInteger
== MulticastDNSPort
.NotAnInteger
) s
= info
->socket
;
130 else if (srcport
.NotAnInteger
== UnicastDNSPort
.NotAnInteger
) s
= info
->socket53
;
132 else { debugf("Source port %d not allowed", (mDNSu16
)srcport
.b
[0]<<8 | srcport
.b
[1]); return(-1); }
133 err
= sendto(s
, msg
, (UInt8
*)end
- (UInt8
*)msg
, 0, (struct sockaddr
*)&to
, sizeof(to
));
134 if (err
< 0) { perror("mDNSPlatformSendUDP sendto"); return(err
); }
136 info
= (NetworkInterfaceInfo2
*)(info
->ifinfo
.next
);
139 return(mStatus_NoError
);
142 static ssize_t
myrecvfrom(const int s
, void *const buffer
, const size_t max
,
143 struct sockaddr
*const from
, size_t *const fromlen
, struct in_addr
*dstaddr
, char ifname
[128])
145 struct iovec databuffers
= { (char *)buffer
, max
};
148 struct cmsghdr
*cmPtr
;
149 char ancillary
[1024];
151 // Set up the message
152 msg
.msg_name
= (caddr_t
)from
;
153 msg
.msg_namelen
= *fromlen
;
154 msg
.msg_iov
= &databuffers
;
156 msg
.msg_control
= (caddr_t
)&ancillary
;
157 msg
.msg_controllen
= sizeof(ancillary
);
161 n
= recvmsg(s
, &msg
, 0);
162 if (n
<0 || msg
.msg_controllen
< sizeof(struct cmsghdr
) || (msg
.msg_flags
& MSG_CTRUNC
))
163 { perror("recvmsg"); return(n
); }
165 *fromlen
= msg
.msg_namelen
;
167 // Parse each option out of the ancillary data.
168 for (cmPtr
= CMSG_FIRSTHDR(&msg
); cmPtr
; cmPtr
= CMSG_NXTHDR(&msg
, cmPtr
))
170 // debugf("myrecvfrom cmsg_level %d cmsg_type %d", cmPtr->cmsg_level, cmPtr->cmsg_type);
171 if (cmPtr
->cmsg_level
== IPPROTO_IP
&& cmPtr
->cmsg_type
== IP_RECVDSTADDR
)
172 *dstaddr
= *(struct in_addr
*)CMSG_DATA(cmPtr
);
173 if (cmPtr
->cmsg_level
== IPPROTO_IP
&& cmPtr
->cmsg_type
== IP_RECVIF
)
175 struct sockaddr_dl
*sdl
= (struct sockaddr_dl
*)CMSG_DATA(cmPtr
);
176 if (sdl
->sdl_nlen
< sizeof(ifname
))
178 mDNSPlatformMemCopy(sdl
->sdl_data
, ifname
, sdl
->sdl_nlen
);
179 ifname
[sdl
->sdl_nlen
] = 0;
180 // debugf("IP_RECVIF sdl_index %d, sdl_data %s len %d", sdl->sdl_index, ifname, sdl->sdl_nlen);
188 mDNSlocal
void myCFSocketCallBack(CFSocketRef s
, CFSocketCallBackType type
, CFDataRef address
, const void *data
, void *context
)
190 mDNSIPAddr senderaddr
, destaddr
;
191 mDNSIPPort senderport
;
192 NetworkInterfaceInfo2
*info
= (NetworkInterfaceInfo2
*)context
;
193 mDNS
*const m
= info
->m
;
196 struct sockaddr_in from
;
197 size_t fromlen
= sizeof(from
);
198 char packetifname
[128] = "";
201 (void)address
; // Parameter not used
202 (void)data
; // Parameter not used
204 if (type
!= kCFSocketReadCallBack
) debugf("myCFSocketCallBack: Why is type not kCFSocketReadCallBack?");
206 if (s
== info
->cfsocket53
)
207 err
= myrecvfrom(info
->socket53
, &packet
, sizeof(packet
), (struct sockaddr
*)&from
, &fromlen
, &to
, packetifname
);
210 err
= myrecvfrom(info
->socket
, &packet
, sizeof(packet
), (struct sockaddr
*)&from
, &fromlen
, &to
, packetifname
);
212 if (err
< 0) { debugf("myCFSocketCallBack recvfrom error %d", err
); return; }
214 senderaddr
.NotAnInteger
= from
.sin_addr
.s_addr
;
215 senderport
.NotAnInteger
= from
.sin_port
;
216 destaddr
.NotAnInteger
= to
.s_addr
;
218 // Even though we indicated a specific interface in the IP_ADD_MEMBERSHIP call, a weirdness of the
219 // sockets API means that even though this socket has only officially joined the multicast group
220 // on one specific interface, the kernel will still deliver multicast packets to it no matter which
221 // interface they arrive on. According to the official Unix Powers That Be, this is Not A Bug.
222 // To work around this weirdness, we use the IP_RECVIF option to find the name of the interface
223 // on which the packet arrived, and ignore the packet if it really arrived on some other interface.
224 if (strcmp(info
->ifa_name
, packetifname
))
226 verbosedebugf("myCFSocketCallBack got a packet from %.4a to %.4a on interface %.4a/%s (Ignored -- really arrived on interface %s)",
227 &senderaddr
, &destaddr
, &info
->ifinfo
.ip
, info
->ifa_name
, packetifname
);
231 verbosedebugf("myCFSocketCallBack got a packet from %.4a to %.4a on interface %.4a/%s",
232 &senderaddr
, &destaddr
, &info
->ifinfo
.ip
, info
->ifa_name
);
234 if (err
< sizeof(DNSMessageHeader
)) { debugf("myCFSocketCallBack packet length (%d) too short", err
); return; }
237 if (s
== info
->cfsocket53
)
238 mDNSCoreReceive(m
, &packet
, (unsigned char*)&packet
+ err
, senderaddr
, senderport
, destaddr
, UnicastDNSPort
, info
->ifinfo
.ip
);
241 mDNSCoreReceive(m
, &packet
, (unsigned char*)&packet
+ err
, senderaddr
, senderport
, destaddr
, MulticastDNSPort
, info
->ifinfo
.ip
);
244 mDNSlocal
void myCFRunLoopTimerCallBack(CFRunLoopTimerRef timer
, void *info
)
246 (void)timer
; // Parameter not used
247 mDNSCoreTask((mDNS
*const)info
);
250 // This gets the text of the field currently labelled "Computer Name" in the Sharing Prefs Control Panel
251 mDNSlocal
void GetUserSpecifiedFriendlyComputerName(domainlabel
*const namelabel
)
253 CFStringEncoding encoding
= kCFStringEncodingUTF8
;
254 CFStringRef cfs
= SCDynamicStoreCopyComputerName(NULL
, &encoding
);
257 CFStringGetPascalString(cfs
, namelabel
->c
, sizeof(*namelabel
), kCFStringEncodingUTF8
);
262 // This gets the text of the field currently labelled "Rendezvous Name" in the Sharing Prefs Control Panel
263 mDNSlocal
void GetUserSpecifiedRFC1034ComputerName(domainlabel
*const namelabel
)
265 CFStringRef cfs
= SCDynamicStoreCopyLocalHostName(NULL
);
268 CFStringGetPascalString(cfs
, namelabel
->c
, sizeof(*namelabel
), kCFStringEncodingUTF8
);
273 mDNSlocal mStatus
SetupSocket(struct sockaddr_in
*ifa_addr
, mDNSIPPort port
, int *s
, CFSocketRef
*c
, CFSocketContext
*context
)
277 const int twofivefive
= 255;
279 struct sockaddr_in listening_sockaddr
;
280 CFRunLoopSourceRef rls
;
282 // Open the socket...
283 *s
= socket(PF_INET
, SOCK_DGRAM
, IPPROTO_UDP
);
285 if (*s
< 0) { perror("socket"); return(*s
); }
287 // ... with a shared UDP port
288 err
= setsockopt(*s
, SOL_SOCKET
, SO_REUSEPORT
, &on
, sizeof(on
));
289 if (err
< 0) { perror("setsockopt - SO_REUSEPORT"); return(err
); }
291 // We want to receive destination addresses
292 err
= setsockopt(*s
, IPPROTO_IP
, IP_RECVDSTADDR
, &on
, sizeof(on
));
293 if (err
< 0) { perror("setsockopt - IP_RECVDSTADDR"); return(err
); }
295 // We want to receive interface identifiers
296 err
= setsockopt(*s
, IPPROTO_IP
, IP_RECVIF
, &on
, sizeof(on
));
297 if (err
< 0) { perror("setsockopt - IP_RECVIF"); return(err
); }
299 // Add multicast group membership on this interface
300 imr
.imr_multiaddr
.s_addr
= AllDNSLinkGroup
.NotAnInteger
;
301 imr
.imr_interface
= ifa_addr
->sin_addr
;
302 err
= setsockopt(*s
, IPPROTO_IP
, IP_ADD_MEMBERSHIP
, &imr
, sizeof(struct ip_mreq
));
303 if (err
< 0) { perror("setsockopt - IP_ADD_MEMBERSHIP"); return(err
); }
305 // Specify outgoing interface too
306 err
= setsockopt(*s
, IPPROTO_IP
, IP_MULTICAST_IF
, &ifa_addr
->sin_addr
, sizeof(ifa_addr
->sin_addr
));
307 if (err
< 0) { perror("setsockopt - IP_MULTICAST_IF"); return(err
); }
309 // Send unicast packets with TTL 255
310 err
= setsockopt(*s
, IPPROTO_IP
, IP_TTL
, &twofivefive
, sizeof(twofivefive
));
311 if (err
< 0) { perror("setsockopt - IP_TTL"); return(err
); }
313 // And multicast packets with TTL 255 too
314 err
= setsockopt(*s
, IPPROTO_IP
, IP_MULTICAST_TTL
, &twofivefive
, sizeof(twofivefive
));
315 if (err
< 0) { perror("setsockopt - IP_MULTICAST_TTL"); return(err
); }
317 // And start listening for packets
318 listening_sockaddr
.sin_family
= AF_INET
;
319 listening_sockaddr
.sin_port
= port
.NotAnInteger
;
320 listening_sockaddr
.sin_addr
.s_addr
= 0; // Want to receive multicasts AND unicasts on this socket
321 err
= bind(*s
, (struct sockaddr
*) &listening_sockaddr
, sizeof(listening_sockaddr
));
324 if (port
.NotAnInteger
== UnicastDNSPort
.NotAnInteger
) err
= 0;
329 *c
= CFSocketCreateWithNative(kCFAllocatorDefault
, *s
, kCFSocketReadCallBack
, myCFSocketCallBack
, context
);
330 rls
= CFSocketCreateRunLoopSource(kCFAllocatorDefault
, *c
, 0);
331 CFRunLoopAddSource(CFRunLoopGetCurrent(), rls
, kCFRunLoopDefaultMode
);
338 mDNSlocal NetworkInterfaceInfo2
*SearchForInterfaceByAddr(mDNS
*const m
, mDNSIPAddr ip
)
340 NetworkInterfaceInfo2
*info
= (NetworkInterfaceInfo2
*)(m
->HostInterfaces
);
343 if (info
->ifinfo
.ip
.NotAnInteger
== ip
.NotAnInteger
) return(info
);
344 info
= (NetworkInterfaceInfo2
*)(info
->ifinfo
.next
);
350 mDNSlocal NetworkInterfaceInfo2
*SearchForInterfaceByName(mDNS
*const m
, char *ifname
)
352 NetworkInterfaceInfo2
*info
= (NetworkInterfaceInfo2
*)(m
->HostInterfaces
);
355 if (!strcmp(info
->ifa_name
, ifname
)) return(info
);
356 info
= (NetworkInterfaceInfo2
*)(info
->ifinfo
.next
);
361 #if RUN_ON_PUMA_WITHOUT_IFADDRS
363 /* Our own header for the programs that need interface configuration info.
364 Include this file, instead of "unp.h". */
366 #define IFA_NAME 16 /* same as IFNAMSIZ in <net/if.h> */
367 #define IFA_HADDR 8 /* allow for 64-bit EUI-64 in future */
370 char ifa_name
[IFA_NAME
]; /* interface name, null terminated */
371 u_char ifa_haddr
[IFA_HADDR
]; /* hardware address */
372 u_short ifa_hlen
; /* #bytes in hardware address: 0, 6, 8 */
373 short ifa_flags
; /* IFF_xxx constants from <net/if.h> */
374 short ifa_myflags
; /* our own IFI_xxx flags */
375 struct sockaddr
*ifa_addr
; /* primary address */
376 struct sockaddr
*ifa_brdaddr
;/* broadcast address */
377 struct sockaddr
*ifa_dstaddr
;/* destination address */
378 struct ifa_info
*ifa_next
; /* next of these structures */
381 #define IFI_ALIAS 1 /* ifa_addr is an alias */
383 /* function prototypes */
384 struct ifa_info
*get_ifa_info(int, int);
385 struct ifa_info
*Get_ifa_info(int, int);
386 void free_ifa_info(struct ifa_info
*);
388 #define HAVE_SOCKADDR_SA_LEN 1
391 get_ifa_info(int family
, int doaliases
)
393 struct ifa_info
*ifi
, *ifihead
, **ifipnext
;
394 int sockfd
, len
, lastlen
, flags
, myflags
;
395 char *ptr
, *buf
, lastname
[IFNAMSIZ
], *cptr
;
397 struct ifreq
*ifr
, ifrcopy
;
398 struct sockaddr_in
*sinptr
;
400 sockfd
= socket(AF_INET
, SOCK_DGRAM
, 0);
403 len
= 100 * sizeof(struct ifreq
); /* initial buffer size guess */
405 buf
= (char *) malloc(len
);
408 if (ioctl(sockfd
, SIOCGIFCONF
, &ifc
) < 0) {
409 if (errno
!= EINVAL
|| lastlen
!= 0)
410 debugf("ioctl error");
412 if (ifc
.ifc_len
== lastlen
)
413 break; /* success, len has not changed */
414 lastlen
= ifc
.ifc_len
;
416 len
+= 10 * sizeof(struct ifreq
); /* increment */
422 /* end get_ifa_info1 */
424 /* include get_ifa_info2 */
425 for (ptr
= buf
; ptr
< buf
+ ifc
.ifc_len
; ) {
426 ifr
= (struct ifreq
*) ptr
;
428 #ifdef HAVE_SOCKADDR_SA_LEN
429 len
= MAX(sizeof(struct sockaddr
), ifr
->ifr_addr
.sa_len
);
431 switch (ifr
->ifr_addr
.sa_family
) {
434 len
= sizeof(struct sockaddr_in6
);
439 len
= sizeof(struct sockaddr
);
442 #endif /* HAVE_SOCKADDR_SA_LEN */
443 ptr
+= sizeof(ifr
->ifr_name
) + len
; /* for next one in buffer */
445 if (ifr
->ifr_addr
.sa_family
!= family
)
446 continue; /* ignore if not desired address family */
449 if ( (cptr
= strchr(ifr
->ifr_name
, ':')) != NULL
)
450 *cptr
= 0; /* replace colon will null */
451 if (strncmp(lastname
, ifr
->ifr_name
, IFNAMSIZ
) == 0) {
453 continue; /* already processed this interface */
456 memcpy(lastname
, ifr
->ifr_name
, IFNAMSIZ
);
459 ioctl(sockfd
, SIOCGIFFLAGS
, &ifrcopy
);
460 flags
= ifrcopy
.ifr_flags
;
461 if ((flags
& IFF_UP
) == 0)
462 continue; /* ignore if interface not up */
464 ifi
= (struct ifa_info
*) calloc(1, sizeof(struct ifa_info
));
465 *ifipnext
= ifi
; /* prev points to this new one */
466 ifipnext
= &ifi
->ifa_next
; /* pointer to next one goes here */
468 ifi
->ifa_flags
= flags
; /* IFF_xxx values */
469 ifi
->ifa_myflags
= myflags
; /* IFI_xxx values */
470 memcpy(ifi
->ifa_name
, ifr
->ifr_name
, IFA_NAME
);
471 ifi
->ifa_name
[IFA_NAME
-1] = '\0';
472 /* end get_ifa_info2 */
473 /* include get_ifa_info3 */
474 switch (ifr
->ifr_addr
.sa_family
) {
476 sinptr
= (struct sockaddr_in
*) &ifr
->ifr_addr
;
477 if (ifi
->ifa_addr
== NULL
) {
478 ifi
->ifa_addr
= (struct sockaddr
*) calloc(1, sizeof(struct sockaddr_in
));
479 memcpy(ifi
->ifa_addr
, sinptr
, sizeof(struct sockaddr_in
));
481 #ifdef SIOCGIFBRDADDR
482 if (flags
& IFF_BROADCAST
) {
483 ioctl(sockfd
, SIOCGIFBRDADDR
, &ifrcopy
);
484 sinptr
= (struct sockaddr_in
*) &ifrcopy
.ifr_broadaddr
;
485 ifi
->ifa_brdaddr
= (struct sockaddr
*) calloc(1, sizeof(struct sockaddr_in
));
486 memcpy(ifi
->ifa_brdaddr
, sinptr
, sizeof(struct sockaddr_in
));
490 #ifdef SIOCGIFDSTADDR
491 if (flags
& IFF_POINTOPOINT
) {
492 ioctl(sockfd
, SIOCGIFDSTADDR
, &ifrcopy
);
493 sinptr
= (struct sockaddr_in
*) &ifrcopy
.ifr_dstaddr
;
494 ifi
->ifa_dstaddr
= (struct sockaddr
*) calloc(1, sizeof(struct sockaddr_in
));
495 memcpy(ifi
->ifa_dstaddr
, sinptr
, sizeof(struct sockaddr_in
));
506 return(ifihead
); /* pointer to first structure in linked list */
508 /* end get_ifa_info3 */
510 /* include free_ifa_info */
511 mDNSlocal
void freeifaddrs(struct ifa_info
*ifihead
)
513 struct ifa_info
*ifi
, *ifinext
;
515 for (ifi
= ifihead
; ifi
!= NULL
; ifi
= ifinext
) {
516 if (ifi
->ifa_addr
!= NULL
)
518 if (ifi
->ifa_brdaddr
!= NULL
)
519 free(ifi
->ifa_brdaddr
);
520 if (ifi
->ifa_dstaddr
!= NULL
)
521 free(ifi
->ifa_dstaddr
);
522 ifinext
= ifi
->ifa_next
; /* can't fetch ifa_next after free() */
523 free(ifi
); /* the ifa_info{} itself */
526 /* end free_ifa_info */
529 Get_ifa_info(int family
, int doaliases
)
531 struct ifa_info
*ifi
;
533 if ( (ifi
= get_ifa_info(family
, doaliases
)) == NULL
)
534 debugf("get_ifa_info error");
538 mDNSlocal
int getifaddrs(struct ifa_info
**ifalist
)
540 *ifalist
= get_ifa_info(PF_INET
, false);
549 mDNSlocal mStatus
SetupInterface(mDNS
*const m
, NetworkInterfaceInfo2
*info
, struct ifaddrs
*ifa
)
552 struct sockaddr_in
*ifa_addr
= (struct sockaddr_in
*)ifa
->ifa_addr
;
553 CFSocketContext myCFSocketContext
= { 0, info
, NULL
, NULL
, NULL
};
555 info
->ifinfo
.ip
.NotAnInteger
= ifa_addr
->sin_addr
.s_addr
;
556 info
->ifinfo
.Advertise
= mDNS_AdvertiseLocalAddresses
;
558 info
->ifa_name
= (char *)mallocL("NetworkInterfaceInfo2 name", strlen(ifa
->ifa_name
) + 1);
559 if (!info
->ifa_name
) return(-1);
560 strcpy(info
->ifa_name
, ifa
->ifa_name
);
561 info
->alias
= SearchForInterfaceByName(m
, ifa
->ifa_name
);
566 info
->cfsocket53
= 0;
569 mDNS_RegisterInterface(m
, &info
->ifinfo
);
572 debugf("SetupInterface: %s Flags %04X %.4a is an alias of %.4a",
573 ifa
->ifa_name
, ifa
->ifa_flags
, &info
->ifinfo
.ip
, &info
->alias
->ifinfo
.ip
);
576 err
= SetupSocket(ifa_addr
, UnicastDNSPort
, &info
->socket53
, &info
->cfsocket53
, &myCFSocketContext
);
579 err
= SetupSocket(ifa_addr
, MulticastDNSPort
, &info
->socket
, &info
->cfsocket
, &myCFSocketContext
);
581 debugf("SetupInterface: %s Flags %04X %.4a Registered",
582 ifa
->ifa_name
, ifa
->ifa_flags
, &info
->ifinfo
.ip
);
587 mDNSlocal
void ClearInterfaceList(mDNS
*const m
)
589 while (m
->HostInterfaces
)
591 NetworkInterfaceInfo2
*info
= (NetworkInterfaceInfo2
*)(m
->HostInterfaces
);
592 mDNS_DeregisterInterface(m
, &info
->ifinfo
);
593 if (info
->ifa_name
) freeL("NetworkInterfaceInfo2 name", info
->ifa_name
);
594 if (info
->socket
> 0) shutdown(info
->socket
, 2);
595 if (info
->cfsocket
) { CFSocketInvalidate(info
->cfsocket
); CFRelease(info
->cfsocket
); }
597 if (info
->socket53
> 0) shutdown(info
->socket53
, 2);
598 if (info
->cfsocket53
) { CFSocketInvalidate(info
->cfsocket53
); CFRelease(info
->cfsocket53
); }
600 freeL("NetworkInterfaceInfo2", info
);
604 mDNSlocal mStatus
SetupInterfaceList(mDNS
*const m
)
606 struct ifaddrs
*ifalist
;
607 int err
= getifaddrs(&ifalist
);
608 struct ifaddrs
*ifa
= ifalist
;
609 struct ifaddrs
*theLoopback
= NULL
;
610 if (err
) return(err
);
612 // Set up the nice label
613 m
->nicelabel
.c
[0] = 0;
614 GetUserSpecifiedFriendlyComputerName(&m
->nicelabel
);
615 if (m
->nicelabel
.c
[0] == 0) ConvertCStringToDomainLabel("Macintosh", &m
->nicelabel
);
617 // Set up the RFC 1034-compliant label
618 m
->hostlabel
.c
[0] = 0;
619 GetUserSpecifiedRFC1034ComputerName(&m
->hostlabel
);
620 if (m
->hostlabel
.c
[0] == 0) ConvertCStringToDomainLabel("Macintosh", &m
->hostlabel
);
622 mDNS_GenerateFQDN(m
);
627 if (ifa
->ifa_addr
->sa_family
!= AF_INET
)
628 debugf("SetupInterface: %s Flags %04X Family %d not AF_INET",
629 ifa
->ifa_name
, ifa
->ifa_flags
, ifa
->ifa_addr
->sa_family
);
630 if (!(ifa
->ifa_flags
& IFF_UP
))
631 debugf("SetupInterface: %s Flags %04X Interface not IFF_UP", ifa
->ifa_name
, ifa
->ifa_flags
);
632 if (ifa
->ifa_flags
& IFF_LOOPBACK
)
633 debugf("SetupInterface: %s Flags %04X Interface IFF_LOOPBACK", ifa
->ifa_name
, ifa
->ifa_flags
);
634 if (ifa
->ifa_flags
& IFF_POINTOPOINT
)
635 debugf("SetupInterface: %s Flags %04X Interface IFF_POINTOPOINT", ifa
->ifa_name
, ifa
->ifa_flags
);
637 if (ifa
->ifa_addr
->sa_family
== AF_INET
&& (ifa
->ifa_flags
& IFF_UP
) &&
638 !(ifa
->ifa_flags
& IFF_POINTOPOINT
))
640 if (ifa
->ifa_flags
& IFF_LOOPBACK
)
644 NetworkInterfaceInfo2
*info
= (NetworkInterfaceInfo2
*)mallocL("NetworkInterfaceInfo2", sizeof(*info
));
645 if (!info
) debugf("SetupInterfaceList: Out of Memory!");
646 else SetupInterface(m
, info
, ifa
);
652 if (!m
->HostInterfaces
&& theLoopback
)
654 NetworkInterfaceInfo2
*info
= (NetworkInterfaceInfo2
*)mallocL("NetworkInterfaceInfo2", sizeof(*info
));
655 if (!info
) debugf("SetupInterfaceList: (theLoopback) Out of Memory!");
656 else SetupInterface(m
, info
, theLoopback
);
659 freeifaddrs(ifalist
);
663 mDNSlocal
void NetworkChanged(SCDynamicStoreRef store
, CFArrayRef changedKeys
, void *context
)
665 mDNS
*const m
= (mDNS
*const)context
;
666 debugf("*** Network Configuration Change ***");
667 (void)store
; // Parameter not used
668 (void)changedKeys
; // Parameter not used
670 ClearInterfaceList(m
);
671 SetupInterfaceList(m
);
672 if (NotifyClientNetworkChanged
) NotifyClientNetworkChanged();
673 mDNSCoreSleep(m
, false);
676 mDNSlocal mStatus
WatchForNetworkChanges(mDNS
*const m
)
679 SCDynamicStoreContext context
= { 0, m
, NULL
, NULL
, NULL
};
680 SCDynamicStoreRef store
= SCDynamicStoreCreate(NULL
, CFSTR("mDNSResponder"), NetworkChanged
, &context
);
681 CFStringRef key1
= SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL
, kSCDynamicStoreDomainState
, kSCEntNetIPv4
);
682 CFStringRef key2
= SCDynamicStoreKeyCreateComputerName(NULL
);
683 CFStringRef key3
= SCDynamicStoreKeyCreateHostNames(NULL
);
684 CFStringRef pattern
= SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL
, kSCDynamicStoreDomainState
, kSCCompAnyRegex
, kSCEntNetIPv4
);
685 CFMutableArrayRef keys
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
686 CFMutableArrayRef patterns
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
688 if (!store
) { fprintf(stderr
, "SCDynamicStoreCreate failed: %s\n", SCErrorString(SCError())); goto error
; }
689 if (!key1
|| !key2
|| !key3
|| !keys
|| !pattern
|| !patterns
) goto error
;
691 CFArrayAppendValue(keys
, key1
);
692 CFArrayAppendValue(keys
, key2
);
693 CFArrayAppendValue(keys
, key3
);
694 CFArrayAppendValue(patterns
, pattern
);
695 if (!SCDynamicStoreSetNotificationKeys(store
, keys
, patterns
))
696 { fprintf(stderr
, "SCDynamicStoreSetNotificationKeys failed: %s\n", SCErrorString(SCError())); goto error
; }
698 m
->p
->StoreRLS
= SCDynamicStoreCreateRunLoopSource(NULL
, store
, 0);
699 if (!m
->p
->StoreRLS
) { fprintf(stderr
, "SCDynamicStoreCreateRunLoopSource failed: %s\n", SCErrorString(SCError())); goto error
; }
701 CFRunLoopAddSource(CFRunLoopGetCurrent(), m
->p
->StoreRLS
, kCFRunLoopDefaultMode
);
707 if (store
) CFRelease(store
);
710 if (key1
) CFRelease(key1
);
711 if (key2
) CFRelease(key2
);
712 if (key3
) CFRelease(key3
);
713 if (pattern
) CFRelease(pattern
);
714 if (keys
) CFRelease(keys
);
715 if (patterns
) CFRelease(patterns
);
720 mDNSlocal
void PowerChanged(void *refcon
, io_service_t service
, natural_t messageType
, void *messageArgument
)
722 mDNS
*const m
= (mDNS
*const)refcon
;
723 (void)service
; // Parameter not used
726 case kIOMessageCanSystemPowerOff
: debugf("PowerChanged kIOMessageCanSystemPowerOff (no action)"); break; // E0000240
727 case kIOMessageSystemWillPowerOff
: debugf("PowerChanged kIOMessageSystemWillPowerOff"); mDNSCoreSleep(m
, true); break; // E0000250
728 case kIOMessageSystemWillNotPowerOff
: debugf("PowerChanged kIOMessageSystemWillNotPowerOff (no action)"); break; // E0000260
729 case kIOMessageCanSystemSleep
: debugf("PowerChanged kIOMessageCanSystemSleep (no action)"); break; // E0000270
730 case kIOMessageSystemWillSleep
: debugf("PowerChanged kIOMessageSystemWillSleep"); mDNSCoreSleep(m
, true); break; // E0000280
731 case kIOMessageSystemWillNotSleep
: debugf("PowerChanged kIOMessageSystemWillNotSleep (no action)"); break; // E0000290
732 case kIOMessageSystemHasPoweredOn
: debugf("PowerChanged kIOMessageSystemHasPoweredOn"); mDNSCoreSleep(m
, false); break; // E0000300
733 default: debugf("PowerChanged unknown message %X", messageType
); break;
735 IOAllowPowerChange(m
->p
->PowerConnection
, (long)messageArgument
);
738 mDNSlocal mStatus
WatchForPowerChanges(mDNS
*const m
)
740 IONotificationPortRef thePortRef
;
741 m
->p
->PowerConnection
= IORegisterForSystemPower(m
, &thePortRef
, PowerChanged
, &m
->p
->PowerNotifier
);
742 if (m
->p
->PowerConnection
)
744 m
->p
->PowerRLS
= IONotificationPortGetRunLoopSource(thePortRef
);
745 CFRunLoopAddSource(CFRunLoopGetCurrent(), m
->p
->PowerRLS
, kCFRunLoopDefaultMode
);
746 return(mStatus_NoError
);
751 mDNSlocal mStatus
mDNSPlatformInit_setup(mDNS
*const m
)
755 CFRunLoopTimerContext myCFRunLoopTimerContext
= { 0, m
, NULL
, NULL
, NULL
};
757 // Note: Every CFRunLoopTimer has to be created with an initial fire time, and a repeat interval, or it becomes
758 // a one-shot timer and you can't use CFRunLoopTimerSetNextFireDate(timer, when) to schedule subsequent firings.
759 // Here we create it with an initial fire time ten seconds from now, and a repeat interval of ten seconds,
760 // knowing that we'll reschedule it using CFRunLoopTimerSetNextFireDate(timer, when) long before that happens.
761 m
->p
->CFTimer
= CFRunLoopTimerCreate(kCFAllocatorDefault
, CFAbsoluteTimeGetCurrent() + 10.0, 10.0, 0, 1,
762 myCFRunLoopTimerCallBack
, &myCFRunLoopTimerContext
);
763 CFRunLoopAddTimer(CFRunLoopGetCurrent(), m
->p
->CFTimer
, kCFRunLoopDefaultMode
);
765 SetupInterfaceList(m
);
767 err
= WatchForNetworkChanges(m
);
768 if (err
) return(err
);
770 err
= WatchForPowerChanges(m
);
774 mDNSexport mStatus
mDNSPlatformInit(mDNS
*const m
)
776 mStatus result
= mDNSPlatformInit_setup(m
);
777 // We don't do asynchronous initialization on OS X, so by the time we get here the setup will already
778 // have succeeded or failed -- so if it succeeded, we should just call mDNSCoreInitComplete() immediately
779 if (result
== mStatus_NoError
) mDNSCoreInitComplete(m
, mStatus_NoError
);
783 mDNSexport
void mDNSPlatformClose(mDNS
*const m
)
785 if (m
->p
->PowerConnection
)
787 CFRunLoopRemoveSource(CFRunLoopGetCurrent(), m
->p
->PowerRLS
, kCFRunLoopDefaultMode
);
788 CFRunLoopSourceInvalidate(m
->p
->PowerRLS
);
789 CFRelease(m
->p
->PowerRLS
);
790 IODeregisterForSystemPower(&m
->p
->PowerNotifier
);
791 m
->p
->PowerConnection
= NULL
;
792 m
->p
->PowerNotifier
= NULL
;
793 m
->p
->PowerRLS
= NULL
;
798 CFRunLoopRemoveSource(CFRunLoopGetCurrent(), m
->p
->StoreRLS
, kCFRunLoopDefaultMode
);
799 CFRunLoopSourceInvalidate(m
->p
->StoreRLS
);
800 CFRelease(m
->p
->StoreRLS
);
801 CFRelease(m
->p
->Store
);
803 m
->p
->StoreRLS
= NULL
;
806 ClearInterfaceList(m
);
810 CFRunLoopTimerInvalidate(m
->p
->CFTimer
);
811 CFRelease(m
->p
->CFTimer
);
812 m
->p
->CFTimer
= NULL
;
816 mDNSexport
void mDNSPlatformScheduleTask(const mDNS
*const m
, SInt32 NextTaskTime
)
820 CFAbsoluteTime ticks
= (CFAbsoluteTime
)(NextTaskTime
- mDNSPlatformTimeNow());
821 CFAbsoluteTime interval
= ticks
/ (CFAbsoluteTime
)mDNSPlatformOneSecond
;
822 CFRunLoopTimerSetNextFireDate(m
->p
->CFTimer
, CFAbsoluteTimeGetCurrent() + interval
);
826 // Locking is a no-op here, because we're CFRunLoop-based, so we can never interrupt ourselves
827 mDNSexport
void mDNSPlatformLock (const mDNS
*const m
) { (void)m
; }
828 mDNSexport
void mDNSPlatformUnlock (const mDNS
*const m
) { (void)m
; }
829 mDNSexport
void mDNSPlatformStrCopy(const void *src
, void *dst
) { strcpy((char *)dst
, (char *)src
); }
830 mDNSexport UInt32
mDNSPlatformStrLen (const void *src
) { return(strlen((char*)src
)); }
831 mDNSexport
void mDNSPlatformMemCopy(const void *src
, void *dst
, UInt32 len
) { memcpy(dst
, src
, len
); }
832 mDNSexport Boolean
mDNSPlatformMemSame(const void *src
, const void *dst
, UInt32 len
) { return(memcmp(dst
, src
, len
) == 0); }
833 mDNSexport
void mDNSPlatformMemZero( void *dst
, UInt32 len
) { bzero(dst
, len
); }
835 mDNSexport SInt32
mDNSPlatformTimeNow()
838 gettimeofday(&tp
, NULL
);
839 // tp.tv_sec is seconds since 1st January 1970 (GMT, with no adjustment for daylight savings time)
840 // tp.tv_usec is microseconds since the start of this second (i.e. values 0 to 999999)
841 // We use the lower 22 bits of tp.tv_sec for the top 22 bits of our result
842 // and we multiply tp.tv_usec by 16 / 15625 to get a value in the range 0-1023 to go in the bottom 10 bits.
843 // This gives us a proper modular (cyclic) counter that has a resolution of roughly 1ms (actually 1/1024 second)
844 // and correctly cycles every 2^22 seconds (4194304 seconds = approx 48 days).
845 return( (tp
.tv_sec
<< 10) | (tp
.tv_usec
* 16 / 15625) );
848 mDNSexport SInt32 mDNSPlatformOneSecond
= 1024;