/******************************************************************************/
/* */
/* X r d C l i e n t U r l S e t . c c */
/* */
/* Author: Fabrizio Furano (INFN Padova, 2004) */
/* Adapted from TXNetFile (root.cern.ch) originally done by */
/* Alvise Dorigo, Fabrizio Furano, INFN Padova, 2003 */
/* Revised by G. Ganis, CERN, June 2005 */
/* */
/* This file is part of the XRootD software suite. */
/* */
/* XRootD is free software: you can redistribute it and/or modify it under */
/* the terms of the GNU Lesser General Public License as published by the */
/* Free Software Foundation, either version 3 of the License, or (at your */
/* option) any later version. */
/* */
/* XRootD is distributed in the hope that it will be useful, but WITHOUT */
/* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or */
/* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public */
/* License for more details. */
/* */
/* You should have received a copy of the GNU Lesser General Public License */
/* along with XRootD in a file called COPYING.LESSER (LGPL license) and file */
/* COPYING (GPL license). If not, see . */
/* */
/* The copyright holder's institutional names and contributor's names may not */
/* be used to endorse or promote products derived from this software without */
/* specific prior written permission of the institution or contributor. */
/******************************************************************************/
//////////////////////////////////////////////////////////////////////////
// //
// A container for multiple urls to be resolved through DNS aliases //
// //
//////////////////////////////////////////////////////////////////////////
#include "XrdClient/XrdClientUrlSet.hh"
#include "XrdClient/XrdClientUrlInfo.hh"
#include "XrdSys/XrdSysDNS.hh"
#include "XrdSys/XrdSysHeaders.hh"
#include
#include
#include // needed by isdigit()
#ifndef WIN32
#include // needed by getservbyname()
#include // needed by ntohs()
#include
#include
#include
#include
#else
#include
#include "XrdSys/XrdWin32.hh"
#include
#endif
#include "XrdClient/XrdClientDebug.hh"
#ifdef __solaris__
#include
#endif
using namespace std;
//_____________________________________________________________________________
XrdOucString XrdClientUrlSet::GetServers()
{
// Returns the final resolved list of servers
XrdOucString s;
for ( int i = 0; i < fUrlArray.GetSize(); i++ ) {
s += fUrlArray[i]->Host;
s += "\n";
}
return s;
}
//_____________________________________________________________________________
double XrdClientUrlSet::GetRandom(int i)
{
// Machine independent random number generator.
// Produces uniformly-distributed floating points between 0 and 1.
// Identical sequence on all machines of >= 32 bits.
// Periodicity = 10**8
// Universal version (Fred James 1985).
// generates a number in ]0,1]
const double kCONS = 4.6566128730774E-10;
const int kMASK24 = 2147483392;
fSeed *= 69069;
unsigned int jy = (fSeed&kMASK24); // Set lower 8 bits to zero to assure exact float
if (jy) return kCONS*jy;
return GetRandom();
}
//_____________________________________________________________________________
XrdClientUrlSet::XrdClientUrlSet(XrdOucString urls) : fIsValid(TRUE)
{
// A container for multiple urls.
// It creates an array of multiple urls parsing the argument 'urls' and
// resolving the DNS aliases
//
// 'urls' MUST be in the form:
//
// [proto://][user1@]host1:port1[,[user2@]host2:port2, ... ,
// [userN@]hostN:portN]]/pathfile
//
// Using the method GetNextUrl() the user can obtain the next
// XrdClientUrlInfo object pointer in the array (the array is cyclic).
// Using the method GetARandomUrl() the user can obtain a random
// XrdClientUrlInfo from the array.
//
UrlArray urlArray;
XrdOucString listOfMachines;
XrdOucString proto;
XrdOucString file;
Info(XrdClientDebug::kHIDEBUG, "XrdClientUrlSet", "parsing: "< 0)
file.assign(urls, p1);
Info(XrdClientDebug::kHIDEBUG,"XrdClientUrlSet", "file: "<GetDebugLevel() >=
XrdClientDebug::kUSERDEBUG)
ShowUrls();
}
}
//_____________________________________________________________________________
XrdClientUrlSet::~XrdClientUrlSet()
{
fTmpUrlArray.Clear();
for( int i=0; i < fUrlArray.GetSize(); i++)
delete fUrlArray[i];
fUrlArray.Clear();
}
//_____________________________________________________________________________
XrdClientUrlInfo *XrdClientUrlSet::GetNextUrl()
{
// Returns the next url object pointer in the array.
// After the last object is returned, the array is rewind-ed.
// Now implemented as a pick from the tmpUrlArray queue
XrdClientUrlInfo *retval;
if ( !fTmpUrlArray.GetSize() ) Rewind();
retval = fTmpUrlArray.Pop_back();
return retval;
}
//_____________________________________________________________________________
void XrdClientUrlSet::Rewind()
{
// Rebuilds tmpUrlArray, i..e the urls that have to be picked
fTmpUrlArray.Clear();
for(int i=0; i <= fUrlArray.GetSize()-1; i++)
fTmpUrlArray.Push_back( fUrlArray[i] );
}
//_____________________________________________________________________________
XrdClientUrlInfo *XrdClientUrlSet::GetARandomUrl()
{
XrdClientUrlInfo *retval;
int rnd = 0;
if (!fTmpUrlArray.GetSize()) Rewind();
// If the urlarray is still empty, just exits
if (!fTmpUrlArray.GetSize()) return 0;
for (int i=0; i < 10; i++)
rnd = static_cast(GetRandom() * fTmpUrlArray.GetSize()) % fTmpUrlArray.GetSize();
// Returns a random url from the ones that have to be picked
// When all the urls have been picked, we restart from the full url set
retval = fTmpUrlArray[rnd];
fTmpUrlArray.Erase(rnd);
return retval;
}
//_____________________________________________________________________________
XrdClientUrlInfo *XrdClientUrlSet::GetARandomUrl(unsigned int seed)
{
XrdClientUrlInfo *retval;
if (!fTmpUrlArray.GetSize()) Rewind();
// If the urlarray is still empty, just exits
if (!fTmpUrlArray.GetSize()) return 0;
// When all the urls have been picked, we restart from the full url set
int rnd = seed % fTmpUrlArray.GetSize();
retval = fTmpUrlArray[rnd];
fTmpUrlArray.Erase(rnd);
return retval;
}
//_____________________________________________________________________________
void XrdClientUrlSet::EraseUrl(XrdClientUrlInfo *url)
{
// Eliminates url from the list
for(int i=0; i < fUrlArray.GetSize(); i++) {
if (url == fUrlArray[i]) {
fUrlArray.Erase(i);
Info(XrdClientDebug::kHIDEBUG, "EraseUrl",
" url found and dropped from the list");
return;
}
}
Info(XrdClientDebug::kHIDEBUG, "EraseUrl", " url NOT found in the list");
}
//_____________________________________________________________________________
void XrdClientUrlSet::ShowUrls()
{
// Prints the list of urls
Info(XrdClientDebug::kUSERDEBUG, "ShowUrls",
"The converted URLs count is " << fUrlArray.GetSize() );
for(int i=0; i < fUrlArray.GetSize(); i++)
Info(XrdClientDebug::kUSERDEBUG, "ShowUrls",
"URL n." << i+1 << ": "<< fUrlArray[i]->GetUrl() << ".");
}
//_____________________________________________________________________________
void XrdClientUrlSet::CheckPort(int &port)
{
// Checks the validity of port in the given host[:port]
// Eventually completes the port if specified in the services file
if (port <= 0) {
// Port not specified
Info(XrdClientDebug::kHIDEBUG, "CheckPort",
"TCP port not specified: trying /etc/services ...");
struct servent *svc = getservbyname("rootd", "tcp");
if (!svc) {
Info(XrdClientDebug::kHIDEBUG, "CheckPort",
"service rootd not specified in /etc/services;" <<
"using default IANA tcp port 1094");
port= 1094;
} else {
port = ntohs(svc->s_port);
Info(XrdClientDebug::kHIDEBUG, "CheckPort",
"found tcp port " << port << ".");
}
} else
// Port is potentially valid
Info(XrdClientDebug::kHIDEBUG, "CheckPort",
"specified port (" << port << ") potentially valid.");
}
//_____________________________________________________________________________
void XrdClientUrlSet::ConvertDNSAlias(UrlArray& urls, XrdOucString proto,
XrdOucString host, XrdOucString file)
{
// Create an XrdClientUrlInfo from protocol 'proto', remote host 'host',
// file 'file' and add it to the array, after having resolved the DNS
// information.
bool hasPort;
XrdOucString tmpaddr;
XrdClientUrlInfo *newurl = new XrdClientUrlInfo(host);
hasPort = (newurl->Port > 0);
if (hasPort) {
Info(XrdClientDebug::kHIDEBUG, "ConvertDNSAlias",
"resolving " << newurl->Host << ":" << newurl->Port);
} else
Info(XrdClientDebug::kHIDEBUG, "ConvertDNSAlias",
"resolving " << newurl->Host);
// Make sure port is a reasonable number
CheckPort(newurl->Port);
// Resolv the DNS information
char *haddr[10] = {0}, *hname[10] = {0};
int naddr = XrdSysDNS::getAddrName(newurl->Host.c_str(), 10, haddr, hname);
// Fill the list
int i = 0;
for (; i < naddr; i++ ) {
// Address
newurl->HostAddr = (const char *) haddr[i];
// Name
newurl->Host = (const char *) hname[i];
// Protocol
newurl->Proto = proto;
// File
newurl->File = file;
// Add to the list
urls.Push_back(newurl);
// Notify
Info(XrdClientDebug::kHIDEBUG, "ConvertDNSAlias",
"found host " << newurl->Host << " with addr " << newurl->HostAddr);
// Get a copy, if we need to store another
if (i < (naddr-1))
newurl = new XrdClientUrlInfo(*newurl);
// Cleanup
if (haddr[i]) free(haddr[i]);
if (hname[i]) free(hname[i]);
}
}