📄 connection.c
字号:
log_warn(LD_NET,"Failing because we have %d connections already. Please "
"raise your ulimit -n.", n_conns);
control_event_general_status(LOG_WARN, "TOO_MANY_CONNECTIONS CURRENT=%d",
n_conns);
return -1;
}
s = tor_open_socket(PF_INET,SOCK_STREAM,IPPROTO_TCP);
if (s < 0) {
log_warn(LD_NET,"Error creating network socket: %s",
tor_socket_strerror(tor_socket_errno(-1)));
return -1;
}
if (options->OutboundBindAddress) {
struct sockaddr_in ext_addr;
memset(&ext_addr, 0, sizeof(ext_addr));
ext_addr.sin_family = AF_INET;
ext_addr.sin_port = 0;
if (!tor_inet_aton(options->OutboundBindAddress, &ext_addr.sin_addr)) {
log_warn(LD_CONFIG,"Outbound bind address '%s' didn't parse. Ignoring.",
options->OutboundBindAddress);
} else {
if (bind(s, (struct sockaddr*)&ext_addr,
(socklen_t)sizeof(ext_addr)) < 0) {
log_warn(LD_NET,"Error binding network socket: %s",
tor_socket_strerror(tor_socket_errno(s)));
tor_close_socket(s);
return -1;
}
}
}
set_socket_nonblocking(s);
if (options->ConstrainedSockets)
set_constrained_socket_buffers(s, (int)options->ConstrainedSockSize);
memset(&dest_addr,0,sizeof(dest_addr));
dest_addr.sin_family = AF_INET;
dest_addr.sin_port = htons(port);
dest_addr.sin_addr.s_addr = htonl(addr);
log_debug(LD_NET,"Connecting to %s:%u.",escaped_safe_str(address),port);
if (connect(s,(struct sockaddr *)&dest_addr,
(socklen_t)sizeof(dest_addr)) < 0) {
int e = tor_socket_errno(s);
if (!ERRNO_IS_CONN_EINPROGRESS(e)) {
/* yuck. kill it. */
log_info(LD_NET,
"connect() to %s:%u failed: %s",escaped_safe_str(address),
port, tor_socket_strerror(e));
tor_close_socket(s);
return -1;
} else {
inprogress = 1;
}
}
if (!server_mode(options))
client_check_address_changed(s);
/* it succeeded. we're connected. */
log_fn(inprogress?LOG_DEBUG:LOG_INFO, LD_NET,
"Connection to %s:%u %s (sock %d).",escaped_safe_str(address),
port, inprogress?"in progress":"established", s);
conn->s = s;
if (connection_add(conn) < 0) /* no space, forget it */
return -1;
return inprogress ? 0 : 1;
}
/**
* Launch any configured listener connections of type <b>type</b>. (A
* listener is configured if <b>port_option</b> is non-zero. If any
* ListenAddress configuration options are given in <b>cfg</b>, create a
* connection binding to each one. Otherwise, create a single
* connection binding to the address <b>default_addr</b>.)
*
* Only launch the listeners of this type that are not already open, and
* only close listeners that are no longer wanted. Existing listeners
* that are still configured are not touched.
*
* If <b>disable_all_conns</b> is set, then never open new conns, and
* close the existing ones.
*
* Add all old conns that should be closed to <b>replaced_conns</b>.
* Add all new connections to <b>new_conns</b>.
*/
static int
retry_listeners(int type, config_line_t *cfg,
int port_option, const char *default_addr,
smartlist_t *replaced_conns,
smartlist_t *new_conns,
int disable_all_conns,
int socket_family)
{
smartlist_t *launch = smartlist_create(), *conns;
int free_launch_elts = 1;
int r;
config_line_t *c;
connection_t *conn;
config_line_t *line;
tor_assert(socket_family == AF_INET || socket_family == AF_UNIX);
if (cfg && port_option) {
for (c = cfg; c; c = c->next) {
smartlist_add(launch, c);
}
free_launch_elts = 0;
} else if (port_option) {
line = tor_malloc_zero(sizeof(config_line_t));
line->key = tor_strdup("");
line->value = tor_strdup(default_addr);
smartlist_add(launch, line);
}
/*
SMARTLIST_FOREACH(launch, config_line_t *, l,
log_fn(LOG_NOTICE, "#%s#%s", l->key, l->value));
*/
conns = get_connection_array();
SMARTLIST_FOREACH(conns, connection_t *, conn,
{
if (conn->type != type ||
conn->socket_family != socket_family ||
conn->marked_for_close)
continue;
/* Okay, so this is a listener. Is it configured? */
line = NULL;
SMARTLIST_FOREACH(launch, config_line_t *, wanted,
{
char *address=NULL;
uint16_t port;
switch (socket_family) {
case AF_INET:
if (!parse_addr_port(LOG_WARN,
wanted->value, &address, NULL, &port)) {
int addr_matches = !strcasecmp(address, conn->address);
tor_free(address);
if (! port)
port = port_option;
if (port == conn->port && addr_matches) {
line = wanted;
break;
}
}
break;
case AF_UNIX:
if (!strcasecmp(wanted->value, conn->address)) {
line = wanted;
break;
}
break;
default:
tor_assert(0);
}
});
if (!line || disable_all_conns) {
/* This one isn't configured. Close it. */
log_notice(LD_NET, "Closing no-longer-configured %s on %s:%d",
conn_type_to_string(type), conn->address, conn->port);
if (replaced_conns) {
smartlist_add(replaced_conns, conn);
} else {
connection_close_immediate(conn);
connection_mark_for_close(conn);
}
} else {
/* It's configured; we don't need to launch it. */
// log_debug(LD_NET, "Already have %s on %s:%d",
// conn_type_to_string(type), conn->address, conn->port);
smartlist_remove(launch, line);
if (free_launch_elts)
config_free_lines(line);
}
});
/* Now open all the listeners that are configured but not opened. */
r = 0;
if (!disable_all_conns) {
SMARTLIST_FOREACH(launch, config_line_t *, cfg_line,
{
char *address = NULL;
struct sockaddr *listensockaddr;
switch (socket_family) {
case AF_INET:
listensockaddr = (struct sockaddr *)
create_inet_sockaddr(cfg_line->value,
(uint16_t) port_option,
&address);
break;
case AF_UNIX:
listensockaddr = (struct sockaddr *)
create_unix_sockaddr(cfg_line->value,
&address);
break;
default:
tor_assert(0);
}
if (listensockaddr) {
conn = connection_create_listener(listensockaddr, type, address);
tor_free(listensockaddr);
tor_free(address);
} else
conn = NULL;
if (!conn) {
r = -1;
} else {
if (new_conns)
smartlist_add(new_conns, conn);
}
});
}
if (free_launch_elts) {
SMARTLIST_FOREACH(launch, config_line_t *, cfg_line,
config_free_lines(cfg_line));
}
smartlist_free(launch);
return r;
}
/** Launch listeners for each port you should have open. Only launch
* listeners who are not already open, and only close listeners we no longer
* want.
*
* Add all old conns that should be closed to <b>replaced_conns</b>.
* Add all new connections to <b>new_conns</b>.
*/
int
retry_all_listeners(smartlist_t *replaced_conns,
smartlist_t *new_conns)
{
or_options_t *options = get_options();
if (retry_listeners(CONN_TYPE_OR_LISTENER, options->ORListenAddress,
options->ORPort, "0.0.0.0",
replaced_conns, new_conns, options->ClientOnly,
AF_INET)<0)
return -1;
if (retry_listeners(CONN_TYPE_DIR_LISTENER, options->DirListenAddress,
options->DirPort, "0.0.0.0",
replaced_conns, new_conns, options->ClientOnly,
AF_INET)<0)
return -1;
if (retry_listeners(CONN_TYPE_AP_LISTENER, options->SocksListenAddress,
options->SocksPort, "127.0.0.1",
replaced_conns, new_conns, 0,
AF_INET)<0)
return -1;
if (retry_listeners(CONN_TYPE_AP_TRANS_LISTENER, options->TransListenAddress,
options->TransPort, "127.0.0.1",
replaced_conns, new_conns, 0,
AF_INET)<0)
return -1;
if (retry_listeners(CONN_TYPE_AP_NATD_LISTENER, options->NatdListenAddress,
options->NatdPort, "127.0.0.1",
replaced_conns, new_conns, 0,
AF_INET)<0)
return -1;
if (retry_listeners(CONN_TYPE_AP_DNS_LISTENER, options->DNSListenAddress,
options->DNSPort, "127.0.0.1",
replaced_conns, new_conns, 0,
AF_INET)<0)
return -1;
if (retry_listeners(CONN_TYPE_CONTROL_LISTENER,
options->ControlListenAddress,
options->ControlPort, "127.0.0.1",
replaced_conns, new_conns, 0,
AF_INET)<0)
return -1;
if (retry_listeners(CONN_TYPE_CONTROL_LISTENER,
options->ControlSocket,
options->ControlSocket ? 1 : 0, NULL,
replaced_conns, new_conns, 0,
AF_UNIX)<0)
return -1;
return 0;
}
/** Return 1 if we should apply rate limiting to <b>conn</b>,
* and 0 otherwise. Right now this just checks if it's an internal
* IP address or an internal connection. */
static int
connection_is_rate_limited(connection_t *conn)
{
if (conn->linked || is_internal_IP(conn->addr, 0))
return 0;
else
return 1;
}
extern int global_read_bucket, global_write_bucket;
extern int global_relayed_read_bucket, global_relayed_write_bucket;
/** Did either global write bucket run dry last second? If so,
* we are likely to run dry again this second, so be stingy with the
* tokens we just put in. */
static int write_buckets_empty_last_second = 0;
/** How many seconds of no active local circuits will make the
* connection revert to the "relayed" bandwidth class? */
#define CLIENT_IDLE_TIME_FOR_PRIORITY 30
/** Return 1 if <b>conn</b> should use tokens from the "relayed"
* bandwidth rates, else 0. Currently, only OR conns with bandwidth
* class 1, and directory conns that are serving data out, count.
*/
static int
connection_counts_as_relayed_traffic(connection_t *conn, time_t now)
{
if (conn->type == CONN_TYPE_OR &&
TO_OR_CONN(conn)->client_used + CLIENT_IDLE_TIME_FOR_PRIORITY < now)
return 1;
if (conn->type == CONN_TYPE_DIR && DIR_CONN_IS_SERVER(conn))
return 1;
return 0;
}
/** Helper function to decide how many bytes out of <b>global_bucket</b>
* we're willing to use for this transaction. <b>base</b> is the size
* of a cell on the network; <b>priority</b> says whether we should
* write many of them or just a few; and <b>conn_bucket</b> (if
* non-negative) provides an upper limit for our answer. */
static ssize_t
connection_bucket_round_robin(int base, int priority,
ssize_t global_bucket, ssize_t conn_bucket)
{
ssize_t at_most;
ssize_t num_bytes_high = (priority ? 32 : 16) * base;
ssize_t num_bytes_low = (priority ? 4 : 2) * base;
/* Do a rudimentary round-robin so one circuit can't hog a connection.
* Pick at most 32 cells, at least 4 cells if possible, and if we're in
* the middle pick 1/8 of the available bandwidth. */
at_most = global_bucket / 8;
at_most -= (at_most % base); /* round down */
if (at_most > num_bytes_high) /* 16 KB, or 8 KB for low-priority */
at_most = num_bytes_high;
else if (at_most < num_bytes_low) /* 2 KB, or 1 KB for low-priority */
at_most = num_bytes_low;
if (at_most > global_bucket)
at_most = global_bucket;
if (conn_bucket >= 0 && at_most > conn_bucket)
at_most = conn_bucket;
if (at_most < 0)
return 0;
return at_most;
}
/** How many bytes at most can we read onto this connection? */
static ssize_t
connection_bucket_read_limit(connection_t *conn, time_t now)
{
int base = connection_speaks_cells(conn) ?
CELL_NETWORK_SIZE : RELAY_PAYLOAD_SIZE;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -