diff --git a/src/or/connection.c b/src/or/connection.c index cc39119a8b..ba6a77c2cf 100644 --- a/src/or/connection.c +++ b/src/or/connection.c @@ -92,6 +92,7 @@ connection_t *connection_new(int type) { conn->timestamp_lastread = now.tv_sec; conn->timestamp_lastwritten = now.tv_sec; +#ifndef TOR_TLS if (connection_speaks_cells(conn)) { conn->f_crypto = crypto_new_cipher_env(CONNECTION_CIPHER); if (!conn->f_crypto) { @@ -105,6 +106,7 @@ connection_t *connection_new(int type) { return NULL; } } +#endif conn->done_sending = conn->done_receiving = 0; return conn; } @@ -120,10 +122,16 @@ void connection_free(connection_t *conn) { free(conn->dest_addr); if(connection_speaks_cells(conn)) { + directory_set_dirty(); +#ifdef TOR_TLS + if (conn->SSL) + crypt_SSL_free(conn->SSL); +#else if (conn->f_crypto) crypto_free_cipher_env(conn->f_crypto); if (conn->b_crypto) crypto_free_cipher_env(conn->b_crypto); +#endif } if (conn->pkey) @@ -133,9 +141,6 @@ void connection_free(connection_t *conn) { log_fn(LOG_INFO,"closing fd %d.",conn->s); close(conn->s); } - if(conn->type == CONN_TYPE_OR) { - directory_set_dirty(); - } free(conn); } @@ -279,22 +284,52 @@ int retry_all_connections(uint16_t or_listenport, uint16_t ap_listenport, uint16 return 0; } +int connection_handle_read(connection_t *conn) { + struct timeval now; + + my_gettimeofday(&now); + conn->timestamp_lastread = now.tv_sec; + + switch(conn->type) { + case CONN_TYPE_OR_LISTENER: + return connection_or_handle_listener_read(conn); + case CONN_TYPE_AP_LISTENER: + return connection_ap_handle_listener_read(conn); + case CONN_TYPE_DIR_LISTENER: + return connection_dir_handle_listener_read(conn); + default: + + if(connection_read_to_buf(conn) < 0) { + if(conn->type == CONN_TYPE_DIR && conn->state == DIR_CONN_STATE_CONNECTING) { + /* it's a directory server and connecting failed: forget about this router */ + /* XXX I suspect pollerr may make Windows not get to this point. :( */ + router_forget_router(conn->addr,conn->port); + /* FIXME i don't think router_forget_router works. */ + } + return -1; + } + if(connection_process_inbuf(conn) < 0) { + //log_fn(LOG_DEBUG,"connection_process_inbuf returned %d.",retval); + return -1; + } + if(!connection_state_is_open(conn) && conn->receiver_bucket == 0) { + log_fn(LOG_DEBUG,"receiver bucket reached 0 before handshake finished. Closing."); + return -1; + } + return 0; + } /* end switch */ +} + int connection_read_to_buf(connection_t *conn) { int read_result; - struct timeval now; int at_most = global_read_bucket; if(connection_speaks_cells(conn)) { assert(conn->receiver_bucket >= 0); - } - if(!connection_speaks_cells(conn)) { + } else { assert(conn->receiver_bucket < 0); } - my_gettimeofday(&now); - - conn->timestamp_lastread = now.tv_sec; - if(conn->receiver_bucket >= 0 && at_most > conn->receiver_bucket) at_most = conn->receiver_bucket; @@ -338,13 +373,44 @@ int connection_outbuf_too_full(connection_t *conn) { } int connection_flush_buf(connection_t *conn) { - return flush_buf(conn->s, &conn->outbuf, &conn->outbuflen, &conn->outbuf_flushlen, &conn->outbuf_datalen); + return flush_buf(conn->s, &conn->outbuf, &conn->outbuflen, + &conn->outbuf_flushlen, &conn->outbuf_datalen); +} + +int connection_handle_write(connection_t *conn) { + struct timeval now; + int retval; + + if(connection_is_listener(conn)) { + log_fn(LOG_DEBUG,"Got a listener socket. Can't happen!"); + return -1; + } + + my_gettimeofday(&now); + conn->timestamp_lastwritten = now.tv_sec; + +#ifdef TOR_TLS + if(connection_speaks_cells(conn)) { + retval = flush_buf_SSL(conn->SSL, &conn->outbuf, &conn->outbuflen, + &conn->outbuf_flushlen, &conn->outbuf_datalen); + ... + + } else +#endif + { + retval = flush_buf(conn->s, &conn->outbuf, &conn->outbuflen, + &conn->outbuf_flushlen, &conn->outbuf_datalen); + /* conns in CONNECTING state will fall through... */ + + if(retval == 0) { /* it's done flushing */ + retval = connection_finished_flushing(conn); /* ...and get handled here. */ + } + } + + return retval; } int connection_write_to_buf(char *string, int len, connection_t *conn) { - struct timeval now; - - my_gettimeofday(&now); if(!len) return 0; @@ -352,12 +418,10 @@ int connection_write_to_buf(char *string, int len, connection_t *conn) { if(conn->marked_for_close) return 0; - conn->timestamp_lastwritten = now.tv_sec; - if( (!connection_speaks_cells(conn)) || (!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 */ + /* connection types other than or, or or not in 'open' state, should flush immediately */ /* also flush immediately if we're not doing LinkPadding, since otherwise it will never flush */ connection_start_writing(conn); conn->outbuf_flushlen += len; @@ -397,78 +461,6 @@ int connection_state_is_open(connection_t *conn) { return 0; } -void connection_send_cell(connection_t *conn) { - cell_t cell; - int bytes_in_full_flushlen; - - assert(0); /* this function has decayed. rewrite before using. */ - - /* this function only gets called if options.LinkPadding is 1 */ - assert(options.LinkPadding == 1); - - assert(conn); - - if(!connection_speaks_cells(conn)) { - /* 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_start_writing(conn); - } -#endif - - connection_increment_send_timeval(conn); /* update when we'll send the next cell */ - - bytes_in_full_flushlen = conn->bandwidth / 100; /* 10ms worth */ - if(bytes_in_full_flushlen < 10*sizeof(cell_t)) - bytes_in_full_flushlen = 10*sizeof(cell_t); /* but at least 10 cells worth */ - - if(conn->outbuf_flushlen > bytes_in_full_flushlen - sizeof(cell_t)) { - /* if we would exceed bytes_in_full_flushlen by adding a new cell */ - return; - } - - 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); - } - - /* The connection_write_cell_to_buf() call doesn't increase the flushlen - * (if link padding is on). So if there isn't a whole cell waiting-but- - * not-yet-flushed, we add a padding cell. Thus in any case the gap between - * outbuf_datalen and outbuf_flushlen is at least sizeof(cell_t). - */ - conn->outbuf_flushlen += sizeof(cell_t); /* instruct it to send a cell */ - connection_start_writing(conn); -} - -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); - - my_gettimeofday(&conn->send_timeval); - - connection_increment_send_timeval(conn); -} - int connection_send_destroy(aci_t aci, connection_t *conn) { cell_t cell; diff --git a/src/or/connection_or.c b/src/or/connection_or.c index 058d776da3..e2ad05e0e8 100644 --- a/src/or/connection_or.c +++ b/src/or/connection_or.c @@ -6,6 +6,7 @@ extern or_options_t options; /* command-line and config-file options */ +#ifndef TOR_TLS static int or_handshake_op_send_keys(connection_t *conn); static int or_handshake_op_finished_sending_keys(connection_t *conn); @@ -15,8 +16,9 @@ static int or_handshake_client_send_auth(connection_t *conn); static int or_handshake_server_process_auth(connection_t *conn); static int or_handshake_server_process_nonce(connection_t *conn); -static void connection_or_set_open(connection_t *conn); static void conn_or_init_crypto(connection_t *conn); +#endif +static void connection_or_set_open(connection_t *conn); /* * @@ -29,7 +31,6 @@ int connection_or_process_inbuf(connection_t *conn) { assert(conn && conn->type == CONN_TYPE_OR); if(conn->inbuf_reached_eof) { - /* eof reached, kill it. */ log_fn(LOG_DEBUG,"conn reached eof. Closing."); return -1; } @@ -37,12 +38,14 @@ int connection_or_process_inbuf(connection_t *conn) { // log(LOG_DEBUG,"connection_or_process_inbuf(): state %d.",conn->state); switch(conn->state) { +#ifndef TOR_TLS case OR_CONN_STATE_CLIENT_AUTH_WAIT: return or_handshake_client_process_auth(conn); case OR_CONN_STATE_SERVER_AUTH_WAIT: return or_handshake_server_process_auth(conn); case OR_CONN_STATE_SERVER_NONCE_WAIT: return or_handshake_server_process_nonce(conn); +#endif case OR_CONN_STATE_OPEN: return connection_process_cell_from_inbuf(conn); default: @@ -583,7 +586,6 @@ or_handshake_server_process_auth(connection_t *conn) { crypto_cipher_decrypt_init_cipher(conn->f_crypto); conn->state = OR_CONN_STATE_OPEN; - connection_init_timeval(conn); connection_watch_events(conn, POLLIN); return connection_process_inbuf(conn); /* in case they sent some cells along with the keys */ @@ -654,10 +656,10 @@ static void connection_or_set_open(connection_t *conn) { conn->state = OR_CONN_STATE_OPEN; directory_set_dirty(); - connection_init_timeval(conn); connection_watch_events(conn, POLLIN); } +#ifndef TOR_TLS static void conn_or_init_crypto(connection_t *conn) { //int x; @@ -673,6 +675,7 @@ conn_or_init_crypto(connection_t *conn) { crypto_cipher_decrypt_init_cipher(conn->b_crypto); /* always encrypt with f, always decrypt with b */ } +#endif diff --git a/src/or/main.c b/src/or/main.c index 0bb241a9de..15647144c5 100644 --- a/src/or/main.c +++ b/src/or/main.c @@ -244,83 +244,47 @@ void connection_start_writing(connection_t *conn) { } static void conn_read(int i) { - int retval; connection_t *conn; + if(!(poll_array[i].revents & (POLLIN|POLLHUP|POLLERR))) + return; /* this conn doesn't want to read */ + /* see http://www.greenend.org.uk/rjk/2001/06/poll.html for + * discussion of POLLIN vs POLLHUP */ + conn = connection_array[i]; - assert(conn); -// log_fn(LOG_DEBUG,"socket %d has something to read.",conn->s); + //log_fn(LOG_DEBUG,"socket %d has something to read.",conn->s); + if( + /* XXX does POLLHUP also mean it's definitely broken? */ #ifdef MS_WINDOWS - if (poll_array[i].revents & POLLERR) { - retval = -1; - goto error; - } + (poll_array[i].revents & POLLERR) || #endif - - if (conn->type == CONN_TYPE_OR_LISTENER) { - retval = connection_or_handle_listener_read(conn); - } else if (conn->type == CONN_TYPE_AP_LISTENER) { - retval = connection_ap_handle_listener_read(conn); - } else if (conn->type == CONN_TYPE_DIR_LISTENER) { - retval = connection_dir_handle_listener_read(conn); - } else { - 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); /* FIXME i don't think this function works. */ - } - if (retval >= 0) { /* all still well */ - retval = connection_process_inbuf(conn); -// log_fn(LOG_DEBUG,"connection_process_inbuf returned %d.",retval); - if(retval >= 0 && !connection_state_is_open(conn) && conn->receiver_bucket == 0) { - log(LOG_DEBUG,"conn_read(): receiver bucket reached 0 before handshake finished. Closing."); - retval = -1; + connection_handle_read(conn) < 0) + { + /* this connection is broken. remove it */ + log_fn(LOG_INFO,"%s connection broken, removing.", conn_type_to_string[conn->type]); + connection_remove(conn); + connection_free(conn); + if(itype]); - connection_remove(conn); - connection_free(conn); - if(is); + //log_fn(LOG_DEBUG,"socket %d wants to write.",conn->s); - if(connection_is_listener(conn)) { - log_fn(LOG_DEBUG,"Got a listener socket. Can't happen!"); - retval = -1; - } else { - /* else it's an OP, OR, or exit */ - retval = connection_flush_buf(conn); /* conns in CONNECTING state will fall through... */ - if(retval == 0) { /* it's done flushing */ - retval = connection_finished_flushing(conn); /* ...and get handled here. */ - } - } - - if(retval < 0) { /* this connection is broken. remove it. */ + if(connection_handle_write(conn) < 0) { /* this connection is broken. remove it. */ log_fn(LOG_DEBUG,"%s connection broken, removing.", conn_type_to_string[conn->type]); connection_remove(conn); connection_free(conn); - if(isend_timeval,&now) <= 0) { /* send_timeval has already passed, let it send a cell */ - connection_send_cell(tmpconn); - } - if(!conn || tv_cmp(&tmpconn->send_timeval, &soonest) < 0) { /* this is the best choice so far */ - conn = tmpconn; - soonest.tv_sec = conn->send_timeval.tv_sec; - soonest.tv_usec = conn->send_timeval.tv_usec; - } - } - - if(conn) { /* we might want to set *timeout sooner */ - ms_until_conn = (soonest.tv_sec - now.tv_sec)*1000 + - (soonest.tv_usec - now.tv_usec)/1000; -// log(LOG_DEBUG,"prepare_for_poll(): conn %d times out in %d ms.",conn->s, ms_until_conn); - if(ms_until_conn < *timeout) { /* use the new one */ -// log(LOG_DEBUG,"prepare_for_poll(): conn %d soonest, in %d ms.",conn->s,ms_until_conn); - *timeout = ms_until_conn; - } - } - } -#endif - static int do_main_loop(void) { int i; int timeout; @@ -516,7 +444,7 @@ static int do_main_loop(void) { /* start up the necessary connections based on which ports are * non-zero. This is where we try to connect to all the other ORs, - * and start the listeners + * and start the listeners. */ retry_all_connections((uint16_t) options.ORPort, (uint16_t) options.APPort, @@ -543,17 +471,10 @@ static int do_main_loop(void) { please_reap_children = 0; } #endif /* signal stuff */ - if(prepare_for_poll(&timeout) < 0) { - log(LOG_DEBUG,"do_main_loop(): prepare_for_poll failed, exiting."); - return -1; - } - /* now timeout is the value we'll hand to poll. It's either -1, meaning - * don't timeout, else it indicates the soonest event (either the - * one-second rollover for refilling receiver buckets, or the soonest - * conn that needs to send a cell) - */ - /* poll until we have an event, or it's time to do something */ + timeout = prepare_for_poll(); + + /* poll until we have an event, or the second ends */ poll_result = poll(poll_array, nfds, timeout); #if 0 /* let catch() handle things like ^c, and otherwise don't worry about it */ @@ -567,16 +488,11 @@ static int do_main_loop(void) { if(poll_result > 0) { /* we have at least one connection to deal with */ /* do all the reads and errors first, so we can detect closed sockets */ for(i=0;i