]> git.meshlink.io Git - meshlink/blobdiff - src/meshlink.c
Add meshlink_set_external_address_discovery_url().
[meshlink] / src / meshlink.c
index 07c518e0dd8c8c112aea2f85a84a756947998005..3ebaee01da441aa589279e2ecd4076dd75cc7f1b 100644 (file)
@@ -221,12 +221,42 @@ char *meshlink_get_external_address(meshlink_handle_t *mesh) {
 }
 
 char *meshlink_get_external_address_for_family(meshlink_handle_t *mesh, int family) {
-       char *hostname = NULL;
+       const char *url = mesh->external_address_url;
+
+       if(!url) {
+               url = "http://meshlink.io/host.cgi";
+       }
+
+       /* Find the hostname part between the slashes */
+       if(strncmp(url, "http://", 7)) {
+               abort();
+               meshlink_errno = MESHLINK_EINTERNAL;
+               return NULL;
+       }
+
+       const char *begin = url + 7;
+
+       const char *end = strchr(begin, '/');
+
+       if(!end) {
+               end = begin + strlen(begin);
+       }
+
+       /* Make a copy */
+       char host[end - begin + 1];
+       strncpy(host, begin, end - begin);
+       host[end - begin] = 0;
+
+       char *port = strchr(host, ':');
+
+       if(port) {
+               *port++ = 0;
+       }
 
        logger(mesh, MESHLINK_DEBUG, "Trying to discover externally visible hostname...\n");
-       struct addrinfo *ai = str2addrinfo("meshlink.io", "80", SOCK_STREAM);
-       static const char request[] = "GET http://www.meshlink.io/host.cgi HTTP/1.0\r\n\r\n";
+       struct addrinfo *ai = str2addrinfo(host, port ? port : "80", SOCK_STREAM);
        char line[256];
+       char *hostname = NULL;
 
        for(struct addrinfo *aip = ai; aip; aip = aip->ai_next) {
                if(family != AF_UNSPEC && aip->ai_family != family) {
@@ -245,7 +275,9 @@ char *meshlink_get_external_address_for_family(meshlink_handle_t *mesh, int fami
                }
 
                if(s >= 0) {
-                       send(s, request, sizeof(request) - 1, 0);
+                       send(s, "GET ", 4, 0);
+                       send(s, url, strlen(url), 0);
+                       send(s, " HTTP/1.0\r\n\r\n", 13, 0);
                        int len = recv(s, line, sizeof(line) - 1, MSG_WAITALL);
 
                        if(len > 0) {
@@ -537,26 +569,52 @@ static bool try_bind(int port) {
                return false;
        }
 
-       //while(ai) {
+       bool success = false;
+
        for(struct addrinfo *aip = ai; aip; aip = aip->ai_next) {
-               int fd = socket(aip->ai_family, SOCK_STREAM, IPPROTO_TCP);
+               /* Try to bind to TCP. */
 
-               if(!fd) {
-                       freeaddrinfo(ai);
-                       return false;
+               int tcp_fd = socket(aip->ai_family, SOCK_STREAM, IPPROTO_TCP);
+
+               if(tcp_fd == -1) {
+                       continue;
                }
 
-               int result = bind(fd, aip->ai_addr, aip->ai_addrlen);
-               closesocket(fd);
+               int result = bind(tcp_fd, aip->ai_addr, aip->ai_addrlen);
+               closesocket(tcp_fd);
 
                if(result) {
-                       freeaddrinfo(ai);
-                       return false;
+                       if(errno == EADDRINUSE) {
+                               /* If this port is in use for any address family, avoid it. */
+                               success = false;
+                               break;
+                       } else {
+                               continue;
+                       }
                }
+
+               /* If TCP worked, then we require that UDP works as well. */
+
+               int udp_fd = socket(aip->ai_family, SOCK_DGRAM, IPPROTO_UDP);
+
+               if(udp_fd == -1) {
+                       success = false;
+                       break;
+               }
+
+               result = bind(udp_fd, aip->ai_addr, aip->ai_addrlen);
+               closesocket(udp_fd);
+
+               if(result) {
+                       success = false;
+                       break;
+               }
+
+               success = true;
        }
 
        freeaddrinfo(ai);
-       return true;
+       return success;
 }
 
 static int check_port(meshlink_handle_t *mesh) {
@@ -1558,9 +1616,6 @@ static void *meshlink_main_loop(void *arg) {
 }
 
 bool meshlink_start(meshlink_handle_t *mesh) {
-       assert(mesh->self);
-       assert(mesh->private_key);
-
        if(!mesh) {
                meshlink_errno = MESHLINK_EINVAL;
                return false;
@@ -1570,6 +1625,8 @@ bool meshlink_start(meshlink_handle_t *mesh) {
 
        pthread_mutex_lock(&mesh->mutex);
 
+       assert(mesh->self);
+       assert(mesh->private_key);
        assert(mesh->self->ecdsa);
        assert(!memcmp((uint8_t *)mesh->self->ecdsa + 64, (uint8_t *)mesh->private_key + 64, 32));
 
@@ -1729,6 +1786,7 @@ void meshlink_close(meshlink_handle_t *mesh) {
        free(mesh->appname);
        free(mesh->confbase);
        free(mesh->config_key);
+       free(mesh->external_address_url);
        ecdsa_free(mesh->private_key);
 
        main_config_unlock(mesh);
@@ -2279,7 +2337,7 @@ bool meshlink_sign(meshlink_handle_t *mesh, const void *data, size_t len, void *
 }
 
 bool meshlink_verify(meshlink_handle_t *mesh, meshlink_node_t *source, const void *data, size_t len, const void *signature, size_t siglen) {
-       if(!mesh || !data || !len || !signature) {
+       if(!mesh || !source || !data || !len || !signature) {
                meshlink_errno = MESHLINK_EINVAL;
                return false;
        }
@@ -2744,6 +2802,8 @@ bool meshlink_join(meshlink_handle_t *mesh, const char *invitation) {
                                        state.sock = -1;
                                        continue;
                                }
+
+                               break;
                        }
 
                        freeaddrinfo(ai);
@@ -3959,6 +4019,23 @@ extern void meshlink_set_inviter_commits_first(struct meshlink_handle *mesh, boo
        pthread_mutex_unlock(&mesh->mutex);
 }
 
+void meshlink_set_external_address_discovery_url(struct meshlink_handle *mesh, const char *url) {
+       if(!mesh) {
+               meshlink_errno = EINVAL;
+               return;
+       }
+
+       if(url && (strncmp(url, "http://", 7) || strchr(url, ' '))) {
+               meshlink_errno = EINVAL;
+               return;
+       }
+
+       pthread_mutex_lock(&mesh->mutex);
+       free(mesh->external_address_url);
+       mesh->external_address_url = url ? xstrdup(url) : NULL;
+       pthread_mutex_unlock(&mesh->mutex);
+}
+
 void handle_network_change(meshlink_handle_t *mesh, bool online) {
        (void)online;