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

Side by Side Diff: net/base/nss_memio.c

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

Powered by Google App Engine
This is Rietveld 408576698