From 11e5656ab7fdbf8bad2e041261542f2bda6a5a8c Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Fri, 16 Feb 2007 20:01:02 +0000 Subject: [PATCH] r11826@catbus: nickm | 2007-02-16 14:58:38 -0500 Resolve 56 DOCDOC comments. svn:r9594 --- src/common/compat.c | 27 +++++++++------ src/common/torgzip.c | 3 +- src/or/buffers.c | 16 +++++++-- src/or/connection_edge.c | 7 ++-- src/or/control.c | 75 +++++++++++++++++++++++++++++----------- src/or/dns.c | 3 +- src/or/hibernate.c | 5 +-- src/or/onion.c | 3 +- src/or/or.h | 2 ++ src/or/policies.c | 27 ++++++++++----- src/or/rephist.c | 4 +-- src/or/routerlist.c | 36 +++++++++++++------ src/or/routerparse.c | 7 ++-- 13 files changed, 149 insertions(+), 66 deletions(-) diff --git a/src/common/compat.c b/src/common/compat.c index 3833c396e8..d9df8892a5 100644 --- a/src/common/compat.c +++ b/src/common/compat.c @@ -114,13 +114,15 @@ const char compat_c_id[] = #endif #ifdef HAVE_SYS_MMAN_H -/** DOCDOC */ +/** Implementation for tor_mmap_t: holds the regular tor_mmap_t, along + * with extra fields needed for mmap()-based memory mapping. */ typedef struct tor_mmap_impl_t { tor_mmap_t base; size_t mapping_size; /**< Size of the actual mapping. (This is this file * size, rounded up to the nearest page.) */ } tor_mmap_impl_t; -/** DOCDOC */ +/** Try to create a memory mapping for filename and return it. On + * failure, return NULL. */ tor_mmap_t * tor_mmap_file(const char *filename) { @@ -170,7 +172,7 @@ tor_mmap_file(const char *filename) return &(res->base); } -/** DOCDOC */ +/** Release storage held for a memory mapping. */ void tor_munmap_file(tor_mmap_t *handle) { @@ -179,7 +181,8 @@ tor_munmap_file(tor_mmap_t *handle) tor_free(h); } #elif defined(MS_WINDOWS) -/** DOCDOC */ +/** Implementation for tor_mmap_t: holds the regular tor_mmap_t, along + * with extra fields needed for WIN32 memory mapping. */ typedef struct win_mmap_t { tor_mmap_t base; HANDLE file_handle; @@ -977,14 +980,16 @@ get_uname(void) */ #if defined(USE_PTHREADS) -/** Wraps a an int (*)(void*) function and its argument so we can +/** Wraps a void (*)(void*) function and its argument so we can * invoke them in a way pthreads would expect. */ typedef struct tor_pthread_data_t { void (*func)(void *); void *data; } tor_pthread_data_t; -/** DOCDOC */ +/** Given a tor_pthread_data_t d, call d->func(d->data);, and + * free d. Used to make sure we can call functions the way pthread + * expects. */ static void * tor_pthread_helper_fn(void *_data) { @@ -1227,7 +1232,7 @@ tor_get_thread_id(void) struct tor_mutex_t { pthread_mutex_t mutex; }; -/** DOCDOC */ +/** Allocate and return new lock. */ tor_mutex_t * tor_mutex_new(void) { @@ -1235,21 +1240,21 @@ tor_mutex_new(void) pthread_mutex_init(&mutex->mutex, NULL); return mutex; } -/** DOCDOC */ +/** Wait until m is free, then acquire it. */ void tor_mutex_acquire(tor_mutex_t *m) { tor_assert(m); pthread_mutex_lock(&m->mutex); } -/** DOCDOC */ +/** Release the lock m so another thread can have it. */ void tor_mutex_release(tor_mutex_t *m) { tor_assert(m); pthread_mutex_unlock(&m->mutex); } -/** DOCDOC */ +/** Free all storage held by the lock m. */ void tor_mutex_free(tor_mutex_t *m) { @@ -1257,7 +1262,7 @@ tor_mutex_free(tor_mutex_t *m) pthread_mutex_destroy(&m->mutex); tor_free(m); } -/** DOCDOC */ +/** Return an integer representing this thread. */ unsigned long tor_get_thread_id(void) { diff --git a/src/common/torgzip.c b/src/common/torgzip.c index acad163daf..e1028293a3 100644 --- a/src/common/torgzip.c +++ b/src/common/torgzip.c @@ -299,7 +299,8 @@ detect_compression_method(const char *in, size_t in_len) } } -/** DOCDOC */ +/** Internal state for a incremental zlib compression/decompression. The body + * of this struct is not exposed. */ struct tor_zlib_state_t { struct z_stream_s stream; int compress; diff --git a/src/or/buffers.c b/src/or/buffers.c index 008e92788d..d8f39b85d5 100644 --- a/src/or/buffers.c +++ b/src/or/buffers.c @@ -20,15 +20,25 @@ const char buffers_c_id[] = #undef PARANOIA #undef NOINLINE -#ifdef SENTINELS /* If SENTINELS is defined, check for attempts to write beyond the - * end/before the start of the buffer. DOCDOC macros + * end/before the start of the buffer. */ +#ifdef SENTINELS +/* 4-byte value to write at the start of each buffer memory region */ #define START_MAGIC 0x70370370u +/* 4-byte value to write at the end of each buffer memory region */ #define END_MAGIC 0xA0B0C0D0u +/* Given buf->mem, yield a pointer to the raw memory region (for free(), + * realloc(), and so on) */ #define RAW_MEM(m) ((void*)(((char*)m)-4)) +/* Given a pointer to the raw memory region (from malloc() or realloc()), + * yield the correct value for buf->mem (just past the first sentinel). */ #define GUARDED_MEM(m) ((void*)(((char*)m)+4)) +/* How much memory do we need to allocate for a buffer to hold ln bytes + * of data? */ #define ALLOC_LEN(ln) ((ln)+8) +/* Initialize the sentinel values on m (a value of buf->mem), which + * has ln useful bytes. */ #define SET_GUARDS(m, ln) \ do { set_uint32((m)-4,START_MAGIC); set_uint32((m)+ln,END_MAGIC); } while (0) #else @@ -49,7 +59,7 @@ const char buffers_c_id[] = #define INLINE #endif -/* DOCDOC */ +/** Magic value for buf_t.magic, to catch pointer errors. */ #define BUFFER_MAGIC 0xB0FFF312u /** A resizeable buffer, optimized for reading and writing. */ struct buf_t { diff --git a/src/or/connection_edge.c b/src/or/connection_edge.c index 56a3009457..f7af439b01 100644 --- a/src/or/connection_edge.c +++ b/src/or/connection_edge.c @@ -1394,9 +1394,10 @@ connection_ap_handshake_rewrite_and_attach(edge_connection_t *conn, safe_str(conn->rend_query)); rend_client_refetch_renddesc(conn->rend_query); } else { /* r > 0 */ -/** DOCDOC */ -#define NUM_SECONDS_BEFORE_REFETCH (60*15) - if (time(NULL) - entry->received < NUM_SECONDS_BEFORE_REFETCH) { +/** How long after we receive a hidden service descriptor do we consider + * it valid? */ +#define NUM_SECONDS_BEFORE_HS_REFETCH (60*15) + if (time(NULL) - entry->received < NUM_SECONDS_BEFORE_HS_REFETCH) { conn->_base.state = AP_CONN_STATE_CIRCUIT_WAIT; log_info(LD_REND, "Descriptor is here and fresh enough. Great."); if (connection_ap_handshake_attach_circuit(conn) < 0) { diff --git a/src/or/control.c b/src/or/control.c index d3f07a9107..b3ae38cc36 100644 --- a/src/or/control.c +++ b/src/or/control.c @@ -11,10 +11,13 @@ const char control_c_id[] = #include "or.h" -/** DOCDOC */ +/** Yield true iff s is the state of a control_connection_t that has + * finished authentication and is accepting commands. */ #define STATE_IS_OPEN(s) ((s) == CONTROL_CONN_STATE_OPEN_V0 || \ (s) == CONTROL_CONN_STATE_OPEN_V1) -/** DOCDOC */ +/** Yield trie iff s is the state of a control_connection_t that is + * speaking the V0 protocol. + */ #define STATE_IS_V0(s) ((s) == CONTROL_CONN_STATE_NEEDAUTH_V0 || \ (s) == CONTROL_CONN_STATE_OPEN_V0) @@ -712,7 +715,17 @@ send_control1_event_string(uint16_t event, event_format_t which, } } -/** DOCDOC */ +/** Helper for send_control1_event and send_control1_event_extended: + * 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. + * + * If extended is true, and the format contains a single '@' character, + * it will be replaced with a space and all text after that character will be + * sent only to controllers that have enabled extended events. + * + * Currently the length of the message is limited to 1024 (including the + * ending \n\r\0. */ static void send_control1_event_impl(uint16_t event, event_format_t which, int extended, const char *format, va_list ap) @@ -1482,7 +1495,8 @@ handle_control_mapaddress(control_connection_t *conn, uint32_t len, return 0; } -/** DOCDOC */ +/** Implementation helper for GETINFO: knows the answers for various + * trivial-to-implement questions. */ static int getinfo_helper_misc(control_connection_t *conn, const char *question, char **answer) @@ -1497,7 +1511,8 @@ getinfo_helper_misc(control_connection_t *conn, const char *question, } else if (!strcmp(question, "events/names")) { *answer = tor_strdup("CIRC STREAM ORCONN BW DEBUG INFO NOTICE WARN ERR " "NEWDESC ADDRMAP AUTHDIR_NEWDESCS DESCCHANGED " - "NS STATUS_GENERAL STATUS_CLIENT STATUS_SERVER"); + "NS STATUS_GENERAL STATUS_CLIENT STATUS_SERVER " + "GUARD STREAM_BW"); } else if (!strcmp(question, "features/names")) { *answer = tor_strdup("VERBOSE_NAMES EXTENDED_EVENTS"); } else if (!strcmp(question, "address")) { @@ -1520,7 +1535,8 @@ getinfo_helper_misc(control_connection_t *conn, const char *question, return 0; } -/** DOCDOC */ +/** Implementatino helper for GETINFO: knows the answers for questions about + * directory information. */ static int getinfo_helper_dir(control_connection_t *control_conn, const char *question, char **answer) @@ -1628,7 +1644,8 @@ getinfo_helper_dir(control_connection_t *control_conn, return 0; } -/** DOCDOC */ +/** Implementation helper for GETINFO: knows how to generate summaries of the + * current states of things we send events about. */ static int getinfo_helper_events(control_connection_t *control_conn, const char *question, char **answer) @@ -1774,23 +1791,29 @@ getinfo_helper_events(control_connection_t *control_conn, return 0; } -/** DOCDOC */ +/** Callback function for GETINFO: on a given control connection, try to + * answer the question q and store the newly-allocated answer in + * *a. If there's no answer, or an error occurs, just don't set + * a. Return 0. + */ typedef int (*getinfo_helper_t)(control_connection_t *, const char *q, char **a); -/** DOCDOC */ +/** A single item for the GETINFO question-to-answer-function table. */ typedef struct getinfo_item_t { - const char *varname; - getinfo_helper_t fn; - const char *desc; - int is_prefix; + const char *varname; /**< The value (or prefix) of the question */ + getinfo_helper_t fn; /**< The function that knows the answer: NULL if + * this entry is documentation-only. */ + const char *desc; /**< Description of the variable. */ + int is_prefix; /** Must varname match exactly, or must it be a prefix? */ } getinfo_item_t; #define ITEM(name, fn, desc) { name, getinfo_helper_##fn, desc, 0 } #define PREFIX(name, fn, desc) { name, getinfo_helper_##fn, desc, 1 } #define DOC(name, desc) { name, NULL, desc, 0 } -/** DOCDOC */ +/** Table mapping questions accepted by GETINFO to the functions that know how + * to answer them. */ static const getinfo_item_t getinfo_items[] = { ITEM("version", misc, "The current version of Tor."), ITEM("config-file", misc, "Current location of the \"torrc\" file."), @@ -1851,6 +1874,7 @@ static const getinfo_item_t getinfo_items[] = { { NULL, NULL, NULL, 0 } }; +/** Allocate and return a list of recognized GETINFO options. */ static char * list_getinfo_options(void) { @@ -2588,7 +2612,8 @@ handle_control_closecircuit(control_connection_t *conn, uint32_t len, return 0; } -/** DOCDOC */ +/** Called when we get a USEFEATURE command: parse the feature list, and + * set up the control_connection's options properly. */ static int handle_control_usefeature(control_connection_t *conn, uint32_t len, @@ -3028,7 +3053,8 @@ connection_control_process_inbuf(control_connection_t *conn) return connection_control_process_inbuf_v1(conn); } -/** DOCDOC */ +/** Convert a numeric reason for destroying a circuit into a string for a + * CIRCUIT event. */ static const char * circuit_end_reason_to_string(int reason) { @@ -3298,7 +3324,9 @@ control_event_stream_status(edge_connection_t *conn, stream_status_event_t tp, return 0; } -/** DOCDOC */ +/** Figure out best name for the target router of an OR connection, and write + * it into the len-character buffer name. Use verbose names if + * long_names is set. */ static void orconn_target_get_name(int long_names, char *name, size_t len, or_connection_t *conn) @@ -3325,7 +3353,7 @@ orconn_target_get_name(int long_names, } } -/** DOCDOC */ +/** Convert a TOR_TLS error code into an END_OR_CONN_* reason. */ int control_tls_error_to_reason(int e) { @@ -3350,7 +3378,8 @@ control_tls_error_to_reason(int e) } } -/** DOCDOC */ +/** Convert the reason for ending an OR connection r into the format + * used in ORCONN events. Return NULL if the reason is unrecognized. */ static const char * or_conn_end_reason_to_string(int r) { @@ -3379,9 +3408,13 @@ or_conn_end_reason_to_string(int r) } } -/** DOCDOC */ +/** Called when the status of an OR connection conn changes: tell any + * interested control connections. tp is the new status for the + * connection. If conn has just closed or failed, then reason + * may be the reason why. + */ int -control_event_or_conn_status(or_connection_t *conn,or_conn_status_event_t tp, +control_event_or_conn_status(or_connection_t *conn, or_conn_status_event_t tp, int reason) { char buf[HEX_DIGEST_LEN+3]; /* status, dollar, identity, NUL */ diff --git a/src/or/dns.c b/src/or/dns.c index 8224423e92..7ee451826d 100644 --- a/src/or/dns.c +++ b/src/or/dns.c @@ -68,7 +68,8 @@ typedef struct pending_connection_t { struct pending_connection_t *next; } pending_connection_t; -/** DOCDOC */ +/** Value of 'magic' field for cached_resolve_t. Used to try to catch bad + * pointers and memory stomping. */ #define CACHED_RESOLVE_MAGIC 0x1234F00D /* Possible states for a cached resolve_t */ diff --git a/src/or/hibernate.c b/src/or/hibernate.c index 5bc91b7757..a3ea9cce0b 100644 --- a/src/or/hibernate.c +++ b/src/or/hibernate.c @@ -42,7 +42,8 @@ typedef enum { extern long stats_n_seconds_working; /* published uptime */ -/** DOCDOC */ +/** Are we currently awake, asleep, running out of bandwidth, or shutting + * down? */ static hibernate_state_t hibernate_state = HIBERNATE_STATE_LIVE; /** If are hibernating, when do we plan to wake up? Set to 0 if we * aren't hibernating. */ @@ -51,7 +52,7 @@ static time_t hibernate_end_time = 0; * we aren't shutting down. */ static time_t shutdown_time = 0; -/** DOCDOC */ +/** Possible accounting periods. */ typedef enum { UNIT_MONTH=1, UNIT_WEEK=2, UNIT_DAY=3, } time_unit_t; diff --git a/src/or/onion.c b/src/or/onion.c index a1df3c4992..fa0896ab0b 100644 --- a/src/or/onion.c +++ b/src/or/onion.c @@ -25,7 +25,8 @@ typedef struct onion_queue_t { /** 5 seconds on the onion queue til we just send back a destroy */ #define ONIONQUEUE_WAIT_CUTOFF 5 -/** DOCDOC */ +/** First and last elements in the linked list of of circuits waiting for CPU + * workers, or NULL if the list is empty. */ static onion_queue_t *ol_list=NULL; static onion_queue_t *ol_tail=NULL; /** Length of ol_list */ diff --git a/src/or/or.h b/src/or/or.h index a2e7545b87..04a6e0eb8d 100644 --- a/src/or/or.h +++ b/src/or/or.h @@ -2669,6 +2669,8 @@ int rep_hist_get_predicted_internal(time_t now, int *need_uptime, int any_predicted_circuits(time_t now); int rep_hist_circbuilding_dormant(time_t now); +/** Possible public/private key operations in Tor: used to keep track of where + * we're spending our time. */ typedef enum { SIGN_DIR, SIGN_RTR, VERIFY_DIR, VERIFY_RTR, diff --git a/src/or/policies.c b/src/or/policies.c index 73a342f6bf..392385ce5a 100644 --- a/src/or/policies.c +++ b/src/or/policies.c @@ -12,15 +12,18 @@ const char policies_c_id[] = \ #include "or.h" -/** DOCDOC */ +/** Policy that addresses for incoming SOCKS connections must match. */ static addr_policy_t *socks_policy = NULL; -/** DOCDOC */ +/** Policy that addresses for incoming directory connections must match. */ static addr_policy_t *dir_policy = NULL; -/** DOCDOC */ +/** Policy that addresses for incoming router descriptors must match in order + * to be published by us. */ static addr_policy_t *authdir_reject_policy = NULL; -/** DOCDOC */ +/** Policy that addresses for incoming router descriptors must match in order + * to be marked as valid in our networkstatus. */ static addr_policy_t *authdir_invalid_policy = NULL; -/** DOCDOC */ +/** Policy that addresses for incoming router descriptors must not + * match in order to not be marked as BadExit. */ static addr_policy_t *authdir_badexit_policy = NULL; /** Parsed addr_policy_t describing which addresses we believe we can start @@ -153,6 +156,7 @@ addr_policy_permits_address(uint32_t addr, uint16_t port, } } +/** DOCDOC */ int fascist_firewall_allows_address_or(uint32_t addr, uint16_t port) { @@ -160,6 +164,7 @@ fascist_firewall_allows_address_or(uint32_t addr, uint16_t port) reachable_or_addr_policy); } +/** DOCDOC */ int fascist_firewall_allows_address_dir(uint32_t addr, uint16_t port) { @@ -215,7 +220,9 @@ authdir_policy_badexit_address(uint32_t addr, uint16_t port) #define REJECT(arg) \ do { *msg = tor_strdup(arg); goto err; } while (0) -/** DOCDOC */ +/** Config helper: If there's any problem with the policy configuration + * options in options, return -1 and set msg to a newly + * allocated description of the error. Else return 0. */ int validate_addr_policies(or_options_t *options, char **msg) { @@ -273,7 +280,8 @@ load_policy_from_option(config_line_t *config, addr_policy_t **policy, } } -/** DOCDOC */ +/** Set all policies based on options, which should have been validated + * first. */ void policies_parse_from_options(or_options_t *options) { @@ -663,7 +671,8 @@ policy_write_item(char *buf, size_t buflen, addr_policy_t *policy) return (int)written; } -/** DOCDOC */ +/** Implementation for GETINFO control command: knows the answer for questions + * about "exit-policy/..." */ int getinfo_helper_policies(control_connection_t *conn, const char *question, char **answer) @@ -689,7 +698,7 @@ addr_policy_free(addr_policy_t *p) } } -/** DOCDOC */ +/** Release all storage held by policy variables. */ void policies_free_all(void) { diff --git a/src/or/rephist.c b/src/or/rephist.c index 8d8350968b..557a69b62c 100644 --- a/src/or/rephist.c +++ b/src/or/rephist.c @@ -956,7 +956,7 @@ static uint32_t n_rend_client_ops = 0; static uint32_t n_rend_mid_ops = 0; static uint32_t n_rend_server_ops = 0; -/** DOCDOC */ +/** Increment the count of the number of times we've done operation */ void note_crypto_pk_op(pk_op_t operation) { @@ -1000,7 +1000,7 @@ note_crypto_pk_op(pk_op_t operation) } } -/** DOCDOC */ +/** Log the number of times we've done each public/private-key operation. */ void dump_pk_ops(int severity) { diff --git a/src/or/routerlist.c b/src/or/routerlist.c index c45064d118..bfaf44dd2f 100644 --- a/src/or/routerlist.c +++ b/src/or/routerlist.c @@ -214,7 +214,9 @@ router_append_to_journal(signed_descriptor_t *desc) return 0; } -/** DOCDOC */ +/** Sorting helper: return <0, 0, or >0 depending on whether the + * signed_descriptor_t* in *a is older, the same age as, or newer than + * the signed_descriptor_t* in *b */ static int _compare_old_routers_by_age(const void **_a, const void **_b) { @@ -222,7 +224,9 @@ _compare_old_routers_by_age(const void **_a, const void **_b) return r1->published_on - r2->published_on; } -/** DOCDOC */ +/** Sorting helper: return <0, 0, or >0 depending on whether the + * routerinfo_t* in *a is older, the same age as, or newer than + * the routerinfo_t in *b */ static int _compare_routers_by_age(const void **_a, const void **_b) { @@ -924,7 +928,8 @@ router_get_advertised_bandwidth(routerinfo_t *router) return router->bandwidthrate; } -/** DOCDOC */ +/** Do not weight any declared bandwidth more than this much when picking + * routers by bandwidth. */ #define MAX_BELIEVABLE_BANDWIDTH 1500000 /* 1.5 MB/sec */ /** Helper function: @@ -1995,7 +2000,9 @@ router_add_to_routerlist(routerinfo_t *router, const char **msg, return 0; } -/** DOCDOC */ +/** Sorting helper: return <0, 0, or >0 depending on whether the + * signed_descriptor_t* in *a has an identity digest preceeding, equal + * to, or later than that of b. */ static int _compare_old_routers_by_identity(const void **_a, const void **_b) { @@ -2006,14 +2013,16 @@ _compare_old_routers_by_identity(const void **_a, const void **_b) return r1->published_on - r2->published_on; } -/** DOCDOC */ +/** Internal type used to represent how long an old descriptor was valid, + * where it appeared in the list of old descriptors, and whether it's extra + * old. Used only by routerlist_remove_old_cached_routers_with_id(). */ struct duration_idx_t { int duration; int idx; int old; }; -/** DOCDOC */ +/** Sorting helper: compare two duration_idx_t by their duration. */ static int _compare_duration_idx(const void *_d1, const void *_d2) { @@ -2620,7 +2629,10 @@ router_get_combined_status_by_digest(const char *digest) _compare_digest_to_routerstatus_entry); } -/** DOCDOC */ +/** Given a nickname (possibly verbose, possibly a hexadecimal digest), return + * the corresponding local_routerstatus_t, or NULL if none exists. Warn the + * user if warn_if_unnamed is set, and they have specified a router by + * nickname, but the Named flag isn't set for that router. */ static local_routerstatus_t * router_get_combined_status_by_nickname(const char *nickname, int warn_if_unnamed) @@ -4105,7 +4117,8 @@ update_router_descriptor_downloads(time_t now) } } -/** DOCDOC */ +/** Return the number of routerstatus_t in entries that we'd actually + * use. */ static int routerstatus_count_usable_entries(smartlist_t *entries) { @@ -4117,9 +4130,12 @@ routerstatus_count_usable_entries(smartlist_t *entries) return count; } -/** DOCDOC */ +/** True iff, the last time we checked whether we had enough directory info + * to build circuits, the answer was "yes". */ static int have_min_dir_info = 0; -/** DOCDOC */ +/** True iff enough has changes since the last time we checked whether we had + * enough directory info to build circuits that our old answer can no longer + * be trusted. */ static int need_to_update_have_min_dir_info = 1; /** Return true iff we have enough networkstatus and router information to diff --git a/src/or/routerparse.c b/src/or/routerparse.c index 4cea72fc2a..233bb3c209 100644 --- a/src/or/routerparse.c +++ b/src/or/routerparse.c @@ -709,7 +709,10 @@ router_parse_list_from_string(const char **s, smartlist_t *dest, static digestmap_t *verified_digests = NULL; #endif -/** DOCDOC */ +/** Log the total count of the number of distinct router digests we've ever + * verified. When compared to the number of times we've verified routerdesc + * signatures in toto, this will tell us if we're doing too much + * multiple-verification. */ void dump_distinct_digest_count(int severity) { @@ -1122,7 +1125,7 @@ _compare_routerstatus_entries(const void **_a, const void **_b) return memcmp(a->identity_digest, b->identity_digest, DIGEST_LEN); } -/** DOCDOC */ +/** Helper: used in call to _smartlist_uniq to clear out duplicate entries. */ static void _free_duplicate_routerstatus_entry(void *e) {