circuituse.c File Reference

Launch the right sort of circuits and attach streams to them. More...

#include "or.h"

Defines

#define REND_PARALLEL_INTRO_DELAY   15
#define MAX_UNUSED_OPEN_CIRCUITS   14
#define TESTING_CIRCUIT_INTERVAL   300
#define IDLE_TIMEOUT_WHILE_LEARNING   (10*60)
#define IDLE_ONE_HOP_CIRC_TIMEOUT   60
#define NUM_PARALLEL_TESTING_CIRCS   4
#define MAX_CIRCUIT_FAILURES   5

Functions

static void circuit_expire_old_circuits_clientside (time_t now)
static void circuit_increment_failure_count (void)
long int lround (double x)
static int circuit_is_acceptable (circuit_t *circ, edge_connection_t *conn, int must_be_open, uint8_t purpose, int need_uptime, int need_internal, time_t now)
static int circuit_is_better (circuit_t *a, circuit_t *b, uint8_t purpose)
static origin_circuit_tcircuit_get_best (edge_connection_t *conn, int must_be_open, uint8_t purpose, int need_uptime, int need_internal)
int circuit_conforms_to_options (const origin_circuit_t *circ, const or_options_t *options)
void circuit_expire_building (time_t now)
void circuit_remove_handled_ports (smartlist_t *needed_ports)
int circuit_stream_is_being_handled (edge_connection_t *conn, uint16_t port, int min)
static void circuit_predict_and_launch_new (void)
void circuit_build_needed_circs (time_t now)
void circuit_detach_stream (circuit_t *circ, edge_connection_t *conn)
void circuit_expire_old_circuits_serverside (time_t now)
void reset_bandwidth_test (void)
int circuit_enough_testing_circs (void)
static void circuit_testing_opened (origin_circuit_t *circ)
static void circuit_testing_failed (origin_circuit_t *circ, int at_last_hop)
void circuit_has_opened (origin_circuit_t *circ)
void circuit_build_failed (origin_circuit_t *circ)
origin_circuit_tcircuit_launch_by_router (uint8_t purpose, routerinfo_t *exit, int flags)
origin_circuit_tcircuit_launch_by_extend_info (uint8_t purpose, extend_info_t *extend_info, int flags)
void circuit_reset_failure_count (int timeout)
static int circuit_get_open_circ_or_launch (edge_connection_t *conn, uint8_t desired_circuit_purpose, origin_circuit_t **circp)
static int cpath_is_on_circuit (origin_circuit_t *circ, crypt_path_t *crypt_path)
static void link_apconn_to_circ (edge_connection_t *apconn, origin_circuit_t *circ, crypt_path_t *cpath)
static void consider_recording_trackhost (edge_connection_t *conn, origin_circuit_t *circ)
int connection_ap_handshake_attach_chosen_circuit (edge_connection_t *conn, origin_circuit_t *circ, crypt_path_t *cpath)
int connection_ap_handshake_attach_circuit (edge_connection_t *conn)

Variables

circuit_tglobal_circuitlist
static int have_performed_bandwidth_test = 0
static int n_circuit_failures = 0
static int did_circs_fail_last_period = 0


Detailed Description

Launch the right sort of circuits and attach streams to them.


Define Documentation

#define IDLE_ONE_HOP_CIRC_TIMEOUT   60

How long do we wait before killing circuits with the properties described below?

Probably we could choose a number here as low as 5 to 10 seconds, since these circs are used for begindir, and a) generally you either ask another begindir question right after or you don't for a long time, b) clients at least through 0.2.1.x choose from the whole set of directory mirrors at each choice, and c) re-establishing a one-hop circuit via create-fast is a light operation assuming the TLS conn is still there.

I expect "b" to go away one day when we move to using directory guards, but I think "a" and "c" are good enough reasons that a low number is safe even then.

Referenced by circuit_expire_old_circuits_serverside().

#define IDLE_TIMEOUT_WHILE_LEARNING   (10*60)

If we haven't yet decided on a good timeout value for circuit building, we close idles circuits aggressively so we can get more data points.

Referenced by circuit_expire_old_circuits_clientside().

#define MAX_CIRCUIT_FAILURES   5

Don't retry launching a new circuit if we try this many times with no success.

Referenced by circuit_launch_by_extend_info(), and circuit_reset_failure_count().

