XRootD
Loading...
Searching...
No Matches
XrdLinkXeq.cc
Go to the documentation of this file.
1/******************************************************************************/
2/* */
3/* X r d L i n k X e q . c c */
4/* */
5/* (c) 2018 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 <limits.h>
31#include <poll.h>
32#include <signal.h>
33#include <cstdio>
34#include <cstring>
35#include <unistd.h>
36#include <sys/types.h>
37#include <sys/uio.h>
38
39#if defined(__linux__) || defined(__GNU__)
40#include <netinet/tcp.h>
41#if !defined(TCP_CORK)
42#undef HAVE_SENDFILE
43#endif
44#endif
45
46#ifdef HAVE_SENDFILE
47
48#if defined(__solaris__) || defined(__linux__) || defined(__GNU__)
49#include <sys/sendfile.h>
50#endif
51
52#endif
53
55#include "XrdSys/XrdSysError.hh"
56#include "XrdSys/XrdSysFD.hh"
58
59#include "Xrd/XrdBuffer.hh"
60#include "Xrd/XrdLink.hh"
61#include "Xrd/XrdLinkCtl.hh"
62#include "Xrd/XrdLinkXeq.hh"
63#include "Xrd/XrdPoll.hh"
64#include "Xrd/XrdScheduler.hh"
65#include "Xrd/XrdSendQ.hh"
66#include "Xrd/XrdTcpMonPin.hh"
67
68#define TRACE_IDENT ID
69#include "Xrd/XrdTrace.hh"
70
71/******************************************************************************/
72/* G l o b a l s */
73/******************************************************************************/
74
75namespace XrdGlobal
76{
77extern XrdSysError Log;
78extern XrdScheduler Sched;
79extern XrdTlsContext *tlsCtx;
81extern int devNull;
83};
84
85using namespace XrdGlobal;
86
87/******************************************************************************/
88/* S t a t i c s */
89/******************************************************************************/
90
91 const char *XrdLinkXeq::TraceID = "LinkXeq";
92
93 long long XrdLinkXeq::LinkBytesIn = 0;
94 long long XrdLinkXeq::LinkBytesOut = 0;
95 long long XrdLinkXeq::LinkConTime = 0;
96 long long XrdLinkXeq::LinkCountTot = 0;
103
104/******************************************************************************/
105/* C o n s t r u c t o r */
106/******************************************************************************/
107
109{
111}
112
114{
115 memcpy(Uname+sizeof(Uname)-7, "anon.0@", 7);
116 strcpy(Lname, "somewhere");
117 ID = &Uname[sizeof(Uname)-5];
118 Comment = ID;
119 sendQ = 0;
120 stallCnt = stallCntTot = 0;
121 tardyCnt = tardyCntTot = 0;
122 SfIntr = 0;
123 isIdle = 0;
125 LockReads= false;
126 KeepFD = false;
127 Protocol = 0;
128 ProtoAlt = 0;
129 CloseRequestCb = 0;
130
131 LinkInfo.Reset();
132 PollInfo.Zorch();
133 ResetLink();
134}
135
136/******************************************************************************/
137/* B a c k l o g */
138/******************************************************************************/
139
141{
143
144// Return backlog information
145//
146 return (sendQ ? sendQ->Backlog() : 0);
147}
148
149/******************************************************************************/
150/* C l i e n t */
151/******************************************************************************/
152
153int XrdLinkXeq::Client(char *nbuf, int nbsz)
154{
155 int ulen;
156
157// Generate full client name
158//
159 if (nbsz <= 0) return 0;
160 ulen = (Lname - ID);
161 if ((ulen + HNlen) >= nbsz) ulen = 0;
162 else {strncpy(nbuf, ID, ulen);
163 strcpy(nbuf+ulen, HostName);
164 ulen += HNlen;
165 }
166 return ulen;
167}
168
169/******************************************************************************/
170/* C l o s e */
171/******************************************************************************/
172
173int XrdLinkXeq::Close(bool defer)
174{ XrdSysMutexHelper opHelper(LinkInfo.opMutex);
175 int csec, fd, rc = 0;
176
177// If a defer close is requested, we can close the descriptor but we must
178// keep the slot number to prevent a new client getting the same fd number.
179// Linux is peculiar in that any in-progress operations will remain in that
180// state even after the FD is closed unless there is some activity either on
181// the connection or an event occurs that causes an operation restart. We
182// portably solve this problem by issuing a shutdown() on the socket prior
183// closing it. On most platforms, this informs readers that the connection is
184// gone (though not on old (i.e. <= 2.3) versions of Linux, sigh). Also, if
185// nonblocking mode is enabled, we need to do this in a separate thread as
186// a shutdown may block for a pretty long time if lots\ of messages are queued.
187// We will ask the SendQ object to schedule the shutdown for us before it
188// commits suicide.
189// Note that we can hold the opMutex while we also get the wrMutex.
190//
191 if (defer)
192 {if (!sendQ) Shutdown(false);
193 else {TRACEI(DEBUG, "Shutdown FD " <<LinkInfo.FD<<" only via SendQ");
194 LinkInfo.InUse++;
195 LinkInfo.FD = -LinkInfo.FD; // Leave poll version untouched!
196 wrMutex.Lock();
197 sendQ->Terminate(this);
198 sendQ = 0;
199 wrMutex.UnLock();
200 }
201 return 0;
202 }
203
204// If we got here then this is not a deferred close so we just need to check
205// if there is a sendq appendage we need to get rid of.
206//
207 if (sendQ)
208 {wrMutex.Lock();
209 sendQ->Terminate();
210 sendQ = 0;
211 wrMutex.UnLock();
212 }
213
214// Multiple protocols may be bound to this link. If it is in use, defer the
215// actual close until the use count drops to one. Similarly, if a thread is
216// dispatched into the protocol (i.e. inside Process()), wait for it to
217// return before we recycle the protocol stack out from under it. Once both
218// counts drain we hold the opMutex until the protocol is removed, so no new
219// dispatch can slip in.
220//
221 while(LinkInfo.InUse > 1 || LinkInfo.dspCnt > 0)
222 {if (LinkInfo.InUse > 1)
223 {opHelper.UnLock();
224 TRACEI(DEBUG, "Close FD "<<LinkInfo.FD <<" deferred, use count="
225 <<LinkInfo.InUse);
226 Serialize();
227 }
228 else
229 {LinkInfo.dspPost++;
230 opHelper.UnLock();
231 TRACEI(DEBUG, "Close FD "<<LinkInfo.FD <<" deferred, dispatch count="
232 <<LinkInfo.dspCnt);
233 LinkInfo.dspSem.Wait();
234 }
235 opHelper.Lock(&LinkInfo.opMutex);
236 }
237 LinkInfo.InUse--;
238 Instance = 0;
239
240// Add up the statistic for this link
241//
242 syncStats(&csec);
243
244// Cleanup TLS if it is active
245//
246 if (isTLS) tlsIO.Shutdown();
247
248// Clean this link up
249//
250 if (Protocol) {Protocol->Recycle(this, csec, LinkInfo.Etext); Protocol = 0;}
251 if (ProtoAlt) {ProtoAlt->Recycle(this, csec, LinkInfo.Etext); ProtoAlt = 0;}
252 if (LinkInfo.Etext) {free(LinkInfo.Etext); LinkInfo.Etext = 0;}
253 LinkInfo.InUse = 0;
254
255// At this point we can have no lock conflicts, so if someone is waiting for
256// us to terminate let them know about it. Note that we will get the condvar
257// mutex while we hold the opMutex. This is the required order! We will also
258// zero out the pointer to the condvar while holding the opmutex.
259//
260 if (LinkInfo.KillcvP)
261 {LinkInfo.KillcvP->Lock();
262 LinkInfo.KillcvP->Signal();
263 LinkInfo.KillcvP->UnLock();
264 LinkInfo.KillcvP = 0;
265 }
266
267// Remove ourselves from the poll table and then from the Link table. We may
268// not hold on to the opMutex when we acquire the LTMutex. However, the link
269// table needs to be cleaned up prior to actually closing the socket. So, we
270// do some fancy footwork to prevent multiple closes of this link.
271//
272 fd = abs(LinkInfo.FD);
273 if (PollInfo.FD > 0)
274 {if (PollInfo.Poller) {XrdPoll::Detach(PollInfo); PollInfo.Poller = 0;}
275 PollInfo.FD = -1;
276 opHelper.UnLock();
278 } else opHelper.UnLock();
279
280// Invoke the TCP monitor if it was loaded.
281//
282 if (TcpMonPin && fd > 2)
283 {XrdTcpMonPin::LinkInfo lnkInfo;
284 lnkInfo.tident = ID;
285 lnkInfo.fd = fd;
286 lnkInfo.consec = csec;
287 lnkInfo.bytesIn = BytesInTot;
288 lnkInfo.bytesOut = BytesOutTot;
289 TcpMonPin->Monitor(Addr, lnkInfo, sizeof(lnkInfo));
290 }
291
292// Close the file descriptor if it isn't being shared. Do it as the last
293// thing because closes and accepts and not interlocked.
294//
295 if (fd >= 2) {if (KeepFD) rc = 0;
296 else rc = (close(fd) < 0 ? errno : 0);
297 }
298 if (rc) Log.Emsg("Link", rc, "close", ID);
299 return rc;
300}
301
302/******************************************************************************/
303/* D o I t */
304/******************************************************************************/
305
307{
308 int rc;
309
310// Count this thread as dispatched into the protocol so that a concurrent
311// Close() waits for the protocol call to return before recycling the protocol
312// stack (e.g. XrdHttp's SSL session) out from under Process(). We may only do
313// so while the link still has a protocol; Close() removes the protocol while
314// continuously holding the opMutex after draining dispatched threads, making
315// this check-and-count atomic with respect to link teardown. Note that we
316// cannot use setRef() for this because InUse counts threads other than the
317// one running the protocol (e.g. Serialize() called within Process() would
318// count us and deadlock).
319//
320 LinkInfo.opMutex.Lock();
321 bool isOpen = (Protocol != 0);
322 if (isOpen) LinkInfo.dspCnt++;
323 LinkInfo.opMutex.UnLock();
324
325// The Process() return code tells us what to do:
326// < 0 -> Stop getting requests,
327// -EINPROGRESS leave link disabled but otherwise all is well
328// -n Error, disable and close the link
329// = 0 -> OK, get next request, if allowed, o/w enable the link
330// > 0 -> Slow link, stop getting requests and enable the link
331//
332 if (isOpen)
333 do {rc = Protocol->Process(this);} while (!rc && Sched.canStick());
334 else {Log.Emsg("Link", "Dispatch on closed link", ID);
335 return;
336 }
337
338// Either re-enable the link and cycle back waiting for a new request, leave
339// disabled, or terminate the connection.
340//
341 bool doCl = false;
342 if (rc >= 0)
343 {if (PollInfo.Poller && !PollInfo.Poller->Enable(PollInfo)) doCl = true;}
344 else if (rc != -EINPROGRESS) doCl = true;
345
346// Indicate that we are no longer dispatched into the protocol, waking up any
347// thread waiting to close this link. This must be done before we ourselves
348// try to close the link lest we deadlock waiting on ourselves.
349//
350 LinkInfo.opMutex.Lock();
351 LinkInfo.dspCnt--;
352 while(LinkInfo.dspCnt == 0 && LinkInfo.dspPost)
353 {LinkInfo.dspSem.Post(); LinkInfo.dspPost--;}
354 LinkInfo.opMutex.UnLock();
355
356 if (doCl)
357 {if (CloseRequestCb)
358 {const bool res = CloseRequestCb(CloseRequestCbArg);
359 if (!res) return;
360 }
361 Close();
362 }
363}
364
365/******************************************************************************/
366/* g e t P e e r C e r t s */
367/******************************************************************************/
368
370{
371 return (isTLS ? tlsIO.getCerts(true) : 0);
372}
373
374/******************************************************************************/
375/* P e e k */
376/******************************************************************************/
377
378int XrdLinkXeq::Peek(char *Buff, int Blen, int timeout)
379{
380 XrdSysMutexHelper theMutex;
381 struct pollfd polltab = {PollInfo.FD, POLLIN|POLLRDNORM, 0};
382 ssize_t mlen;
383 int retc;
384
385// Lock the read mutex if we need to, the helper will unlock it upon exit
386//
387 if (LockReads) theMutex.Lock(&rdMutex);
388
389// Wait until we can actually read something
390//
391 isIdle = 0;
392 do {retc = poll(&polltab, 1, timeout);} while(retc < 0 && errno == EINTR);
393 if (retc != 1)
394 {if (retc == 0) return 0;
395 return Log.Emsg("Link", -errno, "poll", ID);
396 }
397
398// Verify it is safe to read now
399//
400 if (!(polltab.revents & (POLLIN|POLLRDNORM)))
401 {Log.Emsg("Link", XrdPoll::Poll2Text(polltab.revents), "polling", ID);
402 return -1;
403 }
404
405// Do the peek.
406//
407 do {mlen = recv(LinkInfo.FD, Buff, Blen, MSG_PEEK);}
408 while(mlen < 0 && errno == EINTR);
409
410// Return the result
411//
412 if (mlen >= 0) return int(mlen);
413 Log.Emsg("Link", errno, "peek on", ID);
414 return -1;
415}
416
417/******************************************************************************/
418/* R e c v */
419/******************************************************************************/
420
421int XrdLinkXeq::Recv(char *Buff, int Blen)
422{
423 ssize_t rlen;
424
425// Note that we will read only as much as is queued. Use Recv() with a
426// timeout to receive as much data as possible.
427//
428 if (LockReads) rdMutex.Lock();
429 isIdle = 0;
430 do {rlen = read(LinkInfo.FD, Buff, Blen);} while(rlen < 0 && errno == EINTR);
431 if (rlen > 0) AtomicAdd(BytesIn, rlen);
432 if (LockReads) rdMutex.UnLock();
433
434 if (rlen >= 0) return int(rlen);
435 if (LinkInfo.FD >= 0) Log.Emsg("Link", errno, "receive from", ID);
436 return -1;
437}
438
439/******************************************************************************/
440
441int XrdLinkXeq::Recv(char *Buff, int Blen, int timeout)
442{
443 XrdSysMutexHelper theMutex;
444 struct pollfd polltab = {PollInfo.FD, POLLIN|POLLRDNORM, 0};
445 ssize_t rlen, totlen = 0;
446 int retc;
447
448// Lock the read mutex if we need to, the helper will unlock it upon exit
449//
450 if (LockReads) theMutex.Lock(&rdMutex);
451
452// Wait up to timeout milliseconds for data to arrive
453//
454 isIdle = 0;
455 while(Blen > 0)
456 {do {retc = poll(&polltab,1,timeout);} while(retc < 0 && errno == EINTR);
457 if (retc != 1)
458 {if (retc == 0)
459 {tardyCnt++;
460 if (totlen)
461 {if ((++stallCnt & 0xff) == 1) TRACEI(DEBUG,"read timed out");
462 AtomicAdd(BytesIn, totlen);
463 }
464 return int(totlen);
465 }
466 return (LinkInfo.FD >= 0 ? Log.Emsg("Link",-errno,"poll",ID) : -1);
467 }
468
469 // Verify it is safe to read now
470 //
471 if (!(polltab.revents & (POLLIN|POLLRDNORM)))
472 {Log.Emsg("Link", XrdPoll::Poll2Text(polltab.revents),
473 "polling", ID);
474 return -1;
475 }
476
477 // Read as much data as you can. Note that we will force an error
478 // if we get a zero-length read after poll said it was OK.
479 //
480 do {rlen = recv(LinkInfo.FD, Buff, Blen, 0);}
481 while(rlen < 0 && errno == EINTR);
482 if (rlen <= 0)
483 {if (!rlen) return -ENOMSG;
484 if (LinkInfo.FD > 0) Log.Emsg("Link", -errno, "receive from", ID);
485 return -1;
486 }
487 totlen += rlen; Blen -= rlen; Buff += rlen;
488 }
489
490 AtomicAdd(BytesIn, totlen);
491 return int(totlen);
492}
493
494/******************************************************************************/
495
496int XrdLinkXeq::Recv(const struct iovec *iov, int iocnt, int timeout)
497{
498 XrdSysMutexHelper theMutex;
499 struct pollfd polltab = {PollInfo.FD, POLLIN|POLLRDNORM, 0};
500 int retc, rlen;
501
502// Lock the read mutex if we need to, the helper will unlock it upon exit
503//
504 if (LockReads) theMutex.Lock(&rdMutex);
505
506// Wait up to timeout milliseconds for data to arrive
507//
508 isIdle = 0;
509 do {retc = poll(&polltab,1,timeout);} while(retc < 0 && errno == EINTR);
510 if (retc != 1)
511 {if (retc == 0)
512 {tardyCnt++;
513 return 0;
514 }
515 return (LinkInfo.FD >= 0 ? Log.Emsg("Link",-errno,"poll",ID) : -1);
516 }
517
518// Verify it is safe to read now
519//
520 if (!(polltab.revents & (POLLIN|POLLRDNORM)))
521 {Log.Emsg("Link", XrdPoll::Poll2Text(polltab.revents), "polling", ID);
522 return -1;
523 }
524
525// If the iocnt is within limits then just go ahead and read once.
526//
527 if (iocnt <= maxIOV)
528 {rlen = RecvIOV(iov, iocnt);
529 if (rlen > 0) {AtomicAdd(BytesIn, rlen);}
530 return rlen;
531 }
532
533// We will have to break this up into allowable segments and we need to add up
534// the bytes in each segment so that we know when to stop reading.
535//
536 int seglen, segcnt = maxIOV, totlen = 0;
537 do {seglen = 0;
538 for (int i = 0; i < segcnt; i++) seglen += iov[i].iov_len;
539 if ((rlen = RecvIOV(iov, segcnt)) < 0) return rlen;
540 totlen += rlen;
541 if (rlen < seglen) break;
542 iov += segcnt;
543 iocnt -= segcnt;
544 if (iocnt <= maxIOV) segcnt = iocnt;
545 } while(iocnt > 0);
546
547// All done
548//
549 AtomicAdd(BytesIn, totlen);
550 return totlen;
551}
552
553/******************************************************************************/
554/* R e c v A l l */
555/******************************************************************************/
556
557int XrdLinkXeq::RecvAll(char *Buff, int Blen, int timeout)
558{
559 struct pollfd polltab = {PollInfo.FD, POLLIN|POLLRDNORM, 0};
560 ssize_t rlen;
561 int retc;
562
563// Check if timeout specified. Notice that the timeout is the max we will
564// for some data. We will wait forever for all the data. Yeah, it's weird.
565//
566 if (timeout >= 0)
567 {do {retc = poll(&polltab,1,timeout);} while(retc < 0 && errno == EINTR);
568 if (retc != 1)
569 {if (!retc) return -ETIMEDOUT;
570 Log.Emsg("Link",errno,"poll",ID);
571 return -1;
572 }
573 if (!(polltab.revents & (POLLIN|POLLRDNORM)))
574 {Log.Emsg("Link",XrdPoll::Poll2Text(polltab.revents),"polling",ID);
575 return -1;
576 }
577 }
578
579// Note that we will block until we receive all he bytes.
580//
581 if (LockReads) rdMutex.Lock();
582 isIdle = 0;
583 do {rlen = recv(LinkInfo.FD, Buff, Blen, MSG_WAITALL);}
584 while(rlen < 0 && errno == EINTR);
585 if (rlen > 0) AtomicAdd(BytesIn, rlen);
586 if (LockReads) rdMutex.UnLock();
587
588 if (int(rlen) == Blen) return Blen;
589 if (!rlen) {TRACEI(DEBUG, "No RecvAll() data; errno=" <<errno);}
590 else if (rlen > 0) Log.Emsg("RecvAll", "Premature end from", ID);
591 else if (LinkInfo.FD >= 0) Log.Emsg("Link", errno, "receive from", ID);
592 return -1;
593}
594
595/******************************************************************************/
596/* Protected: R e c v I O V */
597/******************************************************************************/
598
599int XrdLinkXeq::RecvIOV(const struct iovec *iov, int iocnt)
600{
601 ssize_t retc = 0;
602
603// Read the data in. On some version of Unix (e.g., Linux) a readv() may
604// end at any time without reading all the bytes when directed to a socket.
605// We always return the number bytes read (or an error). The caller needs to
606// restart the read at the appropriate place in the iovec when more data arrives.
607//
608 do {retc = readv(LinkInfo.FD, iov, iocnt);}
609 while(retc < 0 && errno == EINTR);
610
611// Check how we completed
612//
613 if (retc < 0) Log.Emsg("Link", errno, "receive from", ID);
614 return retc;
615}
616
617/******************************************************************************/
618/* R e g i s t e r */
619/******************************************************************************/
620
621bool XrdLinkXeq::Register(const char *hName)
622{
623
624// Make appropriate changes here
625//
626 if (HostName) free(HostName);
627 HostName = strdup(hName);
628 strlcpy(Lname, hName, sizeof(Lname));
629 return true;
630}
631
632/******************************************************************************/
633/* S e n d */
634/******************************************************************************/
635
636int XrdLinkXeq::Send(const char *Buff, int Blen)
637{
638 ssize_t retc = 0, bytesleft = Blen;
639
640// Get a lock
641//
642 wrMutex.Lock();
643 isIdle = 0;
644 AtomicAdd(BytesOut, Blen);
645
646// Do non-blocking writes if we are setup to do so.
647//
648 if (sendQ)
649 {retc = sendQ->Send(Buff, Blen);
650 wrMutex.UnLock();
651 return retc;
652 }
653
654// Write the data out
655//
656 while(bytesleft)
657 {if ((retc = write(LinkInfo.FD, Buff, bytesleft)) < 0)
658 {if (errno == EINTR) continue;
659 else break;
660 }
661 bytesleft -= retc; Buff += retc;
662 }
663
664// All done
665//
666 wrMutex.UnLock();
667 if (retc >= 0) return Blen;
668 Log.Emsg("Link", errno, "send to", ID);
669 return -1;
670}
671
672/******************************************************************************/
673
674int XrdLinkXeq::Send(const struct iovec *iov, int iocnt, int bytes)
675{
676 int retc;
677
678// Get a lock and assume we will be successful (statistically we are)
679//
680 wrMutex.Lock();
681 isIdle = 0;
682 AtomicAdd(BytesOut, bytes);
683
684// Do non-blocking writes if we are setup to do so.
685//
686 if (sendQ)
687 {retc = sendQ->Send(iov, iocnt, bytes);
688 wrMutex.UnLock();
689 return retc;
690 }
691
692// If the iocnt is within limits then just go ahead and write this out
693//
694 if (iocnt <= maxIOV)
695 {retc = SendIOV(iov, iocnt, bytes);
696 wrMutex.UnLock();
697 return retc;
698 }
699
700// We will have to break this up into allowable segments
701//
702 int seglen, segcnt = maxIOV, iolen = 0;
703 do {seglen = 0;
704 for (int i = 0; i < segcnt; i++) seglen += iov[i].iov_len;
705 if ((retc = SendIOV(iov, segcnt, seglen)) < 0)
706 {wrMutex.UnLock();
707 return retc;
708 }
709 iolen += retc;
710 iov += segcnt;
711 iocnt -= segcnt;
712 if (iocnt <= maxIOV) segcnt = iocnt;
713 } while(iocnt > 0);
714
715// All done
716//
717 wrMutex.UnLock();
718 return iolen;
719}
720
721/******************************************************************************/
722
723int XrdLinkXeq::Send(const sfVec *sfP, int sfN)
724{
725#if !defined(HAVE_SENDFILE)
726
727 return -1;
728
729#elif defined(__solaris__)
730
731 sendfilevec_t vecSF[XrdOucSFVec::sfMax], *vecSFP = vecSF;
732 size_t xframt, totamt, bytes = 0;
733 ssize_t retc;
734 int i = 0;
735
736// Construct the sendfilev() vector
737//
738 for (i = 0; i < sfN; sfP++, i++)
739 {if (sfP->fdnum < 0)
740 {vecSF[i].sfv_fd = SFV_FD_SELF;
741 vecSF[i].sfv_off = (off_t)sfP->buffer;
742 } else {
743 vecSF[i].sfv_fd = sfP->fdnum;
744 vecSF[i].sfv_off = sfP->offset;
745 }
746 vecSF[i].sfv_flag = 0;
747 vecSF[i].sfv_len = sfP->sendsz;
748 bytes += sfP->sendsz;
749 }
750 totamt = bytes;
751
752// Lock the link, issue sendfilev(), and unlock the link. The documentation
753// is very spotty and inconsistent. We can only retry this operation under
754// very limited conditions.
755//
756 wrMutex.Lock();
757 isIdle = 0;
758do{retc = sendfilev(LinkInfo.FD, vecSFP, sfN, &xframt);
759
760// Check if all went well and return if so (usual case)
761//
762 if (xframt == bytes)
763 {AtomicAdd(BytesOut, bytes);
764 wrMutex.UnLock();
765 return totamt;
766 }
767
768// The only one we will recover from is EINTR. We cannot legally get EAGAIN.
769//
770 if (retc < 0 && errno != EINTR) break;
771
772// Try to resume the transfer
773//
774 if (xframt > 0)
775 {AtomicAdd(BytesOut, xframt); bytes -= xframt; SfIntr++;
776 while(xframt > 0 && sfN)
777 {if ((ssize_t)xframt < (ssize_t)vecSFP->sfv_len)
778 {vecSFP->sfv_off += xframt; vecSFP->sfv_len -= xframt; break;}
779 xframt -= vecSFP->sfv_len; vecSFP++; sfN--;
780 }
781 }
782 } while(sfN > 0);
783
784// See if we can recover without destroying the connection
785//
786 retc = (retc < 0 ? errno : ECANCELED);
787 wrMutex.UnLock();
788 Log.Emsg("Link", retc, "send file to", ID);
789 return -1;
790
791#elif defined(__linux__) || defined(__GNU__)
792
793 static const int setON = 1, setOFF = 0;
794 ssize_t retc = 0, bytesleft;
795 off_t myOffset;
796 int i, xfrbytes = 0, uncork = 1, xIntr = 0;
797
798// lock the link
799//
800 wrMutex.Lock();
801 isIdle = 0;
802
803// In linux we need to cork the socket. On permanent errors we do not uncork
804// the socket because it will be closed in short order.
805//
806 if (setsockopt(PollInfo.FD, SOL_TCP, TCP_CORK, &setON, sizeof(setON)) < 0)
807 {Log.Emsg("Link", errno, "cork socket for", ID);
808 uncork = 0; sfOK = 0;
809 }
810
811// Send the header first
812//
813 for (i = 0; i < sfN; sfP++, i++)
814 {if (sfP->fdnum < 0) retc = sendData(sfP->buffer, sfP->sendsz);
815 else {myOffset = sfP->offset; bytesleft = sfP->sendsz;
816 while(bytesleft
817 && (retc=sendfile(LinkInfo.FD,sfP->fdnum,&myOffset,bytesleft)) > 0)
818 {bytesleft -= retc; xIntr++;}
819 }
820 if (retc < 0 && errno == EINTR) continue;
821 if (retc <= 0) break;
822 xfrbytes += sfP->sendsz;
823 }
824
825// Diagnose any sendfile errors
826//
827 if (retc <= 0)
828 {if (retc == 0) errno = ECANCELED;
829 wrMutex.UnLock();
830 Log.Emsg("Link", errno, "send file to", ID);
831 return -1;
832 }
833
834// Now uncork the socket
835//
836 if (uncork
837 && setsockopt(PollInfo.FD, SOL_TCP, TCP_CORK, &setOFF, sizeof(setOFF)) < 0)
838 Log.Emsg("Link", errno, "uncork socket for", ID);
839
840// All done
841//
842 if (xIntr > sfN) SfIntr += (xIntr - sfN);
843 AtomicAdd(BytesOut, xfrbytes);
844 wrMutex.UnLock();
845 return xfrbytes;
846
847#else
848
849 return -1;
850
851#endif
852}
853
854/******************************************************************************/
855/* Protected: s e n d D a t a */
856/******************************************************************************/
857
858int XrdLinkXeq::sendData(const char *Buff, int Blen)
859{
860 ssize_t retc = 0, bytesleft = Blen;
861
862// Write the data out
863//
864 while(bytesleft)
865 {if ((retc = write(LinkInfo.FD, Buff, bytesleft)) < 0)
866 {if (errno == EINTR) continue;
867 else break;
868 }
869 bytesleft -= retc; Buff += retc;
870 }
871
872// All done
873//
874 return retc;
875}
876
877/******************************************************************************/
878/* Protected: S e n d I O V */
879/******************************************************************************/
880
881int XrdLinkXeq::SendIOV(const struct iovec *iov, int iocnt, int bytes)
882{
883 ssize_t bytesleft, n, retc = 0;
884 const char *Buff;
885
886// Write the data out. On some version of Unix (e.g., Linux) a writev() may
887// end at any time without writing all the bytes when directed to a socket.
888// So, we attempt to resume the writev() using a combination of write() and
889// a writev() continuation. This approach slowly converts a writev() to a
890// series of writes if need be. We must do this inline because we must hold
891// the lock until all the bytes are written or an error occurs.
892//
893 bytesleft = static_cast<ssize_t>(bytes);
894 while(bytesleft)
895 {do {retc = writev(LinkInfo.FD, iov, iocnt);}
896 while(retc < 0 && errno == EINTR);
897 if (retc >= bytesleft || retc < 0) break;
898 bytesleft -= retc;
899 while(retc >= (n = static_cast<ssize_t>(iov->iov_len)))
900 {retc -= n; iov++; iocnt--;}
901 Buff = (const char *)iov->iov_base + retc; n -= retc; iov++; iocnt--;
902 while(n) {if ((retc = write(LinkInfo.FD, Buff, n)) < 0)
903 {if (errno == EINTR) continue;
904 else break;
905 }
906 n -= retc; Buff += retc; bytesleft -= retc;
907 }
908 if (retc < 0 || iocnt < 1) break;
909 }
910
911// All done
912//
913 if (retc >= 0) return bytes;
914 Log.Emsg("Link", errno, "send to", ID);
915 return -1;
916}
917
918/******************************************************************************/
919/* s e t I D */
920/******************************************************************************/
921
922void XrdLinkXeq::setID(const char *userid, int procid)
923{
924 char buff[sizeof(Uname)], *bp, *sp;
925 int ulen;
926
927 snprintf(buff, sizeof(buff), "%s.%d:%d", userid, procid, PollInfo.FD);
928 ulen = strlen(buff);
929 sp = buff + ulen - 1;
930 bp = &Uname[sizeof(Uname)-1];
931 if (ulen > (int)sizeof(Uname)) ulen = sizeof(Uname);
932 *bp = '@'; bp--;
933 while(ulen--) {*bp = *sp; bp--; sp--;}
934 ID = bp+1;
935 Comment = (const char *)ID;
936
937// Update the ID in the TLS socket if enabled
938//
939 if (isTLS) tlsIO.SetTraceID(ID);
940}
941
942/******************************************************************************/
943/* s e t N B */
944/******************************************************************************/
945
947{
948// We don't support non-blocking output except for Linux at the moment
949//
950#if !defined(__linux__)
951 return false;
952#else
953// Trace this request
954//
955 TRACEI(DEBUG,"enabling non-blocking output");
956
957// If we don't already have a sendQ object get one. This is a one-time call
958// so to optimize checking if this object exists we also get the opMutex.'
959//
960 LinkInfo.opMutex.Lock();
961 if (!sendQ)
962 {wrMutex.Lock();
963 sendQ = new XrdSendQ(*this, wrMutex);
964 wrMutex.UnLock();
965 }
966 LinkInfo.opMutex.UnLock();
967 return true;
968#endif
969}
970
971/******************************************************************************/
972/* s e t P r o t o c o l */
973/******************************************************************************/
974
976{
977
978// Set new protocol.
979//
980 LinkInfo.opMutex.Lock();
981 XrdProtocol *op = Protocol;
982 if (push) ProtoAlt = Protocol;
983 Protocol = pp;
984 LinkInfo.opMutex.UnLock();
985 return op;
986}
987
988/******************************************************************************/
989/* s e t P r o t N a m e */
990/******************************************************************************/
991
992void XrdLinkXeq::setProtName(const char *name)
993{
994
995// Set the protocol name.
996//
997 LinkInfo.opMutex.Lock();
998 Addr.SetDialect(name);
999 LinkInfo.opMutex.UnLock();
1000}
1001
1002/******************************************************************************/
1003/* s e t T L S */
1004/******************************************************************************/
1005
1006bool XrdLinkXeq::setTLS(bool enable, XrdTlsContext *ctx)
1007{ //???
1008// static const XrdTlsConnection::RW_Mode rwMode=XrdTlsConnection::TLS_RNB_WBL;
1011 const char *eNote;
1012 XrdTls::RC rc;
1013
1014// If we are already in a compatible mode, we are done
1015//
1016
1017 if (isTLS == enable) return true;
1018
1019// If this is a shutdown, then do it now.
1020//
1021 if (!enable)
1022 {tlsIO.Shutdown();
1023 isTLS = enable;
1024 Addr.SetTLS(enable);
1025 return true;
1026 }
1027// We want to initialize TLS, do so now.
1028//
1029 if (!ctx) ctx = tlsCtx;
1030 eNote = tlsIO.Init(*ctx, PollInfo.FD, rwMode, hsMode, false, false, ID);
1031
1032// Check for errors
1033//
1034 if (eNote)
1035 {char buff[1024];
1036 snprintf(buff, sizeof(buff), "Unable to enable tls for %s;", ID);
1037 Log.Emsg("LinkXeq", buff, eNote);
1038 return false;
1039 }
1040
1041// Now we need to accept this TLS connection
1042//
1043 std::string eMsg;
1044 rc = tlsIO.Accept(&eMsg);
1045
1046// Diagnose return state
1047//
1048 if (rc != XrdTls::TLS_AOK) Log.Emsg("LinkXeq", eMsg.c_str());
1049 else {isTLS = enable;
1050 Addr.SetTLS(enable);
1051 Log.Emsg("LinkXeq", ID, "connection upgraded to", verTLS());
1052 }
1053 return rc == XrdTls::TLS_AOK;
1054}
1055
1056/******************************************************************************/
1057/* S F E r r o r */
1058/******************************************************************************/
1059
1061{
1062 Log.Emsg("TLS", rc, "send file to", ID);
1063 return -1;
1064}
1065
1066/******************************************************************************/
1067/* S h u t d o w n */
1068/******************************************************************************/
1069
1070void XrdLinkXeq::Shutdown(bool getLock)
1071{
1072 int temp;
1073
1074// Trace the entry
1075//
1076 TRACEI(DEBUG, (getLock ? "Async" : "Sync") <<" link shutdown in progress");
1077
1078// Get the lock if we need too (external entry via another thread)
1079//
1080 if (getLock) LinkInfo.opMutex.Lock();
1081
1082// If there is something to do, do it now
1083//
1084 temp = Instance; Instance = 0;
1085 if (!KeepFD)
1086 {shutdown(PollInfo.FD, SHUT_RDWR);
1087 if (dup2(devNull, PollInfo.FD) < 0)
1088 {Instance = temp;
1089 Log.Emsg("Link", errno, "shutdown FD for", ID);
1090 }
1091 }
1092
1093// All done
1094//
1095 if (getLock) LinkInfo.opMutex.UnLock();
1096}
1097
1098/******************************************************************************/
1099/* S t a t s */
1100/******************************************************************************/
1101
1102int XrdLinkXeq::Stats(char *buff, int blen, bool do_sync)
1103{
1104 static const char statfmt[] = "<stats id=\"link\"><num>%d</num>"
1105 "<maxn>%d</maxn><tot>%lld</tot><in>%lld</in><out>%lld</out>"
1106 "<ctime>%lld</ctime><tmo>%d</tmo><stall>%d</stall>"
1107 "<sfps>%d</sfps></stats>";
1108 int i;
1109
1110// Check if actual length wanted
1111//
1112 if (!buff) return sizeof(statfmt)+17*6;
1113
1114// We must synchronize the statistical counters
1115//
1116 if (do_sync) XrdLinkCtl::SyncAll();
1117
1118// Obtain lock on the stats area and format it
1119//
1121 i = snprintf(buff, blen, statfmt, AtomicGet(LinkCount),
1131 return i;
1132}
1133
1134/******************************************************************************/
1135/* s y n c S t a t s */
1136/******************************************************************************/
1137
1139{
1140 long long tmpLL;
1141 int tmpI4;
1142
1143// If this is dynamic, get the opMutex lock
1144//
1145 if (!ctime) LinkInfo.opMutex.Lock();
1146
1147// Either the caller has the opMutex or this is called out of close. In either
1148// case, we need to get the read and write mutexes; each followed by the stats
1149// mutex. This order is important because we should not hold the stats mutex
1150// for very long and the r/w mutexes may take a long time to acquire. If we
1151// must maintain the link count we need to actually acquire the stats mutex as
1152// we will be doing compound operations. Atomics are still used to keep other
1153// threads from seeing partial results.
1154//
1156
1157 if (ctime)
1158 {*ctime = time(0) - LinkInfo.conTime;
1159 AtomicAdd(LinkConTime, *ctime);
1160 statsMutex.Lock();
1161 if (LinkCount > 0) AtomicDec(LinkCount);
1162 statsMutex.UnLock();
1163 }
1164
1166
1167 tmpLL = AtomicFAZ(BytesIn);
1168 AtomicAdd(LinkBytesIn, tmpLL); AtomicAdd(BytesInTot, tmpLL);
1169 tmpI4 = AtomicFAZ(tardyCnt);
1171 tmpI4 = AtomicFAZ(stallCnt);
1172 AtomicAdd(LinkStalls, tmpI4); AtomicAdd(stallCntTot, tmpI4);
1174
1176 tmpLL = AtomicFAZ(BytesOut);
1178 tmpI4 = AtomicFAZ(SfIntr);
1179 AtomicAdd(LinkSfIntr, tmpI4);
1181
1182// Make sure the protocol updates it's statistics as well
1183//
1184 if (Protocol) Protocol->Stats(0, 0, 1);
1185
1186// All done
1187//
1188 if (!ctime) LinkInfo.opMutex.UnLock();
1189}
1190
1191/******************************************************************************/
1192/* Protected: T L S _ E r r o r */
1193/******************************************************************************/
1194
1195int XrdLinkXeq::TLS_Error(const char *act, XrdTls::RC rc)
1196{
1197 std::string reason = XrdTls::RC2Text(rc);
1198 char msg[512];
1199
1200 snprintf(msg, sizeof(msg), "Unable to %s %s;", act, ID);
1201 Log.Emsg("TLS", msg, reason.c_str());
1202 return -1;
1203}
1204
1205/******************************************************************************/
1206/* T L S _ P e e k */
1207/******************************************************************************/
1208
1209int XrdLinkXeq::TLS_Peek(char *Buff, int Blen, int timeout)
1210{
1211 XrdSysMutexHelper theMutex;
1212 XrdTls::RC retc;
1213 int rc, rlen;
1214
1215// Lock the read mutex if we need to, the helper will unlock it upon exit
1216//
1217 if (LockReads) theMutex.Lock(&rdMutex);
1218
1219// Wait until we can actually read something
1220//
1221 isIdle = 0;
1222 if (timeout)
1223 {rc = Wait4Data(timeout);
1224 if (rc < 1) return rc;
1225 }
1226
1227// Do the peek and if sucessful, the number of bytes available.
1228//
1229 retc = tlsIO.Peek(Buff, Blen, rlen);
1230 if (retc == XrdTls::TLS_AOK) return rlen;
1231
1232// Dianose the TLS error and return failure
1233//
1234 return TLS_Error("peek on", retc);
1235}
1236
1237/******************************************************************************/
1238/* T L S _ R e c v */
1239/******************************************************************************/
1240
1241int XrdLinkXeq::TLS_Recv(char *Buff, int Blen)
1242{
1243 XrdSysMutexHelper theMutex;
1244 XrdTls::RC retc;
1245 int rlen;
1246
1247// Lock the read mutex if we need to, the helper will unlock it upon exit
1248//
1249 if (LockReads) theMutex.Lock(&rdMutex);
1250
1251// Note that we will read only as much as is queued. Use Recv() with a
1252// timeout to receive as much data as possible.
1253//
1254 isIdle = 0;
1255 retc = tlsIO.Read(Buff, Blen, rlen);
1256 if (retc != XrdTls::TLS_AOK) return TLS_Error("receive from", retc);
1257 if (rlen > 0) AtomicAdd(BytesIn, rlen);
1258 return rlen;
1259}
1260
1261/******************************************************************************/
1262
1263int XrdLinkXeq::TLS_Recv(char *Buff, int Blen, int timeout, bool havelock)
1264{
1265 XrdSysMutexHelper theMutex;
1266 XrdTls::RC retc;
1267 int pend, rlen, totlen = 0;
1268
1269// Lock the read mutex if we need to, the helper will unlock it upon exit
1270//
1271 if (LockReads && !havelock) theMutex.Lock(&rdMutex);
1272
1273// Wait up to timeout milliseconds for data to arrive
1274//
1275 isIdle = 0;
1276 while(Blen > 0)
1277 {pend = tlsIO.Pending(true);
1278 if (!pend) pend = Wait4Data(timeout);
1279 if (pend < 1)
1280 {if (pend < 0) return -1;
1281 tardyCnt++;
1282 if (totlen)
1283 {if ((++stallCnt & 0xff) == 1) TRACEI(DEBUG,"read timed out");
1284 AtomicAdd(BytesIn, totlen);
1285 }
1286 return totlen;
1287 }
1288
1289 // Read as much data as you can. Note that we will force an error
1290 // if we get a zero-length read after poll said it was OK. However,
1291 // if we never read anything, then we simply return -ENOMSG to avoid
1292 // generating a "read link error" as clearly there was a hangup.
1293 //
1294 retc = tlsIO.Read(Buff, Blen, rlen);
1295 if (retc != XrdTls::TLS_AOK)
1296 {if (!totlen) return -ENOMSG;
1297 AtomicAdd(BytesIn, totlen);
1298 return TLS_Error("receive from", retc);
1299 }
1300 if (rlen <= 0) break;
1301 totlen += rlen; Blen -= rlen; Buff += rlen;
1302 }
1303
1304 AtomicAdd(BytesIn, totlen);
1305 return totlen;
1306}
1307
1308/******************************************************************************/
1309
1310int XrdLinkXeq::TLS_Recv(const struct iovec *iov, int iocnt, int timeout)
1311{
1312 XrdSysMutexHelper theMutex;
1313 char *Buff;
1314 int Blen, rlen, totlen = 0;
1315
1316// Lock the read mutex if we need to, the helper will unlock it upon exit
1317//
1318 if (LockReads) theMutex.Lock(&rdMutex);
1319
1320// Individually process each element until we can't read any more
1321//
1322 isIdle = 0;
1323 for (int i = 0; i < iocnt; i++)
1324 {Buff = (char *)iov[i].iov_base;
1325 Blen = iov[i].iov_len;
1326 rlen = TLS_Recv(Buff, Blen, timeout, true);
1327 if (rlen <= 0) break;
1328 totlen += rlen;
1329 if (rlen < Blen) break;
1330 }
1331
1332 if (totlen) {AtomicAdd(BytesIn, totlen);}
1333 return totlen;
1334}
1335
1336/******************************************************************************/
1337/* T L S _ R e c v A l l */
1338/******************************************************************************/
1339
1340int XrdLinkXeq::TLS_RecvAll(char *Buff, int Blen, int timeout)
1341{
1342 int retc;
1343
1344// Check if timeout specified. Notice that the timeout is the max we will
1345// wait for some data. We will wait forever for all the data. Yeah, it's weird.
1346//
1347 if (timeout >= 0)
1348 {retc = tlsIO.Pending(true);
1349 if (!retc) retc = Wait4Data(timeout);
1350 if (retc < 1) return (retc ? -1 : -ETIMEDOUT);
1351 }
1352
1353// Note that we will block until we receive all the bytes.
1354//
1355 return TLS_Recv(Buff, Blen, -1);
1356}
1357
1358/******************************************************************************/
1359/* T L S _ S e n d */
1360/******************************************************************************/
1361
1362int XrdLinkXeq::TLS_Send(const char *Buff, int Blen)
1363{
1365 ssize_t bytesleft = Blen;
1366 XrdTls::RC retc;
1367 int byteswritten;
1368
1369// Prepare to send
1370//
1371 isIdle = 0;
1372 AtomicAdd(BytesOut, Blen);
1373
1374// Do non-blocking writes if we are setup to do so.
1375//
1376 if (sendQ) return sendQ->Send(Buff, Blen);
1377
1378// Write the data out
1379//
1380 while(bytesleft)
1381 {retc = tlsIO.Write(Buff, bytesleft, byteswritten);
1382 if (retc != XrdTls::TLS_AOK) return TLS_Error("send to", retc);
1383 bytesleft -= byteswritten; Buff += byteswritten;
1384 }
1385
1386// All done
1387//
1388 return Blen;
1389}
1390
1391/******************************************************************************/
1392
1393int XrdLinkXeq::TLS_Send(const struct iovec *iov, int iocnt, int bytes)
1394{
1396 XrdTls::RC retc;
1397 int byteswritten;
1398
1399// Get a lock and assume we will be successful (statistically we are). Note
1400// that the calling interface gauranteed bytes are not zero.
1401//
1402 isIdle = 0;
1403 AtomicAdd(BytesOut, bytes);
1404
1405// Do non-blocking writes if we are setup to do so.
1406//
1407 if (sendQ) return sendQ->Send(iov, iocnt, bytes);
1408
1409// Write the data out.
1410//
1411 for (int i = 0; i < iocnt; i++)
1412 {ssize_t bytesleft = iov[i].iov_len;
1413 char *Buff = (char *)iov[i].iov_base;
1414 while(bytesleft)
1415 {retc = tlsIO.Write(Buff, bytesleft, byteswritten);
1416 if (retc != XrdTls::TLS_AOK) return TLS_Error("send to", retc);
1417 bytesleft -= byteswritten; Buff += byteswritten;
1418 }
1419 }
1420
1421// All done
1422//
1423 return bytes;
1424}
1425
1426/******************************************************************************/
1427
1428int XrdLinkXeq::TLS_Send(const sfVec *sfP, int sfN)
1429{
1431 int bytes, buffsz, fileFD, retc;
1432 off_t offset;
1433 ssize_t totamt = 0;
1434 char myBuff[65536];
1435
1436// Convert the sendfile to a regular send. The conversion is not particularly
1437// fast and caller are advised to avoid using sendfile on TLS connections.
1438//
1439 isIdle = 0;
1440 for (int i = 0; i < sfN; sfP++, i++)
1441 {if (!(bytes = sfP->sendsz)) continue;
1442 totamt += bytes;
1443 if (sfP->fdnum < 0)
1444 {if (!TLS_Write(sfP->buffer, bytes)) return -1;
1445 continue;
1446 }
1447 offset = sfP->offset;
1448 fileFD = sfP->fdnum;
1449 buffsz = (bytes < (int)sizeof(myBuff) ? bytes : sizeof(myBuff));
1450 do {do {retc = pread(fileFD, myBuff, buffsz, offset);}
1451 while(retc < 0 && errno == EINTR);
1452 if (retc < 0) return SFError(errno);
1453 if (!retc) break;
1454 if (!TLS_Write(myBuff, buffsz)) return -1;
1455 offset += buffsz; bytes -= buffsz; totamt += retc;
1456 } while(bytes > 0);
1457 }
1458
1459// We are done
1460//
1461 AtomicAdd(BytesOut, totamt);
1462 return totamt;
1463}
1464
1465/******************************************************************************/
1466/* Protected: T L S _ W r i t e */
1467/******************************************************************************/
1468
1469bool XrdLinkXeq::TLS_Write(const char *Buff, int Blen)
1470{
1471 XrdTls::RC retc;
1472 int byteswritten;
1473
1474// Write the data out
1475//
1476 while(Blen)
1477 {retc = tlsIO.Write(Buff, Blen, byteswritten);
1478 if (retc != XrdTls::TLS_AOK)
1479 {TLS_Error("write to", retc);
1480 return false;
1481 }
1482 Blen -= byteswritten; Buff += byteswritten;
1483 }
1484
1485// All done
1486//
1487 return true;
1488}
1489
1490/******************************************************************************/
1491/* v e r T L S */
1492/******************************************************************************/
1493
1495{
1496 return tlsIO.Version();
1497}
1498
1499/******************************************************************************/
1500/* R e g i s t e r C l o s e R e q u e s t C b */
1501/******************************************************************************/
1502
1504 void* cbarg)
1505{
1506 if (pp != Protocol) return false;
1507
1508 CloseRequestCb = cb;
1509 CloseRequestCbArg = cbarg;
1510 return true;
1511}
#define DEBUG(x)
#define close(a)
Definition XrdPosix.hh:48
#define write(a, b, c)
Definition XrdPosix.hh:115
#define writev(a, b, c)
Definition XrdPosix.hh:117
#define readv(a, b, c)
Definition XrdPosix.hh:84
#define read(a, b, c)
Definition XrdPosix.hh:82
#define pread(a, b, c, d)
Definition XrdPosix.hh:80
#define eMsg(x)
#define AtomicFAZ(x)
#define AtomicBeg(Mtx)
#define AtomicDec(x)
#define AtomicGet(x)
#define AtomicEnd(Mtx)
#define AtomicAdd(x, y)
size_t strlcpy(char *dst, const char *src, size_t sz)
#define TRACEI(act, x)
Definition XrdTrace.hh:66
const char * Comment
Definition XrdJob.hh:47
static void SyncAll()
Synchronize statustics for ll links.
static void Unhook(int fd)
Unhook a link from the active table of links.
static const char * TraceID
bool(* CloseRequestCb)(void *)
int TLS_Send(const char *Buff, int Blen)
long long BytesOut
int TLS_Error(const char *act, XrdTls::RC rc)
int TLS_Peek(char *Buff, int Blen, int timeout)
int Client(char *buff, int blen)
char Uname[24]
XrdTlsPeerCerts * getPeerCerts()
static int LinkCountMax
XrdLinkInfo LinkInfo
XrdProtocol * ProtoAlt
int Close(bool defer=false)
XrdNetAddr Addr
int TLS_Recv(char *Buff, int Blen)
int sendData(const char *Buff, int Blen)
long long BytesInTot
bool TLS_Write(const char *Buff, int Blen)
int SendIOV(const struct iovec *iov, int iocnt, int bytes)
XrdProtocol * setProtocol(XrdProtocol *pp, bool push)
static long long LinkCountTot
long long BytesOutTot
void Shutdown(bool getLock)
int Peek(char *buff, int blen, int timeout=-1)
static int LinkCount
void Reset()
int Backlog()
XrdSysMutex wrMutex
static int Stats(char *buff, int blen, bool do_sync=false)
XrdSendQ * sendQ
XrdPollInfo PollInfo
void setID(const char *userid, int procid)
int Recv(char *buff, int blen)
static long long LinkBytesIn
void * CloseRequestCbArg
int TLS_RecvAll(char *Buff, int Blen, int timeout)
int SFError(int rc)
long long BytesIn
int Send(const char *buff, int blen)
XrdSysMutex rdMutex
const char * verTLS()
bool setNB()
int RecvIOV(const struct iovec *iov, int iocnt)
char Lname[256]
static long long LinkConTime
static int LinkSfIntr
XrdTlsSocket tlsIO
void DoIt()
int RecvAll(char *buff, int blen, int timeout=-1)
XrdProtocol * Protocol
bool Register(const char *hName)
static XrdSysMutex statsMutex
void setProtName(const char *name)
static int LinkStalls
static long long LinkBytesOut
void syncStats(int *ctime=0)
bool setTLS(bool enable, XrdTlsContext *ctx=0)
static int LinkTimeOuts
bool RegisterCloseRequestCb(XrdProtocol *pp, bool(*cb)(void *), void *cbarg)
static char * Poll2Text(short events)
Definition XrdPoll.cc:272
static void Detach(XrdPollInfo &pInfo)
Definition XrdPoll.cc:177
void Lock(XrdSysMutex *Mutex)
int fd
Socket file descriptor.
long long bytesOut
Bytes written to the socket.
int consec
Seconds connected.
long long bytesIn
Bytes read from the socket.
const char * tident
Pointer to the client's trace identifier.
@ TLS_HS_BLOCK
Always block during handshake.
@ TLS_RBL_WBL
blocking read blocking write
static std::string RC2Text(XrdTls::RC rc, bool dbg=false)
Definition XrdTls.cc:127
@ TLS_AOK
All went well, will always be zero.
Definition XrdTls.hh:40
XrdTlsContext * tlsCtx
Definition XrdGlobals.cc:52
XrdTcpMonPin * TcpMonPin
Definition XrdLinkXeq.cc:80
const int maxIOV
Definition XrdLinkXeq.cc:82
XrdSysError Log
Definition XrdConfig.cc:113
XrdScheduler Sched
Definition XrdLinkCtl.cc:54
int getIovMax()
int fdnum
File descriptor for data.
int sendsz
Length of data at offset.