mirror of
https://gitlab.torproject.org/tpo/core/tor.git
synced 2024-12-06 19:41:15 +01:00
- 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
This commit is contained in:
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
+83
-16
@@ -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;
|
||||
tor_assert(circ);
|
||||
tor_assert(CIRCUIT_IS_ORIGIN(circ));
|
||||
|
||||
/* XXXXX009 NM */
|
||||
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) {
|
||||
|
||||
+35
-5
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
+5
-5
@@ -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);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user