[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]
[or-cvs] Start implementing framework for revised control spec.
Update of /home/or/cvsroot/tor/src/or
In directory moria:/tmp/cvs-serv4325/src/or
Modified Files:
buffers.c connection.c control.c or.h
Log Message:
Start implementing framework for revised control spec.
Index: buffers.c
===================================================================
RCS file: /home/or/cvsroot/tor/src/or/buffers.c,v
retrieving revision 1.162
retrieving revision 1.163
diff -u -d -r1.162 -r1.163
--- buffers.c 11 Jun 2005 21:17:38 -0000 1.162
+++ buffers.c 17 Jun 2005 18:49:54 -0000 1.163
@@ -108,10 +108,22 @@
/** If the pointer <b>cp</b> has passed beyond the end of the buffer, wrap it
* around. */
static INLINE char *
-_wrap_ptr(buf_t *buf, char *cp) {
+_wrap_ptr(buf_t *buf, char *cp)
+{
return (cp >= buf->mem + buf->len) ? (cp - buf->len) : cp;
}
+/** Return the offset of <b>cp</b> within the buffer. */
+static INLINE int
+_buf_offset(buf_t *buf, char *cp)
+{
+ if (cp >= buf->cur)
+ return cp - buf->cur;
+ else
+ /* return (cp - buf->mem) + buf->mem+buf->len - buf->cur */
+ return cp + buf->len - buf->cur;
+}
+
/** If the range of *<b>len</b> bytes starting at <b>at</b> wraps around the
* end of the buffer, then set *<b>len</b> to the number of bytes starting
* at <b>at</b>, and set *<b>more_len</b> to the number of bytes starting
@@ -1099,7 +1111,7 @@
#define CONTROL_CMD_FRAGMENTHEADER 0x0010
#define CONTROL_CMD_FRAGMENT 0x0011
-/** If there is a complete control message waiting on buf, then store
+/** If there is a complete version 0control message waiting on buf, then store
* its contents into *<b>type_out</b>, store its body's length into
* *<b>len_out</b>, allocate and store a string for its body into
* *<b>body_out</b>, and return 1. (body_out will always be NUL-terminated,
@@ -1107,11 +1119,11 @@
*
* If there is not a complete control message waiting, return 0.
*
- * Return -1 on error.
+ * Return -1 on error; return -2 on "seems to be control protocol v1."
*/
int
-fetch_from_buf_control(buf_t *buf, uint32_t *len_out, uint16_t *type_out,
- char **body_out)
+fetch_from_buf_control0(buf_t *buf, uint32_t *len_out, uint16_t *type_out,
+ char **body_out, int check_for_v1)
{
uint32_t msglen;
uint16_t type;
@@ -1128,10 +1140,13 @@
peek_from_buf(tmp, 4, buf);
msglen = ntohs(get_uint16(tmp));
+ type = ntohs(get_uint16(tmp+2));
+ if (type > 255 && check_for_v1)
+ return -2;
+
if (buf->datalen < 4 + (unsigned)msglen)
return 0;
- type = ntohs(get_uint16(tmp+2));
*len_out = msglen;
*type_out = type;
buf_remove_from_front(buf, 4);
@@ -1145,6 +1160,57 @@
return 1;
}
+/** DOCDOC */
+static char *
+find_char_on_buf(buf_t *buf, char *start, size_t len, char c)
+{
+ size_t len_rest;
+ char *cp;
+ _split_range(buf, start, &len, &len_rest);
+ cp = memchr(buf->cur, c, len);
+ if (cp || !len_rest)
+ return cp;
+ return memchr(buf->mem, c, len_rest);
+}
+
+static char *
+find_crlf_on_buf(buf_t *buf, char *cp)
+{
+ char *next;
+ while (1) {
+ size_t remaining = buf->datalen - _buf_offset(buf,cp);
+ cp = find_char_on_buf(buf, cp, remaining, '\r');
+ if (!cp)
+ return NULL;
+ next = _wrap_ptr(buf, cp+1);
+ if (next == _buf_end(buf))
+ return NULL;
+ if (*next == '\n')
+ return cp;
+ cp = next;
+ }
+}
+
+/* DOCDOC : 0 means 'need to read more'. means done, -1 means "grow buffer." */
+int
+fetch_from_buf_line(buf_t *buf, char *data_out, size_t *data_len)
+{
+ char *eol;
+ size_t sz;
+ /* Look for a CRLF. */
+ if (!(eol = find_crlf_on_buf(buf, buf->cur)))
+ return 0;
+ sz = _buf_offset(buf, eol);
+ if (sz+2 > *data_len) {
+ *data_len = sz+2;
+ return -1;
+ }
+ fetch_from_buf(data_out, sz+2, buf);
+ *data_len = sz+2;
+ return 1;
+}
+
+
/** Log an error and exit if <b>buf</b> is corrupted.
*/
void assert_buf_ok(buf_t *buf)
Index: connection.c
===================================================================
RCS file: /home/or/cvsroot/tor/src/or/connection.c,v
retrieving revision 1.379
retrieving revision 1.380
diff -u -d -r1.379 -r1.380
--- connection.c 15 Jun 2005 18:34:46 -0000 1.379
+++ connection.c 17 Jun 2005 18:49:55 -0000 1.380
@@ -120,8 +120,12 @@
break;
case CONN_TYPE_CONTROL:
switch (state) {
- case CONTROL_CONN_STATE_OPEN: return "open";
- case CONTROL_CONN_STATE_NEEDAUTH: return "waiting for authentication";
+ case CONTROL_CONN_STATE_OPEN_V0: return "open (protocol v0)";
+ case CONTROL_CONN_STATE_OPEN_V1: return "open (protocol v1)";
+ case CONTROL_CONN_STATE_NEEDAUTH_V0:
+ return "waiting for authentication (protocol unknown)";
+ case CONTROL_CONN_STATE_NEEDAUTH_V1:
+ return "waiting for authentication (protocol v1)";
}
break;
}
@@ -667,7 +671,7 @@
conn->state = DIR_CONN_STATE_SERVER_COMMAND_WAIT;
break;
case CONN_TYPE_CONTROL:
- conn->state = CONTROL_CONN_STATE_NEEDAUTH;
+ conn->state = CONTROL_CONN_STATE_NEEDAUTH_V0;
break;
}
return 0;
@@ -1578,7 +1582,9 @@
if ((conn->type == CONN_TYPE_OR && conn->state == OR_CONN_STATE_OPEN) ||
(conn->type == CONN_TYPE_AP && conn->state == AP_CONN_STATE_OPEN) ||
(conn->type == CONN_TYPE_EXIT && conn->state == EXIT_CONN_STATE_OPEN) ||
- (conn->type == CONN_TYPE_CONTROL && conn->state ==CONTROL_CONN_STATE_OPEN))
+ (conn->type == CONN_TYPE_CONTROL &&
+ (conn->state == CONTROL_CONN_STATE_OPEN_V0 ||
+ conn->state == CONTROL_CONN_STATE_OPEN_V1)))
return 1;
return 0;
Index: control.c
===================================================================
RCS file: /home/or/cvsroot/tor/src/or/control.c,v
retrieving revision 1.88
retrieving revision 1.89
diff -u -d -r1.88 -r1.89
--- control.c 11 Jun 2005 18:59:24 -0000 1.88
+++ control.c 17 Jun 2005 18:49:55 -0000 1.89
@@ -10,47 +10,38 @@
#include "or.h"
-/* Protocol outline: a bidirectional stream, over which each side
- * sends a series of messages. Each message has a two-byte length field,
- * a two-byte typecode, and a variable-length body whose length is
- * given in the length field.
- *
- * By default, the server only sends messages in response to client messages.
- * Every client message gets a message in response. The client may, however,
- * _request_ that other messages be delivered asynchronously.
- *
- *
- * Every message type is either client-only or server-only, and every
- * server message type is either synchronous-only (only occurs in
- * response to a client request) or asynchronous-only (never is an
- * answer to a client request.
- *
- * See control-spec.txt for full details.
+#define STATE_IS_OPEN(s) ((s) == CONTROL_CONN_STATE_OPEN_V0 || \
+ (s) == CONTROL_CONN_STATE_OPEN_V1)
+#define STATE_IS_V0(s) ((s) == CONTROL_CONN_STATE_NEEDAUTH_V0 || \
+ (s) == CONTROL_CONN_STATE_OPEN_V0)
+
+/*
+ * See control-spec.txt and control-spec-v0.txt for full details on protocol(s).
*/
/* Recognized message type codes. */
-#define CONTROL_CMD_ERROR 0x0000
-#define CONTROL_CMD_DONE 0x0001
-#define CONTROL_CMD_SETCONF 0x0002
-#define CONTROL_CMD_GETCONF 0x0003
-#define CONTROL_CMD_CONFVALUE 0x0004
-#define CONTROL_CMD_SETEVENTS 0x0005
-#define CONTROL_CMD_EVENT 0x0006
-#define CONTROL_CMD_AUTHENTICATE 0x0007
-#define CONTROL_CMD_SAVECONF 0x0008
-#define CONTROL_CMD_SIGNAL 0x0009
-#define CONTROL_CMD_MAPADDRESS 0x000A
-#define CONTROL_CMD_GETINFO 0x000B
-#define CONTROL_CMD_INFOVALUE 0x000C
-#define CONTROL_CMD_EXTENDCIRCUIT 0x000D
-#define CONTROL_CMD_ATTACHSTREAM 0x000E
-#define CONTROL_CMD_POSTDESCRIPTOR 0x000F
-#define CONTROL_CMD_FRAGMENTHEADER 0x0010
-#define CONTROL_CMD_FRAGMENT 0x0011
-#define CONTROL_CMD_REDIRECTSTREAM 0x0012
-#define CONTROL_CMD_CLOSESTREAM 0x0013
-#define CONTROL_CMD_CLOSECIRCUIT 0x0014
-#define _CONTROL_CMD_MAX_RECOGNIZED 0x0014
+#define CONTROL0_CMD_ERROR 0x0000
+#define CONTROL0_CMD_DONE 0x0001
+#define CONTROL0_CMD_SETCONF 0x0002
+#define CONTROL0_CMD_GETCONF 0x0003
+#define CONTROL0_CMD_CONFVALUE 0x0004
+#define CONTROL0_CMD_SETEVENTS 0x0005
+#define CONTROL0_CMD_EVENT 0x0006
+#define CONTROL0_CMD_AUTHENTICATE 0x0007
+#define CONTROL0_CMD_SAVECONF 0x0008
+#define CONTROL0_CMD_SIGNAL 0x0009
+#define CONTROL0_CMD_MAPADDRESS 0x000A
+#define CONTROL0_CMD_GETINFO 0x000B
+#define CONTROL0_CMD_INFOVALUE 0x000C
+#define CONTROL0_CMD_EXTENDCIRCUIT 0x000D
+#define CONTROL0_CMD_ATTACHSTREAM 0x000E
+#define CONTROL0_CMD_POSTDESCRIPTOR 0x000F
+#define CONTROL0_CMD_FRAGMENTHEADER 0x0010
+#define CONTROL0_CMD_FRAGMENT 0x0011
+#define CONTROL0_CMD_REDIRECTSTREAM 0x0012
+#define CONTROL0_CMD_CLOSESTREAM 0x0013
+#define CONTROL0_CMD_CLOSECIRCUIT 0x0014
+#define _CONTROL0_CMD_MAX_RECOGNIZED 0x0014
/* Recognized error codes. */
#define ERR_UNSPECIFIED 0x0000
@@ -84,7 +75,7 @@
/** Array mapping from message type codes to human-readable message
* type names. */
-static const char * CONTROL_COMMANDS[_CONTROL_CMD_MAX_RECOGNIZED+1] = {
+static const char * CONTROL0_COMMANDS[_CONTROL0_CMD_MAX_RECOGNIZED+1] = {
"error",
"done",
"setconf",
@@ -127,13 +118,13 @@
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,
+static void send_control0_message(connection_t *conn, uint16_t type,
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,
+static void send_control0_error(connection_t *conn, uint16_t error,
const char *message);
-static void send_control_event(uint16_t event, uint32_t len, const char *body);
+static void send_control0_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, uint32_t len,
@@ -168,7 +159,7 @@
static INLINE const char *
control_cmd_to_string(uint16_t cmd)
{
- return (cmd<=_CONTROL_CMD_MAX_RECOGNIZED) ? CONTROL_COMMANDS[cmd] : "Unknown";
+ return (cmd<=_CONTROL0_CMD_MAX_RECOGNIZED) ? CONTROL0_COMMANDS[cmd] : "Unknown";
}
static INLINE int
@@ -209,7 +200,7 @@
get_connection_array(&conns, &n_conns);
for (i = 0; i < n_conns; ++i) {
if (conns[i]->type == CONN_TYPE_CONTROL &&
- conns[i]->state == CONTROL_CONN_STATE_OPEN) {
+ STATE_IS_OPEN(conns[i]->state)) {
global_event_mask |= conns[i]->event_mask;
}
}
@@ -247,16 +238,45 @@
control_event_logmsg);
}
+static INLINE void
+connection_write_str_to_buf(const char *s, connection_t *conn)
+{
+ size_t len = strlen(s);
+ connection_write_to_buf(s, len, conn);
+}
+
+
+static void
+connection_printf_to_buf(connection_t *conn, const char *format, ...)
+{
+ va_list ap;
+ char buf[1024];
+ int r;
+ size_t len;
+ va_start(ap,format);
+ r = tor_snprintf(buf, sizeof(buf), format, ap);
+ va_end(ap);
+ len = strlen(buf);
+ if (memcmp("\r\n\0", buf+len-2, 3)) {
+ buf[1023] = '\0';
+ buf[1022] = '\n';
+ buf[1021] = '\r';
+ }
+ connection_write_to_buf(buf, len, conn);
+}
+
+
/** 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, uint32_t len,
+send_control0_message(connection_t *conn, uint16_t type, uint32_t len,
const char *body)
{
char buf[10];
tor_assert(conn);
+ tor_assert(STATE_IS_V0(conn->state));
tor_assert(len || !body);
- tor_assert(type <= _CONTROL_CMD_MAX_RECOGNIZED);
+ tor_assert(type <= _CONTROL0_CMD_MAX_RECOGNIZED);
if (len < 65536) {
set_uint16(buf, htons(len));
set_uint16(buf+2, htons(type));
@@ -265,7 +285,7 @@
connection_write_to_buf(body, len, conn);
} else {
set_uint16(buf, htons(65535));
- set_uint16(buf+2, htons(CONTROL_CMD_FRAGMENTHEADER));
+ set_uint16(buf+2, htons(CONTROL0_CMD_FRAGMENTHEADER));
set_uint16(buf+4, htons(type));
set_uint32(buf+6, htonl(len));
connection_write_to_buf(buf, 10, conn);
@@ -275,7 +295,7 @@
while (len) {
size_t chunklen = (len<65535)?len:65535;
set_uint16(buf, htons((uint16_t)chunklen));
- set_uint16(buf+2, htons(CONTROL_CMD_FRAGMENT));
+ set_uint16(buf+2, htons(CONTROL0_CMD_FRAGMENT));
connection_write_to_buf(buf, 4, conn);
connection_write_to_buf(body, chunklen, conn);
len -= chunklen;
@@ -288,7 +308,11 @@
static void
send_control_done(connection_t *conn)
{
- send_control_message(conn, CONTROL_CMD_DONE, 0, NULL);
+ if (STATE_IS_V0(conn->state)) {
+ send_control0_message(conn, CONTROL0_CMD_DONE, 0, NULL);
+ } else {
+ connection_write_str_to_buf("250 OK\r\n", conn);
+ }
}
/** DOCDOC */
@@ -297,13 +321,13 @@
{
if (len==0)
len = strlen(msg);
- send_control_message(conn, CONTROL_CMD_DONE, len, msg);
+ send_control0_message(conn, CONTROL0_CMD_DONE, len, msg);
}
/** Send an error message with error code <b>error</b> and body
* <b>message</b> down the connection <b>conn</b> */
static void
-send_control_error(connection_t *conn, uint16_t error, const char *message)
+send_control0_error(connection_t *conn, uint16_t error, const char *message)
{
char buf[256];
size_t len;
@@ -311,14 +335,14 @@
len = strlen(message);
tor_assert(len < (256-2));
memcpy(buf+2, message, len);
- send_control_message(conn, CONTROL_CMD_ERROR, (uint16_t)(len+2), buf);
+ send_control0_message(conn, CONTROL0_CMD_ERROR, (uint16_t)(len+2), buf);
}
/** Send an 'event' message of event type <b>event</b>, containing
* <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, uint32_t len, const char *body)
+send_control0_event(uint16_t event, uint32_t len, const char *body)
{
connection_t **conns;
int n_conns, i;
@@ -335,9 +359,9 @@
get_connection_array(&conns, &n_conns);
for (i = 0; i < n_conns; ++i) {
if (conns[i]->type == CONN_TYPE_CONTROL &&
- conns[i]->state == CONTROL_CONN_STATE_OPEN &&
+ conns[i]->state == CONTROL_CONN_STATE_OPEN_V0 &&
conns[i]->event_mask & (1<<event)) {
- send_control_message(conns[i], CONTROL_CMD_EVENT, buflen, buf);
+ send_control0_message(conns[i], CONTROL0_CMD_EVENT, buflen, buf);
if (event == EVENT_ERR_MSG) {
_connection_controller_force_write(conns[i]);
}
@@ -357,17 +381,17 @@
if (config_get_lines(body, &lines) < 0) {
log_fn(LOG_WARN,"Controller gave us config lines we can't parse.");
- send_control_error(conn, ERR_SYNTAX, "Couldn't parse configuration");
+ send_control0_error(conn, ERR_SYNTAX, "Couldn't parse configuration");
return 0;
}
if ((r=config_trial_assign(lines, 1)) < 0) {
log_fn(LOG_WARN,"Controller gave us config lines that didn't validate.");
if (r==-1) {
- send_control_error(conn, ERR_UNRECOGNIZED_CONFIG_KEY,
+ send_control0_error(conn, ERR_UNRECOGNIZED_CONFIG_KEY,
"Unrecognized option");
} else {
- send_control_error(conn, ERR_INVALID_CONFIG_VALUE,"Invalid option value");
+ send_control0_error(conn, ERR_INVALID_CONFIG_VALUE,"Invalid option value");
}
config_free_lines(lines);
return 0;
@@ -401,7 +425,7 @@
{
int recognized = config_option_is_recognized(q);
if (!recognized) {
- send_control_error(conn, ERR_UNRECOGNIZED_CONFIG_KEY, q);
+ send_control0_error(conn, ERR_UNRECOGNIZED_CONFIG_KEY, q);
goto done;
} else {
struct config_line_t *answer = config_get_assigned_option(options,q);
@@ -423,7 +447,7 @@
});
msg = smartlist_join_strings(answers, "", 0, &msg_len);
- send_control_message(conn, CONTROL_CMD_CONFVALUE,
+ send_control0_message(conn, CONTROL0_CMD_CONFVALUE,
(uint16_t)msg_len, msg_len?msg:NULL);
done:
@@ -444,7 +468,7 @@
uint16_t event_code;
uint32_t event_mask = 0;
if (len % 2) {
- send_control_error(conn, ERR_SYNTAX,
+ send_control0_error(conn, ERR_SYNTAX,
"Odd number of bytes in setevents message");
return 0;
}
@@ -452,7 +476,7 @@
for (; len; len -= 2, body += 2) {
event_code = ntohs(get_uint16(body));
if (event_code < _EVENT_MIN || event_code > _EVENT_MAX) {
- send_control_error(conn, ERR_UNRECOGNIZED_EVENT_CODE,
+ send_control0_error(conn, ERR_UNRECOGNIZED_EVENT_CODE,
"Unrecognized event code");
return 0;
}
@@ -525,12 +549,15 @@
}
err:
- send_control_error(conn, ERR_REJECTED_AUTHENTICATION,"Authentication failed");
+ send_control0_error(conn, ERR_REJECTED_AUTHENTICATION,"Authentication failed");
return 0;
ok:
log_fn(LOG_INFO, "Authenticated control connection (%d)", conn->s);
send_control_done(conn);
- conn->state = CONTROL_CONN_STATE_OPEN;
+ if (STATE_IS_V0(conn->state))
+ conn->state = CONTROL_CONN_STATE_OPEN_V0;
+ else
+ conn->state = CONTROL_CONN_STATE_OPEN_V1;
return 0;
}
@@ -540,7 +567,7 @@
const char *body)
{
if (save_current_config()<0) {
- send_control_error(conn, ERR_INTERNAL,
+ send_control0_error(conn, ERR_INTERNAL,
"Unable to write configuration to disk.");
} else {
send_control_done(conn);
@@ -554,10 +581,10 @@
const char *body)
{
if (len != 1) {
- send_control_error(conn, ERR_SYNTAX,
+ send_control0_error(conn, ERR_SYNTAX,
"Body of SIGNAL command too long or too short.");
} else if (control_signal_act((uint8_t)body[0]) < 0) {
- send_control_error(conn, ERR_SYNTAX, "Unrecognized signal number.");
+ send_control0_error(conn, ERR_SYNTAX, "Unrecognized signal number.");
} else {
send_control_done(conn);
}
@@ -689,10 +716,10 @@
SMARTLIST_FOREACH(questions, const char *, q,
{
if (handle_getinfo_helper(q, &ans) < 0) {
- send_control_error(conn, ERR_INTERNAL, body);
+ send_control0_error(conn, ERR_INTERNAL, body);
goto done;
} if (!ans) {
- send_control_error(conn, ERR_UNRECOGNIZED_CONFIG_KEY, body);
+ send_control0_error(conn, ERR_UNRECOGNIZED_CONFIG_KEY, body);
goto done;
}
smartlist_add(answers, tor_strdup(q));
@@ -701,7 +728,7 @@
msg = smartlist_join_strings2(answers, "\0", 1, 1, &msg_len);
tor_assert(msg_len > 0); /* it will at least be terminated */
- send_control_message(conn, CONTROL_CMD_INFOVALUE,
+ send_control0_message(conn, CONTROL0_CMD_INFOVALUE,
msg_len, msg);
done:
@@ -724,7 +751,7 @@
circuit_t *circ;
char reply[4];
if (len<5) {
- send_control_error(conn, ERR_SYNTAX, "extendcircuit message too short");
+ send_control0_error(conn, ERR_SYNTAX, "extendcircuit message too short");
return 0;
}
@@ -735,13 +762,13 @@
{
routerinfo_t *r = router_get_by_nickname(n);
if (!r) {
- send_control_error(conn, ERR_NO_ROUTER, n);
+ send_control0_error(conn, ERR_NO_ROUTER, n);
goto done;
}
smartlist_add(routers, r);
});
if (!smartlist_len(routers)) {
- send_control_error(conn, ERR_SYNTAX, "No router names provided");
+ send_control0_error(conn, ERR_SYNTAX, "No router names provided");
goto done;
}
@@ -752,7 +779,7 @@
} else {
circ = circuit_get_by_global_id(circ_id);
if (!circ) {
- send_control_error(conn, ERR_NO_CIRC,
+ send_control0_error(conn, ERR_NO_CIRC,
"No circuit found with given ID");
goto done;
}
@@ -769,7 +796,7 @@
if (!circ_id) {
if (circuit_handle_first_hop(circ) < 0) {
circuit_mark_for_close(circ);
- send_control_error(conn, ERR_INTERNAL, "couldn't start circuit");
+ send_control0_error(conn, ERR_INTERNAL, "couldn't start circuit");
goto done;
}
} else {
@@ -778,7 +805,7 @@
if (circuit_send_next_onion_skin(circ) < 0) {
log_fn(LOG_INFO,"send_next_onion_skin failed; circuit marked for closing.");
circuit_mark_for_close(circ);
- send_control_error(conn, ERR_INTERNAL, "couldn't send onion skin");
+ send_control0_error(conn, ERR_INTERNAL, "couldn't send onion skin");
goto done;
}
}
@@ -804,7 +831,7 @@
circuit_t *circ;
if (len < 8) {
- send_control_error(conn, ERR_SYNTAX, "attachstream message too short");
+ send_control0_error(conn, ERR_SYNTAX, "attachstream message too short");
return 0;
}
@@ -812,12 +839,12 @@
circ_id = ntohl(get_uint32(body+4));
if (!(ap_conn = connection_get_by_global_id(conn_id))) {
- send_control_error(conn, ERR_NO_STREAM,
+ send_control0_error(conn, ERR_NO_STREAM,
"No connection found with given ID");
return 0;
}
if (ap_conn->state != AP_CONN_STATE_CONTROLLER_WAIT) {
- send_control_error(conn, ERR_NO_STREAM,
+ send_control0_error(conn, ERR_NO_STREAM,
"Connection was not managed by controller.");
return 0;
}
@@ -831,15 +858,15 @@
}
if (!(circ = circuit_get_by_global_id(circ_id))) {
- send_control_error(conn, ERR_NO_CIRC, "No circuit found with given ID");
+ send_control0_error(conn, ERR_NO_CIRC, "No circuit found with given ID");
return 0;
}
if (circ->state != CIRCUIT_STATE_OPEN) {
- send_control_error(conn, ERR_INTERNAL, "Refuse to attach stream to non-open circ.");
+ send_control0_error(conn, ERR_INTERNAL, "Refuse to attach stream to non-open circ.");
return 0;
}
if (connection_ap_handshake_attach_chosen_circuit(ap_conn, circ) != 1) {
- send_control_error(conn, ERR_INTERNAL, "Unable to attach stream.");
+ send_control0_error(conn, ERR_INTERNAL, "Unable to attach stream.");
return 0;
}
send_control_done(conn);
@@ -854,7 +881,7 @@
const char *msg=NULL;
switch (router_load_single_router(body, &msg)) {
case -1:
- send_control_error(conn,ERR_SYNTAX,msg?msg: "Could not parse descriptor");
+ send_control0_error(conn,ERR_SYNTAX,msg?msg: "Could not parse descriptor");
break;
case 0:
send_control_done2(conn,msg?msg: "Descriptor not added",0);
@@ -875,7 +902,7 @@
connection_t *ap_conn;
uint32_t conn_id;
if (len < 6) {
- send_control_error(conn, ERR_SYNTAX, "redirectstream message too short");
+ send_control0_error(conn, ERR_SYNTAX, "redirectstream message too short");
return 0;
}
conn_id = ntohl(get_uint32(body));
@@ -883,7 +910,7 @@
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,
+ send_control0_error(conn, ERR_NO_STREAM,
"No AP connection found with given ID");
return 0;
}
@@ -904,7 +931,7 @@
uint8_t reason;
if (len < 6) {
- send_control_error(conn, ERR_SYNTAX, "closestream message too short");
+ send_control0_error(conn, ERR_SYNTAX, "closestream message too short");
return 0;
}
@@ -914,7 +941,7 @@
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,
+ send_control0_error(conn, ERR_NO_STREAM,
"No AP connection found with given ID");
return 0;
}
@@ -933,14 +960,14 @@
int safe;
if (len < 5) {
- send_control_error(conn, ERR_SYNTAX, "closecircuit message too short");
+ send_control0_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,
+ send_control0_error(conn, ERR_NO_CIRC,
"No circuit found with given ID");
return 0;
}
@@ -958,13 +985,13 @@
handle_control_fragments(connection_t *conn, uint16_t command_type,
uint32_t body_len, char *body)
{
- if (command_type == CONTROL_CMD_FRAGMENTHEADER) {
+ if (command_type == CONTROL0_CMD_FRAGMENTHEADER) {
if (conn->incoming_cmd) {
log_fn(LOG_WARN, "Dropping incomplete fragmented command");
tor_free(conn->incoming_cmd);
}
if (body_len < 6) {
- send_control_error(conn, ERR_SYNTAX, "FRAGMENTHEADER too short.");
+ send_control0_error(conn, ERR_SYNTAX, "FRAGMENTHEADER too short.");
return 0;
}
conn->incoming_cmd_type = ntohs(get_uint16(body));
@@ -973,9 +1000,9 @@
conn->incoming_cmd = tor_malloc(conn->incoming_cmd_len);
body += 6;
body_len -= 6;
- } else if (command_type == CONTROL_CMD_FRAGMENT) {
+ } else if (command_type == CONTROL0_CMD_FRAGMENT) {
if (!conn->incoming_cmd) {
- send_control_error(conn, ERR_SYNTAX, "Out-of-place FRAGMENT");
+ send_control0_error(conn, ERR_SYNTAX, "Out-of-place FRAGMENT");
return 0;
}
} else {
@@ -984,7 +1011,7 @@
if (conn->incoming_cmd_cur_len + body_len > conn->incoming_cmd_len) {
tor_free(conn->incoming_cmd);
- send_control_error(conn, ERR_SYNTAX,
+ send_control0_error(conn, ERR_SYNTAX,
"Fragmented data exceeds declared length");
return 0;
}
@@ -1009,27 +1036,150 @@
int
connection_control_reached_eof(connection_t *conn)
{
+ tor_assert(conn);
+ tor_assert(conn->type == CONN_TYPE_CONTROL);
+
log_fn(LOG_INFO,"Control connection reached EOF. Closing.");
connection_mark_for_close(conn);
return 0;
}
-/** Called when <b>conn</b> has received more bytes on its inbuf.
- */
-int
-connection_control_process_inbuf(connection_t *conn)
+static int
+connection_control_process_inbuf_v1(connection_t *conn)
{
- uint32_t body_len;
- uint16_t command_type;
- char *body;
+ size_t data_len, cmd_len;
tor_assert(conn);
tor_assert(conn->type == CONN_TYPE_CONTROL);
+ tor_assert(conn->state == CONTROL_CONN_STATE_OPEN_V1 ||
+ conn->state == CONTROL_CONN_STATE_NEEDAUTH_V1);
+
+ if (!conn->incoming_cmd) {
+ conn->incoming_cmd = tor_malloc(1024);
+ conn->incoming_cmd_len = 1024;
+ conn->incoming_cmd_cur_len = 0;
+ }
+
+ again:
+ while (1) {
+ size_t last_idx;
+ int r;
+ while (1) {
+ data_len = conn->incoming_cmd_len - conn->incoming_cmd_cur_len;
+ r = fetch_from_buf_line(conn->inbuf,
+ conn->incoming_cmd+conn->incoming_cmd_cur_len,
+ &data_len);
+ if (r == 0)
+ /* Line not all here yet. Wait. */
+ return 0;
+ else if (r == -1) {
+ while (conn->incoming_cmd_len < data_len)
+ conn->incoming_cmd_len *= 2;
+ conn->incoming_cmd = tor_realloc(conn->incoming_cmd, conn->incoming_cmd_len);
+ }
+ } while (r != 1);
+
+ tor_assert(data_len);
+
+ last_idx = conn->incoming_cmd_cur_len;
+ conn->incoming_cmd_cur_len += data_len;
+
+ /* We have appended a line to incoming_cmd. Is the command done? */
+ if (last_idx == 0 && *conn->incoming_cmd != '+')
+ /* One line command, didn't start with '+'. */
+ break;
+ if (last_idx+3 == conn->incoming_cmd_cur_len &&
+ !memcmp(conn->incoming_cmd + last_idx, ".\r\n", 3))
+ /* Just appended ".\r\n"; we're done. */
+ break;
+ /* Otherwise, read another line. */
+ }
+ data_len = conn->incoming_cmd_cur_len;
+ /* Okay, we now have a command sitting on conn->incoming_cmd. See if we
+ * recognize it.
+ */
+ while (cmd_len < data_len && !isspace(conn->incoming_cmd[cmd_len]))
+ ++cmd_len;
+
+ if (conn->state == CONTROL_CONN_STATE_NEEDAUTH_V1 &&
+ strncasecmp(conn->incoming_cmd, "AUTHENTICATE", cmd_len)) {
+ connection_write_str_to_buf("514 Authentication required.\r\n", conn);
+ conn->incoming_cmd_cur_len = 0;
+ goto again;
+ }
+
+ if (!strncasecmp(conn->incoming_cmd, "SETCONF", cmd_len)) {
+ if (handle_control_setconf(conn, 0, NULL))
+ return -1;
+ } else if (!strncasecmp(conn->incoming_cmd, "GETCONF", cmd_len)) {
+ if (handle_control_getconf(conn, 0, NULL))
+ return -1;
+ } else if (!strncasecmp(conn->incoming_cmd, "SETEVENTS", cmd_len)) {
+ if (handle_control_setevents(conn, 0, NULL))
+ return -1;
+ } else if (!strncasecmp(conn->incoming_cmd, "AUTENTICATE", cmd_len)) {
+ if (handle_control_authenticate(conn, 0, NULL))
+ return -1;
+ } else if (!strncasecmp(conn->incoming_cmd, "SAVECONF", cmd_len)) {
+ if (handle_control_saveconf(conn, 0, NULL))
+ return -1;
+ } else if (!strncasecmp(conn->incoming_cmd, "SIGNAL", cmd_len)) {
+ if (handle_control_signal(conn, 0, NULL))
+ return -1;
+ } else if (!strncasecmp(conn->incoming_cmd, "MAPADDRESS", cmd_len)) {
+ if (handle_control_mapaddress(conn, 0, NULL))
+ return -1;
+ } else if (!strncasecmp(conn->incoming_cmd, "GETINFO", cmd_len)) {
+ if (handle_control_getinfo(conn, 0, NULL))
+ return -1;
+ } else if (!strncasecmp(conn->incoming_cmd, "EXTENDCIRCUIT", cmd_len)) {
+ if (handle_control_extendcircuit(conn, 0, NULL))
+ return -1;
+ } else if (!strncasecmp(conn->incoming_cmd, "ATTACHSTREAM", cmd_len)) {
+ if (handle_control_attachstream(conn, 0, NULL))
+ return -1;
+ } else if (!strncasecmp(conn->incoming_cmd, "+POSTDESCRIPTOR", cmd_len)) {
+ if (handle_control_postdescriptor(conn, 0, NULL))
+ return -1;
+ } else if (!strncasecmp(conn->incoming_cmd, "REDIRECTSTREAM", cmd_len)) {
+ if (handle_control_redirectstream(conn, 0, NULL))
+ return -1;
+ } else if (!strncasecmp(conn->incoming_cmd, "CLOSESTREAM", cmd_len)) {
+ if (handle_control_closestream(conn, 0, NULL))
+ return -1;
+ } else if (!strncasecmp(conn->incoming_cmd, "CLOSECIRCUIT", cmd_len)) {
+ if (handle_control_closecircuit(conn, 0, NULL))
+ return -1;
+ } else {
+ conn->incoming_cmd[cmd_len] = '\0';
+ connection_printf_to_buf(conn, "510 Unrecognizd command \"%s\"\r\n",
+ conn->incoming_cmd);
+ }
+
+ conn->incoming_cmd_cur_len = 0;
+ goto again;
+
+}
+
+
+static int
+connection_control_process_inbuf_v0(connection_t *conn)
+{
+ uint32_t body_len;
+ uint16_t command_type;
+ char *body;
again:
/* Try to suck a control message from the buffer. */
- switch (fetch_from_buf_control(conn->inbuf, &body_len, &command_type, &body))
+ switch (fetch_from_buf_control0(conn->inbuf, &body_len, &command_type, &body,
+ conn->state == CONTROL_CONN_STATE_NEEDAUTH_V0))
{
+ case -2:
+ tor_free(body);
+ log_fn(LOG_INFO, "Detected v1 contol protocol on connection (fd %d)",
+ conn->s);
+ conn->state = CONTROL_CONN_STATE_NEEDAUTH_V1;
+ return connection_control_process_inbuf_v1(conn);
case -1:
tor_free(body);
log_fn(LOG_WARN, "Error in control command. Failing.");
@@ -1046,17 +1196,17 @@
/* We got a command. If we need authentication, only authentication
* commands will be considered. */
- if (conn->state == CONTROL_CONN_STATE_NEEDAUTH &&
- command_type != CONTROL_CMD_AUTHENTICATE) {
+ if (conn->state == CONTROL_CONN_STATE_NEEDAUTH_V0 &&
+ command_type != CONTROL0_CMD_AUTHENTICATE) {
log_fn(LOG_WARN, "Rejecting '%s' command; authentication needed.",
control_cmd_to_string(command_type));
- send_control_error(conn, ERR_UNAUTHORIZED, "Authentication required");
+ send_control0_error(conn, ERR_UNAUTHORIZED, "Authentication required");
tor_free(body);
goto again;
}
- if (command_type == CONTROL_CMD_FRAGMENTHEADER ||
- command_type == CONTROL_CMD_FRAGMENT) {
+ if (command_type == CONTROL0_CMD_FRAGMENTHEADER ||
+ command_type == CONTROL0_CMD_FRAGMENT) {
if (handle_control_fragments(conn, command_type, body_len, body))
return -1;
tor_free(body);
@@ -1075,80 +1225,80 @@
/* Okay, we're willing to process the command. */
switch (command_type)
{
- case CONTROL_CMD_SETCONF:
+ case CONTROL0_CMD_SETCONF:
if (handle_control_setconf(conn, body_len, body))
return -1;
break;
- case CONTROL_CMD_GETCONF:
+ case CONTROL0_CMD_GETCONF:
if (handle_control_getconf(conn, body_len, body))
return -1;
break;
- case CONTROL_CMD_SETEVENTS:
+ case CONTROL0_CMD_SETEVENTS:
if (handle_control_setevents(conn, body_len, body))
return -1;
break;
- case CONTROL_CMD_AUTHENTICATE:
+ case CONTROL0_CMD_AUTHENTICATE:
if (handle_control_authenticate(conn, body_len, body))
return -1;
break;
- case CONTROL_CMD_SAVECONF:
+ case CONTROL0_CMD_SAVECONF:
if (handle_control_saveconf(conn, body_len, body))
return -1;
break;
- case CONTROL_CMD_SIGNAL:
+ case CONTROL0_CMD_SIGNAL:
if (handle_control_signal(conn, body_len, body))
return -1;
break;
- case CONTROL_CMD_MAPADDRESS:
+ case CONTROL0_CMD_MAPADDRESS:
if (handle_control_mapaddress(conn, body_len, body))
return -1;
break;
- case CONTROL_CMD_GETINFO:
+ case CONTROL0_CMD_GETINFO:
if (handle_control_getinfo(conn, body_len, body))
return -1;
break;
- case CONTROL_CMD_EXTENDCIRCUIT:
+ case CONTROL0_CMD_EXTENDCIRCUIT:
if (handle_control_extendcircuit(conn, body_len, body))
return -1;
break;
- case CONTROL_CMD_ATTACHSTREAM:
+ case CONTROL0_CMD_ATTACHSTREAM:
if (handle_control_attachstream(conn, body_len, body))
return -1;
break;
- case CONTROL_CMD_POSTDESCRIPTOR:
+ case CONTROL0_CMD_POSTDESCRIPTOR:
if (handle_control_postdescriptor(conn, body_len, body))
return -1;
break;
- case CONTROL_CMD_REDIRECTSTREAM:
+ case CONTROL0_CMD_REDIRECTSTREAM:
if (handle_control_redirectstream(conn, body_len, body))
return -1;
break;
- case CONTROL_CMD_CLOSESTREAM:
+ case CONTROL0_CMD_CLOSESTREAM:
if (handle_control_closestream(conn, body_len, body))
return -1;
break;
- case CONTROL_CMD_CLOSECIRCUIT:
+ case CONTROL0_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:
- case CONTROL_CMD_EVENT:
- case CONTROL_CMD_INFOVALUE:
+ case CONTROL0_CMD_ERROR:
+ case CONTROL0_CMD_DONE:
+ case CONTROL0_CMD_CONFVALUE:
+ case CONTROL0_CMD_EVENT:
+ case CONTROL0_CMD_INFOVALUE:
log_fn(LOG_WARN, "Received client-only '%s' command; ignoring.",
control_cmd_to_string(command_type));
- send_control_error(conn, ERR_UNRECOGNIZED_TYPE,
+ send_control0_error(conn, ERR_UNRECOGNIZED_TYPE,
"Command type only valid from server to tor client");
break;
- case CONTROL_CMD_FRAGMENTHEADER:
- case CONTROL_CMD_FRAGMENT:
+ case CONTROL0_CMD_FRAGMENTHEADER:
+ case CONTROL0_CMD_FRAGMENT:
log_fn(LOG_WARN, "Recieved command fragment out of order; ignoring.");
- send_control_error(conn, ERR_SYNTAX, "Bad fragmentation on command.");
+ send_control0_error(conn, ERR_SYNTAX, "Bad fragmentation on command.");
default:
log_fn(LOG_WARN, "Received unrecognized command type %d; ignoring.",
(int)command_type);
- send_control_error(conn, ERR_UNRECOGNIZED_TYPE,
+ send_control0_error(conn, ERR_UNRECOGNIZED_TYPE,
"Unrecognized command type");
break;
}
@@ -1156,6 +1306,20 @@
goto again; /* There might be more data. */
}
+/** Called when <b>conn</b> has received more bytes on its inbuf.
+ */
+int
+connection_control_process_inbuf(connection_t *conn)
+{
+ tor_assert(conn);
+ tor_assert(conn->type == CONN_TYPE_CONTROL);
+
+ if (STATE_IS_V0(conn->state))
+ return connection_control_process_inbuf_v0(conn);
+ else
+ return connection_control_process_inbuf_v1(conn);
+}
+
/** Something has happened to circuit <b>circ</b>: tell any interested
* control connections. */
int
@@ -1175,7 +1339,7 @@
set_uint32(msg+1, htonl(circ->global_identifier));
strlcpy(msg+5,path,path_len+1);
- send_control_event(EVENT_CIRCUIT_STATUS, (uint32_t)(path_len+6), msg);
+ send_control0_event(EVENT_CIRCUIT_STATUS, (uint32_t)(path_len+6), msg);
tor_free(path);
tor_free(msg);
return 0;
@@ -1207,7 +1371,7 @@
set_uint32(msg+1, htonl(conn->global_identifier));
strlcpy(msg+5, buf, len+1);
- send_control_event(EVENT_STREAM_STATUS, (uint32_t)(5+len+1), msg);
+ send_control0_event(EVENT_STREAM_STATUS, (uint32_t)(5+len+1), msg);
tor_free(msg);
return 0;
}
@@ -1228,7 +1392,7 @@
buf[0] = (uint8_t)tp;
strlcpy(buf+1,conn->nickname,sizeof(buf)-1);
len = strlen(buf+1);
- send_control_event(EVENT_OR_CONN_STATUS, (uint32_t)(len+1), buf);
+ send_control0_event(EVENT_OR_CONN_STATUS, (uint32_t)(len+1), buf);
return 0;
}
@@ -1244,7 +1408,7 @@
set_uint32(buf, htonl(n_read));
set_uint32(buf+4, htonl(n_written));
- send_control_event(EVENT_BANDWIDTH_USED, 8, buf);
+ send_control0_event(EVENT_BANDWIDTH_USED, 8, buf);
return 0;
}
@@ -1270,9 +1434,9 @@
size_t len = strlen(msg);
sending_logmsg = 1;
if (event)
- send_control_event(event, (uint32_t)(len+1), msg);
+ send_control0_event(event, (uint32_t)(len+1), msg);
if (oldlog)
- send_control_event(EVENT_LOG_OBSOLETE, (uint32_t)(len+1), msg);
+ send_control0_event(EVENT_LOG_OBSOLETE, (uint32_t)(len+1), msg);
sending_logmsg = 0;
}
}
@@ -1298,7 +1462,7 @@
smartlist_add(identities, tor_strdup(buf));
});
msg = smartlist_join_strings(identities, ",", 1, &len);
- send_control_event(EVENT_NEW_DESC, len+1, msg);
+ send_control0_event(EVENT_NEW_DESC, len+1, msg);
SMARTLIST_FOREACH(identities, char *, cp, tor_free(cp));
smartlist_free(identities);
Index: or.h
===================================================================
RCS file: /home/or/cvsroot/tor/src/or/or.h,v
retrieving revision 1.616
retrieving revision 1.617
diff -u -d -r1.616 -r1.617
--- or.h 15 Jun 2005 18:34:46 -0000 1.616
+++ or.h 17 Jun 2005 18:49:55 -0000 1.617
@@ -286,9 +286,11 @@
#define _DIR_CONN_STATE_MAX 5
#define _CONTROL_CONN_STATE_MIN 1
-#define CONTROL_CONN_STATE_OPEN 1
-#define CONTROL_CONN_STATE_NEEDAUTH 2
-#define _CONTROL_CONN_STATE_MAX 2
+#define CONTROL_CONN_STATE_OPEN_V0 1
+#define CONTROL_CONN_STATE_OPEN_V1 2
+#define CONTROL_CONN_STATE_NEEDAUTH_V0 3
+#define CONTROL_CONN_STATE_NEEDAUTH_V1 4
+#define _CONTROL_CONN_STATE_MAX 4
#define _DIR_PURPOSE_MIN 1
/** Purpose for connection to directory server: download a directory. */
@@ -655,10 +657,12 @@
/* Used only by control connections */
uint32_t event_mask;
- uint16_t incoming_cmd_type;
uint32_t incoming_cmd_len;
uint32_t incoming_cmd_cur_len;
char *incoming_cmd;
+
+ /* Used only by control v0 connections */
+ uint16_t incoming_cmd_type;
};
typedef struct connection_t connection_t;
@@ -1181,8 +1185,9 @@
char **headers_out, size_t max_headerlen,
char **body_out, size_t *body_used, size_t max_bodylen);
int fetch_from_buf_socks(buf_t *buf, socks_request_t *req);
-int fetch_from_buf_control(buf_t *buf, uint32_t *len_out, uint16_t *type_out,
- char **body_out);
+int fetch_from_buf_control0(buf_t *buf, uint32_t *len_out, uint16_t *type_out,
+ char **body_out, int check_for_v1);
+int fetch_from_buf_line(buf_t *buf, char *data_out, size_t *data_len);
void assert_buf_ok(buf_t *buf);