XRootD
XrdSsiFileSess.cc
Go to the documentation of this file.
1 /******************************************************************************/
2 /* */
3 /* X r d S s i F i l e S e s s . c c */
4 /* */
5 /* (c) 2016 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 <fcntl.h>
31 #include <stddef.h>
32 #include <cstdio>
33 #include <cstring>
34 #include <arpa/inet.h>
35 #include <sys/types.h>
36 #include <sys/stat.h>
37 #include <sys/uio.h>
38 
39 #include "XrdNet/XrdNetAddrInfo.hh"
40 
41 #include "XrdOuc/XrdOucBuffer.hh"
42 #include "XrdOuc/XrdOucEnv.hh"
43 #include "XrdOuc/XrdOucERoute.hh"
44 #include "XrdOuc/XrdOucPList.hh"
45 
46 #include "XrdSec/XrdSecEntity.hh"
47 
48 #include "XrdSfs/XrdSfsAio.hh"
49 
50 #include "XrdSsi/XrdSsiEntity.hh"
51 #include "XrdSsi/XrdSsiFileSess.hh"
52 #include "XrdSsi/XrdSsiProvider.hh"
53 #include "XrdSsi/XrdSsiRRInfo.hh"
54 #include "XrdSsi/XrdSsiService.hh"
55 #include "XrdSsi/XrdSsiSfs.hh"
56 #include "XrdSsi/XrdSsiStats.hh"
57 #include "XrdSsi/XrdSsiStream.hh"
58 #include "XrdSsi/XrdSsiTrace.hh"
59 #include "XrdSsi/XrdSsiUtils.hh"
60 
61 #include "XrdSys/XrdSysE2T.hh"
62 #include "XrdSys/XrdSysError.hh"
63 
64 /******************************************************************************/
65 /* G l o b a l s */
66 /******************************************************************************/
67 
68 namespace XrdSsi
69 {
70 extern XrdOucBuffPool *BuffPool;
71 extern XrdSsiProvider *Provider;
73 extern XrdSsiStats Stats;
74 extern XrdSysError Log;
75 extern int respWT;
76 extern int minRSZ;
77 extern int maxRSZ;
78 }
79 
80 using namespace XrdSsi;
81 
82 /******************************************************************************/
83 /* L o c a l M a c r o s */
84 /******************************************************************************/
85 
86 #define DUMPIT(x,y) XrdSsiUtils::b2x(x,y,hexBuff,sizeof(hexBuff),dotBuff)<<dotBuff
87 
88 /******************************************************************************/
89 /* L o c a l C l a s s e s */
90 /******************************************************************************/
91 
92 namespace
93 {
94 class nullCallBack : public XrdOucEICB
95 {
96 public:
97 
98 void Done(int &Result, XrdOucErrInfo *eInfo, const char *Path=0) {}
99 
100 int Same(unsigned long long arg1, unsigned long long arg2) {return 0;}
101 
102  nullCallBack() {}
103 virtual ~nullCallBack() {}
104 };
105 
106 nullCallBack nullCB;
107 };
108 
109 /******************************************************************************/
110 /* S t a t i c M e m b e r s */
111 /******************************************************************************/
112 
113 XrdSysMutex XrdSsiFileSess::arMutex;
114 XrdSsiFileSess *XrdSsiFileSess::freeList = 0;
115 int XrdSsiFileSess::freeNum = 0;
116 int XrdSsiFileSess::freeNew = 0;
117 int XrdSsiFileSess::freeMax = 100;
118 int XrdSsiFileSess::freeAbs = 200;
119 
120 bool XrdSsiFileSess::authDNS = false;
121 
122 /******************************************************************************/
123 /* A l l o c */
124 /******************************************************************************/
125 
127 {
128  XrdSsiFileSess *fsP;
129 
130 // Get a lock
131 //
132  arMutex.Lock();
133 
134 // Get either a reuseable object or a new one
135 //
136  if ((fsP = freeList))
137  {freeNum--;
138  freeList = fsP->nextFree;
139  arMutex.UnLock();
140  fsP->Init(einfo, user, true);
141  } else {
142  freeNew++;
143  if (freeMax <= freeAbs && freeNew >= freeMax/2)
144  {freeMax += freeMax/2;
145  freeNew = 0;
146  }
147  arMutex.UnLock();
148  fsP = new XrdSsiFileSess(einfo, user);
149  }
150 
151 // Return the object
152 //
153  return fsP;
154 }
155 
156 /******************************************************************************/
157 /* A t t n I n f o */
158 /******************************************************************************/
159 
161  unsigned int reqID)
162 // Called with the request mutex locked!
163 {
164  EPNAME("AttnInfo");
165  struct AttnResp {struct iovec ioV[4]; XrdSsiRRInfoAttn aHdr;};
166 
167  AttnResp *attnResp;
168  char *mBuff;
169  int n, ioN = 2;
170  bool doFin;
171 
172 // If there is no data we can send back to the client in the attn response,
173 // then simply reply with a short message to make the client come back.
174 //
175  if (!respP->mdlen)
176  {if (respP->rType != XrdSsiRespInfo::isData
177  || respP->blen > XrdSsiResponder::MaxDirectXfr)
178  {eInfo.setErrInfo(0, "");
179  return false;
180  }
181  }
182 
183 // We will be constructing the response in the message buffer. This is
184 // gauranteed to be big enough for our purposes so no need to check the size.
185 //
186  mBuff = eInfo.getMsgBuff(n);
187 
188 // Initialize the response
189 //
190  attnResp = (AttnResp *)mBuff;
191  memset(attnResp, 0, sizeof(AttnResp));
192  attnResp->aHdr.pfxLen = htons(sizeof(XrdSsiRRInfoAttn));
193 
194 // Fill out iovec to point to our header
195 //
196 //?attnResp->ioV[0].iov_len = sizeof(XrdSsiRRInfoAttn) + respP->mdlen;
197  attnResp->ioV[1].iov_base = mBuff+offsetof(struct AttnResp, aHdr);
198  attnResp->ioV[1].iov_len = sizeof(XrdSsiRRInfoAttn);
199 
200 // Fill out the iovec for the metadata if we have some
201 //
202  if (respP->mdlen)
203  {attnResp->ioV[2].iov_base = (void *)respP->mdata;
204  attnResp->ioV[2].iov_len = respP->mdlen; ioN = 3;
205  attnResp->aHdr.mdLen = htonl(respP->mdlen);
206  Stats.Bump(Stats.RspMDBytes, respP->mdlen);
207  if (QTRACE(Debug))
208  {char hexBuff[16],dotBuff[4];
209  DEBUG(reqID <<':' <<gigID <<' ' <<respP->mdlen <<" byte metadata (0x"
210  <<DUMPIT(respP->mdata,respP->mdlen) <<") sent.");
211  }
212  }
213 
214 // Check if we have actual data here as well and can send it along
215 //
216  if (respP->rType == XrdSsiRespInfo::isData
217  && respP->blen+respP->mdlen <= XrdSsiResponder::MaxDirectXfr)
218  {if (respP->blen)
219  {attnResp->ioV[ioN].iov_base = (void *)respP->buff;
220  attnResp->ioV[ioN].iov_len = respP->blen; ioN++;
221  }
222  attnResp->aHdr.tag = XrdSsiRRInfoAttn::fullResp; doFin = true;
223  }
224  else {attnResp->aHdr.tag = XrdSsiRRInfoAttn::pendResp; doFin = false;}
225 
226 // If we sent the full response we must remove the request from the request
227 // table as it will get finished off when the response is actually sent.
228 //
229  if (doFin) rTab.Del(reqID, false);
230 
231 // Setup to have metadata actually sent to the requestor
232 //
233  eInfo.setErrCode(ioN);
234  return doFin;
235 }
236 
237 /******************************************************************************/
238 /* c l o s e */
239 /******************************************************************************/
240 
241 int XrdSsiFileSess::close(bool viaDel)
242 /*
243  Function: Close the file object.
244 
245  Input: None
246 
247  Output: Always returns SFS_OK
248 */
249 {
250  const char *epname = "close";
251 
252 // Do some debugging
253 //
254  DEBUG((gigID ? gigID : "???") <<" del=" <<viaDel);
255 
256 // Collect statistics if this is a delete which implies a lost connection
257 //
258  if (viaDel)
259  {int rCnt = rTab.Num();
260  if (rCnt) Stats.Bump(Stats.ReqFinForce, rCnt);
261  }
262 
263 // Run through all outstanding requests and comlete them
264 //
265  rTab.Reset();
266 
267 // Free any in-progress buffers
268 //
269  if (inProg)
270  {if (oucBuff) {oucBuff->Recycle(); oucBuff = 0;}
271  inProg = false;
272  }
273 
274 // Clean up storage
275 //
276  isOpen = false;
277  return SFS_OK;
278 }
279 
280 /******************************************************************************/
281 /* f c t l */
282 /******************************************************************************/
283 
284 int XrdSsiFileSess::fctl(const int cmd,
285  int alen,
286  const char *args,
287  const XrdSecEntity *client)
288 {
289  static const char *epname = "fctl";
290  XrdSsiRRInfo *rInfo;
291  XrdSsiFileReq *rqstP;
292  unsigned int reqID;
293 
294 // If this isn't the special query, then return an error
295 //
296  if (cmd != SFS_FCTL_SPEC1)
297  return XrdSsiUtils::Emsg(epname, ENOTSUP, "fctl", gigID, *eInfo);
298 
299 // Caller wishes to find out if a request is ready and wait if it is not
300 //
301  if (!args || alen < (int)sizeof(XrdSsiRRInfo))
302  return XrdSsiUtils::Emsg(epname, EINVAL, "fctl", gigID, *eInfo);
303 
304 // Grab the request identifier
305 //
306  rInfo = (XrdSsiRRInfo *)args;
307  reqID = rInfo->Id();
308 
309 // Do some debugging
310 //
311  DEBUG(reqID <<':' <<gigID <<" query resp status");
312 
313 // Find the request
314 //
315  if (!(rqstP = rTab.LookUp(reqID)))
316  return XrdSsiUtils::Emsg(epname, ESRCH, "fctl", gigID, *eInfo);
317 
318 // Check if a response is waiting for the caller
319 //
320  if (rqstP->WantResponse(*eInfo))
321  {DEBUG(reqID <<':' <<gigID <<" resp ready");
323  return SFS_DATAVEC;
324  }
325 
326 // Put this client into callback state
327 //
328  DEBUG(reqID <<':' <<gigID <<" resp not ready");
329  eInfo->setErrCB((XrdOucEICB *)rqstP);
330  eInfo->setErrInfo(respWT, "");
332  return SFS_STARTED;
333 }
334 
335 /******************************************************************************/
336 /* Private: I n i t */
337 /******************************************************************************/
338 
339 void XrdSsiFileSess::Init(XrdOucErrInfo &einfo, const char *user, bool forReuse)
340 {
341  tident = (user ? strdup(user) : strdup(""));
342  eInfo = &einfo;
343  gigID = 0;
344  fsUser = 0;
345  xioP = 0;
346  oucBuff = 0;
347  reqSize = 0;
348  reqLeft = 0;
349  isOpen = false;
350  inProg = false;
351  if (forReuse)
352  {eofVec.Reset();
353  rTab.Clear();
354  }
355 }
356 
357 /******************************************************************************/
358 /* Private: N e w R e q u e s t */
359 /******************************************************************************/
360 
361 bool XrdSsiFileSess::NewRequest(unsigned int reqid,
362  XrdOucBuffer *oP,
363  XrdSfsXioHandle bR,
364  int rSz)
365 {
366  XrdSsiFileReq *reqP;
367 
368 // Allocate a new request object
369 //
370  if (!(reqP=XrdSsiFileReq::Alloc(eInfo,&fileResource,this,gigID,tident,reqid)))
371  return false;
372 
373 // Add it to the table
374 //
375  rTab.Add(reqP, reqid);
376 
377 // Activate the request
378 //
379  inProg = false;
380  reqP->Activate(oP, bR, rSz);
381  return true;
382 }
383 
384 /******************************************************************************/
385 /* o p e n */
386 /******************************************************************************/
387 
388 int XrdSsiFileSess::open(const char *path, // In
389  XrdOucEnv &theEnv, // In
390  XrdSfsFileOpenMode open_mode) // In
391 /*
392  Function: Open the file `path' in the mode indicated by `open_mode'.
393 
394  Input: path - The fully qualified name of the resource.
395  theEnv - Environmental information.
396  open_mode - It must contain only SFS_O_RDWR.
397 
398  Output: Returns SFS_OK upon success, otherwise SFS_ERROR is returned.
399 */
400 {
401  static const char *epname = "open";
402  XrdSsiErrInfo errInfo;
403  const char *eText;
404  int eNum;
405 
406 // Verify that this object is not already associated with an open file
407 //
408  if (isOpen)
409  return XrdSsiUtils::Emsg(epname, EADDRINUSE, "open session", path, *eInfo);
410 
411 // Make sure the open flag is correct (we now open this R/O so don't check)
412 //
413 // if (open_mode != SFS_O_RDWR)
414 // return XrdSsiUtils::Emsg(epname, EPROTOTYPE, "open session", path, *eInfo);
415 
416 // Setup the file resource object
417 //
418  fileResource.Init(path, theEnv, authDNS);
419 
420 // Notify the provider that we will be executing a request
421 //
422  if (Service->Prepare(errInfo, fileResource))
423  {const char *usr = fileResource.rUser.c_str();
424  if (!(*usr)) gigID = strdup(path);
425  else {char gBuff[2048];
426  snprintf(gBuff, sizeof(gBuff), "%s:%s", usr, path);
427  gigID = strdup(gBuff);
428  }
429  DEBUG(gigID <<" prepared.");
430  isOpen = true;
431  return SFS_OK;
432  }
433 
434 // Get error information
435 //
436  eText = errInfo.Get(eNum).c_str();
437  if (!eNum)
438  {eNum = ENOMSG; eText = "Provider returned invalid prepare response.";}
439 
440 // Decode the error
441 //
442  switch(eNum)
443  {case EAGAIN:
444  if (!eText || !(*eText)) break;
445  eNum = errInfo.GetArg();
446  DEBUG(path <<" --> " <<eText <<':' <<eNum);
447  eInfo->setErrInfo(eNum, eText);
449  return SFS_REDIRECT;
450  break;
451  case EBUSY:
452  eNum = errInfo.GetArg();
453  if (!eText || !(*eText)) eText = "Provider is busy.";
454  DEBUG(path <<" dly " <<eNum <<' ' <<eText);
455  if (eNum <= 0) eNum = 1;
456  eInfo->setErrInfo(eNum, eText);
458  return eNum;
459  break;
460  default:
461  if (!eText || !(*eText)) eText = XrdSysE2T(eNum);
462  DEBUG(path <<" err " <<eNum <<' ' <<eText);
463  eInfo->setErrInfo(eNum, eText);
465  return SFS_ERROR;
466  break;
467  };
468 
469 // Something is quite wrong here
470 //
471  Log.Emsg(epname, "Provider redirect returned no target host name!");
472  eInfo->setErrInfo(ENOMSG, "Server logic error");
474  return SFS_ERROR;
475 }
476 
477 /******************************************************************************/
478 /* r e a d */
479 /******************************************************************************/
480 
482  char *buff, // Out
483  XrdSfsXferSize blen) // In
484 /*
485  Function: Read `blen' bytes at `offset' into 'buff' and return the actual
486  number of bytes read.
487 
488  Input: offset - Contains request information.
489  buff - Address of the buffer in which to place the data.
490  blen - The size of the buffer. This is the maximum number
491  of bytes that will be returned.
492 
493  Output: Returns the number of bytes read upon success and SFS_ERROR o/w.
494 */
495 {
496  static const char *epname = "read";
497  XrdSsiRRInfo rInfo(offset);
498  XrdSsiFileReq *rqstP;
499  XrdSfsXferSize retval;
500  unsigned int reqID = rInfo.Id();
501  bool noMore = false;
502 
503 // Find the request object. If not there we may have encountered an eof
504 //
505  if (!(rqstP = rTab.LookUp(reqID)))
506  {if (eofVec.IsSet(reqID))
507  {eofVec.UnSet(reqID);
508  return 0;
509  }
510  return XrdSsiUtils::Emsg(epname, ESRCH, "read", gigID, *eInfo);
511  }
512 
513 // Simply effect the read via the request object
514 //
515  retval = rqstP->Read(noMore, buff, blen);
516 
517 // See if we just completed this request
518 //
519  if (noMore)
520  {rqstP->Finalize();
521  rTab.Del(reqID);
522  eofVec.Set(reqID);
523  }
524 
525 // All done
526 //
527  return retval;
528 }
529 
530 /******************************************************************************/
531 /* R e c y c l e */
532 /******************************************************************************/
533 
535 {
536 
537 // Do an immediate reset on ourselves to avoid getting too many locks
538 //
539  Reset();
540 
541 // Get a lock
542 //
543  arMutex.Lock();
544 
545 // Check if we should place this on the free list or simply delete it
546 //
547  if (freeNum < freeMax)
548  {nextFree = freeList;
549  freeList = this;
550  freeNum++;
551  arMutex.UnLock();
552  } else {
553  arMutex.UnLock();
554  delete this;
555  }
556 }
557 
558 /******************************************************************************/
559 /* Private: R e s e t */
560 /******************************************************************************/
561 
562 void XrdSsiFileSess::Reset()
563 {
564 
565 // Close this session
566 //
567  if (isOpen) close(true);
568 
569 // Release other buffers
570 //
571  if (tident) free(tident);
572  if (fsUser) free(fsUser);
573  if (gigID) free(gigID);
574 }
575 
576 /******************************************************************************/
577 /* S e n d D a t a */
578 /******************************************************************************/
579 
581  XrdSfsFileOffset offset,
582  XrdSfsXferSize size)
583 {
584  static const char *epname = "SendData";
585  XrdSsiRRInfo rInfo(offset);
586  XrdSsiFileReq *rqstP;
587  unsigned int reqID = rInfo.Id();
588  int rc;
589 
590 // Find the request object
591 //
592  if (!(rqstP = rTab.LookUp(reqID)))
593  return XrdSsiUtils::Emsg(epname, ESRCH, "send", gigID, *eInfo);
594 
595 // Simply effect the send via the request object
596 //
597  rc = rqstP->Send(sfDio, size);
598 
599 // Determine how this ended
600 //
601  if (rc > 0) rc = SFS_OK;
602  else {rqstP->Finalize();
603  rTab.Del(reqID);
604  }
605  return rc;
606 }
607 
608 /******************************************************************************/
609 /* t r u n c a t e */
610 /******************************************************************************/
611 
613 /*
614  Function: Set the length of the file object to 'flen' bytes.
615 
616  Input: flen - The new size of the file.
617 
618  Output: Returns SFS_ERROR a this function is not supported.
619 */
620 {
621  static const char *epname = "trunc";
622  XrdSsiFileReq *rqstP;
623  XrdSsiRRInfo rInfo(flen);
624  XrdSsiRRInfo::Opc reqXQ = rInfo.Cmd();
625  unsigned int reqID = rInfo.Id();
626 
627 // Find the request object. If not there we may have encountered an eof
628 //
629  if (!(rqstP = rTab.LookUp(reqID)))
630  {if (eofVec.IsSet(reqID))
631  {eofVec.UnSet(reqID);
632  return 0;
633  }
634  return XrdSsiUtils::Emsg(epname, ESRCH, "cancel", gigID, *eInfo);
635  }
636 
637 // Process request (this can only be a cancel request)
638 //
639  if (reqXQ != XrdSsiRRInfo::Can)
640  return XrdSsiUtils::Emsg(epname, ENOTSUP, "trunc", gigID, *eInfo);
641 
642 // Perform the cancellation
643 //
644  DEBUG(reqID <<':' <<gigID <<" cancelled");
645  rqstP->Finalize();
646  rTab.Del(reqID);
647  return SFS_OK;
648 }
649 
650 /******************************************************************************/
651 /* w r i t e */
652 /******************************************************************************/
653 
655  const char *buff, // In
656  XrdSfsXferSize blen) // In
657 /*
658  Function: Write `blen' bytes at `offset' from 'buff' and return the actual
659  number of bytes written.
660 
661  Input: offset - The absolute byte offset at which to start the write.
662  buff - Address of the buffer from which to get the data.
663  blen - The size of the buffer. This is the maximum number
664  of bytes that will be written to 'fd'.
665 
666  Output: Returns the number of bytes written upon success and SFS_ERROR o/w.
667 
668  Notes: An error return may be delayed until the next write(), close(), or
669  sync() call.
670 */
671 {
672  static const char *epname = "write";
673  XrdSsiRRInfo rInfo(offset);
674  unsigned int reqID = rInfo.Id();
675  int reqPass;
676 
677 // Check if we are reading a request segment and handle that. This assumes that
678 // writes to different requests cannot be interleaved (which they can't be).
679 //
680  if (inProg) return writeAdd(buff, blen, reqID);
681 
682 // Make sure this request does not refer to an active request
683 //
684  if (rTab.LookUp(reqID))
685  return XrdSsiUtils::Emsg(epname, EADDRINUSE, "write", gigID, *eInfo);
686 
687 // The offset contains the actual size of the request, make sure it's OK. Note
688 // that it can be zero and by convention the blen must be one if so.
689 //
690  reqPass = reqSize = rInfo.Size();
691  if (reqSize < blen)
692  {if (reqSize || blen != 1)
693  return XrdSsiUtils::Emsg(epname, EPROTO, "write", gigID, *eInfo);
694  reqSize = 1;
695  } else if (reqSize < 0 || reqSize > maxRSZ)
696  return XrdSsiUtils::Emsg(epname, EFBIG, "write", gigID, *eInfo);
697 
698 // Indicate we are in the progress of collecting the request arguments
699 //
700  inProg = true;
701  eofVec.UnSet(reqID);
702 
703 // Do some debugging
704 //
705  DEBUG(reqID <<':' <<gigID <<" rsz=" <<reqSize <<" wsz=" <<blen);
706 
707 // If the complete request is here then grab the buffer, transfer ownership to
708 // the request object, and then activate it for processing.
709 //
710  if (reqSize == blen && xioP)
711  {XrdSfsXioHandle bRef = xioP->Claim(buff, reqSize, minRSZ);
712  if (!bRef)
713  {if (errno) Log.Emsg(epname,"Xio.Claim() failed;",XrdSysE2T(errno));}
714  else {if (!NewRequest(reqID, 0, bRef, reqPass))
715  return XrdSsiUtils::Emsg(epname,ENOMEM,"write xio",gigID,*eInfo);
716  return blen;
717  }
718  }
719 
720 // The full request is not present, so get a buffer to piece it together
721 //
722  if (!(oucBuff = BuffPool->Alloc(reqSize)))
723  return XrdSsiUtils::Emsg(epname, ENOMEM, "write alloc", gigID, *eInfo);
724 
725 // Setup to buffer this
726 //
727  reqLeft = reqSize - blen;
728  memcpy(oucBuff->Data(), buff, blen);
729  if (!reqLeft)
730  {oucBuff->SetLen(reqSize);
731 
732  if (!NewRequest(reqID, oucBuff, 0, reqPass))
733  return XrdSsiUtils::Emsg(epname, ENOMEM, "write sfs", gigID, *eInfo);
734  oucBuff = 0;
735  } else oucBuff->SetLen(blen, blen);
736  return blen;
737 }
738 
739 /******************************************************************************/
740 /* Private: w r i t e A d d */
741 /******************************************************************************/
742 
743 XrdSfsXferSize XrdSsiFileSess::writeAdd(const char *buff, // In
744  XrdSfsXferSize blen, // In
745  unsigned int rid)
746 /*
747  Function: Add `blen' bytes from 'buff' to request and return the actual
748  number of bytes added.
749 
750  Input: buff - Address of the buffer from which to get the data.
751  blen - The size of the buffer. This is the maximum number
752  of bytes that will be added.
753 
754  Output: Returns the number of bytes added upon success and SFS_ERROR o/w.
755 
756  Notes: An error return may be delayed until the next write(), close(), or
757  sync() call.
758 */
759 {
760  static const char *epname = "writeAdd";
761  int dlen;
762 
763 // Make sure the caller is not exceeding the size stated on the first write
764 //
765  if (blen > reqLeft)
766  return XrdSsiUtils::Emsg(epname, EFBIG, "writeAdd", gigID, *eInfo);
767 
768 // Append the bytes
769 //
770  memcpy(oucBuff->Data(dlen), buff, blen);
771 
772 // Adjust how much we have left
773 //
774  reqLeft -= blen;
775  DEBUG(rid <<':' <<gigID <<" rsz=" <<reqLeft <<" wsz=" <<blen);
776 
777 // If we have a complete request. Transfer the buffer ownership to the request
778 // object and activate processing.
779 //
780  if (!reqLeft)
781  {oucBuff->SetLen(reqSize);
782  if (!NewRequest(rid, oucBuff, 0, reqSize))
783  return XrdSsiUtils::Emsg(epname, ENOMEM, "write", gigID, *eInfo);
784  oucBuff = 0;
785  } else {
786  dlen += blen;
787  oucBuff->SetLen(dlen, dlen);
788  }
789 
790 // Return how much we appended
791 //
792  return blen;
793 }
#define tident
#define DEBUG(x)
Definition: XrdBwmTrace.hh:54
#define EPNAME(x)
Definition: XrdBwmTrace.hh:56
#define QTRACE(act)
Definition: XrdCmsTrace.hh:49
#define close(a)
Definition: XrdPosix.hh:43
XrdOucString Path
#define SFS_DATAVEC
#define SFS_ERROR
#define SFS_REDIRECT
#define SFS_STARTED
int XrdSfsFileOpenMode
#define SFS_FCTL_SPEC1
#define SFS_OK
long long XrdSfsFileOffset
int XrdSfsXferSize
class XrdBuffer * XrdSfsXioHandle
Definition: XrdSfsXio.hh:46
#define DUMPIT(x, y)
const char * XrdSysE2T(int errcode)
Definition: XrdSysE2T.cc:104
XrdOucBuffer * Alloc(int sz)
int setErrInfo(int code, const char *emsg)
char * getMsgBuff(int &mblen)
void Reset()
Reset object to no message state. Call this method to release appendages.
int setErrCode(int code)
void Bump(int &val)
Definition: XrdOucStats.hh:47
int GetArg() const
const std::string & Get(int &eNum) const
bool WantResponse(XrdOucErrInfo &eInfo)
XrdSfsXferSize Read(bool &done, char *buffer, XrdSfsXferSize blen)
int Send(XrdSfsDio *sfDio, XrdSfsXferSize size)
static XrdSsiFileReq * Alloc(XrdOucErrInfo *eP, XrdSsiFileResource *rP, XrdSsiFileSess *fP, const char *sn, const char *id, unsigned int rnum)
void Activate(XrdOucBuffer *oP, XrdSfsXioHandle bR, int rSz)
int fctl(const int cmd, int alen, const char *args, const XrdSecEntity *client)
int open(const char *fileName, XrdOucEnv &theEnv, XrdSfsFileOpenMode openMode)
int close(bool viaDel=false)
XrdSfsXferSize write(XrdSfsFileOffset fileOffset, const char *buffer, XrdSfsXferSize buffer_size)
bool AttnInfo(XrdOucErrInfo &eInfo, const XrdSsiRespInfo *respP, unsigned int reqID)
XrdSfsXferSize read(XrdSfsFileOffset fileOffset, char *buffer, XrdSfsXferSize buffer_size)
int truncate(XrdSfsFileOffset fileOffset)
int SendData(XrdSfsDio *sfDio, XrdSfsFileOffset offset, XrdSfsXferSize size)
static XrdSsiFileSess * Alloc(XrdOucErrInfo &einfo, const char *user)
void Size(unsigned int sz)
Definition: XrdSsiRRInfo.hh:60
void Cmd(Opc cmd)
Definition: XrdSsiRRInfo.hh:45
void Id(unsigned int id)
Definition: XrdSsiRRInfo.hh:52
static const int MaxDirectXfr
virtual bool Prepare(XrdSsiErrInfo &eInfo, const XrdSsiResource &rDesc)
Prepare for processing subsequent resource request.
long long RspMDBytes
Definition: XrdSsiStats.hh:42
static int Emsg(const char *pfx, int ecode, const char *op, const char *path, XrdOucErrInfo &eDest)
Definition: XrdSsiUtils.cc:159
int Emsg(const char *esfx, int ecode, const char *text1, const char *text2=0)
Definition: XrdSysError.cc:95
XrdOucEnv theEnv
XrdSsiStats Stats
XrdSsiProvider * Provider
XrdOucBuffPool * BuffPool
XrdSsiService * Service
XrdSysError Log
static const int fullResp
Definition: XrdSsiRRInfo.hh:92
static const int pendResp
Definition: XrdSsiRRInfo.hh:93
int mdlen
Metadata length.
const char * mdata
-> Metadata about response.