circuituse.c 118 KB
Newer Older
Roger Dingledine's avatar
Roger Dingledine committed
1
2
/* Copyright (c) 2001 Matej Pfajfar.
 * Copyright (c) 2001-2004, Roger Dingledine.
3
 * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
Nick Mathewson's avatar
Nick Mathewson committed
4
 * Copyright (c) 2007-2018, The Tor Project, Inc. */
5
6
7
8
/* See LICENSE for licensing information */

/**
 * \file circuituse.c
9
10
11
12
13
14
15
16
 * \brief Launch the right sort of circuits and attach the right streams to
 * them.
 *
 * As distinct from circuitlist.c, which manages lookups to find circuits, and
 * circuitbuild.c, which handles the logistics of circuit construction, this
 * module keeps track of which streams can be attached to which circuits (in
 * circuit_get_best()), and attaches streams to circuits (with
 * circuit_try_attaching_streams(), connection_ap_handshake_attach_circuit(),
17
 * and connection_ap_handshake_attach_chosen_circuit() ).
18
19
20
21
22
23
24
25
26
27
 *
 * This module also makes sure that we are building circuits for all of the
 * predicted ports, using circuit_remove_handled_ports(),
 * circuit_stream_is_being_handled(), and circuit_build_needed_cirs().  It
 * handles launching circuits for specific targets using
 * circuit_launch_by_extend_info().
 *
 * This is also where we handle expiring circuits that have been around for
 * too long without actually completing, along with the circuit_build_timeout
 * logic in circuitstats.c.
28
29
 **/

30
#include "core/or/or.h"
31
32
#include "app/config/config.h"
#include "core/mainloop/connection.h"
33
34
35
36
37
38
#include "core/or/channel.h"
#include "core/or/circuitbuild.h"
#include "core/or/circuitlist.h"
#include "core/or/circuitstats.h"
#include "core/or/circuituse.h"
#include "core/or/connection_edge.h"
39
40
41
42
43
#include "core/or/policies.h"
#include "feature/client/addressmap.h"
#include "feature/client/bridges.h"
#include "feature/client/circpathbias.h"
#include "feature/client/entrynodes.h"
44
#include "feature/control/control.h"
45
#include "feature/dircommon/directory.h"
46
#include "feature/hs/hs_circuit.h"
47
48
#include "feature/hs/hs_client.h"
#include "feature/hs/hs_common.h"
49
50
#include "feature/hs/hs_ident.h"
#include "feature/hs/hs_stats.h"
51
#include "feature/nodelist/describe.h"
52
#include "feature/nodelist/networkstatus.h"
53
54
55
56
#include "feature/nodelist/nodelist.h"
#include "feature/nodelist/routerlist.h"
#include "feature/relay/routermode.h"
#include "feature/relay/selftest.h"
57
58
59
#include "feature/rend/rendclient.h"
#include "feature/rend/rendcommon.h"
#include "feature/rend/rendservice.h"
60
#include "feature/stats/predict_ports.h"
61
#include "lib/math/fp.h"
62
#include "lib/time/tvdiff.h"
63

64
65
66
67
68
69
70
#include "core/or/cpath_build_state_st.h"
#include "feature/dircommon/dir_connection_st.h"
#include "core/or/entry_connection_st.h"
#include "core/or/extend_info_st.h"
#include "core/or/or_circuit_st.h"
#include "core/or/origin_circuit_st.h"
#include "core/or/socks_request_st.h"
71

72
static void circuit_expire_old_circuits_clientside(void);
73
74
static void circuit_increment_failure_count(void);

75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
/** Check whether the hidden service destination of the stream at
 *  <b>edge_conn</b> is the same as the destination of the circuit at
 *  <b>origin_circ</b>. */
static int
circuit_matches_with_rend_stream(const edge_connection_t *edge_conn,
                                 const origin_circuit_t *origin_circ)
{
  /* Check if this is a v2 rendezvous circ/stream */
  if ((edge_conn->rend_data && !origin_circ->rend_data) ||
      (!edge_conn->rend_data && origin_circ->rend_data) ||
      (edge_conn->rend_data && origin_circ->rend_data &&
       rend_cmp_service_ids(rend_data_get_address(edge_conn->rend_data),
                            rend_data_get_address(origin_circ->rend_data)))) {
    /* this circ is not for this conn */
    return 0;
  }

  /* Check if this is a v3 rendezvous circ/stream */
  if ((edge_conn->hs_ident && !origin_circ->hs_ident) ||
      (!edge_conn->hs_ident && origin_circ->hs_ident) ||
      (edge_conn->hs_ident && origin_circ->hs_ident &&
       !ed25519_pubkey_eq(&edge_conn->hs_ident->identity_pk,
                          &origin_circ->hs_ident->identity_pk))) {
    /* this circ is not for this conn */
    return 0;
  }

  return 1;
}

105
/** Return 1 if <b>circ</b> could be returned by circuit_get_best().
106
107
 * Else return 0.
 */
108
static int
Nick Mathewson's avatar
Nick Mathewson committed
109
circuit_is_acceptable(const origin_circuit_t *origin_circ,
110
                      const entry_connection_t *conn,
111
112
                      int must_be_open, uint8_t purpose,
                      int need_uptime, int need_internal,
113
                      time_t now)
