tor  0.4.0.1-alpha
buffers_net.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-2019, The Tor Project, Inc. */
5 /* See LICENSE for licensing information */
6 
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 
32 #define check() STMT_BEGIN buf_assert_ok(buf); STMT_END
33 #else
34 #define check() STMT_NIL
35 #endif /* defined(PARANOIA) */
36 
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 < INT_MAX);
80  return (int)read_result;
81  }
82 }
83 
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 >= INT_MAX))
107  return -1;
108  if (BUG(buf->datalen >= INT_MAX - 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 < INT_MAX);
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 
144 static inline int
145 flush_chunk(tor_socket_t fd, buf_t *buf, chunk_t *chunk, size_t sz,
146  size_t *buf_flushlen, bool is_socket)
147 {
148  ssize_t write_result;
149 
150  if (sz > chunk->datalen)
151  sz = chunk->datalen;
152 
153  if (is_socket)
154  write_result = tor_socket_send(fd, chunk->data, sz, 0);
155  else
156  write_result = write(fd, chunk->data, sz);
157 
158  if (write_result < 0) {
159  int e = is_socket ? tor_socket_errno(fd) : errno;
160 
161  if (!ERRNO_IS_EAGAIN(e)) { /* it's a real error */
162 #ifdef _WIN32
163  if (e == WSAENOBUFS)
164  log_warn(LD_NET,"write() failed: WSAENOBUFS. Not enough ram?");
165 #endif
166  return -1;
167  }
168  log_debug(LD_NET,"write() would block, returning.");
169  return 0;
170  } else {
171  *buf_flushlen -= write_result;
172  buf_drain(buf, write_result);
173  tor_assert(write_result < INT_MAX);
174  return (int)write_result;
175  }
176 }
177 
184 static int
185 buf_flush_to_fd(buf_t *buf, int fd, size_t sz,
186  size_t *buf_flushlen, bool is_socket)
187 {
188  /* XXXX It's stupid to overload the return values for these functions:
189  * "error status" and "number of bytes flushed" are not mutually exclusive.
190  */
191  int r;
192  size_t flushed = 0;
193  tor_assert(buf_flushlen);
194  tor_assert(SOCKET_OK(fd));
195  if (BUG(*buf_flushlen > buf->datalen)) {
196  *buf_flushlen = buf->datalen;
197  }
198  if (BUG(sz > *buf_flushlen)) {
199  sz = *buf_flushlen;
200  }
201 
202  check();
203  while (sz) {
204  size_t flushlen0;
205  tor_assert(buf->head);
206  if (buf->head->datalen >= sz)
207  flushlen0 = sz;
208  else
209  flushlen0 = buf->head->datalen;
210 
211  r = flush_chunk(fd, buf, buf->head, flushlen0, buf_flushlen, is_socket);
212  check();
213  if (r < 0)
214  return r;
215  flushed += r;
216  sz -= r;
217  if (r == 0 || (size_t)r < flushlen0) /* can't flush any more now. */
218  break;
219  }
220  tor_assert(flushed < INT_MAX);
221  return (int)flushed;
222 }
223 
230 int
231 buf_flush_to_socket(buf_t *buf, tor_socket_t s, size_t sz,
232  size_t *buf_flushlen)
233 {
234  return buf_flush_to_fd(buf, s, sz, buf_flushlen, true);
235 }
236 
242 int
243 buf_read_from_socket(buf_t *buf, tor_socket_t s, size_t at_most,
244  int *reached_eof,
245  int *socket_error)
246 {
247  return buf_read_from_fd(buf, s, at_most, reached_eof, socket_error, true);
248 }
249 
256 int
257 buf_flush_to_pipe(buf_t *buf, int fd, size_t sz,
258  size_t *buf_flushlen)
259 {
260  return buf_flush_to_fd(buf, fd, sz, buf_flushlen, false);
261 }
262 
268 int
269 buf_read_from_pipe(buf_t *buf, int fd, size_t at_most,
270  int *reached_eof,
271  int *socket_error)
272 {
273  return buf_read_from_fd(buf, fd, at_most, reached_eof, socket_error, false);
274 }
int buf_flush_to_socket(buf_t *buf, tor_socket_t s, size_t sz, size_t *buf_flushlen)
Definition: buffers_net.c:231
chunk_t * buf_add_chunk_with_capacity(buf_t *buf, size_t capacity, int capped)
Definition: buffers.c:473
static int read_to_chunk(buf_t *buf, chunk_t *chunk, tor_socket_t fd, size_t at_most, int *reached_eof, int *error, bool is_socket)
Definition: buffers_net.c:44
int buf_flush_to_pipe(buf_t *buf, int fd, size_t sz, size_t *buf_flushlen)
Definition: buffers_net.c:257
static int flush_chunk(tor_socket_t fd, buf_t *buf, chunk_t *chunk, size_t sz, size_t *buf_flushlen, bool is_socket)
Definition: buffers_net.c:145
static int buf_read_from_fd(buf_t *buf, int fd, size_t at_most, int *reached_eof, int *socket_error, bool is_socket)
Definition: buffers_net.c:91
#define SOCKET_OK(s)
Definition: nettypes.h:39
tor_assert(buffer)
Declarations for types used throughout the Tor networking system.
Header file for buffers_net.c.
int buf_read_from_pipe(buf_t *buf, int fd, size_t at_most, int *reached_eof, int *socket_error)
Definition: buffers_net.c:269
#define tor_socket_t
Definition: nettypes.h:36
void buf_drain(buf_t *buf, size_t n)
Definition: buffers.c:328
Header file for buffers.c.
#define LD_NET
Definition: log.h:62
Headers for log.c.
int buf_read_from_socket(buf_t *buf, tor_socket_t s, size_t at_most, int *reached_eof, int *socket_error)
Definition: buffers_net.c:243
Macros to manage assertions, fatal and non-fatal.
static int buf_flush_to_fd(buf_t *buf, int fd, size_t sz, size_t *buf_flushlen, bool is_socket)
Definition: buffers_net.c:185