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

svn:r2640
This commit is contained in:
Nick Mathewson 2004-11-01 20:41:47 +00:00
parent fae20c21bf
commit ce79bab7f1
11 changed files with 1792 additions and 1663 deletions

View File

@ -3,7 +3,7 @@ noinst_LIBRARIES = libor.a libor-crypto.a
#CFLAGS = -Wall -Wpointer-arith -O2 #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 libor_crypto_a_SOURCES = crypto.c aes.c tortls.c torgzip.c
noinst_HEADERS = log.h crypto.h fakepoll.h test.h util.h aes.h torint.h tortls.h strlcpy.c strlcat.c torgzip.h noinst_HEADERS = log.h crypto.h fakepoll.h test.h util.h compat.h aes.h torint.h tortls.h strlcpy.c strlcat.c torgzip.h container.h

660
src/common/compat.c Normal file
View File

@ -0,0 +1,660 @@
/* Copyright 2003-2004 Roger Dingledine; Copyright 2004 Nick Mathewson */
/* See LICENSE for licensing information */
/* $Id$ */
/* This is required on rh7 to make strptime not complain.
*/
#define _GNU_SOURCE
#include "orconfig.h"
#ifdef MS_WINDOWS
#include <io.h>
#include <process.h>
#include <direct.h>
#include <windows.h>
#endif
#ifdef HAVE_UNAME
#include <sys/utsname.h>
#endif
#ifdef HAVE_SYS_TIME_H
#include <sys/time.h>
#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#ifdef HAVE_SYS_FCNTL_H
#include <sys/fcntl.h>
#endif
#ifdef HAVE_PWD_H
#include <pwd.h>
#endif
#ifdef HAVE_GRP_H
#include <grp.h>
#endif
#ifdef HAVE_FCNTL_H
#include <fcntl.h>
#endif
#ifdef HAVE_SYS_RESOURCE_H
#include <sys/resource.h>
#endif
#ifdef HAVE_ERRNO_H
#include <errno.h>
#endif
#ifdef HAVE_NETINET_IN_H
#include <netinet/in.h>
#endif
#ifdef HAVE_ARPA_INET_H
#include <arpa/inet.h>
#endif
#ifndef HAVE_GETTIMEOFDAY
#ifdef HAVE_FTIME
#include <sys/timeb.h>
#endif
#endif
#ifdef HAVE_SYS_SOCKET_H
#include <sys/socket.h>
#endif
#ifdef HAVE_SYS_PARAM_H
#include <sys/param.h> /* FreeBSD needs this to know what version it is */
#endif
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "compat.h"
#include "log.h"
#include "util.h"
/** Replacement for snprintf. Differs from platform snprintf in two
* ways: First, always NUL-terminates its output. Second, always
* returns -1 if the result is truncated. (Note that this return
* behavior does <i>not</i> conform to C99; it just happens to be the
* easiest to emulate "return -1" with conformant implementations than
* it is to emulate "return number that would be written" with
* non-conformant implementations.) */
int tor_snprintf(char *str, size_t size, const char *format, ...)
{
va_list ap;
int r;
va_start(ap,format);
r = tor_vsnprintf(str,size,format,ap);
va_end(ap);
return r;
}
/** Replacement for vsnpritnf; behavior differs as tor_snprintf differs from
* snprintf.
*/
int tor_vsnprintf(char *str, size_t size, const char *format, va_list args)
{
int r;
#ifdef MS_WINDOWS
r = _vsnprintf(str, size, format, args);
#else
r = vsnprintf(str, size, format, args);
#endif
str[size-1] = '\0';
if (r < 0 || ((size_t)r) >= size)
return -1;
return r;
}
#ifndef UNALIGNED_INT_ACCESS_OK
/**
* Read a 16-bit value beginning at <b>cp</b>. Equaivalent to
* *(uint16_t*)(cp), but will not cause segfaults on platforms that forbid
* unaligned memory access.
*/
uint16_t get_uint16(const char *cp)
{
uint16_t v;
memcpy(&v,cp,2);
return v;
}
/**
* Read a 32-bit value beginning at <b>cp</b>. Equaivalent to
* *(uint32_t*)(cp), but will not cause segfaults on platforms that forbid
* unaligned memory access.
*/
uint32_t get_uint32(const char *cp)
{
uint32_t v;
memcpy(&v,cp,4);
return v;
}
/**
* Set a 16-bit value beginning at <b>cp</b> to <b>v</b>. Equivalent to
* *(uint16_t)(cp) = v, but will not cause segfaults on platforms that forbid
* unaligned memory access. */
void set_uint16(char *cp, uint16_t v)
{
memcpy(cp,&v,2);
}
/**
* Set a 32-bit value beginning at <b>cp</b> to <b>v</b>. Equivalent to
* *(uint32_t)(cp) = v, but will not cause segfaults on platforms that forbid
* unaligned memory access. */
void set_uint32(char *cp, uint32_t v)
{
memcpy(cp,&v,4);
}
#endif
/**
* Rename the file 'from' to the file 'to'. On unix, this is the same as
* rename(2). On windows, this removes 'to' first if it already exists.
* Returns 0 on success. Returns -1 and sets errno on failure.
*/
int replace_file(const char *from, const char *to)
{
#ifndef MS_WINDOWS
return rename(from,to);
#else
switch(file_status(to))
{
case FN_NOENT:
break;
case FN_FILE:
if (unlink(to)) return -1;
break;
case FN_ERROR:
return -1;
case FN_DIR:
errno = EISDIR;
return -1;
}
return rename(from,to);
#endif
}
/** Turn <b>socket</b> into a nonblocking socket.
*/
void set_socket_nonblocking(int socket)
{
#ifdef MS_WINDOWS
/* Yes means no and no means yes. Do you not want to be nonblocking? */
int nonblocking = 0;
ioctlsocket(socket, FIONBIO, (unsigned long*) &nonblocking);
#else
fcntl(socket, F_SETFL, O_NONBLOCK);
#endif
}
/**
* Allocate a pair of connected sockets. (Like socketpair(family,
* type,protocol,fd), but works on systems that don't have
* socketpair.)
*
* Currently, only (AF_UNIX, SOCK_STREAM, 0 ) sockets are supported.
*
* Note that on systems without socketpair, this call will fail if
* localhost is inaccessible (for example, if the networking
* stack is down). And even if it succeeds, the socket pair will not
* be able to read while localhost is down later (the socket pair may
* even close, depending on OS-specific timeouts).
**/
int
tor_socketpair(int family, int type, int protocol, int fd[2])
{
#ifdef HAVE_SOCKETPAIR
return socketpair(family, type, protocol, fd);
#else
/* This socketpair does not work when localhost is down. So
* it's really not the same thing at all. But it's close enough
* for now, and really, when localhost is down sometimes, we
* have other problems too.
*/
int listener = -1;
int connector = -1;
int acceptor = -1;
struct sockaddr_in listen_addr;
struct sockaddr_in connect_addr;
int size;
if (protocol
#ifdef AF_UNIX
|| family != AF_UNIX
#endif
) {
#ifdef MS_WINDOWS
errno = WSAEAFNOSUPPORT;
#else
errno = EAFNOSUPPORT;
#endif
return -1;
}
if (!fd) {
errno = EINVAL;
return -1;
}
listener = socket(AF_INET, type, 0);
if (listener == -1)
return -1;
memset (&listen_addr, 0, sizeof (listen_addr));
listen_addr.sin_family = AF_INET;
listen_addr.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
listen_addr.sin_port = 0; /* kernel choses port. */
if (bind(listener, (struct sockaddr *) &listen_addr, sizeof (listen_addr))
== -1)
goto tidy_up_and_fail;
if (listen(listener, 1) == -1)
goto tidy_up_and_fail;
connector = socket(AF_INET, type, 0);
if (connector == -1)
goto tidy_up_and_fail;
/* We want to find out the port number to connect to. */
size = sizeof (connect_addr);
if (getsockname(listener, (struct sockaddr *) &connect_addr, &size) == -1)
goto tidy_up_and_fail;
if (size != sizeof (connect_addr))
goto abort_tidy_up_and_fail;
if (connect(connector, (struct sockaddr *) &connect_addr,
sizeof (connect_addr)) == -1)
goto tidy_up_and_fail;
size = sizeof (listen_addr);
acceptor = accept(listener, (struct sockaddr *) &listen_addr, &size);
if (acceptor == -1)
goto tidy_up_and_fail;
if (size != sizeof(listen_addr))
goto abort_tidy_up_and_fail;
tor_close_socket(listener);
/* Now check we are talking to ourself by matching port and host on the
two sockets. */
if (getsockname(connector, (struct sockaddr *) &connect_addr, &size) == -1)
goto tidy_up_and_fail;
if (size != sizeof (connect_addr)
|| listen_addr.sin_family != connect_addr.sin_family
|| listen_addr.sin_addr.s_addr != connect_addr.sin_addr.s_addr
|| listen_addr.sin_port != connect_addr.sin_port) {
goto abort_tidy_up_and_fail;
}
fd[0] = connector;
fd[1] = acceptor;
return 0;
abort_tidy_up_and_fail:
#ifdef MS_WINDOWS
errno = WSAECONNABORTED;
#else
errno = ECONNABORTED; /* I hope this is portable and appropriate. */
#endif
tidy_up_and_fail:
{
int save_errno = errno;
if (listener != -1)
tor_close_socket(listener);
if (connector != -1)
tor_close_socket(connector);
if (acceptor != -1)
tor_close_socket(acceptor);
errno = save_errno;
return -1;
}
#endif
}
/** Get the maximum allowed number of file descriptors. (Some systems
* have a low soft limit.) Make sure we set it to at least
* <b>required_min</b>. Return 0 if we can, or -1 if we fail. */
int set_max_file_descriptors(int required_min) {
#ifndef HAVE_GETRLIMIT
log_fn(LOG_INFO,"This platform is missing getrlimit(). Proceeding.");
return 0; /* hope we'll be ok */
#else
struct rlimit rlim;
if (getrlimit(RLIMIT_NOFILE, &rlim) != 0) {
log_fn(LOG_WARN, "Could not get maximum number of file descriptors: %s",
strerror(errno));
return -1;
}
if(required_min > rlim.rlim_max) {
log_fn(LOG_WARN,"We need %d file descriptors available, and we're limited to %d. Please change your ulimit.", required_min, (int)rlim.rlim_max);
return -1;
}
if(required_min > rlim.rlim_cur) {
log_fn(LOG_INFO,"Raising max file descriptors from %d to %d.",
(int)rlim.rlim_cur, (int)rlim.rlim_max);
}
rlim.rlim_cur = rlim.rlim_max;
if (setrlimit(RLIMIT_NOFILE, &rlim) != 0) {
log_fn(LOG_WARN, "Could not set maximum number of file descriptors: %s",
strerror(errno));
return -1;
}
return 0;
#endif
}
/** Call setuid and setgid to run as <b>user</b>:<b>group</b>. Return 0 on
* success. On failure, log and return -1.
*/
int switch_id(char *user, char *group) {
#ifndef MS_WINDOWS
struct passwd *pw = NULL;
struct group *gr = NULL;
if (user) {
pw = getpwnam(user);
if (pw == NULL) {
log_fn(LOG_ERR,"User '%s' not found.", user);
return -1;
}
}
/* switch the group first, while we still have the privileges to do so */
if (group) {
gr = getgrnam(group);
if (gr == NULL) {
log_fn(LOG_ERR,"Group '%s' not found.", group);
return -1;
}
if (setgid(gr->gr_gid) != 0) {
log_fn(LOG_ERR,"Error setting GID: %s", strerror(errno));
return -1;
}
} else if (user) {
if (setgid(pw->pw_gid) != 0) {
log_fn(LOG_ERR,"Error setting GID: %s", strerror(errno));
return -1;
}
}
/* now that the group is switched, we can switch users and lose
privileges */
if (user) {
if (setuid(pw->pw_uid) != 0) {
log_fn(LOG_ERR,"Error setting UID: %s", strerror(errno));
return -1;
}
}
return 0;
#endif
log_fn(LOG_ERR,
"User or group specified, but switching users is not supported.");
return -1;
}
/** Set *addr to the IP address (in dotted-quad notation) stored in c.
* Return 1 on success, 0 if c is badly formatted. (Like inet_aton(c,addr),
* but works on Windows and Solaris.)
*/
int tor_inet_aton(const char *c, struct in_addr* addr)
{
#ifdef HAVE_INET_ATON
return inet_aton(c, addr);
#else
uint32_t r;
tor_assert(c);
tor_assert(addr);
if (strcmp(c, "255.255.255.255") == 0) {
addr->s_addr = 0xFFFFFFFFu;
return 1;
}
r = inet_addr(c);
if (r == INADDR_NONE)
return 0;
addr->s_addr = r;
return 1;
#endif
}
/* Hold the result of our call to <b>uname</b>. */
static char uname_result[256];
/* True iff uname_result is set. */
static int uname_result_is_set = 0;
/* Return a pointer to a description of our platform.
*/
const char *
get_uname(void)
{
#ifdef HAVE_UNAME
struct utsname u;
#endif
if (!uname_result_is_set) {
#ifdef HAVE_UNAME
if (uname(&u) != -1) {
/* (linux says 0 is success, solaris says 1 is success) */
tor_snprintf(uname_result, sizeof(uname_result), "%s %s %s",
u.sysname, u.nodename, u.machine);
} else
#endif
{
strlcpy(uname_result, "Unknown platform", sizeof(uname_result));
}
uname_result_is_set = 1;
}
return uname_result;
}
/*
* Process control
*/
/** Minimalist interface to run a void function in the background. On
* unix calls fork, on win32 calls beginthread. Returns -1 on failure.
* func should not return, but rather should call spawn_exit.
*/
int spawn_func(int (*func)(void *), void *data)
{
#ifdef MS_WINDOWS
int rv;
rv = _beginthread(func, 0, data);
if (rv == (unsigned long) -1)
return -1;
return 0;
#else
pid_t pid;
pid = fork();
if (pid<0)
return -1;
if (pid==0) {
/* Child */
func(data);
tor_assert(0); /* Should never reach here. */
return 0; /* suppress "control-reaches-end-of-non-void" warning. */
} else {
/* Parent */
return 0;
}
#endif
}
/** End the current thread/process.
*/
void spawn_exit()
{
#ifdef MS_WINDOWS
_endthread();
#else
exit(0);
#endif
}
/** Set *timeval to the current time of day. On error, log and terminate.
* (Same as gettimeofday(timeval,NULL), but never returns -1.)
*/
void tor_gettimeofday(struct timeval *timeval) {
#ifdef HAVE_GETTIMEOFDAY
if (gettimeofday(timeval, NULL)) {
log_fn(LOG_ERR, "gettimeofday failed.");
/* If gettimeofday dies, we have either given a bad timezone (we didn't),
or segfaulted.*/
exit(1);
}
#elif defined(HAVE_FTIME)
struct timeb tb;
ftime(&tb);
timeval->tv_sec = tb.time;
timeval->tv_usec = tb.millitm * 1000;
#else
#error "No way to get time."
#endif
return;
}
#ifndef MS_WINDOWS
struct tor_mutex_t {
};
tor_mutex_t *tor_mutex_new(void) { return NULL; }
void tor_mutex_acquire(tor_mutex_t *m) { }
void tor_mutex_release(tor_mutex_t *m) { }
void tor_mutex_free(tor_mutex_t *m) { }
#else
struct tor_mutex_t {
HANDLE handle;
};
tor_mutex_t *tor_mutex_new(void)
{
tor_mutex_t *m;
m = tor_malloc_zero(sizeof(tor_mutex_t));
m->handle = CreateMutex(NULL, FALSE, NULL);
tor_assert(m->handle != NULL);
return m;
}
void tor_mutex_free(tor_mutex_t *m)
{
CloseHandle(m->handle);
tor_free(m);
}
void tor_mutex_acquire(tor_mutex_t *m)
{
DWORD r;
r = WaitForSingleObject(m->handle, INFINITE);
switch (r) {
case WAIT_ABANDONED: /* holding thread exited. */
case WAIT_OBJECT_0: /* we got the mutex normally. */
break;
case WAIT_TIMEOUT: /* Should never happen. */
tor_assert(0);
break;
case WAIT_FAILED:
log_fn(LOG_WARN, "Failed to acquire mutex: %d", GetLastError());
}
}
void tor_mutex_release(tor_mutex_t *m)
{
BOOL r;
r = ReleaseMutex(m->handle);
if (!r) {
log_fn(LOG_WARN, "Failed to release mutex: %d", GetLastError());
}
}
#endif
/**
* On Windows, WSAEWOULDBLOCK is not always correct: when you see it,
* you need to ask the socket for its actual errno. Also, you need to
* get your errors from WSAGetLastError, not errno. (If you supply a
* socket of -1, we check WSAGetLastError, but don't correct
* WSAEWOULDBLOCKs.)
*/
#ifdef MS_WINDOWS
int tor_socket_errno(int sock)
{
int optval, optvallen=sizeof(optval);
int err = WSAGetLastError();
if (err == WSAEWOULDBLOCK && sock >= 0) {
if (getsockopt(sock, SOL_SOCKET, SO_ERROR, (void*)&optval, &optvallen))
return err;
if (optval)
return optval;
}
return err;
}
#endif
#ifdef MS_WINDOWS
#define E(code, s) { code, (s " [" #code " ]") }
struct { int code; const char *msg; } windows_socket_errors[] = {
E(WSAEINTR, "Interrupted function call"),
E(WSAEACCES, "Permission denied"),
E(WSAEFAULT, "Bad address"),
E(WSAEINVAL, "Invalid argument"),
E(WSAEMFILE, "Too many open files"),
E(WSAEWOULDBLOCK, "Resource temporarily unavailable"),
E(WSAEINPROGRESS, "Operation now in progress"),
E(WSAEALREADY, "Operation already in progress"),
E(WSAENOTSOCK, "Socket operation on nonsocket"),
E(WSAEDESTADDRREQ, "Destination address required"),
E(WSAEMSGSIZE, "Message too long"),
E(WSAEPROTOTYPE, "Protocol wrong for socket"),
E(WSAENOPROTOOPT, "Bad protocol option"),
E(WSAEPROTONOSUPPORT, "Protocol not supported"),
E(WSAESOCKTNOSUPPORT, "Socket type not supported"),
/* What's the difference between NOTSUPP and NOSUPPORT? :) */
E(WSAEOPNOTSUPP, "Operation not supported"),
E(WSAEPFNOSUPPORT, "Protocol family not supported"),
E(WSAEAFNOSUPPORT, "Address family not supported by protocol family"),
E(WSAEADDRINUSE, "Address already in use"),
E(WSAEADDRNOTAVAIL, "Cannot assign requested address"),
E(WSAENETDOWN, "Network is down"),
E(WSAENETUNREACH, "Network is unreachable"),
E(WSAENETRESET, "Network dropped connection on reset"),
E(WSAECONNABORTED, "Software caused connection abort"),
E(WSAECONNRESET, "Connection reset by peer"),
E(WSAENOBUFS, "No buffer space avaialable"),
E(WSAEISCONN, "Socket is already connected"),
E(WSAENOTCONN, "Socket is not connected"),
E(WSAESHUTDOWN, "Cannot send after socket shutdown"),
E(WSAETIMEDOUT, "Connection timed out"),
E(WSAECONNREFUSED, "Connection refused"),
E(WSAEHOSTDOWN, "Host is down"),
E(WSAEHOSTUNREACH, "No route to host"),
E(WSAEPROCLIM, "Too many processes"),
/* Yes, some of these start with WSA, not WSAE. No, I don't know why. */
E(WSASYSNOTREADY, "Network subsystem is unavailable"),
E(WSAVERNOTSUPPORTED, "Winsock.dll out of range"),
E(WSANOTINITIALISED, "Successful WSAStartup not yet performed"),
E(WSAEDISCON, "Graceful shutdown now in progress"),
#ifdef WSATYPE_NOT_FOUND
E(WSATYPE_NOT_FOUND, "Class type not found"),
#endif
E(WSAHOST_NOT_FOUND, "Host not found"),
E(WSATRY_AGAIN, "Nonauthoritative host not found"),
E(WSANO_RECOVERY, "This is a nonrecoverable error"),
E(WSANO_DATA, "Valid name, no data record of requested type)"),
/* There are some more error codes whose numeric values are marked
* <b>OS dependent</b>. They start with WSA_, apparently for the same
* reason that practitioners of some craft traditions deliberately
* introduce imperfections into their baskets and rugs "to allow the
* evil spirits to escape." If we catch them, then our binaries
* might not report consistent results across versions of Windows.
* Thus, I'm going to let them all fall through.
*/
{ -1, NULL },
};
/** There does not seem to be a strerror equivalent for winsock errors.
* Naturally, we have to roll our own.
*/
const char *tor_socket_strerror(int e)
{
int i;
for (i=0; windows_socket_errors[i].code >= 0; ++i) {
if (e == windows_socket_errors[i].code)
return windows_socket_errors[i].msg;
}
return strerror(e);
}
#endif
/*
Local Variables:
mode:c
indent-tabs-mode:nil
c-basic-offset:2
End:
*/

