TOR源码阅读(二)




今天阅读的内容是一段时间浏览后觉得有必要详细理解的部分,这里由于项目原因不进行具体的技术和语法等等分析,只做功能逻辑分析。

line 1008 in file main.c

run_connection_housekeeping(int i,time_t now) 函数,用于长期的单个连接上的持久性任务,被run_scheduled_ecents()每秒钟周期性调用。

我们来看它做了什么 获取第i个连接,获取当前配置选项结构体,判断当前时间是否超过连接生存周期,查看连接输出缓冲区是否已为空,若为空则进行标记,若连接标记为关闭,结束当前函数。

{
cell_t cell;
connection_t *conn =
smartlist_get(connection_array, i);
const
or_options_t *options =
get_options();
or_connection_t *or_conn;
channel_t *chan =
NULL;
int have_any_circuits;
int past_keepalive =
now >= conn->
timestamp_lastwritten + options->
KeepalivePeriod;

if (conn->
outbuf && !
connection_get_outbuf_len(conn) &&
conn->
type == CONN_TYPE_OR)
TO_OR_CONN(conn)->
timestamp_lastempty = now;

if (conn->
marked_for_close) {
/* nothing to do here */
return;
}

。若连接类型为目录连接,连接活动超时(如果是服务器则为发送,如果为客户端则为接收),打印日志。判断连接目的是否为获取服务器的文件描述符,且读入缓冲已大于1024字节,若是则该连接已满,若不是,则标记连接为已关闭。若连接既非目录连接也非OR连接,则退出函数。

if (conn->
type == CONN_TYPE_DIR &&
((
DIR_CONN_IS_SERVER(conn) &&
conn->
timestamp_lastwritten
+ options->
TestingDirConnectionMaxStall < now) ||
(!
DIR_CONN_IS_SERVER(conn) &&
conn->
timestamp_lastread
+ options->
TestingDirConnectionMaxStall < now))) {
log_info(LD_DIR,
“Expiring wedged directory conn (fd %d, purpose %d)”,
(
int)conn->
s, conn->
purpose);
/* This check is temporary; it’s to let us know whether we should consider
* parsing partial serverdesc responses. */
if (conn->
purpose == DIR_PURPOSE_FETCH_SERVERDESC &&
connection_get_inbuf_len(conn) >=
1024) {
log_info(LD_DIR,
“Trying to extract information from wedged server desc “
“download.”);
connection_dir_reached_eof(
TO_DIR_CONN(conn));
}
else {
connection_mark_for_close(conn);
}
return;
}

if (!
connection_speaks_cells(conn))
return;

连接为OR连接时,若通道上存在链路,则设置当前时间戳为有链路存在的最新时间。若通道上不适合产生新链路,且当前并无链路在其上,则标记之,且若连接状态为已连接,则放弃该连接。若连接并未打开,则连接正常关闭。若连接空闲,且无链路,输出缓冲区为空,则关闭之。若连接超时,也关闭之。若连接仍在生存期内但无数据待发送,则发送一个填充数据元保持链路可用。若均不是,即正常可用通道,则进行通道填充。

if (
channel_is_bad_for_new_circs(
TLS_CHAN_TO_BASE(or_conn->
chan)) &&
! have_any_circuits) {
/* It’s bad for new circuits, and has no unmarked circuits on it:
* mark it now. */
log_info(LD_OR,
“Expiring non-used OR connection to fd %d (%s:%d) [Too old].”,
(
int)conn->
s, conn->
address, conn->
port);
if (conn->
state == OR_CONN_STATE_CONNECTING)
connection_or_connect_failed(
TO_OR_CONN(conn),
END_OR_CONN_REASON_TIMEOUT,
“Tor gave up on the connection”);
connection_or_close_normally(
TO_OR_CONN(conn),
1);
}
else
if (!
connection_state_is_open(conn)) {
if (past_keepalive) {
/* We never managed to actually get this connection open and happy. */
log_info(LD_OR,
“Expiring non-open OR connection to fd %d (%s:%d).”,
(
int)conn->
s,conn->
address, conn->
port);
connection_or_close_normally(
TO_OR_CONN(conn),
0);
}
}
else
if (
we_are_hibernating() &&
! have_any_circuits &&
!
connection_get_outbuf_len(conn)) {
/* We’re hibernating, there’s no circuits, and nothing to flush.*/
log_info(LD_OR,
“Expiring non-used OR connection to fd %d (%s:%d) “
“[Hibernating or exiting].”,
(
int)conn->
s,conn->
address, conn->
port);
connection_or_close_normally(
TO_OR_CONN(conn),
1);
}
else
if (!have_any_circuits &&
now – or_conn->
idle_timeout >=
chan->
timestamp_last_had_circuits) {
log_info(LD_OR,
“Expiring non-used OR connection “U64_FORMAT
” to fd %d “
“(%s:%d) [no circuits for %d; timeout %d; %scanonical].”,
U64_PRINTF_ARG(chan->
global_identifier),
(
int)conn->
s, conn->
address, conn->
port,
(
int)(now – chan->
timestamp_last_had_circuits),
or_conn->
idle_timeout,
or_conn->
is_canonical ?
“” :
“non”);
connection_or_close_normally(
TO_OR_CONN(conn),
0);
}
else
if (
now >= or_conn->
timestamp_lastempty + options->
KeepalivePeriod*
10 &&
now >= conn->
timestamp_lastwritten + options->
KeepalivePeriod*
10) {
log_fn(LOG_PROTOCOL_WARN,LD_PROTOCOL,
“Expiring stuck OR connection to fd %d (%s:%d). (%d bytes to “
“flush; %d seconds since last write)”,
(
int)conn->
s, conn->
address, conn->
port,
(
int)
connection_get_outbuf_len(conn),
(
int)(now-conn->
timestamp_lastwritten));
connection_or_close_normally(
TO_OR_CONN(conn),
0);
}
else
if (past_keepalive && !
connection_get_outbuf_len(conn)) {
/* send a padding cell */
log_fn(LOG_DEBUG,LD_OR,
“Sending keepalive to (%s:%d)”,
conn->
address, conn->
port);
memset(&cell,
0,
sizeof(
cell_t));
cell.
command = CELL_PADDING;
connection_or_write_cell_to_buf(&cell, or_conn);
}
else {
channelpadding_decide_to_pad_channel(chan);
}

开发者思维之缜密再一次使我惊叹,我们所关注的数据填充部分可以下移到channelpadding_decide_to_pad_channel(chan)上。因为我们可以探究若为可用OR连接时,他们会怎么进行通道的填充。

发布了24 篇原创文章 ·
获赞 4 ·
访问量 1万+