Add meshlink_add_invitation_address(), deprecate meshlink_add_address().
authorGuus Sliepen <guus@meshlink.io>
Fri, 6 Mar 2020 22:20:22 +0000 (23:20 +0100)
committerGuus Sliepen <guus@meshlink.io>
Fri, 6 Mar 2020 22:20:22 +0000 (23:20 +0100)
This adds a function to add one or more application-controlled address and
port combinations to invitation URLs. It is meant to replace
meshlink_add_address(), which is too limited because it only allows one
address to be set, and doesn't allow a different port number to be set.

13 files changed:
src/meshlink++.h
src/meshlink.c
src/meshlink.h
src/meshlink.sym
src/meshlink_internal.h
test/blacklist.c
test/channels-fork.c
test/get-all-nodes.c
test/import-export.c
test/invite-join.c
test/trio.c
test/trio2.c
test/utils.c

index 11e7eab..8493c1e 100644 (file)
@@ -486,11 +486,10 @@ public:
                return meshlink_set_canonical_address(handle, node, address, port);
        }
 
-       /// Set the canonical Address for the local node.
-       /** This function sets the canonical Address for the local node.
-        *  This address is stored permanently until it is changed by another call to this function,
-        *  unlike other addresses associated with a node,
-        *  such as those added with meshlink_hint_address() or addresses discovered at runtime.
+       /// Add an invitation address for the local node.
+       /** This function adds an address for the local node, which will be used only for invitation URLs.
+        *  This address is not stored permanently.
+        *  Multiple addresses can be added using multiple calls to this function.
         *
         *  @param address      A nul-terminated C string containing the address, which can be either in numeric format or a hostname.
         *  @param port         A nul-terminated C string containing the port, which can be either in numeric or symbolic format.
@@ -498,19 +497,27 @@ public:
         *
         *  @return             This function returns true if the address was added, false otherwise.
         */
