LCOV - code coverage report
Current view: top level - lunchbox - servus.cpp (source / functions) Hit Total Coverage
Test: lcov2.info Lines: 66 128 51.6 %
Date: 2014-10-01 Functions: 22 36 61.1 %

          Line data    Source code
       1             : 
       2             : /* Copyright (c) 2012-2014, Stefan Eilemann <eile@eyescale.ch>
       3             :  *
       4             :  * This file is part of Lunchbox <https://github.com/Eyescale/Lunchbox>
       5             :  *
       6             :  * This library is free software; you can redistribute it and/or modify it under
       7             :  * the terms of the GNU Lesser General Public License version 2.1 as published
       8             :  * by the Free Software Foundation.
       9             :  *
      10             :  * This library is distributed in the hope that it will be useful, but WITHOUT
      11             :  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
      12             :  * FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
      13             :  * details.
      14             :  *
      15             :  * You should have received a copy of the GNU Lesser General Public License
      16             :  * along with this library; if not, write to the Free Software Foundation, Inc.,
      17             :  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
      18             :  */
      19             : 
      20             : #include "servus.h"
      21             : #include "debug.h"
      22             : 
      23             : namespace lunchbox
      24             : {
      25             : #define ANNOUNCE_TIMEOUT 1000 /*ms*/
      26             : 
      27             : namespace detail
      28             : {
      29          30 : static const std::string empty_;
      30             : typedef std::map< std::string, std::string > ValueMap;
      31             : typedef std::map< std::string, ValueMap > InstanceMap;
      32             : typedef ValueMap::const_iterator ValueMapCIter;
      33             : typedef InstanceMap::const_iterator InstanceMapCIter;
      34             : 
      35             : class Servus
      36             : {
      37             : public:
      38           3 :     Servus() {}
      39           3 :     virtual ~Servus() {}
      40             : 
      41           2 :     void set( const std::string& key, const std::string& value )
      42             :     {
      43           2 :         _data[ key ] = value;
      44           2 :         _updateRecord();
      45           2 :     }
      46             : 
      47           3 :     Strings getKeys() const
      48             :     {
      49           3 :         Strings keys;
      50           9 :         for( ValueMapCIter i = _data.begin(); i != _data.end(); ++i )
      51           6 :             keys.push_back( i->first );
      52           3 :         return keys;
      53             :     }
      54             : 
      55           0 :     const std::string& get( const std::string& key ) const
      56             :     {
      57           0 :         ValueMapCIter i = _data.find( key );
      58           0 :         if( i != _data.end( ))
      59           0 :             return i->second;
      60           0 :         return empty_;
      61             :     }
      62             : 
      63             :     virtual lunchbox::Servus::Result announce( const unsigned short port,
      64             :                                                const std::string& instance ) =0;
      65             :     virtual void withdraw() = 0;
      66             :     virtual bool isAnnounced() const = 0;
      67             : 
      68             :     virtual lunchbox::Servus::Result beginBrowsing(
      69             :         const lunchbox::Servus::Interface interface_ ) = 0;
      70             :     virtual lunchbox::Servus::Result browse( const int32_t timeout ) = 0;
      71             : 
      72             :     virtual void endBrowsing() = 0;
      73             :     virtual bool isBrowsing() const = 0;
      74             :     virtual Strings discover( const lunchbox::Servus::Interface interface_,
      75             :                               const unsigned browseTime ) = 0;
      76             : 
      77           6 :     Strings getInstances() const
      78             :     {
      79           6 :         Strings instances;
      80          39 :         for( InstanceMapCIter i = _instanceMap.begin();
      81          26 :              i != _instanceMap.end(); ++i )
      82             :         {
      83           7 :             instances.push_back( i->first );
      84             :         }
      85           6 :         return instances;
      86             :     }
      87             : 
      88           0 :     Strings getKeys( const std::string& instance ) const
      89             :     {
      90           0 :         Strings keys;
      91           0 :         InstanceMapCIter i = _instanceMap.find( instance );
      92           0 :         if( i == _instanceMap.end( ))
      93           0 :             return keys;
      94             : 
      95           0 :         const ValueMap& values = i->second;
      96           0 :         for( ValueMapCIter j = values.begin(); j != values.end(); ++j )
      97           0 :             keys.push_back( j->first );
      98           0 :         return keys;
      99             :     }
     100             : 
     101           0 :     bool containsKey( const std::string& instance, const std::string& key )
     102             :         const
     103             :     {
     104           0 :         InstanceMapCIter i = _instanceMap.find( instance );
     105           0 :         if( i == _instanceMap.end( ))
     106           0 :             return false;
     107             : 
     108           0 :         const ValueMap& values = i->second;
     109           0 :         ValueMapCIter j = values.find( key );
     110           0 :         if( j == values.end( ))
     111           0 :             return false;
     112           0 :         return true;
     113             :     }
     114             : 
     115           4 :     const std::string& get( const std::string& instance,
     116             :                             const std::string& key ) const
     117             :     {
     118           4 :         InstanceMapCIter i = _instanceMap.find( instance );
     119           4 :         if( i == _instanceMap.end( ))
     120           0 :             return detail::empty_;
     121             : 
     122           4 :         const ValueMap& values = i->second;
     123           4 :         ValueMapCIter j = values.find( key );
     124           4 :         if( j == values.end( ))
     125           0 :             return detail::empty_;
     126           4 :         return j->second;
     127             :     }
     128             : 
     129           0 :     void getData( lunchbox::Servus::Data& data ) const
     130             :     {
     131           0 :         data = _instanceMap;
     132           0 :     }
     133             : 
     134             : protected:
     135             :     InstanceMap _instanceMap; //!< last discovered data
     136             :     ValueMap _data;   //!< self data to announce
     137             : 
     138             :     virtual void _updateRecord() = 0;
     139             : };
     140             : 
     141             : }
     142             : }
     143             : 
     144             : // Impls need detail interface definition above
     145             : #ifdef LUNCHBOX_USE_DNSSD
     146             : #  include "dnssd/servus.h"
     147             : #elif defined(LUNCHBOX_USE_AVAHI_CLIENT)
     148             : #  include "avahi/servus.h"
     149             : #endif
     150             : #include "none/servus.h"
     151             : 
     152             : // http://stackoverflow.com/questions/14430906/multi-threaded-avahi-resolving-causes-segfault
     153             : #include "lock.h"
     154             : #include "scopedMutex.h"
     155             : #ifdef __APPLE__
     156             : static lunchbox::Lock* lock_( 0 );
     157             : #else
     158          30 : static lunchbox::Lock lock_;
     159             : #endif
     160             : 
     161             : namespace lunchbox
     162             : {
     163           1 : bool Servus::isAvailable()
     164             : {
     165             : #if defined(LUNCHBOX_USE_DNSSD) || defined(LUNCHBOX_USE_AVAHI_CLIENT)
     166           1 :     return true;
     167             : #endif
     168             :     return false;
     169             : }
     170             : 
     171           3 : Servus::Servus( const std::string& name LB_UNUSED )
     172             : #ifdef LUNCHBOX_USE_DNSSD
     173             :     : _impl( new dnssd::Servus( name ))
     174             : #elif defined(LUNCHBOX_USE_AVAHI_CLIENT)
     175           3 :     : _impl( new avahi::Servus( name ))
     176             : #else
     177             :     : _impl( new none::Servus( ))
     178             : #endif
     179           3 : {}
     180             : 
     181           3 : Servus::~Servus()
     182             : {
     183           3 :     delete _impl;
     184           3 : }
     185             : 
     186           0 : std::string Servus::Result::getString() const
     187             : {
     188           0 :     const int32_t code = getCode();
     189           0 :     switch( code )
     190             :     {
     191             : #ifdef LUNCHBOX_USE_DNSSD
     192             :     case kDNSServiceErr_Unknown:           return "unknown error";
     193             :     case kDNSServiceErr_NoSuchName:        return "name not found";
     194             :     case kDNSServiceErr_NoMemory:          return "out of memory";
     195             :     case kDNSServiceErr_BadParam:          return "bad parameter";
     196             :     case kDNSServiceErr_BadReference:      return "bad reference";
     197             :     case kDNSServiceErr_BadState:          return "bad state";
     198             :     case kDNSServiceErr_BadFlags:          return "bad flags";
     199             :     case kDNSServiceErr_Unsupported:       return "unsupported";
     200             :     case kDNSServiceErr_NotInitialized:    return "not initialized";
     201             :     case kDNSServiceErr_AlreadyRegistered: return "already registered";
     202             :     case kDNSServiceErr_NameConflict:      return "name conflict";
     203             :     case kDNSServiceErr_Invalid:           return "invalid value";
     204             :     case kDNSServiceErr_Firewall:          return "firewall";
     205             :     case kDNSServiceErr_Incompatible:
     206             :         return "client library incompatible with daemon";
     207             :     case kDNSServiceErr_BadInterfaceIndex: return "bad interface index";
     208             :     case kDNSServiceErr_Refused:           return "refused";
     209             :     case kDNSServiceErr_NoSuchRecord:      return "no such record";
     210             :     case kDNSServiceErr_NoAuth:            return "no authentication";
     211             :     case kDNSServiceErr_NoSuchKey:         return "no such key";
     212             :     case kDNSServiceErr_NATTraversal:      return "NAT traversal";
     213             :     case kDNSServiceErr_DoubleNAT:         return "double NAT";
     214             :     case kDNSServiceErr_BadTime:           return "bad time";
     215             : #endif
     216             : 
     217           0 :     case PENDING:          return "operation pending";
     218           0 :     case NOT_SUPPORTED:    return "Lunchbox compiled without ZeroConf support";
     219           0 :     case POLL_ERROR:       return "Error polling for events";
     220             :     default:
     221           0 :         if( code > 0 )
     222           0 :             return ::strerror( code );
     223           0 :         return lunchbox::Result::getString();
     224             :     }
     225             : }
     226             : 
     227           2 : void Servus::set( const std::string& key, const std::string& value )
     228             : {
     229           2 :     _impl->set( key, value );
     230           2 : }
     231             : 
     232           3 : Strings Servus::getKeys() const
     233             : {
     234           3 :     return _impl->getKeys();
     235             : }
     236             : 
     237           0 : const std::string& Servus::get( const std::string& key ) const
     238             : {
     239           0 :     return _impl->get( key );
     240             : }
     241             : 
     242           3 : Servus::Result Servus::announce( const unsigned short port,
     243             :                                  const std::string& instance )
     244             : {
     245           3 :     ScopedWrite mutex( lock_ );
     246           3 :     return _impl->announce( port, instance );
     247             : }
     248             : 
     249           1 : void Servus::withdraw()
     250             : {
     251           1 :     ScopedWrite mutex( lock_ );
     252           1 :     _impl->withdraw();
     253           1 : }
     254             : 
     255           0 : bool Servus::isAnnounced() const
     256             : {
     257           0 :     return _impl->isAnnounced();
     258             : }
     259             : 
     260           2 : Strings Servus::discover( const Interface addr, const unsigned browseTime )
     261             : {
     262           2 :     ScopedWrite mutex( lock_ );
     263           2 :     return _impl->discover( addr, browseTime );
     264             : }
     265             : 
     266           2 : Servus::Result Servus::beginBrowsing( const lunchbox::Servus::Interface addr )
     267             : {
     268           2 :     ScopedWrite mutex( lock_ );
     269           2 :     return _impl->beginBrowsing( addr );
     270             : }
     271             : 
     272           3 : Servus::Result Servus::browse( int32_t timeout )
     273             : {
     274           3 :     ScopedWrite mutex( lock_ );
     275           3 :     return _impl->browse( timeout );
     276             : }
     277             : 
     278           1 : void Servus::endBrowsing()
     279             : {
     280           1 :     ScopedWrite mutex( lock_ );
     281           1 :     _impl->endBrowsing();
     282           1 : }
     283             : 
     284           5 : bool Servus::isBrowsing() const
     285             : {
     286           5 :     return _impl->isBrowsing();
     287             : }
     288             : 
     289           4 : Strings Servus::getInstances() const
     290             : {
     291           4 :     return _impl->getInstances();
     292             : }
     293             : 
     294           0 : Strings Servus::getKeys( const std::string& instance ) const
     295             : {
     296           0 :     return _impl->getKeys( instance );
     297             : }
     298             : 
     299           0 : bool Servus::containsKey( const std::string& instance,
     300             :                           const std::string& key ) const
     301             : {
     302           0 :     return _impl->containsKey( instance, key );
     303             : }
     304             : 
     305           4 : const std::string& Servus::get( const std::string& instance,
     306             :                                 const std::string& key ) const
     307             : {
     308           4 :     return _impl->get( instance, key );
     309             : }
     310             : 
     311           0 : void Servus::getData( Data& data )
     312             : {
     313           0 :     _impl->getData( data );
     314           0 : }
     315             : 
     316           0 : std::ostream& operator << ( std::ostream& os, const Servus& servus )
     317             : {
     318           0 :     os << disableFlush << disableHeader << "Servus instance"
     319           0 :        << (servus.isAnnounced() ? " " : " not ") << "announced"
     320           0 :        << (servus.isBrowsing() ? " " : " not ") << "browsing, implementation"
     321           0 :        << className( servus._impl ) << indent;
     322             : 
     323           0 :     const Strings& keys = servus.getKeys();
     324           0 :     for( StringsCIter i = keys.begin(); i != keys.end(); ++i )
     325           0 :         os << std::endl << *i << " = " << servus.get( *i );
     326             : 
     327           0 :     return os << exdent << enableHeader << enableFlush;
     328             : }
     329             : 
     330           0 : std::ostream& operator << ( std::ostream& os , const Servus::Interface& addr )
     331             : {
     332           0 :     switch( addr )
     333             :     {
     334           0 :     case Servus::IF_ALL: return os << " all ";
     335           0 :     case Servus::IF_LOCAL: return os << " local ";
     336             :     }
     337           0 :     return os;
     338             : }
     339             : 
     340          90 : }

Generated by: LCOV version 1.10