Tor  0.4.7.0-alpha-dev
buffers_tls.c
Go to the documentation of this file.
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-2021, The Tor Project, Inc. */
5 /* See LICENSE for licensing information */
6 
7 /**
8  * \file buffers_tls.c
9  * \brief Read and write data on a tor_tls_t connection from a buf_t object.
10  **/
11 
12 #define BUFFERS_PRIVATE
13 #include "orconfig.h"
14 #include <stddef.h>
15 #include "lib/buf/buffers.h"
16 #include "lib/tls/buffers_tls.h"
17 #include "lib/cc/torint.h"
18 #include "lib/log/log.h"
19 #include "lib/log/util_bug.h"
20 #include "lib/tls/tortls.h"
21 
22 #ifdef HAVE_UNISTD_H
23 #include <unistd.h>
24 #endif
25 
26 /** As read_to_chunk(), but return (negative) error code on error, blocking,
27  * or TLS, and the number of bytes read otherwise. */
28 static inline int
29 read_to_chunk_tls(buf_t *buf, chunk_t *chunk, tor_tls_t *tls,
30  size_t at_most)
31 {
32  int read_result;
33 
34  tor_assert(CHUNK_REMAINING_CAPACITY(chunk) >= at_most);
35  read_result = tor_tls_read(tls, CHUNK_WRITE_PTR(chunk), at_most);
36  if (read_result < 0)
37  return read_result;
38  buf->datalen += read_result;
39  chunk->datalen += read_result;
40  return read_result;
41 }
42 
43 /** As read_to_buf, but reads from a TLS connection, and returns a TLS
44  * status value rather than the number of bytes read.
45  *
46  * Using TLS on OR connections complicates matters in two ways.
47  *
48  * First, a TLS stream has its own read buffer independent of the
49  * connection's read buffer. (TLS needs to read an entire frame from
50  * the network before it can decrypt any data. Thus, trying to read 1
51  * byte from TLS can require that several KB be read from the network
52  * and decrypted. The extra data is stored in TLS's decrypt buffer.)
53  * Because the data hasn't been read by Tor (it's still inside the TLS),
54  * this means that sometimes a connection "has stuff to read" even when
55  * poll() didn't return POLLIN. The tor_tls_get_pending_bytes function is
56  * used in connection.c to detect TLS objects with non-empty internal
57  * buffers and read from them again.
58  *
59  * Second, the TLS stream's events do not correspond directly to network
60  * events: sometimes, before a TLS stream can read, the network must be
61  * ready to write -- or vice versa.
62  *
63  * On success, return the number of bytes read. On error, a TOR_TLS_* negative
64  * code is returned (expect any of them except TOR_TLS_DONE).
65  */
66 int
67 buf_read_from_tls(buf_t *buf, tor_tls_t *tls, size_t at_most)
68 {
69  int r = 0;
70  size_t total_read = 0;
71 
72  check_no_tls_errors();
73 
74  IF_BUG_ONCE(buf->datalen > BUF_MAX_LEN)
75  return TOR_TLS_ERROR_MISC;
76  IF_BUG_ONCE(buf->datalen > BUF_MAX_LEN - at_most)
77  return TOR_TLS_ERROR_MISC;
78 
79  while (at_most > total_read) {
80  size_t readlen = at_most - total_read;
81  chunk_t *chunk;
82  if (!buf->tail || CHUNK_REMAINING_CAPACITY(buf->tail) < MIN_READ_LEN) {
83  chunk = buf_add_chunk_with_capacity(buf, at_most, 1);
84  if (readlen > chunk->memlen)
85  readlen = chunk->memlen;
86  } else {
87  size_t cap = CHUNK_REMAINING_CAPACITY(buf->tail);
88  chunk = buf->tail;
89  if (cap < readlen)
90  readlen = cap;
91  }
92 
93  r = read_to_chunk_tls(buf, chunk, tls, readlen);
94  if (r < 0)
95  return r; /* Error */
96  tor_assert(total_read+r <= BUF_MAX_LEN);
97  total_read += r;
98  }
99  return (int)total_read;
100 }
101 
102 /** Helper for buf_flush_to_tls(): try to write <b>sz</b> bytes from chunk
103  * <b>chunk</b> of buffer <b>buf</b> onto socket <b>s</b>. (Tries to write
104  * more if there is a forced pending write size.) On success, deduct the
105  * bytes written from *<b>buf_flushlen</b>. Return the number of bytes
106  * written on success, and a TOR_TLS error code on failure or blocking.
107  */
108 static inline int
109 flush_chunk_tls(tor_tls_t *tls, buf_t *buf, chunk_t *chunk, size_t sz)
110 {
111  int r;
112  size_t forced;
113  char *data;
114 
115  forced = tor_tls_get_forced_write_size(tls);
116  if (forced > sz)
117  sz = forced;
118  if (chunk) {
119  data = chunk->data;
120  tor_assert(sz <= chunk->datalen);
121  } else {
122  data = NULL;
123  tor_assert(sz == 0);
124  }
125  r = tor_tls_write(tls, data, sz);
126  if (r < 0)
127  return r;
128  buf_drain(buf, r);
129  log_debug(LD_NET,"flushed %d bytes, %d remain.",
130  r,(int)buf->datalen);
131  return r;
132 }
133 
134 /** As buf_flush_to_socket(), but writes data to a TLS connection. Can write
135  * more than <b>flushlen</b> bytes.
136  */
137 int
138 buf_flush_to_tls(buf_t *buf, tor_tls_t *tls, size_t flushlen)
139 {
140  int r;
141  size_t flushed = 0;
142  ssize_t sz;
143  IF_BUG_ONCE(flushlen > buf->datalen) {
144  flushlen = buf->datalen;
145  }
146  sz = (ssize_t) flushlen;
147 
148  /* we want to let tls write even if flushlen is zero, because it might
149  * have a partial record pending */
150  check_no_tls_errors();
151 
152  do {
153  size_t flushlen0;
154  if (buf->head) {
155  if ((ssize_t)buf->head->datalen >= sz)
156  flushlen0 = sz;
157  else
158  flushlen0 = buf->head->datalen;
159  } else {
160  flushlen0 = 0;
161  }
162 
163  r = flush_chunk_tls(tls, buf, buf->head, flushlen0);
164  if (r < 0)
165  return r;
166  flushed += r;
167  sz -= r;
168  if (r == 0) /* Can't flush any more now. */
169  break;
170  } while (sz > 0);
171  tor_assert(flushed <= BUF_MAX_LEN);
172  return (int)flushed;
173 }
chunk_t * buf_add_chunk_with_capacity(buf_t *buf, size_t capacity, int capped)
Definition: buffers.c:475
void buf_drain(buf_t *buf, size_t n)
Definition: buffers.c:330
Header file for buffers.c.
#define BUF_MAX_LEN
Definition: buffers.h:33
static int read_to_chunk_tls(buf_t *buf, chunk_t *chunk, tor_tls_t *tls, size_t at_most)
Definition: buffers_tls.c:29
static int flush_chunk_tls(tor_tls_t *tls, buf_t *buf, chunk_t *chunk, size_t sz)
Definition: buffers_tls.c:109
int buf_read_from_tls(buf_t *buf, tor_tls_t *tls, size_t at_most)
Definition: buffers_tls.c:67
int buf_flush_to_tls(buf_t *buf, tor_tls_t *tls, size_t flushlen)
Definition: buffers_tls.c:138
Header for buffers_tls.c.
Headers for log.c.
#define LD_NET
Definition: log.h:66
Integer definitions used throughout Tor.
Headers for tortls.c.
int tor_tls_read(tor_tls_t *tls, char *cp, size_t len)
Definition: tortls_nss.c:562
int tor_tls_write(tor_tls_t *tls, const char *cp, size_t n)
Definition: tortls_nss.c:585
size_t tor_tls_get_forced_write_size(tor_tls_t *tls)
Definition: tortls_nss.c:669
Macros to manage assertions, fatal and non-fatal.
#define tor_assert(expr)
Definition: util_bug.h:102
#define IF_BUG_ONCE(cond)
Definition: util_bug.h:246