#include "net.h"
#include "netutl.h"
#include "node.h"
-#include "submesh.h"
#include "packmsg.h"
#include "prf.h"
#include "protocol.h"
}
char *name = packmsg_get_str_dup(&in);
- char *submesh_name = packmsg_get_str_dup(&in);
+ packmsg_skip_element(&in); // submesh_name
dev_class_t devclass = packmsg_get_int32(&in);
uint32_t count = packmsg_get_array(&in);
if(!name || !check_id(name)) {
logger(mesh, MESHLINK_DEBUG, "No valid Name found in invitation!\n");
free(name);
- free(submesh_name);
- return false;
- }
-
- if(!submesh_name || (strcmp(submesh_name, CORE_MESH) && !check_id(submesh_name))) {
- logger(mesh, MESHLINK_DEBUG, "No valid Submesh found in invitation!\n");
- free(name);
- free(submesh_name);
return false;
}
if(!count) {
logger(mesh, MESHLINK_ERROR, "Incomplete invitation file!\n");
free(name);
- free(submesh_name);
return false;
}
free(mesh->self->name);
mesh->name = name;
mesh->self->name = xstrdup(name);
- mesh->self->submesh = strcmp(submesh_name, CORE_MESH) ? lookup_or_create_submesh(mesh, submesh_name) : NULL;
- free(submesh_name);
mesh->self->devclass = devclass == DEV_CLASS_UNKNOWN ? mesh->devclass : devclass;
// Initialize configuration directory
return true;
}
-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 struct timespec idle(event_loop_t *loop, void *data) {
(void)loop;
meshlink_handle_t *mesh = data;
- struct timespec t, tmin = {3600, 0};
- for splay_each(node_t, n, mesh->nodes) {
- if(!n->utcp) {
- continue;
- }
-
- t = utcp_timeout(n->utcp);
-
- if(timespec_lt(&t, &tmin)) {
- tmin = t;
- }
+ if(mesh->peer && mesh->peer->utcp) {
+ return utcp_timeout(mesh->peer->utcp);
+ } else {
+ return (struct timespec) {
+ 3600, 0
+ };
}
-
- return tmin;
}
static bool meshlink_setup(meshlink_handle_t *mesh) {
mesh->appname = xstrdup(params->appname);
mesh->devclass = params->devclass;
mesh->netns = params->netns;
- mesh->submeshes = NULL;
mesh->log_cb = global_log_cb;
mesh->log_level = global_log_level;
mesh->packet = xmalloc(sizeof(vpn_packet_t));
return mesh;
}
-meshlink_submesh_t *meshlink_submesh_open(meshlink_handle_t *mesh, const char *submesh) {
- logger(NULL, MESHLINK_DEBUG, "meshlink_submesh_open(%s)", submesh);
-
- meshlink_submesh_t *s = NULL;
-
- if(!mesh) {
- logger(NULL, MESHLINK_ERROR, "No mesh handle given!\n");
- meshlink_errno = MESHLINK_EINVAL;
- return NULL;
- }
-
- if(!submesh || !*submesh) {
- logger(NULL, MESHLINK_ERROR, "No submesh name given!\n");
- meshlink_errno = MESHLINK_EINVAL;
- return NULL;
- }
-
- //lock mesh->nodes
- if(pthread_mutex_lock(&mesh->mutex) != 0) {
- abort();
- }
-
- s = (meshlink_submesh_t *)create_submesh(mesh, submesh);
-
- pthread_mutex_unlock(&mesh->mutex);
-
- return s;
-}
-
static void *meshlink_main_loop(void *arg) {
meshlink_handle_t *mesh = arg;
}
// Reset node connection timers
- for splay_each(node_t, n, mesh->nodes) {
- n->last_connect_try = 0;
+ if(mesh->peer) {
+ mesh->peer->last_connect_try = 0;
}
-
//Check that a valid name is set
if(!mesh->name) {
logger(mesh, MESHLINK_ERROR, "No name given!\n");
}
// Close all metaconnections
- if(mesh->connections) {
- for(list_node_t *node = mesh->connections->head, *next; node; node = next) {
- next = node->next;
- connection_t *c = node->data;
- c->outgoing = NULL;
- terminate_connection(mesh, c, false);
- }
+ if(mesh->connection) {
+ mesh->connection->outgoing = NULL;
+ terminate_connection(mesh, mesh->connection, false);
}
exit_outgoings(mesh);
// Try to write out any changed node config files, ignore errors at this point.
- if(mesh->nodes) {
- for splay_each(node_t, n, mesh->nodes) {
- if(n->status.dirty) {
- if(!node_write_config(mesh, n, false)) {
- // ignore
- }
- }
+ if(mesh->peer && mesh->peer->status.dirty) {
+ if(!node_write_config(mesh, mesh->peer, false)) {
+ // ignore
}
}
pthread_mutex_unlock(&mesh->mutex);
}
-void meshlink_set_node_pmtu_cb(meshlink_handle_t *mesh, meshlink_node_pmtu_cb_t cb) {
- logger(mesh, MESHLINK_DEBUG, "meshlink_set_node_pmtu_cb(%p)", (void *)(intptr_t)cb);
-
- if(!mesh) {
- meshlink_errno = MESHLINK_EINVAL;
- return;
- }
-
- if(pthread_mutex_lock(&mesh->mutex) != 0) {
- abort();
- }
-
- mesh->node_pmtu_cb = cb;
- pthread_mutex_unlock(&mesh->mutex);
-}
-
void meshlink_set_node_duplicate_cb(meshlink_handle_t *mesh, meshlink_node_duplicate_cb_t cb) {
logger(mesh, MESHLINK_DEBUG, "meshlink_set_node_duplicate_cb(%p)", (void *)(intptr_t)cb);
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);
- mesh->self->in_packets++;
- mesh->self->in_bytes += packet->len;
route(mesh, mesh->self, packet);
free(packet);
}
}
-ssize_t meshlink_get_pmtu(meshlink_handle_t *mesh, meshlink_node_t *destination) {
- if(!mesh || !destination) {
- meshlink_errno = MESHLINK_EINVAL;
- return -1;
- }
-
- if(pthread_mutex_lock(&mesh->mutex) != 0) {
- abort();
- }
-
- node_t *n = (node_t *)destination;
-
- if(!n->status.reachable) {
- pthread_mutex_unlock(&mesh->mutex);
- return 0;
-
- } else if(n->mtuprobes > 30 && n->minmtu) {
- pthread_mutex_unlock(&mesh->mutex);
- return n->minmtu;
- } else {
- pthread_mutex_unlock(&mesh->mutex);
- return MTU;
- }
-}
-
char *meshlink_get_fingerprint(meshlink_handle_t *mesh, meshlink_node_t *node) {
if(!mesh || !node) {
meshlink_errno = MESHLINK_EINVAL;
return (meshlink_node_t *)n;
}
-meshlink_submesh_t *meshlink_get_submesh(meshlink_handle_t *mesh, const char *name) {
- if(!mesh || !name) {
- meshlink_errno = MESHLINK_EINVAL;
- return NULL;
- }
-
- meshlink_submesh_t *submesh = NULL;
-
- if(pthread_mutex_lock(&mesh->mutex) != 0) {
- abort();
- }
-
- submesh = (meshlink_submesh_t *)lookup_submesh(mesh, name);
- pthread_mutex_unlock(&mesh->mutex);
-
- if(!submesh) {
- meshlink_errno = MESHLINK_ENOENT;
- }
-
- return submesh;
-}
-
-meshlink_node_t **meshlink_get_all_nodes(meshlink_handle_t *mesh, meshlink_node_t **nodes, size_t *nmemb) {
- if(!mesh || !nmemb || (*nmemb && !nodes)) {
- meshlink_errno = MESHLINK_EINVAL;
- return NULL;
- }
-
- meshlink_node_t **result;
-
- //lock mesh->nodes
- if(pthread_mutex_lock(&mesh->mutex) != 0) {
- abort();
- }
-
- *nmemb = mesh->nodes->count;
- result = realloc(nodes, *nmemb * sizeof(*nodes));
-
- if(result) {
- meshlink_node_t **p = result;
-
- for splay_each(node_t, n, mesh->nodes) {
- *p++ = (meshlink_node_t *)n;
- }
- } else {
- *nmemb = 0;
- free(nodes);
- meshlink_errno = MESHLINK_ENOMEM;
- }
-
- pthread_mutex_unlock(&mesh->mutex);
-
- return result;
-}
-
-static meshlink_node_t **meshlink_get_all_nodes_by_condition(meshlink_handle_t *mesh, const void *condition, meshlink_node_t **nodes, size_t *nmemb, search_node_by_condition_t search_node) {
- meshlink_node_t **result;
-
- if(pthread_mutex_lock(&mesh->mutex) != 0) {
- abort();
- }
-
- *nmemb = 0;
-
- for splay_each(node_t, n, mesh->nodes) {
- if(search_node(n, condition)) {
- ++*nmemb;
- }
- }
-
- if(*nmemb == 0) {
- free(nodes);
- pthread_mutex_unlock(&mesh->mutex);
- return NULL;
- }
-
- result = realloc(nodes, *nmemb * sizeof(*nodes));
-
- if(result) {
- meshlink_node_t **p = result;
-
- for splay_each(node_t, n, mesh->nodes) {
- if(search_node(n, condition)) {
- *p++ = (meshlink_node_t *)n;
- }
- }
- } else {
- *nmemb = 0;
- free(nodes);
- meshlink_errno = MESHLINK_ENOMEM;
- }
-
- pthread_mutex_unlock(&mesh->mutex);
-
- return result;
-}
-
-static bool search_node_by_dev_class(const node_t *node, const void *condition) {
- dev_class_t *devclass = (dev_class_t *)condition;
-
- if(*devclass == (dev_class_t)node->devclass) {
- return true;
- }
-
- return false;
-}
-
-static bool search_node_by_submesh(const node_t *node, const void *condition) {
- if(condition == node->submesh) {
- return true;
- }
-
- return false;
-}
-
-struct time_range {
- time_t start;
- time_t end;
-};
-
-meshlink_node_t **meshlink_get_all_nodes_by_dev_class(meshlink_handle_t *mesh, dev_class_t devclass, meshlink_node_t **nodes, size_t *nmemb) {
- if(!mesh || devclass < 0 || devclass >= DEV_CLASS_COUNT || !nmemb) {
- meshlink_errno = MESHLINK_EINVAL;
- return NULL;
- }
-
- return meshlink_get_all_nodes_by_condition(mesh, &devclass, nodes, nmemb, search_node_by_dev_class);
-}
-
-meshlink_node_t **meshlink_get_all_nodes_by_submesh(meshlink_handle_t *mesh, meshlink_submesh_t *submesh, meshlink_node_t **nodes, size_t *nmemb) {
- if(!mesh || !submesh || !nmemb) {
- meshlink_errno = MESHLINK_EINVAL;
- return NULL;
- }
-
- return meshlink_get_all_nodes_by_condition(mesh, submesh, nodes, nmemb, search_node_by_submesh);
-}
-
-dev_class_t meshlink_get_node_dev_class(meshlink_handle_t *mesh, meshlink_node_t *node) {
- if(!mesh || !node) {
- meshlink_errno = MESHLINK_EINVAL;
- return -1;
- }
-
- dev_class_t devclass;
-
- if(pthread_mutex_lock(&mesh->mutex) != 0) {
- abort();
- }
-
- devclass = ((node_t *)node)->devclass;
-
- pthread_mutex_unlock(&mesh->mutex);
-
- return devclass;
-}
-
-meshlink_submesh_t *meshlink_get_node_submesh(meshlink_handle_t *mesh, meshlink_node_t *node) {
- if(!mesh || !node) {
- meshlink_errno = MESHLINK_EINVAL;
- return NULL;
- }
-
- node_t *n = (node_t *)node;
-
- meshlink_submesh_t *s;
-
- s = (meshlink_submesh_t *)n->submesh;
-
- return s;
-}
-
-bool meshlink_get_node_reachability(struct meshlink_handle *mesh, struct meshlink_node *node, time_t *last_reachable, time_t *last_unreachable) {
- if(!mesh || !node) {
- meshlink_errno = MESHLINK_EINVAL;
- return NULL;
- }
-
- node_t *n = (node_t *)node;
- bool reachable;
-
- if(pthread_mutex_lock(&mesh->mutex) != 0) {
- abort();
- }
-
- reachable = n->status.reachable && !n->status.blacklisted;
-
- // TODO: handle reachable times?
- (void)last_reachable;
- (void)last_unreachable;
-
- pthread_mutex_unlock(&mesh->mutex);
-
- return reachable;
-}
-
bool meshlink_sign(meshlink_handle_t *mesh, const void *data, size_t len, void *signature, size_t *siglen) {
logger(mesh, MESHLINK_DEBUG, "meshlink_sign(%p, %zu, %p, %p)", data, len, signature, (void *)siglen);
}
// Refuse to join a mesh if we are already part of one. We are part of one if we know at least one other node.
- if(mesh->nodes->count > 1) {
+ if(mesh->peer) {
logger(mesh, MESHLINK_ERROR, "Already part of an existing mesh\n");
meshlink_errno = MESHLINK_EINVAL;
goto exit;
return true;
}
-bool meshlink_forget_node(meshlink_handle_t *mesh, meshlink_node_t *node) {
- logger(mesh, MESHLINK_DEBUG, "meshlink_forget_node(%s)", node ? node->name : "(null)");
-
- if(!mesh || !node) {
- meshlink_errno = MESHLINK_EINVAL;
- return false;
- }
-
- node_t *n = (node_t *)node;
-
- if(pthread_mutex_lock(&mesh->mutex) != 0) {
- abort();
- }
-
- /* Check that the node is not reachable */
- if(n->status.reachable || n->connection) {
- pthread_mutex_unlock(&mesh->mutex);
- logger(mesh, MESHLINK_WARNING, "Could not forget %s: still reachable", n->name);
- return false;
- }
-
- /* Check that we don't have any active UTCP connections */
- if(n->utcp && utcp_is_active(n->utcp)) {
- pthread_mutex_unlock(&mesh->mutex);
- logger(mesh, MESHLINK_WARNING, "Could not forget %s: active UTCP connections", n->name);
- return false;
- }
-
- /* Check that we have no active connections to this node */
- for list_each(connection_t, c, mesh->connections) {
- if(c->node == n) {
- pthread_mutex_unlock(&mesh->mutex);
- logger(mesh, MESHLINK_WARNING, "Could not forget %s: active connection", n->name);
- return false;
- }
- }
-
- /* Remove any pending outgoings to this node */
- if(mesh->outgoings) {
- for list_each(outgoing_t, outgoing, mesh->outgoings) {
- if(outgoing->node == n) {
- list_delete_node(mesh->outgoings, list_node);
- }
- }
- }
-
- /* Delete the config file for this node */
- if(!config_delete(mesh, "current", n->name)) {
- pthread_mutex_unlock(&mesh->mutex);
- return false;
- }
-
- /* Delete the node struct and any remaining edges referencing this node */
- node_del(mesh, n);
-
- pthread_mutex_unlock(&mesh->mutex);
-
- return config_sync(mesh, "current");
-}
-
/* Hint that a hostname may be found at an address
* See header file for detailed comment.
*/
}
}
-static void channel_retransmit(struct utcp_connection *utcp_connection) {
- node_t *n = utcp_connection->utcp->priv;
- meshlink_handle_t *mesh = n->mesh;
-
- if(n->mtuprobes == 31 && n->mtutimeout.cb) {
- timeout_set(&mesh->loop, &n->mtutimeout, &(struct timespec) {
- 0, 0
- });
- }
-}
-
static ssize_t channel_send(struct utcp *utcp, const void *data, size_t len) {
node_t *n = utcp->priv;
mesh->channel_accept_cb = cb;
mesh->receive_cb = channel_receive;
- for splay_each(node_t, n, mesh->nodes) {
- if(!n->utcp && n != mesh->self) {
- n->utcp = utcp_init(channel_accept, channel_pre_accept, channel_send, n);
- utcp_set_mtu(n->utcp, n->mtu - sizeof(meshlink_packethdr_t));
- utcp_set_retransmit_cb(n->utcp, channel_retransmit);
- }
+ if(mesh->peer) {
+ mesh->peer->utcp = utcp_init(channel_accept, channel_pre_accept, channel_send, mesh->peer);
}
pthread_mutex_unlock(&mesh->mutex);
if(!n->utcp) {
n->utcp = utcp_init(channel_accept, channel_pre_accept, channel_send, n);
- utcp_set_mtu(n->utcp, n->mtu - sizeof(meshlink_packethdr_t));
- utcp_set_retransmit_cb(n->utcp, channel_retransmit);
mesh->receive_cb = channel_receive;
if(!n->utcp) {
if(!n->utcp) {
n->utcp = utcp_init(channel_accept, channel_pre_accept, channel_send, n);
- utcp_set_mtu(n->utcp, n->mtu - sizeof(meshlink_packethdr_t));
- utcp_set_retransmit_cb(n->utcp, channel_retransmit);
}
utcp_set_user_timeout(n->utcp, timeout);
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);
- utcp_set_mtu(n->utcp, n->mtu - sizeof(meshlink_packethdr_t));
- utcp_set_retransmit_cb(n->utcp, channel_retransmit);
}
if(mesh->node_status_cb) {
mesh->node_status_cb(mesh, (meshlink_node_t *)n, n->status.reachable && !n->status.blacklisted);
}
-
- if(mesh->node_pmtu_cb) {
- mesh->node_pmtu_cb(mesh, (meshlink_node_t *)n, n->minmtu);
- }
-}
-
-void update_node_pmtu(meshlink_handle_t *mesh, node_t *n) {
- utcp_set_mtu(n->utcp, (n->minmtu > MINMTU ? n->minmtu : MINMTU) - sizeof(meshlink_packethdr_t));
-
- if(mesh->node_pmtu_cb && !n->status.blacklisted) {
- mesh->node_pmtu_cb(mesh, (meshlink_node_t *)n, n->minmtu);
- }
}
void handle_duplicate_node(meshlink_handle_t *mesh, node_t *n) {
void handle_network_change(meshlink_handle_t *mesh, bool online) {
(void)online;
- if(!mesh->connections || !mesh->loop.running) {
+ if(!mesh->loop.running) {
return;
}