Commit 0362cdc1 authored by Nick Mathewson's avatar Nick Mathewson 🤹
Browse files

Move fd and memory-info functions.

parent 973afcc4
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -191,6 +191,8 @@ uptime-*.json
/src/lib/libtor-math-testing.a
/src/lib/libtor-memarea.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-testing.a
/src/lib/libtor-process.a
+2 −0
Original line number Diff line number Diff line
@@ -50,6 +50,7 @@ TOR_UTIL_LIBS = \
	src/lib/libtor-thread.a \
	src/lib/libtor-memarea.a \
	src/lib/libtor-math.a \
        src/lib/libtor-meminfo.a \
	src/lib/libtor-log.a \
	src/lib/libtor-lock.a \
	src/lib/libtor-fdio.a \
@@ -75,6 +76,7 @@ TOR_UTIL_TESTING_LIBS = \
	src/lib/libtor-thread-testing.a \
	src/lib/libtor-memarea-testing.a \
	src/lib/libtor-math-testing.a \
        src/lib/libtor-meminfo-testing.a \
	src/lib/libtor-log-testing.a \
	src/lib/libtor-lock-testing.a \
	src/lib/libtor-fdio-testing.a \
+0 −246
Original line number Diff line number Diff line
@@ -128,132 +128,6 @@ SecureZeroMemory(PVOID ptr, SIZE_T cnt)
#include "lib/net/address.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>. */
static char uname_result[256];
/** True iff uname_result is set. */
@@ -351,126 +225,6 @@ get_uname,(void))
 *   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>
 * bytes of passphrase into <b>output</b>. Return the number of bytes in
 * the passphrase, excluding terminating NUL.
+0 −6
Original line number Diff line number Diff line
@@ -87,12 +87,6 @@ typedef enum {
/* ===== OS compatibility */
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);

/* This needs some of the declarations above so we include it here. */
+0 −24
Original line number Diff line number Diff line
@@ -99,30 +99,6 @@
/* =====
 * 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
 * ===== */
Loading