ROOT logo
// @(#)root/bonjour:$Id: TBonjourBrowser.cxx 34481 2010-07-19 14:51:45Z rdm $
// Author: Fons Rademakers   29/05/2009

/*************************************************************************
 * Copyright (C) 1995-2009, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

//////////////////////////////////////////////////////////////////////////
//                                                                      //
// TBonjourBrowser                                                      //
//                                                                      //
// This class consists of one main member function,                     //
// BrowseForServiceType(), that looks for the service.                  //
// The rest of the class wraps the various bits of Bonjour service      //
// browser. The static callback function is marked with the DNSSD_API   //
// macro to make sure that the callback has the correct calling         //
// convention on Windows.                                               //
//                                                                      //
// Bonjour works out-of-the-box on MacOS X. On Linux you have to        //
// install the Avahi package and run the avahi-daemon. To compile       //
// these classes and run Avahi on Linux you need to install the:        //
//    avahi                                                             //
//    avahi-compat-libdns_sd-devel                                      //
//    nss-mdns                                                          //
// packages. After installation make sure the avahi-daemon is started.  //
//                                                                      //
//////////////////////////////////////////////////////////////////////////

#include "TBonjourBrowser.h"
#include "TBonjourRecord.h"
#include "TSysEvtHandler.h"
#include "TList.h"
#include "TError.h"
#include "TSystem.h"


ClassImp(TBonjourBrowser)

//______________________________________________________________________________
TBonjourBrowser::TBonjourBrowser() : fDNSRef(0), fBonjourSocketHandler(0)
{
   // Default ctor.

   fBonjourRecords = new TList;
   fBonjourRecords->SetOwner();

   // silence Avahi about using Bonjour compat layer
   gSystem->Setenv("AVAHI_COMPAT_NOWARN", "1");
}

//______________________________________________________________________________
TBonjourBrowser::~TBonjourBrowser()
{
   // Cleanup.

   delete fBonjourRecords;
   delete fBonjourSocketHandler;

   if (fDNSRef) {
      DNSServiceRefDeallocate(fDNSRef);
      fDNSRef = 0;
   }
}

//______________________________________________________________________________
Int_t TBonjourBrowser::BrowseForServiceType(const char *serviceType)
{
   // Tell Bonjour to start browsing for a specific type of service.
   // Returns -1 in case of error, 0 otherwise.

   DNSServiceErrorType err = DNSServiceBrowse(&fDNSRef, 0,
                                              0, serviceType, 0,
                                              (DNSServiceBrowseReply)BonjourBrowseReply,
                                              this);
   if (err != kDNSServiceErr_NoError) {
      Error("BrowseForServiceType", "error in DNSServiceBrowse (%d)", err);
      return -1;
   }

   Int_t sockfd = DNSServiceRefSockFD(fDNSRef);
   if (sockfd == -1) {
      Error("BrowseForServiceType", "invalid sockfd");
      return -1;
   }

   fBonjourSocketHandler = new TFileHandler(sockfd, TFileHandler::kRead);
   fBonjourSocketHandler->Connect("Notified()", "TBonjourBrowser", this, "BonjourSocketReadyRead()");
   fBonjourSocketHandler->Add();

   return 0;
}

//______________________________________________________________________________
void TBonjourBrowser::CurrentBonjourRecordsChanged(TList *bonjourRecords)
{
   // Emit CurrentBonjourRecordsChanged signal.

   Emit("CurrentBonjourRecordsChanged(TList*)", (Long_t)bonjourRecords);
}

//______________________________________________________________________________
void TBonjourBrowser::BonjourSocketReadyRead()
{
   // The Bonjour socket is ready for reading. Tell Bonjour to process the
   // information on the socket, this will invoke the BonjourBrowseReply
   // callback. This is a private slot, used in BrowseForServiceType.

   // in case the browser has already been deleted
   if (!fDNSRef) return;

   DNSServiceErrorType err = DNSServiceProcessResult(fDNSRef);
   if (err != kDNSServiceErr_NoError)
      Error("BonjourSocketReadyRead", "error in DNSServiceProcessResult");
}

//______________________________________________________________________________
void TBonjourBrowser::BonjourBrowseReply(DNSServiceRef,
                                         DNSServiceFlags flags, UInt_t,
                                         DNSServiceErrorType errorCode,
                                         const char *serviceName, const char *regType,
                                         const char *replyDomain, void *context)
{
   // Static Bonjour browser callback function.

   TBonjourBrowser *browser = static_cast<TBonjourBrowser*>(context);
   if (errorCode != kDNSServiceErr_NoError) {
      ::Error("TBonjourBrowser::BonjourBrowseReply", "error in BonjourBrowseReply");
      //browser->Error(errorCode);
   } else {
      TBonjourRecord *record = new TBonjourRecord(serviceName, regType, replyDomain);
      if (flags & kDNSServiceFlagsAdd) {
         if (!browser->fBonjourRecords->FindObject(record))
            browser->fBonjourRecords->Add(record);
         else
            delete record;
      } else {
         TBonjourRecord *r = (TBonjourRecord*)browser->fBonjourRecords->Remove(record);
         delete r;
         delete record;
      }
      if (!(flags & kDNSServiceFlagsMoreComing)) {
         browser->CurrentBonjourRecordsChanged(browser->fBonjourRecords);
      }
   }
}
 TBonjourBrowser.cxx:1
 TBonjourBrowser.cxx:2
 TBonjourBrowser.cxx:3
 TBonjourBrowser.cxx:4
 TBonjourBrowser.cxx:5
 TBonjourBrowser.cxx:6
 TBonjourBrowser.cxx:7
 TBonjourBrowser.cxx:8
 TBonjourBrowser.cxx:9
 TBonjourBrowser.cxx:10
 TBonjourBrowser.cxx:11
 TBonjourBrowser.cxx:12
 TBonjourBrowser.cxx:13
 TBonjourBrowser.cxx:14
 TBonjourBrowser.cxx:15
 TBonjourBrowser.cxx:16
 TBonjourBrowser.cxx:17
 TBonjourBrowser.cxx:18
 TBonjourBrowser.cxx:19
 TBonjourBrowser.cxx:20
 TBonjourBrowser.cxx:21
 TBonjourBrowser.cxx:22
 TBonjourBrowser.cxx:23
 TBonjourBrowser.cxx:24
 TBonjourBrowser.cxx:25
 TBonjourBrowser.cxx:26
 TBonjourBrowser.cxx:27
 TBonjourBrowser.cxx:28
 TBonjourBrowser.cxx:29
 TBonjourBrowser.cxx:30
 TBonjourBrowser.cxx:31
 TBonjourBrowser.cxx:32
 TBonjourBrowser.cxx:33
 TBonjourBrowser.cxx:34
 TBonjourBrowser.cxx:35
 TBonjourBrowser.cxx:36
 TBonjourBrowser.cxx:37
 TBonjourBrowser.cxx:38
 TBonjourBrowser.cxx:39
 TBonjourBrowser.cxx:40
 TBonjourBrowser.cxx:41
 TBonjourBrowser.cxx:42
 TBonjourBrowser.cxx:43
 TBonjourBrowser.cxx:44
 TBonjourBrowser.cxx:45
 TBonjourBrowser.cxx:46
 TBonjourBrowser.cxx:47
 TBonjourBrowser.cxx:48
 TBonjourBrowser.cxx:49
 TBonjourBrowser.cxx:50
 TBonjourBrowser.cxx:51
 TBonjourBrowser.cxx:52
 TBonjourBrowser.cxx:53
 TBonjourBrowser.cxx:54
 TBonjourBrowser.cxx:55
 TBonjourBrowser.cxx:56
 TBonjourBrowser.cxx:57
 TBonjourBrowser.cxx:58
 TBonjourBrowser.cxx:59
 TBonjourBrowser.cxx:60
 TBonjourBrowser.cxx:61
 TBonjourBrowser.cxx:62
 TBonjourBrowser.cxx:63
 TBonjourBrowser.cxx:64
 TBonjourBrowser.cxx:65
 TBonjourBrowser.cxx:66
 TBonjourBrowser.cxx:67
 TBonjourBrowser.cxx:68
 TBonjourBrowser.cxx:69
 TBonjourBrowser.cxx:70
 TBonjourBrowser.cxx:71
 TBonjourBrowser.cxx:72
 TBonjourBrowser.cxx:73
 TBonjourBrowser.cxx:74
 TBonjourBrowser.cxx:75
 TBonjourBrowser.cxx:76
 TBonjourBrowser.cxx:77
 TBonjourBrowser.cxx:78
 TBonjourBrowser.cxx:79
 TBonjourBrowser.cxx:80
 TBonjourBrowser.cxx:81
 TBonjourBrowser.cxx:82
 TBonjourBrowser.cxx:83
 TBonjourBrowser.cxx:84
 TBonjourBrowser.cxx:85
 TBonjourBrowser.cxx:86
 TBonjourBrowser.cxx:87
 TBonjourBrowser.cxx:88
 TBonjourBrowser.cxx:89
 TBonjourBrowser.cxx:90
 TBonjourBrowser.cxx:91
 TBonjourBrowser.cxx:92
 TBonjourBrowser.cxx:93
 TBonjourBrowser.cxx:94
 TBonjourBrowser.cxx:95
 TBonjourBrowser.cxx:96
 TBonjourBrowser.cxx:97
 TBonjourBrowser.cxx:98
 TBonjourBrowser.cxx:99
 TBonjourBrowser.cxx:100
 TBonjourBrowser.cxx:101
 TBonjourBrowser.cxx:102
 TBonjourBrowser.cxx:103
 TBonjourBrowser.cxx:104
 TBonjourBrowser.cxx:105
 TBonjourBrowser.cxx:106
 TBonjourBrowser.cxx:107
 TBonjourBrowser.cxx:108
 TBonjourBrowser.cxx:109
 TBonjourBrowser.cxx:110
 TBonjourBrowser.cxx:111
 TBonjourBrowser.cxx:112
 TBonjourBrowser.cxx:113
 TBonjourBrowser.cxx:114
 TBonjourBrowser.cxx:115
 TBonjourBrowser.cxx:116
 TBonjourBrowser.cxx:117
 TBonjourBrowser.cxx:118
 TBonjourBrowser.cxx:119
 TBonjourBrowser.cxx:120
 TBonjourBrowser.cxx:121
 TBonjourBrowser.cxx:122
 TBonjourBrowser.cxx:123
 TBonjourBrowser.cxx:124
 TBonjourBrowser.cxx:125
 TBonjourBrowser.cxx:126
 TBonjourBrowser.cxx:127
 TBonjourBrowser.cxx:128
 TBonjourBrowser.cxx:129
 TBonjourBrowser.cxx:130
 TBonjourBrowser.cxx:131
 TBonjourBrowser.cxx:132
 TBonjourBrowser.cxx:133
 TBonjourBrowser.cxx:134
 TBonjourBrowser.cxx:135
 TBonjourBrowser.cxx:136
 TBonjourBrowser.cxx:137
 TBonjourBrowser.cxx:138
 TBonjourBrowser.cxx:139
 TBonjourBrowser.cxx:140
 TBonjourBrowser.cxx:141
 TBonjourBrowser.cxx:142
 TBonjourBrowser.cxx:143
 TBonjourBrowser.cxx:144
 TBonjourBrowser.cxx:145
 TBonjourBrowser.cxx:146
 TBonjourBrowser.cxx:147
 TBonjourBrowser.cxx:148
 TBonjourBrowser.cxx:149