This allows astyle to be used as a pre-commit hook.
--- /dev/null
+--indent=tab=8
+--convert-tabs
+-xj
+-A2
+-U
*~
.*
!.gitignore
+!.gitmodules
+!.astylerc
core
core.*
/config.*
} else if(!strcasecmp(buf, "who")) {
if(!arg) {
nodes = meshlink_get_all_nodes(mesh, nodes, &nnodes);
- if(!nnodes) {
+ if(!nnodes)
fprintf(stderr, "Could not get list of nodes: %s\n", meshlink_strerror(meshlink_errno));
- } else {
+ else {
printf("%zu known nodes:", nnodes);
for(int i = 0; i < nnodes; i++)
printf(" %s", nodes[i]->name);
}
} else {
meshlink_node_t *node = meshlink_get_node(mesh, arg);
- if(!node) {
+ if(!node)
fprintf(stderr, "Error looking up '%s': %s\n", arg, meshlink_strerror(meshlink_errno));
- } else {
+ else
printf("Node %s found\n", arg);
- }
}
} else if(!strcasecmp(buf, "quit")) {
printf("Bye!\n");
fclose(stdin);
} else if(!strcasecmp(buf, "help")) {
printf(
- "<name>: <message> Send a message to the given node.\n"
- " Subsequent messages don't need the <name>: prefix.\n"
- "/invite <name> Create an invitation for a new node.\n"
- "/join <invitation> Join an existing mesh using an invitation.\n"
- "/kick <name> Blacklist the given node.\n"
- "/who [<name>] List all nodes or show information about the given node.\n"
- "/quit Exit this program.\n"
- );
- } else {
+ "<name>: <message> Send a message to the given node.\n"
+ " Subsequent messages don't need the <name>: prefix.\n"
+ "/invite <name> Create an invitation for a new node.\n"
+ "/join <invitation> Join an existing mesh using an invitation.\n"
+ "/kick <name> Blacklist the given node.\n"
+ "/who [<name>] List all nodes or show information about the given node.\n"
+ "/quit Exit this program.\n"
+ );
+ } else
fprintf(stderr, "Unknown command '/%s'\n", buf);
- }
}
static void parse_input(meshlink_handle_t *mesh, char *buf) {
} else if(!strcasecmp(buf, "who")) {
if(!arg) {
nodes = meshlink_get_all_nodes(mesh, nodes, &nnodes);
- if(!nnodes) {
+ if(!nnodes)
fprintf(stderr, "Could not get list of nodes: %s\n", meshlink_strerror(meshlink_errno));
- } else {
+ else {
printf("%zu known nodes:", nnodes);
for(int i = 0; i < nnodes; i++)
printf(" %s", nodes[i]->name);
}
} else {
meshlink_node_t *node = meshlink_get_node(mesh, arg);
- if(!node) {
+ if(!node)
fprintf(stderr, "Error looking up '%s': %s\n", arg, meshlink_strerror(meshlink_errno));
- } else {
+ else
printf("Node %s found\n", arg);
- }
}
} else if(!strcasecmp(buf, "quit")) {
printf("Bye!\n");
fclose(stdin);
} else if(!strcasecmp(buf, "help")) {
printf(
- "<name>: <message> Send a message to the given node.\n"
- " Subsequent messages don't need the <name>: prefix.\n"
- "/invite <name> Create an invitation for a new node.\n"
- "/join <invitation> Join an existing mesh using an invitation.\n"
- "/kick <name> Blacklist the given node.\n"
- "/who [<name>] List all nodes or show information about the given node.\n"
- "/quit Exit this program.\n"
- );
- } else {
+ "<name>: <message> Send a message to the given node.\n"
+ " Subsequent messages don't need the <name>: prefix.\n"
+ "/invite <name> Create an invitation for a new node.\n"
+ "/join <invitation> Join an existing mesh using an invitation.\n"
+ "/kick <name> Blacklist the given node.\n"
+ "/who [<name>] List all nodes or show information about the given node.\n"
+ "/quit Exit this program.\n"
+ );
+ } else
fprintf(stderr, "Unknown command '/%s'\n", buf);
- }
}
static void parse_input(meshlink_handle_t *mesh, char *buf) {
#include <strings.h>
#include "../src/meshlink++.h"
-class ChatMesh : public meshlink::mesh
-{
+class ChatMesh : public meshlink::mesh {
public:
void log(meshlink::log_level_t level, const char *text) {
const char *levelstr[] = {"DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"};
fprintf(stderr, "%s: %s\n", levelstr[level], text);
- }
+ }
void receive(meshlink::node *source, const void *data, size_t len) {
const char *msg = (const char *)data;
-
+
if(!len || msg[len - 1]) {
fprintf(stderr, "Received invalid data from %s\n", source->name);
return;
}
-
+
printf("%s says: %s\n", source->name, msg);
}
} else if(!strcasecmp(buf, "who")) {
if(!arg) {
nodes = mesh->get_all_nodes(nodes, &nnodes);
- if(!nodes) {
+ if(!nodes)
fprintf(stderr, "Could not get list of nodes: %s\n", meshlink::strerror());
- } else {
+ else {
printf("%zu known nodes:", nnodes);
for(size_t i = 0; i < nnodes; i++)
printf(" %s", nodes[i]->name);
}
} else {
meshlink::node *node = mesh->get_node(arg);
- if(!node) {
+ if(!node)
fprintf(stderr, "Error looking up '%s': %s\n", arg, meshlink::strerror());
- } else {
+ else
printf("Node %s found\n", arg);
- }
}
} else if(!strcasecmp(buf, "quit")) {
printf("Bye!\n");
fclose(stdin);
} else if(!strcasecmp(buf, "help")) {
printf(
- "<name>: <message> Send a message to the given node.\n"
- " Subsequent messages don't need the <name>: prefix.\n"
- "/invite <name> Create an invitation for a new node.\n"
- "/join <invitation> Join an existing mesh using an invitation.\n"
- "/kick <name> Blacklist the given node.\n"
- "/who [<name>] List all nodes or show information about the given node.\n"
- "/quit Exit this program.\n"
- );
- } else {
+ "<name>: <message> Send a message to the given node.\n"
+ " Subsequent messages don't need the <name>: prefix.\n"
+ "/invite <name> Create an invitation for a new node.\n"
+ "/join <invitation> Join an existing mesh using an invitation.\n"
+ "/kick <name> Blacklist the given node.\n"
+ "/who [<name>] List all nodes or show information about the given node.\n"
+ "/quit Exit this program.\n"
+ );
+ } else
fprintf(stderr, "Unknown command '/%s'\n", buf);
- }
}
static void parse_input(meshlink::mesh *mesh, char *buf) {
}
//Test mesh sending data
-static void testmesh () {
+static void testmesh() {
for(int nindex = 0; nindex < n; nindex++) {
- nodes = meshlink_get_all_nodes(mesh[nindex], nodes, &nnodes);
- if(!nodes) {
- fprintf(stderr, "Could not get list of nodes: %s\n", meshlink_strerror(meshlink_errno));
- } else {
- printf("%zu known nodes:\n", nnodes);
- for(int i = 0; i < nnodes; i++) {
- //printf(" %s\n", nodes[i]->name);
- if(!meshlink_send(mesh[nindex], nodes[i], "magic", strlen("magic") + 1)) {
- fprintf(stderr, "Could not send message to '%s': %s\n", nodes[i]->name, meshlink_strerror(meshlink_errno));
- }
- }
-
+ nodes = meshlink_get_all_nodes(mesh[nindex], nodes, &nnodes);
+ if(!nodes)
+ fprintf(stderr, "Could not get list of nodes: %s\n", meshlink_strerror(meshlink_errno));
+ else {
+ printf("%zu known nodes:\n", nnodes);
+ for(int i = 0; i < nnodes; i++) {
+ //printf(" %s\n", nodes[i]->name);
+ if(!meshlink_send(mesh[nindex], nodes[i], "magic", strlen("magic") + 1))
+ fprintf(stderr, "Could not send message to '%s': %s\n", nodes[i]->name, meshlink_strerror(meshlink_errno));
}
+ }
+
}
}
// Make all nodes know about each other by importing each others public keys and addresses.
}
}
-static bool exportmeshgraph(const char* path)
-{
+static bool exportmeshgraph(const char* path) {
struct stat ps;
int psr = stat(path, &ps);
- if(psr == 0 || errno != ENOENT)
- {
+ if(psr == 0 || errno != ENOENT) {
if(psr == -1)
- { perror("stat"); }
+ perror("stat");
else
- { fprintf(stderr, "%s exists already\n", path); }
+ fprintf(stderr, "%s exists already\n", path);
return false;
}
FILE* stream = fopen(path, "w");
- if(!stream)
- {
+ if(!stream) {
perror("stream");
return false;
}
- if(!devtool_export_json_all_edges_state(mesh[0], stream))
- {
+ if(!devtool_export_json_all_edges_state(mesh[0], stream)) {
fclose(stream);
fprintf(stderr, "could not export graph\n");
return false;
}
-void exportmeshgraph_timer(int signum)
-{
+void exportmeshgraph_timer(int signum) {
struct timeval ts;
gettimeofday(&ts, NULL);
#ifndef _WIN32
static bool exportmeshgraph_started = false;
-static bool exportmeshgraph_end(const char* none)
-{
+static bool exportmeshgraph_end(const char* none) {
if(!exportmeshgraph_started)
- { return false; }
+ return false;
struct itimerval zero_timer = { 0 };
- setitimer (ITIMER_REAL, &zero_timer, NULL);
+ setitimer(ITIMER_REAL, &zero_timer, NULL);
exportmeshgraph_started = false;
return true;
}
-static bool exportmeshgraph_begin(const char* timeout_str)
-{
+static bool exportmeshgraph_begin(const char* timeout_str) {
if(!timeout_str)
return false;
- if(exportmeshgraph_started)
- {
+ if(exportmeshgraph_started) {
if(!exportmeshgraph_end(NULL))
return false;
}
int timeout = atoi(timeout_str);
if(timeout < 100)
- { timeout = 100; }
+ timeout = 100;
int timeout_sec = timeout / 1000;
int timeout_msec = timeout % 1000;
timer.it_interval.tv_usec = timeout_msec * 1000;
/* Start a real timer. */
- setitimer (ITIMER_REAL, &timer, NULL);
+ setitimer(ITIMER_REAL, &timer, NULL);
exportmeshgraph_started = true;
return true;
}
#else
-static bool exportmeshgraph_end(const char* none)
-{
+static bool exportmeshgraph_end(const char* none) {
return false;
}
-static bool exportmeshgraph_begin(const char* timeout_str)
-{
+static bool exportmeshgraph_begin(const char* timeout_str) {
return false;
}
#endif
meshlink_stop(mesh[nodeindex]);
if(!meshlink_join(mesh[nodeindex], arg))
fprintf(stderr, "Could not join using invitation: %s\n", meshlink_strerror(meshlink_errno));
- else {
+ else
fprintf(stderr, "Invitation accepted!\n");
- }
if(!meshlink_start(mesh[nodeindex])) {
fprintf(stderr, "Could not restart MeshLink: %s\n", meshlink_strerror(meshlink_errno));
exit(1);
} else if(!strcasecmp(buf, "who")) {
if(!arg) {
nodes = meshlink_get_all_nodes(mesh[nodeindex], nodes, &nnodes);
- if(!nodes) {
+ if(!nodes)
fprintf(stderr, "Could not get list of nodes: %s\n", meshlink_strerror(meshlink_errno));
- } else {
+ else {
printf("%zu known nodes:", nnodes);
for(int i = 0; i < nnodes; i++)
printf(" %s", nodes[i]->name);
}
} else {
meshlink_node_t *node = meshlink_get_node(mesh[nodeindex], arg);
- if(!node) {
+ if(!node)
fprintf(stderr, "Unknown node '%s'\n", arg);
- } else {
+ else
printf("Node %s found, pmtu %zd\n", arg, meshlink_get_pmtu(mesh[nodeindex], node));
- }
}
- } else if(!strcasecmp(buf, "link")) {
+ } else if(!strcasecmp(buf, "link"))
linkmesh();
- } else if(!strcasecmp(buf, "eg")) {
+ else if(!strcasecmp(buf, "eg"))
exportmeshgraph(arg);
- } else if(!strcasecmp(buf, "egb")) {
+ else if(!strcasecmp(buf, "egb"))
exportmeshgraph_begin(arg);
- } else if(!strcasecmp(buf, "ege")) {
+ else if(!strcasecmp(buf, "ege"))
exportmeshgraph_end(NULL);
- } else if(!strcasecmp(buf, "test")) {
+ else if(!strcasecmp(buf, "test"))
testmesh();
- } else if(!strcasecmp(buf, "select")) {
+ else if(!strcasecmp(buf, "select")) {
if(!arg) {
fprintf(stderr, "/select requires an argument!\n");
return;
}
nodeindex = atoi(arg);
printf("Index is now %d\n",nodeindex);
- } else if(!strcasecmp(buf, "stop")) {
+ } else if(!strcasecmp(buf, "stop"))
meshlink_stop(mesh[nodeindex]);
- } else if(!strcasecmp(buf, "quit")) {
+ else if(!strcasecmp(buf, "quit")) {
printf("Bye!\n");
fclose(stdin);
} else if(!strcasecmp(buf, "help")) {
printf(
- "<name>: <message> Send a message to the given node.\n"
- " Subsequent messages don't need the <name>: prefix.\n"
- "/invite <name> Create an invitation for a new node.\n"
- "/join <invitation> Join an existing mesh using an invitation.\n"
- "/kick <name> Blacklist the given node.\n"
- "/who [<name>] List all nodes or show information about the given node.\n"
- "/link Link all nodes together.\n"
- "/eg <path> Export graph as json file.\n"
- "/test Test functionality sending some data to all nodes\n"
- "/select <number> Select the active node running the user commands\n"
- "/stop Call meshlink_stop, use /select first to select which node to stop\n"
- "/quit Exit this program.\n"
- );
- } else {
+ "<name>: <message> Send a message to the given node.\n"
+ " Subsequent messages don't need the <name>: prefix.\n"
+ "/invite <name> Create an invitation for a new node.\n"
+ "/join <invitation> Join an existing mesh using an invitation.\n"
+ "/kick <name> Blacklist the given node.\n"
+ "/who [<name>] List all nodes or show information about the given node.\n"
+ "/link Link all nodes together.\n"
+ "/eg <path> Export graph as json file.\n"
+ "/test Test functionality sending some data to all nodes\n"
+ "/select <number> Select the active node running the user commands\n"
+ "/stop Call meshlink_stop, use /select first to select which node to stop\n"
+ "/quit Exit this program.\n"
+ );
+ } else
fprintf(stderr, "Unknown command '/%s'\n", buf);
- }
}
static void parse_input(char *buf) {
snprintf(nodename, sizeof nodename, "%snode%d", namesprefix,i);
snprintf(filename, sizeof filename, "%s/%s", basebase, nodename);
bool itsnew = access(filename, R_OK);
- if (n/(i+1) > n/4) {
+ if(n/(i+1) > n/4)
mesh[i] = meshlink_open(filename, nodename, "manynodes", DEV_CLASS_BACKBONE);
- }
- else {
+ else
mesh[i] = meshlink_open(filename, nodename, "manynodes", DEV_CLASS_PORTABLE);
- }
meshlink_set_log_cb(mesh[i], MESHLINK_DEBUG, log_message);
if(!mesh[i]) {
fprintf(stderr, "errno is: %d\n", meshlink_errno);
}
if(graphexporttimeout)
- { exportmeshgraph_begin(graphexporttimeout); }
+ exportmeshgraph_begin(graphexporttimeout);
printf("%d nodes started.\nType /help for a list of commands.\n", started);
printf("Received %zu bytes from %s: %s\n", len, source->name, (char*)data);
}
-int main(int argc , char **argv){
+int main(int argc, char **argv) {
char *confbase = argc > 1 ? argv[1] : "/tmp/meshlink/";
char *name = argc > 2 ? argv[2] : "foo";
}
logger(NULL, MESHLINK_ERROR, "\"yes\" or \"no\" expected for configuration variable %s in %s line %d",
- cfg->variable, cfg->file, cfg->line);
+ cfg->variable, cfg->file, cfg->line);
return false;
}
return true;
logger(NULL, MESHLINK_ERROR, "Integer expected for configuration variable %s in %s line %d",
- cfg->variable, cfg->file, cfg->line);
+ cfg->variable, cfg->file, cfg->line);
return false;
}
-bool set_config_int(config_t *cfg, int val)
-{
+bool set_config_int(config_t *cfg, int val) {
if(!cfg)
return false;
return true;
}
-bool set_config_string(config_t *cfg, const char* val)
-{
+bool set_config_string(config_t *cfg, const char* val) {
if(!cfg)
return false;
}
logger(NULL, MESHLINK_ERROR, "Hostname or IP address expected for configuration variable %s in %s line %d",
- cfg->variable, cfg->file, cfg->line);
+ cfg->variable, cfg->file, cfg->line);
return false;
}
if(!*value) {
const char err[] = "No value for variable";
logger(NULL, MESHLINK_ERROR, "%s `%s' on line %d while reading config file %s",
- err, variable, lineno, fname);
+ err, variable, lineno, fname);
return NULL;
}
}
cfg = parse_config_line(line, fname, lineno);
- if (!cfg)
+ if(!cfg)
break;
config_add(config_tree, cfg);
}
return result;
}
-bool write_config_file(const struct splay_tree_t *config_tree, const char *fname)
-{
+bool write_config_file(const struct splay_tree_t *config_tree, const char *fname) {
FILE *fp;
fp = fopen(fname, "w+");
return false;
}
- for splay_each(config_t, cnf, config_tree)
- {
+ for splay_each(config_t, cnf, config_tree) {
if(fwrite(cnf->variable, sizeof(char), strlen(cnf->variable), fp) < strlen(cnf->variable))
goto error;
return x;
}
-bool write_host_config(struct meshlink_handle *mesh, const struct splay_tree_t *config_tree, const char *name)
-{
+bool write_host_config(struct meshlink_handle *mesh, const struct splay_tree_t *config_tree, const char *name) {
char filename[PATH_MAX];
snprintf(filename,PATH_MAX, "%s" SLASH "hosts" SLASH "%s", mesh->confbase, name);
extern void init_configuration(struct splay_tree_t **);
extern void exit_configuration(struct splay_tree_t **);
-extern config_t *new_config(void) __attribute__ ((__malloc__));
+extern config_t *new_config(void) __attribute__((__malloc__));
extern void free_config(config_t *);
extern void config_add(struct splay_tree_t *, config_t *);
extern config_t *lookup_config(struct splay_tree_t *, char *);
#define OPTION_VERSION(x) ((x) >> 24) /* Top 8 bits are for protocol minor version */
typedef struct connection_status_t {
- unsigned int pinged:1; /* sent ping */
- unsigned int active:1; /* 1 if active.. */
- unsigned int connecting:1; /* 1 if we are waiting for a non-blocking connect() to finish */
- unsigned int unused_termreq:1; /* the termination of this connection was requested */
- unsigned int remove_unused:1; /* Set to 1 if you want this connection removed */
- unsigned int timeout_unused:1; /* 1 if gotten timeout */
- unsigned int unused_encryptout:1; /* 1 if we can encrypt outgoing traffic */
- unsigned int unused_decryptin:1; /* 1 if we have to decrypt incoming traffic */
- unsigned int mst:1; /* 1 if this connection is part of a minimum spanning tree */
- unsigned int control:1; /* 1 if this is a control connection */
- unsigned int pcap:1; /* 1 if this is a control connection requesting packet capture */
- unsigned int log:1; /* 1 if this is a control connection requesting log dump */
- unsigned int invitation:1; /* 1 if this is an invitation */
- unsigned int invitation_used:1; /* 1 if the invitation has been consumed */
- unsigned int unused:19;
+ unsigned int pinged:1; /* sent ping */
+ unsigned int active:1; /* 1 if active.. */
+ unsigned int connecting:1; /* 1 if we are waiting for a non-blocking connect() to finish */
+ unsigned int unused_termreq:1; /* the termination of this connection was requested */
+ unsigned int remove_unused:1; /* Set to 1 if you want this connection removed */
+ unsigned int timeout_unused:1; /* 1 if gotten timeout */
+ unsigned int unused_encryptout:1; /* 1 if we can encrypt outgoing traffic */
+ unsigned int unused_decryptin:1; /* 1 if we have to decrypt incoming traffic */
+ unsigned int mst:1; /* 1 if this connection is part of a minimum spanning tree */
+ unsigned int control:1; /* 1 if this is a control connection */
+ unsigned int pcap:1; /* 1 if this is a control connection requesting packet capture */
+ unsigned int log:1; /* 1 if this is a control connection requesting log dump */
+ unsigned int invitation:1; /* 1 if this is an invitation */
+ unsigned int invitation_used:1; /* 1 if the invitation has been consumed */
+ unsigned int unused:19;
} connection_status_t;
#include "ecdsa.h"
extern void init_connections(struct meshlink_handle *mesh);
extern void exit_connections(struct meshlink_handle *mesh);
-extern connection_t *new_connection(void) __attribute__ ((__malloc__));
+extern connection_t *new_connection(void) __attribute__((__malloc__));
extern void free_connection(connection_t *);
extern void connection_add(struct meshlink_handle *mesh, connection_t *);
extern void connection_del(struct meshlink_handle *mesh, connection_t *);
#include "devtools.h"
-static int node_compare(const void *a, const void *b)
-{
+static int node_compare(const void *a, const void *b) {
if(a < b)
return -1;
return 0;
}
-static bool fstrwrite(const char* str, FILE* stream)
-{
+static bool fstrwrite(const char* str, FILE* stream) {
size_t len = strlen(str);
if(fwrite((void*)str, 1, len, stream) != len)
return true;
}
-static const char* __itoa(int value)
-{
- static char buffer[sizeof(int) * 8 + 1]; // not thread safe
+static const char* __itoa(int value) {
+ static char buffer[sizeof(int) * 8 + 1]; // not thread safe
if(snprintf(buffer, sizeof(buffer), "%d", value) == -1)
return "";
return buffer;
}
-bool devtool_export_json_all_edges_state(meshlink_handle_t *mesh, FILE* stream)
-{
+bool devtool_export_json_all_edges_state(meshlink_handle_t *mesh, FILE* stream) {
bool result = true;
pthread_mutex_lock(&(mesh->mesh_mutex));
meshlink_edge_t **edges = meshlink_get_all_edges_state(mesh, NULL, &edge_count);
if((!nodes && node_count != 0) || (!edges && edge_count != 0))
- { goto fail; }
+ goto fail;
// export begin
if(!fstrwrite("{\n", stream))
if(!fstrwrite("\t\"nodes\": {\n", stream))
goto fail;
- for(size_t i = 0; i < node_count; ++i)
- {
+ for(size_t i = 0; i < node_count; ++i) {
if(!fstrwrite("\t\t\"", stream) || !fstrwrite(((node_t*)nodes[i])->name, stream) || !fstrwrite("\": {\n", stream))
goto fail;
if(!fstrwrite("\t\"edges\": {\n", stream))
goto fail;
- for(size_t i = 0; i < edge_count; ++i)
- {
+ 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))
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);
- if(!fstrwrite("\t\t\t\"address\": ", stream) || !fstrwrite(address ? address : "null", stream) || !fstrwrite(",\n", stream))
- {
+ if(!fstrwrite("\t\t\t\"address\": ", stream) || !fstrwrite(address ? address : "null", stream) || !fstrwrite(",\n", stream)) {
free(address);
goto fail;
}
done:
if(nodes)
- { free(nodes); }
+ free(nodes);
for(size_t i = 0; edges && i < edge_count; ++i)
- { free(edges[i]); }
+ free(edges[i]);
if(nodes)
- { free(edges); }
+ free(edges);
pthread_mutex_unlock(&(mesh->mesh_mutex));
#define MESHLINK_MDNS_NAME_KEY "name"
#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)
- {
- buffer[i] = 'a' + (rand() % ('z' - 'a' + 1));
- }
-
- buffer[size-1] = '\0';
+static void generate_rand_string(char* buffer, size_t size) {
+ for(size_t i = 0; i < (size - 1); ++i)
+ buffer[i] = 'a' + (rand() % ('z' - 'a' + 1));
+
+ buffer[size-1] = '\0';
}
-static void discovery_entry_group_callback(CattaServer *server, CattaSEntryGroup *group, CattaEntryGroupState state, void *userdata)
-{
- meshlink_handle_t *mesh = userdata;
-
- // asserts
- assert(mesh != NULL);
- assert(mesh->catta_server != NULL);
- assert(mesh->catta_poll != NULL);
-
- pthread_mutex_lock(&(mesh->mesh_mutex));
-
- /* Called whenever the entry group state changes */
- switch(state)
- {
- case CATTA_ENTRY_GROUP_ESTABLISHED:
- /* The entry group has been established successfully */
- logger(mesh, MESHLINK_DEBUG, "Catta Service successfully established.\n");
- break;
-
- case CATTA_ENTRY_GROUP_COLLISION:
- logger(mesh, MESHLINK_WARNING, "Catta Service collision.\n");
- // @TODO can we just set a new name and retry?
- break;
-
- case CATTA_ENTRY_GROUP_FAILURE :
- /* Some kind of failure happened while we were registering our services */
- logger(mesh, MESHLINK_ERROR, "Catta Entry group failure: %s\n", catta_strerror(catta_server_errno(mesh->catta_server)));
- catta_simple_poll_quit(mesh->catta_poll);
- break;
-
- case CATTA_ENTRY_GROUP_UNCOMMITED:
- case CATTA_ENTRY_GROUP_REGISTERING:
- ;
- }
-
- pthread_mutex_unlock(&(mesh->mesh_mutex));
+static void discovery_entry_group_callback(CattaServer *server, CattaSEntryGroup *group, CattaEntryGroupState state, void *userdata) {
+ meshlink_handle_t *mesh = userdata;
+
+ // asserts
+ assert(mesh != NULL);
+ assert(mesh->catta_server != NULL);
+ assert(mesh->catta_poll != NULL);
+
+ pthread_mutex_lock(&(mesh->mesh_mutex));
+
+ /* Called whenever the entry group state changes */
+ switch(state) {
+ case CATTA_ENTRY_GROUP_ESTABLISHED:
+ /* The entry group has been established successfully */
+ logger(mesh, MESHLINK_DEBUG, "Catta Service successfully established.\n");
+ break;
+
+ case CATTA_ENTRY_GROUP_COLLISION:
+ logger(mesh, MESHLINK_WARNING, "Catta Service collision.\n");
+ // @TODO can we just set a new name and retry?
+ break;
+
+ case CATTA_ENTRY_GROUP_FAILURE :
+ /* Some kind of failure happened while we were registering our services */
+ logger(mesh, MESHLINK_ERROR, "Catta Entry group failure: %s\n", catta_strerror(catta_server_errno(mesh->catta_server)));
+ catta_simple_poll_quit(mesh->catta_poll);
+ break;
+
+ case CATTA_ENTRY_GROUP_UNCOMMITED:
+ case CATTA_ENTRY_GROUP_REGISTERING:
+ ;
+ }
+
+ pthread_mutex_unlock(&(mesh->mesh_mutex));
}
-static void discovery_create_services(meshlink_handle_t *mesh)
-{
- char *txt_name = NULL;
-
- // asserts
- assert(mesh != NULL);
- assert(mesh->name != NULL);
- assert(mesh->myport != NULL);
- assert(mesh->catta_server != NULL);
- assert(mesh->catta_poll != NULL);
- assert(mesh->catta_servicetype != NULL);
- assert(mesh->self != NULL);
-
- pthread_mutex_lock(&(mesh->mesh_mutex));
-
- logger(mesh, MESHLINK_DEBUG, "Adding service\n");
-
- /* Ifthis is the first time we're called, let's create a new entry group */
- if(!mesh->catta_group)
- {
- if(!(mesh->catta_group = catta_s_entry_group_new(mesh->catta_server, discovery_entry_group_callback, mesh)))
- {
- logger(mesh, MESHLINK_ERROR, "catta_entry_group_new() failed: %s\n", catta_strerror(catta_server_errno(mesh->catta_server)));
- goto fail;
- }
- }
-
- /* Create txt records */
- size_t txt_name_len = sizeof(MESHLINK_MDNS_NAME_KEY) + 1 + strlen(mesh->name) + 1;
- txt_name = malloc(txt_name_len);
-
- if(txt_name == NULL)
- {
- logger(mesh, MESHLINK_ERROR, "Could not allocate memory for TXT record\n");
- goto fail;
- }
-
- snprintf(txt_name, txt_name_len, "%s=%s", MESHLINK_MDNS_NAME_KEY, mesh->name);
-
- char txt_fingerprint[sizeof(MESHLINK_MDNS_FINGERPRINT_KEY) + 1 + MESHLINK_FINGERPRINTLEN + 1];
- snprintf(txt_fingerprint, sizeof(txt_fingerprint), "%s=%s", MESHLINK_MDNS_FINGERPRINT_KEY, meshlink_get_fingerprint(mesh, (meshlink_node_t *)mesh->self));
-
- /* 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;
- }
-
- /* Tell the server to register the service */
- if((ret = catta_s_entry_group_commit(mesh->catta_group)) < 0)
- {
- logger(mesh, MESHLINK_ERROR, "Failed to commit entry_group: %s\n", catta_strerror(ret));
- goto fail;
- }
-
- goto done;
+static void discovery_create_services(meshlink_handle_t *mesh) {
+ char *txt_name = NULL;
+
+ // asserts
+ assert(mesh != NULL);
+ assert(mesh->name != NULL);
+ assert(mesh->myport != NULL);
+ assert(mesh->catta_server != NULL);
+ assert(mesh->catta_poll != NULL);
+ assert(mesh->catta_servicetype != NULL);
+ assert(mesh->self != NULL);
+
+ pthread_mutex_lock(&(mesh->mesh_mutex));
+
+ logger(mesh, MESHLINK_DEBUG, "Adding service\n");
+
+ /* Ifthis is the first time we're called, let's create a new entry group */
+ if(!mesh->catta_group) {
+ if(!(mesh->catta_group = catta_s_entry_group_new(mesh->catta_server, discovery_entry_group_callback, mesh))) {
+ logger(mesh, MESHLINK_ERROR, "catta_entry_group_new() failed: %s\n", catta_strerror(catta_server_errno(mesh->catta_server)));
+ goto fail;
+ }
+ }
+
+ /* Create txt records */
+ size_t txt_name_len = sizeof(MESHLINK_MDNS_NAME_KEY) + 1 + strlen(mesh->name) + 1;
+ txt_name = malloc(txt_name_len);
+
+ if(txt_name == NULL) {
+ logger(mesh, MESHLINK_ERROR, "Could not allocate memory for TXT record\n");
+ goto fail;
+ }
+
+ snprintf(txt_name, txt_name_len, "%s=%s", MESHLINK_MDNS_NAME_KEY, mesh->name);
+
+ char txt_fingerprint[sizeof(MESHLINK_MDNS_FINGERPRINT_KEY) + 1 + MESHLINK_FINGERPRINTLEN + 1];
+ snprintf(txt_fingerprint, sizeof(txt_fingerprint), "%s=%s", MESHLINK_MDNS_FINGERPRINT_KEY, meshlink_get_fingerprint(mesh, (meshlink_node_t *)mesh->self));
+
+ /* 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;
+ }
+
+ /* Tell the server to register the service */
+ if((ret = catta_s_entry_group_commit(mesh->catta_group)) < 0) {
+ logger(mesh, MESHLINK_ERROR, "Failed to commit entry_group: %s\n", catta_strerror(ret));
+ goto fail;
+ }
+
+ goto done;
fail:
- catta_simple_poll_quit(mesh->catta_poll);
+ catta_simple_poll_quit(mesh->catta_poll);
done:
- if(txt_name)
- { free(txt_name); }
+ if(txt_name)
+ free(txt_name);
- pthread_mutex_unlock(&(mesh->mesh_mutex));
+ pthread_mutex_unlock(&(mesh->mesh_mutex));
}
-static void discovery_server_callback(CattaServer *server, CattaServerState state, void * userdata)
-{
+static void discovery_server_callback(CattaServer *server, CattaServerState state, void * userdata) {
meshlink_handle_t *mesh = userdata;
- // asserts
- assert(mesh != NULL);
-
- pthread_mutex_lock(&(mesh->mesh_mutex));
-
- switch(state)
- {
- 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)
- {
- discovery_create_services(mesh);
- }
- }
- break;
-
- case CATTA_SERVER_COLLISION:
- {
- // asserts
- assert(mesh->catta_server != NULL);
- assert(mesh->catta_poll != NULL);
-
- /* A host name collision happened. Let's pick a new name for the server */
- char hostname[17];
- generate_rand_string(hostname, sizeof(hostname));
-
- logger(mesh, MESHLINK_WARNING, "Catta host name collision, retrying with '%s'\n", hostname);
- int result = catta_server_set_host_name(mesh->catta_server, hostname);
-
- if(result < 0)
- {
- logger(mesh, MESHLINK_ERROR, "Catta failed to set new host name: %s\n", catta_strerror(result));
- catta_simple_poll_quit(mesh->catta_poll);
- }
- }
- break;
-
- case CATTA_SERVER_REGISTERING:
- {
- /* Let's drop our registered services. When the server is back
- * in CATTA_SERVER_RUNNING state we will register them
- * again with the new host name. */
- if(mesh->catta_group)
- {
- catta_s_entry_group_reset(mesh->catta_group);
- mesh->catta_group = NULL;
- }
- }
- break;
-
- case CATTA_SERVER_FAILURE:
- {
- // asserts
- assert(mesh->catta_server != NULL);
- assert(mesh->catta_poll != NULL);
-
- /* Terminate on failure */
- logger(mesh, MESHLINK_ERROR, "Catta server failure: %s\n", catta_strerror(catta_server_errno(mesh->catta_server)));
- catta_simple_poll_quit(mesh->catta_poll);
- }
- break;
-
- case CATTA_SERVER_INVALID:
- break;
- }
-
- pthread_mutex_unlock(&(mesh->mesh_mutex));
+ // asserts
+ assert(mesh != NULL);
+
+ pthread_mutex_lock(&(mesh->mesh_mutex));
+
+ switch(state) {
+ 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)
+ discovery_create_services(mesh);
+ }
+ break;
+
+ case CATTA_SERVER_COLLISION: {
+ // asserts
+ assert(mesh->catta_server != NULL);
+ assert(mesh->catta_poll != NULL);
+
+ /* A host name collision happened. Let's pick a new name for the server */
+ char hostname[17];
+ generate_rand_string(hostname, sizeof(hostname));
+
+ logger(mesh, MESHLINK_WARNING, "Catta host name collision, retrying with '%s'\n", hostname);
+ int result = catta_server_set_host_name(mesh->catta_server, hostname);
+
+ if(result < 0) {
+ logger(mesh, MESHLINK_ERROR, "Catta failed to set new host name: %s\n", catta_strerror(result));
+ catta_simple_poll_quit(mesh->catta_poll);
+ }
+ }
+ break;
+
+ case CATTA_SERVER_REGISTERING: {
+ /* Let's drop our registered services. When the server is back
+ * in CATTA_SERVER_RUNNING state we will register them
+ * again with the new host name. */
+ if(mesh->catta_group) {
+ catta_s_entry_group_reset(mesh->catta_group);
+ mesh->catta_group = NULL;
+ }
+ }
+ break;
+
+ case CATTA_SERVER_FAILURE: {
+ // asserts
+ assert(mesh->catta_server != NULL);
+ assert(mesh->catta_poll != NULL);
+
+ /* Terminate on failure */
+ logger(mesh, MESHLINK_ERROR, "Catta server failure: %s\n", catta_strerror(catta_server_errno(mesh->catta_server)));
+ catta_simple_poll_quit(mesh->catta_poll);
+ }
+ break;
+
+ case CATTA_SERVER_INVALID:
+ break;
+ }
+
+ pthread_mutex_unlock(&(mesh->mesh_mutex));
}
-static void discovery_resolve_callback(CattaSServiceResolver *resolver, CattaIfIndex interface_, CattaProtocol protocol, CattaResolverEvent event, const char *name, const char *type, const char *domain, const char *host_name, const CattaAddress *address, uint16_t port, CattaStringList *txt, CattaLookupResultFlags flags, void *userdata)
-{
- meshlink_handle_t *mesh = userdata;
-
- // asserts
- assert(resolver != NULL);
- assert(mesh != NULL);
- assert(mesh->catta_server != NULL);
-
- pthread_mutex_lock(&(mesh->mesh_mutex));
-
- /* Called whenever a service has been resolved successfully or timed out */
- switch(event)
- {
- case CATTA_RESOLVER_FAILURE:
- {
- // asserts
- assert(name != NULL);
- assert(type != NULL);
- assert(domain != NULL);
-
- logger(mesh, MESHLINK_WARNING, "(Resolver) Failed to resolve service '%s' of type '%s' in domain '%s': %s\n", name, type, domain, catta_strerror(catta_server_errno(mesh->catta_server)));
- }
- break;
-
- case CATTA_RESOLVER_FOUND:
- {
- // asserts
- assert(name != NULL);
- assert(type != NULL);
- assert(domain != NULL);
- assert(host_name != NULL);
- assert(address != NULL);
- assert(txt != NULL);
-
- char straddr[CATTA_ADDRESS_STR_MAX], *strtxt;
-
- logger(mesh, MESHLINK_DEBUG, "(Resolver) Service '%s' of type '%s' in domain '%s':\n", name, type, domain);
-
- catta_address_snprint(straddr, sizeof(straddr), address);
- strtxt = catta_string_list_to_string(txt);
- logger(mesh, MESHLINK_DEBUG,
- "\t%s:%u (%s)\n"
- "\tTXT=%s\n"
- "\tcookie is %u\n"
- "\tis_local: %i\n"
- "\twide_area: %i\n"
- "\tmulticast: %i\n"
- "\tcached: %i\n",
- host_name, port, straddr,
- strtxt,
- catta_string_list_get_service_cookie(txt),
- !!(flags & CATTA_LOOKUP_RESULT_LOCAL),
- !!(flags & CATTA_LOOKUP_RESULT_WIDE_AREA),
- !!(flags & CATTA_LOOKUP_RESULT_MULTICAST),
- !!(flags & CATTA_LOOKUP_RESULT_CACHED));
- catta_free(strtxt);
-
- // retrieve fingerprint
- CattaStringList *node_name_li = catta_string_list_find(txt, MESHLINK_MDNS_NAME_KEY);
- CattaStringList *node_fp_li = catta_string_list_find(txt, MESHLINK_MDNS_FINGERPRINT_KEY);
-
- if(node_name_li != NULL && node_fp_li != NULL)
- {
- char *node_name = (char*)catta_string_list_get_text(node_name_li) + strlen(MESHLINK_MDNS_NAME_KEY);
- char *node_fp = (char*)catta_string_list_get_text(node_fp_li) + strlen(MESHLINK_MDNS_FINGERPRINT_KEY);
-
- if(node_name[0] == '=' && node_fp[0] == '=')
- {
- node_name += 1;
- node_fp += 1;
-
- meshlink_node_t *node = meshlink_get_node(mesh, node_name);
-
- if(node != NULL)
- {
- logger(mesh, MESHLINK_INFO, "Node %s is part of the mesh network.\n", node->name);
-
- sockaddr_t naddress;
- memset(&naddress, 0, sizeof(naddress));
-
- switch(address->proto)
- {
- case CATTA_PROTO_INET:
- {
- naddress.in.sin_family = AF_INET;
- naddress.in.sin_port = htons(port);
- naddress.in.sin_addr.s_addr = address->data.ipv4.address;
- }
- break;
-
- case CATTA_PROTO_INET6:
- {
- naddress.in6.sin6_family = AF_INET6;
- naddress.in6.sin6_port = htons(port);
- memcpy(naddress.in6.sin6_addr.s6_addr, address->data.ipv6.address, sizeof(naddress.in6.sin6_addr.s6_addr));
- }
- break;
-
- default:
- naddress.unknown.family = AF_UNKNOWN;
- break;
- }
-
- if(naddress.unknown.family != AF_UNKNOWN)
- {
- meshlink_hint_address(mesh, (meshlink_node_t *)node, (struct sockaddr*)&naddress);
- }
- else
- {
- logger(mesh, MESHLINK_WARNING, "Could not resolve node %s to a known address family type.\n", node->name);
- }
- }
- else
- {
- logger(mesh, MESHLINK_WARNING, "Node %s is not part of the mesh network.\n", node_name);
- }
- }
- else
- {
- logger(mesh, MESHLINK_WARNING, "TXT records invalid.\n");
- }
- }
- else
- {
- logger(mesh, MESHLINK_WARNING, "TXT records missing.\n");
- }
- }
- break;
- }
-
- catta_s_service_resolver_free(resolver);
-
- pthread_mutex_unlock(&(mesh->mesh_mutex));
+static void discovery_resolve_callback(CattaSServiceResolver *resolver, CattaIfIndex interface_, CattaProtocol protocol, CattaResolverEvent event, const char *name, const char *type, const char *domain, const char *host_name, const CattaAddress *address, uint16_t port, CattaStringList *txt, CattaLookupResultFlags flags, void *userdata) {
+ meshlink_handle_t *mesh = userdata;
+
+ // asserts
+ assert(resolver != NULL);
+ assert(mesh != NULL);
+ assert(mesh->catta_server != NULL);
+
+ pthread_mutex_lock(&(mesh->mesh_mutex));
+
+ /* Called whenever a service has been resolved successfully or timed out */
+ switch(event) {
+ case CATTA_RESOLVER_FAILURE: {
+ // asserts
+ assert(name != NULL);
+ assert(type != NULL);
+ assert(domain != NULL);
+
+ logger(mesh, MESHLINK_WARNING, "(Resolver) Failed to resolve service '%s' of type '%s' in domain '%s': %s\n", name, type, domain, catta_strerror(catta_server_errno(mesh->catta_server)));
+ }
+ break;
+
+ case CATTA_RESOLVER_FOUND: {
+ // asserts
+ assert(name != NULL);
+ assert(type != NULL);
+ assert(domain != NULL);
+ assert(host_name != NULL);
+ assert(address != NULL);
+ assert(txt != NULL);
+
+ char straddr[CATTA_ADDRESS_STR_MAX], *strtxt;
+
+ logger(mesh, MESHLINK_DEBUG, "(Resolver) Service '%s' of type '%s' in domain '%s':\n", name, type, domain);
+
+ catta_address_snprint(straddr, sizeof(straddr), address);
+ strtxt = catta_string_list_to_string(txt);
+ logger(mesh, MESHLINK_DEBUG,
+ "\t%s:%u (%s)\n"
+ "\tTXT=%s\n"
+ "\tcookie is %u\n"
+ "\tis_local: %i\n"
+ "\twide_area: %i\n"
+ "\tmulticast: %i\n"
+ "\tcached: %i\n",
+ host_name, port, straddr,
+ strtxt,
+ catta_string_list_get_service_cookie(txt),
+ !!(flags & CATTA_LOOKUP_RESULT_LOCAL),
+ !!(flags & CATTA_LOOKUP_RESULT_WIDE_AREA),
+ !!(flags & CATTA_LOOKUP_RESULT_MULTICAST),
+ !!(flags & CATTA_LOOKUP_RESULT_CACHED));
+ catta_free(strtxt);
+
+ // retrieve fingerprint
+ CattaStringList *node_name_li = catta_string_list_find(txt, MESHLINK_MDNS_NAME_KEY);
+ CattaStringList *node_fp_li = catta_string_list_find(txt, MESHLINK_MDNS_FINGERPRINT_KEY);
+
+ if(node_name_li != NULL && node_fp_li != NULL) {
+ char *node_name = (char*)catta_string_list_get_text(node_name_li) + strlen(MESHLINK_MDNS_NAME_KEY);
+ char *node_fp = (char*)catta_string_list_get_text(node_fp_li) + strlen(MESHLINK_MDNS_FINGERPRINT_KEY);
+
+ if(node_name[0] == '=' && node_fp[0] == '=') {
+ node_name += 1;
+ node_fp += 1;
+
+ meshlink_node_t *node = meshlink_get_node(mesh, node_name);
+
+ if(node != NULL) {
+ logger(mesh, MESHLINK_INFO, "Node %s is part of the mesh network.\n", node->name);
+
+ sockaddr_t naddress;
+ memset(&naddress, 0, sizeof(naddress));
+
+ switch(address->proto) {
+ case CATTA_PROTO_INET: {
+ naddress.in.sin_family = AF_INET;
+ naddress.in.sin_port = htons(port);
+ naddress.in.sin_addr.s_addr = address->data.ipv4.address;
+ }
+ break;
+
+ case CATTA_PROTO_INET6: {
+ naddress.in6.sin6_family = AF_INET6;
+ naddress.in6.sin6_port = htons(port);
+ memcpy(naddress.in6.sin6_addr.s6_addr, address->data.ipv6.address, sizeof(naddress.in6.sin6_addr.s6_addr));
+ }
+ break;
+
+ default:
+ naddress.unknown.family = AF_UNKNOWN;
+ break;
+ }
+
+ if(naddress.unknown.family != AF_UNKNOWN)
+ meshlink_hint_address(mesh, (meshlink_node_t *)node, (struct sockaddr*)&naddress);
+ else
+ logger(mesh, MESHLINK_WARNING, "Could not resolve node %s to a known address family type.\n", node->name);
+ } else
+ logger(mesh, MESHLINK_WARNING, "Node %s is not part of the mesh network.\n", node_name);
+ } else
+ logger(mesh, MESHLINK_WARNING, "TXT records invalid.\n");
+ } else
+ logger(mesh, MESHLINK_WARNING, "TXT records missing.\n");
+ }
+ break;
+ }
+
+ catta_s_service_resolver_free(resolver);
+
+ pthread_mutex_unlock(&(mesh->mesh_mutex));
}
-static void discovery_browse_callback(CattaSServiceBrowser *browser, CattaIfIndex interface_, CattaProtocol protocol, CattaBrowserEvent event, const char *name, const char *type, const char *domain, CattaLookupResultFlags flags, void* userdata)
-{
+static void discovery_browse_callback(CattaSServiceBrowser *browser, CattaIfIndex interface_, CattaProtocol protocol, CattaBrowserEvent event, const char *name, const char *type, const char *domain, CattaLookupResultFlags flags, void* userdata) {
meshlink_handle_t *mesh = userdata;
- // asserts
- assert(mesh != NULL);
- assert(mesh->catta_server != NULL);
- assert(mesh->catta_poll != NULL);
-
- pthread_mutex_lock(&(mesh->mesh_mutex));
-
- /* Called whenever a new services becomes available on the LAN or is removed from the LAN */
- switch (event)
- {
- case CATTA_BROWSER_FAILURE:
- {
- logger(mesh, MESHLINK_ERROR, "(Browser) %s\n", catta_strerror(catta_server_errno(mesh->catta_server)));
- catta_simple_poll_quit(mesh->catta_poll);
- }
- break;
-
- case CATTA_BROWSER_NEW:
- {
- // asserts
- assert(name != NULL);
- assert(type != NULL);
- 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)))
- {
- logger(mesh, MESHLINK_DEBUG, "Failed to resolve service '%s': %s\n", name, catta_strerror(catta_server_errno(mesh->catta_server)));
- }
- }
- break;
-
- case CATTA_BROWSER_REMOVE:
- {
- // asserts
- assert(name != NULL);
- assert(type != NULL);
- assert(domain != NULL);
-
- logger(mesh, MESHLINK_DEBUG, "(Browser) REMOVE: service '%s' of type '%s' in domain '%s'\n", name, type, domain);
- }
- break;
-
- case CATTA_BROWSER_ALL_FOR_NOW:
- case CATTA_BROWSER_CACHE_EXHAUSTED:
- {
- logger(mesh, MESHLINK_DEBUG, "(Browser) %s\n", event == CATTA_BROWSER_CACHE_EXHAUSTED ? "CACHE_EXHAUSTED" : "ALL_FOR_NOW");
- }
- break;
- }
-
- pthread_mutex_unlock(&(mesh->mesh_mutex));
+ // asserts
+ assert(mesh != NULL);
+ assert(mesh->catta_server != NULL);
+ assert(mesh->catta_poll != NULL);
+
+ pthread_mutex_lock(&(mesh->mesh_mutex));
+
+ /* Called whenever a new services becomes available on the LAN or is removed from the LAN */
+ switch(event) {
+ case CATTA_BROWSER_FAILURE: {
+ logger(mesh, MESHLINK_ERROR, "(Browser) %s\n", catta_strerror(catta_server_errno(mesh->catta_server)));
+ catta_simple_poll_quit(mesh->catta_poll);
+ }
+ break;
+
+ case CATTA_BROWSER_NEW: {
+ // asserts
+ assert(name != NULL);
+ assert(type != NULL);
+ 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)))
+ logger(mesh, MESHLINK_DEBUG, "Failed to resolve service '%s': %s\n", name, catta_strerror(catta_server_errno(mesh->catta_server)));
+ }
+ break;
+
+ case CATTA_BROWSER_REMOVE: {
+ // asserts
+ assert(name != NULL);
+ assert(type != NULL);
+ assert(domain != NULL);
+
+ logger(mesh, MESHLINK_DEBUG, "(Browser) REMOVE: service '%s' of type '%s' in domain '%s'\n", name, type, domain);
+ }
+ break;
+
+ case CATTA_BROWSER_ALL_FOR_NOW:
+ case CATTA_BROWSER_CACHE_EXHAUSTED: {
+ logger(mesh, MESHLINK_DEBUG, "(Browser) %s\n", event == CATTA_BROWSER_CACHE_EXHAUSTED ? "CACHE_EXHAUSTED" : "ALL_FOR_NOW");
+ }
+ break;
+ }
+
+ pthread_mutex_unlock(&(mesh->mesh_mutex));
}
-static void *discovery_loop(void *userdata)
-{
+static void *discovery_loop(void *userdata) {
meshlink_handle_t *mesh = userdata;
- // asserts
- assert(mesh != NULL);
- assert(mesh->catta_poll != NULL);
+ // asserts
+ assert(mesh != NULL);
+ assert(mesh->catta_poll != NULL);
- catta_simple_poll_loop(mesh->catta_poll);
-
- return NULL;
+ catta_simple_poll_loop(mesh->catta_poll);
+
+ return NULL;
}
-static void discovery_log_cb(CattaLogLevel level, const char *txt)
-{
- meshlink_log_level_t mlevel = MESHLINK_CRITICAL;
+static void discovery_log_cb(CattaLogLevel level, const char *txt) {
+ meshlink_log_level_t mlevel = MESHLINK_CRITICAL;
- switch(level)
- {
- case CATTA_LOG_ERROR:
- mlevel = MESHLINK_ERROR;
- break;
+ switch(level) {
+ case CATTA_LOG_ERROR:
+ mlevel = MESHLINK_ERROR;
+ break;
- case CATTA_LOG_WARN:
- mlevel = MESHLINK_WARNING;
- break;
+ case CATTA_LOG_WARN:
+ mlevel = MESHLINK_WARNING;
+ break;
- case CATTA_LOG_NOTICE:
- case CATTA_LOG_INFO:
- mlevel = MESHLINK_INFO;
- break;
+ case CATTA_LOG_NOTICE:
+ case CATTA_LOG_INFO:
+ mlevel = MESHLINK_INFO;
+ break;
- case CATTA_LOG_DEBUG:
- mlevel = MESHLINK_DEBUG;
- break;
- }
+ case CATTA_LOG_DEBUG:
+ mlevel = MESHLINK_DEBUG;
+ break;
+ }
- logger(NULL, mlevel, "%s\n", txt);
+ logger(NULL, mlevel, "%s\n", txt);
}
-bool discovery_start(meshlink_handle_t *mesh)
-{
- logger(mesh, MESHLINK_DEBUG, "discovery_start called\n");
-
- // asserts
- assert(mesh != NULL);
- assert(mesh->catta_poll == NULL);
- assert(mesh->catta_server == NULL);
- assert(mesh->catta_browser == NULL);
- assert(mesh->discovery_threadstarted == false);
- assert(mesh->catta_servicetype == NULL);
-
- // handle catta logs
- catta_set_log_function(discovery_log_cb);
-
- // create service type string
- size_t servicetype_strlen = sizeof(MESHLINK_MDNS_SERVICE_TYPE) + strlen(mesh->appname) + 1;
- mesh->catta_servicetype = malloc(servicetype_strlen);
-
- if(mesh->catta_servicetype == NULL)
- {
- logger(mesh, MESHLINK_ERROR, "Failed to allocate memory for service type string.\n");
- goto fail;
- }
-
- snprintf(mesh->catta_servicetype, servicetype_strlen, MESHLINK_MDNS_SERVICE_TYPE, mesh->appname);
-
- // Allocate discovery loop object
- if(!(mesh->catta_poll = catta_simple_poll_new()))
- {
- logger(mesh, MESHLINK_ERROR, "Failed to create discovery poll object.\n");
+bool discovery_start(meshlink_handle_t *mesh) {
+ logger(mesh, MESHLINK_DEBUG, "discovery_start called\n");
+
+ // asserts
+ assert(mesh != NULL);
+ assert(mesh->catta_poll == NULL);
+ assert(mesh->catta_server == NULL);
+ assert(mesh->catta_browser == NULL);
+ assert(mesh->discovery_threadstarted == false);
+ assert(mesh->catta_servicetype == NULL);
+
+ // handle catta logs
+ catta_set_log_function(discovery_log_cb);
+
+ // create service type string
+ size_t servicetype_strlen = sizeof(MESHLINK_MDNS_SERVICE_TYPE) + strlen(mesh->appname) + 1;
+ mesh->catta_servicetype = malloc(servicetype_strlen);
+
+ if(mesh->catta_servicetype == NULL) {
+ logger(mesh, MESHLINK_ERROR, "Failed to allocate memory for service type string.\n");
goto fail;
- }
-
- // generate some unique host name (we actually do not care about it)
- char hostname[17];
- generate_rand_string(hostname, sizeof(hostname));
-
- // Let's set the host name for this server.
- CattaServerConfig config;
- catta_server_config_init(&config);
- config.host_name = catta_strdup(hostname);
- config.publish_workstation = 0;
- config.disallow_other_stacks = 0;
- config.publish_hinfo = 0;
- config.publish_addresses = 1;
- config.publish_no_reverse = 1;
-
- /* Allocate a new server */
- int error;
- mesh->catta_server = catta_server_new(catta_simple_poll_get(mesh->catta_poll), &config, discovery_server_callback, mesh, &error);
-
- /* Free the configuration data */
- catta_server_config_free(&config);
-
- /* Check wether creating the server object succeeded */
- if(!mesh->catta_server)
- {
- logger(mesh, MESHLINK_ERROR, "Failed to create discovery server: %s\n", catta_strerror(error));
- goto fail;
- }
-
- // Create the service browser
- if(!(mesh->catta_browser = catta_s_service_browser_new(mesh->catta_server, CATTA_IF_UNSPEC, CATTA_PROTO_UNSPEC, mesh->catta_servicetype, NULL, 0, discovery_browse_callback, mesh)))
- {
- logger(mesh, MESHLINK_ERROR, "Failed to create discovery service browser: %s\n", catta_strerror(catta_server_errno(mesh->catta_server)));
- goto fail;
- }
+ }
+
+ snprintf(mesh->catta_servicetype, servicetype_strlen, MESHLINK_MDNS_SERVICE_TYPE, mesh->appname);
+
+ // Allocate discovery loop object
+ if(!(mesh->catta_poll = catta_simple_poll_new())) {
+ logger(mesh, MESHLINK_ERROR, "Failed to create discovery poll object.\n");
+ goto fail;
+ }
+
+ // generate some unique host name (we actually do not care about it)
+ char hostname[17];
+ generate_rand_string(hostname, sizeof(hostname));
+
+ // Let's set the host name for this server.
+ CattaServerConfig config;
+ catta_server_config_init(&config);
+ config.host_name = catta_strdup(hostname);
+ config.publish_workstation = 0;
+ config.disallow_other_stacks = 0;
+ config.publish_hinfo = 0;
+ config.publish_addresses = 1;
+ config.publish_no_reverse = 1;
+
+ /* Allocate a new server */
+ int error;
+ mesh->catta_server = catta_server_new(catta_simple_poll_get(mesh->catta_poll), &config, discovery_server_callback, mesh, &error);
+
+ /* Free the configuration data */
+ catta_server_config_free(&config);
+
+ /* Check wether creating the server object succeeded */
+ if(!mesh->catta_server) {
+ logger(mesh, MESHLINK_ERROR, "Failed to create discovery server: %s\n", catta_strerror(error));
+ goto fail;
+ }
+
+ // Create the service browser
+ if(!(mesh->catta_browser = catta_s_service_browser_new(mesh->catta_server, CATTA_IF_UNSPEC, CATTA_PROTO_UNSPEC, mesh->catta_servicetype, NULL, 0, discovery_browse_callback, mesh))) {
+ logger(mesh, MESHLINK_ERROR, "Failed to create discovery service browser: %s\n", catta_strerror(catta_server_errno(mesh->catta_server)));
+ goto fail;
+ }
// Start the discovery thread
- if(pthread_create(&mesh->discovery_thread, NULL, discovery_loop, mesh) != 0)
- {
+ if(pthread_create(&mesh->discovery_thread, NULL, discovery_loop, mesh) != 0) {
logger(mesh, MESHLINK_ERROR, "Could not start discovery thread: %s\n", strerror(errno));
memset(&mesh->discovery_thread, 0, sizeof mesh->discovery_thread);
goto fail;
return true;
fail:
- if(mesh->catta_browser != NULL)
- {
- catta_s_service_browser_free(mesh->catta_browser);
- mesh->catta_browser = NULL;
- }
-
- if(mesh->catta_server != NULL)
- {
- catta_server_free(mesh->catta_server);
- mesh->catta_server = NULL;
- }
-
- if(mesh->catta_poll != NULL)
- {
- catta_simple_poll_free(mesh->catta_poll);
- mesh->catta_poll = NULL;
- }
-
- if(mesh->catta_servicetype != NULL)
- {
- free(mesh->catta_servicetype);
- mesh->catta_servicetype = NULL;
- }
-
- return false;
+ if(mesh->catta_browser != NULL) {
+ catta_s_service_browser_free(mesh->catta_browser);
+ mesh->catta_browser = NULL;
+ }
+
+ if(mesh->catta_server != NULL) {
+ catta_server_free(mesh->catta_server);
+ mesh->catta_server = NULL;
+ }
+
+ if(mesh->catta_poll != NULL) {
+ catta_simple_poll_free(mesh->catta_poll);
+ mesh->catta_poll = NULL;
+ }
+
+ if(mesh->catta_servicetype != NULL) {
+ free(mesh->catta_servicetype);
+ mesh->catta_servicetype = NULL;
+ }
+
+ return false;
}
-void discovery_stop(meshlink_handle_t *mesh)
-{
- logger(mesh, MESHLINK_DEBUG, "discovery_stop called\n");
+void discovery_stop(meshlink_handle_t *mesh) {
+ logger(mesh, MESHLINK_DEBUG, "discovery_stop called\n");
- // asserts
- assert(mesh != NULL);
+ // asserts
+ assert(mesh != NULL);
// Shut down
- if(mesh->catta_poll)
- {
- catta_simple_poll_quit(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)
- {
- pthread_join(mesh->discovery_thread, NULL);
- mesh->discovery_threadstarted = false;
- }
+ if(mesh->discovery_threadstarted == true) {
+ pthread_join(mesh->discovery_thread, NULL);
+ mesh->discovery_threadstarted = false;
+ }
// Clean up resources
- if(mesh->catta_browser != NULL)
- {
- catta_s_service_browser_free(mesh->catta_browser);
- mesh->catta_browser = NULL;
- }
-
- if(mesh->catta_group)
- {
- catta_s_entry_group_reset(mesh->catta_group);
- catta_s_entry_group_free(mesh->catta_group);
- mesh->catta_group = NULL;
- }
-
- if(mesh->catta_server != NULL)
- {
- catta_server_free(mesh->catta_server);
- mesh->catta_server = NULL;
- }
-
- if(mesh->catta_poll != NULL)
- {
- catta_simple_poll_free(mesh->catta_poll);
- mesh->catta_poll = NULL;
- }
-
- if(mesh->catta_servicetype != NULL)
- {
- free(mesh->catta_servicetype);
- mesh->catta_servicetype = NULL;
- }
+ if(mesh->catta_browser != NULL) {
+ catta_s_service_browser_free(mesh->catta_browser);
+ mesh->catta_browser = NULL;
+ }
+
+ if(mesh->catta_group) {
+ catta_s_entry_group_reset(mesh->catta_group);
+ catta_s_entry_group_free(mesh->catta_group);
+ mesh->catta_group = NULL;
+ }
+
+ if(mesh->catta_server != NULL) {
+ catta_server_free(mesh->catta_server);
+ mesh->catta_server = NULL;
+ }
+
+ if(mesh->catta_poll != NULL) {
+ catta_simple_poll_free(mesh->catta_poll);
+ mesh->catta_poll = NULL;
+ }
+
+ if(mesh->catta_servicetype != NULL) {
+ free(mesh->catta_servicetype);
+ mesh->catta_servicetype = NULL;
+ }
}
#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;\
+ (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;\
+ (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
typedef struct ecdh ecdh_t;
#endif
-extern ecdh_t *ecdh_generate_public(void *pubkey) __attribute__ ((__malloc__));
-extern bool ecdh_compute_shared(ecdh_t *ecdh, const void *pubkey, void *shared) __attribute__ ((__warn_unused_result__));
+extern ecdh_t *ecdh_generate_public(void *pubkey) __attribute__((__malloc__));
+extern bool ecdh_compute_shared(ecdh_t *ecdh, const void *pubkey, void *shared) __attribute__((__warn_unused_result__));
extern void ecdh_free(ecdh_t *ecdh);
#endif
typedef struct ecdsa ecdsa_t;
#endif
-extern ecdsa_t *ecdsa_set_base64_public_key(const char *p) __attribute__ ((__malloc__));
+extern ecdsa_t *ecdsa_set_base64_public_key(const char *p) __attribute__((__malloc__));
extern char *ecdsa_get_base64_public_key(ecdsa_t *ecdsa);
-extern ecdsa_t *ecdsa_read_pem_public_key(FILE *fp) __attribute__ ((__malloc__));
-extern ecdsa_t *ecdsa_read_pem_private_key(FILE *fp) __attribute__ ((__malloc__));
+extern ecdsa_t *ecdsa_read_pem_public_key(FILE *fp) __attribute__((__malloc__));
+extern ecdsa_t *ecdsa_read_pem_private_key(FILE *fp) __attribute__((__malloc__));
extern size_t ecdsa_size(ecdsa_t *ecdsa);
-extern bool ecdsa_sign(ecdsa_t *ecdsa, const void *in, size_t inlen, void *out) __attribute__ ((__warn_unused_result__));
-extern bool ecdsa_verify(ecdsa_t *ecdsa, const void *in, size_t inlen, const void *out) __attribute__ ((__warn_unused_result__));
+extern bool ecdsa_sign(ecdsa_t *ecdsa, const void *in, size_t inlen, void *out) __attribute__((__warn_unused_result__));
+extern bool ecdsa_verify(ecdsa_t *ecdsa, const void *in, size_t inlen, const void *out) __attribute__((__warn_unused_result__));
extern bool ecdsa_active(ecdsa_t *ecdsa);
extern void ecdsa_free(ecdsa_t *ecdsa);
#include "ecdsa.h"
-extern ecdsa_t *ecdsa_generate(void) __attribute__ ((__malloc__));
-extern bool ecdsa_write_pem_public_key(ecdsa_t *ecdsa, FILE *fp) __attribute__ ((__warn_unused_result__));
-extern bool ecdsa_write_pem_private_key(ecdsa_t *ecdsa, FILE *fp) __attribute__ ((__warn_unused_result__));
+extern ecdsa_t *ecdsa_generate(void) __attribute__((__malloc__));
+extern bool ecdsa_write_pem_public_key(ecdsa_t *ecdsa, FILE *fp) __attribute__((__warn_unused_result__));
+extern bool ecdsa_write_pem_private_key(ecdsa_t *ecdsa, FILE *fp) __attribute__((__warn_unused_result__));
#endif
extern void init_edges(struct meshlink_handle *mesh);
extern void exit_edges(struct meshlink_handle *mesh);
-extern edge_t *new_edge(void) __attribute__ ((__malloc__));
+extern edge_t *new_edge(void) __attribute__((__malloc__));
extern void free_edge(edge_t *);
-extern struct splay_tree_t *new_edge_tree(void) __attribute__ ((__malloc__));
+extern struct splay_tree_t *new_edge_tree(void) __attribute__((__malloc__));
extern void free_edge_tree(struct splay_tree_t *);
extern void edge_add(struct meshlink_handle *mesh, edge_t *);
extern void edge_del(struct meshlink_handle *mesh, edge_t *);
void timeout_add(event_loop_t *loop, timeout_t *timeout, timeout_cb_t cb, void *data, struct timeval *tv) {
if(!timeout->cb)
- timeout->tv = (struct timeval){0, 0};
+ timeout->tv = (struct timeval) {
+ 0, 0
+ };
timeout->cb = cb;
timeout->data = data;
splay_unlink_node(&loop->timeouts, &timeout->node);
timeout->cb = 0;
- timeout->tv = (struct timeval){0, 0};
+ timeout->tv = (struct timeval) {
+ 0, 0
+ };
}
static int signal_compare(const signal_t *a, const signal_t *b) {
if(read(loop->pipefd[0], &signum, 1) != 1)
return;
- signal_t *sig = splay_search(&loop->signals, &((signal_t){.signum = signum}));
+ signal_t *sig = splay_search(&loop->signals, &((signal_t) {
+ .signum = signum
+ }));
if(sig)
sig->cb(loop, sig->data);
}
typedef void (*io_cb_t)(event_loop_t *loop, void *data, int flags);
typedef void (*timeout_cb_t)(event_loop_t *loop, void *data);
typedef void (*signal_cb_t)(event_loop_t *loop, void *data);
-typedef struct timeval (*idle_cb_t)(event_loop_t *loop, void *data);
+typedef struct timeval(*idle_cb_t)(event_loop_t *loop, void *data);
typedef struct io_t {
int fd;
volatile bool running;
struct timeval now;
bool deletion;
-
+
splay_tree_t ios;
splay_tree_t timeouts;
splay_tree_t signals;
#if !HAVE_DECL_GAI_STRERROR
char *gai_strerror(int ecode) {
- 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";
+ 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";
}
}
#endif /* !HAVE_GAI_STRERROR */
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) {
+ if(hints && hints->ai_flags & AI_PASSIVE) {
*res = malloc_ai(port, htonl(0x00000000));
return 0;
}
- if (!hostname) {
+ if(!hostname) {
*res = malloc_ai(port, htonl(0x7f000001));
return 0;
}
if(!hp || !hp->h_addr_list || !hp->h_addr_list[0])
return EAI_NODATA;
- for (i = 0; hp->h_addr_list[i]; i++) {
+ 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)
/* Situation:
- /
- /
+ /
+ /
----->(n)---e-->(e->to)
- \
- \
+ \
+ \
Where e is an edge, (n) and (e->to) are nodes.
n->address is set to the e->address of the edge left of n to n.
bool indirect = n->status.indirect || e->options & OPTION_INDIRECT;
if(e->to->status.visited
- && (!e->to->status.indirect || indirect)
- && (e->to->distance != n->distance + 1 || e->weight >= e->to->prevedge->weight))
+ && (!e->to->status.indirect || indirect)
+ && (e->to->distance != n->distance + 1 || e->weight >= e->to->prevedge->weight))
continue;
e->to->status.visited = true;
if(n->status.reachable) {
logger(mesh, MESHLINK_DEBUG, "Node %s (%s) became reachable",
- n->name, n->hostname);
+ n->name, n->hostname);
} else {
logger(mesh, MESHLINK_DEBUG, "Node %s (%s) became unreachable",
- n->name, n->hostname);
+ n->name, n->hostname);
}
/* TODO: only clear status.validkey if node is unreachable? */
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;
}
const void **values;
} hash_t;
-extern hash_t *hash_alloc(size_t n, size_t size) __attribute__ ((__malloc__));
+extern hash_t *hash_alloc(size_t n, size_t size) __attribute__((__malloc__));
extern void hash_free(hash_t *);
extern void hash_insert(hash_t *, const void *key, const void *value);
/* (De)constructors */
-extern list_t *list_alloc(list_action_t) __attribute__ ((__malloc__));
+extern list_t *list_alloc(list_action_t) __attribute__((__malloc__));
extern void list_free(list_t *);
extern list_node_t *list_alloc_node(void);
extern void list_free_node(list_t *, list_node_t *);
#include "meshlink_internal.h"
-extern void logger(meshlink_handle_t *mesh, meshlink_log_level_t level, const char *format, ...) __attribute__ ((__format__(printf, 3, 4)));
+extern void logger(meshlink_handle_t *mesh, meshlink_log_level_t level, const char *format, ...) __attribute__((__format__(printf, 3, 4)));
#endif /* __MESHLINK_LOGGER_H__ */
#include <new> // for 'placement new'
namespace meshlink {
- class mesh;
- class node;
- class channel;
+class mesh;
+class node;
+class channel;
+
+/// Severity of log messages generated by MeshLink.
+typedef meshlink_log_level_t log_level_t;
+
+/// Code of most recent error encountered.
+typedef meshlink_errno_t errno_t;
+
+/// A callback for receiving data from the mesh.
+/** @param mesh A handle which represents an instance of MeshLink.
+ * @param source A pointer to a meshlink::node describing the source of the data.
+ * @param data A pointer to a buffer containing the data sent by the source.
+ * @param len The length of the received data.
+ */
+typedef void (*receive_cb_t)(mesh *mesh, node *source, const void *data, size_t len);
+
+/// A callback reporting node status changes.
+/** @param mesh A handle which represents an instance of MeshLink.
+ * @param node A pointer to a meshlink::node describing the node whose status changed.
+ * @param reachable True if the node is reachable, false otherwise.
+ */
+typedef void (*node_status_cb_t)(mesh *mesh, node *node, bool reachable);
+
+/// A callback for receiving log messages generated by MeshLink.
+/** @param mesh A handle which represents an instance of MeshLink.
+ * @param level An enum describing the severity level of the message.
+ * @param text A pointer to a string containing the textual log message.
+ */
+typedef void (*log_cb_t)(mesh *mesh, log_level_t level, const char *text);
+
+/// A callback for accepting incoming channels.
+/** @param mesh A handle which represents an instance of MeshLink.
+ * @param channel A handle for the incoming channel.
+ * @param port The port number the peer wishes to connect to.
+ * @param data A pointer to a buffer containing data already received. (Not yet used.)
+ * @param len The length of the data. (Not yet used.)
+ *
+ * @return This function should return true if the application accepts the incoming channel, false otherwise.
+ * If returning false, the channel is invalid and may not be used anymore.
+ */
+typedef bool (*channel_accept_cb_t)(mesh *mesh, channel *channel, uint16_t port, const void *data, size_t len);
+
+/// A callback for receiving data from a channel.
+/** @param mesh A handle which represents an instance of MeshLink.
+ * @param channel A handle for the channel.
+ * @param data A pointer to a buffer containing data sent by the source.
+ * @param len The length of the data.
+ */
+typedef void (*channel_receive_cb_t)(mesh *mesh, channel *channel, const void *data, size_t len);
+
+/// A callback that is called when data can be send on a channel.
+/** @param mesh A handle which represents an instance of MeshLink.
+ * @param channel A handle for the channel.
+ * @param len The maximum length of data that is guaranteed to be accepted by a call to channel_send().
+ */
+typedef void (*channel_poll_cb_t)(mesh *mesh, channel *channel, size_t len);
+
+/// A class describing a MeshLink node.
+class node: public meshlink_node_t {
+};
+
+/// A class describing a MeshLink channel.
+class channel: public meshlink_channel_t {
+public:
+ static const uint32_t RELIABLE = MESHLINK_CHANNEL_RELIABLE;
+ static const uint32_t ORDERED = MESHLINK_CHANNEL_ORDERED;
+ static const uint32_t FRAMED = MESHLINK_CHANNEL_FRAMED;
+ static const uint32_t DROP_LATE = MESHLINK_CHANNEL_DROP_LATE;
+ static const uint32_t TCP = MESHLINK_CHANNEL_TCP;
+ static const uint32_t UDP = MESHLINK_CHANNEL_UDP;
+};
+
+/// A class describing a MeshLink mesh.
+class mesh {
+public:
+ mesh() : handle(0) {}
+
+ virtual ~mesh() {
+ this->close();
+ }
- /// Severity of log messages generated by MeshLink.
- typedef meshlink_log_level_t log_level_t;
+ bool isOpen() const {
+ return (handle!=0);
+ }
- /// Code of most recent error encountered.
- typedef meshlink_errno_t errno_t;
+// TODO: please enable C++11 in autoconf to enable "move constructors":
+// mesh(mesh&& other)
+// : handle(other.handle)
+// {
+// if(handle)
+// handle->priv = this;
+// other.handle = 0;
+// }
- /// A callback for receiving data from the mesh.
- /** @param mesh A handle which represents an instance of MeshLink.
- * @param source A pointer to a meshlink::node describing the source of the data.
- * @param data A pointer to a buffer containing the data sent by the source.
- * @param len The length of the received data.
+ /// Initialize MeshLink's configuration directory.
+ /** This function causes MeshLink to initialize its configuration directory,
+ * if it hasn't already been initialized.
+ * It only has to be run the first time the application starts,
+ * but it is not a problem if it is run more than once, as long as
+ * the arguments given are the same.
+ *
+ * This function does not start any network I/O yet. The application should
+ * first set callbacks, and then call meshlink_start().
+ *
+ * @param confbase The directory in which MeshLink will store its configuration files.
+ * @param name The name which this instance of the application will use in the mesh.
+ * @param appname The application name which will be used in the mesh.
+ * @param dclass The device class which will be used in the mesh.
+ *
+ * @return This function will return a pointer to a meshlink::mesh if MeshLink has succesfully set up its configuration files, NULL otherwise.
*/
- typedef void (*receive_cb_t)(mesh *mesh, node *source, const void *data, size_t len);
+ bool open(const char *confbase, const char *name, const char* appname, dev_class_t devclass) {
+ handle = meshlink_open(confbase, name, appname, devclass);
+ if(handle)
+ handle->priv = this;
+
+ return isOpen();
+ }
- /// A callback reporting node status changes.
- /** @param mesh A handle which represents an instance of MeshLink.
- * @param node A pointer to a meshlink::node describing the node whose status changed.
- * @param reachable True if the node is reachable, false otherwise.
+ mesh(const char *confbase, const char *name, const char* appname, dev_class_t devclass) {
+ open(confbase, name, appname, devclass);
+ }
+
+ /// Close the MeshLink handle.
+ /** This function calls meshlink_stop() if necessary,
+ * and frees all memory allocated by MeshLink.
+ * Afterwards, the handle and any pointers to a struct meshlink_node are invalid.
*/
- typedef void (*node_status_cb_t)(mesh *mesh, node *node, bool reachable);
+ void close() {
+ if(handle) {
+ handle->priv = 0;
+ meshlink_close(handle);
+ }
+ handle=0;
+ }
- /// A callback for receiving log messages generated by MeshLink.
- /** @param mesh A handle which represents an instance of MeshLink.
- * @param level An enum describing the severity level of the message.
- * @param text A pointer to a string containing the textual log message.
+ /** instead of registerin callbacks you derive your own class and overwrite the following abstract member functions.
+ * These functions are run in MeshLink's own thread.
+ * It is therefore important that these functions use apprioriate methods (queues, pipes, locking, etc.)
+ * to hand the data over to the application's thread.
+ * These functions should also not block itself and return as quickly as possible.
+ * The default member functions are no-ops, so you are not required to overwrite all these member functions
*/
- typedef void (*log_cb_t)(mesh *mesh, log_level_t level, const char *text);
- /// A callback for accepting incoming channels.
- /** @param mesh A handle which represents an instance of MeshLink.
+ /// This function is called whenever another node sends data to the local node.
+ virtual void receive(node* source, const void* data, size_t length) { /* do nothing */ }
+
+ /// This functions is called whenever another node's status changed.
+ virtual void node_status(node* peer, bool reachable) { /* do nothing */ }
+
+ /// This functions is called whenever MeshLink has some information to log.
+ virtual void log(log_level_t level, const char* message) { /* do nothing */ }
+
+ /// This functions is called whenever another node attemps to open a channel to the local node.
+ /**
+ * If the channel is accepted, the poll_callback will be set to channel_poll and can be
+ * changed using set_channel_poll_cb(). Likewise, the receive callback is set to
+ * channel_receive().
+ *
+ * The function is run in MeshLink's own thread.
+ * It is therefore important that the callback uses apprioriate methods (queues, pipes, locking, etc.)
+ * to pass data to or from the application's thread.
+ * The callback should also not block itself and return as quickly as possible.
+ *
* @param channel A handle for the incoming channel.
* @param port The port number the peer wishes to connect to.
* @param data A pointer to a buffer containing data already received. (Not yet used.)
* @return This function should return true if the application accepts the incoming channel, false otherwise.
* If returning false, the channel is invalid and may not be used anymore.
*/
- typedef bool (*channel_accept_cb_t)(mesh *mesh, channel *channel, uint16_t port, const void *data, size_t len);
+ virtual bool channel_accept(channel *channel, uint16_t port, const void *data, size_t len) {
+ /* by default reject all channels */
+ return false;
+ }
- /// A callback for receiving data from a channel.
- /** @param mesh A handle which represents an instance of MeshLink.
+ /// This function is called by Meshlink for receiving data from a channel.
+ /**
+ * The function is run in MeshLink's own thread.
+ * It is therefore important that the callback uses apprioriate methods (queues, pipes, locking, etc.)
+ * to pass data to or from the application's thread.
+ * The callback should also not block itself and return as quickly as possible.
+ *
* @param channel A handle for the channel.
* @param data A pointer to a buffer containing data sent by the source.
* @param len The length of the data.
*/
- typedef void (*channel_receive_cb_t)(mesh *mesh, channel *channel, const void *data, size_t len);
+ virtual void channel_receive(channel *channel, const void *data, size_t len) { /* do nothing */ }
- /// A callback that is called when data can be send on a channel.
- /** @param mesh A handle which represents an instance of MeshLink.
+ /// This function is called by Meshlink when data can be send on a channel.
+ /**
+ * The function is run in MeshLink's own thread.
+ * It is therefore important that the callback uses apprioriate methods (queues, pipes, locking, etc.)
+ * to pass data to or from the application's thread.
+ *
+ * The callback should also not block itself and return as quickly as possible.
* @param channel A handle for the channel.
* @param len The maximum length of data that is guaranteed to be accepted by a call to channel_send().
*/
- typedef void (*channel_poll_cb_t)(mesh *mesh, channel *channel, size_t len);
-
- /// A class describing a MeshLink node.
- class node: public meshlink_node_t {
- };
-
- /// A class describing a MeshLink channel.
- class channel: public meshlink_channel_t {
- public:
- static const uint32_t RELIABLE = MESHLINK_CHANNEL_RELIABLE;
- static const uint32_t ORDERED = MESHLINK_CHANNEL_ORDERED;
- static const uint32_t FRAMED = MESHLINK_CHANNEL_FRAMED;
- static const uint32_t DROP_LATE = MESHLINK_CHANNEL_DROP_LATE;
- static const uint32_t TCP = MESHLINK_CHANNEL_TCP;
- static const uint32_t UDP = MESHLINK_CHANNEL_UDP;
- };
-
- /// A class describing a MeshLink mesh.
- class mesh {
- public:
- mesh() : handle(0) {}
-
- virtual ~mesh() {
- this->close();
- }
-
- bool isOpen() const {
- return (handle!=0);
- }
-
-// TODO: please enable C++11 in autoconf to enable "move constructors":
-// mesh(mesh&& other)
-// : handle(other.handle)
-// {
-// if(handle)
-// handle->priv = this;
-// other.handle = 0;
-// }
+ virtual void channel_poll(channel *channel, size_t len) { /* do nothing */ }
- /// Initialize MeshLink's configuration directory.
- /** This function causes MeshLink to initialize its configuration directory,
- * if it hasn't already been initialized.
- * It only has to be run the first time the application starts,
- * but it is not a problem if it is run more than once, as long as
- * the arguments given are the same.
- *
- * This function does not start any network I/O yet. The application should
- * first set callbacks, and then call meshlink_start().
- *
- * @param confbase The directory in which MeshLink will store its configuration files.
- * @param name The name which this instance of the application will use in the mesh.
- * @param appname The application name which will be used in the mesh.
- * @param dclass The device class which will be used in the mesh.
- *
- * @return This function will return a pointer to a meshlink::mesh if MeshLink has succesfully set up its configuration files, NULL otherwise.
- */
- bool open(const char *confbase, const char *name, const char* appname, dev_class_t devclass) {
- handle = meshlink_open(confbase, name, appname, devclass);
- if(handle)
- handle->priv = this;
-
- return isOpen();
- }
-
- mesh(const char *confbase, const char *name, const char* appname, dev_class_t devclass) {
- open(confbase, name, appname, devclass);
- }
-
- /// Close the MeshLink handle.
- /** This function calls meshlink_stop() if necessary,
- * and frees all memory allocated by MeshLink.
- * Afterwards, the handle and any pointers to a struct meshlink_node are invalid.
- */
- void close() {
- if(handle)
- {
- handle->priv = 0;
- meshlink_close(handle);
- }
- handle=0;
- }
-
- /** instead of registerin callbacks you derive your own class and overwrite the following abstract member functions.
- * These functions are run in MeshLink's own thread.
- * It is therefore important that these functions use apprioriate methods (queues, pipes, locking, etc.)
- * to hand the data over to the application's thread.
- * These functions should also not block itself and return as quickly as possible.
- * The default member functions are no-ops, so you are not required to overwrite all these member functions
- */
-
- /// This function is called whenever another node sends data to the local node.
- virtual void receive(node* source, const void* data, size_t length) { /* do nothing */ }
-
- /// This functions is called whenever another node's status changed.
- virtual void node_status(node* peer, bool reachable) { /* do nothing */ }
-
- /// This functions is called whenever MeshLink has some information to log.
- virtual void log(log_level_t level, const char* message) { /* do nothing */ }
-
- /// This functions is called whenever another node attemps to open a channel to the local node.
- /**
- * If the channel is accepted, the poll_callback will be set to channel_poll and can be
- * changed using set_channel_poll_cb(). Likewise, the receive callback is set to
- * channel_receive().
- *
- * The function is run in MeshLink's own thread.
- * It is therefore important that the callback uses apprioriate methods (queues, pipes, locking, etc.)
- * to pass data to or from the application's thread.
- * The callback should also not block itself and return as quickly as possible.
- *
- * @param channel A handle for the incoming channel.
- * @param port The port number the peer wishes to connect to.
- * @param data A pointer to a buffer containing data already received. (Not yet used.)
- * @param len The length of the data. (Not yet used.)
- *
- * @return This function should return true if the application accepts the incoming channel, false otherwise.
- * If returning false, the channel is invalid and may not be used anymore.
- */
- virtual bool channel_accept(channel *channel, uint16_t port, const void *data, size_t len)
- {
- /* by default reject all channels */
- return false;
- }
+ /// Start MeshLink.
+ /** This function causes MeshLink to open network sockets, make outgoing connections, and
+ * create a new thread, which will handle all network I/O.
+ *
+ * @return This function will return true if MeshLink has succesfully started its thread, false otherwise.
+ */
+ bool start() {
+ meshlink_set_receive_cb(handle, &receive_trampoline);
+ meshlink_set_node_status_cb(handle, &node_status_trampoline);
+ meshlink_set_log_cb(handle, MESHLINK_DEBUG, &log_trampoline);
+ meshlink_set_channel_accept_cb(handle, &channel_accept_trampoline);
+ return meshlink_start(handle);
+ }
- /// This function is called by Meshlink for receiving data from a channel.
- /**
- * The function is run in MeshLink's own thread.
- * It is therefore important that the callback uses apprioriate methods (queues, pipes, locking, etc.)
- * to pass data to or from the application's thread.
- * The callback should also not block itself and return as quickly as possible.
- *
- * @param channel A handle for the channel.
- * @param data A pointer to a buffer containing data sent by the source.
- * @param len The length of the data.
- */
- virtual void channel_receive(channel *channel, const void *data, size_t len) { /* do nothing */ }
-
- /// This function is called by Meshlink when data can be send on a channel.
- /**
- * The function is run in MeshLink's own thread.
- * It is therefore important that the callback uses apprioriate methods (queues, pipes, locking, etc.)
- * to pass data to or from the application's thread.
- *
- * The callback should also not block itself and return as quickly as possible.
- * @param channel A handle for the channel.
- * @param len The maximum length of data that is guaranteed to be accepted by a call to channel_send().
- */
- virtual void channel_poll(channel *channel, size_t len) { /* do nothing */ }
-
- /// Start MeshLink.
- /** This function causes MeshLink to open network sockets, make outgoing connections, and
- * create a new thread, which will handle all network I/O.
- *
- * @return This function will return true if MeshLink has succesfully started its thread, false otherwise.
- */
- bool start() {
- meshlink_set_receive_cb (handle, &receive_trampoline);
- meshlink_set_node_status_cb (handle, &node_status_trampoline);
- meshlink_set_log_cb (handle, MESHLINK_DEBUG, &log_trampoline);
- meshlink_set_channel_accept_cb(handle, &channel_accept_trampoline);
- return meshlink_start (handle);
- }
+ /// Stop MeshLink.
+ /** This function causes MeshLink to disconnect from all other nodes,
+ * close all sockets, and shut down its own thread.
+ */
+ void stop() {
+ meshlink_stop(handle);
+ }
- /// Stop MeshLink.
- /** This function causes MeshLink to disconnect from all other nodes,
- * close all sockets, and shut down its own thread.
- */
- void stop() {
- meshlink_stop(handle);
- }
+ /// Send data to another node.
+ /** This functions sends one packet of data to another node in the mesh.
+ * The packet is sent using UDP semantics, which means that
+ * the packet is sent as one unit and is received as one unit,
+ * and that there is no guarantee that the packet will arrive at the destination.
+ * The application should take care of getting an acknowledgement and retransmission if necessary.
+ *
+ * @param destination A pointer to a meshlink::node describing the destination for the data.
+ * @param data A pointer to a buffer containing the data to be sent to the source.
+ * @param len The length of the data.
+ * @return This function will return true if MeshLink has queued the message for transmission, and false otherwise.
+ * A return value of true does not guarantee that the message will actually arrive at the destination.
+ */
+ bool send(node *destination, const void *data, unsigned int len) {
+ return meshlink_send(handle, destination, data, len);
+ }
- /// Send data to another node.
- /** This functions sends one packet of data to another node in the mesh.
- * The packet is sent using UDP semantics, which means that
- * the packet is sent as one unit and is received as one unit,
- * and that there is no guarantee that the packet will arrive at the destination.
- * The application should take care of getting an acknowledgement and retransmission if necessary.
- *
- * @param destination A pointer to a meshlink::node describing the destination for the data.
- * @param data A pointer to a buffer containing the data to be sent to the source.
- * @param len The length of the data.
- * @return This function will return true if MeshLink has queued the message for transmission, and false otherwise.
- * A return value of true does not guarantee that the message will actually arrive at the destination.
- */
- bool send(node *destination, const void *data, unsigned int len) {
- return meshlink_send(handle, destination, data, len);
- }
+ /// Get a handle for a specific node.
+ /** This function returns a handle for the node with the given name.
+ *
+ * @param name The name of the node for which a handle is requested.
+ *
+ * @return A pointer to a meshlink::node which represents the requested node,
+ * or NULL if the requested node does not exist.
+ */
+ node *get_node(const char *name) {
+ return (node *)meshlink_get_node(handle, name);
+ }
- /// Get a handle for a specific node.
- /** This function returns a handle for the node with the given name.
- *
- * @param name The name of the node for which a handle is requested.
- *
- * @return A pointer to a meshlink::node which represents the requested node,
- * or NULL if the requested node does not exist.
- */
- node *get_node(const char *name) {
- return (node *)meshlink_get_node(handle, name);
- }
+ /// Get a handle for our own node.
+ /** This function returns a handle for the local node.
+ *
+ * @return A pointer to a meshlink::node which represents the local node.
+ */
+ node *get_self() {
+ return (node *)meshlink_get_self(handle);
+ }
- /// Get a handle for our own node.
- /** This function returns a handle for the local node.
- *
- * @return A pointer to a meshlink::node which represents the local node.
- */
- node *get_self() {
- return (node *)meshlink_get_self(handle);
- }
+ /// Get a list of all nodes.
+ /** This function returns a list with handles for all known nodes.
+ *
+ * @param nodes A pointer to an array of pointers to meshlink::node, which should be allocated by the application.
+ * @param nmemb The maximum number of pointers that can be stored in the nodes array.
+ *
+ * @return The number of known nodes, or -1 in case of an error.
+ * This can be larger than nmemb, in which case not all nodes were stored in the nodes array.
+ */
+ node **get_all_nodes(node **nodes, size_t *nmemb) {
+ return (node **)meshlink_get_all_nodes(handle, (meshlink_node_t **)nodes, nmemb);
+ }
- /// Get a list of all nodes.
- /** This function returns a list with handles for all known nodes.
- *
- * @param nodes A pointer to an array of pointers to meshlink::node, which should be allocated by the application.
- * @param nmemb The maximum number of pointers that can be stored in the nodes array.
- *
- * @return The number of known nodes, or -1 in case of an error.
- * This can be larger than nmemb, in which case not all nodes were stored in the nodes array.
- */
- node **get_all_nodes(node **nodes, size_t *nmemb) {
- return (node **)meshlink_get_all_nodes(handle, (meshlink_node_t **)nodes, nmemb);
- }
+ /// Sign data using the local node's MeshLink key.
+ /** This function signs data using the local node's MeshLink key.
+ * The generated signature can be securely verified by other nodes.
+ *
+ * @param data A pointer to a buffer containing the data to be signed.
+ * @param len The length of the data to be signed.
+ * @param signature A pointer to a buffer where the signature will be stored.
+ * @param siglen The size of the signature buffer. Will be changed after the call to match the size of the signature itself.
+ *
+ * @return This function returns true if the signature is valid, false otherwise.
+ */
+ bool sign(const void *data, size_t len, void *signature, size_t *siglen) {
+ return meshlink_sign(handle, data, len, signature, siglen);
+ }
- /// Sign data using the local node's MeshLink key.
- /** This function signs data using the local node's MeshLink key.
- * The generated signature can be securely verified by other nodes.
- *
- * @param data A pointer to a buffer containing the data to be signed.
- * @param len The length of the data to be signed.
- * @param signature A pointer to a buffer where the signature will be stored.
- * @param siglen The size of the signature buffer. Will be changed after the call to match the size of the signature itself.
- *
- * @return This function returns true if the signature is valid, false otherwise.
- */
- bool sign(const void *data, size_t len, void *signature, size_t *siglen) {
- return meshlink_sign(handle, data, len, signature, siglen);
- }
+ /// Verify the signature generated by another node of a piece of data.
+ /** This function verifies the signature that another node generated for a piece of data.
+ *
+ * @param source A pointer to a meshlink_node_t describing the source of the signature.
+ * @param data A pointer to a buffer containing the data to be verified.
+ * @param len The length of the data to be verified.
+ * @param signature A pointer to a string containing the signature.
+ * @param siglen The size of the signature.
+ *
+ * @return This function returns true if the signature is valid, false otherwise.
+ */
+ bool verify(node *source, const void *data, size_t len, const void *signature, size_t siglen) {
+ return meshlink_verify(handle, source, data, len, signature, siglen);
+ }
- /// Verify the signature generated by another node of a piece of data.
- /** This function verifies the signature that another node generated for a piece of data.
- *
- * @param source A pointer to a meshlink_node_t describing the source of the signature.
- * @param data A pointer to a buffer containing the data to be verified.
- * @param len The length of the data to be verified.
- * @param signature A pointer to a string containing the signature.
- * @param siglen The size of the signature.
- *
- * @return This function returns true if the signature is valid, false otherwise.
- */
- bool verify(node *source, const void *data, size_t len, const void *signature, size_t siglen) {
- return meshlink_verify(handle, source, data, len, signature, siglen);
- }
+ /// Add an Address for the local node.
+ /** This function adds an Address for the local node, which will be used for invitation URLs.
+ *
+ * @param address A string containing the address, which can be either in numeric format or a hostname.
+ *
+ * @return This function returns true if the address was added, false otherwise.
+ */
+ bool add_address(const char *address) {
+ return meshlink_add_address(handle, address);
+ }
- /// Add an Address for the local node.
- /** This function adds an Address for the local node, which will be used for invitation URLs.
- *
- * @param address A string containing the address, which can be either in numeric format or a hostname.
- *
- * @return This function returns true if the address was added, false otherwise.
- */
- bool add_address(const char *address) {
- return meshlink_add_address(handle, address);
- }
+ /** This function performs tries to discover the local node's external address
+ * by contacting the meshlink.io server. If a reverse lookup of the address works,
+ * the FQDN associated with the address will be returned.
+ *
+ * Please note that this is function only returns a single address,
+ * even if the local node might have more than one external address.
+ * In that case, there is no control over which address will be selected.
+ * Also note that if you have a dynamic IP address, or are behind carrier-grade NAT,
+ * there is no guarantee that the external address will be valid for an extended period of time.
+ *
+ * This function is blocking. It can take several seconds before it returns.
+ * There is no guarantee it will be able to resolve the external address.
+ * Failures might be because by temporary network outages.
+ *
+ * @return This function returns a pointer to a C string containing the discovered external address,
+ * or NULL if there was an error looking up the address.
+ * After get_external_address() returns, the application is free to overwrite or free this string.
+ */
+ bool get_external_address() {
+ return meshlink_get_external_address(handle);
+ }
- /** This function performs tries to discover the local node's external address
- * by contacting the meshlink.io server. If a reverse lookup of the address works,
- * the FQDN associated with the address will be returned.
- *
- * Please note that this is function only returns a single address,
- * even if the local node might have more than one external address.
- * In that case, there is no control over which address will be selected.
- * Also note that if you have a dynamic IP address, or are behind carrier-grade NAT,
- * there is no guarantee that the external address will be valid for an extended period of time.
- *
- * This function is blocking. It can take several seconds before it returns.
- * There is no guarantee it will be able to resolve the external address.
- * Failures might be because by temporary network outages.
- *
- * @return This function returns a pointer to a C string containing the discovered external address,
- * or NULL if there was an error looking up the address.
- * After get_external_address() returns, the application is free to overwrite or free this string.
- */
- bool get_external_address() {
- return meshlink_get_external_address(handle);
- }
+ /// Try to discover the external address for the local node, and add it to its list of addresses.
+ /** This function is equivalent to:
+ *
+ * mesh->add_address(mesh->get_external_address());
+ *
+ * Read the description of get_external_address() for the limitations of this function.
+ *
+ * @return This function returns true if the address was added, false otherwise.
+ */
+ bool add_external_address() {
+ return meshlink_add_external_address(handle);
+ }
- /// Try to discover the external address for the local node, and add it to its list of addresses.
- /** This function is equivalent to:
- *
- * mesh->add_address(mesh->get_external_address());
- *
- * Read the description of get_external_address() for the limitations of this function.
- *
- * @return This function returns true if the address was added, false otherwise.
- */
- bool add_external_address() {
- return meshlink_add_external_address(handle);
- }
+ /// Get the network port used by the local node.
+ /** This function returns the network port that the local node is listening on.
+ *
+ * @param mesh A handle which represents an instance of MeshLink.
+ *
+ * @return This function returns the port number, or -1 in case of an error.
+ */
+ int get_port() {
+ return meshlink_get_port(handle);
+ }
- /// Get the network port used by the local node.
- /** This function returns the network port that the local node is listening on.
- *
- * @param mesh A handle which represents an instance of MeshLink.
- *
- * @return This function returns the port number, or -1 in case of an error.
- */
- int get_port() {
- return meshlink_get_port(handle);
- }
+ /// Set the network port used by the local node.
+ /** This function sets the network port that the local node is listening on.
+ * It may only be called when the mesh is not running.
+ * If unsure, call stop() before calling this function.
+ * Also note that if your node is already part of a mesh with other nodes,
+ * that the other nodes may no longer be able to initiate connections to the local node,
+ * since they will try to connect to the previously configured port.
+ *
+ * @param port The port number to listen on. This must be between 0 and 65535.
+ * If the port is set to 0, then MeshLink will listen on a port
+ * that is randomly assigned by the operating system every time open() is called.
+ *
+ * @return This function returns true if the port was succesfully changed, false otherwise.
+ */
+ bool set_port(int port) {
+ return meshlink_set_port(handle, port);
+ }
- /// Set the network port used by the local node.
- /** This function sets the network port that the local node is listening on.
- * It may only be called when the mesh is not running.
- * If unsure, call stop() before calling this function.
- * Also note that if your node is already part of a mesh with other nodes,
- * that the other nodes may no longer be able to initiate connections to the local node,
- * since they will try to connect to the previously configured port.
- *
- * @param port The port number to listen on. This must be between 0 and 65535.
- * If the port is set to 0, then MeshLink will listen on a port
- * that is randomly assigned by the operating system every time open() is called.
- *
- * @return This function returns true if the port was succesfully changed, false otherwise.
- */
- bool set_port(int port) {
- return meshlink_set_port(handle, port);
- }
+ /// Invite another node into the mesh.
+ /** This function generates an invitation that can be used by another node to join the same mesh as the local node.
+ * The generated invitation is a string containing a URL.
+ * This URL should be passed by the application to the invitee in a way that no eavesdroppers can see the URL.
+ * The URL can only be used once, after the user has joined the mesh the URL is no longer valid.
+ *
+ * @param name The name that the invitee will use in the mesh.
+ *
+ * @return This function returns a string that contains the invitation URL.
+ * The application should call free() after it has finished using the URL.
+ */
+ char *invite(const char *name) {
+ return meshlink_invite(handle, name);
+ }
- /// Invite another node into the mesh.
- /** This function generates an invitation that can be used by another node to join the same mesh as the local node.
- * The generated invitation is a string containing a URL.
- * This URL should be passed by the application to the invitee in a way that no eavesdroppers can see the URL.
- * The URL can only be used once, after the user has joined the mesh the URL is no longer valid.
- *
- * @param name The name that the invitee will use in the mesh.
- *
- * @return This function returns a string that contains the invitation URL.
- * The application should call free() after it has finished using the URL.
- */
- char *invite(const char *name) {
- return meshlink_invite(handle, name);
- }
+ /// Use an invitation to join a mesh.
+ /** This function allows the local node to join an existing mesh using an invitation URL generated by another node.
+ * An invitation can only be used if the local node has never connected to other nodes before.
+ * After a succesfully accepted invitation, the name of the local node may have changed.
+ *
+ * This function may only be called on a mesh that has not been started yet and which is not already part of an existing mesh.
+ *
+ * This function is blocking. It can take several seconds before it returns.
+ * There is no guarantee it will perform a successful join.
+ * Failures might be caused by temporary network outages, or by the invitation having expired.
+ *
+ * @param invitation A string containing the invitation URL.
+ *
+ * @return This function returns true if the local node joined the mesh it was invited to, false otherwise.
+ */
+ bool join(const char *invitation) {
+ return meshlink_join(handle, invitation);
+ }
- /// Use an invitation to join a mesh.
- /** This function allows the local node to join an existing mesh using an invitation URL generated by another node.
- * An invitation can only be used if the local node has never connected to other nodes before.
- * After a succesfully accepted invitation, the name of the local node may have changed.
- *
- * This function may only be called on a mesh that has not been started yet and which is not already part of an existing mesh.
- *
- * This function is blocking. It can take several seconds before it returns.
- * There is no guarantee it will perform a successful join.
- * Failures might be caused by temporary network outages, or by the invitation having expired.
- *
- * @param invitation A string containing the invitation URL.
- *
- * @return This function returns true if the local node joined the mesh it was invited to, false otherwise.
- */
- bool join(const char *invitation) {
- return meshlink_join(handle, invitation);
- }
+ /// Export the local node's key and addresses.
+ /** This function generates a string that contains the local node's public key and one or more IP addresses.
+ * The application can pass it in some way to another node, which can then import it,
+ * granting the local node access to the other node's mesh.
+ *
+ * @return This function returns a string that contains the exported key and addresses.
+ * The application should call free() after it has finished using this string.
+ */
+ char *export_key() {
+ return meshlink_export(handle);
+ }
- /// Export the local node's key and addresses.
- /** This function generates a string that contains the local node's public key and one or more IP addresses.
- * The application can pass it in some way to another node, which can then import it,
- * granting the local node access to the other node's mesh.
- *
- * @return This function returns a string that contains the exported key and addresses.
- * The application should call free() after it has finished using this string.
- */
- char *export_key() {
- return meshlink_export(handle);
- }
+ /// Import another node's key and addresses.
+ /** This function accepts a string containing the exported public key and addresses of another node.
+ * By importing this data, the local node grants the other node access to its mesh.
+ *
+ * @param data A string containing the other node's exported key and addresses.
+ *
+ * @return This function returns true if the data was valid and the other node has been granted access to the mesh, false otherwise.
+ */
+ bool import_key(const char *data) {
+ return meshlink_import(handle, data);
+ }
- /// Import another node's key and addresses.
- /** This function accepts a string containing the exported public key and addresses of another node.
- * By importing this data, the local node grants the other node access to its mesh.
- *
- * @param data A string containing the other node's exported key and addresses.
- *
- * @return This function returns true if the data was valid and the other node has been granted access to the mesh, false otherwise.
- */
- bool import_key(const char *data) {
- return meshlink_import(handle, data);
- }
+ /// Blacklist a node from the mesh.
+ /** This function causes the local node to blacklist another node.
+ * The local node will drop any existing connections to that node,
+ * and will not send data to it nor accept any data received from it any more.
+ *
+ * @param node A pointer to a meshlink::node describing the node to be blacklisted.
+ */
+ void blacklist(node *node) {
+ return meshlink_blacklist(handle, node);
+ }
- /// Blacklist a node from the mesh.
- /** This function causes the local node to blacklist another node.
- * The local node will drop any existing connections to that node,
- * and will not send data to it nor accept any data received from it any more.
- *
- * @param node A pointer to a meshlink::node describing the node to be blacklisted.
- */
- void blacklist(node *node) {
- return meshlink_blacklist(handle, node);
- }
+ /// Set the poll callback.
+ /** This functions sets the callback that is called whenever data can be sent to another node.
+ * The callback is run in MeshLink's own thread.
+ * It is therefore important that the callback uses apprioriate methods (queues, pipes, locking, etc.)
+ * to pass data to or from the application's thread.
+ * The callback should also not block itself and return as quickly as possible.
+ *
+ * @param channel A handle for the channel.
+ * @param cb A pointer to the function which will be called when data can be sent to another node.
+ * If a NULL pointer is given, the callback will be disabled.
+ */
+ void set_channel_poll_cb(channel *channel, channel_poll_cb_t cb) {
+ meshlink_set_channel_poll_cb(handle, channel, (meshlink_channel_poll_cb_t)cb);
+ }
- /// Set the poll callback.
- /** This functions sets the callback that is called whenever data can be sent to another node.
- * The callback is run in MeshLink's own thread.
- * It is therefore important that the callback uses apprioriate methods (queues, pipes, locking, etc.)
- * to pass data to or from the application's thread.
- * The callback should also not block itself and return as quickly as possible.
- *
- * @param channel A handle for the channel.
- * @param cb A pointer to the function which will be called when data can be sent to another node.
- * If a NULL pointer is given, the callback will be disabled.
- */
- void set_channel_poll_cb(channel *channel, channel_poll_cb_t cb) {
- meshlink_set_channel_poll_cb(handle, channel, (meshlink_channel_poll_cb_t)cb);
- }
+ /// Open a reliable stream channel to another node.
+ /** This function is called whenever a remote node wants to open a channel to the local node.
+ * The application then has to decide whether to accept or reject this channel.
+ *
+ * This function sets the channel poll callback to channel_poll_trampoline, which in turn
+ * calls channel_poll. To set a differnt, channel-specific poll callback, use set_channel_poll_cb.
+ *
+ * @param node The node to which this channel is being initiated.
+ * @param port The port number the peer wishes to connect to.
+ * @param cb A pointer to the function which will be called when the remote node sends data to the local node.
+ * @param data A pointer to a buffer containing data to already queue for sending.
+ * @param len The length of the data.
+ * @param flags A bitwise-or'd combination of flags that set the semantics for this channel.
+ *
+ * @return A handle for the channel, or NULL in case of an error.
+ */
+ channel *channel_open(node *node, uint16_t port, channel_receive_cb_t cb, const void *data, size_t len, uint32_t flags = channel::TCP) {
+ channel *ch = (channel *)meshlink_channel_open_ex(handle, node, port, (meshlink_channel_receive_cb_t)cb, data, len, flags);
+ meshlink_set_channel_poll_cb(handle, ch, &channel_poll_trampoline);
+ return ch;
+ }
- /// Open a reliable stream channel to another node.
- /** This function is called whenever a remote node wants to open a channel to the local node.
- * The application then has to decide whether to accept or reject this channel.
- *
- * This function sets the channel poll callback to channel_poll_trampoline, which in turn
- * calls channel_poll. To set a differnt, channel-specific poll callback, use set_channel_poll_cb.
- *
- * @param node The node to which this channel is being initiated.
- * @param port The port number the peer wishes to connect to.
- * @param cb A pointer to the function which will be called when the remote node sends data to the local node.
- * @param data A pointer to a buffer containing data to already queue for sending.
- * @param len The length of the data.
- * @param flags A bitwise-or'd combination of flags that set the semantics for this channel.
- *
- * @return A handle for the channel, or NULL in case of an error.
- */
- channel *channel_open(node *node, uint16_t port, channel_receive_cb_t cb, const void *data, size_t len, uint32_t flags = channel::TCP) {
- channel *ch = (channel *)meshlink_channel_open_ex(handle, node, port, (meshlink_channel_receive_cb_t)cb, data, len, flags);
- meshlink_set_channel_poll_cb(handle, ch, &channel_poll_trampoline);
- return ch;
- }
+ /**
+ * @override
+ * Sets channel_receive_trampoline as cb, which in turn calls this->channel_receive( ... ).
+ */
+ channel *channel_open(node *node, uint16_t port, const void *data, size_t len, uint32_t flags = channel::TCP) {
+ channel *ch = (channel *)meshlink_channel_open_ex(handle, node, port, &channel_receive_trampoline, data, len, flags);
+ meshlink_set_channel_poll_cb(handle, ch, &channel_poll_trampoline);
+ return ch;
+ }
- /**
- * @override
- * Sets channel_receive_trampoline as cb, which in turn calls this->channel_receive( ... ).
- */
- channel *channel_open(node *node, uint16_t port, const void *data, size_t len, uint32_t flags = channel::TCP) {
- channel *ch = (channel *)meshlink_channel_open_ex(handle, node, port, &channel_receive_trampoline, data, len, flags);
- meshlink_set_channel_poll_cb(handle, ch, &channel_poll_trampoline);
- return ch;
- }
+ /// Partially close a reliable stream channel.
+ /** This shuts down the read or write side of a channel, or both, without closing the handle.
+ * It can be used to inform the remote node that the local node has finished sending all data on the channel,
+ * but still allows waiting for incoming data from the remote node.
+ *
+ * @param channel A handle for the channel.
+ * @param direction Must be one of SHUT_RD, SHUT_WR or SHUT_RDWR.
+ */
+ void channel_shutdown(channel *channel, int direction) {
+ return meshlink_channel_shutdown(handle, channel, direction);
+ }
- /// Partially close a reliable stream channel.
- /** This shuts down the read or write side of a channel, or both, without closing the handle.
- * It can be used to inform the remote node that the local node has finished sending all data on the channel,
- * but still allows waiting for incoming data from the remote node.
- *
- * @param channel A handle for the channel.
- * @param direction Must be one of SHUT_RD, SHUT_WR or SHUT_RDWR.
- */
- void channel_shutdown(channel *channel, int direction) {
- return meshlink_channel_shutdown(handle, channel, direction);
- }
+ /// Close a reliable stream channel.
+ /** This informs the remote node that the local node has finished sending all data on the channel.
+ * It also causes the local node to stop accepting incoming data from the remote node.
+ * Afterwards, the channel handle is invalid and must not be used any more.
+ *
+ * @param channel A handle for the channel.
+ */
+ void channel_close(meshlink_channel_t *channel) {
+ return meshlink_channel_close(handle, channel);
+ }
- /// Close a reliable stream channel.
- /** This informs the remote node that the local node has finished sending all data on the channel.
- * It also causes the local node to stop accepting incoming data from the remote node.
- * Afterwards, the channel handle is invalid and must not be used any more.
- *
- * @param channel A handle for the channel.
- */
- void channel_close(meshlink_channel_t *channel) {
- return meshlink_channel_close(handle, channel);
- }
+ /// Transmit data on a channel
+ /** This queues data to send to the remote node.
+ *
+ * @param channel A handle for the channel.
+ * @param data A pointer to a buffer containing data sent by the source.
+ * @param len The length of the data.
+ *
+ * @return The amount of data that was queued, which can be less than len, or a negative value in case of an error.
+ */
+ ssize_t channel_send(channel *channel, void *data, size_t len) {
+ return meshlink_channel_send(handle, channel, data, len);
+ }
- /// Transmit data on a channel
- /** This queues data to send to the remote node.
- *
- * @param channel A handle for the channel.
- * @param data A pointer to a buffer containing data sent by the source.
- * @param len The length of the data.
- *
- * @return The amount of data that was queued, which can be less than len, or a negative value in case of an error.
- */
- ssize_t channel_send(channel *channel, void *data, size_t len) {
- return meshlink_channel_send(handle, channel, data, len);
- }
+private:
+ // non-copyable:
+ mesh(const mesh&) /* TODO: C++11: = delete */;
+ void operator=(const mesh&) /* TODO: C++11: = delete */ ;
+
+ /// static callback trampolines:
+ static void receive_trampoline(meshlink_handle_t* handle, meshlink_node_t* source, const void* data, size_t length) {
+ if(!(handle->priv))
+ return;
+ meshlink::mesh* that = static_cast<mesh*>(handle->priv);
+ that->receive(static_cast<node*>(source), data, length);
+ }
- private:
- // non-copyable:
- mesh(const mesh&) /* TODO: C++11: = delete */;
- void operator=(const mesh&) /* TODO: C++11: = delete */ ;
-
- /// static callback trampolines:
- static void receive_trampoline(meshlink_handle_t* handle, meshlink_node_t* source, const void* data, size_t length)
- {
- 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))
- return;
- meshlink::mesh* that = static_cast<mesh*>(handle->priv);
- that->node_status(static_cast<node*>(peer), reachable);
- }
+ static void node_status_trampoline(meshlink_handle_t* handle, meshlink_node_t* peer, bool reachable) {
+ 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))
- return;
- meshlink::mesh* that = static_cast<mesh*>(handle->priv);
- that->log(level, message);
- }
+ static void log_trampoline(meshlink_handle_t* handle, log_level_t level, const char* message) {
+ 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))
- 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 bool channel_accept_trampoline(meshlink_handle_t *handle, meshlink_channel *channel, uint16_t port, const void *data, size_t len) {
+ 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))
- return;
- meshlink::mesh* that = static_cast<mesh*>(handle->priv);
- that->channel_receive(static_cast<meshlink::channel*>(channel), data, len);
- }
+ static void channel_receive_trampoline(meshlink_handle_t *handle, meshlink_channel *channel, const void* data, size_t len) {
+ 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))
- return;
- meshlink::mesh* that = static_cast<mesh*>(handle->priv);
- that->channel_poll(static_cast<meshlink::channel*>(channel), len);
- }
+ static void channel_poll_trampoline(meshlink_handle_t *handle, meshlink_channel *channel, size_t len) {
+ if(!(handle->priv))
+ return;
+ meshlink::mesh* that = static_cast<mesh*>(handle->priv);
+ that->channel_poll(static_cast<meshlink::channel*>(channel), len);
+ }
- meshlink_handle_t* handle;
- };
+ meshlink_handle_t* handle;
+};
- static const char *strerror(errno_t err = meshlink_errno) {
- return meshlink_strerror(err);
- }
+static const char *strerror(errno_t err = meshlink_errno) {
+ return meshlink_strerror(err);
+}
- /// Destroy a MeshLink instance.
- /** This function remove all configuration files of a MeshLink instance. It should only be called when the application
- * does not have an open handle to this instance. Afterwards, a call to meshlink_open() will create a completely
- * new instance.
- *
- * @param confbase The directory in which MeshLink stores its configuration files.
- * After the function returns, the application is free to overwrite or free @a confbase @a.
- *
- * @return This function will return true if the MeshLink instance was succesfully destroyed, false otherwise.
- */
- static bool destroy(const char *confbase) {
- return meshlink_destroy(confbase);
- }
+/// Destroy a MeshLink instance.
+/** This function remove all configuration files of a MeshLink instance. It should only be called when the application
+ * does not have an open handle to this instance. Afterwards, a call to meshlink_open() will create a completely
+ * new instance.
+ *
+ * @param confbase The directory in which MeshLink stores its configuration files.
+ * After the function returns, the application is free to overwrite or free @a confbase @a.
+ *
+ * @return This function will return true if the MeshLink instance was succesfully destroyed, false otherwise.
+ */
+static bool destroy(const char *confbase) {
+ return meshlink_destroy(confbase);
+}
}
#endif // MESHLINKPP_H
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);
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(!b64key) {
fclose(fh);
return false;
- }
+ }
fprintf(fh, "ECDSAPublicKey = %s\n", b64key);
fprintf(fh, "Port = %s\n", mesh->myport);
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);
-
- case 0:
- mesh->data = xrealloc(mesh->data, mesh->thedatalen + len + 1);
- memcpy(mesh->data + mesh->thedatalen, msg, len);
- mesh->thedatalen += len;
- mesh->data[mesh->thedatalen] = 0;
- break;
+ case SPTPS_HANDSHAKE:
+ return sptps_send_record(&(mesh->sptps), 0, mesh->cookie, sizeof mesh->cookie);
- case 1:
- mesh->thedatalen = 0;
- return finalize_join(mesh);
+ case 0:
+ mesh->data = xrealloc(mesh->data, mesh->thedatalen + len + 1);
+ memcpy(mesh->data + mesh->thedatalen, msg, len);
+ mesh->thedatalen += len;
+ mesh->data[mesh->thedatalen] = 0;
+ break;
- case 2:
- logger(mesh, MESHLINK_DEBUG, "Invitation succesfully accepted.\n");
- shutdown(mesh->sock, SHUT_RDWR);
- mesh->success = true;
- break;
+ case 1:
+ mesh->thedatalen = 0;
+ return finalize_join(mesh);
- default:
- return false;
+ case 2:
+ logger(mesh, MESHLINK_DEBUG, "Invitation succesfully accepted.\n");
+ shutdown(mesh->sock, SHUT_RDWR);
+ mesh->success = true;
+ break;
+
+ default:
+ return false;
}
return true;
meshlink_handle_t *meshlink_open(const char *confbase, const char *name, const char* appname, dev_class_t devclass) {
// Validate arguments provided by the application
bool usingname = false;
-
+
logger(NULL, MESHLINK_DEBUG, "meshlink_open called\n");
if(!confbase || !*confbase) {
if(!name || !*name) {
logger(NULL, MESHLINK_ERROR, "No name given!\n");
//return NULL;
- }
- else { //check name only if there is a name != NULL
+ } else { //check name only if there is a name != NULL
if(!check_id(name)) {
logger(NULL, MESHLINK_ERROR, "Invalid name given!\n");
meshlink_errno = MESHLINK_EINVAL;
return NULL;
- } else { usingname = true;}
+ } else
+ usingname = true;
}
if(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;
pthread_mutexattr_init(&attr);
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
pthread_mutex_init(&(mesh->mesh_mutex), &attr);
-
+
mesh->threadstarted = false;
event_loop_init(&mesh->loop);
mesh->loop.data = mesh;
meshlink_errno = MESHLINK_EINVAL;
return false;
}
-
+
logger(mesh, MESHLINK_DEBUG, "meshlink_start called\n");
pthread_mutex_lock(&(mesh->mesh_mutex));
// TODO: open listening sockets first
//Check that a valid name is set
- if(!mesh->name ) {
+ if(!mesh->name) {
logger(mesh, MESHLINK_DEBUG, "No name given!\n");
meshlink_errno = MESHLINK_EINVAL;
pthread_mutex_unlock(&(mesh->mesh_mutex));
// leave the last byte as 0 to make sure strings are always
// null-terminated if they are longer than the buffer
strncpy(hdr->destination, destination->name, (sizeof hdr->destination) - 1);
- strncpy(hdr->source, mesh->self->name, (sizeof hdr->source) -1 );
+ strncpy(hdr->source, mesh->self->name, (sizeof hdr->source) -1);
memcpy(packet->data + sizeof *hdr, data, len);
// Notify event loop
signal_trigger(&(mesh->loop),&(mesh->datafromapp));
-
+
return true;
}
if(!n->status.reachable) {
pthread_mutex_unlock(&(mesh->mesh_mutex));
return 0;
-
- }
- else if(n->mtuprobes > 30 && n->minmtu) {
+
+ } else if(n->mtuprobes > 30 && n->minmtu) {
pthread_mutex_unlock(&(mesh->mesh_mutex));
return n->minmtu;
- }
- else {
+ } else {
pthread_mutex_unlock(&(mesh->mesh_mutex));
return MTU;
}
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;
}
static bool refresh_invitation_key(meshlink_handle_t *mesh) {
char filename[PATH_MAX];
-
+
pthread_mutex_lock(&(mesh->mesh_mutex));
snprintf(filename, sizeof filename, "%s" SLASH "invitations", mesh->confbase);
meshlink_errno = MESHLINK_EINVAL;
return NULL;
}
-
+
pthread_mutex_lock(&(mesh->mesh_mutex));
// Check validity of the new node's name
// Fill in the details.
fprintf(f, "Name = %s\n", name);
//if(netname)
- // fprintf(f, "NetName = %s\n", netname);
+ // fprintf(f, "NetName = %s\n", netname);
fprintf(f, "ConnectTo = %s\n", mesh->self->name);
// Copy Broadcast and Mode
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]))) {
+ || (!strncasecmp(buf, "Broadcast", 9) && strchr(" \t=", buf[9]))) {
fputs(buf, f);
// Make sure there is a newline character.
if(!strchr(buf, '\n'))
meshlink_errno = MESHLINK_EINVAL;
return false;
}
-
+
pthread_mutex_lock(&(mesh->mesh_mutex));
//TODO: think of a better name for this variable, or of a different way to tokenize the invitation URL.
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);
}
pthread_mutex_lock(&(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");
fclose(f);
buf[len - 1] = 0;
-
+
pthread_mutex_unlock(&(mesh->mesh_mutex));
return buf;
}
meshlink_errno = MESHLINK_EINVAL;
return false;
}
-
+
pthread_mutex_lock(&(mesh->mesh_mutex));
if(strncmp(data, "Name = ", 7)) {
}
pthread_mutex_lock(&(mesh->mesh_mutex));
-
+
node_t *n;
n = (node_t*)node;
n->status.blacklisted=true;
}
pthread_mutex_lock(&(mesh->mesh_mutex));
-
+
node_t *n = (node_t *)node;
n->status.blacklisted = false;
// Ignore hints about ourself.
if((node_t *)node == mesh->self)
return;
-
+
pthread_mutex_lock(&(mesh->mesh_mutex));
-
+
char *host = NULL, *port = NULL, *str = NULL;
sockaddr2str((const sockaddr_t *)addr, &host, &port);
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))
append_config_file(mesh, node->name, "Address", str);
else
logger(mesh, MESHLINK_DEBUG, "Not adding Link Local IPv6 Address to config\n");
}
pthread_mutex_lock(&(mesh->mesh_mutex));
-
+
meshlink_edge_t **result = NULL;
meshlink_edge_t *copy = NULL;
int result_size = 0;
result_size = mesh->edges->count;
// if result is smaller than edges, we have to dealloc all the excess meshlink_edge_t
- if(result_size > *nmemb) {
- result = realloc(edges, result_size * sizeof (meshlink_edge_t*));
- } else {
+ if(result_size > *nmemb)
+ result = realloc(edges, result_size * sizeof(meshlink_edge_t*));
+ else
result = edges;
- }
if(result) {
meshlink_edge_t **p = result;
}
n++;
// the first *nmemb members of result can be re-used
- if(n > *nmemb) {
+ if(n > *nmemb)
copy = xzalloc(sizeof *copy);
- }
- else {
+ else
copy = *p;
- }
copy->from = (meshlink_node_t*)e->from;
copy->to = (meshlink_node_t*)e->to;
copy->address = e->address.storage;
*p++ = copy;
}
// shrink result to the actual amount of memory used
- for(int i = *nmemb; i > result_size; i--) {
+ for(int i = *nmemb; i > result_size; i--)
free(result[i - 1]);
- }
- result = realloc(result, result_size * sizeof (meshlink_edge_t*));
+ result = realloc(result, result_size * sizeof(meshlink_edge_t*));
*nmemb = result_size;
} else {
*nmemb = 0;
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);
}
/// Device class traits
dev_class_traits_t dev_class_traits[_DEV_CLASS_MAX +1] = {
- { .min_connects = 3, .max_connects = 10000, .edge_weight = 1 }, // DEV_CLASS_BACKBONE
- { .min_connects = 3, .max_connects = 100, .edge_weight = 3 }, // DEV_CLASS_STATIONARY
- { .min_connects = 3, .max_connects = 3, .edge_weight = 6 }, // DEV_CLASS_PORTABLE
- { .min_connects = 1, .max_connects = 1, .edge_weight = 9 }, // DEV_CLASS_UNKNOWN
+ { .min_connects = 3, .max_connects = 10000, .edge_weight = 1 }, // DEV_CLASS_BACKBONE
+ { .min_connects = 3, .max_connects = 100, .edge_weight = 3 }, // DEV_CLASS_STATIONARY
+ { .min_connects = 3, .max_connects = 3, .edge_weight = 6 }, // DEV_CLASS_PORTABLE
+ { .min_connects = 1, .max_connects = 1, .edge_weight = 9 }, // DEV_CLASS_UNKNOWN
};
/// An edge in the meshlink network.
struct meshlink_edge {
struct meshlink_node *from; ///< Pointer to a node. Node memory is
- // owned by meshlink and should not be
- // deallocated. Node contents may be
- // changed by meshlink.
+ // owned by meshlink and should not be
+ // deallocated. Node contents may be
+ // changed by meshlink.
struct meshlink_node *to; ///< Pointer to a node. Node memory is
- // owned by meshlink and should not be
- // deallocated. Node contents may be
- // changed by meshlink.
+ // owned by meshlink and should not be
+ // deallocated. Node contents may be
+ // changed by meshlink.
struct sockaddr_storage address;///< The address information associated
- // with this edge.
+ // with this edge.
uint32_t options; ///< Edge options. @TODO what are edge options?
int weight; ///< Weight assigned to this edge.
};
* @param data A pointer to a buffer containing data to already queue for sending, or NULL if there is no data to send.
* After meshlink_send() returns, the application is free to overwrite or free this buffer.
* @param len The length of the data, or 0 if there is no data to send.
- * @param flags A bitwise-or'd combination of flags that set the semantics for this channel.
+ * @param flags A bitwise-or'd combination of flags that set the semantics for this channel.
*
* @return A handle for the channel, or NULL in case of an error.
* The handle is valid until meshlink_channel_close() is called.
* on the array to change its size.
* The contents of this variable will be changed to reflect
* the new size of the array.
- * @return A pointer to an array containing pointers to all known
+ * @return A pointer to an array containing pointers to all known
* edges, or NULL in case of an error.
* If the @a edges @a argument was not NULL, then the
* retun value can be either the same value or a different
struct connection_t *everyone;
struct ecdsa *invitation_key;
- int pinginterval; /* seconds between pings */
- int pingtimeout; /* seconds to wait for response */
+ int pinginterval; /* seconds between pings */
+ int pingtimeout; /* seconds to wait for response */
int maxtimeout;
int sock;
typedef struct meshlink_packethdr {
uint8_t destination[16];
uint8_t source[16];
-} __attribute__ ((__packed__)) meshlink_packethdr_t;
+} __attribute__((__packed__)) meshlink_packethdr_t;
extern void meshlink_send_from_queue(event_loop_t* el,meshlink_handle_t *mesh);
extern void update_node_status(meshlink_handle_t *mesh, struct node_t *n);
#include <unistd.h>
typedef struct meshlink_queue {
- struct meshlink_queue_item *head;
- struct meshlink_queue_item *tail;
+ struct meshlink_queue_item *head;
+ struct meshlink_queue_item *tail;
pthread_mutex_t mutex;
} meshlink_queue_t;
}
logger(mesh, MESHLINK_DEBUG, "Sending %d bytes of metadata to %s (%s)", length,
- c->name, c->hostname);
+ c->name, c->hostname);
if(c->allow_request == ID) {
buffer_add(&c->outbuf, buffer, length);
if(inlen <= 0) {
if(!inlen || !errno) {
logger(mesh, MESHLINK_INFO, "Connection closed by %s (%s)",
- c->name, c->hostname);
+ c->name, c->hostname);
} else if(sockwouldblock(sockerrno))
return true;
else
logger(mesh, MESHLINK_ERROR, "Metadata socket read error for %s (%s): %s",
- c->name, c->hostname, sockstrerror(sockerrno));
+ c->name, c->hostname, sockstrerror(sockerrno));
return false;
}
if(c->inbuf.len >= sizeof inbuf) {
logger(mesh, MESHLINK_ERROR, "Input buffer full for %s (%s)", c->name, c->hostname);
return false;
- } else {
+ } else
return true;
- }
}
return sptps_receive_data(&c->sptps, inbuf, inlen);
}
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 (%s) didn't respond to PING in %ld seconds", c->name, c->hostname, (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)
logger(mesh, MESHLINK_WARNING, "Timeout while connecting to %s (%s)", c->name, c->hostname);
}
}
- timeout_set(&mesh->loop, data, &(struct timeval){mesh->pingtimeout, rand() % 100000});
+ timeout_set(&mesh->loop, data, &(struct timeval) {
+ mesh->pingtimeout, rand() % 100000
+ });
}
// devclass asc, last_successfull_connection desc
-static int node_compare_devclass_asc_lsc_desc(const void *a, const void *b)
-{
+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)
- { return -1; }
+ return -1;
if(na->devclass > nb->devclass)
- { return 1; }
+ return 1;
if(na->last_successfull_connection == nb->last_successfull_connection)
return 0;
}
// last_successfull_connection desc
-static int node_compare_lsc_desc(const void *a, const void *b)
-{
+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)
}
// devclass desc
-static int node_compare_devclass_desc(const void *a, const void *b)
-{
+static int node_compare_devclass_desc(const void *a, const void *b) {
const node_t *na = a, *nb = b;
if(na->devclass < nb->devclass)
- { return -1; }
+ return -1;
if(na->devclass > nb->devclass)
- { return 1; }
+ return 1;
if(na < nb)
return -1;
autoconnect()
{
- timeout = 5
+ timeout = 5
- // find the best one for initial connect
+ // find the best one for initial connect
- if cur < min
- newcon =
- first from nodes
- where dclass <= my.dclass and !connection and (timestamp - last_retry) > retry_timeout
- order by dclass asc, last_connection desc
- if newcon
- timeout = 0
- goto connect
+ if cur < min
+ newcon =
+ first from nodes
+ where dclass <= my.dclass and !connection and (timestamp - last_retry) > retry_timeout
+ order by dclass asc, last_connection desc
+ if newcon
+ timeout = 0
+ goto connect
- // find better nodes to connect to: in case we have less than min connections within [BACKBONE, i] and there are nodes which we are not connected to within the range
+ // find better nodes to connect to: in case we have less than min connections within [BACKBONE, i] and there are nodes which we are not connected to within the range
- if min <= cur < max
- j = 0
- for i = BACKBONE to my.dclass
- j += count(from connections where node.dclass = i)
- if j < min
- newcon =
- first from nodes
- where dclass = i and !connection and (timestamp - last_retry) > retry_timeout
- order by last_connection desc
- if newcon
- goto connect
- else
- break
+ if min <= cur < max
+ j = 0
+ for i = BACKBONE to my.dclass
+ j += count(from connections where node.dclass = i)
+ if j < min
+ newcon =
+ first from nodes
+ where dclass = i and !connection and (timestamp - last_retry) > retry_timeout
+ order by last_connection desc
+ if newcon
+ goto connect
+ else
+ break
- // heal partitions
+ // heal partitions
- if min <= cur < max
- newcon =
- first from nodes
- where dclass <= my.dclass and !reachable and (timestamp - last_retry) > retry_timeout
- order by dclass asc, last_connection desc
- if newcon
- goto connect
+ if min <= cur < max
+ newcon =
+ first from nodes
+ where dclass <= my.dclass and !reachable and (timestamp - last_retry) > retry_timeout
+ order by dclass asc, last_connection desc
+ if newcon
+ goto connect
- // connect
+ // connect
connect:
- if newcon
- connect newcon
-
-
- // disconnect outgoing connections in case we have more than min connections within [BACKBONE, i] and there are nodes which we are connected to within the range [i, PORTABLE]
-
- if min < cur <= max
- j = 0
- for i = BACKBONE to my.dclass
- j += count(from connections where node.dclass = i)
- if min < j
- delcon =
- first from nodes
- where dclass >= i and outgoing_connection
- order by dclass desc
- if disconnect
- goto disconnect
- else
- break
+ if newcon
+ connect newcon
+
+ // disconnect outgoing connections in case we have more than min connections within [BACKBONE, i] and there are nodes which we are connected to within the range [i, PORTABLE]
- // disconnect connections in case we have more than enough connections
+ if min < cur <= max
+ j = 0
+ for i = BACKBONE to my.dclass
+ j += count(from connections where node.dclass = i)
+ if min < j
+ delcon =
+ first from nodes
+ where dclass >= i and outgoing_connection
+ order by dclass desc
+ if disconnect
+ goto disconnect
+ else
+ break
- if max < cur
- delcon =
- first from nodes
- where outgoing_connection
- order by dclass desc
- goto disconnect
- // disconnect
+ // disconnect connections in case we have more than enough connections
+
+ if max < cur
+ delcon =
+ first from nodes
+ where outgoing_connection
+ order by dclass desc
+ goto disconnect
+
+ // disconnect
disconnect
- if delcon
- disconnect delcon
+ if delcon
+ disconnect delcon
- // next iteration
- next (timeout, autoconnect)
+ // next iteration
+ next (timeout, autoconnect)
}
int cur_connects = 0;
- for list_each(connection_t, c, mesh->connections)
- {
+ for list_each(connection_t, c, mesh->connections) {
if(c->status.active)
- {
cur_connects += 1;
- }
}
logger(mesh, MESHLINK_DEBUG, "* cur_connects = %d", cur_connects);
// find the best one for initial connect
- if(cur_connects < min_connects)
- {
+ if(cur_connects < min_connects) {
splay_tree_t *nodes = splay_alloc_tree(node_compare_devclass_asc_lsc_desc, NULL);
- for splay_each(node_t, n, mesh->nodes)
- {
+ 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))
- { splay_insert(nodes, n); }
+ splay_insert(nodes, n);
}
- if(nodes->head)
- {
+ if(nodes->head) {
logger(mesh, MESHLINK_DEBUG, "* found best one for initial connect");
//timeout = 0;
connect_to = (node_t*)nodes->head->data;
- }
- else
- { logger(mesh, MESHLINK_DEBUG, "* could not find node for initial connect"); }
+ } else
+ logger(mesh, MESHLINK_DEBUG, "* could not find node for initial connect");
splay_free_tree(nodes);
}
// find better nodes to connect to
- if(!connect_to && min_connects <= cur_connects && cur_connects < max_connects)
- {
+ if(!connect_to && min_connects <= cur_connects && cur_connects < max_connects) {
unsigned int connects = 0;
- for(int devclass = 0; devclass <= mesh->devclass; ++devclass)
- {
- for list_each(connection_t, c, mesh->connections)
- {
+ for(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)
- { connects += 1; }
+ connects += 1;
}
- if( connects < min_connects )
- {
+ if(connects < min_connects) {
splay_tree_t *nodes = splay_alloc_tree(node_compare_lsc_desc, NULL);
- for splay_each(node_t, n, mesh->nodes)
- {
+ 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))
- { splay_insert(nodes, n); }
+ splay_insert(nodes, n);
}
- if(nodes->head)
- {
+ if(nodes->head) {
logger(mesh, MESHLINK_DEBUG, "* found better node");
connect_to = (node_t*)nodes->head->data;
}
splay_free_tree(nodes);
- }
- else
- { break; }
+ } else
+ break;
}
if(!connect_to)
- { logger(mesh, MESHLINK_DEBUG, "* could not find better nodes"); }
+ logger(mesh, MESHLINK_DEBUG, "* could not find better nodes");
}
// heal partitions
- if(!connect_to && min_connects <= cur_connects && cur_connects < max_connects)
- {
+ if(!connect_to && min_connects <= cur_connects && cur_connects < max_connects) {
splay_tree_t *nodes = splay_alloc_tree(node_compare_devclass_asc_lsc_desc, NULL);
- for splay_each(node_t, n, mesh->nodes)
- {
+ 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))
- { splay_insert(nodes, n); }
+ splay_insert(nodes, n);
}
- if(nodes->head)
- {
+ if(nodes->head) {
logger(mesh, MESHLINK_DEBUG, "* try to heal partition");
connect_to = (node_t*)nodes->head->data;
- }
- else
- { logger(mesh, MESHLINK_DEBUG, "* could not find nodes for partition healing"); }
+ } else
+ logger(mesh, MESHLINK_DEBUG, "* could not find nodes for partition healing");
splay_free_tree(nodes);
}
// perform connect
- if(connect_to && !connect_to->connection)
- {
+ if(connect_to && !connect_to->connection) {
connect_to->last_connect_try = time(NULL);
/* 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))
- {
+ for list_each(outgoing_t, outgoing, mesh->outgoings) {
+ if(!strcmp(outgoing->name, connect_to->name)) {
found = true;
break;
}
}
- if(!found)
- {
+ if(!found) {
logger(mesh, MESHLINK_DEBUG, "Autoconnecting to %s", connect_to->name);
outgoing_t *outgoing = xzalloc(sizeof(outgoing_t));
outgoing->mesh = mesh;
outgoing->name = xstrdup(connect_to->name);
list_insert_tail(mesh->outgoings, outgoing);
setup_outgoing_connection(mesh, outgoing);
- }
- else
- { logger(mesh, MESHLINK_DEBUG, "* skip autoconnect since it is an outgoing connection already"); }
+ } else
+ logger(mesh, MESHLINK_DEBUG, "* skip autoconnect since it is an outgoing connection already");
}
// disconnect suboptimal outgoing connections
- if(min_connects < cur_connects /*&& cur_connects <= max_connects*/)
- {
+ if(min_connects < cur_connects /*&& cur_connects <= max_connects*/) {
unsigned int connects = 0;
- for(int devclass = 0; devclass <= mesh->devclass; ++devclass)
- {
- for list_each(connection_t, c, mesh->connections)
- {
+ for(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)
- { connects += 1; }
+ connects += 1;
}
- if( min_connects < connects )
- {
+ if(min_connects < connects) {
splay_tree_t *nodes = splay_alloc_tree(node_compare_devclass_desc, NULL);
- for list_each(connection_t, c, mesh->connections)
- {
+ for list_each(connection_t, c, mesh->connections) {
if(c->outgoing && c->node && c->node->devclass >= devclass)
- { splay_insert(nodes, c->node); }
+ splay_insert(nodes, c->node);
}
- if(nodes->head)
- {
+ if(nodes->head) {
logger(mesh, MESHLINK_DEBUG, "* disconnect suboptimal outgoing connection");
disconnect_from = (node_t*)nodes->head->data;
}
}
if(!disconnect_from)
- { logger(mesh, MESHLINK_DEBUG, "* no suboptimal outgoing connections"); }
+ logger(mesh, MESHLINK_DEBUG, "* no suboptimal outgoing connections");
}
// disconnect connections (too many connections)
- if(!disconnect_from && max_connects < cur_connects)
- {
+ if(!disconnect_from && max_connects < cur_connects) {
splay_tree_t *nodes = splay_alloc_tree(node_compare_devclass_desc, NULL);
- for list_each(connection_t, c, mesh->connections)
- {
+ for list_each(connection_t, c, mesh->connections) {
if(c->status.active && c->node)
- { splay_insert(nodes, c->node); }
+ splay_insert(nodes, c->node);
}
- if(nodes->head)
- {
+ if(nodes->head) {
logger(mesh, MESHLINK_DEBUG, "* disconnect connection (too many connections)");
//timeout = 0;
disconnect_from = (node_t*)nodes->head->data;
- }
- else
- { logger(mesh, MESHLINK_DEBUG, "* no node we want to disconnect, even though we have too many connections"); }
+ } else
+ logger(mesh, MESHLINK_DEBUG, "* no node we want to disconnect, even though we have too many connections");
splay_free_tree(nodes);
}
// perform disconnect
- if(disconnect_from && disconnect_from->connection)
- {
+ if(disconnect_from && disconnect_from->connection) {
logger(mesh, MESHLINK_DEBUG, "Autodisconnecting from %s", disconnect_from->connection->name);
list_delete(mesh->outgoings, disconnect_from->connection->outgoing);
disconnect_from->connection->outgoing = NULL;
logger(mesh, MESHLINK_DEBUG, "--- autoconnect end ---");
}
- timeout_set(&mesh->loop, data, &(struct timeval){timeout, rand() % 100000});
+ timeout_set(&mesh->loop, data, &(struct timeval) {
+ timeout, rand() % 100000
+ });
}
void handle_meta_connection_data(meshlink_handle_t *mesh, connection_t *c) {
- if (!receive_meta(mesh, c)) {
+ if(!receive_meta(mesh, c)) {
terminate_connection(mesh, c, c->status.active);
return;
}
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});
+ timeout_set(&mesh->loop, &outgoing->ev, &(struct timeval) {
+ 0, 0
+ });
}
/* Check for outgoing connections that are in progress, and reset their ping timers */
}
/* Kick the ping timeout handler */
- timeout_set(&mesh->loop, &mesh->pingtimer, &(struct timeval){0, 0});
+ timeout_set(&mesh->loop, &mesh->pingtimer, &(struct timeval) {
+ 0, 0
+ });
}
/*
this is where it all happens...
*/
int main_loop(meshlink_handle_t *mesh) {
- timeout_add(&mesh->loop, &mesh->pingtimer, timeout_handler, &mesh->pingtimer, &(struct timeval){mesh->pingtimeout, rand() % 100000});
- timeout_add(&mesh->loop, &mesh->periodictimer, periodic_handler, &mesh->periodictimer, &(struct timeval){0, 0});
+ timeout_add(&mesh->loop, &mesh->pingtimer, timeout_handler, &mesh->pingtimer, &(struct timeval) {
+ mesh->pingtimeout, rand() % 100000
+ });
+ timeout_add(&mesh->loop, &mesh->periodictimer, periodic_handler, &mesh->periodictimer, &(struct timeval) {
+ 0, 0
+ });
//Add signal handler
mesh->datafromapp.signum = 0;
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(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)
len = 64;
n->status.broadcast = false;
end:
- timeout_set(&mesh->loop, &n->mtutimeout, &(struct timeval){timeout, rand() % 100000});
+ timeout_set(&mesh->loop, &n->mtutimeout, &(struct timeval) {
+ timeout, rand() % 100000
+ });
}
void send_mtu_probe(meshlink_handle_t *mesh, node_t *n) {
- timeout_add(&mesh->loop, &n->mtutimeout, send_mtu_probe_handler, n, &(struct timeval){1, 0});
+ timeout_add(&mesh->loop, &n->mtutimeout, send_mtu_probe_handler, n, &(struct timeval) {
+ 1, 0
+ });
send_mtu_probe_handler(&mesh->loop, n);
}
/* If we haven't established the PMTU yet, restart the discovery process. */
if(n->mtuprobes > 30) {
- if (len == n->maxmtu + 8) {
+ if(len == n->maxmtu + 8) {
logger(mesh, MESHLINK_INFO, "Increase in PMTU to %s (%s) detected, restarting PMTU discovery", n->name, n->hostname);
n->maxmtu = MTU;
n->mtuprobes = 10;
if(level == 0) {
memcpy(dest, source, len);
return len;
- } else if(level == 10) {
+ } else if(level == 10)
return -1;
- } else if(level < 10) {
+ else if(level < 10) {
#ifdef HAVE_ZLIB
unsigned long destlen = MAXSIZE;
if(compress2(dest, &destlen, source, len, level) == Z_OK)
else
#endif
return -1;
- } else {
+ } else
return -1;
- }
return -1;
}
if(level == 0) {
memcpy(dest, source, len);
return len;
- } else if(level > 9) {
- return -1;
- }
+ } else if(level > 9)
+ return -1;
#ifdef HAVE_ZLIB
else {
unsigned long destlen = MAXSIZE;
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 (%s)",
- packet->len, n->name, n->hostname);
+ packet->len, n->name, n->hostname);
- if (n->status.blacklisted) {
- logger(mesh, MESHLINK_WARNING, "Dropping packet from blacklisted node %s", n->name);
- } else {
- n->in_packets++;
- n->in_bytes += packet->len;
+ if(n->status.blacklisted)
+ logger(mesh, MESHLINK_WARNING, "Dropping packet from blacklisted node %s", n->name);
+ else {
+ n->in_packets++;
+ n->in_bytes += packet->len;
- route(mesh, n, packet);
- }
+ route(mesh, n, packet);
+ }
}
static bool try_mac(meshlink_handle_t *mesh, node_t *n, const vpn_packet_t *inpkt) {
if(!n->status.waitingforkey) {
logger(mesh, MESHLINK_DEBUG, "Got packet from %s (%s) but we haven't exchanged keys yet", n->name, n->hostname);
send_req_key(mesh, n);
- } else {
+ } else
logger(mesh, MESHLINK_DEBUG, "Got packet from %s (%s) but he hasn't got our key yet", n->name, n->hostname);
- }
return;
}
sptps_receive_data(&n->sptps, inpkt->data, inpkt->len);
if(n->outcompression) {
int len = compress_packet(outpkt.data, origpkt->data, origpkt->len, n->outcompression);
- if(len < 0) {
+ if(len < 0)
logger(mesh, MESHLINK_ERROR, "Error while compressing packet to %s (%s)", n->name, n->hostname);
- } else if(len < origpkt->len) {
+ else if(len < origpkt->len) {
outpkt.len = len;
origpkt = &outpkt;
type |= PKT_COMPRESSED;
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 */
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 (%s)", type, len, from->name, from->hostname);
if(type & PKT_COMPRESSED) {
uint16_t ulen = uncompress_packet(inpkt.data, (const uint8_t *)data, len, from->incompression);
- if(ulen < 0) {
+ if(ulen < 0)
return false;
- } else {
+ else
inpkt.len = ulen;
- }
if(inpkt.len > MAXSIZE)
abort();
} else {
}
logger(mesh, MESHLINK_DEBUG, "Sending packet of %d bytes to %s (%s)",
- packet->len, n->name, n->hostname);
+ packet->len, n->name, n->hostname);
if(!n->status.reachable) {
logger(mesh, MESHLINK_WARNING, "Node %s (%s) is not reachable",
- n->name, n->hostname);
+ n->name, n->hostname);
return;
}
send_packet(mesh, mesh->self, packet);
logger(mesh, MESHLINK_INFO, "Broadcasting packet of %d bytes from %s (%s)",
- packet->len, from->name, from->hostname);
+ packet->len, from->name, from->hostname);
for list_each(connection_t, c, mesh->connections)
if(c->status.active && c->status.mst && c != from->nexthop->connection)
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;
- }
+ 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);
}
bool node_read_devclass(meshlink_handle_t *mesh, node_t *n) {
-
+
splay_tree_t *config_tree;
char *p;
if(!read_host_config(mesh, config_tree, n->name))
goto exit;
- if(get_config_string(lookup_config(config_tree, "DeviceClass"), &p))
- {
+ if(get_config_string(lookup_config(config_tree, "DeviceClass"), &p)) {
n->devclass = atoi(p);
free(p);
}
if(n->devclass < 0 || n->devclass > _DEV_CLASS_MAX)
- { n->devclass = _DEV_CLASS_MAX; }
+ n->devclass = _DEV_CLASS_MAX;
exit:
exit_configuration(&config_tree);
config_t* cnf = lookup_config(config_tree, "DeviceClass");
- if(!cnf)
- {
+ if(!cnf) {
cnf = new_config();
cnf->variable = xstrdup("DeviceClass");
config_add(config_tree, cnf);
return false;
if(!add_listen_address(mesh, address, NULL))
return false;
- } else {
+ } else
return false;
- }
}
if(!mesh->listen_sockets) {
#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, "fcntl for %s: %s", c->hostname, 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, "ioctlsocket for %s: %s", c->hostname, sockstrerror(sockerrno));
- }
#endif
#if defined(SOL_TCP) && defined(TCP_NODELAY)
if(fcntl(nfd, F_SETFL, flags | O_NONBLOCK) < 0) {
closesocket(nfd);
logger(mesh, MESHLINK_ERROR, "System call `%s' failed: %s", "fcntl",
- strerror(errno));
+ strerror(errno));
return -1;
}
}
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});
+ timeout_add(&mesh->loop, &outgoing->ev, retry_outgoing_handler, outgoing, &(struct timeval) {
+ outgoing->timeout, rand() % 100000
+ });
logger(mesh, MESHLINK_INFO, "Trying to re-establish outgoing connection in %d seconds", outgoing->timeout);
}
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) {
+ if(!errno || errno == EPIPE)
logger(mesh, MESHLINK_INFO, "Connection closed by %s (%s)", c->name, c->hostname);
- } else if(sockwouldblock(sockerrno)) {
+ else if(sockwouldblock(sockerrno)) {
logger(mesh, MESHLINK_DEBUG, "Sending %d bytes to %s (%s) would block", c->outbuf.len - c->outbuf.offset, c->name, c->hostname);
return;
- } else {
+ } else
logger(mesh, MESHLINK_ERROR, "Could not send %d bytes of data to %s (%s): %s", c->outbuf.len - c->outbuf.offset, c->name, c->hostname, strerror(errno));
- }
terminate_connection(mesh, c, c->status.active);
return;
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);
/* 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)
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 {
+ else {
for list_each(outgoing_t, outgoing, mesh->outgoings)
outgoing->timeout = -1;
}
if(!check_id(name)) {
logger(mesh, MESHLINK_ERROR,
- "Invalid name for outgoing connection in %s line %d",
- cfg->file, cfg->line);
+ "Invalid name for outgoing connection in %s line %d",
+ cfg->file, cfg->line);
free(name);
continue;
}
}
err = getnameinfo(&sa->sa, SALEN(sa->sa), address, sizeof address, port, sizeof port,
- hostnames ? 0 : (NI_NUMERICHOST | NI_NUMERICSERV));
- if(err) {
+ hostnames ? 0 : (NI_NUMERICHOST | NI_NUMERICSERV));
+ 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);
if(result)
return result;
- switch (a->sa.sa_family) {
- case AF_UNSPEC:
- return 0;
+ switch(a->sa.sa_family) {
+ case AF_UNSPEC:
+ return 0;
- case AF_UNKNOWN:
- return strcmp(a->unknown.address, b->unknown.address);
+ case AF_UNKNOWN:
+ return strcmp(a->unknown.address, b->unknown.address);
- case AF_INET:
- return memcmp(&a->in.sin_addr, &b->in.sin_addr, sizeof(a->in.sin_addr));
+ case AF_INET:
+ return memcmp(&a->in.sin_addr, &b->in.sin_addr, sizeof(a->in.sin_addr));
- case AF_INET6:
- return memcmp(&a->in6.sin6_addr, &b->in6.sin6_addr, sizeof(a->in6.sin6_addr));
+ case AF_INET6:
+ return memcmp(&a->in6.sin6_addr, &b->in6.sin6_addr, sizeof(a->in6.sin6_addr));
- default:
- logger(NULL, MESHLINK_ERROR, "sockaddrcmp() was called with unknown address family %d, exitting!",
- a->sa.sa_family);
- abort();
+ default:
+ logger(NULL, MESHLINK_ERROR, "sockaddrcmp() was called with unknown address family %d, exitting!",
+ a->sa.sa_family);
+ abort();
}
}
if(result)
return result;
- switch (a->sa.sa_family) {
- case AF_UNSPEC:
- return 0;
+ switch(a->sa.sa_family) {
+ case AF_UNSPEC:
+ return 0;
- case AF_UNKNOWN:
- result = strcmp(a->unknown.address, b->unknown.address);
+ case AF_UNKNOWN:
+ result = strcmp(a->unknown.address, b->unknown.address);
- if(result)
- return result;
+ if(result)
+ return result;
- return strcmp(a->unknown.port, b->unknown.port);
+ 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);
+ case AF_INET:
+ result = memcmp(&a->in.sin_addr, &b->in.sin_addr, sizeof a->in.sin_addr);
- if(result)
- return result;
+ if(result)
+ return result;
- return memcmp(&a->in.sin_port, &b->in.sin_port, sizeof a->in.sin_port);
+ 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);
+ case AF_INET6:
+ result = memcmp(&a->in6.sin6_addr, &b->in6.sin6_addr, sizeof a->in6.sin6_addr);
- if(result)
- return result;
+ if(result)
+ return result;
- return memcmp(&a->in6.sin6_port, &b->in6.sin6_port, sizeof a->in6.sin6_port);
+ return memcmp(&a->in6.sin6_port, &b->in6.sin6_port, sizeof a->in6.sin6_port);
- default:
- logger(NULL, MESHLINK_ERROR, "sockaddrcmp() was called with unknown address family %d, exitting!",
- a->sa.sa_family);
- abort();
+ default:
+ logger(NULL, MESHLINK_ERROR, "sockaddrcmp() was called with unknown address family %d, exitting!",
+ a->sa.sa_family);
+ abort();
}
}
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);
extern bool hostnames;
-extern struct addrinfo *str2addrinfo(const char *, const char *, int) __attribute__ ((__malloc__));
+extern struct addrinfo *str2addrinfo(const char *, const char *, int) __attribute__((__malloc__));
extern sockaddr_t str2sockaddr(const char *, const char *);
extern void sockaddr2str(const sockaddr_t *, char **, char **);
-extern char *sockaddr2hostname(const sockaddr_t *) __attribute__ ((__malloc__));
+extern char *sockaddr2hostname(const sockaddr_t *) __attribute__((__malloc__));
extern int sockaddrcmp(const sockaddr_t *, const sockaddr_t *);
extern int sockaddrcmp_noport(const sockaddr_t *, const sockaddr_t *);
extern void sockaddrunmap(sockaddr_t *);
extern void init_nodes(struct meshlink_handle *mesh);
extern void exit_nodes(struct meshlink_handle *mesh);
-extern node_t *new_node(void) __attribute__ ((__malloc__));
+extern node_t *new_node(void) __attribute__((__malloc__));
extern void free_node(node_t *);
extern void node_add(struct meshlink_handle *mesh, node_t *);
extern void node_del(struct meshlink_handle *mesh, node_t *);
#ifndef __MESHLINK_PRF_H__
#define __MESHLINK_PRF_H__
-extern bool prf(const char *secret, size_t secretlen, char *seed, size_t seedlen, char *out, size_t outlen) __attribute__ ((__warn_unused_result__));
+extern bool prf(const char *secret, size_t secretlen, char *seed, size_t seedlen, char *out, size_t outlen) __attribute__((__warn_unused_result__));
#endif
/* Jumptable for the request handlers */
static bool (*request_handlers[])(meshlink_handle_t *, connection_t *, const char *) = {
- id_h, NULL, NULL, NULL /* metakey_h, challenge_h, chal_reply_h */, ack_h,
- status_h, error_h, termreq_h,
- ping_h, pong_h,
- NULL, NULL, //add_subnet_h, del_subnet_h,
- add_edge_h, del_edge_h,
- key_changed_h, req_key_h, ans_key_h, tcppacket_h, NULL, //control_h,
+ id_h, NULL, NULL, NULL /* metakey_h, challenge_h, chal_reply_h */, ack_h,
+ status_h, error_h, termreq_h,
+ ping_h, pong_h,
+ NULL, NULL, //add_subnet_h, del_subnet_h,
+ add_edge_h, del_edge_h,
+ key_changed_h, req_key_h, ans_key_h, tcppacket_h, NULL, //control_h,
};
/* Request names */
static char (*request_name[]) = {
- "ID", "METAKEY", "CHALLENGE", "CHAL_REPLY", "ACK",
- "STATUS", "ERROR", "TERMREQ",
- "PING", "PONG",
- "ADD_SUBNET", "DEL_SUBNET",
- "ADD_EDGE", "DEL_EDGE", "KEY_CHANGED", "REQ_KEY", "ANS_KEY", "PACKET", "CONTROL",
+ "ID", "METAKEY", "CHALLENGE", "CHAL_REPLY", "ACK",
+ "STATUS", "ERROR", "TERMREQ",
+ "PING", "PONG",
+ "ADD_SUBNET", "DEL_SUBNET",
+ "ADD_EDGE", "DEL_EDGE", "KEY_CHANGED", "REQ_KEY", "ANS_KEY", "PACKET", "CONTROL",
};
bool check_id(const char *id) {
if(len < 0 || len > MAXBUFSIZE - 1) {
logger(mesh, MESHLINK_ERROR, "Output buffer overflow while sending request to %s (%s)",
- c->name, c->hostname);
+ c->name, c->hostname);
return false;
}
if((reqno < 0) || (reqno >= LAST) || !request_handlers[reqno]) {
logger(mesh, MESHLINK_DEBUG, "Unknown request from %s (%s): %s", c->name, c->hostname, request);
return false;
- } else {
+ } else
logger(mesh, MESHLINK_DEBUG, "Got %s from %s (%s): %s", request_name[reqno], c->name, c->hostname, request);
- }
if((c->allow_request != ALL) && (c->allow_request != reqno)) {
logger(mesh, MESHLINK_ERROR, "Unauthorized request from %s (%s)", c->name, c->hostname);
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){10, rand() % 100000});
+ timeout_set(&mesh->loop, &mesh->past_request_timeout, &(struct timeval) {
+ 10, rand() % 100000
+ });
}
bool seen_request(meshlink_handle_t *mesh, const char *request) {
new->request = xstrdup(request);
new->firstseen = mesh->loop.now.tv_sec;
splay_insert(mesh->past_request_tree, new);
- timeout_add(&mesh->loop, &mesh->past_request_timeout, age_past_requests, NULL, &(struct timeval){10, rand() % 100000});
+ timeout_add(&mesh->loop, &mesh->past_request_timeout, age_past_requests, NULL, &(struct timeval) {
+ 10, rand() % 100000
+ });
return false;
}
}
/* Basic functions */
-extern bool send_request(struct meshlink_handle *mesh, struct connection_t *, const char *, ...) __attribute__ ((__format__(printf, 3, 4)));
+extern bool send_request(struct meshlink_handle *mesh, struct connection_t *, const char *, ...) __attribute__((__format__(printf, 3, 4)));
extern void forward_request(struct meshlink_handle *mesh, struct connection_t *, const char *);
extern bool receive_request(struct meshlink_handle *mesh, struct connection_t *, const char *);
extern bool check_id(const char *);
static bool send_proxyrequest(meshlink_handle_t *mesh, connection_t *c) {
switch(mesh->proxytype) {
- case PROXY_HTTP: {
- char *host;
- char *port;
-
- sockaddr2str(&c->address, &host, &port);
- send_request(mesh, c, "CONNECT %s:%s HTTP/1.1\r\n\r", host, port);
- free(host);
- 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)
- 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_HTTP: {
+ char *host;
+ char *port;
+
+ sockaddr2str(&c->address, &host, &port);
+ send_request(mesh, c, "CONNECT %s:%s HTTP/1.1\r\n\r", host, port);
+ free(host);
+ 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;
}
- case PROXY_SOCKS5: {
- int len = 3 + 6 + (c->address.sa.sa_family == AF_INET ? 4 : 16);
- c->tcplen = 2;
- 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;
- s5req[i++] = strlen(mesh->proxyuser);
- memcpy(s5req + i, mesh->proxyuser, strlen(mesh->proxyuser));
- i += strlen(mesh->proxyuser);
- s5req[i++] = strlen(mesh->proxypass);
- memcpy(s5req + i, mesh->proxypass, strlen(mesh->proxypass));
- i += strlen(mesh->proxypass);
- c->tcplen += 2;
- } else {
- s5req[i++] = 0;
- }
- s5req[i++] = 5;
+ 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)
+ 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)
+ 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;
+ s5req[i++] = strlen(mesh->proxyuser);
+ memcpy(s5req + i, mesh->proxyuser, strlen(mesh->proxyuser));
+ i += strlen(mesh->proxyuser);
+ s5req[i++] = strlen(mesh->proxypass);
+ memcpy(s5req + i, mesh->proxypass, strlen(mesh->proxypass));
+ i += strlen(mesh->proxypass);
+ c->tcplen += 2;
+ } else
s5req[i++] = 0;
- if(c->address.sa.sa_family == AF_INET) {
- s5req[i++] = 1;
- memcpy(s5req + i, &c->address.in.sin_addr, 4);
- i += 4;
- memcpy(s5req + i, &c->address.in.sin_port, 2);
- i += 2;
- c->tcplen += 10;
- } else if(c->address.sa.sa_family == AF_INET6) {
- s5req[i++] = 3;
- memcpy(s5req + i, &c->address.in6.sin6_addr, 16);
- i += 16;
- memcpy(s5req + i, &c->address.in6.sin6_port, 2);
- i += 2;
- c->tcplen += 22;
- } else {
- logger(mesh, MESHLINK_ERROR, "Address family %hx not supported for SOCKS 5 proxies!", c->address.sa.sa_family);
- return false;
- }
- 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");
+ 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);
+ i += 4;
+ memcpy(s5req + i, &c->address.in.sin_port, 2);
+ i += 2;
+ c->tcplen += 10;
+ } else if(c->address.sa.sa_family == AF_INET6) {
+ s5req[i++] = 3;
+ memcpy(s5req + i, &c->address.in6.sin6_addr, 16);
+ i += 16;
+ memcpy(s5req + i, &c->address.in6.sin6_port, 2);
+ i += 2;
+ c->tcplen += 22;
+ } else {
+ logger(mesh, MESHLINK_ERROR, "Address family %hx not supported for SOCKS 5 proxies!", c->address.sa.sa_family);
return false;
+ }
+ 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;
}
}
bool send_id(meshlink_handle_t *mesh, connection_t *c) {
-
+
int minor = mesh->self->connection->protocol_minor;
if(mesh->proxytype && c->outgoing)
if(sscanf(request, "%*d " MAX_STRING " %d.%d", name, &c->protocol_major, &c->protocol_minor) < 2) {
logger(mesh, MESHLINK_ERROR, "Got bad %s from %s (%s)", "ID", c->name,
- c->hostname);
+ c->hostname);
return false;
}
if(!check_id(name)) {
logger(mesh, MESHLINK_ERROR, "Got bad %s from %s (%s): %s", "ID", c->name,
- c->hostname, "invalid name");
+ c->hostname, "invalid name");
return false;
}
if(c->outgoing) {
if(strcmp(c->name, name)) {
logger(mesh, MESHLINK_ERROR, "Peer %s is %s instead of %s", c->hostname, name,
- c->name);
+ c->name);
return false;
}
} else {
if(c->protocol_major != mesh->self->connection->protocol_major) {
logger(mesh, MESHLINK_ERROR, "Peer %s (%s) uses incompatible version %d.%d",
- c->name, c->hostname, c->protocol_major, c->protocol_minor);
+ c->name, c->hostname, c->protocol_major, c->protocol_minor);
return false;
}
if(ecdsa_active(c->ecdsa) && c->protocol_minor < 2) {
logger(mesh, MESHLINK_ERROR, "Peer %s (%s) tries to roll back protocol version to %d.%d",
- c->name, c->hostname, c->protocol_major, c->protocol_minor);
+ c->name, c->hostname, c->protocol_major, c->protocol_minor);
return false;
}
if(sscanf(request, "%*d " MAX_STRING " %d %x", hisport, &devclass, &options) != 3) {
logger(mesh, MESHLINK_ERROR, "Got bad %s from %s (%s)", "ACK", c->name,
- c->hostname);
+ c->hostname);
return false;
}
if(devclass < 0 || devclass > _DEV_CLASS_MAX) {
logger(mesh, MESHLINK_ERROR, "Got bad %s from %s (%s): %s", "ACK", c->name,
- c->hostname, "devclass invalid");
+ c->hostname, "devclass invalid");
return false;
}
c->status.active = true;
logger(mesh, MESHLINK_INFO, "Connection with %s (%s) activated", c->name,
- c->hostname);
+ c->hostname);
/* Send him everything we know */
sockaddr2str(&e->address, &address, &port);
x = send_request(mesh, c, "%d %x %s %d %s %s %s %d %x %d", ADD_EDGE, rand(),
- e->from->name, e->from->devclass, e->to->name, address, port, e->to->devclass,
- e->options, e->weight);
+ e->from->name, e->from->devclass, e->to->name, address, port, e->to->devclass,
+ e->options, e->weight);
free(address);
free(port);
int weight;
if(sscanf(request, "%*d %*x "MAX_STRING" %d "MAX_STRING" "MAX_STRING" "MAX_STRING" %d %x %d",
- from_name, &from_devclass, to_name, to_address, to_port, &to_devclass, &options, &weight) != 8) {
+ from_name, &from_devclass, to_name, to_address, to_port, &to_devclass, &options, &weight) != 8) {
logger(mesh, MESHLINK_ERROR, "Got bad %s from %s (%s)", "ADD_EDGE", c->name,
- c->hostname);
+ c->hostname);
return false;
}
if(!check_id(from_name) || !check_id(to_name)) {
logger(mesh, MESHLINK_ERROR, "Got bad %s from %s (%s): %s", "ADD_EDGE", c->name,
- c->hostname, "invalid name");
+ c->hostname, "invalid name");
return false;
}
if(from_devclass < 0 || from_devclass > _DEV_CLASS_MAX) {
logger(mesh, MESHLINK_ERROR, "Got bad %s from %s (%s): %s", "ADD_EDGE", c->name,
- c->hostname, "from devclass invalid");
+ c->hostname, "from devclass invalid");
return false;
}
if(to_devclass < 0 || to_devclass > _DEV_CLASS_MAX) {
logger(mesh, MESHLINK_ERROR, "Got bad %s from %s (%s): %s", "ADD_EDGE", c->name,
- c->hostname, "to devclass invalid");
+ c->hostname, "to devclass invalid");
return false;
}
if(e->weight != weight || e->options != options || sockaddrcmp(&e->address, &address)) {
if(from == mesh->self) {
logger(mesh, MESHLINK_WARNING, "Got %s from %s (%s) for ourself which does not match existing entry",
- "ADD_EDGE", c->name, c->hostname);
+ "ADD_EDGE", c->name, c->hostname);
send_add_edge(mesh, c, e);
return true;
} else {
logger(mesh, MESHLINK_WARNING, "Got %s from %s (%s) which does not match existing entry",
- "ADD_EDGE", c->name, c->hostname);
+ "ADD_EDGE", c->name, c->hostname);
edge_del(mesh, e);
graph(mesh);
}
return true;
} else if(from == mesh->self) {
logger(mesh, MESHLINK_WARNING, "Got %s from %s (%s) for ourself which does not exist",
- "ADD_EDGE", c->name, c->hostname);
+ "ADD_EDGE", c->name, c->hostname);
mesh->contradicting_add_edge++;
e = new_edge();
e->from = from;
bool send_del_edge(meshlink_handle_t *mesh, connection_t *c, const edge_t *e) {
return send_request(mesh, c, "%d %x %s %s", DEL_EDGE, rand(),
- e->from->name, e->to->name);
+ e->from->name, e->to->name);
}
bool del_edge_h(meshlink_handle_t *mesh, connection_t *c, const char *request) {
if(sscanf(request, "%*d %*x "MAX_STRING" "MAX_STRING, from_name, to_name) != 2) {
logger(mesh, MESHLINK_ERROR, "Got bad %s from %s (%s)", "DEL_EDGE", c->name,
- c->hostname);
+ c->hostname);
return false;
}
if(!check_id(from_name) || !check_id(to_name)) {
logger(mesh, MESHLINK_ERROR, "Got bad %s from %s (%s): %s", "DEL_EDGE", c->name,
- c->hostname, "invalid name");
+ c->hostname, "invalid name");
return false;
}
if(!from) {
logger(mesh, MESHLINK_ERROR, "Got %s from %s (%s) which does not appear in the edge tree",
- "DEL_EDGE", c->name, c->hostname);
+ "DEL_EDGE", c->name, c->hostname);
return true;
}
if(!to) {
logger(mesh, MESHLINK_ERROR, "Got %s from %s (%s) which does not appear in the edge tree",
- "DEL_EDGE", c->name, c->hostname);
+ "DEL_EDGE", c->name, c->hostname);
return true;
}
if(!e) {
logger(mesh, MESHLINK_WARNING, "Got %s from %s (%s) which does not appear in the edge tree",
- "DEL_EDGE", c->name, c->hostname);
+ "DEL_EDGE", c->name, c->hostname);
return true;
}
if(e->from == mesh->self) {
logger(mesh, MESHLINK_WARNING, "Got %s from %s (%s) for ourself",
- "DEL_EDGE", c->name, c->hostname);
+ "DEL_EDGE", c->name, c->hostname);
mesh->contradicting_del_edge++;
send_add_edge(mesh, c, e); /* Send back a correction */
return true;
if(sscanf(request, "%*d %*x " MAX_STRING, name) != 1) {
logger(mesh, MESHLINK_ERROR, "Got bad %s from %s (%s)", "KEY_CHANGED",
- c->name, c->hostname);
+ c->name, c->hostname);
return false;
}
if(!n) {
logger(mesh, MESHLINK_ERROR, "Got %s from %s (%s) origin %s which does not exist",
- "KEY_CHANGED", c->name, c->hostname, name);
+ "KEY_CHANGED", c->name, c->hostname, name);
return true;
}
static bool req_key_ext_h(meshlink_handle_t *mesh, connection_t *c, const char *request, node_t *from, int reqno) {
switch(reqno) {
- case REQ_PUBKEY: {
- char *pubkey = ecdsa_get_base64_public_key(mesh->self->connection->ecdsa);
- send_request(mesh, from->nexthop->connection, "%d %s %s %d %s", REQ_KEY, mesh->self->name, from->name, ANS_PUBKEY, pubkey);
- free(pubkey);
+ case REQ_PUBKEY: {
+ char *pubkey = ecdsa_get_base64_public_key(mesh->self->connection->ecdsa);
+ send_request(mesh, from->nexthop->connection, "%d %s %s %d %s", REQ_KEY, mesh->self->name, from->name, ANS_PUBKEY, pubkey);
+ free(pubkey);
+ return true;
+ }
+
+ case ANS_PUBKEY: {
+ if(node_read_ecdsa_public_key(mesh, from)) {
+ logger(mesh, MESHLINK_WARNING, "Got ANS_PUBKEY from %s (%s) even though we already have his pubkey", from->name, from->hostname);
return true;
}
- case ANS_PUBKEY: {
- if(node_read_ecdsa_public_key(mesh, from)) {
- logger(mesh, MESHLINK_WARNING, "Got ANS_PUBKEY from %s (%s) even though we already have his pubkey", from->name, from->hostname);
- return true;
- }
+ 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): %s", "ANS_PUBKEY", from->name, from->hostname, "invalid pubkey");
+ return true;
+ }
- 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): %s", "ANS_PUBKEY", from->name, from->hostname, "invalid pubkey");
- return true;
- }
+ logger(mesh, MESHLINK_INFO, "Learned ECDSA public key from %s (%s)", from->name, from->hostname);
+ append_config_file(mesh, from->name, "ECDSAPublicKey", pubkey);
+ return true;
+ }
- logger(mesh, MESHLINK_INFO, "Learned ECDSA public key from %s (%s)", from->name, from->hostname);
- append_config_file(mesh, from->name, "ECDSAPublicKey", pubkey);
+ case REQ_KEY: {
+ if(!node_read_ecdsa_public_key(mesh, from)) {
+ logger(mesh, MESHLINK_DEBUG, "No ECDSA key known for %s (%s)", from->name, from->hostname);
+ send_request(mesh, from->nexthop->connection, "%d %s %s %d", REQ_KEY, mesh->self->name, from->name, REQ_PUBKEY);
return true;
}
- case REQ_KEY: {
- if(!node_read_ecdsa_public_key(mesh, from)) {
- logger(mesh, MESHLINK_DEBUG, "No ECDSA key known for %s (%s)", from->name, from->hostname);
- send_request(mesh, from->nexthop->connection, "%d %s %s %d", REQ_KEY, mesh->self->name, from->name, REQ_PUBKEY);
+ 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;
}
+ }
- 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): %s", "REQ_SPTPS_START", from->name, from->hostname, "invalid SPTPS data");
- return true;
- }
+ char buf[MAX_STRING_SIZE];
+ int len;
- char label[sizeof meshlink_udp_label + strlen(from->name) + strlen(mesh->self->name) + 2];
- snprintf(label, sizeof label, "%s %s %s", meshlink_udp_label, from->name, mesh->self->name);
- sptps_stop(&from->sptps);
- from->status.validkey = false;
- from->status.waitingforkey = true;
- from->last_req_key = mesh->loop.now.tv_sec;
- sptps_start(&from->sptps, from, false, true, mesh->self->connection->ecdsa, from->ecdsa, label, sizeof label - 1, send_sptps_data, receive_sptps_record);
- sptps_receive_data(&from->sptps, buf, 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): %s", "REQ_SPTPS_START", from->name, from->hostname, "invalid SPTPS data");
return true;
}
- case REQ_SPTPS: {
- if(!from->status.validkey) {
- logger(mesh, MESHLINK_ERROR, "Got REQ_SPTPS from %s (%s) but we don't have a valid key yet", from->name, from->hostname);
- return true;
- }
+ char label[sizeof meshlink_udp_label + strlen(from->name) + strlen(mesh->self->name) + 2];
+ snprintf(label, sizeof label, "%s %s %s", meshlink_udp_label, from->name, mesh->self->name);
+ sptps_stop(&from->sptps);
+ from->status.validkey = false;
+ from->status.waitingforkey = true;
+ from->last_req_key = mesh->loop.now.tv_sec;
+ sptps_start(&from->sptps, from, false, true, mesh->self->connection->ecdsa, from->ecdsa, label, sizeof label - 1, send_sptps_data, receive_sptps_record);
+ sptps_receive_data(&from->sptps, buf, len);
+ 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): %s", "REQ_SPTPS", from->name, from->hostname, "invalid SPTPS data");
- return true;
- }
- sptps_receive_data(&from->sptps, buf, len);
+ case REQ_SPTPS: {
+ if(!from->status.validkey) {
+ logger(mesh, MESHLINK_ERROR, "Got REQ_SPTPS from %s (%s) but we don't have a valid key yet", from->name, from->hostname);
return true;
}
- default:
- logger(mesh, MESHLINK_ERROR, "Unknown extended REQ_KEY request from %s (%s): %s", from->name, from->hostname, request);
+ 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): %s", "REQ_SPTPS", from->name, from->hostname, "invalid SPTPS data");
return true;
+ }
+ sptps_receive_data(&from->sptps, buf, len);
+ return true;
+ }
+
+ default:
+ logger(mesh, MESHLINK_ERROR, "Unknown extended REQ_KEY request from %s (%s): %s", from->name, from->hostname, request);
+ return true;
}
}
if(sscanf(request, "%*d " MAX_STRING " " MAX_STRING " %d", from_name, to_name, &reqno) < 2) {
logger(mesh, MESHLINK_ERROR, "Got bad %s from %s (%s)", "REQ_KEY", c->name,
- c->hostname);
+ c->hostname);
return false;
}
if(!from) {
logger(mesh, MESHLINK_ERROR, "Got %s from %s (%s) origin %s which does not exist in our connection list",
- "REQ_KEY", c->name, c->hostname, from_name);
+ "REQ_KEY", c->name, c->hostname, from_name);
return true;
}
if(!to) {
logger(mesh, MESHLINK_ERROR, "Got %s from %s (%s) destination %s which does not exist in our connection list",
- "REQ_KEY", c->name, c->hostname, to_name);
+ "REQ_KEY", c->name, c->hostname, to_name);
return true;
}
} else {
if(!to->status.reachable) {
logger(mesh, MESHLINK_WARNING, "Got %s from %s (%s) destination %s which is not reachable",
- "REQ_KEY", c->name, c->hostname, to_name);
+ "REQ_KEY", c->name, c->hostname, to_name);
return true;
}
node_t *from, *to;
if(sscanf(request, "%*d "MAX_STRING" "MAX_STRING" "MAX_STRING" %d %d %d %d "MAX_STRING" "MAX_STRING,
- from_name, to_name, key, &cipher, &digest, &maclength,
- &compression, address, port) < 7) {
+ from_name, to_name, key, &cipher, &digest, &maclength,
+ &compression, address, port) < 7) {
logger(mesh, MESHLINK_ERROR, "Got bad %s from %s (%s)", "ANS_KEY", c->name,
- c->hostname);
+ c->hostname);
return false;
}
if(!from) {
logger(mesh, MESHLINK_ERROR, "Got %s from %s (%s) origin %s which does not exist in our connection list",
- "ANS_KEY", c->name, c->hostname, from_name);
+ "ANS_KEY", c->name, c->hostname, from_name);
return true;
}
if(!to) {
logger(mesh, MESHLINK_ERROR, "Got %s from %s (%s) destination %s which does not exist in our connection list",
- "ANS_KEY", c->name, c->hostname, to_name);
+ "ANS_KEY", c->name, c->hostname, to_name);
return true;
}
if(to != mesh->self) {
if(!to->status.reachable) {
logger(mesh, MESHLINK_WARNING, "Got %s from %s (%s) destination %s which is not reachable",
- "ANS_KEY", c->name, c->hostname, to_name);
+ "ANS_KEY", c->name, c->hostname, to_name);
return true;
}
if(sscanf(request, "%*d %d " MAX_STRING, &statusno, statusstring) != 2) {
logger(mesh, MESHLINK_ERROR, "Got bad %s from %s (%s)", "STATUS",
- c->name, c->hostname);
+ c->name, c->hostname);
return false;
}
logger(mesh, MESHLINK_INFO, "Status message from %s (%s): %d: %s",
- c->name, c->hostname, statusno, statusstring);
+ c->name, c->hostname, statusno, statusstring);
return true;
}
if(sscanf(request, "%*d %d " MAX_STRING, &err, errorstring) != 2) {
logger(mesh, MESHLINK_ERROR, "Got bad %s from %s (%s)", "ERROR",
- c->name, c->hostname);
+ c->name, c->hostname);
return false;
}
logger(mesh, MESHLINK_INFO, "Error message from %s (%s): %d: %s",
- c->name, c->hostname, err, errorstring);
+ c->name, c->hostname, err, errorstring);
return false;
}
if(sscanf(request, "%*d %hd", &len) != 1) {
logger(mesh, MESHLINK_ERROR, "Got bad %s from %s (%s)", "PACKET", c->name,
- c->hostname);
+ c->hostname);
return false;
}
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
+ 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)
grandchild->parent = NULL;
root = grandchild;
- } else if (c > 0 && (grandchild = child->right)) {
+ } else if(c > 0 && (grandchild = child->right)) {
leftbottom->right = child;
child->parent = leftbottom;
leftbottom = child;
grandchild->parent = NULL;
root = grandchild;
- } else if (c < 0 && (grandchild = child->left)) {
+ } else if(c < 0 && (grandchild = child->left)) {
rightbottom->left = child;
child->parent = rightbottom;
rightbottom = child;
root = child;
break;
}
- } else {
+ } else
break;
- }
}
/* Merge trees */
node = node->right;
else
break;
- } else {
+ } else
break;
- }
}
if(result)
} else if(node->next) {
tree->root = node->right;
node->right->parent = NULL;
- } else {
+ } else
tree->root = NULL;
- }
tree->count--;
}
/* (De)constructors */
-extern splay_tree_t *splay_alloc_tree(splay_compare_t, splay_action_t) __attribute__ ((__malloc__));
+extern splay_tree_t *splay_alloc_tree(splay_compare_t, splay_action_t) __attribute__((__malloc__));
extern void splay_free_tree(splay_tree_t *);
-extern splay_node_t *splay_alloc_node(void) __attribute__ ((__malloc__));
+extern splay_node_t *splay_alloc_node(void) __attribute__((__malloc__));
extern void splay_free_node(splay_tree_t *tree, splay_node_t *);
/* Insertion and deletion */
static bool receive_handshake(sptps_t *s, const char *data, uint16_t len) {
// 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))
- return false;
- case SPTPS_KEX:
- // We have sent our KEX request, we expect our peer to sent one as well.
- 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))
- return false;
- if(s->outstate)
- s->state = SPTPS_ACK;
- else {
- s->outstate = true;
- 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))
+ case SPTPS_SECONDARY_KEX:
+ // We receive a secondary KEX request, first respond by sending our own.
+ if(!send_kex(s))
+ return false;
+ case SPTPS_KEX:
+ // We have sent our KEX request, we expect our peer to sent one as well.
+ 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))
+ return false;
+ if(s->outstate)
+ s->state = SPTPS_ACK;
+ else {
+ s->outstate = true;
+ if(!receive_ack(s, NULL, 0))
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);
+ }
+
+ return true;
+ case SPTPS_ACK:
+ // We expect a handshake message to indicate transition to the new keys.
+ 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)
warning(s, "Lost %d packets\n", seqno - s->inseqno);
// Mark all packets in the replay window as being late.
memset(s->late, 255, s->replaywin);
- } else if (seqno < s->inseqno) {
+ } 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)))
return error(s, EIO, "Received late or replayed packet, seqno %d, last received %d\n", seqno, s->inseqno);
} else if(type == SPTPS_HANDSHAKE) {
if(!receive_handshake(s, buffer + 1, len - 21))
abort();
- } else {
+ } else
return error(s, EIO, "Invalid record type %d", type);
- }
return true;
}
} else if(type == SPTPS_HANDSHAKE) {
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;
}
static void usage() {
fprintf(stderr, "Usage: %s [options] private_key_file public_key_file\n\n", program_name);
fprintf(stderr, "Valid options are:\n"
- " --help Display this help and exit.\n"
- "\n");
+ " --help Display this help and exit.\n"
+ "\n");
fprintf(stderr, "Report bugs to bugs@meshlink.io.\n");
}
int option_index = 0;
while((r = getopt_long(argc, argv, "", long_options, &option_index)) != EOF) {
- switch (r) {
- case 0: /* long option */
- break;
+ switch(r) {
+ case 0: /* long option */
+ break;
- case '?': /* wrong options */
- usage();
- return 1;
+ case '?': /* wrong options */
+ usage();
+ return 1;
- case 1: /* help */
- usage();
- return 0;
+ case 1: /* help */
+ usage();
+ return 0;
- default:
- break;
+ default:
+ break;
}
}
ecdsa_t *key = ecdsa_generate();
if(!key)
return 1;
-
+
FILE *fp = fopen(argv[1], "w");
if(fp) {
ecdsa_write_pem_private_key(key, fp);
#include "sptps.h"
// Symbols necessary to link with logger.o
-bool send_request(void *c, const char *msg, ...) { return false; }
+bool send_request(void *c, const char *msg, ...) {
+ return false;
+}
void *mesh;
void *global_log_cb;
int global_log_level;
-bool send_meta(void *c, const char *msg , int len) { return false; }
+bool send_meta(void *c, const char *msg, int len) {
+ return false;
+}
char *logfilename = NULL;
struct timeval now;
#include "utils.h"
// Symbols necessary to link with logger.o
-bool send_request(void *c, const char *msg, ...) { return false; }
+bool send_request(void *c, const char *msg, ...) {
+ return false;
+}
void *mesh;
void *global_log_cb;
int global_log_level;
-bool send_meta(void *c, const char *msg , int len) { return false; }
+bool send_meta(void *c, const char *msg, int len) {
+ return false;
+}
char *logfilename = NULL;
struct timeval now;
static void usage() {
fprintf(stderr, "Usage: %s [options] my_ecdsa_key_file his_ecdsa_key_file [host] port\n\n", program_name);
fprintf(stderr, "Valid options are:\n"
- " -d, --datagram Enable datagram mode.\n"
- " -q, --quit Quit when EOF occurs on stdin.\n"
- " -r, --readonly Only send data from the socket to stdout.\n"
+ " -d, --datagram Enable datagram mode.\n"
+ " -q, --quit Quit when EOF occurs on stdin.\n"
+ " -r, --readonly Only send data from the socket to stdout.\n"
#ifdef HAVE_LINUX
- " -t, --tun Use a tun device instead of stdio.\n"
+ " -t, --tun Use a tun device instead of stdio.\n"
#endif
- " -w, --writeonly Only send data from stdin to the socket.\n"
- " -L, --packet-loss RATE Fake packet loss of RATE percent.\n"
- " -R, --replay-window N Set replay window to N bytes.\n"
- " -v, --verbose Display debug messages.\n"
- "\n");
+ " -w, --writeonly Only send data from stdin to the socket.\n"
+ " -L, --packet-loss RATE Fake packet loss of RATE percent.\n"
+ " -R, --replay-window N Set replay window to N bytes.\n"
+ " -v, --verbose Display debug messages.\n"
+ "\n");
fprintf(stderr, "Report bugs to bugs@meshlink.io.\n");
}
bool quit = false;
while((r = getopt_long(argc, argv, "dqrtwL:W:v", long_options, &option_index)) != EOF) {
- switch (r) {
- case 0: /* long option */
- break;
+ switch(r) {
+ case 0: /* long option */
+ break;
- case 'd': /* datagram mode */
- datagram = true;
- break;
+ case 'd': /* datagram mode */
+ datagram = true;
+ break;
- case 'q': /* close connection on EOF from stdin */
- quit = true;
- break;
+ case 'q': /* close connection on EOF from stdin */
+ quit = true;
+ break;
- case 'r': /* read only */
- readonly = true;
- break;
+ case 'r': /* read only */
+ readonly = true;
+ break;
- case 't': /* read only */
+ case 't': /* read only */
#ifdef HAVE_LINUX
- tun = true;
+ tun = true;
#else
- fprintf(stderr, "--tun is only supported on Linux.\n");
- usage();
- return 1;
+ fprintf(stderr, "--tun is only supported on Linux.\n");
+ usage();
+ return 1;
#endif
- break;
+ break;
- case 'w': /* write only */
- writeonly = true;
- break;
+ case 'w': /* write only */
+ writeonly = true;
+ break;
- case 'L': /* packet loss rate */
- packetloss = atoi(optarg);
- break;
+ case 'L': /* packet loss rate */
+ packetloss = atoi(optarg);
+ break;
- case 'W': /* replay window size */
- sptps_replaywin = atoi(optarg);
- break;
+ case 'W': /* replay window size */
+ sptps_replaywin = atoi(optarg);
+ break;
- case 'v': /* be verbose */
- verbose = true;
- break;
+ case 'v': /* be verbose */
+ verbose = true;
+ break;
- case '?': /* wrong options */
- usage();
- return 1;
+ case '?': /* wrong options */
+ usage();
+ return 1;
- case 1: /* help */
- usage();
- return 0;
+ case 1: /* help */
+ usage();
+ return 0;
- default:
- break;
+ default:
+ break;
}
}
sptps_force_kex(&s);
if(len > 1)
sptps_send_record(&s, 0, buf, len);
- } else
- if(!sptps_send_record(&s, buf[0] == '!' ? 1 : 0, buf, (len == 1 && buf[0] == '\n') ? 0 : buf[0] == '*' ? sizeof buf : len))
+ } else if(!sptps_send_record(&s, buf[0] == '!' ? 1 : 0, buf, (len == 1 && buf[0] == '\n') ? 0 : buf[0] == '*' ? sizeof buf : len))
return 1;
}
if((i & 3) == 3) {
if(triplet & 0xff000000U)
return 0;
- udst[0] = triplet & 0xff; triplet >>= 8;
- udst[1] = triplet & 0xff; triplet >>= 8;
+ udst[0] = triplet & 0xff;
+ triplet >>= 8;
+ udst[1] = triplet & 0xff;
+ triplet >>= 8;
udst[2] = triplet;
triplet = 0;
udst += 3;
if(triplet & 0xff000000U)
return 0;
if((i & 3) == 3) {
- udst[0] = triplet & 0xff; triplet >>= 8;
+ udst[0] = triplet & 0xff;
+ triplet >>= 8;
udst[1] = triplet & 0xff;
return i / 4 * 3 + 2;
} 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) {
int di = length / 3 * 4;
switch(length % 3) {
- case 2:
- triplet = usrc[si] | usrc[si + 1] << 8;
- dst[di] = alphabet[triplet & 63]; triplet >>= 6;
- dst[di + 1] = alphabet[triplet & 63]; triplet >>= 6;
- dst[di + 2] = alphabet[triplet];
- dst[di + 3] = 0;
- length = di + 2;
- break;
- case 1:
- triplet = usrc[si];
- dst[di] = alphabet[triplet & 63]; triplet >>= 6;
- dst[di + 1] = alphabet[triplet];
- dst[di + 2] = 0;
- length = di + 1;
- break;
- default:
- dst[di] = 0;
- length = di;
- break;
+ case 2:
+ triplet = usrc[si] | usrc[si + 1] << 8;
+ dst[di] = alphabet[triplet & 63];
+ triplet >>= 6;
+ dst[di + 1] = alphabet[triplet & 63];
+ triplet >>= 6;
+ dst[di + 2] = alphabet[triplet];
+ dst[di + 3] = 0;
+ length = di + 2;
+ break;
+ case 1:
+ triplet = usrc[si];
+ dst[di] = alphabet[triplet & 63];
+ triplet >>= 6;
+ dst[di + 1] = alphabet[triplet];
+ dst[di + 2] = 0;
+ length = di + 1;
+ break;
+ default:
+ dst[di] = 0;
+ length = di;
+ break;
}
while(si > 0) {
di -= 4;
si -= 3;
triplet = usrc[si] | usrc[si + 1] << 8 | usrc[si + 2] << 16;
- dst[di] = alphabet[triplet & 63]; triplet >>= 6;
- dst[di + 1] = alphabet[triplet & 63]; triplet >>= 6;
- dst[di + 2] = alphabet[triplet & 63]; triplet >>= 6;
+ dst[di] = alphabet[triplet & 63];
+ triplet >>= 6;
+ dst[di + 1] = alphabet[triplet & 63];
+ triplet >>= 6;
+ dst[di + 2] = alphabet[triplet & 63];
+ triplet >>= 6;
dst[di + 3] = alphabet[triplet];
}
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)) {
+ if(!FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
+ 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';
#ifndef __MESHLINK_XALLOC_H__
#define __MESHLINK_XALLOC_H__
-static inline void *xmalloc(size_t n) __attribute__ ((__malloc__));
+static inline void *xmalloc(size_t n) __attribute__((__malloc__));
static inline void *xmalloc(size_t n) {
void *p = malloc(n);
if(!p)
return p;
}
-static inline void *xzalloc(size_t n) __attribute__ ((__malloc__));
+static inline void *xzalloc(size_t n) __attribute__((__malloc__));
static inline void *xzalloc(size_t n) {
void *p = calloc(1, n);
if(!p)
return p;
}
-static inline char *xstrdup(const char *s) __attribute__ ((__malloc__));
+static inline char *xstrdup(const char *s) __attribute__((__malloc__));
static inline char *xstrdup(const char *s) {
char *p = strdup(s);
if(!p)
return result;
}
-static inline int xasprintf(char **strp, const char *fmt, ...) __attribute__ ((__format__(printf, 2, 3)));
+static inline int xasprintf(char **strp, const char *fmt, ...) __attribute__((__format__(printf, 2, 3)));
static inline int xasprintf(char **strp, const char *fmt, ...) {
va_list ap;
va_start(ap, fmt);
}
// Open a channel from foo to bar.
-
+
meshlink_node_t *bar = meshlink_get_node(mesh1, "bar");
if(!bar) {
fprintf(stderr, "Foo could not find bar\n");
}
void foo_receive_cb(meshlink_handle_t *mesh, meshlink_channel_t *channel, const void *data, size_t len) {
- printf("foo_receive_cb %zu: ", len); fwrite(data, 1, len, stdout); printf("\n");
+ printf("foo_receive_cb %zu: ", len);
+ fwrite(data, 1, len, stdout);
+ printf("\n");
if(len == 5 && !memcmp(data, "Hello", 5))
bar_responded = true;
}
void bar_receive_cb(meshlink_handle_t *mesh, meshlink_channel_t *channel, const void *data, size_t len) {
- printf("bar_receive_cb %zu: ", len); fwrite(data, 1, len, stdout);
+ printf("bar_receive_cb %zu: ", len);
+ fwrite(data, 1, len, stdout);
// Echo the data back.
meshlink_channel_send(mesh, channel, data, len);
}
bool accept_cb(meshlink_handle_t *mesh, meshlink_channel_t *channel, uint16_t port, const void *data, size_t len) {
printf("accept_cb: (from %s on port %u) ", channel->node->name, (unsigned int)port);
- if(data) { fwrite(data, 1, len, stdout); printf("\n"); }
+ if(data) {
+ fwrite(data, 1, len, stdout);
+ printf("\n");
+ }
if(port != 7)
return false;
free(data);
// Set the callbacks.
-
+
meshlink_set_channel_accept_cb(mesh1, reject_cb);
meshlink_set_channel_accept_cb(mesh2, accept_cb);
meshlink_set_node_status_cb(mesh1, status_cb);
-
+
// Start both instances
if(!meshlink_start(mesh1)) {
}
// Open a channel from foo to bar.
-
+
meshlink_node_t *bar = meshlink_get_node(mesh1, "bar");
if(!bar) {
fprintf(stderr, "Foo could not find bar\n");
}
// Open a channel from foo to bar.
-
+
meshlink_node_t *bar = meshlink_get_node(mesh1, "bar");
if(!bar) {
fprintf(stderr, "Foo could not find bar\n");
fprintf(stderr, "Sending message failed\n");
return 1;
}
- if(!sent) {
+ if(!sent)
usleep(100000);
- } else {
+ else {
len -= sent;
p += sent;
}
// Start both instances
meshlink_set_node_status_cb(mesh1, status_cb);
-
+
if(!meshlink_start(mesh1)) {
fprintf(stderr, "Foo could not start\n");
return 1;
// Start the first instance and have it generate an invitation.
meshlink_set_node_status_cb(mesh1, status_cb);
-
+
if(!meshlink_start(mesh1)) {
fprintf(stderr, "Foo could not start\n");
return 1;