XRootD
Loading...
Searching...
No Matches
XrdXrootdProtocol.cc
Go to the documentation of this file.
1/******************************************************************************/
2/* */
3/* X r d X r o o t d P r o t o c o l . 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 <poll.h>
31
32#include "XrdVersion.hh"
33
35
36#include "Xrd/XrdBuffer.hh"
37#include "Xrd/XrdLink.hh"
38#include "XrdNet/XrdNetIF.hh"
39#include "XrdOuc/XrdOucEnv.hh"
40#include "XrdOuc/XrdOucUtils.hh"
43#include "XrdOuc/XrdOucUtils.hh"
45#include "XrdSfs/XrdSfsFlags.hh"
48#include "XrdSys/XrdSysTimer.hh"
49#include "XrdTls/XrdTls.hh"
61
62/******************************************************************************/
63/* G l o b a l s */
64/******************************************************************************/
65
66namespace XrdXrootd
67{
68XrdSysError eLog(0, "Xrootd");
72}
73
75
76/******************************************************************************/
77/* S t a t i c M e m b e r s */
78/******************************************************************************/
79
100
102const char *XrdXrootdProtocol::myCName= 0;
109int XrdXrootdProtocol::redirIPHold = 8*60*60; // 8 Hours
114
115int XrdXrootdProtocol::hcMax = 28657; // const for now
117int XrdXrootdProtocol::maxTransz = 262144; // 256KB
120int XrdXrootdProtocol::as_maxperlnk = 8; // Max ops per link
121int XrdXrootdProtocol::as_maxperreq = 8; // Max ops per request
122int XrdXrootdProtocol::as_maxpersrv = 4096;// Max ops per server
126#ifdef __solaris__
128#else
130#endif
132short XrdXrootdProtocol::as_okstutter = 1; // For 64K unit
134bool XrdXrootdProtocol::as_force = false;
136bool XrdXrootdProtocol::as_nosf = false;
137bool XrdXrootdProtocol::as_syncw = false;
138
139const char *XrdXrootdProtocol::myInst = 0;
140const char *XrdXrootdProtocol::TraceID = "Protocol";
142int XrdXrootdProtocol::myPID = static_cast<int>(getpid());
143
146
151const char *XrdXrootdProtocol::myGName= "?";
152const char *XrdXrootdProtocol::myUName= "?";
153time_t XrdXrootdProtocol::keepT = 86400; // 24 hours
154
158
163bool XrdXrootdProtocol::OD_Redir = false;
164
165bool XrdXrootdProtocol::CL_Redir = false;
166
167bool XrdXrootdProtocol::isProxy = false;
168
172
175
177
178/******************************************************************************/
179/* P r o t o c o l M a n a g e m e n t S t a c k s */
180/******************************************************************************/
181
183 XrdXrootdProtocol::ProtStack("ProtStack",
184 "xroot protocol anchor");
185
186/******************************************************************************/
187/* P r o t o c o l L o a d e r */
188/* X r d g e t P r o t o c o l */
189/******************************************************************************/
190
191// This protocol can live in a shared library. The interface below is used by
192// the protocol driver to obtain a copy of the protocol object that can be used
193// to decide whether or not a link is talking a particular protocol.
194//
196
197extern "C"
198{
199XrdProtocol *XrdgetProtocol(const char *pname, char *parms,
201{
202 XrdProtocol *pp = 0;
203 const char *txt = "completed.";
204
205// Put up the banner
206//
207 pi->eDest->Say("Copr. 2012 Stanford University, xroot protocol "
208 kXR_PROTOCOLVSTRING, " version ", XrdVERSION);
209 pi->eDest->Say("++++++ xroot protocol initialization started.");
210
211// Return the protocol object to be used if static init succeeds
212//
213 if (XrdXrootdProtocol::Configure(parms, pi))
214 pp = (XrdProtocol *)new XrdXrootdProtocol();
215 else txt = "failed.";
216 pi->eDest->Say("------ xroot protocol initialization ", txt);
217 return pp;
218}
219}
220
221/******************************************************************************/
222/* P r o t o c o l P o r t D e t e r m i n a t i o n */
223/* X r d g e t P r o t o c o l P o r t */
224/******************************************************************************/
225
226// This function is called early on to determine the port we need to use. The
227// default is ostensibly 1094 but can be overridden; which we allow.
228//
230
231extern "C"
232{
233int XrdgetProtocolPort(const char *pname, char *parms, XrdProtocol_Config *pi)
234{
235
236// Figure out what port number we should return. In practice only one port
237// number is allowed. However, we could potentially have a clustered port
238// and several unclustered ports. So, we let this practicality slide.
239//
240 if (pi->Port < 0) return 1094;
241 return pi->Port;
242}
243}
244
245/******************************************************************************/
246/* X r d P r o t o c o l X r o o t d C l a s s */
247/******************************************************************************/
248
249namespace
250{
253}
254
255/******************************************************************************/
256/* C o n s t r u c t o r */
257/******************************************************************************/
258
260 : XrdProtocol("xroot protocol handler"),
261 XrdSfsXio(SfsXioImpl),
262 ProtLink(this), Entity(0), AppName(0)
263{
264 Reset();
265}
266
267/******************************************************************************/
268/* protected: g e t S I D */
269/******************************************************************************/
270
272{
273 static XrdSysMutex SidMutex;
274 static unsigned int Sid = 1;
275 unsigned int theSid;
276
277// Generate unqiue number for this server instance
278//
279 AtomicBeg(SidMutex);
280 theSid = AtomicInc(Sid);
281 AtomicEnd(SidMutex);
282 return theSid;
283}
284
285/******************************************************************************/
286/* M a t c h */
287/******************************************************************************/
288
289#define TRACELINK lp
290
292{
293static const int hsSZ = sizeof(ClientInitHandShake);
294 char hsbuff[hsSZ];
295 struct ClientInitHandShake *hsData = (ClientInitHandShake *)hsbuff;
296
297static struct hs_response
298 {kXR_unt16 streamid;
299 kXR_unt16 status;
300 kXR_unt32 rlen; // Specified as kXR_int32 in doc!
301 kXR_unt32 pval; // Specified as kXR_int32 in doc!
302 kXR_unt32 styp; // Specified as kXR_int32 in doc!
303 } hsresp={0, 0, htonl(8), htonl(kXR_PROTOCOLVERSION),
304 (isRedir ? htonl((unsigned int)kXR_LBalServer)
305 : htonl((unsigned int)kXR_DataServer))};
307int dlen, rc;
308
309// Peek at the first 20 bytes of data
310//
311 if ((dlen = lp->Peek(hsbuff, hsSZ, hailWait)) < hsSZ)
312 {if (dlen <= 0) lp->setEtext("handshake not received");
313 return (XrdProtocol *)0;
314 }
315
316// Trace the data
317//
318// TRACEI(REQ, "received: " <<Trace->bin2hex(hsbuff,dlen));
319
320// Verify that this is our protocol
321//
322 hsData->fourth = ntohl(hsData->fourth);
323 hsData->fifth = ntohl(hsData->fifth);
324 if (hsData->first || hsData->second || hsData->third
325 || hsData->fourth != 4 || hsData->fifth != ROOTD_PQ) return 0;
326
327// Send the handshake response. We used optimize the subsequent protocol
328// request sent with handshake but the protocol request is now overloaded.
329//
330 rc = lp->Send((char *)&hsresp, sizeof(hsresp));
331
332// Verify that our handshake response was actually sent
333//
334 if (!rc)
335 {lp->setEtext("handshake failed");
336 return (XrdProtocol *)0;
337 }
338
339// We can now read all 20 bytes and discard them (no need to wait for it)
340//
341 if (lp->Recv(hsbuff, hsSZ) != hsSZ)
342 {lp->setEtext("reread failed");
343 return (XrdProtocol *)0;
344 }
345
346// Get a protocol object off the stack (if none, allocate a new one)
347//
348 if (!(xp = ProtStack.Pop())) xp = new XrdXrootdProtocol();
349
350// Bind the protocol to the link and return the protocol
351//
352 SI->Bump(SI->Count);
353 xp->Link = lp;
354 xp->Response.Set(lp);
355 strcpy(xp->Entity.prot, "host");
356 xp->Entity.host = (char *)lp->Host();
357 xp->Entity.addrInfo = lp->AddrInfo();
358 return (XrdProtocol *)xp;
359}
360
361/******************************************************************************/
362/* P r o c e s s */
363/******************************************************************************/
364
365#undef TRACELINK
366#define TRACELINK Link
367
368int XrdXrootdProtocol::Process(XrdLink *lp) // We ignore the argument here
369{
370 int rc;
371 kXR_unt16 reqID;
372
373// Check if we are servicing a slow link
374//
375 if (Resume)
376 {if (myBlen && (rc = getData("data", myBuff, myBlen)) != 0) return rc;
377 else if ((rc = (*this.*Resume)()) != 0) return rc;
378 else {Resume = 0; return 0;}
379 }
380
381// Read the next request header
382//
383 if ((rc=getData("request",(char *)&Request,sizeof(Request))) != 0) return rc;
384
385// Check if we need to copy the request prior to unmarshalling it
386//
387 reqID = ntohs(Request.header.requestid);
388 if (reqID != kXR_sigver && NEED2SECURE(Protect)(Request))
389 {memcpy(&sigReq2Ver, &Request, sizeof(ClientRequest));
390 sigNeed = true;
391 }
392
393// Deserialize the data
394//
395 Request.header.requestid = reqID;
396 Request.header.dlen = ntohl(Request.header.dlen);
397 Response.Set(Request.header.streamid);
398 TRACEP(REQ, "req=" <<XProtocol::reqName(reqID)
399 <<" dlen=" <<Request.header.dlen);
400
401// Every request has an associated data length. It better be >= 0 or we won't
402// be able to know how much data to read.
403//
404 if (Request.header.dlen < 0)
405 {Response.Send(kXR_ArgInvalid, "Invalid request data length");
406 return Link->setEtext("protocol data length error");
407 }
408
409// Process sigver requests now as they appear ahead of a request
410//
411 if (reqID == kXR_sigver) return ProcSig();
412
413// Read any argument data at this point, except when the request is a write.
414// The argument may have to be segmented and we're not prepared to do that here.
415//
416 if (reqID != kXR_write && reqID != kXR_pgwrite && Request.header.dlen)
417 {if (!argp || Request.header.dlen+1 > argp->bsize)
418 {if (argp) BPool->Release(argp);
419 if (!(argp = BPool->Obtain(Request.header.dlen+1)))
420 {Response.Send(kXR_ArgTooLong, "Request argument is too long");
421 return 0;
422 }
423 hcNow = hcPrev; halfBSize = argp->bsize >> 1;
424 }
425 argp->buff[Request.header.dlen] = '\0';
426 if ((rc = getData("arg", argp->buff, Request.header.dlen)))
427 {Resume = &XrdXrootdProtocol::Process2; return rc;}
428 }
429
430// Continue with request processing at the resume point
431//
432 return Process2();
433}
434
435/******************************************************************************/
436/* p r i v a t e P r o c e s s 2 */
437/******************************************************************************/
438
440{
441// If we are verifying requests, see if this request needs to be verified
442//
443 if (sigNeed)
444 {const char *eText = "Request not signed";
445 if (!sigHere || (eText = Protect->Verify(sigReq,sigReq2Ver,argp->buff)))
446 {Response.Send(kXR_SigVerErr, eText);
447 TRACEP(REQ, "req=" <<XProtocol::reqName(Request.header.requestid)
448 <<" verification failed; " <<eText);
449 SI->Bump(SI->badSCnt);
450 return Link->setEtext(eText);
451 } else {
452 SI->Bump(SI->aokSCnt);
453 sigNeed = sigHere = false;
454 }
455 } else {
456 if (sigHere)
457 {TRACEP(REQ, "req=" <<XProtocol::reqName(Request.header.requestid)
458 <<" unneeded signature discarded.");
459 if (sigWarn)
460 {eDest.Emsg("Protocol","Client is needlessly signing requests.");
461 sigWarn = false;
462 }
463 SI->Bump(SI->ignSCnt);
464 sigHere = false;
465 }
466 }
467
468// If the user is not yet logged in, restrict what the user can do
469//
470 if (!Status)
471 switch(Request.header.requestid)
472 {case kXR_login: return do_Login();
473 case kXR_protocol: return do_Protocol();
474 case kXR_bind: return do_Bind();
475 default: Response.Send(kXR_InvalidRequest,
476 "Invalid request; user not logged in");
477 return Link->setEtext("request without login");
478 }
479
480// Help the compiler, select the the high activity requests (the ones with
481// file handles) in a separate switch statement. A special case exists for
482// sync() which return with a callback, so handle it here. Note that stat(fh)
483// normally never does a callback but historically we allowed it to do so.
484// We maintain that capability even when it's likely never used.
485//
486 switch(Request.header.requestid) // First, the ones with file handles
487 {case kXR_read: return do_Read();
488 case kXR_readv: return do_ReadV();
489 case kXR_write: return do_Write();
490 case kXR_writev: return do_WriteV();
491 case kXR_pgread: return do_PgRead();
492 case kXR_pgwrite: return do_PgWrite();
493 case kXR_sync: ReqID.setID(Request.header.streamid);
494 return do_Sync();
495 case kXR_close: ReqID.setID(Request.header.streamid);
496 return do_Close();
497 case kXR_stat: if (!Request.header.dlen)
498 {ReqID.setID(Request.header.streamid);
499 return do_Stat();
500 }
501 break;
502 case kXR_truncate: ReqID.setID(Request.header.streamid);
503 if (!Request.header.dlen) return do_Truncate();
504 break;
505 case kXR_query: if (!Request.header.dlen) return do_Qfh();
506 break;
507 case kXR_chkpoint: return do_ChkPnt();
508 default: break;
509 }
510
511// Now select the requests that do not need authentication
512//
513 switch(Request.header.requestid)
514 {case kXR_protocol: return do_Protocol(); // dlen ignored
515 case kXR_ping: return do_Ping(); // dlen ignored
516 default: break;
517 }
518
519// Force authentication at this point, if need be
520//
521 if (Status & XRD_NEED_AUTH)
522 {int rc;
523 if (Request.header.requestid == kXR_auth) rc = do_Auth();
524 else {Response.Send(kXR_InvalidRequest,
525 "Invalid request; user not authenticated");
526 rc = -1;
527 }
529 return rc;
530 }
531
532// Construct request ID as the following functions are async eligible
533//
534 ReqID.setID(Request.header.streamid);
535
536// Process items that don't need arguments but may have them
537//
538 switch(Request.header.requestid)
539 {case kXR_endsess: return do_Endsess();
540 default: break;
541 }
542
543// All remaining requests require an argument. Make sure we have one
544//
545 if (!argp || !Request.header.dlen)
546 {Response.Send(kXR_ArgMissing, "Required argument not present");
547 return 0;
548 }
549
550// All of the subsequent requests can be redirected and are subject to
551// prefunctory redirection which we check here.
552//
553 if (CL_Redir && !Link->hasBridge())
554 {bool doRdr = false;
555 if (Link->AddrInfo()->isPrivate()) rdType = 1;
556 if (RouteClient.pvtIP && rdType) doRdr = true;
557 else if (RouteClient.lclDom && XrdNetIF::InDomain( Link->AddrInfo()))
558 doRdr = true;
559 else if (RouteClient.DomCnt)
560 {XrdOucString hName = Link->Host();
561 for (int i = 0; i < RouteClient.DomCnt; i++)
562 {if (hName.endswith(RouteClient.Domain[i]))
563 {doRdr = true; break;}
564 }
565 }
566 if (doRdr)
567 {Response.Send(kXR_redirect,Route[RD_client].Port[rdType],
568 Route[RD_client].Host[rdType]);
569 return -1;
570 }
571 }
572
573// Process items that keep own statistics
574//
575 switch(Request.header.requestid)
576 {case kXR_open: return do_Open();
577 case kXR_gpfile: return do_gpFile();
578 default: break;
579 }
580
581// Update misc stats count
582//
583 SI->Bump(SI->miscCnt);
584
585// Now process whatever we have
586//
587 switch(Request.header.requestid)
588 {case kXR_chmod: return do_Chmod();
589 case kXR_dirlist: return do_Dirlist();
590 case kXR_fattr: return do_FAttr();
591 case kXR_locate: return do_Locate();
592 case kXR_mkdir: return do_Mkdir();
593 case kXR_mv: return do_Mv();
594 case kXR_query: return do_Query();
595 case kXR_prepare: return do_Prepare();
596 case kXR_rm: return do_Rm();
597 case kXR_rmdir: return do_Rmdir();
598 case kXR_set: return do_Set();
599 case kXR_stat: return do_Stat();
600 case kXR_statx: return do_Statx();
601 case kXR_truncate: return do_Truncate();
602 default: break;
603 }
604
605// Whatever we have, it's not valid
606//
607 Response.Send(kXR_InvalidRequest, "Invalid request code");
608 return 0;
609}
610
611/******************************************************************************/
612/* P r o c S i g */
613/******************************************************************************/
614
616{
617 int rc;
618
619// Check if we completed reading the signature and if so, we are done
620//
621 if (sigRead)
622 {sigRead = false;
623 sigHere = true;
624 return 0;
625 }
626
627// Verify that the hash is not longer that what we support and is present
628//
629 if (Request.header.dlen <= 0
630 || Request.header.dlen > (int)sizeof(sigBuff))
631 {Response.Send(kXR_ArgInvalid, "Invalid signature data length");
632 return Link->setEtext("signature data length error");
633 }
634
635// Save relevant information for the next round
636//
637 memcpy(&sigReq, &Request, sizeof(ClientSigverRequest));
638 sigReq.header.dlen = htonl(Request.header.dlen);
639
640// Now read in the signature
641//
642 sigRead = true;
643 if ((rc = getData("arg", sigBuff, Request.header.dlen)))
644 {Resume = &XrdXrootdProtocol::ProcSig; return rc;}
645 sigRead = false;
646
647// All done
648//
649 sigHere = true;
650 return 0;
651}
652
653/******************************************************************************/
654/* R e c y c l e */
655/******************************************************************************/
656
657#undef TRACELINK
658#define TRACELINK Link
659
660void XrdXrootdProtocol::Recycle(XrdLink *lp, int csec, const char *reason)
661{
662 char *sfxp, ctbuff[24], buff[128], Flags = (reason ? XROOTD_MON_FORCED : 0);
663 const char *What;
664 XrdSysMutexHelper recycleHelper(unbindMutex);
665
666// Check for disconnect or unbind
667//
668 if (Status == XRD_BOUNDPATH) {What = "unbind"; Flags |= XROOTD_MON_BOUNDP;}
669 else What = "disc";
670
671// Document the disconnect or undind
672//
673 if (lp)
674 {XrdSysTimer::s2hms(csec, ctbuff, sizeof(ctbuff));
675 if (reason && strcmp(reason, "hangup"))
676 {snprintf(buff, sizeof(buff), "%s (%s)", ctbuff, reason);
677 sfxp = buff;
678 } else sfxp = ctbuff;
679
680 eDest.Log(SYS_LOG_02, "Xeq", lp->ID, (char *)What, sfxp);
681 }
682
683// Handle any waiting read on this link. This is a tricky proposition because
684// we don't know if the thread is waiting to run or not. However, we will
685// indicate that gdFail was already called and should the thread run, it will
686// promptly exit should it ever run again. That way, we handle the cleanup.
687//
688 if (gdCtl.linkWait.fetch_or(GetDataCtl::Terminate) == GetDataCtl::Active
689 && (gdCtl.Status == GetDataCtl::inData
690 || gdCtl.Status == GetDataCtl::inDataIov)) gdCtl.CallBack->gdFail();
691
692// If this is a bound stream then we cannot release the resources until
693// all activity ceases on this stream (i.e., lp == 0). This is only relevant for
694// writes that read from the link. if we are still tagged as active and not
695// waiting for link activity then ask to be signalled once activity stops.
696// Otherwise, redrive the parallel I/O so that it cleans up.
697//
698 if (lp && Status == XRD_BOUNDPATH)
699 {streamMutex.Lock();
700 isNOP = true;
701 if (isActive)
702 {if (isLinkWT)
703 {streamMutex.UnLock();
704 do_OffloadIO();
705 } else {
706 while(isActive)
707 {XrdSysCondVar2 aioDone(streamMutex);
708 endNote = &aioDone;
709 aioDone.Wait();
710 endNote = 0;
711 }
712 streamMutex.UnLock();
713 }
714 } else streamMutex.UnLock();
715 boundRecycle->Post();
716 if (lp) return; // Async close
717 }
718
719// Release all appendages
720//
721 Cleanup();
722
723// If we are monitoring logins then we are also monitoring disconnects. We do
724// this after cleanup so that close records can be generated before we cut a
725// disconnect record. This then requires we clear the monitor object here.
726// We and the destrcutor are the only ones who call cleanup and a deletion
727// will call the monitor clear method. So, we won't leak memeory.
728//
729 if (Monitor.Logins()) Monitor.Agent->Disc(Monitor.Did, csec, Flags);
730 if (Monitor.Fstat() ) XrdXrootdMonFile::Disc(Monitor.Did);
731 Monitor.Clear();
732
733// Set fields to starting point (debugging mostly)
734//
735 Reset();
736
737// Push ourselves on the stack
738//
739 if (Response.isOurs()) ProtStack.Push(&ProtLink);
740}
741
742/******************************************************************************/
743/* S t a t G e n */
744/******************************************************************************/
745
746int XrdXrootdProtocol::StatGen(struct stat &buf, char *xxBuff, int xxLen,
747 bool xtnd)
748{
749 const mode_t isReadable = (S_IRUSR | S_IRGRP | S_IROTH);
750 const mode_t isWritable = (S_IWUSR | S_IWGRP | S_IWOTH);
751 const mode_t isExecable = (S_IXUSR | S_IXGRP | S_IXOTH);
752 uid_t theuid;
753 gid_t thegid;
754 union {long long uuid; struct {int hi; int lo;} id;} Dev;
755 long long fsz;
756 int m, n, flags = 0;
757
758// Get the right uid/gid
759//
760 theuid = (Client && Client->uid ? Client->uid : myUID);
761 thegid = (Client && Client->gid ? Client->gid : myGID);
762
763// Compute the unique id
764//
765 Dev.id.lo = buf.st_ino;
766 Dev.id.hi = buf.st_dev;
767
768// Compute correct setting of the readable flag
769//
770 if (buf.st_mode & isReadable
771 &&((buf.st_mode & S_IRUSR && theuid == buf.st_uid)
772 || (buf.st_mode & S_IRGRP && thegid == buf.st_gid)
773 || buf.st_mode & S_IROTH)) flags |= kXR_readable;
774
775// Compute correct setting of the writable flag
776//
777 if (buf.st_mode & isWritable
778 &&((buf.st_mode & S_IWUSR && theuid == buf.st_uid)
779 || (buf.st_mode & S_IWGRP && thegid == buf.st_gid)
780 || buf.st_mode & S_IWOTH)) flags |= kXR_writable;
781
782// Compute correct setting of the execable flag
783//
784 if (buf.st_mode & isExecable
785 &&((buf.st_mode & S_IXUSR && theuid == buf.st_uid)
786 || (buf.st_mode & S_IXGRP && thegid == buf.st_gid)
787 || buf.st_mode & S_IXOTH)) flags |= kXR_xset;
788
789// Compute the other flag settings
790//
791 if (!Dev.uuid) flags |= kXR_offline;
792 if (S_ISDIR(buf.st_mode)) flags |= kXR_isDir;
793 else if (!S_ISREG(buf.st_mode)) flags |= kXR_other;
794 else{if (buf.st_mode & XRDSFS_POSCPEND) flags |= kXR_poscpend;
795 if ((buf.st_rdev & XRDSFS_RDVMASK) == 0)
796 {if (buf.st_rdev & XRDSFS_OFFLINE) flags |= kXR_offline;
797 if (buf.st_rdev & XRDSFS_HASBKUP) flags |= kXR_bkpexist;
798 }
799 }
800 if ((fsFeatures & XrdSfs::hasCACH) != 0 && buf.st_atime != 0)
801 flags |= kXR_cachersp;
802 fsz = static_cast<long long>(buf.st_size);
803
804// Format the default response: <devid> <size> <flags> <mtime>
805//
806 m = snprintf(xxBuff, xxLen, "%lld %lld %d %lld",
807 Dev.uuid, fsz, flags, (long long) buf.st_mtime);
808// if (!xtnd || m >= xxLen) return xxLen;
809//
810
811// Format extended response: <ctime> <atime> <mode>
812//
813 char *origP = xxBuff;
814 char *nullP = xxBuff + m++;
815 xxBuff += m; xxLen -= m;
816 n = snprintf(xxBuff, xxLen, "%lld %lld %04o ",
817 (long long) buf.st_ctime, (long long) buf.st_atime,
818 buf.st_mode&07777);
819 if (n >= xxLen) return m;
820 xxBuff += n; xxLen -= n;
821
822// Tack on owner
823//
824 if (buf.st_uid == myUID)
825 {if (myUNLen >= xxLen) return m;
826 strcpy(xxBuff, myUName);
827 n = myUNLen;
828 } else {
829 if (!(n = XrdOucUtils::UidName(buf.st_uid,xxBuff,xxLen,keepT))) return m;
830 }
831 xxBuff += n;
832 *xxBuff++ = ' ';
833 xxLen -= (n+1);
834
835// Tack on group
836//
837 if (buf.st_gid == myGID)
838 {if (myGNLen >= xxLen) return m;
839 strcpy(xxBuff, myGName);
840 n = myGNLen;
841 } else {
842 if (!(n = XrdOucUtils::GidName(buf.st_gid,xxBuff,xxLen,keepT))) return m;
843 }
844 xxBuff += n+1;
845
846// All done, return full response
847//
848 *nullP = ' ';
849 return xxBuff - origP;
850}
851
852/******************************************************************************/
853/* S t a t s */
854/******************************************************************************/
855
856int XrdXrootdProtocol::Stats(char *buff, int blen, int do_sync)
857{
858// Synchronize statistics if need be
859//
860 if (do_sync)
861 {SI->statsMutex.Lock();
862 SI->readCnt += numReads;
863 cumReads += numReads; numReads = 0;
864 SI->prerCnt += numReadP;
865 cumReadP += numReadP; numReadP = 0;
866
867 SI->rvecCnt += numReadV;
868 cumReadV += numReadV; numReadV = 0;
869 SI->rsegCnt += numSegsV;
870 cumSegsV += numSegsV; numSegsV = 0;
871
872 SI->wvecCnt += numWritV;
873 cumWritV += numWritV; numWritV = 0;
874 SI->wsegCnt += numSegsW;
875 cumSegsW += numSegsW, numSegsW = 0;
876
877 SI->writeCnt += numWrites;
879 SI->statsMutex.UnLock();
880 }
881
882// Now return the statistics
883//
884 return SI->Stats(buff, blen, do_sync);
885}
886
887/******************************************************************************/
888/* X r d S f s X i o M e t h o d s */
889/******************************************************************************/
890/******************************************************************************/
891/* Static: B u f f e r */
892/******************************************************************************/
893
895{
896 XrdBuffer *xbP = (XrdBuffer *)h;
897
898 if (h)
899 {if (bsz) *bsz = xbP->bsize;
900 return xbP->buff;
901 }
902 if (bsz) *bsz = 0;
903 return 0;
904}
905
906/******************************************************************************/
907/* C l a i m */
908/******************************************************************************/
909
910XrdSfsXioHandle XrdXrootdProtocol::Claim(const char *buff, int datasz,
911 int minasz)
912{
913
914// Qualify swap choice
915//
916 if (minasz >= argp->bsize || datasz >= argp->bsize/2) return Swap(buff);
917 errno = 0;
918 return 0;
919}
920
921/******************************************************************************/
922/* Static: R e c l a i m */
923/******************************************************************************/
924
926{
927
928 if (h) BPool->Release((XrdBuffer *)h);
929}
930
931/******************************************************************************/
932/* S t r e a m N O P */
933/******************************************************************************/
934
936{
937
938// Mark this stream as not operation if it is not the control strea,
939//
940 if (PathID)
941 {streamMutex.Lock();
942 isNOP = true;
943 streamMutex.UnLock();
944 }
945}
946
947/******************************************************************************/
948/* S w a p */
949/******************************************************************************/
950
952{
953 XrdBuffer *oldBP = argp;
954
955// Verify the context and linkage and if OK, swap buffers
956//
957 if (Request.header.requestid != kXR_write) errno = ENOTSUP;
958 else if (buff != argp->buff) errno = EINVAL;
959 else {if (h)
960 {argp = (XrdBuffer *)h;
961 return oldBP;
962 } else {
963 argp = BPool->Obtain(argp->bsize);
964 if (argp) return oldBP;
965 argp = oldBP;
966 errno = ENOBUFS;
967 }
968 }
969 return 0;
970}
971
972/******************************************************************************/
973/* V e r i f y S t r e a m */
974/******************************************************************************/
975
977{
979
980// Verify that the path actually exists
981//
982 if (pID >= maxStreams || !(pp = Stream[pID]))
983 {rc = Response.Send(kXR_ArgInvalid, "invalid path ID");
984 return 0;
985 }
986
987// Verify that this path is still functional
988//
989 pp->streamMutex.Lock();
990 if (pp->isNOP)
991 {pp->streamMutex.UnLock();
992 rc = Response.Send(kXR_ArgInvalid, "path ID is not operational");
993 return 0;
994 }
995
996// All done!
997//
998 if (!lok) pp->streamMutex.UnLock();
999 return pp;
1000}
1001
1002/******************************************************************************/
1003/* P r i v a t e M e t h o d s */
1004/******************************************************************************/
1005/******************************************************************************/
1006/* C h e c k S u m */
1007/******************************************************************************/
1008
1009int XrdXrootdProtocol::CheckSum(XrdOucStream *Stream, char **argv, int argc)
1010{
1011 int rc, ecode;
1012
1013// The arguments must have <name> <cstype> <path> <tident> [name] (argc >= 4)
1014//
1015 if (argc < 4)
1016 {Stream->PutLine("Internal error; not enough checksum args!");
1017 return 8;
1018 }
1019
1020// Construct the error information
1021//
1022 XrdOucEnv myEnv;
1023 XrdOucErrInfo myInfo(argv[3], &myEnv);
1024
1025// Add username, if present
1026//
1027 if (argc > 4 && *argv[4]) myEnv.Put("request.name", argv[4]);
1028
1029// Issue the checksum calculation (that's all we do here).
1030//
1031 rc = osFS->chksum(XrdSfsFileSystem::csCalc, argv[1], argv[2], myInfo);
1032
1033// Return result regardless of what it is
1034//
1035 Stream->PutLine(myInfo.getErrText(ecode));
1036 if (rc) {SI->errorCnt++;
1037 if (ecode) rc = ecode;
1038 }
1039 return rc;
1040}
1041
1042/******************************************************************************/
1043/* C l e a n u p */
1044/******************************************************************************/
1045
1046void XrdXrootdProtocol::Cleanup()
1047{
1048 XrdXrootdPio *pioP;
1049 int i;
1050
1051// Handle parallel stream cleanup. The session stream cannot be closed if
1052// there is any queued activity on subordinate streams. A subordinate
1053// can either be closed from the session stream or asynchronously only if
1054// it is active. Which means they could be running while we are running.
1055// So, we first call RequestClose. If this returns true it will inhibit the
1056// asynchronous close and we call close(). Otherwise the asynchronous close
1057// already hapened. Either way we wait for the boundRecycle semaphore to
1058// confirm the first pass through Recycle (via close) and then we trigger
1059// the actual recycle of the object.
1060//
1061 if (Status != XRD_BOUNDPATH)
1062 {streamMutex.Lock();
1063 for (i = 1; i < maxStreams; i++)
1064 if (Stream[i])
1065 {Stream[i]->Stream[0] = 0;
1066 const bool doCl = Stream[i]->RequestClose();
1067 if (doCl) Stream[i]->Link->Close();
1068 Stream[i]->boundRecycle->Wait();
1069 Stream[i]->Recycle(0, 0, 0);
1070 Stream[i] = 0;
1071 }
1072 streamMutex.UnLock();
1073 }
1074
1075// Handle packet parking (needs to be done before deleting other stuff)
1076//
1077 if (pmHandle) delete pmHandle;
1078
1079// Release any internal monitoring information
1080//
1081 if (Entity.moninfo) {free(Entity.moninfo); Entity.moninfo = 0;}
1082
1083// If we have a buffer, release it
1084//
1085 if (argp) {BPool->Release(argp); argp = 0;}
1086
1087// Notify the filesystem of a disconnect prior to deleting file tables
1088//
1089 if (Status != XRD_BOUNDPATH) osFS->Disc(Client);
1090
1091// Handle parallel I/O appendages. We need to do this first as these have
1092// referenced open files and we need to deref them before we cleanup the ftab.
1093//
1094 while((pioP = pioFirst))
1095 {pioP->IO.File->Ref(-1); pioFirst = pioP->Next; pioP->Recycle();}
1096 while((pioP = pioFree )) {pioFree = pioP->Next; pioP->Recycle();}
1097
1098// Delete the FTab if we have it
1099//
1100 if (FTab)
1101 {FTab->Recycle(Monitor.Files() ? Monitor.Agent : 0);
1102 FTab = 0;
1103 }
1104
1105// Handle statistics
1106//
1107 SI->statsMutex.Lock();
1108 SI->readCnt += numReads; SI->writeCnt += numWrites;
1109 SI->statsMutex.UnLock();
1110
1111// Handle authentication protocol
1112//
1113 if (AuthProt) {AuthProt->Delete(); AuthProt = 0;}
1114 if (Protect) {Protect->Delete(); Protect = 0;}
1115
1116// Handle writev appendage
1117//
1118 if (wvInfo) {free(wvInfo); wvInfo = 0;}
1119
1120// Release aplication name
1121//
1122 if (AppName) {free(AppName); AppName = 0;}
1123
1124// Release the pagewrite control object
1125//
1126 if (pgwCtl) delete pgwCtl;
1127
1128// Release the recycle semaphore for bound connections
1129//
1130 if (boundRecycle) { delete boundRecycle; boundRecycle = 0; }
1131}
1132
1133/******************************************************************************/
1134/* g e t D a t a */
1135/******************************************************************************/
1136
1137int XrdXrootdProtocol::getData(const char *dtype, char *buff, int blen)
1138{
1139 int rlen;
1140
1141// Read the data but reschedule he link if we have not received all of the
1142// data within the timeout interval.
1143//
1144 rlen = Link->Recv(buff, blen, readWait);
1145 if (rlen < 0)
1146 {if (rlen != -ENOMSG) return Link->setEtext("link read error");
1147 else return -1;
1148 }
1149 if (rlen < blen)
1150 {myBuff = buff+rlen; myBlen = blen-rlen;
1151 TRACEP(REQ, dtype <<" timeout; read " <<rlen <<" of " <<blen <<" bytes");
1152 return 1;
1153 }
1154 return 0;
1155}
1156
1157/******************************************************************************/
1158
1160 const char *dtype, char *buff, int blen)
1161{
1162 bool inCB = (gdCtl.Status == GetDataCtl::inCallBk);
1163
1164// Setup the control information to direct the vector read
1165//
1166 memset((char *)&gdCtl, 0, sizeof(gdCtl));
1167 gdCtl.BuffLen = blen; // Buffer length (bytes to read)
1168 gdCtl.Buffer = buff; // The actual buffer
1169 gdCtl.CallBack= cbP; // Method to callback upon success
1170 gdCtl.ioDType = dtype; // Name of the data being read for tracing
1171 gdCtl.Status = GetDataCtl::inData;
1172
1173// Effect the read. We prevent recursive calls if this was called while
1174// we were in a callback, which is possible due to I/O continuations.
1175//
1176 if (inCB)
1177 {gdCtl.useCB = true;
1178 return 1;
1179 }
1180 return getDataCont();
1181}
1182
1183/******************************************************************************/
1184namespace {int consumed = 0;}
1185
1187 const char *dtype, struct iovec *iov, int iovn)
1188{
1189 bool inCB = (gdCtl.Status == GetDataCtl::inCallBk);
1190
1191// Setup the control information to direct the vector read
1192//
1193 memset((char *)&gdCtl, 0, sizeof(gdCtl));
1194 gdCtl.iovNum = iovn; // Number of original elements
1195 gdCtl.iovVec = iov; // The actual vector
1196 gdCtl.CallBack= cbP; // Method to callback upon success
1197 gdCtl.ioDType = dtype; // Name of the data being read for tracing
1199
1200// Effect the read. We prevent recursive calls if this was called while
1201// we were in a callback, which is possible due to I/O continuations.
1202//
1203 if (inCB)
1204 {gdCtl.useCB = true;
1205 return 1;
1206 }
1207consumed = 0;
1208 return getDataIovCont();
1209}
1210
1211/******************************************************************************/
1212/* g e t D a t a C o n t */
1213/******************************************************************************/
1214
1215int XrdXrootdProtocol::getDataCont()
1216{
1217 int rlen;
1218
1219// Check if we need to terminate because the link died or we can proceed.
1220//
1221 if (gdCtl.linkWait.fetch_and(0) == GetDataCtl::Terminate)
1222 return -EINPROGRESS;
1223
1224// I/O continuations may occur either via entry or an attempt to continue a new
1225// operation via the callback. This takes care of it here.
1226//
1227do{if ((rlen = Link->Recv(gdCtl.Buffer, gdCtl.BuffLen, readWait)) < 0) break;
1228 gdCtl.Buffer += rlen;
1229 gdCtl.BuffLen -= rlen;
1230
1231// If we completed the read then either return or use the callback. Note that
1232// we convert recursive call for more data into an iterative continuation.
1233//
1234 if (!gdCtl.BuffLen)
1235 {if (gdCtl.useCB)
1236 {gdCtl.Status = GetDataCtl::inCallBk;
1237 if (int(gdCtl.stalls) > as_okstutter)
1238 myStalls += int(gdCtl.stalls)/as_okstutter;
1239 rlen = gdCtl.CallBack->gdDone();
1240 if (rlen < 0) break;
1241 if (gdCtl.Status == GetDataCtl::inData) continue;
1242 if (gdCtl.Status == GetDataCtl::inDataIov) return getDataIovCont();
1243 if (gdCtl.Status == GetDataCtl::inDump) return getDumpCont();
1244 gdCtl.Status = GetDataCtl::inNone;
1245 return rlen;
1246 }
1247 gdCtl.Status = GetDataCtl::inNone;
1248 return 0;
1249 }
1250
1251// Make sure we don't have an over-run
1252//
1253 if (gdCtl.BuffLen < 0)
1254 {rlen = Link->setEtext("link excessive read length error");
1255 break;
1256 }
1257
1258// Record where we stopped and setup to resume here when more data arrives. We
1259// must set myBlen to zero to avoid calling the other GetData() method. We want
1260// to resume and perform the GetData() function here.
1261//
1262 Resume = &XrdXrootdProtocol::getDataCont;
1263 myBlen = 0;
1264 gdCtl.useCB = true;
1265 gdCtl.linkWait = GetDataCtl::Active;
1266 if (gdCtl.stalls < 255) gdCtl.stalls++;
1267
1268// Return indicating we need more data
1269//
1270 TRACEP(REQ, gdCtl.ioDType <<" timeout; read " <<rlen <<" bytes "
1271 <<gdCtl.BuffLen <<" remaining");
1272 return 1;
1273
1274 } while(true);
1275
1276// If got here then we had a link failure or some other fatal issue
1277//
1278 if (rlen != -ENOMSG) return Link->setEtext("link read error");
1279
1280// Use callback, if need be.
1281//
1282 if (gdCtl.useCB)
1283 {gdCtl.Status = GetDataCtl::inCallBk;
1284 gdCtl.CallBack->gdFail();
1285 }
1286 gdCtl.Status = GetDataCtl::inNone;
1287 return -1;
1288}
1289
1290/******************************************************************************/
1291/* g e t D a t I o v C o n t */
1292/******************************************************************************/
1293
1294int XrdXrootdProtocol::getDataIovCont()
1295{
1296 int rc;
1297
1298// Check if we need to terminate because the link died or we can proceed.
1299//
1300 if (gdCtl.linkWait.fetch_and(0) == GetDataCtl::Terminate)
1301 return -EINPROGRESS;
1302
1303// I/O continuations may occur either via entry or an attempt to continue a new
1304// operation via the callback. This takes care of it here.
1305//
1306do{struct iovec *ioV = gdCtl.iovVec;
1307 int i, rlen, iovN = gdCtl.iovNum, iNow = gdCtl.iovNow;
1308
1309// Read as much data as we can. Handle any link error. Note that when a link
1310// error occurs we return failure whether or not the callback wants to do more.
1311//
1312 rlen = Link->Recv(&ioV[iNow], iovN - iNow, readWait);
1313 if (rlen < 0)
1314 {if (rlen != -ENOMSG) Link->setEtext("link read error");
1315 if (gdCtl.iovAdj)
1316 {ioV[iNow].iov_base = ((char *)ioV[iNow].iov_base) - gdCtl.iovAdj;
1317 ioV[iNow].iov_len += gdCtl.iovAdj;
1318 gdCtl.iovAdj = 0;
1319 }
1320 rc = -1;
1321 break;
1322 }
1323
1324// Compute where we finished in the iovec.
1325//
1326 for (i = iNow; i < iovN && (int)ioV[i].iov_len <= rlen; i++)
1327 rlen -= ioV[i].iov_len;
1328
1329// Before proceeding, restore any changes we made to a completed iovec element
1330//
1331 if (i != iNow && gdCtl.iovAdj)
1332 {ioV[iNow].iov_base = ((char *)ioV[iNow].iov_base) - gdCtl.iovAdj;
1333 ioV[iNow].iov_len += gdCtl.iovAdj;
1334 gdCtl.iovAdj = 0;
1335 }
1336
1337// If the vector is complete then effect the callback unless this was the
1338// initial call, we simply return to prevent recursive continuations by
1339// converting a recursive call to an iterative continuation!
1340//
1341 if (i >= iovN)
1342 {if (!rlen)
1343 {if (gdCtl.useCB)
1344 {gdCtl.Status = GetDataCtl::inCallBk;
1345 if (int(gdCtl.stalls) > as_okstutter)
1346 myStalls += int(gdCtl.stalls)/as_okstutter;
1347 rc = gdCtl.CallBack->gdDone();
1348 if (rc < 0) break;
1349 if (gdCtl.Status == GetDataCtl::inDataIov) continue;
1350 if (gdCtl.Status == GetDataCtl::inDump) return getDumpCont();
1351 gdCtl.Status = GetDataCtl::inNone;
1352 return rc;
1353 }
1354 gdCtl.Status = GetDataCtl::inNone;
1355 return 0;
1356 }
1357 rc = Link->setEtext("link iov read length error");
1358 break;
1359 }
1360
1361// Record where we stopped and adjust the iovec element address and length if
1362// needed. Record the change made so that it can be undone as we progress.
1363//
1364 gdCtl.iovNow = i;
1365 if (rlen)
1366 {if (gdCtl.iovAdj == 0) gdCtl.iovNow = i;
1367 gdCtl.iovAdj += rlen;
1368 ioV[i].iov_base = ((char *)ioV[i].iov_base) + rlen;
1369 ioV[i].iov_len -= rlen;
1370 }
1371
1372// Setup to resume here when more data arrives. We must set myBlen to zero to
1373// avoid calling the other GetData() method as we want to resume here.
1374//
1375 Resume = &XrdXrootdProtocol::getDataIovCont;
1376 myBlen = 0;
1377 gdCtl.useCB = true;
1378 gdCtl.linkWait = GetDataCtl::Active;
1379 if (gdCtl.stalls < 255) gdCtl.stalls++;
1380
1381// Return indicating we need more data
1382//
1383 TRACEP(REQ, gdCtl.ioDType<<" read timeout; "<<iovN-i<<" of "
1384 <<gdCtl.iovNum <<" iov elements left");
1385 return 1;
1386
1387 } while(true);
1388
1389// If got here then we had a link failure or some other fatal issue
1390//
1391 if (gdCtl.useCB)
1392 {gdCtl.Status = GetDataCtl::inCallBk;
1393 gdCtl.CallBack->gdFail();
1394 }
1395 gdCtl.Status = GetDataCtl::inNone;
1396 return rc;
1397}
1398
1399/******************************************************************************/
1400/* g e t D u m p */
1401/******************************************************************************/
1402
1403int XrdXrootdProtocol::getDump(const char *dtype, int dlen)
1404{
1405 bool inCB = (gdCtl.Status == GetDataCtl::inCallBk);
1406
1407// Setup the control information to direct the vector read
1408//
1409 memset((char *)&gdCtl, 0, sizeof(gdCtl));
1410 gdCtl.DumpLen = dlen; // Bytes left to drain
1411 gdCtl.ioDType = dtype; // Name of the data being read for tracing
1412 gdCtl.Status = GetDataCtl::inDump;
1413
1414// Effect the read. We prevent recursive calls if this was called while
1415// we were in a callback, which is possible due to I/O continuations.
1416//
1417 return (inCB ? 1 : getDumpCont());
1418}
1419
1420/******************************************************************************/
1421/* Private: g e t D u m p C o n t */
1422/******************************************************************************/
1423
1424int XrdXrootdProtocol::getDumpCont()
1425{
1426 int rlen = 0, rwant;
1427 char buff[65536];
1428
1429 TRACEP(REQ, gdCtl.ioDType<<" discarding "<<gdCtl.DumpLen<<" bytes.");
1430
1431// Read data and discard it
1432//
1433 while(gdCtl.DumpLen > 0)
1434 {if (gdCtl.DumpLen <= (int)sizeof(buff)) rwant = gdCtl.DumpLen;
1435 else rwant = sizeof(buff);
1436 if ((rlen = Link->Recv(buff, rwant, readWait)) <= 0) break;
1437 gdCtl.DumpLen -= rlen;
1438 }
1439
1440// Check if we failed
1441//
1442 if (rlen < 0 || gdCtl.DumpLen < 0)
1443 {if (gdCtl.DumpLen < 0) Link->setEtext("link read overrun error");
1444 else if (rlen != -ENOMSG) Link->setEtext("link read error");
1445 gdCtl.Status = GetDataCtl::inNone;
1446 return -1;
1447 }
1448
1449// Check if we completed
1450//
1451 if (gdCtl.DumpLen == 0)
1452 {gdCtl.Status = GetDataCtl::inNone;
1453 return 0;
1454 }
1455
1456// Wait until more data arrives. We will now need to use the callback.
1457//
1458 Resume = &XrdXrootdProtocol::getDumpCont;
1459 myBlen = 0;
1460
1461 TRACEP(REQ, gdCtl.ioDType<<" read timeout; "<<gdCtl.DumpLen
1462 <<" bytes left to discard");
1463 return 1;
1464}
1465
1466/******************************************************************************/
1467/* R e s e t */
1468/******************************************************************************/
1469
1470void XrdXrootdProtocol::Reset()
1471{
1472 Status = 0;
1473 argp = 0;
1474 Link = 0;
1475 FTab = 0;
1476 pmHandle = 0;
1477 ResumePio = 0;
1478 Resume = 0;
1479 myBuff = (char *)&Request;
1480 myBlen = sizeof(Request);
1481 myBlast = 0;
1482 myStalls = 0;
1483 pgwCtl = 0;
1484 memset(&IO, 0, sizeof(IO));
1485 wvInfo = 0;
1486 numReads = 0;
1487 numReadP = 0;
1488 numReadV = 0;
1489 numSegsV = 0;
1490 numWritV = 0;
1491 numSegsW = 0;
1492 numWrites = 0;
1493 numFiles = 0;
1494 cumReads = 0;
1495 cumReadV = 0;
1496 cumSegsV = 0;
1497 cumWritV = 0;
1498 cumSegsW = 0;
1499 cumWrites = 0;
1500 totReadP = 0;
1501 hcPrev =13;
1502 hcNext =21;
1503 hcNow =13;
1504 Client = 0;
1505 AuthProt = 0;
1506 Protect = 0;
1507 mySID = 0;
1508 CapVer = 0;
1509 CloseRequested = false;
1510 clientPV = 0;
1511 clientRN = 0;
1512 pmDone = false;
1513 reTry = 0;
1514 boundRecycle = 0;
1515 endNote = 0;
1516 PathID = 0;
1517 newPio = false;
1518 rvSeq = 0;
1519 wvSeq = 0;
1520 doTLS = tlsNot; // Assume client is not capable. This will be
1521 ableTLS = false; // resolved during the kXR_protocol interchange.
1522 isTLS = false; // Made true when link converted to TLS
1523 linkAioReq = 0;
1524 pioFree = pioFirst = pioLast = 0;
1525 isActive = isLinkWT= isNOP = false;
1526 sigNeed = sigHere = sigRead = false;
1527 sigWarn = true;
1528 rdType = 0;
1529 Entity.Reset(0);
1530 memset(Stream, 0, sizeof(Stream));
1531 memset((char *)&gdCtl, 0, sizeof(gdCtl));
1532 PrepareCount = 0;
1533 if (AppName) {free(AppName); AppName = 0;}
1534}
1535
1536/******************************************************************************/
1537/* C l o s e R e q u e s t C b */
1538/******************************************************************************/
1539
1541{
1543 return pp->RequestClose();
1544}
1545
1546/******************************************************************************/
1547/* D o C l o s e R e q u e s t e d */
1548/******************************************************************************/
1549
1551{
1553 if (CloseRequested) return false;
1554 CloseRequested = true;
1555 return true;
1556}
@ kXR_ArgInvalid
Definition XProtocol.hh:990
@ kXR_InvalidRequest
Definition XProtocol.hh:996
@ kXR_ArgMissing
Definition XProtocol.hh:991
@ kXR_SigVerErr
@ kXR_ArgTooLong
Definition XProtocol.hh:992
@ kXR_redirect
Definition XProtocol.hh:904
#define kXR_PROTOCOLVSTRING
Definition XProtocol.hh:75
@ kXR_read
Definition XProtocol.hh:125
@ kXR_open
Definition XProtocol.hh:122
@ kXR_writev
Definition XProtocol.hh:143
@ kXR_readv
Definition XProtocol.hh:137
@ kXR_mkdir
Definition XProtocol.hh:120
@ kXR_sync
Definition XProtocol.hh:128
@ kXR_chmod
Definition XProtocol.hh:114
@ kXR_bind
Definition XProtocol.hh:136
@ kXR_dirlist
Definition XProtocol.hh:116
@ kXR_sigver
Definition XProtocol.hh:141
@ kXR_fattr
Definition XProtocol.hh:132
@ kXR_rm
Definition XProtocol.hh:126
@ kXR_query
Definition XProtocol.hh:113
@ kXR_write
Definition XProtocol.hh:131
@ kXR_gpfile
Definition XProtocol.hh:117
@ kXR_login
Definition XProtocol.hh:119
@ kXR_auth
Definition XProtocol.hh:112
@ kXR_endsess
Definition XProtocol.hh:135
@ kXR_set
Definition XProtocol.hh:130
@ kXR_rmdir
Definition XProtocol.hh:127
@ kXR_statx
Definition XProtocol.hh:134
@ kXR_truncate
Definition XProtocol.hh:140
@ kXR_protocol
Definition XProtocol.hh:118
@ kXR_mv
Definition XProtocol.hh:121
@ kXR_ping
Definition XProtocol.hh:123
@ kXR_stat
Definition XProtocol.hh:129
@ kXR_pgread
Definition XProtocol.hh:142
@ kXR_chkpoint
Definition XProtocol.hh:124
@ kXR_locate
Definition XProtocol.hh:139
@ kXR_close
Definition XProtocol.hh:115
@ kXR_pgwrite
Definition XProtocol.hh:138
@ kXR_prepare
Definition XProtocol.hh:133
@ kXR_faMaxVlen
Definition XProtocol.hh:282
@ kXR_faMaxNlen
Definition XProtocol.hh:281
#define kXR_LBalServer
#define kXR_PROTOCOLVERSION
Definition XProtocol.hh:70
#define kXR_DataServer
@ kXR_readable
@ kXR_isDir
@ kXR_offline
@ kXR_bkpexist
@ kXR_other
@ kXR_poscpend
@ kXR_writable
@ kXR_cachersp
@ kXR_xset
unsigned int kXR_unt32
Definition XPtypes.hh:90
unsigned short kXR_unt16
Definition XPtypes.hh:67
#define stat(a, b)
Definition XrdPosix.hh:101
XrdProtocol * XrdgetProtocol(const char *pname, char *parms, XrdProtocol_Config *pi)
int XrdgetProtocolPort(const char *pname, char *parms, XrdProtocol_Config *pi)
#define NEED2SECURE(protP)
This class implements the XRootD protocol security protection.
static const dev_t XRDSFS_HASBKUP
static const dev_t XRDSFS_RDVMASK
#define XRDSFS_POSCPEND
static const dev_t XRDSFS_OFFLINE
class XrdBuffer * XrdSfsXioHandle
Definition XrdSfsXio.hh:46
#define AtomicInc(x)
#define AtomicBeg(Mtx)
#define AtomicEnd(Mtx)
const int SYS_LOG_02
XrdSys::RAtomic< int > RAtomic_int
const kXR_char XROOTD_MON_BOUNDP
const kXR_char XROOTD_MON_FORCED
XrdVERSIONINFO(XrdgetProtocol, xrootd)
XrdProtocol * XrdgetProtocol(const char *pname, char *parms, XrdProtocol_Config *pi)
XrdSysTrace XrdXrootdTrace("Xrootd")
int XrdgetProtocolPort(const char *pname, char *parms, XrdProtocol_Config *pi)
#define ROOTD_PQ
#define XRD_BOUNDPATH
#define XRD_NEED_AUTH
#define TRACEP(act, x)
static const char * reqName(kXR_unt16 reqCode)
Definition XProtocol.cc:151
char * buff
Definition XrdBuffer.hh:45
static bool InDomain(XrdNetAddrInfo *epaddr)
Definition XrdNetIF.cc:606
void Put(const char *varname, const char *value)
Definition XrdOucEnv.hh:85
bool endswith(char c)
static int GidName(gid_t gID, char *gName, int gNsz, time_t keepT=0)
static int UidName(uid_t uID, char *uName, int uNsz, time_t keepT=0)
XrdSysError * eDest
XrdProtocol(const char *jname)
XrdNetAddrInfo * addrInfo
Entity's connection details.
char prot[XrdSecPROTOIDSIZE]
Auth protocol used (e.g. krb5)
char * host
Entity's host name dnr dependent.
XrdSfsXio(XrdSfsXioImpl &xioimpl)
Definition XrdSfsXio.cc:52
void Say(const char *text1, const char *text2=0, const char *txt3=0, const char *text4=0, const char *text5=0, const char *txt6=0)
static char * s2hms(int sec, char *buff, int blen)
static void ClearErrorQueue()
Clear the SSL error queue for the calling thread.
Definition XrdTls.cc:265
void Ref(int num)
static void Disc(unsigned int usrID)
XrdXrootdPio * Next
XrdXrootd::IOParms IO
static XrdXrootdStats * SI
static const char * myInst
XrdXrootdProtocol * VerifyStream(int &rc, int pID, bool lok=true)
static XrdSfsFileSystem * digFS
XrdSecProtect * Protect
XrdNetPMark::Handle * pmHandle
static XrdNetPMark * PMark
XrdXrootdProtocol * Stream[maxStreams]
XrdXrootd::IOParms IO
static XrdXrootdXPath RPList
static XrdNetSocket * AdminSock
XrdProtocol * Match(XrdLink *lp) override
struct XrdXrootdProtocol::GetDataCtl gdCtl
static bool CloseRequestCb(void *cbarg)
XrdXrootdWVInfo * wvInfo
XrdXrootdPgwCtl * pgwCtl
static void Reclaim(XrdSfsXioHandle h)
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)
XrdSfsXioHandle Claim(const char *buff, int datasz, int minasz=0) override
XrdXrootdMonitor::User Monitor
static XrdXrootdRedirPI * RedirPI
static const char * myCName
XrdSfsXioHandle Swap(const char *buff, XrdSfsXioHandle h=0) override
static XrdXrootdFileLock * Locker
SecurityRequest sigReq
int(XrdXrootdProtocol::* Resume)()
static XrdTlsContext * tlsCtx
static XrdXrootdXPath XPList
static XrdScheduler * Sched
static struct XrdXrootdProtocol::RC_Table RouteClient
int Process(XrdLink *lp) override
void Recycle(XrdLink *lp, int consec, const char *reason) override
static char * Buffer(XrdSfsXioHandle h, int *bsz)
static const char * myUName
XrdXrootdResponse Response
int(XrdXrootdProtocol::* ResumePio)()
static const char * TraceID
static int Configure(char *parms, XrdProtocol_Config *pi)
int Stats(char *buff, int blen, int do_sync=0) override
static const int maxStreams
int getDump(const char *dtype, int dlen)
static XrdOucTList * JobCKTLST
static XrdXrootdXPath RQList
static struct XrdXrootdProtocol::RD_Table Route[RD_Num]
static XrdSecProtector * DHS
static XrdBuffManager * BPool
XrdSysSemaphore * boundRecycle
static XrdSecService * CIA
static RAtomic_int srvrAioOps
static const char * myGName
static uint64_t fsFeatures
static XrdOucReqID * PrepID
XrdXrootdPio * pioFirst
XrdSysCondVar2 * endNote
static XrdSfsFileSystem * osFS
void Set(XrdLink *lp)
static const uint64_t hasCACH
Feature: Implements a data cache.
XrdXrootdStats * SI
XrdScheduler * Sched
XrdBuffManager * BPool
XrdSysError eLog