#define MAX_UNUSED_OPEN_CIRCUITS   14

Don't keep more than this many unused open circuits around.

Referenced by circuit_predict_and_launch_new().

#define NUM_PARALLEL_TESTING_CIRCS   4

Number of testing circuits we want open before testing our bandwidth.

Referenced by circuit_enough_testing_circs(), and circuit_testing_opened().

#define TESTING_CIRCUIT_INTERVAL   300

Build a new test circuit every 5 minutes

Referenced by circuit_build_needed_circs().


Function Documentation

void circuit_build_failed ( origin_circuit_t circ  ) 

void circuit_build_needed_circs ( time_t  now  ) 

This function is called once a second, if router_have_min_dir_info() is true. Its job is to make sure all services we offer have enough circuits available. Some services just want enough circuits for current tasks, whereas others want a minimum set of idle circuits hanging around.

References addressmap_clean(), circuit_expire_old_circuits_clientside(), circuit_launch_by_router(), circuit_predict_and_launch_new(), CIRCUIT_PURPOSE_C_GENERAL, circuit_reset_failure_count(), connection_ap_attach_pending(), or_options_t::DisablePredictedCircuits, get_options(), or_options_t::NewCircuitPeriod, proxy_mode(), rend_services_introduce(), and TESTING_CIRCUIT_INTERVAL.

Referenced by run_scheduled_events().

int circuit_conforms_to_options ( const origin_circuit_t circ,
const or_options_t options 
)

Check whether, according to the policies in options, the circuit circ makes sense.

References origin_circuit_t::cpath, or_options_t::ExcludeExitNodes, or_options_t::ExcludeNodes, crypt_path_t::extend_info, crypt_path_t::next, and routerset_contains_extendinfo().

void circuit_detach_stream ( circuit_t circ,
edge_connection_t conn 
)

int circuit_enough_testing_circs ( void   ) 

Return 1 if we've already exercised our bandwidth, or if we have fewer than NUM_PARALLEL_TESTING_CIRCS testing circuits established or on the way. Else return 0.

References CIRCUIT_IS_ORIGIN, CIRCUIT_PURPOSE_TESTING, CIRCUIT_STATE_OPEN, have_performed_bandwidth_test, circuit_t::marked_for_close, circuit_t::next, NUM_PARALLEL_TESTING_CIRCS, circuit_t::purpose, and circuit_t::state.

Referenced by circuit_testing_opened(), consider_testing_reachability(), and rep_hist_circbuilding_dormant().

void circuit_expire_building ( time_t  now  ) 

static void circuit_expire_old_circuits_clientside ( time_t  now  )  [static]

void circuit_expire_old_circuits_serverside ( time_t  now  ) 

static origin_circuit_t* circuit_get_best ( edge_connection_t conn,
int  must_be_open,
uint8_t  purpose,
int  need_uptime,
int  need_internal 
) [static]

Find the best circ that conn can use, preferably one which is dirty. Circ must not be too old.

Conn must be defined.

If must_be_open, ignore circs not in CIRCUIT_STATE_OPEN.

circ_purpose specifies what sort of circuit we must have. It can be C_GENERAL, C_INTRODUCE_ACK_WAIT, or C_REND_JOINED.

If it's REND_JOINED and must_be_open==0, then return the closest rendezvous-purposed circuit that you can find.

If it's INTRODUCE_ACK_WAIT and must_be_open==0, then return the closest introduce-purposed circuit that you can find.

References circuit_is_acceptable(), circuit_is_better(), CIRCUIT_PURPOSE_C_GENERAL, CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT, CIRCUIT_PURPOSE_C_REND_JOINED, CIRCUIT_STATE_OPEN, LD_CIRC, LD_REND, circuit_t::next, circuit_t::state, circuit_t::timestamp_created, TO_ORIGIN_CIRCUIT(), and tor_assert.

Referenced by circuit_get_open_circ_or_launch().

static int circuit_get_open_circ_or_launch ( edge_connection_t conn,
uint8_t  desired_circuit_purpose,
origin_circuit_t **  circp 
) [static]

Find an open circ that we're happy to use for conn and return 1. If there isn't one, and there isn't one on the way, launch one and return 0. If it will never work, return -1.

Write the found or in-progress or launched circ into *circp.