114
{
Nick Mathewson's avatar
Nick Mathewson committed
115
  const circuit_t *circ = TO_CIRCUIT(origin_circ);
116
  const node_t *exitnode;
117
  cpath_build_state_t *build_state;
118
119
120
  tor_assert(circ);
  tor_assert(conn);
  tor_assert(conn->socks_request);
121

122
  if (must_be_open && (circ->state != CIRCUIT_STATE_OPEN || !circ->n_chan))
123
124
125
126
127
    return 0; /* ignore non-open circs */
  if (circ->marked_for_close)
    return 0;

  /* if this circ isn't our purpose, skip. */
128
129
  if (purpose == CIRCUIT_PURPOSE_C_REND_JOINED && !must_be_open) {
    if (circ->purpose != CIRCUIT_PURPOSE_C_ESTABLISH_REND &&
130
131
132
        circ->purpose != CIRCUIT_PURPOSE_C_REND_READY &&
        circ->purpose != CIRCUIT_PURPOSE_C_REND_READY_INTRO_ACKED &&
        circ->purpose != CIRCUIT_PURPOSE_C_REND_JOINED)
133
      return 0;
134
135
  } else if (purpose == CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT &&
             !must_be_open) {
136
137
138
139
    if (circ->purpose != CIRCUIT_PURPOSE_C_INTRODUCING &&
        circ->purpose != CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT)
      return 0;
  } else {
140
    if (purpose != circ->purpose)
141
142
143
      return 0;
  }

144
145
146
147
148
  /* If this is a timed-out hidden service circuit, skip it. */
  if (origin_circ->hs_circ_has_timed_out) {
    return 0;
  }

149
  if (purpose == CIRCUIT_PURPOSE_C_GENERAL ||
150
151
      purpose == CIRCUIT_PURPOSE_C_HSDIR_GET ||
      purpose == CIRCUIT_PURPOSE_S_HSDIR_POST ||
152
      purpose == CIRCUIT_PURPOSE_HS_VANGUARDS ||
153
      purpose == CIRCUIT_PURPOSE_C_REND_JOINED) {
154
    if (circ->timestamp_dirty &&
155
       circ->timestamp_dirty+get_options()->MaxCircuitDirtiness <= now)
156
      return 0;
157
158
159
160
  }

  if (origin_circ->unusable_for_new_conns)
    return 0;
161

162
  /* decide if this circ is suitable for this conn */
163

164
  /* for rend circs, circ->cpath->prev is not the last router in the
165
   * circuit, it's the magical extra service hop. so just check the nickname
166
167
   * of the one we meant to finish at.
   */
Nick Mathewson's avatar
Nick Mathewson committed
168
  build_state = origin_circ->build_state;
169
  exitnode = build_state_get_exit_node(build_state);
170

171
  if (need_uptime && !build_state->need_uptime)
172
    return 0;
173
  if (need_internal != build_state->is_internal)
174
    return 0;
175

176
177
178
  if (purpose == CIRCUIT_PURPOSE_C_GENERAL ||
      purpose == CIRCUIT_PURPOSE_S_HSDIR_POST ||
      purpose == CIRCUIT_PURPOSE_C_HSDIR_GET) {
179
180
    tor_addr_t addr;
    const int family = tor_addr_parse(&addr, conn->socks_request->address);
181
    if (!exitnode && !build_state->onehop_tunnel) {
182
      log_debug(LD_CIRC,"Not considering circuit with unknown router.");
183
184
185
      return 0; /* this circuit is screwed and doesn't know it yet,
                 * or is a rendezvous circuit. */
    }
186
    if (build_state->onehop_tunnel) {
187
      if (!conn->want_onehop) {
188
189
190
        log_debug(LD_CIRC,"Skipping one-hop circuit.");
        return 0;
      }
191
192
193
      tor_assert(conn->chosen_exit_name);
      if (build_state->chosen_exit) {
        char digest[DIGEST_LEN];
194
195
        if (hexdigest_to_digest(conn->chosen_exit_name, digest) < 0)
          return 0; /* broken digest, we don't want it */
196
        if (tor_memneq(digest, build_state->chosen_exit->identity_digest,
197
                          DIGEST_LEN))
198
          return 0; /* this is a circuit to somewhere else */
199
200
        if (tor_digest_is_zero(digest)) {
          /* we don't know the digest; have to compare addr:port */
201
          if (family < 0 ||
202
              !tor_addr_eq(&build_state->chosen_exit->addr, &addr) ||
203
204
205
              build_state->chosen_exit->port != conn->socks_request->port)
            return 0;
        }
206
      }
207
    } else {
208
      if (conn->want_onehop) {
209
210
211
212
        /* don't use three-hop circuits -- that could hurt our anonymity. */
        return 0;
      }
    }
213
214
215
216
217
218
219
    if (origin_circ->prepend_policy && family != -1) {
      int r = compare_tor_addr_to_addr_policy(&addr,
                                              conn->socks_request->port,
                                              origin_circ->prepend_policy);
      if (r == ADDR_POLICY_REJECTED)
        return 0;
    }
220
    if (exitnode && !connection_ap_can_use_exit(conn, exitnode)) {
221
222
223
      /* can't exit from this router */
      return 0;
    }
224
  } else { /* not general: this might be a rend circuit */
225
    const edge_connection_t *edge_conn = ENTRY_TO_EDGE_CONN(conn);
226
    if (!circuit_matches_with_rend_stream(edge_conn, origin_circ)) {
227
      return 0;
228
229
    }
  }
Nick Mathewson's avatar
Nick Mathewson committed
230
231
232
233
234
235
236

  if (!connection_edge_compatible_with_circuit(conn, origin_circ)) {
    /* conn needs to be isolated from other conns that have already used
     * origin_circ */
    return 0;
  }

237
238
239
  return 1;
}

240
/** Return 1 if circuit <b>a</b> is better than circuit <b>b</b> for
Nick Mathewson's avatar
Nick Mathewson committed
241
 * <b>conn</b>, and return 0 otherwise. Used by circuit_get_best.
242
 */
243
static int
Nick Mathewson's avatar
Nick Mathewson committed
244
circuit_is_better(const origin_circuit_t *oa, const origin_circuit_t *ob,
245
                  const entry_connection_t *conn)
