summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNick Mathewson <nickm@torproject.org>2005-06-19 20:40:41 +0000
committerNick Mathewson <nickm@torproject.org>2005-06-19 20:40:41 +0000
commit64fc1f7bae174d62c40686ec00674d2671c88258 (patch)
tree6d1a156e462c22f2fd5da207e95c06509c02f347
parentb5fd75a063e487e845c98530cd2032f303d34462 (diff)
downloadtor-64fc1f7bae174d62c40686ec00674d2671c88258.tar.gz
tor-64fc1f7bae174d62c40686ec00674d2671c88258.zip
Implement all the rest of the new controller protocol, debug a little, add some new features, add ADDRMAP events.
svn:r4460
-rw-r--r--doc/TODO18
-rw-r--r--doc/control-spec.txt26
-rw-r--r--src/or/circuitlist.c7
-rw-r--r--src/or/connection_edge.c2
-rw-r--r--src/or/control.c355
-rw-r--r--src/or/or.h2
6 files changed, 295 insertions, 115 deletions
diff --git a/doc/TODO b/doc/TODO
index 25751624e2..cdd6400f79 100644
--- a/doc/TODO
+++ b/doc/TODO
@@ -54,15 +54,19 @@ For 0.1.0.x:
for 0.1.1.x:
N . Controller improvements
- . new controller protocol
- . Specify
- . Implement
- - controller should have an event to learn about new addressmappings,
+ o new controller protocol
+ o Specify
+ o Implement
+ . Test, debug
+ o add new getinfo options to enumerate things we only find out about
+ currently via events.
+ o controller should have an event to learn about new addressmappings,
e.g. when we learn a hostname to IP mapping ?
- - make sure err-level log events get flushed to the controller
+ . make sure err-level log events get flushed to the controller
immediately, since tor will exit right after.
- - add new getinfo options to enumerate things we only find out about
- currently via events.
+ o Implement
+ - Test, debug
+ - Switch example controllers to use new protocol
- switch accountingmax to count total in+out, not either in or
out. it's easy to move in this direction (not risky), but hard to
back, out if we decide we prefer it the way it already is. hm.
diff --git a/doc/control-spec.txt b/doc/control-spec.txt
index 348662b2c3..c63e96c8d7 100644
--- a/doc/control-spec.txt
+++ b/doc/control-spec.txt
@@ -159,7 +159,7 @@ $Id$
"SETEVENTS" *(SP EventCode) CRLF
EventCode = "CIRC" / "STREAM" / "ORCONN" / "BW" / "DEBUG" /
- "INFO" / "NOTICE" / "WARN" / "ERR" / "NEWDESC"
+ "INFO" / "NOTICE" / "WARN" / "ERR" / "NEWDESC" / "ADDRMAP"
[XXX We should have an "ADDRESSMAP" event to hear when we learn
about dns resolves, etc, so the controller can keep synced. -RD]
@@ -318,7 +318,7 @@ about dns resolves, etc, so the controller can keep synced. -RD]
"stream-status"
A series of lines as for a stream status event. Each is of the form:
- StreamID SP StreamStatus SP Target CRLF
+ StreamID SP StreamStatus SP CircID SP Target CRLF
"orconn-status"
A series of lines as for an OR connection status event. Each is of the
@@ -344,9 +344,9 @@ about dns resolves, etc, so the controller can keep synced. -RD]
request for the server to extend an existing circuit with that ID according
to the specified path.
- If the request is successful, the server sends a "250 OK" message
- containing a message body consisting of the Circuit ID of the (maybe newly
- created) circuit.
+ If the request is successful, the server sends a reply containing a message
+ body consisting of the Circuit ID of the (maybe newly created) circuit.
+ The syntax is "250" SP "EXTENDED" SP CircuitID CRLF.
3.10 ATTACHSTREAM
@@ -491,6 +491,8 @@ about dns resolves, etc, so the controller can keep synced. -RD]
554 Invalid descriptor
+ 555 Unmanaged entity
+
650 Asynchronous event notification
Unless specified to have specific contents, the human-readable messages
@@ -537,20 +539,22 @@ about dns resolves, etc, so the controller can keep synced. -RD]
The syntax is:
- "650" SP "STREAM" SP StreamID SP StreamStatus SP Target
+ "650" SP "STREAM" SP StreamID SP StreamStatus SP CircID SP Target SP
StreamStatus =
"NEW" / ; New request to connect
"NEWRESOLVE" / ; New request to resolve an address
"SENTCONNECT" / ; Sent a connect cell along a circuit
"SENTRESOLVE" / ; Sent a resolve cell along a circuit
- "SUCCEEDED" / ; Received a successful reply; stream established
+ "SUCCEEDED" / ; Received a reply; stream established
"FAILED" / ; Stream failed and not retriable.
"CLOSED" / ; Stream closed
- "DETACHED" ; Stream detached from circuit; still retriable
+ "DETACHED" ; Detached from circuit; still retriable.
Target = Address ":" Port
+ The circuit ID designates which circuit this stream is attached to. If
+ the stream is unattached, the circuit ID "0" is given.
4.1.3 OR Connection status changed
@@ -580,6 +584,12 @@ about dns resolves, etc, so the controller can keep synced. -RD]
Syntax:
"650" SP "NEWDESC" 1*(SP ServerID)
+4.1.6 New Address mapping
+
+ Syntax:
+ "650" SP "ADDRMAP" SP Address SP Address SP Expiry
+ Expiry = DQOUTE ISOTime DQUOTE / "NEVER"
+
5. Implementation notes
5.1. Authentication
diff --git a/src/or/circuitlist.c b/src/or/circuitlist.c
index db67a21688..789781c936 100644
--- a/src/or/circuitlist.c
+++ b/src/or/circuitlist.c
@@ -154,6 +154,13 @@ circuit_close_all_marked(void)
}
}
+/** DOCDOC **/
+circuit_t *
+_circuit_get_global_list(void)
+{
+ return global_circuitlist;
+}
+
/** Function to make circ-\>state human-readable */
const char *
circuit_state_to_string(int state) {
diff --git a/src/or/connection_edge.c b/src/or/connection_edge.c
index 4021749b6f..e0f16e408e 100644
--- a/src/or/connection_edge.c
+++ b/src/or/connection_edge.c
@@ -513,6 +513,7 @@ addressmap_virtaddress_remove(const char *addr, addressmap_entry_t *ent)
}
}
+/* DOCDOC */
static void
addressmap_ent_remove(const char *addr, addressmap_entry_t *ent)
{
@@ -637,6 +638,7 @@ addressmap_register(const char *address, char *new_address, time_t expires)
log_fn(LOG_INFO, "Addressmap: (re)mapped '%s' to '%s'",
safe_str(address), safe_str(ent->new_address));
+ control_event_address_mapped(address, ent->new_address, expires);
}
/** An attempt to resolve <b>address</b> failed at some OR.
diff --git a/src/or/control.c b/src/or/control.c
index 7fc5136e62..e584c68e79 100644
--- a/src/or/control.c
+++ b/src/or/control.c
@@ -71,7 +71,8 @@ const char control_c_id[] = "$Id$";
#define EVENT_NOTICE_MSG 0x0009
#define EVENT_WARN_MSG 0x000A
#define EVENT_ERR_MSG 0x000B
-#define _EVENT_MAX 0x000B
+#define EVENT_ADDRMAP 0x000C
+#define _EVENT_MAX 0x000C
/** Array mapping from message type codes to human-readable message
* type names. */
@@ -161,6 +162,7 @@ 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);
+static int write_stream_target_to_buf(connection_t *conn, char *buf, size_t len);
/** Given a possibly invalid message type code <b>cmd</b>, return a
* human-readable string equivalent. */
@@ -250,6 +252,7 @@ adjust_event_log_severity(void)
control_event_logmsg);
}
+/* DOCDOC */
static INLINE void
connection_write_str_to_buf(const char *s, connection_t *conn)
{
@@ -257,6 +260,7 @@ connection_write_str_to_buf(const char *s, connection_t *conn)
connection_write_to_buf(s, len, conn);
}
+/* DOCDOC ; test */
static size_t
write_escaped_data(const char *data, size_t len, int translate_newlines,
char **out)
@@ -288,50 +292,17 @@ write_escaped_data(const char *data, size_t len, int translate_newlines,
}
*outp++ = *data++;
}
- *outp++ = '\r';
- *outp++ = '\n';
+ if (outp < *out+2 || memcmp(outp-2, "\r\n", 2)) {
+ *outp++ = '\r';
+ *outp++ = '\n';
+ }
*outp++ = '.';
*outp++ = '\r';
*outp++ = '\n';
return outp - *out;
}
-#if 0
-static void
-connection_write_escaped_data_to_buf(const char *data, size_t len,
- int translate_newlines,
- connection_t *conn)
-{
- const char *next;
-
- while (len) {
- if (*data == '.')
- connection_write_to_buf(".", 1, conn);
-
- if (translate_newlines)
- next = tor_memmem(data, len, "\r\n", 2);
- else
- next = tor_memmem(data, len, "\r\n.", 3);
-
- if (next) {
- if (translate_newlines) {
- connection_write_to_buf(data, next-data, conn);
- connection_write_to_buf("\n", 1, conn);
- len -= (next-data+2);
- } else {
- connection_write_to_buf(data, next-data+2, conn);
- len -= (next-data+2);
- }
- data = next + 2;
- } else {
- connection_write_to_buf(data, len, conn);
- break;
- }
- }
- connection_write_to_buf(".\r\n", 3, conn);
-}
-#endif
-
+/* DOCDOC ; test */
static size_t
read_escaped_data(const char *data, size_t len, int translate_newlines,
char **out)
@@ -368,14 +339,54 @@ read_escaped_data(const char *data, size_t len, int translate_newlines,
return outp - *out;
}
+/** DOCDOC; test **/
static const char *
-get_escaped_string(const char *start, char **out, size_t *out_len)
+get_escaped_string(const char *start, size_t in_len_max,
+ char **out, size_t *out_len)
{
- /* XXXX V1 */
- return NULL;
-}
+ const char *cp, *end;
+ char *outp;
+ size_t len=0;
+
+ if (*start != '\"')
+ return NULL;
+
+ cp = start+1;
+ end = start+in_len_max;
+ /* Calculate length. */
+ while (1) {
+ if (cp >= end)
+ return NULL;
+ else if (*cp == '\\') {
+ if (++cp == end)
+ return NULL; /* Can't escape EOS. */
+ ++cp;
+ ++len;
+ } else if (*cp == '\"') {
+ break;
+ } else {
+ ++cp;
+ ++len;
+ }
+ }
+ end = cp;
+ outp = *out = tor_malloc(len+1);
+ *out_len = len;
+ cp = start+1;
+ while (cp < end) {
+ if (*cp == '\\')
+ ++cp;
+ *outp++ = *cp++;
+ }
+ *outp = '\0';
+ tor_assert((outp - *out) == *out_len);
+
+ return end+1;
+}
+
+/* DOCDOC */
static void
connection_printf_to_buf(connection_t *conn, const char *format, ...)
{
@@ -395,29 +406,6 @@ connection_printf_to_buf(connection_t *conn, const char *format, ...)
connection_write_to_buf(buf, len, conn);
}
-#if 0
-static void
-connection_write_reply_lines_to_buf(connection_t *conn,
- const char *code, smartlist_t *lines)
-{
- int i, len;
-
- tor_assert(strlen(code) == 3);
- len = smartlist_len(lines);
- if (!len)
- return;
-
- for (i=0; i < len-1; ++i) {
- connection_write_to_buf(code, 3, conn);
- connection_write_to_buf("-", 1, conn);
- connection_write_str_to_buf(smartlist_get(lines, i), conn);
- }
- connection_write_to_buf(code, 3, conn);
- connection_write_to_buf(" ", 1, conn);
- connection_write_str_to_buf(smartlist_get(lines, len-1), conn);
-}
-#endif
-
/** 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
@@ -514,15 +502,15 @@ send_control0_event(uint16_t event, uint32_t len, const char *body)
conns[i]->state == CONTROL_CONN_STATE_OPEN_V0 &&
conns[i]->event_mask & (1<<event)) {
send_control0_message(conns[i], CONTROL0_CMD_EVENT, buflen, buf);
- if (event == EVENT_ERR_MSG) {
+ if (event == EVENT_ERR_MSG)
_connection_controller_force_write(conns[i]);
- }
}
}
tor_free(buf);
}
+/* DOCDOC */
static void
send_control1_event(uint16_t event, const char *format, ...)
{
@@ -551,9 +539,8 @@ send_control1_event(uint16_t event, const char *format, ...)
conns[i]->state == CONTROL_CONN_STATE_OPEN_V1 &&
conns[i]->event_mask & (1<<event)) {
connection_write_to_buf(buf, len, conns[i]);
- if (event == EVENT_ERR_MSG) {
+ if (event == EVENT_ERR_MSG)
_connection_controller_force_write(conns[i]);
- }
}
}
}
@@ -591,6 +578,7 @@ handle_control_setconf(connection_t *conn, uint32_t len, char *body)
{
int r;
struct config_line_t *lines=NULL;
+ char *start = body;
int v0 = STATE_IS_V0(conn->state);
if (!v0) {
@@ -602,6 +590,7 @@ handle_control_setconf(connection_t *conn, uint32_t len, char *body)
++eq;
memcpy(outp, body, eq-body);
outp += (eq-body);
+ *outp++ = ' ';
body = eq+1;
if (*eq == '=') {
if (*body != '\"') {
@@ -610,7 +599,8 @@ handle_control_setconf(connection_t *conn, uint32_t len, char *body)
} else {
char *val;
size_t val_len;
- body = (char*)get_escaped_string(body, &val, &val_len);
+ body = (char*)get_escaped_string(body, (len - (body-start)),
+ &val, &val_len);
if (!body) {
connection_write_str_to_buf("551 Couldn't parse string\r\n", conn);
tor_free(config);
@@ -618,6 +608,7 @@ handle_control_setconf(connection_t *conn, uint32_t len, char *body)
}
memcpy(outp, val, val_len);
outp += val_len;
+ tor_free(val);
}
}
while (TOR_ISSPACE(*body))
@@ -702,6 +693,7 @@ handle_control_getconf(connection_t *conn, uint32_t body_len, const char *body)
}
} else {
struct config_line_t *answer = config_get_assigned_option(options,q);
+ /* XXXX handle non-set options in V1 at least*/
while (answer) {
struct config_line_t *next;
@@ -808,6 +800,8 @@ handle_control_setevents(connection_t *conn, uint32_t len, const char *body)
event_code = EVENT_ERR_MSG;
else if (!strcasecmp(ev, "NEWDESC"))
event_code = EVENT_NEW_DESC;
+ else if (!strcasecmp(ev, "ADDRMAP"))
+ event_code = EVENT_ADDRMAP;
else {
connection_printf_to_buf(conn, "552 Unrecognized event \"%s\"\r\n",
ev);
@@ -881,7 +875,7 @@ handle_control_authenticate(connection_t *conn, uint32_t len, const char *body)
password = tor_strdup("");
password_len = 0;
} else {
- if (!get_escaped_string(body, &password, &password_len)) {
+ if (!get_escaped_string(body, len, &password, &password_len)) {
connection_write_str_to_buf("551 Invalid quoted string\r\n", conn);
return 0;
}
@@ -1003,21 +997,29 @@ handle_control_signal(connection_t *conn, uint32_t len,
static int
handle_control_mapaddress(connection_t *conn, uint32_t len, const char *body)
{
- /* XXXX V1 */
smartlist_t *elts;
smartlist_t *lines;
smartlist_t *reply;
char *r;
size_t sz;
+ int v0 = STATE_IS_V0(conn->state);
lines = smartlist_create();
elts = smartlist_create();
reply = smartlist_create();
- smartlist_split_string(lines, body, "\n",
- SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0);
+ if (v0)
+ smartlist_split_string(lines, body, "\n",
+ SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0);
+ else
+ smartlist_split_string(lines, body, " ",
+ SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0);
+ /* XXXX Make errors conformant. */
SMARTLIST_FOREACH(lines, char *, line,
{
tor_strlower(line);
- smartlist_split_string(elts, line, " ", 0, 2);
+ if (v0)
+ smartlist_split_string(elts, line, " ", 0, 2);
+ else
+ smartlist_split_string(elts, line, "=", 0, 2);
if (smartlist_len(elts) == 2) {
const char *from = smartlist_get(elts,0);
const char *to = smartlist_get(elts,1);
@@ -1027,21 +1029,31 @@ handle_control_mapaddress(connection_t *conn, uint32_t len, const char *body)
log_fn(LOG_WARN,"Skipping invalid argument '%s' in MapAddress msg",to);
} else if (!strcmp(from, ".") || !strcmp(from, "0.0.0.0")) {
const char *addr = addressmap_register_virtual_address(
- strcmp(from,".") ? RESOLVED_TYPE_HOSTNAME : RESOLVED_TYPE_IPV4,
+ !strcmp(from,".") ? RESOLVED_TYPE_HOSTNAME : RESOLVED_TYPE_IPV4,
tor_strdup(to));
if (!addr) {
log_fn(LOG_WARN,
"Unable to allocate address for '%s' in MapAddress msg",
safe_str(line));
} else {
- size_t anslen = strlen(addr)+strlen(to)+2;
+ size_t anslen = strlen(addr)+strlen(to)+8;
char *ans = tor_malloc(anslen);
- tor_snprintf(ans, anslen, "%s %s", addr, to);
+ if (v0)
+ tor_snprintf(ans, anslen, "%s %s", addr, to);
+ else
+ tor_snprintf(ans, anslen, "250-%s=%s", addr, to);
smartlist_add(reply, ans);
}
} else {
addressmap_register(from, tor_strdup(to), 1);
- smartlist_add(reply, tor_strdup(line));
+ if (v0)
+ smartlist_add(reply, tor_strdup(line));
+ else {
+ size_t anslen = strlen(line)+8;
+ char *ans = tor_malloc(anslen);
+ tor_snprintf(ans, anslen, "250-%s", line);
+ smartlist_add(reply, ans);
+ }
}
} else {
log_fn(LOG_WARN, "Skipping MapAddress line with wrong number of items.");
@@ -1053,8 +1065,15 @@ handle_control_mapaddress(connection_t *conn, uint32_t len, const char *body)
smartlist_free(lines);
smartlist_free(elts);
- r = smartlist_join_strings(reply, "\n", 1, &sz);
- send_control_done2(conn,r,sz);
+ if (v0) {
+ r = smartlist_join_strings(reply, "\n", 1, &sz);
+ send_control_done2(conn,r,sz);
+ } else {
+ if (smartlist_len(reply))
+ ((char*)smartlist_get(reply,smartlist_len(reply)-1))[3] = ' ';
+ r = smartlist_join_strings(reply, "\r\n", 1, &sz);
+ connection_write_to_buf(r, sz, conn);
+ }
SMARTLIST_FOREACH(reply, char *, cp, tor_free(cp));
smartlist_free(reply);
@@ -1086,6 +1105,106 @@ handle_getinfo_helper(const char *question, char **answer)
list_server_status(routerlist->routers, answer) < 0) {
return -1;
}
+ } else if (!strcmp(question, "circuit-status")) {
+ circuit_t *circ;
+ smartlist_t *status = smartlist_create();
+ for (circ = _circuit_get_global_list(); circ; circ = circ->next) {
+ char *s, *path;
+ size_t slen;
+ const char *state;
+ if (! CIRCUIT_IS_ORIGIN(circ) || circ->marked_for_close)
+ continue;
+ path = circuit_list_path(circ,0);
+ if (circ->state == CIRCUIT_STATE_OPEN)
+ state = "BUILT";
+ else if (strlen(path))
+ state = "EXTENDED";
+ else
+ state = "LAUNCHED";
+
+ slen = strlen(path)+strlen(state)+20;
+ s = tor_malloc(slen+1);
+ tor_snprintf(s, slen, "%lu %s %s", (unsigned long)circ->global_identifier,
+ state, path);
+ smartlist_add(status, s);
+ tor_free(path);
+ }
+ *answer = smartlist_join_strings(status, "\r\n", 1, NULL);
+ SMARTLIST_FOREACH(status, char *, cp, tor_free(cp));
+ smartlist_free(status);
+ } else if (!strcmp(question, "stream-status")) {
+ connection_t **conns;
+ int n_conns, i;
+ char buf[256];
+ smartlist_t *status = smartlist_create();
+ get_connection_array(&conns, &n_conns);
+ for (i=0; i < n_conns; ++i) {
+ const char *state;
+ char *s;
+ size_t slen;
+ circuit_t *circ;
+ if (conns[i]->type != CONN_TYPE_AP ||
+ conns[i]->marked_for_close ||
+ conns[i]->state == AP_CONN_STATE_SOCKS_WAIT)
+ continue;
+ switch (conns[i]->state)
+ {
+ case AP_CONN_STATE_CONTROLLER_WAIT:
+ case AP_CONN_STATE_CIRCUIT_WAIT:
+ if (conns[i]->socks_request &&
+ conns[i]->socks_request->command == SOCKS_COMMAND_RESOLVE)
+ state = "NEWRESOLVE";
+ else
+ state = "NEW";
+ break;
+ case AP_CONN_STATE_RENDDESC_WAIT:
+ case AP_CONN_STATE_CONNECT_WAIT:
+ state = "SENTCONNECT"; break;
+ case AP_CONN_STATE_RESOLVE_WAIT:
+ state = "SENTRESOLVE"; break;
+ case AP_CONN_STATE_OPEN:
+ state = "SUCCEEDED"; break;
+ default:
+ log_fn(LOG_WARN, "Asked for stream in unknown state %d",
+ conns[i]->state);
+ continue;
+ }
+ circ = circuit_get_by_edge_conn(conns[i]);
+ write_stream_target_to_buf(conns[i], buf, sizeof(buf));
+ slen = strlen(buf)+strlen(state)+32;
+ s = tor_malloc(slen+1);
+ tor_snprintf(s, slen, "%lu %s %lu %s",
+ (unsigned long) conns[i]->global_identifier,state,
+ circ?(unsigned long)circ->global_identifier : 0ul,
+ buf);
+ smartlist_add(status, s);
+ }
+ *answer = smartlist_join_strings(status, "\r\n", 1, NULL);
+ SMARTLIST_FOREACH(status, char *, cp, tor_free(cp));
+ smartlist_free(status);
+ } else if (!strcmp(question, "orconn-status")) {
+ connection_t **conns;
+ int n_conns, i;
+ smartlist_t *status = smartlist_create();
+ get_connection_array(&conns, &n_conns);
+ for (i=0; i < n_conns; ++i) {
+ const char *state;
+ char *s;
+ size_t slen;
+ if (conns[i]->type != CONN_TYPE_OR || conns[i]->marked_for_close)
+ continue;
+ if (conns[i]->state == OR_CONN_STATE_OPEN)
+ state = "CONNECTED";
+ else
+ state = "LAUNCHED";
+ slen = strlen(conns[i]->nickname)+strlen(state)+2;
+ s = tor_malloc(slen+1);
+ tor_snprintf(s, slen, "%s %s",conns[i]->nickname,state);
+ smartlist_add(status, s);
+ }
+ *answer = smartlist_join_strings(status, "\r\n", 1, NULL);
+ SMARTLIST_FOREACH(status, char *, cp, tor_free(cp));
+ smartlist_free(status);
} else if (!strcmpstart(question, "addr-mappings/")) {
time_t min_e, max_e;
smartlist_t *mappings;
@@ -1152,13 +1271,13 @@ handle_control_getinfo(connection_t *conn, uint32_t len, const char *body)
if (smartlist_len(unrecognized)) {
int i;
tor_assert(!v0);
- for (i=0; i < len-1; ++i)
+ for (i=0; i < smartlist_len(unrecognized)-1; ++i)
connection_printf_to_buf(conn,
- "552-Unrecognized configuration key \"%s\"\r\n",
+ "552-Unrecognized key \"%s\"\r\n",
(char*)smartlist_get(unrecognized, i));
connection_printf_to_buf(conn,
- "552 Unrecognized configuration key \"%s\"\r\n",
- (char*)smartlist_get(unrecognized, len-1));
+ "552 Unrecognized key \"%s\"\r\n",
+ (char*)smartlist_get(unrecognized, i));
goto done;
}
@@ -1174,12 +1293,14 @@ handle_control_getinfo(connection_t *conn, uint32_t len, const char *body)
char *v = smartlist_get(answers, i+1);
/*XXXX Not an adequate test! XXXX011 */
if (!strchr(v, '\n') && !strchr(v, '\r')) {
- connection_printf_to_buf(conn, "250-%s=%s\r\n", k, v);
+ connection_printf_to_buf(conn, "250-%s=", k);
+ connection_write_str_to_buf(v, conn);
+ connection_write_str_to_buf("\r\n", conn);
} else {
char *esc = NULL;
size_t len;
len = write_escaped_data(v, strlen(v), 1, &esc);
- connection_printf_to_buf(conn, "250+%s=", k);
+ connection_printf_to_buf(conn, "250+%s=\r\n", k);
connection_write_to_buf(esc, len, conn);
tor_free(esc);
}
@@ -1371,7 +1492,6 @@ handle_control_attachstream(connection_t *conn, uint32_t len,
return 0;
}
-
if (ap_conn->state != AP_CONN_STATE_CONTROLLER_WAIT) {
if (STATE_IS_V0(conn->state)) {
send_control0_error(conn, ERR_NO_STREAM,
@@ -1679,6 +1799,7 @@ connection_control_reached_eof(connection_t *conn)
return 0;
}
+/* DOCDOC */
static int
connection_control_process_inbuf_v1(connection_t *conn)
{
@@ -1812,6 +1933,7 @@ connection_control_process_inbuf_v1(connection_t *conn)
goto again;
}
+/* DOCDOC */
static int
connection_control_process_inbuf_v0(connection_t *conn)
{
@@ -2015,6 +2137,22 @@ control_event_circuit_status(circuit_t *circ, circuit_status_event_t tp)
return 0;
}
+/** DOCDOC */
+static int
+write_stream_target_to_buf(connection_t *conn, char *buf, size_t len)
+{
+ char buf2[256];
+ if (conn->chosen_exit_name)
+ if (tor_snprintf(buf2, sizeof(buf2), ".%s.exit", conn->chosen_exit_name)<0)
+ return -1;
+ if (tor_snprintf(buf, len, "%s%s:%d",
+ conn->socks_request->address,
+ conn->chosen_exit_name ? buf2 : "",
+ conn->socks_request->port)<0)
+ return -1;
+ return 0;
+}
+
/** Something has happened to the stream associated with AP connection
* <b>conn</b>: tell any interested control connections. */
int
@@ -2022,19 +2160,14 @@ control_event_stream_status(connection_t *conn, stream_status_event_t tp)
{
char *msg;
size_t len;
- char buf[256], buf2[256];
+ char buf[256];
tor_assert(conn->type == CONN_TYPE_AP);
tor_assert(conn->socks_request);
if (!EVENT_IS_INTERESTING(EVENT_STREAM_STATUS))
return 0;
- if (conn->chosen_exit_name)
- tor_snprintf(buf2, sizeof(buf2), ".%s.exit", conn->chosen_exit_name);
- tor_snprintf(buf, sizeof(buf), "%s%s:%d",
- conn->socks_request->address,
- conn->chosen_exit_name ? buf2 : "",
- conn->socks_request->port);
+ write_stream_target_to_buf(conn, buf, sizeof(buf));
if (EVENT_IS_INTERESTING0(EVENT_STREAM_STATUS)) {
len = strlen(buf);
msg = tor_malloc(5+len+1);
@@ -2047,6 +2180,7 @@ control_event_stream_status(connection_t *conn, stream_status_event_t tp)
}
if (EVENT_IS_INTERESTING0(EVENT_STREAM_STATUS)) {
const char *status;
+ circuit_t *circ;
switch (tp)
{
case STREAM_EVENT_SENT_CONNECT: status = "SENTCONNECT"; break;
@@ -2061,10 +2195,12 @@ control_event_stream_status(connection_t *conn, stream_status_event_t tp)
log_fn(LOG_WARN, "Unrecognized status code %d", (int)tp);
return 0;
}
+ circ = circuit_get_by_edge_conn(conn);
send_control1_event(EVENT_STREAM_STATUS,
- "650 STREAM %lu %s %s\r\n",
- (unsigned long)conn->global_identifier,
- status, buf);
+ "650 STREAM %lu %s %lu %s\r\n",
+ (unsigned long)conn->global_identifier, status,
+ circ?(unsigned long)circ->global_identifier : 0ul,
+ buf);
}
return 0;
}
@@ -2167,7 +2303,7 @@ control_event_logmsg(int severity, const char *msg)
if (*cp == '\r' || *cp == '\n')
*cp = ' ';
}
- switch(severity) {
+ switch (severity) {
case LOG_INFO: s = "INFO"; break;
case LOG_NOTICE: s = "NOTICE"; break;
case LOG_WARN: s = "WARN"; break;
@@ -2215,6 +2351,25 @@ control_event_descriptors_changed(smartlist_t *routers)
return 0;
}
+/** DOCDOC */
+int
+control_event_address_mapped(const char *from, const char *to, time_t expires)
+{
+ if (!EVENT_IS_INTERESTING1(EVENT_ADDRMAP))
+ return 0;
+
+ if (expires < 3)
+ send_control1_event(EVENT_ADDRMAP, "650 ADDRMAP %s %s NEVER\r\n", from, to);
+ else {
+ char buf[ISO_TIME_LEN+1];
+ format_local_iso_time(buf,expires);
+ send_control1_event(EVENT_ADDRMAP, "650 ADDRMAP %s %s \"%s\"\r\n",
+ from, to, buf);
+ }
+
+ return 0;
+}
+
/** Choose a random authentication cookie and write it to disk.
* Anybody who can read the cookie from disk will be considered
* authorized to use the control connection. */
diff --git a/src/or/or.h b/src/or/or.h
index 29ba3bbe83..f66ad82646 100644
--- a/src/or/or.h
+++ b/src/or/or.h
@@ -1219,6 +1219,7 @@ void onion_append_to_cpath(crypt_path_t **head_ptr, crypt_path_t *new_hop);
/********************************* circuitlist.c ***********************/
+circuit_t * _circuit_get_global_list(void);
const char *circuit_state_to_string(int state);
enum which_conn_changed_t { P_CONN_CHANGED=1, N_CONN_CHANGED=0 };
void circuit_set_circid_orconn(circuit_t *circ, uint16_t id,
@@ -1478,6 +1479,7 @@ int control_event_or_conn_status(connection_t *conn, or_conn_status_event_t e);
int control_event_bandwidth_used(uint32_t n_read, uint32_t n_written);
void control_event_logmsg(int severity, const char *msg);
int control_event_descriptors_changed(smartlist_t *routers);
+int control_event_address_mapped(const char *from, const char *to,time_t expires);
int init_cookie_authentication(int enabled);
int decode_hashed_password(char *buf, const char *hashed);