18 #include <avahi-common/alternative.h> 19 #include <avahi-common/timeval.h> 20 #include <avahi-common/thread-watch.h> 21 #include <boost/thread/thread.hpp> 22 #include <zeroconf_msgs/Protocols.h> 24 #include "../../include/zeroconf_avahi/zeroconf.hpp" 38 invalid_object(false), threaded_poll(NULL), client(NULL), interface(AVAHI_IF_UNSPEC), permitted_protocols(
46 ROS_ERROR(
"Zeroconf: failed to create an avahi threaded poll.");
51 client = avahi_client_new(avahi_threaded_poll_get(
threaded_poll), static_cast<AvahiClientFlags>(0),
57 ROS_ERROR(
"Zeroconf: failed to create an avahi client.");
78 avahi_service_browser_free(iter->first);
110 ROS_DEBUG(
"Zeroconf: starting the threaded poll.");
119 ROS_WARN_STREAM(
"Zeroconf : not connected to the avahi client, aborting add_listener [" << service_type <<
"]");
129 ROS_WARN_STREAM(
"Zeroconf : already listening for services of type '" << service_type <<
"'");
135 AvahiServiceBrowser *service_browser = NULL;
142 "Zeroconf: failed to create an avahi service browser: " << avahi_strerror(avahi_client_errno(
client)));
151 ROS_INFO_STREAM(
"Zeroconf: added a listener [" << service_type <<
"]");
157 AvahiServiceBrowser *service_browser = NULL;
165 ROS_WARN_STREAM(
"Zeroconf : not currently listening for '" << service_type <<
"', aborting listener removal.");
170 ROS_INFO_STREAM(
"Zeroconf: removing a listener [" << service_type <<
"]");
171 service_browser = browser_iter->second;
178 if ((*iter)->service.type == service_type)
195 avahi_service_browser_free(service_browser);
235 if (avahi_client_get_state(
client) != AVAHI_CLIENT_S_RUNNING)
237 ROS_ERROR(
"Zeroconf: avahi_client_state is not running (probably still registering with avahi daemon)");
246 service_bimap::right_const_iterator iter;
251 "Zeroconf: this node is currently already committing this service [" << service.name <<
"][" << service.type <<
"][" << service.port <<
"]");
258 "Zeroconf: this node has already established this service [" << service.name <<
"][" << service.type <<
"][" << service.port <<
"]");
263 ROS_DEBUG_STREAM(
"Zeroconf: adding a new service [" << service.name <<
"][" << service.type <<
"]");
266 AvahiEntryGroup* group = NULL;
269 ROS_ERROR_STREAM(
"Zeroconf: avahi_entry_group_new() failed: " << avahi_strerror(avahi_client_errno(
client)));
275 service.name.c_str(), service.type.c_str(), service.domain.c_str(), NULL,
276 static_cast<uint16_t
>(service.port), NULL);
279 avahi_entry_group_free(group);
280 if (ret == AVAHI_ERR_COLLISION)
282 std::string old_name = service.name;
284 service.name = avahi_alternative_service_name(service.name.c_str());
286 "Zeroconf: local service name collision, renaming [" << service.name <<
"][" << new_service.name <<
"]");
292 "Zeroconf: failed to add service [" << service.type.c_str() <<
"][" << avahi_strerror(ret) <<
"]");
303 if ((ret = avahi_entry_group_commit(group)) < 0)
305 ROS_ERROR_STREAM(
"Zeroconf: failed to commit entry group [" << avahi_strerror(ret) <<
"]");
306 avahi_entry_group_free(group);
314 ROS_DEBUG(
"Zeroconf: service committed, waiting for callback...");
320 AvahiEntryGroup *group = NULL;
327 group = iter->second;
330 ROS_INFO_STREAM(
"Zeroconf: removing service [" << service.name <<
"][" << service.type <<
"]");
335 "Zeroconf: couldn't remove not currently advertised service [" << service.name <<
"][" << service.type <<
"]");
341 avahi_entry_group_reset(group);
342 avahi_entry_group_free(group);
356 std::vector<zeroconf_msgs::DiscoveredService> &list)
360 if (service_type ==
"")
365 if (((*iter)->service.ipv4_addresses.size() != 0) || ((*iter)->service.ipv6_addresses.size() != 0))
367 list.push_back((*iter)->service);
375 if ((*iter)->service.type == service_type)
378 if (((*iter)->service.ipv4_addresses.size() != 0) || ((*iter)->service.ipv6_addresses.size() != 0))
380 list.push_back((*iter)->service);
387 std::vector<zeroconf_msgs::PublishedService> &list)
391 if (service_type ==
"")
396 list.push_back(iter->second);
404 if (iter->second.type == service_type)
406 list.push_back(iter->second);
420 case (zeroconf_msgs::Protocols::UNSPECIFIED):
422 return AVAHI_PROTO_UNSPEC;
424 case (zeroconf_msgs::Protocols::IPV4):
426 return AVAHI_PROTO_INET;
428 case (zeroconf_msgs::Protocols::IPV6):
430 return AVAHI_PROTO_INET6;
433 return AVAHI_PROTO_UNSPEC;
441 case (zeroconf_msgs::Protocols::UNSPECIFIED):
443 return "unspecified";
445 case (zeroconf_msgs::Protocols::IPV4):
449 case (zeroconf_msgs::Protocols::IPV6):
454 return "unspecified";
462 case (AVAHI_PROTO_UNSPEC):
464 return zeroconf_msgs::Protocols::UNSPECIFIED;
466 case (AVAHI_PROTO_INET):
468 return zeroconf_msgs::Protocols::IPV4;
470 case (AVAHI_PROTO_INET6):
472 return zeroconf_msgs::Protocols::IPV6;
475 return zeroconf_msgs::Protocols::UNSPECIFIED;
483 case (AVAHI_PROTO_UNSPEC):
485 return "unspecified";
487 case (AVAHI_PROTO_INET):
491 case (AVAHI_PROTO_INET6):
496 return "unspecified";
513 if (((*iter)->service.name == service.name) && ((*iter)->service.type == service.type)
514 && ((*iter)->service.domain == service.domain))
544 AvahiBrowserEvent event,
const char *name,
const char *type,
const char *domain,
545 AvahiLookupResultFlags flags,
void* userdata)
553 case AVAHI_BROWSER_FAILURE:
555 "Zeroconf: browser failure [" << avahi_strerror(avahi_client_errno(avahi_service_browser_get_client(browser))));
559 case AVAHI_BROWSER_NEW:
561 zeroconf_msgs::DiscoveredService service;
564 service.domain = domain;
566 AvahiServiceResolver* resolver = avahi_service_resolver_new(zeroconf->
client, interface, protocol, name, type,
568 static_cast<AvahiLookupFlags>(0),
573 "Zeroconf: avahi resolver failure (avahi daemon problem) [" << name <<
"][" << avahi_strerror(avahi_client_errno(zeroconf->
client)) <<
"][" << interface <<
"][" << zeroconf->
avahi_to_txt_protocol(protocol) <<
"]");
583 "Zeroconf: discovered new service [" << name <<
"][" << type <<
"][" << domain <<
"][" << interface <<
"][" << zeroconf->
avahi_to_txt_protocol(protocol) <<
"]");
593 "Tried to insert a new service on top of an old stored one - probably a bug in zeroconf_avahi!");
599 case AVAHI_BROWSER_REMOVE:
601 zeroconf_msgs::DiscoveredService service;
604 service.domain = domain;
618 "Zeroconf: service was removed [" << service.name <<
"][" << service.type <<
"][" << service.domain <<
"][" << interface <<
"][" << zeroconf->
ros_to_txt_protocol(zeroconf->
avahi_to_ros_protocol(protocol)) <<
"]");
632 "Zeroconf: attempted to remove a non-discovered service (probably a bug in zeroconf_avahi!)");
637 case AVAHI_BROWSER_ALL_FOR_NOW:
638 case AVAHI_BROWSER_CACHE_EXHAUSTED:
640 if (event == AVAHI_BROWSER_CACHE_EXHAUSTED)
642 ROS_DEBUG(
"Zeroconf: browser event occured [cache exhausted]");
646 ROS_DEBUG(
"Zeroconf: browser event occured [all for now]");
684 AvahiResolverEvent event,
const char *name,
const char *type,
const char *domain,
685 const char *host_name,
const AvahiAddress *address, uint16_t port, AvahiStringList *txt,
686 AvahiLookupResultFlags flags,
void* userdata)
694 case AVAHI_RESOLVER_FAILURE:
696 zeroconf_msgs::DiscoveredService service;
699 service.domain = domain;
708 if ((*iter)->service.ipv4_addresses.size() != 0)
711 "Zeroconf: timed out resolving service [" << name <<
"][" << type <<
"][" << domain <<
"][" << interface <<
"][" << zeroconf->
avahi_to_txt_protocol(protocol) <<
"][" << (*iter)->service.ipv4_addresses[0] <<
":" << (*iter)->service.port <<
"]");
713 else if ((*iter)->service.ipv6_addresses.size() != 0)
716 "Zeroconf: timed out resolving service [" << name <<
"][" << type <<
"][" << domain <<
"][" << interface <<
"][" << zeroconf->
avahi_to_txt_protocol(protocol) <<
"][" << (*iter)->service.ipv6_addresses[0] <<
":" << (*iter)->service.port <<
"]");
721 "Zeroconf: timed out resolving service [" << name <<
"][" << type <<
"][" << domain <<
"][" << interface <<
"][" << zeroconf->
avahi_to_txt_protocol(protocol) <<
"]");
726 (*iter)->service.ipv4_addresses.clear();
727 (*iter)->service.ipv6_addresses.clear();
728 (*iter)->service.hostname =
"";
729 (*iter)->service.port = 0;
742 "Zeroconf: timed out resolving a service that was not saved, probably a zeroconf_avahi bug!");
747 case AVAHI_RESOLVER_FOUND:
749 char a[AVAHI_ADDRESS_STR_MAX], *t;
752 boost::this_thread::sleep(boost::posix_time::milliseconds(500));
754 t = avahi_string_list_to_string(txt);
755 avahi_address_snprint(a,
sizeof(a), address);
757 zeroconf_msgs::DiscoveredService service;
760 service.domain = domain;
764 case (zeroconf_msgs::Protocols::IPV4):
766 service.ipv4_addresses.push_back(a);
768 size_t found = std::string(a).find(
":");
769 if (found != std::string::npos)
772 "Zeroconf: avahi is behaving badly (bug) - set an ipv6 address for an ipv4 service, recovering...");
779 case (zeroconf_msgs::Protocols::IPV6):
781 service.ipv6_addresses.push_back(a);
792 service.hostname = host_name;
794 service.description = t;
795 service.cookie = avahi_string_list_get_service_cookie(txt);
796 service.is_local = ((flags & AVAHI_LOOKUP_RESULT_LOCAL) == 0 ?
false :
true);
797 service.our_own = ((flags & AVAHI_LOOKUP_RESULT_OUR_OWN) == 0 ?
false :
true);
798 service.wide_area = ((flags & AVAHI_LOOKUP_RESULT_WIDE_AREA) == 0 ?
false :
true);
799 service.multicast = ((flags & AVAHI_LOOKUP_RESULT_MULTICAST) == 0 ?
false :
true);
800 service.cached = ((flags & AVAHI_LOOKUP_RESULT_CACHED) == 0 ?
false :
true);
809 (*iter)->service = service;
816 "Zeroconf: resolved service [" << name <<
"][" << type <<
"][" << domain <<
"][" << interface <<
"][" << zeroconf->
ros_to_txt_protocol((*iter)->protocol) <<
"][" << a <<
":" << service.port <<
"]");
818 ROS_DEBUG_STREAM(
"Zeroconf: \ttype: " << service.type);
819 ROS_DEBUG_STREAM(
"Zeroconf: \tdomain: " << service.domain);
820 ROS_DEBUG_STREAM(
"Zeroconf: \tinterface: " << interface);
821 ROS_DEBUG_STREAM(
"Zeroconf: \tprotocol: " << zeroconf->
ros_to_txt_protocol((*iter)->protocol));
822 ROS_DEBUG_STREAM(
"Zeroconf: \thostname: " << service.hostname);
823 ROS_DEBUG_STREAM(
"Zeroconf: \taddress: " << a);
824 ROS_DEBUG_STREAM(
"Zeroconf: \tport: " << service.port);
825 ROS_DEBUG_STREAM(
"Zeroconf: \tdescription: " << service.description);
826 ROS_DEBUG_STREAM(
"Zeroconf: \tcookie: " << service.cookie);
827 ROS_DEBUG_STREAM(
"Zeroconf: \tis_local: " << (service.is_local ? 1 : 0 ));
828 ROS_DEBUG_STREAM(
"Zeroconf: \tour_own: " << (service.our_own ? 1 : 0 ));
829 ROS_DEBUG_STREAM(
"Zeroconf: \twide_area: " << (service.wide_area ? 1 : 0 ));
830 ROS_DEBUG_STREAM(
"Zeroconf: \tmulticast: " << (service.multicast ? 1 : 0 ));
842 "Zeroconf: timed out resolving a service that was not saved, probably a zeroconf_avahi bug!");
874 case AVAHI_ENTRY_GROUP_ESTABLISHED:
882 service = left->second;
887 "Zeroconf : should never reach here, please report a bug in zeroconf_avahi's entry_group_callback.");
894 "Zeroconf: service successfully established [" << service.name <<
"][" << service.type <<
"][" << service.port <<
"]");
897 case AVAHI_ENTRY_GROUP_COLLISION:
906 service = left->second;
911 "Zeroconf : should never reach here, please report a bug in zeroconf_avahi's entry_group_callback.");
916 std::string alternative_name = avahi_alternative_service_name(service.name.c_str());
918 "Zeroconf: service name collision, renaming service [" << service.name <<
"]" <<
"][" << alternative_name <<
"]");
919 service.name = alternative_name;
920 avahi_entry_group_free(g);
926 case AVAHI_ENTRY_GROUP_FAILURE:
930 "Zeroconf: group state changed, system failure when trying to register service [" << avahi_strerror(avahi_client_errno(avahi_entry_group_get_client(g))) <<
"]");
931 avahi_entry_group_free(g);
935 case AVAHI_ENTRY_GROUP_UNCOMMITED:
941 case AVAHI_ENTRY_GROUP_REGISTERING:
950 service = left->second;
955 "Zeroconf : should never reach here, please report a bug in zeroconf_avahi's entry_group_callback.");
960 "Zeroconf: group state changed, service registering [" << service.name <<
"][" << service.type <<
"]");
965 ROS_DEBUG_STREAM(
"Zeroconf: group state changed, ended in an unknown state [" << state <<
"]");
993 case AVAHI_CLIENT_S_RUNNING:
997 ROS_DEBUG(
"Zeroconf: avahi client up and running.");
1001 case AVAHI_CLIENT_FAILURE:
1003 ROS_ERROR_STREAM(
"Zeroconf: avahi client failure [" << avahi_strerror(avahi_client_errno(c)) <<
"]");
1008 case AVAHI_CLIENT_S_COLLISION:
1010 ROS_DEBUG(
"Zeroconf: avahi client collision.");
1016 case AVAHI_CLIENT_S_REGISTERING:
1018 ROS_DEBUG(
"Zeroconf: avahi client registering.");
1030 case AVAHI_CLIENT_CONNECTING:
1032 ROS_DEBUG(
"Zeroconf: avahi client registering.");
bool add_service_non_threaded(PublishedService &service)
Internal storage for linking discovered service info with active avahi resolvers. ...
boost::mutex service_mutex
static void discovery_callback(AvahiServiceBrowser *b, AvahiIfIndex interface, AvahiProtocol protocol, AvahiBrowserEvent event, const char *name, const char *type, const char *domain, AvahiLookupResultFlags flags, void *userdata)
int avahi_to_ros_protocol(const int &protocol)
static void entry_group_callback(AvahiEntryGroup *g, AvahiEntryGroupState state, void *userdata)
AvahiThreadedPoll * threaded_poll
std::string ros_to_txt_protocol(const int &protocol)
connection_signal_cb new_connection_signal
void list_discovered_services(const std::string &service_type, std::vector< zeroconf_msgs::DiscoveredService > &list)
discovery_bimap discovery_service_types
void list_published_services(const std::string &service_type, std::vector< zeroconf_msgs::PublishedService > &list)
bool add_listener(std::string &service_type)
const int permitted_protocols
service_bimap committed_services
bool add_service(PublishedService &service)
bool remove_service(const PublishedService &service)
int ros_to_avahi_protocol(const int &protocol)
Ros interface to linux's avahi daemon.
#define ROS_WARN_STREAM(args)
#define ROS_DEBUG_STREAM(args)
bool remove_listener(const std::string &service_type)
zeroconf_msgs::PublishedService PublishedService
discovered_service_set::iterator find_discovered_service(zeroconf_msgs::DiscoveredService &service)
#define ROS_INFO_STREAM(args)
static void client_callback(AvahiClient *c, AvahiClientState state, void *userdata)
std::string avahi_to_txt_protocol(const int &protocol)
#define ROS_ERROR_STREAM(args)
service_bimap established_services
connection_signal_cb lost_connection_signal
static void resolve_callback(AvahiServiceResolver *r, 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)
discovered_service_set discovered_services