#include "TEnv.h"
#include "TFileStager.h"
#include "TObjString.h"
#include "TROOT.h"
#include "TSocket.h"
#include "TString.h"
#include "TUrl.h"
#include "TVirtualMutex.h"
#include "TXNetFile.h"
#include "TXNetSystem.h"
#include "XrdOuc/XrdOucString.hh"
#include "XrdClient/XrdClientVector.hh"
#include "XrdClient/XrdClientAdmin.hh"
#include "XrdClient/XrdClientConn.hh"
#include "XrdClient/XrdClientConst.hh"
#include "XrdClient/XrdClientEnv.hh"
#include "XProtocol/XProtocol.hh"
#include "XrdProofdXrdVers.h"
ClassImp(TXNetSystem);
Bool_t TXNetSystem::fgInitDone = kFALSE;
Bool_t TXNetSystem::fgRootdBC = kTRUE;
THashList TXNetSystem::fgAddrFQDN;
THashList TXNetSystem::fgAdminHash;
typedef XrdClientVector<XrdOucString> VecString_t;
TXNetSystem::TXNetSystem(Bool_t owner) : TNetSystem(owner), fDirList(0)
{
SetTitle("(x)rootd system administration");
fIsRootd = kFALSE;
fIsXRootd = kFALSE;
fDir = "";
fDirp = 0;
fUrl = "";
}
TXNetSystem::TXNetSystem(const char *url, Bool_t owner) : TNetSystem(owner), fDirList(0)
{
SetTitle("(x)rootd system administration");
fIsRootd = kFALSE;
fIsXRootd = kFALSE;
fDir = "";
fDirp = 0;
fUrl = url;
fgAddrFQDN.SetOwner();
fgAdminHash.SetOwner();
EnvPutInt(NAME_DEBUG, gEnv->GetValue("XNet.Debug", -1));
if (!fgInitDone)
InitXrdClient();
TNetSystem::InitRemoteEntity(url);
TXNetSystemConnectGuard cguard(this, url);
if (!cguard.IsValid() && !fIsRootd)
Error("TXNetSystem","fatal error: connection creation failed.");
return;
}
XrdClientAdmin *TXNetSystem::Connect(const char *url)
{
TString dummy = url;
dummy += "/dummy";
XrdClientAdmin *cadm = TXNetSystem::GetClientAdmin(dummy);
if (!cadm) {
Error("Connect","fatal error: new object creation failed.");
return cadm;
}
Int_t maxOld = EnvGetLong(NAME_FIRSTCONNECTMAXCNT);
gEnv->SetValue("XNet.FirstConnectMaxCnt", 1);
EnvPutInt(NAME_FIRSTCONNECTMAXCNT, 1);
if (cadm->Connect()) {
fIsXRootd = kTRUE;
EnvPutInt(NAME_FIRSTCONNECTMAXCNT, maxOld);
} else {
EnvPutInt(NAME_FIRSTCONNECTMAXCNT, maxOld);
if (fgRootdBC) {
Bool_t isRootd =
(cadm->GetClientConn()->GetServerType() == kSTRootd);
Int_t sd = cadm->GetClientConn()->GetOpenSockFD();
if (isRootd && sd > -1) {
TSocket *s = new TSocket(sd);
R__LOCKGUARD2(gROOTMutex);
gROOT->GetListOfSockets()->Remove(s);
s->SetOption(kNoBlock, 0);
Int_t rproto = TXNetFile::GetRootdProtocol(s);
if (rproto < 0) {
Error("TXNetSystem", "getting protocol of the rootd server");
cadm = 0;
return 0;
}
s->SetRemoteProtocol(rproto);
TUrl uut((cadm->GetClientConn()
->GetCurrentUrl()).GetUrl().c_str());
TString uu;
TXNetFile::FormUrl(uut,uu);
if (gDebug > 2)
Info("Connect"," url: %s",uu.Data());
s->SetUrl(uu.Data());
s->SetService("rootd");
s->SetServType(TSocket::kROOTD);
if (rproto > 13) {
TNetSystem::Create(uu, s);
} else {
TNetSystem::Create(uu);
}
fIsRootd = kTRUE;
cadm = 0;
} else {
Error("Connect", "some severe error occurred while opening"
" the connection at %s - exit", url);
if (cadm && cadm->LastServerError())
Printf(" '%s'", cadm->LastServerError()->errmsg);
else
Printf(" (error message not available)");
cadm = 0;
return cadm;
}
} else {
Error("Connect",
"while opening the connection at %s - exit", url);
cadm = 0;
return cadm;
}
}
return cadm;
}
void TXNetSystem::InitXrdClient()
{
TXNetFile::SetEnv();
fgInitDone = kTRUE;
if (gEnv->GetValue("XNet.PrintTAG",0) == 1)
Info("TXNetFile","(C) 2005 SLAC TXNetSystem (eXtended TNetSystem) %s",
gROOT->GetVersion());
}
void* TXNetSystem::OpenDirectory(const char* dir)
{
if (fIsXRootd) {
TXNetSystemConnectGuard cg(this, dir);
if (cg.IsValid()) {
fUrl = dir;
fDir = TUrl(dir).GetFile();
fDirp = (void*)&fDir;
vecString dirs;
vecBool existDirs;
XrdOucString s(fDir.Data());
dirs.Push_back(s);
cg.ClientAdmin()->ExistDirs(dirs, existDirs);
cg.ClientAdmin()->GoBackToRedirector();
if (existDirs.GetSize()>0 && existDirs[0])
return fDirp;
else
cg.NotifyLastError();
}
return 0;
}
if (gDebug > 1)
Info("OpenDirectory", "calling TNetSystem::OpenDirectory");
return TNetSystem::OpenDirectory(dir);
}
void TXNetSystem::FreeDirectory(void *dirp)
{
if (fIsXRootd) {
if (dirp != fDirp) {
Error("FreeDirectory","invalid directory pointer (%p, %p)", dirp, fDirp);
return;
}
fDir = "";
fDirp = 0;
fDirEntry = "";
if (fDirList) {
((VecString_t*)fDirList)->Clear();
delete ((VecString_t*)fDirList);
fDirList = 0;
}
return;
}
if (gDebug > 1)
Info("FreeDirectory","calling TNetSystem::FreeDirectory");
return TNetSystem::FreeDirectory(dirp);
}
Int_t TXNetSystem::MakeDirectory(const char* dir)
{
if (fIsXRootd) {
TXNetSystemConnectGuard cg(this, dir);
if (cg.IsValid()) {
Bool_t ok = cg.ClientAdmin()->Mkdir(TUrl(dir).GetFile(),7,5,5);
cg.ClientAdmin()->GoBackToRedirector();
if (ok) {
return 0;
} else {
cg.NotifyLastError();
return -1;
}
}
}
if (gDebug > 1)
Info("MakeDirectory","Calling TNetSystem::MakeDirectory");
return TNetSystem::MakeDirectory(dir);
}
const char* TXNetSystem::GetDirEntry(void *dirp)
{
if (fIsXRootd) {
if (dirp != fDirp) {
Error("GetDirEntry","invalid directory pointer");
return 0;
}
if (!fDirList) {
TXNetSystemConnectGuard cg(this, fUrl);
if (cg.IsValid()) {
fDirList = new VecString_t;
Bool_t ok = cg.ClientAdmin()->DirList(fDir, *(VecString_t*)fDirList);
cg.ClientAdmin()->GoBackToRedirector();
if (!ok) {
cg.NotifyLastError();
delete (VecString_t*)fDirList;
fDirList = 0;
return 0;
}
}
}
if (fDirList && ((VecString_t*)fDirList)->GetSize() > 0) {
fDirEntry = ((VecString_t*)fDirList)->Pop_front().c_str();
return fDirEntry.Data();
}
return 0;
}
if (gDebug > 1) Info("GetDirEntry","Calling TNetSystem::GetDirEntry");
return TNetSystem::GetDirEntry(dirp);
}
Int_t TXNetSystem::GetPathInfo(const char* path, FileStat_t &buf)
{
if (fIsXRootd) {
TXNetSystemConnectGuard cg(this, path);
if (cg.IsValid()) {
Long_t id;
Long64_t size;
Long_t flags;
Long_t modtime;
TUrl urlpath(path);
Bool_t ok = cg.ClientAdmin()->Stat(urlpath.GetFile(),id,size,flags,modtime);
if (ok) {
urlpath.SetProtocol(cg.ClientAdmin()->GetCurrentUrl().Proto.c_str());
urlpath.SetHost(cg.ClientAdmin()->GetCurrentUrl().Host.c_str());
urlpath.SetPort(cg.ClientAdmin()->GetCurrentUrl().Port);
buf.fUrl = urlpath.GetUrl();
}
cg.ClientAdmin()->GoBackToRedirector();
if (flags & kXR_offline) {
buf.fMode = kS_IFOFF;
} else if (ok) {
buf.fDev = (id >> 24);
buf.fIno = (id & 0x00FFFFFF);
buf.fUid = -1;
buf.fGid = -1;
buf.fSize = size;
buf.fMtime = modtime;
if (flags == 0) buf.fMode = kS_IFREG;
if (flags & kXR_xset) buf.fMode = (kS_IFREG|kS_IXUSR|kS_IXGRP|kS_IXOTH);
if (flags & kXR_isDir) buf.fMode = kS_IFDIR;
if (flags & kXR_other) buf.fMode = kS_IFSOCK;
if (flags & kXR_readable) buf.fMode |= kS_IRUSR;
if (flags & kXR_writable) buf.fMode |= kS_IWUSR;
buf.fIsLink = 0;
return 0;
} else {
if (gDebug > 0)
cg.NotifyLastError();
}
}
return 1;
}
if (gDebug > 1)
Info("GetPathInfo","Calling TNetSystem::GetPathInfo");
return TNetSystem::GetPathInfo(path,buf);
}
Bool_t TXNetSystem::ConsistentWith(const char *path, void *dirptr)
{
if (gDebug > 1)
Info("ConsistentWith",
"calling for path: %s, dir: %p", path, dirptr);
return TNetSystem::ConsistentWith(path,dirptr);
}
Bool_t TXNetSystem::AccessPathName(const char *path, EAccessMode mode)
{
if (fIsXRootd) {
FileStat_t buf;
if (GetPathInfo(path, buf) == 0)
if (buf.fMode != kS_IFSOCK)
return kFALSE;
return kTRUE;
}
if (gDebug > 1)
Info("AccessPathName", "calling TNetSystem::AccessPathName");
return TNetSystem::AccessPathName(path,mode);
}
int TXNetSystem::Unlink(const char *path)
{
if (fIsXRootd) {
TXNetSystemConnectGuard cg(this, path);
if (cg.IsValid()) {
Long_t id;
Long64_t size;
Long_t flags;
Long_t modtime;
TString edir = TUrl(path).GetFile();
Bool_t ok = cg.ClientAdmin()->Stat(edir.Data(), id, size, flags, modtime);
if (ok && !(flags & kXR_offline)) {
if (flags & kXR_isDir)
ok = cg.ClientAdmin()->Rmdir(edir.Data());
else
ok = cg.ClientAdmin()->Rm(edir.Data());
cg.ClientAdmin()->GoBackToRedirector();
return ((ok) ? 0 : -1);
} else if (!ok) {
cg.ClientAdmin()->GoBackToRedirector();
cg.NotifyLastError();
}
}
}
if (gDebug > 1)
Info("Unlink", "calling TNetSystem::Unlink");
return -1;
}
Bool_t TXNetSystem::IsOnline(const char *path)
{
FileStat_t st;
if (GetPathInfo(path, st) != 0) {
if (gDebug > 0)
Info("IsOnline", "path '%s' cannot be stat'ed", path);
return kFALSE;
}
if (R_ISOFF(st.fMode)) {
if (gDebug > 0)
Info("IsOnline", "path '%s' is offline", path);
return kFALSE;
}
return kTRUE;
}
Bool_t TXNetSystem::Prepare(const char *path, UChar_t option, UChar_t priority)
{
TXNetSystemConnectGuard cg(this, path);
if (cg.IsValid()) {
XrdOucString pathname = TUrl(path).GetFileAndOptions();
vecString vs;
vs.Push_back(pathname);
cg.ClientAdmin()->Prepare(vs, (kXR_char)option, (kXR_char)priority);
cg.ClientAdmin()->GoBackToRedirector();
if (gDebug >0)
Info("Prepare", "Got Status %d for %s",
cg.ClientAdmin()->LastServerResp()->status, pathname.c_str());
if (!(cg.ClientAdmin()->LastServerResp()->status)){
return kTRUE;
}
cg.NotifyLastError();
}
return kFALSE;
}
Int_t TXNetSystem::Prepare(TCollection *paths,
UChar_t opt, UChar_t prio, TString *bufout)
{
if (!paths) {
Warning("Prepare", "input list is empty!");
return -1;
}
Int_t npaths = 0;
TXNetSystemConnectGuard cg(this, "");
if (cg.IsValid()) {
TString *buf = (bufout) ? bufout : new TString();
TObject *o = 0;
TUrl u;
TString path;
TIter nxt(paths);
while ((o = nxt())) {
TString pn = TFileStager::GetPathName(o);
if (pn == "") {
Warning("Prepare", "object is of unexpected type %s - ignoring", o->ClassName());
continue;
}
u.SetUrl(pn);
path = u.GetFileAndOptions();
path.ReplaceAll("\n","\r");
npaths++;
*buf += Form("%s\n", path.Data());
}
Info("Prepare","buffer ready: issuing prepare (opt=%d, prio=%d) ...",
opt, prio);
cg.ClientAdmin()->Prepare(buf->Data(), (kXR_char)opt, (kXR_char)prio);
cg.ClientAdmin()->GoBackToRedirector();
if (!bufout)
delete buf;
if (gDebug >0)
Info("Prepare", "Got Status %d",
cg.ClientAdmin()->LastServerResp()->status);
if (!(cg.ClientAdmin()->LastServerResp()->status)){
return npaths;
}
cg.NotifyLastError();
}
return -1;
}
Bool_t TXNetSystem::GetPathsInfo(const char *paths, UChar_t *info)
{
if (!paths) {
Warning("GetPathsInfo", "input list is empty!");
return kFALSE;
}
TXNetSystemConnectGuard cg(this, "");
if (cg.IsValid()) {
cg.ClientAdmin()->SysStatX(paths, info);
cg.ClientAdmin()->GoBackToRedirector();
if (gDebug >0)
Info("GetPathsInfo", "Got Status %d",
cg.ClientAdmin()->LastServerResp()->status);
if (!(cg.ClientAdmin()->LastServerResp()->status)){
return kTRUE;
}
cg.NotifyLastError();
}
return kFALSE;
}
Bool_t TXNetSystem::IsPathLocal(const char *path)
{
if (fIsXRootd) {
TXNetSystemConnectGuard cg(this, path);
if (cg.IsValid()) {
if (cg.ClientAdmin()->GetClientConn()->GetServerType() != kSTDataXrootd) {
return kFALSE;
}
}
}
return TSystem::IsPathLocal(path);
}
Int_t TXNetSystem::Locate(const char *path, TString &eurl)
{
if (fIsXRootd) {
TXNetSystemConnectGuard cg(this, path);
if (cg.IsValid()) {
XrdClientLocate_Info li;
TString edir = TUrl(path).GetFile();
if (cg.ClientAdmin()->Locate((kXR_char *)edir.Data(), li)) {
TUrl u(path);
XrdClientUrlInfo ui((const char *)&li.Location[0]);
TNamed *hn = 0;
if (fgAddrFQDN.GetSize() <= 0 ||
!(hn = dynamic_cast<TNamed *>(fgAddrFQDN.FindObject(ui.Host.c_str())))) {
TInetAddress a(gSystem->GetHostByName(ui.Host.c_str()));
if (strlen(a.GetHostName()) > 0)
hn = new TNamed(ui.Host.c_str(), a.GetHostName());
else
hn = new TNamed(ui.Host.c_str(), ui.Host.c_str());
fgAddrFQDN.Add(hn);
if (gDebug > 0)
Info("Locate","caching host name: %s", hn->GetTitle());
}
if (hn)
u.SetHost(hn->GetTitle());
else
u.SetHost(ui.Host.c_str());
u.SetPort(ui.Port);
eurl = u.GetUrl();
return 0;
}
cg.NotifyLastError();
}
return 1;
}
if (gDebug > 0) Info("Locate", "server not Xrootd: method not implemented!");
return -1;
}
XrdClientAdmin *TXNetSystem::GetClientAdmin(const char *url)
{
XrdClientAdmin *ca = 0;
TString key = TXNetSystem::GetKey(url);
TXrdClientAdminWrapper *caw = 0;
if (fgAdminHash.GetSize() > 0 &&
(caw = dynamic_cast<TXrdClientAdminWrapper *>(fgAdminHash.FindObject(key.Data()))))
return caw->fXCA;
ca = new XrdClientAdmin(url);
fgAdminHash.Add(new TXrdClientAdminWrapper(key, ca));
return ca;
}
TString TXNetSystem::GetKey(const char *url)
{
TUrl u(url);
TString key(u.GetUser());
if (!key.IsNull())
key += "@";
key += u.GetHost();
if (u.GetPort() > 0) {
key += ":";
key += u.GetPort();
}
return key;
}
TXrdClientAdminWrapper::~TXrdClientAdminWrapper()
{
SafeDelete(fXCA);
}
TXNetSystemConnectGuard::TXNetSystemConnectGuard(TXNetSystem *xn, const char *url)
: fClientAdmin(0)
{
if (xn)
fClientAdmin = (url && strlen(url) > 0) ? xn->Connect(url)
: xn->Connect(xn->fUrl);
}
TXNetSystemConnectGuard::~TXNetSystemConnectGuard()
{
fClientAdmin = 0;
}
void TXNetSystemConnectGuard::NotifyLastError()
{
if (fClientAdmin)
if (fClientAdmin->GetClientConn())
Printf("Srv err: %s", fClientAdmin->GetClientConn()->LastServerError.errmsg);
}