void CZeroconfAvahi::addService(tServiceMap::mapped_type fp_service_info, AvahiClient* fp_client) { assert(fp_client); CLog::Log(LOGDEBUG, "CZeroconfAvahi::addService() named: %s type: %s port:%i", fp_service_info->m_name.c_str(), fp_service_info->m_type.c_str(), fp_service_info->m_port); //create the group if it doesn't exist if (!fp_service_info->mp_group) { if (!(fp_service_info->mp_group = avahi_entry_group_new(fp_client, &CZeroconfAvahi::groupCallback, this))) { CLog::Log(LOGDEBUG, "CZeroconfAvahi::addService() avahi_entry_group_new() failed: %s", avahi_strerror(avahi_client_errno(fp_client))); fp_service_info->mp_group = 0; return; } } // add entries to the group if it's empty int ret; if (avahi_entry_group_is_empty(fp_service_info->mp_group)) { if ((ret = avahi_entry_group_add_service_strlst(fp_service_info->mp_group, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, AvahiPublishFlags(0), fp_service_info->m_name.c_str(), fp_service_info->m_type.c_str(), NULL, NULL, fp_service_info->m_port, fp_service_info->mp_txt) < 0)) { if (ret == AVAHI_ERR_COLLISION) { char* alt_name = avahi_alternative_service_name(fp_service_info->m_name.c_str()); fp_service_info->m_name = alt_name; avahi_free(alt_name); CLog::Log(LOGNOTICE, "CZeroconfAvahi::addService: Service name collision. Renamed to: %s", fp_service_info->m_name.c_str()); addService(fp_service_info, fp_client); return; } CLog::Log(LOGERROR, "CZeroconfAvahi::addService(): failed to add service named:%s@$(HOSTNAME) type:%s port:%i. Error:%s :/ FIXME!", fp_service_info->m_name.c_str(), fp_service_info->m_type.c_str(), fp_service_info->m_port, avahi_strerror(ret)); return; } } // Tell the server to register the service if ((ret = avahi_entry_group_commit(fp_service_info->mp_group)) < 0) { CLog::Log(LOGERROR, "CZeroconfAvahi::addService(): Failed to commit entry group! Error:%s", avahi_strerror(ret)); // TODO what now? reset the group? free it? } }
void ControllerDiscoveryMDNS::create_service( AvahiServer * server ) { if ( !group ) { group = avahi_s_entry_group_new( server, avahi_entry_group_callback, this ); if ( !group ) { g_warning( "FAILED TO CREATE AVAHI ENTRY GROUP : %s", avahi_strerror( avahi_server_errno( server ) ) ); } } if ( group ) { if ( avahi_s_entry_group_is_empty( group ) ) { int ret = AVAHI_OK; while ( true ) { // TODO: this could loop forever...maybe we should bail at some stage ret = avahi_server_add_service( server, group, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, AvahiPublishFlags( 0 ), name.c_str(), TP_REMOTE_MDNS_SERVICE, NULL, NULL, port, NULL ); if ( ret == AVAHI_ERR_COLLISION ) { rename(); } else { break; } } if ( ret != AVAHI_OK ) { g_warning( "FAILED TO ADD AVAHI SERVICE : %s", avahi_strerror( ret ) ); } else { while ( true ) { // TODO: this could loop forever...maybe we should bail at some stage ret = avahi_server_add_service( server, group, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, AvahiPublishFlags( 0 ), name.c_str(), TP_HTTP_MDNS_SERVICE, NULL, NULL, http_port, NULL ); if ( ret == AVAHI_ERR_COLLISION ) { rename(); } else { break; } } if ( ret != AVAHI_OK ) { g_warning( "FAILED TO ADD AVAHI SERVICE : %s", avahi_strerror( ret ) ); } else { ret = avahi_s_entry_group_commit( group ); if ( ret != AVAHI_OK ) { g_warning( "FAILED TO COMMIT AVAHI SERVICE : %s", avahi_strerror( ret ) ); } } } } } }
void PublishAvahi::create_services(AvahiClient *c) { assert(c); char *n; /// If this is the first time we're called, let's create a new entry group if necessary if (!group) { if (!(group = avahi_entry_group_new(c, entry_group_callback, this))) { logE << "avahi_entry_group_new() failed: " << avahi_strerror(avahi_client_errno(c)) << "\n"; goto fail; } } /// If the group is empty (either because it was just created, or because it was reset previously, add our entries. int ret; if (avahi_entry_group_is_empty(group)) { logO << "Adding service '" << name << "'\n"; /// We will now add two services and one subtype to the entry group for (const auto& service: services_) { if ((ret = avahi_entry_group_add_service(group, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, AvahiPublishFlags(0), name, service.name_.c_str(), NULL, NULL, service.port_, NULL)) < 0) { if (ret == AVAHI_ERR_COLLISION) goto collision; logE << "Failed to add " << service.name_ << " service: " << avahi_strerror(ret) << "\n"; goto fail; } } /// Add an additional (hypothetic) subtype /* if ((ret = avahi_entry_group_add_service_subtype(group, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, AvahiPublishFlags(0), name, "_printer._tcp", NULL, "_magic._sub._printer._tcp") < 0)) { fprintf(stderr, "Failed to add subtype _magic._sub._printer._tcp: %s\n", avahi_strerror(ret)); goto fail; } */ /// Tell the server to register the service if ((ret = avahi_entry_group_commit(group)) < 0) { logE << "Failed to commit entry group: " << avahi_strerror(ret) << "\n"; goto fail; } } return; collision: /// A service name collision with a local service happened. Let's pick a new name n = avahi_alternative_service_name(name); avahi_free(name); name = n; logO << "Service name collision, renaming service to '" << name << "'\n"; avahi_entry_group_reset(group); create_services(c); return; fail: avahi_simple_poll_quit(simple_poll); }
bool CZeroconfAvahi::doForceReAnnounceService(const std::string& fcr_identifier) { bool ret = false; ScopedEventLoopBlock l_block(mp_poll); tServiceMap::iterator it = m_services.find(fcr_identifier); if (it != m_services.end() && it->second->mp_group) { // to force a reannounce on avahi its enough to reverse the txtrecord list it->second->mp_txt = avahi_string_list_reverse(it->second->mp_txt); // this will trigger the reannouncement if ((avahi_entry_group_update_service_txt_strlst(it->second->mp_group, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, AvahiPublishFlags(0), it->second->m_name.c_str(), it->second->m_type.c_str(), NULL, it->second->mp_txt)) >= 0) ret = true; } return ret; }
void PublishAvahi::create_services(AvahiClient *c) { char *n, r[128]; int ret; assert(c); /* If this is the first time we're called, let's create a new * entry group if necessary */ if (!group) { if (!(group = avahi_entry_group_new(c, entry_group_callback, this))) { logE << "avahi_entry_group_new() failed: " << avahi_strerror(avahi_client_errno(c)) << "\n"; goto fail; } } /* If the group is empty (either because it was just created, or * because it was reset previously, add our entries. */ if (avahi_entry_group_is_empty(group)) { logO << "Adding service '" << name << "'\n"; /* Create some random TXT data */ snprintf(r, sizeof(r), "random=%i", rand()); /* We will now add two services and one subtype to the entry * group. The two services have the same name, but differ in * the service type (IPP vs. BSD LPR). Only services with the * same name should be put in the same entry group. */ /* Add the service for IPP */ /* if ((ret = avahi_entry_group_add_service(group, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, AVAHI_PUBLISH_UNIQUE, name, "_ipp._tcp", NULL, NULL, 651, "test=blah", r, NULL)) < 0) { if (ret == AVAHI_ERR_COLLISION) goto collision; fprintf(stderr, "Failed to add _ipp._tcp service: %s\n", avahi_strerror(ret)); goto fail; } */ /* Add the same service for BSD LPR */ for (size_t n=0; n<services.size(); ++n) { if ((ret = avahi_entry_group_add_service(group, AVAHI_IF_UNSPEC, services[n].proto_, AvahiPublishFlags(0), name, services[n].name_.c_str(), NULL, NULL, services[n].port_, NULL)) < 0) { if (ret == AVAHI_ERR_COLLISION) goto collision; logE << "Failed to add " << services[n].name_ << " service: " << avahi_strerror(ret) << "\n"; goto fail; } } /* Add an additional (hypothetic) subtype */ /* if ((ret = avahi_entry_group_add_service_subtype(group, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, AvahiPublishFlags(0), name, "_printer._tcp", NULL, "_magic._sub._printer._tcp") < 0)) { fprintf(stderr, "Failed to add subtype _magic._sub._printer._tcp: %s\n", avahi_strerror(ret)); goto fail; } */ /* Tell the server to register the service */ if ((ret = avahi_entry_group_commit(group)) < 0) { logE << "Failed to commit entry group: " << avahi_strerror(ret) << "\n"; goto fail; } } return; collision: /* A service name collision with a local service happened. Let's * pick a new name */ n = avahi_alternative_service_name(name); avahi_free(name); name = n; logO << "Service name collision, renaming service to '" << name << "'\n"; avahi_entry_group_reset(group); create_services(c); return; fail: avahi_simple_poll_quit(simple_poll); }
void announcer::async_announce(const aware::contact& contact, async_announce_handler h) { assert(ptr != 0); handler = h; const AvahiPublishFlags flags = AvahiPublishFlags(0); const aware::contact::endpoint_type endpoint = contact.get_endpoint(); // Use all network interfaces const AvahiIfIndex interface_index = AVAHI_IF_UNSPEC; // Use only a specific protocol const AvahiProtocol protocol = contact.get_endpoint().protocol() == boost::asio::ip::tcp::v6() ? AVAHI_PROTO_INET6 : AVAHI_PROTO_INET; std::string name = contact.get_name(); // FIXME: from contact (endpoint.protocol()) std::string type = "_" + contact.get_type() + "._tcp"; // Use .local const char *domain = 0; // Host name boost::asio::ip::address address = endpoint.address(); std::string host = address.is_unspecified() ? "" // Use default host name : address.to_string(); property_list properties; if (!contact.get_properties().empty()) { properties = contact.get_properties(); if (properties == 0) { boost::system::error_code error(boost::system::errc::not_enough_memory, boost::system::system_category()); handler(error); return; } } while (true) { int rc = avahi_entry_group_add_service_strlst(ptr, interface_index, protocol, flags, name.c_str(), type.c_str(), domain, host.empty() ? 0 : host.c_str(), endpoint.port(), properties); if (rc == AVAHI_ERR_COLLISION) { char *alternative = avahi_alternative_service_name(name.c_str()); name = alternative; avahi_free(alternative); } else if (rc != AVAHI_OK) { handler(convert_error(rc)); return; } else { break; } } commit(ptr); }