]> git.meshlink.io Git - meshlink-tiny/commitdiff
Remove all support for channels.
authorGuus Sliepen <guus@meshlink.io>
Mon, 21 Jun 2021 21:13:50 +0000 (23:13 +0200)
committerGuus Sliepen <guus@meshlink.io>
Tue, 22 Jun 2021 19:45:41 +0000 (21:45 +0200)
Also, only allow communication with the peer we have a connection to.
Instead of using an inner SPTPS session, just send raw packets directly
over the meta-connection.

25 files changed:
src/Makefile.am
src/connection.h
src/devtools.c
src/meshlink-tiny++.h
src/meshlink-tiny.h
src/meshlink.c
src/meshlink_internal.h
src/meta.c
src/net.c
src/net.h
src/net_packet.c [deleted file]
src/net_setup.c
src/node.c
src/node.h
src/protocol.c
src/protocol.h
src/protocol_auth.c
src/protocol_key.c
src/protocol_misc.c
src/route.c [deleted file]
src/route.h [deleted file]
src/utcp-test.c [deleted file]
src/utcp.c [deleted file]
src/utcp.h [deleted file]
src/utcp_priv.h [deleted file]

index af1d51c407efc14e26bec14aa414b7a9ed1371d2..bcd138e7589c231524eec01d64f42e13c72864f0 100644 (file)
@@ -25,12 +25,7 @@ chacha_poly1305_SOURCES = \
        chacha-poly1305/chacha-poly1305.c chacha-poly1305/chacha-poly1305.h \
        chacha-poly1305/poly1305.c chacha-poly1305/poly1305.h
 
-utcp_SOURCES = \
-       utcp.c utcp.h \
-       utcp_priv.h
-
 lib_LTLIBRARIES = libmeshlink-tiny.la
-EXTRA_PROGRAMS = utcp-test
 
 pkginclude_HEADERS = meshlink-tiny++.h meshlink-tiny.h
 
@@ -55,7 +50,6 @@ libmeshlink_tiny_la_SOURCES = \
        meshlink_queue.h \
        meta.c meta.h \
        net.c net.h \
-       net_packet.c \
        net_setup.c \
        net_socket.c \
        netutl.c netutl.h \
@@ -67,7 +61,6 @@ libmeshlink_tiny_la_SOURCES = \
        protocol_edge.c \
        protocol_key.c \
        protocol_misc.c \
-       route.c route.h \
        sockaddr.h \
        splay_tree.c splay_tree.h \
        sptps.c sptps.h \
@@ -77,17 +70,9 @@ libmeshlink_tiny_la_SOURCES = \
        xoshiro.c xoshiro.h \
        devtools.c devtools.h \
        $(ed25519_SOURCES) \
-       $(chacha_poly1305_SOURCES) \
-       $(utcp_SOURCES)
-
-utcp_test_SOURCES = \
-       utcp-test.c \
-       $(utcp_SOURCES)
+       $(chacha_poly1305_SOURCES)
 
 EXTRA_libmeshlink_tiny_la_DEPENDENCIES = $(srcdir)/meshlink.sym
 
 libmeshlink_tiny_la_CFLAGS = $(PTHREAD_CFLAGS) -fPIC -iquote.
 libmeshlink_tiny_la_LDFLAGS += $(PTHREAD_LIBS)
-
-utcp_test_CFLAGS = $(PTHREAD_CFLAGS) -iquote.
-utcp_test_LDFLAGS = $(PTHREAD_LIBS)
index d414e83d063f55ec7eb5b40eb7dd30a8ad9bdb97..b191896ffe64455e678a8a5ca100c72839b4152b 100644 (file)
@@ -41,6 +41,7 @@ typedef struct connection_status_t {
        uint16_t invitation: 1;             /* 1 if this is an invitation */
        uint16_t invitation_used: 1;        /* 1 if the invitation has been consumed */
        uint16_t initiator: 1;              /* 1 if we initiated this connection */
+       uint16_t raw_packet: 1;             /* 1 if we are expecting a raw packet next */
 } connection_status_t;
 
 #include "ecdsa.h"
