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 // Compute the number of link objects we should allocate at a time.
67 // Generally, we like to allocate 8k of them at a time but always
68 // as a power of two.
69 const unsigned int XrdLinkCtl::LinkAlloc = [] {
70 unsigned i = 8192 / sizeof(XrdLink);
71 unsigned j = 1;
72 while (i >>= 1) j <<= 1;
73 return j;
74 } ();
75 int XrdLinkCtl::LTLast = -1;
76 int XrdLinkCtl::maxFD = 0;
77 XrdSysMutex XrdLinkCtl::LTMutex;
78 short XrdLinkCtl::killWait = 3; // Kill then wait;
79 short XrdLinkCtl::waitKill = 4; // Wait then kill
80
81 const char *XrdLinkCtl::TraceID = "LinkCtl";
82
83namespace
84{
85 XrdSysMutex instMutex;
86 unsigned int myInstance = 1;
87 int idleCheck;
88 int idleTicks;
89
90static const int XRDLINK_USED = 0x01;
91static const int XRDLINK_FREE = 0x00;
92
93class LinkScan : public XrdJob
94{
95public:
96
98 Sched.Schedule((XrdJob *)this, idleCheck+time(0));
99 }
100 LinkScan() : XrdJob("Idle link scan") {}
101 ~LinkScan() {}
102};
103}
104
105/******************************************************************************/
106/* A l l o c */
107/******************************************************************************/
108
110{
111 XrdLinkCtl *lp;
112 char hName[1024], *unp, buff[32];
113 int bl, peerFD = peer.SockFD();
114
115// Make sure that the incoming file descriptor can be handled
116//
117 if (peerFD < 0 || peerFD >= maxFD)
118 {snprintf(hName, sizeof(hName), "%d", peerFD);
119 Log.Emsg("Link", "attempt to alloc out of range FD -",hName);
120 return (XrdLink *)0;
121 }
122
123// Make sure that the link slot is available
124//
125 LTMutex.Lock();
126 if (LinkBat[peerFD])
127 {LTMutex.UnLock();
128 snprintf(hName, sizeof(hName), "%d", peerFD);
129 Log.Emsg("Link", "attempt to reuse active link FD -",hName);
130 return (XrdLink *)0;
131 }
132
133// Check if we already have a link object in this slot. If not, allocate
134// a quantum of link objects and put them in the table.
135//
136 if (!(lp = LinkTab[peerFD]))
137 {unsigned int i;
138 XrdLinkCtl **blp, *nlp = new XrdLinkCtl[LinkAlloc]();
139 if (!nlp)
140 {LTMutex.UnLock();
141 Log.Emsg("Link", ENOMEM, "create link");
142 return (XrdLink *)0;
143 }
144 blp = &LinkTab[peerFD/LinkAlloc*LinkAlloc];
145 for (i = 0; i < LinkAlloc; i++, blp++) *blp = &nlp[i];
146 lp = LinkTab[peerFD];
147 }
148 else lp->Reset();
149 LinkBat[peerFD] = XRDLINK_USED;
150 if (peerFD > LTLast) LTLast = peerFD;
151 LTMutex.UnLock();
152
153// Establish the instance number of this link. This is will prevent us from
154// sending asynchronous responses to the wrong client when the file descriptor
155// gets reused for connections to the same host.
156//
157 instMutex.Lock();
158 lp->Instance = myInstance++;
159 instMutex.UnLock();
160
161// Establish the address and connection name of this link
162//
163 peer.Format(hName, sizeof(hName), XrdNetAddr::fmtAuto,
165 lp->HostName = strdup(hName);
166 lp->HNlen = strlen(hName);
167 XrdNetTCP->Trim(hName);
168 lp->Addr = peer;
169 strlcpy(lp->Lname, hName, sizeof(lp->Lname));
170 bl = sprintf(buff, "anon.0:%d", peerFD);
171 unp = lp->Uname + sizeof(Uname) - bl - 1; // Solaris compatibility
172 memcpy(unp, buff, bl);
173 lp->ID = unp;
174 lp->PollInfo.FD = lp->LinkInfo.FD = peerFD;
175 lp->Comment = (const char *)unp;
176
177// Set options as needed
178//
179 lp->LockReads = (0 != (opts & XRDLINK_RDLOCK));
180 lp->KeepFD = (0 != (opts & XRDLINK_NOCLOSE));
181
182// Update statistics and return the link. We need to actually get the stats
183// mutex even when using atomics because we need to use compound operations.
184// The atomics will keep reporters from seeing partial results.
185//
187 AtomicInc(LinkCountTot); // LinkCountTot++
190 return lp;
191}
192
193/******************************************************************************/
194/* F i n d */
195/******************************************************************************/
196
197// Warning: curr must be set to a value of 0 or less on the initial call and
198// not touched therafter unless a null pointer is returned. When an
199// actual link object pointer is returned, it's refcount is increased.
200// The count is automatically decreased on the next call to Find().
201//
203{
204 XrdLinkCtl *lp;
205 const int MaxSeek = 16;
206 unsigned int myINS;
207 int i, seeklim = MaxSeek;
208
209// Do initialization
210//
211 LTMutex.Lock();
212 if (curr >= 0 && LinkTab[curr]) LinkTab[curr]->setRef(-1);
213 else curr = -1;
214
215// Find next matching link. Since this may take some time, we periodically
216// release the LTMutex lock which drives up overhead but will still allow
217// other critical operations to occur.
218//
219 for (i = curr+1; i <= LTLast; i++)
220 {if ((lp = LinkTab[i]) && LinkBat[i] && lp->HostName)
221 if (!who
222 || who->Match(lp->ID,lp->Lname-lp->ID-1,lp->HostName,lp->HNlen))
223 {myINS = lp->Instance;
224 LTMutex.UnLock();
225 lp->setRef(1);
226 curr = i;
227 if (myINS == lp->Instance) return lp;
228 LTMutex.Lock();
229 }
230 if (!seeklim--) {LTMutex.UnLock(); seeklim = MaxSeek; LTMutex.Lock();}
231 }
232
233// Done scanning the table
234//
235 LTMutex.UnLock();
236 curr = -1;
237 return 0;
238}
239
240/******************************************************************************/
241/* g e t N a m e */
242/******************************************************************************/
243
244// Warning: curr must be set to a value of 0 or less on the initial call and
245// not touched therafter unless null is returned. Returns the length
246// the name in nbuf.
247//
248int XrdLinkCtl::getName(int &curr, char *nbuf, int nbsz, XrdLinkMatch *who)
249{
250 XrdLinkCtl *lp;
251 const int MaxSeek = 16;
252 int i, ulen = 0, seeklim = MaxSeek;
253
254// Find next matching link. Since this may take some time, we periodically
255// release the LTMutex lock which drives up overhead but will still allow
256// other critical operations to occur.
257//
258 LTMutex.Lock();
259 for (i = curr+1; i <= LTLast; i++)
260 {if ((lp = LinkTab[i]) && LinkBat[i] && lp->HostName)
261 if (!who
262 || who->Match(lp->ID,lp->Lname-lp->ID-1,lp->HostName,lp->HNlen))
263 {ulen = lp->Client(nbuf, nbsz);
264 LTMutex.UnLock();
265 curr = i;
266 return ulen;
267 }
268 if (!seeklim--) {LTMutex.UnLock(); seeklim = MaxSeek; LTMutex.Lock();}
269 }
270 LTMutex.UnLock();
271
272// Done scanning the table
273//
274 curr = -1;
275 return 0;
276}
277
278/******************************************************************************/
279/* i d l e S c a n */
280/******************************************************************************/
281
282#undef TRACELINK
283#define TRACELINK lp
284
286{
287 XrdLinkCtl *lp;
288 int i, ltlast, lnum = 0, tmo = 0, tmod = 0;
289
290// Get the current link high watermark
291//
292 LTMutex.Lock();
293 ltlast = LTLast;
294 LTMutex.UnLock();
295
296// Scan across all links looking for idle links. Links are never deallocated
297// so we don't need any special kind of lock for these
298//
299 for (i = 0; i <= ltlast; i++)
300 {if (LinkBat[i] != XRDLINK_USED
301 || !(lp = LinkTab[i])) continue;
302 lnum++;
303 lp->LinkInfo.opMutex.Lock();
304 if (lp->isIdle) tmo++;
305 lp->isIdle++;
306 if ((int(lp->isIdle)) < idleTicks)
307 {lp->LinkInfo.opMutex.UnLock(); continue;}
308 lp->isIdle = 0;
309 if (!(lp->PollInfo.Poller) || !(lp->PollInfo.isEnabled))
310 Log.Emsg("LinkScan","Link",lp->ID,"is disabled and idle.");
311 else if (lp->LinkInfo.InUse == 1)
312 {lp->PollInfo.Poller->Disable(lp->PollInfo, "idle timeout");
313 tmod++;
314 }
315 lp->LinkInfo.opMutex.UnLock();
316 }
317
318// Trace what we did
319//
320 TRACE(CONN, lnum <<" links; " <<tmo <<" idle; " <<tmod <<" force closed");
321}
322
323/******************************************************************************/
324/* s e t K W T */
325/******************************************************************************/
326
327void XrdLinkCtl::setKWT(int wkSec, int kwSec)
328{
329 if (wkSec > 0) waitKill = static_cast<short>(wkSec);
330 if (kwSec > 0) killWait = static_cast<short>(kwSec);
331}
332
333/******************************************************************************/
334/* S e t u p */
335/******************************************************************************/
336
337int XrdLinkCtl::Setup(int maxfds, int idlewait)
338{
339 maxFD = maxfds;
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
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)
#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
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)
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
void syncStats(int *ctime=0)
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
XrdPoll * Poller
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)
XrdInet * XrdNetTCP
Definition XrdGlobals.cc:53
XrdSysError Log
Definition XrdConfig.cc:113
XrdScheduler Sched
Definition XrdLinkCtl.cc:54