Line data Source code
1 : /* Copyright (c) 2007-2021, The Tor Project, Inc. */
2 : /* See LICENSE for licensing information */
3 :
4 : /**
5 : * \file btrack_orconn.c
6 : * \brief Bootstrap tracker for OR connections
7 : *
8 : * Track state changes of OR connections, as published by the
9 : * connection subsystem. Also track circuit launch events, because
10 : * they're one of the few ways to discover the association between a
11 : * channel (and OR connection) and a circuit.
12 : *
13 : * We track all OR connections that we receive events for, whether or
14 : * not they're carrying origin circuits. (An OR connection might
15 : * carry origin circuits only after we first find out about that
16 : * connection.)
17 : *
18 : * All origin ORCONN events update the "any" state variables, while
19 : * only application ORCONN events update the "ap" state variables (and
20 : * also update the "any") variables.
21 : *
22 : * We do this because we want to report the first increments of
23 : * connection progress as the earliest bootstrap phases. This results
24 : * in a better user experience because failures here translate into
25 : * zero or very small amounts of displayed progress, instead of
26 : * progress stuck near completion. The first connection to a relay
27 : * might be a one-hop circuit for directory lookups, or it might be a
28 : * connection for an application circuit because we already have
29 : * enough directory info to build an application circuit.
30 : *
31 : * We call functions in btrack_orconn_cevent.c to generate the actual
32 : * controller events, because some of the state decoding we need to do
33 : * is complicated.
34 : **/
35 :
36 : #include <stdbool.h>
37 :
38 : #include "core/or/or.h"
39 :
40 : #define BTRACK_ORCONN_PRIVATE
41 :
42 : #include "core/or/ocirc_event.h"
43 : #include "core/or/orconn_event.h"
44 : #include "feature/control/btrack_orconn.h"
45 : #include "feature/control/btrack_orconn_cevent.h"
46 : #include "feature/control/btrack_orconn_maps.h"
47 : #include "lib/log/log.h"
48 : #include "lib/pubsub/pubsub.h"
49 :
50 25 : DECLARE_SUBSCRIBE(orconn_state, bto_state_rcvr);
51 6 : DECLARE_SUBSCRIBE(orconn_status, bto_status_rcvr);
52 8 : DECLARE_SUBSCRIBE(ocirc_chan, bto_chan_rcvr);
53 :
54 : /** Pair of a best ORCONN GID and with its state */
55 : typedef struct bto_best_t {
56 : uint64_t gid;
57 : int state;
58 : } bto_best_t;
59 :
60 : /** GID and state of the best ORCONN we've seen so far */
61 : static bto_best_t best_any = { 0, -1 };
62 : /** GID and state of the best application circuit ORCONN we've seen so far */
63 : static bto_best_t best_ap = { 0, -1 };
64 :
65 : /**
66 : * Update a cached state of a best ORCONN progress we've seen so far.
67 : *
68 : * Return true if the new state is better than the old.
69 : **/
70 : static bool
71 39 : bto_update_best(const bt_orconn_t *bto, bto_best_t *best, const char *type)
72 : {
73 39 : if (bto->state < best->state)
74 : return false;
75 : /* Update even if we won't change best->state, because it's more
76 : * recent information that a particular connection transitioned to
77 : * that state. */
78 30 : best->gid = bto->gid;
79 30 : if (bto->state > best->state) {
80 28 : log_info(LD_BTRACK, "ORCONN BEST_%s state %d->%d gid=%"PRIu64, type,
81 : best->state, bto->state, bto->gid);
82 28 : best->state = bto->state;
83 28 : return true;
84 : }
85 : return false;
86 : }
87 :
88 : /**
89 : * Update cached states of best ORCONN progress we've seen
90 : *
91 : * Only update the application ORCONN state if we know it's carrying
92 : * an application circuit.
93 : **/
94 : static void
95 28 : bto_update_bests(const bt_orconn_t *bto)
96 : {
97 28 : tor_assert(bto->is_orig);
98 :
99 28 : if (bto_update_best(bto, &best_any, "ANY"))
100 17 : bto_cevent_anyconn(bto);
101 28 : if (!bto->is_onehop && bto_update_best(bto, &best_ap, "AP"))
102 11 : bto_cevent_apconn(bto);
103 28 : }
104 :
105 : /** Reset cached "best" values */
106 : static void
107 235 : bto_reset_bests(void)
108 : {
109 235 : best_any.gid = best_ap.gid = 0;
110 235 : best_any.state = best_ap.state = -1;
111 235 : }
112 :
113 : /**
114 : * Update cached states of ORCONNs from the incoming message. This
115 : * message comes from code in connection_or.c.
116 : **/
117 : static void
118 25 : bto_state_rcvr(const msg_t *msg, const orconn_state_msg_t *arg)
119 : {
120 25 : bt_orconn_t *bto;
121 :
122 25 : (void)msg;
123 25 : bto = bto_find_or_new(arg->gid, arg->chan);
124 25 : log_debug(LD_BTRACK, "ORCONN gid=%"PRIu64" chan=%"PRIu64
125 : " proxy_type=%d state=%d",
126 : arg->gid, arg->chan, arg->proxy_type, arg->state);
127 25 : bto->proxy_type = arg->proxy_type;
128 25 : bto->state = arg->state;
129 25 : if (bto->is_orig)
130 20 : bto_update_bests(bto);
131 25 : }
132 :
133 : /**
134 : * Delete a cached ORCONN state if we get an incoming message saying
135 : * the ORCONN is failed or closed. This message comes from code in
136 : * control.c.
137 : **/
138 : static void
139 6 : bto_status_rcvr(const msg_t *msg, const orconn_status_msg_t *arg)
140 : {
141 6 : (void)msg;
142 6 : switch (arg->status) {
143 5 : case OR_CONN_EVENT_FAILED:
144 : case OR_CONN_EVENT_CLOSED:
145 5 : log_info(LD_BTRACK, "ORCONN DELETE gid=%"PRIu64" status=%d reason=%d",
146 : arg->gid, arg->status, arg->reason);
147 5 : return bto_delete(arg->gid);
148 : default:
149 : break;
150 : }
151 : }
152 :
153 : /**
154 : * Create or update a cached ORCONN state for a newly launched
155 : * connection, including whether it's launched by an origin circuit
156 : * and whether it's a one-hop circuit.
157 : **/
158 : static void
159 8 : bto_chan_rcvr(const msg_t *msg, const ocirc_chan_msg_t *arg)
160 : {
161 8 : bt_orconn_t *bto;
162 :
163 8 : (void)msg;
164 8 : bto = bto_find_or_new(0, arg->chan);
165 8 : if (!bto->is_orig || (bto->is_onehop && !arg->onehop)) {
166 8 : log_debug(LD_BTRACK, "ORCONN LAUNCH chan=%"PRIu64" onehop=%d",
167 : arg->chan, arg->onehop);
168 : }
169 8 : bto->is_orig = true;
170 8 : if (!arg->onehop)
171 4 : bto->is_onehop = false;
172 8 : bto_update_bests(bto);
173 8 : }
174 :
175 : /**
176 : * Initialize the hash maps and subscribe to ORCONN and origin
177 : * circuit events.
178 : **/
179 : int
180 244 : btrack_orconn_init(void)
181 : {
182 244 : bto_init_maps();
183 :
184 244 : return 0;
185 : }
186 :
187 : int
188 245 : btrack_orconn_add_pubsub(pubsub_connector_t *connector)
189 : {
190 245 : if (DISPATCH_ADD_SUB(connector, orconn, orconn_state))
191 : return -1;
192 245 : if (DISPATCH_ADD_SUB(connector, orconn, orconn_status))
193 : return -1;
194 245 : if (DISPATCH_ADD_SUB(connector, ocirc, ocirc_chan))
195 0 : return -1;
196 : return 0;
197 : }
198 :
199 : /** Clear the hash maps and reset the "best" states */
200 : void
201 235 : btrack_orconn_fini(void)
202 : {
203 235 : bto_clear_maps();
204 235 : bto_reset_bests();
205 235 : bto_cevent_reset();
206 235 : }
|