Line data Source code
1 : /* Copyright (c) 2007-2021, The Tor Project, Inc. */
2 : /* See LICENSE for licensing information */
3 :
4 : /**
5 : * \file btrack_circuit.c
6 : * \brief Bootstrap tracker for origin circuits
7 : *
8 : * Track state changes of origin circuits, as published by the circuit
9 : * subsystem.
10 : **/
11 :
12 : #include "core/or/or.h"
13 :
14 : #include "core/or/ocirc_event.h"
15 :
16 : #include "feature/control/btrack_circuit.h"
17 : #include "feature/control/control.h"
18 : #include "lib/log/log.h"
19 :
20 : /** Pair of a best origin circuit GID with its state or status */
21 : typedef struct btc_best_t {
22 : uint32_t gid;
23 : int val;
24 : } btc_best_t;
25 :
26 : /** GID and state of the best origin circuit we've seen so far */
27 : static btc_best_t best_any_state = { 0, -1 };
28 : /** GID and state of the best application circuit we've seen so far */
29 : static btc_best_t best_ap_state = { 0, -1 };
30 : /** GID and status of the best origin circuit we've seen so far */
31 : static btc_best_t best_any_evtype = { 0, -1 };
32 : /** GID and status of the best application circuit we've seen so far */
33 : static btc_best_t best_ap_evtype = { 0, -1 };
34 :
35 : /** Reset cached "best" values */
36 : static void
37 235 : btc_reset_bests(void)
38 : {
39 235 : best_any_state.gid = best_ap_state.gid = 0;
40 235 : best_any_state.val = best_ap_state.val = -1;
41 235 : best_any_evtype.gid = best_ap_state.gid = 0;
42 235 : best_any_evtype.val = best_ap_evtype.val = -1;
43 235 : }
44 :
45 : /** True if @a state is a "better" origin circuit state than @a best->val */
46 : static bool
47 2 : btc_state_better(int state, const btc_best_t *best)
48 : {
49 2 : return state > best->val;
50 : }
51 :
52 : /**
53 : * Definine an ordering on circuit status events
54 : *
55 : * The CIRC_EVENT_ constants aren't sorted in a useful order, so this
56 : * array helps to decode them. This approach depends on the statuses
57 : * being nonnegative and dense.
58 : **/
59 : static int circ_event_order[] = {
60 : [CIRC_EVENT_FAILED] = -1,
61 : [CIRC_EVENT_CLOSED] = -1,
62 : [CIRC_EVENT_LAUNCHED] = 1,
63 : [CIRC_EVENT_EXTENDED] = 2,
64 : [CIRC_EVENT_BUILT] = 3,
65 : };
66 : #define N_CIRC_EVENT_ORDER \
67 : (sizeof(circ_event_order) / sizeof(circ_event_order[0]))
68 :
69 : /** True if @a state is a "better" origin circuit event status than @a
70 : best->val */
71 : static bool
72 2 : btc_evtype_better(int state, const btc_best_t *best)
73 : {
74 2 : if (state < 0)
75 : return false;
76 2 : if (best->val < 0)
77 : return true;
78 :
79 0 : tor_assert(state >= 0 && (unsigned)state < N_CIRC_EVENT_ORDER);
80 0 : tor_assert(best->val >= 0 && (unsigned)best->val < N_CIRC_EVENT_ORDER);
81 0 : return circ_event_order[state] > circ_event_order[best->val];
82 : }
83 :
84 : static bool
85 2 : btc_update_state(const ocirc_state_msg_t *msg, btc_best_t *best,
86 : const char *type)
87 : {
88 2 : if (btc_state_better(msg->state, best)) {
89 2 : log_info(LD_BTRACK, "CIRC BEST_%s state %d->%d gid=%"PRIu32, type,
90 : best->val, msg->state, msg->gid);
91 2 : best->gid = msg->gid;
92 2 : best->val = msg->state;
93 2 : return true;
94 : }
95 : return false;
96 : }
97 :
98 : static bool
99 2 : btc_update_evtype(const ocirc_cevent_msg_t *msg, btc_best_t *best,
100 : const char *type)
101 : {
102 2 : if (btc_evtype_better(msg->evtype, best)) {
103 2 : log_info(LD_BTRACK, "CIRC BEST_%s evtype %d->%d gid=%"PRIu32, type,
104 : best->val, msg->evtype, msg->gid);
105 2 : best->gid = msg->gid;
106 2 : best->val = msg->evtype;
107 2 : return true;
108 : }
109 : return false;
110 : }
111 :
112 1 : DECLARE_SUBSCRIBE(ocirc_state, btc_state_rcvr);
113 1 : DECLARE_SUBSCRIBE(ocirc_cevent, btc_cevent_rcvr);
114 8 : DECLARE_SUBSCRIBE(ocirc_chan, btc_chan_rcvr);
115 :
116 : static void
117 1 : btc_state_rcvr(const msg_t *msg, const ocirc_state_msg_t *arg)
118 : {
119 1 : (void)msg;
120 1 : log_debug(LD_BTRACK, "CIRC gid=%"PRIu32" state=%d onehop=%d",
121 : arg->gid, arg->state, arg->onehop);
122 :
123 1 : btc_update_state(arg, &best_any_state, "ANY");
124 1 : if (arg->onehop)
125 : return;
126 1 : btc_update_state(arg, &best_ap_state, "AP");
127 : }
128 :
129 : static void
130 1 : btc_cevent_rcvr(const msg_t *msg, const ocirc_cevent_msg_t *arg)
131 : {
132 1 : (void)msg;
133 1 : log_debug(LD_BTRACK, "CIRC gid=%"PRIu32" evtype=%d reason=%d onehop=%d",
134 : arg->gid, arg->evtype, arg->reason, arg->onehop);
135 :
136 1 : btc_update_evtype(arg, &best_any_evtype, "ANY");
137 1 : if (arg->onehop)
138 : return;
139 1 : btc_update_evtype(arg, &best_ap_evtype, "AP");
140 : }
141 :
142 : static void
143 8 : btc_chan_rcvr(const msg_t *msg, const ocirc_chan_msg_t *arg)
144 : {
145 8 : (void)msg;
146 8 : log_debug(LD_BTRACK, "CIRC gid=%"PRIu32" chan=%"PRIu64" onehop=%d",
147 : arg->gid, arg->chan, arg->onehop);
148 8 : }
149 :
150 : int
151 245 : btrack_circ_add_pubsub(pubsub_connector_t *connector)
152 : {
153 245 : if (DISPATCH_ADD_SUB(connector, ocirc, ocirc_chan))
154 : return -1;
155 245 : if (DISPATCH_ADD_SUB(connector, ocirc, ocirc_cevent))
156 : return -1;
157 245 : if (DISPATCH_ADD_SUB(connector, ocirc, ocirc_state))
158 0 : return -1;
159 : return 0;
160 : }
161 :
162 : void
163 235 : btrack_circ_fini(void)
164 : {
165 235 : btc_reset_bests();
166 235 : }
|