XrdClientUrlSet.cc

Go to the documentation of this file.
00001 //////////////////////////////////////////////////////////////////////////
00002 //                                                                      //
00003 // XrdClientUrlSet                                                      // 
00004 //                                                                      //
00005 // Author: Fabrizio Furano (INFN Padova, 2004)                          //
00006 // Adapted from TXNetFile (root.cern.ch) originally done by             //
00007 // Alvise Dorigo, Fabrizio Furano, INFN Padova, 2003                    //
00008 // Revised by G. Ganis, CERN, June 2005                                 //
00009 //                                                                      //
00010 // A container for multiple urls to be resolved through DNS aliases     //
00011 //                                                                      //
00012 //////////////////////////////////////////////////////////////////////////
00013 
00014 //         $Id: XrdClientUrlSet.cc 30949 2009-11-02 16:37:58Z ganis $
00015 
00016 const char *XrdClientUrlSetCVSID = "$Id: XrdClientUrlSet.cc 30949 2009-11-02 16:37:58Z ganis $";
00017 
00018 #include <XrdClient/XrdClientUrlSet.hh>
00019 #include "XrdClient/XrdClientUrlInfo.hh"
00020 #include <XrdNet/XrdNetDNS.hh>
00021 #include "XrdSys/XrdSysHeaders.hh"
00022 
00023 #include <math.h>
00024 #include <stdio.h>
00025 #include <ctype.h>               // needed by isdigit()
00026 #ifndef WIN32
00027 #include <netdb.h>               // needed by getservbyname()
00028 #include <netinet/in.h>          // needed by ntohs()
00029 
00030 #include <stdlib.h>
00031 #include <resolv.h>
00032 #include <sys/time.h>
00033 #include <unistd.h>
00034 #else
00035 #include <stdlib.h>
00036 #include "XrdSys/XrdWin32.hh"
00037 #include <process.h>
00038 #endif
00039 
00040 #include "XrdClient/XrdClientDebug.hh"
00041 
00042 #ifdef __solaris__
00043 #include <sunmath.h>
00044 #endif
00045 
00046 
00047 using namespace std;
00048 
00049 
00050 //_____________________________________________________________________________
00051 XrdOucString XrdClientUrlSet::GetServers()
00052 {
00053    // Returns the final resolved list of servers
00054    XrdOucString s;
00055 
00056    for ( int i = 0; i < fUrlArray.GetSize(); i++ ) {
00057       s += fUrlArray[i]->Host;
00058       s += "\n";
00059    }
00060 
00061    return s;
00062 }
00063 
00064 //_____________________________________________________________________________
00065 double XrdClientUrlSet::GetRandom(int i)
00066 {
00067 //  Machine independent random number generator.
00068 //  Produces uniformly-distributed floating points between 0 and 1.
00069 //  Identical sequence on all machines of >= 32 bits.
00070 //  Periodicity = 10**8
00071 //  Universal version (Fred James 1985).
00072 //  generates a number in ]0,1]
00073 
00074    const double kCONS = 4.6566128730774E-10;
00075    const int kMASK24  = 2147483392;
00076 
00077    fSeed *= 69069;      
00078    unsigned int jy = (fSeed&kMASK24); // Set lower 8 bits to zero to assure exact float
00079    if (jy) return kCONS*jy;
00080    return GetRandom();
00081 }
00082 
00083 //_____________________________________________________________________________
00084 XrdClientUrlSet::XrdClientUrlSet(XrdOucString urls) : fIsValid(TRUE)
00085 {
00086    // A container for multiple urls.
00087    // It creates an array of multiple urls parsing the argument 'urls' and
00088    // resolving the DNS aliases
00089    //
00090    // 'urls' MUST be in the form:
00091    //
00092    //             [proto://][user1@]host1:port1[,[user2@]host2:port2, ... ,
00093    //                       [userN@]hostN:portN]]/pathfile
00094    //
00095    // Using the method GetNextUrl() the user can obtain the next
00096    // XrdClientUrlInfo object pointer in the array (the array is cyclic).
00097    // Using the method GetARandomUrl() the user can obtain a random 
00098    // XrdClientUrlInfo from the array.
00099    //
00100    UrlArray urlArray;
00101    XrdOucString listOfMachines;
00102    XrdOucString proto;
00103    XrdOucString file;
00104    Info(XrdClientDebug::kHIDEBUG, "XrdClientUrlSet", "parsing: "<<urls);
00105 
00106    // Disentangle the protocol, if any
00107    int p1 = 0, p2 = STR_NPOS, left = urls.length();
00108    if ((p2 = urls.find("://")) != STR_NPOS) {
00109       proto.assign(urls, p1, p2-1);
00110       p1 = p2 + 3;
00111       left = urls.length() - p1;
00112    }
00113    Info(XrdClientDebug::kHIDEBUG,"XrdClientUrlSet", "protocol: "<<proto);
00114 
00115    // Locate the list of machines in the input string
00116    if ((p2 = urls.find('/', p1)) != STR_NPOS) {
00117       listOfMachines.assign(urls, p1, p2-1);
00118       p1 = p2+1;
00119       left = urls.length() - p1;
00120    } else {
00121       listOfMachines.assign(urls, p1);
00122       left = 0;
00123    }
00124 
00125    // Nothing to do, if an empty list was found
00126    if (listOfMachines.length() <= 0) {
00127       Error("XrdClientUrlSet", "list of hosts, ports is empty" );
00128       fIsValid = FALSE;
00129       return;
00130    }
00131 
00132    // Get pathfile
00133    if (left > 0)
00134      file.assign(urls, p1);
00135    Info(XrdClientDebug::kHIDEBUG,"XrdClientUrlSet", "file: "<<file);
00136 
00137    // Init of the random number generator
00138    fSeed = getpid();
00139 
00140    //
00141    // We assume the protol is "root://", because this 
00142    // must be the protocol for
00143    //
00144    if ( (proto != "xroot") && ( proto != "root" ) ) {
00145       Error("XrdClientUrlSet", "This is not a root or xroot protocol: "<<proto );
00146       fIsValid = FALSE;
00147       return;
00148    }
00149 
00150    // remove trailing "," that would introduce a null host
00151    while ((listOfMachines.endswith(',')) || (listOfMachines.endswith(' ')))
00152       listOfMachines.erasefromend(1);
00153 
00154    // remove leading "," that would introduce a null host
00155    while (listOfMachines.beginswith(','))
00156       listOfMachines.erasefromstart(1);
00157 
00158    Info(XrdClientDebug::kHIDEBUG,"XrdClientUrlSet",
00159         "list of [host:port] : "<<listOfMachines);
00160 
00161    //
00162    // Set fPathName
00163    //
00164    fPathName = file;
00165 
00166    // If at this point we have a strange pathfile, then it's bad
00167    if ( (fPathName.length() <= 1) || (fPathName == "/") ) {
00168       Error("XrdClientUrlSet", "malformed pathfile " << fPathName);
00169       fIsValid = FALSE;
00170       return;
00171    }
00172 
00173    Info(XrdClientDebug::kHIDEBUG, "XrdClientUrlSet", "Remote file to open is '" <<
00174         fPathName << "'");
00175  
00176    if (fIsValid) {
00177       //
00178       // Parse list
00179       XrdOucString entity;
00180       int from = 0;
00181       while ((from = listOfMachines.tokenize(entity, from, ',')) != STR_NPOS) {
00182          // Convert to UrlInfo format
00183          Info(XrdClientDebug::kDUMPDEBUG,"XrdClientUrlSet",
00184                                          "parsing entity: "<<entity);
00185          ConvertDNSAlias(fUrlArray, proto, entity, file);
00186       }
00187 
00188       if (fUrlArray.GetSize() <= 0)
00189          fIsValid = FALSE;
00190 
00191       if (XrdClientDebug::Instance()->GetDebugLevel() >=
00192           XrdClientDebug::kUSERDEBUG)
00193          ShowUrls();
00194    }
00195 
00196 }
00197 
00198 //_____________________________________________________________________________
00199 XrdClientUrlSet::~XrdClientUrlSet()
00200 {
00201    fTmpUrlArray.Clear();
00202 
00203    for( int i=0; i < fUrlArray.GetSize(); i++)
00204       delete fUrlArray[i];
00205 
00206    fUrlArray.Clear();
00207 }
00208 
00209 //_____________________________________________________________________________
00210 XrdClientUrlInfo *XrdClientUrlSet::GetNextUrl()
00211 {
00212    // Returns the next url object pointer in the array.
00213    // After the last object is returned, the array is rewind-ed.
00214    // Now implemented as a pick from the tmpUrlArray queue
00215 
00216    XrdClientUrlInfo *retval;
00217 
00218    if ( !fTmpUrlArray.GetSize() ) Rewind();
00219 
00220    retval = fTmpUrlArray.Pop_back();
00221 
00222    return retval;
00223 }
00224 
00225 //_____________________________________________________________________________
00226 void XrdClientUrlSet::Rewind()
00227 {
00228    // Rebuilds tmpUrlArray, i..e the urls that have to be picked
00229    fTmpUrlArray.Clear();
00230 
00231    for(int i=0; i <= fUrlArray.GetSize()-1; i++)
00232       fTmpUrlArray.Push_back( fUrlArray[i] );
00233 }
00234 
00235 //_____________________________________________________________________________
00236 XrdClientUrlInfo *XrdClientUrlSet::GetARandomUrl()
00237 {
00238    XrdClientUrlInfo *retval;
00239    int rnd;
00240 
00241    if (!fTmpUrlArray.GetSize()) Rewind();
00242 
00243    // If the urlarray is still empty, just exits
00244    if (!fTmpUrlArray.GetSize()) return 0;
00245    
00246    for (int i=0; i < 10; i++)
00247       rnd = static_cast<int>(GetRandom() * fTmpUrlArray.GetSize()) % fTmpUrlArray.GetSize();
00248 
00249    // Returns a random url from the ones that have to be picked
00250    // When all the urls have been picked, we restart from the full url set
00251 
00252    retval = fTmpUrlArray[rnd];
00253    fTmpUrlArray.Erase(rnd);
00254 
00255    return retval;
00256 }
00257 
00258 
00259 //_____________________________________________________________________________
00260 XrdClientUrlInfo *XrdClientUrlSet::GetARandomUrl(unsigned int seed)
00261 {
00262    XrdClientUrlInfo *retval;
00263 
00264    if (!fTmpUrlArray.GetSize()) Rewind();
00265 
00266    // If the urlarray is still empty, just exits
00267    if (!fTmpUrlArray.GetSize()) return 0;
00268    
00269    // When all the urls have been picked, we restart from the full url set
00270 
00271    int rnd = seed % fTmpUrlArray.GetSize();
00272    retval = fTmpUrlArray[rnd];
00273    fTmpUrlArray.Erase(rnd);
00274 
00275    return retval;
00276 }
00277 
00278 //_____________________________________________________________________________
00279 void XrdClientUrlSet::EraseUrl(XrdClientUrlInfo *url)
00280 {
00281    // Eliminates url from the list
00282 
00283    for(int i=0; i < fUrlArray.GetSize(); i++) {
00284       if (url == fUrlArray[i]) {
00285          fUrlArray.Erase(i);
00286          Info(XrdClientDebug::kHIDEBUG, "EraseUrl",
00287                                         " url found and dropped from the list");
00288          return;
00289       }
00290    }
00291    Info(XrdClientDebug::kHIDEBUG, "EraseUrl", " url NOT found in the list");
00292 }
00293 
00294 //_____________________________________________________________________________
00295 void XrdClientUrlSet::ShowUrls()
00296 {
00297    // Prints the list of urls
00298 
00299    Info(XrdClientDebug::kUSERDEBUG, "ShowUrls",
00300         "The converted URLs count is " << fUrlArray.GetSize() );
00301 
00302    for(int i=0; i < fUrlArray.GetSize(); i++)
00303       Info(XrdClientDebug::kUSERDEBUG, "ShowUrls",
00304            "URL n." << i+1 << ": "<< fUrlArray[i]->GetUrl() << "."); 
00305 
00306 }
00307 
00308 //_____________________________________________________________________________
00309 void XrdClientUrlSet::CheckPort(int &port)
00310 {
00311    // Checks the validity of port in the given host[:port]
00312    // Eventually completes the port if specified in the services file
00313 
00314    if (port <= 0) {
00315 
00316       // Port not specified
00317       Info(XrdClientDebug::kHIDEBUG, "CheckPort",
00318            "TCP port not specified: trying /etc/services ...");
00319 
00320       struct servent *svc = getservbyname("rootd", "tcp");
00321 
00322       if (svc <= 0) {
00323          Info(XrdClientDebug::kHIDEBUG, "CheckPort",
00324               "service rootd not specified in /etc/services;" <<
00325               "using default IANA tcp port 1094");
00326          port= 1094;
00327 
00328       } else {
00329          port = ntohs(svc->s_port);
00330          Info(XrdClientDebug::kHIDEBUG, "CheckPort",
00331               "found tcp port " <<  port << "."); 
00332       }
00333 
00334    } else
00335       // Port is potentially valid
00336       Info(XrdClientDebug::kHIDEBUG, "CheckPort",
00337           "specified port (" <<  port << ") potentially valid."); 
00338 }
00339 
00340 //_____________________________________________________________________________
00341 void XrdClientUrlSet::ConvertDNSAlias(UrlArray& urls, XrdOucString proto, 
00342                                       XrdOucString host, XrdOucString file)
00343 {
00344    // Create an XrdClientUrlInfo from protocol 'proto', remote host 'host',
00345    // file 'file' and add it to the array, after having resolved the DNS
00346    // information.
00347    bool hasPort;
00348    XrdOucString tmpaddr;
00349   
00350    XrdClientUrlInfo *newurl = new XrdClientUrlInfo(host);
00351    hasPort = (newurl->Port > 0);
00352 
00353    if (hasPort) {
00354       Info(XrdClientDebug::kHIDEBUG, "ConvertDNSAlias",
00355            "resolving " << newurl->Host << ":" << newurl->Port);
00356    } else
00357       Info(XrdClientDebug::kHIDEBUG, "ConvertDNSAlias",
00358            "resolving " << newurl->Host);
00359 
00360    // Make sure port is a reasonable number
00361    CheckPort(newurl->Port);
00362 
00363    // Resolv the DNS information
00364    char *haddr[10] = {0}, *hname[10] = {0};
00365    int naddr = XrdNetDNS::getAddrName(newurl->Host.c_str(), 10, haddr, hname);
00366 
00367    // Fill the list
00368    int i = 0;
00369    for (; i < naddr; i++ ) {
00370 
00371       // Address
00372       newurl->HostAddr = (const char *) haddr[i];
00373 
00374       // Name
00375       newurl->Host = (const char *) hname[i];
00376 
00377       // Protocol
00378       newurl->Proto = proto;
00379 
00380       // File
00381       newurl->File = file;
00382 
00383       // Add to the list
00384       urls.Push_back(newurl);
00385       
00386       // Notify
00387       Info(XrdClientDebug::kHIDEBUG, "ConvertDNSAlias",
00388           "found host " << newurl->Host << " with addr " << newurl->HostAddr);
00389 
00390       // Get a copy, if we need to store another 
00391       if (i < (naddr-1))
00392          newurl = new XrdClientUrlInfo(*newurl);
00393 
00394       // Cleanup 
00395       if (haddr[i]) free(haddr[i]);
00396       if (hname[i]) free(hname[i]);
00397    }
00398 }

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