00001
00012
00013
00014
00015
00016 #include <cstdio>
00017 #include <ctime>
00018 #include <avahi-common/alternative.h>
00019 #include <avahi-common/timeval.h>
00020 #include <avahi-common/thread-watch.h>
00021 #include <boost/thread/thread.hpp>
00022 #include <zeroconf_msgs/Protocols.h>
00023 #include <ros/ros.h>
00024 #include "../../include/zeroconf_avahi/zeroconf.hpp"
00025
00026
00027
00028
00029
00030 namespace zeroconf_avahi
00031 {
00032
00033
00034
00035
00036
00037 Zeroconf::Zeroconf() :
00038 invalid_object(false), threaded_poll(NULL), client(NULL), interface(AVAHI_IF_UNSPEC), permitted_protocols(
00039 AVAHI_PROTO_INET)
00040 {
00041 int error;
00042
00043
00044 if (!(threaded_poll = avahi_threaded_poll_new()))
00045 {
00046 ROS_ERROR("Zeroconf: failed to create an avahi threaded poll.");
00047 invalid_object = true;
00048 return;
00049 }
00050
00051 client = avahi_client_new(avahi_threaded_poll_get(threaded_poll), static_cast<AvahiClientFlags>(0),
00052 Zeroconf::client_callback, this, &error);
00053
00054
00055 if (!client)
00056 {
00057 ROS_ERROR("Zeroconf: failed to create an avahi client.");
00058 invalid_object = true;
00059 return;
00060 }
00061
00062
00063
00064
00065 }
00066
00067 Zeroconf::~Zeroconf()
00068 {
00069
00070
00071
00072 {
00073 boost::mutex::scoped_lock lock(service_mutex);
00074 for (discovery_bimap::left_const_iterator iter = discovery_service_types.left.begin();
00075 iter != discovery_service_types.left.end(); ++iter)
00076 {
00077 avahi_service_browser_free(iter->first);
00078 }
00079 discovered_services.clear();
00080 discovery_service_types.clear();
00081 }
00082 if (threaded_poll)
00083 {
00084 avahi_threaded_poll_stop(threaded_poll);
00085 }
00086
00087
00088
00089
00090
00091
00092
00093
00094 if (client)
00095 {
00096 avahi_client_free(client);
00097 }
00098 if (threaded_poll)
00099 {
00100 avahi_threaded_poll_free(threaded_poll);
00101 }
00102 }
00103
00104 void Zeroconf::spin()
00105 {
00106 if (!invalid_object)
00107 {
00108 ROS_DEBUG("Zeroconf: starting the threaded poll.");
00109
00110 avahi_threaded_poll_start(threaded_poll);
00111 }
00112 }
00113
00114 bool Zeroconf::add_listener(std::string &service_type)
00115 {
00116
00117 {
00118 boost::mutex::scoped_lock lock(service_mutex);
00119 discovery_bimap::right_iterator browser_iter = discovery_service_types.right.find(service_type);
00120 if (browser_iter != discovery_service_types.right.end())
00121 {
00122 ROS_WARN_STREAM("Zeroconf : already listening for services of type '" << service_type << "'");
00123 return false;
00124 }
00125 }
00126
00127
00128 AvahiServiceBrowser *service_browser = NULL;
00129 avahi_threaded_poll_lock(threaded_poll);
00130 if (!(service_browser = avahi_service_browser_new(client, interface, permitted_protocols, service_type.c_str(), NULL,
00131 static_cast<AvahiLookupFlags>(0), Zeroconf::discovery_callback,
00132 this)))
00133 {
00134 ROS_ERROR_STREAM(
00135 "Zeroconf: failed to create an avahi service browser: " << avahi_strerror(avahi_client_errno(client)));
00136 return false;
00137 }
00138 avahi_threaded_poll_unlock(threaded_poll);
00139
00140 {
00141 boost::mutex::scoped_lock lock(service_mutex);
00142 discovery_service_types.insert(discovery_bimap::value_type(service_browser, service_type));
00143 }
00144 ROS_INFO_STREAM("Zeroconf: added a listener [" << service_type << "]");
00145 return true;
00146 }
00147
00148 bool Zeroconf::remove_listener(const std::string &service_type)
00149 {
00150 AvahiServiceBrowser *service_browser = NULL;
00151
00152
00153 {
00154 boost::mutex::scoped_lock lock(service_mutex);
00155 discovery_bimap::right_iterator browser_iter = discovery_service_types.right.find(service_type);
00156 if (browser_iter == discovery_service_types.right.end())
00157 {
00158 ROS_WARN_STREAM("Zeroconf : not currently listening for '" << service_type << "', aborting listener removal.");
00159 return false;
00160 }
00161 else
00162 {
00163 ROS_INFO_STREAM("Zeroconf: removing a listener [" << service_type << "]");
00164 service_browser = browser_iter->second;
00165
00166 discovery_service_types.right.erase(browser_iter);
00167
00168 discovered_service_set::iterator iter = discovered_services.begin();
00169 while (iter != discovered_services.end())
00170 {
00171 if ((*iter)->service.type == service_type)
00172 {
00173 ROS_INFO_STREAM("Zeroconf: erasing element " << *iter);
00174 discovered_services.erase(iter++);
00175 }
00176 else
00177 {
00178 ROS_INFO_STREAM("Zeroconf: not erasing element " << *iter);
00179 ++iter;
00180 }
00181 }
00182 }
00183 }
00184
00185 if (service_browser)
00186 {
00187 avahi_threaded_poll_lock(threaded_poll);
00188 avahi_service_browser_free(service_browser);
00189 avahi_threaded_poll_unlock(threaded_poll);
00190 }
00191 return true;
00192 }
00206 bool Zeroconf::add_service(PublishedService &service)
00207 {
00208
00209 avahi_threaded_poll_lock(threaded_poll);
00210 bool result = add_service_non_threaded(service);
00211 avahi_threaded_poll_unlock(threaded_poll);
00212 return result;
00213 }
00214
00223 bool Zeroconf::add_service_non_threaded(PublishedService &service)
00224 {
00225
00226
00227
00228 if (avahi_client_get_state(client) != AVAHI_CLIENT_S_RUNNING)
00229 {
00230 ROS_ERROR("Zeroconf: avahi_client_state is not running (probably still registering with avahi daemon)");
00231 return false;
00232 }
00233
00234
00235
00236
00237 {
00238 boost::mutex::scoped_lock lock(service_mutex);
00239 service_bimap::right_const_iterator iter;
00240 iter = committed_services.right.find(service);
00241 if (iter != committed_services.right.end())
00242 {
00243 ROS_WARN_STREAM(
00244 "Zeroconf: this node is currently already committing this service [" << service.name << "][" << service.type << "][" << service.port << "]");
00245 return true;
00246 }
00247 iter = established_services.right.find(service);
00248 if (iter != established_services.right.end())
00249 {
00250 ROS_WARN_STREAM(
00251 "Zeroconf: this node has already established this service [" << service.name << "][" << service.type << "][" << service.port << "]");
00252 return true;
00253 }
00254 }
00255
00256 ROS_DEBUG_STREAM("Zeroconf: adding a new service [" << service.name << "][" << service.type << "]");
00257
00258
00259 AvahiEntryGroup* group = NULL;
00260 if (!(group = avahi_entry_group_new(client, entry_group_callback, this)))
00261 {
00262 ROS_ERROR_STREAM("Zeroconf: avahi_entry_group_new() failed: " << avahi_strerror(avahi_client_errno(client)));
00263 fail();
00264 return false;
00265 }
00266
00267 int ret = avahi_entry_group_add_service(group, interface, permitted_protocols, static_cast<AvahiPublishFlags>(0),
00268 service.name.c_str(), service.type.c_str(), service.domain.c_str(), NULL,
00269 static_cast<uint16_t>(service.port), NULL);
00270 if (ret < 0)
00271 {
00272 avahi_entry_group_free(group);
00273 if (ret == AVAHI_ERR_COLLISION)
00274 {
00275 std::string old_name = service.name;
00276 PublishedService new_service = service;
00277 service.name = avahi_alternative_service_name(service.name.c_str());
00278 ROS_WARN_STREAM(
00279 "Zeroconf: local service name collision, renaming [" << service.name << "][" << new_service.name << "]");
00280 return add_service_non_threaded(service);
00281 }
00282 else
00283 {
00284 ROS_ERROR_STREAM(
00285 "Zeroconf: failed to add service [" << service.type.c_str() << "][" << avahi_strerror(ret) << "]");
00286 fail();
00287 return false;
00288 }
00289 }
00290
00291
00292 {
00293 boost::mutex::scoped_lock lock(service_mutex);
00294 committed_services.insert(service_bimap::value_type(group, service));
00295 }
00296 if ((ret = avahi_entry_group_commit(group)) < 0)
00297 {
00298 ROS_ERROR_STREAM("Zeroconf: failed to commit entry group [" << avahi_strerror(ret) << "]");
00299 avahi_entry_group_free(group);
00300 {
00301 boost::mutex::scoped_lock lock(service_mutex);
00302 committed_services.left.erase(group);
00303 }
00304 fail();
00305 return false;
00306 }
00307 ROS_DEBUG("Zeroconf: service committed, waiting for callback...");
00308 return true;
00309 }
00310 bool Zeroconf::remove_service(const PublishedService &service)
00311 {
00312
00313 AvahiEntryGroup *group = NULL;
00314 bool erased = false;
00315 {
00316 boost::mutex::scoped_lock lock(service_mutex);
00317 service_bimap::right_const_iterator iter = established_services.right.find(service);
00318 if (iter != established_services.right.end())
00319 {
00320 group = iter->second;
00321 established_services.right.erase(service);
00322 erased = true;
00323 ROS_INFO_STREAM("Zeroconf: removing service [" << service.name << "][" << service.type << "]");
00324 }
00325 else
00326 {
00327 ROS_WARN_STREAM(
00328 "Zeroconf: couldn't remove not currently advertised service [" << service.name << "][" << service.type << "]");
00329 }
00330 }
00331 if (group)
00332 {
00333 avahi_threaded_poll_lock(threaded_poll);
00334 avahi_entry_group_reset(group);
00335 avahi_entry_group_free(group);
00336 avahi_threaded_poll_unlock(threaded_poll);
00337 }
00338 return erased;
00339 }
00348 void Zeroconf::list_discovered_services(const std::string &service_type,
00349 std::vector<zeroconf_msgs::DiscoveredService> &list)
00350 {
00351 list.clear();
00352 boost::mutex::scoped_lock lock(service_mutex);
00353 if (service_type == "")
00354 {
00355 for (discovered_service_set::iterator iter = discovered_services.begin(); iter != discovered_services.end(); ++iter)
00356 {
00357
00358 if (((*iter)->service.ipv4_addresses.size() != 0) || ((*iter)->service.ipv6_addresses.size() != 0))
00359 {
00360 list.push_back((*iter)->service);
00361 }
00362 }
00363 }
00364 else
00365 {
00366 for (discovered_service_set::iterator iter = discovered_services.begin(); iter != discovered_services.end(); ++iter)
00367 {
00368 if ((*iter)->service.type == service_type)
00369 {
00370
00371 if (((*iter)->service.ipv4_addresses.size() != 0) || ((*iter)->service.ipv6_addresses.size() != 0))
00372 {
00373 list.push_back((*iter)->service);
00374 }
00375 }
00376 }
00377 }
00378 }
00379 void Zeroconf::list_published_services(const std::string &service_type,
00380 std::vector<zeroconf_msgs::PublishedService> &list)
00381 {
00382 list.clear();
00383 boost::mutex::scoped_lock lock(service_mutex);
00384 if (service_type == "")
00385 {
00386 for (service_bimap::left_const_iterator iter = established_services.left.begin();
00387 iter != established_services.left.end(); ++iter)
00388 {
00389 list.push_back(iter->second);
00390 }
00391 }
00392 else
00393 {
00394 for (service_bimap::left_const_iterator iter = established_services.left.begin();
00395 iter != established_services.left.end(); ++iter)
00396 {
00397 if (iter->second.type == service_type)
00398 {
00399 list.push_back(iter->second);
00400 }
00401 }
00402 }
00403 }
00404
00405
00406
00407
00408
00409 int Zeroconf::ros_to_avahi_protocol(const int &protocol)
00410 {
00411 switch (protocol)
00412 {
00413 case (zeroconf_msgs::Protocols::UNSPECIFIED):
00414 {
00415 return AVAHI_PROTO_UNSPEC;
00416 }
00417 case (zeroconf_msgs::Protocols::IPV4):
00418 {
00419 return AVAHI_PROTO_INET;
00420 }
00421 case (zeroconf_msgs::Protocols::IPV6):
00422 {
00423 return AVAHI_PROTO_INET6;
00424 }
00425 default:
00426 return AVAHI_PROTO_UNSPEC;
00427 }
00428 }
00429
00430 std::string Zeroconf::ros_to_txt_protocol(const int &protocol)
00431 {
00432 switch (protocol)
00433 {
00434 case (zeroconf_msgs::Protocols::UNSPECIFIED):
00435 {
00436 return "unspecified";
00437 }
00438 case (zeroconf_msgs::Protocols::IPV4):
00439 {
00440 return "ipv4";
00441 }
00442 case (zeroconf_msgs::Protocols::IPV6):
00443 {
00444 return "ipv6";
00445 }
00446 default:
00447 return "unspecified";
00448 }
00449 }
00450
00451 int Zeroconf::avahi_to_ros_protocol(const int &protocol)
00452 {
00453 switch (protocol)
00454 {
00455 case (AVAHI_PROTO_UNSPEC):
00456 {
00457 return zeroconf_msgs::Protocols::UNSPECIFIED;
00458 }
00459 case (AVAHI_PROTO_INET):
00460 {
00461 return zeroconf_msgs::Protocols::IPV4;
00462 }
00463 case (AVAHI_PROTO_INET6):
00464 {
00465 return zeroconf_msgs::Protocols::IPV6;
00466 }
00467 default:
00468 return zeroconf_msgs::Protocols::UNSPECIFIED;
00469 }
00470 }
00471
00472 std::string Zeroconf::avahi_to_txt_protocol(const int &protocol)
00473 {
00474 switch (protocol)
00475 {
00476 case (AVAHI_PROTO_UNSPEC):
00477 {
00478 return "unspecified";
00479 }
00480 case (AVAHI_PROTO_INET):
00481 {
00482 return "ipv4";
00483 }
00484 case (AVAHI_PROTO_INET6):
00485 {
00486 return "ipv6";
00487 }
00488 default:
00489 return "unspecified";
00490 }
00491 }
00492
00501 Zeroconf::discovered_service_set::iterator Zeroconf::find_discovered_service(zeroconf_msgs::DiscoveredService &service)
00502 {
00503 discovered_service_set::iterator iter = discovered_services.begin();
00504 while (iter != discovered_services.end())
00505 {
00506 if (((*iter)->service.name == service.name) && ((*iter)->service.type == service.type)
00507 && ((*iter)->service.domain == service.domain))
00508 {
00509 return iter;
00510 }
00511 else
00512 {
00513 ++iter;
00514 }
00515 }
00516 return discovered_services.end();
00517 }
00518
00519
00520
00521
00536 void Zeroconf::discovery_callback(AvahiServiceBrowser *browser, AvahiIfIndex interface, AvahiProtocol protocol,
00537 AvahiBrowserEvent event, const char *name, const char *type, const char *domain,
00538 AvahiLookupResultFlags flags, void* userdata)
00539 {
00540
00541 Zeroconf *zeroconf = reinterpret_cast<Zeroconf*>(userdata);
00542 assert(browser);
00543
00544 switch (event)
00545 {
00546 case AVAHI_BROWSER_FAILURE:
00547 ROS_ERROR_STREAM(
00548 "Zeroconf: browser failure [" << avahi_strerror(avahi_client_errno(avahi_service_browser_get_client(browser))));
00549 avahi_threaded_poll_quit(zeroconf->threaded_poll);
00550 return;
00551
00552 case AVAHI_BROWSER_NEW:
00553 {
00554 zeroconf_msgs::DiscoveredService service;
00555 service.name = name;
00556 service.type = type;
00557 service.domain = domain;
00558
00559 AvahiServiceResolver* resolver = avahi_service_resolver_new(zeroconf->client, interface, protocol, name, type,
00560 domain, zeroconf->permitted_protocols,
00561 static_cast<AvahiLookupFlags>(0),
00562 Zeroconf::resolve_callback, zeroconf);
00563 if (!resolver)
00564 {
00565 ROS_ERROR_STREAM(
00566 "Zeroconf: avahi resolver failure (avahi daemon problem) [" << name << "][" << avahi_strerror(avahi_client_errno(zeroconf->client)) << "][" << interface << "][" << zeroconf->avahi_to_txt_protocol(protocol) << "]");
00567 break;
00568 }
00569 {
00570 boost::mutex::scoped_lock lock(zeroconf->service_mutex);
00571 boost::shared_ptr<DiscoveredAvahiService> new_service(
00572 new DiscoveredAvahiService(service, resolver, interface, zeroconf->avahi_to_ros_protocol(protocol)));
00573 if ((zeroconf->discovered_services.insert(new_service)).second)
00574 {
00575 ROS_INFO_STREAM(
00576 "Zeroconf: discovered new service [" << name << "][" << type << "][" << domain << "][" << interface << "][" << zeroconf->avahi_to_txt_protocol(protocol) << "]");
00577
00578
00579
00580
00581
00582 }
00583 else
00584 {
00585 ROS_ERROR_STREAM(
00586 "Tried to insert a new service on top of an old stored one - probably a bug in zeroconf_avahi!");
00587 }
00588 }
00589 break;
00590 }
00591
00592 case AVAHI_BROWSER_REMOVE:
00593 {
00594 zeroconf_msgs::DiscoveredService service;
00595 service.name = name;
00596 service.type = type;
00597 service.domain = domain;
00598 {
00599 boost::mutex::scoped_lock lock(zeroconf->service_mutex);
00600 discovered_service_set::iterator iter = zeroconf->find_discovered_service(service);
00601 if (iter != zeroconf->discovered_services.end())
00602 {
00603
00604
00605
00606 zeroconf->discovered_services.erase(iter);
00607
00608
00609
00610 ROS_INFO_STREAM(
00611 "Zeroconf: service was removed [" << service.name << "][" << service.type << "][" << service.domain << "][" << interface << "][" << zeroconf->ros_to_txt_protocol(zeroconf->avahi_to_ros_protocol(protocol)) << "]");
00612
00613
00614
00615
00616
00617 if (zeroconf->lost_connection_signal)
00618 {
00619 zeroconf->lost_connection_signal(service);
00620 }
00621 }
00622 else
00623 {
00624 ROS_ERROR_STREAM(
00625 "Zeroconf: attempted to remove a non-discovered service (probably a bug in zeroconf_avahi!)");
00626 }
00627 }
00628 break;
00629 }
00630 case AVAHI_BROWSER_ALL_FOR_NOW:
00631 case AVAHI_BROWSER_CACHE_EXHAUSTED:
00632 {
00633 if (event == AVAHI_BROWSER_CACHE_EXHAUSTED)
00634 {
00635 ROS_DEBUG("Zeroconf: browser event occured [cache exhausted]");
00636 }
00637 else
00638 {
00639 ROS_DEBUG("Zeroconf: browser event occured [all for now]");
00640 }
00641 break;
00642 }
00643 }
00644 }
00676 void Zeroconf::resolve_callback(AvahiServiceResolver *resolver, AvahiIfIndex interface, AvahiProtocol protocol,
00677 AvahiResolverEvent event, const char *name, const char *type, const char *domain,
00678 const char *host_name, const AvahiAddress *address, uint16_t port, AvahiStringList *txt,
00679 AvahiLookupResultFlags flags, void* userdata)
00680 {
00681
00682 Zeroconf *zeroconf = reinterpret_cast<Zeroconf*>(userdata);
00683 assert(resolver);
00684
00685 switch (event)
00686 {
00687 case AVAHI_RESOLVER_FAILURE:
00688 {
00689 zeroconf_msgs::DiscoveredService service;
00690 service.name = name;
00691 service.type = type;
00692 service.domain = domain;
00693 {
00694 boost::mutex::scoped_lock lock(zeroconf->service_mutex);
00695 discovered_service_set::iterator iter = zeroconf->find_discovered_service(service);
00696 if (iter != zeroconf->discovered_services.end())
00697 {
00698
00699
00700
00701 if ((*iter)->service.ipv4_addresses.size() != 0)
00702 {
00703 ROS_WARN_STREAM(
00704 "Zeroconf: timed out resolving service [" << name << "][" << type << "][" << domain << "][" << interface << "][" << zeroconf->avahi_to_txt_protocol(protocol) << "][" << (*iter)->service.ipv4_addresses[0] << ":" << (*iter)->service.port << "]");
00705 }
00706 else if ((*iter)->service.ipv6_addresses.size() != 0)
00707 {
00708 ROS_WARN_STREAM(
00709 "Zeroconf: timed out resolving service [" << name << "][" << type << "][" << domain << "][" << interface << "][" << zeroconf->avahi_to_txt_protocol(protocol) << "][" << (*iter)->service.ipv6_addresses[0] << ":" << (*iter)->service.port << "]");
00710 }
00711 else
00712 {
00713 ROS_WARN_STREAM(
00714 "Zeroconf: timed out resolving service [" << name << "][" << type << "][" << domain << "][" << interface << "][" << zeroconf->avahi_to_txt_protocol(protocol) << "]");
00715 }
00716
00717
00718
00719 (*iter)->service.ipv4_addresses.clear();
00720 (*iter)->service.ipv6_addresses.clear();
00721 (*iter)->service.hostname = "";
00722 (*iter)->service.port = 0;
00723
00724
00725
00726
00727 if (zeroconf->lost_connection_signal)
00728 {
00729 zeroconf->lost_connection_signal(service);
00730 }
00731 }
00732 else
00733 {
00734 ROS_ERROR_STREAM(
00735 "Zeroconf: timed out resolving a service that was not saved, probably a zeroconf_avahi bug!");
00736 }
00737 }
00738 break;
00739 }
00740 case AVAHI_RESOLVER_FOUND:
00741 {
00742 char a[AVAHI_ADDRESS_STR_MAX], *t;
00743
00744
00745 boost::this_thread::sleep(boost::posix_time::milliseconds(500));
00746
00747 t = avahi_string_list_to_string(txt);
00748 avahi_address_snprint(a, sizeof(a), address);
00749
00750 zeroconf_msgs::DiscoveredService service;
00751 service.name = name;
00752 service.type = type;
00753 service.domain = domain;
00754 bool error = false;
00755 switch (zeroconf->avahi_to_ros_protocol(protocol))
00756 {
00757 case (zeroconf_msgs::Protocols::IPV4):
00758 {
00759 service.ipv4_addresses.push_back(a);
00760
00761 size_t found = std::string(a).find(":");
00762 if (found != std::string::npos)
00763 {
00764 ROS_WARN_STREAM(
00765 "Zeroconf: avahi is behaving badly (bug) - set an ipv6 address for an ipv4 service, recovering...");
00766 avahi_free(t);
00767 error = true;
00768 break;
00769 }
00770 break;
00771 }
00772 case (zeroconf_msgs::Protocols::IPV6):
00773 {
00774 service.ipv6_addresses.push_back(a);
00775 break;
00776 }
00777 default:
00778 break;
00779 }
00780 if (error)
00781 {
00782 break;
00783 }
00784
00785 service.hostname = host_name;
00786 service.port = port;
00787 service.description = t;
00788 service.cookie = avahi_string_list_get_service_cookie(txt);
00789 service.is_local = ((flags & AVAHI_LOOKUP_RESULT_LOCAL) == 0 ? false : true);
00790 service.our_own = ((flags & AVAHI_LOOKUP_RESULT_OUR_OWN) == 0 ? false : true);
00791 service.wide_area = ((flags & AVAHI_LOOKUP_RESULT_WIDE_AREA) == 0 ? false : true);
00792 service.multicast = ((flags & AVAHI_LOOKUP_RESULT_MULTICAST) == 0 ? false : true);
00793 service.cached = ((flags & AVAHI_LOOKUP_RESULT_CACHED) == 0 ? false : true);
00794 {
00795 boost::mutex::scoped_lock lock(zeroconf->service_mutex);
00796 discovered_service_set::iterator iter = zeroconf->find_discovered_service(service);
00797 if (iter != zeroconf->discovered_services.end())
00798 {
00799
00800
00801
00802 (*iter)->service = service;
00803 (*iter)->protocol = zeroconf->avahi_to_ros_protocol(protocol);
00804
00805
00806
00807
00808 ROS_INFO_STREAM(
00809 "Zeroconf: resolved service [" << name << "][" << type << "][" << domain << "][" << interface << "][" << zeroconf->ros_to_txt_protocol((*iter)->protocol) << "][" << a << ":" << service.port << "]");
00810 ROS_DEBUG_STREAM("Zeroconf: \tname: " << service.name);
00811 ROS_DEBUG_STREAM("Zeroconf: \ttype: " << service.type);
00812 ROS_DEBUG_STREAM("Zeroconf: \tdomain: " << service.domain);
00813 ROS_DEBUG_STREAM("Zeroconf: \tinterface: " << interface);
00814 ROS_DEBUG_STREAM("Zeroconf: \tprotocol: " << zeroconf->ros_to_txt_protocol((*iter)->protocol));
00815 ROS_DEBUG_STREAM("Zeroconf: \thostname: " << service.hostname);
00816 ROS_DEBUG_STREAM("Zeroconf: \taddress: " << a);
00817 ROS_DEBUG_STREAM("Zeroconf: \tport: " << service.port);
00818 ROS_DEBUG_STREAM("Zeroconf: \tdescription: " << service.description);
00819 ROS_DEBUG_STREAM("Zeroconf: \tcookie: " << service.cookie);
00820 ROS_DEBUG_STREAM("Zeroconf: \tis_local: " << (service.is_local ? 1 : 0 ));
00821 ROS_DEBUG_STREAM("Zeroconf: \tour_own: " << (service.our_own ? 1 : 0 ));
00822 ROS_DEBUG_STREAM("Zeroconf: \twide_area: " << (service.wide_area ? 1 : 0 ));
00823 ROS_DEBUG_STREAM("Zeroconf: \tmulticast: " << (service.multicast ? 1 : 0 ));
00824
00825
00826
00827 if (zeroconf->new_connection_signal)
00828 {
00829 zeroconf->new_connection_signal(service);
00830 }
00831 }
00832 else
00833 {
00834 ROS_ERROR_STREAM(
00835 "Zeroconf: timed out resolving a service that was not saved, probably a zeroconf_avahi bug!");
00836 }
00837 }
00838
00839 avahi_free(t);
00840 break;
00841 }
00842 }
00843 }
00844
00845
00846
00847
00861 void Zeroconf::entry_group_callback(AvahiEntryGroup *g, AvahiEntryGroupState state, void *userdata)
00862 {
00863
00864 Zeroconf *zeroconf = static_cast<Zeroconf*>(userdata);
00865 switch (state)
00866 {
00867 case AVAHI_ENTRY_GROUP_ESTABLISHED:
00868 {
00869 PublishedService service;
00870 {
00871 boost::mutex::scoped_lock lock(zeroconf->service_mutex);
00872 service_bimap::left_const_iterator left = zeroconf->committed_services.left.find(g);
00873 if (left != zeroconf->committed_services.left.end())
00874 {
00875 service = left->second;
00876 }
00877 else
00878 {
00879 ROS_ERROR(
00880 "Zeroconf : should never reach here, please report a bug in zeroconf_avahi's entry_group_callback.");
00881 return;
00882 }
00883 zeroconf->established_services.insert(service_bimap::value_type(g, service));
00884 zeroconf->committed_services.left.erase(g);
00885 }
00886 ROS_INFO_STREAM(
00887 "Zeroconf: service successfully established [" << service.name << "][" << service.type << "][" << service.port << "]");
00888 break;
00889 }
00890 case AVAHI_ENTRY_GROUP_COLLISION:
00891 {
00892
00893 PublishedService service;
00894 {
00895 boost::mutex::scoped_lock lock(zeroconf->service_mutex);
00896 service_bimap::left_const_iterator left = zeroconf->committed_services.left.find(g);
00897 if (left != zeroconf->committed_services.left.end())
00898 {
00899 service = left->second;
00900 }
00901 else
00902 {
00903 ROS_ERROR(
00904 "Zeroconf : should never reach here, please report a bug in zeroconf_avahi's entry_group_callback.");
00905 return;
00906 }
00907 zeroconf->committed_services.left.erase(g);
00908 }
00909 std::string alternative_name = avahi_alternative_service_name(service.name.c_str());
00910 ROS_INFO_STREAM(
00911 "Zeroconf: service name collision, renaming service [" << service.name << "]" << "][" << alternative_name << "]");
00912 service.name = alternative_name;
00913 avahi_entry_group_free(g);
00914
00915 zeroconf->add_service_non_threaded(service);
00916 break;
00917 }
00918
00919 case AVAHI_ENTRY_GROUP_FAILURE:
00920
00921
00922 ROS_DEBUG_STREAM(
00923 "Zeroconf: group state changed, system failure when trying to register service [" << avahi_strerror(avahi_client_errno(avahi_entry_group_get_client(g))) << "]");
00924 avahi_entry_group_free(g);
00925 zeroconf->fail();
00926 break;
00927
00928 case AVAHI_ENTRY_GROUP_UNCOMMITED:
00929 {
00930 ROS_DEBUG_STREAM("Zeroconf: group state changed, service uncommitted");
00931
00932 break;
00933 }
00934 case AVAHI_ENTRY_GROUP_REGISTERING:
00935 {
00936
00937 PublishedService service;
00938 {
00939 boost::mutex::scoped_lock lock(zeroconf->service_mutex);
00940 service_bimap::left_const_iterator left = zeroconf->committed_services.left.find(g);
00941 if (left != zeroconf->committed_services.left.end())
00942 {
00943 service = left->second;
00944 }
00945 else
00946 {
00947 ROS_ERROR(
00948 "Zeroconf : should never reach here, please report a bug in zeroconf_avahi's entry_group_callback.");
00949 return;
00950 }
00951 }
00952 ROS_DEBUG_STREAM(
00953 "Zeroconf: group state changed, service registering [" << service.name << "][" << service.type << "]");
00954 break;
00955 }
00956 default:
00957 {
00958 ROS_DEBUG_STREAM("Zeroconf: group state changed, ended in an unknown state [" << state << "]");
00959 break;
00960 }
00961 }
00962 }
00963
00964
00965
00966
00976 void Zeroconf::client_callback(AvahiClient *c, AvahiClientState state, void *userdata)
00977 {
00978
00979 Zeroconf *zeroconf = static_cast<Zeroconf*>(userdata);
00980 assert(c);
00981
00982
00983
00984 switch (state)
00985 {
00986 case AVAHI_CLIENT_S_RUNNING:
00987 {
00988
00989
00990 ROS_DEBUG("Zeroconf: avahi client up and running.");
00991 zeroconf->spin();
00992 break;
00993 }
00994 case AVAHI_CLIENT_FAILURE:
00995 {
00996 ROS_ERROR_STREAM("Zeroconf: avahi client failure [" << avahi_strerror(avahi_client_errno(c)) << "]");
00997 zeroconf->fail();
00998
00999 break;
01000 }
01001 case AVAHI_CLIENT_S_COLLISION:
01002 {
01003 ROS_DEBUG("Zeroconf: avahi client collision.");
01004
01005
01006
01007 break;
01008 }
01009 case AVAHI_CLIENT_S_REGISTERING:
01010 {
01011 ROS_DEBUG("Zeroconf: avahi client registering.");
01012
01013
01014
01015
01016
01017
01018
01019
01020
01021 break;
01022 }
01023 case AVAHI_CLIENT_CONNECTING:
01024 {
01025 ROS_DEBUG("Zeroconf: avahi client registering.");
01026 break;
01027 }
01028 }
01029 }
01030
01031 }