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;
166 XrdOucErrInfo eMsg;
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 }
195 AuthProt->Entity.tident = AuthProt->Entity.pident = Link->ID;
196 numReads++;
197 }
198
199// Now try to authenticate the client using the current protocol
200//
201 if (!(rc = AuthProt->Authenticate(&cred, &parm, &eMsg))
202 && CIA->PostProcess(AuthProt->Entity, eMsg))
203 {rc = Response.Send(); Status &= ~XRD_NEED_AUTH; SI->Bump(SI->LoginAU);
204 AuthProt->Entity.ueid = mySID;
205 Client = &AuthProt->Entity; numReads = 0; strcpy(Entity.prot, "host");
206 if (TRACING(TRACE_AUTH)) Client->Display(eDest);
207 if (DHS) Protect = DHS->New4Server(*AuthProt,clientPV&XrdOucEI::uVMask);
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{
247 XrdXrootdSessID *sp = (XrdXrootdSessID *)Request.bind.sessid;
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;
377 XrdOucErrInfo myError(Link->ID, Monitor.Did, clientPV);
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)
427 {if (JobCKS) JobCKS->Cancel(argp->buff, &Response);
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 = ' ';
484 XrdOucErrInfo myError(Link->ID, Monitor.Did, clientPV);
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;
524 XrdXrootdFHandle fh(Request.close.fhandle);
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)))
535 return Response.Send(kXR_FileNotOpen,
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//
649 if (Request.dirlist.options[0] & (kXR_dstat | kXR_dcksm))
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{
696 XrdOucErrInfo myError(Link->ID, Monitor.Did, clientPV);
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)
765 {int ec = osFS->chksum(XrdSfsFileSystem::csGet, 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//
817 sp = (XrdXrootdSessID *)Request.endsess.sessid;
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 }
966 return Response.Send(kXR_TLSRequired, emsg);
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//
978 if (Status) return Response.Send(kXR_InvalidRequest,
979 "duplicate login; already logged in");
980
981// Establish the ID for this link
982//
983 Link->setID(uname, pid);
984 CapVer = Request.login.capver[0];
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 }
1003 if (Request.login.ability & kXR_fullurl)
1005 if (Request.login.ability & kXR_lclfile)
1007 if (Request.login.ability & kXR_multipr)
1009 if (Request.login.ability & kXR_readrdok)
1011 if (Request.login.ability & kXR_hasipv64)
1013 if (Request.login.ability & kXR_redirflags)
1015 if (Request.login.ability2 & kXR_ecredir )
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());
1058 Status = XRD_LOGGEDIN; SI->Bump(SI->LoginUA);
1059 }
1060 }
1061 else {rc = (sendSID ? Response.Send((void *)&sessID, sizeof(sessID))
1062 : Response.Send());
1063 Status = XRD_LOGGEDIN; SI->Bump(SI->LoginUA);
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//
1071 Entity.tident = Entity.pident = Link->ID;
1072 Entity.addrInfo = Link->AddrInfo();
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)))
1114 {Monitor.Report(Entity.moninfo);
1115 if (Entity.moninfo) {free(Entity.moninfo); Entity.moninfo = 0;}
1116 Entity.secMon = &Monitor;
1117 }
1118 }
1119
1120// Complete the rquestID object
1121//
1122 ReqID.setID(Request.header.streamid, Link->FDnum(), Link->Inst());
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;
1138 XrdOucErrInfo myError(Link->ID, Monitor.Did, clientPV);
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;
1171 XrdOucErrInfo myError(Link->ID, Monitor.Did, clientPV);
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;
1313 streamMutex.UnLock();
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();
1336 streamMutex.UnLock();
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 }
1624 streamMutex.UnLock();
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
1665 XrdOucErrInfo myError(Link->ID, Monitor.Did, clientPV);
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 {
1690 if (Request.prepare.options & kXR_cancel)
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
1887 ServerResponseBody_Protocol theResp;
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//
1899 if (Request.protocol.clientpv)
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
1905 if (Request.protocol.flags & ClientProtocolRequest::kXR_bifreqs
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
1914 && Request.protocol.flags & ClientProtocolRequest::kXR_secreqs)
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)
1929 switch(Request.protocol.expect & ClientProtocolRequest::kXR_ExpMask)
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("proxy", val))
2030 {const char* pxyOrigin = "proxy";
2031 if (myRole & kXR_attrProxy)
2032 {pxyOrigin = getenv("XRDXROOTD_PROXY");
2033 if (!pxyOrigin) pxyOrigin = "proxy";
2034 }
2035 n = snprintf(bp,bleft,"%s\n",pxyOrigin);
2036 bp += n; bleft -= n;
2037 }
2038 else if (!strcmp("readv_ior_max", val))
2039 {n = snprintf(bp,bleft,"%d\n",maxReadv_ior);
2040 bp += n; bleft -= n;
2041 }
2042 else if (!strcmp("readv_iov_max", val))
2043 {n = snprintf(bp, bleft, "%d\n", XrdProto::maxRvecsz);
2044 bp += n; bleft -= n;
2045 }
2046 else if (!strcmp("role", val))
2047 {const char *theRole = getenv("XRDROLE");
2048 n = snprintf(bp, bleft, "%s\n", (theRole ? theRole : "none"));
2049 bp += n; bleft -= n;
2050 }
2051 else if (!strcmp("sitename", val))
2052 {const char *siteName = getenv("XRDSITE");
2053 n = snprintf(bp, bleft, "%s\n", (siteName ? siteName : "sitename"));
2054 bp += n; bleft -= n;
2055 }
2056 else if (!strcmp("start", val))
2057 {n = snprintf(bp, bleft, "%s\n", startUP);
2058 bp += n; bleft -= n;
2059 }
2060 else if (!strcmp("sysid", val))
2061 {const char *cidval = getenv("XRDCMSCLUSTERID");
2062 const char *nidval = getenv("XRDCMSVNID");
2063 if (!cidval || !(*cidval) || !nidval || !(*nidval))
2064 {cidval = "sysid"; nidval = "";}
2065 n = snprintf(bp, bleft, "%s %s\n", nidval, cidval);
2066 bp += n; bleft -= n;
2067 }
2068 else if (!strcmp("tpc", val))
2069 {char *tpcval = getenv("XRDTPC");
2070 n = snprintf(bp, bleft, "%s\n", (tpcval ? tpcval : "tpc"));
2071 bp += n; bleft -= n;
2072 }
2073 else if (!strcmp("tpcdlg", val))
2074 {char *tpcval = getenv("XRDTPCDLG");
2075 n = snprintf(bp, bleft, "%s\n", (tpcval ? tpcval : "tpcdlg"));
2076 bp += n; bleft -= n;
2077 }
2078 else if (!strcmp("tls_port", val) && tlsPort)
2079 {n = snprintf(bp, bleft, "%d\n", tlsPort);
2080 bp += n; bleft -= n;
2081 }
2082 else if (!strcmp("window", val) && Window)
2083 {n = snprintf(bp, bleft, "%d\n", Window);
2084 bp += n; bleft -= n;
2085 }
2086 else if (!strcmp("version", val))
2087 {n = snprintf(bp, bleft, "%s\n", XrdVSTRING);
2088 bp += n; bleft -= n;
2089 }
2090 else if (!strcmp("vnid", val))
2091 {const char *nidval = getenv("XRDCMSVNID");
2092 if (!nidval || !(*nidval)) nidval = "vnid";
2093 n = snprintf(bp, bleft, "%s\n", nidval);
2094 }
2095 else if (!strcmp("fattr", val))
2096 {n = snprintf(bp, bleft, "%s\n", usxParms);
2097 bp += n; bleft -= n;
2098 }
2099 else {n = strlen(val);
2100 if (bleft <= n) break;
2101 strcpy(bp, val); bp +=n; *bp = '\n'; bp++;
2102 bleft -= (n+1);
2103 }
2104 } while(bleft > 0 && (val = qcargs.GetToken()));
2105
2106// Make sure all ended well
2107//
2108 if (val)
2109 return Response.Send(kXR_ArgTooLong, "too many query config arguments.");
2110
2111// All done
2112//
2113 return Response.Send(buff, sizeof(buff) - bleft);
2114}
2115
2116/******************************************************************************/
2117/* d o _ Q c o n f C X */
2118/******************************************************************************/
2119
2120int XrdXrootdProtocol::do_QconfCX(XrdOucTokenizer &qcargs, char *val)
2121{
2122 extern XrdOucString *XrdXrootdCF;
2123 bool isCMSD = (*val == 'c');
2124
2125// Make sure there is nothing else following the token
2126//
2127 if ((val = qcargs.GetToken()))
2128 return Response.Send(kXR_ArgInvalid, "too many query config arguments.");
2129
2130// If this is a cms just return a null for now
2131//
2132 if (isCMSD) return Response.Send((void *)"\n", 2);
2133
2134// Display the xrootd configuration
2135//
2136 if (XrdXrootdCF && isTLS && getenv("XROOTD_QCFOK"))
2137 return Response.Send((void *)XrdXrootdCF->c_str(), XrdXrootdCF->length());
2138
2139// Respond with a null
2140//
2141 return Response.Send((void *)"\n", 2);
2142}
2143
2144/******************************************************************************/
2145/* d o _ Q f h */
2146/******************************************************************************/
2147
2148int XrdXrootdProtocol::do_Qfh()
2149{
2150 static XrdXrootdCallBack qryCB("query", XROOTD_MON_QUERY);
2151 XrdXrootdFHandle fh(Request.query.fhandle);
2152 XrdXrootdFile *fp;
2153 const char *fArg = 0, *qType = "";
2154 int rc;
2155 short qopt = (short)ntohs(Request.query.infotype);
2156
2157// Update misc stats count
2158//
2159 SI->Bump(SI->miscCnt);
2160
2161// Find the file object
2162//
2163 if (!FTab || !(fp = FTab->Get(fh.handle)))
2164 return Response.Send(kXR_FileNotOpen,
2165 "query does not refer to an open file");
2166
2167// The query is elegible for a deferred response, indicate we're ok with that
2168//
2169 fp->XrdSfsp->error.setErrCB(&qryCB, ReqID.getID());
2170
2171// Perform the appropriate query
2172//
2173 switch(qopt)
2174 {case kXR_Qopaqug: qType = "Qopaqug";
2175 fArg = (Request.query.dlen ? argp->buff : 0);
2176 rc = fp->XrdSfsp->fctl(SFS_FCTL_SPEC1,
2177 Request.query.dlen, fArg,
2178 CRED);
2179 break;
2180 case kXR_Qvisa: qType = "Qvisa";
2181 rc = fp->XrdSfsp->fctl(SFS_FCTL_STATV, 0,
2182 fp->XrdSfsp->error);
2183 break;
2184 default: return Response.Send(kXR_ArgMissing,
2185 "Required query argument not present");
2186 }
2187
2188// Preform the actual function
2189//
2190 TRACEP(FS, "fh=" <<fh.handle <<" query " <<qType <<" rc=" <<rc);
2191
2192// Return appropriately
2193//
2194 if (SFS_OK != rc)
2195 return fsError(rc, XROOTD_MON_QUERY, fp->XrdSfsp->error, 0, 0);
2196 return Response.Send();
2197}
2198
2199/******************************************************************************/
2200/* d o _ Q o p a q u e */
2201/******************************************************************************/
2202
2203int XrdXrootdProtocol::do_Qopaque(short qopt)
2204{
2205 static XrdXrootdCallBack qpqCB("query", XROOTD_MON_QUERY);
2206 XrdOucErrInfo myError(Link->ID, Monitor.Did, clientPV);
2207 XrdSfsFSctl myData;
2208 const char *Act, *AData;
2209 char *opaque;
2210 int fsctl_cmd, rc, dlen = Request.query.dlen;
2211
2212// Process unstructured as well as structured (path/opaque) requests
2213//
2214 if (qopt == kXR_Qopaque)
2215 {myData.Arg1 = argp->buff; myData.Arg1Len = dlen;
2216 myData.Arg2 = 0; myData.Arg2Len = 0;
2217 fsctl_cmd = SFS_FSCTL_PLUGIO;
2218 Act = " qopaque '"; AData = "...";
2219 } else {
2220 // Check for static routing (this falls under stat)
2221 //
2222 STATIC_REDIRECT(RD_stat);
2223
2224 // Prescreen the path
2225 //
2226 if (rpCheck(argp->buff, &opaque)) return rpEmsg("Querying", argp->buff);
2227 if (!Squash(argp->buff)) return vpEmsg("Querying", argp->buff);
2228
2229 // Setup arguments
2230 //
2231 myData.Arg1 = argp->buff;
2232 myData.Arg1Len = (opaque ? opaque - argp->buff - 1 : dlen);
2233 myData.Arg2 = opaque;
2234 myData.Arg2Len = (opaque ? argp->buff + dlen - opaque : 0);
2235 fsctl_cmd = SFS_FSCTL_PLUGIN;
2236 Act = " qopaquf '"; AData = argp->buff;
2237 }
2238// The query is elegible for a deferred response, indicate we're ok with that
2239//
2240 myError.setErrCB(&qpqCB, ReqID.getID());
2241
2242// Preform the actual function using the supplied arguments
2243//
2244 rc = osFS->FSctl(fsctl_cmd, myData, myError, CRED);
2245 TRACEP(FS, "rc=" <<rc <<Act <<AData <<"'");
2246 if (rc == SFS_OK) return Response.Send("");
2247 return fsError(rc, 0, myError, 0, 0);
2248}
2249
2250/******************************************************************************/
2251/* d o _ Q s p a c e */
2252/******************************************************************************/
2253
2254int XrdXrootdProtocol::do_Qspace()
2255{
2256 static const int fsctl_cmd = SFS_FSCTL_STATLS;
2257 XrdOucErrInfo myError(Link->ID, Monitor.Did, clientPV);
2258 char *opaque;
2259 int n, rc;
2260
2261// Check for static routing
2262//
2263 STATIC_REDIRECT(RD_stat);
2264
2265// Prescreen the path
2266//
2267 if (rpCheck(argp->buff, &opaque)) return rpEmsg("Stating", argp->buff);
2268 if (!Squash(argp->buff)) return vpEmsg("Stating", argp->buff);
2269
2270// Add back the opaque info
2271//
2272 if (opaque)
2273 {n = strlen(argp->buff); argp->buff[n] = '?';
2274 if ((argp->buff)+n != opaque-1)
2275 memmove(&argp->buff[n+1], opaque, strlen(opaque)+1);
2276 }
2277
2278// Preform the actual function using the supplied logical FS name
2279//
2280 rc = osFS->fsctl(fsctl_cmd, argp->buff, myError, CRED);
2281 TRACEP(FS, "rc=" <<rc <<" qspace '" <<argp->buff <<"'");
2282 if (rc == SFS_OK) return Response.Send("");
2283 return fsError(rc, XROOTD_MON_QUERY, myError, argp->buff, opaque);
2284}
2285
2286/******************************************************************************/
2287/* d o _ Q u e r y */
2288/******************************************************************************/
2289
2290int XrdXrootdProtocol::do_Query()
2291{
2292 short qopt = (short)ntohs(Request.query.infotype);
2293
2294// Perform the appropriate query
2295//
2296 switch(qopt)
2297 {case kXR_QStats: return SI->Stats(Response,
2298 (Request.header.dlen ? argp->buff : "a"));
2299 case kXR_Qcksum: return do_CKsum(0);
2300 case kXR_Qckscan: return do_CKsum(1);
2301 case kXR_Qconfig: return do_Qconf();
2302 case kXR_Qspace: return do_Qspace();
2303 case kXR_Qxattr: return do_Qxattr();
2304 case kXR_Qopaque:
2305 case kXR_Qopaquf: return do_Qopaque(qopt);
2306 case kXR_Qopaqug: return do_Qfh();
2307 case kXR_QPrep: return do_Prepare(true);
2308 default: break;
2309 }
2310
2311// Whatever we have, it's not valid
2312//
2313 return Response.Send(kXR_ArgInvalid,
2314 "Invalid information query type code");
2315}
2316
2317/******************************************************************************/
2318/* d o _ Q x a t t r */
2319/******************************************************************************/
2320
2321int XrdXrootdProtocol::do_Qxattr()
2322{
2323 static XrdXrootdCallBack statCB("stat", XROOTD_MON_QUERY);
2324 static const int fsctl_cmd = SFS_FSCTL_STATXA;
2325 int rc;
2326 char *opaque;
2327 XrdOucErrInfo myError(Link->ID,&statCB,ReqID.getID(),Monitor.Did,clientPV);
2328
2329// Check for static routing
2330//
2331 STATIC_REDIRECT(RD_stat);
2332
2333// Prescreen the path
2334//
2335 if (rpCheck(argp->buff, &opaque)) return rpEmsg("Stating", argp->buff);
2336 if (!Squash(argp->buff)) return vpEmsg("Stating", argp->buff);
2337
2338// Add back opaque information is present
2339//
2340 if (opaque)
2341 {int n = strlen(argp->buff); argp->buff[n] = '?';
2342 if ((argp->buff)+n != opaque-1)
2343 memmove(&argp->buff[n+1], opaque, strlen(opaque)+1);
2344 }
2345
2346// Preform the actual function
2347//
2348 rc = osFS->fsctl(fsctl_cmd, argp->buff, myError, CRED);
2349 TRACEP(FS, "rc=" <<rc <<" qxattr " <<argp->buff);
2350 return fsError(rc, XROOTD_MON_QUERY, myError, argp->buff, opaque);
2351}
2352
2353/******************************************************************************/
2354/* d o _ R e a d */
2355/******************************************************************************/
2356
2357int XrdXrootdProtocol::do_Read()
2358{
2359 int pathID, retc;
2360 XrdXrootdFHandle fh(Request.read.fhandle);
2361 numReads++;
2362
2363// We first handle the pre-read list, if any. We do it this way because of
2364// a historical glitch in the protocol. One should really not piggy back a
2365// pre-read on top of a read, though it is allowed.
2366//
2367 if (!Request.header.dlen) pathID = 0;
2368 else if (do_ReadNone(retc, pathID)) return retc;
2369
2370// Unmarshall the data
2371//
2372 IO.IOLen = ntohl(Request.read.rlen);
2373 n2hll(Request.read.offset, IO.Offset);
2374
2375// Find the file object
2376//
2377 if (!FTab || !(IO.File = FTab->Get(fh.handle)))
2378 return Response.Send(kXR_FileNotOpen,
2379 "read does not refer to an open file");
2380
2381// Trace and verify read length is not negative
2382//
2383 TRACEP(FSIO, pathID <<" fh=" <<fh.handle <<" read " <<IO.IOLen
2384 <<'@' <<IO.Offset);
2385 if ( IO.IOLen < 0) return Response.Send(kXR_ArgInvalid,
2386 "Read length is negative");
2387
2388// If we are monitoring, insert a read entry
2389//
2390 if (Monitor.InOut())
2391 Monitor.Agent->Add_rd(IO.File->Stats.FileID, Request.read.rlen,
2392 Request.read.offset);
2393
2394// Short circuit processing if read length is zero
2395//
2396 if (!IO.IOLen) return Response.Send();
2397
2398// There are many competing ways to accomplish a read. Pick the one we
2399// will use and if possible, do a fast dispatch.
2400//
2401 if (IO.File->isMMapped) IO.Mode = XrdXrootd::IOParms::useMMap;
2402 else if (IO.File->sfEnabled && !isTLS && IO.IOLen >= as_minsfsz
2403 && IO.Offset+IO.IOLen <= IO.File->Stats.fSize)
2405 else if (IO.File->AsyncMode && IO.IOLen >= as_miniosz
2406 && IO.Offset+IO.IOLen <= IO.File->Stats.fSize+as_seghalf
2408 {XrdXrootdProtocol *pP;
2409 XrdXrootdNormAio *aioP;
2410
2411 if (!pathID) pP = this;
2412 else {if (!(pP = VerifyStream(retc, pathID, false))) return retc;
2413 if (pP->linkAioReq >= as_maxperlnk) pP = 0;
2414 }
2415 if (pP && (aioP = XrdXrootdNormAio::Alloc(pP,pP->Response,IO.File)))
2416 {if (!IO.File->aioFob) IO.File->aioFob = new XrdXrootdAioFob;
2417 aioP->Read(IO.Offset, IO.IOLen);
2418 return 0;
2419 }
2420 SI->AsyncRej++;
2422 }
2423 else IO.Mode = XrdXrootd::IOParms::useBasic;
2424
2425// See if an alternate path is required, offload the read
2426//
2427 if (pathID) return do_Offload(&XrdXrootdProtocol::do_ReadAll, pathID);
2428
2429// Now read all of the data (do pre-reads first)
2430//
2431 return do_ReadAll();
2432}
2433
2434/******************************************************************************/
2435/* d o _ R e a d A l l */
2436/******************************************************************************/
2437
2438// IO.File = file to be read
2439// IO.Offset = Offset at which to read
2440// IO.IOLen = Number of bytes to read from file and write to socket
2441
2442int XrdXrootdProtocol::do_ReadAll()
2443{
2444 int rc, xframt, Quantum = (IO.IOLen > maxBuffsz ? maxBuffsz : IO.IOLen);
2445 char *buff;
2446
2447// If this file is memory mapped, short ciruit all the logic and immediately
2448// transfer the requested data to minimize latency.
2449//
2450 if (IO.Mode == XrdXrootd::IOParms::useMMap)
2451 {if (IO.Offset >= IO.File->Stats.fSize) return Response.Send();
2452 if (IO.Offset+IO.IOLen <= IO.File->Stats.fSize)
2453 {IO.File->Stats.rdOps(IO.IOLen);
2454 return Response.Send(IO.File->mmAddr+IO.Offset, IO.IOLen);
2455 }
2456 xframt = IO.File->Stats.fSize -IO.Offset;
2457 IO.File->Stats.rdOps(xframt);
2458 return Response.Send(IO.File->mmAddr+IO.Offset, xframt);
2459 }
2460
2461// If we are sendfile enabled, then just send the file if possible
2462//
2463 if (IO.Mode == XrdXrootd::IOParms::useSF)
2464 {IO.File->Stats.rdOps(IO.IOLen);
2465 if (IO.File->fdNum >= 0)
2466 return Response.Send(IO.File->fdNum, IO.Offset, IO.IOLen);
2467 rc = IO.File->XrdSfsp->SendData((XrdSfsDio *)this, IO.Offset, IO.IOLen);
2468 if (rc == SFS_OK)
2469 {if (!IO.IOLen) return 0;
2470 if (IO.IOLen < 0) return -1; // Otherwise retry using read()
2471 } else return fsError(rc, 0, IO.File->XrdSfsp->error, 0, 0);
2472 }
2473
2474// Make sure we have a large enough buffer
2475//
2476 if (!argp || Quantum < halfBSize || Quantum > argp->bsize)
2477 {if ((rc = getBuff(1, Quantum)) <= 0) return rc;}
2478 else if (hcNow < hcNext) hcNow++;
2479 buff = argp->buff;
2480
2481// Now read all of the data. For statistics, we need to record the orignal
2482// amount of the request even if we really do not get to read that much!
2483//
2484 IO.File->Stats.rdOps(IO.IOLen);
2485 do {if ((xframt = IO.File->XrdSfsp->read(IO.Offset, buff, Quantum)) <= 0) break;
2486 if (xframt >= IO.IOLen) return Response.Send(buff, xframt);
2487 if (Response.Send(kXR_oksofar, buff, xframt) < 0) return -1;
2488 IO.Offset += xframt; IO.IOLen -= xframt;
2489 if (IO.IOLen < Quantum) Quantum = IO.IOLen;
2490 } while(IO.IOLen);
2491
2492// Determine why we ended here
2493//
2494 if (xframt == 0) return Response.Send();
2495 return fsError(xframt, 0, IO.File->XrdSfsp->error, 0, 0);
2496}
2497
2498/******************************************************************************/
2499/* d o _ R e a d N o n e */
2500/******************************************************************************/
2501
2502int XrdXrootdProtocol::do_ReadNone(int &retc, int &pathID)
2503{
2504 XrdXrootdFHandle fh;
2505 int ralsz = Request.header.dlen;
2506 struct read_args *rargs=(struct read_args *)(argp->buff);
2507 struct readahead_list *ralsp = (readahead_list *)(rargs+1);
2508
2509// Return the pathid
2510//
2511 pathID = static_cast<int>(rargs->pathid);
2512 if ((ralsz -= sizeof(read_args)) <= 0) return 0;
2513
2514// Make sure that we have a proper pre-read list
2515//
2516 if (ralsz%sizeof(readahead_list))
2517 {Response.Send(kXR_ArgInvalid, "Invalid length for read ahead list");
2518 return 1;
2519 }
2520
2521// Run down the pre-read list
2522//
2523 while(ralsz > 0)
2524 {IO.IOLen = ntohl(ralsp->rlen);
2525 n2hll(ralsp->offset, IO.Offset);
2526 memcpy((void *)&fh.handle, (const void *)ralsp->fhandle,
2527 sizeof(fh.handle));
2528 TRACEP(FSIO, "fh="<<fh.handle<<" read "<<IO.IOLen<<'@'<<IO.Offset);
2529 if (!FTab || !(IO.File = FTab->Get(fh.handle)))
2530 {retc = Response.Send(kXR_FileNotOpen,
2531 "preread does not refer to an open file");
2532 return 1;
2533 }
2534 IO.File->XrdSfsp->read(IO.Offset, IO.IOLen);
2535 ralsz -= sizeof(struct readahead_list);
2536 ralsp++;
2537 numReads++;
2538 };
2539
2540// All done
2541//
2542 return 0;
2543}
2544
2545/******************************************************************************/
2546/* d o _ R e a d V */
2547/******************************************************************************/
2548
2549int XrdXrootdProtocol::do_ReadV()
2550{
2551// This will read multiple buffers at the same time in an attempt to avoid
2552// the latency in a network. The information with the offsets and lengths
2553// of the information to read is passed as a data buffer... then we decode
2554// it and put all the individual buffers in a single one it's up to the
2555// client to interpret it. Code originally developed by Leandro Franco, CERN.
2556// The readv file system code originally added by Brian Bockelman, UNL.
2557//
2558 const int hdrSZ = sizeof(readahead_list);
2559 struct XrdOucIOVec rdVec[XrdProto::maxRvecsz+1];
2560 struct readahead_list *raVec, respHdr;
2561 long long totSZ;
2562 XrdSfsXferSize rdVAmt, rdVXfr, xfrSZ = 0;
2563 int rdVBeg, rdVBreak, rdVNow, rdVNum, rdVecNum;
2564 int currFH, i, k, Quantum, Qleft, rdVecLen = Request.header.dlen;
2565 int rvMon = Monitor.InOut();
2566 int ioMon = (rvMon > 1);
2567 char *buffp, vType = (ioMon ? XROOTD_MON_READU : XROOTD_MON_READV);
2568
2569// Compute number of elements in the read vector and make sure we have no
2570// partial elements.
2571//
2572 rdVecNum = rdVecLen / sizeof(readahead_list);
2573 if ( (rdVecNum <= 0) || (rdVecNum*hdrSZ != rdVecLen) )
2574 return Response.Send(kXR_ArgInvalid, "Read vector is invalid");
2575
2576// Make sure that we can copy the read vector to our local stack. We must impose
2577// a limit on it's size. We do this to be able to reuse the data buffer to
2578// prevent cross-cpu memory cache synchronization.
2579//
2580 if (rdVecNum > XrdProto::maxRvecsz)
2581 return Response.Send(kXR_ArgTooLong, "Read vector is too long");
2582
2583// So, now we account for the number of readv requests and total segments
2584//
2585 numReadV++; numSegsV += rdVecNum;
2586
2587// Run down the list and compute the total size of the read. No individual
2588// read may be greater than the maximum transfer size. We also use this loop
2589// to copy the read ahead list to our readv vector for later processing.
2590//
2591 raVec = (readahead_list *)argp->buff;
2592 totSZ = rdVecLen; Quantum = maxReadv_ior;
2593 for (i = 0; i < rdVecNum; i++)
2594 {totSZ += (rdVec[i].size = ntohl(raVec[i].rlen));
2595 if (rdVec[i].size < 0) return Response.Send(kXR_ArgInvalid,
2596 "Readv length is negative");
2597 if (rdVec[i].size > Quantum) return Response.Send(kXR_NoMemory,
2598 "Single readv transfer is too large");
2599 rdVec[i].offset = ntohll(raVec[i].offset);
2600 memcpy(&rdVec[i].info, raVec[i].fhandle, sizeof(int));
2601 }
2602
2603// Now add an extra dummy element to force flushing of the read vector.
2604//
2605 rdVec[i].offset = -1;
2606 rdVec[i].size = 0;
2607 rdVec[i].info = -1;
2608 rdVBreak = rdVecNum;
2609 rdVecNum++;
2610
2611// We limit the total size of the read to be 2GB for convenience
2612//
2613 if (totSZ > 0x7fffffffLL)
2614 return Response.Send(kXR_NoMemory, "Total readv transfer is too large");
2615
2616// Calculate the transfer unit which will be the smaller of the maximum
2617// transfer unit and the actual amount we need to transfer.
2618//
2619 if ((Quantum = static_cast<int>(totSZ)) > maxTransz) Quantum = maxTransz;
2620
2621// Now obtain the right size buffer
2622//
2623 if ((Quantum < halfBSize && Quantum > 1024) || Quantum > argp->bsize)
2624 {if ((k = getBuff(1, Quantum)) <= 0) return k;}
2625 else if (hcNow < hcNext) hcNow++;
2626
2627// Check that we really have at least one file open. This needs to be done
2628// only once as this code runs in the control thread.
2629//
2630 if (!FTab) return Response.Send(kXR_FileNotOpen,
2631 "readv does not refer to an open file");
2632
2633// Preset the previous and current file handle to be the handle of the first
2634// element and make sure the file is actually open.
2635//
2636 currFH = rdVec[0].info;
2637 memcpy(respHdr.fhandle, &currFH, sizeof(respHdr.fhandle));
2638 if (!(IO.File = FTab->Get(currFH))) return Response.Send(kXR_FileNotOpen,
2639 "readv does not refer to an open file");
2640
2641// Setup variables for running through the list.
2642//
2643 Qleft = Quantum; buffp = argp->buff; rvSeq++;
2644 rdVBeg = rdVNow = 0; rdVXfr = rdVAmt = 0;
2645
2646// Now run through the elements
2647//
2648 for (i = 0; i < rdVecNum; i++)
2649 {if (rdVec[i].info != currFH)
2650 {xfrSZ = IO.File->XrdSfsp->readv(&rdVec[rdVNow], i-rdVNow);
2651 if (xfrSZ != rdVAmt) break;
2652 rdVNum = i - rdVBeg; rdVXfr += rdVAmt;
2653 IO.File->Stats.rvOps(rdVXfr, rdVNum);
2654 if (rvMon)
2655 {Monitor.Agent->Add_rv(IO.File->Stats.FileID, htonl(rdVXfr),
2656 htons(rdVNum), rvSeq, vType);
2657 if (ioMon) for (k = rdVBeg; k < i; k++)
2658 Monitor.Agent->Add_rd(IO.File->Stats.FileID,
2659 htonl(rdVec[k].size), htonll(rdVec[k].offset));
2660 }
2661 rdVXfr = rdVAmt = 0;
2662 if (i == rdVBreak) break;
2663 rdVBeg = rdVNow = i; currFH = rdVec[i].info;
2664 memcpy(respHdr.fhandle, &currFH, sizeof(respHdr.fhandle));
2665 if (!(IO.File = FTab->Get(currFH)))
2666 return Response.Send(kXR_FileNotOpen,
2667 "readv does not refer to an open file");
2668 }
2669
2670 if (Qleft < (rdVec[i].size + hdrSZ))
2671 {if (rdVAmt)
2672 {xfrSZ = IO.File->XrdSfsp->readv(&rdVec[rdVNow], i-rdVNow);
2673 if (xfrSZ != rdVAmt) break;
2674 }
2675 if (Response.Send(kXR_oksofar,argp->buff,Quantum-Qleft) < 0)
2676 return -1;
2677 Qleft = Quantum;
2678 buffp = argp->buff;
2679 rdVNow = i; rdVXfr += rdVAmt; rdVAmt = 0;
2680 }
2681
2682 xfrSZ = rdVec[i].size; rdVAmt += xfrSZ;
2683 respHdr.rlen = htonl(xfrSZ);
2684 respHdr.offset = htonll(rdVec[i].offset);
2685 memcpy(buffp, &respHdr, hdrSZ);
2686 rdVec[i].data = buffp + hdrSZ;
2687 buffp += (xfrSZ+hdrSZ); Qleft -= (xfrSZ+hdrSZ);
2688 TRACEP(FSIO,"fh=" <<currFH<<" readV "<< xfrSZ <<'@'<<rdVec[i].offset);
2689 }
2690
2691// Check if we have an error here. This is indicated when rdVAmt is not zero.
2692//
2693 if (rdVAmt)
2694 {if (xfrSZ >= 0)
2695 {xfrSZ = SFS_ERROR;
2696 IO.File->XrdSfsp->error.setErrInfo(-ENODATA,"readv past EOF");
2697 }
2698 return fsError(xfrSZ, 0, IO.File->XrdSfsp->error, 0, 0);
2699 }
2700
2701// All done, return result of the last segment or just zero
2702//
2703 return (Quantum != Qleft ? Response.Send(argp->buff, Quantum-Qleft) : 0);
2704}
2705
2706/******************************************************************************/
2707/* d o _ R m */
2708/******************************************************************************/
2709
2710int XrdXrootdProtocol::do_Rm()
2711{
2712 int rc;
2713 char *opaque;
2714 XrdOucErrInfo myError(Link->ID, Monitor.Did, clientPV);
2715
2716// Check for static routing
2717//
2718 STATIC_REDIRECT(RD_rm);
2719
2720// Prescreen the path
2721//
2722 if (rpCheck(argp->buff, &opaque)) return rpEmsg("Removing", argp->buff);
2723 if (!Squash(argp->buff)) return vpEmsg("Removing", argp->buff);
2724
2725// Preform the actual function
2726//
2727 rc = osFS->rem(argp->buff, myError, CRED, opaque);
2728 TRACEP(FS, "rc=" <<rc <<" rm " <<argp->buff);
2729 if (SFS_OK == rc) return Response.Send();
2730
2731// An error occurred
2732//
2733 return fsError(rc, XROOTD_MON_RM, myError, argp->buff, opaque);
2734}
2735
2736/******************************************************************************/
2737/* d o _ R m d i r */
2738/******************************************************************************/
2739
2740int XrdXrootdProtocol::do_Rmdir()
2741{
2742 int rc;
2743 char *opaque;
2744 XrdOucErrInfo myError(Link->ID, Monitor.Did, clientPV);
2745
2746// Check for static routing
2747//
2748 STATIC_REDIRECT(RD_rmdir);
2749
2750// Prescreen the path
2751//
2752 if (rpCheck(argp->buff, &opaque)) return rpEmsg("Removing", argp->buff);
2753 if (!Squash(argp->buff)) return vpEmsg("Removing", argp->buff);
2754
2755// Preform the actual function
2756//
2757 rc = osFS->remdir(argp->buff, myError, CRED, opaque);
2758 TRACEP(FS, "rc=" <<rc <<" rmdir " <<argp->buff);
2759 if (SFS_OK == rc) return Response.Send();
2760
2761// An error occurred
2762//
2763 return fsError(rc, XROOTD_MON_RMDIR, myError, argp->buff, opaque);
2764}
2765
2766/******************************************************************************/
2767/* d o _ S e t */
2768/******************************************************************************/
2769
2770int XrdXrootdProtocol::do_Set()
2771{
2772 XrdOucTokenizer setargs(argp->buff);
2773 char *val, *rest;
2774
2775// Get the first argument
2776//
2777 if (!setargs.GetLine() || !(val = setargs.GetToken(&rest)))
2778 return Response.Send(kXR_ArgMissing, "set argument not specified.");
2779
2780// Trace this set
2781//
2782 TRACEP(DEBUG, "set " <<val <<' ' <<rest);
2783
2784// Now determine what the user wants to set
2785//
2786 if (!strcmp("appid", val))
2787 {while(*rest && *rest == ' ') rest++;
2788 eDest.Emsg("Xeq", Link->ID, "appid", rest);
2789 return Response.Send();
2790 }
2791 else if (!strcmp("monitor", val)) return do_Set_Mon(setargs);
2792 else if (!strcmp("cache", val)) return do_Set_Cache(setargs);
2793
2794// All done
2795//
2796 return Response.Send(kXR_ArgInvalid, "invalid set parameter");
2797}
2798
2799/******************************************************************************/
2800/* d o _ S e t _ C a c h e */
2801/******************************************************************************/
2802
2803// Process: set cache <cmd> <args>
2804
2805int XrdXrootdProtocol::do_Set_Cache(XrdOucTokenizer &setargs)
2806{
2807 XrdOucErrInfo myError(Link->ID, Monitor.Did, clientPV);
2808 XrdSfsFSctl myData;
2809 char *cmd, *cargs, *opaque;
2810 const char *myArgs[2];
2811
2812// This set is valid only if we implement a cache
2813//
2814 if ((fsFeatures & XrdSfs::hasCACH) == 0)
2815 return Response.Send(kXR_ArgInvalid, "invalid set parameter");
2816
2817// Get the command and argument
2818//
2819 if (!(cmd = setargs.GetToken(&cargs)))
2820 return Response.Send(kXR_ArgMissing,"set cache argument not specified.");
2821
2822// Prescreen the path if the next token starts with a slash
2823//
2824 if (cargs && *cargs == '/')
2825 {if (rpCheck(cargs, &opaque)) return rpEmsg("Setting", cargs);
2826 if (!Squash(cargs)) return vpEmsg("Setting", cargs);
2827 myData.ArgP = myArgs; myData.Arg2Len = -2;
2828 myArgs[0] = cargs;
2829 myArgs[1] = opaque;
2830 } else {
2831 myData.Arg2 = opaque; myData.Arg2Len = (opaque ? strlen(opaque) : 0);
2832 }
2833 myData.Arg1 = cmd; myData.Arg1Len = strlen(cmd);
2834
2835// Preform the actual function using the supplied arguments
2836//
2837 int rc = osFS->FSctl(SFS_FSCTL_PLUGXC, myData, myError, CRED);
2838 TRACEP(FS, "rc=" <<rc <<"set cache " <<myData.Arg1 <<' ' <<cargs);
2839 if (rc == SFS_OK) return Response.Send("");
2840 return fsError(rc, 0, myError, 0, 0);
2841}
2842
2843/******************************************************************************/
2844/* d o _ S e t _ M o n */
2845/******************************************************************************/
2846
2847// Process: set monitor {off | on} {[appid] | info [info]}
2848
2849int XrdXrootdProtocol::do_Set_Mon(XrdOucTokenizer &setargs)
2850{
2851 char *val, *appid;
2852 kXR_unt32 myseq = 0;
2853
2854// Get the first argument
2855//
2856 if (!(val = setargs.GetToken(&appid)))
2857 return Response.Send(kXR_ArgMissing,"set monitor argument not specified.");
2858
2859// For info requests, nothing changes. However, info events must have been
2860// enabled for us to record them. Route the information via the static
2861// monitor entry, since it knows how to forward the information.
2862//
2863 if (!strcmp(val, "info"))
2864 {if (appid && Monitor.Info())
2865 {while(*appid && *appid == ' ') appid++;
2866 if (strlen(appid) > 1024) appid[1024] = '\0';
2867 if (*appid) myseq = Monitor.MapInfo(appid);
2868 }
2869 return Response.Send((void *)&myseq, sizeof(myseq));
2870 }
2871
2872// Determine if on do appropriate processing
2873//
2874 if (!strcmp(val, "on"))
2875 {Monitor.Enable();
2876 if (appid && Monitor.InOut())
2877 {while(*appid && *appid == ' ') appid++;
2878 if (*appid) Monitor.Agent->appID(appid);
2879 }
2880 if (!Monitor.Did && Monitor.Logins()) MonAuth();
2881 return Response.Send();
2882 }
2883
2884// Determine if off and do appropriate processing
2885//
2886 if (!strcmp(val, "off"))
2887 {if (appid && Monitor.InOut())
2888 {while(*appid && *appid == ' ') appid++;
2889 if (*appid) Monitor.Agent->appID(appid);
2890 }
2891 Monitor.Disable();
2892 return Response.Send();
2893 }
2894
2895// Improper request
2896//
2897 return Response.Send(kXR_ArgInvalid, "invalid set monitor argument");
2898}
2899
2900/******************************************************************************/
2901/* d o _ S t a t */
2902/******************************************************************************/
2903
2904int XrdXrootdProtocol::do_Stat()
2905{
2906 static XrdXrootdCallBack statCB("stat", XROOTD_MON_STAT);
2907 static const int fsctl_cmd = SFS_FSCTL_STATFS;
2908 bool doDig;
2909 int rc;
2910 char *opaque, xxBuff[1024];
2911 struct stat buf;
2912 XrdOucErrInfo myError(Link->ID,&statCB,ReqID.getID(),Monitor.Did,clientPV);
2913
2914// Update misc stats count
2915//
2916 SI->Bump(SI->miscCnt);
2917
2918// The stat request may refer to an open file handle. So, screen this out.
2919//
2920 if (!argp || !Request.header.dlen)
2921 {XrdXrootdFile *fp;
2922 XrdXrootdFHandle fh(Request.stat.fhandle);
2923 if (Request.stat.options & kXR_vfs)
2924 {Response.Send(kXR_ArgMissing, "Required argument not present");
2925 return 0;
2926 }
2927 if (!FTab || !(fp = FTab->Get(fh.handle)))
2928 return Response.Send(kXR_FileNotOpen,
2929 "stat does not refer to an open file");
2930 rc = fp->XrdSfsp->stat(&buf);
2931 TRACEP(FS, "fh=" <<fh.handle <<" stat rc=" <<rc);
2932 if (SFS_OK == rc) return Response.Send(xxBuff,
2933 StatGen(buf,xxBuff,sizeof(xxBuff)));
2934 return fsError(rc, 0, fp->XrdSfsp->error, 0, 0);
2935 }
2936
2937// Check if we are handling a dig type path
2938//
2939 doDig = (digFS && SFS_LCLROOT(argp->buff));
2940
2941// Check for static routing
2942//
2943 if (!doDig) {STATIC_REDIRECT(RD_stat);}
2944
2945// Prescreen the path
2946//
2947 if (rpCheck(argp->buff, &opaque)) return rpEmsg("Stating", argp->buff);
2948 if (!doDig && !Squash(argp->buff))return vpEmsg("Stating", argp->buff);
2949
2950// Preform the actual function, we may been to add back the opaque info
2951//
2952 if (Request.stat.options & kXR_vfs)
2953 {if (opaque)
2954 {int n = strlen(argp->buff); argp->buff[n] = '?';
2955 if ((argp->buff)+n != opaque-1)
2956 memmove(&argp->buff[n+1], opaque, strlen(opaque)+1);
2957 }
2958 rc = osFS->fsctl(fsctl_cmd, argp->buff, myError, CRED);
2959 TRACEP(FS, "rc=" <<rc <<" statfs " <<argp->buff);
2960 if (rc == SFS_OK) Response.Send("");
2961 } else {
2962 if (doDig) rc = digFS->stat(argp->buff, &buf, myError, CRED, opaque);
2963 else rc = osFS->stat(argp->buff, &buf, myError, CRED, opaque);
2964 TRACEP(FS, "rc=" <<rc <<" stat " <<argp->buff);
2965 if (rc == SFS_OK) return Response.Send(xxBuff,
2966 StatGen(buf,xxBuff,sizeof(xxBuff)));
2967 }
2968 return fsError(rc, (doDig ? 0 : XROOTD_MON_STAT),myError,argp->buff,opaque);
2969}
2970
2971/******************************************************************************/
2972/* d o _ S t a t x */
2973/******************************************************************************/
2974
2975int XrdXrootdProtocol::do_Statx()
2976{
2977 static XrdXrootdCallBack statxCB("xstat", XROOTD_MON_STAT);
2978 int rc;
2979 char *path, *opaque, *respinfo = argp->buff;
2980 mode_t mode;
2981 XrdOucErrInfo myError(Link->ID,&statxCB,ReqID.getID(),Monitor.Did,clientPV);
2982 XrdOucTokenizer pathlist(argp->buff);
2983
2984// Check for static routing
2985//
2986 STATIC_REDIRECT(RD_stat);
2987
2988// Cycle through all of the paths in the list
2989//
2990 while((path = pathlist.GetLine()))
2991 {if (rpCheck(path, &opaque)) return rpEmsg("Stating", path);
2992 if (!Squash(path)) return vpEmsg("Stating", path);
2993 rc = osFS->stat(path, mode, myError, CRED, opaque);
2994 TRACEP(FS, "rc=" <<rc <<" stat " <<path);
2995 if (rc != SFS_OK)
2996 return fsError(rc, XROOTD_MON_STAT, myError, path, opaque);
2997 else {if (mode == (mode_t)-1) *respinfo = (char)kXR_offline;
2998 else if (S_ISDIR(mode)) *respinfo = (char)kXR_isDir;
2999 else *respinfo = (char)kXR_file;
3000 }
3001 respinfo++;
3002 }
3003
3004// Return result
3005//
3006 return Response.Send(argp->buff, respinfo-argp->buff);
3007}
3008
3009/******************************************************************************/
3010/* d o _ S y n c */
3011/******************************************************************************/
3012
3013int XrdXrootdProtocol::do_Sync()
3014{
3015 static XrdXrootdCallBack syncCB("sync", 0);
3016 int rc;
3017 XrdXrootdFile *fp;
3018 XrdXrootdFHandle fh(Request.sync.fhandle);
3019
3020// Keep Statistics
3021//
3022 SI->Bump(SI->syncCnt);
3023
3024// Find the file object
3025//
3026 if (!FTab || !(fp = FTab->Get(fh.handle)))
3027 return Response.Send(kXR_FileNotOpen,"sync does not refer to an open file");
3028
3029// The sync is elegible for a deferred response, indicate we're ok with that
3030//
3031 fp->XrdSfsp->error.setErrCB(&syncCB, ReqID.getID());
3032
3033// Sync the file
3034//
3035 rc = fp->XrdSfsp->sync();
3036 TRACEP(FS, "fh=" <<fh.handle <<" sync rc=" <<rc);
3037 if (SFS_OK != rc) return fsError(rc, 0, fp->XrdSfsp->error, 0, 0);
3038
3039// Respond that all went well
3040//
3041 return Response.Send();
3042}
3043
3044/******************************************************************************/
3045/* d o _ T r u n c a t e */
3046/******************************************************************************/
3047
3048int XrdXrootdProtocol::do_Truncate()
3049{
3050 static XrdXrootdCallBack truncCB("trunc", 0);
3051 XrdXrootdFile *fp;
3052 XrdXrootdFHandle fh(Request.truncate.fhandle);
3053 long long theOffset;
3054 int rc;
3055
3056// Unmarshall the data
3057//
3058 n2hll(Request.truncate.offset, theOffset);
3059
3060// Check if this is a truncate for an open file (no path given)
3061//
3062 if (!Request.header.dlen)
3063 {
3064 // Update misc stats count
3065 //
3066 SI->Bump(SI->miscCnt);
3067
3068 // Find the file object
3069 //
3070 if (!FTab || !(fp = FTab->Get(fh.handle)))
3071 return Response.Send(kXR_FileNotOpen,
3072 "trunc does not refer to an open file");
3073
3074 // Truncate the file (it is eligible for async callbacks)
3075 //
3076 fp->XrdSfsp->error.setErrCB(&truncCB, ReqID.getID());
3077 rc = fp->XrdSfsp->truncate(theOffset);
3078 TRACEP(FS, "fh=" <<fh.handle <<" trunc rc=" <<rc <<" sz=" <<theOffset);
3079 if (SFS_OK != rc) return fsError(rc, 0, fp->XrdSfsp->error, 0, 0);
3080
3081 } else {
3082
3083 XrdOucErrInfo myError(Link->ID, Monitor.Did, clientPV);
3084 char *opaque;
3085
3086 // Check for static routing
3087 //
3088 STATIC_REDIRECT(RD_trunc);
3089
3090 // Verify the path and extract out the opaque information
3091 //
3092 if (rpCheck(argp->buff,&opaque)) return rpEmsg("Truncating",argp->buff);
3093 if (!Squash(argp->buff)) return vpEmsg("Truncating",argp->buff);
3094
3095 // Preform the actual function
3096 //
3097 rc = osFS->truncate(argp->buff, (XrdSfsFileOffset)theOffset, myError,
3098 CRED, opaque);
3099 TRACEP(FS, "rc=" <<rc <<" trunc " <<theOffset <<' ' <<argp->buff);
3100 if (SFS_OK != rc)
3101 return fsError(rc, XROOTD_MON_TRUNC, myError, argp->buff, opaque);
3102 }
3103
3104// Respond that all went well
3105//
3106 return Response.Send();
3107}
3108
3109/******************************************************************************/
3110/* d o _ W r i t e */
3111/******************************************************************************/
3112
3113int XrdXrootdProtocol::do_Write()
3114{
3115 int pathID;
3116 XrdXrootdFHandle fh(Request.write.fhandle);
3117 numWrites++;
3118
3119// Unmarshall the data
3120//
3121 IO.IOLen = Request.header.dlen;
3122 n2hll(Request.write.offset, IO.Offset);
3123 pathID = static_cast<int>(Request.write.pathid);
3124
3125// Find the file object. We will drain socket data on the control path only!
3126// .
3127 if (!FTab || !(IO.File = FTab->Get(fh.handle)))
3128 {IO.File = 0;
3129 return do_WriteNone(pathID);
3130 }
3131
3132// Trace and verify that length is not negative
3133//
3134 TRACEP(FSIO, pathID<<" fh="<<fh.handle<<" write "<<IO.IOLen<<'@'<<IO.Offset);
3135 if ( IO.IOLen < 0) return Response.Send(kXR_ArgInvalid,
3136 "Write length is negative");
3137
3138// If we are monitoring, insert a write entry
3139//
3140 if (Monitor.InOut())
3141 Monitor.Agent->Add_wr(IO.File->Stats.FileID, Request.write.dlen,
3142 Request.write.offset);
3143
3144// If zero length write, simply return
3145//
3146 if (!IO.IOLen) return Response.Send();
3147 IO.File->Stats.wrOps(IO.IOLen); // Optimistically correct
3148
3149// If async write allowed and it is a true write request (e.g. not chkpoint) and
3150// current conditions permit async; schedule the write to occur asynchronously
3151//
3152 if (IO.File->AsyncMode && Request.header.requestid == kXR_write
3153 && !as_syncw && IO.IOLen >= as_miniosz && srvrAioOps < as_maxpersrv)
3154 {if (myStalls < as_maxstalls)
3155 {if (pathID) return do_Offload(&XrdXrootdProtocol::do_WriteAio,pathID);
3156 return do_WriteAio();
3157 }
3158 SI->AsyncRej++;
3159 myStalls--;
3160 }
3161
3162// See if an alternate path is required
3163//
3164 if (pathID) return do_Offload(&XrdXrootdProtocol::do_WriteAll, pathID);
3165
3166// Just to the i/o now
3167//
3168 return do_WriteAll();
3169}
3170
3171/******************************************************************************/
3172/* d o _ W r i t e A i o */
3173/******************************************************************************/
3174
3175// IO.File = file to be written
3176// IO.Offset = Offset at which to write
3177// IO.IOLen = Number of bytes to read from socket and write to file
3178
3179int XrdXrootdProtocol::do_WriteAio()
3180{
3181 XrdXrootdNormAio *aioP;
3182
3183// Allocate an aio request object if client hasn't exceeded the link limit
3184//
3186 || !(aioP = XrdXrootdNormAio::Alloc(this, Response, IO.File)))
3187 {SI->AsyncRej++;
3188 if (myStalls > 0) myStalls--;
3189 return do_WriteAll();
3190 }
3191
3192// Issue the write request
3193//
3194 return aioP->Write(IO.Offset, IO.IOLen);
3195}
3196
3197/******************************************************************************/
3198/* d o _ W r i t e A l l */
3199/******************************************************************************/
3200
3201// IO.File = file to be written
3202// IO.Offset = Offset at which to write
3203// IO.IOLen = Number of bytes to read from socket and write to file
3204
3205int XrdXrootdProtocol::do_WriteAll()
3206{
3207 int rc, Quantum = (IO.IOLen > maxBuffsz ? maxBuffsz : IO.IOLen);
3208
3209// Make sure we have a large enough buffer
3210//
3211 if (!argp || Quantum < halfBSize || Quantum > argp->bsize)
3212 {if ((rc = getBuff(0, Quantum)) <= 0) return rc;}
3213 else if (hcNow < hcNext) hcNow++;
3214
3215// Now write all of the data (XrdXrootdProtocol.C defines getData())
3216//
3217 while(IO.IOLen > 0)
3218 {if ((rc = getData("data", argp->buff, Quantum)))
3219 {if (rc > 0)
3220 {Resume = &XrdXrootdProtocol::do_WriteCont;
3221 myBlast = Quantum;
3222 }
3223 return rc;
3224 }
3225 if ((rc = IO.File->XrdSfsp->write(IO.Offset, argp->buff, Quantum)) < 0)
3226 {IO.IOLen = IO.IOLen-Quantum; IO.EInfo[0] = rc; IO.EInfo[1] = 0;
3227 return do_WriteNone();
3228 }
3229 IO.Offset += Quantum; IO.IOLen -= Quantum;
3230 if (IO.IOLen < Quantum) Quantum = IO.IOLen;
3231 }
3232
3233// All done
3234//
3235 return Response.Send();
3236}
3237
3238/******************************************************************************/
3239/* d o _ W r i t e C o n t */
3240/******************************************************************************/
3241
3242// IO.File = file to be written
3243// IO.Offset = Offset at which to write
3244// IO.IOLen = Number of bytes to read from socket and write to file
3245// myBlast = Number of bytes already read from the socket
3246
3247int XrdXrootdProtocol::do_WriteCont()
3248{
3249 int rc;
3250
3251// Write data that was finaly finished comming in
3252//
3253 if ((rc = IO.File->XrdSfsp->write(IO.Offset, argp->buff, myBlast)) < 0)
3254 {IO.IOLen = IO.IOLen-myBlast; IO.EInfo[0] = rc; IO.EInfo[1] = 0;
3255 return do_WriteNone();
3256 }
3257 IO.Offset += myBlast; IO.IOLen -= myBlast;
3258
3259// See if we need to finish this request in the normal way
3260//
3261 if (IO.IOLen > 0) return do_WriteAll();
3262 return Response.Send();
3263}
3264
3265/******************************************************************************/
3266/* d o _ W r i t e N o n e */
3267/******************************************************************************/
3268
3269int XrdXrootdProtocol::do_WriteNone()
3270{
3271 char *buff, dbuff[4096];
3272 int rlen, blen;
3273
3274// Determine which buffer we will use
3275//
3276 if (argp && argp->bsize > (int)sizeof(dbuff))
3277 {buff = argp->buff;
3278 blen = argp->bsize;
3279 } else {
3280 buff = dbuff;
3281 blen = sizeof(dbuff);
3282 }
3283 if (IO.IOLen < blen) blen = IO.IOLen;
3284
3285// Discard any data being transmitted
3286//
3287 TRACEP(REQ, "discarding " <<IO.IOLen <<" bytes");
3288 while(IO.IOLen > 0)
3289 {rlen = Link->Recv(buff, blen, readWait);
3290 if (rlen < 0) return Link->setEtext("link read error");
3291 IO.IOLen -= rlen;
3292 if (rlen < blen)
3293 {myBlen = 0;
3294 Resume = &XrdXrootdProtocol::do_WriteNone;
3295 return 1;
3296 }
3297 if (IO.IOLen < blen) blen = IO.IOLen;
3298 }
3299
3300// Send final message
3301//
3302 return do_WriteNoneMsg();
3303}
3304
3305/******************************************************************************/
3306
3307int XrdXrootdProtocol::do_WriteNone(int pathID, XErrorCode ec,
3308 const char *emsg)
3309{
3310// We can't recover when the data is arriving on a foriegn bound path as there
3311// no way to properly drain the socket. So, we terminate the connection.
3312//
3313 if (pathID != PathID)
3314 {if (ec && emsg) Response.Send(ec, emsg);
3315 else do_WriteNoneMsg();
3316 return Link->setEtext("write protocol violation");
3317 }
3318
3319// Set error code if present
3320//
3321 if (ec != kXR_noErrorYet)
3322 {IO.EInfo[1] = ec;
3323 if (IO.File)
3324 {if (!emsg) emsg = XProtocol::errName(ec);
3325 IO.File->XrdSfsp->error.setErrInfo(0, emsg);
3326 }
3327 }
3328
3329// Otherwise, continue to darin the socket
3330//
3331 return do_WriteNone();
3332}
3333
3334/******************************************************************************/
3335/* d o _ W r i t e N o n e M s g */
3336/******************************************************************************/
3337
3338int XrdXrootdProtocol::do_WriteNoneMsg()
3339{
3340// Send our the error message and return
3341//
3342 if (!IO.File) return
3343 Response.Send(kXR_FileNotOpen,"write does not refer to an open file");
3344
3345 if (IO.EInfo[1])
3346 return Response.Send((XErrorCode)IO.EInfo[1],
3347 IO.File->XrdSfsp->error.getErrText());
3348
3349 if (IO.EInfo[0]) return fsError(IO.EInfo[0], 0, IO.File->XrdSfsp->error, 0, 0);
3350
3351 return Response.Send(kXR_FSError, IO.File->XrdSfsp->error.getErrText());
3352}
3353
3354/******************************************************************************/
3355/* d o _ W r i t e S p a n */
3356/******************************************************************************/
3357
3359{
3360 int rc;
3361 XrdXrootdFHandle fh(Request.write.fhandle);
3362 numWrites++;
3363
3364// Unmarshall the data
3365//
3366 IO.IOLen = Request.header.dlen;
3367 n2hll(Request.write.offset, IO.Offset);
3368
3369// Find the file object. We will only drain socket data on the control path.
3370// .
3371 if (!FTab || !(IO.File = FTab->Get(fh.handle)))
3372 {IO.IOLen -= myBlast;
3373 IO.File = 0;
3374 return do_WriteNone(Request.write.pathid);
3375 }
3376
3377// If we are monitoring, insert a write entry
3378//
3379 if (Monitor.InOut())
3380 Monitor.Agent->Add_wr(IO.File->Stats.FileID, Request.write.dlen,
3381 Request.write.offset);
3382
3383// Trace this entry
3384//
3385 TRACEP(FSIO, "fh=" <<fh.handle <<" write " <<IO.IOLen <<'@' <<IO.Offset);
3386
3387// Write data that was already read
3388//
3389 if ((rc = IO.File->XrdSfsp->write(IO.Offset, myBuff, myBlast)) < 0)
3390 {IO.IOLen = IO.IOLen-myBlast; IO.EInfo[0] = rc; IO.EInfo[1] = 0;
3391 return do_WriteNone();
3392 }
3393 IO.Offset += myBlast; IO.IOLen -= myBlast;
3394
3395// See if we need to finish this request in the normal way
3396//
3397 if (IO.IOLen > 0) return do_WriteAll();
3398 return Response.Send();
3399}
3400
3401/******************************************************************************/
3402/* d o _ W r i t e V */
3403/******************************************************************************/
3404
3405int XrdXrootdProtocol::do_WriteV()
3406{
3407// This will write multiple buffers at the same time in an attempt to avoid
3408// the disk latency. The information with the offsets and lengths of the data
3409// to write is passed as a data buffer. We attempt to optimize as best as
3410// possible, though certain combinations may result in multiple writes. Since
3411// socket flushing is nearly impossible when an error occurs, most errors
3412// simply terminate the connection.
3413//
3414 const int wveSZ = sizeof(XrdProto::write_list);
3415 struct trackInfo
3416 {XrdXrootdWVInfo **wvInfo; bool doit;
3417 trackInfo(XrdXrootdWVInfo **wvP) : wvInfo(wvP), doit(true) {}
3418 ~trackInfo() {if (doit && *wvInfo) {free(*wvInfo); *wvInfo = 0;}}
3419 } freeInfo(&wvInfo);
3420
3421 struct XrdProto::write_list *wrLst;
3422 XrdOucIOVec *wrVec;
3423 long long totSZ, maxSZ;
3424 int curFH, k, Quantum, wrVecNum, wrVecLen = Request.header.dlen;
3425
3426// Compute number of elements in the write vector and make sure we have no
3427// partial elements.
3428//
3429 wrVecNum = wrVecLen / wveSZ;
3430 if ( (wrVecLen <= 0) || (wrVecNum*wveSZ != wrVecLen) )
3431 {Response.Send(kXR_ArgInvalid, "Write vector is invalid");
3432 return -1;
3433 }
3434
3435// Make sure that we can make a copy of the read vector. So, we impose a limit
3436// on it's size.
3437//
3438 if (wrVecNum > XrdProto::maxWvecsz)
3439 {Response.Send(kXR_ArgTooLong, "Write vector is too long");
3440 return -1;
3441 }
3442
3443// Create the verctor write information structure sized as needed.
3444//
3445 if (wvInfo) free(wvInfo);
3446 wvInfo = (XrdXrootdWVInfo *)malloc(sizeof(XrdXrootdWVInfo) +
3447 sizeof(XrdOucIOVec)*(wrVecNum-1));
3448 memset(wvInfo, 0, sizeof(XrdXrootdWVInfo) - sizeof(XrdOucIOVec));
3449 wvInfo->wrVec = wrVec = wvInfo->ioVec;
3450
3451// Run down the list and compute the total size of the write. No individual
3452// write may be greater than the maximum transfer size. We also use this loop
3453// to copy the write list to our writev vector for later processing.
3454//
3455 wrLst = (XrdProto::write_list *)argp->buff;
3456 totSZ = 0; maxSZ = 0; k = 0; Quantum = maxTransz; curFH = 0;
3457 for (int i = 0; i < wrVecNum; i++)
3458 {if (wrLst[i].wlen == 0) continue;
3459 memcpy(&wrVec[k].info, wrLst[i].fhandle, sizeof(int));
3460 wrVec[k].size = ntohl(wrLst[i].wlen);
3461 if (wrVec[k].size < 0)
3462 {Response.Send(kXR_ArgInvalid, "Writev length is negtive");
3463 return -1;
3464 }
3465 if (wrVec[k].size > Quantum)
3466 {Response.Send(kXR_NoMemory,"Single writev transfer is too large");
3467 return -1;
3468 }
3469 wrVec[k].offset = ntohll(wrLst[i].offset);
3470 if (wrVec[k].info == curFH) totSZ += wrVec[k].size;
3471 else {if (maxSZ < totSZ) maxSZ = totSZ;
3472 totSZ = wrVec[k].size;
3473 }
3474 k++;
3475 }
3476
3477// Check if we are not actually writing anything, simply return success
3478//
3479 if (maxSZ < totSZ) maxSZ = totSZ;
3480 if (maxSZ == 0) return Response.Send();
3481
3482// So, now we account for the number of writev requests and total segments
3483//
3484 numWritV++; numSegsW += k; wrVecNum = k;
3485
3486// Calculate the transfer unit which will be the smaller of the maximum
3487// transfer unit and the actual amount we need to transfer.
3488//
3489 if (maxSZ > maxTransz) Quantum = maxTransz;
3490 else Quantum = static_cast<int>(maxSZ);
3491
3492// Now obtain the right size buffer
3493//
3494 if ((Quantum < halfBSize && Quantum > 1024) || Quantum > argp->bsize)
3495 {if (getBuff(0, Quantum) <= 0) return -1;}
3496 else if (hcNow < hcNext) hcNow++;
3497
3498// Check that we really have at least the first file open (part of setup)
3499//
3500 if (!FTab || !(IO.File = FTab->Get(wrVec[0].info)))
3501 {Response.Send(kXR_FileNotOpen, "writev does not refer to an open file");
3502 return -1;
3503 }
3504
3505// Setup to do the complete transfer
3506//
3507 wvInfo->curFH = wrVec[0].info;
3508 wvInfo->vBeg = 0;
3509 wvInfo->vPos = 0;
3510 wvInfo->vEnd = wrVecNum;
3511 wvInfo->vMon = 0;
3512 wvInfo->doSync= (Request.writev.options & ClientWriteVRequest::doSync) != 0;
3513 wvInfo->wvMon = Monitor.InOut();
3514 wvInfo->ioMon = (wvInfo->vMon > 1);
3515// wvInfo->vType = (wvInfo->ioMon ? XROOTD_MON_WRITEU : XROOTD_MON_WRITEV);
3516 IO.WVBytes = 0;
3517 IO.IOLen = wrVec[0].size;
3518 myBuff = argp->buff;
3519 myBlast = 0;
3520
3521// Now we simply start the write operations if this is a true writev request.
3522// Otherwise return to the caller for additional processing.
3523//
3524 freeInfo.doit = false;
3525 if (Request.header.requestid == kXR_writev) return do_WriteVec();
3526 return 0;
3527}
3528
3529/******************************************************************************/
3530/* d o _ W r i t e V e c */
3531/******************************************************************************/
3532
3533int XrdXrootdProtocol::do_WriteVec()
3534{
3535 XrdSfsXferSize xfrSZ;
3536 int rc, wrVNum, vNow = wvInfo->vPos;
3537 bool done, newfile;
3538
3539// Read the complete data from the socket for the current element. Note that
3540// should we enter a resume state; upon re-entry all of the data will be read.
3541//
3542do{if (IO.IOLen > 0)
3543 {wvInfo->wrVec[vNow].data = argp->buff + myBlast;
3544 myBlast += IO.IOLen;
3545 if ((rc = getData("data", myBuff, IO.IOLen)))
3546 {if (rc < 0) return rc;
3547 IO.IOLen = 0;
3548 Resume = &XrdXrootdProtocol::do_WriteVec;
3549 return rc;
3550 }
3551 }
3552
3553// Establish the state at this point as this will tell us what to do next.
3554//
3555 vNow++;
3556 done = newfile = false;
3557 if (vNow >= wvInfo->vEnd) done = true;
3558 else if (wvInfo->wrVec[vNow].info != wvInfo->curFH) newfile = true;
3559 else if (myBlast + wvInfo->wrVec[vNow].size <= argp->bsize)
3560 {IO.IOLen = wvInfo->wrVec[vNow].size;
3561 myBuff = argp->buff + myBlast;
3562 wvInfo->vPos = vNow;
3563 continue;
3564 }
3565
3566// We need to write out what we have.
3567//
3568 wrVNum = vNow - wvInfo->vBeg;
3569 xfrSZ = IO.File->XrdSfsp->writev(&(wvInfo->wrVec[wvInfo->vBeg]), wrVNum);
3570 TRACEP(FSIO,"fh=" <<wvInfo->curFH <<" writeV " << xfrSZ <<':' <<wrVNum);
3571 if (xfrSZ != myBlast) break;
3572
3573// Check if we need to do monitoring or a sync with no deferal. Note that
3574// we currently do not support detailed monitoring for vector writes!
3575//
3576 if (done || newfile)
3577 {int monVnum = vNow - wvInfo->vMon;
3578 IO.File->Stats.wvOps(IO.WVBytes, monVnum);
3588 wvInfo->vMon = vNow;
3589 IO.WVBytes = 0;
3590 if (wvInfo->doSync)
3591 {IO.File->XrdSfsp->error.setErrCB(0,0);
3592 xfrSZ = IO.File->XrdSfsp->sync();
3593 if (xfrSZ< 0) break;
3594 }
3595 }
3596
3597// If we are done, the finish up
3598//
3599 if (done)
3600 {if (wvInfo) {free(wvInfo); wvInfo = 0;}
3601 return Response.Send();
3602 }
3603
3604// Sequence to a new file if we need to do so
3605//
3606 if (newfile)
3607 {if (!FTab || !(IO.File = FTab->Get(wvInfo->wrVec[vNow].info)))
3608 {Response.Send(kXR_FileNotOpen,"writev does not refer to an open file");
3609 return -1;
3610 }
3611 wvInfo->curFH = wvInfo->wrVec[vNow].info;
3612 }
3613
3614// Setup to resume transfer
3615//
3616 myBlast = 0;
3617 myBuff = argp->buff;
3618 IO.IOLen = wvInfo->wrVec[vNow].size;
3619 wvInfo->vBeg = vNow;
3620 wvInfo->vPos = vNow;
3621
3622} while(true);
3623
3624// If we got here then there was a write error (file pointer is valid).
3625//
3626 if (wvInfo) {free(wvInfo); wvInfo = 0;}
3627 return fsError((int)xfrSZ, 0, IO.File->XrdSfsp->error, 0, 0);
3628}
3629
3630/******************************************************************************/
3631/* S e n d F i l e */
3632/******************************************************************************/
3633
3635{
3636
3637// Make sure we have some data to send
3638//
3639 if (!IO.IOLen) return 1;
3640
3641// Send off the data
3642//
3643 IO.IOLen = Response.Send(fildes, IO.Offset, IO.IOLen);
3644 return IO.IOLen;
3645}
3646
3647/******************************************************************************/
3648
3650{
3651 int i, xframt = 0;
3652
3653// Make sure we have some data to send
3654//
3655 if (!IO.IOLen) return 1;
3656
3657// Verify the length, it can't be greater than what the client wants
3658//
3659 for (i = 1; i < sfvnum; i++) xframt += sfvec[i].sendsz;
3660 if (xframt > IO.IOLen) return 1;
3661
3662// Send off the data
3663//
3664 if (xframt) IO.IOLen = Response.Send(sfvec, sfvnum, xframt);
3665 else {IO.IOLen = 0; Response.Send();}
3666 return IO.IOLen;
3667}
3668
3669/******************************************************************************/
3670/* S e t F D */
3671/******************************************************************************/
3672
3674{
3675 if (fildes < 0) IO.File->sfEnabled = 0;
3676 else IO.File->fdNum = fildes;
3677}
3678
3679/******************************************************************************/
3680/* U t i l i t y M e t h o d s */
3681/******************************************************************************/
3682/******************************************************************************/
3683/* f s E r r o r */
3684/******************************************************************************/
3685
3686int XrdXrootdProtocol::fsError(int rc, char opC, XrdOucErrInfo &myError,
3687 const char *Path, char *Cgi)
3688{
3689 int ecode, popt, rs;
3690 const char *eMsg = myError.getErrText(ecode);
3691
3692// Process standard errors
3693//
3694 if (rc == SFS_ERROR)
3695 {SI->errorCnt++;
3696 rc = XProtocol::mapError(ecode);
3697
3698 if (Path && (rc == kXR_Overloaded) && (opC == XROOTD_MON_OPENR
3699 || opC == XROOTD_MON_OPENW || opC == XROOTD_MON_OPENC))
3700 {if (myError.extData()) myError.Reset();
3701 return fsOvrld(opC, Path, Cgi);
3702 }
3703
3704 if (Path && (rc == kXR_NotFound) && RQLxist && opC
3705 && (popt = RQList.Validate(Path)))
3708 Route[popt].Host[rdType],
3709 Route[popt].Port[rdType],
3711 if (Cgi) rs = fsRedirNoEnt(eMsg, Cgi, popt);
3712 else rs = Response.Send(kXR_redirect,
3713 Route[popt].Port[rdType],
3714 Route[popt].Host[rdType]);
3715 } else rs = Response.Send((XErrorCode)rc, eMsg);
3716 if (myError.extData()) myError.Reset();
3717 return rs;
3718 }
3719
3720// Process the redirection (error msg is host:port)
3721//
3722 if (rc == SFS_REDIRECT)
3723 {SI->redirCnt++;
3724 // if the plugin set some redirect flags but the client does not
3725 // support them, clear the flags (set -1)
3726 if( ecode < -1 && !( clientPV & XrdOucEI::uRedirFlgs ) )
3727 ecode = -1;
3728 if (XrdXrootdMonitor::Redirect() && Path && opC)
3730 if (TRACING(TRACE_REDIR))
3731 {if (ecode < 0)
3732 {TRACEI(REDIR, Response.ID() <<"redirecting to " << eMsg);}
3733 else {TRACEI(REDIR, Response.ID() <<"redirecting to "
3734 << eMsg <<':' <<ecode);
3735 }
3736 }
3737 rs = Response.Send(kXR_redirect, ecode, eMsg, myError.getErrTextLen());
3738 if (myError.extData()) myError.Reset();
3739 return rs;
3740 }
3741
3742// Process the deferal. We also synchronize sending the deferal response with
3743// sending the actual deferred response by calling Done() in the callback object.
3744// This allows the requestor of he callback know that we actually send the
3745// kXR_waitresp to the end client and avoid violating time causality.
3746//
3747 if (rc == SFS_STARTED)
3748 {SI->stallCnt++;
3749 if (ecode <= 0) ecode = 1800;
3750 TRACEI(STALL, Response.ID() <<"delaying client up to " <<ecode <<" sec");
3751 rc = Response.Send(kXR_waitresp, ecode, eMsg);
3752 if (myError.getErrCB()) myError.getErrCB()->Done(ecode, &myError);
3753 if (myError.extData()) myError.Reset();
3754 return (rc ? rc : 1);
3755 }
3756
3757// Process the data response
3758//
3759 if (rc == SFS_DATA)
3760 {if (ecode) rs = Response.Send((void *)eMsg, ecode);
3761 else rs = Response.Send();
3762 if (myError.extData()) myError.Reset();
3763 return rs;
3764 }
3765
3766// Process the data response via an iovec
3767//
3768 if (rc == SFS_DATAVEC)
3769 {if (ecode < 2) rs = Response.Send();
3770 else rs = Response.Send((struct iovec *)eMsg, ecode);
3771 if (myError.getErrCB()) myError.getErrCB()->Done(ecode, &myError);
3772 if (myError.extData()) myError.Reset();
3773 return rs;
3774 }
3775
3776// Process the deferal
3777//
3778 if (rc >= SFS_STALL)
3779 {SI->stallCnt++;
3780 TRACEI(STALL, Response.ID() <<"stalling client for " <<rc <<" sec");
3781 rs = Response.Send(kXR_wait, rc, eMsg);
3782 if (myError.extData()) myError.Reset();
3783 return rs;
3784 }
3785
3786// Unknown conditions, report it
3787//
3788 {char buff[32];
3789 SI->errorCnt++;
3790 sprintf(buff, "%d", rc);
3791 eDest.Emsg("Xeq", "Unknown error code", buff, eMsg);
3792 rs = Response.Send(kXR_ServerError, eMsg);
3793 if (myError.extData()) myError.Reset();
3794 return rs;
3795 }
3796}
3797
3798/******************************************************************************/
3799/* f s O v r l d */
3800/******************************************************************************/
3801
3802int XrdXrootdProtocol::fsOvrld(char opC, const char *Path, char *Cgi)
3803{
3804 static const char *prot = "root://";
3805 static int negOne = -1;
3806 static char quest = '?', slash = '/';
3807
3808 struct iovec rdrResp[8];
3809 char *destP=0, dest[512];
3810 int iovNum=0, pOff, port;
3811
3812// If this is a forwarded path and the client can handle full url's then
3813// redirect the client to the destination in the path. Otherwise, if there is
3814// an alternate destination, send client there. Otherwise, stall the client.
3815//
3817 && (pOff = XrdOucUtils::isFWD(Path, &port, dest, sizeof(dest))))
3818 { rdrResp[1].iov_base = (char *)&negOne;
3819 rdrResp[1].iov_len = sizeof(negOne);
3820 rdrResp[2].iov_base = (char *)prot;
3821 rdrResp[2].iov_len = 7; // root://
3822 rdrResp[3].iov_base = (char *)dest;
3823 rdrResp[3].iov_len = strlen(dest); // host:port
3824 rdrResp[4].iov_base = (char *)&slash;
3825 rdrResp[4].iov_len = (*Path == '/' ? 1 : 0); // / or nil for objid
3826 rdrResp[5].iov_base = (char *)(Path+pOff);
3827 rdrResp[5].iov_len = strlen(Path+pOff); // path
3828 if (Cgi && *Cgi)
3829 {rdrResp[6].iov_base = (char *)&quest;
3830 rdrResp[6].iov_len = sizeof(quest); // ?
3831 rdrResp[7].iov_base = (char *)Cgi;
3832 rdrResp[7].iov_len = strlen(Cgi); // cgi
3833 iovNum = 8;
3834 } else iovNum = 6;
3835 destP = dest;
3836 } else if ((destP = Route[RD_ovld].Host[rdType]))
3837 port = Route[RD_ovld].Port[rdType];
3838
3839// If a redirect happened, then trace it.
3840//
3841 if (destP)
3842 {SI->redirCnt++;
3844 XrdXrootdMonitor::Redirect(Monitor.Did, destP, port,
3846 if (iovNum)
3847 {TRACEI(REDIR, Response.ID() <<"redirecting to "<<dest);
3848 return Response.Send(kXR_redirect, rdrResp, iovNum);
3849 } else {
3850 TRACEI(REDIR, Response.ID() <<"redirecting to "<<destP<<':'<<port);
3851 return Response.Send(kXR_redirect, port, destP);
3852 }
3853 }
3854
3855// If there is a stall value, then delay the client
3856//
3857 if (OD_Stall)
3858 {TRACEI(STALL, Response.ID()<<"stalling client for "<<OD_Stall<<" sec");
3859 SI->stallCnt++;
3860 return Response.Send(kXR_wait, OD_Stall, "server is overloaded");
3861 }
3862
3863// We were unsuccessful, return overload as an error
3864//
3865 return Response.Send(kXR_Overloaded, "server is overloaded");
3866}
3867
3868/******************************************************************************/
3869/* f s R e d i r N o E n t */
3870/******************************************************************************/
3871
3872int XrdXrootdProtocol::fsRedirNoEnt(const char *eMsg, char *Cgi, int popt)
3873{
3874 struct iovec ioV[4];
3875 char *tried, *trend, *ptried = 0;
3876 kXR_int32 pnum = htonl(static_cast<kXR_int32>(Route[popt].Port[rdType]));
3877 int tlen;
3878
3879// Try to find the last tried token in the cgi
3880//
3881 if ((trend = Cgi))
3882 {do {if (!(tried = strstr(Cgi, "tried="))) break;
3883 if (tried == trend || *(tried-1) == '&')
3884 {if (!ptried || (*(tried+6) && *(tried+6) != '&')) ptried=tried;}
3885 Cgi = index(tried+6, '&');
3886 } while(Cgi);
3887 }
3888
3889// If we did find a tried, bracket it out with a leading comma (we can modify
3890// the passed cgi string here because this is the last time it will be used.
3891//
3892 if ((tried = ptried))
3893 {tried += 5;
3894 while(*(tried+1) && *(tried+1) == ',') tried++;
3895 trend = index(tried, '&');
3896 if (trend) {tlen = trend - tried; *trend = 0;}
3897 else tlen = strlen(tried);
3898 *tried = ',';
3899 } else tlen = 0;
3900
3901// Check if we are in a redirect loop (i.e. we are listed in the client's cgi).
3902// If so, then treat this and file not found as we've been here before.
3903//
3904 if ((trend = tried) && eMsg)
3905 do {if ((trend = strstr(trend, myCName)))
3906 {if (*(trend+myCNlen) == '\0' || *(trend+myCNlen) == ',')
3907 return Response.Send(kXR_NotFound, eMsg);
3908 trend = index(trend+myCNlen, ',');
3909 }
3910 } while(trend);
3911
3912
3913// If we have not found a tried token or that token far too large to propogate
3914// (i.e. it's likely we have an undetected loop), then do a simple redirect.
3915//
3916 if (!tried || !tlen || tlen > 16384)
3917 return Response.Send(kXR_redirect,
3918 Route[popt].Port[rdType],
3919 Route[popt].Host[rdType]);
3920
3921// We need to append the client's tried list to the one we have to avoid loops
3922//
3923
3924 ioV[1].iov_base = (char *)&pnum;
3925 ioV[1].iov_len = sizeof(pnum);
3926 ioV[2].iov_base = Route[popt].Host[rdType];
3927 ioV[2].iov_len = Route[popt].RDSz[rdType];
3928 ioV[3].iov_base = tried;
3929 ioV[3].iov_len = tlen;
3930
3931// Compute total length
3932//
3933 tlen += sizeof(pnum) + Route[popt].RDSz[rdType];
3934
3935// Send off the redirect
3936//
3937 return Response.Send(kXR_redirect, ioV, 4, tlen);
3938}
3939
3940/******************************************************************************/
3941/* g e t B u f f */
3942/******************************************************************************/
3943
3944int XrdXrootdProtocol::getBuff(const int isRead, int Quantum)
3945{
3946
3947// Check if we need to really get a new buffer
3948//
3949 if (!argp || Quantum > argp->bsize) hcNow = hcPrev;
3950 else if (Quantum >= halfBSize || hcNow-- > 0) return 1;
3951 else if (hcNext >= hcMax) hcNow = hcMax;
3952 else {int tmp = hcPrev;
3953 hcNow = hcNext;
3954 hcPrev = hcNext;
3955 hcNext = tmp+hcNext;
3956 }
3957
3958// Get a new buffer
3959//
3960 if (argp) BPool->Release(argp);
3961 if ((argp = BPool->Obtain(Quantum))) halfBSize = argp->bsize >> 1;
3962 else return Response.Send(kXR_NoMemory, (isRead ?
3963 "insufficient memory to read file" :
3964 "insufficient memory to write file"));
3965
3966// Success
3967//
3968 return 1;
3969}
3970
3971/******************************************************************************/
3972/* Private: g e t C k s T y p e */
3973/******************************************************************************/
3974
3975char *XrdXrootdProtocol::getCksType(char *opaque, char *cspec, int cslen)
3976{
3977 char *cksT;
3978
3979// Get match for user specified checksum type, if any. Otherwise return default.
3980//
3981 if (opaque && *opaque)
3982 {XrdOucEnv jobEnv(opaque);
3983 if ((cksT = jobEnv.Get("cks.type")))
3984 {XrdOucTList *tP = JobCKTLST;
3985 while(tP && strcasecmp(tP->text, cksT)) tP = tP->next;
3986 if (!tP && cspec) snprintf(cspec, cslen, "%s", cksT);
3987 return (tP ? tP->text : 0);
3988 }
3989 }
3990
3991// Return default
3992//
3993 return JobCKT;
3994}
3995
3996/******************************************************************************/
3997/* Private: l o g L o g i n */
3998/******************************************************************************/
3999
4000bool XrdXrootdProtocol::logLogin(bool xauth)
4001{
4002 const char *uName, *ipName, *tMsg, *zMsg = "";
4003 char lBuff[512], pBuff[512];
4004
4005// Determine ip type
4006//
4008 ipName = (clientPV & XrdOucEI::uIPv64 ? "IP46" : "IPv4");
4009 else ipName = (clientPV & XrdOucEI::uIPv64 ? "IP64" : "IPv6");
4010
4011// Determine client name
4012//
4013 if (xauth) uName = (Client->name ? Client->name : "nobody");
4014 else uName = 0;
4015
4016// Check if TLS was or will be used
4017//
4018 tMsg = Link->verTLS();
4019 if (*tMsg) zMsg = " ";
4020
4021// Format the line
4022//
4023 snprintf(lBuff, sizeof(lBuff), "%s %s %s%slogin%s%s",
4024 (clientPV & XrdOucEI::uPrip ? "pvt" : "pub"), ipName,
4025 tMsg, zMsg,
4026 (xauth ? " as " : ""),
4027 (uName ? uName : ""));
4028
4029// Document the login
4030//
4031 if (Client->tident != Client->pident)
4032 {snprintf(pBuff, sizeof(pBuff), "via %s auth for %s",
4033 Client->prot, Client->pident);
4034 } else *pBuff = 0;
4035 eDest.Log(SYS_LOG_01, "Xeq", Link->ID, lBuff, (*pBuff ? pBuff : 0));
4036
4037// Enable TLS if we need to (note sess setting is off if login setting is on).
4038// If we need to but the client is not TLS capable, send an error and terminate.
4039//
4040 if ((doTLS & Req_TLSSess) && !Link->hasBridge())
4041 {if (ableTLS)
4042 {if (Link->setTLS(true, tlsCtx))
4043 {Link->setProtName("xroots");
4044 isTLS = true;
4045 } else {
4046 eDest.Emsg("Xeq", "Unable to require TLS for", Link->ID);
4047 return false;
4048 }
4049 } else {
4050 eDest.Emsg("Xeq","session requires TLS but",Link->ID,"is incapable.");
4051 Response.Send(kXR_TLSRequired, "session requires TLS support");
4052 return false;
4053 }
4054 }
4055
4056// Record the appname in the final SecEntity object
4057//
4058 if (AppName) Client->eaAPI->Add("xrd.appname", (std::string)AppName);
4059
4060// Assign unique identifier to the final SecEntity object
4061//
4062 Client->ueid = mySID;
4063
4064// Propogate a connect through the whole system
4065//
4066 osFS->Connect(Client);
4067 return true;
4068}
4069
4070/******************************************************************************/
4071/* m a p M o d e */
4072/******************************************************************************/
4073
4074#define Map_Mode(x,y) if (Mode & kXR_ ## x) newmode |= S_I ## y
4075
4076int XrdXrootdProtocol::mapMode(int Mode)
4077{
4078 int newmode = 0;
4079
4080// Map the mode in the obvious way
4081//
4082 Map_Mode(ur, RUSR); Map_Mode(uw, WUSR); Map_Mode(ux, XUSR);
4083 Map_Mode(gr, RGRP); Map_Mode(gw, WGRP); Map_Mode(gx, XGRP);
4084 Map_Mode(or, ROTH); Map_Mode(ox, XOTH);
4085
4086// All done
4087//
4088 return newmode;
4089}
4090
4091/******************************************************************************/
4092/* M o n A u t h */
4093/******************************************************************************/
4094
4096{
4097 char Buff[4096];
4098 const char *bP = Buff;
4099
4100 if (Client == &Entity) bP = Entity.moninfo;
4101 else {snprintf(Buff,sizeof(Buff),
4102 "&p=%s&n=%s&h=%s&o=%s&r=%s&g=%s&m=%s%s&I=%c",
4103 Client->prot,
4104 (Client->name ? Client->name : ""),
4105 (Client->host ? Client->host : ""),
4106 (Client->vorg ? Client->vorg : ""),
4107 (Client->role ? Client->role : ""),
4108 (Client->grps ? Client->grps : ""),
4109 (Client->moninfo ? Client->moninfo : ""),
4110 (Entity.moninfo ? Entity.moninfo : ""),
4111 (clientPV & XrdOucEI::uIPv4 ? '4' : '6')
4112 );
4113 Client->secMon = &Monitor;
4114 }
4115
4116 Monitor.Report(bP);
4117 if (Entity.moninfo) {free(Entity.moninfo); Entity.moninfo = 0;}
4118}
4119
4120/******************************************************************************/
4121/* r p C h e c k */
4122/******************************************************************************/
4123
4124int XrdXrootdProtocol::rpCheck(char *fn, char **opaque)
4125{
4126 char *cp;
4127
4128 if (*fn != '/')
4129 {if (!(XPList.Opts() & XROOTDXP_NOSLASH)) return 1;
4130 if ( XPList.Opts() & XROOTDXP_NOCGI) {*opaque = 0; return 0;}
4131 }
4132
4133 if (!(cp = index(fn, '?'))) *opaque = 0;
4134 else {*cp = '\0'; *opaque = cp+1;
4135 if (!**opaque) *opaque = 0;
4136 }
4137
4138 if (*fn != '/') return 0;
4139
4140 while ((cp = index(fn, '/')))
4141 {fn = cp+1;
4142 if (fn[0] == '.' && fn[1] == '.' && fn[2] == '/') return 1;
4143 }
4144 return 0;
4145}
4146
4147/******************************************************************************/
4148/* r p E m s g */
4149/******************************************************************************/
4150
4151int XrdXrootdProtocol::rpEmsg(const char *op, char *fn)
4152{
4153 char buff[2048];
4154 snprintf(buff,sizeof(buff)-1,"%s relative path '%s' is disallowed.",op,fn);
4155 buff[sizeof(buff)-1] = '\0';
4156 return Response.Send(kXR_NotAuthorized, buff);
4157}
4158
4159/******************************************************************************/
4160/* S e t S F */
4161/******************************************************************************/
4162
4163int XrdXrootdProtocol::SetSF(kXR_char *fhandle, bool seton)
4164{
4165 XrdXrootdFHandle fh(fhandle);
4166 XrdXrootdFile *theFile;
4167
4168 if (!FTab || !(theFile = FTab->Get(fh.handle))) return -EBADF;
4169
4170// Turn it off or on if so wanted
4171//
4172 if (!seton) theFile->sfEnabled = 0;
4173 else if (theFile->fdNum >= 0) theFile->sfEnabled = 1;
4174
4175// All done
4176//
4177 return 0;
4178}
4179
4180/******************************************************************************/
4181/* S q u a s h */
4182/******************************************************************************/
4183
4184int XrdXrootdProtocol::Squash(char *fn)
4185{
4186 char *ofn, *ifn = fn;
4187
4188 if (*fn != '/') return XPList.Opts();
4189
4190 while(*ifn)
4191 {if (*ifn == '/')
4192 if (*(ifn+1) == '/'
4193 || (*(ifn+1) == '.' && *(ifn+1) && *(ifn+2) == '/')) break;
4194 ifn++;
4195 }
4196
4197 if (!*ifn) return XPList.Validate(fn, ifn-fn);
4198
4199 ofn = ifn;
4200 while(*ifn) {*ofn = *ifn++;
4201 while(*ofn == '/')
4202 {while(*ifn == '/') ifn++;
4203 if (ifn[0] == '.' && ifn[1] == '/') ifn += 2;
4204 else break;
4205 }
4206 ofn++;
4207 }
4208 *ofn = '\0';
4209
4210 return XPList.Validate(fn, ofn-fn);
4211}
4212
4213/******************************************************************************/
4214/* v p E m s g */
4215/******************************************************************************/
4216
4217int XrdXrootdProtocol::vpEmsg(const char *op, char *fn)
4218{
4219 char buff[2048];
4220 snprintf(buff,sizeof(buff)-1,"%s path '%s' is disallowed.",op,fn);
4221 buff[sizeof(buff)-1] = '\0';
4222 return Response.Send(kXR_NotAuthorized, buff);
4223}
XErrorCode
Definition XProtocol.hh:989
@ kXR_ArgInvalid
Definition XProtocol.hh:990
@ kXR_InvalidRequest
Definition XProtocol.hh:996
@ kXR_ArgMissing
Definition XProtocol.hh:991
@ kXR_TLSRequired
@ kXR_AuthFailed
@ kXR_NotAuthorized
@ kXR_NotFound
@ kXR_FileLocked
Definition XProtocol.hh:993
@ kXR_noErrorYet
@ kXR_ChkSumErr
@ kXR_overQuota
@ kXR_FileNotOpen
Definition XProtocol.hh:994
@ kXR_Unsupported
@ kXR_Cancelled
@ kXR_ServerError
@ kXR_Overloaded
@ kXR_ArgTooLong
Definition XProtocol.hh:992
@ kXR_FSError
Definition XProtocol.hh:995
@ kXR_NoMemory
Definition XProtocol.hh:998
@ kXR_ecredir
Definition XProtocol.hh:371
#define kXR_ShortProtRespLen
#define kXR_gotoTLS
#define kXR_haveTLS
#define kXR_PROTSIGNVERSION
Definition XProtocol.hh:74
kXR_char pathid
Definition XProtocol.hh:653
@ 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
@ kXR_waitresp
Definition XProtocol.hh:906
@ kXR_redirect
Definition XProtocol.hh:904
@ kXR_oksofar
Definition XProtocol.hh:900
@ kXR_ok
Definition XProtocol.hh:899
@ kXR_authmore
Definition XProtocol.hh:902
@ kXR_wait
Definition XProtocol.hh:905
@ kXR_dstat
Definition XProtocol.hh:240
@ kXR_dcksm
Definition XProtocol.hh:241
kXR_char fhandle[4]
Definition XProtocol.hh:659
@ kXR_writev
Definition XProtocol.hh:143
@ kXR_mkdir
Definition XProtocol.hh:120
@ kXR_write
Definition XProtocol.hh:131
kXR_int32 rlen
Definition XProtocol.hh:660
@ kXR_vermask
Definition XProtocol.hh:377
@ kXR_asyncap
Definition XProtocol.hh:378
#define kXR_attrProxy
#define kXR_PROTOCOLVERSION
Definition XProtocol.hh:70
kXR_int64 offset
Definition XProtocol.hh:661
@ kXR_vfs
Definition XProtocol.hh:763
@ 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
ServerResponseReqs_Protocol secreq
@ 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
@ 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()
XrdOucTrace * XrdXrootdTrace
#define TRACE_AUTH
#define TRACE_REDIR
#define ENODATA
#define stat(a, b)
Definition XrdPosix.hh:96
XrdSecBuffer XrdSecParameters
XrdSecBuffer XrdSecCredentials
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
const char * XrdSysE2T(int errcode)
Definition XrdSysE2T.cc:104
const int SYS_LOG_01
if(ec< 0) ec
#define TRACING(x)
Definition XrdTrace.hh:70
#define TRACEI(act, x)
Definition XrdTrace.hh:66
XrdOucString * XrdXrootdCF
#define JOB_Sync
const kXR_char XROOTD_MON_OPENW
const kXR_char XROOTD_MON_STAT
const kXR_char XROOTD_MON_REDLOCAL
const kXR_char XROOTD_MON_PREP
const kXR_char XROOTD_MON_OPENC
const kXR_char XROOTD_MON_TRUNC
const kXR_char XROOTD_MON_CLOSE
const kXR_char XROOTD_MON_CHMOD
const kXR_char XROOTD_MON_LOCATE
const kXR_char XROOTD_MON_OPENR
const kXR_char XROOTD_MON_MV
const kXR_char XROOTD_MON_RMDIR
const kXR_char XROOTD_MON_RM
const kXR_char XROOTD_MON_OPENDIR
const kXR_char XROOTD_MON_QUERY
const kXR_char XROOTD_MON_MKDIR
#define XRD_BOUNDPATH
#define XRD_LOGGEDIN
#define XRD_NEED_AUTH
#define TRACE_FS
#define TRACEP(act, x)
#define XROOTDXP_NOLK
#define XROOTDXP_NOSLASH
#define XROOTDXP_NOMWCHK
#define XROOTDXP_NOCGI
#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)
static const int ValuSize
Definition XrdCksData.hh:42
static const int NameSize
Definition XrdCksData.hh:41
static bool GetAssumeV4()
Definition XrdInet.hh:65
XrdJob(const char *desc="")
Definition XrdJob.hh:51
static XrdLink * fd2link(int fd)
Definition XrdLinkCtl.hh:72
bool isMapped() const
bool isIPType(IPType ipType) const
static bool getEA(const char *cgi, int &ecode, int &acode)
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()
void setUCap(int ucval)
Set user capabilties.
void Reset()
Reset object to no message state. Call this method to release appendages.
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)
XrdSfsDio()
Constructor and destructor.
Definition XrdSfsDio.hh:103
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 int sync()=0
XrdOucErrInfo & error
virtual int open(const char *fileName, XrdSfsFileOpenMode openMode, mode_t createMode, const XrdSecEntity *client=0, const char *opaque=0)=0
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
static void Snooze(int seconds)
XrdXrootdPgwFob * pgwFob
XrdSfsFile * XrdSfsp
XrdXrootdFileStats Stats
static void Open(XrdXrootdFileStats *fsP, const char *Path, unsigned int uDID, bool isRW)
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 XrdScheduler * Sched
static const char Req_TLSLogin
XrdXrootdResponse Response
int(XrdXrootdProtocol::* ResumePio)()
static const int maxStreams
static XrdOucTList * JobCKTLST
static XrdXrootdXPath RQList
static struct XrdXrootdProtocol::RD_Table Route[RD_Num]
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 XrdSfsFileSystem * osFS
void Set(XrdLink *lp)
static const int maxRvecsz
Definition XProtocol.hh:686
static const int maxWvecsz
Definition XProtocol.hh:838
static const uint64_t hasCACH
Feature: Implements a data cache.
static const uint64_t hasSXIO
Feature: Supports SfsXio.
ssize_t Send(int fd, KernelBuffer &buffer)
char * bifResp[2]
static const kXR_int32 doSync
Definition XProtocol.hh:826
char TimeZone
+/- hours from GMT (-128 if not set)
unsigned char Country[2]
Two letter TLD country code.
static const int uRedirFlgs
ucap: Client supports "file://"
static const int uVMask
static const int uUrlOK
ucap: Supports async responses
static const int uIPv64
ucap: Supports only IPv4 info
static const int uReadR
ucap: Supports multiple protocols
static const int uEcRedir
ucap: Client supports redirect flags
static const int uMProt
ucap: Supports url redirects
static const int uLclF
ucap: Client is on a private net
static const int uAsync
ucap: Extract protocol version
static const int uIPv4
ucap: Supports read redirects
static const int uPrip
long long offset
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