diff options
author | Nick Mathewson <nickm@torproject.org> | 2003-08-12 07:43:15 +0000 |
---|---|---|
committer | Nick Mathewson <nickm@torproject.org> | 2003-08-12 07:43:15 +0000 |
commit | 2cb4f7a473a35792f4d7a951ac43bfab79abebec (patch) | |
tree | f7bcfa4e86e3d93878181c7e580eb25f6c4a3132 | |
parent | 5d9cfb71649f15db09290a7c390a0f9d95b52548 (diff) | |
download | tor-2cb4f7a473a35792f4d7a951ac43bfab79abebec.tar.gz tor-2cb4f7a473a35792f4d7a951ac43bfab79abebec.zip |
Adopt socketpair implementation from perl. For now, always use it.
svn:r389
-rw-r--r-- | configure.in | 4 | ||||
-rw-r--r-- | src/common/util.c | 104 | ||||
-rw-r--r-- | src/common/util.h | 2 | ||||
-rw-r--r-- | src/or/dns.c | 2 |
4 files changed, 109 insertions, 3 deletions
diff --git a/configure.in b/configure.in index 83baf2982a..8adc9415d1 100644 --- a/configure.in +++ b/configure.in @@ -134,9 +134,9 @@ AC_CHECK_HEADERS(unistd.h string.h signal.h netdb.h ctype.h poll.h sys/poll.h sy dnl These headers are not essential -AC_CHECK_HEADERS(stdint.h sys/types.h inttypes.h sys/wait.h) +AC_CHECK_HEADERS(stdint.h sys/types.h inttypes.h sys/wait.h netinet/in.h arpa/inet.h) -AC_CHECK_FUNCS(gettimeofday ftime) +AC_CHECK_FUNCS(gettimeofday ftime socketpair) dnl In case we aren't given a working stdint.h, we'll need to grow our own. dnl Watch out. diff --git a/src/common/util.c b/src/common/util.c index 84f623301f..56d3851296 100644 --- a/src/common/util.c +++ b/src/common/util.c @@ -18,6 +18,15 @@ #ifdef HAVE_FCNTL_H #include <fcntl.h> #endif +#ifdef HAVE_SYS_SOCKET_H +#include <sys/socket.h> +#endif +#ifdef HAVE_NETINET_IN_H +#include <netinet/in.h> +#endif +#ifdef HAVE_ARPA_INET_H +#include <arpa/inet.h> +#endif #ifdef HAVE_SYS_TYPES_H #include <sys/types.h> #endif @@ -25,6 +34,8 @@ #include <unistd.h> #endif #include <assert.h> +#include <errno.h> +#include <string.h> #include "util.h" #include "log.h" @@ -147,3 +158,96 @@ void spawn_exit() exit(0); #endif } + + +/* Fake socket pair over TCP. Code adapted from perl 5.8.0's util.c */ +int +tor_socketpair(int family, int type, int protocol, int fd[2]) +{ +#ifdef HAVE_SOCKETPAIR_XXX + /* For testing purposes, we never fall back to real socketpairs. */ + return socketpair(family, type, protocol, fd); +#else + int listener = -1; + int connector = -1; + int acceptor = -1; + struct sockaddr_in listen_addr; + struct sockaddr_in connect_addr; + size_t size; + + if (protocol +#ifdef AF_UNIX + || family != AF_UNIX +#endif + ) { + errno = EAFNOSUPPORT; + return -1; + } + if (!fd) { + errno = EINVAL; + return -1; + } + + listener = socket(AF_INET, type, 0); + if (listener == -1) + return -1; + memset (&listen_addr, 0, sizeof (listen_addr)); + listen_addr.sin_family = AF_INET; + listen_addr.sin_addr.s_addr = htonl (INADDR_LOOPBACK); + listen_addr.sin_port = 0; /* kernel choses port. */ + if (bind(listener, (struct sockaddr *) &listen_addr, sizeof (listen_addr)) + == -1) + goto tidy_up_and_fail; + if (listen(listener, 1) == -1) + goto tidy_up_and_fail; + + connector = socket(AF_INET, type, 0); + if (connector == -1) + goto tidy_up_and_fail; + /* We want to find out the port number to connect to. */ + size = sizeof (connect_addr); + if (getsockname(listener, (struct sockaddr *) &connect_addr, &size) == -1) + goto tidy_up_and_fail; + if (size != sizeof (connect_addr)) + goto abort_tidy_up_and_fail; + if (connect(connector, (struct sockaddr *) &connect_addr, + sizeof (connect_addr)) == -1) + goto tidy_up_and_fail; + + size = sizeof (listen_addr); + acceptor = accept(listener, (struct sockaddr *) &listen_addr, &size); + if (acceptor == -1) + goto tidy_up_and_fail; + if (size != sizeof(listen_addr)) + goto abort_tidy_up_and_fail; + close(listener); + /* Now check we are talking to ourself by matching port and host on the + two sockets. */ + if (getsockname(connector, (struct sockaddr *) &connect_addr, &size) == -1) + goto tidy_up_and_fail; + if (size != sizeof (connect_addr) + || listen_addr.sin_family != connect_addr.sin_family + || listen_addr.sin_addr.s_addr != connect_addr.sin_addr.s_addr + || listen_addr.sin_port != connect_addr.sin_port) { + goto abort_tidy_up_and_fail; + } + fd[0] = connector; + fd[1] = acceptor; + return 0; + + abort_tidy_up_and_fail: + errno = ECONNABORTED; /* I hope this is portable and appropriate. */ + tidy_up_and_fail: + { + int save_errno = errno; + if (listener != -1) + close(listener); + if (connector != -1) + close(connector); + if (acceptor != -1) + close(acceptor); + errno = save_errno; + return -1; + } +#endif +} diff --git a/src/common/util.h b/src/common/util.h index ee3c6eba48..8600387327 100644 --- a/src/common/util.h +++ b/src/common/util.h @@ -52,4 +52,6 @@ void set_socket_nonblocking(int socket); int spawn_func(int (*func)(void *), void *data); void spawn_exit(); +int tor_socketpair(int family, int type, int protocol, int fd[2]); + #endif diff --git a/src/or/dns.c b/src/or/dns.c index 8e735aa1ae..643c61cc6d 100644 --- a/src/or/dns.c +++ b/src/or/dns.c @@ -361,7 +361,7 @@ static int dns_spawn_worker(void) { int fd[2]; connection_t *conn; - if(socketpair(AF_UNIX, SOCK_STREAM, 0, fd) < 0) { + if(tor_socketpair(AF_UNIX, SOCK_STREAM, 0, fd) < 0) { perror("socketpair"); exit(1); } |