xref: /libevent-2.1.12/evutil.c (revision 6b8d02a7)
125007183SNick Mathewson /*
2e49e2891SNick Mathewson  * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson
325007183SNick Mathewson  *
425007183SNick Mathewson  * Redistribution and use in source and binary forms, with or without
525007183SNick Mathewson  * modification, are permitted provided that the following conditions
625007183SNick Mathewson  * are met:
725007183SNick Mathewson  * 1. Redistributions of source code must retain the above copyright
825007183SNick Mathewson  *    notice, this list of conditions and the following disclaimer.
925007183SNick Mathewson  * 2. Redistributions in binary form must reproduce the above copyright
1025007183SNick Mathewson  *    notice, this list of conditions and the following disclaimer in the
1125007183SNick Mathewson  *    documentation and/or other materials provided with the distribution.
1225007183SNick Mathewson  * 3. The name of the author may not be used to endorse or promote products
1325007183SNick Mathewson  *    derived from this software without specific prior written permission.
1425007183SNick Mathewson  *
1525007183SNick Mathewson  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
1625007183SNick Mathewson  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1725007183SNick Mathewson  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
1825007183SNick Mathewson  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
1925007183SNick Mathewson  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
2025007183SNick Mathewson  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2125007183SNick Mathewson  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2225007183SNick Mathewson  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2325007183SNick Mathewson  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2425007183SNick Mathewson  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2525007183SNick Mathewson  */
26784b8773SNick Mathewson 
27ec347b92SNick Mathewson #include "event2/event-config.h"
289b27b307SKevin Bowling #include "evconfig-private.h"
2986f57420SNick Mathewson 
309f560bfaSNick Mathewson #ifdef _WIN32
317868ab5aSNick Mathewson #include <winsock2.h>
329559349cSyuangongji #include <winerror.h>
339935d5b0SNick Mathewson #include <ws2tcpip.h>
3425007183SNick Mathewson #define WIN32_LEAN_AND_MEAN
3525007183SNick Mathewson #include <windows.h>
3625007183SNick Mathewson #undef WIN32_LEAN_AND_MEAN
375c7a7bcaSNick Mathewson #include <io.h>
38d49b5e33SNick Mathewson #include <tchar.h>
393d83f94dSNick Mathewson #include <process.h>
407085a456SNick Mathewson #undef _WIN32_WINNT
417085a456SNick Mathewson /* For structs needed by GetAdaptersAddresses */
427085a456SNick Mathewson #define _WIN32_WINNT 0x0501
437085a456SNick Mathewson #include <iphlpapi.h>
44f602211fSPhilip Homburg #include <netioapi.h>
4525007183SNick Mathewson #endif
4625007183SNick Mathewson 
4725007183SNick Mathewson #include <sys/types.h>
4868120d9bSNick Mathewson #ifdef EVENT__HAVE_SYS_SOCKET_H
4925007183SNick Mathewson #include <sys/socket.h>
5025007183SNick Mathewson #endif
5168120d9bSNick Mathewson #ifdef EVENT__HAVE_UNISTD_H
5225007183SNick Mathewson #include <unistd.h>
5325007183SNick Mathewson #endif
5468120d9bSNick Mathewson #ifdef EVENT__HAVE_FCNTL_H
5525007183SNick Mathewson #include <fcntl.h>
5625007183SNick Mathewson #endif
5768120d9bSNick Mathewson #ifdef EVENT__HAVE_STDLIB_H
58807ab182SNick Mathewson #include <stdlib.h>
59807ab182SNick Mathewson #endif
60d85bce4eSNick Mathewson #include <errno.h>
61850c3ff2SChristopher Davis #include <limits.h>
62c6da86ffSNick Mathewson #include <stdio.h>
630d9d5cfeSNick Mathewson #include <string.h>
6468120d9bSNick Mathewson #ifdef EVENT__HAVE_NETINET_IN_H
6570405e3cSNiels Provos #include <netinet/in.h>
6670405e3cSNiels Provos #endif
6768120d9bSNick Mathewson #ifdef EVENT__HAVE_NETINET_IN6_H
680d9d5cfeSNick Mathewson #include <netinet/in6.h>
690d9d5cfeSNick Mathewson #endif
7068120d9bSNick Mathewson #ifdef EVENT__HAVE_NETINET_TCP_H
715880e4a1SMark Ellzey #include <netinet/tcp.h>
725880e4a1SMark Ellzey #endif
7368120d9bSNick Mathewson #ifdef EVENT__HAVE_ARPA_INET_H
748ee9f9c1SNicholas Marriott #include <arpa/inet.h>
758ee9f9c1SNicholas Marriott #endif
760d1611dcSNick Mathewson #include <time.h>
770f7144fdSNick Mathewson #include <sys/stat.h>
78f602211fSPhilip Homburg #ifndef _WIN32
79f602211fSPhilip Homburg #include <net/if.h>
80f602211fSPhilip Homburg #endif
8168120d9bSNick Mathewson #ifdef EVENT__HAVE_IFADDRS_H
827085a456SNick Mathewson #include <ifaddrs.h>
837085a456SNick Mathewson #endif
84a26442c5SNick Mathewson 
850ac73078SNick Mathewson #include "event2/util.h"
86cd731b77SNick Mathewson #include "util-internal.h"
87169321c9SNick Mathewson #include "log-internal.h"
8886f57420SNick Mathewson #include "mm-internal.h"
890c6ec5d8SPatrick Pelletier #include "evthread-internal.h"
9025007183SNick Mathewson 
910d9d5cfeSNick Mathewson #include "strlcpy-internal.h"
92980bcd68SNick Mathewson #include "ipv6-internal.h"
930d9d5cfeSNick Mathewson 
949f560bfaSNick Mathewson #ifdef _WIN32
954ccdd53fSPatrick Pelletier #define HT_NO_CACHE_HASH_VALUES
964ccdd53fSPatrick Pelletier #include "ht-internal.h"
97e50c0fccSNick Mathewson #define open _open
98e50c0fccSNick Mathewson #define read _read
99e50c0fccSNick Mathewson #define close _close
1006810908aSNick Mathewson #ifndef fstat
1017484df61SNick Mathewson #define fstat _fstati64
1026810908aSNick Mathewson #endif
1036810908aSNick Mathewson #ifndef stat
1047484df61SNick Mathewson #define stat _stati64
1056810908aSNick Mathewson #endif
106336dcaeaSNick Mathewson #define mode_t int
107e50c0fccSNick Mathewson #endif
108e50c0fccSNick Mathewson 
109d2b5f722SRoss Lagerwall int
evutil_open_closeonexec_(const char * pathname,int flags,unsigned mode)1108ac3c4c2SNick Mathewson evutil_open_closeonexec_(const char *pathname, int flags, unsigned mode)
111d2b5f722SRoss Lagerwall {
112d2b5f722SRoss Lagerwall 	int fd;
113d2b5f722SRoss Lagerwall 
114d2b5f722SRoss Lagerwall #ifdef O_CLOEXEC
1152ed44302SNick Mathewson 	fd = open(pathname, flags|O_CLOEXEC, (mode_t)mode);
1162ed44302SNick Mathewson 	if (fd >= 0 || errno == EINVAL)
1172ed44302SNick Mathewson 		return fd;
1182ed44302SNick Mathewson 	/* If we got an EINVAL, fall through and try without O_CLOEXEC */
119d2b5f722SRoss Lagerwall #endif
12003dce42dSNick Mathewson 	fd = open(pathname, flags, (mode_t)mode);
121d2b5f722SRoss Lagerwall 	if (fd < 0)
122d2b5f722SRoss Lagerwall 		return -1;
123d2b5f722SRoss Lagerwall 
1242ed44302SNick Mathewson #if defined(FD_CLOEXEC)
1250de587f4SNick Mathewson 	if (fcntl(fd, F_SETFD, FD_CLOEXEC) < 0) {
1260de587f4SNick Mathewson 		close(fd);
127d2b5f722SRoss Lagerwall 		return -1;
1280de587f4SNick Mathewson 	}
129d2b5f722SRoss Lagerwall #endif
130d2b5f722SRoss Lagerwall 
131d2b5f722SRoss Lagerwall 	return fd;
132d2b5f722SRoss Lagerwall }
133d2b5f722SRoss Lagerwall 
1340f7144fdSNick Mathewson /**
1350f7144fdSNick Mathewson    Read the contents of 'filename' into a newly allocated NUL-terminated
1360f7144fdSNick Mathewson    string.  Set *content_out to hold this string, and *len_out to hold its
1370f7144fdSNick Mathewson    length (not including the appended NUL).  If 'is_binary', open the file in
1380f7144fdSNick Mathewson    binary mode.
1390f7144fdSNick Mathewson 
1400f7144fdSNick Mathewson    Returns 0 on success, -1 if the open fails, and -2 for all other failures.
1410f7144fdSNick Mathewson 
1420f7144fdSNick Mathewson    Used internally only; may go away in a future version.
1430f7144fdSNick Mathewson  */
1440f7144fdSNick Mathewson int
evutil_read_file_(const char * filename,char ** content_out,size_t * len_out,int is_binary)1458ac3c4c2SNick Mathewson evutil_read_file_(const char *filename, char **content_out, size_t *len_out,
1460f7144fdSNick Mathewson     int is_binary)
1470f7144fdSNick Mathewson {
1480f7144fdSNick Mathewson 	int fd, r;
1490f7144fdSNick Mathewson 	struct stat st;
1500f7144fdSNick Mathewson 	char *mem;
1510f7144fdSNick Mathewson 	size_t read_so_far=0;
1520f7144fdSNick Mathewson 	int mode = O_RDONLY;
1530f7144fdSNick Mathewson 
1540f7144fdSNick Mathewson 	EVUTIL_ASSERT(content_out);
1550f7144fdSNick Mathewson 	EVUTIL_ASSERT(len_out);
1560f7144fdSNick Mathewson 	*content_out = NULL;
1570f7144fdSNick Mathewson 	*len_out = 0;
1580f7144fdSNick Mathewson 
1590f7144fdSNick Mathewson #ifdef O_BINARY
1600f7144fdSNick Mathewson 	if (is_binary)
1610f7144fdSNick Mathewson 		mode |= O_BINARY;
1620f7144fdSNick Mathewson #endif
1630f7144fdSNick Mathewson 
1648ac3c4c2SNick Mathewson 	fd = evutil_open_closeonexec_(filename, mode, 0);
1650f7144fdSNick Mathewson 	if (fd < 0)
1660f7144fdSNick Mathewson 		return -1;
1679c8db0f8SNick Mathewson 	if (fstat(fd, &st) || st.st_size < 0 ||
1689c8db0f8SNick Mathewson 	    st.st_size > EV_SSIZE_MAX-1 ) {
1690f7144fdSNick Mathewson 		close(fd);
1700f7144fdSNick Mathewson 		return -2;
1710f7144fdSNick Mathewson 	}
172a3245afeSNick Mathewson 	mem = mm_malloc((size_t)st.st_size + 1);
1730f7144fdSNick Mathewson 	if (!mem) {
1740f7144fdSNick Mathewson 		close(fd);
1750f7144fdSNick Mathewson 		return -2;
1760f7144fdSNick Mathewson 	}
1770f7144fdSNick Mathewson 	read_so_far = 0;
1789f560bfaSNick Mathewson #ifdef _WIN32
1797484df61SNick Mathewson #define N_TO_READ(x) ((x) > INT_MAX) ? INT_MAX : ((int)(x))
1807484df61SNick Mathewson #else
181f8095d64SNick Mathewson #define N_TO_READ(x) (x)
1827484df61SNick Mathewson #endif
1837484df61SNick Mathewson 	while ((r = read(fd, mem+read_so_far, N_TO_READ(st.st_size - read_so_far))) > 0) {
1840f7144fdSNick Mathewson 		read_so_far += r;
1859c8db0f8SNick Mathewson 		if (read_so_far >= (size_t)st.st_size)
1860f7144fdSNick Mathewson 			break;
1879c8db0f8SNick Mathewson 		EVUTIL_ASSERT(read_so_far < (size_t)st.st_size);
1880f7144fdSNick Mathewson 	}
1890f7144fdSNick Mathewson 	close(fd);
1900798dd12SPierre Phaneuf 	if (r < 0) {
1910f7144fdSNick Mathewson 		mm_free(mem);
1920f7144fdSNick Mathewson 		return -2;
1930f7144fdSNick Mathewson 	}
1940f7144fdSNick Mathewson 	mem[read_so_far] = 0;
1950f7144fdSNick Mathewson 
1960f7144fdSNick Mathewson 	*len_out = read_so_far;
1970f7144fdSNick Mathewson 	*content_out = mem;
1980f7144fdSNick Mathewson 	return 0;
1990f7144fdSNick Mathewson }
2000f7144fdSNick Mathewson 
20125007183SNick Mathewson int
evutil_socketpair(int family,int type,int protocol,evutil_socket_t fd[2])2021120f04fSNick Mathewson evutil_socketpair(int family, int type, int protocol, evutil_socket_t fd[2])
20325007183SNick Mathewson {
2049f560bfaSNick Mathewson #ifndef _WIN32
205d85bce4eSNick Mathewson 	return socketpair(family, type, protocol, fd);
20625007183SNick Mathewson #else
2078ac3c4c2SNick Mathewson 	return evutil_ersatz_socketpair_(family, type, protocol, fd);
20857b30cd7SNick Mathewson #endif
20957b30cd7SNick Mathewson }
21057b30cd7SNick Mathewson 
21157b30cd7SNick Mathewson int
evutil_ersatz_socketpair_(int family,int type,int protocol,evutil_socket_t fd[2])2128ac3c4c2SNick Mathewson evutil_ersatz_socketpair_(int family, int type, int protocol,
21357b30cd7SNick Mathewson     evutil_socket_t fd[2])
21457b30cd7SNick Mathewson {
21525007183SNick Mathewson 	/* This code is originally from Tor.  Used with permission. */
21625007183SNick Mathewson 
21725007183SNick Mathewson 	/* This socketpair does not work when localhost is down. So
21825007183SNick Mathewson 	 * it's really not the same thing at all. But it's close enough
21925007183SNick Mathewson 	 * for now, and really, when localhost is down sometimes, we
22025007183SNick Mathewson 	 * have other problems too.
22125007183SNick Mathewson 	 */
2229f560bfaSNick Mathewson #ifdef _WIN32
22357b30cd7SNick Mathewson #define ERR(e) WSA##e
22457b30cd7SNick Mathewson #else
22557b30cd7SNick Mathewson #define ERR(e) e
22657b30cd7SNick Mathewson #endif
2271120f04fSNick Mathewson 	evutil_socket_t listener = -1;
2281120f04fSNick Mathewson 	evutil_socket_t connector = -1;
2291120f04fSNick Mathewson 	evutil_socket_t acceptor = -1;
23025007183SNick Mathewson 	struct sockaddr_in listen_addr;
23125007183SNick Mathewson 	struct sockaddr_in connect_addr;
23257b30cd7SNick Mathewson 	ev_socklen_t size;
23325007183SNick Mathewson 	int saved_errno = -1;
2344b41eebeSlzmths 	int family_test;
23525007183SNick Mathewson 
2364b41eebeSlzmths 	family_test = family != AF_INET;
23725007183SNick Mathewson #ifdef AF_UNIX
2384b41eebeSlzmths 	family_test = family_test && (family != AF_UNIX);
23925007183SNick Mathewson #endif
2404b41eebeSlzmths 	if (protocol || family_test) {
24157b30cd7SNick Mathewson 		EVUTIL_SET_SOCKET_ERROR(ERR(EAFNOSUPPORT));
242fe482977SNick Mathewson 		return -1;
24325007183SNick Mathewson 	}
2444b41eebeSlzmths 
24525007183SNick Mathewson 	if (!fd) {
24657b30cd7SNick Mathewson 		EVUTIL_SET_SOCKET_ERROR(ERR(EINVAL));
247fe482977SNick Mathewson 		return -1;
24825007183SNick Mathewson 	}
24925007183SNick Mathewson 
250d85bce4eSNick Mathewson 	listener = socket(AF_INET, type, 0);
25125007183SNick Mathewson 	if (listener < 0)
252fe482977SNick Mathewson 		return -1;
25325007183SNick Mathewson 	memset(&listen_addr, 0, sizeof(listen_addr));
25425007183SNick Mathewson 	listen_addr.sin_family = AF_INET;
25525007183SNick Mathewson 	listen_addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
25625007183SNick Mathewson 	listen_addr.sin_port = 0;	/* kernel chooses port.	 */
25725007183SNick Mathewson 	if (bind(listener, (struct sockaddr *) &listen_addr, sizeof (listen_addr))
25825007183SNick Mathewson 		== -1)
25925007183SNick Mathewson 		goto tidy_up_and_fail;
26025007183SNick Mathewson 	if (listen(listener, 1) == -1)
26125007183SNick Mathewson 		goto tidy_up_and_fail;
26225007183SNick Mathewson 
263d85bce4eSNick Mathewson 	connector = socket(AF_INET, type, 0);
26425007183SNick Mathewson 	if (connector < 0)
26525007183SNick Mathewson 		goto tidy_up_and_fail;
266043ae748SMark Ellzey 
267043ae748SMark Ellzey 	memset(&connect_addr, 0, sizeof(connect_addr));
268043ae748SMark Ellzey 
26925007183SNick Mathewson 	/* We want to find out the port number to connect to.  */
27025007183SNick Mathewson 	size = sizeof(connect_addr);
27125007183SNick Mathewson 	if (getsockname(listener, (struct sockaddr *) &connect_addr, &size) == -1)
27225007183SNick Mathewson 		goto tidy_up_and_fail;
27325007183SNick Mathewson 	if (size != sizeof (connect_addr))
27425007183SNick Mathewson 		goto abort_tidy_up_and_fail;
27525007183SNick Mathewson 	if (connect(connector, (struct sockaddr *) &connect_addr,
27625007183SNick Mathewson 				sizeof(connect_addr)) == -1)
27725007183SNick Mathewson 		goto tidy_up_and_fail;
27825007183SNick Mathewson 
27925007183SNick Mathewson 	size = sizeof(listen_addr);
28025007183SNick Mathewson 	acceptor = accept(listener, (struct sockaddr *) &listen_addr, &size);
28125007183SNick Mathewson 	if (acceptor < 0)
28225007183SNick Mathewson 		goto tidy_up_and_fail;
28325007183SNick Mathewson 	if (size != sizeof(listen_addr))
28425007183SNick Mathewson 		goto abort_tidy_up_and_fail;
28525007183SNick Mathewson 	/* Now check we are talking to ourself by matching port and host on the
28625007183SNick Mathewson 	   two sockets.	 */
28725007183SNick Mathewson 	if (getsockname(connector, (struct sockaddr *) &connect_addr, &size) == -1)
28825007183SNick Mathewson 		goto tidy_up_and_fail;
28925007183SNick Mathewson 	if (size != sizeof (connect_addr)
29025007183SNick Mathewson 		|| listen_addr.sin_family != connect_addr.sin_family
29125007183SNick Mathewson 		|| listen_addr.sin_addr.s_addr != connect_addr.sin_addr.s_addr
29225007183SNick Mathewson 		|| listen_addr.sin_port != connect_addr.sin_port)
29325007183SNick Mathewson 		goto abort_tidy_up_and_fail;
2940a822a64SNick Mathewson 	evutil_closesocket(listener);
29525007183SNick Mathewson 	fd[0] = connector;
29625007183SNick Mathewson 	fd[1] = acceptor;
29725007183SNick Mathewson 
29825007183SNick Mathewson 	return 0;
29925007183SNick Mathewson 
30025007183SNick Mathewson  abort_tidy_up_and_fail:
30157b30cd7SNick Mathewson 	saved_errno = ERR(ECONNABORTED);
30225007183SNick Mathewson  tidy_up_and_fail:
30325007183SNick Mathewson 	if (saved_errno < 0)
30457b30cd7SNick Mathewson 		saved_errno = EVUTIL_SOCKET_ERROR();
30525007183SNick Mathewson 	if (listener != -1)
306899c1dccSSebastian Sjöberg 		evutil_closesocket(listener);
30725007183SNick Mathewson 	if (connector != -1)
308899c1dccSSebastian Sjöberg 		evutil_closesocket(connector);
30925007183SNick Mathewson 	if (acceptor != -1)
310899c1dccSSebastian Sjöberg 		evutil_closesocket(acceptor);
311fe482977SNick Mathewson 
312e1f09dfeSNick Mathewson 	EVUTIL_SET_SOCKET_ERROR(saved_errno);
313fe482977SNick Mathewson 	return -1;
31457b30cd7SNick Mathewson #undef ERR
31525007183SNick Mathewson }
31625007183SNick Mathewson 
31725007183SNick Mathewson int
evutil_make_socket_nonblocking(evutil_socket_t fd)3181120f04fSNick Mathewson evutil_make_socket_nonblocking(evutil_socket_t fd)
31925007183SNick Mathewson {
3209f560bfaSNick Mathewson #ifdef _WIN32
32125007183SNick Mathewson 	{
322fd36647aSEd Schouten 		unsigned long nonblocking = 1;
323f5ad31c1STrond Norbye 		if (ioctlsocket(fd, FIONBIO, &nonblocking) == SOCKET_ERROR) {
32419c71e74SNick Mathewson 			event_sock_warn(fd, "fcntl(%d, F_GETFL)", (int)fd);
325f5ad31c1STrond Norbye 			return -1;
326f5ad31c1STrond Norbye 		}
32725007183SNick Mathewson 	}
32825007183SNick Mathewson #else
3294c8b7cdcSJardel Weyrich 	{
3307c2dea16SNick Mathewson 		int flags;
3314c8b7cdcSJardel Weyrich 		if ((flags = fcntl(fd, F_GETFL, NULL)) < 0) {
3324df7dbcbSJardel Weyrich 			event_warn("fcntl(%d, F_GETFL)", fd);
3334c8b7cdcSJardel Weyrich 			return -1;
3344c8b7cdcSJardel Weyrich 		}
33542c03da9SMaxime Henrion 		if (!(flags & O_NONBLOCK)) {
3364df7dbcbSJardel Weyrich 			if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1) {
3374df7dbcbSJardel Weyrich 				event_warn("fcntl(%d, F_SETFL)", fd);
33825007183SNick Mathewson 				return -1;
33925007183SNick Mathewson 			}
3404c8b7cdcSJardel Weyrich 		}
34142c03da9SMaxime Henrion 	}
34225007183SNick Mathewson #endif
34325007183SNick Mathewson 	return 0;
34425007183SNick Mathewson }
34525007183SNick Mathewson 
346a1c042bfSNick Mathewson /* Faster version of evutil_make_socket_nonblocking for internal use.
347a1c042bfSNick Mathewson  *
348a1c042bfSNick Mathewson  * Requires that no F_SETFL flags were previously set on the fd.
349a1c042bfSNick Mathewson  */
350a1c042bfSNick Mathewson static int
evutil_fast_socket_nonblocking(evutil_socket_t fd)351a1c042bfSNick Mathewson evutil_fast_socket_nonblocking(evutil_socket_t fd)
352a1c042bfSNick Mathewson {
353a1c042bfSNick Mathewson #ifdef _WIN32
354a1c042bfSNick Mathewson 	return evutil_make_socket_nonblocking(fd);
355a1c042bfSNick Mathewson #else
356a1c042bfSNick Mathewson 	if (fcntl(fd, F_SETFL, O_NONBLOCK) == -1) {
357a1c042bfSNick Mathewson 		event_warn("fcntl(%d, F_SETFL)", fd);
358a1c042bfSNick Mathewson 		return -1;
359a1c042bfSNick Mathewson 	}
360a1c042bfSNick Mathewson 	return 0;
361a1c042bfSNick Mathewson #endif
362a1c042bfSNick Mathewson }
363a1c042bfSNick Mathewson 
364c7b2f8fdSNick Mathewson int
evutil_make_listen_socket_reuseable(evutil_socket_t sock)365c7b2f8fdSNick Mathewson evutil_make_listen_socket_reuseable(evutil_socket_t sock)
366c7b2f8fdSNick Mathewson {
367ce1776c9SEd Schouten #if defined(SO_REUSEADDR) && !defined(_WIN32)
368c7b2f8fdSNick Mathewson 	int one = 1;
369c7b2f8fdSNick Mathewson 	/* REUSEADDR on Unix means, "don't hang on to this address after the
37050e20fe0SNick Mathewson 	 * listener is closed."  On Windows, though, it means "don't keep other
371c7b2f8fdSNick Mathewson 	 * processes from binding to this address while we're using it. */
372c7b2f8fdSNick Mathewson 	return setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void*) &one,
3737c20a6aeSNick Mathewson 	    (ev_socklen_t)sizeof(one));
374c7b2f8fdSNick Mathewson #else
375c7b2f8fdSNick Mathewson 	return 0;
376c7b2f8fdSNick Mathewson #endif
377c7b2f8fdSNick Mathewson }
378c7b2f8fdSNick Mathewson 
379d0939d2bSJardel Weyrich int
evutil_make_listen_socket_reuseable_port(evutil_socket_t sock)380b625361aSMaciej Soltysiak evutil_make_listen_socket_reuseable_port(evutil_socket_t sock)
381b625361aSMaciej Soltysiak {
382b625361aSMaciej Soltysiak #if defined __linux__ && defined(SO_REUSEPORT)
383b625361aSMaciej Soltysiak 	int one = 1;
384b625361aSMaciej Soltysiak 	/* REUSEPORT on Linux 3.9+ means, "Multiple servers (processes or
385b625361aSMaciej Soltysiak 	 * threads) can bind to the same port if they each set the option. */
386b625361aSMaciej Soltysiak 	return setsockopt(sock, SOL_SOCKET, SO_REUSEPORT, (void*) &one,
387b625361aSMaciej Soltysiak 	    (ev_socklen_t)sizeof(one));
388b625361aSMaciej Soltysiak #else
389b625361aSMaciej Soltysiak 	return 0;
390b625361aSMaciej Soltysiak #endif
391b625361aSMaciej Soltysiak }
392b625361aSMaciej Soltysiak 
393b625361aSMaciej Soltysiak int
evutil_make_listen_socket_ipv6only(evutil_socket_t sock)394ba148796SMurat Demirten evutil_make_listen_socket_ipv6only(evutil_socket_t sock)
395ba148796SMurat Demirten {
3961c865238SAzat Khuzhin #if defined(IPV6_V6ONLY)
397ba148796SMurat Demirten 	int one = 1;
398ba148796SMurat Demirten 	return setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, (void*) &one,
399ba148796SMurat Demirten 	    (ev_socklen_t)sizeof(one));
4001c865238SAzat Khuzhin #endif
4011c865238SAzat Khuzhin 	return 0;
402ba148796SMurat Demirten }
403ba148796SMurat Demirten 
404ba148796SMurat Demirten int
evutil_make_tcp_listen_socket_deferred(evutil_socket_t sock)4055880e4a1SMark Ellzey evutil_make_tcp_listen_socket_deferred(evutil_socket_t sock)
4065880e4a1SMark Ellzey {
40768120d9bSNick Mathewson #if defined(EVENT__HAVE_NETINET_TCP_H) && defined(TCP_DEFER_ACCEPT)
4085880e4a1SMark Ellzey 	int one = 1;
4095880e4a1SMark Ellzey 
4105880e4a1SMark Ellzey 	/* TCP_DEFER_ACCEPT tells the kernel to call defer accept() only after data
4115880e4a1SMark Ellzey 	 * has arrived and ready to read */
4125880e4a1SMark Ellzey 	return setsockopt(sock, IPPROTO_TCP, TCP_DEFER_ACCEPT, &one,
4135880e4a1SMark Ellzey 		(ev_socklen_t)sizeof(one));
4145880e4a1SMark Ellzey #endif
4155880e4a1SMark Ellzey 	return 0;
4165880e4a1SMark Ellzey }
4175880e4a1SMark Ellzey 
4185880e4a1SMark Ellzey int
evutil_make_socket_closeonexec(evutil_socket_t fd)419d0939d2bSJardel Weyrich evutil_make_socket_closeonexec(evutil_socket_t fd)
420d0939d2bSJardel Weyrich {
42168120d9bSNick Mathewson #if !defined(_WIN32) && defined(EVENT__HAVE_SETFD)
4227c2dea16SNick Mathewson 	int flags;
423d0939d2bSJardel Weyrich 	if ((flags = fcntl(fd, F_GETFD, NULL)) < 0) {
424d0939d2bSJardel Weyrich 		event_warn("fcntl(%d, F_GETFD)", fd);
425d0939d2bSJardel Weyrich 		return -1;
426d0939d2bSJardel Weyrich 	}
4271f29b18fSNick Mathewson 	if (!(flags & FD_CLOEXEC)) {
428d0939d2bSJardel Weyrich 		if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) == -1) {
429d0939d2bSJardel Weyrich 			event_warn("fcntl(%d, F_SETFD)", fd);
430d0939d2bSJardel Weyrich 			return -1;
431d0939d2bSJardel Weyrich 		}
4321f29b18fSNick Mathewson 	}
433d0939d2bSJardel Weyrich #endif
434d0939d2bSJardel Weyrich 	return 0;
435d0939d2bSJardel Weyrich }
436d0939d2bSJardel Weyrich 
437a1c042bfSNick Mathewson /* Faster version of evutil_make_socket_closeonexec for internal use.
438a1c042bfSNick Mathewson  *
439a1c042bfSNick Mathewson  * Requires that no F_SETFD flags were previously set on the fd.
440a1c042bfSNick Mathewson  */
441a1c042bfSNick Mathewson static int
evutil_fast_socket_closeonexec(evutil_socket_t fd)442a1c042bfSNick Mathewson evutil_fast_socket_closeonexec(evutil_socket_t fd)
443a1c042bfSNick Mathewson {
44468120d9bSNick Mathewson #if !defined(_WIN32) && defined(EVENT__HAVE_SETFD)
445a1c042bfSNick Mathewson 	if (fcntl(fd, F_SETFD, FD_CLOEXEC) == -1) {
446a1c042bfSNick Mathewson 		event_warn("fcntl(%d, F_SETFD)", fd);
447a1c042bfSNick Mathewson 		return -1;
448a1c042bfSNick Mathewson 	}
449a1c042bfSNick Mathewson #endif
450a1c042bfSNick Mathewson 	return 0;
451a1c042bfSNick Mathewson }
452a1c042bfSNick Mathewson 
453899c1dccSSebastian Sjöberg int
evutil_closesocket(evutil_socket_t sock)454899c1dccSSebastian Sjöberg evutil_closesocket(evutil_socket_t sock)
455899c1dccSSebastian Sjöberg {
4569f560bfaSNick Mathewson #ifndef _WIN32
457899c1dccSSebastian Sjöberg 	return close(sock);
458899c1dccSSebastian Sjöberg #else
459899c1dccSSebastian Sjöberg 	return closesocket(sock);
460899c1dccSSebastian Sjöberg #endif
461899c1dccSSebastian Sjöberg }
462899c1dccSSebastian Sjöberg 
463807ab182SNick Mathewson ev_int64_t
evutil_strtoll(const char * s,char ** endptr,int base)464807ab182SNick Mathewson evutil_strtoll(const char *s, char **endptr, int base)
465807ab182SNick Mathewson {
46668120d9bSNick Mathewson #ifdef EVENT__HAVE_STRTOLL
467807ab182SNick Mathewson 	return (ev_int64_t)strtoll(s, endptr, base);
46868120d9bSNick Mathewson #elif EVENT__SIZEOF_LONG == 8
469807ab182SNick Mathewson 	return (ev_int64_t)strtol(s, endptr, base);
4709f560bfaSNick Mathewson #elif defined(_WIN32) && defined(_MSC_VER) && _MSC_VER < 1300
471807ab182SNick Mathewson 	/* XXXX on old versions of MS APIs, we only support base
472807ab182SNick Mathewson 	 * 10. */
473807ab182SNick Mathewson 	ev_int64_t r;
474807ab182SNick Mathewson 	if (base != 10)
475807ab182SNick Mathewson 		return 0;
476807ab182SNick Mathewson 	r = (ev_int64_t) _atoi64(s);
477807ab182SNick Mathewson 	while (isspace(*s))
478807ab182SNick Mathewson 		++s;
479453317b2SNick Mathewson 	if (*s == '-')
480453317b2SNick Mathewson 		++s;
481807ab182SNick Mathewson 	while (isdigit(*s))
482807ab182SNick Mathewson 		++s;
483807ab182SNick Mathewson 	if (endptr)
484807ab182SNick Mathewson 		*endptr = (char*) s;
485807ab182SNick Mathewson 	return r;
4869f560bfaSNick Mathewson #elif defined(_WIN32)
487807ab182SNick Mathewson 	return (ev_int64_t) _strtoi64(s, endptr, base);
48868120d9bSNick Mathewson #elif defined(EVENT__SIZEOF_LONG_LONG) && EVENT__SIZEOF_LONG_LONG == 8
489453317b2SNick Mathewson 	long long r;
490453317b2SNick Mathewson 	int n;
491453317b2SNick Mathewson 	if (base != 10 && base != 16)
492453317b2SNick Mathewson 		return 0;
493453317b2SNick Mathewson 	if (base == 10) {
494453317b2SNick Mathewson 		n = sscanf(s, "%lld", &r);
495453317b2SNick Mathewson 	} else {
496453317b2SNick Mathewson 		unsigned long long ru=0;
497453317b2SNick Mathewson 		n = sscanf(s, "%llx", &ru);
498453317b2SNick Mathewson 		if (ru > EV_INT64_MAX)
499453317b2SNick Mathewson 			return 0;
500453317b2SNick Mathewson 		r = (long long) ru;
501453317b2SNick Mathewson 	}
502453317b2SNick Mathewson 	if (n != 1)
503453317b2SNick Mathewson 		return 0;
5048ac3c4c2SNick Mathewson 	while (EVUTIL_ISSPACE_(*s))
505453317b2SNick Mathewson 		++s;
506453317b2SNick Mathewson 	if (*s == '-')
507453317b2SNick Mathewson 		++s;
508453317b2SNick Mathewson 	if (base == 10) {
5098ac3c4c2SNick Mathewson 		while (EVUTIL_ISDIGIT_(*s))
510453317b2SNick Mathewson 			++s;
511453317b2SNick Mathewson 	} else {
5128ac3c4c2SNick Mathewson 		while (EVUTIL_ISXDIGIT_(*s))
513453317b2SNick Mathewson 			++s;
514453317b2SNick Mathewson 	}
515453317b2SNick Mathewson 	if (endptr)
516453317b2SNick Mathewson 		*endptr = (char*) s;
517453317b2SNick Mathewson 	return r;
518807ab182SNick Mathewson #else
519807ab182SNick Mathewson #error "I don't know how to parse 64-bit integers."
520807ab182SNick Mathewson #endif
521807ab182SNick Mathewson }
522a26442c5SNick Mathewson 
5239f560bfaSNick Mathewson #ifdef _WIN32
524de069b99SNick Mathewson int
evutil_socket_geterror(evutil_socket_t sock)525de069b99SNick Mathewson evutil_socket_geterror(evutil_socket_t sock)
526de069b99SNick Mathewson {
527de069b99SNick Mathewson 	int optval, optvallen=sizeof(optval);
528de069b99SNick Mathewson 	int err = WSAGetLastError();
529de069b99SNick Mathewson 	if (err == WSAEWOULDBLOCK && sock >= 0) {
530de069b99SNick Mathewson 		if (getsockopt(sock, SOL_SOCKET, SO_ERROR, (void*)&optval,
531de069b99SNick Mathewson 					   &optvallen))
532de069b99SNick Mathewson 			return err;
533de069b99SNick Mathewson 		if (optval)
534de069b99SNick Mathewson 			return optval;
535de069b99SNick Mathewson 	}
536de069b99SNick Mathewson 	return err;
537de069b99SNick Mathewson }
538de069b99SNick Mathewson #endif
539de069b99SNick Mathewson 
54057b72488SNick Mathewson /* XXX we should use an enum here. */
5417bc48bfdSNiels Provos /* 2 for connection refused, 1 for connected, 0 for not yet, -1 for error. */
542709c21c4SNick Mathewson int
evutil_socket_connect_(evutil_socket_t * fd_ptr,const struct sockaddr * sa,int socklen)543a8d32c23SAzat Khuzhin evutil_socket_connect_(evutil_socket_t *fd_ptr, const struct sockaddr *sa, int socklen)
544709c21c4SNick Mathewson {
545709c21c4SNick Mathewson 	int made_fd = 0;
546709c21c4SNick Mathewson 
547709c21c4SNick Mathewson 	if (*fd_ptr < 0) {
548709c21c4SNick Mathewson 		if ((*fd_ptr = socket(sa->sa_family, SOCK_STREAM, 0)) < 0)
549709c21c4SNick Mathewson 			goto err;
5507c11e51eSHarlan Stenn 		made_fd = 1;
551709c21c4SNick Mathewson 		if (evutil_make_socket_nonblocking(*fd_ptr) < 0) {
552709c21c4SNick Mathewson 			goto err;
553709c21c4SNick Mathewson 		}
554709c21c4SNick Mathewson 	}
555709c21c4SNick Mathewson 
556709c21c4SNick Mathewson 	if (connect(*fd_ptr, sa, socklen) < 0) {
557709c21c4SNick Mathewson 		int e = evutil_socket_geterror(*fd_ptr);
558709c21c4SNick Mathewson 		if (EVUTIL_ERR_CONNECT_RETRIABLE(e))
559709c21c4SNick Mathewson 			return 0;
5607bc48bfdSNiels Provos 		if (EVUTIL_ERR_CONNECT_REFUSED(e))
5617bc48bfdSNiels Provos 			return 2;
562709c21c4SNick Mathewson 		goto err;
563709c21c4SNick Mathewson 	} else {
564709c21c4SNick Mathewson 		return 1;
565709c21c4SNick Mathewson 	}
566709c21c4SNick Mathewson 
567709c21c4SNick Mathewson err:
568709c21c4SNick Mathewson 	if (made_fd) {
569899c1dccSSebastian Sjöberg 		evutil_closesocket(*fd_ptr);
570709c21c4SNick Mathewson 		*fd_ptr = -1;
571709c21c4SNick Mathewson 	}
572709c21c4SNick Mathewson 	return -1;
573709c21c4SNick Mathewson }
574709c21c4SNick Mathewson 
57525af6954SNick Mathewson /* Check whether a socket on which we called connect() is done
57625af6954SNick Mathewson    connecting. Return 1 for connected, 0 for not yet, -1 for error.  In the
57725af6954SNick Mathewson    error case, set the current socket errno to the error that happened during
57825af6954SNick Mathewson    the connect operation. */
57925af6954SNick Mathewson int
evutil_socket_finished_connecting_(evutil_socket_t fd)5808ac3c4c2SNick Mathewson evutil_socket_finished_connecting_(evutil_socket_t fd)
58125af6954SNick Mathewson {
58225af6954SNick Mathewson 	int e;
58325af6954SNick Mathewson 	ev_socklen_t elen = sizeof(e);
58425af6954SNick Mathewson 
58525af6954SNick Mathewson 	if (getsockopt(fd, SOL_SOCKET, SO_ERROR, (void*)&e, &elen) < 0)
58625af6954SNick Mathewson 		return -1;
58725af6954SNick Mathewson 
58825af6954SNick Mathewson 	if (e) {
58925af6954SNick Mathewson 		if (EVUTIL_ERR_CONNECT_RETRIABLE(e))
59025af6954SNick Mathewson 			return 0;
59125af6954SNick Mathewson 		EVUTIL_SET_SOCKET_ERROR(e);
59225af6954SNick Mathewson 		return -1;
59325af6954SNick Mathewson 	}
59425af6954SNick Mathewson 
59525af6954SNick Mathewson 	return 1;
59625af6954SNick Mathewson }
59725af6954SNick Mathewson 
598c18490e6SNick Mathewson #if (EVUTIL_AI_PASSIVE|EVUTIL_AI_CANONNAME|EVUTIL_AI_NUMERICHOST| \
599c18490e6SNick Mathewson      EVUTIL_AI_NUMERICSERV|EVUTIL_AI_V4MAPPED|EVUTIL_AI_ALL| \
600c18490e6SNick Mathewson      EVUTIL_AI_ADDRCONFIG) != \
601c18490e6SNick Mathewson     (EVUTIL_AI_PASSIVE^EVUTIL_AI_CANONNAME^EVUTIL_AI_NUMERICHOST^ \
602c18490e6SNick Mathewson      EVUTIL_AI_NUMERICSERV^EVUTIL_AI_V4MAPPED^EVUTIL_AI_ALL^ \
603c18490e6SNick Mathewson      EVUTIL_AI_ADDRCONFIG)
604c18490e6SNick Mathewson #error "Some of our EVUTIL_AI_* flags seem to overlap with system AI_* flags"
605c18490e6SNick Mathewson #endif
606c18490e6SNick Mathewson 
60786f57420SNick Mathewson /* We sometimes need to know whether we have an ipv4 address and whether we
60886f57420SNick Mathewson    have an ipv6 address. If 'have_checked_interfaces', then we've already done
60986f57420SNick Mathewson    the test.  If 'had_ipv4_address', then it turns out we had an ipv4 address.
61086f57420SNick Mathewson    If 'had_ipv6_address', then it turns out we had an ipv6 address.   These are
61186f57420SNick Mathewson    set by evutil_check_interfaces. */
61286f57420SNick Mathewson static int have_checked_interfaces, had_ipv4_address, had_ipv6_address;
61386f57420SNick Mathewson 
614b07e43e6SAzat Khuzhin /* True iff the IPv4 address 'addr', in host order, is in 127.0.0.0/8 */
evutil_v4addr_is_localhost(ev_uint32_t addr)615b07e43e6SAzat Khuzhin static inline int evutil_v4addr_is_localhost(ev_uint32_t addr)
616b07e43e6SAzat Khuzhin { return addr>>24 == 127; }
6171a21d7b8SNick Mathewson 
618b07e43e6SAzat Khuzhin /* True iff the IPv4 address 'addr', in host order, is link-local
619b07e43e6SAzat Khuzhin  * 169.254.0.0/16 (RFC3927) */
evutil_v4addr_is_linklocal(ev_uint32_t addr)620b07e43e6SAzat Khuzhin static inline int evutil_v4addr_is_linklocal(ev_uint32_t addr)
621b07e43e6SAzat Khuzhin { return ((addr & 0xffff0000U) == 0xa9fe0000U); }
622b07e43e6SAzat Khuzhin 
623b07e43e6SAzat Khuzhin /* True iff the IPv4 address 'addr', in host order, is a class D
624b07e43e6SAzat Khuzhin  * (multiclass) address.  */
evutil_v4addr_is_classd(ev_uint32_t addr)625b07e43e6SAzat Khuzhin static inline int evutil_v4addr_is_classd(ev_uint32_t addr)
626b07e43e6SAzat Khuzhin { return ((addr>>24) & 0xf0) == 0xe0; }
627b07e43e6SAzat Khuzhin 
628b07e43e6SAzat Khuzhin int
evutil_v4addr_is_local_(const struct in_addr * in)629b07e43e6SAzat Khuzhin evutil_v4addr_is_local_(const struct in_addr *in)
630b07e43e6SAzat Khuzhin {
631b07e43e6SAzat Khuzhin 	const ev_uint32_t addr = ntohl(in->s_addr);
632b07e43e6SAzat Khuzhin 	return addr == INADDR_ANY ||
633b07e43e6SAzat Khuzhin 		evutil_v4addr_is_localhost(addr) ||
634b07e43e6SAzat Khuzhin 		evutil_v4addr_is_linklocal(addr) ||
635b07e43e6SAzat Khuzhin 		evutil_v4addr_is_classd(addr);
636b07e43e6SAzat Khuzhin }
637b07e43e6SAzat Khuzhin int
evutil_v6addr_is_local_(const struct in6_addr * in)638b07e43e6SAzat Khuzhin evutil_v6addr_is_local_(const struct in6_addr *in)
639b07e43e6SAzat Khuzhin {
640b07e43e6SAzat Khuzhin 	static const char ZEROES[] =
641b07e43e6SAzat Khuzhin 		"\x00\x00\x00\x00\x00\x00\x00\x00"
642b07e43e6SAzat Khuzhin 		"\x00\x00\x00\x00\x00\x00\x00\x00";
643b07e43e6SAzat Khuzhin 
644b07e43e6SAzat Khuzhin 	const unsigned char *addr = (const unsigned char *)in->s6_addr;
645b07e43e6SAzat Khuzhin 	return !memcmp(addr, ZEROES, 8) ||
646b07e43e6SAzat Khuzhin 		((addr[0] & 0xfe) == 0xfc) ||
647b07e43e6SAzat Khuzhin 		(addr[0] == 0xfe && (addr[1] & 0xc0) == 0x80) ||
648b07e43e6SAzat Khuzhin 		(addr[0] == 0xfe && (addr[1] & 0xc0) == 0xc0) ||
649b07e43e6SAzat Khuzhin 		(addr[0] == 0xff);
650b07e43e6SAzat Khuzhin }
6511a21d7b8SNick Mathewson 
6527085a456SNick Mathewson static void
evutil_found_ifaddr(const struct sockaddr * sa)6537085a456SNick Mathewson evutil_found_ifaddr(const struct sockaddr *sa)
6547085a456SNick Mathewson {
6557085a456SNick Mathewson 	if (sa->sa_family == AF_INET) {
6567085a456SNick Mathewson 		const struct sockaddr_in *sin = (struct sockaddr_in *)sa;
657b07e43e6SAzat Khuzhin 		if (!evutil_v4addr_is_local_(&sin->sin_addr)) {
6587085a456SNick Mathewson 			event_debug(("Detected an IPv4 interface"));
6597085a456SNick Mathewson 			had_ipv4_address = 1;
6607085a456SNick Mathewson 		}
6617085a456SNick Mathewson 	} else if (sa->sa_family == AF_INET6) {
6627085a456SNick Mathewson 		const struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa;
663b07e43e6SAzat Khuzhin 		if (!evutil_v6addr_is_local_(&sin6->sin6_addr)) {
6647085a456SNick Mathewson 			event_debug(("Detected an IPv6 interface"));
6657085a456SNick Mathewson 			had_ipv6_address = 1;
6667085a456SNick Mathewson 		}
6677085a456SNick Mathewson 	}
6687085a456SNick Mathewson }
6697085a456SNick Mathewson 
67040a3c52dSNick Mathewson #ifdef _WIN32
67140a3c52dSNick Mathewson typedef ULONG (WINAPI *GetAdaptersAddresses_fn_t)(
67240a3c52dSNick Mathewson               ULONG, ULONG, PVOID, PIP_ADAPTER_ADDRESSES, PULONG);
67340a3c52dSNick Mathewson #endif
67440a3c52dSNick Mathewson 
6757085a456SNick Mathewson static int
evutil_check_ifaddrs(void)6767085a456SNick Mathewson evutil_check_ifaddrs(void)
6777085a456SNick Mathewson {
67868120d9bSNick Mathewson #if defined(EVENT__HAVE_GETIFADDRS)
6797085a456SNick Mathewson 	/* Most free Unixy systems provide getifaddrs, which gives us a linked list
6807085a456SNick Mathewson 	 * of struct ifaddrs. */
6817085a456SNick Mathewson 	struct ifaddrs *ifa = NULL;
6827085a456SNick Mathewson 	const struct ifaddrs *i;
6837085a456SNick Mathewson 	if (getifaddrs(&ifa) < 0) {
6847085a456SNick Mathewson 		event_warn("Unable to call getifaddrs()");
6857085a456SNick Mathewson 		return -1;
6867085a456SNick Mathewson 	}
6877085a456SNick Mathewson 
6887085a456SNick Mathewson 	for (i = ifa; i; i = i->ifa_next) {
6897085a456SNick Mathewson 		if (!i->ifa_addr)
6907085a456SNick Mathewson 			continue;
6917085a456SNick Mathewson 		evutil_found_ifaddr(i->ifa_addr);
6927085a456SNick Mathewson 	}
6937085a456SNick Mathewson 
6947085a456SNick Mathewson 	freeifaddrs(ifa);
6957085a456SNick Mathewson 	return 0;
6967085a456SNick Mathewson #elif defined(_WIN32)
6977085a456SNick Mathewson 	/* Windows XP began to provide GetAdaptersAddresses. Windows 2000 had a
6987085a456SNick Mathewson 	   "GetAdaptersInfo", but that's deprecated; let's just try
6997085a456SNick Mathewson 	   GetAdaptersAddresses and fall back to connect+getsockname.
7007085a456SNick Mathewson 	*/
701891adda9SAleksandr-Melnikov 	HMODULE lib = evutil_load_windows_system_library_(TEXT("iphlpapi.dll"));
7027085a456SNick Mathewson 	GetAdaptersAddresses_fn_t fn;
7037085a456SNick Mathewson 	ULONG size, res;
7047085a456SNick Mathewson 	IP_ADAPTER_ADDRESSES *addresses = NULL, *address;
7057085a456SNick Mathewson 	int result = -1;
7067085a456SNick Mathewson 
7077085a456SNick Mathewson #define FLAGS (GAA_FLAG_SKIP_ANYCAST | \
7087085a456SNick Mathewson                GAA_FLAG_SKIP_MULTICAST | \
7097085a456SNick Mathewson                GAA_FLAG_SKIP_DNS_SERVER)
7107085a456SNick Mathewson 
7117085a456SNick Mathewson 	if (!lib)
7127085a456SNick Mathewson 		goto done;
7137085a456SNick Mathewson 
7147085a456SNick Mathewson 	if (!(fn = (GetAdaptersAddresses_fn_t) GetProcAddress(lib, "GetAdaptersAddresses")))
7157085a456SNick Mathewson 		goto done;
7167085a456SNick Mathewson 
7177085a456SNick Mathewson 	/* Guess how much space we need. */
7187085a456SNick Mathewson 	size = 15*1024;
7197085a456SNick Mathewson 	addresses = mm_malloc(size);
7207085a456SNick Mathewson 	if (!addresses)
7217085a456SNick Mathewson 		goto done;
7227085a456SNick Mathewson 	res = fn(AF_UNSPEC, FLAGS, NULL, addresses, &size);
7237085a456SNick Mathewson 	if (res == ERROR_BUFFER_OVERFLOW) {
7247085a456SNick Mathewson 		/* we didn't guess that we needed enough space; try again */
7257085a456SNick Mathewson 		mm_free(addresses);
72640a3c52dSNick Mathewson 		addresses = mm_malloc(size);
7277085a456SNick Mathewson 		if (!addresses)
7287085a456SNick Mathewson 			goto done;
7297085a456SNick Mathewson 		res = fn(AF_UNSPEC, FLAGS, NULL, addresses, &size);
7307085a456SNick Mathewson 	}
7317085a456SNick Mathewson 	if (res != NO_ERROR)
7327085a456SNick Mathewson 		goto done;
7337085a456SNick Mathewson 
7347085a456SNick Mathewson 	for (address = addresses; address; address = address->Next) {
7357085a456SNick Mathewson 		IP_ADAPTER_UNICAST_ADDRESS *a;
7367085a456SNick Mathewson 		for (a = address->FirstUnicastAddress; a; a = a->Next) {
7377085a456SNick Mathewson 			/* Yes, it's a linked list inside a linked list */
7387085a456SNick Mathewson 			struct sockaddr *sa = a->Address.lpSockaddr;
7397085a456SNick Mathewson 			evutil_found_ifaddr(sa);
7407085a456SNick Mathewson 		}
7417085a456SNick Mathewson 	}
7427085a456SNick Mathewson 
7437085a456SNick Mathewson 	result = 0;
7447085a456SNick Mathewson done:
7457085a456SNick Mathewson 	if (lib)
7467085a456SNick Mathewson 		FreeLibrary(lib);
7477085a456SNick Mathewson 	if (addresses)
7487085a456SNick Mathewson 		mm_free(addresses);
7497085a456SNick Mathewson 	return result;
7507085a456SNick Mathewson #else
7517085a456SNick Mathewson 	return -1;
7527085a456SNick Mathewson #endif
7537085a456SNick Mathewson }
7547085a456SNick Mathewson 
75586f57420SNick Mathewson /* Test whether we have an ipv4 interface and an ipv6 interface.  Return 0 if
75686f57420SNick Mathewson  * the test seemed successful. */
75786f57420SNick Mathewson static int
evutil_check_interfaces(void)758a09265acSAzat Khuzhin evutil_check_interfaces(void)
75986f57420SNick Mathewson {
76086f57420SNick Mathewson 	evutil_socket_t fd = -1;
76186f57420SNick Mathewson 	struct sockaddr_in sin, sin_out;
76286f57420SNick Mathewson 	struct sockaddr_in6 sin6, sin6_out;
76386f57420SNick Mathewson 	ev_socklen_t sin_out_len = sizeof(sin_out);
76486f57420SNick Mathewson 	ev_socklen_t sin6_out_len = sizeof(sin6_out);
76586f57420SNick Mathewson 	int r;
766a09265acSAzat Khuzhin 	if (have_checked_interfaces)
76786f57420SNick Mathewson 		return 0;
76886f57420SNick Mathewson 
769ef498aa2Sjeremyerb 	/* From this point on we have done the ipv4/ipv6 interface check */
770ef498aa2Sjeremyerb 	have_checked_interfaces = 1;
771ef498aa2Sjeremyerb 
7727085a456SNick Mathewson 	if (evutil_check_ifaddrs() == 0) {
7737085a456SNick Mathewson 		/* Use a nice sane interface, if this system has one. */
7747085a456SNick Mathewson 		return 0;
7757085a456SNick Mathewson 	}
7767085a456SNick Mathewson 
7777085a456SNick Mathewson 	/* Ugh. There was no nice sane interface.  So to check whether we have
7787085a456SNick Mathewson 	 * an interface open for a given protocol, will try to make a UDP
7797085a456SNick Mathewson 	 * 'connection' to a remote host on the internet.  We don't actually
7807085a456SNick Mathewson 	 * use it, so the address doesn't matter, but we want to pick one that
7817085a456SNick Mathewson 	 * keep us from using a host- or link-local interface. */
78286f57420SNick Mathewson 	memset(&sin, 0, sizeof(sin));
78386f57420SNick Mathewson 	sin.sin_family = AF_INET;
78486f57420SNick Mathewson 	sin.sin_port = htons(53);
78586f57420SNick Mathewson 	r = evutil_inet_pton(AF_INET, "18.244.0.188", &sin.sin_addr);
78686f57420SNick Mathewson 	EVUTIL_ASSERT(r);
78786f57420SNick Mathewson 
78886f57420SNick Mathewson 	memset(&sin6, 0, sizeof(sin6));
78986f57420SNick Mathewson 	sin6.sin6_family = AF_INET6;
79086f57420SNick Mathewson 	sin6.sin6_port = htons(53);
79186f57420SNick Mathewson 	r = evutil_inet_pton(AF_INET6, "2001:4860:b002::68", &sin6.sin6_addr);
79286f57420SNick Mathewson 	EVUTIL_ASSERT(r);
79386f57420SNick Mathewson 
79486f57420SNick Mathewson 	memset(&sin_out, 0, sizeof(sin_out));
79586f57420SNick Mathewson 	memset(&sin6_out, 0, sizeof(sin6_out));
79686f57420SNick Mathewson 
79786f57420SNick Mathewson 	/* XXX some errnos mean 'no address'; some mean 'not enough sockets'. */
79886f57420SNick Mathewson 	if ((fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) >= 0 &&
79986f57420SNick Mathewson 	    connect(fd, (struct sockaddr*)&sin, sizeof(sin)) == 0 &&
80086f57420SNick Mathewson 	    getsockname(fd, (struct sockaddr*)&sin_out, &sin_out_len) == 0) {
80186f57420SNick Mathewson 		/* We might have an IPv4 interface. */
8027085a456SNick Mathewson 		evutil_found_ifaddr((struct sockaddr*) &sin_out);
80386f57420SNick Mathewson 	}
80486f57420SNick Mathewson 	if (fd >= 0)
805899c1dccSSebastian Sjöberg 		evutil_closesocket(fd);
80686f57420SNick Mathewson 
80786f57420SNick Mathewson 	if ((fd = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP)) >= 0 &&
80886f57420SNick Mathewson 	    connect(fd, (struct sockaddr*)&sin6, sizeof(sin6)) == 0 &&
80986f57420SNick Mathewson 	    getsockname(fd, (struct sockaddr*)&sin6_out, &sin6_out_len) == 0) {
81086f57420SNick Mathewson 		/* We might have an IPv6 interface. */
8117085a456SNick Mathewson 		evutil_found_ifaddr((struct sockaddr*) &sin6_out);
81286f57420SNick Mathewson 	}
81386f57420SNick Mathewson 
81486f57420SNick Mathewson 	if (fd >= 0)
815899c1dccSSebastian Sjöberg 		evutil_closesocket(fd);
81686f57420SNick Mathewson 
81786f57420SNick Mathewson 	return 0;
81886f57420SNick Mathewson }
81986f57420SNick Mathewson 
82086f57420SNick Mathewson /* Internal addrinfo flag.  This one is set when we allocate the addrinfo from
82186f57420SNick Mathewson  * inside libevent.  Otherwise, the built-in getaddrinfo() function allocated
82286f57420SNick Mathewson  * it, and we should trust what they said.
82386f57420SNick Mathewson  **/
82486f57420SNick Mathewson #define EVUTIL_AI_LIBEVENT_ALLOCATED 0x80000000
82586f57420SNick Mathewson 
82686f57420SNick Mathewson /* Helper: construct a new addrinfo containing the socket address in
82786f57420SNick Mathewson  * 'sa', which must be a sockaddr_in or a sockaddr_in6.  Take the
82886f57420SNick Mathewson  * socktype and protocol info from hints.  If they weren't set, then
82986f57420SNick Mathewson  * allocate both a TCP and a UDP addrinfo.
83086f57420SNick Mathewson  */
83186f57420SNick Mathewson struct evutil_addrinfo *
evutil_new_addrinfo_(struct sockaddr * sa,ev_socklen_t socklen,const struct evutil_addrinfo * hints)8328ac3c4c2SNick Mathewson evutil_new_addrinfo_(struct sockaddr *sa, ev_socklen_t socklen,
83386f57420SNick Mathewson     const struct evutil_addrinfo *hints)
83486f57420SNick Mathewson {
83586f57420SNick Mathewson 	struct evutil_addrinfo *res;
83686f57420SNick Mathewson 	EVUTIL_ASSERT(hints);
83786f57420SNick Mathewson 
83886f57420SNick Mathewson 	if (hints->ai_socktype == 0 && hints->ai_protocol == 0) {
83986f57420SNick Mathewson 		/* Indecisive user! Give them a UDP and a TCP. */
84086f57420SNick Mathewson 		struct evutil_addrinfo *r1, *r2;
84186f57420SNick Mathewson 		struct evutil_addrinfo tmp;
84286f57420SNick Mathewson 		memcpy(&tmp, hints, sizeof(tmp));
84386f57420SNick Mathewson 		tmp.ai_socktype = SOCK_STREAM; tmp.ai_protocol = IPPROTO_TCP;
8448ac3c4c2SNick Mathewson 		r1 = evutil_new_addrinfo_(sa, socklen, &tmp);
84586f57420SNick Mathewson 		if (!r1)
84686f57420SNick Mathewson 			return NULL;
84786f57420SNick Mathewson 		tmp.ai_socktype = SOCK_DGRAM; tmp.ai_protocol = IPPROTO_UDP;
8488ac3c4c2SNick Mathewson 		r2 = evutil_new_addrinfo_(sa, socklen, &tmp);
84986f57420SNick Mathewson 		if (!r2) {
8500d64051fSJardel Weyrich 			evutil_freeaddrinfo(r1);
85186f57420SNick Mathewson 			return NULL;
85286f57420SNick Mathewson 		}
85386f57420SNick Mathewson 		r1->ai_next = r2;
85486f57420SNick Mathewson 		return r1;
85586f57420SNick Mathewson 	}
85686f57420SNick Mathewson 
85786f57420SNick Mathewson 	/* We're going to allocate extra space to hold the sockaddr. */
85886f57420SNick Mathewson 	res = mm_calloc(1,sizeof(struct evutil_addrinfo)+socklen);
85986f57420SNick Mathewson 	if (!res)
86086f57420SNick Mathewson 		return NULL;
86186f57420SNick Mathewson 	res->ai_addr = (struct sockaddr*)
86286f57420SNick Mathewson 	    (((char*)res) + sizeof(struct evutil_addrinfo));
86386f57420SNick Mathewson 	memcpy(res->ai_addr, sa, socklen);
86486f57420SNick Mathewson 	res->ai_addrlen = socklen;
86586f57420SNick Mathewson 	res->ai_family = sa->sa_family; /* Same or not? XXX */
86686f57420SNick Mathewson 	res->ai_flags = EVUTIL_AI_LIBEVENT_ALLOCATED;
86786f57420SNick Mathewson 	res->ai_socktype = hints->ai_socktype;
86886f57420SNick Mathewson 	res->ai_protocol = hints->ai_protocol;
86986f57420SNick Mathewson 
87086f57420SNick Mathewson 	return res;
87186f57420SNick Mathewson }
87286f57420SNick Mathewson 
87386f57420SNick Mathewson /* Append the addrinfo 'append' to the end of 'first', and return the start of
87486f57420SNick Mathewson  * the list.  Either element can be NULL, in which case we return the element
87586f57420SNick Mathewson  * that is not NULL. */
87686f57420SNick Mathewson struct evutil_addrinfo *
evutil_addrinfo_append_(struct evutil_addrinfo * first,struct evutil_addrinfo * append)8778ac3c4c2SNick Mathewson evutil_addrinfo_append_(struct evutil_addrinfo *first,
87886f57420SNick Mathewson     struct evutil_addrinfo *append)
87986f57420SNick Mathewson {
88086f57420SNick Mathewson 	struct evutil_addrinfo *ai = first;
88186f57420SNick Mathewson 	if (!ai)
88286f57420SNick Mathewson 		return append;
88386f57420SNick Mathewson 	while (ai->ai_next)
88486f57420SNick Mathewson 		ai = ai->ai_next;
88586f57420SNick Mathewson 	ai->ai_next = append;
88686f57420SNick Mathewson 
88786f57420SNick Mathewson 	return first;
88886f57420SNick Mathewson }
88986f57420SNick Mathewson 
890f070a4aeSNick Mathewson static int
parse_numeric_servname(const char * servname)891f070a4aeSNick Mathewson parse_numeric_servname(const char *servname)
892f070a4aeSNick Mathewson {
893f070a4aeSNick Mathewson 	int n;
894f070a4aeSNick Mathewson 	char *endptr=NULL;
895f070a4aeSNick Mathewson 	n = (int) strtol(servname, &endptr, 10);
896f070a4aeSNick Mathewson 	if (n>=0 && n <= 65535 && servname[0] && endptr && !endptr[0])
897f070a4aeSNick Mathewson 		return n;
898f070a4aeSNick Mathewson 	else
899f070a4aeSNick Mathewson 		return -1;
900f070a4aeSNick Mathewson }
901f070a4aeSNick Mathewson 
90286f57420SNick Mathewson /** Parse a service name in 'servname', which can be a decimal port.
90386f57420SNick Mathewson  * Return the port number, or -1 on error.
90486f57420SNick Mathewson  */
90586f57420SNick Mathewson static int
evutil_parse_servname(const char * servname,const char * protocol,const struct evutil_addrinfo * hints)90686f57420SNick Mathewson evutil_parse_servname(const char *servname, const char *protocol,
90786f57420SNick Mathewson     const struct evutil_addrinfo *hints)
90886f57420SNick Mathewson {
909f070a4aeSNick Mathewson 	int n = parse_numeric_servname(servname);
910f070a4aeSNick Mathewson 	if (n>=0)
91186f57420SNick Mathewson 		return n;
91268120d9bSNick Mathewson #if defined(EVENT__HAVE_GETSERVBYNAME) || defined(_WIN32)
91386f57420SNick Mathewson 	if (!(hints->ai_flags & EVUTIL_AI_NUMERICSERV)) {
91486f57420SNick Mathewson 		struct servent *ent = getservbyname(servname, protocol);
91586f57420SNick Mathewson 		if (ent) {
91686f57420SNick Mathewson 			return ntohs(ent->s_port);
91786f57420SNick Mathewson 		}
91886f57420SNick Mathewson 	}
91986f57420SNick Mathewson #endif
92086f57420SNick Mathewson 	return -1;
92186f57420SNick Mathewson }
92286f57420SNick Mathewson 
92386f57420SNick Mathewson /* Return a string corresponding to a protocol number that we can pass to
92486f57420SNick Mathewson  * getservyname.  */
92586f57420SNick Mathewson static const char *
evutil_unparse_protoname(int proto)92686f57420SNick Mathewson evutil_unparse_protoname(int proto)
92786f57420SNick Mathewson {
9285a43df82SJardel Weyrich 	switch (proto) {
9295a43df82SJardel Weyrich 	case 0:
93086f57420SNick Mathewson 		return NULL;
9315a43df82SJardel Weyrich 	case IPPROTO_TCP:
93286f57420SNick Mathewson 		return "tcp";
9335a43df82SJardel Weyrich 	case IPPROTO_UDP:
93486f57420SNick Mathewson 		return "udp";
93586f57420SNick Mathewson #ifdef IPPROTO_SCTP
9365a43df82SJardel Weyrich 	case IPPROTO_SCTP:
93786f57420SNick Mathewson 		return "sctp";
93886f57420SNick Mathewson #endif
9395a43df82SJardel Weyrich 	default:
94068120d9bSNick Mathewson #ifdef EVENT__HAVE_GETPROTOBYNUMBER
94186f57420SNick Mathewson 		{
94286f57420SNick Mathewson 			struct protoent *ent = getprotobynumber(proto);
94386f57420SNick Mathewson 			if (ent)
94486f57420SNick Mathewson 				return ent->p_name;
94586f57420SNick Mathewson 		}
94686f57420SNick Mathewson #endif
94786f57420SNick Mathewson 		return NULL;
94886f57420SNick Mathewson 	}
9495a43df82SJardel Weyrich }
95086f57420SNick Mathewson 
95186f57420SNick Mathewson static void
evutil_getaddrinfo_infer_protocols(struct evutil_addrinfo * hints)95286f57420SNick Mathewson evutil_getaddrinfo_infer_protocols(struct evutil_addrinfo *hints)
95386f57420SNick Mathewson {
95486f57420SNick Mathewson 	/* If we can guess the protocol from the socktype, do so. */
95586f57420SNick Mathewson 	if (!hints->ai_protocol && hints->ai_socktype) {
95686f57420SNick Mathewson 		if (hints->ai_socktype == SOCK_DGRAM)
95786f57420SNick Mathewson 			hints->ai_protocol = IPPROTO_UDP;
95886f57420SNick Mathewson 		else if (hints->ai_socktype == SOCK_STREAM)
95986f57420SNick Mathewson 			hints->ai_protocol = IPPROTO_TCP;
96086f57420SNick Mathewson 	}
96186f57420SNick Mathewson 
96286f57420SNick Mathewson 	/* Set the socktype if it isn't set. */
96386f57420SNick Mathewson 	if (!hints->ai_socktype && hints->ai_protocol) {
96486f57420SNick Mathewson 		if (hints->ai_protocol == IPPROTO_UDP)
96586f57420SNick Mathewson 			hints->ai_socktype = SOCK_DGRAM;
96686f57420SNick Mathewson 		else if (hints->ai_protocol == IPPROTO_TCP)
96786f57420SNick Mathewson 			hints->ai_socktype = SOCK_STREAM;
96886f57420SNick Mathewson #ifdef IPPROTO_SCTP
96986f57420SNick Mathewson 		else if (hints->ai_protocol == IPPROTO_SCTP)
97086f57420SNick Mathewson 			hints->ai_socktype = SOCK_STREAM;
97186f57420SNick Mathewson #endif
97286f57420SNick Mathewson 	}
97386f57420SNick Mathewson }
97486f57420SNick Mathewson 
9753c8f4e75SNick Mathewson #if AF_UNSPEC != PF_UNSPEC
9763c8f4e75SNick Mathewson #error "I cannot build on a system where AF_UNSPEC != PF_UNSPEC"
9773c8f4e75SNick Mathewson #endif
9783c8f4e75SNick Mathewson 
97986f57420SNick Mathewson /** Implements the part of looking up hosts by name that's common to both
98086f57420SNick Mathewson  * the blocking and nonblocking resolver:
98186f57420SNick Mathewson  *   - Adjust 'hints' to have a reasonable socktype and protocol.
98286f57420SNick Mathewson  *   - Look up the port based on 'servname', and store it in *portnum,
98386f57420SNick Mathewson  *   - Handle the nodename==NULL case
98486f57420SNick Mathewson  *   - Handle some invalid arguments cases.
98586f57420SNick Mathewson  *   - Handle the cases where nodename is an IPv4 or IPv6 address.
98686f57420SNick Mathewson  *
98786f57420SNick Mathewson  * If we need the resolver to look up the hostname, we return
98886f57420SNick Mathewson  * EVUTIL_EAI_NEED_RESOLVE.  Otherwise, we can completely implement
98986f57420SNick Mathewson  * getaddrinfo: we return 0 or an appropriate EVUTIL_EAI_* error, and
99086f57420SNick Mathewson  * set *res as getaddrinfo would.
9910b9eb1bfSNick Mathewson  */
9920b9eb1bfSNick Mathewson int
evutil_getaddrinfo_common_(const char * nodename,const char * servname,struct evutil_addrinfo * hints,struct evutil_addrinfo ** res,int * portnum)9938ac3c4c2SNick Mathewson evutil_getaddrinfo_common_(const char *nodename, const char *servname,
99486f57420SNick Mathewson     struct evutil_addrinfo *hints, struct evutil_addrinfo **res, int *portnum)
9950b9eb1bfSNick Mathewson {
99686f57420SNick Mathewson 	int port = 0;
997f602211fSPhilip Homburg 	unsigned int if_index;
99886f57420SNick Mathewson 	const char *pname;
9990b9eb1bfSNick Mathewson 
100086f57420SNick Mathewson 	if (nodename == NULL && servname == NULL)
100186f57420SNick Mathewson 		return EVUTIL_EAI_NONAME;
100286f57420SNick Mathewson 
100386f57420SNick Mathewson 	/* We only understand 3 families */
100486f57420SNick Mathewson 	if (hints->ai_family != PF_UNSPEC && hints->ai_family != PF_INET &&
100586f57420SNick Mathewson 	    hints->ai_family != PF_INET6)
100686f57420SNick Mathewson 		return EVUTIL_EAI_FAMILY;
100786f57420SNick Mathewson 
100886f57420SNick Mathewson 	evutil_getaddrinfo_infer_protocols(hints);
100986f57420SNick Mathewson 
101086f57420SNick Mathewson 	/* Look up the port number and protocol, if possible. */
101186f57420SNick Mathewson 	pname = evutil_unparse_protoname(hints->ai_protocol);
101286f57420SNick Mathewson 	if (servname) {
101386f57420SNick Mathewson 		/* XXXX We could look at the protocol we got back from
101486f57420SNick Mathewson 		 * getservbyname, but it doesn't seem too useful. */
101586f57420SNick Mathewson 		port = evutil_parse_servname(servname, pname, hints);
101686f57420SNick Mathewson 		if (port < 0) {
101786f57420SNick Mathewson 			return EVUTIL_EAI_NONAME;
101886f57420SNick Mathewson 		}
10190b9eb1bfSNick Mathewson 	}
10200b9eb1bfSNick Mathewson 
102186f57420SNick Mathewson 	/* If we have no node name, then we're supposed to bind to 'any' and
102286f57420SNick Mathewson 	 * connect to localhost. */
102386f57420SNick Mathewson 	if (nodename == NULL) {
102486f57420SNick Mathewson 		struct evutil_addrinfo *res4=NULL, *res6=NULL;
102586f57420SNick Mathewson 		if (hints->ai_family != PF_INET) { /* INET6 or UNSPEC. */
10260b9eb1bfSNick Mathewson 			struct sockaddr_in6 sin6;
102786f57420SNick Mathewson 			memset(&sin6, 0, sizeof(sin6));
102886f57420SNick Mathewson 			sin6.sin6_family = AF_INET6;
102986f57420SNick Mathewson 			sin6.sin6_port = htons(port);
1030cb921139SNick Mathewson 			if (hints->ai_flags & EVUTIL_AI_PASSIVE) {
103186f57420SNick Mathewson 				/* Bind to :: */
103286f57420SNick Mathewson 			} else {
103386f57420SNick Mathewson 				/* connect to ::1 */
103486f57420SNick Mathewson 				sin6.sin6_addr.s6_addr[15] = 1;
10350b9eb1bfSNick Mathewson 			}
10368ac3c4c2SNick Mathewson 			res6 = evutil_new_addrinfo_((struct sockaddr*)&sin6,
103786f57420SNick Mathewson 			    sizeof(sin6), hints);
103886f57420SNick Mathewson 			if (!res6)
103986f57420SNick Mathewson 				return EVUTIL_EAI_MEMORY;
104086f57420SNick Mathewson 		}
104186f57420SNick Mathewson 
104286f57420SNick Mathewson 		if (hints->ai_family != PF_INET6) { /* INET or UNSPEC */
104386f57420SNick Mathewson 			struct sockaddr_in sin;
10440b9eb1bfSNick Mathewson 			memset(&sin, 0, sizeof(sin));
10450b9eb1bfSNick Mathewson 			sin.sin_family = AF_INET;
10460b9eb1bfSNick Mathewson 			sin.sin_port = htons(port);
1047cb921139SNick Mathewson 			if (hints->ai_flags & EVUTIL_AI_PASSIVE) {
104886f57420SNick Mathewson 				/* Bind to 0.0.0.0 */
104986f57420SNick Mathewson 			} else {
105086f57420SNick Mathewson 				/* connect to 127.0.0.1 */
105186f57420SNick Mathewson 				sin.sin_addr.s_addr = htonl(0x7f000001);
105286f57420SNick Mathewson 			}
10538ac3c4c2SNick Mathewson 			res4 = evutil_new_addrinfo_((struct sockaddr*)&sin,
105486f57420SNick Mathewson 			    sizeof(sin), hints);
105586f57420SNick Mathewson 			if (!res4) {
105686f57420SNick Mathewson 				if (res6)
105786f57420SNick Mathewson 					evutil_freeaddrinfo(res6);
105886f57420SNick Mathewson 				return EVUTIL_EAI_MEMORY;
105986f57420SNick Mathewson 			}
106086f57420SNick Mathewson 		}
10618ac3c4c2SNick Mathewson 		*res = evutil_addrinfo_append_(res4, res6);
106286f57420SNick Mathewson 		return 0;
106386f57420SNick Mathewson 	}
106486f57420SNick Mathewson 
106586f57420SNick Mathewson 	/* If we can, we should try to parse the hostname without resolving
106686f57420SNick Mathewson 	 * it. */
106786f57420SNick Mathewson 	/* Try ipv6. */
106886f57420SNick Mathewson 	if (hints->ai_family == PF_INET6 || hints->ai_family == PF_UNSPEC) {
106986f57420SNick Mathewson 		struct sockaddr_in6 sin6;
107086f57420SNick Mathewson 		memset(&sin6, 0, sizeof(sin6));
1071f602211fSPhilip Homburg 		if (1 == evutil_inet_pton_scope(
1072f602211fSPhilip Homburg 			AF_INET6, nodename, &sin6.sin6_addr, &if_index)) {
107386f57420SNick Mathewson 			/* Got an ipv6 address. */
10740b9eb1bfSNick Mathewson 			sin6.sin6_family = AF_INET6;
10750b9eb1bfSNick Mathewson 			sin6.sin6_port = htons(port);
1076f602211fSPhilip Homburg 			sin6.sin6_scope_id = if_index;
10778ac3c4c2SNick Mathewson 			*res = evutil_new_addrinfo_((struct sockaddr*)&sin6,
107886f57420SNick Mathewson 			    sizeof(sin6), hints);
107986f57420SNick Mathewson 			if (!*res)
108086f57420SNick Mathewson 				return EVUTIL_EAI_MEMORY;
108186f57420SNick Mathewson 			return 0;
108286f57420SNick Mathewson 		}
108386f57420SNick Mathewson 	}
108486f57420SNick Mathewson 
108586f57420SNick Mathewson 	/* Try ipv4. */
108686f57420SNick Mathewson 	if (hints->ai_family == PF_INET || hints->ai_family == PF_UNSPEC) {
108786f57420SNick Mathewson 		struct sockaddr_in sin;
108886f57420SNick Mathewson 		memset(&sin, 0, sizeof(sin));
108986f57420SNick Mathewson 		if (1==evutil_inet_pton(AF_INET, nodename, &sin.sin_addr)) {
10908dddccd0Stim-le 			/* Got an ipv4 address. */
109186f57420SNick Mathewson 			sin.sin_family = AF_INET;
109286f57420SNick Mathewson 			sin.sin_port = htons(port);
10938ac3c4c2SNick Mathewson 			*res = evutil_new_addrinfo_((struct sockaddr*)&sin,
109486f57420SNick Mathewson 			    sizeof(sin), hints);
109586f57420SNick Mathewson 			if (!*res)
109686f57420SNick Mathewson 				return EVUTIL_EAI_MEMORY;
109786f57420SNick Mathewson 			return 0;
109886f57420SNick Mathewson 		}
109986f57420SNick Mathewson 	}
110086f57420SNick Mathewson 
110186f57420SNick Mathewson 
110286f57420SNick Mathewson 	/* If we have reached this point, we definitely need to do a DNS
110386f57420SNick Mathewson 	 * lookup. */
110486f57420SNick Mathewson 	if ((hints->ai_flags & EVUTIL_AI_NUMERICHOST)) {
110586f57420SNick Mathewson 		/* If we're not allowed to do one, then say so. */
110686f57420SNick Mathewson 		return EVUTIL_EAI_NONAME;
110786f57420SNick Mathewson 	}
110886f57420SNick Mathewson 	*portnum = port;
110986f57420SNick Mathewson 	return EVUTIL_EAI_NEED_RESOLVE;
111086f57420SNick Mathewson }
111186f57420SNick Mathewson 
111268120d9bSNick Mathewson #ifdef EVENT__HAVE_GETADDRINFO
111386f57420SNick Mathewson #define USE_NATIVE_GETADDRINFO
111486f57420SNick Mathewson #endif
111586f57420SNick Mathewson 
11163451c870SNick Mathewson #ifdef USE_NATIVE_GETADDRINFO
11173451c870SNick Mathewson /* A mask of all the flags that we declare, so we can clear them before calling
11183451c870SNick Mathewson  * the native getaddrinfo */
11193451c870SNick Mathewson static const unsigned int ALL_NONNATIVE_AI_FLAGS =
11203451c870SNick Mathewson #ifndef AI_PASSIVE
11213451c870SNick Mathewson     EVUTIL_AI_PASSIVE |
11223451c870SNick Mathewson #endif
11233451c870SNick Mathewson #ifndef AI_CANONNAME
11243451c870SNick Mathewson     EVUTIL_AI_CANONNAME |
11253451c870SNick Mathewson #endif
11263451c870SNick Mathewson #ifndef AI_NUMERICHOST
11273451c870SNick Mathewson     EVUTIL_AI_NUMERICHOST |
11283451c870SNick Mathewson #endif
11293451c870SNick Mathewson #ifndef AI_NUMERICSERV
11303451c870SNick Mathewson     EVUTIL_AI_NUMERICSERV |
11313451c870SNick Mathewson #endif
11323451c870SNick Mathewson #ifndef AI_ADDRCONFIG
11333451c870SNick Mathewson     EVUTIL_AI_ADDRCONFIG |
11343451c870SNick Mathewson #endif
11353451c870SNick Mathewson #ifndef AI_ALL
11363451c870SNick Mathewson     EVUTIL_AI_ALL |
11373451c870SNick Mathewson #endif
11383451c870SNick Mathewson #ifndef AI_V4MAPPED
11393451c870SNick Mathewson     EVUTIL_AI_V4MAPPED |
11403451c870SNick Mathewson #endif
11413451c870SNick Mathewson     EVUTIL_AI_LIBEVENT_ALLOCATED;
11423451c870SNick Mathewson 
11433451c870SNick Mathewson static const unsigned int ALL_NATIVE_AI_FLAGS =
11443451c870SNick Mathewson #ifdef AI_PASSIVE
11453451c870SNick Mathewson     AI_PASSIVE |
11463451c870SNick Mathewson #endif
11473451c870SNick Mathewson #ifdef AI_CANONNAME
11483451c870SNick Mathewson     AI_CANONNAME |
11493451c870SNick Mathewson #endif
11503451c870SNick Mathewson #ifdef AI_NUMERICHOST
11513451c870SNick Mathewson     AI_NUMERICHOST |
11523451c870SNick Mathewson #endif
11533451c870SNick Mathewson #ifdef AI_NUMERICSERV
11543451c870SNick Mathewson     AI_NUMERICSERV |
11553451c870SNick Mathewson #endif
11563451c870SNick Mathewson #ifdef AI_ADDRCONFIG
11573451c870SNick Mathewson     AI_ADDRCONFIG |
11583451c870SNick Mathewson #endif
11593451c870SNick Mathewson #ifdef AI_ALL
11603451c870SNick Mathewson     AI_ALL |
11613451c870SNick Mathewson #endif
11623451c870SNick Mathewson #ifdef AI_V4MAPPED
11633451c870SNick Mathewson     AI_V4MAPPED |
11643451c870SNick Mathewson #endif
11653451c870SNick Mathewson     0;
11663451c870SNick Mathewson #endif
11673451c870SNick Mathewson 
116886f57420SNick Mathewson #ifndef USE_NATIVE_GETADDRINFO
116986f57420SNick Mathewson /* Helper for systems with no getaddrinfo(): make one or more addrinfos out of
117086f57420SNick Mathewson  * a struct hostent.
117186f57420SNick Mathewson  */
117286f57420SNick Mathewson static struct evutil_addrinfo *
addrinfo_from_hostent(const struct hostent * ent,int port,const struct evutil_addrinfo * hints)117386f57420SNick Mathewson addrinfo_from_hostent(const struct hostent *ent,
117486f57420SNick Mathewson     int port, const struct evutil_addrinfo *hints)
117586f57420SNick Mathewson {
117686f57420SNick Mathewson 	int i;
117786f57420SNick Mathewson 	struct sockaddr_in sin;
117886f57420SNick Mathewson 	struct sockaddr_in6 sin6;
117986f57420SNick Mathewson 	struct sockaddr *sa;
118086f57420SNick Mathewson 	int socklen;
118186f57420SNick Mathewson 	struct evutil_addrinfo *res=NULL, *ai;
118286f57420SNick Mathewson 	void *addrp;
118386f57420SNick Mathewson 
118486f57420SNick Mathewson 	if (ent->h_addrtype == PF_INET) {
118586f57420SNick Mathewson 		memset(&sin, 0, sizeof(sin));
118686f57420SNick Mathewson 		sin.sin_family = AF_INET;
118786f57420SNick Mathewson 		sin.sin_port = htons(port);
118886f57420SNick Mathewson 		sa = (struct sockaddr *)&sin;
118986f57420SNick Mathewson 		socklen = sizeof(struct sockaddr_in);
119086f57420SNick Mathewson 		addrp = &sin.sin_addr;
119186f57420SNick Mathewson 		if (ent->h_length != sizeof(sin.sin_addr)) {
119286f57420SNick Mathewson 			event_warnx("Weird h_length from gethostbyname");
119386f57420SNick Mathewson 			return NULL;
119486f57420SNick Mathewson 		}
119586f57420SNick Mathewson 	} else if (ent->h_addrtype == PF_INET6) {
11960b9eb1bfSNick Mathewson 		memset(&sin6, 0, sizeof(sin6));
119786f57420SNick Mathewson 		sin6.sin6_family = AF_INET6;
119886f57420SNick Mathewson 		sin6.sin6_port = htons(port);
119986f57420SNick Mathewson 		sa = (struct sockaddr *)&sin6;
12003499ad97SMark Ellzey 		socklen = sizeof(struct sockaddr_in6);
120186f57420SNick Mathewson 		addrp = &sin6.sin6_addr;
120286f57420SNick Mathewson 		if (ent->h_length != sizeof(sin6.sin6_addr)) {
120386f57420SNick Mathewson 			event_warnx("Weird h_length from gethostbyname");
120486f57420SNick Mathewson 			return NULL;
120586f57420SNick Mathewson 		}
120686f57420SNick Mathewson 	} else
120786f57420SNick Mathewson 		return NULL;
120886f57420SNick Mathewson 
120986f57420SNick Mathewson 	for (i = 0; ent->h_addr_list[i]; ++i) {
121086f57420SNick Mathewson 		memcpy(addrp, ent->h_addr_list[i], ent->h_length);
12118ac3c4c2SNick Mathewson 		ai = evutil_new_addrinfo_(sa, socklen, hints);
121286f57420SNick Mathewson 		if (!ai) {
121386f57420SNick Mathewson 			evutil_freeaddrinfo(res);
121486f57420SNick Mathewson 			return NULL;
121586f57420SNick Mathewson 		}
12168ac3c4c2SNick Mathewson 		res = evutil_addrinfo_append_(res, ai);
121786f57420SNick Mathewson 	}
121886f57420SNick Mathewson 
1219666b0966SJardel Weyrich 	if (res && ((hints->ai_flags & EVUTIL_AI_CANONNAME) && ent->h_name)) {
122086f57420SNick Mathewson 		res->ai_canonname = mm_strdup(ent->h_name);
1221666b0966SJardel Weyrich 		if (res->ai_canonname == NULL) {
1222666b0966SJardel Weyrich 			evutil_freeaddrinfo(res);
1223666b0966SJardel Weyrich 			return NULL;
1224666b0966SJardel Weyrich 		}
1225666b0966SJardel Weyrich 	}
122686f57420SNick Mathewson 
122786f57420SNick Mathewson 	return res;
122886f57420SNick Mathewson }
122986f57420SNick Mathewson #endif
123086f57420SNick Mathewson 
123186f57420SNick Mathewson /* If the EVUTIL_AI_ADDRCONFIG flag is set on hints->ai_flags, and
123286f57420SNick Mathewson  * hints->ai_family is PF_UNSPEC, then revise the value of hints->ai_family so
123386f57420SNick Mathewson  * that we'll only get addresses we could maybe connect to.
123486f57420SNick Mathewson  */
123586f57420SNick Mathewson void
evutil_adjust_hints_for_addrconfig_(struct evutil_addrinfo * hints)12368ac3c4c2SNick Mathewson evutil_adjust_hints_for_addrconfig_(struct evutil_addrinfo *hints)
123786f57420SNick Mathewson {
123886f57420SNick Mathewson 	if (!(hints->ai_flags & EVUTIL_AI_ADDRCONFIG))
123986f57420SNick Mathewson 		return;
124086f57420SNick Mathewson 	if (hints->ai_family != PF_UNSPEC)
124186f57420SNick Mathewson 		return;
1242a09265acSAzat Khuzhin 	evutil_check_interfaces();
124386f57420SNick Mathewson 	if (had_ipv4_address && !had_ipv6_address) {
124486f57420SNick Mathewson 		hints->ai_family = PF_INET;
124586f57420SNick Mathewson 	} else if (!had_ipv4_address && had_ipv6_address) {
124686f57420SNick Mathewson 		hints->ai_family = PF_INET6;
124786f57420SNick Mathewson 	}
124886f57420SNick Mathewson }
124986f57420SNick Mathewson 
1250f070a4aeSNick Mathewson #ifdef USE_NATIVE_GETADDRINFO
12512cf2a286SNick Mathewson static int need_numeric_port_hack_=0;
12522cf2a286SNick Mathewson static int need_socktype_protocol_hack_=0;
12532cf2a286SNick Mathewson static int tested_for_getaddrinfo_hacks=0;
12542cf2a286SNick Mathewson 
1255f070a4aeSNick Mathewson /* Some older BSDs (like OpenBSD up to 4.6) used to believe that
1256f070a4aeSNick Mathewson    giving a numeric port without giving an ai_socktype was verboten.
1257f070a4aeSNick Mathewson    We test for this so we can apply an appropriate workaround.  If it
1258f070a4aeSNick Mathewson    turns out that the bug is present, then:
1259f070a4aeSNick Mathewson 
1260f070a4aeSNick Mathewson     - If nodename==NULL and servname is numeric, we build an answer
12618ac3c4c2SNick Mathewson       ourselves using evutil_getaddrinfo_common_().
1262f070a4aeSNick Mathewson 
1263f070a4aeSNick Mathewson     - If nodename!=NULL and servname is numeric, then we set
1264f070a4aeSNick Mathewson       servname=NULL when calling getaddrinfo, and post-process the
1265f070a4aeSNick Mathewson       result to set the ports on it.
1266f070a4aeSNick Mathewson 
1267f070a4aeSNick Mathewson    We test for this bug at runtime, since otherwise we can't have the
1268f070a4aeSNick Mathewson    same binary run on multiple BSD versions.
12692cf2a286SNick Mathewson 
12702cf2a286SNick Mathewson    - Some versions of Solaris believe that it's nice to leave to protocol
12712cf2a286SNick Mathewson      field set to 0.  We test for this so we can apply an appropriate
12722cf2a286SNick Mathewson      workaround.
1273f070a4aeSNick Mathewson */
ai_find_protocol(struct evutil_addrinfo * ai)12745a157c87SAzat Khuzhin static struct evutil_addrinfo *ai_find_protocol(struct evutil_addrinfo *ai)
127540730ae3SAzat Khuzhin {
127640730ae3SAzat Khuzhin 	while (ai) {
127740730ae3SAzat Khuzhin 		if (ai->ai_protocol)
127840730ae3SAzat Khuzhin 			return ai;
127940730ae3SAzat Khuzhin 		ai = ai->ai_next;
128040730ae3SAzat Khuzhin 	}
128140730ae3SAzat Khuzhin 	return NULL;
128240730ae3SAzat Khuzhin }
12832cf2a286SNick Mathewson static void
test_for_getaddrinfo_hacks(void)12842cf2a286SNick Mathewson test_for_getaddrinfo_hacks(void)
1285f070a4aeSNick Mathewson {
1286f070a4aeSNick Mathewson 	int r, r2;
128740730ae3SAzat Khuzhin 	struct evutil_addrinfo *ai=NULL, *ai2=NULL, *ai3=NULL;
1288f070a4aeSNick Mathewson 	struct evutil_addrinfo hints;
1289f070a4aeSNick Mathewson 
1290f070a4aeSNick Mathewson 	memset(&hints,0,sizeof(hints));
1291f070a4aeSNick Mathewson 	hints.ai_family = PF_UNSPEC;
1292f070a4aeSNick Mathewson 	hints.ai_flags =
1293f070a4aeSNick Mathewson #ifdef AI_NUMERICHOST
1294f070a4aeSNick Mathewson 	    AI_NUMERICHOST |
1295f070a4aeSNick Mathewson #endif
1296f070a4aeSNick Mathewson #ifdef AI_NUMERICSERV
1297f070a4aeSNick Mathewson 	    AI_NUMERICSERV |
1298f070a4aeSNick Mathewson #endif
1299f070a4aeSNick Mathewson 	    0;
1300f070a4aeSNick Mathewson 	r = getaddrinfo("1.2.3.4", "80", &hints, &ai);
130140730ae3SAzat Khuzhin 	getaddrinfo("1.2.3.4", NULL, &hints, &ai3);
1302f070a4aeSNick Mathewson 	hints.ai_socktype = SOCK_STREAM;
1303f070a4aeSNick Mathewson 	r2 = getaddrinfo("1.2.3.4", "80", &hints, &ai2);
1304f070a4aeSNick Mathewson 	if (r2 == 0 && r != 0) {
13052cf2a286SNick Mathewson 		need_numeric_port_hack_=1;
1306f070a4aeSNick Mathewson 	}
130740730ae3SAzat Khuzhin 	if (!ai_find_protocol(ai2) || !ai_find_protocol(ai3)) {
13082cf2a286SNick Mathewson 		need_socktype_protocol_hack_=1;
13092cf2a286SNick Mathewson 	}
13102cf2a286SNick Mathewson 
1311f070a4aeSNick Mathewson 	if (ai)
1312f070a4aeSNick Mathewson 		freeaddrinfo(ai);
1313f070a4aeSNick Mathewson 	if (ai2)
1314f070a4aeSNick Mathewson 		freeaddrinfo(ai2);
131540730ae3SAzat Khuzhin 	if (ai3)
131640730ae3SAzat Khuzhin 		freeaddrinfo(ai3);
13172cf2a286SNick Mathewson 	tested_for_getaddrinfo_hacks=1;
13182cf2a286SNick Mathewson }
13192cf2a286SNick Mathewson 
13202cf2a286SNick Mathewson static inline int
need_numeric_port_hack(void)13212cf2a286SNick Mathewson need_numeric_port_hack(void)
13222cf2a286SNick Mathewson {
13232cf2a286SNick Mathewson 	if (!tested_for_getaddrinfo_hacks)
13242cf2a286SNick Mathewson 		test_for_getaddrinfo_hacks();
13252cf2a286SNick Mathewson 	return need_numeric_port_hack_;
13262cf2a286SNick Mathewson }
13272cf2a286SNick Mathewson 
13282cf2a286SNick Mathewson static inline int
need_socktype_protocol_hack(void)13292cf2a286SNick Mathewson need_socktype_protocol_hack(void)
13302cf2a286SNick Mathewson {
13312cf2a286SNick Mathewson 	if (!tested_for_getaddrinfo_hacks)
13322cf2a286SNick Mathewson 		test_for_getaddrinfo_hacks();
13332cf2a286SNick Mathewson 	return need_socktype_protocol_hack_;
1334f070a4aeSNick Mathewson }
1335f070a4aeSNick Mathewson 
1336f070a4aeSNick Mathewson static void
apply_numeric_port_hack(int port,struct evutil_addrinfo ** ai)1337f070a4aeSNick Mathewson apply_numeric_port_hack(int port, struct evutil_addrinfo **ai)
1338f070a4aeSNick Mathewson {
1339f070a4aeSNick Mathewson 	/* Now we run through the list and set the ports on all of the
13402cf2a286SNick Mathewson 	 * results where ports would make sense. */
1341f070a4aeSNick Mathewson 	for ( ; *ai; ai = &(*ai)->ai_next) {
1342f070a4aeSNick Mathewson 		struct sockaddr *sa = (*ai)->ai_addr;
1343f070a4aeSNick Mathewson 		if (sa && sa->sa_family == AF_INET) {
1344f070a4aeSNick Mathewson 			struct sockaddr_in *sin = (struct sockaddr_in*)sa;
1345f070a4aeSNick Mathewson 			sin->sin_port = htons(port);
1346f070a4aeSNick Mathewson 		} else if (sa && sa->sa_family == AF_INET6) {
1347f070a4aeSNick Mathewson 			struct sockaddr_in6 *sin6 = (struct sockaddr_in6*)sa;
1348f070a4aeSNick Mathewson 			sin6->sin6_port = htons(port);
1349f070a4aeSNick Mathewson 		} else {
1350f070a4aeSNick Mathewson 			/* A numeric port makes no sense here; remove this one
1351f070a4aeSNick Mathewson 			 * from the list. */
1352f070a4aeSNick Mathewson 			struct evutil_addrinfo *victim = *ai;
1353f070a4aeSNick Mathewson 			*ai = victim->ai_next;
1354f070a4aeSNick Mathewson 			victim->ai_next = NULL;
1355f070a4aeSNick Mathewson 			freeaddrinfo(victim);
1356f070a4aeSNick Mathewson 		}
1357f070a4aeSNick Mathewson 	}
1358f070a4aeSNick Mathewson }
135935570716SNick Mathewson 
1360637d17a1SNick Mathewson static int
apply_socktype_protocol_hack(struct evutil_addrinfo * ai)136135570716SNick Mathewson apply_socktype_protocol_hack(struct evutil_addrinfo *ai)
136235570716SNick Mathewson {
136335570716SNick Mathewson 	struct evutil_addrinfo *ai_new;
136435570716SNick Mathewson 	for (; ai; ai = ai->ai_next) {
136535570716SNick Mathewson 		evutil_getaddrinfo_infer_protocols(ai);
136635570716SNick Mathewson 		if (ai->ai_socktype || ai->ai_protocol)
136735570716SNick Mathewson 			continue;
136835570716SNick Mathewson 		ai_new = mm_malloc(sizeof(*ai_new));
1369637d17a1SNick Mathewson 		if (!ai_new)
1370637d17a1SNick Mathewson 			return -1;
137135570716SNick Mathewson 		memcpy(ai_new, ai, sizeof(*ai_new));
137235570716SNick Mathewson 		ai->ai_socktype = SOCK_STREAM;
137335570716SNick Mathewson 		ai->ai_protocol = IPPROTO_TCP;
137435570716SNick Mathewson 		ai_new->ai_socktype = SOCK_DGRAM;
137535570716SNick Mathewson 		ai_new->ai_protocol = IPPROTO_UDP;
137635570716SNick Mathewson 
137735570716SNick Mathewson 		ai_new->ai_next = ai->ai_next;
137835570716SNick Mathewson 		ai->ai_next = ai_new;
137935570716SNick Mathewson 	}
1380637d17a1SNick Mathewson 	return 0;
138135570716SNick Mathewson }
1382f070a4aeSNick Mathewson #endif
1383f070a4aeSNick Mathewson 
138486f57420SNick Mathewson int
evutil_getaddrinfo(const char * nodename,const char * servname,const struct evutil_addrinfo * hints_in,struct evutil_addrinfo ** res)138586f57420SNick Mathewson evutil_getaddrinfo(const char *nodename, const char *servname,
138686f57420SNick Mathewson     const struct evutil_addrinfo *hints_in, struct evutil_addrinfo **res)
138786f57420SNick Mathewson {
138886f57420SNick Mathewson #ifdef USE_NATIVE_GETADDRINFO
138986f57420SNick Mathewson 	struct evutil_addrinfo hints;
1390f070a4aeSNick Mathewson 	int portnum=-1, need_np_hack, err;
1391f070a4aeSNick Mathewson 
139286f57420SNick Mathewson 	if (hints_in) {
139386f57420SNick Mathewson 		memcpy(&hints, hints_in, sizeof(hints));
1394f070a4aeSNick Mathewson 	} else {
1395f070a4aeSNick Mathewson 		memset(&hints, 0, sizeof(hints));
1396f070a4aeSNick Mathewson 		hints.ai_family = PF_UNSPEC;
1397f070a4aeSNick Mathewson 	}
139886f57420SNick Mathewson 
139986f57420SNick Mathewson #ifndef AI_ADDRCONFIG
140086f57420SNick Mathewson 	/* Not every system has AI_ADDRCONFIG, so fake it. */
140186f57420SNick Mathewson 	if (hints.ai_family == PF_UNSPEC &&
140286f57420SNick Mathewson 	    (hints.ai_flags & EVUTIL_AI_ADDRCONFIG)) {
14038ac3c4c2SNick Mathewson 		evutil_adjust_hints_for_addrconfig_(&hints);
140486f57420SNick Mathewson 	}
140586f57420SNick Mathewson #endif
140686f57420SNick Mathewson 
1407f070a4aeSNick Mathewson #ifndef AI_NUMERICSERV
140886f57420SNick Mathewson 	/* Not every system has AI_NUMERICSERV, so fake it. */
140986f57420SNick Mathewson 	if (hints.ai_flags & EVUTIL_AI_NUMERICSERV) {
1410f070a4aeSNick Mathewson 		if (servname && parse_numeric_servname(servname)<0)
141186f57420SNick Mathewson 			return EVUTIL_EAI_NONAME;
141286f57420SNick Mathewson 	}
141386f57420SNick Mathewson #endif
141486f57420SNick Mathewson 
14159151d000SNick Mathewson 	/* Enough operating systems handle enough common non-resolve
14169151d000SNick Mathewson 	 * cases here weirdly enough that we are better off just
14179151d000SNick Mathewson 	 * overriding them.  For example:
1418201d8d0bSNick Mathewson 	 *
1419201d8d0bSNick Mathewson 	 * - Windows doesn't like to infer the protocol from the
1420201d8d0bSNick Mathewson 	 *   socket type, or fill in socket or protocol types much at
1421201d8d0bSNick Mathewson 	 *   all.  It also seems to do its own broken implicit
1422201d8d0bSNick Mathewson 	 *   always-on version of AI_ADDRCONFIG that keeps it from
1423201d8d0bSNick Mathewson 	 *   ever resolving even a literal IPv6 address when
1424201d8d0bSNick Mathewson 	 *   ai_addrtype is PF_UNSPEC.
14259151d000SNick Mathewson 	 */
14269f560bfaSNick Mathewson #ifdef _WIN32
142786f57420SNick Mathewson 	{
1428f070a4aeSNick Mathewson 		int tmp_port;
14298ac3c4c2SNick Mathewson 		err = evutil_getaddrinfo_common_(nodename,servname,&hints,
1430f070a4aeSNick Mathewson 		    res, &tmp_port);
14319151d000SNick Mathewson 		if (err == 0 ||
14329151d000SNick Mathewson 		    err == EVUTIL_EAI_MEMORY ||
14339151d000SNick Mathewson 		    err == EVUTIL_EAI_NONAME)
143486f57420SNick Mathewson 			return err;
14359151d000SNick Mathewson 		/* If we make it here, the system getaddrinfo can
14369151d000SNick Mathewson 		 * have a crack at it. */
143786f57420SNick Mathewson 	}
1438f070a4aeSNick Mathewson #endif
14399151d000SNick Mathewson 
1440f070a4aeSNick Mathewson 	/* See documentation for need_numeric_port_hack above.*/
1441f070a4aeSNick Mathewson 	need_np_hack = need_numeric_port_hack() && servname && !hints.ai_socktype
1442f070a4aeSNick Mathewson 	    && ((portnum=parse_numeric_servname(servname)) >= 0);
1443f070a4aeSNick Mathewson 	if (need_np_hack) {
1444f070a4aeSNick Mathewson 		if (!nodename)
14458ac3c4c2SNick Mathewson 			return evutil_getaddrinfo_common_(
1446f070a4aeSNick Mathewson 				NULL,servname,&hints, res, &portnum);
1447f070a4aeSNick Mathewson 		servname = NULL;
144886f57420SNick Mathewson 	}
144986f57420SNick Mathewson 
14502cf2a286SNick Mathewson 	if (need_socktype_protocol_hack()) {
14512cf2a286SNick Mathewson 		evutil_getaddrinfo_infer_protocols(&hints);
14522cf2a286SNick Mathewson 	}
14532cf2a286SNick Mathewson 
14543451c870SNick Mathewson 	/* Make sure that we didn't actually steal any AI_FLAGS values that
14553451c870SNick Mathewson 	 * the system is using.  (This is a constant expression, and should ge
14563451c870SNick Mathewson 	 * optimized out.)
14573451c870SNick Mathewson 	 *
14583451c870SNick Mathewson 	 * XXXX Turn this into a compile-time failure rather than a run-time
14593451c870SNick Mathewson 	 * failure.
14603451c870SNick Mathewson 	 */
14613451c870SNick Mathewson 	EVUTIL_ASSERT((ALL_NONNATIVE_AI_FLAGS & ALL_NATIVE_AI_FLAGS) == 0);
14623451c870SNick Mathewson 
14633451c870SNick Mathewson 	/* Clear any flags that only libevent understands. */
14643451c870SNick Mathewson 	hints.ai_flags &= ~ALL_NONNATIVE_AI_FLAGS;
14653451c870SNick Mathewson 
1466f070a4aeSNick Mathewson 	err = getaddrinfo(nodename, servname, &hints, res);
1467f070a4aeSNick Mathewson 	if (need_np_hack)
1468f070a4aeSNick Mathewson 		apply_numeric_port_hack(portnum, res);
14692cf2a286SNick Mathewson 
14702cf2a286SNick Mathewson 	if (need_socktype_protocol_hack()) {
1471637d17a1SNick Mathewson 		if (apply_socktype_protocol_hack(*res) < 0) {
1472637d17a1SNick Mathewson 			evutil_freeaddrinfo(*res);
1473637d17a1SNick Mathewson 			*res = NULL;
1474637d17a1SNick Mathewson 			return EVUTIL_EAI_MEMORY;
1475637d17a1SNick Mathewson 		}
14762cf2a286SNick Mathewson 	}
1477f070a4aeSNick Mathewson 	return err;
147886f57420SNick Mathewson #else
147986f57420SNick Mathewson 	int port=0, err;
148086f57420SNick Mathewson 	struct hostent *ent = NULL;
148186f57420SNick Mathewson 	struct evutil_addrinfo hints;
148286f57420SNick Mathewson 
148386f57420SNick Mathewson 	if (hints_in) {
148486f57420SNick Mathewson 		memcpy(&hints, hints_in, sizeof(hints));
14850b9eb1bfSNick Mathewson 	} else {
148686f57420SNick Mathewson 		memset(&hints, 0, sizeof(hints));
148786f57420SNick Mathewson 		hints.ai_family = PF_UNSPEC;
14880b9eb1bfSNick Mathewson 	}
148986f57420SNick Mathewson 
14908ac3c4c2SNick Mathewson 	evutil_adjust_hints_for_addrconfig_(&hints);
149186f57420SNick Mathewson 
14928ac3c4c2SNick Mathewson 	err = evutil_getaddrinfo_common_(nodename, servname, &hints, res, &port);
149386f57420SNick Mathewson 	if (err != EVUTIL_EAI_NEED_RESOLVE) {
149486f57420SNick Mathewson 		/* We either succeeded or failed.  No need to continue */
149586f57420SNick Mathewson 		return err;
14960b9eb1bfSNick Mathewson 	}
149786f57420SNick Mathewson 
149886f57420SNick Mathewson 	err = 0;
149986f57420SNick Mathewson 	/* Use any of the various gethostbyname_r variants as available. */
150086f57420SNick Mathewson 	{
150168120d9bSNick Mathewson #ifdef EVENT__HAVE_GETHOSTBYNAME_R_6_ARG
150286f57420SNick Mathewson 		/* This one is what glibc provides. */
150386f57420SNick Mathewson 		char buf[2048];
150486f57420SNick Mathewson 		struct hostent hostent;
150586f57420SNick Mathewson 		int r;
150686f57420SNick Mathewson 		r = gethostbyname_r(nodename, &hostent, buf, sizeof(buf), &ent,
150786f57420SNick Mathewson 		    &err);
150868120d9bSNick Mathewson #elif defined(EVENT__HAVE_GETHOSTBYNAME_R_5_ARG)
150986f57420SNick Mathewson 		char buf[2048];
151086f57420SNick Mathewson 		struct hostent hostent;
151186f57420SNick Mathewson 		ent = gethostbyname_r(nodename, &hostent, buf, sizeof(buf),
151286f57420SNick Mathewson 		    &err);
151368120d9bSNick Mathewson #elif defined(EVENT__HAVE_GETHOSTBYNAME_R_3_ARG)
151486f57420SNick Mathewson 		struct hostent_data data;
151586f57420SNick Mathewson 		struct hostent hostent;
151686f57420SNick Mathewson 		memset(&data, 0, sizeof(data));
151786f57420SNick Mathewson 		err = gethostbyname_r(nodename, &hostent, &data);
151886f57420SNick Mathewson 		ent = err ? NULL : &hostent;
151986f57420SNick Mathewson #else
152086f57420SNick Mathewson 		/* fall back to gethostbyname. */
152186f57420SNick Mathewson 		/* XXXX This needs a lock everywhere but Windows. */
152286f57420SNick Mathewson 		ent = gethostbyname(nodename);
15239f560bfaSNick Mathewson #ifdef _WIN32
152486f57420SNick Mathewson 		err = WSAGetLastError();
152586f57420SNick Mathewson #else
152686f57420SNick Mathewson 		err = h_errno;
152786f57420SNick Mathewson #endif
152886f57420SNick Mathewson #endif
152986f57420SNick Mathewson 
153086f57420SNick Mathewson 		/* Now we have either ent or err set. */
153186f57420SNick Mathewson 		if (!ent) {
153286f57420SNick Mathewson 			/* XXX is this right for windows ? */
153386f57420SNick Mathewson 			switch (err) {
153486f57420SNick Mathewson 			case TRY_AGAIN:
153586f57420SNick Mathewson 				return EVUTIL_EAI_AGAIN;
153686f57420SNick Mathewson 			case NO_RECOVERY:
153786f57420SNick Mathewson 			default:
153886f57420SNick Mathewson 				return EVUTIL_EAI_FAIL;
153986f57420SNick Mathewson 			case HOST_NOT_FOUND:
154086f57420SNick Mathewson 				return EVUTIL_EAI_NONAME;
154186f57420SNick Mathewson 			case NO_ADDRESS:
154286f57420SNick Mathewson #if NO_DATA != NO_ADDRESS
154386f57420SNick Mathewson 			case NO_DATA:
154486f57420SNick Mathewson #endif
154586f57420SNick Mathewson 				return EVUTIL_EAI_NODATA;
154686f57420SNick Mathewson 			}
154786f57420SNick Mathewson 		}
154886f57420SNick Mathewson 
154986f57420SNick Mathewson 		if (ent->h_addrtype != hints.ai_family &&
155086f57420SNick Mathewson 		    hints.ai_family != PF_UNSPEC) {
155186f57420SNick Mathewson 			/* This wasn't the type we were hoping for.  Too bad
155286f57420SNick Mathewson 			 * we never had a chance to ask gethostbyname for what
155386f57420SNick Mathewson 			 * we wanted. */
155486f57420SNick Mathewson 			return EVUTIL_EAI_NONAME;
155586f57420SNick Mathewson 		}
155686f57420SNick Mathewson 
155786f57420SNick Mathewson 		/* Make sure we got _some_ answers. */
155886f57420SNick Mathewson 		if (ent->h_length == 0)
155986f57420SNick Mathewson 			return EVUTIL_EAI_NODATA;
156086f57420SNick Mathewson 
156186f57420SNick Mathewson 		/* If we got an address type we don't know how to make a
156286f57420SNick Mathewson 		   sockaddr for, give up. */
156386f57420SNick Mathewson 		if (ent->h_addrtype != PF_INET && ent->h_addrtype != PF_INET6)
156486f57420SNick Mathewson 			return EVUTIL_EAI_FAMILY;
156586f57420SNick Mathewson 
156686f57420SNick Mathewson 		*res = addrinfo_from_hostent(ent, port, &hints);
156786f57420SNick Mathewson 		if (! *res)
156886f57420SNick Mathewson 			return EVUTIL_EAI_MEMORY;
156986f57420SNick Mathewson 	}
157086f57420SNick Mathewson 
15710b9eb1bfSNick Mathewson 	return 0;
15720b9eb1bfSNick Mathewson #endif
15730b9eb1bfSNick Mathewson }
15740b9eb1bfSNick Mathewson 
157586f57420SNick Mathewson void
evutil_freeaddrinfo(struct evutil_addrinfo * ai)157686f57420SNick Mathewson evutil_freeaddrinfo(struct evutil_addrinfo *ai)
157786f57420SNick Mathewson {
157868120d9bSNick Mathewson #ifdef EVENT__HAVE_GETADDRINFO
157986f57420SNick Mathewson 	if (!(ai->ai_flags & EVUTIL_AI_LIBEVENT_ALLOCATED)) {
158086f57420SNick Mathewson 		freeaddrinfo(ai);
158186f57420SNick Mathewson 		return;
158286f57420SNick Mathewson 	}
158386f57420SNick Mathewson #endif
158486f57420SNick Mathewson 	while (ai) {
158586f57420SNick Mathewson 		struct evutil_addrinfo *next = ai->ai_next;
158686f57420SNick Mathewson 		if (ai->ai_canonname)
158786f57420SNick Mathewson 			mm_free(ai->ai_canonname);
158886f57420SNick Mathewson 		mm_free(ai);
158986f57420SNick Mathewson 		ai = next;
159086f57420SNick Mathewson 	}
159186f57420SNick Mathewson }
159286f57420SNick Mathewson 
159386f57420SNick Mathewson static evdns_getaddrinfo_fn evdns_getaddrinfo_impl = NULL;
15948cbe65d5SAzat Khuzhin static evdns_getaddrinfo_cancel_fn evdns_getaddrinfo_cancel_impl = NULL;
159586f57420SNick Mathewson 
159686f57420SNick Mathewson void
evutil_set_evdns_getaddrinfo_fn_(evdns_getaddrinfo_fn fn)15978ac3c4c2SNick Mathewson evutil_set_evdns_getaddrinfo_fn_(evdns_getaddrinfo_fn fn)
159886f57420SNick Mathewson {
159986f57420SNick Mathewson 	if (!evdns_getaddrinfo_impl)
160086f57420SNick Mathewson 		evdns_getaddrinfo_impl = fn;
160186f57420SNick Mathewson }
16028cbe65d5SAzat Khuzhin void
evutil_set_evdns_getaddrinfo_cancel_fn_(evdns_getaddrinfo_cancel_fn fn)16038cbe65d5SAzat Khuzhin evutil_set_evdns_getaddrinfo_cancel_fn_(evdns_getaddrinfo_cancel_fn fn)
16048cbe65d5SAzat Khuzhin {
16058cbe65d5SAzat Khuzhin 	if (!evdns_getaddrinfo_cancel_impl)
16068cbe65d5SAzat Khuzhin 		evdns_getaddrinfo_cancel_impl = fn;
16078cbe65d5SAzat Khuzhin }
160886f57420SNick Mathewson 
160986f57420SNick Mathewson /* Internal helper function: act like evdns_getaddrinfo if dns_base is set;
161086f57420SNick Mathewson  * otherwise do a blocking resolve and pass the result to the callback in the
161186f57420SNick Mathewson  * way that evdns_getaddrinfo would.
161286f57420SNick Mathewson  */
evutil_getaddrinfo_async_(struct evdns_base * dns_base,const char * nodename,const char * servname,const struct evutil_addrinfo * hints_in,void (* cb)(int,struct evutil_addrinfo *,void *),void * arg)16138cbe65d5SAzat Khuzhin struct evdns_getaddrinfo_request *evutil_getaddrinfo_async_(
16148cbe65d5SAzat Khuzhin     struct evdns_base *dns_base,
161586f57420SNick Mathewson     const char *nodename, const char *servname,
161686f57420SNick Mathewson     const struct evutil_addrinfo *hints_in,
161786f57420SNick Mathewson     void (*cb)(int, struct evutil_addrinfo *, void *), void *arg)
161886f57420SNick Mathewson {
161986f57420SNick Mathewson 	if (dns_base && evdns_getaddrinfo_impl) {
16208cbe65d5SAzat Khuzhin 		return evdns_getaddrinfo_impl(
162186f57420SNick Mathewson 			dns_base, nodename, servname, hints_in, cb, arg);
162286f57420SNick Mathewson 	} else {
162386f57420SNick Mathewson 		struct evutil_addrinfo *ai=NULL;
162486f57420SNick Mathewson 		int err;
162586f57420SNick Mathewson 		err = evutil_getaddrinfo(nodename, servname, hints_in, &ai);
162686f57420SNick Mathewson 		cb(err, ai, arg);
16278cbe65d5SAzat Khuzhin 		return NULL;
162886f57420SNick Mathewson 	}
16298cbe65d5SAzat Khuzhin }
16308cbe65d5SAzat Khuzhin 
evutil_getaddrinfo_cancel_async_(struct evdns_getaddrinfo_request * data)16318cbe65d5SAzat Khuzhin void evutil_getaddrinfo_cancel_async_(struct evdns_getaddrinfo_request *data)
16328cbe65d5SAzat Khuzhin {
16338cbe65d5SAzat Khuzhin 	if (evdns_getaddrinfo_cancel_impl && data) {
16348cbe65d5SAzat Khuzhin 		evdns_getaddrinfo_cancel_impl(data);
16358cbe65d5SAzat Khuzhin 	}
163686f57420SNick Mathewson }
163786f57420SNick Mathewson 
163886f57420SNick Mathewson const char *
evutil_gai_strerror(int err)163986f57420SNick Mathewson evutil_gai_strerror(int err)
164086f57420SNick Mathewson {
16416810bdb1SNick Mathewson 	/* As a sneaky side-benefit, this case statement will get most
16426810bdb1SNick Mathewson 	 * compilers to tell us if any of the error codes we defined
16436810bdb1SNick Mathewson 	 * conflict with the platform's native error codes. */
164486f57420SNick Mathewson 	switch (err) {
16456810bdb1SNick Mathewson 	case EVUTIL_EAI_CANCEL:
164649418612SNick Mathewson 		return "Request canceled";
16476810bdb1SNick Mathewson 	case 0:
16486810bdb1SNick Mathewson 		return "No error";
16496810bdb1SNick Mathewson 
165086f57420SNick Mathewson 	case EVUTIL_EAI_ADDRFAMILY:
165186f57420SNick Mathewson 		return "address family for nodename not supported";
165286f57420SNick Mathewson 	case EVUTIL_EAI_AGAIN:
165386f57420SNick Mathewson 		return "temporary failure in name resolution";
165486f57420SNick Mathewson 	case EVUTIL_EAI_BADFLAGS:
165586f57420SNick Mathewson 		return "invalid value for ai_flags";
165686f57420SNick Mathewson 	case EVUTIL_EAI_FAIL:
165786f57420SNick Mathewson 		return "non-recoverable failure in name resolution";
165886f57420SNick Mathewson 	case EVUTIL_EAI_FAMILY:
165986f57420SNick Mathewson 		return "ai_family not supported";
166086f57420SNick Mathewson 	case EVUTIL_EAI_MEMORY:
166186f57420SNick Mathewson 		return "memory allocation failure";
166286f57420SNick Mathewson 	case EVUTIL_EAI_NODATA:
166386f57420SNick Mathewson 		return "no address associated with nodename";
166486f57420SNick Mathewson 	case EVUTIL_EAI_NONAME:
166586f57420SNick Mathewson 		return "nodename nor servname provided, or not known";
166686f57420SNick Mathewson 	case EVUTIL_EAI_SERVICE:
166786f57420SNick Mathewson 		return "servname not supported for ai_socktype";
166886f57420SNick Mathewson 	case EVUTIL_EAI_SOCKTYPE:
166986f57420SNick Mathewson 		return "ai_socktype not supported";
16706810bdb1SNick Mathewson 	case EVUTIL_EAI_SYSTEM:
16716810bdb1SNick Mathewson 		return "system error";
167286f57420SNick Mathewson 	default:
16739f560bfaSNick Mathewson #if defined(USE_NATIVE_GETADDRINFO) && defined(_WIN32)
1674b677032bSBrodie Thiesfield 		return gai_strerrorA(err);
1675b677032bSBrodie Thiesfield #elif defined(USE_NATIVE_GETADDRINFO)
16766810bdb1SNick Mathewson 		return gai_strerror(err);
16776810bdb1SNick Mathewson #else
167886f57420SNick Mathewson 		return "Unknown error code";
167986f57420SNick Mathewson #endif
168086f57420SNick Mathewson 	}
168186f57420SNick Mathewson }
168286f57420SNick Mathewson 
16839f560bfaSNick Mathewson #ifdef _WIN32
16840c6ec5d8SPatrick Pelletier /* destructively remove a trailing line terminator from s */
16850c6ec5d8SPatrick Pelletier static void
chomp(char * s)16860c6ec5d8SPatrick Pelletier chomp (char *s)
16870c6ec5d8SPatrick Pelletier {
16880c6ec5d8SPatrick Pelletier 	size_t len;
16890c6ec5d8SPatrick Pelletier 	if (s && (len = strlen (s)) > 0 && s[len - 1] == '\n') {
16900c6ec5d8SPatrick Pelletier 		s[--len] = 0;
16910c6ec5d8SPatrick Pelletier 		if (len > 0 && s[len - 1] == '\r')
16920c6ec5d8SPatrick Pelletier 			s[--len] = 0;
16930c6ec5d8SPatrick Pelletier 	}
16940c6ec5d8SPatrick Pelletier }
1695de069b99SNick Mathewson 
16960c6ec5d8SPatrick Pelletier /* FormatMessage returns allocated strings, but evutil_socket_error_to_string
16970c6ec5d8SPatrick Pelletier  * is supposed to return a string which is good indefinitely without having
16980c6ec5d8SPatrick Pelletier  * to be freed.  To make this work without leaking memory, we cache the
16990c6ec5d8SPatrick Pelletier  * string the first time FormatMessage is called on a particular error
17000c6ec5d8SPatrick Pelletier  * code, and then return the cached string on subsequent calls with the
17010c6ec5d8SPatrick Pelletier  * same code.  The strings aren't freed until libevent_global_shutdown
17020c6ec5d8SPatrick Pelletier  * (or never).  We use a linked list to cache the errors, because we
17030c6ec5d8SPatrick Pelletier  * only expect there to be a few dozen, and that should be fast enough.
1704de069b99SNick Mathewson  */
17050c6ec5d8SPatrick Pelletier 
17064ccdd53fSPatrick Pelletier struct cached_sock_errs_entry {
17074ccdd53fSPatrick Pelletier 	HT_ENTRY(cached_sock_errs_entry) node;
17080c6ec5d8SPatrick Pelletier 	DWORD code;
17090c6ec5d8SPatrick Pelletier 	char *msg; /* allocated with LocalAlloc; free with LocalFree */
1710de069b99SNick Mathewson };
17110c6ec5d8SPatrick Pelletier 
17124ccdd53fSPatrick Pelletier static inline unsigned
hash_cached_sock_errs(const struct cached_sock_errs_entry * e)17134ccdd53fSPatrick Pelletier hash_cached_sock_errs(const struct cached_sock_errs_entry *e)
17144ccdd53fSPatrick Pelletier {
17154ccdd53fSPatrick Pelletier 	/* Use Murmur3's 32-bit finalizer as an integer hash function */
17164ccdd53fSPatrick Pelletier 	DWORD h = e->code;
17174ccdd53fSPatrick Pelletier 	h ^= h >> 16;
17184ccdd53fSPatrick Pelletier 	h *= 0x85ebca6b;
17194ccdd53fSPatrick Pelletier 	h ^= h >> 13;
17204ccdd53fSPatrick Pelletier 	h *= 0xc2b2ae35;
17214ccdd53fSPatrick Pelletier 	h ^= h >> 16;
17224ccdd53fSPatrick Pelletier 	return h;
17234ccdd53fSPatrick Pelletier }
17244ccdd53fSPatrick Pelletier 
17254ccdd53fSPatrick Pelletier static inline int
eq_cached_sock_errs(const struct cached_sock_errs_entry * a,const struct cached_sock_errs_entry * b)17264ccdd53fSPatrick Pelletier eq_cached_sock_errs(const struct cached_sock_errs_entry *a,
17274ccdd53fSPatrick Pelletier 		    const struct cached_sock_errs_entry *b)
17284ccdd53fSPatrick Pelletier {
17294ccdd53fSPatrick Pelletier 	return a->code == b->code;
17304ccdd53fSPatrick Pelletier }
17314ccdd53fSPatrick Pelletier 
17320c6ec5d8SPatrick Pelletier #ifndef EVENT__DISABLE_THREAD_SUPPORT
17330c6ec5d8SPatrick Pelletier static void *windows_socket_errors_lock_ = NULL;
17340c6ec5d8SPatrick Pelletier #endif
17350c6ec5d8SPatrick Pelletier 
17364ccdd53fSPatrick Pelletier static HT_HEAD(cached_sock_errs_map, cached_sock_errs_entry)
17374ccdd53fSPatrick Pelletier      windows_socket_errors = HT_INITIALIZER();
17384ccdd53fSPatrick Pelletier 
17394ccdd53fSPatrick Pelletier HT_PROTOTYPE(cached_sock_errs_map,
17404ccdd53fSPatrick Pelletier 	     cached_sock_errs_entry,
17414ccdd53fSPatrick Pelletier 	     node,
17424ccdd53fSPatrick Pelletier 	     hash_cached_sock_errs,
17434ccdd53fSPatrick Pelletier 	     eq_cached_sock_errs);
17444ccdd53fSPatrick Pelletier 
17454ccdd53fSPatrick Pelletier HT_GENERATE(cached_sock_errs_map,
17464ccdd53fSPatrick Pelletier 	    cached_sock_errs_entry,
17474ccdd53fSPatrick Pelletier 	    node,
17484ccdd53fSPatrick Pelletier 	    hash_cached_sock_errs,
17494ccdd53fSPatrick Pelletier 	    eq_cached_sock_errs,
17504ccdd53fSPatrick Pelletier 	    0.5,
17514ccdd53fSPatrick Pelletier 	    mm_malloc,
17524ccdd53fSPatrick Pelletier 	    mm_realloc,
17534ccdd53fSPatrick Pelletier 	    mm_free);
17540c6ec5d8SPatrick Pelletier 
1755de069b99SNick Mathewson /** Equivalent to strerror, but for windows socket errors. */
1756de069b99SNick Mathewson const char *
evutil_socket_error_to_string(int errcode)1757de069b99SNick Mathewson evutil_socket_error_to_string(int errcode)
1758de069b99SNick Mathewson {
17594ccdd53fSPatrick Pelletier 	struct cached_sock_errs_entry *errs, *newerr, find;
17600c6ec5d8SPatrick Pelletier 	char *msg = NULL;
17610c6ec5d8SPatrick Pelletier 
17620c6ec5d8SPatrick Pelletier 	EVLOCK_LOCK(windows_socket_errors_lock_, 0);
17630c6ec5d8SPatrick Pelletier 
17644ccdd53fSPatrick Pelletier 	find.code = errcode;
17654ccdd53fSPatrick Pelletier 	errs = HT_FIND(cached_sock_errs_map, &windows_socket_errors, &find);
17664ccdd53fSPatrick Pelletier 	if (errs) {
17670c6ec5d8SPatrick Pelletier 		msg = errs->msg;
17680c6ec5d8SPatrick Pelletier 		goto done;
1769de069b99SNick Mathewson 	}
17700c6ec5d8SPatrick Pelletier 
1771e8b78957SMattes D 	if (0 != FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM |
17720c6ec5d8SPatrick Pelletier 			       FORMAT_MESSAGE_IGNORE_INSERTS |
17730c6ec5d8SPatrick Pelletier 			       FORMAT_MESSAGE_ALLOCATE_BUFFER,
1774e8b78957SMattes D 			       NULL, errcode, 0, (char *)&msg, 0, NULL))
17750c6ec5d8SPatrick Pelletier 		chomp (msg);	/* because message has trailing newline */
17760c6ec5d8SPatrick Pelletier 	else {
17770c6ec5d8SPatrick Pelletier 		size_t len = 50;
17780c6ec5d8SPatrick Pelletier 		/* use LocalAlloc because FormatMessage does */
17790c6ec5d8SPatrick Pelletier 		msg = LocalAlloc(LMEM_FIXED, len);
17800c6ec5d8SPatrick Pelletier 		if (!msg) {
1781eeb700ceSNick Mathewson 			msg = (char *)"LocalAlloc failed during Winsock error";
17820c6ec5d8SPatrick Pelletier 			goto done;
1783de069b99SNick Mathewson 		}
17840c6ec5d8SPatrick Pelletier 		evutil_snprintf(msg, len, "winsock error 0x%08x", errcode);
17850c6ec5d8SPatrick Pelletier 	}
17860c6ec5d8SPatrick Pelletier 
17874ccdd53fSPatrick Pelletier 	newerr = (struct cached_sock_errs_entry *)
17884ccdd53fSPatrick Pelletier 		mm_malloc(sizeof (struct cached_sock_errs_entry));
17890c6ec5d8SPatrick Pelletier 
17900c6ec5d8SPatrick Pelletier 	if (!newerr) {
17910c6ec5d8SPatrick Pelletier 		LocalFree(msg);
1792ed26561bSNick Mathewson 		msg = (char *)"malloc failed during Winsock error";
17930c6ec5d8SPatrick Pelletier 		goto done;
17940c6ec5d8SPatrick Pelletier 	}
17950c6ec5d8SPatrick Pelletier 
17960c6ec5d8SPatrick Pelletier 	newerr->code = errcode;
17970c6ec5d8SPatrick Pelletier 	newerr->msg = msg;
17984ccdd53fSPatrick Pelletier 	HT_INSERT(cached_sock_errs_map, &windows_socket_errors, newerr);
17990c6ec5d8SPatrick Pelletier 
18000c6ec5d8SPatrick Pelletier  done:
18010c6ec5d8SPatrick Pelletier 	EVLOCK_UNLOCK(windows_socket_errors_lock_, 0);
18020c6ec5d8SPatrick Pelletier 
18030c6ec5d8SPatrick Pelletier 	return msg;
18040c6ec5d8SPatrick Pelletier }
18050c6ec5d8SPatrick Pelletier 
18060c6ec5d8SPatrick Pelletier #ifndef EVENT__DISABLE_THREAD_SUPPORT
18070c6ec5d8SPatrick Pelletier int
evutil_global_setup_locks_(const int enable_locks)18080c6ec5d8SPatrick Pelletier evutil_global_setup_locks_(const int enable_locks)
18090c6ec5d8SPatrick Pelletier {
18100c6ec5d8SPatrick Pelletier 	EVTHREAD_SETUP_GLOBAL_LOCK(windows_socket_errors_lock_, 0);
18110c6ec5d8SPatrick Pelletier 	return 0;
18120c6ec5d8SPatrick Pelletier }
18130c6ec5d8SPatrick Pelletier #endif
18140c6ec5d8SPatrick Pelletier 
18150c6ec5d8SPatrick Pelletier static void
evutil_free_sock_err_globals(void)18160c6ec5d8SPatrick Pelletier evutil_free_sock_err_globals(void)
18170c6ec5d8SPatrick Pelletier {
18184ccdd53fSPatrick Pelletier 	struct cached_sock_errs_entry **errs, *tofree;
18190c6ec5d8SPatrick Pelletier 
18204ccdd53fSPatrick Pelletier 	for (errs = HT_START(cached_sock_errs_map, &windows_socket_errors)
18214ccdd53fSPatrick Pelletier 		     ; errs; ) {
18224ccdd53fSPatrick Pelletier 		tofree = *errs;
18234ccdd53fSPatrick Pelletier 		errs = HT_NEXT_RMV(cached_sock_errs_map,
18244ccdd53fSPatrick Pelletier 				   &windows_socket_errors,
18254ccdd53fSPatrick Pelletier 				   errs);
18264ccdd53fSPatrick Pelletier 		LocalFree(tofree->msg);
18270c6ec5d8SPatrick Pelletier 		mm_free(tofree);
18280c6ec5d8SPatrick Pelletier 	}
18290c6ec5d8SPatrick Pelletier 
18304ccdd53fSPatrick Pelletier 	HT_CLEAR(cached_sock_errs_map, &windows_socket_errors);
18310c6ec5d8SPatrick Pelletier 
18320c6ec5d8SPatrick Pelletier #ifndef EVENT__DISABLE_THREAD_SUPPORT
18330c6ec5d8SPatrick Pelletier 	if (windows_socket_errors_lock_ != NULL) {
18340c6ec5d8SPatrick Pelletier 		EVTHREAD_FREE_LOCK(windows_socket_errors_lock_, 0);
18350c6ec5d8SPatrick Pelletier 		windows_socket_errors_lock_ = NULL;
18360c6ec5d8SPatrick Pelletier 	}
18370c6ec5d8SPatrick Pelletier #endif
18380c6ec5d8SPatrick Pelletier }
18390c6ec5d8SPatrick Pelletier 
18400c6ec5d8SPatrick Pelletier #else
18410c6ec5d8SPatrick Pelletier 
18420c6ec5d8SPatrick Pelletier #ifndef EVENT__DISABLE_THREAD_SUPPORT
18430c6ec5d8SPatrick Pelletier int
evutil_global_setup_locks_(const int enable_locks)18440c6ec5d8SPatrick Pelletier evutil_global_setup_locks_(const int enable_locks)
18450c6ec5d8SPatrick Pelletier {
18460c6ec5d8SPatrick Pelletier 	return 0;
18470c6ec5d8SPatrick Pelletier }
18480c6ec5d8SPatrick Pelletier #endif
18490c6ec5d8SPatrick Pelletier 
18500c6ec5d8SPatrick Pelletier static void
evutil_free_sock_err_globals(void)18510c6ec5d8SPatrick Pelletier evutil_free_sock_err_globals(void)
18520c6ec5d8SPatrick Pelletier {
18530c6ec5d8SPatrick Pelletier }
18540c6ec5d8SPatrick Pelletier 
1855de069b99SNick Mathewson #endif
1856de069b99SNick Mathewson 
1857c6da86ffSNick Mathewson int
evutil_snprintf(char * buf,size_t buflen,const char * format,...)1858c6da86ffSNick Mathewson evutil_snprintf(char *buf, size_t buflen, const char *format, ...)
1859c6da86ffSNick Mathewson {
1860c6da86ffSNick Mathewson 	int r;
1861c6da86ffSNick Mathewson 	va_list ap;
1862c6da86ffSNick Mathewson 	va_start(ap, format);
186355f91494SNiels Provos 	r = evutil_vsnprintf(buf, buflen, format, ap);
1864c6da86ffSNick Mathewson 	va_end(ap);
1865c6da86ffSNick Mathewson 	return r;
1866c6da86ffSNick Mathewson }
1867c6da86ffSNick Mathewson 
1868c6da86ffSNick Mathewson int
evutil_vsnprintf(char * buf,size_t buflen,const char * format,va_list ap)1869c6da86ffSNick Mathewson evutil_vsnprintf(char *buf, size_t buflen, const char *format, va_list ap)
1870c6da86ffSNick Mathewson {
1871f13bede7SNick Mathewson 	int r;
1872f13bede7SNick Mathewson 	if (!buflen)
1873f13bede7SNick Mathewson 		return 0;
18744e143958SJoakim Söderberg #if defined(_MSC_VER) || defined(_WIN32)
1875f13bede7SNick Mathewson 	r = _vsnprintf(buf, buflen, format, ap);
1876f13bede7SNick Mathewson 	if (r < 0)
1877f13bede7SNick Mathewson 		r = _vscprintf(format, ap);
187832390732SKevin Bowling #elif defined(sgi)
187932390732SKevin Bowling 	/* Make sure we always use the correct vsnprintf on IRIX */
188032390732SKevin Bowling 	extern int      _xpg5_vsnprintf(char * __restrict,
188132390732SKevin Bowling 		__SGI_LIBC_NAMESPACE_QUALIFIER size_t,
188232390732SKevin Bowling 		const char * __restrict, /* va_list */ char *);
188332390732SKevin Bowling 
188432390732SKevin Bowling 	r = _xpg5_vsnprintf(buf, buflen, format, ap);
1885c6da86ffSNick Mathewson #else
1886f13bede7SNick Mathewson 	r = vsnprintf(buf, buflen, format, ap);
1887f13bede7SNick Mathewson #endif
1888c6da86ffSNick Mathewson 	buf[buflen-1] = '\0';
1889c6da86ffSNick Mathewson 	return r;
1890c6da86ffSNick Mathewson }
18910d9d5cfeSNick Mathewson 
18920d9d5cfeSNick Mathewson #define USE_INTERNAL_NTOP
18930d9d5cfeSNick Mathewson #define USE_INTERNAL_PTON
18940d9d5cfeSNick Mathewson 
18950d9d5cfeSNick Mathewson const char *
evutil_inet_ntop(int af,const void * src,char * dst,size_t len)18960d9d5cfeSNick Mathewson evutil_inet_ntop(int af, const void *src, char *dst, size_t len)
18970d9d5cfeSNick Mathewson {
189868120d9bSNick Mathewson #if defined(EVENT__HAVE_INET_NTOP) && !defined(USE_INTERNAL_NTOP)
18990d9d5cfeSNick Mathewson 	return inet_ntop(af, src, dst, len);
19000d9d5cfeSNick Mathewson #else
19010d9d5cfeSNick Mathewson 	if (af == AF_INET) {
19020d9d5cfeSNick Mathewson 		const struct in_addr *in = src;
19030d9d5cfeSNick Mathewson 		const ev_uint32_t a = ntohl(in->s_addr);
19040d9d5cfeSNick Mathewson 		int r;
19050d9d5cfeSNick Mathewson 		r = evutil_snprintf(dst, len, "%d.%d.%d.%d",
19060d9d5cfeSNick Mathewson 		    (int)(ev_uint8_t)((a>>24)&0xff),
19070d9d5cfeSNick Mathewson 		    (int)(ev_uint8_t)((a>>16)&0xff),
19080d9d5cfeSNick Mathewson 		    (int)(ev_uint8_t)((a>>8 )&0xff),
19090d9d5cfeSNick Mathewson 		    (int)(ev_uint8_t)((a    )&0xff));
1910ebf29455SNick Mathewson 		if (r<0||(size_t)r>=len)
19110d9d5cfeSNick Mathewson 			return NULL;
19120d9d5cfeSNick Mathewson 		else
19130d9d5cfeSNick Mathewson 			return dst;
19140d9d5cfeSNick Mathewson #ifdef AF_INET6
19150d9d5cfeSNick Mathewson 	} else if (af == AF_INET6) {
19160d9d5cfeSNick Mathewson 		const struct in6_addr *addr = src;
19170d9d5cfeSNick Mathewson 		char buf[64], *cp;
19180d9d5cfeSNick Mathewson 		int longestGapLen = 0, longestGapPos = -1, i,
19190d9d5cfeSNick Mathewson 			curGapPos = -1, curGapLen = 0;
19200d9d5cfeSNick Mathewson 		ev_uint16_t words[8];
19210d9d5cfeSNick Mathewson 		for (i = 0; i < 8; ++i) {
19220d9d5cfeSNick Mathewson 			words[i] =
19230d9d5cfeSNick Mathewson 			    (((ev_uint16_t)addr->s6_addr[2*i])<<8) + addr->s6_addr[2*i+1];
19240d9d5cfeSNick Mathewson 		}
19250d9d5cfeSNick Mathewson 		if (words[0] == 0 && words[1] == 0 && words[2] == 0 && words[3] == 0 &&
19260d9d5cfeSNick Mathewson 		    words[4] == 0 && ((words[5] == 0 && words[6] && words[7]) ||
19270d9d5cfeSNick Mathewson 			(words[5] == 0xffff))) {
19280d9d5cfeSNick Mathewson 			/* This is an IPv4 address. */
19290d9d5cfeSNick Mathewson 			if (words[5] == 0) {
19300d9d5cfeSNick Mathewson 				evutil_snprintf(buf, sizeof(buf), "::%d.%d.%d.%d",
19310d9d5cfeSNick Mathewson 				    addr->s6_addr[12], addr->s6_addr[13],
19320d9d5cfeSNick Mathewson 				    addr->s6_addr[14], addr->s6_addr[15]);
19330d9d5cfeSNick Mathewson 			} else {
19340d9d5cfeSNick Mathewson 				evutil_snprintf(buf, sizeof(buf), "::%x:%d.%d.%d.%d", words[5],
19350d9d5cfeSNick Mathewson 				    addr->s6_addr[12], addr->s6_addr[13],
19360d9d5cfeSNick Mathewson 				    addr->s6_addr[14], addr->s6_addr[15]);
19370d9d5cfeSNick Mathewson 			}
19380d9d5cfeSNick Mathewson 			if (strlen(buf) > len)
19390d9d5cfeSNick Mathewson 				return NULL;
19400d9d5cfeSNick Mathewson 			strlcpy(dst, buf, len);
19410d9d5cfeSNick Mathewson 			return dst;
19420d9d5cfeSNick Mathewson 		}
19430d9d5cfeSNick Mathewson 		i = 0;
19440d9d5cfeSNick Mathewson 		while (i < 8) {
19450d9d5cfeSNick Mathewson 			if (words[i] == 0) {
19460d9d5cfeSNick Mathewson 				curGapPos = i++;
19470d9d5cfeSNick Mathewson 				curGapLen = 1;
19480d9d5cfeSNick Mathewson 				while (i<8 && words[i] == 0) {
19490d9d5cfeSNick Mathewson 					++i; ++curGapLen;
19500d9d5cfeSNick Mathewson 				}
19510d9d5cfeSNick Mathewson 				if (curGapLen > longestGapLen) {
19520d9d5cfeSNick Mathewson 					longestGapPos = curGapPos;
19530d9d5cfeSNick Mathewson 					longestGapLen = curGapLen;
19540d9d5cfeSNick Mathewson 				}
19550d9d5cfeSNick Mathewson 			} else {
19560d9d5cfeSNick Mathewson 				++i;
19570d9d5cfeSNick Mathewson 			}
19580d9d5cfeSNick Mathewson 		}
19590d9d5cfeSNick Mathewson 		if (longestGapLen<=1)
19600d9d5cfeSNick Mathewson 			longestGapPos = -1;
19610d9d5cfeSNick Mathewson 
19620d9d5cfeSNick Mathewson 		cp = buf;
19630d9d5cfeSNick Mathewson 		for (i = 0; i < 8; ++i) {
19640d9d5cfeSNick Mathewson 			if (words[i] == 0 && longestGapPos == i) {
19650d9d5cfeSNick Mathewson 				if (i == 0)
19660d9d5cfeSNick Mathewson 					*cp++ = ':';
19670d9d5cfeSNick Mathewson 				*cp++ = ':';
19680d9d5cfeSNick Mathewson 				while (i < 8 && words[i] == 0)
19690d9d5cfeSNick Mathewson 					++i;
19700d9d5cfeSNick Mathewson 				--i; /* to compensate for loop increment. */
19710d9d5cfeSNick Mathewson 			} else {
19720d9d5cfeSNick Mathewson 				evutil_snprintf(cp,
19730d9d5cfeSNick Mathewson 								sizeof(buf)-(cp-buf), "%x", (unsigned)words[i]);
19740d9d5cfeSNick Mathewson 				cp += strlen(cp);
19750d9d5cfeSNick Mathewson 				if (i != 7)
19760d9d5cfeSNick Mathewson 					*cp++ = ':';
19770d9d5cfeSNick Mathewson 			}
19780d9d5cfeSNick Mathewson 		}
19790d9d5cfeSNick Mathewson 		*cp = '\0';
19800d9d5cfeSNick Mathewson 		if (strlen(buf) > len)
19810d9d5cfeSNick Mathewson 			return NULL;
19820d9d5cfeSNick Mathewson 		strlcpy(dst, buf, len);
19830d9d5cfeSNick Mathewson 		return dst;
19840d9d5cfeSNick Mathewson #endif
19850d9d5cfeSNick Mathewson 	} else {
19860d9d5cfeSNick Mathewson 		return NULL;
19870d9d5cfeSNick Mathewson 	}
19880d9d5cfeSNick Mathewson #endif
19890d9d5cfeSNick Mathewson }
19900d9d5cfeSNick Mathewson 
19910d9d5cfeSNick Mathewson int
evutil_inet_pton_scope(int af,const char * src,void * dst,unsigned * indexp)1992f602211fSPhilip Homburg evutil_inet_pton_scope(int af, const char *src, void *dst, unsigned *indexp)
1993f602211fSPhilip Homburg {
1994f602211fSPhilip Homburg 	int r;
1995f602211fSPhilip Homburg 	unsigned if_index;
1996f602211fSPhilip Homburg 	char *check, *cp, *tmp_src;
1997f602211fSPhilip Homburg 
1998f602211fSPhilip Homburg 	*indexp = 0; /* Reasonable default */
1999f602211fSPhilip Homburg 
2000f602211fSPhilip Homburg 	/* Bail out if not IPv6 */
2001f602211fSPhilip Homburg 	if (af != AF_INET6)
2002f602211fSPhilip Homburg 		return evutil_inet_pton(af, src, dst);
2003f602211fSPhilip Homburg 
2004f602211fSPhilip Homburg 	cp = strchr(src, '%');
2005f602211fSPhilip Homburg 
2006f602211fSPhilip Homburg 	/* Bail out if no zone ID */
2007f602211fSPhilip Homburg 	if (cp == NULL)
2008f602211fSPhilip Homburg 		return evutil_inet_pton(af, src, dst);
2009f602211fSPhilip Homburg 
2010f602211fSPhilip Homburg 	if_index = if_nametoindex(cp + 1);
2011f602211fSPhilip Homburg 	if (if_index == 0) {
2012f602211fSPhilip Homburg 		/* Could be numeric */
2013f602211fSPhilip Homburg 		if_index = strtoul(cp + 1, &check, 10);
2014f602211fSPhilip Homburg 		if (check[0] != '\0')
2015f602211fSPhilip Homburg 			return 0;
2016f602211fSPhilip Homburg 	}
2017f602211fSPhilip Homburg 	*indexp = if_index;
2018f602211fSPhilip Homburg 	tmp_src = mm_strdup(src);
2019f602211fSPhilip Homburg 	cp = strchr(tmp_src, '%');
2020f602211fSPhilip Homburg 	*cp = '\0';
2021f602211fSPhilip Homburg 	r = evutil_inet_pton(af, tmp_src, dst);
2022f602211fSPhilip Homburg 	free(tmp_src);
2023f602211fSPhilip Homburg 	return r;
2024f602211fSPhilip Homburg }
2025f602211fSPhilip Homburg 
2026f602211fSPhilip Homburg int
evutil_inet_pton(int af,const char * src,void * dst)20270d9d5cfeSNick Mathewson evutil_inet_pton(int af, const char *src, void *dst)
20280d9d5cfeSNick Mathewson {
202968120d9bSNick Mathewson #if defined(EVENT__HAVE_INET_PTON) && !defined(USE_INTERNAL_PTON)
20300d9d5cfeSNick Mathewson 	return inet_pton(af, src, dst);
20310d9d5cfeSNick Mathewson #else
20320d9d5cfeSNick Mathewson 	if (af == AF_INET) {
203358fc9b6cSNick Mathewson 		unsigned a,b,c,d;
2034da49d6a3SNick Mathewson 		char more;
2035da49d6a3SNick Mathewson 		struct in_addr *addr = dst;
203658fc9b6cSNick Mathewson 		if (sscanf(src, "%u.%u.%u.%u%c", &a,&b,&c,&d,&more) != 4)
20370d9d5cfeSNick Mathewson 			return 0;
203858fc9b6cSNick Mathewson 		if (a > 255) return 0;
203958fc9b6cSNick Mathewson 		if (b > 255) return 0;
204058fc9b6cSNick Mathewson 		if (c > 255) return 0;
204158fc9b6cSNick Mathewson 		if (d > 255) return 0;
2042da49d6a3SNick Mathewson 		addr->s_addr = htonl((a<<24) | (b<<16) | (c<<8) | d);
20430d9d5cfeSNick Mathewson 		return 1;
20440d9d5cfeSNick Mathewson #ifdef AF_INET6
20450d9d5cfeSNick Mathewson 	} else if (af == AF_INET6) {
20460d9d5cfeSNick Mathewson 		struct in6_addr *out = dst;
2047ebf29455SNick Mathewson 		ev_uint16_t words[8];
20480d9d5cfeSNick Mathewson 		int gapPos = -1, i, setWords=0;
20490d9d5cfeSNick Mathewson 		const char *dot = strchr(src, '.');
20500d9d5cfeSNick Mathewson 		const char *eow; /* end of words. */
20510d9d5cfeSNick Mathewson 		if (dot == src)
20520d9d5cfeSNick Mathewson 			return 0;
20530d9d5cfeSNick Mathewson 		else if (!dot)
20540d9d5cfeSNick Mathewson 			eow = src+strlen(src);
20550d9d5cfeSNick Mathewson 		else {
205658fc9b6cSNick Mathewson 			unsigned byte1,byte2,byte3,byte4;
20570d9d5cfeSNick Mathewson 			char more;
20588ac3c4c2SNick Mathewson 			for (eow = dot-1; eow >= src && EVUTIL_ISDIGIT_(*eow); --eow)
20590d9d5cfeSNick Mathewson 				;
20600d9d5cfeSNick Mathewson 			++eow;
20610d9d5cfeSNick Mathewson 
20620d9d5cfeSNick Mathewson 			/* We use "scanf" because some platform inet_aton()s are too lax
20630d9d5cfeSNick Mathewson 			 * about IPv4 addresses of the form "1.2.3" */
206458fc9b6cSNick Mathewson 			if (sscanf(eow, "%u.%u.%u.%u%c",
20650d9d5cfeSNick Mathewson 					   &byte1,&byte2,&byte3,&byte4,&more) != 4)
20660d9d5cfeSNick Mathewson 				return 0;
20670d9d5cfeSNick Mathewson 
206858fc9b6cSNick Mathewson 			if (byte1 > 255 ||
206958fc9b6cSNick Mathewson 			    byte2 > 255 ||
207058fc9b6cSNick Mathewson 			    byte3 > 255 ||
207158fc9b6cSNick Mathewson 			    byte4 > 255)
20720d9d5cfeSNick Mathewson 				return 0;
20730d9d5cfeSNick Mathewson 
20740d9d5cfeSNick Mathewson 			words[6] = (byte1<<8) | byte2;
20750d9d5cfeSNick Mathewson 			words[7] = (byte3<<8) | byte4;
20760d9d5cfeSNick Mathewson 			setWords += 2;
20770d9d5cfeSNick Mathewson 		}
20780d9d5cfeSNick Mathewson 
20790d9d5cfeSNick Mathewson 		i = 0;
20800d9d5cfeSNick Mathewson 		while (src < eow) {
20810d9d5cfeSNick Mathewson 			if (i > 7)
20820d9d5cfeSNick Mathewson 				return 0;
20838ac3c4c2SNick Mathewson 			if (EVUTIL_ISXDIGIT_(*src)) {
20840d9d5cfeSNick Mathewson 				char *next;
20850d9d5cfeSNick Mathewson 				long r = strtol(src, &next, 16);
20860d9d5cfeSNick Mathewson 				if (next > 4+src)
20870d9d5cfeSNick Mathewson 					return 0;
20880d9d5cfeSNick Mathewson 				if (next == src)
20890d9d5cfeSNick Mathewson 					return 0;
20900d9d5cfeSNick Mathewson 				if (r<0 || r>65536)
20910d9d5cfeSNick Mathewson 					return 0;
20920d9d5cfeSNick Mathewson 
2093ebf29455SNick Mathewson 				words[i++] = (ev_uint16_t)r;
20940d9d5cfeSNick Mathewson 				setWords++;
20950d9d5cfeSNick Mathewson 				src = next;
20960d9d5cfeSNick Mathewson 				if (*src != ':' && src != eow)
20970d9d5cfeSNick Mathewson 					return 0;
20980d9d5cfeSNick Mathewson 				++src;
20990d9d5cfeSNick Mathewson 			} else if (*src == ':' && i > 0 && gapPos==-1) {
21000d9d5cfeSNick Mathewson 				gapPos = i;
21010d9d5cfeSNick Mathewson 				++src;
21020d9d5cfeSNick Mathewson 			} else if (*src == ':' && i == 0 && src[1] == ':' && gapPos==-1) {
21030d9d5cfeSNick Mathewson 				gapPos = i;
21040d9d5cfeSNick Mathewson 				src += 2;
21050d9d5cfeSNick Mathewson 			} else {
21060d9d5cfeSNick Mathewson 				return 0;
21070d9d5cfeSNick Mathewson 			}
21080d9d5cfeSNick Mathewson 		}
21090d9d5cfeSNick Mathewson 
21100d9d5cfeSNick Mathewson 		if (setWords > 8 ||
21110d9d5cfeSNick Mathewson 			(setWords == 8 && gapPos != -1) ||
21120d9d5cfeSNick Mathewson 			(setWords < 8 && gapPos == -1))
21130d9d5cfeSNick Mathewson 			return 0;
21140d9d5cfeSNick Mathewson 
21150d9d5cfeSNick Mathewson 		if (gapPos >= 0) {
21160d9d5cfeSNick Mathewson 			int nToMove = setWords - (dot ? 2 : 0) - gapPos;
21170d9d5cfeSNick Mathewson 			int gapLen = 8 - setWords;
2118043515bcSNick Mathewson 			/* assert(nToMove >= 0); */
21190d9d5cfeSNick Mathewson 			if (nToMove < 0)
21200d9d5cfeSNick Mathewson 				return -1; /* should be impossible */
21210d9d5cfeSNick Mathewson 			memmove(&words[gapPos+gapLen], &words[gapPos],
2122ebf29455SNick Mathewson 					sizeof(ev_uint16_t)*nToMove);
2123ebf29455SNick Mathewson 			memset(&words[gapPos], 0, sizeof(ev_uint16_t)*gapLen);
21240d9d5cfeSNick Mathewson 		}
21250d9d5cfeSNick Mathewson 		for (i = 0; i < 8; ++i) {
21260d9d5cfeSNick Mathewson 			out->s6_addr[2*i  ] = words[i] >> 8;
21270d9d5cfeSNick Mathewson 			out->s6_addr[2*i+1] = words[i] & 0xff;
21280d9d5cfeSNick Mathewson 		}
21290d9d5cfeSNick Mathewson 
21300d9d5cfeSNick Mathewson 		return 1;
21310d9d5cfeSNick Mathewson #endif
21320d9d5cfeSNick Mathewson 	} else {
21330d9d5cfeSNick Mathewson 		return -1;
21340d9d5cfeSNick Mathewson 	}
21350d9d5cfeSNick Mathewson #endif
21360d9d5cfeSNick Mathewson }
2137cfbd1680SNick Mathewson 
2138cfbd1680SNick Mathewson int
evutil_parse_sockaddr_port(const char * ip_as_string,struct sockaddr * out,int * outlen)2139acaf65c3SNick Mathewson evutil_parse_sockaddr_port(const char *ip_as_string, struct sockaddr *out, int *outlen)
2140cfbd1680SNick Mathewson {
2141cfbd1680SNick Mathewson 	int port;
2142f602211fSPhilip Homburg 	unsigned int if_index;
2143cfbd1680SNick Mathewson 	char buf[128];
2144cfbd1680SNick Mathewson 	const char *cp, *addr_part, *port_part;
2145cfbd1680SNick Mathewson 	int is_ipv6;
2146cfbd1680SNick Mathewson 	/* recognized formats are:
2147cfbd1680SNick Mathewson 	 * [ipv6]:port
2148cfbd1680SNick Mathewson 	 * ipv6
2149cfbd1680SNick Mathewson 	 * [ipv6]
2150cfbd1680SNick Mathewson 	 * ipv4:port
2151cfbd1680SNick Mathewson 	 * ipv4
2152cfbd1680SNick Mathewson 	 */
2153cfbd1680SNick Mathewson 
2154cfbd1680SNick Mathewson 	cp = strchr(ip_as_string, ':');
2155cfbd1680SNick Mathewson 	if (*ip_as_string == '[') {
2156329acc18SAzat Khuzhin 		size_t len;
2157cfbd1680SNick Mathewson 		if (!(cp = strchr(ip_as_string, ']'))) {
2158cfbd1680SNick Mathewson 			return -1;
2159cfbd1680SNick Mathewson 		}
2160329acc18SAzat Khuzhin 		len = ( cp-(ip_as_string + 1) );
2161329acc18SAzat Khuzhin 		if (len > sizeof(buf)-1) {
2162cfbd1680SNick Mathewson 			return -1;
2163cfbd1680SNick Mathewson 		}
2164cfbd1680SNick Mathewson 		memcpy(buf, ip_as_string+1, len);
2165cfbd1680SNick Mathewson 		buf[len] = '\0';
2166cfbd1680SNick Mathewson 		addr_part = buf;
2167cfbd1680SNick Mathewson 		if (cp[1] == ':')
2168cfbd1680SNick Mathewson 			port_part = cp+2;
2169cfbd1680SNick Mathewson 		else
2170cfbd1680SNick Mathewson 			port_part = NULL;
2171cfbd1680SNick Mathewson 		is_ipv6 = 1;
2172cfbd1680SNick Mathewson 	} else if (cp && strchr(cp+1, ':')) {
2173cfbd1680SNick Mathewson 		is_ipv6 = 1;
2174cfbd1680SNick Mathewson 		addr_part = ip_as_string;
2175cfbd1680SNick Mathewson 		port_part = NULL;
2176cfbd1680SNick Mathewson 	} else if (cp) {
2177cfbd1680SNick Mathewson 		is_ipv6 = 0;
2178cfbd1680SNick Mathewson 		if (cp - ip_as_string > (int)sizeof(buf)-1) {
2179cfbd1680SNick Mathewson 			return -1;
2180cfbd1680SNick Mathewson 		}
2181cfbd1680SNick Mathewson 		memcpy(buf, ip_as_string, cp-ip_as_string);
2182cfbd1680SNick Mathewson 		buf[cp-ip_as_string] = '\0';
2183cfbd1680SNick Mathewson 		addr_part = buf;
2184cfbd1680SNick Mathewson 		port_part = cp+1;
2185cfbd1680SNick Mathewson 	} else {
2186cfbd1680SNick Mathewson 		addr_part = ip_as_string;
2187cfbd1680SNick Mathewson 		port_part = NULL;
2188cfbd1680SNick Mathewson 		is_ipv6 = 0;
2189cfbd1680SNick Mathewson 	}
2190cfbd1680SNick Mathewson 
2191cfbd1680SNick Mathewson 	if (port_part == NULL) {
2192cfbd1680SNick Mathewson 		port = 0;
2193cfbd1680SNick Mathewson 	} else {
2194cfbd1680SNick Mathewson 		port = atoi(port_part);
2195cfbd1680SNick Mathewson 		if (port <= 0 || port > 65535) {
2196cfbd1680SNick Mathewson 			return -1;
2197cfbd1680SNick Mathewson 		}
2198cfbd1680SNick Mathewson 	}
2199cfbd1680SNick Mathewson 
2200cfbd1680SNick Mathewson 	if (!addr_part)
2201cfbd1680SNick Mathewson 		return -1; /* Should be impossible. */
220201be8708SNick Mathewson #ifdef AF_INET6
220301be8708SNick Mathewson 	if (is_ipv6)
220401be8708SNick Mathewson 	{
2205cfbd1680SNick Mathewson 		struct sockaddr_in6 sin6;
2206cfbd1680SNick Mathewson 		memset(&sin6, 0, sizeof(sin6));
220768120d9bSNick Mathewson #ifdef EVENT__HAVE_STRUCT_SOCKADDR_IN6_SIN6_LEN
2208cfbd1680SNick Mathewson 		sin6.sin6_len = sizeof(sin6);
2209980bcd68SNick Mathewson #endif
2210cfbd1680SNick Mathewson 		sin6.sin6_family = AF_INET6;
2211cfbd1680SNick Mathewson 		sin6.sin6_port = htons(port);
2212f602211fSPhilip Homburg 		if (1 != evutil_inet_pton_scope(
2213f602211fSPhilip Homburg 			AF_INET6, addr_part, &sin6.sin6_addr, &if_index)) {
2214cfbd1680SNick Mathewson 			return -1;
2215f602211fSPhilip Homburg 		}
22169c8db0f8SNick Mathewson 		if ((int)sizeof(sin6) > *outlen)
2217cfbd1680SNick Mathewson 			return -1;
2218f602211fSPhilip Homburg 		sin6.sin6_scope_id = if_index;
2219acaf65c3SNick Mathewson 		memset(out, 0, *outlen);
2220cfbd1680SNick Mathewson 		memcpy(out, &sin6, sizeof(sin6));
2221acaf65c3SNick Mathewson 		*outlen = sizeof(sin6);
2222cfbd1680SNick Mathewson 		return 0;
222301be8708SNick Mathewson 	}
222401be8708SNick Mathewson 	else
222501be8708SNick Mathewson #endif
222601be8708SNick Mathewson 	{
2227cfbd1680SNick Mathewson 		struct sockaddr_in sin;
2228cfbd1680SNick Mathewson 		memset(&sin, 0, sizeof(sin));
222968120d9bSNick Mathewson #ifdef EVENT__HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
2230cfbd1680SNick Mathewson 		sin.sin_len = sizeof(sin);
2231980bcd68SNick Mathewson #endif
2232cfbd1680SNick Mathewson 		sin.sin_family = AF_INET;
2233cfbd1680SNick Mathewson 		sin.sin_port = htons(port);
2234cfbd1680SNick Mathewson 		if (1 != evutil_inet_pton(AF_INET, addr_part, &sin.sin_addr))
2235cfbd1680SNick Mathewson 			return -1;
22369c8db0f8SNick Mathewson 		if ((int)sizeof(sin) > *outlen)
2237cfbd1680SNick Mathewson 			return -1;
2238acaf65c3SNick Mathewson 		memset(out, 0, *outlen);
2239cfbd1680SNick Mathewson 		memcpy(out, &sin, sizeof(sin));
2240acaf65c3SNick Mathewson 		*outlen = sizeof(sin);
2241cfbd1680SNick Mathewson 		return 0;
2242cfbd1680SNick Mathewson 	}
2243cfbd1680SNick Mathewson }
2244cd731b77SNick Mathewson 
2245b1c79500SNick Mathewson const char *
evutil_format_sockaddr_port_(const struct sockaddr * sa,char * out,size_t outlen)22468ac3c4c2SNick Mathewson evutil_format_sockaddr_port_(const struct sockaddr *sa, char *out, size_t outlen)
2247b1c79500SNick Mathewson {
2248b1c79500SNick Mathewson 	char b[128];
2249b1c79500SNick Mathewson 	const char *res=NULL;
2250b1c79500SNick Mathewson 	int port;
2251b1c79500SNick Mathewson 	if (sa->sa_family == AF_INET) {
2252b1c79500SNick Mathewson 		const struct sockaddr_in *sin = (const struct sockaddr_in*)sa;
2253b1c79500SNick Mathewson 		res = evutil_inet_ntop(AF_INET, &sin->sin_addr,b,sizeof(b));
2254b1c79500SNick Mathewson 		port = ntohs(sin->sin_port);
2255b1c79500SNick Mathewson 		if (res) {
2256b1c79500SNick Mathewson 			evutil_snprintf(out, outlen, "%s:%d", b, port);
2257b1c79500SNick Mathewson 			return out;
2258b1c79500SNick Mathewson 		}
2259b1c79500SNick Mathewson 	} else if (sa->sa_family == AF_INET6) {
2260b1c79500SNick Mathewson 		const struct sockaddr_in6 *sin6 = (const struct sockaddr_in6*)sa;
2261b1c79500SNick Mathewson 		res = evutil_inet_ntop(AF_INET6, &sin6->sin6_addr,b,sizeof(b));
2262b1c79500SNick Mathewson 		port = ntohs(sin6->sin6_port);
2263b1c79500SNick Mathewson 		if (res) {
2264b1c79500SNick Mathewson 			evutil_snprintf(out, outlen, "[%s]:%d", b, port);
2265b1c79500SNick Mathewson 			return out;
2266b1c79500SNick Mathewson 		}
2267b1c79500SNick Mathewson 	}
2268b1c79500SNick Mathewson 
2269b1c79500SNick Mathewson 	evutil_snprintf(out, outlen, "<addr with socktype %d>",
2270b1c79500SNick Mathewson 	    (int)sa->sa_family);
2271b1c79500SNick Mathewson 	return out;
2272b1c79500SNick Mathewson }
2273b1c79500SNick Mathewson 
2274621aafd2SNick Mathewson int
evutil_sockaddr_cmp(const struct sockaddr * sa1,const struct sockaddr * sa2,int include_port)2275621aafd2SNick Mathewson evutil_sockaddr_cmp(const struct sockaddr *sa1, const struct sockaddr *sa2,
2276621aafd2SNick Mathewson     int include_port)
2277621aafd2SNick Mathewson {
2278621aafd2SNick Mathewson 	int r;
2279621aafd2SNick Mathewson 	if (0 != (r = (sa1->sa_family - sa2->sa_family)))
2280621aafd2SNick Mathewson 		return r;
2281621aafd2SNick Mathewson 
2282621aafd2SNick Mathewson 	if (sa1->sa_family == AF_INET) {
2283621aafd2SNick Mathewson 		const struct sockaddr_in *sin1, *sin2;
2284621aafd2SNick Mathewson 		sin1 = (const struct sockaddr_in *)sa1;
2285621aafd2SNick Mathewson 		sin2 = (const struct sockaddr_in *)sa2;
2286621aafd2SNick Mathewson 		if (sin1->sin_addr.s_addr < sin2->sin_addr.s_addr)
2287621aafd2SNick Mathewson 			return -1;
2288621aafd2SNick Mathewson 		else if (sin1->sin_addr.s_addr > sin2->sin_addr.s_addr)
2289621aafd2SNick Mathewson 			return 1;
2290621aafd2SNick Mathewson 		else if (include_port &&
2291621aafd2SNick Mathewson 		    (r = ((int)sin1->sin_port - (int)sin2->sin_port)))
2292621aafd2SNick Mathewson 			return r;
2293621aafd2SNick Mathewson 		else
2294621aafd2SNick Mathewson 			return 0;
2295621aafd2SNick Mathewson 	}
2296621aafd2SNick Mathewson #ifdef AF_INET6
2297621aafd2SNick Mathewson 	else if (sa1->sa_family == AF_INET6) {
2298621aafd2SNick Mathewson 		const struct sockaddr_in6 *sin1, *sin2;
2299621aafd2SNick Mathewson 		sin1 = (const struct sockaddr_in6 *)sa1;
2300621aafd2SNick Mathewson 		sin2 = (const struct sockaddr_in6 *)sa2;
2301621aafd2SNick Mathewson 		if ((r = memcmp(sin1->sin6_addr.s6_addr, sin2->sin6_addr.s6_addr, 16)))
2302621aafd2SNick Mathewson 			return r;
2303621aafd2SNick Mathewson 		else if (include_port &&
2304621aafd2SNick Mathewson 		    (r = ((int)sin1->sin6_port - (int)sin2->sin6_port)))
2305621aafd2SNick Mathewson 			return r;
2306621aafd2SNick Mathewson 		else
2307621aafd2SNick Mathewson 			return 0;
2308621aafd2SNick Mathewson 	}
2309621aafd2SNick Mathewson #endif
2310621aafd2SNick Mathewson 	return 1;
2311621aafd2SNick Mathewson }
2312621aafd2SNick Mathewson 
2313cd731b77SNick Mathewson /* Tables to implement ctypes-replacement EVUTIL_IS*() functions.  Each table
2314cd731b77SNick Mathewson  * has 256 bits to look up whether a character is in some set or not.  This
2315cd731b77SNick Mathewson  * fails on non-ASCII platforms, but so does every other place where we
2316cd731b77SNick Mathewson  * take a char and write it onto the network.
2317cd731b77SNick Mathewson  **/
23181fdec20fSNick Mathewson static const ev_uint32_t EVUTIL_ISALPHA_TABLE[8] =
2319cd731b77SNick Mathewson   { 0, 0, 0x7fffffe, 0x7fffffe, 0, 0, 0, 0 };
23201fdec20fSNick Mathewson static const ev_uint32_t EVUTIL_ISALNUM_TABLE[8] =
2321cd731b77SNick Mathewson   { 0, 0x3ff0000, 0x7fffffe, 0x7fffffe, 0, 0, 0, 0 };
23221fdec20fSNick Mathewson static const ev_uint32_t EVUTIL_ISSPACE_TABLE[8] = { 0x3e00, 0x1, 0, 0, 0, 0, 0, 0 };
23231fdec20fSNick Mathewson static const ev_uint32_t EVUTIL_ISXDIGIT_TABLE[8] =
2324cd731b77SNick Mathewson   { 0, 0x3ff0000, 0x7e, 0x7e, 0, 0, 0, 0 };
23251fdec20fSNick Mathewson static const ev_uint32_t EVUTIL_ISDIGIT_TABLE[8] = { 0, 0x3ff0000, 0, 0, 0, 0, 0, 0 };
23261fdec20fSNick Mathewson static const ev_uint32_t EVUTIL_ISPRINT_TABLE[8] =
2327cd731b77SNick Mathewson   { 0, 0xffffffff, 0xffffffff, 0x7fffffff, 0, 0, 0, 0x0 };
23281fdec20fSNick Mathewson static const ev_uint32_t EVUTIL_ISUPPER_TABLE[8] = { 0, 0, 0x7fffffe, 0, 0, 0, 0, 0 };
23291fdec20fSNick Mathewson static const ev_uint32_t EVUTIL_ISLOWER_TABLE[8] = { 0, 0, 0, 0x7fffffe, 0, 0, 0, 0 };
2330cd731b77SNick Mathewson /* Upper-casing and lowercasing tables to map characters to upper/lowercase
2331cd731b77SNick Mathewson  * equivalents. */
23321fdec20fSNick Mathewson static const unsigned char EVUTIL_TOUPPER_TABLE[256] = {
2333cd731b77SNick Mathewson   0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,
2334cd731b77SNick Mathewson   16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,
2335cd731b77SNick Mathewson   32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,
2336cd731b77SNick Mathewson   48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,
2337cd731b77SNick Mathewson   64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,
2338cd731b77SNick Mathewson   80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,
2339cd731b77SNick Mathewson   96,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,
2340cd731b77SNick Mathewson   80,81,82,83,84,85,86,87,88,89,90,123,124,125,126,127,
2341cd731b77SNick Mathewson   128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,
2342cd731b77SNick Mathewson   144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,
2343cd731b77SNick Mathewson   160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,
2344cd731b77SNick Mathewson   176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,
2345cd731b77SNick Mathewson   192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,
2346cd731b77SNick Mathewson   208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,
2347cd731b77SNick Mathewson   224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,
2348cd731b77SNick Mathewson   240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255,
2349cd731b77SNick Mathewson };
23501fdec20fSNick Mathewson static const unsigned char EVUTIL_TOLOWER_TABLE[256] = {
2351cd731b77SNick Mathewson   0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,
2352cd731b77SNick Mathewson   16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,
2353cd731b77SNick Mathewson   32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,
2354cd731b77SNick Mathewson   48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,
2355cd731b77SNick Mathewson   64,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,
2356cd731b77SNick Mathewson   112,113,114,115,116,117,118,119,120,121,122,91,92,93,94,95,
2357cd731b77SNick Mathewson   96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,
2358cd731b77SNick Mathewson   112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,
2359cd731b77SNick Mathewson   128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,
2360cd731b77SNick Mathewson   144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,
2361cd731b77SNick Mathewson   160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,
2362cd731b77SNick Mathewson   176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,
2363cd731b77SNick Mathewson   192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,
2364cd731b77SNick Mathewson   208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,
2365cd731b77SNick Mathewson   224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,
2366cd731b77SNick Mathewson   240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255,
2367cd731b77SNick Mathewson };
2368f11dff2cSNick Mathewson 
23691fdec20fSNick Mathewson #define IMPL_CTYPE_FN(name)						\
2370c7848fa0SNick Mathewson 	int EVUTIL_##name##_(char c) {					\
23711fdec20fSNick Mathewson 		ev_uint8_t u = c;					\
2372*6b8d02a7SAzat Khuzhin 		return !!(EVUTIL_##name##_TABLE[(u >> 5) & 7] & (1U << (u & 31))); \
23731fdec20fSNick Mathewson 	}
23741fdec20fSNick Mathewson IMPL_CTYPE_FN(ISALPHA)
IMPL_CTYPE_FN(ISALNUM)23751fdec20fSNick Mathewson IMPL_CTYPE_FN(ISALNUM)
23761fdec20fSNick Mathewson IMPL_CTYPE_FN(ISSPACE)
23771fdec20fSNick Mathewson IMPL_CTYPE_FN(ISDIGIT)
23781fdec20fSNick Mathewson IMPL_CTYPE_FN(ISXDIGIT)
23791fdec20fSNick Mathewson IMPL_CTYPE_FN(ISPRINT)
23801fdec20fSNick Mathewson IMPL_CTYPE_FN(ISLOWER)
23811fdec20fSNick Mathewson IMPL_CTYPE_FN(ISUPPER)
23821fdec20fSNick Mathewson 
23838ac3c4c2SNick Mathewson char EVUTIL_TOLOWER_(char c)
23841fdec20fSNick Mathewson {
23851fdec20fSNick Mathewson 	return ((char)EVUTIL_TOLOWER_TABLE[(ev_uint8_t)c]);
23861fdec20fSNick Mathewson }
EVUTIL_TOUPPER_(char c)23878ac3c4c2SNick Mathewson char EVUTIL_TOUPPER_(char c)
23881fdec20fSNick Mathewson {
23891fdec20fSNick Mathewson 	return ((char)EVUTIL_TOUPPER_TABLE[(ev_uint8_t)c]);
23901fdec20fSNick Mathewson }
2391f11dff2cSNick Mathewson int
evutil_ascii_strcasecmp(const char * s1,const char * s2)239272ea534fSNick Mathewson evutil_ascii_strcasecmp(const char *s1, const char *s2)
2393f11dff2cSNick Mathewson {
2394f11dff2cSNick Mathewson 	char c1, c2;
2395f11dff2cSNick Mathewson 	while (1) {
23968ac3c4c2SNick Mathewson 		c1 = EVUTIL_TOLOWER_(*s1++);
23978ac3c4c2SNick Mathewson 		c2 = EVUTIL_TOLOWER_(*s2++);
2398f11dff2cSNick Mathewson 		if (c1 < c2)
2399f11dff2cSNick Mathewson 			return -1;
2400f11dff2cSNick Mathewson 		else if (c1 > c2)
2401f11dff2cSNick Mathewson 			return 1;
2402f11dff2cSNick Mathewson 		else if (c1 == 0)
2403f11dff2cSNick Mathewson 			return 0;
2404f11dff2cSNick Mathewson 	}
2405f11dff2cSNick Mathewson }
evutil_ascii_strncasecmp(const char * s1,const char * s2,size_t n)240672ea534fSNick Mathewson int evutil_ascii_strncasecmp(const char *s1, const char *s2, size_t n)
2407f11dff2cSNick Mathewson {
2408f11dff2cSNick Mathewson 	char c1, c2;
2409f11dff2cSNick Mathewson 	while (n--) {
24108ac3c4c2SNick Mathewson 		c1 = EVUTIL_TOLOWER_(*s1++);
24118ac3c4c2SNick Mathewson 		c2 = EVUTIL_TOLOWER_(*s2++);
2412f11dff2cSNick Mathewson 		if (c1 < c2)
2413f11dff2cSNick Mathewson 			return -1;
2414f11dff2cSNick Mathewson 		else if (c1 > c2)
2415f11dff2cSNick Mathewson 			return 1;
2416f11dff2cSNick Mathewson 		else if (c1 == 0)
2417f11dff2cSNick Mathewson 			return 0;
2418f11dff2cSNick Mathewson 	}
2419f11dff2cSNick Mathewson 	return 0;
2420f11dff2cSNick Mathewson }
2421629a6133SNick Mathewson 
242261b93af5SNick Mathewson void
evutil_rtrim_lws_(char * str)242361b93af5SNick Mathewson evutil_rtrim_lws_(char *str)
242461b93af5SNick Mathewson {
242561b93af5SNick Mathewson 	char *cp;
242661b93af5SNick Mathewson 
242761b93af5SNick Mathewson 	if (str == NULL)
242861b93af5SNick Mathewson 		return;
242961b93af5SNick Mathewson 
243061b93af5SNick Mathewson 	if ((cp = strchr(str, '\0')) == NULL || (cp == str))
243161b93af5SNick Mathewson 		return;
243261b93af5SNick Mathewson 
243361b93af5SNick Mathewson 	--cp;
243461b93af5SNick Mathewson 
243561b93af5SNick Mathewson 	while (*cp == ' ' || *cp == '\t') {
243661b93af5SNick Mathewson 		*cp = '\0';
243761b93af5SNick Mathewson 		if (cp == str)
243861b93af5SNick Mathewson 			break;
243961b93af5SNick Mathewson 		--cp;
244061b93af5SNick Mathewson 	}
244161b93af5SNick Mathewson }
244261b93af5SNick Mathewson 
2443629a6133SNick Mathewson static int
evutil_issetugid(void)2444629a6133SNick Mathewson evutil_issetugid(void)
2445629a6133SNick Mathewson {
244668120d9bSNick Mathewson #ifdef EVENT__HAVE_ISSETUGID
2447629a6133SNick Mathewson 	return issetugid();
2448629a6133SNick Mathewson #else
2449629a6133SNick Mathewson 
245068120d9bSNick Mathewson #ifdef EVENT__HAVE_GETEUID
2451629a6133SNick Mathewson 	if (getuid() != geteuid())
2452629a6133SNick Mathewson 		return 1;
2453629a6133SNick Mathewson #endif
245468120d9bSNick Mathewson #ifdef EVENT__HAVE_GETEGID
2455629a6133SNick Mathewson 	if (getgid() != getegid())
2456629a6133SNick Mathewson 		return 1;
2457629a6133SNick Mathewson #endif
2458629a6133SNick Mathewson 	return 0;
2459629a6133SNick Mathewson #endif
2460629a6133SNick Mathewson }
2461629a6133SNick Mathewson 
2462629a6133SNick Mathewson const char *
evutil_getenv_(const char * varname)24638ac3c4c2SNick Mathewson evutil_getenv_(const char *varname)
2464629a6133SNick Mathewson {
2465629a6133SNick Mathewson 	if (evutil_issetugid())
2466629a6133SNick Mathewson 		return NULL;
2467629a6133SNick Mathewson 
2468629a6133SNick Mathewson 	return getenv(varname);
2469629a6133SNick Mathewson }
2470165d30e3SNick Mathewson 
2471e86af4b7SNicholas Marriott ev_uint32_t
evutil_weakrand_seed_(struct evutil_weakrand_state * state,ev_uint32_t seed)24723aa44159SNick Mathewson evutil_weakrand_seed_(struct evutil_weakrand_state *state, ev_uint32_t seed)
2473165d30e3SNick Mathewson {
24743aa44159SNick Mathewson 	if (seed == 0) {
24753aa44159SNick Mathewson 		struct timeval tv;
24763aa44159SNick Mathewson 		evutil_gettimeofday(&tv, NULL);
24773aa44159SNick Mathewson 		seed = (ev_uint32_t)tv.tv_sec + (ev_uint32_t)tv.tv_usec;
24783aa44159SNick Mathewson #ifdef _WIN32
24793aa44159SNick Mathewson 		seed += (ev_uint32_t) _getpid();
24803aa44159SNick Mathewson #else
24813aa44159SNick Mathewson 		seed += (ev_uint32_t) getpid();
24823aa44159SNick Mathewson #endif
24833aa44159SNick Mathewson 	}
24843aa44159SNick Mathewson 	state->seed = seed;
24853aa44159SNick Mathewson 	return seed;
2486e86af4b7SNicholas Marriott }
2487e86af4b7SNicholas Marriott 
24883aa44159SNick Mathewson ev_int32_t
evutil_weakrand_(struct evutil_weakrand_state * state)24893aa44159SNick Mathewson evutil_weakrand_(struct evutil_weakrand_state *state)
2490e86af4b7SNicholas Marriott {
24913aa44159SNick Mathewson 	/* This RNG implementation is a linear congruential generator, with
24923aa44159SNick Mathewson 	 * modulus 2^31, multiplier 1103515245, and addend 12345.  It's also
24933aa44159SNick Mathewson 	 * used by OpenBSD, and by Glibc's TYPE_0 RNG.
24943aa44159SNick Mathewson 	 *
24953aa44159SNick Mathewson 	 * The linear congruential generator is not an industrial-strength
24963aa44159SNick Mathewson 	 * RNG!  It's fast, but it can have higher-order patterns.  Notably,
24973aa44159SNick Mathewson 	 * the low bits tend to have periodicity.
24983aa44159SNick Mathewson 	 */
24993aa44159SNick Mathewson 	state->seed = ((state->seed) * 1103515245 + 12345) & 0x7fffffff;
25003aa44159SNick Mathewson 	return (ev_int32_t)(state->seed);
25013aa44159SNick Mathewson }
2502e86af4b7SNicholas Marriott 
25033aa44159SNick Mathewson ev_int32_t
evutil_weakrand_range_(struct evutil_weakrand_state * state,ev_int32_t top)25043aa44159SNick Mathewson evutil_weakrand_range_(struct evutil_weakrand_state *state, ev_int32_t top)
25053aa44159SNick Mathewson {
25063aa44159SNick Mathewson 	ev_int32_t divisor, result;
25073aa44159SNick Mathewson 
25083aa44159SNick Mathewson 	/* We can't just do weakrand() % top, since the low bits of the LCG
25093aa44159SNick Mathewson 	 * are less random than the high ones.  (Specifically, since the LCG
25103aa44159SNick Mathewson 	 * modulus is 2^N, every 2^m for m<N will divide the modulus, and so
25113aa44159SNick Mathewson 	 * therefore the low m bits of the LCG will have period 2^m.) */
25123aa44159SNick Mathewson 	divisor = EVUTIL_WEAKRAND_MAX / top;
25133aa44159SNick Mathewson 	do {
25143aa44159SNick Mathewson 		result = evutil_weakrand_(state) / divisor;
25153aa44159SNick Mathewson 	} while (result >= top);
2516e86af4b7SNicholas Marriott 	return result;
2517165d30e3SNick Mathewson }
2518165d30e3SNick Mathewson 
2519f5ced88cSNick Mathewson /**
2520f5ced88cSNick Mathewson  * Volatile pointer to memset: we use this to keep the compiler from
2521f5ced88cSNick Mathewson  * eliminating our call to memset.
2522f5ced88cSNick Mathewson  */
2523f5ced88cSNick Mathewson void * (*volatile evutil_memset_volatile_)(void *, int, size_t) = memset;
2524f5ced88cSNick Mathewson 
2525f5ced88cSNick Mathewson void
evutil_memclear_(void * mem,size_t len)2526f5ced88cSNick Mathewson evutil_memclear_(void *mem, size_t len)
2527f5ced88cSNick Mathewson {
2528f5ced88cSNick Mathewson 	evutil_memset_volatile_(mem, 0, len);
2529f5ced88cSNick Mathewson }
2530f5ced88cSNick Mathewson 
25318d4aaf90SNick Mathewson int
evutil_sockaddr_is_loopback_(const struct sockaddr * addr)25328ac3c4c2SNick Mathewson evutil_sockaddr_is_loopback_(const struct sockaddr *addr)
25338d4aaf90SNick Mathewson {
25348d4aaf90SNick Mathewson 	static const char LOOPBACK_S6[16] =
25358d4aaf90SNick Mathewson 	    "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\1";
25368d4aaf90SNick Mathewson 	if (addr->sa_family == AF_INET) {
25378d4aaf90SNick Mathewson 		struct sockaddr_in *sin = (struct sockaddr_in *)addr;
25388d4aaf90SNick Mathewson 		return (ntohl(sin->sin_addr.s_addr) & 0xff000000) == 0x7f000000;
25398d4aaf90SNick Mathewson 	} else if (addr->sa_family == AF_INET6) {
25408d4aaf90SNick Mathewson 		struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)addr;
25418d4aaf90SNick Mathewson 		return !memcmp(sin6->sin6_addr.s6_addr, LOOPBACK_S6, 16);
25428d4aaf90SNick Mathewson 	}
25438d4aaf90SNick Mathewson 	return 0;
25448d4aaf90SNick Mathewson }
25458d4aaf90SNick Mathewson 
254620fda296SNick Mathewson int
evutil_hex_char_to_int_(char c)25478ac3c4c2SNick Mathewson evutil_hex_char_to_int_(char c)
254820fda296SNick Mathewson {
254920fda296SNick Mathewson 	switch(c)
255020fda296SNick Mathewson 	{
255120fda296SNick Mathewson 		case '0': return 0;
255220fda296SNick Mathewson 		case '1': return 1;
255320fda296SNick Mathewson 		case '2': return 2;
255420fda296SNick Mathewson 		case '3': return 3;
255520fda296SNick Mathewson 		case '4': return 4;
255620fda296SNick Mathewson 		case '5': return 5;
255720fda296SNick Mathewson 		case '6': return 6;
255820fda296SNick Mathewson 		case '7': return 7;
255920fda296SNick Mathewson 		case '8': return 8;
256020fda296SNick Mathewson 		case '9': return 9;
256120fda296SNick Mathewson 		case 'A': case 'a': return 10;
256220fda296SNick Mathewson 		case 'B': case 'b': return 11;
256320fda296SNick Mathewson 		case 'C': case 'c': return 12;
256420fda296SNick Mathewson 		case 'D': case 'd': return 13;
256520fda296SNick Mathewson 		case 'E': case 'e': return 14;
256620fda296SNick Mathewson 		case 'F': case 'f': return 15;
256720fda296SNick Mathewson 	}
256820fda296SNick Mathewson 	return -1;
256920fda296SNick Mathewson }
2570d49b5e33SNick Mathewson 
25719f560bfaSNick Mathewson #ifdef _WIN32
2572f691389eSNick Mathewson HMODULE
evutil_load_windows_system_library_(const TCHAR * library_name)25738ac3c4c2SNick Mathewson evutil_load_windows_system_library_(const TCHAR *library_name)
2574d49b5e33SNick Mathewson {
2575d49b5e33SNick Mathewson   TCHAR path[MAX_PATH];
2576d49b5e33SNick Mathewson   unsigned n;
2577d49b5e33SNick Mathewson   n = GetSystemDirectory(path, MAX_PATH);
2578d49b5e33SNick Mathewson   if (n == 0 || n + _tcslen(library_name) + 2 >= MAX_PATH)
2579d49b5e33SNick Mathewson     return 0;
2580d49b5e33SNick Mathewson   _tcscat(path, TEXT("\\"));
2581d49b5e33SNick Mathewson   _tcscat(path, library_name);
2582d49b5e33SNick Mathewson   return LoadLibrary(path);
2583d49b5e33SNick Mathewson }
2584d49b5e33SNick Mathewson #endif
2585d49b5e33SNick Mathewson 
2586a1c042bfSNick Mathewson /* Internal wrapper around 'socket' to provide Linux-style support for
2587a1c042bfSNick Mathewson  * syscall-saving methods where available.
2588a1c042bfSNick Mathewson  *
2589a1c042bfSNick Mathewson  * In addition to regular socket behavior, you can use a bitwise or to set the
2590a1c042bfSNick Mathewson  * flags EVUTIL_SOCK_NONBLOCK and EVUTIL_SOCK_CLOEXEC in the 'type' argument,
2591a1c042bfSNick Mathewson  * to make the socket nonblocking or close-on-exec with as few syscalls as
2592a1c042bfSNick Mathewson  * possible.
2593a1c042bfSNick Mathewson  */
2594a1c042bfSNick Mathewson evutil_socket_t
evutil_socket_(int domain,int type,int protocol)25958ac3c4c2SNick Mathewson evutil_socket_(int domain, int type, int protocol)
2596a1c042bfSNick Mathewson {
2597a1c042bfSNick Mathewson 	evutil_socket_t r;
2598a1c042bfSNick Mathewson #if defined(SOCK_NONBLOCK) && defined(SOCK_CLOEXEC)
2599a1c042bfSNick Mathewson 	r = socket(domain, type, protocol);
2600a6492cb7SNick Mathewson 	if (r >= 0)
2601a6492cb7SNick Mathewson 		return r;
2602a6492cb7SNick Mathewson 	else if ((type & (SOCK_NONBLOCK|SOCK_CLOEXEC)) == 0)
2603a1c042bfSNick Mathewson 		return -1;
2604a1c042bfSNick Mathewson #endif
2605a1c042bfSNick Mathewson #define SOCKET_TYPE_MASK (~(EVUTIL_SOCK_NONBLOCK|EVUTIL_SOCK_CLOEXEC))
2606a1c042bfSNick Mathewson 	r = socket(domain, type & SOCKET_TYPE_MASK, protocol);
2607a1c042bfSNick Mathewson 	if (r < 0)
2608a1c042bfSNick Mathewson 		return -1;
2609a1c042bfSNick Mathewson 	if (type & EVUTIL_SOCK_NONBLOCK) {
2610a1c042bfSNick Mathewson 		if (evutil_fast_socket_nonblocking(r) < 0) {
2611a1c042bfSNick Mathewson 			evutil_closesocket(r);
2612a1c042bfSNick Mathewson 			return -1;
2613a1c042bfSNick Mathewson 		}
2614a1c042bfSNick Mathewson 	}
2615a1c042bfSNick Mathewson 	if (type & EVUTIL_SOCK_CLOEXEC) {
2616a1c042bfSNick Mathewson 		if (evutil_fast_socket_closeonexec(r) < 0) {
2617a1c042bfSNick Mathewson 			evutil_closesocket(r);
2618a1c042bfSNick Mathewson 			return -1;
2619a1c042bfSNick Mathewson 		}
2620a1c042bfSNick Mathewson 	}
2621a1c042bfSNick Mathewson 	return r;
2622a1c042bfSNick Mathewson }
2623a1c042bfSNick Mathewson 
2624a1c042bfSNick Mathewson /* Internal wrapper around 'accept' or 'accept4' to provide Linux-style
2625a1c042bfSNick Mathewson  * support for syscall-saving methods where available.
2626a1c042bfSNick Mathewson  *
2627a1c042bfSNick Mathewson  * In addition to regular accept behavior, you can set one or more of flags
2628a1c042bfSNick Mathewson  * EVUTIL_SOCK_NONBLOCK and EVUTIL_SOCK_CLOEXEC in the 'flags' argument, to
2629a1c042bfSNick Mathewson  * make the socket nonblocking or close-on-exec with as few syscalls as
2630a1c042bfSNick Mathewson  * possible.
2631a1c042bfSNick Mathewson  */
2632a1c042bfSNick Mathewson evutil_socket_t
evutil_accept4_(evutil_socket_t sockfd,struct sockaddr * addr,ev_socklen_t * addrlen,int flags)26338ac3c4c2SNick Mathewson evutil_accept4_(evutil_socket_t sockfd, struct sockaddr *addr,
2634ca47fa0bSNick Mathewson     ev_socklen_t *addrlen, int flags)
2635a1c042bfSNick Mathewson {
263674d32dd4SNick Mathewson 	evutil_socket_t result;
263768120d9bSNick Mathewson #if defined(EVENT__HAVE_ACCEPT4) && defined(SOCK_CLOEXEC) && defined(SOCK_NONBLOCK)
263874d32dd4SNick Mathewson 	result = accept4(sockfd, addr, addrlen, flags);
26399fbfe9b9SNick Mathewson 	if (result >= 0 || (errno != EINVAL && errno != ENOSYS)) {
26409fbfe9b9SNick Mathewson 		/* A nonnegative result means that we succeeded, so return.
26419fbfe9b9SNick Mathewson 		 * Failing with EINVAL means that an option wasn't supported,
26429fbfe9b9SNick Mathewson 		 * and failing with ENOSYS means that the syscall wasn't
26439fbfe9b9SNick Mathewson 		 * there: in those cases we want to fall back.  Otherwise, we
26449fbfe9b9SNick Mathewson 		 * got a real error, and we should return. */
264574d32dd4SNick Mathewson 		return result;
26469fbfe9b9SNick Mathewson 	}
264774d32dd4SNick Mathewson #endif
264874d32dd4SNick Mathewson 	result = accept(sockfd, addr, addrlen);
2649a1c042bfSNick Mathewson 	if (result < 0)
2650a1c042bfSNick Mathewson 		return result;
2651a1c042bfSNick Mathewson 
2652a1c042bfSNick Mathewson 	if (flags & EVUTIL_SOCK_CLOEXEC) {
2653a1c042bfSNick Mathewson 		if (evutil_fast_socket_closeonexec(result) < 0) {
2654a1c042bfSNick Mathewson 			evutil_closesocket(result);
2655a1c042bfSNick Mathewson 			return -1;
2656a1c042bfSNick Mathewson 		}
2657a1c042bfSNick Mathewson 	}
2658a1c042bfSNick Mathewson 	if (flags & EVUTIL_SOCK_NONBLOCK) {
2659a1c042bfSNick Mathewson 		if (evutil_fast_socket_nonblocking(result) < 0) {
2660a1c042bfSNick Mathewson 			evutil_closesocket(result);
2661a1c042bfSNick Mathewson 			return -1;
2662a1c042bfSNick Mathewson 		}
2663a1c042bfSNick Mathewson 	}
2664a1c042bfSNick Mathewson 	return result;
2665a1c042bfSNick Mathewson }
2666a1c042bfSNick Mathewson 
2667a1c042bfSNick Mathewson /* Internal function: Set fd[0] and fd[1] to a pair of fds such that writes on
26687f0a7564SXiang Zhang  * fd[1] get read from fd[0].  Make both fds nonblocking and close-on-exec.
2669a1c042bfSNick Mathewson  * Return 0 on success, -1 on failure.
2670a1c042bfSNick Mathewson  */
2671a1c042bfSNick Mathewson int
evutil_make_internal_pipe_(evutil_socket_t fd[2])26728ac3c4c2SNick Mathewson evutil_make_internal_pipe_(evutil_socket_t fd[2])
2673a1c042bfSNick Mathewson {
2674a1c042bfSNick Mathewson 	/*
2675a1c042bfSNick Mathewson 	  Making the second socket nonblocking is a bit subtle, given that we
2676a1c042bfSNick Mathewson 	  ignore any EAGAIN returns when writing to it, and you don't usally
2677a1c042bfSNick Mathewson 	  do that for a nonblocking socket. But if the kernel gives us EAGAIN,
2678a1c042bfSNick Mathewson 	  then there's no need to add any more data to the buffer, since
2679a1c042bfSNick Mathewson 	  the main thread is already either about to wake up and drain it,
2680a1c042bfSNick Mathewson 	  or woken up and in the process of draining it.
2681a1c042bfSNick Mathewson 	*/
2682a1c042bfSNick Mathewson 
268368120d9bSNick Mathewson #if defined(EVENT__HAVE_PIPE2)
2684a1c042bfSNick Mathewson 	if (pipe2(fd, O_NONBLOCK|O_CLOEXEC) == 0)
2685a1c042bfSNick Mathewson 		return 0;
2686a1c042bfSNick Mathewson #endif
268768120d9bSNick Mathewson #if defined(EVENT__HAVE_PIPE)
2688a1c042bfSNick Mathewson 	if (pipe(fd) == 0) {
2689a1c042bfSNick Mathewson 		if (evutil_fast_socket_nonblocking(fd[0]) < 0 ||
2690a1c042bfSNick Mathewson 		    evutil_fast_socket_nonblocking(fd[1]) < 0 ||
2691a1c042bfSNick Mathewson 		    evutil_fast_socket_closeonexec(fd[0]) < 0 ||
2692a1c042bfSNick Mathewson 		    evutil_fast_socket_closeonexec(fd[1]) < 0) {
2693a1c042bfSNick Mathewson 			close(fd[0]);
2694a1c042bfSNick Mathewson 			close(fd[1]);
2695a1c042bfSNick Mathewson 			fd[0] = fd[1] = -1;
2696a1c042bfSNick Mathewson 			return -1;
2697a1c042bfSNick Mathewson 		}
2698a1c042bfSNick Mathewson 		return 0;
2699a1c042bfSNick Mathewson 	} else {
2700a1c042bfSNick Mathewson 		event_warn("%s: pipe", __func__);
2701a1c042bfSNick Mathewson 	}
2702a1c042bfSNick Mathewson #endif
2703a1c042bfSNick Mathewson 
2704a1c042bfSNick Mathewson #ifdef _WIN32
2705a1c042bfSNick Mathewson #define LOCAL_SOCKETPAIR_AF AF_INET
2706a1c042bfSNick Mathewson #else
2707a1c042bfSNick Mathewson #define LOCAL_SOCKETPAIR_AF AF_UNIX
2708a1c042bfSNick Mathewson #endif
2709a1c042bfSNick Mathewson 	if (evutil_socketpair(LOCAL_SOCKETPAIR_AF, SOCK_STREAM, 0, fd) == 0) {
2710a1c042bfSNick Mathewson 		if (evutil_fast_socket_nonblocking(fd[0]) < 0 ||
2711a1c042bfSNick Mathewson 		    evutil_fast_socket_nonblocking(fd[1]) < 0 ||
2712a1c042bfSNick Mathewson 		    evutil_fast_socket_closeonexec(fd[0]) < 0 ||
2713a1c042bfSNick Mathewson 		    evutil_fast_socket_closeonexec(fd[1]) < 0) {
2714a1c042bfSNick Mathewson 			evutil_closesocket(fd[0]);
2715a1c042bfSNick Mathewson 			evutil_closesocket(fd[1]);
2716a1c042bfSNick Mathewson 			fd[0] = fd[1] = -1;
2717a1c042bfSNick Mathewson 			return -1;
2718a1c042bfSNick Mathewson 		}
2719a1c042bfSNick Mathewson 		return 0;
2720a1c042bfSNick Mathewson 	}
2721a1c042bfSNick Mathewson 	fd[0] = fd[1] = -1;
2722a1c042bfSNick Mathewson 	return -1;
2723a1c042bfSNick Mathewson }
2724a1c042bfSNick Mathewson 
2725a1c042bfSNick Mathewson /* Wrapper around eventfd on systems that provide it.  Unlike the system
2726a1c042bfSNick Mathewson  * eventfd, it always supports EVUTIL_EFD_CLOEXEC and EVUTIL_EFD_NONBLOCK as
2727a1c042bfSNick Mathewson  * flags.  Returns -1 on error or if eventfd is not supported.
2728a1c042bfSNick Mathewson  */
2729a1c042bfSNick Mathewson evutil_socket_t
evutil_eventfd_(unsigned initval,int flags)27308ac3c4c2SNick Mathewson evutil_eventfd_(unsigned initval, int flags)
2731a1c042bfSNick Mathewson {
273268120d9bSNick Mathewson #if defined(EVENT__HAVE_EVENTFD) && defined(EVENT__HAVE_SYS_EVENTFD_H)
2733a1c042bfSNick Mathewson 	int r;
2734a1c042bfSNick Mathewson #if defined(EFD_CLOEXEC) && defined(EFD_NONBLOCK)
2735a1c042bfSNick Mathewson 	r = eventfd(initval, flags);
2736a1c042bfSNick Mathewson 	if (r >= 0 || flags == 0)
2737a1c042bfSNick Mathewson 		return r;
2738a1c042bfSNick Mathewson #endif
2739a1c042bfSNick Mathewson 	r = eventfd(initval, 0);
2740a1c042bfSNick Mathewson 	if (r < 0)
2741a1c042bfSNick Mathewson 		return r;
2742a1c042bfSNick Mathewson 	if (flags & EVUTIL_EFD_CLOEXEC) {
2743a1c042bfSNick Mathewson 		if (evutil_fast_socket_closeonexec(r) < 0) {
2744a1c042bfSNick Mathewson 			evutil_closesocket(r);
2745a1c042bfSNick Mathewson 			return -1;
2746a1c042bfSNick Mathewson 		}
2747a1c042bfSNick Mathewson 	}
2748a1c042bfSNick Mathewson 	if (flags & EVUTIL_EFD_NONBLOCK) {
2749a1c042bfSNick Mathewson 		if (evutil_fast_socket_nonblocking(r) < 0) {
2750a1c042bfSNick Mathewson 			evutil_closesocket(r);
2751a1c042bfSNick Mathewson 			return -1;
2752a1c042bfSNick Mathewson 		}
2753a1c042bfSNick Mathewson 	}
2754a1c042bfSNick Mathewson 	return r;
2755a1c042bfSNick Mathewson #else
2756a1c042bfSNick Mathewson 	return -1;
2757a1c042bfSNick Mathewson #endif
2758a1c042bfSNick Mathewson }
2759a1c042bfSNick Mathewson 
2760041ca00cSMark Ellzey void
evutil_free_globals_(void)2761041ca00cSMark Ellzey evutil_free_globals_(void)
2762041ca00cSMark Ellzey {
2763041ca00cSMark Ellzey 	evutil_free_secure_rng_globals_();
27640c6ec5d8SPatrick Pelletier 	evutil_free_sock_err_globals();
2765041ca00cSMark Ellzey }
2766