-       bool set_canonical_address(const char *address, const char *port = NULL) {
-               return meshlink_set_canonical_address(handle, get_self(), address, port);
+       bool add_invitation_address(const char *address, const char *port) {
+               return meshlink_add_invitation_address(handle, address, port);
+       }
+
+       /// Clears all invitation address for the local node.
+       /** This function removes all addresses added with meshlink_add_invitation_address().
+        */
+       void clear_invitation_addresses() {
+               return meshlink_clear_invitation_addresses(handle);
        }
 
        /// Add an Address for the local node.
        /** This function adds an Address for the local node, which will be used for invitation URLs.
+        *  @deprecated This function is deprecated, use set_canonical_address() and/or add_invitation_address().
         *
         *  @param address      A string containing the address, which can be either in numeric format or a hostname.
         *
         *  @return             This function returns true if the address was added, false otherwise.
         */
-       bool add_address(const char *address) {
-               return meshlink_add_address(handle, address);
+       bool add_address(const char *address) __attribute__((__deprecated__("use set_canonical_address() and/or add_invitation_address() instead"))) {
+               return meshlink_set_canonical_address(handle, get_self(), address, NULL);
        }
 
        /** This function performs tries to discover the local node's external address
index 3ebaee0..0090d54 100644 (file)
@@ -421,10 +421,15 @@ void remove_duplicate_hostnames(char *host[], char *port[], int n) {
 
 // This gets the hostname part for use in invitation URLs
 static char *get_my_hostname(meshlink_handle_t *mesh, uint32_t flags) {
-       char *hostname[4] = {NULL};
-       char *port[4] = {NULL};
+       int count = 4 + (mesh->invitation_addresses ? mesh->invitation_addresses->count : 0);
+       int n = 0;
+       char *hostname[count];
+       char *port[count];
        char *hostport = NULL;
 
+       memset(hostname, 0, sizeof(hostname));
+       memset(port, 0, sizeof(port));
+
        if(!(flags & (MESHLINK_INVITE_LOCAL | MESHLINK_INVITE_PUBLIC))) {
                flags |= MESHLINK_INVITE_LOCAL | MESHLINK_INVITE_PUBLIC;
        }
@@ -433,30 +438,47 @@ static char *get_my_hostname(meshlink_handle_t *mesh, uint32_t flags) {
                flags |= MESHLINK_INVITE_IPV4 | MESHLINK_INVITE_IPV6;
        }
 
+       // Add all explicitly set invitation addresses
+       if(mesh->invitation_addresses) {
+               for list_each(char, combo, mesh->invitation_addresses) {
+                       hostname[n] = xstrdup(combo);
+                       char *colon = strchr(hostname[n], ':');
+
+                       if(colon) {
+                               *colon = 0;
+                               port[n] = colon + 1;
+                       }
+
+                       n++;
+               }
+       }
+
        // Add local addresses if requested
        if(flags & MESHLINK_INVITE_LOCAL) {
                if(flags & MESHLINK_INVITE_IPV4) {
-                       hostname[0] = meshlink_get_local_address_for_family(mesh, AF_INET);
+                       hostname[n++] = meshlink_get_local_address_for_family(mesh, AF_INET);
                }
 
                if(flags & MESHLINK_INVITE_IPV6) {
-                       hostname[1] = meshlink_get_local_address_for_family(mesh, AF_INET6);
+                       hostname[n++] = meshlink_get_local_address_for_family(mesh, AF_INET6);
                }
        }
 
        // Add public/canonical addresses if requested
        if(flags & MESHLINK_INVITE_PUBLIC) {
                // Try the CanonicalAddress first
-               get_canonical_address(mesh->self, &hostname[2], &port[2]);
+               get_canonical_address(mesh->self, &hostname[n], &port[n]);
 
-               if(!hostname[2]) {
+               if(!hostname[n] && count == 4) {
                        if(flags & MESHLINK_INVITE_IPV4) {
-                               hostname[2] = meshlink_get_external_address_for_family(mesh, AF_INET);
+                               hostname[n++] = meshlink_get_external_address_for_family(mesh, AF_INET);
                        }
 
                        if(flags & MESHLINK_INVITE_IPV6) {
-                               hostname[3] = meshlink_get_external_address_for_family(mesh, AF_INET6);
+                               hostname[n++] = meshlink_get_external_address_for_family(mesh, AF_INET6);
                        }
+               } else {
+                       n++;
                }
        }
 
@@ -1789,6 +1811,10 @@ void meshlink_close(meshlink_handle_t *mesh) {
        free(mesh->external_address_url);
        ecdsa_free(mesh->private_key);
 
+       if(mesh->invitation_addresses) {
+               list_delete_list(mesh->invitation_addresses);
+       }
+
        main_config_unlock(mesh);
 
        pthread_mutex_unlock(&mesh->mutex);
@@ -2420,6 +2446,64 @@ bool meshlink_set_canonical_address(meshlink_handle_t *mesh, meshlink_node_t *no
        return config_sync(mesh, "current");
 }
 
+bool meshlink_add_invitation_address(struct meshlink_handle *mesh, const char *address, const char *port) {
+       if(!mesh || !address) {
+               meshlink_errno = MESHLINK_EINVAL;
+               return false;
+       }
+
+       if(!is_valid_hostname(address)) {
+               logger(mesh, MESHLINK_DEBUG, "Invalid character in address: %s\n", address);
+               meshlink_errno = MESHLINK_EINVAL;
+               return false;
+       }
+
+       if(port && !is_valid_port(port)) {
+               logger(mesh, MESHLINK_DEBUG, "Invalid character in port: %s\n", address);
+               meshlink_errno = MESHLINK_EINVAL;
+               return false;
+       }
+
+       char *combo;
+
+       if(port) {
+               if(strchr(address, ':')) {
+                       xasprintf(&combo, "[%s]:%s", address, port);
+               } else {
+                       xasprintf(&combo, "%s:%s", address, port);
+               }
+       } else {
+               combo = xstrdup(address);
+       }
+
+       pthread_mutex_lock(&mesh->mutex);
+
+       if(!mesh->invitation_addresses) {
+               mesh->invitation_addresses = list_alloc((list_action_t)free);
+       }
+
+       list_insert_tail(mesh->invitation_addresses, combo);
+       pthread_mutex_unlock(&mesh->mutex);
+
+       return true;
+}
+
+void meshlink_clear_invitation_addresses(struct meshlink_handle *mesh) {
+       if(!mesh) {
+               meshlink_errno = MESHLINK_EINVAL;
+               return;
+       }
+
+       pthread_mutex_lock(&mesh->mutex);
+
+       if(mesh->invitation_addresses) {
+               list_delete_list(mesh->invitation_addresses);
+               mesh->invitation_addresses = NULL;
+       }
+
+       pthread_mutex_unlock(&mesh->mutex);
+}
+
 bool meshlink_add_address(meshlink_handle_t *mesh, const char *address) {
        return meshlink_set_canonical_address(mesh, (meshlink_node_t *)mesh->self, address, NULL);
 }
@@ -2436,7 +2520,7 @@ bool meshlink_add_external_address(meshlink_handle_t *mesh) {
                return false;
        }
 
-       bool rval = meshlink_add_address(mesh, address);
+       bool rval = meshlink_set_canonical_address(mesh, (meshlink_node_t *)mesh->self, address, NULL);
        free(address);
 
        return rval;
index 2877c64..1397626 100644 (file)
@@ -810,8 +810,32 @@ extern bool meshlink_verify(struct meshlink_handle *mesh, struct meshlink_node *
  */
 extern bool meshlink_set_canonical_address(struct meshlink_handle *mesh, struct meshlink_node *node, const char *address, const char *port) __attribute__((__warn_unused_result__));
 
+/// Add an invitation address for the local node.
+/** This function adds an address for the local node, which will be used only for invitation URLs.
+ *  This address is not stored permanently.
+ *  Multiple addresses can be added using multiple calls to this function.
+ *
+ *  \memberof meshlink_handle
+ *  @param mesh         A handle which represents an instance of MeshLink.
+ *  @param address      A nul-terminated C string containing the address, which can be either in numeric format or a hostname.
+ *  @param port         A nul-terminated C string containing the port, which can be either in numeric or symbolic format.
+ *                      If it is NULL, the listening port's number will be used.
+ *
+ *  @return             This function returns true if the address was added, false otherwise.
+ */
+extern bool meshlink_add_invitation_address(struct meshlink_handle *mesh, const char *address, const char *port) __attribute__((__warn_unused_result__));
+
+/// Clears all invitation address for the local node.
+/** This function removes all addresses added with meshlink_add_invitation_address().
+ *
+ *  \memberof meshlink_handle
+ *  @param mesh         A handle which represents an instance of MeshLink.
+ */
+extern void meshlink_clear_invitation_addresses(struct meshlink_handle *mesh);
+
 /// Add an Address for the local node.
 /** This function adds an Address for the local node, which will be used for invitation URLs.
+ *  @deprecated This function is deprecated, use meshlink_set_canonical_address() and/or meshlink_add_invitation_address().
  *
  *  \memberof meshlink_handle
  *  @param mesh         A handle which represents an instance of MeshLink.
@@ -819,7 +843,7 @@ extern bool meshlink_set_canonical_address(struct meshlink_handle *mesh, struct
  *
  *  @return             This function returns true if the address was added, false otherwise.
  */
-extern bool meshlink_add_address(struct meshlink_handle *mesh, const char *address) __attribute__((__warn_unused_result__));
+extern bool meshlink_add_address(struct meshlink_handle *mesh, const char *address) __attribute__((__warn_unused_result__, __deprecated__("use meshlink_set_canonical_address() and/or meshlink_add_invitation_address() instead")));
 
 /// Try to discover the external address for the local node.
 /** This function performs tries to discover the local node's external address
@@ -897,7 +921,7 @@ extern char *meshlink_get_local_address_for_family(struct meshlink_handle *mesh,
 /// Try to discover the external address for the local node, and add it to its list of addresses.
 /** This function is equivalent to:
  *
- *    meshlink_add_address(mesh, meshlink_get_external_address(mesh));
+ *    meshlink_set_canonical_address(mesh, meshlink_get_self(mesh), meshlink_get_external_address(mesh), NULL);
  *
  *  Read the description of meshlink_get_external_address() for the limitations of this function.
  *
index 6c4dd57..57eea5e 100644 (file)
@@ -9,6 +9,7 @@ devtool_set_inviter_commits_first
 devtool_trybind_probe
 meshlink_add_address
 meshlink_add_external_address
+meshlink_add_invitation_address
 meshlink_blacklist
 meshlink_blacklist_by_name
 meshlink_channel_aio_fd_receive
@@ -23,6 +24,7 @@ meshlink_channel_open
 meshlink_channel_open_ex
 meshlink_channel_send
 meshlink_channel_shutdown
+meshlink_clear_invitation_addresses
 meshlink_close
 meshlink_destroy
 meshlink_enable_discovery
index 8c67aa3..42df8b8 100644 (file)
@@ -175,6 +175,7 @@ struct meshlink_handle {
        FILE *lockfile;
        void *config_key;
        char *external_address_url;
+       struct list_t *invitation_addresses;
 
        // Thread management
        pthread_t thread;
index 4be4cbd..11a330e 100644 (file)
@@ -62,7 +62,7 @@ int main() {
                assert(mesh[i]);
                free(path);
 
-               assert(meshlink_add_address(mesh[i], "localhost"));
+               assert(meshlink_set_canonical_address(mesh[i], meshlink_get_self(mesh[i]), "localhost", NULL));
 
                data[i] = meshlink_export(mesh[i]);
                assert(data[i]);
index 9168168..f331d0d 100644 (file)
@@ -96,7 +96,7 @@ static int main1(int rfd, int wfd) {
 
        meshlink_enable_discovery(mesh, false);
 
-       assert(meshlink_add_address(mesh, "localhost"));
+       assert(meshlink_set_canonical_address(mesh, meshlink_get_self(mesh), "localhost", NULL));
 
        char *data = meshlink_export(mesh);
        assert(data);
@@ -152,7 +152,7 @@ static int main2(int rfd, int wfd) {
 
        meshlink_enable_discovery(mesh, false);
 
-       assert(meshlink_add_address(mesh, "localhost"));
+       assert(meshlink_set_canonical_address(mesh, meshlink_get_self(mesh), "localhost", NULL));
 
        char *data = meshlink_export(mesh);
        assert(data);
index 5dc4af1..65a0a8a 100644 (file)
@@ -64,7 +64,7 @@ int main() {
 
        for(int i = 0; i < 3; i++) {
                meshlink_enable_discovery(mesh[i], false);
-               assert(meshlink_add_address(mesh[i], "localhost"));
+               assert(meshlink_set_canonical_address(mesh[i], meshlink_get_self(mesh[i]), "localhost", NULL));
                char *data = meshlink_export(mesh[i]);
                assert(data);
 
index 392f1da..5d37146 100644 (file)
@@ -43,8 +43,8 @@ int main() {
 
        // Import and export both side's data
 
-       assert(meshlink_add_address(mesh1, "localhost"));
-       assert(meshlink_add_address(mesh2, "localhost"));
+       assert(meshlink_set_canonical_address(mesh1, meshlink_get_self(mesh1), "localhost", NULL));
+       assert(meshlink_set_canonical_address(mesh2, meshlink_get_self(mesh2), "localhost", NULL));
 
        char *data = meshlink_export(mesh1);
        assert(data);
index 1dd6c26..831cac4 100644 (file)
@@ -50,7 +50,7 @@ int main() {
 
        meshlink_set_node_status_cb(mesh1, status_cb);
 
-       assert(meshlink_add_address(mesh1, "localhost"));
+       assert(meshlink_set_canonical_address(mesh1, meshlink_get_self(mesh1), "localhost", NULL));
        char *baz_url = meshlink_invite(mesh1, NULL, "baz");
        assert(baz_url);
 
index a183b3d..4362f6d 100644 (file)
@@ -65,7 +65,7 @@ int main() {
                assert(mesh[i]);
                free(path);
 
-               assert(meshlink_add_address(mesh[i], "localhost"));
+               assert(meshlink_set_canonical_address(mesh[i], meshlink_get_self(mesh[i]), "localhost", NULL));
 
                data[i] = meshlink_export(mesh[i]);
                assert(data[i]);
index 5731298..d57af96 100644 (file)
@@ -65,7 +65,7 @@ int main() {
                assert(mesh[i]);
                free(path);
 
-               assert(meshlink_add_address(mesh[i], "localhost"));
+               assert(meshlink_set_canonical_address(mesh[i], meshlink_get_self(mesh[i]), "localhost", NULL));
 
                data[i] = meshlink_export(mesh[i]);
                assert(data[i]);
index 28e3d62..d4ba6b6 100644 (file)
@@ -49,8 +49,8 @@ bool wait_sync_flag(struct sync_flag *s, int seconds) {
 void link_meshlink_pair(meshlink_handle_t *a, meshlink_handle_t *b) {
        // Import and export both side's data
 
-       assert(meshlink_add_address(a, "localhost"));
-       assert(meshlink_add_address(b, "localhost"));
+       assert(meshlink_set_canonical_address(a, meshlink_get_self(a), "localhost", NULL));
+       assert(meshlink_set_canonical_address(b, meshlink_get_self(b), "localhost", NULL));
 
        char *data = meshlink_export(a);
        assert(data);