xrootd
|
00001 #ifndef __XRDOUCBONJOUR_HH__ 00002 #define __XRDOUCBONJOUR_HH__ 00003 00004 #include <dns_sd.h> 00005 #include <list> 00006 #include "XrdOuc/XrdOucString.hh" 00007 #include "XrdSys/XrdSysPthread.hh" 00008 00009 #if defined(__linux__) 00010 #include <avahi-client/client.h> 00011 #include <avahi-client/publish.h> 00012 #include <avahi-common/strlst.h> 00013 #endif 00014 00015 class XrdOucBonjourRecord; 00016 class XrdOucBonjourNode; 00017 class XrdOucBonjour; 00018 00019 /******************************************************************************/ 00020 /* T y p e d e f i n i t i o n s */ 00021 /******************************************************************************/ 00022 00023 #define TXT_LENGTH 100 00024 #define TIMEOUT 30 00025 00026 #define kBonjourSrvDisabled -1 00027 #define kBonjourSrvBrowse 0 00028 #define kBonjourSrvRegister 1 00029 #define kBonjourSrvBoth 2 00030 00031 // Type definition for the callback function. 00032 typedef void * (*XrdOucBonjourUpdateCallback)(void *); 00033 00034 // Typedef of an struct to store the registration information. Since it is only 00035 // DCO, we do not need to define a class for that. 00036 typedef struct XrdOucBonjourRegisteredEntry { 00037 XrdOucBonjourRecord * record; 00038 unsigned short port; 00039 // Data for the service reference, both Avahi and Bonjour. 00040 #if defined(__macos__) 00041 // We must mantain this reference alive, since its our link to the mDNS. 00042 DNSServiceRef bonjourRef; 00043 #elif defined(__linux__) 00044 // In the case we are using Avahi, lets store the client info structure. 00045 struct { 00046 AvahiClient * avahiClient; 00047 AvahiEntryGroup * avahiEntryGroup; 00048 } avahiRef; 00049 #endif 00050 } XrdOucBonjourRegisteredEntry; 00051 00052 // Typedef of an struct to store the subcription information. Since it is only 00053 // DCO, we not define a class for that. 00054 typedef struct XrdOucBonjourSubscribedEntry { 00055 XrdOucBonjourUpdateCallback callback; 00056 void * context; 00057 XrdOucString * serviceType; 00058 // Used to carry the Avahi browser information. 00059 #if defined(__linux__) 00060 AvahiClient * client; 00061 #endif 00062 } XrdOucBonjourSubscribedEntry; 00063 00064 // Used to make the resolution dinamycally. 00065 typedef struct XrdOucBonjourResolutionEntry { 00066 XrdOucBonjourNode * node; 00067 XrdOucBonjourSubscribedEntry * callbackID; 00068 } XrdOucBonjourResolutionEntry; 00069 00070 /******************************************************************************/ 00071 /* B o n j o u r r e c o r d */ 00072 /******************************************************************************/ 00073 00074 // Note that this class depends on the compatibility layer of Avahi. 00075 class XrdOucBonjourRecord { 00076 private: 00077 XrdOucString ServiceName; 00078 XrdOucString RegisteredType; 00079 XrdOucString ReplyDomain; 00080 TXTRecordRef TXTRecord; 00081 void InitTXTRecord(); 00082 void CopyTXTRecord(const TXTRecordRef &otherRecord); 00083 00084 public: 00085 XrdOucBonjourRecord() { 00086 InitTXTRecord(); 00087 } 00088 00089 XrdOucBonjourRecord(const char * name, 00090 const char * type, 00091 const char * domain) : 00092 ServiceName(name), RegisteredType(type), ReplyDomain(domain) { 00093 InitTXTRecord(); 00094 } 00095 00096 XrdOucBonjourRecord(const XrdOucBonjourRecord &other) : 00097 ServiceName(other.ServiceName), RegisteredType(other.RegisteredType), 00098 ReplyDomain(other.ReplyDomain) { 00099 InitTXTRecord(); 00100 CopyTXTRecord(other.TXTRecord); 00101 } 00102 00103 virtual ~XrdOucBonjourRecord() { 00104 TXTRecordDeallocate(&TXTRecord); 00105 } 00106 00107 const char *GetServiceName() const { 00108 return ServiceName.length() ? ServiceName.c_str() : NULL; 00109 } 00110 const char *GetRegisteredType() const { 00111 return RegisteredType.length() ? RegisteredType.c_str() : NULL; 00112 } 00113 const char *GetReplyDomain() const { 00114 return ReplyDomain.length() ? ReplyDomain.c_str() : NULL; 00115 } 00116 const char *GetTXTRecordData() const { 00117 return (const char *)TXTRecordGetBytesPtr(&TXTRecord); 00118 } 00119 const char *GetTXTValue(const char * key, int &len) const; 00120 int GetTXTRecordLength() const { 00121 return TXTRecordGetLength(&TXTRecord); 00122 } 00123 00124 #if defined(__linux__) 00125 AvahiStringList *GetTXTAvahiList(); 00126 #endif 00127 00128 int MatchesServiceName(const char * pattern) const { 00129 return (const_cast<XrdOucString &>(ServiceName)).beginswith(pattern); 00130 } 00131 int MatchesRegisteredType(const char * pattern) const { 00132 return (const_cast<XrdOucString &>(RegisteredType)).beginswith(pattern); 00133 } 00134 int MatchesReplyDomain(const char * pattern) const { 00135 return (const_cast<XrdOucString &>(ReplyDomain)).beginswith(pattern); 00136 } 00137 00138 void AddTXTRecord(const char * key, const char * value); 00139 void AddTXTRecord(const char * key, int value); 00140 void AddRawTXTRecord(const char * rawData); 00141 void SetServiceName(const char * name); 00142 void SetRegisteredType(const char * type); 00143 void SetReplyDomain(const char * domain); 00144 void DeleteTXTRecord(); 00145 00146 XrdOucBonjourRecord &operator=(const XrdOucBonjourRecord &other); 00147 00148 void Print() const; 00149 }; 00150 00151 /******************************************************************************/ 00152 /* B o n j o u r n o d e */ 00153 /******************************************************************************/ 00154 00155 class XrdOucBonjourNode { 00156 private: 00157 XrdOucString HostName; 00158 unsigned short Port; 00159 XrdOucBonjourRecord BonjourInfo; 00160 00161 public: 00162 XrdOucBonjourNode() { 00163 Port = 0; 00164 } 00165 00166 XrdOucBonjourNode(const char * hostName, 00167 unsigned short port) : 00168 HostName(hostName) { 00169 Port = port; 00170 } 00171 00172 XrdOucBonjourNode(const char * hostName, 00173 unsigned short port, 00174 XrdOucBonjourRecord const &bonjourInfo) : 00175 HostName(hostName), BonjourInfo(bonjourInfo) { 00176 Port = port; 00177 } 00178 00179 XrdOucBonjourNode(XrdOucBonjourRecord const &bonjourInfo) : 00180 BonjourInfo(bonjourInfo) { 00181 Port = 0; 00182 } 00183 00184 // A handful constructor for the browse reply callback 00185 XrdOucBonjourNode(const char * name, 00186 const char * type, 00187 const char * domain) : 00188 BonjourInfo(name, type, domain) { 00189 Port = 0; 00190 } 00191 00192 XrdOucBonjourNode(const XrdOucBonjourNode &other) : 00193 HostName(other.HostName), BonjourInfo(other.BonjourInfo) { 00194 Port = other.Port; 00195 } 00196 00197 virtual ~XrdOucBonjourNode() { } 00198 00199 const char *GetHostName() const { 00200 return HostName.length() ? HostName.c_str() : NULL; 00201 } 00202 unsigned short GetPort() const { 00203 return Port; 00204 } 00205 const XrdOucBonjourRecord &GetBonjourRecord() const { 00206 return BonjourInfo; 00207 } 00208 XrdOucBonjourRecord &GetBonjourRecord() { 00209 return BonjourInfo; 00210 } 00211 00212 void SetHostName(const char * hostName); 00213 void SetPort(unsigned short port); 00214 void SetBonjourRecord(const XrdOucBonjourRecord &record); 00215 00216 XrdOucBonjourNode &operator=(const XrdOucBonjourNode &other); 00217 00218 void Print() const; 00219 }; 00220 00221 /******************************************************************************/ 00222 /* B o n j o u r s e r v i c e s */ 00223 /******************************************************************************/ 00224 00225 class XrdOucBonjour { 00226 protected: 00227 // List of registered services we have. 00228 std::list<XrdOucBonjourNode *> ListOfNodes; 00229 XrdSysMutex ListOfNodesMutex; 00230 00231 public: 00232 XrdOucBonjour() { } 00233 virtual ~XrdOucBonjour() { } 00234 00235 // Register a service on the mDNS local service. This function also 00236 // subscribes the sender for updates on the discoverage service. 00237 virtual int RegisterService(XrdOucBonjourRecord &record, 00238 unsigned short port = 0) = 0; 00239 00240 // Subscribes a new client to receive updates about service discoveries. 00241 // This will detatch a new thread to process the updates, running (when 00242 // a new update arrives) the callback function in its own thread. This 00243 // function mush be thread-safe, and its responsability of the client 00244 // to ensure that. 00245 virtual int SubscribeForUpdates(const char * servicetype, 00246 XrdOucBonjourUpdateCallback callback, 00247 void * context) = 0; 00248 00249 // Resolves the name of a node. If you provide a pointer to a node 00250 // object, this function completes the current information about hostname 00251 // and port. It is important to use the resolution by-demand since the list 00252 // may not contain updated information due to the use of highly dynamical 00253 // DHCP and APIPA addresses. 00254 virtual int ResolveNodeInformation(XrdOucBonjourResolutionEntry * nodeAndCallback) = 0; 00255 00256 // Returns the current list of discovered nodes through the Bonjour local 00257 // mDNS. This list cannot be modified by clients of the class. 00258 const std::list<XrdOucBonjourNode *> &GetCurrentNodeList() const { 00259 return ListOfNodes; 00260 } 00261 00262 // Methods for locking and unlocking the node table in the case that it 00263 // will be modified or an exclusive access is needed. 00264 void LockNodeList() { 00265 ListOfNodesMutex.Lock(); 00266 } 00267 void UnLockNodeList() { 00268 ListOfNodesMutex.UnLock(); 00269 } 00270 00271 // Accessor to get the singleton instance. 00272 static XrdOucBonjour &getInstance(); 00273 }; 00274 00275 /******************************************************************************/ 00276 /* A b s t r a c t f a c t o r y */ 00277 /******************************************************************************/ 00278 00279 class XrdOucBonjourFactory { 00280 public: 00281 static XrdOucBonjourFactory *FactoryByPlatform(); 00282 00283 virtual XrdOucBonjour &GetBonjourManager() = 0; 00284 virtual ~XrdOucBonjourFactory() { } 00285 }; 00286 00287 #endif