XRootD
XrdLinkCtl.cc
Go to the documentation of this file.
1 /******************************************************************************/
2 /* */
3 /* X r d L i n k C t l . 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 <sys/types.h>
31 #include <fcntl.h>
32 #include <ctime>
33 
34 #include "Xrd/XrdInet.hh"
35 #include "Xrd/XrdLinkCtl.hh"
36 #include "Xrd/XrdLinkMatch.hh"
37 #include "Xrd/XrdPoll.hh"
38 #include "Xrd/XrdScheduler.hh"
39 
40 #define TRACELINK this
41 #include "Xrd/XrdTrace.hh"
42 
43 #include "XrdSys/XrdSysAtomics.hh"
44 #include "XrdSys/XrdSysLogger.hh"
45 #include "XrdSys/XrdSysPthread.hh"
46 
47 /******************************************************************************/
48 /* G l o b a l O b j e c t s */
49 /******************************************************************************/
50 
51 namespace XrdGlobal
52 {
53 extern XrdSysError Log;
55 extern XrdInet *XrdNetTCP;
56 };
57 
58 using namespace XrdGlobal;
59 
60 /******************************************************************************/
61 /* S t a t i c s */
62 /******************************************************************************/
63 
64  XrdLinkCtl **XrdLinkCtl::LinkTab = 0;
65  char *XrdLinkCtl::LinkBat = 0;
66  unsigned int XrdLinkCtl::LinkAlloc= 0;
67  int XrdLinkCtl::LTLast = -1;
68  int XrdLinkCtl::maxFD = 0;
69  XrdSysMutex XrdLinkCtl::LTMutex;
70  short XrdLinkCtl::killWait = 3; // Kill then wait;
71  short XrdLinkCtl::waitKill = 4; // Wait then kill
72 
73  const char *XrdLinkCtl::TraceID = "LinkCtl";
74 
75 namespace
76 {
77  XrdSysMutex instMutex;
78  unsigned int myInstance = 1;
79  int idleCheck;
80  int idleTicks;
81 
82 static const int XRDLINK_USED = 0x01;
83 static const int XRDLINK_FREE = 0x00;
84 
85 class LinkScan : public XrdJob
86 {
87 public:
88 
89 void DoIt() {XrdLinkCtl::idleScan();
90  Sched.Schedule((XrdJob *)this, idleCheck+time(0));
91  }
92  LinkScan() : XrdJob("Idle link scan") {}
93  ~LinkScan() {}
94 };
95 }
96 
97 /******************************************************************************/
98 /* A l l o c */
99 /******************************************************************************/
100 
102 {
103  XrdLinkCtl *lp;
104  char hName[1024], *unp, buff[32];
105  int bl, peerFD = peer.SockFD();
106 
107 // Make sure that the incoming file descriptor can be handled
108 //
109  if (peerFD < 0 || peerFD >= maxFD)
110  {snprintf(hName, sizeof(hName), "%d", peerFD);
111  Log.Emsg("Link", "attempt to alloc out of range FD -",hName);
112  return (XrdLink *)0;
113  }
114 
115 // Make sure that the link slot is available
116 //
117  LTMutex.Lock();
118  if (LinkBat[peerFD])
119  {LTMutex.UnLock();
120  snprintf(hName, sizeof(hName), "%d", peerFD);
121  Log.Emsg("Link", "attempt to reuse active link FD -",hName);
122  return (XrdLink *)0;
123  }
124 
125 // Check if we already have a link object in this slot. If not, allocate
126 // a quantum of link objects and put them in the table.
127 //
128  if (!(lp = LinkTab[peerFD]))
129  {unsigned int i;
130  XrdLinkCtl **blp, *nlp = new XrdLinkCtl[LinkAlloc]();
131  if (!nlp)
132  {LTMutex.UnLock();
133  Log.Emsg("Link", ENOMEM, "create link");
134  return (XrdLink *)0;
135  }
136  blp = &LinkTab[peerFD/LinkAlloc*LinkAlloc];
137  for (i = 0; i < LinkAlloc; i++, blp++) *blp = &nlp[i];
138  lp = LinkTab[peerFD];
139  }
140  else lp->Reset();
141  LinkBat[peerFD] = XRDLINK_USED;
142  if (peerFD > LTLast) LTLast = peerFD;
143  LTMutex.UnLock();
144 
145 // Establish the instance number of this link. This is will prevent us from
146 // sending asynchronous responses to the wrong client when the file descriptor
147 // gets reused for connections to the same host.
148 //
149  instMutex.Lock();
150  lp->Instance = myInstance++;
151  instMutex.UnLock();
152 
153 // Establish the address and connection name of this link
154 //
155  peer.Format(hName, sizeof(hName), XrdNetAddr::fmtAuto,
157  lp->HostName = strdup(hName);
158  lp->HNlen = strlen(hName);
159  XrdNetTCP->Trim(hName);
160  lp->Addr = peer;
161  strlcpy(lp->Lname, hName, sizeof(lp->Lname));
162  bl = sprintf(buff, "anon.0:%d", peerFD);
163  unp = lp->Uname + sizeof(Uname) - bl - 1; // Solaris compatibility
164  memcpy(unp, buff, bl);
165  lp->ID = unp;
166  lp->PollInfo.FD = lp->LinkInfo.FD = peerFD;
167  lp->Comment = (const char *)unp;
168 
169 // Set options as needed
170 //
171  lp->LockReads = (0 != (opts & XRDLINK_RDLOCK));
172  lp->KeepFD = (0 != (opts & XRDLINK_NOCLOSE));
173 
174 // Update statistics and return the link. We need to actually get the stats
175 // mutex even when using atomics because we need to use compound operations.
176 // The atomics will keep reporters from seeing partial results.
177 //
178  statsMutex.Lock();
179  AtomicInc(LinkCountTot); // LinkCountTot++
180  if (LinkCountMax <= AtomicInc(LinkCount)) LinkCountMax = LinkCount;
181  statsMutex.UnLock();
182  return lp;
183 }
184 
185 /******************************************************************************/
186 /* F i n d */
187 /******************************************************************************/
188 
189 // Warning: curr must be set to a value of 0 or less on the initial call and
190 // not touched therafter unless a null pointer is returned. When an
191 // actual link object pointer is returned, it's refcount is increased.
192 // The count is automatically decreased on the next call to Find().
193 //
195 {
196  XrdLinkCtl *lp;
197  const int MaxSeek = 16;
198  unsigned int myINS;
199  int i, seeklim = MaxSeek;
200 
201 // Do initialization
202 //
203  LTMutex.Lock();
204  if (curr >= 0 && LinkTab[curr]) LinkTab[curr]->setRef(-1);
205  else curr = -1;
206 
207 // Find next matching link. Since this may take some time, we periodically
208 // release the LTMutex lock which drives up overhead but will still allow
209 // other critical operations to occur.
210 //
211  for (i = curr+1; i <= LTLast; i++)
212  {if ((lp = LinkTab[i]) && LinkBat[i] && lp->HostName)
213  if (!who
214  || who->Match(lp->ID,lp->Lname-lp->ID-1,lp->HostName,lp->HNlen))
215  {myINS = lp->Instance;
216  LTMutex.UnLock();
217  lp->setRef(1);
218  curr = i;
219  if (myINS == lp->Instance) return lp;
220  LTMutex.Lock();
221  }
222  if (!seeklim--) {LTMutex.UnLock(); seeklim = MaxSeek; LTMutex.Lock();}
223  }
224 
225 // Done scanning the table
226 //
227  LTMutex.UnLock();
228  curr = -1;
229  return 0;
230 }
231 
232 /******************************************************************************/
233 /* g e t N a m e */
234 /******************************************************************************/
235 
236 // Warning: curr must be set to a value of 0 or less on the initial call and
237 // not touched therafter unless null is returned. Returns the length
238 // the name in nbuf.
239 //
240 int XrdLinkCtl::getName(int &curr, char *nbuf, int nbsz, XrdLinkMatch *who)
241 {
242  XrdLinkCtl *lp;
243  const int MaxSeek = 16;
244  int i, ulen = 0, seeklim = MaxSeek;
245 
246 // Find next matching link. Since this may take some time, we periodically
247 // release the LTMutex lock which drives up overhead but will still allow
248 // other critical operations to occur.
249 //
250  LTMutex.Lock();
251  for (i = curr+1; i <= LTLast; i++)
252  {if ((lp = LinkTab[i]) && LinkBat[i] && lp->HostName)
253  if (!who
254  || who->Match(lp->ID,lp->Lname-lp->ID-1,lp->HostName,lp->HNlen))
255  {ulen = lp->Client(nbuf, nbsz);
256  LTMutex.UnLock();
257  curr = i;
258  return ulen;
259  }
260  if (!seeklim--) {LTMutex.UnLock(); seeklim = MaxSeek; LTMutex.Lock();}
261  }
262  LTMutex.UnLock();
263 
264 // Done scanning the table
265 //
266  curr = -1;
267  return 0;
268 }
269 
270 /******************************************************************************/
271 /* i d l e S c a n */
272 /******************************************************************************/
273 
274 #undef TRACELINK
275 #define TRACELINK lp
276 
278 {
279  XrdLinkCtl *lp;
280  int i, ltlast, lnum = 0, tmo = 0, tmod = 0;
281 
282 // Get the current link high watermark
283 //
284  LTMutex.Lock();
285  ltlast = LTLast;
286  LTMutex.UnLock();
287 
288 // Scan across all links looking for idle links. Links are never deallocated
289 // so we don't need any special kind of lock for these
290 //
291  for (i = 0; i <= ltlast; i++)
292  {if (LinkBat[i] != XRDLINK_USED
293  || !(lp = LinkTab[i])) continue;
294  lnum++;
295  lp->LinkInfo.opMutex.Lock();
296  if (lp->isIdle) tmo++;
297  lp->isIdle++;
298  if ((int(lp->isIdle)) < idleTicks)
299  {lp->LinkInfo.opMutex.UnLock(); continue;}
300  lp->isIdle = 0;
301  if (!(lp->PollInfo.Poller) || !(lp->PollInfo.isEnabled))
302  Log.Emsg("LinkScan","Link",lp->ID,"is disabled and idle.");
303  else if (lp->LinkInfo.InUse == 1)
304  {lp->PollInfo.Poller->Disable(lp->PollInfo, "idle timeout");
305  tmod++;
306  }
307  lp->LinkInfo.opMutex.UnLock();
308  }
309 
310 // Trace what we did
311 //
312  TRACE(CONN, lnum <<" links; " <<tmo <<" idle; " <<tmod <<" force closed");
313 }
314 
315 /******************************************************************************/
316 /* s e t K W T */
317 /******************************************************************************/
318 
319 void XrdLinkCtl::setKWT(int wkSec, int kwSec)
320 {
321  if (wkSec > 0) waitKill = static_cast<short>(wkSec);
322  if (kwSec > 0) killWait = static_cast<short>(kwSec);
323 }
324 
325 /******************************************************************************/
326 /* S e t u p */
327 /******************************************************************************/
328 
329 int XrdLinkCtl::Setup(int maxfds, int idlewait)
330 {
331  int numalloc;
332 
333 // Compute the number of link objects we should allocate at a time. Generally,
334 // we like to allocate 8k of them at a time but always as a power of two.
335 //
336  maxFD = maxfds;
337  numalloc = 8192 / sizeof(XrdLink);
338  LinkAlloc = 1;
339  while((numalloc = numalloc/2)) LinkAlloc = LinkAlloc*2;
340  TRACE(DEBUG, "Allocating " <<LinkAlloc <<" link objects at a time");
341 
342 // Create the link table
343 //
344  if (!(LinkTab = (XrdLinkCtl **)malloc(maxfds*sizeof(XrdLinkCtl*)+LinkAlloc)))
345  {Log.Emsg("Link", ENOMEM, "create LinkTab"); return 0;}
346  memset((void *)LinkTab, 0, maxfds*sizeof(XrdLinkCtl *));
347 
348 // Create the slot status table
349 //
350  if (!(LinkBat = (char *)malloc(maxfds*sizeof(char)+LinkAlloc)))
351  {Log.Emsg("Link", ENOMEM, "create LinkBat"); return 0;}
352  memset((void *)LinkBat, XRDLINK_FREE, maxfds*sizeof(char));
353 
354 // Create an idle connection scan job
355 //
356  if (idlewait)
357  {if ((idleCheck = idlewait/3)) idleTicks = 3;
358  else {idleTicks = 1;
359  idleCheck = idlewait;
360  }
361  LinkScan *ls = new LinkScan;
362  Sched.Schedule((XrdJob *)ls, idleCheck+time(0));
363  }
364 
365 // All done
366 //
367  return 1;
368 }
369 
370 /******************************************************************************/
371 /* S y n c A l l */
372 /******************************************************************************/
373 
375 {
376  int myLTLast;
377 
378 // Get the current last entry
379 //
380  LTMutex.Lock(); myLTLast = LTLast; LTMutex.UnLock();
381 
382 // Run through all the links and sync the statistics
383 //
384  for (int i = 0; i <= myLTLast; i++)
385  {if (LinkBat[i] == XRDLINK_USED && LinkTab[i]) LinkTab[i]->syncStats();}
386 }
387 
388 /******************************************************************************/
389 /* U n h o o k */
390 /******************************************************************************/
391 
392 void XrdLinkCtl::Unhook(int fd)
393 {
394 
395 // Indicate link no longer actvely neing used
396 //
397  LTMutex.Lock();
398  LinkBat[fd] = XRDLINK_FREE;
399  if (fd == LTLast) while(LTLast && !(LinkBat[LTLast])) LTLast--;
400  LTMutex.UnLock();
401 }
int DoIt(int argpnt, int argc, char **argv, bool singleshot)
Definition: XrdAccTest.cc:262
#define DEBUG(x)
Definition: XrdBwmTrace.hh:54
#define XRDLINK_NOCLOSE
Definition: XrdLinkCtl.hh:59
#define XRDLINK_RDLOCK
Definition: XrdLinkCtl.hh:58
struct myOpts opts
#define AtomicInc(x)
size_t strlcpy(char *dst, const char *src, size_t sz)
#define TRACE(act, x)
Definition: XrdTrace.hh:63
Definition: XrdJob.hh:43
const char * Comment
Definition: XrdJob.hh:47
static XrdLink * Alloc(XrdNetAddr &peer, int opts=0)
Definition: XrdLinkCtl.cc:101
static void SyncAll()
Synchronize statustics for ll links.
Definition: XrdLinkCtl.cc:374
static short waitKill
Definition: XrdLinkCtl.hh:191
static int Setup(int maxfds, int idlewt)
Definition: XrdLinkCtl.cc:329
static XrdLink * Find(int &curr, XrdLinkMatch *who=0)
Definition: XrdLinkCtl.cc:194
static void setKWT(int wkSec, int kwSec)
Definition: XrdLinkCtl.cc:319
static void idleScan()
Look for idle links and close hem down.
Definition: XrdLinkCtl.cc:277
static short killWait
Link destruction control constants.
Definition: XrdLinkCtl.hh:190
static int getName(int &curr, char *bname, int blen, XrdLinkMatch *who=0)
Definition: XrdLinkCtl.cc:240
static void Unhook(int fd)
Unhook a link from the active table of links.
Definition: XrdLinkCtl.cc:392
XrdSysRecMutex opMutex
Definition: XrdLinkInfo.hh:46
int Match(const char *uname, int unlen, const char *hname, int hnlen)
Definition: XrdLinkMatch.cc:39
int Client(char *buff, int blen)
Definition: XrdLinkXeq.cc:168
char Uname[24]
Definition: XrdLinkXeq.hh:200
XrdLinkInfo LinkInfo
Definition: XrdLinkXeq.hh:144
XrdNetAddr Addr
Definition: XrdLinkXeq.hh:192
void Reset()
Definition: XrdLinkXeq.cc:129
XrdPollInfo PollInfo
Definition: XrdLinkXeq.hh:145
bool LockReads
Definition: XrdLinkXeq.hh:197
char Lname[256]
Definition: XrdLinkXeq.hh:201
static const int noPort
Do not add port number.
static const int old6Map4
Use deprecated IPV6 mapped format.
int Format(char *bAddr, int bLen, fmtUse fmtType=fmtAuto, int fmtOpts=0)
@ fmtAuto
Hostname if already resolved o/w use fmtAddr.
void Trim(char *hname)
Definition: XrdNet.cc:343
bool isEnabled
Definition: XrdPollInfo.hh:46
XrdPoll * Poller
Definition: XrdPollInfo.hh:43
virtual void Disable(XrdPollInfo &pInfo, const char *etxt=0)=0
void Schedule(XrdJob *jp)
int Emsg(const char *esfx, int ecode, const char *text1, const char *text2=0)
Definition: XrdSysError.cc:95
XrdInet * XrdNetTCP
Definition: XrdGlobals.cc:53
XrdSysError Log
Definition: XrdConfig.cc:111
XrdScheduler Sched
Definition: XrdLinkCtl.cc:54