tor

The Tor anonymity network
git clone https://git.dasho.dev/tor.git
Log | Files | Refs | README | LICENSE

buffers_net.c (8183B)


      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_net.c
      9 * \brief Read and write data on a buf_t object.
     10 **/
     11 
     12 #define BUFFERS_PRIVATE
     13 #include "lib/net/buffers_net.h"
     14 #include "lib/buf/buffers.h"
     15 #include "lib/log/log.h"
     16 #include "lib/log/util_bug.h"
     17 #include "lib/net/nettypes.h"
     18 
     19 #ifdef _WIN32
     20 #include <winsock2.h>
     21 #endif
     22 
     23 #include <stdlib.h>
     24 
     25 #ifdef HAVE_UNISTD_H
     26 #include <unistd.h>
     27 #endif
     28 
     29 #ifdef PARANOIA
     30 /** Helper: If PARANOIA is defined, assert that the buffer in local variable
     31 * <b>buf</b> is well-formed. */
     32 #define check() STMT_BEGIN buf_assert_ok(buf); STMT_END
     33 #else
     34 #define check() STMT_NIL
     35 #endif /* defined(PARANOIA) */
     36 
     37 /** Read up to <b>at_most</b> bytes from the file descriptor <b>fd</b> into
     38 * <b>chunk</b> (which must be on <b>buf</b>). If we get an EOF, set
     39 * *<b>reached_eof</b> to 1. Uses <b>tor_socket_recv()</b> iff <b>is_socket</b>
     40 * is true, otherwise it uses <b>read()</b>.  Return -1 on error (and sets
     41 * *<b>error</b> to errno), 0 on eof or blocking, and the number of bytes read
     42 * otherwise. */
     43 static inline int
     44 read_to_chunk(buf_t *buf, chunk_t *chunk, tor_socket_t fd, size_t at_most,
     45              int *reached_eof, int *error, bool is_socket)
     46 {
     47  ssize_t read_result;
     48  if (at_most > CHUNK_REMAINING_CAPACITY(chunk))
     49    at_most = CHUNK_REMAINING_CAPACITY(chunk);
     50 
     51  if (is_socket)
     52    read_result = tor_socket_recv(fd, CHUNK_WRITE_PTR(chunk), at_most, 0);
     53  else
     54    read_result = read(fd, CHUNK_WRITE_PTR(chunk), at_most);
     55 
     56  if (read_result < 0) {
     57    int e = is_socket ? tor_socket_errno(fd) : errno;
     58 
     59    if (!ERRNO_IS_EAGAIN(e)) { /* it's a real error */
     60 #ifdef _WIN32
     61      if (e == WSAENOBUFS)
     62        log_warn(LD_NET, "%s() failed: WSAENOBUFS. Not enough ram?",
     63                 is_socket ? "recv" : "read");
     64 #endif
     65      if (error)
     66        *error = e;
     67      return -1;
     68    }
     69    return 0; /* would block. */
     70  } else if (read_result == 0) {
     71    log_debug(LD_NET,"Encountered eof on fd %d", (int)fd);
     72    *reached_eof = 1;
     73    return 0;
     74  } else { /* actually got bytes. */
     75    buf->datalen += read_result;
     76    chunk->datalen += read_result;
     77    log_debug(LD_NET,"Read %ld bytes. %d on inbuf.", (long)read_result,
     78              (int)buf->datalen);
     79    tor_assert(read_result <= BUF_MAX_LEN);
     80    return (int)read_result;
     81  }
     82 }
     83 
     84 /** Read from file descriptor <b>fd</b>, writing onto end of <b>buf</b>.  Read
     85 * at most <b>at_most</b> bytes, growing the buffer as necessary.  If recv()
     86 * returns 0 (because of EOF), set *<b>reached_eof</b> to 1 and return 0.
     87 * Return -1 on error; else return the number of bytes read.
     88 */
     89 /* XXXX indicate "read blocked" somehow? */
     90 static int
     91 buf_read_from_fd(buf_t *buf, int fd, size_t at_most,
     92                 int *reached_eof,
     93                 int *socket_error,
     94                 bool is_socket)
     95 {
     96  /* XXXX It's stupid to overload the return values for these functions:
     97   * "error status" and "number of bytes read" are not mutually exclusive.
     98   */
     99  int r = 0;
    100  size_t total_read = 0;
    101 
    102  check();
    103  tor_assert(reached_eof);
    104  tor_assert(SOCKET_OK(fd));
    105 
    106  if (BUG(buf->datalen > BUF_MAX_LEN))
    107    return -1;
    108  if (BUG(buf->datalen > BUF_MAX_LEN - at_most))
    109    return -1;
    110 
    111  while (at_most > total_read) {
    112    size_t readlen = at_most - total_read;
    113    chunk_t *chunk;
    114    if (!buf->tail || CHUNK_REMAINING_CAPACITY(buf->tail) < MIN_READ_LEN) {
    115      chunk = buf_add_chunk_with_capacity(buf, at_most, 1);
    116      if (readlen > chunk->memlen)
    117        readlen = chunk->memlen;
    118    } else {
    119      size_t cap = CHUNK_REMAINING_CAPACITY(buf->tail);
    120      chunk = buf->tail;
    121      if (cap < readlen)
    122        readlen = cap;
    123    }
    124 
    125    r = read_to_chunk(buf, chunk, fd, readlen,
    126                      reached_eof, socket_error, is_socket);
    127    check();
    128    if (r < 0)
    129      return r; /* Error */
    130    tor_assert(total_read+r <= BUF_MAX_LEN);
    131    total_read += r;
    132    if ((size_t)r < readlen) { /* eof, block, or no more to read. */
    133      break;
    134    }
    135  }
    136  return (int)total_read;
    137 }
    138 
    139 /** Helper for buf_flush_to_socket(): try to write <b>sz</b> bytes from chunk
    140 * <b>chunk</b> of buffer <b>buf</b> onto file descriptor <b>fd</b>.  Return
    141 * the number of bytes written on success, 0 on blocking, -1 on failure.
    142 */
    143 static inline int
    144 flush_chunk(tor_socket_t fd, buf_t *buf, chunk_t *chunk, size_t sz,
    145            bool is_socket)
    146 {
    147  ssize_t write_result;
    148 
    149  if (sz > chunk->datalen)
    150    sz = chunk->datalen;
    151 
    152  if (is_socket)
    153    write_result = tor_socket_send(fd, chunk->data, sz, 0);
    154  else
    155    write_result = write(fd, chunk->data, sz);
    156 
    157  if (write_result < 0) {
    158    int e = is_socket ? tor_socket_errno(fd) : errno;
    159 
    160    if (!ERRNO_IS_EAGAIN(e)) { /* it's a real error */
    161 #ifdef _WIN32
    162      if (e == WSAENOBUFS)
    163        log_warn(LD_NET,"write() failed: WSAENOBUFS. Not enough ram?");
    164 #endif
    165      return -1;
    166    }
    167    log_debug(LD_NET,"write() would block, returning.");
    168    return 0;
    169  } else {
    170    buf_drain(buf, write_result);
    171    tor_assert(write_result <= BUF_MAX_LEN);
    172    return (int)write_result;
    173  }
    174 }
    175 
    176 /** Write data from <b>buf</b> to the file descriptor <b>fd</b>.  Write at most
    177 * <b>sz</b> bytes, and remove the written bytes
    178 * from the buffer.  Return the number of bytes written on success,
    179 * -1 on failure.  Return 0 if write() would block.
    180 */
    181 static int
    182 buf_flush_to_fd(buf_t *buf, int fd, size_t sz,
    183                bool is_socket)
    184 {
    185  /* XXXX It's stupid to overload the return values for these functions:
    186   * "error status" and "number of bytes flushed" are not mutually exclusive.
    187   */
    188  int r;
    189  size_t flushed = 0;
    190  tor_assert(SOCKET_OK(fd));
    191  if (BUG(sz > buf->datalen)) {
    192    sz = buf->datalen;
    193  }
    194 
    195  check();
    196  while (sz) {
    197    size_t flushlen0;
    198    tor_assert(buf->head);
    199    if (buf->head->datalen >= sz)
    200      flushlen0 = sz;
    201    else
    202      flushlen0 = buf->head->datalen;
    203 
    204    r = flush_chunk(fd, buf, buf->head, flushlen0, is_socket);
    205    check();
    206    if (r < 0)
    207      return r;
    208    flushed += r;
    209    sz -= r;
    210    if (r == 0 || (size_t)r < flushlen0) /* can't flush any more now. */
    211      break;
    212  }
    213  tor_assert(flushed <= BUF_MAX_LEN);
    214  return (int)flushed;
    215 }
    216 
    217 /** Write data from <b>buf</b> to the socket <b>s</b>.  Write at most
    218 * <b>sz</b> bytes, decrement *<b>buf_flushlen</b> by
    219 * the number of bytes actually written, and remove the written bytes
    220 * from the buffer.  Return the number of bytes written on success,
    221 * -1 on failure.  Return 0 if write() would block.
    222 */
    223 int
    224 buf_flush_to_socket(buf_t *buf, tor_socket_t s, size_t sz)
    225 {
    226  return buf_flush_to_fd(buf, s, sz, true);
    227 }
    228 
    229 /** Read from socket <b>s</b>, writing onto end of <b>buf</b>.  Read at most
    230 * <b>at_most</b> bytes, growing the buffer as necessary.  If recv() returns 0
    231 * (because of EOF), set *<b>reached_eof</b> to 1 and return 0. Return -1 on
    232 * error; else return the number of bytes read.
    233 */
    234 int
    235 buf_read_from_socket(buf_t *buf, tor_socket_t s, size_t at_most,
    236                     int *reached_eof,
    237                     int *socket_error)
    238 {
    239  return buf_read_from_fd(buf, s, at_most, reached_eof, socket_error, true);
    240 }
    241 
    242 /** Write data from <b>buf</b> to the pipe <b>fd</b>.  Write at most
    243 * <b>sz</b> bytes, decrement *<b>buf_flushlen</b> by
    244 * the number of bytes actually written, and remove the written bytes
    245 * from the buffer.  Return the number of bytes written on success,
    246 * -1 on failure.  Return 0 if write() would block.
    247 */
    248 int
    249 buf_flush_to_pipe(buf_t *buf, int fd, size_t sz)
    250 {
    251  return buf_flush_to_fd(buf, fd, sz, false);
    252 }
    253 
    254 /** Read from pipe <b>fd</b>, writing onto end of <b>buf</b>.  Read at most
    255 * <b>at_most</b> bytes, growing the buffer as necessary.  If read() returns 0
    256 * (because of EOF), set *<b>reached_eof</b> to 1 and return 0. Return -1 on
    257 * error; else return the number of bytes read.
    258 */
    259 int
    260 buf_read_from_pipe(buf_t *buf, int fd, size_t at_most,
    261                   int *reached_eof,
    262                   int *socket_error)
    263 {
    264  return buf_read_from_fd(buf, fd, at_most, reached_eof, socket_error, false);
    265 }