]> git.ipfire.org Git - thirdparty/tor.git/commitdiff
Split util into util (general utilities), container (smartlist and strmap), and compa...
authorNick Mathewson <nickm@torproject.org>
Mon, 1 Nov 2004 20:41:47 +0000 (20:41 +0000)
committerNick Mathewson <nickm@torproject.org>
Mon, 1 Nov 2004 20:41:47 +0000 (20:41 +0000)
svn:r2640

src/common/Makefile.am
src/common/compat.c [new file with mode: 0644]
src/common/compat.h [new file with mode: 0644]
src/common/container.c [new file with mode: 0644]
src/common/container.h [new file with mode: 0644]
src/common/crypto.c
src/common/log.h
src/common/util.c
src/common/util.h
src/or/or.h
src/tools/tor-resolve.c

index c07f08355e87a12a98fddaf9878076a83a05c9b4..65f722bfe816255ad7a6de596f456a7365bf4dd5 100644 (file)
@@ -3,7 +3,7 @@ noinst_LIBRARIES = libor.a libor-crypto.a
 
 #CFLAGS  = -Wall -Wpointer-arith -O2
 
-libor_a_SOURCES = log.c fakepoll.c util.c 
+libor_a_SOURCES = log.c fakepoll.c util.c compat.c container.c
 libor_crypto_a_SOURCES = crypto.c aes.c tortls.c torgzip.c
 
