#include "meshlink_internal.h"
#include "netutl.h"
#include "node.h"
+#include "submesh.h"
#include "protocol.h"
#include "route.h"
#include "sockaddr.h"
meshlink_log_cb_t global_log_cb;
meshlink_log_level_t global_log_level;
+typedef bool (*search_node_by_condition_t)(const node_t *, const void *);
+
//TODO: this can go away completely
const var_t variables[] = {
/* Server configuration */
{"ConnectTo", VAR_SERVER | VAR_MULTIPLE | VAR_SAFE},
{"Name", VAR_SERVER},
/* Host configuration */
+ {"SubMesh", VAR_HOST | VAR_SAFE},
{"CanonicalAddress", VAR_HOST},
{"Address", VAR_HOST | VAR_MULTIPLE},
{"ECDSAPublicKey", VAR_HOST},
return false;
}
- while(ai) {
- int fd = socket(ai->ai_family, SOCK_STREAM, IPPROTO_TCP);
+ //while(ai) {
+ for(struct addrinfo *aip = ai; aip; aip = aip->ai_next) {
+ int fd = socket(aip->ai_family, SOCK_STREAM, IPPROTO_TCP);
if(!fd) {
freeaddrinfo(ai);
return false;
}
- int result = bind(fd, ai->ai_addr, ai->ai_addrlen);
+ int result = bind(fd, aip->ai_addr, aip->ai_addrlen);
closesocket(fd);
if(result) {
freeaddrinfo(ai);
return false;
}
-
- ai = ai->ai_next;
}
freeaddrinfo(ai);
return finalize_join(mesh);
case 2:
- logger(mesh, MESHLINK_DEBUG, "Invitation succesfully accepted.\n");
+ logger(mesh, MESHLINK_DEBUG, "Invitation successfully accepted.\n");
shutdown(mesh->sock, SHUT_RDWR);
mesh->success = true;
break;
mesh->discovery = true;
mesh->invitation_timeout = 604800; // 1 week
mesh->netns = params->netns;
+ mesh->submeshes = NULL;
if(usingname) {
mesh->name = xstrdup(params->name);
return mesh;
}
+meshlink_submesh_t *meshlink_submesh_open(meshlink_handle_t *mesh, const char *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
+ pthread_mutex_lock(&(mesh->mesh_mutex));
+
+ s = (meshlink_submesh_t *)create_submesh(mesh, submesh);
+
+ pthread_mutex_unlock(&(mesh->mesh_mutex));
+
+ return s;
+}
+
static void *meshlink_main_loop(void *arg) {
meshlink_handle_t *mesh = arg;
pthread_mutex_unlock(&(mesh->mesh_mutex));
}
+void meshlink_set_connection_try_cb(meshlink_handle_t *mesh, meshlink_connection_try_cb_t cb) {
+ if(!mesh) {
+ meshlink_errno = MESHLINK_EINVAL;
+ return;
+ }
+
+ pthread_mutex_lock(&(mesh->mesh_mutex));
+ mesh->connection_try_cb = cb;
+ pthread_mutex_unlock(&(mesh->mesh_mutex));
+}
+
void meshlink_set_node_status_cb(meshlink_handle_t *mesh, meshlink_node_status_cb_t cb) {
if(!mesh) {
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);
+ return false;
+ }
+
// Prepare the packet
vpn_packet_t *packet = malloc(sizeof(*packet));
return node;
}
+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;
+
+ pthread_mutex_lock(&(mesh->mesh_mutex));
+ submesh = (meshlink_submesh_t *)lookup_submesh(mesh, name);
+ pthread_mutex_unlock(&(mesh->mesh_mutex));
+ 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 result;
}
-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 || ((int)devclass < 0) || (devclass > _DEV_CLASS_MAX) || !nmemb) {
- meshlink_errno = MESHLINK_EINVAL;
- return NULL;
- }
-
+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;
pthread_mutex_lock(&(mesh->mesh_mutex));
*nmemb = 0;
for splay_each(node_t, n, mesh->nodes) {
- if(n->devclass == devclass) {
+ if(true == search_node(n, condition)) {
*nmemb = *nmemb + 1;
}
}
meshlink_node_t **p = result;
for splay_each(node_t, n, mesh->nodes) {
- if(n->devclass == devclass) {
+ if(true == search_node(n, condition)) {
*p++ = (meshlink_node_t *)n;
}
}
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 == 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;
+}
+
+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 || ((int)devclass < 0) || (devclass > _DEV_CLASS_MAX) || !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 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_sign(meshlink_handle_t *mesh, const void *data, size_t len, void *signature, size_t *siglen) {
if(!mesh || !data || !len || !signature || !siglen) {
meshlink_errno = MESHLINK_EINVAL;
mesh->invitation_timeout = timeout;
}
-char *meshlink_invite_ex(meshlink_handle_t *mesh, const char *name, uint32_t flags) {
+char *meshlink_invite_ex(meshlink_handle_t *mesh, meshlink_submesh_t *submesh, const char *name, uint32_t flags) {
+ meshlink_submesh_t *s = NULL;
+
if(!mesh) {
meshlink_errno = MESHLINK_EINVAL;
return NULL;
}
+ if(submesh) {
+ s = (meshlink_submesh_t *)lookup_submesh(mesh, submesh->name);
+
+ if(s != submesh) {
+ logger(mesh, MESHLINK_DEBUG, "Invalid SubMesh Handle.\n");
+ meshlink_errno = MESHLINK_EINVAL;
+ return NULL;
+ }
+ } else {
+ s = (meshlink_submesh_t *)mesh->self->submesh;
+ }
+
pthread_mutex_lock(&(mesh->mesh_mutex));
// Check validity of the new node's name
// Fill in the details.
fprintf(f, "Name = %s\n", name);
+
+ if(s) {
+ fprintf(f, "SubMesh = %s\n", s->name);
+ }
+
fprintf(f, "ConnectTo = %s\n", mesh->self->name);
// Copy Broadcast and Mode
return url;
}
-char *meshlink_invite(meshlink_handle_t *mesh, const char *name) {
- return meshlink_invite_ex(mesh, name, 0);
+char *meshlink_invite(meshlink_handle_t *mesh, meshlink_submesh_t *submesh, const char *name) {
+ return meshlink_invite_ex(mesh, submesh, name, 0);
}
bool meshlink_join(meshlink_handle_t *mesh, const char *invitation) {
node_t *n;
n = (node_t *)node;
+
+ if(n == mesh->self) {
+ logger(mesh, MESHLINK_ERROR, "%s blacklisting itself?\n", node->name);
+ meshlink_errno = MESHLINK_EINVAL;
+ pthread_mutex_unlock(&(mesh->mesh_mutex));
+ return;
+ }
+
+ if(n->status.blacklisted) {
+ logger(mesh, MESHLINK_DEBUG, "Node %s already blacklisted\n", node->name);
+ pthread_mutex_unlock(&(mesh->mesh_mutex));
+ return;
+ }
+
n->status.blacklisted = true;
logger(mesh, MESHLINK_DEBUG, "Blacklisted %s.\n", node->name);
}
}
+ utcp_abort_all_connections(n->utcp);
+
+ n->mtu = 0;
+ n->minmtu = 0;
+ n->maxmtu = MTU;
+ n->mtuprobes = 0;
+ n->status.udp_confirmed = false;
+
+ if(n->status.reachable) {
+ update_node_status(mesh, n);
+ }
+
pthread_mutex_unlock(&(mesh->mesh_mutex));
}
pthread_mutex_lock(&(mesh->mesh_mutex));
node_t *n = (node_t *)node;
+
+ if(!n->status.blacklisted) {
+ logger(mesh, MESHLINK_DEBUG, "Node %s was already whitelisted\n", node->name);
+ meshlink_errno = MESHLINK_EINVAL;
+ pthread_mutex_unlock(&(mesh->mesh_mutex));
+ return;
+ }
+
n->status.blacklisted = false;
- //TODO: remove blacklisted = yes from the config file
+ if(n->status.reachable) {
+ update_node_status(mesh, n);
+ }
+
+ //Remove blacklisting from the config file
+ append_config_file(mesh, n->name, "blacklisted", NULL);
pthread_mutex_unlock(&(mesh->mesh_mutex));
return;
}
}
+ if(n->status.blacklisted) {
+ logger(mesh, MESHLINK_ERROR, "Cannot open a channel with blacklisted node\n");
+ return NULL;
+ }
+
meshlink_channel_t *channel = xzalloc(sizeof(*channel));
channel->node = n;
channel->receive_cb = cb;
// TODO: more finegrained locking.
// Ideally we want to put the data into the UTCP connection's send buffer.
- // Then, preferrably only if there is room in the receiver window,
+ // Then, preferably only if there is room in the receiver window,
// kick the meshlink thread to go send packets.
pthread_mutex_lock(&mesh->mesh_mutex);
return channel->c->flags;
}
+size_t meshlink_channel_get_sendq(meshlink_handle_t *mesh, meshlink_channel_t *channel) {
+ if(!mesh || !channel) {
+ meshlink_errno = MESHLINK_EINVAL;
+ return -1;
+ }
+
+ return utcp_get_sendq(channel->c);
+}
+
+size_t meshlink_channel_get_recvq(meshlink_handle_t *mesh, meshlink_channel_t *channel) {
+ if(!mesh || !channel) {
+ meshlink_errno = MESHLINK_EINVAL;
+ return -1;
+ }
+
+ return utcp_get_recvq(channel->c);
+}
+
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);
+ mesh->node_status_cb(mesh, (meshlink_node_t *)n, n->status.reachable && !n->status.blacklisted);
}
}