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