[or-cvs] send the end cell when we realize we"re going to end,

Roger Dingledine arma at seul.org
Tue Oct 21 08:37:10 UTC 2003


Update of /home/or/cvsroot/src/or
In directory moria.mit.edu:/home2/arma/work/onion/cvs/src/or

Modified Files:
	circuit.c connection.c connection_edge.c dns.c or.h test.c 
Log Message:
send the end cell when we realize we're going to end,
not when we're closing the stream.

this lets us put a payload in the end cell if we want to,
to describe why we're closing the stream.

there are still some places where we don't send the end cell
immediately. i need to track them down. but it's a low priority, 
since i've made it send the end cell when we close the stream if
we haven't already sent it.


Index: circuit.c
===================================================================
RCS file: /home/or/cvsroot/src/or/circuit.c,v
retrieving revision 1.79
retrieving revision 1.80
diff -u -d -r1.79 -r1.80
--- circuit.c	15 Oct 2003 18:28:32 -0000	1.79
+++ circuit.c	21 Oct 2003 08:37:07 -0000	1.80
@@ -512,52 +512,59 @@
   circuit_t *circ;
   connection_t *prevconn;
 
-  if(!connection_speaks_cells(conn)) {
-    /* it's an edge conn. need to remove it from the linked list of
-     * conn's for this circuit. Send an 'end' relay command.
-     * But don't kill the circuit.
-     */
-
-    circ = circuit_get_by_conn(conn);
-    if(!circ)
+  switch(conn->type) {
+    case CONN_TYPE_OR:
+      /* We must close all the circuits on it. */
+      while((circ = circuit_get_by_conn(conn))) {
+        if(circ->n_conn == conn) /* it's closing in front of us */
+          circ->n_conn = NULL;
+        if(circ->p_conn == conn) /* it's closing behind us */
+          circ->p_conn = NULL;
+        circuit_close(circ);
+      }  
       return;
+    case CONN_TYPE_AP:
+    case CONN_TYPE_EXIT:
 
-    if(conn == circ->p_streams) {
-      circ->p_streams = conn->next_stream;
-      goto send_end;
-    }
-    if(conn == circ->n_streams) {
-      circ->n_streams = conn->next_stream;
-      goto send_end;
-    }
-    for(prevconn = circ->p_streams; prevconn && prevconn->next_stream && prevconn->next_stream != conn; prevconn = prevconn->next_stream) ;
-    if(prevconn && prevconn->next_stream) {
-      prevconn->next_stream = conn->next_stream;
-      goto send_end;
-    }
-    for(prevconn = circ->n_streams; prevconn && prevconn->next_stream && prevconn->next_stream != conn; prevconn = prevconn->next_stream) ;
-    if(prevconn && prevconn->next_stream) {
-      prevconn->next_stream = conn->next_stream;
-      goto send_end;
-    }
-    log_fn(LOG_ERR,"edge conn not in circuit's list?");
-    assert(0); /* should never get here */
-send_end:
-    connection_edge_send_command(conn, circ, RELAY_COMMAND_END,
-                                 NULL, 0, conn->cpath_layer);
-    return;
-  }
+      /* It's an edge conn. Need to remove it from the linked list of
+       * conn's for this circuit. Confirm that 'end' relay command has
+       * been sent. But don't kill the circuit.
+       */
 
-  /* this connection speaks cells. We must close all the circuits on it. */
-  while((circ = circuit_get_by_conn(conn))) {
-    if(circ->n_conn == conn) /* it's closing in front of us */
-      circ->n_conn = NULL;
-    if(circ->p_conn == conn) /* it's closing behind us */
-      circ->p_conn = NULL;
-    circuit_close(circ);
-  }  
+      circ = circuit_get_by_conn(conn);
+      if(!circ)
+        return;
+
+      if(!conn->has_sent_end) {
+        log_fn(LOG_INFO,"Edge connection hasn't sent end yet? Bug.");
+        connection_edge_send_command(conn, circ, RELAY_COMMAND_END,
+                                     NULL, 0, conn->cpath_layer);
+      }
+
+      if(conn == circ->p_streams) {
+        circ->p_streams = conn->next_stream;
+        return;
+      }
+      if(conn == circ->n_streams) {
+        circ->n_streams = conn->next_stream;
+        return;
+      }
+      for(prevconn = circ->p_streams; prevconn && prevconn->next_stream && prevconn->next_stream != conn; prevconn = prevconn->next_stream) ;
+      if(prevconn && prevconn->next_stream) {
+        prevconn->next_stream = conn->next_stream;
+        return;
+      }
+      for(prevconn = circ->n_streams; prevconn && prevconn->next_stream && prevconn->next_stream != conn; prevconn = prevconn->next_stream) ;
+      if(prevconn && prevconn->next_stream) {
+        prevconn->next_stream = conn->next_stream;
+        return;
+      }
+      log_fn(LOG_ERR,"edge conn not in circuit's list?");
+      assert(0); /* should never get here */
+  } /* end switch */
 }
 
