XRootD
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 
54 #include "XrdSys/XrdSysAtomics.hh"
55 #include "XrdSys/XrdSysError.hh"
56 #include "XrdSys/XrdSysFD.hh"
57 #include "XrdSys/XrdSysPlatform.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 
75 namespace XrdGlobal
76 {
77 extern XrdSysError Log;
78 extern XrdScheduler Sched;
79 extern XrdTlsContext *tlsCtx;
81 extern int devNull;
82  const int maxIOV = XrdSys::getIovMax();
83 };
84 
85 using 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;
97  int XrdLinkXeq::LinkCount = 0;
100  int XrdLinkXeq::LinkStalls = 0;
101  int XrdLinkXeq::LinkSfIntr = 0;
103 
104 /******************************************************************************/
105 /* C o n s t r u c t o r */
106 /******************************************************************************/
107 
108 XrdLinkXeq::XrdLinkXeq() : XrdLink(*this), PollInfo((XrdLink &)*this)
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 
153 int 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 
173 int XrdLinkXeq::Close(bool defer)
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();
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)
275  PollInfo.FD = -1;
276  opHelper.UnLock();
277  XrdLinkCtl::Unhook(fd);
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 //
321  bool isOpen = (Protocol != 0);
322  if (isOpen) LinkInfo.dspCnt++;
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 //
351  LinkInfo.dspCnt--;
352  while(LinkInfo.dspCnt == 0 && LinkInfo.dspPost)
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 
378 int 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 
421 int 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 
441 int 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 
496 int 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 
557 int 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 
599 int 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 
621 bool 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 
636 int 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 
674 int 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 
723 int 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;
758 do{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 
858 int 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 
881 int 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 
922 void 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 //
961  if (!sendQ)
962  {wrMutex.Lock();
963  sendQ = new XrdSendQ(*this, wrMutex);
964  wrMutex.UnLock();
965  }
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 //
981  XrdProtocol *op = Protocol;
982  if (push) ProtoAlt = Protocol;
983  Protocol = pp;
985  return op;
986 }
987 
988 /******************************************************************************/
989 /* s e t P r o t N a m e */
990 /******************************************************************************/
991 
992 void XrdLinkXeq::setProtName(const char *name)
993 {
994 
995 // Set the protocol name.
996 //
998  Addr.SetDialect(name);
1000 }
1001 
1002 /******************************************************************************/
1003 /* s e t T L S */
1004 /******************************************************************************/
1005 
1006 bool 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 
1070 void 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 
1102 int 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 
1138 void XrdLinkXeq::syncStats(int *ctime)
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 //
1155  AtomicBeg(rdMutex);
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);
1170  AtomicAdd(LinkTimeOuts, tmpI4); AtomicAdd(tardyCntTot, tmpI4);
1171  tmpI4 = AtomicFAZ(stallCnt);
1172  AtomicAdd(LinkStalls, tmpI4); AtomicAdd(stallCntTot, tmpI4);
1174 
1176  tmpLL = AtomicFAZ(BytesOut);
1177  AtomicAdd(LinkBytesOut, tmpLL); AtomicAdd(BytesOutTot, tmpLL);
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 
1195 int 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 
1209 int 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 
1241 int 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 
1263 int 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 
1310 int 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 
1340 int 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 
1362 int 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 
1393 int 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 
1428 int 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 
1469 bool 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 
1494 const char *XrdLinkXeq::verTLS()
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)
Definition: XrdBwmTrace.hh:54
ssize_t readv(int fildes, const struct iovec *iov, int iovcnt)
ssize_t write(int fildes, const void *buf, size_t nbyte)
ssize_t writev(int fildes, const struct iovec *iov, int iovcnt)
ssize_t read(int fildes, void *buf, size_t nbyte)
#define close(a)
Definition: XrdPosix.hh:48
#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.
Definition: XrdLinkCtl.cc:374
static void Unhook(int fd)
Unhook a link from the active table of links.
Definition: XrdLinkCtl.cc:392
time_t conTime
Definition: XrdLinkInfo.hh:45
void Reset()
Definition: XrdLinkInfo.hh:55
XrdSysSemaphore dspSem
Definition: XrdLinkInfo.hh:44
char * Etext
Definition: XrdLinkInfo.hh:46
XrdSysRecMutex opMutex
Definition: XrdLinkInfo.hh:47
XrdSysCondVar * KillcvP
Definition: XrdLinkInfo.hh:42
static const char * TraceID
Definition: XrdLinkXeq.hh:160
bool(* CloseRequestCb)(void *)
Definition: XrdLinkXeq.hh:188
int TLS_Send(const char *Buff, int Blen)
Definition: XrdLinkXeq.cc:1362
long long BytesOut
Definition: XrdLinkXeq.hh:175
int TLS_Error(const char *act, XrdTls::RC rc)
Definition: XrdLinkXeq.cc:1195
int TLS_Peek(char *Buff, int Blen, int timeout)
Definition: XrdLinkXeq.cc:1209
int stallCntTot
Definition: XrdLinkXeq.hh:178
int Client(char *buff, int blen)
Definition: XrdLinkXeq.cc:153
char Uname[24]
Definition: XrdLinkXeq.hh:205
XrdTlsPeerCerts * getPeerCerts()
Definition: XrdLinkXeq.cc:369
static int LinkCountMax
Definition: XrdLinkXeq.hh:169
XrdLinkInfo LinkInfo
Definition: XrdLinkXeq.hh:147
XrdProtocol * ProtoAlt
Definition: XrdLinkXeq.hh:187
int Close(bool defer=false)
Definition: XrdLinkXeq.cc:173
XrdNetAddr Addr
Definition: XrdLinkXeq.hh:197
int TLS_Recv(char *Buff, int Blen)
Definition: XrdLinkXeq.cc:1241
int sendData(const char *Buff, int Blen)
Definition: XrdLinkXeq.cc:858
long long BytesInTot
Definition: XrdLinkXeq.hh:174
bool TLS_Write(const char *Buff, int Blen)
Definition: XrdLinkXeq.cc:1469
int SendIOV(const struct iovec *iov, int iocnt, int bytes)
Definition: XrdLinkXeq.cc:881
XrdProtocol * setProtocol(XrdProtocol *pp, bool push)
Definition: XrdLinkXeq.cc:975
static long long LinkCountTot
Definition: XrdLinkXeq.hh:167
long long BytesOutTot
Definition: XrdLinkXeq.hh:176
void Shutdown(bool getLock)
Definition: XrdLinkXeq.cc:1070
int Peek(char *buff, int blen, int timeout=-1)
Definition: XrdLinkXeq.cc:378
static int LinkCount
Definition: XrdLinkXeq.hh:168
void Reset()
Definition: XrdLinkXeq.cc:113
int Backlog()
Definition: XrdLinkXeq.cc:140
XrdSysMutex wrMutex
Definition: XrdLinkXeq.hh:199
static int Stats(char *buff, int blen, bool do_sync=false)
Definition: XrdLinkXeq.cc:1102
XrdSendQ * sendQ
Definition: XrdLinkXeq.hh:200
XrdPollInfo PollInfo
Definition: XrdLinkXeq.hh:148
void setID(const char *userid, int procid)
Definition: XrdLinkXeq.cc:922
bool LockReads
Definition: XrdLinkXeq.hh:202
int Recv(char *buff, int blen)
Definition: XrdLinkXeq.cc:421
static long long LinkBytesIn
Definition: XrdLinkXeq.hh:164
void * CloseRequestCbArg
Definition: XrdLinkXeq.hh:189
int TLS_RecvAll(char *Buff, int Blen, int timeout)
Definition: XrdLinkXeq.cc:1340
int SFError(int rc)
Definition: XrdLinkXeq.cc:1060
long long BytesIn
Definition: XrdLinkXeq.hh:173
int tardyCntTot
Definition: XrdLinkXeq.hh:180
int Send(const char *buff, int blen)
Definition: XrdLinkXeq.cc:636
XrdSysMutex rdMutex
Definition: XrdLinkXeq.hh:198
const char * verTLS()
Definition: XrdLinkXeq.cc:1494
bool setNB()
Definition: XrdLinkXeq.cc:946
int RecvIOV(const struct iovec *iov, int iocnt)
Definition: XrdLinkXeq.cc:599
char Lname[256]
Definition: XrdLinkXeq.hh:206
static long long LinkConTime
Definition: XrdLinkXeq.hh:166
static int LinkSfIntr
Definition: XrdLinkXeq.hh:172
XrdTlsSocket tlsIO
Definition: XrdLinkXeq.hh:193
void DoIt()
Definition: XrdLinkXeq.cc:306
int RecvAll(char *buff, int blen, int timeout=-1)
Definition: XrdLinkXeq.cc:557
XrdProtocol * Protocol
Definition: XrdLinkXeq.hh:186
bool Register(const char *hName)
Definition: XrdLinkXeq.cc:621
static XrdSysMutex statsMutex
Definition: XrdLinkXeq.hh:182
void setProtName(const char *name)
Definition: XrdLinkXeq.cc:992
static int LinkStalls
Definition: XrdLinkXeq.hh:171
static long long LinkBytesOut
Definition: XrdLinkXeq.hh:165
void syncStats(int *ctime=0)
Definition: XrdLinkXeq.cc:1138
bool setTLS(bool enable, XrdTlsContext *ctx=0)
Definition: XrdLinkXeq.cc:1006
static int LinkTimeOuts
Definition: XrdLinkXeq.hh:170
bool RegisterCloseRequestCb(XrdProtocol *pp, bool(*cb)(void *), void *cbarg)
Definition: XrdLinkXeq.cc:1503
void SetDialect(const char *dP)
Definition: XrdNetAddr.hh:205
void SetTLS(bool val)
Definition: XrdNetAddr.cc:590
void Zorch()
Definition: XrdPollInfo.hh:49
XrdPoll * Poller
Definition: XrdPollInfo.hh:43
virtual int Enable(XrdPollInfo &pInfo)=0
static char * Poll2Text(short events)
Definition: XrdPoll.cc:272
static void Detach(XrdPollInfo &pInfo)
Definition: XrdPoll.cc:177
virtual void Recycle(XrdLink *lp=0, int consec=0, const char *reason=0)=0
virtual int Stats(char *buff, int blen, int do_sync=0)=0
virtual int Process(XrdLink *lp)=0
void Terminate(XrdLink *lP=0)
Definition: XrdSendQ.cc:396
int Send(const char *buff, int blen)
Definition: XrdSendQ.cc:230
unsigned int Backlog()
Definition: XrdSendQ.hh:46
int Emsg(const char *esfx, int ecode, const char *text1, const char *text2=0)
Definition: XrdSysError.cc:95
void Lock(XrdSysMutex *Mutex)
int fd
Socket file descriptor.
Definition: XrdTcpMonPin.hh:61
long long bytesOut
Bytes written to the socket.
Definition: XrdTcpMonPin.hh:64
int consec
Seconds connected.
Definition: XrdTcpMonPin.hh:62
virtual void Monitor(XrdNetAddrInfo &netInfo, LinkInfo &lnkInfo, int liLen)=0
long long bytesIn
Bytes read from the socket.
Definition: XrdTcpMonPin.hh:63
const char * tident
Pointer to the client's trace identifier.
Definition: XrdTcpMonPin.hh:60
@ TLS_HS_BLOCK
Always block during handshake.
Definition: XrdTlsSocket.hh:53
XrdTls::RC Accept(std::string *eMsg=0)
void Shutdown(SDType=sdImmed)
@ TLS_RBL_WBL
blocking read blocking write
Definition: XrdTlsSocket.hh:48
XrdTls::RC Write(const char *buffer, size_t size, int &bytesOut)
const char * Version()
XrdTls::RC Read(char *buffer, size_t size, int &bytesRead)
Read from the TLS connection. If necessary, a handshake will be done.
const char * Init(XrdTlsContext &ctx, int sfd, RW_Mode rwm, HS_Mode hsm, bool isClient, bool serial=true, const char *tid="")
void SetTraceID(const char *tid)
int Pending(bool any=true)
XrdTls::RC Peek(char *buffer, size_t size, int &bytesPeek)
XrdTlsPeerCerts * getCerts(bool ver=true)
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 devNull
Definition: XrdGlobals.cc:55
int getIovMax()
int fdnum
File descriptor for data.
Definition: XrdOucSFVec.hh:47
int sendsz
Length of data at offset.
Definition: XrdOucSFVec.hh:46