168
src/common/compat.h Normal file
View File

@ -0,0 +1,168 @@
/* Copyright 2003-2004 Roger Dingledine; Copyright 2004 Nick Mathewson */
/* See LICENSE for licensing information */
/* $Id$ */
#ifndef __COMPAT_H
#define __COMPAT_H
#include "orconfig.h"
#include "torint.h"
#ifdef MS_WINDOWS
#define WIN32_WINNT 0x400
#define _WIN32_WINNT 0x400
#define WIN32_LEAN_AND_MEAN
#if (_MSC_VER <= 1300)
#include <winsock.h>
#else
#include <winsock2.h>
#include <ws2tcpip.h>
#endif
#endif
#ifdef HAVE_SYS_TYPES_H
#include <sys/types.h>
#endif
#include <stdarg.h>
#ifndef NULL_REP_IS_ZERO_BYTES
#error "It seems your platform does not represent NULL as zero. We can't cope."
#endif
/* ===== Compiler compatibility */
/* GCC can check printf types on arbitrary functions. */
#ifdef __GNUC__
#define CHECK_PRINTF(formatIdx, firstArg) \
__attribute__ ((format (printf, formatIdx, firstArg)))
#else
#define CHECK_PRINTF(formatIdx, firstArg)
#endif
/* inline is __inline on windows. */
#ifdef MS_WINDOWS
#define INLINE __inline
#else
#define INLINE inline
#endif
/* Windows compilers before VC7 don't have __FUNCTION__. */
#if defined(_MSC_VER) && _MSC_VER < 1300
#define __FUNCTION__ "???"
#endif
/* ===== String compatibility */
#ifdef MS_WINDOWS
/* Windows names string functions differently from most other platforms. */
#define strncasecmp strnicmp
#define strcasecmp stricmp
#endif
int tor_snprintf(char *str, size_t size, const char *format, ...)
CHECK_PRINTF(3,4);
int tor_vsnprintf(char *str, size_t size, const char *format, va_list args);
/* ===== Time compatibility */
#if !defined(HAVE_GETTIMEOFDAY) && !defined(HAVE_STRUCT_TIMEVAL_TV_SEC)
struct timeval {
time_t tv_sec;
unsigned int tv_usec;
};
#endif
void tor_gettimeofday(struct timeval *timeval);
/* ===== File compatibility */
int replace_file(const char *from, const char *to);
/* ===== Net compatibility */
#ifdef MS_WINDOWS
/** On windows, you have to call close() on fds returned by open(),
* and closesocket() on fds returned by socket(). On Unix, everything
* gets close()'d. We abstract this difference by always using
* tor_close_socket to close sockets, and always using close() on
* files.
*/
#define tor_close_socket(s) closesocket(s)
#else
#define tor_close_socket(s) close(s)
#endif
struct in_addr;
int tor_inet_aton(const char *cp, struct in_addr *addr);
void set_socket_nonblocking(int socket);
int tor_socketpair(int family, int type, int protocol, int fd[2]);
/* For stupid historical reasons, windows sockets have an independent
* set of errnos, and an independent way to get them. Also, you can't
* always believe WSAEWOULDBLOCK. Use the macros below to compare
* errnos against expected values, and use tor_socket_errno to find
* the actual errno after a socket operation fails.
*/
#ifdef MS_WINDOWS
/** Return true if e is EAGAIN or the local equivalent. */
#define ERRNO_IS_EAGAIN(e) ((e) == EAGAIN || (e) == WSAEWOULDBLOCK)
/** Return true if e is EINPROGRESS or the local equivalent. */
#define ERRNO_IS_EINPROGRESS(e) ((e) == WSAEINPROGRESS)
/** Return true if e is EINPROGRESS or the local equivalent as returned by
* a call to connect(). */
#define ERRNO_IS_CONN_EINPROGRESS(e) ((e) == WSAEINPROGRESS || (e)== WSAEINVAL)
/** Return true if e is EAGAIN or another error indicating that a call to
* accept() has no pending connections to return. */
#define ERRNO_IS_ACCEPT_EAGAIN(e) ERRNO_IS_EAGAIN(e)
/** Return true if e is EMFILE or another error indicating that a call to
* accept() has failed because we're out of fds or something. */
#define ERRNO_IS_ACCEPT_RESOURCE_LIMIT(e) \
((e) == WSAEMFILE || (e) == WSAENOBUFS)
int tor_socket_errno(int sock);
const char *tor_socket_strerror(int e);
#else
#define ERRNO_IS_EAGAIN(e) ((e) == EAGAIN)
#define ERRNO_IS_EINPROGRESS(e) ((e) == EINPROGRESS)
#define ERRNO_IS_CONN_EINPROGRESS(e) ((e) == EINPROGRESS)
#define ERRNO_IS_ACCEPT_EAGAIN(e) ((e) == EAGAIN || (e) == ECONNABORTED)
#define ERRNO_IS_ACCEPT_RESOURCE_LIMIT(e) \
((e) == EMFILE || (e) == ENFILE || (e) == ENOBUFS || (e) == ENOMEM)
#define tor_socket_errno(sock) (errno)
#define tor_socket_strerror(e) strerror(e)
#endif
/* ===== OS compatibility */
const char *get_uname(void);
/* Some platforms segfault when you try to access a multi-byte type
* that isn't aligned to a word boundary. The macros and/or functions
* below can be used to access unaligned data on any platform.
*/
#ifdef UNALIGNED_INT_ACCESS_OK
#define get_uint16(cp) (*(uint16_t*)(cp))
#define get_uint32(cp) (*(uint32_t*)(cp))
#define set_uint16(cp,v) do { *(uint16_t*)(cp) = (v); } while (0)
#define set_uint32(cp,v) do { *(uint32_t*)(cp) = (v); } while (0)
#else
uint16_t get_uint16(const char *cp);
uint32_t get_uint32(const char *cp);
void set_uint16(char *cp, uint16_t v);
void set_uint32(char *cp, uint32_t v);
#endif
int set_max_file_descriptors(int required_min);
int switch_id(char *user, char *group);
int spawn_func(int (*func)(void *), void *data);
void spawn_exit(void);
/* Because we use threads instead of processes on Windows, we need locking on
* Windows. On Unixy platforms, these functions are no-ops. */
typedef struct tor_mutex_t tor_mutex_t;
tor_mutex_t *tor_mutex_new(void);
void tor_mutex_acquire(tor_mutex_t *m);
void tor_mutex_release(tor_mutex_t *m);
void tor_mutex_free(tor_mutex_t *m);
#endif
/*
Local Variables:
mode:c
indent-tabs-mode:nil
c-basic-offset:2
End:
*/

