mirror of
https://gitlab.torproject.org/tpo/core/tor.git
synced 2024-12-06 19:41:15 +01:00
Prepare patch for ticket 5129 for merging.
- Preserve old eventdns code. - Add function to close sockets cross-platform, without accounting. - Add changes/ file.
This commit is contained in:
committed by
Nick Mathewson
parent
83a859e24c
commit
ebd4ab1506
@@ -0,0 +1,3 @@
|
||||
o Minor features:
|
||||
- Use the SOCK_NONBLOCK socket type, if supported, to open nonblocking
|
||||
sockets in a single system call. Implements ticket #5129.
|
||||
+105
-36
@@ -948,24 +948,40 @@ socket_accounting_unlock(void)
|
||||
}
|
||||
|
||||
/** As close(), but guaranteed to work for sockets across platforms (including
|
||||
* Windows, where close()ing a socket doesn't work. Returns 0 on success, -1
|
||||
* on failure. */
|
||||
* Windows, where close()ing a socket doesn't work. Returns 0 on success and
|
||||
* the socket error code on failure. */
|
||||
int
|
||||
tor_close_socket(tor_socket_t s)
|
||||
tor_close_socket_simple(tor_socket_t s)
|
||||
{
|
||||
int r = 0;
|
||||
|
||||
/* On Windows, you have to call close() on fds returned by open(),
|
||||
* and closesocket() on fds returned by socket(). On Unix, everything
|
||||
* gets close()'d. We abstract this difference by always using
|
||||
* tor_close_socket to close sockets, and always using close() on
|
||||
* files.
|
||||
*/
|
||||
#if defined(_WIN32)
|
||||
r = closesocket(s);
|
||||
#else
|
||||
r = close(s);
|
||||
#endif
|
||||
* and closesocket() on fds returned by socket(). On Unix, everything
|
||||
* gets close()'d. We abstract this difference by always using
|
||||
* tor_close_socket to close sockets, and always using close() on
|
||||
* files.
|
||||
*/
|
||||
#if defined(_WIN32)
|
||||
r = closesocket(s);
|
||||
#else
|
||||
r = close(s);
|
||||
#endif
|
||||
|
||||
if (r != 0) {
|
||||
int err = tor_socket_errno(-1);
|
||||
log_info(LD_NET, "Close returned an error: %s", tor_socket_strerror(err));
|
||||
return err;
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
/** As tor_close_socket_simple(), but keeps track of the number
|
||||
* of open sockets. Returns 0 on success, -1 on failure. */
|
||||
int
|
||||
tor_close_socket(tor_socket_t s)
|
||||
{
|
||||
int r = tor_close_socket_simple(s);
|
||||
|
||||
socket_accounting_lock();
|
||||
#ifdef DEBUG_SOCKET_COUNTING
|
||||
@@ -980,13 +996,11 @@ tor_close_socket(tor_socket_t s)
|
||||
if (r == 0) {
|
||||
--n_sockets_open;
|
||||
} else {
|
||||
int err = tor_socket_errno(-1);
|
||||
log_info(LD_NET, "Close returned an error: %s", tor_socket_strerror(err));
|
||||
#ifdef _WIN32
|
||||
if (err != WSAENOTSOCK)
|
||||
if (r != WSAENOTSOCK)
|
||||
--n_sockets_open;
|
||||
#else
|
||||
if (err != EBADF)
|
||||
if (r != EBADF)
|
||||
--n_sockets_open;
|
||||
#endif
|
||||
r = -1;
|
||||
@@ -1031,18 +1045,39 @@ mark_socket_open(tor_socket_t s)
|
||||
/** As socket(), but counts the number of open sockets. */
|
||||
tor_socket_t
|
||||
tor_open_socket(int domain, int type, int protocol)
|
||||
{
|
||||
return tor_open_socket_with_extensions(domain, type, protocol, 1, 0);
|
||||
}
|
||||
|
||||
/** As socket(), but creates a nonblocking socket and
|
||||
* counts the number of open sockets. */
|
||||
tor_socket_t
|
||||
tor_open_socket_nonblocking(int domain, int type, int protocol)
|
||||
{
|
||||
return tor_open_socket_with_extensions(domain, type, protocol, 1, 1);
|
||||
}
|
||||
|
||||
/** As socket(), but counts the number of open sockets and handles
|
||||
* socket creation with either of SOCK_CLOEXEC and SOCK_NONBLOCK specified.
|
||||
* <b>cloexec</b> and <b>nonblock</b> should be either 0 or 1 to indicate
|
||||
* if the corresponding extension should be used.*/
|
||||
tor_socket_t
|
||||
tor_open_socket_with_extensions(int domain, int type, int protocol,
|
||||
int cloexec, int nonblock)
|
||||
{
|
||||
tor_socket_t s;
|
||||
#ifdef SOCK_CLOEXEC
|
||||
s = socket(domain, type|SOCK_CLOEXEC, protocol);
|
||||
#if defined(SOCK_CLOEXEC) && defined(SOCK_NONBLOCK)
|
||||
int ext_flags = (cloexec ? SOCK_CLOEXEC : 0) |
|
||||
(nonblock ? SOCK_NONBLOCK : 0);
|
||||
s = socket(domain, type|ext_flags, protocol);
|
||||
if (SOCKET_OK(s))
|
||||
goto socket_ok;
|
||||
/* If we got an error, see if it is EINVAL. EINVAL might indicate that,
|
||||
* even though we were built on a system with SOCK_CLOEXEC support, we
|
||||
* are running on one without. */
|
||||
* even though we were built on a system with SOCK_CLOEXEC and SOCK_NONBLOCK
|
||||
* support, we are running on one without. */
|
||||
if (errno != EINVAL)
|
||||
return s;
|
||||
#endif /* SOCK_CLOEXEC */
|
||||
#endif /* SOCK_CLOEXEC && SOCK_NONBLOCK */
|
||||
|
||||
s = socket(domain, type, protocol);
|
||||
if (! SOCKET_OK(s))
|
||||
@@ -1051,15 +1086,18 @@ tor_open_socket(int domain, int type, int protocol)
|
||||
#if defined(FD_CLOEXEC)
|
||||
if (fcntl(s, F_SETFD, FD_CLOEXEC) == -1) {
|
||||
log_warn(LD_FS,"Couldn't set FD_CLOEXEC: %s", strerror(errno));
|
||||
#if defined(_WIN32)
|
||||
closesocket(s);
|
||||
#else
|
||||
close(s);
|
||||
#endif
|
||||
return -1;
|
||||
tor_close_socket_simple(s);
|
||||
return TOR_INVALID_SOCKET;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (nonblock) {
|
||||
if (set_socket_nonblocking(s) == -1) {
|
||||
tor_close_socket_simple(s);
|
||||
return TOR_INVALID_SOCKET;
|
||||
}
|
||||
}
|
||||
|
||||
goto socket_ok; /* So that socket_ok will not be unused. */
|
||||
|
||||
socket_ok:
|
||||
@@ -1070,19 +1108,41 @@ tor_open_socket(int domain, int type, int protocol)
|
||||
return s;
|
||||
}
|
||||
|
||||
/** As socket(), but counts the number of open sockets. */
|
||||
/** As accept(), but counts the number of open sockets. */
|
||||
tor_socket_t
|
||||
tor_accept_socket(tor_socket_t sockfd, struct sockaddr *addr, socklen_t *len)
|
||||
{
|
||||
return tor_accept_socket_with_extensions(sockfd, addr, len, 1, 0);
|
||||
}
|
||||
|
||||
/** As accept(), but returns a nonblocking socket and
|
||||
* counts the number of open sockets. */
|
||||
tor_socket_t
|
||||
tor_accept_socket_nonblocking(tor_socket_t sockfd, struct sockaddr *addr,
|
||||
socklen_t *len)
|
||||
{
|
||||
return tor_accept_socket_with_extensions(sockfd, addr, len, 1, 1);
|
||||
}
|
||||
|
||||
/** As accept(), but counts the number of open sockets and handles
|
||||
* socket creation with either of SOCK_CLOEXEC and SOCK_NONBLOCK specified.
|
||||
* <b>cloexec</b> and <b>nonblock</b> should be either 0 or 1 to indicate
|
||||
* if the corresponding extension should be used.*/
|
||||
tor_socket_t
|
||||
tor_accept_socket_with_extensions(tor_socket_t sockfd, struct sockaddr *addr,
|
||||
socklen_t *len, int cloexec, int nonblock)
|
||||
{
|
||||
tor_socket_t s;
|
||||
#if defined(HAVE_ACCEPT4) && defined(SOCK_CLOEXEC)
|
||||
s = accept4(sockfd, addr, len, SOCK_CLOEXEC);
|
||||
#if defined(HAVE_ACCEPT4) && defined(SOCK_CLOEXEC) && defined(SOCK_NONBLOCK)
|
||||
int ext_flags = (cloexec ? SOCK_CLOEXEC : 0) |
|
||||
(nonblock ? SOCK_NONBLOCK : 0);
|
||||
s = accept4(sockfd, addr, len, ext_flags);
|
||||
if (SOCKET_OK(s))
|
||||
goto socket_ok;
|
||||
/* If we got an error, see if it is ENOSYS. ENOSYS indicates that,
|
||||
* even though we were built on a system with accept4 support, we
|
||||
* are running on one without. Also, check for EINVAL, which indicates that
|
||||
* we are missing SOCK_CLOEXEC support. */
|
||||
* we are missing SOCK_CLOEXEC/SOCK_NONBLOCK support. */
|
||||
if (errno != EINVAL && errno != ENOSYS)
|
||||
return s;
|
||||
#endif
|
||||
@@ -1092,13 +1152,22 @@ tor_accept_socket(tor_socket_t sockfd, struct sockaddr *addr, socklen_t *len)
|
||||
return s;
|
||||
|
||||
#if defined(FD_CLOEXEC)
|
||||
if (fcntl(s, F_SETFD, FD_CLOEXEC) == -1) {
|
||||
log_warn(LD_NET, "Couldn't set FD_CLOEXEC: %s", strerror(errno));
|
||||
close(s);
|
||||
return TOR_INVALID_SOCKET;
|
||||
if (cloexec) {
|
||||
if (fcntl(s, F_SETFD, FD_CLOEXEC) == -1) {
|
||||
log_warn(LD_NET, "Couldn't set FD_CLOEXEC: %s", strerror(errno));
|
||||
tor_close_socket_simple(s);
|
||||
return TOR_INVALID_SOCKET;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (nonblock) {
|
||||
if (set_socket_nonblocking(s) == -1) {
|
||||
tor_close_socket_simple(s);
|
||||
return TOR_INVALID_SOCKET;
|
||||
}
|
||||
}
|
||||
|
||||
goto socket_ok; /* So that socket_ok will not be unused. */
|
||||
|
||||
socket_ok:
|
||||
|
||||
@@ -450,10 +450,22 @@ typedef int socklen_t;
|
||||
#define TOR_INVALID_SOCKET (-1)
|
||||
#endif
|
||||
|
||||
int tor_close_socket_simple(tor_socket_t s);
|
||||
int tor_close_socket(tor_socket_t s);
|
||||
tor_socket_t tor_open_socket_with_extensions(
|
||||
int domain, int type, int protocol,
|
||||
int cloexec, int nonblock);
|
||||
tor_socket_t tor_open_socket(int domain, int type, int protocol);
|
||||
tor_socket_t tor_open_socket_nonblocking(int domain, int type, int protocol);
|
||||
tor_socket_t tor_accept_socket(tor_socket_t sockfd, struct sockaddr *addr,
|
||||
socklen_t *len);
|
||||
tor_socket_t tor_accept_socket_nonblocking(tor_socket_t sockfd,
|
||||
struct sockaddr *addr,
|
||||
socklen_t *len);
|
||||
tor_socket_t tor_accept_socket_with_extensions(tor_socket_t sockfd,
|
||||
struct sockaddr *addr,
|
||||
socklen_t *len,
|
||||
int cloexec, int nonblock);
|
||||
int get_n_open_sockets(void);
|
||||
|
||||
#define tor_socket_send(s, buf, len, flags) send(s, buf, len, flags)
|
||||
|
||||
@@ -2298,6 +2298,10 @@ _evdns_nameserver_add_impl(const struct sockaddr *address,
|
||||
|
||||
evtimer_set(&ns->timeout_event, nameserver_prod_callback, ns);
|
||||
|
||||
#if 1
|
||||
ns->socket = tor_open_socket_nonblocking(address->sa_family, SOCK_DGRAM, 0);
|
||||
if (!SOCKET_OK(ns->socket)) { err = 1; goto out1; }
|
||||
#else
|
||||
ns->socket = tor_open_socket(address->sa_family, SOCK_DGRAM, 0);
|
||||
if (ns->socket < 0) { err = 1; goto out1; }
|
||||
#ifdef _WIN32
|
||||
@@ -2314,6 +2318,7 @@ _evdns_nameserver_add_impl(const struct sockaddr *address,
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* 1 */
|
||||
if (global_bind_addr_is_set &&
|
||||
!sockaddr_is_loopback((struct sockaddr*)&global_bind_address)) {
|
||||
if (bind(ns->socket, (struct sockaddr *)&global_bind_address,
|
||||
@@ -3473,8 +3478,12 @@ main(int c, char **v) {
|
||||
if (servertest) {
|
||||
int sock;
|
||||
struct sockaddr_in my_addr;
|
||||
#if 1
|
||||
sock = tor_open_socket_nonblocking(PF_INET, SOCK_DGRAM, 0)
|
||||
#else
|
||||
sock = tor_open_socket(PF_INET, SOCK_DGRAM, 0);
|
||||
fcntl(sock, F_SETFL, O_NONBLOCK);
|
||||
#endif
|
||||
my_addr.sin_family = AF_INET;
|
||||
my_addr.sin_port = htons(10053);
|
||||
my_addr.sin_addr.s_addr = INADDR_ANY;
|
||||
|
||||
+4
-17
@@ -970,7 +970,7 @@ connection_listener_new(const struct sockaddr *listensockaddr,
|
||||
log_notice(LD_NET, "Opening %s on %s",
|
||||
conn_type_to_string(type), fmt_addrport(&addr, usePort));
|
||||
|
||||
s = tor_open_socket(tor_addr_family(&addr),
|
||||
s = tor_open_socket_nonblocking(tor_addr_family(&addr),
|
||||
is_tcp ? SOCK_STREAM : SOCK_DGRAM,
|
||||
is_tcp ? IPPROTO_TCP: IPPROTO_UDP);
|
||||
if (!SOCKET_OK(s)) {
|
||||
@@ -1054,7 +1054,7 @@ connection_listener_new(const struct sockaddr *listensockaddr,
|
||||
strerror(errno));
|
||||
goto err;
|
||||
}
|
||||
s = tor_open_socket(AF_UNIX, SOCK_STREAM, 0);
|
||||
s = tor_open_socket_nonblocking(AF_UNIX, SOCK_STREAM, 0);
|
||||
if (! SOCKET_OK(s)) {
|
||||
log_warn(LD_NET,"Socket creation failed: %s.", strerror(errno));
|
||||
goto err;
|
||||
@@ -1102,9 +1102,6 @@ connection_listener_new(const struct sockaddr *listensockaddr,
|
||||
tor_assert(0);
|
||||
}
|
||||
|
||||
if (set_socket_nonblocking(s) == -1)
|
||||
goto err;
|
||||
|
||||
lis_conn = listener_connection_new(type, listensockaddr->sa_family);
|
||||
conn = TO_CONN(lis_conn);
|
||||
conn->socket_family = listensockaddr->sa_family;
|
||||
@@ -1252,7 +1249,7 @@ connection_handle_listener_read(connection_t *conn, int new_type)
|
||||
tor_assert((size_t)remotelen >= sizeof(struct sockaddr_in));
|
||||
memset(&addrbuf, 0, sizeof(addrbuf));
|
||||
|
||||
news = tor_accept_socket(conn->s,remote,&remotelen);
|
||||
news = tor_accept_socket_nonblocking(conn->s,remote,&remotelen);
|
||||
if (!SOCKET_OK(news)) { /* accept() error */
|
||||
int e = tor_socket_errno(conn->s);
|
||||
if (ERRNO_IS_ACCEPT_EAGAIN(e)) {
|
||||
@@ -1272,10 +1269,6 @@ connection_handle_listener_read(connection_t *conn, int new_type)
|
||||
(int)news,(int)conn->s);
|
||||
|
||||
make_socket_reuseable(news);
|
||||
if (set_socket_nonblocking(news) == -1) {
|
||||
tor_close_socket(news);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (options->ConstrainedSockets)
|
||||
set_constrained_socket_buffers(news, (int)options->ConstrainedSockSize);
|
||||
@@ -1467,7 +1460,7 @@ connection_connect(connection_t *conn, const char *address,
|
||||
return -1;
|
||||
}
|
||||
|
||||
s = tor_open_socket(protocol_family,SOCK_STREAM,IPPROTO_TCP);
|
||||
s = tor_open_socket_nonblocking(protocol_family,SOCK_STREAM,IPPROTO_TCP);
|
||||
if (! SOCKET_OK(s)) {
|
||||
*socket_error = tor_socket_errno(-1);
|
||||
log_warn(LD_NET,"Error creating network socket: %s",
|
||||
@@ -1509,12 +1502,6 @@ connection_connect(connection_t *conn, const char *address,
|
||||
}
|
||||
}
|
||||
|
||||
if (set_socket_nonblocking(s) == -1) {
|
||||
*socket_error = tor_socket_errno(s);
|
||||
tor_close_socket(s);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (options->ConstrainedSockets)
|
||||
set_constrained_socket_buffers(s, (int)options->ConstrainedSockSize);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user