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