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