aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/or/Makefile.am2
-rw-r--r--src/or/buffers.c2
-rw-r--r--src/or/circuit.c340
-rw-r--r--src/or/command.c115
-rw-r--r--src/or/config.c4
-rw-r--r--src/or/connection.c122
-rw-r--r--src/or/connection_ap.c203
-rw-r--r--src/or/connection_exit.c353
-rw-r--r--src/or/dns.c434
-rw-r--r--src/or/main.c47
-rw-r--r--src/or/onion.c53
-rw-r--r--src/or/or.h106
12 files changed, 1344 insertions, 437 deletions
diff --git a/src/or/Makefile.am b/src/or/Makefile.am
index 460e0d68f3..e96b195c90 100644
--- a/src/or/Makefile.am
+++ b/src/or/Makefile.am
@@ -9,7 +9,7 @@ or_LDADD = -L../common -lor
or_SOURCES = buffers.c circuit.c command.c connection.c \
connection_exit.c connection_ap.c connection_op.c connection_or.c config.c \
- main.c onion.c routers.c directory.c
+ main.c onion.c routers.c directory.c dns.c
test_config_SOURCES = test_config.c
diff --git a/src/or/buffers.c b/src/or/buffers.c
index 5b4053c90d..45d2b74ddb 100644
--- a/src/or/buffers.c
+++ b/src/or/buffers.c
@@ -51,7 +51,7 @@ int read_to_buf(int s, int at_most, char **buf, int *buflen, int *buf_datalen, i
/* if no linkpadding: do a rudimentary round-robin so one
* connection can't hog an outgoing connection
*/
- at_most = 10*sizeof(cell_t);
+ at_most = 10*sizeof(cell_t); /* FIXME should be 10* size of usable payload */
}
// log(LOG_DEBUG,"read_to_buf(): reading at most %d bytes.",at_most);
diff --git a/src/or/circuit.c b/src/or/circuit.c
index f2b7b6f2b8..6949356bf0 100644
--- a/src/or/circuit.c
+++ b/src/or/circuit.c
@@ -64,8 +64,8 @@ circuit_t *circuit_new(aci_t p_aci, connection_t *p_conn) {
circ->p_aci = p_aci;
/* circ->n_aci remains 0 because we haven't identified the next hop yet */
- circ->n_receive_window = RECEIVE_WINDOW_START;
- circ->p_receive_window = RECEIVE_WINDOW_START;
+ circ->n_receive_circwindow = CIRCWINDOW_START;
+ circ->p_receive_circwindow = CIRCWINDOW_START;
circuit_add(circ);
@@ -73,6 +73,7 @@ circuit_t *circuit_new(aci_t p_aci, connection_t *p_conn) {
}
void circuit_free(circuit_t *circ) {
+ struct data_queue_t *tmpd;
if (circ->n_crypto)
crypto_free_cipher_env(circ->n_crypto);
@@ -83,6 +84,12 @@ void circuit_free(circuit_t *circ) {
free(circ->onion);
if(circ->cpath)
circuit_free_cpath(circ->cpath, circ->cpathlen);
+ while(circ->data_queue) {
+ tmpd = circ->data_queue;
+ circ->data_queue = tmpd->next;
+ free(tmpd->cell);
+ free(tmpd);
+ }
free(circ);
}
@@ -202,7 +209,7 @@ circuit_t *circuit_enumerate_by_naddr_nport(circuit_t *circ, uint32_t naddr, uin
else
circ = circ->next;
- for( ;circ;circ = circ->next) {
+ for( ; circ; circ = circ->next) {
if(circ->n_addr == naddr && circ->n_port == nport)
return circ;
}
@@ -211,56 +218,108 @@ circuit_t *circuit_enumerate_by_naddr_nport(circuit_t *circ, uint32_t naddr, uin
circuit_t *circuit_get_by_aci_conn(aci_t aci, connection_t *conn) {
circuit_t *circ;
+ connection_t *tmpconn;
for(circ=global_circuitlist;circ;circ = circ->next) {
- if(circ->p_conn == conn && circ->p_aci == aci)
- return circ;
- if(circ->n_conn == conn && circ->n_aci == aci)
- return circ;
+ if(circ->p_aci == aci) {
+ for(tmpconn = circ->p_conn; tmpconn; tmpconn = tmpconn->next_topic) {
+ if(tmpconn == conn)
+ return circ;
+ }
+ }
+ if(circ->n_aci == aci) {
+ for(tmpconn = circ->n_conn; tmpconn; tmpconn = tmpconn->next_topic) {
+ if(tmpconn == conn)
+ return circ;
+ }
+ }
}
return NULL;
}
circuit_t *circuit_get_by_conn(connection_t *conn) {
circuit_t *circ;
+ connection_t *tmpconn;
for(circ=global_circuitlist;circ;circ = circ->next) {
- if(circ->p_conn == conn)
- return circ;
- if(circ->n_conn == conn)
- return circ;
+ for(tmpconn = circ->p_conn; tmpconn; tmpconn=tmpconn->next_topic)
+ if(tmpconn == conn)
+ return circ;
+ for(tmpconn = circ->n_conn; tmpconn; tmpconn=tmpconn->next_topic)
+ if(tmpconn == conn)
+ return circ;
}
return NULL;
}
-int circuit_deliver_data_cell(cell_t *cell, circuit_t *circ, connection_t *conn, int crypt_type) {
+int circuit_deliver_data_cell_from_edge(cell_t *cell, circuit_t *circ, char edge_type) {
+ int cell_direction;
+
+ log(LOG_DEBUG,"circuit_deliver_data_cell_from_edge(): called, edge_type %d.", edge_type);
- /* first decrypt cell->length */
- if(circuit_crypt(circ, &(cell->length), 1, crypt_type) < 0) {
- log(LOG_DEBUG,"circuit_deliver_data_cell(): length decryption failed. Dropping connection.");
+ if(edge_type == EDGE_AP) { /* i'm the AP */
+ cell_direction = CELL_DIRECTION_OUT;
+ if(circ->p_receive_circwindow <= 0) {
+ log(LOG_DEBUG,"circuit_deliver_data_cell_from_edge(): window 0, queueing for later.");
+ circ->data_queue = data_queue_add(circ->data_queue, cell);
+ return 0;
+ }
+ circ->p_receive_circwindow--;
+ } else { /* i'm the exit */
+ cell_direction = CELL_DIRECTION_IN;
+ if(circ->n_receive_circwindow <= 0) {
+ log(LOG_DEBUG,"circuit_deliver_data_cell_from_edge(): window 0, queueing for later.");
+ circ->data_queue = data_queue_add(circ->data_queue, cell);
+ return 0;
+ }
+ circ->n_receive_circwindow--;
+ }
+
+ if(circuit_deliver_data_cell(cell, circ, cell_direction) < 0) {
+ return -1;
+ }
+
+ circuit_consider_stop_edge_reading(circ, edge_type); /* has window reached 0? */
+ return 0;
+}
+
+int circuit_deliver_data_cell(cell_t *cell, circuit_t *circ, int cell_direction) {
+ connection_t *conn;
+
+ assert(cell && circ);
+ assert(cell_direction == CELL_DIRECTION_OUT || cell_direction == CELL_DIRECTION_IN);
+ if(cell_direction == CELL_DIRECTION_OUT)
+ conn = circ->n_conn;
+ else
+ conn = circ->p_conn;
+
+ /* first crypt cell->length */
+ if(circuit_crypt(circ, &(cell->length), 1, cell_direction) < 0) {
+ log(LOG_DEBUG,"circuit_deliver_data_cell(): length crypt failed. Dropping connection.");
return -1;
}
- /* then decrypt the payload */
- if(circuit_crypt(circ, (char *)&(cell->payload), CELL_PAYLOAD_SIZE, crypt_type) < 0) {
- log(LOG_DEBUG,"circuit_deliver_data_cell(): payload decryption failed. Dropping connection.");
+ /* then crypt the payload */
+ if(circuit_crypt(circ, (char *)&(cell->payload), CELL_PAYLOAD_SIZE, cell_direction) < 0) {
+ log(LOG_DEBUG,"circuit_deliver_data_cell(): payload crypt failed. Dropping connection.");
return -1;
}
- if(conn->type == CONN_TYPE_EXIT) { /* send payload directly */
-// log(LOG_DEBUG,"circuit_deliver_data_cell(): Sending to exit.");
- return connection_exit_process_data_cell(cell, conn);
+ if((!conn && cell_direction == CELL_DIRECTION_OUT) || (conn && conn->type == CONN_TYPE_EXIT)) {
+ log(LOG_DEBUG,"circuit_deliver_data_cell(): Sending to exit.");
+ return connection_exit_process_data_cell(cell, circ);
}
- if(conn->type == CONN_TYPE_AP) { /* send payload directly */
-// log(LOG_DEBUG,"circuit_deliver_data_cell(): Sending to AP.");
- return connection_ap_process_data_cell(cell, conn);
+ if((!conn && cell_direction == CELL_DIRECTION_IN) || (conn && conn->type == CONN_TYPE_AP)) {
+ log(LOG_DEBUG,"circuit_deliver_data_cell(): Sending to AP.");
+ return connection_ap_process_data_cell(cell, circ);
}
/* else send it as a cell */
-// log(LOG_DEBUG,"circuit_deliver_data_cell(): Sending to connection.");
+ assert(conn);
+ //log(LOG_DEBUG,"circuit_deliver_data_cell(): Sending to connection.");
return connection_write_cell_to_buf(cell, conn);
}
-int circuit_crypt(circuit_t *circ, char *in, int inlen, char crypt_type) {
+int circuit_crypt(circuit_t *circ, char *in, int inlen, char cell_direction) {
char *out;
int i;
crypt_path_t *thishop;
@@ -271,20 +330,17 @@ int circuit_crypt(circuit_t *circ, char *in, int inlen, char crypt_type) {
if(!out)
return -1;
- if(crypt_type == 'e') {
-// log(LOG_DEBUG,"circuit_crypt(): Encrypting %d bytes.",inlen);
+ if(cell_direction == CELL_DIRECTION_IN) { //crypt_type == 'e') {
if(circ->cpath) { /* we're at the beginning of the circuit. We'll want to do layered crypts. */
- /* 'e' means we're preparing to send it out. */
- for (i=0; i < circ->cpathlen; i++) /* moving from last to first hop
- * Remember : cpath is in reverse order, i.e. last hop first
- */
+ for (i=circ->cpathlen-1; i >= 0; i--) /* moving from first to last hop
+ * Remember : cpath is in reverse order, i.e. last hop first
+ */
{
-// log(LOG_DEBUG,"circuit_crypt() : Encrypting via cpath: Processing hop %u",circ->cpathlen-i);
thishop = circ->cpath[i];
-
- /* encrypt */
- if(crypto_cipher_encrypt(thishop->f_crypto, in, inlen, (unsigned char *)out)) {
- log(LOG_ERR,"Error performing encryption:%s",crypto_perror());
+
+ /* decrypt */
+ if(crypto_cipher_decrypt(thishop->b_crypto, in, inlen, out)) {
+ log(LOG_ERR,"Error performing decryption:%s",crypto_perror());
free(out);
return -1;
}
@@ -301,19 +357,17 @@ int circuit_crypt(circuit_t *circ, char *in, int inlen, char crypt_type) {
}
memcpy(in,out,inlen);
}
- } else if(crypt_type == 'd') {
-// log(LOG_DEBUG,"circuit_crypt(): Decrypting %d bytes.",inlen);
+ } else if(cell_direction == CELL_DIRECTION_OUT) { //crypt_type == 'd') {
if(circ->cpath) { /* we're at the beginning of the circuit. We'll want to do layered crypts. */
- for (i=circ->cpathlen-1; i >= 0; i--) /* moving from first to last hop
- * Remember : cpath is in reverse order, i.e. last hop first
- */
+ for (i=0; i < circ->cpathlen; i++) /* moving from last to first hop
+ * Remember : cpath is in reverse order, i.e. last hop first
+ */
{
-// log(LOG_DEBUG,"circuit_crypt() : Decrypting via cpath: Processing hop %u",circ->cpathlen-i);
thishop = circ->cpath[i];
-
+
/* encrypt */
- if(crypto_cipher_decrypt(thishop->b_crypto, in, inlen, out)) {
- log(LOG_ERR,"Error performing decryption:%s",crypto_perror());
+ if(crypto_cipher_encrypt(thishop->f_crypto, in, inlen, (unsigned char *)out)) {
+ log(LOG_ERR,"Error performing encryption:%s",crypto_perror());
free(out);
return -1;
}
@@ -330,19 +384,120 @@ int circuit_crypt(circuit_t *circ, char *in, int inlen, char crypt_type) {
}
memcpy(in,out,inlen);
}
+ } else {
+ log(LOG_ERR,"circuit_crypt(): unknown cell direction %d.", cell_direction);
+ assert(0);
}
free(out);
+ return 0;
+}
+
+void circuit_resume_edge_reading(circuit_t *circ, int edge_type) {
+ connection_t *conn;
+ struct data_queue_t *tmpd;
+
+ assert(edge_type == EDGE_EXIT || edge_type == EDGE_AP);
+
+ if(edge_type == EDGE_EXIT)
+ conn = circ->n_conn;
+ else
+ conn = circ->p_conn;
+
+ /* first, send the queue waiting at circ onto the circuit */
+ while(circ->data_queue) {
+ assert(circ->data_queue->cell);
+ if(edge_type == EDGE_EXIT) {
+ circ->p_receive_circwindow--;
+ assert(circ->p_receive_circwindow >= 0);
+
+ if(circuit_deliver_data_cell(circ->data_queue->cell, circ, CELL_DIRECTION_IN) < 0) {
+ circuit_close(circ);
+ return;
+ }
+ } else { /* ap */
+ circ->p_receive_circwindow--;
+ assert(circ->p_receive_circwindow >= 0);
+
+ if(circuit_deliver_data_cell(circ->data_queue->cell, circ, CELL_DIRECTION_IN) < 0) {
+ circuit_close(circ);
+ return;
+ }
+ }
+ tmpd = circ->data_queue;
+ circ->data_queue = tmpd->next;
+ free(tmpd->cell);
+ free(tmpd);
+
+ if(circuit_consider_stop_edge_reading(circ, edge_type))
+ return;
+ }
+
+ for( ; conn; conn=conn->next_topic) {
+ if((edge_type == EDGE_EXIT && conn->n_receive_topicwindow > 0) ||
+ (edge_type == EDGE_AP && conn->p_receive_topicwindow > 0)) {
+ connection_start_reading(conn);
+ connection_package_raw_inbuf(conn); /* handle whatever might still be on the inbuf */
+ }
+ }
+ circuit_consider_stop_edge_reading(circ, edge_type);
+}
+
+/* returns 1 if the window is empty, else 0. If it's empty, tell edge conns to stop reading. */
+int circuit_consider_stop_edge_reading(circuit_t *circ, int edge_type) {
+ connection_t *conn = NULL;
+
+ assert(edge_type == EDGE_EXIT || edge_type == EDGE_AP);
+
+ if(edge_type == EDGE_EXIT && circ->p_receive_circwindow <= 0)
+ conn = circ->n_conn;
+ else if(edge_type == EDGE_AP && circ->n_receive_circwindow <= 0)
+ conn = circ->p_conn;
+ else
+ return 0;
+
+ for( ; conn; conn=conn->next_topic)
+ connection_stop_reading(conn);
+
+ return 1;
+}
+
+int circuit_consider_sending_sendme(circuit_t *circ, int edge_type) {
+ cell_t sendme;
+ assert(circ);
+
+ sendme.command = CELL_SENDME;
+ sendme.length = CIRCWINDOW_INCREMENT;
+
+ if(edge_type == EDGE_AP) { /* i'm the AP */
+ if(circ->n_receive_circwindow < CIRCWINDOW_START-CIRCWINDOW_INCREMENT) {
+ log(LOG_DEBUG,"circuit_consider_sending_sendme(): Queueing sendme forward.");
+ circ->n_receive_circwindow += CIRCWINDOW_INCREMENT;
+ sendme.aci = circ->n_aci;
+ return connection_write_cell_to_buf(&sendme, circ->n_conn); /* (clobbers sendme) */
+ }
+ } else if(edge_type == EDGE_EXIT) { /* i'm the exit */
+ if(circ->p_receive_circwindow < CIRCWINDOW_START-CIRCWINDOW_INCREMENT) {
+ log(LOG_DEBUG,"circuit_consider_sending_sendme(): Queueing sendme back.");
+ circ->p_receive_circwindow += CIRCWINDOW_INCREMENT;
+ sendme.aci = circ->p_aci;
+ return connection_write_cell_to_buf(&sendme, circ->p_conn); /* (clobbers sendme) */
+ }
+ }
return 0;
}
void circuit_close(circuit_t *circ) {
+ connection_t *conn;
+
circuit_remove(circ);
- if(circ->n_conn)
+ for(conn=circ->n_conn; conn; conn=conn->next_topic) {
connection_send_destroy(circ->n_aci, circ->n_conn);
- if(circ->p_conn)
+ }
+ for(conn=circ->p_conn; conn; conn=conn->next_topic) {
connection_send_destroy(circ->p_aci, circ->p_conn);
+ }
circuit_free(circ);
}
@@ -352,31 +507,98 @@ void circuit_about_to_close_connection(connection_t *conn) {
* down the road, maybe we'll consider that eof doesn't mean can't-write
*/
circuit_t *circ;
+ connection_t *prevconn, *tmpconn;
+ cell_t cell;
+ int edge_type;
+
+ if(!connection_speaks_cells(conn)) {
+ /* it's an edge conn. need to remove it from the linked list of
+ * conn's for this circuit. Send an 'end' data topic.
+ * But don't kill the circuit.
+ */
+
+ circ = circuit_get_by_conn(conn);
+ if(!circ)
+ return;
+
+ memset(&cell, 0, sizeof(cell_t));
+ cell.command = CELL_DATA;
+ cell.length = TOPIC_HEADER_SIZE;
+ *(uint32_t *)cell.payload = conn->topic_id;
+ *cell.payload = TOPIC_COMMAND_END;
+
+ if(conn == circ->p_conn) {
+ circ->p_conn = conn->next_topic;
+ edge_type = EDGE_AP;
+ goto send_end;
+ }
+ if(conn == circ->n_conn) {
+ circ->n_conn = conn->next_topic;
+ edge_type = EDGE_EXIT;
+ goto send_end;
+ }
+ for(prevconn = circ->p_conn; prevconn->next_topic && prevconn->next_topic != conn; prevconn = prevconn->next_topic) ;
+ if(prevconn->next_topic) {
+ prevconn->next_topic = conn->next_topic;
+ edge_type = EDGE_AP;
+ goto send_end;
+ }
+ for(prevconn = circ->n_conn; prevconn->next_topic && prevconn->next_topic != conn; prevconn = prevconn->next_topic) ;
+ if(prevconn->next_topic) {
+ prevconn->next_topic = conn->next_topic;
+ edge_type = EDGE_EXIT;
+ goto send_end;
+ }
+ log(LOG_ERR,"circuit_about_to_close_connection(): edge conn not in circuit's list?");
+ assert(0); /* should never get here */
+send_end:
+ if(edge_type == EDGE_AP) { /* send to circ->n_conn */
+ log(LOG_INFO,"circuit_about_to_close_connection(): send data end forward (aci %d).",circ->n_aci);
+ cell.aci = circ->n_aci;
+ } else { /* send to circ->p_conn */
+ assert(edge_type == EDGE_EXIT);
+ log(LOG_INFO,"circuit_about_to_close_connection(): send data end backward (aci %d).",circ->p_aci);
+ cell.aci = circ->p_aci;
+ }
+
+ if(circuit_deliver_data_cell_from_edge(&cell, circ, edge_type) < 0) {
+ log(LOG_DEBUG,"circuit_about_to_close_connection(): circuit_deliver_data_cell_from_edge (%d) failed. Closing.", edge_type);
+ circuit_close(circ);
+ }
+ return;
+ }
while((circ = circuit_get_by_conn(conn))) {
circuit_remove(circ);
if(circ->n_conn == conn) /* it's closing in front of us */
- /* circ->p_conn should always be set */
- assert(circ->p_conn);
- connection_send_destroy(circ->p_aci, circ->p_conn);
+ for(tmpconn=circ->p_conn; tmpconn; tmpconn=tmpconn->next_topic) {
+ connection_send_destroy(circ->p_aci, tmpconn);
+ }
if(circ->p_conn == conn) /* it's closing behind us */
- if(circ->n_conn)
- connection_send_destroy(circ->n_aci, circ->n_conn);
+ for(tmpconn=circ->n_conn; tmpconn; tmpconn=tmpconn->next_topic) {
+ connection_send_destroy(circ->n_aci, tmpconn);
+ }
circuit_free(circ);
}
}
+/* FIXME this now leaves some out */
void circuit_dump_by_conn(connection_t *conn) {
circuit_t *circ;
+ connection_t *tmpconn;
for(circ=global_circuitlist;circ;circ = circ->next) {
- if(circ->p_conn == conn) {
- printf("Conn %d has App-ward circuit: aci %d (other side %d), state %d (%s)\n",
- conn->poll_index, circ->p_aci, circ->n_aci, circ->state, circuit_state_to_string[circ->state]);
+ for(tmpconn=circ->p_conn; tmpconn; tmpconn=tmpconn->next_topic) {
+ if(tmpconn == conn) {
+ printf("Conn %d has App-ward circuit: aci %d (other side %d), state %d (%s)\n",
+ conn->poll_index, circ->p_aci, circ->n_aci, circ->state, circuit_state_to_string[circ->state]);
+ }
}
- if(circ->n_conn == conn) {
- printf("Conn %d has Exit-ward circuit: aci %d (other side %d), state %d (%s)\n",
- conn->poll_index, circ->n_aci, circ->p_aci, circ->state, circuit_state_to_string[circ->state]);
+ for(tmpconn=circ->n_conn; tmpconn; tmpconn=tmpconn->next_topic) {
+ if(tmpconn == conn) {
+ printf("Conn %d has Exit-ward circuit: aci %d (other side %d), state %d (%s)\n",
+ conn->poll_index, circ->n_aci, circ->p_aci, circ->state, circuit_state_to_string[circ->state]);
+ }
}
}
}
diff --git a/src/or/command.c b/src/or/command.c
index ab042c0609..944a4f0ad5 100644
--- a/src/or/command.c
+++ b/src/or/command.c
@@ -38,8 +38,8 @@ void command_time_process_cell(cell_t *cell, connection_t *conn,
}
void command_process_cell(cell_t *cell, connection_t *conn) {
- static int num_create=0, num_data=0, num_destroy=0, num_sendme=0, num_connected=0;
- static int create_time=0, data_time=0, destroy_time=0, sendme_time=0, connected_time=0;
+ static int num_create=0, num_data=0, num_destroy=0, num_sendme=0;
+ static int create_time=0, data_time=0, destroy_time=0, sendme_time=0;
static long current_second = 0; /* from previous calls to gettimeofday */
struct timeval now;
@@ -55,11 +55,10 @@ void command_process_cell(cell_t *cell, connection_t *conn) {
log(LOG_INFO,"Data: %d (%d ms)", num_data, data_time/1000);
log(LOG_INFO,"Destroy: %d (%d ms)", num_destroy, destroy_time/1000);
log(LOG_INFO,"Sendme: %d (%d ms)", num_sendme, sendme_time/1000);
- log(LOG_INFO,"Connected: %d (%d ms)", num_connected, connected_time/1000);
/* zero out stats */
- num_create = num_data = num_destroy = num_sendme = num_connected = 0;
- create_time = data_time = destroy_time = sendme_time = connected_time = 0;
+ num_create = num_data = num_destroy = num_sendme = 0;
+ create_time = data_time = destroy_time = sendme_time = 0;
/* remember which second it is, for next time */
current_second = now.tv_sec;
@@ -85,10 +84,6 @@ void command_process_cell(cell_t *cell, connection_t *conn) {
command_time_process_cell(cell, conn, &num_sendme, &sendme_time,
command_process_sendme_cell);
break;
- case CELL_CONNECTED:
- command_time_process_cell(cell, conn, &num_connected, &connected_time,
- command_process_connected_cell);
- break;
default:
log(LOG_DEBUG,"Cell of unknown type (%d) received. Dropping.", cell->command);
break;
@@ -115,7 +110,7 @@ void command_process_create_cell(cell_t *cell, connection_t *conn) {
circuit_close(circ);
return;
}
- circ->onion = (unsigned char *)malloc(circ->onionlen);
+ circ->onion = malloc(circ->onionlen);
if(!circ->onion) {
log(LOG_DEBUG,"command_process_create_cell(): Out of memory. Closing.");
circuit_close(circ);
@@ -158,16 +153,6 @@ void command_process_create_cell(cell_t *cell, connection_t *conn) {
return;
}
-#if 0
- conn->onions_handled_this_second++;
- log(LOG_DEBUG,"command_process_create_cell(): Processing onion %d for this second.",conn->onions_handled_this_second);
- if(conn->onions_handled_this_second > options.OnionsPerSecond) {
- log(LOG_INFO,"command_process_create_cell(): Received too many onions (now %d) this second. Closing.", conn->onions_handled_this_second);
- circuit_close(circ);
- return;
- }
-#endif
-
void command_process_sendme_cell(cell_t *cell, connection_t *conn) {
circuit_t *circ;
@@ -189,17 +174,16 @@ void command_process_sendme_cell(cell_t *cell, connection_t *conn) {
/* at this point both circ->n_conn and circ->p_conn are guaranteed to be set */
- if(cell->length != RECEIVE_WINDOW_INCREMENT) {
+ if(cell->length != CIRCWINDOW_INCREMENT) {
log(LOG_WARNING,"command_process_sendme_cell(): non-standard sendme value %d.",cell->length);
}
-// assert(cell->length == RECEIVE_WINDOW_INCREMENT);
if(cell->aci == circ->p_aci) { /* it's an outgoing cell */
- circ->n_receive_window += cell->length;
- log(LOG_DEBUG,"connection_process_sendme_cell(): n_receive_window for aci %d is %d.",circ->n_aci,circ->n_receive_window);
- if(circ->n_conn->type == CONN_TYPE_EXIT) {
- connection_start_reading(circ->n_conn);
- connection_package_raw_inbuf(circ->n_conn); /* handle whatever might still be on the inbuf */
+ circ->n_receive_circwindow += cell->length;
+ assert(circ->n_receive_circwindow <= CIRCWINDOW_START);
+ log(LOG_DEBUG,"connection_process_sendme_cell(): n_receive_circwindow for aci %d is %d.",circ->n_aci,circ->n_receive_circwindow);
+ if(!circ->n_conn || circ->n_conn->type == CONN_TYPE_EXIT) {
+ circuit_resume_edge_reading(circ, EDGE_EXIT);
} else {
cell->aci = circ->n_aci; /* switch it */
if(connection_write_cell_to_buf(cell, circ->n_conn) < 0) { /* (clobbers cell) */
@@ -208,11 +192,11 @@ void command_process_sendme_cell(cell_t *cell, connection_t *conn) {
}
}
} else { /* it's an ingoing cell */
- circ->p_receive_window += cell->length;
- log(LOG_DEBUG,"connection_process_sendme_cell(): p_receive_window for aci %d is %d.",circ->p_aci,circ->p_receive_window);
- if(circ->p_conn->type == CONN_TYPE_AP) {
- connection_start_reading(circ->p_conn);
- connection_package_raw_inbuf(circ->p_conn); /* handle whatever might still be on the inbuf */
+ circ->p_receive_circwindow += cell->length;
+ log(LOG_DEBUG,"connection_process_sendme_cell(): p_receive_circwindow for aci %d is %d.",circ->p_aci,circ->p_receive_circwindow);
+ assert(circ->p_receive_circwindow <= CIRCWINDOW_START);
+ if(!circ->p_conn || circ->p_conn->type == CONN_TYPE_AP) {
+ circuit_resume_edge_reading(circ, EDGE_AP);
} else {
cell->aci = circ->p_aci; /* switch it */
if(connection_write_cell_to_buf(cell, circ->p_conn) < 0) { /* (clobbers cell) */
@@ -246,47 +230,41 @@ void command_process_data_cell(cell_t *cell, connection_t *conn) {
onion_pending_data_add(circ, cell);
return;
}
- /* at this point both circ->n_conn and circ->p_conn are guaranteed to be set */
+
+ /* circ->p_conn and n_conn are only null if we're at an edge point with no connections yet */
if(cell->aci == circ->p_aci) { /* it's an outgoing cell */
cell->aci = circ->n_aci; /* switch it */
- if(--circ->p_receive_window < 0) { /* is it less than 0 after decrement? */
- log(LOG_DEBUG,"connection_process_data_cell(): Too many data cells on aci %d. Closing.", circ->p_aci);
+ if(--circ->p_receive_circwindow < 0) { /* is it less than 0 after decrement? */
+ log(LOG_INFO,"connection_process_data_cell(): Too many data cells for circuit (aci %d). Closing.", circ->p_aci);
circuit_close(circ);
return;
}
- log(LOG_DEBUG,"connection_process_data_cell(): p_receive_window for aci %d is %d.",circ->p_aci,circ->p_receive_window);
- if(circuit_deliver_data_cell(cell, circ, circ->n_conn, 'd') < 0) {
- log(LOG_DEBUG,"command_process_data_cell(): circuit_deliver_data_cell (forward) failed. Closing.");
+ log(LOG_DEBUG,"connection_process_data_cell(): p_receive_circwindow for aci %d is %d.",circ->p_aci,circ->p_receive_circwindow);
+ if(circuit_deliver_data_cell(cell, circ, CELL_DIRECTION_OUT) < 0) {
+ log(LOG_INFO,"command_process_data_cell(): circuit_deliver_data_cell (forward) failed. Closing.");
circuit_close(circ);
return;
}
} else { /* it's an ingoing cell */
cell->aci = circ->p_aci; /* switch it */
- if(--circ->n_receive_window < 0) { /* is it less than 0 after decrement? */
- log(LOG_DEBUG,"connection_process_data_cell(): Too many data cells on aci %d. Closing.", circ->n_aci);
+ if(--circ->n_receive_circwindow < 0) { /* is it less than 0 after decrement? */
+ log(LOG_DEBUG,"connection_process_data_cell(): Too many data cells for circuit (aci %d). Closing.", circ->n_aci);
circuit_close(circ);
return;
}
- log(LOG_DEBUG,"connection_process_data_cell(): n_receive_window for aci %d is %d.",circ->n_aci,circ->n_receive_window);
- if(circ->p_conn->type == CONN_TYPE_AP) { /* we want to decrypt, not encrypt */
- if(circuit_deliver_data_cell(cell, circ, circ->p_conn, 'd') < 0) {
- log(LOG_DEBUG,"command_process_data_cell(): circuit_deliver_data_cell (backward to AP) failed. Closing.");
- circuit_close(circ);
- return;
- }
- } else {
- if(circuit_deliver_data_cell(cell, circ, circ->p_conn, 'e') < 0) {
- log(LOG_DEBUG,"command_process_data_cell(): circuit_deliver_data_cell (backward) failed. Closing.");
- circuit_close(circ);
- return;
- }
+ log(LOG_DEBUG,"connection_process_data_cell(): n_receive_circwindow for aci %d is %d.",circ->n_aci,circ->n_receive_circwindow);
+ if(circuit_deliver_data_cell(cell, circ, CELL_DIRECTION_IN) < 0) {
+ log(LOG_DEBUG,"command_process_data_cell(): circuit_deliver_data_cell (backward to AP) failed. Closing.");
+ circuit_close(circ);
+ return;
}
}
}
void command_process_destroy_cell(cell_t *cell, connection_t *conn) {
circuit_t *circ;
+ connection_t *tmpconn;
circ = circuit_get_by_aci_conn(cell->aci, conn);
@@ -299,34 +277,19 @@ void command_process_destroy_cell(cell_t *cell, connection_t *conn) {
if(circ->state == CIRCUIT_STATE_ONION_PENDING) {
onion_pending_remove(circ);
}
+
circuit_remove(circ);
+
if(cell->aci == circ->p_aci) { /* the destroy came from behind */
- if(circ->n_conn) /* might not be defined, eg if it was just on the pending queue */
- connection_send_destroy(circ->n_aci, circ->n_conn);
+ for(tmpconn = circ->n_conn; tmpconn; tmpconn=tmpconn->next_topic) {
+ connection_send_destroy(circ->n_aci, tmpconn);
+ }
}
if(cell->aci == circ->n_aci) { /* the destroy came from ahead */
- assert(circ->p_conn);
- connection_send_destroy(circ->p_aci, circ->p_conn);
+ for(tmpconn = circ->p_conn; tmpconn; tmpconn=tmpconn->next_topic) {
+ connection_send_destroy(circ->p_aci, tmpconn);
+ }
}
circuit_free(circ);
}
-void command_process_connected_cell(cell_t *cell, connection_t *conn) {
- circuit_t *circ;
-
- circ = circuit_get_by_aci_conn(cell->aci, conn);
-
- if(!circ) {
- log(LOG_DEBUG,"command_process_connected_cell(): unknown circuit %d. Dropping.", cell->aci);
- return;
- }
-
- if(circ->n_conn != conn) {
- log(LOG_WARNING,"command_process_connected_cell(): cell didn't come from n_conn! (aci %d)",cell->aci);
- return;
- }
-
- log(LOG_DEBUG,"command_process_connected_cell(): Received for aci %d.",cell->aci);
- connection_send_connected(circ->p_aci, circ->p_conn);
-}
-
diff --git a/src/or/config.c b/src/or/config.c
index e6472c7aa7..fdd9380e67 100644
--- a/src/or/config.c
+++ b/src/or/config.c
@@ -211,8 +211,8 @@ int getconfig(int argc, char **argv, or_options_t *options) {
options->loglevel = LOG_DEBUG;
options->CoinWeight = 0.8;
options->LinkPadding = 0;
- options->DirRebuildPeriod = 600;
- options->DirFetchPeriod = 6000;
+ options->DirRebuildPeriod = 300;
+ options->DirFetchPeriod = 600;
options->KeepalivePeriod = 300;
options->MaxOnionsPending = 10;
// options->ReconnectPeriod = 6001;
diff --git a/src/or/connection.c b/src/or/connection.c
index 6784580cb6..f7965cdd2f 100644
--- a/src/or/connection.c
+++ b/src/or/connection.c
@@ -19,6 +19,7 @@ char *conn_type_to_string[] = {
"App", /* 7 */
"Dir listener",/* 8 */
"Dir", /* 9 */
+ "DNS master", /* 10 */
};
char *conn_state_to_string[][15] = {
@@ -52,6 +53,7 @@ char *conn_state_to_string[][15] = {
"reading", /* 2 */
"awaiting command", /* 3 */
"writing" }, /* 4 */
+ { "open" }, /* dns master, 0 */
};
/********* END VARIABLES ************/
@@ -354,6 +356,9 @@ int connection_write_to_buf(char *string, int len, connection_t *conn) {
if(!len)
return 0;
+ if(conn->marked_for_close)
+ return 0;
+
conn->timestamp_lastwritten = now.tv_sec;
if( (!connection_speaks_cells(conn)) ||
@@ -507,23 +512,6 @@ int connection_send_destroy(aci_t aci, connection_t *conn) {
return connection_write_cell_to_buf(&cell, conn);
}
-int connection_send_connected(aci_t aci, connection_t *conn) {
- cell_t cell;
-
- assert(conn);
-
- if(!connection_speaks_cells(conn)) {
- log(LOG_INFO,"connection_send_connected(): Aci %d: At entry point. Notifying proxy.", aci);
- connection_ap_send_connected(conn);
- return 0;
- }
-
- cell.aci = aci;
- cell.command = CELL_CONNECTED;
- log(LOG_INFO,"connection_send_connected(): passing back cell (aci %d).",aci);
- return connection_write_cell_to_buf(&cell, conn);
-}
-
int connection_write_cell_to_buf(cell_t *cellp, connection_t *conn) {
char networkcell[CELL_NETWORK_SIZE];
char *n = networkcell;
@@ -588,6 +576,8 @@ int connection_process_inbuf(connection_t *conn) {
return connection_ap_process_inbuf(conn);
case CONN_TYPE_DIR:
return connection_dir_process_inbuf(conn);
+ case CONN_TYPE_DNSMASTER:
+ return connection_dns_process_inbuf(conn);
default:
log(LOG_DEBUG,"connection_process_inbuf() got unexpected conn->type.");
return -1;
@@ -601,70 +591,76 @@ int connection_package_raw_inbuf(connection_t *conn) {
assert(conn);
assert(!connection_speaks_cells(conn));
- /* this function should never get called if the receiver_window is 0 */
+ /* this function should never get called if the receive_topicwindow is 0 */
+
+repeat_connection_package_raw_inbuf:
amount_to_process = conn->inbuf_datalen;
if(!amount_to_process)
return 0;
- if(amount_to_process > CELL_PAYLOAD_SIZE) {
- cell.length = CELL_PAYLOAD_SIZE;
+ if(amount_to_process > CELL_PAYLOAD_SIZE - TOPIC_HEADER_SIZE) {
+ cell.length = CELL_PAYLOAD_SIZE - TOPIC_HEADER_SIZE;
} else {
cell.length = amount_to_process;
}
- if(connection_fetch_from_buf(cell.payload, cell.length, conn) < 0)
+ if(connection_fetch_from_buf(cell.payload+TOPIC_HEADER_SIZE, cell.length, conn) < 0)
return -1;
circ = circuit_get_by_conn(conn);
if(!circ) {
- log(LOG_DEBUG,"connection_raw_package_inbuf(): conn has no circuits!");
+ log(LOG_DEBUG,"connection_package_raw_inbuf(): conn has no circuits!");
return -1;
}
- log(LOG_DEBUG,"connection_raw_package_inbuf(): Packaging %d bytes.",cell.length);
+ log(LOG_DEBUG,"connection_package_raw_inbuf(): Packaging %d bytes (%d waiting).",cell.length, amount_to_process);
+
+ *(uint32_t *)cell.payload = conn->topic_id;
+ *cell.payload = TOPIC_COMMAND_DATA;
+ cell.length += TOPIC_HEADER_SIZE;
+ cell.command = CELL_DATA;
+
if(circ->n_conn == conn) { /* send it backward. we're an exit. */
cell.aci = circ->p_aci;
- cell.command = CELL_DATA;
- if(circuit_deliver_data_cell(&cell, circ, circ->p_conn, 'e') < 0) {
- log(LOG_DEBUG,"connection_raw_package_inbuf(): circuit_deliver_data_cell (backward) failed. Closing.");
+ if(circuit_deliver_data_cell_from_edge(&cell, circ, EDGE_EXIT) < 0) {
+ log(LOG_DEBUG,"connection_package_raw_inbuf(): circuit_deliver_data_cell_from_edge (backward) failed. Closing.");
circuit_close(circ);
return 0;
}
- assert(circ->n_receive_window > 0);
- if(--circ->n_receive_window <= 0) { /* is it 0 after decrement? */
+ assert(conn->n_receive_topicwindow > 0);
+ if(--conn->n_receive_topicwindow <= 0) { /* is it 0 after decrement? */
connection_stop_reading(circ->n_conn);
- log(LOG_DEBUG,"connection_raw_package_inbuf(): receive_window at exit reached 0.");
+ log(LOG_DEBUG,"connection_package_raw_inbuf(): receive_topicwindow at exit reached 0.");
return 0; /* don't process the inbuf any more */
}
- log(LOG_DEBUG,"connection_raw_package_inbuf(): receive_window at exit is %d",circ->n_receive_window);
+ log(LOG_DEBUG,"connection_package_raw_inbuf(): receive_topicwindow at exit is %d",conn->n_receive_topicwindow);
} else { /* send it forward. we're an AP */
cell.aci = circ->n_aci;
- cell.command = CELL_DATA;
- if(circuit_deliver_data_cell(&cell, circ, circ->n_conn, 'e') < 0) {
- /* yes, we use 'e' here, because the AP connection must *encrypt* its input. */
- log(LOG_DEBUG,"connection_raw_package_inbuf(): circuit_deliver_data_cell (forward) failed. Closing.");
+ if(circuit_deliver_data_cell_from_edge(&cell, circ, EDGE_AP) < 0) {
+ log(LOG_DEBUG,"connection_package_raw_inbuf(): circuit_deliver_data_cell_from_edge (forward) failed. Closing.");
circuit_close(circ);
return 0;
}
- assert(circ->p_receive_window > 0);
- if(--circ->p_receive_window <= 0) { /* is it 0 after decrement? */
+ assert(conn->p_receive_topicwindow > 0);
+ if(--conn->p_receive_topicwindow <= 0) { /* is it 0 after decrement? */
connection_stop_reading(circ->p_conn);
- log(LOG_DEBUG,"connection_raw_package_inbuf(): receive_window at AP reached 0.");
+ log(LOG_DEBUG,"connection_package_raw_inbuf(): receive_topicwindow at AP reached 0.");
return 0; /* don't process the inbuf any more */
}
- log(LOG_DEBUG,"connection_raw_package_inbuf(): receive_window at AP is %d",circ->p_receive_window);
+ log(LOG_DEBUG,"connection_package_raw_inbuf(): receive_topicwindow at AP is %d",conn->p_receive_topicwindow);
+ }
+ if(amount_to_process > CELL_PAYLOAD_SIZE - TOPIC_HEADER_SIZE) {
+ log(LOG_DEBUG,"connection_package_raw_inbuf(): recursing.");
+ goto repeat_connection_package_raw_inbuf;
}
- if(amount_to_process > CELL_PAYLOAD_SIZE)
- log(LOG_DEBUG,"connection_raw_package_inbuf(): recursing.");
- return connection_package_raw_inbuf(conn);
return 0;
}
-int connection_consider_sending_sendme(connection_t *conn) {
+int connection_consider_sending_sendme(connection_t *conn, int edge_type) {
circuit_t *circ;
- cell_t sendme;
+ cell_t cell;
if(connection_outbuf_too_full(conn))
return 0;
@@ -675,22 +671,34 @@ int connection_consider_sending_sendme(connection_t *conn) {
log(LOG_DEBUG,"connection_consider_sending_sendme(): No circuit associated with conn. Skipping.");
return 0;
}
- sendme.command = CELL_SENDME;
- sendme.length = RECEIVE_WINDOW_INCREMENT;
- if(circ->n_conn == conn) { /* we're at an exit */
- if(circ->p_receive_window < RECEIVE_WINDOW_START-RECEIVE_WINDOW_INCREMENT) {
- log(LOG_DEBUG,"connection_consider_sending_sendme(): Outbuf %d, Queueing sendme back.", conn->outbuf_flushlen);
- circ->p_receive_window += RECEIVE_WINDOW_INCREMENT;
- sendme.aci = circ->p_aci;
- return connection_write_cell_to_buf(&sendme, circ->p_conn); /* (clobbers sendme) */
+ *(uint32_t *)cell.payload = conn->topic_id;
+ *cell.payload = TOPIC_COMMAND_SENDME;
+ cell.length += TOPIC_HEADER_SIZE;
+ cell.command = CELL_DATA;
+
+ if(edge_type == EDGE_EXIT) { /* we're at an exit */
+ if(conn->p_receive_topicwindow < TOPICWINDOW_START - TOPICWINDOW_INCREMENT) {
+ log(LOG_DEBUG,"connection_consider_sending_sendme(): Outbuf %d, Queueing topic sendme back.", conn->outbuf_flushlen);
+ conn->p_receive_topicwindow += TOPICWINDOW_INCREMENT;
+ cell.aci = circ->p_aci;
+ if(circuit_deliver_data_cell_from_edge(&cell, circ, edge_type) < 0) {
+ log(LOG_DEBUG,"connection_consider_sending_sendme(): circuit_deliver_data_cell_from_edge (backward) failed. Closing.");
+ circuit_close(circ);
+ return 0;
+ }
}
} else { /* we're at an AP */
- if(circ->n_receive_window < RECEIVE_WINDOW_START-RECEIVE_WINDOW_INCREMENT) {
- log(LOG_DEBUG,"connection_consider_sending_sendme(): Outbuf %d, Queueing sendme forward.", conn->outbuf_flushlen);
- circ->n_receive_window += RECEIVE_WINDOW_INCREMENT;
- sendme.aci = circ->n_aci;
- return connection_write_cell_to_buf(&sendme, circ->n_conn); /* (clobbers sendme) */
+ assert(edge_type == EDGE_AP);
+ if(conn->n_receive_topicwindow < TOPICWINDOW_START-TOPICWINDOW_INCREMENT) {
+ log(LOG_DEBUG,"connection_consider_sending_sendme(): Outbuf %d, Queueing topic sendme forward.", conn->outbuf_flushlen);
+ conn->n_receive_topicwindow += TOPICWINDOW_INCREMENT;
+ cell.aci = circ->n_aci;
+ if(circuit_deliver_data_cell_from_edge(&cell, circ, edge_type) < 0) {
+ log(LOG_DEBUG,"connection_consider_sending_sendme(): circuit_deliver_data_cell_from_edge (forward) failed. Closing.");
+ circuit_close(circ);
+ return 0;
+ }
}
}
return 0;
@@ -713,6 +721,8 @@ int connection_finished_flushing(connection_t *conn) {
return connection_exit_finished_flushing(conn);
case CONN_TYPE_DIR:
return connection_dir_finished_flushing(conn);
+ case CONN_TYPE_DNSMASTER:
+ return connection_dns_finished_flushing(conn);
default:
log(LOG_DEBUG,"connection_finished_flushing() got unexpected conn->type.");
return -1;
diff --git a/src/or/connection_ap.c b/src/or/connection_ap.c
index adfceda900..978a9dd029 100644
--- a/src/or/connection_ap.c
+++ b/src/or/connection_ap.c
@@ -22,7 +22,10 @@ int connection_ap_process_inbuf(connection_t *conn) {
case AP_CONN_STATE_SOCKS_WAIT:
return ap_handshake_process_socks(conn);
case AP_CONN_STATE_OPEN:
- return connection_package_raw_inbuf(conn);
+ if(connection_package_raw_inbuf(conn) < 0)
+ return -1;
+ circuit_consider_stop_edge_reading(circuit_get_by_conn(conn), EDGE_AP);
+ return 0;
default:
log(LOG_DEBUG,"connection_ap_process_inbuf() called in state where I'm waiting. Ignoring buf for now.");
}
@@ -33,6 +36,7 @@ int connection_ap_process_inbuf(connection_t *conn) {
int ap_handshake_process_socks(connection_t *conn) {
char c;
socks4_t socks4_info;
+ circuit_t *circ;
assert(conn);
@@ -118,8 +122,25 @@ int ap_handshake_process_socks(connection_t *conn) {
}
}
- /* now we're all ready to make an onion, etc */
- return ap_handshake_create_onion(conn);
+ /* find the circuit that we should use, if there is one. */
+ circ = NULL; /* FIXME don't reuse circs, at least for me. */
+
+ /* now we're all ready to make an onion or send a begin */
+
+ if(circ) {
+ if(circ->state == CIRCUIT_STATE_OPEN) {
+ if(ap_handshake_send_begin(conn, circ) < 0) {
+ circuit_close(circ);
+ return -1;
+ }
+ }
+ } else {
+ if(ap_handshake_create_onion(conn) < 0) {
+ circuit_close(circ);
+ return -1;
+ }
+ }
+ return 0;
}
int ap_handshake_create_onion(connection_t *conn) {
@@ -240,13 +261,18 @@ void ap_handshake_n_conn_open(connection_t *or_conn) {
}
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) {
+ if(ap_handshake_send_onion(p_conn, or_conn, circ) < 0) {
log(LOG_DEBUG,"ap_handshake_n_conn_open(): circuit marked for closing.");
- p_conn->marked_for_close = 1;
- return; /* XXX will want to try the rest too */
- } else {
- circ = circuit_enumerate_by_naddr_nport(circ, or_conn->addr, or_conn->port);
+ 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);
}
}
@@ -289,50 +315,39 @@ int ap_handshake_send_onion(connection_t *ap_conn, connection_t *n_conn, circuit
}
free(tmpbuf);
-#if 0
- /* deliver the ss in a data cell */
- cell.command = CELL_DATA;
- cell.aci = circ->n_aci;
- cell.length = sizeof(ss_t);
- memcpy(cell.payload, &ap_conn->ss, sizeof(ss_t));
- log(LOG_DEBUG,"ap_handshake_send_onion(): Sending a data cell for ss...");
- if(circuit_deliver_data_cell(&cell, circ, circ->n_conn, 'e') < 0) {
- log(LOG_DEBUG,"ap_handshake_send_onion(): failed to deliver ss cell. Closing.");
- circuit_close(circ);
+ if(ap_handshake_send_begin(ap_conn, circ) < 0) {
return -1;
}
-#endif
- /* deliver the dest_addr in a data cell */
- cell.command = CELL_DATA;
- cell.aci = circ->n_aci;
- strncpy(cell.payload, ap_conn->dest_addr, CELL_PAYLOAD_SIZE);
- cell.length = strlen(cell.payload)+1;
- log(LOG_DEBUG,"ap_handshake_send_onion(): Sending a data cell for addr...");
- if(circuit_deliver_data_cell(&cell, circ, circ->n_conn, 'e') < 0) {
- log(LOG_DEBUG,"ap_handshake_send_onion(): failed to deliver addr cell. Closing.");
- circuit_close(circ);
- return -1;
- }
+ circ->state = CIRCUIT_STATE_OPEN;
+ /* FIXME should set circ->expire to something here */
+
+ return 0;
+}
+
+int ap_handshake_send_begin(connection_t *ap_conn, circuit_t *circ) {
+ cell_t cell;
- /* deliver the dest_port in a data cell */
+ memset(&cell, 0, sizeof(cell_t));
+ /* deliver the dest_addr in a data cell */
cell.command = CELL_DATA;
cell.aci = circ->n_aci;
- snprintf(cell.payload, CELL_PAYLOAD_SIZE, "%d", ap_conn->dest_port);
- cell.length = strlen(cell.payload)+1;
- log(LOG_DEBUG,"ap_handshake_send_onion(): Sending a data cell for port...");
- if(circuit_deliver_data_cell(&cell, circ, circ->n_conn, 'e') < 0) {
- log(LOG_DEBUG,"ap_handshake_send_onion(): failed to deliver port cell. Closing.");
- circuit_close(circ);
+ crypto_pseudo_rand(3, cell.payload+1); /* byte 0 is blank, bytes 1-3 are random */
+ /* FIXME check for collisions */
+ cell.payload[0] = 0;
+ ap_conn->topic_id = *(uint32_t *)cell.payload;
+ cell.payload[0] = TOPIC_COMMAND_BEGIN;
+ snprintf(cell.payload+4, CELL_PAYLOAD_SIZE-4, "%s,%d", ap_conn->dest_addr, ap_conn->dest_port);
+ cell.length = strlen(cell.payload+TOPIC_HEADER_SIZE)+1+TOPIC_HEADER_SIZE;
+ log(LOG_DEBUG,"ap_handshake_send_begin(): Sending data cell to begin topic %d.", ap_conn->topic_id);
+ if(circuit_deliver_data_cell_from_edge(&cell, circ, EDGE_AP) < 0) {
+ log(LOG_DEBUG,"ap_handshake_send_begin(): failed to deliver begin cell. Closing.");
return -1;
}
-
- circ->state = CIRCUIT_STATE_OPEN;
+ ap_conn->n_receive_topicwindow = TOPICWINDOW_START;
+ ap_conn->p_receive_topicwindow = TOPICWINDOW_START;
ap_conn->state = AP_CONN_STATE_OPEN;
- log(LOG_INFO,"ap_handshake_send_onion(): Address/port sent, ap socket %d, n_aci %d",ap_conn->s,circ->n_aci);
-
- /* FIXME should set circ->expire to something here */
-
+ log(LOG_INFO,"ap_handshake_send_begin(): Address/port sent, ap socket %d, n_aci %d",ap_conn->s,circ->n_aci);
return 0;
}
@@ -351,30 +366,99 @@ int ap_handshake_socks_reply(connection_t *conn, char result) {
return connection_flush_buf(conn); /* try to flush it, in case we're about to close the conn */
}
-int connection_ap_send_connected(connection_t *conn) {
- assert(conn);
+int connection_ap_process_data_cell(cell_t *cell, circuit_t *circ) {
+ connection_t *conn;
+ int topic_command;
+ int topic_id;
- return ap_handshake_socks_reply(conn, SOCKS4_REQUEST_GRANTED);
-}
+ /* an incoming data cell has arrived */
-int connection_ap_process_data_cell(cell_t *cell, connection_t *conn) {
+ assert(cell && circ);
- /* an incoming data cell has arrived */
+ topic_command = *cell->payload;
+ *cell->payload = 0;
+ topic_id = *(uint32_t *)cell->payload;
+ log(LOG_DEBUG,"connection_ap_process_data_cell(): command %d topic %d", topic_command, topic_id);
- assert(conn && conn->type == CONN_TYPE_AP);
+ circuit_consider_sending_sendme(circ, EDGE_AP);
+
+ for(conn = circ->p_conn; conn && conn->topic_id != topic_id; conn = conn->next_topic) ;
+
+ /* now conn is either NULL, in which case we don't recognize the topic_id, or
+ * it is set, in which case cell is talking about this conn.
+ */
- if(conn->state != AP_CONN_STATE_OPEN) {
+ if(conn && conn->state != AP_CONN_STATE_OPEN) {
/* we should not have gotten this cell */
- log(LOG_DEBUG,"connection_ap_process_data_cell(): Got a data cell when not in 'open' state. Closing.");
- return -1;
+ log(LOG_DEBUG,"connection_ap_process_data_cell(): Got a data cell when not in 'open' state. Dropping.");
+ return 0;
}
-// log(LOG_DEBUG,"connection_ap_process_data_cell(): In state 'open', writing to buf.");
+ switch(topic_command) {
+ case TOPIC_COMMAND_BEGIN:
+ log(LOG_INFO,"connection_ap_process_data_cell(): topic begin request unsupported. Dropping.");
+ break;
+ case TOPIC_COMMAND_DATA:
+ if(!conn) {
+ log(LOG_DEBUG,"connection_ap_process_data_cell(): data cell dropped, unknown topic %d.",topic_id);
+ return 0;
+ }
+ if(--conn->n_receive_topicwindow < 0) { /* is it below 0 after decrement? */
+ log(LOG_DEBUG,"connection_ap_process_data_cell(): receive_topicwindow at exit below 0. Killing.");
+ return -1; /* exit node breaking protocol. kill the whole circuit. */
+ }
+ log(LOG_DEBUG,"connection_ap_process_data_cell(): willing to receive %d more cells from circ",conn->n_receive_topicwindow);
- if(connection_write_to_buf(cell->payload, cell->length, conn) < 0)
- return -1;
- return connection_consider_sending_sendme(conn);
-}
+ if(connection_write_to_buf(cell->payload + TOPIC_HEADER_SIZE,
+ cell->length - TOPIC_HEADER_SIZE, conn) < 0) {
+ conn->marked_for_close = 1;
+ return 0;
+ }
+ if(connection_consider_sending_sendme(conn, EDGE_AP) < 0)
+ conn->marked_for_close = 1;
+ return 0;
+ case TOPIC_COMMAND_END:
+ if(!conn) {
+ log(LOG_DEBUG,"connection_ap_process_data_cell(): end cell dropped, unknown topic %d.",topic_id);
+ return 0;
+ }
+ log(LOG_DEBUG,"connection_ap_process_data_cell(): end cell for topic %d. Removing topic.",topic_id);
+
+ /* go through and identify who points to conn. remove conn from the list. */
+#if 0
+ if(conn == circ->p_conn) {
+ circ->p_conn = conn->next_topic;
+ }
+ for(prevconn = circ->p_conn; prevconn->next_topic != conn; prevconn = prevconn->next_topic) ;
+ prevconn->next_topic = conn->next_topic;
+#endif
+ conn->marked_for_close = 1;
+ break;
+ case TOPIC_COMMAND_CONNECTED:
+ if(!conn) {
+ log(LOG_DEBUG,"connection_ap_process_data_cell(): connected cell dropped, unknown topic %d.",topic_id);
+ break;
+ }
+ log(LOG_DEBUG,"connection_ap_process_data_cell(): Connected! Notifying application.");
+ if(ap_handshake_socks_reply(conn, SOCKS4_REQUEST_GRANTED) < 0) {
+ conn->marked_for_close = 1;
+ }
+ break;
+ case TOPIC_COMMAND_SENDME:
+ if(!conn) {
+ log(LOG_DEBUG,"connection_exit_process_data_cell(): sendme cell dropped, unknown topic %d.",topic_id);
+ return 0;
+ }
+ conn->p_receive_topicwindow += TOPICWINDOW_INCREMENT;
+ connection_start_reading(conn);
+ connection_package_raw_inbuf(conn); /* handle whatever might still be on the inbuf */
+ circuit_consider_stop_edge_reading(circ, EDGE_AP);
+ break;
+ default:
+ log(LOG_DEBUG,"connection_ap_process_data_cell(): unknown topic command %d.",topic_command);
+ }
+ return 0;
+}
int connection_ap_finished_flushing(connection_t *conn) {
@@ -384,14 +468,13 @@ int connection_ap_finished_flushing(connection_t *conn) {
case AP_CONN_STATE_OPEN:
/* FIXME down the road, we'll clear out circuits that are pending to close */
connection_stop_writing(conn);
- return connection_consider_sending_sendme(conn);
+ return connection_consider_sending_sendme(conn, EDGE_AP);
default:
log(LOG_DEBUG,"Bug: connection_ap_finished_flushing() called in unexpected state.");
return 0;
}
return 0;
-
}
int connection_ap_create_listener(struct sockaddr_in *bindaddr) {
diff --git a/src/or/connection_exit.c b/src/or/connection_exit.c
index aa94e6a9ea..871b789ef4 100644
--- a/src/or/connection_exit.c
+++ b/src/or/connection_exit.c
@@ -21,10 +21,12 @@ int connection_exit_process_inbuf(connection_t *conn) {
log(LOG_DEBUG,"connection_exit_process_inbuf(): text from server while in 'connecting' state. Leaving it on buffer.");
return 0;
case EXIT_CONN_STATE_OPEN:
- return connection_package_raw_inbuf(conn);
+ if(connection_package_raw_inbuf(conn) < 0)
+ return -1;
+ circuit_consider_stop_edge_reading(circuit_get_by_conn(conn), EDGE_EXIT);
+ return 0;
}
return 0;
-
}
int connection_exit_finished_flushing(connection_t *conn) {
@@ -46,20 +48,21 @@ int connection_exit_finished_flushing(connection_t *conn) {
}
/* the connect has finished. */
- log(LOG_DEBUG,"connection_exit_finished_flushing() : Connection to %s:%u established.",
+ log(LOG_DEBUG,"connection_exit_finished_flushing(): Connection to %s:%u established.",
conn->address,conn->port);
conn->state = EXIT_CONN_STATE_OPEN;
+ connection_watch_events(conn, POLLIN); /* stop writing, continue reading */
if(connection_wants_to_flush(conn)) /* in case there are any queued data cells */
connection_start_writing(conn);
- connection_start_reading(conn);
return
- connection_exit_send_connected(conn) || /* deliver a 'connected' cell back through the circuit. */
+ connection_exit_send_connected(conn) || /* deliver a 'connected' data cell back through the circuit. */
connection_process_inbuf(conn); /* in case the server has written anything */
case EXIT_CONN_STATE_OPEN:
/* FIXME down the road, we'll clear out circuits that are pending to close */
+ log(LOG_DEBUG,"connection_exit_finished_flushing(): finished flushing.");
connection_stop_writing(conn);
- connection_consider_sending_sendme(conn);
+ connection_consider_sending_sendme(conn, EDGE_EXIT);
return 0;
default:
log(LOG_DEBUG,"Bug: connection_exit_finished_flushing() called in unexpected state.");
@@ -71,6 +74,7 @@ int connection_exit_finished_flushing(connection_t *conn) {
int connection_exit_send_connected(connection_t *conn) {
circuit_t *circ;
+ cell_t cell;
assert(conn);
@@ -81,123 +85,252 @@ int connection_exit_send_connected(connection_t *conn) {
return -1;
}
- return connection_send_connected(circ->p_aci, circ->p_conn);
+ memset(&cell, 0, sizeof(cell_t));
+ cell.aci = circ->p_aci;
+ cell.command = CELL_DATA;
+ *(uint32_t *)cell.payload = conn->topic_id;
+ *cell.payload = TOPIC_COMMAND_CONNECTED;
+ cell.length = TOPIC_HEADER_SIZE;
+ log(LOG_INFO,"connection_exit_send_connected(): passing back cell (aci %d).",circ->p_aci);
+
+ if(circuit_deliver_data_cell_from_edge(&cell, circ, EDGE_EXIT) < 0) {
+ log(LOG_DEBUG,"connection_exit_send_connected(): circuit_deliver_data_cell (backward) failed. Closing.");
+ circuit_close(circ);
+ return 0;
+ }
+ return 0;
}
-int connection_exit_process_data_cell(cell_t *cell, connection_t *conn) {
- struct hostent *rent;
- struct sockaddr_in dest_addr;
- int s; /* for the new socket, if we're on connecting_wait */
+int connection_exit_begin_conn(cell_t *cell, circuit_t *circ) {
+ connection_t *n_conn;
+ char *comma;
+
+ if(!memchr(cell->payload + TOPIC_HEADER_SIZE,0,cell->length - TOPIC_HEADER_SIZE)) {
+ log(LOG_WARNING,"connection_exit_begin_conn(): topic begin cell has no \\0. Dropping.");
+ return 0;
+ }
+ comma = strchr(cell->payload + TOPIC_HEADER_SIZE, ',');
+ if(!comma) {
+ log(LOG_WARNING,"connection_exit_begin_conn(): topic begin cell has no comma. Dropping.");
+ return 0;
+ }
+ *comma = 0;
+
+ if(!atoi(comma+1)) { /* bad port */
+ log(LOG_DEBUG,"connection_exit_begin_conn(): topic begin cell has invalid port. Dropping.");
+ return 0;
+ }
+
+ log(LOG_DEBUG,"connection_exit_begin_conn(): Creating new exit connection.");
+ n_conn = connection_new(CONN_TYPE_EXIT);
+ if(!n_conn) {
+ log(LOG_DEBUG,"connection_exit_begin_conn(): connection_new failed. Closing.");
+ return -1;
+ }
+
+ cell->payload[0] = 0;
+ n_conn->topic_id = *(uint32_t *)(cell->payload);
+
+ n_conn->address = strdup(cell->payload + TOPIC_HEADER_SIZE);
+ n_conn->port = atoi(comma+1);
+ n_conn->state = EXIT_CONN_STATE_RESOLVING;
+ n_conn->receiver_bucket = -1; /* edge connections don't do receiver buckets */
+ n_conn->bandwidth = -1;
+ n_conn->s = -1; /* not yet valid */
+ n_conn->n_receive_topicwindow = TOPICWINDOW_START;
+ n_conn->p_receive_topicwindow = TOPICWINDOW_START;
+ if(connection_add(n_conn) < 0) { /* no space, forget it */
+ log(LOG_DEBUG,"connection_exit_begin_conn(): connection_add failed. Closing.");
+ connection_free(n_conn);
+ return -1;
+ }
+
+ /* add it into the linked list of topics on this circuit */
+ n_conn->next_topic = circ->n_conn;
+ circ->n_conn = n_conn;
+
+ /* send it off to the gethostbyname farm */
+ if(dns_tor_to_master(n_conn->address) < 0) {
+ log(LOG_DEBUG,"connection_exit_begin_conn(): Couldn't queue resolve request.");
+ connection_remove(n_conn);
+ connection_free(n_conn);
+ return 0;
+ }
+
+ return 0;
+}
+
+int connection_exit_process_data_cell(cell_t *cell, circuit_t *circ) {
+ connection_t *conn;
+ int topic_command;
+ int topic_id;
/* an outgoing data cell has arrived */
- assert(conn && conn->type == CONN_TYPE_EXIT);
+ assert(cell && circ);
+
+ topic_command = *cell->payload;
+ *cell->payload = 0;
+ topic_id = *(uint32_t *)cell->payload;
+ log(LOG_DEBUG,"connection_exit_process_data_cell(): command %d topic %d", topic_command, topic_id);
+
+ circuit_consider_sending_sendme(circ, EDGE_EXIT);
+
+ for(conn = circ->n_conn; conn && conn->topic_id != topic_id; conn = conn->next_topic) ;
+
+ /* now conn is either NULL, in which case we don't recognize the topic_id, or
+ * it is set, in which case cell is talking about this conn.
+ */
+
+ if(conn && conn->state != EXIT_CONN_STATE_OPEN) {
+ if(topic_command == TOPIC_COMMAND_END) {
+ log(LOG_ERR,"connection_exit_process_data_cell(): Got an end before we're connected. Marking for close.");
+ conn->marked_for_close = 1;
+ return 0;
+ } else {
+ log(LOG_INFO,"connection_exit_process_data_cell(): Got a non-end data cell when not in 'open' state. Dropping.");
+ return 0;
+ }
+ }
+
+ switch(topic_command) {
+ case TOPIC_COMMAND_BEGIN:
+ if(conn) {
+ log(LOG_INFO,"connection_exit_process_data_cell(): begin cell for known topic. Dropping.");
+ return 0;
+ }
+ return connection_exit_begin_conn(cell, circ);
+ case TOPIC_COMMAND_DATA:
+ if(!conn) {
+ log(LOG_INFO,"connection_exit_process_data_cell(): data cell for unknown topic. Dropping.");
+ return 0;
+ }
+ if(--conn->p_receive_topicwindow < 0) { /* is it below 0 after decrement? */
+ log(LOG_DEBUG,"connection_exit_process_data_cell(): receive_topicwindow at exit below 0. Killing.");
+ return -1; /* AP breaking protocol. kill the whole circuit. */
+ }
+ log(LOG_DEBUG,"connection_exit_process_data_cell(): willing to receive %d more cells from circ",conn->p_receive_topicwindow);
+
+ if(conn->state != EXIT_CONN_STATE_OPEN) {
+ log(LOG_DEBUG,"connection_exit_process_data_cell(): data received while resolving/connecting. Queueing.");
+ }
+ log(LOG_DEBUG,"connection_exit_process_data_cell(): put %d bytes on outbuf.",cell->length - TOPIC_HEADER_SIZE);
+ if(connection_write_to_buf(cell->payload + TOPIC_HEADER_SIZE,
+ cell->length - TOPIC_HEADER_SIZE, conn) < 0) {
+ log(LOG_INFO,"connection_exit_process_data_cell(): write to buf failed. Marking for close.");
+ conn->marked_for_close = 1;
+ return 0;
+ }
+ if(connection_consider_sending_sendme(conn, EDGE_EXIT) < 0)
+ conn->marked_for_close = 1;
+ return 0;
+ case TOPIC_COMMAND_END:
+ if(!conn) {
+ log(LOG_DEBUG,"connection_exit_process_data_cell(): end cell dropped, unknown topic %d.",topic_id);
+ return 0;
+ }
+ log(LOG_DEBUG,"connection_exit_process_data_cell(): end cell for topic %d. Removing topic.",topic_id);
- switch(conn->state) {
- case EXIT_CONN_STATE_CONNECTING_WAIT:
- log(LOG_DEBUG,"connection_exit_process_data_cell(): state is connecting_wait. cell length %d.", cell->length);
#if 0
- if(!conn->ss_received) { /* this cell contains the ss */
- if(cell->length != sizeof(ss_t)) {
- log(LOG_DEBUG,"connection_exit_process_data_cell(): Supposed to contain SS but wrong size. Closing.");
- return -1;
- }
- memcpy(&conn->ss, cell->payload, cell->length);
- if(conn->ss.addr_fmt != SS_ADDR_FMT_ASCII_HOST_PORT) { /* unrecognized address format */
- log(LOG_DEBUG,"connection_exit_process_data_cell(): SS has unrecognized address format. Closing.");
- return -1;
- }
- conn->ss_received = 1;
- log(LOG_DEBUG,"connection_exit_process_data_cell(): SS received.");
- } else
+ /* go through and identify who points to conn. remove conn from the list. */
+ if(conn == circ->n_conn) {
+ circ->n_conn = conn->next_topic;
+ }
+ for(prevconn = circ->n_conn; prevconn->next_topic != conn; prevconn = prevconn->next_topic) ;
+ prevconn->next_topic = conn->next_topic;
#endif
- if (!conn->addr) { /* this cell contains the dest addr */
- if(!memchr(cell->payload,0,cell->length)) {
- log(LOG_DEBUG,"connection_exit_process_data_cell(): dest_addr cell has no \\0. Closing.");
- return -1;
- }
- conn->address = strdup(cell->payload);
- rent = gethostbyname(cell->payload);
- if (!rent) {
- log(LOG_ERR,"connection_exit_process_data_cell(): Could not resolve dest addr %s.",cell->payload);
- return -1;
- }
- memcpy(&conn->addr, rent->h_addr,rent->h_length);
- conn->addr = ntohl(conn->addr); /* get it back to host order */
- log(LOG_DEBUG,"connection_exit_process_data_cell(): addr is %s.",cell->payload);
- } else if (!conn->port) { /* this cell contains the dest port */
- if(!memchr(cell->payload,'\0',cell->length)) {
- log(LOG_DEBUG,"connection_exit_process_data_cell(): dest_port cell has no \\0. Closing.");
- return -1;
- }
- conn->port = atoi(cell->payload);
- if(!conn->port) { /* bad port */
- log(LOG_DEBUG,"connection_exit_process_data_cell(): dest_port cell isn't a valid number. Closing.");
- return -1;
- }
- /* all the necessary info is here. Start the connect() */
- s=socket(PF_INET,SOCK_STREAM,IPPROTO_TCP);
- if (s < 0)
- {
- log(LOG_ERR,"connection_exit_process_data_cell(): Error creating network socket.");
- return -1;
- }
- fcntl(s, F_SETFL, O_NONBLOCK); /* set s to non-blocking */
-
- memset((void *)&dest_addr,0,sizeof(dest_addr));
- dest_addr.sin_family = AF_INET;
- dest_addr.sin_port = htons(conn->port);
- dest_addr.sin_addr.s_addr = htonl(conn->addr);
-
- log(LOG_DEBUG,"connection_exit_process_data_cell(): Connecting to %s:%u.",conn->address,conn->port);
-
- if(connect(s,(struct sockaddr *)&dest_addr,sizeof(dest_addr)) < 0){
- if(errno != EINPROGRESS){
- /* yuck. kill it. */
- log(LOG_DEBUG,"connection_exit_process_data_cell(): Connect failed.");
- return -1;
- } else {
- /* it's in progress. set state appropriately and return. */
- conn->s = s;
- connection_set_poll_socket(conn);
- conn->state = EXIT_CONN_STATE_CONNECTING;
-
- log(LOG_DEBUG,"connection_exit_process_data_cell(): connect in progress, socket %d.",s);
- connection_watch_events(conn, POLLOUT | POLLIN);
- return 0;
- }
- }
+ conn->marked_for_close = 1;
+ break;
+ case TOPIC_COMMAND_CONNECTED:
+ log(LOG_INFO,"connection_exit_process_data_cell(): topic connected request unsupported. Dropping.");
+ break;
+ case TOPIC_COMMAND_SENDME:
+ if(!conn) {
+ log(LOG_DEBUG,"connection_exit_process_data_cell(): sendme cell dropped, unknown topic %d.",topic_id);
+ return 0;
+ }
+ conn->n_receive_topicwindow += TOPICWINDOW_INCREMENT;
+ connection_start_reading(conn);
+ connection_package_raw_inbuf(conn); /* handle whatever might still be on the inbuf */
+ circuit_consider_stop_edge_reading(circ, EDGE_EXIT);
+ break;
+ default:
+ log(LOG_DEBUG,"connection_exit_process_data_cell(): unknown topic command %d.",topic_command);
+ }
+ return 0;
+}
- /* it succeeded. we're connected. */
- log(LOG_DEBUG,"connection_exit_process_data_cell(): Connection to %s:%u established.",conn->address,conn->port);
+#if 0
+static uint32_t address_to_addr(char *address) {
+ struct hostent *rent;
+ uint32_t addr;
+ char *caddr;
- conn->s = s;
- connection_set_poll_socket(conn);
- conn->state = EXIT_CONN_STATE_OPEN;
- if(connection_wants_to_flush(conn)) { /* in case there are any queued data cells */
- log(LOG_NOTICE,"connection_exit_process_data_cell(): tell roger: newly connected conn had data waiting!");
-// connection_start_writing(conn);
- }
-// connection_process_inbuf(conn);
- connection_watch_events(conn, POLLIN);
+ rent = gethostbyname(address);
+ if (!rent) {
+ log(LOG_ERR,"address_to_addr(): Could not resolve dest addr %s.",address);
+ return 0;
+ }
+ memcpy(&addr, rent->h_addr,rent->h_length);
+ addr = ntohl(addr); /* get it back to host order */
+ caddr = (char *)&addr;
+ log(LOG_DEBUG,"address_to_addr(): addr is %d %d %d %d",
+ caddr[0], caddr[1], caddr[2], caddr[3]);
+ return addr;
+}
+#endif
- /* also, deliver a 'connected' cell back through the circuit. */
- return connection_exit_send_connected(conn);
- } else {
- log(LOG_DEBUG,"connection_exit_process_data_cell(): in connecting_wait, but I've already received everything. Closing.");
- return -1;
- }
+int connection_exit_connect(connection_t *conn) {
+ int s; /* for the new socket */
+ struct sockaddr_in dest_addr;
+
+ /* all the necessary info is here. Start the connect() */
+ s=socket(PF_INET,SOCK_STREAM,IPPROTO_TCP);
+ if (s < 0) {
+ log(LOG_ERR,"connection_exit_connect(): Error creating network socket.");
+ return -1;
+ }
+ fcntl(s, F_SETFL, O_NONBLOCK); /* set s to non-blocking */
+
+ memset((void *)&dest_addr,0,sizeof(dest_addr));
+ dest_addr.sin_family = AF_INET;
+ dest_addr.sin_port = htons(conn->port);
+ dest_addr.sin_addr.s_addr = htonl(conn->addr);
+
+ log(LOG_DEBUG,"connection_exit_connect(): Connecting to %s:%u.",conn->address,conn->port);
+
+ if(connect(s,(struct sockaddr *)&dest_addr,sizeof(dest_addr)) < 0) {
+ if(errno != EINPROGRESS){
+ /* yuck. kill it. */
+ perror("connect");
+ log(LOG_DEBUG,"connection_exit_connect(): Connect failed.");
+ return -1;
+ } else {
+ /* it's in progress. set state appropriately and return. */
+ conn->s = s;
+ connection_set_poll_socket(conn);
+ conn->state = EXIT_CONN_STATE_CONNECTING;
+
+ log(LOG_DEBUG,"connection_exit_connect(): connect in progress, socket %d.",s);
+ connection_watch_events(conn, POLLOUT | POLLIN);
return 0;
- case EXIT_CONN_STATE_CONNECTING:
- log(LOG_DEBUG,"connection_exit_process_data_cell(): Data receiving while connecting. Queueing.");
- /* we stay listening for writable, so connect() can finish */
- /* fall through to the next state -- write the cell and consider sending back a sendme */
- case EXIT_CONN_STATE_OPEN:
- if(connection_write_to_buf(cell->payload, cell->length, conn) < 0)
- return -1;
- return connection_consider_sending_sendme(conn);
+ }
}
- return 0;
+ /* it succeeded. we're connected. */
+ log(LOG_DEBUG,"connection_exit_connect(): Connection to %s:%u established.",conn->address,conn->port);
+
+ conn->s = s;
+ connection_set_poll_socket(conn);
+ conn->state = EXIT_CONN_STATE_OPEN;
+ if(connection_wants_to_flush(conn)) { /* in case there are any queued data cells */
+ log(LOG_ERR,"connection_exit_connect(): tell roger: newly connected conn had data waiting!");
+// connection_start_writing(conn);
+ }
+// connection_process_inbuf(conn);
+ connection_watch_events(conn, POLLIN);
+
+ /* also, deliver a 'connected' cell back through the circuit. */
+ return connection_exit_send_connected(conn);
}
diff --git a/src/or/dns.c b/src/or/dns.c
new file mode 100644
index 0000000000..d730159578
--- /dev/null
+++ b/src/or/dns.c
@@ -0,0 +1,434 @@
+/* Copyright 2003 Roger Dingledine. */
+/* See LICENSE for licensing information */
+/* $Id$ */
+
+#include "or.h"
+
+#define MAX_DNSSLAVES 50
+#define MIN_DNSSLAVES 3 /* 1 for the tor process, 3 slaves */
+
+struct slave_data_t {
+ int fd; /* socket to talk on */
+ int num_processed; /* number of times we've used this slave */
+ char busy; /* whether this slave currently has a task */
+ char question[256]; /* the hostname that we're resolving */
+ unsigned char question_len; /* how many bytes in question */
+ char answer[256]; /* the answer to the question */
+ unsigned char answer_len; /* how many bytes in answer */
+};
+
+struct slave_data_t slave_data[MAX_DNSSLAVES+1];
+struct pollfd poll_data[MAX_DNSSLAVES+1];
+
+static int dns_spawn_slave(void);
+static int dns_read_block(int fd, char *string, unsigned char *len);
+static int dns_write_block(int fd, char *string, unsigned char len);
+static int dns_read_tor_question(int index);
+static int dns_read_slave_response(int index);
+static int dns_find_idle_slave(int max);
+static int dns_assign_to_slave(int from, int to);
+static int dns_master_to_tor(int from, int to);
+static void dns_master_main(int fd);
+
+int connection_dns_finished_flushing(connection_t *conn) {
+
+ assert(conn && conn->type == CONN_TYPE_DNSMASTER);
+
+ connection_stop_writing(conn);
+
+ return 0;
+}
+
+int connection_dns_process_inbuf(connection_t *conn) {
+ unsigned char length;
+ char buf[256];
+ char *question;
+ connection_t *exitconn;
+
+ assert(conn && conn->type == CONN_TYPE_DNSMASTER);
+ assert(conn->state == DNSMASTER_STATE_OPEN);
+
+ if(conn->inbuf_reached_eof) {
+ log(LOG_ERR,"connection_dns_process_inbuf(): Read eof. No more dnsmaster!");
+ return -1;
+ }
+
+ assert(conn->inbuf);
+
+ /* peek into the inbuf, so we can check if it's all here */
+ length = *conn->inbuf; /* warning: abstraction violation :( */
+ assert(length < 240);
+
+ if(conn->inbuf_datalen < 1+length) { /* entire answer available? */
+ log(LOG_INFO,"connection_dns_process_inbuf(): %d available, waiting for %d.", conn->inbuf_datalen, length+1);
+ return 0; /* not yet */
+ }
+
+ if(connection_fetch_from_buf(buf,1+length,conn) < 0) {
+ log(LOG_ERR,"connection_dns_process_inbuf(): Broken inbuf. No more dnsmaster!");
+ return -1;
+ }
+
+ question = buf+1;
+ log(LOG_DEBUG,"connection_dns_process_inbuf(): length %d, question '%s', strlen question %d", length, question, strlen(question));
+ assert(length == 4 + strlen(question) + 1);
+
+ /* find the conn that question refers to. */
+ exitconn = connection_get_pendingresolve_by_address(question);
+
+ if(!exitconn) {
+ log(LOG_DEBUG,"connection_dns_process_inbuf(): No conn -- question no longer relevant? Dropping.");
+ return connection_process_inbuf(conn); /* process the remainder of the buffer */
+ }
+ memcpy((char *)&exitconn->addr, buf+1+length-4,4);
+ exitconn->addr = ntohl(exitconn->addr); /* get it back to host order */
+
+ if(connection_exit_connect(exitconn) < 0) {
+ exitconn->marked_for_close = 1;
+ }
+
+ return connection_process_inbuf(conn); /* process the remainder of the buffer */
+}
+
+
+/* return -1 if error, else the fd that can talk to the dns master */
+int dns_master_start(void) {
+ connection_t *conn;
+ pid_t pid;
+ int fd[2];
+
+ if(socketpair(AF_UNIX, SOCK_STREAM, 0, fd) < 0) {
+ log(LOG_ERR,"dns_master_start(): socketpair failed.");
+ return -1;
+ }
+
+ pid = fork();
+ if(pid < 0) {
+ log(LOG_ERR,"dns_master_start(): fork failed.");
+ return -1;
+ }
+ if(pid == 0) { /* i'm the child */
+ log(LOG_DEBUG,"dns_master_start(): child says fd0 %d, fd1 %d.", fd[0], fd[1]);
+ close(fd[0]);
+ dns_master_main(fd[1]);
+ assert(0); /* never gets here */
+ }
+
+ /* i'm the parent */
+
+ close(fd[1]);
+
+ fcntl(fd[0], F_SETFL, O_NONBLOCK); /* set s to non-blocking */
+
+ conn = connection_new(CONN_TYPE_DNSMASTER);
+ if(!conn) {
+ log(LOG_INFO,"dns_master_start(): connection_new failed. Giving up.");
+ /* XXX tell the dnsmaster to die */
+ return -1;
+ }
+
+ conn->s = fd[0];
+ conn->address = strdup("localhost");
+ conn->receiver_bucket = -1; /* edge connections don't do receiver buckets */
+ conn->bandwidth = -1;
+
+ if(connection_add(conn) < 0) { /* no space, forget it */
+ log(LOG_INFO,"dns_master_start(): connection_add failed. Giving up.");
+ connection_free(conn);
+ /* XXX tell the dnsmaster to die */
+ return -1;
+ }
+
+ conn->state = DNSMASTER_STATE_OPEN;
+ connection_start_reading(conn);
+ log(LOG_INFO,"dns_master_start(): dns handler is spawned.");
+ return fd[0];
+}
+
+static void dns_slave_main(int fd) {
+ char question[256];
+ unsigned char question_len;
+ struct hostent *rent;
+
+ for(;;) {
+ if(dns_read_block(fd, question, &question_len) < 0) { /* the master wants us to die */
+ log(LOG_INFO,"dns_slave_main(): eof on read from master. Exiting.");
+ exit(0);
+ }
+
+ rent = gethostbyname(question);
+ if (!rent) {
+ log(LOG_INFO,"dns_slave_main(): Could not resolve dest addr %s. Returning nulls.",question);
+ if(dns_write_block(fd, "\0\0\0\0", 4) < 0) {
+ log(LOG_INFO,"dns_slave_main(): writing to master failed. Exiting.");
+ exit(0);
+ }
+ } else {
+ if(dns_write_block(fd, rent->h_addr, rent->h_length) < 0) {
+ log(LOG_INFO,"dns_slave_main(): writing to master failed. Exiting.");
+ exit(0);
+ }
+ log(LOG_INFO,"dns_slave_main(): Answered question '%s'.",question);
+ }
+ }
+}
+
+static int dns_spawn_slave(void) {
+ pid_t pid;
+ int fd[2];
+
+ if(socketpair(AF_UNIX, SOCK_STREAM, 0, fd) < 0) {
+ perror("socketpair");
+ exit(1);
+ }
+
+ pid = fork();
+ if(pid < 0) {
+ perror("fork");
+ exit(1);
+ }
+ if(pid == 0) { /* i'm the child */
+ close(fd[0]);
+ dns_slave_main(fd[1]);
+ assert(0); /* never gets here */
+ }
+
+ /* i'm the parent */
+ log(LOG_INFO,"dns_spawn_slave(): just spawned a slave."); // XXX change to debug
+ close(fd[1]);
+ return fd[0];
+}
+
+/* read a first byte from fd, put it into *len. Then read *len
+ * bytes from fd and put it into string.
+ * Return -1 if eof or read error or bad len, else return 0.
+ */
+int dns_read_block(int fd, char *string, unsigned char *len) {
+ int read_result;
+
+ log(LOG_DEBUG,"dns_read_block(): Calling read to learn length (fd %d).", fd);
+ read_result = read(fd, len, 1);
+ log(LOG_DEBUG,"dns_read_block(): read finished, returned %d", read_result);
+ if (read_result < 0) {
+ log(LOG_INFO,"dns_read_block(): read len returned error");
+ return -1;
+ } else if (read_result == 0) {
+ log(LOG_INFO,"dns_read_block(): Encountered eof reading len");
+ return -1;
+ } else if (*len <= 0) {
+ log(LOG_INFO,"dns_read_block(): len not >0");
+ return -1;
+ }
+
+ log(LOG_DEBUG,"dns_read_block(): Calling read to get string, length %u.", *len);
+ read_result = read(fd, string, *len);
+ if (read_result < 0) {
+ log(LOG_INFO,"dns_read_block(): read string returned error");
+ return -1;
+ } else if (read_result == 0) {
+ log(LOG_INFO,"dns_read_block(): Encountered eof reading string");
+ return -1;
+ }
+
+ string[*len] = 0; /* null terminate it, just in case */
+ log(LOG_INFO,"dns_read_block(): Read '%s', len %u.",string,*len); // XXX make silent
+ return 0;
+}
+
+/* write ("%c%s", string, len) onto fd */
+static int dns_write_block(int fd, char *string, unsigned char len) {
+ int write_result;
+ int written=0;
+ char tmp[257];
+
+ assert(len <= 250);
+ tmp[0] = len;
+ memcpy(tmp+1, string, len);
+ log(LOG_DEBUG,"dns_write_block(): writing length %u, fd %d.", len, fd);
+
+ while(written < len+1) {
+ write_result = write(fd, tmp, len+1-written);
+ if (write_result < 0) {
+ return -1;
+ }
+ written += write_result;
+ }
+
+ return 0;
+}
+
+/* pull in question. block until we've read everything.
+ * return -1 if eof. */
+static int dns_read_tor_question(int index) {
+
+ log(LOG_DEBUG,"dns_read_tor_question(): Pulling question from tor");
+ if(dns_read_block(slave_data[index].fd,
+ slave_data[index].question,
+ &slave_data[index].question_len) < 0)
+ return -1;
+
+ log(LOG_INFO,"dns_read_tor_question(): Read question '%s'",slave_data[index].question);
+ return 0;
+}
+
+/* pull in answer. block until we've read it. return -1 if eof. */
+static int dns_read_slave_response(int index) {
+
+ if(dns_read_block(slave_data[index].fd,
+ slave_data[index].answer,
+ &slave_data[index].answer_len) < 0)
+ return -1;
+
+ return 0;
+}
+
+static int dns_find_idle_slave(int max) {
+ int i;
+
+ for(i=1;i<max;i++)
+ if(slave_data[i].busy == 0) {
+ log(LOG_DEBUG,"dns_find_idle_slave(): slave %d is chosen.",i);
+ return i;
+ }
+
+ assert(0); /* should never get here */
+}
+
+static int dns_assign_to_slave(int from, int to) {
+
+ slave_data[to].question_len = slave_data[from].question_len;
+ memcpy(slave_data[to].question, slave_data[from].question, slave_data[from].question_len);
+
+// slave_data[from].question_len = 0;
+
+ log(LOG_DEBUG,"dns_assign_to_slave(): from index %d to %d (writing fd %d)",from,to,slave_data[to].fd);
+ if(dns_write_block(slave_data[to].fd,
+ slave_data[to].question,
+ slave_data[to].question_len) < 0) {
+ log(LOG_INFO,"dns_assign_to_slave(): writing to slave failed.");
+ return -1;
+ }
+
+ return 0;
+}
+
+static int dns_master_to_tor(int from, int to) {
+ char tmp[256];
+ unsigned char len;
+
+ len = slave_data[from].question_len+1+slave_data[from].answer_len;
+ memcpy(tmp, slave_data[from].question, slave_data[from].question_len);
+ tmp[slave_data[from].question_len] = 0; /* null terminate it */
+ memcpy(tmp+1+slave_data[from].question_len, slave_data[from].answer, slave_data[from].answer_len);
+
+ log(LOG_DEBUG,"dns_master_to_tor(): question is '%s', length %d",slave_data[from].question,slave_data[from].question_len);
+ log(LOG_DEBUG,"dns_master_to_tor(): answer is %d %d %d %d",
+ slave_data[from].answer[0],
+ slave_data[from].answer[1],
+ slave_data[from].answer[2],
+ slave_data[from].answer[3]);
+ assert(slave_data[from].answer_len == 4);
+ if(dns_write_block(slave_data[to].fd, tmp, len) < 0) {
+ log(LOG_INFO,"dns_master_to_tor(): writing to tor failed.");
+ return -1;
+ }
+
+ return 0;
+}
+
+int dns_tor_to_master(char *address) {
+ connection_t *conn;
+ unsigned char len;
+
+ conn = connection_get_by_type(CONN_TYPE_DNSMASTER);
+ if(!conn) {
+ log(LOG_ERR,"dns_tor_to_master(): dns master nowhere to be found!");
+ /* XXX should do gethostbyname right here */
+ return -1;
+ }
+
+ len = strlen(address);
+ if(connection_write_to_buf(&len, 1, conn) < 0) {
+ log(LOG_DEBUG,"dns_tor_to_master(): Couldn't write length.");
+ return -1;
+ }
+
+ if(connection_write_to_buf(address, len, conn) < 0) {
+ log(LOG_DEBUG,"dns_tor_to_master(): Couldn't write address.");
+ return -1;
+ }
+
+ log(LOG_DEBUG,"dns_tor_to_master(): submitted '%s'", address);
+ return 0;
+}
+
+static void dns_master_main(int fd) {
+ int nfds=1; /* the 0th index is the tor process, the rest are slaves */
+ int num_slaves_busy=0;
+ int num_slaves_needed = MIN_DNSSLAVES;
+ int poll_result, idle, i;
+
+ poll_data[0].fd = slave_data[0].fd = fd;
+ poll_data[0].events = POLLIN;
+
+ for(;;) { /* loop forever */
+
+ assert(num_slaves_needed < MAX_DNSSLAVES);
+ while(nfds-1 < num_slaves_needed) {
+ /* add another slave. */
+
+ i = nfds;
+ memset(&slave_data[i], 0, sizeof(struct slave_data_t));
+ memset(&poll_data[i], 0, sizeof(struct pollfd));
+ slave_data[i].fd = poll_data[i].fd = dns_spawn_slave();
+ poll_data[i].events = POLLIN; /* listen always, to prevent accidental deadlock */
+ nfds++;
+ }
+
+ /* XXX later, decide on a timeout value, to catch wedged slaves */
+
+ poll_result = poll(poll_data, nfds, -1);
+ log(LOG_DEBUG,"dns_master_main(): Poll returned -- activity!");
+ for(i=0;i<nfds;i++) {
+ if(poll_data[i].revents & POLLIN) {
+ if(i==0) { /* note that we read only one question per poll loop */
+ if(dns_read_tor_question(i) >= 0) {
+ while(1) {
+ idle = dns_find_idle_slave(nfds);
+ if(dns_assign_to_slave(i, idle) >= 0)
+ break; /* successfully assigned to one */
+ /* XXX slave must die, recalc num slaves and num busy */
+ }
+ num_slaves_busy++;
+ } else { /* error */
+ log(LOG_INFO,"dns_master_main(): dns_read_tor_question failed. Master dying.");
+ exit(1);
+ }
+ } else {
+ if(dns_read_slave_response(i) >= 0) {
+ if(dns_master_to_tor(i, 0) < 0) {
+ log(LOG_INFO,"dns_master_main(): dns_master_to_tor failed. Master dying.");
+ exit(1);
+ }
+ slave_data[i].busy = 0;
+ num_slaves_busy--;
+ poll_data[0].events = POLLIN; /* resume reading from tor if we'd stopped */
+ } else { /* error */
+ log(LOG_INFO,"dns_master_main(): dns_read_slave_response failed. Leaving slave stranded (FIXME)");
+ }
+ }
+ }
+ }
+ log(LOG_DEBUG,"dns_master_main(): Finished looping over fd's.");
+
+ if(num_slaves_busy >= num_slaves_needed) {
+ if(num_slaves_needed == MAX_DNSSLAVES-1)
+ poll_data[0].events = 0; /* stop reading from tor */
+ else
+ num_slaves_needed++;
+ }
+
+ }
+ assert(0); /* should never get here */
+}
+
diff --git a/src/or/main.c b/src/or/main.c
index 42976a123f..7ee1cfda68 100644
--- a/src/or/main.c
+++ b/src/or/main.c
@@ -76,7 +76,10 @@ int connection_remove(connection_t *conn) {
assert(nfds>0);
log(LOG_INFO,"connection_remove(): removing socket %d, nfds now %d",conn->s, nfds-1);
- circuit_about_to_close_connection(conn); /* flush and send destroys for all circuits on this conn */
+ circuit_about_to_close_connection(conn); /* if it's an edge conn, remove it from the list
+ * of conn's on this circuit. If it's not on an edge,
+ * flush and send destroys for all circuits on this conn
+ */
current_index = conn->poll_index;
if(current_index == nfds-1) { /* this is the end */
@@ -126,7 +129,6 @@ connection_t *connection_twin_get_by_addr_port(uint32_t addr, uint16_t port) {
return conn;
}
}
-
/* guess not */
return NULL;
@@ -142,7 +144,6 @@ connection_t *connection_exact_get_by_addr_port(uint32_t addr, uint16_t port) {
if(conn->addr == addr && conn->port == port)
return conn;
}
-
return NULL;
}
@@ -155,7 +156,21 @@ connection_t *connection_get_by_type(int type) {
if(conn->type == type)
return conn;
}
+ return NULL;
+}
+
+connection_t *connection_get_pendingresolve_by_address(char *address) {
+ int i;
+ connection_t *conn;
+ for(i=0;i<nfds;i++) {
+ conn = connection_array[i];
+ if(conn->type == CONN_TYPE_EXIT &&
+ conn->state == EXIT_CONN_STATE_RESOLVING &&
+ !strcmp(conn->address, address)) {
+ return conn;
+ }
+ }
return NULL;
}
@@ -223,7 +238,7 @@ void check_conn_read(int i) {
retval = connection_read_to_buf(conn);
if (retval < 0 && conn->type == CONN_TYPE_DIR && conn->state == DIR_CONN_STATE_CONNECTING) {
/* it's a directory server and connecting failed: forget about this router */
- router_forget_router(conn->addr,conn->port);
+ router_forget_router(conn->addr,conn->port); /* FIXME i don't think this function works. */
}
if (retval >= 0) { /* all still well */
retval = connection_process_inbuf(conn);
@@ -319,8 +334,8 @@ int prepare_for_poll(int *timeout) {
/* it's time to rebuild our directory */
if(time_to_rebuild_directory == 0) {
/* we just started up. if we build a directory now it will be meaningless. */
- log(LOG_DEBUG,"prepare_for_poll(): Delaying initial dir build for 15 seconds.");
- time_to_rebuild_directory = now.tv_sec + 15; /* try in 15 seconds */
+ log(LOG_DEBUG,"prepare_for_poll(): Delaying initial dir build for 10 seconds.");
+ time_to_rebuild_directory = now.tv_sec + 10; /* try in 10 seconds */
} else {
directory_rebuild();
time_to_rebuild_directory = now.tv_sec + options.DirRebuildPeriod;
@@ -641,19 +656,25 @@ void dump_directory_to_string(char *s, int maxlen) {
int main(int argc, char *argv[]) {
int retval = 0;
- signal (SIGINT, catch); /* catch kills so we can exit cleanly */
-// signal (SIGABRT, catch);
- signal (SIGTERM, catch);
- signal (SIGUSR1, catch); /* to dump stats to stdout */
- signal (SIGHUP, catch); /* to reload directory */
-
if(getconfig(argc,argv,&options))
exit(1);
log(options.loglevel,NULL); /* assign logging severity level from options */
global_role = options.Role; /* assign global_role from options. FIXME: remove from global namespace later. */
- crypto_global_init();
+ if(options.Role & ROLE_OR_LISTEN) { /* only spawn dns handlers if we're a router */
+ if(dns_master_start() < 0) {
+ log(LOG_ERR,"main(): We're running without a dns handler. Bad news.");
+ }
+ }
+
init_tracked_tree(); /* initialize the replay detection tree */
+
+ signal (SIGINT, catch); /* catch kills so we can exit cleanly */
+ signal (SIGTERM, catch);
+ signal (SIGUSR1, catch); /* to dump stats to stdout */
+ signal (SIGHUP, catch); /* to reload directory */
+
+ crypto_global_init();
retval = do_main_loop();
crypto_global_cleanup();
diff --git a/src/or/onion.c b/src/or/onion.c
index 04dda89a92..ff708f5890 100644
--- a/src/or/onion.c
+++ b/src/or/onion.c
@@ -23,17 +23,6 @@ int decide_aci_type(uint32_t local_addr, uint16_t local_port,
return ACI_TYPE_LOWER;
}
-struct data_queue_t {
- cell_t *cell;
- struct data_queue_t *next;
-};
-
-struct onion_queue_t {
- circuit_t *circ;
- struct data_queue_t *data_cells;
- struct onion_queue_t *next;
-};
-
/* global (within this file) variables used by the next few functions */
static struct onion_queue_t *ol_list=NULL;
static struct onion_queue_t *ol_tail=NULL;
@@ -150,12 +139,7 @@ void onion_pending_remove(circuit_t *circ) {
}
-/* a data cell has arrived for a circuit which is still pending. Find
- * the right entry in ol_list, and add it to the end of the 'data_cells'
- * list.
- */
-void onion_pending_data_add(circuit_t *circ, cell_t *cell) {
- struct onion_queue_t *tmpo;
+struct data_queue_t *data_queue_add(struct data_queue_t *list, cell_t *cell) {
struct data_queue_t *tmpd, *newd;
newd = malloc(sizeof(struct data_queue_t));
@@ -163,15 +147,25 @@ void onion_pending_data_add(circuit_t *circ, cell_t *cell) {
newd->cell = malloc(sizeof(cell_t));
memcpy(newd->cell, cell, sizeof(cell_t));
+ if(!list) {
+ return newd;
+ }
+ for(tmpd = list; tmpd->next; tmpd=tmpd->next) ;
+ /* now tmpd->next is null */
+ tmpd->next = newd;
+ return list;
+}
+
+/* a data cell has arrived for a circuit which is still pending. Find
+ * the right entry in ol_list, and add it to the end of the 'data_cells'
+ * list.
+ */
+void onion_pending_data_add(circuit_t *circ, cell_t *cell) {
+ struct onion_queue_t *tmpo;
+
for(tmpo=ol_list; tmpo; tmpo=tmpo->next) {
if(tmpo->circ == circ) {
- if(!tmpo->data_cells) {
- tmpo->data_cells = newd;
- return;
- }
- for(tmpd = tmpo->data_cells; tmpd->next; tmpd=tmpd->next) ;
- /* now tmpd->next is null */
- tmpd->next = newd;
+ tmpo->data_cells = data_queue_add(tmpo->data_cells, cell);
return;
}
}
@@ -286,6 +280,8 @@ static int onion_process(circuit_t *circ) {
return -1;
}
} else { /* this is destined for an exit */
+ log(LOG_DEBUG,"command_process_create_cell(): create cell reached exit. Circuit established.");
+#if 0
log(LOG_DEBUG,"command_process_create_cell(): Creating new exit connection.");
n_conn = connection_new(CONN_TYPE_EXIT);
if(!n_conn) {
@@ -302,6 +298,7 @@ static int onion_process(circuit_t *circ) {
return -1;
}
circ->n_conn = n_conn;
+#endif
}
return 0;
}
@@ -522,7 +519,7 @@ unsigned char *create_onion(routerinfo_t **rarray, int rarray_len, unsigned int
/* set crypto functions */
hop->backf = *(layer+1) >> 4;
hop->forwf = *(layer+1) & 0x0f;
-
+
/* calculate keys */
crypto_SHA_digest(layer+12,16,hop->digest3);
log(LOG_DEBUG,"create_onion() : First SHA pass performed.");
@@ -533,14 +530,14 @@ unsigned char *create_onion(routerinfo_t **rarray, int rarray_len, unsigned int
log(LOG_DEBUG,"create_onion() : Keys generated.");
/* set IV to zero */
memset((void *)iv,0,16);
-
+
/* initialize cipher engines */
if (! (hop->f_crypto = create_onion_cipher(hop->forwf, hop->digest3, iv, 1))) {
/* cipher initialization failed */
log(LOG_ERR,"Could not create a crypto environment.");
goto error;
}
-
+
if (! (hop->b_crypto = create_onion_cipher(hop->backf, hop->digest2, iv, 0))) {
/* cipher initialization failed */
log(LOG_ERR,"Could not create a crypto environment.");
@@ -731,7 +728,7 @@ void pad_onion(unsigned char *onion, uint32_t onionlen, int n)
/* red black tree using Niels' tree.h. I used
-http://www.openbsd.org/cgi-bin/cvsweb/src/regress/sys/sys/tree/rb/rb-test.c?rev=1.2&content-type=text/x-cvsweb-markup
+http://www.openbsd.org/cgi-bin/cvsweb/src/regress/sys/sys/tree/rb/
as my guide */
#include "tree.h"
diff --git a/src/or/or.h b/src/or/or.h
index bfad1c9095..746d4c898a 100644
--- a/src/or/or.h
+++ b/src/or/or.h
@@ -43,7 +43,7 @@
#include "../common/version.h"
#define MAXCONNECTIONS 200 /* upper bound on max connections.
- can be overridden by config file */
+ can be lowered by config file */
#define MAX_BUF_SIZE (640*1024)
#define DEFAULT_BANDWIDTH_OP 102400
@@ -71,9 +71,12 @@
#define CONN_TYPE_AP 7
#define CONN_TYPE_DIR_LISTENER 8
#define CONN_TYPE_DIR 9
+#define CONN_TYPE_DNSMASTER 10
#define LISTENER_STATE_READY 0
+#define DNSMASTER_STATE_OPEN 0
+
#define OP_CONN_STATE_AWAITING_KEYS 0
#define OP_CONN_STATE_OPEN 1
#if 0
@@ -96,8 +99,8 @@
#define OR_CONN_STATE_SERVER_NONCE_WAIT 8 /* waiting for confirmation of nonce */
#define OR_CONN_STATE_OPEN 9 /* ready to send/receive cells. */
-#define EXIT_CONN_STATE_CONNECTING_WAIT 0 /* waiting for standard structure or dest info */
-#define EXIT_CONN_STATE_CONNECTING 1
+#define EXIT_CONN_STATE_RESOLVING 0 /* waiting for response from dnsmaster */
+#define EXIT_CONN_STATE_CONNECTING 1 /* waiting for connect() to finish */
#define EXIT_CONN_STATE_OPEN 2
#if 0
#define EXIT_CONN_STATE_CLOSE 3 /* flushing the buffer, then will close */
@@ -123,6 +126,16 @@
// (or if just one was sent, waiting for that one */
//#define CIRCUIT_STATE_CLOSE 4 /* both acks received, connection is dead */ /* NOT USED */
+#define TOPIC_COMMAND_BEGIN 1
+#define TOPIC_COMMAND_DATA 2
+#define TOPIC_COMMAND_END 3
+#define TOPIC_COMMAND_CONNECTED 4
+#define TOPIC_COMMAND_SENDME 5
+
+#define TOPIC_HEADER_SIZE 4
+
+#define TOPIC_STATE_RESOLVING
+
/* available cipher functions */
#define ONION_CIPHER_IDENTITY 0
#define ONION_CIPHER_DES 1
@@ -131,8 +144,16 @@
/* default cipher function */
#define ONION_DEFAULT_CIPHER ONION_CIPHER_DES
-#define RECEIVE_WINDOW_START 1000
-#define RECEIVE_WINDOW_INCREMENT 100
+#define CELL_DIRECTION_IN 1
+#define CELL_DIRECTION_OUT 2
+#define EDGE_EXIT 3 /* make direction and edge values not overlap, to help catch bugs */
+#define EDGE_AP 4
+
+#define CIRCWINDOW_START 1000
+#define CIRCWINDOW_INCREMENT 100
+
+#define TOPICWINDOW_START 500
+#define TOPICWINDOW_INCREMENT 50
/* cell commands */
#define CELL_PADDING 0
@@ -142,7 +163,6 @@
#define CELL_ACK 4
#define CELL_NACK 5
#define CELL_SENDME 6
-#define CELL_CONNECTED 7
#define CELL_PAYLOAD_SIZE 120
#define CELL_NETWORK_SIZE 128
@@ -191,7 +211,7 @@ typedef struct {
/* dest host follows, terminated by a NULL */
} socks4_t;
-typedef struct {
+struct connection_t {
/* Used by all types: */
@@ -223,8 +243,8 @@ typedef struct {
uint32_t bandwidth; /* connection bandwidth */
int receiver_bucket; /* when this hits 0, stop receiving. Every second we
- * add 'bandwidth' to this, capping it at 10*bandwidth.
- */
+ * add 'bandwidth' to this, capping it at 10*bandwidth.
+ */
struct timeval send_timeval; /* for determining when to send the next cell */
/* link encryption */
@@ -239,8 +259,10 @@ typedef struct {
/* used by exit and ap: */
-// ss_t ss; /* standard structure */
-// int ss_received; /* size of ss, received so far */
+ uint32_t topic_id;
+ struct connection_t *next_topic;
+ int n_receive_topicwindow;
+ int p_receive_topicwindow;
char socks_version;
char read_username;
@@ -251,18 +273,14 @@ typedef struct {
char dest_tmp[512];
int dest_tmplen;
-#if 0 /* obsolete, we now use conn->bandwidth */
- /* link info */
- uint32_t min;
- uint32_t max;
-#endif
-
char *address; /* strdup into this, because free_connection frees it */
crypto_pk_env_t *pkey; /* public RSA key for the other side */
char nonce[8];
-} connection_t;
+};
+
+typedef struct connection_t connection_t;
/* config stuff we know about the other ORs in the network */
typedef struct {
@@ -302,22 +320,25 @@ typedef struct {
} crypt_path_t;
+struct data_queue_t {
+ cell_t *cell;
+ struct data_queue_t *next;
+};
+
/* per-anonymous-connection struct */
typedef struct {
-#if 0
- uint32_t p_addr; /* all in network order */
- uint16_t p_port;
-#endif
uint32_t n_addr;
uint16_t n_port;
connection_t *p_conn;
connection_t *n_conn;
- int n_receive_window;
- int p_receive_window;
+ int n_receive_circwindow;
+ int p_receive_circwindow;
aci_t p_aci; /* connection identifiers */
aci_t n_aci;
+ struct data_queue_t *data_queue; /* for queueing cells at the edges */
+
unsigned char p_f; /* crypto functions */
unsigned char n_f;
@@ -338,6 +359,12 @@ typedef struct {
void *next;
} circuit_t;
+struct onion_queue_t {
+ circuit_t *circ;
+ struct data_queue_t *data_cells;
+ struct onion_queue_t *next;
+};
+
#if 0
typedef struct
{
@@ -399,7 +426,7 @@ int write_to_buf(char *string, int string_len,
*/
int fetch_from_buf(char *string, int string_len,
- char **buf, int *buflen, int *buf_datalen);
+ char **buf, int *buflen, int *buf_datalen);
/* if there is string_len bytes in buf, write them onto string,
* then memmove buf back (that is, remove them from buf)
*/
@@ -429,13 +456,20 @@ 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_enumerate_by_naddr_nport(circuit_t *start, uint32_t naddr, uint16_t nport);
-int circuit_deliver_data_cell(cell_t *cell, circuit_t *circ, connection_t *conn, int crypt_type);
+int circuit_deliver_data_cell_from_edge(cell_t *cell, circuit_t *circ, char edge_type);
+int circuit_deliver_data_cell(cell_t *cell, circuit_t *circ, int crypt_type);
int circuit_crypt(circuit_t *circ, char *in, int inlen, char crypt_type);
+void circuit_resume_edge_reading(circuit_t *circ, int edge_type);
+int circuit_consider_stop_edge_reading(circuit_t *circ, int edge_type);
+int circuit_consider_sending_sendme(circuit_t *circ, int edge_type);
+
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);
@@ -525,7 +559,7 @@ int connection_process_inbuf(connection_t *conn);
int connection_package_raw_inbuf(connection_t *conn);
int connection_process_cell_from_inbuf(connection_t *conn);
-int connection_consider_sending_sendme(connection_t *conn);
+int connection_consider_sending_sendme(connection_t *conn, int edge_type);
int connection_finished_flushing(connection_t *conn);
/********************************* connection_ap.c ****************************/
@@ -537,15 +571,16 @@ 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);
+ 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);
int connection_ap_send_connected(connection_t *conn);
-int connection_ap_process_data_cell(cell_t *cell, connection_t *conn);
+int connection_ap_process_data_cell(cell_t *cell, circuit_t *circ);
int connection_ap_finished_flushing(connection_t *conn);
@@ -558,10 +593,10 @@ int connection_ap_handle_listener_read(connection_t *conn);
int connection_exit_process_inbuf(connection_t *conn);
int connection_exit_package_inbuf(connection_t *conn);
int connection_exit_send_connected(connection_t *conn);
-int connection_exit_process_data_cell(cell_t *cell, connection_t *conn);
+int connection_exit_process_data_cell(cell_t *cell, circuit_t *circ);
int connection_exit_finished_flushing(connection_t *conn);
-
+int connection_exit_connect(connection_t *conn);
/********************************* connection_op.c ***************************/
@@ -610,6 +645,13 @@ int connection_dir_finished_flushing(connection_t *conn);
int connection_dir_create_listener(struct sockaddr_in *bindaddr);
int connection_dir_handle_listener_read(connection_t *conn);
+/********************************* dns.c ***************************/
+
+int connection_dns_finished_flushing(connection_t *conn);
+int connection_dns_process_inbuf(connection_t *conn);
+int dns_tor_to_master(char *address);
+int dns_master_start(void);
+
/********************************* main.c ***************************/
void setprivatekey(crypto_pk_env_t *k);
@@ -622,6 +664,7 @@ connection_t *connection_twin_get_by_addr_port(uint32_t addr, uint16_t port);
connection_t *connection_exact_get_by_addr_port(uint32_t addr, uint16_t port);
connection_t *connection_get_by_type(int type);
+connection_t *connection_get_pendingresolve_by_address(char *address);
void connection_watch_events(connection_t *conn, short events);
void connection_stop_reading(connection_t *conn);
@@ -651,6 +694,7 @@ int onion_pending_add(circuit_t *circ);
int onion_pending_check(void);
void onion_pending_process_one(void);
void onion_pending_remove(circuit_t *circ);
+struct data_queue_t *data_queue_add(struct data_queue_t *list, cell_t *cell);
void onion_pending_data_add(circuit_t *circ, cell_t *cell);
/* uses a weighted coin with weight cw to choose a route length */