1 /* -*- Mode: C; tab-width: 4 -*-
3 * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
18 * This code follows the "Whitesmiths style" C indentation rules. Plenty of discussion
19 * on C indentation can be found on the web, such as <http://www.kafejo.com/komp/1tbs.htm>,
20 * but for the sake of brevity here I will say just this: Curly braces are not syntactially
21 * part of an "if" statement; they are the beginning and ending markers of a compound statement;
22 * therefore common sense dictates that if they are part of a compound statement then they
23 * should be indented to the same level as everything else in that compound statement.
24 * Indenting curly braces at the same level as the "if" implies that curly braces are
25 * part of the "if", which is false. (This is as misleading as people who write "char* x,y;"
26 * thinking that variables x and y are both of type "char*" -- and anyone who doesn't
27 * understand why variable y is not of type "char*" just proves the point that poor code
28 * layout leads people to unfortunate misunderstandings about how the C language really works.)
30 Change History (most recent first):
33 Revision 1.78.2.1 2006/08/29 06:24:34 cheshire
34 Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
36 Revision 1.78 2006/06/28 09:12:22 cheshire
37 Added debugging message
39 Revision 1.77 2006/03/19 02:00:11 cheshire
40 <rdar://problem/4073825> Improve logic for delaying packets after repeated interface transitions
42 Revision 1.76 2006/01/09 19:29:16 cheshire
43 <rdar://problem/4403128> Cap number of "sendto failed" messages we allow mDNSResponder to log
45 Revision 1.75 2006/01/05 22:04:57 cheshire
46 <rdar://problem/4399479> Log error message when send fails with "operation not permitted"
48 Revision 1.74 2006/01/05 21:45:27 cheshire
49 <rdar://problem/4400118> Fix uninitialized structure member in IPv6 code
51 Revision 1.73 2005/10/11 21:31:46 cheshire
52 <rdar://problem/4296177> Don't depend on IP_RECVTTL succeeding (not available on all platforms)
54 Revision 1.72 2005/09/08 20:45:26 cheshire
55 Default dot-local host name should be "Computer" not "Macintosh",
56 since the machine this is running on is most likely NOT a Mac.
58 Revision 1.71 2005/02/26 01:29:12 cheshire
59 Ignore multicasts accidentally delivered to our unicast receiving socket
61 Revision 1.70 2005/02/04 00:39:59 cheshire
62 Move ParseDNSServers() from PosixDaemon.c to mDNSPosix.c so all Posix client layers can use it
64 Revision 1.69 2004/12/18 02:03:28 cheshire
65 Need to #include "dns_sd.h"
67 Revision 1.68 2004/12/18 00:51:52 cheshire
68 Use symbolic constant kDNSServiceInterfaceIndexLocalOnly instead of (mDNSu32) ~0
70 Revision 1.67 2004/12/17 23:37:48 cheshire
71 <rdar://problem/3485365> Guard against repeating wireless dissociation/re-association
72 (and other repetitive configuration changes)
74 Revision 1.66 2004/12/01 04:27:28 cheshire
75 <rdar://problem/3872803> Darwin patches for Solaris and Suse
76 Don't use uint32_t, etc. -- they require stdint.h, which doesn't exist on FreeBSD 4.x, Solaris, etc.
78 Revision 1.65 2004/11/30 22:37:01 cheshire
79 Update copyright dates and add "Mode: C; tab-width: 4" headers
81 Revision 1.64 2004/11/23 03:39:47 cheshire
82 Let interface name/index mapping capability live directly in JNISupport.c,
83 instead of having to call through to the daemon via IPC to get this information.
85 Revision 1.63 2004/11/12 03:16:43 rpantos
86 rdar://problem/3809541 Add mDNSPlatformGetInterfaceByName, mDNSPlatformGetInterfaceName
88 Revision 1.62 2004/10/28 03:24:42 cheshire
89 Rename m->CanReceiveUnicastOn as m->CanReceiveUnicastOn5353
91 Revision 1.61 2004/10/16 00:17:01 cheshire
92 <rdar://problem/3770558> Replace IP TTL 255 check with local subnet source address check
94 Revision 1.60 2004/09/26 23:20:36 ksekar
95 <rdar://problem/3813108> Allow default registrations in multiple wide-area domains
97 Revision 1.59 2004/09/21 21:02:55 cheshire
98 Set up ifname before calling mDNS_RegisterInterface()
100 Revision 1.58 2004/09/17 01:08:54 cheshire
101 Renamed mDNSClientAPI.h to mDNSEmbeddedAPI.h
102 The name "mDNSClientAPI.h" is misleading to new developers looking at this code. The interfaces
103 declared in that file are ONLY appropriate to single-address-space embedded applications.
104 For clients on general-purpose computers, the interfaces defined in dns_sd.h should be used.
106 Revision 1.57 2004/09/17 00:19:11 cheshire
107 For consistency with AllDNSLinkGroupv6, rename AllDNSLinkGroup to AllDNSLinkGroupv4
109 Revision 1.56 2004/09/17 00:15:56 cheshire
110 Rename mDNSPlatformInit_ReceiveUnicast to mDNSPlatformInit_CanReceiveUnicast
112 Revision 1.55 2004/09/16 00:24:49 cheshire
113 <rdar://problem/3803162> Fix unsafe use of mDNSPlatformTimeNow()
115 Revision 1.54 2004/09/15 23:55:00 ksekar
116 <rdar://problem/3800597> mDNSPosix should #include stdint.h
118 Revision 1.53 2004/09/14 23:42:36 cheshire
119 <rdar://problem/3801296> Need to seed random number generator from platform-layer data
121 Revision 1.52 2004/08/25 16:42:13 ksekar
122 Fix Posix build - change mDNS_SetFQDNs to mDNS_SetFQDN, remove unicast
125 Revision 1.51 2004/08/14 03:22:42 cheshire
126 <rdar://problem/3762579> Dynamic DNS UI <-> mDNSResponder glue
127 Add GetUserSpecifiedDDNSName() routine
128 Convert ServiceRegDomain to domainname instead of C string
129 Replace mDNS_GenerateFQDN/mDNS_GenerateGlobalFQDN with mDNS_SetFQDNs
131 Revision 1.50 2004/08/11 01:20:20 cheshire
132 Declare private local functions using "mDNSlocal"
134 Revision 1.49 2004/07/26 22:49:31 ksekar
135 <rdar://problem/3651409>: Feature #9516: Need support for NATPMP in client
137 Revision 1.48 2004/07/20 01:47:36 rpantos
138 NOT_HAVE_SA_LEN applies to v6, too. And use more-portable s6_addr.
140 Revision 1.47 2004/06/25 00:26:27 rpantos
141 Changes to fix the Posix build on Solaris.
143 Revision 1.46 2004/05/13 04:54:20 ksekar
144 Unified list copy/free code. Added symetric list for
146 Revision 1.45 2004/05/12 22:03:09 ksekar
147 Made GetSearchDomainList a true platform-layer call (declaration moved
148 from mDNSMacOSX.h to mDNSEmbeddedAPI.h), impelemted to return "local"
149 only on non-OSX platforms. Changed call to return a copy of the list
150 to avoid shared memory issues. Added a routine to free the list.
152 Revision 1.44 2004/04/21 02:49:11 cheshire
153 To reduce future confusion, renamed 'TxAndRx' to 'McastTxRx'
155 Revision 1.43 2004/04/14 23:09:29 ksekar
156 Support for TSIG signed dynamic updates.
158 Revision 1.42 2004/04/09 17:43:04 cheshire
159 Make sure to set the McastTxRx field so that duplicate suppression works correctly
161 Revision 1.41 2004/02/06 01:19:51 cheshire
162 Conditionally exclude IPv6 code unless HAVE_IPV6 is set
164 Revision 1.40 2004/02/05 01:00:01 rpantos
165 Fix some issues that turned up when building for FreeBSD.
167 Revision 1.39 2004/01/28 21:12:15 cheshire
168 Reconcile mDNSIPv6Support & HAVE_IPV6 into a single flag (HAVE_IPV6)
170 Revision 1.38 2004/01/27 20:15:23 cheshire
171 <rdar://problem/3541288>: Time to prune obsolete code for listening on port 53
173 Revision 1.37 2004/01/24 05:12:03 cheshire
174 <rdar://problem/3534352>: Need separate socket for issuing unicast queries
176 Revision 1.36 2004/01/24 04:59:16 cheshire
177 Fixes so that Posix/Linux, OS9, Windows, and VxWorks targets build again
179 Revision 1.35 2004/01/23 21:37:08 cheshire
180 For consistency, rename multicastSocket to multicastSocket4, and multicastSocketv6 to multicastSocket6
182 Revision 1.34 2004/01/22 03:43:09 cheshire
183 Export constants like mDNSInterface_LocalOnly so that the client layers can use them
185 Revision 1.33 2004/01/21 21:54:20 cheshire
186 <rdar://problem/3448144>: Don't try to receive unicast responses if we're not the first to bind to the UDP port
188 Revision 1.32 2004/01/20 01:49:28 rpantos
189 Tweak error handling of last checkin a bit.
191 Revision 1.31 2004/01/20 01:39:27 rpantos
192 Respond to If changes by rebuilding interface list.
194 Revision 1.30 2003/12/11 19:40:36 cheshire
195 Fix 'destAddr.type == senderAddr.type;' that should have said 'destAddr.type = senderAddr.type;'
197 Revision 1.29 2003/12/11 18:53:22 cheshire
198 Fix compiler warning reported by Paul Guyot
200 Revision 1.28 2003/12/11 03:03:51 rpantos
201 Clean up mDNSPosix so that it builds on OS X again.
203 Revision 1.27 2003/12/08 20:47:02 rpantos
204 Add support for mDNSResponder on Linux.
206 Revision 1.26 2003/11/14 20:59:09 cheshire
207 Clients can't use AssignDomainName macro because mDNSPlatformMemCopy is defined in mDNSPlatformFunctions.h.
208 Best solution is just to combine mDNSEmbeddedAPI.h and mDNSPlatformFunctions.h into a single file.
210 Revision 1.25 2003/10/30 19:25:49 cheshire
211 Fix signed/unsigned warning on certain compilers
213 Revision 1.24 2003/08/18 23:12:23 cheshire
214 <rdar://problem/3382647> mDNSResponder divide by zero in mDNSPlatformRawTime()
216 Revision 1.23 2003/08/12 19:56:26 cheshire
219 Revision 1.22 2003/08/06 18:46:15 cheshire
220 LogMsg() errors are serious -- always report them to stderr, regardless of debugging level
222 Revision 1.21 2003/08/06 18:20:51 cheshire
225 Revision 1.20 2003/08/05 23:56:26 cheshire
226 Update code to compile with the new mDNSCoreReceive() function that requires a TTL
227 (Right now mDNSPosix.c just reports 255 -- we should fix this)
229 Revision 1.19 2003/07/19 03:15:16 cheshire
230 Add generic MemAllocate/MemFree prototypes to mDNSPlatformFunctions.h,
231 and add the obvious trivial implementations to each platform support layer
233 Revision 1.18 2003/07/14 18:11:54 cheshire
234 Fix stricter compiler warnings
236 Revision 1.17 2003/07/13 01:08:38 cheshire
237 There's not much point running mDNS over a point-to-point link; exclude those
239 Revision 1.16 2003/07/02 21:19:59 cheshire
240 <rdar://problem/3313413> Update copyright notices, etc., in source code comments
242 Revision 1.15 2003/06/18 05:48:41 cheshire
245 Revision 1.14 2003/05/26 03:21:30 cheshire
246 Tidy up address structure naming:
247 mDNSIPAddr => mDNSv4Addr (for consistency with mDNSv6Addr)
248 mDNSAddr.addr.ipv4 => mDNSAddr.ip.v4
249 mDNSAddr.addr.ipv6 => mDNSAddr.ip.v6
251 Revision 1.13 2003/05/26 03:01:28 cheshire
252 <rdar://problem/3268904> sprintf/vsprintf-style functions are unsafe; use snprintf/vsnprintf instead
254 Revision 1.12 2003/05/21 03:49:18 cheshire
257 Revision 1.11 2003/05/06 00:00:50 cheshire
258 <rdar://problem/3248914> Rationalize naming of domainname manipulation functions
260 Revision 1.10 2003/04/25 01:45:57 cheshire
261 <rdar://problem/3240002> mDNS_RegisterNoSuchService needs to include a host name
263 Revision 1.9 2003/03/20 21:10:31 cheshire
264 Fixes done at IETF 56 to make mDNSProxyResponderPosix run on Solaris
266 Revision 1.8 2003/03/15 04:40:38 cheshire
267 Change type called "mDNSOpaqueID" to the more descriptive name "mDNSInterfaceID"
269 Revision 1.7 2003/03/13 03:46:21 cheshire
270 Fixes to make the code build on Linux
272 Revision 1.6 2003/03/08 00:35:56 cheshire
273 Switched to using new "mDNS_Execute" model (see "mDNSCore/Implementer Notes.txt")
275 Revision 1.5 2002/12/23 22:13:31 jgraessl
276 Reviewed by: Stuart Cheshire
277 Initial IPv6 support for mDNSResponder.
279 Revision 1.4 2002/09/27 01:47:45 cheshire
280 Workaround for Linux 2.0 systems that don't have IP_PKTINFO
282 Revision 1.3 2002/09/21 20:44:53 zarzycki
285 Revision 1.2 2002/09/19 21:25:36 cheshire
286 mDNS_snprintf() doesn't need to be in a separate file
288 Revision 1.1 2002/09/17 06:24:34 cheshire
292 #include "mDNSEmbeddedAPI.h" // Defines the interface provided to the client layer above
293 #include "mDNSPosix.h" // Defines the specific types needed to run mDNS on this platform
305 #include <sys/types.h>
306 #include <sys/time.h>
307 #include <sys/socket.h>
309 #include <sys/select.h>
310 #include <netinet/in.h>
311 #include <arpa/inet.h>
312 #include <time.h> // platform support for UTC time
315 #include <asm/types.h>
316 #include <linux/netlink.h>
317 #include <linux/rtnetlink.h>
318 #else // USES_NETLINK
319 #include <net/route.h>
321 #endif // USES_NETLINK
324 #include "GenLinkedList.h"
326 // ***************************************************************************
329 // We keep a list of client-supplied event sources in PosixEventSource records
330 struct PosixEventSource
332 mDNSPosixEventCallback Callback
;
335 struct PosixEventSource
*Next
;
337 typedef struct PosixEventSource PosixEventSource
;
339 // Context record for interface change callback
345 typedef struct IfChangeRec IfChangeRec
;
347 // Note that static data is initialized to zero in (modern) C.
348 static fd_set gEventFDs
;
349 static int gMaxFD
; // largest fd in gEventFDs
350 static GenLinkedList gEventSources
; // linked list of PosixEventSource's
351 static sigset_t gEventSignalSet
; // Signals which event loop listens for
352 static sigset_t gEventSignals
; // Signals which were received while inside loop
354 // ***************************************************************************
355 // Globals (for debugging)
357 static int num_registered_interfaces
= 0;
358 static int num_pkts_accepted
= 0;
359 static int num_pkts_rejected
= 0;
361 // ***************************************************************************
364 int gMDNSPlatformPosixVerboseLevel
= 0;
366 #define PosixErrorToStatus(errNum) ((errNum) == 0 ? mStatus_NoError : mStatus_UnknownErr)
368 mDNSlocal
void SockAddrTomDNSAddr(const struct sockaddr
*const sa
, mDNSAddr
*ipAddr
, mDNSIPPort
*ipPort
)
370 switch (sa
->sa_family
)
374 struct sockaddr_in
* sin
= (struct sockaddr_in
*)sa
;
375 ipAddr
->type
= mDNSAddrType_IPv4
;
376 ipAddr
->ip
.v4
.NotAnInteger
= sin
->sin_addr
.s_addr
;
377 if (ipPort
) ipPort
->NotAnInteger
= sin
->sin_port
;
384 struct sockaddr_in6
* sin6
= (struct sockaddr_in6
*)sa
;
385 #ifndef NOT_HAVE_SA_LEN
386 assert(sin6
->sin6_len
== sizeof(*sin6
));
388 ipAddr
->type
= mDNSAddrType_IPv6
;
389 ipAddr
->ip
.v6
= *(mDNSv6Addr
*)&sin6
->sin6_addr
;
390 if (ipPort
) ipPort
->NotAnInteger
= sin6
->sin6_port
;
396 verbosedebugf("SockAddrTomDNSAddr: Uknown address family %d\n", sa
->sa_family
);
397 ipAddr
->type
= mDNSAddrType_None
;
398 if (ipPort
) ipPort
->NotAnInteger
= 0;
403 #if COMPILER_LIKES_PRAGMA_MARK
404 #pragma mark ***** Send and Receive
407 // mDNS core calls this routine when it needs to send a packet.
408 mDNSexport mStatus
mDNSPlatformSendUDP(const mDNS
*const m
, const void *const msg
, const mDNSu8
*const end
,
409 mDNSInterfaceID InterfaceID
, const mDNSAddr
*dst
, mDNSIPPort dstPort
)
412 struct sockaddr_storage to
;
413 PosixNetworkInterface
* thisIntf
= (PosixNetworkInterface
*)(InterfaceID
);
414 int sendingsocket
= -1;
419 assert( (((char *) end
) - ((char *) msg
)) > 0 );
420 assert(dstPort
.NotAnInteger
!= 0);
422 if (dst
->type
== mDNSAddrType_IPv4
)
424 struct sockaddr_in
*sin
= (struct sockaddr_in
*)&to
;
425 #ifndef NOT_HAVE_SA_LEN
426 sin
->sin_len
= sizeof(*sin
);
428 sin
->sin_family
= AF_INET
;
429 sin
->sin_port
= dstPort
.NotAnInteger
;
430 sin
->sin_addr
.s_addr
= dst
->ip
.v4
.NotAnInteger
;
431 sendingsocket
= thisIntf
? thisIntf
->multicastSocket4
: m
->p
->unicastSocket4
;
435 else if (dst
->type
== mDNSAddrType_IPv6
)
437 struct sockaddr_in6
*sin6
= (struct sockaddr_in6
*)&to
;
438 mDNSPlatformMemZero(sin6
, sizeof(*sin6
));
439 #ifndef NOT_HAVE_SA_LEN
440 sin6
->sin6_len
= sizeof(*sin6
);
442 sin6
->sin6_family
= AF_INET6
;
443 sin6
->sin6_port
= dstPort
.NotAnInteger
;
444 sin6
->sin6_addr
= *(struct in6_addr
*)&dst
->ip
.v6
;
445 sendingsocket
= thisIntf
? thisIntf
->multicastSocket6
: m
->p
->unicastSocket6
;
449 if (sendingsocket
>= 0)
450 err
= sendto(sendingsocket
, msg
, (char*)end
- (char*)msg
, 0, (struct sockaddr
*)&to
, GET_SA_LEN(to
));
452 if (err
> 0) err
= 0;
455 static int MessageCount
= 0;
456 // Don't report EHOSTDOWN (i.e. ARP failure), ENETDOWN, or no route to host for unicast destinations
457 if (!mDNSAddressIsAllDNSLinkGroup(dst
))
458 if (errno
== EHOSTDOWN
|| errno
== ENETDOWN
|| errno
== EHOSTUNREACH
|| errno
== ENETUNREACH
) return(mStatus_TransientErr
);
460 if (MessageCount
< 1000)
464 LogMsg("mDNSPlatformSendUDP got error %d (%s) sending packet to %#a on interface %#a/%s/%d",
465 errno
, strerror(errno
), dst
, &thisIntf
->coreIntf
.ip
, thisIntf
->intfName
, thisIntf
->index
);
467 LogMsg("mDNSPlatformSendUDP got error %d (%s) sending packet to %#a", errno
, strerror(errno
), dst
);
471 return PosixErrorToStatus(err
);
474 // This routine is called when the main loop detects that data is available on a socket.
475 mDNSlocal
void SocketDataReady(mDNS
*const m
, PosixNetworkInterface
*intf
, int skt
)
477 mDNSAddr senderAddr
, destAddr
;
478 mDNSIPPort senderPort
;
481 struct my_in_pktinfo packetInfo
;
482 struct sockaddr_storage from
;
487 const mDNSInterfaceID InterfaceID
= intf
? intf
->coreIntf
.InterfaceID
: NULL
;
492 fromLen
= sizeof(from
);
494 packetLen
= recvfrom_flags(skt
, &packet
, sizeof(packet
), &flags
, (struct sockaddr
*) &from
, &fromLen
, &packetInfo
, &ttl
);
498 SockAddrTomDNSAddr((struct sockaddr
*)&from
, &senderAddr
, &senderPort
);
499 SockAddrTomDNSAddr((struct sockaddr
*)&packetInfo
.ipi_addr
, &destAddr
, NULL
);
501 // If we have broken IP_RECVDSTADDR functionality (so far
502 // I've only seen this on OpenBSD) then apply a hack to
503 // convince mDNS Core that this isn't a spoof packet.
504 // Basically what we do is check to see whether the
505 // packet arrived as a multicast and, if so, set its
506 // destAddr to the mDNS address.
508 // I must admit that I could just be doing something
509 // wrong on OpenBSD and hence triggering this problem
510 // but I'm at a loss as to how.
512 // If this platform doesn't have IP_PKTINFO or IP_RECVDSTADDR, then we have
513 // no way to tell the destination address or interface this packet arrived on,
514 // so all we can do is just assume it's a multicast
516 #if HAVE_BROKEN_RECVDSTADDR || (!defined(IP_PKTINFO) && !defined(IP_RECVDSTADDR))
517 if ( (destAddr
.NotAnInteger
== 0) && (flags
& MSG_MCAST
) )
519 destAddr
.type
= senderAddr
.type
;
520 if (senderAddr
.type
== mDNSAddrType_IPv4
) destAddr
.ip
.v4
= AllDNSLinkGroupv4
;
521 else if (senderAddr
.type
== mDNSAddrType_IPv6
) destAddr
.ip
.v6
= AllDNSLinkGroupv6
;
525 // We only accept the packet if the interface on which it came
526 // in matches the interface associated with this socket.
527 // We do this match by name or by index, depending on which
528 // information is available. recvfrom_flags sets the name
529 // to "" if the name isn't available, or the index to -1
530 // if the index is available. This accomodates the various
531 // different capabilities of our target platforms.
536 // Ignore multicasts accidentally delivered to our unicast receiving socket
537 if (mDNSAddrIsDNSMulticast(&destAddr
)) packetLen
= -1;
541 if ( packetInfo
.ipi_ifname
[0] != 0 ) reject
= (strcmp(packetInfo
.ipi_ifname
, intf
->intfName
) != 0);
542 else if ( packetInfo
.ipi_ifindex
!= -1 ) reject
= (packetInfo
.ipi_ifindex
!= intf
->index
);
546 verbosedebugf("SocketDataReady ignored a packet from %#a to %#a on interface %s/%d expecting %#a/%s/%d/%d",
547 &senderAddr
, &destAddr
, packetInfo
.ipi_ifname
, packetInfo
.ipi_ifindex
,
548 &intf
->coreIntf
.ip
, intf
->intfName
, intf
->index
, skt
);
551 if (num_pkts_rejected
> (num_pkts_accepted
+ 1) * (num_registered_interfaces
+ 1) * 2)
554 "*** WARNING: Received %d packets; Accepted %d packets; Rejected %d packets because of interface mismatch\n",
555 num_pkts_accepted
+ num_pkts_rejected
, num_pkts_accepted
, num_pkts_rejected
);
556 num_pkts_accepted
= 0;
557 num_pkts_rejected
= 0;
562 verbosedebugf("SocketDataReady got a packet from %#a to %#a on interface %#a/%s/%d/%d",
563 &senderAddr
, &destAddr
, &intf
->coreIntf
.ip
, intf
->intfName
, intf
->index
, skt
);
570 mDNSCoreReceive(m
, &packet
, (mDNSu8
*)&packet
+ packetLen
,
571 &senderAddr
, senderPort
, &destAddr
, MulticastDNSPort
, InterfaceID
);
574 mDNSexport mStatus
mDNSPlatformTCPConnect(const mDNSAddr
*dst
, mDNSOpaque16 dstport
, mDNSInterfaceID InterfaceID
,
575 TCPConnectionCallback callback
, void *context
, int *descriptor
)
578 (void)dstport
; // Unused
579 (void)InterfaceID
; // Unused
580 (void)callback
; // Unused
581 (void)context
; // Unused
582 (void)descriptor
; // Unused
583 return(mStatus_UnsupportedErr
);
586 mDNSexport
void mDNSPlatformTCPCloseConnection(int sd
)
591 mDNSexport
int mDNSPlatformReadTCP(int sd
, void *buf
, int buflen
)
595 (void)buflen
; // Unused
599 mDNSexport
int mDNSPlatformWriteTCP(int sd
, const char *msg
, int len
)
607 #if COMPILER_LIKES_PRAGMA_MARK
608 #pragma mark ***** Get/Free Search Domain List
611 mDNSexport DNameListElem
*mDNSPlatformGetSearchDomainList(void)
613 static DNameListElem tmp
;
614 static mDNSBool init
= mDNSfalse
;
618 MakeDomainNameFromDNSNameString(&tmp
.name
, "local.");
622 return mDNS_CopyDNameList(&tmp
);
625 mDNSexport DNameListElem
*mDNSPlatformGetRegDomainList(void)
630 #if COMPILER_LIKES_PRAGMA_MARK
631 #pragma mark ***** Init and Term
634 // This gets the current hostname, truncating it at the first dot if necessary
635 mDNSlocal
void GetUserSpecifiedRFC1034ComputerName(domainlabel
*const namelabel
)
638 gethostname((char *)(&namelabel
->c
[1]), MAX_DOMAIN_LABEL
);
639 while (len
< MAX_DOMAIN_LABEL
&& namelabel
->c
[len
+1] && namelabel
->c
[len
+1] != '.') len
++;
640 namelabel
->c
[0] = len
;
643 // On OS X this gets the text of the field labelled "Computer Name" in the Sharing Prefs Control Panel
644 // Other platforms can either get the information from the appropriate place,
645 // or they can alternatively just require all registering services to provide an explicit name
646 mDNSlocal
void GetUserSpecifiedFriendlyComputerName(domainlabel
*const namelabel
)
648 // On Unix we have no better name than the host name, so we just use that.
649 GetUserSpecifiedRFC1034ComputerName( namelabel
);
652 mDNSexport
int ParseDNSServers(mDNS
*m
, const char *filePath
)
657 int numOfServers
= 0;
658 FILE *fp
= fopen(filePath
, "r");
659 if (fp
== NULL
) return -1;
660 while (fgets(line
,sizeof(line
),fp
))
663 line
[255]='\0'; // just to be safe
664 if (sscanf(line
,"%10s %15s", keyword
, nameserver
) != 2) continue; // it will skip whitespaces
665 if (strncmp(keyword
,"nameserver",10)) continue;
666 if (inet_aton(nameserver
, (struct in_addr
*)&ina
) != 0)
669 DNSAddr
.type
= mDNSAddrType_IPv4
;
670 DNSAddr
.ip
.v4
.NotAnInteger
= ina
.s_addr
;
671 mDNS_AddDNSServer(m
, &DNSAddr
, NULL
);
675 return (numOfServers
> 0) ? 0 : -1;
678 // Searches the interface list looking for the named interface.
679 // Returns a pointer to if it found, or NULL otherwise.
680 mDNSlocal PosixNetworkInterface
*SearchForInterfaceByName(mDNS
*const m
, const char *intfName
)
682 PosixNetworkInterface
*intf
;
685 assert(intfName
!= NULL
);
687 intf
= (PosixNetworkInterface
*)(m
->HostInterfaces
);
688 while ( (intf
!= NULL
) && (strcmp(intf
->intfName
, intfName
) != 0) )
689 intf
= (PosixNetworkInterface
*)(intf
->coreIntf
.next
);
694 mDNSexport mDNSInterfaceID
mDNSPlatformInterfaceIDfromInterfaceIndex(mDNS
*const m
, mDNSu32 index
)
696 PosixNetworkInterface
*intf
;
700 if (index
== kDNSServiceInterfaceIndexLocalOnly
) return(mDNSInterface_LocalOnly
);
702 intf
= (PosixNetworkInterface
*)(m
->HostInterfaces
);
703 while ( (intf
!= NULL
) && (mDNSu32
) intf
->index
!= index
)
704 intf
= (PosixNetworkInterface
*)(intf
->coreIntf
.next
);
706 return (mDNSInterfaceID
) intf
;
709 mDNSexport mDNSu32
mDNSPlatformInterfaceIndexfromInterfaceID(mDNS
*const m
, mDNSInterfaceID id
)
711 PosixNetworkInterface
*intf
;
715 if (id
== mDNSInterface_LocalOnly
) return(kDNSServiceInterfaceIndexLocalOnly
);
717 intf
= (PosixNetworkInterface
*)(m
->HostInterfaces
);
718 while ( (intf
!= NULL
) && (mDNSInterfaceID
) intf
!= id
)
719 intf
= (PosixNetworkInterface
*)(intf
->coreIntf
.next
);
721 return intf
? intf
->index
: 0;
724 // Frees the specified PosixNetworkInterface structure. The underlying
725 // interface must have already been deregistered with the mDNS core.
726 mDNSlocal
void FreePosixNetworkInterface(PosixNetworkInterface
*intf
)
728 assert(intf
!= NULL
);
729 if (intf
->intfName
!= NULL
) free((void *)intf
->intfName
);
730 if (intf
->multicastSocket4
!= -1) assert(close(intf
->multicastSocket4
) == 0);
732 if (intf
->multicastSocket6
!= -1) assert(close(intf
->multicastSocket6
) == 0);
737 // Grab the first interface, deregister it, free it, and repeat until done.
738 mDNSlocal
void ClearInterfaceList(mDNS
*const m
)
742 while (m
->HostInterfaces
)
744 PosixNetworkInterface
*intf
= (PosixNetworkInterface
*)(m
->HostInterfaces
);
745 mDNS_DeregisterInterface(m
, &intf
->coreIntf
, mDNSfalse
);
746 if (gMDNSPlatformPosixVerboseLevel
> 0) fprintf(stderr
, "Deregistered interface %s\n", intf
->intfName
);
747 FreePosixNetworkInterface(intf
);
749 num_registered_interfaces
= 0;
750 num_pkts_accepted
= 0;
751 num_pkts_rejected
= 0;
754 // Sets up a send/receive socket.
755 // If mDNSIPPort port is non-zero, then it's a multicast socket on the specified interface
756 // If mDNSIPPort port is zero, then it's a randomly assigned port number, used for sending unicast queries
757 mDNSlocal
int SetupSocket(struct sockaddr
*intfAddr
, mDNSIPPort port
, int interfaceIndex
, int *sktPtr
)
760 static const int kOn
= 1;
761 static const int kIntTwoFiveFive
= 255;
762 static const unsigned char kByteTwoFiveFive
= 255;
763 const mDNSBool JoinMulticastGroup
= (port
.NotAnInteger
!= 0);
765 (void) interfaceIndex
; // This parameter unused on plaforms that don't have IPv6
766 assert(intfAddr
!= NULL
);
767 assert(sktPtr
!= NULL
);
768 assert(*sktPtr
== -1);
770 // Open the socket...
771 if (intfAddr
->sa_family
== AF_INET
) *sktPtr
= socket(PF_INET
, SOCK_DGRAM
, IPPROTO_UDP
);
773 else if (intfAddr
->sa_family
== AF_INET6
) *sktPtr
= socket(PF_INET6
, SOCK_DGRAM
, IPPROTO_UDP
);
777 if (*sktPtr
< 0) { err
= errno
; perror("socket"); }
779 // ... with a shared UDP port, if it's for multicast receiving
780 if (err
== 0 && port
.NotAnInteger
)
782 #if defined(SO_REUSEPORT)
783 err
= setsockopt(*sktPtr
, SOL_SOCKET
, SO_REUSEPORT
, &kOn
, sizeof(kOn
));
784 #elif defined(SO_REUSEADDR)
785 err
= setsockopt(*sktPtr
, SOL_SOCKET
, SO_REUSEADDR
, &kOn
, sizeof(kOn
));
787 #error This platform has no way to avoid address busy errors on multicast.
789 if (err
< 0) { err
= errno
; perror("setsockopt - SO_REUSExxxx"); }
792 // We want to receive destination addresses and interface identifiers.
793 if (intfAddr
->sa_family
== AF_INET
)
796 struct sockaddr_in bindAddr
;
799 #if defined(IP_PKTINFO) // Linux
800 err
= setsockopt(*sktPtr
, IPPROTO_IP
, IP_PKTINFO
, &kOn
, sizeof(kOn
));
801 if (err
< 0) { err
= errno
; perror("setsockopt - IP_PKTINFO"); }
802 #elif defined(IP_RECVDSTADDR) || defined(IP_RECVIF) // BSD and Solaris
803 #if defined(IP_RECVDSTADDR)
804 err
= setsockopt(*sktPtr
, IPPROTO_IP
, IP_RECVDSTADDR
, &kOn
, sizeof(kOn
));
805 if (err
< 0) { err
= errno
; perror("setsockopt - IP_RECVDSTADDR"); }
807 #if defined(IP_RECVIF)
810 err
= setsockopt(*sktPtr
, IPPROTO_IP
, IP_RECVIF
, &kOn
, sizeof(kOn
));
811 if (err
< 0) { err
= errno
; perror("setsockopt - IP_RECVIF"); }
815 #warning This platform has no way to get the destination interface information -- will only work for single-homed hosts
818 #if defined(IP_RECVTTL) // Linux
821 setsockopt(*sktPtr
, IPPROTO_IP
, IP_RECVTTL
, &kOn
, sizeof(kOn
));
822 // We no longer depend on being able to get the received TTL, so don't worry if the option fails
826 // Add multicast group membership on this interface
827 if (err
== 0 && JoinMulticastGroup
)
829 imr
.imr_multiaddr
.s_addr
= AllDNSLinkGroupv4
.NotAnInteger
;
830 imr
.imr_interface
= ((struct sockaddr_in
*)intfAddr
)->sin_addr
;
831 err
= setsockopt(*sktPtr
, IPPROTO_IP
, IP_ADD_MEMBERSHIP
, &imr
, sizeof(imr
));
832 if (err
< 0) { err
= errno
; perror("setsockopt - IP_ADD_MEMBERSHIP"); }
835 // Specify outgoing interface too
836 if (err
== 0 && JoinMulticastGroup
)
838 err
= setsockopt(*sktPtr
, IPPROTO_IP
, IP_MULTICAST_IF
, &((struct sockaddr_in
*)intfAddr
)->sin_addr
, sizeof(struct in_addr
));
839 if (err
< 0) { err
= errno
; perror("setsockopt - IP_MULTICAST_IF"); }
842 // Per the mDNS spec, send unicast packets with TTL 255
845 err
= setsockopt(*sktPtr
, IPPROTO_IP
, IP_TTL
, &kIntTwoFiveFive
, sizeof(kIntTwoFiveFive
));
846 if (err
< 0) { err
= errno
; perror("setsockopt - IP_TTL"); }
849 // and multicast packets with TTL 255 too
850 // There's some debate as to whether IP_MULTICAST_TTL is an int or a byte so we just try both.
853 err
= setsockopt(*sktPtr
, IPPROTO_IP
, IP_MULTICAST_TTL
, &kByteTwoFiveFive
, sizeof(kByteTwoFiveFive
));
854 if (err
< 0 && errno
== EINVAL
)
855 err
= setsockopt(*sktPtr
, IPPROTO_IP
, IP_MULTICAST_TTL
, &kIntTwoFiveFive
, sizeof(kIntTwoFiveFive
));
856 if (err
< 0) { err
= errno
; perror("setsockopt - IP_MULTICAST_TTL"); }
859 // And start listening for packets
862 bindAddr
.sin_family
= AF_INET
;
863 bindAddr
.sin_port
= port
.NotAnInteger
;
864 bindAddr
.sin_addr
.s_addr
= INADDR_ANY
; // Want to receive multicasts AND unicasts on this socket
865 err
= bind(*sktPtr
, (struct sockaddr
*) &bindAddr
, sizeof(bindAddr
));
866 if (err
< 0) { err
= errno
; perror("bind"); fflush(stderr
); }
868 } // endif (intfAddr->sa_family == AF_INET)
871 else if (intfAddr
->sa_family
== AF_INET6
)
873 struct ipv6_mreq imr6
;
874 struct sockaddr_in6 bindAddr6
;
875 #if defined(IPV6_PKTINFO)
878 err
= setsockopt(*sktPtr
, IPPROTO_IPV6
, IPV6_PKTINFO
, &kOn
, sizeof(kOn
));
879 if (err
< 0) { err
= errno
; perror("setsockopt - IPV6_PKTINFO"); }
882 #warning This platform has no way to get the destination interface information for IPv6 -- will only work for single-homed hosts
884 #if defined(IPV6_HOPLIMIT)
887 err
= setsockopt(*sktPtr
, IPPROTO_IPV6
, IPV6_HOPLIMIT
, &kOn
, sizeof(kOn
));
888 if (err
< 0) { err
= errno
; perror("setsockopt - IPV6_HOPLIMIT"); }
892 // Add multicast group membership on this interface
893 if (err
== 0 && JoinMulticastGroup
)
895 imr6
.ipv6mr_multiaddr
= *(const struct in6_addr
*)&AllDNSLinkGroupv6
;
896 imr6
.ipv6mr_interface
= interfaceIndex
;
897 //LogMsg("Joining %.16a on %d", &imr6.ipv6mr_multiaddr, imr6.ipv6mr_interface);
898 err
= setsockopt(*sktPtr
, IPPROTO_IPV6
, IPV6_JOIN_GROUP
, &imr6
, sizeof(imr6
));
902 verbosedebugf("IPV6_JOIN_GROUP %.16a on %d failed.\n", &imr6
.ipv6mr_multiaddr
, imr6
.ipv6mr_interface
);
903 perror("setsockopt - IPV6_JOIN_GROUP");
907 // Specify outgoing interface too
908 if (err
== 0 && JoinMulticastGroup
)
910 u_int multicast_if
= interfaceIndex
;
911 err
= setsockopt(*sktPtr
, IPPROTO_IPV6
, IPV6_MULTICAST_IF
, &multicast_if
, sizeof(multicast_if
));
912 if (err
< 0) { err
= errno
; perror("setsockopt - IPV6_MULTICAST_IF"); }
915 // We want to receive only IPv6 packets on this socket.
916 // Without this option, we may get IPv4 addresses as mapped addresses.
919 err
= setsockopt(*sktPtr
, IPPROTO_IPV6
, IPV6_V6ONLY
, &kOn
, sizeof(kOn
));
920 if (err
< 0) { err
= errno
; perror("setsockopt - IPV6_V6ONLY"); }
923 // Per the mDNS spec, send unicast packets with TTL 255
926 err
= setsockopt(*sktPtr
, IPPROTO_IPV6
, IPV6_UNICAST_HOPS
, &kIntTwoFiveFive
, sizeof(kIntTwoFiveFive
));
927 if (err
< 0) { err
= errno
; perror("setsockopt - IPV6_UNICAST_HOPS"); }
930 // and multicast packets with TTL 255 too
931 // There's some debate as to whether IPV6_MULTICAST_HOPS is an int or a byte so we just try both.
934 err
= setsockopt(*sktPtr
, IPPROTO_IPV6
, IPV6_MULTICAST_HOPS
, &kByteTwoFiveFive
, sizeof(kByteTwoFiveFive
));
935 if (err
< 0 && errno
== EINVAL
)
936 err
= setsockopt(*sktPtr
, IPPROTO_IPV6
, IPV6_MULTICAST_HOPS
, &kIntTwoFiveFive
, sizeof(kIntTwoFiveFive
));
937 if (err
< 0) { err
= errno
; perror("setsockopt - IPV6_MULTICAST_HOPS"); }
940 // And start listening for packets
943 mDNSPlatformMemZero(&bindAddr6
, sizeof(bindAddr6
));
944 #ifndef NOT_HAVE_SA_LEN
945 bindAddr6
.sin6_len
= sizeof(bindAddr6
);
947 bindAddr6
.sin6_family
= AF_INET6
;
948 bindAddr6
.sin6_port
= port
.NotAnInteger
;
949 bindAddr6
.sin6_flowinfo
= 0;
950 bindAddr6
.sin6_addr
= in6addr_any
; // Want to receive multicasts AND unicasts on this socket
951 bindAddr6
.sin6_scope_id
= 0;
952 err
= bind(*sktPtr
, (struct sockaddr
*) &bindAddr6
, sizeof(bindAddr6
));
953 if (err
< 0) { err
= errno
; perror("bind"); fflush(stderr
); }
955 } // endif (intfAddr->sa_family == AF_INET6)
958 // Set the socket to non-blocking.
961 err
= fcntl(*sktPtr
, F_GETFL
, 0);
962 if (err
< 0) err
= errno
;
965 err
= fcntl(*sktPtr
, F_SETFL
, err
| O_NONBLOCK
);
966 if (err
< 0) err
= errno
;
971 if (err
!= 0 && *sktPtr
!= -1) { assert(close(*sktPtr
) == 0); *sktPtr
= -1; }
972 assert( (err
== 0) == (*sktPtr
!= -1) );
976 // Creates a PosixNetworkInterface for the interface whose IP address is
977 // intfAddr and whose name is intfName and registers it with mDNS core.
978 mDNSlocal
int SetupOneInterface(mDNS
*const m
, struct sockaddr
*intfAddr
, struct sockaddr
*intfMask
, const char *intfName
, int intfIndex
)
981 PosixNetworkInterface
*intf
;
982 PosixNetworkInterface
*alias
= NULL
;
985 assert(intfAddr
!= NULL
);
986 assert(intfName
!= NULL
);
987 assert(intfMask
!= NULL
);
989 // Allocate the interface structure itself.
990 intf
= (PosixNetworkInterface
*)malloc(sizeof(*intf
));
991 if (intf
== NULL
) { assert(0); err
= ENOMEM
; }
993 // And make a copy of the intfName.
996 intf
->intfName
= strdup(intfName
);
997 if (intf
->intfName
== NULL
) { assert(0); err
= ENOMEM
; }
1002 // Set up the fields required by the mDNS core.
1003 SockAddrTomDNSAddr(intfAddr
, &intf
->coreIntf
.ip
, NULL
);
1004 SockAddrTomDNSAddr(intfMask
, &intf
->coreIntf
.mask
, NULL
);
1005 //LogMsg("SetupOneInterface: %#a %#a", &intf->coreIntf.ip, &intf->coreIntf.mask);
1006 strncpy(intf
->coreIntf
.ifname
, intfName
, sizeof(intf
->coreIntf
.ifname
));
1007 intf
->coreIntf
.ifname
[sizeof(intf
->coreIntf
.ifname
)-1] = 0;
1008 intf
->coreIntf
.Advertise
= m
->AdvertiseLocalAddresses
;
1009 intf
->coreIntf
.McastTxRx
= mDNStrue
;
1011 // Set up the extra fields in PosixNetworkInterface.
1012 assert(intf
->intfName
!= NULL
); // intf->intfName already set up above
1013 intf
->index
= intfIndex
;
1014 intf
->multicastSocket4
= -1;
1016 intf
->multicastSocket6
= -1;
1018 alias
= SearchForInterfaceByName(m
, intf
->intfName
);
1019 if (alias
== NULL
) alias
= intf
;
1020 intf
->coreIntf
.InterfaceID
= (mDNSInterfaceID
)alias
;
1023 debugf("SetupOneInterface: %s %#a is an alias of %#a", intfName
, &intf
->coreIntf
.ip
, &alias
->coreIntf
.ip
);
1026 // Set up the multicast socket
1029 if (alias
->multicastSocket4
== -1 && intfAddr
->sa_family
== AF_INET
)
1030 err
= SetupSocket(intfAddr
, MulticastDNSPort
, intf
->index
, &alias
->multicastSocket4
);
1032 else if (alias
->multicastSocket6
== -1 && intfAddr
->sa_family
== AF_INET6
)
1033 err
= SetupSocket(intfAddr
, MulticastDNSPort
, intf
->index
, &alias
->multicastSocket6
);
1037 // The interface is all ready to go, let's register it with the mDNS core.
1039 err
= mDNS_RegisterInterface(m
, &intf
->coreIntf
, mDNSfalse
);
1044 num_registered_interfaces
++;
1045 debugf("SetupOneInterface: %s %#a Registered", intf
->intfName
, &intf
->coreIntf
.ip
);
1046 if (gMDNSPlatformPosixVerboseLevel
> 0)
1047 fprintf(stderr
, "Registered interface %s\n", intf
->intfName
);
1051 // Use intfName instead of intf->intfName in the next line to avoid dereferencing NULL.
1052 debugf("SetupOneInterface: %s %#a failed to register %d", intfName
, &intf
->coreIntf
.ip
, err
);
1053 if (intf
) { FreePosixNetworkInterface(intf
); intf
= NULL
; }
1056 assert( (err
== 0) == (intf
!= NULL
) );
1061 // Call get_ifi_info() to obtain a list of active interfaces and call SetupOneInterface() on each one.
1062 mDNSlocal
int SetupInterfaceList(mDNS
*const m
)
1064 mDNSBool foundav4
= mDNSfalse
;
1066 struct ifi_info
*intfList
= get_ifi_info(AF_INET
, mDNStrue
);
1067 struct ifi_info
*firstLoopback
= NULL
;
1070 debugf("SetupInterfaceList");
1072 if (intfList
== NULL
) err
= ENOENT
;
1075 if (err
== 0) /* Link the IPv6 list to the end of the IPv4 list */
1077 struct ifi_info
**p
= &intfList
;
1078 while (*p
) p
= &(*p
)->ifi_next
;
1079 *p
= get_ifi_info(AF_INET6
, mDNStrue
);
1085 struct ifi_info
*i
= intfList
;
1088 if ( ((i
->ifi_addr
->sa_family
== AF_INET
)
1090 || (i
->ifi_addr
->sa_family
== AF_INET6
)
1092 ) && (i
->ifi_flags
& IFF_UP
) && !(i
->ifi_flags
& IFF_POINTOPOINT
) )
1094 if (i
->ifi_flags
& IFF_LOOPBACK
)
1096 if (firstLoopback
== NULL
)
1101 if (SetupOneInterface(m
, i
->ifi_addr
, i
->ifi_netmask
, i
->ifi_name
, i
->ifi_index
) == 0)
1102 if (i
->ifi_addr
->sa_family
== AF_INET
)
1103 foundav4
= mDNStrue
;
1109 // If we found no normal interfaces but we did find a loopback interface, register the
1110 // loopback interface. This allows self-discovery if no interfaces are configured.
1111 // Temporary workaround: Multicast loopback on IPv6 interfaces appears not to work.
1112 // In the interim, we skip loopback interface only if we found at least one v4 interface to use
1113 // if ( (m->HostInterfaces == NULL) && (firstLoopback != NULL) )
1114 if ( !foundav4
&& firstLoopback
)
1115 (void) SetupOneInterface(m
, firstLoopback
->ifi_addr
, firstLoopback
->ifi_netmask
, firstLoopback
->ifi_name
, firstLoopback
->ifi_index
);
1119 if (intfList
!= NULL
) free_ifi_info(intfList
);
1125 // See <http://www.faqs.org/rfcs/rfc3549.html> for a description of NetLink
1127 // Open a socket that will receive interface change notifications
1128 mDNSlocal mStatus
OpenIfNotifySocket( int *pFD
)
1130 mStatus err
= mStatus_NoError
;
1131 struct sockaddr_nl snl
;
1135 sock
= socket( AF_NETLINK
, SOCK_RAW
, NETLINK_ROUTE
);
1139 // Configure read to be non-blocking because inbound msg size is not known in advance
1140 (void) fcntl( sock
, F_SETFL
, O_NONBLOCK
);
1142 /* Subscribe the socket to Link & IP addr notifications. */
1143 bzero( &snl
, sizeof snl
);
1144 snl
.nl_family
= AF_NETLINK
;
1145 snl
.nl_groups
= RTMGRP_LINK
| RTMGRP_IPV4_IFADDR
;
1146 ret
= bind( sock
, (struct sockaddr
*) &snl
, sizeof snl
);
1156 mDNSlocal
void PrintNetLinkMsg( const struct nlmsghdr
*pNLMsg
)
1158 const char *kNLMsgTypes
[] = { "", "NLMSG_NOOP", "NLMSG_ERROR", "NLMSG_DONE", "NLMSG_OVERRUN" };
1159 const char *kNLRtMsgTypes
[] = { "RTM_NEWLINK", "RTM_DELLINK", "RTM_GETLINK", "RTM_NEWADDR", "RTM_DELADDR", "RTM_GETADDR" };
1161 printf( "nlmsghdr len=%d, type=%s, flags=0x%x\n", pNLMsg
->nlmsg_len
,
1162 pNLMsg
->nlmsg_type
< RTM_BASE
? kNLMsgTypes
[ pNLMsg
->nlmsg_type
] : kNLRtMsgTypes
[ pNLMsg
->nlmsg_type
- RTM_BASE
],
1163 pNLMsg
->nlmsg_flags
);
1165 if ( RTM_NEWLINK
<= pNLMsg
->nlmsg_type
&& pNLMsg
->nlmsg_type
<= RTM_GETLINK
)
1167 struct ifinfomsg
*pIfInfo
= (struct ifinfomsg
*) NLMSG_DATA( pNLMsg
);
1168 printf( "ifinfomsg family=%d, type=%d, index=%d, flags=0x%x, change=0x%x\n", pIfInfo
->ifi_family
,
1169 pIfInfo
->ifi_type
, pIfInfo
->ifi_index
, pIfInfo
->ifi_flags
, pIfInfo
->ifi_change
);
1172 else if ( RTM_NEWADDR
<= pNLMsg
->nlmsg_type
&& pNLMsg
->nlmsg_type
<= RTM_GETADDR
)
1174 struct ifaddrmsg
*pIfAddr
= (struct ifaddrmsg
*) NLMSG_DATA( pNLMsg
);
1175 printf( "ifaddrmsg family=%d, index=%d, flags=0x%x\n", pIfAddr
->ifa_family
,
1176 pIfAddr
->ifa_index
, pIfAddr
->ifa_flags
);
1182 mDNSlocal mDNSu32
ProcessRoutingNotification( int sd
)
1183 // Read through the messages on sd and if any indicate that any interface records should
1184 // be torn down and rebuilt, return affected indices as a bitmask. Otherwise return 0.
1188 struct nlmsghdr
*pNLMsg
= (struct nlmsghdr
*) buff
;
1191 // The structure here is more complex than it really ought to be because,
1192 // unfortunately, there's no good way to size a buffer in advance large
1193 // enough to hold all pending data and so avoid message fragmentation.
1194 // (Note that FIONREAD is not supported on AF_NETLINK.)
1196 readCount
= read( sd
, buff
, sizeof buff
);
1199 // Make sure we've got an entire nlmsghdr in the buffer, and payload, too.
1200 // If not, discard already-processed messages in buffer and read more data.
1201 if ( ( (char*) &pNLMsg
[1] > ( buff
+ readCount
)) || // i.e. *pNLMsg extends off end of buffer
1202 ( (char*) pNLMsg
+ pNLMsg
->nlmsg_len
> ( buff
+ readCount
)))
1204 if ( buff
< (char*) pNLMsg
) // we have space to shuffle
1206 // discard processed data
1207 readCount
-= ( (char*) pNLMsg
- buff
);
1208 memmove( buff
, pNLMsg
, readCount
);
1209 pNLMsg
= (struct nlmsghdr
*) buff
;
1212 readCount
+= read( sd
, buff
+ readCount
, sizeof buff
- readCount
);
1213 continue; // spin around and revalidate with new readCount
1216 break; // Otherwise message does not fit in buffer
1220 PrintNetLinkMsg( pNLMsg
);
1223 // Process the NetLink message
1224 if ( pNLMsg
->nlmsg_type
== RTM_GETLINK
|| pNLMsg
->nlmsg_type
== RTM_NEWLINK
)
1225 result
|= 1 << ((struct ifinfomsg
*) NLMSG_DATA( pNLMsg
))->ifi_index
;
1226 else if ( pNLMsg
->nlmsg_type
== RTM_DELADDR
|| pNLMsg
->nlmsg_type
== RTM_NEWADDR
)
1227 result
|= 1 << ((struct ifaddrmsg
*) NLMSG_DATA( pNLMsg
))->ifa_index
;
1229 // Advance pNLMsg to the next message in the buffer
1230 if ( ( pNLMsg
->nlmsg_flags
& NLM_F_MULTI
) != 0 && pNLMsg
->nlmsg_type
!= NLMSG_DONE
)
1232 ssize_t len
= readCount
- ( (char*)pNLMsg
- buff
);
1233 pNLMsg
= NLMSG_NEXT( pNLMsg
, len
);
1242 #else // USES_NETLINK
1244 // Open a socket that will receive interface change notifications
1245 mDNSlocal mStatus
OpenIfNotifySocket( int *pFD
)
1247 *pFD
= socket( AF_ROUTE
, SOCK_RAW
, 0);
1250 return mStatus_UnknownErr
;
1252 // Configure read to be non-blocking because inbound msg size is not known in advance
1253 (void) fcntl( *pFD
, F_SETFL
, O_NONBLOCK
);
1255 return mStatus_NoError
;
1259 mDNSlocal
void PrintRoutingSocketMsg( const struct ifa_msghdr
*pRSMsg
)
1261 const char *kRSMsgTypes
[] = { "", "RTM_ADD", "RTM_DELETE", "RTM_CHANGE", "RTM_GET", "RTM_LOSING",
1262 "RTM_REDIRECT", "RTM_MISS", "RTM_LOCK", "RTM_OLDADD", "RTM_OLDDEL", "RTM_RESOLVE",
1263 "RTM_NEWADDR", "RTM_DELADDR", "RTM_IFINFO", "RTM_NEWMADDR", "RTM_DELMADDR" };
1265 int index
= pRSMsg
->ifam_type
== RTM_IFINFO
? ((struct if_msghdr
*) pRSMsg
)->ifm_index
: pRSMsg
->ifam_index
;
1267 printf( "ifa_msghdr len=%d, type=%s, index=%d\n", pRSMsg
->ifam_msglen
, kRSMsgTypes
[ pRSMsg
->ifam_type
], index
);
1271 mDNSlocal mDNSu32
ProcessRoutingNotification( int sd
)
1272 // Read through the messages on sd and if any indicate that any interface records should
1273 // be torn down and rebuilt, return affected indices as a bitmask. Otherwise return 0.
1277 struct ifa_msghdr
*pRSMsg
= (struct ifa_msghdr
*) buff
;
1280 readCount
= read( sd
, buff
, sizeof buff
);
1281 if ( readCount
< (ssize_t
) sizeof( struct ifa_msghdr
))
1282 return mStatus_UnsupportedErr
; // cannot decipher message
1285 PrintRoutingSocketMsg( pRSMsg
);
1288 // Process the message
1289 if ( pRSMsg
->ifam_type
== RTM_NEWADDR
|| pRSMsg
->ifam_type
== RTM_DELADDR
||
1290 pRSMsg
->ifam_type
== RTM_IFINFO
)
1292 if ( pRSMsg
->ifam_type
== RTM_IFINFO
)
1293 result
|= 1 << ((struct if_msghdr
*) pRSMsg
)->ifm_index
;
1295 result
|= 1 << pRSMsg
->ifam_index
;
1301 #endif // USES_NETLINK
1303 // Called when data appears on interface change notification socket
1304 mDNSlocal
void InterfaceChangeCallback( void *context
)
1306 IfChangeRec
*pChgRec
= (IfChangeRec
*) context
;
1308 mDNSu32 changedInterfaces
= 0;
1309 struct timeval zeroTimeout
= { 0, 0 };
1312 FD_SET( pChgRec
->NotifySD
, &readFDs
);
1316 changedInterfaces
|= ProcessRoutingNotification( pChgRec
->NotifySD
);
1318 while ( 0 < select( pChgRec
->NotifySD
+ 1, &readFDs
, (fd_set
*) NULL
, (fd_set
*) NULL
, &zeroTimeout
));
1320 // Currently we rebuild the entire interface list whenever any interface change is
1321 // detected. If this ever proves to be a performance issue in a multi-homed
1322 // configuration, more care should be paid to changedInterfaces.
1323 if ( changedInterfaces
)
1324 mDNSPlatformPosixRefreshInterfaceList( pChgRec
->mDNS
);
1327 // Register with either a Routing Socket or RtNetLink to listen for interface changes.
1328 mDNSlocal mStatus
WatchForInterfaceChange(mDNS
*const m
)
1331 IfChangeRec
*pChgRec
;
1333 pChgRec
= (IfChangeRec
*) mDNSPlatformMemAllocate( sizeof *pChgRec
);
1334 if ( pChgRec
== NULL
)
1335 return mStatus_NoMemoryErr
;
1338 err
= OpenIfNotifySocket( &pChgRec
->NotifySD
);
1340 err
= mDNSPosixAddFDToEventLoop( pChgRec
->NotifySD
, InterfaceChangeCallback
, pChgRec
);
1345 // Test to see if we're the first client running on UDP port 5353, by trying to bind to 5353 without using SO_REUSEPORT.
1346 // If we fail, someone else got here first. That's not a big problem; we can share the port for multicast responses --
1347 // we just need to be aware that we shouldn't expect to successfully receive unicast UDP responses.
1348 mDNSlocal mDNSBool
mDNSPlatformInit_CanReceiveUnicast(void)
1351 int s
= socket(AF_INET
, SOCK_DGRAM
, IPPROTO_UDP
);
1352 struct sockaddr_in s5353
;
1353 s5353
.sin_family
= AF_INET
;
1354 s5353
.sin_port
= MulticastDNSPort
.NotAnInteger
;
1355 s5353
.sin_addr
.s_addr
= 0;
1356 err
= bind(s
, (struct sockaddr
*)&s5353
, sizeof(s5353
));
1358 if (err
) debugf("No unicast UDP responses");
1359 else debugf("Unicast UDP responses okay");
1363 // mDNS core calls this routine to initialise the platform-specific data.
1364 mDNSexport mStatus
mDNSPlatformInit(mDNS
*const m
)
1370 if (mDNSPlatformInit_CanReceiveUnicast()) m
->CanReceiveUnicastOn5353
= mDNStrue
;
1372 // Tell mDNS core the names of this machine.
1374 // Set up the nice label
1375 m
->nicelabel
.c
[0] = 0;
1376 GetUserSpecifiedFriendlyComputerName(&m
->nicelabel
);
1377 if (m
->nicelabel
.c
[0] == 0) MakeDomainLabelFromLiteralString(&m
->nicelabel
, "Computer");
1379 // Set up the RFC 1034-compliant label
1380 m
->hostlabel
.c
[0] = 0;
1381 GetUserSpecifiedRFC1034ComputerName(&m
->hostlabel
);
1382 if (m
->hostlabel
.c
[0] == 0) MakeDomainLabelFromLiteralString(&m
->hostlabel
, "Computer");
1386 sa
.sa_family
= AF_INET
;
1387 m
->p
->unicastSocket4
= -1;
1388 if (err
== mStatus_NoError
) err
= SetupSocket(&sa
, zeroIPPort
, 0, &m
->p
->unicastSocket4
);
1390 sa
.sa_family
= AF_INET6
;
1391 m
->p
->unicastSocket6
= -1;
1392 if (err
== mStatus_NoError
) err
= SetupSocket(&sa
, zeroIPPort
, 0, &m
->p
->unicastSocket6
);
1395 // Tell mDNS core about the network interfaces on this machine.
1396 if (err
== mStatus_NoError
) err
= SetupInterfaceList(m
);
1398 // Tell mDNS core about DNS Servers
1399 if (err
== mStatus_NoError
) ParseDNSServers(m
, uDNS_SERVERS_FILE
);
1401 if (err
== mStatus_NoError
)
1403 err
= WatchForInterfaceChange(m
);
1404 // Failure to observe interface changes is non-fatal.
1405 if ( err
!= mStatus_NoError
)
1407 fprintf(stderr
, "mDNS(%d) WARNING: Unable to detect interface changes (%d).\n", getpid(), err
);
1408 err
= mStatus_NoError
;
1412 // We don't do asynchronous initialization on the Posix platform, so by the time
1413 // we get here the setup will already have succeeded or failed. If it succeeded,
1414 // we should just call mDNSCoreInitComplete() immediately.
1415 if (err
== mStatus_NoError
)
1416 mDNSCoreInitComplete(m
, mStatus_NoError
);
1418 return PosixErrorToStatus(err
);
1421 // mDNS core calls this routine to clean up the platform-specific data.
1422 // In our case all we need to do is to tear down every network interface.
1423 mDNSexport
void mDNSPlatformClose(mDNS
*const m
)
1426 ClearInterfaceList(m
);
1427 if (m
->p
->unicastSocket4
!= -1) assert(close(m
->p
->unicastSocket4
) == 0);
1429 if (m
->p
->unicastSocket6
!= -1) assert(close(m
->p
->unicastSocket6
) == 0);
1433 mDNSexport mStatus
mDNSPlatformPosixRefreshInterfaceList(mDNS
*const m
)
1436 ClearInterfaceList(m
);
1437 err
= SetupInterfaceList(m
);
1438 return PosixErrorToStatus(err
);
1441 #if COMPILER_LIKES_PRAGMA_MARK
1442 #pragma mark ***** Locking
1445 // On the Posix platform, locking is a no-op because we only ever enter
1446 // mDNS core on the main thread.
1448 // mDNS core calls this routine when it wants to prevent
1449 // the platform from reentering mDNS core code.
1450 mDNSexport
void mDNSPlatformLock (const mDNS
*const m
)
1455 // mDNS core calls this routine when it release the lock taken by
1456 // mDNSPlatformLock and allow the platform to reenter mDNS core code.
1457 mDNSexport
void mDNSPlatformUnlock (const mDNS
*const m
)
1462 #if COMPILER_LIKES_PRAGMA_MARK
1463 #pragma mark ***** Strings
1466 // mDNS core calls this routine to copy C strings.
1467 // On the Posix platform this maps directly to the ANSI C strcpy.
1468 mDNSexport
void mDNSPlatformStrCopy(const void *src
, void *dst
)
1470 strcpy((char *)dst
, (char *)src
);
1473 // mDNS core calls this routine to get the length of a C string.
1474 // On the Posix platform this maps directly to the ANSI C strlen.
1475 mDNSexport mDNSu32
mDNSPlatformStrLen (const void *src
)
1477 return strlen((char*)src
);
1480 // mDNS core calls this routine to copy memory.
1481 // On the Posix platform this maps directly to the ANSI C memcpy.
1482 mDNSexport
void mDNSPlatformMemCopy(const void *src
, void *dst
, mDNSu32 len
)
1484 memcpy(dst
, src
, len
);
1487 // mDNS core calls this routine to test whether blocks of memory are byte-for-byte
1488 // identical. On the Posix platform this is a simple wrapper around ANSI C memcmp.
1489 mDNSexport mDNSBool
mDNSPlatformMemSame(const void *src
, const void *dst
, mDNSu32 len
)
1491 return memcmp(dst
, src
, len
) == 0;
1494 // mDNS core calls this routine to clear blocks of memory.
1495 // On the Posix platform this is a simple wrapper around ANSI C memset.
1496 mDNSexport
void mDNSPlatformMemZero( void *dst
, mDNSu32 len
)
1498 memset(dst
, 0, len
);
1501 mDNSexport
void * mDNSPlatformMemAllocate(mDNSu32 len
) { return(malloc(len
)); }
1502 mDNSexport
void mDNSPlatformMemFree (void *mem
) { free(mem
); }
1504 mDNSexport mDNSu32
mDNSPlatformRandomSeed(void)
1507 gettimeofday(&tv
, NULL
);
1511 mDNSexport mDNSs32 mDNSPlatformOneSecond
= 1024;
1513 mDNSexport mStatus
mDNSPlatformTimeInit(void)
1515 // No special setup is required on Posix -- we just use gettimeofday();
1516 // This is not really safe, because gettimeofday can go backwards if the user manually changes the date or time
1517 // We should find a better way to do this
1518 return(mStatus_NoError
);
1521 mDNSexport mDNSs32
mDNSPlatformRawTime()
1524 gettimeofday(&tv
, NULL
);
1525 // tv.tv_sec is seconds since 1st January 1970 (GMT, with no adjustment for daylight savings time)
1526 // tv.tv_usec is microseconds since the start of this second (i.e. values 0 to 999999)
1527 // We use the lower 22 bits of tv.tv_sec for the top 22 bits of our result
1528 // and we multiply tv.tv_usec by 16 / 15625 to get a value in the range 0-1023 to go in the bottom 10 bits.
1529 // This gives us a proper modular (cyclic) counter that has a resolution of roughly 1ms (actually 1/1024 second)
1530 // and correctly cycles every 2^22 seconds (4194304 seconds = approx 48 days).
1531 return( (tv
.tv_sec
<< 10) | (tv
.tv_usec
* 16 / 15625) );
1534 mDNSexport mDNSs32
mDNSPlatformUTC(void)
1539 mDNSlocal
void mDNSPosixAddToFDSet(int *nfds
, fd_set
*readfds
, int s
)
1541 if (*nfds
< s
+ 1) *nfds
= s
+ 1;
1545 mDNSexport
void mDNSPosixGetFDSet(mDNS
*m
, int *nfds
, fd_set
*readfds
, struct timeval
*timeout
)
1548 struct timeval interval
;
1550 // 1. Call mDNS_Execute() to let mDNSCore do what it needs to do
1551 mDNSs32 nextevent
= mDNS_Execute(m
);
1553 // 2. Build our list of active file descriptors
1554 PosixNetworkInterface
*info
= (PosixNetworkInterface
*)(m
->HostInterfaces
);
1555 if (m
->p
->unicastSocket4
!= -1) mDNSPosixAddToFDSet(nfds
, readfds
, m
->p
->unicastSocket4
);
1557 if (m
->p
->unicastSocket6
!= -1) mDNSPosixAddToFDSet(nfds
, readfds
, m
->p
->unicastSocket6
);
1561 if (info
->multicastSocket4
!= -1) mDNSPosixAddToFDSet(nfds
, readfds
, info
->multicastSocket4
);
1563 if (info
->multicastSocket6
!= -1) mDNSPosixAddToFDSet(nfds
, readfds
, info
->multicastSocket6
);
1565 info
= (PosixNetworkInterface
*)(info
->coreIntf
.next
);
1568 // 3. Calculate the time remaining to the next scheduled event (in struct timeval format)
1569 ticks
= nextevent
- mDNS_TimeNow(m
);
1570 if (ticks
< 1) ticks
= 1;
1571 interval
.tv_sec
= ticks
>> 10; // The high 22 bits are seconds
1572 interval
.tv_usec
= ((ticks
& 0x3FF) * 15625) / 16; // The low 10 bits are 1024ths
1574 // 4. If client's proposed timeout is more than what we want, then reduce it
1575 if (timeout
->tv_sec
> interval
.tv_sec
||
1576 (timeout
->tv_sec
== interval
.tv_sec
&& timeout
->tv_usec
> interval
.tv_usec
))
1577 *timeout
= interval
;
1580 mDNSexport
void mDNSPosixProcessFDSet(mDNS
*const m
, fd_set
*readfds
)
1582 PosixNetworkInterface
*info
;
1584 assert(readfds
!= NULL
);
1585 info
= (PosixNetworkInterface
*)(m
->HostInterfaces
);
1587 if (m
->p
->unicastSocket4
!= -1 && FD_ISSET(m
->p
->unicastSocket4
, readfds
))
1589 FD_CLR(m
->p
->unicastSocket4
, readfds
);
1590 SocketDataReady(m
, NULL
, m
->p
->unicastSocket4
);
1593 if (m
->p
->unicastSocket6
!= -1 && FD_ISSET(m
->p
->unicastSocket6
, readfds
))
1595 FD_CLR(m
->p
->unicastSocket6
, readfds
);
1596 SocketDataReady(m
, NULL
, m
->p
->unicastSocket6
);
1602 if (info
->multicastSocket4
!= -1 && FD_ISSET(info
->multicastSocket4
, readfds
))
1604 FD_CLR(info
->multicastSocket4
, readfds
);
1605 SocketDataReady(m
, info
, info
->multicastSocket4
);
1608 if (info
->multicastSocket6
!= -1 && FD_ISSET(info
->multicastSocket6
, readfds
))
1610 FD_CLR(info
->multicastSocket6
, readfds
);
1611 SocketDataReady(m
, info
, info
->multicastSocket6
);
1614 info
= (PosixNetworkInterface
*)(info
->coreIntf
.next
);
1619 mDNSlocal
void DetermineMaxEventFD( void )
1621 PosixEventSource
*iSource
;
1624 for ( iSource
=(PosixEventSource
*)gEventSources
.Head
; iSource
; iSource
= iSource
->Next
)
1625 if ( gMaxFD
< iSource
->fd
)
1626 gMaxFD
= iSource
->fd
;
1629 // Add a file descriptor to the set that mDNSPosixRunEventLoopOnce() listens to.
1630 mStatus
mDNSPosixAddFDToEventLoop( int fd
, mDNSPosixEventCallback callback
, void *context
)
1632 PosixEventSource
*newSource
;
1634 if ( gEventSources
.LinkOffset
== 0)
1635 InitLinkedList( &gEventSources
, offsetof( PosixEventSource
, Next
));
1637 if ( fd
>= (int) FD_SETSIZE
|| fd
< 0)
1638 return mStatus_UnsupportedErr
;
1639 if ( callback
== NULL
)
1640 return mStatus_BadParamErr
;
1642 newSource
= (PosixEventSource
*) malloc( sizeof *newSource
);
1643 if ( NULL
== newSource
)
1644 return mStatus_NoMemoryErr
;
1646 newSource
->Callback
= callback
;
1647 newSource
->Context
= context
;
1650 AddToTail( &gEventSources
, newSource
);
1651 FD_SET( fd
, &gEventFDs
);
1653 DetermineMaxEventFD();
1655 return mStatus_NoError
;
1658 // Remove a file descriptor from the set that mDNSPosixRunEventLoopOnce() listens to.
1659 mStatus
mDNSPosixRemoveFDFromEventLoop( int fd
)
1661 PosixEventSource
*iSource
;
1663 for ( iSource
=(PosixEventSource
*)gEventSources
.Head
; iSource
; iSource
= iSource
->Next
)
1665 if ( fd
== iSource
->fd
)
1667 FD_CLR( fd
, &gEventFDs
);
1668 RemoveFromList( &gEventSources
, iSource
);
1670 DetermineMaxEventFD();
1671 return mStatus_NoError
;
1674 return mStatus_NoSuchNameErr
;
1677 // Simply note the received signal in gEventSignals.
1678 mDNSlocal
void NoteSignal( int signum
)
1680 sigaddset( &gEventSignals
, signum
);
1683 // Tell the event package to listen for signal and report it in mDNSPosixRunEventLoopOnce().
1684 mStatus
mDNSPosixListenForSignalInEventLoop( int signum
)
1686 struct sigaction action
;
1689 bzero( &action
, sizeof action
); // more portable than member-wise assignment
1690 action
.sa_handler
= NoteSignal
;
1691 err
= sigaction( signum
, &action
, (struct sigaction
*) NULL
);
1693 sigaddset( &gEventSignalSet
, signum
);
1698 // Tell the event package to stop listening for signal in mDNSPosixRunEventLoopOnce().
1699 mStatus
mDNSPosixIgnoreSignalInEventLoop( int signum
)
1701 struct sigaction action
;
1704 bzero( &action
, sizeof action
); // more portable than member-wise assignment
1705 action
.sa_handler
= SIG_DFL
;
1706 err
= sigaction( signum
, &action
, (struct sigaction
*) NULL
);
1708 sigdelset( &gEventSignalSet
, signum
);
1713 // Do a single pass through the attendent event sources and dispatch any found to their callbacks.
1714 // Return as soon as internal timeout expires, or a signal we're listening for is received.
1715 mStatus
mDNSPosixRunEventLoopOnce( mDNS
*m
, const struct timeval
*pTimeout
,
1716 sigset_t
*pSignalsReceived
, mDNSBool
*pDataDispatched
)
1718 fd_set listenFDs
= gEventFDs
;
1719 int fdMax
= 0, numReady
;
1720 struct timeval timeout
= *pTimeout
;
1722 // Include the sockets that are listening to the wire in our select() set
1723 mDNSPosixGetFDSet( m
, &fdMax
, &listenFDs
, &timeout
); // timeout may get modified
1724 if ( fdMax
< gMaxFD
)
1727 numReady
= select( fdMax
+ 1, &listenFDs
, (fd_set
*) NULL
, (fd_set
*) NULL
, &timeout
);
1729 // If any data appeared, invoke its callback
1732 PosixEventSource
*iSource
;
1734 (void) mDNSPosixProcessFDSet( m
, &listenFDs
); // call this first to process wire data for clients
1736 for ( iSource
=(PosixEventSource
*)gEventSources
.Head
; iSource
; iSource
= iSource
->Next
)
1738 if ( FD_ISSET( iSource
->fd
, &listenFDs
))
1740 iSource
->Callback( iSource
->Context
);
1741 break; // in case callback removed elements from gEventSources
1744 *pDataDispatched
= mDNStrue
;
1747 *pDataDispatched
= mDNSfalse
;
1749 (void) sigprocmask( SIG_BLOCK
, &gEventSignalSet
, (sigset_t
*) NULL
);
1750 *pSignalsReceived
= gEventSignals
;
1751 sigemptyset( &gEventSignals
);
1752 (void) sigprocmask( SIG_UNBLOCK
, &gEventSignalSet
, (sigset_t
*) NULL
);
1754 return mStatus_NoError
;