15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2008 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Written in NSPR style to also be suitable for adding to the NSS demo suite
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* memio is a simple NSPR I/O layer that lets you decouple NSS from
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * the real network.  It's rather like openssl's memory bio,
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * and is useful when your app absolutely, positively doesn't
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * want to let NSS do its own networking.
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <stdlib.h>
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <string.h>
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <prerror.h>
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <prinit.h>
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <prlog.h>
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "nss_memio.h"
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*--------------- private memio types -----------------------*/
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*----------------------------------------------------------------------
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Simple private circular buffer class.  Size cannot be changed once allocated.
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)----------------------------------------------------------------------*/
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)struct memio_buffer {
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int head;     /* where to take next byte out of buf */
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int tail;     /* where to put next byte into buf */
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int bufsize;  /* number of bytes allocated to buf */
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /* TODO(port): error handling is pessimistic right now.
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * Once an error is set, the socket is considered broken
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * (PR_WOULD_BLOCK_ERROR not included).
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     */
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    PRErrorCode last_err;
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    char *buf;
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* The 'secret' field of a PRFileDesc created by memio_CreateIOLayer points
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * to one of these.
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * In the public header, we use struct memio_Private as a typesafe alias
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * for this.  This causes a few ugly typecasts in the private file, but
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * seems safer.
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)struct PRFilePrivate {
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /* read requests are satisfied from this buffer */
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    struct memio_buffer readbuf;
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /* write requests are satisfied from this buffer */
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    struct memio_buffer writebuf;
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /* SSL needs to know socket peer's name */
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    PRNetAddr peername;
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /* if set, empty I/O returns EOF instead of EWOULDBLOCK */
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int eof;
582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    /* if set, the number of bytes requested from readbuf that were not
602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)     * fulfilled (due to readbuf being empty) */
612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    int read_requested;
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*--------------- private memio_buffer functions ---------------------*/
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* Forward declarations.  */
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* Allocate a memio_buffer of given size. */
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void memio_buffer_new(struct memio_buffer *mb, int size);
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* Deallocate a memio_buffer allocated by memio_buffer_new. */
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void memio_buffer_destroy(struct memio_buffer *mb);
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* How many bytes can be read out of the buffer without wrapping */
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int memio_buffer_used_contiguous(const struct memio_buffer *mb);
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* How many bytes exist after the wrap? */
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int memio_buffer_wrapped_bytes(const struct memio_buffer *mb);
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* How many bytes can be written into the buffer without wrapping */
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int memio_buffer_unused_contiguous(const struct memio_buffer *mb);
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* Write n bytes into the buffer.  Returns number of bytes written. */
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int memio_buffer_put(struct memio_buffer *mb, const char *buf, int n);
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* Read n bytes from the buffer.  Returns number of bytes read. */
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int memio_buffer_get(struct memio_buffer *mb, char *buf, int n);
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* Allocate a memio_buffer of given size. */
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void memio_buffer_new(struct memio_buffer *mb, int size)
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    mb->head = 0;
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    mb->tail = 0;
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    mb->bufsize = size;
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    mb->buf = malloc(size);
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* Deallocate a memio_buffer allocated by memio_buffer_new. */
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void memio_buffer_destroy(struct memio_buffer *mb)
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    free(mb->buf);
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    mb->buf = NULL;
103a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    mb->bufsize = 0;
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    mb->head = 0;
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    mb->tail = 0;
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* How many bytes can be read out of the buffer without wrapping */
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int memio_buffer_used_contiguous(const struct memio_buffer *mb)
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return (((mb->tail >= mb->head) ? mb->tail : mb->bufsize) - mb->head);
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* How many bytes exist after the wrap? */
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int memio_buffer_wrapped_bytes(const struct memio_buffer *mb)
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return (mb->tail >= mb->head) ? 0 : mb->tail;
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* How many bytes can be written into the buffer without wrapping */
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int memio_buffer_unused_contiguous(const struct memio_buffer *mb)
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (mb->head > mb->tail) return mb->head - mb->tail - 1;
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return mb->bufsize - mb->tail - (mb->head == 0);
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* Write n bytes into the buffer.  Returns number of bytes written. */
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int memio_buffer_put(struct memio_buffer *mb, const char *buf, int n)
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int len;
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int transferred = 0;
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /* Handle part before wrap */
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    len = PR_MIN(n, memio_buffer_unused_contiguous(mb));
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (len > 0) {
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        /* Buffer not full */
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        memcpy(&mb->buf[mb->tail], buf, len);
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        mb->tail += len;
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (mb->tail == mb->bufsize)
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            mb->tail = 0;
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        n -= len;
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        buf += len;
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        transferred += len;
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        /* Handle part after wrap */
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        len = PR_MIN(n, memio_buffer_unused_contiguous(mb));
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (len > 0) {
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            /* Output buffer still not full, input buffer still not empty */
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            memcpy(&mb->buf[mb->tail], buf, len);
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            mb->tail += len;
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            if (mb->tail == mb->bufsize)
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                mb->tail = 0;
153c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch            transferred += len;
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return transferred;
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* Read n bytes from the buffer.  Returns number of bytes read. */
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int memio_buffer_get(struct memio_buffer *mb, char *buf, int n)
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int len;
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int transferred = 0;
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /* Handle part before wrap */
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    len = PR_MIN(n, memio_buffer_used_contiguous(mb));
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (len) {
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        memcpy(buf, &mb->buf[mb->head], len);
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        mb->head += len;
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (mb->head == mb->bufsize)
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            mb->head = 0;
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        n -= len;
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        buf += len;
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        transferred += len;
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        /* Handle part after wrap */
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        len = PR_MIN(n, memio_buffer_used_contiguous(mb));
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (len) {
181c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch            memcpy(buf, &mb->buf[mb->head], len);
182c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch            mb->head += len;
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            if (mb->head == mb->bufsize)
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                mb->head = 0;
185c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch            transferred += len;
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return transferred;
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*--------------- private memio functions -----------------------*/
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static PRStatus PR_CALLBACK memio_Close(PRFileDesc *fd)
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    struct PRFilePrivate *secret = fd->secret;
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    memio_buffer_destroy(&secret->readbuf);
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    memio_buffer_destroy(&secret->writebuf);
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    free(secret);
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    fd->dtor(fd);
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return PR_SUCCESS;
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static PRStatus PR_CALLBACK memio_Shutdown(PRFileDesc *fd, PRIntn how)
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /* TODO: pass shutdown status to app somehow */
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return PR_SUCCESS;
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* If there was a network error in the past taking bytes
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * out of the buffer, return it to the next call that
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * tries to read from an empty buffer.
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int PR_CALLBACK memio_Recv(PRFileDesc *fd, void *buf, PRInt32 len,
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                  PRIntn flags, PRIntervalTime timeout)
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    struct PRFilePrivate *secret;
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    struct memio_buffer *mb;
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int rv;
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (flags) {
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return -1;
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    secret = fd->secret;
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    mb = &secret->readbuf;
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    PR_ASSERT(mb->bufsize);
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    rv = memio_buffer_get(mb, buf, len);
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (rv == 0 && !secret->eof) {
2312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        secret->read_requested = len;
2327d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)        /* If there is no more data in the buffer, report any pending errors
2337d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)         * that were previously observed. Note that both the readbuf and the
2347d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)         * writebuf are checked for errors, since the application may have
2357d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)         * encountered a socket error while writing that would otherwise not
2367d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)         * be reported until the application attempted to write again - which
2377d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)         * it may never do.
2387d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)         */
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (mb->last_err)
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            PR_SetError(mb->last_err, 0);
2417d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)        else if (secret->writebuf.last_err)
2427d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)            PR_SetError(secret->writebuf.last_err, 0);
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        else
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            PR_SetError(PR_WOULD_BLOCK_ERROR, 0);
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return -1;
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    secret->read_requested = 0;
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return rv;
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int PR_CALLBACK memio_Read(PRFileDesc *fd, void *buf, PRInt32 len)
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /* pull bytes from buffer */
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return memio_Recv(fd, buf, len, 0, PR_INTERVAL_NO_TIMEOUT);
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int PR_CALLBACK memio_Send(PRFileDesc *fd, const void *buf, PRInt32 len,
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                  PRIntn flags, PRIntervalTime timeout)
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    struct PRFilePrivate *secret;
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    struct memio_buffer *mb;
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int rv;
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    secret = fd->secret;
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    mb = &secret->writebuf;
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    PR_ASSERT(mb->bufsize);
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2697d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    /* Note that the read error state is not reported, because it cannot be
2707d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)     * reported until all buffered data has been read. If there is an error
2717d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)     * with the next layer, attempting to call Send again will report the
2727d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)     * error appropriately.
2737d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)     */
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (mb->last_err) {
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        PR_SetError(mb->last_err, 0);
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return -1;
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    rv = memio_buffer_put(mb, buf, len);
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (rv == 0) {
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        PR_SetError(PR_WOULD_BLOCK_ERROR, 0);
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return -1;
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return rv;
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int PR_CALLBACK memio_Write(PRFileDesc *fd, const void *buf, PRInt32 len)
2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /* append bytes to buffer */
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return memio_Send(fd, buf, len, 0, PR_INTERVAL_NO_TIMEOUT);
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static PRStatus PR_CALLBACK memio_GetPeerName(PRFileDesc *fd, PRNetAddr *addr)
2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /* TODO: fail if memio_SetPeerName has not been called */
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    struct PRFilePrivate *secret = fd->secret;
2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    *addr = secret->peername;
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return PR_SUCCESS;
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static PRStatus memio_GetSocketOption(PRFileDesc *fd, PRSocketOptionData *data)
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /*
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * Even in the original version for real tcp sockets,
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * PR_SockOpt_Nonblocking is a special case that does not
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * translate to a getsockopt() call
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     */
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (PR_SockOpt_Nonblocking == data->option) {
3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        data->value.non_blocking = PR_TRUE;
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return PR_SUCCESS;
3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    PR_SetError(PR_OPERATION_NOT_SUPPORTED_ERROR, 0);
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return PR_FAILURE;
3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*--------------- private memio data -----------------------*/
3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Implement just the bare minimum number of methods needed to make ssl happy.
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *
3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Oddly, PR_Recv calls ssl_Recv calls ssl_SocketIsBlocking calls
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * PR_GetSocketOption, so we have to provide an implementation of
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * PR_GetSocketOption that just says "I'm nonblocking".
3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static struct PRIOMethods  memio_layer_methods = {
3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    PR_DESC_LAYERED,
3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    memio_Close,
3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    memio_Read,
3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    memio_Write,
3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NULL,
3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NULL,
3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NULL,
3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NULL,
3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NULL,
3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NULL,
3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NULL,
3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NULL,
3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NULL,
3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NULL,
3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NULL,
3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NULL,
3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    memio_Shutdown,
3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    memio_Recv,
3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    memio_Send,
3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NULL,
3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NULL,
3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NULL,
3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NULL,
3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NULL,
3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NULL,
3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    memio_GetPeerName,
3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NULL,
3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NULL,
3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    memio_GetSocketOption,
3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NULL,
3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NULL,
3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NULL,
3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NULL,
3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NULL,
3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NULL,
3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NULL,
3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static PRDescIdentity memio_identity = PR_INVALID_IO_LAYER;
3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static PRStatus memio_InitializeLayerName(void)
3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){
3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    memio_identity = PR_GetUniqueIdentity("memio");
3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return PR_SUCCESS;
3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*--------------- public memio functions -----------------------*/
3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)PRFileDesc *memio_CreateIOLayer(int readbufsize, int writebufsize)
3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){
3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    PRFileDesc *fd;
3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    struct PRFilePrivate *secret;
3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    static PRCallOnceType once;
3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    PR_CallOnce(&once, memio_InitializeLayerName);
3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    fd = PR_CreateIOLayerStub(memio_identity, &memio_layer_methods);
3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    secret = malloc(sizeof(struct PRFilePrivate));
3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    memset(secret, 0, sizeof(*secret));
3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    memio_buffer_new(&secret->readbuf, readbufsize);
3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    memio_buffer_new(&secret->writebuf, writebufsize);
3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    fd->secret = secret;
3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return fd;
3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void memio_SetPeerName(PRFileDesc *fd, const PRNetAddr *peername)
3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){
3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    PRFileDesc *memiofd = PR_GetIdentitiesLayer(fd, memio_identity);
3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    struct PRFilePrivate *secret = memiofd->secret;
3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    secret->peername = *peername;
3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)memio_Private *memio_GetSecret(PRFileDesc *fd)
4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){
4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    PRFileDesc *memiofd = PR_GetIdentitiesLayer(fd, memio_identity);
4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    struct PRFilePrivate *secret =  memiofd->secret;
4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return (memio_Private *)secret;
4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)int memio_GetReadRequest(memio_Private *secret)
4072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles){
4082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return ((PRFilePrivate *)secret)->read_requested;
4092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
4102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int memio_GetReadParams(memio_Private *secret, char **buf)
4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){
4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    struct memio_buffer* mb = &((PRFilePrivate *)secret)->readbuf;
4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    PR_ASSERT(mb->bufsize);
4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    *buf = &mb->buf[mb->tail];
4175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return memio_buffer_unused_contiguous(mb);
4185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)int memio_GetReadableBufferSize(memio_Private *secret)
4212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles){
4222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    struct memio_buffer* mb = &((PRFilePrivate *)secret)->readbuf;
4232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    PR_ASSERT(mb->bufsize);
4242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return memio_buffer_used_contiguous(mb);
4262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
4272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void memio_PutReadResult(memio_Private *secret, int bytes_read)
4295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){
4305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    struct memio_buffer* mb = &((PRFilePrivate *)secret)->readbuf;
4315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    PR_ASSERT(mb->bufsize);
4325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (bytes_read > 0) {
4345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        mb->tail += bytes_read;
4355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (mb->tail == mb->bufsize)
4365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            mb->tail = 0;
4375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else if (bytes_read == 0) {
4385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        /* Record EOF condition and report to caller when buffer runs dry */
4395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        ((PRFilePrivate *)secret)->eof = PR_TRUE;
4405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else /* if (bytes_read < 0) */ {
4415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        mb->last_err = bytes_read;
4425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
4435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
445f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)int memio_GetWriteParams(memio_Private *secret,
446f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                         const char **buf1, unsigned int *len1,
447f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                         const char **buf2, unsigned int *len2)
4485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){
4495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    struct memio_buffer* mb = &((PRFilePrivate *)secret)->writebuf;
4505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    PR_ASSERT(mb->bufsize);
4515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
452f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    if (mb->last_err)
453f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        return mb->last_err;
454f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
4555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    *buf1 = &mb->buf[mb->head];
4565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    *len1 = memio_buffer_used_contiguous(mb);
4575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    *buf2 = mb->buf;
4585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    *len2 = memio_buffer_wrapped_bytes(mb);
459f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    return 0;
4605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void memio_PutWriteResult(memio_Private *secret, int bytes_written)
4635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){
4645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    struct memio_buffer* mb = &((PRFilePrivate *)secret)->writebuf;
4655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    PR_ASSERT(mb->bufsize);
4665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (bytes_written > 0) {
4685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        mb->head += bytes_written;
4695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (mb->head >= mb->bufsize)
4705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            mb->head -= mb->bufsize;
4715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else if (bytes_written < 0) {
4725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        mb->last_err = bytes_written;
4735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
4745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*--------------- private memio_buffer self-test -----------------*/
4775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* Even a trivial unit test is very helpful when doing circular buffers. */
4795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*#define TRIVIAL_SELF_TEST*/
4805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifdef TRIVIAL_SELF_TEST
4815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <stdio.h>
4825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define TEST_BUFLEN 7
4845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define CHECKEQ(a, b) { \
4865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if ((a) != (b)) { \
4875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        printf("%d != %d, Test failed line %d\n", a, b, __LINE__); \
4885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        exit(1); \
4895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } \
4905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int main()
4935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){
4945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    struct memio_buffer mb;
4955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    char buf[100];
4965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int i;
4975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    memio_buffer_new(&mb, TEST_BUFLEN);
4995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    CHECKEQ(memio_buffer_unused_contiguous(&mb), TEST_BUFLEN-1);
5015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    CHECKEQ(memio_buffer_used_contiguous(&mb), 0);
5025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    CHECKEQ(memio_buffer_put(&mb, "howdy", 5), 5);
5045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    CHECKEQ(memio_buffer_unused_contiguous(&mb), TEST_BUFLEN-1-5);
5065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    CHECKEQ(memio_buffer_used_contiguous(&mb), 5);
5075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    CHECKEQ(memio_buffer_wrapped_bytes(&mb), 0);
5085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    CHECKEQ(memio_buffer_put(&mb, "!", 1), 1);
5105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    CHECKEQ(memio_buffer_unused_contiguous(&mb), 0);
5125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    CHECKEQ(memio_buffer_used_contiguous(&mb), 6);
5135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    CHECKEQ(memio_buffer_wrapped_bytes(&mb), 0);
5145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    CHECKEQ(memio_buffer_get(&mb, buf, 6), 6);
5165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    CHECKEQ(memcmp(buf, "howdy!", 6), 0);
5175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    CHECKEQ(memio_buffer_unused_contiguous(&mb), 1);
5195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    CHECKEQ(memio_buffer_used_contiguous(&mb), 0);
5205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    CHECKEQ(memio_buffer_put(&mb, "01234", 5), 5);
5225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    CHECKEQ(memio_buffer_used_contiguous(&mb), 1);
5245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    CHECKEQ(memio_buffer_wrapped_bytes(&mb), 4);
5255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    CHECKEQ(memio_buffer_unused_contiguous(&mb), TEST_BUFLEN-1-5);
5265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    CHECKEQ(memio_buffer_put(&mb, "5", 1), 1);
5285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    CHECKEQ(memio_buffer_unused_contiguous(&mb), 0);
5305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    CHECKEQ(memio_buffer_used_contiguous(&mb), 1);
5315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /* TODO: add more cases */
5335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    printf("Test passed\n");
5355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    exit(0);
5365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
539