Просмотр исходного кода

flow: add SeqPacketSocketSource, SeqPacketSocketSink

ambrop7 15 лет назад
Родитель
Сommit
8106534d0f

+ 2 - 0
flow/CMakeLists.txt

@@ -27,5 +27,7 @@ add_library(flow
     DataProtoKeepaliveSource.c
     PacketProtoFlow.c
     SinglePacketSender.c
+    SeqPacketSocketSink.c
+    SeqPacketSocketSource.c
 )
 target_link_libraries(flow system security)

+ 146 - 0
flow/SeqPacketSocketSink.c

@@ -0,0 +1,146 @@
+/**
+ * @file SeqPacketSocketSink.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 <misc/debug.h>
+
+#include <flow/SeqPacketSocketSink.h>
+
+static void report_error (SeqPacketSocketSink *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 (SeqPacketSocketSink *s, uint8_t *data, int data_len)
+{
+    ASSERT(s->in_len == -1)
+    ASSERT(data_len >= 0)
+    ASSERT(!s->in_error)
+    DebugObject_Access(&s->d_obj);
+    
+    int res = BSocket_Send(s->bsock, data, data_len);
+    if (res < 0) {
+        int error = BSocket_GetError(s->bsock);
+        if (error == BSOCKET_ERROR_LATER) {
+            s->in_len = data_len;
+            s->in = data;
+            BSocket_EnableEvent(s->bsock, BSOCKET_WRITE);
+            return 0;
+        }
+        report_error(s, SEQPACKETSOCKETSINK_ERROR_BSOCKET);
+        return -1;
+    } else {
+        if (res != data_len) {
+            report_error(s, SEQPACKETSOCKETSINK_ERROR_WRONGSIZE);
+            return -1;
+        }
+    }
+    
+    return 1;
+}
+
+static void socket_handler (SeqPacketSocketSink *s, int event)
+{
+    ASSERT(s->in_len >= 0)
+    ASSERT(event == BSOCKET_WRITE)
+    ASSERT(!s->in_error)
+    DebugObject_Access(&s->d_obj);
+    
+    int res = BSocket_Send(s->bsock, s->in, s->in_len);
+    if (res < 0) {
+        int error = BSocket_GetError(s->bsock);
+        if (error == BSOCKET_ERROR_LATER) {
+            return;
+        }
+        report_error(s, SEQPACKETSOCKETSINK_ERROR_BSOCKET);
+        return;
+    } else {
+        if (res != s->in_len) {
+            report_error(s, SEQPACKETSOCKETSINK_ERROR_WRONGSIZE);
+            return;
+        }
+    }
+    
+    BSocket_DisableEvent(s->bsock, BSOCKET_WRITE);
+    s->in_len = -1;
+    
+    PacketPassInterface_Done(&s->input);
+    return;
+}
+
+void SeqPacketSocketSink_Init (SeqPacketSocketSink *s, FlowErrorReporter rep, BSocket *bsock, int mtu)
+{
+    ASSERT(mtu >= 0)
+    
+    // init arguments
+    s->rep = rep;
+    s->bsock = bsock;
+    
+    // init dead var
+    DEAD_INIT(s->dead);
+    
+    // add socket event handler
+    BSocket_AddEventHandler(s->bsock, BSOCKET_WRITE, (BSocket_handler)socket_handler, s);
+    
+    // init input
+    PacketPassInterface_Init(&s->input, mtu, (PacketPassInterface_handler_send)input_handler_send, s);
+    
+    // have no input packet
+    s->in_len = -1;
+    
+    // init debugging
+    #ifndef NDEBUG
+    s->in_error = 0;
+    #endif
+    
+    DebugObject_Init(&s->d_obj);
+}
+
+void SeqPacketSocketSink_Free (SeqPacketSocketSink *s)
+{
+    DebugObject_Free(&s->d_obj);
+
+    // free input
+    PacketPassInterface_Free(&s->input);
+    
+    // remove socket event handler
+    BSocket_RemoveEventHandler(s->bsock, BSOCKET_WRITE);
+    
+    // free dead var
+    DEAD_KILL(s->dead);
+}
+
+PacketPassInterface * SeqPacketSocketSink_GetInput (SeqPacketSocketSink *s)
+{
+    DebugObject_Access(&s->d_obj);
+    
+    return &s->input;
+}

+ 89 - 0
flow/SeqPacketSocketSink.h

@@ -0,0 +1,89 @@
+/**
+ * @file SeqPacketSocketSink.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 PacketPassInterface} sink which sends packets to a seqpacket socket.
+ */
+
+#ifndef BADVPN_FLOW_SEQPACKETSOCKETSINK_H
+#define BADVPN_FLOW_SEQPACKETSOCKETSINK_H
+
+#include <stdint.h>
+
+#include <misc/dead.h>
+#include <system/DebugObject.h>
+#include <system/BSocket.h>
+#include <flow/PacketPassInterface.h>
+#include <flow/error.h>
+
+#define SEQPACKETSOCKETSINK_ERROR_BSOCKET 1
+#define SEQPACKETSOCKETSINK_ERROR_WRONGSIZE 2
+
+/**
+ * A {@link PacketPassInterface} sink which sends packets to a seqpacket socket.
+ */
+typedef struct {
+    DebugObject d_obj;
+    dead_t dead;
+    FlowErrorReporter rep;
+    BSocket *bsock;
+    PacketPassInterface input;
+    int in_len;
+    uint8_t *in;
+    #ifndef NDEBUG
+    int in_error;
+    #endif
+} SeqPacketSocketSink;
+
+/**
+ * Initializes the sink.
+ *
+ * @param s the object
+ * @param rep error reporting data. Error code is an int. Possible error codes:
+ *              - SEQPACKETSOCKETSINK_ERROR_BSOCKET: {@link BSocket_Send} failed
+ *                with an unhandled error code
+ *              - SEQPACKETSOCKETSINK_ERROR_WRONGSIZE: {@link BSocket_Send} succeeded,
+ *                but did not send all of the packet
+ *            The object must be freed from the error handler.
+ * @param bsock socket to write packets to. Registers a BSOCKET_WRITE handler which
+ *              must not be registered.
+ * @param mtu maximum packet size. Must be >=0.
+ */
+void SeqPacketSocketSink_Init (SeqPacketSocketSink *s, FlowErrorReporter rep, BSocket *bsock, int mtu);
+
+/**
+ * Frees the sink.
+ *
+ * @param s the object
+ */
+void SeqPacketSocketSink_Free (SeqPacketSocketSink *s);
+
+/**
+ * Returns the input interface.
+ * The MTU of the interface will be as in {@link SeqPacketSocketSink_Init}.
+ *
+ * @param s the object
+ * @return input interface
+ */
+PacketPassInterface * SeqPacketSocketSink_GetInput (SeqPacketSocketSink *s);
+
+#endif

