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

[or-cvs] Add reasons to DESTROY and RELAY_TRUNCATED cells.



Update of /home/or/cvsroot/tor/src/or
In directory moria:/tmp/cvs-serv29413/src/or

Modified Files:
	circuitbuild.c circuitlist.c circuituse.c command.c 
	connection.c connection_edge.c connection_or.c control.c 
	cpuworker.c onion.c or.h relay.c rendclient.c rendmid.c 
	rendservice.c 
Log Message:
Add reasons to DESTROY and RELAY_TRUNCATED cells.

Index: circuitbuild.c
===================================================================
RCS file: /home/or/cvsroot/tor/src/or/circuitbuild.c,v
retrieving revision 1.200
retrieving revision 1.201
diff -u -p -d -r1.200 -r1.201
--- circuitbuild.c	2 Jan 2006 11:33:14 -0000	1.200
+++ circuitbuild.c	5 Jan 2006 21:23:03 -0000	1.201
@@ -313,14 +313,14 @@ circuit_establish_circuit(uint8_t purpos
 
   if (onion_pick_cpath_exit(circ, info) < 0 ||
       onion_populate_cpath(circ) < 0) {
-    circuit_mark_for_close(circ);
+    circuit_mark_for_close(circ, END_CIRC_AT_ORIGIN);
     return NULL;
   }
 
   control_event_circuit_status(circ, CIRC_EVENT_LAUNCHED);
 
   if (circuit_handle_first_hop(circ) < 0) {
-    circuit_mark_for_close(circ);
+    circuit_mark_for_close(circ, END_CIRC_AT_ORIGIN);
     return NULL;
   }
   return circ;
@@ -420,7 +420,7 @@ circuit_n_conn_done(connection_t *or_con
                 DIGEST_LEN)) {
       if (!status) { /* or_conn failed; close circ */
         info(LD_CIRC,"or_conn failed. Closing circ.");
-        circuit_mark_for_close(circ);
+        circuit_mark_for_close(circ, END_CIRC_REASON_OR_IDENTITY);
         continue;
       }
       debug(LD_CIRC,"Found circ %d, sending create cell.", circ->n_circ_id);
@@ -432,7 +432,7 @@ circuit_n_conn_done(connection_t *or_con
         if (circuit_send_next_onion_skin(circ) < 0) {
           info(LD_CIRC,
                "send_next_onion_skin failed; circuit marked for closing.");
-          circuit_mark_for_close(circ);
+          circuit_mark_for_close(circ, END_CIRC_AT_ORIGIN);
           continue;
           /* XXX could this be bad, eg if next_onion_skin failed because conn
            *     died? */
@@ -441,7 +441,7 @@ circuit_n_conn_done(connection_t *or_con
         /* pull the create cell out of circ->onionskin, and send it */
         tor_assert(circ->onionskin);
         if (circuit_deliver_create_cell(circ,CELL_CREATE,circ->onionskin)<0) {
-          circuit_mark_for_close(circ);
+          circuit_mark_for_close(circ, END_CIRC_REASON_RESOURCELIMIT);
           continue;
         }
         tor_free(circ->onionskin);
@@ -537,7 +537,7 @@ extern int has_completed_circuit;
  * Otherwise, we need to build a relay extend cell and send it
  * forward.
  *
- * Return -1 if we want to tear down circ, else return 0.
+ * Return -reason if we want to tear down circ, else return 0.
  */
 int
 circuit_send_next_onion_skin(circuit_t *circ)
@@ -567,7 +567,7 @@ circuit_send_next_onion_skin(circuit_t *
                             &(circ->cpath->dh_handshake_state),
                             payload) < 0) {
         warn(LD_CIRC,"onion_skin_create (first hop) failed.");
-        return -1;
+        return - END_CIRC_REASON_INTERNAL;
       }
     } else {
       /* We are not an OR, and we're building the first hop of a circuit to a
@@ -582,7 +582,7 @@ circuit_send_next_onion_skin(circuit_t *
     }
 
     if (circuit_deliver_create_cell(circ, cell_type, payload) < 0)
-      return -1;
+      return - END_CIRC_REASON_RESOURCELIMIT;
 
     circ->cpath->state = CPATH_STATE_AWAITING_KEYS;
     circuit_set_state(circ, CIRCUIT_STATE_BUILDING);
@@ -625,7 +625,7 @@ circuit_send_next_onion_skin(circuit_t *
     if (onion_skin_create(hop->extend_info->onion_key,
                           &(hop->dh_handshake_state), onionskin) < 0) {
       warn(LD_CIRC,"onion_skin_create failed.");
-      return -1;
+      return - END_CIRC_REASON_INTERNAL;
     }
 
     debug(LD_CIRC,"Sending extend relay cell.");
@@ -719,7 +719,7 @@ circuit_extend(cell_t *cell, circuit_t *
       n_conn = connection_or_connect(circ->n_addr, circ->n_port, id_digest);
       if (!n_conn) {
         info(LD_CIRC,"Launching n_conn failed. Closing circuit.");
-        circuit_mark_for_close(circ);
+        circuit_mark_for_close(circ, END_CIRC_REASON_CONNECTFAILED);
         return 0;
       }
       debug(LD_CIRC,"connecting in progress (or finished). Good.");
@@ -801,7 +801,7 @@ circuit_init_cpath_crypto(crypt_path_t *
  * Calculate the appropriate keys and digests, make sure KH is
  * correct, and initialize this hop of the cpath.
  *
- * Return -1 if we want to mark circ for close, else return 0.
+ * Return - reason if we want to mark circ for close, else return 0.
  */
 int
 circuit_finish_handshake(circuit_t *circ, uint8_t reply_type, char *reply)
@@ -816,7 +816,7 @@ circuit_finish_handshake(circuit_t *circ
     hop = onion_next_hop_in_cpath(circ->cpath);
     if (!hop) { /* got an extended when we're all done? */
       warn(LD_PROTOCOL,"got extended when circ already built? Closing.");
-      return -1;
+      return - END_CIRC_REASON_TORPROTOCOL;
     }
   }
   tor_assert(hop->state == CPATH_STATE_AWAITING_KEYS);
@@ -825,7 +825,7 @@ circuit_finish_handshake(circuit_t *circ
     if (onion_skin_client_handshake(hop->dh_handshake_state, reply, keys,
                                     DIGEST_LEN*2+CIPHER_KEY_LEN*2) < 0) {
       warn(LD_CIRC,"onion_skin_client_handshake failed.");
-      return -1;
+      return -END_CIRC_REASON_TORPROTOCOL;
     }
     /* Remember hash of g^xy */
     memcpy(hop->handshake_digest, reply+DH_KEY_LEN, DIGEST_LEN);
@@ -833,12 +833,12 @@ circuit_finish_handshake(circuit_t *circ
     if (fast_client_handshake(hop->fast_handshake_state, reply, keys,
                               DIGEST_LEN*2+CIPHER_KEY_LEN*2) < 0) {
       warn(LD_CIRC,"fast_client_handshake failed.");
-      return -1;
+      return -END_CIRC_REASON_TORPROTOCOL;
     }
     memcpy(hop->handshake_digest, reply+DIGEST_LEN, DIGEST_LEN);
   } else {
     warn(LD_PROTOCOL,"CREATED cell type did not match CREATE cell type.");
-    return -1;
+    return -END_CIRC_REASON_TORPROTOCOL;
   }
 
   if (hop->dh_handshake_state) {
@@ -848,7 +848,7 @@ circuit_finish_handshake(circuit_t *circ
   memset(hop->fast_handshake_state, 0, sizeof(hop->fast_handshake_state));
 
   if (circuit_init_cpath_crypto(hop, keys, 0)<0) {
-    return -1;
+    return -END_CIRC_REASON_TORPROTOCOL;
   }
 
   hop->state = CPATH_STATE_OPEN;
@@ -880,7 +880,7 @@ circuit_truncated(circuit_t *circ, crypt
    *     means that a connection broke or an extend failed. For now,
    *     just give up.
    */
-  circuit_mark_for_close(circ);
+  circuit_mark_for_close(circ, END_CIRC_AT_ORIGIN);
   return 0;
 
 #if 0
@@ -1375,12 +1375,13 @@ circuit_append_new_exit(circuit_t *circ,
 int
 circuit_extend_to_new_exit(circuit_t *circ, extend_info_t *info)
 {
+  tor_assert(CIRCUIT_IS_ORIGIN(circ));
   circuit_append_new_exit(circ, info);
   circuit_set_state(circ, CIRCUIT_STATE_BUILDING);
   if (circuit_send_next_onion_skin(circ)<0) {
     warn(LD_CIRC, "Couldn't extend circuit to new point '%s'.",
          info->nickname);
-    circuit_mark_for_close(circ);
+    circuit_mark_for_close(circ, END_CIRC_AT_ORIGIN);
     return -1;
   }
   return 0;
@@ -1731,7 +1732,7 @@ static INLINE int
 is_an_entry_node(char *digest)
 {
   SMARTLIST_FOREACH(entry_nodes, entry_node_t *, entry,
-                    if(!memcmp(digest, entry->identity, DIGEST_LEN))
+                    if (!memcmp(digest, entry->identity, DIGEST_LEN))
                       return 1;
                    );
   return 0;

Index: circuitlist.c
===================================================================
RCS file: /home/or/cvsroot/tor/src/or/circuitlist.c,v
retrieving revision 1.88
retrieving revision 1.89
diff -u -p -d -r1.88 -r1.89
--- circuitlist.c	14 Dec 2005 20:40:40 -0000	1.88
+++ circuitlist.c	5 Jan 2006 21:23:03 -0000	1.89
@@ -470,7 +470,7 @@ circuit_get_by_edge_conn(connection_t *c
  * been marked already.
  */
 void
-circuit_unlink_all_from_or_conn(connection_t *conn)
+circuit_unlink_all_from_or_conn(connection_t *conn, int reason)
 {
   circuit_t *circ;
   for (circ = global_circuitlist; circ; circ = circ->next) {
@@ -480,7 +480,7 @@ circuit_unlink_all_from_or_conn(connecti
       if (circ->p_conn == conn)
         circuit_set_circid_orconn(circ, 0, NULL, P_CONN_CHANGED);
       if (!circ->marked_for_close)
-        circuit_mark_for_close(circ);
+        circuit_mark_for_close(circ, reason);
     }
   }
 }
@@ -607,7 +607,7 @@ circuit_mark_all_unused_circs(void)
     if (CIRCUIT_IS_ORIGIN(circ) &&
         !circ->marked_for_close &&
         !circ->timestamp_dirty)
-      circuit_mark_for_close(circ);
+      circuit_mark_for_close(circ, END_CIRC_AT_ORIGIN);
   }
 }
 
@@ -648,7 +648,8 @@ circuit_expire_all_dirty_circs(void)
  *     rendezvous stream), then mark the other circuit to close as well.
  */
 void
-_circuit_mark_for_close(circuit_t *circ, int line, const char *file)
+_circuit_mark_for_close(circuit_t *circ, int reason, int line,
+                        const char *file)
 {
   connection_t *conn;
 
@@ -663,6 +664,22 @@ _circuit_mark_for_close(circuit_t *circ,
         circ->marked_for_close_file, circ->marked_for_close);
     return;
   }
+  if (reason == END_CIRC_AT_ORIGIN) {
+    if (!CIRCUIT_IS_ORIGIN(circ)) {
+      warn(LD_BUG, "Specified 'at-origin' non-reason for ending circuit, "
+           "but circuit was not at origin. (called %s:%d, purpose=%d)",
+           file, line, circ->purpose);
+    }
+    reason = END_CIRC_REASON_NONE;
+  } else if (CIRCUIT_IS_ORIGIN(circ) && reason != END_CIRC_REASON_NONE) {
+    /* Don't warn about this; there are plenty of places where our code
+     * is origin-agnosic. */
+    reason = END_CIRC_REASON_NONE;
+  }
+  if (reason < _END_CIRC_REASON_MIN || reason > _END_CIRC_REASON_MAX) {
+    warn(LD_BUG, "Reason %d out of range at %s:%d", reason, file, line);
+    reason = END_CIRC_REASON_NONE;
+  }
 
   if (circ->state == CIRCUIT_STATE_ONIONSKIN_PENDING) {
     onion_pending_remove(circ);
@@ -698,7 +715,7 @@ _circuit_mark_for_close(circuit_t *circ,
   }
 
   if (circ->n_conn)
-    connection_send_destroy(circ->n_circ_id, circ->n_conn);
+    connection_or_send_destroy(circ->n_circ_id, circ->n_conn, reason);
   for (conn=circ->n_streams; conn; conn=conn->next_stream)
     connection_edge_destroy(circ->n_circ_id, conn);
   while (circ->resolving_streams) {
@@ -714,7 +731,7 @@ _circuit_mark_for_close(circuit_t *circ,
     conn->on_circuit = NULL;
   }
   if (circ->p_conn)
-    connection_send_destroy(circ->p_circ_id, circ->p_conn);
+    connection_or_send_destroy(circ->p_circ_id, circ->p_conn, reason);
   for (conn=circ->p_streams; conn; conn=conn->next_stream)
     connection_edge_destroy(circ->p_circ_id, conn);
 
@@ -724,7 +741,7 @@ _circuit_mark_for_close(circuit_t *circ,
   if (circ->rend_splice) {
     if (!circ->rend_splice->marked_for_close) {
       /* do this after marking this circuit, to avoid infinite recursion. */
-      circuit_mark_for_close(circ->rend_splice);
+      circuit_mark_for_close(circ->rend_splice, reason);
     }
     circ->rend_splice = NULL;
   }

Index: circuituse.c
===================================================================
RCS file: /home/or/cvsroot/tor/src/or/circuituse.c,v
retrieving revision 1.108
retrieving revision 1.109
diff -u -p -d -r1.108 -r1.109
--- circuituse.c	28 Dec 2005 09:07:31 -0000	1.108
+++ circuituse.c	5 Jan 2006 21:23:03 -0000	1.109
@@ -264,7 +264,7 @@ circuit_expire_building(time_t now)
            circuit_state_to_string(victim->state), victim->purpose);
 
     circuit_log_path(LOG_INFO,LD_CIRC,victim);
-    circuit_mark_for_close(victim);
+    circuit_mark_for_close(victim, END_CIRC_AT_ORIGIN);
   }
 }
 
@@ -523,7 +523,7 @@ circuit_about_to_close_connection(connec
       /* Inform any pending (not attached) circs that they should give up. */
       circuit_n_conn_done(conn, 0);
       /* Now close all the attached circuits on it. */
-      circuit_unlink_all_from_or_conn(conn);
+      circuit_unlink_all_from_or_conn(conn, END_CIRC_REASON_OR_CONN_CLOSED);
       return;
     }
     case CONN_TYPE_AP:
@@ -568,7 +568,7 @@ circuit_expire_old_circuits(void)
       /* (only general and purpose_c circs can get dirty) */
       tor_assert(!circ->n_streams);
       tor_assert(circ->purpose <= CIRCUIT_PURPOSE_C_REND_JOINED);
-      circuit_mark_for_close(circ);
+      circuit_mark_for_close(circ, END_CIRC_AT_ORIGIN);
     } else if (!circ->timestamp_dirty && CIRCUIT_IS_ORIGIN(circ) &&
                circ->state == CIRCUIT_STATE_OPEN &&
                circ->purpose == CIRCUIT_PURPOSE_C_GENERAL) {
@@ -576,7 +576,7 @@ circuit_expire_old_circuits(void)
       if (circ->timestamp_created + CIRCUIT_UNUSED_CIRC_TIMEOUT < now) {
         debug(LD_CIRC,"Closing circuit that has been unused for %d seconds.",
               (int)(now - circ->timestamp_created));
-        circuit_mark_for_close(circ);
+        circuit_mark_for_close(circ, END_CIRC_AT_ORIGIN);
       }
     }
   }
@@ -589,7 +589,7 @@ circuit_testing_opened(circuit_t *circ)
   /* For now, we only use testing circuits to see if our ORPort is
      reachable. But we remember reachability in onionskin_answer(),
      so there's no need to record anything here. Just close the circ. */
-  circuit_mark_for_close(circ);
+  circuit_mark_for_close(circ, END_CIRC_AT_ORIGIN);
 }
 
 /** A testing circuit has failed to build. Take whatever stats we want. */

Index: command.c
===================================================================
RCS file: /home/or/cvsroot/tor/src/or/command.c,v
retrieving revision 1.106
retrieving revision 1.107
diff -u -p -d -r1.106 -r1.107
--- command.c	31 Dec 2005 08:09:26 -0000	1.106
+++ command.c	5 Jan 2006 21:23:03 -0000	1.107
@@ -166,7 +166,8 @@ command_process_create_cell(cell_t *cell
   if (we_are_hibernating()) {
     info(LD_OR,"Received create cell but we're shutting down. Sending back "
          "destroy.");
-    connection_send_destroy(cell->circ_id, conn);
+    connection_or_send_destroy(cell->circ_id, conn,
+                               END_CIRC_REASON_HIBERNATING);
     return;
   }
 
@@ -214,7 +215,7 @@ command_process_create_cell(cell_t *cell
     /* hand it off to the cpuworkers, and then return */
     if (assign_to_cpuworker(NULL, CPUWORKER_TASK_ONION, circ) < 0) {
       warn(LD_GENERAL,"Failed to hand off onionskin. Closing.");
-      circuit_mark_for_close(circ);
+      circuit_mark_for_close(circ, END_CIRC_REASON_INTERNAL);
       return;
     }
     debug(LD_OR,"success: handed off onionskin.");
@@ -226,12 +227,12 @@ command_process_create_cell(cell_t *cell
     tor_assert(cell->command == CELL_CREATE_FAST);
     if (fast_server_handshake(cell->payload, reply, keys, sizeof(keys))<0) {
       warn(LD_OR,"Failed to generate key material. Closing.");
-      circuit_mark_for_close(circ);
+      circuit_mark_for_close(circ, END_CIRC_REASON_INTERNAL);
       return;
     }
     if (onionskin_answer(circ, CELL_CREATED_FAST, reply, keys)<0) {
       warn(LD_OR,"Failed to reply to CREATE_FAST cell. Closing.");
-      circuit_mark_for_close(circ);
+      circuit_mark_for_close(circ, END_CIRC_REASON_INTERNAL);
       return;
     }
   }
@@ -261,7 +262,7 @@ command_process_created_cell(cell_t *cel
   if (circ->n_circ_id != cell->circ_id) {
     log_fn(LOG_PROTOCOL_WARN,LD_PROTOCOL,
            "got created cell from OPward? Closing.");
-    circuit_mark_for_close(circ);
+    circuit_mark_for_close(circ, END_CIRC_REASON_TORPROTOCOL);
     return;
   }
 
@@ -269,13 +270,14 @@ command_process_created_cell(cell_t *cel
     debug(LD_OR,"at OP. Finishing handshake.");
     if (circuit_finish_handshake(circ, cell->command, cell->payload) < 0) {
       warn(LD_OR,"circuit_finish_handshake failed.");
-      circuit_mark_for_close(circ);
+      circuit_mark_for_close(circ, END_CIRC_AT_ORIGIN);
       return;
     }
     debug(LD_OR,"Moving to next skin.");
     if (circuit_send_next_onion_skin(circ) < 0) {
       info(LD_OR,"circuit_send_next_onion_skin failed.");
-      circuit_mark_for_close(circ); /* XXX push this circuit_close lower */
+      /* XXX push this circuit_close lower */
+      circuit_mark_for_close(circ, END_CIRC_AT_ORIGIN);
       return;
     }
   } else { /* pack it into an extended relay cell, and send it. */
@@ -293,6 +295,7 @@ static void
 command_process_relay_cell(cell_t *cell, connection_t *conn)
 {
   circuit_t *circ;
+  int reason;
 
   circ = circuit_get_by_circid_orconn(cell->circ_id, conn);
 
@@ -304,22 +307,24 @@ command_process_relay_cell(cell_t *cell,
 
   if (circ->state == CIRCUIT_STATE_ONIONSKIN_PENDING) {
     log_fn(LOG_PROTOCOL_WARN,LD_PROTOCOL,"circuit in create_wait. Closing.");
-    circuit_mark_for_close(circ);
+    circuit_mark_for_close(circ, END_CIRC_REASON_TORPROTOCOL);
     return;
   }
 
   if (cell->circ_id == circ->p_circ_id) { /* it's an outgoing cell */
-    if (circuit_receive_relay_cell(cell, circ, CELL_DIRECTION_OUT) < 0) {
+    if ((reason = circuit_receive_relay_cell(cell, circ,
+                                             CELL_DIRECTION_OUT)) < 0) {
       log_fn(LOG_PROTOCOL_WARN,LD_PROTOCOL,"circuit_receive_relay_cell "
              "(forward) failed. Closing.");
-      circuit_mark_for_close(circ);
+      circuit_mark_for_close(circ, -reason);
       return;
     }
   } else { /* it's an ingoing cell */
-    if (circuit_receive_relay_cell(cell, circ, CELL_DIRECTION_IN) < 0) {
+    if ((reason = circuit_receive_relay_cell(cell, circ,
+                                             CELL_DIRECTION_IN)) < 0) {
       log_fn(LOG_PROTOCOL_WARN,LD_PROTOCOL,"circuit_receive_relay_cell "
              "(backward) failed. Closing.");
-      circuit_mark_for_close(circ);
+      circuit_mark_for_close(circ, -reason);
       return;
     }
   }
@@ -342,9 +347,10 @@ static void
 command_process_destroy_cell(cell_t *cell, connection_t *conn)
 {
   circuit_t *circ;
+  uint8_t reason;
 
   circ = circuit_get_by_circid_orconn(cell->circ_id, conn);
-
+  reason = (uint8_t)cell->payload[0];
   if (!circ) {
     info(LD_OR,"unknown circuit %d on connection from %s:%d. Dropping.",
          cell->circ_id, conn->address, conn->port);
@@ -355,15 +361,17 @@ command_process_destroy_cell(cell_t *cel
   if (cell->circ_id == circ->p_circ_id) {
     /* the destroy came from behind */
     circuit_set_circid_orconn(circ, 0, NULL, P_CONN_CHANGED);
-    circuit_mark_for_close(circ);
+    circuit_mark_for_close(circ, reason);
   } else { /* the destroy came from ahead */
     circuit_set_circid_orconn(circ, 0, NULL, N_CONN_CHANGED);
     if (CIRCUIT_IS_ORIGIN(circ)) {
-      circuit_mark_for_close(circ);
+      circuit_mark_for_close(circ, reason);
     } else {
+      char payload[1];
       debug(LD_OR, "Delivering 'truncated' back.");
+      payload[0] = (char)reason;
       connection_edge_send_command(NULL, circ, RELAY_COMMAND_TRUNCATED,
-                                   NULL, 0, NULL);
+                                   payload, sizeof(payload), NULL);
     }
   }
 }

Index: connection.c
===================================================================
RCS file: /home/or/cvsroot/tor/src/or/connection.c,v
retrieving revision 1.430
retrieving revision 1.431
diff -u -p -d -r1.430 -r1.431
--- connection.c	5 Jan 2006 12:18:34 -0000	1.430
+++ connection.c	5 Jan 2006 21:23:03 -0000	1.431
@@ -1038,7 +1038,8 @@ connection_read_bucket_decrement(connect
   }
 }
 
-/** DOCDOC */
+/** If we have exhaused our global read bucket, or the read bucket for conn,
+ * stop reading. */
 static void
 connection_consider_empty_buckets(connection_t *conn)
 {
@@ -1546,7 +1547,8 @@ connection_write_to_buf(const char *stri
       /* if it failed, it means we have our package/delivery windows set
          wrong compared to our max outbuf size. close the whole circuit. */
       warn(LD_NET,"write_to_buf failed. Closing circuit (fd %d).", conn->s);
-      circuit_mark_for_close(circuit_get_by_edge_conn(conn));
+      circuit_mark_for_close(circuit_get_by_edge_conn(conn),
+                             END_CIRC_REASON_INTERNAL);
     } else {
       warn(LD_NET,"write_to_buf failed. Closing connection (fd %d).", conn->s);
       connection_mark_for_close(conn);
@@ -1784,28 +1786,6 @@ connection_state_is_connecting(connectio
   return 0;
 }
 
-/** Write a destroy cell with circ ID <b>circ_id</b> onto OR connection
- * <b>conn</b>.
- *
- * Return 0.
- */
-/*XXXX Why isn't this in connection_or.c?*/
-int
-connection_send_destroy(uint16_t circ_id, connection_t *conn)
-{
-  cell_t cell;
-
-  tor_assert(conn);
-  tor_assert(connection_speaks_cells(conn));
-
-  memset(&cell, 0, sizeof(cell_t));
-  cell.circ_id = circ_id;
-  cell.command = CELL_DESTROY;
-  debug(LD_OR,"Sending destroy (circID %d).", circ_id);
-  connection_or_write_cell_to_buf(&cell, conn);
-  return 0;
-}
-
 /** Alloocates a base64'ed authenticator for use in http or https
  * auth, based on the input string <b>authenticator</b>. Returns it
  * if success, else returns NULL. */
@@ -1829,9 +1809,12 @@ alloc_http_authenticator(const char *aut
   return base64_authenticator;
 }
 
-/** DOCDOC
- * XXXX ipv6 NM
+/** Given a socket handle, check whether the local address (sockname) of the
+ * socket is one that we've connected from before.  If so, double-check
+ * whether our address has changed and we need to generate keys.  If we do,
+ * call init_keys().
  */
+/* XXXX Handle IPv6, eventually. */
 static void
 client_check_address_changed(int sock)
 {

Index: connection_edge.c
===================================================================
RCS file: /home/or/cvsroot/tor/src/or/connection_edge.c,v
retrieving revision 1.376
retrieving revision 1.377
diff -u -p -d -r1.376 -r1.377
--- connection_edge.c	14 Dec 2005 20:40:40 -0000	1.376
+++ connection_edge.c	5 Jan 2006 21:23:03 -0000	1.377
@@ -1208,7 +1208,7 @@ connection_ap_handshake_send_begin(conne
   ap_conn->stream_id = get_unique_stream_id_by_circ(circ);
   if (ap_conn->stream_id==0) {
     connection_mark_unattached_ap(ap_conn, END_STREAM_REASON_INTERNAL);
-    circuit_mark_for_close(circ);
+    circuit_mark_for_close(circ, END_CIRC_REASON_RESOURCELIMIT);
     return -1;
   }
 
@@ -1254,7 +1254,7 @@ connection_ap_handshake_send_resolve(con
   ap_conn->stream_id = get_unique_stream_id_by_circ(circ);
   if (ap_conn->stream_id==0) {
     connection_mark_unattached_ap(ap_conn, END_STREAM_REASON_INTERNAL);
-    circuit_mark_for_close(circ);
+    circuit_mark_for_close(circ, END_CIRC_REASON_RESOURCELIMIT);
     return -1;
   }
 
@@ -1519,8 +1519,8 @@ connection_exit_begin_conn(cell_t *cell,
       connection_edge_end(n_stream, END_STREAM_REASON_EXITPOLICY,
                           n_stream->cpath_layer);
       connection_free(n_stream);
-      circuit_mark_for_close(circ); /* knock the whole thing down, somebody
-                                     * screwed up */
+      /* knock the whole thing down, somebody screwed up */
+      circuit_mark_for_close(circ, END_CIRC_REASON_CONNECTFAILED);
       tor_free(address);
       return 0;
     }

Index: connection_or.c
===================================================================
RCS file: /home/or/cvsroot/tor/src/or/connection_or.c,v
retrieving revision 1.207
retrieving revision 1.208
diff -u -p -d -r1.207 -r1.208
--- connection_or.c	28 Dec 2005 09:07:31 -0000	1.207
+++ connection_or.c	5 Jan 2006 21:23:03 -0000	1.208
@@ -779,3 +779,26 @@ loop:
   goto loop; /* process the remainder of the buffer */
 }
 
+/** Write a destroy cell with circ ID <b>circ_id</b> and reason <b>reason</b>
+ * onto OR connection <b>conn</b>.  Don't perform range-checking on reason:
+ * we may want to propagate reasons from other cells.
+ *
+ * Return 0.
+ */
+int
+connection_or_send_destroy(uint16_t circ_id, connection_t *conn, int reason)
+{
+  cell_t cell;
+
+  tor_assert(conn);
+  tor_assert(connection_speaks_cells(conn));
+
+  memset(&cell, 0, sizeof(cell_t));
+  cell.circ_id = circ_id;
+  cell.command = CELL_DESTROY;
+  cell.payload[0] = (uint8_t) reason;
+  debug(LD_OR,"Sending destroy (circID %d).", circ_id);
+  connection_or_write_cell_to_buf(&cell, conn);
+  return 0;
+}
+

Index: control.c
===================================================================
RCS file: /home/or/cvsroot/tor/src/or/control.c,v
retrieving revision 1.160
retrieving revision 1.161
diff -u -p -d -r1.160 -r1.161
--- control.c	28 Dec 2005 09:07:31 -0000	1.160
+++ control.c	5 Jan 2006 21:23:03 -0000	1.161
@@ -1611,7 +1611,7 @@ handle_control_extendcircuit(connection_
   /* now that we've populated the cpath, start extending */
   if (zero_circ) {
     if (circuit_handle_first_hop(circ) < 0) {
-      circuit_mark_for_close(circ);
+      circuit_mark_for_close(circ, END_CIRC_AT_ORIGIN);
       if (v0)
         send_control0_error(conn, ERR_INTERNAL, "couldn't start circuit");
       else
@@ -1624,7 +1624,7 @@ handle_control_extendcircuit(connection_
       if (circuit_send_next_onion_skin(circ) < 0) {
         info(LD_CONTROL,
              "send_next_onion_skin failed; circuit marked for closing.");
-        circuit_mark_for_close(circ);
+        circuit_mark_for_close(circ, END_CIRC_AT_ORIGIN);
         if (v0)
           send_control0_error(conn, ERR_INTERNAL, "couldn't send onion skin");
         else
@@ -1967,7 +1967,7 @@ handle_control_closecircuit(connection_t
   }
 
   if (!safe || !circ->p_streams) {
-    circuit_mark_for_close(circ);
+    circuit_mark_for_close(circ, END_CIRC_REASON_NONE);
   }
 
   send_control_done(conn);

Index: cpuworker.c
===================================================================
RCS file: /home/or/cvsroot/tor/src/or/cpuworker.c,v
retrieving revision 1.95
retrieving revision 1.96
diff -u -p -d -r1.95 -r1.96
--- cpuworker.c	26 Dec 2005 22:42:22 -0000	1.95
+++ cpuworker.c	5 Jan 2006 21:23:03 -0000	1.96
@@ -169,7 +169,7 @@ connection_cpu_process_inbuf(connection_
       debug(LD_OR,
             "decoding onionskin failed. (Old key or bad software.) Closing.");
       if (circ)
-        circuit_mark_for_close(circ);
+        circuit_mark_for_close(circ, END_CIRC_REASON_TORPROTOCOL);
       goto done_processing;
     }
     if (!circ) {
@@ -185,7 +185,7 @@ connection_cpu_process_inbuf(connection_
     if (onionskin_answer(circ, CELL_CREATED, buf+TAG_LEN,
                          buf+TAG_LEN+ONIONSKIN_REPLY_LEN) < 0) {
       warn(LD_OR,"onionskin_answer failed. Closing.");
-      circuit_mark_for_close(circ);
+      circuit_mark_for_close(circ, END_CIRC_REASON_INTERNAL);
       goto done_processing;
     }
     debug(LD_OR,"onionskin_answer succeeded. Yay.");

Index: onion.c
===================================================================
RCS file: /home/or/cvsroot/tor/src/or/onion.c,v
retrieving revision 1.192
retrieving revision 1.193
diff -u -p -d -r1.192 -r1.193
--- onion.c	14 Dec 2005 20:40:40 -0000	1.192
+++ onion.c	5 Jan 2006 21:23:03 -0000	1.193
@@ -71,7 +71,7 @@ onion_pending_add(circuit_t *circ)
     onion_pending_remove(ol_list->circ);
     info(LD_CIRC,
          "Circuit create request is too old; cancelling due to overload.");
-    circuit_mark_for_close(circ);
+    circuit_mark_for_close(circ, END_CIRC_REASON_RESOURCELIMIT);
   }
   return 0;
 }

Index: or.h
===================================================================
RCS file: /home/or/cvsroot/tor/src/or/or.h,v
retrieving revision 1.774
retrieving revision 1.775
diff -u -p -d -r1.774 -r1.775
--- or.h	4 Jan 2006 04:42:10 -0000	1.774
+++ or.h	5 Jan 2006 21:23:03 -0000	1.775
@@ -481,6 +481,19 @@ typedef enum {
 #define RESOLVED_TYPE_ERROR_TRANSIENT 0xF0
 #define RESOLVED_TYPE_ERROR 0xF1
 
+#define END_CIRC_AT_ORIGIN           -1
+#define _END_CIRC_REASON_MIN            0
+#define END_CIRC_REASON_NONE            0
+#define END_CIRC_REASON_TORPROTOCOL     1
+#define END_CIRC_REASON_INTERNAL        2
+#define END_CIRC_REASON_REQUESTED       3
+#define END_CIRC_REASON_HIBERNATING     4
+#define END_CIRC_REASON_RESOURCELIMIT   5
+#define END_CIRC_REASON_CONNECTFAILED   6
+#define END_CIRC_REASON_OR_IDENTITY     7
+#define END_CIRC_REASON_OR_CONN_CLOSED  8
+#define _END_CIRC_REASON_MAX            8
+
 /** Length of 'y' portion of 'y.onion' URL. */
 #define REND_SERVICE_ID_LEN 16
 
@@ -1494,7 +1507,7 @@ circuit_t *circuit_new(uint16_t p_circ_i
 circuit_t *circuit_get_by_circid_orconn(uint16_t circ_id, connection_t *conn);
 int circuit_id_used_on_conn(uint16_t circ_id, connection_t *conn);
 circuit_t *circuit_get_by_edge_conn(connection_t *conn);
-void circuit_unlink_all_from_or_conn(connection_t *conn);
+void circuit_unlink_all_from_or_conn(connection_t *conn, int reason);
 circuit_t *circuit_get_by_global_id(uint32_t id);
 circuit_t *circuit_get_by_rend_query_and_purpose(const char *rend_query,
                                                  uint8_t purpose);
@@ -1506,10 +1519,11 @@ circuit_t *circuit_find_to_cannibalize(u
                                        int need_capacity, int internal);
 void circuit_mark_all_unused_circs(void);
 void circuit_expire_all_dirty_circs(void);
-void _circuit_mark_for_close(circuit_t *circ, int line, const char *file);
+void _circuit_mark_for_close(circuit_t *circ, int reason,
+                             int line, const char *file);
 
-#define circuit_mark_for_close(c) \
-  _circuit_mark_for_close((c), __LINE__, _SHORT_FILE_)
+#define circuit_mark_for_close(c, reason)                               \
+  _circuit_mark_for_close((c), (reason), __LINE__, _SHORT_FILE_)
 
 void assert_cpath_layer_ok(const crypt_path_t *cp);
 void assert_circuit_ok(const circuit_t *c);
@@ -1651,7 +1665,6 @@ int connection_is_listener(connection_t 
 int connection_state_is_open(connection_t *conn);
 int connection_state_is_connecting(connection_t *conn);
 
-int connection_send_destroy(uint16_t circ_id, connection_t *conn);
 char *alloc_http_authenticator(const char *authenticator);
 
 void assert_connection_ok(connection_t *conn, time_t now);
@@ -1742,6 +1755,8 @@ int connection_tls_start_handshake(conne
 int connection_tls_continue_handshake(connection_t *conn);
 
 void connection_or_write_cell_to_buf(const cell_t *cell, connection_t *conn);
+int connection_or_send_destroy(uint16_t circ_id, connection_t *conn,
+                               int reason);
 
 /********************************* control.c ***************************/
 

Index: relay.c
===================================================================
RCS file: /home/or/cvsroot/tor/src/or/relay.c,v
retrieving revision 1.96
retrieving revision 1.97
diff -u -p -d -r1.96 -r1.97
--- relay.c	31 Dec 2005 08:09:26 -0000	1.96
+++ relay.c	5 Jan 2006 21:23:03 -0000	1.97
@@ -138,6 +138,8 @@ relay_crypt_one_payload(crypto_cipher_en
  *    connection_edge.
  *  - Else connection_or_write_cell_to_buf to the conn on the other
  *    side of the circuit.
+ *
+ * Return -reason on failure.
  */
 int
 circuit_receive_relay_cell(cell_t *cell, circuit_t *circ, int cell_direction)
@@ -145,6 +147,7 @@ circuit_receive_relay_cell(cell_t *cell,
   connection_t *conn=NULL;
   crypt_path_t *layer_hint=NULL;
   char recognized=0;
+  int reason;
 
   tor_assert(cell);
   tor_assert(circ);
@@ -163,20 +166,21 @@ circuit_receive_relay_cell(cell_t *cell,
     if (cell_direction == CELL_DIRECTION_OUT) {
       ++stats_n_relay_cells_delivered;
       debug(LD_OR,"Sending away from origin.");
-      if (connection_edge_process_relay_cell(cell, circ, conn, NULL) < 0) {
+      if ((reason=connection_edge_process_relay_cell(cell, circ, conn, NULL))
+          < 0) {
         log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
                "connection_edge_process_relay_cell (away from origin) "
                "failed.");
-        return -1;
+        return reason;
       }
     }
     if (cell_direction == CELL_DIRECTION_IN) {
       ++stats_n_relay_cells_delivered;
       debug(LD_OR,"Sending to origin.");
-      if (connection_edge_process_relay_cell(cell, circ, conn,
-                                             layer_hint) < 0) {
+      if ((reason = connection_edge_process_relay_cell(cell, circ, conn,
+                                                       layer_hint)) < 0) {
         warn(LD_OR,"connection_edge_process_relay_cell (at origin) failed.");
-        return -1;
+        return reason;
       }
     }
     return 0;
@@ -197,19 +201,19 @@ circuit_receive_relay_cell(cell_t *cell,
       tor_assert(circ->rend_splice->purpose ==
                  CIRCUIT_PURPOSE_REND_ESTABLISHED);
       cell->circ_id = circ->rend_splice->p_circ_id;
-      if (circuit_receive_relay_cell(cell, circ->rend_splice,
-                                     CELL_DIRECTION_IN) < 0) {
+      if ((reason = circuit_receive_relay_cell(cell, circ->rend_splice,
+                                               CELL_DIRECTION_IN)) < 0) {
         warn(LD_REND, "Error relaying cell across rendezvous; closing "
              "circuits");
         /* XXXX Do this here, or just return -1? */
-        circuit_mark_for_close(circ);
-        return -1;
+        circuit_mark_for_close(circ, -reason);
+        return reason;
       }
       return 0;
     }
     log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
            "Didn't recognize cell, but circ stops here! Closing circ.");
-    return -1;
+    return -END_CIRC_REASON_TORPROTOCOL;
   }
 
   debug(LD_OR,"Passing on unrecognized cell.");
@@ -489,7 +493,7 @@ connection_edge_send_command(connection_
   if (circuit_package_relay_cell(&cell, circ, cell_direction, cpath_layer)
       < 0) {
     warn(LD_BUG,"circuit_package_relay_cell failed. Closing.");
-    circuit_mark_for_close(circ);
+    circuit_mark_for_close(circ, END_CIRC_REASON_INTERNAL);
     return -1;
   }
   return 0;
@@ -655,7 +659,7 @@ connection_edge_process_end_not_open(
       warn(LD_PROTOCOL,
            "Got an end because of %s, but we're not an AP. Closing.",
            connection_edge_end_reason_str(reason));
-      return -1;
+      return - END_CIRC_REASON_TORPROTOCOL;
     }
     info(LD_APP,"Address '%s' refused due to '%s'. Considering retrying.",
          safe_str(conn->socks_request->address),
@@ -848,7 +852,7 @@ connection_edge_process_relay_cell_not_o
  * If <b>layer_hint</b> is defined, then we're the origin of the
  * circuit, and it specifies the hop that packaged <b>cell</b>.
  *
- * Return -1 if you want to warn and tear down the circuit, else 0.
+ * Return -reason if you want to warn and tear down the circuit, else 0.
  */
 static int
 connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ,
@@ -858,6 +862,7 @@ connection_edge_process_relay_cell(cell_
   static int num_seen=0;
   relay_header_t rh;
   unsigned domain = layer_hint?LD_APP:LD_EXIT;
+  int reason;
 
   tor_assert(cell);
   tor_assert(circ);
@@ -869,7 +874,7 @@ connection_edge_process_relay_cell(cell_
 
   if (rh.length > RELAY_PAYLOAD_SIZE) {
     warn(LD_PROTOCOL, "Relay cell length field too long. Closing circuit.");
-    return -1;
+    return - END_CIRC_REASON_TORPROTOCOL;
   }
 
   /* either conn is NULL, in which case we've got a control cell, or else
@@ -904,7 +909,7 @@ connection_edge_process_relay_cell(cell_
         connection_edge_end(conn, END_STREAM_REASON_TORPROTOCOL,
                             conn->cpath_layer);
         connection_mark_for_close(conn);
-        return -1;
+        return -END_CIRC_REASON_TORPROTOCOL;
       }
       debug(domain,"circ deliver_window now %d.", layer_hint ?
             layer_hint->deliver_window : circ->deliver_window);
@@ -919,7 +924,7 @@ connection_edge_process_relay_cell(cell_
       if (--conn->deliver_window < 0) { /* is it below 0 after decrement? */
         log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
                "(relay data) conn deliver_window below 0. Killing.");
-        return -1; /* somebody's breaking protocol. kill the whole circuit. */
+        return -END_CIRC_REASON_TORPROTOCOL;
       }
 
       stats_n_data_bytes_received += rh.length;
@@ -974,14 +979,14 @@ connection_edge_process_relay_cell(cell_
         return 0;
       }
       debug(domain,"Got an extended cell! Yay.");
-      if (circuit_finish_handshake(circ, CELL_CREATED,
-                                   cell->payload+RELAY_HEADER_SIZE) < 0) {
+      if ((reason = circuit_finish_handshake(circ, CELL_CREATED,
+                                       cell->payload+RELAY_HEADER_SIZE)) < 0) {
         warn(domain,"circuit_finish_handshake failed.");
-        return -1;
+        return reason;
       }
-      if (circuit_send_next_onion_skin(circ)<0) {
+      if ((reason=circuit_send_next_onion_skin(circ))<0) {
         info(domain,"circuit_send_next_onion_skin() failed.");
-        return -1;
+        return reason;
       }
       return 0;
     case RELAY_COMMAND_TRUNCATE:
@@ -990,12 +995,17 @@ connection_edge_process_relay_cell(cell_
         return 0;
       }
       if (circ->n_conn) {
-        connection_send_destroy(circ->n_circ_id, circ->n_conn);
+        uint8_t reason = *(uint8_t*)(cell->payload + RELAY_HEADER_SIZE);
+        connection_or_send_destroy(circ->n_circ_id, circ->n_conn, reason);
         circuit_set_circid_orconn(circ, 0, NULL, N_CONN_CHANGED);
       }
       debug(LD_EXIT, "Processed 'truncate', replying.");
-      connection_edge_send_command(NULL, circ, RELAY_COMMAND_TRUNCATED,
-                                   NULL, 0, NULL);
+      {
+        char payload[1];
+        payload[0] = (char)END_CIRC_REASON_REQUESTED;
+        connection_edge_send_command(NULL, circ, RELAY_COMMAND_TRUNCATED,
+                                     payload, sizeof(payload), NULL);
+      }
       return 0;
     case RELAY_COMMAND_TRUNCATED:
       if (!layer_hint) {
@@ -1008,7 +1018,7 @@ connection_edge_process_relay_cell(cell_
       if (conn) {
         log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
                "'connected' unsupported while open. Closing circ.");
-        return -1;
+        return -END_CIRC_REASON_TORPROTOCOL;
       }
       info(domain,"'connected' received, no conn attached anymore. Ignoring.");
       return 0;
@@ -1055,7 +1065,7 @@ connection_edge_process_relay_cell(cell_
     case RELAY_COMMAND_RESOLVED:
       if (conn) {
         warn(domain,"'resolved' unsupported while open. Closing circ.");
-        return -1;
+        return -END_CIRC_REASON_TORPROTOCOL;
       }
       info(domain,"'resolved' received, no conn attached anymore. Ignoring.");
       return 0;

Index: rendclient.c
===================================================================
RCS file: /home/or/cvsroot/tor/src/or/rendclient.c,v
retrieving revision 1.101
retrieving revision 1.102
diff -u -p -d -r1.101 -r1.102
--- rendclient.c	19 Dec 2005 00:35:18 -0000	1.101
+++ rendclient.c	5 Jan 2006 21:23:03 -0000	1.102
@@ -35,7 +35,7 @@ rend_client_send_establish_rendezvous(ci
 
   if (crypto_rand(circ->rend_cookie, REND_COOKIE_LEN) < 0) {
     warn(LD_BUG, "Internal error: Couldn't produce random cookie.");
-    circuit_mark_for_close(circ);
+    circuit_mark_for_close(circ, END_CIRC_AT_ORIGIN);
     return -1;
   }
   if (connection_edge_send_command(NULL,circ,
@@ -154,8 +154,8 @@ rend_client_send_introduction(circuit_t 
 
   return 0;
 err:
-  circuit_mark_for_close(introcirc);
-  circuit_mark_for_close(rendcirc);
+  circuit_mark_for_close(introcirc, END_CIRC_AT_ORIGIN);
+  circuit_mark_for_close(rendcirc, END_CIRC_AT_ORIGIN);
   return -1;
 }
 
@@ -186,7 +186,7 @@ rend_client_introduction_acked(circuit_t
   if (circ->purpose != CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT) {
     warn(LD_PROTOCOL, "Received REND_INTRODUCE_ACK on unexpected circuit %d.",
          circ->n_circ_id);
-    circuit_mark_for_close(circ);
+    circuit_mark_for_close(circ, END_CIRC_AT_ORIGIN);
     return -1;
   }
 
@@ -208,7 +208,7 @@ rend_client_introduction_acked(circuit_t
     }
     /* close the circuit: we won't need it anymore. */
     circ->purpose = CIRCUIT_PURPOSE_C_INTRODUCE_ACKED;
-    circuit_mark_for_close(circ);
+    circuit_mark_for_close(circ, END_CIRC_AT_ORIGIN);
   } else {
     /* It's a NAK; the introduction point didn't relay our request. */
     circ->purpose = CIRCUIT_PURPOSE_C_INTRODUCING;
@@ -226,7 +226,7 @@ rend_client_introduction_acked(circuit_t
       if (!extend_info) {
         warn(LD_REND, "No introduction points left for %s. Closing.",
              safe_str(circ->rend_query));
-        circuit_mark_for_close(circ);
+        circuit_mark_for_close(circ, END_CIRC_AT_ORIGIN);
         return -1;
       }
       info(LD_REND,
@@ -340,7 +340,7 @@ rend_client_rendezvous_acked(circuit_t *
   if (circ->purpose != CIRCUIT_PURPOSE_C_ESTABLISH_REND) {
     warn(LD_PROTOCOL,"Got a rendezvous ack when we weren't expecting one. "
          "Closing circ.");
-    circuit_mark_for_close(circ);
+    circuit_mark_for_close(circ, END_CIRC_AT_ORIGIN);
     return -1;
   }
   info(LD_REND,"Got rendezvous ack. This circuit is now ready for "
@@ -362,7 +362,7 @@ rend_client_receive_rendezvous(circuit_t
       || !circ->build_state->pending_final_cpath) {
     warn(LD_PROTOCOL,"Got rendezvous2 cell from hidden service, but not "
          "expecting it. Closing.");
-    circuit_mark_for_close(circ);
+    circuit_mark_for_close(circ, END_CIRC_AT_ORIGIN);
     return -1;
   }
 
@@ -408,7 +408,7 @@ rend_client_receive_rendezvous(circuit_t
   circ->build_state->pending_final_cpath = NULL; /* prevent double-free */
   return 0;
  err:
-  circuit_mark_for_close(circ);
+  circuit_mark_for_close(circ, END_CIRC_AT_ORIGIN);
   return -1;
 }
 

Index: rendmid.c
===================================================================
RCS file: /home/or/cvsroot/tor/src/or/rendmid.c,v
retrieving revision 1.46
retrieving revision 1.47
diff -u -p -d -r1.46 -r1.47
--- rendmid.c	14 Dec 2005 20:40:40 -0000	1.46
+++ rendmid.c	5 Jan 2006 21:23:03 -0000	1.47
@@ -25,6 +25,7 @@ rend_mid_establish_intro(circuit_t *circ
   size_t asn1len;
   circuit_t *c;
   char serviceid[REND_SERVICE_ID_LEN+1];
+  int reason = END_CIRC_REASON_INTERNAL;
 
   info(LD_REND,
        "Received an ESTABLISH_INTRO request on circuit %d", circ->p_circ_id);
@@ -32,6 +33,7 @@ rend_mid_establish_intro(circuit_t *circ
   if (circ->purpose != CIRCUIT_PURPOSE_OR || circ->n_conn) {
     warn(LD_PROTOCOL,
          "Rejecting ESTABLISH_INTRO on non-OR or non-edge circuit.");
+    reason = END_CIRC_REASON_TORPROTOCOL;
     goto err;
   }
   if (request_len < 2+DIGEST_LEN)
@@ -44,6 +46,7 @@ rend_mid_establish_intro(circuit_t *circ
     goto truncated;
   pk = crypto_pk_asn1_decode(request+2, asn1len);
   if (!pk) {
+    reason = END_CIRC_REASON_TORPROTOCOL;
     warn(LD_PROTOCOL, "Couldn't decode public key.");
     goto err;
   }
@@ -57,6 +60,7 @@ rend_mid_establish_intro(circuit_t *circ
   }
   if (memcmp(expected_digest, request+2+asn1len, DIGEST_LEN)) {
     warn(LD_PROTOCOL, "Hash of session info was not as expected.");
+    reason = END_CIRC_REASON_TORPROTOCOL;
     goto err;
   }
   /* Rest of body: signature of previous data */
@@ -65,6 +69,7 @@ rend_mid_establish_intro(circuit_t *circ
                                        request_len-(2+DIGEST_LEN+asn1len))<0) {
     warn(LD_PROTOCOL,
          "Incorrect signature on ESTABLISH_INTRO cell; rejecting.");
+    reason = END_CIRC_REASON_TORPROTOCOL;
     goto err;
   }
 
@@ -85,7 +90,7 @@ rend_mid_establish_intro(circuit_t *circ
                                 c,pk_digest,CIRCUIT_PURPOSE_INTRO_POINT))) {
     info(LD_REND, "Replacing old circuit %d for service %s",
          c->p_circ_id, safe_str(serviceid));
-    circuit_mark_for_close(c);
+    circuit_mark_for_close(c, END_CIRC_REASON_REQUESTED);
   }
 
   /* Acknowledge the request. */
@@ -107,9 +112,10 @@ rend_mid_establish_intro(circuit_t *circ
   return 0;
  truncated:
   warn(LD_PROTOCOL, "Rejecting truncated ESTABLISH_INTRO cell.");
+  reason = END_CIRC_REASON_TORPROTOCOL;
  err:
   if (pk) crypto_free_pk_env(pk);
-  circuit_mark_for_close(circ);
+  circuit_mark_for_close(circ, reason);
   return -1;
 }
 
@@ -168,7 +174,7 @@ rend_mid_introduce(circuit_t *circ, cons
   if (connection_edge_send_command(NULL,circ,RELAY_COMMAND_INTRODUCE_ACK,
                                    NULL,0,NULL)) {
     warn(LD_GENERAL, "Unable to send INTRODUCE_ACK cell to Tor client.");
-    circuit_mark_for_close(circ);
+    circuit_mark_for_close(circ, END_CIRC_REASON_INTERNAL);
     return -1;
   }
 
@@ -179,7 +185,8 @@ rend_mid_introduce(circuit_t *circ, cons
   if (connection_edge_send_command(NULL,circ,RELAY_COMMAND_INTRODUCE_ACK,
                                    nak_body, 1, NULL)) {
     warn(LD_GENERAL, "Unable to send NAK to Tor client.");
-    circuit_mark_for_close(circ); /* Is this right? */
+    /* Is this right? */
+    circuit_mark_for_close(circ, END_CIRC_REASON_INTERNAL);
   }
   return -1;
 }
@@ -192,6 +199,7 @@ rend_mid_establish_rendezvous(circuit_t 
                               size_t request_len)
 {
   char hexid[9];
+  int reason = END_CIRC_REASON_TORPROTOCOL;
 
   if (circ->purpose != CIRCUIT_PURPOSE_OR || circ->n_conn) {
     warn(LD_PROTOCOL,
@@ -214,6 +222,7 @@ rend_mid_establish_rendezvous(circuit_t 
                                    RELAY_COMMAND_RENDEZVOUS_ESTABLISHED,
                                    "", 0, NULL)<0) {
     warn(LD_PROTOCOL, "Couldn't send RENDEZVOUS_ESTABLISHED cell.");
+    reason = END_CIRC_REASON_INTERNAL;
     goto err;
   }
 
@@ -227,7 +236,7 @@ rend_mid_establish_rendezvous(circuit_t 
 
   return 0;
  err:
-  circuit_mark_for_close(circ);
+  circuit_mark_for_close(circ, reason);
   return -1;
 }
 
@@ -240,7 +249,7 @@ rend_mid_rendezvous(circuit_t *circ, con
 {
   circuit_t *rend_circ;
   char hexid[9];
-
+  int reason = END_CIRC_REASON_INTERNAL;
   base16_encode(hexid,9,request,request_len<4?request_len:4);
 
   if (request_len>=4) {
@@ -252,6 +261,7 @@ rend_mid_rendezvous(circuit_t *circ, con
     info(LD_REND,
          "Tried to complete rendezvous on non-OR or non-edge circuit %d.",
          circ->p_circ_id);
+    reason = END_CIRC_REASON_TORPROTOCOL;
     goto err;
   }
 
@@ -259,6 +269,7 @@ rend_mid_rendezvous(circuit_t *circ, con
     warn(LD_PROTOCOL,
          "Rejecting RENDEZVOUS1 cell with bad length (%d) on circuit %d.",
          (int)request_len, circ->p_circ_id);
+    reason = END_CIRC_REASON_TORPROTOCOL;
     goto err;
   }
 
@@ -267,6 +278,7 @@ rend_mid_rendezvous(circuit_t *circ, con
     warn(LD_PROTOCOL,
          "Rejecting RENDEZVOUS1 cell with unrecognized rendezvous cookie %s.",
          hexid);
+    reason = END_CIRC_REASON_TORPROTOCOL;
     goto err;
   }
 
@@ -295,7 +307,7 @@ rend_mid_rendezvous(circuit_t *circ, con
 
   return 0;
  err:
-  circuit_mark_for_close(circ);
+  circuit_mark_for_close(circ, reason);
   return -1;
 }
 

Index: rendservice.c
===================================================================
RCS file: /home/or/cvsroot/tor/src/or/rendservice.c,v
retrieving revision 1.150
retrieving revision 1.151
diff -u -p -d -r1.150 -r1.151
--- rendservice.c	14 Dec 2005 20:40:40 -0000	1.150
+++ rendservice.c	5 Jan 2006 21:23:03 -0000	1.151
@@ -605,7 +605,7 @@ rend_service_introduce(circuit_t *circui
   return 0;
  err:
   if (dh) crypto_dh_free(dh);
-  if (launched) circuit_mark_for_close(launched);
+  if (launched) circuit_mark_for_close(launched, END_CIRC_AT_ORIGIN);
   if (extend_info) extend_info_free(extend_info);
   return -1;
 }
@@ -751,7 +751,7 @@ rend_service_intro_has_opened(circuit_t 
 
   return;
  err:
-  circuit_mark_for_close(circuit);
+  circuit_mark_for_close(circuit, END_CIRC_AT_ORIGIN);
 }
 
 /** Called when we get an INTRO_ESTABLISHED cell; mark the circuit as a
@@ -778,7 +778,7 @@ rend_service_intro_established(circuit_t
 
   return 0;
  err:
-  circuit_mark_for_close(circuit);
+  circuit_mark_for_close(circuit, END_CIRC_AT_ORIGIN);
   return -1;
 }
 
@@ -852,7 +852,7 @@ rend_service_rendezvous_has_opened(circu
 
   return;
  err:
-  circuit_mark_for_close(circuit);
+  circuit_mark_for_close(circuit, END_CIRC_AT_ORIGIN);
 }
 
 /*