[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [or-cvs] introduced a periodic keepalive padding cell
- To: or-dev@freehaven.net
- Subject: Re: [or-cvs] introduced a periodic keepalive padding cell
- From: Roger Dingledine <arma@mit.edu>
- Date: Tue, 1 Oct 2002 19:58:35 -0400
- Delivered-To: archiver@seul.org
- Delivered-To: or-dev-outgoing@seul.org
- Delivered-To: or-dev@seul.org
- Delivery-Date: Tue, 01 Oct 2002 19:58:36 -0400
- In-Reply-To: <20021001233733.7D1CB15E722@moria.seul.org>; from arma@seul.org on Tue, Oct 01, 2002 at 07:37:33PM -0400
- References: <20021001233733.7D1CB15E722@moria.seul.org>
- Reply-To: or-dev@freehaven.net
- Sender: owner-or-dev@freehaven.net
- User-Agent: Mutt/1.2.5.1i
People living behind fascist firewalls (like Peter) will enjoy this patch,
I hope. Let me know if the default keepalive frequency (every 300 seconds)
is sufficient.
If we're only an onion proxy and the connection has no active circuits
it is expired; else we send a padding cell.
--Roger
On Tue, Oct 01, 2002 at 07:37:33PM -0400, Roger Dingledine wrote:
> Update of /home/or/cvsroot/src/or
> In directory moria.seul.org:/home/arma/work/onion/cvs/src/or
>
> Modified Files:
> config.c connection.c main.c or.h
> Log Message:
> introduced a periodic keepalive padding cell
>
> now tor can be run safely inside nat'ed areas that kill idle
> connections; and the proxy can handle when you suspend your laptop
> and then emerge hours later from a new domain.
>
>
>
> Index: config.c
> ===================================================================
> RCS file: /home/or/cvsroot/src/or/config.c,v
> retrieving revision 1.18
> retrieving revision 1.19
> diff -u -d -r1.18 -r1.19
> --- config.c 28 Sep 2002 00:52:59 -0000 1.18
> +++ config.c 1 Oct 2002 23:37:31 -0000 1.19
> @@ -99,6 +99,8 @@
> 0, "how many seconds between directory rebuilds", "<rebuildperiod>" },
> { "DirFetchPeriod", 'F', POPT_ARG_INT, &options->DirFetchPeriod,
> 0, "how many seconds between directory fetches", "<fetchperiod>" },
> + { "KeepalivePeriod", 'K', POPT_ARG_INT, &options->KeepalivePeriod,
> + 0, "how many seconds between keepalives", "<keepaliveperiod>" },
> // { "ReconnectPeriod", 'e', POPT_ARG_INT, &options->ReconnectPeriod,
> // 0, "how many seconds between retrying all OR connections", "<reconnectperiod>" },
> { "Role", 'R', POPT_ARG_INT, &options->Role,
> @@ -122,6 +124,7 @@
> options->LinkPadding = 0;
> options->DirRebuildPeriod = 600;
> options->DirFetchPeriod = 6000;
> + options->KeepalivePeriod = 300;
> // options->ReconnectPeriod = 6001;
> options->Role = ROLE_OR_LISTEN | ROLE_OR_CONNECT_ALL | ROLE_OP_LISTEN | ROLE_AP_LISTEN;
>
> @@ -170,9 +173,10 @@
> options->MaxConn,
> options->TrafficShaping,
> options->LinkPadding);
> - printf("DirRebuildPeriod=%d, DirFetchPeriod=%d\n",
> + printf("DirRebuildPeriod=%d, DirFetchPeriod=%d KeepalivePeriod=%d\n",
> options->DirRebuildPeriod,
> - options->DirFetchPeriod);
> + options->DirFetchPeriod,
> + options->KeepalivePeriod);
> }
>
> /* Validate options */
> @@ -284,6 +288,12 @@
> if ( options->DirFetchPeriod < 1)
> {
> log(LOG_ERR,"DirFetchPeriod option must be positive.");
> + code = -1;
> + }
> +
> + if ( options->KeepalivePeriod < 1)
> + {
> + log(LOG_ERR,"KeepalivePeriod option must be positive.");
> code = -1;
> }
>
>
> Index: connection.c
> ===================================================================
> RCS file: /home/or/cvsroot/src/or/connection.c,v
> retrieving revision 1.27
> retrieving revision 1.28
> diff -u -d -r1.27 -r1.28
> --- connection.c 28 Sep 2002 05:53:00 -0000 1.27
> +++ connection.c 1 Oct 2002 23:37:31 -0000 1.28
> @@ -86,6 +86,10 @@
>
> connection_t *connection_new(int type) {
> connection_t *conn;
> + struct timeval now;
> +
> + if(gettimeofday(&now,NULL) < 0)
> + return NULL;
>
> conn = (connection_t *)malloc(sizeof(connection_t));
> if(!conn)
> @@ -99,6 +103,7 @@
>
> conn->receiver_bucket = 10240; /* should be enough to do the handshake */
> conn->bandwidth = conn->receiver_bucket / 10; /* give it a default */
> + conn->timestamp_created = now.tv_sec;
>
> if (connection_speaks_cells(conn)) {
> conn->f_crypto = crypto_new_cipher_env(CRYPTO_CIPHER_DES);
> @@ -320,6 +325,7 @@
>
> int connection_read_to_buf(connection_t *conn) {
> int read_result;
> + struct timeval now;
>
> if(connection_speaks_cells(conn)) {
> assert(conn->receiver_bucket >= 0);
> @@ -327,6 +333,11 @@
> if(!connection_speaks_cells(conn)) {
> assert(conn->receiver_bucket < 0);
> }
> +
> + if(gettimeofday(&now,NULL) < 0)
> + return -1;
> + conn->timestamp_lastread = now.tv_sec;
> +
> read_result = read_to_buf(conn->s, conn->receiver_bucket, &conn->inbuf, &conn->inbuflen,
> &conn->inbuf_datalen, &conn->inbuf_reached_eof);
> // log(LOG_DEBUG,"connection_read_to_buf(): read_to_buf returned %d.",read_result);
> @@ -369,8 +380,15 @@
> }
>
> int connection_write_to_buf(char *string, int len, connection_t *conn) {
> + struct timeval now;
> +
> + if(gettimeofday(&now,NULL) < 0)
> + return -1;
> +
> if(!len)
> return 0;
> +
> + conn->timestamp_lastwritten = now.tv_sec;
>
> if( (!connection_speaks_cells(conn)) ||
> (!connection_state_is_open(conn)) ||
>
> Index: main.c
> ===================================================================
> RCS file: /home/or/cvsroot/src/or/main.c,v
> retrieving revision 1.28
> retrieving revision 1.29
> diff -u -d -r1.28 -r1.29
> --- main.c 28 Sep 2002 01:40:11 -0000 1.28
> +++ main.c 1 Oct 2002 23:37:31 -0000 1.29
> @@ -310,20 +310,11 @@
> connection_t *conn = NULL;
> connection_t *tmpconn;
> struct timeval now, soonest;
> - static int current_second = 0; /* from previous calls to gettimeofday */
> - static int time_to_rebuild_directory = 0;
> - static int time_to_fetch_directory = 0;
> + static long current_second = 0; /* from previous calls to gettimeofday */
> + static long time_to_rebuild_directory = 0;
> + static long time_to_fetch_directory = 0;
> int ms_until_conn;
> -
> - *timeout = -1; /* set it to never timeout, possibly overridden below */
> -
> - /* first check if we need to refill buckets */
> - for(i=0;i<nfds;i++) {
> - if(connection_receiver_bucket_should_increase(connection_array[i])) {
> - need_to_refill_buckets = 1;
> - break;
> - }
> - }
> + cell_t cell;
>
> if(gettimeofday(&now,NULL) < 0)
> return -1;
> @@ -356,6 +347,50 @@
> *timeout = 1000*(time_to_fetch_directory - now.tv_sec) + (1000 - (now.tv_usec / 1000));
> }
>
> + /* check connections to see whether we should send a keepalive, expire, or wait */
> + 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' need a keepalive */
> + /* XXX should time-out unfinished connections someday too */
> + }
> + if(now.tv_sec >= tmpconn->timestamp_lastwritten + options.KeepalivePeriod) {
> + if(!(options.Role & ROLE_OR_CONNECT_ALL) && !circuit_get_by_conn(tmpconn)) {
> + /* we're an onion proxy, with no circuits. kill it. */
> + log(LOG_DEBUG,"prepare_for_poll(): Expiring connection to %d (%s:%d).",
> + i,tmpconn->address, tmpconn->port);
> + tmpconn->marked_for_close = 1;
> + } else {
> + /* either a full router, or we've got a circuit. send a padding cell. */
> +// log(LOG_DEBUG,"prepare_for_poll(): Sending keepalive to (%s:%d)",
> +// tmpconn->address, tmpconn->port);
> + memset(&cell,0,sizeof(cell_t));
> + cell.command = CELL_PADDING;
> + connection_write_cell_to_buf(&cell, tmpconn);
> + }
> + }
> + if(!tmpconn->marked_for_close &&
> + *timeout > 1000*(tmpconn->timestamp_lastwritten + options.KeepalivePeriod - now.tv_sec)) {
> + *timeout = 1000*(tmpconn->timestamp_lastwritten + options.KeepalivePeriod - now.tv_sec);
> + }
> + }
> + assert(*timeout >= 0);
> + /* blow away any connections that need to die. can't do this later
> + * because we might open up a circuit and not realize it.
> + */
> + for(i=0;i<nfds;i++)
> + check_conn_marked(i);
> +
> + /* check if we need to refill buckets */
> + for(i=0;i<nfds;i++) {
> + if(connection_receiver_bucket_should_increase(connection_array[i])) {
> + need_to_refill_buckets = 1;
> + break;
> + }
> + }
> +
> if(need_to_refill_buckets) {
> if(now.tv_sec > current_second) { /* the second has already rolled over! */
> // log(LOG_DEBUG,"prepare_for_poll(): The second has rolled over, immediately refilling.");
> @@ -363,7 +398,7 @@
> connection_increment_receiver_bucket(connection_array[i]);
> current_second = now.tv_sec; /* remember which second it is, for next time */
> }
> - /* this timeout is definitely sooner than either of the above two */
> + /* this timeout is definitely sooner than any of the above ones */
> *timeout = 1000 - (now.tv_usec / 1000); /* how many milliseconds til the next second? */
> }
>
> @@ -394,7 +429,7 @@
> 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(*timeout == -1 || ms_until_conn < *timeout) { /* use the new one */
> + 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;
> }
> @@ -517,18 +552,25 @@
> void dumpstats (void) { /* dump stats to stdout */
> int i;
> connection_t *conn;
> + struct timeval now;
> extern char *conn_type_to_string[];
> extern char *conn_state_to_string[][15];
>
> printf("Dumping stats:\n");
> + if(gettimeofday(&now,NULL) < 0)
> + return ;
>
> for(i=0;i<nfds;i++) {
> conn = connection_array[i];
> - printf("Conn %d (socket %d) type %d (%s), state %d (%s)\n",
> + printf("Conn %d (socket %d) type %d (%s), state %d (%s), created %ld secs ago\n",
> i, conn->s, conn->type, conn_type_to_string[conn->type],
> - conn->state, conn_state_to_string[conn->type][conn->state]);
> + conn->state, conn_state_to_string[conn->type][conn->state], now.tv_sec - conn->timestamp_created);
> if(!connection_is_listener(conn)) {
> printf("Conn %d is to '%s:%d'.\n",i,conn->address, conn->port);
> + printf("Conn %d: %d bytes waiting on inbuf (last read %ld secs ago)\n",i,conn->inbuf_datalen,
> + now.tv_sec - conn->timestamp_lastread);
> + printf("Conn %d: %d bytes waiting on outbuf (last written %ld secs ago)\n",i,conn->outbuf_datalen,
> + now.tv_sec - conn->timestamp_lastwritten);
> }
> circuit_dump_by_conn(conn); /* dump info about all the circuits using this conn */
> printf("\n");
>
> Index: or.h
> ===================================================================
> RCS file: /home/or/cvsroot/src/or/or.h,v
> retrieving revision 1.31
> retrieving revision 1.32
> diff -u -d -r1.31 -r1.32
> --- or.h 28 Sep 2002 05:53:00 -0000 1.31
> +++ or.h 1 Oct 2002 23:37:31 -0000 1.32
> @@ -188,11 +188,15 @@
> int inbuflen;
> int inbuf_datalen;
> int inbuf_reached_eof;
> + long timestamp_lastread;
>
> 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;
>
> // uint16_t aci; /* anonymous connection identifier */
>
> @@ -357,6 +361,7 @@
> int LinkPadding;
> int DirRebuildPeriod;
> int DirFetchPeriod;
> + int KeepalivePeriod;
> int Role;
> int loglevel;
> } or_options_t;
>