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