References origin_circuit_t::_base, edge_connection_t::_base, socks_request_t::address, any_bridge_descriptors_known(), AP_CONN_STATE_CIRCUIT_WAIT, AP_CONN_STATE_RENDDESC_WAIT, base16_decode(), bridges_known_but_down(), bridges_retry_all(), edge_connection_t::chosen_exit_name, edge_connection_t::chosen_exit_optional, CIRCLAUNCH_IS_INTERNAL, CIRCLAUNCH_NEED_CAPACITY, CIRCLAUNCH_NEED_UPTIME, CIRCLAUNCH_ONEHOP_TUNNEL, circuit_get_best(), circuit_launch_by_extend_info(), CIRCUIT_PURPOSE_C_ESTABLISH_REND, CIRCUIT_PURPOSE_C_GENERAL, CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT, CIRCUIT_PURPOSE_C_INTRODUCING, CIRCUIT_PURPOSE_C_REND_JOINED, CIRCUIT_STATE_OPEN, socks_request_t::command, CONN_TYPE_DIR, connection_ap_can_use_exit(), connection_edge_is_rendezvous_stream(), connection_get_by_type(), DIGEST_LEN, escaped_safe_str_client(), extend_info_alloc(), extend_info_free(), extend_info_from_router(), get_options(), HEX_DIGEST_LEN, LD_APP, LD_CIRC, LD_DIR, LD_REND, or_options_t::LongLivedPorts, extend_info_t::nickname, rend_data_t::onion_address, socks_request_t::port, circuit_t::purpose, rend_client_get_random_intro(), rend_client_refetch_v2_renddesc(), rend_client_rendcirc_has_opened(), origin_circuit_t::rend_data, edge_connection_t::rend_data, rend_data_dup(), rep_hist_note_used_internal(), router_exit_policy_all_routers_reject(), router_get_by_nickname(), router_have_minimum_dir_info(), routerlist_retry_directory_downloads(), safe_str_client(), smartlist_string_num_isin(), SOCKS_COMMAND_CONNECT, edge_connection_t::socks_request, circuit_t::state, connection_t::state, tor_addr_from_str(), tor_assert, tor_free, tor_inet_aton(), edge_connection_t::use_begindir, or_options_t::UseBridges, and edge_connection_t::want_onehop.

Referenced by connection_ap_handshake_attach_circuit().

void circuit_has_opened ( origin_circuit_t circ  ) 

The circuit circ has just become open. Take the next step: for rendezvous circuits, we pass circ to the appropriate function in rendclient or rendservice. For general circuits, we call connection_ap_attach_pending, which looks for pending streams that could use circ.

References CIRCUIT_PURPOSE_C_ESTABLISH_REND, CIRCUIT_PURPOSE_C_GENERAL, CIRCUIT_PURPOSE_C_INTRODUCING, CIRCUIT_PURPOSE_S_CONNECT_REND, CIRCUIT_PURPOSE_S_ESTABLISH_INTRO, CIRCUIT_PURPOSE_TESTING, circuit_testing_opened(), connection_ap_attach_pending(), control_event_circuit_status(), rend_client_introcirc_has_opened(), rend_client_rendcirc_has_opened(), rend_service_intro_has_opened(), rend_service_rendezvous_has_opened(), and TO_CIRCUIT.

Referenced by circuit_send_next_onion_skin(), and rend_service_intro_has_opened().

static void circuit_increment_failure_count ( void   )  [static]

Record another failure at opening a general circuit. When we have too many, we'll stop trying for the remainder of this minute.

References LD_CIRC, and n_circuit_failures.

Referenced by circuit_build_failed().

static int circuit_is_acceptable ( circuit_t circ,
edge_connection_t conn,
int  must_be_open,
uint8_t  purpose,
int  need_uptime,
int  need_internal,
time_t  now 
) [static]

static int circuit_is_better ( circuit_t a,
circuit_t b,
uint8_t  purpose 
) [static]

Return 1 if circuit a is better than circuit b for purpose, and return 0 otherwise. Used by circuit_get_best.

References CIRCUIT_IS_ORIGIN, CIRCUIT_PURPOSE_C_GENERAL, CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT, CIRCUIT_PURPOSE_C_REND_JOINED, circuit_t::purpose, circuit_t::timestamp_created, circuit_t::timestamp_dirty, and TO_ORIGIN_CIRCUIT().

Referenced by circuit_get_best().

