mirror of
https://gitlab.torproject.org/tpo/core/tor.git
synced 2024-11-20 10:12:15 +01:00
Move fd and memory-info functions.
This commit is contained in:
parent
973afcc40b
commit
0362cdc169
2
.gitignore
vendored
2
.gitignore
vendored
@ -191,6 +191,8 @@ uptime-*.json
|
|||||||
/src/lib/libtor-math-testing.a
|
/src/lib/libtor-math-testing.a
|
||||||
/src/lib/libtor-memarea.a
|
/src/lib/libtor-memarea.a
|
||||||
/src/lib/libtor-memarea-testing.a
|
/src/lib/libtor-memarea-testing.a
|
||||||
|
/src/lib/libtor-meminfo.a
|
||||||
|
/src/lib/libtor-meminfo-testing.a
|
||||||
/src/lib/libtor-net.a
|
/src/lib/libtor-net.a
|
||||||
/src/lib/libtor-net-testing.a
|
/src/lib/libtor-net-testing.a
|
||||||
/src/lib/libtor-process.a
|
/src/lib/libtor-process.a
|
||||||
|
@ -50,6 +50,7 @@ TOR_UTIL_LIBS = \
|
|||||||
src/lib/libtor-thread.a \
|
src/lib/libtor-thread.a \
|
||||||
src/lib/libtor-memarea.a \
|
src/lib/libtor-memarea.a \
|
||||||
src/lib/libtor-math.a \
|
src/lib/libtor-math.a \
|
||||||
|
src/lib/libtor-meminfo.a \
|
||||||
src/lib/libtor-log.a \
|
src/lib/libtor-log.a \
|
||||||
src/lib/libtor-lock.a \
|
src/lib/libtor-lock.a \
|
||||||
src/lib/libtor-fdio.a \
|
src/lib/libtor-fdio.a \
|
||||||
@ -75,6 +76,7 @@ TOR_UTIL_TESTING_LIBS = \
|
|||||||
src/lib/libtor-thread-testing.a \
|
src/lib/libtor-thread-testing.a \
|
||||||
src/lib/libtor-memarea-testing.a \
|
src/lib/libtor-memarea-testing.a \
|
||||||
src/lib/libtor-math-testing.a \
|
src/lib/libtor-math-testing.a \
|
||||||
|
src/lib/libtor-meminfo-testing.a \
|
||||||
src/lib/libtor-log-testing.a \
|
src/lib/libtor-log-testing.a \
|
||||||
src/lib/libtor-lock-testing.a \
|
src/lib/libtor-lock-testing.a \
|
||||||
src/lib/libtor-fdio-testing.a \
|
src/lib/libtor-fdio-testing.a \
|
||||||
|
@ -128,132 +128,6 @@ SecureZeroMemory(PVOID ptr, SIZE_T cnt)
|
|||||||
#include "lib/net/address.h"
|
#include "lib/net/address.h"
|
||||||
#include "lib/sandbox/sandbox.h"
|
#include "lib/sandbox/sandbox.h"
|
||||||
|
|
||||||
/** 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Hold the result of our call to <b>uname</b>. */
|
/** Hold the result of our call to <b>uname</b>. */
|
||||||
static char uname_result[256];
|
static char uname_result[256];
|
||||||
/** True iff uname_result is set. */
|
/** True iff uname_result is set. */
|
||||||
@ -351,126 +225,6 @@ get_uname,(void))
|
|||||||
* Process control
|
* Process control
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Emit the password prompt <b>prompt</b>, then read up to <b>buflen</b>
|
/** Emit the password prompt <b>prompt</b>, then read up to <b>buflen</b>
|
||||||
* bytes of passphrase into <b>output</b>. Return the number of bytes in
|
* bytes of passphrase into <b>output</b>. Return the number of bytes in
|
||||||
* the passphrase, excluding terminating NUL.
|
* the passphrase, excluding terminating NUL.
|
||||||
|
@ -87,12 +87,6 @@ typedef enum {
|
|||||||
/* ===== OS compatibility */
|
/* ===== OS compatibility */
|
||||||
MOCK_DECL(const char *, get_uname, (void));
|
MOCK_DECL(const char *, get_uname, (void));
|
||||||
|
|
||||||
#if !defined(HAVE_RLIM_T)
|
|
||||||
typedef unsigned long rlim_t;
|
|
||||||
#endif
|
|
||||||
int set_max_file_descriptors(rlim_t limit, int *max);
|
|
||||||
MOCK_DECL(int, get_total_system_memory, (size_t *mem_out));
|
|
||||||
|
|
||||||
ssize_t tor_getpass(const char *prompt, char *output, size_t buflen);
|
ssize_t tor_getpass(const char *prompt, char *output, size_t buflen);
|
||||||
|
|
||||||
/* This needs some of the declarations above so we include it here. */
|
/* This needs some of the declarations above so we include it here. */
|
||||||
|
@ -99,30 +99,6 @@
|
|||||||
/* =====
|
/* =====
|
||||||
* Memory management
|
* Memory management
|
||||||
* ===== */
|
* ===== */
|
||||||
|
|
||||||
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)
|
|
||||||
|
|
||||||
/* =====
|
/* =====
|
||||||
* Math
|
* Math
|
||||||
* ===== */
|
* ===== */
|
||||||
|
@ -42,8 +42,6 @@
|
|||||||
#include "lib/encoding/cstring.h"
|
#include "lib/encoding/cstring.h"
|
||||||
#include "lib/fs/winlib.h"
|
#include "lib/fs/winlib.h"
|
||||||
|
|
||||||
void tor_log_mallinfo(int severity);
|
|
||||||
|
|
||||||
/** Macro: yield a pointer to an enclosing structure given a pointer to
|
/** Macro: yield a pointer to an enclosing structure given a pointer to
|
||||||
* a substructure at offset <b>off</b>. Example:
|
* a substructure at offset <b>off</b>. Example:
|
||||||
* <pre>
|
* <pre>
|
||||||
|
@ -16,6 +16,7 @@ include src/lib/lock/include.am
|
|||||||
include src/lib/log/include.am
|
include src/lib/log/include.am
|
||||||
include src/lib/math/include.am
|
include src/lib/math/include.am
|
||||||
include src/lib/memarea/include.am
|
include src/lib/memarea/include.am
|
||||||
|
include src/lib/meminfo/include.am
|
||||||
include src/lib/malloc/include.am
|
include src/lib/malloc/include.am
|
||||||
include src/lib/net/include.am
|
include src/lib/net/include.am
|
||||||
include src/lib/process/include.am
|
include src/lib/process/include.am
|
||||||
|
8
src/lib/meminfo/.may_include
Normal file
8
src/lib/meminfo/.may_include
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
orconfig.h
|
||||||
|
|
||||||
|
lib/cc/*.h
|
||||||
|
lib/fs/*.h
|
||||||
|
lib/log/*.h
|
||||||
|
lib/malloc/*.h
|
||||||
|
lib/meminfo/*.h
|
||||||
|
lib/testsupport/*.h
|
17
src/lib/meminfo/include.am
Normal file
17
src/lib/meminfo/include.am
Normal file
@ -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
|
173
src/lib/meminfo/meminfo.c
Normal file
173
src/lib/meminfo/meminfo.c
Normal file
@ -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;
|
||||||
|
}
|
15
src/lib/meminfo/meminfo.h
Normal file
15
src/lib/meminfo/meminfo.h
Normal file
@ -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
|
@ -7,6 +7,7 @@ lib/err/*.h
|
|||||||
lib/fs/*.h
|
lib/fs/*.h
|
||||||
lib/log/*.h
|
lib/log/*.h
|
||||||
lib/malloc/*.h
|
lib/malloc/*.h
|
||||||
|
lib/net/*.h
|
||||||
lib/process/*.h
|
lib/process/*.h
|
||||||
lib/string/*.h
|
lib/string/*.h
|
||||||
lib/testsupport/*.h
|
lib/testsupport/*.h
|
||||||
|
@ -5,7 +5,17 @@
|
|||||||
|
|
||||||
#include "orconfig.h"
|
#include "orconfig.h"
|
||||||
#include "lib/process/restrict.h"
|
#include "lib/process/restrict.h"
|
||||||
|
#include "lib/intmath/cmp.h"
|
||||||
#include "lib/log/torlog.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
|
/* 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!
|
* also work on various BSD systems and Mac OS X - send testing feedback!
|
||||||
@ -142,3 +152,129 @@ tor_mlockall(void)
|
|||||||
return -1;
|
return -1;
|
||||||
#endif /* defined(HAVE_UNIX_MLOCKALL) */
|
#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;
|
||||||
|
}
|
||||||
|
@ -11,7 +11,17 @@
|
|||||||
#ifndef TOR_RESTRICT_H
|
#ifndef TOR_RESTRICT_H
|
||||||
#define 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_disable_debugger_attach(void);
|
||||||
int tor_mlockall(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) */
|
#endif /* !defined(TOR_RESTRICT_H) */
|
||||||
|
@ -111,6 +111,7 @@
|
|||||||
#include <shlobj.h>
|
#include <shlobj.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include "lib/meminfo/meminfo.h"
|
||||||
#include "lib/process/daemon.h"
|
#include "lib/process/daemon.h"
|
||||||
#include "lib/process/pidfile.h"
|
#include "lib/process/pidfile.h"
|
||||||
#include "lib/process/restrict.h"
|
#include "lib/process/restrict.h"
|
||||||
|
@ -111,6 +111,7 @@
|
|||||||
#include "lib/process/waitpid.h"
|
#include "lib/process/waitpid.h"
|
||||||
#include "or/ext_orport.h"
|
#include "or/ext_orport.h"
|
||||||
#include "lib/memarea/memarea.h"
|
#include "lib/memarea/memarea.h"
|
||||||
|
#include "lib/meminfo/meminfo.h"
|
||||||
#include "lib/sandbox/sandbox.h"
|
#include "lib/sandbox/sandbox.h"
|
||||||
#include "lib/fs/lockfile.h"
|
#include "lib/fs/lockfile.h"
|
||||||
#include "lib/net/buffers_net.h"
|
#include "lib/net/buffers_net.h"
|
||||||
|
@ -49,6 +49,7 @@
|
|||||||
#include "or/routerinfo_st.h"
|
#include "or/routerinfo_st.h"
|
||||||
|
|
||||||
#include "lib/fs/conffile.h"
|
#include "lib/fs/conffile.h"
|
||||||
|
#include "lib/meminfo/meminfo.h"
|
||||||
#include "lib/net/gethostname.h"
|
#include "lib/net/gethostname.h"
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -32,6 +32,7 @@
|
|||||||
#include "lib/thread/numcpus.h"
|
#include "lib/thread/numcpus.h"
|
||||||
#include "lib/math/fp.h"
|
#include "lib/math/fp.h"
|
||||||
#include "lib/math/laplace.h"
|
#include "lib/math/laplace.h"
|
||||||
|
#include "lib/meminfo/meminfo.h"
|
||||||
#include "lib/time/tvdiff.h"
|
#include "lib/time/tvdiff.h"
|
||||||
|
|
||||||
#ifdef HAVE_PWD_H
|
#ifdef HAVE_PWD_H
|
||||||
|
Loading…
Reference in New Issue
Block a user