246
{
Nick Mathewson's avatar
Nick Mathewson committed
247
248
  const circuit_t *a = TO_CIRCUIT(oa);
  const circuit_t *b = TO_CIRCUIT(ob);
249
  const uint8_t purpose = ENTRY_TO_CONN(conn)->purpose;
Nick Mathewson's avatar
Nick Mathewson committed
250
  int a_bits, b_bits;
Nick Mathewson's avatar
Nick Mathewson committed
251

252
253
254
255
256
257
258
  /* If one of the circuits was allowed to live due to relaxing its timeout,
   * it is definitely worse (it's probably a much slower path). */
  if (oa->relaxed_timeout && !ob->relaxed_timeout)
    return 0; /* ob is better. It's not relaxed. */
  if (!oa->relaxed_timeout && ob->relaxed_timeout)
    return 1; /* oa is better. It's not relaxed. */

259
  switch (purpose) {
260
261
    case CIRCUIT_PURPOSE_S_HSDIR_POST:
    case CIRCUIT_PURPOSE_C_HSDIR_GET:
262
263
264
265
    case CIRCUIT_PURPOSE_C_GENERAL:
      /* if it's used but less dirty it's best;
       * else if it's more recently created it's best
       */
266
267
      if (b->timestamp_dirty) {
        if (a->timestamp_dirty &&
268
            a->timestamp_dirty > b->timestamp_dirty)
269
270
          return 1;
      } else {
271
        if (a->timestamp_dirty ||
272
            timercmp(&a->timestamp_began, &b->timestamp_began, OP_GT))
273
          return 1;
Nick Mathewson's avatar
Nick Mathewson committed
274
        if (ob->build_state->is_internal)
275
          /* XXXX++ what the heck is this internal thing doing here. I
Roger Dingledine's avatar
Roger Dingledine committed
276
277
278
           * think we can get rid of it. circuit_is_acceptable() already
           * makes sure that is_internal is exactly what we need it to
           * be. -RD */
279
          return 1;
280
281
282
283
      }
      break;
    case CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT:
      /* the closer it is to ack_wait the better it is */
284
      if (a->purpose > b->purpose)
285
286
287
288
        return 1;
      break;
    case CIRCUIT_PURPOSE_C_REND_JOINED:
      /* the closer it is to rend_joined the better it is */
289
      if (a->purpose > b->purpose)
290
291
292
        return 1;
      break;
  }
Nick Mathewson's avatar
Nick Mathewson committed
293

294
  /* XXXX Maybe this check should get a higher priority to avoid
Nick Mathewson's avatar
Nick Mathewson committed
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
   *   using up circuits too rapidly. */

  a_bits = connection_edge_update_circuit_isolation(conn,
                                                    (origin_circuit_t*)oa, 1);
  b_bits = connection_edge_update_circuit_isolation(conn,
                                                    (origin_circuit_t*)ob, 1);
  /* if x_bits < 0, then we have not used x for anything; better not to dirty
   * a connection if we can help it. */
  if (a_bits < 0) {
    return 0;
  } else if (b_bits < 0) {
    return 1;
  }
  a_bits &= ~ oa->isolation_flags_mixed;
  a_bits &= ~ ob->isolation_flags_mixed;
  if (n_bits_set_u8(a_bits) < n_bits_set_u8(b_bits)) {
    /* The fewer new restrictions we need to make on a circuit for stream
     * isolation, the better. */
    return 1;
  }

316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
  return 0;
}

/** Find the best circ that conn can use, preferably one which is
 * dirty. Circ must not be too old.
 *
 * Conn must be defined.
 *
 * If must_be_open, ignore circs not in CIRCUIT_STATE_OPEN.
 *
 * circ_purpose specifies what sort of circuit we must have.
 * It can be C_GENERAL, C_INTRODUCE_ACK_WAIT, or C_REND_JOINED.
 *
 * If it's REND_JOINED and must_be_open==0, then return the closest
 * rendezvous-purposed circuit that you can find.
 *
 * If it's INTRODUCE_ACK_WAIT and must_be_open==0, then return the
 * closest introduce-purposed circuit that you can find.
 */
335
static origin_circuit_t *
336
circuit_get_best(const entry_connection_t *conn,
Nick Mathewson's avatar
Nick Mathewson committed
337
                 int must_be_open, uint8_t purpose,
338
                 int need_uptime, int need_internal)
339
{
Nick Mathewson's avatar
Nick Mathewson committed
340
  origin_circuit_t *best=NULL;
341
  struct timeval now;
342
  int intro_going_on_but_too_old = 0;
343
344
345
346

  tor_assert(conn);

  tor_assert(purpose == CIRCUIT_PURPOSE_C_GENERAL ||
347
             purpose == CIRCUIT_PURPOSE_HS_VANGUARDS ||
348
349
             purpose == CIRCUIT_PURPOSE_C_HSDIR_GET ||
             purpose == CIRCUIT_PURPOSE_S_HSDIR_POST ||
350
351
352
             purpose == CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT ||
             purpose == CIRCUIT_PURPOSE_C_REND_JOINED);

353
354
  tor_gettimeofday(&now);

355
  SMARTLIST_FOREACH_BEGIN(circuit_get_global_list(), circuit_t *, circ) {
Nick Mathewson's avatar
Nick Mathewson committed
356
357
358
359
    origin_circuit_t *origin_circ;
    if (!CIRCUIT_IS_ORIGIN(circ))
      continue;
    origin_circ = TO_ORIGIN_CIRCUIT(circ);
360

Mike Perry's avatar
Mike Perry committed
361
362
    /* Log an info message if we're going to launch a new intro circ in
     * parallel */
363
    if (purpose == CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT &&
364
365
        !must_be_open && origin_circ->hs_circ_has_timed_out &&
        !circ->marked_for_close) {
Mike Perry's avatar
Mike Perry committed
366
367
        intro_going_on_but_too_old = 1;
        continue;
368
369
    }

Mike Perry's avatar
Mike Perry committed
370
    if (!circuit_is_acceptable(origin_circ,conn,must_be_open,purpose,
371
                               need_uptime,need_internal, (time_t)now.tv_sec))
Mike Perry's avatar
Mike Perry committed
372
373
      continue;

374
375
376
    /* now this is an acceptable circ to hand back. but that doesn't
     * mean it's the *best* circ to hand back. try to decide.
     */
Nick Mathewson's avatar
Nick Mathewson committed
377
    if (!best || circuit_is_better(origin_circ,best,conn))
Nick Mathewson's avatar
Nick Mathewson committed
378
      best = origin_circ;
379
  }
380
  SMARTLIST_FOREACH_END(circ);
381

382
383
384
385
386
  if (!best && intro_going_on_but_too_old)
    log_info(LD_REND|LD_CIRC, "There is an intro circuit being created "
             "right now, but it has already taken quite a while. Starting "
             "one in parallel.");

Nick Mathewson's avatar
Nick Mathewson committed
387
  return best;
388
389
}

390
391
392
393
394
395
/** Return the number of not-yet-open general-purpose origin circuits. */
static int
count_pending_general_client_circuits(void)
{
  int count = 0;

396
  SMARTLIST_FOREACH_BEGIN(circuit_get_global_list(), circuit_t *, circ) {
397
398
    if (circ->marked_for_close ||
        circ->state == CIRCUIT_STATE_OPEN ||
399
        !CIRCUIT_PURPOSE_COUNTS_TOWARDS_MAXPENDING(circ->purpose) ||
400
401
402
403
404
        !CIRCUIT_IS_ORIGIN(circ))
      continue;

    ++count;
  }
405
  SMARTLIST_FOREACH_END(circ);
406
407
408
409

  return count;
}

