--indent=tab=8
--convert-tabs
--xj
+-j
+-f
-A2
-U
-p
-xg
-k3
+-w
ChangeLog:
git log > ChangeLog
+
+astyle:
+ astyle --options=.astylerc -nQ src/*.[ch] src/ed25519/e*.[ch]
char *buffer_readline(buffer_t *buffer) {
char *newline = memchr(buffer->data + buffer->offset, '\n', buffer->len - buffer->offset);
- if(!newline)
+ if(!newline) {
return NULL;
+ }
size_t len = newline + 1 - (buffer->data + buffer->offset);
*newline = 0;
// Check if we have enough bytes in the buffer, and if so, return a pointer to the start of them.
char *buffer_read(buffer_t *buffer, size_t size) {
- if(buffer->len - buffer->offset < size)
+ if(buffer->len - buffer->offset < size) {
return NULL;
+ }
return buffer_consume(buffer, size);
}
result = strcasecmp(a->variable, b->variable);
- if(result)
+ if(result) {
return result;
+ }
result = a->line - b->line;
- if(result)
+ if(result) {
return result;
- else
+ } else {
return a->file ? strcmp(a->file, b->file) : 0;
+ }
}
void init_configuration(splay_tree_t **config_tree) {
}
void exit_configuration(splay_tree_t **config_tree) {
- if(*config_tree)
+ if(*config_tree) {
splay_delete_tree(*config_tree);
+ }
+
*config_tree = NULL;
}
}
void free_config(config_t *cfg) {
- if(cfg->variable)
+ if(cfg->variable) {
free(cfg->variable);
+ }
- if(cfg->value)
+ if(cfg->value) {
free(cfg->value);
+ }
- if(cfg->file)
+ if(cfg->file) {
free(cfg->file);
+ }
free(cfg);
}
found = splay_search_closest_greater(config_tree, &cfg);
- if(!found)
+ if(!found) {
return NULL;
+ }
- if(strcasecmp(found->variable, variable))
+ if(strcasecmp(found->variable, variable)) {
return NULL;
+ }
return found;
}
if(node->next) {
found = node->next->data;
- if(!strcasecmp(found->variable, cfg->variable))
+ if(!strcasecmp(found->variable, cfg->variable)) {
return found;
+ }
}
}
}
bool get_config_bool(const config_t *cfg, bool *result) {
- if(!cfg)
+ if(!cfg) {
return false;
+ }
if(!strcasecmp(cfg->value, "yes")) {
*result = true;
}
bool get_config_int(const config_t *cfg, int *result) {
- if(!cfg)
+ if(!cfg) {
return false;
+ }
- if(sscanf(cfg->value, "%d", result) == 1)
+ if(sscanf(cfg->value, "%d", result) == 1) {
return true;
+ }
logger(NULL, MESHLINK_ERROR, "Integer expected for configuration variable %s in %s line %d",
cfg->variable, cfg->file, cfg->line);
}
bool set_config_int(config_t *cfg, int val) {
- if(!cfg)
+ if(!cfg) {
return false;
+ }
char val_str[1024];
snprintf(val_str, sizeof(val_str), "%d", val);
- if(cfg->value)
+ if(cfg->value) {
free(cfg->value);
+ }
cfg->value = xstrdup(val_str);
}
bool get_config_string(const config_t *cfg, char **result) {
- if(!cfg)
+ if(!cfg) {
return false;
+ }
*result = xstrdup(cfg->value);
}
bool set_config_string(config_t *cfg, const char *val) {
- if(!cfg)
+ if(!cfg) {
return false;
+ }
- if(cfg->value)
+ if(cfg->value) {
free(cfg->value);
+ }
cfg->value = xstrdup(val);
bool get_config_address(const config_t *cfg, struct addrinfo **result) {
struct addrinfo *ai;
- if(!cfg)
+ if(!cfg) {
return false;
+ }
ai = str2addrinfo(cfg->value, NULL, 0);
char *newline = NULL;
char *p;
- if(feof(fp))
+ if(feof(fp)) {
return NULL;
+ }
p = fgets(buf, buflen, fp);
- if(!p)
+ if(!p) {
return NULL;
+ }
newline = strchr(p, '\n');
- if(!newline)
+ if(!newline) {
return buf;
+ }
/* kill newline and carriage return if necessary */
*newline = '\0';
- if(newline > p && newline[-1] == '\r')
+
+ if(newline > p && newline[-1] == '\r') {
newline[-1] = '\0';
+ }
return buf;
}
variable = value = line;
eol = line + strlen(line);
- while(strchr("\t ", *--eol))
+
+ while(strchr("\t ", *--eol)) {
*eol = '\0';
+ }
len = strcspn(value, "\t =");
value += len;
value += strspn(value, "\t ");
+
if(*value == '=') {
value++;
value += strspn(value, "\t ");
}
+
variable[len] = '\0';
if(!*value) {
line = readline(fp, buffer, sizeof(buffer));
if(!line) {
- if(feof(fp))
+ if(feof(fp)) {
result = true;
+ }
+
break;
}
lineno++;
- if(!*line || *line == '#')
+ if(!*line || *line == '#') {
continue;
+ }
if(ignore) {
- if(!strncmp(line, "-----END", 8))
+ if(!strncmp(line, "-----END", 8)) {
ignore = false;
+ }
+
continue;
}
}
cfg = parse_config_line(line, fname, lineno);
- if(!cfg)
+
+ if(!cfg) {
break;
+ }
+
config_add(config_tree, cfg);
}
}
for splay_each(config_t, cnf, config_tree) {
- if(fwrite(cnf->variable, sizeof(char), strlen(cnf->variable), fp) < strlen(cnf->variable))
+ if(fwrite(cnf->variable, sizeof(char), strlen(cnf->variable), fp) < strlen(cnf->variable)) {
goto error;
+ }
- if(fwrite(" = ", sizeof(char), 3, fp) < 3)
+ if(fwrite(" = ", sizeof(char), 3, fp) < 3) {
goto error;
+ }
- if(fwrite(cnf->value, sizeof(char), strlen(cnf->value), fp) < strlen(cnf->value))
+ if(fwrite(cnf->value, sizeof(char), strlen(cnf->value), fp) < strlen(cnf->value)) {
goto error;
+ }
- if(fwrite("\n", sizeof(char), 1, fp) < 1)
+ if(fwrite("\n", sizeof(char), 1, fp) < 1) {
goto error;
+ }
}
fclose(fp);
errno = 0;
x = read_config_file(mesh->config, filename);
- if(!x && errno)
+ if(!x && errno) {
logger(mesh, MESHLINK_ERROR, "Failed to read `%s': %s", filename, strerror(errno));
+ }
return x;
}
}
while(readline(fr, buf, sizeof(buf))) {
- if(!*buf || *buf == '#')
+ if(!*buf || *buf == '#') {
goto copy;
+ }
sep = strchr(buf, ' ');
- if(!sep)
+
+ if(!sep) {
goto copy;
+ }
*sep = 0;
+
if(strcmp(buf, key)) {
*sep = ' ';
goto copy;
}
// We found the key and the value. We already added it at the top, so ignore this one.
- if(value && sep[1] == '=' && sep[2] == ' ' && !strcmp(sep + 3, value))
+ if(value && sep[1] == '=' && sep[2] == ' ' && !strcmp(sep + 3, value)) {
continue;
+ }
// We found the key but with a different value, delete it if wanted.
found++;
- if((!value || trim) && found > trim)
+
+ if((!value || trim) && found > trim) {
continue;
+ }
*sep = ' ';
fprintf(fw, "%s\n", buf);
}
- if(ferror(fr))
+ if(ferror(fr)) {
error = true;
+ }
fclose(fr);
- if(ferror(fw))
+ if(ferror(fw)) {
error = true;
+ }
- if(fclose(fw))
+ if(fclose(fw)) {
error = true;
+ }
// If any error occured during reading or writing, exit.
if(error) {
#ifdef HAVE_MINGW
char bakname[PATH_MAX];
snprintf(bakname, sizeof(bakname), "%s.bak", filename);
+
if(rename(filename, bakname) || rename(tmpname, filename)) {
rename(bakname, filename);
#else
+
if(rename(tmpname, filename)) {
#endif
return false;
}
void exit_connections(meshlink_handle_t *mesh) {
- if(mesh->connections)
+ if(mesh->connections) {
list_delete_list(mesh->connections);
+ }
free_connection(mesh->everyone);
}
void free_connection(connection_t *c) {
- if(!c)
+ if(!c) {
return;
+ }
sptps_stop(&c->sptps);
ecdsa_free(c->ecdsa);
buffer_clear(&c->inbuf);
buffer_clear(&c->outbuf);
- if(c->io.cb)
+ if(c->io.cb) {
abort();
+ }
- if(c->socket > 0)
+ if(c->socket > 0) {
closesocket(c->socket);
+ }
free(c->name);
- if(c->config_tree)
+ if(c->config_tree) {
exit_configuration(&c->config_tree);
+ }
free(c);
}
void crypto_init(void) {
random_fd = open("/dev/urandom", O_RDONLY);
- if(random_fd < 0)
+
+ if(random_fd < 0) {
random_fd = open("/dev/random", O_RDONLY);
+ }
+
if(random_fd < 0) {
fprintf(stderr, "Could not open source of random numbers: %s\n", strerror(errno));
abort();
void randomize(void *out, size_t outlen) {
while(outlen) {
size_t len = read(random_fd, out, outlen);
+
if(len <= 0) {
- if(errno == EAGAIN || errno == EINTR)
+ if(errno == EAGAIN || errno == EINTR) {
continue;
+ }
+
fprintf(stderr, "Could not read random numbers: %s\n", strerror(errno));
abort();
}
+
out += len;
outlen -= len;
}
result_size = mesh->edges->count / 2;
// if result is smaller than edges, we have to dealloc all the excess devtool_edge_t
- if((size_t)result_size > *nmemb)
+ if((size_t)result_size > *nmemb) {
result = realloc(edges, result_size * sizeof(*result));
- else
+ } else {
result = edges;
+ }
if(result) {
devtool_edge_t *p = result;
for splay_each(edge_t, e, mesh->edges) {
// skip edges that do not represent a two-directional connection
- if((!e->reverse) || (e->reverse->to != e->from))
+ if((!e->reverse) || (e->reverse->to != e->from)) {
continue;
+ }
// don't count edges twice
- if(e->to < e->from)
+ if(e->to < e->from) {
continue;
+ }
assert(n < result_size);
static bool fstrwrite(const char *str, FILE *stream) {
size_t len = strlen(str);
- if(fwrite((void *)str, 1, len, stream) != len)
+ if(fwrite((void *)str, 1, len, stream) != len) {
return false;
+ }
return true;
}
static const char *__itoa(int value) {
static char buffer[sizeof(int) * 8 + 1]; // not thread safe
- if(snprintf(buffer, sizeof(buffer), "%d", value) == -1)
+ if(snprintf(buffer, sizeof(buffer), "%d", value) == -1) {
return "";
+ }
return buffer;
}
meshlink_node_t **nodes = meshlink_get_all_nodes(mesh, NULL, &node_count);
devtool_edge_t *edges = devtool_get_all_edges(mesh, NULL, &edge_count);
- if((!nodes && node_count != 0) || (!edges && edge_count != 0))
+ if((!nodes && node_count != 0) || (!edges && edge_count != 0)) {
goto fail;
+ }
// export begin
- if(!fstrwrite("{\n", stream))
+ if(!fstrwrite("{\n", stream)) {
goto fail;
+ }
// export nodes
- if(!fstrwrite("\t\"nodes\": {\n", stream))
+ if(!fstrwrite("\t\"nodes\": {\n", stream)) {
goto fail;
+ }
for(size_t i = 0; i < node_count; ++i) {
- if(!fstrwrite("\t\t\"", stream) || !fstrwrite(((node_t *)nodes[i])->name, stream) || !fstrwrite("\": {\n", stream))
+ if(!fstrwrite("\t\t\"", stream) || !fstrwrite(((node_t *)nodes[i])->name, stream) || !fstrwrite("\": {\n", stream)) {
goto fail;
+ }
- if(!fstrwrite("\t\t\t\"name\": \"", stream) || !fstrwrite(((node_t *)nodes[i])->name, stream) || !fstrwrite("\",\n", stream))
+ if(!fstrwrite("\t\t\t\"name\": \"", stream) || !fstrwrite(((node_t *)nodes[i])->name, stream) || !fstrwrite("\",\n", stream)) {
goto fail;
+ }
- if(!fstrwrite("\t\t\t\"options\": ", stream) || !fstrwrite(__itoa(((node_t *)nodes[i])->options), stream) || !fstrwrite(",\n", stream))
+ if(!fstrwrite("\t\t\t\"options\": ", stream) || !fstrwrite(__itoa(((node_t *)nodes[i])->options), stream) || !fstrwrite(",\n", stream)) {
goto fail;
+ }
- if(!fstrwrite("\t\t\t\"devclass\": ", stream) || !fstrwrite(__itoa(((node_t *)nodes[i])->devclass), stream) || !fstrwrite("\n", stream))
+ if(!fstrwrite("\t\t\t\"devclass\": ", stream) || !fstrwrite(__itoa(((node_t *)nodes[i])->devclass), stream) || !fstrwrite("\n", stream)) {
goto fail;
+ }
- if(!fstrwrite((i + 1) != node_count ? "\t\t},\n" : "\t\t}\n", stream))
+ if(!fstrwrite((i + 1) != node_count ? "\t\t},\n" : "\t\t}\n", stream)) {
goto fail;
+ }
}
- if(!fstrwrite("\t},\n", stream))
+ if(!fstrwrite("\t},\n", stream)) {
goto fail;
+ }
// export edges
- if(!fstrwrite("\t\"edges\": {\n", stream))
+ if(!fstrwrite("\t\"edges\": {\n", stream)) {
goto fail;
+ }
for(size_t i = 0; i < edge_count; ++i) {
- if(!fstrwrite("\t\t\"", stream) || !fstrwrite(edges[i].from->name, stream) || !fstrwrite("_to_", stream) || !fstrwrite(edges[i].to->name, stream) || !fstrwrite("\": {\n", stream))
+ if(!fstrwrite("\t\t\"", stream) || !fstrwrite(edges[i].from->name, stream) || !fstrwrite("_to_", stream) || !fstrwrite(edges[i].to->name, stream) || !fstrwrite("\": {\n", stream)) {
goto fail;
+ }
- if(!fstrwrite("\t\t\t\"from\": \"", stream) || !fstrwrite(edges[i].from->name, stream) || !fstrwrite("\",\n", stream))
+ if(!fstrwrite("\t\t\t\"from\": \"", stream) || !fstrwrite(edges[i].from->name, stream) || !fstrwrite("\",\n", stream)) {
goto fail;
+ }
- if(!fstrwrite("\t\t\t\"to\": \"", stream) || !fstrwrite(edges[i].to->name, stream) || !fstrwrite("\",\n", stream))
+ if(!fstrwrite("\t\t\t\"to\": \"", stream) || !fstrwrite(edges[i].to->name, stream) || !fstrwrite("\",\n", stream)) {
goto fail;
+ }
char *host = NULL, *port = NULL, *address = NULL;
sockaddr2str((const sockaddr_t *) & (edges[i].address), &host, &port);
- if(host && port)
+ if(host && port) {
xasprintf(&address, "{ \"host\": \"%s\", \"port\": %s }", host, port);
+ }
free(host);
free(port);
free(address);
- if(!fstrwrite("\t\t\t\"options\": ", stream) || !fstrwrite(__itoa(edges[i].options), stream) || !fstrwrite(",\n", stream))
+ if(!fstrwrite("\t\t\t\"options\": ", stream) || !fstrwrite(__itoa(edges[i].options), stream) || !fstrwrite(",\n", stream)) {
goto fail;
+ }
- if(!fstrwrite("\t\t\t\"weight\": ", stream) || !fstrwrite(__itoa(edges[i].weight), stream) || !fstrwrite("\n", stream))
+ if(!fstrwrite("\t\t\t\"weight\": ", stream) || !fstrwrite(__itoa(edges[i].weight), stream) || !fstrwrite("\n", stream)) {
goto fail;
+ }
- if(!fstrwrite((i + 1) != edge_count ? "\t\t},\n" : "\t\t}\n", stream))
+ if(!fstrwrite((i + 1) != edge_count ? "\t\t},\n" : "\t\t}\n", stream)) {
goto fail;
+ }
}
- if(!fstrwrite("\t}\n", stream))
+ if(!fstrwrite("\t}\n", stream)) {
goto fail;
+ }
// DONE!
- if(!fstrwrite("}", stream))
+ if(!fstrwrite("}", stream)) {
goto fail;
+ }
goto done;
#define MESHLINK_MDNS_FINGERPRINT_KEY "fingerprint"
static void generate_rand_string(char *buffer, size_t size) {
- for(size_t i = 0; i < (size - 1); ++i)
+ for(size_t i = 0; i < (size - 1); ++i) {
buffer[i] = 'a' + (rand() % ('z' - 'a' + 1));
+ }
buffer[size - 1] = '\0';
}
/* Add the service */
int ret = 0;
+
if((ret = catta_server_add_service(mesh->catta_server, mesh->catta_group, CATTA_IF_UNSPEC, CATTA_PROTO_UNSPEC, 0, meshlink_get_fingerprint(mesh, (meshlink_node_t *)mesh->self), mesh->catta_servicetype, NULL, NULL, atoi(mesh->myport), txt_name, txt_fingerprint, NULL)) < 0) {
logger(mesh, MESHLINK_ERROR, "Failed to add service: %s\n", catta_strerror(ret));
goto fail;
catta_simple_poll_quit(mesh->catta_poll);
done:
- if(txt_name)
+
+ if(txt_name) {
free(txt_name);
+ }
pthread_mutex_unlock(&(mesh->mesh_mutex));
}
case CATTA_SERVER_RUNNING: {
/* The serve has startup successfully and registered its host
* name on the network, so it's time to create our services */
- if(!mesh->catta_group)
+ if(!mesh->catta_group) {
discovery_create_services(mesh);
+ }
}
break;
break;
}
- if(naddress.unknown.family != AF_UNKNOWN)
+ if(naddress.unknown.family != AF_UNKNOWN) {
meshlink_hint_address(mesh, (meshlink_node_t *)node, (struct sockaddr *)&naddress);
- else
+ } else {
logger(mesh, MESHLINK_WARNING, "Could not resolve node %s to a known address family type.\n", node->name);
- } else
+ }
+ } else {
logger(mesh, MESHLINK_WARNING, "Node %s is not part of the mesh network.\n", node_name);
- } else
+ }
+ } else {
logger(mesh, MESHLINK_WARNING, "TXT records invalid.\n");
- } else
+ }
+ } else {
logger(mesh, MESHLINK_WARNING, "TXT records missing.\n");
+ }
}
break;
}
assert(domain != NULL);
logger(mesh, MESHLINK_DEBUG, "(Browser) NEW: service '%s' of type '%s' in domain '%s'\n", name, type, domain);
+
/* We ignore the returned resolver object. In the callback
function we free it. Ifthe server is terminated before
the callback function is called the server will free
the resolver for us. */
- if(!(catta_s_service_resolver_new(mesh->catta_server, interface_, protocol, name, type, domain, CATTA_PROTO_UNSPEC, 0, discovery_resolve_callback, mesh)))
+ if(!(catta_s_service_resolver_new(mesh->catta_server, interface_, protocol, name, type, domain, CATTA_PROTO_UNSPEC, 0, discovery_resolve_callback, mesh))) {
logger(mesh, MESHLINK_DEBUG, "Failed to resolve service '%s': %s\n", name, catta_strerror(catta_server_errno(mesh->catta_server)));
+ }
}
break;
return true;
fail:
+
if(mesh->catta_browser != NULL) {
catta_s_service_browser_free(mesh->catta_browser);
mesh->catta_browser = NULL;
assert(mesh != NULL);
// Shut down
- if(mesh->catta_poll)
+ if(mesh->catta_poll) {
catta_simple_poll_quit(mesh->catta_poll);
+ }
// Wait for the discovery thread to finish
if(mesh->discovery_threadstarted == true) {
status = vsnprintf(*buf, len, fmt, aq);
va_end(aq);
- if(status >= 0)
+ if(status >= 0) {
*buf = xrealloc(*buf, status + 1);
+ }
if(status > len - 1) {
len = status;
#endif
#ifndef timeradd
-#define timeradd(a, b, r) do {\
- (r)->tv_sec = (a)->tv_sec + (b)->tv_sec;\
- (r)->tv_usec = (a)->tv_usec + (b)->tv_usec;\
- if((r)->tv_usec >= 1000000)\
- (r)->tv_sec++, (r)->tv_usec -= 1000000;\
-} while (0)
+#define timeradd(a, b, r)\
+ do {\
+ (r)->tv_sec = (a)->tv_sec + (b)->tv_sec;\
+ (r)->tv_usec = (a)->tv_usec + (b)->tv_usec;\
+ if((r)->tv_usec >= 1000000)\
+ (r)->tv_sec++, (r)->tv_usec -= 1000000;\
+ } while (0)
#endif
#ifndef timersub
-#define timersub(a, b, r) do {\
- (r)->tv_sec = (a)->tv_sec - (b)->tv_sec;\
- (r)->tv_usec = (a)->tv_usec - (b)->tv_usec;\
- if((r)->tv_usec < 0)\
- (r)->tv_sec--, (r)->tv_usec += 1000000;\
-} while (0)
+#define timersub(a, b, r)\
+ do {\
+ (r)->tv_sec = (a)->tv_sec - (b)->tv_sec;\
+ (r)->tv_usec = (a)->tv_usec - (b)->tv_usec;\
+ if((r)->tv_usec < 0)\
+ (r)->tv_sec--, (r)->tv_usec += 1000000;\
+ } while (0)
#endif
#ifdef HAVE_MINGW
#include "../xalloc.h"
ecdh_t *ecdh_generate_public(void *pubkey) {
- ecdh_t *ecdh = xzalloc(sizeof *ecdh);
+ ecdh_t *ecdh = xzalloc(sizeof * ecdh);
uint8_t seed[32];
randomize(seed, sizeof seed);
return 0;
}
- ecdsa_t *ecdsa = xzalloc(sizeof *ecdsa);
+ ecdsa_t *ecdsa = xzalloc(sizeof * ecdsa);
len = b64decode(p, ecdsa->public, len);
+
if(len != 32) {
logger(NULL, MESHLINK_ERROR, "Invalid format of public key! len = %d", len);
free(ecdsa);
// Read PEM ECDSA keys
ecdsa_t *ecdsa_read_pem_public_key(FILE *fp) {
- ecdsa_t *ecdsa = xzalloc(sizeof *ecdsa);
- if(fread(ecdsa->public, sizeof ecdsa->public, 1, fp) == 1)
+ ecdsa_t *ecdsa = xzalloc(sizeof * ecdsa);
+
+ if(fread(ecdsa->public, sizeof ecdsa->public, 1, fp) == 1) {
return ecdsa;
+ }
+
free(ecdsa);
return 0;
}
ecdsa_t *ecdsa_read_pem_private_key(FILE *fp) {
- ecdsa_t *ecdsa = xmalloc(sizeof *ecdsa);
- if(fread(ecdsa, sizeof *ecdsa, 1, fp) == 1)
+ ecdsa_t *ecdsa = xmalloc(sizeof * ecdsa);
+
+ if(fread(ecdsa, sizeof * ecdsa, 1, fp) == 1) {
return ecdsa;
+ }
+
free(ecdsa);
return 0;
}
// Generate ECDSA key
ecdsa_t *ecdsa_generate(void) {
- ecdsa_t *ecdsa = xzalloc(sizeof *ecdsa);
+ ecdsa_t *ecdsa = xzalloc(sizeof * ecdsa);
uint8_t seed[32];
randomize(seed, sizeof seed);
}
bool ecdsa_write_pem_private_key(ecdsa_t *ecdsa, FILE *fp) {
- return fwrite(ecdsa, sizeof *ecdsa, 1, fp) == 1;
+ return fwrite(ecdsa, sizeof * ecdsa, 1, fp) == 1;
}
#include <stddef.h>
#if defined(_WIN32)
- #if defined(ED25519_BUILD_DLL)
- #define ED25519_DECLSPEC __declspec(dllexport)
- #elif defined(ED25519_DLL)
- #define ED25519_DECLSPEC __declspec(dllimport)
- #else
- #define ED25519_DECLSPEC
- #endif
+#if defined(ED25519_BUILD_DLL)
+#define ED25519_DECLSPEC __declspec(dllexport)
+#elif defined(ED25519_DLL)
+#define ED25519_DECLSPEC __declspec(dllimport)
#else
- #define ED25519_DECLSPEC
+#define ED25519_DECLSPEC
+#endif
+#else
+#define ED25519_DECLSPEC
#endif
result = a->weight - b->weight;
- if(result)
+ if(result) {
return result;
+ }
result = strcmp(a->from->name, b->from->name);
- if(result)
+ if(result) {
return result;
+ }
return strcmp(a->to->name, b->to->name);
}
}
void exit_edges(meshlink_handle_t *mesh) {
- if(mesh->edges)
+ if(mesh->edges) {
splay_delete_tree(mesh->edges);
+ }
+
mesh->edges = NULL;
}
e->reverse = lookup_edge(e->to, e->from);
- if(e->reverse)
+ if(e->reverse) {
e->reverse->reverse = e;
+ }
}
void edge_del(meshlink_handle_t *mesh, edge_t *e) {
- if(e->reverse)
+ if(e->reverse) {
e->reverse->reverse = NULL;
+ }
splay_delete(mesh->edges, e);
splay_delete(e->from->edge_tree, e);
static int timeout_compare(const timeout_t *a, const timeout_t *b) {
struct timeval diff;
timersub(&a->tv, &b->tv, &diff);
- if(diff.tv_sec < 0)
+
+ if(diff.tv_sec < 0) {
return -1;
- if(diff.tv_sec > 0)
+ }
+
+ if(diff.tv_sec > 0) {
return 1;
- if(diff.tv_usec < 0)
+ }
+
+ if(diff.tv_usec < 0) {
return -1;
- if(diff.tv_usec > 0)
+ }
+
+ if(diff.tv_usec > 0) {
return 1;
- if(a < b)
+ }
+
+ if(a < b) {
return -1;
- if(a > b)
+ }
+
+ if(a > b) {
return 1;
+ }
+
return 0;
}
void io_add(event_loop_t *loop, io_t *io, io_cb_t cb, void *data, int fd, int flags) {
- if(io->cb)
+ if(io->cb) {
return;
+ }
io->fd = fd;
io->cb = cb;
io_set(loop, io, flags);
- if(!splay_insert_node(&loop->ios, &io->node))
+ if(!splay_insert_node(&loop->ios, &io->node)) {
abort();
+ }
}
void io_set(event_loop_t *loop, io_t *io, int flags) {
io->flags = flags;
- if(flags & IO_READ)
+ if(flags & IO_READ) {
FD_SET(io->fd, &loop->readfds);
- else
+ } else {
FD_CLR(io->fd, &loop->readfds);
+ }
- if(flags & IO_WRITE)
+ if(flags & IO_WRITE) {
FD_SET(io->fd, &loop->writefds);
- else
+ } else {
FD_CLR(io->fd, &loop->writefds);
+ }
}
void io_del(event_loop_t *loop, io_t *io) {
- if(!io->cb)
+ if(!io->cb) {
return;
+ }
loop->deletion = true;
};
timeout->cb = cb;
+
timeout->data = data;
+
timeout->node.data = timeout;
timeout_set(loop, timeout, tv);
}
void timeout_set(event_loop_t *loop, timeout_t *timeout, struct timeval *tv) {
- if(timerisset(&timeout->tv))
+ if(timerisset(&timeout->tv)) {
splay_unlink_node(&loop->timeouts, &timeout->node);
+ }
- if(!loop->now.tv_sec)
+ if(!loop->now.tv_sec) {
gettimeofday(&loop->now, NULL);
+ }
timeradd(&loop->now, tv, &timeout->tv);
- if(!splay_insert_node(&loop->timeouts, &timeout->node))
+ if(!splay_insert_node(&loop->timeouts, &timeout->node)) {
abort();
+ }
}
void timeout_del(event_loop_t *loop, timeout_t *timeout) {
- if(!timeout->cb)
+ if(!timeout->cb) {
return;
+ }
loop->deletion = true;
(void)data;
(void)flags;
unsigned char signum;
- if(read(loop->pipefd[0], &signum, 1) != 1)
+
+ if(read(loop->pipefd[0], &signum, 1) != 1) {
return;
+ }
signal_t *sig = splay_search(&loop->signals, &((signal_t) {
.signum = signum
}));
- if(sig)
+
+ if(sig) {
sig->cb(loop, sig->data);
+ }
}
static void pipe_init(event_loop_t *loop) {
- if(!pipe(loop->pipefd))
+ if(!pipe(loop->pipefd)) {
io_add(loop, &loop->signalio, signalio_handler, NULL, loop->pipefd[0], IO_READ);
+ }
}
void signal_trigger(event_loop_t *loop, signal_t *sig) {
}
void signal_add(event_loop_t *loop, signal_t *sig, signal_cb_t cb, void *data, uint8_t signum) {
- if(sig->cb)
+ if(sig->cb) {
return;
+ }
sig->cb = cb;
sig->data = data;
sig->signum = signum;
sig->node.data = sig;
- if(loop->pipefd[0] == -1)
+ if(loop->pipefd[0] == -1) {
pipe_init(loop);
+ }
- if(!splay_insert_node(&loop->signals, &sig->node))
+ if(!splay_insert_node(&loop->signals, &sig->node)) {
abort();
+ }
}
void signal_del(event_loop_t *loop, signal_t *sig) {
- if(!sig->cb)
+ if(!sig->cb) {
return;
+ }
loop->deletion = true;
if(diff.tv_sec < 0) {
timeout->cb(loop, timeout->data);
- if(timercmp(&timeout->tv, &loop->now, <))
+
+ if(timercmp(&timeout->tv, &loop->now, <)) {
timeout_del(loop, timeout);
+ }
} else {
tv = &diff;
break;
if(loop->idle_cb) {
it = loop->idle_cb(loop, loop->idle_data);
- if(it.tv_sec >= 0 && (!tv || timercmp(&it, tv, <)))
+
+ if(it.tv_sec >= 0 && (!tv || timercmp(&it, tv, <))) {
tv = ⁢
+ }
}
memcpy(&readable, &loop->readfds, sizeof(readable));
}
// release mesh mutex during select
- if(mutex)
+ if(mutex) {
pthread_mutex_unlock(mutex);
+ }
+
int n = select(fds, &readable, &writable, NULL, tv);
- if(mutex)
+
+ if(mutex) {
pthread_mutex_lock(mutex);
+ }
if(n < 0) {
- if(sockwouldblock(errno))
+ if(sockwouldblock(errno)) {
continue;
- else
+ } else {
return false;
+ }
}
- if(!n)
+ if(!n) {
continue;
+ }
// Normally, splay_each allows the current node to be deleted. However,
// it can be that one io callback triggers the deletion of another io,
loop->deletion = false;
for splay_each(io_t, io, &loop->ios) {
- if(FD_ISSET(io->fd, &writable) && io->cb)
+ if(FD_ISSET(io->fd, &writable) && io->cb) {
io->cb(loop, io->data, IO_WRITE);
- if(loop->deletion)
+ }
+
+ if(loop->deletion) {
break;
- if(FD_ISSET(io->fd, &readable) && io->cb)
+ }
+
+ if(FD_ISSET(io->fd, &readable) && io->cb) {
io->cb(loop, io->data, IO_READ);
- if(loop->deletion)
+ }
+
+ if(loop->deletion) {
break;
+ }
}
}
void event_flush_output(event_loop_t *loop) {
for splay_each(io_t, io, &loop->ios)
- if(FD_ISSET(io->fd, &loop->writefds))
+ if(FD_ISSET(io->fd, &loop->writefds)) {
io->cb(loop, io->data, IO_WRITE);
+ }
}
void event_loop_start(event_loop_t *loop) {
}
void event_loop_exit(event_loop_t *loop) {
- for splay_each(io_t, io, &loop->ios)
+ for splay_each(io_t, io, &loop->ios) {
splay_unlink_node(&loop->ios, node);
- for splay_each(timeout_t, timeout, &loop->timeouts)
+ }
+
+ for splay_each(timeout_t, timeout, &loop->timeouts) {
splay_unlink_node(&loop->timeouts, node);
- for splay_each(signal_t, signal, &loop->signals)
+ }
+
+ for splay_each(signal_t, signal, &loop->signals) {
splay_unlink_node(&loop->signals, node);
+ }
}
switch(ecode) {
case EAI_NODATA:
return "No address associated with hostname";
+
case EAI_MEMORY:
return "Memory allocation failure";
+
case EAI_FAMILY:
return "Address family not supported";
+
default:
return "Unknown error";
}
int i;
uint16_t port = 0;
- if(hints && hints->ai_family != AF_INET && hints->ai_family != AF_UNSPEC)
+ if(hints && hints->ai_family != AF_INET && hints->ai_family != AF_UNSPEC) {
return EAI_FAMILY;
+ }
- if(servname)
+ if(servname) {
port = htons(atoi(servname));
+ }
if(hints && hints->ai_flags & AI_PASSIVE) {
*res = malloc_ai(port, htonl(0x00000000));
hp = gethostbyname(hostname);
- if(!hp || !hp->h_addr_list || !hp->h_addr_list[0])
+ if(!hp || !hp->h_addr_list || !hp->h_addr_list[0]) {
return EAI_NODATA;
+ }
for(i = 0; hp->h_addr_list[i]; i++) {
*res = malloc_ai(port, ((struct in_addr *)hp->h_addr_list[i])->s_addr);
- if(prev)
+ if(prev) {
prev->ai_next = *res;
+ }
prev = *res;
}
struct hostent *hp;
int len;
- if(sa->sa_family != AF_INET)
+ if(sa->sa_family != AF_INET) {
return EAI_FAMILY;
+ }
if(serv && servlen) {
len = snprintf(serv, servlen, "%d", ntohs(sin->sin_port));
- if(len < 0 || len >= servlen)
+
+ if(len < 0 || len >= servlen) {
return EAI_MEMORY;
+ }
}
- if(!host || !hostlen)
+ if(!host || !hostlen) {
return 0;
+ }
if(flags & NI_NUMERICHOST) {
len = snprintf(host, hostlen, "%s", inet_ntoa(sin->sin_addr));
- if(len < 0 || len >= hostlen)
+
+ if(len < 0 || len >= hostlen) {
return EAI_MEMORY;
+ }
+
return 0;
}
hp = gethostbyaddr((char *)&sin->sin_addr, sizeof(struct in_addr), AF_INET);
- if(!hp || !hp->h_name || !hp->h_name[0])
+ if(!hp || !hp->h_name || !hp->h_name[0]) {
return EAI_NODATA;
+ }
len = snprintf(host, hostlen, "%s", hp->h_name);
- if(len < 0 || len >= hostlen)
+
+ if(len < 0 || len >= hostlen) {
return EAI_MEMORY;
+ }
return 0;
}
static void mst_kruskal(meshlink_handle_t *mesh) {
/* Clear MST status on connections */
- for list_each(connection_t, c, mesh->connections)
+ for list_each(connection_t, c, mesh->connections) {
c->status.mst = false;
+ }
logger(mesh, MESHLINK_DEBUG, "Running Kruskal's algorithm:");
/* Clear visited status on nodes */
- for splay_each(node_t, n, mesh->nodes)
+ for splay_each(node_t, n, mesh->nodes) {
n->status.visited = false;
+ }
/* Starting point */
e->from->status.visited = true;
e->to->status.visited = true;
- if(e->connection)
+ if(e->connection) {
e->connection->status.mst = true;
+ }
- if(e->reverse->connection)
+ if(e->reverse->connection) {
e->reverse->connection->status.mst = true;
+ }
logger(mesh, MESHLINK_DEBUG, " Adding edge %s - %s weight %d", e->from->name, e->to->name, e->weight);
for list_each(node_t, n, todo_list) { /* "n" is the node from which we start */
logger(mesh, MESHLINK_DEBUG, " Examining edges from %s", n->name);
- if(n->distance < 0)
+ if(n->distance < 0) {
abort();
+ }
for splay_each(edge_t, e, n->edge_tree) { /* "e" is the edge connected to "from" */
- if(!e->reverse)
+ if(!e->reverse) {
continue;
+ }
/* Situation:
if(e->to->status.visited
&& (!e->to->status.indirect || indirect)
- && (e->to->distance != n->distance + 1 || e->weight >= e->to->prevedge->weight))
+ && (e->to->distance != n->distance + 1 || e->weight >= e->to->prevedge->weight)) {
continue;
+ }
e->to->status.visited = true;
e->to->status.indirect = indirect;
e->to->options = e->options;
e->to->distance = n->distance + 1;
- if(!e->to->status.reachable || (e->to->address.sa.sa_family == AF_UNSPEC && e->address.sa.sa_family != AF_UNKNOWN))
+ if(!e->to->status.reachable || (e->to->address.sa.sa_family == AF_UNSPEC && e->address.sa.sa_family != AF_UNKNOWN)) {
update_node_udp(mesh, e->to, &e->address);
+ }
list_insert_tail(todo_list, e->to);
}
n->status.reachable = !n->status.reachable;
n->last_state_change = mesh->loop.now.tv_sec;
- if(n->status.reachable)
+ if(n->status.reachable) {
logger(mesh, MESHLINK_DEBUG, "Node %s became reachable", n->name);
- else
+ } else {
logger(mesh, MESHLINK_DEBUG, "Node %s became unreachable", n->name);
+ }
/* TODO: only clear status.validkey if node is unreachable? */
memset(&n->status, 0, sizeof(n)->status);
n->options = 0;
} else if(n->connection) {
- if(n->connection->outgoing)
+ if(n->connection->outgoing) {
send_req_key(mesh, n);
+ }
}
}
}
static uint32_t hash_function(const void *p, size_t len) {
const uint8_t *q = p;
uint32_t hash = 0;
+
while(true) {
- for(int i = len > 4 ? 4 : len; --i;)
+ for(int i = len > 4 ? 4 : len; --i;) {
hash += q[len - i] << (8 * i);
+ }
+
hash *= 0x9e370001UL; // Golden ratio prime.
- if(len <= 4)
+
+ if(len <= 4) {
break;
+ }
+
len -= 4;
}
+
return hash;
}
/* Map 32 bits int onto 0..n-1, without throwing away too many bits if n is 2^8 or 2^16 */
static uint32_t modulo(uint32_t hash, size_t n) {
- if(n == 0x100)
+ if(n == 0x100) {
return (hash >> 24) ^ ((hash >> 16) & 0xff) ^ ((hash >> 8) & 0xff) ^ (hash & 0xff);
- else if(n == 0x10000)
+ } else if(n == 0x10000) {
return (hash >> 16) ^ (hash & 0xffff);
- else
+ } else {
return hash % n;
+ }
}
/* (De)allocation */
void *hash_search(const hash_t *hash, const void *key) {
uint32_t i = modulo(hash_function(key, hash->size), hash->n);
- if(hash->values[i] && !memcmp(key, hash->keys + i * hash->size, hash->size))
+
+ if(hash->values[i] && !memcmp(key, hash->keys + i * hash->size, hash->size)) {
return (void *)hash->values[i];
+ }
+
return NULL;
}
void *hash_search_or_insert(hash_t *hash, const void *key, const void *value) {
uint32_t i = modulo(hash_function(key, hash->size), hash->n);
- if(hash->values[i] && !memcmp(key, hash->keys + i * hash->size, hash->size))
+
+ if(hash->values[i] && !memcmp(key, hash->keys + i * hash->size, hash->size)) {
return (void *)hash->values[i];
+ }
+
memcpy(hash->keys + i * hash->size, key, hash->size);
hash->values[i] = value;
return NULL;
void hash_resize(hash_t *hash, size_t n) {
hash->keys = xrealloc(hash->keys, n * hash->size);
hash->values = xrealloc(hash->values, n * sizeof(*hash->values));
+
if(n > hash->n) {
memset(hash->keys + hash->n * hash->size, 0, (n - hash->n) * hash->size);
memset(hash->values + hash->n, 0, (n - hash->n) * sizeof(*hash->values));
}
void list_free_node(list_t *list, list_node_t *node) {
- if(node->data && list->delete)
+ if(node->data && list->delete) {
list->delete(node->data);
+ }
free(node);
}
node->next = list->head;
list->head = node;
- if(node->next)
+ if(node->next) {
node->next->prev = node;
- else
+ } else {
list->tail = node;
+ }
list->count++;
node->prev = list->tail;
list->tail = node;
- if(node->prev)
+ if(node->prev) {
node->prev->next = node;
- else
+ } else {
list->head = node;
+ }
list->count++;
node->prev = after;
after->next = node;
- if(node->next)
+ if(node->next) {
node->next->prev = node;
- else
+ } else {
list->tail = node;
+ }
list->count++;
node->prev = before->prev;
before->prev = node;
- if(node->prev)
+ if(node->prev) {
node->prev->next = node;
- else
+ } else {
list->head = node;
+ }
list->count++;
}
void list_unlink_node(list_t *list, list_node_t *node) {
- if(node->prev)
+ if(node->prev) {
node->prev->next = node->next;
- else
+ } else {
list->head = node->next;
+ }
- if(node->next)
+ if(node->next) {
node->next->prev = node->prev;
- else
+ } else {
list->tail = node->prev;
+ }
list->count--;
}
void list_delete(list_t *list, const void *data) {
for(list_node_t *node = list->head, *next; next = node ? node->next : NULL, node; node = next)
- if(node->data == data)
+ if(node->data == data) {
list_delete_node(list, node);
+ }
}
/* Head/tail lookup */
void *list_get_head(list_t *list) {
- if(list->head)
+ if(list->head) {
return list->head->data;
- else
+ } else {
return NULL;
+ }
}
void *list_get_tail(list_t *list) {
- if(list->tail)
+ if(list->tail) {
return list->tail->data;
- else
+ } else {
return NULL;
+ }
}
/* Fast list deletion */
void list_delete_list(list_t *list) {
- for(list_node_t *node = list->head, *next; next = node ? node->next : NULL, node; node = next)
+ for(list_node_t *node = list->head, *next; next = node ? node->next : NULL, node; node = next) {
list_free_node(list, node);
+ }
list_free(list);
}
/* Traversing */
void list_foreach_node(list_t *list, list_action_node_t action) {
- for(list_node_t *node = list->head, *next; next = node ? node->next : NULL, node; node = next)
+ for(list_node_t *node = list->head, *next; next = node ? node->next : NULL, node; node = next) {
action(node);
+ }
}
void list_foreach(list_t *list, list_action_t action) {
for(list_node_t *node = list->head, *next; next = node ? node->next : NULL, node; node = next)
- if(node->data)
+ if(node->data) {
action(node->data);
+ }
}
// TODO: refactor logging code to use a meshlink_handle_t *.
void logger(meshlink_handle_t *mesh, meshlink_log_level_t level, const char *format, ...) {
if(mesh) {
- if(level < mesh->log_level || !mesh->log_cb)
+ if(level < mesh->log_level || !mesh->log_cb) {
return;
+ }
} else {
- if(level < global_log_level || !global_log_cb)
+ if(level < global_log_level || !global_log_cb) {
return;
+ }
}
va_list ap;
int len = vsnprintf(message, sizeof(message), format, ap);
va_end(ap);
- if(len > 0 && (size_t)len < sizeof(message) && message[len - 1] == '\n')
+ if(len > 0 && (size_t)len < sizeof(message) && message[len - 1] == '\n') {
message[len - 1] = 0;
+ }
- if(mesh)
+ if(mesh) {
mesh->log_cb(mesh, level, message);
- else
+ } else {
global_log_cb(NULL, level, message);
+ }
}
*/
bool open(const char *confbase, const char *name, const char *appname, dev_class_t devclass) {
handle = meshlink_open(confbase, name, appname, devclass);
- if(handle)
+
+ if(handle) {
handle->priv = this;
+ }
return isOpen();
}
handle->priv = 0;
meshlink_close(handle);
}
+
handle = 0;
}
/// static callback trampolines:
static void receive_trampoline(meshlink_handle_t *handle, meshlink_node_t *source, const void *data, size_t length) {
- if(!(handle->priv))
+ if(!(handle->priv)) {
return;
+ }
+
meshlink::mesh *that = static_cast<mesh *>(handle->priv);
that->receive(static_cast<node *>(source), data, length);
}
static void node_status_trampoline(meshlink_handle_t *handle, meshlink_node_t *peer, bool reachable) {
- if(!(handle->priv))
+ if(!(handle->priv)) {
return;
+ }
+
meshlink::mesh *that = static_cast<mesh *>(handle->priv);
that->node_status(static_cast<node *>(peer), reachable);
}
static void log_trampoline(meshlink_handle_t *handle, log_level_t level, const char *message) {
- if(!(handle->priv))
+ if(!(handle->priv)) {
return;
+ }
+
meshlink::mesh *that = static_cast<mesh *>(handle->priv);
that->log(level, message);
}
static bool channel_accept_trampoline(meshlink_handle_t *handle, meshlink_channel *channel, uint16_t port, const void *data, size_t len) {
- if(!(handle->priv))
+ if(!(handle->priv)) {
return false;
+ }
+
meshlink::mesh *that = static_cast<mesh *>(handle->priv);
bool accepted = that->channel_accept(static_cast<meshlink::channel *>(channel), port, data, len);
+
if(accepted) {
meshlink_set_channel_receive_cb(handle, channel, &channel_receive_trampoline);
meshlink_set_channel_poll_cb(handle, channel, &channel_poll_trampoline);
}
+
return accepted;
}
static void channel_receive_trampoline(meshlink_handle_t *handle, meshlink_channel *channel, const void *data, size_t len) {
- if(!(handle->priv))
+ if(!(handle->priv)) {
return;
+ }
+
meshlink::mesh *that = static_cast<mesh *>(handle->priv);
that->channel_receive(static_cast<meshlink::channel *>(channel), data, len);
}
static void channel_poll_trampoline(meshlink_handle_t *handle, meshlink_channel *channel, size_t len) {
- if(!(handle->priv))
+ if(!(handle->priv)) {
return;
+ }
+
meshlink::mesh *that = static_cast<mesh *>(handle->priv);
that->channel_poll(static_cast<meshlink::channel *>(channel), len);
}
static bool fcopy(FILE *out, const char *filename) {
FILE *in = fopen(filename, "r");
+
if(!in) {
logger(NULL, MESHLINK_ERROR, "Could not open %s: %s\n", filename, strerror(errno));
return false;
char buf[1024];
size_t len;
- while((len = fread(buf, 1, sizeof(buf), in)))
+
+ while((len = fread(buf, 1, sizeof(buf), in))) {
fwrite(buf, len, 1, out);
+ }
+
fclose(in);
return true;
}
static int rstrip(char *value) {
int len = strlen(value);
- while(len && strchr("\t\r\n ", value[len - 1]))
+
+ while(len && strchr("\t\r\n ", value[len - 1])) {
value[--len] = 0;
+ }
+
return len;
}
static void scan_for_hostname(const char *filename, char **hostname, char **port) {
char line[4096];
- if(!filename || (*hostname && *port))
+
+ if(!filename || (*hostname && *port)) {
return;
+ }
FILE *f = fopen(filename, "r");
- if(!f)
+
+ if(!f) {
return;
+ }
while(fgets(line, sizeof(line), f)) {
- if(!rstrip(line))
+ if(!rstrip(line)) {
continue;
+ }
+
char *p = line, *q;
p += strcspn(p, "\t =");
- if(!*p)
+
+ if(!*p) {
continue;
+ }
+
q = p + strspn(p, "\t ");
- if(*q == '=')
+
+ if(*q == '=') {
q += 1 + strspn(q + 1, "\t ");
+ }
+
*p = 0;
p = q + strcspn(q, "\t ");
- if(*p)
+
+ if(*p) {
*p++ = 0;
+ }
+
p += strspn(p, "\t ");
p[strcspn(p, "\t ")] = 0;
- if(!*port && !strcasecmp(line, "Port"))
+ if(!*port && !strcasecmp(line, "Port")) {
*port = xstrdup(q);
- else if(!*hostname && !strcasecmp(line, "Address")) {
+ } else if(!*hostname && !strcasecmp(line, "Address")) {
*hostname = xstrdup(q);
+
if(*p) {
free(*port);
*port = xstrdup(p);
}
}
- if(*hostname && *port)
+ if(*hostname && *port) {
break;
+ }
}
fclose(f);
static bool is_valid_hostname(const char *hostname) {
for(const char *p = hostname; *p; p++) {
- if(!(isalnum(*p) || *p == '-' || *p == '.' || *p == ':'))
+ if(!(isalnum(*p) || *p == '-' || *p == '.' || *p == ':')) {
return false;
+ }
}
return true;
while(aip) {
int s = socket(aip->ai_family, aip->ai_socktype, aip->ai_protocol);
+
if(s >= 0) {
set_timeout(s, 5000);
+
if(connect(s, aip->ai_addr, aip->ai_addrlen)) {
closesocket(s);
s = -1;
}
}
+
if(s >= 0) {
send(s, request, sizeof(request) - 1, 0);
int len = recv(s, line, sizeof(line) - 1, MSG_WAITALL);
+
if(len > 0) {
line[len] = 0;
- if(line[len - 1] == '\n')
+
+ if(line[len - 1] == '\n') {
line[--len] = 0;
+ }
+
char *p = strrchr(line, '\n');
- if(p && p[1])
+
+ if(p && p[1]) {
hostname = xstrdup(p + 1);
+ }
}
+
closesocket(s);
- if(hostname)
+
+ if(hostname) {
break;
+ }
}
+
aip = aip->ai_next;
continue;
}
- if(ai)
+ if(ai) {
freeaddrinfo(ai);
+ }
// Check that the hostname is reasonable
if(hostname && !is_valid_hostname(hostname)) {
hostname = NULL;
}
- if(!hostname)
+ if(!hostname) {
meshlink_errno = MESHLINK_ERESOLV;
+ }
return hostname;
}
snprintf(filename, sizeof(filename), "%s" SLASH "hosts" SLASH "%s", mesh->confbase, name);
scan_for_hostname(filename, &hostname, &port);
- if(hostname)
+ if(hostname) {
goto done;
+ }
hostname = meshlink_get_external_address(mesh);
- if(!hostname)
+
+ if(!hostname) {
return NULL;
+ }
f = fopen(filename, "a");
+
if(f) {
fprintf(f, "\nAddress = %s\n", hostname);
fclose(f);
- } else
+ } else {
logger(mesh, MESHLINK_DEBUG, "Could not append Address to %s: %s\n", filename, strerror(errno));
+ }
done:
+
if(port) {
- if(strchr(hostname, ':'))
+ if(strchr(hostname, ':')) {
xasprintf(&hostport, "[%s]:%s", hostname, port);
- else
+ } else {
xasprintf(&hostport, "%s:%s", hostname, port);
+ }
} else {
- if(strchr(hostname, ':'))
+ if(strchr(hostname, ':')) {
xasprintf(&hostport, "[%s]", hostname);
- else
+ } else {
hostport = xstrdup(hostname);
+ }
}
free(hostname);
}
static char *get_line(const char **data) {
- if(!data || !*data)
+ if(!data || !*data) {
return NULL;
+ }
if(! **data) {
*data = NULL;
static char line[1024];
const char *end = strchr(*data, '\n');
size_t len = end ? (size_t)(end - *data) : strlen(*data);
+
if(len >= sizeof(line)) {
logger(NULL, MESHLINK_ERROR, "Maximum line length exceeded!\n");
return NULL;
}
- if(len && !isprint(**data))
+
+ if(len && !isprint(**data)) {
abort();
+ }
memcpy(line, *data, len);
line[len] = 0;
- if(end)
+ if(end) {
*data = end + 1;
- else
+ } else {
*data = NULL;
+ }
return line;
}
static char *get_value(const char *data, const char *var) {
char *line = get_line(&data);
- if(!line)
+
+ if(!line) {
return NULL;
+ }
char *sep = line + strcspn(line, " \t=");
char *val = sep + strspn(sep, " \t");
- if(*val == '=')
+
+ if(*val == '=') {
val += 1 + strspn(val + 1, " \t");
+ }
+
*sep = 0;
- if(strcasecmp(line, var))
+
+ if(strcasecmp(line, var)) {
return NULL;
+ }
+
return val;
}
char portstr[16];
snprintf(portstr, sizeof(portstr), "%d", port);
- if(getaddrinfo(NULL, portstr, &hint, &ai) || !ai)
+ if(getaddrinfo(NULL, portstr, &hint, &ai) || !ai) {
return false;
+ }
while(ai) {
int fd = socket(ai->ai_family, SOCK_STREAM, IPPROTO_TCP);
+
if(!fd) {
freeaddrinfo(ai);
return false;
}
+
int result = bind(fd, ai->ai_addr, ai->ai_addrlen);
closesocket(fd);
+
if(result) {
freeaddrinfo(ai);
return false;
}
+
ai = ai->ai_next;
}
static int check_port(meshlink_handle_t *mesh) {
for(int i = 0; i < 1000; i++) {
int port = 0x1000 + (rand() & 0x7fff);
+
if(try_bind(port)) {
char filename[PATH_MAX];
snprintf(filename, sizeof(filename), "%s" SLASH "hosts" SLASH "%s", mesh->confbase, mesh->name);
FILE *f = fopen(filename, "a");
+
if(!f) {
logger(mesh, MESHLINK_DEBUG, "Please change MeshLink's Port manually.\n");
return 0;
static bool finalize_join(meshlink_handle_t *mesh) {
char *name = xstrdup(get_value(mesh->data, "Name"));
+
if(!name) {
logger(mesh, MESHLINK_DEBUG, "No Name found in invitation!\n");
return false;
snprintf(filename, sizeof(filename), "%s" SLASH "meshlink.conf", mesh->confbase);
FILE *f = fopen(filename, "w");
+
if(!f) {
logger(mesh, MESHLINK_DEBUG, "Could not create file %s: %s\n", filename, strerror(errno));
return false;
snprintf(filename, sizeof(filename), "%s" SLASH "hosts" SLASH "%s", mesh->confbase, name);
FILE *fh = fopen(filename, "w");
+
if(!fh) {
logger(mesh, MESHLINK_DEBUG, "Could not create file %s: %s\n", filename, strerror(errno));
fclose(f);
while((l = get_line(&p))) {
// Ignore comments
- if(*l == '#')
+ if(*l == '#') {
continue;
+ }
// Split line into variable and value
int len = strcspn(l, "\t =");
value = l + len;
value += strspn(value, "\t ");
+
if(*value == '=') {
value++;
value += strspn(value, "\t ");
}
+
l[len] = 0;
// Is it a Name?
if(!strcasecmp(l, "Name"))
- if(strcmp(value, name))
+ if(strcmp(value, name)) {
break;
- else
+ } else {
continue;
- else if(!strcasecmp(l, "NetName"))
+ } else if(!strcasecmp(l, "NetName")) {
continue;
+ }
// Check the list of known variables //TODO: most variables will not be available in meshlink, only name and key will be absolutely necessary
bool found = false;
int i;
+
for(i = 0; variables[i].name; i++) {
- if(strcasecmp(l, variables[i].name))
+ if(strcasecmp(l, variables[i].name)) {
continue;
+ }
+
found = true;
break;
}
}
while((l = get_line(&p))) {
- if(!strcmp(l, "#---------------------------------------------------------------#"))
+ if(!strcmp(l, "#---------------------------------------------------------------#")) {
continue;
+ }
+
int len = strcspn(l, "\t =");
+
if(len == 4 && !strncasecmp(l, "Name", 4)) {
value = l + len;
value += strspn(value, "\t ");
+
if(*value == '=') {
value++;
value += strspn(value, "\t ");
}
+
l[len] = 0;
break;
}
}
char *b64key = ecdsa_get_base64_public_key(mesh->self->connection->ecdsa);
+
if(!b64key) {
fclose(fh);
return false;
static bool invitation_send(void *handle, uint8_t type, const void *data, size_t len) {
(void)type;
meshlink_handle_t *mesh = handle;
+
while(len) {
int result = send(mesh->sock, data, len, 0);
- if(result == -1 && errno == EINTR)
+
+ if(result == -1 && errno == EINTR) {
continue;
- else if(result <= 0)
+ } else if(result <= 0) {
return false;
+ }
+
data += result;
len -= result;
}
+
return true;
}
static bool invitation_receive(void *handle, uint8_t type, const void *msg, uint16_t len) {
meshlink_handle_t *mesh = handle;
+
switch(type) {
case SPTPS_HANDSHAKE:
return sptps_send_record(&(mesh->sptps), 0, mesh->cookie, sizeof(mesh)->cookie);
static bool recvline(meshlink_handle_t *mesh, size_t len) {
char *newline = NULL;
- if(!mesh->sock)
+ if(!mesh->sock) {
abort();
+ }
while(!(newline = memchr(mesh->buffer, '\n', mesh->blen))) {
int result = recv(mesh->sock, mesh->buffer + mesh->blen, sizeof(mesh)->buffer - mesh->blen, 0);
- if(result == -1 && errno == EINTR)
+
+ if(result == -1 && errno == EINTR) {
continue;
- else if(result <= 0)
+ } else if(result <= 0) {
return false;
+ }
+
mesh->blen += result;
}
- if((size_t)(newline - mesh->buffer) >= len)
+ if((size_t)(newline - mesh->buffer) >= len) {
return false;
+ }
len = newline - mesh->buffer;
blen = vsnprintf(buffer, sizeof(buffer), format, ap);
va_end(ap);
- if(blen < 1 || (size_t)blen >= sizeof(buffer))
+ if(blen < 1 || (size_t)blen >= sizeof(buffer)) {
return false;
+ }
buffer[blen] = '\n';
blen++;
while(blen) {
int result = send(fd, p, blen, MSG_NOSIGNAL);
- if(result == -1 && errno == EINTR)
+
+ if(result == -1 && errno == EINTR) {
continue;
- else if(result <= 0)
+ } else if(result <= 0) {
return false;
+ }
+
p += result;
blen -= result;
}
};
const char *meshlink_strerror(meshlink_errno_t err) {
- if((int)err < 0 || err >= sizeof(errstr) / sizeof(*errstr))
+ if((int)err < 0 || err >= sizeof(errstr) / sizeof(*errstr)) {
return "Invalid error code";
+ }
+
return errstr[err];
}
logger(mesh, MESHLINK_DEBUG, "Error during key generation!\n");
meshlink_errno = MESHLINK_EINTERNAL;
return false;
- } else
+ } else {
logger(mesh, MESHLINK_DEBUG, "Done.\n");
+ }
snprintf(privname, sizeof(privname), "%s" SLASH "ecdsa_key.priv", mesh->confbase);
f = fopen(privname, "wb");
(void)loop;
meshlink_handle_t *mesh = data;
struct timeval t, tmin = {3600, 0};
+
for splay_each(node_t, n, mesh->nodes) {
- if(!n->utcp)
+ if(!n->utcp) {
continue;
+ }
+
t = utcp_timeout(n->utcp);
- if(timercmp(&t, &tmin, <))
+
+ if(timercmp(&t, &tmin, <)) {
tmin = t;
+ }
}
+
return tmin;
}
.ai_protocol = IPPROTO_UDP,
};
- if(getaddrinfo(destaddr, "80", &hint, &rai) || !rai)
+ if(getaddrinfo(destaddr, "80", &hint, &rai) || !rai) {
return false;
+ }
int sock = socket(rai->ai_family, rai->ai_socktype, rai->ai_protocol);
+
if(sock == -1) {
freeaddrinfo(rai);
return false;
struct sockaddr_storage sn;
socklen_t sl = sizeof(sn);
- if(getsockname(sock, (struct sockaddr *)&sn, &sl))
+ if(getsockname(sock, (struct sockaddr *)&sn, &sl)) {
return false;
+ }
- if(getnameinfo((struct sockaddr *)&sn, sl, host, hostlen, NULL, 0, NI_NUMERICHOST | NI_NUMERICSERV))
+ if(getnameinfo((struct sockaddr *)&sn, sl, host, hostlen, NULL, 0, NI_NUMERICHOST | NI_NUMERICSERV)) {
return false;
+ }
return true;
}
}
FILE *f = fopen(filename, "w");
+
if(!f) {
logger(mesh, MESHLINK_DEBUG, "Could not create file %s: %s\n", filename, strerror(errno));
meshlink_errno = MESHLINK_ESTORAGE;
logger(NULL, MESHLINK_ERROR, "Invalid name given!\n");
meshlink_errno = MESHLINK_EINVAL;
return NULL;
- } else
+ } else {
usingname = true;
+ }
}
if((int)devclass < 0 || devclass > _DEV_CLASS_MAX) {
mesh->confbase = xstrdup(confbase);
mesh->appname = xstrdup(appname);
mesh->devclass = devclass;
- if(usingname) mesh->name = xstrdup(name);
+
+ if(usingname) {
+ mesh->name = xstrdup(name);
+ }
// initialize mutex
pthread_mutexattr_t attr;
#ifdef HAVE_MINGW
struct WSAData wsa_state;
+
WSAStartup(MAKEWORD(2, 2), &wsa_state);
+
#endif
// Setup up everything
mesh->threadstarted = true;
- if(mesh->discovery)
+ if(mesh->discovery) {
discovery_start(mesh);
+ }
pthread_mutex_unlock(&(mesh->mesh_mutex));
return true;
logger(mesh, MESHLINK_DEBUG, "meshlink_stop called\n");
// Stop discovery
- if(mesh->discovery)
+ if(mesh->discovery) {
discovery_stop(mesh);
+ }
// 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];
- if(sendto(s->udp.fd, "", 1, MSG_NOSIGNAL, &s->sa.sa, SALEN(s->sa.sa)) == -1)
+
+ 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));
}
}
- if(mesh->outgoings)
+ if(mesh->outgoings) {
list_delete_list(mesh->outgoings);
+ }
+
mesh->outgoings = NULL;
pthread_mutex_unlock(&(mesh->mesh_mutex));
event_loop_exit(&mesh->loop);
#ifdef HAVE_MINGW
- if(mesh->confbase)
+
+ if(mesh->confbase) {
WSACleanup();
+ }
+
#endif
ecdsa_free(mesh->invitation_key);
static void deltree(const char *dirname) {
DIR *d = opendir(dirname);
+
if(d) {
struct dirent *ent;
+
while((ent = readdir(d))) {
- if(ent->d_name[0] == '.')
+ if(ent->d_name[0] == '.') {
continue;
+ }
+
char filename[PATH_MAX];
snprintf(filename, sizeof(filename), "%s" SLASH "%s", dirname, ent->d_name);
- if(unlink(filename))
+
+ if(unlink(filename)) {
deltree(filename);
+ }
}
+
closedir(d);
}
+
rmdir(dirname);
return;
}
return false;
}
- if(!len)
+ if(!len) {
return true;
+ }
if(!data) {
meshlink_errno = MESHLINK_EINVAL;
// Prepare the packet
vpn_packet_t *packet = malloc(sizeof(*packet));
+
if(!packet) {
meshlink_errno = MESHLINK_ENOMEM;
return false;
void meshlink_send_from_queue(event_loop_t *loop, meshlink_handle_t *mesh) {
(void)loop;
vpn_packet_t *packet = meshlink_queue_pop(&mesh->outpacketqueue);
- if(!packet)
+
+ if(!packet) {
return;
+ }
mesh->self->in_packets++;
mesh->self->in_bytes += packet->len;
meshlink_errno = MESHLINK_EINVAL;
return -1;
}
+
pthread_mutex_lock(&(mesh->mesh_mutex));
node_t *n = (node_t *)destination;
+
if(!n->status.reachable) {
pthread_mutex_unlock(&(mesh->mesh_mutex));
return 0;
meshlink_errno = MESHLINK_EINVAL;
return NULL;
}
+
pthread_mutex_lock(&(mesh->mesh_mutex));
node_t *n = (node_t *)node;
char *fingerprint = ecdsa_get_base64_public_key(n->ecdsa);
- if(!fingerprint)
+ if(!fingerprint) {
meshlink_errno = MESHLINK_EINTERNAL;
+ }
pthread_mutex_unlock(&(mesh->mesh_mutex));
return fingerprint;
if(result) {
meshlink_node_t **p = result;
- for splay_each(node_t, n, mesh->nodes)
+
+ for splay_each(node_t, n, mesh->nodes) {
*p++ = (meshlink_node_t *)n;
+ }
} else {
*nmemb = 0;
free(nodes);
struct node_t *n = (struct node_t *)source;
node_read_ecdsa_public_key(mesh, n);
+
if(!n->ecdsa) {
meshlink_errno = MESHLINK_EINTERNAL;
rval = false;
- } else
+ } else {
rval = ecdsa_verify(((struct node_t *)source)->ecdsa, data, len, signature);
+ }
+
pthread_mutex_unlock(&(mesh->mesh_mutex));
return rval;
}
pthread_mutex_lock(&(mesh->mesh_mutex));
snprintf(filename, sizeof(filename), "%s" SLASH "invitations", mesh->confbase);
+
if(mkdir(filename, 0700) && errno != EEXIST) {
logger(mesh, MESHLINK_DEBUG, "Could not create directory %s: %s\n", filename, strerror(errno));
meshlink_errno = MESHLINK_ESTORAGE;
// Count the number of valid invitations, clean up old ones
DIR *dir = opendir(filename);
+
if(!dir) {
logger(mesh, MESHLINK_DEBUG, "Could not read directory %s: %s\n", filename, strerror(errno));
meshlink_errno = MESHLINK_ESTORAGE;
time_t deadline = time(NULL) - 604800; // 1 week in the past
while((ent = readdir(dir))) {
- if(strlen(ent->d_name) != 24)
+ if(strlen(ent->d_name) != 24) {
continue;
+ }
+
char invname[PATH_MAX];
struct stat st;
snprintf(invname, sizeof(invname), "%s" SLASH "%s", filename, ent->d_name);
+
if(!stat(invname, &st)) {
- if(mesh->invitation_key && deadline < st.st_mtime)
+ if(mesh->invitation_key && deadline < st.st_mtime) {
count++;
- else
+ } else {
unlink(invname);
+ }
} else {
logger(mesh, MESHLINK_DEBUG, "Could not stat %s: %s\n", invname, strerror(errno));
errno = 0;
// Remove the key if there are no outstanding invitations.
if(!count) {
unlink(filename);
+
if(mesh->invitation_key) {
ecdsa_free(mesh->invitation_key);
mesh->invitation_key = NULL;
// Create a new key if necessary.
FILE *f = fopen(filename, "rb");
+
if(!f) {
if(errno != ENOENT) {
logger(mesh, MESHLINK_DEBUG, "Could not read %s: %s\n", filename, strerror(errno));
}
mesh->invitation_key = ecdsa_generate();
+
if(!mesh->invitation_key) {
logger(mesh, MESHLINK_DEBUG, "Could not generate a new key!\n");
meshlink_errno = MESHLINK_EINTERNAL;
pthread_mutex_unlock(&(mesh->mesh_mutex));
return false;
}
+
f = fopen(filename, "wb");
+
if(!f) {
logger(mesh, MESHLINK_DEBUG, "Could not write %s: %s\n", filename, strerror(errno));
meshlink_errno = MESHLINK_ESTORAGE;
pthread_mutex_unlock(&(mesh->mesh_mutex));
return false;
}
+
chmod(filename, 0600);
ecdsa_write_pem_private_key(mesh->invitation_key, f);
fclose(f);
} else {
mesh->invitation_key = ecdsa_read_pem_private_key(f);
fclose(f);
+
if(!mesh->invitation_key) {
logger(mesh, MESHLINK_DEBUG, "Could not read private key from %s\n", filename);
meshlink_errno = MESHLINK_ESTORAGE;
}
char *address = meshlink_get_external_address(mesh);
- if(!address)
+
+ if(!address) {
return false;
+ }
bool rval = false;
return false;
}
- if(mesh->myport && port == atoi(mesh->myport))
+ if(mesh->myport && port == atoi(mesh->myport)) {
return true;
+ }
if(!try_bind(port)) {
meshlink_errno = MESHLINK_ENETWORK;
bool rval = false;
pthread_mutex_lock(&(mesh->mesh_mutex));
+
if(mesh->threadstarted) {
meshlink_errno = MESHLINK_EINVAL;
goto done;
init_configuration(&mesh->config);
- if(!read_server_config(mesh))
+ if(!read_server_config(mesh)) {
meshlink_errno = MESHLINK_ESTORAGE;
- else if(!setup_network(mesh))
+ } else if(!setup_network(mesh)) {
meshlink_errno = MESHLINK_ENETWORK;
- else
+ } else {
rval = true;
+ }
done:
pthread_mutex_unlock(&(mesh->mesh_mutex));
// Ensure no host configuration file with that name exists
char filename[PATH_MAX];
snprintf(filename, sizeof(filename), "%s" SLASH "hosts" SLASH "%s", mesh->confbase, name);
+
if(!access(filename, F_OK)) {
logger(mesh, MESHLINK_DEBUG, "A host config file for %s already exists!\n", name);
meshlink_errno = MESHLINK_EEXIST;
// Get the local address
char *address = get_my_hostname(mesh);
+
if(!address) {
logger(mesh, MESHLINK_DEBUG, "No Address known for ourselves!\n");
meshlink_errno = MESHLINK_ERESOLV;
// Create a file containing the details of the invitation.
snprintf(filename, sizeof(filename), "%s" SLASH "invitations" SLASH "%s", mesh->confbase, cookiehash);
int ifd = open(filename, O_RDWR | O_CREAT | O_EXCL, 0600);
+
if(!ifd) {
logger(mesh, MESHLINK_DEBUG, "Could not create invitation file %s: %s\n", filename, strerror(errno));
meshlink_errno = MESHLINK_ESTORAGE;
pthread_mutex_unlock(&(mesh->mesh_mutex));
return NULL;
}
+
FILE *f = fdopen(ifd, "w");
- if(!f)
+
+ if(!f) {
abort();
+ }
// Fill in the details.
fprintf(f, "Name = %s\n", name);
// Copy Broadcast and Mode
snprintf(filename, sizeof(filename), "%s" SLASH "meshlink.conf", mesh->confbase);
FILE *tc = fopen(filename, "r");
+
if(tc) {
char buf[1024];
+
while(fgets(buf, sizeof(buf), tc)) {
if((!strncasecmp(buf, "Mode", 4) && strchr(" \t=", buf[4]))
|| (!strncasecmp(buf, "Broadcast", 9) && strchr(" \t=", buf[9]))) {
fputs(buf, f);
+
// Make sure there is a newline character.
- if(!strchr(buf, '\n'))
+ if(!strchr(buf, '\n')) {
fputc('\n', f);
+ }
}
}
+
fclose(tc);
} else {
logger(mesh, MESHLINK_DEBUG, "Could not create %s: %s\n", filename, strerror(errno));
// Split the invitation URL into hostname, port, key hash and cookie.
char *slash = strchr(copy, '/');
- if(!slash)
+
+ if(!slash) {
goto invalid;
+ }
*slash++ = 0;
- if(strlen(slash) != 48)
+ if(strlen(slash) != 48) {
goto invalid;
+ }
char *address = copy;
char *port = NULL;
+
if(*address == '[') {
address++;
char *bracket = strchr(address, ']');
- if(!bracket)
+
+ if(!bracket) {
goto invalid;
+ }
+
*bracket = 0;
- if(bracket[1] == ':')
+
+ if(bracket[1] == ':') {
port = bracket + 2;
+ }
} else {
port = strchr(address, ':');
- if(port)
+
+ if(port) {
*port++ = 0;
+ }
}
- if(!port)
+ if(!port) {
goto invalid;
+ }
- if(!b64decode(slash, mesh->hash, 18) || !b64decode(slash + 24, mesh->cookie, 18))
+ if(!b64decode(slash, mesh->hash, 18) || !b64decode(slash + 24, mesh->cookie, 18)) {
goto invalid;
+ }
// Generate a throw-away key for the invitation.
ecdsa_t *key = ecdsa_generate();
+
if(!key) {
meshlink_errno = MESHLINK_EINTERNAL;
pthread_mutex_unlock(&(mesh->mesh_mutex));
char *b64key = ecdsa_get_base64_public_key(key);
//Before doing meshlink_join make sure we are not connected to another mesh
- if(mesh->threadstarted)
+ if(mesh->threadstarted) {
goto invalid;
+ }
// Connect to the meshlink daemon mentioned in the URL.
struct addrinfo *ai = str2addrinfo(address, port, SOCK_STREAM);
+
if(!ai) {
meshlink_errno = MESHLINK_ERESOLV;
pthread_mutex_unlock(&(mesh->mesh_mutex));
}
mesh->sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
+
if(mesh->sock <= 0) {
logger(mesh, MESHLINK_DEBUG, "Could not open socket: %s\n", strerror(errno));
freeaddrinfo(ai);
// Check if the hash of the key he gave us matches the hash in the URL.
char *fingerprint = mesh->line + 2;
char hishash[64];
+
if(sha512(fingerprint, strlen(fingerprint), hishash)) {
logger(mesh, MESHLINK_DEBUG, "Could not create hash\n%s\n", mesh->line + 2);
meshlink_errno = MESHLINK_EINTERNAL;
pthread_mutex_unlock(&(mesh->mesh_mutex));
return false;
}
+
if(memcmp(hishash, mesh->hash, 18)) {
logger(mesh, MESHLINK_DEBUG, "Peer has an invalid key!\n%s\n", mesh->line + 2);
meshlink_errno = MESHLINK_EPEER;
}
ecdsa_t *hiskey = ecdsa_set_base64_public_key(fingerprint);
+
if(!hiskey) {
meshlink_errno = MESHLINK_EINTERNAL;
pthread_mutex_unlock(&(mesh->mesh_mutex));
while((len = recv(mesh->sock, mesh->line, sizeof(mesh)->line, 0))) {
if(len < 0) {
- if(errno == EINTR)
+ if(errno == EINTR) {
continue;
+ }
+
logger(mesh, MESHLINK_DEBUG, "Error reading data from %s port %s: %s\n", address, port, strerror(errno));
meshlink_errno = MESHLINK_ENETWORK;
pthread_mutex_unlock(&(mesh->mesh_mutex));
char filename[PATH_MAX];
snprintf(filename, sizeof(filename), "%s" SLASH "hosts" SLASH "%s", mesh->confbase, mesh->self->name);
FILE *f = fopen(filename, "r");
+
if(!f) {
logger(mesh, MESHLINK_DEBUG, "Could not open %s: %s\n", filename, strerror(errno));
meshlink_errno = MESHLINK_ESTORAGE;
size_t len = fsize + 9 + strlen(mesh->self->name);
char *buf = xmalloc(len);
snprintf(buf, len, "Name = %s\n", mesh->self->name);
+
if(fread(buf + len - fsize - 1, fsize, 1, f) != 1) {
logger(mesh, MESHLINK_DEBUG, "Error reading from %s: %s\n", filename, strerror(errno));
fclose(f);
}
char *end = strchr(data + 7, '\n');
+
if(!end) {
logger(mesh, MESHLINK_DEBUG, "Invalid data\n");
meshlink_errno = MESHLINK_EPEER;
char name[len + 1];
memcpy(name, data + 7, len);
name[len] = 0;
+
if(!check_id(name)) {
logger(mesh, MESHLINK_DEBUG, "Invalid Name\n");
meshlink_errno = MESHLINK_EPEER;
char filename[PATH_MAX];
snprintf(filename, sizeof(filename), "%s" SLASH "hosts" SLASH "%s", mesh->confbase, name);
+
if(!access(filename, F_OK)) {
logger(mesh, MESHLINK_DEBUG, "File %s already exists, not importing\n", filename);
meshlink_errno = MESHLINK_EEXIST;
}
FILE *f = fopen(filename, "w");
+
if(!f) {
logger(mesh, MESHLINK_DEBUG, "Could not create %s: %s\n", filename, strerror(errno));
meshlink_errno = MESHLINK_ESTORAGE;
* See header file for detailed comment.
*/
void meshlink_hint_address(meshlink_handle_t *mesh, meshlink_node_t *node, const struct sockaddr *addr) {
- if(!mesh || !node || !addr)
+ if(!mesh || !node || !addr) {
return;
+ }
// Ignore hints about ourself.
- if((node_t *)node == mesh->self)
+ if((node_t *)node == mesh->self) {
return;
+ }
pthread_mutex_lock(&(mesh->mesh_mutex));
if(host && port) {
xasprintf(&str, "%s %s", host, port);
- if((strncmp("fe80", host, 4) != 0) && (strncmp("127.", host, 4) != 0) && (strcmp("localhost", host) != 0))
+
+ if((strncmp("fe80", host, 4) != 0) && (strncmp("127.", host, 4) != 0) && (strcmp("localhost", host) != 0)) {
modify_config_file(mesh, node->name, "Address", str, 5);
- else
+ } else {
logger(mesh, MESHLINK_DEBUG, "Not adding Link Local IPv6 Address to config\n");
+ }
}
free(str);
static ssize_t channel_recv(struct utcp_connection *connection, const void *data, size_t len) {
meshlink_channel_t *channel = connection->priv;
- if(!channel)
+
+ if(!channel) {
abort();
+ }
+
node_t *n = channel->node;
meshlink_handle_t *mesh = n->mesh;
- if(n->status.destroyed)
+
+ if(n->status.destroyed) {
meshlink_channel_close(mesh, channel);
- else if(channel->receive_cb)
+ } else if(channel->receive_cb) {
channel->receive_cb(mesh, channel, data, len);
+ }
+
return len;
}
static void channel_accept(struct utcp_connection *utcp_connection, uint16_t port) {
node_t *n = utcp_connection->utcp->priv;
- if(!n)
+
+ if(!n) {
abort();
+ }
+
meshlink_handle_t *mesh = n->mesh;
- if(!mesh->channel_accept_cb)
+
+ if(!mesh->channel_accept_cb) {
return;
+ }
+
meshlink_channel_t *channel = xzalloc(sizeof(*channel));
channel->node = n;
channel->c = utcp_connection;
- if(mesh->channel_accept_cb(mesh, channel, port, NULL, 0))
+
+ if(mesh->channel_accept_cb(mesh, channel, port, NULL, 0)) {
utcp_accept(utcp_connection, channel_recv, channel);
- else
+ } else {
free(channel);
+ }
}
static ssize_t channel_send(struct utcp *utcp, const void *data, size_t len) {
static void channel_receive(meshlink_handle_t *mesh, meshlink_node_t *source, const void *data, size_t len) {
(void)mesh;
node_t *n = (node_t *)source;
- if(!n->utcp)
+
+ if(!n->utcp) {
abort();
+ }
+
utcp_recv(n->utcp, data, len);
}
static void channel_poll(struct utcp_connection *connection, size_t len) {
meshlink_channel_t *channel = connection->priv;
- if(!channel)
+
+ if(!channel) {
abort();
+ }
+
node_t *n = channel->node;
meshlink_handle_t *mesh = n->mesh;
- if(channel->poll_cb)
+
+ if(channel->poll_cb) {
channel->poll_cb(mesh, channel, len);
+ }
}
void meshlink_set_channel_poll_cb(meshlink_handle_t *mesh, meshlink_channel_t *channel, meshlink_channel_poll_cb_t cb) {
pthread_mutex_lock(&mesh->mesh_mutex);
mesh->channel_accept_cb = cb;
mesh->receive_cb = channel_receive;
+
for splay_each(node_t, n, mesh->nodes) {
- if(!n->utcp && n != mesh->self)
+ if(!n->utcp && n != mesh->self) {
n->utcp = utcp_init(channel_accept, channel_pre_accept, channel_send, n);
+ }
}
+
pthread_mutex_unlock(&mesh->mesh_mutex);
}
meshlink_channel_t *meshlink_channel_open_ex(meshlink_handle_t *mesh, meshlink_node_t *node, uint16_t port, meshlink_channel_receive_cb_t cb, const void *data, size_t len, uint32_t flags) {
- if(data || len)
- abort(); // TODO: handle non-NULL data
+ if(data || len) {
+ abort(); // TODO: handle non-NULL data
+ }
if(!mesh || !node) {
meshlink_errno = MESHLINK_EINVAL;
}
node_t *n = (node_t *)node;
+
if(!n->utcp) {
n->utcp = utcp_init(channel_accept, channel_pre_accept, channel_send, n);
mesh->receive_cb = channel_receive;
+
if(!n->utcp) {
meshlink_errno = errno == ENOMEM ? MESHLINK_ENOMEM : MESHLINK_EINTERNAL;
return NULL;
}
}
+
meshlink_channel_t *channel = xzalloc(sizeof(*channel));
channel->node = n;
channel->receive_cb = cb;
channel->c = utcp_connect_ex(n->utcp, port, channel_recv, channel, flags);
+
if(!channel->c) {
meshlink_errno = errno == ENOMEM ? MESHLINK_ENOMEM : MESHLINK_EINTERNAL;
free(channel);
return NULL;
}
+
return channel;
}
return -1;
}
- if(!len)
+ if(!len) {
return 0;
+ }
if(!data) {
meshlink_errno = MESHLINK_EINVAL;
ssize_t retval = utcp_send(channel->c, data, len);
pthread_mutex_unlock(&mesh->mesh_mutex);
- if(retval < 0)
+ if(retval < 0) {
meshlink_errno = MESHLINK_ENETWORK;
+ }
+
return retval;
}
}
void update_node_status(meshlink_handle_t *mesh, node_t *n) {
- if(n->status.reachable && mesh->channel_accept_cb && !n->utcp)
+ if(n->status.reachable && mesh->channel_accept_cb && !n->utcp) {
n->utcp = utcp_init(channel_accept, channel_pre_accept, channel_send, n);
- if(mesh->node_status_cb)
+ }
+
+ if(mesh->node_status_cb) {
mesh->node_status_cb(mesh, (meshlink_node_t *)n, n->status.reachable);
+ }
}
void meshlink_enable_discovery(meshlink_handle_t *mesh, bool enable) {
pthread_mutex_lock(&mesh->mesh_mutex);
- if(mesh->discovery == enable)
+ if(mesh->discovery == enable) {
goto end;
+ }
if(mesh->threadstarted) {
- if(enable)
+ if(enable) {
discovery_start(mesh);
- else
+ } else {
discovery_stop(mesh);
+ }
}
mesh->discovery = enable;
static inline bool meshlink_queue_push(meshlink_queue_t *queue, void *data) {
meshlink_queue_item_t *item = malloc(sizeof(*item));
- if(!item)
+
+ if(!item) {
return false;
+ }
+
item->data = data;
item->next = NULL;
pthread_mutex_lock(&queue->mutex);
- if(!queue->tail)
+
+ if(!queue->tail) {
queue->head = queue->tail = item;
- else
+ } else {
queue->tail = queue->tail->next = item;
+ }
+
pthread_mutex_unlock(&queue->mutex);
return true;
}
meshlink_queue_item_t *item;
void *data;
pthread_mutex_lock(&queue->mutex);
+
if((item = queue->head)) {
queue->head = item->next;
- if(!queue->head)
+
+ if(!queue->head) {
queue->tail = NULL;
+ }
}
+
pthread_mutex_unlock(&queue->mutex);
data = item ? item->data : NULL;
free(item);
void broadcast_meta(meshlink_handle_t *mesh, connection_t *from, const char *buffer, int length) {
for list_each(connection_t, c, mesh->connections)
- if(c != from && c->status.active)
+ if(c != from && c->status.active) {
send_meta(mesh, c, buffer, length);
+ }
}
bool receive_meta_sptps(void *handle, uint8_t type, const void *data, uint16_t length) {
}
if(type == SPTPS_HANDSHAKE) {
- if(c->allow_request == ACK)
+ if(c->allow_request == ACK) {
return send_ack(mesh, c);
- else
+ } else {
return true;
+ }
}
- if(!request)
+ if(!request) {
return true;
+ }
/* Are we receiving a TCPpacket? */
/* Change newline to null byte, just like non-SPTPS requests */
- if(request[length - 1] == '\n')
+ if(request[length - 1] == '\n') {
request[length - 1] = 0;
+ }
/* Otherwise we are waiting for a request */
if(inlen <= 0) {
if(!inlen || !errno) {
logger(mesh, MESHLINK_INFO, "Connection closed by %s", c->name);
- } else if(sockwouldblock(sockerrno))
+ } else if(sockwouldblock(sockerrno)) {
return true;
- else
+ } else {
logger(mesh, MESHLINK_ERROR, "Metadata socket read error for %s: %s", c->name, sockstrerror(sockerrno));
+ }
+
return false;
}
char *request = buffer_readline(&c->inbuf);
if(request) {
- if(!receive_request(mesh, c, request) || c->allow_request == ID)
+ if(!receive_request(mesh, c, request) || c->allow_request == ID) {
return false;
+ }
int left = c->inbuf.len - c->inbuf.offset;
+
if(left > 0) {
fprintf(stderr, "GOT A LITTLE MORE\n");
return sptps_receive_data(&c->sptps, buffer_read(&c->inbuf, left), left);
- } else
+ } else {
return true;
+ }
}
if(c->inbuf.len >= sizeof(inbuf)) {
logger(mesh, MESHLINK_ERROR, "Input buffer full for %s", c->name);
return false;
- } else
+ } else {
return true;
+ }
}
return sptps_receive_data(&c->sptps, inbuf, inlen);
c->status.active = false;
- if(c->node && c->node->connection == c)
+ if(c->node && c->node->connection == c) {
c->node->connection = NULL;
+ }
if(c->edge) {
- if(report)
+ if(report) {
send_del_edge(mesh, mesh->everyone, c->edge);
+ }
edge_del(mesh, c->edge);
c->edge = NULL;
if(report && c->node && !c->node->status.reachable) {
edge_t *e;
e = lookup_edge(c->node, mesh->self);
+
if(e) {
send_del_edge(mesh, mesh->everyone, e);
edge_del(mesh, e);
/* Check if this was our outgoing connection */
- if(outgoing)
+ if(outgoing) {
do_outgoing_connection(mesh, outgoing);
+ }
#ifndef HAVE_MINGW
/* Clean up dead proxy processes */
while(waitpid(-1, NULL, WNOHANG) > 0);
+
#endif
}
for list_each(connection_t, c, mesh->connections) {
// Also make sure that if outstanding key requests for the UDP counterpart of a connection has timed out, we restart it.
if(c->node) {
- if(c->node->status.waitingforkey && c->node->last_req_key + mesh->pingtimeout <= mesh->loop.now.tv_sec)
+ if(c->node->status.waitingforkey && c->node->last_req_key + mesh->pingtimeout <= mesh->loop.now.tv_sec) {
send_req_key(mesh, c->node);
+ }
}
+
if(c->last_ping_time + mesh->pingtimeout <= mesh->loop.now.tv_sec) {
if(c->status.active) {
- if(c->status.pinged)
+ if(c->status.pinged) {
logger(mesh, MESHLINK_INFO, "%s didn't respond to PING in %ld seconds", c->name, (long)mesh->loop.now.tv_sec - c->last_ping_time);
- else if(c->last_ping_time + mesh->pinginterval <= mesh->loop.now.tv_sec) {
+ } else if(c->last_ping_time + mesh->pinginterval <= mesh->loop.now.tv_sec) {
send_ping(mesh, c);
continue;
- } else
+ } else {
continue;
+ }
} else {
- if(c->status.connecting)
+ if(c->status.connecting) {
logger(mesh, MESHLINK_WARNING, "Timeout while connecting to %s", c->name);
- else
+ } else {
logger(mesh, MESHLINK_WARNING, "Timeout from %s during authentication", c->name);
+ }
}
+
terminate_connection(mesh, c, c->status.active);
}
}
static int node_compare_devclass_asc_lsc_desc(const void *a, const void *b) {
const node_t *na = a, *nb = b;
- if(na->devclass < nb->devclass)
+ if(na->devclass < nb->devclass) {
return -1;
+ }
- if(na->devclass > nb->devclass)
+ if(na->devclass > nb->devclass) {
return 1;
+ }
- if(na->last_successfull_connection == nb->last_successfull_connection)
+ if(na->last_successfull_connection == nb->last_successfull_connection) {
return 0;
+ }
- if(na->last_successfull_connection == 0 || na->last_successfull_connection > nb->last_successfull_connection)
+ if(na->last_successfull_connection == 0 || na->last_successfull_connection > nb->last_successfull_connection) {
return -1;
+ }
- if(nb->last_successfull_connection == 0 || na->last_successfull_connection < nb->last_successfull_connection)
+ if(nb->last_successfull_connection == 0 || na->last_successfull_connection < nb->last_successfull_connection) {
return 1;
+ }
- if(na < nb)
+ if(na < nb) {
return -1;
+ }
- if(na > nb)
+ if(na > nb) {
return 1;
+ }
return 0;
}
static int node_compare_lsc_desc(const void *a, const void *b) {
const node_t *na = a, *nb = b;
- if(na->last_successfull_connection == nb->last_successfull_connection)
+ if(na->last_successfull_connection == nb->last_successfull_connection) {
return 0;
+ }
- if(na->last_successfull_connection == 0 || na->last_successfull_connection > nb->last_successfull_connection)
+ if(na->last_successfull_connection == 0 || na->last_successfull_connection > nb->last_successfull_connection) {
return -1;
+ }
- if(nb->last_successfull_connection == 0 || na->last_successfull_connection < nb->last_successfull_connection)
+ if(nb->last_successfull_connection == 0 || na->last_successfull_connection < nb->last_successfull_connection) {
return 1;
+ }
- if(na < nb)
+ if(na < nb) {
return -1;
+ }
- if(na > nb)
+ if(na > nb) {
return 1;
+ }
return 0;
}
static int node_compare_devclass_desc(const void *a, const void *b) {
const node_t *na = a, *nb = b;
- if(na->devclass < nb->devclass)
+ if(na->devclass < nb->devclass) {
return -1;
+ }
- if(na->devclass > nb->devclass)
+ if(na->devclass > nb->devclass) {
return 1;
+ }
- if(na < nb)
+ if(na < nb) {
return -1;
+ }
- if(na > nb)
+ if(na > nb) {
return 1;
+ }
return 0;
}
logger(mesh, MESHLINK_WARNING, "Possible node with same Name as us! Sleeping %d seconds.", mesh->sleeptime);
usleep(mesh->sleeptime * 1000000LL);
mesh->sleeptime *= 2;
- if(mesh->sleeptime < 0)
+
+ if(mesh->sleeptime < 0) {
mesh->sleeptime = 3600;
+ }
} else {
mesh->sleeptime /= 2;
- if(mesh->sleeptime < 10)
+
+ if(mesh->sleeptime < 10) {
mesh->sleeptime = 10;
+ }
}
mesh->contradicting_add_edge = 0;
unsigned int cur_connects = 0;
for list_each(connection_t, c, mesh->connections) {
- if(c->status.active)
+ if(c->status.active) {
cur_connects += 1;
+ }
}
logger(mesh, MESHLINK_DEBUG, "* cur_connects = %d", cur_connects);
for splay_each(node_t, n, mesh->nodes) {
logger(mesh, MESHLINK_DEBUG, "* n->devclass = %d", n->devclass);
- if(n != mesh->self && n->devclass <= mesh->devclass && !n->connection && (n->last_connect_try == 0 || (time(NULL) - n->last_connect_try) > retry_timeout))
+
+ if(n != mesh->self && n->devclass <= mesh->devclass && !n->connection && (n->last_connect_try == 0 || (time(NULL) - n->last_connect_try) > retry_timeout)) {
splay_insert(nodes, n);
+ }
}
if(nodes->head) {
//timeout = 0;
connect_to = (node_t *)nodes->head->data;
- } else
+ } else {
logger(mesh, MESHLINK_DEBUG, "* could not find node for initial connect");
+ }
splay_free_tree(nodes);
}
for(unsigned int devclass = 0; devclass <= mesh->devclass; ++devclass) {
for list_each(connection_t, c, mesh->connections) {
- if(c->status.active && c->node && c->node->devclass == devclass)
+ if(c->status.active && c->node && c->node->devclass == devclass) {
connects += 1;
+ }
}
if(connects < min_connects) {
splay_tree_t *nodes = splay_alloc_tree(node_compare_lsc_desc, NULL);
for splay_each(node_t, n, mesh->nodes) {
- if(n != mesh->self && n->devclass == devclass && !n->connection && (n->last_connect_try == 0 || (time(NULL) - n->last_connect_try) > retry_timeout))
+ if(n != mesh->self && n->devclass == devclass && !n->connection && (n->last_connect_try == 0 || (time(NULL) - n->last_connect_try) > retry_timeout)) {
splay_insert(nodes, n);
+ }
}
if(nodes->head) {
}
splay_free_tree(nodes);
- } else
+ } else {
break;
+ }
}
- if(!connect_to)
+ if(!connect_to) {
logger(mesh, MESHLINK_DEBUG, "* could not find better nodes");
+ }
}
splay_tree_t *nodes = splay_alloc_tree(node_compare_devclass_asc_lsc_desc, NULL);
for splay_each(node_t, n, mesh->nodes) {
- if(n != mesh->self && n->devclass <= mesh->devclass && !n->status.reachable && (n->last_connect_try == 0 || (time(NULL) - n->last_connect_try) > retry_timeout))
+ if(n != mesh->self && n->devclass <= mesh->devclass && !n->status.reachable && (n->last_connect_try == 0 || (time(NULL) - n->last_connect_try) > retry_timeout)) {
splay_insert(nodes, n);
+ }
}
if(nodes->head) {
logger(mesh, MESHLINK_DEBUG, "* try to heal partition");
connect_to = (node_t *)nodes->head->data;
- } else
+ } else {
logger(mesh, MESHLINK_DEBUG, "* could not find nodes for partition healing");
+ }
splay_free_tree(nodes);
}
/* check if there is already a connection attempt to this node */
bool found = false;
+
for list_each(outgoing_t, outgoing, mesh->outgoings) {
if(!strcmp(outgoing->name, connect_to->name)) {
found = true;
outgoing->name = xstrdup(connect_to->name);
list_insert_tail(mesh->outgoings, outgoing);
setup_outgoing_connection(mesh, outgoing);
- } else
+ } else {
logger(mesh, MESHLINK_DEBUG, "* skip autoconnect since it is an outgoing connection already");
+ }
}
for(unsigned int devclass = 0; devclass <= mesh->devclass; ++devclass) {
for list_each(connection_t, c, mesh->connections) {
- if(c->status.active && c->node && c->node->devclass == devclass)
+ if(c->status.active && c->node && c->node->devclass == devclass) {
connects += 1;
+ }
}
if(min_connects < connects) {
splay_tree_t *nodes = splay_alloc_tree(node_compare_devclass_desc, NULL);
for list_each(connection_t, c, mesh->connections) {
- if(c->outgoing && c->node && c->node->devclass >= devclass)
+ if(c->outgoing && c->node && c->node->devclass >= devclass) {
splay_insert(nodes, c->node);
+ }
}
if(nodes->head) {
}
}
- if(!disconnect_from)
+ if(!disconnect_from) {
logger(mesh, MESHLINK_DEBUG, "* no suboptimal outgoing connections");
+ }
}
splay_tree_t *nodes = splay_alloc_tree(node_compare_devclass_desc, NULL);
for list_each(connection_t, c, mesh->connections) {
- if(c->status.active && c->node)
+ if(c->status.active && c->node) {
splay_insert(nodes, c->node);
+ }
}
if(nodes->head) {
//timeout = 0;
disconnect_from = (node_t *)nodes->head->data;
- } else
+ } else {
logger(mesh, MESHLINK_DEBUG, "* no node we want to disconnect, even though we have too many connections");
+ }
splay_free_tree(nodes);
}
/* Reset the reconnection timers for all outgoing connections */
for list_each(outgoing_t, outgoing, mesh->outgoings) {
outgoing->timeout = 0;
+
if(outgoing->ev.cb)
timeout_set(&mesh->loop, &outgoing->ev, &(struct timeval) {
0, 0
/* Check for outgoing connections that are in progress, and reset their ping timers */
for list_each(connection_t, c, mesh->connections) {
- if(c->outgoing && !c->node)
+ if(c->outgoing && !c->node) {
c->last_ping_time = 0;
+ }
}
/* Kick the ping timeout handler */
}
if(n->mtuprobes == 30 || (n->mtuprobes < 30 && n->minmtu >= n->maxmtu)) {
- if(n->minmtu > n->maxmtu)
+ if(n->minmtu > n->maxmtu) {
n->minmtu = n->maxmtu;
- else
+ } else {
n->maxmtu = n->minmtu;
+ }
+
n->mtu = n->minmtu;
logger(mesh, MESHLINK_INFO, "Fixing MTU of %s to %d after %d probes", n->name, n->mtu, n->mtuprobes);
n->mtuprobes = 31;
if(n->mtuprobes == 31) {
timeout = mesh->pinginterval;
goto end;
- } else if(n->mtuprobes == 32)
+ } else if(n->mtuprobes == 32) {
timeout = mesh->pingtimeout;
+ }
for(int i = 0; i < 4 + mesh->localdiscovery; i++) {
int len;
if(i == 0) {
- if(n->mtuprobes < 30 || n->maxmtu + 8 >= MTU)
+ if(n->mtuprobes < 30 || n->maxmtu + 8 >= MTU) {
continue;
+ }
+
len = n->maxmtu + 8;
- } else if(n->maxmtu <= n->minmtu)
+ } else if(n->maxmtu <= n->minmtu) {
len = n->maxmtu;
- else
+ } else {
len = n->minmtu + 1 + rand() % (n->maxmtu - n->minmtu);
+ }
- if(len < 64)
+ if(len < 64) {
len = 64;
+ }
vpn_packet_t packet;
packet.probe = true;
return;
}
- if(n->minmtu)
+ if(n->minmtu) {
n->mtuprobes = 30;
- else
+ } else {
n->mtuprobes = 1;
+ }
}
/* If applicable, raise the minimum supported MTU */
- if(len > n->maxmtu)
+ if(len > n->maxmtu) {
len = n->maxmtu;
- if(n->minmtu < len)
+ }
+
+ if(n->minmtu < len) {
n->minmtu = len;
+ }
}
}
static void receive_packet(meshlink_handle_t *mesh, node_t *n, vpn_packet_t *packet) {
logger(mesh, MESHLINK_DEBUG, "Received packet of %d bytes from %s", packet->len, n->name);
- if(n->status.blacklisted)
+ if(n->status.blacklisted) {
logger(mesh, MESHLINK_WARNING, "Dropping packet from blacklisted node %s", n->name);
- else {
+ } else {
n->in_packets++;
n->in_bytes += packet->len;
if(!n->status.waitingforkey) {
logger(mesh, MESHLINK_DEBUG, "Got packet from %s but we haven't exchanged keys yet", n->name);
send_req_key(mesh, n);
- } else
+ } else {
logger(mesh, MESHLINK_DEBUG, "Got packet from %s but he hasn't got our key yet", n->name);
+ }
+
return;
}
+
sptps_receive_data(&n->sptps, inpkt->data, inpkt->len);
}
static void send_sptps_packet(meshlink_handle_t *mesh, node_t *n, vpn_packet_t *origpkt) {
if(!n->status.validkey) {
logger(mesh, MESHLINK_INFO, "No valid key known yet for %s", n->name);
- if(!n->status.waitingforkey)
+
+ if(!n->status.waitingforkey) {
send_req_key(mesh, n);
- else if(n->last_req_key + 10 < mesh->loop.now.tv_sec) {
+ } else if(n->last_req_key + 10 < mesh->loop.now.tv_sec) {
logger(mesh, MESHLINK_DEBUG, "No key from %s after 10 seconds, restarting SPTPS", n->name);
sptps_stop(&n->sptps);
n->status.waitingforkey = false;
send_req_key(mesh, n);
}
+
return;
}
*sock = n->sock;
/* If the UDP address is confirmed, use it. */
- if(n->status.udp_confirmed)
+ if(n->status.udp_confirmed) {
return;
+ }
/* Send every third packet to n->address; that could be set
to the node's reflexive UDP address discovered during key
exchange. */
static int x = 0;
+
if(++x >= 3) {
x = 0;
return;
if(type >= SPTPS_HANDSHAKE || ((mesh->self->options | to->options) & OPTION_TCPONLY) || (type != PKT_PROBE && len > to->minmtu)) {
char buf[len * 4 / 3 + 5];
b64encode(data, buf, len);
+
/* If no valid key is known yet, send the packets using ANS_KEY requests,
to ensure we get to learn the reflexive UDP address. */
if(!to->status.validkey) {
to->incompression = mesh->self->incompression;
return send_request(mesh, to->nexthop->connection, "%d %s %s %s -1 -1 -1 %d", ANS_KEY, mesh->self->name, to->name, buf, to->incompression);
- } else
+ } else {
return send_request(mesh, to->nexthop->connection, "%d %s %s %d %s", REQ_KEY, mesh->self->name, to->name, REQ_SPTPS, buf);
+ }
}
/* Otherwise, send the packet via UDP */
const sockaddr_t *sa;
int sock;
- if(to->status.broadcast)
+ if(to->status.broadcast) {
choose_broadcast_address(mesh, to, &sa, &sock);
- else
+ } else {
choose_udp_address(mesh, to, &sa, &sock);
+ }
if(sendto(mesh->listen_socket[sock].udp.fd, data, len, 0, &sa->sa, SALEN(sa->sa)) < 0 && !sockwouldblock(sockerrno)) {
if(sockmsgsize(sockerrno)) {
- if(to->maxmtu >= len)
+ if(to->maxmtu >= len) {
to->maxmtu = len - 1;
- if(to->mtu >= len)
+ }
+
+ if(to->mtu >= len) {
to->mtu = len - 1;
+ }
} else {
logger(mesh, MESHLINK_WARNING, "Error sending UDP SPTPS packet to %s: %s", to->name, sockstrerror(sockerrno));
return false;
logger(mesh, MESHLINK_INFO, "SPTPS key exchange with %s succesful", from->name);
from->status.validkey = true;
from->status.waitingforkey = false;
- if(from->utcp)
+
+ if(from->utcp) {
utcp_reset_timers(from->utcp);
+ }
}
+
return true;
}
memcpy(inpkt.data, data, len);
mtu_probe_h(mesh, from, &inpkt, len);
return true;
- } else
+ } else {
inpkt.probe = false;
+ }
if(type & ~(PKT_COMPRESSED)) {
logger(mesh, MESHLINK_ERROR, "Unexpected SPTPS record type %d len %d from %s", type, len, from->name);
void broadcast_packet(meshlink_handle_t *mesh, const node_t *from, vpn_packet_t *packet) {
// Always give ourself a copy of the packet.
- if(from != mesh->self)
+ if(from != mesh->self) {
send_packet(mesh, mesh->self, packet);
+ }
logger(mesh, MESHLINK_INFO, "Broadcasting packet of %d bytes from %s", packet->len, from->name);
for list_each(connection_t, c, mesh->connections)
- if(c->status.active && c->status.mst && c != from->nexthop->connection)
+ if(c->status.active && c->status.mst && c != from->nexthop->connection) {
send_packet(mesh, c->node, packet);
+ }
}
static node_t *try_harder(meshlink_handle_t *mesh, const sockaddr_t *from, const vpn_packet_t *pkt) {
static time_t last_hard_try = 0;
for splay_each(edge_t, e, mesh->edges) {
- if(!e->to->status.reachable || e->to == mesh->self)
+ if(!e->to->status.reachable || e->to == mesh->self) {
continue;
+ }
if(sockaddrcmp_noport(from, &e->address)) {
- if(last_hard_try == mesh->loop.now.tv_sec)
+ if(last_hard_try == mesh->loop.now.tv_sec) {
continue;
+ }
+
hard = true;
}
- if(!try_mac(mesh, e->to, pkt))
+ if(!try_mac(mesh, e->to, pkt)) {
continue;
+ }
n = e->to;
break;
}
- if(hard)
+ if(hard) {
last_hard_try = mesh->loop.now.tv_sec;
+ }
last_hard_try = mesh->loop.now.tv_sec;
return n;
len = recvfrom(ls->udp.fd, pkt.data, MAXSIZE, 0, &from.sa, &fromlen);
if(len <= 0 || len > MAXSIZE) {
- if(!sockwouldblock(sockerrno))
+ if(!sockwouldblock(sockerrno)) {
logger(mesh, MESHLINK_ERROR, "Receiving packet failed: %s", sockstrerror(sockerrno));
+ }
+
return;
}
if(!n) {
n = try_harder(mesh, &from, &pkt);
- if(n)
+
+ if(n) {
update_node_udp(mesh, n, &from);
- else if(mesh->log_level >= MESHLINK_WARNING) {
+ } else if(mesh->log_level >= MESHLINK_WARNING) {
hostname = sockaddr2hostname(&from);
logger(mesh, MESHLINK_WARNING, "Received UDP packet from unknown source %s", hostname);
free(hostname);
return;
- } else
+ } else {
return;
+ }
}
if(n->status.blacklisted) {
logger(mesh, MESHLINK_WARNING, "Dropping packet from blacklisted node %s", n->name);
return;
}
+
n->sock = ls - mesh->listen_socket;
receive_udppacket(mesh, n, &pkt);
#include "xalloc.h"
bool node_read_ecdsa_public_key(meshlink_handle_t *mesh, node_t *n) {
- if(ecdsa_active(n->ecdsa))
+ if(ecdsa_active(n->ecdsa)) {
return true;
+ }
splay_tree_t *config_tree;
char *p;
init_configuration(&config_tree);
- if(!read_host_config(mesh, config_tree, n->name))
+
+ if(!read_host_config(mesh, config_tree, n->name)) {
goto exit;
+ }
/* First, check for simple ECDSAPublicKey statement */
}
bool read_ecdsa_public_key(meshlink_handle_t *mesh, connection_t *c) {
- if(ecdsa_active(c->ecdsa))
+ if(ecdsa_active(c->ecdsa)) {
return true;
+ }
char *p;
if(!c->config_tree) {
init_configuration(&c->config_tree);
- if(!read_host_config(mesh, c->config_tree, c->name))
+
+ if(!read_host_config(mesh, c->config_tree, c->name)) {
return false;
+ }
}
/* First, check for simple ECDSAPublicKey statement */
mesh->self->connection->ecdsa = ecdsa_read_pem_private_key(fp);
fclose(fp);
- if(!mesh->self->connection->ecdsa)
+ if(!mesh->self->connection->ecdsa) {
logger(mesh, MESHLINK_ERROR, "Reading ECDSA private key file failed: %s", strerror(errno));
+ }
return mesh->self->connection->ecdsa;
}
if(fp) {
mesh->invitation_key = ecdsa_read_pem_private_key(fp);
fclose(fp);
- if(!mesh->invitation_key)
+
+ if(!mesh->invitation_key) {
logger(mesh, MESHLINK_ERROR, "Reading ECDSA private key file `%s' failed: %s", filename, strerror(errno));
+ }
}
return mesh->invitation_key;
char *p;
init_configuration(&config_tree);
- if(!read_host_config(mesh, config_tree, n->name))
+
+ if(!read_host_config(mesh, config_tree, n->name)) {
goto exit;
+ }
if(get_config_string(lookup_config(config_tree, "DeviceClass"), &p)) {
n->devclass = atoi(p);
free(p);
}
- if((int)n->devclass < 0 || n->devclass > _DEV_CLASS_MAX)
+ if((int)n->devclass < 0 || n->devclass > _DEV_CLASS_MAX) {
n->devclass = _DEV_CLASS_MAX;
+ }
exit:
exit_configuration(&config_tree);
bool node_write_devclass(meshlink_handle_t *mesh, node_t *n) {
- if((int)n->devclass < 0 || n->devclass > _DEV_CLASS_MAX)
+ if((int)n->devclass < 0 || n->devclass > _DEV_CLASS_MAX) {
return false;
+ }
bool result = false;
set_config_int(cnf, n->devclass);
- if(!write_host_config(mesh, config_tree, n->name))
+ if(!write_host_config(mesh, config_tree, n->name)) {
goto fail;
+ }
result = true;
snprintf(dname, PATH_MAX, "%s" SLASH "hosts", mesh->confbase);
dir = opendir(dname);
+
if(!dir) {
logger(mesh, MESHLINK_ERROR, "Could not open %s: %s", dname, strerror(errno));
return;
}
while((ent = readdir(dir))) {
- if(!check_id(ent->d_name))
+ if(!check_id(ent->d_name)) {
continue;
+ }
node_t *n = lookup_node(mesh, ent->d_name);
- if(n)
+
+ if(n) {
continue;
+ }
n = new_node();
n->name = xstrdup(ent->d_name);
get_config_string(lookup_config(mesh->config, "Name"), &name);
- if(!name)
+ if(!name) {
return NULL;
+ }
if(!check_id(name)) {
logger(mesh, MESHLINK_ERROR, "Invalid name for mesh->self!");
if(address) {
char *space = strchr(address, ' ');
+
if(space) {
*space++ = 0;
port = space;
}
- if(!strcmp(address, "*"))
+ if(!strcmp(address, "*")) {
*address = 0;
+ }
}
struct addrinfo *ai, hint = {};
+
hint.ai_family = addressfamily;
+
hint.ai_socktype = SOCK_STREAM;
+
hint.ai_protocol = IPPROTO_TCP;
+
hint.ai_flags = AI_PASSIVE;
int err = getaddrinfo(address && *address ? address : NULL, port, &hint, &ai);
+
free(address);
if(err || !ai) {
break;
}
- if(found)
+ if(found) {
continue;
+ }
if(mesh->listen_sockets >= MAXSOCKETS) {
logger(mesh, MESHLINK_ERROR, "Too many listening sockets");
int tcp_fd = setup_listen_socket((sockaddr_t *) aip->ai_addr);
- if(tcp_fd < 0)
+ if(tcp_fd < 0) {
continue;
+ }
int udp_fd = setup_vpn_in_socket(mesh, (sockaddr_t *) aip->ai_addr);
mesh->self->options |= PROT_MINOR << 24;
- if(!read_ecdsa_private_key(mesh))
+ if(!read_ecdsa_private_key(mesh)) {
return false;
+ }
/* Ensure mesh->myport is numeric */
if(!atoi(mesh->myport)) {
struct addrinfo *ai = str2addrinfo("localhost", mesh->myport, SOCK_DGRAM);
sockaddr_t sa;
- if(!ai || !ai->ai_addr)
+
+ if(!ai || !ai->ai_addr) {
return false;
+ }
+
free(mesh->myport);
memcpy(&sa, ai->ai_addr, ai->ai_addrlen);
sockaddr2str(&sa, NULL, &mesh->myport);
/* Check some options */
- if(!setup_myself_reloadable(mesh))
+ if(!setup_myself_reloadable(mesh)) {
return false;
+ }
/* Compression */
logger(mesh, MESHLINK_INFO, "Could not bind to port %s, asking OS to choose one for us", mesh->myport);
free(mesh->myport);
mesh->myport = strdup("0");
- if(!mesh->myport)
+
+ if(!mesh->myport) {
return false;
- if(!add_listen_address(mesh, address, NULL))
+ }
+
+ if(!add_listen_address(mesh, address, NULL)) {
return false;
- } else
+ }
+ } else {
return false;
+ }
}
if(!mesh->listen_sockets) {
mesh->pingtimeout = 5;
maxoutbufsize = 10 * MTU;
- if(!setup_myself(mesh))
+ if(!setup_myself(mesh)) {
return false;
+ }
return true;
}
}
}
- if(mesh->outgoings)
+ if(mesh->outgoings) {
list_delete_list(mesh->outgoings);
+ }
if(mesh->self && mesh->self->connection) {
terminate_connection(mesh, mesh->self->connection, false);
exit_nodes(mesh);
exit_connections(mesh);
- if(mesh->myport) free(mesh->myport);
+ if(mesh->myport) {
+ free(mesh->myport);
+ }
return;
}
#ifdef O_NONBLOCK
int flags = fcntl(c->socket, F_GETFL);
- if(fcntl(c->socket, F_SETFL, flags | O_NONBLOCK) < 0)
+ if(fcntl(c->socket, F_SETFL, flags | O_NONBLOCK) < 0) {
logger(c->mesh, MESHLINK_ERROR, "System call `%s' failed: %s", "fcntl", strerror(errno));
+ }
+
#elif defined(WIN32)
unsigned long arg = 1;
- if(ioctlsocket(c->socket, FIONBIO, &arg) != 0)
+ if(ioctlsocket(c->socket, FIONBIO, &arg) != 0) {
logger(c->mesh, MESHLINK_ERROR, "System call `%s' failed: %s", "ioctlsocket", sockstrerror(sockerrno));
+ }
+
#endif
#if defined(SOL_TCP) && defined(TCP_NODELAY)
int s = -1;
for(int i = 0; i < mesh->listen_sockets && mesh->listen_socket[i].bindto; i++) {
- if(mesh->listen_socket[i].sa.sa.sa_family != c->address.sa.sa_family)
+ if(mesh->listen_socket[i].sa.sa.sa_family != c->address.sa.sa_family) {
continue;
- if(s >= 0)
+ }
+
+ if(s >= 0) {
return false;
+ }
+
s = i;
}
- if(s < 0)
+ if(s < 0) {
return false;
+ }
sockaddr_t sa = mesh->listen_socket[s].sa;
- if(sa.sa.sa_family == AF_INET)
+
+ if(sa.sa.sa_family == AF_INET) {
sa.in.sin_port = 0;
- else if(sa.sa.sa_family == AF_INET6)
+ } else if(sa.sa.sa_family == AF_INET6) {
sa.in6.sin6_port = 0;
+ }
if(bind(c->socket, &sa.sa, SALEN(sa.sa))) {
logger(mesh, MESHLINK_WARNING, "Can't bind outgoing socket: %s", strerror(errno));
setsockopt(nfd, SOL_SOCKET, SO_REUSEADDR, (void *)&option, sizeof(option));
#if defined(SOL_IPV6) && defined(IPV6_V6ONLY)
- if(sa->sa.sa_family == AF_INET6)
+
+ if(sa->sa.sa_family == AF_INET6) {
setsockopt(nfd, SOL_IPV6, IPV6_V6ONLY, (void *)&option, sizeof(option));
+ }
+
#endif
if(bind(nfd, &sa->sa, SALEN(sa->sa))) {
#elif defined(WIN32)
{
unsigned long arg = 1;
+
if(ioctlsocket(nfd, FIONBIO, &arg) != 0) {
closesocket(nfd);
logger(mesh, MESHLINK_ERROR, "Call to `%s' failed: %s", "ioctlsocket", sockstrerror(sockerrno));
setsockopt(nfd, SOL_SOCKET, SO_BROADCAST, (void *)&option, sizeof(option));
#if defined(IPPROTO_IPV6) && defined(IPV6_V6ONLY)
- if(sa->sa.sa_family == AF_INET6)
+
+ if(sa->sa.sa_family == AF_INET6) {
setsockopt(nfd, IPPROTO_IPV6, IPV6_V6ONLY, (void *)&option, sizeof(option));
+ }
+
#endif
#if defined(IP_DONTFRAG) && !defined(IP_DONTFRAGMENT)
#endif
#if defined(SOL_IP) && defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DO)
+
if(mesh->self->options & OPTION_PMTU_DISCOVERY) {
option = IP_PMTUDISC_DO;
setsockopt(nfd, SOL_IP, IP_MTU_DISCOVER, (void *)&option, sizeof(option));
}
+
#elif defined(IPPROTO_IP) && defined(IP_DONTFRAGMENT)
+
if(mesh->self->options & OPTION_PMTU_DISCOVERY) {
option = 1;
setsockopt(nfd, IPPROTO_IP, IP_DONTFRAGMENT, (void *)&option, sizeof(option));
}
+
#else
#warning No way to disable IPv4 fragmentation
#endif
#if defined(SOL_IPV6) && defined(IPV6_MTU_DISCOVER) && defined(IPV6_PMTUDISC_DO)
+
if(mesh->self->options & OPTION_PMTU_DISCOVERY) {
option = IPV6_PMTUDISC_DO;
setsockopt(nfd, SOL_IPV6, IPV6_MTU_DISCOVER, (void *)&option, sizeof(option));
}
+
#elif defined(IPPROTO_IPV6) && defined(IPV6_DONTFRAG)
+
if(mesh->self->options & OPTION_PMTU_DISCOVERY) {
option = 1;
setsockopt(nfd, IPPROTO_IPV6, IPV6_DONTFRAG, (void *)&option, sizeof(option));
}
+
#else
#warning No way to disable IPv6 fragmentation
#endif
void retry_outgoing(meshlink_handle_t *mesh, outgoing_t *outgoing) {
outgoing->timeout += 5;
- if(outgoing->timeout > mesh->maxtimeout)
+ if(outgoing->timeout > mesh->maxtimeout) {
outgoing->timeout = mesh->maxtimeout;
+ }
timeout_add(&mesh->loop, &outgoing->ev, retry_outgoing_handler, outgoing, &(struct timeval) {
outgoing->timeout, rand() % 100000
setenv("NAME", mesh->self->name, true);
int result = system(command);
- if(result < 0)
+
+ if(result < 0) {
logger(mesh, MESHLINK_ERROR, "Could not execute %s: %s", command, strerror(errno));
- else if(result)
+ } else if(result) {
logger(mesh, MESHLINK_ERROR, "%s exited with non-zero status %d", command, result);
+ }
+
exit(result);
#else
logger(mesh, MESHLINK_ERROR, "Proxy type exec not supported on this platform!");
}
static void handle_meta_write(meshlink_handle_t *mesh, connection_t *c) {
- if(c->outbuf.len <= c->outbuf.offset)
+ if(c->outbuf.len <= c->outbuf.offset) {
return;
+ }
ssize_t outlen = send(c->socket, c->outbuf.data + c->outbuf.offset, c->outbuf.len - c->outbuf.offset, MSG_NOSIGNAL);
+
if(outlen <= 0) {
if(!errno || errno == EPIPE) {
logger(mesh, MESHLINK_INFO, "Connection closed by %s", c->name);
}
buffer_read(&c->outbuf, outlen);
- if(!c->outbuf.len)
+
+ if(!c->outbuf.len) {
io_set(&mesh->loop, &c->io, IO_READ);
+ }
}
static void handle_meta_io(event_loop_t *loop, void *data, int flags) {
socklen_t len = sizeof(result);
getsockopt(c->socket, SOL_SOCKET, SO_ERROR, (void *)&result, &len);
- if(!result)
+ if(!result) {
finish_connecting(mesh, c);
- else {
+ } else {
logger(mesh, MESHLINK_DEBUG, "Error while connecting to %s: %s", c->name, sockstrerror(result));
terminate_connection(mesh, c, false);
return;
}
}
- if(flags & IO_WRITE)
+ if(flags & IO_WRITE) {
handle_meta_write(mesh, c);
- else
+ } else {
handle_meta_connection_data(mesh, c);
+ }
}
// Find edges pointing to this node, and use them to build a list of unique, known addresses.
struct addrinfo *ai = NULL;
for splay_each(edge_t, e, n->edge_tree) {
- if(!e->reverse)
+ if(!e->reverse) {
continue;
+ }
bool found = false;
+
for(struct addrinfo *aip = ai; aip; aip = aip->ai_next) {
if(!sockaddrcmp(&e->reverse->address, (sockaddr_t *)aip->ai_addr)) {
found = true;
break;
}
}
- if(found)
+
+ if(found) {
continue;
+ }
// Create a new struct addrinfo, and put it at the head of the list.
struct addrinfo *nai = xzalloc(sizeof(*nai) + SALEN(e->reverse->address.sa));
int result;
begin:
+
if(!outgoing->ai && !outgoing->nai) {
if(!outgoing->cfg) {
logger(mesh, MESHLINK_ERROR, "Could not set up a meta connection to %s", outgoing->name);
get_config_string(outgoing->cfg, &address);
space = strchr(address, ' ');
+
if(space) {
port = xstrdup(space + 1);
*space = 0;
}
if(!outgoing->aip) {
- if(outgoing->ai)
+ if(outgoing->ai) {
freeaddrinfo(outgoing->ai);
+ }
+
outgoing->ai = NULL;
- if(outgoing->nai)
+ if(outgoing->nai) {
free_known_addresses(outgoing->nai);
+ }
+
outgoing->nai = NULL;
goto begin;
if(!mesh->proxytype) {
c->socket = socket(c->address.sa.sa_family, SOCK_STREAM, IPPROTO_TCP);
configure_tcp(c);
- } else if(mesh->proxytype == PROXY_EXEC)
+ } else if(mesh->proxytype == PROXY_EXEC) {
do_outgoing_pipe(mesh, c, mesh->proxyhost);
- else {
+ } else {
proxyai = str2addrinfo(mesh->proxyhost, mesh->proxyport, SOCK_STREAM);
+
if(!proxyai) {
free_connection(c);
free(hostname);
goto begin;
}
+
logger(mesh, MESHLINK_INFO, "Using proxy at %s port %s", mesh->proxyhost, mesh->proxyport);
c->socket = socket(proxyai->ai_family, SOCK_STREAM, IPPROTO_TCP);
configure_tcp(c);
if(mesh->proxytype != PROXY_EXEC) {
#if defined(SOL_IPV6) && defined(IPV6_V6ONLY)
int option = 1;
- if(c->address.sa.sa_family == AF_INET6)
+
+ if(c->address.sa.sa_family == AF_INET6) {
setsockopt(c->socket, SOL_IPV6, IPV6_V6ONLY, (void *)&option, sizeof(option));
+ }
+
#endif
bind_to_address(mesh, c);
/* Connect */
- if(!mesh->proxytype)
+ if(!mesh->proxytype) {
result = connect(c->socket, &c->address.sa, SALEN(c->address.sa));
- else if(mesh->proxytype == PROXY_EXEC)
+ } else if(mesh->proxytype == PROXY_EXEC) {
result = 0;
- else {
+ } else {
result = connect(c->socket, proxyai->ai_addr, proxyai->ai_addrlen);
freeaddrinfo(proxyai);
}
outgoing->cfg = lookup_config(outgoing->config_tree, "Address");
get_config_bool(lookup_config(outgoing->config_tree, "blacklisted"), &blacklisted);
- if(blacklisted) return;
+
+ if(blacklisted) {
+ return;
+ }
if(!outgoing->cfg) {
- if(n)
+ if(n) {
outgoing->aip = outgoing->nai = get_known_addresses(n);
+ }
+
if(!outgoing->nai) {
logger(mesh, MESHLINK_ERROR, "No address known for %s", outgoing->name);
return;
static int samehost_burst;
static int samehost_burst_time;
- if(mesh->loop.now.tv_sec - samehost_burst_time > samehost_burst)
+ if(mesh->loop.now.tv_sec - samehost_burst_time > samehost_burst) {
samehost_burst = 0;
- else
+ } else {
samehost_burst -= mesh->loop.now.tv_sec - samehost_burst_time;
+ }
samehost_burst_time = mesh->loop.now.tv_sec;
samehost_burst++;
static int connection_burst;
static int connection_burst_time;
- if(mesh->loop.now.tv_sec - connection_burst_time > connection_burst)
+ if(mesh->loop.now.tv_sec - connection_burst_time > connection_burst) {
connection_burst = 0;
- else
+ } else {
connection_burst -= mesh->loop.now.tv_sec - connection_burst_time;
+ }
connection_burst_time = mesh->loop.now.tv_sec;
connection_burst++;
timeout_del(&mesh->loop, &outgoing->ev);
- if(outgoing->ai)
+ if(outgoing->ai) {
freeaddrinfo(outgoing->ai);
+ }
- if(outgoing->nai)
+ if(outgoing->nai) {
free_known_addresses(outgoing->nai);
+ }
- if(outgoing->config_tree)
+ if(outgoing->config_tree) {
exit_configuration(&outgoing->config_tree);
+ }
- if(outgoing->name)
+ if(outgoing->name) {
free(outgoing->name);
+ }
free(outgoing);
}
void try_outgoing_connections(meshlink_handle_t *mesh) {
/* If there is no outgoing list yet, create one. Otherwise, mark all outgoings as deleted. */
- if(!mesh->outgoings)
+ if(!mesh->outgoings) {
mesh->outgoings = list_alloc((list_action_t)free_outgoing);
- else {
- for list_each(outgoing_t, outgoing, mesh->outgoings)
+ } else {
+ for list_each(outgoing_t, outgoing, mesh->outgoings) {
outgoing->timeout = -1;
+ }
}
/* Make sure there is one outgoing_t in the list for each ConnectTo. */
/* Delete outgoing_ts for which there is no ConnectTo. */
for list_each(outgoing_t, outgoing, mesh->outgoings)
- if(outgoing->timeout == -1)
+ if(outgoing->timeout == -1) {
list_delete_node(mesh->outgoings, node);
+ }
}
int err;
if(sa->sa.sa_family == AF_UNKNOWN) {
- if(addrstr)
+ if(addrstr) {
*addrstr = xstrdup(sa->unknown.address);
- if(portstr)
+ }
+
+ if(portstr) {
*portstr = xstrdup(sa->unknown.port);
+ }
+
return;
}
scopeid = strchr(address, '%');
- if(scopeid)
- *scopeid = '\0'; /* Descope. */
+ if(scopeid) {
+ *scopeid = '\0'; /* Descope. */
+ }
- if(addrstr)
+ if(addrstr) {
*addrstr = xstrdup(address);
- if(portstr)
+ }
+
+ if(portstr) {
*portstr = xstrdup(port);
+ }
}
char *sockaddr2hostname(const sockaddr_t *sa) {
err = getnameinfo(&sa->sa, SALEN(sa->sa), address, sizeof(address), port, sizeof(port),
hostnames ? 0 : (NI_NUMERICHOST | NI_NUMERICSERV));
- if(err)
+
+ if(err) {
logger(NULL, MESHLINK_ERROR, "Error while looking up hostname: %s", err == EAI_SYSTEM ? strerror(errno) : gai_strerror(err));
+ }
xasprintf(&str, "%s port %s", address, port);
result = a->sa.sa_family - b->sa.sa_family;
- if(result)
+ if(result) {
return result;
+ }
switch(a->sa.sa_family) {
case AF_UNSPEC:
result = a->sa.sa_family - b->sa.sa_family;
- if(result)
+ if(result) {
return result;
+ }
switch(a->sa.sa_family) {
case AF_UNSPEC:
case AF_UNKNOWN:
result = strcmp(a->unknown.address, b->unknown.address);
- if(result)
+ if(result) {
return result;
+ }
return strcmp(a->unknown.port, b->unknown.port);
case AF_INET:
result = memcmp(&a->in.sin_addr, &b->in.sin_addr, sizeof(a)->in.sin_addr);
- if(result)
+ if(result) {
return result;
+ }
return memcmp(&a->in.sin_port, &b->in.sin_port, sizeof(a)->in.sin_port);
case AF_INET6:
result = memcmp(&a->in6.sin6_addr, &b->in6.sin6_addr, sizeof(a)->in6.sin6_addr);
- if(result)
+ if(result) {
return result;
+ }
return memcmp(&a->in6.sin6_port, &b->in6.sin6_port, sizeof(a)->in6.sin6_port);
}
void sockaddrcpy(sockaddr_t *a, const sockaddr_t *b) {
- if(b->sa.sa_family != AF_UNKNOWN)
+ if(b->sa.sa_family != AF_UNKNOWN) {
*a = *b;
- else {
+ } else {
a->unknown.family = AF_UNKNOWN;
a->unknown.address = xstrdup(b->unknown.address);
a->unknown.port = xstrdup(b->unknown.port);
}
void exit_nodes(meshlink_handle_t *mesh) {
- if(mesh->node_udp_cache)
+ if(mesh->node_udp_cache) {
hash_free(mesh->node_udp_cache);
- if(mesh->nodes)
+ }
+
+ if(mesh->nodes) {
splay_delete_tree(mesh->nodes);
+ }
+
mesh->node_udp_cache = NULL;
mesh->nodes = NULL;
}
void free_node(node_t *n) {
n->status.destroyed = true;
- if(n->edge_tree)
+ if(n->edge_tree) {
free_edge_tree(n->edge_tree);
+ }
sockaddrfree(&n->address);
ecdsa_free(n->ecdsa);
sptps_stop(&n->sptps);
- if(n->mtutimeout.cb)
+ if(n->mtutimeout.cb) {
abort();
+ }
free(n->name);
void node_del(meshlink_handle_t *mesh, node_t *n) {
timeout_del(&mesh->loop, &n->mtutimeout);
- for splay_each(edge_t, e, n->edge_tree)
+ for splay_each(edge_t, e, n->edge_tree) {
edge_del(mesh, e);
+ }
splay_delete(mesh->nodes, n);
}
if(sa) {
n->address = *sa;
n->sock = 0;
+
for(int i = 0; i < mesh->listen_sockets; i++) {
if(mesh->listen_socket[i].sa.sa.sa_family == sa->sa.sa_family) {
n->sock = i;
#include "ed25519/sha512.h"
static void memxor(char *buf, char c, size_t len) {
- for(size_t i = 0; i < len; i++)
+ for(size_t i = 0; i < len; i++) {
buf[i] ^= c;
+ }
}
static const size_t mdlen = 64;
memcpy(tmp, key, keylen);
memset(tmp + keylen, 0, mdlen - keylen);
} else {
- if(sha512(key, keylen, tmp) != 0)
+ if(sha512(key, keylen, tmp) != 0) {
return false;
+ }
}
- if(sha512_init(&md) != 0)
+ if(sha512_init(&md) != 0) {
return false;
+ }
// ipad
memxor(tmp, 0x36, mdlen);
- if(sha512_update(&md, tmp, mdlen) != 0)
+
+ if(sha512_update(&md, tmp, mdlen) != 0) {
return false;
+ }
// message
- if(sha512_update(&md, msg, msglen) != 0)
+ if(sha512_update(&md, msg, msglen) != 0) {
return false;
+ }
- if(sha512_final(&md, tmp + mdlen) != 0)
+ if(sha512_final(&md, tmp + mdlen) != 0) {
return false;
+ }
// opad
memxor(tmp, 0x36 ^ 0x5c, mdlen);
- if(sha512(tmp, sizeof(tmp), out) != 0)
+
+ if(sha512(tmp, sizeof(tmp), out) != 0) {
return false;
+ }
return true;
}
while(outlen > 0) {
/* Inner HMAC */
- if(!hmac_sha512(data, sizeof(data), secret, secretlen, data))
+ if(!hmac_sha512(data, sizeof(data), secret, secretlen, data)) {
return false;
+ }
/* Outer HMAC */
if(outlen >= mdlen) {
- if(!hmac_sha512(data, sizeof(data), secret, secretlen, out))
+ if(!hmac_sha512(data, sizeof(data), secret, secretlen, out)) {
return false;
+ }
+
out += mdlen;
outlen -= mdlen;
} else {
- if(!hmac_sha512(data, sizeof(data), secret, secretlen, hash))
+ if(!hmac_sha512(data, sizeof(data), secret, secretlen, hash)) {
return false;
+ }
+
memcpy(out, hash, outlen);
out += outlen;
outlen = 0;
};
bool check_id(const char *id) {
- if(!id || !*id)
+ if(!id || !*id) {
return false;
+ }
for(; *id; id++)
- if(!isalnum(*id) && *id != '_' && *id != '-')
+ if(!isalnum(*id) && *id != '_' && *id != '-') {
return false;
+ }
return true;
}
if(c == mesh->everyone) {
broadcast_meta(mesh, NULL, request, len);
return true;
- } else
+ } else {
return send_meta(mesh, c, request, len);
+ }
}
void forward_request(meshlink_handle_t *mesh, connection_t *from, const char *request) {
bool receive_request(meshlink_handle_t *mesh, connection_t *c, const char *request) {
if(c->outgoing && mesh->proxytype == PROXY_HTTP && c->allow_request == ID) {
- if(!request[0] || request[0] == '\r')
+ if(!request[0] || request[0] == '\r') {
return true;
+ }
+
if(!strncasecmp(request, "HTTP/1.1 ", 9)) {
if(!strncmp(request + 9, "200", 3)) {
logger(mesh, MESHLINK_DEBUG, "Proxy request granted");
if((reqno < 0) || (reqno >= LAST) || !request_handlers[reqno]) {
logger(mesh, MESHLINK_DEBUG, "Unknown request from %s: %s", c->name, request);
return false;
- } else
+ } else {
logger(mesh, MESHLINK_DEBUG, "Got %s from %s: %s", request_name[reqno], c->name, request);
+ }
if((c->allow_request != ALL) && (c->allow_request != reqno)) {
logger(mesh, MESHLINK_ERROR, "Unauthorized request from %s", c->name);
}
static void free_past_request(past_request_t *r) {
- if(r->request)
+ if(r->request) {
free((void *)r->request);
+ }
free(r);
}
int left = 0, deleted = 0;
for splay_each(past_request_t, p, mesh->past_request_tree) {
- if(p->firstseen + mesh->pinginterval <= mesh->loop.now.tv_sec)
+ if(p->firstseen + mesh->pinginterval <= mesh->loop.now.tv_sec) {
splay_delete_node(mesh->past_request_tree, node), deleted++;
- else
+ } else {
left++;
+ }
}
- if(left || deleted)
+ if(left || deleted) {
logger(mesh, MESHLINK_DEBUG, "Aging past requests: deleted %d, left %d", deleted, left);
+ }
if(left)
timeout_set(&mesh->loop, &mesh->past_request_timeout, &(struct timeval) {
}
void exit_requests(meshlink_handle_t *mesh) {
- if(mesh->past_request_tree)
+ if(mesh->past_request_tree) {
splay_delete_tree(mesh->past_request_tree);
+ }
+
mesh->past_request_tree = NULL;
timeout_del(&mesh->loop, &mesh->past_request_timeout);
free(port);
return true;
}
+
case PROXY_SOCKS4: {
if(c->address.sa.sa_family != AF_INET) {
logger(mesh, MESHLINK_ERROR, "Cannot connect to an IPv6 host through a SOCKS 4 proxy!");
return false;
}
+
char s4req[9 + (mesh->proxyuser ? strlen(mesh->proxyuser) : 0)];
s4req[0] = 4;
s4req[1] = 1;
memcpy(s4req + 2, &c->address.in.sin_port, 2);
memcpy(s4req + 4, &c->address.in.sin_addr, 4);
- if(mesh->proxyuser)
+
+ if(mesh->proxyuser) {
memcpy(s4req + 8, mesh->proxyuser, strlen(mesh->proxyuser));
+ }
+
s4req[sizeof(s4req) - 1] = 0;
c->tcplen = 8;
return send_meta(mesh, c, s4req, sizeof(s4req));
}
+
case PROXY_SOCKS5: {
int len = 3 + 6 + (c->address.sa.sa_family == AF_INET ? 4 : 16);
c->tcplen = 2;
- if(mesh->proxypass)
+
+ if(mesh->proxypass) {
len += 3 + strlen(mesh->proxyuser) + strlen(mesh->proxypass);
+ }
+
char s5req[len];
int i = 0;
s5req[i++] = 5;
s5req[i++] = 1;
+
if(mesh->proxypass) {
s5req[i++] = 2;
s5req[i++] = 1;
memcpy(s5req + i, mesh->proxypass, strlen(mesh->proxypass));
i += strlen(mesh->proxypass);
c->tcplen += 2;
- } else
+ } else {
s5req[i++] = 0;
+ }
+
s5req[i++] = 5;
s5req[i++] = 1;
s5req[i++] = 0;
+
if(c->address.sa.sa_family == AF_INET) {
s5req[i++] = 1;
memcpy(s5req + i, &c->address.in.sin_addr, 4);
logger(mesh, MESHLINK_ERROR, "Address family %hx not supported for SOCKS 5 proxies!", c->address.sa.sa_family);
return false;
}
- if(i > len)
+
+ if(i > len) {
abort();
+ }
+
return send_meta(mesh, c, s5req, sizeof(s5req));
}
+
case PROXY_SOCKS4A:
logger(mesh, MESHLINK_ERROR, "Proxy type not implemented yet");
return false;
+
case PROXY_EXEC:
return true;
+
default:
logger(mesh, MESHLINK_ERROR, "Unknown proxy type");
return false;
int minor = mesh->self->connection->protocol_minor;
if(mesh->proxytype && c->outgoing)
- if(!send_proxyrequest(mesh, c))
+ if(!send_proxyrequest(mesh, c)) {
return false;
+ }
return send_request(mesh, c, "%d %s %d.%d", ID, mesh->self->connection->name, mesh->self->connection->protocol_major, minor);
}
static bool finalize_invitation(meshlink_handle_t *mesh, connection_t *c, const void *data, uint16_t len) {
(void)len;
+
if(strchr(data, '\n')) {
logger(mesh, MESHLINK_ERROR, "Received invalid key from invited node %s!\n", c->name);
return false;
// Create a new host config file
char filename[PATH_MAX];
snprintf(filename, sizeof(filename), "%s" SLASH "hosts" SLASH "%s", mesh->confbase, c->name);
+
if(!access(filename, F_OK)) {
logger(mesh, MESHLINK_ERROR, "Host config file for %s already exists!\n", c->name);
return false;
}
FILE *f = fopen(filename, "w");
+
if(!f) {
logger(mesh, MESHLINK_ERROR, "Error trying to create %s: %s\n", filename, strerror(errno));
return false;
connection_t *c = handle;
meshlink_handle_t *mesh = c->mesh;
- if(type == 128)
+ if(type == 128) {
return true;
+ }
- if(type == 1 && c->status.invitation_used)
+ if(type == 1 && c->status.invitation_used) {
return finalize_invitation(mesh, c, data, len);
+ }
- if(type != 0 || len != 18 || c->status.invitation_used)
+ if(type != 0 || len != 18 || c->status.invitation_used) {
return false;
+ }
// Recover the filename from the cookie and the key
char *fingerprint = ecdsa_get_base64_public_key(mesh->invitation_key);
// Atomically rename the invitation file
if(rename(filename, usedname)) {
- if(errno == ENOENT)
+ if(errno == ENOENT) {
logger(mesh, MESHLINK_ERROR, "Peer %s tried to use non-existing invitation %s\n", c->name, cookie);
- else
+ } else {
logger(mesh, MESHLINK_ERROR, "Error trying to rename invitation %s\n", cookie);
+ }
+
return false;
}
// Open the renamed file
FILE *f = fopen(usedname, "r");
+
if(!f) {
logger(mesh, MESHLINK_ERROR, "Error trying to open invitation %s\n", cookie);
return false;
// Read the new node's Name from the file
char buf[1024];
fgets(buf, sizeof(buf), f);
- if(*buf)
+
+ if(*buf) {
buf[strlen(buf) - 1] = 0;
+ }
len = strcspn(buf, " \t=");
char *name = buf + len;
name += strspn(name, " \t");
+
if(*name == '=') {
name++;
name += strspn(name, " \t");
}
+
buf[len] = 0;
if(!*buf || !*name || strcasecmp(buf, "Name") || !check_id(name)) {
// Send the node the contents of the invitation file
rewind(f);
size_t result;
- while((result = fread(buf, 1, sizeof(buf), f)))
+
+ while((result = fread(buf, 1, sizeof(buf), f))) {
sptps_send_record(&c->sptps, 0, buf, result);
+ }
+
sptps_send_record(&c->sptps, 1, buf, 0);
fclose(f);
unlink(usedname);
}
c->ecdsa = ecdsa_set_base64_public_key(name + 1);
+
if(!c->ecdsa) {
logger(mesh, MESHLINK_ERROR, "Got bad invitation from %s", c->name);
return false;
c->status.invitation = true;
char *mykey = ecdsa_get_base64_public_key(mesh->invitation_key);
- if(!mykey)
+
+ if(!mykey) {
return false;
- if(!send_request(mesh, c, "%d %s", ACK, mykey))
+ }
+
+ if(!send_request(mesh, c, "%d %s", ACK, mykey)) {
return false;
+ }
+
free(mykey);
c->protocol_minor = 2;
return false;
}
} else {
- if(c->name)
+ if(c->name) {
free(c->name);
+ }
+
c->name = xstrdup(name);
}
logger(mesh, MESHLINK_ERROR, "No key known for peer %s", c->name);
node_t *n = lookup_node(mesh, c->name);
+
if(n && !n->status.waitingforkey) {
logger(mesh, MESHLINK_INFO, "Requesting key from peer %s", c->name);
send_req_key(mesh, n);
c->allow_request = ACK;
char label[sizeof(meshlink_tcp_label) + strlen(mesh->self->name) + strlen(c->name) + 2];
- if(c->outgoing)
+ if(c->outgoing) {
snprintf(label, sizeof(label), "%s %s %s", meshlink_tcp_label, mesh->self->name, c->name);
- else
+ } else {
snprintf(label, sizeof(label), "%s %s %s", meshlink_tcp_label, c->name, mesh->self->name);
+ }
return sptps_start(&c->sptps, c, c->outgoing, false, mesh->self->connection->ecdsa, c->ecdsa, label, sizeof(label) - 1, send_meta_sptps, receive_meta_sptps);
}
/* Check some options */
- if(mesh->self->options & OPTION_PMTU_DISCOVERY)
+ if(mesh->self->options & OPTION_PMTU_DISCOVERY) {
c->options |= OPTION_PMTU_DISCOVERY;
+ }
return send_request(mesh, c, "%d %s %d %x", ACK, mesh->myport, mesh->devclass, (c->options & 0xffffff) | (PROT_MINOR << 24));
}
/* Send all known subnets and edges */
for splay_each(node_t, n, mesh->nodes) {
- for splay_each(edge_t, e, n->edge_tree)
+ for splay_each(edge_t, e, n->edge_tree) {
send_add_edge(mesh, c, e);
+ }
}
}
logger(mesh, MESHLINK_DEBUG, "Established a second connection with %s, closing old connection", n->connection->name);
if(n->connection->outgoing) {
- if(c->outgoing)
+ if(c->outgoing) {
logger(mesh, MESHLINK_WARNING, "Two outgoing connections to the same node!");
- else
+ } else {
c->outgoing = n->connection->outgoing;
+ }
n->connection->outgoing = NULL;
}
n->connection = c;
c->node = n;
+
if(!(c->options & options & OPTION_PMTU_DISCOVERY)) {
c->options &= ~OPTION_PMTU_DISCOVERY;
options &= ~OPTION_PMTU_DISCOVERY;
}
+
c->options |= options;
/* Activate this connection */
return false;
}
- if(seen_request(mesh, request))
+ if(seen_request(mesh, request)) {
return true;
+ }
/* Lookup nodes */
edge_del(mesh, e);
graph(mesh);
}
- } else
+ } else {
return true;
+ }
} else if(from == mesh->self) {
logger(mesh, MESHLINK_WARNING, "Got %s from %s for ourself which does not exist",
"ADD_EDGE", c->name);
return false;
}
- if(seen_request(mesh, request))
+ if(seen_request(mesh, request)) {
return true;
+ }
/* Lookup nodes */
if(!to->status.reachable) {
e = lookup_edge(to, mesh->self);
+
if(e) {
send_del_edge(mesh, mesh->everyone, e);
edge_del(mesh, e);
/* Force key exchange for connections using SPTPS */
for splay_each(node_t, n, mesh->nodes)
- if(n->status.reachable && n->status.validkey)
+ if(n->status.reachable && n->status.validkey) {
sptps_force_kex(&n->sptps);
+ }
}
bool key_changed_h(meshlink_handle_t *mesh, connection_t *c, const char *request) {
return false;
}
- if(seen_request(mesh, request))
+ if(seen_request(mesh, request)) {
return true;
+ }
n = lookup_node(mesh, name);
return true;
}
- if(to->sptps.label)
+ if(to->sptps.label) {
logger(mesh, MESHLINK_DEBUG, "send_req_key(%s) called while sptps->label != NULL!", to->name);
+ }
char label[sizeof(meshlink_udp_label) + strlen(mesh->self->name) + strlen(to->name) + 2];
snprintf(label, sizeof(label), "%s %s %s", meshlink_udp_label, mesh->self->name, to->name);
static bool req_key_ext_h(meshlink_handle_t *mesh, connection_t *c, const char *request, node_t *from, int reqno) {
(void)c;
+
switch(reqno) {
case REQ_PUBKEY: {
char *pubkey = ecdsa_get_base64_public_key(mesh->self->connection->ecdsa);
}
char pubkey[MAX_STRING_SIZE];
+
if(sscanf(request, "%*d %*s %*s %*d " MAX_STRING, pubkey) != 1 || !(from->ecdsa = ecdsa_set_base64_public_key(pubkey))) {
logger(mesh, MESHLINK_ERROR, "Got bad %s from %s: %s", "ANS_PUBKEY", from->name, "invalid pubkey");
return true;
if(from->sptps.label) {
logger(mesh, MESHLINK_DEBUG, "Got REQ_KEY from %s while we already started a SPTPS session!", from->name);
+
if(strcmp(mesh->self->name, from->name) < 0) {
logger(mesh, MESHLINK_DEBUG, "Ignoring REQ_KEY from %s.", from->name);
return true;
char buf[MAX_STRING_SIZE];
int len;
+
if(sscanf(request, "%*d %*s %*s %*d " MAX_STRING, buf) != 1 || !(len = b64decode(buf, buf, strlen(buf)))) {
logger(mesh, MESHLINK_ERROR, "Got bad %s from %s: %s", "REQ_SPTPS", from->name, "invalid SPTPS data");
return true;
}
+
sptps_receive_data(&from->sptps, buf, len);
return true;
}
if(to == mesh->self) { /* Yes */
/* Is this an extended REQ_KEY message? */
- if(reqno)
+ if(reqno) {
return req_key_ext_h(mesh, c, request, from, reqno);
+ }
/* This should never happen. Ignore it, unless it came directly from the connected peer, in which case we disconnect. */
return from->connection != c;
char buf[strlen(key)];
int len = b64decode(key, buf, strlen(key));
- if(!len || !sptps_receive_data(&from->sptps, buf, len))
+ if(!len || !sptps_receive_data(&from->sptps, buf, len)) {
logger(mesh, MESHLINK_ERROR, "Error processing SPTPS data from %s", from->name);
+ }
if(from->status.validkey) {
if(*address && *port) {
update_node_udp(mesh, from, &sa);
}
- if(from->options & OPTION_PMTU_DISCOVERY && !(from->options & OPTION_TCPONLY))
+ if(from->options & OPTION_PMTU_DISCOVERY && !(from->options & OPTION_TCPONLY)) {
send_mtu_probe(mesh, from);
+ }
}
return true;
if(c->outgoing) {
c->outgoing->timeout = 0;
c->outgoing->cfg = NULL;
- if(c->outgoing->ai)
+
+ if(c->outgoing->ai) {
freeaddrinfo(c->outgoing->ai);
+ }
+
c->outgoing->ai = NULL;
c->outgoing->aip = NULL;
}
if(packet->len < length) {
logger(source->mesh, MESHLINK_WARNING, "Got too short packet from %s", source->name);
return false;
- } else
+ } else {
return true;
+ }
}
void route(meshlink_handle_t *mesh, node_t *source, vpn_packet_t *packet) {
logger(mesh, MESHLINK_DEBUG, "Routing packet from \"%s\" to \"%s\"\n", hdr->source, hdr->destination);
//Check Lenght
- if(!checklength(source, packet, sizeof(*hdr)))
+ if(!checklength(source, packet, sizeof(*hdr))) {
return;
+ }
if(owner == NULL) {
//Lookup failed
size_t len = packet->len - sizeof(*hdr);
char hex[len * 2 + 1];
- if(mesh->log_level >= MESHLINK_DEBUG)
- bin2hex(payload, hex, len); // don't do this unless it's going to be logged
+
+ if(mesh->log_level >= MESHLINK_DEBUG) {
+ bin2hex(payload, hex, len); // don't do this unless it's going to be logged
+ }
+
logger(mesh, MESHLINK_DEBUG, "I received a packet for me with payload: %s\n", hex);
- if(mesh->receive_cb)
+ if(mesh->receive_cb) {
mesh->receive_cb(mesh, (meshlink_node_t *)source, payload, len);
+ }
+
return;
}
}
via = (owner->via == mesh->self) ? owner->nexthop : owner->via;
+
if(via == source) {
logger(mesh, MESHLINK_ERROR, "Routing loop for packet from %s!", source->name);
return;
int c;
if(!root) {
- if(result)
+ if(result) {
*result = 0;
+ }
+
return NULL;
}
child->parent = rightbottom;
rightbottom = child;
- if((root->left = child->right))
+ if((root->left = child->right)) {
child->right->parent = root;
+ }
child->right = root;
root->parent = child;
child->parent = leftbottom;
leftbottom = child;
- if((root->right = child->left))
+ if((root->right = child->left)) {
child->left->parent = root;
+ }
child->left = root;
root->parent = child;
root = child;
break;
}
- } else
+ } else {
break;
+ }
}
/* Merge trees */
leftbottom->right = root->left;
root->left->parent = leftbottom;
}
+
root->left = left.right;
left.right->parent = root;
}
rightbottom->left = root->right;
root->right->parent = rightbottom;
}
+
root->right = right.left;
right.left->parent = root;
}
/* Return result */
tree->root = root;
- if(result)
+
+ if(result) {
*result = c;
+ }
return tree->root;
}
while((parent = node->parent)) {
if(!(grandparent = parent->parent)) { /* zig */
if(node == parent->left) {
- if((parent->left = node->right))
+ if((parent->left = node->right)) {
parent->left->parent = parent;
+ }
+
node->right = parent;
} else {
- if((parent->right = node->left))
+ if((parent->right = node->left)) {
parent->right->parent = parent;
+ }
+
node->left = parent;
}
greatgrandparent = grandparent->parent;
if(node == parent->left && parent == grandparent->left) { /* left zig-zig */
- if((grandparent->left = parent->right))
+ if((grandparent->left = parent->right)) {
grandparent->left->parent = grandparent;
+ }
+
parent->right = grandparent;
grandparent->parent = parent;
- if((parent->left = node->right))
+ if((parent->left = node->right)) {
parent->left->parent = parent;
+ }
+
node->right = parent;
parent->parent = node;
} else if(node == parent->right && parent == grandparent->right) { /* right zig-zig */
- if((grandparent->right = parent->left))
+ if((grandparent->right = parent->left)) {
grandparent->right->parent = grandparent;
+ }
+
parent->left = grandparent;
grandparent->parent = parent;
- if((parent->right = node->left))
+ if((parent->right = node->left)) {
parent->right->parent = parent;
+ }
+
node->left = parent;
parent->parent = node;
} else if(node == parent->right && parent == grandparent->left) { /* left-right zig-zag */
- if((parent->right = node->left))
+ if((parent->right = node->left)) {
parent->right->parent = parent;
+ }
+
node->left = parent;
parent->parent = node;
- if((grandparent->left = node->right))
+ if((grandparent->left = node->right)) {
grandparent->left->parent = grandparent;
+ }
+
node->right = grandparent;
grandparent->parent = node;
} else { /* right-left zig-zag */
- if((parent->left = node->right))
+ if((parent->left = node->right)) {
parent->left->parent = parent;
+ }
+
node->right = parent;
parent->parent = node;
- if((grandparent->right = node->left))
+ if((grandparent->right = node->left)) {
grandparent->right->parent = grandparent;
+ }
+
node->left = grandparent;
grandparent->parent = node;
}
if((node->parent = greatgrandparent)) {
- if(grandparent == greatgrandparent->left)
+ if(grandparent == greatgrandparent->left) {
greatgrandparent->left = node;
- else
+ } else {
greatgrandparent->right = node;
+ }
}
}
}
}
void splay_free_node(splay_tree_t *tree, splay_node_t *node) {
- if(node->data && tree->delete)
+ if(node->data && tree->delete) {
tree->delete(node->data);
+ }
free(node);
}
node = tree->root;
if(!node) {
- if(result)
+ if(result) {
*result = 0;
+ }
+
return NULL;
}
c = tree->compare(data, node->data);
if(c < 0) {
- if(node->left)
+ if(node->left) {
node = node->left;
- else
+ } else {
break;
+ }
} else if(c > 0) {
- if(node->right)
+ if(node->right) {
node = node->right;
- else
+ } else {
break;
- } else
+ }
+ } else {
break;
+ }
}
- if(result)
+ if(result) {
*result = c;
+ }
+
return node;
}
node = splay_search_closest_node(tree, data, &result);
- if(result < 0)
+ if(result < 0) {
node = node->prev;
+ }
return node;
}
node = splay_search_closest_node(tree, data, &result);
- if(result > 0)
+ if(result > 0) {
node = node->next;
+ }
return node;
}
} else {
closest = splay_search_closest_node(tree, data, &result);
- if(!result)
+ if(!result) {
return NULL;
+ }
new = splay_alloc_node();
new->data = data;
- if(result < 0)
+ if(result < 0) {
splay_insert_before(tree, closest, new);
- else
+ } else {
splay_insert_after(tree, closest, new);
+ }
}
return new;
node->left = node->right = node->parent = node->next = node->prev = NULL;
- if(!tree->root)
+ if(!tree->root) {
splay_insert_top(tree, node);
- else {
+ } else {
closest = splay_search_closest_node(tree, node->data, &result);
- if(!result)
+ if(!result) {
return NULL;
+ }
- if(result < 0)
+ if(result < 0) {
splay_insert_before(tree, closest, node);
- else
+ } else {
splay_insert_after(tree, closest, node);
+ }
}
return node;
void splay_insert_before(splay_tree_t *tree, splay_node_t *before, splay_node_t *node) {
if(!before) {
- if(tree->tail)
+ if(tree->tail) {
splay_insert_after(tree, tree->tail, node);
- else
+ } else {
splay_insert_top(tree, node);
+ }
+
return;
}
node->next = before;
- if((node->prev = before->prev))
+
+ if((node->prev = before->prev)) {
before->prev->next = node;
- else
+ } else {
tree->head = node;
+ }
+
before->prev = node;
splay_bottom_up(tree, before);
node->right = before;
before->parent = node;
- if((node->left = before->left))
+
+ if((node->left = before->left)) {
before->left->parent = node;
+ }
+
before->left = NULL;
node->parent = NULL;
void splay_insert_after(splay_tree_t *tree, splay_node_t *after, splay_node_t *node) {
if(!after) {
- if(tree->head)
+ if(tree->head) {
splay_insert_before(tree, tree->head, node);
- else
+ } else {
splay_insert_top(tree, node);
+ }
+
return;
}
node->prev = after;
- if((node->next = after->next))
+
+ if((node->next = after->next)) {
after->next->prev = node;
- else
+ } else {
tree->tail = node;
+ }
+
after->next = node;
splay_bottom_up(tree, after);
node->left = after;
after->parent = node;
- if((node->right = after->right))
+
+ if((node->right = after->right)) {
after->right->parent = node;
+ }
+
after->right = NULL;
node->parent = NULL;
node = splay_search_node(tree, data);
- if(node)
+ if(node) {
splay_unlink_node(tree, node);
+ }
return node;
}
void splay_unlink_node(splay_tree_t *tree, splay_node_t *node) {
- if(node->prev)
+ if(node->prev) {
node->prev->next = node->next;
- else
+ } else {
tree->head = node->next;
+ }
- if(node->next)
+ if(node->next) {
node->next->prev = node->prev;
- else
+ } else {
tree->tail = node->prev;
+ }
splay_bottom_up(tree, node);
if(node->prev) {
node->left->parent = NULL;
tree->root = node->left;
- if((node->prev->right = node->right))
+
+ if((node->prev->right = node->right)) {
node->right->parent = node->prev;
+ }
} else if(node->next) {
tree->root = node->right;
node->right->parent = NULL;
- } else
+ } else {
tree->root = NULL;
+ }
tree->count--;
}
node = splay_search_node(tree, data);
- if(node)
+ if(node) {
splay_delete_node(tree, node);
+ }
}
/* Fast tree cleanup */
}
// Send a record (private version, accepts all record types, handles encryption and authentication).
static bool send_record_priv(sptps_t *s, uint8_t type, const void *data, uint16_t len) {
- if(s->datagram)
+ if(s->datagram) {
return send_record_priv_datagram(s, type, data, len);
+ }
char buffer[len + 19UL];
bool sptps_send_record(sptps_t *s, uint8_t type, const void *data, uint16_t len) {
// Sanity checks: application cannot send data before handshake is finished,
// and only record types 0..127 are allowed.
- if(!s->outstate)
+ if(!s->outstate) {
return error(s, EINVAL, "Handshake phase not finished yet");
+ }
- if(type >= SPTPS_HANDSHAKE)
+ if(type >= SPTPS_HANDSHAKE) {
return error(s, EINVAL, "Invalid application record type");
+ }
return send_record_priv(s, type, data, len);
}
size_t keylen = ECDH_SIZE;
// Make room for our KEX message, which we will keep around since send_sig() needs it.
- if(s->mykex)
+ if(s->mykex) {
return false;
+ }
+
s->mykex = realloc(s->mykex, 1 + 32 + keylen);
- if(!s->mykex)
+
+ if(!s->mykex) {
return error(s, errno, strerror(errno));
+ }
// Set version byte to zero.
s->mykex[0] = SPTPS_VERSION;
randomize(s->mykex + 1, 32);
// Create a new ECDH public key.
- if(!(s->ecdh = ecdh_generate_public(s->mykex + 1 + 32)))
+ if(!(s->ecdh = ecdh_generate_public(s->mykex + 1 + 32))) {
return error(s, EINVAL, "Failed to generate ECDH public key");
+ }
return send_record_priv(s, SPTPS_HANDSHAKE, s->mykex, 1 + 32 + keylen);
}
memcpy(msg + 1 + 2 * (33 + keylen), s->label, s->labellen);
// Sign the result.
- if(!ecdsa_sign(s->mykey, msg, sizeof(msg), sig))
+ if(!ecdsa_sign(s->mykey, msg, sizeof(msg), sig)) {
return error(s, EINVAL, "Failed to sign SIG record");
+ }
// Send the SIG exchange record.
return send_record_priv(s, SPTPS_HANDSHAKE, sig, sizeof(sig));
if(!s->outstate) {
s->incipher = chacha_poly1305_init();
s->outcipher = chacha_poly1305_init();
- if(!s->incipher || !s->outcipher)
+
+ if(!s->incipher || !s->outcipher) {
return error(s, EINVAL, "Failed to open cipher");
+ }
}
// Allocate memory for key material
size_t keylen = 2 * CHACHA_POLY1305_KEYLEN;
s->key = realloc(s->key, keylen);
- if(!s->key)
+
+ if(!s->key) {
return error(s, errno, strerror(errno));
+ }
// Create the HMAC seed, which is "key expansion" + session label + server nonce + client nonce
char seed[s->labellen + 64 + 13];
strcpy(seed, "key expansion");
+
if(s->initiator) {
memcpy(seed + 13, s->mykex + 1, 32);
memcpy(seed + 45, s->hiskex + 1, 32);
memcpy(seed + 13, s->hiskex + 1, 32);
memcpy(seed + 45, s->mykex + 1, 32);
}
+
memcpy(seed + 77, s->label, s->labellen);
// Use PRF to generate the key material
- if(!prf(shared, len, seed, s->labellen + 64 + 13, s->key, keylen))
+ if(!prf(shared, len, seed, s->labellen + 64 + 13, s->key, keylen)) {
return error(s, EINVAL, "Failed to generate key material");
+ }
return true;
}
// Receive an ACKnowledgement record.
static bool receive_ack(sptps_t *s, const char *data, uint16_t len) {
(void)data;
- if(len)
+
+ if(len) {
return error(s, EIO, "Invalid ACK record length");
+ }
if(s->initiator) {
- if(!chacha_poly1305_set_key(s->incipher, s->key))
+ if(!chacha_poly1305_set_key(s->incipher, s->key)) {
return error(s, EINVAL, "Failed to set counter");
+ }
} else {
- if(!chacha_poly1305_set_key(s->incipher, s->key + CHACHA_POLY1305_KEYLEN))
+ if(!chacha_poly1305_set_key(s->incipher, s->key + CHACHA_POLY1305_KEYLEN)) {
return error(s, EINVAL, "Failed to set counter");
+ }
}
free(s->key);
// Receive a Key EXchange record, respond by sending a SIG record.
static bool receive_kex(sptps_t *s, const char *data, uint16_t len) {
// Verify length of the HELLO record
- if(len != 1 + 32 + ECDH_SIZE)
+ if(len != 1 + 32 + ECDH_SIZE) {
return error(s, EIO, "Invalid KEX record length");
+ }
// Ignore version number for now.
// Make a copy of the KEX message, send_sig() and receive_sig() need it
- if(s->hiskex)
+ if(s->hiskex) {
return error(s, EINVAL, "Received a second KEX message before first has been processed");
+ }
+
s->hiskex = realloc(s->hiskex, len);
- if(!s->hiskex)
+
+ if(!s->hiskex) {
return error(s, errno, strerror(errno));
+ }
memcpy(s->hiskex, data, len);
size_t siglen = ecdsa_size(s->hiskey);
// Verify length of KEX record.
- if(len != siglen)
+ if(len != siglen) {
return error(s, EIO, "Invalid KEX record length");
+ }
// Concatenate both KEX messages, plus tag indicating if it is from the connection originator
char msg[(1 + 32 + keylen) * 2 + 1 + s->labellen];
memcpy(msg + 1 + 2 * (33 + keylen), s->label, s->labellen);
// Verify signature.
- if(!ecdsa_verify(s->hiskey, msg, sizeof(msg), data))
+ if(!ecdsa_verify(s->hiskey, msg, sizeof(msg), data)) {
return error(s, EIO, "Failed to verify SIG record");
+ }
// Compute shared secret.
char shared[ECDH_SHARED_SIZE];
- if(!ecdh_compute_shared(s->ecdh, s->hiskex + 1 + 32, shared))
+
+ if(!ecdh_compute_shared(s->ecdh, s->hiskex + 1 + 32, shared)) {
return error(s, EINVAL, "Failed to compute ECDH shared secret");
+ }
+
s->ecdh = NULL;
// Generate key material from shared secret.
- if(!generate_key_material(s, shared, sizeof(shared)))
+ if(!generate_key_material(s, shared, sizeof(shared))) {
return false;
+ }
free(s->mykex);
free(s->hiskex);
s->hiskex = NULL;
// Send cipher change record
- if(s->outstate && !send_ack(s))
+ if(s->outstate && !send_ack(s)) {
return false;
+ }
// TODO: only set new keys after ACK has been set/received
if(s->initiator) {
- if(!chacha_poly1305_set_key(s->outcipher, s->key + CHACHA_POLY1305_KEYLEN))
+ if(!chacha_poly1305_set_key(s->outcipher, s->key + CHACHA_POLY1305_KEYLEN)) {
return error(s, EINVAL, "Failed to set key");
+ }
} else {
- if(!chacha_poly1305_set_key(s->outcipher, s->key))
+ if(!chacha_poly1305_set_key(s->outcipher, s->key)) {
return error(s, EINVAL, "Failed to set key");
+ }
}
return true;
// Force another Key EXchange (for testing purposes).
bool sptps_force_kex(sptps_t *s) {
- if(!s->outstate || s->state != SPTPS_SECONDARY_KEX)
+ if(!s->outstate || s->state != SPTPS_SECONDARY_KEX) {
return error(s, EINVAL, "Cannot force KEX in current state");
+ }
s->state = SPTPS_KEX;
return send_kex(s);
// Only a few states to deal with handshaking.
switch(s->state) {
case SPTPS_SECONDARY_KEX:
+
// We receive a secondary KEX request, first respond by sending our own.
- if(!send_kex(s))
+ if(!send_kex(s)) {
return false;
- // fallthrough
+ }
+
+ // fallthrough
case SPTPS_KEX:
+
// We have sent our KEX request, we expect our peer to sent one as well.
- if(!receive_kex(s, data, len))
+ if(!receive_kex(s, data, len)) {
return false;
+ }
+
s->state = SPTPS_SIG;
return true;
+
case SPTPS_SIG:
+
// If we already sent our secondary public ECDH key, we expect the peer to send his.
- if(!receive_sig(s, data, len))
+ if(!receive_sig(s, data, len)) {
return false;
- if(s->outstate)
+ }
+
+ if(s->outstate) {
s->state = SPTPS_ACK;
- else {
+ } else {
s->outstate = true;
- if(!receive_ack(s, NULL, 0))
+
+ if(!receive_ack(s, NULL, 0)) {
return false;
+ }
+
s->receive_record(s->handle, SPTPS_HANDSHAKE, NULL, 0);
s->state = SPTPS_SECONDARY_KEX;
}
return true;
+
case SPTPS_ACK:
+
// We expect a handshake message to indicate transition to the new keys.
- if(!receive_ack(s, data, len))
+ if(!receive_ack(s, data, len)) {
return false;
+ }
+
s->receive_record(s->handle, SPTPS_HANDSHAKE, NULL, 0);
s->state = SPTPS_SECONDARY_KEX;
return true;
+
// TODO: split ACK into a VERify and ACK?
default:
return error(s, EIO, "Invalid session state %d", s->state);
// Check datagram for valid HMAC
bool sptps_verify_datagram(sptps_t *s, const void *data, size_t len) {
- if(!s->instate)
+ if(!s->instate) {
return error(s, EIO, "SPTPS state not ready to verify this datagram");
+ }
- if(len < 21)
+ if(len < 21) {
return error(s, EIO, "Received short packet in sptps_verify_datagram");
+ }
uint32_t seqno;
memcpy(&seqno, data, 4);
static bool sptps_receive_data_datagram(sptps_t *s, const void *vdata, size_t len) {
const char *data = vdata;
- if(len < (s->instate ? 21 : 5))
+ if(len < (s->instate ? 21 : 5)) {
return error(s, EIO, "Received short packet in sptps_receive_data_datagram");
+ }
uint32_t seqno;
memcpy(&seqno, data, 4);
seqno = ntohl(seqno);
if(!s->instate) {
- if(seqno != s->inseqno)
+ if(seqno != s->inseqno) {
return error(s, EIO, "Invalid packet seqno: %d != %d", seqno, s->inseqno);
+ }
s->inseqno = seqno + 1;
uint8_t type = data[4];
- if(type != SPTPS_HANDSHAKE)
+ if(type != SPTPS_HANDSHAKE) {
return error(s, EIO, "Application record received before handshake finished");
+ }
return receive_handshake(s, data + 5, len - 5);
}
size_t outlen;
- if(!chacha_poly1305_decrypt(s->incipher, seqno, data + 4, len - 4, buffer, &outlen))
+ if(!chacha_poly1305_decrypt(s->incipher, seqno, data + 4, len - 4, buffer, &outlen)) {
return error(s, EIO, "Failed to decrypt and verify packet");
+ }
// Replay protection using a sliding window of configurable size.
// s->inseqno is expected sequence number
memset(s->late, 255, s->replaywin);
} else if(seqno < s->inseqno) {
// If the sequence number is farther in the past than the bitmap goes, or if the packet was already received, drop it.
- if((s->inseqno >= s->replaywin * 8 && seqno < s->inseqno - s->replaywin * 8) || !(s->late[(seqno / 8) % s->replaywin] & (1 << seqno % 8)))
+ if((s->inseqno >= s->replaywin * 8 && seqno < s->inseqno - s->replaywin * 8) || !(s->late[(seqno / 8) % s->replaywin] & (1 << seqno % 8))) {
return error(s, EIO, "Received late or replayed packet, seqno %d, last received %d\n", seqno, s->inseqno);
+ }
} else {
// We missed some packets. Mark them in the bitmap as being late.
- for(uint32_t i = s->inseqno; i < seqno; i++)
+ for(uint32_t i = s->inseqno; i < seqno; i++) {
s->late[(i / 8) % s->replaywin] |= 1 << i % 8;
+ }
}
}
s->late[(seqno / 8) % s->replaywin] &= ~(1 << seqno % 8);
}
- if(seqno >= s->inseqno)
+ if(seqno >= s->inseqno) {
s->inseqno = seqno + 1;
+ }
- if(!s->inseqno)
+ if(!s->inseqno) {
s->received = 0;
- else
+ } else {
s->received++;
+ }
// Append a NULL byte for safety.
buffer[len - 20] = 0;
uint8_t type = buffer[0];
if(type < SPTPS_HANDSHAKE) {
- if(!s->instate)
+ if(!s->instate) {
return error(s, EIO, "Application record received before handshake finished");
- if(!s->receive_record(s->handle, type, buffer + 1, len - 21))
+ }
+
+ if(!s->receive_record(s->handle, type, buffer + 1, len - 21)) {
abort();
+ }
} else if(type == SPTPS_HANDSHAKE) {
- if(!receive_handshake(s, buffer + 1, len - 21))
+ if(!receive_handshake(s, buffer + 1, len - 21)) {
abort();
- } else
+ }
+ } else {
return error(s, EIO, "Invalid record type %d", type);
+ }
return true;
}
// Receive incoming data. Check if it contains a complete record, if so, handle it.
bool sptps_receive_data(sptps_t *s, const void *data, size_t len) {
- if(!s->state)
+ if(!s->state) {
return error(s, EIO, "Invalid session state zero");
+ }
- if(s->datagram)
+ if(s->datagram) {
return sptps_receive_data_datagram(s, data, len);
+ }
while(len) {
// First read the 2 length bytes.
if(s->buflen < 2) {
size_t toread = 2 - s->buflen;
- if(toread > len)
+
+ if(toread > len) {
toread = len;
+ }
memcpy(s->inbuf + s->buflen, data, toread);
data += toread;
// Exit early if we don't have the full length.
- if(s->buflen < 2)
+ if(s->buflen < 2) {
return true;
+ }
// Get the length bytes
// If we have the length bytes, ensure our buffer can hold the whole request.
s->inbuf = realloc(s->inbuf, s->reclen + 19UL);
- if(!s->inbuf)
+
+ if(!s->inbuf) {
return error(s, errno, strerror(errno));
+ }
// Exit early if we have no more data to process.
- if(!len)
+ if(!len) {
return true;
+ }
}
// Read up to the end of the record.
size_t toread = s->reclen + (s->instate ? 19UL : 3UL) - s->buflen;
- if(toread > len)
+
+ if(toread > len) {
toread = len;
+ }
memcpy(s->inbuf + s->buflen, data, toread);
s->buflen += toread;
data += toread;
// If we don't have a whole record, exit.
- if(s->buflen < s->reclen + (s->instate ? 19UL : 3UL))
+ if(s->buflen < s->reclen + (s->instate ? 19UL : 3UL)) {
return true;
+ }
// Update sequence number.
// Check HMAC and decrypt.
if(s->instate) {
- if(!chacha_poly1305_decrypt(s->incipher, seqno, s->inbuf + 2UL, s->reclen + 17UL, s->inbuf + 2UL, NULL))
+ if(!chacha_poly1305_decrypt(s->incipher, seqno, s->inbuf + 2UL, s->reclen + 17UL, s->inbuf + 2UL, NULL)) {
return error(s, EINVAL, "Failed to decrypt and verify record");
+ }
}
// Append a NULL byte for safety.
uint8_t type = s->inbuf[2];
if(type < SPTPS_HANDSHAKE) {
- if(!s->instate)
+ if(!s->instate) {
return error(s, EIO, "Application record received before handshake finished");
- if(!s->receive_record(s->handle, type, s->inbuf + 3, s->reclen))
+ }
+
+ if(!s->receive_record(s->handle, type, s->inbuf + 3, s->reclen)) {
return false;
+ }
} else if(type == SPTPS_HANDSHAKE) {
- if(!receive_handshake(s, s->inbuf + 3, s->reclen))
+ if(!receive_handshake(s, s->inbuf + 3, s->reclen)) {
return false;
- } else
+ }
+ } else {
return error(s, EIO, "Invalid record type %d", type);
+ }
s->buflen = 0;
}
// Start a SPTPS session.
bool sptps_start(sptps_t *s, void *handle, bool initiator, bool datagram, ecdsa_t *mykey, ecdsa_t *hiskey, const char *label, size_t labellen, send_data_t send_data, receive_record_t receive_record) {
- if(!s || !mykey || !hiskey || !label || !labellen || !send_data || !receive_record)
+ if(!s || !mykey || !hiskey || !label || !labellen || !send_data || !receive_record) {
return error(s, EINVAL, "Invalid argument to sptps_start()");
+ }
// Initialise struct sptps
memset(s, 0, sizeof(*s));
s->mykey = mykey;
s->hiskey = hiskey;
s->replaywin = sptps_replaywin;
+
if(s->replaywin) {
s->late = malloc(s->replaywin);
- if(!s->late)
+
+ if(!s->late) {
return error(s, errno, strerror(errno));
+ }
+
memset(s->late, 0, s->replaywin);
}
s->label = malloc(labellen);
- if(!s->label)
+
+ if(!s->label) {
return error(s, errno, strerror(errno));
+ }
if(!datagram) {
s->inbuf = malloc(7);
- if(!s->inbuf)
+
+ if(!s->inbuf) {
return error(s, errno, strerror(errno));
+ }
+
s->buflen = 0;
}
-Subproject commit 558c6d183e2a580b811c5603dd48c33b01a3dc7e
+Subproject commit 850542e9585f716985c25d5995ba5bcb2cc6ba87
};
static int charhex2bin(char c) {
- if(isdigit(c))
+ if(isdigit(c)) {
return c - '0';
- else
+ } else {
return toupper(c) - 'A' + 10;
+ }
}
int hex2bin(const char *src, void *vdst, int length) {
uint8_t *dst = vdst;
int i;
- for(i = 0; i < length && isxdigit(src[i * 2]) && isxdigit(src[i * 2 + 1]); i++)
+
+ for(i = 0; i < length && isxdigit(src[i * 2]) && isxdigit(src[i * 2 + 1]); i++) {
dst[i] = charhex2bin(src[i * 2]) * 16 + charhex2bin(src[i * 2 + 1]);
+ }
+
return i;
}
int bin2hex(const void *vsrc, char *dst, int length) {
const uint8_t *src = vsrc;
+
for(int i = length - 1; i >= 0; i--) {
dst[i * 2 + 1] = hexadecimals[(unsigned char) src[i] & 15];
dst[i * 2] = hexadecimals[(unsigned char) src[i] >> 4];
}
+
dst[length * 2] = 0;
return length * 2;
}
for(i = 0; i < length / 3 * 4 && src[i]; i++) {
triplet |= base64_decode[src[i] & 0xff] << (6 * (i & 3));
+
if((i & 3) == 3) {
- if(triplet & 0xff000000U)
+ if(triplet & 0xff000000U) {
return 0;
+ }
+
udst[0] = triplet & 0xff;
triplet >>= 8;
udst[1] = triplet & 0xff;
udst += 3;
}
}
- if(triplet & 0xff000000U)
+
+ if(triplet & 0xff000000U) {
return 0;
+ }
+
if((i & 3) == 3) {
udst[0] = triplet & 0xff;
triplet >>= 8;
} else if((i & 3) == 2) {
udst[0] = triplet & 0xff;
return i / 4 * 3 + 1;
- } else
+ } else {
return i / 4 * 3;
+ }
}
static int b64encode_internal(const void *src, char *dst, int length, const char *alphabet) {
dst[di + 3] = 0;
length = di + 2;
break;
+
case 1:
triplet = usrc[si];
dst[di] = alphabet[triplet & 63];
dst[di + 2] = 0;
length = di + 1;
break;
+
default:
dst[di] = 0;
length = di;
ptr = buf + sprintf(buf, "(%d) ", err);
if(!FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
- NULL, err, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), ptr, sizeof(buf) - (ptr - buf), NULL))
+ NULL, err, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), ptr, sizeof(buf) - (ptr - buf), NULL)) {
strncpy(buf, "(unable to format errormessage)", sizeof(buf));
+ }
+
;
- if((ptr = strchr(buf, '\r')))
- *ptr = '\0';
+ if((ptr = strchr(buf, '\r'))) {
+ * ptr = '\0';
+ }
return buf;
}
unsigned int bitfield_to_int(const void *bitfield, size_t size) {
unsigned int value = 0;
- if(size > sizeof(value))
+
+ if(size > sizeof(value)) {
size = sizeof(value);
+ }
+
memcpy(&value, bitfield, size);
return value;
}
static inline void *xmalloc(size_t n) __attribute__((__malloc__));
static inline void *xmalloc(size_t n) {
void *p = malloc(n);
- if(!p)
+
+ if(!p) {
abort();
+ }
+
return p;
}
static inline void *xzalloc(size_t n) __attribute__((__malloc__));
static inline void *xzalloc(size_t n) {
void *p = calloc(1, n);
- if(!p)
+
+ if(!p) {
abort();
+ }
+
return p;
}
static inline void *xrealloc(void *p, size_t n) {
p = realloc(p, n);
- if(!p)
+
+ if(!p) {
abort();
+ }
+
return p;
}
static inline char *xstrdup(const char *s) __attribute__((__malloc__));
static inline char *xstrdup(const char *s) {
char *p = strdup(s);
- if(!p)
+
+ if(!p) {
abort();
+ }
+
return p;
}
#ifdef HAVE_MINGW
char buf[1024];
int result = vsnprintf(buf, sizeof(buf), fmt, ap);
- if(result < 0)
+
+ if(result < 0) {
abort();
+ }
+
*strp = xstrdup(buf);
#else
int result = vasprintf(strp, fmt, ap);
- if(result < 0)
+
+ if(result < 0) {
abort();
+ }
+
#endif
return result;
}