XrdClientAdmin.cc

Go to the documentation of this file.
00001 //////////////////////////////////////////////////////////////////////////
00002 //                                                                      //
00003 // XrdClientAdmin                                                       //
00004 //                                                                      //
00005 // Author: Fabrizio Furano (INFN Padova, 2004)                          //
00006 // Adapted from XTNetAdmin (root.cern.ch) originally done by            //
00007 //  Alvise Dorigo, Fabrizio Furano                                      //
00008 //          INFN Padova, 2003                                           //
00009 //                                                                      //
00010 // A UNIX reference admin client for xrootd.                            //
00011 //                                                                      //
00012 //////////////////////////////////////////////////////////////////////////
00013 
00014 //       $Id: XrdClientAdmin.cc 38011 2011-02-08 18:35:57Z ganis $
00015 
00016 const char *XrdClientAdminCVSID = "$Id: XrdClientAdmin.cc 38011 2011-02-08 18:35:57Z ganis $";
00017 
00018 #include "XrdClient/XrdClientAdmin.hh"
00019 #include "XrdClient/XrdClientDebug.hh"
00020 #include "XrdClient/XrdClientUrlSet.hh"
00021 #include "XrdClient/XrdClientConn.hh"
00022 #include "XrdClient/XrdClientEnv.hh"
00023 #include "XrdClient/XrdClientConnMgr.hh"
00024 #include "XrdOuc/XrdOucTokenizer.hh"
00025 
00026 
00027 #include <stdio.h>
00028 #include <sys/types.h>
00029 #include <sys/stat.h>
00030 #include <fcntl.h>
00031 #ifndef WIN32
00032 #include <unistd.h>
00033 #include <strings.h>
00034 #include <netinet/in.h>
00035 #endif
00036 
00037 //_____________________________________________________________________________
00038 void joinStrings(XrdOucString &buf, vecString &vs,
00039                  int startidx, int endidx)
00040 {
00041 
00042   if (endidx < 0) endidx = vs.GetSize()-1;
00043 
00044   if (!vs.GetSize() || (vs.GetSize() <= startidx) ||
00045       (endidx < startidx) ){
00046     buf = "";
00047     return;
00048   }
00049 
00050   int lastidx = xrdmin(vs.GetSize()-1, endidx);
00051   
00052   for(int j=startidx; j <= lastidx; j++) {
00053     buf += vs[j];
00054     if (j < lastidx) buf += "\n";
00055   }
00056 
00057 }
00058 
00059 //_____________________________________________________________________________
00060 XrdClientAdmin::XrdClientAdmin(const char *url) {
00061 
00062 
00063   // Pick-up the latest setting of the debug level
00064   DebugSetLevel(EnvGetLong(NAME_DEBUG));
00065 
00066   if (!ConnectionManager)
00067     Info(XrdClientDebug::kUSERDEBUG,
00068          "",
00069          "(C) 2004-2010 by the Xrootd group. XrdClientAdmin " << XRD_CLIENT_VERSION);
00070 
00071    fInitialUrl = url;
00072 
00073    fConnModule = new XrdClientConn();
00074 
00075    if (!fConnModule) {
00076       Error("XrdClientAdmin",
00077             "Object creation failed.");
00078       abort();
00079    }
00080 
00081    // Set this instance as a handler for handling the consequences of a redirection
00082    fConnModule->SetRedirHandler(this);
00083 
00084 }
00085 
00086 //_____________________________________________________________________________
00087 XrdClientAdmin::~XrdClientAdmin()
00088 {
00089    delete fConnModule;
00090 }
00091 
00092 
00093 
00094 //_____________________________________________________________________________
00095 bool XrdClientAdmin::Connect()
00096 {
00097    // Connect to the server
00098 
00099    // Nothing to do if already connected
00100    if (fConnModule && fConnModule->IsConnected()) {
00101       return TRUE;
00102    }
00103 
00104    short locallogid;
00105   
00106    // Now we try to set up the first connection
00107    // We cycle through the list of urls given in fInitialUrl
00108   
00109    // Max number of tries
00110    int connectMaxTry = EnvGetLong(NAME_FIRSTCONNECTMAXCNT);
00111   
00112    // Construction of the url set coming from the resolution of the hosts given
00113    XrdClientUrlSet urlArray(fInitialUrl);
00114    if (!urlArray.IsValid()) {
00115       Error("Connect", "The URL provided is incorrect.");
00116       return FALSE;
00117    }
00118 
00119    // Set the max transaction duration
00120    fConnModule->SetOpTimeLimit(EnvGetLong(NAME_TRANSACTIONTIMEOUT));
00121 
00122    //
00123    // Now start the connection phase, picking randomly from UrlArray
00124    //
00125    urlArray.Rewind();
00126    locallogid = -1;
00127    int urlstried = 0;
00128    for (int connectTry = 0;
00129         (connectTry < connectMaxTry) && (!fConnModule->IsConnected()); 
00130         connectTry++) {
00131 
00132       XrdClientUrlInfo *thisUrl = 0;
00133       urlstried = (urlstried == urlArray.Size()) ? 0 : urlstried;
00134 
00135       if ( fConnModule->IsOpTimeLimitElapsed(time(0)) ) {
00136          // We have been so unlucky and wasted too much time in connecting and being redirected
00137          fConnModule->Disconnect(TRUE);
00138          Error("Connect", "Access to server failed: Too much time elapsed without success.");
00139          break;
00140       }
00141 
00142       bool nogoodurl = TRUE;
00143       while (urlArray.Size() > 0) {
00144      
00145          // Get an url from the available set
00146          if ((thisUrl = urlArray.GetARandomUrl())) {
00147 
00148             if (fConnModule->CheckHostDomain(thisUrl->Host)) {
00149                nogoodurl = FALSE;
00150                Info(XrdClientDebug::kHIDEBUG, "Connect", "Trying to connect to " <<
00151                                               thisUrl->Host << ":" << thisUrl->Port <<
00152                                               ". Connect try " << connectTry+1);
00153                locallogid = fConnModule->Connect(*thisUrl, this);
00154                // To find out if we have tried the whole URLs set
00155                urlstried++;
00156                break;
00157             } else {
00158                // Invalid domain: drop the url and move to next, if any
00159                urlArray.EraseUrl(thisUrl);
00160                continue;
00161             }
00162 
00163          }
00164       }
00165       if (nogoodurl) {
00166          Error("Connect", "Access denied to all URL domains requested");
00167          break;
00168       }
00169      
00170       // We are connected to a host. Let's handshake with it.
00171       if (fConnModule->IsConnected()) {
00172 
00173          // Now the have the logical Connection ID, that we can use as streamid for 
00174          // communications with the server
00175 
00176          Info(XrdClientDebug::kHIDEBUG, "Connect",
00177               "The logical connection id is " << fConnModule->GetLogConnID() <<
00178               ". This will be the streamid for this client");
00179 
00180          fConnModule->SetUrl(*thisUrl);
00181         
00182          Info(XrdClientDebug::kHIDEBUG, "Connect",
00183               "Working url is " << thisUrl->GetUrl());
00184         
00185          // after connection deal with server
00186          if (!fConnModule->GetAccessToSrv()) {
00187             if (fConnModule->LastServerError.errnum == kXR_NotAuthorized) {
00188                if (urlstried == urlArray.Size()) {
00189                   // Authentication error: we tried all the indicated URLs:
00190                   // does not make much sense to retry
00191                   fConnModule->Disconnect(TRUE);
00192                   XrdOucString msg(fConnModule->LastServerError.errmsg);
00193                   msg.erasefromend(1);
00194                   Error("Connect", "Authentication failure: " << msg);
00195                   connectTry = connectMaxTry;
00196                } else {
00197                   XrdOucString msg(fConnModule->LastServerError.errmsg);
00198                   msg.erasefromend(1);
00199                   Info(XrdClientDebug::kHIDEBUG, "Connect",
00200                                                  "Authentication failure: " << msg);
00201                }
00202             } else {
00203                Error("Connect", "Access to server failed: error: " <<
00204                                 fConnModule->LastServerError.errnum << " (" << 
00205                                 fConnModule->LastServerError.errmsg << ") - retrying.");
00206             }
00207          } else {
00208             Info(XrdClientDebug::kUSERDEBUG, "Connect", "Access to server granted.");
00209             break;
00210          }
00211       }
00212      
00213       // The server denied access. We have to disconnect.
00214       Info(XrdClientDebug::kHIDEBUG, "Connect", "Disconnecting.");
00215      
00216       fConnModule->Disconnect(FALSE);
00217      
00218       if (connectTry < connectMaxTry-1) {
00219 
00220          if (DebugLevel() >= XrdClientDebug::kUSERDEBUG)
00221             Info(XrdClientDebug::kUSERDEBUG, "Connect",
00222                  "Connection attempt failed. Sleeping " <<
00223                  EnvGetLong(NAME_RECONNECTWAIT) << " seconds.");
00224      
00225          sleep(EnvGetLong(NAME_RECONNECTWAIT));
00226 
00227       }
00228 
00229    } //for connect try
00230 
00231 
00232    if (!fConnModule->IsConnected()) {
00233       return FALSE;
00234    }
00235 
00236   
00237    //
00238    // Variable initialization
00239    // If the server is a new xrootd ( load balancer or data server)
00240    //
00241    if ((fConnModule->GetServerType() != kSTRootd) && 
00242        (fConnModule->GetServerType() != kSTNone)) {
00243       // Now we are connected to a server that didn't redirect us after the 
00244       // login/auth phase
00245 
00246       Info(XrdClientDebug::kUSERDEBUG, "Connect", "Connected.");
00247 
00248      
00249    } else {
00250       // We close the connection only if we do not know the server type.
00251       // In the rootd case the connection may be re-used later.
00252       if (fConnModule->GetServerType() == kSTNone)
00253          fConnModule->Disconnect(TRUE);
00254 
00255       return FALSE;
00256    }
00257 
00258    return TRUE;
00259 
00260 }
00261 
00262 
00263 
00264 //_____________________________________________________________________________
00265 bool XrdClientAdmin::Stat(const char *fname, long &id, long long &size, long &flags, long &modtime)
00266 {
00267    // Return file stat information. The interface and return value is
00268    // identical to TSystem::GetPathInfo().
00269 
00270    bool ok;
00271 
00272    // Set the max transaction duration
00273    fConnModule->SetOpTimeLimit(EnvGetLong(NAME_TRANSACTIONTIMEOUT));
00274 
00275    // asks the server for stat file informations
00276    ClientRequest statFileRequest;
00277 
00278    memset( &statFileRequest, 0, sizeof(ClientRequest) );
00279 
00280    fConnModule->SetSID(statFileRequest.header.streamid);
00281 
00282    statFileRequest.stat.requestid = kXR_stat;
00283 
00284    memset(statFileRequest.stat.reserved, 0,
00285           sizeof(statFileRequest.stat.reserved));
00286 
00287    statFileRequest.header.dlen = strlen(fname);
00288 
00289    char fStats[2048];
00290    id = 0;
00291    size = 0;
00292    flags = 0;
00293    modtime = 0;
00294 
00295    ok = fConnModule->SendGenCommand(&statFileRequest, (const char*)fname,
00296                                     NULL, fStats , FALSE, (char *)"Stat");
00297 
00298 
00299    if (ok && (fConnModule->LastServerResp.status == 0)) {
00300       if (fConnModule->LastServerResp.dlen >= 0)
00301          fStats[fConnModule->LastServerResp.dlen] = 0;
00302       else
00303          fStats[0] = 0;
00304       Info(XrdClientDebug::kHIDEBUG,
00305            "Stat", "Returned stats=" << fStats);
00306       sscanf(fStats, "%ld %lld %ld %ld", &id, &size, &flags, &modtime);
00307    }
00308 
00309    return ok;
00310 }
00311 
00312 
00313 
00314 //_____________________________________________________________________________
00315 bool XrdClientAdmin::Stat_vfs(const char *fname,
00316                               int &rwservers,
00317                               long long &rwfree,
00318                               int &rwutil,
00319                               int &stagingservers,
00320                               long long &stagingfree,
00321                               int &stagingutil)
00322 {
00323    // Return information for a virtual file system
00324 
00325    bool ok;
00326 
00327    // asks the server for stat file informations
00328    ClientRequest statFileRequest;
00329 
00330    // Set the max transaction duration
00331    fConnModule->SetOpTimeLimit(EnvGetLong(NAME_TRANSACTIONTIMEOUT));
00332 
00333    memset( &statFileRequest, 0, sizeof(ClientRequest) );
00334 
00335    fConnModule->SetSID(statFileRequest.header.streamid);
00336 
00337    statFileRequest.stat.requestid = kXR_stat;
00338 
00339    memset(statFileRequest.stat.reserved, 0,
00340           sizeof(statFileRequest.stat.reserved));
00341 
00342    statFileRequest.stat.options = kXR_vfs;
00343 
00344    statFileRequest.header.dlen = strlen(fname);
00345 
00346    char fStats[2048];
00347    rwservers = 0;
00348    rwfree = 0;
00349    rwutil = 0;
00350    stagingservers = 0;
00351    stagingfree = 0;
00352    stagingutil = 0;
00353 
00354 
00355    ok = fConnModule->SendGenCommand(&statFileRequest, (const char*)fname,
00356                                     NULL, fStats , FALSE, (char *)"Stat_vfs");
00357 
00358 
00359    if (ok && (fConnModule->LastServerResp.status == 0)) {
00360       if (fConnModule->LastServerResp.dlen >= 0)
00361          fStats[fConnModule->LastServerResp.dlen] = 0;
00362       else
00363          fStats[0] = 0;
00364       Info(XrdClientDebug::kHIDEBUG,
00365            "Stat_vfs", "Returned stats=" << fStats);
00366 
00367       sscanf(fStats, "%d %lld %d %d %lld %d", &rwservers, &rwfree, &rwutil,
00368              &stagingservers, &stagingfree, &stagingutil);
00369 
00370    }
00371 
00372    return ok;
00373 }
00374 
00375 
00376 //_____________________________________________________________________________
00377 bool XrdClientAdmin::SysStatX(const char *paths_list, kXR_char *binInfo)
00378 {
00379    XrdOucString pl(paths_list);
00380    bool ret;
00381    // asks the server for stat file informations
00382    ClientRequest statXFileRequest;
00383   
00384    // Set the max transaction duration
00385    fConnModule->SetOpTimeLimit(EnvGetLong(NAME_TRANSACTIONTIMEOUT));
00386 
00387    memset( &statXFileRequest, 0, sizeof(ClientRequest) );
00388    fConnModule->SetSID(statXFileRequest.header.streamid);
00389    statXFileRequest.header.requestid = kXR_statx;
00390 
00391    statXFileRequest.stat.dlen = pl.length();
00392   
00393    ret = fConnModule->SendGenCommand(&statXFileRequest, pl.c_str(),
00394                                      NULL, binInfo , FALSE, (char *)"SysStatX");
00395   
00396    return(ret);
00397 }
00398 
00399 //_____________________________________________________________________________
00400 bool XrdClientAdmin::ExistFiles(vecString &vs, vecBool &vb)
00401 {
00402    bool ret;
00403    XrdOucString buf;
00404    joinStrings(buf, vs);
00405 
00406    kXR_char *Info;
00407    Info = (kXR_char*) malloc(vs.GetSize()+10);
00408    memset((void *)Info, 0, vs.GetSize()+10);
00409   
00410    ret = this->SysStatX(buf.c_str(), Info);
00411 
00412    if (ret) for(int j=0; j <= vs.GetSize()-1; j++) {
00413          bool tmp = TRUE;
00414 
00415          if ( (*(Info+j) & kXR_isDir) || (*(Info+j) & kXR_other) ||
00416               (*(Info+j) & kXR_offline) )
00417                  tmp = FALSE;
00418 
00419          vb.Push_back(tmp);
00420       }
00421 
00422 
00423    free(Info);
00424 
00425    return ret;
00426 }
00427 
00428 //_____________________________________________________________________________
00429 bool XrdClientAdmin::ExistDirs(vecString &vs, vecBool &vb)
00430 {
00431    bool ret;
00432    XrdOucString buf;
00433    joinStrings(buf, vs);
00434 
00435    kXR_char *Info;
00436    Info = (kXR_char*) malloc(vs.GetSize()+10);
00437    memset((void *)Info, 0, vs.GetSize()+10);
00438   
00439    ret = this->SysStatX(buf.c_str(), Info);
00440   
00441    if (ret) for(int j=0; j <= vs.GetSize()-1; j++) {
00442       bool tmp;
00443 
00444       if( (*(Info+j) & kXR_isDir) ) {
00445          tmp = TRUE;
00446          vb.Push_back(tmp);
00447       } else {
00448          tmp = FALSE;
00449          vb.Push_back(tmp);
00450       }
00451 
00452    }
00453 
00454    free(Info);
00455 
00456    return ret;
00457 }
00458 
00459 //_____________________________________________________________________________
00460 bool XrdClientAdmin::IsFileOnline(vecString &vs, vecBool &vb)
00461 {
00462    bool ret;
00463    XrdOucString buf;
00464    joinStrings(buf, vs);
00465 
00466    kXR_char *Info;
00467    Info = (kXR_char*) malloc(vs.GetSize()+10);
00468    memset((void *)Info, 0, vs.GetSize()+10);
00469   
00470    ret = this->SysStatX(buf.c_str(), Info);
00471   
00472    if (ret) for(int j=0; j <= vs.GetSize()-1; j++) {
00473       bool tmp;
00474 
00475       if( !(*(Info+j) & kXR_offline) ) {
00476          tmp = TRUE;
00477          vb.Push_back(tmp);
00478       } else {
00479          tmp = FALSE;
00480          vb.Push_back(tmp);
00481       }
00482       
00483    }
00484 
00485    free(Info);
00486 
00487    return ret;
00488 }
00489 
00490 
00491 // Called by the conn module after a redirection has been succesfully handled
00492 //_____________________________________________________________________________
00493 bool XrdClientAdmin::OpenFileWhenRedirected(char *newfhandle, bool &wasopen) {
00494    // We simply do nothing...
00495    wasopen = FALSE;
00496    return TRUE;
00497 }
00498 
00499 //_____________________________________________________________________________
00500 bool XrdClientAdmin::Rmdir(const char *path) 
00501 {
00502    // Remove an empty remote directory
00503    ClientRequest rmdirFileRequest;
00504 
00505    // Set the max transaction duration
00506    fConnModule->SetOpTimeLimit(EnvGetLong(NAME_TRANSACTIONTIMEOUT));
00507 
00508    memset( &rmdirFileRequest, 0, sizeof(rmdirFileRequest) );
00509    fConnModule->SetSID(rmdirFileRequest.header.streamid);
00510    rmdirFileRequest.header.requestid = kXR_rmdir;
00511    rmdirFileRequest.header.dlen = strlen(path);
00512   
00513    return (fConnModule->SendGenCommand(&rmdirFileRequest, path, 
00514                                        NULL, NULL, FALSE, (char *)"Rmdir"));
00515 
00516 }
00517 
00518 //_____________________________________________________________________________
00519 bool XrdClientAdmin::Rm(const char *file) 
00520 {
00521    // Remove a remote file
00522    ClientRequest rmFileRequest;
00523 
00524    // Set the max transaction duration
00525    fConnModule->SetOpTimeLimit(EnvGetLong(NAME_TRANSACTIONTIMEOUT));
00526 
00527    memset( &rmFileRequest, 0, sizeof(rmFileRequest) );
00528    fConnModule->SetSID(rmFileRequest.header.streamid);
00529    rmFileRequest.header.requestid = kXR_rm;
00530    rmFileRequest.header.dlen = strlen(file);
00531   
00532    return (fConnModule->SendGenCommand(&rmFileRequest, file,
00533                                        NULL, NULL, FALSE, (char *)"Rm"));
00534 }
00535 
00536 //_____________________________________________________________________________
00537 bool XrdClientAdmin::Chmod(const char *file, int user, int group, int other)
00538 {
00539    // Change the permission of a remote file
00540    ClientRequest chmodFileRequest;
00541 
00542    // Set the max transaction duration
00543    fConnModule->SetOpTimeLimit(EnvGetLong(NAME_TRANSACTIONTIMEOUT));
00544 
00545    memset( &chmodFileRequest, 0, sizeof(chmodFileRequest) );
00546 
00547    fConnModule->SetSID(chmodFileRequest.header.streamid);
00548    chmodFileRequest.header.requestid = kXR_chmod;
00549 
00550    if(user  & 4) 
00551       chmodFileRequest.chmod.mode |= kXR_ur;
00552    if(user  & 2) 
00553       chmodFileRequest.chmod.mode |= kXR_uw;
00554    if(user  & 1) 
00555       chmodFileRequest.chmod.mode |= kXR_ux;
00556 
00557    if(group & 4) 
00558       chmodFileRequest.chmod.mode |= kXR_gr;
00559    if(group & 2)
00560       chmodFileRequest.chmod.mode |= kXR_gw;
00561    if(group & 1)
00562       chmodFileRequest.chmod.mode |= kXR_gx;
00563 
00564    if(other & 4)
00565       chmodFileRequest.chmod.mode |= kXR_or;
00566    if(other & 2)
00567       chmodFileRequest.chmod.mode |= kXR_ow;
00568    if(other & 1)
00569       chmodFileRequest.chmod.mode |= kXR_ox;
00570 
00571    chmodFileRequest.header.dlen = strlen(file);
00572   
00573   
00574    return (fConnModule->SendGenCommand(&chmodFileRequest, file,
00575                                        NULL, NULL, FALSE, (char *)"Chmod")); 
00576 
00577 }
00578 
00579 //_____________________________________________________________________________
00580 bool XrdClientAdmin::Mkdir(const char *dir, int user, int group, int other)
00581 {
00582    // Create a remote directory
00583    ClientRequest mkdirRequest;
00584 
00585    // Set the max transaction duration
00586    fConnModule->SetOpTimeLimit(EnvGetLong(NAME_TRANSACTIONTIMEOUT));
00587 
00588    memset( &mkdirRequest, 0, sizeof(mkdirRequest) );
00589 
00590    fConnModule->SetSID(mkdirRequest.header.streamid);
00591 
00592    mkdirRequest.header.requestid = kXR_mkdir;
00593 
00594    memset(mkdirRequest.mkdir.reserved, 0, 
00595           sizeof(mkdirRequest.mkdir.reserved));
00596 
00597    if(user  & 4) 
00598       mkdirRequest.mkdir.mode |= kXR_ur;
00599    if(user  & 2) 
00600       mkdirRequest.mkdir.mode |= kXR_uw;
00601    if(user  & 1) 
00602       mkdirRequest.mkdir.mode |= kXR_ux;
00603 
00604    if(group & 4) 
00605       mkdirRequest.mkdir.mode |= kXR_gr;
00606    if(group & 2)
00607       mkdirRequest.mkdir.mode |= kXR_gw;
00608    if(group & 1)
00609       mkdirRequest.mkdir.mode |= kXR_gx;
00610 
00611    if(other & 4)
00612       mkdirRequest.mkdir.mode |= kXR_or;
00613    if(other & 2)
00614       mkdirRequest.mkdir.mode |= kXR_ow;
00615    if(other & 1)
00616       mkdirRequest.mkdir.mode |= kXR_ox;
00617 
00618    mkdirRequest.mkdir.options[0] = kXR_mkdirpath;
00619 
00620    mkdirRequest.header.dlen = strlen(dir);
00621   
00622    return (fConnModule->SendGenCommand(&mkdirRequest, dir,
00623                                        NULL, NULL, FALSE, (char *)"Mkdir"));
00624 
00625 }
00626 
00627 //_____________________________________________________________________________
00628 bool XrdClientAdmin::Mv(const char *fileSrc, const char *fileDest)
00629 {
00630    bool ret;
00631 
00632    // Rename a remote file
00633    ClientRequest mvFileRequest;
00634 
00635    // Set the max transaction duration
00636    fConnModule->SetOpTimeLimit(EnvGetLong(NAME_TRANSACTIONTIMEOUT));
00637 
00638 
00639    memset( &mvFileRequest, 0, sizeof(mvFileRequest) );
00640 
00641    fConnModule->SetSID(mvFileRequest.header.streamid);
00642    mvFileRequest.header.requestid = kXR_mv;
00643 
00644    mvFileRequest.header.dlen = strlen( fileDest ) + strlen( fileSrc ) + 1; // len + len + string terminator \0
00645 
00646    char *data = new char[mvFileRequest.header.dlen+2]; // + 1 for space separator + 1 for \0
00647    memset(data, 0, mvFileRequest.header.dlen+2);
00648    strcpy( data, fileSrc );
00649    strcat( data, " " );
00650    strcat( data, fileDest );
00651   
00652    ret = fConnModule->SendGenCommand(&mvFileRequest, data,
00653                                      NULL, NULL, FALSE, (char *)"Mv");
00654 
00655    delete(data);
00656 
00657    return ret;
00658 }
00659 
00660 //_____________________________________________________________________________
00661 UnsolRespProcResult XrdClientAdmin::ProcessUnsolicitedMsg(XrdClientUnsolMsgSender *sender,
00662                                                           XrdClientMessage *unsolmsg)
00663 {
00664    // We are here if an unsolicited response comes from a logical conn
00665    // The response comes in the form of an TXMessage *, that must NOT be
00666    // destroyed after processing. It is destroyed by the first sender.
00667    // Remember that we are in a separate thread, since unsolicited 
00668    // responses are asynchronous by nature.
00669 
00670    if (unsolmsg->GetStatusCode() != XrdClientMessage::kXrdMSC_ok) {
00671         Info(XrdClientDebug::kHIDEBUG,
00672              "ProcessUnsolicitedMsg", "Incoming unsolicited communication error message." );
00673     }
00674     else {
00675         Info(XrdClientDebug::kHIDEBUG,
00676              "ProcessUnsolicitedMsg", "Incoming unsolicited response from streamid " <<
00677              unsolmsg->HeaderSID() );
00678     }
00679 
00680    // Local processing ....
00681    if (unsolmsg->IsAttn()) {
00682       struct ServerResponseBody_Attn *attnbody;
00683 
00684       attnbody = (struct ServerResponseBody_Attn *)unsolmsg->GetData();
00685 
00686       int actnum = (attnbody) ? (attnbody->actnum) : 0;
00687 
00688       // "True" async resp is processed here
00689       switch (actnum) {
00690 
00691       case kXR_asyncdi:
00692          // Disconnection + delayed reconnection request
00693 
00694          struct ServerResponseBody_Attn_asyncdi *di;
00695          di = (struct ServerResponseBody_Attn_asyncdi *)unsolmsg->GetData();
00696 
00697          // Explicit redirection request
00698          if (di) {
00699             Info(XrdClientDebug::kUSERDEBUG,
00700                  "ProcessUnsolicitedMsg", "Requested Disconnection + Reconnect in " <<
00701                  ntohl(di->wsec) << " seconds.");
00702 
00703             fConnModule->SetRequestedDestHost((char *)(fConnModule->GetCurrentUrl().Host.c_str()),
00704                                               fConnModule->GetCurrentUrl().Port);
00705             fConnModule->SetREQDelayedConnectState(ntohl(di->wsec));
00706          }
00707 
00708          // Other objects may be interested in this async resp
00709          return kUNSOL_CONTINUE;
00710          break;
00711          
00712       case kXR_asyncrd:
00713          // Redirection request
00714 
00715          struct ServerResponseBody_Attn_asyncrd *rd;
00716          rd = (struct ServerResponseBody_Attn_asyncrd *)unsolmsg->GetData();
00717 
00718          // Explicit redirection request
00719          if (rd && (strlen(rd->host) > 0)) {
00720             Info(XrdClientDebug::kUSERDEBUG,
00721                  "ProcessUnsolicitedMsg", "Requested redir to " << rd->host <<
00722                  ":" << ntohl(rd->port));
00723 
00724             fConnModule->SetRequestedDestHost(rd->host, ntohl(rd->port));
00725          }
00726 
00727          // Other objects may be interested in this async resp
00728          return kUNSOL_CONTINUE;
00729          break;
00730 
00731       case kXR_asyncwt:
00732          // Puts the client in wait state
00733 
00734          struct ServerResponseBody_Attn_asyncwt *wt;
00735          wt = (struct ServerResponseBody_Attn_asyncwt *)unsolmsg->GetData();
00736 
00737          if (wt) {
00738             Info(XrdClientDebug::kUSERDEBUG,
00739                  "ProcessUnsolicitedMsg", "Pausing client for " << ntohl(wt->wsec) <<
00740                  " seconds.");
00741 
00742             fConnModule->SetREQPauseState(ntohl(wt->wsec));
00743          }
00744 
00745          // Other objects may be interested in this async resp
00746          return kUNSOL_CONTINUE;
00747          break;
00748 
00749       case kXR_asyncgo:
00750          // Resumes from pause state
00751 
00752          Info(XrdClientDebug::kUSERDEBUG,
00753               "ProcessUnsolicitedMsg", "Resuming from pause.");
00754 
00755             fConnModule->SetREQPauseState(0);
00756 
00757          // Other objects may be interested in this async resp
00758          return kUNSOL_CONTINUE;
00759          break;
00760 
00761       case kXR_asynresp:
00762         // A response to a request which got a kXR_waitresp as a response
00763         
00764         // We pass it direcly to the connmodule for processing
00765         // The processing will tell if the streamid matched or not,
00766         // in order to stop further processing
00767         return fConnModule->ProcessAsynResp(unsolmsg);
00768         break;
00769 
00770       default:
00771 
00772         Info(XrdClientDebug::kUSERDEBUG,
00773               "ProcessUnsolicitedMsg", "Empty message");
00774 
00775         // Propagate the message
00776         return kUNSOL_CONTINUE;
00777 
00778       } // switch
00779 
00780       
00781    }
00782    else
00783        // Let's see if the message is a communication error message
00784        if (unsolmsg->GetStatusCode() != XrdClientMessage::kXrdMSC_ok)
00785            return fConnModule->ProcessAsynResp(unsolmsg);
00786 
00787 
00788    return kUNSOL_CONTINUE;
00789 }
00790 
00791 
00792 
00793 //_____________________________________________________________________________
00794 bool XrdClientAdmin::Protocol(kXR_int32 &proto, kXR_int32 &kind)
00795 {
00796    ClientRequest protoRequest;
00797 
00798    // Set the max transaction duration
00799    fConnModule->SetOpTimeLimit(EnvGetLong(NAME_TRANSACTIONTIMEOUT));
00800 
00801    memset( &protoRequest, 0, sizeof(protoRequest) );
00802 
00803    fConnModule->SetSID(protoRequest.header.streamid);
00804 
00805    protoRequest.header.requestid = kXR_protocol;
00806 
00807    char buf[8]; // For now 8 bytes are returned... in future could increase with more infos
00808    bool ret = fConnModule->SendGenCommand(&protoRequest, NULL,
00809                                           NULL, buf, FALSE, (char *)"Protocol");
00810   
00811    memcpy(&proto, buf, sizeof(proto));
00812    memcpy(&kind, buf + sizeof(proto), sizeof(kind));
00813 
00814    proto = ntohl(proto);
00815    kind  = ntohl(kind);
00816     
00817    return ret;
00818 }
00819 
00820 //_____________________________________________________________________________
00821 bool XrdClientAdmin::Prepare(vecString vs, kXR_char option, kXR_char prty)
00822 {
00823   // Send a bulk prepare request for a vector of paths
00824   // Split a huge prepare list into smaller chunks
00825 
00826    XrdOucString buf;
00827 
00828    // Set the max transaction duration
00829    fConnModule->SetOpTimeLimit(EnvGetLong(NAME_TRANSACTIONTIMEOUT));
00830 
00831    if (vs.GetSize() < 75) {
00832      joinStrings(buf, vs);
00833      return Prepare(buf.c_str(), option, prty);
00834    }
00835 
00836 
00837    for (int i = 0; i < vs.GetSize()+50; i+=50) {
00838      joinStrings(buf, vs, i, i+49);
00839 
00840      if (!Prepare(buf.c_str(), option, prty)) return false;
00841      buf = "";
00842    }
00843 
00844    return true;
00845 }
00846 
00847 //_____________________________________________________________________________
00848 bool XrdClientAdmin::Prepare(const char *buf, kXR_char option, kXR_char prty)
00849 {
00850    // Send a bulk prepare request for a '\n' separated list in buf
00851 
00852    ClientRequest prepareRequest;
00853 
00854    // Set the max transaction duration
00855    fConnModule->SetOpTimeLimit(EnvGetLong(NAME_TRANSACTIONTIMEOUT));
00856 
00857    memset( &prepareRequest, 0, sizeof(prepareRequest) );
00858 
00859    fConnModule->SetSID(prepareRequest.header.streamid);
00860 
00861    prepareRequest.header.requestid    = kXR_prepare;
00862    prepareRequest.prepare.options     = option;
00863    prepareRequest.prepare.prty        = prty;
00864 
00865    prepareRequest.header.dlen = strlen(buf);
00866 
00867    bool ret = fConnModule->SendGenCommand(&prepareRequest, buf,
00868                                           NULL, NULL , FALSE, (char *)"Prepare");
00869 
00870    return ret;
00871 }
00872 
00873 //_____________________________________________________________________________
00874 bool  XrdClientAdmin::DirList(const char *dir, vecString &entries, bool askallservers) {
00875    // Get an ls-like output with respect to the specified dir
00876 
00877    // If this is a redirector, we will be given the list of the servers
00878    //  which host this directory
00879    // If askallservers is true then we will just ask for the whole list of servers.
00880    //  the query will always be the same, and this will likely skip the 5s delay after the first shot
00881    //  The danger is to be forced to contact a huge number of servers in very big clusters
00882    //
00883    bool ret = true;
00884    XrdClientVector<XrdClientLocate_Info> hosts;
00885    if (askallservers && (fConnModule->GetServerProtocol() >= 0x291)) {
00886       char str[1024];
00887       strcpy(str, "*");
00888       strncat(str, dir, 1023);
00889       if (!Locate((kXR_char *)str, hosts)) return false;
00890    }
00891    else {
00892       XrdClientLocate_Info nfo;
00893       memset(&nfo, 0, sizeof(nfo));
00894       strcpy((char *)nfo.Location, GetCurrentUrl().HostWPort.c_str());
00895       hosts.Push_back(nfo);
00896    }
00897 
00898 
00899    // Then we cycle among them asking everyone
00900    bool foundsomething = false;
00901    for (int i = 0; i < hosts.GetSize(); i++) {
00902 
00903       fConnModule->Disconnect(false);
00904       XrdClientUrlInfo url((const char *)hosts[i].Location);
00905 
00906       url.Proto = "root";
00907 
00908       if (fConnModule->GoToAnotherServer(url) != kOK) {
00909          ret = false;
00910          break;
00911       }
00912 
00913       fConnModule->ClearLastServerError();
00914       if (!DirList_low(dir, entries))  {
00915          if (fConnModule->LastServerError.errnum != kXR_NotFound) {
00916             ret = false;
00917             break;
00918          }
00919       }
00920       else foundsomething = true;
00921 
00922 
00923    }
00924 
00925    // At the end we want to rewind to the main redirector in any case
00926    GoBackToRedirector();
00927 
00928    if (!foundsomething) ret = false;
00929    return ret;
00930 }
00931 
00932 //_____________________________________________________________________________
00933 bool  XrdClientAdmin::DirList(const char *dir,
00934                               XrdClientVector<XrdClientAdmin::DirListInfo> &dirlistinfo,
00935                               bool askallservers) {
00936    // Get an ls-like output with respect to the specified dir
00937    // Here we are also interested in the stat information for each file
00938 
00939    // If this is a redirector, we will be given the list of the servers
00940    //  which host this directory
00941    // If askallservers is true then we will just ask for the whole list of servers.
00942    //  the query will always be the same, and this will likely skip the 5s delay after the first shot
00943    //  The danger is to be forced to contact a huge number of servers in very big clusters
00944    //  If this is a concern, one should set askallservers to false
00945    //
00946    bool ret = true;
00947    vecString entries;
00948    XrdClientVector<XrdClientLocate_Info> hosts;
00949    XrdOucString fullpath;
00950 
00951    if (askallservers && (fConnModule->GetServerProtocol() >= 0x291)) {
00952       char str[1024];
00953       strcpy(str, "*");
00954       strncat(str, dir, 1023);
00955       if (!Locate((kXR_char *)str, hosts)) return false;
00956    }
00957    else {
00958       XrdClientLocate_Info nfo;
00959       memset(&nfo, 0, sizeof(nfo));
00960       strcpy((char *)nfo.Location, GetCurrentUrl().HostWPort.c_str());
00961       hosts.Push_back(nfo);
00962    }
00963 
00964 
00965    // Then we cycle among them asking everyone
00966    bool foundsomething = false;
00967    for (int i = 0; i < hosts.GetSize(); i++) {
00968 
00969       fConnModule->Disconnect(false);
00970       XrdClientUrlInfo url((const char *)hosts[i].Location);
00971       url.Proto = "root";
00972 
00973       if (fConnModule->GoToAnotherServer(url) != kOK) {
00974          ret = false;
00975          break;
00976       }
00977 
00978       fConnModule->ClearLastServerError();
00979 
00980       int precentries = entries.GetSize();
00981       if (!DirList_low(dir, entries)) {
00982          if ((fConnModule->LastServerError.errnum != kXR_NotFound) && (fConnModule->LastServerError.errnum != kXR_noErrorYet)) {
00983             ret = false;
00984             break;
00985          }
00986       }
00987       else foundsomething = true;
00988 
00989       int newentries = entries.GetSize();
00990 
00991       DirListInfo info;
00992       dirlistinfo.Resize(newentries);
00993 
00994       // Here we have the entries. We want to accumulate the stat information for each of them
00995       // We are still connected to the same server which gave the last dirlist response
00996       info.host = GetCurrentUrl().HostWPort;
00997       for (int k = precentries; k < newentries; k++) {
00998          info.fullpath = dir;
00999          if (info.fullpath[info.fullpath.length()-1] != '/') info.fullpath += "/";
01000          info.fullpath += entries[k];
01001          info.size = 0;
01002          info.id = 0;
01003          info.flags = 0;
01004          info.modtime = 0;
01005 
01006          if (!Stat(info.fullpath.c_str(),
01007                    info.id,
01008                    info.size,
01009                    info.flags,
01010                    info.modtime)) {
01011             ret = false;
01012             //break;
01013          }
01014 
01015          dirlistinfo[k] = info;
01016 
01017       }
01018 
01019    }
01020 
01021    // At the end we want to rewind to the main redirector in any case
01022    GoBackToRedirector();
01023 
01024    if (!foundsomething) ret = false;
01025    return ret;
01026  }
01027 
01028 
01029 
01030 
01031 
01032 //_____________________________________________________________________________
01033 bool  XrdClientAdmin::DirList_low(const char *dir, vecString &entries) {
01034    bool ret;
01035    // asks the server for the content of a directory
01036    ClientRequest DirListFileRequest;
01037    kXR_char *dl;
01038   
01039    // Set the max transaction duration
01040    fConnModule->SetOpTimeLimit(EnvGetLong(NAME_TRANSACTIONTIMEOUT));
01041 
01042    memset( &DirListFileRequest, 0, sizeof(ClientRequest) );
01043    fConnModule->SetSID(DirListFileRequest.header.streamid);
01044    DirListFileRequest.header.requestid = kXR_dirlist;
01045 
01046    DirListFileRequest.dirlist.dlen = strlen(dir);
01047   
01048    // Note that the connmodule has to dynamically alloc the space for the answer
01049    ret = fConnModule->SendGenCommand(&DirListFileRequest, dir,
01050                                      reinterpret_cast<void **>(&dl), 0, TRUE, (char *)"DirList");
01051   
01052    // Now parse the answer building the entries vector
01053    if (ret) {
01054 
01055       kXR_char *startp = dl, *endp = dl;
01056       char entry[1024];
01057       XrdOucString e;
01058 
01059       while (startp) {
01060 
01061          if ( (endp = (kXR_char *)strchr((const char*)startp, '\n')) ) {
01062             strncpy(entry, (char *)startp, endp-startp);
01063             entry[endp-startp] = 0;
01064             endp++;
01065          }
01066          else
01067             strcpy(entry, (char *)startp);
01068       
01069 
01070          if (strlen(entry) && strcmp((char *)entry, ".") && strcmp((char *)entry, "..")) {
01071             e = entry;
01072             entries.Push_back(e);
01073          }
01074 
01075 
01076          startp = endp;
01077       }
01078 
01079    
01080   
01081    }
01082 
01083    if (dl) free(dl);
01084    return(ret);
01085 
01086 }
01087 
01088 //_____________________________________________________________________________
01089 long XrdClientAdmin::GetChecksum(kXR_char *path, kXR_char **chksum)
01090 {
01091    ClientRequest chksumRequest;
01092 
01093    // Set the max transaction duration
01094    fConnModule->SetOpTimeLimit(EnvGetLong(NAME_TRANSACTIONTIMEOUT));
01095 
01096 
01097    memset( &chksumRequest, 0, sizeof(chksumRequest) );
01098 
01099    fConnModule->SetSID(chksumRequest.header.streamid);
01100 
01101    chksumRequest.query.requestid = kXR_query;
01102    chksumRequest.query.infotype = kXR_Qcksum;
01103    chksumRequest.query.dlen = strlen((char *) path);
01104 
01105    bool ret = fConnModule->SendGenCommand(&chksumRequest, (const char*) path,
01106                                           (void **)chksum, NULL, TRUE,
01107                                           (char *)"GetChecksum");
01108   
01109    if (ret) return (fConnModule->LastServerResp.dlen);
01110    else return 0;
01111 }
01112 
01113 int XrdClientAdmin::LocalLocate(kXR_char *path, XrdClientVector<XrdClientLocate_Info> &res,
01114                                 bool writable, int opts, bool all) {
01115   // Fires a locate req towards the currently connected server, and pushes the
01116   // results into the res vector
01117   //
01118   // If 'all' is false, returns the position in the vector of the found info (-1 if
01119   // not found); else returns the number of non-data servers.
01120 
01121    ClientRequest locateRequest;
01122 
01123    char *resp = 0;
01124    int retval = (all) ? 0 : -1;
01125 
01126    memset( &locateRequest, 0, sizeof(locateRequest) );
01127 
01128    fConnModule->SetSID(locateRequest.header.streamid);
01129 
01130    locateRequest.locate.requestid = kXR_locate;
01131    locateRequest.locate.options   = opts;
01132    locateRequest.locate.dlen = strlen((char *) path);
01133 
01134    // Resp is allocated inside the call
01135    bool ret = fConnModule->SendGenCommand(&locateRequest, (const char*) path,
01136                                           (void **)&resp, 0, true,
01137                                           (char *)"LocalLocate");
01138 
01139    if (!ret) return -2;
01140    if (!resp) return -1;
01141    if (!strlen(resp)) {
01142      free(resp);
01143      return -1;
01144    }
01145 
01146  
01147 
01148    // Parse the output
01149    XrdOucString rs(resp), s;
01150    free(resp);
01151    int from = 0;
01152    while ((from = rs.tokenize(s,from,' ')) != -1) {
01153 
01154       // If a token is bad, we keep the ones processed previously
01155       if (s.length() < 8 || (s[2] != '[') || (s[4] != ':')) {
01156          Error("LocalLocate", "Invalid server response. Resp: '" << s << "'");
01157          continue;
01158       }
01159 
01160       XrdClientLocate_Info nfo;
01161 
01162       // Info type
01163       switch (s[0]) {
01164       case 'S':
01165          nfo.Infotype = XrdClientLocate_Info::kXrdcLocDataServer;
01166          break;
01167       case 's':
01168          nfo.Infotype = XrdClientLocate_Info::kXrdcLocDataServerPending;
01169          break;
01170       case 'M':
01171          nfo.Infotype = XrdClientLocate_Info::kXrdcLocManager;
01172          break;
01173       case 'm':
01174          nfo.Infotype = XrdClientLocate_Info::kXrdcLocManagerPending;
01175          break;
01176       default:
01177          Info(XrdClientDebug::kNODEBUG, "LocalLocate",
01178                "Unknown info type: '" << s << "'");
01179       }
01180 
01181       // Write capabilities
01182       nfo.CanWrite = (s[1] == 'w') ? 1 : 0;
01183 
01184       // Endpoint url
01185       s.erase(0, s.find("[::")+3);
01186       s.replace("]","");
01187       strcpy((char *)nfo.Location, s.c_str());
01188 
01189       res.Push_back(nfo);
01190 
01191       if (nfo.Infotype == XrdClientLocate_Info::kXrdcLocDataServer) {
01192          if (!all) {
01193             if (!writable || nfo.CanWrite) {
01194                retval = res.GetSize() - 1;
01195                break;
01196             }
01197          }
01198       } else {
01199          if (all)
01200             // Count non-dataservers
01201             retval++;
01202       }
01203    }
01204 
01205    return retval;
01206 }
01207 
01208 
01209 //_____________________________________________________________________________
01210 bool XrdClientAdmin::Locate(kXR_char *path, XrdClientLocate_Info &resp, bool writable)
01211 {
01212    // Find out any exact location of file 'path' and save the corresponding
01213    // URL in resp.
01214    // Returns true if found
01215    // If the retval is false and writable==true , resp contains a non writable url
01216    //  if there is one
01217 
01218    bool found = false;
01219    memset(&resp, 0, sizeof(resp));
01220 
01221    if (!fConnModule) return 0;
01222    if (!fConnModule->IsConnected()) return 0;
01223 
01224    // Set the max transaction duration
01225    fConnModule->SetOpTimeLimit(EnvGetLong(NAME_TRANSACTIONTIMEOUT));
01226 
01227 
01228 
01229    // Old servers will use what's there
01230    if (fConnModule->GetServerProtocol() < 0x290) {
01231      long id, flags, modtime;
01232      long long size;
01233 
01234      bool ok = Stat((const char *)path, id, size, flags, modtime);
01235      if (ok && (fConnModule->LastServerResp.status == 0)) {
01236        resp.Infotype = XrdClientLocate_Info::kXrdcLocDataServer;
01237        resp.CanWrite = 1;
01238        strcpy((char *)resp.Location, fConnModule->GetCurrentUrl().HostWPort.c_str());
01239      }
01240      GoBackToRedirector();
01241      return ok;
01242    }
01243 
01244 
01245    XrdClientUrlInfo currurl(fConnModule->GetCurrentUrl().GetUrl());
01246    if (!currurl.HostWPort.length()) return 0;
01247 
01248    // Set up the starting point in the vectored queue
01249    XrdClientVector<XrdClientLocate_Info> hosts;
01250    XrdClientLocate_Info nfo;
01251    nfo.Infotype = XrdClientLocate_Info::kXrdcLocManager;
01252    nfo.CanWrite = true;
01253    strcpy((char *)nfo.Location, currurl.HostWPort.c_str());
01254    hosts.Push_back(nfo);
01255    bool firsthost = true;
01256    XrdClientLocate_Info currnfo;
01257 
01258    int pos = 0;
01259 
01260    // Expand a level, i.e. ask to all the masters and remove items from the list
01261    while  (pos < hosts.GetSize()) {
01262      
01263      // Take the first item to process
01264      currnfo = hosts[pos];
01265      
01266      // If it's a master, we have to contact it, otherwise take the next
01267      if ((currnfo.Infotype == XrdClientLocate_Info::kXrdcLocDataServer) ||
01268          (currnfo.Infotype == XrdClientLocate_Info::kXrdcLocDataServerPending)) {
01269        pos++;
01270        continue;
01271      }
01272      
01273      // Here, currnfo is pointing to a master we have to contact
01274      currurl.TakeUrl((char *)currnfo.Location);
01275      if (currurl.HostAddr == "") currurl.HostAddr = currurl.Host;
01276      
01277      // Connect to the given host. At the beginning we are connected to the starting point
01278      // A failed connection is just ignored. Only one attempt is performed. Timeouts are
01279      // honored.
01280      if (!firsthost) {
01281        fConnModule->Disconnect(false);
01282        if (fConnModule->GoToAnotherServer(currurl) != kOK) {
01283          hosts.Erase(pos);
01284          continue;
01285        }
01286      }
01287      
01288      if (firsthost) firsthost = false;
01289      
01290      // We are connected, do the locate
01291      int posds = LocalLocate(path, hosts, writable, kXR_nowait);
01292      
01293      found = (posds > -1) ? 1 : 0;
01294      
01295      if (found) {
01296        resp = hosts[posds];
01297        break;
01298      }
01299      
01300      // We did not finish, take the next
01301      hosts.Erase(pos);
01302    }
01303 
01304    if (!found && hosts.GetSize()) {
01305      // If not found, we check anyway in the remaining list
01306      // to pick a pending one if present
01307      for (int ii = 0; ii < hosts.GetSize(); ii++) {
01308        currnfo = hosts[ii];
01309        if ( (currnfo.Infotype == XrdClientLocate_Info::kXrdcLocDataServer) ||
01310             (currnfo.Infotype == XrdClientLocate_Info::kXrdcLocDataServerPending) ) {
01311              resp = currnfo;
01312              
01313              if (!writable || resp.CanWrite) {
01314                found = true;
01315                break;
01316              }
01317              
01318            }
01319 
01320 
01321      }
01322 
01323    }
01324 
01325    // At the end we want to rewind to the main redirector in any case
01326    GoBackToRedirector();
01327 
01328    return found;
01329 }
01330 
01331 
01332 //_____________________________________________________________________________
01333 bool XrdClientAdmin::Locate( kXR_char *path,
01334                              XrdClientVector<XrdClientLocate_Info> &hosts,
01335                              int opts )
01336 {
01337    // Find out any exact location of file 'path' and save the corresponding
01338    // URL in resp.
01339    // Returns true if found at least one
01340 
01341    hosts.Clear();
01342 
01343    if (!fConnModule) return 0;
01344    if (!fConnModule->IsConnected()) return 0;
01345 
01346 
01347    // Set the max transaction duration
01348    fConnModule->SetOpTimeLimit(EnvGetLong(NAME_TRANSACTIONTIMEOUT));
01349 
01350 
01351 
01352    // Old servers will use what's there
01353    if (fConnModule->GetServerProtocol() < 0x290) {
01354      long id, flags, modtime;
01355      long long size;
01356      XrdClientLocate_Info resp;
01357 
01358      bool ok = Stat((const char *)path, id, size, flags, modtime);
01359      if (ok && (fConnModule->LastServerResp.status == 0)) {
01360        resp.Infotype = XrdClientLocate_Info::kXrdcLocDataServer;
01361        resp.CanWrite = 1;
01362        strcpy((char *)resp.Location, fConnModule->GetCurrentUrl().HostWPort.c_str());
01363        hosts.Push_back(resp);
01364      }
01365      GoBackToRedirector();
01366 
01367      return ok;
01368    }
01369 
01370    XrdClientUrlInfo currurl(fConnModule->GetCurrentUrl().GetUrl());
01371    if (!currurl.HostWPort.length()) return 0;
01372 
01373    // Set up the starting point in the vectored queue
01374    XrdClientLocate_Info nfo;
01375    nfo.Infotype = XrdClientLocate_Info::kXrdcLocManager;
01376    nfo.CanWrite = true;
01377    strcpy((char *)nfo.Location, currurl.HostWPort.c_str());
01378    hosts.Push_back(nfo);
01379    bool firsthost = true;
01380    XrdClientLocate_Info currnfo;
01381 
01382    int pos = 0;
01383 
01384    // Expand a level, i.e. ask to all the masters and remove items from the list
01385    while (pos < hosts.GetSize()) {
01386      
01387      // Take the first item to process
01388      currnfo = hosts[pos];
01389      
01390      // If it's a master, we have to contact it, otherwise take the next
01391      if ((currnfo.Infotype == XrdClientLocate_Info::kXrdcLocDataServer) ||
01392          (currnfo.Infotype == XrdClientLocate_Info::kXrdcLocDataServerPending)) {
01393        pos++;
01394        continue;
01395      }
01396      
01397      // Here, currnfo is pointing to a master we have to contact
01398      currurl.TakeUrl((char *)currnfo.Location);
01399      if (currurl.HostAddr == "") currurl.HostAddr = currurl.Host;
01400      
01401      // Connect to the given host. At the beginning we are connected to the starting point
01402      // A failed connection is just ignored. Only one attempt is performed. Timeouts are
01403      // honored.
01404      if (!firsthost) {
01405        
01406        fConnModule->Disconnect(false);
01407        if (fConnModule->GoToAnotherServer(currurl) != kOK) {
01408          hosts.Erase(pos);
01409          continue;
01410        }
01411      }
01412      
01413      if (firsthost) firsthost = false;
01414      
01415      // We are connected, do the locate
01416      LocalLocate(path, hosts, true, opts, true);
01417      
01418      // We did not finish, take the next
01419      hosts.Erase(pos);
01420    }
01421    
01422    // At the end we want to rewind to the main redirector in any case
01423    GoBackToRedirector();
01424 
01425    return (hosts.GetSize() > 0);
01426 }
01427 
01428 bool XrdClientAdmin::Truncate(const char *path, long long newsize) {
01429 
01430    ClientRequest truncateRequest;
01431    int l = strlen(path);
01432    if (!l) return false;
01433 
01434    // Set the max transaction duration
01435    fConnModule->SetOpTimeLimit(EnvGetLong(NAME_TRANSACTIONTIMEOUT));
01436 
01437 
01438    memset( &truncateRequest, 0, sizeof(truncateRequest) );
01439 
01440    fConnModule->SetSID(truncateRequest.header.streamid);
01441 
01442    truncateRequest.header.requestid     = kXR_truncate;
01443    truncateRequest.truncate.offset      = newsize;
01444 
01445    truncateRequest.header.dlen = l;
01446 
01447    bool ret = fConnModule->SendGenCommand(&truncateRequest, path,
01448                                           NULL, NULL , FALSE, (char *)"Truncate");
01449 
01450    return ret;
01451 
01452 
01453 }
01454 
01455 
01456 
01457 // Quickly jump to the former redirector. Useful after having been redirected.
01458 void XrdClientAdmin::GoBackToRedirector() {
01459 
01460    if (fConnModule) {
01461       fConnModule->GoBackToRedirector();
01462 
01463       if (!fConnModule->IsConnected()) {
01464          XrdClientUrlInfo u(fInitialUrl);
01465          fConnModule->GoToAnotherServer(u);
01466       }
01467 
01468    }
01469 
01470 
01471 
01472 }
01473 
01474 
01475 
01476 // Compute an estimation of the available free space in the given cachefs partition
01477 // The estimation can be fooled if multiple servers mount the same network storage
01478 bool XrdClientAdmin::GetSpaceInfo(const char *logicalname,
01479                                   long long &totspace,
01480                                   long long &totfree,
01481                                   long long &totused,
01482                                   long long &largestchunk) {
01483 
01484    bool ret = true;
01485    XrdClientVector<XrdClientLocate_Info> hosts;
01486 
01487    totspace = 0;
01488    totfree = 0;
01489    totused = 0;
01490    largestchunk = 0;
01491 
01492    if (fConnModule->GetServerProtocol() >= 0x291) {
01493       if (!Locate((kXR_char *)"*", hosts)) return false;
01494    }
01495    else {
01496       XrdClientLocate_Info nfo;
01497       memset(&nfo, 0, sizeof(nfo));
01498       strcpy((char *)nfo.Location, GetCurrentUrl().HostWPort.c_str());
01499       hosts.Push_back(nfo);
01500    }
01501 
01502 
01503    // Then we cycle among them asking everyone
01504    for (int i = 0; i < hosts.GetSize(); i++) {
01505 
01506       fConnModule->Disconnect(false);
01507       XrdClientUrlInfo url((const char *)hosts[i].Location);
01508 
01509       url.Proto = "root";
01510 
01511       if (fConnModule->GoToAnotherServer(url) != kOK) {
01512          ret = false;
01513          break;
01514       }
01515 
01516 
01517 
01518       // Fire the query request and update the results
01519       ClientRequest qspacereq;
01520 
01521       // Set the max transaction duration
01522       fConnModule->SetOpTimeLimit(EnvGetLong(NAME_TRANSACTIONTIMEOUT));
01523 
01524 
01525       memset( &qspacereq, 0, sizeof(qspacereq) );
01526 
01527       fConnModule->SetSID(qspacereq.header.streamid);
01528 
01529       qspacereq.query.requestid = kXR_query;
01530       qspacereq.query.infotype = kXR_Qspace;
01531       qspacereq.query.dlen = ( logicalname ? strlen(logicalname) : 0);
01532 
01533       char *resp = 0;
01534       if (fConnModule->SendGenCommand(&qspacereq, logicalname,
01535                                       (void **)&resp, 0, TRUE,
01536                                       (char *)"GetSpaceInfo")) {
01537 
01538          XrdOucString rs(resp), s;
01539          free(resp);
01540 
01541          // Here we have the response relative to a server
01542          // Now we are going to have fun in parsing it
01543 
01544          int from = 0;
01545          while ((from = rs.tokenize(s,from,'&')) != -1) {
01546             if (s.length() < 4) continue;
01547 
01548             int pos = s.find("=");
01549             XrdOucString tk, val;
01550             if (pos != STR_NPOS) {
01551                tk.assign(s, 0, pos-1);
01552                val.assign(s, pos+1);
01553 #ifndef WIN32
01554                if ( (tk == "oss.space") && (val.length() > 1) ) {
01555                   totspace += atoll(val.c_str());
01556                } else
01557                   if ( (tk == "oss.free") && (val.length() > 1) ) {
01558                      totfree += atoll(val.c_str());
01559                   } else
01560                      if ( (tk == "oss.maxf") && (val.length() > 1) ) {
01561                         largestchunk = xrdmax(largestchunk, atoll(val.c_str()));
01562                      } else
01563                         if ( (tk == "oss.used") && (val.length() > 1) ) {
01564                            totused += atoll(val.c_str());
01565                         }
01566 #else
01567                if ( (tk == "oss.space") && (val.length() > 1) ) {
01568                   totspace += _atoi64(val.c_str());
01569                } else
01570                   if ( (tk == "oss.free") && (val.length() > 1) ) {
01571                      totfree += _atoi64(val.c_str());
01572                   } else
01573                      if ( (tk == "oss.maxf") && (val.length() > 1) ) {
01574                         largestchunk = xrdmax(largestchunk, _atoi64(val.c_str()));
01575                      } else
01576                         if ( (tk == "oss.used") && (val.length() > 1) ) {
01577                            totused += _atoi64(val.c_str());
01578                         }
01579 #endif
01580             }
01581          }
01582 
01583 
01584       }
01585 
01586    }
01587 
01588    // At the end we want to rewind to the main redirector in any case
01589    GoBackToRedirector();
01590    return ret;
01591 
01592 
01593 }

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