aboutsummaryrefslogtreecommitdiff
path: root/src/or/control.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/or/control.c')
-rw-r--r--src/or/control.c83
1 files changed, 81 insertions, 2 deletions
diff --git a/src/or/control.c b/src/or/control.c
index a655521ec9..3114dbf2d3 100644
--- a/src/or/control.c
+++ b/src/or/control.c
@@ -48,8 +48,10 @@ const char control_c_id[] = "$Id$";
#define CONTROL_CMD_POSTDESCRIPTOR 0x000F
#define CONTROL_CMD_FRAGMENTHEADER 0x0010
#define CONTROL_CMD_FRAGMENT 0x0011
-#define CONTROL_CMD_REDIRECTSTREAM 0x0012
-#define _CONTROL_CMD_MAX_RECOGNIZED 0x0012
+#define CONTROL_CMD_REDIRECTSTREAM 0x0012
+#define CONTROL_CMD_CLOSESTREAM 0x0013
+#define CONTROL_CMD_CLOSECIRCUIT 0x0014
+#define _CONTROL_CMD_MAX_RECOGNIZED 0x0014
/* Recognized error codes. */
#define ERR_UNSPECIFIED 0x0000
@@ -152,6 +154,10 @@ static int handle_control_postdescriptor(connection_t *conn, uint32_t len,
const char *body);
static int handle_control_redirectstream(connection_t *conn, uint32_t len,
const char *body);
+static int handle_control_closestream(connection_t *conn, uint32_t len,
+ const char *body);
+static int handle_control_closecircuit(connection_t *conn, uint32_t len,
+ const char *body);
/** Given a possibly invalid message type code <b>cmd</b>, return a
* human-readable string equivalent. */
@@ -772,7 +778,72 @@ handle_control_redirectstream(connection_t *conn, uint32_t len,
send_control_done(conn);
return 0;
}
+static int
+handle_control_closestream(connection_t *conn, uint32_t len,
+ const char *body)
+{
+ uint32_t conn_id;
+ connection_t *ap_conn;
+ uint8_t reason;
+ int hold_open;
+
+ if (len < 6) {
+ send_control_error(conn, ERR_SYNTAX, "closestream message too short");
+ return 0;
+ }
+
+ conn_id = ntohl(get_uint32(body));
+ reason = *(uint8_t*)(body+4);
+ hold_open = (*(uint8_t*)(body+5)) & 1;
+
+ if (!(ap_conn = connection_get_by_global_id(conn_id))
+ || ap_conn->state != CONN_TYPE_AP
+ || !ap_conn->socks_request) {
+ send_control_error(conn, ERR_NO_STREAM,
+ "No AP connection found with given ID");
+ return 0;
+ }
+
+ if (!ap_conn->socks_request->has_finished) {
+ socks5_reply_status_t status =
+ connection_edge_end_reason_socks5_response(reason);
+ connection_ap_handshake_socks_reply(ap_conn, NULL, 0, status);
+ }
+ if (hold_open)
+ ap_conn->hold_open_until_flushed = 1;
+ connection_mark_for_close(ap_conn);
+
+ send_control_done(conn);
+ return 0;
+}
+static int
+handle_control_closecircuit(connection_t *conn, uint32_t len,
+ const char *body)
+{
+ uint32_t circ_id;
+ circuit_t *circ;
+ int safe;
+ if (len < 5) {
+ send_control_error(conn, ERR_SYNTAX, "closecircuit message too short");
+ return 0;
+ }
+ circ_id = ntohl(get_uint32(body));
+ safe = (*(uint8_t*)(body+4)) & 1;
+
+ if (!(circ = circuit_get_by_global_id(circ_id))) {
+ send_control_error(conn, ERR_NO_CIRC,
+ "No circuit found with given ID");
+ return 0;
+ }
+
+ if (!safe || !circ->p_streams) {
+ circuit_mark_for_close(circ);
+ }
+
+ send_control_done(conn);
+ return 0;
+}
/** Called when <b>conn</b> has no more bytes left on its outbuf. */
int
@@ -882,6 +953,14 @@ connection_control_process_inbuf(connection_t *conn) {
if (handle_control_redirectstream(conn, body_len, body))
return -1;
break;
+ case CONTROL_CMD_CLOSESTREAM:
+ if (handle_control_closestream(conn, body_len, body))
+ return -1;
+ break;
+ case CONTROL_CMD_CLOSECIRCUIT:
+ if (handle_control_closecircuit(conn, body_len, body))
+ return -1;
+ break;
case CONTROL_CMD_ERROR:
case CONTROL_CMD_DONE:
case CONTROL_CMD_CONFVALUE: