aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/or/circuitbuild.c38
-rw-r--r--src/or/circuitlist.c9
-rw-r--r--src/or/circuituse.c2
-rw-r--r--src/or/connection.c7
-rw-r--r--src/or/connection_edge.c5
-rw-r--r--src/or/connection_or.c9
-rw-r--r--src/or/control.c103
-rw-r--r--src/or/dirserv.c6
-rw-r--r--src/or/main.c1
-rw-r--r--src/or/or.h40
-rw-r--r--src/or/router.c5
-rw-r--r--src/or/routerlist.c2
-rw-r--r--src/or/test.c10
13 files changed, 199 insertions, 38 deletions
diff --git a/src/or/circuitbuild.c b/src/or/circuitbuild.c
index f163abe2b..170cde8c2 100644
--- a/src/or/circuitbuild.c
+++ b/src/or/circuitbuild.c
@@ -63,6 +63,40 @@ static uint16_t get_unique_circ_id_by_conn(connection_t *conn, int circ_id_type)
return test_circ_id;
}
+/** Allocate and return a comma-separated list of the currently built
+ * elements of circuit_t.
+ */
+char *circuit_list_path(circuit_t *circ)
+{
+ struct crypt_path_t *hop;
+ routerinfo_t *r;
+ smartlist_t *elements;
+ char *s;
+ tor_assert(CIRCUIT_IS_ORIGIN(circ));
+ tor_assert(circ->cpath);
+
+ elements = smartlist_create();
+
+ for (hop = circ->cpath; hop; hop = hop->next) {
+ if (hop->state != CPATH_STATE_OPEN)
+ break;
+ if ((r = router_get_by_digest(hop->identity_digest))) {
+ smartlist_add(elements, tor_strdup(r->nickname));
+ } else if (circ->purpose == CIRCUIT_PURPOSE_C_REND_JOINED) {
+ smartlist_add(elements, tor_strdup("<rendezvous splice>"));
+ } else {
+ s = tor_malloc(HEX_DIGEST_LEN+2);
+ s[0]='$';
+ base16_encode(s+1,HEX_DIGEST_LEN+1,hop->identity_digest,DIGEST_LEN);
+ smartlist_add(elements, s);
+ }
+ }
+
+ s = smartlist_join_strings(elements, ",", 0, NULL);
+ SMARTLIST_FOREACH(elements, char*, cp, tor_free(cp));
+ return s;
+}
+
/** Log, at severity <b>severity</b>, the nicknames of each router in
* circ's cpath. Also log the length of the cpath, and the intended
* exit point.
@@ -220,6 +254,8 @@ circuit_t *circuit_establish_circuit(uint8_t purpose,
return NULL;
}
+ control_event_circuit_status(circ, CIRC_EVENT_LAUNCHED);
+
/* now see if we're already connected to the first OR in 'route' */
tor_assert(firsthop);
@@ -604,6 +640,8 @@ int circuit_finish_handshake(circuit_t *circ, char *reply) {
hop->state = CPATH_STATE_OPEN;
log_fn(LOG_INFO,"finished");
circuit_log_path(LOG_INFO,circ);
+ control_event_circuit_status(circ, CIRC_EVENT_EXTENDED);
+
return 0;
}
diff --git a/src/or/circuitlist.c b/src/or/circuitlist.c
index dc90b9bc9..ad31d6f8e 100644
--- a/src/or/circuitlist.c
+++ b/src/or/circuitlist.c
@@ -74,6 +74,7 @@ void circuit_close_all_marked(void)
*/
circuit_t *circuit_new(uint16_t p_circ_id, connection_t *p_conn) {
circuit_t *circ;
+ static uint32_t n_circuits_allocated = 0;
circ = tor_malloc_zero(sizeof(circuit_t));
circ->magic = CIRCUIT_MAGIC;
@@ -93,6 +94,7 @@ circuit_t *circuit_new(uint16_t p_circ_id, connection_t *p_conn) {
circ->deliver_window = CIRCWINDOW_START;
circ->next_stream_id = crypto_pseudo_rand_int(1<<16);
+ circ->global_identifier = n_circuits_allocated++;
circuit_add(circ);
@@ -353,10 +355,15 @@ int _circuit_mark_for_close(circuit_t *circ) {
* links worked and which didn't.
*/
if (circ->state != CIRCUIT_STATE_OPEN) {
- if(CIRCUIT_IS_ORIGIN(circ))
+ if(CIRCUIT_IS_ORIGIN(circ)) {
circuit_build_failed(circ); /* take actions if necessary */
+ }
circuit_rep_hist_note_result(circ);
}
+ if (CIRCUIT_IS_ORIGIN(circ)) {
+ control_event_circuit_status(circ,
+ (circ->state == CIRCUIT_STATE_OPEN)?CIRC_EVENT_CLOSED:CIRC_EVENT_FAILED);
+ }
if (circ->purpose == CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT) {
tor_assert(circ->state == CIRCUIT_STATE_OPEN);
/* treat this like getting a nack from it */
diff --git a/src/or/circuituse.c b/src/or/circuituse.c
index 6ec7a640b..ba4f65047 100644
--- a/src/or/circuituse.c
+++ b/src/or/circuituse.c
@@ -489,6 +489,8 @@ circuit_expire_old_circuits(void)
*/
void circuit_has_opened(circuit_t *circ) {
+ control_event_circuit_status(circ, CIRC_EVENT_BUILT);
+
switch(circ->purpose) {
case CIRCUIT_PURPOSE_C_ESTABLISH_REND:
rend_client_rendcirc_has_opened(circ);
diff --git a/src/or/connection.c b/src/or/connection.c
index 79c5b997f..7d3b4c43b 100644
--- a/src/or/connection.c
+++ b/src/or/connection.c
@@ -198,12 +198,15 @@ void connection_about_to_close_connection(connection_t *conn)
case CONN_TYPE_OR:
/* Remember why we're closing this connection. */
if (conn->state != OR_CONN_STATE_OPEN) {
- if(connection_or_nonopen_was_started_here(conn))
+ if(connection_or_nonopen_was_started_here(conn)) {
rep_hist_note_connect_failed(conn->identity_digest, time(NULL));
+ control_event_or_conn_status(conn, OR_CONN_EVENT_FAILED);
+ }
} else if (0) { // XXX reason == CLOSE_REASON_UNUSED_OR_CONN) {
rep_hist_note_disconnect(conn->identity_digest, time(NULL));
} else if(conn->identity_digest) {
rep_hist_note_connection_died(conn->identity_digest, time(NULL));
+ control_event_or_conn_status(conn, OR_CONN_EVENT_CLOSED);
}
break;
case CONN_TYPE_AP:
@@ -212,6 +215,8 @@ void connection_about_to_close_connection(connection_t *conn)
connection_ap_handshake_socks_reply(conn, NULL, 0, 0);
conn->socks_request->has_finished = 1;
conn->hold_open_until_flushed = 1;
+ } else {
+ control_event_stream_status(conn, STREAM_EVENT_CLOSED);
}
break;
case CONN_TYPE_EXIT:
diff --git a/src/or/connection_edge.c b/src/or/connection_edge.c
index e7eec0533..51506b362 100644
--- a/src/or/connection_edge.c
+++ b/src/or/connection_edge.c
@@ -521,6 +521,7 @@ int connection_ap_handshake_send_begin(connection_t *ap_conn, circuit_t *circ)
ap_conn->deliver_window = STREAMWINDOW_START;
ap_conn->state = AP_CONN_STATE_CONNECT_WAIT;
log_fn(LOG_INFO,"Address/port sent, ap socket %d, n_circ_id %d",ap_conn->s,circ->n_circ_id);
+ control_event_stream_status(ap_conn, STREAM_EVENT_SENT_CONNECT);
return 0;
}
@@ -561,6 +562,7 @@ int connection_ap_handshake_send_resolve(connection_t *ap_conn, circuit_t *circ)
ap_conn->state = AP_CONN_STATE_RESOLVE_WAIT;
log_fn(LOG_INFO,"Address sent for resolve, ap socket %d, n_circ_id %d",ap_conn->s,circ->n_circ_id);
+ control_event_stream_status(ap_conn, STREAM_EVENT_SENT_RESOLVE);
return 0;
}
@@ -689,6 +691,9 @@ void connection_ap_handshake_socks_reply(connection_t *conn, char *reply,
size_t replylen, int success) {
char buf[256];
+ control_event_stream_status(conn,
+ success ? STREAM_EVENT_SUCCEEDED : STREAM_EVENT_FAILED);
+
if(replylen) { /* we already have a reply in mind */
connection_write_to_buf(reply, replylen, conn);
return;
diff --git a/src/or/connection_or.c b/src/or/connection_or.c
index 02cb4fa23..2852ad599 100644
--- a/src/or/connection_or.c
+++ b/src/or/connection_or.c
@@ -140,8 +140,9 @@ connection_or_init_conn_from_address(connection_t *conn,
if (n) {
conn->nickname = tor_strdup(n);
} else {
- conn->nickname = tor_malloc(HEX_DIGEST_LEN+1);
- base16_encode(conn->nickname, HEX_DIGEST_LEN+1,
+ conn->nickname = tor_malloc(HEX_DIGEST_LEN+2);
+ conn->nickname[0] = '$';
+ base16_encode(conn->nickname+1, HEX_DIGEST_LEN+1,
conn->identity_digest, DIGEST_LEN);
}
tor_free(conn->address);
@@ -223,10 +224,12 @@ connection_t *connection_or_connect(uint32_t addr, uint16_t port,
/* set up conn so it's got all the data we need to remember */
connection_or_init_conn_from_address(conn, addr, port, id_digest);
conn->state = OR_CONN_STATE_CONNECTING;
+ control_event_or_conn_status(conn, OR_CONN_EVENT_LAUNCHED);
switch(connection_connect(conn, conn->address, addr, port)) {
case -1:
router_mark_as_down(conn->identity_digest);
+ control_event_or_conn_status(conn, OR_CONN_EVENT_FAILED);
connection_free(conn);
return NULL;
case 0:
@@ -376,6 +379,7 @@ connection_tls_finish_handshake(connection_t *conn) {
log_fn(options.DirPort ? LOG_WARN : LOG_INFO,
"Other side (%s:%d) is '%s', but we tried to connect to '%s'",
conn->address, conn->port, nickname, conn->nickname);
+ control_event_or_conn_status(conn, OR_CONN_EVENT_FAILED);
return -1;
}
} else {
@@ -393,6 +397,7 @@ connection_tls_finish_handshake(connection_t *conn) {
circuit_n_conn_done(conn, 1); /* send the pending creates, if any. */
/* Note the success */
rep_hist_note_connect_succeeded(conn->identity_digest, time(NULL));
+ control_event_or_conn_status(conn, OR_CONN_EVENT_CONNECTED);
return 0;
}
diff --git a/src/or/control.c b/src/or/control.c
index 877342560..5ffcd2807 100644
--- a/src/or/control.c
+++ b/src/or/control.c
@@ -43,6 +43,8 @@ static const char *CONTROL_COMMANDS[] = {
"authenticate",
};
+extern or_options_t options;
+
static uint32_t global_event_mask = 0;
static void update_global_event_mask(void);
@@ -131,17 +133,57 @@ send_control_event(uint16_t event, uint16_t len, const char *body)
}
}
-static int
+static int
handle_control_setconf(connection_t *conn, uint16_t len,
const char *body)
{
/* XXXX009 NM */
return 0;
}
-static int handle_control_getconf(connection_t *conn, uint16_t len,
+
+static int handle_control_getconf(connection_t *conn, uint16_t body_len,
const char *body)
{
- /* XXXX009 NM */
+ smartlist_t *answer_elements = NULL;
+ char *msg = NULL;
+ size_t msg_len;
+
+ if (body[body_len-1] != '\0') {
+ send_control_error(conn, ERR_UNSPECIFIED,
+ "getconf message body not nul-terminated.");
+ return 0;
+ }
+ /* Now we can be sure that body will end in a nul-terminated string. */
+
+ answer_elements = smartlist_create();
+ while (body_len) {
+ size_t question_len = strlen(body);
+ struct config_line_t *answer = config_get_assigned_option(&options,body);
+ if (!answer) {
+ send_control_error(conn, ERR_UNRECOGNIZED_CONFIG_KEY, body);
+ goto done;
+ } else {
+ while (answer) {
+ struct config_line_t *next;
+ smartlist_add(answer_elements, answer->key);
+ smartlist_add(answer_elements, answer->value);
+ next = answer->next;
+ tor_free(answer);
+ answer = next;
+ }
+ }
+ body += question_len+1;
+ body_len -= question_len+1;
+ }
+
+ msg = smartlist_join_strings2(answer_elements, "\0", 1, 0, &msg_len);
+ send_control_message(conn, CONTROL_CMD_CONFVALUE, msg_len, msg);
+
+ done:
+ SMARTLIST_FOREACH(answer_elements, char *, cp, tor_free(cp));
+ smartlist_free(answer_elements);
+ tor_free(msg);
+
return 0;
}
static int handle_control_setevents(connection_t *conn, uint16_t len,
@@ -263,37 +305,63 @@ int connection_control_process_inbuf(connection_t *conn) {
goto again; /* There might be more data. */
}
-int control_event_circuit_status(circuit_t *circ)
+int control_event_circuit_status(circuit_t *circ, circuit_status_event_t tp)
{
+ char *path, *msg;
+ size_t path_len;
if (!EVENT_IS_INTERESTING(EVENT_CIRCUIT_STATUS))
return 0;
-
- /* XXXXX009 NM */
-
+ tor_assert(circ);
+ tor_assert(CIRCUIT_IS_ORIGIN(circ));
+
+ path = circuit_list_path(circ);
+ path_len = strlen(path);
+ msg = tor_malloc(1+4+path_len+1); /* event, circid, path, NUL. */
+ msg[0] = (uint8_t) tp;
+ set_uint32(msg+1, htonl(circ->global_identifier));
+ strlcpy(msg+5,path,path_len+1);
+
+ send_control_event(EVENT_STREAM_STATUS, (uint16_t)(path_len+6), msg);
+ tor_free(path);
+ tor_free(msg);
return 0;
}
-int control_event_stream_status(connection_t *conn)
+int control_event_stream_status(connection_t *conn, stream_status_event_t tp)
{
+ char *msg;
+ size_t len;
tor_assert(conn->type == CONN_TYPE_AP);
+ tor_assert(conn->socks_request);
if (!EVENT_IS_INTERESTING(EVENT_STREAM_STATUS))
return 0;
- /* XXXXX009 NM */
+ len = strlen(conn->socks_request->address);
+ msg = tor_malloc(5+len+1);
+ msg[0] = (uint8_t) tp;
+ set_uint32(msg+1, htonl(conn->s)); /* ???? Is this a security problem? */
+ strlcpy(msg+5, conn->socks_request->address, len+1);
+ send_control_event(EVENT_STREAM_STATUS, (uint16_t)(5+len+1), msg);
+ tor_free(msg);
return 0;
}
-int control_event_or_conn_status(connection_t *conn)
+int control_event_or_conn_status(connection_t *conn,or_conn_status_event_t tp)
{
+ char buf[HEX_DIGEST_LEN+3]; /* status, dollar, identity, NUL */
+ size_t len;
+
tor_assert(conn->type == CONN_TYPE_OR);
if (!EVENT_IS_INTERESTING(EVENT_OR_CONN_STATUS))
return 0;
- /* XXXXX009 NM */
-
+ 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);
return 0;
}
@@ -311,19 +379,18 @@ int control_event_bandwidth_used(uint32_t n_read, uint32_t n_written)
return 0;
}
-int control_event_warning(const char *msg)
+void control_event_logmsg(int severity, const char *msg)
{
size_t len;
+ if (severity > LOG_WARN) /* Less important than warning? ignore for now. */
+ return;
if (!EVENT_IS_INTERESTING(EVENT_WARNING))
- return 0;
+ return;
len = strlen(msg);
- send_control_event(EVENT_WARNING, len+1, msg);
-
- return 0;
+ send_control_event(EVENT_WARNING, (uint16_t)(len+1), msg);
}
-
/*
Local Variabls:
mode:c
diff --git a/src/or/dirserv.c b/src/or/dirserv.c
index 2483efc74..56c1446f1 100644
--- a/src/or/dirserv.c
+++ b/src/or/dirserv.c
@@ -523,9 +523,9 @@ list_server_status(char **running_routers_out, char **router_status_out)
});
if (running_routers_out)
- *running_routers_out = smartlist_join_strings(rr_entries, " ", 0);
+ *running_routers_out = smartlist_join_strings(rr_entries, " ", 0,NULL);
if (router_status_out)
- *router_status_out = smartlist_join_strings(rs_entries, " ", 0);
+ *router_status_out = smartlist_join_strings(rs_entries, " ", 0,NULL);
SMARTLIST_FOREACH(rr_entries, char *, cp, tor_free(cp));
SMARTLIST_FOREACH(rs_entries, char *, cp, tor_free(cp));
@@ -611,7 +611,7 @@ dirserv_dump_directory_to_string(char *s, size_t maxlen,
smartlist_split_string(versions, ln->value, ",",
SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0);
}
- recommended_versions = smartlist_join_strings(versions,",",0);
+ recommended_versions = smartlist_join_strings(versions,",",0,NULL);
SMARTLIST_FOREACH(versions,char *,s,tor_free(s));
smartlist_free(versions);
}
diff --git a/src/or/main.c b/src/or/main.c
index bd5bc883b..812f8c96a 100644
--- a/src/or/main.c
+++ b/src/or/main.c
@@ -971,6 +971,7 @@ static int init_from_config(int argc, char **argv) {
/* Close the temporary log we used while starting up, if it isn't already
* gone. */
close_temp_logs();
+ add_callback_log(LOG_WARN, LOG_ERR, control_event_logmsg);
/* Start backgrounding the process, if requested. */
if (options.RunAsDaemon) {
diff --git a/src/or/or.h b/src/or/or.h
index 76ec2e1d5..a25a909c8 100644
--- a/src/or/or.h
+++ b/src/or/or.h
@@ -822,6 +822,10 @@ struct circuit_t {
* is not marked for close. */
struct circuit_t *rend_splice;
+ /** Quasi-global identifier for this circuit; used for control.c */
+ /* XXXX009 NM This can get re-used after 2**32 circuits. */
+ uint32_t global_identifier;
+
struct circuit_t *next; /**< Next circuit in linked list. */
};
@@ -1000,6 +1004,7 @@ void assert_buf_ok(buf_t *buf);
/********************************* circuitbuild.c **********************/
+char *circuit_list_path(circuit_t *circ);
void circuit_log_path(int severity, circuit_t *circ);
void circuit_rep_hist_note_result(circuit_t *circ);
void circuit_dump_by_conn(connection_t *conn, int severity);
@@ -1084,6 +1089,8 @@ void config_parse_exit_policy(struct config_line_t *cfg,
struct exit_policy_t **dest);
void exit_policy_free(struct exit_policy_t *p);
const char *get_data_directory(or_options_t *options);
+struct config_line_t *config_get_assigned_option(or_options_t *options,
+ const char *key);
/********************************* connection.c ***************************/
@@ -1202,14 +1209,37 @@ void connection_or_update_nickname(connection_t *conn);
/********************************* control.c ***************************/
+typedef enum circuit_status_event_t {
+ CIRC_EVENT_LAUNCHED = 0,
+ CIRC_EVENT_BUILT = 1,
+ CIRC_EVENT_EXTENDED = 2,
+ CIRC_EVENT_FAILED = 3,
+ CIRC_EVENT_CLOSED = 4,
+} circuit_status_event_t;
+
+typedef enum stream_status_event_t {
+ STREAM_EVENT_SENT_CONNECT = 0,
+ STREAM_EVENT_SENT_RESOLVE = 1,
+ STREAM_EVENT_SUCCEEDED = 2,
+ STREAM_EVENT_FAILED = 3,
+ STREAM_EVENT_CLOSED = 4
+} stream_status_event_t;
+
+typedef enum or_conn_status_event_t {
+ OR_CONN_EVENT_LAUNCHED = 0,
+ OR_CONN_EVENT_CONNECTED = 1,
+ OR_CONN_EVENT_FAILED = 2,
+ OR_CONN_EVENT_CLOSED = 3,
+} or_conn_status_event_t;
+
int connection_control_finished_flushing(connection_t *conn);
int connection_control_process_inbuf(connection_t *conn);
-int control_event_circuit_status(circuit_t *circ);
-int control_event_stream_status(connection_t *conn);
-int control_event_or_conn_status(connection_t *conn);
+int control_event_circuit_status(circuit_t *circ, circuit_status_event_t e);
+int control_event_stream_status(connection_t *conn, stream_status_event_t e);
+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);
-int control_event_warning(const char *msg);
+void control_event_logmsg(int severity, const char *msg);
/********************************* cpuworker.c *****************************/
@@ -1543,7 +1573,7 @@ int router_get_runningrouters_hash(const char *s, char *digest);
int router_parse_list_from_string(const char **s,
routerlist_t **dest,
smartlist_t *good_nickname_list,
- int rr_format,
+ int rr_format,
time_t published);
int router_parse_routerlist_from_directory(const char *s,
routerlist_t **dest,
diff --git a/src/or/router.c b/src/or/router.c
index 8b1ba1763..989e7aed9 100644
--- a/src/or/router.c
+++ b/src/or/router.c
@@ -640,8 +640,9 @@ int router_dump_router_to_string(char *s, size_t maxlen, routerinfo_t *router,
bandwidth_usage = rep_hist_get_bandwidth_lines();
if (router->declared_family && smartlist_len(router->declared_family)) {
- char *s = smartlist_join_strings(router->declared_family, " ", 0);
- size_t n = strlen(s) + strlen("opt family ") + 2; /* 1 for \n, 1 for \0. */
+ size_t n;
+ char *s = smartlist_join_strings(router->declared_family, " ", 0, &n);
+ n += strlen("opt family ") + 2; /* 1 for \n, 1 for \0. */
family_line = tor_malloc(n);
tor_snprintf(family_line, n, "opt family %s\n", s);
tor_free(s);
diff --git a/src/or/routerlist.c b/src/or/routerlist.c
index 0460de283..2ed8d1b6a 100644
--- a/src/or/routerlist.c
+++ b/src/or/routerlist.c
@@ -1167,7 +1167,7 @@ int routers_update_status_from_entry(smartlist_t *routers,
r->status_set_at = time(NULL);
}
});
-
+
return 0;
}
diff --git a/src/or/test.c b/src/or/test.c
index d278d771d..2cece29d7 100644
--- a/src/or/test.c
+++ b/src/or/test.c
@@ -566,19 +566,19 @@ test_util(void) {
test_streq("a", smartlist_get(sl, 1));
test_streq("bc", smartlist_get(sl, 2));
test_streq("", smartlist_get(sl, 3));
- cp = smartlist_join_strings(sl, "", 0);
+ cp = smartlist_join_strings(sl, "", 0, NULL);
test_streq(cp, "abcabc");
tor_free(cp);
- cp = smartlist_join_strings(sl, "!", 0);
+ cp = smartlist_join_strings(sl, "!", 0, NULL);
test_streq(cp, "abc!a!bc!");
tor_free(cp);
- cp = smartlist_join_strings(sl, "XY", 0);
+ cp = smartlist_join_strings(sl, "XY", 0, NULL);
test_streq(cp, "abcXYaXYbcXY");
tor_free(cp);
- cp = smartlist_join_strings(sl, "XY", 1);
+ cp = smartlist_join_strings(sl, "XY", 1, NULL);
test_streq(cp, "abcXYaXYbcXYXY");
tor_free(cp);
- cp = smartlist_join_strings(sl, "", 1);
+ cp = smartlist_join_strings(sl, "", 1, NULL);
test_streq(cp, "abcabc");
tor_free(cp);