410
#if 0
411
/** Check whether, according to the policies in <b>options</b>, the
412
 * circuit <b>circ</b> makes sense. */
413
414
415
/* XXXX currently only checks Exclude{Exit}Nodes; it should check more.
 * Also, it doesn't have the right definition of an exit circuit. Also,
 * it's never called. */
416
417
418
419
420
421
int
circuit_conforms_to_options(const origin_circuit_t *circ,
                            const or_options_t *options)
{
  const crypt_path_t *cpath, *cpath_next = NULL;

422
423
  /* first check if it includes any excluded nodes */
  for (cpath = circ->cpath; cpath_next != circ->cpath; cpath = cpath_next) {
424
425
426
427
    cpath_next = cpath->next;
    if (routerset_contains_extendinfo(options->ExcludeNodes,
                                      cpath->extend_info))
      return 0;
428
  }
429

430
431
432
433
  /* then consider the final hop */
  if (routerset_contains_extendinfo(options->ExcludeExitNodes,
                                    circ->cpath->prev->extend_info))
    return 0;
434
435
436

  return 1;
}
437
#endif /* 0 */
438

439
440
/**
 * Close all circuits that start at us, aren't open, and were born
441
 * at least CircuitBuildTimeout seconds ago.
442
443
444
445
446
447
448
449
 *
 * TODO: This function is now partially redundant to
 * circuit_build_times_handle_completed_hop(), but that function only
 * covers circuits up to and including 3 hops that are still actually
 * completing hops. However, circuit_expire_building() also handles longer
 * circuits, as well as circuits that are completely stalled.
 * In the future (after prop247/other path selection revamping), we probably
 * want to eliminate this rats nest in favor of a simpler approach.
450
 */
451
void
452
circuit_expire_building(void)
453
{
454
455
456
  /* circ_times.timeout_ms and circ_times.close_ms are from
   * circuit_build_times_get_initial_timeout() if we haven't computed
   * custom timeouts yet */
457
  struct timeval general_cutoff, begindir_cutoff, fourhop_cutoff,
Mike Perry's avatar
Mike Perry committed
458
459
    close_cutoff, extremely_old_cutoff, hs_extremely_old_cutoff,
    cannibalized_cutoff, c_intro_cutoff, s_intro_cutoff, stream_cutoff;
460
  const or_options_t *options = get_options();
461
  struct timeval now;
462
  cpath_build_state_t *build_state;
463
  int any_opened_circs = 0;
464

465
  tor_gettimeofday(&now);
466
467
468
469
470

  /* Check to see if we have any opened circuits. If we don't,
   * we want to be more lenient with timeouts, in case the
   * user has relocated and/or changed network connections.
   * See bug #3443. */
471
  any_opened_circs = circuit_any_opened_circuits();
472

473
474
475
476
#define SET_CUTOFF(target, msec) do {                       \
    long ms = tor_lround(msec);                             \
    struct timeval diff;                                    \
    diff.tv_sec = ms / 1000;                                \
477
    diff.tv_usec = (int)((ms % 1000) * 1000);               \
478
479
480
    timersub(&now, &diff, &target);                         \
  } while (0)

Mike Perry's avatar
Mike Perry committed
481
  /**
Mike Perry's avatar
Mike Perry committed
482
483
484
485
486
487
488
489
490
   * Because circuit build timeout is calculated only based on 3 hop
   * general purpose circuit construction, we need to scale the timeout
   * to make it properly apply to longer circuits, and circuits of
   * certain usage types. The following diagram illustrates how we
   * derive the scaling below. In short, we calculate the number
   * of times our telescoping-based circuit construction causes cells
   * to traverse each link for the circuit purpose types in question,
   * and then assume each link is equivalent.
   *
Mike Perry's avatar
Mike Perry committed
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
   * OP --a--> A --b--> B --c--> C
   * OP --a--> A --b--> B --c--> C --d--> D
   *
   * Let h = a = b = c = d
   *
   * Three hops (general_cutoff)
   *   RTTs = 3a + 2b + c
   *   RTTs = 6h
   * Cannibalized:
   *   RTTs = a+b+c+d
   *   RTTs = 4h
   * Four hops:
   *   RTTs = 4a + 3b + 2c + d
   *   RTTs = 10h
   * Client INTRODUCE1+ACK: // XXX: correct?
   *   RTTs = 5a + 4b + 3c + 2d
   *   RTTs = 14h
   * Server intro:
   *   RTTs = 4a + 3b + 2c
   *   RTTs = 9h
   */
512
513
  SET_CUTOFF(general_cutoff, get_circuit_build_timeout_ms());
  SET_CUTOFF(begindir_cutoff, get_circuit_build_timeout_ms());
Mike Perry's avatar
Mike Perry committed
514

515
516
517
518
  // TODO: We should probably use route_len_for_purpose() here instead,
  // except that does not count the extra round trip for things like server
  // intros and rends.

Mike Perry's avatar
Mike Perry committed
519
520
  /* > 3hop circs seem to have a 1.0 second delay on their cannibalized
   * 4th hop. */
521
  SET_CUTOFF(fourhop_cutoff, get_circuit_build_timeout_ms() * (10/6.0) + 1000);
Mike Perry's avatar
Mike Perry committed
522
523
524
525
526
527

  /* CIRCUIT_PURPOSE_C_ESTABLISH_REND behaves more like a RELAY cell.
   * Use the stream cutoff (more or less). */
  SET_CUTOFF(stream_cutoff, MAX(options->CircuitStreamTimeout,15)*1000 + 1000);

  /* Be lenient with cannibalized circs. They already survived the official
Roger Dingledine's avatar
Roger Dingledine committed
528
   * CBT, and they're usually not performance-critical. */
Mike Perry's avatar
Mike Perry committed
529
  SET_CUTOFF(cannibalized_cutoff,
530
             MAX(get_circuit_build_close_time_ms()*(4/6.0),
Mike Perry's avatar
Mike Perry committed
531
532
                 options->CircuitStreamTimeout * 1000) + 1000);

