|
@@ -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;
|