diff options
Diffstat (limited to 'src/core/mainloop/connection.c')
-rw-r--r-- | src/core/mainloop/connection.c | 407 |
1 files changed, 297 insertions, 110 deletions
diff --git a/src/core/mainloop/connection.c b/src/core/mainloop/connection.c index 36b2c6ef63..ada542629a 100644 --- a/src/core/mainloop/connection.c +++ b/src/core/mainloop/connection.c @@ -82,6 +82,7 @@ #include "core/or/policies.h" #include "core/or/reasons.h" #include "core/or/relay.h" +#include "core/or/status.h" #include "core/or/crypt_path.h" #include "core/proto/proto_haproxy.h" #include "core/proto/proto_http.h" @@ -98,6 +99,8 @@ #include "feature/hibernate/hibernate.h" #include "feature/hs/hs_common.h" #include "feature/hs/hs_ident.h" +#include "feature/hs/hs_metrics.h" +#include "feature/metrics/metrics.h" #include "feature/nodelist/nodelist.h" #include "feature/nodelist/routerlist.h" #include "feature/relay/dns.h" @@ -105,8 +108,11 @@ #include "feature/relay/routermode.h" #include "feature/rend/rendclient.h" #include "feature/rend/rendcommon.h" +#include "feature/stats/connstats.h" #include "feature/stats/rephist.h" +#include "feature/stats/bwhist.h" #include "lib/crypt_ops/crypto_util.h" +#include "lib/crypt_ops/crypto_format.h" #include "lib/geoip/geoip.h" #include "lib/cc/ctassert.h" @@ -214,12 +220,17 @@ static smartlist_t *outgoing_addrs = NULL; case CONN_TYPE_AP_TRANS_LISTENER: \ case CONN_TYPE_AP_NATD_LISTENER: \ case CONN_TYPE_AP_DNS_LISTENER: \ - case CONN_TYPE_AP_HTTP_CONNECT_LISTENER + case CONN_TYPE_AP_HTTP_CONNECT_LISTENER: \ + case CONN_TYPE_METRICS_LISTENER /**************************************************************/ -/** Convert a connection_t* to an listener_connection_t*; assert if the cast - * is invalid. */ +/** + * Cast a `connection_t *` to a `listener_connection_t *`. + * + * Exit with an assertion failure if the input is not a + * `listener_connection_t`. + **/ listener_connection_t * TO_LISTENER_CONN(connection_t *c) { @@ -227,6 +238,18 @@ TO_LISTENER_CONN(connection_t *c) return DOWNCAST(listener_connection_t, c); } +/** + * Cast a `const connection_t *` to a `const listener_connection_t *`. + * + * Exit with an assertion failure if the input is not a + * `listener_connection_t`. + **/ +const listener_connection_t * +CONST_TO_LISTENER_CONN(const connection_t *c) +{ + return TO_LISTENER_CONN((connection_t *)c); +} + size_t connection_get_inbuf_len(connection_t *conn) { @@ -263,6 +286,8 @@ conn_type_to_string(int type) case CONN_TYPE_EXT_OR: return "Extended OR"; case CONN_TYPE_EXT_OR_LISTENER: return "Extended OR listener"; case CONN_TYPE_AP_HTTP_CONNECT_LISTENER: return "HTTP tunnel listener"; + case CONN_TYPE_METRICS_LISTENER: return "Metrics listener"; + case CONN_TYPE_METRICS: return "Metrics"; default: log_warn(LD_BUG, "unknown connection type %d", type); tor_snprintf(buf, sizeof(buf), "unknown [%d]", type); @@ -350,13 +375,187 @@ conn_state_to_string(int type, int state) break; } + if (state == 0) { + return "uninitialized"; + } + log_warn(LD_BUG, "unknown connection state %d (type %d)", state, type); tor_snprintf(buf, sizeof(buf), "unknown state [%d] on unknown [%s] connection", state, conn_type_to_string(type)); + tor_assert_nonfatal_unreached_once(); return buf; } +/** + * Helper: describe the peer or address of connection @a conn in a + * human-readable manner. + * + * Returns a pointer to a static buffer; future calls to + * connection_describe_peer_internal() will invalidate this buffer. + * + * If <b>include_preposition</b> is true, include a preposition before the + * peer address. + * + * Nobody should parse the output of this function; it can and will change in + * future versions of tor. + **/ +static const char * +connection_describe_peer_internal(const connection_t *conn, + bool include_preposition) +{ + IF_BUG_ONCE(!conn) { + return "null peer"; + } + + static char peer_buf[256]; + const tor_addr_t *addr = &conn->addr; + const char *address = NULL; + const char *prep; + bool scrub = false; + char extra_buf[128]; + extra_buf[0] = 0; + + /* First, figure out the preposition to use */ + switch (conn->type) { + CASE_ANY_LISTENER_TYPE: + prep = "on"; + break; + case CONN_TYPE_EXIT: + prep = "to"; + break; + case CONN_TYPE_CONTROL: + case CONN_TYPE_AP: + case CONN_TYPE_EXT_OR: + prep = "from"; + break; + default: + prep = "with"; + break; + } + + /* Now figure out the address. */ + if (conn->socket_family == AF_UNIX) { + /* For unix sockets, we always use the `address` string. */ + address = conn->address ? conn->address : "unix socket"; + } else if (conn->type == CONN_TYPE_OR) { + /* For OR connections, we have a lot to do. */ + const or_connection_t *or_conn = CONST_TO_OR_CONN(conn); + /* We report the IDs we're talking to... */ + if (fast_digest_is_zero(or_conn->identity_digest)) { + // This could be a client, so scrub it. No identity to report. + scrub = true; + } else { + const ed25519_public_key_t *ed_id = + connection_or_get_alleged_ed25519_id(or_conn); + char ed_id_buf[ED25519_BASE64_LEN+1]; + char rsa_id_buf[HEX_DIGEST_LEN+1]; + if (ed_id) { + ed25519_public_to_base64(ed_id_buf, ed_id); + } else { + strlcpy(ed_id_buf, "<none>", sizeof(ed_id_buf)); + } + base16_encode(rsa_id_buf, sizeof(rsa_id_buf), + or_conn->identity_digest, DIGEST_LEN); + tor_snprintf(extra_buf, sizeof(extra_buf), + " ID=%s RSA_ID=%s", ed_id_buf, rsa_id_buf); + } + if (! scrub && (! tor_addr_eq(addr, &or_conn->canonical_orport.addr) || + conn->port != or_conn->canonical_orport.port)) { + /* We report canonical address, if it's different */ + char canonical_addr_buf[TOR_ADDR_BUF_LEN]; + if (tor_addr_to_str(canonical_addr_buf, &or_conn->canonical_orport.addr, + sizeof(canonical_addr_buf), 1)) { + tor_snprintf(extra_buf+strlen(extra_buf), + sizeof(extra_buf)-strlen(extra_buf), + " canonical_addr=%s:%"PRIu16, + canonical_addr_buf, + or_conn->canonical_orport.port); + } + } + } else if (conn->type == CONN_TYPE_EXIT) { + scrub = true; /* This is a client's request; scrub it with SafeLogging. */ + if (tor_addr_is_null(addr)) { + address = conn->address; + strlcpy(extra_buf, " (DNS lookup pending)", sizeof(extra_buf)); + } + } + + char addr_buf[TOR_ADDR_BUF_LEN]; + if (address == NULL) { + if (tor_addr_family(addr) == 0) { + address = "<unset>"; + } else { + address = tor_addr_to_str(addr_buf, addr, sizeof(addr_buf), 1); + if (!address) { + address = "<can't format!>"; + tor_assert_nonfatal_unreached_once(); + } + } + } + + char portbuf[7]; + portbuf[0]=0; + if (scrub && get_options()->SafeLogging_ != SAFELOG_SCRUB_NONE) { + address = "[scrubbed]"; + } else { + /* Only set the port if we're not scrubbing the address. */ + if (conn->port != 0) { + tor_snprintf(portbuf, sizeof(portbuf), ":%d", conn->port); + } + } + + const char *sp = include_preposition ? " " : ""; + if (! include_preposition) + prep = ""; + + tor_snprintf(peer_buf, sizeof(peer_buf), + "%s%s%s%s%s", prep, sp, address, portbuf, extra_buf); + return peer_buf; +} + +/** + * Describe the peer or address of connection @a conn in a + * human-readable manner. + * + * Returns a pointer to a static buffer; future calls to + * connection_describe_peer() or connection_describe() will invalidate this + * buffer. + * + * Nobody should parse the output of this function; it can and will change in + * future versions of tor. + **/ +const char * +connection_describe_peer(const connection_t *conn) +{ + return connection_describe_peer_internal(conn, false); +} + +/** + * Describe a connection for logging purposes. + * + * Returns a pointer to a static buffer; future calls to connection_describe() + * will invalidate this buffer. + * + * Nobody should parse the output of this function; it can and will change in + * future versions of tor. + **/ +const char * +connection_describe(const connection_t *conn) +{ + IF_BUG_ONCE(!conn) { + return "null connection"; + } + static char desc_buf[256]; + const char *peer = connection_describe_peer_internal(conn, true); + tor_snprintf(desc_buf, sizeof(desc_buf), + "%s connection (%s) %s", + conn_type_to_string(conn->type), + conn_state_to_string(conn->type, conn->state), + peer); + return desc_buf; +} + /** Allocate and return a new dir_connection_t, initialized as by * connection_init(). */ dir_connection_t * @@ -382,6 +581,7 @@ or_connection_new(int type, int socket_family) tor_assert(type == CONN_TYPE_OR || type == CONN_TYPE_EXT_OR); connection_init(now, TO_CONN(or_conn), type, socket_family); + tor_addr_make_unspec(&or_conn->canonical_orport.addr); connection_or_set_canonical(or_conn, 0); if (type == CONN_TYPE_EXT_OR) { @@ -852,11 +1052,11 @@ connection_close_immediate(connection_t *conn) tor_fragile_assert(); return; } - if (conn->outbuf_flushlen) { - log_info(LD_NET,"fd %d, type %s, state %s, %d bytes on outbuf.", + if (connection_get_outbuf_len(conn)) { + log_info(LD_NET,"fd %d, type %s, state %s, %"TOR_PRIuSZ" bytes on outbuf.", (int)conn->s, conn_type_to_string(conn->type), conn_state_to_string(conn->type, conn->state), - (int)conn->outbuf_flushlen); + buf_datalen(conn->outbuf)); } connection_unregister_events(conn); @@ -872,7 +1072,6 @@ connection_close_immediate(connection_t *conn) conn->linked_conn_is_closed = 1; if (conn->outbuf) buf_clear(conn->outbuf); - conn->outbuf_flushlen = 0; } /** Mark <b>conn</b> to be closed next time we loop through @@ -1549,13 +1748,8 @@ connection_listener_new(const struct sockaddr *listensockaddr, */ connection_check_oos(get_n_open_sockets(), 0); - if (conn->socket_family == AF_UNIX) { - log_notice(LD_NET, "Opened %s on %s", - conn_type_to_string(type), conn->address); - } else { - log_notice(LD_NET, "Opened %s on %s", - conn_type_to_string(type), fmt_addrport(&addr, gotPort)); - } + log_notice(LD_NET, "Opened %s", connection_describe(conn)); + return conn; err: @@ -1836,6 +2030,10 @@ connection_handle_listener_read(connection_t *conn, int new_type) log_notice(LD_CONTROL, "New control connection opened from %s.", fmt_and_decorate_addr(&addr)); } + if (new_type == CONN_TYPE_METRICS) { + log_info(LD_CONTROL, "New metrics connection opened from %s.", + fmt_and_decorate_addr(&addr)); + } } else if (conn->socket_family == AF_UNIX && conn->type != CONN_TYPE_AP) { tor_assert(conn->type == CONN_TYPE_CONTROL_LISTENER); @@ -1863,6 +2061,9 @@ connection_handle_listener_read(connection_t *conn, int new_type) connection_mark_for_close(newconn); return 0; } + + note_connection(true /* inbound */, conn->socket_family); + return 0; } @@ -2034,6 +2235,8 @@ connection_connect_sockaddr,(connection_t *conn, } } + note_connection(false /* outbound */, conn->socket_family); + /* it succeeded. we're connected. */ log_fn(inprogress ? LOG_DEBUG : LOG_INFO, LD_NET, "Connection to socket %s (sock "TOR_SOCKET_T_FORMAT").", @@ -2067,22 +2270,13 @@ connection_connect_log_client_use_ip_version(const connection_t *conn) return; } - const int must_ipv4 = !fascist_firewall_use_ipv6(options); + const int must_ipv4 = !reachable_addr_use_ipv6(options); const int must_ipv6 = (options->ClientUseIPv4 == 0); const int pref_ipv6 = (conn->type == CONN_TYPE_OR - ? fascist_firewall_prefer_ipv6_orport(options) - : fascist_firewall_prefer_ipv6_dirport(options)); + ? reachable_addr_prefer_ipv6_orport(options) + : reachable_addr_prefer_ipv6_dirport(options)); tor_addr_t real_addr; - tor_addr_make_null(&real_addr, AF_UNSPEC); - - /* OR conns keep the original address in real_addr, as addr gets overwritten - * with the descriptor address */ - if (conn->type == CONN_TYPE_OR) { - const or_connection_t *or_conn = TO_OR_CONN((connection_t *)conn); - tor_addr_copy(&real_addr, &or_conn->real_addr); - } else if (conn->type == CONN_TYPE_DIR) { - tor_addr_copy(&real_addr, &conn->addr); - } + tor_addr_copy(&real_addr, &conn->addr); /* Check if we broke a mandatory address family restriction */ if ((must_ipv4 && tor_addr_family(&real_addr) == AF_INET6) @@ -2105,7 +2299,7 @@ connection_connect_log_client_use_ip_version(const connection_t *conn) return; } - if (fascist_firewall_use_ipv6(options)) { + if (reachable_addr_use_ipv6(options)) { log_info(LD_NET, "Our outgoing connection is using IPv%d.", tor_addr_family(&real_addr) == AF_INET6 ? 6 : 4); } @@ -2115,13 +2309,13 @@ connection_connect_log_client_use_ip_version(const connection_t *conn) || (pref_ipv6 && tor_addr_family(&real_addr) == AF_INET)) { log_info(LD_NET, "Outgoing connection to %s doesn't satisfy " "ClientPreferIPv6%sPort %d, with ClientUseIPv4 %d, and " - "fascist_firewall_use_ipv6 %d (ClientUseIPv6 %d and UseBridges " + "reachable_addr_use_ipv6 %d (ClientUseIPv6 %d and UseBridges " "%d).", fmt_addr(&real_addr), conn->type == CONN_TYPE_OR ? "OR" : "Dir", conn->type == CONN_TYPE_OR ? options->ClientPreferIPv6ORPort : options->ClientPreferIPv6DirPort, - options->ClientUseIPv4, fascist_firewall_use_ipv6(options), + options->ClientUseIPv4, reachable_addr_use_ipv6(options), options->ClientUseIPv6, options->UseBridges); } } @@ -2155,9 +2349,9 @@ conn_get_outbound_address(sa_family_t family, ext_addr = &options->OutboundBindAddresses[OUTBOUND_ADDR_EXIT] [fam_index]; } else if (!tor_addr_is_null( - &options->OutboundBindAddresses[OUTBOUND_ADDR_EXIT_AND_OR] + &options->OutboundBindAddresses[OUTBOUND_ADDR_ANY] [fam_index])) { - ext_addr = &options->OutboundBindAddresses[OUTBOUND_ADDR_EXIT_AND_OR] + ext_addr = &options->OutboundBindAddresses[OUTBOUND_ADDR_ANY] [fam_index]; } } else { // All non-exit connections @@ -2166,9 +2360,9 @@ conn_get_outbound_address(sa_family_t family, ext_addr = &options->OutboundBindAddresses[OUTBOUND_ADDR_OR] [fam_index]; } else if (!tor_addr_is_null( - &options->OutboundBindAddresses[OUTBOUND_ADDR_EXIT_AND_OR] + &options->OutboundBindAddresses[OUTBOUND_ADDR_ANY] [fam_index])) { - ext_addr = &options->OutboundBindAddresses[OUTBOUND_ADDR_EXIT_AND_OR] + ext_addr = &options->OutboundBindAddresses[OUTBOUND_ADDR_ANY] [fam_index]; } } @@ -2608,8 +2802,8 @@ connection_read_https_proxy_response(connection_t *conn) if (parse_http_response(headers, &status_code, &date_header, NULL, &reason) < 0) { log_warn(LD_NET, - "Unparseable headers from proxy (connecting to '%s'). Closing.", - conn->address); + "Unparseable headers from proxy (%s). Closing.", + connection_describe(conn)); tor_free(headers); return -1; } @@ -2618,8 +2812,8 @@ connection_read_https_proxy_response(connection_t *conn) if (status_code == 200) { log_info(LD_NET, - "HTTPS connect to '%s' successful! (200 %s) Starting TLS.", - conn->address, escaped(reason)); + "HTTPS connect for %s successful! (200 %s) Starting TLS.", + connection_describe(conn), escaped(reason)); tor_free(reason); return 1; } @@ -2835,16 +3029,16 @@ connection_read_proxy_handshake(connection_t *conn) if (ret < 0) { if (reason) { - log_warn(LD_NET, "Proxy Client: unable to connect to %s:%d (%s)", - conn->address, conn->port, escaped(reason)); + log_warn(LD_NET, "Proxy Client: unable to connect %s (%s)", + connection_describe(conn), escaped(reason)); tor_free(reason); } else { - log_warn(LD_NET, "Proxy Client: unable to connect to %s:%d", - conn->address, conn->port); + log_warn(LD_NET, "Proxy Client: unable to connect %s", + connection_describe(conn)); } } else if (ret == 1) { - log_info(LD_NET, "Proxy Client: connection to %s:%d successful", - conn->address, conn->port); + log_info(LD_NET, "Proxy Client: %s successful", + connection_describe(conn)); } return ret; @@ -3001,10 +3195,10 @@ retry_all_listeners(smartlist_t *new_conns, int close_all_noncontrol) smartlist_t *replacements = smartlist_new(); const or_options_t *options = get_options(); int retval = 0; - const uint16_t old_or_port = router_get_advertised_or_port(options); + const uint16_t old_or_port = routerconf_find_or_port(options, AF_INET); const uint16_t old_or_port_ipv6 = - router_get_advertised_or_port_by_af(options,AF_INET6); - const uint16_t old_dir_port = router_get_advertised_dir_port(options, 0); + routerconf_find_or_port(options,AF_INET6); + const uint16_t old_dir_port = routerconf_find_dir_port(options, 0); SMARTLIST_FOREACH_BEGIN(get_connection_array(), connection_t *, conn) { if (connection_is_listener(conn) && !conn->marked_for_close) @@ -3035,8 +3229,8 @@ retry_all_listeners(smartlist_t *new_conns, int close_all_noncontrol) connection_t *old_conn = r->old_conn; if (skip) { - log_debug(LD_NET, "Skipping creating new listener for %s:%d", - old_conn->address, old_conn->port); + log_debug(LD_NET, "Skipping creating new listener for %s", + connection_describe(old_conn)); continue; } @@ -3059,10 +3253,11 @@ retry_all_listeners(smartlist_t *new_conns, int close_all_noncontrol) smartlist_add(new_conns, new_conn); - log_notice(LD_NET, "Closed no-longer-configured %s on %s:%d " - "(replaced by %s:%d)", - conn_type_to_string(old_conn->type), old_conn->address, - old_conn->port, new_conn->address, new_conn->port); + char *old_desc = tor_strdup(connection_describe(old_conn)); + log_notice(LD_NET, "Closed no-longer-configured %s " + "(replaced by %s)", + old_desc, connection_describe(new_conn)); + tor_free(old_desc); } SMARTLIST_FOREACH_END(r); #endif /* defined(ENABLE_LISTENER_REBIND) */ @@ -3080,10 +3275,9 @@ retry_all_listeners(smartlist_t *new_conns, int close_all_noncontrol) SMARTLIST_FOREACH(replacements, listener_replacement_t *, r, tor_free(r)); smartlist_free(replacements); - if (old_or_port != router_get_advertised_or_port(options) || - old_or_port_ipv6 != router_get_advertised_or_port_by_af(options, - AF_INET6) || - old_dir_port != router_get_advertised_dir_port(options, 0)) { + if (old_or_port != routerconf_find_or_port(options, AF_INET) || + old_or_port_ipv6 != routerconf_find_or_port(options, AF_INET6) || + old_dir_port != routerconf_find_dir_port(options, 0)) { /* Our chosen ORPort or DirPort is not what it used to be: the * descriptor we had (if any) should be regenerated. (We won't * automatically notice this because of changes in the option, @@ -3261,12 +3455,12 @@ connection_bucket_write_limit(connection_t *conn, time_t now) { int base = RELAY_PAYLOAD_SIZE; int priority = conn->type != CONN_TYPE_DIR; - size_t conn_bucket = conn->outbuf_flushlen; + size_t conn_bucket = buf_datalen(conn->outbuf); size_t global_bucket_val = token_bucket_rw_get_write(&global_bucket); if (!connection_is_rate_limited(conn)) { /* be willing to write to local conns even if our buckets are empty */ - return conn->outbuf_flushlen; + return conn_bucket; } if (connection_speaks_cells(conn)) { @@ -3356,9 +3550,9 @@ record_num_bytes_transferred_impl(connection_t *conn, /* Count bytes of answering direct and tunneled directory requests */ if (conn->type == CONN_TYPE_DIR && conn->purpose == DIR_PURPOSE_SERVER) { if (num_read > 0) - rep_hist_note_dir_bytes_read(num_read, now); + bwhist_note_dir_bytes_read(num_read, now); if (num_written > 0) - rep_hist_note_dir_bytes_written(num_written, now); + bwhist_note_dir_bytes_written(num_written, now); } /* Linked connections and internal IPs aren't counted for statistics or @@ -3373,15 +3567,16 @@ record_num_bytes_transferred_impl(connection_t *conn, if (!connection_is_rate_limited(conn)) return; + const bool is_ipv6 = (conn->socket_family == AF_INET6); if (conn->type == CONN_TYPE_OR) - rep_hist_note_or_conn_bytes(conn->global_identifier, num_read, - num_written, now); + conn_stats_note_or_conn_bytes(conn->global_identifier, num_read, + num_written, now, is_ipv6); if (num_read > 0) { - rep_hist_note_bytes_read(num_read, now); + bwhist_note_bytes_read(num_read, now, is_ipv6); } if (num_written > 0) { - rep_hist_note_bytes_written(num_written, now); + bwhist_note_bytes_written(num_written, now, is_ipv6); } if (conn->type == CONN_TYPE_EXIT) rep_hist_note_exit_bytes(conn->port, num_written, num_read); @@ -3707,6 +3902,8 @@ connection_handle_read_impl(connection_t *conn) return connection_handle_listener_read(conn, CONN_TYPE_DIR); case CONN_TYPE_CONTROL_LISTENER: return connection_handle_listener_read(conn, CONN_TYPE_CONTROL); + case CONN_TYPE_METRICS_LISTENER: + return connection_handle_listener_read(conn, CONN_TYPE_METRICS); case CONN_TYPE_AP_DNS_LISTENER: /* This should never happen; eventdns.c handles the reads here. */ tor_fragile_assert(); @@ -3870,17 +4067,14 @@ connection_buf_read_from_socket(connection_t *conn, ssize_t *max_to_read, switch (result) { case TOR_TLS_CLOSE: case TOR_TLS_ERROR_IO: - log_debug(LD_NET,"TLS connection closed %son read. Closing. " - "(Nickname %s, address %s)", - result == TOR_TLS_CLOSE ? "cleanly " : "", - or_conn->nickname ? or_conn->nickname : "not set", - conn->address); + log_debug(LD_NET,"TLS %s closed %son read. Closing.", + connection_describe(conn), + result == TOR_TLS_CLOSE ? "cleanly " : ""); return result; CASE_TOR_TLS_ERROR_ANY_NONIO: - log_debug(LD_NET,"tls error [%s]. breaking (nickname %s, address %s).", + log_debug(LD_NET,"tls error [%s] from %s. Breaking.", tor_tls_err_to_string(result), - or_conn->nickname ? or_conn->nickname : "not set", - conn->address); + connection_describe(conn)); return result; case TOR_TLS_WANTWRITE: connection_start_writing(conn); @@ -3921,12 +4115,7 @@ connection_buf_read_from_socket(connection_t *conn, ssize_t *max_to_read, result, (long)n_read, (long)n_written); } else if (conn->linked) { if (conn->linked_conn) { - result = buf_move_to_buf(conn->inbuf, conn->linked_conn->outbuf, - &conn->linked_conn->outbuf_flushlen); - if (BUG(result<0)) { - log_warn(LD_BUG, "reading from linked connection buffer failed."); - return -1; - } + result = (int) buf_move_all(conn->inbuf, conn->linked_conn->outbuf); } else { result = 0; } @@ -3961,6 +4150,14 @@ connection_buf_read_from_socket(connection_t *conn, ssize_t *max_to_read, /* change *max_to_read */ *max_to_read = at_most - n_read; + /* Onion service application connection. Note read bytes for metrics. */ + if (CONN_IS_EDGE(conn) && TO_EDGE_CONN(conn)->hs_ident) { + edge_connection_t *edge_conn = TO_EDGE_CONN(conn); + hs_metrics_app_read_bytes(&edge_conn->hs_ident->identity_pk, + edge_conn->hs_ident->orig_virtual_port, + n_read); + } + /* Update edge_conn->n_read */ if (conn->type == CONN_TYPE_AP) { edge_connection_t *edge_conn = TO_EDGE_CONN(conn); @@ -4030,12 +4227,11 @@ connection_fetch_from_buf_http(connection_t *conn, body_out, body_used, max_bodylen, force_complete); } -/** Return conn-\>outbuf_flushlen: how many bytes conn wants to flush - * from its outbuf. */ +/** Return true if this connection has data to flush. */ int connection_wants_to_flush(connection_t *conn) { - return conn->outbuf_flushlen > 0; + return connection_get_outbuf_len(conn) > 0; } /** Are there too many bytes on edge connection <b>conn</b>'s outbuf to @@ -4045,7 +4241,7 @@ connection_wants_to_flush(connection_t *conn) int connection_outbuf_too_full(connection_t *conn) { - return (conn->outbuf_flushlen > 10*CELL_PAYLOAD_SIZE); + return connection_get_outbuf_len(conn) > 10*CELL_PAYLOAD_SIZE; } /** @@ -4171,7 +4367,7 @@ connection_handle_write_impl(connection_t *conn, int force) return -1; } - max_to_write = force ? (ssize_t)conn->outbuf_flushlen + max_to_write = force ? (ssize_t)buf_datalen(conn->outbuf) : connection_bucket_write_limit(conn, now); if (connection_speaks_cells(conn) && @@ -4203,7 +4399,7 @@ connection_handle_write_impl(connection_t *conn, int force) /* else open, or closing */ initial_size = buf_datalen(conn->outbuf); result = buf_flush_to_tls(conn->outbuf, or_conn->tls, - max_to_write, &conn->outbuf_flushlen); + max_to_write); if (result >= 0) update_send_buffer_size(conn->s); @@ -4269,7 +4465,7 @@ connection_handle_write_impl(connection_t *conn, int force) } else { CONN_LOG_PROTECT(conn, result = buf_flush_to_socket(conn->outbuf, conn->s, - max_to_write, &conn->outbuf_flushlen)); + max_to_write)); if (result < 0) { if (CONN_IS_EDGE(conn)) connection_edge_end_errno(TO_EDGE_CONN(conn)); @@ -4425,10 +4621,10 @@ connection_write_to_buf_failed(connection_t *conn) /** Helper for connection_write_to_buf_impl and connection_write_buf_to_buf: * * Called when an attempt to add bytes on <b>conn</b>'s outbuf has succeeded: - * record the number of bytes added. + * start writing if appropriate. */ static void -connection_write_to_buf_commit(connection_t *conn, size_t len) +connection_write_to_buf_commit(connection_t *conn) { /* If we receive optimistic data in the EXIT_CONN_STATE_RESOLVING * state, we don't want to try to write it right away, since @@ -4437,7 +4633,6 @@ connection_write_to_buf_commit(connection_t *conn, size_t len) if (conn->write_event) { connection_start_writing(conn); } - conn->outbuf_flushlen += len; } /** Append <b>len</b> bytes of <b>string</b> onto <b>conn</b>'s @@ -4460,25 +4655,20 @@ connection_write_to_buf_impl_,(const char *string, size_t len, if (!connection_may_write_to_buf(conn)) return; - size_t written; - if (zlib) { - size_t old_datalen = buf_datalen(conn->outbuf); dir_connection_t *dir_conn = TO_DIR_CONN(conn); int done = zlib < 0; CONN_LOG_PROTECT(conn, r = buf_add_compress(conn->outbuf, dir_conn->compress_state, string, len, done)); - written = buf_datalen(conn->outbuf) - old_datalen; } else { CONN_LOG_PROTECT(conn, r = buf_add(conn->outbuf, string, len)); - written = len; } if (r < 0) { connection_write_to_buf_failed(conn); return; } - connection_write_to_buf_commit(conn, written); + connection_write_to_buf_commit(conn); } /** @@ -4523,7 +4713,7 @@ connection_buf_add_buf(connection_t *conn, buf_t *buf) return; buf_move_all(conn->outbuf, buf); - connection_write_to_buf_commit(conn, len); + connection_write_to_buf_commit(conn); } #define CONN_GET_ALL_TEMPLATE(var, test) \ @@ -4733,7 +4923,7 @@ any_other_active_or_conns(const or_connection_t *this_conn) connection_t *conn = connection_get_another_active_or_conn(this_conn); if (conn != NULL) { log_debug(LD_DIR, "%s: Found an OR connection: %s", - __func__, conn->address); + __func__, connection_describe(conn)); return 1; } @@ -4883,7 +5073,7 @@ client_check_address_changed(tor_socket_t sock) smartlist_clear(outgoing_addrs); smartlist_add(outgoing_addrs, tor_memdup(&out_addr, sizeof(tor_addr_t))); /* We'll need to resolve ourselves again. */ - reset_last_resolved_addr(); + resolved_addr_reset_last(AF_INET); /* Okay, now change our keys. */ ip_address_changed(1); } @@ -4937,6 +5127,8 @@ connection_process_inbuf(connection_t *conn, int package_partial) return connection_dir_process_inbuf(TO_DIR_CONN(conn)); case CONN_TYPE_CONTROL: return connection_control_process_inbuf(TO_CONTROL_CONN(conn)); + case CONN_TYPE_METRICS: + return metrics_connection_process_inbuf(conn); default: log_err(LD_BUG,"got unexpected conn type %d.", conn->type); tor_fragile_assert(); @@ -4995,6 +5187,8 @@ connection_finished_flushing(connection_t *conn) return connection_dir_finished_flushing(TO_DIR_CONN(conn)); case CONN_TYPE_CONTROL: return connection_control_finished_flushing(TO_CONTROL_CONN(conn)); + case CONN_TYPE_METRICS: + return metrics_connection_finished_flushing(conn); default: log_err(LD_BUG,"got unexpected conn type %d.", conn->type); tor_fragile_assert(); @@ -5050,6 +5244,8 @@ connection_reached_eof(connection_t *conn) return connection_dir_reached_eof(TO_DIR_CONN(conn)); case CONN_TYPE_CONTROL: return connection_control_reached_eof(TO_CONTROL_CONN(conn)); + case CONN_TYPE_METRICS: + return metrics_connection_reached_eof(conn); default: log_err(LD_BUG,"got unexpected conn type %d.", conn->type); tor_fragile_assert(); @@ -5411,18 +5607,6 @@ assert_connection_ok(connection_t *conn, time_t now) if (conn->linked) tor_assert(!SOCKET_OK(conn->s)); - if (conn->outbuf_flushlen > 0) { - /* With optimistic data, we may have queued data in - * EXIT_CONN_STATE_RESOLVING while the conn is not yet marked to writing. - * */ - tor_assert((conn->type == CONN_TYPE_EXIT && - conn->state == EXIT_CONN_STATE_RESOLVING) || - connection_is_writing(conn) || - conn->write_blocked_on_bw || - (CONN_IS_EDGE(conn) && - TO_EDGE_CONN(conn)->edge_blocked_on_circ)); - } - if (conn->hold_open_until_flushed) tor_assert(conn->marked_for_close); @@ -5512,6 +5696,9 @@ assert_connection_ok(connection_t *conn, time_t now) tor_assert(conn->state >= CONTROL_CONN_STATE_MIN_); tor_assert(conn->state <= CONTROL_CONN_STATE_MAX_); break; + case CONN_TYPE_METRICS: + /* No state. */ + break; default: tor_assert(0); } |