Prop210: Refactor connection_get_* to produce lists and counts
[tor.git] / src / test / test_channeltls.c
blob016e504ab3e3434fe7cfd14bee4da185313a84c8
1 /* Copyright (c) 2014-2015, The Tor Project, Inc. */
2 /* See LICENSE for licensing information */
4 #include <math.h>
6 #define TOR_CHANNEL_INTERNAL_
7 #include "or.h"
8 #include "address.h"
9 #include "buffers.h"
10 #include "channel.h"
11 #include "channeltls.h"
12 #include "connection_or.h"
13 #include "config.h"
14 /* For init/free stuff */
15 #include "scheduler.h"
16 #include "tortls.h"
18 /* Test suite stuff */
19 #include "test.h"
20 #include "fakechans.h"
22 /* The channeltls unit tests */
23 static void test_channeltls_create(void *arg);
24 static void test_channeltls_num_bytes_queued(void *arg);
25 static void test_channeltls_overhead_estimate(void *arg);
27 /* Mocks used by channeltls unit tests */
28 static size_t tlschan_buf_datalen_mock(const buf_t *buf);
29 static or_connection_t * tlschan_connection_or_connect_mock(
30 const tor_addr_t *addr,
31 uint16_t port,
32 const char *digest,
33 channel_tls_t *tlschan);
34 static int tlschan_is_local_addr_mock(const tor_addr_t *addr);
36 /* Fake close method */
37 static void tlschan_fake_close_method(channel_t *chan);
39 /* Flags controlling behavior of channeltls unit test mocks */
40 static int tlschan_local = 0;
41 static const buf_t * tlschan_buf_datalen_mock_target = NULL;
42 static size_t tlschan_buf_datalen_mock_size = 0;
44 /* Thing to cast to fake tor_tls_t * to appease assert_connection_ok() */
45 static int fake_tortls = 0; /* Bleh... */
47 static void
48 test_channeltls_create(void *arg)
50 tor_addr_t test_addr;
51 channel_t *ch = NULL;
52 const char test_digest[DIGEST_LEN] = {
53 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a,
54 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14 };
56 (void)arg;
58 /* Set up a fake address to fake-connect to */
59 test_addr.family = AF_INET;
60 test_addr.addr.in_addr.s_addr = htonl(0x01020304);
62 /* For this test we always want the address to be treated as non-local */
63 tlschan_local = 0;
64 /* Install is_local_addr() mock */
65 MOCK(is_local_addr, tlschan_is_local_addr_mock);
67 /* Install mock for connection_or_connect() */
68 MOCK(connection_or_connect, tlschan_connection_or_connect_mock);
70 /* Try connecting */
71 ch = channel_tls_connect(&test_addr, 567, test_digest);
72 tt_assert(ch != NULL);
74 done:
75 if (ch) {
76 MOCK(scheduler_release_channel, scheduler_release_channel_mock);
78 * Use fake close method that doesn't try to do too much to fake
79 * orconn
81 ch->close = tlschan_fake_close_method;
82 channel_mark_for_close(ch);
83 free_fake_channel(ch);
84 UNMOCK(scheduler_release_channel);
87 UNMOCK(connection_or_connect);
88 UNMOCK(is_local_addr);
90 return;
93 static void
94 test_channeltls_num_bytes_queued(void *arg)
96 tor_addr_t test_addr;
97 channel_t *ch = NULL;
98 const char test_digest[DIGEST_LEN] = {
99 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a,
100 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14 };
101 channel_tls_t *tlschan = NULL;
102 size_t len;
103 int fake_outbuf = 0, n;
105 (void)arg;
107 /* Set up a fake address to fake-connect to */
108 test_addr.family = AF_INET;
109 test_addr.addr.in_addr.s_addr = htonl(0x01020304);
111 /* For this test we always want the address to be treated as non-local */
112 tlschan_local = 0;
113 /* Install is_local_addr() mock */
114 MOCK(is_local_addr, tlschan_is_local_addr_mock);
116 /* Install mock for connection_or_connect() */
117 MOCK(connection_or_connect, tlschan_connection_or_connect_mock);
119 /* Try connecting */
120 ch = channel_tls_connect(&test_addr, 567, test_digest);
121 tt_assert(ch != NULL);
124 * Next, we have to test ch->num_bytes_queued, which is
125 * channel_tls_num_bytes_queued_method. We can't mock
126 * connection_get_outbuf_len() directly because it's static INLINE
127 * in connection.h, but we can mock buf_datalen(). Note that
128 * if bufferevents ever work, this will break with them enabled.
131 tt_assert(ch->num_bytes_queued != NULL);
132 tlschan = BASE_CHAN_TO_TLS(ch);
133 tt_assert(tlschan != NULL);
134 if (TO_CONN(tlschan->conn)->outbuf == NULL) {
135 /* We need an outbuf to make sure buf_datalen() gets called */
136 fake_outbuf = 1;
137 TO_CONN(tlschan->conn)->outbuf = buf_new();
139 tlschan_buf_datalen_mock_target = TO_CONN(tlschan->conn)->outbuf;
140 tlschan_buf_datalen_mock_size = 1024;
141 MOCK(buf_datalen, tlschan_buf_datalen_mock);
142 len = ch->num_bytes_queued(ch);
143 tt_int_op(len, ==, tlschan_buf_datalen_mock_size);
145 * We also cover num_cells_writeable here; since wide_circ_ids = 0 on
146 * the fake tlschans, cell_network_size returns 512, and so with
147 * tlschan_buf_datalen_mock_size == 1024, we should be able to write
148 * ceil((OR_CONN_HIGHWATER - 1024) / 512) = ceil(OR_CONN_HIGHWATER / 512)
149 * - 2 cells.
151 n = ch->num_cells_writeable(ch);
152 tt_int_op(n, ==, CEIL_DIV(OR_CONN_HIGHWATER, 512) - 2);
153 UNMOCK(buf_datalen);
154 tlschan_buf_datalen_mock_target = NULL;
155 tlschan_buf_datalen_mock_size = 0;
156 if (fake_outbuf) {
157 buf_free(TO_CONN(tlschan->conn)->outbuf);
158 TO_CONN(tlschan->conn)->outbuf = NULL;
161 done:
162 if (ch) {
163 MOCK(scheduler_release_channel, scheduler_release_channel_mock);
165 * Use fake close method that doesn't try to do too much to fake
166 * orconn
168 ch->close = tlschan_fake_close_method;
169 channel_mark_for_close(ch);
170 free_fake_channel(ch);
171 UNMOCK(scheduler_release_channel);
174 UNMOCK(connection_or_connect);
175 UNMOCK(is_local_addr);
177 return;
180 static void
181 test_channeltls_overhead_estimate(void *arg)
183 tor_addr_t test_addr;
184 channel_t *ch = NULL;
185 const char test_digest[DIGEST_LEN] = {
186 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a,
187 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14 };
188 float r;
189 channel_tls_t *tlschan = NULL;
191 (void)arg;
193 /* Set up a fake address to fake-connect to */
194 test_addr.family = AF_INET;
195 test_addr.addr.in_addr.s_addr = htonl(0x01020304);
197 /* For this test we always want the address to be treated as non-local */
198 tlschan_local = 0;
199 /* Install is_local_addr() mock */
200 MOCK(is_local_addr, tlschan_is_local_addr_mock);
202 /* Install mock for connection_or_connect() */
203 MOCK(connection_or_connect, tlschan_connection_or_connect_mock);
205 /* Try connecting */
206 ch = channel_tls_connect(&test_addr, 567, test_digest);
207 tt_assert(ch != NULL);
209 /* First case: silly low ratios should get clamped to 1.0f */
210 tlschan = BASE_CHAN_TO_TLS(ch);
211 tt_assert(tlschan != NULL);
212 tlschan->conn->bytes_xmitted = 128;
213 tlschan->conn->bytes_xmitted_by_tls = 64;
214 r = ch->get_overhead_estimate(ch);
215 tt_assert(fabsf(r - 1.0f) < 1E-12);
217 tlschan->conn->bytes_xmitted_by_tls = 127;
218 r = ch->get_overhead_estimate(ch);
219 tt_assert(fabsf(r - 1.0f) < 1E-12);
221 /* Now middle of the range */
222 tlschan->conn->bytes_xmitted_by_tls = 192;
223 r = ch->get_overhead_estimate(ch);
224 tt_assert(fabsf(r - 1.5f) < 1E-12);
226 /* Now above the 2.0f clamp */
227 tlschan->conn->bytes_xmitted_by_tls = 257;
228 r = ch->get_overhead_estimate(ch);
229 tt_assert(fabsf(r - 2.0f) < 1E-12);
231 tlschan->conn->bytes_xmitted_by_tls = 512;
232 r = ch->get_overhead_estimate(ch);
233 tt_assert(fabsf(r - 2.0f) < 1E-12);
235 done:
236 if (ch) {
237 MOCK(scheduler_release_channel, scheduler_release_channel_mock);
239 * Use fake close method that doesn't try to do too much to fake
240 * orconn
242 ch->close = tlschan_fake_close_method;
243 channel_mark_for_close(ch);
244 free_fake_channel(ch);
245 UNMOCK(scheduler_release_channel);
248 UNMOCK(connection_or_connect);
249 UNMOCK(is_local_addr);
251 return;
254 static size_t
255 tlschan_buf_datalen_mock(const buf_t *buf)
257 if (buf != NULL && buf == tlschan_buf_datalen_mock_target) {
258 return tlschan_buf_datalen_mock_size;
259 } else {
260 return buf_datalen__real(buf);
264 static or_connection_t *
265 tlschan_connection_or_connect_mock(const tor_addr_t *addr,
266 uint16_t port,
267 const char *digest,
268 channel_tls_t *tlschan)
270 or_connection_t *result = NULL;
272 tt_assert(addr != NULL);
273 tt_assert(port != 0);
274 tt_assert(digest != NULL);
275 tt_assert(tlschan != NULL);
277 /* Make a fake orconn */
278 result = tor_malloc_zero(sizeof(*result));
279 result->base_.magic = OR_CONNECTION_MAGIC;
280 result->base_.state = OR_CONN_STATE_OPEN;
281 result->base_.type = CONN_TYPE_OR;
282 result->base_.socket_family = addr->family;
283 result->base_.address = tor_strdup("<fake>");
284 memcpy(&(result->base_.addr), addr, sizeof(tor_addr_t));
285 result->base_.port = port;
286 memcpy(result->identity_digest, digest, DIGEST_LEN);
287 result->chan = tlschan;
288 memcpy(&(result->real_addr), addr, sizeof(tor_addr_t));
289 result->tls = (tor_tls_t *)((void *)(&fake_tortls));
291 done:
292 return result;
295 static void
296 tlschan_fake_close_method(channel_t *chan)
298 channel_tls_t *tlschan = NULL;
300 tt_assert(chan != NULL);
301 tt_int_op(chan->magic, ==, TLS_CHAN_MAGIC);
303 tlschan = BASE_CHAN_TO_TLS(chan);
304 tt_assert(tlschan != NULL);
306 /* Just free the fake orconn */
307 tor_free(tlschan->conn->base_.address);
308 tor_free(tlschan->conn);
310 channel_closed(chan);
312 done:
313 return;
316 static int
317 tlschan_is_local_addr_mock(const tor_addr_t *addr)
319 tt_assert(addr != NULL);
321 done:
322 return tlschan_local;
325 struct testcase_t channeltls_tests[] = {
326 { "create", test_channeltls_create, TT_FORK, NULL, NULL },
327 { "num_bytes_queued", test_channeltls_num_bytes_queued,
328 TT_FORK, NULL, NULL },
329 { "overhead_estimate", test_channeltls_overhead_estimate,
330 TT_FORK, NULL, NULL },
331 END_OF_TESTCASES