diff --git a/src/or/control.c b/src/or/control.c index bfaf4555e8..f3e9711050 100644 --- a/src/or/control.c +++ b/src/or/control.c @@ -182,6 +182,8 @@ control_cmd_to_string(uint16_t cmd) return (cmd<=_CONTROL0_CMD_MAX_RECOGNIZED) ? CONTROL0_COMMANDS[cmd] : "Unknown"; } +/** Given a control event code for a message event, return the corresponding + * log severity. */ static INLINE int event_to_log_severity(int event) { @@ -195,7 +197,7 @@ event_to_log_severity(int event) } } -/** DOCDOC */ +/** Given a log severity, return the corresponding control event code. */ static INLINE int log_severity_to_event(int severity) { @@ -232,7 +234,9 @@ control_update_global_event_mask(void) control_adjust_event_log_severity(); } -/** DOCDOC */ +/** Adjust the log severities that result in control_event_logmsg being called + * to match the severity of log messages that any controllers are interested + * in. */ void control_adjust_event_log_severity(void) { @@ -370,7 +374,14 @@ read_escaped_data(const char *data, size_t len, int translate_newlines, return outp - *out; } -/** DOCDOC; test **/ +/** Given a pointer to a string starting at start containing + * in_len_max characters, decode a string beginning with a single + * quote, containing any number of non-quote characters or characters escaped + * with a backslash, and ending with a final quote. Place the resulting + * string (unquoted, unescaped) into a newly allocated string in *out; + * store its length in out_len. On success, return a pointer to the + * character immediately following the escaped string. On failure, return + * NULL. **/ static const char * get_escaped_string(const char *start, size_t in_len_max, char **out, size_t *out_len) @@ -489,7 +500,9 @@ send_control_done(connection_t *conn) } } -/** DOCDOC */ +/** Send a "DONE" message down the v0 control message conn, with body + * as provided in the len bytes at msg. + */ static void send_control_done2(connection_t *conn, const char *msg, size_t len) { @@ -545,7 +558,9 @@ send_control0_event(uint16_t event, uint32_t len, const char *body) tor_free(buf); } -/* DOCDOC */ +/* Send an event to all v1 controllers that are listening for code + * event. The event's body is created by the printf-style format in + * format, and other arguments as provided. */ static void send_control1_event(uint16_t event, const char *format, ...) { @@ -581,6 +596,7 @@ send_control1_event(uint16_t event, const char *format, ...) } } +/** Given a text circuit id, return the corresponding circuit. */ static circuit_t * get_circ(const char *id) { @@ -592,6 +608,7 @@ get_circ(const char *id) return circuit_get_by_global_id(n_id); } +/** Given a text stream id, return the corresponding AP connection. */ static connection_t * get_stream(const char *id) { @@ -994,7 +1011,8 @@ handle_control_authenticate(connection_t *conn, uint32_t len, const char *body) return 0; } -/** DOCDOC */ +/** Called when we get a SAVECONF command. Try to flush the current options to + * disk, and report success or failure. */ static int handle_control_saveconf(connection_t *conn, uint32_t len, const char *body) @@ -1012,7 +1030,9 @@ handle_control_saveconf(connection_t *conn, uint32_t len, return 0; } -/** DOCDOC */ +/** Called when we get a SIGNAL command. React to the provided signal, and + * report success or failure. (If the signal results in a shutdown, success + * may not be reported.) */ static int handle_control_signal(connection_t *conn, uint32_t len, const char *body) @@ -1064,7 +1084,8 @@ handle_control_signal(connection_t *conn, uint32_t len, return 0; } -/** DOCDOC */ +/** Called when we get a MAPADDRESS command; try to bind all listed addresses, + * and report success or failrue. */ static int handle_control_mapaddress(connection_t *conn, uint32_t len, const char *body) { @@ -1152,7 +1173,8 @@ handle_control_mapaddress(connection_t *conn, uint32_t len, const char *body) return 0; } -/** DOCDOC */ +/** Return a newly allocated string listing all valid GETINFO fields as + * required by GETINFO info/names. */ static char * list_getinfo_options(void) { @@ -1340,7 +1362,8 @@ handle_getinfo_helper(const char *question, char **answer) return 0; } -/** DOCDOC */ +/** Called when we receive a GETINFO command. Try to fetch all requested + * information, and reply with information or error message. */ static int handle_control_getinfo(connection_t *conn, uint32_t len, const char *body) { @@ -1431,7 +1454,8 @@ handle_control_getinfo(connection_t *conn, uint32_t len, const char *body) return 0; } -/** DOCDOC */ +/** Callled when we get an EXTENDCIRCUIT message. Try to extend the listed + * circuit, and report succcess or failure. */ static int handle_control_extendcircuit(connection_t *conn, uint32_t len, const char *body) @@ -1560,7 +1584,8 @@ handle_control_extendcircuit(connection_t *conn, uint32_t len, return 0; } -/** DOCDOC */ +/** Callled when we get an ATTACHSTREAM message. Try to attach the requested + * stream, and report succcess or failure. */ static int handle_control_attachstream(connection_t *conn, uint32_t len, const char *body) @@ -1652,7 +1677,9 @@ handle_control_attachstream(connection_t *conn, uint32_t len, return 0; } -/** DOCDOC */ + +/** Callled when we get a POSTDESCRIPTORT message. Try to learn the provided + * descriptor, and report succcess or failure. */ static int handle_control_postdescriptor(connection_t *conn, uint32_t len, const char *body) @@ -1694,7 +1721,8 @@ handle_control_postdescriptor(connection_t *conn, uint32_t len, return 0; } -/** DOCDOC */ +/** Called when we receive a REDIRECTSTERAM command. Try to change the target + * adderess of the named AP steream, and report success or failure. */ static int handle_control_redirectstream(connection_t *conn, uint32_t len, const char *body) @@ -1745,7 +1773,8 @@ handle_control_redirectstream(connection_t *conn, uint32_t len, return 0; } -/** DOCDOC */ +/** Called when we get a CLOSESTREAM command; try to close the named stream + * and report success or failure. */ static int handle_control_closestream(connection_t *conn, uint32_t len, const char *body) @@ -1801,7 +1830,8 @@ handle_control_closestream(connection_t *conn, uint32_t len, return 0; } -/** DOCDOC */ +/** Called when we get a CLOSECIRCUIT command; try to close the named circuit + * and report success or failure. */ static int handle_control_closecircuit(connection_t *conn, uint32_t len, const char *body) @@ -1857,7 +1887,11 @@ handle_control_closecircuit(connection_t *conn, uint32_t len, return 0; } -/** DOCDOC */ +/** Called when we get a v0 FRAGMENTHEADER or FRAGMENT command; try to append + * the data to conn->incoming_cmd, setting conn->incoming_(type|len|cur_len) + * as appropriate. If the command is malformed, drop it and all pending + * fragments and report failure. + */ static int handle_control_fragments(connection_t *conn, uint16_t command_type, uint32_t body_len, char *body) @@ -1921,7 +1955,9 @@ connection_control_reached_eof(connection_t *conn) return 0; } -/* DOCDOC */ +/** Called when data has arrived on a v1 control connection: Try to fetch + * commands from conn->inbuf, and execute them. + */ static int connection_control_process_inbuf_v1(connection_t *conn) { @@ -2070,7 +2106,9 @@ connection_control_process_inbuf_v1(connection_t *conn) goto again; } -/* DOCDOC */ +/** Called when data has arrived on a v0 control connection: Try to fetch + * commands from conn->inbuf, and execute them. + */ static int connection_control_process_inbuf_v0(connection_t *conn) { @@ -2274,7 +2312,10 @@ control_event_circuit_status(circuit_t *circ, circuit_status_event_t tp) return 0; } -/** DOCDOC */ +/** Given an AP connection conn and a len-character buffer + * buf, determine the address:port combination requested on + * conn, and write it to buf. Return 0 on success, -1 on + * failure. */ static int write_stream_target_to_buf(connection_t *conn, char *buf, size_t len) { @@ -2403,14 +2444,17 @@ control_event_bandwidth_used(uint32_t n_read, uint32_t n_written) return 0; } -/** DOCDOC */ +/** Called when we are sending a log message to the controllers: suspend + * sending further log messages to the controllers until we're done. Used by + * CONN_LOG_PROTECT. */ void disable_control_logging(void) { ++disable_log_messages; } -/** DOCDOC */ +/** We're done sending a log message to the controllers: re-enable controller + * logging. Used by CONN_LOG_PROTECT. */ void enable_control_logging(void) { @@ -2436,12 +2480,12 @@ control_event_logmsg(int severity, const char *msg) if (oldlog || event) { size_t len = strlen(msg); - disable_log_messages = 1; + ++disable_log_messages; if (event) send_control0_event(event, (uint32_t)(len+1), msg); if (oldlog) send_control0_event(EVENT_LOG_OBSOLETE, (uint32_t)(len+1), msg); - disable_log_messages = 0; + --disable_log_messages; } event = log_severity_to_event(severity); @@ -2463,9 +2507,9 @@ control_event_logmsg(int severity, const char *msg) case LOG_ERR: s = "ERR"; break; default: s = "UnknownLogSeverity"; break; } - disable_log_messages = 1; + ++disable_log_messages; send_control1_event(event, "650 %s %s\r\n", s, b?b:msg); - disable_log_messages = 0; + --disable_log_messages; tor_free(b); } } @@ -2506,7 +2550,8 @@ control_event_descriptors_changed(smartlist_t *routers) return 0; } -/** DOCDOC */ +/** Called whenever an address mapping on from from changes to to. + * expires values less than 3 are special; see connection_edge.c. */ int control_event_address_mapped(const char *from, const char *to, time_t expires) { diff --git a/src/or/directory.c b/src/or/directory.c index 7a2e80f614..60d34b9eed 100644 --- a/src/or/directory.c +++ b/src/or/directory.c @@ -1008,9 +1008,17 @@ connection_dir_client_reached_eof(connection_t *conn) tor_free(body); tor_free(headers); tor_free(reason); return -1; } - /* as we learn from them, we remove them from 'which' */ - router_load_routers_from_string(body, 0, which); - directory_info_has_arrived(time(NULL), 0); + /* Learn the routers, assuming we requested by fingerprint or "all". + * Right now, we only use "authority" to fetch ourself, so we don't want + * to risk replacing ourself with a router running at the addr:port we + * think we have. + */ + if (which || (conn->requested_resource && + !strcmpstart(conn->requested_resource, "all"))) { + /* as we learn from them, we remove them from 'which' */ + router_load_routers_from_string(body, 0, which); + directory_info_has_arrived(time(NULL), 0); + } if (which) { /* mark remaining ones as failed */ log_fn(LOG_NOTICE, "Received %d/%d routers.", n_asked_for-smartlist_len(which), n_asked_for); @@ -1627,7 +1635,11 @@ dir_routerdesc_download_failed(smartlist_t *failed) /* update_router_descriptor_downloads(time(NULL)); */ } -/* DOCDOC */ +/* Given a directory resource request generated by us, containing zero + * or more strings separated by plus signs, followed optionally by ".z", store + * the strings, in order, into fp_out. If compressed_out is + * non-NULL, set it to 1 if the resource ends in ".z", else set it to 0. + */ int dir_split_resource_into_fingerprints(const char *resource, smartlist_t *fp_out, int *compressed_out) diff --git a/src/or/or.h b/src/or/or.h index d09ed701ea..c191696301 100644 --- a/src/or/or.h +++ b/src/or/or.h @@ -1669,6 +1669,12 @@ void control_adjust_event_log_severity(void); void disable_control_logging(void); void enable_control_logging(void); +/** Execute the statement stmt, which may log events concerning the + * connection conn. To prevent infinite loops, disable log messages + * being stent to controllers if conn is a control connection. + * + * Stmt must not contain any return or goto statements. + */ #define CONN_LOG_PROTECT(conn, stmt) \ do { \ int _log_conn_is_control = (conn && conn->type == CONN_TYPE_CONTROL); \ @@ -1679,6 +1685,11 @@ void enable_control_logging(void); enable_control_logging(); \ } while (0) +/** Log information about the connection conn, protecting it as with + * CONN_LOG_PROTECT. Example: + * + * LOG_FN_CONN(conn, (LOG_DEBUG, "Socket %d wants to write", conn->s)); + **/ #define LOG_FN_CONN(conn, args) \ CONN_LOG_PROTECT(conn, log_fn args) diff --git a/src/or/routerlist.c b/src/or/routerlist.c index 86def549f2..8fcd1d4aff 100644 --- a/src/or/routerlist.c +++ b/src/or/routerlist.c @@ -49,9 +49,11 @@ extern int has_fetched_directory; /**< from main.c */ static smartlist_t *networkstatus_list = NULL; /** Global list of routerstatuses_t for each router, known or unknown. */ static smartlist_t *routerstatus_list = NULL; -/*DOCDOC */ +/** True iff any member of networkstatus_list has changed since the last time + * we called routerstatus_list_update_from_networkstatus(). */ static int networkstatus_list_has_changed = 0; -/*DOCDOC */ +/** True iff any element of routerstatus_list has changed since the last + * time we called routers_update_all_from_networkstatus().*/ static int routerstatus_list_has_changed = 0; /** Repopulate our list of network_status_t objects from the list cached on @@ -1548,7 +1550,8 @@ networkstatus_find_entry(networkstatus_t *ns, const char *digest) _compare_digest_to_routerstatus_entry); } -/*DOCDOC*/ +/** Return the consensus view of the status of the router whose digest is + * digest, or NULL if we don't know about any such router. */ local_routerstatus_t * router_get_combined_status_by_digest(const char *digest) { @@ -2078,7 +2081,11 @@ routers_update_all_from_networkstatus(void) * our view of who's running. */ #define MIN_TO_INFLUENCE_RUNNING 3 -/** DOCDOC */ +/** Change the is_recent field of each member of networkstatus_list so that + * all members more recent than DEFAULT_RUNNING_INTERVAL are recent, and + * at least the MIN_TO_INFLUENCE_RUNNING most recent members are resent, and no + * others are recent. Set networkstatus_list_has_changed if anything happeed. + */ void networkstatus_list_update_recent(time_t now) { @@ -2119,7 +2126,11 @@ networkstatus_list_update_recent(time_t now) networkstatus_list_has_changed = 1; } -/* DOCDOC */ +/** Update our view of router status (as stored in routerstatus_list) from + * the current set of network status documents (as stored in networkstatus_list). + * Do nothing unless the network status list has changed since the last time + * this function was called. + */ static void routerstatus_list_update_from_networkstatus(time_t now) { @@ -2493,26 +2504,33 @@ update_router_descriptor_downloads(time_t now) #define MAX_DL_PER_REQUEST 128 #define MIN_DL_PER_REQUEST 4 #define MIN_REQUESTS 3 +#define MAX_DL_TO_DELAY 16 +#define MAX_INTERVAL_WITHOUT_REQUEST 10*60 smartlist_t *downloadable = NULL; int get_all = 0; - int always_split = !server_mode(get_options()) || !get_options()->DirPort; + int mirror = server_mode(get_options()) && get_options()->DirPort; + static time_t last_download_attempted = 0; if (!networkstatus_list || smartlist_len(networkstatus_list)<2) get_all = 1; if (get_all) { log_fn(LOG_NOTICE, "Launching request for all routers"); + last_download_attempted = now; directory_get_from_dirserver(DIR_PURPOSE_FETCH_SERVERDESC,"all.z",1); return; } downloadable = router_list_downloadable(); - if (smartlist_len(downloadable)) { + if (smartlist_len(downloadable) >= MAX_DL_TO_DELAY || + (smartlist_len(downloadable) && + (mirror || + last_download_attempted + MAX_INTERVAL_WITHOUT_REQUEST < now))) { int i, j, n, n_per_request=MAX_DL_PER_REQUEST; size_t r_len = MAX_DL_PER_REQUEST*(HEX_DIGEST_LEN+1)+16; char *resource = tor_malloc(r_len); n = smartlist_len(downloadable); - if (always_split) { + if (! mirror) { n_per_request = (n+MIN_REQUESTS-1) / MIN_REQUESTS; if (n_per_request > MAX_DL_PER_REQUEST) n_per_request = MAX_DL_PER_REQUEST; @@ -2532,6 +2550,7 @@ update_router_descriptor_downloads(time_t now) *cp++ = '+'; } memcpy(cp-1, ".z", 3); + last_download_attempted = now; directory_get_from_dirserver(DIR_PURPOSE_FETCH_SERVERDESC,resource,1); } tor_free(resource); @@ -2556,7 +2575,9 @@ router_have_minimum_dir_info(void) return smartlist_len(routerlist->routers) > (avg/4); } -/** DOCDOC */ +/** Reset the descriptor download failure count on all routers, so that we + * can retry any long-failed routers immediately. + */ void router_reset_descriptor_download_failures(void) { diff --git a/src/or/routerparse.c b/src/or/routerparse.c index 51ab77ffd0..7665e2a705 100644 --- a/src/or/routerparse.c +++ b/src/or/routerparse.c @@ -245,20 +245,19 @@ router_append_dirobj_signature(char *buf, size_t buf_len, const char *digest, return -1; } -/** Return 1 if myversion is not in versionlist, and if at least - * one version of Tor on versionlist is newer than myversion. - - * Return 1 if no version from the same series as myversion is - * in versionlist (and myversion is not the newest - * version), or if a newer version from the same series is in - * versionlist. +/** Return VS_RECOMMENDED if myversion is contained in + * versionlist. Else, return VS_OLD if every member of + * versionlist is newer than myversion. Else, return + * VS_NEW_IN_SERIES if there is at least one member of versionlist in + * the same series (major.minor.micro) as myversion, but no such member + * is newer than myversion.. Else, return VS_NEW if every memeber of + * versionlist is older than myversion. Else, return + * VS_UNRECOMMENDED. * - * Otherwise return 0. * (versionlist is a comma-separated list of version strings, * optionally prefixed with "Tor". Versions that can't be parsed are * ignored.) - * - * DOCDOC interface changed */ + */ version_status_t tor_version_is_obsolete(const char *myversion, const char *versionlist) { @@ -322,7 +321,17 @@ tor_version_is_obsolete(const char *myversion, const char *versionlist) return ret; } -/** DOCDOC */ +/** Return the combined status of the current version, given that we know of + * one set of networkstatuses that give us status a, and another that + * gives us status b. + * + * For example, if one authority thinks that we're NEW, and another thinks + * we're OLD, we're simply UNRECOMMENDED. + * + * This function does not handle calculating whether we're RECOMMENDED; that + * follows a simple majority rule. This function simply calculates *why* + * we're not recommended (if we're not). + */ version_status_t version_status_join(version_status_t a, version_status_t b) {