LCOV - code coverage report
Current view: top level - lunchbox - servus.cpp (source / functions) Hit Total Coverage
Test: lcov2.info Lines: 173 277 62.5 %
Date: 2014-08-05 Functions: 28 42 66.7 %

          Line data    Source code
       1             : 
       2             : /* Copyright (c) 2012, 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             : 
      22             : #include "debug.h"
      23             : 
      24             : #ifdef LUNCHBOX_USE_DNSSD
      25             : #  ifdef _MSC_VER
      26             : #    define SERVUS_BONJOUR
      27             : #    include "os.h"
      28             : #  else
      29             : #    include <arpa/inet.h>
      30             : #    include <sys/time.h>
      31             : #    include <unistd.h>
      32             : #  endif
      33             : #  ifdef __APPLE__
      34             : #    define SERVUS_BONJOUR
      35             : #  endif
      36             : #  ifndef SERVUS_BONJOUR
      37             : #    define SERVUS_AVAHI
      38             : #    include "lock.h"
      39             : #    include "scopedMutex.h"
      40             : #  endif
      41             : #  include <dns_sd.h>
      42             : #endif
      43             : 
      44             : #include <algorithm>
      45             : #include <cassert>
      46             : #include <cerrno>
      47             : #include <cstdio>
      48             : #include <cstdlib>
      49             : #include <cstring>
      50             : #include <iostream>
      51             : #include <sstream>
      52             : 
      53             : namespace lunchbox
      54             : {
      55             : typedef std::map< std::string, std::string > ValueMap;
      56             : typedef std::map< std::string, ValueMap > InstanceMap;
      57             : typedef ValueMap::const_iterator ValueMapCIter;
      58             : typedef InstanceMap::const_iterator InstanceMapCIter;
      59          29 : static const std::string empty_;
      60             : 
      61             : #ifdef SERVUS_AVAHI
      62          29 : static Lock lock_;
      63             : #endif
      64             : 
      65             : #define ANNOUNCE_TIMEOUT 1000 /*ms*/
      66             : 
      67             : namespace detail
      68             : {
      69             : class Servus
      70             : {
      71             : public:
      72             : #ifdef LUNCHBOX_USE_DNSSD
      73           1 :     explicit Servus( const std::string& name )
      74             :         : name_( name )
      75             :         , service_( 0 )
      76           1 :         , result_( lunchbox::Servus::Result::PENDING )
      77           1 :     {}
      78             : #else
      79             :     explicit Servus( const std::string& ) {}
      80             : #endif
      81             : 
      82           1 :     ~Servus()
      83           1 :     {
      84             : #ifdef LUNCHBOX_USE_DNSSD
      85           1 :         withdraw();
      86             : #endif
      87           1 :     }
      88             : 
      89             : #ifdef LUNCHBOX_USE_DNSSD
      90           2 :     void set( const std::string& key, const std::string& value )
      91             :     {
      92           2 :         data_[ key ] = value;
      93           2 :         updateRecord_();
      94           2 :     }
      95             : #else
      96             :     void set( const std::string&, const std::string& ) {}
      97             : #endif
      98             : 
      99           1 :     Strings getKeys() const
     100             :     {
     101           1 :         Strings keys;
     102             : #ifdef LUNCHBOX_USE_DNSSD
     103           3 :         for( ValueMapCIter i = data_.begin(); i != data_.end(); ++i )
     104           2 :             keys.push_back( i->first );
     105             : #endif
     106           1 :         return keys;
     107             :     }
     108             : 
     109             : #ifdef LUNCHBOX_USE_DNSSD
     110           0 :     const std::string& get( const std::string& key ) const
     111             :     {
     112           0 :         ValueMapCIter i = data_.find( key );
     113           0 :         if( i != data_.end( ))
     114           0 :             return i->second;
     115           0 :         return empty_;
     116             :     }
     117             : #else
     118             :     const std::string& get( const std::string& ) const
     119             :     {
     120             :         return empty_;
     121             :     }
     122             : #endif
     123             : 
     124             : #ifdef LUNCHBOX_USE_DNSSD
     125           2 :     lunchbox::Servus::Result announce( const unsigned short port,
     126             :                                       const std::string& instance )
     127             :     {
     128           2 :         if( service_ )
     129           0 :             return lunchbox::Servus::Result( kDNSServiceErr_NotInitialized );
     130             : 
     131             :         TXTRecordRef record;
     132           2 :         createTXTRecord_( record );
     133             : 
     134             :         const lunchbox::Servus::Result result(
     135             :             DNSServiceRegister( &service_, 0 /* flags */,
     136             :                                 0 /* all interfaces */,
     137           2 :                                 instance.empty() ? 0 : instance.c_str(),
     138             :                                 name_.c_str(), 0 /* default domains */,
     139           2 :                                 0 /* hostname */, htons( port ),
     140           2 :                                 TXTRecordGetLength( &record ),
     141             :                                 TXTRecordGetBytesPtr( &record ),
     142             :                                 (DNSServiceRegisterReply)registerCBS_,
     143           8 :                                 this ));
     144           2 :         TXTRecordDeallocate( &record );
     145             : 
     146           2 :         if( result )
     147           2 :             return handleEvents_( service_, ANNOUNCE_TIMEOUT );
     148             : 
     149           0 :         LBWARN << "DNSServiceRegister returned: " << result << std::endl;
     150           0 :         return result;
     151             :     }
     152             : #else
     153             :     lunchbox::Servus::Result announce( const unsigned short, const std::string&)
     154             :     {
     155             :         return lunchbox::Servus::Result( lunchbox::Servus::Result::NOT_SUPPORTED);
     156             :     }
     157             : #endif
     158             : 
     159           2 :     void withdraw()
     160             :     {
     161             : #ifdef LUNCHBOX_USE_DNSSD
     162           2 :         if( !service_ )
     163           2 :             return;
     164             : 
     165           2 :         DNSServiceRefDeallocate( service_ );
     166           2 :         service_ = 0;
     167             : #endif
     168             :     }
     169             : 
     170           0 :     bool isAnnounced() const
     171             :         {
     172             : #ifdef LUNCHBOX_USE_DNSSD
     173           0 :             return service_ != 0;
     174             : #endif
     175             :             return false;
     176             :         }
     177             : 
     178             : #ifdef LUNCHBOX_USE_DNSSD
     179           2 :     Strings discover( const lunchbox::Servus::Interface interface_,
     180             :                       const unsigned browseTime )
     181             :     {
     182           2 :         instanceMap_.clear();
     183             : 
     184             : #   ifdef SERVUS_BONJOUR
     185             :         const lunchbox::Servus::Interface addr = interface_;
     186             : #   endif
     187             : #   ifdef SERVUS_AVAHI // no kDNSServiceInterfaceIndexLocalOnly support in avahi
     188           2 :         const lunchbox::Servus::Interface addr = lunchbox::Servus::IF_ALL;
     189             : #   endif
     190             :         DNSServiceRef service;
     191             :         const DNSServiceErrorType error = DNSServiceBrowse( &service, 0,
     192             :                                                             addr,
     193             :                                                             name_.c_str(),
     194             :                                                             "",
     195             :                                      (DNSServiceBrowseReply)browseCBS_,
     196           2 :                                                             this );
     197           2 :         if( error != kDNSServiceErr_NoError )
     198             :         {
     199           0 :             LBWARN << "DNSServiceDiscovery error: " << error << std::endl;
     200           0 :             DNSServiceRefDeallocate( service );
     201           0 :             return getInstances();
     202             :         }
     203             : 
     204           2 :         handleEvents_( service, browseTime );
     205           2 :         DNSServiceRefDeallocate( service );
     206             : 
     207             : #   ifdef SERVUS_AVAHI // let's implement InterfaceIndexLocalOnly for avahi
     208           2 :         if( interface_ == lunchbox::Servus::IF_LOCAL )
     209             :         {
     210           2 :             Strings hosts;
     211           2 :             char hostname[256] = {0};
     212             : 
     213           2 :             gethostname( hostname, 256 );
     214             : 
     215           4 :             std::string name = hostname;
     216           2 :             const size_t dotPos = name.find( '.' );
     217           2 :             if( dotPos != std::string::npos )
     218           2 :                 name = name.substr( 0, dotPos );
     219             : 
     220           2 :             hosts.push_back( name );
     221           2 :             hosts.push_back( name + ".local." );
     222             : 
     223           4 :             InstanceMap localData;
     224          12 :             for( InstanceMapCIter i = instanceMap_.begin();
     225           8 :                  i != instanceMap_.end(); ++i )
     226             :             {
     227           2 :                 const ValueMap& values = i->second;
     228           2 :                 const ValueMapCIter j = values.find( "servus_host" );
     229           2 :                 const std::string& current = j->second;
     230           2 :                 if( std::find( hosts.begin(), hosts.end(), current ) !=
     231             :                     hosts.end( ))
     232             :                 {
     233           2 :                     localData[ i->first ] = i->second;
     234             :                 }
     235             :             }
     236           4 :             instanceMap_.swap( localData );
     237             :         }
     238             : #   endif
     239           2 :         return getInstances();
     240             :     }
     241             : #else
     242             :     Strings discover( const lunchbox::Servus::Interface, const unsigned )
     243             :     {
     244             :         return getInstances();
     245             :     }
     246             : #endif
     247             : 
     248           2 :     Strings getInstances() const
     249             :     {
     250           2 :         Strings instances;
     251             : #ifdef LUNCHBOX_USE_DNSSD
     252          12 :         for( InstanceMapCIter i = instanceMap_.begin();
     253           8 :              i != instanceMap_.end(); ++i )
     254             :         {
     255           2 :             instances.push_back( i->first );
     256             :         }
     257             : #endif
     258           2 :         return instances;
     259             :     }
     260             : 
     261             : #ifdef LUNCHBOX_USE_DNSSD
     262           0 :     Strings getKeys( const std::string& instance ) const
     263             :     {
     264           0 :         Strings keys;
     265           0 :         InstanceMapCIter i = instanceMap_.find( instance );
     266           0 :         if( i == instanceMap_.end( ))
     267           0 :             return keys;
     268             : 
     269           0 :         const ValueMap& values = i->second;
     270           0 :         for( ValueMapCIter j = values.begin(); j != values.end(); ++j )
     271           0 :             keys.push_back( j->first );
     272           0 :         return keys;
     273             :     }
     274             : #else
     275             :     Strings getKeys( const std::string& ) const
     276             :     {
     277             :         return Strings();
     278             :     }
     279             : #endif
     280             : 
     281             : #ifdef LUNCHBOX_USE_DNSSD
     282           0 :     bool containsKey( const std::string& instance,
     283             :                       const std::string& key ) const
     284             :     {
     285           0 :         InstanceMapCIter i = instanceMap_.find( instance );
     286           0 :         if( i == instanceMap_.end( ))
     287           0 :             return false;
     288             : 
     289           0 :         const ValueMap& values = i->second;
     290           0 :         ValueMapCIter j = values.find( key );
     291           0 :         if( j == values.end( ))
     292           0 :             return false;
     293           0 :         return true;
     294             :     }
     295             : #else
     296             :     bool containsKey( const std::string&, const std::string& ) const
     297             :     {
     298             :         return false;
     299             :     }
     300             : #endif
     301             : 
     302             : #ifdef LUNCHBOX_USE_DNSSD
     303           2 :     const std::string& get( const std::string& instance,
     304             :                             const std::string& key ) const
     305             :     {
     306           2 :         InstanceMapCIter i = instanceMap_.find( instance );
     307           2 :         if( i == instanceMap_.end( ))
     308           0 :             return empty_;
     309             : 
     310           2 :         const ValueMap& values = i->second;
     311           2 :         ValueMapCIter j = values.find( key );
     312           2 :         if( j == values.end( ))
     313           0 :             return empty_;
     314           2 :         return j->second;
     315             :     }
     316             : #else
     317             :     const std::string& get( const std::string&, const std::string& ) const
     318             :     {
     319             :         return empty_;
     320             :     }
     321             : #endif
     322             : 
     323             : #ifdef LUNCHBOX_USE_DNSSD
     324           0 :     void getData( lunchbox::Servus::Data& data )
     325             :     {
     326           0 :         data = instanceMap_;
     327           0 :     }
     328             : #else
     329             :     void getData( lunchbox::Servus::Data& ) {}
     330             : #endif
     331             : 
     332             : private:
     333             : #ifdef LUNCHBOX_USE_DNSSD
     334             :     const std::string name_;
     335             :     InstanceMap instanceMap_; //!< last discovered data
     336             :     ValueMap data_;   //!< self data to announce
     337             :     DNSServiceRef service_; //!< used for announce()
     338             :     int32_t result_;
     339             :     std::string browsedName_;
     340             : 
     341           2 :     void updateRecord_()
     342             :     {
     343           2 :         if( !service_ )
     344           3 :             return;
     345             : 
     346             :         TXTRecordRef record;
     347           1 :         createTXTRecord_( record );
     348             : 
     349             :         const DNSServiceErrorType error =
     350             :             DNSServiceUpdateRecord( service_, 0, 0,
     351           1 :                                     TXTRecordGetLength( &record ),
     352           2 :                                     TXTRecordGetBytesPtr( &record ), 0 );
     353           1 :         TXTRecordDeallocate( &record );
     354           1 :         if( error != kDNSServiceErr_NoError )
     355           0 :             LBWARN << "DNSServiceUpdateRecord error: " << error << std::endl;
     356             :     }
     357             : 
     358           3 :     void createTXTRecord_( TXTRecordRef& record )
     359             :     {
     360           3 :         TXTRecordCreate( &record, 0, 0 );
     361           6 :         for( ValueMapCIter i = data_.begin(); i != data_.end(); ++i )
     362             :         {
     363           3 :             const std::string& key = i->first;
     364           3 :             const std::string& value = i->second;
     365           3 :             const uint8_t valueSize = value.length() > 255 ?
     366           3 :                                           255 : uint8_t( value.length( ));
     367           3 :             TXTRecordSetValue( &record, key.c_str(), valueSize, value.c_str( ));
     368             :         }
     369           3 :     }
     370             : 
     371           8 :     lunchbox::Servus::Result handleEvents_( DNSServiceRef service,
     372             :                                             const int32_t timeout = -1 )
     373             :     {
     374           8 :         assert( service );
     375           8 :         if( !service )
     376           0 :             return lunchbox::Servus::Result( kDNSServiceErr_Unknown );
     377             : 
     378           8 :         const int fd = DNSServiceRefSockFD( service );
     379           8 :         const int nfds = fd + 1;
     380             : 
     381          55 :         while( result_ == lunchbox::Servus::Result::PENDING )
     382             :         {
     383             :             fd_set fdSet;
     384          41 :             FD_ZERO( &fdSet );
     385          41 :             FD_SET( fd, &fdSet );
     386             : 
     387             :             struct timeval tv;
     388          41 :             tv.tv_sec = timeout / 1000;
     389          41 :             tv.tv_usec = (timeout % 1000) * 1000;
     390             : 
     391             :             const int result = ::select( nfds, &fdSet, 0, 0,
     392          41 :                                          timeout < 0 ? 0 : &tv );
     393          41 :             switch( result )
     394             :             {
     395             :               case 0: // timeout
     396           4 :                 return lunchbox::Servus::Result( result_ );
     397             : 
     398             :               case -1: // error
     399           0 :                 LBWARN << "Select error: " << strerror( errno ) << " ("
     400           0 :                           << errno << ")" << std::endl;
     401           0 :                 if( errno != EINTR )
     402             :                 {
     403           0 :                     withdraw();
     404           0 :                     result_ = errno;
     405             :                 }
     406           0 :                 break;
     407             : 
     408             :               default:
     409          39 :                 if( FD_ISSET( fd, &fdSet ))
     410             :                 {
     411             :                     const DNSServiceErrorType error =
     412          39 :                         DNSServiceProcessResult( service );
     413             : 
     414          39 :                     if( error != kDNSServiceErr_NoError )
     415             :                     {
     416           0 :                         LBWARN << "DNSServiceProcessResult error: " << error
     417           0 :                                << std::endl;
     418           0 :                         withdraw();
     419           0 :                         result_ = error;
     420             :                     }
     421             :                 }
     422          39 :                 break;
     423             :             }
     424             :         }
     425             : 
     426           6 :         lunchbox::Servus::Result result( result_ );
     427           6 :         result_ = lunchbox::Servus::Result::PENDING; // reset for next operation
     428           6 :         return result;
     429             :     }
     430             : 
     431           2 :     static void registerCBS_( DNSServiceRef, DNSServiceFlags,
     432             :                               DNSServiceErrorType error, const char* name,
     433             :                               const char* type, const char* domain,
     434             :                               Servus* servus )
     435             :     {
     436           2 :         servus->registerCB_( name, type, domain, error );
     437           2 :     }
     438             : 
     439           2 :     void registerCB_( const char* name, const char* type, const char* domain,
     440             :                       DNSServiceErrorType error )
     441             :     {
     442           2 :         if( error == kDNSServiceErr_NoError)
     443           6 :             LBINFO << "Registered " << name << "." << type << "." << domain
     444           6 :                       << std::endl;
     445             :         else
     446             :         {
     447           0 :             LBWARN << "Register callback error: " << error << std::endl;
     448           0 :             withdraw();
     449             :         }
     450           2 :         result_ = error;
     451           2 :     }
     452             : 
     453           4 :     static void browseCBS_( DNSServiceRef, DNSServiceFlags flags,
     454             :                             uint32_t interfaceIdx, DNSServiceErrorType error,
     455             :                             const char* name, const char* type,
     456             :                             const char* domain, Servus* servus )
     457             :     {
     458           4 :         servus->browseCB_( flags, interfaceIdx, error, name, type, domain );
     459           4 :     }
     460             : 
     461           4 :     void browseCB_( DNSServiceFlags flags, uint32_t interfaceIdx,
     462             :                     DNSServiceErrorType error, const char* name,
     463             :                     const char* type, const char* domain )
     464             :     {
     465           4 :         if( error != kDNSServiceErr_NoError)
     466             :         {
     467           0 :             LBWARN << "Browse callback error: " << error << std::endl;
     468           0 :             return;
     469             :         }
     470             : 
     471           4 :         if( !( flags & kDNSServiceFlagsAdd ))
     472           0 :             return;
     473             : 
     474           4 :         browsedName_ = name;
     475             : 
     476           4 :         DNSServiceRef service = 0;
     477             :         const DNSServiceErrorType resolve =
     478             :             DNSServiceResolve( &service, 0, interfaceIdx, name, type, domain,
     479           4 :                                (DNSServiceResolveReply)resolveCBS_, this );
     480           4 :         if( resolve != kDNSServiceErr_NoError)
     481           0 :             LBWARN << "DNSServiceResolve error: " << resolve << std::endl;
     482             : 
     483           4 :         if( service )
     484             :         {
     485           4 :             handleEvents_( service, 500 );
     486           4 :             DNSServiceRefDeallocate( service );
     487             :         }
     488             :     }
     489             : 
     490           4 :     static void resolveCBS_( DNSServiceRef, DNSServiceFlags,
     491             :                              uint32_t /*interfaceIdx*/,
     492             :                              DNSServiceErrorType error,
     493             :                              const char* /*name*/, const char* host,
     494             :                              uint16_t /*port*/,
     495             :                              uint16_t txtLen, const unsigned char* txt,
     496             :                              Servus* servus )
     497             :     {
     498           4 :         if( error == kDNSServiceErr_NoError)
     499           4 :             servus->resolveCB_( host, txtLen, txt );
     500           4 :         servus->result_ = error;
     501           4 :     }
     502             : 
     503           4 :     void resolveCB_( const char* host, uint16_t txtLen,
     504             :                      const unsigned char* txt )
     505             :     {
     506           4 :         ValueMap& values = instanceMap_[ browsedName_ ];
     507           4 :         values[ "servus_host" ] = host;
     508             : 
     509           4 :         char key[256] = {0};
     510           4 :         const char* value = 0;
     511           4 :         uint8_t valueLen = 0;
     512             : 
     513           4 :         uint16_t i = 0;
     514          14 :         while( TXTRecordGetItemAtIndex( txtLen, txt, i, sizeof( key ), key,
     515          10 :                                         &valueLen, (const void**)( &value )) ==
     516             :                kDNSServiceErr_NoError )
     517             :         {
     518             : 
     519           6 :             values[ key ] = std::string( value, valueLen );
     520           6 :             ++i;
     521             :         }
     522           4 :     }
     523             : #endif
     524             : };
     525             : }
     526             : 
     527           1 : Servus::Servus( const std::string& name )
     528           1 :         : impl_( new detail::Servus( name ))
     529           1 : {}
     530             : 
     531           1 : Servus::~Servus()
     532             : {
     533           1 :     delete impl_;
     534           1 : }
     535             : 
     536           0 : std::string Servus::Result::getString() const
     537             : {
     538           0 :     const int32_t code = getCode();
     539           0 :     switch( code )
     540             :     {
     541             : #ifdef LUNCHBOX_USE_DNSSD
     542           0 :     case kDNSServiceErr_Unknown:           return "unknown error";
     543           0 :     case kDNSServiceErr_NoSuchName:        return "name not found";
     544           0 :     case kDNSServiceErr_NoMemory:          return "out of memory";
     545           0 :     case kDNSServiceErr_BadParam:          return "bad parameter";
     546           0 :     case kDNSServiceErr_BadReference:      return "bad reference";
     547           0 :     case kDNSServiceErr_BadState:          return "bad state";
     548           0 :     case kDNSServiceErr_BadFlags:          return "bad flags";
     549           0 :     case kDNSServiceErr_Unsupported:       return "unsupported";
     550           0 :     case kDNSServiceErr_NotInitialized:    return "not initialized";
     551           0 :     case kDNSServiceErr_AlreadyRegistered: return "already registered";
     552           0 :     case kDNSServiceErr_NameConflict:      return "name conflict";
     553           0 :     case kDNSServiceErr_Invalid:           return "invalid value";
     554           0 :     case kDNSServiceErr_Firewall:          return "firewall";
     555             :     case kDNSServiceErr_Incompatible:
     556           0 :         return "client library incompatible with daemon";
     557           0 :     case kDNSServiceErr_BadInterfaceIndex: return "bad interface index";
     558           0 :     case kDNSServiceErr_Refused:           return "refused";
     559           0 :     case kDNSServiceErr_NoSuchRecord:      return "no such record";
     560           0 :     case kDNSServiceErr_NoAuth:            return "no authentication";
     561           0 :     case kDNSServiceErr_NoSuchKey:         return "no such key";
     562           0 :     case kDNSServiceErr_NATTraversal:      return "NAT traversal";
     563           0 :     case kDNSServiceErr_DoubleNAT:         return "double NAT";
     564           0 :     case kDNSServiceErr_BadTime:           return "bad time";
     565             : #endif
     566             : 
     567           0 :     case PENDING:          return "operation did not complete";
     568           0 :     case NOT_SUPPORTED:    return "Lunchbox compiled without ZeroConf support";
     569             : 
     570             :     default:
     571           0 :         if( code > 0 )
     572           0 :             return ::strerror( code );
     573           0 :         return lunchbox::Result::getString();
     574             :     }
     575             : }
     576             : 
     577           2 : void Servus::set( const std::string& key, const std::string& value )
     578             : {
     579           2 :     impl_->set( key, value );
     580           2 : }
     581             : 
     582           1 : Strings Servus::getKeys() const
     583             : {
     584           1 :     return impl_->getKeys();
     585             : }
     586             : 
     587           0 : const std::string& Servus::get( const std::string& key ) const
     588             : {
     589           0 :     return impl_->get( key );
     590             : }
     591             : 
     592           2 : Servus::Result Servus::announce( const unsigned short port,
     593             :                                  const std::string& instance )
     594             : {
     595             : #ifdef SERVUS_AVAHI
     596           2 :     ScopedWrite mutex( lock_ );
     597             : #endif
     598           2 :     return impl_->announce( port, instance );
     599             : }
     600             : 
     601           1 : void Servus::withdraw()
     602             : {
     603             : #ifdef SERVUS_AVAHI
     604           1 :     ScopedWrite mutex( lock_ );
     605             : #endif
     606           1 :     impl_->withdraw();
     607           1 : }
     608             : 
     609           0 : bool Servus::isAnnounced() const
     610             : {
     611           0 :     return impl_->isAnnounced();
     612             : }
     613             : 
     614           2 : Strings Servus::discover( const Interface addr, const unsigned browseTime )
     615             : {
     616             : #ifdef SERVUS_AVAHI
     617           2 :     ScopedWrite mutex( lock_ );
     618             : #endif
     619           2 :     return impl_->discover( addr, browseTime );
     620             : }
     621             : 
     622           0 : Strings Servus::getInstances() const
     623             : {
     624           0 :     return impl_->getInstances();
     625             : }
     626             : 
     627           0 : Strings Servus::getKeys( const std::string& instance ) const
     628             : {
     629           0 :     return impl_->getKeys( instance );
     630             : }
     631             : 
     632           0 : bool Servus::containsKey( const std::string& instance,
     633             :                           const std::string& key ) const
     634             : {
     635           0 :     return impl_->containsKey( instance, key );
     636             : }
     637             : 
     638           2 : const std::string& Servus::get( const std::string& instance,
     639             :                                 const std::string& key ) const
     640             : {
     641           2 :     return impl_->get( instance, key );
     642             : }
     643             : 
     644           0 : void Servus::getData( Data& data )
     645             : {
     646           0 :     impl_->getData( data );
     647           0 : }
     648             : 
     649             : #ifdef LUNCHBOX_USE_DNSSD
     650           0 : std::ostream& operator << ( std::ostream& os, const Servus& servus )
     651             : {
     652           0 :     os << disableFlush << disableHeader << "Servus instance"
     653           0 :        << (servus.isAnnounced() ? " " : " not ") << "announced" << indent;
     654             : 
     655           0 :     const Strings& keys = servus.getKeys();
     656           0 :     for( StringsCIter i = keys.begin(); i != keys.end(); ++i )
     657           0 :         os << std::endl << *i << " = " << servus.get( *i );
     658             : 
     659           0 :     return os << exdent << enableHeader << enableFlush;
     660             : }
     661             : #else
     662             : std::ostream& operator << ( std::ostream& os, const Servus& )
     663             : {
     664             :     return os << "No dnssd support, empty Servus implementation";
     665             : }
     666             : #endif
     667             : 
     668          87 : }

Generated by: LCOV version 1.10