Merge remote-tracking branch 'rransom/feature2411-v4'

This commit is contained in:
Nick Mathewson 2011-12-22 10:51:39 -05:00
commit 7cb804343b
4 changed files with 180 additions and 32 deletions

12
changes/feature2411 Normal file
View File

@ -0,0 +1,12 @@
o Minor features:
- Report flags that control a circuit's path selection to
controllers in CIRC events and in replies to 'GETINFO
circuit-status'. Implements part of ticket 2411.
- Report the hidden service address and current state of a
hidden-service-related circuit to controllers in CIRC events and
in replies to 'GETINFO circuit-status'. Implements part of
ticket 2411.

View File

@ -378,6 +378,63 @@ circuit_purpose_to_controller_string(uint8_t purpose)
} }
} }
/** Return a string specifying the state of the hidden-service circuit
* purpose <b>purpose</b>, or NULL if <b>purpose</b> is not a
* hidden-service-related circuit purpose. */
const char *
circuit_purpose_to_controller_hs_state_string(uint8_t purpose)
{
switch (purpose)
{
default:
log_fn(LOG_WARN, LD_BUG,
"Unrecognized circuit purpose: %d",
(int)purpose);
tor_fragile_assert();
/* fall through */
case CIRCUIT_PURPOSE_OR:
case CIRCUIT_PURPOSE_C_GENERAL:
case CIRCUIT_PURPOSE_C_MEASURE_TIMEOUT:
case CIRCUIT_PURPOSE_TESTING:
case CIRCUIT_PURPOSE_CONTROLLER:
return NULL;
case CIRCUIT_PURPOSE_INTRO_POINT:
return "OR_HSSI_ESTABLISHED";
case CIRCUIT_PURPOSE_REND_POINT_WAITING:
return "OR_HSCR_ESTABLISHED";
case CIRCUIT_PURPOSE_REND_ESTABLISHED:
return "OR_HS_R_JOINED";
case CIRCUIT_PURPOSE_C_INTRODUCING:
return "HSCI_CONNECTING";
case CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT:
return "HSCI_INTRO_SENT";
case CIRCUIT_PURPOSE_C_INTRODUCE_ACKED:
return "HSCI_DONE";
case CIRCUIT_PURPOSE_C_ESTABLISH_REND:
return "HSCR_CONNECTING";
case CIRCUIT_PURPOSE_C_REND_READY:
return "HSCR_ESTABLISHED_IDLE";
case CIRCUIT_PURPOSE_C_REND_READY_INTRO_ACKED:
return "HSCR_ESTABLISHED_WAITING";
case CIRCUIT_PURPOSE_C_REND_JOINED:
return "HSCR_JOINED";
case CIRCUIT_PURPOSE_S_ESTABLISH_INTRO:
return "HSSI_CONNECTING";
case CIRCUIT_PURPOSE_S_INTRO:
return "HSSI_ESTABLISHED";
case CIRCUIT_PURPOSE_S_CONNECT_REND:
return "HSSR_CONNECTING";
case CIRCUIT_PURPOSE_S_REND_JOINED:
return "HSSR_JOINED";
}
}
/** Return a human-readable string for the circuit purpose <b>purpose</b>. */ /** Return a human-readable string for the circuit purpose <b>purpose</b>. */
const char * const char *
circuit_purpose_to_string(uint8_t purpose) circuit_purpose_to_string(uint8_t purpose)

View File

