]> git.meshlink.io Git - meshlink/commitdiff
Improve support for submeshes.
authorlakshminarayanagurram <lakshminarayana@elear.solutions>
Mon, 25 Feb 2019 10:00:35 +0000 (11:00 +0100)
committerGuus Sliepen <guus@meshlink.io>
Mon, 25 Feb 2019 10:25:45 +0000 (11:25 +0100)
14 files changed:
src/connection.h
src/meshlink.c
src/meshlink.h
src/meta.c
src/meta.h
src/net_packet.c
src/protocol.c
src/protocol.h
src/protocol_auth.c
src/protocol_edge.c
src/protocol_key.c
src/protocol_misc.c
src/submesh.c
src/submesh.h

index 9b272dc88741879e0e291405be05db0694e1717b..ca934a4976412eba97d346dc259cf50f76d559a6 100644 (file)
@@ -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;
index 8f0f82d1a8ae1c3afe5f94f0db22c134c2783ecd..6f83c22fbd762a8bc68fd0c71b01af1aa1cdd844 100644 (file)
@@ -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));
index a73bccf33beba50245feec92d659551ab39e0396..6f645373a4faa7e552864b32b93c31875ced053b 100644 (file)
@@ -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.
  *
index aa3499e95b8f1b3a059fc820b0a2fa885acc0873..d293b2ee2c8c75d626953c09d63f51276fe48961 100644 (file)
@@ -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;
index 6372e34af91dfb562a9d9aeaa072a27983072b5b..88e601a3fb9f98a3694bbb524df46c126ca5b7db 100644 (file)
@@ -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
index 162dcef2075ea571d467a1ac3b7d18f9de24f18e..857f00fac867452be47c1a5b63e652945333ae49 100644 (file)
@@ -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);
                }
        }
 
index 785e20b534b83213f9ed28b01941cce34b494e86..95f6aa39f49eda059094a615753ce417c33a43ed 100644 (file)
@@ -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) {
index 92ccef01482f7d8882b431c35420812cdac55a3a..47aacd990f1966fb1a6dc0a04219311c55d9fea8 100644 (file)
@@ -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 *);
 
index 487f34c96ebef3f640ea2339540dc7607100fe62..7f00da2b950b2c0690105b61e41f82ca7cadc040 100644 (file)
@@ -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) {
index 6788109847371e0afb7e6dd7ff754cf11661a0cb..5bfd6e21830d961bb51210a1b3be49dc87a0d5bd 100644 (file)
 #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 */
 
index cae95047220341def5d777f2e01f58ed309d6c53..43a227bbd65b459aaf7254a5069609ff2a1ea6f7 100644 (file)
@@ -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. */
index 727881bd1080476d2c5d9303b76d315f702cc2a0..d0401b93be299bddd5e232fda3f3bf6688ee6d58 100644 (file)
@@ -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) {
index 428ab5b61693f861400375765df240083079a13a..7d4a326ed733cd9bf551e4f3bf0ea041c34e8934 100644 (file)
@@ -1,6 +1,6 @@
 /*
-    node.c -- node tree management
-    Copyright (C) 2014 Guus Sliepen <guus@meshlink.io>,
+    submesh.c -- submesh management
+    Copyright (C) 2019 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
@@ -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
index b5d90b301d6ae726724c25b14fbc09ac79cab35e..31f166a45586c20843e60e6e8cc685de063b8d0a 100644 (file)
@@ -2,8 +2,8 @@
 #define MESHLINK_SUBMESH_H
 
 /*
-    submesh.h -- header for node.c
-    Copyright (C) 2014, 2017 Guus Sliepen <guus@meshlink.io>
+    submesh.h -- header for submesh.c
+    Copyright (C) 2019 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
@@ -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