origin_circuit_t* circuit_launch_by_extend_info ( uint8_t  purpose,
extend_info_t extend_info,
int  flags 
)

Launch a new circuit with purpose purpose and exit node extend_info (or NULL to select a random exit node). If flags contains CIRCLAUNCH_NEED_UPTIME, choose among routers with high uptime. If CIRCLAUNCH_NEED_CAPACITY is set, choose among routers with high bandwidth. If CIRCLAUNCH_IS_INTERNAL is true, the last hop need not be an exit node. If CIRCLAUNCH_ONEHOP_TUNNEL is set, the circuit will have only one hop. Return the newly allocated circuit on success, or NULL on failure.

References origin_circuit_t::_base, origin_circuit_t::build_state, build_state_get_exit_nickname(), CIRCLAUNCH_ONEHOP_TUNNEL, circuit_establish_circuit(), circuit_extend_to_new_exit(), circuit_find_to_cannibalize(), CIRCUIT_PURPOSE_C_ESTABLISH_REND, CIRCUIT_PURPOSE_C_GENERAL, CIRCUIT_PURPOSE_C_INTRODUCING, CIRCUIT_PURPOSE_S_CONNECT_REND, CIRCUIT_PURPOSE_S_ESTABLISH_INTRO, CIRCUIT_PURPOSE_TESTING, did_circs_fail_last_period, LD_BUG, LD_CIRC, MAX_CIRCUIT_FAILURES, n_circuit_failures, circuit_t::purpose, router_have_minimum_dir_info(), circuit_t::timestamp_created, tor_assert, and tor_fragile_assert.

Referenced by circuit_get_open_circ_or_launch(), circuit_launch_by_router(), rend_client_introduction_acked(), rend_service_introduce(), rend_service_launch_establish_intro(), and rend_service_relaunch_rendezvous().

origin_circuit_t* circuit_launch_by_router ( uint8_t  purpose,
routerinfo_t exit,
int  flags 
)

static void circuit_predict_and_launch_new ( void   )  [static]

void circuit_remove_handled_ports ( smartlist_t needed_ports  ) 

Remove any elements in needed_ports that are handled by an open or in-progress circuit.

References circuit_stream_is_being_handled(), LD_CIRC, MIN_CIRCUITS_HANDLING_STREAM, smartlist_del(), tor_assert, and tor_free.

Referenced by circuit_get_unhandled_ports().

void circuit_reset_failure_count ( int  timeout  ) 

Reset the failure count for opening general circuits. This means we will try MAX_CIRCUIT_FAILURES times more (if necessary) before stopping again.

References did_circs_fail_last_period, MAX_CIRCUIT_FAILURES, and n_circuit_failures.

Referenced by circuit_build_needed_circs(), and circuit_send_next_onion_skin().

int circuit_stream_is_being_handled ( edge_connection_t conn,
uint16_t  port,
int  min 
)

static void circuit_testing_failed ( origin_circuit_t circ,
int  at_last_hop 
) [static]

A testing circuit has failed to build. Take whatever stats we want.

References check_whether_orport_reachable(), get_options(), LD_GENERAL, and server_mode().

Referenced by circuit_build_failed().

static void circuit_testing_opened ( origin_circuit_t circ  )  [static]

A testing circuit has completed. Take whatever stats we want. Noticing reachability is taken care of in onionskin_answer(), so there's no need to record anything here. But if we still want to do the bandwidth test, and we now have enough testing circuits open, do it.

References check_whether_orport_reachable(), circuit_enough_testing_circs(), consider_testing_reachability(), END_CIRC_AT_ORIGIN, have_performed_bandwidth_test, NUM_PARALLEL_TESTING_CIRCS, router_perform_bandwidth_test(), and TO_CIRCUIT.

Referenced by circuit_has_opened().

int connection_ap_handshake_attach_chosen_circuit ( edge_connection_t conn,
origin_circuit_t circ,
crypt_path_t cpath 
)

Attempt to attach the connection conn to circ, and send a begin or resolve cell as appropriate. Return values are as for connection_ap_handshake_attach_circuit. The stream will exit from the hop indicated by cpath, or from the last hop in circ's cpath if cpath is NULL.

