From 12af87539b3380e97a9433930e4fa60cd825c157 Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Fri, 20 Oct 2006 17:54:36 +0000 Subject: [PATCH] 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 --- doc/control-spec.txt | 19 +++++++++++++++ src/or/connection.c | 4 ++-- src/or/connection_edge.c | 16 +++++++------ src/or/control.c | 52 ++++++++++++++++++++++++++++++++++++---- src/or/or.h | 11 ++++++++- 5 files changed, 88 insertions(+), 14 deletions(-) diff --git a/doc/control-spec.txt b/doc/control-spec.txt index b6638958d8..abf9de8dfe 100644 --- a/doc/control-spec.txt +++ b/doc/control-spec.txt @@ -835,6 +835,7 @@ $Id$ The syntax is: "650" SP "STREAM" SP StreamID SP StreamStatus SP CircID SP Target + [SP "REASON=" Reason [ SP "REMOTE_REASON=" Reason ]] CRLF StreamStatus = "NEW" / ; New request to connect @@ -851,6 +852,24 @@ $Id$ The circuit ID designates which circuit this stream is attached to. If 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 The syntax is: diff --git a/src/or/connection.c b/src/or/connection.c index d60291253e..25b633a065 100644 --- a/src/or/connection.c +++ b/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" " back a socks reply.", 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; case CONN_TYPE_EXIT: edge_conn = TO_EDGE_CONN(conn); diff --git a/src/or/connection_edge.c b/src/or/connection_edge.c index ad88e4153e..5a415bb04f 100644 --- a/src/or/connection_edge.c +++ b/src/or/connection_edge.c @@ -498,7 +498,8 @@ circuit_discard_optional_exit_enclaves(extend_info_t *info) int 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); if (! get_options()->LeaveStreamsUnattached) { 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 */ if (socks->command == SOCKS_COMMAND_CONNECT) - control_event_stream_status(conn, STREAM_EVENT_NEW); + control_event_stream_status(conn, STREAM_EVENT_NEW, 0); else - control_event_stream_status(conn, STREAM_EVENT_NEW_RESOLVE); + control_event_stream_status(conn, STREAM_EVENT_NEW_RESOLVE, 0); if (options->LeaveStreamsUnattached) { 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 */ - control_event_stream_status(conn, STREAM_EVENT_NEW); + control_event_stream_status(conn, STREAM_EVENT_NEW, 0); if (options->LeaveStreamsUnattached) { 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; log_info(LD_APP,"Address/port sent, ap socket %d, n_circ_id %d", 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; } @@ -1623,7 +1624,7 @@ connection_ap_handshake_send_resolve(edge_connection_t *ap_conn, ap_conn->_base.state = AP_CONN_STATE_RESOLVE_WAIT; log_info(LD_APP,"Address sent for resolve, ap socket %d, n_circ_id %d", 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; } @@ -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 */ 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) { log_warn(LD_BUG, "Harmless bug: duplicate calls to " diff --git a/src/or/control.c b/src/or/control.c index 84d4ee4d56..562c7c64ab 100644 --- a/src/or/control.c +++ b/src/or/control.c @@ -2946,10 +2946,34 @@ write_stream_target_to_buf(edge_connection_t *conn, char *buf, size_t len) 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 * conn: tell any interested control connections. */ 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; size_t len; @@ -2971,9 +2995,11 @@ control_event_stream_status(edge_connection_t *conn, stream_status_event_t tp) tor_free(msg); } if (EVENT_IS_INTERESTING1(EVENT_STREAM_STATUS)) { + char reason_buf[64]; const char *status; circuit_t *circ; origin_circuit_t *origin_circ = NULL; + reason_buf[0] = '\0'; switch (tp) { 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); 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); if (circ && CIRCUIT_IS_ORIGIN(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, origin_circ? (unsigned long)origin_circ->global_identifier : 0ul, - buf); + buf, reason_buf); /* XXX need to specify its intended exit, etc? */ } return 0; diff --git a/src/or/or.h b/src/or/or.h index 86c626a779..ae116d0440 100644 --- a/src/or/or.h +++ b/src/or/or.h @@ -464,6 +464,10 @@ typedef enum { #define RELAY_COMMAND_RENDEZVOUS_ESTABLISHED 39 #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_RESOLVEFAILED 2 #define END_STREAM_REASON_CONNECTREFUSED 3 @@ -479,6 +483,10 @@ typedef enum { #define END_STREAM_REASON_TORPROTOCOL 13 #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, * 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 @@ -2089,7 +2097,8 @@ int connection_control_process_inbuf(control_connection_t *conn); int control_event_circuit_status(origin_circuit_t *circ, circuit_status_event_t e, int reason); 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, or_conn_status_event_t e); int control_event_bandwidth_used(uint32_t n_read, uint32_t n_written);