Merge remote-tracking branch 'ffmancera/github/bug23271'
[tor/appveyor.git] / src / common / buffers_tls.c
blob041f78b818602841ea179e9c241396b69e3a88f4
1 /* Copyright (c) 2001 Matej Pfajfar.
2 * Copyright (c) 2001-2004, Roger Dingledine.
3 * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
4 * Copyright (c) 2007-2017, The Tor Project, Inc. */
5 /* See LICENSE for licensing information */
7 #define BUFFERS_PRIVATE
8 #include "orconfig.h"
9 #include <stddef.h>
10 #include "buffers.h"
11 #include "buffers_tls.h"
12 #include "compat.h"
13 #include "compress.h"
14 #include "util.h"
15 #include "torint.h"
16 #include "torlog.h"
17 #include "tortls.h"
18 #ifdef HAVE_UNISTD_H
19 #include <unistd.h>
20 #endif
22 /** As read_to_chunk(), but return (negative) error code on error, blocking,
23 * or TLS, and the number of bytes read otherwise. */
24 static inline int
25 read_to_chunk_tls(buf_t *buf, chunk_t *chunk, tor_tls_t *tls,
26 size_t at_most)
28 int read_result;
30 tor_assert(CHUNK_REMAINING_CAPACITY(chunk) >= at_most);
31 read_result = tor_tls_read(tls, CHUNK_WRITE_PTR(chunk), at_most);
32 if (read_result < 0)
33 return read_result;
34 buf->datalen += read_result;
35 chunk->datalen += read_result;
36 return read_result;
39 /** As read_to_buf, but reads from a TLS connection, and returns a TLS
40 * status value rather than the number of bytes read.
42 * Using TLS on OR connections complicates matters in two ways.
44 * First, a TLS stream has its own read buffer independent of the
45 * connection's read buffer. (TLS needs to read an entire frame from
46 * the network before it can decrypt any data. Thus, trying to read 1
47 * byte from TLS can require that several KB be read from the network
48 * and decrypted. The extra data is stored in TLS's decrypt buffer.)
49 * Because the data hasn't been read by Tor (it's still inside the TLS),
50 * this means that sometimes a connection "has stuff to read" even when
51 * poll() didn't return POLLIN. The tor_tls_get_pending_bytes function is
52 * used in connection.c to detect TLS objects with non-empty internal
53 * buffers and read from them again.
55 * Second, the TLS stream's events do not correspond directly to network
56 * events: sometimes, before a TLS stream can read, the network must be
57 * ready to write -- or vice versa.
59 int
60 buf_read_from_tls(buf_t *buf, tor_tls_t *tls, size_t at_most)
62 int r = 0;
63 size_t total_read = 0;
65 check_no_tls_errors();
67 if (BUG(buf->datalen >= INT_MAX))
68 return -1;
69 if (BUG(buf->datalen >= INT_MAX - at_most))
70 return -1;
72 while (at_most > total_read) {
73 size_t readlen = at_most - total_read;
74 chunk_t *chunk;
75 if (!buf->tail || CHUNK_REMAINING_CAPACITY(buf->tail) < MIN_READ_LEN) {
76 chunk = buf_add_chunk_with_capacity(buf, at_most, 1);
77 if (readlen > chunk->memlen)
78 readlen = chunk->memlen;
79 } else {
80 size_t cap = CHUNK_REMAINING_CAPACITY(buf->tail);
81 chunk = buf->tail;
82 if (cap < readlen)
83 readlen = cap;
86 r = read_to_chunk_tls(buf, chunk, tls, readlen);
87 if (r < 0)
88 return r; /* Error */
89 tor_assert(total_read+r < INT_MAX);
90 total_read += r;
91 if ((size_t)r < readlen) /* eof, block, or no more to read. */
92 break;
94 return (int)total_read;
97 /** Helper for buf_flush_to_tls(): try to write <b>sz</b> bytes from chunk
98 * <b>chunk</b> of buffer <b>buf</b> onto socket <b>s</b>. (Tries to write
99 * more if there is a forced pending write size.) On success, deduct the
100 * bytes written from *<b>buf_flushlen</b>. Return the number of bytes
101 * written on success, and a TOR_TLS error code on failure or blocking.
103 static inline int
104 flush_chunk_tls(tor_tls_t *tls, buf_t *buf, chunk_t *chunk,
105 size_t sz, size_t *buf_flushlen)
107 int r;
108 size_t forced;
109 char *data;
111 forced = tor_tls_get_forced_write_size(tls);
112 if (forced > sz)
113 sz = forced;
114 if (chunk) {
115 data = chunk->data;
116 tor_assert(sz <= chunk->datalen);
117 } else {
118 data = NULL;
119 tor_assert(sz == 0);
121 r = tor_tls_write(tls, data, sz);
122 if (r < 0)
123 return r;
124 if (*buf_flushlen > (size_t)r)
125 *buf_flushlen -= r;
126 else
127 *buf_flushlen = 0;
128 buf_drain(buf, r);
129 log_debug(LD_NET,"flushed %d bytes, %d ready to flush, %d remain.",
130 r,(int)*buf_flushlen,(int)buf->datalen);
131 return r;
134 /** As buf_flush_to_socket(), but writes data to a TLS connection. Can write
135 * more than <b>flushlen</b> bytes.
138 buf_flush_to_tls(buf_t *buf, tor_tls_t *tls, size_t flushlen,
139 size_t *buf_flushlen)
141 int r;
142 size_t flushed = 0;
143 ssize_t sz;
144 tor_assert(buf_flushlen);
145 if (BUG(*buf_flushlen > buf->datalen)) {
146 *buf_flushlen = buf->datalen;
148 if (BUG(flushlen > *buf_flushlen)) {
149 flushlen = *buf_flushlen;
151 sz = (ssize_t) flushlen;
153 /* we want to let tls write even if flushlen is zero, because it might
154 * have a partial record pending */
155 check_no_tls_errors();
157 do {
158 size_t flushlen0;
159 if (buf->head) {
160 if ((ssize_t)buf->head->datalen >= sz)
161 flushlen0 = sz;
162 else
163 flushlen0 = buf->head->datalen;
164 } else {
165 flushlen0 = 0;
168 r = flush_chunk_tls(tls, buf, buf->head, flushlen0, buf_flushlen);
169 if (r < 0)
170 return r;
171 flushed += r;
172 sz -= r;
173 if (r == 0) /* Can't flush any more now. */
174 break;
175 } while (sz > 0);
176 tor_assert(flushed < INT_MAX);
177 return (int)flushed;