1 /* -*- Mode: C; tab-width: 4; c-file-style: "bsd"; c-basic-offset: 4; fill-column: 108; indent-tabs-mode: nil; -*-
3 * Copyright (c) 2004-2019 Apple 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.
17 * This file defines functions that are common to platforms with Posix APIs.
18 * Current examples are mDNSMacOSX and mDNSPosix.
21 #include <stdio.h> // Needed for fopen() etc.
22 #include <unistd.h> // Needed for close()
23 #include <stdlib.h> // Needed for malloc()
24 #include <string.h> // Needed for strlen() etc.
25 #include <errno.h> // Needed for errno etc.
26 #include <sys/socket.h> // Needed for socket() etc.
27 #include <netinet/in.h> // Needed for sockaddr_in
29 #include <sys/fcntl.h>
30 #include <netinet/tcp.h>
31 #include <arpa/inet.h>
34 #if APPLE_OSX_mDNSResponder
38 #include "mDNSEmbeddedAPI.h" // Defines the interface provided to the client layer above
39 #include "DNSCommon.h"
40 #include "PlatformCommon.h"
42 #ifdef NOT_HAVE_SOCKLEN_T
43 typedef unsigned int socklen_t
;
46 #if MDNS_MALLOC_DEBUGGING
47 // We ONLY want this for malloc debugging--on a running production system we want to deal with
48 // malloc failures, not just die. There is a small performance penalty for enabling these options
49 // as well, so they are all only appropriate for debugging. The flags mean:
51 // A = warnings are errors
52 // X = abort on failure
54 // J = allocated memory is initialized to a pattern
55 // R causes realloc to always reallocate even if not needed
57 char _malloc_options
[] = "AXZ";
59 mDNSlocal mDNSListValidator
*listValidators
;
61 mDNSexport
void mDNSPlatformAddListValidator(mDNSListValidator
*lv
, mDNSListValidationFunction
*lvf
,
62 const char *lvfName
, void *context
)
64 mDNSPlatformMemZero(lv
, sizeof *lv
);
66 lv
->validationFunctionName
= lvfName
;
67 lv
->context
= context
;
68 lv
->next
= listValidators
;
72 mDNSlocal
void validateLists(void)
74 mDNSListValidator
*vfp
;
75 // Check Unix Domain Socket client lists (uds_daemon.c)
76 for (vfp
= listValidators
; vfp
; vfp
= vfp
->next
)
78 vfp
->validator(vfp
->context
);
81 mDNSPlatformValidateLists();
84 #define kAllocMagic 0xDEAD1234
85 #define kGuardMagic 0xDEAD1234
86 #define kFreeMagic 0xDEADDEAD
87 #define kAllocLargeSize 32768
89 mDNSexport
void *mallocL(const char *msg
, mDNSu32 size
)
91 // Allocate space for two words of sanity checking data before the requested block and two words after.
92 // Adjust the length for alignment.
93 mDNSu32
*mem
= malloc(sizeof(mDNSu32
) * 4 + size
);
96 { LogMsg("malloc( %s : %u ) failed", msg
, size
); return(NULL
); }
99 mDNSu32
*after
= (mDNSu32
*)((mDNSu8
*)(mem
+ 2) + size
);
100 if (size
> kAllocLargeSize
) LogMsg("malloc( %s : %lu ) @ %p suspiciously large", msg
, size
, &mem
[2]);
101 else if (MDNS_MALLOC_DEBUGGING
>= 2) LogMsg("malloc( %s : %lu ) @ %p", msg
, size
, &mem
[2]);
102 mem
[ 0] = kAllocMagic
;
103 guard
[0] = kGuardMagic
;
106 memcpy(after
, &guard
, sizeof guard
);
107 memset(&mem
[2], 0xFF, size
);
113 mDNSexport
void *callocL(const char *msg
, mDNSu32 size
)
116 const mDNSu32 headerSize
= 4 * sizeof(mDNSu32
);
118 // Allocate space for two words of sanity checking data before the requested block and two words after.
119 // Adjust the length for alignment.
120 mDNSu32
*mem
= (mDNSu32
*)calloc(1, headerSize
+ size
);
122 { LogMsg("calloc( %s : %u ) failed", msg
, size
); return(NULL
); }
125 mDNSu32
*after
= (mDNSu32
*)((mDNSu8
*)(mem
+ 2) + size
);
126 if (size
> kAllocLargeSize
) LogMsg("calloc( %s : %lu ) @ %p suspiciously large", msg
, size
, &mem
[2]);
127 else if (MDNS_MALLOC_DEBUGGING
>= 2) LogMsg("calloc( %s : %lu ) @ %p", msg
, size
, &mem
[2]);
128 mem
[ 0] = kAllocMagic
;
129 guard
[0] = kGuardMagic
;
132 memcpy(after
, guard
, sizeof guard
);
138 mDNSexport
void freeL(const char *msg
, void *x
)
141 LogMsg("free( %s @ NULL )!", msg
);
144 mDNSu32
*mem
= ((mDNSu32
*)x
) - 2;
145 if (mem
[0] == kFreeMagic
) { LogMemCorruption("free( %s : %lu @ %p ) !!!! ALREADY DISPOSED !!!!", msg
, mem
[1], &mem
[2]); return; }
146 if (mem
[0] != kAllocMagic
) { LogMemCorruption("free( %s : %lu @ %p ) !!!! NEVER ALLOCATED !!!!", msg
, mem
[1], &mem
[2]); return; }
147 if (mem
[1] > kAllocLargeSize
) LogMsg("free( %s : %lu @ %p) suspiciously large", msg
, mem
[1], &mem
[2]);
148 else if (MDNS_MALLOC_DEBUGGING
>= 2) LogMsg("free( %s : %ld @ %p)", msg
, mem
[1], &mem
[2]);
149 mDNSu32
*after
= (mDNSu32
*)((mDNSu8
*)x
+ mem
[1]);
152 memcpy(guard
, after
, sizeof guard
);
153 if (guard
[0] != kGuardMagic
) { LogMemCorruption("free( %s : %lu @ %p ) !!!! END GUARD OVERWRITE !!!!",
154 msg
, mem
[1], &mem
[2]); return; }
155 if (guard
[1] != mem
[1]) { LogMemCorruption("free( %s : %lu @ %p ) !!!! LENGTH MISMATCH !!!!",
156 msg
, mem
[1], &mem
[2]); return; }
158 memset(mem
+ 2, 0xFF, mem
[1] + 2 * sizeof(mDNSu32
));
166 // Bind a UDP socket to find the source address to a destination
167 mDNSexport
void mDNSPlatformSourceAddrForDest(mDNSAddr
*const src
, const mDNSAddr
*const dst
)
169 union { struct sockaddr s
; struct sockaddr_in a4
; struct sockaddr_in6 a6
; } addr
;
170 socklen_t len
= sizeof(addr
);
171 socklen_t inner_len
= 0;
172 int sock
= socket(AF_INET
, SOCK_DGRAM
, 0);
173 src
->type
= mDNSAddrType_None
;
174 if (sock
== -1) return;
175 if (dst
->type
== mDNSAddrType_IPv4
)
177 inner_len
= sizeof(addr
.a4
);
178 #ifndef NOT_HAVE_SA_LEN
179 addr
.a4
.sin_len
= inner_len
;
181 addr
.a4
.sin_family
= AF_INET
;
182 addr
.a4
.sin_port
= 1; // Not important, any port will do
183 addr
.a4
.sin_addr
.s_addr
= dst
->ip
.v4
.NotAnInteger
;
185 else if (dst
->type
== mDNSAddrType_IPv6
)
187 inner_len
= sizeof(addr
.a6
);
188 #ifndef NOT_HAVE_SA_LEN
189 addr
.a6
.sin6_len
= inner_len
;
191 addr
.a6
.sin6_family
= AF_INET6
;
192 addr
.a6
.sin6_flowinfo
= 0;
193 addr
.a6
.sin6_port
= 1; // Not important, any port will do
194 addr
.a6
.sin6_addr
= *(struct in6_addr
*)&dst
->ip
.v6
;
195 addr
.a6
.sin6_scope_id
= 0;
199 if ((connect(sock
, &addr
.s
, inner_len
)) < 0)
200 { LogMsg("mDNSPlatformSourceAddrForDest: connect %#a failed errno %d (%s)", dst
, errno
, strerror(errno
)); goto exit
; }
202 if ((getsockname(sock
, &addr
.s
, &len
)) < 0)
203 { LogMsg("mDNSPlatformSourceAddrForDest: getsockname failed errno %d (%s)", errno
, strerror(errno
)); goto exit
; }
205 src
->type
= dst
->type
;
206 if (dst
->type
== mDNSAddrType_IPv4
) src
->ip
.v4
.NotAnInteger
= addr
.a4
.sin_addr
.s_addr
;
207 else src
->ip
.v6
= *(mDNSv6Addr
*)&addr
.a6
.sin6_addr
;
212 // dst must be at least MAX_ESCAPED_DOMAIN_NAME bytes, and option must be less than 32 bytes in length
213 mDNSlocal mDNSBool
GetConfigOption(char *dst
, const char *option
, FILE *f
)
215 char buf
[32+1+MAX_ESCAPED_DOMAIN_NAME
]; // Option name, one space, option value
216 size_t len
= strlen(option
);
217 if (len
+ 1 + MAX_ESCAPED_DOMAIN_NAME
> sizeof(buf
)-1) { LogMsg("GetConfigOption: option %s too long", option
); return mDNSfalse
; }
218 fseek(f
, 0, SEEK_SET
); // set position to beginning of stream
219 while (fgets(buf
, sizeof(buf
), f
)) // Read at most sizeof(buf)-1 bytes from file, and append '\0' C-string terminator
221 if (!strncmp(buf
, option
, len
))
223 strncpy(dst
, buf
+ len
+ 1, MAX_ESCAPED_DOMAIN_NAME
-1);
224 if (dst
[MAX_ESCAPED_DOMAIN_NAME
-1]) dst
[MAX_ESCAPED_DOMAIN_NAME
-1] = '\0';
226 if (len
&& dst
[len
-1] == '\n') dst
[len
-1] = '\0'; // chop newline
230 debugf("Option %s not set", option
);
234 mDNSexport
void ReadDDNSSettingsFromConfFile(mDNS
*const m
, const char *const filename
, domainname
*const hostname
, domainname
*const domain
, mDNSBool
*DomainDiscoveryDisabled
)
236 char buf
[MAX_ESCAPED_DOMAIN_NAME
] = "";
238 FILE *f
= fopen(filename
, "r");
240 if (hostname
) hostname
->c
[0] = 0;
241 if (domain
) domain
->c
[0] = 0;
242 if (DomainDiscoveryDisabled
) *DomainDiscoveryDisabled
= mDNSfalse
;
246 if (DomainDiscoveryDisabled
&& GetConfigOption(buf
, "DomainDiscoveryDisabled", f
) && !strcasecmp(buf
, "true")) *DomainDiscoveryDisabled
= mDNStrue
;
247 if (hostname
&& GetConfigOption(buf
, "hostname", f
) && !MakeDomainNameFromDNSNameString(hostname
, buf
)) goto badf
;
248 if (domain
&& GetConfigOption(buf
, "zone", f
) && !MakeDomainNameFromDNSNameString(domain
, buf
)) goto badf
;
250 GetConfigOption(buf
, "secret-64", f
); // failure means no authentication
256 if (errno
!= ENOENT
) LogMsg("ERROR: Config file exists, but cannot be opened.");
260 if (domain
&& domain
->c
[0] && buf
[0])
262 DomainAuthInfo
*info
= (DomainAuthInfo
*) mDNSPlatformMemAllocateClear(sizeof(*info
));
263 // for now we assume keyname = service reg domain and we use same key for service and hostname registration
264 err
= mDNS_SetSecretForDomain(m
, info
, domain
, domain
, buf
, NULL
, 0);
265 if (err
) LogMsg("ERROR: mDNS_SetSecretForDomain returned %d for domain %##s", err
, domain
->c
);
271 LogMsg("ERROR: malformatted config file");
276 mDNSexport
void mDNSPlatformWriteDebugMsg(const char *msg
)
278 fprintf(stderr
,"%s\n", msg
);
283 #if !MDNSRESPONDER_SUPPORTS(APPLE, OS_LOG)
284 mDNSexport
void mDNSPlatformWriteLogMsg(const char *ident
, const char *buffer
, mDNSLogLevel_t loglevel
)
286 #if APPLE_OSX_mDNSResponder && LogTimeStamps
287 extern mDNS mDNSStorage
;
288 extern mDNSu32 mDNSPlatformClockDivisor
;
289 mDNSs32 t
= mDNSStorage
.timenow
? mDNSStorage
.timenow
: mDNSPlatformClockDivisor
? mDNS_TimeNow_NoLock(&mDNSStorage
) : 0;
290 int ms
= ((t
< 0) ? -t
: t
) % 1000;
293 if (mDNS_DebugMode
) // In debug mode we write to stderr
295 #if APPLE_OSX_mDNSResponder && LogTimeStamps
296 if (ident
&& ident
[0] && mDNSPlatformClockDivisor
)
297 fprintf(stderr
,"%8d.%03d: %s\n", (int)(t
/1000), ms
, buffer
);
300 fprintf(stderr
,"%s\n", buffer
);
303 else // else, in production mode, we write to syslog
305 static int log_inited
= 0;
310 case MDNS_LOG_FAULT
: syslog_level
= LOG_ERR
; break;
311 case MDNS_LOG_ERROR
: syslog_level
= LOG_ERR
; break;
312 case MDNS_LOG_WARNING
: syslog_level
= LOG_WARNING
; break;
313 case MDNS_LOG_DEFAULT
: syslog_level
= LOG_NOTICE
; break;
314 case MDNS_LOG_INFO
: syslog_level
= LOG_INFO
; break;
315 case MDNS_LOG_DEBUG
: syslog_level
= LOG_DEBUG
; break;
316 default: syslog_level
= LOG_NOTICE
; break;
319 if (!log_inited
) { openlog(ident
, LOG_CONS
, LOG_DAEMON
); log_inited
++; }
321 #if APPLE_OSX_mDNSResponder && LogTimeStamps
322 if (ident
&& ident
[0] && mDNSPlatformClockDivisor
)
323 syslog(syslog_level
, "%8d.%03d: %s", (int)(t
/1000), ms
, buffer
);
327 syslog(syslog_level
, "%s", buffer
);
331 #endif // !MDNSRESPONDER_SUPPORTS(APPLE, OS_LOG)
333 mDNSexport mDNSBool
mDNSPosixTCPSocketSetup(int *fd
, mDNSAddr_Type addrType
, mDNSIPPort
*port
, mDNSIPPort
*outTcpPort
)
335 int sa_family
= (addrType
== mDNSAddrType_IPv4
) ? AF_INET
: AF_INET6
;
338 mDNSu32 lowWater
= 15384;
340 sock
= socket(sa_family
, SOCK_STREAM
, IPPROTO_TCP
);
343 if (errno
!= EAFNOSUPPORT
)
345 LogMsg("mDNSPosixTCPSocketSetup: socket error %d errno %d (%s)", sock
, errno
, strerror(errno
));
354 struct sockaddr_in sin
;
355 struct sockaddr_in6 sin6
;
357 // If port is not NULL, bind to it.
360 socklen_t len
= (sa_family
== AF_INET
) ? sizeof (struct sockaddr_in
) : sizeof (struct sockaddr_in6
);
361 mDNSPlatformMemZero(&addr
, sizeof addr
);
363 addr
.sa
.sa_family
= sa_family
;
364 #ifndef NOT_HAVE_SA_LEN
365 addr
.sa
.sa_len
= len
;
367 if (sa_family
== AF_INET6
)
369 addr
.sin6
.sin6_port
= port
->NotAnInteger
;
373 addr
.sin
.sin_port
= port
->NotAnInteger
;
375 err
= bind(sock
, &addr
.sa
, len
);
378 LogMsg("mDNSPosixTCPSocketSetup getsockname: %s", strerror(errno
));
383 socklen_t addrlen
= sizeof addr
;
384 err
= getsockname(sock
, (struct sockaddr
*)&addr
, &addrlen
);
387 LogMsg("mDNSPosixTCPSocketSetup getsockname: %s", strerror(errno
));
390 if (sa_family
== AF_INET6
)
392 outTcpPort
->NotAnInteger
= addr
.sin6
.sin6_port
;
396 outTcpPort
->NotAnInteger
= addr
.sin
.sin_port
;
399 port
->NotAnInteger
= outTcpPort
->NotAnInteger
;
401 err
= setsockopt(sock
, IPPROTO_TCP
, TCP_NOTSENT_LOWAT
, &lowWater
, sizeof lowWater
);
404 LogMsg("mDNSPosixTCPSocketSetup: TCP_NOTSENT_LOWAT failed: %s", strerror(errno
));
411 mDNSexport TCPSocket
*mDNSPosixDoTCPListenCallback(int fd
, mDNSAddr_Type addressType
, TCPSocketFlags socketFlags
,
412 TCPAcceptedCallback callback
, void *context
)
416 struct sockaddr_in6 sin6
;
417 struct sockaddr_in sin
;
421 socklen_t slen
= sizeof address
;
425 TCPSocket
*sock
= mDNSNULL
;
429 mDNSu32 lowWater
= 16384;
430 // When we remember our connection, we remember a name that we can print for logging. But
431 // since we are the listener in this case, we don't /have/ a name for it. This buffer
432 // is used to print the IP address into a human readable string which will serve that purpose
434 char namebuf
[INET6_ADDRSTRLEN
+ 1 + 5 + 1];
436 remoteSock
= accept(fd
, &address
.sa
, &slen
);
439 LogMsg("mDNSPosixDoTCPListenCallback: accept returned %d", remoteSock
);
443 failed
= fcntl(remoteSock
, F_SETFL
, O_NONBLOCK
);
447 LogMsg("mDNSPosixDoTCPListenCallback: fcntl returned %d", errno
);
451 failed
= setsockopt(remoteSock
, IPPROTO_TCP
, TCP_NOTSENT_LOWAT
,
452 &lowWater
, sizeof lowWater
);
456 LogMsg("mDNSPosixDoTCPListenCallback: TCP_NOTSENT_LOWAT returned %d", errno
);
460 if (address
.sa
.sa_family
== AF_INET6
)
462 // If we are listening on an IPv4/IPv6 socket, the incoming address might be an IPv4-in-IPv6 address
463 for (i
= 0; i
< 10; i
++)
465 if (address
.sin6
.sin6_addr
.s6_addr
[i
] != 0)
467 addr
.type
= mDNSAddrType_IPv6
;
472 // a legit IPv4 address would be ::ffff:a.b.c.d; if there's no ::ffff bit, then it's an IPv6
473 // address with a really weird prefix.
474 if (address
.sin6
.sin6_addr
.s6_addr
[10] != 0xFF || address
.sin6
.sin6_addr
.s6_addr
[11] != 0xFF)
476 addr
.type
= mDNSAddrType_IPv6
;
477 } else if (addressType
!= mDNSAddrType_None
)
479 if (inet_ntop(AF_INET
, &address
.sin6
.sin6_addr
.s6_addr
[12], namebuf
, INET6_ADDRSTRLEN
+ 1) == NULL
)
481 strcpy(namebuf
, ":unknown:");
483 LogMsg("mDNSPosixDoTCPListenCallback received an IPv4 connection from %s on an IPv6-only socket.",
490 addr
.type
= mDNSAddrType_IPv4
;
493 if (addr
.type
== mDNSAddrType_IPv6
)
495 if (inet_ntop(address
.sin6
.sin6_family
, &address
.sin6
.sin6_addr
, namebuf
, INET6_ADDRSTRLEN
+ 1) == NULL
)
497 strcpy(namebuf
, ":unknown:");
499 memcpy(&addr
.ip
.v6
, &address
.sin6
.sin6_addr
, sizeof addr
.ip
.v6
);
503 if (inet_ntop(AF_INET
, &address
.sin6
.sin6_addr
.s6_addr
[12], namebuf
, INET6_ADDRSTRLEN
+ 1) == NULL
)
505 strcpy(namebuf
, ":unknown:");
507 memcpy(&addr
.ip
.v4
, &address
.sin6
.sin6_addr
.s6_addr
[12], sizeof addr
.ip
.v4
);
509 port
.NotAnInteger
= address
.sin6
.sin6_port
;
511 else if (address
.sa
.sa_family
== AF_INET
)
513 addr
.type
= mDNSAddrType_IPv4
;
514 memcpy(&addr
.ip
.v4
, &address
.sin
.sin_addr
, sizeof addr
.ip
.v4
);
515 port
.NotAnInteger
= address
.sin
.sin_port
;
516 if (inet_ntop(AF_INET
, &address
.sin
.sin_addr
, namebuf
, INET6_ADDRSTRLEN
+ 1) == NULL
)
518 strcpy(namebuf
, ":unknown:");
521 LogMsg("mDNSPosixDoTCPListenCallback: connection from unknown address family %d", address
.sa
.sa_family
);
525 nbp
= namebuf
+ strlen(namebuf
);
527 snprintf(nbp
, 6, "%u", ntohs(port
.NotAnInteger
));
529 sock
= mDNSPlatformTCPAccept(socketFlags
, remoteSock
);
532 LogMsg("mDNSPosixDoTCPListenCallback: mDNSPlatformTCPAccept returned NULL; dropping connection from %s",
537 callback(sock
, &addr
, &port
, namebuf
, context
);
542 mDNSexport mDNSBool
mDNSPosixTCPListen(int *fd
, mDNSAddr_Type addrtype
, mDNSIPPort
*port
, mDNSAddr
*addr
,
543 mDNSBool reuseAddr
, int queueLength
)
548 struct sockaddr_in6 sin6
;
549 struct sockaddr_in sin
;
558 // We require an addrtype parameter because addr is allowed to be null, but they have to agree.
559 if (addr
!= mDNSNULL
&& addr
->type
!= addrtype
)
561 LogMsg("mDNSPlatformTCPListen: address type conflict: %d:%d", addr
->type
, addrtype
);
564 if (port
== mDNSNULL
)
566 LogMsg("mDNSPlatformTCPListen: port must not be NULL");
570 mDNSPlatformMemZero(&address
, sizeof address
);
571 if (addrtype
== mDNSAddrType_None
|| addrtype
== mDNSAddrType_IPv6
)
573 // Set up DNS listener socket
574 if (addr
!= mDNSNULL
)
576 memcpy(&address
.sin6
.sin6_addr
.s6_addr
, &addr
->ip
, sizeof address
.sin6
.sin6_addr
.s6_addr
);
578 address
.sin6
.sin6_port
= port
->NotAnInteger
;
580 sock_len
= sizeof address
.sin6
;
581 address
.sin6
.sin6_family
= AF_INET6
;
583 else if (addrtype
== mDNSAddrType_IPv4
)
585 if (addr
!= mDNSNULL
)
587 memcpy(&address
.sin
.sin_addr
.s_addr
, &addr
->ip
, sizeof address
.sin
.sin_addr
.s_addr
);
589 address
.sin
.sin_port
= port
->NotAnInteger
;
590 sock_len
= sizeof address
.sin
;
591 address
.sin
.sin_family
= AF_INET
;
595 LogMsg("mDNSPlatformTCPListen: invalid address type: %d", addrtype
);
598 #ifndef NOT_HAVE_SA_LEN
599 address
.sa
.sa_len
= sock_len
;
601 sock
= socket(address
.sa
.sa_family
, SOCK_STREAM
, IPPROTO_TCP
);
605 LogMsg("mDNSPlatformTCPListen: socket call failed: %s", strerror(errno
));
610 // The reuseAddr flag is used to indicate that we want to listen on this port even if
611 // there are still lingering sockets. We will still fail if there is another listener.
612 // Note that this requires SO_REUSEADDR, not SO_REUSEPORT, which does not have special
613 // handling for lingering sockets.
616 failed
= setsockopt(sock
, SOL_SOCKET
, SO_REUSEADDR
, &one
, sizeof one
);
619 LogMsg("mDNSPlatformTCPListen: SO_REUSEADDR failed %s", strerror(errno
));
624 // Bind to the port and (if provided) address
625 failed
= bind(sock
, &address
.sa
, sock_len
);
628 LogMsg("mDNSPlatformTCPListen: bind failed %s", strerror(errno
));
632 // If there was no specified listen port, we need to know what port we got.
633 if (port
->NotAnInteger
== 0)
635 mDNSPlatformMemZero(&address
, sizeof address
);
636 failed
= getsockname(sock
, &address
.sa
, &sock_len
);
639 LogMsg("mDNSRelay: getsockname failed: %s", strerror(errno
));
642 if (address
.sa
.sa_family
== AF_INET
)
644 port
->NotAnInteger
= address
.sin
.sin_port
;
648 port
->NotAnInteger
= address
.sin6
.sin6_port
;
652 failed
= listen(sock
, queueLength
);
655 LogMsg("mDNSPlatformTCPListen: listen failed: %s", strerror(errno
));
661 mDNSexport
long mDNSPosixReadTCP(int fd
, void *buf
, unsigned long buflen
, mDNSBool
*closed
)
663 static int CLOSEDcount
= 0;
664 static int EAGAINcount
= 0;
665 ssize_t nread
= recv(fd
, buf
, buflen
, 0);
671 } // On success, clear our error counters
675 if ((++CLOSEDcount
% 20) == 0)
677 LogMsg("ERROR: mDNSPosixReadFromSocket - recv %d got CLOSED %d times", fd
, CLOSEDcount
);
678 assert(CLOSEDcount
< 1000);
679 // Recovery Mechanism to bail mDNSResponder out of trouble: Instead of logging the same error
680 // msg multiple times, crash mDNSResponder using assert() and restart fresh. See advantages
682 // 1.Better User Experience
683 // 2.CrashLogs frequency can be monitored
684 // 3.StackTrace can be used for more info
687 // else nread is negative -- see what kind of error we got
688 else if (errno
== ECONNRESET
)
690 nread
= 0; *closed
= mDNStrue
;
692 else if (errno
!= EAGAIN
)
694 LogMsg("ERROR: mDNSPosixReadFromSocket - recv: %d (%s)", errno
, strerror(errno
));
698 { // errno is EAGAIN (EWOULDBLOCK) -- no data available
700 if ((++EAGAINcount
% 1000) == 0)
702 LogMsg("ERROR: mDNSPosixReadFromSocket - recv %d got EAGAIN %d times", fd
, EAGAINcount
);
709 mDNSexport
long mDNSPosixWriteTCP(int fd
, const char *msg
, unsigned long len
)
714 result
= write(fd
, msg
, len
);
723 LogMsg("ERROR: mDNSPosixWriteTCP - send %s", strerror(errno
)); nsent
= -1;
728 nsent
= (long)result
;