summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRoger Dingledine <arma@torproject.org>2004-05-10 04:42:22 +0000
committerRoger Dingledine <arma@torproject.org>2004-05-10 04:42:22 +0000
commit4845fe7197768da95dee0153a647a30eac29eef7 (patch)
tree764e3eb95542b320b3c10ad943b4d9a30089cad9
parent81922a125ca17d6d46a378f9e7bf609d884524c2 (diff)
downloadtor-4845fe7197768da95dee0153a647a30eac29eef7.tar.gz
tor-4845fe7197768da95dee0153a647a30eac29eef7.zip
comment and doxygenate connection_edge.c
svn:r1833
-rw-r--r--src/or/connection_edge.c236
1 files changed, 213 insertions, 23 deletions
diff --git a/src/or/connection_edge.c b/src/or/connection_edge.c
index b07fcf391d..520a512eb5 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;