Commit 451f8b50 authored by Nick Mathewson's avatar Nick Mathewson 🌉
Browse files

- Implement all of control interface except authentication, setconfig,

  and actually making the sockets.
- Make sure that identity-based nicknames start with $.
- Use new string_join interface.


svn:r2661
parent 86ba0029
......@@ -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;
}
......
......@@ -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 */
......
......@@ -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);
......
......@@ -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:
......
......@@ -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;
......
......@@ -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;
}
......
......@@ -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
......
......@@ -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);
}
......
......@@ -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) {
......
......@@ -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,
......
......@@ -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);
......
......@@ -1167,7 +1167,7 @@ int routers_update_status_from_entry(smartlist_t *routers,
r->status_set_at = time(NULL);
}
});
return 0;
}
......
......@@ -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);
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment