buffers_tls.c 5.2 KB

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