Loading...
Searching...
No Matches
XrdXrootdXeq.cc
Go to the documentation of this file.
/******************************************************************************/
/* */
/* X r d X r o o t d X e q . c c */
/* */
/* (c) 2004 by the Board of Trustees of the Leland Stanford, Jr., University */
/* Produced by Andrew Hanushevsky for Stanford University under contract */
/* DE-AC02-76-SFO0515 with the Department of Energy */
/* */
/* 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 <http://www.gnu.org/licenses/>. */
/* */
/* 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. */
/******************************************************************************/
#include <cctype>
#include <cstdio>
#include <map>
#include <string>
#include <sys/time.h>
#include "XrdSfs/XrdSfsInterface.hh"
#include "XrdSfs/XrdSfsFlags.hh"
#include "XrdSys/XrdSysError.hh"
#include "XrdSys/XrdSysPlatform.hh"
#include "XrdSys/XrdSysTimer.hh"
#include "XrdCks/XrdCksData.hh"
#include "XrdOuc/XrdOucEnv.hh"
#include "XrdOuc/XrdOucReqID.hh"
#include "XrdOuc/XrdOucTList.hh"
#include "XrdOuc/XrdOucStream.hh"
#include "XrdOuc/XrdOucString.hh"
#include "XrdOuc/XrdOucTokenizer.hh"
#include "XrdOuc/XrdOucUtils.hh"
#include "XrdSec/XrdSecEntityAttr.hh"
#include "XrdSec/XrdSecInterface.hh"
#include "XrdSec/XrdSecProtector.hh"
#include "XrdSys/XrdSysE2T.hh"
#include "Xrd/XrdBuffer.hh"
#include "Xrd/XrdInet.hh"
#include "Xrd/XrdLinkCtl.hh"
#include "XrdXrootd/XrdXrootdAioFob.hh"
#include "XrdXrootd/XrdXrootdCallBack.hh"
#include "XrdXrootd/XrdXrootdFile.hh"
#include "XrdXrootd/XrdXrootdFileLock.hh"
#include "XrdXrootd/XrdXrootdJob.hh"
#include "XrdXrootd/XrdXrootdMonFile.hh"
#include "XrdXrootd/XrdXrootdMonitor.hh"
#include "XrdXrootd/XrdXrootdNormAio.hh"
#include "XrdXrootd/XrdXrootdPio.hh"
#include "XrdXrootd/XrdXrootdPrepare.hh"
#include "XrdXrootd/XrdXrootdProtocol.hh"
#include "XrdXrootd/XrdXrootdRedirPI.hh"
#include "XrdXrootd/XrdXrootdStats.hh"
#include "XrdXrootd/XrdXrootdTrace.hh"
#include "XrdXrootd/XrdXrootdWVInfo.hh"
#include "XrdXrootd/XrdXrootdXeq.hh"
#include "XrdXrootd/XrdXrootdXPath.hh"
#include "XrdVersion.hh"
#ifndef ENODATA
#define ENODATA ENOATTR
#endif
#ifndef ETIME
#define ETIME ETIMEDOUT
#endif
/******************************************************************************/
/* G l o b a l s */
/******************************************************************************/
extern XrdSysTrace XrdXrootdTrace;
/******************************************************************************/
/* L o c a l S t r u c t u r e s */
/******************************************************************************/
struct XrdXrootdSessID
{unsigned int Sid;
int Pid;
int FD;
unsigned int Inst;
XrdXrootdSessID() {}
~XrdXrootdSessID() {}
};
/******************************************************************************/
/* L o c a l D e f i n e s */
/******************************************************************************/
namespace
{
const char *getTime()
{
static char buff[16];
char tuff[8];
struct timeval tv;
struct tm *tmp;
if (gettimeofday(&tv, 0))
{perror("gettimeofday");
exit(255);
}
tmp = localtime(&tv.tv_sec);
if (!tmp)
{perror("localtime");
exit(255);
}
//012345678901234
if (strftime(buff, sizeof(buff), "%y%m%d:%H%M%S. ", tmp) <= 0)
{errno = EINVAL;
perror("strftime");
exit(255);
}
snprintf(tuff, sizeof(tuff), "%d", static_cast<int>(tv.tv_usec/100000));
buff[14] = tuff[0];
return buff;
}
// comment out genUEID as it is not used
//
//int genUEID()
//{
// static XrdSysMutex ueidMutex;
// static int ueidVal = 1;
// AtomicBeg(ueidMutex);
// int n = AtomicInc(ueidVal);
// AtomicEnd(ueidMutex);
// return n;
//}
// Startup time
// 012345670123456
// yymmdd:hhmmss.t
static const char *startUP = getTime();
}
/******************************************************************************/
/* d o _ A u t h */
/******************************************************************************/
int XrdXrootdProtocol::do_Auth()
{
XrdSecCredentials cred;
XrdSecParameters *parm = 0;
XrdOucErrInfo eMsg;
const char *eText;
int rc, n;
// Ignore authenticate requests if security turned off
//
if (!CIA) return Response.Send();
cred.size = Request.header.dlen;
cred.buffer = argp->buff;
// If we have no auth protocol or the current protocol is being changed by the
// client (the client can do so at any time), try to get it. Track number of
// times we got a protocol object as the read count (we will zero it out later).
// The credtype change check is always done. While the credtype is consistent,
// not all protocols provided this information in the past. So, old clients will
// not necessarily be able to switch protocols mid-stream.
//
if (!AuthProt
|| strncmp(Entity.prot, (const char *)Request.auth.credtype,
sizeof(Request.auth.credtype)))
{if (AuthProt) AuthProt->Delete();
size_t size = sizeof(Request.auth.credtype);
strncpy(Entity.prot, (const char *)Request.auth.credtype, size);
if (!(AuthProt = CIA->getProtocol(Link->Host(), *(Link->AddrInfo()),
&cred, eMsg)))
{eText = eMsg.getErrText(rc);
eDest.Emsg("Xeq", "User authentication failed;", eText);
return Response.Send(kXR_AuthFailed, eText);
}
AuthProt->Entity.tident = AuthProt->Entity.pident = Link->ID;
numReads++;
}
// Now try to authenticate the client using the current protocol
//
if (!(rc = AuthProt->Authenticate(&cred, &parm, &eMsg))
&& CIA->PostProcess(AuthProt->Entity, eMsg))
{rc = Response.Send(); Status &= ~XRD_NEED_AUTH; SI->Bump(SI->LoginAU);
AuthProt->Entity.ueid = mySID;
Client = &AuthProt->Entity; numReads = 0; strcpy(Entity.prot, "host");
if (TRACING(TRACE_AUTH)) Client->Display(eDest);
if (DHS) Protect = DHS->New4Server(*AuthProt,clientPV&XrdOucEI::uVMask);
if (Monitor.Logins() && Monitor.Auths()) MonAuth();
if (!logLogin(true)) return -1;
return rc;
}
// If we need to continue authentication, tell the client as much
//
if (rc > 0)
{TRACEP(LOGIN, "more auth requested; sz=" <<(parm ? parm->size : 0));
if (parm) {rc = Response.Send(kXR_authmore, parm->buffer, parm->size);
delete parm;
return rc;
}
eDest.Emsg("Xeq", "Security requested additional auth w/o parms!");
return Response.Send(kXR_ServerError,"invalid authentication exchange");
}
// Authentication failed. We will delete the authentication object and zero
// out the pointer. We can do this without any locks because this section is
// single threaded relative to a connection. To prevent guessing attacks, we
// wait a variable amount of time if there have been 3 or more tries.
//
if (AuthProt) {AuthProt->Delete(); AuthProt = 0;}
if ((n = numReads - 2) > 0) XrdSysTimer::Snooze(n > 5 ? 5 : n);
// We got an error, bail out.
//
SI->Bump(SI->AuthBad);
eText = eMsg.getErrText(rc);
eDest.Emsg("Xeq", "User authentication failed;", eText);
return Response.Send(kXR_AuthFailed, eText);
}
/******************************************************************************/
/* d o _ B i n d */
/******************************************************************************/
int XrdXrootdProtocol::do_Bind()
{
XrdXrootdSessID *sp = (XrdXrootdSessID *)Request.bind.sessid;
XrdXrootdProtocol *pp;
XrdLink *lp;
int i, pPid, rc;
char buff[64], *cp, *dp;
// Update misc stats count
//
SI->Bump(SI->miscCnt);
// Check if binds need to occur on a TLS connection.
//
if ((doTLS & Req_TLSData) && !isTLS && !Link->hasBridge())
return Response.Send(kXR_TLSRequired, "bind requires TLS");
// Find the link we are to bind to
//
if (sp->FD <= 0 || !(lp = XrdLinkCtl::fd2link(sp->FD, sp->Inst)))
return Response.Send(kXR_NotFound, "session not found");
// The link may have escaped so we need to hold this link and try again
//
lp->Hold(1);
if (lp != XrdLinkCtl::fd2link(sp->FD, sp->Inst))
{lp->Hold(0);
return Response.Send(kXR_NotFound, "session just closed");
}
// Get the protocol associated with the link
//
if (!(pp=dynamic_cast<XrdXrootdProtocol *>(lp->getProtocol()))||lp != pp->Link)
{lp->Hold(0);
return Response.Send(kXR_ArgInvalid, "session protocol not xroot");
}
// Verify that the parent protocol is fully logged in
//
if (!(pp->Status & XRD_LOGGEDIN) || (pp->Status & XRD_NEED_AUTH))
{lp->Hold(0);
return Response.Send(kXR_ArgInvalid, "session not logged in");
}
// Verify that the bind is valid for the requestor
//
if (sp->Pid != myPID || sp->Sid != pp->mySID)
{lp->Hold(0);
return Response.Send(kXR_ArgInvalid, "invalid session ID");
}
// For now, verify that the request is comming from the same host
//
if (strcmp(Link->Host(), lp->Host()))
{lp->Hold(0);
return Response.Send(kXR_NotAuthorized, "cross-host bind not allowed");
}
// We need to hold the parent's stream mutex to prevent inspection or
// modification of other parallel binds that may occur
//
XrdSysMutexHelper smHelper(pp->streamMutex);
// Find a slot for this path in parent protocol
//
for (i = 1; i < maxStreams && pp->Stream[i]; i++) {}
if (i >= maxStreams)
{lp->Hold(0);
return Response.Send(kXR_NoMemory, "bind limit exceeded");
}
// Link this protocol to the parent
//
pp->Stream[i] = this;
Stream[0] = pp;
PathID = i;
// Construct a login name for this bind session
//
cp = strdup(lp->ID);
if ( (dp = rindex(cp, '@'))) *dp = '\0';
if (!(dp = rindex(cp, '.'))) pPid = 0;
else {*dp++ = '\0'; pPid = strtol(dp, (char **)NULL, 10);}
Link->setID(cp, pPid);
free(cp);
CapVer = pp->CapVer;
Status = XRD_BOUNDPATH;
clientPV = pp->clientPV;
// Check if we need to enable packet marking for this stream
//
if (pp->pmDone)
{pmDone = true;
if (pp->pmHandle) pmHandle = PMark->Begin(*(Link->AddrInfo()),
*(pp->pmHandle), Link->ID);
}
// Document the bind
//
smHelper.UnLock();
sprintf(buff, "FD %d#%d bound", Link->FDnum(), i);
eDest.Log(SYS_LOG_01, "Xeq", buff, lp->ID);
// Get the required number of parallel I/O objects
//
pioFree = XrdXrootdPio::Alloc(maxPio);
// There are no errors possible at this point unless the response fails
//
buff[0] = static_cast<char>(i);
if (!(rc = Response.Send(kXR_ok, buff, 1))) rc = -EINPROGRESS;
// Return but keep the link disabled
//
lp->Hold(0);
return rc;
}
/******************************************************************************/
/* d o _ C h k P n t */
/* */
/* Resides in XrdXrootdXeqChkPnt.cc */
/******************************************************************************/
/******************************************************************************/
/* d o _ c h m o d */
/******************************************************************************/
int XrdXrootdProtocol::do_Chmod()
{
int mode, rc;
char *opaque;
XrdOucErrInfo myError(Link->ID, Monitor.Did, clientPV);
// Check for static routing
//
STATIC_REDIRECT(RD_chmod);
// Unmarshall the data
//
mode = mapMode((int)ntohs(Request.chmod.mode));
if (rpCheck(argp->buff, &opaque)) return rpEmsg("Modifying", argp->buff);
if (!Squash(argp->buff)) return vpEmsg("Modifying", argp->buff);
// Preform the actual function
//
rc = osFS->chmod(argp->buff, (XrdSfsMode)mode, myError, CRED, opaque);
TRACEP(FS, "chmod rc=" <<rc <<" mode=" <<Xrd::oct1 <<mode <<' ' <<argp->buff);
if (SFS_OK == rc) return Response.Send();
// An error occurred
//
return fsError(rc, XROOTD_MON_CHMOD, myError, argp->buff, opaque);
}
/******************************************************************************/
/* d o _ C K s u m */
/******************************************************************************/
int XrdXrootdProtocol::do_CKsum(int canit)
{
char *opaque;
char *algT = JobCKT, *args[6];
int rc;
// Check for static routing
//
STATIC_REDIRECT(RD_chksum);
// Check if we support this operation
//
if (!JobCKT || (!JobLCL && !JobCKS))
return Response.Send(kXR_Unsupported, "query chksum is not supported");
// Prescreen the path
//
if (rpCheck(argp->buff, &opaque)) return rpEmsg("Check summing", argp->buff);
if (!Squash(argp->buff)) return vpEmsg("Check summing", argp->buff);
// If this is a cancel request, do it now
//
if (canit)
{if (JobCKS) JobCKS->Cancel(argp->buff, &Response);
return Response.Send();
}
// Check if multiple checksums are supported and if so, pre-process
//
if (JobCKCGI && opaque && *opaque)
{char cksT[64];
algT = getCksType(opaque, cksT, sizeof(cksT));
if (!algT)
{char ebuf[1024];
snprintf(ebuf, sizeof(ebuf), "%s checksum not supported.", cksT);
return Response.Send(kXR_ServerError, ebuf);
}
}
// If we are allowed to locally query the checksum to avoid computation, do it
//
if (JobLCL && (rc = do_CKsum(algT, argp->buff, opaque)) <= 0) return rc;
// Just make absolutely sure we can continue with a calculation
//
if (!JobCKS)
return Response.Send(kXR_ServerError, "Logic error computing checksum.");
// Check if multiple checksums are supported and construct right argument list
// We make a concession to a wrongly placed setfsuid/gid plugin. Fortunately,
// it only needs to know user's name but that can come from another plugin.
//
std::string keyval; // Contents will be copied prior to return!
if (JobCKCGI > 1 || JobLCL)
{args[0] = algT;
args[1] = algT;
args[2] = argp->buff;
args[3] = const_cast<char *>(Client->tident);
if (Client->eaAPI->Get(std::string("request.name"), keyval) && !keyval.empty())
args[4] = const_cast<char *>(keyval.c_str());
else if (Client->name) args[4] = Client->name;
else args[4] = 0;
args[5] = 0;
} else {
args[0] = algT;
args[1] = argp->buff;
args[2] = 0;
}
// Preform the actual function
//
return JobCKS->Schedule(argp->buff, (const char **)args, &Response,
((CapVer & kXR_vermask) >= kXR_ver002 ? 0 : JOB_Sync));
}
/******************************************************************************/
int XrdXrootdProtocol::do_CKsum(char *algT, const char *Path, char *Opaque)
{
static char Space = ' ';
XrdOucErrInfo myError(Link->ID, Monitor.Did, clientPV);
int CKTLen = strlen(algT);
int ec, rc = osFS->chksum(XrdSfsFileSystem::csGet, algT, Path,
myError, CRED, Opaque);
const char *csData = myError.getErrText(ec);
// Diagnose any hard errors
//
if (rc) return fsError(rc, 0, myError, Path, Opaque);
// Return result if it is actually available
//
if (*csData)
{if (*csData == '!') return Response.Send(csData+1);
struct iovec iov[4] = {{0,0}, {algT, (size_t)CKTLen}, {&Space, 1},
{(char *)csData, strlen(csData)+1}};
return Response.Send(iov, 4);
}
// Diagnose soft errors
//
if (!JobCKS)
{const char *eTxt[2] = {JobCKT, " checksum not available."};
myError.setErrInfo(0, eTxt, 2);
return Response.Send(kXR_ChkSumErr, myError.getErrText());
}
// Return indicating that we should try calculating the checksum
//
return 1;
}
/******************************************************************************/
/* d o _ C l o s e */
/******************************************************************************/
int XrdXrootdProtocol::do_Close()
{
static XrdXrootdCallBack closeCB("close", XROOTD_MON_CLOSE);
XrdXrootdFile *fp;
XrdXrootdFHandle fh(Request.close.fhandle);
int rc;
bool doDel = true;
// Keep statistics
//
SI->Bump(SI->miscCnt);
// Find the file object
//
if (!FTab || !(fp = FTab->Get(fh.handle)))
return Response.Send(kXR_FileNotOpen,
"close does not refer to an open file");
// Serialize the file to make sure all references due to async I/O and parallel
// stream operations have completed.
//
fp->Serialize();
// If the file has a fob then it was subject to pgwrite and if uncorrected
// checksum errors exist do a forced close. This will trigger POSC or a restore.
//
if (fp->pgwFob && !do_PgClose(fp, rc))
{FTab->Del((Monitor.Files() ? Monitor.Agent : 0), fh.handle, true);
numFiles--;
return rc;
}
// Setup the callback to allow close() to return SFS_STARTED so we can defer
// the response to the close request as it may be a lengthy operation. In
// this case the argument is the actual file pointer and the link reference
// is recorded in the file object.
//
fp->cbArg = ReqID.getID();
fp->XrdSfsp->error.setErrCB(&closeCB, (unsigned long long)fp);
// Add a reference count to the file in case the close will be deferred. In
// the deferred case the reference is used to prevent the callback from
// deleting the file until we have done necessary processing of the object
// during its removal from the open table.
//
fp->Ref(1);
// Do an explicit close of the file here; check for exceptions. Stall requests
// leave the file open as there will be a retry. Otherwise, we remove the
// file from our open table but a "started" return defers the the delete.
//
rc = fp->XrdSfsp->close();
TRACEP(FS, " fh=" <<fh.handle <<" close rc=" <<rc);
if (rc == SFS_STARTED) doDel = false;
else {fp->Ref(-1);
if (rc >= SFS_STALL)
return fsError(rc, 0, fp->XrdSfsp->error, 0, 0);
}
// Before we potentially delete the file handle in FTab->Del, generate the
// appropriate error code (if necessary). Note that we delay the call
// to Response.Send() in the successful case to avoid holding on to the lock
// while the response is sent.
//
int retval = 0;
if (SFS_OK != rc) retval = fsError(rc, 0, fp->XrdSfsp->error, 0, 0);
// Delete the file from the file table. If the file object is deleted then it
// will unlock the file In all cases, final monitoring records will be produced.
//
FTab->Del((Monitor.Files() ? Monitor.Agent : 0), fh.handle, doDel);
numFiles--;
if (!doDel) fp->Ref(-1);
// Send back the right response
//
if (SFS_OK == rc) return Response.Send();
return retval;
}
/******************************************************************************/
/* d o _ D i r l i s t */
/******************************************************************************/
int XrdXrootdProtocol::do_Dirlist()
{
int bleft, rc = 0, dlen, cnt = 0;
char *opaque, *buff, ebuff[4096];
const char *dname;
XrdSfsDirectory *dp;
bool doDig;
// Check if we are digging for data
//
doDig = (digFS && SFS_LCLROOT(argp->buff));
// Check for static routing
//
if (!doDig) {STATIC_REDIRECT(RD_dirlist);}
// Prescreen the path
//
if (rpCheck(argp->buff, &opaque)) return rpEmsg("Listing", argp->buff);
if (!doDig && !Squash(argp->buff))return vpEmsg("Listing", argp->buff);
// Get a directory object
//
if (doDig) dp = digFS->newDir(Link->ID, Monitor.Did);
else dp = osFS->newDir(Link->ID, Monitor.Did);
// Make sure we have the object
//
if (!dp)
{snprintf(ebuff,sizeof(ebuff)-1,"Insufficient memory to open %s",argp->buff);
eDest.Emsg("Xeq", ebuff);
return Response.Send(kXR_NoMemory, ebuff);
}
// First open the directory
//
dp->error.setUCap(clientPV);
if ((rc = dp->open(argp->buff, CRED, opaque)))
{rc = fsError(rc, XROOTD_MON_OPENDIR, dp->error, argp->buff, opaque);
delete dp;
return rc;
}
// Check if the caller wants stat information as well
//
if (Request.dirlist.options[0] & (kXR_dstat | kXR_dcksm))
return do_DirStat(dp, ebuff, opaque);
// Start retreiving each entry and place in a local buffer with a trailing new
// line character (the last entry will have a null byte). If we cannot fit a
// full entry in the buffer, send what we have with an OKSOFAR and continue.
// This code depends on the fact that a directory entry will never be longer
// than sizeof( ebuff)-1; otherwise, an infinite loop will result. No errors
// are allowed to be reflected at this point.
//
dname = 0;
do {buff = ebuff; bleft = sizeof(ebuff);
while(dname || (dname = dp->nextEntry()))
{dlen = strlen(dname);
if (dlen > 2 || dname[0] != '.' || (dlen == 2 && dname[1] != '.'))
{if ((bleft -= (dlen+1)) < 0) break;
strcpy(buff, dname); buff += dlen; *buff = '\n'; buff++; cnt++;
}
dname = 0;
}
if (dname) rc = Response.Send(kXR_oksofar, ebuff, buff-ebuff);
} while(!rc && dname);
// Send the ending packet if we actually have one to send
//
if (!rc)
{if (ebuff == buff) rc = Response.Send();
else {*(buff-1) = '\0';
rc = Response.Send((void *)ebuff, buff-ebuff);
}
}
// Close the directory
//
dp->close();
delete dp;
if (!rc) {TRACEP(FS, "dirlist entries=" <<cnt <<" path=" <<argp->buff);}
return rc;
}
/******************************************************************************/
/* d o _ D i r S t a t */
/******************************************************************************/
int XrdXrootdProtocol::do_DirStat(XrdSfsDirectory *dp, char *pbuff,
char *opaque)
{
XrdOucErrInfo myError(Link->ID, Monitor.Did, clientPV);
struct stat Stat;
char *buff, *dLoc, *algT = 0;
const char *csData, *dname;
int bleft, rc = 0, dlen, cnt = 0, statSz = 160;
bool manStat;
struct {char ebuff[8192]; char epad[512];} XB;
// Preprocess checksum request. If we don't support checksums or if the
// requested checksum type is not supported, ignore it.
//
if ((Request.dirlist.options[0] & kXR_dcksm) && JobLCL)
{char cksT[64];
algT = getCksType(opaque, cksT, sizeof(cksT));
if (!algT)
{char ebuf[1024];
snprintf(ebuf, sizeof(ebuf), "%s checksum not supported.", cksT);
return Response.Send(kXR_ServerError, ebuf);
}
statSz += XrdCksData::NameSize + (XrdCksData::ValuSize*2) + 8;
}
// We always return stat information, see if we can use autostat
//
manStat = (dp->autoStat(&Stat) != SFS_OK);
// Construct the path to the directory as we will be asking for stat calls
// if the interface does not support autostat or returning checksums.
//
if (manStat || algT)
{strcpy(pbuff, argp->buff);
dlen = strlen(pbuff);
if (pbuff[dlen-1] != '/') {pbuff[dlen] = '/'; dlen++;}
dLoc = pbuff+dlen;
} else dLoc = 0;
// The initial leadin is a "dot" entry to indicate to the client that we
// support the dstat option (older servers will not do that). It's up to the
// client to issue individual stat requests in that case.
//
memset(&Stat, 0, sizeof(Stat));
strcpy(XB.ebuff, ".\n0 0 0 0\n");
buff = XB.ebuff+10; bleft = sizeof(XB.ebuff)-10;
// Start retreiving each entry and place in a local buffer with a trailing new
// line character (the last entry will have a null byte). If we cannot fit a
// full entry in the buffer, send what we have with an OKSOFAR and continue.
// This code depends on the fact that a directory entry will never be longer
// than sizeof( ebuff)-1; otherwise, an infinite loop will result. No errors
// are allowed to be reflected at this point.
//
dname = 0;
do {while(dname || (dname = dp->nextEntry()))
{dlen = strlen(dname);
if (dlen > 2 || dname[0] != '.' || (dlen == 2 && dname[1] != '.'))
{if ((bleft -= (dlen+1)) < 0 || bleft < statSz) break;
if (dLoc) strcpy(dLoc, dname);
if (manStat)
{rc = osFS->stat(pbuff, &Stat, myError, CRED, opaque);
if (rc == SFS_ERROR && myError.getErrInfo() == ENOENT)
{dname = 0; continue;}
if (rc != SFS_OK)
return fsError(rc, XROOTD_MON_STAT, myError,
argp->buff, opaque);
}
strcpy(buff, dname); buff += dlen; *buff = '\n'; buff++; cnt++;
dlen = StatGen(Stat, buff, sizeof(XB.epad));
bleft -= dlen; buff += (dlen-1);
if (algT)
{int ec = osFS->chksum(XrdSfsFileSystem::csGet, algT,
pbuff, myError, CRED, opaque);
csData = myError.getErrText();
if (ec != SFS_OK || !(*csData) || *csData == '!')
csData = "none";
int n = snprintf(buff,sizeof(XB.epad)," [ %s:%s ]",
algT, csData);
buff += n; bleft -= n;
}
*buff = '\n'; buff++;
}
dname = 0;
}
if (dname)
{rc = Response.Send(kXR_oksofar, XB.ebuff, buff-XB.ebuff);
buff = XB.ebuff; bleft = sizeof(XB.ebuff);
TRACEP(FS, "dirstat sofar n=" <<cnt <<" path=" <<argp->buff);
}
} while(!rc && dname);
// Send the ending packet if we actually have one to send
//
if (!rc)
{if (XB.ebuff == buff) rc = Response.Send();
else {*(buff-1) = '\0';
rc = Response.Send((void *)XB.ebuff, buff-XB.ebuff);
}
}
// Close the directory
//
dp->close();
delete dp;
if (!rc) {TRACEP(FS, "dirstat entries=" <<cnt <<" path=" <<argp->buff);}
return rc;
}
/******************************************************************************/
/* d o _ E n d s e s s */
/******************************************************************************/
int XrdXrootdProtocol::do_Endsess()
{
XrdXrootdSessID *sp, sessID;
int rc;
// Update misc stats count
//
SI->Bump(SI->miscCnt);
// Extract out the FD and Instance from the session ID
//
sp = (XrdXrootdSessID *)Request.endsess.sessid;
memcpy((void *)&sessID.Pid, &sp->Pid, sizeof(sessID.Pid));
memcpy((void *)&sessID.FD, &sp->FD, sizeof(sessID.FD));
memcpy((void *)&sessID.Inst, &sp->Inst, sizeof(sessID.Inst));
// Trace this request
//
TRACEP(LOGIN, "endsess " <<sessID.Pid <<':' <<sessID.FD <<'.' <<sessID.Inst);
// If this session id does not refer to us, ignore the request
//
if (sessID.Pid != myPID) return Response.Send();
// Terminate the indicated session, if possible. This could also be a self-termination.
//
if ((sessID.FD == 0 && sessID.Inst == 0)
|| !(rc = Link->Terminate(0, sessID.FD, sessID.Inst))) return -1;
// Trace this request
//
TRACEP(LOGIN, "endsess " <<sessID.Pid <<':' <<sessID.FD <<'.' <<sessID.Inst
<<" rc=" <<rc <<" (" <<XrdSysE2T(rc < 0 ? -rc : EAGAIN) <<")");
// Return result. We only return obvious problems (exclude ESRCH and EPIPE).
//
if (rc > 0)
return (rc = Response.Send(kXR_wait, rc, "session still active")) ? rc:1;
if (rc == -EACCES)return Response.Send(kXR_NotAuthorized, "not session owner");
if (rc == -ETIME) return Response.Send(kXR_Cancelled,"session not ended");
return Response.Send();
}
/******************************************************************************/
/* d o _ F A t t r */
/* */
/* Resides in XrdXrootdXeqFAttr.cc */
/******************************************************************************/
/******************************************************************************/
/* d o _ g p F i l e */
/******************************************************************************/
int XrdXrootdProtocol::do_gpFile()
{
// int gopts, buffsz;
// Keep Statistics (TO DO: differentiate get vs put)
//
SI->Bump(SI->getfCnt);
// SI->Bump(SI->putfCnt);
// Check if gpfile need to occur on a TLS connection
//
if ((doTLS & Req_TLSGPFile) && !isTLS && !Link->hasBridge())
return Response.Send(kXR_TLSRequired, "gpfile requires TLS");
return Response.Send(kXR_Unsupported, "gpfile request is not supported");
}
/******************************************************************************/
/* d o _ L o c a t e */
/******************************************************************************/
int XrdXrootdProtocol::do_Locate()
{
static XrdXrootdCallBack locCB("locate", XROOTD_MON_LOCATE);
int rc, opts, fsctl_cmd = SFS_FSCTL_LOCATE;
char *opaque = 0, *Path, *fn = argp->buff, opt[8], *op=opt;
XrdOucErrInfo myError(Link->ID,&locCB,ReqID.getID(),Monitor.Did,clientPV);
bool doDig = false;
// Unmarshall the data
//
opts = (int)ntohs(Request.locate.options);
// Map the options
//
if (opts & kXR_nowait) {fsctl_cmd |= SFS_O_NOWAIT; *op++ = 'i';}
if (opts & kXR_refresh) {fsctl_cmd |= SFS_O_RESET; *op++ = 's';}
if (opts & kXR_force ) {fsctl_cmd |= SFS_O_FORCE; *op++ = 'f';}
if (opts & kXR_prefname){fsctl_cmd |= SFS_O_HNAME; *op++ = 'n';}
if (opts & kXR_compress){fsctl_cmd |= SFS_O_RAWIO; *op++ = 'u';}
if (opts & kXR_4dirlist){fsctl_cmd |= SFS_O_DIRLIST;*op++ = 'D';}
*op = '\0';
TRACEP(FS, "locate " <<opt <<' ' <<fn);
// Check if this is a non-specific locate
//
if (*fn != '*'){Path = fn;
doDig = (digFS && SFS_LCLROOT(Path));
}
else if (*(fn+1)) {Path = fn+1;
doDig = (digFS && SFS_LCLROOT(Path));
}
else {Path = 0;
fn = XPList.Next()->Path();
fsctl_cmd |= SFS_O_TRUNC;
}
// Check for static routing
//
if (!doDig) {STATIC_REDIRECT(RD_locate);}
// Prescreen the path
//
if (Path)
{if (rpCheck(Path, &opaque)) return rpEmsg("Locating", Path);
if (!doDig && !Squash(Path))return vpEmsg("Locating", Path);
}
// Preform the actual function. For regular Fs add back any opaque info
//
if (doDig) rc = digFS->fsctl(fsctl_cmd, fn, myError, CRED);
else {if (opaque)
{int n = strlen(argp->buff); argp->buff[n] = '?';
if ((argp->buff)+n != opaque-1)
memmove(&argp->buff[n+1], opaque, strlen(opaque)+1);
}
rc = osFS->fsctl(fsctl_cmd, fn, myError, CRED);
}
TRACEP(FS, "rc=" <<rc <<" locate " <<fn);
return fsError(rc, (doDig ? 0 : XROOTD_MON_LOCATE), myError, Path, opaque);
}
/******************************************************************************/
/* d o _ L o g i n */
/*.x***************************************************************************/
int XrdXrootdProtocol::do_Login()
{
XrdXrootdSessID sessID;
XrdNetAddrInfo *addrP;
int i, pid, rc, sendSID = 0;
char uname[sizeof(Request.login.username)+1];
// Keep Statistics
//
SI->Bump(SI->LoginAT);
// Check if login need to occur on a TLS connection
//
if ((doTLS & Req_TLSLogin) && !isTLS && !Link->hasBridge())
{const char *emsg = "login requires TLS be enabled";
if (!ableTLS)
{emsg = "login requires TLS support";
eDest.Emsg("Xeq","login requires TLS but",Link->ID,"is incapable.");
}
return Response.Send(kXR_TLSRequired, emsg);
}
// Unmarshall the pid and construct username using the POSIX.1-2008 standard
//
pid = (int)ntohl(Request.login.pid);
strncpy(uname, (const char *)Request.login.username, sizeof(uname)-1);
uname[sizeof(uname)-1] = 0;
XrdOucUtils::Sanitize(uname);
// Make sure the user is not already logged in
//
if (Status) return Response.Send(kXR_InvalidRequest,
"duplicate login; already logged in");
// Establish the ID for this link
//
Link->setID(uname, pid);
CapVer = Request.login.capver[0];
// Establish the session ID if the client can handle it (protocol version > 0)
//
if ((i = (CapVer & kXR_vermask)))
{sessID.FD = Link->FDnum();
sessID.Inst = Link->Inst();
sessID.Pid = myPID;
mySID = getSID();
sessID.Sid = mySID;
sendSID = 1;
if (!clientPV)
{ if (i >= kXR_ver004) clientPV = (int)0x0310;
else if (i == kXR_ver003) clientPV = (int)0x0300;
else if (i == kXR_ver002) clientPV = (int)0x0290;
else if (i == kXR_ver001) clientPV = (int)0x0200;
else clientPV = (int)0x0100;
}
if (CapVer & kXR_asyncap) clientPV |= XrdOucEI::uAsync;
if (Request.login.ability & kXR_fullurl)
clientPV |= XrdOucEI::uUrlOK;
if (Request.login.ability & kXR_lclfile)
clientPV |= XrdOucEI::uLclF;
if (Request.login.ability & kXR_multipr)
clientPV |= (XrdOucEI::uMProt | XrdOucEI::uUrlOK);
if (Request.login.ability & kXR_readrdok)
clientPV |= XrdOucEI::uReadR;
if (Request.login.ability & kXR_hasipv64)
clientPV |= XrdOucEI::uIPv64;
if (Request.login.ability & kXR_redirflags)
clientPV |= XrdOucEI::uRedirFlgs;
if (Request.login.ability2 & kXR_ecredir )
clientPV |= XrdOucEI::uEcRedir;
}
// Mark the client as IPv4 if they came in as IPv4 or mapped IPv4 we can only
// return IPv4 addresses. Of course, if the client is dual-stacked then we
// simply indicate the client can accept either (the client better be honest).
//
addrP = Link->AddrInfo();
if (addrP->isIPType(XrdNetAddrInfo::IPv4) || addrP->isMapped())
clientPV |= XrdOucEI::uIPv4;
// WORKAROUND: XrdCl 4.0.x often identifies worker nodes as being IPv6-only.
// Rather than breaking a significant number of our dual-stack workers, we
// automatically denote IPv6 connections as also supporting IPv4 - regardless
// of what the remote client claims. This was fixed in 4.3.x but we can't
// tell release differences until 4.5 when we can safely ignore this as we
// also don't want to misidentify IPv6-only clients either.
else if (i < kXR_ver004 && XrdInet::GetAssumeV4())
clientPV |= XrdOucEI::uIPv64;
// Mark the client as being on a private net if the address is private
//
if (addrP->isPrivate()) {clientPV |= XrdOucEI::uPrip; rdType = 1;}
else rdType = 0;
// Get the security token for this link. We will either get a token, a null
// string indicating host-only authentication, or a null indicating no
// authentication. We can then optimize of each case.
//
if (CIA)
{const char *pp=CIA->getParms(i, Link->AddrInfo());
if (pp && i ) {if (!sendSID) rc = Response.Send((void *)pp, i);
else {struct iovec iov[3];
iov[1].iov_base = (char *)&sessID;
iov[1].iov_len = sizeof(sessID);
iov[2].iov_base = (char *)pp;
iov[2].iov_len = i;
rc = Response.Send(iov,3,int(i+sizeof(sessID)));
}
Status = (XRD_LOGGEDIN | XRD_NEED_AUTH);
}
else {rc = (sendSID ? Response.Send((void *)&sessID, sizeof(sessID))
: Response.Send());
Status = XRD_LOGGEDIN; SI->Bump(SI->LoginUA);
}
}
else {rc = (sendSID ? Response.Send((void *)&sessID, sizeof(sessID))
: Response.Send());
Status = XRD_LOGGEDIN; SI->Bump(SI->LoginUA);
}
// We always allow at least host-based authentication. This may be over-ridden
// should strong authentication be enabled. Allocation of the protocol object
// already supplied the protocol name and the host name. We supply the tident
// and the connection details in addrInfo.
//
Entity.tident = Entity.pident = Link->ID;
Entity.addrInfo = Link->AddrInfo();
Client = &Entity;
// Check if we need to process a login environment
//
if (Request.login.dlen > 8)
{XrdOucEnv loginEnv(argp->buff+1, Request.login.dlen-1);
char *rnumb = loginEnv.Get("xrd.rn");
char *cCode = loginEnv.Get("xrd.cc");
char *tzVal = loginEnv.Get("xrd.tz");
char *appXQ = loginEnv.Get("xrd.appname");
char *aInfo = loginEnv.Get("xrd.info");
int tzNum = (tzVal ? atoi(tzVal) : 0);
if (cCode && *cCode && tzNum >= -12 && tzNum <= 14)
{XrdNetAddrInfo::LocInfo locInfo;
locInfo.Country[0] = cCode[0]; locInfo.Country[1] = cCode[1];
locInfo.TimeZone = tzNum & 0xff;
Link->setLocation(locInfo);
}
if (Monitor.Ready() && (appXQ || aInfo))
{char apBuff[1024];
snprintf(apBuff, sizeof(apBuff), "&R=%s&x=%s&y=%s&I=%c",
(rnumb ? rnumb : ""),
(appXQ ? appXQ : ""), (aInfo ? aInfo : ""),
(clientPV & XrdOucEI::uIPv4 ? '4' : '6'));
Entity.moninfo = strdup(apBuff);
}
if (rnumb)
{int majr, minr, pchr;
if (sscanf(rnumb, "v%d.%d.%d", &majr, &minr, &pchr) == 3)
clientRN = (majr<<16) | ((minr<<8) | pchr);
else if (sscanf(rnumb, "v%d-%*x", &majr) == 1) clientRN = -1;
}
if (appXQ) AppName = strdup(appXQ);
}
// Allocate a monitoring object, if needed for this connection
//
if (Monitor.Ready())
{Monitor.Register(Link->ID, Link->Host(), "xroot", mySID);
if (Monitor.Logins() && (!Monitor.Auths() || !(Status & XRD_NEED_AUTH)))
{Monitor.Report(Entity.moninfo);
if (Entity.moninfo) {free(Entity.moninfo); Entity.moninfo = 0;}
Entity.secMon = &Monitor;
}
}
// Complete the rquestID object
//
ReqID.setID(Request.header.streamid, Link->FDnum(), Link->Inst());
// Document this login
//
if (!(Status & XRD_NEED_AUTH) && !logLogin()) return -1;
return rc;
}
/******************************************************************************/
/* d o _ M k d i r */
/******************************************************************************/
int XrdXrootdProtocol::do_Mkdir()
{
int mode, rc;
char *opaque;
XrdOucErrInfo myError(Link->ID, Monitor.Did, clientPV);
// Check for static routing
//
STATIC_REDIRECT(RD_mkdir);
// Unmarshall the data
//
mode = mapMode((int)ntohs(Request.mkdir.mode)) | S_IRWXU;
if (Request.mkdir.options[0] & static_cast<unsigned char>(kXR_mkdirpath))
mode |= SFS_O_MKPTH;
if (rpCheck(argp->buff, &opaque)) return rpEmsg("Creating", argp->buff);
if (!Squash(argp->buff)) return vpEmsg("Creating", argp->buff);
// Preform the actual function
//
rc = osFS->mkdir(argp->buff, (XrdSfsMode)mode, myError, CRED, opaque);
TRACEP(FS, "rc=" <<rc <<" mkdir " <<Xrd::oct1 <<mode <<' ' <<argp->buff);
if (SFS_OK == rc) return Response.Send();
// An error occurred
//
return fsError(rc, XROOTD_MON_MKDIR, myError, argp->buff, opaque);
}
/******************************************************************************/
/* d o _ M v */
/******************************************************************************/
int XrdXrootdProtocol::do_Mv()
{
int rc;
char *oldp, *newp, *Opaque, *Npaque;
XrdOucErrInfo myError(Link->ID, Monitor.Did, clientPV);
// Check for static routing
//
STATIC_REDIRECT(RD_mv);
// Find the space separator between the old and new paths
//
oldp = newp = argp->buff;
if (Request.mv.arg1len)
{int n = ntohs(Request.mv.arg1len);
if (n < 0 || n >= Request.mv.dlen || *(argp->buff+n) != ' ')
return Response.Send(kXR_ArgInvalid, "invalid path specification");
*(oldp+n) = 0;
newp += n+1;
} else {
while(*newp && *newp != ' ') newp++;
if (*newp) {*newp = '\0'; newp++;
while(*newp && *newp == ' ') newp++;
}
}
// Get rid of relative paths and multiple slashes
//
if (rpCheck(oldp, &Opaque)) return rpEmsg("Renaming", oldp);
if (rpCheck(newp, &Npaque)) return rpEmsg("Renaming to", newp);
if (!Squash(oldp)) return vpEmsg("Renaming", oldp);
if (!Squash(newp)) return vpEmsg("Renaming to", newp);
// Check if new path actually specified here
//
if (*newp == '\0')
Response.Send(kXR_ArgMissing, "new path specified for mv");
// Preform the actual function
//
rc = osFS->rename(oldp, newp, myError, CRED, Opaque, Npaque);
TRACEP(FS, "rc=" <<rc <<" mv " <<oldp <<' ' <<newp);
if (SFS_OK == rc) return Response.Send();
// An error occurred
//
return fsError(rc, XROOTD_MON_MV, myError, oldp, Opaque);
}
/******************************************************************************/
/* d o _ O f f l o a d */
/******************************************************************************/
int XrdXrootdProtocol::do_Offload(int (XrdXrootdProtocol::*Invoke)(),int pathID)
{
XrdSysSemaphore isAvail(0);
XrdXrootdProtocol *pp;
XrdXrootdPio *pioP;
int rc;
kXR_char streamID[2];
// Verify that the path actually exists (note we will have the stream lock)
//
if (!(pp = VerifyStream(rc, pathID))) return rc;
// Grab the stream ID
//
Response.StreamID(streamID);
// Try to schedule this operation. In order to maximize the I/O overlap, we
// will wait until the stream gets control and will have a chance to start
// reading from the network. We handle refs for consistency.
//
do{if (!pp->isActive)
{pp->IO = IO;
pp->myBlen = 0;
pp->Resume = &XrdXrootdProtocol::do_OffloadIO;
pp->ResumePio= Invoke;
pp->isActive = true;
pp->newPio = true;
pp->reTry = &isAvail;
pp->Response.Set(streamID);
pp->streamMutex.UnLock();
Link->setRef(1);
IO.File->Ref(1);
Sched->Schedule((XrdJob *)(pp->Link));
isAvail.Wait();
return 0;
}
if ((pioP = pp->pioFree)) break;
pp->reTry = &isAvail;
pp->streamMutex.UnLock();
TRACEP(FSZIO, "busy path " <<pathID <<" offs=" <<IO.Offset);
isAvail.Wait();
TRACEP(FSZIO, "retry path " <<pathID <<" offs=" <<IO.Offset);
pp->streamMutex.Lock();
if (pp->isNOP)
{pp->streamMutex.UnLock();
return Response.Send(kXR_ArgInvalid, "path ID is not connected");
}
} while(1);
// Fill out the queue entry and add it to the queue
//
pp->pioFree = pioP->Next; pioP->Next = 0;
pioP->Set(Invoke, IO, streamID);
IO.File->Ref(1);
if (pp->pioLast) pp->pioLast->Next = pioP;
else pp->pioFirst = pioP;
pp->pioLast = pioP;
pp->streamMutex.UnLock();
return 0;
}
/******************************************************************************/
/* d o _ O f f l o a d I O */
/******************************************************************************/
int XrdXrootdProtocol::do_OffloadIO()
{
XrdXrootdPio *pioP;
int rc;
// Entry implies that we just got scheduled and are marked as active. Hence
// we need to post the session thread so that it can pick up the next request.
//
streamMutex.Lock();
isLinkWT = false;
if (newPio)
{newPio = false;
if (reTry) {reTry->Post(); reTry = 0;}
TRACEP(FSZIO, "dispatch new I/O path " <<PathID <<" offs=" <<IO.Offset);
}
// Perform all I/O operations on a parallel stream
//
if (!isNOP)
do {streamMutex.UnLock();
rc = (*this.*ResumePio)();
streamMutex.Lock();
if (rc > 0 && !isNOP)
{ResumePio = Resume;
Resume = &XrdXrootdProtocol::do_OffloadIO;
isLinkWT = true;
streamMutex.UnLock();
return rc;
}
IO.File->Ref(-1); // Note: File was ref'd when request was queued
if (rc || isNOP || !(pioP = pioFirst)) break;
if (!(pioFirst = pioP->Next)) pioLast = 0;
IO = pioP->IO;
ResumePio = pioP->ResumePio;
Response.Set(pioP->StreamID);
pioP->Next = pioFree; pioFree = pioP;
if (reTry) {reTry->Post(); reTry = 0;}
} while(1);
else {rc = -1; IO.File->Ref(-1);}
// There are no pending operations or the link died
//
if (rc) isNOP = true;
isActive = false;
Stream[0]->Link->setRef(-1);
if (reTry) {reTry->Post(); reTry = 0;}
if (endNote) endNote->Signal();
streamMutex.UnLock();
TRACEP(FSZIO, "offload complete path "<<PathID<<" virt rc=" <<rc);
return (rc ? rc : -EINPROGRESS);
}
/******************************************************************************/
/* d o _ O p e n */
/******************************************************************************/
namespace
{
struct OpenHelper
{XrdSfsFile *fp;
XrdXrootdFile *xp;
XrdXrootdFileLock *Locker;
const char *path;
char mode;
bool isOK;
OpenHelper(XrdXrootdFileLock *lkP, const char *fn)
: fp(0), xp(0), Locker(lkP), path(fn), mode(0),
isOK(false) {}
~OpenHelper()
{if (!isOK)
{if (xp) delete xp; // Deletes fp & unlocks
else {if (fp) delete fp;
if (mode) Locker->Unlock(path,mode);
}
}
}
};
}
int XrdXrootdProtocol::do_Open()
{
static XrdXrootdCallBack openCB("open file", XROOTD_MON_OPENR);
int fhandle;
int rc, mode, opts, openopts, compchk = 0;
int popt, retStat = 0;
char *opaque, usage, ebuff[2048], opC;
bool doDig, doforce = false, isAsync = false;
char *fn = argp->buff, opt[16], *op=opt;
XrdSfsFile *fp;
XrdXrootdFile *xp;
struct stat statbuf;
struct ServerResponseBody_Open myResp;
int resplen = sizeof(myResp.fhandle);
struct iovec IOResp[3]; // Note that IOResp[0] is completed by Response
// Keep Statistics
//
SI->Bump(SI->openCnt);
// Unmarshall the data
//
mode = (int)ntohs(Request.open.mode);
opts = (int)ntohs(Request.open.options);
// Map the mode and options
//
mode = mapMode(mode) | S_IRUSR | S_IWUSR; usage = 'r';
if (opts & kXR_open_read)
{openopts = SFS_O_RDONLY; *op++ = 'r'; opC = XROOTD_MON_OPENR;}
else if (opts & kXR_open_updt)
{openopts = SFS_O_RDWR; *op++ = 'u'; usage = 'w';
opC = XROOTD_MON_OPENW;}
else if (opts & kXR_open_wrto)
{openopts = SFS_O_WRONLY; *op++ = 'o'; usage = 'w';
opC = XROOTD_MON_OPENW;}
else {openopts = SFS_O_RDONLY; *op++ = 'r'; opC = XROOTD_MON_OPENR;}
if (opts & kXR_new)
{openopts |= SFS_O_CREAT; *op++ = 'n'; opC = XROOTD_MON_OPENC;
if (opts & kXR_replica) {*op++ = '+';
openopts |= SFS_O_REPLICA;
}
// Up until 3/28/19 we mistakenly used kXR_mkdir instead of
// kXR_mkpath to allow path creation. That meant, path creation was
// allowed if _mkpath|_async|_refresh|_open_apnd|_replica were set.
// Since the client has always turned on _async that meant that
// path creation was always enabled. We continue this boondogle
// using the correct flag for backward compatibility reasons, sigh.
//
if (opts & (kXR_mkpath | kXR_async))
{*op++ = 'm';
mode |= SFS_O_MKPTH;
}
}
else if (opts & kXR_delete)
{openopts = SFS_O_TRUNC; *op++ = 'd'; opC = XROOTD_MON_OPENW;
if (opts & (kXR_mkpath | kXR_async))
{*op++ = 'm';
mode |= SFS_O_MKPTH;
}
}
if (opts & kXR_compress)
{openopts |= SFS_O_RAWIO; *op++ = 'c'; compchk = 1;}
if (opts & kXR_force) {*op++ = 'f'; doforce = true;}
if ((opts & kXR_async || as_force) && as_aioOK)
{*op++ = 'a'; isAsync = true;}
if (opts & kXR_refresh) {*op++ = 's'; openopts |= SFS_O_RESET;
SI->Bump(SI->Refresh);
}
if (opts & kXR_retstat) {*op++ = 't'; retStat = 1;}
if (opts & kXR_posc) {*op++ = 'p'; openopts |= SFS_O_POSC;}
if (opts & kXR_seqio) {*op++ = 'S'; openopts |= SFS_O_SEQIO;}
*op = '\0';
// Do some tracing, avoid exposing any security token in the URL
//
if (TRACING(TRACE_FS))
{char* cgiP = index(fn, '?');
if (cgiP) *cgiP = 0;
TRACEP(FS, "open " <<opt <<' ' <<fn);
if (cgiP) *cgiP = '?';
}
// Check if opaque data has been provided
//
if (rpCheck(fn, &opaque)) return rpEmsg("Opening", fn);
// Check if this is a local dig type file
//
doDig = (digFS && SFS_LCLPATH(fn));
// Validate the path and then check if static redirection applies
//
if (doDig) {popt = XROOTDXP_NOLK; opC = 0;}
else {int ropt;
if (!(popt = Squash(fn))) return vpEmsg("Opening", fn);
if (Route[RD_open1].Host[rdType] && (ropt = RPList.Validate(fn)))
return Response.Send(kXR_redirect, Route[ropt].Port[rdType],
Route[ropt].Host[rdType]);
}
// Add the multi-write option if this path supports it
//
if (popt & XROOTDXP_NOMWCHK) openopts |= SFS_O_MULTIW;
// Construct an open helper to release resources should we exit due to an error.
//
OpenHelper oHelp(Locker, fn);
// Lock this file
//
if (!(popt & XROOTDXP_NOLK))
{if ((rc = Locker->Lock(fn, usage, doforce)))
{const char *who;
if (rc > 0) who = (rc > 1 ? "readers" : "reader");
else { rc = -rc;
who = (rc > 1 ? "writers" : "writer");
}
snprintf(ebuff, sizeof(ebuff)-1,
"%s file %s is already opened by %d %s; open denied.",
('r' == usage ? "Input" : "Output"), fn, rc, who);
eDest.Emsg("Xeq", ebuff);
return Response.Send(kXR_FileLocked, ebuff);
} else oHelp.mode = usage;
}
// Get a file object
//
if (doDig) fp = digFS->newFile(Link->ID, Monitor.Did);
else fp = osFS->newFile(Link->ID, Monitor.Did);
// Make sure we got one
//
if (!fp)
{snprintf(ebuff, sizeof(ebuff)-1,"Insufficient memory to open %s",fn);
eDest.Emsg("Xeq", ebuff);
return Response.Send(kXR_NoMemory, ebuff);
}
oHelp.fp = fp;
// The open is elegible for a deferred response, indicate we're ok with that
//
fp->error.setErrCB(&openCB, ReqID.getID());
fp->error.setUCap(clientPV);
// If TPC opens require TLS but this is not a TLS connection, prohibit TPC
//
if ((doTLS & Req_TLSTPC) && !isTLS && !Link->hasBridge())
openopts|= SFS_O_NOTPC;
// Open the file
//
if ((rc = fp->open(fn, (XrdSfsFileOpenMode)openopts,
(mode_t)mode, CRED, opaque)))
{rc = fsError(rc, opC, fp->error, fn, opaque); return rc;}
// Obtain a hyper file object
//
xp = new XrdXrootdFile(Link->ID, fn, fp, usage, isAsync, &statbuf);
if (!xp)
{snprintf(ebuff, sizeof(ebuff)-1, "Insufficient memory to open %s", fn);
eDest.Emsg("Xeq", ebuff);
return Response.Send(kXR_NoMemory, ebuff);
}
oHelp.xp = xp;
// Serialize the link
//
Link->Serialize();
*ebuff = '\0';
// Create a file table for this link if it does not have one
//
if (!FTab) FTab = new XrdXrootdFileTable(Monitor.Did);
// Insert this file into the link's file table
//
if (!FTab || (fhandle = FTab->Add(xp)) < 0)
{snprintf(ebuff, sizeof(ebuff)-1, "Insufficient memory to open %s", fn);
eDest.Emsg("Xeq", ebuff);
return Response.Send(kXR_NoMemory, ebuff);
}
// If the file supports exchange buffering, supply it with the object
//
if (fsFeatures & XrdSfs::hasSXIO) fp->setXio(this);
// Document forced opens
//
if (doforce)
{int rdrs, wrtrs;
Locker->numLocks(fn, rdrs, wrtrs);
if (('r' == usage && wrtrs) || ('w' == usage && rdrs) || wrtrs > 1)
{snprintf(ebuff, sizeof(ebuff)-1,
"%s file %s forced opened with %d reader(s) and %d writer(s).",
('r' == usage ? "Input" : "Output"), fn, rdrs, wrtrs);
eDest.Emsg("Xeq", ebuff);
}
}
// Determine if file is compressed
//
memset(&myResp, 0, sizeof(myResp));
if (!compchk) resplen = sizeof(myResp.fhandle);
else {int cpsize;
fp->getCXinfo((char *)myResp.cptype, cpsize);
myResp.cpsize = static_cast<kXR_int32>(htonl(cpsize));
resplen = sizeof(myResp);
}
// If client wants a stat in open, return the stat information
//
if (retStat)
{retStat = StatGen(statbuf, ebuff, sizeof(ebuff));
IOResp[1].iov_base = (char *)&myResp; IOResp[1].iov_len = sizeof(myResp);
IOResp[2].iov_base = ebuff; IOResp[2].iov_len = retStat;
resplen = sizeof(myResp) + retStat;
}
// If we are monitoring, send off a path to dictionary mapping (must try 1st!)
//
if (Monitor.Files())
{xp->Stats.FileID = Monitor.MapPath(fn);
if (!(xp->Stats.monLvl)) xp->Stats.monLvl = XrdXrootdFileStats::monOn;
Monitor.Agent->Open(xp->Stats.FileID, statbuf.st_size);
}
// Since file monitoring is deprecated, a dictid may not have been assigned.
// But if fstream monitoring is enabled it will assign the dictid.
//
if (Monitor.Fstat())
XrdXrootdMonFile::Open(&(xp->Stats), fn, Monitor.Did, usage == 'w');
// Insert the file handle
//
memcpy((void *)myResp.fhandle,(const void *)&fhandle,sizeof(myResp.fhandle));
numFiles++;
// If packet marking is enabled, notify that we have potentially started data.
// We also need to extend the marking to any associated streams.
//
int eCode, aCode;
if (PMark && !pmDone)
{streamMutex.Lock();
pmDone = true;
if ((pmHandle = PMark->Begin(*Client, fn, opaque, AppName)))
for (int i = 1; i < maxStreams; i++)
{if (Stream[i] && !(Stream[i]->pmDone))
{Stream[i]->pmDone = true;
Stream[i]->pmHandle =
PMark->Begin(*(Stream[i]->Link->AddrInfo()),
*pmHandle, Stream[i]->Link->ID);
}
}
streamMutex.UnLock();
if (pmHandle && Monitor.Logins() && pmHandle->getEA(eCode, aCode))
Monitor.Report(eCode, aCode);
} else {
if (!pmDone && Monitor.Logins()
&& XrdNetPMark::getEA(opaque, eCode, aCode))
{Monitor.Report(eCode, aCode); pmDone = true;}
}
// Respond (failure is not an option now)
//
oHelp.isOK = true;
if (retStat) return Response.Send(IOResp, 3, resplen);
else return Response.Send((void *)&myResp, resplen);
}
/******************************************************************************/
/* d o _ P i n g */
/******************************************************************************/
int XrdXrootdProtocol::do_Ping()
{
// Keep Statistics
//
SI->Bump(SI->miscCnt);
// This is a basic nop
//
return Response.Send();
}
/******************************************************************************/
/* d o _ P r e p a r e */
/******************************************************************************/
int XrdXrootdProtocol::do_Prepare(bool isQuery)
{
static XrdXrootdCallBack prpCB("query", XROOTD_MON_QUERY);
XrdOucErrInfo myError(Link->ID, Monitor.Did, clientPV);
XrdOucTokenizer pathlist(argp->buff);
XrdOucTList *pFirst=0, *pP, *pLast = 0;
XrdOucTList *oFirst=0, *oP, *oLast = 0;
XrdOucTListHelper pHelp(&pFirst), oHelp(&oFirst);
XrdXrootdPrepArgs pargs(0, 0);
XrdSfsPrep fsprep;
int rc, pathnum = 0;
char reqid[128], nidbuff[512], *path, *opaque, *prpid = 0;
unsigned short optX = ntohs(Request.prepare.optionX);
char opts;
bool isCancel, isEvict, isPrepare;
// Check if this is an evict request (similar to stage)
//
isEvict = (optX & kXR_evict) != 0;
// Establish what we are really doing here
//
if (isQuery)
{opts = 0;
isCancel = false;
} else {
if (Request.prepare.options & kXR_cancel)
{opts = 0;
isCancel = true;
} else {
opts = (isEvict ? 0 : Request.prepare.options);
isCancel = false;
}
}
isPrepare = !(isCancel || isQuery);
// Apply prepare limits, as necessary.
//
if (isPrepare && (PrepareLimit >= 0) && (++PrepareCount > PrepareLimit)) {
if (LimitError) {
return Response.Send( kXR_overQuota,
"Surpassed this connection's prepare limit.");
} else {
return Response.Send();
}
}
// Check for static routing
//
if ((opts & kXR_stage) || isCancel) {STATIC_REDIRECT(RD_prepstg);}
STATIC_REDIRECT(RD_prepare);
// Prehandle requests that must have a requestID. Otherwise, generate one.
// Note that prepare request id's have two formats. The external format is
// is qualifiaed by this host while the internal one removes the qualification.
// The internal one is only used for the native prepare implementation.
// To wit: prpid is the unqualified ID while reqid is the qualified one for
// generated id's while prpid is always the specified request id.
//
if (isCancel || isQuery)
{if (!(prpid = pathlist.GetLine()))
return Response.Send(kXR_ArgMissing, "Prepare requestid not specified");
fsprep.reqid = prpid;
fsprep.opts = (isCancel ? Prep_CANCEL : Prep_QUERY);
if (!PrepareAlt)
{char hname[256];
int hport;
prpid = PrepID->isMine(prpid, hport, hname, sizeof(hname));
if (!prpid)
{if (!hport) return Response.Send(kXR_ArgInvalid,
"Prepare requestid owned by an unknown server");
TRACEI(REDIR, Response.ID() <<" redirecting prepare to "
<< hname <<':' <<hport);
return Response.Send(kXR_redirect, hport, hname);
}
}
} else {
if (opts & kXR_stage)
{prpid = PrepID->ID(reqid, sizeof(reqid));
fsprep.reqid = reqid;
fsprep.opts = Prep_STAGE | (opts & kXR_coloc ? Prep_COLOC : 0);
} else {
reqid[0]='*'; reqid[1]='\0';
fsprep.reqid = prpid = reqid;
fsprep.opts = (isEvict ? Prep_EVICT : 0);
}
}
// Initialize the file system prepare arg list
//
fsprep.paths = 0;
fsprep.oinfo = 0;
fsprep.notify = 0;
// Cycle through all of the paths in the list
//
while((path = pathlist.GetLine()))
{if (rpCheck(path, &opaque)) return rpEmsg("Preparing", path);
if (!Squash(path)) return vpEmsg("Preparing", path);
pP = new XrdOucTList(path, pathnum);
(pLast ? (pLast->next = pP) : (pFirst = pP)); pLast = pP;
oP = new XrdOucTList(opaque, 0);
(oLast ? (oLast->next = oP) : (oFirst = oP)); oLast = oP;
pathnum++;
}
fsprep.paths = pFirst;
fsprep.oinfo = oFirst;
// We support callbacks but only for alternate prepare processing
//
if (PrepareAlt) myError.setErrCB(&prpCB, ReqID.getID());
// Process cancel requests here; they are simple at this point.
//
if (isCancel)
{if (SFS_OK != (rc = osFS->prepare(fsprep, myError, CRED)))
return fsError(rc, XROOTD_MON_PREP, myError, path, 0);
rc = Response.Send();
if (!PrepareAlt) XrdXrootdPrepare::Logdel(prpid);
return rc;
}
// Process query requests here; they are simple at this point.
//
if (isQuery)
{if (PrepareAlt)
{if (SFS_OK != (rc = osFS->prepare(fsprep, myError, CRED)))
return fsError(rc, XROOTD_MON_PREP, myError, path, 0);
rc = Response.Send();
} else {
char *mBuff = myError.getMsgBuff(rc);
pargs.reqid = prpid;
pargs.user = Link->ID;
pargs.paths = pFirst;
rc = XrdXrootdPrepare::List(pargs, mBuff, rc);
if (rc < 0) rc = Response.Send("No information found.");
else rc = Response.Send(mBuff);
}
return rc;
}
// Make sure we have at least one path
//
if (!pFirst)
return Response.Send(kXR_ArgMissing, "No prepare paths specified");
// Handle evict. We only support the evicts for alternate prepare handlers.
//
if (isEvict)
{if (PrepareAlt
&& (SFS_OK != (rc = osFS->prepare(fsprep, myError, CRED))))
return fsError(rc, XROOTD_MON_PREP, myError, path, 0);
return Response.Send();
}
// Handle notification parameter. The notification depends on whether or not
// we have a custom prepare handler.
//
if (opts & kXR_notify)
{const char *nprot = (opts & kXR_usetcp ? "tcp" : "udp");
fsprep.notify = nidbuff;
if (PrepareAlt)
{if (Request.prepare.port == 0) fsprep.notify = 0;
else snprintf(nidbuff, sizeof(nidbuff), "%s://%s:%d/",
nprot, Link->Host(), ntohs(Request.prepare.port));
} else sprintf(nidbuff, Notify, nprot, Link->FDnum(), Link->ID);
if (fsprep.notify)
fsprep.opts |= (opts & kXR_noerrs ? Prep_SENDAOK : Prep_SENDACK);
}
// Complete prepare options
//
fsprep.opts |= (opts & kXR_fresh ? Prep_FRESH : 0);
if (opts & kXR_wmode) fsprep.opts |= Prep_WMODE;
if (PrepareAlt)
{switch(Request.prepare.prty)
{case 0: fsprep.opts |= Prep_PRTY0; break;
case 1: fsprep.opts |= Prep_PRTY1; break;
case 2: fsprep.opts |= Prep_PRTY2; break;
case 3: fsprep.opts |= Prep_PRTY3; break;
default: break;
}
} else {
if (Request.prepare.prty == 0) fsprep.opts |= Prep_PRTY0;
else fsprep.opts |= Prep_PRTY1;
}
// Issue the prepare request
//
if (SFS_OK != (rc = osFS->prepare(fsprep, myError, CRED)))
return fsError(rc, XROOTD_MON_PREP, myError, pFirst->text, oFirst->text);
// Perform final processing
//
if (!(opts & kXR_stage)) rc = Response.Send();
else {rc = Response.Send(reqid, strlen(reqid));
if (!PrepareAlt)
{pargs.reqid = prpid;
pargs.user = Link->ID;
pargs.paths = pFirst;
XrdXrootdPrepare::Log(pargs);
}
}
return rc;
}
/******************************************************************************/
/* d o _ P r o t o c o l */
/******************************************************************************/
namespace XrdXrootd
{
extern char *bifResp[2];
extern int bifRLen[2];
}
int XrdXrootdProtocol::do_Protocol()
{
static kXR_int32 verNum = static_cast<kXR_int32>(htonl(kXR_PROTOCOLVERSION));
static kXR_int32 theRle = static_cast<kXR_int32>(htonl(myRole));
static kXR_int32 theRlf = static_cast<kXR_int32>(htonl(myRolf));
static kXR_int32 theRlt = static_cast<kXR_int32>(htonl(myRole|kXR_gotoTLS));
ServerResponseBody_Protocol theResp;
struct iovec ioVec[4] = {{0,0},{&theResp,kXR_ShortProtRespLen},{0,0},{0,0}};
int rc, iovN = 2, RespLen = kXR_ShortProtRespLen;
bool wantTLS = false;
// Keep Statistics
//
SI->Bump(SI->miscCnt);
// Determine which response to provide
//
if (Request.protocol.clientpv)
{int cvn = XrdOucEI::uVMask & ntohl(Request.protocol.clientpv);
if (!Status || !(clientPV & XrdOucEI::uVMask))
clientPV = (clientPV & ~XrdOucEI::uVMask) | cvn;
else cvn = (clientPV & XrdOucEI::uVMask);
if (Request.protocol.flags & ClientProtocolRequest::kXR_bifreqs
&& XrdXrootd::bifResp[0])
{int k =( Link->AddrInfo()->isPrivate() ? 1 : 0);
ioVec[iovN ].iov_base = XrdXrootd::bifResp[k];
ioVec[iovN++].iov_len = XrdXrootd::bifRLen[k];
RespLen += XrdXrootd::bifRLen[k];
}
if (DHS && cvn >= kXR_PROTSIGNVERSION
&& Request.protocol.flags & ClientProtocolRequest::kXR_secreqs)
{int n = DHS->ProtResp(theResp.secreq, *(Link->AddrInfo()), cvn);
ioVec[iovN ].iov_base = (void *)&theResp.secreq;
ioVec[iovN++].iov_len = n;
RespLen += n;
}
if ((myRole & kXR_haveTLS) != 0 && !(Link->hasTLS()))
{wantTLS = (Request.protocol.flags &
ClientProtocolRequest::kXR_wantTLS) != 0;
ableTLS = wantTLS || (Request.protocol.flags &
ClientProtocolRequest::kXR_ableTLS) != 0;
if (ableTLS) doTLS = tlsCap;
else doTLS = tlsNot;
if (ableTLS && !wantTLS)
switch(Request.protocol.expect & ClientProtocolRequest::kXR_ExpMask)
{case ClientProtocolRequest::kXR_ExpBind:
wantTLS = (doTLS & Req_TLSData) != 0;
break;
case ClientProtocolRequest::kXR_ExpLogin:
wantTLS = (doTLS & Req_TLSLogin) != 0;
break;
case ClientProtocolRequest::kXR_ExpTPC:
wantTLS = (doTLS & Req_TLSTPC) != 0 ||
(doTLS & Req_TLSLogin) != 0;
break;
default: break;
}
}
theResp.flags = (wantTLS ? theRlt : theRle);
} else {
theResp.flags = theRlf;
doTLS = tlsNot;
}
// Send the response
//
theResp.pval = verNum;
rc = Response.Send(ioVec, iovN, RespLen);
// If the client wants to start using TLS, enable it now. If we fail then we
// have no choice but to terminate the connection. Note that incapable clients
// don't want TLS but if we require TLS anyway, they will get an error either
// pre-login or post-login or on a bind later on.
//
if (rc == 0 && wantTLS)
{if (Link->setTLS(true, tlsCtx))
{Link->setProtName("xroots");
isTLS = true;
} else {
eDest.Emsg("Xeq", "Unable to enable TLS for", Link->ID);
rc = -1;
}
}
return rc;
}
/******************************************************************************/
/* d o _ Q c o n f */
/******************************************************************************/
int XrdXrootdProtocol::do_Qconf()
{
static const int fsctl_cmd = SFS_FSCTL_STATCC|SFS_O_LOCAL;
XrdOucTokenizer qcargs(argp->buff);
char *val, buff[4096], *bp=buff;
int n, bleft = sizeof(buff);
// Get the first argument
//
if (!qcargs.GetLine() || !(val = qcargs.GetToken()))
return Response.Send(kXR_ArgMissing, "query config argument not specified.");
// The first item can be xrootd or cmsd to display the config file
//
if (!strcmp(val, "cmsd") || !strcmp(val, "xrootd"))
return do_QconfCX(qcargs, val);
// Trace this query variable
//
do {TRACEP(DEBUG, "query config " <<val);
// Now determine what the user wants to query
//
if (!strcmp("bind_max", val))
{n = snprintf(bp, bleft, "%d\n", maxStreams-1);
bp += n; bleft -= n;
}
else if (!strcmp("chksum", val))
{const char *csList = getenv("XRD_CSLIST");
if (!JobCKT || !csList)
{n = snprintf(bp, bleft, "chksum\n");
bp += n; bleft -= n;
continue;
}
n = snprintf(bp, bleft, "%s\n", csList);
bp += n; bleft -= n;
}
else if (!strcmp("cid", val))
{const char *cidval = getenv("XRDCMSCLUSTERID");
if (!cidval || !(*cidval)) cidval = "cid";
n = snprintf(bp, bleft, "%s\n", cidval);
bp += n; bleft -= n;
}
else if (!strcmp("cms", val))
{XrdOucErrInfo myError(Link->ID, Monitor.Did, clientPV);
if (osFS->fsctl(fsctl_cmd, ".", myError, CRED) == SFS_DATA)
n = snprintf(bp, bleft, "%s\n", myError.getErrText());
else n = snprintf(bp, bleft, "%s\n", "cms");
bp += n; bleft -= n;
}
else if (!strcmp("pio_max", val))
{n = snprintf(bp, bleft, "%d\n", maxPio+1);
bp += n; bleft -= n;
}
else if (!strcmp("proxy", val))
{const char* pxyOrigin = "proxy";
if (myRole & kXR_attrProxy)
{pxyOrigin = getenv("XRDXROOTD_PROXY");
if (!pxyOrigin) pxyOrigin = "proxy";
}
n = snprintf(bp,bleft,"%s\n",pxyOrigin);
bp += n; bleft -= n;
}
else if (!strcmp("readv_ior_max", val))
{n = snprintf(bp,bleft,"%d\n",maxReadv_ior);
bp += n; bleft -= n;
}
else if (!strcmp("readv_iov_max", val))
{n = snprintf(bp, bleft, "%d\n", XrdProto::maxRvecsz);
bp += n; bleft -= n;
}
else if (!strcmp("role", val))
{const char *theRole = getenv("XRDROLE");
n = snprintf(bp, bleft, "%s\n", (theRole ? theRole : "none"));
bp += n; bleft -= n;
}
else if (!strcmp("sitename", val))
{const char *siteName = getenv("XRDSITE");
n = snprintf(bp, bleft, "%s\n", (siteName ? siteName : "sitename"));
bp += n; bleft -= n;
}
else if (!strcmp("start", val))
{n = snprintf(bp, bleft, "%s\n", startUP);
bp += n; bleft -= n;
}
else if (!strcmp("sysid", val))
{const char *cidval = getenv("XRDCMSCLUSTERID");
const char *nidval = getenv("XRDCMSVNID");
if (!cidval || !(*cidval) || !nidval || !(*nidval))
{cidval = "sysid"; nidval = "";}
n = snprintf(bp, bleft, "%s %s\n", nidval, cidval);
bp += n; bleft -= n;
}
else if (!strcmp("tpc", val))
{char *tpcval = getenv("XRDTPC");
n = snprintf(bp, bleft, "%s\n", (tpcval ? tpcval : "tpc"));
bp += n; bleft -= n;
}
else if (!strcmp("tpcdlg", val))
{char *tpcval = getenv("XRDTPCDLG");
n = snprintf(bp, bleft, "%s\n", (tpcval ? tpcval : "tpcdlg"));
bp += n; bleft -= n;
}
else if (!strcmp("tls_port", val) && tlsPort)
{n = snprintf(bp, bleft, "%d\n", tlsPort);
bp += n; bleft -= n;
}
else if (!strcmp("window", val) && Window)
{n = snprintf(bp, bleft, "%d\n", Window);
bp += n; bleft -= n;
}
else if (!strcmp("version", val))
{n = snprintf(bp, bleft, "%s\n", XrdVSTRING);
bp += n; bleft -= n;
}
else if (!strcmp("vnid", val))
{const char *nidval = getenv("XRDCMSVNID");
if (!nidval || !(*nidval)) nidval = "vnid";
n = snprintf(bp, bleft, "%s\n", nidval);
}
else if (!strcmp("fattr", val))
{n = snprintf(bp, bleft, "%s\n", usxParms);
bp += n; bleft -= n;
}
else {n = strlen(val);
if (bleft <= n) break;
strcpy(bp, val); bp +=n; *bp = '\n'; bp++;
bleft -= (n+1);
}
} while(bleft > 0 && (val = qcargs.GetToken()));
// Make sure all ended well
//
if (val)
return Response.Send(kXR_ArgTooLong, "too many query config arguments.");
// All done
//
return Response.Send(buff, sizeof(buff) - bleft);
}
/******************************************************************************/
/* d o _ Q c o n f C X */
/******************************************************************************/
int XrdXrootdProtocol::do_QconfCX(XrdOucTokenizer &qcargs, char *val)
{
extern XrdOucString *XrdXrootdCF;
bool isCMSD = (*val == 'c');
// Make sure there is nothing else following the token
//
if ((val = qcargs.GetToken()))
return Response.Send(kXR_ArgInvalid, "too many query config arguments.");
// If this is a cms just return a null for now
//
if (isCMSD) return Response.Send((void *)"\n", 2);
// Display the xrootd configuration
//
if (XrdXrootdCF && isTLS && getenv("XROOTD_QCFOK"))
return Response.Send((void *)XrdXrootdCF->c_str(), XrdXrootdCF->length());
// Respond with a null
//
return Response.Send((void *)"\n", 2);
}
/******************************************************************************/
/* d o _ Q f h */
/******************************************************************************/
int XrdXrootdProtocol::do_Qfh()
{
static XrdXrootdCallBack qryCB("query", XROOTD_MON_QUERY);
XrdXrootdFHandle fh(Request.query.fhandle);
XrdXrootdFile *fp;
const char *fArg = 0, *qType = "";
int rc;
short qopt = (short)ntohs(Request.query.infotype);
// Update misc stats count
//
SI->Bump(SI->miscCnt);
// Find the file object
//
if (!FTab || !(fp = FTab->Get(fh.handle)))
return Response.Send(kXR_FileNotOpen,
"query does not refer to an open file");
// The query is elegible for a deferred response, indicate we're ok with that
//
fp->XrdSfsp->error.setErrCB(&qryCB, ReqID.getID());
// Perform the appropriate query
//
switch(qopt)
{case kXR_Qopaqug: qType = "Qopaqug";
fArg = (Request.query.dlen ? argp->buff : 0);
rc = fp->XrdSfsp->fctl(SFS_FCTL_SPEC1,
Request.query.dlen, fArg,
CRED);
break;
case kXR_Qvisa: qType = "Qvisa";
rc = fp->XrdSfsp->fctl(SFS_FCTL_STATV, 0,
fp->XrdSfsp->error);
break;
default: return Response.Send(kXR_ArgMissing,
"Required query argument not present");
}
// Preform the actual function
//
TRACEP(FS, "fh=" <<fh.handle <<" query " <<qType <<" rc=" <<rc);
// Return appropriately
//
if (SFS_OK != rc)
return fsError(rc, XROOTD_MON_QUERY, fp->XrdSfsp->error, 0, 0);
return Response.Send();
}
/******************************************************************************/
/* d o _ Q o p a q u e */
/******************************************************************************/
int XrdXrootdProtocol::do_Qopaque(short qopt)
{
static XrdXrootdCallBack qpqCB("query", XROOTD_MON_QUERY);
XrdOucErrInfo myError(Link->ID, Monitor.Did, clientPV);
XrdSfsFSctl myData;
const char *Act, *AData;
char *opaque;
int fsctl_cmd, rc, dlen = Request.query.dlen;
// Process unstructured as well as structured (path/opaque) requests
//
if (qopt == kXR_Qopaque)
{myData.Arg1 = argp->buff; myData.Arg1Len = dlen;
myData.Arg2 = 0; myData.Arg2Len = 0;
fsctl_cmd = SFS_FSCTL_PLUGIO;
Act = " qopaque '"; AData = "...";
} else {
// Check for static routing (this falls under stat)
//
STATIC_REDIRECT(RD_stat);
// Prescreen the path
//
if (rpCheck(argp->buff, &opaque)) return rpEmsg("Querying", argp->buff);
if (!Squash(argp->buff)) return vpEmsg("Querying", argp->buff);
// Setup arguments
//
myData.Arg1 = argp->buff;
myData.Arg1Len = (opaque ? opaque - argp->buff - 1 : dlen);
myData.Arg2 = opaque;
myData.Arg2Len = (opaque ? argp->buff + dlen - opaque : 0);
fsctl_cmd = SFS_FSCTL_PLUGIN;
Act = " qopaquf '"; AData = argp->buff;
}
// The query is elegible for a deferred response, indicate we're ok with that
//
myError.setErrCB(&qpqCB, ReqID.getID());
// Preform the actual function using the supplied arguments
//
rc = osFS->FSctl(fsctl_cmd, myData, myError, CRED);
TRACEP(FS, "rc=" <<rc <<Act <<AData <<"'");
if (rc == SFS_OK) return Response.Send("");
return fsError(rc, 0, myError, 0, 0);
}
/******************************************************************************/
/* d o _ Q s p a c e */
/******************************************************************************/
int XrdXrootdProtocol::do_Qspace()
{
static const int fsctl_cmd = SFS_FSCTL_STATLS;
XrdOucErrInfo myError(Link->ID, Monitor.Did, clientPV);
char *opaque;
int n, rc;
// Check for static routing
//
STATIC_REDIRECT(RD_stat);
// Prescreen the path
//
if (rpCheck(argp->buff, &opaque)) return rpEmsg("Stating", argp->buff);
if (!Squash(argp->buff)) return vpEmsg("Stating", argp->buff);
// Add back the opaque info
//
if (opaque)
{n = strlen(argp->buff); argp->buff[n] = '?';
if ((argp->buff)+n != opaque-1)
memmove(&argp->buff[n+1], opaque, strlen(opaque)+1);
}
// Preform the actual function using the supplied logical FS name
//
rc = osFS->fsctl(fsctl_cmd, argp->buff, myError, CRED);
TRACEP(FS, "rc=" <<rc <<" qspace '" <<argp->buff <<"'");
if (rc == SFS_OK) return Response.Send("");
return fsError(rc, XROOTD_MON_QUERY, myError, argp->buff, opaque);
}
/******************************************************************************/
/* d o _ Q u e r y */
/******************************************************************************/
int XrdXrootdProtocol::do_Query()
{
short qopt = (short)ntohs(Request.query.infotype);
// Perform the appropriate query
//
switch(qopt)
{case kXR_QStats: return SI->Stats(Response,
(Request.header.dlen ? argp->buff : "a"));
case kXR_Qcksum: return do_CKsum(0);
case kXR_Qckscan: return do_CKsum(1);
case kXR_Qconfig: return do_Qconf();
case kXR_Qspace: return do_Qspace();
case kXR_Qxattr: return do_Qxattr();
case kXR_Qopaque:
case kXR_Qopaquf: return do_Qopaque(qopt);
case kXR_Qopaqug: return do_Qfh();
case kXR_QPrep: return do_Prepare(true);
default: break;
}
// Whatever we have, it's not valid
//
return Response.Send(kXR_ArgInvalid,
"Invalid information query type code");
}
/******************************************************************************/
/* d o _ Q x a t t r */
/******************************************************************************/
int XrdXrootdProtocol::do_Qxattr()
{
static XrdXrootdCallBack statCB("stat", XROOTD_MON_QUERY);
static const int fsctl_cmd = SFS_FSCTL_STATXA;
int rc;
char *opaque;
XrdOucErrInfo myError(Link->ID,&statCB,ReqID.getID(),Monitor.Did,clientPV);
// Check for static routing
//
STATIC_REDIRECT(RD_stat);
// Prescreen the path
//
if (rpCheck(argp->buff, &opaque)) return rpEmsg("Stating", argp->buff);
if (!Squash(argp->buff)) return vpEmsg("Stating", argp->buff);
// Add back opaque information is present
//
if (opaque)
{int n = strlen(argp->buff); argp->buff[n] = '?';
if ((argp->buff)+n != opaque-1)
memmove(&argp->buff[n+1], opaque, strlen(opaque)+1);
}
// Preform the actual function
//
rc = osFS->fsctl(fsctl_cmd, argp->buff, myError, CRED);
TRACEP(FS, "rc=" <<rc <<" qxattr " <<argp->buff);
return fsError(rc, XROOTD_MON_QUERY, myError, argp->buff, opaque);
}
/******************************************************************************/
/* d o _ R e a d */
/******************************************************************************/
int XrdXrootdProtocol::do_Read()
{
int pathID, retc;
XrdXrootdFHandle fh(Request.read.fhandle);
numReads++;
// We first handle the pre-read list, if any. We do it this way because of
// a historical glitch in the protocol. One should really not piggy back a
// pre-read on top of a read, though it is allowed.
//
if (!Request.header.dlen) pathID = 0;
else if (do_ReadNone(retc, pathID)) return retc;
// Unmarshall the data
//
IO.IOLen = ntohl(Request.read.rlen);
n2hll(Request.read.offset, IO.Offset);
// Find the file object
//
if (!FTab || !(IO.File = FTab->Get(fh.handle)))
return Response.Send(kXR_FileNotOpen,
"read does not refer to an open file");
// Trace and verify read length is not negative
//
TRACEP(FSIO, pathID <<" fh=" <<fh.handle <<" read " <<IO.IOLen
<<'@' <<IO.Offset);
if ( IO.IOLen < 0) return Response.Send(kXR_ArgInvalid,
"Read length is negative");
// If we are monitoring, insert a read entry
//
if (Monitor.InOut())
Monitor.Agent->Add_rd(IO.File->Stats.FileID, Request.read.rlen,
Request.read.offset);
// Short circuit processing if read length is zero
//
if (!IO.IOLen) return Response.Send();
// There are many competing ways to accomplish a read. Pick the one we
// will use and if possible, do a fast dispatch.
//
if (IO.File->isMMapped) IO.Mode = XrdXrootd::IOParms::useMMap;
else if (IO.File->sfEnabled && !isTLS && IO.IOLen >= as_minsfsz
&& IO.Offset+IO.IOLen <= IO.File->Stats.fSize)
IO.Mode = XrdXrootd::IOParms::useSF;
else if (IO.File->AsyncMode && IO.IOLen >= as_miniosz
&& IO.Offset+IO.IOLen <= IO.File->Stats.fSize+as_seghalf
&& linkAioReq < as_maxperlnk && srvrAioOps < as_maxpersrv)
{XrdXrootdProtocol *pP;
XrdXrootdNormAio *aioP;
if (!pathID) pP = this;
else {if (!(pP = VerifyStream(retc, pathID, false))) return retc;
if (pP->linkAioReq >= as_maxperlnk) pP = 0;
}
if (pP && (aioP = XrdXrootdNormAio::Alloc(pP,Response,IO.File)))
{if (!IO.File->aioFob) IO.File->aioFob = new XrdXrootdAioFob;
aioP->Read(IO.Offset, IO.IOLen);
return 0;
}
SI->AsyncRej++;
IO.Mode = XrdXrootd::IOParms::useBasic;
}
else IO.Mode = XrdXrootd::IOParms::useBasic;
// See if an alternate path is required, offload the read
//
if (pathID) return do_Offload(&XrdXrootdProtocol::do_ReadAll, pathID);
// Now read all of the data (do pre-reads first)
//
return do_ReadAll();
}
/******************************************************************************/
/* d o _ R e a d A l l */
/******************************************************************************/
// IO.File = file to be read
// IO.Offset = Offset at which to read
// IO.IOLen = Number of bytes to read from file and write to socket
int XrdXrootdProtocol::do_ReadAll()
{
int rc, xframt, Quantum = (IO.IOLen > maxBuffsz ? maxBuffsz : IO.IOLen);
char *buff;
// If this file is memory mapped, short ciruit all the logic and immediately
// transfer the requested data to minimize latency.
//
if (IO.Mode == XrdXrootd::IOParms::useMMap)
{if (IO.Offset >= IO.File->Stats.fSize) return Response.Send();
if (IO.Offset+IO.IOLen <= IO.File->Stats.fSize)
{IO.File->Stats.rdOps(IO.IOLen);
return Response.Send(IO.File->mmAddr+IO.Offset, IO.IOLen);
}
xframt = IO.File->Stats.fSize -IO.Offset;
IO.File->Stats.rdOps(xframt);
return Response.Send(IO.File->mmAddr+IO.Offset, xframt);
}
// If we are sendfile enabled, then just send the file if possible
//
if (IO.Mode == XrdXrootd::IOParms::useSF)
{IO.File->Stats.rdOps(IO.IOLen);
if (IO.File->fdNum >= 0)
return Response.Send(IO.File->fdNum, IO.Offset, IO.IOLen);
rc = IO.File->XrdSfsp->SendData((XrdSfsDio *)this, IO.Offset, IO.IOLen);
if (rc == SFS_OK)
{if (!IO.IOLen) return 0;
if (IO.IOLen < 0) return -1; // Otherwise retry using read()
} else return fsError(rc, 0, IO.File->XrdSfsp->error, 0, 0);
}
// Make sure we have a large enough buffer
//
if (!argp || Quantum < halfBSize || Quantum > argp->bsize)
{if ((rc = getBuff(1, Quantum)) <= 0) return rc;}
else if (hcNow < hcNext) hcNow++;
buff = argp->buff;
// Now read all of the data. For statistics, we need to record the orignal
// amount of the request even if we really do not get to read that much!
//
IO.File->Stats.rdOps(IO.IOLen);
do {if ((xframt = IO.File->XrdSfsp->read(IO.Offset, buff, Quantum)) <= 0) break;
if (xframt >= IO.IOLen) return Response.Send(buff, xframt);
if (Response.Send(kXR_oksofar, buff, xframt) < 0) return -1;
IO.Offset += xframt; IO.IOLen -= xframt;
if (IO.IOLen < Quantum) Quantum = IO.IOLen;
} while(IO.IOLen);
// Determine why we ended here
//
if (xframt == 0) return Response.Send();
return fsError(xframt, 0, IO.File->XrdSfsp->error, 0, 0);
}
/******************************************************************************/
/* d o _ R e a d N o n e */
/******************************************************************************/
int XrdXrootdProtocol::do_ReadNone(int &retc, int &pathID)
{
XrdXrootdFHandle fh;
int ralsz = Request.header.dlen;
struct read_args *rargs=(struct read_args *)(argp->buff);
struct readahead_list *ralsp = (readahead_list *)(rargs+1);
// Return the pathid
//
pathID = static_cast<int>(rargs->pathid);
if ((ralsz -= sizeof(read_args)) <= 0) return 0;
// Make sure that we have a proper pre-read list
//
if (ralsz%sizeof(readahead_list))
{Response.Send(kXR_ArgInvalid, "Invalid length for read ahead list");
return 1;
}
// Run down the pre-read list
//
while(ralsz > 0)
{IO.IOLen = ntohl(ralsp->rlen);
n2hll(ralsp->offset, IO.Offset);
memcpy((void *)&fh.handle, (const void *)ralsp->fhandle,
sizeof(fh.handle));
TRACEP(FSIO, "fh="<<fh.handle<<" read "<<IO.IOLen<<'@'<<IO.Offset);
if (!FTab || !(IO.File = FTab->Get(fh.handle)))
{retc = Response.Send(kXR_FileNotOpen,
"preread does not refer to an open file");
return 1;
}
IO.File->XrdSfsp->read(IO.Offset, IO.IOLen);
ralsz -= sizeof(struct readahead_list);
ralsp++;
numReads++;
};
// All done
//
return 0;
}
/******************************************************************************/
/* d o _ R e a d V */
/******************************************************************************/
int XrdXrootdProtocol::do_ReadV()
{
// This will read multiple buffers at the same time in an attempt to avoid
// the latency in a network. The information with the offsets and lengths
// of the information to read is passed as a data buffer... then we decode
// it and put all the individual buffers in a single one it's up to the
// client to interpret it. Code originally developed by Leandro Franco, CERN.
// The readv file system code originally added by Brian Bockelman, UNL.
//
const int hdrSZ = sizeof(readahead_list);
struct XrdOucIOVec rdVec[XrdProto::maxRvecsz+1];
struct readahead_list *raVec, respHdr;
long long totSZ;
XrdSfsXferSize rdVAmt, rdVXfr, xfrSZ = 0;
int rdVBeg, rdVBreak, rdVNow, rdVNum, rdVecNum;
int currFH, i, k, Quantum, Qleft, rdVecLen = Request.header.dlen;
int rvMon = Monitor.InOut();
int ioMon = (rvMon > 1);
char *buffp, vType = (ioMon ? XROOTD_MON_READU : XROOTD_MON_READV);
// Compute number of elements in the read vector and make sure we have no
// partial elements.
//
rdVecNum = rdVecLen / sizeof(readahead_list);
if ( (rdVecNum <= 0) || (rdVecNum*hdrSZ != rdVecLen) )
return Response.Send(kXR_ArgInvalid, "Read vector is invalid");
// Make sure that we can copy the read vector to our local stack. We must impose
// a limit on it's size. We do this to be able to reuse the data buffer to
// prevent cross-cpu memory cache synchronization.
//
if (rdVecNum > XrdProto::maxRvecsz)
return Response.Send(kXR_ArgTooLong, "Read vector is too long");
// So, now we account for the number of readv requests and total segments
//
numReadV++; numSegsV += rdVecNum;
// Run down the list and compute the total size of the read. No individual
// read may be greater than the maximum transfer size. We also use this loop
// to copy the read ahead list to our readv vector for later processing.
//
raVec = (readahead_list *)argp->buff;
totSZ = rdVecLen; Quantum = maxReadv_ior;
for (i = 0; i < rdVecNum; i++)
{totSZ += (rdVec[i].size = ntohl(raVec[i].rlen));
if (rdVec[i].size < 0) return Response.Send(kXR_ArgInvalid,
"Readv length is negative");
if (rdVec[i].size > Quantum) return Response.Send(kXR_NoMemory,
"Single readv transfer is too large");
rdVec[i].offset = ntohll(raVec[i].offset);
memcpy(&rdVec[i].info, raVec[i].fhandle, sizeof(int));
}
// Now add an extra dummy element to force flushing of the read vector.
//
rdVec[i].offset = -1;
rdVec[i].size = 0;
rdVec[i].info = -1;
rdVBreak = rdVecNum;
rdVecNum++;
// We limit the total size of the read to be 2GB for convenience
//
if (totSZ > 0x80000000LL)
return Response.Send(kXR_NoMemory, "Total readv transfer is too large");
// Calculate the transfer unit which will be the smaller of the maximum
// transfer unit and the actual amount we need to transfer.
//
Quantum = totSZ < maxTransz ? totSZ : maxTransz;
// Now obtain the right size buffer
//
if ((Quantum < halfBSize && Quantum > 1024) || Quantum > argp->bsize)
{if ((k = getBuff(1, Quantum)) <= 0) return k;}
else if (hcNow < hcNext) hcNow++;
// Check that we really have at least one file open. This needs to be done
// only once as this code runs in the control thread.
//
if (!FTab) return Response.Send(kXR_FileNotOpen,
"readv does not refer to an open file");
// Preset the previous and current file handle to be the handle of the first
// element and make sure the file is actually open.
//
currFH = rdVec[0].info;
memcpy(respHdr.fhandle, &currFH, sizeof(respHdr.fhandle));
if (!(IO.File = FTab->Get(currFH))) return Response.Send(kXR_FileNotOpen,
"readv does not refer to an open file");
// Setup variables for running through the list.
//
Qleft = Quantum; buffp = argp->buff; rvSeq++;
rdVBeg = rdVNow = 0; rdVXfr = rdVAmt = 0;
// Now run through the elements
//
for (i = 0; i < rdVecNum; i++)
{if (rdVec[i].info != currFH)
{xfrSZ = IO.File->XrdSfsp->readv(&rdVec[rdVNow], i-rdVNow);
if (xfrSZ != rdVAmt) break;
rdVNum = i - rdVBeg; rdVXfr += rdVAmt;
IO.File->Stats.rvOps(rdVXfr, rdVNum);
if (rvMon)
{Monitor.Agent->Add_rv(IO.File->Stats.FileID, htonl(rdVXfr),
htons(rdVNum), rvSeq, vType);
if (ioMon) for (k = rdVBeg; k < i; k++)
Monitor.Agent->Add_rd(IO.File->Stats.FileID,
htonl(rdVec[k].size), htonll(rdVec[k].offset));
}
rdVXfr = rdVAmt = 0;
if (i == rdVBreak) break;
rdVBeg = rdVNow = i; currFH = rdVec[i].info;
memcpy(respHdr.fhandle, &currFH, sizeof(respHdr.fhandle));
if (!(IO.File = FTab->Get(currFH)))
return Response.Send(kXR_FileNotOpen,
"readv does not refer to an open file");
}
if (Qleft < (rdVec[i].size + hdrSZ))
{if (rdVAmt)
{xfrSZ = IO.File->XrdSfsp->readv(&rdVec[rdVNow], i-rdVNow);
if (xfrSZ != rdVAmt) break;
}
if (Response.Send(kXR_oksofar,argp->buff,Quantum-Qleft) < 0)
return -1;
Qleft = Quantum;
buffp = argp->buff;
rdVNow = i; rdVXfr += rdVAmt; rdVAmt = 0;
}
xfrSZ = rdVec[i].size; rdVAmt += xfrSZ;
respHdr.rlen = htonl(xfrSZ);
respHdr.offset = htonll(rdVec[i].offset);
memcpy(buffp, &respHdr, hdrSZ);
rdVec[i].data = buffp + hdrSZ;
buffp += (xfrSZ+hdrSZ); Qleft -= (xfrSZ+hdrSZ);
TRACEP(FSIO,"fh=" <<currFH<<" readV "<< xfrSZ <<'@'<<rdVec[i].offset);
}
// Check if we have an error here. This is indicated when rdVAmt is not zero.
//
if (rdVAmt)
{if (xfrSZ >= 0)
{xfrSZ = SFS_ERROR;
IO.File->XrdSfsp->error.setErrInfo(-ENODATA,"readv past EOF");
}
return fsError(xfrSZ, 0, IO.File->XrdSfsp->error, 0, 0);
}
// All done, return result of the last segment or just zero
//
return (Quantum != Qleft ? Response.Send(argp->buff, Quantum-Qleft) : 0);
}
/******************************************************************************/
/* d o _ R m */
/******************************************************************************/
int XrdXrootdProtocol::do_Rm()
{
int rc;
char *opaque;
XrdOucErrInfo myError(Link->ID, Monitor.Did, clientPV);
// Check for static routing
//
STATIC_REDIRECT(RD_rm);
// Prescreen the path
//
if (rpCheck(argp->buff, &opaque)) return rpEmsg("Removing", argp->buff);
if (!Squash(argp->buff)) return vpEmsg("Removing", argp->buff);
// Preform the actual function
//
rc = osFS->rem(argp->buff, myError, CRED, opaque);
TRACEP(FS, "rc=" <<rc <<" rm " <<argp->buff);
if (SFS_OK == rc) return Response.Send();
// An error occurred
//
return fsError(rc, XROOTD_MON_RM, myError, argp->buff, opaque);
}
/******************************************************************************/
/* d o _ R m d i r */
/******************************************************************************/
int XrdXrootdProtocol::do_Rmdir()
{
int rc;
char *opaque;
XrdOucErrInfo myError(Link->ID, Monitor.Did, clientPV);
// Check for static routing
//
STATIC_REDIRECT(RD_rmdir);
// Prescreen the path
//
if (rpCheck(argp->buff, &opaque)) return rpEmsg("Removing", argp->buff);
if (!Squash(argp->buff)) return vpEmsg("Removing", argp->buff);
// Preform the actual function
//
rc = osFS->remdir(argp->buff, myError, CRED, opaque);
TRACEP(FS, "rc=" <<rc <<" rmdir " <<argp->buff);
if (SFS_OK == rc) return Response.Send();
// An error occurred
//
return fsError(rc, XROOTD_MON_RMDIR, myError, argp->buff, opaque);
}
/******************************************************************************/
/* d o _ S e t */
/******************************************************************************/
int XrdXrootdProtocol::do_Set()
{
XrdOucTokenizer setargs(argp->buff);
char *val, *rest;
// Get the first argument
//
if (!setargs.GetLine() || !(val = setargs.GetToken(&rest)))
return Response.Send(kXR_ArgMissing, "set argument not specified.");
// Trace this set
//
TRACEP(DEBUG, "set " <<val <<' ' <<rest);
// Now determine what the user wants to set
//
if (!strcmp("appid", val))
{while(*rest && *rest == ' ') rest++;
eDest.Emsg("Xeq", Link->ID, "appid", rest);
return Response.Send();
}
else if (!strcmp("monitor", val)) return do_Set_Mon(setargs);
else if (!strcmp("cache", val)) return do_Set_Cache(setargs);
// All done
//
return Response.Send(kXR_ArgInvalid, "invalid set parameter");
}
/******************************************************************************/
/* d o _ S e t _ C a c h e */
/******************************************************************************/
// Process: set cache <cmd> <args>
int XrdXrootdProtocol::do_Set_Cache(XrdOucTokenizer &setargs)
{
XrdOucErrInfo myError(Link->ID, Monitor.Did, clientPV);
XrdSfsFSctl myData;
char *cmd, *cargs, *opaque = nullptr;
const char *myArgs[2];
// This set is valid only if we implement a cache
//
if ((fsFeatures & XrdSfs::hasCACH) == 0)
return Response.Send(kXR_ArgInvalid, "invalid set parameter");
// Get the command and argument
//
if (!(cmd = setargs.GetToken(&cargs)))
return Response.Send(kXR_ArgMissing,"set cache argument not specified.");
// Prescreen the path if the next token starts with a slash
//
if (cargs && *cargs == '/')
{if (rpCheck(cargs, &opaque)) return rpEmsg("Setting", cargs);
if (!Squash(cargs)) return vpEmsg("Setting", cargs);
myData.ArgP = myArgs; myData.Arg2Len = -2;
myArgs[0] = cargs;
myArgs[1] = opaque;
} else {
myData.Arg2 = opaque; myData.Arg2Len = (opaque ? strlen(opaque) : 0);
}
myData.Arg1 = cmd; myData.Arg1Len = strlen(cmd);
// Preform the actual function using the supplied arguments
//
int rc = osFS->FSctl(SFS_FSCTL_PLUGXC, myData, myError, CRED);
TRACEP(FS, "rc=" <<rc <<"set cache " <<myData.Arg1 <<' ' <<cargs);
if (rc == SFS_OK) return Response.Send("");
return fsError(rc, 0, myError, 0, 0);
}
/******************************************************************************/
/* d o _ S e t _ M o n */
/******************************************************************************/
// Process: set monitor {off | on} {[appid] | info [info]}
int XrdXrootdProtocol::do_Set_Mon(XrdOucTokenizer &setargs)
{
char *val, *appid;
kXR_unt32 myseq = 0;
// Get the first argument
//
if (!(val = setargs.GetToken(&appid)))
return Response.Send(kXR_ArgMissing,"set monitor argument not specified.");
// For info requests, nothing changes. However, info events must have been
// enabled for us to record them. Route the information via the static
// monitor entry, since it knows how to forward the information.
//
if (!strcmp(val, "info"))
{if (appid && Monitor.Info())
{while(*appid && *appid == ' ') appid++;
if (strlen(appid) > 1024) appid[1024] = '\0';
if (*appid) myseq = Monitor.MapInfo(appid);
}
return Response.Send((void *)&myseq, sizeof(myseq));
}
// Determine if on do appropriate processing
//
if (!strcmp(val, "on"))
{Monitor.Enable();
if (appid && Monitor.InOut())
{while(*appid && *appid == ' ') appid++;
if (*appid) Monitor.Agent->appID(appid);
}
if (!Monitor.Did && Monitor.Logins()) MonAuth();
return Response.Send();
}
// Determine if off and do appropriate processing
//
if (!strcmp(val, "off"))
{if (appid && Monitor.InOut())
{while(*appid && *appid == ' ') appid++;
if (*appid) Monitor.Agent->appID(appid);
}
Monitor.Disable();
return Response.Send();
}
// Improper request
//
return Response.Send(kXR_ArgInvalid, "invalid set monitor argument");
}
/******************************************************************************/
/* d o _ S t a t */
/******************************************************************************/
int XrdXrootdProtocol::do_Stat()
{
static XrdXrootdCallBack statCB("stat", XROOTD_MON_STAT);
static const int fsctl_cmd = SFS_FSCTL_STATFS;
bool doDig;
int rc;
char *opaque, xxBuff[1024];
struct stat buf;
XrdOucErrInfo myError(Link->ID,&statCB,ReqID.getID(),Monitor.Did,clientPV);
// Update misc stats count
//
SI->Bump(SI->miscCnt);
// The stat request may refer to an open file handle. So, screen this out.
//
if (!argp || !Request.header.dlen)
{XrdXrootdFile *fp;
XrdXrootdFHandle fh(Request.stat.fhandle);
if (Request.stat.options & kXR_vfs)
{Response.Send(kXR_ArgMissing, "Required argument not present");
return 0;
}
if (!FTab || !(fp = FTab->Get(fh.handle)))
return Response.Send(kXR_FileNotOpen,
"stat does not refer to an open file");
rc = fp->XrdSfsp->stat(&buf);
TRACEP(FS, "fh=" <<fh.handle <<" stat rc=" <<rc);
if (SFS_OK == rc) return Response.Send(xxBuff,
StatGen(buf,xxBuff,sizeof(xxBuff)));
return fsError(rc, 0, fp->XrdSfsp->error, 0, 0);
}
// Check if we are handling a dig type path
//
doDig = (digFS && SFS_LCLROOT(argp->buff));
// Check for static routing
//
if (!doDig) {STATIC_REDIRECT(RD_stat);}
// Prescreen the path
//
if (rpCheck(argp->buff, &opaque)) return rpEmsg("Stating", argp->buff);
if (!doDig && !Squash(argp->buff))return vpEmsg("Stating", argp->buff);
// Preform the actual function, we may been to add back the opaque info
//
if (Request.stat.options & kXR_vfs)
{if (opaque)
{int n = strlen(argp->buff); argp->buff[n] = '?';
if ((argp->buff)+n != opaque-1)
memmove(&argp->buff[n+1], opaque, strlen(opaque)+1);
}
rc = osFS->fsctl(fsctl_cmd, argp->buff, myError, CRED);
TRACEP(FS, "rc=" <<rc <<" statfs " <<argp->buff);
if (rc == SFS_OK) Response.Send("");
} else {
if (doDig) rc = digFS->stat(argp->buff, &buf, myError, CRED, opaque);
else rc = osFS->stat(argp->buff, &buf, myError, CRED, opaque);
TRACEP(FS, "rc=" <<rc <<" stat " <<argp->buff);
if (rc == SFS_OK) return Response.Send(xxBuff,
StatGen(buf,xxBuff,sizeof(xxBuff)));
}
return fsError(rc, (doDig ? 0 : XROOTD_MON_STAT),myError,argp->buff,opaque);
}
/******************************************************************************/
/* d o _ S t a t x */
/******************************************************************************/
int XrdXrootdProtocol::do_Statx()
{
static XrdXrootdCallBack statxCB("xstat", XROOTD_MON_STAT);
int rc;
char *path, *opaque, *respinfo = argp->buff;
mode_t mode;
XrdOucErrInfo myError(Link->ID,&statxCB,ReqID.getID(),Monitor.Did,clientPV);
XrdOucTokenizer pathlist(argp->buff);
// Check for static routing
//
STATIC_REDIRECT(RD_stat);
// Cycle through all of the paths in the list
//
while((path = pathlist.GetLine()))
{if (rpCheck(path, &opaque)) return rpEmsg("Stating", path);
if (!Squash(path)) return vpEmsg("Stating", path);
rc = osFS->stat(path, mode, myError, CRED, opaque);
TRACEP(FS, "rc=" <<rc <<" stat " <<path);
if (rc != SFS_OK)
return fsError(rc, XROOTD_MON_STAT, myError, path, opaque);
else {if (mode == (mode_t)-1) *respinfo = (char)kXR_offline;
else if (S_ISDIR(mode)) *respinfo = (char)kXR_isDir;
else *respinfo = (char)kXR_file;
}
respinfo++;
}
// Return result
//
return Response.Send(argp->buff, respinfo-argp->buff);
}
/******************************************************************************/
/* d o _ S y n c */
/******************************************************************************/
int XrdXrootdProtocol::do_Sync()
{
static XrdXrootdCallBack syncCB("sync", 0);
int rc;
XrdXrootdFile *fp;
XrdXrootdFHandle fh(Request.sync.fhandle);
// Keep Statistics
//
SI->Bump(SI->syncCnt);
// Find the file object
//
if (!FTab || !(fp = FTab->Get(fh.handle)))
return Response.Send(kXR_FileNotOpen,"sync does not refer to an open file");
// The sync is elegible for a deferred response, indicate we're ok with that
//
fp->XrdSfsp->error.setErrCB(&syncCB, ReqID.getID());
// Sync the file
//
rc = fp->XrdSfsp->sync();
TRACEP(FS, "fh=" <<fh.handle <<" sync rc=" <<rc);
if (SFS_OK != rc) return fsError(rc, 0, fp->XrdSfsp->error, 0, 0);
// Respond that all went well
//
return Response.Send();
}
/******************************************************************************/
/* d o _ T r u n c a t e */
/******************************************************************************/
int XrdXrootdProtocol::do_Truncate()
{
static XrdXrootdCallBack truncCB("trunc", 0);
XrdXrootdFile *fp;
XrdXrootdFHandle fh(Request.truncate.fhandle);
long long theOffset;
int rc;
// Unmarshall the data
//
n2hll(Request.truncate.offset, theOffset);
// Check if this is a truncate for an open file (no path given)
//
if (!Request.header.dlen)
{
// Update misc stats count
//
SI->Bump(SI->miscCnt);
// Find the file object
//
if (!FTab || !(fp = FTab->Get(fh.handle)))
return Response.Send(kXR_FileNotOpen,
"trunc does not refer to an open file");
// Truncate the file (it is eligible for async callbacks)
//
fp->XrdSfsp->error.setErrCB(&truncCB, ReqID.getID());
rc = fp->XrdSfsp->truncate(theOffset);
TRACEP(FS, "fh=" <<fh.handle <<" trunc rc=" <<rc <<" sz=" <<theOffset);
if (SFS_OK != rc) return fsError(rc, 0, fp->XrdSfsp->error, 0, 0);
} else {
XrdOucErrInfo myError(Link->ID, Monitor.Did, clientPV);
char *opaque;
// Check for static routing
//
STATIC_REDIRECT(RD_trunc);
// Verify the path and extract out the opaque information
//
if (rpCheck(argp->buff,&opaque)) return rpEmsg("Truncating",argp->buff);
if (!Squash(argp->buff)) return vpEmsg("Truncating",argp->buff);
// Preform the actual function
//
rc = osFS->truncate(argp->buff, (XrdSfsFileOffset)theOffset, myError,
CRED, opaque);
TRACEP(FS, "rc=" <<rc <<" trunc " <<theOffset <<' ' <<argp->buff);
if (SFS_OK != rc)
return fsError(rc, XROOTD_MON_TRUNC, myError, argp->buff, opaque);
}
// Respond that all went well
//
return Response.Send();
}
/******************************************************************************/
/* d o _ W r i t e */
/******************************************************************************/
int XrdXrootdProtocol::do_Write()
{
int pathID;
XrdXrootdFHandle fh(Request.write.fhandle);
numWrites++;
// Unmarshall the data
//
IO.IOLen = Request.header.dlen;
n2hll(Request.write.offset, IO.Offset);
pathID = static_cast<int>(Request.write.pathid);
// Find the file object. We will drain socket data on the control path only!
// .
if (!FTab || !(IO.File = FTab->Get(fh.handle)))
{IO.File = 0;
return do_WriteNone(pathID);
}
// Trace and verify that length is not negative
//
TRACEP(FSIO, pathID<<" fh="<<fh.handle<<" write "<<IO.IOLen<<'@'<<IO.Offset);
if ( IO.IOLen < 0) return Response.Send(kXR_ArgInvalid,
"Write length is negative");
// If we are monitoring, insert a write entry
//
if (Monitor.InOut())
Monitor.Agent->Add_wr(IO.File->Stats.FileID, Request.write.dlen,
Request.write.offset);
// If zero length write, simply return
//
if (!IO.IOLen) return Response.Send();
IO.File->Stats.wrOps(IO.IOLen); // Optimistically correct
// If async write allowed and it is a true write request (e.g. not chkpoint) and
// current conditions permit async; schedule the write to occur asynchronously
//
if (IO.File->AsyncMode && Request.header.requestid == kXR_write
&& !as_syncw && IO.IOLen >= as_miniosz && srvrAioOps < as_maxpersrv)
{if (myStalls < as_maxstalls)
{if (pathID) return do_Offload(&XrdXrootdProtocol::do_WriteAio,pathID);
return do_WriteAio();
}
SI->AsyncRej++;
myStalls--;
}
// See if an alternate path is required
//
if (pathID) return do_Offload(&XrdXrootdProtocol::do_WriteAll, pathID);
// Just to the i/o now
//
return do_WriteAll();
}
/******************************************************************************/
/* d o _ W r i t e A i o */
/******************************************************************************/
// IO.File = file to be written
// IO.Offset = Offset at which to write
// IO.IOLen = Number of bytes to read from socket and write to file
int XrdXrootdProtocol::do_WriteAio()
{
XrdXrootdNormAio *aioP;
// Allocate an aio request object if client hasn't exceeded the link limit
//
if (linkAioReq >= as_maxperlnk
|| !(aioP = XrdXrootdNormAio::Alloc(this, Response, IO.File)))
{SI->AsyncRej++;
if (myStalls > 0) myStalls--;
return do_WriteAll();
}
// Issue the write request
//
return aioP->Write(IO.Offset, IO.IOLen);
}
/******************************************************************************/
/* d o _ W r i t e A l l */
/******************************************************************************/
// IO.File = file to be written
// IO.Offset = Offset at which to write
// IO.IOLen = Number of bytes to read from socket and write to file
int XrdXrootdProtocol::do_WriteAll()
{
int rc, Quantum = (IO.IOLen > maxBuffsz ? maxBuffsz : IO.IOLen);
// Make sure we have a large enough buffer
//
if (!argp || Quantum < halfBSize || Quantum > argp->bsize)
{if ((rc = getBuff(0, Quantum)) <= 0) return rc;}
else if (hcNow < hcNext) hcNow++;
// Now write all of the data (XrdXrootdProtocol.C defines getData())
//
while(IO.IOLen > 0)
{if ((rc = getData("data", argp->buff, Quantum)))
{if (rc > 0)
{Resume = &XrdXrootdProtocol::do_WriteCont;
myBlast = Quantum;
}
return rc;
}
if ((rc = IO.File->XrdSfsp->write(IO.Offset, argp->buff, Quantum)) < 0)
{IO.IOLen = IO.IOLen-Quantum; IO.EInfo[0] = rc; IO.EInfo[1] = 0;
return do_WriteNone();
}
IO.Offset += Quantum; IO.IOLen -= Quantum;
if (IO.IOLen < Quantum) Quantum = IO.IOLen;
}
// All done
//
return Response.Send();
}
/******************************************************************************/
/* d o _ W r i t e C o n t */
/******************************************************************************/
// IO.File = file to be written
// IO.Offset = Offset at which to write
// IO.IOLen = Number of bytes to read from socket and write to file
// myBlast = Number of bytes already read from the socket
int XrdXrootdProtocol::do_WriteCont()
{
int rc;
// Write data that was finaly finished comming in
//
if ((rc = IO.File->XrdSfsp->write(IO.Offset, argp->buff, myBlast)) < 0)
{IO.IOLen = IO.IOLen-myBlast; IO.EInfo[0] = rc; IO.EInfo[1] = 0;
return do_WriteNone();
}
IO.Offset += myBlast; IO.IOLen -= myBlast;
// See if we need to finish this request in the normal way
//
if (IO.IOLen > 0) return do_WriteAll();
return Response.Send();
}
/******************************************************************************/
/* d o _ W r i t e N o n e */
/******************************************************************************/
int XrdXrootdProtocol::do_WriteNone()
{
char *buff, dbuff[4096];
int rlen, blen;
// Determine which buffer we will use
//
if (argp && argp->bsize > (int)sizeof(dbuff))
{buff = argp->buff;
blen = argp->bsize;
} else {
buff = dbuff;
blen = sizeof(dbuff);
}
if (IO.IOLen < blen) blen = IO.IOLen;
// Discard any data being transmitted
//
TRACEP(REQ, "discarding " <<IO.IOLen <<" bytes");
while(IO.IOLen > 0)
{rlen = Link->Recv(buff, blen, readWait);
if (rlen < 0) return Link->setEtext("link read error");
IO.IOLen -= rlen;
if (rlen < blen)
{myBlen = 0;
Resume = &XrdXrootdProtocol::do_WriteNone;
return 1;
}
if (IO.IOLen < blen) blen = IO.IOLen;
}
// Send final message
//
return do_WriteNoneMsg();
}
/******************************************************************************/
int XrdXrootdProtocol::do_WriteNone(int pathID, XErrorCode ec,
const char *emsg)
{
// We can't recover when the data is arriving on a foriegn bound path as there
// no way to properly drain the socket. So, we terminate the connection.
//
if (pathID != PathID)
{if (ec && emsg) Response.Send(ec, emsg);
else do_WriteNoneMsg();
return Link->setEtext("write protocol violation");
}
// Set error code if present
//
if (ec != kXR_noErrorYet)
{IO.EInfo[1] = ec;
if (IO.File)
{if (!emsg) emsg = XProtocol::errName(ec);
IO.File->XrdSfsp->error.setErrInfo(0, emsg);
}
}
// Otherwise, continue to darin the socket
//
return do_WriteNone();
}
/******************************************************************************/
/* d o _ W r i t e N o n e M s g */
/******************************************************************************/
int XrdXrootdProtocol::do_WriteNoneMsg()
{
// Send our the error message and return
//
if (!IO.File) return
Response.Send(kXR_FileNotOpen,"write does not refer to an open file");
if (IO.EInfo[1])
return Response.Send((XErrorCode)IO.EInfo[1],
IO.File->XrdSfsp->error.getErrText());
if (IO.EInfo[0]) return fsError(IO.EInfo[0], 0, IO.File->XrdSfsp->error, 0, 0);
return Response.Send(kXR_FSError, IO.File->XrdSfsp->error.getErrText());
}
/******************************************************************************/
/* d o _ W r i t e S p a n */
/******************************************************************************/
int XrdXrootdProtocol::do_WriteSpan()
{
int rc;
XrdXrootdFHandle fh(Request.write.fhandle);
numWrites++;
// Unmarshall the data
//
IO.IOLen = Request.header.dlen;
n2hll(Request.write.offset, IO.Offset);
// Find the file object. We will only drain socket data on the control path.
// .
if (!FTab || !(IO.File = FTab->Get(fh.handle)))
{IO.IOLen -= myBlast;
IO.File = 0;
return do_WriteNone(Request.write.pathid);
}
// If we are monitoring, insert a write entry
//
if (Monitor.InOut())
Monitor.Agent->Add_wr(IO.File->Stats.FileID, Request.write.dlen,
Request.write.offset);
IO.File->Stats.wrOps(IO.IOLen); // Optimistically correct
// Trace this entry
//
TRACEP(FSIO, "fh=" <<fh.handle <<" write " <<IO.IOLen <<'@' <<IO.Offset);
// Write data that was already read
//
if ((rc = IO.File->XrdSfsp->write(IO.Offset, myBuff, myBlast)) < 0)
{IO.IOLen = IO.IOLen-myBlast; IO.EInfo[0] = rc; IO.EInfo[1] = 0;
return do_WriteNone();
}
IO.Offset += myBlast; IO.IOLen -= myBlast;
// See if we need to finish this request in the normal way
//
if (IO.IOLen > 0) return do_WriteAll();
return Response.Send();
}
/******************************************************************************/
/* d o _ W r i t e V */
/******************************************************************************/
int XrdXrootdProtocol::do_WriteV()
{
// This will write multiple buffers at the same time in an attempt to avoid
// the disk latency. The information with the offsets and lengths of the data
// to write is passed as a data buffer. We attempt to optimize as best as
// possible, though certain combinations may result in multiple writes. Since
// socket flushing is nearly impossible when an error occurs, most errors
// simply terminate the connection.
//
const int wveSZ = sizeof(XrdProto::write_list);
struct trackInfo
{XrdXrootdWVInfo **wvInfo; bool doit;
trackInfo(XrdXrootdWVInfo **wvP) : wvInfo(wvP), doit(true) {}
~trackInfo() {if (doit && *wvInfo) {free(*wvInfo); *wvInfo = 0;}}
} freeInfo(&wvInfo);
struct XrdProto::write_list *wrLst;
XrdOucIOVec *wrVec;
long long totSZ, maxSZ;
int curFH, k, Quantum, wrVecNum, wrVecLen = Request.header.dlen;
// Compute number of elements in the write vector and make sure we have no
// partial elements.
//
wrVecNum = wrVecLen / wveSZ;
if ( (wrVecLen <= 0) || (wrVecNum*wveSZ != wrVecLen) )
{Response.Send(kXR_ArgInvalid, "Write vector is invalid");
return -1;
}
// Make sure that we can make a copy of the read vector. So, we impose a limit
// on it's size.
//
if (wrVecNum > XrdProto::maxWvecsz)
{Response.Send(kXR_ArgTooLong, "Write vector is too long");
return -1;
}
// Create the verctor write information structure sized as needed.
//
if (wvInfo) free(wvInfo);
wvInfo = (XrdXrootdWVInfo *)malloc(sizeof(XrdXrootdWVInfo) +
sizeof(XrdOucIOVec)*(wrVecNum-1));
memset(wvInfo, 0, sizeof(XrdXrootdWVInfo) - sizeof(XrdOucIOVec));
wvInfo->wrVec = wrVec = wvInfo->ioVec;
// Run down the list and compute the total size of the write. No individual
// write may be greater than the maximum transfer size. We also use this loop
// to copy the write list to our writev vector for later processing.
//
wrLst = (XrdProto::write_list *)argp->buff;
totSZ = 0; maxSZ = 0; k = 0; Quantum = maxTransz; curFH = 0;
for (int i = 0; i < wrVecNum; i++)
{if (wrLst[i].wlen == 0) continue;
memcpy(&wrVec[k].info, wrLst[i].fhandle, sizeof(int));
wrVec[k].size = ntohl(wrLst[i].wlen);
if (wrVec[k].size < 0)
{Response.Send(kXR_ArgInvalid, "Writev length is negtive");
return -1;
}
if (wrVec[k].size > Quantum)
{Response.Send(kXR_NoMemory,"Single writev transfer is too large");
return -1;
}
wrVec[k].offset = ntohll(wrLst[i].offset);
if (wrVec[k].info == curFH) totSZ += wrVec[k].size;
else {if (maxSZ < totSZ) maxSZ = totSZ;
totSZ = wrVec[k].size;
}
k++;
}
// Check if we are not actually writing anything, simply return success
//
if (maxSZ < totSZ) maxSZ = totSZ;
if (maxSZ == 0) return Response.Send();
// So, now we account for the number of writev requests and total segments
//
numWritV++; numSegsW += k; wrVecNum = k;
// Calculate the transfer unit which will be the smaller of the maximum
// transfer unit and the actual amount we need to transfer.
//
if (maxSZ > maxTransz) Quantum = maxTransz;
else Quantum = static_cast<int>(maxSZ);
// Now obtain the right size buffer
//
if ((Quantum < halfBSize && Quantum > 1024) || Quantum > argp->bsize)
{if (getBuff(0, Quantum) <= 0) return -1;}
else if (hcNow < hcNext) hcNow++;
// Check that we really have at least the first file open (part of setup)
//
if (!FTab || !(IO.File = FTab->Get(wrVec[0].info)))
{Response.Send(kXR_FileNotOpen, "writev does not refer to an open file");
return -1;
}
// Setup to do the complete transfer
//
wvInfo->curFH = wrVec[0].info;
wvInfo->vBeg = 0;
wvInfo->vPos = 0;
wvInfo->vEnd = wrVecNum;
wvInfo->vMon = 0;
wvInfo->doSync= (Request.writev.options & ClientWriteVRequest::doSync) != 0;
wvInfo->wvMon = Monitor.InOut();
wvInfo->ioMon = (wvInfo->vMon > 1);
// wvInfo->vType = (wvInfo->ioMon ? XROOTD_MON_WRITEU : XROOTD_MON_WRITEV);
IO.WVBytes = 0;
IO.IOLen = wrVec[0].size;
myBuff = argp->buff;
myBlast = 0;
// Now we simply start the write operations if this is a true writev request.
// Otherwise return to the caller for additional processing.
//
freeInfo.doit = false;
if (Request.header.requestid == kXR_writev) return do_WriteVec();
return 0;
}
/******************************************************************************/
/* d o _ W r i t e V e c */
/******************************************************************************/
int XrdXrootdProtocol::do_WriteVec()
{
XrdSfsXferSize xfrSZ;
int rc, wrVNum, vNow = wvInfo->vPos;
bool done, newfile;
// Read the complete data from the socket for the current element. Note that
// should we enter a resume state; upon re-entry all of the data will be read.
//
do{if (IO.IOLen > 0)
{wvInfo->wrVec[vNow].data = argp->buff + myBlast;
myBlast += IO.IOLen;
if ((rc = getData("data", myBuff, IO.IOLen)))
{if (rc < 0) return rc;
IO.IOLen = 0;
Resume = &XrdXrootdProtocol::do_WriteVec;
return rc;
}
}
// Establish the state at this point as this will tell us what to do next.
//
vNow++;
done = newfile = false;
if (vNow >= wvInfo->vEnd) done = true;
else if (wvInfo->wrVec[vNow].info != wvInfo->curFH) newfile = true;
else if (myBlast + wvInfo->wrVec[vNow].size <= argp->bsize)
{IO.IOLen = wvInfo->wrVec[vNow].size;
myBuff = argp->buff + myBlast;
wvInfo->vPos = vNow;
continue;
}
// We need to write out what we have.
//
wrVNum = vNow - wvInfo->vBeg;
xfrSZ = IO.File->XrdSfsp->writev(&(wvInfo->wrVec[wvInfo->vBeg]), wrVNum);
TRACEP(FSIO,"fh=" <<wvInfo->curFH <<" writeV " << xfrSZ <<':' <<wrVNum);
if (xfrSZ != myBlast) break;
// Check if we need to do monitoring or a sync with no deferal. Note that
// we currently do not support detailed monitoring for vector writes!
//
if (done || newfile)
{int monVnum = vNow - wvInfo->vMon;
IO.File->Stats.wvOps(IO.WVBytes, monVnum);
wvInfo->vMon = vNow;
IO.WVBytes = 0;
if (wvInfo->doSync)
{IO.File->XrdSfsp->error.setErrCB(0,0);
xfrSZ = IO.File->XrdSfsp->sync();
if (xfrSZ< 0) break;
}
}
// If we are done, the finish up
//
if (done)
{if (wvInfo) {free(wvInfo); wvInfo = 0;}
return Response.Send();
}
// Sequence to a new file if we need to do so
//
if (newfile)
{if (!FTab || !(IO.File = FTab->Get(wvInfo->wrVec[vNow].info)))
{Response.Send(kXR_FileNotOpen,"writev does not refer to an open file");
return -1;
}
wvInfo->curFH = wvInfo->wrVec[vNow].info;
}
// Setup to resume transfer
//
myBlast = 0;
myBuff = argp->buff;
IO.IOLen = wvInfo->wrVec[vNow].size;
wvInfo->vBeg = vNow;
wvInfo->vPos = vNow;
} while(true);
// If we got here then there was a write error (file pointer is valid).
//
if (wvInfo) {free(wvInfo); wvInfo = 0;}
return fsError((int)xfrSZ, 0, IO.File->XrdSfsp->error, 0, 0);
}
/******************************************************************************/
/* S e n d F i l e */
/******************************************************************************/
int XrdXrootdProtocol::SendFile(int fildes)
{
// Make sure we have some data to send
//
if (!IO.IOLen) return 1;
// Send off the data
//
IO.IOLen = Response.Send(fildes, IO.Offset, IO.IOLen);
return IO.IOLen;
}
/******************************************************************************/
int XrdXrootdProtocol::SendFile(XrdOucSFVec *sfvec, int sfvnum)
{
int i, xframt = 0;
// Make sure we have some data to send
//
if (!IO.IOLen) return 1;
// Verify the length, it can't be greater than what the client wants
//
for (i = 1; i < sfvnum; i++) xframt += sfvec[i].sendsz;
if (xframt > IO.IOLen) return 1;
// Send off the data
//
if (xframt) IO.IOLen = Response.Send(sfvec, sfvnum, xframt);
else {IO.IOLen = 0; Response.Send();}
return IO.IOLen;
}
/******************************************************************************/
/* S e t F D */
/******************************************************************************/
void XrdXrootdProtocol::SetFD(int fildes)
{
if (fildes < 0) IO.File->sfEnabled = 0;
else IO.File->fdNum = fildes;
}
/******************************************************************************/
/* U t i l i t y M e t h o d s */
/******************************************************************************/
/******************************************************************************/
/* f s E r r o r */
/******************************************************************************/
int XrdXrootdProtocol::fsError(int rc, char opC, XrdOucErrInfo &myError,
const char *Path, char *Cgi)
{
int ecode, popt, rs;
const char *eMsg = myError.getErrText(ecode);
// Process standard errors
//
if (rc == SFS_ERROR)
{SI->errorCnt++;
rc = XProtocol::mapError(ecode);
if (Path && (rc == kXR_Overloaded) && (opC == XROOTD_MON_OPENR
|| opC == XROOTD_MON_OPENW || opC == XROOTD_MON_OPENC))
{if (myError.extData()) myError.Reset();
return fsOvrld(opC, Path, Cgi);
}
if (Path && (rc == kXR_NotFound) && RQLxist && opC
&& (popt = RQList.Validate(Path)))
{if (XrdXrootdMonitor::Redirect())
XrdXrootdMonitor::Redirect(Monitor.Did,
Route[popt].Host[rdType],
Route[popt].Port[rdType],
opC|XROOTD_MON_REDLOCAL, Path);
if (Cgi) rs = fsRedirNoEnt(eMsg, Cgi, popt);
else rs = Response.Send(kXR_redirect,
Route[popt].Port[rdType],
Route[popt].Host[rdType]);
} else rs = Response.Send((XErrorCode)rc, eMsg);
if (myError.extData()) myError.Reset();
return rs;
}
// Process the redirection (error msg is host:port)
//
if (rc == SFS_REDIRECT)
{SI->redirCnt++;
// if the plugin set some redirect flags but the client does not
// support them, clear the flags (set -1)
if( ecode < -1 && !( clientPV & XrdOucEI::uRedirFlgs ) )
ecode = -1;
if (XrdXrootdMonitor::Redirect() && Path && opC)
XrdXrootdMonitor::Redirect(Monitor.Did, eMsg, Port, opC, Path);
if (TRACING(TRACE_REDIR))
{if (ecode < 0)
{TRACEI(REDIR, Response.ID() <<"redirecting to " << eMsg);}
else {TRACEI(REDIR, Response.ID() <<"redirecting to "
<< eMsg <<':' <<ecode);
}
}
if (RedirPI) rs = fsRedirPI(eMsg, ecode, myError.getErrTextLen());
else rs = Response.Send(kXR_redirect, ecode, eMsg,
myError.getErrTextLen());
if (myError.extData()) myError.Reset();
return rs;
}
// Process the deferal. We also synchronize sending the deferal response with
// sending the actual deferred response by calling Done() in the callback object.
// This allows the requestor of he callback know that we actually send the
// kXR_waitresp to the end client and avoid violating time causality.
//
if (rc == SFS_STARTED)
{SI->stallCnt++;
if (ecode <= 0) ecode = 1800;
TRACEI(STALL, Response.ID() <<"delaying client up to " <<ecode <<" sec");
rc = Response.Send(kXR_waitresp, ecode, eMsg);
if (myError.getErrCB()) myError.getErrCB()->Done(ecode, &myError);
if (myError.extData()) myError.Reset();
return (rc ? rc : 1);
}
// Process the data response
//
if (rc == SFS_DATA)
{if (ecode) rs = Response.Send((void *)eMsg, ecode);
else rs = Response.Send();
if (myError.extData()) myError.Reset();
return rs;
}
// Process the data response via an iovec
//
if (rc == SFS_DATAVEC)
{if (ecode < 2) rs = Response.Send();
else rs = Response.Send((struct iovec *)eMsg, ecode);
if (myError.getErrCB()) myError.getErrCB()->Done(ecode, &myError);
if (myError.extData()) myError.Reset();
return rs;
}
// Process the deferal
//
if (rc >= SFS_STALL)
{SI->stallCnt++;
TRACEI(STALL, Response.ID() <<"stalling client for " <<rc <<" sec");
rs = Response.Send(kXR_wait, rc, eMsg);
if (myError.extData()) myError.Reset();
return rs;
}
// Unknown conditions, report it
//
{char buff[32];
SI->errorCnt++;
sprintf(buff, "%d", rc);
eDest.Emsg("Xeq", "Unknown error code", buff, eMsg);
rs = Response.Send(kXR_ServerError, eMsg);
if (myError.extData()) myError.Reset();
return rs;
}
}
/******************************************************************************/
/* f s O v r l d */
/******************************************************************************/
int XrdXrootdProtocol::fsOvrld(char opC, const char *Path, char *Cgi)
{
static const char *prot = "root://";
static int negOne = -1;
static char quest = '?', slash = '/';
struct iovec rdrResp[8];
char *destP=0, dest[512];
int iovNum=0, pOff, port;
// If this is a forwarded path and the client can handle full url's then
// redirect the client to the destination in the path. Otherwise, if there is
// an alternate destination, send client there. Otherwise, stall the client.
//
if (OD_Bypass && clientPV & XrdOucEI::uUrlOK
&& (pOff = XrdOucUtils::isFWD(Path, &port, dest, sizeof(dest))))
{ rdrResp[1].iov_base = (char *)&negOne;
rdrResp[1].iov_len = sizeof(negOne);
rdrResp[2].iov_base = (char *)prot;
rdrResp[2].iov_len = 7; // root://
rdrResp[3].iov_base = (char *)dest;
rdrResp[3].iov_len = strlen(dest); // host:port
rdrResp[4].iov_base = (char *)&slash;
rdrResp[4].iov_len = (*Path == '/' ? 1 : 0); // / or nil for objid
rdrResp[5].iov_base = (char *)(Path+pOff);
rdrResp[5].iov_len = strlen(Path+pOff); // path
if (Cgi && *Cgi)
{rdrResp[6].iov_base = (char *)&quest;
rdrResp[6].iov_len = sizeof(quest); // ?
rdrResp[7].iov_base = (char *)Cgi;
rdrResp[7].iov_len = strlen(Cgi); // cgi
iovNum = 8;
} else iovNum = 6;
destP = dest;
} else if ((destP = Route[RD_ovld].Host[rdType]))
port = Route[RD_ovld].Port[rdType];
// If a redirect happened, then trace it.
//
if (destP)
{SI->redirCnt++;
if (XrdXrootdMonitor::Redirect())
XrdXrootdMonitor::Redirect(Monitor.Did, destP, port,
opC|XROOTD_MON_REDLOCAL, Path);
if (iovNum)
{TRACEI(REDIR, Response.ID() <<"redirecting to "<<dest);
return Response.Send(kXR_redirect, rdrResp, iovNum);
} else {
TRACEI(REDIR, Response.ID() <<"redirecting to "<<destP<<':'<<port);
return Response.Send(kXR_redirect, port, destP);
}
}
// If there is a stall value, then delay the client
//
if (OD_Stall)
{TRACEI(STALL, Response.ID()<<"stalling client for "<<OD_Stall<<" sec");
SI->stallCnt++;
return Response.Send(kXR_wait, OD_Stall, "server is overloaded");
}
// We were unsuccessful, return overload as an error
//
return Response.Send(kXR_Overloaded, "server is overloaded");
}
/******************************************************************************/
/* f s R e d i r N o E n t */
/******************************************************************************/
int XrdXrootdProtocol::fsRedirNoEnt(const char *eMsg, char *Cgi, int popt)
{
struct iovec ioV[4];
char *tried, *trend, *ptried = 0;
kXR_int32 pnum = htonl(static_cast<kXR_int32>(Route[popt].Port[rdType]));
int tlen;
// Try to find the last tried token in the cgi
//
if ((trend = Cgi))
{do {if (!(tried = strstr(Cgi, "tried="))) break;
if (tried == trend || *(tried-1) == '&')
{if (!ptried || (*(tried+6) && *(tried+6) != '&')) ptried=tried;}
Cgi = index(tried+6, '&');
} while(Cgi);
}
// If we did find a tried, bracket it out with a leading comma (we can modify
// the passed cgi string here because this is the last time it will be used.
//
if ((tried = ptried))
{tried += 5;
while(*(tried+1) && *(tried+1) == ',') tried++;
trend = index(tried, '&');
if (trend) {tlen = trend - tried; *trend = 0;}
else tlen = strlen(tried);
*tried = ',';
} else tlen = 0;
// Check if we are in a redirect loop (i.e. we are listed in the client's cgi).
// If so, then treat this and file not found as we've been here before.
//
if ((trend = tried) && eMsg)
do {if ((trend = strstr(trend, myCName)))
{if (*(trend+myCNlen) == '\0' || *(trend+myCNlen) == ',')
return Response.Send(kXR_NotFound, eMsg);
trend = index(trend+myCNlen, ',');
}
} while(trend);
// If we have not found a tried token or that token far too large to propogate
// (i.e. it's likely we have an undetected loop), then do a simple redirect.
//
if (!tried || !tlen || tlen > 16384)
return Response.Send(kXR_redirect,
Route[popt].Port[rdType],
Route[popt].Host[rdType]);
// We need to append the client's tried list to the one we have to avoid loops
//
ioV[1].iov_base = (char *)&pnum;
ioV[1].iov_len = sizeof(pnum);
ioV[2].iov_base = Route[popt].Host[rdType];
ioV[2].iov_len = Route[popt].RDSz[rdType];
ioV[3].iov_base = tried;
ioV[3].iov_len = tlen;
// Compute total length
//
tlen += sizeof(pnum) + Route[popt].RDSz[rdType];
// Send off the redirect
//
return Response.Send(kXR_redirect, ioV, 4, tlen);
}
/******************************************************************************/
/* f s R e d i r I P */
/******************************************************************************/
namespace XrdXrootd
{
struct netInfo
{XrdNetAddr netAddr;
XrdSysMutex niMutex;
char* netID;
time_t expTime = 0;
RAtomic_uint refs = {0};
netInfo(const char*id) : netID(strdup(id)) {}
~netInfo() {if (netID) free(netID);}
};
}
XrdXrootd::netInfo* XrdXrootdProtocol::fsRedirIP(const char *netID, int port)
{
auto cmpchr = [](const char* a, const char* b) {return strcmp(a,b)<0;};
static std::map<const char*,XrdXrootd::netInfo*,decltype(cmpchr)> niMap(cmpchr);
static XrdSysMutex niMapMtx;
XrdXrootd::netInfo* niP;
// First, chek if we have an entry for this item. We need a lock because
// some oher thread may be adding a node to the map. Nodes are never deleted.
//
niMapMtx.Lock();
auto it = niMap.find(netID);
if (it == niMap.end())
{niP = new XrdXrootd::netInfo(netID);
niMap[niP->netID] = niP;
} else niP = it->second;
niMapMtx.UnLock();
niP->niMutex.Lock();
// Validate/initialize the corresponding netaddr object. For newly allocated
// objects it is always done. For pre-exiting objects only when they expire.
// Note: when expTime is zero then refs must be 1 and this is a 1st time init,
//
time_t nowT = time(0);
niP->refs++;
if (niP->expTime <= nowT && niP->refs == 1)
{const char* eTxt = niP->netAddr.Set(netID, port);
if (eTxt)
{if (niP->expTime == 0)
{eDest.Emsg("RedirIP", "Unable to init NetInfo for", netID, eTxt);
niP->refs--;
niP->niMutex.UnLock();
return 0;
}
eDest.Emsg("RedirIP", "Unable to refresh NetInfo for", netID, eTxt);
niP->expTime += 60;
} else niP->expTime = nowT + redirIPHold;
}
// We have valid network info on the target
//
niP->niMutex.UnLock();
return niP;
}
/******************************************************************************/
/* f s R e d i r P I */
/******************************************************************************/
int XrdXrootdProtocol::fsRedirPI(const char *trg, int port, int trglen)
{
struct THandle
{XrdXrootd::netInfo* Info;
THandle() : Info(0) {}
~THandle() {if (Info) Info->refs--;}
} T;
std::string Target;
int newPort = port;
// Handle the most comman case first - a simple host and port.
//
if (port >= 0)
{std::string TDst;
const char* TCgi = index(trg, '?');
if (!TCgi) {TCgi = ""; TDst = trg;}
else TDst.assign(trg, TCgi-trg);
T.Info = fsRedirIP(TDst.c_str(), port);
if (!T.Info) return Response.Send(kXR_redirect, port, trg, trglen);
uint16_t TPort = static_cast<uint16_t>(newPort);
Target = RedirPI->Redirect(TDst.c_str(), TPort, TCgi, T.Info->netAddr,
*(Link->AddrInfo()));
newPort = static_cast<int>(TPort);
} else {
// This is a url which requires additional handling. If the url is not
// valid we skip calling the plugin as the situation is not salvageable
// and the client will complain. We also require that the host and optional
// port be atleast two characters long.
//
std::string urlHead, TDst, urlPort;
const char* urlTail;
const char* hBeg = strstr(trg, "://");
if (!hBeg)
{eDest.Emsg("RedirPI", "Invalid redirect URL -", trg);
return Response.Send(kXR_redirect, port, trg, trglen);
}
hBeg += 3;
urlHead.assign(trg, hBeg-trg);
urlTail = strstr(hBeg, "/");
if (!urlTail) {urlTail = ""; TDst = hBeg;}
else {if (urlTail-hBeg < 3)
{eDest.Emsg("RedirPI", "Mlalformed URL -", trg);
return Response.Send(kXR_redirect, port, trg, trglen);
}
TDst.assign(hBeg, urlTail-hBeg);
}
T.Info = fsRedirIP(TDst.c_str(), port);
if (!T.Info) return Response.Send(kXR_redirect, port, trg, trglen);
size_t colon = TDst.find(":");
if (colon != std::string::npos)
{urlPort.assign(TDst, colon+1, std::string::npos);
TDst.erase(colon);
}
Target = RedirPI->RedirectURL(urlHead.c_str(), Target.c_str(),
urlPort.c_str(), urlTail, newPort,
T.Info->netAddr, *(Link->AddrInfo()));
if (port == -1 || newPort >= 0) newPort = port;
}
// Handle the result of calling the plugin
//
if (!Target.size()) return Response.Send(kXR_redirect, port, trg, trglen);
if (Target.front() != '!')
{TRACEI(REDIR, Response.ID() <<"plugin redirects to "
<<Target.c_str() <<" portarg="<<newPort);
return Response.Send(kXR_redirect,port,Target.c_str(),Target.size());
}
// The redirect plgin enountered an error, so we bail.
//
char mbuff[1024];
snprintf(mbuff,sizeof(mbuff),"Redirect failed; %s",Target.c_str());
eDest.Emsg("Xeq_RedirPI", mbuff);
return Response.Send(kXR_ServerError, mbuff);
}
/******************************************************************************/
/* g e t B u f f */
/******************************************************************************/
int XrdXrootdProtocol::getBuff(const int isRead, int Quantum)
{
// Check if we need to really get a new buffer
//
if (!argp || Quantum > argp->bsize) hcNow = hcPrev;
else if (Quantum >= halfBSize || hcNow-- > 0) return 1;
else if (hcNext >= hcMax) hcNow = hcMax;
else {int tmp = hcPrev;
hcNow = hcNext;
hcPrev = hcNext;
hcNext = tmp+hcNext;
}
// Get a new buffer
//
if (argp) BPool->Release(argp);
if ((argp = BPool->Obtain(Quantum))) halfBSize = argp->bsize >> 1;
else return Response.Send(kXR_NoMemory, (isRead ?
"insufficient memory to read file" :
"insufficient memory to write file"));
// Success
//
return 1;
}
/******************************************************************************/
/* Private: g e t C k s T y p e */
/******************************************************************************/
char *XrdXrootdProtocol::getCksType(char *opaque, char *cspec, int cslen)
{
char *cksT;
// Get match for user specified checksum type, if any. Otherwise return default.
//
if (opaque && *opaque)
{XrdOucEnv jobEnv(opaque);
if ((cksT = jobEnv.Get("cks.type")))
{XrdOucTList *tP = JobCKTLST;
while(tP && strcasecmp(tP->text, cksT)) tP = tP->next;
if (!tP && cspec) snprintf(cspec, cslen, "%s", cksT);
return (tP ? tP->text : 0);
}
}
// Return default
//
return JobCKT;
}
/******************************************************************************/
/* Private: l o g L o g i n */
/******************************************************************************/
bool XrdXrootdProtocol::logLogin(bool xauth)
{
const char *uName, *ipName, *tMsg, *zMsg = "";
char lBuff[512], pBuff[512];
// Determine ip type
//
if (clientPV & XrdOucEI::uIPv4)
ipName = (clientPV & XrdOucEI::uIPv64 ? "IP46" : "IPv4");
else ipName = (clientPV & XrdOucEI::uIPv64 ? "IP64" : "IPv6");
// Determine client name
//
if (xauth) uName = (Client->name ? Client->name : "nobody");
else uName = 0;
// Check if TLS was or will be used
//
tMsg = Link->verTLS();
if (*tMsg) zMsg = " ";
// Format the line
//
snprintf(lBuff, sizeof(lBuff), "%s %s %s%slogin%s%s",
(clientPV & XrdOucEI::uPrip ? "pvt" : "pub"), ipName,
tMsg, zMsg,
(xauth ? " as " : ""),
(uName ? uName : ""));
// Document the login
//
if (Client->tident != Client->pident)
{snprintf(pBuff, sizeof(pBuff), "via %s auth for %s",
Client->prot, Client->pident);
} else *pBuff = 0;
eDest.Log(SYS_LOG_01, "Xeq", Link->ID, lBuff, (*pBuff ? pBuff : 0));
// Enable TLS if we need to (note sess setting is off if login setting is on).
// If we need to but the client is not TLS capable, send an error and terminate.
//
if ((doTLS & Req_TLSSess) && !Link->hasBridge())
{if (ableTLS)
{if (Link->setTLS(true, tlsCtx))
{Link->setProtName("xroots");
isTLS = true;
} else {
eDest.Emsg("Xeq", "Unable to require TLS for", Link->ID);
return false;
}
} else {
eDest.Emsg("Xeq","session requires TLS but",Link->ID,"is incapable.");
Response.Send(kXR_TLSRequired, "session requires TLS support");
return false;
}
}
// Record the appname in the final SecEntity object
//
if (AppName) Client->eaAPI->Add("xrd.appname", (std::string)AppName);
// Assign unique identifier to the final SecEntity object
//
Client->ueid = mySID;
// Propogate a connect through the whole system
//
osFS->Connect(Client);
return true;
}
/******************************************************************************/
/* m a p M o d e */
/******************************************************************************/
#define Map_Mode(x,y) if (Mode & kXR_ ## x) newmode |= S_I ## y
int XrdXrootdProtocol::mapMode(int Mode)
{
int newmode = 0;
// Map the mode in the obvious way
//
Map_Mode(ur, RUSR); Map_Mode(uw, WUSR); Map_Mode(ux, XUSR);
Map_Mode(gr, RGRP); Map_Mode(gw, WGRP); Map_Mode(gx, XGRP);
Map_Mode(or, ROTH); Map_Mode(ox, XOTH);
// All done
//
return newmode;
}
/******************************************************************************/
/* M o n A u t h */
/******************************************************************************/
void XrdXrootdProtocol::MonAuth()
{
char Buff[4096];
const char *bP = Buff;
if (Client == &Entity) bP = Entity.moninfo;
else {snprintf(Buff,sizeof(Buff),
"&p=%s&n=%s&h=%s&o=%s&r=%s&g=%s&m=%s%s&I=%c",
Client->prot,
(Client->name ? Client->name : ""),
(Client->host ? Client->host : ""),
(Client->vorg ? Client->vorg : ""),
(Client->role ? Client->role : ""),
(Client->grps ? Client->grps : ""),
(Client->moninfo ? Client->moninfo : ""),
(Entity.moninfo ? Entity.moninfo : ""),
(clientPV & XrdOucEI::uIPv4 ? '4' : '6')
);
Client->secMon = &Monitor;
}
Monitor.Report(bP);
if (Entity.moninfo) {free(Entity.moninfo); Entity.moninfo = 0;}
}
/******************************************************************************/
/* r p C h e c k */
/******************************************************************************/
int XrdXrootdProtocol::rpCheck(char *fn, char **opaque)
{
char *cp;
if (*fn != '/')
{if (!(XPList.Opts() & XROOTDXP_NOSLASH)) return 1;
if ( XPList.Opts() & XROOTDXP_NOCGI) {*opaque = 0; return 0;}
}
if (!(cp = index(fn, '?'))) *opaque = 0;
else {*cp = '\0'; *opaque = cp+1;
if (!**opaque) *opaque = 0;
}
if (*fn != '/') return 0;
while ((cp = index(fn, '/')))
{fn = cp+1;
if (fn[0] == '.' && fn[1] == '.' && fn[2] == '/') return 1;
}
return 0;
}
/******************************************************************************/
/* r p E m s g */
/******************************************************************************/
int XrdXrootdProtocol::rpEmsg(const char *op, char *fn)
{
char buff[2048];
snprintf(buff,sizeof(buff)-1,"%s relative path '%s' is disallowed.",op,fn);
buff[sizeof(buff)-1] = '\0';
return Response.Send(kXR_NotAuthorized, buff);
}
/******************************************************************************/
/* S e t S F */
/******************************************************************************/
int XrdXrootdProtocol::SetSF(kXR_char *fhandle, bool seton)
{
XrdXrootdFHandle fh(fhandle);
XrdXrootdFile *theFile;
if (!FTab || !(theFile = FTab->Get(fh.handle))) return -EBADF;
// Turn it off or on if so wanted
//
if (!seton) theFile->sfEnabled = 0;
else if (theFile->fdNum >= 0) theFile->sfEnabled = 1;
// All done
//
return 0;
}
/******************************************************************************/
/* S q u a s h */
/******************************************************************************/
int XrdXrootdProtocol::Squash(char *fn)
{
char *ofn, *ifn = fn;
if (*fn != '/') return XPList.Opts();
while(*ifn)
{if (*ifn == '/')
if (*(ifn+1) == '/'
|| (*(ifn+1) == '.' && *(ifn+1) && *(ifn+2) == '/')) break;
ifn++;
}
if (!*ifn) return XPList.Validate(fn, ifn-fn);
ofn = ifn;
while(*ifn) {*ofn = *ifn++;
while(*ofn == '/')
{while(*ifn == '/') ifn++;
if (ifn[0] == '.' && ifn[1] == '/') ifn += 2;
else break;
}
ofn++;
}
*ofn = '\0';
return XPList.Validate(fn, ofn-fn);
}
/******************************************************************************/
/* v p E m s g */
/******************************************************************************/
int XrdXrootdProtocol::vpEmsg(const char *op, char *fn)
{
char buff[2048];
snprintf(buff,sizeof(buff)-1,"%s path '%s' is disallowed.",op,fn);
buff[sizeof(buff)-1] = '\0';
return Response.Send(kXR_NotAuthorized, buff);
}
XErrorCode
XErrorCode
Definition XProtocol.hh:989
kXR_ArgInvalid
@ kXR_ArgInvalid
Definition XProtocol.hh:990
kXR_InvalidRequest
@ kXR_InvalidRequest
Definition XProtocol.hh:996
kXR_ArgMissing
@ kXR_ArgMissing
Definition XProtocol.hh:991
kXR_TLSRequired
@ kXR_TLSRequired
Definition XProtocol.hh:1018
kXR_AuthFailed
@ kXR_AuthFailed
Definition XProtocol.hh:1020
kXR_NotAuthorized
@ kXR_NotAuthorized
Definition XProtocol.hh:1000
kXR_NotFound
@ kXR_NotFound
Definition XProtocol.hh:1001
kXR_FileLocked
@ kXR_FileLocked
Definition XProtocol.hh:993
kXR_noErrorYet
@ kXR_noErrorYet
Definition XProtocol.hh:1027
kXR_ChkSumErr
@ kXR_ChkSumErr
Definition XProtocol.hh:1009
kXR_overQuota
@ kXR_overQuota
Definition XProtocol.hh:1011
kXR_FileNotOpen
@ kXR_FileNotOpen
Definition XProtocol.hh:994
kXR_Unsupported
@ kXR_Unsupported
Definition XProtocol.hh:1003
kXR_Cancelled
@ kXR_Cancelled
Definition XProtocol.hh:1007
kXR_ServerError
@ kXR_ServerError
Definition XProtocol.hh:1002
kXR_Overloaded
@ kXR_Overloaded
Definition XProtocol.hh:1014
kXR_ArgTooLong
@ kXR_ArgTooLong
Definition XProtocol.hh:992
kXR_FSError
@ kXR_FSError
Definition XProtocol.hh:995
kXR_NoMemory
@ kXR_NoMemory
Definition XProtocol.hh:998
kXR_ecredir
@ kXR_ecredir
Definition XProtocol.hh:371
kXR_ShortProtRespLen
#define kXR_ShortProtRespLen
Definition XProtocol.hh:1200
kXR_gotoTLS
#define kXR_gotoTLS
Definition XProtocol.hh:1180
kXR_haveTLS
#define kXR_haveTLS
Definition XProtocol.hh:1179
kXR_PROTSIGNVERSION
#define kXR_PROTSIGNVERSION
Definition XProtocol.hh:74
read_args::pathid
kXR_char pathid
Definition XProtocol.hh:653
kXR_open_wrto
@ kXR_open_wrto
Definition XProtocol.hh:469
kXR_compress
@ kXR_compress
Definition XProtocol.hh:452
kXR_async
@ kXR_async
Definition XProtocol.hh:458
kXR_delete
@ kXR_delete
Definition XProtocol.hh:453
kXR_prefname
@ kXR_prefname
Definition XProtocol.hh:461
kXR_nowait
@ kXR_nowait
Definition XProtocol.hh:467
kXR_open_read
@ kXR_open_read
Definition XProtocol.hh:456
kXR_open_updt
@ kXR_open_updt
Definition XProtocol.hh:457
kXR_mkpath
@ kXR_mkpath
Definition XProtocol.hh:460
kXR_seqio
@ kXR_seqio
Definition XProtocol.hh:468
kXR_replica
@ kXR_replica
Definition XProtocol.hh:465
kXR_posc
@ kXR_posc
Definition XProtocol.hh:466
kXR_refresh
@ kXR_refresh
Definition XProtocol.hh:459
kXR_new
@ kXR_new
Definition XProtocol.hh:455
kXR_force
@ kXR_force
Definition XProtocol.hh:454
kXR_4dirlist
@ kXR_4dirlist
Definition XProtocol.hh:464
kXR_retstat
@ kXR_retstat
Definition XProtocol.hh:463
ServerResponseBody_Protocol::pval
kXR_int32 pval
Definition XProtocol.hh:1192
kXR_waitresp
@ kXR_waitresp
Definition XProtocol.hh:906
kXR_redirect
@ kXR_redirect
Definition XProtocol.hh:904
kXR_oksofar
@ kXR_oksofar
Definition XProtocol.hh:900
kXR_ok
@ kXR_ok
Definition XProtocol.hh:899
kXR_authmore
@ kXR_authmore
Definition XProtocol.hh:902
kXR_wait
@ kXR_wait
Definition XProtocol.hh:905
kXR_dstat
@ kXR_dstat
Definition XProtocol.hh:240
kXR_dcksm
@ kXR_dcksm
Definition XProtocol.hh:241
readahead_list::fhandle
kXR_char fhandle[4]
Definition XProtocol.hh:659
kXR_writev
@ kXR_writev
Definition XProtocol.hh:143
kXR_write
@ kXR_write
Definition XProtocol.hh:131
readahead_list::rlen
kXR_int32 rlen
Definition XProtocol.hh:660
kXR_vermask
@ kXR_vermask
Definition XProtocol.hh:377
kXR_asyncap
@ kXR_asyncap
Definition XProtocol.hh:378
kXR_attrProxy
#define kXR_attrProxy
Definition XProtocol.hh:1160
kXR_PROTOCOLVERSION
#define kXR_PROTOCOLVERSION
Definition XProtocol.hh:70
readahead_list::offset
kXR_int64 offset
Definition XProtocol.hh:661
kXR_vfs
@ kXR_vfs
Definition XProtocol.hh:763
kXR_mkdirpath
@ kXR_mkdirpath
Definition XProtocol.hh:410
kXR_wmode
@ kXR_wmode
Definition XProtocol.hh:591
kXR_evict
@ kXR_evict
Definition XProtocol.hh:596
kXR_usetcp
@ kXR_usetcp
Definition XProtocol.hh:594
kXR_cancel
@ kXR_cancel
Definition XProtocol.hh:587
kXR_fresh
@ kXR_fresh
Definition XProtocol.hh:593
kXR_notify
@ kXR_notify
Definition XProtocol.hh:588
kXR_coloc
@ kXR_coloc
Definition XProtocol.hh:592
kXR_stage
@ kXR_stage
Definition XProtocol.hh:590
kXR_noerrs
@ kXR_noerrs
Definition XProtocol.hh:589
ServerResponseBody_Protocol::flags
kXR_int32 flags
Definition XProtocol.hh:1193
ServerResponseBody_Protocol::secreq
ServerResponseReqs_Protocol secreq
Definition XProtocol.hh:1194
kXR_file
@ kXR_file
Definition XProtocol.hh:1219
kXR_isDir
@ kXR_isDir
Definition XProtocol.hh:1221
kXR_offline
@ kXR_offline
Definition XProtocol.hh:1223
kXR_QPrep
@ kXR_QPrep
Definition XProtocol.hh:616
kXR_Qopaqug
@ kXR_Qopaqug
Definition XProtocol.hh:625
kXR_Qconfig
@ kXR_Qconfig
Definition XProtocol.hh:621
kXR_Qopaquf
@ kXR_Qopaquf
Definition XProtocol.hh:624
kXR_Qckscan
@ kXR_Qckscan
Definition XProtocol.hh:620
kXR_Qxattr
@ kXR_Qxattr
Definition XProtocol.hh:618
kXR_Qspace
@ kXR_Qspace
Definition XProtocol.hh:619
kXR_Qvisa
@ kXR_Qvisa
Definition XProtocol.hh:622
kXR_QStats
@ kXR_QStats
Definition XProtocol.hh:615
kXR_Qcksum
@ kXR_Qcksum
Definition XProtocol.hh:617
kXR_Qopaque
@ kXR_Qopaque
Definition XProtocol.hh:623
kXR_ver001
@ kXR_ver001
Definition XProtocol.hh:385
kXR_ver003
@ kXR_ver003
Definition XProtocol.hh:387
kXR_ver004
@ kXR_ver004
Definition XProtocol.hh:388
kXR_ver002
@ kXR_ver002
Definition XProtocol.hh:386
kXR_readrdok
@ kXR_readrdok
Definition XProtocol.hh:360
kXR_fullurl
@ kXR_fullurl
Definition XProtocol.hh:358
kXR_lclfile
@ kXR_lclfile
Definition XProtocol.hh:364
kXR_multipr
@ kXR_multipr
Definition XProtocol.hh:359
kXR_redirflags
@ kXR_redirflags
Definition XProtocol.hh:365
kXR_hasipv64
@ kXR_hasipv64
Definition XProtocol.hh:361
kXR_int32
int kXR_int32
Definition XPtypes.hh:89
kXR_unt32
unsigned int kXR_unt32
Definition XPtypes.hh:90
kXR_char
unsigned char kXR_char
Definition XPtypes.hh:65
XrdBuffer.hh
DEBUG
#define DEBUG(x)
Definition XrdBwmTrace.hh:54
XrdCksData.hh
Stat
struct stat Stat
Definition XrdCks.cc:49
usage
void usage()
Definition XrdClReplay.cc:1072
XrdXrootdTrace
XrdOucTrace * XrdXrootdTrace
Definition XrdFrmAdminMain.cc:96
TRACE_AUTH
#define TRACE_AUTH
Definition XrdHttpTrace.hh:48
TRACE_REDIR
#define TRACE_REDIR
Definition XrdHttpTrace.hh:52
XrdInet.hh
XrdLinkCtl.hh
ETIME
#define ETIME
Definition XrdLink.cc:74
ENODATA
#define ENODATA
Definition XrdOfsChkPnt.cc:48
XrdOucEnv.hh
XrdOucReqID.hh
XrdOucStream.hh
XrdOucString.hh
XrdOucTList.hh
XrdOucTokenizer.hh
XrdOucUtils.hh
stat
#define stat(a, b)
Definition XrdPosix.hh:101
XrdSecEntityAttr.hh
XrdSecInterface.hh
XrdSecParameters
XrdSecBuffer XrdSecParameters
Definition XrdSecInterface.hh:79
XrdSecCredentials
XrdSecBuffer XrdSecCredentials
Definition XrdSecInterface.hh:69
XrdSecProtector.hh
Mode
int Mode
Definition XrdSecgsiProxy.cc:94
Path
XrdOucString Path
Definition XrdSecpwdSrvAdmin.cc:160
eMsg
#define eMsg(x)
Definition XrdSecsssAdmin.cc:53
opts
struct myOpts opts
emsg
int emsg(int rc, char *msg)
Definition XrdSectestServer.cc:309
XrdSfsFlags.hh
XrdSfsInterface.hh
Prep_EVICT
#define Prep_EVICT
Definition XrdSfsInterface.hh:157
XrdSfsMode
int XrdSfsMode
Definition XrdSfsInterface.hh:130
SFS_DATAVEC
#define SFS_DATAVEC
Definition XrdSfsInterface.hh:113
SFS_O_HNAME
#define SFS_O_HNAME
Definition XrdSfsInterface.hh:60
Prep_FRESH
#define Prep_FRESH
Definition XrdSfsInterface.hh:154
XrdSfsFSctl::Arg1
const char * Arg1
PLUGINO, PLUGION, PLUGXC.
Definition XrdSfsInterface.hh:163
SFS_DATA
#define SFS_DATA
Definition XrdSfsInterface.hh:112
XrdSfsFSctl::Arg2Len
int Arg2Len
Length or -count of args in extension.
Definition XrdSfsInterface.hh:165
Prep_CANCEL
#define Prep_CANCEL
Definition XrdSfsInterface.hh:155
SFS_O_RESET
#define SFS_O_RESET
Definition XrdSfsInterface.hh:64
SFS_O_DIRLIST
#define SFS_O_DIRLIST
Definition XrdSfsInterface.hh:57
SFS_FSCTL_STATFS
#define SFS_FSCTL_STATFS
Definition XrdSfsInterface.hh:97
Prep_QUERY
#define Prep_QUERY
Definition XrdSfsInterface.hh:156
XrdSfsPrep::notify
char * notify
Notification path or 0.
Definition XrdSfsInterface.hh:175
XrdSfsPrep::paths
XrdOucTList * paths
List of paths.
Definition XrdSfsInterface.hh:177
XrdSfsPrep::oinfo
XrdOucTList * oinfo
1-to-1 correspondence of opaque info
Definition XrdSfsInterface.hh:178
SFS_ERROR
#define SFS_ERROR
Definition XrdSfsInterface.hh:109
Prep_WMODE
#define Prep_WMODE
Definition XrdSfsInterface.hh:151
SFS_LCLROOT
#define SFS_LCLROOT(x)
Definition XrdSfsInterface.hh:121
SFS_O_SEQIO
#define SFS_O_SEQIO
Definition XrdSfsInterface.hh:66
SFS_O_NOTPC
#define SFS_O_NOTPC
Definition XrdSfsInterface.hh:56
SFS_O_FORCE
#define SFS_O_FORCE
Definition XrdSfsInterface.hh:59
SFS_O_POSC
#define SFS_O_POSC
Definition XrdSfsInterface.hh:58
SFS_FCTL_STATV
#define SFS_FCTL_STATV
Definition XrdSfsInterface.hh:87
SFS_REDIRECT
#define SFS_REDIRECT
Definition XrdSfsInterface.hh:110
Prep_PRTY3
#define Prep_PRTY3
Definition XrdSfsInterface.hh:146
Prep_PRTY0
#define Prep_PRTY0
Definition XrdSfsInterface.hh:143
SFS_O_MKPTH
#define SFS_O_MKPTH
Definition XrdSfsInterface.hh:71
Prep_PRTY2
#define Prep_PRTY2
Definition XrdSfsInterface.hh:145
SFS_STALL
#define SFS_STALL
Definition XrdSfsInterface.hh:107
SFS_O_RDONLY
#define SFS_O_RDONLY
Definition XrdSfsInterface.hh:50
SFS_STARTED
#define SFS_STARTED
Definition XrdSfsInterface.hh:111
Prep_COLOC
#define Prep_COLOC
Definition XrdSfsInterface.hh:153
SFS_O_MULTIW
#define SFS_O_MULTIW
Definition XrdSfsInterface.hh:55
SFS_FSCTL_STATLS
#define SFS_FSCTL_STATLS
Definition XrdSfsInterface.hh:98
Prep_STAGE
#define Prep_STAGE
Definition XrdSfsInterface.hh:152
SFS_FSCTL_STATCC
#define SFS_FSCTL_STATCC
Definition XrdSfsInterface.hh:100
XrdSfsPrep::reqid
char * reqid
Request ID.
Definition XrdSfsInterface.hh:174
SFS_O_WRONLY
#define SFS_O_WRONLY
Definition XrdSfsInterface.hh:51
SFS_O_CREAT
#define SFS_O_CREAT
Definition XrdSfsInterface.hh:53
SFS_FSCTL_STATXA
#define SFS_FSCTL_STATXA
Definition XrdSfsInterface.hh:99
SFS_FSCTL_LOCATE
#define SFS_FSCTL_LOCATE
Definition XrdSfsInterface.hh:96
SFS_O_RAWIO
#define SFS_O_RAWIO
Definition XrdSfsInterface.hh:63
SFS_O_RDWR
#define SFS_O_RDWR
Definition XrdSfsInterface.hh:52
Prep_PRTY1
#define Prep_PRTY1
Definition XrdSfsInterface.hh:144
Prep_SENDACK
#define Prep_SENDACK
Definition XrdSfsInterface.hh:150
SFS_FSCTL_PLUGIO
#define SFS_FSCTL_PLUGIO
Definition XrdSfsInterface.hh:102
SFS_O_LOCAL
#define SFS_O_LOCAL
Definition XrdSfsInterface.hh:61
XrdSfsFileOpenMode
int XrdSfsFileOpenMode
Definition XrdSfsInterface.hh:129
XrdSfsFSctl::Arg1Len
int Arg1Len
Length.
Definition XrdSfsInterface.hh:164
SFS_FCTL_SPEC1
#define SFS_FCTL_SPEC1
Definition XrdSfsInterface.hh:88
SFS_OK
#define SFS_OK
Definition XrdSfsInterface.hh:108
XrdSfsFileOffset
long long XrdSfsFileOffset
Definition XrdSfsInterface.hh:128
SFS_LCLPATH
#define SFS_LCLPATH(x)
Definition XrdSfsInterface.hh:119
SFS_O_NOWAIT
#define SFS_O_NOWAIT
Definition XrdSfsInterface.hh:62
SFS_FSCTL_PLUGXC
#define SFS_FSCTL_PLUGXC
Definition XrdSfsInterface.hh:103
XrdSfsPrep::opts
int opts
Prep_xxx.
Definition XrdSfsInterface.hh:176
SFS_O_REPLICA
#define SFS_O_REPLICA
Definition XrdSfsInterface.hh:65
SFS_FSCTL_PLUGIN
#define SFS_FSCTL_PLUGIN
Definition XrdSfsInterface.hh:101
SFS_O_TRUNC
#define SFS_O_TRUNC
Definition XrdSfsInterface.hh:54
XrdSfsXferSize
int XrdSfsXferSize
Definition XrdSfsInterface.hh:131
Prep_SENDAOK
#define Prep_SENDAOK
Definition XrdSfsInterface.hh:148
XrdSysE2T
const char * XrdSysE2T(int errcode)
Definition XrdSysE2T.cc:104
XrdSysE2T.hh
XrdSysError.hh
SYS_LOG_01
const int SYS_LOG_01
Definition XrdSysError.hh:72
ec
ec
Definition XrdSysFAttrSun.icc:100
if
if(ec< 0) ec
XrdSysPlatform.hh
RAtomic_uint
XrdSys::RAtomic< unsigned int > RAtomic_uint
Definition XrdSysRAtomic.hh:326
XrdSysTimer.hh
TRACING
#define TRACING(x)
Definition XrdTrace.hh:70
TRACEI
#define TRACEI(act, x)
Definition XrdTrace.hh:66
XrdXrootdAioFob.hh
XrdXrootdCallBack.hh
XrdXrootdCF
XrdOucString * XrdXrootdCF
Definition XrdXrootdConfig.cc:113
XrdXrootdFileLock.hh
XrdXrootdFile.hh
XrdXrootdJob.hh
JOB_Sync
#define JOB_Sync
Definition XrdXrootdJob.hh:48
XROOTD_MON_OPENW
const kXR_char XROOTD_MON_OPENW
Definition XrdXrootdMonData.hh:139
XROOTD_MON_STAT
const kXR_char XROOTD_MON_STAT
Definition XrdXrootdMonData.hh:146
XROOTD_MON_REDLOCAL
const kXR_char XROOTD_MON_REDLOCAL
Definition XrdXrootdMonData.hh:132
XROOTD_MON_PREP
const kXR_char XROOTD_MON_PREP
Definition XrdXrootdMonData.hh:142
XROOTD_MON_OPENC
const kXR_char XROOTD_MON_OPENC
Definition XrdXrootdMonData.hh:137
XROOTD_MON_TRUNC
const kXR_char XROOTD_MON_TRUNC
Definition XrdXrootdMonData.hh:147
XROOTD_MON_CLOSE
const kXR_char XROOTD_MON_CLOSE
Definition XrdXrootdMonData.hh:94
XROOTD_MON_CHMOD
const kXR_char XROOTD_MON_CHMOD
Definition XrdXrootdMonData.hh:134
XROOTD_MON_LOCATE
const kXR_char XROOTD_MON_LOCATE
Definition XrdXrootdMonData.hh:135
XROOTD_MON_OPENR
const kXR_char XROOTD_MON_OPENR
Definition XrdXrootdMonData.hh:138
XROOTD_MON_MV
const kXR_char XROOTD_MON_MV
Definition XrdXrootdMonData.hh:141
XROOTD_MON_RMDIR
const kXR_char XROOTD_MON_RMDIR
Definition XrdXrootdMonData.hh:145
XROOTD_MON_RM
const kXR_char XROOTD_MON_RM
Definition XrdXrootdMonData.hh:144
XROOTD_MON_OPENDIR
const kXR_char XROOTD_MON_OPENDIR
Definition XrdXrootdMonData.hh:136
XROOTD_MON_QUERY
const kXR_char XROOTD_MON_QUERY
Definition XrdXrootdMonData.hh:143
XROOTD_MON_MKDIR
const kXR_char XROOTD_MON_MKDIR
Definition XrdXrootdMonData.hh:140
XrdXrootdMonFile.hh
XrdXrootdMonitor.hh
XrdXrootdNormAio.hh
XrdXrootdPio.hh
XrdXrootdPrepare.hh
XrdXrootdProtocol.hh
XRD_BOUNDPATH
#define XRD_BOUNDPATH
Definition XrdXrootdProtocol.hh:59
XRD_LOGGEDIN
#define XRD_LOGGEDIN
Definition XrdXrootdProtocol.hh:57
XRD_NEED_AUTH
#define XRD_NEED_AUTH
Definition XrdXrootdProtocol.hh:58
XrdXrootdRedirPI.hh
XrdXrootdStats.hh
XrdXrootdTrace.hh
TRACE_FS
#define TRACE_FS
Definition XrdXrootdTrace.hh:37
TRACEP
#define TRACEP(act, x)
Definition XrdXrootdTrace.hh:63
XrdXrootdWVInfo.hh
XrdXrootdWVInfo
Definition XrdXrootdWVInfo.hh:35
XrdXrootdXPath.hh
XROOTDXP_NOLK
#define XROOTDXP_NOLK
Definition XrdXrootdXPath.hh:37
XROOTDXP_NOSLASH
#define XROOTDXP_NOSLASH
Definition XrdXrootdXPath.hh:39
XROOTDXP_NOMWCHK
#define XROOTDXP_NOMWCHK
Definition XrdXrootdXPath.hh:40
XROOTDXP_NOCGI
#define XROOTDXP_NOCGI
Definition XrdXrootdXPath.hh:38
Map_Mode
#define Map_Mode(x, y)
Definition XrdXrootdXeq.cc:4225
XrdXrootdXeq.hh
STATIC_REDIRECT
#define STATIC_REDIRECT(xfnc)
Definition XrdXrootdXeq.hh:38
CRED
#define CRED
Definition XrdXrootdXeq.hh:34
XProtocol::errName
static const char * errName(kXR_int32 errCode)
Definition XProtocol.cc:130
XProtocol::mapError
static int mapError(int rc)
Definition XProtocol.hh:1362
XrdCksData::ValuSize
static const int ValuSize
Definition XrdCksData.hh:42
XrdCksData::NameSize
static const int NameSize
Definition XrdCksData.hh:41
XrdInet::GetAssumeV4
static bool GetAssumeV4()
Definition XrdInet.hh:65
XrdJob::XrdJob
XrdJob(const char *desc="")
Definition XrdJob.hh:51
XrdLinkCtl::fd2link
static XrdLink * fd2link(int fd)
Definition XrdLinkCtl.hh:72
XrdLink::Hold
void Hold(bool lk)
Definition XrdLink.cc:240
XrdLink::ID
char * ID
Pointer to the client's link identity.
Definition XrdLink.hh:210
XrdLink::getProtocol
XrdProtocol * getProtocol()
Obtain current protocol object pointer.
Definition XrdLink.cc:234
XrdLink::Host
const char * Host() const
Definition XrdLink.hh:204
XrdNetAddrInfo::isMapped
bool isMapped() const
Definition XrdNetAddrInfo.hh:155
XrdNetAddrInfo::IPv4
@ IPv4
Definition XrdNetAddrInfo.hh:144
XrdNetAddrInfo::isIPType
bool isIPType(IPType ipType) const
Definition XrdNetAddrInfo.hh:146
XrdNetAddrInfo::isPrivate
bool isPrivate()
Definition XrdNetAddrInfo.cc:200
XrdNetAddr
Definition XrdNetAddr.hh:42
XrdNetAddr::Set
const char * Set(const char *hSpec, int pNum=PortInSpec)
Definition XrdNetAddr.cc:216
XrdNetPMark::getEA
static bool getEA(const char *cgi, int &ecode, int &acode)
Definition XrdNetPMark.cc:40
XrdOucEICB::Done
virtual void Done(int &Result, XrdOucErrInfo *eInfo, const char *Path=0)=0
XrdOucErrInfo
Definition XrdOucErrInfo.hh:101
XrdOucErrInfo::getErrCB
XrdOucEICB * getErrCB()
Definition XrdOucErrInfo.hh:224
XrdOucErrInfo::getErrTextLen
int getErrTextLen()
Definition XrdOucErrInfo.hh:286
XrdOucErrInfo::setErrCB
void setErrCB(XrdOucEICB *cb, unsigned long long cbarg=0)
Definition XrdOucErrInfo.hh:125
XrdOucErrInfo::getErrText
const char * getErrText()
Definition XrdOucErrInfo.hh:262
XrdOucErrInfo::extData
bool extData()
Definition XrdOucErrInfo.hh:371
XrdOucErrInfo::setUCap
void setUCap(int ucval)
Set user capabilties.
Definition XrdOucErrInfo.hh:395
XrdOucErrInfo::Reset
void Reset()
Reset object to no message state. Call this method to release appendages.
Definition XrdOucErrInfo.hh:377
XrdOucString::length
int length() const
Definition XrdOucString.hh:279
XrdOucString::c_str
const char * c_str() const
Definition XrdOucString.hh:278
XrdOucTList::next
XrdOucTList * next
Definition XrdOucTList.hh:45
XrdOucTList::text
char * text
Definition XrdOucTList.hh:46
XrdOucTokenizer
Definition XrdOucTokenizer.hh:33
XrdOucTokenizer::GetToken
char * GetToken(char **rest=0, int lowcase=0)
Definition XrdOucTokenizer.cc:93
XrdOucUtils::Sanitize
static void Sanitize(char *instr, char subc='_')
Definition XrdOucUtils.cc:1176
XrdOucUtils::isFWD
static int isFWD(const char *path, int *port=0, char *hBuff=0, int hBLen=0, bool pTrim=false)
Definition XrdOucUtils.cc:847
XrdSfsDio::XrdSfsDio
XrdSfsDio()
Constructor and destructor.
Definition XrdSfsDio.hh:103
XrdSfsDirectory
Definition XrdSfsInterface.hh:244
XrdSfsDirectory::autoStat
virtual int autoStat(struct stat *buf)
Definition XrdSfsInterface.cc:46
XrdSfsDirectory::open
virtual int open(const char *path, const XrdSecEntity *client=0, const char *opaque=0)=0
XrdSfsDirectory::error
XrdOucErrInfo & error
Definition XrdSfsInterface.hh:252
XrdSfsDirectory::nextEntry
virtual const char * nextEntry()=0
XrdSfsDirectory::close
virtual int close()=0
XrdSfsFileSystem::csGet
@ csGet
Definition XrdSfsInterface.hh:928
XrdSfsFile::sync
virtual int sync()=0
XrdSfsFile::error
XrdOucErrInfo & error
Definition XrdSfsInterface.hh:378
XrdSfsFile::open
virtual int open(const char *fileName, XrdSfsFileOpenMode openMode, mode_t createMode, const XrdSecEntity *client=0, const char *opaque=0)=0
XrdSfsFile::truncate
virtual int truncate(XrdSfsFileOffset fsize)=0
XrdSfsFile::getCXinfo
virtual int getCXinfo(char cxtype[4], int &cxrsz)=0
XrdSfsFile::stat
virtual int stat(struct stat *buf)=0
XrdSfsFile::setXio
virtual void setXio(XrdSfsXio *xioP)
Definition XrdSfsInterface.hh:766
XrdSfsFile::fctl
virtual int fctl(const int cmd, const char *args, XrdOucErrInfo &eInfo)=0
XrdSysMutex
Definition XrdSysPthread.hh:165
XrdSysMutex::Lock
void Lock()
Definition XrdSysPthread.hh:222
XrdSysMutex::UnLock
void UnLock()
Definition XrdSysPthread.hh:224
XrdSysTimer::Snooze
static void Snooze(int seconds)
Definition XrdSysTimer.cc:168
XrdSysTrace
Definition XrdSysTrace.hh:49
XrdXrootdFileStats::monLvl
char monLvl
Definition XrdXrootdFileStats.hh:41
XrdXrootdFileStats::monOn
@ monOn
Definition XrdXrootdFileStats.hh:53
XrdXrootdFileStats::FileID
kXR_unt32 FileID
Definition XrdXrootdFileStats.hh:39
XrdXrootdFile
Definition XrdXrootdFile.hh:101
XrdXrootdFile::sfEnabled
bool sfEnabled
Definition XrdXrootdFile.hh:113
XrdXrootdFile::pgwFob
XrdXrootdPgwFob * pgwFob
Definition XrdXrootdFile.hh:118
XrdXrootdFile::Serialize
void Serialize()
Definition XrdXrootdFile.cc:184
XrdXrootdFile::XrdSfsp
XrdSfsFile * XrdSfsp
Definition XrdXrootdFile.hh:104
XrdXrootdFile::Stats
XrdXrootdFileStats Stats
Definition XrdXrootdFile.hh:122
XrdXrootdMonFile::Open
static void Open(XrdXrootdFileStats *fsP, const char *Path, unsigned int uDID, bool isRW)
Definition XrdXrootdMonFile.cc:464
XrdXrootdMonitor::Redirect
static int Redirect()
Definition XrdXrootdMonitor.hh:141
XrdXrootdNormAio::Write
int Write(long long offs, int dlen) override
Definition XrdXrootdNormAio.cc:479
XrdXrootdNormAio::Read
void Read(long long offs, int dlen) override
Definition XrdXrootdNormAio.cc:386
XrdXrootdNormAio::Alloc
static XrdXrootdNormAio * Alloc(XrdXrootdProtocol *protP, XrdXrootdResponse &resp, XrdXrootdFile *fP)
Definition XrdXrootdNormAio.cc:84
XrdXrootdPio::Next
XrdXrootdPio * Next
Definition XrdXrootdPio.hh:43
XrdXrootdPio::IO
XrdXrootd::IOParms IO
Definition XrdXrootdPio.hh:45
XrdXrootdPio::ResumePio
int(XrdXrootdProtocol::* ResumePio)()
Definition XrdXrootdPio.hh:44
XrdXrootdPio::Alloc
static XrdXrootdPio * Alloc(int n=1)
Definition XrdXrootdPio.cc:45
XrdXrootdPio::StreamID
kXR_char StreamID[2]
Definition XrdXrootdPio.hh:46
XrdXrootdPio::Set
void Set(int(XrdXrootdProtocol::*Invoke)(), XrdXrootd::IOParms &io, const kXR_char *theSID)
Definition XrdXrootdPio.hh:59
XrdXrootdPrepare::List
static int List(XrdXrootdPrepArgs &pargs, char *resp, int resplen)
Definition XrdXrootdPrepare.cc:92
XrdXrootdPrepare::Log
static void Log(XrdXrootdPrepArgs &pargs)
Definition XrdXrootdPrepare.cc:149
XrdXrootdPrepare::Logdel
static void Logdel(char *reqid)
Definition XrdXrootdPrepare.cc:210
XrdXrootdProtocol
Definition XrdXrootdProtocol.hh:160
XrdXrootdProtocol::SI
static XrdXrootdStats * SI
Definition XrdXrootdProtocol.hh:490
XrdXrootdProtocol::SendFile
int SendFile(int fildes) override
Definition XrdXrootdXeq.cc:3636
XrdXrootdProtocol::Entity
XrdSecEntity Entity
Definition XrdXrootdProtocol.hh:529
XrdXrootdProtocol::VerifyStream
XrdXrootdProtocol * VerifyStream(int &rc, int pID, bool lok=true)
Definition XrdXrootdProtocol.cc:975
XrdXrootdProtocol::digFS
static XrdSfsFileSystem * digFS
Definition XrdXrootdProtocol.hh:397
XrdXrootdProtocol::isActive
bool isActive
Definition XrdXrootdProtocol.hh:605
XrdXrootdProtocol::SetSF
int SetSF(kXR_char *fhandle, bool seton=false)
Definition XrdXrootdXeq.cc:4314
XrdXrootdProtocol::Protect
XrdSecProtect * Protect
Definition XrdXrootdProtocol.hh:530
XrdXrootdProtocol::isLinkWT
bool isLinkWT
Definition XrdXrootdProtocol.hh:606
XrdXrootdProtocol::pmHandle
XrdNetPMark::Handle * pmHandle
Definition XrdXrootdProtocol.hh:516
XrdXrootdProtocol::PMark
static XrdNetPMark * PMark
Definition XrdXrootdProtocol.hh:405
XrdXrootdProtocol::numFiles
int numFiles
Definition XrdXrootdProtocol.hh:498
XrdXrootdProtocol::Stream
XrdXrootdProtocol * Stream[maxStreams]
Definition XrdXrootdProtocol.hh:603
XrdXrootdProtocol::IO
XrdXrootd::IOParms IO
Definition XrdXrootdProtocol.hh:587
XrdXrootdProtocol::AppName
char * AppName
Definition XrdXrootdProtocol.hh:531
XrdXrootdProtocol::as_maxpersrv
static int as_maxpersrv
Definition XrdXrootdProtocol.hh:224
XrdXrootdProtocol::RPList
static XrdXrootdXPath RPList
Definition XrdXrootdProtocol.hh:393
XrdXrootdProtocol::myBlast
int myBlast
Definition XrdXrootdProtocol.hh:553
XrdXrootdProtocol::rvSeq
unsigned char rvSeq
Definition XrdXrootdProtocol.hh:617
XrdXrootdProtocol::Client
XrdSecEntity * Client
Definition XrdXrootdProtocol.hh:527
XrdXrootdProtocol::as_miniosz
static int as_miniosz
Definition XrdXrootdProtocol.hh:225
XrdXrootdProtocol::Req_TLSGPFile
static const char Req_TLSGPFile
Definition XrdXrootdProtocol.hh:474
XrdXrootdProtocol::Port
static int Port
Definition XrdXrootdProtocol.hh:430
XrdXrootdProtocol::ableTLS
bool ableTLS
Definition XrdXrootdProtocol.hh:621
XrdXrootdProtocol::as_aioOK
static bool as_aioOK
Definition XrdXrootdProtocol.hh:233
XrdXrootdProtocol::XrdXrootdProtocol
XrdXrootdProtocol()
Definition XrdXrootdProtocol.cc:259
XrdXrootdProtocol::pmDone
bool pmDone
Definition XrdXrootdProtocol.hh:519
XrdXrootdProtocol::RQLxist
static int RQLxist
Definition XrdXrootdProtocol.hh:409
XrdXrootdProtocol::Request
ClientRequest Request
Definition XrdXrootdProtocol.hh:635
XrdXrootdProtocol::OD_Bypass
static bool OD_Bypass
Definition XrdXrootdProtocol.hh:458
XrdXrootdProtocol::myBuff
char * myBuff
Definition XrdXrootdProtocol.hh:551
XrdXrootdProtocol::hcMax
static int hcMax
Definition XrdXrootdProtocol.hh:591
XrdXrootdProtocol::SetFD
void SetFD(int fildes) override
Definition XrdXrootdXeq.cc:3675
XrdXrootdProtocol::Req_TLSSess
static const char Req_TLSSess
Definition XrdXrootdProtocol.hh:476
XrdXrootdProtocol::wvInfo
XrdXrootdWVInfo * wvInfo
Definition XrdXrootdProtocol.hh:584
XrdXrootdProtocol::reTry
XrdSysSemaphore * reTry
Definition XrdXrootdProtocol.hh:601
XrdXrootdProtocol::FTab
XrdXrootdFileTable * FTab
Definition XrdXrootdProtocol.hh:514
XrdXrootdProtocol::readWait
static int readWait
Definition XrdXrootdProtocol.hh:429
XrdXrootdProtocol::numWritV
int numWritV
Definition XrdXrootdProtocol.hh:495
XrdXrootdProtocol::JobCKS
static XrdXrootdJob * JobCKS
Definition XrdXrootdProtocol.hh:440
XrdXrootdProtocol::eDest
static XrdSysError & eDest
Definition XrdXrootdProtocol.hh:404
XrdXrootdProtocol::getSID
static unsigned int getSID()
Definition XrdXrootdProtocol.cc:271
XrdXrootdProtocol::newPio
bool newPio
Definition XrdXrootdProtocol.hh:616
XrdXrootdProtocol::AuthProt
XrdSecProtocol * AuthProt
Definition XrdXrootdProtocol.hh:528
XrdXrootdProtocol::myRole
static int myRole
Definition XrdXrootdProtocol.hh:411
XrdXrootdProtocol::getData
int getData(gdCallBack *gdcbP, const char *dtype, char *buff, int blen)
XrdXrootdProtocol::usxParms
static char * usxParms
Definition XrdXrootdProtocol.hh:469
XrdXrootdProtocol::Monitor
XrdXrootdMonitor::User Monitor
Definition XrdXrootdProtocol.hh:515
XrdXrootdProtocol::RedirPI
static XrdXrootdRedirPI * RedirPI
Definition XrdXrootdProtocol.hh:406
XrdXrootdProtocol::tlsNot
static char tlsNot
Definition XrdXrootdProtocol.hh:480
XrdXrootdProtocol::myStalls
int myStalls
Definition XrdXrootdProtocol.hh:507
XrdXrootdProtocol::clientPV
int clientPV
Definition XrdXrootdProtocol.hh:517
XrdXrootdProtocol::myCName
static const char * myCName
Definition XrdXrootdProtocol.hh:435
XrdXrootdProtocol::isNOP
bool isNOP
Definition XrdXrootdProtocol.hh:607
XrdXrootdProtocol::pioFree
XrdXrootdPio * pioFree
Definition XrdXrootdProtocol.hh:613
XrdXrootdProtocol::PrepareCount
int PrepareCount
Definition XrdXrootdProtocol.hh:629
XrdXrootdProtocol::myCNlen
static int myCNlen
Definition XrdXrootdProtocol.hh:436
XrdXrootdProtocol::Req_TLSData
static const char Req_TLSData
Definition XrdXrootdProtocol.hh:473
XrdXrootdProtocol::as_syncw
static bool as_syncw
Definition XrdXrootdProtocol.hh:235
XrdXrootdProtocol::mySID
unsigned int mySID
Definition XrdXrootdProtocol.hh:604
XrdXrootdProtocol::maxBuffsz
static int maxBuffsz
Definition XrdXrootdProtocol.hh:484
XrdXrootdProtocol::Link
XrdLink * Link
Definition XrdXrootdProtocol.hh:512
XrdXrootdProtocol::Locker
static XrdXrootdFileLock * Locker
Definition XrdXrootdProtocol.hh:401
XrdXrootdProtocol::numReadV
int numReadV
Definition XrdXrootdProtocol.hh:493
XrdXrootdProtocol::maxPio
static const int maxPio
Definition XrdXrootdProtocol.hh:610
XrdXrootdProtocol::numSegsW
int numSegsW
Definition XrdXrootdProtocol.hh:496
XrdXrootdProtocol::Resume
int(XrdXrootdProtocol::* Resume)()
Definition XrdXrootdProtocol.hh:586
XrdXrootdProtocol::myPID
static int myPID
Definition XrdXrootdProtocol.hh:410
XrdXrootdProtocol::Req_TLSTPC
static const char Req_TLSTPC
Definition XrdXrootdProtocol.hh:477
XrdXrootdProtocol::tlsCtx
static XrdTlsContext * tlsCtx
Definition XrdXrootdProtocol.hh:400
XrdXrootdProtocol::as_maxstalls
static int as_maxstalls
Definition XrdXrootdProtocol.hh:229
XrdXrootdProtocol::redirIPHold
static int redirIPHold
Definition XrdXrootdProtocol.hh:433
XrdXrootdProtocol::PathID
short PathID
Definition XrdXrootdProtocol.hh:615
XrdXrootdProtocol::streamMutex
XrdSysMutex streamMutex
Definition XrdXrootdProtocol.hh:600
XrdXrootdProtocol::MonAuth
void MonAuth()
Definition XrdXrootdXeq.cc:4246
XrdXrootdProtocol::pioLast
XrdXrootdPio * pioLast
Definition XrdXrootdProtocol.hh:612
XrdXrootdProtocol::tlsCap
static char tlsCap
Definition XrdXrootdProtocol.hh:479
XrdXrootdProtocol::PrepareAlt
static bool PrepareAlt
Definition XrdXrootdProtocol.hh:626
XrdXrootdProtocol::XPList
static XrdXrootdXPath XPList
Definition XrdXrootdProtocol.hh:395
XrdXrootdProtocol::as_maxperlnk
static int as_maxperlnk
Definition XrdXrootdProtocol.hh:222
XrdXrootdProtocol::isTLS
bool isTLS
Definition XrdXrootdProtocol.hh:622
XrdXrootdProtocol::Sched
static XrdScheduler * Sched
Definition XrdXrootdProtocol.hh:402
XrdXrootdProtocol::clientRN
int clientRN
Definition XrdXrootdProtocol.hh:518
XrdXrootdProtocol::CapVer
unsigned char CapVer
Definition XrdXrootdProtocol.hh:523
XrdXrootdProtocol::tlsPort
static int tlsPort
Definition XrdXrootdProtocol.hh:432
XrdXrootdProtocol::OD_Stall
static int OD_Stall
Definition XrdXrootdProtocol.hh:457
XrdXrootdProtocol::PrepareLimit
static int PrepareLimit
Definition XrdXrootdProtocol.hh:630
XrdXrootdProtocol::Req_TLSLogin
static const char Req_TLSLogin
Definition XrdXrootdProtocol.hh:475
XrdXrootdProtocol::Status
char Status
Definition XrdXrootdProtocol.hh:522
XrdXrootdProtocol::Response
XrdXrootdResponse Response
Definition XrdXrootdProtocol.hh:636
XrdXrootdProtocol::ResumePio
int(XrdXrootdProtocol::* ResumePio)()
Definition XrdXrootdProtocol.hh:585
XrdXrootdProtocol::JobLCL
static char JobLCL
Definition XrdXrootdProtocol.hh:438
XrdXrootdProtocol::hcNow
int hcNow
Definition XrdXrootdProtocol.hh:594
XrdXrootdProtocol::JobCKT
static char * JobCKT
Definition XrdXrootdProtocol.hh:441
XrdXrootdProtocol::JobCKCGI
static char JobCKCGI
Definition XrdXrootdProtocol.hh:439
XrdXrootdProtocol::numSegsV
int numSegsV
Definition XrdXrootdProtocol.hh:494
XrdXrootdProtocol::argp
XrdBuffer * argp
Definition XrdXrootdProtocol.hh:513
XrdXrootdProtocol::maxStreams
static const int maxStreams
Definition XrdXrootdProtocol.hh:218
XrdXrootdProtocol::as_seghalf
static int as_seghalf
Definition XrdXrootdProtocol.hh:227
XrdXrootdProtocol::hcNext
int hcNext
Definition XrdXrootdProtocol.hh:593
XrdXrootdProtocol::numWrites
int numWrites
Definition XrdXrootdProtocol.hh:497
XrdXrootdProtocol::JobCKTLST
static XrdOucTList * JobCKTLST
Definition XrdXrootdProtocol.hh:442
XrdXrootdProtocol::myRolf
static int myRolf
Definition XrdXrootdProtocol.hh:412
XrdXrootdProtocol::RQList
static XrdXrootdXPath RQList
Definition XrdXrootdProtocol.hh:394
XrdXrootdProtocol::Route
static struct XrdXrootdProtocol::RD_Table Route[RD_Num]
Definition XrdXrootdProtocol.cc:159
XrdXrootdProtocol::DHS
static XrdSecProtector * DHS
Definition XrdXrootdProtocol.hh:399
XrdXrootdProtocol::as_minsfsz
static int as_minsfsz
Definition XrdXrootdProtocol.hh:226
XrdXrootdProtocol::BPool
static XrdBuffManager * BPool
Definition XrdXrootdProtocol.hh:403
XrdXrootdProtocol::CIA
static XrdSecService * CIA
Definition XrdXrootdProtocol.hh:398
XrdXrootdProtocol::srvrAioOps
static RAtomic_int srvrAioOps
Definition XrdXrootdProtocol.hh:176
XrdXrootdProtocol::myBlen
int myBlen
Definition XrdXrootdProtocol.hh:552
XrdXrootdProtocol::do_WriteSpan
int do_WriteSpan()
Definition XrdXrootdXeq.cc:3359
XrdXrootdProtocol::Notify
static char * Notify
Definition XrdXrootdProtocol.hh:434
XrdXrootdProtocol::fsFeatures
static uint64_t fsFeatures
Definition XrdXrootdProtocol.hh:444
XrdXrootdProtocol::numReads
int numReads
Definition XrdXrootdProtocol.hh:491
XrdXrootdProtocol::ReqID
XrdXrootdReqID ReqID
Definition XrdXrootdProtocol.hh:634
XrdXrootdProtocol::hcPrev
int hcPrev
Definition XrdXrootdProtocol.hh:592
XrdXrootdProtocol::rdType
short rdType
Definition XrdXrootdProtocol.hh:521
XrdXrootdProtocol::PrepID
static XrdOucReqID * PrepID
Definition XrdXrootdProtocol.hh:443
XrdXrootdProtocol::halfBSize
int halfBSize
Definition XrdXrootdProtocol.hh:595
XrdXrootdProtocol::doTLS
char doTLS
Definition XrdXrootdProtocol.hh:620
XrdXrootdProtocol::Window
static int Window
Definition XrdXrootdProtocol.hh:431
XrdXrootdProtocol::pioFirst
XrdXrootdPio * pioFirst
Definition XrdXrootdProtocol.hh:611
XrdXrootdProtocol::linkAioReq
RAtomic_int linkAioReq
Definition XrdXrootdProtocol.hh:545
XrdXrootdProtocol::as_force
static bool as_force
Definition XrdXrootdProtocol.hh:232
XrdXrootdProtocol::endNote
XrdSysCondVar2 * endNote
Definition XrdXrootdProtocol.hh:602
XrdXrootdProtocol::osFS
static XrdSfsFileSystem * osFS
Definition XrdXrootdProtocol.hh:396
XrdXrootdProtocol::LimitError
static bool LimitError
Definition XrdXrootdProtocol.hh:627
XrdXrootdProtocol::maxTransz
static int maxTransz
Definition XrdXrootdProtocol.hh:485
XrdXrootdProtocol::maxReadv_ior
static int maxReadv_ior
Definition XrdXrootdProtocol.hh:486
XrdXrootdResponse::Set
void Set(XrdLink *lp)
Definition XrdXrootdResponse.hh:76
XrdXrootdStats::errorCnt
int errorCnt
Definition XrdXrootdStats.hh:43
XrdXrootdXPath::Opts
int Opts()
Definition XrdXrootdXPath.hh:47
TPC::Info
@ Info
Definition XrdHttpTpcTPC.hh:29
XrdProto::maxRvecsz
static const int maxRvecsz
Definition XProtocol.hh:686
XrdProto::maxWvecsz
static const int maxWvecsz
Definition XProtocol.hh:838
XrdProto::write_list
Definition XProtocol.hh:831
XrdSfs::hasCACH
static const uint64_t hasCACH
Feature: Implements a data cache.
Definition XrdSfsFlags.hh:74
XrdSfs::hasSXIO
static const uint64_t hasSXIO
Feature: Supports SfsXio.
Definition XrdSfsFlags.hh:68
XrdSys::Send
ssize_t Send(int fd, KernelBuffer &buffer)
Definition XrdSysKernelBuffer.hh:442
XrdXrootd
Definition XrdXrootdAioBuff.cc:49
XrdXrootd::bifRLen
int bifRLen[2]
Definition XrdXrootdConfig.cc:992
XrdXrootd::bifResp
char * bifResp[2]
Definition XrdXrootdConfig.cc:991
Xrd::oct1
@ oct1
Definition XrdSysTrace.hh:42
ClientProtocolRequest::kXR_secreqs
@ kXR_secreqs
Definition XProtocol.hh:565
ClientProtocolRequest::kXR_bifreqs
@ kXR_bifreqs
Definition XProtocol.hh:568
ClientProtocolRequest::kXR_wantTLS
@ kXR_wantTLS
Definition XProtocol.hh:567
ClientProtocolRequest::kXR_ableTLS
@ kXR_ableTLS
Definition XProtocol.hh:566
ClientProtocolRequest::kXR_ExpTPC
@ kXR_ExpTPC
Definition XProtocol.hh:577
ClientProtocolRequest::kXR_ExpMask
@ kXR_ExpMask
Definition XProtocol.hh:572
ClientProtocolRequest::kXR_ExpLogin
@ kXR_ExpLogin
Definition XProtocol.hh:576
ClientProtocolRequest::kXR_ExpBind
@ kXR_ExpBind
Definition XProtocol.hh:574
ClientWriteVRequest::doSync
static const kXR_int32 doSync
Definition XProtocol.hh:826
XrdNetAddrInfo::LocInfo::TimeZone
char TimeZone
+/- hours from GMT (-128 if not set)
Definition XrdNetAddrInfo.hh:198
XrdNetAddrInfo::LocInfo::Country
unsigned char Country[2]
Two letter TLD country code.
Definition XrdNetAddrInfo.hh:195
XrdOucEI::uRedirFlgs
static const int uRedirFlgs
ucap: Client supports "file://"
Definition XrdOucErrInfo.hh:69
XrdOucEI::uVMask
static const int uVMask
Definition XrdOucErrInfo.hh:59
XrdOucEI::uUrlOK
static const int uUrlOK
ucap: Supports async responses
Definition XrdOucErrInfo.hh:61
XrdOucEI::uIPv64
static const int uIPv64
ucap: Supports only IPv4 info
Definition XrdOucErrInfo.hh:65
XrdOucEI::uReadR
static const int uReadR
ucap: Supports multiple protocols
Definition XrdOucErrInfo.hh:63
XrdOucEI::uEcRedir
static const int uEcRedir
ucap: Client supports redirect flags
Definition XrdOucErrInfo.hh:70
XrdOucEI::uMProt
static const int uMProt
ucap: Supports url redirects
Definition XrdOucErrInfo.hh:62
XrdOucEI::uLclF
static const int uLclF
ucap: Client is on a private net
Definition XrdOucErrInfo.hh:68
XrdOucEI::uAsync
static const int uAsync
ucap: Extract protocol version
Definition XrdOucErrInfo.hh:60
XrdOucEI::uIPv4
static const int uIPv4
ucap: Supports read redirects
Definition XrdOucErrInfo.hh:64
XrdOucEI::uPrip
static const int uPrip
Definition XrdOucErrInfo.hh:67
XrdOucIOVec::size
int size
Definition XrdOucIOVec.hh:43
XrdOucIOVec::offset
long long offset
Definition XrdOucIOVec.hh:42
XrdOucIOVec::info
int info
Definition XrdOucIOVec.hh:44
XrdOucSFVec
Definition XrdOucSFVec.hh:43
XrdSecBuffer::buffer
char * buffer
Pointer to the buffer.
Definition XrdSecInterface.hh:53
XrdSecBuffer::size
int size
Size of the buffer or length of data in the buffer.
Definition XrdSecInterface.hh:52
XrdXrootdFHandle
Definition XrdXrootdXeq.hh:48
XrdXrootdFHandle::handle
kXR_int32 handle
Definition XrdXrootdXeq.hh:48
XrdXrootdSessID::FD
int FD
Definition XrdXrootdXeq.cc:97
XrdXrootdSessID::Pid
int Pid
Definition XrdXrootdXeq.cc:96
XrdXrootdSessID::XrdXrootdSessID
XrdXrootdSessID()
Definition XrdXrootdXeq.cc:100
XrdXrootdSessID::Sid
unsigned int Sid
Definition XrdXrootdXeq.cc:95
XrdXrootdSessID::Inst
unsigned int Inst
Definition XrdXrootdXeq.cc:98
XrdXrootdSessID::~XrdXrootdSessID
~XrdXrootdSessID()
Definition XrdXrootdXeq.cc:101
XrdXrootd::IOParms::useSF
static const int useSF
Definition XrdXrootdProtocol.hh:150
XrdXrootd::IOParms::useBasic
static const int useBasic
Definition XrdXrootdProtocol.hh:148
XrdXrootd::IOParms::useMMap
static const int useMMap
Definition XrdXrootdProtocol.hh:149
XrdXrootd::netInfo
Definition XrdXrootdXeq.cc:3951
XrdXrootd::netInfo::netAddr
XrdNetAddr netAddr
Definition XrdXrootdXeq.cc:3951
XrdXrootd::netInfo::expTime
time_t expTime
Definition XrdXrootdXeq.cc:3954
XrdXrootd::netInfo::refs
RAtomic_uint refs
Definition XrdXrootdXeq.cc:3955
XrdXrootd::netInfo::niMutex
XrdSysMutex niMutex
Definition XrdXrootdXeq.cc:3952
XrdXrootd::netInfo::~netInfo
~netInfo()
Definition XrdXrootdXeq.cc:3958
XrdXrootd::netInfo::netID
char * netID
Definition XrdXrootdXeq.cc:3953
XrdXrootd::netInfo::netInfo
netInfo(const char *id)
Definition XrdXrootdXeq.cc:3957