// Validate arguments provided by the application
bool usingname = false;
+
+ logger(NULL, MESHLINK_DEBUG, "meshlink_open called\n");
if(!confbase || !*confbase) {
logger(NULL, MESHLINK_ERROR, "No confbase given!\n");
mesh->appname = xstrdup(appname);
mesh->dclass = dclass;
if (usingname) mesh->name = xstrdup(name);
- pthread_mutex_init ( &(mesh->nodes_mutex), NULL);
+
+ // 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;
return NULL;
}
+ logger(NULL, MESHLINK_DEBUG, "meshlink_open returning\n");
return mesh;
}
static void *meshlink_main_loop(void *arg) {
meshlink_handle_t *mesh = arg;
+ pthread_mutex_lock(&(mesh->mesh_mutex));
+
try_outgoing_connections(mesh);
logger(mesh, MESHLINK_DEBUG, "Starting main_loop...\n");
main_loop(mesh);
logger(mesh, MESHLINK_DEBUG, "main_loop returned.\n");
+ pthread_mutex_unlock(&(mesh->mesh_mutex));
return NULL;
}
bool meshlink_start(meshlink_handle_t *mesh) {
-
- logger(mesh, MESHLINK_DEBUG, "meshlink_start called\n");
-
if(!mesh) {
meshlink_errno = MESHLINK_EINVAL;
return false;
}
+ pthread_mutex_lock(&(mesh->mesh_mutex));
+
+ logger(mesh, MESHLINK_DEBUG, "meshlink_start called\n");
// TODO: open listening sockets first
if(!mesh->name ) {
logger(mesh, MESHLINK_DEBUG, "No name given!\n");
meshlink_errno = MESHLINK_EINVAL;
+ pthread_mutex_unlock(&(mesh->mesh_mutex));
return false;
}
logger(mesh, MESHLINK_DEBUG, "Could not start thread: %s\n", strerror(errno));
memset(&mesh->thread, 0, sizeof mesh->thread);
meshlink_errno = MESHLINK_EINTERNAL;
+ pthread_mutex_unlock(&(mesh->mesh_mutex));
return false;
}
discovery_start(mesh);
+ pthread_mutex_unlock(&(mesh->mesh_mutex));
return true;
}
void meshlink_stop(meshlink_handle_t *mesh) {
-
- logger(mesh, MESHLINK_DEBUG, "meshlink_stop called\n");
-
if(!mesh) {
meshlink_errno = MESHLINK_EINVAL;
return;
}
+ pthread_mutex_lock(&(mesh->mesh_mutex));
+ logger(mesh, MESHLINK_DEBUG, "meshlink_stop called\n");
+
// Stop discovery
discovery_stop(mesh);
shutdown(s->tcp.fd, SHUT_RDWR);
// Wait for the main thread to finish
-
+ pthread_mutex_unlock(&(mesh->mesh_mutex));
pthread_join(mesh->thread, NULL);
+ pthread_mutex_lock(&(mesh->mesh_mutex));
+
mesh->threadstarted = false;
// Fix the socket
logger(mesh, MESHLINK_ERROR, "Could not repair listenen socket!");
else
io_add(&mesh->loop, &s->tcp, handle_new_meta_connection, s, s->tcp.fd, IO_READ);
+
+ pthread_mutex_unlock(&(mesh->mesh_mutex));
}
void meshlink_close(meshlink_handle_t *mesh) {
return;
}
+ // lock is not released after this
+ pthread_mutex_lock(&(mesh->mesh_mutex));
+
// Close and free all resources used.
close_network_connections(mesh);
free(mesh->name);
free(mesh->appname);
free(mesh->confbase);
+ pthread_mutex_destroy(&(mesh->mesh_mutex));
memset(mesh, 0, sizeof *mesh);
return;
}
+ pthread_mutex_lock(&(mesh->mesh_mutex));
mesh->receive_cb = cb;
+ pthread_mutex_unlock(&(mesh->mesh_mutex));
}
void meshlink_set_node_status_cb(meshlink_handle_t *mesh, meshlink_node_status_cb_t cb) {
return;
}
+ pthread_mutex_lock(&(mesh->mesh_mutex));
mesh->node_status_cb = cb;
+ pthread_mutex_unlock(&(mesh->mesh_mutex));
}
void meshlink_set_log_cb(meshlink_handle_t *mesh, meshlink_log_level_t level, meshlink_log_cb_t cb) {
if(mesh) {
+ pthread_mutex_lock(&(mesh->mesh_mutex));
mesh->log_cb = cb;
mesh->log_level = cb ? level : 0;
+ pthread_mutex_unlock(&(mesh->mesh_mutex));
} else {
global_log_cb = cb;
global_log_level = cb ? level : 0;
return false;
}
+ pthread_mutex_lock(&(mesh->mesh_mutex));
+
//add packet to the queue
outpacketqueue_t *packet_in_queue = xzalloc(sizeof *packet_in_queue);
packet_in_queue->destination=destination;
packet_in_queue->len=len;
if(!meshlink_queue_push(&mesh->outpacketqueue, packet_in_queue)) {
free(packet_in_queue);
+ pthread_mutex_unlock(&(mesh->mesh_mutex));
return false;
}
//notify event loop
signal_trigger(&(mesh->loop),&(mesh->datafromapp));
+
+ pthread_mutex_unlock(&(mesh->mesh_mutex));
return true;
}
void meshlink_send_from_queue(event_loop_t* el,meshlink_handle_t *mesh) {
+ pthread_mutex_lock(&(mesh->mesh_mutex));
+
vpn_packet_t packet;
meshlink_packethdr_t *hdr = (meshlink_packethdr_t *)packet.data;
outpacketqueue_t* p = meshlink_queue_pop(&mesh->outpacketqueue);
if(!p)
+ pthread_mutex_unlock(&(mesh->mesh_mutex));
return;
if (sizeof(meshlink_packethdr_t) + p->len > MAXSIZE) {
+ pthread_mutex_unlock(&(mesh->mesh_mutex));
//log something
- return ;
+ return;
}
packet.probe = false;
mesh->self->in_packets++;
mesh->self->in_bytes += packet.len;
route(mesh, mesh->self, &packet);
+
+ pthread_mutex_unlock(&(mesh->mesh_mutex));
return ;
}
meshlink_errno = MESHLINK_EINVAL;
return -1;
}
+ pthread_mutex_lock(&(mesh->mesh_mutex));
node_t *n = (node_t *)destination;
- if(!n->status.reachable)
+ 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;
+ }
}
char *meshlink_get_fingerprint(meshlink_handle_t *mesh, meshlink_node_t *node) {
meshlink_errno = MESHLINK_EINVAL;
return NULL;
}
+ pthread_mutex_lock(&(mesh->mesh_mutex));
node_t *n = (node_t *)node;
if(!node_read_ecdsa_public_key(mesh, n) || !n->ecdsa) {
meshlink_errno = MESHLINK_EINTERNAL;
+ pthread_mutex_unlock(&(mesh->mesh_mutex));
return false;
}
if(!fingerprint)
meshlink_errno = MESHLINK_EINTERNAL;
+ pthread_mutex_unlock(&(mesh->mesh_mutex));
return fingerprint;
}
return NULL;
}
- return (meshlink_node_t *)lookup_node(mesh, (char *)name); // TODO: make lookup_node() use const
+ meshlink_node_t *node = NULL;
+
+ pthread_mutex_lock(&(mesh->mesh_mutex));
+ node = (meshlink_node_t *)lookup_node(mesh, (char *)name); // TODO: make lookup_node() use const
+ pthread_mutex_unlock(&(mesh->mesh_mutex));
+ return node;
}
meshlink_node_t **meshlink_get_all_nodes(meshlink_handle_t *mesh, meshlink_node_t **nodes, size_t *nmemb) {
meshlink_node_t **result;
//lock mesh->nodes
- pthread_mutex_lock(&(mesh->nodes_mutex));
+ pthread_mutex_lock(&(mesh->mesh_mutex));
*nmemb = mesh->nodes->count;
result = realloc(nodes, *nmemb * sizeof *nodes);
meshlink_errno = MESHLINK_ENOMEM;
}
- pthread_mutex_unlock(&(mesh->nodes_mutex));
+ pthread_mutex_unlock(&(mesh->mesh_mutex));
return result;
}
return false;
}
+ pthread_mutex_lock(&(mesh->mesh_mutex));
+
if(!ecdsa_sign(mesh->self->connection->ecdsa, data, len, signature)) {
meshlink_errno = MESHLINK_EINTERNAL;
+ pthread_mutex_unlock(&(mesh->mesh_mutex));
return false;
}
*siglen = MESHLINK_SIGLEN;
+ pthread_mutex_unlock(&(mesh->mesh_mutex));
return true;
}
return false;
}
+ pthread_mutex_lock(&(mesh->mesh_mutex));
+
+ bool rval = false;
+
struct node_t *n = (struct node_t *)source;
node_read_ecdsa_public_key(mesh, n);
if(!n->ecdsa) {
meshlink_errno = MESHLINK_EINTERNAL;
- return false;
+ rval = false;
+ } else {
+ rval = ecdsa_verify(((struct node_t *)source)->ecdsa, data, len, signature);
}
-
- return 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);
if(mkdir(filename, 0700) && errno != EEXIST) {
logger(mesh, MESHLINK_DEBUG, "Could not create directory %s: %s\n", filename, strerror(errno));
meshlink_errno = MESHLINK_ESTORAGE;
+ pthread_mutex_unlock(&(mesh->mesh_mutex));
return false;
}
if(!dir) {
logger(mesh, MESHLINK_DEBUG, "Could not read directory %s: %s\n", filename, strerror(errno));
meshlink_errno = MESHLINK_ESTORAGE;
+ pthread_mutex_unlock(&(mesh->mesh_mutex));
return false;
}
logger(mesh, MESHLINK_DEBUG, "Error while reading directory %s: %s\n", filename, strerror(errno));
closedir(dir);
meshlink_errno = MESHLINK_ESTORAGE;
+ pthread_mutex_unlock(&(mesh->mesh_mutex));
return false;
}
}
}
- if(mesh->invitation_key)
+ if(mesh->invitation_key) {
+ pthread_mutex_unlock(&(mesh->mesh_mutex));
return true;
+ }
// Create a new key if necessary.
FILE *f = fopen(filename, "r");
if(errno != ENOENT) {
logger(mesh, MESHLINK_DEBUG, "Could not read %s: %s\n", filename, strerror(errno));
meshlink_errno = MESHLINK_ESTORAGE;
+ pthread_mutex_unlock(&(mesh->mesh_mutex));
return false;
}
if(!mesh->invitation_key) {
logger(mesh, MESHLINK_DEBUG, "Could not generate a new key!\n");
meshlink_errno = MESHLINK_EINTERNAL;
+ pthread_mutex_unlock(&(mesh->mesh_mutex));
return false;
}
f = fopen(filename, "w");
if(!f) {
logger(mesh, MESHLINK_DEBUG, "Could not write %s: %s\n", filename, strerror(errno));
meshlink_errno = MESHLINK_ESTORAGE;
+ pthread_mutex_unlock(&(mesh->mesh_mutex));
return false;
}
chmod(filename, 0600);
}
}
+ pthread_mutex_unlock(&(mesh->mesh_mutex));
return mesh->invitation_key;
}
meshlink_errno = MESHLINK_EINVAL;
return false;
}
+
+ bool rval = false;
+
+ pthread_mutex_lock(&(mesh->mesh_mutex));
for(const char *p = address; *p; p++) {
if(isalnum(*p) || *p == '-' || *p == '.' || *p == ':')
continue;
logger(mesh, MESHLINK_DEBUG, "Invalid character in address: %s\n", address);
meshlink_errno = MESHLINK_EINVAL;
+ pthread_mutex_unlock(&(mesh->mesh_mutex));
return false;
}
- return append_config_file(mesh, mesh->self->name, "Address", address);
+ rval = append_config_file(mesh, mesh->self->name, "Address", address);
+ pthread_mutex_unlock(&(mesh->mesh_mutex));
+ return rval;
}
char *meshlink_invite(meshlink_handle_t *mesh, const char *name) {
meshlink_errno = MESHLINK_EINVAL;
return NULL;
}
+
+ pthread_mutex_lock(&(mesh->mesh_mutex));
// Check validity of the new node's name
if(!check_id(name)) {
logger(mesh, MESHLINK_DEBUG, "Invalid name for node.\n");
meshlink_errno = MESHLINK_EINVAL;
+ pthread_mutex_unlock(&(mesh->mesh_mutex));
return NULL;
}
if(!access(filename, F_OK)) {
logger(mesh, MESHLINK_DEBUG, "A host config file for %s already exists!\n", name);
meshlink_errno = MESHLINK_EEXIST;
+ pthread_mutex_unlock(&(mesh->mesh_mutex));
return NULL;
}
if(meshlink_get_node(mesh, name)) {
logger(mesh, MESHLINK_DEBUG, "A node with name %s is already known!\n", name);
meshlink_errno = MESHLINK_EEXIST;
+ pthread_mutex_unlock(&(mesh->mesh_mutex));
return NULL;
}
if(!address) {
logger(mesh, MESHLINK_DEBUG, "No Address known for ourselves!\n");
meshlink_errno = MESHLINK_ERESOLV;
+ pthread_mutex_unlock(&(mesh->mesh_mutex));
return NULL;
}
if(!refresh_invitation_key(mesh)) {
meshlink_errno = MESHLINK_EINTERNAL;
+ pthread_mutex_unlock(&(mesh->mesh_mutex));
return NULL;
}
if(!ifd) {
logger(mesh, MESHLINK_DEBUG, "Could not create invitation file %s: %s\n", filename, strerror(errno));
meshlink_errno = MESHLINK_ESTORAGE;
+ pthread_mutex_unlock(&(mesh->mesh_mutex));
return NULL;
}
FILE *f = fdopen(ifd, "w");
} else {
logger(mesh, MESHLINK_DEBUG, "Could not create %s: %s\n", filename, strerror(errno));
meshlink_errno = MESHLINK_ESTORAGE;
+ pthread_mutex_unlock(&(mesh->mesh_mutex));
return NULL;
}
xasprintf(&url, "%s/%s%s", address, hash, cookie);
free(address);
+ pthread_mutex_unlock(&(mesh->mesh_mutex));
return url;
}
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 copy[strlen(invitation) + 1];
ecdsa_t *key = ecdsa_generate();
if(!key) {
meshlink_errno = MESHLINK_EINTERNAL;
+ pthread_mutex_unlock(&(mesh->mesh_mutex));
return false;
}
struct addrinfo *ai = str2addrinfo(address, port, SOCK_STREAM);
if(!ai) {
meshlink_errno = MESHLINK_ERESOLV;
+ pthread_mutex_unlock(&(mesh->mesh_mutex));
return false;
}
logger(mesh, MESHLINK_DEBUG, "Could not open socket: %s\n", strerror(errno));
freeaddrinfo(ai);
meshlink_errno = MESHLINK_ENETWORK;
+ pthread_mutex_unlock(&(mesh->mesh_mutex));
return false;
}
closesocket(mesh->sock);
freeaddrinfo(ai);
meshlink_errno = MESHLINK_ENETWORK;
+ pthread_mutex_unlock(&(mesh->mesh_mutex));
return false;
}
logger(mesh, MESHLINK_DEBUG, "Error sending request to %s port %s: %s\n", address, port, strerror(errno));
closesocket(mesh->sock);
meshlink_errno = MESHLINK_ENETWORK;
+ pthread_mutex_unlock(&(mesh->mesh_mutex));
return false;
}
logger(mesh, MESHLINK_DEBUG, "Cannot read greeting from peer\n");
closesocket(mesh->sock);
meshlink_errno = MESHLINK_ENETWORK;
+ pthread_mutex_unlock(&(mesh->mesh_mutex));
return false;
}
if(sha512(fingerprint, strlen(fingerprint), hishash)) {
logger(mesh, MESHLINK_DEBUG, "Could not create hash\n%s\n", mesh->line + 2);
meshlink_errno = MESHLINK_EINTERNAL;
+ pthread_mutex_unlock(&(mesh->mesh_mutex));
return false;
}
if(memcmp(hishash, mesh->hash, 18)) {
logger(mesh, MESHLINK_DEBUG, "Peer has an invalid key!\n%s\n", mesh->line + 2);
meshlink_errno = MESHLINK_EPEER;
+ pthread_mutex_unlock(&(mesh->mesh_mutex));
return false;
}
ecdsa_t *hiskey = ecdsa_set_base64_public_key(fingerprint);
if(!hiskey) {
meshlink_errno = MESHLINK_EINTERNAL;
+ pthread_mutex_unlock(&(mesh->mesh_mutex));
return false;
}
// Start an SPTPS session
if(!sptps_start(&mesh->sptps, mesh, true, false, key, hiskey, "meshlink invitation", 15, invitation_send, invitation_receive)) {
meshlink_errno = MESHLINK_EINTERNAL;
+ pthread_mutex_unlock(&(mesh->mesh_mutex));
return false;
}
// Feed rest of input buffer to SPTPS
if(!sptps_receive_data(&mesh->sptps, mesh->buffer, mesh->blen)) {
meshlink_errno = MESHLINK_EPEER;
+ pthread_mutex_unlock(&(mesh->mesh_mutex));
return false;
}
continue;
logger(mesh, MESHLINK_DEBUG, "Error reading data from %s port %s: %s\n", address, port, strerror(errno));
meshlink_errno = MESHLINK_ENETWORK;
+ pthread_mutex_unlock(&(mesh->mesh_mutex));
return false;
}
if(!sptps_receive_data(&mesh->sptps, mesh->line, len)) {
meshlink_errno = MESHLINK_EPEER;
+ pthread_mutex_unlock(&(mesh->mesh_mutex));
return false;
}
}
if(!mesh->success) {
logger(mesh, MESHLINK_DEBUG, "Connection closed by peer, invitation cancelled.\n");
meshlink_errno = MESHLINK_EPEER;
+ pthread_mutex_unlock(&(mesh->mesh_mutex));
return false;
}
+ pthread_mutex_unlock(&(mesh->mesh_mutex));
return true;
invalid:
logger(mesh, MESHLINK_DEBUG, "Invalid invitation URL or you are already connected to a Mesh ?\n");
meshlink_errno = MESHLINK_EINVAL;
+ pthread_mutex_unlock(&(mesh->mesh_mutex));
return false;
}
return NULL;
}
+ 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");
if(!f) {
logger(mesh, MESHLINK_DEBUG, "Could not open %s: %s\n", filename, strerror(errno));
meshlink_errno = MESHLINK_ESTORAGE;
+ pthread_mutex_unlock(&(mesh->mesh_mutex));
return NULL;
}
logger(mesh, MESHLINK_DEBUG, "Error reading from %s: %s\n", filename, strerror(errno));
fclose(f);
meshlink_errno = MESHLINK_ESTORAGE;
+ pthread_mutex_unlock(&(mesh->mesh_mutex));
return NULL;
}
fclose(f);
buf[len - 1] = 0;
+
+ pthread_mutex_lock(&(mesh->mesh_mutex));
return buf;
}
meshlink_errno = MESHLINK_EINVAL;
return false;
}
+
+ pthread_mutex_lock(&(mesh->mesh_mutex));
if(strncmp(data, "Name = ", 7)) {
logger(mesh, MESHLINK_DEBUG, "Invalid data\n");
meshlink_errno = MESHLINK_EPEER;
+ pthread_mutex_unlock(&(mesh->mesh_mutex));
return false;
}
if(!end) {
logger(mesh, MESHLINK_DEBUG, "Invalid data\n");
meshlink_errno = MESHLINK_EPEER;
+ pthread_mutex_unlock(&(mesh->mesh_mutex));
return false;
}
if(!check_id(name)) {
logger(mesh, MESHLINK_DEBUG, "Invalid Name\n");
meshlink_errno = MESHLINK_EPEER;
+ pthread_mutex_unlock(&(mesh->mesh_mutex));
return false;
}
if(!access(filename, F_OK)) {
logger(mesh, MESHLINK_DEBUG, "File %s already exists, not importing\n", filename);
meshlink_errno = MESHLINK_EEXIST;
+ pthread_mutex_unlock(&(mesh->mesh_mutex));
return false;
}
if(errno != ENOENT) {
logger(mesh, MESHLINK_DEBUG, "Error accessing %s: %s\n", filename, strerror(errno));
meshlink_errno = MESHLINK_ESTORAGE;
+ pthread_mutex_unlock(&(mesh->mesh_mutex));
return false;
}
if(!f) {
logger(mesh, MESHLINK_DEBUG, "Could not create %s: %s\n", filename, strerror(errno));
meshlink_errno = MESHLINK_ESTORAGE;
+ pthread_mutex_unlock(&(mesh->mesh_mutex));
return false;
}
load_all_nodes(mesh);
+ pthread_mutex_unlock(&(mesh->mesh_mutex));
return true;
}
return;
}
+ pthread_mutex_lock(&(mesh->mesh_mutex));
+
node_t *n;
n = (node_t*)node;
n->status.blacklisted=true;
//Make blacklisting persistent in the config file
append_config_file(mesh, n->name, "blacklisted", "yes");
+ pthread_mutex_unlock(&(mesh->mesh_mutex));
return;
}
return;
}
+ pthread_mutex_lock(&(mesh->mesh_mutex));
+
node_t *n = (node_t *)node;
n->status.blacklisted = false;
//TODO: remove blacklisted = yes from the config file
+ pthread_mutex_unlock(&(mesh->mesh_mutex));
return;
}
if(!mesh || !node || !addr)
return;
+ pthread_mutex_lock(&(mesh->mesh_mutex));
+
char *host = NULL, *port = NULL, *str = NULL;
sockaddr2str((const sockaddr_t *)addr, &host, &port);
free(host);
free(port);
+ pthread_mutex_unlock(&(mesh->mesh_mutex));
// @TODO do we want to fire off a connection attempt right away?
}