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_mkpath | kXR_async))
1428 {*op++ = 'm';
1429 mode |= SFS_O_MKPTH;
1430 }
1431 }
1432 if (opts & kXR_compress)
1433 {openopts |= SFS_O_RAWIO; *op++ = 'c'; compchk = 1;}
1434 if (opts & kXR_force) {*op++ = 'f'; doforce = true;}
1435 if ((opts & kXR_async || as_force) && as_aioOK)
1436 {*op++ = 'a'; isAsync = true;}
1437 if (opts & kXR_refresh) {*op++ = 's'; openopts |= SFS_O_RESET;
1438 SI->Bump(SI->Refresh);
1439 }
1440 if (opts & kXR_retstat) {*op++ = 't'; retStat = 1;}
1441 if (opts & kXR_posc) {*op++ = 'p'; openopts |= SFS_O_POSC;}
1442 if (opts & kXR_seqio) {*op++ = 'S'; openopts |= SFS_O_SEQIO;}
1443 *op = '\0';
1444
1445// Do some tracing, avoid exposing any security token in the URL
1446//
1447 if (TRACING(TRACE_FS))
1448 {char* cgiP = index(fn, '?');
1449 if (cgiP) *cgiP = 0;
1450 TRACEP(FS, "open " <<opt <<' ' <<fn);
1451 if (cgiP) *cgiP = '?';
1452 }
1453
1454// Check if opaque data has been provided
1455//
1456 if (rpCheck(fn, &opaque)) return rpEmsg("Opening", fn);
1457
1458// Check if this is a local dig type file
1459//
1460 doDig = (digFS && SFS_LCLPATH(fn));
1461
1462// Validate the path and then check if static redirection applies
1463//
1464 if (doDig) {popt = XROOTDXP_NOLK; opC = 0;}
1465 else {int ropt;
1466 if (!(popt = Squash(fn))) return vpEmsg("Opening", fn);
1467 if (Route[RD_open1].Host[rdType] && (ropt = RPList.Validate(fn)))
1468 return Response.Send(kXR_redirect, Route[ropt].Port[rdType],
1469 Route[ropt].Host[rdType]);
1470 }
1471
1472// Add the multi-write option if this path supports it
1473//
1474 if (popt & XROOTDXP_NOMWCHK) openopts |= SFS_O_MULTIW;
1475
1476// Construct an open helper to release resources should we exit due to an error.
1477//
1478 OpenHelper oHelp(Locker, fn);
1479
1480// Lock this file
1481//
1482 if (!(popt & XROOTDXP_NOLK))
1483 {if ((rc = Locker->Lock(fn, usage, doforce)))
1484 {const char *who;
1485 if (rc > 0) who = (rc > 1 ? "readers" : "reader");
1486 else { rc = -rc;
1487 who = (rc > 1 ? "writers" : "writer");
1488 }
1489 snprintf(ebuff, sizeof(ebuff)-1,
1490 "%s file %s is already opened by %d %s; open denied.",
1491 ('r' == usage ? "Input" : "Output"), fn, rc, who);
1492 eDest.Emsg("Xeq", ebuff);
1493 return Response.Send(kXR_FileLocked, ebuff);
1494 } else oHelp.mode = usage;
1495 }
1496
1497// Get a file object
1498//
1499 if (doDig) fp = digFS->newFile(Link->ID, Monitor.Did);
1500 else fp = osFS->newFile(Link->ID, Monitor.Did);
1501
1502// Make sure we got one
1503//
1504 if (!fp)
1505 {snprintf(ebuff, sizeof(ebuff)-1,"Insufficient memory to open %s",fn);
1506 eDest.Emsg("Xeq", ebuff);
1507 return Response.Send(kXR_NoMemory, ebuff);
1508 }
1509 oHelp.fp = fp;
1510
1511// The open is elegible for a deferred response, indicate we're ok with that
1512//
1513 fp->error.setErrCB(&openCB, ReqID.getID());
1514 fp->error.setUCap(clientPV);
1515
1516// If TPC opens require TLS but this is not a TLS connection, prohibit TPC
1517//
1518 if ((doTLS & Req_TLSTPC) && !isTLS && !Link->hasBridge())
1519 openopts|= SFS_O_NOTPC;
1520
1521// Open the file
1522//
1523 if ((rc = fp->open(fn, (XrdSfsFileOpenMode)openopts,
1524 (mode_t)mode, CRED, opaque)))
1525 {rc = fsError(rc, opC, fp->error, fn, opaque); return rc;}
1526
1527// Obtain a hyper file object
1528//
1529 xp = new XrdXrootdFile(Link->ID, fn, fp, usage, isAsync, &statbuf);
1530 if (!xp)
1531 {snprintf(ebuff, sizeof(ebuff)-1, "Insufficient memory to open %s", fn);
1532 eDest.Emsg("Xeq", ebuff);
1533 return Response.Send(kXR_NoMemory, ebuff);
1534 }
1535 oHelp.xp = xp;
1536
1537// Serialize the link
1538//
1539 Link->Serialize();
1540 *ebuff = '\0';
1541
1542// Create a file table for this link if it does not have one
1543//
1544 if (!FTab) FTab = new XrdXrootdFileTable(Monitor.Did);
1545
1546// Insert this file into the link's file table
1547//
1548 if (!FTab || (fhandle = FTab->Add(xp)) < 0)
1549 {snprintf(ebuff, sizeof(ebuff)-1, "Insufficient memory to open %s", fn);
1550 eDest.Emsg("Xeq", ebuff);
1551 return Response.Send(kXR_NoMemory, ebuff);
1552 }
1553
1554// If the file supports exchange buffering, supply it with the object
1555//
1556 if (fsFeatures & XrdSfs::hasSXIO) fp->setXio(this);
1557
1558// Document forced opens
1559//
1560 if (doforce)
1561 {int rdrs, wrtrs;
1562 Locker->numLocks(fn, rdrs, wrtrs);
1563 if (('r' == usage && wrtrs) || ('w' == usage && rdrs) || wrtrs > 1)
1564 {snprintf(ebuff, sizeof(ebuff)-1,
1565 "%s file %s forced opened with %d reader(s) and %d writer(s).",
1566 ('r' == usage ? "Input" : "Output"), fn, rdrs, wrtrs);
1567 eDest.Emsg("Xeq", ebuff);
1568 }
1569 }
1570
1571// Determine if file is compressed
1572//
1573 memset(&myResp, 0, sizeof(myResp));
1574 if (!compchk) resplen = sizeof(myResp.fhandle);
1575 else {int cpsize;
1576 fp->getCXinfo((char *)myResp.cptype, cpsize);
1577 myResp.cpsize = static_cast<kXR_int32>(htonl(cpsize));
1578 resplen = sizeof(myResp);
1579 }
1580
1581// If client wants a stat in open, return the stat information
1582//
1583 if (retStat)
1584 {retStat = StatGen(statbuf, ebuff, sizeof(ebuff));
1585 IOResp[1].iov_base = (char *)&myResp; IOResp[1].iov_len = sizeof(myResp);
1586 IOResp[2].iov_base = ebuff; IOResp[2].iov_len = retStat;
1587 resplen = sizeof(myResp) + retStat;
1588 }
1589
1590// If we are monitoring, send off a path to dictionary mapping (must try 1st!)
1591//
1592 if (Monitor.Files())
1593 {xp->Stats.FileID = Monitor.MapPath(fn);
1595 Monitor.Agent->Open(xp->Stats.FileID, statbuf.st_size);
1596 }
1597
1598// Since file monitoring is deprecated, a dictid may not have been assigned.
1599// But if fstream monitoring is enabled it will assign the dictid.
1600//
1601 if (Monitor.Fstat())
1602 XrdXrootdMonFile::Open(&(xp->Stats), fn, Monitor.Did, usage == 'w');
1603
1604// Insert the file handle
1605//
1606 memcpy((void *)myResp.fhandle,(const void *)&fhandle,sizeof(myResp.fhandle));
1607 numFiles++;
1608
1609// If packet marking is enabled, notify that we have potentially started data.
1610// We also need to extend the marking to any associated streams.
1611//
1612 int eCode, aCode;
1613 if (PMark && !pmDone)
1614 {streamMutex.Lock();
1615 pmDone = true;
1616 if ((pmHandle = PMark->Begin(*Client, fn, opaque, AppName)))
1617 for (int i = 1; i < maxStreams; i++)
1618 {if (Stream[i] && !(Stream[i]->pmDone))
1619 {Stream[i]->pmDone = true;
1620 Stream[i]->pmHandle =
1621 PMark->Begin(*(Stream[i]->Link->AddrInfo()),
1622 *pmHandle, Stream[i]->Link->ID);
1623 }
1624 }
1625 streamMutex.UnLock();
1626
1627 if (pmHandle && Monitor.Logins() && pmHandle->getEA(eCode, aCode))
1628 Monitor.Report(eCode, aCode);
1629 } else {
1630 if (!pmDone && Monitor.Logins()
1631 && XrdNetPMark::getEA(opaque, eCode, aCode))
1632 {Monitor.Report(eCode, aCode); pmDone = true;}
1633 }
1634
1635// Respond (failure is not an option now)
1636//
1637 oHelp.isOK = true;
1638 if (retStat) return Response.Send(IOResp, 3, resplen);
1639 else return Response.Send((void *)&myResp, resplen);
1640}
1641
1642/******************************************************************************/
1643/* d o _ P i n g */
1644/******************************************************************************/
1645
1646int XrdXrootdProtocol::do_Ping()
1647{
1648
1649// Keep Statistics
1650//
1651 SI->Bump(SI->miscCnt);
1652
1653// This is a basic nop
1654//
1655 return Response.Send();
1656}
1657
1658/******************************************************************************/
1659/* d o _ P r e p a r e */
1660/******************************************************************************/
1661
1662int XrdXrootdProtocol::do_Prepare(bool isQuery)
1663{
1664 static XrdXrootdCallBack prpCB("query", XROOTD_MON_QUERY);
1665
1666 XrdOucErrInfo myError(Link->ID, Monitor.Did, clientPV);
1667
1668 XrdOucTokenizer pathlist(argp->buff);
1669 XrdOucTList *pFirst=0, *pP, *pLast = 0;
1670 XrdOucTList *oFirst=0, *oP, *oLast = 0;
1671 XrdOucTListHelper pHelp(&pFirst), oHelp(&oFirst);
1672 XrdXrootdPrepArgs pargs(0, 0);
1673 XrdSfsPrep fsprep;
1674
1675 int rc, pathnum = 0;
1676 char reqid[128], nidbuff[512], *path, *opaque, *prpid = 0;
1677 unsigned short optX = ntohs(Request.prepare.optionX);
1678 char opts;
1679 bool isCancel, isEvict, isPrepare;
1680
1681// Check if this is an evict request (similar to stage)
1682//
1683 isEvict = (optX & kXR_evict) != 0;
1684
1685// Establish what we are really doing here
1686//
1687 if (isQuery)
1688 {opts = 0;
1689 isCancel = false;
1690 } else {
1691 if (Request.prepare.options & kXR_cancel)
1692 {opts = 0;
1693 isCancel = true;
1694 } else {
1695 opts = (isEvict ? 0 : Request.prepare.options);
1696 isCancel = false;
1697 }
1698 }
1699 isPrepare = !(isCancel || isQuery);
1700
1701// Apply prepare limits, as necessary.
1702//
1703 if (isPrepare && (PrepareLimit >= 0) && (++PrepareCount > PrepareLimit)) {
1704 if (LimitError) {
1705 return Response.Send( kXR_overQuota,
1706 "Surpassed this connection's prepare limit.");
1707 } else {
1708 return Response.Send();
1709 }
1710 }
1711
1712// Check for static routing
1713//
1714 if ((opts & kXR_stage) || isCancel) {STATIC_REDIRECT(RD_prepstg);}
1715 STATIC_REDIRECT(RD_prepare);
1716
1717// Prehandle requests that must have a requestID. Otherwise, generate one.
1718// Note that prepare request id's have two formats. The external format is
1719// is qualifiaed by this host while the internal one removes the qualification.
1720// The internal one is only used for the native prepare implementation.
1721// To wit: prpid is the unqualified ID while reqid is the qualified one for
1722// generated id's while prpid is always the specified request id.
1723//
1724 if (isCancel || isQuery)
1725 {if (!(prpid = pathlist.GetLine()))
1726 return Response.Send(kXR_ArgMissing, "Prepare requestid not specified");
1727 fsprep.reqid = prpid;
1728 fsprep.opts = (isCancel ? Prep_CANCEL : Prep_QUERY);
1729 if (!PrepareAlt)
1730 {char hname[256];
1731 int hport;
1732 prpid = PrepID->isMine(prpid, hport, hname, sizeof(hname));
1733 if (!prpid)
1734 {if (!hport) return Response.Send(kXR_ArgInvalid,
1735 "Prepare requestid owned by an unknown server");
1736 TRACEI(REDIR, Response.ID() <<" redirecting prepare to "
1737 << hname <<':' <<hport);
1738 return Response.Send(kXR_redirect, hport, hname);
1739 }
1740 }
1741 } else {
1742 if (opts & kXR_stage)
1743 {prpid = PrepID->ID(reqid, sizeof(reqid));
1744 fsprep.reqid = reqid;
1745 fsprep.opts = Prep_STAGE | (opts & kXR_coloc ? Prep_COLOC : 0);
1746 } else {
1747 reqid[0]='*'; reqid[1]='\0';
1748 fsprep.reqid = prpid = reqid;
1749 fsprep.opts = (isEvict ? Prep_EVICT : 0);
1750 }
1751 }
1752
1753// Initialize the file system prepare arg list
1754//
1755 fsprep.paths = 0;
1756 fsprep.oinfo = 0;
1757 fsprep.notify = 0;
1758
1759// Cycle through all of the paths in the list
1760//
1761 while((path = pathlist.GetLine()))
1762 {if (rpCheck(path, &opaque)) return rpEmsg("Preparing", path);
1763 if (!Squash(path)) return vpEmsg("Preparing", path);
1764 pP = new XrdOucTList(path, pathnum);
1765 (pLast ? (pLast->next = pP) : (pFirst = pP)); pLast = pP;
1766 oP = new XrdOucTList(opaque, 0);
1767 (oLast ? (oLast->next = oP) : (oFirst = oP)); oLast = oP;
1768 pathnum++;
1769 }
1770 fsprep.paths = pFirst;
1771 fsprep.oinfo = oFirst;
1772
1773// We support callbacks but only for alternate prepare processing
1774//
1775 if (PrepareAlt) myError.setErrCB(&prpCB, ReqID.getID());
1776
1777// Process cancel requests here; they are simple at this point.
1778//
1779 if (isCancel)
1780 {if (SFS_OK != (rc = osFS->prepare(fsprep, myError, CRED)))
1781 return fsError(rc, XROOTD_MON_PREP, myError, path, 0);
1782 rc = Response.Send();
1784 return rc;
1785 }
1786
1787// Process query requests here; they are simple at this point.
1788//
1789 if (isQuery)
1790 {if (PrepareAlt)
1791 {if (SFS_OK != (rc = osFS->prepare(fsprep, myError, CRED)))
1792 return fsError(rc, XROOTD_MON_PREP, myError, path, 0);
1793 rc = Response.Send();
1794 } else {
1795 char *mBuff = myError.getMsgBuff(rc);
1796 pargs.reqid = prpid;
1797 pargs.user = Link->ID;
1798 pargs.paths = pFirst;
1799 rc = XrdXrootdPrepare::List(pargs, mBuff, rc);
1800 if (rc < 0) rc = Response.Send("No information found.");
1801 else rc = Response.Send(mBuff);
1802 }
1803 return rc;
1804 }
1805
1806// Make sure we have at least one path
1807//
1808 if (!pFirst)
1809 return Response.Send(kXR_ArgMissing, "No prepare paths specified");
1810
1811// Handle evict. We only support the evicts for alternate prepare handlers.
1812//
1813 if (isEvict)
1814 {if (PrepareAlt
1815 && (SFS_OK != (rc = osFS->prepare(fsprep, myError, CRED))))
1816 return fsError(rc, XROOTD_MON_PREP, myError, path, 0);
1817 return Response.Send();
1818 }
1819
1820// Handle notification parameter. The notification depends on whether or not
1821// we have a custom prepare handler.
1822//
1823 if (opts & kXR_notify)
1824 {const char *nprot = (opts & kXR_usetcp ? "tcp" : "udp");
1825 fsprep.notify = nidbuff;
1826 if (PrepareAlt)
1827 {if (Request.prepare.port == 0) fsprep.notify = 0;
1828 else snprintf(nidbuff, sizeof(nidbuff), "%s://%s:%d/",
1829 nprot, Link->Host(), ntohs(Request.prepare.port));
1830 } else sprintf(nidbuff, Notify, nprot, Link->FDnum(), Link->ID);
1831 if (fsprep.notify)
1832 fsprep.opts |= (opts & kXR_noerrs ? Prep_SENDAOK : Prep_SENDACK);
1833 }
1834
1835// Complete prepare options
1836//
1837 fsprep.opts |= (opts & kXR_fresh ? Prep_FRESH : 0);
1838 if (opts & kXR_wmode) fsprep.opts |= Prep_WMODE;
1839 if (PrepareAlt)
1840 {switch(Request.prepare.prty)
1841 {case 0: fsprep.opts |= Prep_PRTY0; break;
1842 case 1: fsprep.opts |= Prep_PRTY1; break;
1843 case 2: fsprep.opts |= Prep_PRTY2; break;
1844 case 3: fsprep.opts |= Prep_PRTY3; break;
1845 default: break;
1846 }
1847 } else {
1848 if (Request.prepare.prty == 0) fsprep.opts |= Prep_PRTY0;
1849 else fsprep.opts |= Prep_PRTY1;
1850 }
1851
1852// Issue the prepare request
1853//
1854 if (SFS_OK != (rc = osFS->prepare(fsprep, myError, CRED)))
1855 return fsError(rc, XROOTD_MON_PREP, myError, pFirst->text, oFirst->text);
1856
1857// Perform final processing
1858//
1859 if (!(opts & kXR_stage)) rc = Response.Send();
1860 else {rc = Response.Send(reqid, strlen(reqid));
1861 if (!PrepareAlt)
1862 {pargs.reqid = prpid;
1863 pargs.user = Link->ID;
1864 pargs.paths = pFirst;
1865 XrdXrootdPrepare::Log(pargs);
1866 }
1867 }
1868 return rc;
1869}
1870
1871/******************************************************************************/
1872/* d o _ P r o t o c o l */
1873/******************************************************************************/
1874
1875namespace XrdXrootd
1876{
1877extern char *bifResp[2];
1878extern int bifRLen[2];
1879}
1880
1881int XrdXrootdProtocol::do_Protocol()
1882{
1883 static kXR_int32 verNum = static_cast<kXR_int32>(htonl(kXR_PROTOCOLVERSION));
1884 static kXR_int32 theRle = static_cast<kXR_int32>(htonl(myRole));
1885 static kXR_int32 theRlf = static_cast<kXR_int32>(htonl(myRolf));
1886 static kXR_int32 theRlt = static_cast<kXR_int32>(htonl(myRole|kXR_gotoTLS));
1887
1888 ServerResponseBody_Protocol theResp;
1889 struct iovec ioVec[4] = {{0,0},{&theResp,kXR_ShortProtRespLen},{0,0},{0,0}};
1890
1891 int rc, iovN = 2, RespLen = kXR_ShortProtRespLen;
1892 bool wantTLS = false;
1893
1894// Keep Statistics
1895//
1896 SI->Bump(SI->miscCnt);
1897
1898// Determine which response to provide
1899//
1900 if (Request.protocol.clientpv)
1901 {int cvn = XrdOucEI::uVMask & ntohl(Request.protocol.clientpv);
1902 if (!Status || !(clientPV & XrdOucEI::uVMask))
1903 clientPV = (clientPV & ~XrdOucEI::uVMask) | cvn;
1904 else cvn = (clientPV & XrdOucEI::uVMask);
1905
1906 if (Request.protocol.flags & ClientProtocolRequest::kXR_bifreqs
1907 && XrdXrootd::bifResp[0])
1908 {int k =( Link->AddrInfo()->isPrivate() ? 1 : 0);
1909 ioVec[iovN ].iov_base = XrdXrootd::bifResp[k];
1910 ioVec[iovN++].iov_len = XrdXrootd::bifRLen[k];
1911 RespLen += XrdXrootd::bifRLen[k];
1912 }
1913
1914 if (DHS && cvn >= kXR_PROTSIGNVERSION
1915 && Request.protocol.flags & ClientProtocolRequest::kXR_secreqs)
1916 {int n = DHS->ProtResp(theResp.secreq, *(Link->AddrInfo()), cvn);
1917 ioVec[iovN ].iov_base = (void *)&theResp.secreq;
1918 ioVec[iovN++].iov_len = n;
1919 RespLen += n;
1920 }
1921
1922 if ((myRole & kXR_haveTLS) != 0 && !(Link->hasTLS()))
1923 {wantTLS = (Request.protocol.flags &
1925 ableTLS = wantTLS || (Request.protocol.flags &
1927 if (ableTLS) doTLS = tlsCap;
1928 else doTLS = tlsNot;
1929 if (ableTLS && !wantTLS)
1930 switch(Request.protocol.expect & ClientProtocolRequest::kXR_ExpMask)
1932 wantTLS = (doTLS & Req_TLSData) != 0;
1933 break;
1935 wantTLS = (doTLS & Req_TLSLogin) != 0;
1936 break;
1938 wantTLS = (doTLS & Req_TLSTPC) != 0 ||
1939 (doTLS & Req_TLSLogin) != 0;
1940 break;
1941 default: break;
1942 }
1943 }
1944 theResp.flags = (wantTLS ? theRlt : theRle);
1945 } else {
1946 theResp.flags = theRlf;
1947 doTLS = tlsNot;
1948 }
1949
1950// Send the response
1951//
1952 theResp.pval = verNum;
1953 rc = Response.Send(ioVec, iovN, RespLen);
1954
1955// If the client wants to start using TLS, enable it now. If we fail then we
1956// have no choice but to terminate the connection. Note that incapable clients
1957// don't want TLS but if we require TLS anyway, they will get an error either
1958// pre-login or post-login or on a bind later on.
1959//
1960 if (rc == 0 && wantTLS)
1961 {if (Link->setTLS(true, tlsCtx))
1962 {Link->setProtName("xroots");
1963 isTLS = true;
1964 } else {
1965 eDest.Emsg("Xeq", "Unable to enable TLS for", Link->ID);
1966 rc = -1;
1967 }
1968 }
1969 return rc;
1970}
1971
1972/******************************************************************************/
1973/* d o _ Q c o n f */
1974/******************************************************************************/
1975
1976int XrdXrootdProtocol::do_Qconf()
1977{
1978 static const int fsctl_cmd = SFS_FSCTL_STATCC|SFS_O_LOCAL;
1979 XrdOucTokenizer qcargs(argp->buff);
1980 char *val, buff[4096], *bp=buff;
1981 int n, bleft = sizeof(buff);
1982
1983// Get the first argument
1984//
1985 if (!qcargs.GetLine() || !(val = qcargs.GetToken()))
1986 return Response.Send(kXR_ArgMissing, "query config argument not specified.");
1987
1988// The first item can be xrootd or cmsd to display the config file
1989//
1990 if (!strcmp(val, "cmsd") || !strcmp(val, "xrootd"))
1991 return do_QconfCX(qcargs, val);
1992
1993// Trace this query variable
1994//
1995 do {TRACEP(DEBUG, "query config " <<val);
1996
1997 // Now determine what the user wants to query
1998 //
1999 if (!strcmp("bind_max", val))
2000 {n = snprintf(bp, bleft, "%d\n", maxStreams-1);
2001 bp += n; bleft -= n;
2002 }
2003 else if (!strcmp("chksum", val))
2004 {const char *csList = getenv("XRD_CSLIST");
2005 if (!JobCKT || !csList)
2006 {n = snprintf(bp, bleft, "chksum\n");
2007 bp += n; bleft -= n;
2008 continue;
2009 }
2010 n = snprintf(bp, bleft, "%s\n", csList);
2011 bp += n; bleft -= n;
2012 }
2013 else if (!strcmp("cid", val))
2014 {const char *cidval = getenv("XRDCMSCLUSTERID");
2015 if (!cidval || !(*cidval)) cidval = "cid";
2016 n = snprintf(bp, bleft, "%s\n", cidval);
2017 bp += n; bleft -= n;
2018 }
2019 else if (!strcmp("cms", val))
2020 {XrdOucErrInfo myError(Link->ID, Monitor.Did, clientPV);
2021 if (osFS->fsctl(fsctl_cmd, ".", myError, CRED) == SFS_DATA)
2022 n = snprintf(bp, bleft, "%s\n", myError.getErrText());
2023 else n = snprintf(bp, bleft, "%s\n", "cms");
2024 bp += n; bleft -= n;
2025 }
2026 else if (!strcmp("pio_max", val))
2027 {n = snprintf(bp, bleft, "%d\n", maxPio+1);
2028 bp += n; bleft -= n;
2029 }
2030 else if (!strcmp("proxy", val))
2031 {const char* pxyOrigin = "proxy";
2032 if (myRole & kXR_attrProxy)
2033 {pxyOrigin = getenv("XRDXROOTD_PROXY");
2034 if (!pxyOrigin) pxyOrigin = "proxy";
2035 }
2036 n = snprintf(bp,bleft,"%s\n",pxyOrigin);
2037 bp += n; bleft -= n;
2038 }
2039 else if (!strcmp("readv_ior_max", val))
2040 {n = snprintf(bp,bleft,"%d\n",maxReadv_ior);
2041 bp += n; bleft -= n;
2042 }
2043 else if (!strcmp("readv_iov_max", val))
2044 {n = snprintf(bp, bleft, "%d\n", XrdProto::maxRvecsz);
2045 bp += n; bleft -= n;
2046 }
2047 else if (!strcmp("role", val))
2048 {const char *theRole = getenv("XRDROLE");
2049 n = snprintf(bp, bleft, "%s\n", (theRole ? theRole : "none"));
2050 bp += n; bleft -= n;
2051 }
2052 else if (!strcmp("sitename", val))
2053 {const char *siteName = getenv("XRDSITE");
2054 n = snprintf(bp, bleft, "%s\n", (siteName ? siteName : "sitename"));
2055 bp += n; bleft -= n;
2056 }
2057 else if (!strcmp("start", val))
2058 {n = snprintf(bp, bleft, "%s\n", startUP);
2059 bp += n; bleft -= n;
2060 }
2061 else if (!strcmp("sysid", val))
2062 {const char *cidval = getenv("XRDCMSCLUSTERID");
2063 const char *nidval = getenv("XRDCMSVNID");
2064 if (!cidval || !(*cidval) || !nidval || !(*nidval))
2065 {cidval = "sysid"; nidval = "";}
2066 n = snprintf(bp, bleft, "%s %s\n", nidval, cidval);
2067 bp += n; bleft -= n;
2068 }
2069 else if (!strcmp("tpc", val))
2070 {char *tpcval = getenv("XRDTPC");
2071 n = snprintf(bp, bleft, "%s\n", (tpcval ? tpcval : "tpc"));
2072 bp += n; bleft -= n;
2073 }
2074 else if (!strcmp("tpcdlg", val))
2075 {char *tpcval = getenv("XRDTPCDLG");
2076 n = snprintf(bp, bleft, "%s\n", (tpcval ? tpcval : "tpcdlg"));
2077 bp += n; bleft -= n;
2078 }
2079 else if (!strcmp("tls_port", val) && tlsPort)
2080 {n = snprintf(bp, bleft, "%d\n", tlsPort);
2081 bp += n; bleft -= n;
2082 }
2083 else if (!strcmp("window", val) && Window)
2084 {n = snprintf(bp, bleft, "%d\n", Window);
2085 bp += n; bleft -= n;
2086 }
2087 else if (!strcmp("version", val))
2088 {n = snprintf(bp, bleft, "%s\n", XrdVSTRING);
2089 bp += n; bleft -= n;
2090 }
2091 else if (!strcmp("vnid", val))
2092 {const char *nidval = getenv("XRDCMSVNID");
2093 if (!nidval || !(*nidval)) nidval = "vnid";
2094 n = snprintf(bp, bleft, "%s\n", nidval);
2095 }
2096 else if (!strcmp("fattr", val))
2097 {n = snprintf(bp, bleft, "%s\n", usxParms);
2098 bp += n; bleft -= n;
2099 }
2100 else {n = strlen(val);
2101 if (bleft <= n) break;
2102 strcpy(bp, val); bp +=n; *bp = '\n'; bp++;
2103 bleft -= (n+1);
2104 }
2105 } while(bleft > 0 && (val = qcargs.GetToken()));
2106
2107// Make sure all ended well
2108//
2109 if (val)
2110 return Response.Send(kXR_ArgTooLong, "too many query config arguments.");
2111
2112// All done
2113//
2114 return Response.Send(buff, sizeof(buff) - bleft);
2115}
2116
2117/******************************************************************************/
2118/* d o _ Q c o n f C X */
2119/******************************************************************************/
2120
2121int XrdXrootdProtocol::do_QconfCX(XrdOucTokenizer &qcargs, char *val)
2122{
2123 extern XrdOucString *XrdXrootdCF;
2124 bool isCMSD = (*val == 'c');
2125
2126// Make sure there is nothing else following the token
2127//
2128 if ((val = qcargs.GetToken()))
2129 return Response.Send(kXR_ArgInvalid, "too many query config arguments.");
2130
2131// If this is a cms just return a null for now
2132//
2133 if (isCMSD) return Response.Send((void *)"\n", 2);
2134
2135// Display the xrootd configuration
2136//
2137 if (XrdXrootdCF && isTLS && getenv("XROOTD_QCFOK"))
2138 return Response.Send((void *)XrdXrootdCF->c_str(), XrdXrootdCF->length());
2139
2140// Respond with a null
2141//
2142 return Response.Send((void *)"\n", 2);
2143}
2144
2145/******************************************************************************/
2146/* d o _ Q f h */
2147/******************************************************************************/
2148
2149int XrdXrootdProtocol::do_Qfh()
2150{
2151 static XrdXrootdCallBack qryCB("query", XROOTD_MON_QUERY);
2152 XrdXrootdFHandle fh(Request.query.fhandle);
2153 XrdXrootdFile *fp;
2154 const char *fArg = 0, *qType = "";
2155 int rc;
2156 short qopt = (short)ntohs(Request.query.infotype);
2157
2158// Update misc stats count
2159//
2160 SI->Bump(SI->miscCnt);
2161
2162// Find the file object
2163//
2164 if (!FTab || !(fp = FTab->Get(fh.handle)))
2165 return Response.Send(kXR_FileNotOpen,
2166 "query does not refer to an open file");
2167
2168// The query is elegible for a deferred response, indicate we're ok with that
2169//
2170 fp->XrdSfsp->error.setErrCB(&qryCB, ReqID.getID());
2171
2172// Perform the appropriate query
2173//
2174 switch(qopt)
2175 {case kXR_Qopaqug: qType = "Qopaqug";
2176 fArg = (Request.query.dlen ? argp->buff : 0);
2177 rc = fp->XrdSfsp->fctl(SFS_FCTL_SPEC1,
2178 Request.query.dlen, fArg,
2179 CRED);
2180 break;
2181 case kXR_Qvisa: qType = "Qvisa";
2182 rc = fp->XrdSfsp->fctl(SFS_FCTL_STATV, 0,
2183 fp->XrdSfsp->error);
2184 break;
2185 default: return Response.Send(kXR_ArgMissing,
2186 "Required query argument not present");
2187 }
2188
2189// Preform the actual function
2190//
2191 TRACEP(FS, "fh=" <<fh.handle <<" query " <<qType <<" rc=" <<rc);
2192
2193// Return appropriately
2194//
2195 if (SFS_OK != rc)
2196 return fsError(rc, XROOTD_MON_QUERY, fp->XrdSfsp->error, 0, 0);
2197 return Response.Send();
2198}
2199
2200/******************************************************************************/
2201/* d o _ Q o p a q u e */
2202/******************************************************************************/
2203
2204int XrdXrootdProtocol::do_Qopaque(short qopt)
2205{
2206 static XrdXrootdCallBack qpqCB("query", XROOTD_MON_QUERY);
2207 XrdOucErrInfo myError(Link->ID, Monitor.Did, clientPV);
2208 XrdSfsFSctl myData;
2209 const char *Act, *AData;
2210 char *opaque;
2211 int fsctl_cmd, rc, dlen = Request.query.dlen;
2212
2213// Process unstructured as well as structured (path/opaque) requests
2214//
2215 if (qopt == kXR_Qopaque)
2216 {myData.Arg1 = argp->buff; myData.Arg1Len = dlen;
2217 myData.Arg2 = 0; myData.Arg2Len = 0;
2218 fsctl_cmd = SFS_FSCTL_PLUGIO;
2219 Act = " qopaque '"; AData = "...";
2220 } else {
2221 // Check for static routing (this falls under stat)
2222 //
2223 STATIC_REDIRECT(RD_stat);
2224
2225 // Prescreen the path
2226 //
2227 if (rpCheck(argp->buff, &opaque)) return rpEmsg("Querying", argp->buff);
2228 if (!Squash(argp->buff)) return vpEmsg("Querying", argp->buff);
2229
2230 // Setup arguments
2231 //
2232 myData.Arg1 = argp->buff;
2233 myData.Arg1Len = (opaque ? opaque - argp->buff - 1 : dlen);
2234 myData.Arg2 = opaque;
2235 myData.Arg2Len = (opaque ? argp->buff + dlen - opaque : 0);
2236 fsctl_cmd = SFS_FSCTL_PLUGIN;
2237 Act = " qopaquf '"; AData = argp->buff;
2238 }
2239// The query is elegible for a deferred response, indicate we're ok with that
2240//
2241 myError.setErrCB(&qpqCB, ReqID.getID());
2242
2243// Preform the actual function using the supplied arguments
2244//
2245 rc = osFS->FSctl(fsctl_cmd, myData, myError, CRED);
2246 TRACEP(FS, "rc=" <<rc <<Act <<AData <<"'");
2247 if (rc == SFS_OK) return Response.Send("");
2248 return fsError(rc, 0, myError, 0, 0);
2249}
2250
2251/******************************************************************************/
2252/* d o _ Q s p a c e */
2253/******************************************************************************/
2254
2255int XrdXrootdProtocol::do_Qspace()
2256{
2257 static const int fsctl_cmd = SFS_FSCTL_STATLS;
2258 XrdOucErrInfo myError(Link->ID, Monitor.Did, clientPV);
2259 char *opaque;
2260 int n, rc;
2261
2262// Check for static routing
2263//
2264 STATIC_REDIRECT(RD_stat);
2265
2266// Prescreen the path
2267//
2268 if (rpCheck(argp->buff, &opaque)) return rpEmsg("Stating", argp->buff);
2269 if (!Squash(argp->buff)) return vpEmsg("Stating", argp->buff);
2270
2271// Add back the opaque info
2272//
2273 if (opaque)
2274 {n = strlen(argp->buff); argp->buff[n] = '?';
2275 if ((argp->buff)+n != opaque-1)
2276 memmove(&argp->buff[n+1], opaque, strlen(opaque)+1);
2277 }
2278
2279// Preform the actual function using the supplied logical FS name
2280//
2281 rc = osFS->fsctl(fsctl_cmd, argp->buff, myError, CRED);
2282 TRACEP(FS, "rc=" <<rc <<" qspace '" <<argp->buff <<"'");
2283 if (rc == SFS_OK) return Response.Send("");
2284 return fsError(rc, XROOTD_MON_QUERY, myError, argp->buff, opaque);
2285}
2286
2287/******************************************************************************/
2288/* d o _ Q u e r y */
2289/******************************************************************************/
2290
2291int XrdXrootdProtocol::do_Query()
2292{
2293 short qopt = (short)ntohs(Request.query.infotype);
2294
2295// Perform the appropriate query
2296//
2297 switch(qopt)
2298 {case kXR_QStats: return SI->Stats(Response,
2299 (Request.header.dlen ? argp->buff : "a"));
2300 case kXR_Qcksum: return do_CKsum(0);
2301 case kXR_Qckscan: return do_CKsum(1);
2302 case kXR_Qconfig: return do_Qconf();
2303 case kXR_Qspace: return do_Qspace();
2304 case kXR_Qxattr: return do_Qxattr();
2305 case kXR_Qopaque:
2306 case kXR_Qopaquf: return do_Qopaque(qopt);
2307 case kXR_Qopaqug: return do_Qfh();
2308 case kXR_QPrep: return do_Prepare(true);
2309 default: break;
2310 }
2311
2312// Whatever we have, it's not valid
2313//
2314 return Response.Send(kXR_ArgInvalid,
2315 "Invalid information query type code");
2316}
2317
2318/******************************************************************************/
2319/* d o _ Q x a t t r */
2320/******************************************************************************/
2321
2322int XrdXrootdProtocol::do_Qxattr()
2323{
2324 static XrdXrootdCallBack statCB("stat", XROOTD_MON_QUERY);
2325 static const int fsctl_cmd = SFS_FSCTL_STATXA;
2326 int rc;
2327 char *opaque;
2328 XrdOucErrInfo myError(Link->ID,&statCB,ReqID.getID(),Monitor.Did,clientPV);
2329
2330// Check for static routing
2331//
2332 STATIC_REDIRECT(RD_stat);
2333
2334// Prescreen the path
2335//
2336 if (rpCheck(argp->buff, &opaque)) return rpEmsg("Stating", argp->buff);
2337 if (!Squash(argp->buff)) return vpEmsg("Stating", argp->buff);
2338
2339// Add back opaque information is present
2340//
2341 if (opaque)
2342 {int n = strlen(argp->buff); argp->buff[n] = '?';
2343 if ((argp->buff)+n != opaque-1)
2344 memmove(&argp->buff[n+1], opaque, strlen(opaque)+1);
2345 }
2346
2347// Preform the actual function
2348//
2349 rc = osFS->fsctl(fsctl_cmd, argp->buff, myError, CRED);
2350 TRACEP(FS, "rc=" <<rc <<" qxattr " <<argp->buff);
2351 return fsError(rc, XROOTD_MON_QUERY, myError, argp->buff, opaque);
2352}
2353
2354/******************************************************************************/
2355/* d o _ R e a d */
2356/******************************************************************************/
2357
2358int XrdXrootdProtocol::do_Read()
2359{
2360 int pathID, retc;
2361 XrdXrootdFHandle fh(Request.read.fhandle);
2362 numReads++;
2363
2364// We first handle the pre-read list, if any. We do it this way because of
2365// a historical glitch in the protocol. One should really not piggy back a
2366// pre-read on top of a read, though it is allowed.
2367//
2368 if (!Request.header.dlen) pathID = 0;
2369 else if (do_ReadNone(retc, pathID)) return retc;
2370
2371// Unmarshall the data
2372//
2373 IO.IOLen = ntohl(Request.read.rlen);
2374 n2hll(Request.read.offset, IO.Offset);
2375
2376// Find the file object
2377//
2378 if (!FTab || !(IO.File = FTab->Get(fh.handle)))
2379 return Response.Send(kXR_FileNotOpen,
2380 "read does not refer to an open file");
2381
2382// Trace and verify read length is not negative
2383//
2384 TRACEP(FSIO, pathID <<" fh=" <<fh.handle <<" read " <<IO.IOLen
2385 <<'@' <<IO.Offset);
2386 if ( IO.IOLen < 0) return Response.Send(kXR_ArgInvalid,
2387 "Read length is negative");
2388
2389// If we are monitoring, insert a read entry
2390//
2391 if (Monitor.InOut())
2392 Monitor.Agent->Add_rd(IO.File->Stats.FileID, Request.read.rlen,
2393 Request.read.offset);
2394
2395// Short circuit processing if read length is zero
2396//
2397 if (!IO.IOLen) return Response.Send();
2398
2399// There are many competing ways to accomplish a read. Pick the one we
2400// will use and if possible, do a fast dispatch.
2401//
2402 if (IO.File->isMMapped) IO.Mode = XrdXrootd::IOParms::useMMap;
2403 else if (IO.File->sfEnabled && !isTLS && IO.IOLen >= as_minsfsz
2404 && IO.Offset+IO.IOLen <= IO.File->Stats.fSize)
2406 else if (IO.File->AsyncMode && IO.IOLen >= as_miniosz
2407 && IO.Offset+IO.IOLen <= IO.File->Stats.fSize+as_seghalf
2409 {XrdXrootdProtocol *pP;
2410 XrdXrootdNormAio *aioP;
2411
2412 if (!pathID) pP = this;
2413 else {if (!(pP = VerifyStream(retc, pathID, false))) return retc;
2414 if (pP->linkAioReq >= as_maxperlnk) pP = 0;
2415 }
2416 if (pP && (aioP = XrdXrootdNormAio::Alloc(pP,pP->Response,IO.File)))
2417 {if (!IO.File->aioFob) IO.File->aioFob = new XrdXrootdAioFob;
2418 aioP->Read(IO.Offset, IO.IOLen);
2419 return 0;
2420 }
2421 SI->AsyncRej++;
2423 }
2424 else IO.Mode = XrdXrootd::IOParms::useBasic;
2425
2426// See if an alternate path is required, offload the read
2427//
2428 if (pathID) return do_Offload(&XrdXrootdProtocol::do_ReadAll, pathID);
2429
2430// Now read all of the data (do pre-reads first)
2431//
2432 return do_ReadAll();
2433}
2434
2435/******************************************************************************/
2436/* d o _ R e a d A l l */
2437/******************************************************************************/
2438
2439// IO.File = file to be read
2440// IO.Offset = Offset at which to read
2441// IO.IOLen = Number of bytes to read from file and write to socket
2442
2443int XrdXrootdProtocol::do_ReadAll()
2444{
2445 int rc, xframt, Quantum = (IO.IOLen > maxBuffsz ? maxBuffsz : IO.IOLen);
2446 char *buff;
2447
2448// If this file is memory mapped, short ciruit all the logic and immediately
2449// transfer the requested data to minimize latency.
2450//
2451 if (IO.Mode == XrdXrootd::IOParms::useMMap)
2452 {if (IO.Offset >= IO.File->Stats.fSize) return Response.Send();
2453 if (IO.Offset+IO.IOLen <= IO.File->Stats.fSize)
2454 {IO.File->Stats.rdOps(IO.IOLen);
2455 return Response.Send(IO.File->mmAddr+IO.Offset, IO.IOLen);
2456 }
2457 xframt = IO.File->Stats.fSize -IO.Offset;
2458 IO.File->Stats.rdOps(xframt);
2459 return Response.Send(IO.File->mmAddr+IO.Offset, xframt);
2460 }
2461
2462// If we are sendfile enabled, then just send the file if possible
2463//
2464 if (IO.Mode == XrdXrootd::IOParms::useSF)
2465 {IO.File->Stats.rdOps(IO.IOLen);
2466 if (IO.File->fdNum >= 0)
2467 return Response.Send(IO.File->fdNum, IO.Offset, IO.IOLen);
2468 rc = IO.File->XrdSfsp->SendData((XrdSfsDio *)this, IO.Offset, IO.IOLen);
2469 if (rc == SFS_OK)
2470 {if (!IO.IOLen) return 0;
2471 if (IO.IOLen < 0) return -1; // Otherwise retry using read()
2472 } else return fsError(rc, 0, IO.File->XrdSfsp->error, 0, 0);
2473 }
2474
2475// Make sure we have a large enough buffer
2476//
2477 if (!argp || Quantum < halfBSize || Quantum > argp->bsize)
2478 {if ((rc = getBuff(1, Quantum)) <= 0) return rc;}
2479 else if (hcNow < hcNext) hcNow++;
2480 buff = argp->buff;
2481
2482// Now read all of the data. For statistics, we need to record the orignal
2483// amount of the request even if we really do not get to read that much!
2484//
2485 IO.File->Stats.rdOps(IO.IOLen);
2486 do {if ((xframt = IO.File->XrdSfsp->read(IO.Offset, buff, Quantum)) <= 0) break;
2487 if (xframt >= IO.IOLen) return Response.Send(buff, xframt);
2488 if (Response.Send(kXR_oksofar, buff, xframt) < 0) return -1;
2489 IO.Offset += xframt; IO.IOLen -= xframt;
2490 if (IO.IOLen < Quantum) Quantum = IO.IOLen;
2491 } while(IO.IOLen);
2492
2493// Determine why we ended here
2494//
2495 if (xframt == 0) return Response.Send();
2496 return fsError(xframt, 0, IO.File->XrdSfsp->error, 0, 0);
2497}
2498
2499/******************************************************************************/
2500/* d o _ R e a d N o n e */
2501/******************************************************************************/
2502
2503int XrdXrootdProtocol::do_ReadNone(int &retc, int &pathID)
2504{
2505 XrdXrootdFHandle fh;
2506 int ralsz = Request.header.dlen;
2507 struct read_args *rargs=(struct read_args *)(argp->buff);
2508 struct readahead_list *ralsp = (readahead_list *)(rargs+1);
2509
2510// Return the pathid
2511//
2512 pathID = static_cast<int>(rargs->pathid);
2513 if ((ralsz -= sizeof(read_args)) <= 0) return 0;
2514
2515// Make sure that we have a proper pre-read list
2516//
2517 if (ralsz%sizeof(readahead_list))
2518 {Response.Send(kXR_ArgInvalid, "Invalid length for read ahead list");
2519 return 1;
2520 }
2521
2522// Run down the pre-read list
2523//
2524 while(ralsz > 0)
2525 {IO.IOLen = ntohl(ralsp->rlen);
2526 n2hll(ralsp->offset, IO.Offset);
2527 memcpy((void *)&fh.handle, (const void *)ralsp->fhandle,
2528 sizeof(fh.handle));
2529 TRACEP(FSIO, "fh="<<fh.handle<<" read "<<IO.IOLen<<'@'<<IO.Offset);
2530 if (!FTab || !(IO.File = FTab->Get(fh.handle)))
2531 {retc = Response.Send(kXR_FileNotOpen,
2532 "preread does not refer to an open file");
2533 return 1;
2534 }
2535 IO.File->XrdSfsp->read(IO.Offset, IO.IOLen);
2536 ralsz -= sizeof(struct readahead_list);
2537 ralsp++;
2538 numReads++;
2539 };
2540
2541// All done
2542//
2543 return 0;
2544}
2545
2546/******************************************************************************/
2547/* d o _ R e a d V */
2548/******************************************************************************/
2549
2550int XrdXrootdProtocol::do_ReadV()
2551{
2552// This will read multiple buffers at the same time in an attempt to avoid
2553// the latency in a network. The information with the offsets and lengths
2554// of the information to read is passed as a data buffer... then we decode
2555// it and put all the individual buffers in a single one it's up to the
2556// client to interpret it. Code originally developed by Leandro Franco, CERN.
2557// The readv file system code originally added by Brian Bockelman, UNL.
2558//
2559 const int hdrSZ = sizeof(readahead_list);
2560 struct XrdOucIOVec rdVec[XrdProto::maxRvecsz+1];
2561 struct readahead_list *raVec, respHdr;
2562 long long totSZ;
2563 XrdSfsXferSize rdVAmt, rdVXfr, xfrSZ = 0;
2564 int rdVBeg, rdVBreak, rdVNow, rdVNum, rdVecNum;
2565 int currFH, i, k, Quantum, Qleft, rdVecLen = Request.header.dlen;
2566 int rvMon = Monitor.InOut();
2567 int ioMon = (rvMon > 1);
2568 char *buffp, vType = (ioMon ? XROOTD_MON_READU : XROOTD_MON_READV);
2569
2570// Compute number of elements in the read vector and make sure we have no
2571// partial elements.
2572//
2573 rdVecNum = rdVecLen / sizeof(readahead_list);
2574 if ( (rdVecNum <= 0) || (rdVecNum*hdrSZ != rdVecLen) )
2575 return Response.Send(kXR_ArgInvalid, "Read vector is invalid");
2576
2577// Make sure that we can copy the read vector to our local stack. We must impose
2578// a limit on it's size. We do this to be able to reuse the data buffer to
2579// prevent cross-cpu memory cache synchronization.
2580//
2581 if (rdVecNum > XrdProto::maxRvecsz)
2582 return Response.Send(kXR_ArgTooLong, "Read vector is too long");
2583
2584// So, now we account for the number of readv requests and total segments
2585//
2586 numReadV++; numSegsV += rdVecNum;
2587
2588// Run down the list and compute the total size of the read. No individual
2589// read may be greater than the maximum transfer size. We also use this loop
2590// to copy the read ahead list to our readv vector for later processing.
2591//
2592 raVec = (readahead_list *)argp->buff;
2593 totSZ = rdVecLen; Quantum = maxReadv_ior;
2594 for (i = 0; i < rdVecNum; i++)
2595 {totSZ += (rdVec[i].size = ntohl(raVec[i].rlen));
2596 if (rdVec[i].size < 0) return Response.Send(kXR_ArgInvalid,
2597 "Readv length is negative");
2598 if (rdVec[i].size > Quantum) return Response.Send(kXR_NoMemory,
2599 "Single readv transfer is too large");
2600 rdVec[i].offset = ntohll(raVec[i].offset);
2601 memcpy(&rdVec[i].info, raVec[i].fhandle, sizeof(int));
2602 }
2603
2604// Now add an extra dummy element to force flushing of the read vector.
2605//
2606 rdVec[i].offset = -1;
2607 rdVec[i].size = 0;
2608 rdVec[i].info = -1;
2609 rdVBreak = rdVecNum;
2610 rdVecNum++;
2611
2612// We limit the total size of the read to be 2GB for convenience
2613//
2614 if (totSZ > 0x7fffffffLL)
2615 return Response.Send(kXR_NoMemory, "Total readv transfer is too large");
2616
2617// Calculate the transfer unit which will be the smaller of the maximum
2618// transfer unit and the actual amount we need to transfer.
2619//
2620 if ((Quantum = static_cast<int>(totSZ)) > maxTransz) Quantum = maxTransz;
2621
2622// Now obtain the right size buffer
2623//
2624 if ((Quantum < halfBSize && Quantum > 1024) || Quantum > argp->bsize)
2625 {if ((k = getBuff(1, Quantum)) <= 0) return k;}
2626 else if (hcNow < hcNext) hcNow++;
2627
2628// Check that we really have at least one file open. This needs to be done
2629// only once as this code runs in the control thread.
2630//
2631 if (!FTab) return Response.Send(kXR_FileNotOpen,
2632 "readv does not refer to an open file");
2633
2634// Preset the previous and current file handle to be the handle of the first
2635// element and make sure the file is actually open.
2636//
2637 currFH = rdVec[0].info;
2638 memcpy(respHdr.fhandle, &currFH, sizeof(respHdr.fhandle));
2639 if (!(IO.File = FTab->Get(currFH))) return Response.Send(kXR_FileNotOpen,
2640 "readv does not refer to an open file");
2641
2642// Setup variables for running through the list.
2643//
2644 Qleft = Quantum; buffp = argp->buff; rvSeq++;
2645 rdVBeg = rdVNow = 0; rdVXfr = rdVAmt = 0;
2646
2647// Now run through the elements
2648//
2649 for (i = 0; i < rdVecNum; i++)
2650 {if (rdVec[i].info != currFH)
2651 {xfrSZ = IO.File->XrdSfsp->readv(&rdVec[rdVNow], i-rdVNow);
2652 if (xfrSZ != rdVAmt) break;
2653 rdVNum = i - rdVBeg; rdVXfr += rdVAmt;
2654 IO.File->Stats.rvOps(rdVXfr, rdVNum);
2655 if (rvMon)
2656 {Monitor.Agent->Add_rv(IO.File->Stats.FileID, htonl(rdVXfr),
2657 htons(rdVNum), rvSeq, vType);
2658 if (ioMon) for (k = rdVBeg; k < i; k++)
2659 Monitor.Agent->Add_rd(IO.File->Stats.FileID,
2660 htonl(rdVec[k].size), htonll(rdVec[k].offset));
2661 }
2662 rdVXfr = rdVAmt = 0;
2663 if (i == rdVBreak) break;
2664 rdVBeg = rdVNow = i; currFH = rdVec[i].info;
2665 memcpy(respHdr.fhandle, &currFH, sizeof(respHdr.fhandle));
2666 if (!(IO.File = FTab->Get(currFH)))
2667 return Response.Send(kXR_FileNotOpen,
2668 "readv does not refer to an open file");
2669 }
2670
2671 if (Qleft < (rdVec[i].size + hdrSZ))
2672 {if (rdVAmt)
2673 {xfrSZ = IO.File->XrdSfsp->readv(&rdVec[rdVNow], i-rdVNow);
2674 if (xfrSZ != rdVAmt) break;
2675 }
2676 if (Response.Send(kXR_oksofar,argp->buff,Quantum-Qleft) < 0)
2677 return -1;
2678 Qleft = Quantum;
2679 buffp = argp->buff;
2680 rdVNow = i; rdVXfr += rdVAmt; rdVAmt = 0;
2681 }
2682
2683 xfrSZ = rdVec[i].size; rdVAmt += xfrSZ;
2684 respHdr.rlen = htonl(xfrSZ);
2685 respHdr.offset = htonll(rdVec[i].offset);
2686 memcpy(buffp, &respHdr, hdrSZ);
2687 rdVec[i].data = buffp + hdrSZ;
2688 buffp += (xfrSZ+hdrSZ); Qleft -= (xfrSZ+hdrSZ);
2689 TRACEP(FSIO,"fh=" <<currFH<<" readV "<< xfrSZ <<'@'<<rdVec[i].offset);
2690 }
2691
2692// Check if we have an error here. This is indicated when rdVAmt is not zero.
2693//
2694 if (rdVAmt)
2695 {if (xfrSZ >= 0)
2696 {xfrSZ = SFS_ERROR;
2697 IO.File->XrdSfsp->error.setErrInfo(-ENODATA,"readv past EOF");
2698 }
2699 return fsError(xfrSZ, 0, IO.File->XrdSfsp->error, 0, 0);
2700 }
2701
2702// All done, return result of the last segment or just zero
2703//
2704 return (Quantum != Qleft ? Response.Send(argp->buff, Quantum-Qleft) : 0);
2705}
2706
2707/******************************************************************************/
2708/* d o _ R m */
2709/******************************************************************************/
2710
2711int XrdXrootdProtocol::do_Rm()
2712{
2713 int rc;
2714 char *opaque;
2715 XrdOucErrInfo myError(Link->ID, Monitor.Did, clientPV);
2716
2717// Check for static routing
2718//
2719 STATIC_REDIRECT(RD_rm);
2720
2721// Prescreen the path
2722//
2723 if (rpCheck(argp->buff, &opaque)) return rpEmsg("Removing", argp->buff);
2724 if (!Squash(argp->buff)) return vpEmsg("Removing", argp->buff);
2725
2726// Preform the actual function
2727//
2728 rc = osFS->rem(argp->buff, myError, CRED, opaque);
2729 TRACEP(FS, "rc=" <<rc <<" rm " <<argp->buff);
2730 if (SFS_OK == rc) return Response.Send();
2731
2732// An error occurred
2733//
2734 return fsError(rc, XROOTD_MON_RM, myError, argp->buff, opaque);
2735}
2736
2737/******************************************************************************/
2738/* d o _ R m d i r */
2739/******************************************************************************/
2740
2741int XrdXrootdProtocol::do_Rmdir()
2742{
2743 int rc;
2744 char *opaque;
2745 XrdOucErrInfo myError(Link->ID, Monitor.Did, clientPV);
2746
2747// Check for static routing
2748//
2749 STATIC_REDIRECT(RD_rmdir);
2750
2751// Prescreen the path
2752//
2753 if (rpCheck(argp->buff, &opaque)) return rpEmsg("Removing", argp->buff);
2754 if (!Squash(argp->buff)) return vpEmsg("Removing", argp->buff);
2755
2756// Preform the actual function
2757//
2758 rc = osFS->remdir(argp->buff, myError, CRED, opaque);
2759 TRACEP(FS, "rc=" <<rc <<" rmdir " <<argp->buff);
2760 if (SFS_OK == rc) return Response.Send();
2761
2762// An error occurred
2763//
2764 return fsError(rc, XROOTD_MON_RMDIR, myError, argp->buff, opaque);
2765}
2766
2767/******************************************************************************/
2768/* d o _ S e t */
2769/******************************************************************************/
2770
2771int XrdXrootdProtocol::do_Set()
2772{
2773 XrdOucTokenizer setargs(argp->buff);
2774 char *val, *rest;
2775
2776// Get the first argument
2777//
2778 if (!setargs.GetLine() || !(val = setargs.GetToken(&rest)))
2779 return Response.Send(kXR_ArgMissing, "set argument not specified.");
2780
2781// Trace this set
2782//
2783 TRACEP(DEBUG, "set " <<val <<' ' <<rest);
2784
2785// Now determine what the user wants to set
2786//
2787 if (!strcmp("appid", val))
2788 {while(*rest && *rest == ' ') rest++;
2789 eDest.Emsg("Xeq", Link->ID, "appid", rest);
2790 return Response.Send();
2791 }
2792 else if (!strcmp("monitor", val)) return do_Set_Mon(setargs);
2793 else if (!strcmp("cache", val)) return do_Set_Cache(setargs);
2794
2795// All done
2796//
2797 return Response.Send(kXR_ArgInvalid, "invalid set parameter");
2798}
2799
2800/******************************************************************************/
2801/* d o _ S e t _ C a c h e */
2802/******************************************************************************/
2803
2804// Process: set cache <cmd> <args>
2805
2806int XrdXrootdProtocol::do_Set_Cache(XrdOucTokenizer &setargs)
2807{
2808 XrdOucErrInfo myError(Link->ID, Monitor.Did, clientPV);
2809 XrdSfsFSctl myData;
2810 char *cmd, *cargs, *opaque;
2811 const char *myArgs[2];
2812
2813// This set is valid only if we implement a cache
2814//
2815 if ((fsFeatures & XrdSfs::hasCACH) == 0)
2816 return Response.Send(kXR_ArgInvalid, "invalid set parameter");
2817
2818// Get the command and argument
2819//
2820 if (!(cmd = setargs.GetToken(&cargs)))
2821 return Response.Send(kXR_ArgMissing,"set cache argument not specified.");
2822
2823// Prescreen the path if the next token starts with a slash
2824//
2825 if (cargs && *cargs == '/')
2826 {if (rpCheck(cargs, &opaque)) return rpEmsg("Setting", cargs);
2827 if (!Squash(cargs)) return vpEmsg("Setting", cargs);
2828 myData.ArgP = myArgs; myData.Arg2Len = -2;
2829 myArgs[0] = cargs;
2830 myArgs[1] = opaque;
2831 } else {
2832 myData.Arg2 = opaque; myData.Arg2Len = (opaque ? strlen(opaque) : 0);
2833 }
2834 myData.Arg1 = cmd; myData.Arg1Len = strlen(cmd);
2835
2836// Preform the actual function using the supplied arguments
2837//
2838 int rc = osFS->FSctl(SFS_FSCTL_PLUGXC, myData, myError, CRED);
2839 TRACEP(FS, "rc=" <<rc <<"set cache " <<myData.Arg1 <<' ' <<cargs);
2840 if (rc == SFS_OK) return Response.Send("");
2841 return fsError(rc, 0, myError, 0, 0);
2842}
2843
2844/******************************************************************************/
2845/* d o _ S e t _ M o n */
2846/******************************************************************************/
2847
2848// Process: set monitor {off | on} {[appid] | info [info]}
2849
2850int XrdXrootdProtocol::do_Set_Mon(XrdOucTokenizer &setargs)
2851{
2852 char *val, *appid;
2853 kXR_unt32 myseq = 0;
2854
2855// Get the first argument
2856//
2857 if (!(val = setargs.GetToken(&appid)))
2858 return Response.Send(kXR_ArgMissing,"set monitor argument not specified.");
2859
2860// For info requests, nothing changes. However, info events must have been
2861// enabled for us to record them. Route the information via the static
2862// monitor entry, since it knows how to forward the information.
2863//
2864 if (!strcmp(val, "info"))
2865 {if (appid && Monitor.Info())
2866 {while(*appid && *appid == ' ') appid++;
2867 if (strlen(appid) > 1024) appid[1024] = '\0';
2868 if (*appid) myseq = Monitor.MapInfo(appid);
2869 }
2870 return Response.Send((void *)&myseq, sizeof(myseq));
2871 }
2872
2873// Determine if on do appropriate processing
2874//
2875 if (!strcmp(val, "on"))
2876 {Monitor.Enable();
2877 if (appid && Monitor.InOut())
2878 {while(*appid && *appid == ' ') appid++;
2879 if (*appid) Monitor.Agent->appID(appid);
2880 }
2881 if (!Monitor.Did && Monitor.Logins()) MonAuth();
2882 return Response.Send();
2883 }
2884
2885// Determine if off and do appropriate processing
2886//
2887 if (!strcmp(val, "off"))
2888 {if (appid && Monitor.InOut())
2889 {while(*appid && *appid == ' ') appid++;
2890 if (*appid) Monitor.Agent->appID(appid);
2891 }
2892 Monitor.Disable();
2893 return Response.Send();
2894 }
2895
2896// Improper request
2897//
2898 return Response.Send(kXR_ArgInvalid, "invalid set monitor argument");
2899}
2900
2901/******************************************************************************/
2902/* d o _ S t a t */
2903/******************************************************************************/
2904
2905int XrdXrootdProtocol::do_Stat()
2906{
2907 static XrdXrootdCallBack statCB("stat", XROOTD_MON_STAT);
2908 static const int fsctl_cmd = SFS_FSCTL_STATFS;
2909 bool doDig;
2910 int rc;
2911 char *opaque, xxBuff[1024];
2912 struct stat buf;
2913 XrdOucErrInfo myError(Link->ID,&statCB,ReqID.getID(),Monitor.Did,clientPV);
2914
2915// Update misc stats count
2916//
2917 SI->Bump(SI->miscCnt);
2918
2919// The stat request may refer to an open file handle. So, screen this out.
2920//
2921 if (!argp || !Request.header.dlen)
2922 {XrdXrootdFile *fp;
2923 XrdXrootdFHandle fh(Request.stat.fhandle);
2924 if (Request.stat.options & kXR_vfs)
2925 {Response.Send(kXR_ArgMissing, "Required argument not present");
2926 return 0;
2927 }
2928 if (!FTab || !(fp = FTab->Get(fh.handle)))
2929 return Response.Send(kXR_FileNotOpen,
2930 "stat does not refer to an open file");
2931 rc = fp->XrdSfsp->stat(&buf);
2932 TRACEP(FS, "fh=" <<fh.handle <<" stat rc=" <<rc);
2933 if (SFS_OK == rc) return Response.Send(xxBuff,
2934 StatGen(buf,xxBuff,sizeof(xxBuff)));
2935 return fsError(rc, 0, fp->XrdSfsp->error, 0, 0);
2936 }
2937
2938// Check if we are handling a dig type path
2939//
2940 doDig = (digFS && SFS_LCLROOT(argp->buff));
2941
2942// Check for static routing
2943//
2944 if (!doDig) {STATIC_REDIRECT(RD_stat);}
2945
2946// Prescreen the path
2947//
2948 if (rpCheck(argp->buff, &opaque)) return rpEmsg("Stating", argp->buff);
2949 if (!doDig && !Squash(argp->buff))return vpEmsg("Stating", argp->buff);
2950
2951// Preform the actual function, we may been to add back the opaque info
2952//
2953 if (Request.stat.options & kXR_vfs)
2954 {if (opaque)
2955 {int n = strlen(argp->buff); argp->buff[n] = '?';
2956 if ((argp->buff)+n != opaque-1)
2957 memmove(&argp->buff[n+1], opaque, strlen(opaque)+1);
2958 }
2959 rc = osFS->fsctl(fsctl_cmd, argp->buff, myError, CRED);
2960 TRACEP(FS, "rc=" <<rc <<" statfs " <<argp->buff);
2961 if (rc == SFS_OK) Response.Send("");
2962 } else {
2963 if (doDig) rc = digFS->stat(argp->buff, &buf, myError, CRED, opaque);
2964 else rc = osFS->stat(argp->buff, &buf, myError, CRED, opaque);
2965 TRACEP(FS, "rc=" <<rc <<" stat " <<argp->buff);
2966 if (rc == SFS_OK) return Response.Send(xxBuff,
2967 StatGen(buf,xxBuff,sizeof(xxBuff)));
2968 }
2969 return fsError(rc, (doDig ? 0 : XROOTD_MON_STAT),myError,argp->buff,opaque);
2970}
2971
2972/******************************************************************************/
2973/* d o _ S t a t x */
2974/******************************************************************************/
2975
2976int XrdXrootdProtocol::do_Statx()
2977{
2978 static XrdXrootdCallBack statxCB("xstat", XROOTD_MON_STAT);
2979 int rc;
2980 char *path, *opaque, *respinfo = argp->buff;
2981 mode_t mode;
2982 XrdOucErrInfo myError(Link->ID,&statxCB,ReqID.getID(),Monitor.Did,clientPV);
2983 XrdOucTokenizer pathlist(argp->buff);
2984
2985// Check for static routing
2986//
2987 STATIC_REDIRECT(RD_stat);
2988
2989// Cycle through all of the paths in the list
2990//
2991 while((path = pathlist.GetLine()))
2992 {if (rpCheck(path, &opaque)) return rpEmsg("Stating", path);
2993 if (!Squash(path)) return vpEmsg("Stating", path);
2994 rc = osFS->stat(path, mode, myError, CRED, opaque);
2995 TRACEP(FS, "rc=" <<rc <<" stat " <<path);
2996 if (rc != SFS_OK)
2997 return fsError(rc, XROOTD_MON_STAT, myError, path, opaque);
2998 else {if (mode == (mode_t)-1) *respinfo = (char)kXR_offline;
2999 else if (S_ISDIR(mode)) *respinfo = (char)kXR_isDir;
3000 else *respinfo = (char)kXR_file;
3001 }
3002 respinfo++;
3003 }
3004
3005// Return result
3006//
3007 return Response.Send(argp->buff, respinfo-argp->buff);
3008}
3009
3010/******************************************************************************/
3011/* d o _ S y n c */
3012/******************************************************************************/
3013
3014int XrdXrootdProtocol::do_Sync()
3015{
3016 static XrdXrootdCallBack syncCB("sync", 0);
3017 int rc;
3018 XrdXrootdFile *fp;
3019 XrdXrootdFHandle fh(Request.sync.fhandle);
3020
3021// Keep Statistics
3022//
3023 SI->Bump(SI->syncCnt);
3024
3025// Find the file object
3026//
3027 if (!FTab || !(fp = FTab->Get(fh.handle)))
3028 return Response.Send(kXR_FileNotOpen,"sync does not refer to an open file");
3029
3030// The sync is elegible for a deferred response, indicate we're ok with that
3031//
3032 fp->XrdSfsp->error.setErrCB(&syncCB, ReqID.getID());
3033
3034// Sync the file
3035//
3036 rc = fp->XrdSfsp->sync();
3037 TRACEP(FS, "fh=" <<fh.handle <<" sync rc=" <<rc);
3038 if (SFS_OK != rc) return fsError(rc, 0, fp->XrdSfsp->error, 0, 0);
3039
3040// Respond that all went well
3041//
3042 return Response.Send();
3043}
3044
3045/******************************************************************************/
3046/* d o _ T r u n c a t e */
3047/******************************************************************************/
3048
3049int XrdXrootdProtocol::do_Truncate()
3050{
3051 static XrdXrootdCallBack truncCB("trunc", 0);
3052 XrdXrootdFile *fp;
3053 XrdXrootdFHandle fh(Request.truncate.fhandle);
3054 long long theOffset;
3055 int rc;
3056
3057// Unmarshall the data
3058//
3059 n2hll(Request.truncate.offset, theOffset);
3060
3061// Check if this is a truncate for an open file (no path given)
3062//
3063 if (!Request.header.dlen)
3064 {
3065 // Update misc stats count
3066 //
3067 SI->Bump(SI->miscCnt);
3068
3069 // Find the file object
3070 //
3071 if (!FTab || !(fp = FTab->Get(fh.handle)))
3072 return Response.Send(kXR_FileNotOpen,
3073 "trunc does not refer to an open file");
3074
3075 // Truncate the file (it is eligible for async callbacks)
3076 //
3077 fp->XrdSfsp->error.setErrCB(&truncCB, ReqID.getID());
3078 rc = fp->XrdSfsp->truncate(theOffset);
3079 TRACEP(FS, "fh=" <<fh.handle <<" trunc rc=" <<rc <<" sz=" <<theOffset);
3080 if (SFS_OK != rc) return fsError(rc, 0, fp->XrdSfsp->error, 0, 0);
3081
3082 } else {
3083
3084 XrdOucErrInfo myError(Link->ID, Monitor.Did, clientPV);
3085 char *opaque;
3086
3087 // Check for static routing
3088 //
3089 STATIC_REDIRECT(RD_trunc);
3090
3091 // Verify the path and extract out the opaque information
3092 //
3093 if (rpCheck(argp->buff,&opaque)) return rpEmsg("Truncating",argp->buff);
3094 if (!Squash(argp->buff)) return vpEmsg("Truncating",argp->buff);
3095
3096 // Preform the actual function
3097 //
3098 rc = osFS->truncate(argp->buff, (XrdSfsFileOffset)theOffset, myError,
3099 CRED, opaque);
3100 TRACEP(FS, "rc=" <<rc <<" trunc " <<theOffset <<' ' <<argp->buff);
3101 if (SFS_OK != rc)
3102 return fsError(rc, XROOTD_MON_TRUNC, myError, argp->buff, opaque);
3103 }
3104
3105// Respond that all went well
3106//
3107 return Response.Send();
3108}
3109
3110/******************************************************************************/
3111/* d o _ W r i t e */
3112/******************************************************************************/
3113
3114int XrdXrootdProtocol::do_Write()
3115{
3116 int pathID;
3117 XrdXrootdFHandle fh(Request.write.fhandle);
3118 numWrites++;
3119
3120// Unmarshall the data
3121//
3122 IO.IOLen = Request.header.dlen;
3123 n2hll(Request.write.offset, IO.Offset);
3124 pathID = static_cast<int>(Request.write.pathid);
3125
3126// Find the file object. We will drain socket data on the control path only!
3127// .
3128 if (!FTab || !(IO.File = FTab->Get(fh.handle)))
3129 {IO.File = 0;
3130 return do_WriteNone(pathID);
3131 }
3132
3133// Trace and verify that length is not negative
3134//
3135 TRACEP(FSIO, pathID<<" fh="<<fh.handle<<" write "<<IO.IOLen<<'@'<<IO.Offset);
3136 if ( IO.IOLen < 0) return Response.Send(kXR_ArgInvalid,
3137 "Write length is negative");
3138
3139// If we are monitoring, insert a write entry
3140//
3141 if (Monitor.InOut())
3142 Monitor.Agent->Add_wr(IO.File->Stats.FileID, Request.write.dlen,
3143 Request.write.offset);
3144
3145// If zero length write, simply return
3146//
3147 if (!IO.IOLen) return Response.Send();
3148 IO.File->Stats.wrOps(IO.IOLen); // Optimistically correct
3149
3150// If async write allowed and it is a true write request (e.g. not chkpoint) and
3151// current conditions permit async; schedule the write to occur asynchronously
3152//
3153 if (IO.File->AsyncMode && Request.header.requestid == kXR_write
3154 && !as_syncw && IO.IOLen >= as_miniosz && srvrAioOps < as_maxpersrv)
3155 {if (myStalls < as_maxstalls)
3156 {if (pathID) return do_Offload(&XrdXrootdProtocol::do_WriteAio,pathID);
3157 return do_WriteAio();
3158 }
3159 SI->AsyncRej++;
3160 myStalls--;
3161 }
3162
3163// See if an alternate path is required
3164//
3165 if (pathID) return do_Offload(&XrdXrootdProtocol::do_WriteAll, pathID);
3166
3167// Just to the i/o now
3168//
3169 return do_WriteAll();
3170}
3171
3172/******************************************************************************/
3173/* d o _ W r i t e A i o */
3174/******************************************************************************/
3175
3176// IO.File = file to be written
3177// IO.Offset = Offset at which to write
3178// IO.IOLen = Number of bytes to read from socket and write to file
3179
3180int XrdXrootdProtocol::do_WriteAio()
3181{
3182 XrdXrootdNormAio *aioP;
3183
3184// Allocate an aio request object if client hasn't exceeded the link limit
3185//
3187 || !(aioP = XrdXrootdNormAio::Alloc(this, Response, IO.File)))
3188 {SI->AsyncRej++;
3189 if (myStalls > 0) myStalls--;
3190 return do_WriteAll();
3191 }
3192
3193// Issue the write request
3194//
3195 return aioP->Write(IO.Offset, IO.IOLen);
3196}
3197
3198/******************************************************************************/
3199/* d o _ W r i t e A l l */
3200/******************************************************************************/
3201
3202// IO.File = file to be written
3203// IO.Offset = Offset at which to write
3204// IO.IOLen = Number of bytes to read from socket and write to file
3205
3206int XrdXrootdProtocol::do_WriteAll()
3207{
3208 int rc, Quantum = (IO.IOLen > maxBuffsz ? maxBuffsz : IO.IOLen);
3209
3210// Make sure we have a large enough buffer
3211//
3212 if (!argp || Quantum < halfBSize || Quantum > argp->bsize)
3213 {if ((rc = getBuff(0, Quantum)) <= 0) return rc;}
3214 else if (hcNow < hcNext) hcNow++;
3215
3216// Now write all of the data (XrdXrootdProtocol.C defines getData())
3217//
3218 while(IO.IOLen > 0)
3219 {if ((rc = getData("data", argp->buff, Quantum)))
3220 {if (rc > 0)
3221 {Resume = &XrdXrootdProtocol::do_WriteCont;
3222 myBlast = Quantum;
3223 }
3224 return rc;
3225 }
3226 if ((rc = IO.File->XrdSfsp->write(IO.Offset, argp->buff, Quantum)) < 0)
3227 {IO.IOLen = IO.IOLen-Quantum; IO.EInfo[0] = rc; IO.EInfo[1] = 0;
3228 return do_WriteNone();
3229 }
3230 IO.Offset += Quantum; IO.IOLen -= Quantum;
3231 if (IO.IOLen < Quantum) Quantum = IO.IOLen;
3232 }
3233
3234// All done
3235//
3236 return Response.Send();
3237}
3238
3239/******************************************************************************/
3240/* d o _ W r i t e C o n t */
3241/******************************************************************************/
3242
3243// IO.File = file to be written
3244// IO.Offset = Offset at which to write
3245// IO.IOLen = Number of bytes to read from socket and write to file
3246// myBlast = Number of bytes already read from the socket
3247
3248int XrdXrootdProtocol::do_WriteCont()
3249{
3250 int rc;
3251
3252// Write data that was finaly finished comming in
3253//
3254 if ((rc = IO.File->XrdSfsp->write(IO.Offset, argp->buff, myBlast)) < 0)
3255 {IO.IOLen = IO.IOLen-myBlast; IO.EInfo[0] = rc; IO.EInfo[1] = 0;
3256 return do_WriteNone();
3257 }
3258 IO.Offset += myBlast; IO.IOLen -= myBlast;
3259
3260// See if we need to finish this request in the normal way
3261//
3262 if (IO.IOLen > 0) return do_WriteAll();
3263 return Response.Send();
3264}
3265
3266/******************************************************************************/
3267/* d o _ W r i t e N o n e */
3268/******************************************************************************/
3269
3270int XrdXrootdProtocol::do_WriteNone()
3271{
3272 char *buff, dbuff[4096];
3273 int rlen, blen;
3274
3275// Determine which buffer we will use
3276//
3277 if (argp && argp->bsize > (int)sizeof(dbuff))
3278 {buff = argp->buff;
3279 blen = argp->bsize;
3280 } else {
3281 buff = dbuff;
3282 blen = sizeof(dbuff);
3283 }
3284 if (IO.IOLen < blen) blen = IO.IOLen;
3285
3286// Discard any data being transmitted
3287//
3288 TRACEP(REQ, "discarding " <<IO.IOLen <<" bytes");
3289 while(IO.IOLen > 0)
3290 {rlen = Link->Recv(buff, blen, readWait);
3291 if (rlen < 0) return Link->setEtext("link read error");
3292 IO.IOLen -= rlen;
3293 if (rlen < blen)
3294 {myBlen = 0;
3295 Resume = &XrdXrootdProtocol::do_WriteNone;
3296 return 1;
3297 }
3298 if (IO.IOLen < blen) blen = IO.IOLen;
3299 }
3300
3301// Send final message
3302//
3303 return do_WriteNoneMsg();
3304}
3305
3306/******************************************************************************/
3307
3308int XrdXrootdProtocol::do_WriteNone(int pathID, XErrorCode ec,
3309 const char *emsg)
3310{
3311// We can't recover when the data is arriving on a foriegn bound path as there
3312// no way to properly drain the socket. So, we terminate the connection.
3313//
3314 if (pathID != PathID)
3315 {if (ec && emsg) Response.Send(ec, emsg);
3316 else do_WriteNoneMsg();
3317 return Link->setEtext("write protocol violation");
3318 }
3319
3320// Set error code if present
3321//
3322 if (ec != kXR_noErrorYet)
3323 {IO.EInfo[1] = ec;
3324 if (IO.File)
3325 {if (!emsg) emsg = XProtocol::errName(ec);
3326 IO.File->XrdSfsp->error.setErrInfo(0, emsg);
3327 }
3328 }
3329
3330// Otherwise, continue to darin the socket
3331//
3332 return do_WriteNone();
3333}
3334
3335/******************************************************************************/
3336/* d o _ W r i t e N o n e M s g */
3337/******************************************************************************/
3338
3339int XrdXrootdProtocol::do_WriteNoneMsg()
3340{
3341// Send our the error message and return
3342//
3343 if (!IO.File) return
3344 Response.Send(kXR_FileNotOpen,"write does not refer to an open file");
3345
3346 if (IO.EInfo[1])
3347 return Response.Send((XErrorCode)IO.EInfo[1],
3348 IO.File->XrdSfsp->error.getErrText());
3349
3350 if (IO.EInfo[0]) return fsError(IO.EInfo[0], 0, IO.File->XrdSfsp->error, 0, 0);
3351
3352 return Response.Send(kXR_FSError, IO.File->XrdSfsp->error.getErrText());
3353}
3354
3355/******************************************************************************/
3356/* d o _ W r i t e S p a n */
3357/******************************************************************************/
3358
3360{
3361 int rc;
3362 XrdXrootdFHandle fh(Request.write.fhandle);
3363 numWrites++;
3364
3365// Unmarshall the data
3366//
3367 IO.IOLen = Request.header.dlen;
3368 n2hll(Request.write.offset, IO.Offset);
3369
3370// Find the file object. We will only drain socket data on the control path.
3371// .
3372 if (!FTab || !(IO.File = FTab->Get(fh.handle)))
3373 {IO.IOLen -= myBlast;
3374 IO.File = 0;
3375 return do_WriteNone(Request.write.pathid);
3376 }
3377
3378// If we are monitoring, insert a write entry
3379//
3380 if (Monitor.InOut())
3381 Monitor.Agent->Add_wr(IO.File->Stats.FileID, Request.write.dlen,
3382 Request.write.offset);
3383 IO.File->Stats.wrOps(IO.IOLen); // Optimistically correct
3384
3385// Trace this entry
3386//
3387 TRACEP(FSIO, "fh=" <<fh.handle <<" write " <<IO.IOLen <<'@' <<IO.Offset);
3388
3389// Write data that was already read
3390//
3391 if ((rc = IO.File->XrdSfsp->write(IO.Offset, myBuff, myBlast)) < 0)
3392 {IO.IOLen = IO.IOLen-myBlast; IO.EInfo[0] = rc; IO.EInfo[1] = 0;
3393 return do_WriteNone();
3394 }
3395 IO.Offset += myBlast; IO.IOLen -= myBlast;
3396
3397// See if we need to finish this request in the normal way
3398//
3399 if (IO.IOLen > 0) return do_WriteAll();
3400 return Response.Send();
3401}
3402
3403/******************************************************************************/
3404/* d o _ W r i t e V */
3405/******************************************************************************/
3406
3407int XrdXrootdProtocol::do_WriteV()
3408{
3409// This will write multiple buffers at the same time in an attempt to avoid
3410// the disk latency. The information with the offsets and lengths of the data
3411// to write is passed as a data buffer. We attempt to optimize as best as
3412// possible, though certain combinations may result in multiple writes. Since
3413// socket flushing is nearly impossible when an error occurs, most errors
3414// simply terminate the connection.
3415//
3416 const int wveSZ = sizeof(XrdProto::write_list);
3417 struct trackInfo
3418 {XrdXrootdWVInfo **wvInfo; bool doit;
3419 trackInfo(XrdXrootdWVInfo **wvP) : wvInfo(wvP), doit(true) {}
3420 ~trackInfo() {if (doit && *wvInfo) {free(*wvInfo); *wvInfo = 0;}}
3421 } freeInfo(&wvInfo);
3422
3423 struct XrdProto::write_list *wrLst;
3424 XrdOucIOVec *wrVec;
3425 long long totSZ, maxSZ;
3426 int curFH, k, Quantum, wrVecNum, wrVecLen = Request.header.dlen;
3427
3428// Compute number of elements in the write vector and make sure we have no
3429// partial elements.
3430//
3431 wrVecNum = wrVecLen / wveSZ;
3432 if ( (wrVecLen <= 0) || (wrVecNum*wveSZ != wrVecLen) )
3433 {Response.Send(kXR_ArgInvalid, "Write vector is invalid");
3434 return -1;
3435 }
3436
3437// Make sure that we can make a copy of the read vector. So, we impose a limit
3438// on it's size.
3439//
3440 if (wrVecNum > XrdProto::maxWvecsz)
3441 {Response.Send(kXR_ArgTooLong, "Write vector is too long");
3442 return -1;
3443 }
3444
3445// Create the verctor write information structure sized as needed.
3446//
3447 if (wvInfo) free(wvInfo);
3448 wvInfo = (XrdXrootdWVInfo *)malloc(sizeof(XrdXrootdWVInfo) +
3449 sizeof(XrdOucIOVec)*(wrVecNum-1));
3450 memset(wvInfo, 0, sizeof(XrdXrootdWVInfo) - sizeof(XrdOucIOVec));
3451 wvInfo->wrVec = wrVec = wvInfo->ioVec;
3452
3453// Run down the list and compute the total size of the write. No individual
3454// write may be greater than the maximum transfer size. We also use this loop
3455// to copy the write list to our writev vector for later processing.
3456//
3457 wrLst = (XrdProto::write_list *)argp->buff;
3458 totSZ = 0; maxSZ = 0; k = 0; Quantum = maxTransz; curFH = 0;
3459 for (int i = 0; i < wrVecNum; i++)
3460 {if (wrLst[i].wlen == 0) continue;
3461 memcpy(&wrVec[k].info, wrLst[i].fhandle, sizeof(int));
3462 wrVec[k].size = ntohl(wrLst[i].wlen);
3463 if (wrVec[k].size < 0)
3464 {Response.Send(kXR_ArgInvalid, "Writev length is negtive");
3465 return -1;
3466 }
3467 if (wrVec[k].size > Quantum)
3468 {Response.Send(kXR_NoMemory,"Single writev transfer is too large");
3469 return -1;
3470 }
3471 wrVec[k].offset = ntohll(wrLst[i].offset);
3472 if (wrVec[k].info == curFH) totSZ += wrVec[k].size;
3473 else {if (maxSZ < totSZ) maxSZ = totSZ;
3474 totSZ = wrVec[k].size;
3475 }
3476 k++;
3477 }
3478
3479// Check if we are not actually writing anything, simply return success
3480//
3481 if (maxSZ < totSZ) maxSZ = totSZ;
3482 if (maxSZ == 0) return Response.Send();
3483
3484// So, now we account for the number of writev requests and total segments
3485//
3486 numWritV++; numSegsW += k; wrVecNum = k;
3487
3488// Calculate the transfer unit which will be the smaller of the maximum
3489// transfer unit and the actual amount we need to transfer.
3490//
3491 if (maxSZ > maxTransz) Quantum = maxTransz;
3492 else Quantum = static_cast<int>(maxSZ);
3493
3494// Now obtain the right size buffer
3495//
3496 if ((Quantum < halfBSize && Quantum > 1024) || Quantum > argp->bsize)
3497 {if (getBuff(0, Quantum) <= 0) return -1;}
3498 else if (hcNow < hcNext) hcNow++;
3499
3500// Check that we really have at least the first file open (part of setup)
3501//
3502 if (!FTab || !(IO.File = FTab->Get(wrVec[0].info)))
3503 {Response.Send(kXR_FileNotOpen, "writev does not refer to an open file");
3504 return -1;
3505 }
3506
3507// Setup to do the complete transfer
3508//
3509 wvInfo->curFH = wrVec[0].info;
3510 wvInfo->vBeg = 0;
3511 wvInfo->vPos = 0;
3512 wvInfo->vEnd = wrVecNum;
3513 wvInfo->vMon = 0;
3514 wvInfo->doSync= (Request.writev.options & ClientWriteVRequest::doSync) != 0;
3515 wvInfo->wvMon = Monitor.InOut();
3516 wvInfo->ioMon = (wvInfo->vMon > 1);
3517// wvInfo->vType = (wvInfo->ioMon ? XROOTD_MON_WRITEU : XROOTD_MON_WRITEV);
3518 IO.WVBytes = 0;
3519 IO.IOLen = wrVec[0].size;
3520 myBuff = argp->buff;
3521 myBlast = 0;
3522
3523// Now we simply start the write operations if this is a true writev request.
3524// Otherwise return to the caller for additional processing.
3525//
3526 freeInfo.doit = false;
3527 if (Request.header.requestid == kXR_writev) return do_WriteVec();
3528 return 0;
3529}
3530
3531/******************************************************************************/
3532/* d o _ W r i t e V e c */
3533/******************************************************************************/
3534
3535int XrdXrootdProtocol::do_WriteVec()
3536{
3537 XrdSfsXferSize xfrSZ;
3538 int rc, wrVNum, vNow = wvInfo->vPos;
3539 bool done, newfile;
3540
3541// Read the complete data from the socket for the current element. Note that
3542// should we enter a resume state; upon re-entry all of the data will be read.
3543//
3544do{if (IO.IOLen > 0)
3545 {wvInfo->wrVec[vNow].data = argp->buff + myBlast;
3546 myBlast += IO.IOLen;
3547 if ((rc = getData("data", myBuff, IO.IOLen)))
3548 {if (rc < 0) return rc;
3549 IO.IOLen = 0;
3550 Resume = &XrdXrootdProtocol::do_WriteVec;
3551 return rc;
3552 }
3553 }
3554
3555// Establish the state at this point as this will tell us what to do next.
3556//
3557 vNow++;
3558 done = newfile = false;
3559 if (vNow >= wvInfo->vEnd) done = true;
3560 else if (wvInfo->wrVec[vNow].info != wvInfo->curFH) newfile = true;
3561 else if (myBlast + wvInfo->wrVec[vNow].size <= argp->bsize)
3562 {IO.IOLen = wvInfo->wrVec[vNow].size;
3563 myBuff = argp->buff + myBlast;
3564 wvInfo->vPos = vNow;
3565 continue;
3566 }
3567
3568// We need to write out what we have.
3569//
3570 wrVNum = vNow - wvInfo->vBeg;
3571 xfrSZ = IO.File->XrdSfsp->writev(&(wvInfo->wrVec[wvInfo->vBeg]), wrVNum);
3572 TRACEP(FSIO,"fh=" <<wvInfo->curFH <<" writeV " << xfrSZ <<':' <<wrVNum);
3573 if (xfrSZ != myBlast) break;
3574
3575// Check if we need to do monitoring or a sync with no deferal. Note that
3576// we currently do not support detailed monitoring for vector writes!
3577//
3578 if (done || newfile)
3579 {int monVnum = vNow - wvInfo->vMon;
3580 IO.File->Stats.wvOps(IO.WVBytes, monVnum);
3590 wvInfo->vMon = vNow;
3591 IO.WVBytes = 0;
3592 if (wvInfo->doSync)
3593 {IO.File->XrdSfsp->error.setErrCB(0,0);
3594 xfrSZ = IO.File->XrdSfsp->sync();
3595 if (xfrSZ< 0) break;
3596 }
3597 }
3598
3599// If we are done, the finish up
3600//
3601 if (done)
3602 {if (wvInfo) {free(wvInfo); wvInfo = 0;}
3603 return Response.Send();
3604 }
3605
3606// Sequence to a new file if we need to do so
3607//
3608 if (newfile)
3609 {if (!FTab || !(IO.File = FTab->Get(wvInfo->wrVec[vNow].info)))
3610 {Response.Send(kXR_FileNotOpen,"writev does not refer to an open file");
3611 return -1;
3612 }
3613 wvInfo->curFH = wvInfo->wrVec[vNow].info;
3614 }
3615
3616// Setup to resume transfer
3617//
3618 myBlast = 0;
3619 myBuff = argp->buff;
3620 IO.IOLen = wvInfo->wrVec[vNow].size;
3621 wvInfo->vBeg = vNow;
3622 wvInfo->vPos = vNow;
3623
3624} while(true);
3625
3626// If we got here then there was a write error (file pointer is valid).
3627//
3628 if (wvInfo) {free(wvInfo); wvInfo = 0;}
3629 return fsError((int)xfrSZ, 0, IO.File->XrdSfsp->error, 0, 0);
3630}
3631
3632/******************************************************************************/
3633/* S e n d F i l e */
3634/******************************************************************************/
3635
3637{
3638
3639// Make sure we have some data to send
3640//
3641 if (!IO.IOLen) return 1;
3642
3643// Send off the data
3644//
3645 IO.IOLen = Response.Send(fildes, IO.Offset, IO.IOLen);
3646 return IO.IOLen;
3647}
3648
3649/******************************************************************************/
3650
3652{
3653 int i, xframt = 0;
3654
3655// Make sure we have some data to send
3656//
3657 if (!IO.IOLen) return 1;
3658
3659// Verify the length, it can't be greater than what the client wants
3660//
3661 for (i = 1; i < sfvnum; i++) xframt += sfvec[i].sendsz;
3662 if (xframt > IO.IOLen) return 1;
3663
3664// Send off the data
3665//
3666 if (xframt) IO.IOLen = Response.Send(sfvec, sfvnum, xframt);
3667 else {IO.IOLen = 0; Response.Send();}
3668 return IO.IOLen;
3669}
3670
3671/******************************************************************************/
3672/* S e t F D */
3673/******************************************************************************/
3674
3676{
3677 if (fildes < 0) IO.File->sfEnabled = 0;
3678 else IO.File->fdNum = fildes;
3679}
3680
3681/******************************************************************************/
3682/* U t i l i t y M e t h o d s */
3683/******************************************************************************/
3684/******************************************************************************/
3685/* f s E r r o r */
3686/******************************************************************************/
3687
3688int XrdXrootdProtocol::fsError(int rc, char opC, XrdOucErrInfo &myError,
3689 const char *Path, char *Cgi)
3690{
3691 int ecode, popt, rs;
3692 const char *eMsg = myError.getErrText(ecode);
3693
3694// Process standard errors
3695//
3696 if (rc == SFS_ERROR)
3697 {SI->errorCnt++;
3698 rc = XProtocol::mapError(ecode);
3699
3700 if (Path && (rc == kXR_Overloaded) && (opC == XROOTD_MON_OPENR
3701 || opC == XROOTD_MON_OPENW || opC == XROOTD_MON_OPENC))
3702 {if (myError.extData()) myError.Reset();
3703 return fsOvrld(opC, Path, Cgi);
3704 }
3705
3706 if (Path && (rc == kXR_NotFound) && RQLxist && opC
3707 && (popt = RQList.Validate(Path)))
3710 Route[popt].Host[rdType],
3711 Route[popt].Port[rdType],
3713 if (Cgi) rs = fsRedirNoEnt(eMsg, Cgi, popt);
3714 else rs = Response.Send(kXR_redirect,
3715 Route[popt].Port[rdType],
3716 Route[popt].Host[rdType]);
3717 } else rs = Response.Send((XErrorCode)rc, eMsg);
3718 if (myError.extData()) myError.Reset();
3719 return rs;
3720 }
3721
3722// Process the redirection (error msg is host:port)
3723//
3724 if (rc == SFS_REDIRECT)
3725 {SI->redirCnt++;
3726 // if the plugin set some redirect flags but the client does not
3727 // support them, clear the flags (set -1)
3728 if( ecode < -1 && !( clientPV & XrdOucEI::uRedirFlgs ) )
3729 ecode = -1;
3730 if (XrdXrootdMonitor::Redirect() && Path && opC)
3732 if (TRACING(TRACE_REDIR))
3733 {if (ecode < 0)
3734 {TRACEI(REDIR, Response.ID() <<"redirecting to " << eMsg);}
3735 else {TRACEI(REDIR, Response.ID() <<"redirecting to "
3736 << eMsg <<':' <<ecode);
3737 }
3738 }
3739 rs = Response.Send(kXR_redirect, ecode, eMsg, myError.getErrTextLen());
3740 if (myError.extData()) myError.Reset();
3741 return rs;
3742 }
3743
3744// Process the deferal. We also synchronize sending the deferal response with
3745// sending the actual deferred response by calling Done() in the callback object.
3746// This allows the requestor of he callback know that we actually send the
3747// kXR_waitresp to the end client and avoid violating time causality.
3748//
3749 if (rc == SFS_STARTED)
3750 {SI->stallCnt++;
3751 if (ecode <= 0) ecode = 1800;
3752 TRACEI(STALL, Response.ID() <<"delaying client up to " <<ecode <<" sec");
3753 rc = Response.Send(kXR_waitresp, ecode, eMsg);
3754 if (myError.getErrCB()) myError.getErrCB()->Done(ecode, &myError);
3755 if (myError.extData()) myError.Reset();
3756 return (rc ? rc : 1);
3757 }
3758
3759// Process the data response
3760//
3761 if (rc == SFS_DATA)
3762 {if (ecode) rs = Response.Send((void *)eMsg, ecode);
3763 else rs = Response.Send();
3764 if (myError.extData()) myError.Reset();
3765 return rs;
3766 }
3767
3768// Process the data response via an iovec
3769//
3770 if (rc == SFS_DATAVEC)
3771 {if (ecode < 2) rs = Response.Send();
3772 else rs = Response.Send((struct iovec *)eMsg, ecode);
3773 if (myError.getErrCB()) myError.getErrCB()->Done(ecode, &myError);
3774 if (myError.extData()) myError.Reset();
3775 return rs;
3776 }
3777
3778// Process the deferal
3779//
3780 if (rc >= SFS_STALL)
3781 {SI->stallCnt++;
3782 TRACEI(STALL, Response.ID() <<"stalling client for " <<rc <<" sec");
3783 rs = Response.Send(kXR_wait, rc, eMsg);
3784 if (myError.extData()) myError.Reset();
3785 return rs;
3786 }
3787
3788// Unknown conditions, report it
3789//
3790 {char buff[32];
3791 SI->errorCnt++;
3792 sprintf(buff, "%d", rc);
3793 eDest.Emsg("Xeq", "Unknown error code", buff, eMsg);
3794 rs = Response.Send(kXR_ServerError, eMsg);
3795 if (myError.extData()) myError.Reset();
3796 return rs;
3797 }
3798}
3799
3800/******************************************************************************/
3801/* f s O v r l d */
3802/******************************************************************************/
3803
3804int XrdXrootdProtocol::fsOvrld(char opC, const char *Path, char *Cgi)
3805{
3806 static const char *prot = "root://";
3807 static int negOne = -1;
3808 static char quest = '?', slash = '/';
3809
3810 struct iovec rdrResp[8];
3811 char *destP=0, dest[512];
3812 int iovNum=0, pOff, port;
3813
3814// If this is a forwarded path and the client can handle full url's then
3815// redirect the client to the destination in the path. Otherwise, if there is
3816// an alternate destination, send client there. Otherwise, stall the client.
3817//
3819 && (pOff = XrdOucUtils::isFWD(Path, &port, dest, sizeof(dest))))
3820 { rdrResp[1].iov_base = (char *)&negOne;
3821 rdrResp[1].iov_len = sizeof(negOne);
3822 rdrResp[2].iov_base = (char *)prot;
3823 rdrResp[2].iov_len = 7; // root://
3824 rdrResp[3].iov_base = (char *)dest;
3825 rdrResp[3].iov_len = strlen(dest); // host:port
3826 rdrResp[4].iov_base = (char *)&slash;
3827 rdrResp[4].iov_len = (*Path == '/' ? 1 : 0); // / or nil for objid
3828 rdrResp[5].iov_base = (char *)(Path+pOff);
3829 rdrResp[5].iov_len = strlen(Path+pOff); // path
3830 if (Cgi && *Cgi)
3831 {rdrResp[6].iov_base = (char *)&quest;
3832 rdrResp[6].iov_len = sizeof(quest); // ?
3833 rdrResp[7].iov_base = (char *)Cgi;
3834 rdrResp[7].iov_len = strlen(Cgi); // cgi
3835 iovNum = 8;
3836 } else iovNum = 6;
3837 destP = dest;
3838 } else if ((destP = Route[RD_ovld].Host[rdType]))
3839 port = Route[RD_ovld].Port[rdType];
3840
3841// If a redirect happened, then trace it.
3842//
3843 if (destP)
3844 {SI->redirCnt++;
3846 XrdXrootdMonitor::Redirect(Monitor.Did, destP, port,
3848 if (iovNum)
3849 {TRACEI(REDIR, Response.ID() <<"redirecting to "<<dest);
3850 return Response.Send(kXR_redirect, rdrResp, iovNum);
3851 } else {
3852 TRACEI(REDIR, Response.ID() <<"redirecting to "<<destP<<':'<<port);
3853 return Response.Send(kXR_redirect, port, destP);
3854 }
3855 }
3856
3857// If there is a stall value, then delay the client
3858//
3859 if (OD_Stall)
3860 {TRACEI(STALL, Response.ID()<<"stalling client for "<<OD_Stall<<" sec");
3861 SI->stallCnt++;
3862 return Response.Send(kXR_wait, OD_Stall, "server is overloaded");
3863 }
3864
3865// We were unsuccessful, return overload as an error
3866//
3867 return Response.Send(kXR_Overloaded, "server is overloaded");
3868}
3869
3870/******************************************************************************/
3871/* f s R e d i r N o E n t */
3872/******************************************************************************/
3873
3874int XrdXrootdProtocol::fsRedirNoEnt(const char *eMsg, char *Cgi, int popt)
3875{
3876 struct iovec ioV[4];
3877 char *tried, *trend, *ptried = 0;
3878 kXR_int32 pnum = htonl(static_cast<kXR_int32>(Route[popt].Port[rdType]));
3879 int tlen;
3880
3881// Try to find the last tried token in the cgi
3882//
3883 if ((trend = Cgi))
3884 {do {if (!(tried = strstr(Cgi, "tried="))) break;
3885 if (tried == trend || *(tried-1) == '&')
3886 {if (!ptried || (*(tried+6) && *(tried+6) != '&')) ptried=tried;}
3887 Cgi = index(tried+6, '&');
3888 } while(Cgi);
3889 }
3890
3891// If we did find a tried, bracket it out with a leading comma (we can modify
3892// the passed cgi string here because this is the last time it will be used.
3893//
3894 if ((tried = ptried))
3895 {tried += 5;
3896 while(*(tried+1) && *(tried+1) == ',') tried++;
3897 trend = index(tried, '&');
3898 if (trend) {tlen = trend - tried; *trend = 0;}
3899 else tlen = strlen(tried);
3900 *tried = ',';
3901 } else tlen = 0;
3902
3903// Check if we are in a redirect loop (i.e. we are listed in the client's cgi).
3904// If so, then treat this and file not found as we've been here before.
3905//
3906 if ((trend = tried) && eMsg)
3907 do {if ((trend = strstr(trend, myCName)))
3908 {if (*(trend+myCNlen) == '\0' || *(trend+myCNlen) == ',')
3909 return Response.Send(kXR_NotFound, eMsg);
3910 trend = index(trend+myCNlen, ',');
3911 }
3912 } while(trend);
3913
3914
3915// If we have not found a tried token or that token far too large to propogate
3916// (i.e. it's likely we have an undetected loop), then do a simple redirect.
3917//
3918 if (!tried || !tlen || tlen > 16384)
3919 return Response.Send(kXR_redirect,
3920 Route[popt].Port[rdType],
3921 Route[popt].Host[rdType]);
3922
3923// We need to append the client's tried list to the one we have to avoid loops
3924//
3925
3926 ioV[1].iov_base = (char *)&pnum;
3927 ioV[1].iov_len = sizeof(pnum);
3928 ioV[2].iov_base = Route[popt].Host[rdType];
3929 ioV[2].iov_len = Route[popt].RDSz[rdType];
3930 ioV[3].iov_base = tried;
3931 ioV[3].iov_len = tlen;
3932
3933// Compute total length
3934//
3935 tlen += sizeof(pnum) + Route[popt].RDSz[rdType];
3936
3937// Send off the redirect
3938//
3939 return Response.Send(kXR_redirect, ioV, 4, tlen);
3940}
3941
3942/******************************************************************************/
3943/* g e t B u f f */
3944/******************************************************************************/
3945
3946int XrdXrootdProtocol::getBuff(const int isRead, int Quantum)
3947{
3948
3949// Check if we need to really get a new buffer
3950//
3951 if (!argp || Quantum > argp->bsize) hcNow = hcPrev;
3952 else if (Quantum >= halfBSize || hcNow-- > 0) return 1;
3953 else if (hcNext >= hcMax) hcNow = hcMax;
3954 else {int tmp = hcPrev;
3955 hcNow = hcNext;
3956 hcPrev = hcNext;
3957 hcNext = tmp+hcNext;
3958 }
3959
3960// Get a new buffer
3961//
3962 if (argp) BPool->Release(argp);
3963 if ((argp = BPool->Obtain(Quantum))) halfBSize = argp->bsize >> 1;
3964 else return Response.Send(kXR_NoMemory, (isRead ?
3965 "insufficient memory to read file" :
3966 "insufficient memory to write file"));
3967
3968// Success
3969//
3970 return 1;
3971}
3972
3973/******************************************************************************/
3974/* Private: g e t C k s T y p e */
3975/******************************************************************************/
3976
3977char *XrdXrootdProtocol::getCksType(char *opaque, char *cspec, int cslen)
3978{
3979 char *cksT;
3980
3981// Get match for user specified checksum type, if any. Otherwise return default.
3982//
3983 if (opaque && *opaque)
3984 {XrdOucEnv jobEnv(opaque);
3985 if ((cksT = jobEnv.Get("cks.type")))
3986 {XrdOucTList *tP = JobCKTLST;
3987 while(tP && strcasecmp(tP->text, cksT)) tP = tP->next;
3988 if (!tP && cspec) snprintf(cspec, cslen, "%s", cksT);
3989 return (tP ? tP->text : 0);
3990 }
3991 }
3992
3993// Return default
3994//
3995 return JobCKT;
3996}
3997
3998/******************************************************************************/
3999/* Private: l o g L o g i n */
4000/******************************************************************************/
4001
4002bool XrdXrootdProtocol::logLogin(bool xauth)
4003{
4004 const char *uName, *ipName, *tMsg, *zMsg = "";
4005 char lBuff[512], pBuff[512];
4006
4007// Determine ip type
4008//
4010 ipName = (clientPV & XrdOucEI::uIPv64 ? "IP46" : "IPv4");
4011 else ipName = (clientPV & XrdOucEI::uIPv64 ? "IP64" : "IPv6");
4012
4013// Determine client name
4014//
4015 if (xauth) uName = (Client->name ? Client->name : "nobody");
4016 else uName = 0;
4017
4018// Check if TLS was or will be used
4019//
4020 tMsg = Link->verTLS();
4021 if (*tMsg) zMsg = " ";
4022
4023// Format the line
4024//
4025 snprintf(lBuff, sizeof(lBuff), "%s %s %s%slogin%s%s",
4026 (clientPV & XrdOucEI::uPrip ? "pvt" : "pub"), ipName,
4027 tMsg, zMsg,
4028 (xauth ? " as " : ""),
4029 (uName ? uName : ""));
4030
4031// Document the login
4032//
4033 if (Client->tident != Client->pident)
4034 {snprintf(pBuff, sizeof(pBuff), "via %s auth for %s",
4035 Client->prot, Client->pident);
4036 } else *pBuff = 0;
4037 eDest.Log(SYS_LOG_01, "Xeq", Link->ID, lBuff, (*pBuff ? pBuff : 0));
4038
4039// Enable TLS if we need to (note sess setting is off if login setting is on).
4040// If we need to but the client is not TLS capable, send an error and terminate.
4041//
4042 if ((doTLS & Req_TLSSess) && !Link->hasBridge())
4043 {if (ableTLS)
4044 {if (Link->setTLS(true, tlsCtx))
4045 {Link->setProtName("xroots");
4046 isTLS = true;
4047 } else {
4048 eDest.Emsg("Xeq", "Unable to require TLS for", Link->ID);
4049 return false;
4050 }
4051 } else {
4052 eDest.Emsg("Xeq","session requires TLS but",Link->ID,"is incapable.");
4053 Response.Send(kXR_TLSRequired, "session requires TLS support");
4054 return false;
4055 }
4056 }
4057
4058// Record the appname in the final SecEntity object
4059//
4060 if (AppName) Client->eaAPI->Add("xrd.appname", (std::string)AppName);
4061
4062// Assign unique identifier to the final SecEntity object
4063//
4064 Client->ueid = mySID;
4065
4066// Propogate a connect through the whole system
4067//
4068 osFS->Connect(Client);
4069 return true;
4070}
4071
4072/******************************************************************************/
4073/* m a p M o d e */
4074/******************************************************************************/
4075
4076#define Map_Mode(x,y) if (Mode & kXR_ ## x) newmode |= S_I ## y
4077
4078int XrdXrootdProtocol::mapMode(int Mode)
4079{
4080 int newmode = 0;
4081
4082// Map the mode in the obvious way
4083//
4084 Map_Mode(ur, RUSR); Map_Mode(uw, WUSR); Map_Mode(ux, XUSR);
4085 Map_Mode(gr, RGRP); Map_Mode(gw, WGRP); Map_Mode(gx, XGRP);
4086 Map_Mode(or, ROTH); Map_Mode(ox, XOTH);
4087
4088// All done
4089//
4090 return newmode;
4091}
4092
4093/******************************************************************************/
4094/* M o n A u t h */
4095/******************************************************************************/
4096
4098{
4099 char Buff[4096];
4100 const char *bP = Buff;
4101
4102 if (Client == &Entity) bP = Entity.moninfo;
4103 else {snprintf(Buff,sizeof(Buff),
4104 "&p=%s&n=%s&h=%s&o=%s&r=%s&g=%s&m=%s%s&I=%c",
4105 Client->prot,
4106 (Client->name ? Client->name : ""),
4107 (Client->host ? Client->host : ""),
4108 (Client->vorg ? Client->vorg : ""),
4109 (Client->role ? Client->role : ""),
4110 (Client->grps ? Client->grps : ""),
4111 (Client->moninfo ? Client->moninfo : ""),
4112 (Entity.moninfo ? Entity.moninfo : ""),
4113 (clientPV & XrdOucEI::uIPv4 ? '4' : '6')
4114 );
4115 Client->secMon = &Monitor;
4116 }
4117
4118 Monitor.Report(bP);
4119 if (Entity.moninfo) {free(Entity.moninfo); Entity.moninfo = 0;}
4120}
4121
4122/******************************************************************************/
4123/* r p C h e c k */
4124/******************************************************************************/
4125
4126int XrdXrootdProtocol::rpCheck(char *fn, char **opaque)
4127{
4128 char *cp;
4129
4130 if (*fn != '/')
4131 {if (!(XPList.Opts() & XROOTDXP_NOSLASH)) return 1;
4132 if ( XPList.Opts() & XROOTDXP_NOCGI) {*opaque = 0; return 0;}
4133 }
4134
4135 if (!(cp = index(fn, '?'))) *opaque = 0;
4136 else {*cp = '\0'; *opaque = cp+1;
4137 if (!**opaque) *opaque = 0;
4138 }
4139
4140 if (*fn != '/') return 0;
4141
4142 while ((cp = index(fn, '/')))
4143 {fn = cp+1;
4144 if (fn[0] == '.' && fn[1] == '.' && fn[2] == '/') return 1;
4145 }
4146 return 0;
4147}
4148
4149/******************************************************************************/
4150/* r p E m s g */
4151/******************************************************************************/
4152
4153int XrdXrootdProtocol::rpEmsg(const char *op, char *fn)
4154{
4155 char buff[2048];
4156 snprintf(buff,sizeof(buff)-1,"%s relative path '%s' is disallowed.",op,fn);
4157 buff[sizeof(buff)-1] = '\0';
4158 return Response.Send(kXR_NotAuthorized, buff);
4159}
4160
4161/******************************************************************************/
4162/* S e t S F */
4163/******************************************************************************/
4164
4165int XrdXrootdProtocol::SetSF(kXR_char *fhandle, bool seton)
4166{
4167 XrdXrootdFHandle fh(fhandle);
4168 XrdXrootdFile *theFile;
4169
4170 if (!FTab || !(theFile = FTab->Get(fh.handle))) return -EBADF;
4171
4172// Turn it off or on if so wanted
4173//
4174 if (!seton) theFile->sfEnabled = 0;
4175 else if (theFile->fdNum >= 0) theFile->sfEnabled = 1;
4176
4177// All done
4178//
4179 return 0;
4180}
4181
4182/******************************************************************************/
4183/* S q u a s h */
4184/******************************************************************************/
4185
4186int XrdXrootdProtocol::Squash(char *fn)
4187{
4188 char *ofn, *ifn = fn;
4189
4190 if (*fn != '/') return XPList.Opts();
4191
4192 while(*ifn)
4193 {if (*ifn == '/')
4194 if (*(ifn+1) == '/'
4195 || (*(ifn+1) == '.' && *(ifn+1) && *(ifn+2) == '/')) break;
4196 ifn++;
4197 }
4198
4199 if (!*ifn) return XPList.Validate(fn, ifn-fn);
4200
4201 ofn = ifn;
4202 while(*ifn) {*ofn = *ifn++;
4203 while(*ofn == '/')
4204 {while(*ifn == '/') ifn++;
4205 if (ifn[0] == '.' && ifn[1] == '/') ifn += 2;
4206 else break;
4207 }
4208 ofn++;
4209 }
4210 *ofn = '\0';
4211
4212 return XPList.Validate(fn, ofn-fn);
4213}
4214
4215/******************************************************************************/
4216/* v p E m s g */
4217/******************************************************************************/
4218
4219int XrdXrootdProtocol::vpEmsg(const char *op, char *fn)
4220{
4221 char buff[2048];
4222 snprintf(buff,sizeof(buff)-1,"%s path '%s' is disallowed.",op,fn);
4223 buff[sizeof(buff)-1] = '\0';
4224 return Response.Send(kXR_NotAuthorized, buff);
4225}
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_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:101
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