r13773@catbus: nickm | 2007-07-16 11:58:25 -0400

Initial "constrained socket buffers" patch from coderman. needs tweaking.


svn:r10842
This commit is contained in:
Nick Mathewson 2007-07-16 16:23:34 +00:00
parent 6d2cb32d10
commit f4a6673758
4 changed files with 98 additions and 0 deletions

View File

@ -101,6 +101,33 @@ You probably don't need to adjust this. It has no effect on
Windows since that platform lacks getrlimit(). (Default: 1000) Windows since that platform lacks getrlimit(). (Default: 1000)
.LP .LP
.TP .TP
\fBConstrainedSockets \fR\fB0\fR|\fB1\fR\fP
If set, Tor will attempt to shrink the recv and xmit buffers for all
sockets to the size specified in \fBConstrainedSockSize\fP. This is useful
for virtual servers and other environments where system level TCP
buffers may be limited. If you encounter the "Error creating network
socket: No buffer space available" message you are likely experiencing
this problem.
The preferred solution is to have the admin increase the buffer pool for
the host itself via /proc/sys/net/ipv4/tcp_mem or equivalent facility.
The DirPort option should also not be used if TCP buffers are scarce. The
cached directory requests consume additional sockets which exacerbates the
problem.
You should \fBnot\fP enable this feature unless you encounter the no buffer
space available issue. Reducing the TCP buffers affects window size for
for the TCP stream and will reduce throughput in proportion to round trip
time on long paths.
.LP
.TP
\fBConstrainedSockSize \fR\fINUM\fP
When \fBConstrainedSockets\fP is enabled the recv and xmit buffers for
all sockets will be set to this limit. Must be a value between 2048
and 262144 in 1024 byte increments. Default of 8192 is recommended.
.LP
.TP
\fBControlPort \fR\fIPort\fP \fBControlPort \fR\fIPort\fP
If set, Tor will accept connections on this port and allow those If set, Tor will accept connections on this port and allow those
connections to control the Tor process using the Tor Control Protocol connections to control the Tor process using the Tor Control Protocol

View File

