[tor-commits] [tor/master] Extract tor_ersatz_socketpair into a new c file

nickm at torproject.org nickm at torproject.org
Tue Sep 4 15:05:03 UTC 2018


commit 2884639ad63583d2a5a3dd14185c77212e566b5f
Author: Nick Mathewson <nickm at torproject.org>
Date:   Wed Aug 1 08:47:27 2018 -0400

    Extract tor_ersatz_socketpair into a new c file
    
    I'm doing this because I want to make it a lower-level function
    again, so that we can use it without linking in the rest of the
    universe.
---
 src/lib/net/include.am   |   4 +-
 src/lib/net/socket.c     | 155 +-------------------------------------------
 src/lib/net/socket.h     |   8 ---
 src/lib/net/socketpair.c | 164 +++++++++++++++++++++++++++++++++++++++++++++++
 src/lib/net/socketpair.h |  19 ++++++
 src/test/test_util.c     |   1 +
 6 files changed, 188 insertions(+), 163 deletions(-)

diff --git a/src/lib/net/include.am b/src/lib/net/include.am
index 67db0d5af..ff0967e78 100644
--- a/src/lib/net/include.am
+++ b/src/lib/net/include.am
@@ -12,7 +12,8 @@ src_lib_libtor_net_a_SOURCES =			\
 	src/lib/net/gethostname.c		\
 	src/lib/net/inaddr.c			\
 	src/lib/net/resolve.c			\
-	src/lib/net/socket.c
+	src/lib/net/socket.c			\
+	src/lib/net/socketpair.c
 
 src_lib_libtor_net_testing_a_SOURCES = \
 	$(src_lib_libtor_net_a_SOURCES)
@@ -29,4 +30,5 @@ noinst_HEADERS +=				\
 	src/lib/net/nettypes.h			\
 	src/lib/net/resolve.h			\
 	src/lib/net/socket.h			\
+	src/lib/net/socketpair.h		\
 	src/lib/net/socks5_status.h
diff --git a/src/lib/net/socket.c b/src/lib/net/socket.c
index 5847bb873..5487b8d9d 100644
--- a/src/lib/net/socket.c
+++ b/src/lib/net/socket.c
@@ -11,6 +11,7 @@
 
 #define SOCKET_PRIVATE
 #include "lib/net/socket.h"
+#include "lib/net/socketpair.h"
 #include "lib/net/address.h"
 #include "lib/cc/compat_compiler.h"
 #include "lib/err/torerr.h"
@@ -476,160 +477,6 @@ tor_socketpair(int family, int type, int protocol, tor_socket_t fd[2])
 #endif /* defined(HAVE_SOCKETPAIR) && !defined(_WIN32) */
 }
 
