Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/ambrop72/badvpn.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorambrop7 <ambrop7@1a93d707-3861-5ebc-ad3b-9740d49b5140>2010-10-25 13:17:17 +0400
committerambrop7 <ambrop7@1a93d707-3861-5ebc-ad3b-9740d49b5140>2010-10-25 13:17:17 +0400
commit198d6cd4b88ff46f486d2777caf591d59d474fd4 (patch)
treeb3c896166be4bbdd41fe625e22a8371854efd5f8 /nspr_support
parent2af3ceb222cfda3c381fa1e0595085a851ef648c (diff)
Initial import
Diffstat (limited to 'nspr_support')
-rw-r--r--nspr_support/BPRFileDesc.c254
-rw-r--r--nspr_support/BPRFileDesc.h127
-rw-r--r--nspr_support/BSocketPRFileDesc.c294
-rw-r--r--nspr_support/BSocketPRFileDesc.h54
-rw-r--r--nspr_support/CMakeLists.txt8
-rw-r--r--nspr_support/DummyPRFileDesc.c169
-rw-r--r--nspr_support/DummyPRFileDesc.h54
-rw-r--r--nspr_support/PRStreamSink.c138
-rw-r--r--nspr_support/PRStreamSink.h84
-rw-r--r--nspr_support/PRStreamSource.c144
-rw-r--r--nspr_support/PRStreamSource.h86
11 files changed, 1412 insertions, 0 deletions
diff --git a/nspr_support/BPRFileDesc.c b/nspr_support/BPRFileDesc.c
new file mode 100644
index 0000000..cd54e7d
--- /dev/null
+++ b/nspr_support/BPRFileDesc.c
@@ -0,0 +1,254 @@
+/**
+ * @file BPRFileDesc.c
+ * @author Ambroz Bizjak <ambrop7@gmail.com>
+ *
+ * @section LICENSE
+ *
+ * This file is part of BadVPN.
+ *
+ * BadVPN is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ * BadVPN is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <stdlib.h>
+
+#include <misc/offset.h>
+#include <misc/debug.h>
+
+#include <nspr_support/BPRFileDesc.h>
+
+static void init_handlers (BPRFileDesc *obj);
+static int get_event_index (int event);
+static int get_bsocket_events (PRUint16 pr_events);
+static void init_bottom (BPRFileDesc *obj);
+static void free_bottom (BPRFileDesc *obj);
+static void update_bottom (BPRFileDesc *obj);
+static void set_bottom_events (BPRFileDesc *obj, PRInt16 new_events);
+static void socket_handler (BPRFileDesc *obj, int event);
+
+void init_handlers (BPRFileDesc *obj)
+{
+ int i;
+ for (i = 0; i < 2; i++) {
+ obj->handlers[i] = NULL;
+ }
+}
+
+int get_event_index (int event)
+{
+ switch (event) {
+ case PR_POLL_READ:
+ return 0;
+ case PR_POLL_WRITE:
+ return 1;
+ default:
+ ASSERT(0)
+ return 0;
+ }
+}
+
+int get_bsocket_events (PRUint16 pr_events)
+{
+ int res = 0;
+
+ if (pr_events&PR_POLL_READ) {
+ res |= BSOCKET_READ;
+ }
+ if (pr_events&PR_POLL_WRITE) {
+ res |= BSOCKET_WRITE;
+ }
+
+ return res;
+}
+
+void init_bottom (BPRFileDesc *obj)
+{
+ PRFileDesc *layer = obj->prfd;
+ do {
+ if (layer->identity == bsocketprfiledesc_identity) {
+ obj->bottom_type = BPRFILEDESC_BOTTOM_BSOCKET;
+ obj->bottom = layer;
+ BSocket_AddGlobalEventHandler((BSocket *)obj->bottom->secret, (BSocket_handler)socket_handler, obj);
+ return;
+ }
+ layer = layer->lower;
+ } while (layer);
+
+ ASSERT(0)
+}
+
+void free_bottom (BPRFileDesc *obj)
+{
+ switch (obj->bottom_type) {
+ case BPRFILEDESC_BOTTOM_BSOCKET:
+ BSocket_RemoveGlobalEventHandler((BSocket *)obj->bottom->secret);
+ break;
+ default:
+ ASSERT(0)
+ break;
+ }
+}
+
+void update_bottom (BPRFileDesc *obj)
+{
+ // calculate bottom events
+ PRInt16 new_bottom_events = 0;
+ PRInt16 new_flags;
+ PRInt16 out_flags;
+ if (obj->waitEvents&PR_POLL_READ) {
+ new_flags = obj->prfd->methods->poll(obj->prfd, PR_POLL_READ, &out_flags);
+ if ((new_flags&out_flags) == 0) {
+ new_bottom_events |= new_flags;
+ }
+ }
+ if (obj->waitEvents&PR_POLL_WRITE) {
+ new_flags = obj->prfd->methods->poll(obj->prfd, PR_POLL_WRITE, &out_flags);
+ if ((new_flags&out_flags) == 0) {
+ new_bottom_events |= new_flags;
+ }
+ }
+
+ switch (obj->bottom_type) {
+ case BPRFILEDESC_BOTTOM_BSOCKET:
+ BSocket_SetGlobalEvents((BSocket *)obj->bottom->secret, get_bsocket_events(new_bottom_events));
+ break;
+ default:
+ ASSERT(0)
+ break;
+ }
+}
+
+void socket_handler (BPRFileDesc *obj, int events)
+{
+ // make sure bottom events are not recalculated whenever an event
+ // is disabled or enabled, it's faster to do it only once
+ obj->in_handler = 1;
+
+ // call handlers for all enabled events
+
+ if (obj->waitEvents&PR_POLL_READ) {
+ BPRFileDesc_DisableEvent(obj, PR_POLL_READ);
+ DEAD_ENTER(obj->dead)
+ obj->handlers[0](obj->handlers_user[0], PR_POLL_READ);
+ if (DEAD_LEAVE(obj->dead)) {
+ return;
+ }
+ }
+
+ if (obj->waitEvents&PR_POLL_WRITE) {
+ BPRFileDesc_DisableEvent(obj, PR_POLL_WRITE);
+ DEAD_ENTER(obj->dead)
+ obj->handlers[1](obj->handlers_user[1], PR_POLL_WRITE);
+ if (DEAD_LEAVE(obj->dead)) {
+ return;
+ }
+ }
+
+ // recalculate bottom events
+ obj->in_handler = 0;
+ update_bottom(obj);
+}
+
+void BPRFileDesc_Init (BPRFileDesc *obj, PRFileDesc *prfd)
+{
+ DEAD_INIT(obj->dead);
+ obj->prfd = prfd;
+ init_handlers(obj);
+ obj->waitEvents = 0;
+ init_bottom(obj);
+ obj->in_handler = 0;
+
+ // init debug object
+ DebugObject_Init(&obj->d_obj);
+}
+
+void BPRFileDesc_Free (BPRFileDesc *obj)
+{
+ // free debug object
+ DebugObject_Free(&obj->d_obj);
+
+ free_bottom(obj);
+ DEAD_KILL(obj->dead);
+}
+
+void BPRFileDesc_AddEventHandler (BPRFileDesc *obj, PRInt16 event, BPRFileDesc_handler handler, void *user)
+{
+ ASSERT(handler)
+
+ // get index
+ int index = get_event_index(event);
+
+ // event must not have handler
+ ASSERT(!obj->handlers[index])
+
+ // change handler
+ obj->handlers[index] = handler;
+ obj->handlers_user[index] = user;
+}
+
+void BPRFileDesc_RemoveEventHandler (BPRFileDesc *obj, PRInt16 event)
+{
+ // get index
+ int index = get_event_index(event);
+
+ // event must have handler
+ ASSERT(obj->handlers[index])
+
+ // disable event if enabled
+ if (obj->waitEvents&event) {
+ BPRFileDesc_DisableEvent(obj, event);
+ }
+
+ // change handler
+ obj->handlers[index] = NULL;
+}
+
+void BPRFileDesc_EnableEvent (BPRFileDesc *obj, PRInt16 event)
+{
+ // get index
+ int index = get_event_index(event);
+
+ // event must have handler
+ ASSERT(obj->handlers[index])
+
+ // event must not be enabled
+ ASSERT(!(obj->waitEvents&event))
+
+ // update events
+ obj->waitEvents |= event;
+
+ // update bottom
+ if (!obj->in_handler) {
+ update_bottom(obj);
+ }
+}
+
+void BPRFileDesc_DisableEvent (BPRFileDesc *obj, PRInt16 event)
+{
+ // get index
+ int index = get_event_index(event);
+
+ // event must have handler
+ ASSERT(obj->handlers[index])
+
+ // event must be enabled
+ ASSERT(obj->waitEvents&event)
+
+ // update events
+ obj->waitEvents &= ~event;
+
+ // update bottom
+ if (!obj->in_handler) {
+ update_bottom(obj);
+ }
+}
diff --git a/nspr_support/BPRFileDesc.h b/nspr_support/BPRFileDesc.h
new file mode 100644
index 0000000..13aabdf
--- /dev/null
+++ b/nspr_support/BPRFileDesc.h
@@ -0,0 +1,127 @@
+/**
+ * @file BPRFileDesc.h
+ * @author Ambroz Bizjak <ambrop7@gmail.com>
+ *
+ * @section LICENSE
+ *
+ * This file is part of BadVPN.
+ *
+ * BadVPN is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ * BadVPN is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * @section DESCRIPTION
+ *
+ * Object used for obtaining notifications for available I/O operations
+ * on NSPR file descriptors (PRFileDesc) with supported bottom layers.
+ * Currently only the {@link BSocketPRFileDesc} bottom layer is supported.
+ */
+
+#ifndef BADVPN_NSPRSUPPORT_BPRFILEDESC_H
+#define BADVPN_NSPRSUPPORT_BPRFILEDESC_H
+
+#include <misc/dead.h>
+#include <system/DebugObject.h>
+#include <nspr_support/BSocketPRFileDesc.h>
+
+#define BPRFILEDESC_BOTTOM_BSOCKET 1
+
+/**
+ * Handler function called when an event occurs on the NSPR file descriptor.
+ * It is guaranteed that the event had a handler and was enabled.
+ * The event is disabled before the handler is called.
+ *
+ * @param user as in {@link BPRFileDesc_AddEventHandler}
+ * @param event event being reported
+ */
+typedef void (*BPRFileDesc_handler) (void *user, PRInt16 event);
+
+/**
+ * Object used for obtaining notifications for available I/O operations
+ * on NSPR file descriptors (PRFileDesc) with supported bottom layers.
+ * Currently only the {@link BSocketPRFileDesc} bottom layer is supported.
+ */
+typedef struct {
+ DebugObject d_obj;
+ dead_t dead;
+ BReactor *reactor;
+ PRFileDesc *prfd;
+ BPRFileDesc_handler handlers[2];
+ void *handlers_user[2];
+ PRInt16 waitEvents;
+ int bottom_type;
+ PRFileDesc *bottom;
+ int in_handler;
+} BPRFileDesc;
+
+/**
+ * Initializes the object.
+ *
+ * @param obj the object
+ * @param prfd NSPR file descriptor for which notifications are needed.
+ * Its bottom layer must be a {@link BSocketPRFileDesc}.
+ * The bottom {@link BSocket} must not have any event handlers
+ * registered (socket-global or event-specific).
+ * This object registers a socket-global event handler for
+ * the bottom {@link BSocket}.
+ */
+void BPRFileDesc_Init (BPRFileDesc *obj, PRFileDesc *prfd);
+
+/**
+ * Frees the object.
+ * @param obj the object
+ */
+void BPRFileDesc_Free (BPRFileDesc *obj);
+
+/**
+ * Registers a handler for an event.
+ * The event must not already have a handler.
+ *
+ * @param obj the object
+ * @param event NSPR event to register the handler for. Must be
+ * PR_POLL_READ or PR_POLL_WRITE.
+ * @param user value to pass to handler
+ */
+void BPRFileDesc_AddEventHandler (BPRFileDesc *obj, PRInt16 event, BPRFileDesc_handler handler, void *user);
+
+/**
+ * Unregisters a handler for an event.
+ * The event must have a handler.
+ *
+ * @param obj the object
+ * @param event NSPR event to unregister the handler for
+ */
+void BPRFileDesc_RemoveEventHandler (BPRFileDesc *obj, PRInt16 event);
+
+/**
+ * Enables monitoring of an event.
+ * The event must have a handler.
+ * The event must not be enabled.
+ * If the operation associated with the event can already be performed,
+ * the handler for the event may never be called.
+ *
+ * @param obj the object
+ * @param event NSPR event to enable monitoring for
+ */
+void BPRFileDesc_EnableEvent (BPRFileDesc *obj, PRInt16 event);
+
+/**
+ * Disables monitoring of an event.
+ * The event must have a handler.
+ * The event must be enabled.
+ *
+ * @param obj the object
+ * @param event NSPR event to disable monitoring for
+ */
+void BPRFileDesc_DisableEvent (BPRFileDesc *obj, PRInt16 event);
+
+#endif
diff --git a/nspr_support/BSocketPRFileDesc.c b/nspr_support/BSocketPRFileDesc.c
new file mode 100644
index 0000000..8924d6a
--- /dev/null
+++ b/nspr_support/BSocketPRFileDesc.c
@@ -0,0 +1,294 @@
+/**
+ * @file BSocketPRFileDesc.c
+ * @author Ambroz Bizjak <ambrop7@gmail.com>
+ *
+ * @section LICENSE
+ *
+ * This file is part of BadVPN.
+ *
+ * BadVPN is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ * BadVPN is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+
+#include <prerror.h>
+#include <prmem.h>
+
+#include <misc/debug.h>
+#include <misc/offset.h>
+
+#include <nspr_support/BSocketPRFileDesc.h>
+
+#ifndef NDEBUG
+int bsocketprfiledesc_initialized = 0;
+#endif
+PRDescIdentity bsocketprfiledesc_identity;
+
+static int baddr_to_prnetaddr (PRNetAddr *out, BAddr addr)
+{
+ memset(out, 0, sizeof(PRNetAddr));
+
+ switch (addr.type) {
+ case BADDR_TYPE_IPV4:
+ out->inet.family = PR_AF_INET;
+ out->inet.port = addr.ipv4.port;
+ out->inet.ip = addr.ipv4.ip;
+ break;
+ case BADDR_TYPE_IPV6:
+ out->ipv6.family = PR_AF_INET6;
+ out->ipv6.port = addr.ipv6.port;
+ out->ipv6.flowinfo = 0;
+ memcpy(&out->ipv6.ip, addr.ipv6.ip, 16);
+ break;
+ default:
+ return 0;
+ }
+
+ return 1;
+}
+
+static PRStatus method_close (PRFileDesc *fd)
+{
+ return PR_SUCCESS;
+}
+
+static PRInt32 method_read (PRFileDesc *fd, void *buf, PRInt32 amount)
+{
+ ASSERT(amount >= 0)
+
+ BSocket *bsock = (BSocket *)fd->secret;
+
+ if (amount > INT_MAX) {
+ amount = INT_MAX;
+ }
+
+ int res = BSocket_Recv(bsock, buf, amount);
+ if (res < 0) {
+ switch (BSocket_GetError(bsock)) {
+ case BSOCKET_ERROR_LATER:
+ PR_SetError(PR_WOULD_BLOCK_ERROR, 0);
+ return -1;
+ default:
+ PR_SetError(PR_UNKNOWN_ERROR, 0);
+ return -1;
+ }
+ }
+
+ return res;
+}
+
+static PRInt32 method_write (PRFileDesc *fd, const void *buf, PRInt32 amount)
+{
+ ASSERT(amount >= 0)
+
+ BSocket *bsock = (BSocket *)fd->secret;
+
+ if (amount > INT_MAX) {
+ amount = INT_MAX;
+ }
+
+ int res = BSocket_Send(bsock, (uint8_t *)buf, amount);
+ ASSERT(res != 0)
+ if (res < 0) {
+ switch (BSocket_GetError(bsock)) {
+ case BSOCKET_ERROR_LATER:
+ PR_SetError(PR_WOULD_BLOCK_ERROR, 0);
+ return -1;
+ default:
+ PR_SetError(PR_UNKNOWN_ERROR, 0);
+ return -1;
+ }
+ }
+
+ return res;
+}
+
+static PRStatus method_shutdown (PRFileDesc *fd, PRIntn how)
+{
+ PR_SetError(PR_INVALID_METHOD_ERROR, 0);
+ return PR_FAILURE;
+}
+
+static PRInt32 method_recv (PRFileDesc *fd, void *buf, PRInt32 amount, PRIntn flags, PRIntervalTime timeout)
+{
+ ASSERT(flags == 0)
+
+ return method_read(fd, buf, amount);
+}
+
+static PRInt32 method_send (PRFileDesc *fd, const void *buf, PRInt32 amount, PRIntn flags, PRIntervalTime timeout)
+{
+ ASSERT(flags == 0)
+
+ return method_write(fd, buf, amount);
+}
+
+static PRInt16 method_poll (PRFileDesc *fd, PRInt16 in_flags, PRInt16 *out_flags)
+{
+ *out_flags = 0;
+ return in_flags;
+}
+
+static PRStatus method_getpeername (PRFileDesc *fd, PRNetAddr *addr)
+{
+ BSocket *bsock = (BSocket *)fd->secret;
+
+ BAddr baddr;
+ if (BSocket_GetPeerName(bsock, &baddr) < 0) {
+ PR_SetError(PR_UNKNOWN_ERROR, 0);
+ return PR_FAILURE;
+ }
+
+ if (!baddr_to_prnetaddr(addr, baddr)) {
+ PR_SetError(PR_UNKNOWN_ERROR, 0);
+ return PR_FAILURE;
+ }
+
+ return PR_SUCCESS;
+}
+
+static PRStatus method_getsocketoption (PRFileDesc *fd, PRSocketOptionData *data)
+{
+ BSocket *bsock = (BSocket *)fd->secret;
+
+ switch (data->option) {
+ case PR_SockOpt_Nonblocking:
+ data->value.non_blocking = PR_TRUE;
+ return PR_SUCCESS;
+ }
+
+ PR_SetError(PR_UNKNOWN_ERROR, 0);
+ return PR_FAILURE;
+}
+
+static PRStatus method_setsocketoption (PRFileDesc *fd, const PRSocketOptionData *data)
+{
+ PR_SetError(PR_UNKNOWN_ERROR, 0);
+ return PR_FAILURE;
+}
+
+static PRIntn _PR_InvalidIntn (void)
+{
+ ASSERT(0)
+ PR_SetError(PR_INVALID_METHOD_ERROR, 0);
+ return -1;
+}
+
+static PRInt32 _PR_InvalidInt32 (void)
+{
+ ASSERT(0)
+ PR_SetError(PR_INVALID_METHOD_ERROR, 0);
+ return -1;
+}
+
+static PRInt64 _PR_InvalidInt64 (void)
+{
+ ASSERT(0)
+ PR_SetError(PR_INVALID_METHOD_ERROR, 0);
+ return -1;
+}
+
+static PROffset32 _PR_InvalidOffset32 (void)
+{
+ ASSERT(0)
+ PR_SetError(PR_INVALID_METHOD_ERROR, 0);
+ return -1;
+}
+
+static PROffset64 _PR_InvalidOffset64 (void)
+{
+ ASSERT(0)
+ PR_SetError(PR_INVALID_METHOD_ERROR, 0);
+ return -1;
+}
+
+static PRStatus _PR_InvalidStatus (void)
+{
+ ASSERT(0)
+ PR_SetError(PR_INVALID_METHOD_ERROR, 0);
+ return PR_FAILURE;
+}
+
+static PRFileDesc *_PR_InvalidDesc (void)
+{
+ ASSERT(0)
+ PR_SetError(PR_INVALID_METHOD_ERROR, 0);
+ return NULL;
+}
+
+static PRIOMethods methods = {
+ (PRDescType)0,
+ method_close,
+ method_read,
+ method_write,
+ (PRAvailableFN)_PR_InvalidInt32,
+ (PRAvailable64FN)_PR_InvalidInt64,
+ (PRFsyncFN)_PR_InvalidStatus,
+ (PRSeekFN)_PR_InvalidOffset32,
+ (PRSeek64FN)_PR_InvalidOffset64,
+ (PRFileInfoFN)_PR_InvalidStatus,
+ (PRFileInfo64FN)_PR_InvalidStatus,
+ (PRWritevFN)_PR_InvalidInt32,
+ (PRConnectFN)_PR_InvalidStatus,
+ (PRAcceptFN)_PR_InvalidDesc,
+ (PRBindFN)_PR_InvalidStatus,
+ (PRListenFN)_PR_InvalidStatus,
+ method_shutdown,
+ method_recv,
+ method_send,
+ (PRRecvfromFN)_PR_InvalidInt32,
+ (PRSendtoFN)_PR_InvalidInt32,
+ method_poll,
+ (PRAcceptreadFN)_PR_InvalidInt32,
+ (PRTransmitfileFN)_PR_InvalidInt32,
+ (PRGetsocknameFN)_PR_InvalidStatus,
+ method_getpeername,
+ (PRReservedFN)_PR_InvalidIntn,
+ (PRReservedFN)_PR_InvalidIntn,
+ method_getsocketoption,
+ method_setsocketoption,
+ (PRSendfileFN)_PR_InvalidInt32,
+ (PRConnectcontinueFN)_PR_InvalidStatus,
+ (PRReservedFN)_PR_InvalidIntn,
+ (PRReservedFN)_PR_InvalidIntn,
+ (PRReservedFN)_PR_InvalidIntn,
+ (PRReservedFN)_PR_InvalidIntn
+};
+
+int BSocketPRFileDesc_GlobalInit (void)
+{
+ ASSERT(!bsocketprfiledesc_initialized)
+
+ if ((bsocketprfiledesc_identity = PR_GetUniqueIdentity("BSocketPRFileDesc")) == PR_INVALID_IO_LAYER) {
+ return 0;
+ }
+
+ #ifndef NDEBUG
+ bsocketprfiledesc_initialized = 1;
+ #endif
+
+ return 1;
+}
+
+void BSocketPRFileDesc_Create (PRFileDesc *prfd, BSocket *bsock)
+{
+ ASSERT(bsocketprfiledesc_initialized)
+
+ memset(prfd, 0, sizeof(prfd));
+ prfd->methods = &methods;
+ prfd->secret = (PRFilePrivate *)bsock;
+ prfd->identity = bsocketprfiledesc_identity;
+}
diff --git a/nspr_support/BSocketPRFileDesc.h b/nspr_support/BSocketPRFileDesc.h
new file mode 100644
index 0000000..6cf8e52
--- /dev/null
+++ b/nspr_support/BSocketPRFileDesc.h
@@ -0,0 +1,54 @@
+/**
+ * @file BSocketPRFileDesc.h
+ * @author Ambroz Bizjak <ambrop7@gmail.com>
+ *
+ * @section LICENSE
+ *
+ * This file is part of BadVPN.
+ *
+ * BadVPN is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ * BadVPN is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * @section DESCRIPTION
+ *
+ * NSPR file descriptor (PRFileDesc) for {@link BSocket} stream sockets.
+ */
+
+#ifndef BADVPN_NSPRSUPPORT_BSOCKETPRFILEDESC_H
+#define BADVPN_NSPRSUPPORT_BSOCKETPRFILEDESC_H
+
+#include <prio.h>
+
+#include <misc/debug.h>
+#include <system/BSocket.h>
+
+extern PRDescIdentity bsocketprfiledesc_identity;
+
+/**
+ * Globally initializes the {@link BSocket} NSPR file descriptor backend.
+ * Must not have been called successfully.
+ *
+ * @return 1 on success, 0 on failure
+ */
+int BSocketPRFileDesc_GlobalInit (void) WARN_UNUSED;
+
+/**
+ * Creates a NSPR file descriptor using {@link BSocket} for I/O.
+ * {@link BSocketPRFileDesc_GlobalInit} must have been done.
+ *
+ * @param prfd uninitialized PRFileDesc structure
+ * @param bsock socket to use. The socket should be a stream socket.
+ */
+void BSocketPRFileDesc_Create (PRFileDesc *prfd, BSocket *bsock);
+
+#endif
diff --git a/nspr_support/CMakeLists.txt b/nspr_support/CMakeLists.txt
new file mode 100644
index 0000000..010c397
--- /dev/null
+++ b/nspr_support/CMakeLists.txt
@@ -0,0 +1,8 @@
+add_library(nspr_support
+ BSocketPRFileDesc.c
+ DummyPRFileDesc.c
+ BPRFileDesc.c
+ PRStreamSource.c
+ PRStreamSink.c
+)
+target_link_libraries(nspr_support system ${NSPR_LIBRARIES})
diff --git a/nspr_support/DummyPRFileDesc.c b/nspr_support/DummyPRFileDesc.c
new file mode 100644
index 0000000..a99be41
--- /dev/null
+++ b/nspr_support/DummyPRFileDesc.c
@@ -0,0 +1,169 @@
+/**
+ * @file DummyPRFileDesc.c
+ * @author Ambroz Bizjak <ambrop7@gmail.com>
+ *
+ * @section LICENSE
+ *
+ * This file is part of BadVPN.
+ *
+ * BadVPN is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ * BadVPN is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+
+#include <prerror.h>
+#include <prmem.h>
+
+#include <misc/debug.h>
+#include <misc/offset.h>
+
+#include <nspr_support/DummyPRFileDesc.h>
+
+#ifndef NDEBUG
+int dummyprfiledesc_initialized = 0;
+#endif
+PRDescIdentity dummyprfiledesc_identity;
+
+static PRStatus method_close (PRFileDesc *fd)
+{
+ return PR_SUCCESS;
+}
+
+static PRStatus method_getpeername (PRFileDesc *fd, PRNetAddr *addr)
+{
+ PR_SetError(PR_UNKNOWN_ERROR, 0);
+ return PR_FAILURE;
+}
+
+static PRIntn _PR_InvalidIntn (void)
+{
+ ASSERT(0)
+ PR_SetError(PR_INVALID_METHOD_ERROR, 0);
+ return -1;
+}
+
+static PRInt16 _PR_InvalidInt16 (void)
+{
+ ASSERT(0)
+ PR_SetError(PR_INVALID_METHOD_ERROR, 0);
+ return -1;
+}
+
+static PRInt32 _PR_InvalidInt32 (void)
+{
+ ASSERT(0)
+ PR_SetError(PR_INVALID_METHOD_ERROR, 0);
+ return -1;
+}
+
+static PRInt64 _PR_InvalidInt64 (void)
+{
+ ASSERT(0)
+ PR_SetError(PR_INVALID_METHOD_ERROR, 0);
+ return -1;
+}
+
+static PROffset32 _PR_InvalidOffset32 (void)
+{
+ ASSERT(0)
+ PR_SetError(PR_INVALID_METHOD_ERROR, 0);
+ return -1;
+}
+
+static PROffset64 _PR_InvalidOffset64 (void)
+{
+ ASSERT(0)
+ PR_SetError(PR_INVALID_METHOD_ERROR, 0);
+ return -1;
+}
+
+static PRStatus _PR_InvalidStatus (void)
+{
+ ASSERT(0)
+ PR_SetError(PR_INVALID_METHOD_ERROR, 0);
+ return PR_FAILURE;
+}
+
+static PRFileDesc *_PR_InvalidDesc (void)
+{
+ ASSERT(0)
+ PR_SetError(PR_INVALID_METHOD_ERROR, 0);
+ return NULL;
+}
+
+static PRIOMethods methods = {
+ (PRDescType)0,
+ method_close,
+ (PRReadFN)_PR_InvalidInt32,
+ (PRWriteFN)_PR_InvalidInt32,
+ (PRAvailableFN)_PR_InvalidInt32,
+ (PRAvailable64FN)_PR_InvalidInt64,
+ (PRFsyncFN)_PR_InvalidStatus,
+ (PRSeekFN)_PR_InvalidOffset32,
+ (PRSeek64FN)_PR_InvalidOffset64,
+ (PRFileInfoFN)_PR_InvalidStatus,
+ (PRFileInfo64FN)_PR_InvalidStatus,
+ (PRWritevFN)_PR_InvalidInt32,
+ (PRConnectFN)_PR_InvalidStatus,
+ (PRAcceptFN)_PR_InvalidDesc,
+ (PRBindFN)_PR_InvalidStatus,
+ (PRListenFN)_PR_InvalidStatus,
+ (PRShutdownFN)_PR_InvalidStatus,
+ (PRRecvFN)_PR_InvalidInt32,
+ (PRSendFN)_PR_InvalidInt32,
+ (PRRecvfromFN)_PR_InvalidInt32,
+ (PRSendtoFN)_PR_InvalidInt32,
+ (PRPollFN)_PR_InvalidInt16,
+ (PRAcceptreadFN)_PR_InvalidInt32,
+ (PRTransmitfileFN)_PR_InvalidInt32,
+ (PRGetsocknameFN)_PR_InvalidStatus,
+ method_getpeername,
+ (PRReservedFN)_PR_InvalidIntn,
+ (PRReservedFN)_PR_InvalidIntn,
+ (PRGetsocketoptionFN)_PR_InvalidStatus,
+ (PRSetsocketoptionFN)_PR_InvalidStatus,
+ (PRSendfileFN)_PR_InvalidInt32,
+ (PRConnectcontinueFN)_PR_InvalidStatus,
+ (PRReservedFN)_PR_InvalidIntn,
+ (PRReservedFN)_PR_InvalidIntn,
+ (PRReservedFN)_PR_InvalidIntn,
+ (PRReservedFN)_PR_InvalidIntn
+};
+
+int DummyPRFileDesc_GlobalInit (void)
+{
+ ASSERT(!dummyprfiledesc_initialized)
+
+ if ((dummyprfiledesc_identity = PR_GetUniqueIdentity("DummyPRFileDesc")) == PR_INVALID_IO_LAYER) {
+ return 0;
+ }
+
+ #ifndef NDEBUG
+ dummyprfiledesc_initialized = 1;
+ #endif
+
+ return 1;
+}
+
+void DummyPRFileDesc_Create (PRFileDesc *prfd)
+{
+ ASSERT(dummyprfiledesc_initialized)
+
+ memset(prfd, 0, sizeof(prfd));
+ prfd->methods = &methods;
+ prfd->secret = NULL;
+ prfd->identity = dummyprfiledesc_identity;
+}
diff --git a/nspr_support/DummyPRFileDesc.h b/nspr_support/DummyPRFileDesc.h
new file mode 100644
index 0000000..c24f1ec
--- /dev/null
+++ b/nspr_support/DummyPRFileDesc.h
@@ -0,0 +1,54 @@
+/**
+ * @file DummyPRFileDesc.h
+ * @author Ambroz Bizjak <ambrop7@gmail.com>
+ *
+ * @section LICENSE
+ *
+ * This file is part of BadVPN.
+ *
+ * BadVPN is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ * BadVPN is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * @section DESCRIPTION
+ *
+ * Dummy NSPR file descriptor (PRFileDesc).
+ * Used for creating a model SSL file descriptor to cache various stuff
+ * to improve performance.
+ */
+
+#ifndef BADVPN_NSPRSUPPORT_DUMMYPRFILEDESC_H
+#define BADVPN_NSPRSUPPORT_DUMMYPRFILEDESC_H
+
+#include <prio.h>
+
+#include <misc/debug.h>
+
+extern PRDescIdentity dummyprfiledesc_identity;
+
+/**
+ * Globally initialize the dummy NSPR file descriptor backend.
+ * Must not have been called successfully.
+ *
+ * @return 1 on success, 0 on failure
+ */
+int DummyPRFileDesc_GlobalInit (void) WARN_UNUSED;
+
+/**
+ * Creates a dummy NSPR file descriptor.
+ * {@link DummyPRFileDesc_GlobalInit} must have been done.
+ *
+ * @param prfd uninitialized PRFileDesc structure
+ */
+void DummyPRFileDesc_Create (PRFileDesc *prfd);
+
+#endif
diff --git a/nspr_support/PRStreamSink.c b/nspr_support/PRStreamSink.c
new file mode 100644
index 0000000..8d2330e
--- /dev/null
+++ b/nspr_support/PRStreamSink.c
@@ -0,0 +1,138 @@
+/**
+ * @file PRStreamSink.c
+ * @author Ambroz Bizjak <ambrop7@gmail.com>
+ *
+ * @section LICENSE
+ *
+ * This file is part of BadVPN.
+ *
+ * BadVPN is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ * BadVPN is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <prerror.h>
+
+#include <misc/debug.h>
+
+#include <nspr_support/PRStreamSink.h>
+
+static void report_error (PRStreamSink *s, int error)
+{
+ #ifndef NDEBUG
+ s->in_error = 1;
+ DEAD_ENTER(s->dead)
+ #endif
+
+ FlowErrorReporter_ReportError(&s->rep, &error);
+
+ #ifndef NDEBUG
+ ASSERT(DEAD_KILLED)
+ DEAD_LEAVE(s->dead);
+ #endif
+}
+
+static int input_handler_send (PRStreamSink *s, uint8_t *data, int data_len)
+{
+ ASSERT(s->in_len == -1)
+ ASSERT(data_len > 0)
+ ASSERT(!s->in_error)
+
+ int res = PR_Write(s->bprfd->prfd, data, data_len);
+ if (res < 0) {
+ PRErrorCode error = PR_GetError();
+ if (error == PR_WOULD_BLOCK_ERROR) {
+ s->in_len = data_len;
+ s->in = data;
+ BPRFileDesc_EnableEvent(s->bprfd, PR_POLL_WRITE);
+ return 0;
+ }
+ report_error(s, PRSTREAMSINK_ERROR_NSPR);
+ return -1;
+ }
+
+ ASSERT(res > 0)
+
+ return res;
+}
+
+static void prfd_handler (PRStreamSink *s, PRInt16 event)
+{
+ ASSERT(s->in_len > 0)
+ ASSERT(event == PR_POLL_WRITE)
+ ASSERT(!s->in_error)
+
+ int res = PR_Write(s->bprfd->prfd, s->in, s->in_len);
+ if (res < 0) {
+ PRErrorCode error = PR_GetError();
+ if (error == PR_WOULD_BLOCK_ERROR) {
+ BPRFileDesc_EnableEvent(s->bprfd, PR_POLL_WRITE);
+ return;
+ }
+ report_error(s, PRSTREAMSINK_ERROR_NSPR);
+ return;
+ }
+
+ ASSERT(res > 0)
+
+ s->in_len = -1;
+
+ StreamPassInterface_Done(&s->input, res);
+ return;
+}
+
+void PRStreamSink_Init (PRStreamSink *s, FlowErrorReporter rep, BPRFileDesc *bprfd)
+{
+ // init arguments
+ s->rep = rep;
+ s->bprfd = bprfd;
+
+ // init dead var
+ DEAD_INIT(s->dead);
+
+ // add socket event handler
+ BPRFileDesc_AddEventHandler(s->bprfd, PR_POLL_WRITE, (BPRFileDesc_handler)prfd_handler, s);
+
+ // init input
+ StreamPassInterface_Init(&s->input, (StreamPassInterface_handler_send)input_handler_send, s);
+
+ // have no input packet
+ s->in_len = -1;
+
+ // init debugging
+ #ifndef NDEBUG
+ s->in_error = 0;
+ #endif
+
+ // init debug object
+ DebugObject_Init(&s->d_obj);
+}
+
+void PRStreamSink_Free (PRStreamSink *s)
+{
+ // free debug object
+ DebugObject_Free(&s->d_obj);
+
+ // free input
+ StreamPassInterface_Free(&s->input);
+
+ // remove socket event handler
+ BPRFileDesc_RemoveEventHandler(s->bprfd, PR_POLL_WRITE);
+
+ // free dead var
+ DEAD_KILL(s->dead);
+}
+
+StreamPassInterface * PRStreamSink_GetInput (PRStreamSink *s)
+{
+ return &s->input;
+}
diff --git a/nspr_support/PRStreamSink.h b/nspr_support/PRStreamSink.h
new file mode 100644
index 0000000..cc405a0
--- /dev/null
+++ b/nspr_support/PRStreamSink.h
@@ -0,0 +1,84 @@
+/**
+ * @file PRStreamSink.h
+ * @author Ambroz Bizjak <ambrop7@gmail.com>
+ *
+ * @section LICENSE
+ *
+ * This file is part of BadVPN.
+ *
+ * BadVPN is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ * BadVPN is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * @section DESCRIPTION
+ *
+ * A {@link StreamPassInterface} sink for a NSPR file descriptor (PRFileDesc) via {@link BPRFileDesc}.
+ */
+
+#ifndef BADVPN_NSPRSUPPORT_PRSTREAMSINK_H
+#define BADVPN_NSPRSUPPORT_PRSTREAMSINK_H
+
+#include <stdint.h>
+
+#include <misc/dead.h>
+#include <system/DebugObject.h>
+#include <flow/error.h>
+#include <flow/StreamPassInterface.h>
+#include <nspr_support/BPRFileDesc.h>
+
+#define PRSTREAMSINK_ERROR_NSPR 1
+
+/**
+ * A {@link StreamPassInterface} sink for a NSPR file descriptor (PRFileDesc) via {@link BPRFileDesc}.
+ */
+typedef struct {
+ DebugObject d_obj;
+ dead_t dead;
+ FlowErrorReporter rep;
+ BPRFileDesc *bprfd;
+ StreamPassInterface input;
+ int in_len;
+ uint8_t *in;
+ #ifndef NDEBUG
+ int in_error;
+ #endif
+} PRStreamSink;
+
+/**
+ * Initializes the object.
+ *
+ * @param s the object
+ * @param rep error reporting data. Error code is an int. Possible error codes:
+ * - PRSTREAMSINK_ERROR_NSPR: {@link PR_Write} failed
+ * with an unhandled error code
+ * The object must be freed from the error handler.
+ * @param bprfd the {@link BPRFileDesc} object to write data to. Registers a
+ * PR_POLL_WRITE handler which must not be registered.
+ */
+void PRStreamSink_Init (PRStreamSink *s, FlowErrorReporter rep, BPRFileDesc *bprfd);
+
+/**
+ * Frees the object.
+ *
+ * @param s the object
+ */
+void PRStreamSink_Free (PRStreamSink *s);
+
+/**
+ * Returns the input interface.
+ *
+ * @param s the object
+ * @return input interface
+ */
+StreamPassInterface * PRStreamSink_GetInput (PRStreamSink *s);
+
+#endif
diff --git a/nspr_support/PRStreamSource.c b/nspr_support/PRStreamSource.c
new file mode 100644
index 0000000..74860ae
--- /dev/null
+++ b/nspr_support/PRStreamSource.c
@@ -0,0 +1,144 @@
+/**
+ * @file PRStreamSource.c
+ * @author Ambroz Bizjak <ambrop7@gmail.com>
+ *
+ * @section LICENSE
+ *
+ * This file is part of BadVPN.
+ *
+ * BadVPN is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ * BadVPN is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <prerror.h>
+
+#include <misc/debug.h>
+
+#include <nspr_support/PRStreamSource.h>
+
+static void report_error (PRStreamSource *s, int error)
+{
+ #ifndef NDEBUG
+ s->in_error = 1;
+ DEAD_ENTER(s->dead)
+ #endif
+
+ FlowErrorReporter_ReportError(&s->rep, &error);
+
+ #ifndef NDEBUG
+ ASSERT(DEAD_KILLED)
+ DEAD_LEAVE(s->dead);
+ #endif
+}
+
+static int output_handler_recv (PRStreamSource *s, uint8_t *data, int data_avail)
+{
+ ASSERT(s->out_avail == -1)
+ ASSERT(data_avail > 0)
+ ASSERT(!s->in_error)
+
+ PRInt32 res = PR_Read(s->bprfd->prfd, data, data_avail);
+ if (res < 0) {
+ PRErrorCode error = PR_GetError();
+ if (error == PR_WOULD_BLOCK_ERROR) {
+ s->out_avail = data_avail;
+ s->out = data;
+ BPRFileDesc_EnableEvent(s->bprfd, PR_POLL_READ);
+ return 0;
+ }
+ report_error(s, PRSTREAMSOURCE_ERROR_NSPR);
+ return -1;
+ }
+
+ if (res == 0) {
+ report_error(s, PRSTREAMSOURCE_ERROR_CLOSED);
+ return -1;
+ }
+
+ return res;
+}
+
+static void prfd_handler (PRStreamSource *s, PRInt16 event)
+{
+ ASSERT(s->out_avail > 0)
+ ASSERT(event == PR_POLL_READ)
+ ASSERT(!s->in_error)
+
+ PRInt32 res = PR_Read(s->bprfd->prfd, s->out, s->out_avail);
+ if (res < 0) {
+ PRErrorCode error = PR_GetError();
+ if (error == PR_WOULD_BLOCK_ERROR) {
+ BPRFileDesc_EnableEvent(s->bprfd, PR_POLL_READ);
+ return;
+ }
+ report_error(s, PRSTREAMSOURCE_ERROR_NSPR);
+ return;
+ }
+
+ if (res == 0) {
+ report_error(s, PRSTREAMSOURCE_ERROR_CLOSED);
+ return;
+ }
+
+ s->out_avail = -1;
+
+ StreamRecvInterface_Done(&s->output, res);
+ return;
+}
+
+void PRStreamSource_Init (PRStreamSource *s, FlowErrorReporter rep, BPRFileDesc *bprfd)
+{
+ // init arguments
+ s->rep = rep;
+ s->bprfd = bprfd;
+
+ // init dead var
+ DEAD_INIT(s->dead);
+
+ // add socket event handler
+ BPRFileDesc_AddEventHandler(s->bprfd, PR_POLL_READ, (BPRFileDesc_handler)prfd_handler, s);
+
+ // init output
+ StreamRecvInterface_Init(&s->output, (StreamRecvInterface_handler_recv)output_handler_recv, s);
+
+ // have no output packet
+ s->out_avail = -1;
+
+ // init debugging
+ #ifndef NDEBUG
+ s->in_error = 0;
+ #endif
+
+ // init debug object
+ DebugObject_Init(&s->d_obj);
+}
+
+void PRStreamSource_Free (PRStreamSource *s)
+{
+ // free debug object
+ DebugObject_Free(&s->d_obj);
+
+ // free output
+ StreamRecvInterface_Free(&s->output);
+
+ // remove socket event handler
+ BPRFileDesc_RemoveEventHandler(s->bprfd, PR_POLL_READ);
+
+ // free dead var
+ DEAD_KILL(s->dead);
+}
+
+StreamRecvInterface * PRStreamSource_GetOutput (PRStreamSource *s)
+{
+ return &s->output;
+}
diff --git a/nspr_support/PRStreamSource.h b/nspr_support/PRStreamSource.h
new file mode 100644
index 0000000..23ac94c
--- /dev/null
+++ b/nspr_support/PRStreamSource.h
@@ -0,0 +1,86 @@
+/**
+ * @file PRStreamSource.h
+ * @author Ambroz Bizjak <ambrop7@gmail.com>
+ *
+ * @section LICENSE
+ *
+ * This file is part of BadVPN.
+ *
+ * BadVPN is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ * BadVPN is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * @section DESCRIPTION
+ *
+ * A {@link StreamRecvInterface} source for a NSPR file descriptor (PRFileDesc) via {@link BPRFileDesc}.
+ */
+
+#ifndef BADVPN_NSPRSUPPORT_PRSTREAMSOURCE_H
+#define BADVPN_NSPRSUPPORT_PRSTREAMSOURCE_H
+
+#include <stdint.h>
+
+#include <misc/dead.h>
+#include <system/DebugObject.h>
+#include <flow/error.h>
+#include <flow/StreamRecvInterface.h>
+#include <nspr_support/BPRFileDesc.h>
+
+#define PRSTREAMSOURCE_ERROR_CLOSED 0
+#define PRSTREAMSOURCE_ERROR_NSPR 1
+
+/**
+ * A {@link StreamRecvInterface} source for a NSPR file descriptor (PRFileDesc) via {@link BPRFileDesc}.
+ */
+typedef struct {
+ DebugObject d_obj;
+ dead_t dead;
+ FlowErrorReporter rep;
+ BPRFileDesc *bprfd;
+ StreamRecvInterface output;
+ int out_avail;
+ uint8_t *out;
+ #ifndef NDEBUG
+ int in_error;
+ #endif
+} PRStreamSource;
+
+/**
+ * Initializes the object.
+ *
+ * @param s the object
+ * @param rep error reporting data. Error code is an int. Possible error codes:
+ * - PRSTREAMSOURCE_ERROR_CLOSED: {@link PR_Read} returned 0
+ * - PRSTREAMSOURCE_ERROR_NSPR: {@link PR_Read} failed
+ * with an unhandled error code
+ * The object must be freed from the error handler.
+ * @param bprfd the {@link BPRFileDesc} object to read data from. Registers a
+ * PR_POLL_READ handler which must not be registered.
+ */
+void PRStreamSource_Init (PRStreamSource *s, FlowErrorReporter rep, BPRFileDesc *bprfd);
+
+/**
+ * Frees the object.
+ *
+ * @param s the object
+ */
+void PRStreamSource_Free (PRStreamSource *s);
+
+/**
+ * Returns the output interface.
+ *
+ * @param s the object
+ * @return output interface
+ */
+StreamRecvInterface * PRStreamSource_GetOutput (PRStreamSource *s);
+
+#endif