// [License] // The Ariba-Underlay Copyright // // Copyright (c) 2008-2009, Institute of Telematics, Universität Karlsruhe (TH) // // Institute of Telematics // Universität Karlsruhe (TH) // Zirkel 2, 76128 Karlsruhe // Germany // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // 1. Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // 2. Redistributions in binary form must reproduce the above copyright // notice, this list of conditions and the following disclaimer in the // documentation and/or other materials provided with the distribution. // // THIS SOFTWARE IS PROVIDED BY THE INSTITUTE OF TELEMATICS ``AS IS'' AND // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE ARIBA PROJECT OR // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // The views and conclusions contained in the software and documentation // are those of the authors and should not be interpreted as representing // official policies, either expressed or implied, of the Institute of // Telematics. // [License] #include "MulticastDns.h" namespace ariba { namespace utility { use_logging_cpp(MulticastDns); MulticastDns::MulticastDns(string type, BootstrapInformationCallback* _callback) : BootstrapModule(type, _callback), serviceType(type){ #ifdef HAVE_LIBAVAHI_CLIENT avahiclient = NULL; avahigroup = NULL; avahipoll = NULL; avahibrowser = NULL; #endif // HAVE_LIBAVAHI_CLIENT } MulticastDns::~MulticastDns(){ } string MulticastDns::getName(){ return "MulticastDns"; } string MulticastDns::getInformation(){ return "bootstrap module based on multicast-dns using the avahi library"; } bool MulticastDns::isFunctional(){ #ifdef HAVE_LIBAVAHI_CLIENT return true; #else return false; #endif } void MulticastDns::start(){ #ifdef HAVE_LIBAVAHI_CLIENT int error = 0; // create a new avahi polling thread avahipoll = avahi_threaded_poll_new(); assert( avahipoll != NULL ); // create a new avahi client avahiclient = avahi_client_new( avahi_threaded_poll_get(avahipoll), (AvahiClientFlags)0, MulticastDns::client_callback, this, &error ); assert( avahiclient != NULL ); // block the event loop avahi_threaded_poll_lock( avahipoll ); // create the service browser avahibrowser = avahi_service_browser_new( avahiclient, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, serviceType.c_str(), NULL, (AvahiLookupFlags)0, MulticastDns::browse_callback, this); //unblock the event loop and let it run avahi_threaded_poll_unlock( avahipoll ); avahi_threaded_poll_start( avahipoll ); #endif // HAVE_LIBAVAHI_CLIENT } void MulticastDns::stop(){ #ifdef HAVE_LIBAVAHI_CLIENT avahi_threaded_poll_stop( avahipoll ); avahi_service_browser_free( avahibrowser ); if( avahigroup != NULL ) avahi_entry_group_free( avahigroup ); avahi_client_free( avahiclient ); avahi_threaded_poll_free( avahipoll ); #endif // HAVE_LIBAVAHI_CLIENT } void MulticastDns::publishService(string name, string info){ #ifdef HAVE_LIBAVAHI_CLIENT avahi_threaded_poll_lock(avahipoll); assert( avahiclient != NULL ); char* n = NULL; int ret = 0; if( avahigroup == NULL){ avahigroup = avahi_entry_group_new(avahiclient, MulticastDns::entry_group_callback, this); if(avahigroup == NULL) { logging_warn("avahi_entry_group_new failed " << avahi_strerror(avahi_client_errno(avahiclient))); avahi_threaded_poll_quit(avahipoll); return; } } logging_debug("avahi adding service " << name); ret = avahi_entry_group_add_service( avahigroup, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, (AvahiPublishFlags)0, name.c_str(), serviceType.c_str(), NULL, NULL, 0, info.c_str(), NULL); if( ret < 0 ){ logging_warn("failed to add service " << name << ": " << avahi_strerror(ret)); avahi_threaded_poll_quit(avahipoll); return; } // tell the server to register the service ret = avahi_entry_group_commit(avahigroup); if(ret < 0) { logging_warn("failed to commit entry group: " << avahi_strerror(ret)); avahi_threaded_poll_quit(avahipoll); } avahi_threaded_poll_unlock(avahipoll); #endif // HAVE_LIBAVAHI_CLIENT } void MulticastDns::revokeService(string name){ #ifdef HAVE_LIBAVAHI_CLIENT if (avahigroup) avahi_entry_group_reset(avahigroup); #endif // HAVE_LIBAVAHI_CLIENT } #ifdef HAVE_LIBAVAHI_CLIENT void MulticastDns::client_callback(AvahiClient* client, AvahiClientState state, void* userdata){ MulticastDns* obj = (MulticastDns*)userdata; assert( obj != NULL ); switch (state) { case AVAHI_CLIENT_S_RUNNING: // server has startup successfully and registered its host // name on the network, so it's time to create our services logging_debug("avahi client is running"); break; case AVAHI_CLIENT_FAILURE: logging_warn( "avahi client failure " << avahi_strerror(avahi_client_errno(client)) ); avahi_threaded_poll_quit(obj->avahipoll); break; case AVAHI_CLIENT_S_COLLISION: logging_warn("avahi client collision"); break; case AVAHI_CLIENT_S_REGISTERING: // // the server records are now being established. This // might be caused by a host name change. We need to wait // for our own records to register until the host name is // properly esatblished // if( obj->avahigroup != NULL ) avahi_entry_group_reset(obj->avahigroup); break; case AVAHI_CLIENT_CONNECTING: break; } } void MulticastDns::entry_group_callback(AvahiEntryGroup* group, AvahiEntryGroupState state, void* userdata){ AvahiClient* client = avahi_entry_group_get_client( group ); assert( client != NULL); MulticastDns* obj = (MulticastDns*)userdata; assert(obj != NULL); obj->avahigroup = group; // // called whenever the entry group state changes // switch(state) { case AVAHI_ENTRY_GROUP_ESTABLISHED: // entry group has been established successfully logging_debug( "service entry group successfully established" ); break; case AVAHI_ENTRY_GROUP_COLLISION: // service name collision logging_warn("service name collision for name"); break; case AVAHI_ENTRY_GROUP_FAILURE: logging_warn("service group failure: " << avahi_strerror(avahi_client_errno(client))); avahi_threaded_poll_quit(obj->avahipoll); break; case AVAHI_ENTRY_GROUP_UNCOMMITED: break; case AVAHI_ENTRY_GROUP_REGISTERING: break; } //switch(state) } void MulticastDns::browse_callback(AvahiServiceBrowser* browser, AvahiIfIndex interface, AvahiProtocol protocol, AvahiBrowserEvent event, const char* name, const char* type, const char* domain, AvahiLookupResultFlags flags, void* userdata){ AvahiClient* client = avahi_service_browser_get_client(browser); MulticastDns* obj = (MulticastDns*)userdata; assert( client != NULL); assert( obj != NULL ); switch (event) { case AVAHI_BROWSER_FAILURE: logging_warn("avahi browser failure " << avahi_strerror(avahi_client_errno(client))); avahi_threaded_poll_quit( obj->avahipoll ); break; case AVAHI_BROWSER_NEW: if (!(avahi_service_resolver_new(client, interface, protocol, name, type, domain, AVAHI_PROTO_UNSPEC, (AvahiLookupFlags)0, MulticastDns::resolve_callback, obj))){ logging_warn( "failed to resolve service " << name << ", error " << avahi_strerror(avahi_client_errno(client))); } break; case AVAHI_BROWSER_REMOVE: break; case AVAHI_BROWSER_ALL_FOR_NOW: break; case AVAHI_BROWSER_CACHE_EXHAUSTED: break; } } void MulticastDns::resolve_callback(AvahiServiceResolver* resolver, AvahiIfIndex interface, AvahiProtocol protocol, AvahiResolverEvent event, const char *name, const char* type, const char* domain, const char* host_name, const AvahiAddress* address, uint16_t port, AvahiStringList* txt, AvahiLookupResultFlags flags, void* userdata){ AvahiClient* client = avahi_service_resolver_get_client(resolver); MulticastDns* obj = (MulticastDns*)userdata; assert( client != NULL ); assert( obj != NULL ); switch(event) { case AVAHI_RESOLVER_FAILURE: logging_warn("resolver failed to resolve service " << name << ", error " << avahi_strerror(avahi_client_errno(client))); break; case AVAHI_RESOLVER_FOUND: { char a[AVAHI_ADDRESS_STR_MAX]; char* t = NULL; avahi_address_snprint(a, sizeof(a), address); t = avahi_string_list_to_string(txt); if(obj != NULL && obj->callback != NULL){ obj->callback->onBootstrapServiceFound(name, t); //foundNewService(name, type, domain, host_name, (int)port, a, t); } avahi_free( resolver ); break; } } avahi_service_resolver_free( resolver ); } #endif // HAVE_LIBAVAHI_CLIENT }} //namespace ariba, utility