diff options
author | Nick Mathewson <nickm@torproject.org> | 2004-11-01 20:41:47 +0000 |
---|---|---|
committer | Nick Mathewson <nickm@torproject.org> | 2004-11-01 20:41:47 +0000 |
commit | ce79bab7f1880136eb511195eb670c1cc06cbc69 (patch) | |
tree | dcf553311e269d3c4586b5caa8b47548ea903654 /src | |
parent | fae20c21bfa1afa5ab604d1c21597e22cdad3122 (diff) | |
download | tor-ce79bab7f1880136eb511195eb670c1cc06cbc69.tar tor-ce79bab7f1880136eb511195eb670c1cc06cbc69.tar.gz |
Split util into util (general utilities), container (smartlist and strmap), and compat (cross-platform compatability).
svn:r2640
Diffstat (limited to 'src')
-rw-r--r-- | src/common/Makefile.am | 4 | ||||
-rw-r--r-- | src/common/compat.c | 660 | ||||
-rw-r--r-- | src/common/compat.h | 168 | ||||
-rw-r--r-- | src/common/container.c | 612 | ||||
-rw-r--r-- | src/common/container.h | 78 | ||||
-rw-r--r-- | src/common/crypto.c | 1 | ||||
-rw-r--r-- | src/common/log.h | 10 | ||||
-rw-r--r-- | src/common/util.c | 1665 | ||||
-rw-r--r-- | src/common/util.h | 228 | ||||
-rw-r--r-- | src/or/or.h | 2 | ||||
-rw-r--r-- | src/tools/tor-resolve.c | 1 |
11 files changed, 1779 insertions, 1650 deletions
diff --git a/src/common/Makefile.am b/src/common/Makefile.am index c07f08355..65f722bfe 100644 --- a/src/common/Makefile.am +++ b/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 diff --git a/src/common/compat.c b/src/common/compat.c new file mode 100644 index 000000000..5b4c93110 --- /dev/null +++ b/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: +*/ diff --git a/src/common/compat.h b/src/common/compat.h new file mode 100644 index 000000000..afc8af41f --- /dev/null +++ b/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: +*/ diff --git a/src/common/container.c b/src/common/container.c new file mode 100644 index 000000000..8eea7438a --- /dev/null +++ b/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>&SPLIT_SKIP_SPACE is true, remove initial and + * trailing space from each entry. If + * <b>flags</b>&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 index 000000000..7569cb349 --- /dev/null +++ b/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: +*/ + diff --git a/src/common/crypto.c b/src/common/crypto.c index e63a92c99..cff4242e2 100644 --- a/src/common/crypto.c +++ b/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" diff --git a/src/common/log.h b/src/common/log.h index 0e458142f..55dabafaa 100644 --- a/src/common/log.h +++ b/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); diff --git a/src/common/util.c b/src/common/util.c index 06ad5d91f..45639e342 100644 --- a/src/common/util.c +++ b/src/common/util.c @@ -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. @@ -15,16 +15,8 @@ #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> @@ -35,23 +27,11 @@ #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 @@ -102,12 +76,6 @@ #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 @@ -129,6 +97,10 @@ #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>&SPLIT_SKIP_SPACE is true, remove initial and - * trailing space from each entry. If - * <b>flags</b>&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,32 +329,127 @@ const char *find_whitespace(const char *s) { return s; } -/* - * Time +/** 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 +tor_parse_long(const char *s, int base, long min, long max, + int *ok, char **next) +{ + char *endptr; + long r; -/** 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); + 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; } -#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; + *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. */ @@ -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,265 +970,6 @@ 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.) - */ -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. @@ -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 } /* diff --git a/src/common/util.h b/src/common/util.h index 4fd31612a..2c47a46cc 100644 --- a/src/common/util.h +++ b/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 diff --git a/src/or/or.h b/src/or/or.h index 43a18c8c6..cf03e955d 100644 --- a/src/or/or.h +++ b/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" diff --git a/src/tools/tor-resolve.c b/src/tools/tor-resolve.c index 67dd0dff7..724973874 100644 --- a/src/tools/tor-resolve.c +++ b/src/tools/tor-resolve.c @@ -4,6 +4,7 @@ #include "orconfig.h" +#include "../common/compat.h" #include "../common/util.h" #include "../common/log.h" |