comment and doxygenate connection_edge.c

svn:r1833
This commit is contained in:
Roger Dingledine
2004-05-10 04:42:22 +00:00
parent 81922a125c
commit 4845fe7197
+213 -23
View File
@@ -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;