Roger Dingledine's avatar
Roger Dingledine committed
533
  /* Intro circs have an extra round trip (and are also 4 hops long) */
534
  SET_CUTOFF(c_intro_cutoff, get_circuit_build_timeout_ms() * (14/6.0) + 1000);
Mike Perry's avatar
Mike Perry committed
535

Roger Dingledine's avatar
Roger Dingledine committed
536
  /* Server intro circs have an extra round trip */
537
  SET_CUTOFF(s_intro_cutoff, get_circuit_build_timeout_ms() * (9/6.0) + 1000);
Mike Perry's avatar
Mike Perry committed
538

539
540
  SET_CUTOFF(close_cutoff, get_circuit_build_close_time_ms());
  SET_CUTOFF(extremely_old_cutoff, get_circuit_build_close_time_ms()*2 + 1000);
541

542
  SET_CUTOFF(hs_extremely_old_cutoff,
543
             MAX(get_circuit_build_close_time_ms()*2 + 1000,
544
545
                 options->SocksTimeout * 1000));

546
  SMARTLIST_FOREACH_BEGIN(circuit_get_global_list(), circuit_t *,victim) {
547
    struct timeval cutoff;
548
    if (!CIRCUIT_IS_ORIGIN(victim) || /* didn't originate here */
549
550
551
552
553
554
555
556
557
558
559
560
        victim->marked_for_close)     /* don't mess with marked circs */
      continue;

    /* If we haven't yet started the first hop, it means we don't have
     * any orconns available, and thus have not started counting time yet
     * for this circuit. See circuit_deliver_create_cell() and uses of
     * timestamp_began.
     *
     * Continue to wait in this case. The ORConn should timeout
     * independently and kill us then.
     */
    if (TO_ORIGIN_CIRCUIT(victim)->cpath->state == CPATH_STATE_CLOSED) {
561
      continue;
562
    }
563

564
    build_state = TO_ORIGIN_CIRCUIT(victim)->build_state;
565
566
    if (build_state && build_state->onehop_tunnel)
      cutoff = begindir_cutoff;
567
568
    else if (victim->purpose == CIRCUIT_PURPOSE_C_MEASURE_TIMEOUT)
      cutoff = close_cutoff;
569
    else if (victim->purpose == CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT)
Mike Perry's avatar
Mike Perry committed
570
571
572
573
574
      cutoff = c_intro_cutoff;
    else if (victim->purpose == CIRCUIT_PURPOSE_S_ESTABLISH_INTRO)
      cutoff = s_intro_cutoff;
    else if (victim->purpose == CIRCUIT_PURPOSE_C_ESTABLISH_REND)
      cutoff = stream_cutoff;
575
576
    else if (victim->purpose == CIRCUIT_PURPOSE_PATH_BIAS_TESTING)
      cutoff = close_cutoff;
Mike Perry's avatar
Mike Perry committed
577
578
579
580
581
    else if (TO_ORIGIN_CIRCUIT(victim)->has_opened &&
             victim->state != CIRCUIT_STATE_OPEN)
      cutoff = cannibalized_cutoff;
    else if (build_state && build_state->desired_path_len >= 4)
      cutoff = fourhop_cutoff;
582
583
    else
      cutoff = general_cutoff;
584

585
586
587
    if (TO_ORIGIN_CIRCUIT(victim)->hs_circ_has_timed_out)
      cutoff = hs_extremely_old_cutoff;

588
    if (timercmp(&victim->timestamp_began, &cutoff, OP_GT))
589
590
      continue; /* it's still young, leave it alone */

591
592
593
594
595
596
    /* We need to double-check the opened state here because
     * we don't want to consider opened 1-hop dircon circuits for
     * deciding when to relax the timeout, but we *do* want to relax
     * those circuits too if nothing else is opened *and* they still
     * aren't either. */
    if (!any_opened_circs && victim->state != CIRCUIT_STATE_OPEN) {
597
      /* It's still young enough that we wouldn't close it, right? */
598
      if (timercmp(&victim->timestamp_began, &close_cutoff, OP_GT)) {
599
600
601
602
        if (!TO_ORIGIN_CIRCUIT(victim)->relaxed_timeout) {
          int first_hop_succeeded = TO_ORIGIN_CIRCUIT(victim)->cpath->state
                                      == CPATH_STATE_OPEN;
          log_info(LD_CIRC,
603
                 "No circuits are opened. Relaxing timeout for circuit %d "
604
                 "(a %s %d-hop circuit in state %s with channel state %s).",
605
606
                 TO_ORIGIN_CIRCUIT(victim)->global_identifier,
                 circuit_purpose_to_string(victim->purpose),
607
608
609
                 TO_ORIGIN_CIRCUIT(victim)->build_state ?
                   TO_ORIGIN_CIRCUIT(victim)->build_state->desired_path_len :
                   -1,
610
                 circuit_state_to_string(victim->state),
Mike Perry's avatar
Mike Perry committed
611
612
                 victim->n_chan ?
                    channel_state_to_string(victim->n_chan->state) : "none");
613
614
615
616
617

          /* We count the timeout here for CBT, because technically this
           * was a timeout, and the timeout value needs to reset if we
           * see enough of them. Note this means we also need to avoid
           * double-counting below, too. */
618
          circuit_build_times_count_timeout(get_circuit_build_times_mutable(),
619
              first_hop_succeeded);
620
621
622
623
          TO_ORIGIN_CIRCUIT(victim)->relaxed_timeout = 1;
        }
        continue;
      } else {
624
        static ratelim_t relax_timeout_limit = RATELIM_INIT(3600);
625
        const double build_close_ms = get_circuit_build_close_time_ms();
626
        log_fn_ratelim(&relax_timeout_limit, LOG_NOTICE, LD_CIRC,
627
628
629
                 "No circuits are opened. Relaxed timeout for circuit %d "
                 "(a %s %d-hop circuit in state %s with channel state %s) to "
                 "%ldms. However, it appears the circuit has timed out "
630
                 "anyway.",
631
632
                 TO_ORIGIN_CIRCUIT(victim)->global_identifier,
                 circuit_purpose_to_string(victim->purpose),
633
634
635
                 TO_ORIGIN_CIRCUIT(victim)->build_state ?
                   TO_ORIGIN_CIRCUIT(victim)->build_state->desired_path_len :
                   -1,
636
                 circuit_state_to_string(victim->state),
Mike Perry's avatar
Mike Perry committed
637
638
                 victim->n_chan ?
                    channel_state_to_string(victim->n_chan->state) : "none",
639
                 (long)build_close_ms);
640
641
642
      }
    }

643
#if 0
644
    /* some debug logs, to help track bugs */
645
    if (victim->purpose >= CIRCUIT_PURPOSE_C_INTRODUCING &&
646
        victim->purpose <= CIRCUIT_PURPOSE_C_REND_READY_INTRO_ACKED) {
647
      if (!victim->timestamp_dirty)
Nick Mathewson's avatar
Nick Mathewson committed
648
        log_fn(LOG_DEBUG,"Considering %sopen purpose %d to %s (circid %d)."
649
               "(clean).",
650
               victim->state == CIRCUIT_STATE_OPEN ? "" : "non",
Nick Mathewson's avatar
Nick Mathewson committed
651
               victim->purpose, victim->build_state->chosen_exit_name,
652
653
               victim->n_circ_id);
      else
Nick Mathewson's avatar
Nick Mathewson committed
654
        log_fn(LOG_DEBUG,"Considering %sopen purpose %d to %s (circid %d). "
655
               "%d secs since dirty.",
656
               victim->state == CIRCUIT_STATE_OPEN ? "" : "non",
Nick Mathewson's avatar
Nick Mathewson committed
657
               victim->purpose, victim->build_state->chosen_exit_name,
658
659
660
               victim->n_circ_id,
               (int)(now - victim->timestamp_dirty));
    }
661
#endif /* 0 */
662
663
664

    /* if circ is !open, or if it's open but purpose is a non-finished
     * intro or rend, then mark it for close */
665
666
    if (victim->state == CIRCUIT_STATE_OPEN) {
      switch (victim->purpose) {
667
        default: /* most open circuits can be left alone. */
668
669
          continue; /* yes, continue inside a switch refers to the nearest
                     * enclosing loop. C is smart. */
670
        case CIRCUIT_PURPOSE_S_ESTABLISH_INTRO:
671
          break; /* too old, need to die */
672
673
        case CIRCUIT_PURPOSE_C_REND_READY:
          /* it's a rend_ready circ -- has it already picked a query? */
674
675
676
          /* c_rend_ready circs measure age since timestamp_dirty,
           * because that's set when they switch purposes
           */
677
          if (TO_ORIGIN_CIRCUIT(victim)->rend_data ||
678
              TO_ORIGIN_CIRCUIT(victim)->hs_ident ||
679
              victim->timestamp_dirty > cutoff.tv_sec)
680
681
            continue;
          break;
682
683
684
685
686
        case CIRCUIT_PURPOSE_PATH_BIAS_TESTING:
          /* Open path bias testing circuits are given a long
           * time to complete the test, but not forever */
          TO_ORIGIN_CIRCUIT(victim)->path_state = PATH_STATE_USE_FAILED;
          break;
Mike Perry's avatar
Mike Perry committed
687
        case CIRCUIT_PURPOSE_C_INTRODUCING:
688
          /* That purpose means that the intro point circuit has been opened
689
           * successfully but the INTRODUCE1 cell hasn't been sent yet because
690
691
692
693
694
           * the client is waiting for the rendezvous point circuit to open.
           * Keep this circuit open while waiting for the rendezvous circuit.
           * We let the circuit idle timeout take care of cleaning this
           * circuit if it never used. */
          continue;
Mike Perry's avatar
Mike Perry committed
695
        case CIRCUIT_PURPOSE_C_ESTABLISH_REND:
696
697
698
699
700
701
        case CIRCUIT_PURPOSE_C_REND_READY_INTRO_ACKED:
        case CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT:
          /* rend and intro circs become dirty each time they
           * make an introduction attempt. so timestamp_dirty
           * will reflect the time since the last attempt.
           */
702
          if (victim->timestamp_dirty > cutoff.tv_sec)
703
704
705
            continue;
          break;
      }
706
707
708
    } else { /* circuit not open, consider recording failure as timeout */
      int first_hop_succeeded = TO_ORIGIN_CIRCUIT(victim)->cpath &&
            TO_ORIGIN_CIRCUIT(victim)->cpath->state == CPATH_STATE_OPEN;
709
710

      if (TO_ORIGIN_CIRCUIT(victim)->p_streams != NULL) {
711
        log_warn(LD_BUG, "Circuit %d (purpose %d, %s) has timed out, "
712
713
                 "yet has attached streams!",
                 TO_ORIGIN_CIRCUIT(victim)->global_identifier,
714
715
                 victim->purpose,
                 circuit_purpose_to_string(victim->purpose));
716
717
718
719
        tor_fragile_assert();
        continue;
      }

720
      if (circuit_timeout_want_to_count_circ(TO_ORIGIN_CIRCUIT(victim)) &&
721
          circuit_build_times_enough_to_compute(get_circuit_build_times())) {
722
723

        log_info(LD_CIRC,
724
725
                 "Deciding to count the timeout for circuit %"PRIu32"\n",
                 TO_ORIGIN_CIRCUIT(victim)->global_identifier);
726

727
728
729
        /* Circuits are allowed to last longer for measurement.
         * Switch their purpose and wait. */
        if (victim->purpose != CIRCUIT_PURPOSE_C_MEASURE_TIMEOUT) {
730
731
          circuit_build_times_mark_circ_as_measurement_only(TO_ORIGIN_CIRCUIT(
                                                            victim));
732
733
          continue;
        }
734

735
736
737
738
739
        /*
         * If the circuit build time is much greater than we would have cut
         * it off at, we probably had a suspend event along this codepath,
         * and we should discard the value.
         */
740
        if (timercmp(&victim->timestamp_began, &extremely_old_cutoff, OP_LT)) {
741
742
          log_notice(LD_CIRC,
                     "Extremely large value for circuit build timeout: %lds. "
743
                     "Assuming clock jump. Purpose %d (%s)",
744
                     (long)(now.tv_sec - victim->timestamp_began.tv_sec),
745
                     victim->purpose,
746
                     circuit_purpose_to_string(victim->purpose));
747
        } else if (circuit_build_times_count_close(
748
749
750
            get_circuit_build_times_mutable(),
            first_hop_succeeded,
            (time_t)victim->timestamp_created.tv_sec)) {
751
          circuit_build_times_set_timeout(get_circuit_build_times_mutable());
752
        }
753
      }
754
    }
755

756
757
758
759
    /* If this is a hidden service client circuit which is far enough along in
     * connecting to its destination, and we haven't already flagged it as
     * 'timed out', flag it so we'll launch another intro or rend circ, but
     * don't mark it for close yet.
760
761
762
763
     *
     * (Circs flagged as 'timed out' are given a much longer timeout
     * period above, so we won't close them in the next call to
     * circuit_expire_building.) */
764
    if (!(TO_ORIGIN_CIRCUIT(victim)->hs_circ_has_timed_out)) {
765
766
767
768
769
770
771
772
      switch (victim->purpose) {
      case CIRCUIT_PURPOSE_C_REND_READY:
        /* We only want to spare a rend circ if it has been specified in
         * an INTRODUCE1 cell sent to a hidden service.  A circ's
         * pending_final_cpath field is non-NULL iff it is a rend circ
         * and we have tried to send an INTRODUCE1 cell specifying it.
         * Thus, if the pending_final_cpath field *is* NULL, then we
         * want to not spare it. */
773
774
        if (TO_ORIGIN_CIRCUIT(victim)->build_state &&
            TO_ORIGIN_CIRCUIT(victim)->build_state->pending_final_cpath ==
775
776
            NULL)
          break;
Mike Perry's avatar
Mike Perry committed
777
        /* fallthrough! */
778
779
780
      case CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT:
      case CIRCUIT_PURPOSE_C_REND_READY_INTRO_ACKED:
        /* If we have reached this line, we want to spare the circ for now. */
781
        log_info(LD_CIRC,"Marking circ %u (state %d:%s, purpose %d) "
782
                 "as timed-out HS circ",
783
                 (unsigned)victim->n_circ_id,
784
785
786
787
788
789
790
791
792
                 victim->state, circuit_state_to_string(victim->state),
                 victim->purpose);
        TO_ORIGIN_CIRCUIT(victim)->hs_circ_has_timed_out = 1;
        continue;
      default:
        break;
      }
    }

793
794
795
    /* If this is a service-side rendezvous circuit which is far
     * enough along in connecting to its destination, consider sparing
     * it. */
796
    if (!(TO_ORIGIN_CIRCUIT(victim)->hs_circ_has_timed_out) &&
797
        victim->purpose == CIRCUIT_PURPOSE_S_CONNECT_REND) {
798
      log_info(LD_CIRC,"Marking circ %u (state %d:%s, purpose %d) "
799
               "as timed-out HS circ; relaunching rendezvous attempt.",
800
               (unsigned)victim->n_circ_id,
801
802
803
               victim->state, circuit_state_to_string(victim->state),
               victim->purpose);
      TO_ORIGIN_CIRCUIT(victim)->hs_circ_has_timed_out = 1;
804
      hs_circ_retry_service_rendezvous_point(TO_ORIGIN_CIRCUIT(victim));
805
806
807
      continue;
    }

808
    if (victim->n_chan)
Mike Perry's avatar
Mike Perry committed
809
      log_info(LD_CIRC,
810
               "Abandoning circ %u %s:%u (state %d,%d:%s, purpose %d, "
Mike Perry's avatar
Mike Perry committed
811
               "len %d)", TO_ORIGIN_CIRCUIT(victim)->global_identifier,
812
               channel_get_canonical_remote_descr(victim->n_chan),
813
               (unsigned)victim->n_circ_id,
Mike Perry's avatar
Mike Perry committed
814
               TO_ORIGIN_CIRCUIT(victim)->has_opened,
815
               victim->state, circuit_state_to_string(victim->state),
Mike Perry's avatar
Mike Perry committed
816
               victim->purpose,
817
818
819
               TO_ORIGIN_CIRCUIT(victim)->build_state ?
                 TO_ORIGIN_CIRCUIT(victim)->build_state->desired_path_len :
                 -1);
820
    else
Mike Perry's avatar
Mike Perry committed
821
      log_info(LD_CIRC,
822
               "Abandoning circ %u %u (state %d,%d:%s, purpose %d, len %d)",
Mike Perry's avatar
Mike Perry committed
823
               TO_ORIGIN_CIRCUIT(victim)->global_identifier,
824
825
               (unsigned)victim->n_circ_id,
               TO_ORIGIN_CIRCUIT(victim)->has_opened,
Mike Perry's avatar
Mike Perry committed
826
827
               victim->state,
               circuit_state_to_string(victim->state), victim->purpose,
828
829
830
               TO_ORIGIN_CIRCUIT(victim)->build_state ?
                 TO_ORIGIN_CIRCUIT(victim)->build_state->desired_path_len :
                 -1);
831

832
    circuit_log_path(LOG_INFO,LD_CIRC,TO_ORIGIN_CIRCUIT(victim));
833
834
835
836
    if (victim->purpose == CIRCUIT_PURPOSE_C_MEASURE_TIMEOUT)
      circuit_mark_for_close(victim, END_CIRC_REASON_MEASUREMENT_EXPIRED);
    else
      circuit_mark_for_close(victim, END_CIRC_REASON_TIMEOUT);
837
838

    pathbias_count_timeout(TO_ORIGIN_CIRCUIT(victim));
839
  } SMARTLIST_FOREACH_END(victim);