612
src/common/container.c Normal file
View File

@ -0,0 +1,612 @@
/* Copyright 2003-2004 Roger Dingledine; Copyright 2004 Nick Mathewson */
/* See LICENSE for licensing information */
/* $Id$ */
#include "compat.h"
#include "util.h"
#include "log.h"
#include "../or/tree.h"
#include "container.h"
#ifdef HAVE_CTYPE_H
#include <ctype.h>
#endif
#include <stdlib.h>
#include <string.h>
/* =====
* smartlist_t: a simple resizeable array abstraction.
* ===== */
/* All newly allocated smartlists have this capacity.
*/
#define SMARTLIST_DEFAULT_CAPACITY 32
struct smartlist_t {
/** <b>list</b> has enough capacity to store exactly <b>capacity</b> elements
* before it needs to be resized. Only the first <b>num_used</b> (\<=
* capacity) elements point to valid data.
*/
void **list;
int num_used;
int capacity;
};
/** Allocate and return an empty smartlist.
*/
smartlist_t *smartlist_create() {
smartlist_t *sl = tor_malloc(sizeof(smartlist_t));
sl->num_used = 0;
sl->capacity = SMARTLIST_DEFAULT_CAPACITY;
sl->list = tor_malloc(sizeof(void *) * sl->capacity);
return sl;
}
/** Deallocate a smartlist. Does not release storage associated with the
* list's elements.
*/
void smartlist_free(smartlist_t *sl) {
free(sl->list);
free(sl);
}
/** Change the capacity of the smartlist to <b>n</b>, so that we can grow
* the list up to <b>n</b> elements with no further reallocation or wasted
* space. If <b>n</b> is less than or equal to the number of elements
* currently in the list, reduce the list's capacity as much as
* possible without losing elements.
*/
void smartlist_set_capacity(smartlist_t *sl, int n) {
if (n < sl->num_used)
n = sl->num_used;
if (sl->capacity != n) {
sl->capacity = n;
sl->list = tor_realloc(sl->list, sizeof(void*)*sl->capacity);
}
}
/** Remove all elements from the list.
*/
void smartlist_clear(smartlist_t *sl) {
sl->num_used = 0;
}
/** Set the list's new length to <b>len</b> (which must be \<= the list's
* current size). Remove the last smartlist_len(sl)-len elements from the
* list.
*/
void smartlist_truncate(smartlist_t *sl, int len)
{
tor_assert(len <= sl->num_used);
sl->num_used = len;
}
/** Append element to the end of the list. */
void smartlist_add(smartlist_t *sl, void *element) {
if (sl->num_used >= sl->capacity) {
sl->capacity *= 2;
sl->list = tor_realloc(sl->list, sizeof(void*)*sl->capacity);
}
sl->list[sl->num_used++] = element;
}
/** Append each element from S2 to the end of S1. */
void smartlist_add_all(smartlist_t *sl, const smartlist_t *s2)
{
SMARTLIST_FOREACH(s2, void *, element, smartlist_add(sl, element));
}
/** Remove all elements E from sl such that E==element. Does not preserve
* the order of s1.
*/
void smartlist_remove(smartlist_t *sl, void *element) {
int i;
if(element == NULL)
return;
for(i=0; i < sl->num_used; i++)
if(sl->list[i] == element) {
sl->list[i] = sl->list[--sl->num_used]; /* swap with the end */
i--; /* so we process the new i'th element */
}
}
/** Return true iff some element E of sl has E==element.
*/
int smartlist_isin(const smartlist_t *sl, void *element) {
int i;
for(i=0; i < sl->num_used; i++)
if(sl->list[i] == element)
return 1;
return 0;
}
int smartlist_string_isin(const smartlist_t *sl, const char *element) {
int i;
for(i=0; i < sl->num_used; i++)
if(strcmp((const char*)sl->list[i],element)==0)
return 1;
return 0;
}
/** Return true iff some element E of sl2 has smartlist_isin(sl1,E).
*/
int smartlist_overlap(const smartlist_t *sl1, const smartlist_t *sl2) {
int i;
for(i=0; i < sl2->num_used; i++)
if(smartlist_isin(sl1, sl2->list[i]))
return 1;
return 0;
}
/** Remove every element E of sl1 such that !smartlist_isin(sl2,E).
* Does not preserve the order of sl1.
*/
void smartlist_intersect(smartlist_t *sl1, const smartlist_t *sl2) {
int i;
for(i=0; i < sl1->num_used; i++)
if(!smartlist_isin(sl2, sl1->list[i])) {
sl1->list[i] = sl1->list[--sl1->num_used]; /* swap with the end */
i--; /* so we process the new i'th element */
}
}
/** Remove every element E of sl1 such that smartlist_isin(sl2,E).
* Does not preserve the order of sl1.
*/
void smartlist_subtract(smartlist_t *sl1, const smartlist_t *sl2) {
int i;
for(i=0; i < sl2->num_used; i++)
smartlist_remove(sl1, sl2->list[i]);
}
/** Return the <b>idx</b>th element of sl.
*/
void *smartlist_get(const smartlist_t *sl, int idx)
{
tor_assert(sl);
tor_assert(idx>=0);
tor_assert(idx < sl->num_used);
return sl->list[idx];
}
/** Change the value of the <b>idx</b>th element of sl to <b>val</b>; return the old
* value of the <b>idx</b>th element.
*/
void *smartlist_set(smartlist_t *sl, int idx, void *val)
{
void *old;
tor_assert(sl);
tor_assert(idx>=0);
tor_assert(idx < sl->num_used);
old = sl->list[idx];
sl->list[idx] = val;
return old;
}
/** Remove the <b>idx</b>th element of sl; if idx is not the last
* element, swap the last element of sl into the <b>idx</b>th space.
* Return the old value of the <b>idx</b>th element.
*/
void *smartlist_del(smartlist_t *sl, int idx)
{
void *old;
tor_assert(sl);
tor_assert(idx>=0);
tor_assert(idx < sl->num_used);
old = sl->list[idx];
sl->list[idx] = sl->list[--sl->num_used];
return old;
}
/** Remove the <b>idx</b>th element of sl; if idx is not the last element,
* moving all subsequent elements back one space. Return the old value
* of the <b>idx</b>th element.
*/
void *smartlist_del_keeporder(smartlist_t *sl, int idx)
{
void *old;
tor_assert(sl);
tor_assert(idx>=0);
tor_assert(idx < sl->num_used);
old = sl->list[idx];
--sl->num_used;
if (idx < sl->num_used)
memmove(sl->list+idx, sl->list+idx+1, sizeof(void*)*(sl->num_used-idx));
return old;
}
/** Return the number of items in sl.
*/
int smartlist_len(const smartlist_t *sl)
{
return sl->num_used;
}
/** Insert the value <b>val</b> as the new <b>idx</b>th element of
* <b>sl</b>, moving all items previously at <b>idx</b> or later
* forward one space.
*/
void smartlist_insert(smartlist_t *sl, int idx, void *val)
{
tor_assert(sl);
tor_assert(idx>=0);
tor_assert(idx <= sl->num_used);
if (idx == sl->num_used) {
smartlist_add(sl, val);
} else {
/* Ensure sufficient capacity */
if (sl->num_used >= sl->capacity) {
sl->capacity *= 2;
sl->list = tor_realloc(sl->list, sizeof(void*)*sl->capacity);
}
/* Move other elements away */
if (idx < sl->num_used)
memmove(sl->list + idx + 1, sl->list + idx,
sizeof(void*)*(sl->num_used-idx));
sl->num_used++;
sl->list[idx] = val;
}
}
/**
* Split a string <b>str</b> along all occurences of <b>sep</b>,
* adding the split strings, in order, to <b>sl</b>. If
* <b>flags</b>&amp;SPLIT_SKIP_SPACE is true, remove initial and
* trailing space from each entry. If
* <b>flags</b>&amp;SPLIT_IGNORE_BLANK is true, remove any entries of
* length 0. If max>0, divide the string into no more than <b>max</b>
* pieces.
*/
int smartlist_split_string(smartlist_t *sl, const char *str, const char *sep,
int flags, int max)
{
const char *cp, *end, *next;
int n = 0;
tor_assert(sl);
tor_assert(str);
tor_assert(sep);
cp = str;
while (1) {
if (flags&SPLIT_SKIP_SPACE) {
while (isspace((int)*cp)) ++cp;
}
if (max>0 && n == max-1) {
end = strchr(cp,'\0');
} else {
end = strstr(cp,sep);
if (!end)
end = strchr(cp,'\0');
}
if (!*end) {
next = NULL;
} else {
next = end+strlen(sep);
}
if (flags&SPLIT_SKIP_SPACE) {
while (end > cp && isspace((int)*(end-1)))
--end;
}
if (end != cp || !(flags&SPLIT_IGNORE_BLANK)) {
smartlist_add(sl, tor_strndup(cp, end-cp));
++n;
}
if (!next)
break;
cp = next;
}
return n;
}
/** Allocate and return a new string containing the concatenation of
* the elements of <b>sl</b>, in order, separated by <b>join</b>. If
* <b>terminate</b> is true, also terminate the string with <b>join</b>.
* Requires that every element of <b>sl</b> is NUL-terminated string.
*/
char *smartlist_join_strings(smartlist_t *sl, const char *join, int terminate)
{
int i;
size_t n = 0, jlen;
char *r = NULL, *dst, *src;
tor_assert(sl);
tor_assert(join);
jlen = strlen(join);
for (i = 0; i < sl->num_used; ++i) {
n += strlen(sl->list[i]);
n += jlen;
}
if (!terminate) n -= jlen;
dst = r = tor_malloc(n+1);
for (i = 0; i < sl->num_used; ) {
for (src = sl->list[i]; *src; )
*dst++ = *src++;
if (++i < sl->num_used || terminate) {
memcpy(dst, join, jlen);
dst += jlen;
}
}
*dst = '\0';
return r;
}
/* Splay-tree implementation of string-to-void* map
*/
struct strmap_entry_t {
SPLAY_ENTRY(strmap_entry_t) node;
char *key;
void *val;
};
struct strmap_t {
SPLAY_HEAD(strmap_tree, strmap_entry_t) head;
};
static int compare_strmap_entries(struct strmap_entry_t *a,
struct strmap_entry_t *b)
{
return strcmp(a->key, b->key);
}
SPLAY_PROTOTYPE(strmap_tree, strmap_entry_t, node, compare_strmap_entries);
SPLAY_GENERATE(strmap_tree, strmap_entry_t, node, compare_strmap_entries);
/** Create a new empty map from strings to void*'s.
*/
strmap_t* strmap_new(void)
{
strmap_t *result;
result = tor_malloc(sizeof(strmap_t));
SPLAY_INIT(&result->head);
return result;
}
/** Set the current value for <b>key</b> to <b>val</b>. Returns the previous
* value for <b>key</b> if one was set, or NULL if one was not.
*
* This function makes a copy of <b>key</b> if necessary, but not of <b>val</b>.
*/
void* strmap_set(strmap_t *map, const char *key, void *val)
{
strmap_entry_t *resolve;
strmap_entry_t search;
void *oldval;
tor_assert(map);
tor_assert(key);
tor_assert(val);
search.key = (char*)key;
resolve = SPLAY_FIND(strmap_tree, &map->head, &search);
if (resolve) {
oldval = resolve->val;
resolve->val = val;
return oldval;
} else {
resolve = tor_malloc_zero(sizeof(strmap_entry_t));
resolve->key = tor_strdup(key);
resolve->val = val;
SPLAY_INSERT(strmap_tree, &map->head, resolve);
return NULL;
}
}
/** Return the current value associated with <b>key</b>, or NULL if no
* value is set.
*/
void* strmap_get(strmap_t *map, const char *key)
{
strmap_entry_t *resolve;
strmap_entry_t search;
tor_assert(map);
tor_assert(key);
search.key = (char*)key;
resolve = SPLAY_FIND(strmap_tree, &map->head, &search);
if (resolve) {
return resolve->val;
} else {
return NULL;
}
}
/** Remove the value currently associated with <b>key</b> from the map.
* Return the value if one was set, or NULL if there was no entry for
* <b>key</b>.
*
* Note: you must free any storage associated with the returned value.
*/
void* strmap_remove(strmap_t *map, const char *key)
{
strmap_entry_t *resolve;
strmap_entry_t search;
void *oldval;
tor_assert(map);
tor_assert(key);
search.key = (char*)key;
resolve = SPLAY_FIND(strmap_tree, &map->head, &search);
if (resolve) {
oldval = resolve->val;
SPLAY_REMOVE(strmap_tree, &map->head, resolve);
tor_free(resolve->key);
tor_free(resolve);
return oldval;
} else {
return NULL;
}
}
/** Same as strmap_set, but first converts <b>key</b> to lowercase. */
void* strmap_set_lc(strmap_t *map, const char *key, void *val)
{
/* We could be a little faster by using strcasecmp instead, and a separate
* type, but I don't think it matters. */
void *v;
char *lc_key = tor_strdup(key);
tor_strlower(lc_key);
v = strmap_set(map,lc_key,val);
tor_free(lc_key);
return v;
}
/** Same as strmap_get, but first converts <b>key</b> to lowercase. */
void* strmap_get_lc(strmap_t *map, const char *key)
{
void *v;
char *lc_key = tor_strdup(key);
tor_strlower(lc_key);
v = strmap_get(map,lc_key);
tor_free(lc_key);
return v;
}
/** Same as strmap_remove, but first converts <b>key</b> to lowercase */
void* strmap_remove_lc(strmap_t *map, const char *key)
{
void *v;
char *lc_key = tor_strdup(key);
tor_strlower(lc_key);
v = strmap_remove(map,lc_key);
tor_free(lc_key);
return v;
}
/** Invoke fn() on every entry of the map, in order. For every entry,
* fn() is invoked with that entry's key, that entry's value, and the
* value of <b>data</b> supplied to strmap_foreach. fn() must return a new
* (possibly unmodified) value for each entry: if fn() returns NULL, the
* entry is removed.
*
* Example:
* \code
* static void* upcase_and_remove_empty_vals(const char *key, void *val,
* void* data) {
* char *cp = (char*)val;
* if (!*cp) { // val is an empty string.
* free(val);
* return NULL;
* } else {
* for (; *cp; cp++)
* *cp = toupper(*cp);
* }
* return val;
* }
* }
*
* ...
*
* strmap_foreach(map, upcase_and_remove_empty_vals, NULL);
* \endcode
*/
void strmap_foreach(strmap_t *map,
void* (*fn)(const char *key, void *val, void *data),
void *data)
{
strmap_entry_t *ptr, *next;
tor_assert(map);
tor_assert(fn);
for (ptr = SPLAY_MIN(strmap_tree, &map->head); ptr != NULL; ptr = next) {
/* This remove-in-place usage is specifically blessed in tree(3). */
next = SPLAY_NEXT(strmap_tree, &map->head, ptr);
ptr->val = fn(ptr->key, ptr->val, data);
if (!ptr->val) {
SPLAY_REMOVE(strmap_tree, &map->head, ptr);
tor_free(ptr->key);
tor_free(ptr);
}
}
}
/** return an <b>iterator</b> pointer to the front of a map.
*
* Iterator example:
*
* \code
* // uppercase values in "map", removing empty values.
*
* strmap_iter_t *iter;
* const char *key;
* void *val;
* char *cp;
*
* for (iter = strmap_iter_init(map); !strmap_iter_done(iter); ) {
* strmap_iter_get(iter, &key, &val);
* cp = (char*)val;
* if (!*cp) {
* iter = strmap_iter_next_rmv(iter);
* free(val);
* } else {
* for(;*cp;cp++) *cp = toupper(*cp);
* iter = strmap_iter_next(iter);
* }
* }
* \endcode
*
*/
strmap_iter_t *strmap_iter_init(strmap_t *map)
{
tor_assert(map);
return SPLAY_MIN(strmap_tree, &map->head);
}
/** Advance the iterator <b>iter</b> for map a single step to the next entry.
*/
strmap_iter_t *strmap_iter_next(strmap_t *map, strmap_iter_t *iter)
{
tor_assert(map);
tor_assert(iter);
return SPLAY_NEXT(strmap_tree, &map->head, iter);
}
/** Advance the iterator <b>iter</b> a single step to the next entry, removing
* the current entry.
*/
strmap_iter_t *strmap_iter_next_rmv(strmap_t *map, strmap_iter_t *iter)
{
strmap_iter_t *next;
tor_assert(map);
tor_assert(iter);
next = SPLAY_NEXT(strmap_tree, &map->head, iter);
SPLAY_REMOVE(strmap_tree, &map->head, iter);
tor_free(iter->key);
tor_free(iter);
return next;
}
/** Set *keyp and *valp to the current entry pointed to by iter.
*/
void strmap_iter_get(strmap_iter_t *iter, const char **keyp, void **valp)
{
tor_assert(iter);
tor_assert(keyp);
tor_assert(valp);
*keyp = iter->key;
*valp = iter->val;
}
/** Return true iff iter has advanced past the last entry of map.
*/
int strmap_iter_done(strmap_iter_t *iter)
{
return iter == NULL;
}
/** Remove all entries from <b>map</b>, and deallocate storage for those entries.
* If free_val is provided, it is invoked on every value in <b>map</b>.
*/
void strmap_free(strmap_t *map, void (*free_val)(void*))
{
strmap_entry_t *ent, *next;
for (ent = SPLAY_MIN(strmap_tree, &map->head); ent != NULL; ent = next) {
next = SPLAY_NEXT(strmap_tree, &map->head, ent);
SPLAY_REMOVE(strmap_tree, &map->head, ent);
tor_free(ent->key);
if (free_val)
tor_free(ent->val);
}
tor_assert(SPLAY_EMPTY(&map->head));
tor_free(map);
}
int strmap_isempty(strmap_t *map)
{
return SPLAY_EMPTY(&map->head);
}
/*
Local Variables:
mode:c
indent-tabs-mode:nil
c-basic-offset:2
End:
*/

