Tor  0.4.7.0-alpha-dev
hs_metrics.c
Go to the documentation of this file.
1 /* Copyright (c) 2020-2021, The Tor Project, Inc. */
2 /* See LICENSE for licensing information */
3 
4 /**
5  * @file hs_metrics.c
6  * @brief Onion service metrics exposed through the MetricsPort
7  **/
8 
9 #define HS_METRICS_ENTRY_PRIVATE
10 
11 #include "orconfig.h"
12 
13 #include "lib/malloc/malloc.h"
16 
17 #include "feature/hs/hs_metrics.h"
19 #include "feature/hs/hs_service.h"
20 
21 /** Return a static buffer pointer that contains the port as a string.
22  *
23  * Subsequent call to this function invalidates the previous buffer. */
24 static const char *
25 port_to_str(const uint16_t port)
26 {
27  static char buf[8];
28  tor_snprintf(buf, sizeof(buf), "%u", port);
29  return buf;
30 }
31 
32 /** Initialize a metrics store for the given service.
33  *
34  * Essentially, this goes over the base_metrics array and adds them all to the
35  * store set with their label(s) if any. */
36 static void
38 {
39  metrics_store_t *store;
40 
41  tor_assert(service);
42 
43  store = service->metrics.store;
44 
45  for (size_t i = 0; i < base_metrics_size; ++i) {
46  metrics_store_entry_t *entry =
48  base_metrics[i].help);
49 
50  /* Add labels to the entry. */
52  metrics_format_label("onion", service->onion_address));
53  if (base_metrics[i].port_as_label && service->config.ports) {
55  const hs_port_config_t *, p) {
57  metrics_format_label("port", port_to_str(p->virtual_port)));
58  } SMARTLIST_FOREACH_END(p);
59  }
60  }
61 }
62 
63 /** Update the metrics key entry in the store in the given service. The port,
64  * if non 0, is used to find the correct metrics entry. The value n is the
65  * value used to update the entry. */
66 void
67 hs_metrics_update_by_service(const hs_metrics_key_t key,
68  hs_service_t *service, const uint16_t port,
69  int64_t n)
70 {
71  tor_assert(service);
72 
73  /* Get the metrics entry in the store. */
74  smartlist_t *entries = metrics_store_get_all(service->metrics.store,
75  base_metrics[key].name);
76  if (BUG(!entries)) {
77  return;
78  }
79 
80  /* We need to find the right metrics entry by finding the port label if any.
81  *
82  * XXX: This is not the most optimal due to the string format. Maybe at some
83  * point turn this into a kvline and a map in a metric entry? */
84  SMARTLIST_FOREACH_BEGIN(entries, metrics_store_entry_t *, entry) {
85  if (port == 0 ||
87  metrics_format_label("port", port_to_str(port)))) {
89  break;
90  }
91  } SMARTLIST_FOREACH_END(entry);
92 }
93 
94 /** Update the metrics key entry in the store of a service identified by the
95  * given identity public key. The port, if non 0, is used to find the correct
96  * metrics entry. The value n is the value used to update the entry.
97  *
98  * This is used by callsite that have access to the key but not the service
99  * object so an extra lookup is done to find the service. */
100 void
101 hs_metrics_update_by_ident(const hs_metrics_key_t key,
102  const ed25519_public_key_t *ident_pk,
103  const uint16_t port, int64_t n)
104 {
105  hs_service_t *service;
106 
107  tor_assert(ident_pk);
108 
109  service = hs_service_find(ident_pk);
110  if (!service) {
111  /* This is possible because an onion service client can end up here due to
112  * having an identity key onto a connection _to_ an onion service. We
113  * can't differentiate that from an actual onion service initiated by a
114  * service and thus the only way to know is to lookup the service. */
115  return;
116  }
117  hs_metrics_update_by_service(key, service, port, n);
118 }
119 
120 /** Return a list of all the onion service metrics stores. This is the
121  * function attached to the .get_metrics() member of the subsys_t. */
122 const smartlist_t *
124 {
125  /* We can't have the caller to free the returned list so keep it static,
126  * simply update it. */
127  static smartlist_t *stores_list = NULL;
128 
129  smartlist_free(stores_list);
130  stores_list = hs_service_get_metrics_stores();
131  return stores_list;
132 }
133 
134 /** Initialize the metrics store in the given service. */
135 void
137 {
138  tor_assert(service);
139 
140  /* This function is called when we register a service and so it could either
141  * be a new service or a service that was just reloaded through a HUP signal
142  * for instance. Thus, it is possible that the service has already an
143  * initialized store. If so, just return. */
144  if (service->metrics.store) {
145  return;
146  }
147 
148  service->metrics.store = metrics_store_new();
149  init_store(service);
150 }
151 
152 /** Free the metrics store in the given service. */
153 void
155 {
156  tor_assert(service);
157 
158  metrics_store_free(service->metrics.store);
159 }
const char * name
Definition: config.c:2434
void hs_metrics_update_by_ident(const hs_metrics_key_t key, const ed25519_public_key_t *ident_pk, const uint16_t port, int64_t n)
Definition: hs_metrics.c:101
static const char * port_to_str(const uint16_t port)
Definition: hs_metrics.c:25
void hs_metrics_service_free(hs_service_t *service)
Definition: hs_metrics.c:154
void hs_metrics_update_by_service(const hs_metrics_key_t key, hs_service_t *service, const uint16_t port, int64_t n)
Definition: hs_metrics.c:67
void hs_metrics_service_init(hs_service_t *service)
Definition: hs_metrics.c:136
static void init_store(hs_service_t *service)
Definition: hs_metrics.c:37
const smartlist_t * hs_metrics_get_stores(void)
Definition: hs_metrics.c:123
Header for feature/hs/hs_metrics.c.
const hs_metrics_entry_t base_metrics[]
const size_t base_metrics_size
Header for feature/hs/hs_metrics_entry.c.
smartlist_t * hs_service_get_metrics_stores(void)
Definition: hs_service.c:4264
hs_service_t * hs_service_find(const ed25519_public_key_t *identity_pk)
Definition: hs_service.c:4280
Header file containing service data for the HS subsystem.
Headers for util_malloc.c.
const char * metrics_format_label(const char *key, const char *value)
smartlist_t * metrics_store_get_all(const metrics_store_t *store, const char *name)
Definition: metrics_store.c:98
metrics_store_entry_t * metrics_store_add(metrics_store_t *store, metrics_type_t type, const char *name, const char *help)
metrics_store_t * metrics_store_new(void)
Definition: metrics_store.c:74
Header for lib/metrics/metrics_store.c.
void metrics_store_entry_update(metrics_store_entry_t *entry, const int64_t value)
void metrics_store_entry_add_label(metrics_store_entry_t *entry, const char *label)
bool metrics_store_entry_has_label(const metrics_store_entry_t *entry, const char *label)
int tor_snprintf(char *str, size_t size, const char *format,...)
Definition: printf.c:27
Header for smartlist.c.
#define SMARTLIST_FOREACH_BEGIN(sl, type, var)
smartlist_t * ports
Definition: hs_service.h:214
metrics_store_t * store
Definition: hs_service.h:41
char onion_address[HS_SERVICE_ADDR_LEN_BASE32+1]
Definition: hs_service.h:300
hs_service_config_t config
Definition: hs_service.h:313
hs_service_metrics_t metrics
Definition: hs_service.h:321
#define tor_assert(expr)
Definition: util_bug.h:102