Tor源碼檔案分析 — Main

來源:互聯網
上載者:User

  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程式主函數執行分支流程。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.