diff options
author | ambrop7 <ambrop7@1a93d707-3861-5ebc-ad3b-9740d49b5140> | 2010-10-25 13:17:17 +0400 |
---|---|---|
committer | ambrop7 <ambrop7@1a93d707-3861-5ebc-ad3b-9740d49b5140> | 2010-10-25 13:17:17 +0400 |
commit | 198d6cd4b88ff46f486d2777caf591d59d474fd4 (patch) | |
tree | b3c896166be4bbdd41fe625e22a8371854efd5f8 /nspr_support | |
parent | 2af3ceb222cfda3c381fa1e0595085a851ef648c (diff) |
Initial import
Diffstat (limited to 'nspr_support')
-rw-r--r-- | nspr_support/BPRFileDesc.c | 254 | ||||
-rw-r--r-- | nspr_support/BPRFileDesc.h | 127 | ||||
-rw-r--r-- | nspr_support/BSocketPRFileDesc.c | 294 | ||||
-rw-r--r-- | nspr_support/BSocketPRFileDesc.h | 54 | ||||
-rw-r--r-- | nspr_support/CMakeLists.txt | 8 | ||||
-rw-r--r-- | nspr_support/DummyPRFileDesc.c | 169 | ||||
-rw-r--r-- | nspr_support/DummyPRFileDesc.h | 54 | ||||
-rw-r--r-- | nspr_support/PRStreamSink.c | 138 | ||||
-rw-r--r-- | nspr_support/PRStreamSink.h | 84 | ||||
-rw-r--r-- | nspr_support/PRStreamSource.c | 144 | ||||
-rw-r--r-- | nspr_support/PRStreamSource.h | 86 |
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 |