zeroconf.hpp
Go to the documentation of this file.
00001 
00009 /*****************************************************************************
00010  ** Includes
00011  *****************************************************************************/
00012 
00013 #include <set>
00014 #include <string>
00015 
00016 #include <avahi-client/publish.h>
00017 #include <avahi-client/client.h>
00018 #include <avahi-client/lookup.h>
00019 #include <avahi-common/malloc.h>
00020 #include <avahi-common/error.h>
00021 #include <avahi-common/thread-watch.h>
00022 
00023 #include <boost/thread/mutex.hpp>
00024 #include <boost/bimap/bimap.hpp>
00025 #include <boost/function.hpp>
00026 #include <boost/shared_ptr.hpp>
00027 
00028 #include <zeroconf_msgs/PublishedService.h>
00029 #include <zeroconf_msgs/DiscoveredService.h>
00030 
00031 /*****************************************************************************
00032  ** Namespaces
00033  *****************************************************************************/
00034 
00035 namespace zeroconf_avahi
00036 {
00037 
00038 /*****************************************************************************
00039  ** Utilities
00040  *****************************************************************************/
00050 struct PublishedServiceCompare
00051 {
00052   bool operator()(const zeroconf_msgs::PublishedService &a, const zeroconf_msgs::PublishedService &b) const
00053   {
00054     if (a.name != b.name)
00055     {
00056       return a.name < b.name;
00057     }
00058     else if (a.type != b.type)
00059     {
00060       return a.type < b.type;
00061     }
00062     else
00063     {
00064       return a.port < b.port;
00065     }
00066   }
00067 };
00068 
00078 class DiscoveredAvahiService
00079 {
00080 public:
00081   DiscoveredAvahiService() :
00082       resolver(NULL)
00083   {
00084   }
00085   DiscoveredAvahiService(zeroconf_msgs::DiscoveredService &discovered_service, AvahiServiceResolver *new_resolver,
00086                          int protocol, int hardware_interface) :
00087       service(discovered_service), protocol(protocol), hardware_interface(hardware_interface), resolver(new_resolver)
00088   {
00089 
00090   }
00091   ~DiscoveredAvahiService()
00092   {
00093     if (resolver)
00094     {
00095       avahi_service_resolver_free(resolver);
00096     }
00097   }
00098   zeroconf_msgs::DiscoveredService service;
00099   int protocol;
00100   int hardware_interface;
00101   AvahiServiceResolver *resolver;
00102 };
00103 
00110 struct DiscoveredAvahiServiceCompare
00111 {
00112   bool operator()(const boost::shared_ptr<DiscoveredAvahiService> avahi_service_a,
00113                   const boost::shared_ptr<DiscoveredAvahiService> avahi_service_b) const
00114   {
00115     const zeroconf_msgs::DiscoveredService &a = avahi_service_a->service;
00116     const zeroconf_msgs::DiscoveredService &b = avahi_service_b->service;
00117     if (a.name != b.name)
00118     {
00119       return a.name < b.name;
00120     }
00121     else if (a.type != b.type)
00122     {
00123       return a.type < b.type;
00124     }
00125     else if (a.domain != b.domain)
00126     {
00127       return a.domain < b.domain;
00128     }
00129     else if (avahi_service_a->hardware_interface != avahi_service_b->hardware_interface)
00130     {
00131       return avahi_service_a->hardware_interface < avahi_service_b->hardware_interface;
00132     }
00133     else
00134     {
00135       return avahi_service_a->protocol < avahi_service_b->protocol;
00136     }
00137   }
00138 };
00139 
00140 /*****************************************************************************
00141  ** Interfaces
00142  *****************************************************************************/
00162 class Zeroconf
00163 {
00164 private:
00165   typedef zeroconf_msgs::PublishedService PublishedService;
00166   typedef boost::bimaps::bimap<AvahiEntryGroup*, boost::bimaps::set_of<PublishedService, PublishedServiceCompare> > service_bimap;
00167   typedef boost::bimaps::bimap<AvahiServiceBrowser*, boost::bimaps::set_of<std::string> > discovery_bimap;
00168   typedef std::set<boost::shared_ptr<DiscoveredAvahiService>, DiscoveredAvahiServiceCompare> discovered_service_set;
00169   typedef std::pair<AvahiEntryGroup*, PublishedService> service_map_pair;
00170   typedef boost::function<void(zeroconf_msgs::DiscoveredService)> connection_signal_cb;
00171 
00172 public:
00173   Zeroconf();
00174   ~Zeroconf();
00175   bool add_service(PublishedService &service);
00176   bool remove_service(const PublishedService &service);
00177   // Todo : would be useful to be able to remove services in various other ways
00178   // bool remove_services_by_name(const std::string& service_name);
00179   // bool remove_services_by_type(const std::string& service_type);
00180   // bool remove_services() <-- remove *all* services
00181   bool add_listener(std::string &service_type);
00182   bool remove_listener(const std::string &service_type);
00183   void list_discovered_services(const std::string &service_type, std::vector<zeroconf_msgs::DiscoveredService> &list);
00184   void list_published_services(const std::string &service_type, std::vector<zeroconf_msgs::PublishedService> &list);
00185 
00186   void connect_signal_callbacks(connection_signal_cb new_connections, connection_signal_cb lost_connections)
00187   {
00188     new_connection_signal = new_connections;
00189     lost_connection_signal = lost_connections;
00190   }
00191 
00192   void spin();
00193 
00194 private:
00195   bool invalid_object;
00196   AvahiThreadedPoll *threaded_poll;
00197   AvahiClient *client;
00198   service_bimap committed_services;
00199   service_bimap established_services;
00200   discovery_bimap discovery_service_types;
00201   discovered_service_set discovered_services;
00202   boost::mutex service_mutex;
00203   const int interface;
00204   const int permitted_protocols;
00205   connection_signal_cb new_connection_signal, lost_connection_signal;
00206 
00207   /*********************
00208    ** Utilitiies
00209    **********************/
00210   int ros_to_avahi_protocol(const int &protocol);
00211   std::string ros_to_txt_protocol(const int &protocol);
00212   int avahi_to_ros_protocol(const int &protocol);
00213   std::string avahi_to_txt_protocol(const int &protocol);
00214   discovered_service_set::iterator find_discovered_service(zeroconf_msgs::DiscoveredService &service);
00215 
00216   /*********************
00217    ** Mechanics
00218    **********************/
00219   bool add_service_non_threaded(PublishedService &service);
00220   void fail()
00221   {
00222     avahi_threaded_poll_quit(threaded_poll);
00223     invalid_object = true;
00224   }
00225 
00226   /*********************
00227    ** Callbacks
00228    **********************/
00229   static void entry_group_callback(AvahiEntryGroup *g, AvahiEntryGroupState state, void *userdata);
00230   static void client_callback(AvahiClient *c, AvahiClientState state, void * userdata);
00231   static void discovery_callback(AvahiServiceBrowser *b, AvahiIfIndex interface, AvahiProtocol protocol,
00232                                  AvahiBrowserEvent event, const char *name, const char *type, const char *domain,
00233                                  AvahiLookupResultFlags flags, void* userdata);
00234   static void resolve_callback(AvahiServiceResolver *r, AvahiIfIndex interface, AvahiProtocol protocol,
00235                                AvahiResolverEvent event, const char *name, const char *type, const char *domain,
00236                                const char *host_name, const AvahiAddress *address, uint16_t port, AvahiStringList *txt,
00237                                AvahiLookupResultFlags flags, void* userdata);
00238   static void modify_callback(AVAHI_GCC_UNUSED AvahiTimeout *e, void *userdata);
00239 };
00240 
00241 } // namespace zeroconf_avahi


zeroconf_avahi
Author(s): Daniel Stonier
autogenerated on Mon Oct 6 2014 09:12:37