aboutsummaryrefslogtreecommitdiff
path: root/src/or/relay.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/or/relay.c')
-rw-r--r--src/or/relay.c108
1 files changed, 95 insertions, 13 deletions
diff --git a/src/or/relay.c b/src/or/relay.c
index 866c3d8757..10be51228b 100644
--- a/src/or/relay.c
+++ b/src/or/relay.c
@@ -457,26 +457,105 @@ int connection_edge_send_command(connection_t *fromconn, circuit_t *circ,
* why the stream is closing.
*/
static const char *
-connection_edge_end_reason(char *payload, uint16_t length) {
+connection_edge_end_reason_str(char *payload, uint16_t length) {
if (length < 1) {
log_fn(LOG_WARN,"End cell arrived with length 0. Should be at least 1.");
return "MALFORMED";
}
- if (*payload < _MIN_END_STREAM_REASON || *payload > _MAX_END_STREAM_REASON) {
- log_fn(LOG_WARN,"Reason for ending (%d) not recognized.",*payload);
- return "MALFORMED";
- }
switch (*payload) {
case END_STREAM_REASON_MISC: return "misc error";
case END_STREAM_REASON_RESOLVEFAILED: return "resolve failed";
- case END_STREAM_REASON_CONNECTFAILED: return "connect failed";
+ case END_STREAM_REASON_CONNECTREFUSED: return "connection refused";
case END_STREAM_REASON_EXITPOLICY: return "exit policy failed";
case END_STREAM_REASON_DESTROY: return "destroyed";
case END_STREAM_REASON_DONE: return "closed normally";
case END_STREAM_REASON_TIMEOUT: return "gave up (timeout)";
+ case END_STREAM_REASON_HIBERNATING: return "server is hibernating";
+ case END_STREAM_REASON_INTERNAL: return "internal error at server";
+ case END_STREAM_REASON_RESOURCELIMIT: return "server out of resources";
+ case END_STREAM_REASON_CONNRESET: return "connection reset";
+ default:
+ log_fn(LOG_WARN,"Reason for ending (%d) not recognized.",*payload);
+ return "unknown";
+ }
+}
+
+socks5_reply_status_t
+connection_edge_end_reason_sock5_response(char *payload, uint16_t length) {
+ if (length < 1) {
+ log_fn(LOG_WARN,"End cell arrived with length 0. Should be at least 1.");
+ return SOCKS5_GENERAL_ERROR;
+ }
+ switch (*payload) {
+ case END_STREAM_REASON_MISC:
+ return SOCKS5_GENERAL_ERROR;
+ case END_STREAM_REASON_RESOLVEFAILED:
+ return SOCKS5_HOST_UNREACHABLE;
+ case END_STREAM_REASON_CONNECTREFUSED:
+ return SOCKS5_CONNECTION_REFUSED;
+ case END_STREAM_REASON_EXITPOLICY:
+ return SOCKS5_CONNECTION_REFUSED;
+ case END_STREAM_REASON_DESTROY:
+ return SOCKS5_GENERAL_ERROR;
+ case END_STREAM_REASON_DONE:
+ return SOCKS5_SUCCEEDED;
+ case END_STREAM_REASON_TIMEOUT:
+ return SOCKS5_TTL_EXPIRED;
+ case END_STREAM_REASON_RESOURCELIMIT:
+ return SOCKS5_GENERAL_ERROR;
+ case END_STREAM_REASON_HIBERNATING:
+ return SOCKS5_GENERAL_ERROR;
+ case END_STREAM_REASON_INTERNAL:
+ return SOCKS5_GENERAL_ERROR;
+ case END_STREAM_REASON_CONNRESET:
+ return SOCKS5_CONNECTION_REFUSED;
+ default:
+ log_fn(LOG_WARN,"Reason for ending (%d) not recognized.",*payload);
+ return SOCKS5_GENERAL_ERROR;
+ }
+}
+
+#ifdef MS_WINDOWS
+#define E_CASE(s) case s: case WSA ## s
+#define W_CASE(s) case s:
+#else
+#define E_CASE(s) case s
+#define W_CASE(s)
+#endif
+
+int
+errno_to_end_reasaon(int e)
+{
+ switch (e) {
+ E_CASE(EPIPE):
+ return END_STREAM_REASON_DONE;
+ E_CASE(EBADF):
+ E_CASE(EFAULT):
+ E_CASE(EINVAL):
+ E_CASE(EISCONN):
+ E_CASE(ENOTSOCK):
+ E_CASE(EPROTONOSUPPORT):
+ E_CASE(EAFNOSUPPORT):
+ E_CASE(EACCES):
+ E_CASE(ENOTCONN):
+ E_CASE(ENETUNREACH):
+ return END_STREAM_REASON_INTERNAL;
+ E_CASE(ECONNREFUSED):
+ return END_STREAM_REASON_CONNECTREFUSED;
+ E_CASE(ECONNRESET):
+ return END_STREAM_REASON_CONNRESET;
+ E_CASE(ETIMEDOUT):
+ return END_STREAM_REASON_TIMEOUT;
+ E_CASE(ENOBUFS):
+ E_CASE(ENOMEM):
+ E_CASE(ENFILE):
+ E_CASE(EMFILE):
+ return END_STREAM_REASON_RESOURCELIMIT;
+ default:
+ log_fn(LOG_INFO, "Didn't recognize errno %d (%s); telling the OP that we are ending a stream for 'misc' reason.",
+ e, tor_socket_strerror(e));
+ return END_STREAM_REASON_MISC;
}
- tor_assert(0);
- return "";
}
/** How many times will I retry a stream that fails due to DNS
@@ -567,7 +646,8 @@ connection_edge_process_relay_cell_not_open(
}
}
log_fn(LOG_INFO,"Edge got end (%s) before we're connected. Marking for close.",
- connection_edge_end_reason(cell->payload+RELAY_HEADER_SIZE, rh->length));
+ connection_edge_end_reason_str(cell->payload+RELAY_HEADER_SIZE,
+ rh->length));
if (CIRCUIT_IS_ORIGIN(circ))
circuit_log_path(LOG_INFO,circ);
conn->has_sent_end = 1; /* we just got an 'end', don't need to send one */
@@ -722,14 +802,16 @@ connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ,
case RELAY_COMMAND_END:
if (!conn) {
log_fn(LOG_INFO,"end cell (%s) dropped, unknown stream.",
- connection_edge_end_reason(cell->payload+RELAY_HEADER_SIZE, rh.length));
+ connection_edge_end_reason_str(cell->payload+RELAY_HEADER_SIZE,
+ rh.length));
return 0;
}
/* XXX add to this log_fn the exit node's nickname? */
log_fn(LOG_INFO,"%d: end cell (%s) for stream %d. Removing stream. Size %d.",
- conn->s,
- connection_edge_end_reason(cell->payload+RELAY_HEADER_SIZE, rh.length),
- conn->stream_id, (int)conn->stream_size);
+ conn->s,
+ connection_edge_end_reason_str(cell->payload+RELAY_HEADER_SIZE,
+ rh.length),
+ conn->stream_id, (int)conn->stream_size);
#ifdef HALF_OPEN
conn->done_sending = 1;