XRootD
Loading...
Searching...
No Matches
XrdXrootdXeq.cc
Go to the documentation of this file.
1/******************************************************************************/
2/* */
3/* X r d X r o o t d X e q . c c */
4/* */
5/* (c) 2004 by the Board of Trustees of the Leland Stanford, Jr., University */
6/* Produced by Andrew Hanushevsky for Stanford University under contract */
7/* DE-AC02-76-SFO0515 with the Department of Energy */
8/* */
9/* This file is part of the XRootD software suite. */
10/* */
11/* XRootD is free software: you can redistribute it and/or modify it under */
12/* the terms of the GNU Lesser General Public License as published by the */
13/* Free Software Foundation, either version 3 of the License, or (at your */
14/* option) any later version. */
15/* */
16/* XRootD is distributed in the hope that it will be useful, but WITHOUT */
17/* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or */
18/* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public */
19/* License for more details. */
20/* */
21/* You should have received a copy of the GNU Lesser General Public License */
22/* along with XRootD in a file called COPYING.LESSER (LGPL license) and file */
23/* COPYING (GPL license). If not, see <http://www.gnu.org/licenses/>. */
24/* */
25/* The copyright holder's institutional names and contributor's names may not */
26/* be used to endorse or promote products derived from this software without */
27/* specific prior written permission of the institution or contributor. */
28/******************************************************************************/
29
30#include <cctype>
31#include <cstdio>
32#include <string>
33#include <sys/time.h>
34
36#include "XrdSfs/XrdSfsFlags.hh"
37#include "XrdSys/XrdSysError.hh"
39#include "XrdSys/XrdSysTimer.hh"
40#include "XrdCks/XrdCksData.hh"
41#include "XrdOuc/XrdOucEnv.hh"
42#include "XrdOuc/XrdOucReqID.hh"
43#include "XrdOuc/XrdOucTList.hh"
47#include "XrdOuc/XrdOucUtils.hh"
51#include "XrdSys/XrdSysE2T.hh"
52#include "Xrd/XrdBuffer.hh"
53#include "Xrd/XrdInet.hh"
54#include "Xrd/XrdLinkCtl.hh"
71
72#include "XrdVersion.hh"
73
74#ifndef ENODATA
75#define ENODATA ENOATTR
76#endif
77
78#ifndef ETIME
79#define ETIME ETIMEDOUT
80#endif
81
82/******************************************************************************/
83/* G l o b a l s */
84/******************************************************************************/
85
87
88/******************************************************************************/
89/* L o c a l S t r u c t u r e s */
90/******************************************************************************/
91
93 {unsigned int Sid;
94 int Pid;
95 int FD;
96 unsigned int Inst;
97
100 };
101
102/******************************************************************************/
103/* L o c a l D e f i n e s */
104/******************************************************************************/
105
106namespace
107{
108
109const char *getTime()
110{
111static char buff[16];
112char tuff[8];
113struct timeval tv;
114struct tm *tmp;
115
116 if (gettimeofday(&tv, 0))
117 {perror("gettimeofday");
118 exit(255);
119 }
120 tmp = localtime(&tv.tv_sec);
121 if (!tmp)
122 {perror("localtime");
123 exit(255);
124 }
125 //012345678901234
126 if (strftime(buff, sizeof(buff), "%y%m%d:%H%M%S. ", tmp) <= 0)
127 {errno = EINVAL;
128 perror("strftime");
129 exit(255);
130 }
131
132 snprintf(tuff, sizeof(tuff), "%d", static_cast<int>(tv.tv_usec/100000));
133 buff[14] = tuff[0];
134 return buff;
135}
136
137// comment out genUEID as it is not used
138//
139
140//int genUEID()
141//{
142// static XrdSysMutex ueidMutex;
143// static int ueidVal = 1;
144// AtomicBeg(ueidMutex);
145// int n = AtomicInc(ueidVal);
146// AtomicEnd(ueidMutex);
147// return n;
148//}
149
150// Startup time
151// 012345670123456
152// yymmdd:hhmmss.t
153static const char *startUP = getTime();
154}
155
156/******************************************************************************/
157/* d o _ A u t h */
158/******************************************************************************/
159
160int XrdXrootdProtocol::do_Auth()
161{
163 XrdSecParameters *parm = 0;
165 const char *eText;
166 int rc, n;
167
168// Ignore authenticate requests if security turned off
169//
170 if (!CIA) return Response.Send();
171 cred.size = Request.header.dlen;
172 cred.buffer = argp->buff;
173
174// If we have no auth protocol or the current protocol is being changed by the
175// client (the client can do so at any time), try to get it. Track number of
176// times we got a protocol object as the read count (we will zero it out later).
177// The credtype change check is always done. While the credtype is consistent,
178// not all protocols provided this information in the past. So, old clients will
179// not necessarily be able to switch protocols mid-stream.
180//
181 if (!AuthProt
182 || strncmp(Entity.prot, (const char *)Request.auth.credtype,
183 sizeof(Request.auth.credtype)))
184 {if (AuthProt) AuthProt->Delete();
185 size_t size = sizeof(Request.auth.credtype);
186 strncpy(Entity.prot, (const char *)Request.auth.credtype, size);
187 if (!(AuthProt = CIA->getProtocol(Link->Host(), *(Link->AddrInfo()),
188 &cred, eMsg)))
189 {eText = eMsg.getErrText(rc);
190 eDest.Emsg("Xeq", "User authentication failed;", eText);
191 return Response.Send(kXR_AuthFailed, eText);
192 }
194 numReads++;
195 }
196
197// Now try to authenticate the client using the current protocol
198//
199 if (!(rc = AuthProt->Authenticate(&cred, &parm, &eMsg))
201 {rc = Response.Send(); Status &= ~XRD_NEED_AUTH; SI->Bump(SI->LoginAU);
203 Client = &AuthProt->Entity; numReads = 0; strcpy(Entity.prot, "host");
206 if (Monitor.Logins() && Monitor.Auths()) MonAuth();
207 if (!logLogin(true)) return -1;
208 return rc;
209 }
210
211// If we need to continue authentication, tell the client as much
212//
213 if (rc > 0)
214 {TRACEP(LOGIN, "more auth requested; sz=" <<(parm ? parm->size : 0));
215 if (parm) {rc = Response.Send(kXR_authmore, parm->buffer, parm->size);
216 delete parm;
217 return rc;
218 }
219 eDest.Emsg("Xeq", "Security requested additional auth w/o parms!");
220 return Response.Send(kXR_ServerError,"invalid authentication exchange");
221 }
222
223// Authentication failed. We will delete the authentication object and zero
224// out the pointer. We can do this without any locks because this section is
225// single threaded relative to a connection. To prevent guessing attacks, we
226// wait a variable amount of time if there have been 3 or more tries.
227//
228 if (AuthProt) {AuthProt->Delete(); AuthProt = 0;}
229 if ((n = numReads - 2) > 0) XrdSysTimer::Snooze(n > 5 ? 5 : n);
230
231// We got an error, bail out.
232//
233 SI->Bump(SI->AuthBad);
234 eText = eMsg.getErrText(rc);
235 eDest.Emsg("Xeq", "User authentication failed;", eText);
236 return Response.Send(kXR_AuthFailed, eText);
237}
238
239/******************************************************************************/
240/* d o _ B i n d */
241/******************************************************************************/
242
243int XrdXrootdProtocol::do_Bind()
244{
247 XrdLink *lp;
248 int i, pPid, rc;
249 char buff[64], *cp, *dp;
250
251// Update misc stats count
252//
253 SI->Bump(SI->miscCnt);
254
255// Check if binds need to occur on a TLS connection.
256//
257 if ((doTLS & Req_TLSData) && !isTLS && !Link->hasBridge())
258 return Response.Send(kXR_TLSRequired, "bind requires TLS");
259
260// Find the link we are to bind to
261//
262 if (sp->FD <= 0 || !(lp = XrdLinkCtl::fd2link(sp->FD, sp->Inst)))
263 return Response.Send(kXR_NotFound, "session not found");
264
265// The link may have escaped so we need to hold this link and try again
266//
267 lp->Hold(1);
268 if (lp != XrdLinkCtl::fd2link(sp->FD, sp->Inst))
269 {lp->Hold(0);
270 return Response.Send(kXR_NotFound, "session just closed");
271 }
272
273// Get the protocol associated with the link
274//
275 if (!(pp=dynamic_cast<XrdXrootdProtocol *>(lp->getProtocol()))||lp != pp->Link)
276 {lp->Hold(0);
277 return Response.Send(kXR_ArgInvalid, "session protocol not xroot");
278 }
279
280// Verify that the parent protocol is fully logged in
281//
282 if (!(pp->Status & XRD_LOGGEDIN) || (pp->Status & XRD_NEED_AUTH))
283 {lp->Hold(0);
284 return Response.Send(kXR_ArgInvalid, "session not logged in");
285 }
286
287// Verify that the bind is valid for the requestor
288//
289 if (sp->Pid != myPID || sp->Sid != pp->mySID)
290 {lp->Hold(0);
291 return Response.Send(kXR_ArgInvalid, "invalid session ID");
292 }
293
294// For now, verify that the request is comming from the same host
295//
296 if (strcmp(Link->Host(), lp->Host()))
297 {lp->Hold(0);
298 return Response.Send(kXR_NotAuthorized, "cross-host bind not allowed");
299 }
300
301// We need to hold the parent's stream mutex to prevent inspection or
302// modification of other parallel binds that may occur
303//
304 XrdSysMutexHelper smHelper(pp->streamMutex);
305
306// Find a slot for this path in parent protocol
307//
308 for (i = 1; i < maxStreams && pp->Stream[i]; i++) {}
309 if (i >= maxStreams)
310 {lp->Hold(0);
311 return Response.Send(kXR_NoMemory, "bind limit exceeded");
312 }
313
314// Link this protocol to the parent
315//
316 pp->Stream[i] = this;
317 Stream[0] = pp;
318 PathID = i;
319
320// Construct a login name for this bind session
321//
322 cp = strdup(lp->ID);
323 if ( (dp = rindex(cp, '@'))) *dp = '\0';
324 if (!(dp = rindex(cp, '.'))) pPid = 0;
325 else {*dp++ = '\0'; pPid = strtol(dp, (char **)NULL, 10);}
326 Link->setID(cp, pPid);
327 free(cp);
328 CapVer = pp->CapVer;
330 clientPV = pp->clientPV;
331
332// Check if we need to enable packet marking for this stream
333//
334 if (pp->pmDone)
335 {pmDone = true;
336 if (pp->pmHandle) pmHandle = PMark->Begin(*(Link->AddrInfo()),
337 *(pp->pmHandle), Link->ID);
338 }
339
340// Document the bind
341//
342 smHelper.UnLock();
343 sprintf(buff, "FD %d#%d bound", Link->FDnum(), i);
344 eDest.Log(SYS_LOG_01, "Xeq", buff, lp->ID);
345
346// Get the required number of parallel I/O objects
347//
349
350// There are no errors possible at this point unless the response fails
351//
352 buff[0] = static_cast<char>(i);
353 if (!(rc = Response.Send(kXR_ok, buff, 1))) rc = -EINPROGRESS;
354
355// Return but keep the link disabled
356//
357 lp->Hold(0);
358 return rc;
359}
360
361/******************************************************************************/
362/* d o _ C h k P n t */
363/* */
364/* Resides in XrdXrootdXeqChkPnt.cc */
365/******************************************************************************/
366
367/******************************************************************************/
368/* d o _ c h m o d */
369/******************************************************************************/
370
371int XrdXrootdProtocol::do_Chmod()
372{
373 int mode, rc;
374 char *opaque;
376
377// Check for static routing
378//
379 STATIC_REDIRECT(RD_chmod);
380
381// Unmarshall the data
382//
383 mode = mapMode((int)ntohs(Request.chmod.mode));
384 if (rpCheck(argp->buff, &opaque)) return rpEmsg("Modifying", argp->buff);
385 if (!Squash(argp->buff)) return vpEmsg("Modifying", argp->buff);
386
387// Preform the actual function
388//
389 rc = osFS->chmod(argp->buff, (XrdSfsMode)mode, myError, CRED, opaque);
390 TRACEP(FS, "chmod rc=" <<rc <<" mode=" <<Xrd::oct1 <<mode <<' ' <<argp->buff);
391 if (SFS_OK == rc) return Response.Send();
392
393// An error occurred
394//
395 return fsError(rc, XROOTD_MON_CHMOD, myError, argp->buff, opaque);
396}
397
398/******************************************************************************/
399/* d o _ C K s u m */
400/******************************************************************************/
401
402int XrdXrootdProtocol::do_CKsum(int canit)
403{
404 char *opaque;
405 char *algT = JobCKT, *args[6];
406 int rc;
407
408// Check for static routing
409//
410 STATIC_REDIRECT(RD_chksum);
411
412// Check if we support this operation
413//
414 if (!JobCKT || (!JobLCL && !JobCKS))
415 return Response.Send(kXR_Unsupported, "query chksum is not supported");
416
417// Prescreen the path
418//
419 if (rpCheck(argp->buff, &opaque)) return rpEmsg("Check summing", argp->buff);
420 if (!Squash(argp->buff)) return vpEmsg("Check summing", argp->buff);
421
422// If this is a cancel request, do it now
423//
424 if (canit)
426 return Response.Send();
427 }
428
429// Check if multiple checksums are supported and if so, pre-process
430//
431 if (JobCKCGI && opaque && *opaque)
432 {char cksT[64];
433 algT = getCksType(opaque, cksT, sizeof(cksT));
434 if (!algT)
435 {char ebuf[1024];
436 snprintf(ebuf, sizeof(ebuf), "%s checksum not supported.", cksT);
437 return Response.Send(kXR_ServerError, ebuf);
438 }
439 }
440
441// If we are allowed to locally query the checksum to avoid computation, do it
442//
443 if (JobLCL && (rc = do_CKsum(algT, argp->buff, opaque)) <= 0) return rc;
444
445// Just make absolutely sure we can continue with a calculation
446//
447 if (!JobCKS)
448 return Response.Send(kXR_ServerError, "Logic error computing checksum.");
449
450// Check if multiple checksums are supported and construct right argument list
451// We make a concession to a wrongly placed setfsuid/gid plugin. Fortunately,
452// it only needs to know user's name but that can come from another plugin.
453//
454 std::string keyval; // Contents will be copied prior to return!
455 if (JobCKCGI > 1 || JobLCL)
456 {args[0] = algT;
457 args[1] = algT;
458 args[2] = argp->buff;
459 args[3] = const_cast<char *>(Client->tident);
460 if (Client->eaAPI->Get(std::string("request.name"), keyval) && !keyval.empty())
461 args[4] = const_cast<char *>(keyval.c_str());
462 else if (Client->name) args[4] = Client->name;
463 else args[4] = 0;
464 args[5] = 0;
465 } else {
466 args[0] = algT;
467 args[1] = argp->buff;
468 args[2] = 0;
469 }
470
471// Preform the actual function
472//
473 return JobCKS->Schedule(argp->buff, (const char **)args, &Response,
474 ((CapVer & kXR_vermask) >= kXR_ver002 ? 0 : JOB_Sync));
475}
476
477/******************************************************************************/
478
479int XrdXrootdProtocol::do_CKsum(char *algT, const char *Path, char *Opaque)
480{
481 static char Space = ' ';
483 int CKTLen = strlen(algT);
484 int ec, rc = osFS->chksum(XrdSfsFileSystem::csGet, algT, Path,
485 myError, CRED, Opaque);
486 const char *csData = myError.getErrText(ec);
487
488// Diagnose any hard errors
489//
490 if (rc) return fsError(rc, 0, myError, Path, Opaque);
491
492// Return result if it is actually available
493//
494 if (*csData)
495 {if (*csData == '!') return Response.Send(csData+1);
496 struct iovec iov[4] = {{0,0}, {algT, (size_t)CKTLen}, {&Space, 1},
497 {(char *)csData, strlen(csData)+1}};
498 return Response.Send(iov, 4);
499 }
500
501// Diagnose soft errors
502//
503 if (!JobCKS)
504 {const char *eTxt[2] = {JobCKT, " checksum not available."};
505 myError.setErrInfo(0, eTxt, 2);
506 return Response.Send(kXR_ChkSumErr, myError.getErrText());
507 }
508
509// Return indicating that we should try calculating the checksum
510//
511 return 1;
512}
513
514/******************************************************************************/
515/* d o _ C l o s e */
516/******************************************************************************/
517
518int XrdXrootdProtocol::do_Close()
519{
520 static XrdXrootdCallBack closeCB("close", XROOTD_MON_CLOSE);
521 XrdXrootdFile *fp;
523 int rc;
524 bool doDel = true;
525
526// Keep statistics
527//
528 SI->Bump(SI->miscCnt);
529
530// Find the file object
531//
532 if (!FTab || !(fp = FTab->Get(fh.handle)))
534 "close does not refer to an open file");
535
536// Serialize the file to make sure all references due to async I/O and parallel
537// stream operations have completed.
538//
539 fp->Serialize();
540
541// If the file has a fob then it was subject to pgwrite and if uncorrected
542// checksum errors exist do a forced close. This will trigger POSC or a restore.
543//
544 if (fp->pgwFob && !do_PgClose(fp, rc))
545 {FTab->Del((Monitor.Files() ? Monitor.Agent : 0), fh.handle, true);
546 numFiles--;
547 return rc;
548 }
549
550// Setup the callback to allow close() to return SFS_STARTED so we can defer
551// the response to the close request as it may be a lengthy operation. In
552// this case the argument is the actual file pointer and the link reference
553// is recorded in the file object.
554//
555 fp->cbArg = ReqID.getID();
556 fp->XrdSfsp->error.setErrCB(&closeCB, (unsigned long long)fp);
557
558// Add a reference count to the file in case the close will be deferred. In
559// the deferred case the reference is used to prevent the callback from
560// deleting the file until we have done necessary processing of the object
561// during its removal from the open table.
562//
563 fp->Ref(1);
564
565// Do an explicit close of the file here; check for exceptions. Stall requests
566// leave the file open as there will be a retry. Otherwise, we remove the
567// file from our open table but a "started" return defers the the delete.
568//
569 rc = fp->XrdSfsp->close();
570 TRACEP(FS, " fh=" <<fh.handle <<" close rc=" <<rc);
571 if (rc == SFS_STARTED) doDel = false;
572 else {fp->Ref(-1);
573 if (rc >= SFS_STALL)
574 return fsError(rc, 0, fp->XrdSfsp->error, 0, 0);
575 }
576
577// Before we potentially delete the file handle in FTab->Del, generate the
578// appropriate error code (if necessary). Note that we delay the call
579// to Response.Send() in the successful case to avoid holding on to the lock
580// while the response is sent.
581//
582 int retval = 0;
583 if (SFS_OK != rc) retval = fsError(rc, 0, fp->XrdSfsp->error, 0, 0);
584
585// Delete the file from the file table. If the file object is deleted then it
586// will unlock the file In all cases, final monitoring records will be produced.
587//
588 FTab->Del((Monitor.Files() ? Monitor.Agent : 0), fh.handle, doDel);
589 numFiles--;
590 if (!doDel) fp->Ref(-1);
591
592// Send back the right response
593//
594 if (SFS_OK == rc) return Response.Send();
595 return retval;
596}
597
598/******************************************************************************/
599/* d o _ D i r l i s t */
600/******************************************************************************/
601
602int XrdXrootdProtocol::do_Dirlist()
603{
604 int bleft, rc = 0, dlen, cnt = 0;
605 char *opaque, *buff, ebuff[4096];
606 const char *dname;
607 XrdSfsDirectory *dp;
608 bool doDig;
609
610// Check if we are digging for data
611//
612 doDig = (digFS && SFS_LCLROOT(argp->buff));
613
614// Check for static routing
615//
616 if (!doDig) {STATIC_REDIRECT(RD_dirlist);}
617
618// Prescreen the path
619//
620 if (rpCheck(argp->buff, &opaque)) return rpEmsg("Listing", argp->buff);
621 if (!doDig && !Squash(argp->buff))return vpEmsg("Listing", argp->buff);
622
623// Get a directory object
624//
625 if (doDig) dp = digFS->newDir(Link->ID, Monitor.Did);
626 else dp = osFS->newDir(Link->ID, Monitor.Did);
627
628// Make sure we have the object
629//
630 if (!dp)
631 {snprintf(ebuff,sizeof(ebuff)-1,"Insufficient memory to open %s",argp->buff);
632 eDest.Emsg("Xeq", ebuff);
633 return Response.Send(kXR_NoMemory, ebuff);
634 }
635
636// First open the directory
637//
639 if ((rc = dp->open(argp->buff, CRED, opaque)))
640 {rc = fsError(rc, XROOTD_MON_OPENDIR, dp->error, argp->buff, opaque);
641 delete dp;
642 return rc;
643 }
644
645// Check if the caller wants stat information as well
646//
648 return do_DirStat(dp, ebuff, opaque);
649
650// Start retreiving each entry and place in a local buffer with a trailing new
651// line character (the last entry will have a null byte). If we cannot fit a
652// full entry in the buffer, send what we have with an OKSOFAR and continue.
653// This code depends on the fact that a directory entry will never be longer
654// than sizeof( ebuff)-1; otherwise, an infinite loop will result. No errors
655// are allowed to be reflected at this point.
656//
657 dname = 0;
658 do {buff = ebuff; bleft = sizeof(ebuff);
659 while(dname || (dname = dp->nextEntry()))
660 {dlen = strlen(dname);
661 if (dlen > 2 || dname[0] != '.' || (dlen == 2 && dname[1] != '.'))
662 {if ((bleft -= (dlen+1)) < 0) break;
663 strcpy(buff, dname); buff += dlen; *buff = '\n'; buff++; cnt++;
664 }
665 dname = 0;
666 }
667 if (dname) rc = Response.Send(kXR_oksofar, ebuff, buff-ebuff);
668 } while(!rc && dname);
669
670// Send the ending packet if we actually have one to send
671//
672 if (!rc)
673 {if (ebuff == buff) rc = Response.Send();
674 else {*(buff-1) = '\0';
675 rc = Response.Send((void *)ebuff, buff-ebuff);
676 }
677 }
678
679// Close the directory
680//
681 dp->close();
682 delete dp;
683 if (!rc) {TRACEP(FS, "dirlist entries=" <<cnt <<" path=" <<argp->buff);}
684 return rc;
685}
686
687/******************************************************************************/
688/* d o _ D i r S t a t */
689/******************************************************************************/
690
691int XrdXrootdProtocol::do_DirStat(XrdSfsDirectory *dp, char *pbuff,
692 char *opaque)
693{
695 struct stat Stat;
696 char *buff, *dLoc, *algT = 0;
697 const char *csData, *dname;
698 int bleft, rc = 0, dlen, cnt = 0, statSz = 160;
699 bool manStat;
700 struct {char ebuff[8192]; char epad[512];} XB;
701
702// Preprocess checksum request. If we don't support checksums or if the
703// requested checksum type is not supported, ignore it.
704//
705 if ((Request.dirlist.options[0] & kXR_dcksm) && JobLCL)
706 {char cksT[64];
707 algT = getCksType(opaque, cksT, sizeof(cksT));
708 if (!algT)
709 {char ebuf[1024];
710 snprintf(ebuf, sizeof(ebuf), "%s checksum not supported.", cksT);
711 return Response.Send(kXR_ServerError, ebuf);
712 }
713 statSz += XrdCksData::NameSize + (XrdCksData::ValuSize*2) + 8;
714 }
715
716// We always return stat information, see if we can use autostat
717//
718 manStat = (dp->autoStat(&Stat) != SFS_OK);
719
720// Construct the path to the directory as we will be asking for stat calls
721// if the interface does not support autostat or returning checksums.
722//
723 if (manStat || algT)
724 {strcpy(pbuff, argp->buff);
725 dlen = strlen(pbuff);
726 if (pbuff[dlen-1] != '/') {pbuff[dlen] = '/'; dlen++;}
727 dLoc = pbuff+dlen;
728 } else dLoc = 0;
729
730// The initial leadin is a "dot" entry to indicate to the client that we
731// support the dstat option (older servers will not do that). It's up to the
732// client to issue individual stat requests in that case.
733//
734 memset(&Stat, 0, sizeof(Stat));
735 strcpy(XB.ebuff, ".\n0 0 0 0\n");
736 buff = XB.ebuff+10; bleft = sizeof(XB.ebuff)-10;
737
738// Start retreiving each entry and place in a local buffer with a trailing new
739// line character (the last entry will have a null byte). If we cannot fit a
740// full entry in the buffer, send what we have with an OKSOFAR and continue.
741// This code depends on the fact that a directory entry will never be longer
742// than sizeof( ebuff)-1; otherwise, an infinite loop will result. No errors
743// are allowed to be reflected at this point.
744//
745 dname = 0;
746 do {while(dname || (dname = dp->nextEntry()))
747 {dlen = strlen(dname);
748 if (dlen > 2 || dname[0] != '.' || (dlen == 2 && dname[1] != '.'))
749 {if ((bleft -= (dlen+1)) < 0 || bleft < statSz) break;
750 if (dLoc) strcpy(dLoc, dname);
751 if (manStat)
752 {rc = osFS->stat(pbuff, &Stat, myError, CRED, opaque);
753 if (rc == SFS_ERROR && myError.getErrInfo() == ENOENT)
754 {dname = 0; continue;}
755 if (rc != SFS_OK)
756 return fsError(rc, XROOTD_MON_STAT, myError,
757 argp->buff, opaque);
758 }
759 strcpy(buff, dname); buff += dlen; *buff = '\n'; buff++; cnt++;
760 dlen = StatGen(Stat, buff, sizeof(XB.epad));
761 bleft -= dlen; buff += (dlen-1);
762 if (algT)
764 pbuff, myError, CRED, opaque);
765 csData = myError.getErrText();
766 if (ec != SFS_OK || !(*csData) || *csData == '!')
767 csData = "none";
768 int n = snprintf(buff,sizeof(XB.epad)," [ %s:%s ]",
769 algT, csData);
770 buff += n; bleft -= n;
771 }
772 *buff = '\n'; buff++;
773 }
774 dname = 0;
775 }
776 if (dname)
777 {rc = Response.Send(kXR_oksofar, XB.ebuff, buff-XB.ebuff);
778 buff = XB.ebuff; bleft = sizeof(XB.ebuff);
779 TRACEP(FS, "dirstat sofar n=" <<cnt <<" path=" <<argp->buff);
780 }
781 } while(!rc && dname);
782
783// Send the ending packet if we actually have one to send
784//
785 if (!rc)
786 {if (XB.ebuff == buff) rc = Response.Send();
787 else {*(buff-1) = '\0';
788 rc = Response.Send((void *)XB.ebuff, buff-XB.ebuff);
789 }
790 }
791
792// Close the directory
793//
794 dp->close();
795 delete dp;
796 if (!rc) {TRACEP(FS, "dirstat entries=" <<cnt <<" path=" <<argp->buff);}
797 return rc;
798}
799
800/******************************************************************************/
801/* d o _ E n d s e s s */
802/******************************************************************************/
803
804int XrdXrootdProtocol::do_Endsess()
805{
806 XrdXrootdSessID *sp, sessID;
807 int rc;
808
809// Update misc stats count
810//
811 SI->Bump(SI->miscCnt);
812
813// Extract out the FD and Instance from the session ID
814//
816 memcpy((void *)&sessID.Pid, &sp->Pid, sizeof(sessID.Pid));
817 memcpy((void *)&sessID.FD, &sp->FD, sizeof(sessID.FD));
818 memcpy((void *)&sessID.Inst, &sp->Inst, sizeof(sessID.Inst));
819
820// Trace this request
821//
822 TRACEP(LOGIN, "endsess " <<sessID.Pid <<':' <<sessID.FD <<'.' <<sessID.Inst);
823
824// If this session id does not refer to us, ignore the request
825//
826 if (sessID.Pid != myPID) return Response.Send();
827
828// Terminate the indicated session, if possible. This could also be a self-termination.
829//
830 if ((sessID.FD == 0 && sessID.Inst == 0)
831 || !(rc = Link->Terminate(0, sessID.FD, sessID.Inst))) return -1;
832
833// Trace this request
834//
835 TRACEP(LOGIN, "endsess " <<sessID.Pid <<':' <<sessID.FD <<'.' <<sessID.Inst
836 <<" rc=" <<rc <<" (" <<XrdSysE2T(rc < 0 ? -rc : EAGAIN) <<")");
837
838// Return result. We only return obvious problems (exclude ESRCH and EPIPE).
839//
840 if (rc > 0)
841 return (rc = Response.Send(kXR_wait, rc, "session still active")) ? rc:1;
842
843 if (rc == -EACCES)return Response.Send(kXR_NotAuthorized, "not session owner");
844 if (rc == -ETIME) return Response.Send(kXR_Cancelled,"session not ended");
845
846 return Response.Send();
847}
848
849/******************************************************************************/
850/* d o _ F A t t r */
851/* */
852/* Resides in XrdXrootdXeqFAttr.cc */
853/******************************************************************************/
854
855/******************************************************************************/
856/* d o _ g p F i l e */
857/******************************************************************************/
858
859int XrdXrootdProtocol::do_gpFile()
860{
861// int gopts, buffsz;
862
863// Keep Statistics (TO DO: differentiate get vs put)
864//
865 SI->Bump(SI->getfCnt);
866// SI->Bump(SI->putfCnt);
867
868// Check if gpfile need to occur on a TLS connection
869//
870 if ((doTLS & Req_TLSGPFile) && !isTLS && !Link->hasBridge())
871 return Response.Send(kXR_TLSRequired, "gpfile requires TLS");
872
873 return Response.Send(kXR_Unsupported, "gpfile request is not supported");
874}
875
876/******************************************************************************/
877/* d o _ L o c a t e */
878/******************************************************************************/
879
880int XrdXrootdProtocol::do_Locate()
881{
882 static XrdXrootdCallBack locCB("locate", XROOTD_MON_LOCATE);
883 int rc, opts, fsctl_cmd = SFS_FSCTL_LOCATE;
884 char *opaque = 0, *Path, *fn = argp->buff, opt[8], *op=opt;
885 XrdOucErrInfo myError(Link->ID,&locCB,ReqID.getID(),Monitor.Did,clientPV);
886 bool doDig = false;
887
888// Unmarshall the data
889//
890 opts = (int)ntohs(Request.locate.options);
891
892// Map the options
893//
894 if (opts & kXR_nowait) {fsctl_cmd |= SFS_O_NOWAIT; *op++ = 'i';}
895 if (opts & kXR_refresh) {fsctl_cmd |= SFS_O_RESET; *op++ = 's';}
896 if (opts & kXR_force ) {fsctl_cmd |= SFS_O_FORCE; *op++ = 'f';}
897 if (opts & kXR_prefname){fsctl_cmd |= SFS_O_HNAME; *op++ = 'n';}
898 if (opts & kXR_compress){fsctl_cmd |= SFS_O_RAWIO; *op++ = 'u';}
899 if (opts & kXR_4dirlist){fsctl_cmd |= SFS_O_DIRLIST;*op++ = 'D';}
900 *op = '\0';
901 TRACEP(FS, "locate " <<opt <<' ' <<fn);
902
903// Check if this is a non-specific locate
904//
905 if (*fn != '*'){Path = fn;
906 doDig = (digFS && SFS_LCLROOT(Path));
907 }
908 else if (*(fn+1)) {Path = fn+1;
909 doDig = (digFS && SFS_LCLROOT(Path));
910 }
911 else {Path = 0;
912 fn = XPList.Next()->Path();
913 fsctl_cmd |= SFS_O_TRUNC;
914 }
915
916// Check for static routing
917//
918 if (!doDig) {STATIC_REDIRECT(RD_locate);}
919
920// Prescreen the path
921//
922 if (Path)
923 {if (rpCheck(Path, &opaque)) return rpEmsg("Locating", Path);
924 if (!doDig && !Squash(Path))return vpEmsg("Locating", Path);
925 }
926
927// Preform the actual function. For regular Fs add back any opaque info
928//
929 if (doDig) rc = digFS->fsctl(fsctl_cmd, fn, myError, CRED);
930 else {if (opaque)
931 {int n = strlen(argp->buff); argp->buff[n] = '?';
932 if ((argp->buff)+n != opaque-1)
933 memmove(&argp->buff[n+1], opaque, strlen(opaque)+1);
934 }
935 rc = osFS->fsctl(fsctl_cmd, fn, myError, CRED);
936 }
937 TRACEP(FS, "rc=" <<rc <<" locate " <<fn);
938 return fsError(rc, (doDig ? 0 : XROOTD_MON_LOCATE), myError, Path, opaque);
939}
940
941/******************************************************************************/
942/* d o _ L o g i n */
943/*.x***************************************************************************/
944
945int XrdXrootdProtocol::do_Login()
946{
947 XrdXrootdSessID sessID;
948 XrdNetAddrInfo *addrP;
949 int i, pid, rc, sendSID = 0;
950 char uname[sizeof(Request.login.username)+1];
951
952// Keep Statistics
953//
954 SI->Bump(SI->LoginAT);
955
956// Check if login need to occur on a TLS connection
957//
958 if ((doTLS & Req_TLSLogin) && !isTLS && !Link->hasBridge())
959 {const char *emsg = "login requires TLS be enabled";
960 if (!ableTLS)
961 {emsg = "login requires TLS support";
962 eDest.Emsg("Xeq","login requires TLS but",Link->ID,"is incapable.");
963 }
965 }
966
967// Unmarshall the pid and construct username using the POSIX.1-2008 standard
968//
969 pid = (int)ntohl(Request.login.pid);
970 strncpy(uname, (const char *)Request.login.username, sizeof(uname)-1);
971 uname[sizeof(uname)-1] = 0;
973
974// Make sure the user is not already logged in
975//
977 "duplicate login; already logged in");
978
979// Establish the ID for this link
980//
981 Link->setID(uname, pid);
983
984// Establish the session ID if the client can handle it (protocol version > 0)
985//
986 if ((i = (CapVer & kXR_vermask)))
987 {sessID.FD = Link->FDnum();
988 sessID.Inst = Link->Inst();
989 sessID.Pid = myPID;
990 mySID = getSID();
991 sessID.Sid = mySID;
992 sendSID = 1;
993 if (!clientPV)
994 { if (i >= kXR_ver004) clientPV = (int)0x0310;
995 else if (i == kXR_ver003) clientPV = (int)0x0300;
996 else if (i == kXR_ver002) clientPV = (int)0x0290;
997 else if (i == kXR_ver001) clientPV = (int)0x0200;
998 else clientPV = (int)0x0100;
999 }
1015 }
1016
1017// Mark the client as IPv4 if they came in as IPv4 or mapped IPv4 we can only
1018// return IPv4 addresses. Of course, if the client is dual-stacked then we
1019// simply indicate the client can accept either (the client better be honest).
1020//
1021 addrP = Link->AddrInfo();
1022 if (addrP->isIPType(XrdNetAddrInfo::IPv4) || addrP->isMapped())
1024// WORKAROUND: XrdCl 4.0.x often identifies worker nodes as being IPv6-only.
1025// Rather than breaking a significant number of our dual-stack workers, we
1026// automatically denote IPv6 connections as also supporting IPv4 - regardless
1027// of what the remote client claims. This was fixed in 4.3.x but we can't
1028// tell release differences until 4.5 when we can safely ignore this as we
1029// also don't want to misidentify IPv6-only clients either.
1030 else if (i < kXR_ver004 && XrdInet::GetAssumeV4())
1032
1033// Mark the client as being on a private net if the address is private
1034//
1035 if (addrP->isPrivate()) {clientPV |= XrdOucEI::uPrip; rdType = 1;}
1036 else rdType = 0;
1037
1038// Get the security token for this link. We will either get a token, a null
1039// string indicating host-only authentication, or a null indicating no
1040// authentication. We can then optimize of each case.
1041//
1042 if (CIA)
1043 {const char *pp=CIA->getParms(i, Link->AddrInfo());
1044 if (pp && i ) {if (!sendSID) rc = Response.Send((void *)pp, i);
1045 else {struct iovec iov[3];
1046 iov[1].iov_base = (char *)&sessID;
1047 iov[1].iov_len = sizeof(sessID);
1048 iov[2].iov_base = (char *)pp;
1049 iov[2].iov_len = i;
1050 rc = Response.Send(iov,3,int(i+sizeof(sessID)));
1051 }
1053 }
1054 else {rc = (sendSID ? Response.Send((void *)&sessID, sizeof(sessID))
1055 : Response.Send());
1057 }
1058 }
1059 else {rc = (sendSID ? Response.Send((void *)&sessID, sizeof(sessID))
1060 : Response.Send());
1062 }
1063
1064// We always allow at least host-based authentication. This may be over-ridden
1065// should strong authentication be enabled. Allocation of the protocol object
1066// already supplied the protocol name and the host name. We supply the tident
1067// and the connection details in addrInfo.
1068//
1071 Client = &Entity;
1072
1073// Check if we need to process a login environment
1074//
1075 if (Request.login.dlen > 8)
1076 {XrdOucEnv loginEnv(argp->buff+1, Request.login.dlen-1);
1077 char *rnumb = loginEnv.Get("xrd.rn");
1078 char *cCode = loginEnv.Get("xrd.cc");
1079 char *tzVal = loginEnv.Get("xrd.tz");
1080 char *appXQ = loginEnv.Get("xrd.appname");
1081 char *aInfo = loginEnv.Get("xrd.info");
1082 int tzNum = (tzVal ? atoi(tzVal) : 0);
1083 if (cCode && *cCode && tzNum >= -12 && tzNum <= 14)
1084 {XrdNetAddrInfo::LocInfo locInfo;
1085 locInfo.Country[0] = cCode[0]; locInfo.Country[1] = cCode[1];
1086 locInfo.TimeZone = tzNum & 0xff;
1087 Link->setLocation(locInfo);
1088 }
1089 if (Monitor.Ready() && (appXQ || aInfo))
1090 {char apBuff[1024];
1091 snprintf(apBuff, sizeof(apBuff), "&R=%s&x=%s&y=%s&I=%c",
1092 (rnumb ? rnumb : ""),
1093 (appXQ ? appXQ : ""), (aInfo ? aInfo : ""),
1094 (clientPV & XrdOucEI::uIPv4 ? '4' : '6'));
1095 Entity.moninfo = strdup(apBuff);
1096 }
1097
1098 if (rnumb)
1099 {int majr, minr, pchr;
1100 if (sscanf(rnumb, "v%d.%d.%d", &majr, &minr, &pchr) == 3)
1101 clientRN = (majr<<16) | ((minr<<8) | pchr);
1102 else if (sscanf(rnumb, "v%d-%*x", &majr) == 1) clientRN = -1;
1103 }
1104 if (appXQ) AppName = strdup(appXQ);
1105 }
1106
1107// Allocate a monitoring object, if needed for this connection
1108//
1109 if (Monitor.Ready())
1110 {Monitor.Register(Link->ID, Link->Host(), "xroot", mySID);
1111 if (Monitor.Logins() && (!Monitor.Auths() || !(Status & XRD_NEED_AUTH)))
1113 if (Entity.moninfo) {free(Entity.moninfo); Entity.moninfo = 0;}
1115 }
1116 }
1117
1118// Complete the rquestID object
1119//
1121
1122// Document this login
1123//
1124 if (!(Status & XRD_NEED_AUTH) && !logLogin()) return -1;
1125 return rc;
1126}
1127
1128/******************************************************************************/
1129/* d o _ M k d i r */
1130/******************************************************************************/
1131
1132int XrdXrootdProtocol::do_Mkdir()
1133{
1134 int mode, rc;
1135 char *opaque;
1137
1138// Check for static routing
1139//
1140 STATIC_REDIRECT(RD_mkdir);
1141
1142// Unmarshall the data
1143//
1144 mode = mapMode((int)ntohs(Request.mkdir.mode)) | S_IRWXU;
1145 if (Request.mkdir.options[0] & static_cast<unsigned char>(kXR_mkdirpath))
1146 mode |= SFS_O_MKPTH;
1147 if (rpCheck(argp->buff, &opaque)) return rpEmsg("Creating", argp->buff);
1148 if (!Squash(argp->buff)) return vpEmsg("Creating", argp->buff);
1149
1150// Preform the actual function
1151//
1152 rc = osFS->mkdir(argp->buff, (XrdSfsMode)mode, myError, CRED, opaque);
1153 TRACEP(FS, "rc=" <<rc <<" mkdir " <<Xrd::oct1 <<mode <<' ' <<argp->buff);
1154 if (SFS_OK == rc) return Response.Send();
1155
1156// An error occurred
1157//
1158 return fsError(rc, XROOTD_MON_MKDIR, myError, argp->buff, opaque);
1159}
1160
1161/******************************************************************************/
1162/* d o _ M v */
1163/******************************************************************************/
1164
1165int XrdXrootdProtocol::do_Mv()
1166{
1167 int rc;
1168 char *oldp, *newp, *Opaque, *Npaque;
1170
1171// Check for static routing
1172//
1173 STATIC_REDIRECT(RD_mv);
1174
1175// Find the space separator between the old and new paths
1176//
1177 oldp = newp = argp->buff;
1178 if (Request.mv.arg1len)
1179 {int n = ntohs(Request.mv.arg1len);
1180 if (n < 0 || n >= Request.mv.dlen || *(argp->buff+n) != ' ')
1181 return Response.Send(kXR_ArgInvalid, "invalid path specification");
1182 *(oldp+n) = 0;
1183 newp += n+1;
1184 } else {
1185 while(*newp && *newp != ' ') newp++;
1186 if (*newp) {*newp = '\0'; newp++;
1187 while(*newp && *newp == ' ') newp++;
1188 }
1189 }
1190
1191// Get rid of relative paths and multiple slashes
1192//
1193 if (rpCheck(oldp, &Opaque)) return rpEmsg("Renaming", oldp);
1194 if (rpCheck(newp, &Npaque)) return rpEmsg("Renaming to", newp);
1195 if (!Squash(oldp)) return vpEmsg("Renaming", oldp);
1196 if (!Squash(newp)) return vpEmsg("Renaming to", newp);
1197
1198// Check if new path actually specified here
1199//
1200 if (*newp == '\0')
1201 Response.Send(kXR_ArgMissing, "new path specified for mv");
1202
1203// Preform the actual function
1204//
1205 rc = osFS->rename(oldp, newp, myError, CRED, Opaque, Npaque);
1206 TRACEP(FS, "rc=" <<rc <<" mv " <<oldp <<' ' <<newp);
1207 if (SFS_OK == rc) return Response.Send();
1208
1209// An error occurred
1210//
1211 return fsError(rc, XROOTD_MON_MV, myError, oldp, Opaque);
1212}
1213
1214/******************************************************************************/
1215/* d o _ O f f l o a d */
1216/******************************************************************************/
1217
1218int XrdXrootdProtocol::do_Offload(int (XrdXrootdProtocol::*Invoke)(),int pathID)
1219{
1220 XrdSysSemaphore isAvail(0);
1222 XrdXrootdPio *pioP;
1223 int rc;
1224 kXR_char streamID[2];
1225
1226// Verify that the path actually exists (note we will have the stream lock)
1227//
1228 if (!(pp = VerifyStream(rc, pathID))) return rc;
1229
1230// Grab the stream ID
1231//
1232 Response.StreamID(streamID);
1233
1234// Try to schedule this operation. In order to maximize the I/O overlap, we
1235// will wait until the stream gets control and will have a chance to start
1236// reading from the network. We handle refs for consistency.
1237//
1238 do{if (!pp->isActive)
1239 {pp->IO = IO;
1240 pp->myBlen = 0;
1241 pp->Resume = &XrdXrootdProtocol::do_OffloadIO;
1242 pp->ResumePio= Invoke;
1243 pp->isActive = true;
1244 pp->newPio = true;
1245 pp->reTry = &isAvail;
1246 pp->Response.Set(streamID);
1247 pp->streamMutex.UnLock();
1248 Link->setRef(1);
1249 IO.File->Ref(1);
1250 Sched->Schedule((XrdJob *)(pp->Link));
1251 isAvail.Wait();
1252 return 0;
1253 }
1254
1255 if ((pioP = pp->pioFree)) break;
1256 pp->reTry = &isAvail;
1257 pp->streamMutex.UnLock();
1258 TRACEP(FSZIO, "busy path " <<pathID <<" offs=" <<IO.Offset);
1259 isAvail.Wait();
1260 TRACEP(FSZIO, "retry path " <<pathID <<" offs=" <<IO.Offset);
1261 pp->streamMutex.Lock();
1262 if (pp->isNOP)
1263 {pp->streamMutex.UnLock();
1264 return Response.Send(kXR_ArgInvalid, "path ID is not connected");
1265 }
1266 } while(1);
1267
1268// Fill out the queue entry and add it to the queue
1269//
1270 pp->pioFree = pioP->Next; pioP->Next = 0;
1271 pioP->Set(Invoke, IO, streamID);
1272 IO.File->Ref(1);
1273 if (pp->pioLast) pp->pioLast->Next = pioP;
1274 else pp->pioFirst = pioP;
1275 pp->pioLast = pioP;
1276 pp->streamMutex.UnLock();
1277 return 0;
1278}
1279
1280/******************************************************************************/
1281/* d o _ O f f l o a d I O */
1282/******************************************************************************/
1283
1284int XrdXrootdProtocol::do_OffloadIO()
1285{
1286 XrdXrootdPio *pioP;
1287 int rc;
1288
1289// Entry implies that we just got scheduled and are marked as active. Hence
1290// we need to post the session thread so that it can pick up the next request.
1291//
1292 streamMutex.Lock();
1293 isLinkWT = false;
1294 if (newPio)
1295 {newPio = false;
1296 if (reTry) {reTry->Post(); reTry = 0;}
1297 TRACEP(FSZIO, "dispatch new I/O path " <<PathID <<" offs=" <<IO.Offset);
1298 }
1299
1300// Perform all I/O operations on a parallel stream
1301//
1302 if (!isNOP)
1303 do {streamMutex.UnLock();
1304 rc = (*this.*ResumePio)();
1305 streamMutex.Lock();
1306
1307 if (rc > 0 && !isNOP)
1308 {ResumePio = Resume;
1309 Resume = &XrdXrootdProtocol::do_OffloadIO;
1310 isLinkWT = true;
1312 return rc;
1313 }
1314
1315 IO.File->Ref(-1); // Note: File was ref'd when request was queued
1316 if (rc || isNOP || !(pioP = pioFirst)) break;
1317 if (!(pioFirst = pioP->Next)) pioLast = 0;
1318
1319 IO = pioP->IO;
1320 ResumePio = pioP->ResumePio;
1321 Response.Set(pioP->StreamID);
1322 pioP->Next = pioFree; pioFree = pioP;
1323 if (reTry) {reTry->Post(); reTry = 0;}
1324 } while(1);
1325 else {rc = -1; IO.File->Ref(-1);}
1326
1327// There are no pending operations or the link died
1328//
1329 if (rc) isNOP = true;
1330 isActive = false;
1331 Stream[0]->Link->setRef(-1);
1332 if (reTry) {reTry->Post(); reTry = 0;}
1333 if (endNote) endNote->Signal();
1335 TRACEP(FSZIO, "offload complete path "<<PathID<<" virt rc=" <<rc);
1336 return (rc ? rc : -EINPROGRESS);
1337}
1338
1339/******************************************************************************/
1340/* d o _ O p e n */
1341/******************************************************************************/
1342
1343namespace
1344{
1345struct OpenHelper
1346 {XrdSfsFile *fp;
1347 XrdXrootdFile *xp;
1348 XrdXrootdFileLock *Locker;
1349 const char *path;
1350 char mode;
1351 bool isOK;
1352
1353 OpenHelper(XrdXrootdFileLock *lkP, const char *fn)
1354 : fp(0), xp(0), Locker(lkP), path(fn), mode(0),
1355 isOK(false) {}
1356
1357 ~OpenHelper()
1358 {if (!isOK)
1359 {if (xp) delete xp; // Deletes fp & unlocks
1360 else {if (fp) delete fp;
1361 if (mode) Locker->Unlock(path,mode);
1362 }
1363 }
1364 }
1365 };
1366}
1367
1368int XrdXrootdProtocol::do_Open()
1369{
1370 static XrdXrootdCallBack openCB("open file", XROOTD_MON_OPENR);
1371 int fhandle;
1372 int rc, mode, opts, openopts, compchk = 0;
1373 int popt, retStat = 0;
1374 char *opaque, usage, ebuff[2048], opC;
1375 bool doDig, doforce = false, isAsync = false;
1376 char *fn = argp->buff, opt[16], *op=opt;
1377 XrdSfsFile *fp;
1378 XrdXrootdFile *xp;
1379 struct stat statbuf;
1380 struct ServerResponseBody_Open myResp;
1381 int resplen = sizeof(myResp.fhandle);
1382 struct iovec IOResp[3]; // Note that IOResp[0] is completed by Response
1383
1384// Keep Statistics
1385//
1386 SI->Bump(SI->openCnt);
1387
1388// Unmarshall the data
1389//
1390 mode = (int)ntohs(Request.open.mode);
1391 opts = (int)ntohs(Request.open.options);
1392
1393// Map the mode and options
1394//
1395 mode = mapMode(mode) | S_IRUSR | S_IWUSR; usage = 'r';
1396 if (opts & kXR_open_read)
1397 {openopts = SFS_O_RDONLY; *op++ = 'r'; opC = XROOTD_MON_OPENR;}
1398 else if (opts & kXR_open_updt)
1399 {openopts = SFS_O_RDWR; *op++ = 'u'; usage = 'w';
1400 opC = XROOTD_MON_OPENW;}
1401 else if (opts & kXR_open_wrto)
1402 {openopts = SFS_O_WRONLY; *op++ = 'o'; usage = 'w';
1403 opC = XROOTD_MON_OPENW;}
1404 else {openopts = SFS_O_RDONLY; *op++ = 'r'; opC = XROOTD_MON_OPENR;}
1405
1406 if (opts & kXR_new)
1407 {openopts |= SFS_O_CREAT; *op++ = 'n'; opC = XROOTD_MON_OPENC;
1408 if (opts & kXR_replica) {*op++ = '+';
1409 openopts |= SFS_O_REPLICA;
1410 }
1411 // Up until 3/28/19 we mistakenly used kXR_mkdir instead of
1412 // kXR_mkpath to allow path creation. That meant, path creation was
1413 // allowed if _mkpath|_async|_refresh|_open_apnd|_replica were set.
1414 // Since the client has always turned on _async that meant that
1415 // path creation was always enabled. We continue this boondogle
1416 // using the correct flag for backward compatibility reasons, sigh.
1417 //
1418 if (opts & (kXR_mkpath | kXR_async))
1419 {*op++ = 'm';
1420 mode |= SFS_O_MKPTH;
1421 }
1422 }
1423 else if (opts & kXR_delete)
1424 {openopts = SFS_O_TRUNC; *op++ = 'd'; opC = XROOTD_MON_OPENW;
1425 if (opts & (kXR_mkpath | kXR_async))
1426 {*op++ = 'm';
1427 mode |= SFS_O_MKPTH;
1428 }
1429 }
1430 if (opts & kXR_compress)
1431 {openopts |= SFS_O_RAWIO; *op++ = 'c'; compchk = 1;}
1432 if (opts & kXR_force) {*op++ = 'f'; doforce = true;}
1433 if ((opts & kXR_async || as_force) && as_aioOK)
1434 {*op++ = 'a'; isAsync = true;}
1435 if (opts & kXR_refresh) {*op++ = 's'; openopts |= SFS_O_RESET;
1436 SI->Bump(SI->Refresh);
1437 }
1438 if (opts & kXR_retstat) {*op++ = 't'; retStat = 1;}
1439 if (opts & kXR_posc) {*op++ = 'p'; openopts |= SFS_O_POSC;}
1440 if (opts & kXR_seqio) {*op++ = 'S'; openopts |= SFS_O_SEQIO;}
1441 *op = '\0';
1442
1443// Do some tracing, avoid exposing any security token in the URL
1444//
1445 if (TRACING(TRACE_FS))
1446 {char* cgiP = index(fn, '?');
1447 if (cgiP) *cgiP = 0;
1448 TRACEP(FS, "open " <<opt <<' ' <<fn);
1449 if (cgiP) *cgiP = '?';
1450 }
1451
1452// Check if opaque data has been provided
1453//
1454 if (rpCheck(fn, &opaque)) return rpEmsg("Opening", fn);
1455
1456// Check if this is a local dig type file
1457//
1458 doDig = (digFS && SFS_LCLPATH(fn));
1459
1460// Validate the path and then check if static redirection applies
1461//
1462 if (doDig) {popt = XROOTDXP_NOLK; opC = 0;}
1463 else {int ropt;
1464 if (!(popt = Squash(fn))) return vpEmsg("Opening", fn);
1465 if (Route[RD_open1].Host[rdType] && (ropt = RPList.Validate(fn)))
1466 return Response.Send(kXR_redirect, Route[ropt].Port[rdType],
1467 Route[ropt].Host[rdType]);
1468 }
1469
1470// Add the multi-write option if this path supports it
1471//
1472 if (popt & XROOTDXP_NOMWCHK) openopts |= SFS_O_MULTIW;
1473
1474// Construct an open helper to release resources should we exit due to an error.
1475//
1476 OpenHelper oHelp(Locker, fn);
1477
1478// Lock this file
1479//
1480 if (!(popt & XROOTDXP_NOLK))
1481 {if ((rc = Locker->Lock(fn, usage, doforce)))
1482 {const char *who;
1483 if (rc > 0) who = (rc > 1 ? "readers" : "reader");
1484 else { rc = -rc;
1485 who = (rc > 1 ? "writers" : "writer");
1486 }
1487 snprintf(ebuff, sizeof(ebuff)-1,
1488 "%s file %s is already opened by %d %s; open denied.",
1489 ('r' == usage ? "Input" : "Output"), fn, rc, who);
1490 eDest.Emsg("Xeq", ebuff);
1491 return Response.Send(kXR_FileLocked, ebuff);
1492 } else oHelp.mode = usage;
1493 }
1494
1495// Get a file object
1496//
1497 if (doDig) fp = digFS->newFile(Link->ID, Monitor.Did);
1498 else fp = osFS->newFile(Link->ID, Monitor.Did);
1499
1500// Make sure we got one
1501//
1502 if (!fp)
1503 {snprintf(ebuff, sizeof(ebuff)-1,"Insufficient memory to open %s",fn);
1504 eDest.Emsg("Xeq", ebuff);
1505 return Response.Send(kXR_NoMemory, ebuff);
1506 }
1507 oHelp.fp = fp;
1508
1509// The open is elegible for a deferred response, indicate we're ok with that
1510//
1511 fp->error.setErrCB(&openCB, ReqID.getID());
1512 fp->error.setUCap(clientPV);
1513
1514// If TPC opens require TLS but this is not a TLS connection, prohibit TPC
1515//
1516 if ((doTLS & Req_TLSTPC) && !isTLS && !Link->hasBridge())
1517 openopts|= SFS_O_NOTPC;
1518
1519// Open the file
1520//
1521 if ((rc = fp->open(fn, (XrdSfsFileOpenMode)openopts,
1522 (mode_t)mode, CRED, opaque)))
1523 {rc = fsError(rc, opC, fp->error, fn, opaque); return rc;}
1524
1525// Obtain a hyper file object
1526//
1527 xp = new XrdXrootdFile(Link->ID, fn, fp, usage, isAsync, &statbuf);
1528 if (!xp)
1529 {snprintf(ebuff, sizeof(ebuff)-1, "Insufficient memory to open %s", fn);
1530 eDest.Emsg("Xeq", ebuff);
1531 return Response.Send(kXR_NoMemory, ebuff);
1532 }
1533 oHelp.xp = xp;
1534
1535// Serialize the link
1536//
1537 Link->Serialize();
1538 *ebuff = '\0';
1539
1540// Create a file table for this link if it does not have one
1541//
1542 if (!FTab) FTab = new XrdXrootdFileTable(Monitor.Did);
1543
1544// Insert this file into the link's file table
1545//
1546 if (!FTab || (fhandle = FTab->Add(xp)) < 0)
1547 {snprintf(ebuff, sizeof(ebuff)-1, "Insufficient memory to open %s", fn);
1548 eDest.Emsg("Xeq", ebuff);
1549 return Response.Send(kXR_NoMemory, ebuff);
1550 }
1551
1552// If the file supports exchange buffering, supply it with the object
1553//
1554 if (fsFeatures & XrdSfs::hasSXIO) fp->setXio(this);
1555
1556// Document forced opens
1557//
1558 if (doforce)
1559 {int rdrs, wrtrs;
1560 Locker->numLocks(fn, rdrs, wrtrs);
1561 if (('r' == usage && wrtrs) || ('w' == usage && rdrs) || wrtrs > 1)
1562 {snprintf(ebuff, sizeof(ebuff)-1,
1563 "%s file %s forced opened with %d reader(s) and %d writer(s).",
1564 ('r' == usage ? "Input" : "Output"), fn, rdrs, wrtrs);
1565 eDest.Emsg("Xeq", ebuff);
1566 }
1567 }
1568
1569// Determine if file is compressed
1570//
1571 memset(&myResp, 0, sizeof(myResp));
1572 if (!compchk) resplen = sizeof(myResp.fhandle);
1573 else {int cpsize;
1574 fp->getCXinfo((char *)myResp.cptype, cpsize);
1575 myResp.cpsize = static_cast<kXR_int32>(htonl(cpsize));
1576 resplen = sizeof(myResp);
1577 }
1578
1579// If client wants a stat in open, return the stat information
1580//
1581 if (retStat)
1582 {retStat = StatGen(statbuf, ebuff, sizeof(ebuff));
1583 IOResp[1].iov_base = (char *)&myResp; IOResp[1].iov_len = sizeof(myResp);
1584 IOResp[2].iov_base = ebuff; IOResp[2].iov_len = retStat;
1585 resplen = sizeof(myResp) + retStat;
1586 }
1587
1588// If we are monitoring, send off a path to dictionary mapping (must try 1st!)
1589//
1590 if (Monitor.Files())
1591 {xp->Stats.FileID = Monitor.MapPath(fn);
1593 Monitor.Agent->Open(xp->Stats.FileID, statbuf.st_size);
1594 }
1595
1596// Since file monitoring is deprecated, a dictid may not have been assigned.
1597// But if fstream monitoring is enabled it will assign the dictid.
1598//
1599 if (Monitor.Fstat())
1600 XrdXrootdMonFile::Open(&(xp->Stats), fn, Monitor.Did, usage == 'w');
1601
1602// Insert the file handle
1603//
1604 memcpy((void *)myResp.fhandle,(const void *)&fhandle,sizeof(myResp.fhandle));
1605 numFiles++;
1606
1607// If packet marking is enabled, notify that we have potentially started data.
1608// We also need to extend the marking to any associated streams.
1609//
1610 int eCode, aCode;
1611 if (PMark && !pmDone)
1612 {streamMutex.Lock();
1613 pmDone = true;
1614 if ((pmHandle = PMark->Begin(*Client, fn, opaque, AppName)))
1615 for (int i = 1; i < maxStreams; i++)
1616 {if (Stream[i] && !(Stream[i]->pmDone))
1617 {Stream[i]->pmDone = true;
1618 Stream[i]->pmHandle =
1619 PMark->Begin(*(Stream[i]->Link->AddrInfo()),
1620 *pmHandle, Stream[i]->Link->ID);
1621 }
1622 }
1624
1625 if (pmHandle && Monitor.Logins() && pmHandle->getEA(eCode, aCode))
1626 Monitor.Report(eCode, aCode);
1627 } else {
1628 if (!pmDone && Monitor.Logins()
1629 && XrdNetPMark::getEA(opaque, eCode, aCode))
1630 {Monitor.Report(eCode, aCode); pmDone = true;}
1631 }
1632
1633// Respond (failure is not an option now)
1634//
1635 oHelp.isOK = true;
1636 if (retStat) return Response.Send(IOResp, 3, resplen);
1637 else return Response.Send((void *)&myResp, resplen);
1638}
1639
1640/******************************************************************************/
1641/* d o _ P i n g */
1642/******************************************************************************/
1643
1644int XrdXrootdProtocol::do_Ping()
1645{
1646
1647// Keep Statistics
1648//
1649 SI->Bump(SI->miscCnt);
1650
1651// This is a basic nop
1652//
1653 return Response.Send();
1654}
1655
1656/******************************************************************************/
1657/* d o _ P r e p a r e */
1658/******************************************************************************/
1659
1660int XrdXrootdProtocol::do_Prepare(bool isQuery)
1661{
1662 static XrdXrootdCallBack prpCB("query", XROOTD_MON_QUERY);
1663
1665
1666 XrdOucTokenizer pathlist(argp->buff);
1667 XrdOucTList *pFirst=0, *pP, *pLast = 0;
1668 XrdOucTList *oFirst=0, *oP, *oLast = 0;
1669 XrdOucTListHelper pHelp(&pFirst), oHelp(&oFirst);
1670 XrdXrootdPrepArgs pargs(0, 0);
1671 XrdSfsPrep fsprep;
1672
1673 int rc, pathnum = 0;
1674 char reqid[128], nidbuff[512], *path, *opaque, *prpid = 0;
1675 unsigned short optX = ntohs(Request.prepare.optionX);
1676 char opts;
1677 bool isCancel, isEvict, isPrepare;
1678
1679// Check if this is an evict request (similar to stage)
1680//
1681 isEvict = (optX & kXR_evict) != 0;
1682
1683// Establish what we are really doing here
1684//
1685 if (isQuery)
1686 {opts = 0;
1687 isCancel = false;
1688 } else {
1690 {opts = 0;
1691 isCancel = true;
1692 } else {
1693 opts = (isEvict ? 0 : Request.prepare.options);
1694 isCancel = false;
1695 }
1696 }
1697 isPrepare = !(isCancel || isQuery);
1698
1699// Apply prepare limits, as necessary.
1700//
1701 if (isPrepare && (PrepareLimit >= 0) && (++PrepareCount > PrepareLimit)) {
1702 if (LimitError) {
1703 return Response.Send( kXR_overQuota,
1704 "Surpassed this connection's prepare limit.");
1705 } else {
1706 return Response.Send();
1707 }
1708 }
1709
1710// Check for static routing
1711//
1712 if ((opts & kXR_stage) || isCancel) {STATIC_REDIRECT(RD_prepstg);}
1713 STATIC_REDIRECT(RD_prepare);
1714
1715// Prehandle requests that must have a requestID. Otherwise, generate one.
1716// Note that prepare request id's have two formats. The external format is
1717// is qualifiaed by this host while the internal one removes the qualification.
1718// The internal one is only used for the native prepare implementation.
1719// To wit: prpid is the unqualified ID while reqid is the qualified one for
1720// generated id's while prpid is always the specified request id.
1721//
1722 if (isCancel || isQuery)
1723 {if (!(prpid = pathlist.GetLine()))
1724 return Response.Send(kXR_ArgMissing, "Prepare requestid not specified");
1725 fsprep.reqid = prpid;
1726 fsprep.opts = (isCancel ? Prep_CANCEL : Prep_QUERY);
1727 if (!PrepareAlt)
1728 {char hname[256];
1729 int hport;
1730 prpid = PrepID->isMine(prpid, hport, hname, sizeof(hname));
1731 if (!prpid)
1732 {if (!hport) return Response.Send(kXR_ArgInvalid,
1733 "Prepare requestid owned by an unknown server");
1734 TRACEI(REDIR, Response.ID() <<" redirecting prepare to "
1735 << hname <<':' <<hport);
1736 return Response.Send(kXR_redirect, hport, hname);
1737 }
1738 }
1739 } else {
1740 if (opts & kXR_stage)
1741 {prpid = PrepID->ID(reqid, sizeof(reqid));
1742 fsprep.reqid = reqid;
1743 fsprep.opts = Prep_STAGE | (opts & kXR_coloc ? Prep_COLOC : 0);
1744 } else {
1745 reqid[0]='*'; reqid[1]='\0';
1746 fsprep.reqid = prpid = reqid;
1747 fsprep.opts = (isEvict ? Prep_EVICT : 0);
1748 }
1749 }
1750
1751// Initialize the file system prepare arg list
1752//
1753 fsprep.paths = 0;
1754 fsprep.oinfo = 0;
1755 fsprep.notify = 0;
1756
1757// Cycle through all of the paths in the list
1758//
1759 while((path = pathlist.GetLine()))
1760 {if (rpCheck(path, &opaque)) return rpEmsg("Preparing", path);
1761 if (!Squash(path)) return vpEmsg("Preparing", path);
1762 pP = new XrdOucTList(path, pathnum);
1763 (pLast ? (pLast->next = pP) : (pFirst = pP)); pLast = pP;
1764 oP = new XrdOucTList(opaque, 0);
1765 (oLast ? (oLast->next = oP) : (oFirst = oP)); oLast = oP;
1766 pathnum++;
1767 }
1768 fsprep.paths = pFirst;
1769 fsprep.oinfo = oFirst;
1770
1771// We support callbacks but only for alternate prepare processing
1772//
1773 if (PrepareAlt) myError.setErrCB(&prpCB, ReqID.getID());
1774
1775// Process cancel requests here; they are simple at this point.
1776//
1777 if (isCancel)
1778 {if (SFS_OK != (rc = osFS->prepare(fsprep, myError, CRED)))
1779 return fsError(rc, XROOTD_MON_PREP, myError, path, 0);
1780 rc = Response.Send();
1782 return rc;
1783 }
1784
1785// Process query requests here; they are simple at this point.
1786//
1787 if (isQuery)
1788 {if (PrepareAlt)
1789 {if (SFS_OK != (rc = osFS->prepare(fsprep, myError, CRED)))
1790 return fsError(rc, XROOTD_MON_PREP, myError, path, 0);
1791 rc = Response.Send();
1792 } else {
1793 char *mBuff = myError.getMsgBuff(rc);
1794 pargs.reqid = prpid;
1795 pargs.user = Link->ID;
1796 pargs.paths = pFirst;
1797 rc = XrdXrootdPrepare::List(pargs, mBuff, rc);
1798 if (rc < 0) rc = Response.Send("No information found.");
1799 else rc = Response.Send(mBuff);
1800 }
1801 return rc;
1802 }
1803
1804// Make sure we have at least one path
1805//
1806 if (!pFirst)
1807 return Response.Send(kXR_ArgMissing, "No prepare paths specified");
1808
1809// Handle evict. We only support the evicts for alternate prepare handlers.
1810//
1811 if (isEvict)
1812 {if (PrepareAlt
1813 && (SFS_OK != (rc = osFS->prepare(fsprep, myError, CRED))))
1814 return fsError(rc, XROOTD_MON_PREP, myError, path, 0);
1815 return Response.Send();
1816 }
1817
1818// Handle notification parameter. The notification depends on whether or not
1819// we have a custom prepare handler.
1820//
1821 if (opts & kXR_notify)
1822 {const char *nprot = (opts & kXR_usetcp ? "tcp" : "udp");
1823 fsprep.notify = nidbuff;
1824 if (PrepareAlt)
1825 {if (Request.prepare.port == 0) fsprep.notify = 0;
1826 else snprintf(nidbuff, sizeof(nidbuff), "%s://%s:%d/",
1827 nprot, Link->Host(), ntohs(Request.prepare.port));
1828 } else sprintf(nidbuff, Notify, nprot, Link->FDnum(), Link->ID);
1829 if (fsprep.notify)
1830 fsprep.opts |= (opts & kXR_noerrs ? Prep_SENDAOK : Prep_SENDACK);
1831 }
1832
1833// Complete prepare options
1834//
1835 fsprep.opts |= (opts & kXR_fresh ? Prep_FRESH : 0);
1836 if (opts & kXR_wmode) fsprep.opts |= Prep_WMODE;
1837 if (PrepareAlt)
1838 {switch(Request.prepare.prty)
1839 {case 0: fsprep.opts |= Prep_PRTY0; break;
1840 case 1: fsprep.opts |= Prep_PRTY1; break;
1841 case 2: fsprep.opts |= Prep_PRTY2; break;
1842 case 3: fsprep.opts |= Prep_PRTY3; break;
1843 default: break;
1844 }
1845 } else {
1846 if (Request.prepare.prty == 0) fsprep.opts |= Prep_PRTY0;
1847 else fsprep.opts |= Prep_PRTY1;
1848 }
1849
1850// Issue the prepare request
1851//
1852 if (SFS_OK != (rc = osFS->prepare(fsprep, myError, CRED)))
1853 return fsError(rc, XROOTD_MON_PREP, myError, pFirst->text, oFirst->text);
1854
1855// Perform final processing
1856//
1857 if (!(opts & kXR_stage)) rc = Response.Send();
1858 else {rc = Response.Send(reqid, strlen(reqid));
1859 if (!PrepareAlt)
1860 {pargs.reqid = prpid;
1861 pargs.user = Link->ID;
1862 pargs.paths = pFirst;
1863 XrdXrootdPrepare::Log(pargs);
1864 }
1865 }
1866 return rc;
1867}
1868
1869/******************************************************************************/
1870/* d o _ P r o t o c o l */
1871/******************************************************************************/
1872
1873namespace XrdXrootd
1874{
1875extern char *bifResp[2];
1876extern int bifRLen[2];
1877}
1878
1879int XrdXrootdProtocol::do_Protocol()
1880{
1881 static kXR_int32 verNum = static_cast<kXR_int32>(htonl(kXR_PROTOCOLVERSION));
1882 static kXR_int32 theRle = static_cast<kXR_int32>(htonl(myRole));
1883 static kXR_int32 theRlf = static_cast<kXR_int32>(htonl(myRolf));
1884 static kXR_int32 theRlt = static_cast<kXR_int32>(htonl(myRole|kXR_gotoTLS));
1885
1887 struct iovec ioVec[4] = {{0,0},{&theResp,kXR_ShortProtRespLen},{0,0},{0,0}};
1888
1889 int rc, iovN = 2, RespLen = kXR_ShortProtRespLen;
1890 bool wantTLS = false;
1891
1892// Keep Statistics
1893//
1894 SI->Bump(SI->miscCnt);
1895
1896// Determine which response to provide
1897//
1899 {int cvn = XrdOucEI::uVMask & ntohl(Request.protocol.clientpv);
1900 if (!Status || !(clientPV & XrdOucEI::uVMask))
1901 clientPV = (clientPV & ~XrdOucEI::uVMask) | cvn;
1902 else cvn = (clientPV & XrdOucEI::uVMask);
1903
1905 && XrdXrootd::bifResp[0])
1906 {int k =( Link->AddrInfo()->isPrivate() ? 1 : 0);
1907 ioVec[iovN ].iov_base = XrdXrootd::bifResp[k];
1908 ioVec[iovN++].iov_len = XrdXrootd::bifRLen[k];
1909 RespLen += XrdXrootd::bifRLen[k];
1910 }
1911
1912 if (DHS && cvn >= kXR_PROTSIGNVERSION
1914 {int n = DHS->ProtResp(theResp.secreq, *(Link->AddrInfo()), cvn);
1915 ioVec[iovN ].iov_base = (void *)&theResp.secreq;
1916 ioVec[iovN++].iov_len = n;
1917 RespLen += n;
1918 }
1919
1920 if ((myRole & kXR_haveTLS) != 0 && !(Link->hasTLS()))
1921 {wantTLS = (Request.protocol.flags &
1923 ableTLS = wantTLS || (Request.protocol.flags &
1925 if (ableTLS) doTLS = tlsCap;
1926 else doTLS = tlsNot;
1927 if (ableTLS && !wantTLS)
1930 wantTLS = (doTLS & Req_TLSData) != 0;
1931 break;
1933 wantTLS = (doTLS & Req_TLSLogin) != 0;
1934 break;
1936 wantTLS = (doTLS & Req_TLSTPC) != 0 ||
1937 (doTLS & Req_TLSLogin) != 0;
1938 break;
1939 default: break;
1940 }
1941 }
1942 theResp.flags = (wantTLS ? theRlt : theRle);
1943 } else {
1944 theResp.flags = theRlf;
1945 doTLS = tlsNot;
1946 }
1947
1948// Send the response
1949//
1950 theResp.pval = verNum;
1951 rc = Response.Send(ioVec, iovN, RespLen);
1952
1953// If the client wants to start using TLS, enable it now. If we fail then we
1954// have no choice but to terminate the connection. Note that incapable clients
1955// don't want TLS but if we require TLS anyway, they will get an error either
1956// pre-login or post-login or on a bind later on.
1957//
1958 if (rc == 0 && wantTLS)
1959 {if (Link->setTLS(true, tlsCtx))
1960 {Link->setProtName("xroots");
1961 isTLS = true;
1962 } else {
1963 eDest.Emsg("Xeq", "Unable to enable TLS for", Link->ID);
1964 rc = -1;
1965 }
1966 }
1967 return rc;
1968}
1969
1970/******************************************************************************/
1971/* d o _ Q c o n f */
1972/******************************************************************************/
1973
1974int XrdXrootdProtocol::do_Qconf()
1975{
1976 static const int fsctl_cmd = SFS_FSCTL_STATCC|SFS_O_LOCAL;
1977 XrdOucTokenizer qcargs(argp->buff);
1978 char *val, buff[4096], *bp=buff;
1979 int n, bleft = sizeof(buff);
1980
1981// Get the first argument
1982//
1983 if (!qcargs.GetLine() || !(val = qcargs.GetToken()))
1984 return Response.Send(kXR_ArgMissing, "query config argument not specified.");
1985
1986// The first item can be xrootd or cmsd to display the config file
1987//
1988 if (!strcmp(val, "cmsd") || !strcmp(val, "xrootd"))
1989 return do_QconfCX(qcargs, val);
1990
1991// Trace this query variable
1992//
1993 do {TRACEP(DEBUG, "query config " <<val);
1994
1995 // Now determine what the user wants to query
1996 //
1997 if (!strcmp("bind_max", val))
1998 {n = snprintf(bp, bleft, "%d\n", maxStreams-1);
1999 bp += n; bleft -= n;
2000 }
2001 else if (!strcmp("chksum", val))
2002 {const char *csList = getenv("XRD_CSLIST");
2003 if (!JobCKT || !csList)
2004 {n = snprintf(bp, bleft, "chksum\n");
2005 bp += n; bleft -= n;
2006 continue;
2007 }
2008 n = snprintf(bp, bleft, "%s\n", csList);
2009 bp += n; bleft -= n;
2010 }
2011 else if (!strcmp("cid", val))
2012 {const char *cidval = getenv("XRDCMSCLUSTERID");
2013 if (!cidval || !(*cidval)) cidval = "cid";
2014 n = snprintf(bp, bleft, "%s\n", cidval);
2015 bp += n; bleft -= n;
2016 }
2017 else if (!strcmp("cms", val))
2018 {XrdOucErrInfo myError(Link->ID, Monitor.Did, clientPV);
2019 if (osFS->fsctl(fsctl_cmd, ".", myError, CRED) == SFS_DATA)
2020 n = snprintf(bp, bleft, "%s\n", myError.getErrText());
2021 else n = snprintf(bp, bleft, "%s\n", "cms");
2022 bp += n; bleft -= n;
2023 }
2024 else if (!strcmp("pio_max", val))
2025 {n = snprintf(bp, bleft, "%d\n", maxPio+1);
2026 bp += n; bleft -= n;
2027 }
2028 else if (!strcmp("proxy", val))
2029 {const char* pxyOrigin = "proxy";
2030 if (myRole & kXR_attrProxy)
2031 {pxyOrigin = getenv("XRDXROOTD_PROXY");
2032 if (!pxyOrigin) pxyOrigin = "proxy";
2033 }
2034 n = snprintf(bp,bleft,"%s\n",pxyOrigin);
2035 bp += n; bleft -= n;
2036 }
2037 else if (!strcmp("readv_ior_max", val))
2038 {n = snprintf(bp,bleft,"%d\n",maxReadv_ior);
2039 bp += n; bleft -= n;
2040 }
2041 else if (!strcmp("readv_iov_max", val))
2042 {n = snprintf(bp, bleft, "%d\n", XrdProto::maxRvecsz);
2043 bp += n; bleft -= n;
2044 }
2045 else if (!strcmp("role", val))
2046 {const char *theRole = getenv("XRDROLE");
2047 n = snprintf(bp, bleft, "%s\n", (theRole ? theRole : "none"));
2048 bp += n; bleft -= n;
2049 }
2050 else if (!strcmp("sitename", val))
2051 {const char *siteName = getenv("XRDSITE");
2052 n = snprintf(bp, bleft, "%s\n", (siteName ? siteName : "sitename"));
2053 bp += n; bleft -= n;
2054 }
2055 else if (!strcmp("start", val))
2056 {n = snprintf(bp, bleft, "%s\n", startUP);
2057 bp += n; bleft -= n;
2058 }
2059 else if (!strcmp("sysid", val))
2060 {const char *cidval = getenv("XRDCMSCLUSTERID");
2061 const char *nidval = getenv("XRDCMSVNID");
2062 if (!cidval || !(*cidval) || !nidval || !(*nidval))
2063 {cidval = "sysid"; nidval = "";}
2064 n = snprintf(bp, bleft, "%s %s\n", nidval, cidval);
2065 bp += n; bleft -= n;
2066 }
2067 else if (!strcmp("tpc", val))
2068 {char *tpcval = getenv("XRDTPC");
2069 n = snprintf(bp, bleft, "%s\n", (tpcval ? tpcval : "tpc"));
2070 bp += n; bleft -= n;
2071 }
2072 else if (!strcmp("tpcdlg", val))
2073 {char *tpcval = getenv("XRDTPCDLG");
2074 n = snprintf(bp, bleft, "%s\n", (tpcval ? tpcval : "tpcdlg"));
2075 bp += n; bleft -= n;
2076 }
2077 else if (!strcmp("tls_port", val) && tlsPort)
2078 {n = snprintf(bp, bleft, "%d\n", tlsPort);
2079 bp += n; bleft -= n;
2080 }
2081 else if (!strcmp("window", val) && Window)
2082 {n = snprintf(bp, bleft, "%d\n", Window);
2083 bp += n; bleft -= n;
2084 }
2085 else if (!strcmp("version", val))
2086 {n = snprintf(bp, bleft, "%s\n", XrdVSTRING);
2087 bp += n; bleft -= n;
2088 }
2089 else if (!strcmp("vnid", val))
2090 {const char *nidval = getenv("XRDCMSVNID");
2091 if (!nidval || !(*nidval)) nidval = "vnid";
2092 n = snprintf(bp, bleft, "%s\n", nidval);
2093 }
2094 else if (!strcmp("fattr", val))
2095 {n = snprintf(bp, bleft, "%s\n", usxParms);
2096 bp += n; bleft -= n;
2097 }
2098 else {n = strlen(val);
2099 if (bleft <= n) break;
2100 strcpy(bp, val); bp +=n; *bp = '\n'; bp++;
2101 bleft -= (n+1);
2102 }
2103 } while(bleft > 0 && (val = qcargs.GetToken()));
2104
2105// Make sure all ended well
2106//
2107 if (val)
2108 return Response.Send(kXR_ArgTooLong, "too many query config arguments.");
2109
2110// All done
2111//
2112 return Response.Send(buff, sizeof(buff) - bleft);
2113}
2114
2115/******************************************************************************/
2116/* d o _ Q c o n f C X */
2117/******************************************************************************/
2118
2119int XrdXrootdProtocol::do_QconfCX(XrdOucTokenizer &qcargs, char *val)
2120{
2121 extern XrdOucString *XrdXrootdCF;
2122 bool isCMSD = (*val == 'c');
2123
2124// Make sure there is nothing else following the token
2125//
2126 if ((val = qcargs.GetToken()))
2127 return Response.Send(kXR_ArgInvalid, "too many query config arguments.");
2128
2129// If this is a cms just return a null for now
2130//
2131 if (isCMSD) return Response.Send((void *)"\n", 2);
2132
2133// Display the xrootd configuration
2134//
2135 if (XrdXrootdCF && isTLS && getenv("XROOTD_QCFOK"))
2136 return Response.Send((void *)XrdXrootdCF->c_str(), XrdXrootdCF->length());
2137
2138// Respond with a null
2139//
2140 return Response.Send((void *)"\n", 2);
2141}
2142
2143/******************************************************************************/
2144/* d o _ Q f h */
2145/******************************************************************************/
2146
2147int XrdXrootdProtocol::do_Qfh()
2148{
2149 static XrdXrootdCallBack qryCB("query", XROOTD_MON_QUERY);
2151 XrdXrootdFile *fp;
2152 const char *fArg = 0, *qType = "";
2153 int rc;
2154 short qopt = (short)ntohs(Request.query.infotype);
2155
2156// Update misc stats count
2157//
2158 SI->Bump(SI->miscCnt);
2159
2160// Find the file object
2161//
2162 if (!FTab || !(fp = FTab->Get(fh.handle)))
2164 "query does not refer to an open file");
2165
2166// The query is elegible for a deferred response, indicate we're ok with that
2167//
2168 fp->XrdSfsp->error.setErrCB(&qryCB, ReqID.getID());
2169
2170// Perform the appropriate query
2171//
2172 switch(qopt)
2173 {case kXR_Qopaqug: qType = "Qopaqug";
2174 fArg = (Request.query.dlen ? argp->buff : 0);
2175 rc = fp->XrdSfsp->fctl(SFS_FCTL_SPEC1,
2176 Request.query.dlen, fArg,
2177 CRED);
2178 break;
2179 case kXR_Qvisa: qType = "Qvisa";
2180 rc = fp->XrdSfsp->fctl(SFS_FCTL_STATV, 0,
2181 fp->XrdSfsp->error);
2182 break;
2183 default: return Response.Send(kXR_ArgMissing,
2184 "Required query argument not present");
2185 }
2186
2187// Preform the actual function
2188//
2189 TRACEP(FS, "fh=" <<fh.handle <<" query " <<qType <<" rc=" <<rc);
2190
2191// Return appropriately
2192//
2193 if (SFS_OK != rc)
2194 return fsError(rc, XROOTD_MON_QUERY, fp->XrdSfsp->error, 0, 0);
2195 return Response.Send();
2196}
2197
2198/******************************************************************************/
2199/* d o _ Q o p a q u e */
2200/******************************************************************************/
2201
2202int XrdXrootdProtocol::do_Qopaque(short qopt)
2203{
2204 static XrdXrootdCallBack qpqCB("query", XROOTD_MON_QUERY);
2206 XrdSfsFSctl myData;
2207 const char *Act, *AData;
2208 char *opaque;
2209 int fsctl_cmd, rc, dlen = Request.query.dlen;
2210
2211// Process unstructured as well as structured (path/opaque) requests
2212//
2213 if (qopt == kXR_Qopaque)
2214 {myData.Arg1 = argp->buff; myData.Arg1Len = dlen;
2215 myData.Arg2 = 0; myData.Arg2Len = 0;
2216 fsctl_cmd = SFS_FSCTL_PLUGIO;
2217 Act = " qopaque '"; AData = "...";
2218 } else {
2219 // Check for static routing (this falls under stat)
2220 //
2221 STATIC_REDIRECT(RD_stat);
2222
2223 // Prescreen the path
2224 //
2225 if (rpCheck(argp->buff, &opaque)) return rpEmsg("Querying", argp->buff);
2226 if (!Squash(argp->buff)) return vpEmsg("Querying", argp->buff);
2227
2228 // Setup arguments
2229 //
2230 myData.Arg1 = argp->buff;
2231 myData.Arg1Len = (opaque ? opaque - argp->buff - 1 : dlen);
2232 myData.Arg2 = opaque;
2233 myData.Arg2Len = (opaque ? argp->buff + dlen - opaque : 0);
2234 fsctl_cmd = SFS_FSCTL_PLUGIN;
2235 Act = " qopaquf '"; AData = argp->buff;
2236 }
2237// The query is elegible for a deferred response, indicate we're ok with that
2238//
2239 myError.setErrCB(&qpqCB, ReqID.getID());
2240
2241// Preform the actual function using the supplied arguments
2242//
2243 rc = osFS->FSctl(fsctl_cmd, myData, myError, CRED);
2244 TRACEP(FS, "rc=" <<rc <<Act <<AData <<"'");
2245 if (rc == SFS_OK) return Response.Send("");
2246 return fsError(rc, 0, myError, 0, 0);
2247}
2248
2249/******************************************************************************/
2250/* d o _ Q s p a c e */
2251/******************************************************************************/
2252
2253int XrdXrootdProtocol::do_Qspace()
2254{
2255 static const int fsctl_cmd = SFS_FSCTL_STATLS;
2257 char *opaque;
2258 int n, rc;
2259
2260// Check for static routing
2261//
2262 STATIC_REDIRECT(RD_stat);
2263
2264// Prescreen the path
2265//
2266 if (rpCheck(argp->buff, &opaque)) return rpEmsg("Stating", argp->buff);
2267 if (!Squash(argp->buff)) return vpEmsg("Stating", argp->buff);
2268
2269// Add back the opaque info
2270//
2271 if (opaque)
2272 {n = strlen(argp->buff); argp->buff[n] = '?';
2273 if ((argp->buff)+n != opaque-1)
2274 memmove(&argp->buff[n+1], opaque, strlen(opaque)+1);
2275 }
2276
2277// Preform the actual function using the supplied logical FS name
2278//
2279 rc = osFS->fsctl(fsctl_cmd, argp->buff, myError, CRED);
2280 TRACEP(FS, "rc=" <<rc <<" qspace '" <<argp->buff <<"'");
2281 if (rc == SFS_OK) return Response.Send("");
2282 return fsError(rc, XROOTD_MON_QUERY, myError, argp->buff, opaque);
2283}
2284
2285/******************************************************************************/
2286/* d o _ Q u e r y */
2287/******************************************************************************/
2288
2289int XrdXrootdProtocol::do_Query()
2290{
2291 short qopt = (short)ntohs(Request.query.infotype);
2292
2293// Perform the appropriate query
2294//
2295 switch(qopt)
2296 {case kXR_QStats: return SI->Stats(Response,
2297 (Request.header.dlen ? argp->buff : "a"));
2298 case kXR_Qcksum: return do_CKsum(0);
2299 case kXR_Qckscan: return do_CKsum(1);
2300 case kXR_Qconfig: return do_Qconf();
2301 case kXR_Qspace: return do_Qspace();
2302 case kXR_Qxattr: return do_Qxattr();
2303 case kXR_Qopaque:
2304 case kXR_Qopaquf: return do_Qopaque(qopt);
2305 case kXR_Qopaqug: return do_Qfh();
2306 case kXR_QPrep: return do_Prepare(true);
2307 default: break;
2308 }
2309
2310// Whatever we have, it's not valid
2311//
2313 "Invalid information query type code");
2314}
2315
2316/******************************************************************************/
2317/* d o _ Q x a t t r */
2318/******************************************************************************/
2319
2320int XrdXrootdProtocol::do_Qxattr()
2321{
2322 static XrdXrootdCallBack statCB("stat", XROOTD_MON_QUERY);
2323 static const int fsctl_cmd = SFS_FSCTL_STATXA;
2324 int rc;
2325 char *opaque;
2326 XrdOucErrInfo myError(Link->ID,&statCB,ReqID.getID(),Monitor.Did,clientPV);
2327
2328// Check for static routing
2329//
2330 STATIC_REDIRECT(RD_stat);
2331
2332// Prescreen the path
2333//
2334 if (rpCheck(argp->buff, &opaque)) return rpEmsg("Stating", argp->buff);
2335 if (!Squash(argp->buff)) return vpEmsg("Stating", argp->buff);
2336
2337// Add back opaque information is present
2338//
2339 if (opaque)
2340 {int n = strlen(argp->buff); argp->buff[n] = '?';
2341 if ((argp->buff)+n != opaque-1)
2342 memmove(&argp->buff[n+1], opaque, strlen(opaque)+1);
2343 }
2344
2345// Preform the actual function
2346//
2347 rc = osFS->fsctl(fsctl_cmd, argp->buff, myError, CRED);
2348 TRACEP(FS, "rc=" <<rc <<" qxattr " <<argp->buff);
2349 return fsError(rc, XROOTD_MON_QUERY, myError, argp->buff, opaque);
2350}
2351
2352/******************************************************************************/
2353/* d o _ R e a d */
2354/******************************************************************************/
2355
2356int XrdXrootdProtocol::do_Read()
2357{
2358 int pathID, retc;
2360 numReads++;
2361
2362// We first handle the pre-read list, if any. We do it this way because of
2363// a historical glitch in the protocol. One should really not piggy back a
2364// pre-read on top of a read, though it is allowed.
2365//
2366 if (!Request.header.dlen) pathID = 0;
2367 else if (do_ReadNone(retc, pathID)) return retc;
2368
2369// Unmarshall the data
2370//
2371 IO.IOLen = ntohl(Request.read.rlen);
2372 n2hll(Request.read.offset, IO.Offset);
2373
2374// Find the file object
2375//
2376 if (!FTab || !(IO.File = FTab->Get(fh.handle)))
2378 "read does not refer to an open file");
2379
2380// Trace and verify read length is not negative
2381//
2382 TRACEP(FSIO, pathID <<" fh=" <<fh.handle <<" read " <<IO.IOLen
2383 <<'@' <<IO.Offset);
2384 if ( IO.IOLen < 0) return Response.Send(kXR_ArgInvalid,
2385 "Read length is negative");
2386
2387// If we are monitoring, insert a read entry
2388//
2389 if (Monitor.InOut())
2392
2393// Short circuit processing if read length is zero
2394//
2395 if (!IO.IOLen) return Response.Send();
2396
2397// There are many competing ways to accomplish a read. Pick the one we
2398// will use and if possible, do a fast dispatch.
2399//
2401 else if (IO.File->sfEnabled && !isTLS && IO.IOLen >= as_minsfsz
2402 && IO.Offset+IO.IOLen <= IO.File->Stats.fSize)
2404 else if (IO.File->AsyncMode && IO.IOLen >= as_miniosz
2405 && IO.Offset+IO.IOLen <= IO.File->Stats.fSize+as_seghalf
2407 {XrdXrootdProtocol *pP;
2408 XrdXrootdNormAio *aioP;
2409
2410 if (!pathID) pP = this;
2411 else {if (!(pP = VerifyStream(retc, pathID, false))) return retc;
2412 if (pP->linkAioReq >= as_maxperlnk) pP = 0;
2413 }
2414 if (pP && (aioP = XrdXrootdNormAio::Alloc(pP,pP->Response,IO.File)))
2415 {if (!IO.File->aioFob) IO.File->aioFob = new XrdXrootdAioFob;
2416 aioP->Read(IO.Offset, IO.IOLen);
2417 return 0;
2418 }
2419 SI->AsyncRej++;
2421 }
2423
2424// See if an alternate path is required, offload the read
2425//
2426 if (pathID) return do_Offload(&XrdXrootdProtocol::do_ReadAll, pathID);
2427
2428// Now read all of the data (do pre-reads first)
2429//
2430 return do_ReadAll();
2431}
2432
2433/******************************************************************************/
2434/* d o _ R e a d A l l */
2435/******************************************************************************/
2436
2437// IO.File = file to be read
2438// IO.Offset = Offset at which to read
2439// IO.IOLen = Number of bytes to read from file and write to socket
2440
2441int XrdXrootdProtocol::do_ReadAll()
2442{
2443 int rc, xframt, Quantum = (IO.IOLen > maxBuffsz ? maxBuffsz : IO.IOLen);
2444 char *buff;
2445
2446// If this file is memory mapped, short ciruit all the logic and immediately
2447// transfer the requested data to minimize latency.
2448//
2450 {if (IO.Offset >= IO.File->Stats.fSize) return Response.Send();
2451 if (IO.Offset+IO.IOLen <= IO.File->Stats.fSize)
2453 return Response.Send(IO.File->mmAddr+IO.Offset, IO.IOLen);
2454 }
2455 xframt = IO.File->Stats.fSize -IO.Offset;
2456 IO.File->Stats.rdOps(xframt);
2457 return Response.Send(IO.File->mmAddr+IO.Offset, xframt);
2458 }
2459
2460// If we are sendfile enabled, then just send the file if possible
2461//
2464 if (IO.File->fdNum >= 0)
2465 return Response.Send(IO.File->fdNum, IO.Offset, IO.IOLen);
2466 rc = IO.File->XrdSfsp->SendData((XrdSfsDio *)this, IO.Offset, IO.IOLen);
2467 if (rc == SFS_OK)
2468 {if (!IO.IOLen) return 0;
2469 if (IO.IOLen < 0) return -1; // Otherwise retry using read()
2470 } else return fsError(rc, 0, IO.File->XrdSfsp->error, 0, 0);
2471 }
2472
2473// Make sure we have a large enough buffer
2474//
2475 if (!argp || Quantum < halfBSize || Quantum > argp->bsize)
2476 {if ((rc = getBuff(1, Quantum)) <= 0) return rc;}
2477 else if (hcNow < hcNext) hcNow++;
2478 buff = argp->buff;
2479
2480// Now read all of the data. For statistics, we need to record the orignal
2481// amount of the request even if we really do not get to read that much!
2482//
2484 do {if ((xframt = IO.File->XrdSfsp->read(IO.Offset, buff, Quantum)) <= 0) break;
2485 if (xframt >= IO.IOLen) return Response.Send(buff, xframt);
2486 if (Response.Send(kXR_oksofar, buff, xframt) < 0) return -1;
2487 IO.Offset += xframt; IO.IOLen -= xframt;
2488 if (IO.IOLen < Quantum) Quantum = IO.IOLen;
2489 } while(IO.IOLen);
2490
2491// Determine why we ended here
2492//
2493 if (xframt == 0) return Response.Send();
2494 return fsError(xframt, 0, IO.File->XrdSfsp->error, 0, 0);
2495}
2496
2497/******************************************************************************/
2498/* d o _ R e a d N o n e */
2499/******************************************************************************/
2500
2501int XrdXrootdProtocol::do_ReadNone(int &retc, int &pathID)
2502{
2504 int ralsz = Request.header.dlen;
2505 struct read_args *rargs=(struct read_args *)(argp->buff);
2506 struct readahead_list *ralsp = (readahead_list *)(rargs+1);
2507
2508// Return the pathid
2509//
2510 pathID = static_cast<int>(rargs->pathid);
2511 if ((ralsz -= sizeof(read_args)) <= 0) return 0;
2512
2513// Make sure that we have a proper pre-read list
2514//
2515 if (ralsz%sizeof(readahead_list))
2516 {Response.Send(kXR_ArgInvalid, "Invalid length for read ahead list");
2517 return 1;
2518 }
2519
2520// Run down the pre-read list
2521//
2522 while(ralsz > 0)
2523 {IO.IOLen = ntohl(ralsp->rlen);
2524 n2hll(ralsp->offset, IO.Offset);
2525 memcpy((void *)&fh.handle, (const void *)ralsp->fhandle,
2526 sizeof(fh.handle));
2527 TRACEP(FSIO, "fh="<<fh.handle<<" read "<<IO.IOLen<<'@'<<IO.Offset);
2528 if (!FTab || !(IO.File = FTab->Get(fh.handle)))
2530 "preread does not refer to an open file");
2531 return 1;
2532 }
2533 IO.File->XrdSfsp->read(IO.Offset, IO.IOLen);
2534 ralsz -= sizeof(struct readahead_list);
2535 ralsp++;
2536 numReads++;
2537 };
2538
2539// All done
2540//
2541 return 0;
2542}
2543
2544/******************************************************************************/
2545/* d o _ R e a d V */
2546/******************************************************************************/
2547
2548int XrdXrootdProtocol::do_ReadV()
2549{
2550// This will read multiple buffers at the same time in an attempt to avoid
2551// the latency in a network. The information with the offsets and lengths
2552// of the information to read is passed as a data buffer... then we decode
2553// it and put all the individual buffers in a single one it's up to the
2554// client to interpret it. Code originally developed by Leandro Franco, CERN.
2555// The readv file system code originally added by Brian Bockelman, UNL.
2556//
2557 const int hdrSZ = sizeof(readahead_list);
2558 struct XrdOucIOVec rdVec[XrdProto::maxRvecsz+1];
2559 struct readahead_list *raVec, respHdr;
2560 long long totSZ;
2561 XrdSfsXferSize rdVAmt, rdVXfr, xfrSZ = 0;
2562 int rdVBeg, rdVBreak, rdVNow, rdVNum, rdVecNum;
2563 int currFH, i, k, Quantum, Qleft, rdVecLen = Request.header.dlen;
2564 int rvMon = Monitor.InOut();
2565 int ioMon = (rvMon > 1);
2566 char *buffp, vType = (ioMon ? XROOTD_MON_READU : XROOTD_MON_READV);
2567
2568// Compute number of elements in the read vector and make sure we have no
2569// partial elements.
2570//
2571 rdVecNum = rdVecLen / sizeof(readahead_list);
2572 if ( (rdVecNum <= 0) || (rdVecNum*hdrSZ != rdVecLen) )
2573 return Response.Send(kXR_ArgInvalid, "Read vector is invalid");
2574
2575// Make sure that we can copy the read vector to our local stack. We must impose
2576// a limit on it's size. We do this to be able to reuse the data buffer to
2577// prevent cross-cpu memory cache synchronization.
2578//
2579 if (rdVecNum > XrdProto::maxRvecsz)
2580 return Response.Send(kXR_ArgTooLong, "Read vector is too long");
2581
2582// So, now we account for the number of readv requests and total segments
2583//
2584 numReadV++; numSegsV += rdVecNum;
2585
2586// Run down the list and compute the total size of the read. No individual
2587// read may be greater than the maximum transfer size. We also use this loop
2588// to copy the read ahead list to our readv vector for later processing.
2589//
2590 raVec = (readahead_list *)argp->buff;
2591 totSZ = rdVecLen; Quantum = maxReadv_ior;
2592 for (i = 0; i < rdVecNum; i++)
2593 {totSZ += (rdVec[i].size = ntohl(raVec[i].rlen));
2594 if (rdVec[i].size < 0) return Response.Send(kXR_ArgInvalid,
2595 "Readv length is negative");
2596 if (rdVec[i].size > Quantum) return Response.Send(kXR_NoMemory,
2597 "Single readv transfer is too large");
2598 rdVec[i].offset = ntohll(raVec[i].offset);
2599 memcpy(&rdVec[i].info, raVec[i].fhandle, sizeof(int));
2600 }
2601
2602// Now add an extra dummy element to force flushing of the read vector.
2603//
2604 rdVec[i].offset = -1;
2605 rdVec[i].size = 0;
2606 rdVec[i].info = -1;
2607 rdVBreak = rdVecNum;
2608 rdVecNum++;
2609
2610// We limit the total size of the read to be 2GB for convenience
2611//
2612 if (totSZ > 0x7fffffffLL)
2613 return Response.Send(kXR_NoMemory, "Total readv transfer is too large");
2614
2615// Calculate the transfer unit which will be the smaller of the maximum
2616// transfer unit and the actual amount we need to transfer.
2617//
2618 if ((Quantum = static_cast<int>(totSZ)) > maxTransz) Quantum = maxTransz;
2619
2620// Now obtain the right size buffer
2621//
2622 if ((Quantum < halfBSize && Quantum > 1024) || Quantum > argp->bsize)
2623 {if ((k = getBuff(1, Quantum)) <= 0) return k;}
2624 else if (hcNow < hcNext) hcNow++;
2625
2626// Check that we really have at least one file open. This needs to be done
2627// only once as this code runs in the control thread.
2628//
2629 if (!FTab) return Response.Send(kXR_FileNotOpen,
2630 "readv does not refer to an open file");
2631
2632// Preset the previous and current file handle to be the handle of the first
2633// element and make sure the file is actually open.
2634//
2635 currFH = rdVec[0].info;
2636 memcpy(respHdr.fhandle, &currFH, sizeof(respHdr.fhandle));
2637 if (!(IO.File = FTab->Get(currFH))) return Response.Send(kXR_FileNotOpen,
2638 "readv does not refer to an open file");
2639
2640// Setup variables for running through the list.
2641//
2642 Qleft = Quantum; buffp = argp->buff; rvSeq++;
2643 rdVBeg = rdVNow = 0; rdVXfr = rdVAmt = 0;
2644
2645// Now run through the elements
2646//
2647 for (i = 0; i < rdVecNum; i++)
2648 {if (rdVec[i].info != currFH)
2649 {xfrSZ = IO.File->XrdSfsp->readv(&rdVec[rdVNow], i-rdVNow);
2650 if (xfrSZ != rdVAmt) break;
2651 rdVNum = i - rdVBeg; rdVXfr += rdVAmt;
2652 IO.File->Stats.rvOps(rdVXfr, rdVNum);
2653 if (rvMon)
2654 {Monitor.Agent->Add_rv(IO.File->Stats.FileID, htonl(rdVXfr),
2655 htons(rdVNum), rvSeq, vType);
2656 if (ioMon) for (k = rdVBeg; k < i; k++)
2658 htonl(rdVec[k].size), htonll(rdVec[k].offset));
2659 }
2660 rdVXfr = rdVAmt = 0;
2661 if (i == rdVBreak) break;
2662 rdVBeg = rdVNow = i; currFH = rdVec[i].info;
2663 memcpy(respHdr.fhandle, &currFH, sizeof(respHdr.fhandle));
2664 if (!(IO.File = FTab->Get(currFH)))
2666 "readv does not refer to an open file");
2667 }
2668
2669 if (Qleft < (rdVec[i].size + hdrSZ))
2670 {if (rdVAmt)
2671 {xfrSZ = IO.File->XrdSfsp->readv(&rdVec[rdVNow], i-rdVNow);
2672 if (xfrSZ != rdVAmt) break;
2673 }
2674 if (Response.Send(kXR_oksofar,argp->buff,Quantum-Qleft) < 0)
2675 return -1;
2676 Qleft = Quantum;
2677 buffp = argp->buff;
2678 rdVNow = i; rdVXfr += rdVAmt; rdVAmt = 0;
2679 }
2680
2681 xfrSZ = rdVec[i].size; rdVAmt += xfrSZ;
2682 respHdr.rlen = htonl(xfrSZ);
2683 respHdr.offset = htonll(rdVec[i].offset);
2684 memcpy(buffp, &respHdr, hdrSZ);
2685 rdVec[i].data = buffp + hdrSZ;
2686 buffp += (xfrSZ+hdrSZ); Qleft -= (xfrSZ+hdrSZ);
2687 TRACEP(FSIO,"fh=" <<currFH<<" readV "<< xfrSZ <<'@'<<rdVec[i].offset);
2688 }
2689
2690// Check if we have an error here. This is indicated when rdVAmt is not zero.
2691//
2692 if (rdVAmt)
2693 {if (xfrSZ >= 0)
2694 {xfrSZ = SFS_ERROR;
2695 IO.File->XrdSfsp->error.setErrInfo(-ENODATA,"readv past EOF");
2696 }
2697 return fsError(xfrSZ, 0, IO.File->XrdSfsp->error, 0, 0);
2698 }
2699
2700// All done, return result of the last segment or just zero
2701//
2702 return (Quantum != Qleft ? Response.Send(argp->buff, Quantum-Qleft) : 0);
2703}
2704
2705/******************************************************************************/
2706/* d o _ R m */
2707/******************************************************************************/
2708
2709int XrdXrootdProtocol::do_Rm()
2710{
2711 int rc;
2712 char *opaque;
2714
2715// Check for static routing
2716//
2717 STATIC_REDIRECT(RD_rm);
2718
2719// Prescreen the path
2720//
2721 if (rpCheck(argp->buff, &opaque)) return rpEmsg("Removing", argp->buff);
2722 if (!Squash(argp->buff)) return vpEmsg("Removing", argp->buff);
2723
2724// Preform the actual function
2725//
2726 rc = osFS->rem(argp->buff, myError, CRED, opaque);
2727 TRACEP(FS, "rc=" <<rc <<" rm " <<argp->buff);
2728 if (SFS_OK == rc) return Response.Send();
2729
2730// An error occurred
2731//
2732 return fsError(rc, XROOTD_MON_RM, myError, argp->buff, opaque);
2733}
2734
2735/******************************************************************************/
2736/* d o _ R m d i r */
2737/******************************************************************************/
2738
2739int XrdXrootdProtocol::do_Rmdir()
2740{
2741 int rc;
2742 char *opaque;
2744
2745// Check for static routing
2746//
2747 STATIC_REDIRECT(RD_rmdir);
2748
2749// Prescreen the path
2750//
2751 if (rpCheck(argp->buff, &opaque)) return rpEmsg("Removing", argp->buff);
2752 if (!Squash(argp->buff)) return vpEmsg("Removing", argp->buff);
2753
2754// Preform the actual function
2755//
2756 rc = osFS->remdir(argp->buff, myError, CRED, opaque);
2757 TRACEP(FS, "rc=" <<rc <<" rmdir " <<argp->buff);
2758 if (SFS_OK == rc) return Response.Send();
2759
2760// An error occurred
2761//
2762 return fsError(rc, XROOTD_MON_RMDIR, myError, argp->buff, opaque);
2763}
2764
2765/******************************************************************************/
2766/* d o _ S e t */
2767/******************************************************************************/
2768
2769int XrdXrootdProtocol::do_Set()
2770{
2771 XrdOucTokenizer setargs(argp->buff);
2772 char *val, *rest;
2773
2774// Get the first argument
2775//
2776 if (!setargs.GetLine() || !(val = setargs.GetToken(&rest)))
2777 return Response.Send(kXR_ArgMissing, "set argument not specified.");
2778
2779// Trace this set
2780//
2781 TRACEP(DEBUG, "set " <<val <<' ' <<rest);
2782
2783// Now determine what the user wants to set
2784//
2785 if (!strcmp("appid", val))
2786 {while(*rest && *rest == ' ') rest++;
2787 eDest.Emsg("Xeq", Link->ID, "appid", rest);
2788 return Response.Send();
2789 }
2790 else if (!strcmp("monitor", val)) return do_Set_Mon(setargs);
2791 else if (!strcmp("cache", val)) return do_Set_Cache(setargs);
2792
2793// All done
2794//
2795 return Response.Send(kXR_ArgInvalid, "invalid set parameter");
2796}
2797
2798/******************************************************************************/
2799/* d o _ S e t _ C a c h e */
2800/******************************************************************************/
2801
2802// Process: set cache <cmd> <args>
2803
2804int XrdXrootdProtocol::do_Set_Cache(XrdOucTokenizer &setargs)
2805{
2807 XrdSfsFSctl myData;
2808 char *cmd, *cargs, *opaque = nullptr;
2809 const char *myArgs[2];
2810
2811// This set is valid only if we implement a cache
2812//
2813 if ((fsFeatures & XrdSfs::hasCACH) == 0)
2814 return Response.Send(kXR_ArgInvalid, "invalid set parameter");
2815
2816// Get the command and argument
2817//
2818 if (!(cmd = setargs.GetToken(&cargs)))
2819 return Response.Send(kXR_ArgMissing,"set cache argument not specified.");
2820
2821// Prescreen the path if the next token starts with a slash
2822//
2823 if (cargs && *cargs == '/')
2824 {if (rpCheck(cargs, &opaque)) return rpEmsg("Setting", cargs);
2825 if (!Squash(cargs)) return vpEmsg("Setting", cargs);
2826 myData.ArgP = myArgs; myData.Arg2Len = -2;
2827 myArgs[0] = cargs;
2828 myArgs[1] = opaque;
2829 } else {
2830 myData.Arg2 = opaque; myData.Arg2Len = (opaque ? strlen(opaque) : 0);
2831 }
2832 myData.Arg1 = cmd; myData.Arg1Len = strlen(cmd);
2833
2834// Preform the actual function using the supplied arguments
2835//
2836 int rc = osFS->FSctl(SFS_FSCTL_PLUGXC, myData, myError, CRED);
2837 TRACEP(FS, "rc=" <<rc <<"set cache " <<myData.Arg1 <<' ' <<cargs);
2838 if (rc == SFS_OK) return Response.Send("");
2839 return fsError(rc, 0, myError, 0, 0);
2840}
2841
2842/******************************************************************************/
2843/* d o _ S e t _ M o n */
2844/******************************************************************************/
2845
2846// Process: set monitor {off | on} {[appid] | info [info]}
2847
2848int XrdXrootdProtocol::do_Set_Mon(XrdOucTokenizer &setargs)
2849{
2850 char *val, *appid;
2851 kXR_unt32 myseq = 0;
2852
2853// Get the first argument
2854//
2855 if (!(val = setargs.GetToken(&appid)))
2856 return Response.Send(kXR_ArgMissing,"set monitor argument not specified.");
2857
2858// For info requests, nothing changes. However, info events must have been
2859// enabled for us to record them. Route the information via the static
2860// monitor entry, since it knows how to forward the information.
2861//
2862 if (!strcmp(val, "info"))
2863 {if (appid && Monitor.Info())
2864 {while(*appid && *appid == ' ') appid++;
2865 if (strlen(appid) > 1024) appid[1024] = '\0';
2866 if (*appid) myseq = Monitor.MapInfo(appid);
2867 }
2868 return Response.Send((void *)&myseq, sizeof(myseq));
2869 }
2870
2871// Determine if on do appropriate processing
2872//
2873 if (!strcmp(val, "on"))
2874 {Monitor.Enable();
2875 if (appid && Monitor.InOut())
2876 {while(*appid && *appid == ' ') appid++;
2877 if (*appid) Monitor.Agent->appID(appid);
2878 }
2879 if (!Monitor.Did && Monitor.Logins()) MonAuth();
2880 return Response.Send();
2881 }
2882
2883// Determine if off and do appropriate processing
2884//
2885 if (!strcmp(val, "off"))
2886 {if (appid && Monitor.InOut())
2887 {while(*appid && *appid == ' ') appid++;
2888 if (*appid) Monitor.Agent->appID(appid);
2889 }
2890 Monitor.Disable();
2891 return Response.Send();
2892 }
2893
2894// Improper request
2895//
2896 return Response.Send(kXR_ArgInvalid, "invalid set monitor argument");
2897}
2898
2899/******************************************************************************/
2900/* d o _ S t a t */
2901/******************************************************************************/
2902
2903int XrdXrootdProtocol::do_Stat()
2904{
2905 static XrdXrootdCallBack statCB("stat", XROOTD_MON_STAT);
2906 static const int fsctl_cmd = SFS_FSCTL_STATFS;
2907 bool doDig;
2908 int rc;
2909 char *opaque, xxBuff[1024];
2910 struct stat buf;
2911 XrdOucErrInfo myError(Link->ID,&statCB,ReqID.getID(),Monitor.Did,clientPV);
2912
2913// Update misc stats count
2914//
2915 SI->Bump(SI->miscCnt);
2916
2917// The stat request may refer to an open file handle. So, screen this out.
2918//
2919 if (!argp || !Request.header.dlen)
2920 {XrdXrootdFile *fp;
2923 {Response.Send(kXR_ArgMissing, "Required argument not present");
2924 return 0;
2925 }
2926 if (!FTab || !(fp = FTab->Get(fh.handle)))
2928 "stat does not refer to an open file");
2929 rc = fp->XrdSfsp->stat(&buf);
2930 TRACEP(FS, "fh=" <<fh.handle <<" stat rc=" <<rc);
2931 if (SFS_OK == rc) return Response.Send(xxBuff,
2932 StatGen(buf,xxBuff,sizeof(xxBuff)));
2933 return fsError(rc, 0, fp->XrdSfsp->error, 0, 0);
2934 }
2935
2936// Check if we are handling a dig type path
2937//
2938 doDig = (digFS && SFS_LCLROOT(argp->buff));
2939
2940// Check for static routing
2941//
2942 if (!doDig) {STATIC_REDIRECT(RD_stat);}
2943
2944// Prescreen the path
2945//
2946 if (rpCheck(argp->buff, &opaque)) return rpEmsg("Stating", argp->buff);
2947 if (!doDig && !Squash(argp->buff))return vpEmsg("Stating", argp->buff);
2948
2949// Preform the actual function, we may been to add back the opaque info
2950//
2952 {if (opaque)
2953 {int n = strlen(argp->buff); argp->buff[n] = '?';
2954 if ((argp->buff)+n != opaque-1)
2955 memmove(&argp->buff[n+1], opaque, strlen(opaque)+1);
2956 }
2957 rc = osFS->fsctl(fsctl_cmd, argp->buff, myError, CRED);
2958 TRACEP(FS, "rc=" <<rc <<" statfs " <<argp->buff);
2959 if (rc == SFS_OK) Response.Send("");
2960 } else {
2961 if (doDig) rc = digFS->stat(argp->buff, &buf, myError, CRED, opaque);
2962 else rc = osFS->stat(argp->buff, &buf, myError, CRED, opaque);
2963 TRACEP(FS, "rc=" <<rc <<" stat " <<argp->buff);
2964 if (rc == SFS_OK) return Response.Send(xxBuff,
2965 StatGen(buf,xxBuff,sizeof(xxBuff)));
2966 }
2967 return fsError(rc, (doDig ? 0 : XROOTD_MON_STAT),myError,argp->buff,opaque);
2968}
2969
2970/******************************************************************************/
2971/* d o _ S t a t x */
2972/******************************************************************************/
2973
2974int XrdXrootdProtocol::do_Statx()
2975{
2976 static XrdXrootdCallBack statxCB("xstat", XROOTD_MON_STAT);
2977 int rc;
2978 char *path, *opaque, *respinfo = argp->buff;
2979 mode_t mode;
2980 XrdOucErrInfo myError(Link->ID,&statxCB,ReqID.getID(),Monitor.Did,clientPV);
2981 XrdOucTokenizer pathlist(argp->buff);
2982
2983// Check for static routing
2984//
2985 STATIC_REDIRECT(RD_stat);
2986
2987// Cycle through all of the paths in the list
2988//
2989 while((path = pathlist.GetLine()))
2990 {if (rpCheck(path, &opaque)) return rpEmsg("Stating", path);
2991 if (!Squash(path)) return vpEmsg("Stating", path);
2992 rc = osFS->stat(path, mode, myError, CRED, opaque);
2993 TRACEP(FS, "rc=" <<rc <<" stat " <<path);
2994 if (rc != SFS_OK)
2995 return fsError(rc, XROOTD_MON_STAT, myError, path, opaque);
2996 else {if (mode == (mode_t)-1) *respinfo = (char)kXR_offline;
2997 else if (S_ISDIR(mode)) *respinfo = (char)kXR_isDir;
2998 else *respinfo = (char)kXR_file;
2999 }
3000 respinfo++;
3001 }
3002
3003// Return result
3004//
3005 return Response.Send(argp->buff, respinfo-argp->buff);
3006}
3007
3008/******************************************************************************/
3009/* d o _ S y n c */
3010/******************************************************************************/
3011
3012int XrdXrootdProtocol::do_Sync()
3013{
3014 static XrdXrootdCallBack syncCB("sync", 0);
3015 int rc;
3016 XrdXrootdFile *fp;
3018
3019// Keep Statistics
3020//
3021 SI->Bump(SI->syncCnt);
3022
3023// Find the file object
3024//
3025 if (!FTab || !(fp = FTab->Get(fh.handle)))
3026 return Response.Send(kXR_FileNotOpen,"sync does not refer to an open file");
3027
3028// The sync is elegible for a deferred response, indicate we're ok with that
3029//
3030 fp->XrdSfsp->error.setErrCB(&syncCB, ReqID.getID());
3031
3032// Sync the file
3033//
3034 rc = fp->XrdSfsp->sync();
3035 TRACEP(FS, "fh=" <<fh.handle <<" sync rc=" <<rc);
3036 if (SFS_OK != rc) return fsError(rc, 0, fp->XrdSfsp->error, 0, 0);
3037
3038// Respond that all went well
3039//
3040 return Response.Send();
3041}
3042
3043/******************************************************************************/
3044/* d o _ T r u n c a t e */
3045/******************************************************************************/
3046
3047int XrdXrootdProtocol::do_Truncate()
3048{
3049 static XrdXrootdCallBack truncCB("trunc", 0);
3050 XrdXrootdFile *fp;
3052 long long theOffset;
3053 int rc;
3054
3055// Unmarshall the data
3056//
3057 n2hll(Request.truncate.offset, theOffset);
3058
3059// Check if this is a truncate for an open file (no path given)
3060//
3061 if (!Request.header.dlen)
3062 {
3063 // Update misc stats count
3064 //
3065 SI->Bump(SI->miscCnt);
3066
3067 // Find the file object
3068 //
3069 if (!FTab || !(fp = FTab->Get(fh.handle)))
3071 "trunc does not refer to an open file");
3072
3073 // Truncate the file (it is eligible for async callbacks)
3074 //
3075 fp->XrdSfsp->error.setErrCB(&truncCB, ReqID.getID());
3076 rc = fp->XrdSfsp->truncate(theOffset);
3077 TRACEP(FS, "fh=" <<fh.handle <<" trunc rc=" <<rc <<" sz=" <<theOffset);
3078 if (SFS_OK != rc) return fsError(rc, 0, fp->XrdSfsp->error, 0, 0);
3079
3080 } else {
3081
3083 char *opaque;
3084
3085 // Check for static routing
3086 //
3087 STATIC_REDIRECT(RD_trunc);
3088
3089 // Verify the path and extract out the opaque information
3090 //
3091 if (rpCheck(argp->buff,&opaque)) return rpEmsg("Truncating",argp->buff);
3092 if (!Squash(argp->buff)) return vpEmsg("Truncating",argp->buff);
3093
3094 // Preform the actual function
3095 //
3096 rc = osFS->truncate(argp->buff, (XrdSfsFileOffset)theOffset, myError,
3097 CRED, opaque);
3098 TRACEP(FS, "rc=" <<rc <<" trunc " <<theOffset <<' ' <<argp->buff);
3099 if (SFS_OK != rc)
3100 return fsError(rc, XROOTD_MON_TRUNC, myError, argp->buff, opaque);
3101 }
3102
3103// Respond that all went well
3104//
3105 return Response.Send();
3106}
3107
3108/******************************************************************************/
3109/* d o _ W r i t e */
3110/******************************************************************************/
3111
3112int XrdXrootdProtocol::do_Write()
3113{
3114 int pathID;
3116 numWrites++;
3117
3118// Unmarshall the data
3119//
3121 n2hll(Request.write.offset, IO.Offset);
3122 pathID = static_cast<int>(Request.write.pathid);
3123
3124// Find the file object. We will drain socket data on the control path only!
3125// .
3126 if (!FTab || !(IO.File = FTab->Get(fh.handle)))
3127 {IO.File = 0;
3128 return do_WriteNone(pathID);
3129 }
3130
3131// Trace and verify that length is not negative
3132//
3133 TRACEP(FSIO, pathID<<" fh="<<fh.handle<<" write "<<IO.IOLen<<'@'<<IO.Offset);
3134 if ( IO.IOLen < 0) return Response.Send(kXR_ArgInvalid,
3135 "Write length is negative");
3136
3137// If we are monitoring, insert a write entry
3138//
3139 if (Monitor.InOut())
3142
3143// If zero length write, simply return
3144//
3145 if (!IO.IOLen) return Response.Send();
3146 IO.File->Stats.wrOps(IO.IOLen); // Optimistically correct
3147
3148// If async write allowed and it is a true write request (e.g. not chkpoint) and
3149// current conditions permit async; schedule the write to occur asynchronously
3150//
3153 {if (myStalls < as_maxstalls)
3154 {if (pathID) return do_Offload(&XrdXrootdProtocol::do_WriteAio,pathID);
3155 return do_WriteAio();
3156 }
3157 SI->AsyncRej++;
3158 myStalls--;
3159 }
3160
3161// See if an alternate path is required
3162//
3163 if (pathID) return do_Offload(&XrdXrootdProtocol::do_WriteAll, pathID);
3164
3165// Just to the i/o now
3166//
3167 return do_WriteAll();
3168}
3169
3170/******************************************************************************/
3171/* d o _ W r i t e A i o */
3172/******************************************************************************/
3173
3174// IO.File = file to be written
3175// IO.Offset = Offset at which to write
3176// IO.IOLen = Number of bytes to read from socket and write to file
3177
3178int XrdXrootdProtocol::do_WriteAio()
3179{
3180 XrdXrootdNormAio *aioP;
3181
3182// Allocate an aio request object if client hasn't exceeded the link limit
3183//
3185 || !(aioP = XrdXrootdNormAio::Alloc(this, Response, IO.File)))
3186 {SI->AsyncRej++;
3187 if (myStalls > 0) myStalls--;
3188 return do_WriteAll();
3189 }
3190
3191// Issue the write request
3192//
3193 return aioP->Write(IO.Offset, IO.IOLen);
3194}
3195
3196/******************************************************************************/
3197/* d o _ W r i t e A l l */
3198/******************************************************************************/
3199
3200// IO.File = file to be written
3201// IO.Offset = Offset at which to write
3202// IO.IOLen = Number of bytes to read from socket and write to file
3203
3204int XrdXrootdProtocol::do_WriteAll()
3205{
3206 int rc, Quantum = (IO.IOLen > maxBuffsz ? maxBuffsz : IO.IOLen);
3207
3208// Make sure we have a large enough buffer
3209//
3210 if (!argp || Quantum < halfBSize || Quantum > argp->bsize)
3211 {if ((rc = getBuff(0, Quantum)) <= 0) return rc;}
3212 else if (hcNow < hcNext) hcNow++;
3213
3214// Now write all of the data (XrdXrootdProtocol.C defines getData())
3215//
3216 while(IO.IOLen > 0)
3217 {if ((rc = getData("data", argp->buff, Quantum)))
3218 {if (rc > 0)
3219 {Resume = &XrdXrootdProtocol::do_WriteCont;
3220 myBlast = Quantum;
3221 }
3222 return rc;
3223 }
3224 if ((rc = IO.File->XrdSfsp->write(IO.Offset, argp->buff, Quantum)) < 0)
3225 {IO.IOLen = IO.IOLen-Quantum; IO.EInfo[0] = rc; IO.EInfo[1] = 0;
3226 return do_WriteNone();
3227 }
3228 IO.Offset += Quantum; IO.IOLen -= Quantum;
3229 if (IO.IOLen < Quantum) Quantum = IO.IOLen;
3230 }
3231
3232// All done
3233//
3234 return Response.Send();
3235}
3236
3237/******************************************************************************/
3238/* d o _ W r i t e C o n t */
3239/******************************************************************************/
3240
3241// IO.File = file to be written
3242// IO.Offset = Offset at which to write
3243// IO.IOLen = Number of bytes to read from socket and write to file
3244// myBlast = Number of bytes already read from the socket
3245
3246int XrdXrootdProtocol::do_WriteCont()
3247{
3248 int rc;
3249
3250// Write data that was finaly finished comming in
3251//
3252 if ((rc = IO.File->XrdSfsp->write(IO.Offset, argp->buff, myBlast)) < 0)
3253 {IO.IOLen = IO.IOLen-myBlast; IO.EInfo[0] = rc; IO.EInfo[1] = 0;
3254 return do_WriteNone();
3255 }
3256 IO.Offset += myBlast; IO.IOLen -= myBlast;
3257
3258// See if we need to finish this request in the normal way
3259//
3260 if (IO.IOLen > 0) return do_WriteAll();
3261 return Response.Send();
3262}
3263
3264/******************************************************************************/
3265/* d o _ W r i t e N o n e */
3266/******************************************************************************/
3267
3268int XrdXrootdProtocol::do_WriteNone()
3269{
3270 char *buff, dbuff[4096];
3271 int rlen, blen;
3272
3273// Determine which buffer we will use
3274//
3275 if (argp && argp->bsize > (int)sizeof(dbuff))
3276 {buff = argp->buff;
3277 blen = argp->bsize;
3278 } else {
3279 buff = dbuff;
3280 blen = sizeof(dbuff);
3281 }
3282 if (IO.IOLen < blen) blen = IO.IOLen;
3283
3284// Discard any data being transmitted
3285//
3286 TRACEP(REQ, "discarding " <<IO.IOLen <<" bytes");
3287 while(IO.IOLen > 0)
3288 {rlen = Link->Recv(buff, blen, readWait);
3289 if (rlen < 0) return Link->setEtext("link read error");
3290 IO.IOLen -= rlen;
3291 if (rlen < blen)
3292 {myBlen = 0;
3293 Resume = &XrdXrootdProtocol::do_WriteNone;
3294 return 1;
3295 }
3296 if (IO.IOLen < blen) blen = IO.IOLen;
3297 }
3298
3299// Send final message
3300//
3301 return do_WriteNoneMsg();
3302}
3303
3304/******************************************************************************/
3305
3306int XrdXrootdProtocol::do_WriteNone(int pathID, XErrorCode ec,
3307 const char *emsg)
3308{
3309// We can't recover when the data is arriving on a foriegn bound path as there
3310// no way to properly drain the socket. So, we terminate the connection.
3311//
3312 if (pathID != PathID)
3313 {if (ec && emsg) Response.Send(ec, emsg);
3314 else do_WriteNoneMsg();
3315 return Link->setEtext("write protocol violation");
3316 }
3317
3318// Set error code if present
3319//
3320 if (ec != kXR_noErrorYet)
3321 {IO.EInfo[1] = ec;
3322 if (IO.File)
3323 {if (!emsg) emsg = XProtocol::errName(ec);
3325 }
3326 }
3327
3328// Otherwise, continue to darin the socket
3329//
3330 return do_WriteNone();
3331}
3332
3333/******************************************************************************/
3334/* d o _ W r i t e N o n e M s g */
3335/******************************************************************************/
3336
3337int XrdXrootdProtocol::do_WriteNoneMsg()
3338{
3339// Send our the error message and return
3340//
3341 if (!IO.File) return
3342 Response.Send(kXR_FileNotOpen,"write does not refer to an open file");
3343
3344 if (IO.EInfo[1])
3345 return Response.Send((XErrorCode)IO.EInfo[1],
3347
3348 if (IO.EInfo[0]) return fsError(IO.EInfo[0], 0, IO.File->XrdSfsp->error, 0, 0);
3349
3351}
3352
3353/******************************************************************************/
3354/* d o _ W r i t e S p a n */
3355/******************************************************************************/
3356
3358{
3359 int rc;
3361 numWrites++;
3362
3363// Unmarshall the data
3364//
3366 n2hll(Request.write.offset, IO.Offset);
3367
3368// Find the file object. We will only drain socket data on the control path.
3369// .
3370 if (!FTab || !(IO.File = FTab->Get(fh.handle)))
3371 {IO.IOLen -= myBlast;
3372 IO.File = 0;
3373 return do_WriteNone(Request.write.pathid);
3374 }
3375
3376// If we are monitoring, insert a write entry
3377//
3378 if (Monitor.InOut())
3381 IO.File->Stats.wrOps(IO.IOLen); // Optimistically correct
3382
3383// Trace this entry
3384//
3385 TRACEP(FSIO, "fh=" <<fh.handle <<" write " <<IO.IOLen <<'@' <<IO.Offset);
3386
3387// Write data that was already read
3388//
3389 if ((rc = IO.File->XrdSfsp->write(IO.Offset, myBuff, myBlast)) < 0)
3390 {IO.IOLen = IO.IOLen-myBlast; IO.EInfo[0] = rc; IO.EInfo[1] = 0;
3391 return do_WriteNone();
3392 }
3393 IO.Offset += myBlast; IO.IOLen -= myBlast;
3394
3395// See if we need to finish this request in the normal way
3396//
3397 if (IO.IOLen > 0) return do_WriteAll();
3398 return Response.Send();
3399}
3400
3401/******************************************************************************/
3402/* d o _ W r i t e V */
3403/******************************************************************************/
3404
3405int XrdXrootdProtocol::do_WriteV()
3406{
3407// This will write multiple buffers at the same time in an attempt to avoid
3408// the disk latency. The information with the offsets and lengths of the data
3409// to write is passed as a data buffer. We attempt to optimize as best as
3410// possible, though certain combinations may result in multiple writes. Since
3411// socket flushing is nearly impossible when an error occurs, most errors
3412// simply terminate the connection.
3413//
3414 const int wveSZ = sizeof(XrdProto::write_list);
3415 struct trackInfo
3416 {XrdXrootdWVInfo **wvInfo; bool doit;
3417 trackInfo(XrdXrootdWVInfo **wvP) : wvInfo(wvP), doit(true) {}
3418 ~trackInfo() {if (doit && *wvInfo) {free(*wvInfo); *wvInfo = 0;}}
3419 } freeInfo(&wvInfo);
3420
3421 struct XrdProto::write_list *wrLst;
3422 XrdOucIOVec *wrVec;
3423 long long totSZ, maxSZ;
3424 int curFH, k, Quantum, wrVecNum, wrVecLen = Request.header.dlen;
3425
3426// Compute number of elements in the write vector and make sure we have no
3427// partial elements.
3428//
3429 wrVecNum = wrVecLen / wveSZ;
3430 if ( (wrVecLen <= 0) || (wrVecNum*wveSZ != wrVecLen) )
3431 {Response.Send(kXR_ArgInvalid, "Write vector is invalid");
3432 return -1;
3433 }
3434
3435// Make sure that we can make a copy of the read vector. So, we impose a limit
3436// on it's size.
3437//
3438 if (wrVecNum > XrdProto::maxWvecsz)
3439 {Response.Send(kXR_ArgTooLong, "Write vector is too long");
3440 return -1;
3441 }
3442
3443// Create the verctor write information structure sized as needed.
3444//
3445 if (wvInfo) free(wvInfo);
3446 wvInfo = (XrdXrootdWVInfo *)malloc(sizeof(XrdXrootdWVInfo) +
3447 sizeof(XrdOucIOVec)*(wrVecNum-1));
3448 memset(wvInfo, 0, sizeof(XrdXrootdWVInfo) - sizeof(XrdOucIOVec));
3449 wvInfo->wrVec = wrVec = wvInfo->ioVec;
3450
3451// Run down the list and compute the total size of the write. No individual
3452// write may be greater than the maximum transfer size. We also use this loop
3453// to copy the write list to our writev vector for later processing.
3454//
3455 wrLst = (XrdProto::write_list *)argp->buff;
3456 totSZ = 0; maxSZ = 0; k = 0; Quantum = maxTransz; curFH = 0;
3457 for (int i = 0; i < wrVecNum; i++)
3458 {if (wrLst[i].wlen == 0) continue;
3459 memcpy(&wrVec[k].info, wrLst[i].fhandle, sizeof(int));
3460 wrVec[k].size = ntohl(wrLst[i].wlen);
3461 if (wrVec[k].size < 0)
3462 {Response.Send(kXR_ArgInvalid, "Writev length is negtive");
3463 return -1;
3464 }
3465 if (wrVec[k].size > Quantum)
3466 {Response.Send(kXR_NoMemory,"Single writev transfer is too large");
3467 return -1;
3468 }
3469 wrVec[k].offset = ntohll(wrLst[i].offset);
3470 if (wrVec[k].info == curFH) totSZ += wrVec[k].size;
3471 else {if (maxSZ < totSZ) maxSZ = totSZ;
3472 totSZ = wrVec[k].size;
3473 }
3474 k++;
3475 }
3476
3477// Check if we are not actually writing anything, simply return success
3478//
3479 if (maxSZ < totSZ) maxSZ = totSZ;
3480 if (maxSZ == 0) return Response.Send();
3481
3482// So, now we account for the number of writev requests and total segments
3483//
3484 numWritV++; numSegsW += k; wrVecNum = k;
3485
3486// Calculate the transfer unit which will be the smaller of the maximum
3487// transfer unit and the actual amount we need to transfer.
3488//
3489 if (maxSZ > maxTransz) Quantum = maxTransz;
3490 else Quantum = static_cast<int>(maxSZ);
3491
3492// Now obtain the right size buffer
3493//
3494 if ((Quantum < halfBSize && Quantum > 1024) || Quantum > argp->bsize)
3495 {if (getBuff(0, Quantum) <= 0) return -1;}
3496 else if (hcNow < hcNext) hcNow++;
3497
3498// Check that we really have at least the first file open (part of setup)
3499//
3500 if (!FTab || !(IO.File = FTab->Get(wrVec[0].info)))
3501 {Response.Send(kXR_FileNotOpen, "writev does not refer to an open file");
3502 return -1;
3503 }
3504
3505// Setup to do the complete transfer
3506//
3507 wvInfo->curFH = wrVec[0].info;
3508 wvInfo->vBeg = 0;
3509 wvInfo->vPos = 0;
3510 wvInfo->vEnd = wrVecNum;
3511 wvInfo->vMon = 0;
3514 wvInfo->ioMon = (wvInfo->vMon > 1);
3515// wvInfo->vType = (wvInfo->ioMon ? XROOTD_MON_WRITEU : XROOTD_MON_WRITEV);
3516 IO.WVBytes = 0;
3517 IO.IOLen = wrVec[0].size;
3518 myBuff = argp->buff;
3519 myBlast = 0;
3520
3521// Now we simply start the write operations if this is a true writev request.
3522// Otherwise return to the caller for additional processing.
3523//
3524 freeInfo.doit = false;
3525 if (Request.header.requestid == kXR_writev) return do_WriteVec();
3526 return 0;
3527}
3528
3529/******************************************************************************/
3530/* d o _ W r i t e V e c */
3531/******************************************************************************/
3532
3533int XrdXrootdProtocol::do_WriteVec()
3534{
3535 XrdSfsXferSize xfrSZ;
3536 int rc, wrVNum, vNow = wvInfo->vPos;
3537 bool done, newfile;
3538
3539// Read the complete data from the socket for the current element. Note that
3540// should we enter a resume state; upon re-entry all of the data will be read.
3541//
3542do{if (IO.IOLen > 0)
3543 {wvInfo->wrVec[vNow].data = argp->buff + myBlast;
3544 myBlast += IO.IOLen;
3545 if ((rc = getData("data", myBuff, IO.IOLen)))
3546 {if (rc < 0) return rc;
3547 IO.IOLen = 0;
3548 Resume = &XrdXrootdProtocol::do_WriteVec;
3549 return rc;
3550 }
3551 }
3552
3553// Establish the state at this point as this will tell us what to do next.
3554//
3555 vNow++;
3556 done = newfile = false;
3557 if (vNow >= wvInfo->vEnd) done = true;
3558 else if (wvInfo->wrVec[vNow].info != wvInfo->curFH) newfile = true;
3559 else if (myBlast + wvInfo->wrVec[vNow].size <= argp->bsize)
3560 {IO.IOLen = wvInfo->wrVec[vNow].size;
3561 myBuff = argp->buff + myBlast;
3562 wvInfo->vPos = vNow;
3563 continue;
3564 }
3565
3566// We need to write out what we have.
3567//
3568 wrVNum = vNow - wvInfo->vBeg;
3569 xfrSZ = IO.File->XrdSfsp->writev(&(wvInfo->wrVec[wvInfo->vBeg]), wrVNum);
3570 TRACEP(FSIO,"fh=" <<wvInfo->curFH <<" writeV " << xfrSZ <<':' <<wrVNum);
3571 if (xfrSZ != myBlast) break;
3572
3573// Check if we need to do monitoring or a sync with no deferal. Note that
3574// we currently do not support detailed monitoring for vector writes!
3575//
3576 if (done || newfile)
3577 {int monVnum = vNow - wvInfo->vMon;
3578 IO.File->Stats.wvOps(IO.WVBytes, monVnum);
3588 wvInfo->vMon = vNow;
3589 IO.WVBytes = 0;
3590 if (wvInfo->doSync)
3591 {IO.File->XrdSfsp->error.setErrCB(0,0);
3592 xfrSZ = IO.File->XrdSfsp->sync();
3593 if (xfrSZ< 0) break;
3594 }
3595 }
3596
3597// If we are done, the finish up
3598//
3599 if (done)
3600 {if (wvInfo) {free(wvInfo); wvInfo = 0;}
3601 return Response.Send();
3602 }
3603
3604// Sequence to a new file if we need to do so
3605//
3606 if (newfile)
3607 {if (!FTab || !(IO.File = FTab->Get(wvInfo->wrVec[vNow].info)))
3608 {Response.Send(kXR_FileNotOpen,"writev does not refer to an open file");
3609 return -1;
3610 }
3611 wvInfo->curFH = wvInfo->wrVec[vNow].info;
3612 }
3613
3614// Setup to resume transfer
3615//
3616 myBlast = 0;
3617 myBuff = argp->buff;
3618 IO.IOLen = wvInfo->wrVec[vNow].size;
3619 wvInfo->vBeg = vNow;
3620 wvInfo->vPos = vNow;
3621
3622} while(true);
3623
3624// If we got here then there was a write error (file pointer is valid).
3625//
3626 if (wvInfo) {free(wvInfo); wvInfo = 0;}
3627 return fsError((int)xfrSZ, 0, IO.File->XrdSfsp->error, 0, 0);
3628}
3629
3630/******************************************************************************/
3631/* S e n d F i l e */
3632/******************************************************************************/
3633
3635{
3636
3637// Make sure we have some data to send
3638//
3639 if (!IO.IOLen) return 1;
3640
3641// Send off the data
3642//
3643 IO.IOLen = Response.Send(fildes, IO.Offset, IO.IOLen);
3644 return IO.IOLen;
3645}
3646
3647/******************************************************************************/
3648
3650{
3651 int i, xframt = 0;
3652
3653// Make sure we have some data to send
3654//
3655 if (!IO.IOLen) return 1;
3656
3657// Verify the length, it can't be greater than what the client wants
3658//
3659 for (i = 1; i < sfvnum; i++) xframt += sfvec[i].sendsz;
3660 if (xframt > IO.IOLen) return 1;
3661
3662// Send off the data
3663//
3664 if (xframt) IO.IOLen = Response.Send(sfvec, sfvnum, xframt);
3665 else {IO.IOLen = 0; Response.Send();}
3666 return IO.IOLen;
3667}
3668
3669/******************************************************************************/
3670/* S e t F D */
3671/******************************************************************************/
3672
3674{
3675 if (fildes < 0) IO.File->sfEnabled = 0;
3676 else IO.File->fdNum = fildes;
3677}
3678
3679/******************************************************************************/
3680/* U t i l i t y M e t h o d s */
3681/******************************************************************************/
3682/******************************************************************************/
3683/* f s E r r o r */
3684/******************************************************************************/
3685
3686int XrdXrootdProtocol::fsError(int rc, char opC, XrdOucErrInfo &myError,
3687 const char *Path, char *Cgi)
3688{
3689 int ecode, popt, rs;
3690 const char *eMsg = myError.getErrText(ecode);
3691
3692// Process standard errors
3693//
3694 if (rc == SFS_ERROR)
3695 {SI->errorCnt++;
3696 rc = XProtocol::mapError(ecode);
3697
3698 if (Path && (rc == kXR_Overloaded) && (opC == XROOTD_MON_OPENR
3699 || opC == XROOTD_MON_OPENW || opC == XROOTD_MON_OPENC))
3700 {if (myError.extData()) myError.Reset();
3701 return fsOvrld(opC, Path, Cgi);
3702 }
3703
3704 if (Path && (rc == kXR_NotFound) && RQLxist && opC
3705 && (popt = RQList.Validate(Path)))
3708 Route[popt].Host[rdType],
3709 Route[popt].Port[rdType],
3711 if (Cgi) rs = fsRedirNoEnt(eMsg, Cgi, popt);
3712 else rs = Response.Send(kXR_redirect,
3713 Route[popt].Port[rdType],
3714 Route[popt].Host[rdType]);
3715 } else rs = Response.Send((XErrorCode)rc, eMsg);
3716 if (myError.extData()) myError.Reset();
3717 return rs;
3718 }
3719
3720// Process the redirection (error msg is host:port)
3721//
3722 if (rc == SFS_REDIRECT)
3723 {SI->redirCnt++;
3724 // if the plugin set some redirect flags but the client does not
3725 // support them, clear the flags (set -1)
3726 if( ecode < -1 && !( clientPV & XrdOucEI::uRedirFlgs ) )
3727 ecode = -1;
3728 if (XrdXrootdMonitor::Redirect() && Path && opC)
3730 if (TRACING(TRACE_REDIR))
3731 {if (ecode < 0)
3732 {TRACEI(REDIR, Response.ID() <<"redirecting to " << eMsg);}
3733 else {TRACEI(REDIR, Response.ID() <<"redirecting to "
3734 << eMsg <<':' <<ecode);
3735 }
3736 }
3737 rs = Response.Send(kXR_redirect, ecode, eMsg, myError.getErrTextLen());
3738 if (myError.extData()) myError.Reset();
3739 return rs;
3740 }
3741
3742// Process the deferal. We also synchronize sending the deferal response with
3743// sending the actual deferred response by calling Done() in the callback object.
3744// This allows the requestor of he callback know that we actually send the
3745// kXR_waitresp to the end client and avoid violating time causality.
3746//
3747 if (rc == SFS_STARTED)
3748 {SI->stallCnt++;
3749 if (ecode <= 0) ecode = 1800;
3750 TRACEI(STALL, Response.ID() <<"delaying client up to " <<ecode <<" sec");
3751 rc = Response.Send(kXR_waitresp, ecode, eMsg);
3752 if (myError.getErrCB()) myError.getErrCB()->Done(ecode, &myError);
3753 if (myError.extData()) myError.Reset();
3754 return (rc ? rc : 1);
3755 }
3756
3757// Process the data response
3758//
3759 if (rc == SFS_DATA)
3760 {if (ecode) rs = Response.Send((void *)eMsg, ecode);
3761 else rs = Response.Send();
3762 if (myError.extData()) myError.Reset();
3763 return rs;
3764 }
3765
3766// Process the data response via an iovec
3767//
3768 if (rc == SFS_DATAVEC)
3769 {if (ecode < 2) rs = Response.Send();
3770 else rs = Response.Send((struct iovec *)eMsg, ecode);
3771 if (myError.getErrCB()) myError.getErrCB()->Done(ecode, &myError);
3772 if (myError.extData()) myError.Reset();
3773 return rs;
3774 }
3775
3776// Process the deferal
3777//
3778 if (rc >= SFS_STALL)
3779 {SI->stallCnt++;
3780 TRACEI(STALL, Response.ID() <<"stalling client for " <<rc <<" sec");
3781 rs = Response.Send(kXR_wait, rc, eMsg);
3782 if (myError.extData()) myError.Reset();
3783 return rs;
3784 }
3785
3786// Unknown conditions, report it
3787//
3788 {char buff[32];
3789 SI->errorCnt++;
3790 sprintf(buff, "%d", rc);
3791 eDest.Emsg("Xeq", "Unknown error code", buff, eMsg);
3793 if (myError.extData()) myError.Reset();
3794 return rs;
3795 }
3796}
3797
3798/******************************************************************************/
3799/* f s O v r l d */
3800/******************************************************************************/
3801
3802int XrdXrootdProtocol::fsOvrld(char opC, const char *Path, char *Cgi)
3803{
3804 static const char *prot = "root://";
3805 static int negOne = -1;
3806 static char quest = '?', slash = '/';
3807
3808 struct iovec rdrResp[8];
3809 char *destP=0, dest[512];
3810 int iovNum=0, pOff, port;
3811
3812// If this is a forwarded path and the client can handle full url's then
3813// redirect the client to the destination in the path. Otherwise, if there is
3814// an alternate destination, send client there. Otherwise, stall the client.
3815//
3817 && (pOff = XrdOucUtils::isFWD(Path, &port, dest, sizeof(dest))))
3818 { rdrResp[1].iov_base = (char *)&negOne;
3819 rdrResp[1].iov_len = sizeof(negOne);
3820 rdrResp[2].iov_base = (char *)prot;
3821 rdrResp[2].iov_len = 7; // root://
3822 rdrResp[3].iov_base = (char *)dest;
3823 rdrResp[3].iov_len = strlen(dest); // host:port
3824 rdrResp[4].iov_base = (char *)&slash;
3825 rdrResp[4].iov_len = (*Path == '/' ? 1 : 0); // / or nil for objid
3826 rdrResp[5].iov_base = (char *)(Path+pOff);
3827 rdrResp[5].iov_len = strlen(Path+pOff); // path
3828 if (Cgi && *Cgi)
3829 {rdrResp[6].iov_base = (char *)&quest;
3830 rdrResp[6].iov_len = sizeof(quest); // ?
3831 rdrResp[7].iov_base = (char *)Cgi;
3832 rdrResp[7].iov_len = strlen(Cgi); // cgi
3833 iovNum = 8;
3834 } else iovNum = 6;
3835 destP = dest;
3836 } else if ((destP = Route[RD_ovld].Host[rdType]))
3837 port = Route[RD_ovld].Port[rdType];
3838
3839// If a redirect happened, then trace it.
3840//
3841 if (destP)
3842 {SI->redirCnt++;
3846 if (iovNum)
3847 {TRACEI(REDIR, Response.ID() <<"redirecting to "<<dest);
3848 return Response.Send(kXR_redirect, rdrResp, iovNum);
3849 } else {
3850 TRACEI(REDIR, Response.ID() <<"redirecting to "<<destP<<':'<<port);
3851 return Response.Send(kXR_redirect, port, destP);
3852 }
3853 }
3854
3855// If there is a stall value, then delay the client
3856//
3857 if (OD_Stall)
3858 {TRACEI(STALL, Response.ID()<<"stalling client for "<<OD_Stall<<" sec");
3859 SI->stallCnt++;
3860 return Response.Send(kXR_wait, OD_Stall, "server is overloaded");
3861 }
3862
3863// We were unsuccessful, return overload as an error
3864//
3865 return Response.Send(kXR_Overloaded, "server is overloaded");
3866}
3867
3868/******************************************************************************/
3869/* f s R e d i r N o E n t */
3870/******************************************************************************/
3871
3872int XrdXrootdProtocol::fsRedirNoEnt(const char *eMsg, char *Cgi, int popt)
3873{
3874 struct iovec ioV[4];
3875 char *tried, *trend, *ptried = 0;
3876 kXR_int32 pnum = htonl(static_cast<kXR_int32>(Route[popt].Port[rdType]));
3877 int tlen;
3878
3879// Try to find the last tried token in the cgi
3880//
3881 if ((trend = Cgi))
3882 {do {if (!(tried = strstr(Cgi, "tried="))) break;
3883 if (tried == trend || *(tried-1) == '&')
3884 {if (!ptried || (*(tried+6) && *(tried+6) != '&')) ptried=tried;}
3885 Cgi = index(tried+6, '&');
3886 } while(Cgi);
3887 }
3888
3889// If we did find a tried, bracket it out with a leading comma (we can modify
3890// the passed cgi string here because this is the last time it will be used.
3891//
3892 if ((tried = ptried))
3893 {tried += 5;
3894 while(*(tried+1) && *(tried+1) == ',') tried++;
3895 trend = index(tried, '&');
3896 if (trend) {tlen = trend - tried; *trend = 0;}
3897 else tlen = strlen(tried);
3898 *tried = ',';
3899 } else tlen = 0;
3900
3901// Check if we are in a redirect loop (i.e. we are listed in the client's cgi).
3902// If so, then treat this and file not found as we've been here before.
3903//
3904 if ((trend = tried) && eMsg)
3905 do {if ((trend = strstr(trend, myCName)))
3906 {if (*(trend+myCNlen) == '\0' || *(trend+myCNlen) == ',')
3907 return Response.Send(kXR_NotFound, eMsg);
3908 trend = index(trend+myCNlen, ',');
3909 }
3910 } while(trend);
3911
3912
3913// If we have not found a tried token or that token far too large to propogate
3914// (i.e. it's likely we have an undetected loop), then do a simple redirect.
3915//
3916 if (!tried || !tlen || tlen > 16384)
3917 return Response.Send(kXR_redirect,
3918 Route[popt].Port[rdType],
3919 Route[popt].Host[rdType]);
3920
3921// We need to append the client's tried list to the one we have to avoid loops
3922//
3923
3924 ioV[1].iov_base = (char *)&pnum;
3925 ioV[1].iov_len = sizeof(pnum);
3926 ioV[2].iov_base = Route[popt].Host[rdType];
3927 ioV[2].iov_len = Route[popt].RDSz[rdType];
3928 ioV[3].iov_base = tried;
3929 ioV[3].iov_len = tlen;
3930
3931// Compute total length
3932//
3933 tlen += sizeof(pnum) + Route[popt].RDSz[rdType];
3934
3935// Send off the redirect
3936//
3937 return Response.Send(kXR_redirect, ioV, 4, tlen);
3938}
3939
3940/******************************************************************************/
3941/* g e t B u f f */
3942/******************************************************************************/
3943
3944int XrdXrootdProtocol::getBuff(const int isRead, int Quantum)
3945{
3946
3947// Check if we need to really get a new buffer
3948//
3949 if (!argp || Quantum > argp->bsize) hcNow = hcPrev;
3950 else if (Quantum >= halfBSize || hcNow-- > 0) return 1;
3951 else if (hcNext >= hcMax) hcNow = hcMax;
3952 else {int tmp = hcPrev;
3953 hcNow = hcNext;
3954 hcPrev = hcNext;
3955 hcNext = tmp+hcNext;
3956 }
3957
3958// Get a new buffer
3959//
3960 if (argp) BPool->Release(argp);
3961 if ((argp = BPool->Obtain(Quantum))) halfBSize = argp->bsize >> 1;
3962 else return Response.Send(kXR_NoMemory, (isRead ?
3963 "insufficient memory to read file" :
3964 "insufficient memory to write file"));
3965
3966// Success
3967//
3968 return 1;
3969}
3970
3971/******************************************************************************/
3972/* Private: g e t C k s T y p e */
3973/******************************************************************************/
3974
3975char *XrdXrootdProtocol::getCksType(char *opaque, char *cspec, int cslen)
3976{
3977 char *cksT;
3978
3979// Get match for user specified checksum type, if any. Otherwise return default.
3980//
3981 if (opaque && *opaque)
3982 {XrdOucEnv jobEnv(opaque);
3983 if ((cksT = jobEnv.Get("cks.type")))
3984 {XrdOucTList *tP = JobCKTLST;
3985 while(tP && strcasecmp(tP->text, cksT)) tP = tP->next;
3986 if (!tP && cspec) snprintf(cspec, cslen, "%s", cksT);
3987 return (tP ? tP->text : 0);
3988 }
3989 }
3990
3991// Return default
3992//
3993 return JobCKT;
3994}
3995
3996/******************************************************************************/
3997/* Private: l o g L o g i n */
3998/******************************************************************************/
3999
4000bool XrdXrootdProtocol::logLogin(bool xauth)
4001{
4002 const char *uName, *ipName, *tMsg, *zMsg = "";
4003 char lBuff[512], pBuff[512];
4004
4005// Determine ip type
4006//
4008 ipName = (clientPV & XrdOucEI::uIPv64 ? "IP46" : "IPv4");
4009 else ipName = (clientPV & XrdOucEI::uIPv64 ? "IP64" : "IPv6");
4010
4011// Determine client name
4012//
4013 if (xauth) uName = (Client->name ? Client->name : "nobody");
4014 else uName = 0;
4015
4016// Check if TLS was or will be used
4017//
4018 tMsg = Link->verTLS();
4019 if (*tMsg) zMsg = " ";
4020
4021// Format the line
4022//
4023 snprintf(lBuff, sizeof(lBuff), "%s %s %s%slogin%s%s",
4024 (clientPV & XrdOucEI::uPrip ? "pvt" : "pub"), ipName,
4025 tMsg, zMsg,
4026 (xauth ? " as " : ""),
4027 (uName ? uName : ""));
4028
4029// Document the login
4030//
4031 if (Client->tident != Client->pident)
4032 {snprintf(pBuff, sizeof(pBuff), "via %s auth for %s",
4034 } else *pBuff = 0;
4035 eDest.Log(SYS_LOG_01, "Xeq", Link->ID, lBuff, (*pBuff ? pBuff : 0));
4036
4037// Enable TLS if we need to (note sess setting is off if login setting is on).
4038// If we need to but the client is not TLS capable, send an error and terminate.
4039//
4040 if ((doTLS & Req_TLSSess) && !Link->hasBridge())
4041 {if (ableTLS)
4042 {if (Link->setTLS(true, tlsCtx))
4043 {Link->setProtName("xroots");
4044 isTLS = true;
4045 } else {
4046 eDest.Emsg("Xeq", "Unable to require TLS for", Link->ID);
4047 return false;
4048 }
4049 } else {
4050 eDest.Emsg("Xeq","session requires TLS but",Link->ID,"is incapable.");
4051 Response.Send(kXR_TLSRequired, "session requires TLS support");
4052 return false;
4053 }
4054 }
4055
4056// Record the appname in the final SecEntity object
4057//
4058 if (AppName) Client->eaAPI->Add("xrd.appname", (std::string)AppName);
4059
4060// Assign unique identifier to the final SecEntity object
4061//
4062 Client->ueid = mySID;
4063
4064// Propogate a connect through the whole system
4065//
4067 return true;
4068}
4069
4070/******************************************************************************/
4071/* m a p M o d e */
4072/******************************************************************************/
4073
4074#define Map_Mode(x,y) if (Mode & kXR_ ## x) newmode |= S_I ## y
4075
4076int XrdXrootdProtocol::mapMode(int Mode)
4077{
4078 int newmode = 0;
4079
4080// Map the mode in the obvious way
4081//
4082 Map_Mode(ur, RUSR); Map_Mode(uw, WUSR); Map_Mode(ux, XUSR);
4083 Map_Mode(gr, RGRP); Map_Mode(gw, WGRP); Map_Mode(gx, XGRP);
4084 Map_Mode(or, ROTH); Map_Mode(ox, XOTH);
4085
4086// All done
4087//
4088 return newmode;
4089}
4090
4091/******************************************************************************/
4092/* M o n A u t h */
4093/******************************************************************************/
4094
4096{
4097 char Buff[4096];
4098 const char *bP = Buff;
4099
4100 if (Client == &Entity) bP = Entity.moninfo;
4101 else {snprintf(Buff,sizeof(Buff),
4102 "&p=%s&n=%s&h=%s&o=%s&r=%s&g=%s&m=%s%s&I=%c",
4103 Client->prot,
4104 (Client->name ? Client->name : ""),
4105 (Client->host ? Client->host : ""),
4106 (Client->vorg ? Client->vorg : ""),
4107 (Client->role ? Client->role : ""),
4108 (Client->grps ? Client->grps : ""),
4109 (Client->moninfo ? Client->moninfo : ""),
4110 (Entity.moninfo ? Entity.moninfo : ""),
4111 (clientPV & XrdOucEI::uIPv4 ? '4' : '6')
4112 );
4113 Client->secMon = &Monitor;
4114 }
4115
4116 Monitor.Report(bP);
4117 if (Entity.moninfo) {free(Entity.moninfo); Entity.moninfo = 0;}
4118}
4119
4120/******************************************************************************/
4121/* r p C h e c k */
4122/******************************************************************************/
4123
4124int XrdXrootdProtocol::rpCheck(char *fn, char **opaque)
4125{
4126 char *cp;
4127
4128 if (*fn != '/')
4129 {if (!(XPList.Opts() & XROOTDXP_NOSLASH)) return 1;
4130 if ( XPList.Opts() & XROOTDXP_NOCGI) {*opaque = 0; return 0;}
4131 }
4132
4133 if (!(cp = index(fn, '?'))) *opaque = 0;
4134 else {*cp = '\0'; *opaque = cp+1;
4135 if (!**opaque) *opaque = 0;
4136 }
4137
4138 if (*fn != '/') return 0;
4139
4140 while ((cp = index(fn, '/')))
4141 {fn = cp+1;
4142 if (fn[0] == '.' && fn[1] == '.' && fn[2] == '/') return 1;
4143 }
4144 return 0;
4145}
4146
4147/******************************************************************************/
4148/* r p E m s g */
4149/******************************************************************************/
4150
4151int XrdXrootdProtocol::rpEmsg(const char *op, char *fn)
4152{
4153 char buff[2048];
4154 snprintf(buff,sizeof(buff)-1,"%s relative path '%s' is disallowed.",op,fn);
4155 buff[sizeof(buff)-1] = '\0';
4156 return Response.Send(kXR_NotAuthorized, buff);
4157}
4158
4159/******************************************************************************/
4160/* S e t S F */
4161/******************************************************************************/
4162
4163int XrdXrootdProtocol::SetSF(kXR_char *fhandle, bool seton)
4164{
4165 XrdXrootdFHandle fh(fhandle);
4166 XrdXrootdFile *theFile;
4167
4168 if (!FTab || !(theFile = FTab->Get(fh.handle))) return -EBADF;
4169
4170// Turn it off or on if so wanted
4171//
4172 if (!seton) theFile->sfEnabled = 0;
4173 else if (theFile->fdNum >= 0) theFile->sfEnabled = 1;
4174
4175// All done
4176//
4177 return 0;
4178}
4179
4180/******************************************************************************/
4181/* S q u a s h */
4182/******************************************************************************/
4183
4184int XrdXrootdProtocol::Squash(char *fn)
4185{
4186 char *ofn, *ifn = fn;
4187
4188 if (*fn != '/') return XPList.Opts();
4189
4190 while(*ifn)
4191 {if (*ifn == '/')
4192 if (*(ifn+1) == '/'
4193 || (*(ifn+1) == '.' && *(ifn+1) && *(ifn+2) == '/')) break;
4194 ifn++;
4195 }
4196
4197 if (!*ifn) return XPList.Validate(fn, ifn-fn);
4198
4199 ofn = ifn;
4200 while(*ifn) {*ofn = *ifn++;
4201 while(*ofn == '/')
4202 {while(*ifn == '/') ifn++;
4203 if (ifn[0] == '.' && ifn[1] == '/') ifn += 2;
4204 else break;
4205 }
4206 ofn++;
4207 }
4208 *ofn = '\0';
4209
4210 return XPList.Validate(fn, ofn-fn);
4211}
4212
4213/******************************************************************************/
4214/* v p E m s g */
4215/******************************************************************************/
4216
4217int XrdXrootdProtocol::vpEmsg(const char *op, char *fn)
4218{
4219 char buff[2048];
4220 snprintf(buff,sizeof(buff)-1,"%s path '%s' is disallowed.",op,fn);
4221 buff[sizeof(buff)-1] = '\0';
4222 return Response.Send(kXR_NotAuthorized, buff);
4223}
kXR_char options[1]
Definition XProtocol.hh:248
XErrorCode
Definition XProtocol.hh:989
@ kXR_ArgInvalid
Definition XProtocol.hh:990
@ kXR_InvalidRequest
Definition XProtocol.hh:996
@ kXR_ArgMissing
Definition XProtocol.hh:991
@ kXR_TLSRequired
@ kXR_AuthFailed
@ kXR_NotAuthorized
@ kXR_NotFound
@ kXR_FileLocked
Definition XProtocol.hh:993
@ kXR_noErrorYet
@ kXR_ChkSumErr
@ kXR_overQuota
@ kXR_FileNotOpen
Definition XProtocol.hh:994
@ kXR_Unsupported
@ kXR_Cancelled
@ kXR_ServerError
@ kXR_Overloaded
@ kXR_ArgTooLong
Definition XProtocol.hh:992
@ kXR_FSError
Definition XProtocol.hh:995
@ kXR_NoMemory
Definition XProtocol.hh:998
kXR_int16 arg1len
Definition XProtocol.hh:430
struct ClientTruncateRequest truncate
Definition XProtocol.hh:875
@ kXR_ecredir
Definition XProtocol.hh:371
#define kXR_ShortProtRespLen
kXR_char fhandle[4]
Definition XProtocol.hh:782
#define kXR_gotoTLS
struct ClientCloseRequest close
Definition XProtocol.hh:851
kXR_char fhandle[4]
Definition XProtocol.hh:807
#define kXR_haveTLS
kXR_char streamid[2]
Definition XProtocol.hh:156
kXR_char fhandle[4]
Definition XProtocol.hh:771
struct ClientMkdirRequest mkdir
Definition XProtocol.hh:858
kXR_int32 dlen
Definition XProtocol.hh:431
struct ClientAuthRequest auth
Definition XProtocol.hh:847
kXR_unt16 options
Definition XProtocol.hh:481
#define kXR_PROTSIGNVERSION
Definition XProtocol.hh:74
struct ClientDirlistRequest dirlist
Definition XProtocol.hh:852
kXR_char pathid
Definition XProtocol.hh:653
kXR_char credtype[4]
Definition XProtocol.hh:170
kXR_char username[8]
Definition XProtocol.hh:396
@ kXR_open_wrto
Definition XProtocol.hh:469
@ kXR_compress
Definition XProtocol.hh:452
@ kXR_async
Definition XProtocol.hh:458
@ kXR_delete
Definition XProtocol.hh:453
@ kXR_prefname
Definition XProtocol.hh:461
@ kXR_nowait
Definition XProtocol.hh:467
@ kXR_open_read
Definition XProtocol.hh:456
@ kXR_open_updt
Definition XProtocol.hh:457
@ kXR_mkpath
Definition XProtocol.hh:460
@ kXR_seqio
Definition XProtocol.hh:468
@ kXR_replica
Definition XProtocol.hh:465
@ kXR_posc
Definition XProtocol.hh:466
@ kXR_refresh
Definition XProtocol.hh:459
@ kXR_new
Definition XProtocol.hh:455
@ kXR_force
Definition XProtocol.hh:454
@ kXR_4dirlist
Definition XProtocol.hh:464
@ kXR_retstat
Definition XProtocol.hh:463
struct ClientOpenRequest open
Definition XProtocol.hh:860
@ kXR_waitresp
Definition XProtocol.hh:906
@ kXR_redirect
Definition XProtocol.hh:904
@ kXR_oksofar
Definition XProtocol.hh:900
@ kXR_ok
Definition XProtocol.hh:899
@ kXR_authmore
Definition XProtocol.hh:902
@ kXR_wait
Definition XProtocol.hh:905
@ kXR_dstat
Definition XProtocol.hh:240
@ kXR_dcksm
Definition XProtocol.hh:241
struct ClientRequestHdr header
Definition XProtocol.hh:846
kXR_char fhandle[4]
Definition XProtocol.hh:645
kXR_char fhandle[4]
Definition XProtocol.hh:659
struct ClientWriteVRequest writev
Definition XProtocol.hh:877
kXR_char fhandle[4]
Definition XProtocol.hh:229
struct ClientLoginRequest login
Definition XProtocol.hh:857
kXR_unt16 requestid
Definition XProtocol.hh:157
kXR_char fhandle[4]
Definition XProtocol.hh:633
kXR_char sessid[16]
Definition XProtocol.hh:181
@ kXR_writev
Definition XProtocol.hh:143
@ kXR_write
Definition XProtocol.hh:131
struct ClientChmodRequest chmod
Definition XProtocol.hh:850
struct ClientQueryRequest query
Definition XProtocol.hh:866
struct ClientReadRequest read
Definition XProtocol.hh:867
struct ClientMvRequest mv
Definition XProtocol.hh:859
kXR_int32 rlen
Definition XProtocol.hh:660
kXR_char sessid[16]
Definition XProtocol.hh:259
struct ClientBindRequest bind
Definition XProtocol.hh:848
@ kXR_vermask
Definition XProtocol.hh:377
@ kXR_asyncap
Definition XProtocol.hh:378
#define kXR_attrProxy
kXR_char options[1]
Definition XProtocol.hh:416
#define kXR_PROTOCOLVERSION
Definition XProtocol.hh:70
struct ClientEndsessRequest endsess
Definition XProtocol.hh:853
struct ClientSyncRequest sync
Definition XProtocol.hh:874
kXR_int64 offset
Definition XProtocol.hh:661
@ kXR_vfs
Definition XProtocol.hh:763
struct ClientPrepareRequest prepare
Definition XProtocol.hh:864
@ kXR_mkdirpath
Definition XProtocol.hh:410
@ kXR_wmode
Definition XProtocol.hh:591
@ kXR_evict
Definition XProtocol.hh:596
@ kXR_usetcp
Definition XProtocol.hh:594
@ kXR_cancel
Definition XProtocol.hh:587
@ kXR_fresh
Definition XProtocol.hh:593
@ kXR_notify
Definition XProtocol.hh:588
@ kXR_coloc
Definition XProtocol.hh:592
@ kXR_stage
Definition XProtocol.hh:590
@ kXR_noerrs
Definition XProtocol.hh:589
struct ClientStatRequest stat
Definition XProtocol.hh:873
struct ClientWriteRequest write
Definition XProtocol.hh:876
ServerResponseReqs_Protocol secreq
kXR_char capver[1]
Definition XProtocol.hh:399
struct ClientProtocolRequest protocol
Definition XProtocol.hh:865
@ kXR_file
@ kXR_isDir
@ kXR_offline
@ kXR_QPrep
Definition XProtocol.hh:616
@ kXR_Qopaqug
Definition XProtocol.hh:625
@ kXR_Qconfig
Definition XProtocol.hh:621
@ kXR_Qopaquf
Definition XProtocol.hh:624
@ kXR_Qckscan
Definition XProtocol.hh:620
@ kXR_Qxattr
Definition XProtocol.hh:618
@ kXR_Qspace
Definition XProtocol.hh:619
@ kXR_Qvisa
Definition XProtocol.hh:622
@ kXR_QStats
Definition XProtocol.hh:615
@ kXR_Qcksum
Definition XProtocol.hh:617
@ kXR_Qopaque
Definition XProtocol.hh:623
struct ClientLocateRequest locate
Definition XProtocol.hh:856
@ kXR_ver001
Definition XProtocol.hh:385
@ kXR_ver003
Definition XProtocol.hh:387
@ kXR_ver004
Definition XProtocol.hh:388
@ kXR_ver002
Definition XProtocol.hh:386
@ kXR_readrdok
Definition XProtocol.hh:360
@ kXR_fullurl
Definition XProtocol.hh:358
@ kXR_lclfile
Definition XProtocol.hh:364
@ kXR_multipr
Definition XProtocol.hh:359
@ kXR_redirflags
Definition XProtocol.hh:365
@ kXR_hasipv64
Definition XProtocol.hh:361
int kXR_int32
Definition XPtypes.hh:89
unsigned int kXR_unt32
Definition XPtypes.hh:90
unsigned char kXR_char
Definition XPtypes.hh:65
#define DEBUG(x)
struct stat Stat
Definition XrdCks.cc:49
void usage()
#define TRACE_AUTH
#define TRACE_REDIR
#define ENODATA
#define stat(a, b)
Definition XrdPosix.hh:101
int Mode
XrdOucString Path
#define eMsg(x)
struct myOpts opts
int emsg(int rc, char *msg)
#define Prep_EVICT
int XrdSfsMode
#define SFS_DATAVEC
#define SFS_O_HNAME
#define Prep_FRESH
const char * Arg1
PLUGINO, PLUGION, PLUGXC.
#define SFS_DATA
int Arg2Len
Length or -count of args in extension.
#define Prep_CANCEL
#define SFS_O_RESET
#define SFS_O_DIRLIST
#define SFS_FSCTL_STATFS
#define Prep_QUERY
char * notify
Notification path or 0.
XrdOucTList * paths
List of paths.
XrdOucTList * oinfo
1-to-1 correspondence of opaque info
#define SFS_ERROR
#define Prep_WMODE
#define SFS_LCLROOT(x)
#define SFS_O_SEQIO
#define SFS_O_NOTPC
#define SFS_O_FORCE
#define SFS_O_POSC
#define SFS_FCTL_STATV
#define SFS_REDIRECT
#define Prep_PRTY3
#define Prep_PRTY0
#define SFS_O_MKPTH
#define Prep_PRTY2
#define SFS_STALL
#define SFS_O_RDONLY
#define SFS_STARTED
#define Prep_COLOC
#define SFS_O_MULTIW
#define SFS_FSCTL_STATLS
#define Prep_STAGE
#define SFS_FSCTL_STATCC
char * reqid
Request ID.
#define SFS_O_WRONLY
#define SFS_O_CREAT
#define SFS_FSCTL_STATXA
#define SFS_FSCTL_LOCATE
#define SFS_O_RAWIO
#define SFS_O_RDWR
#define Prep_PRTY1
#define Prep_SENDACK
#define SFS_FSCTL_PLUGIO
#define SFS_O_LOCAL
int XrdSfsFileOpenMode
int Arg1Len
Length.
#define SFS_FCTL_SPEC1
#define SFS_OK
long long XrdSfsFileOffset
#define SFS_LCLPATH(x)
#define SFS_O_NOWAIT
#define SFS_FSCTL_PLUGXC
int opts
Prep_xxx.
#define SFS_O_REPLICA
#define SFS_FSCTL_PLUGIN
#define SFS_O_TRUNC
int XrdSfsXferSize
#define Prep_SENDAOK
< Prepare parameters
< SFS_FSCTL_PLUGIN/PLUGIO/PLUGXC parms
const char * XrdSysE2T(int errcode)
Definition XrdSysE2T.cc:104
const int SYS_LOG_01
if(ec< 0) ec
#define TRACING(x)
Definition XrdTrace.hh:70
#define TRACEI(act, x)
Definition XrdTrace.hh:66
XrdOucString * XrdXrootdCF
#define JOB_Sync
const kXR_char XROOTD_MON_OPENW
const kXR_char XROOTD_MON_STAT
const kXR_char XROOTD_MON_REDLOCAL
const kXR_char XROOTD_MON_PREP
const kXR_char XROOTD_MON_OPENC
const kXR_char XROOTD_MON_TRUNC
const kXR_char XROOTD_MON_CLOSE
const kXR_char XROOTD_MON_CHMOD
const kXR_char XROOTD_MON_LOCATE
const kXR_char XROOTD_MON_OPENR
const kXR_char XROOTD_MON_MV
const kXR_char XROOTD_MON_RMDIR
const kXR_char XROOTD_MON_RM
const kXR_char XROOTD_MON_OPENDIR
const kXR_char XROOTD_MON_QUERY
const kXR_char XROOTD_MON_MKDIR
#define XRD_BOUNDPATH
#define XRD_LOGGEDIN
#define XRD_NEED_AUTH
#define TRACE_FS
#define TRACEP(act, x)
XrdOucIOVec ioVec[1]
XrdOucIOVec * wrVec
#define XROOTDXP_NOLK
#define XROOTDXP_NOSLASH
#define XROOTDXP_NOMWCHK
#define XROOTDXP_NOCGI
XrdSysTrace XrdXrootdTrace
#define Map_Mode(x, y)
#define STATIC_REDIRECT(xfnc)
#define CRED
static const char * errName(kXR_int32 errCode)
Definition XProtocol.cc:130
static int mapError(int rc)
void Release(XrdBuffer *bp)
Definition XrdBuffer.cc:221
XrdBuffer * Obtain(int bsz)
Definition XrdBuffer.cc:140
char * buff
Definition XrdBuffer.hh:45
static const int ValuSize
Definition XrdCksData.hh:42
static const int NameSize
Definition XrdCksData.hh:41
static bool GetAssumeV4()
Definition XrdInet.hh:65
static XrdLink * fd2link(int fd)
Definition XrdLinkCtl.hh:72
bool isMapped() const
bool isIPType(IPType ipType) const
bool getEA(int &ec, int &ac)
static bool getEA(const char *cgi, int &ecode, int &acode)
virtual Handle * Begin(XrdSecEntity &Client, const char *path=0, const char *cgi=0, const char *app=0)=0
virtual void Done(int &Result, XrdOucErrInfo *eInfo, const char *Path=0)=0
XrdOucEICB * getErrCB()
void setErrCB(XrdOucEICB *cb, unsigned long long cbarg=0)
const char * getErrText()
int setErrInfo(int code, const char *emsg)
void setUCap(int ucval)
Set user capabilties.
void Reset()
Reset object to no message state. Call this method to release appendages.
char * ID(char *buff, int blen)
char * isMine(char *reqid, int &hport, char *hname, int hlen)
void Bump(int &val)
int length() const
const char * c_str() const
XrdOucTList * next
char * GetToken(char **rest=0, int lowcase=0)
static void Sanitize(char *instr, char subc='_')
static int isFWD(const char *path, int *port=0, char *hBuff=0, int hBLen=0, bool pTrim=false)
void Schedule(XrdJob *jp)
bool Add(XrdSecAttr &attr)
XrdSecAttr * Get(const void *sigkey)
char * vorg
Entity's virtual organization(s)
const char * pident
Trace identifier (originator)
XrdNetAddrInfo * addrInfo
Entity's connection details.
XrdSecEntityAttr * eaAPI
non-const API to attributes
const char * tident
Trace identifier always preset.
char prot[XrdSecPROTOIDSIZE]
Auth protocol used (e.g. krb5)
XrdSecMonitor * secMon
If !0 security monitoring enabled.
char * grps
Entity's group name(s)
char * name
Entity's name.
unsigned int ueid
Unique ID of entity instance.
char * role
Entity's role(s)
void Display(XrdSysError &mDest)
char * moninfo
Information for monitoring.
char * host
Entity's host name dnr dependent.
virtual XrdSecProtect * New4Server(XrdSecProtocol &aprot, int plvl)
virtual int ProtResp(ServerResponseReqs_Protocol &resp, XrdNetAddrInfo &nai, int pver)
XrdSecEntity Entity
virtual void Delete()=0
Delete the protocol object. DO NOT use C++ delete() on this object.
virtual int Authenticate(XrdSecCredentials *cred, XrdSecParameters **parms, XrdOucErrInfo *einfo=0)=0
virtual XrdSecProtocol * getProtocol(const char *host, XrdNetAddrInfo &endPoint, const XrdSecCredentials *cred, XrdOucErrInfo &einfo)=0
virtual bool PostProcess(XrdSecEntity &entity, XrdOucErrInfo &einfo)
virtual const char * getParms(int &size, XrdNetAddrInfo *endPoint=0)=0
virtual int autoStat(struct stat *buf)
virtual int open(const char *path, const XrdSecEntity *client=0, const char *opaque=0)=0
XrdOucErrInfo & error
virtual const char * nextEntry()=0
virtual int close()=0
virtual void Connect(const XrdSecEntity *client=0)
virtual int chmod(const char *path, XrdSfsMode mode, XrdOucErrInfo &eInfo, const XrdSecEntity *client=0, const char *opaque=0)=0
virtual int fsctl(const int cmd, const char *args, XrdOucErrInfo &eInfo, const XrdSecEntity *client=0)=0
virtual int rename(const char *oPath, const char *nPath, XrdOucErrInfo &eInfo, const XrdSecEntity *client=0, const char *opaqueO=0, const char *opaqueN=0)=0
virtual int mkdir(const char *path, XrdSfsMode mode, XrdOucErrInfo &eInfo, const XrdSecEntity *client=0, const char *opaque=0)=0
virtual int FSctl(const int cmd, XrdSfsFSctl &args, XrdOucErrInfo &eInfo, const XrdSecEntity *client=0)
virtual XrdSfsFile * newFile(char *user=0, int MonID=0)=0
virtual int truncate(const char *path, XrdSfsFileOffset fsize, XrdOucErrInfo &eInfo, const XrdSecEntity *client=0, const char *opaque=0)=0
virtual int chksum(csFunc Func, const char *csName, const char *path, XrdOucErrInfo &eInfo, const XrdSecEntity *client=0, const char *opaque=0)
virtual int remdir(const char *path, XrdOucErrInfo &eInfo, const XrdSecEntity *client=0, const char *opaque=0)=0
virtual int prepare(XrdSfsPrep &pargs, XrdOucErrInfo &eInfo, const XrdSecEntity *client=0)=0
virtual int stat(const char *Name, struct stat *buf, XrdOucErrInfo &eInfo, const XrdSecEntity *client=0, const char *opaque=0)=0
virtual int rem(const char *path, XrdOucErrInfo &eInfo, const XrdSecEntity *client=0, const char *opaque=0)=0
virtual XrdSfsDirectory * newDir(char *user=0, int MonID=0)=0
virtual XrdSfsXferSize writev(XrdOucIOVec *writeV, int wdvCnt)
virtual int sync()=0
XrdOucErrInfo & error
virtual int SendData(XrdSfsDio *sfDio, XrdSfsFileOffset offset, XrdSfsXferSize size)
virtual int open(const char *fileName, XrdSfsFileOpenMode openMode, mode_t createMode, const XrdSecEntity *client=0, const char *opaque=0)=0
virtual XrdSfsXferSize read(XrdSfsFileOffset offset, XrdSfsXferSize size)=0
virtual XrdSfsXferSize readv(XrdOucIOVec *readV, int rdvCnt)
virtual int truncate(XrdSfsFileOffset fsize)=0
virtual int getCXinfo(char cxtype[4], int &cxrsz)=0
virtual int stat(struct stat *buf)=0
virtual void setXio(XrdSfsXio *xioP)
virtual int fctl(const int cmd, const char *args, XrdOucErrInfo &eInfo)=0
virtual XrdSfsXferSize write(XrdSfsFileOffset offset, const char *buffer, XrdSfsXferSize size)=0
int Emsg(const char *esfx, int ecode, const char *text1, const char *text2=0)
void Log(int mask, const char *esfx, const char *text1, const char *text2=0, const char *text3=0)
static void Snooze(int seconds)
virtual void numLocks(const char *path, int &rcnt, int &wcnt)=0
virtual int Unlock(const char *path, char mode)=0
virtual int Lock(const char *path, char mode, bool force)=0
void rvOps(int rsz, int ssz)
void wvOps(int wsz, int ssz)
int Add(XrdXrootdFile *fp)
XrdXrootdFile * Get(int fnum)
XrdXrootdFile * Del(XrdXrootdMonitor *monP, int fnum, bool dodel=true)
void Ref(int num)
XrdXrootdPgwFob * pgwFob
XrdSfsFile * XrdSfsp
XrdXrootdAioFob * aioFob
XrdXrootdFileStats Stats
int Schedule(const char *jkey, const char **args, XrdXrootdResponse *resp, int Opts=0)
int Cancel(const char *jkey=0, XrdXrootdResponse *resp=0)
static void Open(XrdXrootdFileStats *fsP, const char *Path, unsigned int uDID, bool isRW)
kXR_unt32 MapInfo(const char *Info)
kXR_unt32 MapPath(const char *Path)
void Register(const char *Uname, const char *Hname, const char *Pname, unsigned int xSID=0)
void Report(const char *Info)
XrdXrootdMonitor * Agent
void appID(char *id)
void Add_rv(kXR_unt32 dictid, kXR_int32 rlen, kXR_int16 vcnt, kXR_char vseq, kXR_char vtype)
void Add_rd(kXR_unt32 dictid, kXR_int32 rlen, kXR_int64 offset)
void Add_wr(kXR_unt32 dictid, kXR_int32 wlen, kXR_int64 offset)
void Open(kXR_unt32 dictid, off_t fsize)
int Write(long long offs, int dlen) override
void Read(long long offs, int dlen) override
static XrdXrootdNormAio * Alloc(XrdXrootdProtocol *protP, XrdXrootdResponse &resp, XrdXrootdFile *fP)
XrdXrootdPio * Next
XrdXrootd::IOParms IO
int(XrdXrootdProtocol::* ResumePio)()
static XrdXrootdPio * Alloc(int n=1)
kXR_char StreamID[2]
void Set(int(XrdXrootdProtocol::*Invoke)(), XrdXrootd::IOParms &io, const kXR_char *theSID)
static int List(XrdXrootdPrepArgs &pargs, char *resp, int resplen)
static void Log(XrdXrootdPrepArgs &pargs)
static void Logdel(char *reqid)
static XrdXrootdStats * SI
int SendFile(int fildes) override
XrdXrootdProtocol * VerifyStream(int &rc, int pID, bool lok=true)
static XrdSfsFileSystem * digFS
int SetSF(kXR_char *fhandle, bool seton=false)
XrdSecProtect * Protect
XrdNetPMark::Handle * pmHandle
static XrdNetPMark * PMark
XrdXrootdProtocol * Stream[maxStreams]
XrdXrootd::IOParms IO
static XrdXrootdXPath RPList
static const char Req_TLSGPFile
void SetFD(int fildes) override
static const char Req_TLSSess
XrdXrootdWVInfo * wvInfo
XrdSysSemaphore * reTry
XrdXrootdFileTable * FTab
static XrdXrootdJob * JobCKS
static XrdSysError & eDest
static unsigned int getSID()
XrdSecProtocol * AuthProt
int getData(gdCallBack *gdcbP, const char *dtype, char *buff, int blen)
XrdXrootdMonitor::User Monitor
static const char * myCName
static const char Req_TLSData
static XrdXrootdFileLock * Locker
static const int maxPio
int(XrdXrootdProtocol::* Resume)()
static const char Req_TLSTPC
static XrdTlsContext * tlsCtx
static XrdXrootdXPath XPList
static const char Req_TLSLogin
XrdXrootdResponse Response
int(XrdXrootdProtocol::* ResumePio)()
static const int maxStreams
static XrdOucTList * JobCKTLST
static XrdXrootdXPath RQList
static XrdSecProtector * DHS
static XrdBuffManager * BPool
static XrdSecService * CIA
static RAtomic_int srvrAioOps
static uint64_t fsFeatures
static XrdOucReqID * PrepID
XrdXrootdPio * pioFirst
XrdSysCondVar2 * endNote
static struct XrdXrootdProtocol::RD_Table Route[RD_Num]
static XrdSfsFileSystem * osFS
void setID(unsigned long long id)
unsigned long long getID()
void Set(XrdLink *lp)
int Stats(char *buff, int blen, int do_sync=0)
int Validate(const char *pd, const int pl=0)
XrdXrootdXPath * Next()
XrdScheduler Sched
Definition XrdLinkCtl.cc:54
static const int maxRvecsz
Definition XProtocol.hh:686
static const int maxWvecsz
Definition XProtocol.hh:838
static const uint64_t hasCACH
Feature: Implements a data cache.
static const uint64_t hasSXIO
Feature: Supports SfsXio.
ssize_t Send(int fd, KernelBuffer &buffer)
char * bifResp[2]
static const kXR_int32 doSync
Definition XProtocol.hh:826
char TimeZone
+/- hours from GMT (-128 if not set)
unsigned char Country[2]
Two letter TLD country code.
static const int uRedirFlgs
ucap: Client supports "file://"
static const int uVMask
static const int uUrlOK
ucap: Supports async responses
static const int uIPv64
ucap: Supports only IPv4 info
static const int uReadR
ucap: Supports multiple protocols
static const int uEcRedir
ucap: Client supports redirect flags
static const int uMProt
ucap: Supports url redirects
static const int uLclF
ucap: Client is on a private net
static const int uAsync
ucap: Extract protocol version
static const int uIPv4
ucap: Supports read redirects
static const int uPrip
long long offset
Generic structure to pass security information back and forth.
char * buffer
Pointer to the buffer.
int size
Size of the buffer or length of data in the buffer.
unsigned int Sid
unsigned int Inst
static const int useSF
static const int useBasic
static const int useMMap