aboutsummaryrefslogtreecommitdiff
path: root/src/feature/control/btrack_orconn_cevent.c
blob: d11be592808e8cd5932a3af169404645018d0b95 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
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
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
/* Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */

/**
 * \file btrack_orconn_cevent.c
 * \brief Emit bootstrap status events for OR connections
 *
 * We do some decoding of the raw OR_CONN_STATE_* values.  For
 * example, OR_CONN_STATE_CONNECTING means the first TCP connect()
 * completing, regardless of whether it's directly to a relay instead
 * of a proxy or a PT.
 **/

#include <stdbool.h>

#include "core/or/or.h"

#define BTRACK_ORCONN_PRIVATE

#include "core/or/orconn_event.h"
#include "feature/control/btrack_orconn.h"
#include "feature/control/btrack_orconn_cevent.h"
#include "feature/control/control_events.h"

/**
 * Have we completed our first OR connection?
 *
 * Block display of application circuit progress until we do, to avoid
 * some misleading behavior of jumping to high progress.
 **/
static bool bto_first_orconn = false;

/** Is the ORCONN using a pluggable transport? */
static bool
using_pt(const bt_orconn_t *bto)
{
  return bto->proxy_type == PROXY_PLUGGABLE;
}

/** Is the ORCONN using a non-PT proxy? */
static bool
using_proxy(const bt_orconn_t *bto)
{
  switch (bto->proxy_type) {
  case PROXY_CONNECT:
  case PROXY_SOCKS4:
  case PROXY_SOCKS5:
  case PROXY_HAPROXY:
    return true;
  default:
    return false;
  }
}

/**
 * Emit control events when we have updated our idea of the best state
 * that any OR connection has reached.
 *
 * Do some decoding of the ORCONN states depending on whether a PT or
 * a proxy is in use.
 **/
void
bto_cevent_anyconn(const bt_orconn_t *bto)
{
  switch (bto->state) {
  case OR_CONN_STATE_CONNECTING:
    /* Exactly what kind of thing we're connecting to isn't
     * information we directly get from the states in connection_or.c,
     * so decode it here. */
    if (using_pt(bto))
      control_event_bootstrap(BOOTSTRAP_STATUS_CONN_PT, 0);
    else if (using_proxy(bto))
      control_event_bootstrap(BOOTSTRAP_STATUS_CONN_PROXY, 0);
    else
      control_event_bootstrap(BOOTSTRAP_STATUS_CONN, 0);
    break;
  case OR_CONN_STATE_PROXY_HANDSHAKING:
    /* Similarly, starting a proxy handshake means the TCP connect()
     * succeeded to the proxy.  Let's be specific about what kind of
     * proxy. */
    if (using_pt(bto))
      control_event_bootstrap(BOOTSTRAP_STATUS_CONN_DONE_PT, 0);
    else if (using_proxy(bto))
      control_event_bootstrap(BOOTSTRAP_STATUS_CONN_DONE_PROXY, 0);
    break;
  case OR_CONN_STATE_TLS_HANDSHAKING:
    control_event_bootstrap(BOOTSTRAP_STATUS_CONN_DONE, 0);
    break;
  case OR_CONN_STATE_TLS_CLIENT_RENEGOTIATING:
  case OR_CONN_STATE_OR_HANDSHAKING_V2:
  case OR_CONN_STATE_OR_HANDSHAKING_V3:
    control_event_bootstrap(BOOTSTRAP_STATUS_HANDSHAKE, 0);
    break;
  case OR_CONN_STATE_OPEN:
    control_event_bootstrap(BOOTSTRAP_STATUS_HANDSHAKE_DONE, 0);
    /* Unblock directory progress display */
    control_event_boot_first_orconn();
    /* Unblock apconn progress display */
    bto_first_orconn = true;
    break;
  default:
    break;
  }
}

/**
 * Emit control events when we have updated our idea of the best state
 * that any application circuit OR connection has reached.
 *
 * Do some decoding of the ORCONN states depending on whether a PT or
 * a proxy is in use.
 **/
void
bto_cevent_apconn(const bt_orconn_t *bto)
{
  if (!bto_first_orconn)
    return;

  switch (bto->state) {
  case OR_CONN_STATE_CONNECTING:
    /* Exactly what kind of thing we're connecting to isn't
     * information we directly get from the states in connection_or.c,
     * so decode it here. */
    if (using_pt(bto))
      control_event_bootstrap(BOOTSTRAP_STATUS_AP_CONN_PT, 0);
    else if (using_proxy(bto))
      control_event_bootstrap(BOOTSTRAP_STATUS_AP_CONN_PROXY, 0);
    else
      control_event_bootstrap(BOOTSTRAP_STATUS_AP_CONN, 0);
    break;
  case OR_CONN_STATE_PROXY_HANDSHAKING:
    /* Similarly, starting a proxy handshake means the TCP connect()
     * succeeded to the proxy.  Let's be specific about what kind of
     * proxy. */
    if (using_pt(bto))
      control_event_bootstrap(BOOTSTRAP_STATUS_AP_CONN_DONE_PT, 0);
    else if (using_proxy(bto))
      control_event_bootstrap(BOOTSTRAP_STATUS_AP_CONN_DONE_PROXY, 0);
    break;
  case OR_CONN_STATE_TLS_HANDSHAKING:
    control_event_bootstrap(BOOTSTRAP_STATUS_AP_CONN_DONE, 0);
    break;
  case OR_CONN_STATE_TLS_CLIENT_RENEGOTIATING:
  case OR_CONN_STATE_OR_HANDSHAKING_V2:
  case OR_CONN_STATE_OR_HANDSHAKING_V3:
    control_event_bootstrap(BOOTSTRAP_STATUS_AP_HANDSHAKE, 0);
    break;
  case OR_CONN_STATE_OPEN:
    control_event_bootstrap(BOOTSTRAP_STATUS_AP_HANDSHAKE_DONE, 0);
    break;
  default:
    break;
  }
}

/** Forget that we completed our first OR connection */
void
bto_cevent_reset(void)
{
  bto_first_orconn = false;
}