#include "node.h"
#include "protocol.h"
#include "route.h"
+#include "sockaddr.h"
#include "utils.h"
#include "xalloc.h"
#include "ed25519/sha512.h"
fclose(f);
}
-static char *get_my_hostname(meshlink_handle_t* mesh) {
- char *hostname = NULL;
- char *port = NULL;
- char *hostport = NULL;
- char *name = mesh->self->name;
- char filename[PATH_MAX] = "";
- char line[4096];
- FILE *f;
- // Use first Address statement in own host config file
- snprintf(filename, sizeof filename, "%s" SLASH "hosts" SLASH "%s", mesh->confbase, name);
- scan_for_hostname(filename, &hostname, &port);
+static bool is_valid_hostname(const char *hostname) {
+ for(const char *p = hostname; *p; p++) {
+ if(!(isalnum(*p) || *p == '-' || *p == '.' || *p == ':'))
+ return false;
+ }
- if(hostname)
- goto done;
+ return true;
+}
+
+char *meshlink_get_external_address(meshlink_handle_t *mesh) {
+ char *hostname = NULL;
- // If that doesn't work, guess externally visible hostname
logger(mesh, MESHLINK_DEBUG, "Trying to discover externally visible hostname...\n");
struct addrinfo *ai = str2addrinfo("meshlink.io", "80", SOCK_STREAM);
struct addrinfo *aip = ai;
static const char request[] = "GET http://www.meshlink.io/host.cgi HTTP/1.0\r\n\r\n";
+ char line[256];
while(aip) {
int s = socket(aip->ai_family, aip->ai_socktype, aip->ai_protocol);
freeaddrinfo(ai);
// Check that the hostname is reasonable
- if(hostname) {
- for(char *p = hostname; *p; p++) {
- if(isalnum(*p) || *p == '-' || *p == '.' || *p == ':')
- continue;
- // If not, forget it.
- free(hostname);
- hostname = NULL;
- break;
- }
+ if(hostname && !is_valid_hostname(hostname)) {
+ free(hostname);
+ hostname = NULL;
}
+ if(!hostname)
+ meshlink_errno = MESHLINK_ERESOLV;
+
+ return hostname;
+}
+
+static char *get_my_hostname(meshlink_handle_t* mesh) {
+ char *hostname = NULL;
+ char *port = NULL;
+ char *hostport = NULL;
+ char *name = mesh->self->name;
+ char filename[PATH_MAX] = "";
+ FILE *f;
+
+ // Use first Address statement in own host config file
+ snprintf(filename, sizeof filename, "%s" SLASH "hosts" SLASH "%s", mesh->confbase, name);
+ scan_for_hostname(filename, &hostname, &port);
+
+ if(hostname)
+ goto done;
+
+ hostname = meshlink_get_external_address(mesh);
if(!hostname)
return NULL;
meshlink_errno = MESHLINK_EINVAL;
return false;
}
- pthread_mutex_lock(&(mesh->mesh_mutex));
logger(mesh, MESHLINK_DEBUG, "meshlink_start called\n");
+ pthread_mutex_lock(&(mesh->mesh_mutex));
+
+ if(mesh->threadstarted) {
+ logger(mesh, MESHLINK_DEBUG, "thread was already running\n");
+ pthread_mutex_unlock(&(mesh->mesh_mutex));
+ return true;
+ }
+
+ if(mesh->listen_socket[0].tcp.fd < 0) {
+ logger(mesh, MESHLINK_ERROR, "Listening socket not open\n");
+ meshlink_errno = MESHLINK_ENETWORK;
+ return false;
+ }
+
mesh->thedatalen = 0;
// TODO: open listening sockets first
// Start the main thread
+ event_loop_start(&mesh->loop);
+
if(pthread_create(&mesh->thread, NULL, meshlink_main_loop, mesh) != 0) {
logger(mesh, MESHLINK_DEBUG, "Could not start thread: %s\n", strerror(errno));
memset(&mesh->thread, 0, sizeof mesh->thread);
// Stop discovery
discovery_stop(mesh);
- // Shut down a listening socket to signal the main thread to shut down
+ pthread_mutex_lock(&(mesh->mesh_mutex));
+ logger(mesh, MESHLINK_DEBUG, "meshlink_stop called\n");
+ // Shut down the main thread
+ event_loop_stop(&mesh->loop);
+
+ // Send ourselves a UDP packet to kick the event loop
listen_socket_t *s = &mesh->listen_socket[0];
- shutdown(s->tcp.fd, SHUT_RDWR);
+ if(sendto(s->udp.fd, "", 1, MSG_NOSIGNAL, &s->sa.sa, SALEN(s->sa.sa)) == -1)
+ logger(mesh, MESHLINK_ERROR, "Could not send a UDP packet to ourself");
// Wait for the main thread to finish
pthread_mutex_unlock(&(mesh->mesh_mutex));
mesh->threadstarted = false;
- // Fix the socket
-
- closesocket(s->tcp.fd);
- io_del(&mesh->loop, &s->tcp);
- s->tcp.fd = setup_listen_socket(&s->sa);
- if(s->tcp.fd < 0)
- logger(mesh, MESHLINK_ERROR, "Could not repair listenen socket!");
- else
- io_add(&mesh->loop, &s->tcp, handle_new_meta_connection, s, s->tcp.fd, IO_READ);
-
pthread_mutex_unlock(&(mesh->mesh_mutex));
}
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;
+ }
+
bool rval = false;
pthread_mutex_lock(&(mesh->mesh_mutex));
+ rval = append_config_file(mesh, mesh->self->name, "Address", address);
+ pthread_mutex_unlock(&(mesh->mesh_mutex));
- for(const char *p = address; *p; p++) {
- if(isalnum(*p) || *p == '-' || *p == '.' || *p == ':')
- continue;
- logger(mesh, MESHLINK_DEBUG, "Invalid character in address: %s\n", address);
+ return rval;
+}
+
+bool meshlink_add_external_address(meshlink_handle_t *mesh) {
+ if(!mesh) {
meshlink_errno = MESHLINK_EINVAL;
- pthread_mutex_unlock(&(mesh->mesh_mutex));
return false;
}
+ char *address = meshlink_get_external_address(mesh);
+ if(!address)
+ return false;
+
+ bool rval = false;
+
+ pthread_mutex_lock(&(mesh->mesh_mutex));
rval = append_config_file(mesh, mesh->self->name, "Address", address);
pthread_mutex_unlock(&(mesh->mesh_mutex));
+
+ free(address);
return rval;
}
*nmemb = result_size;
} else {
*nmemb = 0;
- free(result);
meshlink_errno = MESHLINK_ENOMEM;
}