@ -15,6 +15,7 @@
circuit_t * _circuit_get_global_list(void); circuit_t * _circuit_get_global_list(void);
const char *circuit_state_to_string(int state); const char *circuit_state_to_string(int state);
const char *circuit_purpose_to_controller_string(uint8_t purpose); const char *circuit_purpose_to_controller_string(uint8_t purpose);
const char *circuit_purpose_to_controller_hs_state_string(uint8_t purpose);
const char *circuit_purpose_to_string(uint8_t purpose); const char *circuit_purpose_to_string(uint8_t purpose);
void circuit_dump_by_conn(connection_t *conn, int severity); void circuit_dump_by_conn(connection_t *conn, int severity);
void circuit_set_p_circid_orconn(or_circuit_t *circ, circid_t id, void circuit_set_p_circid_orconn(or_circuit_t *circ, circid_t id,

View File

@ -1780,6 +1780,88 @@ getinfo_helper_dir(control_connection_t *control_conn,
return 0; return 0;
} }
/** Allocate and return a description of <b>circ</b>'s current status,
* including its path (if any). */
static char *
circuit_describe_status_for_controller(origin_circuit_t *circ)
{
char *rv;
smartlist_t *descparts = smartlist_create();
{
char *vpath = circuit_list_path_for_controller(circ);
if (*vpath) {
smartlist_add(descparts, vpath);
} else {
tor_free(vpath); /* empty path; don't put an extra space in the result */
}
}
{
char *buildflags = NULL;
cpath_build_state_t *build_state = circ->build_state;
smartlist_t *flaglist = smartlist_create();
char *flaglist_joined;
if (build_state->onehop_tunnel)
smartlist_add(flaglist, (void *)"ONEHOP_TUNNEL");
if (build_state->is_internal)
smartlist_add(flaglist, (void *)"IS_INTERNAL");
if (build_state->need_capacity)
smartlist_add(flaglist, (void *)"NEED_CAPACITY");
if (build_state->need_uptime)
smartlist_add(flaglist, (void *)"NEED_UPTIME");
/* Only emit a BUILD_FLAGS argument if it will have a non-empty value. */
if (smartlist_len(flaglist)) {
flaglist_joined = smartlist_join_strings(flaglist, ",", 0, NULL);
tor_asprintf(&buildflags, "BUILD_FLAGS=%s", flaglist_joined);
smartlist_add(descparts, buildflags);
tor_free(flaglist_joined);
}
smartlist_free(flaglist);
}
{
char *purpose = NULL;
tor_asprintf(&purpose, "PURPOSE=%s",
circuit_purpose_to_controller_string(circ->_base.purpose));
smartlist_add(descparts, purpose);
}
{
char *hs_state_arg = NULL;
const char *hs_state =
circuit_purpose_to_controller_hs_state_string(circ->_base.purpose);
if (hs_state != NULL) {
tor_asprintf(&hs_state_arg, "HS_STATE=%s",
hs_state);
smartlist_add(descparts, hs_state_arg);
}
}
if (circ->rend_data != NULL) {
char *rend_query_arg = NULL;
tor_asprintf(&rend_query_arg, "REND_QUERY=%s",
circ->rend_data->onion_address);
smartlist_add(descparts, rend_query_arg);
}
rv = smartlist_join_strings(descparts, " ", 0, NULL);
SMARTLIST_FOREACH(descparts, char *, cp, tor_free(cp));
smartlist_free(descparts);
return rv;
}
/** Implementation helper for GETINFO: knows how to generate summaries of the /** Implementation helper for GETINFO: knows how to generate summaries of the
* current states of things we send events about. */ * current states of things we send events about. */
static int static int
@ -1789,33 +1871,33 @@ getinfo_helper_events(control_connection_t *control_conn,
{ {
(void) control_conn; (void) control_conn;
if (!strcmp(question, "circuit-status")) { if (!strcmp(question, "circuit-status")) {
circuit_t *circ; circuit_t *circ_;
smartlist_t *status = smartlist_create(); smartlist_t *status = smartlist_create();
for (circ = _circuit_get_global_list(); circ; circ = circ->next) { for (circ_ = _circuit_get_global_list(); circ_; circ_ = circ_->next) {
char *s, *path; origin_circuit_t *circ;
char *s, *circdesc;
size_t slen; size_t slen;
const char *state; const char *state;
const char *purpose; if (! CIRCUIT_IS_ORIGIN(circ_) || circ_->marked_for_close)
if (! CIRCUIT_IS_ORIGIN(circ) || circ->marked_for_close)
continue; continue;
circ = TO_ORIGIN_CIRCUIT(circ_);
path = circuit_list_path_for_controller(TO_ORIGIN_CIRCUIT(circ)); if (circ->_base.state == CIRCUIT_STATE_OPEN)
if (circ->state == CIRCUIT_STATE_OPEN)
state = "BUILT"; state = "BUILT";
else if (strlen(path)) else if (circ->cpath)
state = "EXTENDED"; state = "EXTENDED";
else else
state = "LAUNCHED"; state = "LAUNCHED";
purpose = circuit_purpose_to_controller_string(circ->purpose); circdesc = circuit_describe_status_for_controller(circ);
slen = strlen(path)+strlen(state)+strlen(purpose)+30;
slen = strlen(circdesc)+strlen(state)+30;
s = tor_malloc(slen+1); s = tor_malloc(slen+1);
tor_snprintf(s, slen, "%lu %s%s%s PURPOSE=%s", tor_snprintf(s, slen, "%lu %s%s%s",
(unsigned long)TO_ORIGIN_CIRCUIT(circ)->global_identifier, (unsigned long)circ->global_identifier,
state, *path ? " " : "", path, purpose); state, *circdesc ? " " : "", circdesc);
smartlist_add(status, s); smartlist_add(status, s);
tor_free(path); tor_free(circdesc);
} }
*answer = smartlist_join_strings(status, "\r\n", 0, NULL); *answer = smartlist_join_strings(status, "\r\n", 0, NULL);
SMARTLIST_FOREACH(status, char *, cp, tor_free(cp)); SMARTLIST_FOREACH(status, char *, cp, tor_free(cp));
@ -3237,7 +3319,7 @@ control_event_circuit_status(origin_circuit_t *circ, circuit_status_event_t tp,
int reason_code) int reason_code)
{ {
const char *status; const char *status;
char extended_buf[96]; char reasons[64] = "";
if (!EVENT_IS_INTERESTING(EVENT_CIRCUIT_STATUS)) if (!EVENT_IS_INTERESTING(EVENT_CIRCUIT_STATUS))
return 0; return 0;
tor_assert(circ); tor_assert(circ);
@ -3254,36 +3336,32 @@ control_event_circuit_status(origin_circuit_t *circ, circuit_status_event_t tp,
return 0; return 0;
} }
tor_snprintf(extended_buf, sizeof(extended_buf), "PURPOSE=%s",
circuit_purpose_to_controller_string(circ->_base.purpose));
if (tp == CIRC_EVENT_FAILED || tp == CIRC_EVENT_CLOSED) { if (tp == CIRC_EVENT_FAILED || tp == CIRC_EVENT_CLOSED) {
const char *reason_str = circuit_end_reason_to_control_string(reason_code); const char *reason_str = circuit_end_reason_to_control_string(reason_code);
char *reason = NULL; char unk_reason_buf[16];
size_t n=strlen(extended_buf);
if (!reason_str) { if (!reason_str) {
reason = tor_malloc(16); tor_snprintf(unk_reason_buf, 16, "UNKNOWN_%d", reason_code);
tor_snprintf(reason, 16, "UNKNOWN_%d", reason_code); reason_str = unk_reason_buf;
reason_str = reason;
} }
if (reason_code > 0 && reason_code & END_CIRC_REASON_FLAG_REMOTE) { if (reason_code > 0 && reason_code & END_CIRC_REASON_FLAG_REMOTE) {
tor_snprintf(extended_buf+n, sizeof(extended_buf)-n, tor_snprintf(reasons, sizeof(reasons),
" REASON=DESTROYED REMOTE_REASON=%s", reason_str); " REASON=DESTROYED REMOTE_REASON=%s", reason_str);
} else { } else {
tor_snprintf(extended_buf+n, sizeof(extended_buf)-n, tor_snprintf(reasons, sizeof(reasons),
" REASON=%s", reason_str); " REASON=%s", reason_str);
} }
tor_free(reason);
} }
{ {
char *vpath = circuit_list_path_for_controller(circ); char *circdesc = circuit_describe_status_for_controller(circ);
const char *sp = strlen(vpath) ? " " : ""; const char *sp = strlen(circdesc) ? " " : "";
send_control_event(EVENT_CIRCUIT_STATUS, ALL_FORMATS, send_control_event(EVENT_CIRCUIT_STATUS, ALL_FORMATS,
"650 CIRC %lu %s%s%s%s\r\n", "650 CIRC %lu %s%s%s%s\r\n",
(unsigned long)circ->global_identifier, (unsigned long)circ->global_identifier,
status, sp, vpath, extended_buf); status, sp,
tor_free(vpath); circdesc,
reasons);
tor_free(circdesc);
} }
return 0; return 0;