Browse Source

r9303@Kushana: nickm | 2006-10-20 12:07:34 -0400
Start implementing reason extension for stream events to match the one one used by circuit events. (Not a complete implementation yet; actual reasons are not passed to control.c)


svn:r8777

Nick Mathewson 19 years ago
parent
commit
12af87539b
5 changed files with 88 additions and 14 deletions
  1. 19 0
      doc/control-spec.txt
  2. 2 2
      src/or/connection.c
  3. 9 7
      src/or/connection_edge.c
  4. 48 4
      src/or/control.c
  5. 10 1
      src/or/or.h

+ 19 - 0
doc/control-spec.txt

@@ -835,6 +835,7 @@ $Id$
     The syntax is:
     The syntax is:
 
 
       "650" SP "STREAM" SP StreamID SP StreamStatus SP CircID SP Target
       "650" SP "STREAM" SP StreamID SP StreamStatus SP CircID SP Target
+          [SP "REASON=" Reason [ SP "REMOTE_REASON=" Reason ]] CRLF
 
 
       StreamStatus =
       StreamStatus =
                "NEW"          / ; New request to connect
                "NEW"          / ; New request to connect
@@ -851,6 +852,24 @@ $Id$
   The circuit ID designates which circuit this stream is attached to.  If
   The circuit ID designates which circuit this stream is attached to.  If
   the stream is unattached, the circuit ID "0" is given.
   the stream is unattached, the circuit ID "0" is given.
 
 
+      Reason = "MISC" / "RESOLVEFAILED" / "CONNECTREFUSED" /
+               "EXITPOLICY" / "DESTROY" / "DONE" / "TIMEOUT" /
+               "HIBERNATING" / "INTERNAL"/ "RESOURCELIMIT" /
+               "CONNRESET" / "TORPROTOCOL" / "NOTDIRECTORY" / "END"
+
+   The "REASON" field is provided only for FAILED, CLOSED, and DETACHED
+   events, and only if extended events are enabled (see 3.19).  Clients MUST
+   accept reasons not listed above.  Reasons are as given in tor-spec.txt,
+   except for:
+
+      END          (We received a RELAY_END cell from the other side of thise
+                    stream.)
+
+   The "REMOTE_REASON" field is provided only when we receive a RELAY_END
+   cell, and only if extended events are enabled.  It contains the actual
+   reason given by the remote OR for closing the stream. Clients MUST accept
+   reasons not listed above.  Reasons are as listed in tor-spec.txt.
+
 4.1.3. OR Connection status changed
 4.1.3. OR Connection status changed
 
 
   The syntax is:
   The syntax is:

+ 2 - 2
src/or/connection.c

@@ -458,9 +458,9 @@ connection_about_to_close_connection(connection_t *conn)
         log_warn(LD_BUG,"Bug: Closing stream (marked at %s:%d) without sending"
         log_warn(LD_BUG,"Bug: Closing stream (marked at %s:%d) without sending"
                  " back a socks reply.",
                  " back a socks reply.",
                  conn->marked_for_close_file, conn->marked_for_close);
                  conn->marked_for_close_file, conn->marked_for_close);
-      } else {
-        control_event_stream_status(edge_conn, STREAM_EVENT_CLOSED);
       }
       }
+      control_event_stream_status(edge_conn, STREAM_EVENT_CLOSED,
+                                  END_STREAM_REASON_FIXME_XXXX);
       break;
       break;
     case CONN_TYPE_EXIT:
     case CONN_TYPE_EXIT:
       edge_conn = TO_EDGE_CONN(conn);
       edge_conn = TO_EDGE_CONN(conn);

+ 9 - 7
src/or/connection_edge.c

