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