@@ -63,6 +64,7 @@ typedef struct connection_t {
        struct buffer_t outbuf;
        io_t io;                        /* input/output event on this metadata connection */
        int allow_request;              /* defined if there's only one request possible */
+       uint16_t packet_len;            /* length of a raw packet being received */
        time_t last_ping_time;          /* last time we saw some activity from the other end or pinged them */
        time_t last_key_renewal;        /* last time we renewed the SPTPS key */
 
index 1b08d420197460e912322f6f05b684aa2251366d..1a647210420484c82fe4c80088d129c24f41ab3c 100644 (file)
@@ -79,8 +79,6 @@ void devtool_force_sptps_renewal(meshlink_handle_t *mesh, meshlink_node_t *node)
        node_t *n = (node_t *)node;
        connection_t *c = n->connection;
 
-       n->last_req_key = -3600;
-
        if(c) {
                c->last_key_renewal = -3600;
        }
index cfcf2b946fe95b03a1563eb8996e766a04cfe61c..4793ea0f198704d05eb02259f5f4ccf223568157 100644 (file)
@@ -26,7 +26,6 @@
 namespace meshlink {
 class mesh;
 class node;
-class channel;
 
 /// Severity of log messages generated by MeshLink.
 typedef meshlink_log_level_t log_level_t;
@@ -70,58 +69,10 @@ typedef void (*duplicate_cb_t)(mesh *mesh, node *node);
  */
 typedef void (*log_cb_t)(mesh *mesh, log_level_t level, const char *text);
 
-/// A callback for listening for incoming channels.
-/** @param mesh         A handle which represents an instance of MeshLink.
- *  @param node         A handle for the node that wants to open a channel.
- *  @param port         The port number the peer wishes to connect to.
- *
- *  @return             This function should return true if the application listens for the incoming channel, false otherwise.
- */
-typedef bool (*meshlink_channel_listen_cb_t)(struct meshlink_handle *mesh, struct meshlink_node *node, uint16_t port);
-
-/// A callback for accepting incoming channels.
-/** @param mesh         A handle which represents an instance of MeshLink.
- *  @param channel      A handle for the incoming channel.
- *  @param port         The port number the peer wishes to connect to.
- *  @param data         A pointer to a buffer containing data already received. (Not yet used.)
- *  @param len          The length of the data. (Not yet used.)
- *
- *  @return             This function should return true if the application accepts the incoming channel, false otherwise.
- *                      If returning false, the channel is invalid and may not be used anymore.
- */
-typedef bool (*channel_accept_cb_t)(mesh *mesh, channel *channel, uint16_t port, const void *data, size_t len);
-
-/// A callback for receiving data from a channel.
-/** @param mesh         A handle which represents an instance of MeshLink.
- *  @param channel      A handle for the channel.
- *  @param data         A pointer to a buffer containing data sent by the source.
- *  @param len          The length of the data.
- */
-typedef void (*channel_receive_cb_t)(mesh *mesh, channel *channel, const void *data, size_t len);
-
-/// A callback that is called when data can be send on a channel.
-/** @param mesh         A handle which represents an instance of MeshLink.
- *  @param channel      A handle for the channel.
- *  @param len          The maximum length of data that is guaranteed to be accepted by a call to channel_send().
- */
-typedef void (*channel_poll_cb_t)(mesh *mesh, channel *channel, size_t len);
-
 /// A class describing a MeshLink node.
 class node: public meshlink_node_t {
 };
 
-/// A class describing a MeshLink channel.
-class channel: public meshlink_channel_t {
-public:
-       static const uint32_t RELIABLE = MESHLINK_CHANNEL_RELIABLE;
-       static const uint32_t ORDERED = MESHLINK_CHANNEL_ORDERED;
-       static const uint32_t FRAMED = MESHLINK_CHANNEL_FRAMED;
-       static const uint32_t DROP_LATE = MESHLINK_CHANNEL_DROP_LATE;
-       static const uint32_t NO_PARTIAL = MESHLINK_CHANNEL_NO_PARTIAL;
-       static const uint32_t TCP = MESHLINK_CHANNEL_TCP;
-       static const uint32_t UDP = MESHLINK_CHANNEL_UDP;
-};
-
 /// A class describing a MeshLink mesh.
 class mesh {
 public:
@@ -237,87 +188,6 @@ public:
                (void)peer;
        }
 
-       /// This functions is called to determine if we are listening for incoming channels.
-       /**
-        *  The function is run in MeshLink's own thread.
-        *  It is therefore important that the callback uses apprioriate methods (queues, pipes, locking, etc.)
-        *  to pass data to or from the application's thread.
-        *  The callback should also not block itself and return as quickly as possible.
-        *
-        *  @param node         A handle for the node that wants to open a channel.
-        *  @param port         The port number the peer wishes to connect to.
-        *
-        *  @return             This function should return true if the application accepts the incoming channel, false otherwise.
-        */
-       virtual bool channel_listen(node *node, uint16_t port) {
-               /* by default accept all channels */
-               (void)node;
-               (void)port;
-               return true;
-       }
-
-       /// This functions is called whenever another node attempts to open a channel to the local node.
-       /**
-        *  If the channel is accepted, the poll_callback will be set to channel_poll and can be
-        *  changed using set_channel_poll_cb(). Likewise, the receive callback is set to
-        *  channel_receive().
-        *
-        *  The function is run in MeshLink's own thread.
-        *  It is therefore important that the callback uses apprioriate methods (queues, pipes, locking, etc.)
-        *  to pass data to or from the application's thread.
-        *  The callback should also not block itself and return as quickly as possible.
-        *
-        *  @param channel      A handle for the incoming channel.
-        *  @param port         The port number the peer wishes to connect to.
-        *  @param data         A pointer to a buffer containing data already received. (Not yet used.)
-        *  @param len          The length of the data. (Not yet used.)
-        *
-        *  @return             This function should return true if the application accepts the incoming channel, false otherwise.
-        *                      If returning false, the channel is invalid and may not be used anymore.
-        */
-       virtual bool channel_accept(channel *channel, uint16_t port, const void *data, size_t len) {
-               /* by default reject all channels */
-               (void)channel;
-               (void)port;
-               (void)data;
-               (void)len;
-               return false;
-       }
-
-       /// This function is called by Meshlink for receiving data from a channel.
-       /**
-        *  The function is run in MeshLink's own thread.
-        *  It is therefore important that the callback uses apprioriate methods (queues, pipes, locking, etc.)
-        *  to pass data to or from the application's thread.
-        *  The callback should also not block itself and return as quickly as possible.
-        *
-        *  @param channel      A handle for the channel.
-        *  @param data         A pointer to a buffer containing data sent by the source.
-        *  @param len          The length of the data.
-        */
-       virtual void channel_receive(channel *channel, const void *data, size_t len) {
-               /* do nothing */
-               (void)channel;
-               (void)data;
-               (void)len;
-       }
-
-       /// This function is called by Meshlink when data can be send on a channel.
-       /**
-        *  The function is run in MeshLink's own thread.
-        *  It is therefore important that the callback uses apprioriate methods (queues, pipes, locking, etc.)
-        *  to pass data to or from the application's thread.
-        *
-        *  The callback should also not block itself and return as quickly as possible.
-        *  @param channel      A handle for the channel.
-        *  @param len          The maximum length of data that is guaranteed to be accepted by a call to channel_send().
-        */
-       virtual void channel_poll(channel *channel, size_t len) {
-               /* do nothing */
-               (void)channel;
-               (void)len;
-       }
-
        /// Start MeshLink.
        /** This function causes MeshLink to open network sockets, make outgoing connections, and
         *  create a new thread, which will handle all network I/O.
@@ -330,8 +200,6 @@ public:
                meshlink_set_node_duplicate_cb(handle, &node_duplicate_trampoline);
                meshlink_set_log_cb(handle, MESHLINK_DEBUG, &log_trampoline);
                meshlink_set_error_cb(handle, &error_trampoline);
-               meshlink_set_channel_listen_cb(handle, &channel_listen_trampoline);
-               meshlink_set_channel_accept_cb(handle, &channel_accept_trampoline);
                meshlink_set_connection_try_cb(handle, &connection_try_trampoline);
                return meshlink_start(handle);
        }
@@ -542,8 +410,6 @@ public:
        /** This function allows the local node to forget any information it has about a node,
         *  and if possible will remove any data it has stored on disk about the node.
         *
-        *  Any open channels to this node must be closed before calling this function.
-        *
         *  After this call returns, the node handle is invalid and may no longer be used, regardless
         *  of the return value of this call.
         *
@@ -561,144 +427,6 @@ public:
                return meshlink_forget_node(handle, node);
        }
 
-       /// Set the flags of a channel.
-       /** This function allows changing some of the channel flags.
-        *  Currently only MESHLINK_CHANNEL_NO_PARTIAL and MESHLINK_CHANNEL_DROP_LATE are supported, other flags are ignored.
-        *  These flags only affect the local side of the channel with the peer.
-        *  The changes take effect immediately.
-        *
-        *  @param channel   A handle for the channel.
-        *  @param flags     A bitwise-or'd combination of flags that set the semantics for this channel.
-        */
-       void set_channel_flags(channel *channel, uint32_t flags) {
-               meshlink_set_channel_flags(handle, channel, flags);
-       }
-
-       /// Set the connection timeout used for channels to the given node.
-       /** This sets the timeout after which unresponsive channels will be reported as closed.
-        *  The timeout is set for all current and future channels to the given node.
-        *
-        *  @param node         The node to set the channel timeout for.
-        *  @param timeout      The timeout in seconds after which unresponsive channels will be reported as closed.
-        *                      The default is 60 seconds.
-        */
-       void set_node_channel_timeout(node *node, int timeout) {
-               meshlink_set_node_channel_timeout(handle, node, timeout);
-       }
-
-       /// Open a reliable stream channel to another node.
-       /** This function is called whenever a remote node wants to open a channel to the local node.
-        *  The application then has to decide whether to accept or reject this channel.
-        *
-        *  This function sets the channel poll callback to channel_poll_trampoline, which in turn
-        *  calls channel_poll. To set a different, channel-specific poll callback, use set_channel_poll_cb.
-        *
-        *  @param node         The node to which this channel is being initiated.
-        *  @param port         The port number the peer wishes to connect to.
-        *  @param cb           A pointer to the function which will be called when the remote node sends data to the local node.
-        *  @param data         A pointer to a buffer containing data to already queue for sending.
-        *  @param len          The length of the data.
-        *                      If len is 0, the data pointer is copied into the channel's priv member.
-        *  @param flags        A bitwise-or'd combination of flags that set the semantics for this channel.
-        *
-        *  @return             A handle for the channel, or NULL in case of an error.
-        */
-       channel *channel_open(node *node, uint16_t port, channel_receive_cb_t cb, const void *data, size_t len, uint32_t flags = channel::TCP) {
-               channel *ch = (channel *)meshlink_channel_open_ex(handle, node, port, (meshlink_channel_receive_cb_t)cb, data, len, flags);
-               return ch;
-       }
-
-       /// Open a reliable stream channel to another node.
-       /** This function is called whenever a remote node wants to open a channel to the local node.
-        *  The application then has to decide whether to accept or reject this channel.
-        *
-        *  This function sets the channel receive callback to channel_receive_trampoline,
-        *  which in turn calls channel_receive.
-        *
-        *  This function sets the channel poll callback to channel_poll_trampoline, which in turn
-        *  calls channel_poll. To set a different, channel-specific poll callback, use set_channel_poll_cb.
-        *
-        *  @param node         The node to which this channel is being initiated.
-        *  @param port         The port number the peer wishes to connect to.
-        *  @param data         A pointer to a buffer containing data to already queue for sending.
-        *  @param len          The length of the data.
-        *                      If len is 0, the data pointer is copied into the channel's priv member.
-        *  @param flags        A bitwise-or'd combination of flags that set the semantics for this channel.
-        *
-        *  @return             A handle for the channel, or NULL in case of an error.
-        */
-       channel *channel_open(node *node, uint16_t port, const void *data, size_t len, uint32_t flags = channel::TCP) {
-               channel *ch = (channel *)meshlink_channel_open_ex(handle, node, port, &channel_receive_trampoline, data, len, flags);
-               return ch;
-       }
-
-       /// Partially close a reliable stream channel.
-       /** This shuts down the read or write side of a channel, or both, without closing the handle.
-        *  It can be used to inform the remote node that the local node has finished sending all data on the channel,
-        *  but still allows waiting for incoming data from the remote node.
-        *
-        *  @param channel      A handle for the channel.
-        *  @param direction    Must be one of SHUT_RD, SHUT_WR or SHUT_RDWR.
-        */
-       void channel_shutdown(channel *channel, int direction) {
-               return meshlink_channel_shutdown(handle, channel, direction);
-       }
-
-       /// Close a reliable stream channel.
-       /** This informs the remote node that the local node has finished sending all data on the channel.
-        *  It also causes the local node to stop accepting incoming data from the remote node.
-        *  Afterwards, the channel handle is invalid and must not be used any more.
-        *
-        *  It is allowed to call this function at any time on a valid handle, even inside callback functions.
-        *  If called with a valid handle, this function always succeeds, otherwise the result is undefined.
-        *
-        *  @param channel      A handle for the channel.
-        */
-       void channel_close(meshlink_channel_t *channel) {
-               return meshlink_channel_close(handle, channel);
-       }
-
-       /// Abort a reliable stream channel.
-       /** This aborts a channel.
-        *  Data that was in the send and receive buffers is dropped, so potentially there is some data that
-        *  was sent on this channel that will not be received by the peer.
-        *  Afterwards, the channel handle is invalid and must not be used any more.
-        *
-        *  It is allowed to call this function at any time on a valid handle, even inside callback functions.
-        *  If called with a valid handle, this function always succeeds, otherwise the result is undefined.
-        *
-        *  @param channel      A handle for the channel.
-        */
-       void channel_abort(meshlink_channel_t *channel) {
-               return meshlink_channel_abort(handle, channel);
-       }
-
-       /// Transmit data on a channel
-       /** This queues data to send to the remote node.
-        *
-        *  @param channel      A handle for the channel.
-        *  @param data         A pointer to a buffer containing data sent by the source.
-        *  @param len          The length of the data.
-        *
-        *  @return             The amount of data that was queued, which can be less than len, or a negative value in case of an error.
-        *                      If MESHLINK_CHANNEL_NO_PARTIAL is set, then the result will either be len,
-        *                      0 if the buffer is currently too full, or -1 if len is too big even for an empty buffer.
-        */
-       ssize_t channel_send(channel *channel, void *data, size_t len) {
-               return meshlink_channel_send(handle, channel, data, len);
-       }
-
-       /// Get the maximum segment size of a channel.
-       /** This returns the amount of bytes that can be sent at once for channels with UDP semantics.
-        *
-        *  @param channel      A handle for the channel.
-        *
-        *  @return             The amount of bytes in the receive buffer.
-        */
-       size_t channel_get_mss(channel *channel) {
-               return meshlink_channel_get_mss(handle, channel);
-       };
-
        /// Inform MeshLink that the local network configuration might have changed
        /** This is intended to be used when there is no way for MeshLink to get notifications of local network changes.
         *  It forces MeshLink to scan all network interfaces for changes in up/down status and new/removed addresses,
@@ -812,48 +540,6 @@ private:
                that->connection_try(static_cast<node *>(peer));
        }
 
-       static bool channel_listen_trampoline(meshlink_handle_t *handle, meshlink_node_t *node, uint16_t port) {
-               if(!(handle->priv)) {
-                       return false;
-               }
-
-               meshlink::mesh *that = static_cast<mesh *>(handle->priv);
-               return that->channel_listen(static_cast<meshlink::node *>(node), port);
-       }
-
-       static bool channel_accept_trampoline(meshlink_handle_t *handle, meshlink_channel *channel, uint16_t port, const void *data, size_t len) {
-               if(!(handle->priv)) {
-                       return false;
-               }
-
-               meshlink::mesh *that = static_cast<mesh *>(handle->priv);
-               bool accepted = that->channel_accept(static_cast<meshlink::channel *>(channel), port, data, len);
-
-               if(accepted) {
-                       meshlink_set_channel_receive_cb(handle, channel, &channel_receive_trampoline);
-               }
-
-               return accepted;
-       }
-
-       static void channel_receive_trampoline(meshlink_handle_t *handle, meshlink_channel *channel, const void *data, size_t len) {
-               if(!(handle->priv)) {
-                       return;
-               }
-
-               meshlink::mesh *that = static_cast<mesh *>(handle->priv);
-               that->channel_receive(static_cast<meshlink::channel *>(channel), data, len);
-       }
-
-       static void channel_poll_trampoline(meshlink_handle_t *handle, meshlink_channel *channel, size_t len) {
-               if(!(handle->priv)) {
-                       return;
-               }
-
-               meshlink::mesh *that = static_cast<mesh *>(handle->priv);
-               that->channel_poll(static_cast<meshlink::channel *>(channel), len);
-       }
-
        meshlink_handle_t *handle;
 };
 
index 8ba8addd43e279316a6a665b7edb97c39cb5b19b..5cb9c5edeec73b70629028d8c7378a15150eb17c 100644 (file)
@@ -48,9 +48,6 @@ typedef struct meshlink_handle meshlink_handle_t;
 /// A handle for a MeshLink node.
 typedef struct meshlink_node meshlink_node_t;
 
-/// A handle for a MeshLink channel.
-typedef struct meshlink_channel meshlink_channel_t;
-
 /// A struct containing all parameters used for opening a mesh.
 typedef struct meshlink_open_params meshlink_open_params_t;
 
@@ -94,15 +91,6 @@ static const uint32_t MESHLINK_INVITE_IPV4 = 4;     // Only use IPv4 addresses i
 static const uint32_t MESHLINK_INVITE_IPV6 = 8;     // Only use IPv6 addresses in the URL
 static const uint32_t MESHLINK_INVITE_NUMERIC = 16; // Don't look up hostnames
 
-/// Channel flags
-static const uint32_t MESHLINK_CHANNEL_RELIABLE = 1;   // Data is retransmitted when packets are lost.
-static const uint32_t MESHLINK_CHANNEL_ORDERED = 2;    // Data is delivered in-order to the application.
-static const uint32_t MESHLINK_CHANNEL_FRAMED = 4;     // Data is delivered in chunks of the same length as data was originally sent.
-static const uint32_t MESHLINK_CHANNEL_DROP_LATE = 8;  // When packets are reordered, late packets are ignored.
-static const uint32_t MESHLINK_CHANNEL_NO_PARTIAL = 16; // Calls to meshlink_channel_send() will either send all data or nothing.
-static const uint32_t MESHLINK_CHANNEL_TCP = 3;        // Select TCP semantics.
-static const uint32_t MESHLINK_CHANNEL_UDP = 0;        // Select UDP semantics.
-
 /// A variable holding the last encountered error from MeshLink.
 /** This is a thread local variable that contains the error code of the most recent error
  *  encountered by a MeshLink API function called in the current thread.
@@ -123,11 +111,6 @@ struct meshlink_node {
        void *priv;             ///< Private pointer which may be set freely by the application, and is never used or modified by MeshLink.
 };
 
-struct meshlink_channel {
-       struct meshlink_node *const node; ///< Pointer to the peer of this channel.
-       void *priv;                       ///< Private pointer which may be set freely by the application, and is never used or modified by MeshLink.
-};
-
 #endif // MESHLINK_INTERNAL_H
 
 /// Get the text for the given MeshLink error code.
@@ -333,7 +316,6 @@ bool meshlink_start(struct meshlink_handle *mesh) __attribute__((__warn_unused_r
  *  close all sockets, and shut down its own thread.
  *
  *  This function always succeeds. It is allowed to call meshlink_stop() even if MeshLink is already stopped or has never been started.
- *  Channels that are still open will remain valid, but any communication via channels will stop as well.
  *
  *  \memberof meshlink_handle
  *  @param mesh     A handle which represents an instance of MeshLink.
@@ -342,8 +324,8 @@ void meshlink_stop(struct meshlink_handle *mesh);
 
 /// Close the MeshLink handle.
 /** This function calls meshlink_stop() if necessary,
- *  and frees the struct meshlink_handle and all associacted memory allocated by MeshLink, including all channels.
- *  Afterwards, the handle and any pointers to a struct meshlink_node or struct meshlink_channel are invalid.
+ *  and frees the struct meshlink_handle and all associacted memory allocated by MeshLink.
+ *  Afterwards, the handle and any pointers to a struct meshlink_node are invalid.
  *
  *  It is allowed to call this function at any time on a valid handle, except inside callback functions.
  *  If called at a proper time with a valid handle, this function always succeeds.
@@ -816,8 +798,6 @@ bool meshlink_import(struct meshlink_handle *mesh, const char *data) __attribute
 /** This function allows the local node to forget any information it has about a node,
  *  and if possible will remove any data it has stored on disk about the node.
  *
- *  Any open channels to this node must be closed before calling this function.
- *
  *  After this call returns, the node handle is invalid and may no longer be used, regardless
  *  of the return value of this call.
  *
@@ -834,269 +814,6 @@ bool meshlink_import(struct meshlink_handle *mesh, const char *data) __attribute
  */
 bool meshlink_forget_node(struct meshlink_handle *mesh, struct meshlink_node *node);
 
-/// A callback for listening for incoming channels.
-/** This function is called whenever a remote node wants to open a channel to the local node.
- *  This callback should only make a decision whether to accept or reject this channel.
- *  The accept callback should be set to get a handle to the actual channel.
- *
- *  The callback is run in MeshLink's own thread.
- *  It is therefore important that the callback return quickly and uses apprioriate methods (queues, pipes, locking, etc.)
- *  to hand any data over to the application's thread.
- *
- *  @param mesh         A handle which represents an instance of MeshLink.
- *  @param node         A handle for the node that wants to open a channel.
- *  @param port         The port number the peer wishes to connect to.
- *
- *  @return             This function should return true if the application accepts the incoming channel, false otherwise.
- */
-typedef bool (*meshlink_channel_listen_cb_t)(struct meshlink_handle *mesh, struct meshlink_node *node, uint16_t port);
-
-/// A callback for accepting incoming channels.
-/** This function is called whenever a remote node has opened a channel to the local node.
- *
- *  The callback is run in MeshLink's own thread.
- *  It is therefore important that the callback return quickly and uses apprioriate methods (queues, pipes, locking, etc.)
- *  to hand any data over to the application's thread.
- *
- *  @param mesh         A handle which represents an instance of MeshLink.
- *  @param channel      A handle for the incoming channel.
- *                      If the application accepts the incoming channel by returning true,
- *                      then this handle is valid until meshlink_channel_close() is called on it.
- *                      If the application rejects the incoming channel by returning false,
- *                      then this handle is invalid after the callback returns
- *                      (the callback does not need to call meshlink_channel_close() itself in this case).
- *  @param port         The port number the peer wishes to connect to.
- *  @param data         A pointer to a buffer containing data already received, or NULL in case no data has been received yet. (Not yet used.)
- *                      The pointer is only valid during the lifetime of the callback.
- *                      The callback should mempcy() the data if it needs to be available outside the callback.
- *  @param len          The length of the data, or 0 in case no data has been received yet. (Not yet used.)
- *
- *  @return             This function should return true if the application accepts the incoming channel, false otherwise.
- *                      If returning false, the channel is invalid and may not be used anymore.
- */
-typedef bool (*meshlink_channel_accept_cb_t)(struct meshlink_handle *mesh, struct meshlink_channel *channel, uint16_t port, const void *data, size_t len);
-
-/// A callback for receiving data from a channel.
-/** This function is called whenever data is received from a remote node on a channel.
- *
- *  This function is also called in case the channel has been closed by the remote node, or when the channel is terminated abnormally.
- *  In both cases, @a data will be NULL and @a len will be 0, and meshlink_errno will be set.
- *  In any case, the @a channel handle will still be valid until the application calls meshlink_close().
- *
- *  @param mesh         A handle which represents an instance of MeshLink.
- *  @param channel      A handle for the channel.
- *  @param data         A pointer to a buffer containing data sent by the source, or NULL in case of an error.
- *                      The pointer is only valid during the lifetime of the callback.
- *                      The callback should mempcy() the data if it needs to be available outside the callback.
- *  @param len          The length of the data, or 0 in case of an error.
- */
-typedef void (*meshlink_channel_receive_cb_t)(struct meshlink_handle *mesh, struct meshlink_channel *channel, const void *data, size_t len);
-
-/// Set the listen callback.
-/** This functions sets the callback that is called whenever another node wants to open a channel to the local node.
- *  The callback is run in MeshLink's own thread.
- *  It is therefore important that the callback uses apprioriate methods (queues, pipes, locking, etc.)
- *  to hand the data over to the application's thread.
- *  The callback should also not block itself and return as quickly as possible.
- *
- *  If no listen or accept callbacks are set, incoming channels are rejected.
- *
- *  \memberof meshlink_handle
- *  @param mesh      A handle which represents an instance of MeshLink.
- *  @param cb        A pointer to the function which will be called when another node want to open a channel.
- *                   If a NULL pointer is given, the callback will be disabled.
- */
-void meshlink_set_channel_listen_cb(struct meshlink_handle *mesh, meshlink_channel_listen_cb_t cb);
-
-/// Set the accept callback.
-/** This functions sets the callback that is called whenever a remote node has opened a channel to the local node.
- *  The callback is run in MeshLink's own thread.
- *  It is therefore important that the callback uses apprioriate methods (queues, pipes, locking, etc.)
- *  to hand the data over to the application's thread.
- *  The callback should also not block itself and return as quickly as possible.
- *
- *  If no listen or accept callbacks are set, incoming channels are rejected.
- *
- *  \memberof meshlink_handle
- *  @param mesh      A handle which represents an instance of MeshLink.
- *  @param cb        A pointer to the function which will be called when a new channel has been opened by a remote node.
- *                   If a NULL pointer is given, the callback will be disabled.
- */
-void meshlink_set_channel_accept_cb(struct meshlink_handle *mesh, meshlink_channel_accept_cb_t cb);
-
-/// Set the receive callback.
-/** This functions sets the callback that is called whenever another node sends data to the local node.
- *  The callback is run in MeshLink's own thread.
- *  It is therefore important that the callback uses apprioriate methods (queues, pipes, locking, etc.)
- *  to hand the data over to the application's thread.
- *  The callback should also not block itself and return as quickly as possible.
- *
- *  \memberof meshlink_channel
- *  @param mesh      A handle which represents an instance of MeshLink.
- *  @param channel   A handle for the channel.
- *  @param cb        A pointer to the function which will be called when another node sends data to the local node.
- *                   If a NULL pointer is given, the callback will be disabled and incoming data is ignored.
- */
-void meshlink_set_channel_receive_cb(struct meshlink_handle *mesh, struct meshlink_channel *channel, meshlink_channel_receive_cb_t cb);
-
-/// Set the flags of a channel.
-/** This function allows changing some of the channel flags.
- *  Currently only MESHLINK_CHANNEL_NO_PARTIAL and MESHLINK_CHANNEL_DROP_LATE are supported, other flags are ignored.
- *  These flags only affect the local side of the channel with the peer.
- *  The changes take effect immediately.
- *
- *  \memberof meshlink_channel
- *  @param mesh      A handle which represents an instance of MeshLink.
- *  @param channel   A handle for the channel.
- *  @param flags     A bitwise-or'd combination of flags that set the semantics for this channel.
- */
-void meshlink_set_channel_flags(struct meshlink_handle *mesh, struct meshlink_channel *channel, uint32_t flags);
-
-/// Open a reliable stream channel to another node.
-/** This function is called whenever a remote node wants to open a channel to the local node.
- *  The application then has to decide whether to accept or reject this channel.
- *
- *  This function returns a pointer to a struct meshlink_channel that will be allocated by MeshLink.
- *  When the application does no longer need to use this channel, it must call meshlink_close()
- *  to free its resources.
- *
- *  \memberof meshlink_node
- *  @param mesh         A handle which represents an instance of MeshLink.
- *  @param node         The node to which this channel is being initiated.
- *  @param port         The port number the peer wishes to connect to.
- *  @param cb           A pointer to the function which will be called when the remote node sends data to the local node.
- *                      The pointer may be NULL, in which case incoming data is ignored.
- *  @param data         A pointer to a buffer containing data to already queue for sending, or NULL if there is no data to send.
- *                      After meshlink_send() returns, the application is free to overwrite or free this buffer.
- *                      If len is 0, the data pointer is copied into the channel's priv member.
- *  @param len          The length of the data, or 0 if there is no data to send.
- *  @param flags        A bitwise-or'd combination of flags that set the semantics for this channel.
- *
- *  @return             A handle for the channel, or NULL in case of an error.
- *                      The handle is valid until meshlink_channel_close() is called.
- */
-struct meshlink_channel *meshlink_channel_open_ex(struct meshlink_handle *mesh, struct meshlink_node *node, uint16_t port, meshlink_channel_receive_cb_t cb, const void *data, size_t len, uint32_t flags) __attribute__((__warn_unused_result__));
-
-/// Open a reliable stream channel to another node.
-/** This function is called whenever a remote node wants to open a channel to the local node.
- *  The application then has to decide whether to accept or reject this channel.
- *
- *  This function returns a pointer to a struct meshlink_channel that will be allocated by MeshLink.
- *  When the application does no longer need to use this channel, it must call meshlink_close()
- *  to free its resources.
- *
- *  Calling this function is equivalent to calling meshlink_channel_open_ex()
- *  with the flags set to MESHLINK_CHANNEL_TCP.
- *
- *  \memberof meshlink_node
- *  @param mesh         A handle which represents an instance of MeshLink.
- *  @param node         The node to which this channel is being initiated.
- *  @param port         The port number the peer wishes to connect to.
- *  @param cb           A pointer to the function which will be called when the remote node sends data to the local node.
- *                      The pointer may be NULL, in which case incoming data is ignored.
- *  @param data         A pointer to a buffer containing data to already queue for sending, or NULL if there is no data to send.
- *                      After meshlink_send() returns, the application is free to overwrite or free this buffer.
- *  @param len          The length of the data, or 0 if there is no data to send.
- *                      If len is 0, the data pointer is copied into the channel's priv member.
- *
- *  @return             A handle for the channel, or NULL in case of an error.
- *                      The handle is valid until meshlink_channel_close() is called.
- */
-struct meshlink_channel *meshlink_channel_open(struct meshlink_handle *mesh, struct meshlink_node *node, uint16_t port, meshlink_channel_receive_cb_t cb, const void *data, size_t len) __attribute__((__warn_unused_result__));
-
-/// Partially close a reliable stream channel.
-/** This shuts down the read or write side of a channel, or both, without closing the handle.
- *  It can be used to inform the remote node that the local node has finished sending all data on the channel,
- *  but still allows waiting for incoming data from the remote node.
- *
- *  Shutting down the receive direction is also possible, and is equivalent to setting the receive callback to NULL.
- *
- *  \memberof meshlink_channel
- *  @param mesh         A handle which represents an instance of MeshLink.
- *  @param channel      A handle for the channel.
- *  @param direction    Must be one of SHUT_RD, SHUT_WR or SHUT_RDWR, otherwise this call will not have any affect.
- */
-void meshlink_channel_shutdown(struct meshlink_handle *mesh, struct meshlink_channel *channel, int direction);
-
-/// Close a reliable stream channel.
-/** This informs the remote node that the local node has finished sending all data on the channel.
- *  It also causes the local node to stop accepting incoming data from the remote node.
- *  Afterwards, the channel handle is invalid and must not be used any more.
- *
- *  It is allowed to call this function at any time on a valid handle, even inside callback functions.
- *  If called with a valid handle, this function always succeeds, otherwise the result is undefined.
- *
- *  \memberof meshlink_channel
- *  @param mesh         A handle which represents an instance of MeshLink.
- *  @param channel      A handle for the channel.
- */
-void meshlink_channel_close(struct meshlink_handle *mesh, struct meshlink_channel *channel);
-
-/// Abort a reliable stream channel.
-/** This aborts a channel.
- *  Data that was in the send and receive buffers is dropped, so potentially there is some data that
- *  was sent on this channel that will not be received by the peer.
- *  Afterwards, the channel handle is invalid and must not be used any more.
- *
- *  It is allowed to call this function at any time on a valid handle, even inside callback functions.
- *  If called with a valid handle, this function always succeeds, otherwise the result is undefined.
- *
- *  \memberof meshlink_channel
- *  @param mesh         A handle which represents an instance of MeshLink.
- *  @param channel      A handle for the channel.
- */
-void meshlink_channel_abort(struct meshlink_handle *mesh, struct meshlink_channel *channel);
-
-/// Transmit data on a channel
-/** This queues data to send to the remote node.
- *
- *  \memberof meshlink_channel
- *  @param mesh         A handle which represents an instance of MeshLink.
- *  @param channel      A handle for the channel.
- *  @param data         A pointer to a buffer containing data sent by the source, or NULL if there is no data to send.
- *                      After meshlink_send() returns, the application is free to overwrite or free this buffer.
- *  @param len          The length of the data, or 0 if there is no data to send.
- *
- *  @return             The amount of data that was queued, which can be less than len, or a negative value in case of an error.
- *                      If MESHLINK_CHANNEL_NO_PARTIAL is set, then the result will either be len,
- *                      0 if the buffer is currently too full, or -1 if len is too big even for an empty buffer.
- */
-ssize_t meshlink_channel_send(struct meshlink_handle *mesh, struct meshlink_channel *channel, const void *data, size_t len) __attribute__((__warn_unused_result__));
-
-/// Get channel flags.
-/** This returns the flags used when opening this channel.
- *
- *  \memberof meshlink_channel
- *  @param mesh         A handle which represents an instance of MeshLink.
- *  @param channel      A handle for the channel.
- *
- *  @return             The flags set for this channel.
- */
-uint32_t meshlink_channel_get_flags(struct meshlink_handle *mesh, struct meshlink_channel *channel) __attribute__((__warn_unused_result__));
-
-/// Get the maximum segment size of a channel.
-/** This returns the amount of bytes that can be sent at once for channels with UDP semantics.
- *
- *  \memberof meshlink_channel
- *  @param mesh         A handle which represents an instance of MeshLink.
- *  @param channel      A handle for the channel.
- *
- *  @return             The amount of bytes in the receive buffer.
- */
-size_t meshlink_channel_get_mss(struct meshlink_handle *mesh, struct meshlink_channel *channel) __attribute__((__warn_unused_result__));
-
-/// Set the connection timeout used for channels to the given node.
-/** This sets the timeout after which unresponsive channels will be reported as closed.
- *  The timeout is set for all current and future channels to the given node.
- *
- *  \memberof meshlink_node
- *  @param mesh         A handle which represents an instance of MeshLink.
- *  @param node         A pointer to a struct meshlink_node describing the node to set the channel connection timeout for.
- *  @param timeout      The timeout in seconds after which unresponsive channels will be reported as closed.
- *                      The default is 60 seconds.
- */
-void meshlink_set_node_channel_timeout(struct meshlink_handle *mesh, struct meshlink_node *node, int timeout);
-
 /// Hint that a hostname may be found at an address
 /** This function indicates to meshlink that the given hostname is likely found
  *  at the given IP address and port.
index c27afc86dcf51f5d032beb2f2caab6a2daef9327..b69c1619e498beec8a288c3960e4abb9983ddcac 100644 (file)
@@ -30,7 +30,6 @@
 #include "packmsg.h"
 #include "prf.h"
 #include "protocol.h"
-#include "route.h"
 #include "sockaddr.h"
 #include "utils.h"
 #include "xalloc.h"
@@ -490,15 +489,11 @@ static bool ecdsa_keygen(meshlink_handle_t *mesh) {
 
 static struct timespec idle(event_loop_t *loop, void *data) {
        (void)loop;
-       meshlink_handle_t *mesh = data;
+       (void)data;
 
-       if(mesh->peer && mesh->peer->utcp) {
-               return utcp_timeout(mesh->peer->utcp);
-       } else {
-               return (struct timespec) {
-                       3600, 0
-               };
-       }
+       return (struct timespec) {
+               3600, 0
+       };
 }
 
 static bool meshlink_setup(meshlink_handle_t *mesh) {
@@ -1468,56 +1463,6 @@ void meshlink_set_error_cb(struct meshlink_handle *mesh, meshlink_error_cb_t cb)
        pthread_mutex_unlock(&mesh->mutex);
 }
 
-static bool prepare_packet(meshlink_handle_t *mesh, meshlink_node_t *destination, const void *data, size_t len, vpn_packet_t *packet) {
-       meshlink_packethdr_t *hdr;
-
-       if(len > MAXSIZE - sizeof(*hdr)) {
-               meshlink_errno = MESHLINK_EINVAL;
-               return false;
-       }
-
-       node_t *n = (node_t *)destination;
-
-       if(n->status.blacklisted) {
-               logger(mesh, MESHLINK_ERROR, "Node %s blacklisted, dropping packet\n", n->name);
-               meshlink_errno = MESHLINK_EBLACKLISTED;
-               return false;
-       }
-
-       // Prepare the packet
-       packet->probe = false;
-       packet->tcp = false;
-       packet->len = len + sizeof(*hdr);
-
-       hdr = (meshlink_packethdr_t *)packet->data;
-       memset(hdr, 0, sizeof(*hdr));
-       // leave the last byte as 0 to make sure strings are always
-       // null-terminated if they are longer than the buffer
-       strncpy((char *)hdr->destination, destination->name, sizeof(hdr->destination) - 1);
-       strncpy((char *)hdr->source, mesh->self->name, sizeof(hdr->source) - 1);
-
-       memcpy(packet->data + sizeof(*hdr), data, len);
-
-       return true;
-}
-
-static bool meshlink_send_immediate(meshlink_handle_t *mesh, meshlink_node_t *destination, const void *data, size_t len) {
-       assert(mesh);
-       assert(destination);
-       assert(data);
-       assert(len);
-
-       // Prepare the packet
-       if(!prepare_packet(mesh, destination, data, len, mesh->packet)) {
-               return false;
-       }
-
-       // Send it immediately
-       route(mesh, mesh->self, mesh->packet);
-
-       return true;
-}
-
 bool meshlink_send(meshlink_handle_t *mesh, meshlink_node_t *destination, const void *data, size_t len) {
        logger(mesh, MESHLINK_DEBUG, "meshlink_send(%s, %p, %zu)", destination ? destination->name : "(null)", data, len);
 
@@ -1531,7 +1476,7 @@ bool meshlink_send(meshlink_handle_t *mesh, meshlink_node_t *destination, const
                return true;
        }
 
-       if(!data) {
+       if(!data || len > MTU) {
                meshlink_errno = MESHLINK_EINVAL;
                return false;
        }
@@ -1544,10 +1489,8 @@ bool meshlink_send(meshlink_handle_t *mesh, meshlink_node_t *destination, const
                return false;
        }
 
-       if(!prepare_packet(mesh, destination, data, len, packet)) {
-               free(packet);
-               return false;
-       }
+       packet->len = len;
+       memcpy(packet->data, data, len);
 
        // Queue it
        if(!meshlink_queue_push(&mesh->outpacketqueue, packet)) {
@@ -1572,7 +1515,7 @@ void meshlink_send_from_queue(event_loop_t *loop, void *data) {
 
        for(vpn_packet_t *packet; (packet = meshlink_queue_pop(&mesh->outpacketqueue));) {
                logger(mesh, MESHLINK_DEBUG, "Removing packet of %d bytes from packet queue", packet->len);
-               route(mesh, mesh->self, packet);
+               send_raw_packet(mesh, mesh->peer->connection, packet);
                free(packet);
        }
 }
@@ -2246,367 +2189,7 @@ void meshlink_hint_address(meshlink_handle_t *mesh, meshlink_node_t *node, const
        // @TODO do we want to fire off a connection attempt right away?
 }
 
-static bool channel_pre_accept(struct utcp *utcp, uint16_t port) {
-       (void)port;
-       node_t *n = utcp->priv;
-       meshlink_handle_t *mesh = n->mesh;
-
-       if(mesh->channel_accept_cb && mesh->channel_listen_cb) {
-               return mesh->channel_listen_cb(mesh, (meshlink_node_t *)n, port);
-       } else {
-               return mesh->channel_accept_cb;
-       }
-}
-
-static ssize_t channel_recv(struct utcp_connection *connection, const void *data, size_t len) {
-       meshlink_channel_t *channel = connection->priv;
-
-       if(!channel) {
-               abort();
-       }
-
-       node_t *n = channel->node;
-       meshlink_handle_t *mesh = n->mesh;
-
-       if(n->status.destroyed) {
-               meshlink_channel_close(mesh, channel);
-               return len;
-       }
-
-       const char *p = data;
-       size_t left = len;
-
-       if(channel->receive_cb) {
-               channel->receive_cb(mesh, channel, p, left);
-       }
-
-       return len;
-}
-
-static void channel_accept(struct utcp_connection *utcp_connection, uint16_t port) {
-       node_t *n = utcp_connection->utcp->priv;
-
-       if(!n) {
-               abort();
-       }
-
-       meshlink_handle_t *mesh = n->mesh;
-
-       if(!mesh->channel_accept_cb) {
-               return;
-       }
-
-       meshlink_channel_t *channel = xzalloc(sizeof(*channel));
-       channel->node = n;
-       channel->c = utcp_connection;
-
-       if(mesh->channel_accept_cb(mesh, channel, port, NULL, 0)) {
-               utcp_accept(utcp_connection, channel_recv, channel);
-       } else {
-               free(channel);
-       }
-}
-
-static ssize_t channel_send(struct utcp *utcp, const void *data, size_t len) {
-       node_t *n = utcp->priv;
-
-       if(n->status.destroyed) {
-               return -1;
-       }
-
-       meshlink_handle_t *mesh = n->mesh;
-       return meshlink_send_immediate(mesh, (meshlink_node_t *)n, data, len) ? (ssize_t)len : -1;
-}
-
-void meshlink_set_channel_receive_cb(meshlink_handle_t *mesh, meshlink_channel_t *channel, meshlink_channel_receive_cb_t cb) {
-       logger(mesh, MESHLINK_DEBUG, "meshlink_set_channel_receive_cb(%p, %p)", (void *)channel, (void *)(intptr_t)cb);
-
-       if(!mesh || !channel) {
-               meshlink_errno = MESHLINK_EINVAL;
-               return;
-       }
-
-       channel->receive_cb = cb;
-}
-
-static void channel_receive(meshlink_handle_t *mesh, meshlink_node_t *source, const void *data, size_t len) {
-       (void)mesh;
-       node_t *n = (node_t *)source;
-
-       if(!n->utcp) {
-               abort();
-       }
-
-       utcp_recv(n->utcp, data, len);
-}
-
-void meshlink_set_channel_listen_cb(meshlink_handle_t *mesh, meshlink_channel_listen_cb_t cb) {
-       logger(mesh, MESHLINK_DEBUG, "meshlink_set_channel_listen_cb(%p)", (void *)(intptr_t)cb);
-
-       if(!mesh) {
-               meshlink_errno = MESHLINK_EINVAL;
-               return;
-       }
-
-       if(pthread_mutex_lock(&mesh->mutex) != 0) {
-               abort();
-       }
-
-       mesh->channel_listen_cb = cb;
-
-       pthread_mutex_unlock(&mesh->mutex);
-}
-
-void meshlink_set_channel_accept_cb(meshlink_handle_t *mesh, meshlink_channel_accept_cb_t cb) {
-       logger(mesh, MESHLINK_DEBUG, "meshlink_set_channel_accept_cb(%p)", (void *)(intptr_t)cb);
-
-       if(!mesh) {
-               meshlink_errno = MESHLINK_EINVAL;
-               return;
-       }
-
-       if(pthread_mutex_lock(&mesh->mutex) != 0) {
-               abort();
-       }
-
-       mesh->channel_accept_cb = cb;
-       mesh->receive_cb = channel_receive;
-
-       if(mesh->peer) {
-               mesh->peer->utcp = utcp_init(channel_accept, channel_pre_accept, channel_send, mesh->peer);
-       }
-
-       pthread_mutex_unlock(&mesh->mutex);
-}
-
-void meshlink_set_channel_flags(meshlink_handle_t *mesh, meshlink_channel_t *channel, uint32_t flags) {
-       logger(mesh, MESHLINK_DEBUG, "meshlink_set_channel_flags(%p, %u)", (void *)channel, flags);
-
-       if(!mesh || !channel) {
-               meshlink_errno = MESHLINK_EINVAL;
-               return;
-       }
-
-       if(pthread_mutex_lock(&mesh->mutex) != 0) {
-               abort();
-       }
-
-       utcp_set_flags(channel->c, flags);
-       pthread_mutex_unlock(&mesh->mutex);
-}
-
-meshlink_channel_t *meshlink_channel_open_ex(meshlink_handle_t *mesh, meshlink_node_t *node, uint16_t port, meshlink_channel_receive_cb_t cb, const void *data, size_t len, uint32_t flags) {
-       logger(mesh, MESHLINK_DEBUG, "meshlink_channel_open_ex(%s, %u, %p, %p, %zu, %u)", node ? node->name : "(null)", port, (void *)(intptr_t)cb, data, len, flags);
-
-       if(data && len) {
-               abort();        // TODO: handle non-NULL data
-       }
-
-       if(!mesh || !node) {
-               meshlink_errno = MESHLINK_EINVAL;
-               return NULL;
-       }
-
-       if(pthread_mutex_lock(&mesh->mutex) != 0) {
-               abort();
-       }
-
-       node_t *n = (node_t *)node;
-
-       if(!n->utcp) {
-               n->utcp = utcp_init(channel_accept, channel_pre_accept, channel_send, n);
-               mesh->receive_cb = channel_receive;
-
-               if(!n->utcp) {
-                       meshlink_errno = errno == ENOMEM ? MESHLINK_ENOMEM : MESHLINK_EINTERNAL;
-                       pthread_mutex_unlock(&mesh->mutex);
-                       return NULL;
-               }
-       }
-
-       if(n->status.blacklisted) {
-               logger(mesh, MESHLINK_ERROR, "Cannot open a channel with blacklisted node\n");
-               meshlink_errno = MESHLINK_EBLACKLISTED;
-               pthread_mutex_unlock(&mesh->mutex);
-               return NULL;
-       }
-
-       meshlink_channel_t *channel = xzalloc(sizeof(*channel));
-       channel->node = n;
-       channel->receive_cb = cb;
-
-       if(data && !len) {
-               channel->priv = (void *)data;
-       }
-
-       channel->c = utcp_connect_ex(n->utcp, port, channel_recv, channel, flags);
-
-       pthread_mutex_unlock(&mesh->mutex);
-
-       if(!channel->c) {
-               meshlink_errno = errno == ENOMEM ? MESHLINK_ENOMEM : MESHLINK_EINTERNAL;
-               free(channel);
-               return NULL;
-       }
-
-       return channel;
-}
-
-meshlink_channel_t *meshlink_channel_open(meshlink_handle_t *mesh, meshlink_node_t *node, uint16_t port, meshlink_channel_receive_cb_t cb, const void *data, size_t len) {
-       logger(mesh, MESHLINK_DEBUG, "meshlink_channel_open_ex(%s, %u, %p, %p, %zu)", node ? node->name : "(null)", port, (void *)(intptr_t)cb, data, len);
-
-       return meshlink_channel_open_ex(mesh, node, port, cb, data, len, MESHLINK_CHANNEL_TCP);
-}
-
-void meshlink_channel_shutdown(meshlink_handle_t *mesh, meshlink_channel_t *channel, int direction) {
-       logger(mesh, MESHLINK_DEBUG, "meshlink_channel_shutdown(%p, %d)", (void *)channel, direction);
-
-       if(!mesh || !channel) {
-               meshlink_errno = MESHLINK_EINVAL;
-               return;
-       }
-
-       if(pthread_mutex_lock(&mesh->mutex) != 0) {
-               abort();
-       }
-
-       utcp_shutdown(channel->c, direction);
-       pthread_mutex_unlock(&mesh->mutex);
-}
-
-void meshlink_channel_close(meshlink_handle_t *mesh, meshlink_channel_t *channel) {
-       logger(mesh, MESHLINK_DEBUG, "meshlink_channel_close(%p)", (void *)channel);
-
-       if(!mesh || !channel) {
-               meshlink_errno = MESHLINK_EINVAL;
-               return;
-       }
-
-       if(pthread_mutex_lock(&mesh->mutex) != 0) {
-               abort();
-       }
-
-       if(channel->c) {
-               utcp_close(channel->c);
-               channel->c = NULL;
-       }
-
-       if(!channel->in_callback) {
-               free(channel);
-       }
-
-       pthread_mutex_unlock(&mesh->mutex);
-}
-
-void meshlink_channel_abort(meshlink_handle_t *mesh, meshlink_channel_t *channel) {
-       logger(mesh, MESHLINK_DEBUG, "meshlink_channel_abort(%p)", (void *)channel);
-
-       if(!mesh || !channel) {
-               meshlink_errno = MESHLINK_EINVAL;
-               return;
-       }
-
-       if(pthread_mutex_lock(&mesh->mutex) != 0) {
-               abort();
-       }
-
-       if(channel->c) {
-               utcp_abort(channel->c);
-               channel->c = NULL;
-       }
-
-       if(!channel->in_callback) {
-               free(channel);
-       }
-
-       pthread_mutex_unlock(&mesh->mutex);
-}
-
-ssize_t meshlink_channel_send(meshlink_handle_t *mesh, meshlink_channel_t *channel, const void *data, size_t len) {
-       logger(mesh, MESHLINK_DEBUG, "meshlink_channel_send(%p, %p, %zu)", (void *)channel, data, len);
-
-       if(!mesh || !channel) {
-               meshlink_errno = MESHLINK_EINVAL;
-               return -1;
-       }
-
-       if(!len) {
-               return 0;
-       }
-
-       if(!data) {
-               meshlink_errno = MESHLINK_EINVAL;
-               return -1;
-       }
-
-       // TODO: more finegrained locking.
-       // Ideally we want to put the data into the UTCP connection's send buffer.
-       // Then, preferably only if there is room in the receiver window,
-       // kick the meshlink thread to go send packets.
-
-       ssize_t retval;
-
-       if(pthread_mutex_lock(&mesh->mutex) != 0) {
-               abort();
-       }
-
-       retval = utcp_send(channel->c, data, len);
-
-       pthread_mutex_unlock(&mesh->mutex);
-
-       if(retval < 0) {
-               meshlink_errno = MESHLINK_ENETWORK;
-       }
-
-       return retval;
-}
-
-uint32_t meshlink_channel_get_flags(meshlink_handle_t *mesh, meshlink_channel_t *channel) {
-       if(!mesh || !channel) {
-               meshlink_errno = MESHLINK_EINVAL;
-               return -1;
-       }
-
-       return channel->c->flags;
-}
-
-size_t meshlink_channel_get_mss(meshlink_handle_t *mesh, meshlink_channel_t *channel) {
-       if(!mesh || !channel) {
-               meshlink_errno = MESHLINK_EINVAL;
-               return -1;
-       }
-
-       return utcp_get_mss(channel->node->utcp);
-}
-
-void meshlink_set_node_channel_timeout(meshlink_handle_t *mesh, meshlink_node_t *node, int timeout) {
-       logger(mesh, MESHLINK_DEBUG, "meshlink_set_node_channel_timeout(%s, %d)", node ? node->name : "(null)", timeout);
-
-       if(!mesh || !node) {
-               meshlink_errno = MESHLINK_EINVAL;
-               return;
-       }
-
-       node_t *n = (node_t *)node;
-
-       if(pthread_mutex_lock(&mesh->mutex) != 0) {
-               abort();
-       }
-
-       if(!n->utcp) {
-               n->utcp = utcp_init(channel_accept, channel_pre_accept, channel_send, n);
-       }
-
-       utcp_set_user_timeout(n->utcp, timeout);
-
-       pthread_mutex_unlock(&mesh->mutex);
-}
-
 void update_node_status(meshlink_handle_t *mesh, node_t *n) {
-       if(n->status.reachable && mesh->channel_accept_cb && !n->utcp) {
-               n->utcp = utcp_init(channel_accept, channel_pre_accept, channel_send, n);
-       }
-
        if(mesh->node_status_cb) {
                mesh->node_status_cb(mesh, (meshlink_node_t *)n, n->status.reachable && !n->status.blacklisted);
        }
@@ -2732,17 +2315,6 @@ void meshlink_set_inviter_commits_first(struct meshlink_handle *mesh, bool invit
        pthread_mutex_unlock(&mesh->mutex);
 }
 
-void meshlink_set_scheduling_granularity(struct meshlink_handle *mesh, long granularity) {
-       logger(mesh, MESHLINK_DEBUG, "meshlink_set_scheduling_granularity(%ld)", granularity);
-
-       if(!mesh || granularity < 0) {
-               meshlink_errno = EINVAL;
-               return;
-       }
-
-       utcp_set_clock_granularity(granularity);
-}
-
 void meshlink_set_storage_policy(struct meshlink_handle *mesh, meshlink_storage_policy_t policy) {
        logger(mesh, MESHLINK_DEBUG, "meshlink_set_storage_policy(%d)", policy);
 
@@ -2787,7 +2359,6 @@ void call_error_cb(meshlink_handle_t *mesh, meshlink_errno_t cb_errno) {
 
 static void __attribute__((constructor)) meshlink_init(void) {
        crypto_init();
-       utcp_set_clock_granularity(10000);
 }
 
 static void __attribute__((destructor)) meshlink_exit(void) {
index 56c810f31c4ff4a5c87024a54bb00926322d67ea..f77d700692f410ec34b6284583e5e253ee9de6de 100644 (file)
@@ -111,8 +111,6 @@ struct meshlink_handle {
        // Infrequently used callbacks
        meshlink_node_status_cb_t node_status_cb;
        meshlink_node_status_cb_t meta_status_cb;
-       meshlink_channel_listen_cb_t channel_listen_cb;
-       meshlink_channel_accept_cb_t channel_accept_cb;
        meshlink_node_duplicate_cb_t node_duplicate_cb;
        meshlink_connection_try_cb_t connection_try_cb;
        meshlink_error_cb_t error_cb;
@@ -150,22 +148,6 @@ struct meshlink_node {
        void *priv;
 };
 
-/// A channel.
-struct meshlink_channel {
-       struct node_t *node;
-       void *priv;
-       bool in_callback;
-
-       struct utcp_connection *c;
-       meshlink_channel_receive_cb_t receive_cb;
-};
-
-/// Header for data packets routed between nodes
-typedef struct meshlink_packethdr {
-       uint8_t destination[16];
-       uint8_t source[16];
-} __attribute__((__packed__)) meshlink_packethdr_t;
-
 void meshlink_send_from_queue(event_loop_t *loop, void *mesh);
 void update_node_status(meshlink_handle_t *mesh, struct node_t *n);
 extern meshlink_log_level_t global_log_level;
index 09edf79d503b920a0e6739d1ea4d9b2c3355b1a0..12241f819892fc13bde6891b688e89ea908f803e 100644 (file)
@@ -47,7 +47,7 @@ bool send_meta_sptps(void *handle, uint8_t type, const void *buffer, size_t leng
 bool send_meta(meshlink_handle_t *mesh, connection_t *c, const char *buffer, int length) {
        assert(c);
        assert(buffer);
-       assert(length);
+       assert(length >= 0);
 
        logger(mesh, MESHLINK_DEBUG, "Sending %d bytes of metadata to %s", length, c->name);
 
@@ -95,6 +95,18 @@ bool receive_meta_sptps(void *handle, uint8_t type, const void *data, uint16_t l
                return true;
        }
 
+       /* Are we receiving a raw packet? */
+
+       if(c->status.raw_packet) {
+               c->status.raw_packet = false;
+
+               if(mesh->receive_cb) {
+                       mesh->receive_cb(mesh, (meshlink_node_t *)c->node, data, length);
+               }
+
+               return true;
+       }
+
        /* Change newline to null byte, just like non-SPTPS requests */
 
        if(request[length - 1] == '\n') {
index 101c95792dc3eb76476205a85dd3f68bd0b149b7..d930d1fdd7a2c36e61ee4b11a88f9e32a7a43cf7 100644 (file)
--- a/src/net.c
+++ b/src/net.c
@@ -101,12 +101,6 @@ static void timeout_handler(event_loop_t *loop, void *data) {
                }
 
                // Also make sure that if outstanding key requests for the UDP counterpart of a connection has timed out, we restart it.
-               if(c->node) {
-                       if(c->node->status.waitingforkey && c->node->last_req_key + pingtimeout < mesh->loop.now.tv_sec) {
-                               send_req_key(mesh, c->node);
-                       }
-               }
-
                if(c->status.active && c->last_key_renewal + 3600 < mesh->loop.now.tv_sec) {
                        devtool_sptps_renewal_probe((meshlink_node_t *)c->node);
 
@@ -191,21 +185,6 @@ static void periodic_handler(event_loop_t *loop, void *data) {
                                logger(mesh, MESHLINK_DEBUG, "Could not update %s", n->name);
                        }
                }
-
-               if(n->status.reachable && n->status.validkey && n->last_req_key + 3600 < mesh->loop.now.tv_sec) {
-                       logger(mesh, MESHLINK_DEBUG, "SPTPS key renewal for node %s", n->name);
-                       devtool_sptps_renewal_probe((meshlink_node_t *)n);
-
-                       if(!sptps_force_kex(&n->sptps)) {
-                               logger(mesh, MESHLINK_ERROR, "SPTPS key renewal for node %s failed", n->name);
-                               n->status.validkey = false;
-                               sptps_stop(&n->sptps);
-                               n->status.waitingforkey = false;
-                               n->last_req_key = -3600;
-                       } else {
-                               n->last_req_key = mesh->loop.now.tv_sec;
-                       }
-               }
        }
 
        timeout_set(&mesh->loop, data, &(struct timespec) {
index 91b9ad2e80f76c15ed177535c4b97487864581b5..ec37eaad6d9eb480bc002fdb7694ac88b74845fd 100644 (file)
--- a/src/net.h
+++ b/src/net.h
 #define MAXBUFSIZE ((MAXSIZE * 8) / 6 + 128)
 
 typedef struct vpn_packet_t {
-       uint16_t probe: 1;
-       int16_t tcp: 1;
        uint16_t len;           /* the actual number of bytes in the `data' field */
        uint8_t data[MAXSIZE];
 } vpn_packet_t;
 
-/* Packet types when using SPTPS */
-
-#define PKT_COMPRESSED 1
-#define PKT_PROBE 4
-
-typedef enum packet_type_t {
-       PACKET_NORMAL,
-       PACKET_COMPRESSED,
-       PACKET_PROBE
-} packet_type_t;
-
 #include "conf.h"
 #include "list.h"
 
@@ -88,10 +75,6 @@ void handle_incoming_vpn_data(struct event_loop_t *loop, void *, int);
 void finish_connecting(struct meshlink_handle *mesh, struct connection_t *);
 void do_outgoing_connection(struct meshlink_handle *mesh, struct outgoing_t *);
 void handle_new_meta_connection(struct event_loop_t *loop, void *, int);
-bool send_sptps_data(void *handle, uint8_t type, const void *data, size_t len);
-bool receive_sptps_record(void *handle, uint8_t type, const void *data, uint16_t len) __attribute__((__warn_unused_result__));
-void send_packet(struct meshlink_handle *mesh, struct node_t *, struct vpn_packet_t *);
-char *get_name(struct meshlink_handle *mesh) __attribute__((__warn_unused_result__));
 void load_all_nodes(struct meshlink_handle *mesh);
 bool setup_myself_reloadable(struct meshlink_handle *mesh) __attribute__((__warn_unused_result__));
 bool setup_network(struct meshlink_handle *mesh) __attribute__((__warn_unused_result__));
diff --git a/src/net_packet.c b/src/net_packet.c
deleted file mode 100644 (file)
index 21e164a..0000000
+++ /dev/null
@@ -1,189 +0,0 @@
-/*
-    net_packet.c -- Handles in- and outgoing VPN packets
-    Copyright (C) 2014-2017 Guus Sliepen <guus@meshlink.io>
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    This program 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 "system.h"
-
-#include "conf.h"
-#include "connection.h"
-#include "crypto.h"
-#include "logger.h"
-#include "meshlink_internal.h"
-#include "net.h"
-#include "netutl.h"
-#include "protocol.h"
-#include "route.h"
-#include "utils.h"
-#include "xalloc.h"
-
-int keylifetime = 0;
-
-/* VPN packet I/O */
-
-static void receive_packet(meshlink_handle_t *mesh, node_t *n, vpn_packet_t *packet) {
-       logger(mesh, MESHLINK_DEBUG, "Received packet of %d bytes from %s", packet->len, n->name);
-
-       if(n->status.blacklisted) {
-               logger(mesh, MESHLINK_WARNING, "Dropping packet from blacklisted node %s", n->name);
-       } else {
-               route(mesh, n, packet);
-       }
-}
-
-static void send_sptps_packet(meshlink_handle_t *mesh, node_t *n, vpn_packet_t *origpkt) {
-       if(!n->status.reachable) {
-               logger(mesh, MESHLINK_ERROR, "Trying to send SPTPS data to unreachable node %s", n->name);
-               return;
-       }
-
-       if(!n->status.validkey) {
-               logger(mesh, MESHLINK_INFO, "No valid key known yet for %s", n->name);
-
-               if(!n->status.waitingforkey) {
-                       send_req_key(mesh, n);
-               } else if(n->last_req_key + 10 < mesh->loop.now.tv_sec) {
-                       logger(mesh, MESHLINK_DEBUG, "No key from %s after 10 seconds, restarting SPTPS", n->name);
-                       sptps_stop(&n->sptps);
-                       n->status.waitingforkey = false;
-                       send_req_key(mesh, n);
-               }
-
-               return;
-       }
-
-       uint8_t type = 0;
-
-       // If it's a probe, send it immediately without trying to compress it.
-       if(origpkt->probe) {
-               sptps_send_record(&n->sptps, PKT_PROBE, origpkt->data, origpkt->len);
-               return;
-       }
-
-       sptps_send_record(&n->sptps, type, origpkt->data, origpkt->len);
-       return;
-}
-
-bool send_sptps_data(void *handle, uint8_t type, const void *data, size_t len) {
-       assert(handle);
-       assert(data);
-       assert(len);
-
-       node_t *to = handle;
-       meshlink_handle_t *mesh = to->mesh;
-
-       if(!to->status.reachable) {
-               logger(mesh, MESHLINK_ERROR, "Trying to send SPTPS data to unreachable node %s", to->name);
-               return false;
-       }
-
-
-       if(type == PKT_PROBE) {
-               /* Probe packets are not supported. */
-               return false;
-       }
-
-       /* Send it via TCP. */
-
-       char buf[len * 4 / 3 + 5];
-       b64encode(data, buf, len);
-
-       if(!to->nexthop || !to->nexthop->connection) {
-               logger(mesh, MESHLINK_WARNING, "Unable to forward SPTPS packet to %s via %s", to->name, to->nexthop ? to->nexthop->name : to->name);
-               return false;
-       }
-
-       /* If no valid key is known yet, send the packets using ANS_KEY requests,
-          to ensure we get to learn the reflexive UDP address. */
-       if(!to->status.validkey) {
-               return send_request(mesh, to->nexthop->connection, "%d %s %s %s -1 -1 -1 %d", ANS_KEY, mesh->self->name, to->name, buf, 0);
-       } else {
-               return send_request(mesh, to->nexthop->connection, "%d %s %s %d %s", REQ_KEY, mesh->self->name, to->name, REQ_SPTPS, buf);
-       }
-}
-
-bool receive_sptps_record(void *handle, uint8_t type, const void *data, uint16_t len) {
-       assert(handle);
-       assert(!data || len);
-
-       node_t *from = handle;
-       meshlink_handle_t *mesh = from->mesh;
-
-       if(type == SPTPS_HANDSHAKE) {
-               if(!from->status.validkey) {
-                       logger(mesh, MESHLINK_INFO, "SPTPS key exchange with %s successful", from->name);
-                       from->status.validkey = true;
-                       from->status.waitingforkey = false;
-
-                       if(from->utcp) {
-                               utcp_reset_timers(from->utcp);
-                       }
-               }
-
-               return true;
-       }
-
-       if(len > MAXSIZE) {
-               logger(mesh, MESHLINK_ERROR, "Packet from %s larger than maximum supported size (%d > %d)", from->name, len, MAXSIZE);
-               return false;
-       }
-
-       vpn_packet_t inpkt;
-
-       if(type == PKT_PROBE) {
-               /* We shouldn't receive any UDP probe packets. */
-               return false;
-       } else {
-               inpkt.probe = false;
-       }
-
-       if(type & ~(PKT_COMPRESSED)) {
-               logger(mesh, MESHLINK_ERROR, "Unexpected SPTPS record type %d len %d from %s", type, len, from->name);
-               return false;
-       }
-
-       if(type & PKT_COMPRESSED) {
-               logger(mesh, MESHLINK_ERROR, "Error while decompressing packet from %s", from->name);
-               return false;
-       }
-
-       memcpy(inpkt.data, data, len); // TODO: get rid of memcpy
-       inpkt.len = len;
-
-       receive_packet(mesh, from, &inpkt);
-       return true;
-}
-
-/*
-  send a packet to the given vpn ip.
-*/
-void send_packet(meshlink_handle_t *mesh, node_t *n, vpn_packet_t *packet) {
-       if(n == mesh->self) {
-               // TODO: send to application
-               return;
-       }
-
-       logger(mesh, MESHLINK_DEBUG, "Sending packet of %d bytes to %s", packet->len, n->name);
-
-       if(!n->status.reachable) {
-               logger(mesh, MESHLINK_WARNING, "Node %s is not reachable", n->name);
-               return;
-       }
-
-       send_sptps_packet(mesh, n, packet);
-       return;
-}
index 8850f2e11133d02170b271c74b12015c8b5bb9a6..7f8804b17be524cdfcc5d8d3abc9ad7cee20677b 100644 (file)
@@ -28,7 +28,6 @@
 #include "netutl.h"
 #include "packmsg.h"
 #include "protocol.h"
-#include "route.h"
 #include "utils.h"
 #include "xalloc.h"
 
index 01173f8380617807aa5d8f279ff31cf8b4fb2aca..c02644dc020d58c37e11133182514fe3c16894e5 100644 (file)
@@ -51,10 +51,7 @@ node_t *new_node(void) {
 void free_node(node_t *n) {
        n->status.destroyed = true;
 
-       utcp_exit(n->utcp);
-
        ecdsa_free(n->ecdsa);
-       sptps_stop(&n->sptps);
 
        free(n->name);
        free(n->canonical_address);
index 7384f17ca94d3a6848bbf488f116c778a5be3ce1..90e0c29bc09a6814579605fc15b54a95b2c2f175 100644 (file)
@@ -24,7 +24,6 @@
 #include "meshlink_internal.h"
 #include "sockaddr.h"
 #include "sptps.h"
-#include "utcp.h"
 
 typedef struct node_status_t {
        uint16_t validkey: 1;               /* 1 if we currently have a valid key for him */
@@ -51,17 +50,11 @@ typedef struct node_t {
        node_status_t status;
        dev_class_t devclass;
 
-       // Used for packet I/O
        uint32_t session_id;                    /* Unique ID for this node's currently running process */
-       sptps_t sptps;
-
-       struct utcp *utcp;
 
        // Used for meta-connection I/O, timeouts
        struct meshlink_handle *mesh;           /* The mesh this node belongs to */
 
-       time_t last_req_key;
-
        struct ecdsa *ecdsa;                    /* His public ECDSA key */
 
        struct connection_t *connection;        /* Connection associated with this node (if a direct connection exists) */
index 25419c04d2a1414b21b28d0bdc5f60555ece4776..61a76081a20c1337a7ee830b481a82e8f9bcd72b 100644 (file)
@@ -43,6 +43,7 @@ static bool (*request_handlers[NUM_REQUESTS])(meshlink_handle_t *, connection_t
        [KEY_CHANGED] = key_changed_h,
        [REQ_KEY] = req_key_h,
        [ANS_KEY] = ans_key_h,
+       [PACKET] = raw_packet_h,
 };
 
 /* Request names */
@@ -60,6 +61,7 @@ static const char *request_name[NUM_REQUESTS] __attribute__((unused)) = {
        [KEY_CHANGED] = "KEY_CHANGED",
        [REQ_KEY] = "REQ_KEY",
        [ANS_KEY] = "ANS_KEY",
+       [PACKET] = "PACKET",
 };
 
 bool check_id(const char *id) {
index ed7e5dfffc86e3acb32be5a750f914b2a8dbd928..02c22666c91f559d327d06fa7962baadba72324d 100644 (file)
@@ -57,6 +57,10 @@ typedef enum request_error_t {
        BLACKLISTED = 1,
 } request_error_t;
 
+/* Protocol support flags */
+
+static const uint32_t PROTOCOL_TINY = 1; // Peer is using meshlink-tiny
+
 /* Maximum size of strings in a request.
  * scanf terminates %2048s with a NUL character,
  * but the NUL character can be written after the 2048th non-NUL character.
@@ -82,8 +86,8 @@ bool send_error(struct meshlink_handle *mesh, struct connection_t *, request_err
 bool send_ping(struct meshlink_handle *mesh, struct connection_t *);
 bool send_pong(struct meshlink_handle *mesh, struct connection_t *);
 bool send_add_edge(struct meshlink_handle *mesh, struct connection_t *, int);
-bool send_req_key(struct meshlink_handle *mesh, struct node_t *);
 bool send_canonical_address(struct meshlink_handle *mesh, struct node_t *);
+bool send_raw_packet(struct meshlink_handle *mesh, struct connection_t *, const vpn_packet_t *);
 
 /* Request handlers  */
 
@@ -99,5 +103,6 @@ bool del_edge_h(struct meshlink_handle *mesh, struct connection_t *, const char
 bool key_changed_h(struct meshlink_handle *mesh, struct connection_t *, const char *);
 bool req_key_h(struct meshlink_handle *mesh, struct connection_t *, const char *);
 bool ans_key_h(struct meshlink_handle *mesh, struct connection_t *, const char *);
+bool raw_packet_h(struct meshlink_handle *mesh, struct connection_t *, const char *);
 
 #endif
index 573da14817126e6876bed2d15397f747adc2d815..9ffd9de2989ad2563ce17439d8486844e216b811 100644 (file)
@@ -42,7 +42,7 @@
 extern bool node_write_devclass(meshlink_handle_t *mesh, node_t *n);
 
 bool send_id(meshlink_handle_t *mesh, connection_t *c) {
-       return send_request(mesh, c, "%d %s %d.%d %s", ID, mesh->self->name, PROT_MAJOR, PROT_MINOR, mesh->appname);
+       return send_request(mesh, c, "%d %s %d.%d %s %u", ID, mesh->self->name, PROT_MAJOR, PROT_MINOR, mesh->appname, PROTOCOL_TINY);
 }
 
 bool id_h(meshlink_handle_t *mesh, connection_t *c, const char *request) {
@@ -50,8 +50,9 @@ bool id_h(meshlink_handle_t *mesh, connection_t *c, const char *request) {
        assert(*request);
 
        char name[MAX_STRING_SIZE];
+       uint32_t flags;
 
-       if(sscanf(request, "%*d " MAX_STRING " %d.%d", name, &c->protocol_major, &c->protocol_minor) < 2) {
+       if(sscanf(request, "%*d " MAX_STRING " %d.%d %*s %u", name, &c->protocol_major, &c->protocol_minor, &flags) < 4) {
                logger(mesh, MESHLINK_ERROR, "Got bad %s from %s", "ID", c->name);
                return false;
        }
@@ -97,12 +98,6 @@ bool id_h(meshlink_handle_t *mesh, connection_t *c, const char *request) {
 
        if(!node_read_public_key(mesh, n)) {
                logger(mesh, MESHLINK_ERROR, "No key known for peer %s", c->name);
-
-               if(n->status.reachable && !n->status.waitingforkey) {
-                       logger(mesh, MESHLINK_INFO, "Requesting key from peer %s", c->name);
-                       send_req_key(mesh, n);
-               }
-
                return false;
        }
 
@@ -200,11 +195,5 @@ bool ack_h(meshlink_handle_t *mesh, connection_t *c, const char *request) {
        n->status.reachable = true;
        update_node_status(mesh, c->node);
 
-       /* Request a session key to jump start UDP traffic */
-
-       if(c->status.initiator) {
-               send_req_key(mesh, n);
-       }
-
        return true;
 }
index 6ee28750376aeaa07f8bdeb7c4c4e84ca7a5e5a0..c278531cc745b896b4aaa9707a68b18eb05fd1a7 100644 (file)
@@ -31,8 +31,6 @@
 #include "utils.h"
 #include "xalloc.h"
 
-static const int req_key_timeout = 2;
-
 bool key_changed_h(meshlink_handle_t *mesh, connection_t *c, const char *request) {
        (void)mesh;
        (void)c;
@@ -40,381 +38,16 @@ bool key_changed_h(meshlink_handle_t *mesh, connection_t *c, const char *request
        return true;
 }
 
-static bool send_initial_sptps_data(void *handle, uint8_t type, const void *data, size_t len) {
-       (void)type;
-
-       assert(data);
-       assert(len);
-
-       node_t *to = handle;
-       meshlink_handle_t *mesh = to->mesh;
-
-       if(!to->nexthop || !to->nexthop->connection) {
-               logger(mesh, MESHLINK_WARNING, "Cannot send SPTPS data to %s via %s", to->name, to->nexthop ? to->nexthop->name : to->name);
-               return false;
-       }
-
-       to->sptps.send_data = send_sptps_data;
-       char buf[len * 4 / 3 + 5];
-       b64encode(data, buf, len);
-       return send_request(mesh, to->nexthop->connection, "%d %s %s %d %s", REQ_KEY, mesh->self->name, to->name, REQ_KEY, buf);
-}
-
-bool send_canonical_address(meshlink_handle_t *mesh, node_t *to) {
-       if(!mesh->self->canonical_address) {
-               return true;
-       }
-
-       return send_request(mesh, to->nexthop->connection, "%d %s %s %d %s", REQ_KEY, mesh->self->name, to->name, REQ_CANONICAL, mesh->self->canonical_address);
-}
-
-bool send_req_key(meshlink_handle_t *mesh, node_t *to) {
-       if(!node_read_public_key(mesh, to)) {
-               logger(mesh, MESHLINK_DEBUG, "No ECDSA key known for %s", to->name);
-
-               if(!to->nexthop || !to->nexthop->connection) {
-                       logger(mesh, MESHLINK_WARNING, "Cannot send REQ_PUBKEY to %s via %s", to->name, to->nexthop ? to->nexthop->name : to->name);
-                       return true;
-               }
-
-               char *pubkey = ecdsa_get_base64_public_key(mesh->private_key);
-               send_request(mesh, to->nexthop->connection, "%d %s %s %d %s", REQ_KEY, mesh->self->name, to->name, REQ_PUBKEY, pubkey);
-               free(pubkey);
-               return true;
-       }
-
-       if(to->sptps.label) {
-               logger(mesh, MESHLINK_DEBUG, "send_req_key(%s) called while sptps->label != NULL!", to->name);
-       }
-
-       /* Send our canonical address to help with UDP hole punching */
-       send_canonical_address(mesh, to);
-
-       char label[sizeof(meshlink_udp_label) + strlen(mesh->self->name) + strlen(to->name) + 2];
-       snprintf(label, sizeof(label), "%s %s %s", meshlink_udp_label, mesh->self->name, to->name);
-       sptps_stop(&to->sptps);
-       to->status.validkey = false;
-       to->status.waitingforkey = true;
-       to->last_req_key = mesh->loop.now.tv_sec;
-       return sptps_start(&to->sptps, to, true, true, mesh->private_key, to->ecdsa, label, sizeof(label) - 1, send_initial_sptps_data, receive_sptps_record);
-}
-
-/* REQ_KEY is overloaded to allow arbitrary requests to be routed between two nodes. */
-
-static bool req_key_ext_h(meshlink_handle_t *mesh, connection_t *c, const char *request, node_t *from, int reqno) {
-       (void)c;
-
-       if(!from->nexthop || !from->nexthop->connection) {
-               logger(mesh, MESHLINK_WARNING, "Cannot answer REQ_KEY from %s via %s", from->name, from->nexthop ? from->nexthop->name : from->name);
-               return true;
-       }
-
-       switch(reqno) {
-       case REQ_PUBKEY: {
-               char *pubkey = ecdsa_get_base64_public_key(mesh->private_key);
-
-               if(!node_read_public_key(mesh, from)) {
-                       char hiskey[MAX_STRING_SIZE];
-
-                       if(sscanf(request, "%*d %*s %*s %*d " MAX_STRING, hiskey) == 1) {
-                               from->ecdsa = ecdsa_set_base64_public_key(hiskey);
-
-                               if(!from->ecdsa) {
-                                       logger(mesh, MESHLINK_ERROR, "Got bad %s from %s: %s", "REQ_PUBKEY", from->name, "invalid pubkey");
-                                       return true;
-                               }
-
-                               logger(mesh, MESHLINK_INFO, "Learned ECDSA public key from %s", from->name);
-                               from->status.dirty = true;
-
-                               if(!node_write_config(mesh, from, true)) {
-                                       // ignore
-                               }
-                       }
-               }
-
-               send_request(mesh, from->nexthop->connection, "%d %s %s %d %s", REQ_KEY, mesh->self->name, from->name, ANS_PUBKEY, pubkey);
-               free(pubkey);
-               return true;
-       }
-
-       case ANS_PUBKEY: {
-               if(node_read_public_key(mesh, from)) {
-                       logger(mesh, MESHLINK_WARNING, "Got ANS_PUBKEY from %s even though we already have his pubkey", from->name);
-                       return true;
-               }
-
-               char pubkey[MAX_STRING_SIZE];
-
-               if(sscanf(request, "%*d %*s %*s %*d " MAX_STRING, pubkey) != 1 || !(from->ecdsa = ecdsa_set_base64_public_key(pubkey))) {
-                       logger(mesh, MESHLINK_ERROR, "Got bad %s from %s: %s", "ANS_PUBKEY", from->name, "invalid pubkey");
-                       return true;
-               }
-
-               logger(mesh, MESHLINK_INFO, "Learned ECDSA public key from %s", from->name);
-               from->status.dirty = true;
-
-               if(!node_write_config(mesh, from, true)) {
-                       // ignore
-               }
-
-               /* If we are trying to form an outgoing connection to this node, retry immediately */
-               if(mesh->outgoing) {
-                       if(mesh->outgoing->node == from && mesh->outgoing->ev.cb) {
-                               mesh->outgoing->timeout = 0;
-                               timeout_set(&mesh->loop, &mesh->outgoing->ev, &(struct timespec) {
-                                       0, 0
-                               });
-                       }
-               }
-
-               /* Also reset any UTCP timers */
-               utcp_reset_timers(from->utcp);
-
-               return true;
-       }
-
-       case REQ_KEY: {
-               if(!node_read_public_key(mesh, from)) {
-                       logger(mesh, MESHLINK_DEBUG, "No ECDSA key known for %s", from->name);
-                       send_request(mesh, from->nexthop->connection, "%d %s %s %d", REQ_KEY, mesh->self->name, from->name, REQ_PUBKEY);
-                       return true;
-               }
-
-               if(from->sptps.label) {
-                       logger(mesh, MESHLINK_DEBUG, "Got REQ_KEY from %s while we already started a SPTPS session!", from->name);
-
-                       if(mesh->loop.now.tv_sec < from->last_req_key + req_key_timeout && strcmp(mesh->self->name, from->name) < 0) {
-                               logger(mesh, MESHLINK_DEBUG, "Ignoring REQ_KEY from %s.", from->name);
-                               return true;
-                       }
-               }
-
-               char buf[MAX_STRING_SIZE];
-               int len;
-
-               if(sscanf(request, "%*d %*s %*s %*d " MAX_STRING, buf) != 1 || !(len = b64decode(buf, buf, strlen(buf)))) {
-                       logger(mesh, MESHLINK_ERROR, "Got bad %s from %s: %s", "REQ_SPTPS_START", from->name, "invalid SPTPS data");
-                       return true;
-               }
-
-               char label[sizeof(meshlink_udp_label) + strlen(from->name) + strlen(mesh->self->name) + 2];
-               snprintf(label, sizeof(label), "%s %s %s", meshlink_udp_label, from->name, mesh->self->name);
-               sptps_stop(&from->sptps);
-               from->status.validkey = false;
-               from->status.waitingforkey = true;
-               from->last_req_key = mesh->loop.now.tv_sec;
-
-               /* Send our canonical address to help with UDP hole punching */
-               send_canonical_address(mesh, from);
-
-               if(!sptps_start(&from->sptps, from, false, true, mesh->private_key, from->ecdsa, label, sizeof(label) - 1, send_sptps_data, receive_sptps_record)) {
-                       logger(mesh, MESHLINK_ERROR, "Could not start SPTPS session with %s: %s", from->name, strerror(errno));
-                       return true;
-               }
-
-               if(!sptps_receive_data(&from->sptps, buf, len)) {
-                       logger(mesh, MESHLINK_ERROR, "Could not process SPTPS data from %s: %s", from->name, strerror(errno));
-                       return true;
-               }
-
-               return true;
-       }
-
-       case REQ_SPTPS: {
-               if(!from->status.validkey) {
-                       logger(mesh, MESHLINK_ERROR, "Got REQ_SPTPS from %s but we don't have a valid key yet", from->name);
-                       return true;
-               }
-
-               char buf[MAX_STRING_SIZE];
-               int len;
-
-               if(sscanf(request, "%*d %*s %*s %*d " MAX_STRING, buf) != 1 || !(len = b64decode(buf, buf, strlen(buf)))) {
-                       logger(mesh, MESHLINK_ERROR, "Got bad %s from %s: %s", "REQ_SPTPS", from->name, "invalid SPTPS data");
-                       return true;
-               }
-
-               if(!sptps_receive_data(&from->sptps, buf, len)) {
-                       logger(mesh, MESHLINK_ERROR, "Could not process SPTPS data from %s: %s", from->name, strerror(errno));
-                       return true;
-               }
-
-               return true;
-       }
-
-       case REQ_CANONICAL: {
-               char host[MAX_STRING_SIZE];
-               char port[MAX_STRING_SIZE];
-
-               if(sscanf(request, "%*d %*s %*s %*d " MAX_STRING " " MAX_STRING, host, port) != 2) {
-                       logger(mesh, MESHLINK_ERROR, "Got bad %s from %s: %s", "REQ_CANONICAL", from->name, "invalid canonical address");
-                       return true;
-               }
-
-               char *canonical_address;
-               xasprintf(&canonical_address, "%s %s", host, port);
-
-               if(mesh->log_level <= MESHLINK_DEBUG && (!from->canonical_address || strcmp(from->canonical_address, canonical_address))) {
-                       logger(mesh, MESHLINK_DEBUG, "Updating canonical address of %s to %s", from->name, canonical_address);
-               }
-
-               free(from->canonical_address);
-               from->canonical_address = canonical_address;
-               return true;
-       }
-
-       default:
-               logger(mesh, MESHLINK_ERROR, "Unknown extended REQ_KEY request from %s: %s", from->name, request);
-               return true;
-       }
-}
-
 bool req_key_h(meshlink_handle_t *mesh, connection_t *c, const char *request) {
-       assert(request);
-       assert(*request);
-
-       char from_name[MAX_STRING_SIZE];
-       char to_name[MAX_STRING_SIZE];
-       node_t *from, *to;
-       int reqno = 0;
-
-       if(sscanf(request, "%*d " MAX_STRING " " MAX_STRING " %d", from_name, to_name, &reqno) < 2) {
-               logger(mesh, MESHLINK_ERROR, "Got bad %s from %s", "REQ_KEY", c->name);
-               return false;
-       }
-
-       if(!check_id(from_name) || !check_id(to_name)) {
-               logger(mesh, MESHLINK_ERROR, "Got bad %s from %s: %s", "REQ_KEY", c->name, "invalid name");
-               return false;
-       }
-
-       from = lookup_node(mesh, from_name);
-
-       if(!from) {
-               logger(mesh, MESHLINK_ERROR, "Got %s from %s origin %s which does not exist in our connection list",
-                      "REQ_KEY", c->name, from_name);
-               return true;
-       }
-
-       to = lookup_node(mesh, to_name);
-
-       if(!to) {
-               logger(mesh, MESHLINK_ERROR, "Got %s from %s destination %s which does not exist in our connection list",
-                      "REQ_KEY", c->name, to_name);
-               return true;
-       }
-
-       /* Check if this key request is for us */
-
-       if(to == mesh->self) {                      /* Yes */
-               /* Is this an extended REQ_KEY message? */
-               if(reqno) {
-                       return req_key_ext_h(mesh, c, request, from, reqno);
-               }
-
-               /* This should never happen. Ignore it, unless it came directly from the connected peer, in which case we disconnect. */
-               return from->connection != c;
-       } else {
-               if(!to->status.reachable || !to->nexthop || !to->nexthop->connection) {
-                       logger(mesh, MESHLINK_WARNING, "Got %s from %s destination %s which is not reachable",
-                              "REQ_KEY", c->name, to_name);
-                       return true;
-               }
-
-               send_request(mesh, to->nexthop->connection, "%s", request);
-       }
-
+       (void)mesh;
+       (void)c;
+       (void)request;
        return true;
 }
 
 bool ans_key_h(meshlink_handle_t *mesh, connection_t *c, const char *request) {
-       assert(request);
-       assert(*request);
+       (void)mesh;
        (void)c;
-
-       char from_name[MAX_STRING_SIZE];
-       char to_name[MAX_STRING_SIZE];
-       char key[MAX_STRING_SIZE];
-       char address[MAX_STRING_SIZE] = "";
-       char port[MAX_STRING_SIZE] = "";
-       int cipher, digest, maclength, compression;
-       node_t *from, *to;
-
-       if(sscanf(request, "%*d "MAX_STRING" "MAX_STRING" "MAX_STRING" %d %d %d %d "MAX_STRING" "MAX_STRING,
-                       from_name, to_name, key, &cipher, &digest, &maclength,
-                       &compression, address, port) < 7) {
-               logger(mesh, MESHLINK_ERROR, "Got bad %s from %s", "ANS_KEY", c->name);
-               return false;
-       }
-
-       if(!check_id(from_name) || !check_id(to_name)) {
-               logger(mesh, MESHLINK_ERROR, "Got bad %s from %s: %s", "ANS_KEY", c->name, "invalid name");
-               return false;
-       }
-
-       from = lookup_node(mesh, from_name);
-
-       if(!from) {
-               logger(mesh, MESHLINK_ERROR, "Got %s from %s origin %s which does not exist in our connection list",
-                      "ANS_KEY", c->name, from_name);
-               return true;
-       }
-
-       to = lookup_node(mesh, to_name);
-
-       if(!to) {
-               logger(mesh, MESHLINK_ERROR, "Got %s from %s destination %s which does not exist in our connection list",
-                      "ANS_KEY", c->name, to_name);
-               return true;
-       }
-
-       /* Forward it if necessary */
-
-       if(to != mesh->self) {
-               logger(mesh, MESHLINK_WARNING, "Got %s from %s destination %s which is not for us",
-                      "ANS_KEY", c->name, to_name);
-               return true;
-       }
-
-       /* Is this an ANS_KEY informing us of our own reflexive UDP address? */
-
-       if(from == mesh->self) {
-               if(*key == '.' && *address && *port) {
-                       /* Ignore reflexive UDP address */
-               } else {
-                       logger(mesh, MESHLINK_WARNING, "Got %s from %s from %s to %s",
-                              "ANS_KEY", c->name, from_name, to_name);
-               }
-
-               return true;
-       }
-
-       /* Process SPTPS data if present */
-
-       if(*key != '.') {
-               /* Don't use key material until every check has passed. */
-               from->status.validkey = false;
-
-               /* Compression is not supported. */
-               if(compression != 0) {
-                       logger(mesh, MESHLINK_ERROR, "Node %s uses bogus compression level!", from->name);
-                       return true;
-               }
-
-               char buf[strlen(key)];
-               int len = b64decode(key, buf, strlen(key));
-
-               if(!len || !sptps_receive_data(&from->sptps, buf, len)) {
-                       logger(mesh, MESHLINK_ERROR, "Error processing SPTPS data from %s", from->name);
-               }
-       }
-
-       if(from->status.validkey) {
-               if(*address && *port) {
-                       /* Ignore reflexive UDP address */
-               }
-       }
-
+       (void)request;
        return true;
-}
+}
\ No newline at end of file
index 9218f967f26833ed0ebd369591c4cd16e66fff5f..d9466f0608afba670c37cd8c4ce36b4465d0b184 100644 (file)
@@ -100,3 +100,14 @@ bool pong_h(meshlink_handle_t *mesh, connection_t *c, const char *request) {
 
        return true;
 }
+
+bool send_raw_packet(meshlink_handle_t *mesh, connection_t *c, const vpn_packet_t *packet) {
+       return send_request(mesh, c, "%d", PACKET) && send_meta(mesh, c, (const char *)packet->data, packet->len);
+}
+
+bool raw_packet_h(meshlink_handle_t *mesh, connection_t *c, const char *request) {
+       (void)mesh;
+       (void)request;
+       c->status.raw_packet = true;
+       return true;
+}
diff --git a/src/route.c b/src/route.c
deleted file mode 100644 (file)
index ee36a9b..0000000
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
-    route.c -- routing
-    Copyright (C) 2014 Guus Sliepen <guus@meshlink.io>
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    This program 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 "system.h"
-
-#include "logger.h"
-#include "meshlink_internal.h"
-#include "net.h"
-#include "route.h"
-#include "utils.h"
-
-static bool checklength(node_t *source, vpn_packet_t *packet, uint16_t length) {
-       assert(length);
-
-       if(packet->len < length) {
-               logger(source->mesh, MESHLINK_WARNING, "Got too short packet from %s", source->name);
-               return false;
-       } else {
-               return true;
-       }
-}
-
-void route(meshlink_handle_t *mesh, node_t *source, vpn_packet_t *packet) {
-       assert(source);
-
-       // TODO: route on name or key
-
-       meshlink_packethdr_t *hdr = (meshlink_packethdr_t *) packet->data;
-       node_t *dest = lookup_node(mesh, (char *)hdr->destination);
-       logger(mesh, MESHLINK_DEBUG, "Routing packet from \"%s\" to \"%s\"\n", hdr->source, hdr->destination);
-
-       //Check Length
-       if(!checklength(source, packet, sizeof(*hdr))) {
-               return;
-       }
-
-       if(dest == NULL) {
-               //Lookup failed
-               logger(mesh, MESHLINK_WARNING, "Can't lookup the destination of a packet in the route() function. This should never happen!\n");
-               logger(mesh, MESHLINK_WARNING, "Destination was: %s\n", hdr->destination);
-               return;
-       }
-
-       if(dest == mesh->self) {
-               const void *payload = packet->data + sizeof(*hdr);
-               size_t len = packet->len - sizeof(*hdr);
-
-               char hex[len * 2 + 1];
-
-               if(mesh->log_level <= MESHLINK_DEBUG) {
-                       bin2hex(payload, hex, len);        // don't do this unless it's going to be logged
-               }
-
-               logger(mesh, MESHLINK_DEBUG, "I received a packet for me with payload: %s\n", hex);
-
-               if(mesh->receive_cb) {
-                       mesh->receive_cb(mesh, (meshlink_node_t *)source, payload, len);
-               }
-
-               return;
-       }
-
-       if(!dest->status.reachable) {
-               //TODO: check what to do here, not just print a warning
-               logger(mesh, MESHLINK_WARNING, "The destination of a packet in the route() function is unreachable. Dropping packet.\n");
-               return;
-       }
-
-       if(dest == source) {
-               logger(mesh, MESHLINK_ERROR, "Routing loop for packet from %s!", source->name);
-               return;
-       }
-
-       send_packet(mesh, dest, packet);
-       return;
-}
diff --git a/src/route.h b/src/route.h
deleted file mode 100644 (file)
index 92e9fe0..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-#ifndef MESHLINK_ROUTE_H
-#define MESHLINK_ROUTE_H
-
-/*
-    route.h -- header file for route.c
-    Copyright (C) 2014, 2017 Guus Sliepen <guus@meshlink.io>
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    This program 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 "net.h"
-#include "node.h"
-
-void route(struct meshlink_handle *mesh, struct node_t *, struct vpn_packet_t *);
-
-#endif
diff --git a/src/utcp-test.c b/src/utcp-test.c
deleted file mode 100644 (file)
index a7c0534..0000000
+++ /dev/null
@@ -1,410 +0,0 @@
-/*
-    utcp-test.c -- Test application for UTCP
-    Copyright (C) 2014-2020 Guus Sliepen <guus@tinc-vpn.org>
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    This program 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 "system.h"
-#include <poll.h>
-#include <time.h>
-
-#include "utcp.h"
-
-#define DIR_READ 1
-#define DIR_WRITE 2
-
-static struct utcp_connection *c;
-static int dir = DIR_READ | DIR_WRITE;
-static long inpktno;
-static long outpktno;
-static long dropfrom;
-static long dropto;
-static double reorder;
-static long reorder_dist = 10;
-static double dropin;
-static double dropout;
-static long total_out;
-static long total_in;
-static FILE *reference;
-static long mtu;
-static long bufsize;
-
-static char *reorder_data;
-static size_t reorder_len;
-static int reorder_countdown;
-
-#if UTCP_DEBUG
-static void debug(const char *format, ...) {
-       struct timespec tv;
-       char buf[1024];
-       int len;
-
-       clock_gettime(CLOCK_REALTIME, &tv);
-       len = snprintf(buf, sizeof(buf), "%ld.%06lu ", (long)tv.tv_sec, tv.tv_nsec / 1000);
-       va_list ap;
-       va_start(ap, format);
-       len += vsnprintf(buf + len, sizeof(buf) - len, format, ap);
-       va_end(ap);
-
-       if(len > 0 && (size_t)len < sizeof(buf)) {
-               fwrite(buf, len, 1, stderr);
-       }
-}
-#else
-#define debug(...) do {} while(0)
-#endif
-
-static ssize_t do_recv(struct utcp_connection *rc, const void *data, size_t len) {
-       (void)rc;
-
-       if(!data || !len) {
-               if(errno) {
-                       debug("Error: %s\n", strerror(errno));
-                       dir = 0;
-               } else {
-                       dir &= ~DIR_WRITE;
-                       debug("Connection closed by peer\n");
-               }
-
-               return -1;
-       }
-
-       if(reference) {
-               char buf[len];
-
-               if(fread(buf, len, 1, reference) != 1) {
-                       debug("Error reading reference\n");
-                       abort();
-               }
-
-               if(memcmp(buf, data, len)) {
-                       debug("Received data differs from reference\n");
-                       abort();
-               }
-       }
-
-       return write(1, data, len);
-}
-
-static void do_accept(struct utcp_connection *nc, uint16_t port) {
-       (void)port;
-       utcp_accept(nc, do_recv, NULL);
-       c = nc;
-
-       if(bufsize) {
-               utcp_set_sndbuf(c, NULL, bufsize);
-               utcp_set_rcvbuf(c, NULL, bufsize);
-       }
-
-       utcp_set_accept_cb(c->utcp, NULL, NULL);
-}
-
-static ssize_t do_send(struct utcp *utcp, const void *data, size_t len) {
-       int s = *(int *)utcp->priv;
-       outpktno++;
-
-       if(outpktno >= dropfrom && outpktno < dropto) {
-               if(drand48() < dropout) {
-                       debug("Dropped outgoing packet\n");
-                       return len;
-               }
-
-               if(!reorder_data && drand48() < reorder) {
-                       reorder_data = malloc(len);
-
-                       if(!reorder_data) {
-                               debug("Out of memory\n");
-                               return len;
-                       }
-
-                       reorder_len = len;
-                       memcpy(reorder_data, data, len);
-                       reorder_countdown = 1 + drand48() * reorder_dist;
-                       return len;
-               }
-       }
-
-       if(reorder_data) {
-               if(--reorder_countdown < 0) {
-                       total_out += reorder_len;
-                       send(s, reorder_data, reorder_len, MSG_DONTWAIT);
-                       free(reorder_data);
-                       reorder_data = NULL;
-               }
-       }
-
-       total_out += len;
-       ssize_t result = send(s, data, len, MSG_DONTWAIT);
-
-       if(result <= 0) {
-               debug("Error sending UDP packet: %s\n", strerror(errno));
-       }
-
-       return result;
-}
-
-static void set_mtu(struct utcp *u, int s) {
-#ifdef IP_MTU
-
-       if(!mtu) {
-               socklen_t optlen = sizeof(mtu);
-               getsockopt(s, IPPROTO_IP, IP_MTU, &mtu, &optlen);
-       }
-
-#else
-       (void)s;
-#endif
-
-       if(!mtu || mtu == 65535) {
-               mtu = 1500;
-       }
-
-       debug("Using MTU %lu\n", mtu);
-
-       utcp_set_mtu(u, mtu ? mtu - 28 : 1300);
-}
-
-int main(int argc, char *argv[]) {
-       srand(time(NULL));
-       srand48(time(NULL));
-
-       if(argc < 2 || argc > 3) {
-               return 1;
-       }
-
-       bool server = argc == 2;
-       bool connected = false;
-       uint32_t flags = UTCP_TCP;
-       size_t read_size = 102400;
-
-       if(getenv("DROPIN")) {
-               dropin = atof(getenv("DROPIN"));
-       }
-
-       if(getenv("DROPOUT")) {
-               dropout = atof(getenv("DROPOUT"));
-       }
-
-       if(getenv("DROPFROM")) {
-               dropfrom = atoi(getenv("DROPFROM"));
-       }
-
-       if(getenv("DROPTO")) {
-               dropto = atoi(getenv("DROPTO"));
-       }
-
-       if(getenv("REORDER")) {
-               reorder = atof(getenv("REORDER"));
-       }
-
-       if(getenv("REORDER_DIST")) {
-               reorder_dist = atoi(getenv("REORDER_DIST"));
-       }
-
-       if(getenv("FLAGS")) {
-               flags = atoi(getenv("FLAGS"));
-       }
-
-       if(getenv("READ_SIZE")) {
-               read_size = atoi(getenv("READ_SIZE"));
-       }
-
-       if(getenv("MTU")) {
-               mtu = atoi(getenv("MTU"));
-       }
-
-       if(getenv("BUFSIZE")) {
-               bufsize = atoi(getenv("BUFSIZE"));
-       }
-
-       char *reference_filename = getenv("REFERENCE");
-
-       if(reference_filename) {
-               reference = fopen(reference_filename, "r");
-       }
-
-       if(dropto < dropfrom) {
-               dropto = 1 << 30;
-       }
-
-       struct addrinfo *ai;
-
-       struct addrinfo hint = {
-               .ai_flags = server ? AI_PASSIVE : 0,
-               .ai_socktype = SOCK_DGRAM,
-       };
-
-       getaddrinfo(server ? NULL : argv[1], server ? argv[1] : argv[2], &hint, &ai);
-
-       if(!ai) {
-               debug("Could not lookup address: %s\n", strerror(errno));
-               return 1;
-       }
-
-       int s = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
-
-       if(s == -1) {
-               debug("Could not create socket: %s\n", strerror(errno));
-               return 1;
-       }
-
-       static const int one = 1;
-       setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &one, sizeof one);
-
-       if(server) {
-               if(bind(s, ai->ai_addr, ai->ai_addrlen)) {
-                       debug("Could not bind: %s\n", strerror(errno));
-                       return 1;
-               }
-       } else {
-#ifdef SO_NOSIGPIPE
-               int nosigpipe = 1;
-               setsockopt(s, SOL_SOCKET, SO_NOSIGPIPE, &nosigpipe, sizeof(nosigpipe));
-#endif
-
-               if(connect(s, ai->ai_addr, ai->ai_addrlen)) {
-                       debug("Could not connect: %s\n", strerror(errno));
-                       return 1;
-               }
-
-               connected = true;
-       }
-
-       freeaddrinfo(ai);
-
-       struct utcp *u = utcp_init(server ? do_accept : NULL, NULL, do_send, &s);
-
-       if(!u) {
-               debug("Could not initialize UTCP\n");
-               return 1;
-       }
-
-       utcp_set_user_timeout(u, 10);
-
-       if(!server) {
-               set_mtu(u, s);
-               c = utcp_connect_ex(u, 1, do_recv, NULL, flags);
-
-               if(bufsize) {
-                       utcp_set_sndbuf(c, NULL, bufsize);
-                       utcp_set_rcvbuf(c, NULL, bufsize);
-               }
-       }
-
-       struct pollfd fds[2] = {
-               {.fd = 0, .events = POLLIN | POLLERR | POLLHUP},
-               {.fd = s, .events = POLLIN | POLLERR | POLLHUP},
-       };
-
-       char buf[102400];
-
-       struct timespec timeout = utcp_timeout(u);
-
-       while(!connected || utcp_is_active(u)) {
-               size_t max = c ? utcp_get_sndbuf_free(c) : 0;
-
-               if(max > sizeof(buf)) {
-                       max = sizeof(buf);
-               }
-
-               if(max > read_size) {
-                       max = read_size;
-               }
-
-               int timeout_ms = timeout.tv_sec * 1000 + timeout.tv_nsec / 1000000 + 1;
-
-               debug("polling, dir = %d, timeout = %d\n", dir, timeout_ms);
-
-               if((dir & DIR_READ) && max) {
-                       poll(fds, 2, timeout_ms);
-               } else {
-                       poll(fds + 1, 1, timeout_ms);
-               }
-
-               if(fds[0].revents) {
-                       fds[0].revents = 0;
-                       ssize_t len = read(0, buf, max);
-                       debug("stdin %zd\n", len);
-
-                       if(len <= 0) {
-                               fds[0].fd = -1;
-                               dir &= ~DIR_READ;
-
-                               if(c) {
-                                       utcp_shutdown(c, SHUT_WR);
-                               }
-
-                               if(len == -1) {
-                                       break;
-                               } else {
-                                       continue;
-                               }
-                       }
-
-                       if(c) {
-                               ssize_t sent = utcp_send(c, buf, len);
-
-                               if(sent != len) {
-                                       debug("Short send: %zd != %zd\n", sent, len);
-                               }
-                       }
-               }
-
-               if(fds[1].revents) {
-                       fds[1].revents = 0;
-                       struct sockaddr_storage ss;
-                       socklen_t sl = sizeof(ss);
-                       int len = recvfrom(s, buf, sizeof(buf), MSG_DONTWAIT, (struct sockaddr *)&ss, &sl);
-                       debug("netin %zu\n", len);
-
-                       if(len <= 0) {
-                               debug("Error receiving UDP packet: %s\n", strerror(errno));
-                               break;
-                       }
-
-                       if(!connected) {
-                               if(!connect(s, (struct sockaddr *)&ss, sl)) {
-                                       connected = true;
-                                       set_mtu(u, s);
-                               }
-                       }
-
-                       inpktno++;
-
-                       if(inpktno >= dropto || inpktno < dropfrom || drand48() >= dropin) {
-                               total_in += len;
-
-                               if(utcp_recv(u, buf, len) == -1) {
-                                       debug("Error receiving UTCP packet: %s\n", strerror(errno));
-                               }
-                       } else {
-                               debug("Dropped incoming packet\n");
-                       }
-               }
-
-               timeout = utcp_timeout(u);
-       };
-
-       utcp_close(c);
-
-       utcp_exit(u);
-
-       free(reorder_data);
-
-       debug("Total bytes in: %ld, out: %ld\n", total_in, total_out);
-
-       return 0;
-}
diff --git a/src/utcp.c b/src/utcp.c
deleted file mode 100644 (file)
index 0909a01..0000000
+++ /dev/null
@@ -1,1717 +0,0 @@
-/*
-    utcp.c -- Userspace TCP
-    Copyright (C) 2014-2017 Guus Sliepen <guus@tinc-vpn.org>
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    This program 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 "system.h"
-#include <time.h>
-
-#include "utcp_priv.h"
-
-#ifndef EBADMSG
-#define EBADMSG         104
-#endif
-
-#ifndef SHUT_RDWR
-#define SHUT_RDWR 2
-#endif
-
-#ifdef poll
-#undef poll
-#endif
-
-#ifndef UTCP_CLOCK
-#if defined(CLOCK_MONOTONIC_RAW) && defined(__x86_64__)
-#define UTCP_CLOCK CLOCK_MONOTONIC_RAW
-#else
-#define UTCP_CLOCK CLOCK_MONOTONIC
-#endif
-#endif
-
-static void timespec_sub(const struct timespec *a, const struct timespec *b, struct timespec *r) {
-       r->tv_sec = a->tv_sec - b->tv_sec;
-       r->tv_nsec = a->tv_nsec - b->tv_nsec;
-
-       if(r->tv_nsec < 0) {
-               r->tv_sec--, r->tv_nsec += NSEC_PER_SEC;
-       }
-}
-
-static int32_t timespec_diff_usec(const struct timespec *a, const struct timespec *b) {
-       return (a->tv_sec - b->tv_sec) * 1000000 + (a->tv_nsec - b->tv_nsec) / 1000;
-}
-
-static bool timespec_lt(const struct timespec *a, const struct timespec *b) {
-       if(a->tv_sec == b->tv_sec) {
-               return a->tv_nsec < b->tv_nsec;
-       } else {
-               return a->tv_sec < b->tv_sec;
-       }
-}
-
-static void timespec_clear(struct timespec *a) {
-       a->tv_sec = 0;
-       a->tv_nsec = 0;
-}
-
-static bool timespec_isset(const struct timespec *a) {
-       return a->tv_sec;
-}
-
-static long CLOCK_GRANULARITY; // usec
-
-static inline size_t min(size_t a, size_t b) {
-       return a < b ? a : b;
-}
-
-static inline size_t max(size_t a, size_t b) {
-       return a > b ? a : b;
-}
-
-#ifdef UTCP_DEBUG
-#include <stdarg.h>
-
-#ifndef UTCP_DEBUG_DATALEN
-#define UTCP_DEBUG_DATALEN 20
-#endif
-
-static void debug(struct utcp_connection *c, const char *format, ...) {
-       struct timespec tv;
-       char buf[1024];
-       int len;
-
-       clock_gettime(CLOCK_REALTIME, &tv);
-       len = snprintf(buf, sizeof(buf), "%ld.%06lu %u:%u ", (long)tv.tv_sec, tv.tv_nsec / 1000, c ? c->src : 0, c ? c->dst : 0);
-       va_list ap;
-       va_start(ap, format);
-       len += vsnprintf(buf + len, sizeof(buf) - len, format, ap);
-       va_end(ap);
-
-       if(len > 0 && (size_t)len < sizeof(buf)) {
-               fwrite(buf, len, 1, stderr);
-       }
-}
-
-static void print_packet(struct utcp_connection *c, const char *dir, const void *pkt, size_t len) {
-       struct hdr hdr;
-
-       if(len < sizeof(hdr)) {
-               debug(c, "%s: short packet (%lu bytes)\n", dir, (unsigned long)len);
-               return;
-       }
-
-       memcpy(&hdr, pkt, sizeof(hdr));
-
-       uint32_t datalen;
-
-       if(len > sizeof(hdr)) {
-               datalen = min(len - sizeof(hdr), UTCP_DEBUG_DATALEN);
-       } else {
-               datalen = 0;
-       }
-
-
-       const uint8_t *data = (uint8_t *)pkt + sizeof(hdr);
-       char str[datalen * 2 + 1];
-       char *p = str;
-
-       for(uint32_t i = 0; i < datalen; i++) {
-               *p++ = "0123456789ABCDEF"[data[i] >> 4];
-               *p++ = "0123456789ABCDEF"[data[i] & 15];
-       }
-
-       *p = 0;
-
-       debug(c, "%s: len %lu src %u dst %u seq %u ack %u wnd %u aux %x ctl %s%s%s%s%s data %s\n",
-             dir, (unsigned long)len, hdr.src, hdr.dst, hdr.seq, hdr.ack, hdr.wnd, hdr.aux,
-             hdr.ctl & SYN ? "SYN" : "",
-             hdr.ctl & RST ? "RST" : "",
-             hdr.ctl & FIN ? "FIN" : "",
-             hdr.ctl & ACK ? "ACK" : "",
-             hdr.ctl & MF ? "MF" : "",
-             str
-            );
-}
-
-static void debug_cwnd(struct utcp_connection *c) {
-       debug(c, "snd.cwnd %u snd.ssthresh %u\n", c->snd.cwnd, ~c->snd.ssthresh ? c->snd.ssthresh : 0);
-}
-#else
-#define debug(...) do {} while(0)
-#define print_packet(...) do {} while(0)
-#define debug_cwnd(...) do {} while(0)
-#endif
-
-static void set_state(struct utcp_connection *c, enum state state) {
-       c->state = state;
-
-       if(state == ESTABLISHED) {
-               timespec_clear(&c->conn_timeout);
-       }
-
-       debug(c, "state %s\n", strstate[state]);
-}
-
-static bool fin_wanted(struct utcp_connection *c, uint32_t seq) {
-       if(seq != c->snd.last) {
-               return false;
-       }
-
-       switch(c->state) {
-       case FIN_WAIT_1:
-       case CLOSING:
-       case LAST_ACK:
-               return true;
-
-       default:
-               return false;
-       }
-}
-
-static int32_t seqdiff(uint32_t a, uint32_t b) {
-       return a - b;
-}
-
-// Connections are stored in a sorted list.
-// This gives O(log(N)) lookup time, O(N log(N)) insertion time and O(N) deletion time.
-
-static int compare(const void *va, const void *vb) {
-       assert(va && vb);
-
-       const struct utcp_connection *a = *(struct utcp_connection **)va;
-       const struct utcp_connection *b = *(struct utcp_connection **)vb;
-
-       assert(a && b);
-
-       int c = (int)a->src - (int)b->src;
-
-       if(c) {
-               return c;
-       }
-
-       c = (int)a->dst - (int)b->dst;
-       return c;
-}
-
-static struct utcp_connection *find_connection(const struct utcp *utcp, uint16_t src, uint16_t dst) {
-       if(!utcp->nconnections) {
-               return NULL;
-       }
-
-       struct utcp_connection key = {
-               .src = src,
-               .dst = dst,
-       }, *keyp = &key;
-       struct utcp_connection **match = bsearch(&keyp, utcp->connections, utcp->nconnections, sizeof(*utcp->connections), compare);
-       return match ? *match : NULL;
-}
-
-static void free_connection(struct utcp_connection *c) {
-       struct utcp *utcp = c->utcp;
-       struct utcp_connection **cp = bsearch(&c, utcp->connections, utcp->nconnections, sizeof(*utcp->connections), compare);
-
-       assert(cp);
-
-       int i = cp - utcp->connections;
-       memmove(cp, cp + 1, (utcp->nconnections - i - 1) * sizeof(*cp));
-       utcp->nconnections--;
-
-       free(c);
-}
-
-static struct utcp_connection *allocate_connection(struct utcp *utcp, uint16_t src, uint16_t dst) {
-       // Check whether this combination of src and dst is free
-
-       if(src) {
-               if(find_connection(utcp, src, dst)) {
-                       errno = EADDRINUSE;
-                       return NULL;
-               }
-       } else { // If src == 0, generate a random port number with the high bit set
-               if(utcp->nconnections >= 32767) {
-                       errno = ENOMEM;
-                       return NULL;
-               }
-
-               src = rand() | 0x8000;
-
-               while(find_connection(utcp, src, dst)) {
-                       src++;
-               }
-       }
-
-       // Allocate memory for the new connection
-
-       if(utcp->nconnections >= utcp->nallocated) {
-               if(!utcp->nallocated) {
-                       utcp->nallocated = 4;
-               } else {
-                       utcp->nallocated *= 2;
-               }
-
-               struct utcp_connection **new_array = realloc(utcp->connections, utcp->nallocated * sizeof(*utcp->connections));
-
-               if(!new_array) {
-                       return NULL;
-               }
-
-               utcp->connections = new_array;
-       }
-
-       struct utcp_connection *c = calloc(1, sizeof(*c));
-
-       if(!c) {
-               return NULL;
-       }
-
-       // Fill in the details
-
-       c->src = src;
-       c->dst = dst;
-#ifdef UTCP_DEBUG
-       c->snd.iss = 0;
-#else
-       c->snd.iss = rand();
-#endif
-       c->snd.una = c->snd.iss;
-       c->snd.nxt = c->snd.iss + 1;
-       c->snd.last = c->snd.nxt;
-       c->snd.cwnd = (utcp->mss > 2190 ? 2 : utcp->mss > 1095 ? 3 : 4) * utcp->mss;
-       c->snd.ssthresh = ~0;
-       debug_cwnd(c);
-       c->srtt = 0;
-       c->rttvar = 0;
-       c->rto = START_RTO;
-       c->utcp = utcp;
-
-       // Add it to the sorted list of connections
-
-       utcp->connections[utcp->nconnections++] = c;
-       qsort(utcp->connections, utcp->nconnections, sizeof(*utcp->connections), compare);
-
-       return c;
-}
-
-static inline uint32_t absdiff(uint32_t a, uint32_t b) {
-       if(a > b) {
-               return a - b;
-       } else {
-               return b - a;
-       }
-}
-
-// Update RTT variables. See RFC 6298.
-static void update_rtt(struct utcp_connection *c, uint32_t rtt) {
-       if(!rtt) {
-               debug(c, "invalid rtt\n");
-               return;
-       }
-
-       if(!c->srtt) {
-               c->srtt = rtt;
-               c->rttvar = rtt / 2;
-       } else {
-               c->rttvar = (c->rttvar * 3 + absdiff(c->srtt, rtt)) / 4;
-               c->srtt = (c->srtt * 7 + rtt) / 8;
-       }
-
-       c->rto = c->srtt + max(4 * c->rttvar, CLOCK_GRANULARITY);
-
-       if(c->rto > MAX_RTO) {
-               c->rto = MAX_RTO;
-       }
-
-       debug(c, "rtt %u srtt %u rttvar %u rto %u\n", rtt, c->srtt, c->rttvar, c->rto);
-}
-
-static void start_retransmit_timer(struct utcp_connection *c) {
-       clock_gettime(UTCP_CLOCK, &c->rtrx_timeout);
-
-       uint32_t rto = c->rto;
-
-       while(rto > USEC_PER_SEC) {
-               c->rtrx_timeout.tv_sec++;
-               rto -= USEC_PER_SEC;
-       }
-
-       c->rtrx_timeout.tv_nsec += rto * 1000;
-
-       if(c->rtrx_timeout.tv_nsec >= NSEC_PER_SEC) {
-               c->rtrx_timeout.tv_nsec -= NSEC_PER_SEC;
-               c->rtrx_timeout.tv_sec++;
-       }
-
-       debug(c, "rtrx_timeout %ld.%06lu\n", c->rtrx_timeout.tv_sec, c->rtrx_timeout.tv_nsec);
-}
-
-static void stop_retransmit_timer(struct utcp_connection *c) {
-       timespec_clear(&c->rtrx_timeout);
-       debug(c, "rtrx_timeout cleared\n");
-}
-
-struct utcp_connection *utcp_connect_ex(struct utcp *utcp, uint16_t dst, utcp_recv_t recv, void *priv, uint32_t flags) {
-       struct utcp_connection *c = allocate_connection(utcp, 0, dst);
-
-       if(!c) {
-               return NULL;
-       }
-
-       assert(flags == 0); // UDP only
-
-       c->flags = flags;
-       c->recv = recv;
-       c->priv = priv;
-
-       struct {
-               struct hdr hdr;
-               uint8_t init[4];
-       } pkt;
-
-       pkt.hdr.src = c->src;
-       pkt.hdr.dst = c->dst;
-       pkt.hdr.seq = c->snd.iss;
-       pkt.hdr.ack = 0;
-       pkt.hdr.wnd = c->utcp->mtu;
-       pkt.hdr.ctl = SYN;
-       pkt.hdr.aux = 0x0101;
-       pkt.init[0] = 1;
-       pkt.init[1] = 0;
-       pkt.init[2] = 0;
-       pkt.init[3] = flags & 0x7;
-
-       set_state(c, SYN_SENT);
-
-       print_packet(c, "send", &pkt, sizeof(pkt));
-       utcp->send(utcp, &pkt, sizeof(pkt));
-
-       clock_gettime(UTCP_CLOCK, &c->conn_timeout);
-       c->conn_timeout.tv_sec += utcp->timeout;
-
-       start_retransmit_timer(c);
-
-       return c;
-}
-
-void utcp_accept(struct utcp_connection *c, utcp_recv_t recv, void *priv) {
-       if(c->reapable || c->state != SYN_RECEIVED) {
-               debug(c, "accept() called on invalid connection in state %s\n", c, strstate[c->state]);
-               return;
-       }
-
-       debug(c, "accepted %p %p\n", c, recv, priv);
-       c->recv = recv;
-       c->priv = priv;
-       set_state(c, ESTABLISHED);
-}
-
-static void ack(struct utcp_connection *c, const void *data, size_t len) {
-       struct {
-               struct hdr hdr;
-               uint8_t data[];
-       } *pkt = c->utcp->pkt;
-
-       pkt->hdr.src = c->src;
-       pkt->hdr.dst = c->dst;
-       pkt->hdr.ack = c->rcv.nxt;
-       pkt->hdr.wnd = 0;
-       pkt->hdr.ctl = ACK;
-       pkt->hdr.aux = 0;
-
-       uint32_t seglen = len;
-       pkt->hdr.seq = c->snd.nxt;
-
-       c->snd.nxt += seglen;
-
-       if(fin_wanted(c, c->snd.nxt)) {
-               pkt->hdr.ctl |= FIN;
-       }
-
-       if(data && len) {
-               assert(len <= c->utcp->mtu);
-               memcpy(pkt->data, data, len);
-       } else {
-               assert(!data && !len);
-       }
-
-       if(!c->rtt_start.tv_sec) {
-               // Start RTT measurement
-               clock_gettime(UTCP_CLOCK, &c->rtt_start);
-               c->rtt_seq = pkt->hdr.seq + seglen;
-               debug(c, "starting RTT measurement, expecting ack %u\n", c->rtt_seq);
-       }
-
-       print_packet(c, "send", pkt, sizeof(pkt->hdr) + seglen);
-       c->utcp->send(c->utcp, pkt, sizeof(pkt->hdr) + seglen);
-}
-
-ssize_t utcp_send(struct utcp_connection *c, const void *data, size_t len) {
-       if(c->reapable) {
-               debug(c, "send() called on closed connection\n");
-               errno = EBADF;
-               return -1;
-       }
-
-       switch(c->state) {
-       case CLOSED:
-       case LISTEN:
-               debug(c, "send() called on unconnected connection\n");
-               errno = ENOTCONN;
-               return -1;
-
-       case SYN_SENT:
-       case SYN_RECEIVED:
-       case ESTABLISHED:
-       case CLOSE_WAIT:
-               break;
-
-       case FIN_WAIT_1:
-       case FIN_WAIT_2:
-       case CLOSING:
-       case LAST_ACK:
-       case TIME_WAIT:
-               debug(c, "send() called on closed connection\n");
-               errno = EPIPE;
-               return -1;
-       }
-
-       // Exit early if we have nothing to send.
-
-       if(!len) {
-               return 0;
-       }
-
-       if(!data) {
-               errno = EFAULT;
-               return -1;
-       }
-
-       if(len > MAX_UNRELIABLE_SIZE || len > c->utcp->mtu) {
-               errno = EMSGSIZE;
-               return -1;
-       }
-
-       if(len <= 0) {
-               return len;
-       }
-
-       c->snd.last += len;
-
-       // Don't send anything yet if the connection has not fully established yet
-
-       if(c->state == SYN_SENT || c->state == SYN_RECEIVED) {
-               return len;
-       }
-
-       ack(c, data, len);
-
-       c->snd.una = c->snd.nxt = c->snd.last;
-
-       return len;
-}
-
-static void swap_ports(struct hdr *hdr) {
-       uint16_t tmp = hdr->src;
-       hdr->src = hdr->dst;
-       hdr->dst = tmp;
-}
-
-static void retransmit(struct utcp_connection *c) {
-       if(c->state == CLOSED || c->snd.last == c->snd.una) {
-               debug(c, "retransmit() called but nothing to retransmit!\n");
-               stop_retransmit_timer(c);
-               return;
-       }
-
-       struct utcp *utcp = c->utcp;
-
-       struct {
-               struct hdr hdr;
-               uint8_t data[];
-       } *pkt = c->utcp->pkt;
-
-       pkt->hdr.src = c->src;
-       pkt->hdr.dst = c->dst;
-       pkt->hdr.wnd = c->utcp->mtu;
-       pkt->hdr.aux = 0;
-
-       switch(c->state) {
-       case SYN_SENT:
-               // Send our SYN again
-               pkt->hdr.seq = c->snd.iss;
-               pkt->hdr.ack = 0;
-               pkt->hdr.ctl = SYN;
-               pkt->hdr.aux = 0x0101;
-               pkt->data[0] = 1;
-               pkt->data[1] = 0;
-               pkt->data[2] = 0;
-               pkt->data[3] = c->flags & 0x7;
-               print_packet(c, "rtrx", pkt, sizeof(pkt->hdr) + 4);
-               utcp->send(utcp, pkt, sizeof(pkt->hdr) + 4);
-               break;
-
-       case SYN_RECEIVED:
-               // Send SYNACK again
-               pkt->hdr.seq = c->snd.nxt;
-               pkt->hdr.ack = c->rcv.nxt;
-               pkt->hdr.ctl = SYN | ACK;
-               print_packet(c, "rtrx", pkt, sizeof(pkt->hdr));
-               utcp->send(utcp, pkt, sizeof(pkt->hdr));
-               break;
-
-       case ESTABLISHED:
-               break;
-
-       case FIN_WAIT_1:
-       case CLOSE_WAIT:
-       case CLOSING:
-       case LAST_ACK:
-               // Send unacked data again.
-               pkt->hdr.seq = c->snd.una;
-               pkt->hdr.ack = c->rcv.nxt;
-               pkt->hdr.ctl = ACK;
-               uint32_t len = min(seqdiff(c->snd.last, c->snd.una), utcp->mss);
-
-               if(fin_wanted(c, c->snd.una + len)) {
-                       len--;
-                       pkt->hdr.ctl |= FIN;
-               } else {
-                       break;
-               }
-
-               assert(len == 0);
-
-               print_packet(c, "rtrx", pkt, sizeof(pkt->hdr) + len);
-               utcp->send(utcp, pkt, sizeof(pkt->hdr) + len);
-               break;
-
-       case CLOSED:
-       case LISTEN:
-       case TIME_WAIT:
-       case FIN_WAIT_2:
-               // We shouldn't need to retransmit anything in this state.
-#ifdef UTCP_DEBUG
-               abort();
-#endif
-               stop_retransmit_timer(c);
-               goto cleanup;
-       }
-
-       start_retransmit_timer(c);
-       c->rto *= 2;
-
-       if(c->rto > MAX_RTO) {
-               c->rto = MAX_RTO;
-       }
-
-       c->rtt_start.tv_sec = 0; // invalidate RTT timer
-       c->dupack = 0; // cancel any ongoing fast recovery
-
-cleanup:
-       return;
-}
-
-static void handle_unreliable(struct utcp_connection *c, const struct hdr *hdr, const void *data, size_t len) {
-       // Fast path for unfragmented packets
-       if(!hdr->wnd && !(hdr->ctl & MF)) {
-               if(c->recv) {
-                       c->recv(c, data, len);
-               }
-
-               c->rcv.nxt = hdr->seq + len;
-               return;
-       }
-}
-
-static void handle_incoming_data(struct utcp_connection *c, const struct hdr *hdr, const void *data, size_t len) {
-       handle_unreliable(c, hdr, data, len);
-}
-
-ssize_t utcp_recv(struct utcp *utcp, const void *data, size_t len) {
-       const uint8_t *ptr = data;
-
-       if(!utcp) {
-               errno = EFAULT;
-               return -1;
-       }
-
-       if(!len) {
-               return 0;
-       }
-
-       if(!data) {
-               errno = EFAULT;
-               return -1;
-       }
-
-       // Drop packets smaller than the header
-
-       struct hdr hdr;
-
-       if(len < sizeof(hdr)) {
-               print_packet(NULL, "recv", data, len);
-               errno = EBADMSG;
-               return -1;
-       }
-
-       // Make a copy from the potentially unaligned data to a struct hdr
-
-       memcpy(&hdr, ptr, sizeof(hdr));
-
-       // Try to match the packet to an existing connection
-
-       struct utcp_connection *c = find_connection(utcp, hdr.dst, hdr.src);
-       print_packet(c, "recv", data, len);
-
-       // Process the header
-
-       ptr += sizeof(hdr);
-       len -= sizeof(hdr);
-
-       // Drop packets with an unknown CTL flag
-
-       if(hdr.ctl & ~(SYN | ACK | RST | FIN | MF)) {
-               print_packet(NULL, "recv", data, len);
-               errno = EBADMSG;
-               return -1;
-       }
-
-       // Check for auxiliary headers
-
-       const uint8_t *init = NULL;
-
-       uint16_t aux = hdr.aux;
-
-       while(aux) {
-               size_t auxlen = 4 * (aux >> 8) & 0xf;
-               uint8_t auxtype = aux & 0xff;
-
-               if(len < auxlen) {
-                       errno = EBADMSG;
-                       return -1;
-               }
-
-               switch(auxtype) {
-               case AUX_INIT:
-                       if(!(hdr.ctl & SYN) || auxlen != 4) {
-                               errno = EBADMSG;
-                               return -1;
-                       }
-
-                       init = ptr;
-                       break;
-
-               default:
-                       errno = EBADMSG;
-                       return -1;
-               }
-
-               len -= auxlen;
-               ptr += auxlen;
-
-               if(!(aux & 0x800)) {
-                       break;
-               }
-
-               if(len < 2) {
-                       errno = EBADMSG;
-                       return -1;
-               }
-
-               memcpy(&aux, ptr, 2);
-               len -= 2;
-               ptr += 2;
-       }
-
-       // Is it for a new connection?
-
-       if(!c) {
-               // Ignore RST packets
-
-               if(hdr.ctl & RST) {
-                       return 0;
-               }
-
-               // Is it a SYN packet and are we LISTENing?
-
-               if(hdr.ctl & SYN && !(hdr.ctl & ACK) && utcp->accept) {
-                       // If we don't want to accept it, send a RST back
-                       if((utcp->listen && !utcp->listen(utcp, hdr.dst))) {
-                               len = 1;
-                               goto reset;
-                       }
-
-                       // Try to allocate memory, otherwise send a RST back
-                       c = allocate_connection(utcp, hdr.dst, hdr.src);
-
-                       if(!c) {
-                               len = 1;
-                               goto reset;
-                       }
-
-                       // Parse auxilliary information
-                       if(init) {
-                               if(init[0] < 1) {
-                                       len = 1;
-                                       goto reset;
-                               }
-
-                               c->flags = init[3] & 0x7;
-                       } else {
-                               c->flags = UTCP_UDP;
-                       }
-
-synack:
-                       // Return SYN+ACK, go to SYN_RECEIVED state
-                       c->snd.wnd = hdr.wnd;
-                       c->rcv.irs = hdr.seq;
-                       c->rcv.nxt = c->rcv.irs + 1;
-                       set_state(c, SYN_RECEIVED);
-
-                       struct {
-                               struct hdr hdr;
-                               uint8_t data[4];
-                       } pkt;
-
-                       pkt.hdr.src = c->src;
-                       pkt.hdr.dst = c->dst;
-                       pkt.hdr.ack = c->rcv.irs + 1;
-                       pkt.hdr.seq = c->snd.iss;
-                       pkt.hdr.wnd = c->utcp->mtu;
-                       pkt.hdr.ctl = SYN | ACK;
-
-                       if(init) {
-                               pkt.hdr.aux = 0x0101;
-                               pkt.data[0] = 1;
-                               pkt.data[1] = 0;
-                               pkt.data[2] = 0;
-                               pkt.data[3] = c->flags & 0x7;
-                               print_packet(c, "send", &pkt, sizeof(hdr) + 4);
-                               utcp->send(utcp, &pkt, sizeof(hdr) + 4);
-                       } else {
-                               pkt.hdr.aux = 0;
-                               print_packet(c, "send", &pkt, sizeof(hdr));
-                               utcp->send(utcp, &pkt, sizeof(hdr));
-                       }
-
-                       start_retransmit_timer(c);
-               } else {
-                       // No, we don't want your packets, send a RST back
-                       len = 1;
-                       goto reset;
-               }
-
-               return 0;
-       }
-
-       debug(c, "state %s\n", strstate[c->state]);
-
-       // In case this is for a CLOSED connection, ignore the packet.
-       // TODO: make it so incoming packets can never match a CLOSED connection.
-
-       if(c->state == CLOSED) {
-               debug(c, "got packet for closed connection\n");
-               goto reset;
-       }
-
-       // It is for an existing connection.
-
-       // 1. Drop invalid packets.
-
-       // 1a. Drop packets that should not happen in our current state.
-
-       switch(c->state) {
-       case SYN_SENT:
-       case SYN_RECEIVED:
-       case ESTABLISHED:
-       case FIN_WAIT_1:
-       case FIN_WAIT_2:
-       case CLOSE_WAIT:
-       case CLOSING:
-       case LAST_ACK:
-       case TIME_WAIT:
-               break;
-
-       default:
-#ifdef UTCP_DEBUG
-               abort();
-#endif
-               break;
-       }
-
-#if UTCP_DEBUG
-       int32_t rcv_offset = seqdiff(hdr.seq, c->rcv.nxt);
-
-       if(rcv_offset) {
-               debug(c, "packet out of order, offset %u bytes", rcv_offset);
-       }
-
-#endif
-
-       c->snd.wnd = hdr.wnd; // TODO: move below
-
-       // 1c. Drop packets with an invalid ACK.
-       // ackno should not roll back, and it should also not be bigger than what we ever could have sent
-       // (= snd.una + c->sndbuf.used).
-
-       if(hdr.ack != c->snd.last && c->state >= ESTABLISHED) {
-               hdr.ack = c->snd.una;
-       }
-
-       // 2. Handle RST packets
-
-       if(hdr.ctl & RST) {
-               switch(c->state) {
-               case SYN_SENT:
-                       if(!(hdr.ctl & ACK)) {
-                               return 0;
-                       }
-
-                       // The peer has refused our connection.
-                       set_state(c, CLOSED);
-                       errno = ECONNREFUSED;
-
-                       if(c->recv) {
-                               c->recv(c, NULL, 0);
-                       }
-
-                       return 0;
-
-               case SYN_RECEIVED:
-                       if(hdr.ctl & ACK) {
-                               return 0;
-                       }
-
-                       // We haven't told the application about this connection yet. Silently delete.
-                       free_connection(c);
-                       return 0;
-
-               case ESTABLISHED:
-               case FIN_WAIT_1:
-               case FIN_WAIT_2:
-               case CLOSE_WAIT:
-                       if(hdr.ctl & ACK) {
-                               return 0;
-                       }
-
-                       // The peer has aborted our connection.
-                       set_state(c, CLOSED);
-                       errno = ECONNRESET;
-
-                       if(c->recv) {
-                               c->recv(c, NULL, 0);
-                       }
-
-                       return 0;
-
-               case CLOSING:
-               case LAST_ACK:
-               case TIME_WAIT:
-                       if(hdr.ctl & ACK) {
-                               return 0;
-                       }
-
-                       // As far as the application is concerned, the connection has already been closed.
-                       // If it has called utcp_close() already, we can immediately free this connection.
-                       if(c->reapable) {
-                               free_connection(c);
-                               return 0;
-                       }
-
-                       // Otherwise, immediately move to the CLOSED state.
-                       set_state(c, CLOSED);
-                       return 0;
-
-               default:
-#ifdef UTCP_DEBUG
-                       abort();
-#endif
-                       break;
-               }
-       }
-
-       uint32_t advanced;
-
-       if(!(hdr.ctl & ACK)) {
-               advanced = 0;
-               goto skip_ack;
-       }
-
-       // 3. Advance snd.una
-
-       if(seqdiff(hdr.ack, c->snd.last) > 0 || seqdiff(hdr.ack, c->snd.una) < 0) {
-               debug(c, "packet ack seqno out of range, %u <= %u < %u\n", c->snd.una, hdr.ack, c->snd.una + c->sndbuf.used);
-               goto reset;
-       }
-
-       advanced = seqdiff(hdr.ack, c->snd.una);
-
-       if(advanced) {
-               // RTT measurement
-               if(c->rtt_start.tv_sec) {
-                       if(c->rtt_seq == hdr.ack) {
-                               struct timespec now;
-                               clock_gettime(UTCP_CLOCK, &now);
-                               int32_t diff = timespec_diff_usec(&now, &c->rtt_start);
-                               update_rtt(c, diff);
-                               c->rtt_start.tv_sec = 0;
-                       } else if(c->rtt_seq < hdr.ack) {
-                               debug(c, "cancelling RTT measurement: %u < %u\n", c->rtt_seq, hdr.ack);
-                               c->rtt_start.tv_sec = 0;
-                       }
-               }
-
-               int32_t data_acked = advanced;
-
-               switch(c->state) {
-               case SYN_SENT:
-               case SYN_RECEIVED:
-                       data_acked--;
-                       break;
-
-               // TODO: handle FIN as well.
-               default:
-                       break;
-               }
-
-               assert(data_acked >= 0);
-
-#ifndef NDEBUG
-               int32_t bufused = seqdiff(c->snd.last, c->snd.una);
-               assert(data_acked <= bufused);
-#endif
-
-               // Also advance snd.nxt if possible
-               if(seqdiff(c->snd.nxt, hdr.ack) < 0) {
-                       c->snd.nxt = hdr.ack;
-               }
-
-               c->snd.una = hdr.ack;
-
-               if(c->dupack) {
-                       if(c->dupack >= 3) {
-                               debug(c, "fast recovery ended\n");
-                               c->snd.cwnd = c->snd.ssthresh;
-                       }
-
-                       c->dupack = 0;
-               }
-
-               // Increase the congestion window according to RFC 5681
-               if(c->snd.cwnd < c->snd.ssthresh) {
-                       c->snd.cwnd += min(advanced, utcp->mss); // eq. 2
-               } else {
-                       c->snd.cwnd += max(1, (utcp->mss * utcp->mss) / c->snd.cwnd); // eq. 3
-               }
-
-               if(c->snd.cwnd > c->utcp->mtu) {
-                       c->snd.cwnd = c->utcp->mtu;
-               }
-
-               debug_cwnd(c);
-
-               // Check if we have sent a FIN that is now ACKed.
-               switch(c->state) {
-               case FIN_WAIT_1:
-                       if(c->snd.una == c->snd.last) {
-                               set_state(c, FIN_WAIT_2);
-                       }
-
-                       break;
-
-               case CLOSING:
-                       if(c->snd.una == c->snd.last) {
-                               clock_gettime(UTCP_CLOCK, &c->conn_timeout);
-                               c->conn_timeout.tv_sec += utcp->timeout;
-                               set_state(c, TIME_WAIT);
-                       }
-
-                       break;
-
-               default:
-                       break;
-               }
-       }
-
-       // 4. Update timers
-
-       if(advanced) {
-               if(c->snd.una == c->snd.last) {
-                       stop_retransmit_timer(c);
-                       timespec_clear(&c->conn_timeout);
-               }
-       }
-
-skip_ack:
-       // 5. Process SYN stuff
-
-       if(hdr.ctl & SYN) {
-               switch(c->state) {
-               case SYN_SENT:
-
-                       // This is a SYNACK. It should always have ACKed the SYN.
-                       if(!advanced) {
-                               goto reset;
-                       }
-
-                       c->rcv.irs = hdr.seq;
-                       c->rcv.nxt = hdr.seq + 1;
-
-                       if(c->shut_wr) {
-                               c->snd.last++;
-                               set_state(c, FIN_WAIT_1);
-                       } else {
-                               set_state(c, ESTABLISHED);
-                       }
-
-                       break;
-
-               case SYN_RECEIVED:
-                       // This is a retransmit of a SYN, send back the SYNACK.
-                       goto synack;
-
-               case ESTABLISHED:
-               case FIN_WAIT_1:
-               case FIN_WAIT_2:
-               case CLOSE_WAIT:
-               case CLOSING:
-               case LAST_ACK:
-               case TIME_WAIT:
-                       // This could be a retransmission. Ignore the SYN flag, but send an ACK back.
-                       break;
-
-               default:
-#ifdef UTCP_DEBUG
-                       abort();
-#endif
-                       return 0;
-               }
-       }
-
-       // 6. Process new data
-
-       if(c->state == SYN_RECEIVED) {
-               // This is the ACK after the SYNACK. It should always have ACKed the SYNACK.
-               if(!advanced) {
-                       goto reset;
-               }
-
-               // Are we still LISTENing?
-               if(utcp->accept) {
-                       utcp->accept(c, c->src);
-               }
-
-               if(c->state != ESTABLISHED) {
-                       set_state(c, CLOSED);
-                       c->reapable = true;
-                       goto reset;
-               }
-       }
-
-       if(len) {
-               switch(c->state) {
-               case SYN_SENT:
-               case SYN_RECEIVED:
-                       // This should never happen.
-#ifdef UTCP_DEBUG
-                       abort();
-#endif
-                       return 0;
-
-               case ESTABLISHED:
-                       break;
-
-               case FIN_WAIT_1:
-               case FIN_WAIT_2:
-                       if(c->reapable) {
-                               // We already closed the connection and are not interested in more data.
-                               goto reset;
-                       }
-
-                       break;
-
-               case CLOSE_WAIT:
-               case CLOSING:
-               case LAST_ACK:
-               case TIME_WAIT:
-                       // Ehm no, We should never receive more data after a FIN.
-                       goto reset;
-
-               default:
-#ifdef UTCP_DEBUG
-                       abort();
-#endif
-                       return 0;
-               }
-
-               handle_incoming_data(c, &hdr, ptr, len);
-       }
-
-       // 7. Process FIN stuff
-
-       if(hdr.ctl & FIN) {
-               switch(c->state) {
-               case SYN_SENT:
-               case SYN_RECEIVED:
-                       // This should never happen.
-#ifdef UTCP_DEBUG
-                       abort();
-#endif
-                       break;
-
-               case ESTABLISHED:
-                       set_state(c, CLOSE_WAIT);
-                       break;
-
-               case FIN_WAIT_1:
-                       set_state(c, CLOSING);
-                       break;
-
-               case FIN_WAIT_2:
-                       clock_gettime(UTCP_CLOCK, &c->conn_timeout);
-                       c->conn_timeout.tv_sec += utcp->timeout;
-                       set_state(c, TIME_WAIT);
-                       break;
-
-               case CLOSE_WAIT:
-               case CLOSING:
-               case LAST_ACK:
-               case TIME_WAIT:
-                       // Ehm, no. We should never receive a second FIN.
-                       goto reset;
-
-               default:
-#ifdef UTCP_DEBUG
-                       abort();
-#endif
-                       break;
-               }
-
-               // FIN counts as one sequence number
-               c->rcv.nxt++;
-               len++;
-
-               // Inform the application that the peer closed its end of the connection.
-               if(c->recv) {
-                       errno = 0;
-                       c->recv(c, NULL, 0);
-               }
-       }
-
-       // Now we send something back if:
-       // - we received data, so we have to send back an ACK
-       //   -> sendatleastone = true
-       // - or we got an ack, so we should maybe send a bit more data
-       //   -> sendatleastone = false
-
-       if(hdr.ctl & SYN || hdr.ctl & FIN) {
-               ack(c, NULL, 0);
-       }
-
-       return 0;
-
-reset:
-       swap_ports(&hdr);
-       hdr.wnd = 0;
-       hdr.aux = 0;
-
-       if(hdr.ctl & ACK) {
-               hdr.seq = hdr.ack;
-               hdr.ctl = RST;
-       } else {
-               hdr.ack = hdr.seq + len;
-               hdr.seq = 0;
-               hdr.ctl = RST | ACK;
-       }
-
-       print_packet(c, "send", &hdr, sizeof(hdr));
-       utcp->send(utcp, &hdr, sizeof(hdr));
-       return 0;
-
-}
-
-int utcp_shutdown(struct utcp_connection *c, int dir) {
-       debug(c, "shutdown %d at %u\n", dir, c ? c->snd.last : 0);
-
-       if(!c) {
-               errno = EFAULT;
-               return -1;
-       }
-
-       if(c->reapable) {
-               debug(c, "shutdown() called on closed connection\n");
-               errno = EBADF;
-               return -1;
-       }
-
-       if(!(dir == UTCP_SHUT_RD || dir == UTCP_SHUT_WR || dir == UTCP_SHUT_RDWR)) {
-               errno = EINVAL;
-               return -1;
-       }
-
-       // TCP does not have a provision for stopping incoming packets.
-       // The best we can do is to just ignore them.
-       if(dir == UTCP_SHUT_RD || dir == UTCP_SHUT_RDWR) {
-               c->recv = NULL;
-       }
-
-       // The rest of the code deals with shutting down writes.
-       if(dir == UTCP_SHUT_RD) {
-               return 0;
-       }
-
-       // Only process shutting down writes once.
-       if(c->shut_wr) {
-               return 0;
-       }
-
-       c->shut_wr = true;
-
-       switch(c->state) {
-       case CLOSED:
-       case LISTEN:
-               errno = ENOTCONN;
-               return -1;
-
-       case SYN_SENT:
-               return 0;
-
-       case SYN_RECEIVED:
-       case ESTABLISHED:
-               set_state(c, FIN_WAIT_1);
-               break;
-
-       case FIN_WAIT_1:
-       case FIN_WAIT_2:
-               return 0;
-
-       case CLOSE_WAIT:
-               set_state(c, CLOSING);
-               break;
-
-       case CLOSING:
-       case LAST_ACK:
-       case TIME_WAIT:
-               return 0;
-       }
-
-       c->snd.last++;
-
-       ack(c, NULL, 0);
-
-       if(!timespec_isset(&c->rtrx_timeout)) {
-               start_retransmit_timer(c);
-       }
-
-       return 0;
-}
-
-static bool reset_connection(struct utcp_connection *c) {
-       if(!c) {
-               errno = EFAULT;
-               return false;
-       }
-
-       if(c->reapable) {
-               debug(c, "abort() called on closed connection\n");
-               errno = EBADF;
-               return false;
-       }
-
-       switch(c->state) {
-       case CLOSED:
-               return true;
-
-       case LISTEN:
-       case SYN_SENT:
-       case CLOSING:
-       case LAST_ACK:
-       case TIME_WAIT:
-               set_state(c, CLOSED);
-               return true;
-
-       case SYN_RECEIVED:
-       case ESTABLISHED:
-       case FIN_WAIT_1:
-       case FIN_WAIT_2:
-       case CLOSE_WAIT:
-               set_state(c, CLOSED);
-               break;
-       }
-
-       // Send RST
-
-       struct hdr hdr;
-
-       hdr.src = c->src;
-       hdr.dst = c->dst;
-       hdr.seq = c->snd.nxt;
-       hdr.ack = c->rcv.nxt;
-       hdr.wnd = 0;
-       hdr.ctl = RST;
-       hdr.aux = 0;
-
-       print_packet(c, "send", &hdr, sizeof(hdr));
-       c->utcp->send(c->utcp, &hdr, sizeof(hdr));
-       return true;
-}
-
-static void set_reapable(struct utcp_connection *c) {
-       c->recv = NULL;
-       c->reapable = true;
-}
-
-// Resets all connections, but does not invalidate connection handles
-void utcp_reset_all_connections(struct utcp *utcp) {
-       if(!utcp) {
-               errno = EINVAL;
-               return;
-       }
-
-       for(int i = 0; i < utcp->nconnections; i++) {
-               struct utcp_connection *c = utcp->connections[i];
-
-               if(c->reapable || c->state == CLOSED) {
-                       continue;
-               }
-
-               reset_connection(c);
-
-               if(c->recv) {
-                       errno = 0;
-                       c->recv(c, NULL, 0);
-               }
-       }
-
-       return;
-}
-
-int utcp_close(struct utcp_connection *c) {
-       if(utcp_shutdown(c, SHUT_RDWR) && errno != ENOTCONN) {
-               return -1;
-       }
-
-       set_reapable(c);
-       return 0;
-}
-
-int utcp_abort(struct utcp_connection *c) {
-       if(!reset_connection(c)) {
-               return -1;
-       }
-
-       set_reapable(c);
-       return 0;
-}
-
-/* Handle timeouts.
- * One call to this function will loop through all connections,
- * checking if something needs to be resent or not.
- * The return value is the time to the next timeout in milliseconds,
- * or maybe a negative value if the timeout is infinite.
- */
-struct timespec utcp_timeout(struct utcp *utcp) {
-       struct timespec now;
-       clock_gettime(UTCP_CLOCK, &now);
-       struct timespec next = {now.tv_sec + 3600, now.tv_nsec};
-
-       for(int i = 0; i < utcp->nconnections; i++) {
-               struct utcp_connection *c = utcp->connections[i];
-
-               if(!c) {
-                       continue;
-               }
-
-               // delete connections that have been utcp_close()d.
-               if(c->state == CLOSED) {
-                       if(c->reapable) {
-                               debug(c, "reaping\n");
-                               free_connection(c);
-                               i--;
-                       }
-
-                       continue;
-               }
-
-               if(timespec_isset(&c->conn_timeout) && timespec_lt(&c->conn_timeout, &now)) {
-                       errno = ETIMEDOUT;
-                       c->state = CLOSED;
-
-                       if(c->recv) {
-                               c->recv(c, NULL, 0);
-                       }
-
-                       continue;
-               }
-
-               if(timespec_isset(&c->rtrx_timeout) && timespec_lt(&c->rtrx_timeout, &now)) {
-                       debug(c, "retransmitting after timeout\n");
-                       retransmit(c);
-               }
-
-               if(timespec_isset(&c->conn_timeout) && timespec_lt(&c->conn_timeout, &next)) {
-                       next = c->conn_timeout;
-               }
-
-               if(timespec_isset(&c->rtrx_timeout) && timespec_lt(&c->rtrx_timeout, &next)) {
-                       next = c->rtrx_timeout;
-               }
-       }
-
-       struct timespec diff;
-
-       timespec_sub(&next, &now, &diff);
-
-       return diff;
-}
-
-bool utcp_is_active(struct utcp *utcp) {
-       if(!utcp) {
-               return false;
-       }
-
-       for(int i = 0; i < utcp->nconnections; i++)
-               if(utcp->connections[i]->state != CLOSED && utcp->connections[i]->state != TIME_WAIT) {
-                       return true;
-               }
-
-       return false;
-}
-
-struct utcp *utcp_init(utcp_accept_t accept, utcp_listen_t listen, utcp_send_t send, void *priv) {
-       if(!send) {
-               errno = EFAULT;
-               return NULL;
-       }
-
-       struct utcp *utcp = calloc(1, sizeof(*utcp));
-
-       if(!utcp) {
-               return NULL;
-       }
-
-       utcp_set_mtu(utcp, DEFAULT_MTU);
-
-       if(!utcp->pkt) {
-               free(utcp);
-               return NULL;
-       }
-
-       if(!CLOCK_GRANULARITY) {
-               struct timespec res;
-               clock_getres(UTCP_CLOCK, &res);
-               CLOCK_GRANULARITY = res.tv_sec * USEC_PER_SEC + res.tv_nsec / 1000;
-       }
-
-       utcp->accept = accept;
-       utcp->listen = listen;
-       utcp->send = send;
-       utcp->priv = priv;
-       utcp->timeout = DEFAULT_USER_TIMEOUT; // sec
-
-       return utcp;
-}
-
-void utcp_exit(struct utcp *utcp) {
-       if(!utcp) {
-               return;
-       }
-
-       for(int i = 0; i < utcp->nconnections; i++) {
-               struct utcp_connection *c = utcp->connections[i];
-
-               if(!c->reapable) {
-                       if(c->recv) {
-                               c->recv(c, NULL, 0);
-                       }
-               }
-
-               free(c);
-       }
-
-       free(utcp->connections);
-       free(utcp->pkt);
-       free(utcp);
-}
-
-uint16_t utcp_get_mtu(struct utcp *utcp) {
-       return utcp ? utcp->mtu : 0;
-}
-
-uint16_t utcp_get_mss(struct utcp *utcp) {
-       return utcp ? utcp->mss : 0;
-}
-
-void utcp_set_mtu(struct utcp *utcp, uint16_t mtu) {
-       if(!utcp) {
-               return;
-       }
-
-       if(mtu <= sizeof(struct hdr)) {
-               return;
-       }
-
-       if(mtu > utcp->mtu) {
-               char *new = realloc(utcp->pkt, mtu + sizeof(struct hdr));
-
-               if(!new) {
-                       return;
-               }
-
-               utcp->pkt = new;
-       }
-
-       utcp->mtu = mtu;
-       utcp->mss = mtu - sizeof(struct hdr);
-}
-
-void utcp_reset_timers(struct utcp *utcp) {
-       if(!utcp) {
-               return;
-       }
-
-       struct timespec now, then;
-
-       clock_gettime(UTCP_CLOCK, &now);
-
-       then = now;
-
-       then.tv_sec += utcp->timeout;
-
-       for(int i = 0; i < utcp->nconnections; i++) {
-               struct utcp_connection *c = utcp->connections[i];
-
-               if(c->reapable) {
-                       continue;
-               }
-
-               if(timespec_isset(&c->rtrx_timeout)) {
-                       c->rtrx_timeout = now;
-               }
-
-               if(timespec_isset(&c->conn_timeout)) {
-                       c->conn_timeout = then;
-               }
-
-               c->rtt_start.tv_sec = 0;
-
-               if(c->rto > START_RTO) {
-                       c->rto = START_RTO;
-               }
-       }
-}
-
-int utcp_get_user_timeout(struct utcp *u) {
-       return u ? u->timeout : 0;
-}
-
-void utcp_set_user_timeout(struct utcp *u, int timeout) {
-       if(u) {
-               u->timeout = timeout;
-       }
-}
-
-bool utcp_get_nodelay(struct utcp_connection *c) {
-       return c ? c->nodelay : false;
-}
-
-void utcp_set_nodelay(struct utcp_connection *c, bool nodelay) {
-       if(c) {
-               c->nodelay = nodelay;
-       }
-}
-
-bool utcp_get_keepalive(struct utcp_connection *c) {
-       return c ? c->keepalive : false;
-}
-
-void utcp_set_keepalive(struct utcp_connection *c, bool keepalive) {
-       if(c) {
-               c->keepalive = keepalive;
-       }
-}
-
-void utcp_set_recv_cb(struct utcp_connection *c, utcp_recv_t recv) {
-       if(c) {
-               c->recv = recv;
-       }
-}
-
-void utcp_set_accept_cb(struct utcp *utcp, utcp_accept_t accept, utcp_listen_t listen) {
-       if(utcp) {
-               utcp->accept = accept;
-               utcp->listen = listen;
-       }
-}
-
-void utcp_expect_data(struct utcp_connection *c, bool expect) {
-       if(!c || c->reapable) {
-               return;
-       }
-
-       if(!(c->state == ESTABLISHED || c->state == FIN_WAIT_1 || c->state == FIN_WAIT_2)) {
-               return;
-       }
-
-       if(expect) {
-               // If we expect data, start the connection timer.
-               if(!timespec_isset(&c->conn_timeout)) {
-                       clock_gettime(UTCP_CLOCK, &c->conn_timeout);
-                       c->conn_timeout.tv_sec += c->utcp->timeout;
-               }
-       } else {
-               // If we want to cancel expecting data, only clear the timer when there is no unACKed data.
-               if(c->snd.una == c->snd.last) {
-                       timespec_clear(&c->conn_timeout);
-               }
-       }
-}
-
-void utcp_set_flags(struct utcp_connection *c, uint32_t flags) {
-       c->flags &= ~UTCP_CHANGEABLE_FLAGS;
-       c->flags |= flags & UTCP_CHANGEABLE_FLAGS;
-}
-
-void utcp_offline(struct utcp *utcp, bool offline) {
-       struct timespec now;
-       clock_gettime(UTCP_CLOCK, &now);
-
-       for(int i = 0; i < utcp->nconnections; i++) {
-               struct utcp_connection *c = utcp->connections[i];
-
-               if(c->reapable) {
-                       continue;
-               }
-
-               utcp_expect_data(c, offline);
-
-               if(!offline) {
-                       if(timespec_isset(&c->rtrx_timeout)) {
-                               c->rtrx_timeout = now;
-                       }
-
-                       utcp->connections[i]->rtt_start.tv_sec = 0;
-
-                       if(c->rto > START_RTO) {
-                               c->rto = START_RTO;
-                       }
-               }
-       }
-}
-
-void utcp_set_clock_granularity(long granularity) {
-       CLOCK_GRANULARITY = granularity;
-}
diff --git a/src/utcp.h b/src/utcp.h
deleted file mode 100644 (file)
index e34d96c..0000000
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
-    utcp.h -- Userspace TCP
-    Copyright (C) 2014 Guus Sliepen <guus@tinc-vpn.org>
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    This program 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.
-*/
-
-#ifndef UTCP_H
-#define UTCP_H
-
-#include <unistd.h>
-#include <stdint.h>
-#include <stdbool.h>
-// TODO: Windows
-#include <sys/time.h>
-
-#ifndef UTCP_INTERNAL
-struct utcp {
-       void *priv;
-};
-
-struct utcp_connection {
-       void *priv;
-       struct utcp *const utcp;
-       const uint32_t flags;
-};
-#else
-struct utcp;
-struct utcp_connection;
-#endif
-
-#define UTCP_SHUT_RD 0
-#define UTCP_SHUT_WR 1
-#define UTCP_SHUT_RDWR 2
-
-//#define UTCP_ORDERED 1
-//#define UTCP_RELIABLE 2
-//#define UTCP_FRAMED 4
-//#define UTCP_DROP_LATE 8
-//#define UTCP_NO_PARTIAL 16
-
-//#define UTCP_TCP 3
-#define UTCP_UDP 0
-#define UTCP_CHANGEABLE_FLAGS 0x0U
-
-typedef bool (*utcp_listen_t)(struct utcp *utcp, uint16_t port);
-typedef void (*utcp_accept_t)(struct utcp_connection *utcp_connection, uint16_t port);
-
-typedef ssize_t (*utcp_send_t)(struct utcp *utcp, const void *data, size_t len);
-typedef ssize_t (*utcp_recv_t)(struct utcp_connection *connection, const void *data, size_t len);
-
-
-struct utcp *utcp_init(utcp_accept_t accept, utcp_listen_t listen, utcp_send_t send, void *priv);
-void utcp_exit(struct utcp *utcp);
-
-struct utcp_connection *utcp_connect_ex(struct utcp *utcp, uint16_t port, utcp_recv_t recv, void *priv, uint32_t flags);
-void utcp_accept(struct utcp_connection *utcp, utcp_recv_t recv, void *priv);
-ssize_t utcp_send(struct utcp_connection *connection, const void *data, size_t len);
-ssize_t utcp_recv(struct utcp *utcp, const void *data, size_t len);
-int utcp_close(struct utcp_connection *connection);
-int utcp_abort(struct utcp_connection *connection);
-int utcp_shutdown(struct utcp_connection *connection, int how);
-struct timespec utcp_timeout(struct utcp *utcp);
-void utcp_set_recv_cb(struct utcp_connection *connection, utcp_recv_t recv);
-void utcp_set_accept_cb(struct utcp *utcp, utcp_accept_t accept, utcp_listen_t listen);
-bool utcp_is_active(struct utcp *utcp);
-void utcp_reset_all_connections(struct utcp *utcp);
-
-// Global socket options
-
-int utcp_get_user_timeout(struct utcp *utcp);
-void utcp_set_user_timeout(struct utcp *utcp, int seconds);
-
-uint16_t utcp_get_mtu(struct utcp *utcp);
-uint16_t utcp_get_mss(struct utcp *utcp);
-void utcp_set_mtu(struct utcp *utcp, uint16_t mtu);
-
-void utcp_reset_timers(struct utcp *utcp);
-
-void utcp_offline(struct utcp *utcp, bool offline);
-
-// Per-socket options
-
-bool utcp_get_nodelay(struct utcp_connection *connection);
-void utcp_set_nodelay(struct utcp_connection *connection, bool nodelay);
-
-bool utcp_get_keepalive(struct utcp_connection *connection);
-void utcp_set_keepalive(struct utcp_connection *connection, bool keepalive);
-
-void utcp_expect_data(struct utcp_connection *connection, bool expect);
-
-void utcp_set_flags(struct utcp_connection *connection, uint32_t flags);
-
-// Completely global options
-
-void utcp_set_clock_granularity(long granularity);
-
-#endif
diff --git a/src/utcp_priv.h b/src/utcp_priv.h
deleted file mode 100644 (file)
index 2c41349..0000000
+++ /dev/null
@@ -1,172 +0,0 @@
-/*
-    utcp.h -- Userspace TCP
-    Copyright (C) 2014 Guus Sliepen <guus@tinc-vpn.org>
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    This program 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.
-*/
-
-#ifndef UTCP_PRIV_H
-#define UTCP_PRIV_H
-
-#define UTCP_INTERNAL
-#include "utcp.h"
-
-#define PREP(l) char pkt[(l) + sizeof struct hdr]; struct hdr *hdr = &pkt;
-
-#define SYN 1
-#define ACK 2
-#define FIN 4
-#define RST 8
-#define MF 16
-
-#define AUX_INIT 1
-#define AUX_FRAME 2
-#define AUX_SAK 3
-#define AUX_TIMESTAMP 4
-
-#define MAX_UNRELIABLE_SIZE 16777215
-#define DEFAULT_MTU 1000
-
-#define USEC_PER_SEC 1000000L
-#define NSEC_PER_SEC 1000000000L
-#define DEFAULT_USER_TIMEOUT 60
-#define START_RTO (1 * USEC_PER_SEC)
-#define MAX_RTO (3 * USEC_PER_SEC)
-
-struct hdr {
-       uint16_t src; // Source port
-       uint16_t dst; // Destination port
-       uint32_t seq; // Sequence number
-       uint32_t ack; // Acknowledgement number
-       uint32_t wnd; // Window size
-       uint16_t ctl; // Flags (SYN, ACK, FIN, RST)
-       uint16_t aux; // other stuff
-};
-
-enum state {
-       CLOSED,
-       LISTEN,
-       SYN_SENT,
-       SYN_RECEIVED,
-       ESTABLISHED,
-       FIN_WAIT_1,
-       FIN_WAIT_2,
-       CLOSE_WAIT,
-       CLOSING,
-       LAST_ACK,
-       TIME_WAIT
-};
-
-static const char *strstate[] __attribute__((unused)) = {
-       [CLOSED] = "CLOSED",
-       [LISTEN] = "LISTEN",
-       [SYN_SENT] = "SYN_SENT",
-       [SYN_RECEIVED] = "SYN_RECEIVED",
-       [ESTABLISHED] = "ESTABLISHED",
-       [FIN_WAIT_1] = "FIN_WAIT_1",
-       [FIN_WAIT_2] = "FIN_WAIT_2",
-       [CLOSE_WAIT] = "CLOSE_WAIT",
-       [CLOSING] = "CLOSING",
-       [LAST_ACK] = "LAST_ACK",
-       [TIME_WAIT] = "TIME_WAIT"
-};
-
-struct utcp_connection {
-       void *priv;
-       struct utcp *utcp;
-       uint32_t flags;
-
-       bool reapable;
-
-       // Callbacks
-
-       utcp_recv_t recv;
-
-       // TCP State
-
-       uint16_t src;
-       uint16_t dst;
-       enum state state;
-
-       struct {
-               uint32_t una;
-               uint32_t nxt;
-               uint32_t wnd;
-               uint32_t iss;
-
-               uint32_t last;
-               uint32_t cwnd;
-               uint32_t ssthresh;
-       } snd;
-
-       struct {
-               uint32_t nxt;
-               uint32_t irs;
-       } rcv;
-
-       int dupack;
-
-       // Timers
-
-       struct timespec conn_timeout;
-       struct timespec rtrx_timeout;
-       struct timespec rtt_start;
-       uint32_t rtt_seq;
-
-       // RTT variables
-
-       uint32_t srtt; // usec
-       uint32_t rttvar; // usec
-       uint32_t rto; // usec
-
-       // Per-socket options
-
-       bool nodelay;
-       bool keepalive;
-       bool shut_wr;
-
-       // Congestion avoidance state
-
-       struct timespec tlast;
-       uint64_t bandwidth;
-};
-
-struct utcp {
-       void *priv;
-
-       // Callbacks
-
-       utcp_accept_t accept;
-       utcp_listen_t listen;
-       utcp_send_t send;
-
-       // Packet buffer
-
-       void *pkt;
-
-       // Global socket options
-
-       uint16_t mtu; // The maximum size of a UTCP packet, including headers.
-       uint16_t mss; // The maximum size of the payload of a UTCP packet.
-       int timeout; // sec
-
-       // Connection management
-
-       struct utcp_connection **connections;
-       int nconnections;
-       int nallocated;
-};
-
-#endif