+
 /* FIXME this now leaves some out */
 void circuit_dump_by_conn(connection_t *conn, int severity) {
   circuit_t *circ;
@@ -903,7 +910,11 @@
     for(stream = circ->p_streams; stream; stream=stream->next_stream) {
       if(stream->cpath_layer == victim) {
         log_fn(LOG_INFO, "Marking stream %d for close.", *(int*)stream->stream_id);
-/*ENDCLOSE*/    stream->marked_for_close = 1;
+        /* no need to send 'end' relay cells,
+         * because the other side's already dead
+         */
+        stream->marked_for_close = 1;
+        stream->has_sent_end = 1;
       }
     }
 

Index: connection.c
===================================================================
RCS file: /home/or/cvsroot/src/or/connection.c,v
retrieving revision 1.122
retrieving revision 1.123
diff -u -d -r1.122 -r1.123
--- connection.c	15 Oct 2003 18:50:16 -0000	1.122
+++ connection.c	21 Oct 2003 08:37:07 -0000	1.123
@@ -353,9 +353,9 @@
   } else {
     /* do a rudimentary round-robin so one connection can't hog a thickpipe */
     if(connection_speaks_cells(conn)) {
-      at_most = 10*(CELL_NETWORK_SIZE);
+      at_most = 30*(CELL_NETWORK_SIZE);
     } else {
-      at_most = 10*(CELL_PAYLOAD_SIZE - RELAY_HEADER_SIZE);
+      at_most = 30*(CELL_PAYLOAD_SIZE - RELAY_HEADER_SIZE);
     }
 
     if(at_most > global_read_bucket)
@@ -644,7 +644,8 @@
 
   if(!connection_speaks_cells(conn)) {
      log_fn(LOG_INFO,"Aci %d: At an edge. Marking connection for close.", aci);
-/*ENDCLOSE*/ conn->marked_for_close = 1;
+     connection_edge_end(conn, NULL, 0, conn->cpath_layer);
+     /* if they already sent a destroy, they know. XXX can just close? */
      return 0;
   }
 

Index: connection_edge.c
===================================================================
RCS file: /home/or/cvsroot/src/or/connection_edge.c,v
retrieving revision 1.41
retrieving revision 1.42
diff -u -d -r1.41 -r1.42
--- connection_edge.c	15 Oct 2003 18:50:16 -0000	1.41
+++ connection_edge.c	21 Oct 2003 08:37:07 -0000	1.42
@@ -26,27 +26,34 @@
     /* eof reached; we're done reading, but we might want to write more. */ 
     conn->done_receiving = 1;
     shutdown(conn->s, 0); /* XXX check return, refactor NM */
-    if (conn->done_sending)
-/*ENDCLOSE*/  conn->marked_for_close = 1;
-
-    /* XXX Factor out common logic here and in circuit_about_to_close NM */
-    connection_edge_send_command(conn, circuit_get_by_conn(conn), RELAY_COMMAND_END,
-                                 NULL, 0, conn->cpath_layer);
+    if (conn->done_sending) {
+      connection_edge_end(conn, NULL, 0, conn->cpath_layer);
+    } else {
+      connection_edge_send_command(conn, circuit_get_by_conn(conn), RELAY_COMMAND_END,
+                                   NULL, 0, conn->cpath_layer);
+    }
     return 0;
 #else 
     /* eof reached, kill it. */
     log_fn(LOG_INFO,"conn (fd %d) reached eof. Closing.", conn->s);
-/*ENDCLOSE*/ return -1;
+    connection_edge_end(conn, NULL, 0, conn->cpath_layer);
+    return -1;
 #endif
   }
 
   switch(conn->state) {
     case AP_CONN_STATE_SOCKS_WAIT:
-/*ENDCLOSE*/  return connection_ap_handshake_process_socks(conn);
+      if(connection_ap_handshake_process_socks(conn) < 0) {
+        connection_edge_end(conn, NULL, 0, conn->cpath_layer);
+        return -1;
+      }
+      return 0;
     case AP_CONN_STATE_OPEN:
     case EXIT_CONN_STATE_OPEN:
-      if(connection_edge_package_raw_inbuf(conn) < 0)
-/*ENDCLOSE*/  return -1;
+      if(connection_edge_package_raw_inbuf(conn) < 0) {
+        connection_edge_end(conn, NULL, 0, conn->cpath_layer);
+        return -1;
+      }
       return 0;
     case EXIT_CONN_STATE_CONNECTING:
       log_fn(LOG_INFO,"text from server while in 'connecting' state at exit. Leaving it on buffer.");
@@ -56,6 +63,25 @@
   return 0;
 }
 
