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