char *name = packmsg_get_str_dup(&in);
packmsg_skip_element(&in); /* submesh */
- int32_t devclass = packmsg_get_int32(&in);
+ dev_class_t devclass = packmsg_get_int32(&in);
uint32_t count = packmsg_get_array(&in);
if(!name) {
}
}
+ /* Ensure the configuration directory metadata is on disk */
+ if(!config_sync(mesh, "current")) {
+ return false;
+ }
+
sptps_send_record(&(mesh->sptps), 1, ecdsa_get_public_key(mesh->private_key), 32);
logger(mesh, MESHLINK_DEBUG, "Configuration stored in: %s\n", mesh->confbase);
return false;
}
+ /* Ensure the configuration directory metadata is on disk */
+ if(!config_sync(mesh, "current")) {
+ return false;
+ }
+
if(!main_config_lock(mesh)) {
logger(NULL, MESHLINK_ERROR, "Cannot lock main config file\n");
meshlink_errno = MESHLINK_ESTORAGE;
}
}
- if((int)devclass < 0 || devclass > _DEV_CLASS_MAX) {
+ if(devclass < 0 || devclass >= DEV_CLASS_COUNT) {
logger(NULL, MESHLINK_ERROR, "Invalid devclass given!\n");
meshlink_errno = MESHLINK_EINVAL;
return NULL;
free(params);
}
+/// Device class traits
+static const dev_class_traits_t default_class_traits[DEV_CLASS_COUNT] = {
+ { .pingtimeout = 5, .pinginterval = 60, .min_connects = 3, .max_connects = 10000, .edge_weight = 1 }, // DEV_CLASS_BACKBONE
+ { .pingtimeout = 5, .pinginterval = 60, .min_connects = 3, .max_connects = 100, .edge_weight = 3 }, // DEV_CLASS_STATIONARY
+ { .pingtimeout = 5, .pinginterval = 60, .min_connects = 3, .max_connects = 3, .edge_weight = 6 }, // DEV_CLASS_PORTABLE
+ { .pingtimeout = 5, .pinginterval = 60, .min_connects = 1, .max_connects = 1, .edge_weight = 9 }, // DEV_CLASS_UNKNOWN
+};
+
meshlink_handle_t *meshlink_open(const char *confbase, const char *name, const char *appname, dev_class_t devclass) {
if(!confbase || !*confbase) {
logger(NULL, MESHLINK_ERROR, "No confbase given!\n");
}
}
- if((int)params->devclass < 0 || params->devclass > _DEV_CLASS_MAX) {
+ if(params->devclass < 0 || params->devclass >= DEV_CLASS_COUNT) {
logger(NULL, MESHLINK_ERROR, "Invalid devclass given!\n");
meshlink_errno = MESHLINK_EINVAL;
return NULL;
mesh->invitation_timeout = 604800; // 1 week
mesh->netns = params->netns;
mesh->submeshes = NULL;
+ mesh->log_cb = global_log_cb;
+ mesh->log_level = global_log_level;
+
+ memcpy(mesh->dev_class_traits, default_class_traits, sizeof(default_class_traits));
if(usingname) {
mesh->name = xstrdup(params->name);
}
meshlink_node_t **meshlink_get_all_nodes_by_dev_class(meshlink_handle_t *mesh, dev_class_t devclass, meshlink_node_t **nodes, size_t *nmemb) {
- if(!mesh || ((int)devclass < 0) || (devclass > _DEV_CLASS_MAX) || !nmemb) {
+ if(!mesh || devclass < 0 || devclass >= DEV_CLASS_COUNT || !nmemb) {
meshlink_errno = MESHLINK_EINVAL;
return NULL;
}
return false;
}
+ if(!config_sync(mesh, "current")) {
+ return false;
+ }
+
return true;
}
n->status.blacklisted = true;
node_write_config(mesh, n);
+ config_sync(mesh, "current");
+
logger(mesh, MESHLINK_DEBUG, "Blacklisted %s.\n", node->name);
//Immediately terminate any connections we have with the blacklisted node
n->status.blacklisted = false;
node_write_config(mesh, n);
+ config_sync(mesh, "current");
pthread_mutex_unlock(&(mesh->mesh_mutex));
return;
return mesh->channel_accept_cb;
}
+static void aio_signal(meshlink_handle_t *mesh, meshlink_channel_t *channel, meshlink_aio_buffer_t *aio) {
+ if(aio->data) {
+ if(aio->cb.buffer) {
+ aio->cb.buffer(mesh, channel, aio->data, aio->len, aio->priv);
+ }
+ } else {
+ if(aio->cb.fd) {
+ aio->cb.fd(mesh, channel, aio->fd, aio->done, aio->priv);
+ }
+ }
+}
+
static ssize_t channel_recv(struct utcp_connection *connection, const void *data, size_t len) {
meshlink_channel_t *channel = connection->priv;
todo = left;
}
- memcpy((char *)aio->data + aio->done, p, todo);
+ if(aio->data) {
+ memcpy((char *)aio->data + aio->done, p, todo);
+ } else {
+ ssize_t result = write(aio->fd, p, todo);
+
+ if(result > 0) {
+ todo = result;
+ }
+ }
+
aio->done += todo;
if(aio->done == aio->len) {
channel->aio_receive = aio->next;
-
- if(aio->cb) {
- aio->cb(mesh, channel, aio->data, aio->len, aio->priv);
- }
-
+ aio_signal(mesh, channel, aio);
free(aio);
}
if(aio) {
/* We at least one AIO buffer. Send as much as possible form the first buffer. */
size_t left = aio->len - aio->done;
+ ssize_t sent;
if(len > left) {
len = left;
}
- ssize_t sent = utcp_send(connection, (char *)aio->data + aio->done, len);
+ if(aio->data) {
+ sent = utcp_send(connection, (char *)aio->data + aio->done, len);
+ } else {
+ char buf[65536];
+ size_t todo = utcp_get_sndbuf_free(connection);
+
+ if(todo > left) {
+ todo = left;
+ }
+
+ if(todo > sizeof(buf)) {
+ todo = sizeof(buf);
+ }
+
+ ssize_t result = read(aio->fd, buf, todo);
+
+ if(result > 0) {
+ sent = utcp_send(connection, buf, result);
+ } else {
+ sent = result;
+ }
+ }
if(sent >= 0) {
aio->done += sent;
/* If the buffer is now completely sent, call the callback and dispose of it. */
if(aio->done >= aio->len) {
channel->aio_send = aio->next;
-
- if(aio->cb) {
- aio->cb(mesh, channel, aio->data, aio->len, aio->priv);
- }
-
+ aio_signal(mesh, channel, aio);
free(aio);
}
} else {
/* Clean up any outstanding AIO buffers. */
for(meshlink_aio_buffer_t *aio = channel->aio_send, *next; aio; aio = next) {
next = aio->next;
-
- if(aio->cb) {
- aio->cb(mesh, channel, aio->data, aio->len, aio->priv);
- }
-
+ aio_signal(mesh, channel, aio);
free(aio);
}
for(meshlink_aio_buffer_t *aio = channel->aio_receive, *next; aio; aio = next) {
next = aio->next;
-
- if(aio->cb) {
- aio->cb(mesh, channel, aio->data, aio->len, aio->priv);
- }
-
+ aio_signal(mesh, channel, aio);
free(aio);
}
meshlink_aio_buffer_t *aio = xzalloc(sizeof(*aio));
aio->data = data;
aio->len = len;
- aio->cb = cb;
+ aio->cb.buffer = cb;
+ aio->priv = priv;
+
+ pthread_mutex_lock(&mesh->mesh_mutex);
+
+ /* Append the AIO buffer descriptor to the end of the chain */
+ meshlink_aio_buffer_t **p = &channel->aio_send;
+
+ while(*p) {
+ p = &(*p)->next;
+ }
+
+ *p = aio;
+
+ /* Ensure the poll callback is set, and call it right now to push data if possible */
+ utcp_set_poll_cb(channel->c, channel_poll);
+ channel_poll(channel->c, len);
+
+ pthread_mutex_unlock(&mesh->mesh_mutex);
+
+ return true;
+}
+
+bool meshlink_channel_aio_fd_send(meshlink_handle_t *mesh, meshlink_channel_t *channel, int fd, size_t len, meshlink_aio_fd_cb_t cb, void *priv) {
+ if(!mesh || !channel) {
+ meshlink_errno = MESHLINK_EINVAL;
+ return false;
+ }
+
+ if(!len || fd == -1) {
+ meshlink_errno = MESHLINK_EINVAL;
+ return false;
+ }
+
+ meshlink_aio_buffer_t *aio = xzalloc(sizeof(*aio));
+ aio->fd = fd;
+ aio->len = len;
+ aio->cb.fd = cb;
aio->priv = priv;
pthread_mutex_lock(&mesh->mesh_mutex);
meshlink_aio_buffer_t *aio = xzalloc(sizeof(*aio));
aio->data = data;
aio->len = len;
- aio->cb = cb;
+ aio->cb.buffer = cb;
+ aio->priv = priv;
+
+ pthread_mutex_lock(&mesh->mesh_mutex);
+
+ /* Append the AIO buffer descriptor to the end of the chain */
+ meshlink_aio_buffer_t **p = &channel->aio_receive;
+
+ while(*p) {
+ p = &(*p)->next;
+ }
+
+ *p = aio;
+
+ pthread_mutex_unlock(&mesh->mesh_mutex);
+
+ return true;
+}
+
+bool meshlink_channel_aio_fd_receive(meshlink_handle_t *mesh, meshlink_channel_t *channel, int fd, size_t len, meshlink_aio_fd_cb_t cb, void *priv) {
+ if(!mesh || !channel) {
+ meshlink_errno = MESHLINK_EINVAL;
+ return false;
+ }
+
+ if(!len || fd == -1) {
+ meshlink_errno = MESHLINK_EINVAL;
+ return false;
+ }
+
+ meshlink_aio_buffer_t *aio = xzalloc(sizeof(*aio));
+ aio->fd = fd;
+ aio->len = len;
+ aio->cb.fd = cb;
aio->priv = priv;
pthread_mutex_lock(&mesh->mesh_mutex);
#endif
}
+void meshlink_set_dev_class_timeouts(meshlink_handle_t *mesh, dev_class_t devclass, int pinginterval, int pingtimeout) {
+ if(!mesh || devclass < 0 || devclass >= DEV_CLASS_COUNT) {
+ meshlink_errno = EINVAL;
+ return;
+ }
+
+ if(pinginterval < 1 || pingtimeout < 1 || pingtimeout > pinginterval) {
+ meshlink_errno = EINVAL;
+ return;
+ }
+
+ pthread_mutex_lock(&mesh->mesh_mutex);
+ mesh->dev_class_traits[devclass].pinginterval = pinginterval;
+ mesh->dev_class_traits[devclass].pingtimeout = pingtimeout;
+ pthread_mutex_unlock(&mesh->mesh_mutex);
+}
+
void handle_network_change(meshlink_handle_t *mesh, bool online) {
(void)online;
static void __attribute__((destructor)) meshlink_exit(void) {
crypto_exit();
}
-
-/// Device class traits
-const 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
-};