diff options
author | Roger Dingledine <arma@torproject.org> | 2004-05-10 04:42:22 +0000 |
---|---|---|
committer | Roger Dingledine <arma@torproject.org> | 2004-05-10 04:42:22 +0000 |
commit | 4845fe7197768da95dee0153a647a30eac29eef7 (patch) | |
tree | 764e3eb95542b320b3c10ad943b4d9a30089cad9 /src | |
parent | 81922a125ca17d6d46a378f9e7bf609d884524c2 (diff) | |
download | tor-4845fe7197768da95dee0153a647a30eac29eef7.tar tor-4845fe7197768da95dee0153a647a30eac29eef7.tar.gz |
comment and doxygenate connection_edge.c
svn:r1833
Diffstat (limited to 'src')
-rw-r--r-- | src/or/connection_edge.c | 236 |
1 files changed, 213 insertions, 23 deletions
diff --git a/src/or/connection_edge.c b/src/or/connection_edge.c index b07fcf391..520a512eb 100644 --- a/src/or/connection_edge.c +++ b/src/or/connection_edge.c @@ -2,11 +2,16 @@ /* See LICENSE for licensing information */ /* $Id$ */ +/** + * \file connection_edge.c + * \brief Handle edge streams and relay cells. + **/ + #include "or.h" #include "tree.h" extern or_options_t options; /* command-line and config-file options */ -extern char *conn_state_to_string[][_CONN_TYPE_MAX+1]; +extern char *conn_state_to_string[][_CONN_TYPE_MAX+1]; /* from connection.c */ static int connection_ap_handshake_process_socks(connection_t *conn); @@ -17,6 +22,10 @@ static uint32_t client_dns_lookup_entry(const char *address); static void client_dns_set_entry(const char *address, uint32_t val); static int client_dns_incr_failures(const char *address); +/** Pack the relay_header_t host-order structure <b>src</b> into + * network-order in the buffer <b>dest</b>. See tor-spec.txt for details + * about the wire format. + */ void relay_header_pack(char *dest, const relay_header_t *src) { *(uint8_t*)(dest) = src->command; @@ -26,6 +35,9 @@ void relay_header_pack(char *dest, const relay_header_t *src) { set_uint16(dest+9, htons(src->length)); } +/** Unpack the network-order buffer <b>src</b> into a host-order + * relay_header_t structure <b>dest</b>. + */ void relay_header_unpack(relay_header_t *dest, const char *src) { dest->command = *(uint8_t*)(src); @@ -35,7 +47,18 @@ void relay_header_unpack(relay_header_t *dest, const char *src) { dest->length = ntohs(get_uint16(src+9)); } -/* mark and return -1 if there was an unexpected error with the conn, +/** Handle new bytes on conn->inbuf, or notification of eof. + * + * If there was an EOF, then send an end and mark the connection + * for close. + * + * Otherwise handle it based on state: + * - If it's waiting for socks info, try to read another step of the + * socks handshake out of conn->inbuf. + * - If it's open, then package more relay cells from the stream. + * - Else, leave the bytes on inbuf alone for now. + * + * Mark and return -1 if there was an unexpected error with the conn, * else return 0. */ int connection_edge_process_inbuf(connection_t *conn) { @@ -98,6 +121,9 @@ int connection_edge_process_inbuf(connection_t *conn) { return -1; } +/** This edge needs to be closed, because its circuit has closed. + * Mark it for close and return 0. + */ int connection_edge_destroy(uint16_t circ_id, connection_t *conn) { tor_assert(conn->type == CONN_TYPE_AP || conn->type == CONN_TYPE_EXIT); @@ -111,7 +137,12 @@ int connection_edge_destroy(uint16_t circ_id, connection_t *conn) { return 0; } -static char *connection_edge_end_reason(char *payload, uint16_t length) { +/** Translate the <b>payload</b> of length <b>length</b>, which + * came from a relay 'end' cell, into a static const string describing + * why the stream is closing. + */ +static const char * +connection_edge_end_reason(char *payload, uint16_t length) { if(length < 1) { log_fn(LOG_WARN,"End cell arrived with length 0. Should be at least 1."); return "MALFORMED"; @@ -133,6 +164,14 @@ static char *connection_edge_end_reason(char *payload, uint16_t length) { return ""; } +/** Send a relay end cell from stream <b>conn</b> to conn's circuit, + * with a destination of cpath_layer. (If cpath_layer is NULL, the + * destination is the circuit's origin.) Mark the relay end cell as + * closing because of <b>reason</b>. + * + * Return -1 if this function has already been called on this conn, + * else return 0. + */ int connection_edge_end(connection_t *conn, char reason, crypt_path_t *cpath_layer) { char payload[5]; int payload_len=1; @@ -164,10 +203,10 @@ int connection_edge_end(connection_t *conn, char reason, crypt_path_t *cpath_lay return 0; } -/* Make a relay cell out of 'relay_command' and 'payload', and - * send it onto the open circuit 'circ'. 'fromconn' is the stream - * that's sending the relay cell, or NULL if it's a control cell, - * 'cpath_layer' is NULL for OR->OP cells, or the destination hop +/** Make a relay cell out of <b>relay_command</b> and <b>payload</b>, and + * send it onto the open circuit <b>circ</b>. <b>fromconn</b> is the stream + * that's sending the relay cell, or NULL if it's a control cell. + * <b>cpath_layer</b> is NULL for OR->OP cells, or the destination hop * for OP->OR cells. * * If you can't send the cell, mark the circuit for close and @@ -217,9 +256,20 @@ int connection_edge_send_command(connection_t *fromconn, circuit_t *circ, return 0; } +/** How many times will I retry a stream that fails due to DNS + * resolve failure? + */ #define MAX_RESOLVE_FAILURES 3 -int connection_edge_process_relay_cell_not_open( +/** An incoming relay cell has arrived from circuit <b>circ</b> to + * stream <b>conn</b>. + * + * The arguments here are the same as in + * connection_edge_process_relay_cell() below; this function is called + * from there when <b>conn</b> is defined and not in an open state. + */ +static int +connection_edge_process_relay_cell_not_open( relay_header_t *rh, cell_t *cell, circuit_t *circ, connection_t *conn, crypt_path_t *layer_hint) { uint32_t addr; @@ -293,8 +343,15 @@ int connection_edge_process_relay_cell_not_open( return -1; } -/* an incoming relay cell has arrived. return -1 if you want to tear down the - * circuit, else 0. */ +/** An incoming relay cell has arrived on circuit <b>circ</b>. If + * <b>conn</b> is NULL this is a control cell, else <b>cell</b> is + * destined for <b>conn</b>. + * + * If <b>layer_hint</b> is defined, then we're the origin of the + * circuit, and it specifies the hop that packaged <b>cell</b>. + * + * Return -1 if you want to tear down the circuit, else 0. + */ int connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ, connection_t *conn, crypt_path_t *layer_hint) { @@ -474,6 +531,20 @@ int connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ, return -1; } +/** Connection <b>conn</b> has finished writing and has no bytes left on + * its outbuf. + * + * If it's in state 'connecting', then take a look at the socket, and + * take appropriate actions (such as sending back a relay 'connected' + * cell) if the connect succeeded. + * + * If it's in state 'open', stop writing, consider responding with a + * sendme, and return. + * Otherwise, stop writing and return. + * + * If <b>conn</b> is broken, mark it for close and return -1, else + * return 0. + */ int connection_edge_finished_flushing(connection_t *conn) { unsigned char connected_payload[4]; int e, len=sizeof(e); @@ -539,6 +610,12 @@ uint64_t stats_n_data_bytes_packaged = 0; uint64_t stats_n_data_cells_received = 0; uint64_t stats_n_data_bytes_received = 0; +/** While conn->inbuf has an entire relay payload of bytes on it, + * and the appropriate package windows aren't empty, grab a cell + * and send it down the circuit. + * + * Return -1 if conn should be marked for close, else return 0. + */ int connection_edge_package_raw_inbuf(connection_t *conn) { int amount_to_process, length; char payload[CELL_PAYLOAD_SIZE]; @@ -606,7 +683,21 @@ repeat_connection_edge_package_raw_inbuf: goto repeat_connection_edge_package_raw_inbuf; } +/** How many times do we retry a general-purpose stream (detach it from + * one circuit and try another, after we wait a while with no 'connected' + * cell) before giving up? + */ #define MAX_STREAM_RETRIES 4 + +/** Find all general-purpose AP streams in state connect_wait that sent + * their begin cell >=15 seconds ago. Detach from their current circuit, + * and mark their current circuit as unsuitable for new streams. Then call + * connection_ap_handshake_attach_circuit() to attach to a new circuit (if + * available) or launch a new one. + * + * For rendezvous streams, simply give up after 45 seconds (with no + * retry attempt). + */ void connection_ap_expire_beginning(void) { connection_t **carray; connection_t *conn; @@ -672,7 +763,9 @@ void connection_ap_expire_beginning(void) { } /* end for */ } -/* Tell any APs that are waiting for a new circuit that one is available */ +/** Tell any AP streamss that are waiting for a new circuit that one is + * available. + */ void connection_ap_attach_pending(void) { connection_t **carray; @@ -694,6 +787,12 @@ void connection_ap_attach_pending(void) } } +/** Called when we've just received a relay data cell, or when + * we've just finished flushing all bytes to stream <b>conn</b>. + * + * If conn->outbuf is not too full, and our deliver window is + * low, send back a suitable number of stream-level sendme cells. + */ static void connection_edge_consider_sending_sendme(connection_t *conn) { circuit_t *circ; @@ -719,7 +818,19 @@ static void connection_edge_consider_sending_sendme(connection_t *conn) { } } -/* return -1 if an unexpected error with conn, else 0. */ +/** connection_edge_process_inbuf() found a conn in state + * socks_wait. See if conn->inbuf has the right bytes to proceed with + * the socks handshake. + * + * If the handshake is complete, and it's for a general circuit, then + * try to attach it to a circuit (or launch one as needed). If it's for + * a rendezvous circuit, then fetch a rendezvous descriptor first (or + * attach/launch a circuit if the rendezvous descriptor is already here + * and fresh enough). + * + * Return -1 if an unexpected error with conn (and it should be marked + * for close), else return 0. + */ static int connection_ap_handshake_process_socks(connection_t *conn) { socks_request_t *socks; int sockshere; @@ -789,10 +900,11 @@ static int connection_ap_handshake_process_socks(connection_t *conn) { return 0; } -/* Find an open circ that we're happy with: return 1. if there isn't - * one, and there isn't one on the way, launch one and return 0. if it +/** Find an open circ that we're happy with: 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. + * + * Write the found or in-progress or launched circ into *circp. */ static int circuit_get_open_circ_or_launch(connection_t *conn, @@ -866,6 +978,10 @@ circuit_get_open_circ_or_launch(connection_t *conn, return 0; } +/** Attach the AP stream <b>apconn</b> to circ's linked list of + * p_streams. Also set apconn's cpath_layer to the last hop in + * circ's cpath. + */ void link_apconn_to_circ(connection_t *apconn, circuit_t *circ) { /* add it into the linked list of streams on this circuit */ log_fn(LOG_DEBUG,"attaching new conn to circ. n_circ_id %d.", circ->n_circ_id); @@ -878,7 +994,7 @@ void link_apconn_to_circ(connection_t *apconn, circuit_t *circ) { apconn->cpath_layer = circ->cpath->prev; } -/* Try to find a safe live circuit for CONN_TYPE_AP connection conn. If +/** 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); * else launch new circuit (if necessary) and return 0. @@ -990,8 +1106,8 @@ int connection_ap_handshake_attach_circuit(connection_t *conn) { } } -/* Iterate over the two bytes of stream_id until we get one that is not - * already in use. Return 0 if can't get a unique stream_id. +/** Iterate over the two bytes of stream_id until we get one that is not + * already in use; return it. Return 0 if can't get a unique stream_id. */ static uint16_t get_unique_stream_id_by_circ(circuit_t *circ) { connection_t *tmpconn; @@ -1013,7 +1129,11 @@ again: return test_stream_id; } -/* deliver the destaddr:destport in a relay cell */ +/** Write a relay begin cell, using destaddr and destport from ap_conn's + * socks_request field, and send it down circ. + * + * If ap_conn is broken, mark it for close and return -1. Else return 0. + */ int connection_ap_handshake_send_begin(connection_t *ap_conn, circuit_t *circ) { char payload[CELL_PAYLOAD_SIZE]; @@ -1060,9 +1180,10 @@ int connection_ap_handshake_send_begin(connection_t *ap_conn, circuit_t *circ) return 0; } -/* make an ap connection_t, do a socketpair and attach one side +/** Make an AP connection_t, do a socketpair and attach one side * to the conn, connection_add it, initialize it to circuit_wait, * and call connection_ap_handshake_attach_circuit(conn) on it. + * * Return the other end of the socketpair, or -1 if error. */ int connection_ap_make_bridge(char *address, uint16_t port) { @@ -1115,6 +1236,14 @@ int connection_ap_make_bridge(char *address, uint16_t port) { return fd[1]; } +/** Send a socks reply to stream <b>conn</b>, using the appropriate + * socks version, etc. + * + * If <b>reply</b> is defined, then write <b>replylen</b> bytes of it + * to conn and return. + * + * Otherwise, send back a reply based on whether <b>success</b> is 1 or 0. + */ void connection_ap_handshake_socks_reply(connection_t *conn, char *reply, int replylen, char success) { char buf[256]; @@ -1148,6 +1277,22 @@ void connection_ap_handshake_socks_reply(connection_t *conn, char *reply, return; } +/** A relay 'begin' cell has arrived, and either we are an exit hop + * for the circuit, or we are the origin and it is a rendezvous begin. + * + * Launch a new exit connection and initialize things appropriately. + * + * If it's a rendezvous stream, call connection_exit_connect() on + * it. + * + * For general streams, call dns_resolve() on it first, and only call + * connection_exit_connect() if the dns answer is already known. + * + * Note that we don't call connection_add() on the new stream! We wait + * for connection_exit_connect() to do that. + * + * Return -1 if we want to tear down <b>circ</b>. Else return 0. + */ static int connection_exit_begin_conn(cell_t *cell, circuit_t *circ) { connection_t *n_stream; relay_header_t rh; @@ -1241,6 +1386,13 @@ static int connection_exit_begin_conn(cell_t *cell, circuit_t *circ) { return 0; } +/** Connect to conn's specified addr and port. If it worked, conn + * has now been added to the connection_array. + * + * Send back a connected cell. Include the resolved IP of the destination + * address, but <em>only</em> if it's a general exit stream. (Rendezvous + * streams must not reveal what IP they connected to.) + */ void connection_exit_connect(connection_t *conn) { unsigned char connected_payload[4]; @@ -1290,6 +1442,9 @@ void connection_exit_connect(connection_t *conn) { } } +/** Return 1 if <b>conn</b> is a rendezvous stream, or 0 if + * it is a general stream. + */ int connection_edge_is_rendezvous_stream(connection_t *conn) { tor_assert(conn); if(*conn->rend_query) /* XXX */ @@ -1297,6 +1452,11 @@ int connection_edge_is_rendezvous_stream(connection_t *conn) { return 0; } +/** Return 1 if router <b>exit</b> might allow stream <b>conn</b> + * to exit from it, or 0 if it definitely will not allow it. + * (We might be uncertain if conn's destination address has not yet been + * resolved.) + */ int connection_ap_can_use_exit(connection_t *conn, routerinfo_t *exit) { uint32_t addr; @@ -1321,19 +1481,31 @@ int connection_ap_can_use_exit(connection_t *conn, routerinfo_t *exit) * by answering funny things to stream begin requests, and later * other clients would reuse those funny addr's. Hm. */ + +/** A client-side struct to remember the resolved IP (addr) for + * a given address. These structs make up a tree, with client_dns_map + * below as its root. + */ struct client_dns_entry { - uint32_t addr; - time_t expires; - int n_failures; + uint32_t addr; /**< The resolved IP of this entry */ + time_t expires; /**< At what second does addr expire? */ + int n_failures; /**< How many times has this entry failed to resolve so far? */ }; + +/** How many elements are in the client dns cache currently? */ static int client_dns_size = 0; +/** The tree of client-side cached DNS resolves. */ static strmap_t *client_dns_map = NULL; +/** Initialize client_dns_map and client_dns_size. */ void client_dns_init(void) { client_dns_map = strmap_new(); client_dns_size = 0; } +/** Return the client_dns_entry that corresponds to <b>address</b>. + * If it's not there, allocate and return a new entry for <b>address</b>. + */ static struct client_dns_entry * _get_or_create_ent(const char *address) { @@ -1348,6 +1520,9 @@ _get_or_create_ent(const char *address) return ent; } +/** Return the IP associated with <b>address</b>, if we know it + * and it's still fresh enough. Otherwise return 0. + */ static uint32_t client_dns_lookup_entry(const char *address) { struct client_dns_entry *ent; @@ -1381,6 +1556,10 @@ static uint32_t client_dns_lookup_entry(const char *address) } } +/** An attempt to resolve <b>address</b> failed at some OR. + * Increment the number of resolve failures we have on record + * for it, and then return that number. + */ static int client_dns_incr_failures(const char *address) { struct client_dns_entry *ent; @@ -1391,6 +1570,11 @@ static int client_dns_incr_failures(const char *address) return ent->n_failures; } +/** Record the fact that <b>address</b> resolved to <b>val</b>. + * We can now use this in subsequent streams in client_dns_lookup_entry(), + * so we can more correctly choose a router that will allow <b>address</b> + * to exit from him. + */ static void client_dns_set_entry(const char *address, uint32_t val) { struct client_dns_entry *ent; @@ -1412,6 +1596,9 @@ static void client_dns_set_entry(const char *address, uint32_t val) ent->n_failures = 0; } +/** A helper function for client_dns_clean() below. If ent is too old, + * then remove it from the tree and return NULL, else return ent. + */ static void* _remove_if_expired(const char *addr, struct client_dns_entry *ent, time_t *nowp) @@ -1425,6 +1612,9 @@ static void* _remove_if_expired(const char *addr, } } +/** Clean out entries from the client-side DNS cache that were + * resolved long enough ago that they are no longer valid. + */ void client_dns_clean(void) { time_t now; |