// Find out what local address a socket would use if we connect to the given address.
// We do this using connect() on a UDP socket, so the kernel has to resolve the address
// of both endpoints, but this will actually not send any UDP packet.
-static bool getlocaladdr(char *destaddr, struct sockaddr *sn, socklen_t *sl, int netns) {
+static bool getlocaladdr(char *destaddr, sockaddr_t *sa, socklen_t *salen, int netns) {
struct addrinfo *rai = NULL;
const struct addrinfo hint = {
.ai_family = AF_UNSPEC,
freeaddrinfo(rai);
- if(getsockname(sock, sn, sl)) {
+ if(getsockname(sock, &sa->sa, salen)) {
closesocket(sock);
return false;
}
}
static bool getlocaladdrname(char *destaddr, char *host, socklen_t hostlen, int netns) {
- struct sockaddr_storage sn;
- socklen_t sl = sizeof(sn);
+ sockaddr_t sa;
+ socklen_t salen = sizeof(sa);
- if(!getlocaladdr(destaddr, (struct sockaddr *)&sn, &sl, netns)) {
+ if(!getlocaladdr(destaddr, &sa, &salen, netns)) {
return false;
}
- if(getnameinfo((struct sockaddr *)&sn, sl, host, hostlen, NULL, 0, NI_NUMERICHOST | NI_NUMERICSERV)) {
+ if(getnameinfo(&sa.sa, salen, host, hostlen, NULL, 0, NI_NUMERICHOST | NI_NUMERICSERV)) {
return false;
}
remove_duplicate_hostnames(hostname, port, 4);
- if(!(flags & MESHLINK_INVITE_NUMERIC)) {
- for(int i = 0; i < 4; i++) {
- if(!hostname[i]) {
- continue;
- }
+ // Resolve the hostnames
+ for(int i = 0; i < 4; i++) {
+ if(!hostname[i]) {
+ continue;
+ }
- // 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);
+ // 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) {
- continue;
- }
+ if(err || !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);
+ // Remember the address
+ node_add_recent_address(mesh, mesh->self, (sockaddr_t *)ai_in->ai_addr);
- if(err || !is_valid_hostname(resolved_host)) {
- freeaddrinfo(ai_in);
- continue;
- }
+ if(flags & MESHLINK_INVITE_NUMERIC) {
+ // We don't need to do any further conversion
+ 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);
+ // 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 || !ai_out) {
- freeaddrinfo(ai_in);
- continue;
- }
+ if(err || !is_valid_hostname(resolved_host)) {
+ 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;
- }
+ // Convert the hostname back to a sockaddr
+ hint.ai_family = ai_in->ai_family;
+ err = getaddrinfo(resolved_host, resolved_port, &hint, &ai_out);
- // Yes: replace the hostname with the resolved one
- free(hostname[i]);
- hostname[i] = xstrdup(resolved_host);
+ 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);
}
// Remove duplicates again, since IPv4 and IPv6 addresses might map to the same hostname
continue;
}
- // Ensure we have the same addresses in our own host config file.
- char *tmphostport;
- xasprintf(&tmphostport, "%s %s", hostname[i], port[i]);
- /// TODO: FIX
- //config_add_string(&mesh->config, "Address", tmphostport);
- free(tmphostport);
-
// Append the address to the hostport string
char *newhostport;
xasprintf(&newhostport, (strchr(hostname[i], ':') ? "%s%s[%s]:%s" : "%s%s%s:%s"), hostport ? hostport : "", hostport ? "," : "", hostname[i], port[i]);
}
// Write host config files
- while(count--) {
+ for(uint32_t i = 0; i < count; i++) {
const void *data;
uint32_t len = packmsg_get_bin_raw(&in, &data);
return false;
}
- node_add(mesh, n);
+ if(i == 0) {
+ /* The first host config file is of the inviter itself;
+ * remember the address we are currently using for the invitation connection.
+ */
+ sockaddr_t sa;
+ socklen_t salen = sizeof(sa);
- if(!config_write(mesh, "current", n->name, &config, mesh->config_key)) {
+ if(getpeername(mesh->sock, &sa.sa, &salen) == 0) {
+ node_add_recent_address(mesh, n, &sa);
+ }
+ }
+
+ if(!node_write_config(mesh, n)) {
+ free_node(n);
return false;
}
+
+ node_add(mesh, n);
}
/* Ensure the configuration directory metadata is on disk */
// Get our local address(es) by simulating connecting to an Internet host.
static void add_local_addresses(meshlink_handle_t *mesh) {
- struct sockaddr_storage sn;
- sn.ss_family = AF_UNKNOWN;
- socklen_t sl = sizeof(sn);
+ sockaddr_t sa;
+ sa.storage.ss_family = AF_UNKNOWN;
+ socklen_t salen = sizeof(sa);
// IPv4 example.org
- if(getlocaladdr("93.184.216.34", (struct sockaddr *)&sn, &sl, mesh->netns)) {
- ((struct sockaddr_in *)&sn)->sin_port = ntohs(atoi(mesh->myport));
- meshlink_hint_address(mesh, (meshlink_node_t *)mesh->self, (struct sockaddr *)&sn);
+ if(getlocaladdr("93.184.216.34", &sa, &salen, mesh->netns)) {
+ sa.in.sin_port = ntohs(atoi(mesh->myport));
+ node_add_recent_address(mesh, mesh->self, &sa);
}
// IPv6 example.org
- sl = sizeof(sn);
+ salen = sizeof(sa);
- if(getlocaladdr("2606:2800:220:1:248:1893:25c8:1946", (struct sockaddr *)&sn, &sl, mesh->netns)) {
- ((struct sockaddr_in6 *)&sn)->sin6_port = ntohs(atoi(mesh->myport));
- meshlink_hint_address(mesh, (meshlink_node_t *)mesh->self, (struct sockaddr *)&sn);
+ if(getlocaladdr("2606:2800:220:1:248:1893:25c8:1946", &sa, &salen, mesh->netns)) {
+ sa.in6.sin6_port = ntohs(atoi(mesh->myport));
+ node_add_recent_address(mesh, mesh->self, &sa);
}
}
// Send ourselves a UDP packet to kick the event loop
for(int i = 0; i < mesh->listen_sockets; i++) {
sockaddr_t sa;
- socklen_t salen = sizeof(sa.sa);
+ socklen_t salen = sizeof(sa);
if(getsockname(mesh->listen_socket[i].udp.fd, &sa.sa, &salen) == -1) {
logger(mesh, MESHLINK_ERROR, "System call `%s' failed: %s", "getsockname", sockstrerror(sockerrno));
// Check validity of the new node's name
if(!check_id(name)) {
- logger(mesh, MESHLINK_DEBUG, "Invalid name for node.\n");
+ logger(mesh, MESHLINK_ERROR, "Invalid name for node.\n");
meshlink_errno = MESHLINK_EINVAL;
pthread_mutex_unlock(&mesh->mutex);
return NULL;
// Ensure no host configuration file with that name exists
if(config_exists(mesh, "current", name)) {
- logger(mesh, MESHLINK_DEBUG, "A host config file for %s already exists!\n", name);
+ logger(mesh, MESHLINK_ERROR, "A host config file for %s already exists!\n", name);
meshlink_errno = MESHLINK_EEXIST;
pthread_mutex_unlock(&mesh->mutex);
return NULL;
// Ensure no other nodes know about this name
if(meshlink_get_node(mesh, name)) {
- logger(mesh, MESHLINK_DEBUG, "A node with name %s is already known!\n", name);
+ logger(mesh, MESHLINK_ERROR, "A node with name %s is already known!\n", name);
meshlink_errno = MESHLINK_EEXIST;
pthread_mutex_unlock(&mesh->mutex);
return NULL;
char *address = get_my_hostname(mesh, flags);
if(!address) {
- logger(mesh, MESHLINK_DEBUG, "No Address known for ourselves!\n");
+ logger(mesh, MESHLINK_ERROR, "No Address known for ourselves!\n");
meshlink_errno = MESHLINK_ERESOLV;
pthread_mutex_unlock(&mesh->mutex);
return NULL;
return NULL;
}
+ // If we changed our own host config file, write it out now
+ if(mesh->self->status.dirty) {
+ if(!node_write_config(mesh, mesh->self)) {
+ logger(mesh, MESHLINK_ERROR, "Could not write our own host conifg file!\n");
+ pthread_mutex_unlock(&mesh->mutex);
+ return NULL;
+ }
+ }
+
char hash[64];
// Create a hash of the key.
pthread_mutex_lock(&mesh->mutex);
node_t *n = (node_t *)node;
- memmove(n->recent + 1, n->recent, (MAX_RECENT - 1) * sizeof(*n->recent));
- memcpy(n->recent, addr, SALEN(*addr));
- if(!node_write_config(mesh, n)) {
- logger(mesh, MESHLINK_DEBUG, "Could not update %s\n", n->name);
+ if(node_add_recent_address(mesh, n, (sockaddr_t *)addr)) {
+ if(!node_write_config(mesh, n)) {
+ logger(mesh, MESHLINK_DEBUG, "Could not update %s\n", n->name);
+ }
}
pthread_mutex_unlock(&mesh->mutex);
pthread_mutex_unlock(&mesh->mutex);
}
+void meshlink_set_dev_class_fast_retry_period(meshlink_handle_t *mesh, dev_class_t devclass, int fast_retry_period) {
+ if(!mesh || devclass < 0 || devclass >= DEV_CLASS_COUNT) {
+ meshlink_errno = EINVAL;
+ return;
+ }
+
+ if(fast_retry_period < 0) {
+ meshlink_errno = EINVAL;
+ return;
+ }
+
+ pthread_mutex_lock(&mesh->mutex);
+ mesh->dev_class_traits[devclass].fast_retry_period = fast_retry_period;
+ pthread_mutex_unlock(&mesh->mutex);
+}
+
void handle_network_change(meshlink_handle_t *mesh, bool online) {
(void)online;