@@ -498,7 +498,8 @@ circuit_discard_optional_exit_enclaves(extend_info_t *info)
 int
 int
 connection_ap_detach_retriable(edge_connection_t *conn, origin_circuit_t *circ)
 connection_ap_detach_retriable(edge_connection_t *conn, origin_circuit_t *circ)
 {
 {
-  control_event_stream_status(conn, STREAM_EVENT_FAILED_RETRIABLE);
+  control_event_stream_status(conn, STREAM_EVENT_FAILED_RETRIABLE,
+                              END_STREAM_REASON_FIXME_XXXX);
   conn->_base.timestamp_lastread = time(NULL);
   conn->_base.timestamp_lastread = time(NULL);
   if (! get_options()->LeaveStreamsUnattached) {
   if (! get_options()->LeaveStreamsUnattached) {
     conn->_base.state = AP_CONN_STATE_CIRCUIT_WAIT;
     conn->_base.state = AP_CONN_STATE_CIRCUIT_WAIT;
@@ -1436,9 +1437,9 @@ connection_ap_handshake_process_socks(edge_connection_t *conn)
   } /* else socks handshake is done, continue processing */
   } /* else socks handshake is done, continue processing */
 
 
   if (socks->command == SOCKS_COMMAND_CONNECT)
   if (socks->command == SOCKS_COMMAND_CONNECT)
-    control_event_stream_status(conn, STREAM_EVENT_NEW);
+    control_event_stream_status(conn, STREAM_EVENT_NEW, 0);
   else
   else
-    control_event_stream_status(conn, STREAM_EVENT_NEW_RESOLVE);
+    control_event_stream_status(conn, STREAM_EVENT_NEW_RESOLVE, 0);
 
 
   if (options->LeaveStreamsUnattached) {
   if (options->LeaveStreamsUnattached) {
     conn->_base.state = AP_CONN_STATE_CONTROLLER_WAIT;
     conn->_base.state = AP_CONN_STATE_CONTROLLER_WAIT;
@@ -1480,7 +1481,7 @@ connection_ap_process_transparent(edge_connection_t *conn)
   }
   }
   /* we have the original destination */
   /* we have the original destination */
 
 
-  control_event_stream_status(conn, STREAM_EVENT_NEW);
+  control_event_stream_status(conn, STREAM_EVENT_NEW, 0);
 
 
   if (options->LeaveStreamsUnattached) {
   if (options->LeaveStreamsUnattached) {
     conn->_base.state = AP_CONN_STATE_CONTROLLER_WAIT;
     conn->_base.state = AP_CONN_STATE_CONTROLLER_WAIT;
@@ -1557,7 +1558,7 @@ connection_ap_handshake_send_begin(edge_connection_t *ap_conn,
   ap_conn->_base.state = AP_CONN_STATE_CONNECT_WAIT;
   ap_conn->_base.state = AP_CONN_STATE_CONNECT_WAIT;
   log_info(LD_APP,"Address/port sent, ap socket %d, n_circ_id %d",
   log_info(LD_APP,"Address/port sent, ap socket %d, n_circ_id %d",
            ap_conn->_base.s, circ->_base.n_circ_id);
            ap_conn->_base.s, circ->_base.n_circ_id);
-  control_event_stream_status(ap_conn, STREAM_EVENT_SENT_CONNECT);
+  control_event_stream_status(ap_conn, STREAM_EVENT_SENT_CONNECT, 0);
   return 0;
   return 0;
 }
 }
 
 
@@ -1623,7 +1624,7 @@ connection_ap_handshake_send_resolve(edge_connection_t *ap_conn,
   ap_conn->_base.state = AP_CONN_STATE_RESOLVE_WAIT;
   ap_conn->_base.state = AP_CONN_STATE_RESOLVE_WAIT;
   log_info(LD_APP,"Address sent for resolve, ap socket %d, n_circ_id %d",
   log_info(LD_APP,"Address sent for resolve, ap socket %d, n_circ_id %d",
            ap_conn->_base.s, circ->_base.n_circ_id);
            ap_conn->_base.s, circ->_base.n_circ_id);
-  control_event_stream_status(ap_conn, STREAM_EVENT_SENT_RESOLVE);
+  control_event_stream_status(ap_conn, STREAM_EVENT_SENT_RESOLVE, 0);
   return 0;
   return 0;
 }
 }
 
 
@@ -1781,7 +1782,8 @@ connection_ap_handshake_socks_reply(edge_connection_t *conn, char *reply,
   tor_assert(conn->socks_request); /* make sure it's an AP stream */
   tor_assert(conn->socks_request); /* make sure it's an AP stream */
 
 
   control_event_stream_status(conn,
   control_event_stream_status(conn,
-     status==SOCKS5_SUCCEEDED ? STREAM_EVENT_SUCCEEDED : STREAM_EVENT_FAILED);
+     status==SOCKS5_SUCCEEDED ? STREAM_EVENT_SUCCEEDED : STREAM_EVENT_FAILED,
+                              END_STREAM_REASON_FIXME_XXXX);
 
 
   if (conn->socks_request->has_finished) {
   if (conn->socks_request->has_finished) {
     log_warn(LD_BUG, "Harmless bug: duplicate calls to "
     log_warn(LD_BUG, "Harmless bug: duplicate calls to "

+ 48 - 4
src/or/control.c

@@ -2946,10 +2946,34 @@ write_stream_target_to_buf(edge_connection_t *conn, char *buf, size_t len)
   return 0;
   return 0;
 }
 }
 
 
+/* DOCDOC */
+static const char *
+stream_end_reason_to_string(int reason)
+{
+  reason &= ~END_CIRC_REASON_FLAG_REMOTE;
+  switch (reason) {
+    case END_STREAM_REASON_MISC: return "MISC";
+    case END_STREAM_REASON_RESOLVEFAILED: return "RESOLVEFAILED";
+    case END_STREAM_REASON_CONNECTREFUSED: return "CONNECTREFUSED";
+    case END_STREAM_REASON_EXITPOLICY: return "EXITPOLICY";
+    case END_STREAM_REASON_DESTROY: return "DESTROY";
+    case END_STREAM_REASON_DONE: return "DONE";
+    case END_STREAM_REASON_TIMEOUT: return "TIMEOUT";
+    case END_STREAM_REASON_HIBERNATING: return "HIBERNATING";
+    case END_STREAM_REASON_INTERNAL: return "INTERNAL";
+    case END_STREAM_REASON_RESOURCELIMIT: return "RESOURCELIMIT";
+    case END_STREAM_REASON_CONNRESET: return "CONNRESET";
+    case END_STREAM_REASON_TORPROTOCOL: return "TORPROTOCOL";
+    case END_STREAM_REASON_NOTDIRECTORY: return "NOTDIRECTORY";
+    default: return NULL;
+  }
+}
+
 /** Something has happened to the stream associated with AP connection
 /** Something has happened to the stream associated with AP connection
  * <b>conn</b>: tell any interested control connections. */
  * <b>conn</b>: tell any interested control connections. */
 int
 int
-control_event_stream_status(edge_connection_t *conn, stream_status_event_t tp)
+control_event_stream_status(edge_connection_t *conn, stream_status_event_t tp,
+                            int reason_code)
 {
 {
   char *msg;
   char *msg;
   size_t len;
   size_t len;
@@ -2971,9 +2995,11 @@ control_event_stream_status(edge_connection_t *conn, stream_status_event_t tp)
     tor_free(msg);
     tor_free(msg);
   }
   }
   if (EVENT_IS_INTERESTING1(EVENT_STREAM_STATUS)) {
   if (EVENT_IS_INTERESTING1(EVENT_STREAM_STATUS)) {
+    char reason_buf[64];
     const char *status;
     const char *status;
     circuit_t *circ;
     circuit_t *circ;
     origin_circuit_t *origin_circ = NULL;
     origin_circuit_t *origin_circ = NULL;
+    reason_buf[0] = '\0';
     switch (tp)
     switch (tp)
       {
       {
       case STREAM_EVENT_SENT_CONNECT: status = "SENTCONNECT"; break;
       case STREAM_EVENT_SENT_CONNECT: status = "SENTCONNECT"; break;
@@ -2988,15 +3014,33 @@ control_event_stream_status(edge_connection_t *conn, stream_status_event_t tp)
         log_warn(LD_BUG, "Unrecognized status code %d", (int)tp);
         log_warn(LD_BUG, "Unrecognized status code %d", (int)tp);
         return 0;
         return 0;
       }
       }
+    if (reason_code && (tp == STREAM_EVENT_FAILED ||
+                        tp == STREAM_EVENT_CLOSED ||
+                        tp == STREAM_EVENT_FAILED_RETRIABLE)) {
+      const char *reason_str = stream_end_reason_to_string(reason_code);
+      char *r = NULL;
+      if (!reason_str) {
+        r = tor_malloc(16);
+        tor_snprintf(r, 16, "UNKNOWN_%d", reason_code);
+        reason_str = r;
+      }
+      if (reason_code & END_STREAM_REASON_FLAG_REMOTE)
+        tor_snprintf(reason_buf, sizeof(reason_buf),
+                     "REASON=END REMOTE_REASON=%s", reason_str);
+      else
+        tor_snprintf(reason_buf, sizeof(reason_buf),
+                     "REASON=%s", reason_str);
+      tor_free(r);
+    }
     circ = circuit_get_by_edge_conn(conn);
     circ = circuit_get_by_edge_conn(conn);
     if (circ && CIRCUIT_IS_ORIGIN(circ))
     if (circ && CIRCUIT_IS_ORIGIN(circ))
       origin_circ = TO_ORIGIN_CIRCUIT(circ);
       origin_circ = TO_ORIGIN_CIRCUIT(circ);
-    send_control1_event(EVENT_STREAM_STATUS, ALL_NAMES,
-                        "650 STREAM %lu %s %lu %s\r\n",
+    send_control1_event_extended(EVENT_STREAM_STATUS, ALL_NAMES,
+                        "650 STREAM %lu %s %lu %s@%s\r\n",
                         (unsigned long)conn->global_identifier, status,
                         (unsigned long)conn->global_identifier, status,
                         origin_circ?
                         origin_circ?
                            (unsigned long)origin_circ->global_identifier : 0ul,
                            (unsigned long)origin_circ->global_identifier : 0ul,
-                        buf);
+                        buf, reason_buf);
     /* XXX need to specify its intended exit, etc? */
     /* XXX need to specify its intended exit, etc? */
   }
   }
   return 0;
   return 0;

+ 10 - 1
src/or/or.h

@@ -464,6 +464,10 @@ typedef enum {
 #define RELAY_COMMAND_RENDEZVOUS_ESTABLISHED 39
 #define RELAY_COMMAND_RENDEZVOUS_ESTABLISHED 39
 #define RELAY_COMMAND_INTRODUCE_ACK 40
 #define RELAY_COMMAND_INTRODUCE_ACK 40
 
 
+/* XXXX Placeholder: remove me as soon as we have correct reasons sent
+ * everywhere. */
+#define END_STREAM_REASON_FIXME_XXXX 0
+
 #define END_STREAM_REASON_MISC 1
 #define END_STREAM_REASON_MISC 1
 #define END_STREAM_REASON_RESOLVEFAILED 2
 #define END_STREAM_REASON_RESOLVEFAILED 2
 #define END_STREAM_REASON_CONNECTREFUSED 3
 #define END_STREAM_REASON_CONNECTREFUSED 3
@@ -479,6 +483,10 @@ typedef enum {
 #define END_STREAM_REASON_TORPROTOCOL 13
 #define END_STREAM_REASON_TORPROTOCOL 13
 #define END_STREAM_REASON_NOTDIRECTORY 14
 #define END_STREAM_REASON_NOTDIRECTORY 14
 
 
+/* OR this with the argument to control_event_stream_status to indicate that
+ * the reason came from an END cell. */
+#define END_STREAM_REASON_FLAG_REMOTE     512
+
 /* These high-numbered end reasons are not part of the official spec,
 /* These high-numbered end reasons are not part of the official spec,
  * and are not intended to be put in relay end cells. They are here
  * and are not intended to be put in relay end cells. They are here
  * to be more informative when sending back socks replies to the
  * to be more informative when sending back socks replies to the
@@ -2089,7 +2097,8 @@ int connection_control_process_inbuf(control_connection_t *conn);
 int control_event_circuit_status(origin_circuit_t *circ,
 int control_event_circuit_status(origin_circuit_t *circ,
                                  circuit_status_event_t e, int reason);
                                  circuit_status_event_t e, int reason);
 int control_event_stream_status(edge_connection_t *conn,
 int control_event_stream_status(edge_connection_t *conn,
-                                stream_status_event_t e);
+                                stream_status_event_t e,
+                                int reason);
 int control_event_or_conn_status(or_connection_t *conn,
 int control_event_or_conn_status(or_connection_t *conn,
                                  or_conn_status_event_t e);
                                  or_conn_status_event_t e);
 int control_event_bandwidth_used(uint32_t n_read, uint32_t n_written);
 int control_event_bandwidth_used(uint32_t n_read, uint32_t n_written);