diff options
Diffstat (limited to 'src/common/compat.c')
-rw-r--r-- | src/common/compat.c | 516 |
1 files changed, 80 insertions, 436 deletions
diff --git a/src/common/compat.c b/src/common/compat.c index e25ecc462d..1788e32ee3 100644 --- a/src/common/compat.c +++ b/src/common/compat.c @@ -1,6 +1,6 @@ /* Copyright (c) 2003-2004, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2013, The Tor Project, Inc. */ + * Copyright (c) 2007-2015, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -27,7 +27,6 @@ #include "compat.h" #ifdef _WIN32 -#include <process.h> #include <windows.h> #include <sys/locking.h> #endif @@ -77,6 +76,7 @@ /* Includes for the process attaching prevention */ #if defined(HAVE_SYS_PRCTL_H) && defined(__linux__) +/* Only use the linux prctl; the IRIX prctl is totally different */ #include <sys/prctl.h> #elif defined(__APPLE__) #include <sys/types.h> @@ -110,10 +110,6 @@ #ifdef HAVE_SYS_FILE_H #include <sys/file.h> #endif -#if defined(HAVE_SYS_PRCTL_H) && defined(__linux__) -/* Only use the linux prctl; the IRIX prctl is totally different */ -#include <sys/prctl.h> -#endif #ifdef TOR_UNIT_TESTS #if !defined(HAVE_USLEEP) && defined(HAVE_SYS_SELECT_H) /* as fallback implementation for tor_sleep_msec */ @@ -141,9 +137,10 @@ int tor_open_cloexec(const char *path, int flags, unsigned mode) { int fd; + const char *p = path; #ifdef O_CLOEXEC - path = sandbox_intern_string(path); - fd = open(path, flags|O_CLOEXEC, mode); + p = sandbox_intern_string(path); + fd = open(p, flags|O_CLOEXEC, mode); if (fd >= 0) return fd; /* If we got an error, see if it is EINVAL. EINVAL might indicate that, @@ -153,8 +150,8 @@ tor_open_cloexec(const char *path, int flags, unsigned mode) return -1; #endif - log_debug(LD_FS, "Opening %s with flags %x", path, flags); - fd = open(path, flags, mode); + log_debug(LD_FS, "Opening %s with flags %x", p, flags); + fd = open(p, flags, mode); #ifdef FD_CLOEXEC if (fd >= 0) { if (fcntl(fd, F_SETFD, FD_CLOEXEC) == -1) { @@ -825,6 +822,7 @@ replace_file(const char *from, const char *to) case FN_NOENT: break; case FN_FILE: + case FN_EMPTY: if (unlink(to)) return -1; break; case FN_ERROR: @@ -981,14 +979,23 @@ tor_fd_getpos(int fd) #endif } -/** Move <b>fd</b> to the end of the file. Return -1 on error, 0 on success. */ +/** Move <b>fd</b> to the end of the file. Return -1 on error, 0 on success. + * If the file is a pipe, do nothing and succeed. + **/ int tor_fd_seekend(int fd) { #ifdef _WIN32 return _lseek(fd, 0, SEEK_END) < 0 ? -1 : 0; #else - return lseek(fd, 0, SEEK_END) < 0 ? -1 : 0; + off_t rc = lseek(fd, 0, SEEK_END) < 0 ? -1 : 0; +#ifdef ESPIPE + /* If we get an error and ESPIPE, then it's a pipe or a socket of a fifo: + * no need to worry. */ + if (rc < 0 && errno == ESPIPE) + rc = 0; +#endif + return (rc < 0) ? -1 : 0; #endif } @@ -1004,6 +1011,23 @@ tor_fd_setpos(int fd, off_t pos) #endif } +/** Replacement for ftruncate(fd, 0): move to the front of the file and remove + * all the rest of the file. Return -1 on error, 0 on success. */ +int +tor_ftruncate(int fd) +{ + /* Rumor has it that some versions of ftruncate do not move the file pointer. + */ + if (tor_fd_setpos(fd, 0) < 0) + return -1; + +#ifdef _WIN32 + return _chsize(fd, 0); +#else + return ftruncate(fd, 0); +#endif +} + #undef DEBUG_SOCKET_COUNTING #ifdef DEBUG_SOCKET_COUNTING /** A bitarray of all fds that should be passed to tor_socket_close(). Only @@ -1409,6 +1433,9 @@ tor_ersatz_socketpair(int family, int type, int protocol, tor_socket_t fd[2]) socklen_t size; int saved_errno = -1; + memset(&connect_addr, 0, sizeof(connect_addr)); + memset(&listen_addr, 0, sizeof(listen_addr)); + if (protocol #ifdef AF_UNIX || family != AF_UNIX @@ -1670,12 +1697,12 @@ log_credential_status(void) /* log supplementary groups */ sup_gids_size = 64; - sup_gids = tor_malloc(sizeof(gid_t) * 64); + sup_gids = tor_calloc(64, sizeof(gid_t)); while ((ngids = getgroups(sup_gids_size, sup_gids)) < 0 && errno == EINVAL && sup_gids_size < NGROUPS_MAX) { sup_gids_size *= 2; - sup_gids = tor_realloc(sup_gids, sizeof(gid_t) * sup_gids_size); + sup_gids = tor_reallocarray(sup_gids, sizeof(gid_t), sup_gids_size); } if (ngids < 0) { @@ -1766,8 +1793,8 @@ tor_getpwnam(const char *username) if ((pw = getpwnam(username))) { tor_passwd_free(passwd_cached); passwd_cached = tor_passwd_dup(pw); - log_notice(LD_GENERAL, "Caching new entry %s for %s", - passwd_cached->pw_name, username); + log_info(LD_GENERAL, "Caching new entry %s for %s", + passwd_cached->pw_name, username); return pw; } @@ -2170,9 +2197,20 @@ get_environment(void) #endif } -/** 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.) +/** Get name of current host and write it to <b>name</b> array, whose + * length is specified by <b>namelen</b> argument. Return 0 upon + * successfull completion; otherwise return return -1. (Currently, + * this function is merely a mockable wrapper for POSIX gethostname().) + */ +MOCK_IMPL(int, +tor_gethostname,(char *name, size_t namelen)) +{ + return gethostname(name,namelen); +} + +/** Set *addr to the IP address (in dotted-quad notation) stored in *str. + * Return 1 on success, 0 if *str is badly formatted. + * (Like inet_aton(str,addr), but works on Windows and Solaris.) */ int tor_inet_aton(const char *str, struct in_addr* addr) @@ -2392,8 +2430,9 @@ tor_inet_pton(int af, const char *src, void *dst) * (This function exists because standard windows gethostbyname * doesn't treat raw IP addresses properly.) */ -int -tor_lookup_hostname(const char *name, uint32_t *addr) + +MOCK_IMPL(int, +tor_lookup_hostname,(const char *name, uint32_t *addr)) { tor_addr_t myaddr; int ret; @@ -2485,14 +2524,12 @@ get_uname(void) "Unrecognized version of Windows [major=%d,minor=%d]", (int)info.dwMajorVersion,(int)info.dwMinorVersion); } -#if !defined (WINCE) #ifdef VER_NT_SERVER if (info.wProductType == VER_NT_SERVER || info.wProductType == VER_NT_DOMAIN_CONTROLLER) { strlcat(uname_result, " [server]", sizeof(uname_result)); } #endif -#endif #else strlcpy(uname_result, "Unknown platform", sizeof(uname_result)); #endif @@ -2506,109 +2543,6 @@ get_uname(void) * Process control */ -#if defined(USE_PTHREADS) -/** Wraps a void (*)(void*) function and its argument so we can - * invoke them in a way pthreads would expect. - */ -typedef struct tor_pthread_data_t { - void (*func)(void *); - void *data; -} tor_pthread_data_t; -/** Given a tor_pthread_data_t <b>_data</b>, call _data->func(d->data) - * and free _data. Used to make sure we can call functions the way pthread - * expects. */ -static void * -tor_pthread_helper_fn(void *_data) -{ - tor_pthread_data_t *data = _data; - void (*func)(void*); - void *arg; - /* mask signals to worker threads to avoid SIGPIPE, etc */ - sigset_t sigs; - /* We're in a subthread; don't handle any signals here. */ - sigfillset(&sigs); - pthread_sigmask(SIG_SETMASK, &sigs, NULL); - - func = data->func; - arg = data->data; - tor_free(_data); - func(arg); - return NULL; -} -/** - * A pthread attribute to make threads start detached. - */ -static pthread_attr_t attr_detached; -/** True iff we've called tor_threads_init() */ -static int threads_initialized = 0; -#endif - -/** 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. - * - * NOTE: if <b>data</b> is used, it should not be allocated on the stack, - * since in a multithreaded environment, there is no way to be sure that - * the caller's stack will still be around when the called function is - * running. - */ -int -spawn_func(void (*func)(void *), void *data) -{ -#if defined(USE_WIN32_THREADS) - int rv; - rv = (int)_beginthread(func, 0, data); - if (rv == (int)-1) - return -1; - return 0; -#elif defined(USE_PTHREADS) - pthread_t thread; - tor_pthread_data_t *d; - if (PREDICT_UNLIKELY(!threads_initialized)) - tor_threads_init(); - d = tor_malloc(sizeof(tor_pthread_data_t)); - d->data = data; - d->func = func; - if (pthread_create(&thread,&attr_detached,tor_pthread_helper_fn,d)) - 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(void) -{ -#if defined(USE_WIN32_THREADS) - _endthread(); - //we should never get here. my compiler thinks that _endthread returns, this - //is an attempt to fool it. - tor_assert(0); - _exit(0); -#elif defined(USE_PTHREADS) - pthread_exit(NULL); -#else - /* http://www.erlenstar.demon.co.uk/unix/faq_2.html says we should - * call _exit, not exit, from child processes. */ - _exit(0); -#endif -} - /** Implementation logic for compute_num_cpus(). */ static int compute_num_cpus_impl(void) @@ -2697,15 +2631,8 @@ tor_gettimeofday(struct timeval *timeval) uint64_t ft_64; FILETIME ft_ft; } ft; -#if defined (WINCE) - /* wince do not have GetSystemTimeAsFileTime */ - SYSTEMTIME stime; - GetSystemTime(&stime); - SystemTimeToFileTime(&stime,&ft.ft_ft); -#else /* number of 100-nsec units since Jan 1, 1601 */ GetSystemTimeAsFileTime(&ft.ft_ft); -#endif if (ft.ft_64 < EPOCH_BIAS) { log_err(LD_GENERAL,"System time is before 1970; failing."); exit(1); @@ -2731,7 +2658,7 @@ tor_gettimeofday(struct timeval *timeval) return; } -#if defined(TOR_IS_MULTITHREADED) && !defined(_WIN32) +#if !defined(_WIN32) /** Defined iff we need to add locks when defining fake versions of reentrant * versions of time-related functions. */ #define TIME_FNS_NEED_LOCKS @@ -2750,14 +2677,24 @@ correct_tm(int islocal, const time_t *timep, struct tm *resultbuf, const char *outcome; if (PREDICT_LIKELY(r)) { - if (r->tm_year > 8099) { /* We can't strftime dates after 9999 CE. */ + /* We can't strftime dates after 9999 CE, and we want to avoid dates + * before 1 CE (avoiding the year 0 issue and negative years). */ + if (r->tm_year > 8099) { r->tm_year = 8099; r->tm_mon = 11; r->tm_mday = 31; - r->tm_yday = 365; + r->tm_yday = 364; r->tm_hour = 23; r->tm_min = 59; r->tm_sec = 59; + } else if (r->tm_year < (1-1900)) { + r->tm_year = (1-1900); + r->tm_mon = 0; + r->tm_mday = 1; + r->tm_yday = 0; + r->tm_hour = 0; + r->tm_min = 0; + r->tm_sec = 0; } return r; } @@ -2771,7 +2708,7 @@ correct_tm(int islocal, const time_t *timep, struct tm *resultbuf, r->tm_year = 70; /* 1970 CE */ r->tm_mon = 0; r->tm_mday = 1; - r->tm_yday = 1; + r->tm_yday = 0; r->tm_hour = 0; r->tm_min = 0 ; r->tm_sec = 0; @@ -2784,7 +2721,7 @@ correct_tm(int islocal, const time_t *timep, struct tm *resultbuf, r->tm_year = 137; /* 2037 CE */ r->tm_mon = 11; r->tm_mday = 31; - r->tm_yday = 365; + r->tm_yday = 364; r->tm_hour = 23; r->tm_min = 59; r->tm_sec = 59; @@ -2853,7 +2790,7 @@ tor_localtime_r(const time_t *timep, struct tm *result) /** @} */ /** @{ */ -/** As gmtimee_r, but defined for platforms that don't have it: +/** As gmtime_r, but defined for platforms that don't have it: * * Convert *<b>timep</b> to a struct tm in UTC, and store the value in * *<b>result</b>. Return the result on success, or NULL on failure. @@ -2894,282 +2831,6 @@ tor_gmtime_r(const time_t *timep, struct tm *result) } #endif -#if defined(USE_WIN32_THREADS) -void -tor_mutex_init(tor_mutex_t *m) -{ - InitializeCriticalSection(&m->mutex); -} -void -tor_mutex_uninit(tor_mutex_t *m) -{ - DeleteCriticalSection(&m->mutex); -} -void -tor_mutex_acquire(tor_mutex_t *m) -{ - tor_assert(m); - EnterCriticalSection(&m->mutex); -} -void -tor_mutex_release(tor_mutex_t *m) -{ - LeaveCriticalSection(&m->mutex); -} -unsigned long -tor_get_thread_id(void) -{ - return (unsigned long)GetCurrentThreadId(); -} -#elif defined(USE_PTHREADS) -/** A mutex attribute that we're going to use to tell pthreads that we want - * "reentrant" mutexes (i.e., once we can re-lock if we're already holding - * them.) */ -static pthread_mutexattr_t attr_reentrant; -/** Initialize <b>mutex</b> so it can be locked. Every mutex must be set - * up with tor_mutex_init() or tor_mutex_new(); not both. */ -void -tor_mutex_init(tor_mutex_t *mutex) -{ - int err; - if (PREDICT_UNLIKELY(!threads_initialized)) - tor_threads_init(); - err = pthread_mutex_init(&mutex->mutex, &attr_reentrant); - if (PREDICT_UNLIKELY(err)) { - log_err(LD_GENERAL, "Error %d creating a mutex.", err); - tor_fragile_assert(); - } -} -/** Wait until <b>m</b> is free, then acquire it. */ -void -tor_mutex_acquire(tor_mutex_t *m) -{ - int err; - tor_assert(m); - err = pthread_mutex_lock(&m->mutex); - if (PREDICT_UNLIKELY(err)) { - log_err(LD_GENERAL, "Error %d locking a mutex.", err); - tor_fragile_assert(); - } -} -/** Release the lock <b>m</b> so another thread can have it. */ -void -tor_mutex_release(tor_mutex_t *m) -{ - int err; - tor_assert(m); - err = pthread_mutex_unlock(&m->mutex); - if (PREDICT_UNLIKELY(err)) { - log_err(LD_GENERAL, "Error %d unlocking a mutex.", err); - tor_fragile_assert(); - } -} -/** Clean up the mutex <b>m</b> so that it no longer uses any system - * resources. Does not free <b>m</b>. This function must only be called on - * mutexes from tor_mutex_init(). */ -void -tor_mutex_uninit(tor_mutex_t *m) -{ - int err; - tor_assert(m); - err = pthread_mutex_destroy(&m->mutex); - if (PREDICT_UNLIKELY(err)) { - log_err(LD_GENERAL, "Error %d destroying a mutex.", err); - tor_fragile_assert(); - } -} -/** Return an integer representing this thread. */ -unsigned long -tor_get_thread_id(void) -{ - union { - pthread_t thr; - unsigned long id; - } r; - r.thr = pthread_self(); - return r.id; -} -#endif - -#ifdef TOR_IS_MULTITHREADED -/** Return a newly allocated, ready-for-use mutex. */ -tor_mutex_t * -tor_mutex_new(void) -{ - tor_mutex_t *m = tor_malloc_zero(sizeof(tor_mutex_t)); - tor_mutex_init(m); - return m; -} -/** Release all storage and system resources held by <b>m</b>. */ -void -tor_mutex_free(tor_mutex_t *m) -{ - if (!m) - return; - tor_mutex_uninit(m); - tor_free(m); -} -#endif - -/* Conditions. */ -#ifdef USE_PTHREADS -#if 0 -/** Cross-platform condition implementation. */ -struct tor_cond_t { - pthread_cond_t cond; -}; -/** Return a newly allocated condition, with nobody waiting on it. */ -tor_cond_t * -tor_cond_new(void) -{ - tor_cond_t *cond = tor_malloc_zero(sizeof(tor_cond_t)); - if (pthread_cond_init(&cond->cond, NULL)) { - tor_free(cond); - return NULL; - } - return cond; -} -/** Release all resources held by <b>cond</b>. */ -void -tor_cond_free(tor_cond_t *cond) -{ - if (!cond) - return; - if (pthread_cond_destroy(&cond->cond)) { - log_warn(LD_GENERAL,"Error freeing condition: %s", strerror(errno)); - return; - } - tor_free(cond); -} -/** Wait until one of the tor_cond_signal functions is called on <b>cond</b>. - * All waiters on the condition must wait holding the same <b>mutex</b>. - * Returns 0 on success, negative on failure. */ -int -tor_cond_wait(tor_cond_t *cond, tor_mutex_t *mutex) -{ - return pthread_cond_wait(&cond->cond, &mutex->mutex) ? -1 : 0; -} -/** Wake up one of the waiters on <b>cond</b>. */ -void -tor_cond_signal_one(tor_cond_t *cond) -{ - pthread_cond_signal(&cond->cond); -} -/** Wake up all of the waiters on <b>cond</b>. */ -void -tor_cond_signal_all(tor_cond_t *cond) -{ - pthread_cond_broadcast(&cond->cond); -} -#endif -/** Set up common structures for use by threading. */ -void -tor_threads_init(void) -{ - if (!threads_initialized) { - pthread_mutexattr_init(&attr_reentrant); - pthread_mutexattr_settype(&attr_reentrant, PTHREAD_MUTEX_RECURSIVE); - tor_assert(0==pthread_attr_init(&attr_detached)); - tor_assert(0==pthread_attr_setdetachstate(&attr_detached, 1)); - threads_initialized = 1; - set_main_thread(); - } -} -#elif defined(USE_WIN32_THREADS) -#if 0 -static DWORD cond_event_tls_index; -struct tor_cond_t { - CRITICAL_SECTION mutex; - smartlist_t *events; -}; -tor_cond_t * -tor_cond_new(void) -{ - tor_cond_t *cond = tor_malloc_zero(sizeof(tor_cond_t)); - InitializeCriticalSection(&cond->mutex); - cond->events = smartlist_new(); - return cond; -} -void -tor_cond_free(tor_cond_t *cond) -{ - if (!cond) - return; - DeleteCriticalSection(&cond->mutex); - /* XXXX notify? */ - smartlist_free(cond->events); - tor_free(cond); -} -int -tor_cond_wait(tor_cond_t *cond, tor_mutex_t *mutex) -{ - HANDLE event; - int r; - tor_assert(cond); - tor_assert(mutex); - event = TlsGetValue(cond_event_tls_index); - if (!event) { - event = CreateEvent(0, FALSE, FALSE, NULL); - TlsSetValue(cond_event_tls_index, event); - } - EnterCriticalSection(&cond->mutex); - - tor_assert(WaitForSingleObject(event, 0) == WAIT_TIMEOUT); - tor_assert(!smartlist_contains(cond->events, event)); - smartlist_add(cond->events, event); - - LeaveCriticalSection(&cond->mutex); - - tor_mutex_release(mutex); - r = WaitForSingleObject(event, INFINITE); - tor_mutex_acquire(mutex); - - switch (r) { - case WAIT_OBJECT_0: /* we got the mutex normally. */ - break; - case WAIT_ABANDONED: /* holding thread exited. */ - case WAIT_TIMEOUT: /* Should never happen. */ - tor_assert(0); - break; - case WAIT_FAILED: - log_warn(LD_GENERAL, "Failed to acquire mutex: %d",(int) GetLastError()); - } - return 0; -} -void -tor_cond_signal_one(tor_cond_t *cond) -{ - HANDLE event; - tor_assert(cond); - - EnterCriticalSection(&cond->mutex); - - if ((event = smartlist_pop_last(cond->events))) - SetEvent(event); - - LeaveCriticalSection(&cond->mutex); -} -void -tor_cond_signal_all(tor_cond_t *cond) -{ - tor_assert(cond); - - EnterCriticalSection(&cond->mutex); - SMARTLIST_FOREACH(cond->events, HANDLE, event, SetEvent(event)); - smartlist_clear(cond->events); - LeaveCriticalSection(&cond->mutex); -} -#endif -void -tor_threads_init(void) -{ -#if 0 - cond_event_tls_index = TlsAlloc(); -#endif - set_main_thread(); -} -#endif - #if defined(HAVE_MLOCKALL) && HAVE_DECL_MLOCKALL && defined(RLIMIT_MEMLOCK) /** Attempt to raise the current and max rlimit to infinity for our process. * This only needs to be done once and can probably only be done when we have @@ -3253,23 +2914,6 @@ tor_mlockall(void) #endif } -/** Identity of the "main" thread */ -static unsigned long main_thread_id = -1; - -/** Start considering the current thread to be the 'main thread'. This has - * no effect on anything besides in_main_thread(). */ -void -set_main_thread(void) -{ - main_thread_id = tor_get_thread_id(); -} -/** Return true iff called from the main thread. */ -int -in_main_thread(void) -{ - return main_thread_id == tor_get_thread_id(); -} - /** * 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 @@ -3517,7 +3161,7 @@ get_total_system_memory_impl(void) size_t len = sizeof(memsize); int mib[2] = {CTL_HW, HW_USERMEM}; if (sysctl(mib,2,&memsize,&len,NULL,0)) - return -1; + return 0; return memsize; @@ -3548,12 +3192,12 @@ get_total_system_memory(size_t *mem_out) return 0; } -#if SIZE_T_MAX != UINT64_MAX - if (m > SIZE_T_MAX) { +#if SIZE_MAX != UINT64_MAX + if (m > SIZE_MAX) { /* I think this could happen if we're a 32-bit Tor running on a 64-bit * system: we could have more system memory than would fit in a * size_t. */ - m = SIZE_T_MAX; + m = SIZE_MAX; } #endif |