XrdOucBonjour.cc

Go to the documentation of this file.
00001 /*
00002    C++ implementation of Bonjour services.  Code is based
00003    on the implementation of TBonjour* classes written by
00004    Fons Rademakers for the ROOT Framework.
00005 */
00006 
00007 #include <arpa/inet.h>
00008 #include <net/if.h>
00009 #include <sys/select.h>
00010 #include <cstdlib>
00011 #include "XrdOuc/XrdOucBonjour.hh"
00012 #include "XrdSys/XrdSysError.hh"
00013 #include "Xrd/XrdProtLoad.hh"
00014 
00015 // Conditional inclusion of headers dependent on platform.
00016 #include "XrdOuc/XrdOucFactoryBonjour.hh"
00017 
00018 /******************************************************************************/
00019 /*                      G l o b a l   V a r i a b l e s                       */
00020 /******************************************************************************/
00021 
00022 extern XrdSysError  XrdLog;               // Defined in XrdMain.cc
00023 
00024 /******************************************************************************/
00025 /*                        B o n j o u r   r e c o r d                         */
00026 /******************************************************************************/
00027 
00028 #if !defined(__macos__)
00029 AvahiStringList *XrdOucBonjourRecord::GetTXTAvahiList()
00030 {
00031    AvahiStringList *list;
00032    uint16_t len, i;
00033    char key[256];
00034    const void *rawData, *value;
00035    uint8_t valueLen;
00036    XrdOucString entry;
00037    char valueTrimmed[1024];
00038 
00039    // Initialize common data.
00040    list = NULL;
00041    i = 0;
00042    key[0] = '\0';
00043    value = NULL;
00044 
00045    // Get TXT record raw data.
00046    rawData = TXTRecordGetBytesPtr(&TXTRecord);
00047    len = TXTRecordGetLength(&TXTRecord);
00048 
00049    // Iterate through all the elements of the TXT record list creating a list
00050    // item for all of them.
00051    while (TXTRecordGetItemAtIndex(len, rawData, i, 256, key, &valueLen, &value) != kDNSServiceErr_Invalid) {
00052       // Empty string.
00053       entry.hardreset();
00054       // Construct the entry according to the mDNS TXT management rules.
00055       entry.append(key);
00056       if (value != NULL) {
00057          entry.append("=");
00058          if (valueLen > 0) {
00059             // The 'n' version of strcpy is more secure.
00060             strncpy(valueTrimmed, (const char *)value, valueLen);
00061             // Terminate the string to ensure buffer security.
00062             valueTrimmed[valueLen] = '\0';
00063             // Now, append.
00064             entry.append(valueTrimmed);
00065          }
00066       }
00067       // Build the Avahi List Entry. Note that you must free this list after
00068       // using it with the avahi_string_list_free() function.
00069       list = avahi_string_list_add(list, entry.c_str());
00070       i++;
00071    }
00072 
00073    // Return the list.
00074    return list;
00075 }
00076 #endif
00077 
00078 void XrdOucBonjourRecord::AddTXTRecord(const char * key, const char * value)
00079 {
00080    TXTRecordSetValue(&TXTRecord, key, strlen(value), value);
00081 }
00082 
00083 void XrdOucBonjourRecord::AddTXTRecord(const char * key, int value)
00084 {
00085    char value_str[256];
00086 
00087    snprintf(value_str, 256, "%d", value);
00088 
00089    AddTXTRecord(key, value_str);
00090 }
00091 
00092 void XrdOucBonjourRecord::SetServiceName(const char * name)
00093 {
00094    // This method is specially maded for use when a local installation of
00095    // multiple processes listening on different ports. It is more efficient
00096    // to do an assign than to create a new object, furthermore, if the object
00097    // is on the stack, this method minimizes the use of the heap (at least
00098    // directly, since XrdOucString makes use of it for character storage).
00099    ServiceName.assign(name, 0);
00100 }
00101 
00102 void XrdOucBonjourRecord::SetRegisteredType(const char * type)
00103 {
00104    RegisteredType.assign(type, 0);
00105 }
00106 
00107 void XrdOucBonjourRecord::SetReplyDomain(const char * domain)
00108 {
00109    ReplyDomain.assign(domain, 0);
00110 }
00111 
00112 void XrdOucBonjourRecord::DeleteTXTRecord()
00113 {
00114    TXTRecordDeallocate(&TXTRecord);
00115    InitTXTRecord();
00116 }
00117 
00118 XrdOucBonjourRecord & XrdOucBonjourRecord::operator=(const XrdOucBonjourRecord &other)
00119 {
00120    if (this != &other) {
00121       ServiceName.assign(other.ServiceName, 0);
00122       RegisteredType.assign(other.RegisteredType, 0);
00123       ReplyDomain.assign(other.ReplyDomain, 0);
00124       TXTRecordDeallocate(&TXTRecord);
00125       InitTXTRecord();
00126       CopyTXTRecord(other.TXTRecord);
00127    }
00128 
00129    return *this;
00130 }
00131 
00132 void XrdOucBonjourRecord::Print() const
00133 {
00134    XrdLog.Say("INFO: Bonjour RECORD = ", GetServiceName(), GetRegisteredType(), GetReplyDomain());
00135    XrdLog.Say("INFO: Bonjour TXT = ", GetTXTRecordData());
00136 }
00137 
00138 void XrdOucBonjourRecord::AddRawTXTRecord(const char * rawData)
00139 {
00140    uint16_t i = 0, len;
00141    char key[256];
00142    uint8_t valueLen;
00143    const void * value;
00144 
00145    TXTRecordDeallocate(&TXTRecord);
00146    InitTXTRecord();
00147 
00148    len = strlen(rawData);
00149    while (TXTRecordGetItemAtIndex(len, rawData, i, 256, key, &valueLen, &value) != kDNSServiceErr_Invalid) {
00150       TXTRecordSetValue(&TXTRecord, key, valueLen, value);
00151       i++;
00152    }
00153 }
00154 
00155 void XrdOucBonjourRecord::InitTXTRecord()
00156 {
00157    TXTRecordCreate(&TXTRecord, 0, NULL);
00158 }
00159 
00160 void XrdOucBonjourRecord::CopyTXTRecord(const TXTRecordRef &otherRecord)
00161 {
00162    uint16_t i = 0, len;
00163    const void * rawTXT;
00164    char key[256];
00165    uint8_t valueLen;
00166    const void * value;
00167 
00168    len = TXTRecordGetLength(&otherRecord);
00169    rawTXT = TXTRecordGetBytesPtr(&otherRecord);
00170    while (TXTRecordGetItemAtIndex(len, rawTXT, i, 256, key, &valueLen, &value) != kDNSServiceErr_Invalid) {
00171       TXTRecordSetValue(&TXTRecord, key, valueLen, value);
00172       i++;
00173    }
00174 }
00175 
00176 const char * XrdOucBonjourRecord::GetTXTValue(const char * key, int &valueLen) const
00177 {
00178    uint16_t len;
00179    uint8_t valLen;
00180    const void * rawTXT;
00181 
00182    len = TXTRecordGetLength(&TXTRecord);
00183    rawTXT = TXTRecordGetBytesPtr(&TXTRecord);
00184 
00185    // Copy the results.
00186    rawTXT = TXTRecordGetValuePtr(len, rawTXT, key, &valLen);
00187    valueLen = valLen;
00188 
00189    return (const char *)rawTXT;
00190 }
00191 
00192 /******************************************************************************/
00193 /*                          B o n j o u r   n o d e                           */
00194 /******************************************************************************/
00195 
00196 void XrdOucBonjourNode::SetHostName(const char * hostName)
00197 {
00198    HostName.assign(hostName, 0);
00199 }
00200 
00201 void XrdOucBonjourNode::SetPort(unsigned short port)
00202 {
00203    Port = port;
00204 }
00205 
00206 void XrdOucBonjourNode::SetBonjourRecord(const XrdOucBonjourRecord &record)
00207 {
00208    BonjourInfo = record;
00209 }
00210 
00211 XrdOucBonjourNode & XrdOucBonjourNode::operator=(const XrdOucBonjourNode &other)
00212 {
00213    if (this != &other) {
00214       HostName.assign(other.HostName, 0);
00215       Port = other.Port;
00216       BonjourInfo = other.BonjourInfo;
00217    }
00218 
00219    return *this;
00220 }
00221 
00222 void XrdOucBonjourNode::Print() const
00223 {
00224    char port[36];
00225    snprintf(port, 36, "%d (%p)", GetPort(), this);
00226    const char *host = GetHostName() ? GetHostName() : "<empty>";
00227    XrdLog.Say("INFO: Bonjour NODE = ", host, ":", port);
00228    GetBonjourRecord().Print();
00229 }
00230 
00231 /******************************************************************************/
00232 /*                      A b s t r a c t   f a c t o r y                       */
00233 /******************************************************************************/
00234 
00235 XrdOucBonjourFactory *XrdOucBonjourFactory::FactoryByPlatform()
00236 {
00237    // Construct a factory object depending on the plaform we are running. This
00238    // is resolved at compilation time, so it is fast, but static.
00239    // There is room to improvement here, refining how we detect the operating
00240    // system and taking into account how to deal with Windows, since there is a
00241    // project to port Avahi to Win32 (natively) and mDNS is currently supported.
00242 #if defined(__macos__)  // We are on Mac OS X, so load the mDNS version.
00243    return new XrdOucAppleBonjourFactory();
00244 #elif defined(__linux__) // We are on GNU/Linux, so load the Avahi version.
00245    return new XrdOucAvahiBonjourFactory();
00246 #else // Currently, Windows is not supported (altough with mDNS can be).
00247    return NULL;
00248 #endif
00249 }

Generated on Tue Jul 5 14:46:48 2011 for ROOT_528-00b_version by  doxygen 1.5.1