840
841
}

842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
/**
 * Mark for close all circuits that start here, that were built through a
 * guard we weren't sure if we wanted to use, and that have been waiting
 * around for way too long.
 */
void
circuit_expire_waiting_for_better_guard(void)
{
  SMARTLIST_FOREACH_BEGIN(circuit_get_global_origin_circuit_list(),
                          origin_circuit_t *, circ) {
    if (TO_CIRCUIT(circ)->marked_for_close)
      continue;
    if (circ->guard_state == NULL)
      continue;
    if (entry_guard_state_should_expire(circ->guard_state))
      circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_NONE);
  } SMARTLIST_FOREACH_END(circ);
}

Nick Mathewson's avatar
Nick Mathewson committed
861
862
863
864
/** For debugging #8387: track when we last called
 * circuit_expire_old_circuits_clientside. */
static time_t last_expired_clientside_circuits = 0;

865
866
867
/**
 * As a diagnostic for bug 8387, log information about how many one-hop
 * circuits we have around that have been there for at least <b>age</b>
David Goulet's avatar
David Goulet committed
868
 * seconds. Log a few of them. Ignores Single Onion Service intro, it is
869
 * expected to be long-term one-hop circuits.
870
871
872
873
874
 */
void
circuit_log_ancient_one_hop_circuits(int age)
{
#define MAX_ANCIENT_ONEHOP_CIRCUITS_TO_LOG 10
875
876
  time_t now = time(NULL);
  time_t cutoff = now - age;
877
878
  int n_found = 0;
  smartlist_t *log_these = smartlist_new();
879
  const or_options_t *options = get_options();
880

881
  SMARTLIST_FOREACH_BEGIN(circuit_get_global_list(), circuit_t *, circ) {
882
883
884
885
886
    const origin_circuit_t *ocirc;
    if (! CIRCUIT_IS_ORIGIN(circ))
      continue;
    if (circ->timestamp_created.tv_sec >= cutoff)
      continue;
887
    /* Single Onion Services deliberately make long term one-hop intro
888
     * and rendezvous connections. Don't log the established ones. */
889
    if (rend_service_allow_non_anonymous_connection(options) &&
890
891
        (circ->purpose == CIRCUIT_PURPOSE_S_INTRO ||
         circ->purpose == CIRCUIT_PURPOSE_S_REND_JOINED))
892
      continue;
893
894
895
896
897
898
899
900
901
    ocirc = CONST_TO_ORIGIN_CIRCUIT(circ);

    if (ocirc->build_state && ocirc->build_state->onehop_tunnel) {
      ++n_found;

      if (smartlist_len(log_these) < MAX_ANCIENT_ONEHOP_CIRCUITS_TO_LOG)
        smartlist_add(log_these, (origin_circuit_t*) ocirc);
    }
  }
902
  SMARTLIST_FOREACH_END(circ);
903
904
905
906
907

  if (n_found == 0)
    goto done;

  log_notice(LD_HEARTBEAT,
908
909
             "Diagnostic for issue 8387: Found %d one-hop circuits more "
             "than %d seconds old! Logging %d...",
910
911
912
913
             n_found, age, smartlist_len(log_these));

  SMARTLIST_FOREACH_BEGIN(log_these, const origin_circuit_t *, ocirc) {
    char created[ISO_TIME_LEN+1];
914
915
916
    int stream_num;
    const edge_connection_t *conn;
    char *dirty = NULL;
917
    const circuit_t *circ = TO_CIRCUIT(ocirc);
918

919
    format_local_iso_time(created,
920
                          (time_t)circ->timestamp_created.tv_sec);
921

922
923
924
925
926
927
    if (circ->timestamp_dirty) {
      char dirty_since[ISO_TIME_LEN+1];
      format_local_iso_time(dirty_since, circ->timestamp_dirty);

      tor_asprintf(&dirty, "Dirty since %s (%ld seconds vs %ld-second cutoff)",
                   dirty_since, (long)(now - circ->timestamp_dirty),
928
                   (long) options->MaxCircuitDirtiness);
929
930
931
932
    } else {
      dirty = tor_strdup("Not marked dirty");
    }

933
    log_notice(LD_HEARTBEAT, "  #%d created at %s. %s, %s. %s for close. "
934
               "Package window: %d. "
935
               "%s for new conns. %s.",
936
937
938
939
940
               ocirc_sl_idx,
               created,
               circuit_state_to_string(circ->state),
               circuit_purpose_to_string(circ->purpose),
               circ->marked_for_close ? "Marked" : "Not marked",
941
               circ->package_window,
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
               ocirc->unusable_for_new_conns ? "Not usable" : "usable",
               dirty);
    tor_free(dirty);

    stream_num = 0;
    for (conn = ocirc->p_streams; conn; conn = conn->next_stream) {
      const connection_t *c = TO_CONN(conn);
      char stream_created[ISO_TIME_LEN+1];
      if (++stream_num >= 5)
        break;

      format_local_iso_time(stream_created, c->timestamp_created);

      log_notice(LD_HEARTBEAT, "     Stream#%d created at %s. "
                 "%s conn in state %s. "
957
958
                 "It is %slinked and %sreading from a linked connection %p. "
                 "Package window %d. "
959
960
961
962
963
964
                 "%s for close (%s:%d). Hold-open is %sset. "
                 "Has %ssent RELAY_END. %s on circuit.",
                 stream_num,
                 stream_created,
                 conn_type_to_string(c->type),
                 conn_state_to_string(c->type, c->state),
965
966
967
968
                 c->linked ? "" : "not ",
                 c->reading_from_linked_conn ? "": "not",
                 c->linked_conn,
                 conn->package_window,
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
                 c->marked_for_close ? "Marked" : "Not marked",
                 c->marked_for_close_file ? c->marked_for_close_file : "--",
                 c->marked_for_close,
                 c->hold_open_until_flushed ? "" : "not ",
                 conn->edge_has_sent_end ? "" : "not ",
                 conn->edge_blocked_on_circ ? "Blocked" : "Not blocked");
      if (! c->linked_conn)
        continue;

      c = c->linked_conn;

      log_notice(LD_HEARTBEAT, "        Linked to %s connection in state %s "
                 "(Purpose %d). %s for close (%s:%d). Hold-open is %sset. ",
                 conn_type_to_string(c->type),
                 conn_state_to_string(c->type, c->state),
                 c->purpose,
                 c->marked_for_close ? "Marked" : "Not marked",
                 c->marked_for_close_file ? c->marked_for_close_file : "--",
                 c->marked_for_close,
                 c->hold_open_until_flushed ? "" : "not ");
    }
990
991
  } SMARTLIST_FOREACH_END(ocirc);

Nick Mathewson's avatar
Nick Mathewson committed
992
993
994
995
  log_notice(LD_HEARTBEAT, "It has been %ld seconds since I last called "
             "circuit_expire_old_circuits_clientside().",
             (long)(now - last_expired_clientside_circuits));

996
997
998
999
 done:
  smartlist_free(log_these);
}

1000
/** Remove any elements in <b>needed_ports</b> that are handled by an
For faster browsing, not all history is shown. View entire blame