aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNick Mathewson <nickm@torproject.org>2003-08-12 07:43:15 +0000
committerNick Mathewson <nickm@torproject.org>2003-08-12 07:43:15 +0000
commit2cb4f7a473a35792f4d7a951ac43bfab79abebec (patch)
treef7bcfa4e86e3d93878181c7e580eb25f6c4a3132
parent5d9cfb71649f15db09290a7c390a0f9d95b52548 (diff)
downloadtor-2cb4f7a473a35792f4d7a951ac43bfab79abebec.tar.gz
tor-2cb4f7a473a35792f4d7a951ac43bfab79abebec.zip
Adopt socketpair implementation from perl. For now, always use it.
svn:r389
-rw-r--r--configure.in4
-rw-r--r--src/common/util.c104
-rw-r--r--src/common/util.h2
-rw-r--r--src/or/dns.c2
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);
}