[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]

[or-cvs] streams are now 8 bytes, and are recognized by intermediate...



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

Modified Files:
	circuit.c command.c connection.c connection_ap.c 
	connection_edge.c connection_exit.c onion.c or.h 
Log Message:
streams are now 8 bytes, and are recognized by intermediate hops
the OP only crypts the appropriate number of times depending on which
layer (hop on the path) it's for/from.


Index: circuit.c
===================================================================
RCS file: /home/or/cvsroot/src/or/circuit.c,v
retrieving revision 1.40
retrieving revision 1.41
diff -u -d -r1.40 -r1.41
--- circuit.c	1 May 2003 22:55:50 -0000	1.40
+++ circuit.c	2 May 2003 21:29:25 -0000	1.41
@@ -281,7 +281,8 @@
   return bestcirc;
 }
 
-int circuit_deliver_relay_cell_from_edge(cell_t *cell, circuit_t *circ, char edge_type) {
+int circuit_deliver_relay_cell_from_edge(cell_t *cell, circuit_t *circ,
+                                         char edge_type, crypt_path_t *layer_hint) {
   int cell_direction;
   static int numsent_ap=0, numsent_exit=0;
 
@@ -293,7 +294,7 @@
     log(LOG_DEBUG,"circuit_deliver_relay_cell_from_edge(): now sent %d relay cells from ap", numsent_ap);
     if(circ->p_receive_circwindow <= 0) {
       log(LOG_DEBUG,"circuit_deliver_relay_cell_from_edge(): pwindow 0, queueing for later.");
-      circ->relay_queue = relay_queue_add(circ->relay_queue, cell);
+      circ->relay_queue = relay_queue_add(circ->relay_queue, cell, layer_hint);
       return 0;
     }
     circ->p_receive_circwindow--;
@@ -304,13 +305,13 @@
     log(LOG_DEBUG,"circuit_deliver_relay_cell_from_edge(): now sent %d relay cells from exit", numsent_exit);
     if(circ->n_receive_circwindow <= 0) {
       log(LOG_DEBUG,"circuit_deliver_relay_cell_from_edge(): nwindow 0, queueing for later.");
-      circ->relay_queue = relay_queue_add(circ->relay_queue, cell);
+      circ->relay_queue = relay_queue_add(circ->relay_queue, cell, layer_hint);
       return 0;
     }
     circ->n_receive_circwindow--;
   }
 
-  if(circuit_deliver_relay_cell(cell, circ, cell_direction) < 0) {
+  if(circuit_deliver_relay_cell(cell, circ, cell_direction, layer_hint) < 0) {
     return -1;
   }
 
@@ -318,113 +319,168 @@
   return 0;
 }
 
-int circuit_deliver_relay_cell(cell_t *cell, circuit_t *circ, int cell_direction) {
-  connection_t *conn;
+int circuit_deliver_relay_cell(cell_t *cell, circuit_t *circ,
+                               int cell_direction, crypt_path_t *layer_hint) {
+  connection_t *conn=NULL;
+  char recognized=0;
+  char buf[256];
 
   assert(cell && circ);
   assert(cell_direction == CELL_DIRECTION_OUT || cell_direction == CELL_DIRECTION_IN); 
-  if(cell_direction == CELL_DIRECTION_OUT)
-    conn = circ->n_conn;
-  else
-    conn = circ->p_conn;
 
-  /* first crypt cell->length */
-  if(circuit_crypt(circ, &(cell->length), 1, cell_direction) < 0) {
-    log(LOG_DEBUG,"circuit_deliver_relay_cell(): length crypt failed. Dropping connection.");
-    return -1;
-  }
+  buf[0] = cell->length;
+  memcpy(buf+1, cell->payload, CELL_PAYLOAD_SIZE);
 
-  /* then crypt the payload */
-  if(circuit_crypt(circ, (char *)&(cell->payload), CELL_PAYLOAD_SIZE, cell_direction) < 0) {
-    log(LOG_DEBUG,"circuit_deliver_relay_cell(): payload crypt failed. Dropping connection.");
+  log(LOG_DEBUG,"circuit_deliver_relay_cell(): streamid %d before crypt.", *(int*)(cell->payload+1));
+
+  if(relay_crypt(circ, buf, 1+CELL_PAYLOAD_SIZE, cell_direction, layer_hint, &recognized, &conn) < 0) {
+    log(LOG_DEBUG,"circuit_deliver_relay_cell(): relay crypt failed. Dropping connection.");
     return -1;
   }
 
-  if(cell_direction == CELL_DIRECTION_OUT && (!conn || conn->type == CONN_TYPE_EXIT)) {
-    log(LOG_DEBUG,"circuit_deliver_relay_cell(): Sending to exit.");
-    return connection_edge_process_relay_cell(cell, circ, EDGE_EXIT);
+  cell->length = buf[0];
+  memcpy(cell->payload, buf+1, CELL_PAYLOAD_SIZE);
+
+  if(recognized) {
+    if(cell_direction == CELL_DIRECTION_OUT) {
+      log(LOG_DEBUG,"circuit_deliver_relay_cell(): Sending to exit.");
+      return connection_edge_process_relay_cell(cell, circ, conn, EDGE_EXIT);
+    }
+    if(cell_direction == CELL_DIRECTION_IN) {
+      log(LOG_DEBUG,"circuit_deliver_relay_cell(): Sending to AP.");
+      return connection_edge_process_relay_cell(cell, circ, conn, EDGE_AP);
+    }
   }
-  if(cell_direction == CELL_DIRECTION_IN && (!conn || conn->type == CONN_TYPE_AP)) {
-    log(LOG_DEBUG,"circuit_deliver_relay_cell(): Sending to AP.");
-    return connection_edge_process_relay_cell(cell, circ, EDGE_AP);
+
+  /* not recognized. pass it on. */
+  if(cell_direction == CELL_DIRECTION_OUT)
+    conn = circ->n_conn;
+  else
+    conn = circ->p_conn;
+
+  if(!conn || !connection_speaks_cells(conn)) {
+    log(LOG_INFO,"circuit_deliver_relay_cell(): Didn't recognize cell (%d), but circ stops here! Dropping.", *(int *)(cell->payload+1));
+    return 0;
   }
-  /* else send it as a cell */
-  assert(conn);
-  //log(LOG_DEBUG,"circuit_deliver_relay_cell(): Sending to connection.");
+
   return connection_write_cell_to_buf(cell, conn);
 }
 
-int circuit_crypt(circuit_t *circ, char *in, int inlen, char cell_direction) {
-  char *out;
+int relay_crypt(circuit_t *circ, char *in, int inlen, char cell_direction,
+                crypt_path_t *layer_hint, char *recognized, connection_t **conn) {
   crypt_path_t *thishop;
+  char out[256];
 
-  assert(circ && in);
+  assert(circ && in && recognized && conn);
 
-  out = (char *)malloc(inlen);
-  if(!out)
-    return -1;
+  assert(inlen < 256);
 
   if(cell_direction == CELL_DIRECTION_IN) { 
     if(circ->cpath) { /* we're at the beginning of the circuit. We'll want to do layered crypts. */
       thishop = circ->cpath;
-      /* Remember: cpath is in forward order, that is, first hop first. */
-      do {
+      do { /* Remember: cpath is in forward order, that is, first hop first. */
         assert(thishop);
+
         /* decrypt */
         if(crypto_cipher_decrypt(thishop->b_crypto, in, inlen, out)) {
           log(LOG_ERR,"Error performing decryption:%s",crypto_perror());
-          free(out);
           return -1;
         }
-
-        /* copy ciphertext back to buf */
         memcpy(in,out,inlen);
+
+        if( (*recognized = relay_check_recognized(circ, cell_direction, in+2, conn)))
+          return 0;
+
         thishop = thishop->next;
       } while(thishop != circ->cpath);
+      log(LOG_INFO,"relay_crypt(): in-cell at OP not recognized. Killing circuit.");
+      return -1;
     } else { /* we're in the middle. Just one crypt. */
-      if(crypto_cipher_encrypt(circ->p_crypto,in, inlen, out)) {
+
+      if(crypto_cipher_encrypt(circ->p_crypto, in, inlen, out)) {
         log(LOG_ERR,"circuit_encrypt(): Encryption failed for ACI : %u (%s).",
             circ->p_aci, crypto_perror());
-        free(out);
         return -1;
       }
       memcpy(in,out,inlen);
+
+      /* don't check for recognized. only the OP can recognize a stream on the way back. */
+
     }
   } else if(cell_direction == CELL_DIRECTION_OUT) { 
     if(circ->cpath) { /* we're at the beginning of the circuit. We'll want to do layered crypts. */
-      thishop = circ->cpath->prev;
+
+      thishop = layer_hint; /* we already know which layer, from when we package_raw_inbuf'ed */
       /* moving from last to first hop */
       do {
         assert(thishop);
+
         /* encrypt */
-        if(crypto_cipher_encrypt(thishop->f_crypto, in, inlen, (unsigned char *)out)) {
+        if(crypto_cipher_encrypt(thishop->f_crypto, in, inlen, out)) {
           log(LOG_ERR,"Error performing encryption:%s",crypto_perror());
-          free(out);
           return -1;
         }
-
-        /* copy ciphertext back to buf */
         memcpy(in,out,inlen);
+
         thishop = thishop->prev;
       } while(thishop != circ->cpath->prev);
     } else { /* we're in the middle. Just one crypt. */
+
       if(crypto_cipher_decrypt(circ->n_crypto,in, inlen, out)) {
         log(LOG_ERR,"circuit_crypt(): Decryption failed for ACI : %u (%s).",
             circ->n_aci, crypto_perror());
-        free(out);
         return -1;
       }
       memcpy(in,out,inlen);
+
+      if( (*recognized = relay_check_recognized(circ, cell_direction, in+2, conn)))
+        return 0;
+
     }
   } else {
     log(LOG_ERR,"circuit_crypt(): unknown cell direction %d.", cell_direction);
     assert(0);
   }
 
-  free(out);
   return 0;
 }
 
+int relay_check_recognized(circuit_t *circ, int cell_direction, char *stream, connection_t **conn) {
+/* FIXME can optimize by passing thishop in */
+  connection_t *tmpconn;
+
+  log(LOG_DEBUG,"relay_check_recognized(): entering");
+  if(!memcmp(stream,ZERO_STREAM,STREAM_ID_SIZE))
+    return 1; /* the zero stream is always recognized */
+
+  if(cell_direction == CELL_DIRECTION_OUT)
+    tmpconn = circ->n_conn;
+  else
+    tmpconn = circ->p_conn;
+
+  log(LOG_DEBUG,"relay_check_recognized(): not the zero stream.");
+  if(!tmpconn)
+    return 0; /* no conns? don't recognize it */
+
+  while(tmpconn && tmpconn->type == CONN_TYPE_OR) {
+    log(LOG_DEBUG,"relay_check_recognized(): skipping over an OR conn");
+    tmpconn = tmpconn->next_stream;
+  }
+
+  for( ; tmpconn; tmpconn=tmpconn->next_stream) {
+    if(!memcmp(stream,tmpconn->stream_id, STREAM_ID_SIZE)) {
+      log(LOG_DEBUG,"relay_check_recognized(): recognized stream %d.", *(int*)stream);
+      *conn = tmpconn;
+      return 1;
+    }
+    log(LOG_DEBUG,"relay_check_recognized(): considered stream %d, not it.",*(int*)tmpconn->stream_id);
+  }
+
+  log(LOG_DEBUG,"relay_check_recognized(): Didn't recognize. Giving up.");
+  return 0;
+
+}
+
 void circuit_resume_edge_reading(circuit_t *circ, int edge_type) {
   connection_t *conn;
   struct relay_queue_t *tmpd;
@@ -438,7 +494,7 @@
       circ->n_receive_circwindow--;
       assert(circ->n_receive_circwindow >= 0);
 
-      if(circuit_deliver_relay_cell(circ->relay_queue->cell, circ, CELL_DIRECTION_IN) < 0) {
+      if(circuit_deliver_relay_cell(circ->relay_queue->cell, circ, CELL_DIRECTION_IN, circ->relay_queue->layer_hint) < 0) {
         circuit_close(circ);
         return;
       }
@@ -446,7 +502,7 @@
       circ->p_receive_circwindow--;
       assert(circ->p_receive_circwindow >= 0);
 
-      if(circuit_deliver_relay_cell(circ->relay_queue->cell, circ, CELL_DIRECTION_OUT) < 0) {
+      if(circuit_deliver_relay_cell(circ->relay_queue->cell, circ, CELL_DIRECTION_OUT, circ->relay_queue->layer_hint) < 0) {
         circuit_close(circ);
         return;
       }

Index: command.c
===================================================================
RCS file: /home/or/cvsroot/src/or/command.c,v
retrieving revision 1.25
retrieving revision 1.26
diff -u -d -r1.25 -r1.26
--- command.c	1 May 2003 06:42:28 -0000	1.25
+++ command.c	2 May 2003 21:29:25 -0000	1.26
@@ -241,14 +241,14 @@
 
   if(cell->aci == circ->p_aci) { /* it's an outgoing cell */
     cell->aci = circ->n_aci; /* switch it */
-    if(circuit_deliver_relay_cell(cell, circ, CELL_DIRECTION_OUT) < 0) {
+    if(circuit_deliver_relay_cell(cell, circ, CELL_DIRECTION_OUT, conn->cpath_layer) < 0) {
       log(LOG_INFO,"command_process_relay_cell(): circuit_deliver_relay_cell (forward) failed. Closing.");
       circuit_close(circ);
       return;
     }
   } else { /* it's an ingoing cell */
     cell->aci = circ->p_aci; /* switch it */
-    if(circuit_deliver_relay_cell(cell, circ, CELL_DIRECTION_IN) < 0) {
+    if(circuit_deliver_relay_cell(cell, circ, CELL_DIRECTION_IN, NULL) < 0) {
       log(LOG_DEBUG,"command_process_relay_cell(): circuit_deliver_relay_cell (backward) failed. Closing.");
       circuit_close(circ);
       return;

Index: connection.c
===================================================================
RCS file: /home/or/cvsroot/src/or/connection.c,v
retrieving revision 1.58
retrieving revision 1.59
diff -u -d -r1.58 -r1.59
--- connection.c	1 May 2003 06:42:28 -0000	1.58
+++ connection.c	2 May 2003 21:29:25 -0000	1.59
@@ -706,7 +706,7 @@
 
   if(conn->type == CONN_TYPE_EXIT) {
     cell.aci = circ->p_aci;
-    if(circuit_deliver_relay_cell_from_edge(&cell, circ, EDGE_EXIT) < 0) {
+    if(circuit_deliver_relay_cell_from_edge(&cell, circ, EDGE_EXIT, NULL) < 0) {
       log(LOG_DEBUG,"connection_package_raw_inbuf(): circuit_deliver_relay_cell_from_edge (backward) failed. Closing.");
       circuit_close(circ);
       return 0;
@@ -721,7 +721,7 @@
   } else { /* send it forward. we're an AP */
     assert(conn->type == CONN_TYPE_AP);
     cell.aci = circ->n_aci;
-    if(circuit_deliver_relay_cell_from_edge(&cell, circ, EDGE_AP) < 0) {
+    if(circuit_deliver_relay_cell_from_edge(&cell, circ, EDGE_AP, conn->cpath_layer) < 0) {
       log(LOG_DEBUG,"connection_package_raw_inbuf(): circuit_deliver_relay_cell_from_edge (forward) failed. Closing.");
       circuit_close(circ);
       return 0;
@@ -763,7 +763,7 @@
       log(LOG_DEBUG,"connection_consider_sending_sendme(): Outbuf %d, Queueing stream sendme back.", conn->outbuf_flushlen);
       conn->p_receive_streamwindow += STREAMWINDOW_INCREMENT;
       cell.aci = circ->p_aci;
-      if(circuit_deliver_relay_cell_from_edge(&cell, circ, edge_type) < 0) {
+      if(circuit_deliver_relay_cell_from_edge(&cell, circ, edge_type, NULL) < 0) {
         log(LOG_DEBUG,"connection_consider_sending_sendme(): circuit_deliver_relay_cell_from_edge (backward) failed. Closing.");
         circuit_close(circ);
         return 0;
@@ -775,7 +775,7 @@
       log(LOG_DEBUG,"connection_consider_sending_sendme(): Outbuf %d, Queueing stream sendme forward.", conn->outbuf_flushlen);
       conn->n_receive_streamwindow += STREAMWINDOW_INCREMENT;
       cell.aci = circ->n_aci;
-      if(circuit_deliver_relay_cell_from_edge(&cell, circ, edge_type) < 0) {
+      if(circuit_deliver_relay_cell_from_edge(&cell, circ, edge_type, conn->cpath_layer) < 0) {
         log(LOG_DEBUG,"connection_consider_sending_sendme(): circuit_deliver_relay_cell_from_edge (forward) failed. Closing.");
         circuit_close(circ);
         return 0;

Index: connection_ap.c
===================================================================
RCS file: /home/or/cvsroot/src/or/connection_ap.c,v
retrieving revision 1.40
retrieving revision 1.41
diff -u -d -r1.40 -r1.41
--- connection_ap.c	1 May 2003 22:55:50 -0000	1.40
+++ connection_ap.c	2 May 2003 21:29:25 -0000	1.41
@@ -108,6 +108,10 @@
   conn->next_stream = circ->p_conn;
   circ->p_conn = conn;
 
+  assert(circ->cpath && circ->cpath->prev);
+  assert(circ->cpath->prev->state == CPATH_STATE_OPEN);
+  conn->cpath_layer = circ->cpath->prev;
+
   if(ap_handshake_send_begin(conn, circ) < 0) {
     circuit_close(circ);
     return -1;
@@ -118,23 +122,24 @@
 
 int ap_handshake_send_begin(connection_t *ap_conn, circuit_t *circ) {
   cell_t cell;
-  uint16_t stream_id;
 
   memset(&cell, 0, sizeof(cell_t));
   /* deliver the dest_addr in a relay cell */
   cell.command = CELL_RELAY;
   cell.aci = circ->n_aci;
   SET_CELL_RELAY_COMMAND(cell, RELAY_COMMAND_BEGIN);
-  if (CRYPTO_PSEUDO_RAND_INT(stream_id))
+  if(crypto_pseudo_rand(STREAM_ID_SIZE, ap_conn->stream_id) < 0)
     return -1;
-  SET_CELL_STREAM_ID(cell, stream_id);
   /* FIXME check for collisions */
-  ap_conn->stream_id = stream_id;
+  SET_CELL_STREAM_ID(cell, ZERO_STREAM);
 
-  snprintf(cell.payload+4, CELL_PAYLOAD_SIZE-4, "%s:%d", ap_conn->dest_addr, ap_conn->dest_port);
-  cell.length = strlen(cell.payload+RELAY_HEADER_SIZE)+1+RELAY_HEADER_SIZE;
-  log(LOG_DEBUG,"ap_handshake_send_begin(): Sending relay cell to begin stream %d.", ap_conn->stream_id);
-  if(circuit_deliver_relay_cell_from_edge(&cell, circ, EDGE_AP) < 0) {
+  memcpy(cell.payload+RELAY_HEADER_SIZE, ap_conn->stream_id, STREAM_ID_SIZE);
+  cell.length = 
+    snprintf(cell.payload+RELAY_HEADER_SIZE+STREAM_ID_SIZE, CELL_PAYLOAD_SIZE-RELAY_HEADER_SIZE-STREAM_ID_SIZE,
+             "%s:%d", ap_conn->dest_addr, ap_conn->dest_port) + 
+    1 + STREAM_ID_SIZE + RELAY_HEADER_SIZE;
+  log(LOG_DEBUG,"ap_handshake_send_begin(): Sending relay cell (id %d) to begin stream %d.", *(int *)(cell.payload+1),*(int *)ap_conn->stream_id);
+  if(circuit_deliver_relay_cell_from_edge(&cell, circ, EDGE_AP, ap_conn->cpath_layer) < 0) {
     log(LOG_DEBUG,"ap_handshake_send_begin(): failed to deliver begin cell. Closing.");
     return -1;
   }

Index: connection_edge.c
===================================================================
RCS file: /home/or/cvsroot/src/or/connection_edge.c,v
retrieving revision 1.6
retrieving revision 1.7
diff -u -d -r1.6 -r1.7
--- connection_edge.c	1 May 2003 06:42:28 -0000	1.6
+++ connection_edge.c	2 May 2003 21:29:25 -0000	1.7
@@ -31,7 +31,7 @@
     SET_CELL_STREAM_ID(cell, conn->stream_id);
     cell.aci = circ->n_aci;
 
-    if (circuit_deliver_relay_cell_from_edge(&cell, circ, conn->type) < 0) {
+    if (circuit_deliver_relay_cell_from_edge(&cell, circ, conn->type, conn->cpath_layer) < 0) {
       log(LOG_DEBUG,"connection_edge_process_inbuf: circuit_deliver_relay_cell_from_edge failed.  Closing");
       circuit_close(circ);
     }
@@ -82,18 +82,16 @@
   cell.length = RELAY_HEADER_SIZE;
   log(LOG_INFO,"connection_edge_send_command(): delivering %d cell %s.", relay_command, conn->type == CONN_TYPE_AP ? "forward" : "backward");
 
-  if(circuit_deliver_relay_cell_from_edge(&cell, circ, conn->type) < 0) {
-    log(LOG_DEBUG,"connection_edge_send_command(): circuit_deliver_relay_cell failed. Closing.");
+  if(circuit_deliver_relay_cell_from_edge(&cell, circ, conn->type, conn->cpath_layer) < 0) {
+    log(LOG_DEBUG,"connection_edge_send_command(): circuit_deliver_relay_cell_from_edge failed. Closing.");
     circuit_close(circ);
     return 0;
   }
   return 0;
 }
 
-int connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ, int edge_type) {
-  connection_t *conn;
+int connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ, connection_t *conn, int edge_type) {
   int relay_command;
-  int stream_id;
   static int num_seen=0;
 
   /* an incoming relay cell has arrived */
@@ -101,23 +99,14 @@
   assert(cell && circ);
 
   relay_command = CELL_RELAY_COMMAND(*cell);
-  stream_id = CELL_STREAM_ID(*cell);
-  log(LOG_DEBUG,"connection_edge_process_relay_cell(): command %d stream %d", relay_command, stream_id);
+//  log(LOG_DEBUG,"connection_edge_process_relay_cell(): command %d stream %d", relay_command, stream_id);
   num_seen++;
   log(LOG_DEBUG,"connection_edge_process_relay_cell(): Now seen %d relay cells here.", num_seen);
 
   circuit_consider_sending_sendme(circ, edge_type);
 
-  if(edge_type == EDGE_AP)
-    conn = circ->p_conn;
-  else
-    conn = circ->n_conn;
-
-  for( ; conn && conn->stream_id != stream_id; conn = conn->next_stream) ;
-
-  /* now conn is either NULL, in which case we don't recognize the stream_id, or
-   * it is set, in which case cell is talking about this conn.
-   */
+  /* either conn is NULL, in which case we've got a control cell, or else
+   * conn points to the recognized stream. */
 
   if(conn && conn->state != AP_CONN_STATE_OPEN && conn->state != EXIT_CONN_STATE_OPEN) {
     if(conn->type == CONN_TYPE_EXIT && relay_command == RELAY_COMMAND_END) {
@@ -143,7 +132,7 @@
       }
     case RELAY_COMMAND_DATA:
       if(!conn) {
-        log(LOG_DEBUG,"connection_edge_process_relay_cell(): relay cell dropped, unknown stream %d.",stream_id);
+        log(LOG_DEBUG,"connection_edge_process_relay_cell(): relay cell dropped, unknown stream %d.",*(int*)conn->stream_id);
         return 0;
       }
       if((edge_type == EDGE_AP && --conn->n_receive_streamwindow < 0) ||
@@ -172,10 +161,10 @@
       return 0;
     case RELAY_COMMAND_END:
       if(!conn) {
-        log(LOG_DEBUG,"connection_edge_process_relay_cell(): end cell dropped, unknown stream %d.",stream_id);
+        log(LOG_DEBUG,"connection_edge_process_relay_cell(): end cell dropped, unknown stream %d.",*(int*)conn->stream_id);
         return 0;
       }
-      log(LOG_DEBUG,"connection_edge_process_relay_cell(): end cell for stream %d. Removing stream.",stream_id);
+      log(LOG_DEBUG,"connection_edge_process_relay_cell(): end cell for stream %d. Removing stream.",*(int*)conn->stream_id);
 
       /* go through and identify who points to conn. remove conn from the list. */
 #if 0
@@ -199,7 +188,7 @@
         return 0;
       }
       if(!conn) {
-        log(LOG_DEBUG,"connection_edge_process_relay_cell(): connected cell dropped, unknown stream %d.",stream_id);
+        log(LOG_DEBUG,"connection_edge_process_relay_cell(): connected cell dropped, unknown stream %d.",*(int*)conn->stream_id);
         break;
       }
       log(LOG_DEBUG,"connection_edge_process_relay_cell(): Connected! Notifying application.");
@@ -209,7 +198,7 @@
       break;
     case RELAY_COMMAND_SENDME:
       if(!conn) {
-        log(LOG_DEBUG,"connection_edge_process_relay_cell(): sendme cell dropped, unknown stream %d.",stream_id);
+        log(LOG_DEBUG,"connection_edge_process_relay_cell(): sendme cell dropped, unknown stream %d.",*(int*)conn->stream_id);
         return 0;
       }
       if(edge_type == EDGE_AP)

Index: connection_exit.c
===================================================================
RCS file: /home/or/cvsroot/src/or/connection_exit.c,v
retrieving revision 1.32
retrieving revision 1.33
diff -u -d -r1.32 -r1.33
--- connection_exit.c	1 May 2003 06:42:28 -0000	1.32
+++ connection_exit.c	2 May 2003 21:29:25 -0000	1.33
@@ -8,11 +8,11 @@
   connection_t *n_conn;
   char *colon;
 
-  if(!memchr(cell->payload + RELAY_HEADER_SIZE,0,cell->length - RELAY_HEADER_SIZE)) {
+  if(!memchr(cell->payload+RELAY_HEADER_SIZE+STREAM_ID_SIZE,0,cell->length-RELAY_HEADER_SIZE-STREAM_ID_SIZE)) {
     log(LOG_WARNING,"connection_exit_begin_conn(): relay begin cell has no \\0. Dropping.");
     return 0;
   }
-  colon = strchr(cell->payload + RELAY_HEADER_SIZE, ':');
+  colon = strchr(cell->payload+RELAY_HEADER_SIZE+STREAM_ID_SIZE, ':');
   if(!colon) {
     log(LOG_WARNING,"connection_exit_begin_conn(): relay begin cell has no colon. Dropping.");
     return 0;
@@ -31,10 +31,8 @@
     return 0;
   }
 
-//  cell->payload[0] = 0;
-  n_conn->stream_id = CELL_STREAM_ID(*cell);
-
-  n_conn->address = strdup(cell->payload + RELAY_HEADER_SIZE);
+  memcpy(n_conn->stream_id, cell->payload + RELAY_HEADER_SIZE, STREAM_ID_SIZE);
+  n_conn->address = strdup(cell->payload + RELAY_HEADER_SIZE + STREAM_ID_SIZE);
   n_conn->port = atoi(colon+1);
   n_conn->state = EXIT_CONN_STATE_RESOLVING;
   n_conn->receiver_bucket = -1; /* edge connections don't do receiver buckets */

Index: onion.c
===================================================================
RCS file: /home/or/cvsroot/src/or/onion.c,v
retrieving revision 1.41
retrieving revision 1.42
diff -u -d -r1.41 -r1.42
--- onion.c	1 May 2003 22:55:51 -0000	1.41
+++ onion.c	2 May 2003 21:29:25 -0000	1.42
@@ -141,13 +141,14 @@
 
 }
 
-struct relay_queue_t *relay_queue_add(struct relay_queue_t *list, cell_t *cell) {
+struct relay_queue_t *relay_queue_add(struct relay_queue_t *list, cell_t *cell, crypt_path_t *layer_hint) {
   struct relay_queue_t *tmpd, *newd;
 
   newd = malloc(sizeof(struct relay_queue_t));
   memset(newd, 0, sizeof(struct relay_queue_t));
   newd->cell = malloc(sizeof(cell_t));
   memcpy(newd->cell, cell, sizeof(cell_t));
+  newd->layer_hint = layer_hint;
 
   if(!list) {
     return newd;
@@ -167,7 +168,7 @@
 
   for(tmpo=ol_list; tmpo; tmpo=tmpo->next) {
     if(tmpo->circ == circ) {
-      tmpo->relay_cells = relay_queue_add(tmpo->relay_cells, cell);
+      tmpo->relay_cells = relay_queue_add(tmpo->relay_cells, cell, NULL);
       return;
     }
   }

Index: or.h
===================================================================
RCS file: /home/or/cvsroot/src/or/or.h,v
retrieving revision 1.70
retrieving revision 1.71
diff -u -d -r1.70 -r1.71
--- or.h	1 May 2003 22:55:51 -0000	1.70
+++ or.h	2 May 2003 21:29:25 -0000	1.71
@@ -128,7 +128,7 @@
 #define RELAY_COMMAND_CONNECTED 4
 #define RELAY_COMMAND_SENDME 5
 
-#define RELAY_HEADER_SIZE 4
+#define RELAY_HEADER_SIZE 8
 
 #define RELAY_STATE_RESOLVING
 
@@ -195,15 +195,17 @@
 typedef struct { 
   aci_t aci; /* Anonymous Connection Identifier */
   unsigned char command;
-  unsigned char length; /* of payload if relay cell, else value of sendme */
+  unsigned char length; /* of payload if relay cell */
   uint32_t seq; /* sequence number */
 
   unsigned char payload[CELL_PAYLOAD_SIZE];
 } cell_t;
 #define CELL_RELAY_COMMAND(c)         (*(uint8_t*)((c).payload))
 #define SET_CELL_RELAY_COMMAND(c,cmd) (*(uint8_t*)((c).payload) = (cmd))
-#define CELL_STREAM_ID(c)             ntohs(*(uint16_t*)((c).payload+2))
-#define SET_CELL_STREAM_ID(c,id)      (*(uint16_t*)((c).payload+2) = htons(id))
+#define STREAM_ID_SIZE 7
+#define SET_CELL_STREAM_ID(c,id)      memcpy((c).payload+1,(id),STREAM_ID_SIZE)
+
+#define ZERO_STREAM "\0\0\0\0\0\0\0\0"
 
 #define SOCKS4_REQUEST_GRANTED          90
 #define SOCKS4_REQUEST_REJECT           91
@@ -265,8 +267,9 @@
   uint16_t port;
 
 /* used by exit and ap: */
-  uint16_t stream_id;
+  char stream_id[STREAM_ID_SIZE];
   struct connection_t *next_stream;
+  struct crypt_path_t *cpath_layer; /* a pointer to which node in the circ this conn exits at */
   int n_receive_streamwindow;
   int p_receive_streamwindow;
   int done_sending;
@@ -335,7 +338,7 @@
   void *next;
 } routerinfo_t;
 
-typedef struct { 
+struct crypt_path_t { 
   char digest2[20]; /* second SHA output for onion_layer_t.keyseed */
   char digest3[20]; /* third SHA output for onion_layer_t.keyseed */
 
@@ -347,13 +350,16 @@
 #define CPATH_STATE_CLOSED 0
 #define CPATH_STATE_AWAITING_KEY 1
 #define CPATH_STATE_OPEN 2
-  void *next;
-  void *prev; /* doubly linked list */
+  struct crypt_path_t *next;
+  struct crypt_path_t *prev; /* doubly linked list */
 
-} crypt_path_t;
+};
+
+typedef struct crypt_path_t crypt_path_t;
 
 struct relay_queue_t {
   cell_t *cell;
+  crypt_path_t *layer_hint;
   struct relay_queue_t *next;
 };
 
@@ -506,9 +512,13 @@
 circuit_t *circuit_get_newest_ap(void);
 circuit_t *circuit_enumerate_by_naddr_nport(circuit_t *start, uint32_t naddr, uint16_t nport);
 
-int circuit_deliver_relay_cell_from_edge(cell_t *cell, circuit_t *circ, char edge_type);
-int circuit_deliver_relay_cell(cell_t *cell, circuit_t *circ, int crypt_type);
-int circuit_crypt(circuit_t *circ, char *in, int inlen, char crypt_type);
+int circuit_deliver_relay_cell_from_edge(cell_t *cell, circuit_t *circ,
+                                         char edge_type, crypt_path_t *layer_hint);
+int circuit_deliver_relay_cell(cell_t *cell, circuit_t *circ,
+                               int cell_direction, crypt_path_t *layer_hint);
+int relay_crypt(circuit_t *circ, char *in, int inlen, char cell_direction,
+                crypt_path_t *layer_hint, char *recognized, connection_t **conn);
+int relay_check_recognized(circuit_t *circ, int cell_direction, char *stream, connection_t **conn);
 
 void circuit_resume_edge_reading(circuit_t *circ, int edge_type);
 int circuit_consider_stop_edge_reading(circuit_t *circ, int edge_type);
@@ -645,7 +655,7 @@
 
 int connection_edge_process_inbuf(connection_t *conn);
 int connection_edge_send_command(connection_t *conn, circuit_t *circ, int relay_command);
-int connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ, int edge_type);
+int connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ, connection_t *conn, int edge_type);
 int connection_edge_finished_flushing(connection_t *conn);
 
 /********************************* connection_exit.c ***************************/
@@ -753,7 +763,7 @@
 int onion_pending_check(void);
 void onion_pending_process_one(void);
 void onion_pending_remove(circuit_t *circ);
-struct relay_queue_t *relay_queue_add(struct relay_queue_t *list, cell_t *cell);
+struct relay_queue_t *relay_queue_add(struct relay_queue_t *list, cell_t *cell, crypt_path_t *layer_hint);
 void onion_pending_relay_add(circuit_t *circ, cell_t *cell);
 
 /* uses a weighted coin with weight cw to choose a route length */