fprintf(stderr, "/join requires an argument!\n");
return;
}
-
+ meshlink_stop(mesh);
if(!meshlink_join(mesh, arg))
fprintf(stderr, "Could not join using invitation: %s\n", meshlink_strerror(meshlink_errno));
- else
+ else {
fprintf(stderr, "Invitation accepted!\n");
+ if(!meshlink_start(mesh)) {
+ fprintf(stderr, "Could not start MeshLink: %s\n", meshlink_strerror(meshlink_errno));
+ return;
+ }
+ }
} else if(!strcasecmp(buf, "kick")) {
if(!arg) {
fprintf(stderr, "/kick requires an argument!\n");
#include <strings.h>
#include "../src/meshlink++.h"
-static void log_message(meshlink::mesh *mesh, meshlink::log_level_t level, const char *text) {
- const char *levelstr[] = {"DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"};
- fprintf(stderr, "%s: %s\n", levelstr[level], text);
-}
-
-static void receive(meshlink::mesh *mesh, meshlink::node *source, const void *data, size_t len) {
- const char *msg = (const char *)data;
+class ChatMesh : public meshlink::mesh
+{
+public:
+ void log(meshlink::log_level_t level, const char *text) {
+ const char *levelstr[] = {"DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"};
+ fprintf(stderr, "%s: %s\n", levelstr[level], text);
+ }
- if(!len || msg[len - 1]) {
- fprintf(stderr, "Received invalid data from %s\n", source->name);
- return;
+ void receive(meshlink::node *source, const void *data, size_t len) {
+ const char *msg = (const char *)data;
+
+ if(!len || msg[len - 1]) {
+ fprintf(stderr, "Received invalid data from %s\n", source->name);
+ return;
+ }
+
+ printf("%s says: %s\n", source->name, msg);
}
- printf("%s says: %s\n", source->name, msg);
-}
-
-static void node_status(meshlink::mesh *mesh, meshlink::node *node, bool reachable) {
- if(reachable)
- printf("%s joined.\n", node->name);
- else
- printf("%s left.\n", node->name);
-}
+ void node_status(meshlink::node *node, bool reachable) {
+ if(reachable)
+ printf("%s joined.\n", node->name);
+ else
+ printf("%s left.\n", node->name);
+ }
+};
static meshlink::node **nodes;
static size_t nnodes;
if(!nodes) {
fprintf(stderr, "Could not get list of nodes: %s\n", meshlink::strerror());
} else {
- printf("%d known nodes:", nnodes);
+ printf("%zu known nodes:", nnodes);
for(size_t i = 0; i < nnodes; i++)
printf(" %s", nodes[i]->name);
printf("\n");
printf("Message sent to '%s'.\n", destination->name);
}
+
int main(int argc, char *argv[]) {
const char *confbase = ".chat";
const char *nick = NULL;
if(argc > 2)
nick = argv[2];
- meshlink::mesh *mesh = meshlink::open(confbase, nick, "chatpp");
+ ChatMesh* mesh = meshlink::open<ChatMesh>(confbase, nick, "chatpp");
+
if(!mesh) {
fprintf(stderr, "Could not open MeshLink: %s\n", meshlink::strerror());
return 1;
}
- mesh->set_receive_cb(receive);
- mesh->set_node_status_cb(node_status);
- mesh->set_log_cb(MESHLINK_INFO, log_message);
-
if(!mesh->start()) {
fprintf(stderr, "Could not start MeshLink: %s\n", meshlink::strerror());
return 1;
static int n = 100;
static meshlink_handle_t **mesh;
-static void log_message(meshlink_handle_t *mesh, meshlink_log_level_t level, const char *text) {
- const char *levelstr[] = {"DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"};
- fprintf(stderr, "%s: %s\n", levelstr[level], text);
-}
-
-static void receive(meshlink_handle_t *mesh, meshlink_node_t *source, const void *data, size_t len) {
- const char *msg = data;
-
- if(!len || msg[len - 1]) {
- fprintf(stderr, "Received invalid data from %s\n", source->name);
- return;
- }
-
- printf("%s says: %s\n", source->name, msg);
-}
-
-static void node_status(meshlink_handle_t *mesh, meshlink_node_t *node, bool reachable) {
- if(reachable)
- printf("%s joined.\n", node->name);
- else
- printf("%s left.\n", node->name);
-}
+static meshlink_node_t **nodes;
+static size_t nnodes;
// Make all nodes know about each other by importing each others public keys and addresses.
static void linkmesh() {
printf("Node '%s' blacklisted.\n", arg);
} else if(!strcasecmp(buf, "who")) {
if(!arg) {
- meshlink_node_t *nodes[100];
- size_t n = meshlink_get_all_nodes(mesh[0], nodes, 100);
- if(!n) {
- fprintf(stderr, "No nodes known!\n");
+ nodes = meshlink_get_all_nodes(mesh[0], nodes, &nnodes);
+ if(!nodes) {
+ fprintf(stderr, "Could not get list of nodes: %s\n", meshlink_strerror(meshlink_errno));
} else {
- printf("Known nodes:");
- for(int i = 0; i < n && i < 100; i++)
+ printf("%zu known nodes:", nnodes);
+ for(int i = 0; i < nnodes; i++)
printf(" %s", nodes[i]->name);
- if(n > 100)
- printf(" (and %zu more)", n - 100);
printf("\n");
}
} else {
{
// asserts
assert(mesh != NULL);
- assert(mesh->avahi_poll != NULL);
- assert(mesh->avahi_server != NULL);
- assert(mesh->avahi_browser != NULL);
- assert(mesh->discovery_threadstarted == true);
- assert(mesh->avahi_servicetype != NULL);
- // Shut down
- avahi_simple_poll_quit(mesh->avahi_poll);
+ // Shut down
+ if(mesh->avahi_poll)
+ {
+ avahi_simple_poll_quit(mesh->avahi_poll);
+ }
// Wait for the discovery thread to finish
- pthread_join(mesh->discovery_thread, NULL);
+ if(mesh->discovery_threadstarted == true)
+ {
+ pthread_join(mesh->discovery_thread, NULL);
+ mesh->discovery_threadstarted = false;
+ }
// Clean up resources
- avahi_s_service_browser_free(mesh->avahi_browser);
- mesh->avahi_browser = NULL;
+ if(mesh->avahi_browser != NULL)
+ {
+ avahi_s_service_browser_free(mesh->avahi_browser);
+ mesh->avahi_browser = NULL;
+ }
- avahi_server_free(mesh->avahi_server);
- mesh->avahi_server = NULL;
+ if(mesh->avahi_server != NULL)
+ {
+ avahi_server_free(mesh->avahi_server);
+ mesh->avahi_server = NULL;
+ }
- avahi_simple_poll_free(mesh->avahi_poll);
- mesh->avahi_poll = NULL;
+ if(mesh->avahi_poll != NULL)
+ {
+ avahi_simple_poll_free(mesh->avahi_poll);
+ mesh->avahi_poll = NULL;
+ }
- free(mesh->avahi_servicetype);
- mesh->avahi_servicetype = NULL;
+ if(mesh->avahi_servicetype != NULL)
+ {
+ free(mesh->avahi_servicetype);
+ mesh->avahi_servicetype = NULL;
+ }
}
return 1;
}
- fread(seed, 1, 32, f);
+ if(fread(seed, 32, 1, f) != 1)
+ return 1;
+
fclose(f);
#endif
if(!io->cb)
return;
+ loop->deletion = true;
+
io_set(loop, io, 0);
splay_unlink_node(&loop->ios, &io->node);
if(!timeout->cb)
return;
+ loop->deletion = true;
+
splay_unlink_node(&loop->timeouts, &timeout->node);
timeout->cb = 0;
timeout->tv = (struct timeval){0, 0};
if(!sig->cb)
return;
+ loop->deletion = true;
+
splay_unlink_node(&loop->signals, &sig->node);
sig->cb = NULL;
}
if(!n)
continue;
+ // Normally, splay_each allows the current node to be deleted. However,
+ // it can be that one io callback triggers the deletion of another io,
+ // so we have to detect this and break the loop.
+
+ loop->deletion = false;
+
for splay_each(io_t, io, &loop->ios) {
- if(FD_ISSET(io->fd, &writable))
+ if(FD_ISSET(io->fd, &writable) && io->cb)
io->cb(loop, io->data, IO_WRITE);
- else if(FD_ISSET(io->fd, &readable))
+ if(loop->deletion)
+ break;
+ if(FD_ISSET(io->fd, &readable) && io->cb)
io->cb(loop, io->data, IO_READ);
+ if(loop->deletion)
+ break;
}
}
volatile bool running;
struct timeval now;
+ bool deletion;
splay_tree_t ios;
splay_tree_t timeouts;
#define MESHLINKPP_H
#include <meshlink.h>
+#include <new> // for 'placement new'
namespace meshlink {
class mesh;
/// A class describing a MeshLink mesh.
class mesh: public meshlink_handle_t {
- public:
- // TODO: delete constructor, add a destructor.
-
+ public:
+ mesh() {}
+
+ virtual ~mesh() {
+ meshlink_close(this);
+ }
+
+ /** instead of registerin callbacks you derive your own class and overwrite the following abstract member functions.
+ * These functions are run in MeshLink's own thread.
+ * It is therefore important that these functions use apprioriate methods (queues, pipes, locking, etc.)
+ * to hand the data over to the application's thread.
+ * These functions should also not block itself and return as quickly as possible.
+ * The default member functions are no-ops, so you are not required to overwrite all these member functions
+ */
+
+ /// This function is called whenever another node sends data to the local node.
+ virtual void receive(node* source, const void* data, size_t length) { /* do nothing */ }
+
+ /// This functions is called whenever another node's status changed.
+ virtual void node_status(node* peer, bool reachable) { /* do nothing */ }
+
+ /// This functions is called whenever MeshLink has some information to log.
+ virtual void log(log_level_t level, const char* message) { /* do nothing */ }
+
/// 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.
* @return This function will return true if MeshLink has succesfully started its thread, false otherwise.
*/
bool start() {
+ meshlink_set_receive_cb (this, &receive_trampoline);
+ meshlink_set_node_status_cb(this, &node_status_trampoline);
+ meshlink_set_log_cb (this, MESHLINK_DEBUG, &log_trampoline);
return meshlink_start(this);
}
meshlink_stop(this);
}
- /// 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.
- *
- * @param cb A pointer to the function which will be called when another node sends data to the local node.
- */
- void set_receive_cb(receive_cb_t cb) {
- meshlink_set_receive_cb(this, (meshlink_receive_cb_t)cb);
- }
-
- /// Set the node status callback.
- /** This functions sets the callback that is called whenever another node's status changed.
- * 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.
- *
- * @param cb A pointer to the function which will be called when another node's status changes.
- */
- void set_node_status_cb(node_status_cb_t cb) {
- meshlink_set_node_status_cb(this, (meshlink_node_status_cb_t)cb);
- }
-
- /// Set the log callback.
- /** This functions sets the callback that is called whenever MeshLink has some information to log.
- * The callback is run in MeshLink's own thread.
- * It is 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.
- *
- * @param level An enum describing the minimum severity level. Debugging information with a lower level will not trigger the callback.
- * @param cb A pointer to the function which will be called when another node sends data to the local node.
- */
- void set_log_cb(meshlink_log_level_t level, log_cb_t cb) {
- meshlink_set_log_cb(this, level, (meshlink_log_cb_t)cb);
- }
-
/// Send data to another node.
/** This functions sends one packet of data to another node in the mesh.
* The packet is sent using UDP semantics, which means that
return meshlink_channel_send(this, channel, data, len);
}
+ private:
+ // non-copyable:
+ mesh(const mesh&) /* TODO: C++11: = delete */;
+ void operator=(const mesh&) /* TODO: C++11: = delete */ ;
+
+ /// static callback trampolines:
+ static void receive_trampoline(meshlink_handle_t* handle, meshlink_node_t* source, const void* data, size_t length)
+ {
+ mesh* that = static_cast<mesh*>(handle);
+ that->receive(static_cast<node*>(source), data, length);
+ }
+
+ static void node_status_trampoline(meshlink_handle_t* handle, meshlink_node_t* peer, bool reachable)
+ {
+ mesh* that = static_cast<mesh*>(handle);
+ that->node_status(static_cast<node*>(peer), reachable);
+ }
+
+ static void log_trampoline(meshlink_handle_t* handle, log_level_t level, const char* message)
+ {
+ mesh* that = static_cast<mesh*>(handle);
+ that->log(level, message);
+ }
};
/// Initialize MeshLink's configuration directory.
*
* @return This function will return a pointer to a meshlink::mesh if MeshLink has succesfully set up its configuration files, NULL otherwise.
*/
- static mesh *open(const char *confbase, const char *name, const char* appname) {
- return (mesh *)meshlink_open(confbase, name, appname);
+ template<class MESH>
+ static MESH* open(const char *confbase, const char *name, const char* appname) {
+ void* mp = (void *)meshlink_open_with_size(confbase, name, appname, sizeof(MESH));
+ return new (mp) MESH;
}
/// Close the MeshLink handle.
static const char *strerror(errno_t err = meshlink_errno) {
return meshlink_strerror(err);
}
-};
+
+}
#endif // MESHLINKPP_H
}
static int check_port(meshlink_handle_t *mesh) {
- if(try_bind(655))
- return 655;
-
- fprintf(stderr, "Warning: could not bind to port 655.\n");
-
- for(int i = 0; i < 100; i++) {
+ for(int i = 0; i < 1000; i++) {
int port = 0x1000 + (rand() & 0x7fff);
if(try_bind(port)) {
char filename[PATH_MAX];
fprintf(f, "Port = %d\n", port);
fclose(f);
- fprintf(stderr, "MeshLink will instead listen on port %d.\n", port);
return port;
}
}
}
meshlink_handle_t *meshlink_open(const char *confbase, const char *name, const char* appname) {
+ return meshlink_open_with_size(confbase, name, appname, sizeof(meshlink_handle_t));
+}
+
+meshlink_handle_t *meshlink_open_with_size(const char *confbase, const char *name, const char* appname, size_t size) {
+
// Validate arguments provided by the application
bool usingname = false;
} else { usingname = true;}
}
- meshlink_handle_t *mesh = xzalloc(sizeof *mesh);
+ meshlink_handle_t *mesh = xzalloc(size);
mesh->confbase = xstrdup(confbase);
mesh->appname = xstrdup(appname);
if (usingname) mesh->name = xstrdup(name);
- pthread_mutex_init ( &(mesh->outpacketqueue_mutex), NULL);
pthread_mutex_init ( &(mesh->nodes_mutex), NULL);
mesh->threadstarted = false;
event_loop_init(&mesh->loop);
try_outgoing_connections(mesh);
+ fprintf(stderr, "Starting main_loop...\n");
main_loop(mesh);
+ fprintf(stderr, "main_loop returned.\n");
return NULL;
}
}
void meshlink_stop(meshlink_handle_t *mesh) {
+
if(!mesh) {
meshlink_errno = MESHLINK_EINVAL;
return;
// Stop discovery
discovery_stop(mesh);
- // Shut down the listening sockets to signal the main thread to shut down
+ // Shut down a listening socket to signal the main thread to shut down
- for(int i = 0; i < mesh->listen_sockets; i++) {
- shutdown(mesh->listen_socket[i].tcp.fd, SHUT_RDWR);
- shutdown(mesh->listen_socket[i].udp.fd, SHUT_RDWR);
- }
+ listen_socket_t *s = &mesh->listen_socket[0];
+ shutdown(s->tcp.fd, SHUT_RDWR);
// Wait for the main thread to finish
pthread_join(mesh->thread, NULL);
+ mesh->threadstarted = false;
+
+ // Fix the socket
+
+ closesocket(s->tcp.fd);
+ io_del(&mesh->loop, &s->tcp);
+ s->tcp.fd = setup_listen_socket(&s->sa);
+ if(s->tcp.fd < 0)
+ logger(DEBUG_ALWAYS, LOG_ERR, "Could not repair listenen socket!");
+ else
+ io_add(&mesh->loop, &s->tcp, handle_new_meta_connection, s, s->tcp.fd, IO_READ);
}
void meshlink_close(meshlink_handle_t *mesh) {
return false;
}
- /* If there is no outgoing list yet, create one. */
-
- if(!mesh->outpacketqueue)
- mesh->outpacketqueue = list_alloc(NULL);
-
//add packet to the queue
outpacketqueue_t *packet_in_queue = xzalloc(sizeof *packet_in_queue);
packet_in_queue->destination=destination;
packet_in_queue->data=data;
packet_in_queue->len=len;
- pthread_mutex_lock(&(mesh->outpacketqueue_mutex));
- list_insert_head(mesh->outpacketqueue,packet_in_queue);
- pthread_mutex_unlock(&(mesh->outpacketqueue_mutex));
+ if(!meshlink_queue_push(&mesh->outpacketqueue, packet_in_queue)) {
+ free(packet_in_queue);
+ return false;
+ }
//notify event loop
signal_trigger(&(mesh->loop),&(mesh->datafromapp));
vpn_packet_t packet;
meshlink_packethdr_t *hdr = (meshlink_packethdr_t *)packet.data;
- outpacketqueue_t* p = list_get_tail(mesh->outpacketqueue);
- if (p)
- list_delete_tail(mesh->outpacketqueue);
- else return ;
+ outpacketqueue_t* p = meshlink_queue_pop(&mesh->outpacketqueue);
+ if(!p)
+ return;
if (sizeof(meshlink_packethdr_t) + p->len > MAXSIZE) {
//log something
}
if(!port)
- port = "655";
+ goto invalid;
if(!b64decode(slash, mesh->hash, 18) || !b64decode(slash + 24, mesh->cookie, 18))
goto invalid;
#include <stddef.h>
#include <unistd.h>
+#if defined(_WIN32)
+#include <Winsock2.h>
+#else
+#include <sys/types.h>
+#include <sys/socket.h>
+#endif
+
#ifdef __cplusplus
extern "C" {
#endif
*/
extern meshlink_handle_t *meshlink_open(const char *confbase, const char *name, const char* appname);
+/// is used by the C++ wrapper to allocate more memory behind the handle
+extern meshlink_handle_t *meshlink_open_with_size(const char *confbase, const char *name, const char* appname, size_t size);
+
/// 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.
#include "hash.h"
#include "logger.h"
#include "meshlink.h"
+#include "meshlink_queue.h"
#include "sockaddr.h"
#include "sptps.h"
struct list_t *connections;
struct list_t *outgoings;
- struct list_t *outpacketqueue;
+ meshlink_queue_t outpacketqueue;
struct splay_tree_t *past_request_tree;
timeout_t past_request_timeout;
--- /dev/null
+/*
+ queue.h -- Thread-safe queue
+ 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.
+*/
+
+#ifndef MESHLINK_QUEUE_H
+#define MESHLINK_QUEUE_H
+
+#include <pthread.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <unistd.h>
+
+typedef struct meshlink_queue {
+ struct meshlink_queue_item *head;
+ struct meshlink_queue_item *tail;
+ pthread_mutex_t mutex;
+} meshlink_queue_t;
+
+typedef struct meshlink_queue_item {
+ void *data;
+ struct meshlink_queue_item *next;
+} meshlink_queue_item_t;
+
+static inline bool meshlink_queue_push(meshlink_queue_t *queue, void *data) {
+ meshlink_queue_item_t *item = malloc(sizeof *item);
+ if(!item)
+ return false;
+ item->data = data;
+ item->next = NULL;
+ pthread_mutex_lock(&queue->mutex);
+ if(!queue->tail)
+ queue->head = queue->tail = item;
+ else
+ queue->tail = queue->tail->next = item;
+ pthread_mutex_unlock(&queue->mutex);
+ return true;
+}
+
+static inline void *meshlink_queue_pop(meshlink_queue_t *queue) {
+ meshlink_queue_item_t *item;
+ void *data;
+ pthread_mutex_lock(&queue->mutex);
+ if((item = queue->head)) {
+ queue->head = item->next;
+ if(!queue->head)
+ queue->tail = NULL;
+ }
+ pthread_mutex_unlock(&queue->mutex);
+ data = item ? item->data : NULL;
+ free(item);
+ return data;
+}
+
+#endif
#include "protocol.h"
#include "xalloc.h"
+static const int min(int a, int b) {
+ return a < b ? a : b;
+}
+
/*
Terminate a connection:
- Mark it as inactive
//the user will read this debug message "Autoconnecting to %s" that is misleading
logger(DEBUG_CONNECTIONS, LOG_INFO, "Autoconnecting to %s", n->name);
outgoing_t *outgoing = xzalloc(sizeof *outgoing);
+ outgoing->mesh = mesh;
outgoing->name = xstrdup(n->name);
list_insert_tail(mesh->outgoings, outgoing);
setup_outgoing_connection(mesh, outgoing);
mesh->contradicting_add_edge = 0;
mesh->contradicting_del_edge = 0;
+ int timeout = 5;
+
/* If AutoConnect is set, check if we need to make or break connections. */
if(autoconnect && mesh->nodes->count > 1) {
}
}
}
+
+ if (nc + mesh->outgoings->count < min(autoconnect, mesh->nodes->count - 1))
+ timeout = 0;
}
- timeout_set(&mesh->loop, data, &(struct timeval){5, rand() % 100000});
+ timeout_set(&mesh->loop, data, &(struct timeval){timeout, rand() % 100000});
}
void handle_meta_connection_data(meshlink_handle_t *mesh, connection_t *c) {
*/
int main_loop(meshlink_handle_t *mesh) {
timeout_add(&mesh->loop, &mesh->pingtimer, timeout_handler, &mesh->pingtimer, &(struct timeval){mesh->pingtimeout, rand() % 100000});
- timeout_add(&mesh->loop, &mesh->periodictimer, periodic_handler, &mesh->periodictimer, &(struct timeval){mesh->pingtimeout, rand() % 100000});
+ timeout_add(&mesh->loop, &mesh->periodictimer, periodic_handler, &mesh->periodictimer, &(struct timeval){0, 0});
//Add signal handler
mesh->datafromapp.signum = 0;
mesh->self->connection->name = xstrdup(name);
read_host_config(mesh, mesh->config, name);
- if(!get_config_string(lookup_config(mesh->config, "Port"), &mesh->myport))
- mesh->myport = xstrdup("655");
+ if(!get_config_string(lookup_config(mesh->config, "Port"), &mesh->myport)) {
+ logger(DEBUG_ALWAYS, LOG_ERR, "Port for MeshLink instance required!");
+ return false;
+ }
mesh->self->connection->options = 0;
mesh->self->connection->protocol_major = PROT_MAJOR;
return false;
}
- // TODO: require Port to be set? Or use "0" and use getsockname()?
-
- if(!mesh->myport)
- mesh->myport = xstrdup("655");
-
xasprintf(&mesh->self->hostname, "MYSELF port %s", mesh->myport);
mesh->self->connection->hostname = xstrdup(mesh->self->hostname);
if(c->outbuf.len <= c->outbuf.offset)
return;
- ssize_t outlen = send(c->socket, c->outbuf.data + c->outbuf.offset, c->outbuf.len - c->outbuf.offset, 0);
+ ssize_t outlen = send(c->socket, c->outbuf.data + c->outbuf.offset, c->outbuf.len - c->outbuf.offset, MSG_NOSIGNAL);
if(outlen <= 0) {
if(!errno || errno == EPIPE) {
logger(DEBUG_CONNECTIONS, LOG_NOTICE, "Connection closed by %s (%s)", c->name, c->hostname);
*space = 0;
} else {
// TODO: Only allow Address statements?
- if(!get_config_string(lookup_config(outgoing->config_tree, "Port"), &port))
- port = xstrdup("655");
+ if(!get_config_string(lookup_config(outgoing->config_tree, "Port"), &port)) {
+ logger(DEBUG_CONNECTIONS, LOG_ERR, "No Port known for %s", outgoing->name);
+ retry_outgoing(mesh, outgoing);
+ return false;
+ }
}
outgoing->ai = str2addrinfo(address, port, SOCK_STREAM);
if(!s->instate || len < 21)
return error(s, EIO, "Received short packet");
- // TODO: just decrypt without updating the replay window
+ uint32_t seqno;
+ memcpy(&seqno, data, 4);
+ seqno = ntohl(seqno);
+ // TODO: check whether seqno makes sense, to avoid CPU intensive decrypt
- return true;
+ char buffer[len];
+ size_t outlen;
+ return chacha_poly1305_decrypt(s->incipher, seqno, data + 4, len - 4, buffer, &outlen);
}
// Receive incoming data, datagram version.
int main(int argc, char *argv[]) {
// Open a new meshlink instance.
- meshlink::mesh *mesh = meshlink::open("basicpp_conf", "foo");
+ meshlink::mesh *mesh = meshlink::open<meshlink::mesh>("basicpp_conf", "foo");
if(!mesh) {
cerr << "Could not initialize configuration for foo\n";
return 1;
// Check that the name is ignored now, and that we still are "foo".
- mesh = meshlink::open("basic_conf", "bar");
+ mesh = meshlink::open<meshlink::mesh>("basic_conf", "bar");
if(!mesh) {
cerr << "Could not open configuration for foo a second time\n";
return 1;
return 1;
}
+ int pmtu = meshlink_get_pmtu(mesh2, meshlink_get_node(mesh2, "bar"));
+ for(int i = 0; i < 10 && !pmtu; i++) {
+ sleep(1);
+ pmtu = meshlink_get_pmtu(mesh2, meshlink_get_node(mesh2, "bar"));
+ }
+
+ if(!pmtu) {
+ fprintf(stderr, "UDP communication with bar not possible after 10 seconds\n");
+ return 1;
+ }
+
// Clean up.
meshlink_stop(mesh2);
return 1;
}
+ int pmtu = meshlink_get_pmtu(mesh1, meshlink_get_node(mesh1, "baz"));
+ for(int i = 0; i < 10 && !pmtu; i++) {
+ sleep(1);
+ pmtu = meshlink_get_pmtu(mesh1, meshlink_get_node(mesh1, "baz"));
+ }
+
+ if(!pmtu) {
+ fprintf(stderr, "UDP communication with baz not possible after 10 seconds\n");
+ return 1;
+ }
+
// Clean up.
meshlink_stop(mesh2);