From 0d133a5ff230ad78da3208d32521d7549836187e Mon Sep 17 00:00:00 2001 From: lakshminarayanagurram Date: Mon, 25 Feb 2019 11:00:35 +0100 Subject: [PATCH] Improve support for submeshes. --- src/connection.h | 2 + src/meshlink.c | 81 ++++++++++++++++------ src/meshlink.h | 30 ++++++++ src/meta.c | 10 +++ src/meta.h | 2 + src/net_packet.c | 4 +- src/protocol.c | 25 +++++-- src/protocol.h | 4 +- src/protocol_auth.c | 45 ++++++++++-- src/protocol_edge.c | 162 +++++++++++++++++++++++++++++++++++++------- src/protocol_key.c | 23 ++++--- src/protocol_misc.c | 4 +- src/submesh.c | 80 +++++++++++++++++++++- src/submesh.h | 9 ++- 14 files changed, 410 insertions(+), 71 deletions(-) diff --git a/src/connection.h b/src/connection.h index 9b272dc8..ca934a49 100644 --- a/src/connection.h +++ b/src/connection.h @@ -52,6 +52,7 @@ typedef struct connection_status_t { #include "edge.h" #include "net.h" #include "node.h" +#include "submesh.h" typedef struct connection_t { char *name; /* name he claims to have */ @@ -71,6 +72,7 @@ typedef struct connection_t { ecdsa_t *ecdsa; /* his public ECDSA key */ sptps_t sptps; + struct submesh_t *submesh; /* his submesh handle if available in invitation file */ int incompression; int outcompression; diff --git a/src/meshlink.c b/src/meshlink.c index 8f0f82d1..6f83c22f 100644 --- a/src/meshlink.c +++ b/src/meshlink.c @@ -54,6 +54,8 @@ __thread meshlink_errno_t meshlink_errno; 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 */ @@ -1433,20 +1435,13 @@ meshlink_submesh_t *meshlink_submesh_open(meshlink_handle_t *mesh, const char * return NULL; } - s = (meshlink_submesh_t *)lookup_submesh(mesh, submesh); - - if(s) { - logger(NULL, MESHLINK_ERROR, "SubMesh Already exists!\n"); - meshlink_errno = MESHLINK_EEXIST; - return NULL; - } + //lock mesh->nodes + pthread_mutex_lock(&(mesh->mesh_mutex)); - s = (meshlink_submesh_t *)new_submesh(); - s->name = xstrdup(submesh); + s = (meshlink_submesh_t *)create_submesh(mesh, submesh); - submesh_add(mesh, (submesh_t *)s); + pthread_mutex_unlock(&(mesh->mesh_mutex)); - meshlink_errno = MESHLINK_OK; return s; } @@ -1889,12 +1884,7 @@ meshlink_node_t **meshlink_get_all_nodes(meshlink_handle_t *mesh, meshlink_node_ 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)); @@ -1902,7 +1892,7 @@ meshlink_node_t **meshlink_get_all_nodes_by_dev_class(meshlink_handle_t *mesh, d *nmemb = 0; for splay_each(node_t, n, mesh->nodes) { - if(n->devclass == devclass) { + if(true == search_node(n, condition)) { *nmemb = *nmemb + 1; } } @@ -1919,7 +1909,7 @@ meshlink_node_t **meshlink_get_all_nodes_by_dev_class(meshlink_handle_t *mesh, d 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; } } @@ -1934,6 +1924,42 @@ meshlink_node_t **meshlink_get_all_nodes_by_dev_class(meshlink_handle_t *mesh, d 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; @@ -1951,6 +1977,21 @@ dev_class_t meshlink_get_node_dev_class(meshlink_handle_t *mesh, meshlink_node_t 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; @@ -2274,6 +2315,8 @@ char *meshlink_invite_ex(meshlink_handle_t *mesh, meshlink_submesh_t *submesh, c meshlink_errno = MESHLINK_EINVAL; return NULL; } + } else { + s = (meshlink_submesh_t *)mesh->self->submesh; } pthread_mutex_lock(&(mesh->mesh_mutex)); diff --git a/src/meshlink.h b/src/meshlink.h index a73bccf3..6f645373 100644 --- a/src/meshlink.h +++ b/src/meshlink.h @@ -508,6 +508,26 @@ extern bool meshlink_sign(meshlink_handle_t *mesh, const void *data, size_t len, */ extern 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); +/// Get the list of all nodes by Submesh. +/** This function returns a list with handles for all the nodes that matches with the given @a Submesh @a . + * + * @param mesh A handle which represents an instance of MeshLink. + * @param submesh Submesh handle of the nodes for which the list has to be obtained. + * @param nodes A pointer to a previously allocated array of pointers to meshlink_node_t, or NULL in which case MeshLink will allocate a new array. + * The application can supply an array it allocated itself with malloc, or the return value from the previous call to this function (which is the preferred way). + * The application is allowed to call free() on the array whenever it wishes. + * The pointers in the array are valid until meshlink_close() is called. + * @param nmemb A pointer to a variable holding the number of nodes with the same @a device class @a that are stored in the array. + * In case the @a nodes @a argument is not NULL, MeshLink might call realloc() on the array to change its size. + * The contents of this variable will be changed to reflect the new size of the array. + * + * @return A pointer to an array containing pointers to all known nodes of the given Submesh, or NULL in case of an error. + * If the @a nodes @a argument was not NULL, then the return value can either be the same value or a different value. + * If it is a new value, the old value of @a nodes @a should not be used anymore. + * If the new value is NULL, then the old array will have been freed by MeshLink. + */ +extern meshlink_node_t **meshlink_get_all_nodes_by_submesh(meshlink_handle_t *mesh, meshlink_submesh_t *submesh, meshlink_node_t **nodes, size_t *nmemb); + /// Get the node's device class. /** This function returns the device class of the given node. * @@ -518,6 +538,16 @@ extern meshlink_node_t **meshlink_get_all_nodes_by_dev_class(meshlink_handle_t * */ extern dev_class_t meshlink_get_node_dev_class(meshlink_handle_t *mesh, meshlink_node_t *node); +/// Get the node's submesh handle. +/** This function returns the submesh handle of the given node. + * + * @param mesh A handle which represents an instance of MeshLink. + * @param node A pointer to a meshlink_node_t describing the node. + * + * @return This function returns the submesh handle of the @a node @a , or NULL in case of an error. + */ +extern meshlink_submesh_t *meshlink_get_node_submesh(meshlink_handle_t *mesh, meshlink_node_t *node); + /// Verify the signature generated by another node of a piece of data. /** This function verifies the signature that another node generated for a piece of data. * diff --git a/src/meta.c b/src/meta.c index aa3499e9..d293b2ee 100644 --- a/src/meta.c +++ b/src/meta.c @@ -68,6 +68,16 @@ void broadcast_meta(meshlink_handle_t *mesh, connection_t *from, const char *buf } } +void broadcast_submesh_meta(meshlink_handle_t *mesh, connection_t *from, submesh_t *s, + const char *buffer, int length) { + for list_each(connection_t, c, mesh->connections) + if(c != from && c->status.active) { + if(c->node && submesh_allows_node(s, c->node)) { + send_meta(mesh, c, buffer, length); + } + } +} + bool receive_meta_sptps(void *handle, uint8_t type, const void *data, uint16_t length) { connection_t *c = handle; meshlink_handle_t *mesh = c->mesh; diff --git a/src/meta.h b/src/meta.h index 6372e34a..88e601a3 100644 --- a/src/meta.h +++ b/src/meta.h @@ -26,6 +26,8 @@ extern bool send_meta(struct meshlink_handle *mesh, struct connection_t *, const extern bool send_meta_sptps(void *, uint8_t, const void *, size_t); extern bool receive_meta_sptps(void *, uint8_t, const void *, uint16_t); extern void broadcast_meta(struct meshlink_handle *mesh, struct connection_t *, const char *, int); +extern void broadcast_submesh_meta(struct meshlink_handle *mesh, connection_t *from, submesh_t *s, + const char *buffer, int length); extern bool receive_meta(struct meshlink_handle *mesh, struct connection_t *); #endif diff --git a/src/net_packet.c b/src/net_packet.c index 162dcef2..857f00fa 100644 --- a/src/net_packet.c +++ b/src/net_packet.c @@ -383,9 +383,9 @@ bool send_sptps_data(void *handle, uint8_t type, const void *data, size_t len) { to ensure we get to learn the reflexive UDP address. */ if(!to->status.validkey) { to->incompression = mesh->self->incompression; - return send_request(mesh, to->nexthop->connection, "%d %s %s %s -1 -1 -1 %d", ANS_KEY, mesh->self->name, to->name, buf, to->incompression); + return send_request(mesh, to->nexthop->connection, NULL, "%d %s %s %s -1 -1 -1 %d", ANS_KEY, mesh->self->name, to->name, buf, to->incompression); } else { - return send_request(mesh, to->nexthop->connection, "%d %s %s %d %s", REQ_KEY, mesh->self->name, to->name, REQ_SPTPS, buf); + return send_request(mesh, to->nexthop->connection, NULL, "%d %s %s %d %s", REQ_KEY, mesh->self->name, to->name, REQ_SPTPS, buf); } } diff --git a/src/protocol.c b/src/protocol.c index 785e20b5..95f6aa39 100644 --- a/src/protocol.c +++ b/src/protocol.c @@ -27,6 +27,7 @@ #include "protocol.h" #include "utils.h" #include "xalloc.h" +#include "submesh.h" /* Jumptable for the request handlers */ @@ -65,11 +66,15 @@ bool check_id(const char *id) { /* Generic request routines - takes care of logging and error detection as well */ -bool send_request(meshlink_handle_t *mesh, connection_t *c, const char *format, ...) { +bool send_request(meshlink_handle_t *mesh, connection_t *c, submesh_t *s, const char *format, ...) { va_list args; char request[MAXBUFSIZE]; int len; + if(!c) { + return false; + } + /* Use vsnprintf instead of vxasprintf: faster, no memory fragmentation, cleanup is automatic, and there is a limit on the input buffer anyway */ @@ -88,22 +93,34 @@ bool send_request(meshlink_handle_t *mesh, connection_t *c, const char *format, request[len++] = '\n'; if(c == mesh->everyone) { - broadcast_meta(mesh, NULL, request, len); + + if(s) { + broadcast_submesh_meta(mesh, NULL, s, request, len); + } else { + broadcast_meta(mesh, NULL, request, len); + } + return true; } else { return send_meta(mesh, c, request, len); } } -void forward_request(meshlink_handle_t *mesh, connection_t *from, const char *request) { +void forward_request(meshlink_handle_t *mesh, connection_t *from, submesh_t *s, const char *request) { logger(mesh, MESHLINK_DEBUG, "Forwarding %s from %s: %s", request_name[atoi(request)], from->name, request); // Create a temporary newline-terminated copy of the request int len = strlen(request); char tmp[len + 1]; + memcpy(tmp, request, len); tmp[len] = '\n'; - broadcast_meta(mesh, from, tmp, sizeof(tmp)); + + if(s) { + broadcast_submesh_meta(mesh, from, s, tmp, sizeof(tmp)); + } else { + broadcast_meta(mesh, from, tmp, sizeof(tmp)); + } } bool receive_request(meshlink_handle_t *mesh, connection_t *c, const char *request) { diff --git a/src/protocol.h b/src/protocol.h index 92ccef01..47aacd99 100644 --- a/src/protocol.h +++ b/src/protocol.h @@ -70,8 +70,8 @@ typedef struct past_request_t { /* Basic functions */ -extern bool send_request(struct meshlink_handle *mesh, struct connection_t *, const char *, ...) __attribute__((__format__(printf, 3, 4))); -extern void forward_request(struct meshlink_handle *mesh, struct connection_t *, const char *); +extern bool send_request(struct meshlink_handle *mesh, struct connection_t *, struct submesh_t *s, const char *, ...) __attribute__((__format__(printf, 4, 5))); +extern void forward_request(struct meshlink_handle *mesh, struct connection_t *, struct submesh_t *, const char *); extern bool receive_request(struct meshlink_handle *mesh, struct connection_t *, const char *); extern bool check_id(const char *); diff --git a/src/protocol_auth.c b/src/protocol_auth.c index 487f34c9..7f00da2b 100644 --- a/src/protocol_auth.c +++ b/src/protocol_auth.c @@ -48,7 +48,7 @@ static bool send_proxyrequest(meshlink_handle_t *mesh, connection_t *c) { char *port; sockaddr2str(&c->address, &host, &port); - send_request(mesh, c, "CONNECT %s:%s HTTP/1.1\r\n\r", host, port); + send_request(mesh, c, NULL, "CONNECT %s:%s HTTP/1.1\r\n\r", host, port); free(host); free(port); return true; @@ -151,7 +151,7 @@ bool send_id(meshlink_handle_t *mesh, connection_t *c) { return false; } - return send_request(mesh, c, "%d %s %d.%d %s", ID, mesh->self->connection->name, mesh->self->connection->protocol_major, minor, mesh->appname); + return send_request(mesh, c, NULL, "%d %s %d.%d %s", ID, mesh->self->connection->name, mesh->self->connection->protocol_major, minor, mesh->appname); } static bool finalize_invitation(meshlink_handle_t *mesh, connection_t *c, const void *data, uint16_t len) { @@ -179,6 +179,11 @@ static bool finalize_invitation(meshlink_handle_t *mesh, connection_t *c, const } fprintf(f, "ECDSAPublicKey = %s\n", (const char *)data); + + if(c->submesh) { + fprintf(f, "SubMesh = %s\n", c->submesh->name); + } + fclose(f); logger(mesh, MESHLINK_INFO, "Key succesfully received from %s", c->name); @@ -288,6 +293,38 @@ static bool receive_invitation_sptps(void *handle, uint8_t type, const void *dat free(c->name); c->name = xstrdup(name); + // Check if the file contains Sub-Mesh information + buf[0] = 0; + fgets(buf, sizeof(buf), f); + + if(*buf) { + buf[strlen(buf) - 1] = 0; + } + + if(!strncmp(buf, "SubMesh", 7)) { + len = strcspn(buf, " \t="); + char *submesh_name = buf + len; + submesh_name += strspn(submesh_name, " \t"); + + if(*submesh_name == '=') { + submesh_name++; + submesh_name += strspn(submesh_name, " \t"); + } + + if(!check_id(submesh_name)) { + logger(mesh, MESHLINK_ERROR, "Invalid invitation file %s\n", cookie); + fclose(f); + return false; + } + + c->submesh = NULL; + c->submesh = lookup_or_create_submesh(mesh, submesh_name); + + if(!c->submesh) { + return false; + } + } + // Send the node the contents of the invitation file rewind(f); size_t result; @@ -336,7 +373,7 @@ bool id_h(meshlink_handle_t *mesh, connection_t *c, const char *request) { return false; } - if(!send_request(mesh, c, "%d %s", ACK, mykey)) { + if(!send_request(mesh, c, NULL, "%d %s", ACK, mykey)) { return false; } @@ -438,7 +475,7 @@ bool send_ack(meshlink_handle_t *mesh, connection_t *c) { c->options |= OPTION_PMTU_DISCOVERY; } - return send_request(mesh, c, "%d %s %d %x", ACK, mesh->myport, mesh->devclass, (c->options & 0xffffff) | (PROT_MINOR << 24)); + return send_request(mesh, c, NULL, "%d %s %d %x", ACK, mesh->myport, mesh->devclass, (c->options & 0xffffff) | (PROT_MINOR << 24)); } static void send_everything(meshlink_handle_t *mesh, connection_t *c) { diff --git a/src/protocol_edge.c b/src/protocol_edge.c index 67881098..5bfd6e21 100644 --- a/src/protocol_edge.c +++ b/src/protocol_edge.c @@ -32,18 +32,54 @@ #include "protocol.h" #include "utils.h" #include "xalloc.h" +#include "submesh.h" extern bool node_write_devclass(meshlink_handle_t *mesh, node_t *n); +extern bool node_write_submesh(meshlink_handle_t *mesh, node_t *n); bool send_add_edge(meshlink_handle_t *mesh, connection_t *c, const edge_t *e, int contradictions) { bool x; char *address, *port; + char *from_submesh, *to_submesh; + submesh_t *s = NULL; + + if(c->node && c->node->submesh) { + if(!submesh_allows_node(e->from->submesh, c->node)) { + return true; + } + + if(!submesh_allows_node(e->to->submesh, c->node)) { + return true; + } + } + + if(e->from->submesh && e->to->submesh && (e->from->submesh != e->to->submesh)) { + return true; + } sockaddr2str(&e->address, &address, &port); - x = send_request(mesh, c, "%d %x %s %d %s %s %s %d %x %d %d", ADD_EDGE, rand(), - e->from->name, e->from->devclass, e->to->name, address, port, e->to->devclass, - e->options, e->weight, contradictions); + if(e->from->submesh) { + from_submesh = e->from->submesh->name; + } else { + from_submesh = CORE_MESH; + } + + if(e->to->submesh) { + to_submesh = e->to->submesh->name; + } else { + to_submesh = CORE_MESH; + } + + if(e->from->submesh) { + s = e->from->submesh; + } else { + s = e->to->submesh; + } + + x = send_request(mesh, c, s, "%d %x %s %d %s %s %s %s %d %s %x %d %d", ADD_EDGE, rand(), + e->from->name, e->from->devclass, from_submesh, e->to->name, address, port, + e->to->devclass, to_submesh, e->options, e->weight, contradictions); free(address); free(port); @@ -55,28 +91,25 @@ bool add_edge_h(meshlink_handle_t *mesh, connection_t *c, const char *request) { node_t *from, *to; char from_name[MAX_STRING_SIZE]; int from_devclass; + char from_submesh_name[MAX_STRING_SIZE] = ""; char to_name[MAX_STRING_SIZE]; char to_address[MAX_STRING_SIZE]; char to_port[MAX_STRING_SIZE]; int to_devclass; + char to_submesh_name[MAX_STRING_SIZE] = ""; sockaddr_t address; uint32_t options; int weight; int contradictions = 0; + submesh_t *s = NULL; - if(sscanf(request, "%*d %*x "MAX_STRING" %d "MAX_STRING" "MAX_STRING" "MAX_STRING" %d %x %d %d", - from_name, &from_devclass, to_name, to_address, to_port, &to_devclass, &options, &weight, &contradictions) < 8) { + if(sscanf(request, "%*d %*x "MAX_STRING" %d "MAX_STRING" "MAX_STRING" "MAX_STRING" "MAX_STRING" %d "MAX_STRING" %x %d %d", + from_name, &from_devclass, from_submesh_name, to_name, to_address, to_port, &to_devclass, to_submesh_name, + &options, &weight, &contradictions) < 10) { logger(mesh, MESHLINK_ERROR, "Got bad %s from %s", "ADD_EDGE", c->name); return false; } - /* Check if names are valid */ - - if(!check_id(from_name) || !check_id(to_name)) { - logger(mesh, MESHLINK_ERROR, "Got bad %s from %s: %s", "ADD_EDGE", c->name, "invalid name"); - return false; - } - // Check if devclasses are valid if(from_devclass < 0 || from_devclass > _DEV_CLASS_MAX) { @@ -89,6 +122,16 @@ bool add_edge_h(meshlink_handle_t *mesh, connection_t *c, const char *request) { return false; } + if(0 == strcmp(from_submesh_name, "")) { + logger(mesh, MESHLINK_ERROR, "Got bad %s from %s: %s", "ADD_EDGE", c->name, "invalid submesh id"); + return false; + } + + if(0 == strcmp(to_submesh_name, "")) { + logger(mesh, MESHLINK_ERROR, "Got bad %s from %s: %s", "ADD_EDGE", c->name, "invalid submesh id"); + return false; + } + if(seen_request(mesh, request)) { return true; } @@ -102,6 +145,15 @@ bool add_edge_h(meshlink_handle_t *mesh, connection_t *c, const char *request) { from = new_node(); from->status.blacklisted = mesh->default_blacklist; from->name = xstrdup(from_name); + + from->submesh = NULL; + + if(0 != strcmp(from_submesh_name, CORE_MESH)) { + if(!(from->submesh = lookup_or_create_submesh(mesh, from_submesh_name))) { + return false; + } + } + node_add(mesh, from); } @@ -112,16 +164,34 @@ bool add_edge_h(meshlink_handle_t *mesh, connection_t *c, const char *request) { from->devclass = from_devclass; node_write_devclass(mesh, from); + if(from->submesh) { + node_write_submesh(mesh, from); + } + if(!to) { to = new_node(); to->status.blacklisted = mesh->default_blacklist; to->name = xstrdup(to_name); + + to->submesh = NULL; + + if(0 != strcmp(to_submesh_name, CORE_MESH)) { + if(!(to->submesh = lookup_or_create_submesh(mesh, to_submesh_name))) { + return false; + + } + } + node_add(mesh, to); } to->devclass = to_devclass; node_write_devclass(mesh, to); + if(to->submesh) { + node_write_submesh(mesh, to); + } + /* Convert addresses */ address = str2sockaddr(to_address, to_port); @@ -166,19 +236,53 @@ bool add_edge_h(meshlink_handle_t *mesh, connection_t *c, const char *request) { e->weight = weight; edge_add(mesh, e); - /* Tell the rest about the new edge */ - - forward_request(mesh, c, request); - /* Run MST before or after we tell the rest? */ graph(mesh); + if(e->from->submesh && e->to->submesh && (e->from->submesh != e->to->submesh)) { + logger(mesh, MESHLINK_ERROR, "Dropping add edge ( %s to %s )", e->from->submesh->name, e->to->submesh->name); + return false; + } + + if(e->from->submesh) { + s = e->from->submesh; + } else { + s = e->to->submesh; + } + + /* Tell the rest about the new edge */ + + forward_request(mesh, c, s, request); + return true; } bool send_del_edge(meshlink_handle_t *mesh, connection_t *c, const edge_t *e, int contradictions) { - return send_request(mesh, c, "%d %x %s %s %d", DEL_EDGE, rand(), + submesh_t *s = NULL; + + if(c->node && c->node->submesh) { + if(!submesh_allows_node(e->from->submesh, c->node)) { + return true; + } + + if(!submesh_allows_node(e->to->submesh, c->node)) { + return true; + } + } + + if(e->from->submesh && e->to->submesh && (e->from->submesh != e->to->submesh)) { + return true; + } + + + if(e->from->submesh) { + s = e->from->submesh; + } else { + s = e->to->submesh; + } + + return send_request(mesh, c, s, "%d %x %s %s %d", DEL_EDGE, rand(), e->from->name, e->to->name, contradictions); } @@ -188,19 +292,13 @@ bool del_edge_h(meshlink_handle_t *mesh, connection_t *c, const char *request) { char to_name[MAX_STRING_SIZE]; node_t *from, *to; int contradictions = 0; + submesh_t *s = NULL; if(sscanf(request, "%*d %*x "MAX_STRING" "MAX_STRING" %d", from_name, to_name, &contradictions) < 2) { logger(mesh, MESHLINK_ERROR, "Got bad %s from %s", "DEL_EDGE", c->name); return false; } - /* Check if names are valid */ - - if(!check_id(from_name) || !check_id(to_name)) { - logger(mesh, MESHLINK_ERROR, "Got bad %s from %s: %s", "DEL_EDGE", c->name, "invalid name"); - return false; - } - if(seen_request(mesh, request)) { return true; } @@ -246,7 +344,21 @@ bool del_edge_h(meshlink_handle_t *mesh, connection_t *c, const char *request) { /* Tell the rest about the deleted edge */ - forward_request(mesh, c, request); + + if(!e->from->submesh || !e->to->submesh || (e->from->submesh == e->to->submesh)) { + if(e->from->submesh) { + s = e->from->submesh; + } else { + s = e->to->submesh; + } + + /* Tell the rest about the deleted edge */ + forward_request(mesh, c, s, request); + + } else { + logger(mesh, MESHLINK_ERROR, "Dropping del edge ( %s to %s )", e->from->submesh->name, e->to->submesh->name); + return false; + } /* Delete the edge */ diff --git a/src/protocol_key.c b/src/protocol_key.c index cae95047..43a227bb 100644 --- a/src/protocol_key.c +++ b/src/protocol_key.c @@ -32,7 +32,7 @@ #include "xalloc.h" void send_key_changed(meshlink_handle_t *mesh) { - send_request(mesh, mesh->everyone, "%d %x %s", KEY_CHANGED, rand(), mesh->self->name); + send_request(mesh, mesh->everyone, NULL, "%d %x %s", KEY_CHANGED, rand(), mesh->self->name); /* Force key exchange for connections using SPTPS */ @@ -64,7 +64,7 @@ bool key_changed_h(meshlink_handle_t *mesh, connection_t *c, const char *request /* Tell the others */ - forward_request(mesh, c, request); + forward_request(mesh, c, NULL, request); return true; } @@ -76,13 +76,13 @@ static bool send_initial_sptps_data(void *handle, uint8_t type, const void *data 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); + return send_request(mesh, to->nexthop->connection, NULL, "%d %s %s %d %s", REQ_KEY, mesh->self->name, to->name, REQ_KEY, buf); } bool send_req_key(meshlink_handle_t *mesh, node_t *to) { if(!node_read_ecdsa_public_key(mesh, to)) { logger(mesh, MESHLINK_DEBUG, "No ECDSA key known for %s", to->name); - send_request(mesh, to->nexthop->connection, "%d %s %s %d", REQ_KEY, mesh->self->name, to->name, REQ_PUBKEY); + send_request(mesh, to->nexthop->connection, NULL, "%d %s %s %d", REQ_KEY, mesh->self->name, to->name, REQ_PUBKEY); return true; } @@ -108,7 +108,12 @@ static bool req_key_ext_h(meshlink_handle_t *mesh, connection_t *c, const char * switch(reqno) { case REQ_PUBKEY: { char *pubkey = ecdsa_get_base64_public_key(mesh->self->connection->ecdsa); - send_request(mesh, from->nexthop->connection, "%d %s %s %d %s", REQ_KEY, mesh->self->name, from->name, ANS_PUBKEY, pubkey); + + if(!from->nexthop || !from->nexthop->connection) { + return false; + } + + send_request(mesh, from->nexthop->connection, NULL, "%d %s %s %d %s", REQ_KEY, mesh->self->name, from->name, ANS_PUBKEY, pubkey); free(pubkey); return true; } @@ -134,7 +139,7 @@ static bool req_key_ext_h(meshlink_handle_t *mesh, connection_t *c, const char * case REQ_KEY: { if(!node_read_ecdsa_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); + send_request(mesh, from->nexthop->connection, NULL, "%d %s %s %d", REQ_KEY, mesh->self->name, from->name, REQ_PUBKEY); return true; } @@ -239,7 +244,7 @@ bool req_key_h(meshlink_handle_t *mesh, connection_t *c, const char *request) { return true; } - send_request(mesh, to->nexthop->connection, "%s", request); + send_request(mesh, to->nexthop->connection, NULL, "%s", request); } return true; @@ -301,13 +306,13 @@ bool ans_key_h(meshlink_handle_t *mesh, connection_t *c, const char *request) { char *address, *port; logger(mesh, MESHLINK_DEBUG, "Appending reflexive UDP address to ANS_KEY from %s to %s", from->name, to->name); sockaddr2str(&from->address, &address, &port); - send_request(mesh, to->nexthop->connection, "%s %s %s", request, address, port); + send_request(mesh, to->nexthop->connection, NULL, "%s %s %s", request, address, port); free(address); free(port); return true; } - return send_request(mesh, to->nexthop->connection, "%s", request); + return send_request(mesh, to->nexthop->connection, NULL, "%s", request); } /* Don't use key material until every check has passed. */ diff --git a/src/protocol_misc.c b/src/protocol_misc.c index 727881bd..d0401b93 100644 --- a/src/protocol_misc.c +++ b/src/protocol_misc.c @@ -72,7 +72,7 @@ bool send_ping(meshlink_handle_t *mesh, connection_t *c) { c->status.pinged = true; c->last_ping_time = mesh->loop.now.tv_sec; - return send_request(mesh, c, "%d", PING); + return send_request(mesh, c, NULL, "%d", PING); } bool ping_h(meshlink_handle_t *mesh, connection_t *c, const char *request) { @@ -81,7 +81,7 @@ bool ping_h(meshlink_handle_t *mesh, connection_t *c, const char *request) { } bool send_pong(meshlink_handle_t *mesh, connection_t *c) { - return send_request(mesh, c, "%d", PONG); + return send_request(mesh, c, NULL, "%d", PONG); } bool pong_h(meshlink_handle_t *mesh, connection_t *c, const char *request) { diff --git a/src/submesh.c b/src/submesh.c index 428ab5b6..7d4a326e 100644 --- a/src/submesh.c +++ b/src/submesh.c @@ -1,6 +1,6 @@ /* - node.c -- node tree management - Copyright (C) 2014 Guus Sliepen , + submesh.c -- submesh management + Copyright (C) 2019 Guus Sliepen , 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 @@ -28,6 +28,7 @@ #include "splay_tree.h" #include "utils.h" #include "xalloc.h" +#include "protocol.h" void init_submeshes(meshlink_handle_t *mesh) { mesh->submeshes = list_alloc((list_action_t)free_submesh); @@ -55,6 +56,73 @@ void free_submesh(submesh_t *s) { free(s); } +static submesh_t *submesh_new(meshlink_handle_t *mesh, const char *submesh) { + submesh_t *s = NULL; + + s = new_submesh(); + s->name = xstrdup(submesh); + + submesh_add(mesh, (submesh_t *)s); + return s; +} + +submesh_t *create_submesh(meshlink_handle_t *mesh, const char *submesh) { + submesh_t *s = NULL; + + if(0 == strcmp(submesh, CORE_MESH)) { + logger(NULL, MESHLINK_ERROR, "Cannot create submesh handle for core mesh!\n"); + meshlink_errno = MESHLINK_EINVAL; + return NULL; + } + + if(!check_id(submesh)) { + logger(NULL, MESHLINK_ERROR, "Invalid SubMesh Id!\n"); + meshlink_errno = MESHLINK_EINVAL; + return NULL; + } + + s = lookup_submesh(mesh, submesh); + + if(s) { + logger(NULL, MESHLINK_ERROR, "SubMesh Already exists!\n"); + meshlink_errno = MESHLINK_EEXIST; + return NULL; + } + + s = submesh_new(mesh, submesh); + + meshlink_errno = MESHLINK_OK; + return s; +} + +submesh_t *lookup_or_create_submesh(meshlink_handle_t *mesh, const char *submesh) { + submesh_t *s = NULL; + + if(0 == strcmp(submesh, CORE_MESH)) { + logger(NULL, MESHLINK_ERROR, "Cannot create submesh handle for core mesh!\n"); + meshlink_errno = MESHLINK_EINVAL; + return NULL; + } + + if(!check_id(submesh)) { + logger(NULL, MESHLINK_ERROR, "Invalid SubMesh Id!\n"); + meshlink_errno = MESHLINK_EINVAL; + return NULL; + } + + s = lookup_submesh(mesh, submesh); + + if(s) { + meshlink_errno = MESHLINK_OK; + return s; + } + + s = submesh_new(mesh, submesh); + + meshlink_errno = MESHLINK_OK; + return s; +} + void submesh_add(meshlink_handle_t *mesh, submesh_t *s) { s->mesh = mesh; list_insert_tail(mesh->submeshes, (void *)s); @@ -80,3 +148,11 @@ submesh_t *lookup_submesh(struct meshlink_handle *mesh, const char *submesh_name return submesh; } + +bool submesh_allows_node(const submesh_t *submesh, const node_t *node) { + if(!node->submesh || !submesh || submesh == node->submesh) { + return true; + } else { + return false; + } +} \ No newline at end of file diff --git a/src/submesh.h b/src/submesh.h index b5d90b30..31f166a4 100644 --- a/src/submesh.h +++ b/src/submesh.h @@ -2,8 +2,8 @@ #define MESHLINK_SUBMESH_H /* - submesh.h -- header for node.c - Copyright (C) 2014, 2017 Guus Sliepen + submesh.h -- header for submesh.c + Copyright (C) 2019 Guus Sliepen 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 @@ -22,6 +22,8 @@ #include "meshlink_internal.h" +#define CORE_MESH "." + typedef struct submesh_t { char *name; /* name of this Sub-Mesh */ void *priv; @@ -33,8 +35,11 @@ extern void init_submeshes(struct meshlink_handle *mesh); extern void exit_submeshes(struct meshlink_handle *mesh); extern submesh_t *new_submesh(void) __attribute__((__malloc__)); extern void free_submesh(submesh_t *); +extern submesh_t *create_submesh(struct meshlink_handle *mesh, const char *); extern void submesh_add(struct meshlink_handle *mesh, submesh_t *); extern void submesh_del(struct meshlink_handle *mesh, submesh_t *); extern submesh_t *lookup_submesh(struct meshlink_handle *mesh, const char *); +extern submesh_t *lookup_or_create_submesh(struct meshlink_handle *mesh, const char *); +extern bool submesh_allows_node(const submesh_t *submesh, const struct node_t *node); #endif -- 2.39.2