Browse Source

Split util into util (general utilities), container (smartlist and strmap), and compat (cross-platform compatability).

svn:r2640
Nick Mathewson 19 years ago
parent
commit
ce79bab7f1
11 changed files with 1692 additions and 1206 deletions
  1. 2 2
      src/common/Makefile.am
  2. 660 0
      src/common/compat.c
  3. 168 0
      src/common/compat.h
  4. 612 0
      src/common/container.c
  5. 78 0
      src/common/container.h
  6. 1 0
      src/common/crypto.c
  7. 2 8
      src/common/log.h
  8. 149 985
      src/common/util.c
  9. 17 211
      src/common/util.h
  10. 2 0
      src/or/or.h
  11. 1 0
      src/tools/tor-resolve.c

+ 2 - 2
src/common/Makefile.am

@@ -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

+ 660 - 0
src/common/compat.c

@@ -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:
+*/

+ 168 - 0
src/common/compat.h

@@ -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:
+*/

+ 612 - 0
src/common/container.c

@@ -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:
+*/

+ 78 - 0
src/common/container.h

@@ -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:
+*/
+

+ 1 - 0
src/common/crypto.c

@@ -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"

+ 2 - 8
src/common/log.h

@@ -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
@@ -51,14 +53,6 @@
 #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);

File diff suppressed because it is too large
+ 149 - 985
src/common/util.c


+ 17 - 211
src/common/util.h

@@ -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
@@ -21,40 +21,6 @@
 #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

+ 2 - 0
src/or/or.h

@@ -116,6 +116,8 @@
 #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"
 

+ 1 - 0
src/tools/tor-resolve.c

@@ -4,6 +4,7 @@
 
 #include "orconfig.h"
 
+#include "../common/compat.h"
 #include "../common/util.h"
 #include "../common/log.h"
 

Some files were not shown because too many files changed in this diff