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 extern void LogErrorMessage(const char *format
, ...);
82 // ***************************************************************************
85 typedef struct NetworkInterfaceInfo2_struct NetworkInterfaceInfo2
;
86 struct NetworkInterfaceInfo2_struct
88 NetworkInterfaceInfo ifinfo
;
91 NetworkInterfaceInfo2
*alias
;
96 CFSocketRef cfsocket53
;
100 // ***************************************************************************
103 mDNSexport
void debugf_(const char *format
, ...)
105 unsigned char buffer
[512];
107 va_start(ptr
,format
);
108 buffer
[mDNS_vsprintf((char *)buffer
, format
, ptr
)] = 0;
110 fprintf(stderr
, "%s\n", buffer
);
114 mDNSexport mStatus
mDNSPlatformSendUDP(const mDNS
*const m
, const DNSMessage
*const msg
, const mDNSu8
*const end
,
115 mDNSIPAddr src
, mDNSIPPort srcport
, mDNSIPAddr dst
, mDNSIPPort dstport
)
117 NetworkInterfaceInfo2
*info
= (NetworkInterfaceInfo2
*)(m
->HostInterfaces
);
118 struct sockaddr_in to
;
119 to
.sin_family
= AF_INET
;
120 to
.sin_port
= dstport
.NotAnInteger
;
121 to
.sin_addr
.s_addr
= dst
. NotAnInteger
;
123 if (src
.NotAnInteger
== 0) debugf("mDNSPlatformSendUDP ERROR! Cannot send from zero source address");
127 if (info
->ifinfo
.ip
.NotAnInteger
== src
.NotAnInteger
)
130 if (srcport
.NotAnInteger
== MulticastDNSPort
.NotAnInteger
) s
= info
->socket
;
132 else if (srcport
.NotAnInteger
== UnicastDNSPort
.NotAnInteger
) s
= info
->socket53
;
134 else { debugf("Source port %d not allowed", (mDNSu16
)srcport
.b
[0]<<8 | srcport
.b
[1]); return(-1); }
135 err
= sendto(s
, msg
, (UInt8
*)end
- (UInt8
*)msg
, 0, (struct sockaddr
*)&to
, sizeof(to
));
136 if (err
< 0) { perror("mDNSPlatformSendUDP sendto"); return(err
); }
138 info
= (NetworkInterfaceInfo2
*)(info
->ifinfo
.next
);
141 return(mStatus_NoError
);
144 static ssize_t
myrecvfrom(const int s
, void *const buffer
, const size_t max
,
145 struct sockaddr
*const from
, size_t *const fromlen
, struct in_addr
*dstaddr
, char ifname
[128])
147 static int numLogMessages
= 0;
148 struct iovec databuffers
= { (char *)buffer
, max
};
151 struct cmsghdr
*cmPtr
;
152 char ancillary
[1024];
154 // Set up the message
155 msg
.msg_name
= (caddr_t
)from
;
156 msg
.msg_namelen
= *fromlen
;
157 msg
.msg_iov
= &databuffers
;
159 msg
.msg_control
= (caddr_t
)&ancillary
;
160 msg
.msg_controllen
= sizeof(ancillary
);
164 n
= recvmsg(s
, &msg
, 0);
167 if (numLogMessages
++ < 100) LogErrorMessage("CFSocket.c: recvmsg(%d) returned error %d errno %d", s
, n
, errno
);
170 if (msg
.msg_controllen
< sizeof(struct cmsghdr
))
172 if (numLogMessages
++ < 100) LogErrorMessage("CFSocket.c: recvmsg(%d) msg.msg_controllen %d < sizeof(struct cmsghdr) %d",
173 s
, msg
.msg_controllen
, sizeof(struct cmsghdr
));
176 if (msg
.msg_flags
& MSG_CTRUNC
)
178 if (numLogMessages
++ < 100) LogErrorMessage("CFSocket.c: recvmsg(%d) msg.msg_flags & MSG_CTRUNC", s
);
182 *fromlen
= msg
.msg_namelen
;
184 // Parse each option out of the ancillary data.
185 for (cmPtr
= CMSG_FIRSTHDR(&msg
); cmPtr
; cmPtr
= CMSG_NXTHDR(&msg
, cmPtr
))
187 // debugf("myrecvfrom cmsg_level %d cmsg_type %d", cmPtr->cmsg_level, cmPtr->cmsg_type);
188 if (cmPtr
->cmsg_level
== IPPROTO_IP
&& cmPtr
->cmsg_type
== IP_RECVDSTADDR
)
189 *dstaddr
= *(struct in_addr
*)CMSG_DATA(cmPtr
);
190 if (cmPtr
->cmsg_level
== IPPROTO_IP
&& cmPtr
->cmsg_type
== IP_RECVIF
)
192 struct sockaddr_dl
*sdl
= (struct sockaddr_dl
*)CMSG_DATA(cmPtr
);
193 if (sdl
->sdl_nlen
< sizeof(ifname
))
195 mDNSPlatformMemCopy(sdl
->sdl_data
, ifname
, sdl
->sdl_nlen
);
196 ifname
[sdl
->sdl_nlen
] = 0;
197 // debugf("IP_RECVIF sdl_index %d, sdl_data %s len %d", sdl->sdl_index, ifname, sdl->sdl_nlen);
205 mDNSlocal
void myCFSocketCallBack(CFSocketRef s
, CFSocketCallBackType type
, CFDataRef address
, const void *data
, void *context
)
207 mDNSIPAddr senderaddr
, destaddr
;
208 mDNSIPPort senderport
;
209 NetworkInterfaceInfo2
*info
= (NetworkInterfaceInfo2
*)context
;
210 mDNS
*const m
= info
->m
;
213 struct sockaddr_in from
;
214 size_t fromlen
= sizeof(from
);
215 char packetifname
[128] = "";
219 (void)address
; // Parameter not used
220 (void)data
; // Parameter not used
222 if (type
!= kCFSocketReadCallBack
) LogErrorMessage("CFSocketCallBack: CallBackType %d is not kCFSocketReadCallBack", type
);
224 if (s
== info
->cfsocket53
)
228 if (s
== info
->cfsocket
)
231 err
= myrecvfrom(s1
, &packet
, sizeof(packet
), (struct sockaddr
*)&from
, &fromlen
, &to
, packetifname
);
233 if (err
< 0 || s1
< 0 || s1
!= CFSocketGetNative(s
))
235 LogErrorMessage("CFSocketCallBack: s1 %d native socket %d", s1
, CFSocketGetNative(s
));
236 LogErrorMessage("CFSocketCallBack: cfs %X, cfsocket53 %X, cfsocket %X", s
, info
->cfsocket53
, info
->cfsocket
);
237 LogErrorMessage("CFSocketCallBack: skt53 %X, sktv4 %X", info
->socket53
, info
->socket
);
238 LogErrorMessage("CFSocketCallBack recvfrom(%d) error %d errno %d", s1
, err
, errno
);
242 senderaddr
.NotAnInteger
= from
.sin_addr
.s_addr
;
243 senderport
.NotAnInteger
= from
.sin_port
;
244 destaddr
.NotAnInteger
= to
.s_addr
;
246 // Even though we indicated a specific interface in the IP_ADD_MEMBERSHIP call, a weirdness of the
247 // sockets API means that even though this socket has only officially joined the multicast group
248 // on one specific interface, the kernel will still deliver multicast packets to it no matter which
249 // interface they arrive on. According to the official Unix Powers That Be, this is Not A Bug.
250 // To work around this weirdness, we use the IP_RECVIF option to find the name of the interface
251 // on which the packet arrived, and ignore the packet if it really arrived on some other interface.
252 if (strcmp(info
->ifa_name
, packetifname
))
254 verbosedebugf("myCFSocketCallBack got a packet from %.4a to %.4a on interface %.4a/%s (Ignored -- really arrived on interface %s)",
255 &senderaddr
, &destaddr
, &info
->ifinfo
.ip
, info
->ifa_name
, packetifname
);
259 verbosedebugf("myCFSocketCallBack got a packet from %.4a to %.4a on interface %.4a/%s",
260 &senderaddr
, &destaddr
, &info
->ifinfo
.ip
, info
->ifa_name
);
262 if (err
< sizeof(DNSMessageHeader
)) { debugf("myCFSocketCallBack packet length (%d) too short", err
); return; }
265 if (s
== info
->cfsocket53
)
266 mDNSCoreReceive(m
, &packet
, (unsigned char*)&packet
+ err
, senderaddr
, senderport
, destaddr
, UnicastDNSPort
, info
->ifinfo
.ip
);
269 mDNSCoreReceive(m
, &packet
, (unsigned char*)&packet
+ err
, senderaddr
, senderport
, destaddr
, MulticastDNSPort
, info
->ifinfo
.ip
);
272 mDNSlocal
void myCFRunLoopTimerCallBack(CFRunLoopTimerRef timer
, void *info
)
274 (void)timer
; // Parameter not used
275 mDNSCoreTask((mDNS
*const)info
);
278 // This gets the text of the field currently labelled "Computer Name" in the Sharing Prefs Control Panel
279 mDNSlocal
void GetUserSpecifiedFriendlyComputerName(domainlabel
*const namelabel
)
281 CFStringEncoding encoding
= kCFStringEncodingUTF8
;
282 CFStringRef cfs
= SCDynamicStoreCopyComputerName(NULL
, &encoding
);
285 CFStringGetPascalString(cfs
, namelabel
->c
, sizeof(*namelabel
), kCFStringEncodingUTF8
);
290 // This gets the text of the field currently labelled "Rendezvous Name" in the Sharing Prefs Control Panel
291 mDNSlocal
void GetUserSpecifiedRFC1034ComputerName(domainlabel
*const namelabel
)
293 CFStringRef cfs
= SCDynamicStoreCopyLocalHostName(NULL
);
296 CFStringGetPascalString(cfs
, namelabel
->c
, sizeof(*namelabel
), kCFStringEncodingUTF8
);
301 mDNSlocal mStatus
SetupSocket(struct sockaddr_in
*ifa_addr
, mDNSIPPort port
, int *s
, CFSocketRef
*c
, CFSocketContext
*context
)
305 const int twofivefive
= 255;
307 struct sockaddr_in listening_sockaddr
;
308 CFRunLoopSourceRef rls
;
310 if (*s
> 0) { LogErrorMessage("SetupSocket ERROR: socket %d is already set", *s
); return(-1); }
311 if (*c
) { LogErrorMessage("SetupSocket ERROR: CFSocketRef %X is already set", *c
); return(-1); }
313 // Open the socket...
314 *s
= socket(PF_INET
, SOCK_DGRAM
, IPPROTO_UDP
);
316 if (*s
< 0) { perror("socket"); return(*s
); }
318 // ... with a shared UDP port
319 err
= setsockopt(*s
, SOL_SOCKET
, SO_REUSEPORT
, &on
, sizeof(on
));
320 if (err
< 0) { perror("setsockopt - SO_REUSEPORT"); return(err
); }
322 // We want to receive destination addresses
323 err
= setsockopt(*s
, IPPROTO_IP
, IP_RECVDSTADDR
, &on
, sizeof(on
));
324 if (err
< 0) { perror("setsockopt - IP_RECVDSTADDR"); return(err
); }
326 // We want to receive interface identifiers
327 err
= setsockopt(*s
, IPPROTO_IP
, IP_RECVIF
, &on
, sizeof(on
));
328 if (err
< 0) { perror("setsockopt - IP_RECVIF"); return(err
); }
330 // Add multicast group membership on this interface
331 imr
.imr_multiaddr
.s_addr
= AllDNSLinkGroup
.NotAnInteger
;
332 imr
.imr_interface
= ifa_addr
->sin_addr
;
333 err
= setsockopt(*s
, IPPROTO_IP
, IP_ADD_MEMBERSHIP
, &imr
, sizeof(struct ip_mreq
));
334 if (err
< 0) { perror("setsockopt - IP_ADD_MEMBERSHIP"); return(err
); }
336 // Specify outgoing interface too
337 err
= setsockopt(*s
, IPPROTO_IP
, IP_MULTICAST_IF
, &ifa_addr
->sin_addr
, sizeof(ifa_addr
->sin_addr
));
338 if (err
< 0) { perror("setsockopt - IP_MULTICAST_IF"); return(err
); }
340 // Send unicast packets with TTL 255
341 err
= setsockopt(*s
, IPPROTO_IP
, IP_TTL
, &twofivefive
, sizeof(twofivefive
));
342 if (err
< 0) { perror("setsockopt - IP_TTL"); return(err
); }
344 // And multicast packets with TTL 255 too
345 err
= setsockopt(*s
, IPPROTO_IP
, IP_MULTICAST_TTL
, &twofivefive
, sizeof(twofivefive
));
346 if (err
< 0) { perror("setsockopt - IP_MULTICAST_TTL"); return(err
); }
348 // And start listening for packets
349 listening_sockaddr
.sin_family
= AF_INET
;
350 listening_sockaddr
.sin_port
= port
.NotAnInteger
;
351 listening_sockaddr
.sin_addr
.s_addr
= 0; // Want to receive multicasts AND unicasts on this socket
352 err
= bind(*s
, (struct sockaddr
*) &listening_sockaddr
, sizeof(listening_sockaddr
));
355 if (port
.NotAnInteger
== UnicastDNSPort
.NotAnInteger
) err
= 0;
360 *c
= CFSocketCreateWithNative(kCFAllocatorDefault
, *s
, kCFSocketReadCallBack
, myCFSocketCallBack
, context
);
361 rls
= CFSocketCreateRunLoopSource(kCFAllocatorDefault
, *c
, 0);
362 CFRunLoopAddSource(CFRunLoopGetCurrent(), rls
, kCFRunLoopDefaultMode
);
369 mDNSlocal NetworkInterfaceInfo2
*SearchForInterfaceByAddr(mDNS
*const m
, mDNSIPAddr ip
)
371 NetworkInterfaceInfo2
*info
= (NetworkInterfaceInfo2
*)(m
->HostInterfaces
);
374 if (info
->ifinfo
.ip
.NotAnInteger
== ip
.NotAnInteger
) return(info
);
375 info
= (NetworkInterfaceInfo2
*)(info
->ifinfo
.next
);
381 mDNSlocal NetworkInterfaceInfo2
*SearchForInterfaceByName(mDNS
*const m
, char *ifname
)
383 NetworkInterfaceInfo2
*info
= (NetworkInterfaceInfo2
*)(m
->HostInterfaces
);
386 if (!strcmp(info
->ifa_name
, ifname
)) return(info
);
387 info
= (NetworkInterfaceInfo2
*)(info
->ifinfo
.next
);
392 #if RUN_ON_PUMA_WITHOUT_IFADDRS
394 /* Our own header for the programs that need interface configuration info.
395 Include this file, instead of "unp.h". */
397 #define IFA_NAME 16 /* same as IFNAMSIZ in <net/if.h> */
398 #define IFA_HADDR 8 /* allow for 64-bit EUI-64 in future */
401 char ifa_name
[IFA_NAME
]; /* interface name, null terminated */
402 u_char ifa_haddr
[IFA_HADDR
]; /* hardware address */
403 u_short ifa_hlen
; /* #bytes in hardware address: 0, 6, 8 */
404 short ifa_flags
; /* IFF_xxx constants from <net/if.h> */
405 short ifa_myflags
; /* our own IFI_xxx flags */
406 struct sockaddr
*ifa_addr
; /* primary address */
407 struct sockaddr
*ifa_brdaddr
;/* broadcast address */
408 struct sockaddr
*ifa_dstaddr
;/* destination address */
409 struct ifa_info
*ifa_next
; /* next of these structures */
412 #define IFI_ALIAS 1 /* ifa_addr is an alias */
414 /* function prototypes */
415 struct ifa_info
*get_ifa_info(int, int);
416 struct ifa_info
*Get_ifa_info(int, int);
417 void free_ifa_info(struct ifa_info
*);
419 #define HAVE_SOCKADDR_SA_LEN 1
422 get_ifa_info(int family
, int doaliases
)
424 struct ifa_info
*ifi
, *ifihead
, **ifipnext
;
425 int sockfd
, len
, lastlen
, flags
, myflags
;
426 char *ptr
, *buf
, lastname
[IFNAMSIZ
], *cptr
;
428 struct ifreq
*ifr
, ifrcopy
;
429 struct sockaddr_in
*sinptr
;
431 sockfd
= socket(AF_INET
, SOCK_DGRAM
, 0);
434 len
= 100 * sizeof(struct ifreq
); /* initial buffer size guess */
436 buf
= (char *) malloc(len
);
439 if (ioctl(sockfd
, SIOCGIFCONF
, &ifc
) < 0) {
440 if (errno
!= EINVAL
|| lastlen
!= 0)
441 debugf("ioctl error");
443 if (ifc
.ifc_len
== lastlen
)
444 break; /* success, len has not changed */
445 lastlen
= ifc
.ifc_len
;
447 len
+= 10 * sizeof(struct ifreq
); /* increment */
453 /* end get_ifa_info1 */
455 /* include get_ifa_info2 */
456 for (ptr
= buf
; ptr
< buf
+ ifc
.ifc_len
; ) {
457 ifr
= (struct ifreq
*) ptr
;
459 #ifdef HAVE_SOCKADDR_SA_LEN
460 len
= MAX(sizeof(struct sockaddr
), ifr
->ifr_addr
.sa_len
);
462 switch (ifr
->ifr_addr
.sa_family
) {
465 len
= sizeof(struct sockaddr_in6
);
470 len
= sizeof(struct sockaddr
);
473 #endif /* HAVE_SOCKADDR_SA_LEN */
474 ptr
+= sizeof(ifr
->ifr_name
) + len
; /* for next one in buffer */
476 if (ifr
->ifr_addr
.sa_family
!= family
)
477 continue; /* ignore if not desired address family */
480 if ( (cptr
= strchr(ifr
->ifr_name
, ':')) != NULL
)
481 *cptr
= 0; /* replace colon will null */
482 if (strncmp(lastname
, ifr
->ifr_name
, IFNAMSIZ
) == 0) {
484 continue; /* already processed this interface */
487 memcpy(lastname
, ifr
->ifr_name
, IFNAMSIZ
);
490 ioctl(sockfd
, SIOCGIFFLAGS
, &ifrcopy
);
491 flags
= ifrcopy
.ifr_flags
;
492 if ((flags
& IFF_UP
) == 0)
493 continue; /* ignore if interface not up */
495 ifi
= (struct ifa_info
*) calloc(1, sizeof(struct ifa_info
));
496 *ifipnext
= ifi
; /* prev points to this new one */
497 ifipnext
= &ifi
->ifa_next
; /* pointer to next one goes here */
499 ifi
->ifa_flags
= flags
; /* IFF_xxx values */
500 ifi
->ifa_myflags
= myflags
; /* IFI_xxx values */
501 memcpy(ifi
->ifa_name
, ifr
->ifr_name
, IFA_NAME
);
502 ifi
->ifa_name
[IFA_NAME
-1] = '\0';
503 /* end get_ifa_info2 */
504 /* include get_ifa_info3 */
505 switch (ifr
->ifr_addr
.sa_family
) {
507 sinptr
= (struct sockaddr_in
*) &ifr
->ifr_addr
;
508 if (ifi
->ifa_addr
== NULL
) {
509 ifi
->ifa_addr
= (struct sockaddr
*) calloc(1, sizeof(struct sockaddr_in
));
510 memcpy(ifi
->ifa_addr
, sinptr
, sizeof(struct sockaddr_in
));
512 #ifdef SIOCGIFBRDADDR
513 if (flags
& IFF_BROADCAST
) {
514 ioctl(sockfd
, SIOCGIFBRDADDR
, &ifrcopy
);
515 sinptr
= (struct sockaddr_in
*) &ifrcopy
.ifr_broadaddr
;
516 ifi
->ifa_brdaddr
= (struct sockaddr
*) calloc(1, sizeof(struct sockaddr_in
));
517 memcpy(ifi
->ifa_brdaddr
, sinptr
, sizeof(struct sockaddr_in
));
521 #ifdef SIOCGIFDSTADDR
522 if (flags
& IFF_POINTOPOINT
) {
523 ioctl(sockfd
, SIOCGIFDSTADDR
, &ifrcopy
);
524 sinptr
= (struct sockaddr_in
*) &ifrcopy
.ifr_dstaddr
;
525 ifi
->ifa_dstaddr
= (struct sockaddr
*) calloc(1, sizeof(struct sockaddr_in
));
526 memcpy(ifi
->ifa_dstaddr
, sinptr
, sizeof(struct sockaddr_in
));
537 return(ifihead
); /* pointer to first structure in linked list */
539 /* end get_ifa_info3 */
541 /* include free_ifa_info */
542 mDNSlocal
void freeifaddrs(struct ifa_info
*ifihead
)
544 struct ifa_info
*ifi
, *ifinext
;
546 for (ifi
= ifihead
; ifi
!= NULL
; ifi
= ifinext
) {
547 if (ifi
->ifa_addr
!= NULL
)
549 if (ifi
->ifa_brdaddr
!= NULL
)
550 free(ifi
->ifa_brdaddr
);
551 if (ifi
->ifa_dstaddr
!= NULL
)
552 free(ifi
->ifa_dstaddr
);
553 ifinext
= ifi
->ifa_next
; /* can't fetch ifa_next after free() */
554 free(ifi
); /* the ifa_info{} itself */
557 /* end free_ifa_info */
560 Get_ifa_info(int family
, int doaliases
)
562 struct ifa_info
*ifi
;
564 if ( (ifi
= get_ifa_info(family
, doaliases
)) == NULL
)
565 debugf("get_ifa_info error");
569 mDNSlocal
int getifaddrs(struct ifa_info
**ifalist
)
571 *ifalist
= get_ifa_info(PF_INET
, false);
580 mDNSlocal mStatus
SetupInterface(mDNS
*const m
, NetworkInterfaceInfo2
*info
, struct ifaddrs
*ifa
)
583 struct sockaddr_in
*ifa_addr
= (struct sockaddr_in
*)ifa
->ifa_addr
;
584 CFSocketContext myCFSocketContext
= { 0, info
, NULL
, NULL
, NULL
};
586 info
->ifinfo
.ip
.NotAnInteger
= ifa_addr
->sin_addr
.s_addr
;
587 info
->ifinfo
.Advertise
= mDNS_AdvertiseLocalAddresses
;
589 info
->ifa_name
= (char *)mallocL("NetworkInterfaceInfo2 name", strlen(ifa
->ifa_name
) + 1);
590 if (!info
->ifa_name
) return(-1);
591 strcpy(info
->ifa_name
, ifa
->ifa_name
);
592 info
->alias
= SearchForInterfaceByName(m
, ifa
->ifa_name
);
597 info
->cfsocket53
= 0;
600 mDNS_RegisterInterface(m
, &info
->ifinfo
);
603 debugf("SetupInterface: %s Flags %04X %.4a is an alias of %.4a",
604 ifa
->ifa_name
, ifa
->ifa_flags
, &info
->ifinfo
.ip
, &info
->alias
->ifinfo
.ip
);
607 err
= SetupSocket(ifa_addr
, UnicastDNSPort
, &info
->socket53
, &info
->cfsocket53
, &myCFSocketContext
);
610 err
= SetupSocket(ifa_addr
, MulticastDNSPort
, &info
->socket
, &info
->cfsocket
, &myCFSocketContext
);
612 debugf("SetupInterface: %s Flags %04X %.4a Registered socket53 %d socket5353 %d",
613 ifa
->ifa_name
, ifa
->ifa_flags
, &info
->ifinfo
.ip
, info
->socket53
, info
->socket
);
618 mDNSlocal
void ClearInterfaceList(mDNS
*const m
)
620 while (m
->HostInterfaces
)
622 NetworkInterfaceInfo2
*info
= (NetworkInterfaceInfo2
*)(m
->HostInterfaces
);
623 mDNS_DeregisterInterface(m
, &info
->ifinfo
);
624 if (info
->ifa_name
) freeL("NetworkInterfaceInfo2 name", info
->ifa_name
);
625 if (info
->socket
> 0) shutdown(info
->socket
, 2);
626 if (info
->cfsocket
) { CFSocketInvalidate(info
->cfsocket
); CFRelease(info
->cfsocket
); }
628 if (info
->socket53
> 0) shutdown(info
->socket53
, 2);
629 if (info
->cfsocket53
) { CFSocketInvalidate(info
->cfsocket53
); CFRelease(info
->cfsocket53
); }
631 freeL("NetworkInterfaceInfo2", info
);
635 mDNSlocal mStatus
SetupInterfaceList(mDNS
*const m
)
637 struct ifaddrs
*ifalist
;
638 int err
= getifaddrs(&ifalist
);
639 struct ifaddrs
*ifa
= ifalist
;
640 struct ifaddrs
*theLoopback
= NULL
;
641 if (err
) return(err
);
643 // Set up the nice label
644 m
->nicelabel
.c
[0] = 0;
645 GetUserSpecifiedFriendlyComputerName(&m
->nicelabel
);
646 if (m
->nicelabel
.c
[0] == 0) ConvertCStringToDomainLabel("Macintosh", &m
->nicelabel
);
648 // Set up the RFC 1034-compliant label
649 m
->hostlabel
.c
[0] = 0;
650 GetUserSpecifiedRFC1034ComputerName(&m
->hostlabel
);
651 if (m
->hostlabel
.c
[0] == 0) ConvertCStringToDomainLabel("Macintosh", &m
->hostlabel
);
653 mDNS_GenerateFQDN(m
);
658 if (ifa
->ifa_addr
->sa_family
!= AF_INET
)
659 debugf("SetupInterface: %s Flags %04X Family %d not AF_INET",
660 ifa
->ifa_name
, ifa
->ifa_flags
, ifa
->ifa_addr
->sa_family
);
661 if (!(ifa
->ifa_flags
& IFF_UP
))
662 debugf("SetupInterface: %s Flags %04X Interface not IFF_UP", ifa
->ifa_name
, ifa
->ifa_flags
);
663 if (ifa
->ifa_flags
& IFF_LOOPBACK
)
664 debugf("SetupInterface: %s Flags %04X Interface IFF_LOOPBACK", ifa
->ifa_name
, ifa
->ifa_flags
);
665 if (ifa
->ifa_flags
& IFF_POINTOPOINT
)
666 debugf("SetupInterface: %s Flags %04X Interface IFF_POINTOPOINT", ifa
->ifa_name
, ifa
->ifa_flags
);
668 if (ifa
->ifa_addr
->sa_family
== AF_INET
&& (ifa
->ifa_flags
& IFF_UP
) &&
669 !(ifa
->ifa_flags
& IFF_POINTOPOINT
))
671 if (ifa
->ifa_flags
& IFF_LOOPBACK
)
675 NetworkInterfaceInfo2
*info
= (NetworkInterfaceInfo2
*)mallocL("NetworkInterfaceInfo2", sizeof(*info
));
676 if (!info
) debugf("SetupInterfaceList: Out of Memory!");
677 else SetupInterface(m
, info
, ifa
);
683 if (!m
->HostInterfaces
&& theLoopback
)
685 NetworkInterfaceInfo2
*info
= (NetworkInterfaceInfo2
*)mallocL("NetworkInterfaceInfo2", sizeof(*info
));
686 if (!info
) debugf("SetupInterfaceList: (theLoopback) Out of Memory!");
687 else SetupInterface(m
, info
, theLoopback
);
690 freeifaddrs(ifalist
);
694 mDNSlocal
void NetworkChanged(SCDynamicStoreRef store
, CFArrayRef changedKeys
, void *context
)
696 mDNS
*const m
= (mDNS
*const)context
;
697 debugf("*** Network Configuration Change ***");
698 (void)store
; // Parameter not used
699 (void)changedKeys
; // Parameter not used
701 ClearInterfaceList(m
);
702 SetupInterfaceList(m
);
703 if (NotifyClientNetworkChanged
) NotifyClientNetworkChanged();
704 mDNSCoreSleep(m
, false);
707 mDNSlocal mStatus
WatchForNetworkChanges(mDNS
*const m
)
710 SCDynamicStoreContext context
= { 0, m
, NULL
, NULL
, NULL
};
711 SCDynamicStoreRef store
= SCDynamicStoreCreate(NULL
, CFSTR("mDNSResponder"), NetworkChanged
, &context
);
712 CFStringRef key1
= SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL
, kSCDynamicStoreDomainState
, kSCEntNetIPv4
);
713 CFStringRef key2
= SCDynamicStoreKeyCreateComputerName(NULL
);
714 CFStringRef key3
= SCDynamicStoreKeyCreateHostNames(NULL
);
715 CFStringRef pattern
= SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL
, kSCDynamicStoreDomainState
, kSCCompAnyRegex
, kSCEntNetIPv4
);
716 CFMutableArrayRef keys
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
717 CFMutableArrayRef patterns
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
719 if (!store
) { fprintf(stderr
, "SCDynamicStoreCreate failed: %s\n", SCErrorString(SCError())); goto error
; }
720 if (!key1
|| !key2
|| !key3
|| !keys
|| !pattern
|| !patterns
) goto error
;
722 CFArrayAppendValue(keys
, key1
);
723 CFArrayAppendValue(keys
, key2
);
724 CFArrayAppendValue(keys
, key3
);
725 CFArrayAppendValue(patterns
, pattern
);
726 if (!SCDynamicStoreSetNotificationKeys(store
, keys
, patterns
))
727 { fprintf(stderr
, "SCDynamicStoreSetNotificationKeys failed: %s\n", SCErrorString(SCError())); goto error
; }
729 m
->p
->StoreRLS
= SCDynamicStoreCreateRunLoopSource(NULL
, store
, 0);
730 if (!m
->p
->StoreRLS
) { fprintf(stderr
, "SCDynamicStoreCreateRunLoopSource failed: %s\n", SCErrorString(SCError())); goto error
; }
732 CFRunLoopAddSource(CFRunLoopGetCurrent(), m
->p
->StoreRLS
, kCFRunLoopDefaultMode
);
738 if (store
) CFRelease(store
);
741 if (key1
) CFRelease(key1
);
742 if (key2
) CFRelease(key2
);
743 if (key3
) CFRelease(key3
);
744 if (pattern
) CFRelease(pattern
);
745 if (keys
) CFRelease(keys
);
746 if (patterns
) CFRelease(patterns
);
751 mDNSlocal
void PowerChanged(void *refcon
, io_service_t service
, natural_t messageType
, void *messageArgument
)
753 mDNS
*const m
= (mDNS
*const)refcon
;
754 (void)service
; // Parameter not used
757 case kIOMessageCanSystemPowerOff
: debugf("PowerChanged kIOMessageCanSystemPowerOff (no action)"); break; // E0000240
758 case kIOMessageSystemWillPowerOff
: debugf("PowerChanged kIOMessageSystemWillPowerOff"); mDNSCoreSleep(m
, true); break; // E0000250
759 case kIOMessageSystemWillNotPowerOff
: debugf("PowerChanged kIOMessageSystemWillNotPowerOff (no action)"); break; // E0000260
760 case kIOMessageCanSystemSleep
: debugf("PowerChanged kIOMessageCanSystemSleep (no action)"); break; // E0000270
761 case kIOMessageSystemWillSleep
: debugf("PowerChanged kIOMessageSystemWillSleep"); mDNSCoreSleep(m
, true); break; // E0000280
762 case kIOMessageSystemWillNotSleep
: debugf("PowerChanged kIOMessageSystemWillNotSleep (no action)"); break; // E0000290
763 case kIOMessageSystemHasPoweredOn
: debugf("PowerChanged kIOMessageSystemHasPoweredOn"); mDNSCoreSleep(m
, false); break; // E0000300
764 default: debugf("PowerChanged unknown message %X", messageType
); break;
766 IOAllowPowerChange(m
->p
->PowerConnection
, (long)messageArgument
);
769 mDNSlocal mStatus
WatchForPowerChanges(mDNS
*const m
)
771 IONotificationPortRef thePortRef
;
772 m
->p
->PowerConnection
= IORegisterForSystemPower(m
, &thePortRef
, PowerChanged
, &m
->p
->PowerNotifier
);
773 if (m
->p
->PowerConnection
)
775 m
->p
->PowerRLS
= IONotificationPortGetRunLoopSource(thePortRef
);
776 CFRunLoopAddSource(CFRunLoopGetCurrent(), m
->p
->PowerRLS
, kCFRunLoopDefaultMode
);
777 return(mStatus_NoError
);
782 mDNSlocal mStatus
mDNSPlatformInit_setup(mDNS
*const m
)
786 CFRunLoopTimerContext myCFRunLoopTimerContext
= { 0, m
, NULL
, NULL
, NULL
};
788 // Note: Every CFRunLoopTimer has to be created with an initial fire time, and a repeat interval, or it becomes
789 // a one-shot timer and you can't use CFRunLoopTimerSetNextFireDate(timer, when) to schedule subsequent firings.
790 // Here we create it with an initial fire time ten seconds from now, and a repeat interval of ten seconds,
791 // knowing that we'll reschedule it using CFRunLoopTimerSetNextFireDate(timer, when) long before that happens.
792 m
->p
->CFTimer
= CFRunLoopTimerCreate(kCFAllocatorDefault
, CFAbsoluteTimeGetCurrent() + 10.0, 10.0, 0, 1,
793 myCFRunLoopTimerCallBack
, &myCFRunLoopTimerContext
);
794 CFRunLoopAddTimer(CFRunLoopGetCurrent(), m
->p
->CFTimer
, kCFRunLoopDefaultMode
);
796 SetupInterfaceList(m
);
798 err
= WatchForNetworkChanges(m
);
799 if (err
) return(err
);
801 err
= WatchForPowerChanges(m
);
805 mDNSexport mStatus
mDNSPlatformInit(mDNS
*const m
)
807 mStatus result
= mDNSPlatformInit_setup(m
);
808 // We don't do asynchronous initialization on OS X, so by the time we get here the setup will already
809 // have succeeded or failed -- so if it succeeded, we should just call mDNSCoreInitComplete() immediately
810 if (result
== mStatus_NoError
) mDNSCoreInitComplete(m
, mStatus_NoError
);
814 mDNSexport
void mDNSPlatformClose(mDNS
*const m
)
816 if (m
->p
->PowerConnection
)
818 CFRunLoopRemoveSource(CFRunLoopGetCurrent(), m
->p
->PowerRLS
, kCFRunLoopDefaultMode
);
819 CFRunLoopSourceInvalidate(m
->p
->PowerRLS
);
820 CFRelease(m
->p
->PowerRLS
);
821 IODeregisterForSystemPower(&m
->p
->PowerNotifier
);
822 m
->p
->PowerConnection
= NULL
;
823 m
->p
->PowerNotifier
= NULL
;
824 m
->p
->PowerRLS
= NULL
;
829 CFRunLoopRemoveSource(CFRunLoopGetCurrent(), m
->p
->StoreRLS
, kCFRunLoopDefaultMode
);
830 CFRunLoopSourceInvalidate(m
->p
->StoreRLS
);
831 CFRelease(m
->p
->StoreRLS
);
832 CFRelease(m
->p
->Store
);
834 m
->p
->StoreRLS
= NULL
;
837 ClearInterfaceList(m
);
841 CFRunLoopTimerInvalidate(m
->p
->CFTimer
);
842 CFRelease(m
->p
->CFTimer
);
843 m
->p
->CFTimer
= NULL
;
847 mDNSexport
void mDNSPlatformScheduleTask(const mDNS
*const m
, SInt32 NextTaskTime
)
851 CFAbsoluteTime ticks
= (CFAbsoluteTime
)(NextTaskTime
- mDNSPlatformTimeNow());
852 CFAbsoluteTime interval
= ticks
/ (CFAbsoluteTime
)mDNSPlatformOneSecond
;
853 CFRunLoopTimerSetNextFireDate(m
->p
->CFTimer
, CFAbsoluteTimeGetCurrent() + interval
);
857 // Locking is a no-op here, because we're CFRunLoop-based, so we can never interrupt ourselves
858 mDNSexport
void mDNSPlatformLock (const mDNS
*const m
) { (void)m
; }
859 mDNSexport
void mDNSPlatformUnlock (const mDNS
*const m
) { (void)m
; }
860 mDNSexport
void mDNSPlatformStrCopy(const void *src
, void *dst
) { strcpy((char *)dst
, (char *)src
); }
861 mDNSexport UInt32
mDNSPlatformStrLen (const void *src
) { return(strlen((char*)src
)); }
862 mDNSexport
void mDNSPlatformMemCopy(const void *src
, void *dst
, UInt32 len
) { memcpy(dst
, src
, len
); }
863 mDNSexport Boolean
mDNSPlatformMemSame(const void *src
, const void *dst
, UInt32 len
) { return(memcmp(dst
, src
, len
) == 0); }
864 mDNSexport
void mDNSPlatformMemZero( void *dst
, UInt32 len
) { bzero(dst
, len
); }
866 mDNSexport SInt32
mDNSPlatformTimeNow()
869 gettimeofday(&tp
, NULL
);
870 // tp.tv_sec is seconds since 1st January 1970 (GMT, with no adjustment for daylight savings time)
871 // tp.tv_usec is microseconds since the start of this second (i.e. values 0 to 999999)
872 // We use the lower 22 bits of tp.tv_sec for the top 22 bits of our result
873 // 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.
874 // This gives us a proper modular (cyclic) counter that has a resolution of roughly 1ms (actually 1/1024 second)
875 // and correctly cycles every 2^22 seconds (4194304 seconds = approx 48 days).
876 return( (tp
.tv_sec
<< 10) | (tp
.tv_usec
* 16 / 15625) );
879 mDNSexport SInt32 mDNSPlatformOneSecond
= 1024;