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

[or-cvs] r8672: Touch up last patch (to add REASON to CIRC events): make som (in tor/trunk: . doc src/or)



Author: nickm
Date: 2006-10-09 11:47:50 -0400 (Mon, 09 Oct 2006)
New Revision: 8672

Modified:
   tor/trunk/
   tor/trunk/ChangeLog
   tor/trunk/doc/TODO
   tor/trunk/doc/control-spec.txt
   tor/trunk/src/or/circuitbuild.c
   tor/trunk/src/or/circuitlist.c
   tor/trunk/src/or/circuituse.c
   tor/trunk/src/or/control.c
   tor/trunk/src/or/or.h
   tor/trunk/src/or/rendservice.c
Log:
 r8973@totoro:  nickm | 2006-10-09 11:45:47 -0400
 Touch up last patch (to add REASON to CIRC events): make some reasons
 more sensible, send reasons only to controllers that have enabled
 extended events, and clean up whitespace.
 
 



Property changes on: tor/trunk
___________________________________________________________________
 svk:merge ticket from /tor/trunk [r8973] on 96637b51-b116-0410-a10e-9941ebb49b64

Modified: tor/trunk/ChangeLog
===================================================================
--- tor/trunk/ChangeLog	2006-10-09 15:47:27 UTC (rev 8671)
+++ tor/trunk/ChangeLog	2006-10-09 15:47:50 UTC (rev 8672)
@@ -1,6 +1,8 @@
 Changes in version 0.1.2.3-alpha - 2006-10-??
   o Minor features, controller:
-    - Add a REASON field to CIRC events. (Patch from Mike Perry)
+    - Add a REASON field to CIRC events; for backward compatibility, this
+      field is sent only to controllers that have enabled the extended
+      event format. (Patch from Mike Perry)
 
   o Minor bugfixes:
     - Change NT service functions to be loaded on demand.  This lets us

Modified: tor/trunk/doc/TODO
===================================================================
--- tor/trunk/doc/TODO	2006-10-09 15:47:27 UTC (rev 8671)
+++ tor/trunk/doc/TODO	2006-10-09 15:47:50 UTC (rev 8672)
@@ -58,6 +58,11 @@
 
 N - Send back RELAY_END cells on malformed RELAY_BEGIN.
 
+N - Change the circuit end reason display a little for reasons from
+    destroyed/truncated circuits.  We want to indicate both that we're
+    closing because somebody told us to, and why they told us they wanted to
+    close.
+
 x - We should ship with a list of stable dir mirrors -- they're not
     trusted like the authorities, but they'll provide more robustness
     and diversity for bootstrapping clients.

Modified: tor/trunk/doc/control-spec.txt
===================================================================
--- tor/trunk/doc/control-spec.txt	2006-10-09 15:47:27 UTC (rev 8671)
+++ tor/trunk/doc/control-spec.txt	2006-10-09 15:47:50 UTC (rev 8672)
@@ -751,7 +751,7 @@
 
    The syntax is:
 
-     "650" SP "CIRC" SP CircuitID SP CircStatus [SP Path] 
+     "650" SP "CIRC" SP CircuitID SP CircStatus [SP Path]
           [SP "REASON=" Reason] CRLF
 
       CircStatus =
@@ -763,15 +763,19 @@
 
       Path = ServerID *("," ServerID)
 
-      Reason = "NONE" / "TORPROTOCOL" / "INTERNAL" / "REQUESTED" / 
+      Reason = "NONE" / "TORPROTOCOL" / "INTERNAL" / "REQUESTED" /
                "HIBERNATING" / "RESOURCELIMIT" / "CONNECTFAILED" /
                "OR_IDENTITY" / "OR_CONN_CLOSED"
 
    The path is provided only when the circuit has been extended at least one
    hop.
 
-   Reason is provided only for FAILED and CLOSED events.
+   The "REASON" field is provided only for FAILED and CLOSED events, and only
+   if extended events are enabled (see 3.19).  Clients MUST accept reasons
+   not listed above.
 
+   [XXXX Explain what the reasons mean.]
+
 4.1.2. Stream status changed
 
     The syntax is:

