Merge branch 'maint-0.2.9' into maint-0.3.3
[tor.git] / src / test / test_channeltls.c
blob94f1893caef33912f682b8c0224d2339da75e6ba
1 /* Copyright (c) 2014-2017, The Tor Project, Inc. */
2 /* See LICENSE for licensing information */
4 #include "orconfig.h"
6 #include <math.h>
8 #define TOR_CHANNEL_INTERNAL_
9 #include "or.h"
10 #include "address.h"
11 #include "buffers.h"
12 #include "channel.h"
13 #include "channeltls.h"
14 #include "connection_or.h"
15 #include "config.h"
16 /* For init/free stuff */
17 #include "scheduler.h"
18 #include "tortls.h"
20 /* Test suite stuff */
21 #include "test.h"
22 #include "fakechans.h"
24 /* The channeltls unit tests */
25 static void test_channeltls_create(void *arg);
26 static void test_channeltls_num_bytes_queued(void *arg);
27 static void test_channeltls_overhead_estimate(void *arg);
29 /* Mocks used by channeltls unit tests */
30 static size_t tlschan_buf_datalen_mock(const buf_t *buf);
31 static or_connection_t * tlschan_connection_or_connect_mock(
32 const tor_addr_t *addr,
33 uint16_t port,
34 const char *digest,
35 const ed25519_public_key_t *ed_id,
36 channel_tls_t *tlschan);
37 static int tlschan_is_local_addr_mock(const tor_addr_t *addr);
39 /* Fake close method */
40 static void tlschan_fake_close_method(channel_t *chan);
42 /* Flags controlling behavior of channeltls unit test mocks */
43 static int tlschan_local = 0;
44 static const buf_t * tlschan_buf_datalen_mock_target = NULL;
45 static size_t tlschan_buf_datalen_mock_size = 0;
47 /* Thing to cast to fake tor_tls_t * to appease assert_connection_ok() */
48 static int fake_tortls = 0; /* Bleh... */
50 static void
51 test_channeltls_create(void *arg)
53 tor_addr_t test_addr;
54 channel_t *ch = NULL;
55 const char test_digest[DIGEST_LEN] = {
56 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a,
57 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14 };
59 (void)arg;
61 /* Set up a fake address to fake-connect to */
62 test_addr.family = AF_INET;
63 test_addr.addr.in_addr.s_addr = htonl(0x01020304);
65 /* For this test we always want the address to be treated as non-local */
66 tlschan_local = 0;
67 /* Install is_local_addr() mock */
68 MOCK(is_local_addr, tlschan_is_local_addr_mock);
70 /* Install mock for connection_or_connect() */
71 MOCK(connection_or_connect, tlschan_connection_or_connect_mock);
73 /* Try connecting */
74 ch = channel_tls_connect(&test_addr, 567, test_digest, NULL);
75 tt_ptr_op(ch, OP_NE, NULL);
77 done:
78 if (ch) {
79 MOCK(scheduler_release_channel, scheduler_release_channel_mock);
81 * Use fake close method that doesn't try to do too much to fake
82 * orconn
84 ch->close = tlschan_fake_close_method;
85 channel_mark_for_close(ch);
86 free_fake_channel(ch);
87 UNMOCK(scheduler_release_channel);
90 UNMOCK(connection_or_connect);
91 UNMOCK(is_local_addr);
93 return;
96 static void
97 test_channeltls_num_bytes_queued(void *arg)
99 tor_addr_t test_addr;
100 channel_t *ch = NULL;
101 const char test_digest[DIGEST_LEN] = {
102 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a,
103 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14 };
104 channel_tls_t *tlschan = NULL;
105 size_t len;
106 int fake_outbuf = 0, n;
108 (void)arg;
110 /* Set up a fake address to fake-connect to */
111 test_addr.family = AF_INET;
112 test_addr.addr.in_addr.s_addr = htonl(0x01020304);
114 /* For this test we always want the address to be treated as non-local */
115 tlschan_local = 0;
116 /* Install is_local_addr() mock */
117 MOCK(is_local_addr, tlschan_is_local_addr_mock);
119 /* Install mock for connection_or_connect() */
120 MOCK(connection_or_connect, tlschan_connection_or_connect_mock);
122 /* Try connecting */
123 ch = channel_tls_connect(&test_addr, 567, test_digest, NULL);
124 tt_ptr_op(ch, OP_NE, NULL);
127 * Next, we have to test ch->num_bytes_queued, which is
128 * channel_tls_num_bytes_queued_method. We can't mock
129 * connection_get_outbuf_len() directly because it's static inline
130 * in connection.h, but we can mock buf_datalen().
133 tt_assert(ch->num_bytes_queued != NULL);
134 tlschan = BASE_CHAN_TO_TLS(ch);
135 tt_ptr_op(tlschan, OP_NE, NULL);
136 if (TO_CONN(tlschan->conn)->outbuf == NULL) {
137 /* We need an outbuf to make sure buf_datalen() gets called */
138 fake_outbuf = 1;
139 TO_CONN(tlschan->conn)->outbuf = buf_new();
141 tlschan_buf_datalen_mock_target = TO_CONN(tlschan->conn)->outbuf;
142 tlschan_buf_datalen_mock_size = 1024;
143 MOCK(buf_datalen, tlschan_buf_datalen_mock);
144 len = ch->num_bytes_queued(ch);
145 tt_int_op(len, OP_EQ, tlschan_buf_datalen_mock_size);
147 * We also cover num_cells_writeable here; since wide_circ_ids = 0 on
148 * the fake tlschans, cell_network_size returns 512, and so with
149 * tlschan_buf_datalen_mock_size == 1024, we should be able to write
150 * ceil((OR_CONN_HIGHWATER - 1024) / 512) = ceil(OR_CONN_HIGHWATER / 512)
151 * - 2 cells.
153 n = ch->num_cells_writeable(ch);
154 tt_int_op(n, OP_EQ, CEIL_DIV(OR_CONN_HIGHWATER, 512) - 2);
155 UNMOCK(buf_datalen);
156 tlschan_buf_datalen_mock_target = NULL;
157 tlschan_buf_datalen_mock_size = 0;
158 if (fake_outbuf) {
159 buf_free(TO_CONN(tlschan->conn)->outbuf);
160 TO_CONN(tlschan->conn)->outbuf = NULL;
163 done:
164 if (ch) {
165 MOCK(scheduler_release_channel, scheduler_release_channel_mock);
167 * Use fake close method that doesn't try to do too much to fake
168 * orconn
170 ch->close = tlschan_fake_close_method;
171 channel_mark_for_close(ch);
172 free_fake_channel(ch);
173 UNMOCK(scheduler_release_channel);
176 UNMOCK(connection_or_connect);
177 UNMOCK(is_local_addr);
179 return;
182 static void
183 test_channeltls_overhead_estimate(void *arg)
185 tor_addr_t test_addr;
186 channel_t *ch = NULL;
187 const char test_digest[DIGEST_LEN] = {
188 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a,
189 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14 };
190 double r;
191 channel_tls_t *tlschan = NULL;
193 (void)arg;
195 /* Set up a fake address to fake-connect to */
196 test_addr.family = AF_INET;
197 test_addr.addr.in_addr.s_addr = htonl(0x01020304);
199 /* For this test we always want the address to be treated as non-local */
200 tlschan_local = 0;
201 /* Install is_local_addr() mock */
202 MOCK(is_local_addr, tlschan_is_local_addr_mock);
204 /* Install mock for connection_or_connect() */
205 MOCK(connection_or_connect, tlschan_connection_or_connect_mock);
207 /* Try connecting */
208 ch = channel_tls_connect(&test_addr, 567, test_digest, NULL);
209 tt_ptr_op(ch, OP_NE, NULL);
211 /* First case: silly low ratios should get clamped to 1.0 */
212 tlschan = BASE_CHAN_TO_TLS(ch);
213 tt_ptr_op(tlschan, OP_NE, NULL);
214 tlschan->conn->bytes_xmitted = 128;
215 tlschan->conn->bytes_xmitted_by_tls = 64;
216 r = ch->get_overhead_estimate(ch);
217 tt_assert(fabs(r - 1.0) < 1E-12);
219 tlschan->conn->bytes_xmitted_by_tls = 127;
220 r = ch->get_overhead_estimate(ch);
221 tt_assert(fabs(r - 1.0) < 1E-12);
223 /* Now middle of the range */
224 tlschan->conn->bytes_xmitted_by_tls = 192;
225 r = ch->get_overhead_estimate(ch);
226 tt_assert(fabs(r - 1.5) < 1E-12);
228 /* Now above the 2.0 clamp */
229 tlschan->conn->bytes_xmitted_by_tls = 257;
230 r = ch->get_overhead_estimate(ch);
231 tt_assert(fabs(r - 2.0) < 1E-12);
233 tlschan->conn->bytes_xmitted_by_tls = 512;
234 r = ch->get_overhead_estimate(ch);
235 tt_assert(fabs(r - 2.0) < 1E-12);
237 done:
238 if (ch) {
239 MOCK(scheduler_release_channel, scheduler_release_channel_mock);
241 * Use fake close method that doesn't try to do too much to fake
242 * orconn
244 ch->close = tlschan_fake_close_method;
245 channel_mark_for_close(ch);
246 free_fake_channel(ch);
247 UNMOCK(scheduler_release_channel);
250 UNMOCK(connection_or_connect);
251 UNMOCK(is_local_addr);
253 return;
256 static size_t
257 tlschan_buf_datalen_mock(const buf_t *buf)
259 if (buf != NULL && buf == tlschan_buf_datalen_mock_target) {
260 return tlschan_buf_datalen_mock_size;
261 } else {
262 return buf_datalen__real(buf);
266 static or_connection_t *
267 tlschan_connection_or_connect_mock(const tor_addr_t *addr,
268 uint16_t port,
269 const char *digest,
270 const ed25519_public_key_t *ed_id,
271 channel_tls_t *tlschan)
273 or_connection_t *result = NULL;
274 (void) ed_id; // XXXX Not yet used.
276 tt_ptr_op(addr, OP_NE, NULL);
277 tt_uint_op(port, OP_NE, 0);
278 tt_ptr_op(digest, OP_NE, NULL);
279 tt_ptr_op(tlschan, OP_NE, NULL);
281 /* Make a fake orconn */
282 result = tor_malloc_zero(sizeof(*result));
283 result->base_.magic = OR_CONNECTION_MAGIC;
284 result->base_.state = OR_CONN_STATE_OPEN;
285 result->base_.type = CONN_TYPE_OR;
286 result->base_.socket_family = addr->family;
287 result->base_.address = tor_strdup("<fake>");
288 memcpy(&(result->base_.addr), addr, sizeof(tor_addr_t));
289 result->base_.port = port;
290 memcpy(result->identity_digest, digest, DIGEST_LEN);
291 result->chan = tlschan;
292 memcpy(&(result->real_addr), addr, sizeof(tor_addr_t));
293 result->tls = (tor_tls_t *)((void *)(&fake_tortls));
295 done:
296 return result;
299 static void
300 tlschan_fake_close_method(channel_t *chan)
302 channel_tls_t *tlschan = NULL;
304 tt_ptr_op(chan, OP_NE, NULL);
305 tt_int_op(chan->magic, OP_EQ, TLS_CHAN_MAGIC);
307 tlschan = BASE_CHAN_TO_TLS(chan);
308 tt_ptr_op(tlschan, OP_NE, NULL);
310 /* Just free the fake orconn */
311 tor_free(tlschan->conn->base_.address);
312 tor_free(tlschan->conn);
314 channel_closed(chan);
316 done:
317 return;
320 static int
321 tlschan_is_local_addr_mock(const tor_addr_t *addr)
323 tt_ptr_op(addr, OP_NE, NULL);
325 done:
326 return tlschan_local;
329 struct testcase_t channeltls_tests[] = {
330 { "create", test_channeltls_create, TT_FORK, NULL, NULL },
331 { "num_bytes_queued", test_channeltls_num_bytes_queued,
332 TT_FORK, NULL, NULL },
333 { "overhead_estimate", test_channeltls_overhead_estimate,
334 TT_FORK, NULL, NULL },
335 END_OF_TESTCASES