+void connection_edge_end(connection_t *conn, void *payload, int payload_len,
+                         crypt_path_t *cpath_layer) {
+  circuit_t *circ = circuit_get_by_conn(conn);
+
+  if(conn->has_sent_end) {
+    log_fn(LOG_WARN,"It appears I've already sent the end. Are you calling me twice?");
+    return;
+  }
+
+  if(circ) {
+    log_fn(LOG_DEBUG,"Marking conn (fd %d) and sending end.",conn->s);
+    connection_edge_send_command(conn, circ, RELAY_COMMAND_END,
+                                 payload, payload_len, cpath_layer);
+  }
+
+  conn->marked_for_close = 1;
+  conn->has_sent_end = 1;
+}
+
 void connection_edge_send_command(connection_t *fromconn, circuit_t *circ, int relay_command,
                                   void *payload, int payload_len, crypt_path_t *cpath_layer) {
   cell_t cell;
@@ -128,6 +154,7 @@
       return 0;
     } else {
       log_fn(LOG_WARN,"Got an unexpected relay cell, not in 'open' state. Closing.");
+      connection_edge_end(conn, NULL, 0, conn->cpath_layer);
       return -1;
     }
   }
@@ -148,12 +175,15 @@
       if((edge_type == EDGE_AP && --layer_hint->deliver_window < 0) ||
          (edge_type == EDGE_EXIT && --circ->deliver_window < 0)) {
         log_fn(LOG_WARN,"(relay data) circ deliver_window below 0. Killing.");
+        connection_edge_end(conn, NULL, 0, conn->cpath_layer);
         return -1;
       }
       log_fn(LOG_DEBUG,"circ deliver_window now %d.", edge_type == EDGE_AP ? layer_hint->deliver_window : circ->deliver_window);
 
-      if(circuit_consider_sending_sendme(circ, edge_type, layer_hint) < 0)
+      if(circuit_consider_sending_sendme(circ, edge_type, layer_hint) < 0) {
+        conn->has_sent_end = 1; /* we failed because conn is broken. can't send end. */
         return -1;
+      }
 
       if(!conn) {
         log_fn(LOG_INFO,"relay cell dropped, unknown stream %d.",*(int*)conn->stream_id);
@@ -181,10 +211,14 @@
 #ifdef HALF_OPEN
       conn->done_sending = 1;
       shutdown(conn->s, 1); /* XXX check return; refactor NM */
-      if (conn->done_receiving)
-/*ENDCLOSE*/  conn->marked_for_close = 1;
+      if (conn->done_receiving) {
+        conn->marked_for_close = 1;
+        conn->has_sent_end = 1; /* no need to send end, we just got one! */
+      }
+#else
+      conn->marked_for_close = 1;
+      conn->has_sent_end = 1; /* no need to send end, we just got one! */
 #endif
-/*ENDCLOSE*/  conn->marked_for_close = 1;
       break;
     case RELAY_COMMAND_EXTEND:
       if(conn) {
@@ -233,7 +267,8 @@
       }
       log_fn(LOG_INFO,"Connected! Notifying application.");
       if(connection_ap_handshake_socks_reply(conn, NULL, 0, 1) < 0) {
-/*ENDCLOSE*/    conn->marked_for_close = 1;
+        log_fn(LOG_INFO,"Writing to socks-speaking application failed. Closing.");
+        connection_edge_end(conn, NULL, 0, conn->cpath_layer);
       }
       break;
     case RELAY_COMMAND_SENDME:
@@ -529,10 +564,14 @@
   return 0; /* if socks_version isn't 4 or 5, don't send anything */
 }
 
