Loading src/or/connection.c +79 −87 Original line number Diff line number Diff line Loading @@ -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) { Loading @@ -105,6 +106,7 @@ connection_t *connection_new(int type) { return NULL; } } #endif conn->done_sending = conn->done_receiving = 0; return conn; } Loading @@ -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) Loading @@ -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); } Loading Loading @@ -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; Loading Loading @@ -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_write_to_buf(char *string, int len, connection_t *conn) { 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) { if(!len) return 0; Loading @@ -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; Loading Loading @@ -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; Loading src/or/connection_or.c +7 −4 Original line number Diff line number Diff line Loading @@ -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); Loading @@ -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); /* * Loading @@ -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; } Loading @@ -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: Loading Loading @@ -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 */ Loading Loading @@ -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; Loading @@ -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 Loading src/or/main.c +31 −115 Original line number Diff line number Diff line Loading @@ -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); if( /* XXX does POLLHUP also mean it's definitely broken? */ #ifdef MS_WINDOWS if (poll_array[i].revents & POLLERR) { retval = -1; goto error; } #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; } } } #ifdef MS_WINDOWS error: (poll_array[i].revents & POLLERR) || #endif if(retval < 0) { /* this connection is broken. remove it */ 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(i<nfds) { /* we just replaced the one at i with a new one. process it too. */ if(poll_array[i].revents & (POLLIN|POLLHUP|POLLERR)) /* something to read */ if(i<nfds) { /* we just replaced the one at i with a new one. process it too. */ conn_read(i); } } } static void conn_write(int i) { int retval; connection_t *conn; if(!(poll_array[i].revents & POLLOUT)) return; /* this conn doesn't want to write */ conn = connection_array[i]; //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(i<nfds) { /* we just replaced the one at i with a new one. process it too. */ if(poll_array[i].revents & POLLOUT) /* something to write */ if(i<nfds) { /* we just replaced the one at i with a new one. process it too. */ conn_write(i); } } Loading @@ -346,7 +310,7 @@ static void check_conn_marked(int i) { } } static int prepare_for_poll(int *timeout) { static int prepare_for_poll(void) { int i; // connection_t *conn = NULL; connection_t *tmpconn; Loading Loading @@ -434,45 +398,9 @@ static int prepare_for_poll(int *timeout) { current_second = now.tv_sec; /* remember which second it is, for next time */ } *timeout = 1000 - (now.tv_usec / 1000); /* how many milliseconds til the next second? */ return 0; return (1000 - (now.tv_usec / 1000)); /* how many milliseconds til the next second? */ } /* Link padding stuff left here for fun. Not used now. */ #if 0 if(options.LinkPadding) { /* now check which conn wants to speak soonest */ for(i=0;i<nfds;i++) { tmpconn = connection_array[i]; if(!connection_speaks_cells(tmpconn)) continue; /* this conn type doesn't send cells */ if(!connection_state_is_open(tmpconn)) continue; /* only conns in state 'open' have a valid send_timeval */ while(tv_cmp(&tmpconn->send_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; Loading Loading @@ -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, Loading @@ -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 */ Loading @@ -567,15 +488,10 @@ 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<nfds;i++) if(poll_array[i].revents & (POLLIN|POLLHUP|POLLERR)) /* something to read, or an error. */ conn_read(i); /* this also blows away broken connections */ /* see http://www.greenend.org.uk/rjk/2001/06/poll.html for discussion * of POLLIN vs POLLHUP */ /* then do the writes */ for(i=0;i<nfds;i++) if(poll_array[i].revents & POLLOUT) /* something to write */ conn_write(i); /* any of the conns need to be closed now? */ Loading src/or/or.h +52 −45 Original line number Diff line number Diff line Loading @@ -94,7 +94,7 @@ #include "../common/log.h" #include "../common/util.h" #define RECOMMENDED_SOFTWARE_VERSIONS "0.0.2pre6,0.0.2pre7" #define RECOMMENDED_SOFTWARE_VERSIONS "0.0.2pre8" #define MAXCONNECTIONS 1000 /* upper bound on max connections. can be lowered by config file */ Loading Loading @@ -131,6 +131,7 @@ #define CPUWORKER_TASK_ONION CPUWORKER_STATE_BUSY_ONION #define CPUWORKER_TASK_HANDSHAKE CPUWORKER_STATE_BUSY_HANDSHAKE #ifndef TOR_TLS /* how to read these states: * foo_CONN_STATE_bar_baz: * "I am acting as a bar, currently in stage baz of talking with a foo." Loading @@ -145,6 +146,11 @@ #define OR_CONN_STATE_SERVER_SENDING_AUTH 7 /* writing auth and nonce */ #define OR_CONN_STATE_SERVER_NONCE_WAIT 8 /* waiting for confirmation of nonce */ #define OR_CONN_STATE_OPEN 9 /* ready to send/receive cells. */ #else #define OR_CONN_STATE_CONNECTING 0 /* waiting for connect() to finish */ #define OR_CONN_STATE_HANDSHAKING 1 /* SSL is handshaking, not done yet */ #define OR_CONN_STATE_OPEN 2 /* ready to send/receive cells. */ #endif #define EXIT_CONN_STATE_RESOLVING 0 /* waiting for response from dns farm */ #define EXIT_CONN_STATE_CONNECTING 1 /* waiting for connect() to finish */ Loading Loading @@ -272,73 +278,72 @@ typedef struct { struct connection_t { /* Used by all types: */ uint8_t type; int state; uint8_t wants_to_read; uint8_t state; uint8_t wants_to_read; /* should we start reading again once * the bandwidth throttler allows it? */ int s; /* our socket */ int poll_index; int marked_for_close; int poll_index; /* index of this conn into the poll_array */ int marked_for_close; /* should we close this conn on the next * iteration of the main loop? */ char *inbuf; int inbuflen; int inbuf_datalen; int inbuf_reached_eof; long timestamp_lastread; int inbuflen; /* how many bytes are alloc'ed for inbuf? */ int inbuf_datalen; /* how many bytes of data are on inbuf? */ int inbuf_reached_eof; /* did read() return 0 on this conn? */ long timestamp_lastread; /* when was the last time poll() said we could read? */ char *outbuf; int outbuflen; /* how many bytes are allocated for the outbuf? */ int outbuf_flushlen; /* how much data should we try to flush from the outbuf? */ int outbuf_datalen; /* how much data is there total on the outbuf? */ long timestamp_lastwritten; long timestamp_created; long timestamp_lastwritten; /* when was the last time poll() said we could write? */ /* used by OR and OP: */ long timestamp_created; /* when was this connection_t created? */ uint32_t bandwidth; /* connection bandwidth */ uint32_t bandwidth; /* connection bandwidth. Set to -1 for non-OR conns. */ int receiver_bucket; /* when this hits 0, stop receiving. Every second we * add 'bandwidth' to this, capping it at 10*bandwidth. * Set to -1 for non-OR conns. */ struct timeval send_timeval; /* for determining when to send the next cell */ uint32_t addr; /* these two uniquely identify a router. Both in host order. */ uint16_t port; /* if non-zero, they identify the guy on the other end * of the connection. */ char *address; /* FQDN (or IP) of the guy on the other end. * strdup into this, because free_connection frees it */ crypto_pk_env_t *pkey; /* public RSA key for the other side */ #ifndef TOR_TLS /* Used only by OR connections: */ /* link encryption */ crypto_cipher_env_t *f_crypto; crypto_cipher_env_t *b_crypto; // struct timeval lastsend; /* time of last transmission to the client */ // struct timeval interval; /* transmission interval */ uint32_t addr; /* these two uniquely identify a router. Both in host order. */ uint16_t port; char nonce[8]; #endif /* used by exit and ap: */ /* Used only by edge connections: */ char stream_id[STREAM_ID_SIZE]; struct connection_t *next_stream; struct connection_t *next_stream; /* points to the next stream at this edge, if any */ struct crypt_path_t *cpath_layer; /* a pointer to which node in the circ this conn exits at */ int package_window; int deliver_window; int done_sending; int done_receiving; int package_window; /* how many more relay cells can i send into the circuit? */ int deliver_window; /* how many more relay cells can end at me? */ /* Used by ap: */ char socks_version; char read_username; int done_sending; /* for half-open connections; not used currently */ int done_receiving; /* Used by exit and ap: */ char *dest_addr; /* Used only by AP connections: */ char socks_version; /* what socks version are they speaking at me? */ char read_username; /* have i read the username yet? */ char *dest_addr; /* what address and port are this stream's destination? */ uint16_t dest_port; /* host order */ /* Used by everyone */ char *address; /* strdup into this, because free_connection frees it */ /* Used for cell connections */ crypto_pk_env_t *pkey; /* public RSA key for the other side */ /* Used while negotiating OR/OR connections */ char nonce[8]; /* Used by worker connections */ /* Used only by worker connections: */ int num_processed; /* statistics kept by dns worker */ struct circuit_t *circ; /* by cpu worker to know who he's working for */ }; Loading Loading @@ -392,7 +397,7 @@ struct crypt_path_t { uint32_t addr; uint16_t port; char state; uint8_t state; #define CPATH_STATE_CLOSED 0 #define CPATH_STATE_AWAITING_KEYS 1 #define CPATH_STATE_OPEN 2 Loading Loading @@ -429,9 +434,9 @@ struct circuit_t { char onionskin[DH_ONIONSKIN_LEN]; /* for storage while onionskin pending */ long timestamp_created; char dirty; /* whether this circuit has been used yet */ uint8_t dirty; /* whether this circuit has been used yet */ int state; uint8_t state; // unsigned char *onion; /* stores the onion when state is CONN_STATE_OPEN_WAIT */ // uint32_t onionlen; /* total onion length */ Loading Loading @@ -612,6 +617,7 @@ int connection_handle_listener_read(connection_t *conn, int new_type, int new_st /* start all connections that should be up but aren't */ int retry_all_connections(uint16_t or_listenport, uint16_t ap_listenport, uint16_t dir_listenport); int connection_handle_read(connection_t *conn); int connection_read_to_buf(connection_t *conn); int connection_fetch_from_buf(char *string, int len, connection_t *conn); Loading @@ -620,6 +626,7 @@ int connection_outbuf_too_full(connection_t *conn); int connection_find_on_inbuf(char *string, int len, connection_t *conn); int connection_wants_to_flush(connection_t *conn); int connection_flush_buf(connection_t *conn); int connection_handle_write(connection_t *conn); int connection_write_to_buf(char *string, int len, connection_t *conn); void connection_send_cell(connection_t *conn); Loading Loading
src/or/connection.c +79 −87 Original line number Diff line number Diff line Loading @@ -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) { Loading @@ -105,6 +106,7 @@ connection_t *connection_new(int type) { return NULL; } } #endif conn->done_sending = conn->done_receiving = 0; return conn; } Loading @@ -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) Loading @@ -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); } Loading Loading @@ -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; Loading Loading @@ -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_write_to_buf(char *string, int len, connection_t *conn) { 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) { if(!len) return 0; Loading @@ -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; Loading Loading @@ -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; Loading
src/or/connection_or.c +7 −4 Original line number Diff line number Diff line Loading @@ -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); Loading @@ -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); /* * Loading @@ -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; } Loading @@ -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: Loading Loading @@ -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 */ Loading Loading @@ -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; Loading @@ -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 Loading
src/or/main.c +31 −115 Original line number Diff line number Diff line Loading @@ -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); if( /* XXX does POLLHUP also mean it's definitely broken? */ #ifdef MS_WINDOWS if (poll_array[i].revents & POLLERR) { retval = -1; goto error; } #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; } } } #ifdef MS_WINDOWS error: (poll_array[i].revents & POLLERR) || #endif if(retval < 0) { /* this connection is broken. remove it */ 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(i<nfds) { /* we just replaced the one at i with a new one. process it too. */ if(poll_array[i].revents & (POLLIN|POLLHUP|POLLERR)) /* something to read */ if(i<nfds) { /* we just replaced the one at i with a new one. process it too. */ conn_read(i); } } } static void conn_write(int i) { int retval; connection_t *conn; if(!(poll_array[i].revents & POLLOUT)) return; /* this conn doesn't want to write */ conn = connection_array[i]; //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(i<nfds) { /* we just replaced the one at i with a new one. process it too. */ if(poll_array[i].revents & POLLOUT) /* something to write */ if(i<nfds) { /* we just replaced the one at i with a new one. process it too. */ conn_write(i); } } Loading @@ -346,7 +310,7 @@ static void check_conn_marked(int i) { } } static int prepare_for_poll(int *timeout) { static int prepare_for_poll(void) { int i; // connection_t *conn = NULL; connection_t *tmpconn; Loading Loading @@ -434,45 +398,9 @@ static int prepare_for_poll(int *timeout) { current_second = now.tv_sec; /* remember which second it is, for next time */ } *timeout = 1000 - (now.tv_usec / 1000); /* how many milliseconds til the next second? */ return 0; return (1000 - (now.tv_usec / 1000)); /* how many milliseconds til the next second? */ } /* Link padding stuff left here for fun. Not used now. */ #if 0 if(options.LinkPadding) { /* now check which conn wants to speak soonest */ for(i=0;i<nfds;i++) { tmpconn = connection_array[i]; if(!connection_speaks_cells(tmpconn)) continue; /* this conn type doesn't send cells */ if(!connection_state_is_open(tmpconn)) continue; /* only conns in state 'open' have a valid send_timeval */ while(tv_cmp(&tmpconn->send_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; Loading Loading @@ -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, Loading @@ -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 */ Loading @@ -567,15 +488,10 @@ 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<nfds;i++) if(poll_array[i].revents & (POLLIN|POLLHUP|POLLERR)) /* something to read, or an error. */ conn_read(i); /* this also blows away broken connections */ /* see http://www.greenend.org.uk/rjk/2001/06/poll.html for discussion * of POLLIN vs POLLHUP */ /* then do the writes */ for(i=0;i<nfds;i++) if(poll_array[i].revents & POLLOUT) /* something to write */ conn_write(i); /* any of the conns need to be closed now? */ Loading
src/or/or.h +52 −45 Original line number Diff line number Diff line Loading @@ -94,7 +94,7 @@ #include "../common/log.h" #include "../common/util.h" #define RECOMMENDED_SOFTWARE_VERSIONS "0.0.2pre6,0.0.2pre7" #define RECOMMENDED_SOFTWARE_VERSIONS "0.0.2pre8" #define MAXCONNECTIONS 1000 /* upper bound on max connections. can be lowered by config file */ Loading Loading @@ -131,6 +131,7 @@ #define CPUWORKER_TASK_ONION CPUWORKER_STATE_BUSY_ONION #define CPUWORKER_TASK_HANDSHAKE CPUWORKER_STATE_BUSY_HANDSHAKE #ifndef TOR_TLS /* how to read these states: * foo_CONN_STATE_bar_baz: * "I am acting as a bar, currently in stage baz of talking with a foo." Loading @@ -145,6 +146,11 @@ #define OR_CONN_STATE_SERVER_SENDING_AUTH 7 /* writing auth and nonce */ #define OR_CONN_STATE_SERVER_NONCE_WAIT 8 /* waiting for confirmation of nonce */ #define OR_CONN_STATE_OPEN 9 /* ready to send/receive cells. */ #else #define OR_CONN_STATE_CONNECTING 0 /* waiting for connect() to finish */ #define OR_CONN_STATE_HANDSHAKING 1 /* SSL is handshaking, not done yet */ #define OR_CONN_STATE_OPEN 2 /* ready to send/receive cells. */ #endif #define EXIT_CONN_STATE_RESOLVING 0 /* waiting for response from dns farm */ #define EXIT_CONN_STATE_CONNECTING 1 /* waiting for connect() to finish */ Loading Loading @@ -272,73 +278,72 @@ typedef struct { struct connection_t { /* Used by all types: */ uint8_t type; int state; uint8_t wants_to_read; uint8_t state; uint8_t wants_to_read; /* should we start reading again once * the bandwidth throttler allows it? */ int s; /* our socket */ int poll_index; int marked_for_close; int poll_index; /* index of this conn into the poll_array */ int marked_for_close; /* should we close this conn on the next * iteration of the main loop? */ char *inbuf; int inbuflen; int inbuf_datalen; int inbuf_reached_eof; long timestamp_lastread; int inbuflen; /* how many bytes are alloc'ed for inbuf? */ int inbuf_datalen; /* how many bytes of data are on inbuf? */ int inbuf_reached_eof; /* did read() return 0 on this conn? */ long timestamp_lastread; /* when was the last time poll() said we could read? */ char *outbuf; int outbuflen; /* how many bytes are allocated for the outbuf? */ int outbuf_flushlen; /* how much data should we try to flush from the outbuf? */ int outbuf_datalen; /* how much data is there total on the outbuf? */ long timestamp_lastwritten; long timestamp_created; long timestamp_lastwritten; /* when was the last time poll() said we could write? */ /* used by OR and OP: */ long timestamp_created; /* when was this connection_t created? */ uint32_t bandwidth; /* connection bandwidth */ uint32_t bandwidth; /* connection bandwidth. Set to -1 for non-OR conns. */ int receiver_bucket; /* when this hits 0, stop receiving. Every second we * add 'bandwidth' to this, capping it at 10*bandwidth. * Set to -1 for non-OR conns. */ struct timeval send_timeval; /* for determining when to send the next cell */ uint32_t addr; /* these two uniquely identify a router. Both in host order. */ uint16_t port; /* if non-zero, they identify the guy on the other end * of the connection. */ char *address; /* FQDN (or IP) of the guy on the other end. * strdup into this, because free_connection frees it */ crypto_pk_env_t *pkey; /* public RSA key for the other side */ #ifndef TOR_TLS /* Used only by OR connections: */ /* link encryption */ crypto_cipher_env_t *f_crypto; crypto_cipher_env_t *b_crypto; // struct timeval lastsend; /* time of last transmission to the client */ // struct timeval interval; /* transmission interval */ uint32_t addr; /* these two uniquely identify a router. Both in host order. */ uint16_t port; char nonce[8]; #endif /* used by exit and ap: */ /* Used only by edge connections: */ char stream_id[STREAM_ID_SIZE]; struct connection_t *next_stream; struct connection_t *next_stream; /* points to the next stream at this edge, if any */ struct crypt_path_t *cpath_layer; /* a pointer to which node in the circ this conn exits at */ int package_window; int deliver_window; int done_sending; int done_receiving; int package_window; /* how many more relay cells can i send into the circuit? */ int deliver_window; /* how many more relay cells can end at me? */ /* Used by ap: */ char socks_version; char read_username; int done_sending; /* for half-open connections; not used currently */ int done_receiving; /* Used by exit and ap: */ char *dest_addr; /* Used only by AP connections: */ char socks_version; /* what socks version are they speaking at me? */ char read_username; /* have i read the username yet? */ char *dest_addr; /* what address and port are this stream's destination? */ uint16_t dest_port; /* host order */ /* Used by everyone */ char *address; /* strdup into this, because free_connection frees it */ /* Used for cell connections */ crypto_pk_env_t *pkey; /* public RSA key for the other side */ /* Used while negotiating OR/OR connections */ char nonce[8]; /* Used by worker connections */ /* Used only by worker connections: */ int num_processed; /* statistics kept by dns worker */ struct circuit_t *circ; /* by cpu worker to know who he's working for */ }; Loading Loading @@ -392,7 +397,7 @@ struct crypt_path_t { uint32_t addr; uint16_t port; char state; uint8_t state; #define CPATH_STATE_CLOSED 0 #define CPATH_STATE_AWAITING_KEYS 1 #define CPATH_STATE_OPEN 2 Loading Loading @@ -429,9 +434,9 @@ struct circuit_t { char onionskin[DH_ONIONSKIN_LEN]; /* for storage while onionskin pending */ long timestamp_created; char dirty; /* whether this circuit has been used yet */ uint8_t dirty; /* whether this circuit has been used yet */ int state; uint8_t state; // unsigned char *onion; /* stores the onion when state is CONN_STATE_OPEN_WAIT */ // uint32_t onionlen; /* total onion length */ Loading Loading @@ -612,6 +617,7 @@ int connection_handle_listener_read(connection_t *conn, int new_type, int new_st /* start all connections that should be up but aren't */ int retry_all_connections(uint16_t or_listenport, uint16_t ap_listenport, uint16_t dir_listenport); int connection_handle_read(connection_t *conn); int connection_read_to_buf(connection_t *conn); int connection_fetch_from_buf(char *string, int len, connection_t *conn); Loading @@ -620,6 +626,7 @@ int connection_outbuf_too_full(connection_t *conn); int connection_find_on_inbuf(char *string, int len, connection_t *conn); int connection_wants_to_flush(connection_t *conn); int connection_flush_buf(connection_t *conn); int connection_handle_write(connection_t *conn); int connection_write_to_buf(char *string, int len, connection_t *conn); void connection_send_cell(connection_t *conn); Loading