Forward port changelog
[tor.git] / src / or / rephist.c
blob4537032803503f392e92ceca5d46fc6964888a1b
1 /* Copyright 2004 Roger Dingledine, Nick Mathewson. */
2 /* See LICENSE for licensing information */
3 /* $Id$ */
4 const char rephist_c_id[] = "$Id$";
6 /**
7 * \file rephist.c
8 * \brief Basic history functionality for reputation module.
9 **/
11 #include "or.h"
13 static void bw_arrays_init(void);
14 static void predicted_ports_init(void);
16 /** History of an OR-\>OR link. */
17 typedef struct link_history_t {
18 /** When did we start tracking this list? */
19 time_t since;
20 /** When did we most recently note a change to this link */
21 time_t changed;
22 /** How many times did extending from OR1 to OR2 succeed? */
23 unsigned long n_extend_ok;
24 /** How many times did extending from OR1 to OR2 fail? */
25 unsigned long n_extend_fail;
26 } link_history_t;
28 /** History of an OR. */
29 typedef struct or_history_t {
30 /** When did we start tracking this OR? */
31 time_t since;
32 /** When did we most recently note a change to this OR? */
33 time_t changed;
34 /** How many times did we successfully connect? */
35 unsigned long n_conn_ok;
36 /** How many times did we try to connect and fail?*/
37 unsigned long n_conn_fail;
38 /** How many seconds have we been connected to this OR before
39 * 'up_since'? */
40 unsigned long uptime;
41 /** How many seconds have we been unable to connect to this OR before
42 * 'down_since'? */
43 unsigned long downtime;
44 /** If nonzero, we have been connected since this time. */
45 time_t up_since;
46 /** If nonzero, we have been unable to connect since this time. */
47 time_t down_since;
48 /** Map from hex OR2 identity digest to a link_history_t for the link
49 * from this OR to OR2. */
50 strmap_t *link_history_map;
51 } or_history_t;
53 /** Map from hex OR identity digest to or_history_t. */
54 static strmap_t *history_map = NULL;
56 /** Return the or_history_t for the named OR, creating it if necessary.
58 static or_history_t *get_or_history(const char* id)
60 or_history_t *hist;
61 char hexid[HEX_DIGEST_LEN+1];
62 base16_encode(hexid, HEX_DIGEST_LEN+1, id, DIGEST_LEN);
64 if (!strcmp(hexid, "0000000000000000000000000000000000000000"))
65 return NULL;
67 hist = (or_history_t*) strmap_get(history_map, hexid);
68 if (!hist) {
69 hist = tor_malloc_zero(sizeof(or_history_t));
70 hist->link_history_map = strmap_new();
71 hist->since = hist->changed = time(NULL);
72 strmap_set(history_map, hexid, hist);
74 return hist;
77 /** Return the link_history_t for the link from the first named OR to
78 * the second, creating it if necessary. (ORs are identified by
79 * identity digest)
81 static link_history_t *get_link_history(const char *from_id,
82 const char *to_id)
84 or_history_t *orhist;
85 link_history_t *lhist;
86 char to_hexid[HEX_DIGEST_LEN+1];
87 orhist = get_or_history(from_id);
88 if (!orhist)
89 return NULL;
90 base16_encode(to_hexid, HEX_DIGEST_LEN+1, to_id, DIGEST_LEN);
91 if (!strcmp(to_hexid, "0000000000000000000000000000000000000000"))
92 return NULL;
93 lhist = (link_history_t*) strmap_get(orhist->link_history_map, to_hexid);
94 if (!lhist) {
95 lhist = tor_malloc_zero(sizeof(link_history_t));
96 lhist->since = lhist->changed = time(NULL);
97 strmap_set(orhist->link_history_map, to_hexid, lhist);
99 return lhist;
102 static void
103 _free_link_history(void *val)
105 tor_free(val);
108 static void
109 free_or_history(or_history_t *hist)
111 strmap_free(hist->link_history_map, _free_link_history);
112 tor_free(hist);
115 /** Update an or_history_t object <b>hist</b> so that its uptime/downtime
116 * count is up-to-date as of <b>when</b>.
118 static void update_or_history(or_history_t *hist, time_t when)
120 tor_assert(hist);
121 if (hist->up_since) {
122 tor_assert(!hist->down_since);
123 hist->uptime += (when - hist->up_since);
124 hist->up_since = when;
125 } else if (hist->down_since) {
126 hist->downtime += (when - hist->down_since);
127 hist->down_since = when;
131 /** Initialize the static data structures for tracking history.
133 void rep_hist_init(void)
135 history_map = strmap_new();
136 bw_arrays_init();
137 predicted_ports_init();
140 /** Remember that an attempt to connect to the OR with identity digest
141 * <b>id</b> failed at <b>when</b>.
143 void rep_hist_note_connect_failed(const char* id, time_t when)
145 or_history_t *hist;
146 hist = get_or_history(id);
147 if (!hist)
148 return;
149 ++hist->n_conn_fail;
150 if (hist->up_since) {
151 hist->uptime += (when - hist->up_since);
152 hist->up_since = 0;
154 if (!hist->down_since)
155 hist->down_since = when;
156 hist->changed = when;
159 /** Remember that an attempt to connect to the OR with identity digest
160 * <b>id</b> succeeded at <b>when</b>.
162 void rep_hist_note_connect_succeeded(const char* id, time_t when)
164 or_history_t *hist;
165 hist = get_or_history(id);
166 if (!hist)
167 return;
168 ++hist->n_conn_ok;
169 if (hist->down_since) {
170 hist->downtime += (when - hist->down_since);
171 hist->down_since = 0;
173 if (!hist->up_since)
174 hist->up_since = when;
175 hist->changed = when;
178 /** Remember that we intentionally closed our connection to the OR
179 * with identity digest <b>id</b> at <b>when</b>.
181 void rep_hist_note_disconnect(const char* id, time_t when)
183 or_history_t *hist;
184 hist = get_or_history(id);
185 if (!hist)
186 return;
187 ++hist->n_conn_ok;
188 if (hist->up_since) {
189 hist->uptime += (when - hist->up_since);
190 hist->up_since = 0;
192 hist->changed = when;
195 /** Remember that our connection to the OR with identity digest
196 * <b>id</b> had an error and stopped working at <b>when</b>.
198 void rep_hist_note_connection_died(const char* id, time_t when)
200 or_history_t *hist;
201 if (!id) {
202 /* XXXX009 Well, everybody has an ID now. Hm. */
203 /* If conn has no nickname, it's either an OP, or it is an OR
204 * which didn't complete its handshake (or did and was unapproved).
205 * Ignore it.
207 return;
209 hist = get_or_history(id);
210 if (!hist)
211 return;
212 if (hist->up_since) {
213 hist->uptime += (when - hist->up_since);
214 hist->up_since = 0;
216 if (!hist->down_since)
217 hist->down_since = when;
218 hist->changed = when;
221 /** Remember that we successfully extended from the OR with identity
222 * digest <b>from_id</b> to the OR with identity digest
223 * <b>to_name</b>.
225 void rep_hist_note_extend_succeeded(const char *from_id,
226 const char *to_id)
228 link_history_t *hist;
229 /* log_fn(LOG_WARN, "EXTEND SUCCEEDED: %s->%s",from_name,to_name); */
230 hist = get_link_history(from_id, to_id);
231 if (!hist)
232 return;
233 ++hist->n_extend_ok;
234 hist->changed = time(NULL);
237 /** Remember that we tried to extend from the OR with identity digest
238 * <b>from_id</b> to the OR with identity digest <b>to_name</b>, but
239 * failed.
241 void rep_hist_note_extend_failed(const char *from_id, const char *to_id)
243 link_history_t *hist;
244 /* log_fn(LOG_WARN, "EXTEND FAILED: %s->%s",from_name,to_name); */
245 hist = get_link_history(from_id, to_id);
246 if (!hist)
247 return;
248 ++hist->n_extend_fail;
249 hist->changed = time(NULL);
252 /** Log all the reliability data we have remembered, with the chosen
253 * severity.
255 void rep_hist_dump_stats(time_t now, int severity)
257 strmap_iter_t *lhist_it;
258 strmap_iter_t *orhist_it;
259 const char *name1, *name2, *hexdigest1, *hexdigest2;
260 or_history_t *or_history;
261 link_history_t *link_history;
262 void *or_history_p, *link_history_p;
263 double uptime;
264 char buffer[2048];
265 size_t len;
266 int ret;
267 unsigned long upt, downt;
268 routerinfo_t *r;
270 rep_history_clean(now-24*60*60);
272 log(severity, "--------------- Dumping history information:");
274 for (orhist_it = strmap_iter_init(history_map); !strmap_iter_done(orhist_it);
275 orhist_it = strmap_iter_next(history_map,orhist_it)) {
276 strmap_iter_get(orhist_it, &hexdigest1, &or_history_p);
277 or_history = (or_history_t*) or_history_p;
279 if ((r = router_get_by_hexdigest(hexdigest1)))
280 name1 = r->nickname;
281 else
282 name1 = "(unknown)";
284 update_or_history(or_history, now);
285 upt = or_history->uptime;
286 downt = or_history->downtime;
287 if (upt+downt) {
288 uptime = ((double)upt) / (upt+downt);
289 } else {
290 uptime=1.0;
292 log(severity,
293 "OR %s [%s]: %ld/%ld good connections; uptime %ld/%ld sec (%.2f%%)",
294 name1, hexdigest1,
295 or_history->n_conn_ok, or_history->n_conn_fail+or_history->n_conn_ok,
296 upt, upt+downt, uptime*100.0);
298 if (!strmap_isempty(or_history->link_history_map)) {
299 strlcpy(buffer, " Extend attempts: ", sizeof(buffer));
300 len = strlen(buffer);
301 for (lhist_it = strmap_iter_init(or_history->link_history_map);
302 !strmap_iter_done(lhist_it);
303 lhist_it = strmap_iter_next(or_history->link_history_map, lhist_it)) {
304 strmap_iter_get(lhist_it, &hexdigest2, &link_history_p);
305 if ((r = router_get_by_hexdigest(hexdigest2)))
306 name2 = r->nickname;
307 else
308 name2 = "(unknown)";
310 link_history = (link_history_t*) link_history_p;
312 ret = tor_snprintf(buffer+len, 2048-len, "%s(%ld/%ld); ", name2,
313 link_history->n_extend_ok,
314 link_history->n_extend_ok+link_history->n_extend_fail);
315 if (ret<0)
316 break;
317 else
318 len += ret;
320 log(severity, "%s", buffer);
325 /** Remove history info for routers/links that haven't changed since
326 * <b>before</b> */
327 void rep_history_clean(time_t before)
329 or_history_t *or_history;
330 link_history_t *link_history;
331 void *or_history_p, *link_history_p;
332 strmap_iter_t *orhist_it, *lhist_it;
333 const char *hd1, *hd2;
335 orhist_it = strmap_iter_init(history_map);
336 while (!strmap_iter_done(orhist_it)) {
337 strmap_iter_get(orhist_it, &hd1, &or_history_p);
338 or_history = or_history_p;
339 if (or_history->changed < before) {
340 free_or_history(or_history);
341 orhist_it = strmap_iter_next_rmv(history_map, orhist_it);
342 continue;
344 for (lhist_it = strmap_iter_init(or_history->link_history_map);
345 !strmap_iter_done(lhist_it); ) {
346 strmap_iter_get(lhist_it, &hd2, &link_history_p);
347 link_history = link_history_p;
348 if (link_history->changed < before) {
349 tor_free(link_history);
350 lhist_it = strmap_iter_next_rmv(or_history->link_history_map,lhist_it);
351 continue;
353 lhist_it = strmap_iter_next(or_history->link_history_map,lhist_it);
355 orhist_it = strmap_iter_next(history_map, orhist_it);
359 #if 0
360 void write_rep_history(const char *filename)
362 FILE *f = NULL;
363 char *tmpfile;
364 int completed = 0;
365 or_history_t *or_history;
366 link_history_t *link_history;
367 strmap_iter_t *lhist_it;
368 strmap_iter_t *orhist_it;
369 void *or_history_p, *link_history_p;
370 const char *name1;
372 tmpfile = tor_malloc(strlen(filename)+5);
373 tor_snprintf(tmpfile, strlen(filename)+5, "%s_tmp", filename);
375 f = fopen(tmpfile, "w");
376 if (!f) goto done;
377 for (orhist_it = strmap_iter_init(history_map); !strmap_iter_done(orhist_it);
378 orhist_it = strmap_iter_next(history_map,orhist_it)) {
379 strmap_iter_get(orhist_it, &name1, &or_history_p);
380 or_history = (or_history_t*) or_history_p;
381 fprintf(f, "link %s connected:u%ld failed:%uld uptime:%uld",
382 name1, or_history->since1,
385 done:
386 if (f)
387 fclose(f);
388 if (completed)
389 replace_file(filename, tmpfile);
390 else
391 unlink(tmpfile);
392 tor_free(tmpfile);
394 #endif
396 #define NUM_SECS_ROLLING_MEASURE 10
397 #define NUM_SECS_BW_SUM_IS_VALID (24*60*60) /* one day */
398 #define NUM_SECS_BW_SUM_INTERVAL (15*60)
399 #define NUM_TOTALS (NUM_SECS_BW_SUM_IS_VALID/NUM_SECS_BW_SUM_INTERVAL)
402 * Structure to track bandwidth use, and remember the maxima for a given
403 * time period.
405 typedef struct bw_array_t {
406 /** Observation array: Total number of bytes transferred in each of the last
407 * NUM_SECS_ROLLING_MEASURE seconds. This is used as a circular array. */
408 int obs[NUM_SECS_ROLLING_MEASURE];
409 int cur_obs_idx; /**< Current position in obs. */
410 time_t cur_obs_time; /**< Time represented in obs[cur_obs_idx] */
411 int total_obs; /**< Total for all members of obs except obs[cur_obs_idx] */
412 int max_total; /**< Largest value that total_obs has taken on in the current
413 * period. */
414 int total_in_period; /**< Total bytes transferred in the current period. */
416 /** When does the next period begin? */
417 time_t next_period;
418 /** Where in 'maxima' should the maximum bandwidth usage for the current
419 * period be stored? */
420 int next_max_idx;
421 /** How many values in maxima/totals have been set ever? */
422 int num_maxes_set;
423 /** Circular array of the maximum
424 * bandwidth-per-NUM_SECS_ROLLING_MEASURE usage for the last
425 * NUM_TOTALS periods */
426 int maxima[NUM_TOTALS];
427 /** Circular array of the total bandwidth usage for the last NUM_TOTALS
428 * periods */
429 int totals[NUM_TOTALS];
430 } bw_array_t;
432 /** Shift the current period of b forward by one.
434 static void commit_max(bw_array_t *b) {
435 /* Store total from current period. */
436 b->totals[b->next_max_idx] = b->total_in_period;
437 /* Store maximum from current period. */
438 b->maxima[b->next_max_idx++] = b->max_total;
439 /* Advance next_period and next_max_idx */
440 b->next_period += NUM_SECS_BW_SUM_INTERVAL;
441 if (b->next_max_idx == NUM_TOTALS)
442 b->next_max_idx = 0;
443 if (b->num_maxes_set < NUM_TOTALS)
444 ++b->num_maxes_set;
445 /* Reset max_total. */
446 b->max_total = 0;
447 /* Reset total_in_period. */
448 b->total_in_period = 0;
451 /** Shift the current observation time of 'b' forward by one second.
453 static INLINE void advance_obs(bw_array_t *b) {
454 int nextidx;
455 int total;
457 /* Calculate the total bandwidth for the last NUM_SECS_ROLLING_MEASURE
458 * seconds; adjust max_total as needed.*/
459 total = b->total_obs + b->obs[b->cur_obs_idx];
460 if (total > b->max_total)
461 b->max_total = total;
463 nextidx = b->cur_obs_idx+1;
464 if (nextidx == NUM_SECS_ROLLING_MEASURE)
465 nextidx = 0;
467 b->total_obs = total - b->obs[nextidx];
468 b->obs[nextidx]=0;
469 b->cur_obs_idx = nextidx;
471 if (++b->cur_obs_time >= b->next_period)
472 commit_max(b);
475 /** Add 'n' bytes to the number of bytes in b for second 'when'.
477 static INLINE void add_obs(bw_array_t *b, time_t when, int n) {
478 /* Don't record data in the past. */
479 if (when<b->cur_obs_time)
480 return;
481 /* If we're currently adding observations for an earlier second than
482 * 'when', advance b->cur_obs_time and b->cur_obs_idx by an
483 * appropriate number of seconds, and do all the other housekeeping */
484 while (when>b->cur_obs_time)
485 advance_obs(b);
487 b->obs[b->cur_obs_idx] += n;
488 b->total_in_period += n;
491 /** Allocate, initialize, and return a new bw_array.
493 static bw_array_t *bw_array_new(void) {
494 bw_array_t *b;
495 time_t start;
496 b = tor_malloc_zero(sizeof(bw_array_t));
497 start = time(NULL);
498 b->cur_obs_time = start;
499 b->next_period = start + NUM_SECS_BW_SUM_INTERVAL;
500 return b;
503 static bw_array_t *read_array = NULL;
504 static bw_array_t *write_array = NULL;
506 /** Set up read_array and write_array
508 static void bw_arrays_init(void)
510 read_array = bw_array_new();
511 write_array = bw_array_new();
514 /** We read <b>num_bytes</b> more bytes in second <b>when</b>.
516 * Add num_bytes to the current running total for <b>when</b>.
518 * <b>when</b> can go back to time, but it's safe to ignore calls
519 * earlier than the latest <b>when</b> you've heard of.
521 void rep_hist_note_bytes_written(int num_bytes, time_t when) {
522 /* Maybe a circular array for recent seconds, and step to a new point
523 * every time a new second shows up. Or simpler is to just to have
524 * a normal array and push down each item every second; it's short.
526 /* When a new second has rolled over, compute the sum of the bytes we've
527 * seen over when-1 to when-1-NUM_SECS_ROLLING_MEASURE, and stick it
528 * somewhere. See rep_hist_bandwidth_assess() below.
530 add_obs(write_array, when, num_bytes);
533 /** We wrote <b>num_bytes</b> more bytes in second <b>when</b>.
534 * (like rep_hist_note_bytes_written() above)
536 void rep_hist_note_bytes_read(int num_bytes, time_t when) {
537 /* if we're smart, we can make this func and the one above share code */
538 add_obs(read_array, when, num_bytes);
541 /** Helper: Return the largest value in b->maxima. (This is equal to the
542 * most bandwidth used in any NUM_SECS_ROLLING_MEASURE period for the last
543 * NUM_SECS_BW_SUM_IS_VALID seconds.)
545 static int find_largest_max(bw_array_t *b)
547 int i,max;
548 max=0;
549 for (i=0; i<NUM_TOTALS; ++i) {
550 if (b->maxima[i]>max)
551 max = b->maxima[i];
553 return max;
557 * Find the largest sums in the past NUM_SECS_BW_SUM_IS_VALID (roughly)
558 * seconds. Find one sum for reading and one for writing. They don't have
559 * to be at the same time).
561 * Return the smaller of these sums, divided by NUM_SECS_ROLLING_MEASURE.
563 int rep_hist_bandwidth_assess(void) {
564 int w,r;
565 r = find_largest_max(read_array);
566 w = find_largest_max(write_array);
567 if (r>w)
568 return (int)(w/(double)NUM_SECS_ROLLING_MEASURE);
569 else
570 return (int)(r/(double)NUM_SECS_ROLLING_MEASURE);
572 return 0;
576 * Allocate and return lines for representing this server's bandwidth
577 * history in its descriptor.
579 char *
580 rep_hist_get_bandwidth_lines(void)
582 char *buf, *cp;
583 char t[ISO_TIME_LEN+1];
584 int r, i, n;
585 bw_array_t *b;
586 size_t len;
588 /* opt (read|write)-history yyyy-mm-dd HH:MM:SS (n s) n,n,n,n,n... */
589 len = (60+12*NUM_TOTALS)*2;
590 buf = tor_malloc_zero(len);
591 cp = buf;
592 for (r=0;r<2;++r) {
593 b = r?read_array:write_array;
594 tor_assert(b);
595 format_iso_time(t, b->next_period-NUM_SECS_BW_SUM_INTERVAL);
596 tor_snprintf(cp, len-(cp-buf), "opt %s %s (%d s) ", r?"read-history ":"write-history", t,
597 NUM_SECS_BW_SUM_INTERVAL);
598 cp += strlen(cp);
600 if (b->num_maxes_set <= b->next_max_idx)
601 /* We haven't been through the circular array yet; time starts at i=0.*/
602 i = 0;
603 else
604 /* We've been around the array at least once. The next i to be
605 overwritten is the oldest. */
606 i = b->next_max_idx;
608 for (n=0; n<b->num_maxes_set; ++n,++i) {
609 while (i >= NUM_TOTALS) i -= NUM_TOTALS;
610 if (n==(b->num_maxes_set-1))
611 tor_snprintf(cp, len-(cp-buf), "%d", b->totals[i]);
612 else
613 tor_snprintf(cp, len-(cp-buf), "%d,", b->totals[i]);
614 cp += strlen(cp);
616 strlcat(cp, "\n", len-(cp-buf));
617 ++cp;
619 return buf;
622 /** A list of port numbers that have been used recently. */
623 static smartlist_t *predicted_ports_list=NULL;
624 /** The corresponding most recently used time for each port. */
625 static smartlist_t *predicted_ports_times=NULL;
627 static void add_predicted_port(uint16_t port, time_t now) {
628 uint16_t *tmp_port = tor_malloc(sizeof(uint16_t));
629 time_t *tmp_time = tor_malloc(sizeof(time_t));
630 *tmp_port = port;
631 *tmp_time = now;
632 smartlist_add(predicted_ports_list, tmp_port);
633 smartlist_add(predicted_ports_times, tmp_time);
636 static void predicted_ports_init(void) {
637 predicted_ports_list = smartlist_create();
638 predicted_ports_times = smartlist_create();
639 add_predicted_port(80, time(NULL)); /* add one to kickstart us */
642 /** Remember that <b>port</b> has been asked for as of time <b>now</b>.
643 * This is used for predicting what sorts of streams we'll make in the
644 * future and making circuits to anticipate that.
646 void rep_hist_note_used_port(uint16_t port, time_t now) {
647 int i;
648 uint16_t *tmp_port;
649 time_t *tmp_time;
651 tor_assert(predicted_ports_list);
652 tor_assert(predicted_ports_times);
654 if (!port) /* record nothing */
655 return;
657 for (i = 0; i < smartlist_len(predicted_ports_list); ++i) {
658 tmp_port = smartlist_get(predicted_ports_list, i);
659 tmp_time = smartlist_get(predicted_ports_times, i);
660 if (*tmp_port == port) {
661 *tmp_time = now;
662 return;
665 /* it's not there yet; we need to add it */
666 add_predicted_port(port, now);
669 #define PREDICTED_CIRCS_RELEVANCE_TIME (3600) /* 1 hour */
671 /** Return a pointer to the list of port numbers that
672 * are likely to be asked for in the near future.
674 * The caller promises not to mess with it.
676 smartlist_t *rep_hist_get_predicted_ports(time_t now) {
677 int i;
678 uint16_t *tmp_port;
679 time_t *tmp_time;
681 tor_assert(predicted_ports_list);
682 tor_assert(predicted_ports_times);
684 /* clean out obsolete entries */
685 for (i = 0; i < smartlist_len(predicted_ports_list); ++i) {
686 tmp_time = smartlist_get(predicted_ports_times, i);
687 if (*tmp_time + PREDICTED_CIRCS_RELEVANCE_TIME < now) {
688 tmp_port = smartlist_get(predicted_ports_list, i);
689 log_fn(LOG_DEBUG, "Expiring predicted port %d", *tmp_port);
690 smartlist_del(predicted_ports_list, i);
691 smartlist_del(predicted_ports_times, i);
692 tor_free(tmp_port);
693 tor_free(tmp_time);
694 i--;
697 return predicted_ports_list;
700 /** The last time at which we needed an internal circ. */
701 static time_t predicted_hidserv_time = 0;
702 /** The last time we needed an internal circ with good uptime. */
703 static time_t predicted_hidserv_uptime_time = 0;
704 /** The last time we needed an internal circ with good capacity. */
705 static time_t predicted_hidserv_capacity_time = 0;
707 /** Remember that we used an internal circ at time <b>now</b>. */
708 void rep_hist_note_used_hidserv(time_t now, int need_uptime, int need_capacity) {
709 predicted_hidserv_time = now;
710 if (need_uptime)
711 predicted_hidserv_uptime_time = now;
712 if (need_capacity)
713 predicted_hidserv_capacity_time = now;
716 /** Return 1 if we've used an internal circ recently; else return 0. */
717 int rep_hist_get_predicted_hidserv(time_t now, int *need_uptime, int *need_capacity) {
718 if (!predicted_hidserv_time) /* initialize it */
719 predicted_hidserv_time = now;
720 if (predicted_hidserv_time + PREDICTED_CIRCS_RELEVANCE_TIME < now)
721 return 0; /* too long ago */
722 if (predicted_hidserv_uptime_time + PREDICTED_CIRCS_RELEVANCE_TIME < now)
723 *need_uptime = 1;
724 if (predicted_hidserv_capacity_time + PREDICTED_CIRCS_RELEVANCE_TIME < now)
725 *need_capacity = 1;
726 return 1;
729 /* not used yet */
730 void rep_hist_note_used_resolve(time_t now) { }
731 int rep_hist_get_predicted_resolve(time_t now) { return 0; }