diff options
Diffstat (limited to 'src/or/connection.c')
-rw-r--r-- | src/or/connection.c | 169 |
1 files changed, 165 insertions, 4 deletions
diff --git a/src/or/connection.c b/src/or/connection.c index 0b80db796..8b4155d15 100644 --- a/src/or/connection.c +++ b/src/or/connection.c @@ -1,8 +1,13 @@ +/* Copyright 2001,2002 Roger Dingledine, Matej Pfajfar. */ +/* See LICENSE for licensing information */ +/* $Id$ */ #include "or.h" /********* START VARIABLES **********/ +extern or_options_t options; /* command-line and config-file options */ + #if 0 /* these are now out of date :( -RD */ char *conn_type_to_string[] = { @@ -38,6 +43,34 @@ char *conn_state_to_string[][10] = { /********* END VARIABLES ************/ +/**************************************************************/ + +int tv_cmp(struct timeval *a, struct timeval *b) { + if (a->tv_sec > b->tv_sec) + return 1; + if (a->tv_sec < b->tv_sec) + return -1; + if (a->tv_usec > b->tv_usec) + return 1; + if (a->tv_usec < b->tv_usec) + return -1; + return 0; +} + +void tv_add(struct timeval *a, struct timeval *b) { + a->tv_usec += b->tv_usec; + a->tv_sec += b->tv_sec + (a->tv_usec / 1000000); + a->tv_usec %= 1000000; +} + +void tv_addms(struct timeval *a, long ms) { + a->tv_usec += (ms * 1000) % 1000000; + a->tv_sec += ((ms * 1000) / 1000000) + (a->tv_usec / 1000000); + a->tv_usec %= 1000000; +} + +/**************************************************************/ + connection_t *connection_new(int type) { connection_t *conn; @@ -51,6 +84,8 @@ connection_t *connection_new(int type) { buf_new(&conn->outbuf, &conn->outbuflen, &conn->outbuf_datalen) < 0) return NULL; + conn->receiver_bucket = 10240; /* should be enough to do the handshake */ + conn->bandwidth = conn->receiver_bucket / 10; /* give it a default */ return conn; } @@ -245,7 +280,26 @@ connection_t *connection_connect_to_router_as_op(routerinfo_t *router, RSA *prke } int connection_read_to_buf(connection_t *conn) { - return read_to_buf(conn->s, &conn->inbuf, &conn->inbuflen, &conn->inbuf_datalen, &conn->inbuf_reached_eof); + int read_result; + + 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) { + conn->receiver_bucket -= read_result; + if(conn->receiver_bucket <= 0) { + + connection_stop_reading(conn); + + /* If we're not in 'open' state here, then we're never going to finish the + * handshake, because we'll never increment the receiver_bucket. But we + * can't check for that here, because the buf we just read might have enough + * on it to finish the handshake. So we check for that in check_conn_read(). + */ + } + } + + return read_result; } int connection_fetch_from_buf(char *string, int len, connection_t *conn) { @@ -253,16 +307,114 @@ int connection_fetch_from_buf(char *string, int len, connection_t *conn) { } int connection_flush_buf(connection_t *conn) { - return flush_buf(conn->s, &conn->outbuf, &conn->outbuflen, &conn->outbuf_datalen); + return flush_buf(conn->s, &conn->outbuf, &conn->outbuflen, &conn->outbuf_flushlen, &conn->outbuf_datalen); } int connection_write_to_buf(char *string, int len, connection_t *conn) { if(!len) return 0; - connection_watch_events(conn, POLLOUT | POLLIN); + + if( (conn->type != CONN_TYPE_OR && conn->type != CONN_TYPE_OR) || + (!connection_state_is_open(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); + conn->outbuf_flushlen += len; + } + return write_to_buf(string, len, &conn->outbuf, &conn->outbuflen, &conn->outbuf_datalen); } +int connection_receiver_bucket_should_increase(connection_t *conn) { + assert(conn); + + if(conn->receiver_bucket > 10*conn->bandwidth) + return 0; + + return 1; +} + +void connection_increment_receiver_bucket (connection_t *conn) { + assert(conn); + + if(connection_receiver_bucket_should_increase(conn)) { + /* yes, the receiver_bucket can become overfull here. But not by much. */ + conn->receiver_bucket += conn->bandwidth*1.1; + if(connection_state_is_open(conn)) { + /* if we're in state 'open', then start reading again */ + connection_start_reading(conn); + } + } +} + +int connection_state_is_open(connection_t *conn) { + assert(conn); + + if((conn->type == CONN_TYPE_OR && conn->state == OR_CONN_STATE_OPEN) || + (conn->type == CONN_TYPE_OP && conn->state == OP_CONN_STATE_OPEN) || + (conn->type == CONN_TYPE_AP && conn->state == AP_CONN_STATE_OPEN) || + (conn->type == CONN_TYPE_EXIT && conn->state == EXIT_CONN_STATE_OPEN)) + return 1; + + return 0; +} + +void connection_send_cell(connection_t *conn) { + cell_t cell; + + assert(conn); + + if(conn->type != CONN_TYPE_OR && conn->type != CONN_TYPE_OP) { + /* this conn doesn't speak cells. do nothing. */ + return; + } + + if(!connection_state_is_open(conn)) { + /* it's not in 'open' state, all data should already be waiting to be flushed */ + assert(conn->outbuf_datalen == conn->outbuf_flushlen); + return; + } + +#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); + } +#endif + +#if 1 /* experimental code, that sends padding cells too. 'probably' works :) */ + if(conn->outbuf_datalen - conn->outbuf_flushlen < sizeof(cell_t)) { + /* we need to queue a padding cell first */ + memset(&cell,0,sizeof(cell_t)); + cell.command = CELL_PADDING; + connection_write_cell_to_buf(&cell, conn); + } + + conn->outbuf_flushlen += sizeof(cell_t); /* instruct it to send a cell */ + connection_watch_events(conn, POLLOUT | POLLIN); +#endif + + connection_increment_send_timeval(conn); /* update when we'll send the next cell */ +} + +void connection_increment_send_timeval(connection_t *conn) { + /* add "1000000 * sizeof(cell_t) / conn->bandwidth" microseconds to conn->send_timeval */ + /* FIXME should perhaps use ceil() of this. For now I simply add 1. */ + + tv_addms(&conn->send_timeval, 1+1000 * sizeof(cell_t) / conn->bandwidth); +} + +void connection_init_timeval(connection_t *conn) { + + assert(conn); + + if(gettimeofday(&conn->send_timeval,NULL) < 0) + return; + + connection_increment_send_timeval(conn); +} + int connection_send_destroy(aci_t aci, connection_t *conn) { cell_t cell; @@ -276,6 +428,8 @@ int connection_send_destroy(aci_t aci, connection_t *conn) { 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); @@ -291,7 +445,6 @@ int connection_write_cell_to_buf(cell_t *cellp, connection_t *conn) { } return connection_write_to_buf((char *)cellp, sizeof(cell_t), conn); - } int connection_encrypt_cell_header(cell_t *cellp, connection_t *conn) { @@ -300,22 +453,26 @@ int connection_encrypt_cell_header(cell_t *cellp, connection_t *conn) { int x; char *px; +#if 0 printf("Sending: Cell header plaintext: "); px = (char *)cellp; for(x=0;x<8;x++) { printf("%u ",px[x]); } printf("\n"); +#endif if(!EVP_EncryptUpdate(&conn->f_ctx, newheader, &newsize, (char *)cellp, 8)) { log(LOG_ERR,"Could not encrypt data for connection %s:%u.",conn->address,ntohs(conn->port)); return -1; } +#if 0 printf("Sending: Cell header crypttext: "); for(x=0;x<8;x++) { printf("%u ",newheader[x]); } printf("\n"); +#endif memcpy(cellp,newheader,8); return 0; @@ -430,22 +587,26 @@ int connection_process_cell_from_inbuf(connection_t *conn) { return -1; } +#if 0 printf("Cell header crypttext: "); for(x=0;x<8;x++) { printf("%u ",crypted[x]); } printf("\n"); +#endif /* decrypt */ if(!EVP_DecryptUpdate(&conn->b_ctx,(unsigned char *)outbuf,&outlen,crypted,8)) { 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); +#if 0 printf("Cell header plaintext: "); for(x=0;x<8;x++) { printf("%u ",outbuf[x]); } printf("\n"); +#endif /* copy the rest of the cell */ memcpy((char *)outbuf+8, (char *)crypted+8, sizeof(cell_t)-8); |