-#ifdef NEED_ERSATZ_SOCKETPAIR
-
-static inline socklen_t
-SIZEOF_SOCKADDR(int domain)
-{
-  switch (domain) {
-    case AF_INET:
-      return sizeof(struct sockaddr_in);
-    case AF_INET6:
-      return sizeof(struct sockaddr_in6);
-    default:
-      return 0;
-  }
-}
-
-/**
- * Helper used to implement socketpair on systems that lack it, by
- * making a direct connection to localhost.
- */
-STATIC int
-tor_ersatz_socketpair(int family, int type, int protocol, tor_socket_t fd[2])
-{
-    /* This socketpair does not work when localhost is down. So
-     * it's really not the same thing at all. But it's close enough
-     * for now, and really, when localhost is down sometimes, we
-     * have other problems too.
-     */
-    tor_socket_t listener = TOR_INVALID_SOCKET;
-    tor_socket_t connector = TOR_INVALID_SOCKET;
-    tor_socket_t acceptor = TOR_INVALID_SOCKET;
-    tor_addr_t listen_tor_addr;
-    struct sockaddr_storage connect_addr_ss, listen_addr_ss;
-    struct sockaddr *listen_addr = (struct sockaddr *) &listen_addr_ss;
-    uint16_t listen_port = 0;
-    tor_addr_t connect_tor_addr;
-    uint16_t connect_port = 0;
-    struct sockaddr *connect_addr = (struct sockaddr *) &connect_addr_ss;
-    socklen_t size;
-    int saved_errno = -1;
-    int ersatz_domain = AF_INET;
-
-    memset(&connect_tor_addr, 0, sizeof(connect_tor_addr));
-    memset(&connect_addr_ss, 0, sizeof(connect_addr_ss));
-    memset(&listen_tor_addr, 0, sizeof(listen_tor_addr));
-    memset(&listen_addr_ss, 0, sizeof(listen_addr_ss));
-
-    if (protocol
-#ifdef AF_UNIX
-        || family != AF_UNIX
-#endif
-        ) {
-#ifdef _WIN32
-      return -WSAEAFNOSUPPORT;
-#else
-      return -EAFNOSUPPORT;
-#endif
-    }
-    if (!fd) {
-      return -EINVAL;
-    }
-
-    listener = tor_open_socket(ersatz_domain, type, 0);
-    if (!SOCKET_OK(listener)) {
-      int first_errno = tor_socket_errno(-1);
-      if (first_errno == SOCK_ERRNO(EPROTONOSUPPORT)
-          && ersatz_domain == AF_INET) {
-        /* Assume we're on an IPv6-only system */
-        ersatz_domain = AF_INET6;
-        listener = tor_open_socket(ersatz_domain, type, 0);
-        if (!SOCKET_OK(listener)) {
-          /* Keep the previous behaviour, which was to return the IPv4 error.
-           * (This may be less informative on IPv6-only systems.)
-           * XX/teor - is there a better way to decide which errno to return?
-           * (I doubt we care much either way, once there is an error.)
-           */
-          return -first_errno;
-        }
-      }
-    }
-    /* If there is no 127.0.0.1 or ::1, this will and must fail. Otherwise, we
-     * risk exposing a socketpair on a routable IP address. (Some BSD jails
-     * use a routable address for localhost. Fortunately, they have the real
-     * AF_UNIX socketpair.) */
-    if (ersatz_domain == AF_INET) {
-      tor_addr_from_ipv4h(&listen_tor_addr, INADDR_LOOPBACK);
-    } else {
-      tor_addr_parse(&listen_tor_addr, "[::1]");
-    }
-    tor_assert(tor_addr_is_loopback(&listen_tor_addr));
-    size = tor_addr_to_sockaddr(&listen_tor_addr,
-                         0 /* kernel chooses port.  */,
-                         listen_addr,
-                         sizeof(listen_addr_ss));
-    if (bind(listener, listen_addr, size) == -1)
-      goto tidy_up_and_fail;
-    if (listen(listener, 1) == -1)
-      goto tidy_up_and_fail;
-
-    connector = tor_open_socket(ersatz_domain, type, 0);
-    if (!SOCKET_OK(connector))
-      goto tidy_up_and_fail;
-    /* We want to find out the port number to connect to.  */
-    size = sizeof(connect_addr_ss);
-    if (getsockname(listener, connect_addr, &size) == -1)
-      goto tidy_up_and_fail;
-    if (size != SIZEOF_SOCKADDR (connect_addr->sa_family))
-      goto abort_tidy_up_and_fail;
-    if (connect(connector, connect_addr, size) == -1)
-      goto tidy_up_and_fail;
-
-    size = sizeof(listen_addr_ss);
-    acceptor = tor_accept_socket(listener, listen_addr, &size);
-    if (!SOCKET_OK(acceptor))
-      goto tidy_up_and_fail;
-    if (size != SIZEOF_SOCKADDR(listen_addr->sa_family))
-      goto abort_tidy_up_and_fail;
-    /* Now check we are talking to ourself by matching port and host on the
-       two sockets.  */
-    if (getsockname(connector, connect_addr, &size) == -1)
-      goto tidy_up_and_fail;
-    /* Set *_tor_addr and *_port to the address and port that was used */
-    tor_addr_from_sockaddr(&listen_tor_addr, listen_addr, &listen_port);
-    tor_addr_from_sockaddr(&connect_tor_addr, connect_addr, &connect_port);
-    if (size != SIZEOF_SOCKADDR (connect_addr->sa_family)
-        || tor_addr_compare(&listen_tor_addr, &connect_tor_addr, CMP_SEMANTIC)
-        || listen_port != connect_port) {
-      goto abort_tidy_up_and_fail;
-    }
-    tor_close_socket(listener);
-    fd[0] = connector;
-    fd[1] = acceptor;
-
-    return 0;
-
-  abort_tidy_up_and_fail:
-#ifdef _WIN32
-    saved_errno = WSAECONNABORTED;
-#else
-    saved_errno = ECONNABORTED; /* I hope this is portable and appropriate.  */
-#endif
-  tidy_up_and_fail:
-    if (saved_errno < 0)
-      saved_errno = errno;
-    if (SOCKET_OK(listener))
-      tor_close_socket(listener);
-    if (SOCKET_OK(connector))
-      tor_close_socket(connector);
-    if (SOCKET_OK(acceptor))
-      tor_close_socket(acceptor);
-    return -saved_errno;
-}
-
-#endif /* defined(NEED_ERSATZ_SOCKETPAIR) */
-
 /** Mockable wrapper for getsockname(). */
 MOCK_IMPL(int,
 tor_getsockname,(tor_socket_t sock, struct sockaddr *address,
diff --git a/src/lib/net/socket.h b/src/lib/net/socket.h
index e2092c727..5b7d6dbbc 100644
--- a/src/lib/net/socket.h
+++ b/src/lib/net/socket.h
@@ -110,14 +110,6 @@ const char *tor_socket_strerror(int e);
 #define tor_socket_strerror(e)       strerror(e)
 #endif /* defined(_WIN32) */
 
-#ifdef SOCKET_PRIVATE
-#if !defined(HAVE_SOCKETPAIR) || defined(_WIN32) || defined(TOR_UNIT_TESTS)
-#define NEED_ERSATZ_SOCKETPAIR
-STATIC int tor_ersatz_socketpair(int family, int type, int protocol,
-                                   tor_socket_t fd[2]);
-#endif
-#endif /* defined(COMPAT_PRIVATE) */
-
 #if defined(_WIN32) && !defined(SIO_IDEAL_SEND_BACKLOG_QUERY)
 #define SIO_IDEAL_SEND_BACKLOG_QUERY 0x4004747b
 #endif
diff --git a/src/lib/net/socketpair.c b/src/lib/net/socketpair.c
new file mode 100644
index 000000000..945bdee69
--- /dev/null
+++ b/src/lib/net/socketpair.c
@@ -0,0 +1,164 @@
+/* Copyright (c) 2003-2004, Roger Dingledine
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2018, The Tor Project, Inc. */
+
+#include "lib/net/socketpair.h"
+#include "lib/net/socket.h"
+#include "lib/net/address.h"
+
+#include <errno.h>
+#include <string.h>
+
+#ifdef NEED_ERSATZ_SOCKETPAIR
+
+static inline socklen_t
+SIZEOF_SOCKADDR(int domain)
+{
+  switch (domain) {
+    case AF_INET:
+      return sizeof(struct sockaddr_in);
+    case AF_INET6:
+      return sizeof(struct sockaddr_in6);
+    default:
+      return 0;
+  }
+}
+
+/**
+ * Helper used to implement socketpair on systems that lack it, by
+ * making a direct connection to localhost.
+ */
+STATIC int
+tor_ersatz_socketpair(int family, int type, int protocol, tor_socket_t fd[2])
+{
+    /* This socketpair does not work when localhost is down. So
+     * it's really not the same thing at all. But it's close enough
+     * for now, and really, when localhost is down sometimes, we
+     * have other problems too.
+     */
+    tor_socket_t listener = TOR_INVALID_SOCKET;
+    tor_socket_t connector = TOR_INVALID_SOCKET;
+    tor_socket_t acceptor = TOR_INVALID_SOCKET;
+    tor_addr_t listen_tor_addr;
+    struct sockaddr_storage connect_addr_ss, listen_addr_ss;
+    struct sockaddr *listen_addr = (struct sockaddr *) &listen_addr_ss;
+    uint16_t listen_port = 0;
+    tor_addr_t connect_tor_addr;
+    uint16_t connect_port = 0;
+    struct sockaddr *connect_addr = (struct sockaddr *) &connect_addr_ss;
+    socklen_t size;
+    int saved_errno = -1;
+    int ersatz_domain = AF_INET;
+
+    memset(&connect_tor_addr, 0, sizeof(connect_tor_addr));
+    memset(&connect_addr_ss, 0, sizeof(connect_addr_ss));
+    memset(&listen_tor_addr, 0, sizeof(listen_tor_addr));
+    memset(&listen_addr_ss, 0, sizeof(listen_addr_ss));
+
+    if (protocol
+#ifdef AF_UNIX
+        || family != AF_UNIX
+#endif
+        ) {
+#ifdef _WIN32
+      return -WSAEAFNOSUPPORT;
+#else
+      return -EAFNOSUPPORT;
+#endif
+    }
+    if (!fd) {
+      return -EINVAL;
+    }
+
+    listener = tor_open_socket(ersatz_domain, type, 0);
+    if (!SOCKET_OK(listener)) {
+      int first_errno = tor_socket_errno(-1);
+      if (first_errno == SOCK_ERRNO(EPROTONOSUPPORT)
+          && ersatz_domain == AF_INET) {
+        /* Assume we're on an IPv6-only system */
+        ersatz_domain = AF_INET6;
+        listener = tor_open_socket(ersatz_domain, type, 0);
+        if (!SOCKET_OK(listener)) {
+          /* Keep the previous behaviour, which was to return the IPv4 error.
+           * (This may be less informative on IPv6-only systems.)
+           * XX/teor - is there a better way to decide which errno to return?
+           * (I doubt we care much either way, once there is an error.)
+           */
+          return -first_errno;
+        }
+      }
+    }
+    /* If there is no 127.0.0.1 or ::1, this will and must fail. Otherwise, we
+     * risk exposing a socketpair on a routable IP address. (Some BSD jails
+     * use a routable address for localhost. Fortunately, they have the real
+     * AF_UNIX socketpair.) */
+    if (ersatz_domain == AF_INET) {
+      tor_addr_from_ipv4h(&listen_tor_addr, INADDR_LOOPBACK);
+    } else {
+      tor_addr_parse(&listen_tor_addr, "[::1]");
+    }
+    tor_assert(tor_addr_is_loopback(&listen_tor_addr));
+    size = tor_addr_to_sockaddr(&listen_tor_addr,
+                         0 /* kernel chooses port.  */,
+                         listen_addr,
+                         sizeof(listen_addr_ss));
+    if (bind(listener, listen_addr, size) == -1)
+      goto tidy_up_and_fail;
+    if (listen(listener, 1) == -1)
+      goto tidy_up_and_fail;
+
+    connector = tor_open_socket(ersatz_domain, type, 0);
+    if (!SOCKET_OK(connector))
+      goto tidy_up_and_fail;
+    /* We want to find out the port number to connect to.  */
+    size = sizeof(connect_addr_ss);
+    if (getsockname(listener, connect_addr, &size) == -1)
+      goto tidy_up_and_fail;
+    if (size != SIZEOF_SOCKADDR (connect_addr->sa_family))
+      goto abort_tidy_up_and_fail;
+    if (connect(connector, connect_addr, size) == -1)
+      goto tidy_up_and_fail;
+
+    size = sizeof(listen_addr_ss);
+    acceptor = tor_accept_socket(listener, listen_addr, &size);
+    if (!SOCKET_OK(acceptor))
+      goto tidy_up_and_fail;
+    if (size != SIZEOF_SOCKADDR(listen_addr->sa_family))
+      goto abort_tidy_up_and_fail;
+    /* Now check we are talking to ourself by matching port and host on the
+       two sockets.  */
+    if (getsockname(connector, connect_addr, &size) == -1)
+      goto tidy_up_and_fail;
+    /* Set *_tor_addr and *_port to the address and port that was used */
+    tor_addr_from_sockaddr(&listen_tor_addr, listen_addr, &listen_port);
+    tor_addr_from_sockaddr(&connect_tor_addr, connect_addr, &connect_port);
+    if (size != SIZEOF_SOCKADDR (connect_addr->sa_family)
+        || tor_addr_compare(&listen_tor_addr, &connect_tor_addr, CMP_SEMANTIC)
+        || listen_port != connect_port) {
+      goto abort_tidy_up_and_fail;
+    }
+    tor_close_socket(listener);
+    fd[0] = connector;
+    fd[1] = acceptor;
+
+    return 0;
+
+  abort_tidy_up_and_fail:
+#ifdef _WIN32
+    saved_errno = WSAECONNABORTED;
+#else
+    saved_errno = ECONNABORTED; /* I hope this is portable and appropriate.  */
+#endif
+  tidy_up_and_fail:
+    if (saved_errno < 0)
+      saved_errno = errno;
+    if (SOCKET_OK(listener))
+      tor_close_socket(listener);
+    if (SOCKET_OK(connector))
+      tor_close_socket(connector);
+    if (SOCKET_OK(acceptor))
+      tor_close_socket(acceptor);
+    return -saved_errno;
+}
+
+#endif /* defined(NEED_ERSATZ_SOCKETPAIR) */
diff --git a/src/lib/net/socketpair.h b/src/lib/net/socketpair.h
new file mode 100644
index 000000000..3efa65a67
--- /dev/null
+++ b/src/lib/net/socketpair.h
@@ -0,0 +1,19 @@
+/* Copyright (c) 2003-2004, Roger Dingledine
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2018, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+#ifndef TOR_SOCKETPAIR_H
+#define TOR_SOCKETPAIR_H
+
+#include "orconfig.h"
+#include "lib/testsupport/testsupport.h"
+#include "lib/net/nettypes.h"
+
+#if !defined(HAVE_SOCKETPAIR) || defined(_WIN32) || defined(TOR_UNIT_TESTS)
+#define NEED_ERSATZ_SOCKETPAIR
+STATIC int tor_ersatz_socketpair(int family, int type, int protocol,
+                                 tor_socket_t fd[2]);
+#endif
+
+#endif
diff --git a/src/test/test_util.c b/src/test/test_util.c
index 99fee4c5a..7afe83c69 100644
--- a/src/test/test_util.c
+++ b/src/test/test_util.c
@@ -38,6 +38,7 @@
 #include "lib/meminfo/meminfo.h"
 #include "lib/time/tvdiff.h"
 #include "lib/encoding/confline.h"
+#include "lib/net/socketpair.h"
 
 #ifdef HAVE_PWD_H
 #include <pwd.h>





More information about the tor-commits mailing list