References origin_circuit_t::_base, edge_connection_t::_base, AP_CONN_STATE_CIRCUIT_WAIT, AP_CONN_STATE_CONTROLLER_WAIT, CIRCUIT_STATE_OPEN, socks_request_t::command, connection_ap_handshake_send_begin(), connection_ap_handshake_send_resolve(), consider_recording_trackhost(), link_apconn_to_circ(), SOCKS_COMMAND_CONNECT, edge_connection_t::socks_request, circuit_t::state, connection_t::state, circuit_t::timestamp_dirty, tor_assert, and edge_connection_t::use_begindir.

Referenced by connection_ap_handshake_attach_circuit().

int connection_ap_handshake_attach_circuit ( edge_connection_t conn  ) 

Try to find a safe live circuit for CONN_TYPE_AP connection conn. If we don't find one: if conn cannot be handled by any known nodes, warn and return -1 (conn needs to die, and is maybe already marked); else launch new circuit (if necessary) and return 0. Otherwise, associate conn with a safe live circuit, do the right next step, and return 1.

References origin_circuit_t::_base, edge_connection_t::_base, connection_t::addr, socks_request_t::address, AP_CONN_STATE_CIRCUIT_WAIT, assert_circuit_ok(), edge_connection_t::chosen_exit_name, edge_connection_t::chosen_exit_optional, circuit_get_open_circ_or_launch(), CIRCUIT_IS_ORIGIN, circuit_log_path(), CIRCUIT_PURPOSE_C_GENERAL, CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT, CIRCUIT_PURPOSE_C_INTRODUCING, CIRCUIT_PURPOSE_C_REND_JOINED, CIRCUIT_PURPOSE_C_REND_READY, CIRCUIT_PURPOSE_C_REND_READY_INTRO_ACKED, CIRCUIT_STATE_OPEN, connection_ap_can_use_exit(), connection_ap_handshake_attach_chosen_circuit(), connection_ap_handshake_send_begin(), connection_edge_is_rendezvous_stream(), edge_connection_t::cpath_layer, get_options(), LD_APP, LD_CIRC, LD_REND, link_apconn_to_circ(), circuit_t::marked_for_close, circuit_t::n_circ_id, circuit_t::next, rend_data_t::onion_address, socks_request_t::port, connection_t::port, circuit_t::purpose, rend_client_send_introduction(), rend_cmp_service_ids(), edge_connection_t::rend_data, origin_circuit_t::rend_data, router_get_by_nickname(), safe_str_client(), edge_connection_t::socks_request, or_options_t::SocksTimeout, connection_t::state, connection_t::timestamp_created, circuit_t::timestamp_dirty, TO_CIRCUIT, TO_ORIGIN_CIRCUIT(), tor_addr_is_null(), tor_assert, tor_free, and edge_connection_t::want_onehop.

Referenced by connection_ap_attach_pending(), connection_ap_detach_retriable(), connection_ap_make_link(), and rend_client_desc_trynow().

static void consider_recording_trackhost ( edge_connection_t conn,
origin_circuit_t circ 
) [static]

static int cpath_is_on_circuit ( origin_circuit_t circ,
crypt_path_t crypt_path 
) [static]

Return true iff crypt_path is one of the crypt_paths for circ.

References origin_circuit_t::cpath, and crypt_path_t::next.

Referenced by link_apconn_to_circ().

static void link_apconn_to_circ ( edge_connection_t apconn,
origin_circuit_t circ,
crypt_path_t cpath 
) [static]

void reset_bandwidth_test ( void   ) 

Reset have_performed_bandwidth_test, so we'll start building testing circuits again so we can exercise our bandwidth.

References have_performed_bandwidth_test.

Referenced by ip_address_changed(), and run_scheduled_events().


Variable Documentation

int did_circs_fail_last_period = 0 [static]

Before the last time we called circuit_reset_failure_count(), were there a lot of failures?

Referenced by circuit_launch_by_extend_info(), and circuit_reset_failure_count().

A global list of all circuits at this hop.

True iff we've ever had enough testing circuits open to test our bandwidth.

Referenced by circuit_enough_testing_circs(), circuit_testing_opened(), and reset_bandwidth_test().

int n_circuit_failures = 0 [static]

Number of consecutive failures so far; should only be touched by circuit_launch_new and circuit_*_failure_count.

Referenced by circuit_increment_failure_count(), circuit_launch_by_extend_info(), and circuit_reset_failure_count().


Generated on Tue May 25 00:30:40 2010 for tor by  doxygen 1.5.6