00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
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>
00026 #ifndef WIN32
00027 #include <netdb.h>
00028 #include <netinet/in.h>
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
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
00068
00069
00070
00071
00072
00073
00074 const double kCONS = 4.6566128730774E-10;
00075 const int kMASK24 = 2147483392;
00076
00077 fSeed *= 69069;
00078 unsigned int jy = (fSeed&kMASK24);
00079 if (jy) return kCONS*jy;
00080 return GetRandom();
00081 }
00082
00083
00084 XrdClientUrlSet::XrdClientUrlSet(XrdOucString urls) : fIsValid(TRUE)
00085 {
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097
00098
00099
00100 UrlArray urlArray;
00101 XrdOucString listOfMachines;
00102 XrdOucString proto;
00103 XrdOucString file;
00104 Info(XrdClientDebug::kHIDEBUG, "XrdClientUrlSet", "parsing: "<<urls);
00105
00106
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
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
00126 if (listOfMachines.length() <= 0) {
00127 Error("XrdClientUrlSet", "list of hosts, ports is empty" );
00128 fIsValid = FALSE;
00129 return;
00130 }
00131
00132
00133 if (left > 0)
00134 file.assign(urls, p1);
00135 Info(XrdClientDebug::kHIDEBUG,"XrdClientUrlSet", "file: "<<file);
00136
00137
00138 fSeed = getpid();
00139
00140
00141
00142
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
00151 while ((listOfMachines.endswith(',')) || (listOfMachines.endswith(' ')))
00152 listOfMachines.erasefromend(1);
00153
00154
00155 while (listOfMachines.beginswith(','))
00156 listOfMachines.erasefromstart(1);
00157
00158 Info(XrdClientDebug::kHIDEBUG,"XrdClientUrlSet",
00159 "list of [host:port] : "<<listOfMachines);
00160
00161
00162
00163
00164 fPathName = file;
00165
00166
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
00179 XrdOucString entity;
00180 int from = 0;
00181 while ((from = listOfMachines.tokenize(entity, from, ',')) != STR_NPOS) {
00182
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
00213
00214
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
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
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
00250
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
00267 if (!fTmpUrlArray.GetSize()) return 0;
00268
00269
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
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
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
00312
00313
00314 if (port <= 0) {
00315
00316
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
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
00345
00346
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
00361 CheckPort(newurl->Port);
00362
00363
00364 char *haddr[10] = {0}, *hname[10] = {0};
00365 int naddr = XrdNetDNS::getAddrName(newurl->Host.c_str(), 10, haddr, hname);
00366
00367
00368 int i = 0;
00369 for (; i < naddr; i++ ) {
00370
00371
00372 newurl->HostAddr = (const char *) haddr[i];
00373
00374
00375 newurl->Host = (const char *) hname[i];
00376
00377
00378 newurl->Proto = proto;
00379
00380
00381 newurl->File = file;
00382
00383
00384 urls.Push_back(newurl);
00385
00386
00387 Info(XrdClientDebug::kHIDEBUG, "ConvertDNSAlias",
00388 "found host " << newurl->Host << " with addr " << newurl->HostAddr);
00389
00390
00391 if (i < (naddr-1))
00392 newurl = new XrdClientUrlInfo(*newurl);
00393
00394
00395 if (haddr[i]) free(haddr[i]);
00396 if (hname[i]) free(hname[i]);
00397 }
00398 }