Main檔案是Tor系統的主要執行函數所處檔案,內容偏多,但是較於其他底層處理函數所在的檔案,也算較少。所以這裡做簡要的分析,其中刪去很多不常見的,不重要的函數,大家可以自行在源檔案內部查看。
1. 全域變數
全域變數在檔案頭部定義,每個全域變數都已經有比較詳盡的英文分析和解釋,這裡再做簡單的羅列。
1)系統(先前)已讀與已寫位元組數以及用於流量控制的令牌桶全域變數;(先前與當前已讀寫位元組數的區別與refill回呼函數相關)
令牌桶用於控制整個系統的流量,經過初始化,減少,增加等操作(當讀寫相應的令牌數不夠時,系統或串連會停止讀或寫):
// 初始化令牌桶令牌數/** Initialize the global read bucket to options-\>BandwidthBurst. */voidconnection_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 voidconnection_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. */voidconnection_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> */voidprocess_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_BUFFEREVENTSint 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.功能函數(加*號的為極重要函數)
dumpmemusage
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程式主函數執行分支流程。