From 3febbb4453f5c6b0286e7e3c68a5dbcec975b6fd Mon Sep 17 00:00:00 2001 From: Guus Sliepen Date: Fri, 6 Mar 2020 23:20:22 +0100 Subject: [PATCH] Add meshlink_add_invitation_address(), deprecate meshlink_add_address(). 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. --- src/meshlink++.h | 25 ++++++---- src/meshlink.c | 102 ++++++++++++++++++++++++++++++++++++---- src/meshlink.h | 28 ++++++++++- src/meshlink.sym | 2 + src/meshlink_internal.h | 1 + test/blacklist.c | 2 +- test/channels-fork.c | 4 +- test/get-all-nodes.c | 2 +- test/import-export.c | 4 +- test/invite-join.c | 2 +- test/trio.c | 2 +- test/trio2.c | 2 +- test/utils.c | 4 +- 13 files changed, 149 insertions(+), 31 deletions(-) diff --git a/src/meshlink++.h b/src/meshlink++.h index 11e7eabb..8493c1ed 100644 --- a/src/meshlink++.h +++ b/src/meshlink++.h @@ -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 diff --git a/src/meshlink.c b/src/meshlink.c index 3ebaee01..0090d54d 100644 --- a/src/meshlink.c +++ b/src/meshlink.c @@ -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; diff --git a/src/meshlink.h b/src/meshlink.h index 2877c64e..13976266 100644 --- a/src/meshlink.h +++ b/src/meshlink.h @@ -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. * diff --git a/src/meshlink.sym b/src/meshlink.sym index 6c4dd572..57eea5e5 100644 --- a/src/meshlink.sym +++ b/src/meshlink.sym @@ -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 diff --git a/src/meshlink_internal.h b/src/meshlink_internal.h index 8c67aa3e..42df8b89 100644 --- a/src/meshlink_internal.h +++ b/src/meshlink_internal.h @@ -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; diff --git a/test/blacklist.c b/test/blacklist.c index 4be4cbd0..11a330eb 100644 --- a/test/blacklist.c +++ b/test/blacklist.c @@ -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]); diff --git a/test/channels-fork.c b/test/channels-fork.c index 9168168c..f331d0d2 100644 --- a/test/channels-fork.c +++ b/test/channels-fork.c @@ -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); diff --git a/test/get-all-nodes.c b/test/get-all-nodes.c index 5dc4af1e..65a0a8a4 100644 --- a/test/get-all-nodes.c +++ b/test/get-all-nodes.c @@ -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); diff --git a/test/import-export.c b/test/import-export.c index 392f1dac..5d37146f 100644 --- a/test/import-export.c +++ b/test/import-export.c @@ -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); diff --git a/test/invite-join.c b/test/invite-join.c index 1dd6c26d..831cac41 100644 --- a/test/invite-join.c +++ b/test/invite-join.c @@ -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); diff --git a/test/trio.c b/test/trio.c index a183b3da..4362f6da 100644 --- a/test/trio.c +++ b/test/trio.c @@ -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]); diff --git a/test/trio2.c b/test/trio2.c index 57312988..d57af960 100644 --- a/test/trio2.c +++ b/test/trio2.c @@ -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]); diff --git a/test/utils.c b/test/utils.c index 28e3d62f..d4ba6b6d 100644 --- a/test/utils.c +++ b/test/utils.c @@ -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); -- 2.39.5