-/*ENDCLOSE*/ static int connection_exit_begin_conn(cell_t *cell, circuit_t *circ) {
+static int connection_exit_begin_conn(cell_t *cell, circuit_t *circ) {
   connection_t *n_stream;
   char *colon;
 
+  /* XXX currently we don't send an end cell back if we drop the
+   * begin because it's malformed.
+   */
+
   if(!memchr(cell->payload+RELAY_HEADER_SIZE+STREAM_ID_SIZE,0,
              cell->length-RELAY_HEADER_SIZE-STREAM_ID_SIZE)) {
     log_fn(LOG_WARN,"relay begin cell has no \\0. Dropping.");
@@ -578,6 +617,7 @@
       /* else fall through */
     case -1: /* resolve failed */
       log_fn(LOG_WARN,"Resolve or connect failed (%s).", n_stream->address);
+      connection_edge_end(n_stream, NULL, 0, NULL);
       connection_remove(n_stream);
       connection_free(n_stream);
     case 0: /* resolve added to pending list */

Index: dns.c
===================================================================
RCS file: /home/or/cvsroot/src/or/dns.c,v
retrieving revision 1.34
retrieving revision 1.35
diff -u -d -r1.34 -r1.35
--- dns.c	18 Oct 2003 07:09:09 -0000	1.34
+++ dns.c	21 Oct 2003 08:37:07 -0000	1.35
@@ -220,7 +220,7 @@
     /* mark all pending connections to fail */
     while(resolve->pending_connections) {
       pend = resolve->pending_connections;
-/*ENDCLOSE*/  pend->conn->marked_for_close = 1;
+      connection_edge_end(pend->conn, NULL, 0, NULL);
       resolve->pending_connections = pend->next;
       free(pend);
     }
@@ -273,7 +273,7 @@
     pend = resolve->pending_connections;
     pend->conn->addr = resolve->answer;
     if(resolve->state == CACHE_STATE_FAILED || connection_exit_connect(pend->conn) < 0) {
-/*ENDCLOSE*/  pend->conn->marked_for_close = 1;
+      connection_edge_end(pend->conn, NULL, 0, NULL);
     }
     resolve->pending_connections = pend->next;
     free(pend);

Index: or.h
===================================================================
RCS file: /home/or/cvsroot/src/or/or.h,v
retrieving revision 1.168
retrieving revision 1.169
diff -u -d -r1.168 -r1.169
--- or.h	19 Oct 2003 05:45:22 -0000	1.168
+++ or.h	21 Oct 2003 08:37:07 -0000	1.169
@@ -310,6 +310,8 @@
 
   int done_sending; /* for half-open connections; not used currently */
   int done_receiving;
+  char has_sent_end; /* for debugging: set once we've set the stream end,
+                        and check in circuit_about_to_close_connection() */
 };
 
 typedef struct connection_t connection_t;
@@ -581,6 +583,9 @@
 /********************************* connection_edge.c ***************************/
 
 int connection_edge_process_inbuf(connection_t *conn);
+void connection_edge_end(connection_t *conn, void *payload, int payload_len,
+                         crypt_path_t *cpath_layer);
+
 void connection_edge_send_command(connection_t *fromconn, circuit_t *circ, int relay_command,
                                   void *payload, int payload_len, crypt_path_t *cpath_layer);
 

Index: test.c
===================================================================
RCS file: /home/or/cvsroot/src/or/test.c,v
retrieving revision 1.43
retrieving revision 1.44
diff -u -d -r1.43 -r1.44
--- test.c	14 Oct 2003 01:34:31 -0000	1.43
+++ test.c	21 Oct 2003 08:37:07 -0000	1.44
@@ -46,7 +46,7 @@
 
 void
 test_buffers() {
-#define MAX_BUF_SIZE 640*1024
+#define MAX_BUF_SIZE 1024*1024
   char str[256];
   char str2[256];
 
@@ -61,7 +61,7 @@
   if (!(buf = buf_new()))
     test_fail();
 
-  test_eq(buf_capacity(buf), 2*1024);
+  test_eq(buf_capacity(buf), 512*1024);
   test_eq(buf_datalen(buf), 0);
 
   /****
@@ -77,7 +77,7 @@
   s = open("/tmp/tor_test/data", O_RDONLY, 0);
   eof = 0;
   i = read_to_buf(s, 10, buf, &eof);
-  test_eq(buf_capacity(buf), 2*1024);
+  test_eq(buf_capacity(buf), 512*1024);
   test_eq(buf_datalen(buf), 10);
   test_eq(eof, 0);
   test_eq(i, 10);
@@ -85,7 +85,7 @@
 
   /* Test reading 0 bytes. */
   i = read_to_buf(s, 0, buf, &eof);
-  test_eq(buf_capacity(buf), MAX_BUF_SIZE);
+  test_eq(buf_capacity(buf), 512*1024);
   test_eq(buf_datalen(buf), 10);
   test_eq(eof, 0);
   test_eq(i, 0);
@@ -103,7 +103,7 @@
   /* Now test when buffer is filled with more data to read. */
   buf2 = buf_new_with_capacity(32);
   i = read_to_buf(s, 128, buf2, &eof);
-  test_eq(buf_capacity(buf2), 32);
+  test_eq(buf_capacity(buf2), 128);
   test_eq(buf_datalen(buf2), 32);
   test_eq(eof, 0);
   test_eq(i, 32);



More information about the tor-commits mailing list