LCOV - code coverage report
Current view: top level - lib/net - buffers_net.c (source / functions) Hit Total Coverage
Test: lcov.info Lines: 69 89 77.5 %
Date: 2021-11-24 03:28:48 Functions: 6 8 75.0 %

          Line data    Source code
       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          10 : 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          10 :   ssize_t read_result;
      48          10 :   if (at_most > CHUNK_REMAINING_CAPACITY(chunk))
      49             :     at_most = CHUNK_REMAINING_CAPACITY(chunk);
      50             : 
      51          10 :   if (is_socket)
      52           0 :     read_result = tor_socket_recv(fd, CHUNK_WRITE_PTR(chunk), at_most, 0);
      53             :   else
      54          10 :     read_result = read(fd, CHUNK_WRITE_PTR(chunk), at_most);
      55             : 
      56          10 :   if (read_result < 0) {
      57           0 :     int e = is_socket ? tor_socket_errno(fd) : errno;
      58             : 
      59           0 :     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           0 :       if (error)
      66           0 :         *error = e;
      67           0 :       return -1;
      68             :     }
      69             :     return 0; /* would block. */
      70          10 :   } else if (read_result == 0) {
      71           4 :     log_debug(LD_NET,"Encountered eof on fd %d", (int)fd);
      72           4 :     *reached_eof = 1;
      73           4 :     return 0;
      74             :   } else { /* actually got bytes. */
      75           6 :     buf->datalen += read_result;
      76           6 :     chunk->datalen += read_result;
      77           6 :     log_debug(LD_NET,"Read %ld bytes. %d on inbuf.", (long)read_result,
      78             :               (int)buf->datalen);
      79           6 :     tor_assert(read_result <= BUF_MAX_LEN);
      80           6 :     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          10 : 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          10 :   int r = 0;
     100          10 :   size_t total_read = 0;
     101             : 
     102          10 :   check();
     103          10 :   tor_assert(reached_eof);
     104          10 :   tor_assert(SOCKET_OK(fd));
     105             : 
     106          10 :   if (BUG(buf->datalen > BUF_MAX_LEN))
     107           0 :     return -1;
     108          10 :   if (BUG(buf->datalen > BUF_MAX_LEN - at_most))
     109           0 :     return -1;
     110             : 
     111          10 :   while (at_most > total_read) {
     112          10 :     size_t readlen = at_most - total_read;
     113          10 :     chunk_t *chunk;
     114          10 :     if (!buf->tail || CHUNK_REMAINING_CAPACITY(buf->tail) < MIN_READ_LEN) {
     115           7 :       chunk = buf_add_chunk_with_capacity(buf, at_most, 1);
     116           7 :       if (readlen > chunk->memlen)
     117             :         readlen = chunk->memlen;
     118             :     } else {
     119           3 :       size_t cap = CHUNK_REMAINING_CAPACITY(buf->tail);
     120           3 :       chunk = buf->tail;
     121           3 :       if (cap < readlen)
     122             :         readlen = cap;
     123             :     }
     124             : 
     125          10 :     r = read_to_chunk(buf, chunk, fd, readlen,
     126             :                       reached_eof, socket_error, is_socket);
     127          10 :     check();
     128          10 :     if (r < 0)
     129           0 :       return r; /* Error */
     130          10 :     tor_assert(total_read+r <= BUF_MAX_LEN);
     131          10 :     total_read += r;
     132          10 :     if ((size_t)r < readlen) { /* eof, block, or no more to read. */
     133             :       break;
     134             :     }
     135             :   }
     136          10 :   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           3 : flush_chunk(tor_socket_t fd, buf_t *buf, chunk_t *chunk, size_t sz,
     145             :             bool is_socket)
     146             : {
     147           3 :   ssize_t write_result;
     148             : 
     149           3 :   if (sz > chunk->datalen)
     150             :     sz = chunk->datalen;
     151             : 
     152           3 :   if (is_socket)
     153           0 :     write_result = tor_socket_send(fd, chunk->data, sz, 0);
     154             :   else
     155           3 :     write_result = write(fd, chunk->data, sz);
     156             : 
     157           3 :   if (write_result < 0) {
     158           0 :     int e = is_socket ? tor_socket_errno(fd) : errno;
     159             : 
     160           0 :     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           0 :     log_debug(LD_NET,"write() would block, returning.");
     168           0 :     return 0;
     169             :   } else {
     170           3 :     buf_drain(buf, write_result);
     171           3 :     tor_assert(write_result <= BUF_MAX_LEN);
     172           3 :     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           3 : 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           3 :   int r;
     189           3 :   size_t flushed = 0;
     190           3 :   tor_assert(SOCKET_OK(fd));
     191           3 :   if (BUG(sz > buf->datalen)) {
     192           0 :     sz = buf->datalen;
     193             :   }
     194             : 
     195             :   check();
     196           6 :   while (sz) {
     197           3 :     size_t flushlen0;
     198           3 :     tor_assert(buf->head);
     199           3 :     if (buf->head->datalen >= sz)
     200             :       flushlen0 = sz;
     201             :     else
     202             :       flushlen0 = buf->head->datalen;
     203             : 
     204           3 :     r = flush_chunk(fd, buf, buf->head, flushlen0, is_socket);
     205           3 :     check();
     206           3 :     if (r < 0)
     207           0 :       return r;
     208           3 :     flushed += r;
     209           3 :     sz -= r;
     210           3 :     if (r == 0 || (size_t)r < flushlen0) /* can't flush any more now. */
     211             :       break;
     212             :   }
     213           3 :   tor_assert(flushed <= BUF_MAX_LEN);
     214           3 :   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           0 : buf_flush_to_socket(buf_t *buf, tor_socket_t s, size_t sz)
     225             : {
     226           0 :   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           0 : 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           0 :   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           3 : buf_flush_to_pipe(buf_t *buf, int fd, size_t sz)
     250             : {
     251           3 :   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          10 : buf_read_from_pipe(buf_t *buf, int fd, size_t at_most,
     261             :                    int *reached_eof,
     262             :                    int *socket_error)
     263             : {
     264          10 :   return buf_read_from_fd(buf, fd, at_most, reached_eof, socket_error, false);
     265             : }

Generated by: LCOV version 1.14