Modified: tor/trunk/src/or/circuitbuild.c
===================================================================
--- tor/trunk/src/or/circuitbuild.c	2006-10-09 15:47:27 UTC (rev 8671)
+++ tor/trunk/src/or/circuitbuild.c	2006-10-09 15:47:50 UTC (rev 8672)
@@ -305,6 +305,7 @@
 
   if (onion_pick_cpath_exit(circ, info) < 0 ||
       onion_populate_cpath(circ) < 0) {
+    /* XXX should there be a 'couldn't build a path' reason? */
     circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_INTERNAL);
     return NULL;
   }
@@ -425,7 +426,8 @@
        * set_circid_orconn here. */
       circ->n_conn = or_conn;
       if (CIRCUIT_IS_ORIGIN(circ)) {
-        if ((err_reason = circuit_send_next_onion_skin(TO_ORIGIN_CIRCUIT(circ))) < 0) {
+        if ((err_reason =
+             circuit_send_next_onion_skin(TO_ORIGIN_CIRCUIT(circ))) < 0) {
           log_info(LD_CIRC,
                    "send_next_onion_skin failed; circuit marked for closing.");
           circuit_mark_for_close(circ, -err_reason);
@@ -892,7 +894,7 @@
    *     means that a connection broke or an extend failed. For now,
    *     just give up.
    */
-  circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_TORPROTOCOL);
+  circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_OR_CONN_CLOSED);
   return 0;
 
 #if 0

Modified: tor/trunk/src/or/circuitlist.c
===================================================================
--- tor/trunk/src/or/circuitlist.c	2006-10-09 15:47:27 UTC (rev 8671)
+++ tor/trunk/src/or/circuitlist.c	2006-10-09 15:47:50 UTC (rev 8672)
@@ -824,7 +824,7 @@
 _circuit_mark_for_close(circuit_t *circ, int reason, int line,
                         const char *file)
 {
-  int orig_reason = reason;
+  int orig_reason = reason; /* Passed to the controller */
   assert_circuit_ok(circ);
   tor_assert(line);
   tor_assert(file);
@@ -844,10 +844,8 @@
     }
     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-agnostic. */
-    /* In fact, due to the desire to export reason information to the 
-     * controller, it has been made even more "origin-agnostic" than before */
+    /* We don't send reasons when closing circuits at the origin, but we want
+     * to track them anyway so we can give them to the controller. */
     reason = END_CIRC_REASON_NONE;
   }
   if (reason < _END_CIRC_REASON_MIN || reason > _END_CIRC_REASON_MAX) {

Modified: tor/trunk/src/or/circuituse.c
===================================================================
--- tor/trunk/src/or/circuituse.c	2006-10-09 15:47:27 UTC (rev 8671)
+++ tor/trunk/src/or/circuituse.c	2006-10-09 15:47:50 UTC (rev 8672)
@@ -265,6 +265,7 @@
                circuit_state_to_string(victim->state), victim->purpose);
 
     circuit_log_path(LOG_INFO,LD_CIRC,TO_ORIGIN_CIRCUIT(victim));
+    /* XXXX Should there be a timeout reason? CONNECTFAILED isn't right. */
     circuit_mark_for_close(victim, END_CIRC_REASON_CONNECTFAILED);
   }
 }
@@ -583,6 +584,7 @@
       log_debug(LD_CIRC, "Closing n_circ_id %d (dirty %d secs ago, purp %d)",
                 circ->n_circ_id, (int)(now - circ->timestamp_dirty),
                 circ->purpose);
+      /* XXXX Should there be a timeout reason? REQUESTED isn't right. */
       circuit_mark_for_close(circ, END_CIRC_REASON_REQUESTED);
     } else if (!circ->timestamp_dirty &&
                circ->state == CIRCUIT_STATE_OPEN &&
@@ -591,6 +593,7 @@
         log_debug(LD_CIRC,
                   "Closing circuit that has been unused for %d seconds.",
                   (int)(now - circ->timestamp_created));
+        /* XXXX Should there be a timeout reason? REQUESTED isn't right. */
         circuit_mark_for_close(circ, END_CIRC_REASON_REQUESTED);
       }
     }

