1c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// Copyright (c) 2008 The Chromium Authors. All rights reserved.
2c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// Use of this source code is governed by a BSD-style license that can be
3c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// found in the LICENSE file.
4c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// Written in NSPR style to also be suitable for adding to the NSS demo suite
5c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
6c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott/* memio is a simple NSPR I/O layer that lets you decouple NSS from
7c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott * the real network.  It's rather like openssl's memory bio,
8c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott * and is useful when your app absolutely, positively doesn't
9c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott * want to let NSS do its own networking.
10c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott */
11c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
12c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include <stdlib.h>
13c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include <string.h>
14c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
15c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include <prerror.h>
16c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include <prinit.h>
17c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include <prlog.h>
18c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
19c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "nss_memio.h"
20c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
21c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott/*--------------- private memio types -----------------------*/
22c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
23c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott/*----------------------------------------------------------------------
24c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott Simple private circular buffer class.  Size cannot be changed once allocated.
25c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott----------------------------------------------------------------------*/
26c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
27c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottstruct memio_buffer {
28c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    int head;     /* where to take next byte out of buf */
29c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    int tail;     /* where to put next byte into buf */
30c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    int bufsize;  /* number of bytes allocated to buf */
31c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    /* TODO(port): error handling is pessimistic right now.
32c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott     * Once an error is set, the socket is considered broken
33c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott     * (PR_WOULD_BLOCK_ERROR not included).
34c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott     */
35c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    PRErrorCode last_err;
36c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    char *buf;
37c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott};
38c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
39c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
40c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott/* The 'secret' field of a PRFileDesc created by memio_CreateIOLayer points
41c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott * to one of these.
42c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott * In the public header, we use struct memio_Private as a typesafe alias
43c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott * for this.  This causes a few ugly typecasts in the private file, but
44c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott * seems safer.
45c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott */
46c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottstruct PRFilePrivate {
47c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    /* read requests are satisfied from this buffer */
48c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    struct memio_buffer readbuf;
49c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
50c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    /* write requests are satisfied from this buffer */
51c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    struct memio_buffer writebuf;
52c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
53c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    /* SSL needs to know socket peer's name */
54c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    PRNetAddr peername;
55c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
56c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    /* if set, empty I/O returns EOF instead of EWOULDBLOCK */
57c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    int eof;
58c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott};
59c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
60c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott/*--------------- private memio_buffer functions ---------------------*/
61c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
62c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott/* Forward declarations.  */
63c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
64c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott/* Allocate a memio_buffer of given size. */
65c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottstatic void memio_buffer_new(struct memio_buffer *mb, int size);
66c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
67c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott/* Deallocate a memio_buffer allocated by memio_buffer_new. */
68c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottstatic void memio_buffer_destroy(struct memio_buffer *mb);
69c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
70c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott/* How many bytes can be read out of the buffer without wrapping */
71c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottstatic int memio_buffer_used_contiguous(const struct memio_buffer *mb);
72c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
733345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick/* How many bytes exist after the wrap? */
743345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickstatic int memio_buffer_wrapped_bytes(const struct memio_buffer *mb);
753345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
76c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott/* How many bytes can be written into the buffer without wrapping */
77c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottstatic int memio_buffer_unused_contiguous(const struct memio_buffer *mb);
78c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
79c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott/* Write n bytes into the buffer.  Returns number of bytes written. */
80c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottstatic int memio_buffer_put(struct memio_buffer *mb, const char *buf, int n);
81c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
82c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott/* Read n bytes from the buffer.  Returns number of bytes read. */
83c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottstatic int memio_buffer_get(struct memio_buffer *mb, char *buf, int n);
84c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
85c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott/* Allocate a memio_buffer of given size. */
86c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottstatic void memio_buffer_new(struct memio_buffer *mb, int size)
87c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott{
88c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    mb->head = 0;
89c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    mb->tail = 0;
90c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    mb->bufsize = size;
91c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    mb->buf = malloc(size);
92c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
93c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
94c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott/* Deallocate a memio_buffer allocated by memio_buffer_new. */
95c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottstatic void memio_buffer_destroy(struct memio_buffer *mb)
96c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott{
97c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    free(mb->buf);
98c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    mb->buf = NULL;
99c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    mb->head = 0;
100c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    mb->tail = 0;
101c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
102c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
103c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott/* How many bytes can be read out of the buffer without wrapping */
104c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottstatic int memio_buffer_used_contiguous(const struct memio_buffer *mb)
105c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott{
106c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    return (((mb->tail >= mb->head) ? mb->tail : mb->bufsize) - mb->head);
107c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
108c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
1093345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick/* How many bytes exist after the wrap? */
1103345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickstatic int memio_buffer_wrapped_bytes(const struct memio_buffer *mb)
1113345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick{
1123345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    return (mb->tail >= mb->head) ? 0 : mb->tail;
1133345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
1143345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
115c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott/* How many bytes can be written into the buffer without wrapping */
116c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottstatic int memio_buffer_unused_contiguous(const struct memio_buffer *mb)
117c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott{
118c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    if (mb->head > mb->tail) return mb->head - mb->tail - 1;
119c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    return mb->bufsize - mb->tail - (mb->head == 0);
120c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
121c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
122c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott/* Write n bytes into the buffer.  Returns number of bytes written. */
123c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottstatic int memio_buffer_put(struct memio_buffer *mb, const char *buf, int n)
124c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott{
125c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    int len;
126c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    int transferred = 0;
127c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
128c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    /* Handle part before wrap */
129c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    len = PR_MIN(n, memio_buffer_unused_contiguous(mb));
130c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    if (len > 0) {
131c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        /* Buffer not full */
132c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        memcpy(&mb->buf[mb->tail], buf, len);
133c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        mb->tail += len;
134c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        if (mb->tail == mb->bufsize)
135c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott            mb->tail = 0;
136c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        n -= len;
137c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        buf += len;
138c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        transferred += len;
139c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
140c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        /* Handle part after wrap */
141c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        len = PR_MIN(n, memio_buffer_unused_contiguous(mb));
142c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        if (len > 0) {
143c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott            /* Output buffer still not full, input buffer still not empty */
144c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott            memcpy(&mb->buf[mb->tail], buf, len);
145c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott            mb->tail += len;
146c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott            if (mb->tail == mb->bufsize)
147c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                mb->tail = 0;
148c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                transferred += len;
149c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        }
150c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    }
151c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
152c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    return transferred;
153c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
154c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
155c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
156c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott/* Read n bytes from the buffer.  Returns number of bytes read. */
157c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottstatic int memio_buffer_get(struct memio_buffer *mb, char *buf, int n)
158c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott{
159c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    int len;
160c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    int transferred = 0;
161c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
162c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    /* Handle part before wrap */
163c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    len = PR_MIN(n, memio_buffer_used_contiguous(mb));
164c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    if (len) {
165c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        memcpy(buf, &mb->buf[mb->head], len);
166c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        mb->head += len;
167c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        if (mb->head == mb->bufsize)
168c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott            mb->head = 0;
169c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        n -= len;
170c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        buf += len;
171c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        transferred += len;
172c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
173c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        /* Handle part after wrap */
174c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        len = PR_MIN(n, memio_buffer_used_contiguous(mb));
175c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        if (len) {
176c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        memcpy(buf, &mb->buf[mb->head], len);
177c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        mb->head += len;
178c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott            if (mb->head == mb->bufsize)
179c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                mb->head = 0;
180c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                transferred += len;
181c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        }
182c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    }
183c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
184c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    return transferred;
185c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
186c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
187c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott/*--------------- private memio functions -----------------------*/
188c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
189c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottstatic PRStatus PR_CALLBACK memio_Close(PRFileDesc *fd)
190c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott{
191c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    struct PRFilePrivate *secret = fd->secret;
192c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    memio_buffer_destroy(&secret->readbuf);
193c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    memio_buffer_destroy(&secret->writebuf);
194c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    free(secret);
195c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    fd->dtor(fd);
196c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    return PR_SUCCESS;
197c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
198c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
199c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottstatic PRStatus PR_CALLBACK memio_Shutdown(PRFileDesc *fd, PRIntn how)
200c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott{
201c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    /* TODO: pass shutdown status to app somehow */
202c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    return PR_SUCCESS;
203c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
204c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
205c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott/* If there was a network error in the past taking bytes
206c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott * out of the buffer, return it to the next call that
207c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott * tries to read from an empty buffer.
208c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott */
209c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottstatic int PR_CALLBACK memio_Recv(PRFileDesc *fd, void *buf, PRInt32 len,
210c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                                  PRIntn flags, PRIntervalTime timeout)
211c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott{
212c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    struct PRFilePrivate *secret;
213c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    struct memio_buffer *mb;
214c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    int rv;
215c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
216c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    if (flags) {
217c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
218c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        return -1;
219c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    }
220c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
221c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    secret = fd->secret;
222c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    mb = &secret->readbuf;
223c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    PR_ASSERT(mb->bufsize);
224c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    rv = memio_buffer_get(mb, buf, len);
225c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    if (rv == 0 && !secret->eof) {
226c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        if (mb->last_err)
227c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott            PR_SetError(mb->last_err, 0);
228c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        else
229c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott            PR_SetError(PR_WOULD_BLOCK_ERROR, 0);
230c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        return -1;
231c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    }
232c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
233c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    return rv;
234c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
235c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
236c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottstatic int PR_CALLBACK memio_Read(PRFileDesc *fd, void *buf, PRInt32 len)
237c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott{
238c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    /* pull bytes from buffer */
239c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    return memio_Recv(fd, buf, len, 0, PR_INTERVAL_NO_TIMEOUT);
240c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
241c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
242c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottstatic int PR_CALLBACK memio_Send(PRFileDesc *fd, const void *buf, PRInt32 len,
243c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                                  PRIntn flags, PRIntervalTime timeout)
244c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott{
245c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    struct PRFilePrivate *secret;
246c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    struct memio_buffer *mb;
247c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    int rv;
248c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
249c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    secret = fd->secret;
250c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    mb = &secret->writebuf;
251c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    PR_ASSERT(mb->bufsize);
252c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
253c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    if (mb->last_err) {
254c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        PR_SetError(mb->last_err, 0);
255c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        return -1;
256c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    }
257c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    rv = memio_buffer_put(mb, buf, len);
258c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    if (rv == 0) {
259c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        PR_SetError(PR_WOULD_BLOCK_ERROR, 0);
260c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        return -1;
261c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    }
262c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    return rv;
263c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
264c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
265c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottstatic int PR_CALLBACK memio_Write(PRFileDesc *fd, const void *buf, PRInt32 len)
266c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott{
267c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    /* append bytes to buffer */
268c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    return memio_Send(fd, buf, len, 0, PR_INTERVAL_NO_TIMEOUT);
269c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
270c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
271c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottstatic PRStatus PR_CALLBACK memio_GetPeerName(PRFileDesc *fd, PRNetAddr *addr)
272c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott{
273c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    /* TODO: fail if memio_SetPeerName has not been called */
274c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    struct PRFilePrivate *secret = fd->secret;
275c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    *addr = secret->peername;
276c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    return PR_SUCCESS;
277c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
278c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
279c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottstatic PRStatus memio_GetSocketOption(PRFileDesc *fd, PRSocketOptionData *data)
280c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott{
281c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    /*
282c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott     * Even in the original version for real tcp sockets,
283c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott     * PR_SockOpt_Nonblocking is a special case that does not
284c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott     * translate to a getsockopt() call
285c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott     */
286c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    if (PR_SockOpt_Nonblocking == data->option) {
287c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        data->value.non_blocking = PR_TRUE;
288c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        return PR_SUCCESS;
289c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    }
290c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    PR_SetError(PR_OPERATION_NOT_SUPPORTED_ERROR, 0);
291c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    return PR_FAILURE;
292c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
293c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
294c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott/*--------------- private memio data -----------------------*/
295c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
296c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott/*
297c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott * Implement just the bare minimum number of methods needed to make ssl happy.
298c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott *
299c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott * Oddly, PR_Recv calls ssl_Recv calls ssl_SocketIsBlocking calls
300c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott * PR_GetSocketOption, so we have to provide an implementation of
301c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott * PR_GetSocketOption that just says "I'm nonblocking".
302c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott */
303c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
304c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottstatic struct PRIOMethods  memio_layer_methods = {
305c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    PR_DESC_LAYERED,
306c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    memio_Close,
307c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    memio_Read,
308c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    memio_Write,
309c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    NULL,
310c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    NULL,
311c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    NULL,
312c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    NULL,
313c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    NULL,
314c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    NULL,
315c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    NULL,
316c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    NULL,
317c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    NULL,
318c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    NULL,
319c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    NULL,
320c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    NULL,
321c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    memio_Shutdown,
322c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    memio_Recv,
323c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    memio_Send,
324c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    NULL,
325c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    NULL,
326c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    NULL,
327c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    NULL,
328c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    NULL,
329c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    NULL,
330c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    memio_GetPeerName,
331c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    NULL,
332c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    NULL,
333c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    memio_GetSocketOption,
334c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    NULL,
335c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    NULL,
336c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    NULL,
337c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    NULL,
338c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    NULL,
339c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    NULL,
340c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    NULL,
341c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott};
342c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
343c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottstatic PRDescIdentity memio_identity = PR_INVALID_IO_LAYER;
344c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
345c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottstatic PRStatus memio_InitializeLayerName(void)
346c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott{
347c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    memio_identity = PR_GetUniqueIdentity("memio");
348c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    return PR_SUCCESS;
349c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
350c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
351c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott/*--------------- public memio functions -----------------------*/
352c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
353c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick ScottPRFileDesc *memio_CreateIOLayer(int bufsize)
354c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott{
355c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    PRFileDesc *fd;
356c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    struct PRFilePrivate *secret;
357c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    static PRCallOnceType once;
358c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
359c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    PR_CallOnce(&once, memio_InitializeLayerName);
360c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
361c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    fd = PR_CreateIOLayerStub(memio_identity, &memio_layer_methods);
362c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    secret = malloc(sizeof(struct PRFilePrivate));
363c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    memset(secret, 0, sizeof(*secret));
364c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
365c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    memio_buffer_new(&secret->readbuf, bufsize);
366c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    memio_buffer_new(&secret->writebuf, bufsize);
367c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    fd->secret = secret;
368c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    return fd;
369c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
370c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
371c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottvoid memio_SetPeerName(PRFileDesc *fd, const PRNetAddr *peername)
372c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott{
373c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    PRFileDesc *memiofd = PR_GetIdentitiesLayer(fd, memio_identity);
374c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    struct PRFilePrivate *secret = memiofd->secret;
375c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    secret->peername = *peername;
376c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
377c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
378c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottmemio_Private *memio_GetSecret(PRFileDesc *fd)
379c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott{
380c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    PRFileDesc *memiofd = PR_GetIdentitiesLayer(fd, memio_identity);
381c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    struct PRFilePrivate *secret =  memiofd->secret;
382c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    return (memio_Private *)secret;
383c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
384c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
385c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottint memio_GetReadParams(memio_Private *secret, char **buf)
386c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott{
387c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    struct memio_buffer* mb = &((PRFilePrivate *)secret)->readbuf;
388c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    PR_ASSERT(mb->bufsize);
389c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
390c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    *buf = &mb->buf[mb->tail];
391c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    return memio_buffer_unused_contiguous(mb);
392c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
393c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
394c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottvoid memio_PutReadResult(memio_Private *secret, int bytes_read)
395c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott{
396c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    struct memio_buffer* mb = &((PRFilePrivate *)secret)->readbuf;
397c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    PR_ASSERT(mb->bufsize);
398c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
399c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    if (bytes_read > 0) {
400c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        mb->tail += bytes_read;
401c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        if (mb->tail == mb->bufsize)
402c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott            mb->tail = 0;
403c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    } else if (bytes_read == 0) {
404c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        /* Record EOF condition and report to caller when buffer runs dry */
405c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        ((PRFilePrivate *)secret)->eof = PR_TRUE;
406c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    } else /* if (bytes_read < 0) */ {
407c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        mb->last_err = bytes_read;
408c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    }
409c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
410c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
4113345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickvoid memio_GetWriteParams(memio_Private *secret,
4123345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                          const char **buf1, unsigned int *len1,
4133345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                          const char **buf2, unsigned int *len2)
414c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott{
415c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    struct memio_buffer* mb = &((PRFilePrivate *)secret)->writebuf;
416c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    PR_ASSERT(mb->bufsize);
417c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
4183345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    *buf1 = &mb->buf[mb->head];
4193345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    *len1 = memio_buffer_used_contiguous(mb);
4203345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    *buf2 = mb->buf;
4213345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    *len2 = memio_buffer_wrapped_bytes(mb);
422c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
423c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
424c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottvoid memio_PutWriteResult(memio_Private *secret, int bytes_written)
425c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott{
426c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    struct memio_buffer* mb = &((PRFilePrivate *)secret)->writebuf;
427c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    PR_ASSERT(mb->bufsize);
428c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
429c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    if (bytes_written > 0) {
430c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        mb->head += bytes_written;
4313345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick        if (mb->head >= mb->bufsize)
4323345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick            mb->head -= mb->bufsize;
433c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    } else if (bytes_written < 0) {
434c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        mb->last_err = bytes_written;
435c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    }
436c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
437c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
438c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott/*--------------- private memio_buffer self-test -----------------*/
439c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
440c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott/* Even a trivial unit test is very helpful when doing circular buffers. */
441c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott/*#define TRIVIAL_SELF_TEST*/
442c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#ifdef TRIVIAL_SELF_TEST
443c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include <stdio.h>
444c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
445c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#define TEST_BUFLEN 7
446c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
447c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#define CHECKEQ(a, b) { \
448c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    if ((a) != (b)) { \
449c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        printf("%d != %d, Test failed line %d\n", a, b, __LINE__); \
450c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        exit(1); \
451c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    } \
452c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
453c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
454c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottint main()
455c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott{
456c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    struct memio_buffer mb;
457c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    char buf[100];
458c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    int i;
459c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
460c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    memio_buffer_new(&mb, TEST_BUFLEN);
461c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
462c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    CHECKEQ(memio_buffer_unused_contiguous(&mb), TEST_BUFLEN-1);
463c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    CHECKEQ(memio_buffer_used_contiguous(&mb), 0);
464c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
465c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    CHECKEQ(memio_buffer_put(&mb, "howdy", 5), 5);
466c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
467c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    CHECKEQ(memio_buffer_unused_contiguous(&mb), TEST_BUFLEN-1-5);
468c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    CHECKEQ(memio_buffer_used_contiguous(&mb), 5);
4693345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    CHECKEQ(memio_buffer_wrapped_bytes(&mb), 0);
470c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
471c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    CHECKEQ(memio_buffer_put(&mb, "!", 1), 1);
472c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
473c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    CHECKEQ(memio_buffer_unused_contiguous(&mb), 0);
474c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    CHECKEQ(memio_buffer_used_contiguous(&mb), 6);
4753345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    CHECKEQ(memio_buffer_wrapped_bytes(&mb), 0);
476c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
477c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    CHECKEQ(memio_buffer_get(&mb, buf, 6), 6);
478c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    CHECKEQ(memcmp(buf, "howdy!", 6), 0);
479c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
480c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    CHECKEQ(memio_buffer_unused_contiguous(&mb), 1);
481c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    CHECKEQ(memio_buffer_used_contiguous(&mb), 0);
482c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
483c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    CHECKEQ(memio_buffer_put(&mb, "01234", 5), 5);
484c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
485c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    CHECKEQ(memio_buffer_used_contiguous(&mb), 1);
4863345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    CHECKEQ(memio_buffer_wrapped_bytes(&mb), 4);
487c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    CHECKEQ(memio_buffer_unused_contiguous(&mb), TEST_BUFLEN-1-5);
488c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
489c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    CHECKEQ(memio_buffer_put(&mb, "5", 1), 1);
490c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
491c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    CHECKEQ(memio_buffer_unused_contiguous(&mb), 0);
492c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    CHECKEQ(memio_buffer_used_contiguous(&mb), 1);
493c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
494c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    /* TODO: add more cases */
495c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
496c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    printf("Test passed\n");
497c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    exit(0);
498c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
499c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
500c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#endif
501