aboutsummaryrefslogtreecommitdiff
path: root/src/or
diff options
context:
space:
mode:
Diffstat (limited to 'src/or')
-rw-r--r--src/or/circuit.c242
-rw-r--r--src/or/config.c2
-rw-r--r--src/or/connection_ap.c208
-rw-r--r--src/or/connection_or.c2
-rw-r--r--src/or/main.c17
-rw-r--r--src/or/onion.c20
-rw-r--r--src/or/or.h39
-rw-r--r--src/or/test.c2
8 files changed, 288 insertions, 244 deletions
diff --git a/src/or/circuit.c b/src/or/circuit.c
index 593c5bddf..2157be0f2 100644
--- a/src/or/circuit.c
+++ b/src/or/circuit.c
@@ -4,6 +4,8 @@
#include "or.h"
+extern or_options_t options; /* command-line and config-file options */
+
/********* START VARIABLES **********/
static circuit_t *global_circuitlist=NULL;
@@ -49,12 +51,18 @@ void circuit_remove(circuit_t *circ) {
circuit_t *circuit_new(aci_t p_aci, connection_t *p_conn) {
circuit_t *circ;
+ struct timeval now;
+
+ if(gettimeofday(&now,NULL) < 0)
+ return NULL;
circ = (circuit_t *)malloc(sizeof(circuit_t));
if(!circ)
return NULL;
memset(circ,0,sizeof(circuit_t)); /* zero it out */
+ circ->timestamp_created = now.tv_sec;
+
circ->p_aci = p_aci;
circ->p_conn = p_conn;
@@ -252,20 +260,24 @@ circuit_t *circuit_get_by_conn(connection_t *conn) {
return NULL;
}
-circuit_t *circuit_get_by_edge_type(char edge_type) {
- circuit_t *circ;
+circuit_t *circuit_get_newest_by_edge_type(char edge_type) {
+ circuit_t *circ, *bestcirc=NULL;
for(circ=global_circuitlist;circ;circ = circ->next) {
- if(edge_type == EDGE_AP && circ->n_conn && circ->n_conn->type == CONN_TYPE_OR) {
- log(LOG_DEBUG,"circuit_get_by_edge_type(): Choosing n_aci %d.", circ->n_aci);
- return circ;
+ if(edge_type == EDGE_AP && (!circ->p_conn || circ->p_conn->type == CONN_TYPE_AP)) {
+ if(!bestcirc ||
+ (circ->state == CIRCUIT_STATE_OPEN && bestcirc->timestamp_created < circ->timestamp_created)) {
+ log(LOG_DEBUG,"circuit_get_newest_by_edge_type(): Choosing n_aci %d.", circ->n_aci);
+ bestcirc = circ;
+ }
}
- if(edge_type == EDGE_EXIT && circ->p_conn && circ->p_conn->type == CONN_TYPE_OR) {
- return circ;
+ if(edge_type == EDGE_EXIT && (!circ->n_conn || circ->n_conn->type == CONN_TYPE_EXIT)) {
+ if(!bestcirc ||
+ (circ->state == CIRCUIT_STATE_OPEN && bestcirc->timestamp_created < circ->timestamp_created))
+ bestcirc = circ;
}
- log(LOG_DEBUG,"circuit_get_by_edge_type(): Skipping p_aci %d / n_aci %d.", circ->p_aci, circ->n_aci);
}
- return NULL;
+ return bestcirc;
}
int circuit_deliver_data_cell_from_edge(cell_t *cell, circuit_t *circ, char edge_type) {
@@ -517,8 +529,11 @@ int circuit_consider_sending_sendme(circuit_t *circ, int edge_type) {
void circuit_close(circuit_t *circ) {
connection_t *conn;
+ circuit_t *youngest;
assert(circ);
+ if(options.APPort)
+ youngest = circuit_get_newest_by_edge_type(EDGE_AP);
circuit_remove(circ);
for(conn=circ->n_conn; conn; conn=conn->next_topic) {
connection_send_destroy(circ->n_aci, circ->n_conn);
@@ -526,6 +541,11 @@ void circuit_close(circuit_t *circ) {
for(conn=circ->p_conn; conn; conn=conn->next_topic) {
connection_send_destroy(circ->p_aci, circ->p_conn);
}
+ if(options.APPort && youngest == circ) { /* check this after we've sent the destroys, to reduce races */
+ /* our current circuit just died. Launch another one pronto. */
+ log(LOG_INFO,"circuit_close(): Youngest circuit dying. Launching a replacement.");
+ circuit_launch_new(1);
+ }
circuit_free(circ);
}
@@ -610,6 +630,210 @@ void circuit_dump_by_conn(connection_t *conn) {
}
}
+void circuit_expire_unused_circuits(void) {
+ circuit_t *circ, *tmpcirc;
+ circuit_t *youngest;
+
+ youngest = circuit_get_newest_by_edge_type(EDGE_AP);
+
+ circ = global_circuitlist;
+ while(circ) {
+ tmpcirc = circ;
+ circ = circ->next;
+ if(tmpcirc != youngest && (!tmpcirc->p_conn || tmpcirc->p_conn->type == CONN_TYPE_AP)) {
+ log(LOG_DEBUG,"circuit_expire_unused_circuits(): Closing n_aci %d",tmpcirc->n_aci);
+ circuit_close(tmpcirc);
+ }
+ }
+}
+
+/* failure_status code: negative means reset failures to 0. Other values mean
+ * add that value to the current number of failures, then if we don't have too
+ * many failures on record, try to make a new circuit.
+ */
+void circuit_launch_new(int failure_status) {
+ static int failures=0;
+
+ if(failure_status == -1) { /* I was called because a circuit succeeded */
+ failures = 0;
+ return;
+ }
+
+ failures += failure_status;
+
+retry_circuit:
+
+ if(failures > 5) {
+ log(LOG_INFO,"circuit_launch_new(): Giving up, %d failures.", failures);
+ return;
+ }
+
+ if(circuit_create_onion() < 0) {
+ failures++;
+ goto retry_circuit;
+ }
+
+ failures = 0;
+ return;
+}
+
+int circuit_create_onion(void) {
+ int i;
+ int routelen; /* length of the route */
+ unsigned int *route; /* hops in the route as an array of indexes into rarray */
+ unsigned char *onion; /* holds the onion */
+ int onionlen; /* onion length in host order */
+ crypt_path_t **cpath; /* defines the crypt operations that need to be performed on incoming/outgoing data */
+
+ /* choose a route */
+ route = (unsigned int *)router_new_route(&routelen);
+ if (!route) {
+ log(LOG_ERR,"circuit_create_onion(): Error choosing a route through the OR network.");
+ return -1;
+ }
+ log(LOG_DEBUG,"circuit_create_onion(): Chosen a route of length %u : ",routelen);
+
+ /* allocate memory for the crypt path */
+ cpath = malloc(routelen * sizeof(crypt_path_t *));
+ if (!cpath) {
+ log(LOG_ERR,"circuit_create_onion(): Error allocating memory for cpath.");
+ free(route);
+ return -1;
+ }
+
+ /* create an onion and calculate crypto keys */
+ onion = router_create_onion(route,routelen,&onionlen,cpath);
+ if (!onion) {
+ log(LOG_ERR,"circuit_create_onion(): Error creating an onion.");
+ free(route);
+ free(cpath); /* it's got nothing in it, since !onion */
+ return -1;
+ }
+ log(LOG_DEBUG,"circuit_create_onion(): Created an onion of size %u bytes.",onionlen);
+ log(LOG_DEBUG,"circuit_create_onion(): Crypt path :");
+ for (i=0;i<routelen;i++) {
+ log(LOG_DEBUG,"circuit_create_onion() : %u/%u",(cpath[i])->forwf, (cpath[i])->backf);
+ }
+
+ return circuit_establish_circuit(route, routelen, onion, onionlen, cpath);
+}
+
+int circuit_establish_circuit(unsigned int *route, int routelen, char *onion,
+ int onionlen, crypt_path_t **cpath) {
+ routerinfo_t *firsthop;
+ connection_t *n_conn;
+ circuit_t *circ;
+
+ /* now see if we're already connected to the first OR in 'route' */
+ firsthop = router_get_first_in_route(route, routelen);
+ assert(firsthop); /* should always be defined */
+ free(route); /* we don't need it anymore */
+
+ circ = circuit_new(0, NULL); /* sets circ->p_aci and circ->p_conn */
+ circ->state = CIRCUIT_STATE_OR_WAIT;
+ circ->onion = onion;
+ circ->onionlen = onionlen;
+ circ->cpath = cpath;
+ circ->cpathlen = routelen;
+
+ log(LOG_DEBUG,"circuit_establish_circuit(): Looking for firsthop '%s:%u'",
+ firsthop->address,firsthop->or_port);
+ n_conn = connection_twin_get_by_addr_port(firsthop->addr,firsthop->or_port);
+ if(!n_conn || n_conn->state != OR_CONN_STATE_OPEN) { /* not currently connected */
+ circ->n_addr = firsthop->addr;
+ circ->n_port = firsthop->or_port;
+ if(options.ORPort) { /* we would be connected if he were up. but he's not. */
+ log(LOG_DEBUG,"circuit_establish_circuit(): Route's firsthop isn't connected.");
+ circuit_close(circ);
+ return -1;
+ }
+
+ if(!n_conn) { /* launch the connection */
+ n_conn = connection_or_connect_as_op(firsthop);
+ if(!n_conn) { /* connect failed, forget the whole thing */
+ log(LOG_DEBUG,"circuit_establish_circuit(): connect to firsthop failed. Closing.");
+ circuit_close(circ);
+ return -1;
+ }
+ }
+
+ return 0; /* return success. The onion/circuit/etc will be taken care of automatically
+ * (may already have been) whenever n_conn reaches OR_CONN_STATE_OPEN.
+ */
+ } else { /* it (or a twin) is already open. use it. */
+ circ->n_addr = n_conn->addr;
+ circ->n_port = n_conn->port;
+ return circuit_send_onion(n_conn, circ);
+ }
+}
+
+/* find circuits that are waiting on me, if any, and get them to send the onion */
+void circuit_n_conn_open(connection_t *or_conn) {
+ circuit_t *circ;
+
+ log(LOG_DEBUG,"circuit_n_conn_open(): Starting.");
+ circ = circuit_enumerate_by_naddr_nport(NULL, or_conn->addr, or_conn->port);
+ for(;;) {
+ if(!circ)
+ return;
+
+ log(LOG_DEBUG,"circuit_n_conn_open(): Found circ, sending onion.");
+ if(circuit_send_onion(or_conn, circ) < 0) {
+ log(LOG_DEBUG,"circuit_n_conn_open(): circuit marked for closing.");
+ circuit_close(circ);
+ return; /* FIXME will want to try the other circuits too? */
+ }
+ circ = circuit_enumerate_by_naddr_nport(circ, or_conn->addr, or_conn->port);
+ }
+}
+
+int circuit_send_onion(connection_t *n_conn, circuit_t *circ) {
+ cell_t cell;
+ int tmpbuflen, dataleft;
+ char *tmpbuf;
+
+ circ->n_aci = get_unique_aci_by_addr_port(circ->n_addr, circ->n_port, ACI_TYPE_BOTH);
+ circ->n_conn = n_conn;
+ log(LOG_DEBUG,"circuit_send_onion(): n_conn is %s:%u",n_conn->address,n_conn->port);
+
+ /* deliver the onion as one or more create cells */
+ cell.command = CELL_CREATE;
+ cell.aci = circ->n_aci;
+
+ tmpbuflen = circ->onionlen+4;
+ tmpbuf = malloc(tmpbuflen);
+ if(!tmpbuf)
+ return -1;
+ *(uint32_t*)tmpbuf = htonl(circ->onionlen);
+ memcpy(tmpbuf+4, circ->onion, circ->onionlen);
+
+ dataleft = tmpbuflen;
+ while(dataleft) {
+ cell.command = CELL_CREATE;
+ cell.aci = circ->n_aci;
+ log(LOG_DEBUG,"circuit_send_onion(): Sending a create cell for the onion...");
+ if(dataleft >= CELL_PAYLOAD_SIZE) {
+ cell.length = CELL_PAYLOAD_SIZE;
+ memcpy(cell.payload, tmpbuf + tmpbuflen - dataleft, CELL_PAYLOAD_SIZE);
+ connection_write_cell_to_buf(&cell, n_conn);
+ dataleft -= CELL_PAYLOAD_SIZE;
+ } else { /* last cell */
+ cell.length = dataleft;
+ memcpy(cell.payload, tmpbuf + tmpbuflen - dataleft, dataleft);
+ /* fill extra space with 0 bytes */
+ memset(cell.payload + dataleft, 0, CELL_PAYLOAD_SIZE - dataleft);
+ connection_write_cell_to_buf(&cell, n_conn);
+ dataleft = 0;
+ }
+ }
+ free(tmpbuf);
+
+ circ->state = CIRCUIT_STATE_OPEN;
+ /* FIXME should set circ->expire to something here */
+
+ return 0;
+}
+
/*
Local Variables:
mode:c
diff --git a/src/or/config.c b/src/or/config.c
index d8828bdd3..f6c0bda54 100644
--- a/src/or/config.c
+++ b/src/or/config.c
@@ -187,6 +187,7 @@ void config_assign(or_options_t *options, struct config_line *list) {
config_compare(list, "DirFetchPeriod", CONFIG_TYPE_INT, &options->DirFetchPeriod) ||
config_compare(list, "KeepalivePeriod", CONFIG_TYPE_INT, &options->KeepalivePeriod) ||
config_compare(list, "MaxOnionsPending",CONFIG_TYPE_INT, &options->MaxOnionsPending) ||
+ config_compare(list, "NewCircuitPeriod",CONFIG_TYPE_INT, &options->NewCircuitPeriod) ||
config_compare(list, "Daemon", CONFIG_TYPE_BOOL, &options->Daemon) ||
config_compare(list, "TrafficShaping", CONFIG_TYPE_BOOL, &options->TrafficShaping) ||
@@ -224,6 +225,7 @@ int getconfig(int argc, char **argv, or_options_t *options) {
options->DirFetchPeriod = 600;
options->KeepalivePeriod = 300;
options->MaxOnionsPending = 10;
+ options->NewCircuitPeriod = 60; /* once a minute */
// options->ReconnectPeriod = 6001;
/* get config lines from /etc/torrc and assign them */
diff --git a/src/or/connection_ap.c b/src/or/connection_ap.c
index 831dd9b16..2a98537b8 100644
--- a/src/or/connection_ap.c
+++ b/src/or/connection_ap.c
@@ -4,8 +4,6 @@
#include "or.h"
-extern or_options_t options; /* command-line and config-file options */
-
int ap_handshake_process_socks(connection_t *conn) {
char c;
socks4_t socks4_info;
@@ -96,211 +94,25 @@ int ap_handshake_process_socks(connection_t *conn) {
}
/* find the circuit that we should use, if there is one. */
- circ = circuit_get_by_edge_type(EDGE_AP);
+ circ = circuit_get_newest_by_edge_type(EDGE_AP);
+ circ->dirty = 1;
/* now we're all ready to make an onion or send a begin */
- if(circ && circ->state == CIRCUIT_STATE_OPEN) {
- /* FIXME if circ not yet open, figure out how to queue this begin? */
- /* add it into the linked list of topics on this circuit */
- log(LOG_DEBUG,"ap_handshake_process_socks(): attaching new conn to circ. n_aci %d.", circ->n_aci);
- conn->next_topic = circ->p_conn;
- circ->p_conn = conn;
-
- if(ap_handshake_send_begin(conn, circ) < 0) {
- circuit_close(circ);
- return -1;
- }
- } else {
- if(ap_handshake_create_onion(conn) < 0) {
- if(circ)
- circuit_close(circ);
- return -1;
- }
- }
- return 0;
-}
-
-int ap_handshake_create_onion(connection_t *conn) {
- int i;
- int routelen = 0; /* length of the route */
- unsigned int *route = NULL; /* hops in the route as an array of indexes into rarray */
- unsigned char *onion = NULL; /* holds the onion */
- int onionlen = 0; /* onion length in host order */
- crypt_path_t **cpath = NULL; /* defines the crypt operations that need to be performed on incoming/outgoing data */
-
- assert(conn);
-
- /* choose a route */
- route = (unsigned int *)router_new_route(&routelen);
- if (!route) {
- log(LOG_ERR,"ap_handshake_create_onion(): Error choosing a route through the OR network.");
+ if(!circ) {
+ log(LOG_INFO,"ap_handshake_process_socks(): No circuit ready. Closing.");
return -1;
}
- log(LOG_DEBUG,"ap_handshake_create_onion(): Chosen a route of length %u : ",routelen);
-#if 0
- for (i=routelen-1;i>=0;i--)
- {
- log(LOG_DEBUG,"ap_handshake_process_ss() : %u : %s:%u, %u",routelen-i,(routerarray[route[i]])->address,ntohs((routerarray[route[i]])->port),RSA_size((routerarray[route[i]])->pkey));
- }
-#endif
- /* allocate memory for the crypt path */
- cpath = malloc(routelen * sizeof(crypt_path_t *));
- if (!cpath) {
- log(LOG_ERR,"ap_handshake_create_onion(): Error allocating memory for cpath.");
- free(route);
- return -1;
- }
+ /* add it into the linked list of topics on this circuit */
+ log(LOG_DEBUG,"ap_handshake_process_socks(): attaching new conn to circ. n_aci %d.", circ->n_aci);
+ conn->next_topic = circ->p_conn;
+ circ->p_conn = conn;
- /* create an onion and calculate crypto keys */
- onion = router_create_onion(route,routelen,&onionlen,cpath);
- if (!onion) {
- log(LOG_ERR,"ap_handshake_create_onion(): Error creating an onion.");
- free(route);
- free(cpath); /* it's got nothing in it, since !onion */
+ if(ap_handshake_send_begin(conn, circ) < 0) {
+ circuit_close(circ);
return -1;
}
- log(LOG_DEBUG,"ap_handshake_create_onion(): Created an onion of size %u bytes.",onionlen);
- log(LOG_DEBUG,"ap_handshake_create_onion(): Crypt path :");
- for (i=0;i<routelen;i++) {
- log(LOG_DEBUG,"ap_handshake_create_onion() : %u/%u",(cpath[i])->forwf, (cpath[i])->backf);
- }
-
- return ap_handshake_establish_circuit(conn, route, routelen, onion, onionlen, cpath);
-}
-
-int ap_handshake_establish_circuit(connection_t *conn, unsigned int *route, int routelen, char *onion,
- int onionlen, crypt_path_t **cpath) {
- routerinfo_t *firsthop;
- connection_t *n_conn;
- circuit_t *circ;
-
- /* now see if we're already connected to the first OR in 'route' */
- firsthop = router_get_first_in_route(route, routelen);
- assert(firsthop); /* should always be defined */
- free(route); /* we don't need it anymore */
-
- circ = circuit_new(0, conn); /* sets circ->p_aci and circ->p_conn */
- circ->state = CIRCUIT_STATE_OR_WAIT;
- circ->onion = onion;
- circ->onionlen = onionlen;
- circ->cpath = cpath;
- circ->cpathlen = routelen;
-
- log(LOG_DEBUG,"ap_handshake_establish_circuit(): Looking for firsthop '%s:%u'",
- firsthop->address,firsthop->or_port);
- n_conn = connection_twin_get_by_addr_port(firsthop->addr,firsthop->or_port);
- if(!n_conn || n_conn->state != OR_CONN_STATE_OPEN) { /* not currently connected */
- circ->n_addr = firsthop->addr;
- circ->n_port = firsthop->or_port;
- if(options.ORPort) { /* we would be connected if he were up. but he's not. */
- log(LOG_DEBUG,"ap_handshake_establish_circuit(): Route's firsthop isn't connected.");
- circuit_close(circ);
- return -1;
- }
-
- conn->state = AP_CONN_STATE_OR_WAIT;
- connection_stop_reading(conn); /* Stop listening for input from the AP! */
-
- if(!n_conn) { /* launch the connection */
- n_conn = connection_or_connect_as_op(firsthop);
- if(!n_conn) { /* connect failed, forget the whole thing */
- log(LOG_DEBUG,"ap_handshake_establish_circuit(): connect to firsthop failed. Closing.");
- circuit_close(circ);
- return -1;
- }
- }
-
- return 0; /* return success. The onion/circuit/etc will be taken care of automatically
- * (may already have been) whenever n_conn reaches OR_CONN_STATE_OPEN.
- */
- } else { /* it (or a twin) is already open. use it. */
- circ->n_addr = n_conn->addr;
- circ->n_port = n_conn->port;
- return ap_handshake_send_onion(conn, n_conn, circ);
- }
-}
-
-/* find circuits that are waiting on me, if any, and get them to send the onion */
-void ap_handshake_n_conn_open(connection_t *or_conn) {
- circuit_t *circ;
- connection_t *p_conn;
-
- log(LOG_DEBUG,"ap_handshake_n_conn_open(): Starting.");
- circ = circuit_enumerate_by_naddr_nport(NULL, or_conn->addr, or_conn->port);
- for(;;) {
- if(!circ)
- return;
-
- p_conn = circ->p_conn;
- if(p_conn->state != AP_CONN_STATE_OR_WAIT) {
- log(LOG_WARNING,"Bug: ap_handshake_n_conn_open() got an ap_conn not in OR_WAIT state.");
- }
- connection_start_reading(p_conn); /* resume listening for reads */
- log(LOG_DEBUG,"ap_handshake_n_conn_open(): Found circ, sending onion.");
- if(ap_handshake_send_onion(p_conn, or_conn, circ) < 0) {
- log(LOG_DEBUG,"ap_handshake_n_conn_open(): circuit marked for closing.");
- circuit_close(circ);
- return; /* FIXME will want to try the other circuits too? */
- }
- for(p_conn = p_conn->next_topic; p_conn; p_conn = p_conn->next_topic) { /* start up any other pending topics */
- if(ap_handshake_send_begin(p_conn, circ) < 0) {
- circuit_close(circ);
- return;
- }
- }
- circ = circuit_enumerate_by_naddr_nport(circ, or_conn->addr, or_conn->port);
- }
-}
-
-int ap_handshake_send_onion(connection_t *ap_conn, connection_t *n_conn, circuit_t *circ) {
- cell_t cell;
- int tmpbuflen, dataleft;
- char *tmpbuf;
-
- circ->n_aci = get_unique_aci_by_addr_port(circ->n_addr, circ->n_port, ACI_TYPE_BOTH);
- circ->n_conn = n_conn;
- log(LOG_DEBUG,"ap_handshake_send_onion(): n_conn is %s:%u",n_conn->address,n_conn->port);
-
- /* deliver the onion as one or more create cells */
- cell.command = CELL_CREATE;
- cell.aci = circ->n_aci;
-
- tmpbuflen = circ->onionlen+4;
- tmpbuf = malloc(tmpbuflen);
- if(!tmpbuf)
- return -1;
- *(uint32_t*)tmpbuf = htonl(circ->onionlen);
- memcpy(tmpbuf+4, circ->onion, circ->onionlen);
-
- dataleft = tmpbuflen;
- while(dataleft) {
- cell.command = CELL_CREATE;
- cell.aci = circ->n_aci;
- log(LOG_DEBUG,"ap_handshake_send_onion(): Sending a create cell for the onion...");
- if(dataleft >= CELL_PAYLOAD_SIZE) {
- cell.length = CELL_PAYLOAD_SIZE;
- memcpy(cell.payload, tmpbuf + tmpbuflen - dataleft, CELL_PAYLOAD_SIZE);
- connection_write_cell_to_buf(&cell, n_conn);
- dataleft -= CELL_PAYLOAD_SIZE;
- } else { /* last cell */
- cell.length = dataleft;
- memcpy(cell.payload, tmpbuf + tmpbuflen - dataleft, dataleft);
- /* fill extra space with 0 bytes */
- memset(cell.payload + dataleft, 0, CELL_PAYLOAD_SIZE - dataleft);
- connection_write_cell_to_buf(&cell, n_conn);
- dataleft = 0;
- }
- }
- free(tmpbuf);
-
- if(ap_handshake_send_begin(ap_conn, circ) < 0) {
- return -1;
- }
-
- circ->state = CIRCUIT_STATE_OPEN;
- /* FIXME should set circ->expire to something here */
return 0;
}
diff --git a/src/or/connection_or.c b/src/or/connection_or.c
index 9cac2c9ca..15ad3839d 100644
--- a/src/or/connection_or.c
+++ b/src/or/connection_or.c
@@ -334,7 +334,7 @@ int or_handshake_op_finished_sending_keys(connection_t *conn) {
conn_or_init_crypto(conn);
connection_or_set_open(conn);
- ap_handshake_n_conn_open(conn); /* send the pending onions */
+ circuit_n_conn_open(conn); /* send the pending onion(s) */
return 0;
}
diff --git a/src/or/main.c b/src/or/main.c
index 446603627..023836d4b 100644
--- a/src/or/main.c
+++ b/src/or/main.c
@@ -302,8 +302,10 @@ int prepare_for_poll(int *timeout) {
struct timeval now; //soonest;
static long current_second = 0; /* from previous calls to gettimeofday */
static long time_to_fetch_directory = 0;
+ static long time_to_new_circuit = 0;
// int ms_until_conn;
cell_t cell;
+ circuit_t *circ;
if(gettimeofday(&now,NULL) < 0)
return -1;
@@ -321,6 +323,17 @@ int prepare_for_poll(int *timeout) {
}
}
+ if(options.APPort && time_to_new_circuit < now.tv_sec) {
+ circuit_expire_unused_circuits();
+ circuit_launch_new(-1); /* tell it to forget about previous failures */
+ circ = circuit_get_newest_by_edge_type(EDGE_AP);
+ if(!circ || circ->dirty) {
+ log(LOG_INFO,"prepare_for_poll(): Youngest circuit missing or dirty; launching replacement.");
+ circuit_launch_new(0); /* make an onion and lay the circuit */
+ }
+ time_to_new_circuit = now.tv_sec + options.NewCircuitPeriod;
+ }
+
/* do housekeeping for each connection */
for(i=0;i<nfds;i++) {
tmpconn = connection_array[i];
@@ -514,7 +527,7 @@ static void catch(int the_signal) {
}
}
-void dumpstats (void) { /* dump stats to stdout */
+void dumpstats(void) { /* dump stats to stdout */
int i;
connection_t *conn;
struct timeval now;
@@ -638,7 +651,7 @@ void dump_directory_to_string(char *s, int maxlen) {
}
-void daemonize() {
+void daemonize(void) {
/* Fork; parent exits. */
if (fork())
exit(0);
diff --git a/src/or/onion.c b/src/or/onion.c
index 6d920052a..d2cc6839b 100644
--- a/src/or/onion.c
+++ b/src/or/onion.c
@@ -337,9 +337,9 @@ unsigned int *new_route(double cw, routerinfo_t **rarray, int rarray_len, int *r
{
int i, j;
int num_acceptable_routers;
- unsigned int *route = NULL;
+ unsigned int *route;
unsigned int oldchoice, choice;
-
+
assert((cw >= 0) && (cw < 1) && (rarray) && (routelen) ); /* valid parameters */
*routelen = chooselen(cw);
@@ -351,6 +351,11 @@ unsigned int *new_route(double cw, routerinfo_t **rarray, int rarray_len, int *r
num_acceptable_routers = count_acceptable_routers(rarray, rarray_len);
+ if(num_acceptable_routers < 2) {
+ log(LOG_INFO,"new_route(): Not enough acceptable routers. Failing.");
+ return NULL;
+ }
+
if(num_acceptable_routers < *routelen) {
log(LOG_DEBUG,"new_route(): Cutting routelen from %d to %d.",*routelen, num_acceptable_routers);
*routelen = num_acceptable_routers;
@@ -399,13 +404,16 @@ unsigned int *new_route(double cw, routerinfo_t **rarray, int rarray_len, int *r
static int count_acceptable_routers(routerinfo_t **rarray, int rarray_len) {
int i, j;
int num=0;
+ connection_t *conn;
for(i=0;i<rarray_len;i++) {
log(LOG_DEBUG,"Contemplating whether router %d is a new option...",i);
- if(options.ORPort &&
- !connection_exact_get_by_addr_port(rarray[i]->addr, rarray[i]->or_port)) {
- log(LOG_DEBUG,"Nope, %d is not connected.",i);
- goto next_i_loop;
+ if(options.ORPort) {
+ conn = connection_exact_get_by_addr_port(rarray[i]->addr, rarray[i]->or_port);
+ if(!conn || conn->type != CONN_TYPE_OR || conn->state != OR_CONN_STATE_OPEN) {
+ log(LOG_DEBUG,"Nope, %d is not connected.",i);
+ goto next_i_loop;
+ }
}
for(j=0;j<i;j++) {
if(!crypto_pk_cmp_keys(rarray[i]->pkey, rarray[j]->pkey)) {
diff --git a/src/or/or.h b/src/or/or.h
index cc8f0461e..fcd3acff8 100644
--- a/src/or/or.h
+++ b/src/or/or.h
@@ -341,7 +341,7 @@ struct data_queue_t {
struct data_queue_t *next;
};
-/* per-anonymous-connection struct */
+/* struct for a path (circuit) through the network */
typedef struct {
uint32_t n_addr;
uint16_t n_port;
@@ -365,6 +365,8 @@ typedef struct {
int cpathlen;
uint32_t expire; /* expiration time for the corresponding onion */
+ long timestamp_created;
+ char dirty; /* whether this circuit has been used yet */
int state;
@@ -381,20 +383,6 @@ struct onion_queue_t {
struct onion_queue_t *next;
};
-#if 0
-typedef struct
-{
- int zero:1;
- int version:7;
- int backf:4;
- int forwf:4;
- uint16_t port;
- uint32_t addr;
- uint32_t expire;
- unsigned char keyseed[16];
-} onion_layer_t;
-#endif
-
#define ONION_LAYER_SIZE 28
#define ONION_PADDING_SIZE (128-ONION_LAYER_SIZE)
@@ -415,11 +403,11 @@ typedef struct {
int DirFetchPeriod;
int KeepalivePeriod;
int MaxOnionsPending;
+ int NewCircuitPeriod;
int Role;
int loglevel;
} or_options_t;
-
/* all the function prototypes go here */
/********************************* buffers.c ***************************/
@@ -491,7 +479,7 @@ aci_t get_unique_aci_by_addr_port(uint32_t addr, uint16_t port, int aci_type);
circuit_t *circuit_get_by_aci_conn(aci_t aci, connection_t *conn);
circuit_t *circuit_get_by_conn(connection_t *conn);
-circuit_t *circuit_get_by_edge_type(char edge_type);
+circuit_t *circuit_get_newest_by_edge_type(char edge_type);
circuit_t *circuit_enumerate_by_naddr_nport(circuit_t *start, uint32_t naddr, uint16_t nport);
int circuit_deliver_data_cell_from_edge(cell_t *cell, circuit_t *circ, char edge_type);
@@ -506,8 +494,6 @@ int circuit_init(circuit_t *circ, int aci_type);
void circuit_free(circuit_t *circ);
void circuit_free_cpath(crypt_path_t **cpath, int cpathlen);
-
-
void circuit_close(circuit_t *circ);
void circuit_about_to_close_connection(connection_t *conn);
@@ -515,6 +501,13 @@ void circuit_about_to_close_connection(connection_t *conn);
void circuit_dump_by_conn(connection_t *conn);
+void circuit_launch_new(int failure_status);
+int circuit_create_onion(void);
+int circuit_establish_circuit(unsigned int *route, int routelen, char *onion,
+ int onionlen, crypt_path_t **cpath);
+void circuit_n_conn_open(connection_t *or_conn);
+int circuit_send_onion(connection_t *or_conn, circuit_t *circ);
+
/********************************* command.c ***************************/
void command_process_cell(cell_t *cell, connection_t *conn);
@@ -611,14 +604,6 @@ int connection_finished_flushing(connection_t *conn);
int ap_handshake_process_socks(connection_t *conn);
-int ap_handshake_create_onion(connection_t *conn);
-
-int ap_handshake_establish_circuit(connection_t *conn, unsigned int *route, int routelen, char *onion,
- int onionlen, crypt_path_t **cpath);
-
-void ap_handshake_n_conn_open(connection_t *or_conn);
-
-int ap_handshake_send_onion(connection_t *ap_conn, connection_t *or_conn, circuit_t *circ);
int ap_handshake_send_begin(connection_t *ap_conn, circuit_t *circ);
int ap_handshake_socks_reply(connection_t *conn, char result);
diff --git a/src/or/test.c b/src/or/test.c
index 5453f4b18..3ff3fb6f6 100644
--- a/src/or/test.c
+++ b/src/or/test.c
@@ -182,7 +182,7 @@ test_buffers() {
j = decompress_buf_to_buf(&buf, &buflen, &buf_datalen,
&buf2, &buf2len, &buf2_datalen,
decomp, 1);
- /*XXXX check result *
+ /*XXXX check result */
/* Now compress more, into less room. */
for (i = 0; i < 20; ++i) {