Tor源码文件分析 -- Main
2013-04-27 16:50
495 查看
Main文件是Tor系统的主要执行函数所处文件,内容偏多,但是较于其他底层处理函数所在的文件,也算较少。所以这里做简要的分析,其中删去很多不常见的,不重要的函数,大家可以自行在源文件内部查看。
1)系统(先前)已读与已写字节数以及用于流量控制的令牌桶全局变量;(先前与当前已读写字节数的区别与refill回调函数相关)
令牌桶用于控制整个系统的流量,经过初始化,减少,增加等操作(当读写相应的令牌数不够时,系统或连接会停止读或写):
先前已读写字节数全局变量的具体赋值处于函数second_elapsed_callback之中,其他地方没有引用:
当前已读写字节数全局变量的具体赋值处于函数refill_callback之中,其他地方没有引用:
2)系统启动时间和运行时间;
系统启动时间初始化于Tor系统初始化阶段,未曾修改过:
系统运行时间在函数second_elapsed_callback中随时间增加;在系统发生重要变故的时候会被重新设置为0,例如hibernation,Ip改变等情况。
3)启动下次DNS检查的时间;
只有在系统配置为服务器时候才使用,改变部分在函数run_scheduled_events之中,此处略去。
4)newnym相关变量;
newnym信号相关变量均于信号处理函数内部进行改变,入口大致为:
5)三大连接链表全局变量:全连接链表,可关闭的连接链表,活动的linked连接列表;(linked连接的含义,在Tor源码分析中会提到)
这三个连接链表因为引用非常多,不可能贴出其主要引用位置。大致的可以说,当系统出现相关连接时,会被加入到相关连接列表中:全部的,可关闭的,活动的linked。当系统删除相关连接时,这些对应的连接就会被从相关连接列表中删除。这个部分是Tor系统的核心控制部分,会在系统代码分析中经常遇到,所以此处就粗略描述。
6)Libevent循环指示变量;
call_loop_once变量用于指示Libevent循环是否阻塞。如果该值为1,则Libevent会不阻塞地执行被激活的事件处理函数,当没有需要执行的处理函数时,会返回。如果该值为0,则Libevent会阻塞地执行被激活的事件处理函数,即没有需要执行的处理函数时,阻塞不返回。在后者的情况下,Tor系统为了处理特定的事件而需要推出loop循环,则需要调用特定的tor_event_base_loopexit函数来让主循环暂时退出:
7)链路可用性指示变量。
以下为所有全局变量的罗列:
dumpstats
记录内存使用情况与系统当前状态,输出至log;
conn_read_callback*
conn_write_callback*
second_elapsed_callback* -> run_schedule_events -> run_connection_housekeeping
refill_callback
signal_callback -> process_signal
读写、秒定时器、令牌桶填充以及信号处理回调函数;
conn_close_if_marked
关闭连接池中已被标记为关闭的连接;
connection_should_read_from_linked_conn*
connection_start_reading_from_linked_conn*
connection_stop_reading_from_linked_conn*
判断linked连接的可读性,并对该连接进行读写准备操作;(所谓的读写准备操作,就与上文中所提到的活动的linked连接链表有直接关系。实际上就是对活动linked连接链表的增删操作。活动linked链表会在每次程序主循环时被检测,激活其中所有连接进行读写调度。
connection_add ->
connection_add_connecting -> connection_add_impl*
向连接池中添加新连接,并为该连接生成读写事件,但并不将事件加入调度池;(->代表调用,下同)
connection_unlink -> connection_remove -> connection_unregister_events
从右到左依次为将连接的读写事件从调度池中删除,并将连接从连接池中删除,最终将连接完全释放;
connection_watch_events* -> connection_start_reading,connection_start_writing,connection_stop_reading,connection_stop_writing
connection_is_reading
connection_is_writing
针对连接的读写事件加入调度池或调出调度池的操作和读写判断;普通连接的操作通过调度池完成,linked连接的操作通过活动linked连接链表完成。
try_locking
have_lockfile
release_locking
全局加锁文件加解锁控制;
tor_main -> tor_init*,do_main_loop*,do_list_fingerprint,do_hash_password
Tor程序主函数执行分支流程。
1. 全局变量
全局变量在文件头部定义,每个全局变量都已经有比较详尽的英文分析和解释,这里再做简单的罗列。1)系统(先前)已读与已写字节数以及用于流量控制的令牌桶全局变量;(先前与当前已读写字节数的区别与refill回调函数相关)
令牌桶用于控制整个系统的流量,经过初始化,减少,增加等操作(当读写相应的令牌数不够时,系统或连接会停止读或写):
// 初始化令牌桶令牌数 /** Initialize the global read bucket to options-\>BandwidthBurst. */ void connection_bucket_init(void) { const or_options_t *options = get_options(); /* start it at max traffic */ global_read_bucket = (int)options->BandwidthBurst; global_write_bucket = (int)options->BandwidthBurst; if (options->RelayBandwidthRate) { global_relayed_read_bucket = (int)options->RelayBandwidthBurst; global_relayed_write_bucket = (int)options->RelayBandwidthBurst; } else { global_relayed_read_bucket = (int)options->BandwidthBurst; global_relayed_write_bucket = (int)options->BandwidthBurst; } }
// 减少令牌桶令牌数 /** We just read <b>num_read</b> and wrote <b>num_written</b> bytes * onto <b>conn</b>. Decrement buckets appropriately. */ static void connection_buckets_decrement(connection_t *conn, time_t now, size_t num_read, size_t num_written) { ...... if (connection_counts_as_relayed_traffic(conn, now)) { global_relayed_read_bucket -= (int)num_read; global_relayed_write_bucket -= (int)num_written; } global_read_bucket -= (int)num_read; global_write_bucket -= (int)num_written; ...... }
// 增加令牌桶令牌数 /** Time has passed; increment buckets appropriately. */ void connection_bucket_refill(int milliseconds_elapsed, time_t now) { ...... /* refill the global buckets */ connection_bucket_refill_helper(&global_read_bucket, bandwidthrate, bandwidthburst, milliseconds_elapsed, "global_read_bucket"); connection_bucket_refill_helper(&global_write_bucket, bandwidthrate, bandwidthburst, milliseconds_elapsed, "global_write_bucket"); connection_bucket_refill_helper(&global_relayed_read_bucket, relayrate, relayburst, milliseconds_elapsed, "global_relayed_read_bucket"); connection_bucket_refill_helper(&global_relayed_write_bucket, relayrate, relayburst, milliseconds_elapsed, "global_relayed_write_bucket"); ...... }
先前已读写字节数全局变量的具体赋值处于函数second_elapsed_callback之中,其他地方没有引用:
bytes_read = (size_t)(stats_n_bytes_read - stats_prev_n_read); bytes_written = (size_t)(stats_n_bytes_written - stats_prev_n_written); stats_prev_n_read = stats_n_bytes_read; stats_prev_n_written = stats_n_bytes_written;
当前已读写字节数全局变量的具体赋值处于函数refill_callback之中,其他地方没有引用:
bytes_written = stats_prev_global_write_bucket - global_write_bucket; bytes_read = stats_prev_global_read_bucket - global_read_bucket; stats_n_bytes_read += bytes_read; stats_n_bytes_written += bytes_written;
2)系统启动时间和运行时间;
系统启动时间初始化于Tor系统初始化阶段,未曾修改过:
tor_init(int argc, char *argv[]) { ...... time_of_process_start = time(NULL); ...... }
系统运行时间在函数second_elapsed_callback中随时间增加;在系统发生重要变故的时候会被重新设置为0,例如hibernation,Ip改变等情况。
3)启动下次DNS检查的时间;
只有在系统配置为服务器时候才使用,改变部分在函数run_scheduled_events之中,此处略去。
4)newnym相关变量;
newnym信号相关变量均于信号处理函数内部进行改变,入口大致为:
/** Do the work of acting on a signal received in <b>sig</b> */ void process_signal(uintptr_t sig) { switch (sig) { .... case SIGNEWNYM: { time_t now = time(NULL); if (time_of_last_signewnym + MAX_SIGNEWNYM_RATE > now) { signewnym_is_pending = 1; log(LOG_NOTICE, LD_CONTROL, "Rate limiting NEWNYM request: delaying by %d second(s)", (int)(MAX_SIGNEWNYM_RATE+time_of_last_signewnym-now)); } else { signewnym_impl(now); } break; } ...... }
5)三大连接链表全局变量:全连接链表,可关闭的连接链表,活动的linked连接列表;(linked连接的含义,在Tor源码分析中会提到)
这三个连接链表因为引用非常多,不可能贴出其主要引用位置。大致的可以说,当系统出现相关连接时,会被加入到相关连接列表中:全部的,可关闭的,活动的linked。当系统删除相关连接时,这些对应的连接就会被从相关连接列表中删除。这个部分是Tor系统的核心控制部分,会在系统代码分析中经常遇到,所以此处就粗略描述。
6)Libevent循环指示变量;
call_loop_once变量用于指示Libevent循环是否阻塞。如果该值为1,则Libevent会不阻塞地执行被激活的事件处理函数,当没有需要执行的处理函数时,会返回。如果该值为0,则Libevent会阻塞地执行被激活的事件处理函数,即没有需要执行的处理函数时,阻塞不返回。在后者的情况下,Tor系统为了处理特定的事件而需要推出loop循环,则需要调用特定的tor_event_base_loopexit函数来让主循环暂时退出:
do_main_loop { ...... /* All active linked conns should get their read events activated. */ SMARTLIST_FOREACH(active_linked_connection_lst, connection_t *, conn, event_active(conn->read_event, EV_READ, 1)); called_loop_once = smartlist_len(active_linked_connection_lst) ? 1 : 0; update_approx_time(time(NULL)); /* poll until we have an event, or the second ends, or until we have * some active linked connections to trigger events for. */ loop_result = event_base_loop(tor_libevent_get_base(), called_loop_once ? EVLOOP_ONCE : 0); ...... }
7)链路可用性指示变量。
以下为所有全局变量的罗列:
#ifndef USE_BUFFEREVENTS int global_read_bucket; /**< Max number of bytes I can read this second. */ int global_write_bucket; /**< Max number of bytes I can write this second. */ /** Max number of relayed (bandwidth class 1) bytes I can read this second. */ int global_relayed_read_bucket; /** Max number of relayed (bandwidth class 1) bytes I can write this second. */ int global_relayed_write_bucket; /** What was the read bucket before the last second_elapsed_callback() call? * (used to determine how many bytes we've read). */ static int stats_prev_global_read_bucket; /** What was the write bucket before the last second_elapsed_callback() call? * (used to determine how many bytes we've written). */ static int stats_prev_global_write_bucket; #endif /* DOCDOC stats_prev_n_read */ static uint64_t stats_prev_n_read = 0; /* DOCDOC stats_prev_n_written */ static uint64_t stats_prev_n_written = 0; /* XXX we might want to keep stats about global_relayed_*_bucket too. Or not.*/ /** How many bytes have we read since we started the process? */ static uint64_t stats_n_bytes_read = 0; /** How many bytes have we written since we started the process? */ static uint64_t stats_n_bytes_written = 0; /** What time did this process start up? */ time_t time_of_process_start = 0; /** How many seconds have we been running? */ long stats_n_seconds_working = 0; /** When do we next launch DNS wildcarding checks? */ static time_t time_to_check_for_correct_dns = 0; /** How often will we honor SIGNEWNYM requests? */ #define MAX_SIGNEWNYM_RATE 10 /** When did we last process a SIGNEWNYM request? */ static time_t time_of_last_signewnym = 0; /** Is there a signewnym request we're currently waiting to handle? */ static int signewnym_is_pending = 0; /** How many times have we called newnym? */ static unsigned newnym_epoch = 0; /** Smartlist of all open connections. */ static smartlist_t *connection_array = NULL; /** List of connections that have been marked for close and need to be freed * and removed from connection_array. */ static smartlist_t *closeable_connection_lst = NULL; /** List of linked connections that are currently reading data into their * inbuf from their partner's outbuf. */ static smartlist_t *active_linked_connection_lst = NULL; /** Flag: Set to true iff we entered the current libevent main loop via * <b>loop_once</b>. If so, there's no need to trigger a loopexit in order * to handle linked connections. */ static int called_loop_once = 0; /** We set this to 1 when we've opened a circuit, so we can print a log * entry to inform the user that Tor is working. We set it to 0 when * we think the fact that we once opened a circuit doesn't mean we can do so * any longer (a big time jump happened, when we notice our directory is * heinously out-of-date, etc. */ int can_complete_circuit=0;
2.功能函数(加*号的为极重要函数)
dumpmemusagedumpstats
记录内存使用情况与系统当前状态,输出至log;
conn_read_callback*
conn_write_callback*
second_elapsed_callback* -> run_schedule_events -> run_connection_housekeeping
refill_callback
signal_callback -> process_signal
读写、秒定时器、令牌桶填充以及信号处理回调函数;
conn_close_if_marked
关闭连接池中已被标记为关闭的连接;
connection_should_read_from_linked_conn*
connection_start_reading_from_linked_conn*
connection_stop_reading_from_linked_conn*
判断linked连接的可读性,并对该连接进行读写准备操作;(所谓的读写准备操作,就与上文中所提到的活动的linked连接链表有直接关系。实际上就是对活动linked连接链表的增删操作。活动linked链表会在每次程序主循环时被检测,激活其中所有连接进行读写调度。
connection_add ->
connection_add_connecting -> connection_add_impl*
向连接池中添加新连接,并为该连接生成读写事件,但并不将事件加入调度池;(->代表调用,下同)
connection_unlink -> connection_remove -> connection_unregister_events
从右到左依次为将连接的读写事件从调度池中删除,并将连接从连接池中删除,最终将连接完全释放;
connection_watch_events* -> connection_start_reading,connection_start_writing,connection_stop_reading,connection_stop_writing
connection_is_reading
connection_is_writing
针对连接的读写事件加入调度池或调出调度池的操作和读写判断;普通连接的操作通过调度池完成,linked连接的操作通过活动linked连接链表完成。
try_locking
have_lockfile
release_locking
全局加锁文件加解锁控制;
tor_main -> tor_init*,do_main_loop*,do_list_fingerprint,do_hash_password
Tor程序主函数执行分支流程。
相关文章推荐
- Tor源码文件分析 -- Connection
- Tor源码文件分析 -- Cpuworker
- Tor源码文件分析 -- Connection_OR
- Tor源码文件分析 -- Circuits全局变量
- Tor源码文件分析 -- Hibernation
- Tor源码文件分析 -- Connetion_Edge
- Tor源码文件分析 -- Control
- Tor源码文件分析 -- Log
- 基于TCP网络通信的自动升级程序源码分析--生成升级文件相关的配置文件
- Hadoop之HDFS原理及文件上传下载源码分析(上)
- (转)x264源码分析(1):main、parse、encode、x264_encoder_open函数代码分析
- 7z文件格式及其源码的分析(三)
- Wordpress源码分析 目录结构-文件调用关系(1)
- 文件系统(一)--super.c bitmap.c inode.c 源码分析
- CI框架源码完全分析之核心文件(安全类)Security.php
- UE4源码分析2-文件目录说明
- Spring源码分析-配置文件的解析(二)
- Solr4.8.0源码分析(10)之Lucene的索引文件(3)
- CI源码分析(一)—config配置文件模块
- 【Android7.1.2源码解析系列】实战分析init.rc文件