-noinst_HEADERS = log.h crypto.h fakepoll.h test.h util.h aes.h torint.h tortls.h strlcpy.c strlcat.c torgzip.h
+noinst_HEADERS = log.h crypto.h fakepoll.h test.h util.h compat.h aes.h torint.h tortls.h strlcpy.c strlcat.c torgzip.h container.h
diff --git a/src/common/compat.c b/src/common/compat.c
new file mode 100644 (file)
index 0000000..5b4c931
--- /dev/null
@@ -0,0 +1,660 @@
+/* Copyright 2003-2004 Roger Dingledine; Copyright 2004 Nick Mathewson */
+/* See LICENSE for licensing information */
+/* $Id$ */
+
+
+/* This is required on rh7 to make strptime not complain.
+ */
+#define _GNU_SOURCE
+
+#include "orconfig.h"
+
+#ifdef MS_WINDOWS
+#include <io.h>
+#include <process.h>
+#include <direct.h>
+#include <windows.h>
+#endif
+#ifdef HAVE_UNAME
+#include <sys/utsname.h>
+#endif
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#ifdef HAVE_SYS_FCNTL_H
+#include <sys/fcntl.h>
+#endif
+#ifdef HAVE_PWD_H
+#include <pwd.h>
+#endif
+#ifdef HAVE_GRP_H
+#include <grp.h>
+#endif
+#ifdef HAVE_FCNTL_H
+#include <fcntl.h>
+#endif
+#ifdef HAVE_SYS_RESOURCE_H
+#include <sys/resource.h>
+#endif
+#ifdef HAVE_ERRNO_H
+#include <errno.h>
+#endif
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+#ifndef HAVE_GETTIMEOFDAY
+#ifdef HAVE_FTIME
+#include <sys/timeb.h>
+#endif
+#endif
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+#ifdef HAVE_SYS_PARAM_H
+#include <sys/param.h> /* FreeBSD needs this to know what version it is */
+#endif
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "compat.h"
+#include "log.h"
+#include "util.h"
+
+/** Replacement for snprintf.  Differs from platform snprintf in two
+ * ways: First, always NUL-terminates its output.  Second, always
+ * returns -1 if the result is truncated.  (Note that this return
+ * behavior does <i>not</i> conform to C99; it just happens to be the
+ * easiest to emulate "return -1" with conformant implementations than
+ * it is to emulate "return number that would be written" with
+ * non-conformant implementations.) */
+int tor_snprintf(char *str, size_t size, const char *format, ...)
+{
+  va_list ap;
+  int r;
+  va_start(ap,format);
+  r = tor_vsnprintf(str,size,format,ap);
+  va_end(ap);
+  return r;
+}
+
+/** Replacement for vsnpritnf; behavior differs as tor_snprintf differs from
+ * snprintf.
+ */
+int tor_vsnprintf(char *str, size_t size, const char *format, va_list args)
+{
+  int r;
+#ifdef MS_WINDOWS
+  r = _vsnprintf(str, size, format, args);
+#else
+  r = vsnprintf(str, size, format, args);
+#endif
+  str[size-1] = '\0';
+  if (r < 0 || ((size_t)r) >= size)
+    return -1;
+  return r;
+}
+
+#ifndef UNALIGNED_INT_ACCESS_OK
+/**
+ * Read a 16-bit value beginning at <b>cp</b>.  Equaivalent to
+ * *(uint16_t*)(cp), but will not cause segfaults on platforms that forbid
+ * unaligned memory access.
+ */
+uint16_t get_uint16(const char *cp)
+{
+  uint16_t v;
+  memcpy(&v,cp,2);
+  return v;
+}
+/**
+ * Read a 32-bit value beginning at <b>cp</b>.  Equaivalent to
+ * *(uint32_t*)(cp), but will not cause segfaults on platforms that forbid
+ * unaligned memory access.
+ */
+uint32_t get_uint32(const char *cp)
+{
+  uint32_t v;
+  memcpy(&v,cp,4);
+  return v;
+}
+/**
+ * Set a 16-bit value beginning at <b>cp</b> to <b>v</b>. Equivalent to
+ * *(uint16_t)(cp) = v, but will not cause segfaults on platforms that forbid
+ * unaligned memory access. */
+void set_uint16(char *cp, uint16_t v)
+{
+  memcpy(cp,&v,2);
+}
+/**
+ * Set a 32-bit value beginning at <b>cp</b> to <b>v</b>. Equivalent to
+ * *(uint32_t)(cp) = v, but will not cause segfaults on platforms that forbid
+ * unaligned memory access. */
+void set_uint32(char *cp, uint32_t v)
+{
+  memcpy(cp,&v,4);
+}
+#endif
+
+/**
+ * Rename the file 'from' to the file 'to'.  On unix, this is the same as
+ * rename(2).  On windows, this removes 'to' first if it already exists.
+ * Returns 0 on success.  Returns -1 and sets errno on failure.
+ */
+int replace_file(const char *from, const char *to)
+{
+#ifndef MS_WINDOWS
+  return rename(from,to);
+#else
+  switch(file_status(to))
+    {
+    case FN_NOENT:
+      break;
+    case FN_FILE:
+      if (unlink(to)) return -1;
+      break;
+    case FN_ERROR:
+      return -1;
+    case FN_DIR:
+      errno = EISDIR;
+      return -1;
+    }
+  return rename(from,to);
+#endif
+}
+
+/** Turn <b>socket</b> into a nonblocking socket.
+ */
+void set_socket_nonblocking(int socket)
+{
+#ifdef MS_WINDOWS
+  /* Yes means no and no means yes.  Do you not want to be nonblocking? */
+  int nonblocking = 0;
+  ioctlsocket(socket, FIONBIO, (unsigned long*) &nonblocking);
+#else
+  fcntl(socket, F_SETFL, O_NONBLOCK);
+#endif
+}
+
+/**
+ * Allocate a pair of connected sockets.  (Like socketpair(family,
+ * type,protocol,fd), but works on systems that don't have
+ * socketpair.)
+ *
+ * Currently, only (AF_UNIX, SOCK_STREAM, 0 ) sockets are supported.
+ *
+ * Note that on systems without socketpair, this call will fail if
+ * localhost is inaccessible (for example, if the networking
+ * stack is down). And even if it succeeds, the socket pair will not
+ * be able to read while localhost is down later (the socket pair may
+ * even close, depending on OS-specific timeouts).
+ **/
+int
+tor_socketpair(int family, int type, int protocol, int fd[2])
+{
+#ifdef HAVE_SOCKETPAIR
+    return socketpair(family, type, protocol, fd);
+#else
+    /* 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.
+     */
+    int listener = -1;
+    int connector = -1;
+    int acceptor = -1;
+    struct sockaddr_in listen_addr;
+    struct sockaddr_in connect_addr;
+    int size;
+
+    if (protocol
+#ifdef AF_UNIX
+        || family != AF_UNIX
+#endif
+        ) {
+#ifdef MS_WINDOWS
+        errno = WSAEAFNOSUPPORT;
+#else
+        errno = EAFNOSUPPORT;
+#endif
+        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;
+    tor_close_socket(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:
+#ifdef MS_WINDOWS
+  errno = WSAECONNABORTED;
+#else
+  errno = ECONNABORTED; /* I hope this is portable and appropriate.  */
+#endif
+  tidy_up_and_fail:
+    {
+        int save_errno = errno;
+        if (listener != -1)
+            tor_close_socket(listener);
+        if (connector != -1)
+            tor_close_socket(connector);
+        if (acceptor != -1)
+            tor_close_socket(acceptor);
+        errno = save_errno;
+        return -1;
+    }
+#endif
+}
+
+/** Get the maximum allowed number of file descriptors. (Some systems
+ * have a low soft limit.) Make sure we set it to at least
+ * <b>required_min</b>. Return 0 if we can, or -1 if we fail. */
+int set_max_file_descriptors(int required_min) {
+#ifndef HAVE_GETRLIMIT
+  log_fn(LOG_INFO,"This platform is missing getrlimit(). Proceeding.");
+  return 0; /* hope we'll be ok */
+#else
+  struct rlimit rlim;
+
+  if (getrlimit(RLIMIT_NOFILE, &rlim) != 0) {
+    log_fn(LOG_WARN, "Could not get maximum number of file descriptors: %s",
+           strerror(errno));
+    return -1;
+  }
+  if(required_min > rlim.rlim_max) {
+    log_fn(LOG_WARN,"We need %d file descriptors available, and we're limited to %d. Please change your ulimit.", required_min, (int)rlim.rlim_max);
+    return -1;
+  }
+  if(required_min > rlim.rlim_cur) {
+    log_fn(LOG_INFO,"Raising max file descriptors from %d to %d.",
+           (int)rlim.rlim_cur, (int)rlim.rlim_max);
+  }
+  rlim.rlim_cur = rlim.rlim_max;
+  if (setrlimit(RLIMIT_NOFILE, &rlim) != 0) {
+    log_fn(LOG_WARN, "Could not set maximum number of file descriptors: %s",
+           strerror(errno));
+    return -1;
+  }
+  return 0;
+#endif
+}
+
+/** Call setuid and setgid to run as <b>user</b>:<b>group</b>.  Return 0 on
+ * success.  On failure, log and return -1.
+ */
+int switch_id(char *user, char *group) {
+#ifndef MS_WINDOWS
+  struct passwd *pw = NULL;
+  struct group *gr = NULL;
+
+  if (user) {
+    pw = getpwnam(user);
+    if (pw == NULL) {
+      log_fn(LOG_ERR,"User '%s' not found.", user);
+      return -1;
+    }
+  }
+
+  /* switch the group first, while we still have the privileges to do so */
+  if (group) {
+    gr = getgrnam(group);
+    if (gr == NULL) {
+      log_fn(LOG_ERR,"Group '%s' not found.", group);
+      return -1;
+    }
+
+    if (setgid(gr->gr_gid) != 0) {
+      log_fn(LOG_ERR,"Error setting GID: %s", strerror(errno));
+      return -1;
+    }
+  } else if (user) {
+    if (setgid(pw->pw_gid) != 0) {
+      log_fn(LOG_ERR,"Error setting GID: %s", strerror(errno));
+      return -1;
+    }
+  }
+
+  /* now that the group is switched, we can switch users and lose
+     privileges */
+  if (user) {
+    if (setuid(pw->pw_uid) != 0) {
+      log_fn(LOG_ERR,"Error setting UID: %s", strerror(errno));
+      return -1;
+    }
+  }
+
+  return 0;
+#endif
+
+  log_fn(LOG_ERR,
+         "User or group specified, but switching users is not supported.");
+
+  return -1;
+}
+
+/** Set *addr to the IP address (in dotted-quad notation) stored in c.
+ * Return 1 on success, 0 if c is badly formatted.  (Like inet_aton(c,addr),
+ * but works on Windows and Solaris.)
+ */
+int tor_inet_aton(const char *c, struct in_addr* addr)
+{
+#ifdef HAVE_INET_ATON
+  return inet_aton(c, addr);
+#else
+  uint32_t r;
+  tor_assert(c);
+  tor_assert(addr);
+  if (strcmp(c, "255.255.255.255") == 0) {
+    addr->s_addr = 0xFFFFFFFFu;
+    return 1;
+  }
+  r = inet_addr(c);
+  if (r == INADDR_NONE)
+    return 0;
+  addr->s_addr = r;
+  return 1;
+#endif
+}
+
+/* Hold the result of our call to <b>uname</b>. */
+static char uname_result[256];
+/* True iff uname_result is set. */
+static int uname_result_is_set = 0;
+
+/* Return a pointer to a description of our platform.
+ */
+const char *
+get_uname(void)
+{
+#ifdef HAVE_UNAME
+  struct utsname u;
+#endif
+  if (!uname_result_is_set) {
+#ifdef HAVE_UNAME
+    if (uname(&u) != -1) {
+      /* (linux says 0 is success, solaris says 1 is success) */
+      tor_snprintf(uname_result, sizeof(uname_result), "%s %s %s",
+               u.sysname, u.nodename, u.machine);
+    } else
+#endif
+      {
+        strlcpy(uname_result, "Unknown platform", sizeof(uname_result));
+      }
+    uname_result_is_set = 1;
+  }
+  return uname_result;
+}
+
+/*
+ *   Process control
+ */
+
+/** Minimalist interface to run a void function in the background.  On
+ * unix calls fork, on win32 calls beginthread.  Returns -1 on failure.
+ * func should not return, but rather should call spawn_exit.
+ */
+int spawn_func(int (*func)(void *), void *data)
+{
+#ifdef MS_WINDOWS
+  int rv;
+  rv = _beginthread(func, 0, data);
+  if (rv == (unsigned long) -1)
+    return -1;
+  return 0;
+#else
+  pid_t pid;
+  pid = fork();
+  if (pid<0)
+    return -1;
+  if (pid==0) {
+    /* Child */
+    func(data);
+    tor_assert(0); /* Should never reach here. */
+    return 0; /* suppress "control-reaches-end-of-non-void" warning. */
+  } else {
+    /* Parent */
+    return 0;
+  }
+#endif
+}
+
+/** End the current thread/process.
+ */
+void spawn_exit()
+{
+#ifdef MS_WINDOWS
+  _endthread();
+#else
+  exit(0);
+#endif
+}
+
+
+/** Set *timeval to the current time of day.  On error, log and terminate.
+ * (Same as gettimeofday(timeval,NULL), but never returns -1.)
+ */
+void tor_gettimeofday(struct timeval *timeval) {
+#ifdef HAVE_GETTIMEOFDAY
+  if (gettimeofday(timeval, NULL)) {
+    log_fn(LOG_ERR, "gettimeofday failed.");
+    /* If gettimeofday dies, we have either given a bad timezone (we didn't),
+       or segfaulted.*/
+    exit(1);
+  }
+#elif defined(HAVE_FTIME)
+  struct timeb tb;
+  ftime(&tb);
+  timeval->tv_sec = tb.time;
+  timeval->tv_usec = tb.millitm * 1000;
+#else
+#error "No way to get time."
+#endif
+  return;
+}
+
+#ifndef MS_WINDOWS
+struct tor_mutex_t {
+};
+tor_mutex_t *tor_mutex_new(void) { return NULL; }
+void tor_mutex_acquire(tor_mutex_t *m) { }
+void tor_mutex_release(tor_mutex_t *m) { }
+void tor_mutex_free(tor_mutex_t *m) { }
+#else
+struct tor_mutex_t {
+  HANDLE handle;
+};
+tor_mutex_t *tor_mutex_new(void)
+{
+  tor_mutex_t *m;
+  m = tor_malloc_zero(sizeof(tor_mutex_t));
+  m->handle = CreateMutex(NULL, FALSE, NULL);
+  tor_assert(m->handle != NULL);
+  return m;
+}
+void tor_mutex_free(tor_mutex_t *m)
+{
+  CloseHandle(m->handle);
+  tor_free(m);
+}
+void tor_mutex_acquire(tor_mutex_t *m)
+{
+  DWORD r;
+  r = WaitForSingleObject(m->handle, INFINITE);
+  switch (r) {
+    case WAIT_ABANDONED: /* holding thread exited. */
+        case WAIT_OBJECT_0: /* we got the mutex normally. */
+      break;
+    case WAIT_TIMEOUT: /* Should never happen. */
+          tor_assert(0);
+      break;
+        case WAIT_FAILED:
+      log_fn(LOG_WARN, "Failed to acquire mutex: %d", GetLastError());
+  }
+}
+void tor_mutex_release(tor_mutex_t *m)
+{
+  BOOL r;
+  r = ReleaseMutex(m->handle);
+  if (!r) {
+    log_fn(LOG_WARN, "Failed to release mutex: %d", GetLastError());
+  }
+}
+#endif
+
+
+/**
+ * On Windows, WSAEWOULDBLOCK is not always correct: when you see it,
+ * you need to ask the socket for its actual errno.  Also, you need to
+ * get your errors from WSAGetLastError, not errno.  (If you supply a
+ * socket of -1, we check WSAGetLastError, but don't correct
+ * WSAEWOULDBLOCKs.)
+ */
+#ifdef MS_WINDOWS
+int tor_socket_errno(int sock)
+{
+  int optval, optvallen=sizeof(optval);
+  int err = WSAGetLastError();
+  if (err == WSAEWOULDBLOCK && sock >= 0) {
+    if (getsockopt(sock, SOL_SOCKET, SO_ERROR, (void*)&optval, &optvallen))
+      return err;
+    if (optval)
+      return optval;
+  }
+  return err;
+}
+#endif
+
+#ifdef MS_WINDOWS
+#define E(code, s) { code, (s " [" #code " ]") }
+struct { int code; const char *msg; } windows_socket_errors[] = {
+  E(WSAEINTR, "Interrupted function call"),
+  E(WSAEACCES, "Permission denied"),
+  E(WSAEFAULT, "Bad address"),
+  E(WSAEINVAL, "Invalid argument"),
+  E(WSAEMFILE, "Too many open files"),
+  E(WSAEWOULDBLOCK,  "Resource temporarily unavailable"),
+  E(WSAEINPROGRESS, "Operation now in progress"),
+  E(WSAEALREADY, "Operation already in progress"),
+  E(WSAENOTSOCK, "Socket operation on nonsocket"),
+  E(WSAEDESTADDRREQ, "Destination address required"),
+  E(WSAEMSGSIZE, "Message too long"),
+  E(WSAEPROTOTYPE, "Protocol wrong for socket"),
+  E(WSAENOPROTOOPT, "Bad protocol option"),
+  E(WSAEPROTONOSUPPORT, "Protocol not supported"),
+  E(WSAESOCKTNOSUPPORT, "Socket type not supported"),
+  /* What's the difference between NOTSUPP and NOSUPPORT? :) */
+  E(WSAEOPNOTSUPP, "Operation not supported"),
+  E(WSAEPFNOSUPPORT,  "Protocol family not supported"),
+  E(WSAEAFNOSUPPORT, "Address family not supported by protocol family"),
+  E(WSAEADDRINUSE, "Address already in use"),
+  E(WSAEADDRNOTAVAIL, "Cannot assign requested address"),
+  E(WSAENETDOWN, "Network is down"),
+  E(WSAENETUNREACH, "Network is unreachable"),
+  E(WSAENETRESET, "Network dropped connection on reset"),
+  E(WSAECONNABORTED, "Software caused connection abort"),
+  E(WSAECONNRESET, "Connection reset by peer"),
+  E(WSAENOBUFS, "No buffer space avaialable"),
+  E(WSAEISCONN, "Socket is already connected"),
+  E(WSAENOTCONN, "Socket is not connected"),
+  E(WSAESHUTDOWN, "Cannot send after socket shutdown"),
+  E(WSAETIMEDOUT, "Connection timed out"),
+  E(WSAECONNREFUSED, "Connection refused"),
+  E(WSAEHOSTDOWN, "Host is down"),
+  E(WSAEHOSTUNREACH, "No route to host"),
+  E(WSAEPROCLIM, "Too many processes"),
+  /* Yes, some of these start with WSA, not WSAE. No, I don't know why. */
+  E(WSASYSNOTREADY, "Network subsystem is unavailable"),
+  E(WSAVERNOTSUPPORTED, "Winsock.dll out of range"),
+  E(WSANOTINITIALISED, "Successful WSAStartup not yet performed"),
+  E(WSAEDISCON, "Graceful shutdown now in progress"),
+#ifdef WSATYPE_NOT_FOUND
+  E(WSATYPE_NOT_FOUND, "Class type not found"),
+#endif
+  E(WSAHOST_NOT_FOUND, "Host not found"),
+  E(WSATRY_AGAIN, "Nonauthoritative host not found"),
+  E(WSANO_RECOVERY, "This is a nonrecoverable error"),
+  E(WSANO_DATA, "Valid name, no data record of requested type)"),
+
+  /* There are some more error codes whose numeric values are marked
+   * <b>OS dependent</b>. They start with WSA_, apparently for the same
+   * reason that practitioners of some craft traditions deliberately
+   * introduce imperfections into their baskets and rugs "to allow the
+   * evil spirits to escape."  If we catch them, then our binaries
+   * might not report consistent results across versions of Windows.
+   * Thus, I'm going to let them all fall through.
+   */
+  { -1, NULL },
+};
+/** There does not seem to be a strerror equivalent for winsock errors.
+ * Naturally, we have to roll our own.
+ */
+const char *tor_socket_strerror(int e)
+{
+  int i;
+  for (i=0; windows_socket_errors[i].code >= 0; ++i) {
+    if (e == windows_socket_errors[i].code)
+      return windows_socket_errors[i].msg;
+  }
+  return strerror(e);
+}
+#endif
+/*
+  Local Variables:
+  mode:c
+  indent-tabs-mode:nil
+  c-basic-offset:2
+  End:
+*/
diff --git a/src/common/compat.h b/src/common/compat.h
new file mode 100644 (file)
index 0000000..afc8af4
--- /dev/null
@@ -0,0 +1,168 @@
+/* Copyright 2003-2004 Roger Dingledine; Copyright 2004 Nick Mathewson */
+/* See LICENSE for licensing information */
+/* $Id$ */
+
+#ifndef __COMPAT_H
+#define __COMPAT_H
+
+#include "orconfig.h"
+#include "torint.h"
+#ifdef MS_WINDOWS
+#define WIN32_WINNT 0x400
+#define _WIN32_WINNT 0x400
+#define WIN32_LEAN_AND_MEAN
+#if (_MSC_VER <= 1300)
+#include <winsock.h>
+#else
+#include <winsock2.h>
+#include <ws2tcpip.h>
+#endif
+#endif
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#include <stdarg.h>
+
+#ifndef NULL_REP_IS_ZERO_BYTES
+#error "It seems your platform does not represent NULL as zero. We can't cope."
+#endif
+
+/* ===== Compiler compatibility */
+
+/* GCC can check printf types on arbitrary functions. */
+#ifdef __GNUC__
+#define CHECK_PRINTF(formatIdx, firstArg) \
+   __attribute__ ((format (printf, formatIdx, firstArg)))
+#else
+#define CHECK_PRINTF(formatIdx, firstArg)
+#endif
+
+/* inline is __inline on windows. */
+#ifdef MS_WINDOWS
+#define INLINE __inline
+#else
+#define INLINE inline
+#endif
+
+/* Windows compilers before VC7 don't have __FUNCTION__. */
+#if defined(_MSC_VER) && _MSC_VER < 1300
+#define __FUNCTION__ "???"
+#endif
+
+/* ===== String compatibility */
+#ifdef MS_WINDOWS
+/* Windows names string functions differently from most other platforms. */
+#define strncasecmp strnicmp
+#define strcasecmp stricmp
+#endif
+
+int tor_snprintf(char *str, size_t size, const char *format, ...)
+     CHECK_PRINTF(3,4);
+int tor_vsnprintf(char *str, size_t size, const char *format, va_list args);
+
+/* ===== Time compatibility */
+#if !defined(HAVE_GETTIMEOFDAY) && !defined(HAVE_STRUCT_TIMEVAL_TV_SEC)
+struct timeval {
+  time_t tv_sec;
+  unsigned int tv_usec;
+};
+#endif
+
+void tor_gettimeofday(struct timeval *timeval);
+
+/* ===== File compatibility */
+int replace_file(const char *from, const char *to);
+
+/* ===== Net compatibility */
+#ifdef MS_WINDOWS
+/** 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.
+ */
+#define tor_close_socket(s) closesocket(s)
+#else
+#define tor_close_socket(s) close(s)
+#endif
+
+struct in_addr;
+int tor_inet_aton(const char *cp, struct in_addr *addr);
+void set_socket_nonblocking(int socket);
+int tor_socketpair(int family, int type, int protocol, int fd[2]);
+/* For stupid historical reasons, windows sockets have an independent
+ * set of errnos, and an independent way to get them.  Also, you can't
+ * always believe WSAEWOULDBLOCK.  Use the macros below to compare
+ * errnos against expected values, and use tor_socket_errno to find
+ * the actual errno after a socket operation fails.
+ */
+#ifdef MS_WINDOWS
+/** Return true if e is EAGAIN or the local equivalent. */
+#define ERRNO_IS_EAGAIN(e)           ((e) == EAGAIN || (e) == WSAEWOULDBLOCK)
+/** Return true if e is EINPROGRESS or the local equivalent. */
+#define ERRNO_IS_EINPROGRESS(e)      ((e) == WSAEINPROGRESS)
+/** Return true if e is EINPROGRESS or the local equivalent as returned by
+ * a call to connect(). */
+#define ERRNO_IS_CONN_EINPROGRESS(e) ((e) == WSAEINPROGRESS || (e)== WSAEINVAL)
+/** Return true if e is EAGAIN or another error indicating that a call to
+ * accept() has no pending connections to return. */
+#define ERRNO_IS_ACCEPT_EAGAIN(e)    ERRNO_IS_EAGAIN(e)
+/** Return true if e is EMFILE or another error indicating that a call to
+ * accept() has failed because we're out of fds or something. */
+#define ERRNO_IS_ACCEPT_RESOURCE_LIMIT(e) \
+  ((e) == WSAEMFILE || (e) == WSAENOBUFS)
+int tor_socket_errno(int sock);
+const char *tor_socket_strerror(int e);
+#else
+#define ERRNO_IS_EAGAIN(e)           ((e) == EAGAIN)
+#define ERRNO_IS_EINPROGRESS(e)      ((e) == EINPROGRESS)
+#define ERRNO_IS_CONN_EINPROGRESS(e) ((e) == EINPROGRESS)
+#define ERRNO_IS_ACCEPT_EAGAIN(e)    ((e) == EAGAIN || (e) == ECONNABORTED)
+#define ERRNO_IS_ACCEPT_RESOURCE_LIMIT(e) \
+  ((e) == EMFILE || (e) == ENFILE || (e) == ENOBUFS || (e) == ENOMEM)
+#define tor_socket_errno(sock)       (errno)
+#define tor_socket_strerror(e)       strerror(e)
+#endif
+
+/* ===== OS compatibility */
+const char *get_uname(void);
+
+/* Some platforms segfault when you try to access a multi-byte type
+ * that isn't aligned to a word boundary.  The macros and/or functions
+ * below can be used to access unaligned data on any platform.
+ */
+#ifdef UNALIGNED_INT_ACCESS_OK
+#define get_uint16(cp) (*(uint16_t*)(cp))
+#define get_uint32(cp) (*(uint32_t*)(cp))
+#define set_uint16(cp,v) do { *(uint16_t*)(cp) = (v); } while (0)
+#define set_uint32(cp,v) do { *(uint32_t*)(cp) = (v); } while (0)
+#else
+uint16_t get_uint16(const char *cp);
+uint32_t get_uint32(const char *cp);
+void set_uint16(char *cp, uint16_t v);
+void set_uint32(char *cp, uint32_t v);
+#endif
+
+int set_max_file_descriptors(int required_min);
+int switch_id(char *user, char *group);
+
+int spawn_func(int (*func)(void *), void *data);
+void spawn_exit(void);
+
+/* Because we use threads instead of processes on Windows, we need locking on
+ * Windows.  On Unixy platforms, these functions are no-ops. */
+typedef struct tor_mutex_t tor_mutex_t;
+tor_mutex_t *tor_mutex_new(void);
+void tor_mutex_acquire(tor_mutex_t *m);
+void tor_mutex_release(tor_mutex_t *m);
+void tor_mutex_free(tor_mutex_t *m);
+
+#endif
+
+/*
+  Local Variables:
+  mode:c
+  indent-tabs-mode:nil
+  c-basic-offset:2
+  End:
+*/
diff --git a/src/common/container.c b/src/common/container.c
new file mode 100644 (file)
index 0000000..8eea743
--- /dev/null
@@ -0,0 +1,612 @@
+/* Copyright 2003-2004 Roger Dingledine; Copyright 2004 Nick Mathewson */
+/* See LICENSE for licensing information */
+/* $Id$ */
+
+#include "compat.h"
+#include "util.h"
+#include "log.h"
+#include "../or/tree.h"
+#include "container.h"
+
+#ifdef HAVE_CTYPE_H
+#include <ctype.h>
+#endif
+#include <stdlib.h>
+#include <string.h>
+
+
+/* =====
+ * smartlist_t: a simple resizeable array abstraction.
+ * ===== */
+
+/* All newly allocated smartlists have this capacity.
+ */
+#define SMARTLIST_DEFAULT_CAPACITY 32
+
+struct smartlist_t {
+  /** <b>list</b> has enough capacity to store exactly <b>capacity</b> elements
+   * before it needs to be resized.  Only the first <b>num_used</b> (\<=
+   * capacity) elements point to valid data.
+   */
+  void **list;
+  int num_used;
+  int capacity;
+};
+
+/** Allocate and return an empty smartlist.
+ */
+smartlist_t *smartlist_create() {
+  smartlist_t *sl = tor_malloc(sizeof(smartlist_t));
+  sl->num_used = 0;
+  sl->capacity = SMARTLIST_DEFAULT_CAPACITY;
+  sl->list = tor_malloc(sizeof(void *) * sl->capacity);
+  return sl;
+}
+
+/** Deallocate a smartlist.  Does not release storage associated with the
+ * list's elements.
+ */
+void smartlist_free(smartlist_t *sl) {
+  free(sl->list);
+  free(sl);
+}
+
+/** Change the capacity of the smartlist to <b>n</b>, so that we can grow
+ * the list up to <b>n</b> elements with no further reallocation or wasted
+ * space.  If <b>n</b> is less than or equal to the number of elements
+ * currently in the list, reduce the list's capacity as much as
+ * possible without losing elements.
+ */
+void smartlist_set_capacity(smartlist_t *sl, int n) {
+  if (n < sl->num_used)
+    n = sl->num_used;
+  if (sl->capacity != n) {
+    sl->capacity = n;
+    sl->list = tor_realloc(sl->list, sizeof(void*)*sl->capacity);
+  }
+}
+
+/** Remove all elements from the list.
+ */
+void smartlist_clear(smartlist_t *sl) {
+  sl->num_used = 0;
+}
+
+/** Set the list's new length to <b>len</b> (which must be \<= the list's
+ * current size). Remove the last smartlist_len(sl)-len elements from the
+ * list.
+ */
+void smartlist_truncate(smartlist_t *sl, int len)
+{
+  tor_assert(len <= sl->num_used);
+  sl->num_used = len;
+}
+
+/** Append element to the end of the list. */
+void smartlist_add(smartlist_t *sl, void *element) {
+  if (sl->num_used >= sl->capacity) {
+    sl->capacity *= 2;
+    sl->list = tor_realloc(sl->list, sizeof(void*)*sl->capacity);
+  }
+  sl->list[sl->num_used++] = element;
+}
+
+/** Append each element from S2 to the end of S1. */
+void smartlist_add_all(smartlist_t *sl, const smartlist_t *s2)
+{
+  SMARTLIST_FOREACH(s2, void *, element, smartlist_add(sl, element));
+}
+
+/** Remove all elements E from sl such that E==element.  Does not preserve
+ * the order of s1.
+ */
+void smartlist_remove(smartlist_t *sl, void *element) {
+  int i;
+  if(element == NULL)
+    return;
+  for(i=0; i < sl->num_used; i++)
+    if(sl->list[i] == element) {
+      sl->list[i] = sl->list[--sl->num_used]; /* swap with the end */
+      i--; /* so we process the new i'th element */
+    }
+}
+
+/** Return true iff some element E of sl has E==element.
+ */
+int smartlist_isin(const smartlist_t *sl, void *element) {
+  int i;
+  for(i=0; i < sl->num_used; i++)
+    if(sl->list[i] == element)
+      return 1;
+  return 0;
+}
+
+int smartlist_string_isin(const smartlist_t *sl, const char *element) {
+  int i;
+  for(i=0; i < sl->num_used; i++)
+    if(strcmp((const char*)sl->list[i],element)==0)
+      return 1;
+  return 0;
+}
+
+/** Return true iff some element E of sl2 has smartlist_isin(sl1,E).
+ */
+int smartlist_overlap(const smartlist_t *sl1, const smartlist_t *sl2) {
+  int i;
+  for(i=0; i < sl2->num_used; i++)
+    if(smartlist_isin(sl1, sl2->list[i]))
+      return 1;
+  return 0;
+}
+
+/** Remove every element E of sl1 such that !smartlist_isin(sl2,E).
+ * Does not preserve the order of sl1.
+ */
+void smartlist_intersect(smartlist_t *sl1, const smartlist_t *sl2) {
+  int i;
+  for(i=0; i < sl1->num_used; i++)
+    if(!smartlist_isin(sl2, sl1->list[i])) {
+      sl1->list[i] = sl1->list[--sl1->num_used]; /* swap with the end */
+      i--; /* so we process the new i'th element */
+    }
+}
+
+/** Remove every element E of sl1 such that smartlist_isin(sl2,E).
+ * Does not preserve the order of sl1.
+ */
+void smartlist_subtract(smartlist_t *sl1, const smartlist_t *sl2) {
+  int i;
+  for(i=0; i < sl2->num_used; i++)
+    smartlist_remove(sl1, sl2->list[i]);
+}
+
+/** Return the <b>idx</b>th element of sl.
+ */
+void *smartlist_get(const smartlist_t *sl, int idx)
+{
+  tor_assert(sl);
+  tor_assert(idx>=0);
+  tor_assert(idx < sl->num_used);
+  return sl->list[idx];
+}
+/** Change the value of the <b>idx</b>th element of sl to <b>val</b>; return the old
+ * value of the <b>idx</b>th element.
+ */
+void *smartlist_set(smartlist_t *sl, int idx, void *val)
+{
+  void *old;
+  tor_assert(sl);
+  tor_assert(idx>=0);
+  tor_assert(idx < sl->num_used);
+  old = sl->list[idx];
+  sl->list[idx] = val;
+  return old;
+}
+/** Remove the <b>idx</b>th element of sl; if idx is not the last
+ * element, swap the last element of sl into the <b>idx</b>th space.
+ * Return the old value of the <b>idx</b>th element.
+ */
+void *smartlist_del(smartlist_t *sl, int idx)
+{
+  void *old;
+  tor_assert(sl);
+  tor_assert(idx>=0);
+  tor_assert(idx < sl->num_used);
+  old = sl->list[idx];
+  sl->list[idx] = sl->list[--sl->num_used];
+  return old;
+}
+/** Remove the <b>idx</b>th element of sl; if idx is not the last element,
+ * moving all subsequent elements back one space. Return the old value
+ * of the <b>idx</b>th element.
+ */
+void *smartlist_del_keeporder(smartlist_t *sl, int idx)
+{
+  void *old;
+  tor_assert(sl);
+  tor_assert(idx>=0);
+  tor_assert(idx < sl->num_used);
+  old = sl->list[idx];
+  --sl->num_used;
+  if (idx < sl->num_used)
+    memmove(sl->list+idx, sl->list+idx+1, sizeof(void*)*(sl->num_used-idx));
+  return old;
+}
+/** Return the number of items in sl.
+ */
+int smartlist_len(const smartlist_t *sl)
+{
+  return sl->num_used;
+}
+/** Insert the value <b>val</b> as the new <b>idx</b>th element of
+ * <b>sl</b>, moving all items previously at <b>idx</b> or later
+ * forward one space.
+ */
+void smartlist_insert(smartlist_t *sl, int idx, void *val)
+{
+  tor_assert(sl);
+  tor_assert(idx>=0);
+  tor_assert(idx <= sl->num_used);
+  if (idx == sl->num_used) {
+    smartlist_add(sl, val);
+  } else {
+    /* Ensure sufficient capacity */
+    if (sl->num_used >= sl->capacity) {
+      sl->capacity *= 2;
+      sl->list = tor_realloc(sl->list, sizeof(void*)*sl->capacity);
+    }
+    /* Move other elements away */
+    if (idx < sl->num_used)
+      memmove(sl->list + idx + 1, sl->list + idx,
+              sizeof(void*)*(sl->num_used-idx));
+    sl->num_used++;
+    sl->list[idx] = val;
+  }
+}
+
+/**
+ * Split a string <b>str</b> along all occurences of <b>sep</b>,
+ * adding the split strings, in order, to <b>sl</b>.  If
+ * <b>flags</b>&amp;SPLIT_SKIP_SPACE is true, remove initial and
+ * trailing space from each entry.  If
+ * <b>flags</b>&amp;SPLIT_IGNORE_BLANK is true, remove any entries of
+ * length 0.  If max>0, divide the string into no more than <b>max</b>
+ * pieces.
+ */
+int smartlist_split_string(smartlist_t *sl, const char *str, const char *sep,
+                           int flags, int max)
+{
+  const char *cp, *end, *next;
+  int n = 0;
+
+  tor_assert(sl);
+  tor_assert(str);
+  tor_assert(sep);
+
+  cp = str;
+  while (1) {
+    if (flags&SPLIT_SKIP_SPACE) {
+      while (isspace((int)*cp)) ++cp;
+    }
+
+    if (max>0 && n == max-1) {
+      end = strchr(cp,'\0');
+    } else {
+      end = strstr(cp,sep);
+      if (!end)
+        end = strchr(cp,'\0');
+    }
+    if (!*end) {
+      next = NULL;
+    } else {
+      next = end+strlen(sep);
+    }
+
+    if (flags&SPLIT_SKIP_SPACE) {
+      while (end > cp && isspace((int)*(end-1)))
+        --end;
+    }
+    if (end != cp || !(flags&SPLIT_IGNORE_BLANK)) {
+      smartlist_add(sl, tor_strndup(cp, end-cp));
+      ++n;
+    }
+    if (!next)
+      break;
+    cp = next;
+  }
+
+  return n;
+}
+
+/** Allocate and return a new string containing the concatenation of
+ * the elements of <b>sl</b>, in order, separated by <b>join</b>.  If
+ * <b>terminate</b> is true, also terminate the string with <b>join</b>.
+ * Requires that every element of <b>sl</b> is NUL-terminated string.
+ */
+char *smartlist_join_strings(smartlist_t *sl, const char *join, int terminate)
+{
+  int i;
+  size_t n = 0, jlen;
+  char *r = NULL, *dst, *src;
+
+  tor_assert(sl);
+  tor_assert(join);
+  jlen = strlen(join);
+  for (i = 0; i < sl->num_used; ++i) {
+    n += strlen(sl->list[i]);
+    n += jlen;
+  }
+  if (!terminate) n -= jlen;
+  dst = r = tor_malloc(n+1);
+  for (i = 0; i < sl->num_used; ) {
+    for (src = sl->list[i]; *src; )
+      *dst++ = *src++;
+    if (++i < sl->num_used || terminate) {
+      memcpy(dst, join, jlen);
+      dst += jlen;
+    }
+  }
+  *dst = '\0';
+  return r;
+}
+
+/* Splay-tree implementation of string-to-void* map
+ */
+struct strmap_entry_t {
+  SPLAY_ENTRY(strmap_entry_t) node;
+  char *key;
+  void *val;
+};
+
+struct strmap_t {
+  SPLAY_HEAD(strmap_tree, strmap_entry_t) head;
+};
+
+static int compare_strmap_entries(struct strmap_entry_t *a,
+                                 struct strmap_entry_t *b)
+{
+  return strcmp(a->key, b->key);
+}
+
+SPLAY_PROTOTYPE(strmap_tree, strmap_entry_t, node, compare_strmap_entries);
+SPLAY_GENERATE(strmap_tree, strmap_entry_t, node, compare_strmap_entries);
+
+/** Create a new empty map from strings to void*'s.
+ */
+strmap_t* strmap_new(void)
+{
+  strmap_t *result;
+  result = tor_malloc(sizeof(strmap_t));
+  SPLAY_INIT(&result->head);
+  return result;
+}
+
+/** Set the current value for <b>key</b> to <b>val</b>.  Returns the previous
+ * value for <b>key</b> if one was set, or NULL if one was not.
+ *
+ * This function makes a copy of <b>key</b> if necessary, but not of <b>val</b>.
+ */
+void* strmap_set(strmap_t *map, const char *key, void *val)
+{
+  strmap_entry_t *resolve;
+  strmap_entry_t search;
+  void *oldval;
+  tor_assert(map);
+  tor_assert(key);
+  tor_assert(val);
+  search.key = (char*)key;
+  resolve = SPLAY_FIND(strmap_tree, &map->head, &search);
+  if (resolve) {
+    oldval = resolve->val;
+    resolve->val = val;
+    return oldval;
+  } else {
+    resolve = tor_malloc_zero(sizeof(strmap_entry_t));
+    resolve->key = tor_strdup(key);
+    resolve->val = val;
+    SPLAY_INSERT(strmap_tree, &map->head, resolve);
+    return NULL;
+  }
+}
+
+/** Return the current value associated with <b>key</b>, or NULL if no
+ * value is set.
+ */
+void* strmap_get(strmap_t *map, const char *key)
+{
+  strmap_entry_t *resolve;
+  strmap_entry_t search;
+  tor_assert(map);
+  tor_assert(key);
+  search.key = (char*)key;
+  resolve = SPLAY_FIND(strmap_tree, &map->head, &search);
+  if (resolve) {
+    return resolve->val;
+  } else {
+    return NULL;
+  }
+}
+
+/** Remove the value currently associated with <b>key</b> from the map.
+ * Return the value if one was set, or NULL if there was no entry for
+ * <b>key</b>.
+ *
+ * Note: you must free any storage associated with the returned value.
+ */
+void* strmap_remove(strmap_t *map, const char *key)
+{
+  strmap_entry_t *resolve;
+  strmap_entry_t search;
+  void *oldval;
+  tor_assert(map);
+  tor_assert(key);
+  search.key = (char*)key;
+  resolve = SPLAY_FIND(strmap_tree, &map->head, &search);
+  if (resolve) {
+    oldval = resolve->val;
+    SPLAY_REMOVE(strmap_tree, &map->head, resolve);
+    tor_free(resolve->key);
+    tor_free(resolve);
+    return oldval;
+  } else {
+    return NULL;
+  }
+}
+
+/** Same as strmap_set, but first converts <b>key</b> to lowercase. */
+void* strmap_set_lc(strmap_t *map, const char *key, void *val)
+{
+  /* We could be a little faster by using strcasecmp instead, and a separate
+   * type, but I don't think it matters. */
+  void *v;
+  char *lc_key = tor_strdup(key);
+  tor_strlower(lc_key);
+  v = strmap_set(map,lc_key,val);
+  tor_free(lc_key);
+  return v;
+}
+/** Same as strmap_get, but first converts <b>key</b> to lowercase. */
+void* strmap_get_lc(strmap_t *map, const char *key)
+{
+  void *v;
+  char *lc_key = tor_strdup(key);
+  tor_strlower(lc_key);
+  v = strmap_get(map,lc_key);
+  tor_free(lc_key);
+  return v;
+}
+/** Same as strmap_remove, but first converts <b>key</b> to lowercase */
+void* strmap_remove_lc(strmap_t *map, const char *key)
+{
+  void *v;
+  char *lc_key = tor_strdup(key);
+  tor_strlower(lc_key);
+  v = strmap_remove(map,lc_key);
+  tor_free(lc_key);
+  return v;
+}
+
+/** Invoke fn() on every entry of the map, in order.  For every entry,
+ * fn() is invoked with that entry's key, that entry's value, and the
+ * value of <b>data</b> supplied to strmap_foreach.  fn() must return a new
+ * (possibly unmodified) value for each entry: if fn() returns NULL, the
+ * entry is removed.
+ *
+ * Example:
+ * \code
+ *   static void* upcase_and_remove_empty_vals(const char *key, void *val,
+ *                                             void* data) {
+ *     char *cp = (char*)val;
+ *     if (!*cp) {  // val is an empty string.
+ *       free(val);
+ *       return NULL;
+ *     } else {
+ *       for (; *cp; cp++)
+ *         *cp = toupper(*cp);
+ *       }
+ *       return val;
+ *     }
+ *   }
+ *
+ *   ...
+ *
+ *   strmap_foreach(map, upcase_and_remove_empty_vals, NULL);
+ * \endcode
+ */
+void strmap_foreach(strmap_t *map,
+                    void* (*fn)(const char *key, void *val, void *data),
+                    void *data)
+{
+  strmap_entry_t *ptr, *next;
+  tor_assert(map);
+  tor_assert(fn);
+  for (ptr = SPLAY_MIN(strmap_tree, &map->head); ptr != NULL; ptr = next) {
+    /* This remove-in-place usage is specifically blessed in tree(3). */
+    next = SPLAY_NEXT(strmap_tree, &map->head, ptr);
+    ptr->val = fn(ptr->key, ptr->val, data);
+    if (!ptr->val) {
+      SPLAY_REMOVE(strmap_tree, &map->head, ptr);
+      tor_free(ptr->key);
+      tor_free(ptr);
+    }
+  }
+}
+
+/** return an <b>iterator</b> pointer to the front of a map.
+ *
+ * Iterator example:
+ *
+ * \code
+ * // uppercase values in "map", removing empty values.
+ *
+ * strmap_iter_t *iter;
+ * const char *key;
+ * void *val;
+ * char *cp;
+ *
+ * for (iter = strmap_iter_init(map); !strmap_iter_done(iter); ) {
+ *    strmap_iter_get(iter, &key, &val);
+ *    cp = (char*)val;
+ *    if (!*cp) {
+ *       iter = strmap_iter_next_rmv(iter);
+ *       free(val);
+ *    } else {
+ *       for(;*cp;cp++) *cp = toupper(*cp);
+ *       iter = strmap_iter_next(iter);
+ *    }
+ * }
+ * \endcode
+ *
+ */
+strmap_iter_t *strmap_iter_init(strmap_t *map)
+{
+  tor_assert(map);
+  return SPLAY_MIN(strmap_tree, &map->head);
+}
+/** Advance the iterator <b>iter</b> for map a single step to the next entry.
+ */
+strmap_iter_t *strmap_iter_next(strmap_t *map, strmap_iter_t *iter)
+{
+  tor_assert(map);
+  tor_assert(iter);
+  return SPLAY_NEXT(strmap_tree, &map->head, iter);
+}
+/** Advance the iterator <b>iter</b> a single step to the next entry, removing
+ * the current entry.
+ */
+strmap_iter_t *strmap_iter_next_rmv(strmap_t *map, strmap_iter_t *iter)
+{
+  strmap_iter_t *next;
+  tor_assert(map);
+  tor_assert(iter);
+  next = SPLAY_NEXT(strmap_tree, &map->head, iter);
+  SPLAY_REMOVE(strmap_tree, &map->head, iter);
+  tor_free(iter->key);
+  tor_free(iter);
+  return next;
+}
+/** Set *keyp and *valp to the current entry pointed to by iter.
+ */
+void strmap_iter_get(strmap_iter_t *iter, const char **keyp, void **valp)
+{
+  tor_assert(iter);
+  tor_assert(keyp);
+  tor_assert(valp);
+  *keyp = iter->key;
+  *valp = iter->val;
+}
+/** Return true iff iter has advanced past the last entry of map.
+ */
+int strmap_iter_done(strmap_iter_t *iter)
+{
+  return iter == NULL;
+}
+/** Remove all entries from <b>map</b>, and deallocate storage for those entries.
+ * If free_val is provided, it is invoked on every value in <b>map</b>.
+ */
+void strmap_free(strmap_t *map, void (*free_val)(void*))
+{
+  strmap_entry_t *ent, *next;
+  for (ent = SPLAY_MIN(strmap_tree, &map->head); ent != NULL; ent = next) {
+    next = SPLAY_NEXT(strmap_tree, &map->head, ent);
+    SPLAY_REMOVE(strmap_tree, &map->head, ent);
+    tor_free(ent->key);
+    if (free_val)
+      tor_free(ent->val);
+  }
+  tor_assert(SPLAY_EMPTY(&map->head));
+  tor_free(map);
+}
+
+int strmap_isempty(strmap_t *map)
+{
+  return SPLAY_EMPTY(&map->head);
+}
+
+/*
+  Local Variables:
+  mode:c
+  indent-tabs-mode:nil
+  c-basic-offset:2
+  End:
+*/
diff --git a/src/common/container.h b/src/common/container.h
new file mode 100644 (file)
index 0000000..7569cb3
--- /dev/null
@@ -0,0 +1,78 @@
+/* Copyright 2003-2004 Roger Dingledine; Copyright 2004 Nick Mathewson */
+/* See LICENSE for licensing information */
+/* $Id$ */
+
+#ifndef __CONTAINER_H
+#define __CONTAINER_H
+
+/** Generic resizeable array. */
+typedef struct smartlist_t smartlist_t;
+
+smartlist_t *smartlist_create(void);
+void smartlist_free(smartlist_t *sl);
+void smartlist_set_capacity(smartlist_t *sl, int n);
+void smartlist_clear(smartlist_t *sl);
+void smartlist_truncate(smartlist_t *sl, int n);
+void smartlist_add(smartlist_t *sl, void *element);
+void smartlist_add_all(smartlist_t *sl, const smartlist_t *s2);
+void smartlist_remove(smartlist_t *sl, void *element);
+int smartlist_isin(const smartlist_t *sl, void *element);
+int smartlist_string_isin(const smartlist_t *sl, const char *element);
+int smartlist_overlap(const smartlist_t *sl1, const smartlist_t *sl2);
+void smartlist_intersect(smartlist_t *sl1, const smartlist_t *sl2);
+void smartlist_subtract(smartlist_t *sl1, const smartlist_t *sl2);
+void *smartlist_choose(const smartlist_t *sl);
+void *smartlist_get(const smartlist_t *sl, int idx);
+void *smartlist_set(smartlist_t *sl, int idx, void *val);
+void *smartlist_del(smartlist_t *sl, int idx);
+void *smartlist_del_keeporder(smartlist_t *sl, int idx);
+void smartlist_insert(smartlist_t *sl, int idx, void *val);
+int smartlist_len(const smartlist_t *sl);
+#define SPLIT_SKIP_SPACE   0x01
+#define SPLIT_IGNORE_BLANK 0x02
+int smartlist_split_string(smartlist_t *sl, const char *str, const char *sep,
+                           int flags, int max);
+char *smartlist_join_strings(smartlist_t *sl, const char *join, int terminate);
+
+#define SMARTLIST_FOREACH(sl, type, var, cmd)                   \
+  do {                                                          \
+    int var ## _sl_idx, var ## _sl_len=smartlist_len(sl);       \
+    type var;                                                   \
+    for(var ## _sl_idx = 0; var ## _sl_idx < var ## _sl_len;    \
+        ++var ## _sl_idx) {                                     \
+      var = smartlist_get((sl),var ## _sl_idx);                 \
+      cmd;                                                      \
+    } } while (0)
+
+/* Map from const char * to void*. Implemented with a splay tree. */
+typedef struct strmap_t strmap_t;
+typedef struct strmap_entry_t strmap_entry_t;
+typedef struct strmap_entry_t strmap_iter_t;
+strmap_t* strmap_new(void);
+void* strmap_set(strmap_t *map, const char *key, void *val);
+void* strmap_get(strmap_t *map, const char *key);
+void* strmap_remove(strmap_t *map, const char *key);
+void* strmap_set_lc(strmap_t *map, const char *key, void *val);
+void* strmap_get_lc(strmap_t *map, const char *key);
+void* strmap_remove_lc(strmap_t *map, const char *key);
+typedef void* (*strmap_foreach_fn)(const char *key, void *val, void *data);
+void strmap_foreach(strmap_t *map, strmap_foreach_fn fn, void *data);
+void strmap_free(strmap_t *map, void (*free_val)(void*));
+int strmap_isempty(strmap_t *map);
+
+strmap_iter_t *strmap_iter_init(strmap_t *map);
+strmap_iter_t *strmap_iter_next(strmap_t *map, strmap_iter_t *iter);
+strmap_iter_t *strmap_iter_next_rmv(strmap_t *map, strmap_iter_t *iter);
+void strmap_iter_get(strmap_iter_t *iter, const char **keyp, void **valp);
+
+int strmap_iter_done(strmap_iter_t *iter);
+
+#endif
+/*
+  Local Variables:
+  mode:c
+  indent-tabs-mode:nil
+  c-basic-offset:2
+  End:
+*/
+
index e63a92c99b5dc7b969e912489d94ffc60e614275..cff4242e22a825edaf8c12eae3f454679350c323 100644 (file)
@@ -53,6 +53,7 @@
 #include "log.h"
 #include "aes.h"
 #include "util.h"
+#include "container.h"
 
 #if OPENSSL_VERSION_NUMBER < 0x00905000l
 #error "We require openssl >= 0.9.5"
index 0e458142f2ffcec7b284053922a83115155f4e22..55dabafaaabc0843423cba6a201daeeff230c92a 100644 (file)
@@ -15,6 +15,8 @@
  * \brief Headers for log.c
  */
 
+#include "../common/compat.h"
+
 #ifdef HAVE_SYSLOG_H
 #include <syslog.h>
 #define LOG_WARN LOG_WARNING
 #define LOG_ERR     3
 #endif
 
-/* magic to make GCC check for proper format strings. */
-#ifdef __GNUC__
-#define CHECK_PRINTF(formatIdx, firstArg) \
-   __attribute__ ((format (printf, formatIdx, firstArg)))
-#else
-#define CHECK_PRINTF(formatIdx, firstArg)
-#endif
-
 int parse_log_level(const char *level);
 void add_stream_log(int severityMin, int severityMax, const char *name, FILE *stream);
 int add_file_log(int severityMin, int severityMax, const char *filename);
index 06ad5d91fdb35797db19f4528509d75199ac1c99..45639e342604f77f52e1e0bef285cf227c0257eb 100644 (file)
@@ -6,7 +6,7 @@
  * \file util.c
  *
  * \brief Common functions for strings, IO, network, data structures,
- * process control, and cross-platform portability.
+ * process control.
  **/
 
 /* This is required on rh7 to make strptime not complain.
 
 #include "orconfig.h"
 
+/* XXXX probably some of these are unneeded. find out which. */
 #ifdef MS_WINDOWS
-#define WIN32_WINNT 0x400
-#define _WIN32_WINNT 0x400
-#define WIN32_LEAN_AND_MEAN
-#if _MSC_VER > 1300
-#include <winsock2.h>
-#include <ws2tcpip.h>
-#elif defined(_MSC_VER)
-#include <winsock.h>
-#endif
 #include <io.h>
 #include <process.h>
 #include <direct.h>
 #include <stdio.h>
 #include <string.h>
 #include <assert.h>
-#ifndef HAVE_GETTIMEOFDAY
-#ifdef HAVE_FTIME
-#include <sys/timeb.h>
-#endif
-#endif
 
 #include "util.h"
 #include "log.h"
 #include "crypto.h"
-#include "../or/tree.h"
 
-#ifdef HAVE_UNAME
-#include <sys/utsname.h>
-#endif
-#ifdef HAVE_CTYPE_H
-#include <ctype.h>
-#endif
 #ifdef HAVE_NETINET_IN_H
 #include <netinet/in.h>
 #endif
@@ -64,9 +44,6 @@
 #ifdef HAVE_LIMITS_H
 #include <limits.h>
 #endif
-#ifdef HAVE_SYS_PARAM_H
-#include <sys/param.h> /* FreeBSD needs this to know what version it is */
-#endif
 #ifdef HAVE_SYS_LIMITS_H
 #include <sys/limits.h>
 #endif
@@ -90,9 +67,6 @@
 #ifdef HAVE_SYS_TIME_H
 #include <sys/time.h>
 #endif
-#ifdef HAVE_SYS_RESOURCE_H
-#include <sys/resource.h>
-#endif
 #ifdef HAVE_UNISTD_H
 #include <unistd.h>
 #endif
 #ifdef HAVE_SYS_FCNTL_H
 #include <sys/fcntl.h>
 #endif
-#ifdef HAVE_PWD_H
-#include <pwd.h>
-#endif
-#ifdef HAVE_GRP_H
-#include <grp.h>
-#endif
 #ifdef HAVE_FCNTL_H
 #include <fcntl.h>
 #endif
 #define O_BINARY 0
 #endif
 
+/* =====
+ * Memory management
+ * ===== */
+
 /** Allocate a chunk of <b>size</b> bytes of memory, and return a pointer to
  * result.  On error, log and terminate the process.  (Same as malloc(size),
  * but never returns NULL.)
@@ -205,6 +177,10 @@ char *tor_strndup(const char *s, size_t n) {
   return dup;
 }
 
+/* =====
+ * String manipulation
+ * ===== */
+
 /** Remove from the string <b>s</b> every character which appears in
  * <b>strip</b>.  Return the number of characters removed. */
 int tor_strstrip(char *s, const char *strip)
@@ -280,48 +256,6 @@ int tor_strpartition(char *dest, size_t dest_len,
   return 0;
 }
 
-#ifndef UNALIGNED_INT_ACCESS_OK
-/**
- * Read a 16-bit value beginning at <b>cp</b>.  Equaivalent to
- * *(uint16_t*)(cp), but will not cause segfaults on platforms that forbid
- * unaligned memory access.
- */
-uint16_t get_uint16(const char *cp)
-{
-  uint16_t v;
-  memcpy(&v,cp,2);
-  return v;
-}
-/**
- * Read a 32-bit value beginning at <b>cp</b>.  Equaivalent to
- * *(uint32_t*)(cp), but will not cause segfaults on platforms that forbid
- * unaligned memory access.
- */
-uint32_t get_uint32(const char *cp)
-{
-  uint32_t v;
-  memcpy(&v,cp,4);
-  return v;
-}
-/**
- * Set a 16-bit value beginning at <b>cp</b> to <b>v</b>. Equivalent to
- * *(uint16_t)(cp) = v, but will not cause segfaults on platforms that forbid
- * unaligned memory access. */
-void set_uint16(char *cp, uint16_t v)
-{
-  memcpy(cp,&v,2);
-}
-/**
- * Set a 32-bit value beginning at <b>cp</b> to <b>v</b>. Equivalent to
- * *(uint32_t)(cp) = v, but will not cause segfaults on platforms that forbid
- * unaligned memory access. */
-void set_uint32(char *cp, uint32_t v)
-{
-  memcpy(cp,&v,4);
-}
-#endif
-
-
 /** Return a pointer to a NUL-terminated hexidecimal string encoding
  * the first <b>fromlen</b> bytes of <b>from</b>. (fromlen must be \<= 32.) The
  * result does not need to be deallocated, but repeated calls to
@@ -336,599 +270,6 @@ const char *hex_str(const char *from, size_t fromlen)
   return buf;
 }
 
-/*****
- * smartlist_t: a simple resizeable array abstraction.
- *****/
-
-/* All newly allocated smartlists have this capacity.
- */
-#define SMARTLIST_DEFAULT_CAPACITY 32
-
-
-struct smartlist_t {
-  /** <b>list</b> has enough capacity to store exactly <b>capacity</b> elements
-   * before it needs to be resized.  Only the first <b>num_used</b> (\<=
-   * capacity) elements point to valid data.
-   */
-  void **list;
-  int num_used;
-  int capacity;
-};
-
-/** Allocate and return an empty smartlist.
- */
-smartlist_t *smartlist_create() {
-  smartlist_t *sl = tor_malloc(sizeof(smartlist_t));
-  sl->num_used = 0;
-  sl->capacity = SMARTLIST_DEFAULT_CAPACITY;
-  sl->list = tor_malloc(sizeof(void *) * sl->capacity);
-  return sl;
-}
-
-/** Deallocate a smartlist.  Does not release storage associated with the
- * list's elements.
- */
-void smartlist_free(smartlist_t *sl) {
-  free(sl->list);
-  free(sl);
-}
-
-/** Change the capacity of the smartlist to <b>n</b>, so that we can grow
- * the list up to <b>n</b> elements with no further reallocation or wasted
- * space.  If <b>n</b> is less than or equal to the number of elements
- * currently in the list, reduce the list's capacity as much as
- * possible without losing elements.
- */
-void smartlist_set_capacity(smartlist_t *sl, int n) {
-  if (n < sl->num_used)
-    n = sl->num_used;
-  if (sl->capacity != n) {
-    sl->capacity = n;
-    sl->list = tor_realloc(sl->list, sizeof(void*)*sl->capacity);
-  }
-}
-
-/** Remove all elements from the list.
- */
-void smartlist_clear(smartlist_t *sl) {
-  sl->num_used = 0;
-}
-
-/** Set the list's new length to <b>len</b> (which must be \<= the list's
- * current size). Remove the last smartlist_len(sl)-len elements from the
- * list.
- */
-void smartlist_truncate(smartlist_t *sl, int len)
-{
-  tor_assert(len <= sl->num_used);
-  sl->num_used = len;
-}
-
-/** Append element to the end of the list. */
-void smartlist_add(smartlist_t *sl, void *element) {
-  if (sl->num_used >= sl->capacity) {
-    sl->capacity *= 2;
-    sl->list = tor_realloc(sl->list, sizeof(void*)*sl->capacity);
-  }
-  sl->list[sl->num_used++] = element;
-}
-
-/** Append each element from S2 to the end of S1. */
-void smartlist_add_all(smartlist_t *sl, const smartlist_t *s2)
-{
-  SMARTLIST_FOREACH(s2, void *, element, smartlist_add(sl, element));
-}
-
-/** Remove all elements E from sl such that E==element.  Does not preserve
- * the order of s1.
- */
-void smartlist_remove(smartlist_t *sl, void *element) {
-  int i;
-  if(element == NULL)
-    return;
-  for(i=0; i < sl->num_used; i++)
-    if(sl->list[i] == element) {
-      sl->list[i] = sl->list[--sl->num_used]; /* swap with the end */
-      i--; /* so we process the new i'th element */
-    }
-}
-
-/** Return true iff some element E of sl has E==element.
- */
-int smartlist_isin(const smartlist_t *sl, void *element) {
-  int i;
-  for(i=0; i < sl->num_used; i++)
-    if(sl->list[i] == element)
-      return 1;
-  return 0;
-}
-
-int smartlist_string_isin(const smartlist_t *sl, const char *element) {
-  int i;
-  for(i=0; i < sl->num_used; i++)
-    if(strcmp((const char*)sl->list[i],element)==0)
-      return 1;
-  return 0;
-}
-
-/** Return true iff some element E of sl2 has smartlist_isin(sl1,E).
- */
-int smartlist_overlap(const smartlist_t *sl1, const smartlist_t *sl2) {
-  int i;
-  for(i=0; i < sl2->num_used; i++)
-    if(smartlist_isin(sl1, sl2->list[i]))
-      return 1;
-  return 0;
-}
-
-/** Remove every element E of sl1 such that !smartlist_isin(sl2,E).
- * Does not preserve the order of sl1.
- */
-void smartlist_intersect(smartlist_t *sl1, const smartlist_t *sl2) {
-  int i;
-  for(i=0; i < sl1->num_used; i++)
-    if(!smartlist_isin(sl2, sl1->list[i])) {
-      sl1->list[i] = sl1->list[--sl1->num_used]; /* swap with the end */
-      i--; /* so we process the new i'th element */
-    }
-}
-
-/** Remove every element E of sl1 such that smartlist_isin(sl2,E).
- * Does not preserve the order of sl1.
- */
-void smartlist_subtract(smartlist_t *sl1, const smartlist_t *sl2) {
-  int i;
-  for(i=0; i < sl2->num_used; i++)
-    smartlist_remove(sl1, sl2->list[i]);
-}
-
-/** Return the <b>idx</b>th element of sl.
- */
-void *smartlist_get(const smartlist_t *sl, int idx)
-{
-  tor_assert(sl);
-  tor_assert(idx>=0);
-  tor_assert(idx < sl->num_used);
-  return sl->list[idx];
-}
-/** Change the value of the <b>idx</b>th element of sl to <b>val</b>; return the old
- * value of the <b>idx</b>th element.
- */
-void *smartlist_set(smartlist_t *sl, int idx, void *val)
-{
-  void *old;
-  tor_assert(sl);
-  tor_assert(idx>=0);
-  tor_assert(idx < sl->num_used);
-  old = sl->list[idx];
-  sl->list[idx] = val;
-  return old;
-}
-/** Remove the <b>idx</b>th element of sl; if idx is not the last
- * element, swap the last element of sl into the <b>idx</b>th space.
- * Return the old value of the <b>idx</b>th element.
- */
-void *smartlist_del(smartlist_t *sl, int idx)
-{
-  void *old;
-  tor_assert(sl);
-  tor_assert(idx>=0);
-  tor_assert(idx < sl->num_used);
-  old = sl->list[idx];
-  sl->list[idx] = sl->list[--sl->num_used];
-  return old;
-}
-/** Remove the <b>idx</b>th element of sl; if idx is not the last element,
- * moving all subsequent elements back one space. Return the old value
- * of the <b>idx</b>th element.
- */
-void *smartlist_del_keeporder(smartlist_t *sl, int idx)
-{
-  void *old;
-  tor_assert(sl);
-  tor_assert(idx>=0);
-  tor_assert(idx < sl->num_used);
-  old = sl->list[idx];
-  --sl->num_used;
-  if (idx < sl->num_used)
-    memmove(sl->list+idx, sl->list+idx+1, sizeof(void*)*(sl->num_used-idx));
-  return old;
-}
-/** Return the number of items in sl.
- */
-int smartlist_len(const smartlist_t *sl)
-{
-  return sl->num_used;
-}
-/** Insert the value <b>val</b> as the new <b>idx</b>th element of
- * <b>sl</b>, moving all items previously at <b>idx</b> or later
- * forward one space.
- */
-void smartlist_insert(smartlist_t *sl, int idx, void *val)
-{
-  tor_assert(sl);
-  tor_assert(idx>=0);
-  tor_assert(idx <= sl->num_used);
-  if (idx == sl->num_used) {
-    smartlist_add(sl, val);
-  } else {
-    /* Ensure sufficient capacity */
-    if (sl->num_used >= sl->capacity) {
-      sl->capacity *= 2;
-      sl->list = tor_realloc(sl->list, sizeof(void*)*sl->capacity);
-    }
-    /* Move other elements away */
-    if (idx < sl->num_used)
-      memmove(sl->list + idx + 1, sl->list + idx,
-              sizeof(void*)*(sl->num_used-idx));
-    sl->num_used++;
-    sl->list[idx] = val;
-  }
-}
-
-/**
- * Split a string <b>str</b> along all occurences of <b>sep</b>,
- * adding the split strings, in order, to <b>sl</b>.  If
- * <b>flags</b>&amp;SPLIT_SKIP_SPACE is true, remove initial and
- * trailing space from each entry.  If
- * <b>flags</b>&amp;SPLIT_IGNORE_BLANK is true, remove any entries of
- * length 0.  If max>0, divide the string into no more than <b>max</b>
- * pieces.
- */
-int smartlist_split_string(smartlist_t *sl, const char *str, const char *sep,
-                           int flags, int max)
-{
-  const char *cp, *end, *next;
-  int n = 0;
-
-  tor_assert(sl);
-  tor_assert(str);
-  tor_assert(sep);
-
-  cp = str;
-  while (1) {
-    if (flags&SPLIT_SKIP_SPACE) {
-      while (isspace((int)*cp)) ++cp;
-    }
-
-    if (max>0 && n == max-1) {
-      end = strchr(cp,'\0');
-    } else {
-      end = strstr(cp,sep);
-      if (!end)
-        end = strchr(cp,'\0');
-    }
-    if (!*end) {
-      next = NULL;
-    } else {
-      next = end+strlen(sep);
-    }
-
-    if (flags&SPLIT_SKIP_SPACE) {
-      while (end > cp && isspace((int)*(end-1)))
-        --end;
-    }
-    if (end != cp || !(flags&SPLIT_IGNORE_BLANK)) {
-      smartlist_add(sl, tor_strndup(cp, end-cp));
-      ++n;
-    }
-    if (!next)
-      break;
-    cp = next;
-  }
-
-  return n;
-}
-
-/** Allocate and return a new string containing the concatenation of
- * the elements of <b>sl</b>, in order, separated by <b>join</b>.  If
- * <b>terminate</b> is true, also terminate the string with <b>join</b>.
- * Requires that every element of <b>sl</b> is NUL-terminated string.
- */
-char *smartlist_join_strings(smartlist_t *sl, const char *join, int terminate)
-{
-  int i;
-  size_t n = 0, jlen;
-  char *r = NULL, *dst, *src;
-
-  tor_assert(sl);
-  tor_assert(join);
-  jlen = strlen(join);
-  for (i = 0; i < sl->num_used; ++i) {
-    n += strlen(sl->list[i]);
-    n += jlen;
-  }
-  if (!terminate) n -= jlen;
-  dst = r = tor_malloc(n+1);
-  for (i = 0; i < sl->num_used; ) {
-    for (src = sl->list[i]; *src; )
-      *dst++ = *src++;
-    if (++i < sl->num_used || terminate) {
-      memcpy(dst, join, jlen);
-      dst += jlen;
-    }
-  }
-  *dst = '\0';
-  return r;
-}
-
-/* Splay-tree implementation of string-to-void* map
- */
-struct strmap_entry_t {
-  SPLAY_ENTRY(strmap_entry_t) node;
-  char *key;
-  void *val;
-};
-
-struct strmap_t {
-  SPLAY_HEAD(strmap_tree, strmap_entry_t) head;
-};
-
-static int compare_strmap_entries(struct strmap_entry_t *a,
-                                 struct strmap_entry_t *b)
-{
-  return strcmp(a->key, b->key);
-}
-
-SPLAY_PROTOTYPE(strmap_tree, strmap_entry_t, node, compare_strmap_entries);
-SPLAY_GENERATE(strmap_tree, strmap_entry_t, node, compare_strmap_entries);
-
-/** Create a new empty map from strings to void*'s.
- */
-strmap_t* strmap_new(void)
-{
-  strmap_t *result;
-  result = tor_malloc(sizeof(strmap_t));
-  SPLAY_INIT(&result->head);
-  return result;
-}
-
-/** Set the current value for <b>key</b> to <b>val</b>.  Returns the previous
- * value for <b>key</b> if one was set, or NULL if one was not.
- *
- * This function makes a copy of <b>key</b> if necessary, but not of <b>val</b>.
- */
-void* strmap_set(strmap_t *map, const char *key, void *val)
-{
-  strmap_entry_t *resolve;
-  strmap_entry_t search;
-  void *oldval;
-  tor_assert(map);
-  tor_assert(key);
-  tor_assert(val);
-  search.key = (char*)key;
-  resolve = SPLAY_FIND(strmap_tree, &map->head, &search);
-  if (resolve) {
-    oldval = resolve->val;
-    resolve->val = val;
-    return oldval;
-  } else {
-    resolve = tor_malloc_zero(sizeof(strmap_entry_t));
-    resolve->key = tor_strdup(key);
-    resolve->val = val;
-    SPLAY_INSERT(strmap_tree, &map->head, resolve);
-    return NULL;
-  }
-}
-
-/** Return the current value associated with <b>key</b>, or NULL if no
- * value is set.
- */
-void* strmap_get(strmap_t *map, const char *key)
-{
-  strmap_entry_t *resolve;
-  strmap_entry_t search;
-  tor_assert(map);
-  tor_assert(key);
-  search.key = (char*)key;
-  resolve = SPLAY_FIND(strmap_tree, &map->head, &search);
-  if (resolve) {
-    return resolve->val;
-  } else {
-    return NULL;
-  }
-}
-
-/** Remove the value currently associated with <b>key</b> from the map.
- * Return the value if one was set, or NULL if there was no entry for
- * <b>key</b>.
- *
- * Note: you must free any storage associated with the returned value.
- */
-void* strmap_remove(strmap_t *map, const char *key)
-{
-  strmap_entry_t *resolve;
-  strmap_entry_t search;
-  void *oldval;
-  tor_assert(map);
-  tor_assert(key);
-  search.key = (char*)key;
-  resolve = SPLAY_FIND(strmap_tree, &map->head, &search);
-  if (resolve) {
-    oldval = resolve->val;
-    SPLAY_REMOVE(strmap_tree, &map->head, resolve);
-    tor_free(resolve->key);
-    tor_free(resolve);
-    return oldval;
-  } else {
-    return NULL;
-  }
-}
-
-/** Same as strmap_set, but first converts <b>key</b> to lowercase. */
-void* strmap_set_lc(strmap_t *map, const char *key, void *val)
-{
-  /* We could be a little faster by using strcasecmp instead, and a separate
-   * type, but I don't think it matters. */
-  void *v;
-  char *lc_key = tor_strdup(key);
-  tor_strlower(lc_key);
-  v = strmap_set(map,lc_key,val);
-  tor_free(lc_key);
-  return v;
-}
-/** Same as strmap_get, but first converts <b>key</b> to lowercase. */
-void* strmap_get_lc(strmap_t *map, const char *key)
-{
-  void *v;
-  char *lc_key = tor_strdup(key);
-  tor_strlower(lc_key);
-  v = strmap_get(map,lc_key);
-  tor_free(lc_key);
-  return v;
-}
-/** Same as strmap_remove, but first converts <b>key</b> to lowercase */
-void* strmap_remove_lc(strmap_t *map, const char *key)
-{
-  void *v;
-  char *lc_key = tor_strdup(key);
-  tor_strlower(lc_key);
-  v = strmap_remove(map,lc_key);
-  tor_free(lc_key);
-  return v;
-}
-
-/** Invoke fn() on every entry of the map, in order.  For every entry,
- * fn() is invoked with that entry's key, that entry's value, and the
- * value of <b>data</b> supplied to strmap_foreach.  fn() must return a new
- * (possibly unmodified) value for each entry: if fn() returns NULL, the
- * entry is removed.
- *
- * Example:
- * \code
- *   static void* upcase_and_remove_empty_vals(const char *key, void *val,
- *                                             void* data) {
- *     char *cp = (char*)val;
- *     if (!*cp) {  // val is an empty string.
- *       free(val);
- *       return NULL;
- *     } else {
- *       for (; *cp; cp++)
- *         *cp = toupper(*cp);
- *       }
- *       return val;
- *     }
- *   }
- *
- *   ...
- *
- *   strmap_foreach(map, upcase_and_remove_empty_vals, NULL);
- * \endcode
- */
-void strmap_foreach(strmap_t *map,
-                    void* (*fn)(const char *key, void *val, void *data),
-                    void *data)
-{
-  strmap_entry_t *ptr, *next;
-  tor_assert(map);
-  tor_assert(fn);
-  for (ptr = SPLAY_MIN(strmap_tree, &map->head); ptr != NULL; ptr = next) {
-    /* This remove-in-place usage is specifically blessed in tree(3). */
-    next = SPLAY_NEXT(strmap_tree, &map->head, ptr);
-    ptr->val = fn(ptr->key, ptr->val, data);
-    if (!ptr->val) {
-      SPLAY_REMOVE(strmap_tree, &map->head, ptr);
-      tor_free(ptr->key);
-      tor_free(ptr);
-    }
-  }
-}
-
-/** return an <b>iterator</b> pointer to the front of a map.
- *
- * Iterator example:
- *
- * \code
- * // uppercase values in "map", removing empty values.
- *
- * strmap_iter_t *iter;
- * const char *key;
- * void *val;
- * char *cp;
- *
- * for (iter = strmap_iter_init(map); !strmap_iter_done(iter); ) {
- *    strmap_iter_get(iter, &key, &val);
- *    cp = (char*)val;
- *    if (!*cp) {
- *       iter = strmap_iter_next_rmv(iter);
- *       free(val);
- *    } else {
- *       for(;*cp;cp++) *cp = toupper(*cp);
- *       iter = strmap_iter_next(iter);
- *    }
- * }
- * \endcode
- *
- */
-strmap_iter_t *strmap_iter_init(strmap_t *map)
-{
-  tor_assert(map);
-  return SPLAY_MIN(strmap_tree, &map->head);
-}
-/** Advance the iterator <b>iter</b> for map a single step to the next entry.
- */
-strmap_iter_t *strmap_iter_next(strmap_t *map, strmap_iter_t *iter)
-{
-  tor_assert(map);
-  tor_assert(iter);
-  return SPLAY_NEXT(strmap_tree, &map->head, iter);
-}
-/** Advance the iterator <b>iter</b> a single step to the next entry, removing
- * the current entry.
- */
-strmap_iter_t *strmap_iter_next_rmv(strmap_t *map, strmap_iter_t *iter)
-{
-  strmap_iter_t *next;
-  tor_assert(map);
-  tor_assert(iter);
-  next = SPLAY_NEXT(strmap_tree, &map->head, iter);
-  SPLAY_REMOVE(strmap_tree, &map->head, iter);
-  tor_free(iter->key);
-  tor_free(iter);
-  return next;
-}
-/** Set *keyp and *valp to the current entry pointed to by iter.
- */
-void strmap_iter_get(strmap_iter_t *iter, const char **keyp, void **valp)
-{
-  tor_assert(iter);
-  tor_assert(keyp);
-  tor_assert(valp);
-  *keyp = iter->key;
-  *valp = iter->val;
-}
-/** Return true iff iter has advanced past the last entry of map.
- */
-int strmap_iter_done(strmap_iter_t *iter)
-{
-  return iter == NULL;
-}
-/** Remove all entries from <b>map</b>, and deallocate storage for those entries.
- * If free_val is provided, it is invoked on every value in <b>map</b>.
- */
-void strmap_free(strmap_t *map, void (*free_val)(void*))
-{
-  strmap_entry_t *ent, *next;
-  for (ent = SPLAY_MIN(strmap_tree, &map->head); ent != NULL; ent = next) {
-    next = SPLAY_NEXT(strmap_tree, &map->head, ent);
-    SPLAY_REMOVE(strmap_tree, &map->head, ent);
-    tor_free(ent->key);
-    if (free_val)
-      tor_free(ent->val);
-  }
-  tor_assert(SPLAY_EMPTY(&map->head));
-  tor_free(map);
-}
-
-int strmap_isempty(strmap_t *map)
-{
-  return SPLAY_EMPTY(&map->head);
-}
-
-/*
- *    String manipulation
- */
-
 /** Convert all alphabetic characters in the nul-terminated string <b>s</b> to
  * lowercase. */
 void tor_strlower(char *s)
@@ -988,51 +329,146 @@ const char *find_whitespace(const char *s) {
   return s;
 }
 
-/*
- * Time
- */
-
-/** Set *timeval to the current time of day.  On error, log and terminate.
- * (Same as gettimeofday(timeval,NULL), but never returns -1.)
- */
-void tor_gettimeofday(struct timeval *timeval) {
-#ifdef HAVE_GETTIMEOFDAY
-  if (gettimeofday(timeval, NULL)) {
-    log_fn(LOG_ERR, "gettimeofday failed.");
-    /* If gettimeofday dies, we have either given a bad timezone (we didn't),
-       or segfaulted.*/
-    exit(1);
-  }
-#elif defined(HAVE_FTIME)
-  struct timeb tb;
-  ftime(&tb);
-  timeval->tv_sec = tb.time;
-  timeval->tv_usec = tb.millitm * 1000;
-#else
-#error "No way to get time."
-#endif
-  return;
-}
-
-/** Return the number of microseconds elapsed between *start and *end.
- * If start is after end, return 0.
+/** Extract a long from the start of s, in the given numeric base.  If
+ * there is unconverted data and next is provided, set *next to the
+ * first unconverted character.  An error has occurred if no characters
+ * are converted; or if there are unconverted characters and next is NULL; or
+ * if the parsed value is not between min and max.  When no error occurs,
+ * return the parsed value and set *ok (if provided) to 1.  When an error
+ * ocurs, return 0 and set *ok (if provided) to 0.
  */
 long
-tv_udiff(struct timeval *start, struct timeval *end)
+tor_parse_long(const char *s, int base, long min, long max,
+               int *ok, char **next)
 {
-  long udiff;
-  long secdiff = end->tv_sec - start->tv_sec;
-
-  if (secdiff+1 > LONG_MAX/1000000) {
-    log_fn(LOG_WARN, "comparing times too far apart.");
-    return LONG_MAX;
-  }
+  char *endptr;
+  long r;
 
-  udiff = secdiff*1000000L + (end->tv_usec - start->tv_usec);
-  if(udiff < 0) {
-    log_fn(LOG_INFO, "start (%ld.%ld) is after end (%ld.%ld). Returning 0.",
-           (long)start->tv_sec, (long)start->tv_usec, (long)end->tv_sec, (long)end->tv_usec);
-    return 0;
+  r = strtol(s, &endptr, base);
+  /* Was at least one character converted? */
+  if (endptr == s)
+    goto err;
+  /* Were there unexpected unconverted characters? */
+  if (!next && *endptr)
+    goto err;
+  /* Is r within limits? */
+  if (r < min || r > max)
+    goto err;
+
+  if (ok) *ok = 1;
+  if (next) *next = endptr;
+  return r;
+ err:
+  if (ok) *ok = 0;
+  if (next) *next = endptr;
+  return 0;
+}
+
+unsigned long
+tor_parse_ulong(const char *s, int base, unsigned long min,
+                unsigned long max, int *ok, char **next)
+{
+  char *endptr;
+  unsigned long r;
+
+  r = strtol(s, &endptr, base);
+  /* Was at least one character converted? */
+  if (endptr == s)
+    goto err;
+  /* Were there unexpected unconverted characters? */
+  if (!next && *endptr)
+    goto err;
+  /* Is r within limits? */
+  if (r < min || r > max)
+    goto err;
+
+  if (ok) *ok = 1;
+  if (next) *next = endptr;
+  return r;
+ err:
+  if (ok) *ok = 0;
+  if (next) *next = endptr;
+  return 0;
+}
+
+void base16_encode(char *dest, size_t destlen, const char *src, size_t srclen)
+{
+  const char *end;
+  char *cp;
+
+  tor_assert(destlen >= srclen*2+1);
+
+  cp = dest;
+  end = src+srclen;
+  while (src<end) {
+    sprintf(cp,"%02X",*(const uint8_t*)src);
+    ++src;
+    cp += 2;
+  }
+  *cp = '\0';
+}
+
+static const char HEX_DIGITS[] = "0123456789ABCDEFabcdef";
+
+static INLINE int hex_decode_digit(char c)
+{
+  const char *cp;
+  int n;
+  cp = strchr(HEX_DIGITS, c);
+  if (!cp)
+    return -1;
+  n = cp-HEX_DIGITS;
+  if (n<=15)
+    return n; /* digit or uppercase */
+  else
+    return n-6; /* lowercase */
+}
+
+int base16_decode(char *dest, size_t destlen, const char *src, size_t srclen)
+{
+  const char *end;
+  int v1,v2;
+  if ((srclen % 2) != 0)
+    return -1;
+  if (destlen < srclen/2)
+    return -1;
+  end = src+srclen;
+  while (src<end) {
+    v1 = hex_decode_digit(*src);
+    v2 = hex_decode_digit(*(src+1));
+    if(v1<0||v2<0)
+      return -1;
+    *(uint8_t*)dest = (v1<<4)|v2;
+    ++dest;
+    src+=2;
+  }
+  return 0;
+}
+
+
+/* =====
+ * Time
+ * ===== */
+
+/** Return the number of microseconds elapsed between *start and *end.
+ * If start is after end, return 0.
+ */
+long
+tv_udiff(struct timeval *start, struct timeval *end)
+{
+  long udiff;
+  long secdiff = end->tv_sec - start->tv_sec;
+
+  if (secdiff+1 > LONG_MAX/1000000) {
+    log_fn(LOG_WARN, "comparing times too far apart.");
+    return LONG_MAX;
+  }
+
+  udiff = secdiff*1000000L + (end->tv_usec - start->tv_usec);
+  if(udiff < 0) {
+    log_fn(LOG_INFO, "start (%ld.%ld) is after end (%ld.%ld). Returning 0.",
+           (long)start->tv_sec, (long)start->tv_usec, (long)end->tv_sec, (long)end->tv_usec);
+    return 0;
   }
   return udiff;
 }
@@ -1189,10 +625,9 @@ int parse_iso_time(const char *cp, time_t *t) {
   return 0;
 }
 
-
-/*
- *   Low-level I/O.
- */
+/* =====
+ * File helpers
+ * ===== */
 
 /** Write <b>count</b> bytes from <b>buf</b> to <b>fd</b>.  <b>isSocket</b>
  * must be 1 if fd was returned by socket() or accept(), and 0 if fd
@@ -1238,277 +673,6 @@ int read_all(int fd, char *buf, size_t count, int isSocket) {
   return count;
 }
 
-/** Turn <b>socket</b> into a nonblocking socket.
- */
-void set_socket_nonblocking(int socket)
-{
-#ifdef MS_WINDOWS
-  /* Yes means no and no means yes.  Do you not want to be nonblocking? */
-  int nonblocking = 0;
-  ioctlsocket(socket, FIONBIO, (unsigned long*) &nonblocking);
-#else
-  fcntl(socket, F_SETFL, O_NONBLOCK);
-#endif
-}
-
-/*
- *   Process control
- */
-
-/** Minimalist interface to run a void function in the background.  On
- * unix calls fork, on win32 calls beginthread.  Returns -1 on failure.
- * func should not return, but rather should call spawn_exit.
- */
-int spawn_func(int (*func)(void *), void *data)
-{
-#ifdef MS_WINDOWS
-  int rv;
-  rv = _beginthread(func, 0, data);
-  if (rv == (unsigned long) -1)
-    return -1;
-  return 0;
-#else
-  pid_t pid;
-  pid = fork();
-  if (pid<0)
-    return -1;
-  if (pid==0) {
-    /* Child */
-    func(data);
-    tor_assert(0); /* Should never reach here. */
-    return 0; /* suppress "control-reaches-end-of-non-void" warning. */
-  } else {
-    /* Parent */
-    return 0;
-  }
-#endif
-}
-
-/** End the current thread/process.
- */
-void spawn_exit()
-{
-#ifdef MS_WINDOWS
-  _endthread();
-#else
-  exit(0);
-#endif
-}
-
-
-/**
- * Allocate a pair of connected sockets.  (Like socketpair(family,
- * type,protocol,fd), but works on systems that don't have
- * socketpair.)
- *
- * Currently, only (AF_UNIX, SOCK_STREAM, 0 ) sockets are supported.
- *
- * Note that on systems without socketpair, this call will fail if
- * localhost is inaccessible (for example, if the networking
- * stack is down). And even if it succeeds, the socket pair will not
- * be able to read while localhost is down later (the socket pair may
- * even close, depending on OS-specific timeouts).
- **/
-int
-tor_socketpair(int family, int type, int protocol, int fd[2])
-{
-#ifdef HAVE_SOCKETPAIR
-    return socketpair(family, type, protocol, fd);
-#else
-    /* 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.
-     */
-    int listener = -1;
-    int connector = -1;
-    int acceptor = -1;
-    struct sockaddr_in listen_addr;
-    struct sockaddr_in connect_addr;
-    int size;
-
-    if (protocol
-#ifdef AF_UNIX
-        || family != AF_UNIX
-#endif
-        ) {
-#ifdef MS_WINDOWS
-        errno = WSAEAFNOSUPPORT;
-#else
-        errno = EAFNOSUPPORT;
-#endif
-        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;
-    tor_close_socket(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:
-#ifdef MS_WINDOWS
-  errno = WSAECONNABORTED;
-#else
-  errno = ECONNABORTED; /* I hope this is portable and appropriate.  */
-#endif
-  tidy_up_and_fail:
-    {
-        int save_errno = errno;
-        if (listener != -1)
-            tor_close_socket(listener);
-        if (connector != -1)
-            tor_close_socket(connector);
-        if (acceptor != -1)
-            tor_close_socket(acceptor);
-        errno = save_errno;
-        return -1;
-    }
-#endif
-}
-
-/**
- * On Windows, WSAEWOULDBLOCK is not always correct: when you see it,
- * you need to ask the socket for its actual errno.  Also, you need to
- * get your errors from WSAGetLastError, not errno.  (If you supply a
- * socket of -1, we check WSAGetLastError, but don't correct
- * WSAEWOULDBLOCKs.)
- */
-#ifdef MS_WINDOWS
-int tor_socket_errno(int sock)
-{
-  int optval, optvallen=sizeof(optval);
-  int err = WSAGetLastError();
-  if (err == WSAEWOULDBLOCK && sock >= 0) {
-    if (getsockopt(sock, SOL_SOCKET, SO_ERROR, (void*)&optval, &optvallen))
-      return err;
-    if (optval)
-      return optval;
-  }
-  return err;
-}
-#endif
-
-#ifdef MS_WINDOWS
-#define E(code, s) { code, (s " [" #code " ]") }
-struct { int code; const char *msg; } windows_socket_errors[] = {
-  E(WSAEINTR, "Interrupted function call"),
-  E(WSAEACCES, "Permission denied"),
-  E(WSAEFAULT, "Bad address"),
-  E(WSAEINVAL, "Invalid argument"),
-  E(WSAEMFILE, "Too many open files"),
-  E(WSAEWOULDBLOCK,  "Resource temporarily unavailable"),
-  E(WSAEINPROGRESS, "Operation now in progress"),
-  E(WSAEALREADY, "Operation already in progress"),
-  E(WSAENOTSOCK, "Socket operation on nonsocket"),
-  E(WSAEDESTADDRREQ, "Destination address required"),
-  E(WSAEMSGSIZE, "Message too long"),
-  E(WSAEPROTOTYPE, "Protocol wrong for socket"),
-  E(WSAENOPROTOOPT, "Bad protocol option"),
-  E(WSAEPROTONOSUPPORT, "Protocol not supported"),
-  E(WSAESOCKTNOSUPPORT, "Socket type not supported"),
-  /* What's the difference between NOTSUPP and NOSUPPORT? :) */
-  E(WSAEOPNOTSUPP, "Operation not supported"),
-  E(WSAEPFNOSUPPORT,  "Protocol family not supported"),
-  E(WSAEAFNOSUPPORT, "Address family not supported by protocol family"),
-  E(WSAEADDRINUSE, "Address already in use"),
-  E(WSAEADDRNOTAVAIL, "Cannot assign requested address"),
-  E(WSAENETDOWN, "Network is down"),
-  E(WSAENETUNREACH, "Network is unreachable"),
-  E(WSAENETRESET, "Network dropped connection on reset"),
-  E(WSAECONNABORTED, "Software caused connection abort"),
-  E(WSAECONNRESET, "Connection reset by peer"),
-  E(WSAENOBUFS, "No buffer space avaialable"),
-  E(WSAEISCONN, "Socket is already connected"),
-  E(WSAENOTCONN, "Socket is not connected"),
-  E(WSAESHUTDOWN, "Cannot send after socket shutdown"),
-  E(WSAETIMEDOUT, "Connection timed out"),
-  E(WSAECONNREFUSED, "Connection refused"),
-  E(WSAEHOSTDOWN, "Host is down"),
-  E(WSAEHOSTUNREACH, "No route to host"),
-  E(WSAEPROCLIM, "Too many processes"),
-  /* Yes, some of these start with WSA, not WSAE. No, I don't know why. */
-  E(WSASYSNOTREADY, "Network subsystem is unavailable"),
-  E(WSAVERNOTSUPPORTED, "Winsock.dll out of range"),
-  E(WSANOTINITIALISED, "Successful WSAStartup not yet performed"),
-  E(WSAEDISCON, "Graceful shutdown now in progress"),
-#ifdef WSATYPE_NOT_FOUND
-  E(WSATYPE_NOT_FOUND, "Class type not found"),
-#endif
-  E(WSAHOST_NOT_FOUND, "Host not found"),
-  E(WSATRY_AGAIN, "Nonauthoritative host not found"),
-  E(WSANO_RECOVERY, "This is a nonrecoverable error"),
-  E(WSANO_DATA, "Valid name, no data record of requested type)"),
-
-  /* There are some more error codes whose numeric values are marked
-   * <b>OS dependent</b>. They start with WSA_, apparently for the same
-   * reason that practitioners of some craft traditions deliberately
-   * introduce imperfections into their baskets and rugs "to allow the
-   * evil spirits to escape."  If we catch them, then our binaries
-   * might not report consistent results across versions of Windows.
-   * Thus, I'm going to let them all fall through.
-   */
-  { -1, NULL },
-};
-/** There does not seem to be a strerror equivalent for winsock errors.
- * Naturally, we have to roll our own.
- */
-const char *tor_socket_strerror(int e)
-{
-  int i;
-  for (i=0; windows_socket_errors[i].code >= 0; ++i) {
-    if (e == windows_socket_errors[i].code)
-      return windows_socket_errors[i].msg;
-  }
-  return strerror(e);
-}
-#endif
-
 /*
  *    Filesystem operations.
  */
@@ -1623,6 +787,7 @@ write_str_to_file(const char *fname, const char *str, int bin)
     return -1;
   }
 
+  /* XXXX use replace_file() instead. */
 #ifdef MS_WINDOWS
   /* On Windows, rename doesn't replace.  We could call ReplaceFile, but
    * that's hard, and we can probably sneak by without atomicity. */
@@ -1778,32 +943,9 @@ char *expand_filename(const char *filename)
   }
 }
 
-/**
- * Rename the file 'from' to the file 'to'.  On unix, this is the same as
- * rename(2).  On windows, this removes 'to' first if it already exists.
- * Returns 0 on success.  Returns -1 and sets errno on failure.
- */
-int replace_file(const char *from, const char *to)
-{
-#ifndef MS_WINDOWS
-  return rename(from,to);
-#else
-  switch(file_status(to))
-    {
-    case FN_NOENT:
-      break;
-    case FN_FILE:
-      if (unlink(to)) return -1;
-      break;
-    case FN_ERROR:
-      return -1;
-    case FN_DIR:
-      errno = EISDIR;
-      return -1;
-    }
-  return rename(from,to);
-#endif
-}
+/* =====
+ * Net helpers
+ * ===== */
 
 /** Return true iff <b>ip</b> (in host order) is an IP reserved to localhost,
  * or reserved for local networks by RFC 1918.
@@ -1828,273 +970,14 @@ int is_local_IP(uint32_t ip) {
   return is_internal_IP(ip);
 }
 
-/* Hold the result of our call to <b>uname</b>. */
-static char uname_result[256];
-/* True iff uname_result is set. */
-static int uname_result_is_set = 0;
-
-/* Return a pointer to a description of our platform.
- */
-const char *
-get_uname(void)
-{
-#ifdef HAVE_UNAME
-  struct utsname u;
-#endif
-  if (!uname_result_is_set) {
-#ifdef HAVE_UNAME
-    if (uname(&u) != -1) {
-      /* (linux says 0 is success, solaris says 1 is success) */
-      tor_snprintf(uname_result, sizeof(uname_result), "%s %s %s",
-               u.sysname, u.nodename, u.machine);
-    } else
-#endif
-      {
-        strlcpy(uname_result, "Unknown platform", sizeof(uname_result));
-      }
-    uname_result_is_set = 1;
-  }
-  return uname_result;
-}
-
-#ifndef MS_WINDOWS
-/* Based on code contributed by christian grothoff */
-static int start_daemon_called = 0;
-static int finish_daemon_called = 0;
-static int daemon_filedes[2];
-/** Start putting the process into daemon mode: fork and drop all resources
- * except standard fds.  The parent process never returns, but stays around
- * until finish_daemon is called.  (Note: it's safe to call this more
- * than once: calls after the first are ignored.)
+/** Similar behavior to Unix gethostbyname: resolve <b>name</b>, and set
+ * *addr to the proper IP address, in network byte order.  Returns 0
+ * on success, -1 on failure; 1 on transient failure.
+ *
+ * (This function exists because standard windows gethostbyname
+ * doesn't treat raw IP addresses properly.)
  */
-void start_daemon(const char *desired_cwd)
-{
-  pid_t pid;
-
-  if (start_daemon_called)
-    return;
-  start_daemon_called = 1;
-
-  if(!desired_cwd)
-    desired_cwd = "/";
-   /* Don't hold the wrong FS mounted */
-  if (chdir(desired_cwd) < 0) {
-    log_fn(LOG_ERR,"chdir to %s failed. Exiting.",desired_cwd);
-    exit(1);
-  }
-
-  pipe(daemon_filedes);
-  pid = fork();
-  if (pid < 0) {
-    log_fn(LOG_ERR,"fork failed. Exiting.");
-    exit(1);
-  }
-  if (pid) {  /* Parent */
-    int ok;
-    char c;
-
-    close(daemon_filedes[1]); /* we only read */
-    ok = -1;
-    while (0 < read(daemon_filedes[0], &c, sizeof(char))) {
-      if (c == '.')
-        ok = 1;
-    }
-    fflush(stdout);
-    if (ok == 1)
-      exit(0);
-    else
-      exit(1); /* child reported error */
-  } else { /* Child */
-    close(daemon_filedes[0]); /* we only write */
-
-    pid = setsid(); /* Detach from controlling terminal */
-    /*
-     * Fork one more time, so the parent (the session group leader) can exit.
-     * This means that we, as a non-session group leader, can never regain a
-     * controlling terminal.   This part is recommended by Stevens's
-     * _Advanced Programming in the Unix Environment_.
-     */
-    if (fork() != 0) {
-      exit(0);
-    }
-    return;
-  }
-}
-
-/** Finish putting the process into daemon mode: drop standard fds, and tell
- * the parent process to exit.  (Note: it's safe to call this more than once:
- * calls after the first are ignored.  Calls start_daemon first if it hasn't
- * been called already.)
- */
-void finish_daemon(void)
-{
-  int nullfd;
-  char c = '.';
-  if (finish_daemon_called)
-    return;
-  if (!start_daemon_called)
-    start_daemon(NULL);
-  finish_daemon_called = 1;
-
-  nullfd = open("/dev/null",
-                O_CREAT | O_RDWR | O_APPEND);
-  if (nullfd < 0) {
-    log_fn(LOG_ERR,"/dev/null can't be opened. Exiting.");
-    exit(1);
-  }
-  /* close fds linking to invoking terminal, but
-   * close usual incoming fds, but redirect them somewhere
-   * useful so the fds don't get reallocated elsewhere.
-   */
-  if (dup2(nullfd,0) < 0 ||
-      dup2(nullfd,1) < 0 ||
-      dup2(nullfd,2) < 0) {
-    log_fn(LOG_ERR,"dup2 failed. Exiting.");
-    exit(1);
-  }
-  write(daemon_filedes[1], &c, sizeof(char)); /* signal success */
-  close(daemon_filedes[1]);
-}
-#else
-/* defined(MS_WINDOWS) */
-void start_daemon(const char *cp) {}
-void finish_daemon(void) {}
-#endif
-
-/** Write the current process ID, followed by NL, into <b>filename</b>.
- */
-void write_pidfile(char *filename) {
-#ifndef MS_WINDOWS
-  FILE *pidfile;
-
-  if ((pidfile = fopen(filename, "w")) == NULL) {
-    log_fn(LOG_WARN, "Unable to open %s for writing: %s", filename,
-           strerror(errno));
-  } else {
-    fprintf(pidfile, "%d\n", (int)getpid());
-    fclose(pidfile);
-  }
-#endif
-}
-
-/** Get the maximum allowed number of file descriptors. (Some systems
- * have a low soft limit.) Make sure we set it to at least
- * <b>required_min</b>. Return 0 if we can, or -1 if we fail. */
-int set_max_file_descriptors(int required_min) {
-  struct rlimit rlim;
-
-#ifndef HAVE_GETRLIMIT
-  log_fn(LOG_INFO,"This platform is missing getrlimit(). Proceeding.");
-  return 0; /* hope we'll be ok */
-#endif
-
-  if (getrlimit(RLIMIT_NOFILE, &rlim) != 0) {
-    log_fn(LOG_WARN, "Could not get maximum number of file descriptors: %s",
-           strerror(errno));
-    return -1;
-  }
-  if(required_min > rlim.rlim_max) {
-    log_fn(LOG_WARN,"We need %d file descriptors available, and we're limited to %d. Please change your ulimit.", required_min, (int)rlim.rlim_max);
-    return -1;
-  }
-  if(required_min > rlim.rlim_cur) {
-    log_fn(LOG_INFO,"Raising max file descriptors from %d to %d.",
-           (int)rlim.rlim_cur, (int)rlim.rlim_max);
-  }
-  rlim.rlim_cur = rlim.rlim_max;
-  if (setrlimit(RLIMIT_NOFILE, &rlim) != 0) {
-    log_fn(LOG_WARN, "Could not set maximum number of file descriptors: %s",
-           strerror(errno));
-    return -1;
-  }
-  return 0;
-}
-
-/** Call setuid and setgid to run as <b>user</b>:<b>group</b>.  Return 0 on
- * success.  On failure, log and return -1.
- */
-int switch_id(char *user, char *group) {
-#ifndef MS_WINDOWS
-  struct passwd *pw = NULL;
-  struct group *gr = NULL;
-
-  if (user) {
-    pw = getpwnam(user);
-    if (pw == NULL) {
-      log_fn(LOG_ERR,"User '%s' not found.", user);
-      return -1;
-    }
-  }
-
-  /* switch the group first, while we still have the privileges to do so */
-  if (group) {
-    gr = getgrnam(group);
-    if (gr == NULL) {
-      log_fn(LOG_ERR,"Group '%s' not found.", group);
-      return -1;
-    }
-
-    if (setgid(gr->gr_gid) != 0) {
-      log_fn(LOG_ERR,"Error setting GID: %s", strerror(errno));
-      return -1;
-    }
-  } else if (user) {
-    if (setgid(pw->pw_gid) != 0) {
-      log_fn(LOG_ERR,"Error setting GID: %s", strerror(errno));
-      return -1;
-    }
-  }
-
-  /* now that the group is switched, we can switch users and lose
-     privileges */
-  if (user) {
-    if (setuid(pw->pw_uid) != 0) {
-      log_fn(LOG_ERR,"Error setting UID: %s", strerror(errno));
-      return -1;
-    }
-  }
-
-  return 0;
-#endif
-
-  log_fn(LOG_ERR,
-         "User or group specified, but switching users is not supported.");
-
-  return -1;
-}
-
-/** Set *addr to the IP address (in dotted-quad notation) stored in c.
- * Return 1 on success, 0 if c is badly formatted.  (Like inet_aton(c,addr),
- * but works on Windows and Solaris.)
- */
-int tor_inet_aton(const char *c, struct in_addr* addr)
-{
-#ifdef HAVE_INET_ATON
-  return inet_aton(c, addr);
-#else
-  uint32_t r;
-  tor_assert(c);
-  tor_assert(addr);
-  if (strcmp(c, "255.255.255.255") == 0) {
-    addr->s_addr = 0xFFFFFFFFu;
-    return 1;
-  }
-  r = inet_addr(c);
-  if (r == INADDR_NONE)
-    return 0;
-  addr->s_addr = r;
-  return 1;
-#endif
-}
-
-/** Similar behavior to Unix gethostbyname: resolve <b>name</b>, and set
- * *addr to the proper IP address, in network byte order.  Returns 0
- * on success, -1 on failure; 1 on transient failure.
- *
- * (This function exists because standard windows gethostbyname
- * doesn't treat raw IP addresses properly.)
- */
-int tor_lookup_hostname(const char *name, uint32_t *addr)
+int tor_lookup_hostname(const char *name, uint32_t *addr)
 {
   /* Perhaps eventually this should be replaced by a tor_getaddrinfo or
    * something.
@@ -2285,204 +1168,128 @@ parse_addr_and_port_range(const char *s, uint32_t *addr_out,
   return -1;
 }
 
-/** Extract a long from the start of s, in the given numeric base.  If
- * there is unconverted data and next is provided, set *next to the
- * first unconverted character.  An error has occurred if no characters
- * are converted; or if there are unconverted characters and next is NULL; or
- * if the parsed value is not between min and max.  When no error occurs,
- * return the parsed value and set *ok (if provided) to 1.  When an error
- * ocurs, return 0 and set *ok (if provided) to 0.
+/* =====
+ * Process helpers
+ * ===== */
+
+#ifndef MS_WINDOWS
+/* Based on code contributed by christian grothoff */
+static int start_daemon_called = 0;
+static int finish_daemon_called = 0;
+static int daemon_filedes[2];
+/** Start putting the process into daemon mode: fork and drop all resources
+ * except standard fds.  The parent process never returns, but stays around
+ * until finish_daemon is called.  (Note: it's safe to call this more
+ * than once: calls after the first are ignored.)
  */
-long
-tor_parse_long(const char *s, int base, long min, long max,
-               int *ok, char **next)
+void start_daemon(const char *desired_cwd)
 {
-  char *endptr;
-  long r;
-
-  r = strtol(s, &endptr, base);
-  /* Was at least one character converted? */
-  if (endptr == s)
-    goto err;
-  /* Were there unexpected unconverted characters? */
-  if (!next && *endptr)
-    goto err;
-  /* Is r within limits? */
-  if (r < min || r > max)
-    goto err;
+  pid_t pid;
 
-  if (ok) *ok = 1;
-  if (next) *next = endptr;
-  return r;
- err:
-  if (ok) *ok = 0;
-  if (next) *next = endptr;
-  return 0;
-}
+  if (start_daemon_called)
+    return;
+  start_daemon_called = 1;
 
-unsigned long
-tor_parse_ulong(const char *s, int base, unsigned long min,
-                unsigned long max, int *ok, char **next)
-{
-  char *endptr;
-  unsigned long r;
+  if(!desired_cwd)
+    desired_cwd = "/";
+   /* Don't hold the wrong FS mounted */
+  if (chdir(desired_cwd) < 0) {
+    log_fn(LOG_ERR,"chdir to %s failed. Exiting.",desired_cwd);
+    exit(1);
+  }
 
-  r = strtol(s, &endptr, base);
-  /* Was at least one character converted? */
-  if (endptr == s)
-    goto err;
-  /* Were there unexpected unconverted characters? */
-  if (!next && *endptr)
-    goto err;
-  /* Is r within limits? */
-  if (r < min || r > max)
-    goto err;
+  pipe(daemon_filedes);
+  pid = fork();
+  if (pid < 0) {
+    log_fn(LOG_ERR,"fork failed. Exiting.");
+    exit(1);
+  }
+  if (pid) {  /* Parent */
+    int ok;
+    char c;
 
-  if (ok) *ok = 1;
-  if (next) *next = endptr;
-  return r;
- err:
-  if (ok) *ok = 0;
-  if (next) *next = endptr;
-  return 0;
-}
+    close(daemon_filedes[1]); /* we only read */
+    ok = -1;
+    while (0 < read(daemon_filedes[0], &c, sizeof(char))) {
+      if (c == '.')
+        ok = 1;
+    }
+    fflush(stdout);
+    if (ok == 1)
+      exit(0);
+    else
+      exit(1); /* child reported error */
+  } else { /* Child */
+    close(daemon_filedes[0]); /* we only write */
 
-/** Replacement for snprintf.  Differs from platform snprintf in two
- * ways: First, always NUL-terminates its output.  Second, always
- * returns -1 if the result is truncated.  (Note that this return
- * behavior does <i>not</i> conform to C99; it just happens to be the
- * easiest to emulate "return -1" with conformant implementations than
- * it is to emulate "return number that would be written" with
- * non-conformant implementations.) */
-int tor_snprintf(char *str, size_t size, const char *format, ...)
-{
-  va_list ap;
-  int r;
-  va_start(ap,format);
-  r = tor_vsnprintf(str,size,format,ap);
-  va_end(ap);
-  return r;
+    pid = setsid(); /* Detach from controlling terminal */
+    /*
+     * Fork one more time, so the parent (the session group leader) can exit.
+     * This means that we, as a non-session group leader, can never regain a
+     * controlling terminal.   This part is recommended by Stevens's
+     * _Advanced Programming in the Unix Environment_.
+     */
+    if (fork() != 0) {
+      exit(0);
+    }
+    return;
+  }
 }
 
-/** Replacement for vsnpritnf; behavior differs as tor_snprintf differs from
- * snprintf.
+/** Finish putting the process into daemon mode: drop standard fds, and tell
+ * the parent process to exit.  (Note: it's safe to call this more than once:
+ * calls after the first are ignored.  Calls start_daemon first if it hasn't
+ * been called already.)
  */
-int tor_vsnprintf(char *str, size_t size, const char *format, va_list args)
+void finish_daemon(void)
 {
-  int r;
-#ifdef MS_WINDOWS
-  r = _vsnprintf(str, size, format, args);
-#else
-  r = vsnprintf(str, size, format, args);
-#endif
-  str[size-1] = '\0';
-  if (r < 0 || ((size_t)r) >= size)
-    return -1;
-  return r;
-}
-
+  int nullfd;
+  char c = '.';
+  if (finish_daemon_called)
+    return;
+  if (!start_daemon_called)
+    start_daemon(NULL);
+  finish_daemon_called = 1;
 
-#ifndef MS_WINDOWS
-struct tor_mutex_t {
-};
-tor_mutex_t *tor_mutex_new(void) { return NULL; }
-void tor_mutex_acquire(tor_mutex_t *m) { }
-void tor_mutex_release(tor_mutex_t *m) { }
-void tor_mutex_free(tor_mutex_t *m) { }
-#else
-struct tor_mutex_t {
-  HANDLE handle;
-};
-tor_mutex_t *tor_mutex_new(void)
-{
-  tor_mutex_t *m;
-  m = tor_malloc_zero(sizeof(tor_mutex_t));
-  m->handle = CreateMutex(NULL, FALSE, NULL);
-  tor_assert(m->handle != NULL);
-  return m;
-}
-void tor_mutex_free(tor_mutex_t *m)
-{
-  CloseHandle(m->handle);
-  tor_free(m);
-}
-void tor_mutex_acquire(tor_mutex_t *m)
-{
-  DWORD r;
-  r = WaitForSingleObject(m->handle, INFINITE);
-  switch (r) {
-    case WAIT_ABANDONED: /* holding thread exited. */
-        case WAIT_OBJECT_0: /* we got the mutex normally. */
-      break;
-    case WAIT_TIMEOUT: /* Should never happen. */
-          tor_assert(0);
-      break;
-        case WAIT_FAILED:
-      log_fn(LOG_WARN, "Failed to acquire mutex: %d", GetLastError());
+  nullfd = open("/dev/null",
+                O_CREAT | O_RDWR | O_APPEND);
+  if (nullfd < 0) {
+    log_fn(LOG_ERR,"/dev/null can't be opened. Exiting.");
+    exit(1);
   }
-}
-void tor_mutex_release(tor_mutex_t *m)
-{
-  BOOL r;
-  r = ReleaseMutex(m->handle);
-  if (!r) {
-    log_fn(LOG_WARN, "Failed to release mutex: %d", GetLastError());
+  /* close fds linking to invoking terminal, but
+   * close usual incoming fds, but redirect them somewhere
+   * useful so the fds don't get reallocated elsewhere.
+   */
+  if (dup2(nullfd,0) < 0 ||
+      dup2(nullfd,1) < 0 ||
+      dup2(nullfd,2) < 0) {
+    log_fn(LOG_ERR,"dup2 failed. Exiting.");
+    exit(1);
   }
+  write(daemon_filedes[1], &c, sizeof(char)); /* signal success */
+  close(daemon_filedes[1]);
 }
+#else
+/* defined(MS_WINDOWS) */
+void start_daemon(const char *cp) {}
+void finish_daemon(void) {}
 #endif
 
-void base16_encode(char *dest, size_t destlen, const char *src, size_t srclen)
-{
-  const char *end;
-  char *cp;
-
-  tor_assert(destlen >= srclen*2+1);
-
-  cp = dest;
-  end = src+srclen;
-  while (src<end) {
-    sprintf(cp,"%02X",*(const uint8_t*)src);
-    ++src;
-    cp += 2;
-  }
-  *cp = '\0';
-}
-
-static const char HEX_DIGITS[] = "0123456789ABCDEFabcdef";
-
-static INLINE int hex_decode_digit(char c)
-{
-  const char *cp;
-  int n;
-  cp = strchr(HEX_DIGITS, c);
-  if (!cp)
-    return -1;
-  n = cp-HEX_DIGITS;
-  if (n<=15)
-    return n; /* digit or uppercase */
-  else
-    return n-6; /* lowercase */
-}
+/** Write the current process ID, followed by NL, into <b>filename</b>.
+ */
+void write_pidfile(char *filename) {
+#ifndef MS_WINDOWS
+  FILE *pidfile;
 
-int base16_decode(char *dest, size_t destlen, const char *src, size_t srclen)
-{
-  const char *end;
-  int v1,v2;
-  if ((srclen % 2) != 0)
-    return -1;
-  if (destlen < srclen/2)
-    return -1;
-  end = src+srclen;
-  while (src<end) {
-    v1 = hex_decode_digit(*src);
-    v2 = hex_decode_digit(*(src+1));
-    if(v1<0||v2<0)
-      return -1;
-    *(uint8_t*)dest = (v1<<4)|v2;
-    ++dest;
-    src+=2;
+  if ((pidfile = fopen(filename, "w")) == NULL) {
+    log_fn(LOG_WARN, "Unable to open %s for writing: %s", filename,
+           strerror(errno));
+  } else {
+    fprintf(pidfile, "%d\n", (int)getpid());
+    fclose(pidfile);
   }
-  return 0;
+#endif
 }
 
 /*
index 4fd31612a507e8e8c04c5aa508626ddce279a650..2c47a46cc33dddb8522f6160ad9f042c2c4b4db3 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright 2003 Roger Dingledine */
+/* Copyright 2003-2004 Roger Dingledine; Copyright 2004 Nick Mathewson */
 /* See LICENSE for licensing information */
 /* $Id$ */
 
@@ -13,7 +13,7 @@
 #include "orconfig.h"
 #include "torint.h"
 #include <stdio.h>
-#include <stdarg.h>
+#include <assert.h>
 #ifdef HAVE_SYS_TIME_H
 #include <sys/time.h>
 #endif
 #include <time.h>
 #endif
 
-#ifndef NULL_REP_IS_ZERO_BYTES
-#error "It seems your platform does not represent NULL as zero. We can't cope."
-#endif
-
-#ifdef MS_WINDOWS
-#if (_MSC_VER <= 1300)
-#include <winsock.h>
-#else
-#include <winsock2.h>
-#include <ws2tcpip.h>
-#endif
-#endif
-
-#if !defined(HAVE_GETTIMEOFDAY) && !defined(HAVE_STRUCT_TIMEVAL_TV_SEC)
-struct timeval {
-  time_t tv_sec;
-  unsigned int tv_usec;
-};
-#endif
-
-#ifdef MS_WINDOWS
-/* Windows names string functions differently from most other platforms. */
-#define strncasecmp strnicmp
-#define strcasecmp stricmp
-/* "inline" is __inline on windows. " */
-#define INLINE __inline
-/* Windows compilers before VC7 don't have __FUNCTION__. */
-#if _MSC_VER < 1300
-#define __FUNCTION__ "???"
-#endif
-#else
-#define INLINE inline
-#endif
-
 /** Replace assert() with a variant that sends failures to the log before
  * calling assert() normally.
  */
@@ -70,29 +36,19 @@ struct timeval {
  } } while (0)
 #endif
 
-#ifdef MS_WINDOWS
-/** 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.
- */
-#define tor_close_socket(s) closesocket(s)
-#else
-#define tor_close_socket(s) close(s)
-#endif
-
-#define HEX_CHARACTERS "0123456789ABCDEFabcdef"
-
-size_t strlcat(char *dst, const char *src, size_t siz);
-size_t strlcpy(char *dst, const char *src, size_t siz);
-
+/* Memory management */
 void *tor_malloc(size_t size);
 void *tor_malloc_zero(size_t size);
 void *tor_realloc(void *ptr, size_t size);
 char *tor_strdup(const char *s);
 char *tor_strndup(const char *s, size_t n);
 #define tor_free(p) do {if(p) {free(p); (p)=NULL;}} while(0)
+
+/* String manipulation */
+#define HEX_CHARACTERS "0123456789ABCDEFabcdef"
+size_t strlcat(char *dst, const char *src, size_t siz);
+size_t strlcpy(char *dst, const char *src, size_t siz);
+
 void tor_strlower(char *s);
 int strcmpstart(const char *s1, const char *s2);
 int tor_strstrip(char *s, const char *strip);
@@ -106,106 +62,13 @@ long tor_parse_long(const char *s, int base, long min,
                     long max, int *ok, char **next);
 unsigned long tor_parse_ulong(const char *s, int base, unsigned long min,
                               unsigned long max, int *ok, char **next);
-
-/* XXXX duplicated from log.h */
-#ifdef __GNUC__
-#define CHECK_PRINTF(formatIdx, firstArg) \
-   __attribute__ ((format (printf, formatIdx, firstArg)))
-#else
-#define CHECK_PRINTF(formatIdx, firstArg)
-#endif
-
-int tor_snprintf(char *str, size_t size, const char *format, ...)
-     CHECK_PRINTF(3,4);
-int tor_vsnprintf(char *str, size_t size, const char *format, va_list args);
-     
-/* Some platforms segfault when you try to access a multi-byte type
- * that isn't aligned to a word boundary.  The macros and/or functions
- * below can be used to access unaligned data on any platform.
- */
-#ifdef UNALIGNED_INT_ACCESS_OK
-#define get_uint16(cp) (*(uint16_t*)(cp))
-#define get_uint32(cp) (*(uint32_t*)(cp))
-#define set_uint16(cp,v) do { *(uint16_t*)(cp) = (v); } while (0)
-#define set_uint32(cp,v) do { *(uint32_t*)(cp) = (v); } while (0)
-#else
-uint16_t get_uint16(const char *cp);
-uint32_t get_uint32(const char *cp);
-void set_uint16(char *cp, uint16_t v);
-void set_uint32(char *cp, uint32_t v);
-#endif
-
 const char *hex_str(const char *from, size_t fromlen);
-
-/** Generic resizeable array. */
-typedef struct smartlist_t smartlist_t;
-
-smartlist_t *smartlist_create(void);
-void smartlist_free(smartlist_t *sl);
-void smartlist_set_capacity(smartlist_t *sl, int n);
-void smartlist_clear(smartlist_t *sl);
-void smartlist_truncate(smartlist_t *sl, int n);
-void smartlist_add(smartlist_t *sl, void *element);
-void smartlist_add_all(smartlist_t *sl, const smartlist_t *s2);
-void smartlist_remove(smartlist_t *sl, void *element);
-int smartlist_isin(const smartlist_t *sl, void *element);
-int smartlist_string_isin(const smartlist_t *sl, const char *element);
-int smartlist_overlap(const smartlist_t *sl1, const smartlist_t *sl2);
-void smartlist_intersect(smartlist_t *sl1, const smartlist_t *sl2);
-void smartlist_subtract(smartlist_t *sl1, const smartlist_t *sl2);
-void *smartlist_choose(const smartlist_t *sl);
-void *smartlist_get(const smartlist_t *sl, int idx);
-void *smartlist_set(smartlist_t *sl, int idx, void *val);
-void *smartlist_del(smartlist_t *sl, int idx);
-void *smartlist_del_keeporder(smartlist_t *sl, int idx);
-void smartlist_insert(smartlist_t *sl, int idx, void *val);
-int smartlist_len(const smartlist_t *sl);
-#define SPLIT_SKIP_SPACE   0x01
-#define SPLIT_IGNORE_BLANK 0x02
-int smartlist_split_string(smartlist_t *sl, const char *str, const char *sep,
-                           int flags, int max);
-char *smartlist_join_strings(smartlist_t *sl, const char *join, int terminate);
-
-#define SMARTLIST_FOREACH(sl, type, var, cmd)                   \
-  do {                                                          \
-    int var ## _sl_idx, var ## _sl_len=smartlist_len(sl);       \
-    type var;                                                   \
-    for(var ## _sl_idx = 0; var ## _sl_idx < var ## _sl_len;    \
-        ++var ## _sl_idx) {                                     \
-      var = smartlist_get((sl),var ## _sl_idx);                 \
-      cmd;                                                      \
-    } } while (0)
-
-/* Map from const char * to void*. Implemented with a splay tree. */
-typedef struct strmap_t strmap_t;
-typedef struct strmap_entry_t strmap_entry_t;
-typedef struct strmap_entry_t strmap_iter_t;
-strmap_t* strmap_new(void);
-void* strmap_set(strmap_t *map, const char *key, void *val);
-void* strmap_get(strmap_t *map, const char *key);
-void* strmap_remove(strmap_t *map, const char *key);
-void* strmap_set_lc(strmap_t *map, const char *key, void *val);
-void* strmap_get_lc(strmap_t *map, const char *key);
-void* strmap_remove_lc(strmap_t *map, const char *key);
-typedef void* (*strmap_foreach_fn)(const char *key, void *val, void *data);
-void strmap_foreach(strmap_t *map, strmap_foreach_fn fn, void *data);
-void strmap_free(strmap_t *map, void (*free_val)(void*));
-int strmap_isempty(strmap_t *map);
-
-strmap_iter_t *strmap_iter_init(strmap_t *map);
-strmap_iter_t *strmap_iter_next(strmap_t *map, strmap_iter_t *iter);
-strmap_iter_t *strmap_iter_next_rmv(strmap_t *map, strmap_iter_t *iter);
-void strmap_iter_get(strmap_iter_t *iter, const char **keyp, void **valp);
-
-int strmap_iter_done(strmap_iter_t *iter);
-
-/* String manipulation */
 const char *eat_whitespace(const char *s);
 const char *eat_whitespace_no_nl(const char *s);
 const char *find_whitespace(const char *s);
 
+
 /* Time helpers */
-void tor_gettimeofday(struct timeval *timeval);
 long tv_udiff(struct timeval *start, struct timeval *end);
 void tv_addms(struct timeval *a, long ms);
 void tv_add(struct timeval *a, struct timeval *b);
@@ -218,92 +81,35 @@ int parse_rfc1123_time(const char *buf, time_t *t);
 void format_iso_time(char *buf, time_t t);
 int parse_iso_time(const char *buf, time_t *t);
 
+/* File helpers */
 int write_all(int fd, const char *buf, size_t count, int isSocket);
 int read_all(int fd, char *buf, size_t count, int isSocket);
 
-void set_socket_nonblocking(int socket);
-
 typedef enum { FN_ERROR, FN_NOENT, FN_FILE, FN_DIR} file_status_t;
-
 file_status_t file_status(const char *filename);
+
 int check_private_dir(const char *dirname, int create);
 int write_str_to_file(const char *fname, const char *str, int bin);
 char *read_file_to_str(const char *filename, int bin);
 int parse_line_from_file(char *line, size_t maxlen, FILE *f, char **key_out, char **value_out);
 char *expand_filename(const char *filename);
-int replace_file(const char *from, const char *to);
-
-int spawn_func(int (*func)(void *), void *data);
-void spawn_exit(void);
-
-/* Because we use threads instead of processes on Windows, we need locking on Windows.
- * On Unixy platforms, these functions are no-ops. */
-typedef struct tor_mutex_t tor_mutex_t;
-tor_mutex_t *tor_mutex_new(void);
-void tor_mutex_acquire(tor_mutex_t *m);
-void tor_mutex_release(tor_mutex_t *m);
-void tor_mutex_free(tor_mutex_t *m);
-
-int tor_socketpair(int family, int type, int protocol, int fd[2]);
 
+/* Net helpers */
 int is_internal_IP(uint32_t ip);
 int is_local_IP(uint32_t ip);
-
-const char *get_uname(void);
-
-void start_daemon(const char *desired_cwd);
-void finish_daemon(void);
-
-void write_pidfile(char *filename);
-int set_max_file_descriptors(int required_min);
-int switch_id(char *user, char *group);
-
-struct in_addr;
-int tor_inet_aton(const char *cp, struct in_addr *addr);
 int tor_lookup_hostname(const char *name, uint32_t *addr);
 int parse_addr_port(const char *addrport, char **address, uint32_t *addr,
                     uint16_t *port);
-
 int parse_addr_and_port_range(const char *s, uint32_t *addr_out,
                               uint32_t *mask_out, uint16_t *port_min_out,
                               uint16_t *port_max_out);
 
-/* For stupid historical reasons, windows sockets have an independent
- * set of errnos, and an independent way to get them.  Also, you can't
- * always believe WSAEWOULDBLOCK.  Use the macros below to compare
- * errnos against expected values, and use tor_socket_errno to find
- * the actual errno after a socket operation fails.
- */
-#ifdef MS_WINDOWS
-/** Return true if e is EAGAIN or the local equivalent. */
-#define ERRNO_IS_EAGAIN(e)           ((e) == EAGAIN || (e) == WSAEWOULDBLOCK)
-/** Return true if e is EINPROGRESS or the local equivalent. */
-#define ERRNO_IS_EINPROGRESS(e)      ((e) == WSAEINPROGRESS)
-/** Return true if e is EINPROGRESS or the local equivalent as returned by
- * a call to connect(). */
-#define ERRNO_IS_CONN_EINPROGRESS(e) ((e) == WSAEINPROGRESS || (e)== WSAEINVAL)
-/** Return true if e is EAGAIN or another error indicating that a call to
- * accept() has no pending connections to return. */
-#define ERRNO_IS_ACCEPT_EAGAIN(e)    ERRNO_IS_EAGAIN(e)
-/** Return true if e is EMFILE or another error indicating that a call to
- * accept() has failed because we're out of fds or something. */
-#define ERRNO_IS_ACCEPT_RESOURCE_LIMIT(e) \
-  ((e) == WSAEMFILE || (e) == WSAENOBUFS)
-int tor_socket_errno(int sock);
-const char *tor_socket_strerror(int e);
-#else
-#define ERRNO_IS_EAGAIN(e)           ((e) == EAGAIN)
-#define ERRNO_IS_EINPROGRESS(e)      ((e) == EINPROGRESS)
-#define ERRNO_IS_CONN_EINPROGRESS(e) ((e) == EINPROGRESS)
-#define ERRNO_IS_ACCEPT_EAGAIN(e)    ((e) == EAGAIN || (e) == ECONNABORTED)
-#define ERRNO_IS_ACCEPT_RESOURCE_LIMIT(e) \
-  ((e) == EMFILE || (e) == ENFILE || (e) == ENOBUFS || (e) == ENOMEM)
-#define tor_socket_errno(sock)       (errno)
-#define tor_socket_strerror(e)       strerror(e)
-#endif
+/* Process helpers */
+void start_daemon(const char *desired_cwd);
+void finish_daemon(void);
+void write_pidfile(char *filename);
 
 #endif
-
 /*
   Local Variables:
   mode:c
index 43a18c8c6bf181982d811972750ac4195fee64ac..cf03e955dc7f308be58f0176137a87410761f6f6 100644 (file)
 #include "../common/crypto.h"
 #include "../common/tortls.h"
 #include "../common/log.h"
+#include "../common/compat.h"
+#include "../common/container.h"
 #include "../common/util.h"
 #include "../common/torgzip.h"
 
index 67dd0dff722494c1e607b14ff34a40b83af811a0..724973874379e522451d63712de1f8a994c81b92 100644 (file)
@@ -4,6 +4,7 @@
 
 #include "orconfig.h"
 
+#include "../common/compat.h"
 #include "../common/util.h"
 #include "../common/log.h"