aboutsummaryrefslogtreecommitdiff
path: root/src/lib
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib')
-rw-r--r--src/lib/meminfo/.may_include8
-rw-r--r--src/lib/meminfo/include.am17
-rw-r--r--src/lib/meminfo/meminfo.c173
-rw-r--r--src/lib/meminfo/meminfo.h15
-rw-r--r--src/lib/process/.may_include1
-rw-r--r--src/lib/process/restrict.c136
-rw-r--r--src/lib/process/restrict.h10
7 files changed, 360 insertions, 0 deletions
diff --git a/src/lib/meminfo/.may_include b/src/lib/meminfo/.may_include
new file mode 100644
index 0000000000..9e4d25fd6a
--- /dev/null
+++ b/src/lib/meminfo/.may_include
@@ -0,0 +1,8 @@
+orconfig.h
+
+lib/cc/*.h
+lib/fs/*.h
+lib/log/*.h
+lib/malloc/*.h
+lib/meminfo/*.h
+lib/testsupport/*.h
diff --git a/src/lib/meminfo/include.am b/src/lib/meminfo/include.am
new file mode 100644
index 0000000000..d1fdde6313
--- /dev/null
+++ b/src/lib/meminfo/include.am
@@ -0,0 +1,17 @@
+
+noinst_LIBRARIES += src/lib/libtor-meminfo.a
+
+if UNITTESTS_ENABLED
+noinst_LIBRARIES += src/lib/libtor-meminfo-testing.a
+endif
+
+src_lib_libtor_meminfo_a_SOURCES = \
+ src/lib/meminfo/meminfo.c
+
+src_lib_libtor_meminfo_testing_a_SOURCES = \
+ $(src_lib_libtor_meminfo_a_SOURCES)
+src_lib_libtor_meminfo_testing_a_CPPFLAGS = $(AM_CPPFLAGS) $(TEST_CPPFLAGS)
+src_lib_libtor_meminfo_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS)
+
+noinst_HEADERS += \
+ src/lib/meminfo/meminfo.h
diff --git a/src/lib/meminfo/meminfo.c b/src/lib/meminfo/meminfo.c
new file mode 100644
index 0000000000..34b4ad3b5d
--- /dev/null
+++ b/src/lib/meminfo/meminfo.c
@@ -0,0 +1,173 @@
+/* Copyright (c) 2003-2004, Roger Dingledine
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2018, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+#include "lib/meminfo/meminfo.h"
+
+#include "lib/cc/compat_compiler.h"
+#include "lib/cc/torint.h"
+#include "lib/fs/files.h"
+#include "lib/log/torlog.h"
+#include "lib/malloc/util_malloc.h"
+
+#ifdef HAVE_SYS_SYSCTL_H
+#include <sys/sysctl.h>
+#endif
+#ifdef HAVE_FCNTL_H
+#include <fcntl.h>
+#endif
+#ifdef HAVE_MALLOC_H
+#include <malloc.h>
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#ifdef _WIN32
+#include <windows.h>
+#endif
+#include <string.h>
+
+DISABLE_GCC_WARNING(aggregate-return)
+/** Call the platform malloc info function, and dump the results to the log at
+ * level <b>severity</b>. If no such function exists, do nothing. */
+void
+tor_log_mallinfo(int severity)
+{
+#ifdef HAVE_MALLINFO
+ struct mallinfo mi;
+ memset(&mi, 0, sizeof(mi));
+ mi = mallinfo();
+ tor_log(severity, LD_MM,
+ "mallinfo() said: arena=%d, ordblks=%d, smblks=%d, hblks=%d, "
+ "hblkhd=%d, usmblks=%d, fsmblks=%d, uordblks=%d, fordblks=%d, "
+ "keepcost=%d",
+ mi.arena, mi.ordblks, mi.smblks, mi.hblks,
+ mi.hblkhd, mi.usmblks, mi.fsmblks, mi.uordblks, mi.fordblks,
+ mi.keepcost);
+#else /* !(defined(HAVE_MALLINFO)) */
+ (void)severity;
+#endif /* defined(HAVE_MALLINFO) */
+}
+ENABLE_GCC_WARNING(aggregate-return)
+
+#if defined(HW_PHYSMEM64)
+/* This appears to be an OpenBSD thing */
+#define INT64_HW_MEM HW_PHYSMEM64
+#elif defined(HW_MEMSIZE)
+/* OSX defines this one */
+#define INT64_HW_MEM HW_MEMSIZE
+#endif /* defined(HW_PHYSMEM64) || ... */
+
+/**
+ * Helper: try to detect the total system memory, and return it. On failure,
+ * return 0.
+ */
+static uint64_t
+get_total_system_memory_impl(void)
+{
+#if defined(__linux__)
+ /* On linux, sysctl is deprecated. Because proc is so awesome that you
+ * shouldn't _want_ to write portable code, I guess? */
+ unsigned long long result=0;
+ int fd = -1;
+ char *s = NULL;
+ const char *cp;
+ size_t file_size=0;
+ if (-1 == (fd = tor_open_cloexec("/proc/meminfo",O_RDONLY,0)))
+ return 0;
+ s = read_file_to_str_until_eof(fd, 65536, &file_size);
+ if (!s)
+ goto err;
+ cp = strstr(s, "MemTotal:");
+ if (!cp)
+ goto err;
+ /* Use the system sscanf so that space will match a wider number of space */
+ if (sscanf(cp, "MemTotal: %llu kB\n", &result) != 1)
+ goto err;
+
+ close(fd);
+ tor_free(s);
+ return result * 1024;
+
+ /* LCOV_EXCL_START Can't reach this unless proc is broken. */
+ err:
+ tor_free(s);
+ close(fd);
+ return 0;
+ /* LCOV_EXCL_STOP */
+#elif defined (_WIN32)
+ /* Windows has MEMORYSTATUSEX; pretty straightforward. */
+ MEMORYSTATUSEX ms;
+ memset(&ms, 0, sizeof(ms));
+ ms.dwLength = sizeof(ms);
+ if (! GlobalMemoryStatusEx(&ms))
+ return 0;
+
+ return ms.ullTotalPhys;
+
+#elif defined(HAVE_SYSCTL) && defined(INT64_HW_MEM)
+ /* On many systems, HW_PYHSMEM is clipped to 32 bits; let's use a better
+ * variant if we know about it. */
+ uint64_t memsize = 0;
+ size_t len = sizeof(memsize);
+ int mib[2] = {CTL_HW, INT64_HW_MEM};
+ if (sysctl(mib,2,&memsize,&len,NULL,0))
+ return 0;
+
+ return memsize;
+
+#elif defined(HAVE_SYSCTL) && defined(HW_PHYSMEM)
+ /* On some systems (like FreeBSD I hope) you can use a size_t with
+ * HW_PHYSMEM. */
+ size_t memsize=0;
+ size_t len = sizeof(memsize);
+ int mib[2] = {CTL_HW, HW_USERMEM};
+ if (sysctl(mib,2,&memsize,&len,NULL,0))
+ return 0;
+
+ return memsize;
+
+#else
+ /* I have no clue. */
+ return 0;
+#endif /* defined(__linux__) || ... */
+}
+
+/**
+ * Try to find out how much physical memory the system has. On success,
+ * return 0 and set *<b>mem_out</b> to that value. On failure, return -1.
+ */
+MOCK_IMPL(int,
+get_total_system_memory, (size_t *mem_out))
+{
+ static size_t mem_cached=0;
+ uint64_t m = get_total_system_memory_impl();
+ if (0 == m) {
+ /* LCOV_EXCL_START -- can't make this happen without mocking. */
+ /* We couldn't find our memory total */
+ if (0 == mem_cached) {
+ /* We have no cached value either */
+ *mem_out = 0;
+ return -1;
+ }
+
+ *mem_out = mem_cached;
+ return 0;
+ /* LCOV_EXCL_STOP */
+ }
+
+#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_MAX;
+ }
+#endif /* SIZE_MAX != UINT64_MAX */
+
+ *mem_out = mem_cached = (size_t) m;
+
+ return 0;
+}
diff --git a/src/lib/meminfo/meminfo.h b/src/lib/meminfo/meminfo.h
new file mode 100644
index 0000000000..a970e992f0
--- /dev/null
+++ b/src/lib/meminfo/meminfo.h
@@ -0,0 +1,15 @@
+/* Copyright (c) 2003-2004, Roger Dingledine
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2018, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+#ifndef TOR_MEMINFO_H
+#define TOR_MEMINFO_H
+
+#include "lib/testsupport/testsupport.h"
+#include <stddef.h>
+
+void tor_log_mallinfo(int severity);
+MOCK_DECL(int, get_total_system_memory, (size_t *mem_out));
+
+#endif
diff --git a/src/lib/process/.may_include b/src/lib/process/.may_include
index b195fb0056..c02e7fddb2 100644
--- a/src/lib/process/.may_include
+++ b/src/lib/process/.may_include
@@ -7,6 +7,7 @@ lib/err/*.h
lib/fs/*.h
lib/log/*.h
lib/malloc/*.h
+lib/net/*.h
lib/process/*.h
lib/string/*.h
lib/testsupport/*.h
diff --git a/src/lib/process/restrict.c b/src/lib/process/restrict.c
index 85c04efbbf..bb44cc3d15 100644
--- a/src/lib/process/restrict.c
+++ b/src/lib/process/restrict.c
@@ -5,7 +5,17 @@
#include "orconfig.h"
#include "lib/process/restrict.h"
+#include "lib/intmath/cmp.h"
#include "lib/log/torlog.h"
+#include "lib/log/util_bug.h"
+#include "lib/net/socket.h"
+
+#ifdef HAVE_SYS_MMAN_H
+#include <sys/mman.h>
+#endif
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
/* We only use the linux prctl for now. There is no Win32 support; this may
* also work on various BSD systems and Mac OS X - send testing feedback!
@@ -142,3 +152,129 @@ tor_mlockall(void)
return -1;
#endif /* defined(HAVE_UNIX_MLOCKALL) */
}
+
+/** 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, and tell the
+ * system we want to use up to that number. (Some systems have a low soft
+ * limit, and let us set it higher.) We compute this by finding the largest
+ * number that we can use.
+ *
+ * If the limit is below the reserved file descriptor value (ULIMIT_BUFFER),
+ * return -1 and <b>max_out</b> is untouched.
+ *
+ * If we can't find a number greater than or equal to <b>limit</b>, then we
+ * fail by returning -1 and <b>max_out</b> is untouched.
+ *
+ * If we are unable to set the limit value because of setrlimit() failing,
+ * return 0 and <b>max_out</b> is set to the current maximum value returned
+ * by getrlimit().
+ *
+ * Otherwise, return 0 and store the maximum we found inside <b>max_out</b>
+ * and set <b>max_sockets</b> with that value as well.*/
+int
+set_max_file_descriptors(rlim_t limit, int *max_out)
+{
+ if (limit < ULIMIT_BUFFER) {
+ log_warn(LD_CONFIG,
+ "ConnLimit must be at least %d. Failing.", ULIMIT_BUFFER);
+ return -1;
+ }
+
+ /* Define some maximum connections values for systems where we cannot
+ * automatically determine a limit. Re Cygwin, see
+ * http://archives.seul.org/or/talk/Aug-2006/msg00210.html
+ * For an iPhone, 9999 should work. For Windows and all other unknown
+ * systems we use 15000 as the default. */
+#ifndef HAVE_GETRLIMIT
+#if defined(CYGWIN) || defined(__CYGWIN__)
+ const char *platform = "Cygwin";
+ const unsigned long MAX_CONNECTIONS = 3200;
+#elif defined(_WIN32)
+ const char *platform = "Windows";
+ const unsigned long MAX_CONNECTIONS = 15000;
+#else
+ const char *platform = "unknown platforms with no getrlimit()";
+ const unsigned long MAX_CONNECTIONS = 15000;
+#endif /* defined(CYGWIN) || defined(__CYGWIN__) || ... */
+ log_fn(LOG_INFO, LD_NET,
+ "This platform is missing getrlimit(). Proceeding.");
+ if (limit > MAX_CONNECTIONS) {
+ log_warn(LD_CONFIG,
+ "We do not support more than %lu file descriptors "
+ "on %s. Tried to raise to %lu.",
+ (unsigned long)MAX_CONNECTIONS, platform, (unsigned long)limit);
+ return -1;
+ }
+ limit = MAX_CONNECTIONS;
+#else /* !(!defined(HAVE_GETRLIMIT)) */
+ struct rlimit rlim;
+
+ if (getrlimit(RLIMIT_NOFILE, &rlim) != 0) {
+ log_warn(LD_NET, "Could not get maximum number of file descriptors: %s",
+ strerror(errno));
+ return -1;
+ }
+ if (rlim.rlim_max < limit) {
+ log_warn(LD_CONFIG,"We need %lu file descriptors available, and we're "
+ "limited to %lu. Please change your ulimit -n.",
+ (unsigned long)limit, (unsigned long)rlim.rlim_max);
+ return -1;
+ }
+
+ if (rlim.rlim_max > rlim.rlim_cur) {
+ log_info(LD_NET,"Raising max file descriptors from %lu to %lu.",
+ (unsigned long)rlim.rlim_cur, (unsigned long)rlim.rlim_max);
+ }
+ /* Set the current limit value so if the attempt to set the limit to the
+ * max fails at least we'll have a valid value of maximum sockets. */
+ *max_out = (int)rlim.rlim_cur - ULIMIT_BUFFER;
+ set_max_sockets(*max_out);
+ rlim.rlim_cur = rlim.rlim_max;
+
+ if (setrlimit(RLIMIT_NOFILE, &rlim) != 0) {
+ int couldnt_set = 1;
+ const int setrlimit_errno = errno;
+#ifdef OPEN_MAX
+ uint64_t try_limit = OPEN_MAX - ULIMIT_BUFFER;
+ if (errno == EINVAL && try_limit < (uint64_t) rlim.rlim_cur) {
+ /* On some platforms, OPEN_MAX is the real limit, and getrlimit() is
+ * full of nasty lies. I'm looking at you, OSX 10.5.... */
+ rlim.rlim_cur = MIN((rlim_t) try_limit, rlim.rlim_cur);
+ if (setrlimit(RLIMIT_NOFILE, &rlim) == 0) {
+ if (rlim.rlim_cur < (rlim_t)limit) {
+ log_warn(LD_CONFIG, "We are limited to %lu file descriptors by "
+ "OPEN_MAX (%lu), and ConnLimit is %lu. Changing "
+ "ConnLimit; sorry.",
+ (unsigned long)try_limit, (unsigned long)OPEN_MAX,
+ (unsigned long)limit);
+ } else {
+ log_info(LD_CONFIG, "Dropped connection limit to %lu based on "
+ "OPEN_MAX (%lu); Apparently, %lu was too high and rlimit "
+ "lied to us.",
+ (unsigned long)try_limit, (unsigned long)OPEN_MAX,
+ (unsigned long)rlim.rlim_max);
+ }
+ couldnt_set = 0;
+ }
+ }
+#endif /* defined(OPEN_MAX) */
+ if (couldnt_set) {
+ log_warn(LD_CONFIG,"Couldn't set maximum number of file descriptors: %s",
+ strerror(setrlimit_errno));
+ }
+ }
+ /* leave some overhead for logs, etc, */
+ limit = rlim.rlim_cur;
+#endif /* !defined(HAVE_GETRLIMIT) */
+
+ if (limit > INT_MAX)
+ limit = INT_MAX;
+ tor_assert(max_out);
+ *max_out = (int)limit - ULIMIT_BUFFER;
+ set_max_sockets(*max_out);
+
+ return 0;
+}
diff --git a/src/lib/process/restrict.h b/src/lib/process/restrict.h
index d608c9c9bd..c7f76f8233 100644
--- a/src/lib/process/restrict.h
+++ b/src/lib/process/restrict.h
@@ -11,7 +11,17 @@
#ifndef TOR_RESTRICT_H
#define TOR_RESTRICT_H
+#include "orconfig.h"
+#ifdef HAVE_SYS_RESOURCE_H
+#include <sys/resource.h>
+#endif
+
int tor_disable_debugger_attach(void);
int tor_mlockall(void);
+#if !defined(HAVE_RLIM_T)
+typedef unsigned long rlim_t;
+#endif
+int set_max_file_descriptors(rlim_t limit, int *max_out);
+
#endif /* !defined(TOR_RESTRICT_H) */