Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(61)

Side by Side Diff: runtime/bin/net/nss_memio.cc

Issue 1319703002: Breaking Change: merge BoringSSL branch into master (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Created 5 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « runtime/bin/net/nss_memio.h ('k') | runtime/bin/net/os_linux.S » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright (c) 2008 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 // Written in NSPR style to also be suitable for adding to the NSS demo suite
5
6 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
7 // for details. All rights reserved. Use of this source code is governed by a
8 // BSD-style license that can be found in the LICENSE file.
9
10 // This file is a modified copy of Chromium's src/net/base/nss_memio.c.
11 // char* has been changed to uint8_t* everywhere, and C++ casts are used.
12 // Revision 291806 (this should agree with "nss_rev" in DEPS).
13
14
15 /* memio is a simple NSPR I/O layer that lets you decouple NSS from
16 * the real network. It's rather like openssl's memory bio,
17 * and is useful when your app absolutely, positively doesn't
18 * want to let NSS do its own networking.
19 */
20 #include "bin/net/nss_memio.h"
21
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25
26 #include "prerror.h"
27 #include "prinit.h"
28 #include "prlog.h"
29
30 /*--------------- private memio types -----------------------*/
31
32 /*----------------------------------------------------------------------
33 Simple private circular buffer class. Size cannot be changed once allocated.
34 ----------------------------------------------------------------------*/
35
36 struct memio_buffer {
37 int head; /* where to take next byte out of buf */
38 int tail; /* where to put next byte into buf */
39 int bufsize; /* number of bytes allocated to buf */
40 /* TODO(port): error handling is pessimistic right now.
41 * Once an error is set, the socket is considered broken
42 * (PR_WOULD_BLOCK_ERROR not included).
43 */
44 PRErrorCode last_err;
45 uint8_t* buf;
46 };
47
48
49 /* The 'secret' field of a PRFileDesc created by memio_CreateIOLayer points
50 * to one of these.
51 * In the public header, we use struct memio_Private as a typesafe alias
52 * for this. This causes a few ugly typecasts in the private file, but
53 * seems safer.
54 */
55 struct PRFilePrivate {
56 /* read requests are satisfied from this buffer */
57 struct memio_buffer readbuf;
58
59 /* write requests are satisfied from this buffer */
60 struct memio_buffer writebuf;
61
62 /* SSL needs to know socket peer's name */
63 PRNetAddr peername;
64
65 /* if set, empty I/O returns EOF instead of EWOULDBLOCK */
66 int eof;
67
68 /* if set, the number of bytes requested from readbuf that were not
69 * fulfilled (due to readbuf being empty) */
70 int read_requested;
71 };
72
73 /*--------------- private memio_buffer functions ---------------------*/
74
75 /* Forward declarations. */
76
77 /* Allocate a memio_buffer of given size. */
78 static void memio_buffer_new(struct memio_buffer *mb, int size);
79
80 /* Deallocate a memio_buffer allocated by memio_buffer_new. */
81 static void memio_buffer_destroy(struct memio_buffer *mb);
82
83 /* How many bytes can be read out of the buffer without wrapping */
84 static int memio_buffer_used_contiguous(const struct memio_buffer *mb);
85
86 /* How many bytes exist after the wrap? */
87 static int memio_buffer_wrapped_bytes(const struct memio_buffer *mb);
88
89 /* How many bytes can be written into the buffer without wrapping */
90 static int memio_buffer_unused_contiguous(const struct memio_buffer *mb);
91
92 /* Write n bytes into the buffer. Returns number of bytes written. */
93 static int memio_buffer_put(struct memio_buffer *mb, const uint8_t* buf, int n);
94
95 /* Read n bytes from the buffer. Returns number of bytes read. */
96 static int memio_buffer_get(struct memio_buffer *mb, uint8_t* buf, int n);
97
98 /* Allocate a memio_buffer of given size. */
99 static void memio_buffer_new(struct memio_buffer *mb, int size) {
100 mb->head = 0;
101 mb->tail = 0;
102 mb->bufsize = size;
103 mb->buf = static_cast<uint8_t*>(malloc(size));
104 }
105
106 /* Deallocate a memio_buffer allocated by memio_buffer_new. */
107 static void memio_buffer_destroy(struct memio_buffer *mb) {
108 free(mb->buf);
109 mb->buf = NULL;
110 mb->bufsize = 0;
111 mb->head = 0;
112 mb->tail = 0;
113 }
114
115 /* How many bytes can be read out of the buffer without wrapping */
116 static int memio_buffer_used_contiguous(const struct memio_buffer *mb) {
117 return (((mb->tail >= mb->head) ? mb->tail : mb->bufsize) - mb->head);
118 }
119
120 /* How many bytes exist after the wrap? */
121 static int memio_buffer_wrapped_bytes(const struct memio_buffer *mb) {
122 return (mb->tail >= mb->head) ? 0 : mb->tail;
123 }
124
125 /* How many bytes can be written into the buffer without wrapping */
126 static int memio_buffer_unused_contiguous(const struct memio_buffer *mb) {
127 if (mb->head > mb->tail) return mb->head - mb->tail - 1;
128 return mb->bufsize - mb->tail - (mb->head == 0);
129 }
130
131 /* Write n bytes into the buffer. Returns number of bytes written. */
132 static int memio_buffer_put(struct memio_buffer *mb,
133 const uint8_t* buf,
134 int n) {
135 int len;
136 int transferred = 0;
137
138 /* Handle part before wrap */
139 len = PR_MIN(n, memio_buffer_unused_contiguous(mb));
140 if (len > 0) {
141 /* Buffer not full */
142 memmove(&mb->buf[mb->tail], buf, len);
143 mb->tail += len;
144 if (mb->tail == mb->bufsize)
145 mb->tail = 0;
146 n -= len;
147 buf += len;
148 transferred += len;
149
150 /* Handle part after wrap */
151 len = PR_MIN(n, memio_buffer_unused_contiguous(mb));
152 if (len > 0) {
153 /* Output buffer still not full, input buffer still not empty */
154 memmove(&mb->buf[mb->tail], buf, len);
155 mb->tail += len;
156 if (mb->tail == mb->bufsize)
157 mb->tail = 0;
158 transferred += len;
159 }
160 }
161
162 return transferred;
163 }
164
165
166 /* Read n bytes from the buffer. Returns number of bytes read. */
167 static int memio_buffer_get(struct memio_buffer *mb, uint8_t* buf, int n) {
168 int len;
169 int transferred = 0;
170
171 /* Handle part before wrap */
172 len = PR_MIN(n, memio_buffer_used_contiguous(mb));
173 if (len) {
174 memmove(buf, &mb->buf[mb->head], len);
175 mb->head += len;
176 if (mb->head == mb->bufsize)
177 mb->head = 0;
178 n -= len;
179 buf += len;
180 transferred += len;
181
182 /* Handle part after wrap */
183 len = PR_MIN(n, memio_buffer_used_contiguous(mb));
184 if (len) {
185 memmove(buf, &mb->buf[mb->head], len);
186 mb->head += len;
187 if (mb->head == mb->bufsize)
188 mb->head = 0;
189 transferred += len;
190 }
191 }
192
193 return transferred;
194 }
195
196 /*--------------- private memio functions -----------------------*/
197
198 static PRStatus PR_CALLBACK memio_Close(PRFileDesc *fd) {
199 struct PRFilePrivate *secret = fd->secret;
200 memio_buffer_destroy(&secret->readbuf);
201 memio_buffer_destroy(&secret->writebuf);
202 free(secret);
203 fd->dtor(fd);
204 return PR_SUCCESS;
205 }
206
207 static PRStatus PR_CALLBACK memio_Shutdown(PRFileDesc *fd, PRIntn how) {
208 /* TODO: pass shutdown status to app somehow */
209 return PR_SUCCESS;
210 }
211
212 /* If there was a network error in the past taking bytes
213 * out of the buffer, return it to the next call that
214 * tries to read from an empty buffer.
215 */
216 static int PR_CALLBACK memio_Recv(PRFileDesc *fd,
217 uint8_t *buf,
218 PRInt32 len,
219 PRIntn flags,
220 PRIntervalTime timeout) {
221 struct PRFilePrivate *secret;
222 struct memio_buffer *mb;
223 int rv;
224
225 if (flags) {
226 PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
227 return -1;
228 }
229
230 secret = fd->secret;
231 mb = &secret->readbuf;
232 PR_ASSERT(mb->bufsize);
233 rv = memio_buffer_get(mb, buf, len);
234 if (rv == 0 && !secret->eof) {
235 secret->read_requested = len;
236 /* If there is no more data in the buffer, report any pending errors
237 * that were previously observed. Note that both the readbuf and the
238 * writebuf are checked for errors, since the application may have
239 * encountered a socket error while writing that would otherwise not
240 * be reported until the application attempted to write again - which
241 * it may never do.
242 */
243 if (mb->last_err)
244 PR_SetError(mb->last_err, 0);
245 else if (secret->writebuf.last_err)
246 PR_SetError(secret->writebuf.last_err, 0);
247 else
248 PR_SetError(PR_WOULD_BLOCK_ERROR, 0);
249 return -1;
250 }
251
252 secret->read_requested = 0;
253 return rv;
254 }
255
256 static int PR_CALLBACK memio_Read(PRFileDesc *fd, uint8_t *buf, PRInt32 len) {
257 /* pull bytes from buffer */
258 return memio_Recv(fd, buf, len, 0, PR_INTERVAL_NO_TIMEOUT);
259 }
260
261 static int PR_CALLBACK memio_Send(PRFileDesc *fd,
262 const uint8_t *buf,
263 PRInt32 len,
264 PRIntn flags,
265 PRIntervalTime timeout) {
266 struct PRFilePrivate *secret;
267 struct memio_buffer *mb;
268 int rv;
269
270 secret = fd->secret;
271 mb = &secret->writebuf;
272 PR_ASSERT(mb->bufsize);
273
274 /* Note that the read error state is not reported, because it cannot be
275 * reported until all buffered data has been read. If there is an error
276 * with the next layer, attempting to call Send again will report the
277 * error appropriately.
278 */
279 if (mb->last_err) {
280 PR_SetError(mb->last_err, 0);
281 return -1;
282 }
283 rv = memio_buffer_put(mb, buf, len);
284 if (rv == 0) {
285 PR_SetError(PR_WOULD_BLOCK_ERROR, 0);
286 return -1;
287 }
288 return rv;
289 }
290
291 static int PR_CALLBACK memio_Write(PRFileDesc *fd,
292 const uint8_t *buf,
293 PRInt32 len) {
294 /* append bytes to buffer */
295 return memio_Send(fd, buf, len, 0, PR_INTERVAL_NO_TIMEOUT);
296 }
297
298 static PRStatus PR_CALLBACK memio_GetPeerName(PRFileDesc *fd, PRNetAddr *addr) {
299 /* TODO: fail if memio_SetPeerName has not been called */
300 struct PRFilePrivate *secret = fd->secret;
301 *addr = secret->peername;
302 return PR_SUCCESS;
303 }
304
305 static PRStatus memio_GetSocketOption(PRFileDesc *fd,
306 PRSocketOptionData *data) {
307 /*
308 * Even in the original version for real tcp sockets,
309 * PR_SockOpt_Nonblocking is a special case that does not
310 * translate to a getsockopt() call
311 */
312 if (PR_SockOpt_Nonblocking == data->option) {
313 data->value.non_blocking = PR_TRUE;
314 return PR_SUCCESS;
315 }
316 PR_SetError(PR_OPERATION_NOT_SUPPORTED_ERROR, 0);
317 return PR_FAILURE;
318 }
319
320 /*--------------- private memio data -----------------------*/
321
322 /*
323 * Implement just the bare minimum number of methods needed to make ssl happy.
324 *
325 * Oddly, PR_Recv calls ssl_Recv calls ssl_SocketIsBlocking calls
326 * PR_GetSocketOption, so we have to provide an implementation of
327 * PR_GetSocketOption that just says "I'm nonblocking".
328 */
329
330 static struct PRIOMethods memio_layer_methods = {
331 PR_DESC_LAYERED,
332 memio_Close,
333 (PRReadFN)memio_Read,
334 (PRWriteFN)memio_Write,
335 NULL,
336 NULL,
337 NULL,
338 NULL,
339 NULL,
340 NULL,
341 NULL,
342 NULL,
343 NULL,
344 NULL,
345 NULL,
346 NULL,
347 memio_Shutdown,
348 (PRRecvFN)memio_Recv,
349 (PRSendFN)memio_Send,
350 NULL,
351 NULL,
352 NULL,
353 NULL,
354 NULL,
355 NULL,
356 memio_GetPeerName,
357 NULL,
358 NULL,
359 memio_GetSocketOption,
360 NULL,
361 NULL,
362 NULL,
363 NULL,
364 NULL,
365 NULL,
366 NULL,
367 };
368
369 static PRDescIdentity memio_identity = PR_INVALID_IO_LAYER;
370
371 static PRStatus memio_InitializeLayerName(void) {
372 memio_identity = PR_GetUniqueIdentity("memio");
373 return PR_SUCCESS;
374 }
375
376 /*--------------- public memio functions -----------------------*/
377
378 PRFileDesc *memio_CreateIOLayer(int readbufsize, int writebufsize) {
379 PRFileDesc *fd;
380 struct PRFilePrivate *secret;
381 static PRCallOnceType once;
382
383 PR_CallOnce(&once, memio_InitializeLayerName);
384
385 fd = PR_CreateIOLayerStub(memio_identity, &memio_layer_methods);
386 secret = static_cast<PRFilePrivate*>(malloc(sizeof(struct PRFilePrivate)));
387 memset(secret, 0, sizeof(*secret));
388
389 memio_buffer_new(&secret->readbuf, readbufsize);
390 memio_buffer_new(&secret->writebuf, writebufsize);
391 fd->secret = secret;
392 return fd;
393 }
394
395 void memio_SetPeerName(PRFileDesc* fd, const PRNetAddr* peername) {
396 PRFileDesc *memiofd = PR_GetIdentitiesLayer(fd, memio_identity);
397 struct PRFilePrivate *secret = memiofd->secret;
398 secret->peername = *peername;
399 }
400
401 memio_Private* memio_GetSecret(PRFileDesc* fd) {
402 PRFileDesc* memiofd = PR_GetIdentitiesLayer(fd, memio_identity);
403 struct PRFilePrivate *secret = memiofd->secret;
404 return reinterpret_cast<memio_Private*>(secret);
405 }
406
407 int memio_GetReadRequest(memio_Private *secret) {
408 return reinterpret_cast<PRFilePrivate*>(secret)->read_requested;
409 }
410
411 int memio_GetReadParams(memio_Private* secret, uint8_t** buf) {
412 struct memio_buffer* mb =
413 &(reinterpret_cast<PRFilePrivate*>(secret)->readbuf);
414 PR_ASSERT(mb->bufsize);
415
416 *buf = &mb->buf[mb->tail];
417 return memio_buffer_unused_contiguous(mb);
418 }
419
420 int memio_GetReadableBufferSize(memio_Private *secret) {
421 struct memio_buffer* mb =
422 &(reinterpret_cast<PRFilePrivate*>(secret)->readbuf);
423 PR_ASSERT(mb->bufsize);
424
425 return memio_buffer_used_contiguous(mb);
426 }
427
428 void memio_PutReadResult(memio_Private *secret, int bytes_read) {
429 struct memio_buffer* mb =
430 &(reinterpret_cast<PRFilePrivate*>(secret)->readbuf);
431 PR_ASSERT(mb->bufsize);
432
433 if (bytes_read > 0) {
434 mb->tail += bytes_read;
435 if (mb->tail == mb->bufsize)
436 mb->tail = 0;
437 } else if (bytes_read == 0) {
438 /* Record EOF condition and report to caller when buffer runs dry */
439 reinterpret_cast<PRFilePrivate*>(secret)->eof = PR_TRUE;
440 } else /* if (bytes_read < 0) */ {
441 mb->last_err = bytes_read;
442 }
443 }
444
445 int memio_GetWriteParams(memio_Private *secret,
446 const uint8_t** buf1, unsigned int *len1,
447 const uint8_t** buf2, unsigned int *len2) {
448 struct memio_buffer* mb =
449 &(reinterpret_cast<PRFilePrivate*>(secret)->writebuf);
450 PR_ASSERT(mb->bufsize);
451
452 if (mb->last_err)
453 return mb->last_err;
454
455 *buf1 = &mb->buf[mb->head];
456 *len1 = memio_buffer_used_contiguous(mb);
457 *buf2 = mb->buf;
458 *len2 = memio_buffer_wrapped_bytes(mb);
459 return 0;
460 }
461
462 void memio_PutWriteResult(memio_Private *secret, int bytes_written) {
463 struct memio_buffer* mb =
464 &(reinterpret_cast<PRFilePrivate*>(secret)->writebuf);
465 PR_ASSERT(mb->bufsize);
466
467 if (bytes_written > 0) {
468 mb->head += bytes_written;
469 if (mb->head >= mb->bufsize)
470 mb->head -= mb->bufsize;
471 } else if (bytes_written < 0) {
472 mb->last_err = bytes_written;
473 }
474 }
475
476 /*--------------- private memio_buffer self-test -----------------*/
477
478 /* Even a trivial unit test is very helpful when doing circular buffers. */
479 /*#define TRIVIAL_SELF_TEST*/
480 #ifdef TRIVIAL_SELF_TEST
481
482 #define TEST_BUFLEN 7
483
484 #define CHECKEQ(a, b) { \
485 if ((a) != (b)) { \
486 printf("%d != %d, Test failed line %d\n", a, b, __LINE__); \
487 exit(1); \
488 } \
489 }
490
491 #define FROM_STR(a) reinterpret_cast<const uint8_t*>(a)
492
493 int main() {
494 struct memio_buffer mb;
495 uint8_t buf[100];
496 int i;
497
498 memio_buffer_new(&mb, TEST_BUFLEN);
499
500 CHECKEQ(memio_buffer_unused_contiguous(&mb), TEST_BUFLEN-1);
501 CHECKEQ(memio_buffer_used_contiguous(&mb), 0);
502
503 CHECKEQ(memio_buffer_put(&mb, FROM_STR("howdy"), 5), 5);
504
505 CHECKEQ(memio_buffer_unused_contiguous(&mb), TEST_BUFLEN-1-5);
506 CHECKEQ(memio_buffer_used_contiguous(&mb), 5);
507 CHECKEQ(memio_buffer_wrapped_bytes(&mb), 0);
508
509 CHECKEQ(memio_buffer_put(&mb, FROM_STR("!"), 1), 1);
510
511 CHECKEQ(memio_buffer_unused_contiguous(&mb), 0);
512 CHECKEQ(memio_buffer_used_contiguous(&mb), 6);
513 CHECKEQ(memio_buffer_wrapped_bytes(&mb), 0);
514
515 CHECKEQ(memio_buffer_get(&mb, buf, 6), 6);
516 CHECKEQ(memcmp(buf, FROM_STR("howdy!"), 6), 0);
517
518 CHECKEQ(memio_buffer_unused_contiguous(&mb), 1);
519 CHECKEQ(memio_buffer_used_contiguous(&mb), 0);
520
521 CHECKEQ(memio_buffer_put(&mb, FROM_STR("01234"), 5), 5);
522
523 CHECKEQ(memio_buffer_used_contiguous(&mb), 1);
524 CHECKEQ(memio_buffer_wrapped_bytes(&mb), 4);
525 CHECKEQ(memio_buffer_unused_contiguous(&mb), TEST_BUFLEN-1-5);
526
527 CHECKEQ(memio_buffer_put(&mb, FROM_STR("5"), 1), 1);
528
529 CHECKEQ(memio_buffer_unused_contiguous(&mb), 0);
530 CHECKEQ(memio_buffer_used_contiguous(&mb), 1);
531
532 /* TODO: add more cases */
533
534 printf("Test passed\n");
535 exit(0);
536 }
537
538 #endif
OLDNEW
« no previous file with comments | « runtime/bin/net/nss_memio.h ('k') | runtime/bin/net/os_linux.S » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698