@ -146,6 +146,8 @@ static config_var_t _option_vars[] = {
VAR("CircuitIdleTimeout", INTERVAL, CircuitIdleTimeout, "1 hour"), VAR("CircuitIdleTimeout", INTERVAL, CircuitIdleTimeout, "1 hour"),
VAR("ClientOnly", BOOL, ClientOnly, "0"), VAR("ClientOnly", BOOL, ClientOnly, "0"),
VAR("ConnLimit", UINT, ConnLimit, "1000"), VAR("ConnLimit", UINT, ConnLimit, "1000"),
VAR("ConstrainedSockets", BOOL, ConstrainedSockets, "0"),
VAR("ConstrainedSockSize", UINT, ConstrainedSockSize, "8192"),
VAR("ContactInfo", STRING, ContactInfo, NULL), VAR("ContactInfo", STRING, ContactInfo, NULL),
VAR("ControlListenAddress",LINELIST, ControlListenAddress, NULL), VAR("ControlListenAddress",LINELIST, ControlListenAddress, NULL),
VAR("ControlPort", UINT, ControlPort, "0"), VAR("ControlPort", UINT, ControlPort, "0"),
@ -330,6 +332,11 @@ static config_var_description_t options_description[] = {
{ "BandwidthBurst", "Limit the maximum token buffer size (also known as " { "BandwidthBurst", "Limit the maximum token buffer size (also known as "
"burst) to the given number of bytes." }, "burst) to the given number of bytes." },
{ "ConnLimit", "Maximum number of simultaneous sockets allowed." }, { "ConnLimit", "Maximum number of simultaneous sockets allowed." },
{ "ConstrainedSockets", "Shrink tx and rx buffers for sockets to avoid "
"system limits on vservers and related environments. See man page for "
"more information regarding this option." },
{ "ConstrainedSockSize", "Limit socket buffers to this size when "
"ConstrainedSockets is enabled." },
/* ControlListenAddress */ /* ControlListenAddress */
{ "ControlPort", "If set, Tor will accept connections from the same machine " { "ControlPort", "If set, Tor will accept connections from the same machine "
"(localhost only) on this port, and allow those connections to control " "(localhost only) on this port, and allow those connections to control "
@ -2925,6 +2932,29 @@ options_validate(or_options_t *old_options, or_options_t *options,
} }
} }
if (options->ConstrainedSockets) {
/* If the user wants to constrain socket buffer use, make sure the desired
* limit is between MIN|MAX_TCPSOCK_BUFFER in k increments. */
if (options->ConstrainedSockSize < MIN_TCPSOCK_BUFFER ||
options->ConstrainedSockSize > MAX_TCPSOCK_BUFFER ||
options->ConstrainedSockSize % 1024 ) {
r = tor_snprintf(buf, sizeof(buf),
"ConstrainedSockSize is invalid. Must be a value between %d and %d "
"in 1024 byte increments.",
MIN_TCPSOCK_BUFFER, MAX_TCPSOCK_BUFFER);
*msg = tor_strdup(r >= 0 ? buf : "internal error");
return -1;
}
if (options->DirPort) {
/* Providing cached directory entries while system TCP buffers are scarce
* will exacerbate the socket errors. Suggest that this be disabled. */
COMPLAIN("You have requested constrained socket buffers while also "
"serving directory entries via DirPort. It is strongly "
"suggested that you disable serving directory requests when "
"system TCP buffer resources are scarce.");
}
}
if (rend_config_services(options, 1) < 0) if (rend_config_services(options, 1) < 0)
REJECT("Failed to configure rendezvous options. See logs for details."); REJECT("Failed to configure rendezvous options. See logs for details.");

View File

@ -28,6 +28,7 @@ static int connection_reached_eof(connection_t *conn);
static int connection_read_to_buf(connection_t *conn, int *max_to_read); static int connection_read_to_buf(connection_t *conn, int *max_to_read);
static int connection_process_inbuf(connection_t *conn, int package_partial); static int connection_process_inbuf(connection_t *conn, int package_partial);
static void client_check_address_changed(int sock); static void client_check_address_changed(int sock);
static void set_constrained_socket_buffers(int sock, int size);
static uint32_t last_interface_ip = 0; static uint32_t last_interface_ip = 0;
static smartlist_t *outgoing_addrs = NULL; static smartlist_t *outgoing_addrs = NULL;
@ -898,6 +899,8 @@ connection_handle_listener_read(connection_t *conn, int new_type)
/* length of the remote address. Must be whatever accept() needs. */ /* length of the remote address. Must be whatever accept() needs. */
socklen_t remotelen = 256; socklen_t remotelen = 256;
char tmpbuf[INET_NTOA_BUF_LEN]; char tmpbuf[INET_NTOA_BUF_LEN];
or_options_t *options = get_options();
tor_assert((size_t)remotelen >= sizeof(struct sockaddr_in)); tor_assert((size_t)remotelen >= sizeof(struct sockaddr_in));
memset(addrbuf, 0, sizeof(addrbuf)); memset(addrbuf, 0, sizeof(addrbuf));
@ -923,6 +926,10 @@ connection_handle_listener_read(connection_t *conn, int new_type)
set_socket_nonblocking(news); set_socket_nonblocking(news);
if (options->ConstrainedSockets) {
set_constrained_socket_buffers (news, options->ConstrainedSockSize);
}
tor_assert(((struct sockaddr*)addrbuf)->sa_family == conn->socket_family); tor_assert(((struct sockaddr*)addrbuf)->sa_family == conn->socket_family);
if (conn->socket_family == AF_INET) { if (conn->socket_family == AF_INET) {
@ -1096,6 +1103,10 @@ connection_connect(connection_t *conn, const char *address,
set_socket_nonblocking(s); set_socket_nonblocking(s);
if (options->ConstrainedSockets) {
set_constrained_socket_buffers (s, options->ConstrainedSockSize);
}
memset(&dest_addr,0,sizeof(dest_addr)); memset(&dest_addr,0,sizeof(dest_addr));
dest_addr.sin_family = AF_INET; dest_addr.sin_family = AF_INET;
dest_addr.sin_port = htons(port); dest_addr.sin_port = htons(port);
@ -2540,6 +2551,29 @@ client_check_address_changed(int sock)
} }
} }
/** Some systems have limited system buffers for recv and xmit on
* sockets allocated in a virtual server or similar environment. For a Tor
* server this can produce the "Error creating network socket: No buffer
* space available" error once all available TCP buffer space is consumed.
* This method will attempt to constrain the buffers allocated for the socket
* to the desired size to stay below system TCP buffer limits.
*/
static void
set_constrained_socket_buffers(int sock, int size)
{
if (setsockopt(sock, SOL_SOCKET, SO_SNDBUF, (const char *)&size, sizeof(size)) < 0) {
int e = tor_socket_errno(sock);
log_warn(LD_NET, "setsockopt() to constrain send buffer to %d bytes failed: %s",
size, tor_socket_strerror(e));
}
if (setsockopt(sock, SOL_SOCKET, SO_RCVBUF, (const char *)&size, sizeof(size)) < 0) {
int e = tor_socket_errno(sock);
log_warn(LD_NET, "setsockopt() to constrain recv buffer to %d bytes failed: %s",
size, tor_socket_strerror(e));
}
return;
}
/** Process new bytes that have arrived on conn-\>inbuf. /** Process new bytes that have arrived on conn-\>inbuf.
* *
* This function just passes conn to the connection-specific * This function just passes conn to the connection-specific

View File

@ -1748,6 +1748,10 @@ typedef struct exit_redirect_t {
unsigned is_redirect:1; unsigned is_redirect:1;
} exit_redirect_t; } exit_redirect_t;
/* limits for TCP send and recv buffer size used for constrained sockets */
#define MIN_TCPSOCK_BUFFER 2048
#define MAX_TCPSOCK_BUFFER 262144 /* 256k */
/** A linked list of lines in a config file. */ /** A linked list of lines in a config file. */
typedef struct config_line_t { typedef struct config_line_t {
char *key; char *key;
@ -1889,6 +1893,9 @@ typedef struct {
config_line_t *ReachableORAddresses; /**< IP:ports for OR conns. */ config_line_t *ReachableORAddresses; /**< IP:ports for OR conns. */
config_line_t *ReachableDirAddresses; /**< IP:ports for Dir conns. */ config_line_t *ReachableDirAddresses; /**< IP:ports for Dir conns. */
int ConstrainedSockets; /**< Shrink xmit and recv socket buffers. */
int ConstrainedSockSize; /**< Size of constrained buffers. */
/** Application ports that require all nodes in circ to have sufficient /** Application ports that require all nodes in circ to have sufficient
* uptime. */ * uptime. */
smartlist_t *LongLivedPorts; smartlist_t *LongLivedPorts;