*/
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.
(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
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);
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;
(void)port;
node_t *n = utcp->priv;
meshlink_handle_t *mesh = n->mesh;
- return mesh->channel_accept_cb;
+
+ 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;
+ }
}
/* Finish one AIO buffer, return true if the channel is still open. */
pthread_mutex_unlock(&mesh->mutex);
}
+void meshlink_set_channel_listen_cb(meshlink_handle_t *mesh, meshlink_channel_listen_cb_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) {
if(!mesh) {
meshlink_errno = MESHLINK_EINVAL;
*/
void meshlink_set_default_blacklist(struct meshlink_handle *mesh, bool blacklist);
-/// A callback for accepting incoming channels.
+/// A callback for listening for incoming channels.
/** 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 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.)
*/
typedef void (*meshlink_channel_poll_cb_t)(struct meshlink_handle *mesh, struct meshlink_channel *channel, 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 another node sends data to the local node.
+/** 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 accept callback is set, incoming channels are rejected.
+ * 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 sends data to the local node.
+ * @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);
meshlink_send
meshlink_set_canonical_address
meshlink_set_channel_accept_cb
+meshlink_set_channel_listen_cb
meshlink_set_channel_poll_cb
meshlink_set_channel_rcvbuf
meshlink_set_channel_receive_cb
meshlink_node_status_cb_t node_status_cb;
meshlink_node_status_cb_t meta_status_cb;
meshlink_node_pmtu_cb_t node_pmtu_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;
if(hdr.ctl & SYN && !(hdr.ctl & ACK) && utcp->accept) {
// If we don't want to accept it, send a RST back
- if((utcp->pre_accept && !utcp->pre_accept(utcp, hdr.dst))) {
+ if((utcp->listen && !utcp->listen(utcp, hdr.dst))) {
len = 1;
goto reset;
}
return false;
}
-struct utcp *utcp_init(utcp_accept_t accept, utcp_pre_accept_t pre_accept, utcp_send_t send, void *priv) {
+struct utcp *utcp_init(utcp_accept_t accept, utcp_listen_t listen, utcp_send_t send, void *priv) {
if(!send) {
errno = EFAULT;
return NULL;
}
utcp->accept = accept;
- utcp->pre_accept = pre_accept;
+ utcp->listen = listen;
utcp->send = send;
utcp->priv = priv;
utcp->timeout = DEFAULT_USER_TIMEOUT; // sec
}
}
-void utcp_set_accept_cb(struct utcp *utcp, utcp_accept_t accept, utcp_pre_accept_t pre_accept) {
+void utcp_set_accept_cb(struct utcp *utcp, utcp_accept_t accept, utcp_listen_t listen) {
if(utcp) {
utcp->accept = accept;
- utcp->pre_accept = pre_accept;
+ utcp->listen = listen;
}
}
#define UTCP_TCP 3
#define UTCP_UDP 0
-typedef bool (*utcp_pre_accept_t)(struct utcp *utcp, uint16_t port);
+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 void (*utcp_retransmit_t)(struct utcp_connection *connection);
typedef void (*utcp_poll_t)(struct utcp_connection *connection, size_t len);
-struct utcp *utcp_init(utcp_accept_t accept, utcp_pre_accept_t pre_accept, utcp_send_t send, void *priv);
+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);
struct timespec utcp_timeout(struct utcp *utcp);
void utcp_set_recv_cb(struct utcp_connection *connection, utcp_recv_t recv);
void utcp_set_poll_cb(struct utcp_connection *connection, utcp_poll_t poll);
-void utcp_set_accept_cb(struct utcp *utcp, utcp_accept_t accept, utcp_pre_accept_t pre_accept);
+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_abort_all_connections(struct utcp *utcp);
// Callbacks
utcp_accept_t accept;
- utcp_pre_accept_t pre_accept;
+ utcp_listen_t listen;
utcp_retransmit_t retransmit;
utcp_send_t send;
set_sync_flag(&info->flag, true);
}
-static bool reject_cb(meshlink_handle_t *mesh, meshlink_channel_t *channel, uint16_t port, const void *data, size_t len) {
- (void)mesh;
- (void)channel;
- (void)port;
- (void)data;
- (void)len;
-
- return false;
-}
-
static bool accept_cb(meshlink_handle_t *mesh, meshlink_channel_t *channel, uint16_t port, const void *data, size_t len) {
assert(port && port <= nchannels);
assert(!data);
// Set the callbacks.
- meshlink_set_channel_accept_cb(mesh_a, reject_cb);
meshlink_set_channel_accept_cb(mesh_b, accept_cb);
// Start both instances
set_sync_flag(&info->flag, true);
}
-static bool reject_cb(meshlink_handle_t *mesh, meshlink_channel_t *channel, uint16_t port, const void *data, size_t len) {
- (void)mesh;
- (void)channel;
- (void)port;
- (void)data;
- (void)len;
-
- return false;
-}
-
static void receive_cb(meshlink_handle_t *mesh, meshlink_channel_t *channel, const void *data, size_t len) {
(void)mesh;
(void)channel;
mesh_b->priv = in_infos;
- meshlink_set_channel_accept_cb(mesh_a, reject_cb);
meshlink_set_channel_accept_cb(mesh_b, accept_cb);
// Start both instances
meshlink_channel_close(mesh, channel);
}
-static bool reject_cb(meshlink_handle_t *mesh, meshlink_channel_t *channel, uint16_t port, const void *data, size_t len) {
- (void)mesh;
- (void)channel;
- (void)port;
- (void)data;
- (void)len;
-
- return false;
-}
-
static bool accept_cb(meshlink_handle_t *mesh, meshlink_channel_t *channel, uint16_t port, const void *data, size_t len) {
(void)port;
// Set the callbacks.
- meshlink_set_channel_accept_cb(a, reject_cb);
meshlink_set_channel_accept_cb(b, accept_cb);
// Open a channel from a to b before starting the mesh.
channel_opened.flag = false;
open_meshlink_pair(&a, &b, "channels-cornercases");
- meshlink_set_channel_accept_cb(a, reject_cb);
meshlink_set_channel_accept_cb(b, accept_cb);
start_meshlink_pair(a, b);
#include "../src/meshlink.h"
#include "utils.h"
+static bool listen_cb(meshlink_handle_t *mesh, meshlink_node_t *node, uint16_t port) {
+ (void)mesh;
+ (void)node;
+
+ return port == 7;
+}
+
static bool accept_cb(meshlink_handle_t *mesh, meshlink_channel_t *channel, uint16_t port, const void *data, size_t len) {
(void)mesh;
(void)channel;
// Set the callbacks.
+ meshlink_set_channel_listen_cb(mesh_b, listen_cb);
meshlink_set_channel_accept_cb(mesh_b, accept_cb);
// Open a channel from a to b
// Try setting up a new channel while b is still down.
- set_sync_flag(&poll_flag, false);
- set_sync_flag(&receive_flag, false);
+ reset_sync_flag(&poll_flag);
+ reset_sync_flag(&receive_flag);
channel = meshlink_channel_open(mesh_a, b, 7, NULL, NULL, 0);
assert(channel);
meshlink_channel_close(mesh_a, channel);
- // Restart b and create a new channel
+ // Restart b and create a new channel to the wrong port
- set_sync_flag(&poll_flag, false);
- set_sync_flag(&receive_flag, false);
+ reset_sync_flag(&poll_flag);
+ reset_sync_flag(&receive_flag);
meshlink_set_node_channel_timeout(mesh_a, b, 60);
assert(meshlink_start(mesh_b));
+ channel = meshlink_channel_open(mesh_a, b, 42, receive_cb, NULL, 0);
+ meshlink_set_channel_poll_cb(mesh_a, channel, poll_cb);
+ assert(channel);
+ assert(wait_sync_flag(&poll_flag, 10));
+ assert(poll_len == 0);
+ meshlink_channel_close(mesh_a, channel);
+
+ // Create a channel that will be accepted
+
+ reset_sync_flag(&poll_flag);
+
channel = meshlink_channel_open(mesh_a, b, 7, receive_cb, NULL, 0);
meshlink_set_channel_poll_cb(mesh_a, channel, poll_cb);
assert(channel);
}
}
-static bool reject_cb(meshlink_handle_t *mesh, meshlink_channel_t *channel, uint16_t port, const void *data, size_t len) {
- (void)mesh;
- (void)channel;
- (void)port;
- (void)data;
- (void)len;
-
- return false;
-}
-
static bool accept_cb(meshlink_handle_t *mesh, meshlink_channel_t *channel, uint16_t port, const void *data, size_t len) {
if(port != 7) {
return false;
assert(meshlink_import(mesh, indata));
- meshlink_set_channel_accept_cb(mesh, reject_cb);
-
assert(meshlink_start(mesh));
// Open a channel from foo to bar.
meshlink_channel_close(mesh, channel);
}
-static bool reject_cb(meshlink_handle_t *mesh, meshlink_channel_t *channel, uint16_t port, const void *data, size_t len) {
- (void)mesh;
- (void)channel;
- (void)port;
- (void)data;
- (void)len;
-
- return false;
-}
-
static bool accept_cb(meshlink_handle_t *mesh, meshlink_channel_t *channel, uint16_t port, const void *data, size_t len) {
(void)port;
// Set the callbacks.
- meshlink_set_channel_accept_cb(a, reject_cb);
meshlink_set_channel_accept_cb(b, accept_cb);
// Open a channel from a to b before starting the mesh.
reset_sync_flag(&b_closed);
open_meshlink_pair(&a, &b, "channels-udp-cornercases");
- meshlink_set_channel_accept_cb(a, reject_cb);
meshlink_set_channel_accept_cb(b, accept_cb);
start_meshlink_pair(a, b);
assert(meshlink_channel_send(mesh, channel, data, len) == (ssize_t)len);
}
-static bool reject_cb(meshlink_handle_t *mesh, meshlink_channel_t *channel, uint16_t port, const void *data, size_t len) {
- (void)mesh;
- (void)channel;
- (void)port;
- (void)data;
- (void)len;
-
- return false;
-}
-
static bool accept_cb(meshlink_handle_t *mesh, meshlink_channel_t *channel, uint16_t port, const void *data, size_t len) {
printf("accept_cb: (from %s on port %u) ", channel->node->name, (unsigned int)port);
// Set the callbacks.
- meshlink_set_channel_accept_cb(mesh_a, reject_cb);
meshlink_set_channel_accept_cb(mesh_b, accept_cb);
// Start both instances
assert(write(1, data, len) == (ssize_t)len);
}
-static bool reject_cb(meshlink_handle_t *mesh, meshlink_channel_t *channel, uint16_t port, const void *data, size_t len) {
- (void)mesh;
- (void)channel;
- (void)port;
- (void)data;
- (void)len;
-
- return false;
-}
-
static bool accept_cb(meshlink_handle_t *mesh, meshlink_channel_t *channel, uint16_t port, const void *data, size_t len) {
if(port != 7) {
return false;
meshlink_handle_t *mesh = meshlink_open("echo-fork_conf.1", "a", "echo-fork", DEV_CLASS_BACKBONE);
assert(mesh);
- meshlink_set_channel_accept_cb(mesh, reject_cb);
-
assert(meshlink_start(mesh));
// Open a channel.