cc: Added inline to Tile::IsReadyToDraw
[chromium-blink-merge.git] / net / base / nss_memio.c
blob51012e608c49cd87c1629ee8e7312173c87f36d3
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
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.
12 #include <stdlib.h>
13 #include <string.h>
15 #include <prerror.h>
16 #include <prinit.h>
17 #include <prlog.h>
19 #include "nss_memio.h"
21 /*--------------- private memio types -----------------------*/
23 /*----------------------------------------------------------------------
24 Simple private circular buffer class. Size cannot be changed once allocated.
25 ----------------------------------------------------------------------*/
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).
35 PRErrorCode last_err;
36 char *buf;
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.
46 struct PRFilePrivate {
47 /* read requests are satisfied from this buffer */
48 struct memio_buffer readbuf;
50 /* write requests are satisfied from this buffer */
51 struct memio_buffer writebuf;
53 /* SSL needs to know socket peer's name */
54 PRNetAddr peername;
56 /* if set, empty I/O returns EOF instead of EWOULDBLOCK */
57 int eof;
59 /* if set, the number of bytes requested from readbuf that were not
60 * fulfilled (due to readbuf being empty) */
61 int read_requested;
64 /*--------------- private memio_buffer functions ---------------------*/
66 /* Forward declarations. */
68 /* Allocate a memio_buffer of given size. */
69 static void memio_buffer_new(struct memio_buffer *mb, int size);
71 /* Deallocate a memio_buffer allocated by memio_buffer_new. */
72 static void memio_buffer_destroy(struct memio_buffer *mb);
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);
77 /* How many bytes exist after the wrap? */
78 static int memio_buffer_wrapped_bytes(const struct memio_buffer *mb);
80 /* How many bytes can be written into the buffer without wrapping */
81 static int memio_buffer_unused_contiguous(const struct memio_buffer *mb);
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);
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);
89 /* Allocate a memio_buffer of given size. */
90 static void memio_buffer_new(struct memio_buffer *mb, int size)
92 mb->head = 0;
93 mb->tail = 0;
94 mb->bufsize = size;
95 mb->buf = malloc(size);
98 /* Deallocate a memio_buffer allocated by memio_buffer_new. */
99 static void memio_buffer_destroy(struct memio_buffer *mb)
101 free(mb->buf);
102 mb->buf = NULL;
103 mb->head = 0;
104 mb->tail = 0;
107 /* How many bytes can be read out of the buffer without wrapping */
108 static int memio_buffer_used_contiguous(const struct memio_buffer *mb)
110 return (((mb->tail >= mb->head) ? mb->tail : mb->bufsize) - mb->head);
113 /* How many bytes exist after the wrap? */
114 static int memio_buffer_wrapped_bytes(const struct memio_buffer *mb)
116 return (mb->tail >= mb->head) ? 0 : mb->tail;
119 /* How many bytes can be written into the buffer without wrapping */
120 static int memio_buffer_unused_contiguous(const struct memio_buffer *mb)
122 if (mb->head > mb->tail) return mb->head - mb->tail - 1;
123 return mb->bufsize - mb->tail - (mb->head == 0);
126 /* Write n bytes into the buffer. Returns number of bytes written. */
127 static int memio_buffer_put(struct memio_buffer *mb, const char *buf, int n)
129 int len;
130 int transferred = 0;
132 /* Handle part before wrap */
133 len = PR_MIN(n, memio_buffer_unused_contiguous(mb));
134 if (len > 0) {
135 /* Buffer not full */
136 memcpy(&mb->buf[mb->tail], buf, len);
137 mb->tail += len;
138 if (mb->tail == mb->bufsize)
139 mb->tail = 0;
140 n -= len;
141 buf += len;
142 transferred += len;
144 /* Handle part after wrap */
145 len = PR_MIN(n, memio_buffer_unused_contiguous(mb));
146 if (len > 0) {
147 /* Output buffer still not full, input buffer still not empty */
148 memcpy(&mb->buf[mb->tail], buf, len);
149 mb->tail += len;
150 if (mb->tail == mb->bufsize)
151 mb->tail = 0;
152 transferred += len;
156 return transferred;
160 /* Read n bytes from the buffer. Returns number of bytes read. */
161 static int memio_buffer_get(struct memio_buffer *mb, char *buf, int n)
163 int len;
164 int transferred = 0;
166 /* Handle part before wrap */
167 len = PR_MIN(n, memio_buffer_used_contiguous(mb));
168 if (len) {
169 memcpy(buf, &mb->buf[mb->head], len);
170 mb->head += len;
171 if (mb->head == mb->bufsize)
172 mb->head = 0;
173 n -= len;
174 buf += len;
175 transferred += len;
177 /* Handle part after wrap */
178 len = PR_MIN(n, memio_buffer_used_contiguous(mb));
179 if (len) {
180 memcpy(buf, &mb->buf[mb->head], len);
181 mb->head += len;
182 if (mb->head == mb->bufsize)
183 mb->head = 0;
184 transferred += len;
188 return transferred;
191 /*--------------- private memio functions -----------------------*/
193 static PRStatus PR_CALLBACK memio_Close(PRFileDesc *fd)
195 struct PRFilePrivate *secret = fd->secret;
196 memio_buffer_destroy(&secret->readbuf);
197 memio_buffer_destroy(&secret->writebuf);
198 free(secret);
199 fd->dtor(fd);
200 return PR_SUCCESS;
203 static PRStatus PR_CALLBACK memio_Shutdown(PRFileDesc *fd, PRIntn how)
205 /* TODO: pass shutdown status to app somehow */
206 return PR_SUCCESS;
209 /* If there was a network error in the past taking bytes
210 * out of the buffer, return it to the next call that
211 * tries to read from an empty buffer.
213 static int PR_CALLBACK memio_Recv(PRFileDesc *fd, void *buf, PRInt32 len,
214 PRIntn flags, PRIntervalTime timeout)
216 struct PRFilePrivate *secret;
217 struct memio_buffer *mb;
218 int rv;
220 if (flags) {
221 PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
222 return -1;
225 secret = fd->secret;
226 mb = &secret->readbuf;
227 PR_ASSERT(mb->bufsize);
228 rv = memio_buffer_get(mb, buf, len);
229 if (rv == 0 && !secret->eof) {
230 secret->read_requested = len;
231 /* If there is no more data in the buffer, report any pending errors
232 * that were previously observed. Note that both the readbuf and the
233 * writebuf are checked for errors, since the application may have
234 * encountered a socket error while writing that would otherwise not
235 * be reported until the application attempted to write again - which
236 * it may never do.
238 if (mb->last_err)
239 PR_SetError(mb->last_err, 0);
240 else if (secret->writebuf.last_err)
241 PR_SetError(secret->writebuf.last_err, 0);
242 else
243 PR_SetError(PR_WOULD_BLOCK_ERROR, 0);
244 return -1;
247 secret->read_requested = 0;
248 return rv;
251 static int PR_CALLBACK memio_Read(PRFileDesc *fd, void *buf, PRInt32 len)
253 /* pull bytes from buffer */
254 return memio_Recv(fd, buf, len, 0, PR_INTERVAL_NO_TIMEOUT);
257 static int PR_CALLBACK memio_Send(PRFileDesc *fd, const void *buf, PRInt32 len,
258 PRIntn flags, PRIntervalTime timeout)
260 struct PRFilePrivate *secret;
261 struct memio_buffer *mb;
262 int rv;
264 secret = fd->secret;
265 mb = &secret->writebuf;
266 PR_ASSERT(mb->bufsize);
268 /* Note that the read error state is not reported, because it cannot be
269 * reported until all buffered data has been read. If there is an error
270 * with the next layer, attempting to call Send again will report the
271 * error appropriately.
273 if (mb->last_err) {
274 PR_SetError(mb->last_err, 0);
275 return -1;
277 rv = memio_buffer_put(mb, buf, len);
278 if (rv == 0) {
279 PR_SetError(PR_WOULD_BLOCK_ERROR, 0);
280 return -1;
282 return rv;
285 static int PR_CALLBACK memio_Write(PRFileDesc *fd, const void *buf, PRInt32 len)
287 /* append bytes to buffer */
288 return memio_Send(fd, buf, len, 0, PR_INTERVAL_NO_TIMEOUT);
291 static PRStatus PR_CALLBACK memio_GetPeerName(PRFileDesc *fd, PRNetAddr *addr)
293 /* TODO: fail if memio_SetPeerName has not been called */
294 struct PRFilePrivate *secret = fd->secret;
295 *addr = secret->peername;
296 return PR_SUCCESS;
299 static PRStatus memio_GetSocketOption(PRFileDesc *fd, PRSocketOptionData *data)
302 * Even in the original version for real tcp sockets,
303 * PR_SockOpt_Nonblocking is a special case that does not
304 * translate to a getsockopt() call
306 if (PR_SockOpt_Nonblocking == data->option) {
307 data->value.non_blocking = PR_TRUE;
308 return PR_SUCCESS;
310 PR_SetError(PR_OPERATION_NOT_SUPPORTED_ERROR, 0);
311 return PR_FAILURE;
314 /*--------------- private memio data -----------------------*/
317 * Implement just the bare minimum number of methods needed to make ssl happy.
319 * Oddly, PR_Recv calls ssl_Recv calls ssl_SocketIsBlocking calls
320 * PR_GetSocketOption, so we have to provide an implementation of
321 * PR_GetSocketOption that just says "I'm nonblocking".
324 static struct PRIOMethods memio_layer_methods = {
325 PR_DESC_LAYERED,
326 memio_Close,
327 memio_Read,
328 memio_Write,
329 NULL,
330 NULL,
331 NULL,
332 NULL,
333 NULL,
334 NULL,
335 NULL,
336 NULL,
337 NULL,
338 NULL,
339 NULL,
340 NULL,
341 memio_Shutdown,
342 memio_Recv,
343 memio_Send,
344 NULL,
345 NULL,
346 NULL,
347 NULL,
348 NULL,
349 NULL,
350 memio_GetPeerName,
351 NULL,
352 NULL,
353 memio_GetSocketOption,
354 NULL,
355 NULL,
356 NULL,
357 NULL,
358 NULL,
359 NULL,
360 NULL,
363 static PRDescIdentity memio_identity = PR_INVALID_IO_LAYER;
365 static PRStatus memio_InitializeLayerName(void)
367 memio_identity = PR_GetUniqueIdentity("memio");
368 return PR_SUCCESS;
371 /*--------------- public memio functions -----------------------*/
373 PRFileDesc *memio_CreateIOLayer(int readbufsize, int writebufsize)
375 PRFileDesc *fd;
376 struct PRFilePrivate *secret;
377 static PRCallOnceType once;
379 PR_CallOnce(&once, memio_InitializeLayerName);
381 fd = PR_CreateIOLayerStub(memio_identity, &memio_layer_methods);
382 secret = malloc(sizeof(struct PRFilePrivate));
383 memset(secret, 0, sizeof(*secret));
385 memio_buffer_new(&secret->readbuf, readbufsize);
386 memio_buffer_new(&secret->writebuf, writebufsize);
387 fd->secret = secret;
388 return fd;
391 void memio_SetPeerName(PRFileDesc *fd, const PRNetAddr *peername)
393 PRFileDesc *memiofd = PR_GetIdentitiesLayer(fd, memio_identity);
394 struct PRFilePrivate *secret = memiofd->secret;
395 secret->peername = *peername;
398 memio_Private *memio_GetSecret(PRFileDesc *fd)
400 PRFileDesc *memiofd = PR_GetIdentitiesLayer(fd, memio_identity);
401 struct PRFilePrivate *secret = memiofd->secret;
402 return (memio_Private *)secret;
405 int memio_GetReadRequest(memio_Private *secret)
407 return ((PRFilePrivate *)secret)->read_requested;
410 int memio_GetReadParams(memio_Private *secret, char **buf)
412 struct memio_buffer* mb = &((PRFilePrivate *)secret)->readbuf;
413 PR_ASSERT(mb->bufsize);
415 *buf = &mb->buf[mb->tail];
416 return memio_buffer_unused_contiguous(mb);
419 int memio_GetReadableBufferSize(memio_Private *secret)
421 struct memio_buffer* mb = &((PRFilePrivate *)secret)->readbuf;
422 PR_ASSERT(mb->bufsize);
424 return memio_buffer_used_contiguous(mb);
427 void memio_PutReadResult(memio_Private *secret, int bytes_read)
429 struct memio_buffer* mb = &((PRFilePrivate *)secret)->readbuf;
430 PR_ASSERT(mb->bufsize);
432 if (bytes_read > 0) {
433 mb->tail += bytes_read;
434 if (mb->tail == mb->bufsize)
435 mb->tail = 0;
436 } else if (bytes_read == 0) {
437 /* Record EOF condition and report to caller when buffer runs dry */
438 ((PRFilePrivate *)secret)->eof = PR_TRUE;
439 } else /* if (bytes_read < 0) */ {
440 mb->last_err = bytes_read;
444 void memio_GetWriteParams(memio_Private *secret,
445 const char **buf1, unsigned int *len1,
446 const char **buf2, unsigned int *len2)
448 struct memio_buffer* mb = &((PRFilePrivate *)secret)->writebuf;
449 PR_ASSERT(mb->bufsize);
451 *buf1 = &mb->buf[mb->head];
452 *len1 = memio_buffer_used_contiguous(mb);
453 *buf2 = mb->buf;
454 *len2 = memio_buffer_wrapped_bytes(mb);
457 void memio_PutWriteResult(memio_Private *secret, int bytes_written)
459 struct memio_buffer* mb = &((PRFilePrivate *)secret)->writebuf;
460 PR_ASSERT(mb->bufsize);
462 if (bytes_written > 0) {
463 mb->head += bytes_written;
464 if (mb->head >= mb->bufsize)
465 mb->head -= mb->bufsize;
466 } else if (bytes_written < 0) {
467 mb->last_err = bytes_written;
471 /*--------------- private memio_buffer self-test -----------------*/
473 /* Even a trivial unit test is very helpful when doing circular buffers. */
474 /*#define TRIVIAL_SELF_TEST*/
475 #ifdef TRIVIAL_SELF_TEST
476 #include <stdio.h>
478 #define TEST_BUFLEN 7
480 #define CHECKEQ(a, b) { \
481 if ((a) != (b)) { \
482 printf("%d != %d, Test failed line %d\n", a, b, __LINE__); \
483 exit(1); \
487 int main()
489 struct memio_buffer mb;
490 char buf[100];
491 int i;
493 memio_buffer_new(&mb, TEST_BUFLEN);
495 CHECKEQ(memio_buffer_unused_contiguous(&mb), TEST_BUFLEN-1);
496 CHECKEQ(memio_buffer_used_contiguous(&mb), 0);
498 CHECKEQ(memio_buffer_put(&mb, "howdy", 5), 5);
500 CHECKEQ(memio_buffer_unused_contiguous(&mb), TEST_BUFLEN-1-5);
501 CHECKEQ(memio_buffer_used_contiguous(&mb), 5);
502 CHECKEQ(memio_buffer_wrapped_bytes(&mb), 0);
504 CHECKEQ(memio_buffer_put(&mb, "!", 1), 1);
506 CHECKEQ(memio_buffer_unused_contiguous(&mb), 0);
507 CHECKEQ(memio_buffer_used_contiguous(&mb), 6);
508 CHECKEQ(memio_buffer_wrapped_bytes(&mb), 0);
510 CHECKEQ(memio_buffer_get(&mb, buf, 6), 6);
511 CHECKEQ(memcmp(buf, "howdy!", 6), 0);
513 CHECKEQ(memio_buffer_unused_contiguous(&mb), 1);
514 CHECKEQ(memio_buffer_used_contiguous(&mb), 0);
516 CHECKEQ(memio_buffer_put(&mb, "01234", 5), 5);
518 CHECKEQ(memio_buffer_used_contiguous(&mb), 1);
519 CHECKEQ(memio_buffer_wrapped_bytes(&mb), 4);
520 CHECKEQ(memio_buffer_unused_contiguous(&mb), TEST_BUFLEN-1-5);
522 CHECKEQ(memio_buffer_put(&mb, "5", 1), 1);
524 CHECKEQ(memio_buffer_unused_contiguous(&mb), 0);
525 CHECKEQ(memio_buffer_used_contiguous(&mb), 1);
527 /* TODO: add more cases */
529 printf("Test passed\n");
530 exit(0);
533 #endif