mirror of
https://gitlab.torproject.org/tpo/core/tor.git
synced 2024-09-21 13:34:59 +02:00
general cleanup and reabstraction, to prepare for tls
svn:r426
This commit is contained in:
parent
99d1e4931b
commit
7a34cdf5ee
@ -92,6 +92,7 @@ connection_t *connection_new(int type) {
|
|||||||
conn->timestamp_lastread = now.tv_sec;
|
conn->timestamp_lastread = now.tv_sec;
|
||||||
conn->timestamp_lastwritten = now.tv_sec;
|
conn->timestamp_lastwritten = now.tv_sec;
|
||||||
|
|
||||||
|
#ifndef TOR_TLS
|
||||||
if (connection_speaks_cells(conn)) {
|
if (connection_speaks_cells(conn)) {
|
||||||
conn->f_crypto = crypto_new_cipher_env(CONNECTION_CIPHER);
|
conn->f_crypto = crypto_new_cipher_env(CONNECTION_CIPHER);
|
||||||
if (!conn->f_crypto) {
|
if (!conn->f_crypto) {
|
||||||
@ -105,6 +106,7 @@ connection_t *connection_new(int type) {
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
conn->done_sending = conn->done_receiving = 0;
|
conn->done_sending = conn->done_receiving = 0;
|
||||||
return conn;
|
return conn;
|
||||||
}
|
}
|
||||||
@ -120,10 +122,16 @@ void connection_free(connection_t *conn) {
|
|||||||
free(conn->dest_addr);
|
free(conn->dest_addr);
|
||||||
|
|
||||||
if(connection_speaks_cells(conn)) {
|
if(connection_speaks_cells(conn)) {
|
||||||
|
directory_set_dirty();
|
||||||
|
#ifdef TOR_TLS
|
||||||
|
if (conn->SSL)
|
||||||
|
crypt_SSL_free(conn->SSL);
|
||||||
|
#else
|
||||||
if (conn->f_crypto)
|
if (conn->f_crypto)
|
||||||
crypto_free_cipher_env(conn->f_crypto);
|
crypto_free_cipher_env(conn->f_crypto);
|
||||||
if (conn->b_crypto)
|
if (conn->b_crypto)
|
||||||
crypto_free_cipher_env(conn->b_crypto);
|
crypto_free_cipher_env(conn->b_crypto);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
if (conn->pkey)
|
if (conn->pkey)
|
||||||
@ -133,9 +141,6 @@ void connection_free(connection_t *conn) {
|
|||||||
log_fn(LOG_INFO,"closing fd %d.",conn->s);
|
log_fn(LOG_INFO,"closing fd %d.",conn->s);
|
||||||
close(conn->s);
|
close(conn->s);
|
||||||
}
|
}
|
||||||
if(conn->type == CONN_TYPE_OR) {
|
|
||||||
directory_set_dirty();
|
|
||||||
}
|
|
||||||
free(conn);
|
free(conn);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -279,22 +284,52 @@ int retry_all_connections(uint16_t or_listenport, uint16_t ap_listenport, uint16
|
|||||||
return 0;
|
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 connection_read_to_buf(connection_t *conn) {
|
||||||
int read_result;
|
int read_result;
|
||||||
struct timeval now;
|
|
||||||
int at_most = global_read_bucket;
|
int at_most = global_read_bucket;
|
||||||
|
|
||||||
if(connection_speaks_cells(conn)) {
|
if(connection_speaks_cells(conn)) {
|
||||||
assert(conn->receiver_bucket >= 0);
|
assert(conn->receiver_bucket >= 0);
|
||||||
}
|
} else {
|
||||||
if(!connection_speaks_cells(conn)) {
|
|
||||||
assert(conn->receiver_bucket < 0);
|
assert(conn->receiver_bucket < 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
my_gettimeofday(&now);
|
|
||||||
|
|
||||||
conn->timestamp_lastread = now.tv_sec;
|
|
||||||
|
|
||||||
if(conn->receiver_bucket >= 0 && at_most > conn->receiver_bucket)
|
if(conn->receiver_bucket >= 0 && at_most > conn->receiver_bucket)
|
||||||
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) {
|
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) {
|
int connection_write_to_buf(char *string, int len, connection_t *conn) {
|
||||||
struct timeval now;
|
|
||||||
|
|
||||||
my_gettimeofday(&now);
|
|
||||||
|
|
||||||
if(!len)
|
if(!len)
|
||||||
return 0;
|
return 0;
|
||||||
@ -352,12 +418,10 @@ int connection_write_to_buf(char *string, int len, connection_t *conn) {
|
|||||||
if(conn->marked_for_close)
|
if(conn->marked_for_close)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
conn->timestamp_lastwritten = now.tv_sec;
|
|
||||||
|
|
||||||
if( (!connection_speaks_cells(conn)) ||
|
if( (!connection_speaks_cells(conn)) ||
|
||||||
(!connection_state_is_open(conn)) ||
|
(!connection_state_is_open(conn)) ||
|
||||||
(options.LinkPadding == 0) ) {
|
(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 */
|
/* also flush immediately if we're not doing LinkPadding, since otherwise it will never flush */
|
||||||
connection_start_writing(conn);
|
connection_start_writing(conn);
|
||||||
conn->outbuf_flushlen += len;
|
conn->outbuf_flushlen += len;
|
||||||
@ -397,78 +461,6 @@ int connection_state_is_open(connection_t *conn) {
|
|||||||
return 0;
|
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) {
|
int connection_send_destroy(aci_t aci, connection_t *conn) {
|
||||||
cell_t cell;
|
cell_t cell;
|
||||||
|
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
|
|
||||||
extern or_options_t options; /* command-line and config-file options */
|
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_send_keys(connection_t *conn);
|
||||||
static int or_handshake_op_finished_sending_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_auth(connection_t *conn);
|
||||||
static int or_handshake_server_process_nonce(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);
|
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);
|
assert(conn && conn->type == CONN_TYPE_OR);
|
||||||
|
|
||||||
if(conn->inbuf_reached_eof) {
|
if(conn->inbuf_reached_eof) {
|
||||||
/* eof reached, kill it. */
|
|
||||||
log_fn(LOG_DEBUG,"conn reached eof. Closing.");
|
log_fn(LOG_DEBUG,"conn reached eof. Closing.");
|
||||||
return -1;
|
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);
|
// log(LOG_DEBUG,"connection_or_process_inbuf(): state %d.",conn->state);
|
||||||
|
|
||||||
switch(conn->state) {
|
switch(conn->state) {
|
||||||
|
#ifndef TOR_TLS
|
||||||
case OR_CONN_STATE_CLIENT_AUTH_WAIT:
|
case OR_CONN_STATE_CLIENT_AUTH_WAIT:
|
||||||
return or_handshake_client_process_auth(conn);
|
return or_handshake_client_process_auth(conn);
|
||||||
case OR_CONN_STATE_SERVER_AUTH_WAIT:
|
case OR_CONN_STATE_SERVER_AUTH_WAIT:
|
||||||
return or_handshake_server_process_auth(conn);
|
return or_handshake_server_process_auth(conn);
|
||||||
case OR_CONN_STATE_SERVER_NONCE_WAIT:
|
case OR_CONN_STATE_SERVER_NONCE_WAIT:
|
||||||
return or_handshake_server_process_nonce(conn);
|
return or_handshake_server_process_nonce(conn);
|
||||||
|
#endif
|
||||||
case OR_CONN_STATE_OPEN:
|
case OR_CONN_STATE_OPEN:
|
||||||
return connection_process_cell_from_inbuf(conn);
|
return connection_process_cell_from_inbuf(conn);
|
||||||
default:
|
default:
|
||||||
@ -583,7 +586,6 @@ or_handshake_server_process_auth(connection_t *conn) {
|
|||||||
crypto_cipher_decrypt_init_cipher(conn->f_crypto);
|
crypto_cipher_decrypt_init_cipher(conn->f_crypto);
|
||||||
|
|
||||||
conn->state = OR_CONN_STATE_OPEN;
|
conn->state = OR_CONN_STATE_OPEN;
|
||||||
connection_init_timeval(conn);
|
|
||||||
connection_watch_events(conn, POLLIN);
|
connection_watch_events(conn, POLLIN);
|
||||||
|
|
||||||
return connection_process_inbuf(conn); /* in case they sent some cells along with the keys */
|
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) {
|
connection_or_set_open(connection_t *conn) {
|
||||||
conn->state = OR_CONN_STATE_OPEN;
|
conn->state = OR_CONN_STATE_OPEN;
|
||||||
directory_set_dirty();
|
directory_set_dirty();
|
||||||
connection_init_timeval(conn);
|
|
||||||
connection_watch_events(conn, POLLIN);
|
connection_watch_events(conn, POLLIN);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef TOR_TLS
|
||||||
static void
|
static void
|
||||||
conn_or_init_crypto(connection_t *conn) {
|
conn_or_init_crypto(connection_t *conn) {
|
||||||
//int x;
|
//int x;
|
||||||
@ -673,6 +675,7 @@ conn_or_init_crypto(connection_t *conn) {
|
|||||||
crypto_cipher_decrypt_init_cipher(conn->b_crypto);
|
crypto_cipher_decrypt_init_cipher(conn->b_crypto);
|
||||||
/* always encrypt with f, always decrypt with b */
|
/* always encrypt with f, always decrypt with b */
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
146
src/or/main.c
146
src/or/main.c
@ -244,83 +244,47 @@ void connection_start_writing(connection_t *conn) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void conn_read(int i) {
|
static void conn_read(int i) {
|
||||||
int retval;
|
|
||||||
connection_t *conn;
|
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];
|
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
|
#ifdef MS_WINDOWS
|
||||||
if (poll_array[i].revents & POLLERR) {
|
(poll_array[i].revents & POLLERR) ||
|
||||||
retval = -1;
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
connection_handle_read(conn) < 0)
|
||||||
if (conn->type == CONN_TYPE_OR_LISTENER) {
|
{
|
||||||
retval = connection_or_handle_listener_read(conn);
|
/* this connection is broken. remove it */
|
||||||
} else if (conn->type == CONN_TYPE_AP_LISTENER) {
|
log_fn(LOG_INFO,"%s connection broken, removing.", conn_type_to_string[conn->type]);
|
||||||
retval = connection_ap_handle_listener_read(conn);
|
connection_remove(conn);
|
||||||
} else if (conn->type == CONN_TYPE_DIR_LISTENER) {
|
connection_free(conn);
|
||||||
retval = connection_dir_handle_listener_read(conn);
|
if(i<nfds) { /* we just replaced the one at i with a new one. process it too. */
|
||||||
} else {
|
conn_read(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); /* 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:
|
|
||||||
#endif
|
|
||||||
if(retval < 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 */
|
|
||||||
conn_read(i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void conn_write(int i) {
|
static void conn_write(int i) {
|
||||||
int retval;
|
|
||||||
connection_t *conn;
|
connection_t *conn;
|
||||||
|
|
||||||
|
if(!(poll_array[i].revents & POLLOUT))
|
||||||
|
return; /* this conn doesn't want to write */
|
||||||
|
|
||||||
conn = connection_array[i];
|
conn = connection_array[i];
|
||||||
// log_fn(LOG_DEBUG,"socket %d wants to write.",conn->s);
|
//log_fn(LOG_DEBUG,"socket %d wants to write.",conn->s);
|
||||||
|
|
||||||
if(connection_is_listener(conn)) {
|
if(connection_handle_write(conn) < 0) { /* this connection is broken. remove it. */
|
||||||
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. */
|
|
||||||
log_fn(LOG_DEBUG,"%s connection broken, removing.", conn_type_to_string[conn->type]);
|
log_fn(LOG_DEBUG,"%s connection broken, removing.", conn_type_to_string[conn->type]);
|
||||||
connection_remove(conn);
|
connection_remove(conn);
|
||||||
connection_free(conn);
|
connection_free(conn);
|
||||||
if(i<nfds) { /* we just replaced the one at i with a new one.
|
if(i<nfds) { /* we just replaced the one at i with a new one. process it too. */
|
||||||
process it too. */
|
|
||||||
if(poll_array[i].revents & POLLOUT) /* something to write */
|
|
||||||
conn_write(i);
|
conn_write(i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -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;
|
int i;
|
||||||
// connection_t *conn = NULL;
|
// connection_t *conn = NULL;
|
||||||
connection_t *tmpconn;
|
connection_t *tmpconn;
|
||||||
@ -434,45 +398,9 @@ static int prepare_for_poll(int *timeout) {
|
|||||||
current_second = now.tv_sec; /* remember which second it is, for next time */
|
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 (1000 - (now.tv_usec / 1000)); /* how many milliseconds til the next second? */
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* 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) {
|
static int do_main_loop(void) {
|
||||||
int i;
|
int i;
|
||||||
int timeout;
|
int timeout;
|
||||||
@ -516,7 +444,7 @@ static int do_main_loop(void) {
|
|||||||
|
|
||||||
/* start up the necessary connections based on which ports are
|
/* start up the necessary connections based on which ports are
|
||||||
* non-zero. This is where we try to connect to all the other ORs,
|
* 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,
|
retry_all_connections((uint16_t) options.ORPort,
|
||||||
(uint16_t) options.APPort,
|
(uint16_t) options.APPort,
|
||||||
@ -543,17 +471,10 @@ static int do_main_loop(void) {
|
|||||||
please_reap_children = 0;
|
please_reap_children = 0;
|
||||||
}
|
}
|
||||||
#endif /* signal stuff */
|
#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);
|
poll_result = poll(poll_array, nfds, timeout);
|
||||||
|
|
||||||
#if 0 /* let catch() handle things like ^c, and otherwise don't worry about it */
|
#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 */
|
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 */
|
/* do all the reads and errors first, so we can detect closed sockets */
|
||||||
for(i=0;i<nfds;i++)
|
for(i=0;i<nfds;i++)
|
||||||
if(poll_array[i].revents & (POLLIN|POLLHUP|POLLERR))
|
conn_read(i); /* this also blows away broken connections */
|
||||||
/* 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 */
|
/* then do the writes */
|
||||||
for(i=0;i<nfds;i++)
|
for(i=0;i<nfds;i++)
|
||||||
if(poll_array[i].revents & POLLOUT) /* something to write */
|
conn_write(i);
|
||||||
conn_write(i);
|
|
||||||
|
|
||||||
/* any of the conns need to be closed now? */
|
/* any of the conns need to be closed now? */
|
||||||
for(i=0;i<nfds;i++)
|
for(i=0;i<nfds;i++)
|
||||||
|
97
src/or/or.h
97
src/or/or.h
@ -94,7 +94,7 @@
|
|||||||
#include "../common/log.h"
|
#include "../common/log.h"
|
||||||
#include "../common/util.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.
|
#define MAXCONNECTIONS 1000 /* upper bound on max connections.
|
||||||
can be lowered by config file */
|
can be lowered by config file */
|
||||||
@ -131,6 +131,7 @@
|
|||||||
#define CPUWORKER_TASK_ONION CPUWORKER_STATE_BUSY_ONION
|
#define CPUWORKER_TASK_ONION CPUWORKER_STATE_BUSY_ONION
|
||||||
#define CPUWORKER_TASK_HANDSHAKE CPUWORKER_STATE_BUSY_HANDSHAKE
|
#define CPUWORKER_TASK_HANDSHAKE CPUWORKER_STATE_BUSY_HANDSHAKE
|
||||||
|
|
||||||
|
#ifndef TOR_TLS
|
||||||
/* how to read these states:
|
/* how to read these states:
|
||||||
* foo_CONN_STATE_bar_baz:
|
* foo_CONN_STATE_bar_baz:
|
||||||
* "I am acting as a bar, currently in stage baz of talking with a foo."
|
* "I am acting as a bar, currently in stage baz of talking with a foo."
|
||||||
@ -145,6 +146,11 @@
|
|||||||
#define OR_CONN_STATE_SERVER_SENDING_AUTH 7 /* writing auth and nonce */
|
#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_SERVER_NONCE_WAIT 8 /* waiting for confirmation of nonce */
|
||||||
#define OR_CONN_STATE_OPEN 9 /* ready to send/receive cells. */
|
#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_RESOLVING 0 /* waiting for response from dns farm */
|
||||||
#define EXIT_CONN_STATE_CONNECTING 1 /* waiting for connect() to finish */
|
#define EXIT_CONN_STATE_CONNECTING 1 /* waiting for connect() to finish */
|
||||||
@ -272,73 +278,72 @@ typedef struct {
|
|||||||
|
|
||||||
struct connection_t {
|
struct connection_t {
|
||||||
|
|
||||||
/* Used by all types: */
|
|
||||||
|
|
||||||
uint8_t type;
|
uint8_t type;
|
||||||
int state;
|
uint8_t state;
|
||||||
uint8_t wants_to_read;
|
uint8_t wants_to_read; /* should we start reading again once
|
||||||
|
* the bandwidth throttler allows it?
|
||||||
|
*/
|
||||||
int s; /* our socket */
|
int s; /* our socket */
|
||||||
int poll_index;
|
int poll_index; /* index of this conn into the poll_array */
|
||||||
int marked_for_close;
|
int marked_for_close; /* should we close this conn on the next
|
||||||
|
* iteration of the main loop?
|
||||||
|
*/
|
||||||
|
|
||||||
char *inbuf;
|
char *inbuf;
|
||||||
int inbuflen;
|
int inbuflen; /* how many bytes are alloc'ed for inbuf? */
|
||||||
int inbuf_datalen;
|
int inbuf_datalen; /* how many bytes of data are on inbuf? */
|
||||||
int inbuf_reached_eof;
|
int inbuf_reached_eof; /* did read() return 0 on this conn? */
|
||||||
long timestamp_lastread;
|
long timestamp_lastread; /* when was the last time poll() said we could read? */
|
||||||
|
|
||||||
char *outbuf;
|
char *outbuf;
|
||||||
int outbuflen; /* how many bytes are allocated for the 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_flushlen; /* how much data should we try to flush from the outbuf? */
|
||||||
int outbuf_datalen; /* how much data is there total on the outbuf? */
|
int outbuf_datalen; /* how much data is there total on the outbuf? */
|
||||||
long timestamp_lastwritten;
|
long timestamp_lastwritten; /* when was the last time poll() said we could write? */
|
||||||
|
|
||||||
long timestamp_created;
|
long timestamp_created; /* when was this connection_t created? */
|
||||||
|
|
||||||
/* used by OR and OP: */
|
uint32_t bandwidth; /* connection bandwidth. Set to -1 for non-OR conns. */
|
||||||
|
|
||||||
uint32_t bandwidth; /* connection bandwidth */
|
|
||||||
int receiver_bucket; /* when this hits 0, stop receiving. Every second we
|
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.
|
||||||
|
* 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 */
|
/* link encryption */
|
||||||
crypto_cipher_env_t *f_crypto;
|
crypto_cipher_env_t *f_crypto;
|
||||||
crypto_cipher_env_t *b_crypto;
|
crypto_cipher_env_t *b_crypto;
|
||||||
|
|
||||||
// struct timeval lastsend; /* time of last transmission to the client */
|
char nonce[8];
|
||||||
// struct timeval interval; /* transmission interval */
|
#endif
|
||||||
|
|
||||||
uint32_t addr; /* these two uniquely identify a router. Both in host order. */
|
/* Used only by edge connections: */
|
||||||
uint16_t port;
|
|
||||||
|
|
||||||
/* used by exit and ap: */
|
|
||||||
char stream_id[STREAM_ID_SIZE];
|
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 */
|
struct crypt_path_t *cpath_layer; /* a pointer to which node in the circ this conn exits at */
|
||||||
int package_window;
|
int package_window; /* how many more relay cells can i send into the circuit? */
|
||||||
int deliver_window;
|
int deliver_window; /* how many more relay cells can end at me? */
|
||||||
int done_sending;
|
|
||||||
|
int done_sending; /* for half-open connections; not used currently */
|
||||||
int done_receiving;
|
int done_receiving;
|
||||||
|
|
||||||
/* Used by ap: */
|
/* Used only by AP connections: */
|
||||||
char socks_version;
|
char socks_version; /* what socks version are they speaking at me? */
|
||||||
char read_username;
|
char read_username; /* have i read the username yet? */
|
||||||
|
char *dest_addr; /* what address and port are this stream's destination? */
|
||||||
/* Used by exit and ap: */
|
|
||||||
char *dest_addr;
|
|
||||||
uint16_t dest_port; /* host order */
|
uint16_t dest_port; /* host order */
|
||||||
|
|
||||||
/* Used by everyone */
|
/* Used only by worker connections: */
|
||||||
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 */
|
|
||||||
int num_processed; /* statistics kept by dns worker */
|
int num_processed; /* statistics kept by dns worker */
|
||||||
struct circuit_t *circ; /* by cpu worker to know who he's working for */
|
struct circuit_t *circ; /* by cpu worker to know who he's working for */
|
||||||
};
|
};
|
||||||
@ -392,7 +397,7 @@ struct crypt_path_t {
|
|||||||
uint32_t addr;
|
uint32_t addr;
|
||||||
uint16_t port;
|
uint16_t port;
|
||||||
|
|
||||||
char state;
|
uint8_t state;
|
||||||
#define CPATH_STATE_CLOSED 0
|
#define CPATH_STATE_CLOSED 0
|
||||||
#define CPATH_STATE_AWAITING_KEYS 1
|
#define CPATH_STATE_AWAITING_KEYS 1
|
||||||
#define CPATH_STATE_OPEN 2
|
#define CPATH_STATE_OPEN 2
|
||||||
@ -429,9 +434,9 @@ struct circuit_t {
|
|||||||
|
|
||||||
char onionskin[DH_ONIONSKIN_LEN]; /* for storage while onionskin pending */
|
char onionskin[DH_ONIONSKIN_LEN]; /* for storage while onionskin pending */
|
||||||
long timestamp_created;
|
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 */
|
// unsigned char *onion; /* stores the onion when state is CONN_STATE_OPEN_WAIT */
|
||||||
// uint32_t onionlen; /* total onion length */
|
// uint32_t onionlen; /* total onion length */
|
||||||
@ -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 */
|
/* 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 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_read_to_buf(connection_t *conn);
|
||||||
|
|
||||||
int connection_fetch_from_buf(char *string, int len, connection_t *conn);
|
int connection_fetch_from_buf(char *string, int len, connection_t *conn);
|
||||||
@ -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_find_on_inbuf(char *string, int len, connection_t *conn);
|
||||||
int connection_wants_to_flush(connection_t *conn);
|
int connection_wants_to_flush(connection_t *conn);
|
||||||
int connection_flush_buf(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);
|
int connection_write_to_buf(char *string, int len, connection_t *conn);
|
||||||
void connection_send_cell(connection_t *conn);
|
void connection_send_cell(connection_t *conn);
|
||||||
|
Loading…
Reference in New Issue
Block a user