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:
Peter Retzlaff
2013-05-27 19:16:43 +00:00
committed by Nick Mathewson
parent 83a859e24c
commit ebd4ab1506
5 changed files with 133 additions and 53 deletions
+3
View File
@@ -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
View File
@@ -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:
+12
View File
@@ -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)
+9
View File
@@ -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
View File
@@ -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);