+static bool ecdsa_keygen(meshlink_handle_t *mesh) {
+ logger(mesh, MESHLINK_DEBUG, "Generating ECDSA keypairs:\n");
+
+ mesh->private_key = ecdsa_generate();
+ mesh->invitation_key = ecdsa_generate();
+
+ if(!mesh->private_key || !mesh->invitation_key) {
+ logger(mesh, MESHLINK_DEBUG, "Error during key generation!\n");
+ meshlink_errno = MESHLINK_EINTERNAL;
+ return false;
+ }
+
+ logger(mesh, MESHLINK_DEBUG, "Done.\n");
+
+ return true;
+}
+
+static struct timeval idle(event_loop_t *loop, void *data) {
+ (void)loop;
+ meshlink_handle_t *mesh = data;
+ struct timeval t, tmin = {3600, 0};
+
+ for splay_each(node_t, n, mesh->nodes) {
+ if(!n->utcp) {
+ continue;
+ }
+
+ t = utcp_timeout(n->utcp);
+
+ if(timercmp(&t, &tmin, <)) {
+ tmin = t;
+ }
+ }
+
+ return tmin;
+}
+
+// Get our local address(es) by simulating connecting to an Internet host.
+static void add_local_addresses(meshlink_handle_t *mesh) {
+ struct sockaddr_storage sn;
+ socklen_t sl = sizeof(sn);
+
+ // IPv4 example.org
+
+ if(getlocaladdr("93.184.216.34", (struct sockaddr *)&sn, &sl, mesh->netns)) {
+ ((struct sockaddr_in *)&sn)->sin_port = ntohs(atoi(mesh->myport));
+ meshlink_hint_address(mesh, (meshlink_node_t *)mesh->self, (struct sockaddr *)&sn);
+ }
+
+ // IPv6 example.org
+
+ sl = sizeof(sn);
+
+ if(getlocaladdr("2606:2800:220:1:248:1893:25c8:1946", (struct sockaddr *)&sn, &sl, mesh->netns)) {
+ ((struct sockaddr_in6 *)&sn)->sin6_port = ntohs(atoi(mesh->myport));
+ meshlink_hint_address(mesh, (meshlink_node_t *)mesh->self, (struct sockaddr *)&sn);
+ }
+}
+
+static bool meshlink_setup(meshlink_handle_t *mesh) {
+ if(!config_init(mesh, "current")) {
+ logger(mesh, MESHLINK_ERROR, "Could not set up configuration in %s/current: %s\n", mesh->confbase, strerror(errno));
+ meshlink_errno = MESHLINK_ESTORAGE;
+ return false;
+ }
+
+ if(!ecdsa_keygen(mesh)) {
+ meshlink_errno = MESHLINK_EINTERNAL;
+ return false;
+ }
+
+ if(check_port(mesh) == 0) {
+ meshlink_errno = MESHLINK_ENETWORK;
+ return false;
+ }
+
+ /* Create a node for ourself */
+
+ mesh->self = new_node();
+ mesh->self->name = xstrdup(mesh->name);
+ mesh->self->devclass = mesh->devclass;
+ mesh->self->ecdsa = ecdsa_set_public_key(ecdsa_get_public_key(mesh->private_key));
+
+ if(!write_main_config_files(mesh)) {
+ logger(mesh, MESHLINK_ERROR, "Could not write main config files into %s/current: %s\n", mesh->confbase, strerror(errno));
+ meshlink_errno = MESHLINK_ESTORAGE;
+ return false;
+ }
+
+ if(!main_config_lock(mesh)) {
+ logger(NULL, MESHLINK_ERROR, "Cannot lock main config file\n");
+ meshlink_errno = MESHLINK_ESTORAGE;
+ return false;
+ }
+
+ return true;
+}
+
+static bool meshlink_read_config(meshlink_handle_t *mesh) {
+ // Open the configuration file and lock it
+ if(!main_config_lock(mesh)) {
+ logger(NULL, MESHLINK_ERROR, "Cannot lock main config file\n");
+ meshlink_errno = MESHLINK_ESTORAGE;
+ return false;
+ }
+
+ config_t config;
+
+ if(!main_config_read(mesh, "current", &config, mesh->config_key)) {
+ logger(NULL, MESHLINK_ERROR, "Could not read main configuration file!");
+ return false;
+ }
+
+ packmsg_input_t in = {config.buf, config.len};
+ const void *private_key;
+ const void *invitation_key;
+
+ uint32_t version = packmsg_get_uint32(&in);
+ char *name = packmsg_get_str_dup(&in);
+ uint32_t private_key_len = packmsg_get_bin_raw(&in, &private_key);
+ uint32_t invitation_key_len = packmsg_get_bin_raw(&in, &invitation_key);
+ uint16_t myport = packmsg_get_uint16(&in);
+
+ if(!packmsg_done(&in) || version != MESHLINK_CONFIG_VERSION || private_key_len != 96 || invitation_key_len != 96) {
+ logger(NULL, MESHLINK_ERROR, "Error parsing main configuration file!");
+ free(name);
+ config_free(&config);
+ return false;
+ }
+
+#if 0
+
+ // TODO: check this?
+ if(mesh->name && strcmp(mesh->name, name)) {
+ logger(NULL, MESHLINK_ERROR, "Configuration is for a different name (%s)!", name);
+ meshlink_errno = MESHLINK_ESTORAGE;
+ free(name);
+ config_free(&config);
+ return false;
+ }
+
+#endif
+
+ free(mesh->name);
+ mesh->name = name;
+ xasprintf(&mesh->myport, "%u", myport);
+ mesh->private_key = ecdsa_set_private_key(private_key);
+ mesh->invitation_key = ecdsa_set_private_key(invitation_key);
+ config_free(&config);
+
+ /* Create a node for ourself and read our host configuration file */
+
+ mesh->self = new_node();
+ mesh->self->name = xstrdup(name);
+ mesh->self->devclass = mesh->devclass;
+
+ if(!node_read_public_key(mesh, mesh->self)) {
+ logger(NULL, MESHLINK_ERROR, "Could not read our host configuration file!");
+ meshlink_errno = MESHLINK_ESTORAGE;
+ free_node(mesh->self);
+ mesh->self = NULL;
+ return false;
+ }
+
+ return true;
+}
+
+#ifdef HAVE_SETNS
+static void *setup_network_in_netns_thread(void *arg) {
+ meshlink_handle_t *mesh = arg;
+
+ if(setns(mesh->netns, CLONE_NEWNET) != 0) {
+ return NULL;
+ }
+
+ bool success = setup_network(mesh);
+ add_local_addresses(mesh);
+ return success ? arg : NULL;
+}
+#endif // HAVE_SETNS
+
+meshlink_open_params_t *meshlink_open_params_init(const char *confbase, const char *name, const char *appname, dev_class_t devclass) {
+ if(!confbase || !*confbase) {
+ logger(NULL, MESHLINK_ERROR, "No confbase given!\n");
+ meshlink_errno = MESHLINK_EINVAL;
+ return NULL;
+ }
+
+ if(!appname || !*appname) {
+ logger(NULL, MESHLINK_ERROR, "No appname given!\n");
+ meshlink_errno = MESHLINK_EINVAL;
+ return NULL;
+ }
+
+ if(strchr(appname, ' ')) {
+ logger(NULL, MESHLINK_ERROR, "Invalid appname given!\n");
+ meshlink_errno = MESHLINK_EINVAL;
+ return NULL;
+ }
+
+ if(!name || !*name) {
+ logger(NULL, MESHLINK_ERROR, "No name given!\n");
+ //return 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;
+ }
+ }
+
+ if((int)devclass < 0 || devclass > _DEV_CLASS_MAX) {
+ logger(NULL, MESHLINK_ERROR, "Invalid devclass given!\n");
+ meshlink_errno = MESHLINK_EINVAL;
+ return NULL;
+ }
+
+ meshlink_open_params_t *params = xzalloc(sizeof * params);
+
+ params->confbase = xstrdup(confbase);
+ params->name = xstrdup(name);
+ params->appname = xstrdup(appname);
+ params->devclass = devclass;
+ params->netns = -1;
+
+ return params;
+}
+
+bool meshlink_open_params_set_netns(meshlink_open_params_t *params, int netns) {
+ if(!params) {
+ meshlink_errno = MESHLINK_EINVAL;
+ return false;
+ }
+
+ params->netns = netns;
+
+ return true;
+}