summaryrefslogtreecommitdiff
path: root/src/or/control.c
diff options
context:
space:
mode:
authorNick Mathewson <nickm@torproject.org>2005-03-02 20:22:10 +0000
committerNick Mathewson <nickm@torproject.org>2005-03-02 20:22:10 +0000
commitb494c2223df3a53e47045cf8044bbaeb2377ebf1 (patch)
treeaad36c5019bc43d1e5639db095bd20bd7cc85e8d /src/or/control.c
parent65230fd39f0c333ce8616f5a578f4941ea9f0b94 (diff)
downloadtor-b494c2223df3a53e47045cf8044bbaeb2377ebf1.tar.gz
tor-b494c2223df3a53e47045cf8044bbaeb2377ebf1.zip
Specify and implement fragmented control messages to allow for (among other things) long GETINFO replies. Otherwise we could hit the 64K barrier on questions like "please dump your client-side DNS cache."
svn:r3726
Diffstat (limited to 'src/or/control.c')
-rw-r--r--src/or/control.c116
1 files changed, 73 insertions, 43 deletions
diff --git a/src/or/control.c b/src/or/control.c
index ff54f38959..4714e8ee7a 100644
--- a/src/or/control.c
+++ b/src/or/control.c
@@ -46,7 +46,9 @@ const char control_c_id[] = "$Id$";
#define CONTROL_CMD_EXTENDCIRCUIT 0x000D
#define CONTROL_CMD_ATTACHSTREAM 0x000E
#define CONTROL_CMD_POSTDESCRIPTOR 0x000F
-#define _CONTROL_CMD_MAX_RECOGNIZED 0x000F
+#define CONTROL_CMD_FRAGMENTHEADER 0x0010
+#define CONTROL_CMD_FRAGMENT 0x0011
+#define _CONTROL_CMD_MAX_RECOGNIZED 0x0011
/* Recognized error codes. */
#define ERR_UNSPECIFIED 0x0000
@@ -89,7 +91,9 @@ static const char * CONTROL_COMMANDS[_CONTROL_CMD_MAX_RECOGNIZED+1] = {
"infovalue",
"extendcircuit",
"attachstream",
- "postdescriptor"
+ "postdescriptor",
+ "fragmentheader",
+ "fragment",
};
/** Bitfield: The bit 1&lt;&lt;e is set if <b>any</b> open control
@@ -115,33 +119,33 @@ static char authentication_cookie[AUTHENTICATION_COOKIE_LEN];
static void update_global_event_mask(void);
static void send_control_message(connection_t *conn, uint16_t type,
- uint16_t len, const char *body);
+ uint32_t len, const char *body);
static void send_control_done(connection_t *conn);
static void send_control_done2(connection_t *conn, const char *msg, size_t len);
static void send_control_error(connection_t *conn, uint16_t error,
const char *message);
-static void send_control_event(uint16_t event, uint16_t len, const char *body);
-static int handle_control_setconf(connection_t *conn, uint16_t len,
+static void send_control_event(uint16_t event, uint32_t len, const char *body);
+static int handle_control_setconf(connection_t *conn, uint32_t len,
char *body);
-static int handle_control_getconf(connection_t *conn, uint16_t len,
+static int handle_control_getconf(connection_t *conn, uint32_t len,
const char *body);
-static int handle_control_setevents(connection_t *conn, uint16_t len,
+static int handle_control_setevents(connection_t *conn, uint32_t len,
const char *body);
-static int handle_control_authenticate(connection_t *conn, uint16_t len,
+static int handle_control_authenticate(connection_t *conn, uint32_t len,
const char *body);
-static int handle_control_saveconf(connection_t *conn, uint16_t len,
+static int handle_control_saveconf(connection_t *conn, uint32_t len,
const char *body);
-static int handle_control_signal(connection_t *conn, uint16_t len,
+static int handle_control_signal(connection_t *conn, uint32_t len,
const char *body);
-static int handle_control_mapaddress(connection_t *conn, uint16_t len,
+static int handle_control_mapaddress(connection_t *conn, uint32_t len,
const char *body);
-static int handle_control_getinfo(connection_t *conn, uint16_t len,
+static int handle_control_getinfo(connection_t *conn, uint32_t len,
const char *body);
-static int handle_control_extendcircuit(connection_t *conn, uint16_t len,
+static int handle_control_extendcircuit(connection_t *conn, uint32_t len,
const char *body);
-static int handle_control_attachstream(connection_t *conn, uint16_t len,
+static int handle_control_attachstream(connection_t *conn, uint32_t len,
const char *body);
-static int handle_control_postdescriptor(connection_t *conn, uint16_t len,
+static int handle_control_postdescriptor(connection_t *conn, uint32_t len,
const char *body);
/** Given a possibly invalid message type code <b>cmd</b>, return a
@@ -172,18 +176,38 @@ static void update_global_event_mask(void)
/** Send a message of type <b>type</b> containing <b>len</b> bytes
* from <b>body</b> along the control connection <b>conn</b> */
static void
-send_control_message(connection_t *conn, uint16_t type, uint16_t len,
+send_control_message(connection_t *conn, uint16_t type, uint32_t len,
const char *body)
{
- char buf[4];
+ char buf[10];
tor_assert(conn);
tor_assert(len || !body);
tor_assert(type <= _CONTROL_CMD_MAX_RECOGNIZED);
- set_uint16(buf, htons(len));
- set_uint16(buf+2, htons(type));
- connection_write_to_buf(buf, 4, conn);
- if (len)
- connection_write_to_buf(body, len, conn);
+ if (len < 65536) {
+ set_uint16(buf, htons(len));
+ set_uint16(buf+2, htons(type));
+ connection_write_to_buf(buf, 4, conn);
+ if (len)
+ connection_write_to_buf(body, len, conn);
+ } else {
+ set_uint16(buf, htons(65535));
+ set_uint16(buf+2, htons(CONTROL_CMD_FRAGMENTHEADER));
+ set_uint16(buf+4, htons(type));
+ set_uint32(buf+6, htonl(len));
+ connection_write_to_buf(buf, 10, conn);
+ connection_write_to_buf(body, 65535-6, conn);
+ len -= (65535-6);
+ body += (65535-6);
+ while (len) {
+ size_t chunklen = (len<65535)?len:65535;
+ set_uint16(buf, htons((uint16_t)chunklen));
+ set_uint16(buf+2, htons(CONTROL_CMD_FRAGMENT));
+ connection_write_to_buf(buf, 4, conn);
+ connection_write_to_buf(body, chunklen, conn);
+ len -= chunklen;
+ body += chunklen;
+ }
+ }
}
/** Send a "DONE" message down the control connection <b>conn</b> */
@@ -216,7 +240,7 @@ send_control_error(connection_t *conn, uint16_t error, const char *message)
* <b>len</b> bytes in <b>body</b> to every control connection that
* is interested in it. */
static void
-send_control_event(uint16_t event, uint16_t len, const char *body)
+send_control_event(uint16_t event, uint32_t len, const char *body)
{
connection_t **conns;
int n_conns, i;
@@ -233,7 +257,7 @@ send_control_event(uint16_t event, uint16_t len, const char *body)
if (conns[i]->type == CONN_TYPE_CONTROL &&
conns[i]->state == CONTROL_CONN_STATE_OPEN &&
conns[i]->event_mask & (1<<event)) {
- send_control_message(conns[i], CONTROL_CMD_EVENT, (uint16_t)(buflen), buf);
+ send_control_message(conns[i], CONTROL_CMD_EVENT, buflen, buf);
}
}
@@ -243,7 +267,7 @@ send_control_event(uint16_t event, uint16_t len, const char *body)
/** Called when we receive a SETCONF message: parse the body and try
* to update our configuration. Reply with a DONE or ERROR message. */
static int
-handle_control_setconf(connection_t *conn, uint16_t len, char *body)
+handle_control_setconf(connection_t *conn, uint32_t len, char *body)
{
int r;
struct config_line_t *lines=NULL;
@@ -278,7 +302,7 @@ handle_control_setconf(connection_t *conn, uint16_t len, char *body)
/** Called when we receive a GETCONF message. Parse the request, and
* reply with a CONFVALUE or an ERROR message */
static int
-handle_control_getconf(connection_t *conn, uint16_t body_len, const char *body)
+handle_control_getconf(connection_t *conn, uint32_t body_len, const char *body)
{
smartlist_t *questions = NULL;
smartlist_t *answers = NULL;
@@ -332,7 +356,7 @@ handle_control_getconf(connection_t *conn, uint16_t body_len, const char *body)
/** Called when we get a SETEVENTS message: update conn->event_mask,
* and reply with DONE or ERROR. */
static int
-handle_control_setevents(connection_t *conn, uint16_t len, const char *body)
+handle_control_setevents(connection_t *conn, uint32_t len, const char *body)
{
uint16_t event_code;
uint32_t event_mask = 0;
@@ -382,7 +406,7 @@ decode_hashed_password(char *buf, const char *hashed)
* OPEN. Reply with DONE or ERROR.
*/
static int
-handle_control_authenticate(connection_t *conn, uint16_t len, const char *body)
+handle_control_authenticate(connection_t *conn, uint32_t len, const char *body)
{
or_options_t *options = get_options();
if (options->CookieAuthentication) {
@@ -421,7 +445,7 @@ handle_control_authenticate(connection_t *conn, uint16_t len, const char *body)
}
static int
-handle_control_saveconf(connection_t *conn, uint16_t len,
+handle_control_saveconf(connection_t *conn, uint32_t len,
const char *body)
{
if (save_current_config()<0) {
@@ -434,7 +458,7 @@ handle_control_saveconf(connection_t *conn, uint16_t len,
}
static int
-handle_control_signal(connection_t *conn, uint16_t len,
+handle_control_signal(connection_t *conn, uint32_t len,
const char *body)
{
if (len != 1) {
@@ -449,7 +473,7 @@ handle_control_signal(connection_t *conn, uint16_t len,
}
static int
-handle_control_mapaddress(connection_t *conn, uint16_t len, const char *body)
+handle_control_mapaddress(connection_t *conn, uint32_t len, const char *body)
{
smartlist_t *elts;
smartlist_t *lines;
@@ -478,8 +502,9 @@ handle_control_mapaddress(connection_t *conn, uint16_t len, const char *body)
log_fn(LOG_WARN,
"Unable to allocate address for '%s' in AdressMap msg", line);
} else {
- char *ans = tor_malloc(strlen(addr)+strlen(to)+2);
- tor_snprintf(ans, "%s %s", addr, to);
+ size_t anslen = strlen(addr)+strlen(to)+2;
+ char *ans = tor_malloc(anslen);
+ tor_snprintf(ans, anslen, "%s %s", addr, to);
addressmap_register(addr, tor_strdup(to), 0);
smartlist_add(reply, ans);
}
@@ -542,7 +567,7 @@ handle_getinfo_helper(const char *question)
}
static int
-handle_control_getinfo(connection_t *conn, uint16_t len, const char *body)
+handle_control_getinfo(connection_t *conn, uint32_t len, const char *body)
{
smartlist_t *questions = NULL;
smartlist_t *answers = NULL;
@@ -574,7 +599,7 @@ handle_control_getinfo(connection_t *conn, uint16_t len, const char *body)
msg = smartlist_join_strings2(answers, "\0", 1, 1, &msg_len);
send_control_message(conn, CONTROL_CMD_INFOVALUE,
- (uint16_t)msg_len, msg_len?msg:NULL);
+ msg_len, msg_len?msg:NULL);
done:
if (answers) SMARTLIST_FOREACH(answers, char *, cp, tor_free(cp));
@@ -586,20 +611,20 @@ handle_control_getinfo(connection_t *conn, uint16_t len, const char *body)
return 0;
}
static int
-handle_control_extendcircuit(connection_t *conn, uint16_t len,
+handle_control_extendcircuit(connection_t *conn, uint32_t len,
const char *body)
{
send_control_error(conn,ERR_UNRECOGNIZED_TYPE,"not yet implemented");
return 0;
}
-static int handle_control_attachstream(connection_t *conn, uint16_t len,
+static int handle_control_attachstream(connection_t *conn, uint32_t len,
const char *body)
{
send_control_error(conn,ERR_UNRECOGNIZED_TYPE,"not yet implemented");
return 0;
}
static int
-handle_control_postdescriptor(connection_t *conn, uint16_t len,
+handle_control_postdescriptor(connection_t *conn, uint32_t len,
const char *body)
{
if (router_load_single_router(body)<0) {
@@ -634,7 +659,8 @@ int connection_control_reached_eof(connection_t *conn) {
*/
int
connection_control_process_inbuf(connection_t *conn) {
- uint16_t body_len, command_type;
+ uint32_t body_len;
+ uint16_t command_type;
char *body;
tor_assert(conn);
@@ -726,6 +752,10 @@ connection_control_process_inbuf(connection_t *conn) {
send_control_error(conn, ERR_UNRECOGNIZED_TYPE,
"Command type only valid from server to tor client");
break;
+ case CONTROL_CMD_FRAGMENTHEADER:
+ case CONTROL_CMD_FRAGMENT:
+ log_fn(LOG_WARN, "Recieved command fragment out of order; ignoring.");
+ send_control_error(conn, ERR_SYNTAX, "Bad fragmentation on command.");
default:
log_fn(LOG_WARN, "Received unrecognized command type %d; ignoring.",
(int)command_type);
@@ -756,7 +786,7 @@ control_event_circuit_status(circuit_t *circ, circuit_status_event_t tp)
set_uint32(msg+1, htonl(circ->global_identifier));
strlcpy(msg+5,path,path_len+1);
- send_control_event(EVENT_CIRCUIT_STATUS, (uint16_t)(path_len+6), msg);
+ send_control_event(EVENT_CIRCUIT_STATUS, (uint32_t)(path_len+6), msg);
tor_free(path);
tor_free(msg);
return 0;
@@ -784,7 +814,7 @@ control_event_stream_status(connection_t *conn, stream_status_event_t tp)
set_uint32(msg+1, htonl(conn->global_identifier));
strlcpy(msg+5, buf, len+1);
- send_control_event(EVENT_STREAM_STATUS, (uint16_t)(5+len+1), msg);
+ send_control_event(EVENT_STREAM_STATUS, (uint32_t)(5+len+1), msg);
tor_free(msg);
return 0;
}
@@ -805,7 +835,7 @@ control_event_or_conn_status(connection_t *conn,or_conn_status_event_t tp)
buf[0] = (uint8_t)tp;
strlcpy(buf+1,conn->nickname,sizeof(buf)-1);
len = strlen(buf+1);
- send_control_event(EVENT_OR_CONN_STATUS, (uint16_t)(len+1), buf);
+ send_control_event(EVENT_OR_CONN_STATUS, (uint32_t)(len+1), buf);
return 0;
}
@@ -837,7 +867,7 @@ control_event_logmsg(int severity, const char *msg)
return;
len = strlen(msg);
- send_control_event(EVENT_WARNING, (uint16_t)(len+1), msg);
+ send_control_event(EVENT_WARNING, (uint32_t)(len+1), msg);
}
/** Choose a random authentication cookie and write it to disk.