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

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

Issue 10916081: Add secure sockets to dart:io (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Address comments, remove HandshakeStartHandler. Created 8 years, 1 month 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 | Annotate | Revision Log
« no previous file with comments | « runtime/bin/net/nss_memio.h ('k') | runtime/bin/tls_socket.h » ('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 #include "bin/net/nss_memio.h"
12
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <string.h>
16
17 #include "prerror.h"
18 #include "prinit.h"
19 #include "prlog.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 uint8_t* 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
60 /*--------------- private memio_buffer functions ---------------------*/
61
62 /* Forward declarations. */
63
64 /* Allocate a memio_buffer of given size. */
65 static void memio_buffer_new(struct memio_buffer *mb, int size);
66
67 /* Deallocate a memio_buffer allocated by memio_buffer_new. */
68 static void memio_buffer_destroy(struct memio_buffer *mb);
69
70 /* How many bytes can be read out of the buffer without wrapping */
71 static int memio_buffer_used_contiguous(const struct memio_buffer *mb);
72
73 /* How many bytes exist after the wrap? */
74 static int memio_buffer_wrapped_bytes(const struct memio_buffer *mb);
75
76 /* How many bytes can be written into the buffer without wrapping */
77 static int memio_buffer_unused_contiguous(const struct memio_buffer *mb);
78
79 /* Write n bytes into the buffer. Returns number of bytes written. */
80 static int memio_buffer_put(struct memio_buffer *mb, const uint8_t* buf, int n);
81
82 /* Read n bytes from the buffer. Returns number of bytes read. */
83 static int memio_buffer_get(struct memio_buffer *mb, uint8_t* buf, int n);
84
85 /* Allocate a memio_buffer of given size. */
86 static void memio_buffer_new(struct memio_buffer *mb, int size) {
87 mb->head = 0;
88 mb->tail = 0;
89 mb->bufsize = size;
90 mb->buf = static_cast<uint8_t*>(malloc(size));
91 }
92
93 /* Deallocate a memio_buffer allocated by memio_buffer_new. */
94 static void memio_buffer_destroy(struct memio_buffer *mb) {
95 free(mb->buf);
96 mb->buf = NULL;
97 mb->head = 0;
98 mb->tail = 0;
99 }
100
101 /* How many bytes can be read out of the buffer without wrapping */
102 static int memio_buffer_used_contiguous(const struct memio_buffer *mb) {
103 return (((mb->tail >= mb->head) ? mb->tail : mb->bufsize) - mb->head);
104 }
105
106 /* How many bytes exist after the wrap? */
107 static int memio_buffer_wrapped_bytes(const struct memio_buffer *mb) {
108 return (mb->tail >= mb->head) ? 0 : mb->tail;
109 }
110
111 /* How many bytes can be written into the buffer without wrapping */
112 static int memio_buffer_unused_contiguous(const struct memio_buffer *mb) {
113 if (mb->head > mb->tail) return mb->head - mb->tail - 1;
114 return mb->bufsize - mb->tail - (mb->head == 0);
115 }
116
117 /* Write n bytes into the buffer. Returns number of bytes written. */
118 static int memio_buffer_put(struct memio_buffer *mb,
119 const uint8_t* buf,
120 int n) {
121 int len;
122 int transferred = 0;
123
124 /* Handle part before wrap */
125 len = PR_MIN(n, memio_buffer_unused_contiguous(mb));
126 if (len > 0) {
127 /* Buffer not full */
128 memmove(&mb->buf[mb->tail], buf, len);
129 mb->tail += len;
130 if (mb->tail == mb->bufsize)
131 mb->tail = 0;
132 n -= len;
133 buf += len;
134 transferred += len;
135
136 /* Handle part after wrap */
137 len = PR_MIN(n, memio_buffer_unused_contiguous(mb));
138 if (len > 0) {
139 /* Output buffer still not full, input buffer still not empty */
140 memmove(&mb->buf[mb->tail], buf, len);
141 mb->tail += len;
142 if (mb->tail == mb->bufsize)
143 mb->tail = 0;
144 transferred += len;
145 }
146 }
147
148 return transferred;
149 }
150
151
152 /* Read n bytes from the buffer. Returns number of bytes read. */
153 static int memio_buffer_get(struct memio_buffer *mb, uint8_t* buf, int n) {
154 int len;
155 int transferred = 0;
156
157 /* Handle part before wrap */
158 len = PR_MIN(n, memio_buffer_used_contiguous(mb));
159 if (len) {
160 memmove(buf, &mb->buf[mb->head], len);
161 mb->head += len;
162 if (mb->head == mb->bufsize)
163 mb->head = 0;
164 n -= len;
165 buf += len;
166 transferred += len;
167
168 /* Handle part after wrap */
169 len = PR_MIN(n, memio_buffer_used_contiguous(mb));
170 if (len) {
171 memmove(buf, &mb->buf[mb->head], len);
172 mb->head += len;
173 if (mb->head == mb->bufsize)
174 mb->head = 0;
175 transferred += len;
176 }
177 }
178
179 return transferred;
180 }
181
182 /*--------------- private memio functions -----------------------*/
183
184 static PRStatus PR_CALLBACK memio_Close(PRFileDesc *fd) {
185 struct PRFilePrivate *secret = fd->secret;
186 memio_buffer_destroy(&secret->readbuf);
187 memio_buffer_destroy(&secret->writebuf);
188 free(secret);
189 fd->dtor(fd);
190 return PR_SUCCESS;
191 }
192
193 static PRStatus PR_CALLBACK memio_Shutdown(PRFileDesc *fd, PRIntn how) {
194 /* TODO: pass shutdown status to app somehow */
195 return PR_SUCCESS;
196 }
197
198 /* If there was a network error in the past taking bytes
199 * out of the buffer, return it to the next call that
200 * tries to read from an empty buffer.
201 */
202 static int PR_CALLBACK memio_Recv(PRFileDesc *fd,
203 uint8_t *buf,
204 PRInt32 len,
205 PRIntn flags,
206 PRIntervalTime timeout) {
207 struct PRFilePrivate *secret;
208 struct memio_buffer *mb;
209 int rv;
210
211 if (flags) {
212 PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
213 return -1;
214 }
215
216 secret = fd->secret;
217 mb = &secret->readbuf;
218 PR_ASSERT(mb->bufsize);
219 rv = memio_buffer_get(mb, buf, len);
220 if (rv == 0 && !secret->eof) {
221 if (mb->last_err)
222 PR_SetError(mb->last_err, 0);
223 else
224 PR_SetError(PR_WOULD_BLOCK_ERROR, 0);
225 return -1;
226 }
227
228 return rv;
229 }
230
231 static int PR_CALLBACK memio_Read(PRFileDesc *fd, uint8_t *buf, PRInt32 len) {
232 /* pull bytes from buffer */
233 return memio_Recv(fd, buf, len, 0, PR_INTERVAL_NO_TIMEOUT);
234 }
235
236 static int PR_CALLBACK memio_Send(PRFileDesc *fd,
237 const uint8_t *buf,
238 PRInt32 len,
239 PRIntn flags,
240 PRIntervalTime timeout) {
241 struct PRFilePrivate *secret;
242 struct memio_buffer *mb;
243 int rv;
244
245 secret = fd->secret;
246 mb = &secret->writebuf;
247 PR_ASSERT(mb->bufsize);
248
249 if (mb->last_err) {
250 PR_SetError(mb->last_err, 0);
251 return -1;
252 }
253 rv = memio_buffer_put(mb, buf, len);
254 if (rv == 0) {
255 PR_SetError(PR_WOULD_BLOCK_ERROR, 0);
256 return -1;
257 }
258 return rv;
259 }
260
261 static int PR_CALLBACK memio_Write(PRFileDesc *fd,
262 const uint8_t *buf,
263 PRInt32 len) {
264 /* append bytes to buffer */
265 return memio_Send(fd, buf, len, 0, PR_INTERVAL_NO_TIMEOUT);
266 }
267
268 static PRStatus PR_CALLBACK memio_GetPeerName(PRFileDesc *fd, PRNetAddr *addr) {
269 /* TODO: fail if memio_SetPeerName has not been called */
270 struct PRFilePrivate *secret = fd->secret;
271 *addr = secret->peername;
272 return PR_SUCCESS;
273 }
274
275 static PRStatus memio_GetSocketOption(PRFileDesc *fd,
276 PRSocketOptionData *data) {
277 /*
278 * Even in the original version for real tcp sockets,
279 * PR_SockOpt_Nonblocking is a special case that does not
280 * translate to a getsockopt() call
281 */
282 if (PR_SockOpt_Nonblocking == data->option) {
283 data->value.non_blocking = PR_TRUE;
284 return PR_SUCCESS;
285 }
286 PR_SetError(PR_OPERATION_NOT_SUPPORTED_ERROR, 0);
287 return PR_FAILURE;
288 }
289
290 /*--------------- private memio data -----------------------*/
291
292 /*
293 * Implement just the bare minimum number of methods needed to make ssl happy.
294 *
295 * Oddly, PR_Recv calls ssl_Recv calls ssl_SocketIsBlocking calls
296 * PR_GetSocketOption, so we have to provide an implementation of
297 * PR_GetSocketOption that just says "I'm nonblocking".
298 */
299
300 static struct PRIOMethods memio_layer_methods = {
301 PR_DESC_LAYERED,
302 memio_Close,
303 (PRReadFN)memio_Read,
304 (PRWriteFN)memio_Write,
305 NULL,
306 NULL,
307 NULL,
308 NULL,
309 NULL,
310 NULL,
311 NULL,
312 NULL,
313 NULL,
314 NULL,
315 NULL,
316 NULL,
317 memio_Shutdown,
318 (PRRecvFN)memio_Recv,
319 (PRSendFN)memio_Send,
320 NULL,
321 NULL,
322 NULL,
323 NULL,
324 NULL,
325 NULL,
326 memio_GetPeerName,
327 NULL,
328 NULL,
329 memio_GetSocketOption,
330 NULL,
331 NULL,
332 NULL,
333 NULL,
334 NULL,
335 NULL,
336 NULL,
337 };
338
339 static PRDescIdentity memio_identity = PR_INVALID_IO_LAYER;
340
341 static PRStatus memio_InitializeLayerName(void) {
342 memio_identity = PR_GetUniqueIdentity("memio");
343 return PR_SUCCESS;
344 }
345
346 /*--------------- public memio functions -----------------------*/
347
348 PRFileDesc *memio_CreateIOLayer(int bufsize) {
349 PRFileDesc *fd;
350 struct PRFilePrivate *secret;
351 static PRCallOnceType once;
352
353 PR_CallOnce(&once, memio_InitializeLayerName);
354
355 fd = PR_CreateIOLayerStub(memio_identity, &memio_layer_methods);
356 secret = static_cast<PRFilePrivate*>(malloc(sizeof(struct PRFilePrivate)));
357 memset(secret, 0, sizeof(*secret));
358
359 memio_buffer_new(&secret->readbuf, bufsize);
360 memio_buffer_new(&secret->writebuf, bufsize);
361 fd->secret = secret;
362 return fd;
363 }
364
365 void memio_SetPeerName(PRFileDesc* fd, const PRNetAddr* peername) {
366 PRFileDesc *memiofd = PR_GetIdentitiesLayer(fd, memio_identity);
367 struct PRFilePrivate *secret = memiofd->secret;
368 secret->peername = *peername;
369 }
370
371 memio_Private* memio_GetSecret(PRFileDesc* fd) {
372 PRFileDesc* memiofd = PR_GetIdentitiesLayer(fd, memio_identity);
373 return reinterpret_cast<memio_Private*>(memiofd->secret);
374 }
375
376 int memio_GetReadParams(memio_Private* secret, uint8_t** buf) {
377 struct memio_buffer* mb =
378 &(reinterpret_cast<PRFilePrivate*>(secret)->readbuf);
379 PR_ASSERT(mb->bufsize);
380
381 *buf = &mb->buf[mb->tail];
382 return memio_buffer_unused_contiguous(mb);
383 }
384
385 void memio_PutReadResult(memio_Private *secret, int bytes_read) {
386 struct memio_buffer* mb =
387 &(reinterpret_cast<PRFilePrivate*>(secret)->readbuf);
388 PR_ASSERT(mb->bufsize);
389
390 if (bytes_read > 0) {
391 mb->tail += bytes_read;
392 if (mb->tail == mb->bufsize)
393 mb->tail = 0;
394 } else if (bytes_read == 0) {
395 /* Record EOF condition and report to caller when buffer runs dry */
396 reinterpret_cast<PRFilePrivate*>(secret)->eof = PR_TRUE;
397 } else /* if (bytes_read < 0) */ {
398 mb->last_err = bytes_read;
399 }
400 }
401
402 void memio_GetWriteParams(memio_Private *secret,
403 const uint8_t** buf1, unsigned int *len1,
404 const uint8_t** buf2, unsigned int *len2) {
405 struct memio_buffer* mb =
406 &(reinterpret_cast<PRFilePrivate*>(secret)->writebuf);
407 PR_ASSERT(mb->bufsize);
408
409 *buf1 = &mb->buf[mb->head];
410 *len1 = memio_buffer_used_contiguous(mb);
411 *buf2 = mb->buf;
412 *len2 = memio_buffer_wrapped_bytes(mb);
413 }
414
415 void memio_PutWriteResult(memio_Private *secret, int bytes_written) {
416 struct memio_buffer* mb =
417 &(reinterpret_cast<PRFilePrivate*>(secret)->writebuf);
418 PR_ASSERT(mb->bufsize);
419
420 if (bytes_written > 0) {
421 mb->head += bytes_written;
422 if (mb->head >= mb->bufsize)
423 mb->head -= mb->bufsize;
424 } else if (bytes_written < 0) {
425 mb->last_err = bytes_written;
426 }
427 }
428
429 /*--------------- private memio_buffer self-test -----------------*/
430
431 /* Even a trivial unit test is very helpful when doing circular buffers. */
432 /*#define TRIVIAL_SELF_TEST*/
433 #ifdef TRIVIAL_SELF_TEST
434
435 #define TEST_BUFLEN 7
436
437 #define CHECKEQ(a, b) { \
438 if ((a) != (b)) { \
439 printf("%d != %d, Test failed line %d\n", a, b, __LINE__); \
440 exit(1); \
441 } \
442 }
443
444 #define FROM_STR(a) reinterpret_cast<const uint8_t*>(a)
445
446 int main() {
447 struct memio_buffer mb;
448 uint8_t buf[100];
449 int i;
450
451 memio_buffer_new(&mb, TEST_BUFLEN);
452
453 CHECKEQ(memio_buffer_unused_contiguous(&mb), TEST_BUFLEN-1);
454 CHECKEQ(memio_buffer_used_contiguous(&mb), 0);
455
456 CHECKEQ(memio_buffer_put(&mb, FROM_STR("howdy"), 5), 5);
457
458 CHECKEQ(memio_buffer_unused_contiguous(&mb), TEST_BUFLEN-1-5);
459 CHECKEQ(memio_buffer_used_contiguous(&mb), 5);
460 CHECKEQ(memio_buffer_wrapped_bytes(&mb), 0);
461
462 CHECKEQ(memio_buffer_put(&mb, FROM_STR("!"), 1), 1);
463
464 CHECKEQ(memio_buffer_unused_contiguous(&mb), 0);
465 CHECKEQ(memio_buffer_used_contiguous(&mb), 6);
466 CHECKEQ(memio_buffer_wrapped_bytes(&mb), 0);
467
468 CHECKEQ(memio_buffer_get(&mb, buf, 6), 6);
469 CHECKEQ(memcmp(buf, FROM_STR("howdy!"), 6), 0);
470
471 CHECKEQ(memio_buffer_unused_contiguous(&mb), 1);
472 CHECKEQ(memio_buffer_used_contiguous(&mb), 0);
473
474 CHECKEQ(memio_buffer_put(&mb, FROM_STR("01234"), 5), 5);
475
476 CHECKEQ(memio_buffer_used_contiguous(&mb), 1);
477 CHECKEQ(memio_buffer_wrapped_bytes(&mb), 4);
478 CHECKEQ(memio_buffer_unused_contiguous(&mb), TEST_BUFLEN-1-5);
479
480 CHECKEQ(memio_buffer_put(&mb, FROM_STR("5"), 1), 1);
481
482 CHECKEQ(memio_buffer_unused_contiguous(&mb), 0);
483 CHECKEQ(memio_buffer_used_contiguous(&mb), 1);
484
485 /* TODO: add more cases */
486
487 printf("Test passed\n");
488 exit(0);
489 }
490
491 #endif
OLDNEW
« no previous file with comments | « runtime/bin/net/nss_memio.h ('k') | runtime/bin/tls_socket.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698