+ 140 - 0
flow/SeqPacketSocketSource.c

@@ -0,0 +1,140 @@
+/**
+ * @file SeqPacketSocketSource.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/debug.h>
+
+#include <flow/SeqPacketSocketSource.h>
+
+static void report_error (SeqPacketSocketSource *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 (SeqPacketSocketSource *s, uint8_t *data, int *data_len)
+{
+    ASSERT(!s->out_have)
+    ASSERT(!s->in_error)
+    DebugObject_Access(&s->d_obj);
+    
+    int res = BSocket_Recv(s->bsock, data, s->mtu);
+    if (res < 0) {
+        int error = BSocket_GetError(s->bsock);
+        if (error == BSOCKET_ERROR_LATER) {
+            s->out_have = 1;
+            s->out = data;
+            BSocket_EnableEvent(s->bsock, BSOCKET_READ);
+            return 0;
+        }
+        report_error(s, SEQPACKETSOCKETSOURCE_ERROR_BSOCKET);
+        return -1;
+    }
+    
+    *data_len = res;
+    return 1;
+}
+
+static void socket_handler (SeqPacketSocketSource *s, int event)
+{
+    ASSERT(s->out_have)
+    ASSERT(event == BSOCKET_READ)
+    ASSERT(!s->in_error)
+    DebugObject_Access(&s->d_obj);
+    
+    int res = BSocket_Recv(s->bsock, s->out, s->mtu);
+    if (res < 0) {
+        int error = BSocket_GetError(s->bsock);
+        if (error == BSOCKET_ERROR_LATER) {
+            // nothing to receive, continue in socket_handler
+            return;
+        }
+        report_error(s, SEQPACKETSOCKETSOURCE_ERROR_BSOCKET);
+        return;
+    }
+    
+    BSocket_DisableEvent(s->bsock, BSOCKET_READ);
+    s->out_have = 0;
+    
+    PacketRecvInterface_Done(&s->output, res);
+    return;
+}
+
+void SeqPacketSocketSource_Init (SeqPacketSocketSource *s, FlowErrorReporter rep, BSocket *bsock, int mtu)
+{
+    ASSERT(mtu >= 0)
+    
+    // init arguments
+    s->rep = rep;
+    s->bsock = bsock;
+    s->mtu = mtu;
+    
+    // init dead var
+    DEAD_INIT(s->dead);
+    
+    // add socket event handler
+    BSocket_AddEventHandler(s->bsock, BSOCKET_READ, (BSocket_handler)socket_handler, s);
+    
+    // init output
+    PacketRecvInterface_Init(&s->output, mtu, (PacketRecvInterface_handler_recv)output_handler_recv, s);
+    
+    // have no output packet
+    s->out_have = 0;
+    
+    // init debugging
+    #ifndef NDEBUG
+    s->in_error = 0;
+    #endif
+    
+    DebugObject_Init(&s->d_obj);
+}
+
+void SeqPacketSocketSource_Free (SeqPacketSocketSource *s)
+{
+    DebugObject_Free(&s->d_obj);
+
+    // free output
+    PacketRecvInterface_Free(&s->output);
+    
+    // remove socket event handler
+    BSocket_RemoveEventHandler(s->bsock, BSOCKET_READ);
+    
+    // free dead var
+    DEAD_KILL(s->dead);
+}
+
+PacketRecvInterface * SeqPacketSocketSource_GetOutput (SeqPacketSocketSource *s)
+{
+    DebugObject_Access(&s->d_obj);
+    
+    return &s->output;
+}

+ 85 - 0
flow/SeqPacketSocketSource.h

@@ -0,0 +1,85 @@
+/**
+ * @file SeqPacketSocketSource.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 PacketRecvInterface} source which receives packets from a seqpacket socket.
+ */
+
+#ifndef BADVPN_FLOW_SEQPACKETSOCKETSOURCE_H
+#define BADVPN_FLOW_SEQPACKETSOCKETSOURCE_H
+
+#include <misc/dead.h>
+#include <system/DebugObject.h>
+#include <system/BSocket.h>
+#include <flow/error.h>
+#include <flow/PacketRecvInterface.h>
+
+#define SEQPACKETSOCKETSOURCE_ERROR_BSOCKET 1
+
+/**
+ * A {@link PacketRecvInterface} source which receives packets from a seqpacket socket.
+ */
+typedef struct {
+    DebugObject d_obj;
+    dead_t dead;
+    FlowErrorReporter rep;
+    BSocket *bsock;
+    int mtu;
+    PacketRecvInterface output;
+    int out_have;
+    uint8_t *out;
+    #ifndef NDEBUG
+    int in_error;
+    #endif
+} SeqPacketSocketSource;
+
+/**
+ * Initializes the object.
+ *
+ * @param s the object
+ * @param rep error reporting data. Error code is an int. Possible error codes:
+ *              - SEQPACKETSOCKETSOURCE_ERROR_BSOCKET: {@link BSocket_Recv} failed
+ *                with an unhandled error code
+ *            The object must be freed from the error handler.
+ * @param bsock socket to read data from. The BSOCKET_READ event must be disabled.
+ * *            Takes over reading on the socket.
+ * @param mtu maximum packet size. Must be >=0.
+ */
+void SeqPacketSocketSource_Init (SeqPacketSocketSource *s, FlowErrorReporter rep, BSocket *bsock, int mtu);
+
+/**
+ * Frees the object.
+ *
+ * @param s the object
+ */
+void SeqPacketSocketSource_Free (SeqPacketSocketSource *s);
+
+/**
+ * Returns the output interface.
+ * The MTU of the interface will be as in {@link SeqPacketSocketSource_Init}.
+ *
+ * @param s the object
+ * @return output interface
+ */
+PacketRecvInterface * SeqPacketSocketSource_GetOutput (SeqPacketSocketSource *s);
+
+#endif