diff options
Diffstat (limited to 'src/or/directory.c')
-rw-r--r-- | src/or/directory.c | 612 |
1 files changed, 284 insertions, 328 deletions
diff --git a/src/or/directory.c b/src/or/directory.c index 91b5322bcf..3a3f3a0012 100644 --- a/src/or/directory.c +++ b/src/or/directory.c @@ -38,17 +38,16 @@ directory_initiate_command(const char *address, uint32_t addr, uint16_t port, const char *payload, size_t payload_len); static void -directory_send_command(dir_connection_t *conn, const char *platform, +directory_send_command(connection_t *conn, const char *platform, int purpose, const char *resource, const char *payload, size_t payload_len); -static int directory_handle_command(dir_connection_t *conn); +static int directory_handle_command(connection_t *conn); static int body_is_plausible(const char *body, size_t body_len, int purpose); static int purpose_is_private(uint8_t purpose); static char *http_get_header(const char *headers, const char *which); -static void http_set_address_origin(const char *headers, connection_t *conn); -static void connection_dir_download_networkstatus_failed( - dir_connection_t *conn); -static void connection_dir_download_routerdesc_failed(dir_connection_t *conn); +static char *http_get_origin(const char *headers, connection_t *conn); +static void connection_dir_download_networkstatus_failed(connection_t *conn); +static void connection_dir_download_routerdesc_failed(connection_t *conn); static void dir_networkstatus_download_failed(smartlist_t *failed); static void dir_routerdesc_download_failed(smartlist_t *failed); static void note_request(const char *key, size_t bytes); @@ -59,8 +58,6 @@ static void note_request(const char *key, size_t bytes); * before deciding that one of us has the wrong time? */ #define ALLOW_DIRECTORY_TIME_SKEW (30*60) -#define X_ADDRESS_HEADER "X-Your-Address-Is: " - /********* END VARIABLES ************/ /** Return true iff the directory purpose 'purpose' must use an @@ -241,7 +238,7 @@ directory_initiate_command_routerstatus(routerstatus_t *status, { const char *platform = NULL; routerinfo_t *router; - char address_buf[INET_NTOA_BUF_LEN+1]; + char address_buf[INET_NTOA_BUF_LEN]; struct in_addr in; const char *address; if ((router = router_get_by_digest(status->identity_digest))) { @@ -262,24 +259,24 @@ directory_initiate_command_routerstatus(routerstatus_t *status, * directory server: Mark the router as down and try again if possible. */ void -connection_dir_request_failed(dir_connection_t *conn) +connection_dir_request_failed(connection_t *conn) { if (router_digest_is_me(conn->identity_digest)) return; /* this was a test fetch. don't retry. */ router_set_status(conn->identity_digest, 0); /* don't try him again */ - if (conn->_base.purpose == DIR_PURPOSE_FETCH_DIR || - conn->_base.purpose == DIR_PURPOSE_FETCH_RUNNING_LIST) { + if (conn->purpose == DIR_PURPOSE_FETCH_DIR || + conn->purpose == DIR_PURPOSE_FETCH_RUNNING_LIST) { log_info(LD_DIR, "Giving up on directory server at '%s:%d'; retrying", - conn->_base.address, conn->_base.port); - directory_get_from_dirserver(conn->_base.purpose, NULL, + conn->address, conn->port); + directory_get_from_dirserver(conn->purpose, NULL, 0 /* don't retry_if_no_servers */); - } else if (conn->_base.purpose == DIR_PURPOSE_FETCH_NETWORKSTATUS) { + } else if (conn->purpose == DIR_PURPOSE_FETCH_NETWORKSTATUS) { log_info(LD_DIR, "Giving up on directory server at '%s'; retrying", - conn->_base.address); + conn->address); connection_dir_download_networkstatus_failed(conn); - } else if (conn->_base.purpose == DIR_PURPOSE_FETCH_SERVERDESC) { + } else if (conn->purpose == DIR_PURPOSE_FETCH_SERVERDESC) { log_info(LD_DIR, "Giving up on directory server at '%s'; retrying", - conn->_base.address); + conn->address); connection_dir_download_routerdesc_failed(conn); } } @@ -289,7 +286,7 @@ connection_dir_request_failed(dir_connection_t *conn) * retry the fetch now, later, or never. */ static void -connection_dir_download_networkstatus_failed(dir_connection_t *conn) +connection_dir_download_networkstatus_failed(connection_t *conn) { if (!conn->requested_resource) { /* We never reached directory_send_command, which means that we never @@ -302,14 +299,14 @@ connection_dir_download_networkstatus_failed(dir_connection_t *conn) smartlist_t *trusted_dirs = router_get_trusted_dir_servers(); SMARTLIST_FOREACH(trusted_dirs, trusted_dir_server_t *, ds, ++ds->n_networkstatus_failures); - directory_get_from_dirserver(conn->_base.purpose, "all.z", + directory_get_from_dirserver(conn->purpose, "all.z", 0 /* don't retry_if_no_servers */); } else if (!strcmpstart(conn->requested_resource, "fp/")) { /* We were trying to download by fingerprint; mark them all as having * failed, and possibly retry them later.*/ smartlist_t *failed = smartlist_create(); dir_split_resource_into_fingerprints(conn->requested_resource+3, - failed, NULL, 0, 0); + failed, NULL, 0); if (smartlist_len(failed)) { dir_networkstatus_download_failed(failed); SMARTLIST_FOREACH(failed, char *, cp, tor_free(cp)); @@ -322,13 +319,11 @@ connection_dir_download_networkstatus_failed(dir_connection_t *conn) * on connection <b>conn</b> failed. */ static void -connection_dir_download_routerdesc_failed(dir_connection_t *conn) +connection_dir_download_routerdesc_failed(connection_t *conn) { /* Try again. No need to increment the failure count for routerdescs, since * it's not their fault.*/ /* update_router_descriptor_downloads(time(NULL)); */ - (void) conn; - /* XXXX Why did the above get commented out? -NM */ } /** Helper for directory_initiate_command_(router|trusted_dir): send the @@ -343,7 +338,7 @@ directory_initiate_command(const char *address, uint32_t addr, int private_connection, const char *resource, const char *payload, size_t payload_len) { - dir_connection_t *conn; + connection_t *conn; tor_assert(address); tor_assert(addr); @@ -377,19 +372,18 @@ directory_initiate_command(const char *address, uint32_t addr, tor_assert(0); } - conn = TO_DIR_CONN(connection_new(CONN_TYPE_DIR)); + conn = connection_new(CONN_TYPE_DIR); /* set up conn so it's got all the data we need to remember */ - conn->_base.addr = addr; - conn->_base.port = dir_port; - conn->_base.address = tor_strdup(address); + conn->addr = addr; + conn->port = dir_port; + conn->address = tor_strdup(address); memcpy(conn->identity_digest, digest, DIGEST_LEN); - conn->_base.purpose = purpose; + conn->purpose = purpose; /* give it an initial state */ - conn->_base.state = DIR_CONN_STATE_CONNECTING; - conn->dirconn_direct = (private_connection == 0); + conn->state = DIR_CONN_STATE_CONNECTING; if (!private_connection) { /* then we want to connect directly */ @@ -399,21 +393,19 @@ directory_initiate_command(const char *address, uint32_t addr, dir_port = get_options()->HttpProxyPort; } - switch (connection_connect(TO_CONN(conn), conn->_base.address, addr, - dir_port)) { + switch (connection_connect(conn, conn->address, addr, dir_port)) { case -1: connection_dir_request_failed(conn); /* retry if we want */ - connection_free(TO_CONN(conn)); + connection_free(conn); return; case 1: - /* start flushing conn */ - conn->_base.state = DIR_CONN_STATE_CLIENT_SENDING; + conn->state = DIR_CONN_STATE_CLIENT_SENDING; /* start flushing conn */ /* fall through */ case 0: /* queue the command on the outbuf */ directory_send_command(conn, platform, purpose, resource, payload, payload_len); - connection_watch_events(TO_CONN(conn), EV_READ | EV_WRITE); + connection_watch_events(conn, EV_READ | EV_WRITE); /* writable indicates finish, readable indicates broken link, error indicates broken link in windowsland. */ } @@ -422,24 +414,23 @@ directory_initiate_command(const char *address, uint32_t addr, * populate it and add it at the right state * socketpair and hook up both sides */ - conn->_base.s = connection_ap_make_bridge(conn->_base.address, - conn->_base.port); - if (conn->_base.s < 0) { + conn->s = connection_ap_make_bridge(conn->address, conn->port); + if (conn->s < 0) { log_warn(LD_NET,"Making AP bridge to dirserver failed."); - connection_mark_for_close(TO_CONN(conn)); + connection_mark_for_close(conn); return; } - if (connection_add(TO_CONN(conn)) < 0) { + if (connection_add(conn) < 0) { log_warn(LD_NET,"Unable to add AP bridge to dirserver."); - connection_mark_for_close(TO_CONN(conn)); + connection_mark_for_close(conn); return; } - conn->_base.state = DIR_CONN_STATE_CLIENT_SENDING; + conn->state = DIR_CONN_STATE_CLIENT_SENDING; /* queue the command on the outbuf */ directory_send_command(conn, platform, purpose, resource, payload, payload_len); - connection_watch_events(TO_CONN(conn), EV_READ | EV_WRITE); + connection_watch_events(conn, EV_READ | EV_WRITE); } } @@ -447,7 +438,7 @@ directory_initiate_command(const char *address, uint32_t addr, * are as in directory_initiate_command. */ static void -directory_send_command(dir_connection_t *conn, const char *platform, +directory_send_command(connection_t *conn, const char *platform, int purpose, const char *resource, const char *payload, size_t payload_len) { @@ -460,18 +451,18 @@ directory_send_command(dir_connection_t *conn, const char *platform, size_t len; tor_assert(conn); - tor_assert(conn->_base.type == CONN_TYPE_DIR); + tor_assert(conn->type == CONN_TYPE_DIR); tor_free(conn->requested_resource); if (resource) conn->requested_resource = tor_strdup(resource); /* come up with a string for which Host: we want */ - if (conn->_base.port == 80) { - strlcpy(hoststring, conn->_base.address, sizeof(hoststring)); + if (conn->port == 80) { + strlcpy(hoststring, conn->address, sizeof(hoststring)); } else { tor_snprintf(hoststring, sizeof(hoststring),"%s:%d", - conn->_base.address, conn->_base.port); + conn->address, conn->port); } /* come up with some proxy lines, if we're using one. */ @@ -568,8 +559,8 @@ directory_send_command(dir_connection_t *conn, const char *platform, } tor_snprintf(request, sizeof(request), "%s %s", httpcommand, proxystring); - connection_write_to_buf(request, strlen(request), TO_CONN(conn)); - connection_write_to_buf(url, strlen(url), TO_CONN(conn)); + connection_write_to_buf(request, strlen(request), conn); + connection_write_to_buf(url, strlen(url), conn); tor_free(url); if (!strcmp(httpcommand, "GET") && !payload) { @@ -584,11 +575,11 @@ directory_send_command(dir_connection_t *conn, const char *platform, hoststring, proxyauthstring); } - connection_write_to_buf(request, strlen(request), TO_CONN(conn)); + connection_write_to_buf(request, strlen(request), conn); if (payload) { /* then send the payload afterwards too */ - connection_write_to_buf(payload, payload_len, TO_CONN(conn)); + connection_write_to_buf(payload, payload_len, conn); } } @@ -597,7 +588,7 @@ directory_send_command(dir_connection_t *conn, const char *platform, * "\%s [http[s]://]\%s HTTP/1..." * \endverbatim * If it's well-formed, strdup the second \%s into *<b>url</b>, and - * nul-terminate it. If the url doesn't start with "/tor/", rewrite it + * null-terminate it. If the url doesn't start with "/tor/", rewrite it * so it does. Return 0. * Otherwise, return -1. */ @@ -664,11 +655,12 @@ http_get_header(const char *headers, const char *which) return NULL; } -/** If <b>headers</b> indicates that a proxy was involved, then rewrite - * <b>conn</b>-\>address to describe our best guess of the address that - * originated this HTTP request. */ -static void -http_set_address_origin(const char *headers, connection_t *conn) +/** Allocate and return a string describing the source of an HTTP request with + * headers <b>headers</b> received on <b>conn</b>. The format is either + * "'1.2.3.4'", or "'1.2.3.4' (forwarded for '5.6.7.8')". + */ +static char * +http_get_origin(const char *headers, connection_t *conn) { char *fwd; @@ -676,9 +668,17 @@ http_set_address_origin(const char *headers, connection_t *conn) if (!fwd) fwd = http_get_header(headers, "X-Forwarded-For: "); if (fwd) { - tor_free(conn->address); - conn->address = tor_strdup(escaped(fwd)); + size_t len = strlen(fwd)+strlen(conn->address)+32; + char *result = tor_malloc(len); + tor_snprintf(result, len, "'%s' (forwarded for %s)", conn->address, + escaped(fwd)); tor_free(fwd); + return result; + } else { + size_t len = strlen(conn->address)+3; + char *result = tor_malloc(len); + tor_snprintf(result, len, "'%s'", conn->address); + return result; } } @@ -808,7 +808,7 @@ body_is_plausible(const char *body, size_t len, int purpose) * The caller will take care of marking the connection for close. */ static int -connection_dir_client_reached_eof(dir_connection_t *conn) +connection_dir_client_reached_eof(connection_t *conn) { char *body; char *headers; @@ -820,18 +820,17 @@ connection_dir_client_reached_eof(dir_connection_t *conn) int compression; int plausible; int skewed=0; - int allow_partial = conn->_base.purpose == DIR_PURPOSE_FETCH_SERVERDESC; + int allow_partial = conn->purpose == DIR_PURPOSE_FETCH_SERVERDESC; int was_compressed=0; - char *guess; - switch (fetch_from_buf_http(conn->_base.inbuf, + switch (fetch_from_buf_http(conn->inbuf, &headers, MAX_HEADERS_SIZE, &body, &body_len, MAX_DIR_SIZE, allow_partial)) { case -1: /* overflow */ log_warn(LD_PROTOCOL, "'fetch' response too large (server '%s:%d'). Closing.", - conn->_base.address, conn->_base.port); + conn->address, conn->port); return -1; case 0: log_info(LD_HTTP, @@ -844,7 +843,7 @@ connection_dir_client_reached_eof(dir_connection_t *conn) if (parse_http_response(headers, &status_code, &date_header, &compression, &reason) < 0) { log_warn(LD_HTTP,"Unparseable headers (server '%s:%d'). Closing.", - conn->_base.address, conn->_base.port); + conn->address, conn->port); tor_free(body); tor_free(headers); return -1; } @@ -852,15 +851,7 @@ connection_dir_client_reached_eof(dir_connection_t *conn) log_debug(LD_DIR, "Received response from directory server '%s:%d': %d %s", - conn->_base.address, conn->_base.port, status_code, - escaped(reason)); - - /* now check if it's got any hints for us about our IP address. */ - guess = http_get_header(headers, X_ADDRESS_HEADER); - if (guess) { - router_new_address_suggestion(guess); - tor_free(guess); - } + conn->address, conn->port, status_code, escaped(reason)); if (date_header > 0) { now = time(NULL); @@ -871,7 +862,7 @@ connection_dir_client_reached_eof(dir_connection_t *conn) LD_HTTP, "Received directory with skewed time (server '%s:%d'): " "we are %d minutes %s, or the directory is %d minutes %s.", - conn->_base.address, conn->_base.port, + conn->address, conn->port, abs(delta)/60, delta>0 ? "ahead" : "behind", abs(delta)/60, delta>0 ? "behind" : "ahead"); skewed = 1; /* don't check the recommended-versions line */ @@ -884,13 +875,12 @@ connection_dir_client_reached_eof(dir_connection_t *conn) if (status_code == 503) { log_info(LD_DIR,"Received http status code %d (%s) from server " "'%s:%d'. I'll try again soon.", - status_code, escaped(reason), conn->_base.address, - conn->_base.port); + status_code, escaped(reason), conn->address, conn->port); tor_free(body); tor_free(headers); tor_free(reason); return -1; } - plausible = body_is_plausible(body, body_len, conn->_base.purpose); + plausible = body_is_plausible(body, body_len, conn->purpose); if (compression || !plausible) { char *new_body = NULL; size_t new_len = 0; @@ -917,8 +907,7 @@ connection_dir_client_reached_eof(dir_connection_t *conn) log_info(LD_HTTP, "HTTP body from server '%s:%d' was labeled %s, " "but it seems to be %s.%s", - conn->_base.address, conn->_base.port, description1, - description2, + conn->address, conn->port, description1, description2, (compression>0 && guessed>0)?" Trying both.":""); } /* Try declared compression first if we can. */ @@ -935,7 +924,7 @@ connection_dir_client_reached_eof(dir_connection_t *conn) if (!plausible && !new_body) { log_fn(LOG_PROTOCOL_WARN, LD_HTTP, "Unable to decompress HTTP body (server '%s:%d').", - conn->_base.address, conn->_base.port); + conn->address, conn->port); tor_free(body); tor_free(headers); tor_free(reason); return -1; } @@ -947,40 +936,38 @@ connection_dir_client_reached_eof(dir_connection_t *conn) } } - if (conn->_base.purpose == DIR_PURPOSE_FETCH_DIR) { + if (conn->purpose == DIR_PURPOSE_FETCH_DIR) { /* fetch/process the directory to cache it. */ log_info(LD_DIR,"Received directory (size %d) from server '%s:%d'", - (int)body_len, conn->_base.address, conn->_base.port); + (int)body_len, conn->address, conn->port); if (status_code != 200) { log_warn(LD_DIR,"Received http status code %d (%s) from server " "'%s:%d'. I'll try again soon.", - status_code, escaped(reason), conn->_base.address, - conn->_base.port); + status_code, escaped(reason), conn->address, conn->port); tor_free(body); tor_free(headers); tor_free(reason); return -1; } if (router_parse_directory(body) < 0) { log_notice(LD_DIR,"I failed to parse the directory I fetched from " - "'%s:%d'. Ignoring.", conn->_base.address, conn->_base.port); + "'%s:%d'. Ignoring.", conn->address, conn->port); } note_request(was_compressed?"dl/dir.z":"dl/dir", orig_len); } - if (conn->_base.purpose == DIR_PURPOSE_FETCH_RUNNING_LIST) { + if (conn->purpose == DIR_PURPOSE_FETCH_RUNNING_LIST) { /* just update our list of running routers, if this list is new info */ log_info(LD_DIR,"Received running-routers list (size %d)", (int)body_len); if (status_code != 200) { log_warn(LD_DIR,"Received http status code %d (%s) from server " "'%s:%d'. I'll try again soon.", - status_code, escaped(reason), conn->_base.address, - conn->_base.port); + status_code, escaped(reason), conn->address, conn->port); tor_free(body); tor_free(headers); tor_free(reason); return -1; } if (router_parse_runningrouters(body)<0) { log_warn(LD_DIR, "Bad running-routers from server '%s:%d'. I'll try again soon.", - conn->_base.address, conn->_base.port); + conn->address, conn->port); tor_free(body); tor_free(headers); tor_free(reason); return -1; } @@ -988,18 +975,17 @@ connection_dir_client_reached_eof(dir_connection_t *conn) "dl/running-routers", orig_len); } - if (conn->_base.purpose == DIR_PURPOSE_FETCH_NETWORKSTATUS) { + if (conn->purpose == DIR_PURPOSE_FETCH_NETWORKSTATUS) { smartlist_t *which = NULL; - int source; char *cp; log_info(LD_DIR,"Received networkstatus objects (size %d) from server " - "'%s:%d'",(int) body_len, conn->_base.address, conn->_base.port); + "'%s:%d'",(int) body_len, conn->address, conn->port); if (status_code != 200) { log_warn(LD_DIR, "Received http status code %d (%s) from server " "'%s:%d' while fetching \"/tor/status/%s\". I'll try again soon.", - status_code, escaped(reason), conn->_base.address, - conn->_base.port, conn->requested_resource); + status_code, escaped(reason), conn->address, conn->port, + conn->requested_resource); tor_free(body); tor_free(headers); tor_free(reason); connection_dir_download_networkstatus_failed(conn); return -1; @@ -1007,13 +993,11 @@ connection_dir_client_reached_eof(dir_connection_t *conn) note_request(was_compressed?"dl/status.z":"dl/status", orig_len); if (conn->requested_resource && !strcmpstart(conn->requested_resource,"fp/")) { - source = NS_FROM_DIR_BY_FP; which = smartlist_create(); dir_split_resource_into_fingerprints(conn->requested_resource+3, - which, NULL, 0, 0); + which, NULL, 0); } else if (conn->requested_resource && !strcmpstart(conn->requested_resource, "all")) { - source = NS_FROM_DIR_ALL; which = smartlist_create(); SMARTLIST_FOREACH(router_get_trusted_dir_servers(), trusted_dir_server_t *, ds, @@ -1022,11 +1006,6 @@ connection_dir_client_reached_eof(dir_connection_t *conn) base16_encode(cp, HEX_DIGEST_LEN+1, ds->digest, DIGEST_LEN); smartlist_add(which, cp); }); - } else { - /* Can we even end up here? -- weasel*/ - source = NS_FROM_DIR_BY_FP; - log_warn(LD_BUG, "we received a networkstatus but we did neither ask" - "for it by fp/ nor did we ask for all."); } cp = body; while (*cp) { @@ -1034,7 +1013,7 @@ connection_dir_client_reached_eof(dir_connection_t *conn) if (next) next[1] = '\0'; /* learn from it, and then remove it from 'which' */ - if (router_set_networkstatus(cp, time(NULL), source, which)<0) + if (router_set_networkstatus(cp, time(NULL), NS_FROM_DIR, which)<0) break; if (next) { next[1] = 'n'; @@ -1054,17 +1033,17 @@ connection_dir_client_reached_eof(dir_connection_t *conn) } } - if (conn->_base.purpose == DIR_PURPOSE_FETCH_SERVERDESC) { + if (conn->purpose == DIR_PURPOSE_FETCH_SERVERDESC) { smartlist_t *which = NULL; int n_asked_for = 0; log_info(LD_DIR,"Received server info (size %d) from server '%s:%d'", - (int)body_len, conn->_base.address, conn->_base.port); + (int)body_len, conn->address, conn->port); note_request(was_compressed?"dl/server.z":"dl/server", orig_len); if (conn->requested_resource && !strcmpstart(conn->requested_resource,"d/")) { which = smartlist_create(); dir_split_resource_into_fingerprints(conn->requested_resource+2, - which, NULL, 0, 0); + which, NULL, 0); n_asked_for = smartlist_len(which); } if (status_code != 200) { @@ -1075,8 +1054,8 @@ connection_dir_client_reached_eof(dir_connection_t *conn) log_fn(dir_okay ? LOG_INFO : LOG_WARN, LD_DIR, "Received http status code %d (%s) from server '%s:%d' " "while fetching \"/tor/server/%s\". I'll try again soon.", - status_code, escaped(reason), conn->_base.address, - conn->_base.port, conn->requested_resource); + status_code, escaped(reason), conn->address, conn->port, + conn->requested_resource); if (!which) { connection_dir_download_routerdesc_failed(conn); } else { @@ -1095,13 +1074,13 @@ connection_dir_client_reached_eof(dir_connection_t *conn) 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, SAVED_NOWHERE, which); + router_load_routers_from_string(body, 0, which); directory_info_has_arrived(time(NULL), 0); } if (which) { /* mark remaining ones as failed */ log_info(LD_DIR, "Received %d/%d routers requested from %s:%d", n_asked_for-smartlist_len(which), n_asked_for, - conn->_base.address, (int)conn->_base.port); + conn->address, (int)conn->port); if (smartlist_len(which)) { dir_routerdesc_download_failed(which); } @@ -1114,13 +1093,13 @@ connection_dir_client_reached_eof(dir_connection_t *conn) routerinfo_t *me = router_get_my_routerinfo(); if (me && router_digest_is_me(conn->identity_digest) && - me->addr == conn->_base.addr && - me->dir_port == conn->_base.port) + me->addr == conn->addr && + me->dir_port == conn->port) router_dirport_found_reachable(); } } - if (conn->_base.purpose == DIR_PURPOSE_UPLOAD_DIR) { + if (conn->purpose == DIR_PURPOSE_UPLOAD_DIR) { switch (status_code) { case 200: log_info(LD_GENERAL,"eof (status 200) after uploading server " @@ -1129,7 +1108,7 @@ connection_dir_client_reached_eof(dir_connection_t *conn) case 400: log_warn(LD_GENERAL,"http status 400 (%s) response from " "dirserver '%s:%d'. Please correct.", - escaped(reason), conn->_base.address, conn->_base.port); + escaped(reason), conn->address, conn->port); break; case 403: log_warn(LD_GENERAL, @@ -1137,21 +1116,19 @@ connection_dir_client_reached_eof(dir_connection_t *conn) "'%s:%d'. Is your clock skewed? Have you mailed us your key " "fingerprint? Are you using the right key? Are you using a " "private IP address? See http://tor.eff.org/doc/" - "tor-doc-server.html",escaped(reason), conn->_base.address, - conn->_base.port); + "tor-doc-server.html",escaped(reason), conn->address, conn->port); break; default: log_warn(LD_GENERAL, "http status %d (%s) reason unexpected (server '%s:%d').", - status_code, escaped(reason), conn->_base.address, - conn->_base.port); + status_code, escaped(reason), conn->address, conn->port); break; } /* return 0 in all cases, since we don't want to mark any * dirservers down just because they don't like us. */ } - if (conn->_base.purpose == DIR_PURPOSE_FETCH_RENDDESC) { + if (conn->purpose == DIR_PURPOSE_FETCH_RENDDESC) { log_info(LD_REND,"Received rendezvous descriptor (size %d, status %d " "(%s))", (int)body_len, status_code, escaped(reason)); @@ -1163,7 +1140,7 @@ connection_dir_client_reached_eof(dir_connection_t *conn) * cleans it up */ } else { /* success. notify pending connections about this. */ - conn->_base.purpose = DIR_PURPOSE_HAS_FETCHED_RENDDESC; + conn->purpose = DIR_PURPOSE_HAS_FETCHED_RENDDESC; rend_client_desc_here(conn->rend_query); } break; @@ -1179,13 +1156,12 @@ connection_dir_client_reached_eof(dir_connection_t *conn) default: log_warn(LD_REND,"http status %d (%s) response unexpected (server " "'%s:%d').", - status_code, escaped(reason), conn->_base.address, - conn->_base.port); + status_code, escaped(reason), conn->address, conn->port); break; } } - if (conn->_base.purpose == DIR_PURPOSE_UPLOAD_RENDDESC) { + if (conn->purpose == DIR_PURPOSE_UPLOAD_RENDDESC) { switch (status_code) { case 200: log_info(LD_REND, @@ -1195,13 +1171,12 @@ connection_dir_client_reached_eof(dir_connection_t *conn) case 400: log_warn(LD_REND,"http status 400 (%s) response from dirserver " "'%s:%d'. Malformed rendezvous descriptor?", - escaped(reason), conn->_base.address, conn->_base.port); + escaped(reason), conn->address, conn->port); break; default: log_warn(LD_REND,"http status %d (%s) response unexpected (server " "'%s:%d').", - status_code, escaped(reason), conn->_base.address, - conn->_base.port); + status_code, escaped(reason), conn->address, conn->port); break; } } @@ -1211,20 +1186,20 @@ connection_dir_client_reached_eof(dir_connection_t *conn) /** Called when a directory connection reaches EOF */ int -connection_dir_reached_eof(dir_connection_t *conn) +connection_dir_reached_eof(connection_t *conn) { int retval; - if (conn->_base.state != DIR_CONN_STATE_CLIENT_READING) { + if (conn->state != DIR_CONN_STATE_CLIENT_READING) { log_info(LD_HTTP,"conn reached eof, not reading. Closing."); - connection_close_immediate(TO_CONN(conn)); /* error: give up on flushing */ - connection_mark_for_close(TO_CONN(conn)); + connection_close_immediate(conn); /* error: give up on flushing */ + connection_mark_for_close(conn); return -1; } retval = connection_dir_client_reached_eof(conn); if (retval == 0) /* success */ - conn->_base.state = DIR_CONN_STATE_CLIENT_FINISHED; - connection_mark_for_close(TO_CONN(conn)); + conn->state = DIR_CONN_STATE_CLIENT_FINISHED; + connection_mark_for_close(conn); return retval; } @@ -1232,10 +1207,10 @@ connection_dir_reached_eof(dir_connection_t *conn) * directory servers and connections <em>at</em> directory servers.) */ int -connection_dir_process_inbuf(dir_connection_t *conn) +connection_dir_process_inbuf(connection_t *conn) { tor_assert(conn); - tor_assert(conn->_base.type == CONN_TYPE_DIR); + tor_assert(conn->type == CONN_TYPE_DIR); /* Directory clients write, then read data until they receive EOF; * directory servers read data until they get an HTTP command, then @@ -1244,9 +1219,9 @@ connection_dir_process_inbuf(dir_connection_t *conn) */ /* If we're on the dirserver side, look for a command. */ - if (conn->_base.state == DIR_CONN_STATE_SERVER_COMMAND_WAIT) { + if (conn->state == DIR_CONN_STATE_SERVER_COMMAND_WAIT) { if (directory_handle_command(conn) < 0) { - connection_mark_for_close(TO_CONN(conn)); + connection_mark_for_close(conn); return -1; } return 0; @@ -1254,7 +1229,7 @@ connection_dir_process_inbuf(dir_connection_t *conn) /* XXX for READ states, might want to make sure inbuf isn't too big */ - if (!conn->_base.inbuf_reached_eof) + if (!conn->inbuf_reached_eof) log_debug(LD_HTTP,"Got data, not eof. Leaving on inbuf."); return 0; } @@ -1263,7 +1238,7 @@ connection_dir_process_inbuf(dir_connection_t *conn) * <b>status</b> and <b>reason_phrase</b>. Write it to <b>conn</b>. */ static void -write_http_status_line(dir_connection_t *conn, int status, +write_http_status_line(connection_t *conn, int status, const char *reason_phrase) { char buf[256]; @@ -1272,43 +1247,7 @@ write_http_status_line(dir_connection_t *conn, int status, log_warn(LD_BUG,"Bug: status line too long."); return; } - connection_write_to_buf(buf, strlen(buf), TO_CONN(conn)); -} - -/** DOCDOC */ -static void -write_http_response_header(dir_connection_t *conn, ssize_t length, - const char *type, const char *encoding) -{ - char date[RFC1123_TIME_LEN+1]; - char tmp[1024]; - char *cp; - - tor_assert(conn); - tor_assert(type); - - format_rfc1123_time(date, time(NULL)); - cp = tmp; - tor_snprintf(cp, sizeof(tmp), - "HTTP/1.0 200 OK\r\nDate: %s\r\nContent-Type: %s\r\n" - X_ADDRESS_HEADER "%s\r\n", - date, type, conn->_base.address); - cp += strlen(tmp); - if (encoding) { - tor_snprintf(cp, sizeof(tmp)-(cp-tmp), - "Content-Encoding: %s\r\n", encoding); - cp += strlen(cp); - } - if (length >= 0) { - tor_snprintf(cp, sizeof(tmp)-(cp-tmp), - "Content-Length: %ld\r\n", (long)length); - cp += strlen(cp); - } - if (sizeof(tmp)-(cp-tmp) > 3) - memcpy(cp, "\r\n", 3); - else - tor_assert(0); - connection_write_to_buf(tmp, strlen(tmp), TO_CONN(conn)); + connection_write_to_buf(buf, strlen(buf), conn); } /** Helper function: return 1 if there are any dir conns of purpose @@ -1328,7 +1267,7 @@ already_fetching_directory(int purpose) if (conn->type == CONN_TYPE_DIR && conn->purpose == purpose && !conn->marked_for_close && - !router_digest_is_me(TO_DIR_CONN(conn)->identity_digest)) + !router_digest_is_me(conn->identity_digest)) return 1; } return 0; @@ -1392,8 +1331,7 @@ directory_dump_request_log(void) static void note_request(const char *key, size_t bytes) { - (void)key; - (void)bytes; + return; } char * @@ -1409,19 +1347,18 @@ directory_dump_request_log(void) * conn-\>outbuf. If the request is unrecognized, send a 400. * Always return 0. */ static int -directory_handle_command_get(dir_connection_t *conn, char *headers, +directory_handle_command_get(connection_t *conn, char *headers, char *body, size_t body_len) { size_t dlen; const char *cp; char *url = NULL; - /* We ignore the body of a GET request. */ - (void)body; - (void)body_len; + char tmp[8192]; + char date[RFC1123_TIME_LEN+1]; log_debug(LD_DIRSERV,"Received GET command."); - conn->_base.state = DIR_CONN_STATE_SERVER_WRITING; + conn->state = DIR_CONN_STATE_SERVER_WRITING; if (parse_http_url(headers, &url) < 0) { write_http_status_line(conn, 400, "Bad request"); @@ -1431,9 +1368,9 @@ directory_handle_command_get(dir_connection_t *conn, char *headers, if (!strcmp(url,"/tor/") || !strcmp(url,"/tor/dir.z")) { /* dir fetch */ int deflated = !strcmp(url,"/tor/dir.z"); - cached_dir_t *d = dirserv_get_directory(); + dlen = dirserv_get_directory(&cp, deflated); - if (!d) { + if (dlen == 0) { log_notice(LD_DIRSERV,"Client asked for the mirrored directory, but we " "don't have a good one yet. Sending 503 Dir not available."); write_http_status_line(conn, 503, "Directory unavailable"); @@ -1443,7 +1380,6 @@ directory_handle_command_get(dir_connection_t *conn, char *headers, tor_free(url); return 0; } - dlen = deflated ? d->dir_z_len : d->dir_len; if (global_write_bucket_empty()) { log_info(LD_DIRSERV, @@ -1459,18 +1395,16 @@ directory_handle_command_get(dir_connection_t *conn, char *headers, log_debug(LD_DIRSERV,"Dumping %sdirectory to client.", deflated?"deflated ":""); - write_http_response_header(conn, dlen, - deflated?"application/octet-stream":"text/plain", - deflated?"deflate":"identity"); - conn->cached_dir = d; - conn->cached_dir_offset = 0; - if (! deflated) - conn->zlib_state = tor_zlib_new(0, ZLIB_METHOD); - ++d->refcnt; - - /* Prime the connection with some data. */ - conn->dir_spool_src = DIR_SPOOL_CACHED_DIR; - connection_dirserv_flushed_some(conn); + format_rfc1123_time(date, time(NULL)); + tor_snprintf(tmp, sizeof(tmp), + "HTTP/1.0 200 OK\r\nDate: %s\r\nContent-Length: %d\r\n" + "Content-Type: %s\r\nContent-Encoding: %s\r\n\r\n", + date, + (int)dlen, + deflated?"application/octet-stream":"text/plain", + deflated?"deflate":"identity"); + connection_write_to_buf(tmp, strlen(tmp), conn); + connection_write_to_buf(cp, dlen, conn); return 0; } @@ -1488,10 +1422,16 @@ directory_handle_command_get(dir_connection_t *conn, char *headers, return 0; } - write_http_response_header(conn, dlen, + format_rfc1123_time(date, time(NULL)); + tor_snprintf(tmp, sizeof(tmp), + "HTTP/1.0 200 OK\r\nDate: %s\r\nContent-Length: %d\r\n" + "Content-Type: %s\r\nContent-Encoding: %s\r\n\r\n", + date, + (int)dlen, deflated?"application/octet-stream":"text/plain", deflated?"deflate":"identity"); - connection_write_to_buf(cp, strlen(cp), TO_CONN(conn)); + connection_write_to_buf(tmp, strlen(tmp), conn); + connection_write_to_buf(cp, strlen(cp), conn); return 0; } @@ -1499,12 +1439,12 @@ directory_handle_command_get(dir_connection_t *conn, char *headers, /* v2 network status fetch. */ size_t url_len = strlen(url); int deflated = !strcmp(url+url_len-2, ".z"); - smartlist_t *dir_fps = smartlist_create(); + smartlist_t *dir_objs = smartlist_create(); const char *request_type = NULL; const char *key = url + strlen("/tor/status/"); if (deflated) url[url_len-2] = '\0'; - dirserv_get_networkstatus_v2_fingerprints(dir_fps, key); + dirserv_get_networkstatus_v2(dir_objs, key); if (!strcmpstart(key, "fp/")) request_type = deflated?"/tor/status/fp.z":"/tor/status/fp"; else if (!strcmpstart(key, "authority")) @@ -1515,24 +1455,32 @@ directory_handle_command_get(dir_connection_t *conn, char *headers, else request_type = "/tor/status/?"; tor_free(url); - if (!smartlist_len(dir_fps)) { /* we failed to create/cache cp */ + if (!smartlist_len(dir_objs)) { /* we failed to create/cache cp */ write_http_status_line(conn, 503, "Network status object unavailable"); - smartlist_free(dir_fps); + smartlist_free(dir_objs); return 0; } - // note_request(request_type,dlen); - write_http_response_header(conn, -1, - deflated?"application/octet_stream":"text/plain", - deflated?"deflate":NULL); - - conn->fingerprint_stack = dir_fps; - if (! deflated) - conn->zlib_state = tor_zlib_new(0, ZLIB_METHOD); - - /* Prime the connection with some data. */ - conn->dir_spool_src = DIR_SPOOL_NETWORKSTATUS; - connection_dirserv_flushed_some(conn); - + dlen = 0; + SMARTLIST_FOREACH(dir_objs, cached_dir_t *, d, + dlen += deflated?d->dir_z_len:d->dir_len); + note_request(request_type,dlen); + format_rfc1123_time(date, time(NULL)); + tor_snprintf(tmp, sizeof(tmp), + "HTTP/1.0 200 OK\r\nDate: %s\r\nContent-Length: %d\r\n" + "Content-Type: %s\r\nContent-Encoding: %s\r\n\r\n", + date, + (int)dlen, + deflated?"application/octet-stream":"text/plain", + deflated?"deflate":"identity"); + connection_write_to_buf(tmp, strlen(tmp), conn); + SMARTLIST_FOREACH(dir_objs, cached_dir_t *, d, + { + if (deflated) + connection_write_to_buf(d->dir_z, d->dir_z_len, conn); + else + connection_write_to_buf(d->dir, d->dir_len, conn); + }); + smartlist_free(dir_objs); return 0; } @@ -1541,12 +1489,11 @@ directory_handle_command_get(dir_connection_t *conn, char *headers, int deflated = !strcmp(url+url_len-2, ".z"); int res; const char *msg; + smartlist_t *descs = smartlist_create(); const char *request_type = NULL; if (deflated) url[url_len-2] = '\0'; - conn->fingerprint_stack = smartlist_create(); - res = dirserv_get_routerdesc_fingerprints(conn->fingerprint_stack, url, - &msg); + res = dirserv_get_routerdescs(descs, url, &msg); if (!strcmpstart(url, "/tor/server/fp/")) request_type = deflated?"/tor/server/fp.z":"/tor/server/fp"; @@ -1559,22 +1506,62 @@ directory_handle_command_get(dir_connection_t *conn, char *headers, request_type = deflated?"/tor/server/d.z":"/tor/server/d"; else request_type = "/tor/server/?"; - if (!strcmpstart(url, "/tor/server/d/")) - conn->dir_spool_src = DIR_SPOOL_SERVER_BY_DIGEST; - else - conn->dir_spool_src = DIR_SPOOL_SERVER_BY_FP; tor_free(url); if (res < 0) write_http_status_line(conn, 404, msg); else { - write_http_response_header(conn, -1, - deflated?"application/octet_stream":"text/plain", - deflated?"deflate":NULL); - if (deflated) - conn->zlib_state = tor_zlib_new(1, ZLIB_METHOD); - /* Prime the connection with some data. */ - connection_dirserv_flushed_some(conn); + size_t len = 0; + format_rfc1123_time(date, time(NULL)); + SMARTLIST_FOREACH(descs, signed_descriptor_t *, ri, + len += ri->signed_descriptor_len); + if (deflated) { + size_t compressed_len; + char *compressed; + char *inp = tor_malloc(len+smartlist_len(descs)+1); + char *cp = inp; + SMARTLIST_FOREACH(descs, signed_descriptor_t *, ri, + { + const char *body = signed_descriptor_get_body(ri); + memcpy(cp, body, ri->signed_descriptor_len); + cp += ri->signed_descriptor_len; + *cp++ = '\n'; + }); + *cp = '\0'; + /* XXXX This could be way more efficiently handled; let's see if it + * shows up under oprofile. */ + if (tor_gzip_compress(&compressed, &compressed_len, + inp, cp-inp, ZLIB_METHOD)<0) { + tor_free(inp); + smartlist_free(descs); + return -1; + } + tor_free(inp); + tor_snprintf(tmp, sizeof(tmp), + "HTTP/1.0 200 OK\r\nDate: %s\r\nContent-Length: %d\r\n" + "Content-Type: application/octet-stream\r\n" + "Content-Encoding: deflate\r\n\r\n", + date, + (int)compressed_len); + note_request(request_type, compressed_len); + connection_write_to_buf(tmp, strlen(tmp), conn); + connection_write_to_buf(compressed, compressed_len, conn); + tor_free(compressed); + } else { + tor_snprintf(tmp, sizeof(tmp), + "HTTP/1.0 200 OK\r\nDate: %s\r\nContent-Length: %d\r\n" + "Content-Type: text/plain\r\n\r\n", + date, + (int)len); + note_request(request_type, len); + connection_write_to_buf(tmp, strlen(tmp), conn); + SMARTLIST_FOREACH(descs, signed_descriptor_t *, ri, + { + const char *body = signed_descriptor_get_body(ri); + connection_write_to_buf(body, ri->signed_descriptor_len, conn); + }); + } } + smartlist_free(descs); return 0; } @@ -1599,11 +1586,16 @@ directory_handle_command_get(dir_connection_t *conn, char *headers, } switch (rend_cache_lookup_desc(query, versioned?-1:0, &descp, &desc_len)) { case 1: /* valid */ - write_http_response_header(conn, desc_len, "application/octet-stream", - NULL); + format_rfc1123_time(date, time(NULL)); + tor_snprintf(tmp, sizeof(tmp), + "HTTP/1.0 200 OK\r\nDate: %s\r\nContent-Length: %d\r\n" + "Content-Type: application/octet-stream\r\n\r\n", + date, + (int)desc_len); note_request("/tor/rendezvous?/", desc_len); + connection_write_to_buf(tmp, strlen(tmp), conn); /* need to send descp separately, because it may include nuls */ - connection_write_to_buf(descp, desc_len, TO_CONN(conn)); + connection_write_to_buf(descp, desc_len, conn); break; case 0: /* well-formed but not present */ write_http_status_line(conn, 404, "Not found"); @@ -1619,8 +1611,14 @@ directory_handle_command_get(dir_connection_t *conn, char *headers, if (!strcmpstart(url,"/tor/bytes.txt")) { char *bytes = directory_dump_request_log(); size_t len = strlen(bytes); - write_http_response_header(conn, len, "text/plain", NULL); - connection_write_to_buf(bytes, len, TO_CONN(conn)); + format_rfc1123_time(date, time(NULL)); + tor_snprintf(tmp, sizeof(tmp), + "HTTP/1.0 200 OK\r\nDate: %s\r\nContent-Length: %d\r\n" + "Content-Type: text/plain\r\n\r\n", + date, + (int)len); + connection_write_to_buf(tmp, strlen(tmp), conn); + connection_write_to_buf(bytes, len, conn); tor_free(bytes); tor_free(url); return 0; @@ -1630,32 +1628,14 @@ directory_handle_command_get(dir_connection_t *conn, char *headers, rewritten to /tor/robots.txt */ char robots[] = "User-agent: *\r\nDisallow: /\r\n"; size_t len = strlen(robots); - write_http_response_header(conn, len, "text/plain", NULL); - connection_write_to_buf(robots, len, TO_CONN(conn)); - tor_free(url); - return 0; - } - - if (!strcmp(url,"/tor/dir-all-weaselhack") && - (conn->_base.addr == 0x7f000001ul) && - authdir_mode(get_options())) { - /* XXX until weasel rewrites his scripts XXXX012 */ - char *new_directory=NULL; - - if (dirserv_dump_directory_to_string(&new_directory, - get_identity_key(), 1)) { - log_warn(LD_BUG, "Error creating full v1 directory."); - tor_free(new_directory); - write_http_status_line(conn, 503, "Directory unavailable"); - return 0; - } - - dlen = strlen(new_directory); - - write_http_response_header(conn, dlen, "text/plain", "identity"); - - connection_write_to_buf(new_directory, dlen, TO_CONN(conn)); - tor_free(new_directory); + format_rfc1123_time(date, time(NULL)); + tor_snprintf(tmp, sizeof(tmp), + "HTTP/1.0 200 OK\r\nDate: %s\r\nContent-Length: %d\r\n" + "Content-Type: text/plain\r\n\r\n", + date, + (int)len); + connection_write_to_buf(tmp, strlen(tmp), conn); + connection_write_to_buf(robots, len, conn); tor_free(url); return 0; } @@ -1672,14 +1652,16 @@ directory_handle_command_get(dir_connection_t *conn, char *headers, * response into conn-\>outbuf. If the request is unrecognized, send a * 400. Always return 0. */ static int -directory_handle_command_post(dir_connection_t *conn, char *headers, +directory_handle_command_post(connection_t *conn, char *headers, char *body, size_t body_len) { + const char *cp; + char *origin = NULL; char *url = NULL; log_debug(LD_DIRSERV,"Received POST command."); - conn->_base.state = DIR_CONN_STATE_SERVER_WRITING; + conn->state = DIR_CONN_STATE_SERVER_WRITING; if (!authdir_mode(get_options())) { /* we just provide cached directories; we don't want to @@ -1694,19 +1676,19 @@ directory_handle_command_post(dir_connection_t *conn, char *headers, return 0; } log_debug(LD_DIRSERV,"rewritten url as '%s'.", url); + origin = http_get_origin(headers, conn); if (!strcmp(url,"/tor/")) { /* server descriptor post */ const char *msg; int r = dirserv_add_descriptor(body, &msg); tor_assert(msg); if (r > 0) - dirserv_get_directory(); /* rebuild and write to disk */ + dirserv_get_directory(&cp, 0); /* rebuild and write to disk */ switch (r) { case -2: case -1: case 1: - log_notice(LD_DIRSERV,"Rejected router descriptor from %s.", - conn->_base.address); + log_notice(LD_DIRSERV,"Rejected router descriptor from %s.", origin); /* malformed descriptor, or something wrong */ write_http_status_line(conn, 400, msg); break; @@ -1724,7 +1706,7 @@ directory_handle_command_post(dir_connection_t *conn, char *headers, // char tmp[1024*2+1]; log_fn(LOG_PROTOCOL_WARN, LD_DIRSERV, "Rejected rend descriptor (length %d) from %s.", - (int)body_len, conn->_base.address); + (int)body_len, origin); #if 0 if (body_len <= 1024) { base16_encode(tmp, sizeof(tmp), body, body_len); @@ -1743,6 +1725,7 @@ directory_handle_command_post(dir_connection_t *conn, char *headers, done: tor_free(url); + tor_free(origin); return 0; } @@ -1752,22 +1735,21 @@ directory_handle_command_post(dir_connection_t *conn, char *headers, * buffer. Return a 0 on success, or -1 on error. */ static int -directory_handle_command(dir_connection_t *conn) +directory_handle_command(connection_t *conn) { char *headers=NULL, *body=NULL; size_t body_len=0; int r; tor_assert(conn); - tor_assert(conn->_base.type == CONN_TYPE_DIR); + tor_assert(conn->type == CONN_TYPE_DIR); - switch (fetch_from_buf_http(conn->_base.inbuf, + switch (fetch_from_buf_http(conn->inbuf, &headers, MAX_HEADERS_SIZE, &body, &body_len, MAX_BODY_SIZE, 0)) { case -1: /* overflow */ log_warn(LD_DIRSERV, - "Invalid input from address '%s'. Closing.", - conn->_base.address); + "Invalid input from address '%s'. Closing.", conn->address); return -1; case 0: log_debug(LD_DIRSERV,"command not all here yet."); @@ -1775,7 +1757,6 @@ directory_handle_command(dir_connection_t *conn) /* case 1, fall through */ } - http_set_address_origin(headers, TO_CONN(conn)); //log_debug(LD_DIRSERV,"headers %s, body %s.", headers, body); if (!strncasecmp(headers,"GET",3)) @@ -1798,24 +1779,23 @@ directory_handle_command(dir_connection_t *conn) * appropriate. */ int -connection_dir_finished_flushing(dir_connection_t *conn) +connection_dir_finished_flushing(connection_t *conn) { tor_assert(conn); - tor_assert(conn->_base.type == CONN_TYPE_DIR); + tor_assert(conn->type == CONN_TYPE_DIR); - switch (conn->_base.state) { + switch (conn->state) { case DIR_CONN_STATE_CLIENT_SENDING: log_debug(LD_DIR,"client finished sending command."); - conn->_base.state = DIR_CONN_STATE_CLIENT_READING; - connection_stop_writing(TO_CONN(conn)); + conn->state = DIR_CONN_STATE_CLIENT_READING; + connection_stop_writing(conn); return 0; case DIR_CONN_STATE_SERVER_WRITING: log_debug(LD_DIRSERV,"Finished writing server response. Closing."); - connection_mark_for_close(TO_CONN(conn)); + connection_mark_for_close(conn); return 0; default: - log_warn(LD_BUG,"Bug: called in unexpected state %d.", - conn->_base.state); + log_warn(LD_BUG,"Bug: called in unexpected state %d.", conn->state); tor_fragile_assert(); return -1; } @@ -1825,16 +1805,16 @@ connection_dir_finished_flushing(dir_connection_t *conn) /** Connected handler for directory connections: begin sending data to the * server */ int -connection_dir_finished_connecting(dir_connection_t *conn) +connection_dir_finished_connecting(connection_t *conn) { tor_assert(conn); - tor_assert(conn->_base.type == CONN_TYPE_DIR); - tor_assert(conn->_base.state == DIR_CONN_STATE_CONNECTING); + tor_assert(conn->type == CONN_TYPE_DIR); + tor_assert(conn->state == DIR_CONN_STATE_CONNECTING); log_debug(LD_HTTP,"Dir connection to router %s:%u established.", - conn->_base.address,conn->_base.port); + conn->address,conn->port); - conn->_base.state = DIR_CONN_STATE_CLIENT_SENDING; /* start flushing conn */ + conn->state = DIR_CONN_STATE_CLIENT_SENDING; /* start flushing conn */ return 0; } @@ -1912,21 +1892,21 @@ dir_routerdesc_download_failed(smartlist_t *failed) * the strings, in order, into <b>fp_out</b>. If <b>compressed_out</b> is * non-NULL, set it to 1 if the resource ends in ".z", else set it to 0. If * decode_hex is true, then delete all elements that aren't hex digests, and - * decode the rest. If sort_uniq is true, then sort the list and remove - * all duplicates. + * decode the rest. */ int dir_split_resource_into_fingerprints(const char *resource, smartlist_t *fp_out, int *compressed_out, - int decode_hex, int sort_uniq) + int decode_hex) { - smartlist_t *fp_tmp = smartlist_create(); + int old_len; tor_assert(fp_out); - smartlist_split_string(fp_tmp, resource, "+", 0, 0); + old_len = smartlist_len(fp_out); + smartlist_split_string(fp_out, resource, "+", 0, 0); if (compressed_out) *compressed_out = 0; - if (smartlist_len(fp_tmp)) { - char *last = smartlist_get(fp_tmp,smartlist_len(fp_tmp)-1); + if (smartlist_len(fp_out) > old_len) { + char *last = smartlist_get(fp_out,smartlist_len(fp_out)-1); size_t last_len = strlen(last); if (last_len > 2 && !strcmp(last+last_len-2, ".z")) { last[last_len-2] = '\0'; @@ -1937,51 +1917,27 @@ dir_split_resource_into_fingerprints(const char *resource, if (decode_hex) { int i; char *cp, *d = NULL; - for (i = 0; i < smartlist_len(fp_tmp); ++i) { - cp = smartlist_get(fp_tmp, i); + for (i = old_len; i < smartlist_len(fp_out); ++i) { + cp = smartlist_get(fp_out, i); if (strlen(cp) != HEX_DIGEST_LEN) { log_info(LD_DIR, "Skipping digest %s with non-standard length.", escaped(cp)); - smartlist_del_keeporder(fp_tmp, i--); + smartlist_del(fp_out, i--); goto again; } d = tor_malloc_zero(DIGEST_LEN); if (base16_decode(d, DIGEST_LEN, cp, HEX_DIGEST_LEN)<0) { log_info(LD_DIR, "Skipping non-decodable digest %s", escaped(cp)); - smartlist_del_keeporder(fp_tmp, i--); + smartlist_del(fp_out, i--); goto again; } - smartlist_set(fp_tmp, i, d); + smartlist_set(fp_out, i, d); d = NULL; again: tor_free(cp); tor_free(d); } } - if (sort_uniq) { - smartlist_t *fp_tmp2 = smartlist_create(); - int i; - if (decode_hex) - smartlist_sort_digests(fp_tmp); - else - smartlist_sort_strings(fp_tmp); - if (smartlist_len(fp_tmp)) - smartlist_add(fp_tmp2, smartlist_get(fp_tmp, 0)); - for (i = 1; i < smartlist_len(fp_tmp); ++i) { - char *cp = smartlist_get(fp_tmp, i); - char *last = smartlist_get(fp_tmp2, smartlist_len(fp_tmp2)-1); - - if ((decode_hex && memcmp(cp, last, DIGEST_LEN)) - || (!decode_hex && strcasecmp(cp, last))) - smartlist_add(fp_tmp2, cp); - else - tor_free(cp); - } - smartlist_free(fp_tmp); - fp_tmp = fp_tmp2; - } - smartlist_add_all(fp_out, fp_tmp); - smartlist_free(fp_tmp); return 0; } |