LCOV - code coverage report
Current view: top level - feature/control - btrack_orconn.c (source / functions) Hit Total Coverage
Test: lcov.info Lines: 60 61 98.4 %
Date: 2021-11-24 03:28:48 Functions: 12 12 100.0 %

          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 : }

Generated by: LCOV version 1.14