Modified: tor/trunk/src/or/control.c
===================================================================
--- tor/trunk/src/or/control.c	2006-10-09 15:47:27 UTC (rev 8671)
+++ tor/trunk/src/or/control.c	2006-10-09 15:47:50 UTC (rev 8672)
@@ -144,9 +144,13 @@
 static int authentication_cookie_is_set = 0;
 static char authentication_cookie[AUTHENTICATION_COOKIE_LEN];
 
-typedef enum {
-  SHORT_NAMES,LONG_NAMES,ALL_NAMES
-} name_type_t;
+#define SHORT_NAMES 1
+#define LONG_NAMES 2
+#define ALL_NAMES (SHORT_NAMES|LONG_NAMES)
+#define EXTENDED_FORMAT 4
+#define NONEXTENDED_FORMAT 8
+#define ALL_FORMATS (EXTENDED_FORMAT|NONEXTENDED_FORMAT)
+typedef int event_format_t;
 
 static void connection_printf_to_buf(control_connection_t *conn,
                                      const char *format, ...)
@@ -164,9 +168,12 @@
                                const char *message);
 static void send_control0_event(uint16_t event, uint32_t len,
                                 const char *body);
-static void send_control1_event(uint16_t event, name_type_t which,
+static void send_control1_event(uint16_t event, event_format_t which,
                                 const char *format, ...)
   CHECK_PRINTF(3,4);
+static void send_control1_event_extended(uint16_t event, event_format_t which,
+                                         const char *format, ...)
+  CHECK_PRINTF(3,4);
 static int handle_control_setconf(control_connection_t *conn, uint32_t len,
                                   char *body);
 static int handle_control_resetconf(control_connection_t *conn, uint32_t len,
@@ -614,9 +621,12 @@
 }
 
 /* Send an event to all v1 controllers that are listening for code
- * <b>event</b>.  The event's body is given by <b>msg</b>. */
+ * <b>event</b>.  The event's body is given by <b>msg</b>.
+ *
+ * docdoc which, is_extended */
 static void
-send_control1_event_string(uint16_t event, name_type_t which, const char *msg)
+send_control1_event_string(uint16_t event, event_format_t which,
+                           const char *msg)
 {
   connection_t **conns;
   int n_conns, i;
@@ -629,13 +639,20 @@
         !conns[i]->marked_for_close &&
         conns[i]->state == CONTROL_CONN_STATE_OPEN_V1) {
       control_connection_t *control_conn = TO_CONTROL_CONN(conns[i]);
-      if (which == SHORT_NAMES) {
-        if (control_conn->use_long_names)
+      if (control_conn->use_long_names) {
+        if (!(which & LONG_NAMES))
           continue;
-      } else if (which == LONG_NAMES) {
-        if (! control_conn->use_long_names)
+      } else {
+        if (!(which & SHORT_NAMES))
           continue;
       }
+      if (control_conn->use_extended_events) {
+        if (!(which & EXTENDED_FORMAT))
+          continue;
+      } else {
+        if (!(which & NONEXTENDED_FORMAT))
+          continue;
+      }
       if (control_conn->event_mask & (1<<event)) {
         connection_write_to_buf(msg, strlen(msg), TO_CONN(control_conn));
         if (event == EVENT_ERR_MSG)
@@ -645,24 +662,17 @@
   }
 }
 
-/* Send an event to all v1 controllers that are listening for code
- * <b>event</b>.  The event's body is created by the printf-style format in
- * <b>format</b>, and other arguments as provided.
- *
- * Currently the length of the message is limited to 1024 (including the
- * ending \n\r\0. */
 static void
-send_control1_event(uint16_t event, name_type_t which, const char *format, ...)
+send_control1_event_impl(uint16_t event, event_format_t which, int extended,
+                         const char *format, va_list ap)
 {
 #define SEND_CONTROL1_EVENT_BUFFERSIZE 1024
   int r;
   char buf[SEND_CONTROL1_EVENT_BUFFERSIZE]; /* XXXX Length */
-  va_list ap;
   size_t len;
+  char *cp;
 
-  va_start(ap, format);
   r = tor_vsnprintf(buf, sizeof(buf), format, ap);
-  va_end(ap);
   if (r<0) {
     log_warn(LD_BUG, "Unable to format event for controller.");
     return;
@@ -676,9 +686,53 @@
     buf[SEND_CONTROL1_EVENT_BUFFERSIZE-3] = '\r';
   }
 
-  send_control1_event_string(event, which, buf);
+  if (extended && (cp = strchr(buf, '@'))) {
+    which &= ~ALL_FORMATS;
+    *cp = ' ';
+    send_control1_event_string(event, which|EXTENDED_FORMAT, buf);
+    memcpy(cp, "\r\n\0", 3);
+    send_control1_event_string(event, which|NONEXTENDED_FORMAT, buf);
+  } else {
+    send_control1_event_string(event, which|ALL_FORMATS, buf);
+  }
 }
 
+/* Send an event to all v1 controllers that are listening for code
+ * <b>event</b>.  The event's body is created by the printf-style format in
+ * <b>format</b>, and other arguments as provided.
+ *
+ * Currently the length of the message is limited to 1024 (including the
+ * ending \n\r\0. */
+static void
+send_control1_event(uint16_t event, event_format_t which,
+                    const char *format, ...)
+{
+  va_list ap;
+  va_start(ap, format);
+  send_control1_event_impl(event, which, 0, format, ap);
+  va_end(ap);
+}
+
+/* Send an event to all v1 controllers that are listening for code
+ * <b>event</b>.  The event's body is created by the printf-style format in
+ * <b>format</b>, and other arguments as provided.
+ *
+ * If the format contains a single '@' character, it will be replaced with a
+ * space and all text after that character will be sent only to controllers
+ * that have enabled extended events.
+ *
+ * Currently the length of the message is limited to 1024 (including the
+ * ending \n\r\0. */
+static void
+send_control1_event_extended(uint16_t event, event_format_t which,
+                             const char *format, ...)
+{
+  va_list ap;
+  va_start(ap, format);
+  send_control1_event_impl(event, which, 1, format, ap);
+  va_end(ap);
+}
+
 /** Given a text circuit <b>id</b>, return the corresponding circuit. */
 static origin_circuit_t *
 get_circ(const char *id)
@@ -1009,7 +1063,8 @@
     smartlist_free(events);
   }
   conn->event_mask = event_mask;
-  conn->use_extended_events = extended;
+  if (extended)
+    conn->use_extended_events = 1;
 
   control_update_global_event_mask();
   send_control_done(conn);
@@ -2338,7 +2393,7 @@
   SMARTLIST_FOREACH(args, const char *, arg, {
       if (!strcasecmp(arg, "VERBOSE_NAMES"))
         verbose_names = 1;
-      else if (!strcasecmp(arg, "EXTENDED_EVENTS"))
+      else if (!strcasecmp(arg, "EXTENDED_FORMAT"))
         extended_events = 1;
       else {
         connection_printf_to_buf(conn, "552 Unrecognized feature \"%s\"\r\n",
@@ -2744,11 +2799,43 @@
     return connection_control_process_inbuf_v1(conn);
 }
 
+static const char *
+circuit_end_reason_to_string(int reason)
+{
+  switch (reason) {
+    case END_CIRC_AT_ORIGIN:
+      /* This shouldn't get passed here; it's a catch-all reason. */
+      return "REASON=ORIGIN";
+    case END_CIRC_REASON_NONE:
+      /* This shouldn't get passed here; it's a catch-all reason. */
+      return "REASON=NONE";
+    case END_CIRC_REASON_TORPROTOCOL:
+      return "REASON=TORPROTOCOL";
+    case END_CIRC_REASON_INTERNAL:
+      return "REASON=INTERNAL";
+    case END_CIRC_REASON_REQUESTED:
+      return "REASON=REQUESTED";
+    case END_CIRC_REASON_HIBERNATING:
+      return "REASON=HIBERNATING";
+    case END_CIRC_REASON_RESOURCELIMIT:
+      return "REASON=RESOURCELIMIT";
+    case END_CIRC_REASON_CONNECTFAILED:
+      return "REASON=CONNECTFAILED";
+    case END_CIRC_REASON_OR_IDENTITY:
+      return "REASON=OR_IDENTITY";
+    case END_CIRC_REASON_OR_CONN_CLOSED:
+      return "REASON=OR_CONN_CLOSED";
+    default:
+      log_warn(LD_BUG, "Unrecognized reason code %d", (int)reason);
+      return NULL;
+  }
+}
+
 /** Something has happened to circuit <b>circ</b>: tell any interested
  * control connections. */
 int
 control_event_circuit_status(origin_circuit_t *circ, circuit_status_event_t tp,
-        int rsn)
+                             int reason_code)
 {
   char *path=NULL, *msg;
   if (!EVENT_IS_INTERESTING(EVENT_CIRCUIT_STATUS))
@@ -2783,34 +2870,20 @@
         return 0;
       }
 
-    if(tp == CIRC_EVENT_FAILED || tp == CIRC_EVENT_CLOSED) {
-        switch (rsn)
-          {
-          case END_CIRC_AT_ORIGIN: reason = " REASON=ORIGIN"; break;
-          case END_CIRC_REASON_NONE: reason = " REASON=NONE"; break;
-          case END_CIRC_REASON_TORPROTOCOL: reason = " REASON=TORPROTOCOL"; break;
-          case END_CIRC_REASON_INTERNAL: reason = " REASON=INTERNAL"; break;
-          case END_CIRC_REASON_REQUESTED: reason = " REASON=REQUESTED"; break;
-          case END_CIRC_REASON_HIBERNATING: reason = " REASON=HIBERNATING"; break;
-          case END_CIRC_REASON_RESOURCELIMIT: reason = " REASON=RESOURCELIMIT"; break;
-          case END_CIRC_REASON_CONNECTFAILED: reason = " REASON=CONNECTFAILED"; break;
-          case END_CIRC_REASON_OR_IDENTITY: reason = " REASON=OR_IDENTITY"; break;
-          case END_CIRC_REASON_OR_CONN_CLOSED: reason = " REASON=OR_CONN_CLOSED"; break;
-          default:
-            log_warn(LD_BUG, "Unrecognized reason code %d", (int)rsn);
-          }
+    if (tp == CIRC_EVENT_FAILED || tp == CIRC_EVENT_CLOSED) {
+      reason = circuit_end_reason_to_string(reason_code);
     }
 
     if (EVENT_IS_INTERESTING1S(EVENT_CIRCUIT_STATUS)) {
-      send_control1_event(EVENT_CIRCUIT_STATUS, SHORT_NAMES,
-                          "650 CIRC %lu %s %s%s\r\n",
+      send_control1_event_extended(EVENT_CIRCUIT_STATUS, SHORT_NAMES,
+                          "650 CIRC %lu %s %s@%s\r\n",
                           (unsigned long)circ->global_identifier,
                           status, path, reason);
     }
     if (EVENT_IS_INTERESTING1L(EVENT_CIRCUIT_STATUS)) {
       char *vpath = circuit_list_path_for_controller(circ);
-      send_control1_event(EVENT_CIRCUIT_STATUS, LONG_NAMES,
-                          "650 CIRC %lu %s %s%s\r\n",
+      send_control1_event_extended(EVENT_CIRCUIT_STATUS, LONG_NAMES,
+                          "650 CIRC %lu %s %s@%s\r\n",
                           (unsigned long)circ->global_identifier,
                           status, vpath, reason);
       tor_free(vpath);
@@ -3097,7 +3170,7 @@
     size_t len = strlen(ids)+32;
     msg = tor_malloc(len);
     tor_snprintf(msg, len, "650 NEWDESC %s\r\n", ids);
-    send_control1_event_string(EVENT_NEW_DESC, SHORT_NAMES, msg);
+    send_control1_event_string(EVENT_NEW_DESC, SHORT_NAMES|ALL_FORMATS, msg);
     tor_free(ids);
     tor_free(msg);
   }
@@ -3114,7 +3187,7 @@
     len = strlen(ids)+32;
     msg = tor_malloc(len);
     tor_snprintf(msg, len, "650 NEWDESC %s\r\n", ids);
-    send_control1_event_string(EVENT_NEW_DESC, LONG_NAMES, msg);
+    send_control1_event_string(EVENT_NEW_DESC, LONG_NAMES|ALL_FORMATS, msg);
     tor_free(ids);
     tor_free(msg);
     SMARTLIST_FOREACH(names, char *, cp, tor_free(cp));
@@ -3180,7 +3253,8 @@
   buf = tor_malloc(totallen);
   strlcpy(buf, firstline, totallen);
   strlcpy(buf+strlen(firstline), esc, totallen);
-  send_control1_event_string(EVENT_AUTHDIR_NEWDESCS, ALL_NAMES, buf);
+  send_control1_event_string(EVENT_AUTHDIR_NEWDESCS, ALL_NAMES|ALL_FORMATS,
+                             buf);
 
   tor_free(esc);
   tor_free(buf);

Modified: tor/trunk/src/or/or.h
===================================================================
--- tor/trunk/src/or/or.h	2006-10-09 15:47:27 UTC (rev 8671)
+++ tor/trunk/src/or/or.h	2006-10-09 15:47:50 UTC (rev 8672)
@@ -2069,7 +2069,7 @@
 int connection_control_process_inbuf(control_connection_t *conn);
 
 int control_event_circuit_status(origin_circuit_t *circ,
-                                 circuit_status_event_t e, int rsn);
+                                 circuit_status_event_t e, int reason);
 int control_event_stream_status(edge_connection_t *conn,
                                 stream_status_event_t e);
 int control_event_or_conn_status(or_connection_t *conn,

Modified: tor/trunk/src/or/rendservice.c
===================================================================
--- tor/trunk/src/or/rendservice.c	2006-10-09 15:47:27 UTC (rev 8671)
+++ tor/trunk/src/or/rendservice.c	2006-10-09 15:47:50 UTC (rev 8672)
@@ -428,6 +428,7 @@
   char serviceid[REND_SERVICE_ID_LEN+1];
   char hexcookie[9];
   int circ_needs_uptime;
+  int reason = END_CIRC_REASON_TORPROTOCOL;
 
   base32_encode(serviceid, REND_SERVICE_ID_LEN+1,
                 circuit->rend_pk_digest,10);
@@ -493,12 +494,14 @@
     if ((int)len != 7+DIGEST_LEN+2+klen+20+128) {
       log_warn(LD_PROTOCOL, "Bad length %u for version 2 INTRODUCE2 cell.",
                (int)len);
+      reason = END_CIRC_REASON_TORPROTOCOL;
       goto err;
     }
     extend_info->onion_key = crypto_pk_asn1_decode(buf+7+DIGEST_LEN+2, klen);
     if (!extend_info->onion_key) {
       log_warn(LD_PROTOCOL,
                "Error decoding onion key in version 2 INTRODUCE2 cell.");
+      reason = END_CIRC_REASON_TORPROTOCOL;
       goto err;
     }
     ptr = buf+7+DIGEST_LEN+2+klen;
@@ -537,6 +540,8 @@
     if (!router) {
       log_info(LD_REND, "Couldn't find router %s named in rendezvous cell.",
                escaped(rp_nickname));
+      /* XXXX Add a no-such-router reason? */
+      reason = END_CIRC_REASON_TORPROTOCOL;
       goto err;
     }
 
@@ -545,6 +550,7 @@
 
   if (len != REND_COOKIE_LEN+DH_KEY_LEN) {
     log_warn(LD_PROTOCOL, "Bad length %u for INTRODUCE2 cell.", (int)len);
+    reason = END_CIRC_REASON_TORPROTOCOL;
     return -1;
   }
 
@@ -556,11 +562,13 @@
   if (!dh || crypto_dh_generate_public(dh)<0) {
     log_warn(LD_BUG,"Internal error: couldn't build DH state "
              "or generate public key.");
+    reason = END_CIRC_REASON_INTERNAL;
     goto err;
   }
   if (crypto_dh_compute_secret(dh, ptr+REND_COOKIE_LEN, DH_KEY_LEN, keys,
                                DIGEST_LEN+CPATH_KEY_MATERIAL_LEN)<0) {
     log_warn(LD_BUG, "Internal error: couldn't complete DH handshake");
+    reason = END_CIRC_REASON_INTERNAL;
     goto err;
   }
 
@@ -583,6 +591,7 @@
     log_warn(LD_REND, "Giving up launching first hop of circuit to rendezvous "
              "point '%s' for service %s.",
              extend_info->nickname, serviceid);
+    reason = END_CIRC_REASON_CONNECTFAILED;
     goto err;
   }
   log_info(LD_REND,
@@ -612,7 +621,7 @@
  err:
   if (dh) crypto_dh_free(dh);
   if (launched)
-    circuit_mark_for_close(TO_CIRCUIT(launched), END_CIRC_REASON_TORPROTOCOL);
+    circuit_mark_for_close(TO_CIRCUIT(launched), reason);
   if (extend_info) extend_info_free(extend_info);
   return -1;
 }
@@ -717,6 +726,7 @@
   char buf[RELAY_PAYLOAD_SIZE];
   char auth[DIGEST_LEN + 9];
   char serviceid[REND_SERVICE_ID_LEN+1];
+  int reason = END_CIRC_REASON_TORPROTOCOL;
 
   tor_assert(circuit->_base.purpose == CIRCUIT_PURPOSE_S_ESTABLISH_INTRO);
   tor_assert(circuit->cpath);
@@ -728,6 +738,8 @@
   if (!service) {
     log_warn(LD_REND, "Unrecognized service ID %s on introduction circuit %d.",
              serviceid, circuit->_base.n_circ_id);
+    /* XXXX Add a no-such-servicer reason? */
+    reason = END_CIRC_REASON_CONNECTFAILED;
     goto err;
   }
 
@@ -748,6 +760,7 @@
   r = crypto_pk_private_sign_digest(service->private_key, buf+len, buf, len);
   if (r<0) {
     log_warn(LD_BUG, "Internal error: couldn't sign introduction request.");
+    reason = END_CIRC_REASON_INTERNAL;
     goto err;
   }
   len += r;
@@ -758,12 +771,13 @@
     log_info(LD_GENERAL,
              "Couldn't send introduction request for service %s on circuit %d",
              serviceid, circuit->_base.n_circ_id);
+    reason = END_CIRC_REASON_INTERNAL;
     goto err;
   }
 
   return;
  err:
-  circuit_mark_for_close(TO_CIRCUIT(circuit), END_CIRC_REASON_TORPROTOCOL);
+  circuit_mark_for_close(TO_CIRCUIT(circuit), reason);
 }
 
 /** Called when we get an INTRO_ESTABLISHED cell; mark the circuit as a
@@ -808,6 +822,7 @@
   crypt_path_t *hop;
   char serviceid[REND_SERVICE_ID_LEN+1];
   char hexcookie[9];
+  int reason;
 
   tor_assert(circuit->_base.purpose == CIRCUIT_PURPOSE_S_CONNECT_REND);
   tor_assert(circuit->cpath);
@@ -828,6 +843,7 @@
   if (!service) {
     log_warn(LD_GENERAL, "Internal error: unrecognized service ID on "
              "introduction circuit.");
+    reason = END_CIRC_REASON_INTERNAL;
     goto err;
   }
 
@@ -836,6 +852,7 @@
   if (crypto_dh_get_public(hop->dh_handshake_state,
                            buf+REND_COOKIE_LEN, DH_KEY_LEN)<0) {
     log_warn(LD_GENERAL,"Couldn't get DH public key.");
+    reason = END_CIRC_REASON_INTERNAL;
     goto err;
   }
   memcpy(buf+REND_COOKIE_LEN+DH_KEY_LEN, hop->handshake_digest,
@@ -847,6 +864,7 @@
                                    buf, REND_COOKIE_LEN+DH_KEY_LEN+DIGEST_LEN,
                                    circuit->cpath->prev)<0) {
     log_warn(LD_GENERAL, "Couldn't send RENDEZVOUS1 cell.");
+    reason = END_CIRC_REASON_INTERNAL;
     goto err;
   }
 
@@ -869,7 +887,7 @@
 
   return;
  err:
-  circuit_mark_for_close(TO_CIRCUIT(circuit), END_CIRC_REASON_TORPROTOCOL);
+  circuit_mark_for_close(TO_CIRCUIT(circuit), reason);
 }
 
 /*