#include "system.h"
#include <pthread.h>
+#include "adns.h"
#include "crypto.h"
#include "ecdsagen.h"
#include "logger.h"
.ai_family = AF_UNSPEC,
.ai_socktype = SOCK_DGRAM,
.ai_protocol = IPPROTO_UDP,
+ .ai_flags = AI_NUMERICHOST | AI_NUMERICSERV,
};
if(getaddrinfo(destaddr, "80", &hint, &rai) || !rai) {
}
logger(mesh, MESHLINK_DEBUG, "Trying to discover externally visible hostname...\n");
- struct addrinfo *ai = str2addrinfo(host, port ? port : "80", SOCK_STREAM);
+ struct addrinfo *ai = adns_blocking_request(mesh, xstrdup(host), xstrdup(port ? port : "80"), 5);
char line[256];
char *hostname = NULL;
}
// Convert what we have to a sockaddr
- struct addrinfo *ai_in, *ai_out;
- struct addrinfo hint = {
- .ai_family = AF_UNSPEC,
- .ai_flags = AI_NUMERICSERV,
- .ai_socktype = SOCK_STREAM,
- };
- int err = getaddrinfo(hostname[i], port[i], &hint, &ai_in);
-
- if(err || !ai_in) {
+ struct addrinfo *ai_in = adns_blocking_request(mesh, xstrdup(hostname[i]), xstrdup(port[i]), 5);
+
+ if(!ai_in) {
continue;
}
node_add_recent_address(mesh, mesh->self, (sockaddr_t *)aip->ai_addr);
}
- if(flags & MESHLINK_INVITE_NUMERIC) {
- // We don't need to do any further conversion
- freeaddrinfo(ai_in);
- continue;
- }
-
- // Convert it to a hostname
- char resolved_host[NI_MAXHOST];
- char resolved_port[NI_MAXSERV];
- err = getnameinfo(ai_in->ai_addr, ai_in->ai_addrlen, resolved_host, sizeof resolved_host, resolved_port, sizeof resolved_port, NI_NUMERICSERV);
-
- if(err || !is_valid_hostname(resolved_host)) {
- freeaddrinfo(ai_in);
- continue;
- }
-
- // Convert the hostname back to a sockaddr
- hint.ai_family = ai_in->ai_family;
- err = getaddrinfo(resolved_host, resolved_port, &hint, &ai_out);
-
- if(err || !ai_out) {
- freeaddrinfo(ai_in);
- continue;
- }
-
- // Check if it's still the same sockaddr
- if(ai_in->ai_addrlen != ai_out->ai_addrlen || memcmp(ai_in->ai_addr, ai_out->ai_addr, ai_in->ai_addrlen)) {
- freeaddrinfo(ai_in);
- freeaddrinfo(ai_out);
- continue;
- }
-
- // Yes: replace the hostname with the resolved one
- free(hostname[i]);
- hostname[i] = xstrdup(resolved_host);
-
freeaddrinfo(ai_in);
- freeaddrinfo(ai_out);
+ continue;
}
// Remove duplicates again, since IPv4 and IPv6 addresses might map to the same hostname
}
char *name = packmsg_get_str_dup(&in);
- packmsg_skip_element(&in); /* submesh */
+ char *submesh_name = packmsg_get_str_dup(&in);
dev_class_t devclass = packmsg_get_int32(&in);
uint32_t count = packmsg_get_array(&in);
- if(!name) {
- logger(mesh, MESHLINK_DEBUG, "No Name found in invitation!\n");
+ if(!name || !check_id(name)) {
+ logger(mesh, MESHLINK_DEBUG, "No valid Name found in invitation!\n");
+ free(name);
+ free(submesh_name);
return false;
}
- if(!check_id(name)) {
- logger(mesh, MESHLINK_DEBUG, "Invalid Name found in invitation: %s!\n", name);
+ if(!submesh_name || (strcmp(submesh_name, CORE_MESH) && !check_id(submesh_name))) {
+ logger(mesh, MESHLINK_DEBUG, "No valid Submesh found in invitation!\n");
free(name);
+ free(submesh_name);
return false;
}
if(!count) {
logger(mesh, MESHLINK_ERROR, "Incomplete invitation file!\n");
free(name);
+ free(submesh_name);
return false;
}
free(mesh->self->name);
mesh->name = name;
mesh->self->name = xstrdup(name);
+ mesh->self->submesh = strcmp(submesh_name, CORE_MESH) ? lookup_or_create_submesh(mesh, submesh_name) : NULL;
+ free(submesh_name);
mesh->self->devclass = devclass == DEV_CLASS_UNKNOWN ? mesh->devclass : devclass;
// Initialize configuration directory
meshlink_handle_t *mesh = data;
struct timespec t, tmin = {3600, 0};
+#ifdef HAVE_SENDMMSG
+ flush_mmsg(mesh);
+#endif
+
for splay_each(node_t, n, mesh->nodes) {
if(!n->utcp) {
continue;
return false;
}
-#if 0
-
- // TODO: check this?
if(mesh->name && strcmp(mesh->name, name)) {
logger(NULL, MESHLINK_ERROR, "Configuration is for a different name (%s)!", name);
meshlink_errno = MESHLINK_ESTORAGE;
return false;
}
-#endif
-
free(mesh->name);
mesh->name = name;
xasprintf(&mesh->myport, "%u", myport);
return NULL;
}
- if(!name || !*name) {
- logger(NULL, MESHLINK_ERROR, "No name given!\n");
- meshlink_errno = MESHLINK_EINVAL;
- return NULL;
- };
-
- if(!check_id(name)) {
+ if(name && !check_id(name)) {
logger(NULL, MESHLINK_ERROR, "Invalid name given!\n");
meshlink_errno = MESHLINK_EINVAL;
return NULL;
meshlink_open_params_t *params = xzalloc(sizeof * params);
params->confbase = xstrdup(confbase);
- params->name = xstrdup(name);
+ params->name = name ? xstrdup(name) : NULL;
params->appname = xstrdup(appname);
params->devclass = devclass;
params->netns = -1;
}
meshlink_handle_t *meshlink_open_ephemeral(const char *name, const char *appname, dev_class_t devclass) {
+ if(!name) {
+ logger(NULL, MESHLINK_ERROR, "No name given!\n");
+ meshlink_errno = MESHLINK_EINVAL;
+ return NULL;
+ }
+
+ if(!check_id(name)) {
+ logger(NULL, MESHLINK_ERROR, "Invalid name given!\n");
+ meshlink_errno = MESHLINK_EINVAL;
+ return NULL;
+ }
+
+ if(!appname || !*appname) {
+ logger(NULL, MESHLINK_ERROR, "No appname given!\n");
+ meshlink_errno = MESHLINK_EINVAL;
+ return NULL;
+ }
+
+ if(strchr(appname, ' ')) {
+ logger(NULL, MESHLINK_ERROR, "Invalid appname given!\n");
+ meshlink_errno = MESHLINK_EINVAL;
+ return NULL;
+ }
+
+ if(devclass < 0 || devclass >= DEV_CLASS_COUNT) {
+ logger(NULL, MESHLINK_ERROR, "Invalid devclass given!\n");
+ meshlink_errno = MESHLINK_EINVAL;
+ return NULL;
+ }
+
/* Create a temporary struct on the stack, to avoid allocating and freeing one. */
meshlink_open_params_t params;
memset(¶ms, 0, sizeof(params));
}
meshlink_handle_t *meshlink_open_ex(const meshlink_open_params_t *params) {
- // Validate arguments provided by the application
- bool usingname = false;
-
logger(NULL, MESHLINK_DEBUG, "meshlink_open called\n");
+ // Validate arguments provided by the application
if(!params->appname || !*params->appname) {
logger(NULL, MESHLINK_ERROR, "No appname given!\n");
meshlink_errno = MESHLINK_EINVAL;
return NULL;
}
- if(!params->name || !*params->name) {
- logger(NULL, MESHLINK_ERROR, "No name given!\n");
- //return NULL;
- } else { //check name only if there is a name != NULL
-
- if(!check_id(params->name)) {
- logger(NULL, MESHLINK_ERROR, "Invalid name given!\n");
- meshlink_errno = MESHLINK_EINVAL;
- return NULL;
- } else {
- usingname = true;
- }
+ if(params->name && !check_id(params->name)) {
+ logger(NULL, MESHLINK_ERROR, "Invalid name given!\n");
+ meshlink_errno = MESHLINK_EINVAL;
+ return NULL;
}
if(params->devclass < 0 || params->devclass >= DEV_CLASS_COUNT) {
memcpy(mesh->dev_class_traits, default_class_traits, sizeof(default_class_traits));
- if(usingname) {
- mesh->name = xstrdup(params->name);
- }
+ mesh->name = params->name ? xstrdup(params->name) : NULL;
// Hash the key
if(params->key) {
// If no configuration exists yet, create it.
if(!meshlink_confbase_exists(mesh)) {
+ if(!mesh->name) {
+ logger(NULL, MESHLINK_ERROR, "No configuration files found!\n");
+ meshlink_close(mesh);
+ meshlink_errno = MESHLINK_ESTORAGE;
+ return NULL;
+ }
+
if(!meshlink_setup(mesh)) {
logger(NULL, MESHLINK_ERROR, "Cannot create initial configuration\n");
meshlink_close(mesh);
return false;
}
+#if defined(HAVE_RECVMMSG) || defined(HAVE_SENDMMSG)
+ init_mmsg(mesh);
+#endif
init_outgoings(mesh);
+ init_adns(mesh);
// Start the main thread
}
}
+ exit_adns(mesh);
exit_outgoings(mesh);
+#if defined(HAVE_RECVMMSG) || defined(HAVE_SENDMMSG)
+ exit_mmsg(mesh);
+#endif
// Ensure we are considered unreachable
if(mesh->nodes) {
}
if(!is_valid_hostname(address)) {
- logger(mesh, MESHLINK_DEBUG, "Invalid character in address: %s\n", address);
+ logger(mesh, MESHLINK_DEBUG, "Invalid character in address: %s", address);
+ meshlink_errno = MESHLINK_EINVAL;
+ return false;
+ }
+
+ if((node_t *)node != mesh->self && !port) {
+ logger(mesh, MESHLINK_DEBUG, "Missing port number!");
meshlink_errno = MESHLINK_EINVAL;
return false;
+
}
if(port && !is_valid_port(port)) {
- logger(mesh, MESHLINK_DEBUG, "Invalid character in port: %s\n", address);
+ logger(mesh, MESHLINK_DEBUG, "Invalid character in port: %s", address);
meshlink_errno = MESHLINK_EINVAL;
return false;
}
}
// Connect to the meshlink daemon mentioned in the URL.
- struct addrinfo *ai = str2addrinfo(address, port, SOCK_STREAM);
+ struct addrinfo *ai = adns_blocking_request(mesh, xstrdup(address), xstrdup(port), 5);
if(ai) {
for(struct addrinfo *aip = ai; aip; aip = aip->ai_next) {
packmsg_add_int32(&out, mesh->self->devclass);
packmsg_add_bool(&out, mesh->self->status.blacklisted);
packmsg_add_bin(&out, ecdsa_get_public_key(mesh->private_key), 32);
- packmsg_add_str(&out, mesh->self->canonical_address ? mesh->self->canonical_address : "");
+
+ if(mesh->self->canonical_address && !strchr(mesh->self->canonical_address, ' ')) {
+ char *canonical_address = NULL;
+ xasprintf(&canonical_address, "%s %s", mesh->self->canonical_address, mesh->myport);
+ packmsg_add_str(&out, canonical_address);
+ free(canonical_address);
+ } else {
+ packmsg_add_str(&out, mesh->self->canonical_address ? mesh->self->canonical_address : "");
+ }
uint32_t count = 0;
pthread_mutex_unlock(&mesh->mutex);
}
+void meshlink_set_scheduling_granularity(struct meshlink_handle *mesh, long granularity) {
+ if(!mesh || granularity < 0) {
+ meshlink_errno = EINVAL;
+ return;
+ }
+
+ utcp_set_clock_granularity(granularity);
+}
+
void handle_network_change(meshlink_handle_t *mesh, bool online) {
(void)online;
static void __attribute__((constructor)) meshlink_init(void) {
crypto_init();
+ utcp_set_clock_granularity(10000);
}
static void __attribute__((destructor)) meshlink_exit(void) {