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