tor  0.4.2.0-alpha-dev
predict_ports.c
Go to the documentation of this file.
1 /* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
2  * Copyright (c) 2007-2019, The Tor Project, Inc. */
3 /* See LICENSE for licensing information */
4 
18 #include "core/or/or.h"
19 
20 #include "app/config/config.h"
21 #include "core/or/channelpadding.h"
22 #include "core/or/circuituse.h"
24 #include "feature/relay/selftest.h"
25 #include "feature/stats/predict_ports.h"
26 #include "lib/container/bitarray.h"
27 #include "lib/time/tvdiff.h"
28 
29 static size_t predicted_ports_total_alloc = 0;
30 
31 static void predicted_ports_alloc(void);
32 
36 typedef struct predicted_port_t {
38  uint16_t port;
40  time_t time;
42 
46 static time_t prediction_timeout=0;
48 static time_t last_prediction_add_time=0;
49 
53 int
55 {
56  time_t seconds_waited;
57  time_t seconds_left;
58 
59  /* Protect against overflow of return value. This can happen if the clock
60  * jumps backwards in time. Update the last prediction time (aka last
61  * active time) to prevent it. This update is preferable to using monotonic
62  * time because it prevents clock jumps into the past from simply causing
63  * very long idle timeouts while the monotonic time stands still. */
64  seconds_waited = time_diff(last_prediction_add_time, now);
65  if (seconds_waited == TIME_MAX) {
67  seconds_waited = 0;
68  }
69 
70  /* Protect against underflow of the return value. This can happen for very
71  * large periods of inactivity/system sleep. */
72  if (seconds_waited > prediction_timeout)
73  return 0;
74 
75  seconds_left = time_diff(seconds_waited, prediction_timeout);
76  if (BUG(seconds_left == TIME_MAX))
77  return INT_MAX;
78 
79  return (int)(seconds_left);
80 }
81 
86 static void
87 add_predicted_port(time_t now, uint16_t port)
88 {
89  predicted_port_t *pp = tor_malloc(sizeof(predicted_port_t));
90 
91  // If the list is empty, re-randomize predicted ports lifetime
92  if (!any_predicted_circuits(now)) {
94  (time_t)channelpadding_get_circuits_available_timeout();
95  }
96 
98 
99  log_info(LD_CIRC,
100  "New port prediction added. Will continue predictive circ building "
101  "for %d more seconds.",
103 
104  pp->port = port;
105  pp->time = now;
106  predicted_ports_total_alloc += sizeof(*pp);
108 }
109 
114 void
115 rep_hist_note_used_port(time_t now, uint16_t port)
116 {
118 
119  if (!port) /* record nothing */
120  return;
121 
123  if (pp->port == port) {
124  pp->time = now;
125 
127  log_info(LD_CIRC,
128  "New port prediction added. Will continue predictive circ "
129  "building for %d more seconds.",
131  return;
132  }
133  } SMARTLIST_FOREACH_END(pp);
134  /* it's not there yet; we need to add it */
135  add_predicted_port(now, port);
136 }
137 
141 smartlist_t *
143 {
144  int predicted_circs_relevance_time;
145  smartlist_t *out = smartlist_new();
147 
148  predicted_circs_relevance_time = (int)prediction_timeout;
149 
150  /* clean out obsolete entries */
152  if (pp->time + predicted_circs_relevance_time < now) {
153  log_debug(LD_CIRC, "Expiring predicted port %d", pp->port);
154 
155  predicted_ports_total_alloc -= sizeof(predicted_port_t);
156  tor_free(pp);
158  } else {
159  smartlist_add(out, tor_memdup(&pp->port, sizeof(uint16_t)));
160  }
161  } SMARTLIST_FOREACH_END(pp);
162  return out;
163 }
164 
169 void
171 {
172  /* Let's do this on O(N), not O(N^2). */
173  bitarray_t *remove_ports = bitarray_init_zero(UINT16_MAX);
174  SMARTLIST_FOREACH(rmv_ports, const uint16_t *, p,
175  bitarray_set(remove_ports, *p));
177  if (bitarray_is_set(remove_ports, pp->port)) {
178  tor_free(pp);
179  predicted_ports_total_alloc -= sizeof(*pp);
181  }
182  } SMARTLIST_FOREACH_END(pp);
183  bitarray_free(remove_ports);
184 }
185 
191 void
193 {
194  rep_hist_note_used_port(now, 80);
195 }
196 
198 static time_t predicted_internal_time = 0;
203 
205 void
206 rep_hist_note_used_internal(time_t now, int need_uptime, int need_capacity)
207 {
208  // If the list is empty, re-randomize predicted ports lifetime
209  if (!any_predicted_circuits(now)) {
210  prediction_timeout = channelpadding_get_circuits_available_timeout();
211  }
212 
214 
215  log_info(LD_CIRC,
216  "New port prediction added. Will continue predictive circ building "
217  "for %d more seconds.",
219 
221  if (need_uptime)
223  if (need_capacity)
225 }
226 
228 int
229 rep_hist_get_predicted_internal(time_t now, int *need_uptime,
230  int *need_capacity)
231 {
232  int predicted_circs_relevance_time;
233 
234  predicted_circs_relevance_time = (int)prediction_timeout;
235 
236  if (!predicted_internal_time) { /* initialize it */
240  }
241  if (predicted_internal_time + predicted_circs_relevance_time < now)
242  return 0; /* too long ago */
243  if (predicted_internal_uptime_time + predicted_circs_relevance_time >= now)
244  *need_uptime = 1;
245  // Always predict that we need capacity.
246  *need_capacity = 1;
247  return 1;
248 }
249 
252 int
254 {
255  int predicted_circs_relevance_time;
256  predicted_circs_relevance_time = (int)prediction_timeout;
257 
258  return smartlist_len(predicted_ports_list) ||
259  predicted_internal_time + predicted_circs_relevance_time >= now;
260 }
261 
263 int
265 {
266  const or_options_t *options = get_options();
267 
268  if (any_predicted_circuits(now))
269  return 0;
270 
271  /* see if we'll still need to build testing circuits */
272  if (server_mode(options) &&
273  (!check_whether_orport_reachable(options) ||
275  return 0;
276  if (!check_whether_dirport_reachable(options))
277  return 0;
278 
279  return 1;
280 }
281 
287 static void
289 {
290  predicted_ports_list = smartlist_new();
291 }
292 
293 void
294 predicted_ports_init(void)
295 {
297  add_predicted_port(time(NULL), 443); // Add a port to get us started
298 }
299 
303 void
305 {
307  return;
308  predicted_ports_total_alloc -=
309  smartlist_len(predicted_ports_list)*sizeof(predicted_port_t);
311  pp, tor_free(pp));
312  smartlist_free(predicted_ports_list);
313 }
static void add_predicted_port(time_t now, uint16_t port)
Definition: predict_ports.c:87
void rep_hist_note_used_internal(time_t now, int need_uptime, int need_capacity)
#define SMARTLIST_FOREACH_BEGIN(sl, type, var)
unsigned int bitarray_t
Definition: bitarray.h:30
static time_t predicted_internal_uptime_time
static time_t predicted_internal_time
Implements a variable-sized (but non-resizeable) bit-array.
int predicted_ports_prediction_time_remaining(time_t now)
Definition: predict_ports.c:54
void rep_hist_remove_predicted_ports(const smartlist_t *rmv_ports)
void smartlist_add(smartlist_t *sl, void *element)
int any_predicted_circuits(time_t now)
Header file for config.c.
struct predicted_port_t predicted_port_t
#define tor_free(p)
Definition: malloc.h:52
#define SMARTLIST_DEL_CURRENT(sl, var)
Header for tvdiff.c.
static time_t last_prediction_add_time
Definition: predict_ports.c:48
static void bitarray_set(bitarray_t *b, int bit)
Definition: bitarray.h:68
tor_assert(buffer)
#define LD_CIRC
Definition: log.h:79
Header file for routermode.c.
time_t time_diff(const time_t t1, const time_t t2)
Definition: tvdiff.c:181
static time_t prediction_timeout
Definition: predict_ports.c:46
Master header file for Tor-specific functionality.
int rep_hist_circbuilding_dormant(time_t now)
static time_t predicted_internal_capacity_time
int rep_hist_get_predicted_internal(time_t now, int *need_uptime, int *need_capacity)
static bitarray_t * bitarray_init_zero(unsigned int n_bits)
Definition: bitarray.h:33
Header file for circuituse.c.
smartlist_t * rep_hist_get_predicted_ports(time_t now)
#define SMARTLIST_FOREACH(sl, type, var, cmd)
static void predicted_ports_alloc(void)
void rep_hist_note_used_resolve(time_t now)
void rep_hist_note_used_port(time_t now, uint16_t port)
Header file for selftest.c.
void predicted_ports_free_all(void)
int circuit_enough_testing_circs(void)
Definition: circuituse.c:1621
static smartlist_t * predicted_ports_list
Definition: predict_ports.c:44
static unsigned int bitarray_is_set(bitarray_t *b, int bit)
Definition: bitarray.h:81
int check_whether_orport_reachable(const or_options_t *options)
Definition: selftest.c:75
int check_whether_dirport_reachable(const or_options_t *options)
Definition: selftest.c:92