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 #include "mDNSClientAPI.h" // Defines the interface provided to the client layer above
42 #include "mDNSPlatformFunctions.h" // Defines the interface to the supporting layer below
43 #include "mDNSPlatformEnvironment.h" // Defines the specific types needed to run mDNS on this platform
44 #include "mDNSvsprintf.h" // Used to implement debugf_();
47 #include <stdarg.h> // For va_list support
49 #include <net/if_dl.h>
51 #include <sys/param.h>
52 #include <sys/socket.h>
54 // Code contributed by Dave Heller:
55 // Define RUN_ON_PUMA_WITHOUT_IFADDRS to compile code that will
56 // work on Mac OS X 10.1, which does not have the getifaddrs call.
57 #define RUN_ON_PUMA_WITHOUT_IFADDRS 0
59 #if RUN_ON_PUMA_WITHOUT_IFADDRS
61 #include <sys/ioctl.h>
62 #include <sys/sockio.h>
63 #define ifaddrs ifa_info
65 #define ifa_broadaddr ifa_dstaddr /* broadcast address interface */
67 #include <sys/cdefs.h>
75 #include <IOKit/IOKitLib.h>
76 #include <IOKit/IOMessage.h>
78 // ***************************************************************************
81 typedef struct NetworkInterfaceInfo2_struct NetworkInterfaceInfo2
;
82 struct NetworkInterfaceInfo2_struct
84 NetworkInterfaceInfo ifinfo
;
87 NetworkInterfaceInfo2
*alias
;
92 CFSocketRef cfsocket53
;
96 // ***************************************************************************
99 mDNSexport
void debugf_(const char *format
, ...)
101 unsigned char buffer
[512];
103 va_start(ptr
,format
);
104 buffer
[mDNS_vsprintf((char *)buffer
, format
, ptr
)] = 0;
106 fprintf(stderr
, "%s\n", buffer
);
110 mDNSexport mStatus
mDNSPlatformSendUDP(const mDNS
*const m
, const DNSMessage
*const msg
, const mDNSu8
*const end
,
111 mDNSIPAddr src
, mDNSIPPort srcport
, mDNSIPAddr dst
, mDNSIPPort dstport
)
113 NetworkInterfaceInfo2
*info
= (NetworkInterfaceInfo2
*)(m
->HostInterfaces
);
114 struct sockaddr_in to
;
115 to
.sin_family
= AF_INET
;
116 to
.sin_port
= dstport
.NotAnInteger
;
117 to
.sin_addr
.s_addr
= dst
. NotAnInteger
;
119 if (src
.NotAnInteger
== 0) debugf("mDNSPlatformSendUDP ERROR! Cannot send from zero source address");
123 if (info
->ifinfo
.ip
.NotAnInteger
== src
.NotAnInteger
)
126 if (srcport
.NotAnInteger
== MulticastDNSPort
.NotAnInteger
) s
= info
->socket
;
128 else if (srcport
.NotAnInteger
== UnicastDNSPort
.NotAnInteger
) s
= info
->socket53
;
130 else { debugf("Source port %d not allowed", (mDNSu16
)srcport
.b
[0]<<8 | srcport
.b
[1]); return(-1); }
131 err
= sendto(s
, msg
, (UInt8
*)end
- (UInt8
*)msg
, 0, (struct sockaddr
*)&to
, sizeof(to
));
132 if (err
< 0) { perror("mDNSPlatformSendUDP sendto"); return(err
); }
134 info
= (NetworkInterfaceInfo2
*)(info
->ifinfo
.next
);
137 return(mStatus_NoError
);
140 static ssize_t
myrecvfrom(const int s
, void *const buffer
, const size_t max
,
141 struct sockaddr
*const from
, size_t *const fromlen
, struct in_addr
*dstaddr
, char ifname
[128])
143 struct iovec databuffers
= { (char *)buffer
, max
};
146 struct cmsghdr
*cmPtr
;
147 char ancillary
[1024];
149 // Set up the message
150 msg
.msg_name
= (caddr_t
)from
;
151 msg
.msg_namelen
= *fromlen
;
152 msg
.msg_iov
= &databuffers
;
154 msg
.msg_control
= (caddr_t
)&ancillary
;
155 msg
.msg_controllen
= sizeof(ancillary
);
159 n
= recvmsg(s
, &msg
, 0);
160 if (n
<0 || msg
.msg_controllen
< sizeof(struct cmsghdr
) || (msg
.msg_flags
& MSG_CTRUNC
))
161 { perror("recvmsg"); return(n
); }
163 *fromlen
= msg
.msg_namelen
;
165 // Parse each option out of the ancillary data.
166 for (cmPtr
= CMSG_FIRSTHDR(&msg
); cmPtr
; cmPtr
= CMSG_NXTHDR(&msg
, cmPtr
))
168 // debugf("myrecvfrom cmsg_level %d cmsg_type %d", cmPtr->cmsg_level, cmPtr->cmsg_type);
169 if (cmPtr
->cmsg_level
== IPPROTO_IP
&& cmPtr
->cmsg_type
== IP_RECVDSTADDR
)
170 *dstaddr
= *(struct in_addr
*)CMSG_DATA(cmPtr
);
171 if (cmPtr
->cmsg_level
== IPPROTO_IP
&& cmPtr
->cmsg_type
== IP_RECVIF
)
173 struct sockaddr_dl
*sdl
= (struct sockaddr_dl
*)CMSG_DATA(cmPtr
);
174 if (sdl
->sdl_nlen
< sizeof(ifname
))
176 mDNSPlatformMemCopy(sdl
->sdl_data
, ifname
, sdl
->sdl_nlen
);
177 ifname
[sdl
->sdl_nlen
] = 0;
178 // debugf("IP_RECVIF sdl_index %d, sdl_data %s len %d", sdl->sdl_index, ifname, sdl->sdl_nlen);
186 mDNSlocal
void myCFSocketCallBack(CFSocketRef s
, CFSocketCallBackType type
, CFDataRef address
, const void *data
, void *context
)
188 mDNSIPAddr senderaddr
, destaddr
;
189 mDNSIPPort senderport
;
190 NetworkInterfaceInfo2
*info
= (NetworkInterfaceInfo2
*)context
;
191 mDNS
*const m
= info
->m
;
194 struct sockaddr_in from
;
195 size_t fromlen
= sizeof(from
);
196 char packetifname
[128] = "";
199 (void)address
; // Parameter not used
200 (void)data
; // Parameter not used
202 if (type
!= kCFSocketReadCallBack
) debugf("myCFSocketCallBack: Why is type not kCFSocketReadCallBack?");
204 if (s
== info
->cfsocket53
)
205 err
= myrecvfrom(info
->socket53
, &packet
, sizeof(packet
), (struct sockaddr
*)&from
, &fromlen
, &to
, packetifname
);
208 err
= myrecvfrom(info
->socket
, &packet
, sizeof(packet
), (struct sockaddr
*)&from
, &fromlen
, &to
, packetifname
);
210 if (err
< 0) { debugf("myCFSocketCallBack recvfrom error %d", err
); return; }
212 senderaddr
.NotAnInteger
= from
.sin_addr
.s_addr
;
213 senderport
.NotAnInteger
= from
.sin_port
;
214 destaddr
.NotAnInteger
= to
.s_addr
;
216 // Even though we indicated a specific interface in the IP_ADD_MEMBERSHIP call, a weirdness of the
217 // sockets API means that even though this socket has only officially joined the multicast group
218 // on one specific interface, the kernel will still deliver multicast packets to it no matter which
219 // interface they arrive on. According to the official Unix Powers That Be, this is Not A Bug.
220 // To work around this weirdness, we use the IP_RECVIF option to find the name of the interface
221 // on which the packet arrived, and ignore the packet if it really arrived on some other interface.
222 if (strcmp(info
->ifa_name
, packetifname
))
224 verbosedebugf("myCFSocketCallBack got a packet from %.4a to %.4a on interface %.4a/%s (Ignored -- really arrived on interface %s)",
225 &senderaddr
, &destaddr
, &info
->ifinfo
.ip
, info
->ifa_name
, packetifname
);
229 verbosedebugf("myCFSocketCallBack got a packet from %.4a to %.4a on interface %.4a/%s",
230 &senderaddr
, &destaddr
, &info
->ifinfo
.ip
, info
->ifa_name
);
232 if (err
< sizeof(DNSMessageHeader
)) { debugf("myCFSocketCallBack packet length (%d) too short", err
); return; }
235 if (s
== info
->cfsocket53
)
236 mDNSCoreReceive(m
, &packet
, (unsigned char*)&packet
+ err
, senderaddr
, senderport
, destaddr
, UnicastDNSPort
, info
->ifinfo
.ip
);
239 mDNSCoreReceive(m
, &packet
, (unsigned char*)&packet
+ err
, senderaddr
, senderport
, destaddr
, MulticastDNSPort
, info
->ifinfo
.ip
);
242 mDNSlocal
void myCFRunLoopTimerCallBack(CFRunLoopTimerRef timer
, void *info
)
244 (void)timer
; // Parameter not used
245 mDNSCoreTask((mDNS
*const)info
);
248 // This gets the text of the field currently labelled "Computer Name" in the Sharing Prefs Control Panel
249 mDNSlocal
void GetUserSpecifiedFriendlyComputerName(domainlabel
*const namelabel
)
251 CFStringEncoding encoding
= kCFStringEncodingUTF8
;
252 CFStringRef cfs
= SCDynamicStoreCopyComputerName(NULL
, &encoding
);
255 CFStringGetPascalString(cfs
, namelabel
->c
, sizeof(*namelabel
), kCFStringEncodingUTF8
);
260 // This gets the text of the field currently labelled "Rendezvous Name" in the Sharing Prefs Control Panel
261 mDNSlocal
void GetUserSpecifiedRFC1034ComputerName(domainlabel
*const namelabel
)
263 CFStringRef cfs
= SCDynamicStoreCopyLocalHostName(NULL
);
266 CFStringGetPascalString(cfs
, namelabel
->c
, sizeof(*namelabel
), kCFStringEncodingUTF8
);
271 mDNSlocal mStatus
SetupSocket(struct sockaddr_in
*ifa_addr
, mDNSIPPort port
, int *s
, CFSocketRef
*c
, CFSocketContext
*context
)
275 const int twofivefive
= 255;
277 struct sockaddr_in listening_sockaddr
;
278 CFRunLoopSourceRef rls
;
280 // Open the socket...
281 *s
= socket(PF_INET
, SOCK_DGRAM
, IPPROTO_UDP
);
283 if (*s
< 0) { perror("socket"); return(*s
); }
285 // ... with a shared UDP port
286 err
= setsockopt(*s
, SOL_SOCKET
, SO_REUSEPORT
, &on
, sizeof(on
));
287 if (err
< 0) { perror("setsockopt - SO_REUSEPORT"); return(err
); }
289 // We want to receive destination addresses
290 err
= setsockopt(*s
, IPPROTO_IP
, IP_RECVDSTADDR
, &on
, sizeof(on
));
291 if (err
< 0) { perror("setsockopt - IP_RECVDSTADDR"); return(err
); }
293 // We want to receive interface identifiers
294 err
= setsockopt(*s
, IPPROTO_IP
, IP_RECVIF
, &on
, sizeof(on
));
295 if (err
< 0) { perror("setsockopt - IP_RECVIF"); return(err
); }
297 // Add multicast group membership on this interface
298 imr
.imr_multiaddr
.s_addr
= AllDNSLinkGroup
.NotAnInteger
;
299 imr
.imr_interface
= ifa_addr
->sin_addr
;
300 err
= setsockopt(*s
, IPPROTO_IP
, IP_ADD_MEMBERSHIP
, &imr
, sizeof(struct ip_mreq
));
301 if (err
< 0) { perror("setsockopt - IP_ADD_MEMBERSHIP"); return(err
); }
303 // Specify outgoing interface too
304 err
= setsockopt(*s
, IPPROTO_IP
, IP_MULTICAST_IF
, &ifa_addr
->sin_addr
, sizeof(ifa_addr
->sin_addr
));
305 if (err
< 0) { perror("setsockopt - IP_MULTICAST_IF"); return(err
); }
307 // Send unicast packets with TTL 255
308 err
= setsockopt(*s
, IPPROTO_IP
, IP_TTL
, &twofivefive
, sizeof(twofivefive
));
309 if (err
< 0) { perror("setsockopt - IP_TTL"); return(err
); }
311 // And multicast packets with TTL 255 too
312 err
= setsockopt(*s
, IPPROTO_IP
, IP_MULTICAST_TTL
, &twofivefive
, sizeof(twofivefive
));
313 if (err
< 0) { perror("setsockopt - IP_MULTICAST_TTL"); return(err
); }
315 // And start listening for packets
316 listening_sockaddr
.sin_family
= AF_INET
;
317 listening_sockaddr
.sin_port
= port
.NotAnInteger
;
318 listening_sockaddr
.sin_addr
.s_addr
= 0; // Want to receive multicasts AND unicasts on this socket
319 err
= bind(*s
, (struct sockaddr
*) &listening_sockaddr
, sizeof(listening_sockaddr
));
322 if (port
.NotAnInteger
== UnicastDNSPort
.NotAnInteger
) err
= 0;
327 *c
= CFSocketCreateWithNative(kCFAllocatorDefault
, *s
, kCFSocketReadCallBack
, myCFSocketCallBack
, context
);
328 rls
= CFSocketCreateRunLoopSource(kCFAllocatorDefault
, *c
, 0);
329 CFRunLoopAddSource(CFRunLoopGetCurrent(), rls
, kCFRunLoopDefaultMode
);
336 mDNSlocal NetworkInterfaceInfo2
*SearchForInterfaceByAddr(mDNS
*const m
, mDNSIPAddr ip
)
338 NetworkInterfaceInfo2
*info
= (NetworkInterfaceInfo2
*)(m
->HostInterfaces
);
341 if (info
->ifinfo
.ip
.NotAnInteger
== ip
.NotAnInteger
) return(info
);
342 info
= (NetworkInterfaceInfo2
*)(info
->ifinfo
.next
);
348 mDNSlocal NetworkInterfaceInfo2
*SearchForInterfaceByName(mDNS
*const m
, char *ifname
)
350 NetworkInterfaceInfo2
*info
= (NetworkInterfaceInfo2
*)(m
->HostInterfaces
);
353 if (!strcmp(info
->ifa_name
, ifname
)) return(info
);
354 info
= (NetworkInterfaceInfo2
*)(info
->ifinfo
.next
);
359 #if RUN_ON_PUMA_WITHOUT_IFADDRS
361 /* Our own header for the programs that need interface configuration info.
362 Include this file, instead of "unp.h". */
364 #define IFA_NAME 16 /* same as IFNAMSIZ in <net/if.h> */
365 #define IFA_HADDR 8 /* allow for 64-bit EUI-64 in future */
368 char ifa_name
[IFA_NAME
]; /* interface name, null terminated */
369 u_char ifa_haddr
[IFA_HADDR
]; /* hardware address */
370 u_short ifa_hlen
; /* #bytes in hardware address: 0, 6, 8 */
371 short ifa_flags
; /* IFF_xxx constants from <net/if.h> */
372 short ifa_myflags
; /* our own IFI_xxx flags */
373 struct sockaddr
*ifa_addr
; /* primary address */
374 struct sockaddr
*ifa_brdaddr
;/* broadcast address */
375 struct sockaddr
*ifa_dstaddr
;/* destination address */
376 struct ifa_info
*ifa_next
; /* next of these structures */
379 #define IFI_ALIAS 1 /* ifa_addr is an alias */
381 /* function prototypes */
382 struct ifa_info
*get_ifa_info(int, int);
383 struct ifa_info
*Get_ifa_info(int, int);
384 void free_ifa_info(struct ifa_info
*);
386 #define HAVE_SOCKADDR_SA_LEN 1
389 get_ifa_info(int family
, int doaliases
)
391 struct ifa_info
*ifi
, *ifihead
, **ifipnext
;
392 int sockfd
, len
, lastlen
, flags
, myflags
;
393 char *ptr
, *buf
, lastname
[IFNAMSIZ
], *cptr
;
395 struct ifreq
*ifr
, ifrcopy
;
396 struct sockaddr_in
*sinptr
;
398 sockfd
= socket(AF_INET
, SOCK_DGRAM
, 0);
401 len
= 100 * sizeof(struct ifreq
); /* initial buffer size guess */
403 buf
= (char *) malloc(len
);
406 if (ioctl(sockfd
, SIOCGIFCONF
, &ifc
) < 0) {
407 if (errno
!= EINVAL
|| lastlen
!= 0)
408 debugf("ioctl error");
410 if (ifc
.ifc_len
== lastlen
)
411 break; /* success, len has not changed */
412 lastlen
= ifc
.ifc_len
;
414 len
+= 10 * sizeof(struct ifreq
); /* increment */
420 /* end get_ifa_info1 */
422 /* include get_ifa_info2 */
423 for (ptr
= buf
; ptr
< buf
+ ifc
.ifc_len
; ) {
424 ifr
= (struct ifreq
*) ptr
;
426 #ifdef HAVE_SOCKADDR_SA_LEN
427 len
= MAX(sizeof(struct sockaddr
), ifr
->ifr_addr
.sa_len
);
429 switch (ifr
->ifr_addr
.sa_family
) {
432 len
= sizeof(struct sockaddr_in6
);
437 len
= sizeof(struct sockaddr
);
440 #endif /* HAVE_SOCKADDR_SA_LEN */
441 ptr
+= sizeof(ifr
->ifr_name
) + len
; /* for next one in buffer */
443 if (ifr
->ifr_addr
.sa_family
!= family
)
444 continue; /* ignore if not desired address family */
447 if ( (cptr
= strchr(ifr
->ifr_name
, ':')) != NULL
)
448 *cptr
= 0; /* replace colon will null */
449 if (strncmp(lastname
, ifr
->ifr_name
, IFNAMSIZ
) == 0) {
451 continue; /* already processed this interface */
454 memcpy(lastname
, ifr
->ifr_name
, IFNAMSIZ
);
457 ioctl(sockfd
, SIOCGIFFLAGS
, &ifrcopy
);
458 flags
= ifrcopy
.ifr_flags
;
459 if ((flags
& IFF_UP
) == 0)
460 continue; /* ignore if interface not up */
462 ifi
= (struct ifa_info
*) calloc(1, sizeof(struct ifa_info
));
463 *ifipnext
= ifi
; /* prev points to this new one */
464 ifipnext
= &ifi
->ifa_next
; /* pointer to next one goes here */
466 ifi
->ifa_flags
= flags
; /* IFF_xxx values */
467 ifi
->ifa_myflags
= myflags
; /* IFI_xxx values */
468 memcpy(ifi
->ifa_name
, ifr
->ifr_name
, IFA_NAME
);
469 ifi
->ifa_name
[IFA_NAME
-1] = '\0';
470 /* end get_ifa_info2 */
471 /* include get_ifa_info3 */
472 switch (ifr
->ifr_addr
.sa_family
) {
474 sinptr
= (struct sockaddr_in
*) &ifr
->ifr_addr
;
475 if (ifi
->ifa_addr
== NULL
) {
476 ifi
->ifa_addr
= (struct sockaddr
*) calloc(1, sizeof(struct sockaddr_in
));
477 memcpy(ifi
->ifa_addr
, sinptr
, sizeof(struct sockaddr_in
));
479 #ifdef SIOCGIFBRDADDR
480 if (flags
& IFF_BROADCAST
) {
481 ioctl(sockfd
, SIOCGIFBRDADDR
, &ifrcopy
);
482 sinptr
= (struct sockaddr_in
*) &ifrcopy
.ifr_broadaddr
;
483 ifi
->ifa_brdaddr
= (struct sockaddr
*) calloc(1, sizeof(struct sockaddr_in
));
484 memcpy(ifi
->ifa_brdaddr
, sinptr
, sizeof(struct sockaddr_in
));
488 #ifdef SIOCGIFDSTADDR
489 if (flags
& IFF_POINTOPOINT
) {
490 ioctl(sockfd
, SIOCGIFDSTADDR
, &ifrcopy
);
491 sinptr
= (struct sockaddr_in
*) &ifrcopy
.ifr_dstaddr
;
492 ifi
->ifa_dstaddr
= (struct sockaddr
*) calloc(1, sizeof(struct sockaddr_in
));
493 memcpy(ifi
->ifa_dstaddr
, sinptr
, sizeof(struct sockaddr_in
));
504 return(ifihead
); /* pointer to first structure in linked list */
506 /* end get_ifa_info3 */
508 /* include free_ifa_info */
509 mDNSlocal
void freeifaddrs(struct ifa_info
*ifihead
)
511 struct ifa_info
*ifi
, *ifinext
;
513 for (ifi
= ifihead
; ifi
!= NULL
; ifi
= ifinext
) {
514 if (ifi
->ifa_addr
!= NULL
)
516 if (ifi
->ifa_brdaddr
!= NULL
)
517 free(ifi
->ifa_brdaddr
);
518 if (ifi
->ifa_dstaddr
!= NULL
)
519 free(ifi
->ifa_dstaddr
);
520 ifinext
= ifi
->ifa_next
; /* can't fetch ifa_next after free() */
521 free(ifi
); /* the ifa_info{} itself */
524 /* end free_ifa_info */
527 Get_ifa_info(int family
, int doaliases
)
529 struct ifa_info
*ifi
;
531 if ( (ifi
= get_ifa_info(family
, doaliases
)) == NULL
)
532 debugf("get_ifa_info error");
536 mDNSlocal
int getifaddrs(struct ifa_info
**ifalist
)
538 *ifalist
= get_ifa_info(PF_INET
, false);
547 mDNSlocal mStatus
SetupInterface(mDNS
*const m
, NetworkInterfaceInfo2
*info
, struct ifaddrs
*ifa
)
550 struct sockaddr_in
*ifa_addr
= (struct sockaddr_in
*)ifa
->ifa_addr
;
551 CFSocketContext myCFSocketContext
= { 0, info
, NULL
, NULL
, NULL
};
553 info
->ifinfo
.ip
.NotAnInteger
= ifa_addr
->sin_addr
.s_addr
;
554 info
->ifinfo
.Advertise
= mDNS_AdvertiseLocalAddresses
;
556 info
->ifa_name
= (char *)mallocL("NetworkInterfaceInfo2 name", strlen(ifa
->ifa_name
) + 1);
557 if (!info
->ifa_name
) return(-1);
558 strcpy(info
->ifa_name
, ifa
->ifa_name
);
559 info
->alias
= SearchForInterfaceByName(m
, ifa
->ifa_name
);
564 info
->cfsocket53
= 0;
567 mDNS_RegisterInterface(m
, &info
->ifinfo
);
570 debugf("SetupInterface: %s Flags %04X %.4a is an alias of %.4a",
571 ifa
->ifa_name
, ifa
->ifa_flags
, &info
->ifinfo
.ip
, &info
->alias
->ifinfo
.ip
);
574 err
= SetupSocket(ifa_addr
, UnicastDNSPort
, &info
->socket53
, &info
->cfsocket53
, &myCFSocketContext
);
577 err
= SetupSocket(ifa_addr
, MulticastDNSPort
, &info
->socket
, &info
->cfsocket
, &myCFSocketContext
);
579 debugf("SetupInterface: %s Flags %04X %.4a Registered",
580 ifa
->ifa_name
, ifa
->ifa_flags
, &info
->ifinfo
.ip
);
585 mDNSlocal
void ClearInterfaceList(mDNS
*const m
)
587 while (m
->HostInterfaces
)
589 NetworkInterfaceInfo2
*info
= (NetworkInterfaceInfo2
*)(m
->HostInterfaces
);
590 mDNS_DeregisterInterface(m
, &info
->ifinfo
);
591 if (info
->ifa_name
) freeL("NetworkInterfaceInfo2 name", info
->ifa_name
);
592 if (info
->socket
> 0) shutdown(info
->socket
, 2);
593 if (info
->cfsocket
) { CFSocketInvalidate(info
->cfsocket
); CFRelease(info
->cfsocket
); }
595 if (info
->socket53
> 0) shutdown(info
->socket53
, 2);
596 if (info
->cfsocket53
) { CFSocketInvalidate(info
->cfsocket53
); CFRelease(info
->cfsocket53
); }
598 freeL("NetworkInterfaceInfo2", info
);
602 mDNSlocal mStatus
SetupInterfaceList(mDNS
*const m
)
604 struct ifaddrs
*ifalist
;
605 int err
= getifaddrs(&ifalist
);
606 struct ifaddrs
*ifa
= ifalist
;
607 struct ifaddrs
*theLoopback
= NULL
;
608 if (err
) return(err
);
610 // Set up the nice label
611 m
->nicelabel
.c
[0] = 0;
612 GetUserSpecifiedFriendlyComputerName(&m
->nicelabel
);
613 if (m
->nicelabel
.c
[0] == 0) ConvertCStringToDomainLabel("Macintosh", &m
->nicelabel
);
615 // Set up the RFC 1034-compliant label
616 m
->hostlabel
.c
[0] = 0;
617 GetUserSpecifiedRFC1034ComputerName(&m
->hostlabel
);
618 if (m
->hostlabel
.c
[0] == 0) ConvertCStringToDomainLabel("Macintosh", &m
->hostlabel
);
620 mDNS_GenerateFQDN(m
);
625 if (ifa
->ifa_addr
->sa_family
!= AF_INET
)
626 debugf("SetupInterface: %s Flags %04X Family %d not AF_INET",
627 ifa
->ifa_name
, ifa
->ifa_flags
, ifa
->ifa_addr
->sa_family
);
628 if (!(ifa
->ifa_flags
& IFF_UP
))
629 debugf("SetupInterface: %s Flags %04X Interface not IFF_UP", ifa
->ifa_name
, ifa
->ifa_flags
);
630 if (ifa
->ifa_flags
& IFF_LOOPBACK
)
631 debugf("SetupInterface: %s Flags %04X Interface IFF_LOOPBACK", ifa
->ifa_name
, ifa
->ifa_flags
);
632 if (ifa
->ifa_flags
& IFF_POINTOPOINT
)
633 debugf("SetupInterface: %s Flags %04X Interface IFF_POINTOPOINT", ifa
->ifa_name
, ifa
->ifa_flags
);
635 if (ifa
->ifa_addr
->sa_family
== AF_INET
&& (ifa
->ifa_flags
& IFF_UP
) &&
636 !(ifa
->ifa_flags
& IFF_POINTOPOINT
))
638 if (ifa
->ifa_flags
& IFF_LOOPBACK
)
642 NetworkInterfaceInfo2
*info
= (NetworkInterfaceInfo2
*)mallocL("NetworkInterfaceInfo2", sizeof(*info
));
643 if (!info
) debugf("SetupInterfaceList: Out of Memory!");
644 else SetupInterface(m
, info
, ifa
);
650 if (!m
->HostInterfaces
&& theLoopback
)
652 NetworkInterfaceInfo2
*info
= (NetworkInterfaceInfo2
*)mallocL("NetworkInterfaceInfo2", sizeof(*info
));
653 if (!info
) debugf("SetupInterfaceList: (theLoopback) Out of Memory!");
654 else SetupInterface(m
, info
, theLoopback
);
657 freeifaddrs(ifalist
);
661 mDNSlocal
void NetworkChanged(SCDynamicStoreRef store
, CFArrayRef changedKeys
, void *context
)
663 mDNS
*const m
= (mDNS
*const)context
;
664 debugf("*** Network Configuration Change ***");
665 (void)store
; // Parameter not used
666 (void)changedKeys
; // Parameter not used
667 ClearInterfaceList(m
);
668 SetupInterfaceList(m
);
669 mDNSCoreSleep(m
, false);
672 mDNSlocal mStatus
WatchForNetworkChanges(mDNS
*const m
)
675 SCDynamicStoreContext context
= { 0, m
, NULL
, NULL
, NULL
};
676 SCDynamicStoreRef store
= SCDynamicStoreCreate(NULL
, CFSTR("mDNSResponder"), NetworkChanged
, &context
);
677 CFStringRef key1
= SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL
, kSCDynamicStoreDomainState
, kSCEntNetIPv4
);
678 CFStringRef key2
= SCDynamicStoreKeyCreateComputerName(NULL
);
679 CFStringRef key3
= SCDynamicStoreKeyCreateHostNames(NULL
);
680 CFStringRef pattern
= SCDynamicStoreKeyCreateNetworkServiceEntity(NULL
, kSCDynamicStoreDomainState
, kSCCompAnyRegex
, kSCEntNetIPv4
);
681 CFMutableArrayRef keys
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
682 CFMutableArrayRef patterns
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
684 if (!store
) { fprintf(stderr
, "SCDynamicStoreCreate failed: %s\n", SCErrorString(SCError())); goto error
; }
685 if (!key1
|| !key2
|| !key3
|| !keys
|| !pattern
|| !patterns
) goto error
;
687 CFArrayAppendValue(keys
, key1
);
688 CFArrayAppendValue(keys
, key2
);
689 CFArrayAppendValue(keys
, key3
);
690 CFArrayAppendValue(patterns
, pattern
);
691 if (!SCDynamicStoreSetNotificationKeys(store
, keys
, patterns
))
692 { fprintf(stderr
, "SCDynamicStoreSetNotificationKeys failed: %s\n", SCErrorString(SCError())); goto error
; }
694 m
->p
->StoreRLS
= SCDynamicStoreCreateRunLoopSource(NULL
, store
, 0);
695 if (!m
->p
->StoreRLS
) { fprintf(stderr
, "SCDynamicStoreCreateRunLoopSource failed: %s\n", SCErrorString(SCError())); goto error
; }
697 CFRunLoopAddSource(CFRunLoopGetCurrent(), m
->p
->StoreRLS
, kCFRunLoopDefaultMode
);
703 if (store
) CFRelease(store
);
706 if (key1
) CFRelease(key1
);
707 if (key2
) CFRelease(key2
);
708 if (key3
) CFRelease(key3
);
709 if (pattern
) CFRelease(pattern
);
710 if (keys
) CFRelease(keys
);
711 if (patterns
) CFRelease(patterns
);
716 mDNSlocal
void PowerChanged(void *refcon
, io_service_t service
, natural_t messageType
, void *messageArgument
)
718 mDNS
*const m
= (mDNS
*const)refcon
;
719 (void)service
; // Parameter not used
722 case kIOMessageCanSystemPowerOff
: debugf("PowerChanged kIOMessageCanSystemPowerOff (no action)"); break; // E0000240
723 case kIOMessageSystemWillPowerOff
: debugf("PowerChanged kIOMessageSystemWillPowerOff"); mDNSCoreSleep(m
, true); break; // E0000250
724 case kIOMessageSystemWillNotPowerOff
: debugf("PowerChanged kIOMessageSystemWillNotPowerOff (no action)"); break; // E0000260
725 case kIOMessageCanSystemSleep
: debugf("PowerChanged kIOMessageCanSystemSleep (no action)"); break; // E0000270
726 case kIOMessageSystemWillSleep
: debugf("PowerChanged kIOMessageSystemWillSleep"); mDNSCoreSleep(m
, true); break; // E0000280
727 case kIOMessageSystemWillNotSleep
: debugf("PowerChanged kIOMessageSystemWillNotSleep (no action)"); break; // E0000290
728 case kIOMessageSystemHasPoweredOn
: debugf("PowerChanged kIOMessageSystemHasPoweredOn"); mDNSCoreSleep(m
, false); break; // E0000300
729 default: debugf("PowerChanged unknown message %X", messageType
); break;
731 IOAllowPowerChange(m
->p
->PowerConnection
, (long)messageArgument
);
734 mDNSlocal mStatus
WatchForPowerChanges(mDNS
*const m
)
736 IONotificationPortRef thePortRef
;
737 m
->p
->PowerConnection
= IORegisterForSystemPower(m
, &thePortRef
, PowerChanged
, &m
->p
->PowerNotifier
);
738 if (m
->p
->PowerConnection
)
740 m
->p
->PowerRLS
= IONotificationPortGetRunLoopSource(thePortRef
);
741 CFRunLoopAddSource(CFRunLoopGetCurrent(), m
->p
->PowerRLS
, kCFRunLoopDefaultMode
);
742 return(mStatus_NoError
);
747 mDNSlocal mStatus
mDNSPlatformInit_setup(mDNS
*const m
)
751 CFRunLoopTimerContext myCFRunLoopTimerContext
= { 0, m
, NULL
, NULL
, NULL
};
753 // Note: Every CFRunLoopTimer has to be created with an initial fire time, and a repeat interval, or it becomes
754 // a one-shot timer and you can't use CFRunLoopTimerSetNextFireDate(timer, when) to schedule subsequent firings.
755 // Here we create it with an initial fire time ten seconds from now, and a repeat interval of ten seconds,
756 // knowing that we'll reschedule it using CFRunLoopTimerSetNextFireDate(timer, when) long before that happens.
757 m
->p
->CFTimer
= CFRunLoopTimerCreate(kCFAllocatorDefault
, CFAbsoluteTimeGetCurrent() + 10.0, 10.0, 0, 1,
758 myCFRunLoopTimerCallBack
, &myCFRunLoopTimerContext
);
759 CFRunLoopAddTimer(CFRunLoopGetCurrent(), m
->p
->CFTimer
, kCFRunLoopDefaultMode
);
761 SetupInterfaceList(m
);
763 err
= WatchForNetworkChanges(m
);
764 if (err
) return(err
);
766 err
= WatchForPowerChanges(m
);
770 mDNSexport mStatus
mDNSPlatformInit(mDNS
*const m
)
772 mStatus result
= mDNSPlatformInit_setup(m
);
773 // We don't do asynchronous initialization on OS X, so by the time we get here the setup will already
774 // have succeeded or failed -- so if it succeeded, we should just call mDNSCoreInitComplete() immediately
775 if (result
== mStatus_NoError
) mDNSCoreInitComplete(m
, mStatus_NoError
);
779 mDNSexport
void mDNSPlatformClose(mDNS
*const m
)
781 if (m
->p
->PowerConnection
)
783 CFRunLoopRemoveSource(CFRunLoopGetCurrent(), m
->p
->PowerRLS
, kCFRunLoopDefaultMode
);
784 CFRunLoopSourceInvalidate(m
->p
->PowerRLS
);
785 CFRelease(m
->p
->PowerRLS
);
786 IODeregisterForSystemPower(&m
->p
->PowerNotifier
);
787 m
->p
->PowerConnection
= NULL
;
788 m
->p
->PowerNotifier
= NULL
;
789 m
->p
->PowerRLS
= NULL
;
794 CFRunLoopRemoveSource(CFRunLoopGetCurrent(), m
->p
->StoreRLS
, kCFRunLoopDefaultMode
);
795 CFRunLoopSourceInvalidate(m
->p
->StoreRLS
);
796 CFRelease(m
->p
->StoreRLS
);
797 CFRelease(m
->p
->Store
);
799 m
->p
->StoreRLS
= NULL
;
802 ClearInterfaceList(m
);
806 CFRunLoopTimerInvalidate(m
->p
->CFTimer
);
807 CFRelease(m
->p
->CFTimer
);
808 m
->p
->CFTimer
= NULL
;
812 // To Do: Find out how to implement a proper modular time function in CF
813 mDNSexport
void mDNSPlatformScheduleTask(const mDNS
*const m
, SInt32 NextTaskTime
)
817 CFAbsoluteTime ticks
= (CFAbsoluteTime
)(NextTaskTime
- mDNSPlatformTimeNow());
818 CFAbsoluteTime interval
= ticks
/ (CFAbsoluteTime
)mDNSPlatformOneSecond
;
819 CFRunLoopTimerSetNextFireDate(m
->p
->CFTimer
, CFAbsoluteTimeGetCurrent() + interval
);
823 // Locking is a no-op here, because we're CFRunLoop-based, so we can never interrupt ourselves
824 mDNSexport
void mDNSPlatformLock (const mDNS
*const m
) { (void)m
; }
825 mDNSexport
void mDNSPlatformUnlock (const mDNS
*const m
) { (void)m
; }
826 mDNSexport
void mDNSPlatformStrCopy(const void *src
, void *dst
) { strcpy((char *)dst
, (char *)src
); }
827 mDNSexport UInt32
mDNSPlatformStrLen (const void *src
) { return(strlen((char*)src
)); }
828 mDNSexport
void mDNSPlatformMemCopy(const void *src
, void *dst
, UInt32 len
) { memcpy(dst
, src
, len
); }
829 mDNSexport Boolean
mDNSPlatformMemSame(const void *src
, const void *dst
, UInt32 len
) { return(memcmp(dst
, src
, len
) == 0); }
830 mDNSexport
void mDNSPlatformMemZero( void *dst
, UInt32 len
) { bzero(dst
, len
); }
832 mDNSexport SInt32
mDNSPlatformTimeNow()
835 gettimeofday(&tp
, NULL
);
836 // tp.tv_sec is seconds since 1st January 1970 (GMT, with no adjustment for daylight savings time)
837 // tp.tv_usec is microseconds since the start of this second (i.e. values 0 to 999999)
838 // We use the lower 22 bits of tp.tv_sec for the top 22 bits of our result
839 // 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.
840 // This gives us a proper modular (cyclic) counter that has a resolution of roughly 1ms (actually 1/1024 second)
841 // and correctly cycles every 2^22 seconds (4194304 seconds = approx 48 days).
842 return( (tp
.tv_sec
<< 10) | (tp
.tv_usec
* 16 / 15625) );
845 mDNSexport SInt32 mDNSPlatformOneSecond
= 1024;