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 = 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//
179 AtomicInc(LinkCountTot); // LinkCountTot++
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//
240int 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
319void 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
329int 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
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}
#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
virtual void DoIt()=0
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:111
XrdScheduler Sched
Definition XrdLinkCtl.cc:54