00001
00002
00003
00004
00005
00006
00007 #include <arpa/inet.h>
00008 #include <net/if.h>
00009 #include <sys/select.h>
00010 #include <cstdlib>
00011 #include "Xrd/XrdConfig.hh"
00012 #include "XrdOuc/XrdOucBonjour.hh"
00013 #include "XrdOuc/XrdOucFactoryBonjour.hh"
00014 #include "XrdSys/XrdSysError.hh"
00015 #include "Xrd/XrdInet.hh"
00016 #include "Xrd/XrdProtLoad.hh"
00017
00018
00019
00020
00021
00022 extern XrdConfig XrdConf;
00023 extern XrdSysError XrdLog;
00024 extern XrdInet *XrdNetTCP[];
00025
00026
00027
00028
00029
00030 void XrdOucAppleBonjour::RegisterReply(DNSServiceRef ref, DNSServiceFlags flags,
00031 DNSServiceErrorType error, const char * name,
00032 const char * regtype, const char * domain,
00033 void * context)
00034 {
00035 XrdOucBonjourRegisteredEntry * entry;
00036 entry = (XrdOucBonjourRegisteredEntry *)context;
00037
00038
00039
00040
00041 if (error != kDNSServiceErr_NoError) {
00042 ((XrdOucAppleBonjour &)getInstance()).ListOfRegistrations.remove(entry);
00043 delete entry->record;
00044 free(entry);
00045 XrdLog.Emsg("OucBonjour", error, "complete the registration callback");
00046 return;
00047 }
00048
00049
00050 entry->record->SetServiceName(name);
00051 entry->record->SetRegisteredType(regtype);
00052 entry->record->SetReplyDomain(domain);
00053 }
00054
00055 int XrdOucAppleBonjour::RegisterService(XrdOucBonjourRecord &record, unsigned short port)
00056 {
00057 XrdOucBonjourRegisteredEntry * entry;
00058 DNSServiceErrorType err;
00059 fd_set descriptors;
00060 int sockfd;
00061 struct timeval timeout;
00062
00063
00064 if (port == 0)
00065 port = (XrdNetTCP[0] == XrdNetTCP[XrdProtLoad::ProtoMax]
00066 ? -(XrdNetTCP[0]->Port()) : XrdNetTCP[0]->Port());
00067
00068
00069 entry = (XrdOucBonjourRegisteredEntry *)malloc(sizeof(XrdOucBonjourRegisteredEntry));
00070 if (!entry)
00071 return -1;
00072
00073 entry->record = new XrdOucBonjourRecord(record);
00074 entry->port = port;
00075
00076
00077 err = DNSServiceRegister(&(entry->bonjourRef),
00078 0,
00079 0,
00080 record.GetServiceName(),
00081 record.GetRegisteredType(),
00082 record.GetReplyDomain(),
00083 NULL,
00084 htons(port),
00085 record.GetTXTRecordLength(),
00086 record.GetTXTRecordData(),
00087 RegisterReply,
00088 entry);
00089
00090 if (err != kDNSServiceErr_NoError) {
00091 XrdLog.Emsg("OucBonjour", err, "rRegigster service", record.GetRegisteredType());
00092 XrdLog.Emsg("OucBonjour", err, "launch the registration");
00093
00094 delete entry->record;
00095 free(entry);
00096 return -1;
00097 }
00098
00099
00100
00101 sockfd = DNSServiceRefSockFD(entry->bonjourRef);
00102
00103 FD_ZERO(&descriptors);
00104 FD_SET(sockfd, &descriptors);
00105 timeout.tv_sec = TIMEOUT;
00106 timeout.tv_usec = 0;
00107
00108 if (select(sockfd + 1, &descriptors, NULL, NULL, &timeout) > 0) {
00109 err = DNSServiceProcessResult(entry->bonjourRef);
00110 if (err != kDNSServiceErr_NoError) {
00111 XrdLog.Emsg("OucBonjour", err, "process the registration procedure");
00112 return -1;
00113 }
00114 } else {
00115 XrdLog.Emsg("OucBonjour", err, "wait to the registration response");
00116 return -1;
00117 }
00118
00119 ListOfRegistrations.push_back(entry);
00120 return 0;
00121 }
00122
00123
00124
00125
00126
00127 void * XrdOucAppleBonjour::BrowseEventLoopThread(void * context)
00128 {
00129 int sockfd;
00130 int selRes;
00131 int stopEventLoop = 0;
00132 DNSServiceRef serviceRef;
00133 DNSServiceErrorType err;
00134 fd_set descriptors;
00135 XrdOucBonjourSubscribedEntry * callbackID;
00136
00137 callbackID = (XrdOucBonjourSubscribedEntry *)context;
00138
00139
00140
00141
00142 XrdSysThread::SetCancelOn();
00143 XrdSysThread::SetCancelAsynchronous();
00144
00145
00146 err = DNSServiceBrowse(&serviceRef,
00147 0,
00148 0,
00149 callbackID->serviceType->c_str(),
00150 NULL,
00151 BrowseReply,
00152 context);
00153
00154
00155 if (err != kDNSServiceErr_NoError) {
00156 XrdLog.Emsg("OucBonjour", err, "launch the discovery process");
00157 return NULL;
00158 }
00159
00160
00161 sockfd = DNSServiceRefSockFD(serviceRef);
00162
00163 while (!stopEventLoop) {
00164
00165 FD_ZERO(&descriptors);
00166 FD_SET(sockfd, &descriptors);
00167
00168
00169 selRes = select(sockfd + 1, &descriptors, NULL, NULL, NULL);
00170
00171
00172 if (selRes > 0) {
00173 if (FD_ISSET(sockfd, &descriptors)) {
00174
00175
00176 err = DNSServiceProcessResult(serviceRef);
00177 if (err != kDNSServiceErr_NoError) {
00178 XrdLog.Emsg("OucBonjour", err, "process an event in event loop");
00179 stopEventLoop = 1;
00180 }
00181 }
00182 } else if (selRes == -1) {
00183 XrdLog.Emsg("OucBonjour", "The select() call failed");
00184 stopEventLoop = 1;
00185 }
00186 }
00187
00188 XrdLog.Emsg("OucBonjour", "The browsing event loop has ended unexpectedly");
00189 return NULL;
00190 }
00191
00192 void XrdOucAppleBonjour::BrowseReply(DNSServiceRef ref, DNSServiceFlags flags,
00193 uint32_t interfaceIndex, DNSServiceErrorType error,
00194 const char * name, const char * regtype,
00195 const char * domain, void * context)
00196 {
00197
00198 XrdOucAppleBonjour *instance;
00199 XrdOucBonjourNode *node;
00200 XrdOucBonjourSubscribedEntry * callbackID;
00201 XrdOucBonjourResolutionEntry * nodeAndCallback;
00202
00203 callbackID = (XrdOucBonjourSubscribedEntry *)context;
00204
00205 if (error != kDNSServiceErr_NoError) {
00206 XrdLog.Emsg("OucBonjour", error, "complete the browse callback");
00207 return;
00208 }
00209
00210
00211 instance = &XrdOucAppleBonjour::getInstance();
00212
00213
00214 if (flags & kDNSServiceFlagsAdd) {
00215
00216 node = new XrdOucBonjourNode(name, regtype, domain);
00217 nodeAndCallback = (XrdOucBonjourResolutionEntry *)malloc(sizeof(XrdOucBonjourResolutionEntry));
00218 nodeAndCallback->node = node;
00219 nodeAndCallback->callbackID = callbackID;
00220
00221
00222 instance->ResolveNodeInformation(nodeAndCallback);
00223
00224
00225
00226
00227
00228
00229 XrdLog.Say("------ XrdOucBonjour: discovered a new node: ", name);
00230 } else {
00231
00232 XrdOucAppleBonjourSearchNode predicate(name);
00233
00234 instance->LockNodeList();
00235 instance->ListOfNodes.remove_if(predicate);
00236 instance->UnLockNodeList();
00237
00238 XrdLog.Say("------ XrdOucBonjour: the node ", name, " went out the network");
00239
00240
00241 if (!(flags & kDNSServiceFlagsMoreComing))
00242 callbackID->callback(callbackID->context);
00243 }
00244 }
00245
00246
00247
00248
00249
00250 int XrdOucAppleBonjour::SubscribeForUpdates(const char * servicetype,
00251 XrdOucBonjourUpdateCallback callback,
00252 void * context)
00253 {
00254 pthread_t thread;
00255 XrdOucBonjourSubscribedEntry * callbackID = (XrdOucBonjourSubscribedEntry *)malloc(sizeof(XrdOucBonjourSubscribedEntry));
00256 callbackID->callback = callback;
00257 callbackID->context = context;
00258 callbackID->serviceType = new XrdOucString(servicetype);
00259
00260
00261 return XrdSysThread::Run(&thread, BrowseEventLoopThread, callbackID);
00262 }
00263
00264
00265
00266
00267
00268 void XrdOucAppleBonjour::ResolveReply(DNSServiceRef ref, DNSServiceFlags flags,
00269 uint32_t interfaceIndex, DNSServiceErrorType error,
00270 const char * fullname, const char * hostname,
00271 uint16_t port, uint16_t txtLen,
00272 const unsigned char * txtVal, void * context)
00273 {
00274 XrdOucAppleBonjour * instance;
00275 XrdOucBonjourResolutionEntry * nodeAndCallback;
00276
00277 if (error != kDNSServiceErr_NoError) {
00278 XrdLog.Emsg("OucBonjour", error, "complete the resolve callback");
00279 return;
00280 }
00281
00282 nodeAndCallback = static_cast<XrdOucBonjourResolutionEntry *>(context);
00283
00284
00285 nodeAndCallback->node->SetHostName(hostname);
00286 nodeAndCallback->node->SetPort(ntohs(port));
00287
00288
00289 nodeAndCallback->node->GetBonjourRecord().AddRawTXTRecord((const char *)txtVal);
00290
00291
00292 instance = &XrdOucAppleBonjour::getInstance();
00293
00294
00295 instance->LockNodeList();
00296 instance->ListOfNodes.push_back(nodeAndCallback->node);
00297 instance->UnLockNodeList();
00298
00299
00300 if (!(flags & kDNSServiceFlagsMoreComing))
00301 nodeAndCallback->callbackID->callback(nodeAndCallback->callbackID->context);
00302
00303 free(nodeAndCallback);
00304 }
00305
00306 int XrdOucAppleBonjour::ResolveNodeInformation(XrdOucBonjourResolutionEntry * nodeAndCallback)
00307 {
00308 DNSServiceErrorType err;
00309 DNSServiceRef serviceRef;
00310 fd_set descriptors;
00311 int sockfd;
00312 struct timeval timeout;
00313
00314
00315 err = DNSServiceResolve(&serviceRef,
00316 0,
00317 0,
00318 nodeAndCallback->node->GetBonjourRecord().GetServiceName(),
00319 nodeAndCallback->node->GetBonjourRecord().GetRegisteredType(),
00320 nodeAndCallback->node->GetBonjourRecord().GetReplyDomain(),
00321 ResolveReply,
00322 nodeAndCallback);
00323
00324
00325 if (err != kDNSServiceErr_NoError) {
00326 XrdLog.Emsg("OucBonjour", err, "start the resolution procedure");
00327 return -1;
00328 }
00329
00330
00331
00332 sockfd = DNSServiceRefSockFD(serviceRef);
00333
00334 FD_ZERO(&descriptors);
00335 FD_SET(sockfd, &descriptors);
00336 timeout.tv_sec = TIMEOUT;
00337 timeout.tv_usec = 0;
00338
00339 if (select(sockfd + 1, &descriptors, NULL, NULL, &timeout) > 0) {
00340 err = DNSServiceProcessResult(serviceRef);
00341
00342 DNSServiceRefDeallocate(serviceRef);
00343 if (err != kDNSServiceErr_NoError) {
00344 XrdLog.Emsg("OucBonjour", err, "process the resolution procedure");
00345 return -1;
00346 }
00347 } else {
00348 XrdLog.Emsg("OucBonjour", err, "wait to the resolution response");
00349 return -1;
00350 }
00351
00352
00353 return 0;
00354 }
00355
00356
00357
00358
00359
00360 bool XrdOucAppleBonjour::XrdOucAppleBonjourSearchNode::operator()(XrdOucBonjourNode * value)
00361 {
00362 return strcmp(value->GetBonjourRecord().GetServiceName(), ServiceName) == 0;
00363 }
00364
00365 XrdOucAppleBonjour * XrdOucAppleBonjour::_Instance = NULL;
00366
00367 XrdSysMutex XrdOucAppleBonjour::SingletonMutex;
00368
00369 XrdOucAppleBonjour::XrdOucAppleBonjour()
00370 {
00371 char *env = new char[22];
00372 strcpy(env, "AVAHI_COMPAT_NOWARN=1");
00373 putenv(env);
00374 }
00375
00376 XrdOucAppleBonjour::~XrdOucAppleBonjour() { }
00377
00378
00379
00380
00381
00382
00383 XrdOucAppleBonjour &XrdOucAppleBonjour::getInstance()
00384 {
00385
00386
00387 static XrdOucAppleBonjourSingletonCleanup cleanGuard;
00388
00389 SingletonMutex.Lock();
00390 if (!_Instance)
00391 _Instance = new XrdOucAppleBonjour();
00392 SingletonMutex.UnLock();
00393
00394 return *_Instance;
00395 }
00396
00397 XrdOucAppleBonjour::XrdOucAppleBonjourSingletonCleanup::~XrdOucAppleBonjourSingletonCleanup()
00398 {
00399 SingletonMutex.Lock();
00400 if (_Instance) {
00401 delete XrdOucAppleBonjour::_Instance;
00402 XrdOucAppleBonjour::_Instance = NULL;
00403 }
00404 SingletonMutex.UnLock();
00405 }