+ assert(mesh);
+
+ if(pthread_mutex_lock(&mesh->discovery_mutex) != 0) {
+ abort();
+ }
+
+ // handle catta logs
+ catta_set_log_function(discovery_log_cb);
+
+ // create service type string
+ char appname[strlen(mesh->appname) + 2];
+ strcpy(appname, mesh->appname);
+
+ for(char *p = appname; *p; p++) {
+ if(!isalnum(*p) && *p != '_' && *p != '-') {
+ *p = '_';
+ }
+ }
+
+ if(!appname[1]) {
+ appname[1] = '_';
+ appname[2] = '\0';
+ }
+
+ size_t servicetype_strlen = sizeof(MESHLINK_MDNS_SERVICE_TYPE) + strlen(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, 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(mesh, 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;
+ config.allow_point_to_point = 1;
+
+ /* Allocate a new server */
+ int error;
+ const CattaPoll *poller = catta_simple_poll_get(mesh->catta_poll);
+
+ if(!poller) {
+ logger(mesh, MESHLINK_ERROR, "Failed to create discovery server: %s\n", catta_strerror(error));
+ goto fail;
+ }
+
+ mesh->catta_server = catta_server_new(poller, &config, discovery_server_callback, mesh, &error);
+
+ /* Free the configuration data */
+ catta_server_config_free(&config);
+
+ /* Check whether 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;
+ }
+
+ status = true;
+
+fail:
+
+ pthread_cond_broadcast(&mesh->discovery_cond);
+ pthread_mutex_unlock(&mesh->discovery_mutex);
+
+ if(status) {
+ catta_simple_poll_loop(mesh->catta_poll);
+ }
+
+ if(mesh->catta_browser) {
+ 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) {
+ catta_server_free(mesh->catta_server);
+ mesh->catta_server = NULL;
+ }
+
+ if(mesh->catta_poll) {
+ catta_simple_poll_free(mesh->catta_poll);
+ mesh->catta_poll = NULL;
+ }
+
+ if(mesh->catta_servicetype) {
+ free(mesh->catta_servicetype);
+ mesh->catta_servicetype = NULL;
+ }
+
+ return NULL;
+}
+
+#if defined(__linux)
+static void netlink_getlink(int fd) {
+ static const struct {
+ struct nlmsghdr nlm;
+ struct ifinfomsg ifi;
+ } msg = {
+ .nlm.nlmsg_len = NLMSG_LENGTH(sizeof(msg.ifi)),
+ .nlm.nlmsg_type = RTM_GETLINK,
+ .nlm.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST,
+ .nlm.nlmsg_seq = 1,
+ .ifi.ifi_family = AF_UNSPEC,
+ };
+ send(fd, &msg, msg.nlm.nlmsg_len, 0);
+}
+
+static void netlink_getaddr(int fd) {
+ static const struct {
+ struct nlmsghdr nlm;
+ struct ifaddrmsg ifa;
+ } msg = {
+ .nlm.nlmsg_len = NLMSG_LENGTH(sizeof(msg.ifa)),
+ .nlm.nlmsg_type = RTM_GETADDR,
+ .nlm.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST,
+ .nlm.nlmsg_seq = 2,
+ .ifa.ifa_family = AF_UNSPEC,
+ };
+ send(fd, &msg, msg.nlm.nlmsg_len, 0);
+}