|
@@ -101,9 +101,7 @@ void connection_free(connection_t *conn) {
|
|
|
if(conn->dest_port)
|
|
|
free(conn->dest_port);
|
|
|
|
|
|
- /* FIXME should we do these for all connections, or just ORs, or what */
|
|
|
- if(conn->type == CONN_TYPE_OR ||
|
|
|
- conn->type == CONN_TYPE_OP) {
|
|
|
+ if(connection_speaks_cells(conn)) {
|
|
|
EVP_CIPHER_CTX_cleanup(&conn->f_ctx);
|
|
|
EVP_CIPHER_CTX_cleanup(&conn->b_ctx);
|
|
|
}
|
|
@@ -158,7 +156,7 @@ int connection_create_listener(RSA *prkey, struct sockaddr_in *local, int type)
|
|
|
log(LOG_DEBUG,"connection_create_listener(): Listening on local port %u.",ntohs(local->sin_port));
|
|
|
|
|
|
conn->state = LISTENER_STATE_READY;
|
|
|
- connection_watch_events(conn, POLLIN);
|
|
|
+ connection_start_reading(conn);
|
|
|
|
|
|
return 0;
|
|
|
}
|
|
@@ -185,6 +183,11 @@ int connection_handle_listener_read(connection_t *conn, int new_type, int new_st
|
|
|
newconn = connection_new(new_type);
|
|
|
newconn->s = news;
|
|
|
|
|
|
+ if(!connection_speaks_cells(newconn)) {
|
|
|
+ newconn->receiver_bucket = -1;
|
|
|
+ newconn->bandwidth = -1;
|
|
|
+ }
|
|
|
+
|
|
|
/* learn things from parent, so we can perform auth */
|
|
|
memcpy(&newconn->local,&conn->local,sizeof(struct sockaddr_in));
|
|
|
newconn->prkey = conn->prkey;
|
|
@@ -197,7 +200,7 @@ int connection_handle_listener_read(connection_t *conn, int new_type, int new_st
|
|
|
|
|
|
log(LOG_DEBUG,"connection_handle_listener_read(): socket %d entered state %d.",newconn->s, new_state);
|
|
|
newconn->state = new_state;
|
|
|
- connection_watch_events(newconn, POLLIN);
|
|
|
+ connection_start_reading(newconn);
|
|
|
|
|
|
return 0;
|
|
|
}
|
|
@@ -284,13 +287,20 @@ connection_t *connection_connect_to_router_as_op(routerinfo_t *router, RSA *prke
|
|
|
int connection_read_to_buf(connection_t *conn) {
|
|
|
int read_result;
|
|
|
|
|
|
+ if(connection_speaks_cells(conn)) {
|
|
|
+ assert(conn->receiver_bucket >= 0);
|
|
|
+ }
|
|
|
+ if(!connection_speaks_cells(conn)) {
|
|
|
+ assert(conn->receiver_bucket < 0);
|
|
|
+ }
|
|
|
read_result = read_to_buf(conn->s, conn->receiver_bucket, &conn->inbuf, &conn->inbuflen,
|
|
|
&conn->inbuf_datalen, &conn->inbuf_reached_eof);
|
|
|
- log(LOG_DEBUG,"connection_read_to_buf(): read_to_buf returned %d.",read_result);
|
|
|
- if(read_result >= 0) {
|
|
|
+// log(LOG_DEBUG,"connection_read_to_buf(): read_to_buf returned %d.",read_result);
|
|
|
+ if(read_result >= 0 && connection_speaks_cells(conn)) {
|
|
|
conn->receiver_bucket -= read_result;
|
|
|
if(conn->receiver_bucket <= 0) {
|
|
|
|
|
|
+// log(LOG_DEBUG,"connection_read_to_buf() stopping reading, receiver bucket full.");
|
|
|
connection_stop_reading(conn);
|
|
|
|
|
|
/* If we're not in 'open' state here, then we're never going to finish the
|
|
@@ -308,6 +318,14 @@ int connection_fetch_from_buf(char *string, int len, connection_t *conn) {
|
|
|
return fetch_from_buf(string, len, &conn->inbuf, &conn->inbuflen, &conn->inbuf_datalen);
|
|
|
}
|
|
|
|
|
|
+int connection_wants_to_flush(connection_t *conn) {
|
|
|
+ return conn->outbuf_flushlen;
|
|
|
+}
|
|
|
+
|
|
|
+int connection_outbuf_too_full(connection_t *conn) {
|
|
|
+ return (conn->outbuf_flushlen > 10*CELL_PAYLOAD_SIZE);
|
|
|
+}
|
|
|
+
|
|
|
int connection_flush_buf(connection_t *conn) {
|
|
|
return flush_buf(conn->s, &conn->outbuf, &conn->outbuflen, &conn->outbuf_flushlen, &conn->outbuf_datalen);
|
|
|
}
|
|
@@ -321,7 +339,7 @@ int connection_write_to_buf(char *string, int len, connection_t *conn) {
|
|
|
(options.LinkPadding == 0) ) {
|
|
|
/* connection types other than or and op, or or/op not in 'open' state, should flush immediately */
|
|
|
/* also flush immediately if we're not doing LinkPadding, since otherwise it will never flush */
|
|
|
- connection_watch_events(conn, POLLOUT | POLLIN);
|
|
|
+ connection_start_writing(conn);
|
|
|
conn->outbuf_flushlen += len;
|
|
|
}
|
|
|
|
|
@@ -331,6 +349,9 @@ int connection_write_to_buf(char *string, int len, connection_t *conn) {
|
|
|
int connection_receiver_bucket_should_increase(connection_t *conn) {
|
|
|
assert(conn);
|
|
|
|
|
|
+ if(!connection_speaks_cells(conn))
|
|
|
+ return 0; /* edge connections don't use receiver_buckets */
|
|
|
+
|
|
|
if(conn->receiver_bucket > 10*conn->bandwidth)
|
|
|
return 0;
|
|
|
|
|
@@ -350,6 +371,15 @@ void connection_increment_receiver_bucket (connection_t *conn) {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+int connection_speaks_cells(connection_t *conn) {
|
|
|
+ assert(conn);
|
|
|
+
|
|
|
+ if(conn->type == CONN_TYPE_OR || conn->type == CONN_TYPE_OP)
|
|
|
+ return 1;
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
int connection_state_is_open(connection_t *conn) {
|
|
|
assert(conn);
|
|
|
|
|
@@ -371,7 +401,7 @@ void connection_send_cell(connection_t *conn) {
|
|
|
|
|
|
assert(conn);
|
|
|
|
|
|
- if(conn->type != CONN_TYPE_OR && conn->type != CONN_TYPE_OP) {
|
|
|
+ if(!connection_speaks_cells(conn)) {
|
|
|
/* this conn doesn't speak cells. do nothing. */
|
|
|
return;
|
|
|
}
|
|
@@ -385,7 +415,7 @@ void connection_send_cell(connection_t *conn) {
|
|
|
#if 0 /* use to send evenly spaced cells, but not padding */
|
|
|
if(conn->outbuf_datalen - conn->outbuf_flushlen >= sizeof(cell_t)) {
|
|
|
conn->outbuf_flushlen += sizeof(cell_t); /* instruct it to send a cell */
|
|
|
- connection_watch_events(conn, POLLOUT | POLLIN);
|
|
|
+ connection_start_writing(conn);
|
|
|
}
|
|
|
#endif
|
|
|
|
|
@@ -408,7 +438,7 @@ void connection_send_cell(connection_t *conn) {
|
|
|
}
|
|
|
|
|
|
conn->outbuf_flushlen += sizeof(cell_t); /* instruct it to send a cell */
|
|
|
- connection_watch_events(conn, POLLOUT | POLLIN);
|
|
|
+ connection_start_writing(conn);
|
|
|
|
|
|
}
|
|
|
|
|
@@ -434,16 +464,12 @@ int connection_send_destroy(aci_t aci, connection_t *conn) {
|
|
|
|
|
|
assert(conn);
|
|
|
|
|
|
- if(conn->type == CONN_TYPE_OP ||
|
|
|
- conn->type == CONN_TYPE_AP ||
|
|
|
- conn->type == CONN_TYPE_EXIT) {
|
|
|
+ if(!connection_speaks_cells(conn)) {
|
|
|
log(LOG_DEBUG,"connection_send_destroy(): At an edge. Marking connection for close.");
|
|
|
conn->marked_for_close = 1;
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
- assert(conn->type == CONN_TYPE_OR);
|
|
|
-
|
|
|
cell.aci = aci;
|
|
|
cell.command = CELL_DESTROY;
|
|
|
log(LOG_DEBUG,"connection_send_destroy(): Sending destroy (aci %d).",aci);
|
|
@@ -452,7 +478,6 @@ int connection_send_destroy(aci_t aci, connection_t *conn) {
|
|
|
}
|
|
|
|
|
|
int connection_write_cell_to_buf(cell_t *cellp, connection_t *conn) {
|
|
|
- /* FIXME in the future, we should modify windows, etc, here */
|
|
|
|
|
|
if(connection_encrypt_cell_header(cellp,conn)<0) {
|
|
|
return -1;
|
|
@@ -464,10 +489,10 @@ int connection_write_cell_to_buf(cell_t *cellp, connection_t *conn) {
|
|
|
int connection_encrypt_cell_header(cell_t *cellp, connection_t *conn) {
|
|
|
char newheader[8];
|
|
|
int newsize;
|
|
|
+#if 0
|
|
|
int x;
|
|
|
char *px;
|
|
|
|
|
|
-#if 0
|
|
|
printf("Sending: Cell header plaintext: ");
|
|
|
px = (char *)cellp;
|
|
|
for(x=0;x<8;x++) {
|
|
@@ -517,7 +542,8 @@ int connection_package_raw_inbuf(connection_t *conn) {
|
|
|
circuit_t *circ;
|
|
|
|
|
|
assert(conn);
|
|
|
- assert(conn->type == CONN_TYPE_EXIT || conn->type == CONN_TYPE_AP);
|
|
|
+ assert(!connection_speaks_cells(conn));
|
|
|
+ /* this function should never get called if the receiver_window is 0 */
|
|
|
|
|
|
amount_to_process = conn->inbuf_datalen;
|
|
|
|
|
@@ -548,6 +574,13 @@ int connection_package_raw_inbuf(connection_t *conn) {
|
|
|
circuit_close(circ);
|
|
|
return 0;
|
|
|
}
|
|
|
+ assert(circ->n_receive_window > 0);
|
|
|
+ if(--circ->n_receive_window <= 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.");
|
|
|
+ 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);
|
|
|
} else { /* send it forward. we're an AP */
|
|
|
cell.aci = circ->n_aci;
|
|
|
cell.command = CELL_DATA;
|
|
@@ -557,17 +590,58 @@ int connection_package_raw_inbuf(connection_t *conn) {
|
|
|
circuit_close(circ);
|
|
|
return 0;
|
|
|
}
|
|
|
+ assert(circ->p_receive_window > 0);
|
|
|
+ if(--circ->p_receive_window <= 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.");
|
|
|
+ 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);
|
|
|
}
|
|
|
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) {
|
|
|
+ circuit_t *circ;
|
|
|
+ cell_t sendme;
|
|
|
+
|
|
|
+ if(connection_outbuf_too_full(conn))
|
|
|
+ return 0;
|
|
|
+
|
|
|
+ circ = circuit_get_by_conn(conn);
|
|
|
+ if(!circ) {
|
|
|
+ log(LOG_DEBUG,"connection_consider_sending_sendme(): Bug: no circuit associated with conn. Closing.");
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+ 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(): Queueing sendme back.");
|
|
|
+ circ->p_receive_window += RECEIVE_WINDOW_INCREMENT;
|
|
|
+ sendme.aci = circ->p_aci;
|
|
|
+ return connection_write_cell_to_buf(&sendme, circ->p_conn); /* (clobbers sendme) */
|
|
|
+ }
|
|
|
+ } else { /* we're at an AP */
|
|
|
+ if(circ->n_receive_window < RECEIVE_WINDOW_START-RECEIVE_WINDOW_INCREMENT) {
|
|
|
+ log(LOG_DEBUG,"connection_consider_sending_sendme(): Queueing sendme forward.");
|
|
|
+ circ->n_receive_window += RECEIVE_WINDOW_INCREMENT;
|
|
|
+ sendme.aci = circ->n_aci;
|
|
|
+ return connection_write_cell_to_buf(&sendme, circ->n_conn); /* (clobbers sendme) */
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
int connection_finished_flushing(connection_t *conn) {
|
|
|
|
|
|
assert(conn);
|
|
|
|
|
|
- log(LOG_DEBUG,"connection_finished_flushing() entered. Socket %u.", conn->s);
|
|
|
+// log(LOG_DEBUG,"connection_finished_flushing() entered. Socket %u.", conn->s);
|
|
|
|
|
|
switch(conn->type) {
|
|
|
case CONN_TYPE_AP:
|
|
@@ -591,7 +665,7 @@ int connection_process_cell_from_inbuf(connection_t *conn) {
|
|
|
char crypted[128];
|
|
|
char outbuf[1024];
|
|
|
int outlen;
|
|
|
- int x;
|
|
|
+// int x;
|
|
|
cell_t *cellp;
|
|
|
|
|
|
if(conn->inbuf_datalen < 128) /* entire response available? */
|
|
@@ -613,7 +687,7 @@ int connection_process_cell_from_inbuf(connection_t *conn) {
|
|
|
log(LOG_ERR,"connection_process_cell_from_inbuf(): Decryption failed, dropping.");
|
|
|
return connection_process_inbuf(conn); /* process the remainder of the buffer */
|
|
|
}
|
|
|
- log(LOG_DEBUG,"connection_process_cell_from_inbuf(): Cell decrypted (%d bytes).",outlen);
|
|
|
+// log(LOG_DEBUG,"connection_process_cell_from_inbuf(): Cell decrypted (%d bytes).",outlen);
|
|
|
#if 0
|
|
|
printf("Cell header plaintext: ");
|
|
|
for(x=0;x<8;x++) {
|
|
@@ -625,7 +699,7 @@ int connection_process_cell_from_inbuf(connection_t *conn) {
|
|
|
/* copy the rest of the cell */
|
|
|
memcpy((char *)outbuf+8, (char *)crypted+8, sizeof(cell_t)-8);
|
|
|
cellp = (cell_t *)outbuf;
|
|
|
- log(LOG_DEBUG,"connection_process_cell_from_inbuf(): Decrypted cell is of type %u (ACI %u).",cellp->command,cellp->aci);
|
|
|
+// log(LOG_DEBUG,"connection_process_cell_from_inbuf(): Decrypted cell is of type %u (ACI %u).",cellp->command,cellp->aci);
|
|
|
command_process_cell(cellp, conn);
|
|
|
|
|
|
return connection_process_inbuf(conn); /* process the remainder of the buffer */
|