mirror of
https://gitlab.torproject.org/tpo/core/tor.git
synced 2024-11-24 04:13:28 +01:00
conn: New Metrics listener port
If MetricsPort is defined, listen on it and handle the incoming request. Signed-off-by: David Goulet <dgoulet@torproject.org>
This commit is contained in:
parent
a882d1bf0a
commit
4f5cea1f59
@ -91,6 +91,7 @@
|
||||
#include "feature/dirclient/dirclient_modes.h"
|
||||
#include "feature/hibernate/hibernate.h"
|
||||
#include "feature/hs/hs_config.h"
|
||||
#include "feature/metrics/metrics.h"
|
||||
#include "feature/nodelist/dirlist.h"
|
||||
#include "feature/nodelist/networkstatus.h"
|
||||
#include "feature/nodelist/nickname.h"
|
||||
@ -560,6 +561,8 @@ static const config_var_t option_vars_[] = {
|
||||
OBSOLETE("MaxOnionsPending"),
|
||||
V(MaxOnionQueueDelay, MSEC_INTERVAL, "1750 msec"),
|
||||
V(MaxUnparseableDescSizeToLog, MEMUNIT, "10 MB"),
|
||||
VPORT(MetricsPort),
|
||||
V(MetricsPortPolicy, LINELIST, NULL),
|
||||
VAR("MyFamily", LINELIST, MyFamily_lines, NULL),
|
||||
V(NewCircuitPeriod, INTERVAL, "30 seconds"),
|
||||
OBSOLETE("NamingAuthoritativeDirectory"),
|
||||
@ -6461,6 +6464,10 @@ parse_ports(or_options_t *options, int validate_only,
|
||||
*msg = tor_strdup("Invalid HTTPTunnelPort configuration");
|
||||
goto err;
|
||||
}
|
||||
if (metrics_parse_ports(options, ports, msg) < 0) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
{
|
||||
unsigned control_port_flags = CL_PORT_NO_STREAM_OPTIONS |
|
||||
CL_PORT_WARN_NONLOCAL;
|
||||
|
@ -164,6 +164,8 @@ struct or_options_t {
|
||||
struct config_line_t *ORPort_lines;
|
||||
/** Ports to listen on for extended OR connections. */
|
||||
struct config_line_t *ExtORPort_lines;
|
||||
/** Ports to listen on for Metrics connections. */
|
||||
struct config_line_t *MetricsPort_lines;
|
||||
/** Ports to listen on for SOCKS connections. */
|
||||
struct config_line_t *SocksPort_lines;
|
||||
/** Ports to listen on for transparent pf/netfilter connections. */
|
||||
@ -223,6 +225,7 @@ struct or_options_t {
|
||||
unsigned int DNSPort_set : 1;
|
||||
unsigned int ExtORPort_set : 1;
|
||||
unsigned int HTTPTunnelPort_set : 1;
|
||||
unsigned int MetricsPort_set : 1;
|
||||
/**@}*/
|
||||
|
||||
/** Whether to publish our descriptor regardless of all our self-tests
|
||||
@ -1076,6 +1079,9 @@ struct or_options_t {
|
||||
**/
|
||||
int DormantCanceledByStartup;
|
||||
|
||||
/** List of policy allowed to query the Metrics port. */
|
||||
struct config_line_t *MetricsPortPolicy;
|
||||
|
||||
/**
|
||||
* Configuration objects for individual modules.
|
||||
*
|
||||
|
@ -99,6 +99,7 @@
|
||||
#include "feature/hibernate/hibernate.h"
|
||||
#include "feature/hs/hs_common.h"
|
||||
#include "feature/hs/hs_ident.h"
|
||||
#include "feature/metrics/metrics.h"
|
||||
#include "feature/nodelist/nodelist.h"
|
||||
#include "feature/nodelist/routerlist.h"
|
||||
#include "feature/relay/dns.h"
|
||||
@ -218,7 +219,8 @@ 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
|
||||
|
||||
/**************************************************************/
|
||||
|
||||
@ -283,6 +285,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);
|
||||
@ -2025,6 +2029,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);
|
||||
@ -3893,6 +3901,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();
|
||||
@ -5108,6 +5118,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();
|
||||
@ -5671,6 +5683,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);
|
||||
}
|
||||
|
@ -73,8 +73,12 @@ struct buf_t;
|
||||
#define CONN_TYPE_EXT_OR_LISTENER 17
|
||||
/** Type for sockets listening for HTTP CONNECT tunnel connections. */
|
||||
#define CONN_TYPE_AP_HTTP_CONNECT_LISTENER 18
|
||||
/** Type for sockets listening for Metrics query connections. */
|
||||
#define CONN_TYPE_METRICS_LISTENER 19
|
||||
/** Type for connections from metrics listener. */
|
||||
#define CONN_TYPE_METRICS 20
|
||||
|
||||
#define CONN_TYPE_MAX_ 19
|
||||
#define CONN_TYPE_MAX_ 21
|
||||
/* !!!! If _CONN_TYPE_MAX is ever over 31, we must grow the type field in
|
||||
* struct connection_t. */
|
||||
|
||||
|
@ -48,6 +48,8 @@
|
||||
static smartlist_t *socks_policy = NULL;
|
||||
/** Policy that addresses for incoming directory connections must match. */
|
||||
static smartlist_t *dir_policy = NULL;
|
||||
/** Policy for incoming MetricsPort connections that must match. */
|
||||
static smartlist_t *metrics_policy = NULL;
|
||||
/** Policy that addresses for incoming router descriptors must match in order
|
||||
* to be published by us. */
|
||||
static smartlist_t *authdir_reject_policy = NULL;
|
||||
@ -1060,6 +1062,15 @@ socks_policy_permits_address(const tor_addr_t *addr)
|
||||
return addr_policy_permits_tor_addr(addr, 1, socks_policy);
|
||||
}
|
||||
|
||||
/** Return 1 if <b>addr</b> is permitted to connect to our metrics port,
|
||||
* based on <b>socks_policy</b>. Else return 0.
|
||||
*/
|
||||
int
|
||||
metrics_policy_permits_address(const tor_addr_t *addr)
|
||||
{
|
||||
return addr_policy_permits_tor_addr(addr, 1, metrics_policy);
|
||||
}
|
||||
|
||||
/** Return true iff the address <b>addr</b> is in a country listed in the
|
||||
* case-insensitive list of country codes <b>cc_list</b>. */
|
||||
static int
|
||||
@ -1218,6 +1229,22 @@ load_policy_from_option(config_line_t *config, const char *option_name,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Helper: Parse the MetricsPortPolicy option into the metrics_policy and set
|
||||
* the reject all by default.
|
||||
*
|
||||
* Return 0 on success else -1. */
|
||||
static int
|
||||
parse_metrics_port_policy(const or_options_t *options)
|
||||
{
|
||||
if (load_policy_from_option(options->MetricsPortPolicy, "MetricsPortPolicy",
|
||||
&metrics_policy, -1) < 0) {
|
||||
return -1;
|
||||
}
|
||||
/* It is a reject all by default. */
|
||||
append_exit_policy_string(&metrics_policy, "reject *:*");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Set all policies based on <b>options</b>, which should have been validated
|
||||
* first by validate_addr_policies. */
|
||||
int
|
||||
@ -1239,6 +1266,9 @@ policies_parse_from_options(const or_options_t *options)
|
||||
if (load_policy_from_option(options->AuthDirBadExit, "AuthDirBadExit",
|
||||
&authdir_badexit_policy, ADDR_POLICY_REJECT) < 0)
|
||||
ret = -1;
|
||||
if (parse_metrics_port_policy(options) < 0) {
|
||||
ret = -1;
|
||||
}
|
||||
if (parse_reachable_addresses() < 0)
|
||||
ret = -1;
|
||||
return ret;
|
||||
@ -3074,6 +3104,8 @@ policies_free_all(void)
|
||||
socks_policy = NULL;
|
||||
addr_policy_list_free(dir_policy);
|
||||
dir_policy = NULL;
|
||||
addr_policy_list_free(metrics_policy);
|
||||
metrics_policy = NULL;
|
||||
addr_policy_list_free(authdir_reject_policy);
|
||||
authdir_reject_policy = NULL;
|
||||
addr_policy_list_free(authdir_invalid_policy);
|
||||
|
@ -102,6 +102,7 @@ void reachable_addr_choose_from_dir_server(const dir_server_t *ds,
|
||||
|
||||
int dir_policy_permits_address(const tor_addr_t *addr);
|
||||
int socks_policy_permits_address(const tor_addr_t *addr);
|
||||
int metrics_policy_permits_address(const tor_addr_t *addr);
|
||||
int authdir_policy_permits_address(const tor_addr_t *addr, uint16_t port);
|
||||
int authdir_policy_valid_address(const tor_addr_t *addr, uint16_t port);
|
||||
int authdir_policy_badexit_address(const tor_addr_t *addr, uint16_t port);
|
||||
|
@ -206,6 +206,8 @@ entry_connection_describe_status_for_controller(const entry_connection_t *conn)
|
||||
case CONN_TYPE_AP_DNS_LISTENER: client_protocol = "DNS"; break;
|
||||
case CONN_TYPE_AP_HTTP_CONNECT_LISTENER:
|
||||
client_protocol = "HTTPCONNECT"; break;
|
||||
case CONN_TYPE_METRICS_LISTENER:
|
||||
client_protocol = "METRICS"; break;
|
||||
default: client_protocol = "UNKNOWN";
|
||||
}
|
||||
smartlist_add_asprintf(descparts, "CLIENT_PROTOCOL=%s",
|
||||
|
@ -287,6 +287,8 @@ getinfo_helper_listeners(control_connection_t *control_conn,
|
||||
type = CONN_TYPE_AP_DNS_LISTENER;
|
||||
else if (!strcmp(question, "net/listeners/control"))
|
||||
type = CONN_TYPE_CONTROL_LISTENER;
|
||||
else if (!strcmp(question, "net/listeners/metrics"))
|
||||
type = CONN_TYPE_METRICS_LISTENER;
|
||||
else
|
||||
return 0; /* unknown key */
|
||||
|
||||
|
@ -8,25 +8,68 @@
|
||||
|
||||
#include "orconfig.h"
|
||||
|
||||
#include "lib/container/smartlist.h"
|
||||
#include "core/or/or.h"
|
||||
|
||||
#include "lib/encoding/confline.h"
|
||||
#include "lib/log/util_bug.h"
|
||||
#include "lib/malloc/malloc.h"
|
||||
#include "lib/metrics/metrics_store.h"
|
||||
#include "lib/net/resolve.h"
|
||||
#include "lib/string/printf.h"
|
||||
#include "lib/net/nettypes.h"
|
||||
#include "lib/net/address.h"
|
||||
|
||||
#include "core/mainloop/connection.h"
|
||||
#include "core/or/connection_st.h"
|
||||
#include "core/or/policies.h"
|
||||
#include "core/or/port_cfg_st.h"
|
||||
#include "core/proto/proto_http.h"
|
||||
|
||||
#include "feature/dircommon/directory.h"
|
||||
#include "feature/metrics/metrics.h"
|
||||
|
||||
#include "app/config/config.h"
|
||||
#include "app/main/subsysmgr.h"
|
||||
|
||||
/** Return newly allocated string containing the output of all subsystems
|
||||
/** Metrics format driver set by the MetricsPort option. */
|
||||
static metrics_format_t the_format = METRICS_FORMAT_PROMETHEUS;
|
||||
|
||||
/** Return true iff the given peer address is allowed by our MetricsPortPolicy
|
||||
* option that is is in that list. */
|
||||
static bool
|
||||
metrics_request_allowed(const tor_addr_t *peer_addr)
|
||||
{
|
||||
tor_assert(peer_addr);
|
||||
|
||||
return metrics_policy_permits_address(peer_addr);
|
||||
}
|
||||
|
||||
/** Helper: For a metrics port connection, write the HTTP response header
|
||||
* using the data length passed. */
|
||||
static void
|
||||
write_metrics_http_response(const size_t data_len, connection_t *conn)
|
||||
{
|
||||
char date[RFC1123_TIME_LEN+1];
|
||||
buf_t *buf = buf_new_with_capacity(128 + data_len);
|
||||
|
||||
format_rfc1123_time(date, approx_time());
|
||||
buf_add_printf(buf, "HTTP/1.0 200 OK\r\nDate: %s\r\n", date);
|
||||
buf_add_printf(buf, "Content-Type: text/plain; charset=utf-8\r\n");
|
||||
buf_add_printf(buf, "Content-Length: %" TOR_PRIuSZ "\r\n", data_len);
|
||||
buf_add_string(buf, "\r\n");
|
||||
|
||||
connection_buf_add_buf(conn, buf);
|
||||
buf_free(buf);
|
||||
}
|
||||
|
||||
/** Return newly allocated buffer containing the output of all subsystems
|
||||
* having metrics.
|
||||
*
|
||||
* This is used to output the content on the MetricsPort. */
|
||||
char *
|
||||
buf_t *
|
||||
metrics_get_output(const metrics_format_t fmt)
|
||||
{
|
||||
char *data;
|
||||
smartlist_t *chunks = smartlist_new();
|
||||
buf_t *data = buf_new();
|
||||
|
||||
/* Go over all subsystems that exposes a metrics store. */
|
||||
for (unsigned i = 0; i < n_tor_subsystems; ++i) {
|
||||
@ -40,19 +83,166 @@ metrics_get_output(const metrics_format_t fmt)
|
||||
|
||||
if (sys->get_metrics && (stores = sys->get_metrics())) {
|
||||
SMARTLIST_FOREACH_BEGIN(stores, const metrics_store_t *, store) {
|
||||
smartlist_add(chunks, metrics_store_get_output(fmt, store));
|
||||
metrics_store_get_output(fmt, store, data);
|
||||
} SMARTLIST_FOREACH_END(store);
|
||||
}
|
||||
}
|
||||
|
||||
data = smartlist_join_strings(chunks, "\n", 0, NULL);
|
||||
|
||||
SMARTLIST_FOREACH(chunks, char *, c, tor_free(c));
|
||||
smartlist_free(chunks);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
/** Process what is in the inbuf of this connection of type metrics.
|
||||
*
|
||||
* Return 0 on success else -1 on error which will close the connection. */
|
||||
int
|
||||
metrics_connection_process_inbuf(connection_t *conn)
|
||||
{
|
||||
int ret = -1;
|
||||
char *headers = NULL, *command = NULL, *url = NULL;
|
||||
const char *errmsg = NULL;
|
||||
|
||||
tor_assert(conn);
|
||||
tor_assert(conn->type == CONN_TYPE_METRICS);
|
||||
|
||||
if (!metrics_request_allowed(&conn->addr)) {
|
||||
/* Close connection. Don't bother returning anything if you are not
|
||||
* allowed by being on the policy list. */
|
||||
errmsg = NULL;
|
||||
goto err;
|
||||
}
|
||||
|
||||
const int http_status = fetch_from_buf_http(conn->inbuf, &headers, 1024,
|
||||
NULL, NULL, 1024, 0);
|
||||
if (http_status < 0) {
|
||||
errmsg = "HTTP/1.0 400 Bad Request\r\n\r\n";
|
||||
goto err;
|
||||
} else if (http_status == 0) {
|
||||
/* no HTTP request yet. */
|
||||
goto done;
|
||||
}
|
||||
|
||||
const int cmd_status = parse_http_command(headers, &command, &url);
|
||||
if (cmd_status < 0) {
|
||||
errmsg = "HTTP/1.0 400 Bad Request\r\n\r\n";
|
||||
goto err;
|
||||
} else if (strcmpstart(command, "GET")) {
|
||||
errmsg = "HTTP/1.0 405 Method Not Allowed\r\n\r\n";
|
||||
goto err;
|
||||
}
|
||||
tor_assert(url);
|
||||
|
||||
/* Where we expect the query to come for. */
|
||||
#define EXPECTED_URL_PATH "/metrics"
|
||||
#define EXPECTED_URL_PATH_LEN (sizeof(EXPECTED_URL_PATH) - 1) /* No NUL */
|
||||
|
||||
if (!strcmpstart(url, EXPECTED_URL_PATH) &&
|
||||
strlen(url) == EXPECTED_URL_PATH_LEN) {
|
||||
buf_t *data = metrics_get_output(the_format);
|
||||
|
||||
write_metrics_http_response(buf_datalen(data), conn);
|
||||
connection_buf_add_buf(conn, data);
|
||||
buf_free(data);
|
||||
} else {
|
||||
errmsg = "HTTP/1.0 404 Not Found\r\n\r\n";
|
||||
goto err;
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
goto done;
|
||||
|
||||
err:
|
||||
if (errmsg) {
|
||||
log_info(LD_EDGE, "HTTP metrics error: saying %s", escaped(errmsg));
|
||||
connection_buf_add(errmsg, strlen(errmsg), conn);
|
||||
}
|
||||
|
||||
done:
|
||||
tor_free(headers);
|
||||
tor_free(command);
|
||||
tor_free(url);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/** Parse metrics ports from options. On success, add the port to the ports
|
||||
* list and return 0. On failure, set err_msg_out to a newly allocated string
|
||||
* describing the problem and return -1. */
|
||||
int
|
||||
metrics_parse_ports(or_options_t *options, smartlist_t *ports,
|
||||
char **err_msg_out)
|
||||
{
|
||||
int num_elems, ok = 0, ret = -1;
|
||||
const char *addrport_str = NULL, *fmt_str = NULL;
|
||||
smartlist_t *elems = NULL;
|
||||
port_cfg_t *cfg = NULL;
|
||||
|
||||
tor_assert(options);
|
||||
tor_assert(ports);
|
||||
|
||||
/* No metrics port to configure, just move on . */
|
||||
if (!options->MetricsPort_lines) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
elems = smartlist_new();
|
||||
|
||||
/* Split between the protocol and the address/port. */
|
||||
num_elems = smartlist_split_string(elems,
|
||||
options->MetricsPort_lines->value, " ",
|
||||
SPLIT_SKIP_SPACE | SPLIT_IGNORE_BLANK, 2);
|
||||
if (num_elems < 1) {
|
||||
*err_msg_out = tor_strdup("MetricsPort is missing port.");
|
||||
goto end;
|
||||
}
|
||||
|
||||
addrport_str = smartlist_get(elems, 0);
|
||||
if (num_elems >= 2) {
|
||||
/* Parse the format if any. */
|
||||
fmt_str = smartlist_get(elems, 1);
|
||||
if (!strcasecmp(fmt_str, "prometheus")) {
|
||||
the_format = METRICS_FORMAT_PROMETHEUS;
|
||||
} else {
|
||||
tor_asprintf(err_msg_out, "MetricsPort unknown format: %s", fmt_str);
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
|
||||
/* Port configuration with default address. */
|
||||
cfg = port_cfg_new(0);
|
||||
cfg->type = CONN_TYPE_METRICS_LISTENER;
|
||||
|
||||
/* Parse the port first. Then an address if any can be found. */
|
||||
cfg->port = (int) tor_parse_long(addrport_str, 10, 0, 65535, &ok, NULL);
|
||||
if (ok) {
|
||||
tor_addr_parse(&cfg->addr, "127.0.0.1");
|
||||
} else {
|
||||
/* We probably have a host:port situation */
|
||||
if (tor_addr_port_lookup(addrport_str, &cfg->addr,
|
||||
(uint16_t *) &cfg->port) < 0) {
|
||||
*err_msg_out = tor_strdup("MetricsPort address/port failed to parse or "
|
||||
"resolve.");
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
/* Add it to the ports list. */
|
||||
smartlist_add(ports, cfg);
|
||||
|
||||
/* It is set. MetricsPort doesn't support the NoListen options or such that
|
||||
* would prevent from being a real listener port. */
|
||||
options->MetricsPort_set = 1;
|
||||
|
||||
/* Success. */
|
||||
ret = 0;
|
||||
|
||||
end:
|
||||
if (ret != 0) {
|
||||
port_cfg_free(cfg);
|
||||
}
|
||||
SMARTLIST_FOREACH(elems, char *, e, tor_free(e));
|
||||
smartlist_free(elems);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/** Initialize the subsystem. */
|
||||
void
|
||||
metrics_init(void)
|
||||
|
@ -9,13 +9,27 @@
|
||||
#ifndef TOR_FEATURE_METRICS_METRICS_H
|
||||
#define TOR_FEATURE_METRICS_METRICS_H
|
||||
|
||||
#include "lib/buf/buffers.h"
|
||||
#include "lib/container/smartlist.h"
|
||||
|
||||
#include "app/config/or_options_st.h"
|
||||
|
||||
#include "lib/metrics/metrics_common.h"
|
||||
|
||||
struct connection_t;
|
||||
|
||||
/* Initializer / Cleanup. */
|
||||
void metrics_init(void);
|
||||
void metrics_cleanup(void);
|
||||
|
||||
/* Accessors. */
|
||||
char *metrics_get_output(const metrics_format_t fmt);
|
||||
buf_t *metrics_get_output(const metrics_format_t fmt);
|
||||
|
||||
/* Connection. */
|
||||
int metrics_connection_process_inbuf(struct connection_t *conn);
|
||||
|
||||
/* Configuration. */
|
||||
int metrics_parse_ports(or_options_t *options, smartlist_t *ports,
|
||||
char **err_msg_out);
|
||||
|
||||
#endif /* !defined(TOR_FEATURE_METRICS_METRICS_H) */
|
||||
|
Loading…
Reference in New Issue
Block a user