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