summaryrefslogtreecommitdiff
path: root/src/common/compat.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/common/compat.c')
-rw-r--r--src/common/compat.c485
1 files changed, 412 insertions, 73 deletions
diff --git a/src/common/compat.c b/src/common/compat.c
index 333ef5b0f0..3644bd9996 100644
--- a/src/common/compat.c
+++ b/src/common/compat.c
@@ -15,6 +15,8 @@
/* This is required on rh7 to make strptime not complain.
* We also need it to make memmem get defined (where available)
*/
+/* XXXX023 We should just use AC_USE_SYSTEM_EXTENSIONS in our autoconf,
+ * and get this (and other important stuff!) automatically */
#define _GNU_SOURCE
#include "compat.h"
@@ -88,7 +90,7 @@
#include <sys/prctl.h>
#endif
-#include "log.h"
+#include "torlog.h"
#include "util.h"
#include "container.h"
#include "address.h"
@@ -170,12 +172,17 @@ tor_munmap_file(tor_mmap_t *handle)
tor_mmap_t *
tor_mmap_file(const char *filename)
{
+ TCHAR tfilename[MAX_PATH]= {0};
tor_mmap_t *res = tor_malloc_zero(sizeof(tor_mmap_t));
int empty = 0;
res->file_handle = INVALID_HANDLE_VALUE;
res->mmap_handle = NULL;
-
- res->file_handle = CreateFile(filename,
+#ifdef UNICODE
+ mbstowcs(tfilename,filename,MAX_PATH);
+#else
+ strlcpy(tfilename,filename,MAX_PATH);
+#endif
+ res->file_handle = CreateFile(tfilename,
GENERIC_READ, FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
@@ -308,6 +315,100 @@ tor_vsnprintf(char *str, size_t size, const char *format, va_list args)
return r;
}
+/**
+ * Portable asprintf implementation. Does a printf() into a newly malloc'd
+ * string. Sets *<b>strp</b> to this string, and returns its length (not
+ * including the terminating NUL character).
+ *
+ * You can treat this function as if its implementation were something like
+ <pre>
+ char buf[_INFINITY_];
+ tor_snprintf(buf, sizeof(buf), fmt, args);
+ *strp = tor_strdup(buf);
+ return strlen(*strp):
+ </pre>
+ * Where _INFINITY_ is an imaginary constant so big that any string can fit
+ * into it.
+ */
+int
+tor_asprintf(char **strp, const char *fmt, ...)
+{
+ int r;
+ va_list args;
+ va_start(args, fmt);
+ r = tor_vasprintf(strp, fmt, args);
+ va_end(args);
+ if (!*strp || r < 0) {
+ log_err(LD_BUG, "Internal error in asprintf");
+ tor_assert(0);
+ }
+ return r;
+}
+
+/**
+ * Portable vasprintf implementation. Does a printf() into a newly malloc'd
+ * string. Differs from regular vasprintf in the same ways that
+ * tor_asprintf() differs from regular asprintf.
+ */
+int
+tor_vasprintf(char **strp, const char *fmt, va_list args)
+{
+ /* use a temporary variable in case *strp is in args. */
+ char *strp_tmp=NULL;
+#ifdef HAVE_VASPRINTF
+ /* If the platform gives us one, use it. */
+ int r = vasprintf(&strp_tmp, fmt, args);
+ if (r < 0)
+ *strp = NULL;
+ else
+ *strp = strp_tmp;
+ return r;
+#elif defined(_MSC_VER)
+ /* On Windows, _vsnprintf won't tell us the length of the string if it
+ * overflows, so we need to use _vcsprintf to tell how much to allocate */
+ int len, r;
+ char *res;
+ len = _vscprintf(fmt, args);
+ if (len < 0) {
+ *strp = NULL;
+ return -1;
+ }
+ strp_tmp = tor_malloc(len + 1);
+ r = _vsnprintf(strp_tmp, len+1, fmt, args);
+ if (r != len) {
+ tor_free(strp_tmp);
+ *strp = NULL;
+ return -1;
+ }
+ *strp = strp_tmp;
+ return len;
+#else
+ /* Everywhere else, we have a decent vsnprintf that tells us how many
+ * characters we need. We give it a try on a short buffer first, since
+ * it might be nice to avoid the second vsnprintf call.
+ */
+ char buf[128];
+ int len, r;
+ va_list tmp_args;
+ va_copy(tmp_args, args);
+ len = vsnprintf(buf, sizeof(buf), fmt, tmp_args);
+ va_end(tmp_args);
+ if (len < (int)sizeof(buf)) {
+ *strp = tor_strdup(buf);
+ return len;
+ }
+ strp_tmp = tor_malloc(len+1);
+ r = vsnprintf(strp_tmp, len+1, fmt, args);
+ if (r != len) {
+ tor_free(strp_tmp);
+ *strp = NULL;
+ return -1;
+ }
+ *strp = strp_tmp;
+ return len;
+#endif
+}
+
/** Given <b>hlen</b> bytes at <b>haystack</b> and <b>nlen</b> bytes at
* <b>needle</b>, return a pointer to the first occurrence of the needle
* within the haystack, or NULL if there is no such occurrence.
@@ -399,6 +500,37 @@ const char TOR_TOLOWER_TABLE[256] = {
240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255,
};
+/** Implementation of strtok_r for platforms whose coders haven't figured out
+ * how to write one. Hey guys! You can use this code here for free! */
+char *
+tor_strtok_r_impl(char *str, const char *sep, char **lasts)
+{
+ char *cp, *start;
+ if (str)
+ start = cp = *lasts = str;
+ else if (!*lasts)
+ return NULL;
+ else
+ start = cp = *lasts;
+
+ tor_assert(*sep);
+ if (sep[1]) {
+ while (*cp && !strchr(sep, *cp))
+ ++cp;
+ } else {
+ tor_assert(strlen(sep) == 1);
+ cp = strchr(cp, *sep);
+ }
+
+ if (!cp || !*cp) {
+ *lasts = NULL;
+ } else {
+ *cp++ = '\0';
+ *lasts = cp;
+ }
+ return start;
+}
+
#ifdef MS_WINDOWS
/** Take a filename and return a pointer to its final element. This
* function is called on __FILE__ to fix a MSVC nit where __FILE__
@@ -450,8 +582,8 @@ get_uint32(const void *cp)
return v;
}
/**
- * Read a 32-bit value beginning at <b>cp</b>. Equivalent to
- * *(uint32_t*)(cp), but will not cause segfaults on platforms that forbid
+ * Read a 64-bit value beginning at <b>cp</b>. Equivalent to
+ * *(uint64_t*)(cp), but will not cause segfaults on platforms that forbid
* unaligned memory access.
*/
uint64_t
@@ -530,7 +662,9 @@ touch_file(const char *fname)
/** Represents a lockfile on which we hold the lock. */
struct tor_lockfile_t {
+ /** Name of the file */
char *filename;
+ /** File descriptor used to hold the file open */
int fd;
};
@@ -546,7 +680,10 @@ struct tor_lockfile_t {
*
* (Implementation note: because we need to fall back to fcntl on some
* platforms, these locks are per-process, not per-thread. If you want
- * to do in-process locking, use tor_mutex_t like a normal person.)
+ * to do in-process locking, use tor_mutex_t like a normal person.
+ * On Windows, when <b>blocking</b> is true, the maximum time that
+ * is actually waited is 10 seconds, after which NULL is returned
+ * and <b>locked_out</b> is set to 1.)
*/
tor_lockfile_t *
tor_lockfile_lock(const char *filename, int blocking, int *locked_out)
@@ -566,7 +703,7 @@ tor_lockfile_lock(const char *filename, int blocking, int *locked_out)
#ifdef WIN32
_lseek(fd, 0, SEEK_SET);
if (_locking(fd, blocking ? _LK_LOCK : _LK_NBLCK, 1) < 0) {
- if (errno != EDEADLOCK)
+ if (errno != EACCES && errno != EDEADLOCK)
log_warn(LD_FS,"Couldn't lock \"%s\": %s", filename, strerror(errno));
else
*locked_out = 1;
@@ -633,7 +770,8 @@ tor_lockfile_unlock(tor_lockfile_t *lockfile)
tor_free(lockfile);
}
-/* Some old versions of Unix didn't define constants for these values,
+/** @{ */
+/** Some old versions of Unix didn't define constants for these values,
* and instead expect you to say 0, 1, or 2. */
#ifndef SEEK_CUR
#define SEEK_CUR 1
@@ -641,6 +779,7 @@ tor_lockfile_unlock(tor_lockfile_t *lockfile)
#ifndef SEEK_END
#define SEEK_END 2
#endif
+/** @} */
/** Return the position of <b>fd</b> with respect to the start of the file. */
off_t
@@ -680,6 +819,7 @@ static int n_sockets_open = 0;
/** Mutex to protect open_sockets, max_socket, and n_sockets_open. */
static tor_mutex_t *socket_accounting_mutex = NULL;
+/** Helper: acquire the socket accounting lock. */
static INLINE void
socket_accounting_lock(void)
{
@@ -688,6 +828,7 @@ socket_accounting_lock(void)
tor_mutex_acquire(socket_accounting_mutex);
}
+/** Helper: release the socket accounting lock. */
static INLINE void
socket_accounting_unlock(void)
{
@@ -746,6 +887,7 @@ tor_close_socket(int s)
return r;
}
+/** @{ */
#ifdef DEBUG_SOCKET_COUNTING
/** Helper: if DEBUG_SOCKET_COUNTING is enabled, remember that <b>s</b> is
* now an open socket. */
@@ -770,6 +912,7 @@ mark_socket_open(int s)
#else
#define mark_socket_open(s) STMT_NIL
#endif
+/** @} */
/** As socket(), but counts the number of open sockets. */
int
@@ -957,6 +1100,8 @@ tor_socketpair(int family, int type, int protocol, int fd[2])
#endif
}
+/** Number of extra file descriptors to keep in reserve beyond those that we
+ * tell Tor it's allowed to use. */
#define ULIMIT_BUFFER 32 /* keep 32 extra fd's beyond _ConnLimit */
/** Learn the maximum allowed number of file descriptors. (Some systems
@@ -979,9 +1124,6 @@ set_max_file_descriptors(rlim_t limit, int *max_out)
#if defined(CYGWIN) || defined(__CYGWIN__)
const char *platform = "Cygwin";
const unsigned long MAX_CONNECTIONS = 3200;
-#elif defined(IPHONE)
- const char *platform = "iPhone";
- const unsigned long MAX_CONNECTIONS = 9999;
#elif defined(MS_WINDOWS)
const char *platform = "Windows";
const unsigned long MAX_CONNECTIONS = 15000;
@@ -1072,6 +1214,7 @@ set_max_file_descriptors(rlim_t limit, int *max_out)
static int
log_credential_status(void)
{
+/** Log level to use when describing non-error UID/GID status. */
#define CREDENTIAL_LOG_LEVEL LOG_INFO
/* Real, effective and saved UIDs */
uid_t ruid, euid, suid;
@@ -1553,6 +1696,30 @@ tor_lookup_hostname(const char *name, uint32_t *addr)
return -1;
}
+/** Initialize the insecure libc RNG. */
+void
+tor_init_weak_random(unsigned seed)
+{
+#ifdef MS_WINDOWS
+ srand(seed);
+#else
+ srandom(seed);
+#endif
+}
+
+/** Return a randomly chosen value in the range 0..TOR_RAND_MAX. This
+ * entropy will not be cryptographically strong; do not rely on it
+ * for anything an adversary should not be able to predict. */
+long
+tor_weak_random(void)
+{
+#ifdef MS_WINDOWS
+ return rand();
+#else
+ return random();
+#endif
+}
+
/** Hold the result of our call to <b>uname</b>. */
static char uname_result[256];
/** True iff uname_result is set. */
@@ -1578,13 +1745,14 @@ get_uname(void)
#ifdef MS_WINDOWS
OSVERSIONINFOEX info;
int i;
- unsigned int leftover_mask;
const char *plat = NULL;
const char *extra = NULL;
+ char acsd[MAX_PATH] = {0};
static struct {
unsigned major; unsigned minor; const char *version;
} win_version_table[] = {
- { 6, 0, "Windows \"Longhorn\"" },
+ { 6, 1, "Windows 7" },
+ { 6, 0, "Windows Vista" },
{ 5, 2, "Windows Server 2003" },
{ 5, 1, "Windows XP" },
{ 5, 0, "Windows 2000" },
@@ -1595,25 +1763,6 @@ get_uname(void)
{ 3, 51, "Windows NT 3.51" },
{ 0, 0, NULL }
};
-#ifdef VER_SUITE_BACKOFFICE
- static struct {
- unsigned int mask; const char *str;
- } win_mask_table[] = {
- { VER_SUITE_BACKOFFICE, " {backoffice}" },
- { VER_SUITE_BLADE, " {\"blade\" (2003, web edition)}" },
- { VER_SUITE_DATACENTER, " {datacenter}" },
- { VER_SUITE_ENTERPRISE, " {enterprise}" },
- { VER_SUITE_EMBEDDEDNT, " {embedded}" },
- { VER_SUITE_PERSONAL, " {personal}" },
- { VER_SUITE_SINGLEUSERTS,
- " {terminal services, single user}" },
- { VER_SUITE_SMALLBUSINESS, " {small business}" },
- { VER_SUITE_SMALLBUSINESS_RESTRICTED,
- " {small business, restricted}" },
- { VER_SUITE_TERMINAL, " {terminal services}" },
- { 0, NULL },
- };
-#endif
memset(&info, 0, sizeof(info));
info.dwOSVersionInfoSize = sizeof(info);
if (! GetVersionEx((LPOSVERSIONINFO)&info)) {
@@ -1622,14 +1771,19 @@ get_uname(void)
uname_result_is_set = 1;
return uname_result;
}
+#ifdef UNICODE
+ wcstombs(acsd, info.szCSDVersion, MAX_PATH);
+#else
+ strlcpy(acsd, info.szCSDVersion, sizeof(acsd));
+#endif
if (info.dwMajorVersion == 4 && info.dwMinorVersion == 0) {
if (info.dwPlatformId == VER_PLATFORM_WIN32_NT)
plat = "Windows NT 4.0";
else
plat = "Windows 95";
- if (info.szCSDVersion[1] == 'B')
+ if (acsd[1] == 'B')
extra = "OSR2 (B)";
- else if (info.szCSDVersion[1] == 'C')
+ else if (acsd[1] == 'C')
extra = "OSR2 (C)";
} else {
for (i=0; win_version_table[i].major>0; ++i) {
@@ -1641,29 +1795,30 @@ get_uname(void)
}
}
if (plat && !strcmp(plat, "Windows 98")) {
- if (info.szCSDVersion[1] == 'A')
+ if (acsd[1] == 'A')
extra = "SE (A)";
- else if (info.szCSDVersion[1] == 'B')
+ else if (acsd[1] == 'B')
extra = "SE (B)";
}
if (plat) {
if (!extra)
- extra = info.szCSDVersion;
+ extra = acsd;
tor_snprintf(uname_result, sizeof(uname_result), "%s %s",
plat, extra);
} else {
if (info.dwMajorVersion > 6 ||
- (info.dwMajorVersion==6 && info.dwMinorVersion>0))
+ (info.dwMajorVersion==6 && info.dwMinorVersion>1))
tor_snprintf(uname_result, sizeof(uname_result),
"Very recent version of Windows [major=%d,minor=%d] %s",
(int)info.dwMajorVersion,(int)info.dwMinorVersion,
- info.szCSDVersion);
+ acsd);
else
tor_snprintf(uname_result, sizeof(uname_result),
"Unrecognized version of Windows [major=%d,minor=%d] %s",
(int)info.dwMajorVersion,(int)info.dwMinorVersion,
- info.szCSDVersion);
+ acsd);
}
+#if !defined (WINCE)
#ifdef VER_SUITE_BACKOFFICE
if (info.wProductType == VER_NT_DOMAIN_CONTROLLER) {
strlcat(uname_result, " [domain controller]", sizeof(uname_result));
@@ -1672,18 +1827,7 @@ get_uname(void)
} else if (info.wProductType == VER_NT_WORKSTATION) {
strlcat(uname_result, " [workstation]", sizeof(uname_result));
}
- leftover_mask = info.wSuiteMask;
- for (i = 0; win_mask_table[i].mask; ++i) {
- if (info.wSuiteMask & win_mask_table[i].mask) {
- strlcat(uname_result, win_mask_table[i].str, sizeof(uname_result));
- leftover_mask &= ~win_mask_table[i].mask;
- }
- }
- if (leftover_mask) {
- size_t len = strlen(uname_result);
- tor_snprintf(uname_result+len, sizeof(uname_result)-len,
- " {0x%x}", info.wSuiteMask);
- }
+#endif
#endif
#else
strlcpy(uname_result, "Unknown platform", sizeof(uname_result));
@@ -1793,7 +1937,6 @@ spawn_exit(void)
* call _exit, not exit, from child processes. */
_exit(0);
#endif
-
}
/** Set *timeval to the current time of day. On error, log and terminate.
@@ -1813,8 +1956,15 @@ 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);
@@ -1846,8 +1996,88 @@ tor_gettimeofday(struct timeval *timeval)
#define TIME_FNS_NEED_LOCKS
#endif
-#ifndef HAVE_LOCALTIME_R
-#ifdef TIME_FNS_NEED_LOCKS
+static struct tm *
+correct_tm(int islocal, const time_t *timep, struct tm *resultbuf,
+ struct tm *r)
+{
+ const char *outcome;
+
+ if (PREDICT_LIKELY(r)) {
+ if (r->tm_year > 8099) { /* We can't strftime dates after 9999 CE. */
+ r->tm_year = 8099;
+ r->tm_mon = 11;
+ r->tm_mday = 31;
+ r->tm_yday = 365;
+ r->tm_hour = 23;
+ r->tm_min = 59;
+ r->tm_sec = 59;
+ }
+ return r;
+ }
+
+ /* If we get here, gmtime or localtime returned NULL. It might have done
+ * this because of overrun or underrun, or it might have done it because of
+ * some other weird issue. */
+ if (timep) {
+ if (*timep < 0) {
+ r = resultbuf;
+ r->tm_year = 70; /* 1970 CE */
+ r->tm_mon = 0;
+ r->tm_mday = 1;
+ r->tm_yday = 1;
+ r->tm_hour = 0;
+ r->tm_min = 0 ;
+ r->tm_sec = 0;
+ outcome = "Rounding up to 1970";
+ goto done;
+ } else if (*timep >= INT32_MAX) {
+ /* Rounding down to INT32_MAX isn't so great, but keep in mind that we
+ * only do it if gmtime/localtime tells us NULL. */
+ r = resultbuf;
+ r->tm_year = 137; /* 2037 CE */
+ r->tm_mon = 11;
+ r->tm_mday = 31;
+ r->tm_yday = 365;
+ r->tm_hour = 23;
+ r->tm_min = 59;
+ r->tm_sec = 59;
+ outcome = "Rounding down to 2037";
+ goto done;
+ }
+ }
+
+ /* If we get here, then gmtime/localtime failed without getting an extreme
+ * value for *timep */
+
+ tor_fragile_assert();
+ r = resultbuf;
+ memset(resultbuf, 0, sizeof(struct tm));
+ outcome="can't recover";
+ done:
+ log_warn(LD_BUG, "%s("I64_FORMAT") failed with error %s: %s",
+ islocal?"localtime":"gmtime",
+ timep?I64_PRINTF_ARG(*timep):0,
+ strerror(errno),
+ outcome);
+ return r;
+}
+
+
+/** @{ */
+/** As localtime_r, but defined for platforms that don't have it:
+ *
+ * Convert *<b>timep</b> to a struct tm in local time, and store the value in
+ * *<b>result</b>. Return the result on success, or NULL on failure.
+ */
+#ifdef HAVE_LOCALTIME_R
+struct tm *
+tor_localtime_r(const time_t *timep, struct tm *result)
+{
+ struct tm *r;
+ r = localtime_r(timep, result);
+ return correct_tm(1, timep, result, r);
+}
+#elif defined(TIME_FNS_NEED_LOCKS)
struct tm *
tor_localtime_r(const time_t *timep, struct tm *result)
{
@@ -1857,9 +2087,10 @@ tor_localtime_r(const time_t *timep, struct tm *result)
tor_assert(result);
tor_mutex_acquire(m);
r = localtime(timep);
- memcpy(result, r, sizeof(struct tm));
+ if (r)
+ memcpy(result, r, sizeof(struct tm));
tor_mutex_release(m);
- return result;
+ return correct_tm(1, timep, result, r);
}
#else
struct tm *
@@ -1868,14 +2099,28 @@ tor_localtime_r(const time_t *timep, struct tm *result)
struct tm *r;
tor_assert(result);
r = localtime(timep);
- memcpy(result, r, sizeof(struct tm));
- return result;
+ if (r)
+ memcpy(result, r, sizeof(struct tm));
+ return correct_tm(1, timep, result, r);
}
#endif
-#endif
+/** @} */
-#ifndef HAVE_GMTIME_R
-#ifdef TIME_FNS_NEED_LOCKS
+/** @{ */
+/** As gmtimee_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.
+ */
+#ifdef HAVE_GMTIME_R
+struct tm *
+tor_gmtime_r(const time_t *timep, struct tm *result)
+{
+ struct tm *r;
+ r = gmtime_r(timep, result);
+ return correct_tm(0, timep, result, r);
+}
+#elif defined(TIME_FNS_NEED_LOCKS)
struct tm *
tor_gmtime_r(const time_t *timep, struct tm *result)
{
@@ -1885,9 +2130,10 @@ tor_gmtime_r(const time_t *timep, struct tm *result)
tor_assert(result);
tor_mutex_acquire(m);
r = gmtime(timep);
- memcpy(result, r, sizeof(struct tm));
+ if (r)
+ memcpy(result, r, sizeof(struct tm));
tor_mutex_release(m);
- return result;
+ return correct_tm(0, timep, result, r);
}
#else
struct tm *
@@ -1896,11 +2142,11 @@ tor_gmtime_r(const time_t *timep, struct tm *result)
struct tm *r;
tor_assert(result);
r = gmtime(timep);
- memcpy(result, r, sizeof(struct tm));
- return result;
+ if (r)
+ memcpy(result, r, sizeof(struct tm));
+ return correct_tm(0, timep, result, r);
}
#endif
-#endif
#if defined(USE_WIN32_THREADS)
void
@@ -2014,6 +2260,8 @@ tor_mutex_new(void)
void
tor_mutex_free(tor_mutex_t *m)
{
+ if (!m)
+ return;
tor_mutex_uninit(m);
tor_free(m);
}
@@ -2041,7 +2289,8 @@ tor_cond_new(void)
void
tor_cond_free(tor_cond_t *cond)
{
- tor_assert(cond);
+ if (!cond)
+ return;
if (pthread_cond_destroy(&cond->cond)) {
log_warn(LD_GENERAL,"Error freeing condition: %s", strerror(errno));
return;
@@ -2098,7 +2347,8 @@ tor_cond_new(void)
void
tor_cond_free(tor_cond_t *cond)
{
- tor_assert(cond);
+ if (!cond)
+ return;
DeleteCriticalSection(&cond->mutex);
/* XXXX notify? */
smartlist_free(cond->events);
@@ -2174,6 +2424,89 @@ tor_threads_init(void)
}
#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
+ * not already dropped privileges.
+ */
+static int
+tor_set_max_memlock(void)
+{
+ /* Future consideration for Windows is probably SetProcessWorkingSetSize
+ * This is similar to setting the memory rlimit of RLIMIT_MEMLOCK
+ * http://msdn.microsoft.com/en-us/library/ms686234(VS.85).aspx
+ */
+
+ struct rlimit limit;
+
+ /* RLIM_INFINITY is -1 on some platforms. */
+ limit.rlim_cur = RLIM_INFINITY;
+ limit.rlim_max = RLIM_INFINITY;
+
+ if (setrlimit(RLIMIT_MEMLOCK, &limit) == -1) {
+ if (errno == EPERM) {
+ log_warn(LD_GENERAL, "You appear to lack permissions to change memory "
+ "limits. Are you root?");
+ }
+ log_warn(LD_GENERAL, "Unable to raise RLIMIT_MEMLOCK: %s",
+ strerror(errno));
+ return -1;
+ }
+
+ return 0;
+}
+#endif
+
+/** Attempt to lock all current and all future memory pages.
+ * This should only be called once and while we're privileged.
+ * Like mlockall() we return 0 when we're successful and -1 when we're not.
+ * Unlike mlockall() we return 1 if we've already attempted to lock memory.
+ */
+int
+tor_mlockall(void)
+{
+ static int memory_lock_attempted = 0;
+
+ if (memory_lock_attempted) {
+ return 1;
+ }
+
+ memory_lock_attempted = 1;
+
+ /*
+ * Future consideration for Windows may be VirtualLock
+ * VirtualLock appears to implement mlock() but not mlockall()
+ *
+ * http://msdn.microsoft.com/en-us/library/aa366895(VS.85).aspx
+ */
+
+#if defined(HAVE_MLOCKALL) && HAVE_DECL_MLOCKALL && defined(RLIMIT_MEMLOCK)
+ if (tor_set_max_memlock() == 0) {
+ log_debug(LD_GENERAL, "RLIMIT_MEMLOCK is now set to RLIM_INFINITY.");
+ }
+
+ if (mlockall(MCL_CURRENT|MCL_FUTURE) == 0) {
+ log_info(LD_GENERAL, "Insecure OS paging is effectively disabled.");
+ return 0;
+ } else {
+ if (errno == ENOSYS) {
+ /* Apple - it's 2009! I'm looking at you. Grrr. */
+ log_notice(LD_GENERAL, "It appears that mlockall() is not available on "
+ "your platform.");
+ } else if (errno == EPERM) {
+ log_notice(LD_GENERAL, "It appears that you lack the permissions to "
+ "lock memory. Are you root?");
+ }
+ log_notice(LD_GENERAL, "Unable to lock all current and future memory "
+ "pages: %s", strerror(errno));
+ return -1;
+ }
+#else
+ log_warn(LD_GENERAL, "Unable to lock memory pages. mlockall() unsupported?");
+ return -1;
+#endif
+}
+
/** Identity of the "main" thread */
static unsigned long main_thread_id = -1;
@@ -2325,20 +2658,26 @@ network_init(void)
char *
format_win32_error(DWORD err)
{
- LPVOID str = NULL;
+ TCHAR *str = NULL;
char *result;
/* Somebody once decided that this interface was better than strerror(). */
- FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER |
+ FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, err,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
- (LPTSTR) &str,
+ (LPVOID)&str,
0, NULL);
if (str) {
- result = tor_strdup((char*)str);
+#ifdef UNICODE
+ char abuf[1024] = {0};
+ wcstombs(abuf,str,1024);
+ result = tor_strdup(abuf);
+#else
+ result = tor_strdup(str);
+#endif
LocalFree(str); /* LocalFree != free() */
} else {
result = tor_strdup("<unformattable error>");