diff --git a/src/common/compat.c b/src/common/compat.c index 095f1b2f71..7667dd3541 100644 --- a/src/common/compat.c +++ b/src/common/compat.c @@ -357,37 +357,51 @@ tor_socketpair(int family, int type, int protocol, int fd[2]) #endif } +#define ULIMIT_BUFFER 32 /* keep 32 extra fd's beyond _ConnLimit */ + /** Get the maximum allowed number of file descriptors. (Some systems * have a low soft limit.) Make sure we set it to at least - * required_min. Return 0 if we can, or -1 if we fail. */ -int set_max_file_descriptors(unsigned int required_min) { + * *limit. Return a new limit if we can, or -1 if we fail. */ +int set_max_file_descriptors(int limit, int cap) { #ifndef HAVE_GETRLIMIT log_fn(LOG_INFO,"This platform is missing getrlimit(). Proceeding."); - return 0; /* hope we'll be ok */ + if (limit > cap) { + log(LOG_INFO, "ConnLimit must be at most %d. Capping it.", cap); + limit = cap; + } #else struct rlimit rlim; + int most; if (getrlimit(RLIMIT_NOFILE, &rlim) != 0) { log_fn(LOG_WARN, "Could not get maximum number of file descriptors: %s", strerror(errno)); return -1; } - if (required_min > rlim.rlim_max) { - log_fn(LOG_WARN,"We need %u file descriptors available, and we're limited to %lu. Please change your ulimit.", required_min, (unsigned long int)rlim.rlim_max); + if (rlim.rlim_max < limit) { + log_fn(LOG_WARN,"We need %d file descriptors available, and we're limited to %lu. Please change your ulimit -n.", limit, (unsigned long int)rlim.rlim_max); return -1; } - if (required_min > rlim.rlim_cur) { - log_fn(LOG_INFO,"Raising max file descriptors from %lu to %lu.", - (unsigned long int)rlim.rlim_cur, (unsigned long int)rlim.rlim_max); + most = ((rlim.rlim_max > cap) ? cap : rlim.rlim_max); + if (most > rlim.rlim_cur) { + log_fn(LOG_INFO,"Raising max file descriptors from %lu to %d.", + (unsigned long int)rlim.rlim_cur, most); } - rlim.rlim_cur = rlim.rlim_max; + rlim.rlim_cur = most; if (setrlimit(RLIMIT_NOFILE, &rlim) != 0) { log_fn(LOG_WARN, "Could not set maximum number of file descriptors: %s", strerror(errno)); return -1; } - return 0; + /* leave some overhead for logs, etc, */ + limit = most; #endif + + if (limit < ULIMIT_BUFFER) { + log_fn(LOG_WARN,"ConnLimit must be at least %d. Failing.", ULIMIT_BUFFER); + return -1; + } + return limit - ULIMIT_BUFFER; } /** Call setuid and setgid to run as user:group. Return 0 on diff --git a/src/common/compat.h b/src/common/compat.h index ec433ddd7b..f813becbcb 100644 --- a/src/common/compat.h +++ b/src/common/compat.h @@ -195,7 +195,7 @@ void set_uint16(char *cp, uint16_t v); void set_uint32(char *cp, uint32_t v); #endif -int set_max_file_descriptors(unsigned int required_min); +int set_max_file_descriptors(int limit, int cap); int switch_id(char *user, char *group); #ifdef HAVE_PWD_H char *get_user_homedir(const char *username); diff --git a/src/or/config.c b/src/or/config.c index 2e69de2602..7fa6fe853c 100644 --- a/src/or/config.c +++ b/src/or/config.c @@ -64,6 +64,7 @@ static config_abbrev_t config_abbrevs[] = { { "BandwidthRateBytes", "BandwidthRate", 0}, { "BandwidthBurstBytes", "BandwidthBurst", 0}, { "DirFetchPostPeriod", "StatusFetchPeriod", 0}, + { "MaxConn", "ConnLimit", 0}, { NULL, NULL , 0}, }; #undef PLURAL @@ -141,7 +142,7 @@ static config_var_t config_vars[] = { VAR("LogLevel", LINELIST_S, OldLogOptions, NULL), VAR("LogFile", LINELIST_S, OldLogOptions, NULL), OBSOLETE("LinkPadding"), - VAR("MaxConn", UINT, MaxConn, "1024"), + VAR("ConnLimit", UINT, ConnLimit, "1024"), VAR("MaxOnionsPending", UINT, MaxOnionsPending, "100"), VAR("MonthlyAccountingStart",UINT, _MonthlyAccountingStart,"0"), VAR("AccountingMaxKB", UINT, _AccountingMaxKB, "0"), @@ -312,7 +313,9 @@ options_act(void) { close_temp_logs(); add_callback_log(LOG_NOTICE, LOG_ERR, control_event_logmsg); - if (set_max_file_descriptors(options->MaxConn) < 0) + options->_ConnLimit = + set_max_file_descriptors(options->ConnLimit, MAXCONNECTIONS); + if (options->_ConnLimit < 0) return -1; { @@ -1345,16 +1348,6 @@ options_validate(or_options_t *options) result = -1; } - if (options->MaxConn < 1) { - log(LOG_WARN, "MaxConn option must be a non-zero positive integer."); - result = -1; - } - - if (options->MaxConn > MAXCONNECTIONS) { - log(LOG_WARN, "MaxConn option must be at most %d.", MAXCONNECTIONS); - result = -1; - } - #define MIN_DIR_FETCH_PERIOD 600 #define MIN_DIR_POST_PERIOD 300 #define MIN_REND_POST_PERIOD 300 diff --git a/src/or/main.c b/src/or/main.c index a629d45422..6ac83e1728 100644 --- a/src/or/main.c +++ b/src/or/main.c @@ -118,8 +118,8 @@ int connection_add(connection_t *conn) { tor_assert(conn); tor_assert(conn->s >= 0); - if (nfds >= get_options()->MaxConn-1) { - log_fn(LOG_WARN,"Failing because we have %d connections already. Please set MaxConn higher.", nfds); + if (nfds >= get_options()->_ConnLimit-1) { + log_fn(LOG_WARN,"Failing because we have %d connections already. Please raise your ulimit -n.", nfds); return -1; } diff --git a/src/or/or.h b/src/or/or.h index 059adefa57..12d07c2985 100644 --- a/src/or/or.h +++ b/src/or/or.h @@ -948,7 +948,8 @@ typedef struct { int DirPort; /**< Port to listen on for directory connections. */ int AuthoritativeDir; /**< Boolean: is this an authoritative directory? */ int ClientOnly; /**< Boolean: should we never evolve into a server role? */ - int MaxConn; /**< Maximum number of simultaneous connections. */ + int ConnLimit; /**< Requested maximum number of simultaneous connections. */ + int _ConnLimit; /**< Actual maximum number of simultaneous connections. */ int IgnoreVersion; /**< If true, run no matter what versions of Tor the * directory recommends. */ int RunAsDaemon; /**< If true, run in the background. (Unix only) */