78
src/common/container.h Normal file
View File

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

View File

@ -53,6 +53,7 @@
#include "log.h" #include "log.h"
#include "aes.h" #include "aes.h"
#include "util.h" #include "util.h"
#include "container.h"
#if OPENSSL_VERSION_NUMBER < 0x00905000l #if OPENSSL_VERSION_NUMBER < 0x00905000l
#error "We require openssl >= 0.9.5" #error "We require openssl >= 0.9.5"

View File

@ -15,6 +15,8 @@
* \brief Headers for log.c * \brief Headers for log.c
*/ */
#include "../common/compat.h"
#ifdef HAVE_SYSLOG_H #ifdef HAVE_SYSLOG_H
#include <syslog.h> #include <syslog.h>
#define LOG_WARN LOG_WARNING #define LOG_WARN LOG_WARNING
@ -51,14 +53,6 @@
#define LOG_ERR 3 #define LOG_ERR 3
#endif #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); int parse_log_level(const char *level);
void add_stream_log(int severityMin, int severityMax, const char *name, FILE *stream); void add_stream_log(int severityMin, int severityMax, const char *name, FILE *stream);
int add_file_log(int severityMin, int severityMax, const char *filename); int add_file_log(int severityMin, int severityMax, const char *filename);

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +1,4 @@
/* Copyright 2003 Roger Dingledine */ /* Copyright 2003-2004 Roger Dingledine; Copyright 2004 Nick Mathewson */
/* See LICENSE for licensing information */ /* See LICENSE for licensing information */
/* $Id$ */ /* $Id$ */
@ -13,7 +13,7 @@
#include "orconfig.h" #include "orconfig.h"
#include "torint.h" #include "torint.h"
#include <stdio.h> #include <stdio.h>
#include <stdarg.h> #include <assert.h>
#ifdef HAVE_SYS_TIME_H #ifdef HAVE_SYS_TIME_H
#include <sys/time.h> #include <sys/time.h>
#endif #endif
@ -21,40 +21,6 @@
#include <time.h> #include <time.h>
#endif #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 /** Replace assert() with a variant that sends failures to the log before
* calling assert() normally. * calling assert() normally.
*/ */
@ -70,29 +36,19 @@ struct timeval {
} } while (0) } } while (0)
#endif #endif
#ifdef MS_WINDOWS /* Memory management */
/** 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);
void *tor_malloc(size_t size); void *tor_malloc(size_t size);
void *tor_malloc_zero(size_t size); void *tor_malloc_zero(size_t size);
void *tor_realloc(void *ptr, size_t size); void *tor_realloc(void *ptr, size_t size);
char *tor_strdup(const char *s); char *tor_strdup(const char *s);
char *tor_strndup(const char *s, size_t n); char *tor_strndup(const char *s, size_t n);
#define tor_free(p) do {if(p) {free(p); (p)=NULL;}} while(0) #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); void tor_strlower(char *s);
int strcmpstart(const char *s1, const char *s2); int strcmpstart(const char *s1, const char *s2);
int tor_strstrip(char *s, const char *strip); 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); long max, int *ok, char **next);
unsigned long tor_parse_ulong(const char *s, int base, unsigned long min, unsigned long tor_parse_ulong(const char *s, int base, unsigned long min,
unsigned long max, int *ok, char **next); 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); 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(const char *s);
const char *eat_whitespace_no_nl(const char *s); const char *eat_whitespace_no_nl(const char *s);
const char *find_whitespace(const char *s); const char *find_whitespace(const char *s);
/* Time helpers */ /* Time helpers */
void tor_gettimeofday(struct timeval *timeval);
long tv_udiff(struct timeval *start, struct timeval *end); long tv_udiff(struct timeval *start, struct timeval *end);
void tv_addms(struct timeval *a, long ms); void tv_addms(struct timeval *a, long ms);
void tv_add(struct timeval *a, struct timeval *b); 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); void format_iso_time(char *buf, time_t t);
int parse_iso_time(const 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 write_all(int fd, const char *buf, size_t count, int isSocket);
int read_all(int fd, 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; typedef enum { FN_ERROR, FN_NOENT, FN_FILE, FN_DIR} file_status_t;
file_status_t file_status(const char *filename); file_status_t file_status(const char *filename);
int check_private_dir(const char *dirname, int create); int check_private_dir(const char *dirname, int create);
int write_str_to_file(const char *fname, const char *str, int bin); int write_str_to_file(const char *fname, const char *str, int bin);
char *read_file_to_str(const char *filename, 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); int parse_line_from_file(char *line, size_t maxlen, FILE *f, char **key_out, char **value_out);
char *expand_filename(const char *filename); 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_internal_IP(uint32_t ip);
int is_local_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 tor_lookup_hostname(const char *name, uint32_t *addr);
int parse_addr_port(const char *addrport, char **address, uint32_t *addr, int parse_addr_port(const char *addrport, char **address, uint32_t *addr,
uint16_t *port); uint16_t *port);
int parse_addr_and_port_range(const char *s, uint32_t *addr_out, int parse_addr_and_port_range(const char *s, uint32_t *addr_out,
uint32_t *mask_out, uint16_t *port_min_out, uint32_t *mask_out, uint16_t *port_min_out,
uint16_t *port_max_out); uint16_t *port_max_out);
/* For stupid historical reasons, windows sockets have an independent /* Process helpers */
* set of errnos, and an independent way to get them. Also, you can't void start_daemon(const char *desired_cwd);
* always believe WSAEWOULDBLOCK. Use the macros below to compare void finish_daemon(void);
* errnos against expected values, and use tor_socket_errno to find void write_pidfile(char *filename);
* 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
#endif #endif
/* /*
Local Variables: Local Variables:
mode:c mode:c

View File

@ -116,6 +116,8 @@
#include "../common/crypto.h" #include "../common/crypto.h"
#include "../common/tortls.h" #include "../common/tortls.h"
#include "../common/log.h" #include "../common/log.h"
#include "../common/compat.h"
#include "../common/container.h"
#include "../common/util.h" #include "../common/util.h"
#include "../common/torgzip.h" #include "../common/torgzip.h"

View File

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