#ifdef _WIN32 #define HT_NO_CACHE_HASH_VALUES #include"ht-internal.h" #define open _open #define read _read #define close _close #ifndef fstat #define fstat _fstati64 #endif #ifndef stat #define stat _stati64 #endif #define mode_t int #endif
int
evutil_open_closeonexec_(constchar *pathname, int flags, unsigned mode)
{ int fd;
#ifdef O_CLOEXEC
fd = open(pathname, flags|O_CLOEXEC, (mode_t)mode); if (fd >= 0 || errno == EINVAL) return fd; /* If we got an EINVAL, fall through and try without O_CLOEXEC */ #endif
fd = open(pathname, flags, (mode_t)mode); if (fd < 0) return -1;
int
evutil_socketpair(int family, int type, int protocol, evutil_socket_t fd[2])
{ #ifndef _WIN32 return socketpair(family, type, protocol, fd); #else return evutil_ersatz_socketpair_(family, type, protocol, fd); #endif
}
int
evutil_ersatz_socketpair_(int family, int type, int protocol,
evutil_socket_t fd[2])
{ /* This code is originally from Tor. Used with permission. */
/* This socketpair does not work when localhost is down. So *it'sreallynotthesamethingatall.Butit'scloseenough *fornow,andreally,whenlocalhostisdownsometimes,we *haveotherproblemstoo.
*/ #ifdef _WIN32 #define ERR(e) WSA##e #else #define ERR(e) e #endif
evutil_socket_t listener = -1;
evutil_socket_t connector = -1;
evutil_socket_t acceptor = -1; struct sockaddr_in listen_addr; struct sockaddr_in connect_addr;
ev_socklen_t size; int saved_errno = -1; int family_test;
/* We want to find out the port number to connect to. */
size = sizeof(connect_addr); if (getsockname(listener, (struct sockaddr *) &connect_addr, &size) == -1) goto tidy_up_and_fail; if (size != sizeof (connect_addr)) goto abort_tidy_up_and_fail; if (connect(connector, (struct sockaddr *) &connect_addr, sizeof(connect_addr)) == -1) goto tidy_up_and_fail;
size = sizeof(listen_addr);
acceptor = accept(listener, (struct sockaddr *) &listen_addr, &size); if (acceptor < 0) goto tidy_up_and_fail; if (size != sizeof(listen_addr)) goto abort_tidy_up_and_fail; /* Now check we are talking to ourself by matching port and host on the
two sockets. */ if (getsockname(connector, (struct sockaddr *) &connect_addr, &size) == -1) goto tidy_up_and_fail; if (size != sizeof (connect_addr)
|| listen_addr.sin_family != connect_addr.sin_family
|| listen_addr.sin_addr.s_addr != connect_addr.sin_addr.s_addr
|| listen_addr.sin_port != connect_addr.sin_port) goto abort_tidy_up_and_fail;
evutil_closesocket(listener);
fd[0] = connector;
fd[1] = acceptor;
return0;
abort_tidy_up_and_fail:
saved_errno = ERR(ECONNABORTED);
tidy_up_and_fail: if (saved_errno < 0)
saved_errno = EVUTIL_SOCKET_ERROR(); if (listener != -1)
evutil_closesocket(listener); if (connector != -1)
evutil_closesocket(connector); if (acceptor != -1)
evutil_closesocket(acceptor);
/* Faster version of evutil_make_socket_nonblocking for internal use. * *RequiresthatnoF_SETFLflagswerepreviouslysetonthefd.
*/ staticint
evutil_fast_socket_nonblocking(evutil_socket_t fd)
{ #ifdef _WIN32 return evutil_make_socket_nonblocking(fd); #else if (fcntl(fd, F_SETFL, O_NONBLOCK) == -1) {
event_warn("fcntl(%d, F_SETFL)", fd); return -1;
} return0; #endif
}
int
evutil_make_listen_socket_reuseable(evutil_socket_t sock)
{ #ifdefined(SO_REUSEADDR) && !defined(_WIN32) int one = 1; /* REUSEADDR on Unix means, "don't hang on to this address after the *listenerisclosed."OnWindows,though,itmeans"don'tkeepother
* processes from binding to this address while we're using it. */ return setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void*) &one,
(ev_socklen_t)sizeof(one)); #else return0; #endif
}
int
evutil_make_listen_socket_reuseable_port(evutil_socket_t sock)
{ #ifdefined __linux__ && defined(SO_REUSEPORT) int one = 1; /* REUSEPORT on Linux 3.9+ means, "Multiple servers (processes or
* threads) can bind to the same port if they each set the option. */ return setsockopt(sock, SOL_SOCKET, SO_REUSEPORT, (void*) &one,
(ev_socklen_t)sizeof(one)); #else return0; #endif
}
int
evutil_make_listen_socket_ipv6only(evutil_socket_t sock)
{ #ifdefined(IPV6_V6ONLY) int one = 1; return setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, (void*) &one,
(ev_socklen_t)sizeof(one)); #endif return0;
}
int
evutil_make_tcp_listen_socket_deferred(evutil_socket_t sock)
{ #ifdefined(EVENT__HAVE_NETINET_TCP_H) && defined(TCP_DEFER_ACCEPT) int one = 1;
/* TCP_DEFER_ACCEPT tells the kernel to call defer accept() only after data
* has arrived and ready to read */ return setsockopt(sock, IPPROTO_TCP, TCP_DEFER_ACCEPT, &one,
(ev_socklen_t)sizeof(one)); #endif return0;
}
int
evutil_make_socket_closeonexec(evutil_socket_t fd)
{ #if !defined(_WIN32) && defined(EVENT__HAVE_SETFD) int flags; if ((flags = fcntl(fd, F_GETFD, NULL)) < 0) {
event_warn("fcntl(%d, F_GETFD)", fd); return -1;
} if (!(flags & FD_CLOEXEC)) { if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) == -1) {
event_warn("fcntl(%d, F_SETFD)", fd); return -1;
}
} #endif return0;
}
/* Faster version of evutil_make_socket_closeonexec for internal use. * *RequiresthatnoF_SETFDflagswerepreviouslysetonthefd.
*/ staticint
evutil_fast_socket_closeonexec(evutil_socket_t fd)
{ #if !defined(_WIN32) && defined(EVENT__HAVE_SETFD) if (fcntl(fd, F_SETFD, FD_CLOEXEC) == -1) {
event_warn("fcntl(%d, F_SETFD)", fd); return -1;
} #endif return0;
}
ev_int64_t
evutil_strtoll(constchar *s, char **endptr, int base)
{ #ifdef EVENT__HAVE_STRTOLL return (ev_int64_t)strtoll(s, endptr, base); #elif EVENT__SIZEOF_LONG == 8 return (ev_int64_t)strtol(s, endptr, base); #elifdefined(_WIN32) && defined(_MSC_VER) && _MSC_VER < 1300 /* XXXX on old versions of MS APIs, we only support base
* 10. */
ev_int64_t r; if (base != 10) return0;
r = (ev_int64_t) _atoi64(s); while (isspace(*s))
++s; if (*s == '-')
++s; while (isdigit(*s))
++s; if (endptr)
*endptr = (char*) s; return r; #elifdefined(_WIN32) return (ev_int64_t) _strtoi64(s, endptr, base); #elifdefined(EVENT__SIZEOF_LONG_LONG) && EVENT__SIZEOF_LONG_LONG == 8 longlong r; int n; if (base != 10 && base != 16) return0; if (base == 10) {
n = sscanf(s, "%lld", &r);
} else { unsignedlonglong ru=0;
n = sscanf(s, "%llx", &ru); if (ru > EV_INT64_MAX) return0;
r = (longlong) ru;
} if (n != 1) return0; while (EVUTIL_ISSPACE_(*s))
++s; if (*s == '-')
++s; if (base == 10) { while (EVUTIL_ISDIGIT_(*s))
++s;
} else { while (EVUTIL_ISXDIGIT_(*s))
++s;
} if (endptr)
*endptr = (char*) s; return r; #else #error"I don't know how to parse 64-bit integers." #endif
}
#ifdef _WIN32 int
evutil_socket_geterror(evutil_socket_t sock)
{ int optval, optvallen=sizeof(optval); int err = WSAGetLastError(); if (err == WSAEWOULDBLOCK && sock >= 0) { if (getsockopt(sock, SOL_SOCKET, SO_ERROR, (void*)&optval,
&optvallen)) return err; if (optval) return optval;
} return err;
} #endif
/* XXX we should use an enum here. */ /* 2 for connection refused, 1 for connected, 0 for not yet, -1 for error. */ int
evutil_socket_connect_(evutil_socket_t *fd_ptr, conststruct sockaddr *sa, int socklen)
{ int made_fd = 0;
if (*fd_ptr < 0) { if ((*fd_ptr = socket(sa->sa_family, SOCK_STREAM, 0)) < 0) goto err;
made_fd = 1; if (evutil_make_socket_nonblocking(*fd_ptr) < 0) { goto err;
}
}
if (connect(*fd_ptr, sa, socklen) < 0) { int e = evutil_socket_geterror(*fd_ptr); if (EVUTIL_ERR_CONNECT_RETRIABLE(e)) return0; if (EVUTIL_ERR_CONNECT_REFUSED(e)) return2; goto err;
} else { return1;
}
/* Check whether a socket on which we called connect() is done connecting.Return1forconnected,0fornotyet,-1forerror.Inthe errorcase,setthecurrentsocketerrnototheerrorthathappenedduring
the connect operation. */ int
evutil_socket_finished_connecting_(evutil_socket_t fd)
{ int e;
ev_socklen_t elen = sizeof(e);
if (getsockopt(fd, SOL_SOCKET, SO_ERROR, (void*)&e, &elen) < 0) return -1;
if (e) { if (EVUTIL_ERR_CONNECT_RETRIABLE(e)) return0;
EVUTIL_SET_SOCKET_ERROR(e); return -1;
}
return1;
}
#if (EVUTIL_AI_PASSIVE|EVUTIL_AI_CANONNAME|EVUTIL_AI_NUMERICHOST| \
EVUTIL_AI_NUMERICSERV|EVUTIL_AI_V4MAPPED|EVUTIL_AI_ALL| \
EVUTIL_AI_ADDRCONFIG) != \
(EVUTIL_AI_PASSIVE^EVUTIL_AI_CANONNAME^EVUTIL_AI_NUMERICHOST^ \
EVUTIL_AI_NUMERICSERV^EVUTIL_AI_V4MAPPED^EVUTIL_AI_ALL^ \
EVUTIL_AI_ADDRCONFIG) #error"Some of our EVUTIL_AI_* flags seem to overlap with system AI_* flags" #endif
/* We sometimes need to know whether we have an ipv4 address and whether we haveanipv6address.If'have_checked_interfaces',thenwe'vealreadydone thetest.If'had_ipv4_address',thenitturnsoutwehadanipv4address. If'had_ipv6_address',thenitturnsoutwehadanipv6address.Theseare
set by evutil_check_interfaces. */ staticint have_checked_interfaces, had_ipv4_address, had_ipv6_address;
/* True iff the IPv4 address 'addr', in host order, is in 127.0.0.0/8 */ staticinlineint evutil_v4addr_is_localhost(ev_uint32_t addr)
{ return addr>>24 == 127; }
/* True iff the IPv4 address 'addr', in host order, is link-local
* 169.254.0.0/16 (RFC3927) */ staticinlineint evutil_v4addr_is_linklocal(ev_uint32_t addr)
{ return ((addr & 0xffff0000U) == 0xa9fe0000U); }
/* True iff the IPv4 address 'addr', in host order, is a class D
* (multiclass) address. */ staticinlineint evutil_v4addr_is_classd(ev_uint32_t addr)
{ return ((addr>>24) & 0xf0) == 0xe0; }
staticint
evutil_check_ifaddrs(void)
{ #ifdefined(EVENT__HAVE_GETIFADDRS) /* Most free Unixy systems provide getifaddrs, which gives us a linked list
* of struct ifaddrs. */ struct ifaddrs *ifa = NULL; conststruct ifaddrs *i; if (getifaddrs(&ifa) < 0) {
event_warn("Unable to call getifaddrs()"); return -1;
}
for (i = ifa; i; i = i->ifa_next) { if (!i->ifa_addr) continue;
evutil_found_ifaddr(i->ifa_addr);
}
freeifaddrs(ifa); return0; #elifdefined(_WIN32) /* Windows XP began to provide GetAdaptersAddresses. Windows 2000 had a "GetAdaptersInfo",butthat'sdeprecated;let'sjusttry GetAdaptersAddressesandfallbacktoconnect+getsockname.
*/
HMODULE lib = evutil_load_windows_system_library_(TEXT("iphlpapi.dll"));
GetAdaptersAddresses_fn_t fn;
ULONG size, res;
IP_ADAPTER_ADDRESSES *addresses = NULL, *address; int result = -1;
if (!(fn = (GetAdaptersAddresses_fn_t) GetProcAddress(lib, "GetAdaptersAddresses"))) goto done;
/* Guess how much space we need. */
size = 15*1024;
addresses = mm_malloc(size); if (!addresses) goto done;
res = fn(AF_UNSPEC, FLAGS, NULL, addresses, &size); if (res == ERROR_BUFFER_OVERFLOW) { /* we didn't guess that we needed enough space; try again */
mm_free(addresses);
addresses = mm_malloc(size); if (!addresses) goto done;
res = fn(AF_UNSPEC, FLAGS, NULL, addresses, &size);
} if (res != NO_ERROR) goto done;
for (address = addresses; address; address = address->Next) {
IP_ADAPTER_UNICAST_ADDRESS *a; for (a = address->FirstUnicastAddress; a; a = a->Next) { /* Yes, it's a linked list inside a linked list */ struct sockaddr *sa = a->Address.lpSockaddr;
evutil_found_ifaddr(sa);
}
}
result = 0;
done: if (lib)
FreeLibrary(lib); if (addresses)
mm_free(addresses); return result; #else return -1; #endif
}
/* Test whether we have an ipv4 interface and an ipv6 interface. Return 0 if
* the test seemed successful. */ staticint
evutil_check_interfaces(void)
{
evutil_socket_t fd = -1; struct sockaddr_in sin, sin_out; struct sockaddr_in6 sin6, sin6_out;
ev_socklen_t sin_out_len = sizeof(sin_out);
ev_socklen_t sin6_out_len = sizeof(sin6_out); int r; if (have_checked_interfaces) return0;
/* From this point on we have done the ipv4/ipv6 interface check */
have_checked_interfaces = 1;
if (evutil_check_ifaddrs() == 0) { /* Use a nice sane interface, if this system has one. */ return0;
}
/* Ugh. There was no nice sane interface. So to check whether we have *aninterfaceopenforagivenprotocol,willtrytomakeaUDP *'connection'toaremotehostontheinternet.Wedon'tactually *useit,sotheaddressdoesn'tmatter,butwewanttopickonethat
* keep us from using a host- or link-local interface. */
memset(&sin, 0, sizeof(sin));
sin.sin_family = AF_INET;
sin.sin_port = htons(53);
r = evutil_inet_pton(AF_INET, "18.244.0.188", &sin.sin_addr);
EVUTIL_ASSERT(r);
/* XXX some errnos mean 'no address'; some mean 'not enough sockets'. */ if ((fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) >= 0 &&
connect(fd, (struct sockaddr*)&sin, sizeof(sin)) == 0 &&
getsockname(fd, (struct sockaddr*)&sin_out, &sin_out_len) == 0) { /* We might have an IPv4 interface. */
evutil_found_ifaddr((struct sockaddr*) &sin_out);
} if (fd >= 0)
evutil_closesocket(fd);
if ((fd = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP)) >= 0 &&
connect(fd, (struct sockaddr*)&sin6, sizeof(sin6)) == 0 &&
getsockname(fd, (struct sockaddr*)&sin6_out, &sin6_out_len) == 0) { /* We might have an IPv6 interface. */
evutil_found_ifaddr((struct sockaddr*) &sin6_out);
}
if (fd >= 0)
evutil_closesocket(fd);
return0;
}
/* Internal addrinfo flag. This one is set when we allocate the addrinfo from *insidelibevent.Otherwise,thebuilt-ingetaddrinfo()functionallocated *it,andweshouldtrustwhattheysaid.
**/ #define EVUTIL_AI_LIBEVENT_ALLOCATED 0x80000000
/* Helper: construct a new addrinfo containing the socket address in *'sa',whichmustbeasockaddr_inorasockaddr_in6.Takethe *socktypeandprotocolinfofromhints.Iftheyweren'tset,then *allocatebothaTCPandaUDPaddrinfo.
*/ struct evutil_addrinfo *
evutil_new_addrinfo_(struct sockaddr *sa, ev_socklen_t socklen, conststruct evutil_addrinfo *hints)
{ struct evutil_addrinfo *res;
EVUTIL_ASSERT(hints);
if (hints->ai_socktype == 0 && hints->ai_protocol == 0) { /* Indecisive user! Give them a UDP and a TCP. */ struct evutil_addrinfo *r1, *r2; struct evutil_addrinfo tmp;
memcpy(&tmp, hints, sizeof(tmp));
tmp.ai_socktype = SOCK_STREAM; tmp.ai_protocol = IPPROTO_TCP;
r1 = evutil_new_addrinfo_(sa, socklen, &tmp); if (!r1) return NULL;
tmp.ai_socktype = SOCK_DGRAM; tmp.ai_protocol = IPPROTO_UDP;
r2 = evutil_new_addrinfo_(sa, socklen, &tmp); if (!r2) {
evutil_freeaddrinfo(r1); return NULL;
}
r1->ai_next = r2; return r1;
}
/* We're going to allocate extra space to hold the sockaddr. */
res = mm_calloc(1,sizeof(struct evutil_addrinfo)+socklen); if (!res) return NULL;
res->ai_addr = (struct sockaddr*)
(((char*)res) + sizeof(struct evutil_addrinfo));
memcpy(res->ai_addr, sa, socklen);
res->ai_addrlen = socklen;
res->ai_family = sa->sa_family; /* Same or not? XXX */
res->ai_flags = EVUTIL_AI_LIBEVENT_ALLOCATED;
res->ai_socktype = hints->ai_socktype;
res->ai_protocol = hints->ai_protocol;
return res;
}
/* Append the addrinfo 'append' to the end of 'first', and return the start of *thelist.EitherelementcanbeNULL,inwhichcasewereturntheelement
* that is not NULL. */ struct evutil_addrinfo *
evutil_addrinfo_append_(struct evutil_addrinfo *first, struct evutil_addrinfo *append)
{ struct evutil_addrinfo *ai = first; if (!ai) return append; while (ai->ai_next)
ai = ai->ai_next;
ai->ai_next = append;
return first;
}
staticint
parse_numeric_servname(constchar *servname)
{ int n; char *endptr=NULL;
n = (int) strtol(servname, &endptr, 10); if (n>=0 && n <= 65535 && servname[0] && endptr && !endptr[0]) return n; else return -1;
}
/** Parse a service name in 'servname', which can be a decimal port. *Returntheportnumber,or-1onerror.
*/ staticint
evutil_parse_servname(constchar *servname, constchar *protocol, conststruct evutil_addrinfo *hints)
{ int n = parse_numeric_servname(servname); if (n>=0) return n; #ifdefined(EVENT__HAVE_GETSERVBYNAME) || defined(_WIN32) if (!(hints->ai_flags & EVUTIL_AI_NUMERICSERV)) { struct servent *ent = getservbyname(servname, protocol); if (ent) { return ntohs(ent->s_port);
}
} #endif return -1;
}
/* Return a string corresponding to a protocol number that we can pass to
* getservyname. */ staticconstchar *
evutil_unparse_protoname(int proto)
{ switch (proto) { case0: return NULL; case IPPROTO_TCP: return"tcp"; case IPPROTO_UDP: return"udp"; #ifdef IPPROTO_SCTP case IPPROTO_SCTP: return"sctp"; #endif default: #ifdef EVENT__HAVE_GETPROTOBYNUMBER
{ struct protoent *ent = getprotobynumber(proto); if (ent) return ent->p_name;
} #endif return NULL;
}
}
staticvoid
evutil_getaddrinfo_infer_protocols(struct evutil_addrinfo *hints)
{ /* If we can guess the protocol from the socktype, do so. */ if (!hints->ai_protocol && hints->ai_socktype) { if (hints->ai_socktype == SOCK_DGRAM)
hints->ai_protocol = IPPROTO_UDP; elseif (hints->ai_socktype == SOCK_STREAM)
hints->ai_protocol = IPPROTO_TCP;
}
/* Set the socktype if it isn't set. */ if (!hints->ai_socktype && hints->ai_protocol) { if (hints->ai_protocol == IPPROTO_UDP)
hints->ai_socktype = SOCK_DGRAM; elseif (hints->ai_protocol == IPPROTO_TCP)
hints->ai_socktype = SOCK_STREAM; #ifdef IPPROTO_SCTP elseif (hints->ai_protocol == IPPROTO_SCTP)
hints->ai_socktype = SOCK_STREAM; #endif
}
}
#if AF_UNSPEC != PF_UNSPEC #error"I cannot build on a system where AF_UNSPEC != PF_UNSPEC" #endif
/** Implements the part of looking up hosts by name that's common to both *theblockingandnonblockingresolver: *-Adjust'hints'tohaveareasonablesocktypeandprotocol. *-Lookuptheportbasedon'servname',andstoreitin*portnum, *-Handlethenodename==NULLcase *-Handlesomeinvalidargumentscases. *-HandlethecaseswherenodenameisanIPv4orIPv6address. * *Ifweneedtheresolvertolookupthehostname,wereturn *EVUTIL_EAI_NEED_RESOLVE.Otherwise,wecancompletelyimplement *getaddrinfo:wereturn0oranappropriateEVUTIL_EAI_*error,and *set*resasgetaddrinfowould.
*/ int
evutil_getaddrinfo_common_(constchar *nodename, constchar *servname, struct evutil_addrinfo *hints, struct evutil_addrinfo **res, int *portnum)
{ int port = 0; unsignedint if_index; constchar *pname;
if (nodename == NULL && servname == NULL) return EVUTIL_EAI_NONAME;
/* We only understand 3 families */ if (hints->ai_family != PF_UNSPEC && hints->ai_family != PF_INET &&
hints->ai_family != PF_INET6) return EVUTIL_EAI_FAMILY;
evutil_getaddrinfo_infer_protocols(hints);
/* Look up the port number and protocol, if possible. */
pname = evutil_unparse_protoname(hints->ai_protocol); if (servname) { /* XXXX We could look at the protocol we got back from
* getservbyname, but it doesn't seem too useful. */
port = evutil_parse_servname(servname, pname, hints); if (port < 0) { return EVUTIL_EAI_NONAME;
}
}
/* If we have no node name, then we're supposed to bind to 'any' and
* connect to localhost. */ if (nodename == NULL) { struct evutil_addrinfo *res4=NULL, *res6=NULL; if (hints->ai_family != PF_INET) { /* INET6 or UNSPEC. */ struct sockaddr_in6 sin6;
memset(&sin6, 0, sizeof(sin6));
sin6.sin6_family = AF_INET6;
sin6.sin6_port = htons(port); if (hints->ai_flags & EVUTIL_AI_PASSIVE) { /* Bind to :: */
} else { /* connect to ::1 */
sin6.sin6_addr.s6_addr[15] = 1;
}
res6 = evutil_new_addrinfo_((struct sockaddr*)&sin6, sizeof(sin6), hints); if (!res6) return EVUTIL_EAI_MEMORY;
}
if (hints->ai_family != PF_INET6) { /* INET or UNSPEC */ struct sockaddr_in sin;
memset(&sin, 0, sizeof(sin));
sin.sin_family = AF_INET;
sin.sin_port = htons(port); if (hints->ai_flags & EVUTIL_AI_PASSIVE) { /* Bind to 0.0.0.0 */
} else { /* connect to 127.0.0.1 */
sin.sin_addr.s_addr = htonl(0x7f000001);
}
res4 = evutil_new_addrinfo_((struct sockaddr*)&sin, sizeof(sin), hints); if (!res4) { if (res6)
evutil_freeaddrinfo(res6); return EVUTIL_EAI_MEMORY;
}
}
*res = evutil_addrinfo_append_(res4, res6); return0;
}
/* If we can, we should try to parse the hostname without resolving
* it. */ /* Try ipv6. */ if (hints->ai_family == PF_INET6 || hints->ai_family == PF_UNSPEC) { struct sockaddr_in6 sin6;
memset(&sin6, 0, sizeof(sin6)); if (1 == evutil_inet_pton_scope(
AF_INET6, nodename, &sin6.sin6_addr, &if_index)) { /* Got an ipv6 address. */
sin6.sin6_family = AF_INET6;
sin6.sin6_port = htons(port);
sin6.sin6_scope_id = if_index;
*res = evutil_new_addrinfo_((struct sockaddr*)&sin6, sizeof(sin6), hints); if (!*res) return EVUTIL_EAI_MEMORY; return0;
}
}
/* If we have reached this point, we definitely need to do a DNS
* lookup. */ if ((hints->ai_flags & EVUTIL_AI_NUMERICHOST)) { /* If we're not allowed to do one, then say so. */ return EVUTIL_EAI_NONAME;
}
*portnum = port; return EVUTIL_EAI_NEED_RESOLVE;
}
#ifndef USE_NATIVE_GETADDRINFO /* Helper for systems with no getaddrinfo(): make one or more addrinfos out of *astructhostent.
*/ staticstruct evutil_addrinfo *
addrinfo_from_hostent(conststruct hostent *ent, int port, conststruct evutil_addrinfo *hints)
{ int i; struct sockaddr_in sin; struct sockaddr_in6 sin6; struct sockaddr *sa; int socklen; struct evutil_addrinfo *res=NULL, *ai; void *addrp;
/* If the EVUTIL_AI_ADDRCONFIG flag is set on hints->ai_flags, and *hints->ai_familyisPF_UNSPEC,thenrevisethevalueofhints->ai_familyso *thatwe'llonlygetaddresseswecouldmaybeconnectto.
*/ void
evutil_adjust_hints_for_addrconfig_(struct evutil_addrinfo *hints)
{ if (!(hints->ai_flags & EVUTIL_AI_ADDRCONFIG)) return; if (hints->ai_family != PF_UNSPEC) return;
evutil_check_interfaces(); if (had_ipv4_address && !had_ipv6_address) {
hints->ai_family = PF_INET;
} elseif (!had_ipv4_address && had_ipv6_address) {
hints->ai_family = PF_INET6;
}
}
/* Some older BSDs (like OpenBSD up to 4.6) used to believe that givinganumericportwithoutgivinganai_socktypewasverboten. Wetestforthissowecanapplyanappropriateworkaround.Ifit turnsoutthatthebugispresent,then:
if (ai)
freeaddrinfo(ai); if (ai2)
freeaddrinfo(ai2); if (ai3)
freeaddrinfo(ai3);
tested_for_getaddrinfo_hacks=1;
}
staticinlineint
need_numeric_port_hack(void)
{ if (!tested_for_getaddrinfo_hacks)
test_for_getaddrinfo_hacks(); return need_numeric_port_hack_;
}
staticinlineint
need_socktype_protocol_hack(void)
{ if (!tested_for_getaddrinfo_hacks)
test_for_getaddrinfo_hacks(); return need_socktype_protocol_hack_;
}
staticvoid
apply_numeric_port_hack(int port, struct evutil_addrinfo **ai)
{ /* Now we run through the list and set the ports on all of the
* results where ports would make sense. */ for ( ; *ai; ai = &(*ai)->ai_next) { struct sockaddr *sa = (*ai)->ai_addr; if (sa && sa->sa_family == AF_INET) { struct sockaddr_in *sin = (struct sockaddr_in*)sa;
sin->sin_port = htons(port);
} elseif (sa && sa->sa_family == AF_INET6) { struct sockaddr_in6 *sin6 = (struct sockaddr_in6*)sa;
sin6->sin6_port = htons(port);
} else { /* A numeric port makes no sense here; remove this one
* from the list. */ struct evutil_addrinfo *victim = *ai;
*ai = victim->ai_next;
victim->ai_next = NULL;
freeaddrinfo(victim);
}
}
}
#ifndef AI_ADDRCONFIG /* Not every system has AI_ADDRCONFIG, so fake it. */ if (hints.ai_family == PF_UNSPEC &&
(hints.ai_flags & EVUTIL_AI_ADDRCONFIG)) {
evutil_adjust_hints_for_addrconfig_(&hints);
} #endif
#ifndef AI_NUMERICSERV /* Not every system has AI_NUMERICSERV, so fake it. */ if (hints.ai_flags & EVUTIL_AI_NUMERICSERV) { if (servname && parse_numeric_servname(servname)<0) return EVUTIL_EAI_NONAME;
} #endif
/* Enough operating systems handle enough common non-resolve *caseshereweirdlyenoughthatwearebetteroffjust *overridingthem.Forexample: * *-Windowsdoesn'tliketoinfertheprotocolfromthe *sockettype,orfillinsocketorprotocoltypesmuchat *all.Italsoseemstodoitsownbrokenimplicit *always-onversionofAI_ADDRCONFIGthatkeepsitfrom *everresolvingevenaliteralIPv6addresswhen *ai_addrtypeisPF_UNSPEC.
*/ #ifdef _WIN32
{ int tmp_port;
err = evutil_getaddrinfo_common_(nodename,servname,&hints,
res, &tmp_port); if (err == 0 ||
err == EVUTIL_EAI_MEMORY ||
err == EVUTIL_EAI_NONAME) return err; /* If we make it here, the system getaddrinfo can
* have a crack at it. */
} #endif
/* See documentation for need_numeric_port_hack above.*/
need_np_hack = need_numeric_port_hack() && servname && !hints.ai_socktype
&& ((portnum=parse_numeric_servname(servname)) >= 0); if (need_np_hack) { if (!nodename) return evutil_getaddrinfo_common_(
NULL,servname,&hints, res, &portnum);
servname = NULL;
}
if (need_socktype_protocol_hack()) {
evutil_getaddrinfo_infer_protocols(&hints);
}
/* Make sure that we didn't actually steal any AI_FLAGS values that *thesystemisusing.(Thisisaconstantexpression,andshouldge *optimizedout.) * *XXXXTurnthisintoacompile-timefailureratherthanarun-time *failure.
*/
EVUTIL_ASSERT((ALL_NONNATIVE_AI_FLAGS & ALL_NATIVE_AI_FLAGS) == 0);
/* Clear any flags that only libevent understands. */
hints.ai_flags &= ~ALL_NONNATIVE_AI_FLAGS;
err = getaddrinfo(nodename, servname, &hints, res); if (need_np_hack)
apply_numeric_port_hack(portnum, res);
if (need_socktype_protocol_hack()) { if (apply_socktype_protocol_hack(*res) < 0) {
evutil_freeaddrinfo(*res);
*res = NULL; return EVUTIL_EAI_MEMORY;
}
} return err; #else int port=0, err; struct hostent *ent = NULL; struct evutil_addrinfo hints;
err = evutil_getaddrinfo_common_(nodename, servname, &hints, res, &port); if (err != EVUTIL_EAI_NEED_RESOLVE) { /* We either succeeded or failed. No need to continue */ return err;
}
err = 0; /* Use any of the various gethostbyname_r variants as available. */
{ #ifdef EVENT__HAVE_GETHOSTBYNAME_R_6_ARG /* This one is what glibc provides. */ char buf[2048]; struct hostent hostent; int r;
r = gethostbyname_r(nodename, &hostent, buf, sizeof(buf), &ent,
&err); #elifdefined(EVENT__HAVE_GETHOSTBYNAME_R_5_ARG) char buf[2048]; struct hostent hostent;
ent = gethostbyname_r(nodename, &hostent, buf, sizeof(buf),
&err); #elifdefined(EVENT__HAVE_GETHOSTBYNAME_R_3_ARG) struct hostent_data data; struct hostent hostent;
memset(&data, 0, sizeof(data));
err = gethostbyname_r(nodename, &hostent, &data);
ent = err ? NULL : &hostent; #else /* fall back to gethostbyname. */ /* XXXX This needs a lock everywhere but Windows. */
ent = gethostbyname(nodename); #ifdef _WIN32
err = WSAGetLastError(); #else
err = h_errno; #endif #endif
/* Now we have either ent or err set. */ if (!ent) { /* XXX is this right for windows ? */ switch (err) { case TRY_AGAIN: return EVUTIL_EAI_AGAIN; case NO_RECOVERY: default: return EVUTIL_EAI_FAIL; case HOST_NOT_FOUND: return EVUTIL_EAI_NONAME; case NO_ADDRESS: #if NO_DATA != NO_ADDRESS case NO_DATA: #endif return EVUTIL_EAI_NODATA;
}
}
if (ent->h_addrtype != hints.ai_family &&
hints.ai_family != PF_UNSPEC) { /* This wasn't the type we were hoping for. Too bad *weneverhadachancetoaskgethostbynameforwhat
* we wanted. */ return EVUTIL_EAI_NONAME;
}
/* Make sure we got _some_ answers. */ if (ent->h_length == 0) return EVUTIL_EAI_NODATA;
/* If we got an address type we don't know how to make a
sockaddr for, give up. */ if (ent->h_addrtype != PF_INET && ent->h_addrtype != PF_INET6) return EVUTIL_EAI_FAMILY;
constchar *
evutil_gai_strerror(int err)
{ /* As a sneaky side-benefit, this case statement will get most *compilerstotellusifanyoftheerrorcodeswedefined
* conflict with the platform's native error codes. */ switch (err) { case EVUTIL_EAI_CANCEL: return"Request canceled"; case0: return"No error";
case EVUTIL_EAI_ADDRFAMILY: return"address family for nodename not supported"; case EVUTIL_EAI_AGAIN: return"temporary failure in name resolution"; case EVUTIL_EAI_BADFLAGS: return"invalid value for ai_flags"; case EVUTIL_EAI_FAIL: return"non-recoverable failure in name resolution"; case EVUTIL_EAI_FAMILY: return"ai_family not supported"; case EVUTIL_EAI_MEMORY: return"memory allocation failure"; case EVUTIL_EAI_NODATA: return"no address associated with nodename"; case EVUTIL_EAI_NONAME: return"nodename nor servname provided, or not known"; case EVUTIL_EAI_SERVICE: return"servname not supported for ai_socktype"; case EVUTIL_EAI_SOCKTYPE: return"ai_socktype not supported"; case EVUTIL_EAI_SYSTEM: return"system error"; default: #ifdefined(USE_NATIVE_GETADDRINFO) && defined(_WIN32) return gai_strerrorA(err); #elifdefined(USE_NATIVE_GETADDRINFO) return gai_strerror(err); #else return"Unknown error code"; #endif
}
}
#ifdef _WIN32 /* destructively remove a trailing line terminator from s */ staticvoid
chomp (char *s)
{
size_t len; if (s && (len = strlen (s)) > 0 && s[len - 1] == '\n') {
s[--len] = 0; if (len > 0 && s[len - 1] == '\r')
s[--len] = 0;
}
}
struct cached_sock_errs_entry {
HT_ENTRY(cached_sock_errs_entry) node;
DWORD code; char *msg; /* allocated with LocalAlloc; free with LocalFree */
};
staticinlineunsigned
hash_cached_sock_errs(conststruct cached_sock_errs_entry *e)
{ /* Use Murmur3's 32-bit finalizer as an integer hash function */
DWORD h = e->code;
h ^= h >> 16;
h *= 0x85ebca6b;
h ^= h >> 13;
h *= 0xc2b2ae35;
h ^= h >> 16; return h;
}
#ifndef EVENT__DISABLE_THREAD_SUPPORT int
evutil_global_setup_locks_(constint enable_locks)
{ return0;
} #endif
staticvoid
evutil_free_sock_err_globals(void)
{
}
#endif
int
evutil_snprintf(char *buf, size_t buflen, constchar *format, ...)
{ int r;
va_list ap;
va_start(ap, format);
r = evutil_vsnprintf(buf, buflen, format, ap);
va_end(ap); return r;
}
int
evutil_vsnprintf(char *buf, size_t buflen, constchar *format, va_list ap)
{ int r; if (!buflen) return0; #ifdefined(_MSC_VER) || defined(_WIN32)
r = _vsnprintf(buf, buflen, format, ap); if (r < 0)
r = _vscprintf(format, ap); #elifdefined(sgi) /* Make sure we always use the correct vsnprintf on IRIX */ externint _xpg5_vsnprintf(char * __restrict,
__SGI_LIBC_NAMESPACE_QUALIFIER size_t, constchar * __restrict, /* va_list */ char *);
r = _xpg5_vsnprintf(buf, buflen, format, ap); #else
r = vsnprintf(buf, buflen, format, ap); #endif
buf[buflen-1] = '\0'; return r;
}
constchar *
evutil_inet_ntop(int af, constvoid *src, char *dst, size_t len)
{ #ifdefined(EVENT__HAVE_INET_NTOP) && !defined(USE_INTERNAL_NTOP) return inet_ntop(af, src, dst, len); #else if (af == AF_INET) { conststruct in_addr *in = src; const ev_uint32_t a = ntohl(in->s_addr); int r;
r = evutil_snprintf(dst, len, "%d.%d.%d.%d",
(int)(ev_uint8_t)((a>>24)&0xff),
(int)(ev_uint8_t)((a>>16)&0xff),
(int)(ev_uint8_t)((a>>8 )&0xff),
(int)(ev_uint8_t)((a )&0xff)); if (r<0||(size_t)r>=len) return NULL; else return dst; #ifdef AF_INET6
} elseif (af == AF_INET6) { conststruct in6_addr *addr = src; char buf[64], *cp; int longestGapLen = 0, longestGapPos = -1, i,
curGapPos = -1, curGapLen = 0;
ev_uint16_t words[8]; for (i = 0; i < 8; ++i) {
words[i] =
(((ev_uint16_t)addr->s6_addr[2*i])<<8) + addr->s6_addr[2*i+1];
} if (words[0] == 0 && words[1] == 0 && words[2] == 0 && words[3] == 0 &&
words[4] == 0 && ((words[5] == 0 && words[6] && words[7]) ||
(words[5] == 0xffff))) { /* This is an IPv4 address. */ if (words[5] == 0) {
evutil_snprintf(buf, sizeof(buf), "::%d.%d.%d.%d",
addr->s6_addr[12], addr->s6_addr[13],
addr->s6_addr[14], addr->s6_addr[15]);
} else {
evutil_snprintf(buf, sizeof(buf), "::%x:%d.%d.%d.%d", words[5],
addr->s6_addr[12], addr->s6_addr[13],
addr->s6_addr[14], addr->s6_addr[15]);
} if (strlen(buf) > len) return NULL;
strlcpy(dst, buf, len); return dst;
}
i = 0; while (i < 8) { if (words[i] == 0) {
curGapPos = i++;
curGapLen = 1; while (i<8 && words[i] == 0) {
++i; ++curGapLen;
} if (curGapLen > longestGapLen) {
longestGapPos = curGapPos;
longestGapLen = curGapLen;
}
} else {
++i;
}
} if (longestGapLen<=1)
longestGapPos = -1;
cp = buf; for (i = 0; i < 8; ++i) { if (words[i] == 0 && longestGapPos == i) { if (i == 0)
*cp++ = ':';
*cp++ = ':'; while (i < 8 && words[i] == 0)
++i;
--i; /* to compensate for loop increment. */
} else {
evutil_snprintf(cp, sizeof(buf)-(cp-buf), "%x", (unsigned)words[i]);
cp += strlen(cp); if (i != 7)
*cp++ = ':';
}
}
*cp = '\0'; if (strlen(buf) > len) return NULL;
strlcpy(dst, buf, len); return dst; #endif
} else { return NULL;
} #endif
}
int
evutil_inet_pton_scope(int af, constchar *src, void *dst, unsigned *indexp)
{ int r; unsigned if_index; char *check, *cp, *tmp_src;
*indexp = 0; /* Reasonable default */
/* Bail out if not IPv6 */ if (af != AF_INET6) return evutil_inet_pton(af, src, dst);
cp = strchr(src, '%');
/* Bail out if no zone ID */ if (cp == NULL) return evutil_inet_pton(af, src, dst);
if_index = if_nametoindex(cp + 1); if (if_index == 0) { /* Could be numeric */
if_index = strtoul(cp + 1, &check, 10); if (check[0] != '\0') return0;
}
*indexp = if_index;
tmp_src = mm_strdup(src);
cp = strchr(tmp_src, '%');
*cp = '\0';
r = evutil_inet_pton(af, tmp_src, dst);
free(tmp_src); return r;
}
int
evutil_inet_pton(int af, constchar *src, void *dst)
{ #ifdefined(EVENT__HAVE_INET_PTON) && !defined(USE_INTERNAL_PTON) return inet_pton(af, src, dst); #else if (af == AF_INET) { unsigned a,b,c,d; char more; struct in_addr *addr = dst; if (sscanf(src, "%u.%u.%u.%u%c", &a,&b,&c,&d,&more) != 4) return0; if (a > 255) return0; if (b > 255) return0; if (c > 255) return0; if (d > 255) return0;
addr->s_addr = htonl((a<<24) | (b<<16) | (c<<8) | d); return1; #ifdef AF_INET6
} elseif (af == AF_INET6) { struct in6_addr *out = dst;
ev_uint16_t words[8]; int gapPos = -1, i, setWords=0; constchar *dot = strchr(src, '.'); constchar *eow; /* end of words. */ if (dot == src) return0; elseif (!dot)
eow = src+strlen(src); else { unsigned byte1,byte2,byte3,byte4; char more; for (eow = dot-1; eow >= src && EVUTIL_ISDIGIT_(*eow); --eow)
;
++eow;
/* We use "scanf" because some platform inet_aton()s are too lax
* about IPv4 addresses of the form "1.2.3" */ if (sscanf(eow, "%u.%u.%u.%u%c",
&byte1,&byte2,&byte3,&byte4,&more) != 4) return0;
i = 0; while (src < eow) { if (i > 7) return0; if (EVUTIL_ISXDIGIT_(*src)) { char *next; long r = strtol(src, &next, 16); if (next > 4+src) return0; if (next == src) return0; if (r<0 || r>65536) return0;
/* We can't just do weakrand() % top, since the low bits of the LCG *arelessrandomthanthehighones.(Specifically,sincetheLCG *modulusis2^N,every2^mform<Nwilldividethemodulus,andso
* therefore the low m bits of the LCG will have period 2^m.) */
divisor = EVUTIL_WEAKRAND_MAX / top; do {
result = evutil_weakrand_(state) / divisor;
} while (result >= top); return result;
}
/* Internal wrapper around 'socket' to provide Linux-style support for *syscall-savingmethodswhereavailable. * *Inadditiontoregularsocketbehavior,youcanuseabitwiseortosetthe *flagsEVUTIL_SOCK_NONBLOCKandEVUTIL_SOCK_CLOEXECinthe'type'argument, *tomakethesocketnonblockingorclose-on-execwithasfewsyscallsas *possible.
*/
evutil_socket_t
evutil_socket_(int domain, int type, int protocol)
{
evutil_socket_t r; #ifdefined(SOCK_NONBLOCK) && defined(SOCK_CLOEXEC)
r = socket(domain, type, protocol); if (r >= 0) return r; elseif ((type & (SOCK_NONBLOCK|SOCK_CLOEXEC)) == 0) return -1; #endif #define SOCKET_TYPE_MASK (~(EVUTIL_SOCK_NONBLOCK|EVUTIL_SOCK_CLOEXEC))
r = socket(domain, type & SOCKET_TYPE_MASK, protocol); if (r < 0) return -1; if (type & EVUTIL_SOCK_NONBLOCK) { if (evutil_fast_socket_nonblocking(r) < 0) {
evutil_closesocket(r); return -1;
}
} if (type & EVUTIL_SOCK_CLOEXEC) { if (evutil_fast_socket_closeonexec(r) < 0) {
evutil_closesocket(r); return -1;
}
} return r;
}
/* Internal wrapper around 'accept' or 'accept4' to provide Linux-style *supportforsyscall-savingmethodswhereavailable. * *Inadditiontoregularacceptbehavior,youcansetoneormoreofflags *EVUTIL_SOCK_NONBLOCKandEVUTIL_SOCK_CLOEXECinthe'flags'argument,to *makethesocketnonblockingorclose-on-execwithasfewsyscallsas *possible.
*/
evutil_socket_t
evutil_accept4_(evutil_socket_t sockfd, struct sockaddr *addr,
ev_socklen_t *addrlen, int flags)
{
evutil_socket_t result; #ifdefined(EVENT__HAVE_ACCEPT4) && defined(SOCK_CLOEXEC) && defined(SOCK_NONBLOCK)
result = accept4(sockfd, addr, addrlen, flags); if (result >= 0 || (errno != EINVAL && errno != ENOSYS)) { /* A nonnegative result means that we succeeded, so return. *FailingwithEINVALmeansthatanoptionwasn'tsupported, *andfailingwithENOSYSmeansthatthesyscallwasn't *there:inthosecaseswewanttofallback.Otherwise,we
* got a real error, and we should return. */ return result;
} #endif
result = accept(sockfd, addr, addrlen); if (result < 0) return result;
if (flags & EVUTIL_SOCK_CLOEXEC) { if (evutil_fast_socket_closeonexec(result) < 0) {
evutil_closesocket(result); return -1;
}
} if (flags & EVUTIL_SOCK_NONBLOCK) { if (evutil_fast_socket_nonblocking(result) < 0) {
evutil_closesocket(result); return -1;
}
} return result;
}
/* Internal function: Set fd[0] and fd[1] to a pair of fds such that writes on *fd[1]getreadfromfd[0].Makebothfdsnonblockingandclose-on-exec. *Return0onsuccess,-1onfailure.
*/ int
evutil_make_internal_pipe_(evutil_socket_t fd[2])
{ /* Makingthesecondsocketnonblockingisabitsubtle,giventhatwe ignoreanyEAGAINreturnswhenwritingtoit,andyoudon'tusally dothatforanonblockingsocket.ButifthekernelgivesusEAGAIN, thenthere'snoneedtoaddanymoredatatothebuffer,since themainthreadisalreadyeitherabouttowakeupanddrainit, orwokenupandintheprocessofdrainingit.
*/
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.