XRootD
Loading...
Searching...
No Matches
XrdXrootdMonitor.cc
Go to the documentation of this file.
1/******************************************************************************/
2/* */
3/* X r d X r o o t d M o n i t o r . c c */
4/* */
5/* (c) 2004 by the Board of Trustees of the Leland Stanford, Jr., University */
6/* All Rights Reserved */
7/* Produced by Andrew Hanushevsky for Stanford University under contract */
8/* DE-AC02-76-SFO0515 with the Department of Energy */
9/* */
10/* This file is part of the XRootD software suite. */
11/* */
12/* XRootD is free software: you can redistribute it and/or modify it under */
13/* the terms of the GNU Lesser General Public License as published by the */
14/* Free Software Foundation, either version 3 of the License, or (at your */
15/* option) any later version. */
16/* */
17/* XRootD is distributed in the hope that it will be useful, but WITHOUT */
18/* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or */
19/* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public */
20/* License for more details. */
21/* */
22/* You should have received a copy of the GNU Lesser General Public License */
23/* along with XRootD in a file called COPYING.LESSER (LGPL license) and file */
24/* COPYING (GPL license). If not, see <http://www.gnu.org/licenses/>. */
25/* */
26/* The copyright holder's institutional names and contributor's names may not */
27/* be used to endorse or promote products derived from this software without */
28/* specific prior written permission of the institution or contributor. */
29/******************************************************************************/
30
31#include <algorithm>
32#include <cerrno>
33#include <cstdio>
34#include <cstdlib>
35#include <cstring>
36#include <ctime>
37#include <unistd.h>
38#include <sys/types.h>
39
40#include "XrdVersion.hh"
41
42#include "XrdNet/XrdNetMsg.hh"
43#include "XrdOuc/XrdOucEnv.hh"
44#include "XrdOuc/XrdOucUtils.hh"
45#include "XrdSys/XrdSysError.hh"
47
48#include "Xrd/XrdScheduler.hh"
52
53/******************************************************************************/
54/* S t a t i c A l l o c a t i o n */
55/******************************************************************************/
56
57char *XrdXrootdMonitor::idRec = 0;
58int XrdXrootdMonitor::idLen = 0;
59char *XrdXrootdMonitor::Dest1 = 0;
60int XrdXrootdMonitor::monMode1 = 0;
61XrdNetMsg *XrdXrootdMonitor::InetDest1 = 0;
62char *XrdXrootdMonitor::Dest2 = 0;
63int XrdXrootdMonitor::monMode2 = 0;
64XrdNetMsg *XrdXrootdMonitor::InetDest2 = 0;
66XrdSysMutex XrdXrootdMonitor::windowMutex;
67int XrdXrootdMonitor::monRlen = 0;
68XrdXrootdMonitor::MonRdrBuff
69 XrdXrootdMonitor::rdrMon[XrdXrootdMonitor::rdrMax];
70XrdXrootdMonitor::MonRdrBuff
71 *XrdXrootdMonitor::rdrMP = 0;
72XrdSysMutex XrdXrootdMonitor::rdrMutex;
73int XrdXrootdMonitor::monBlen = 0;
74int XrdXrootdMonitor::lastEnt = 0;
75int XrdXrootdMonitor::lastRnt = 0;
76int XrdXrootdMonitor::isEnabled = 0;
77int XrdXrootdMonitor::numMonitor = 0;
78int XrdXrootdMonitor::autoFlash = 0;
79int XrdXrootdMonitor::autoFlush = 600;
80int XrdXrootdMonitor::FlushTime = 0;
81int XrdXrootdMonitor::monIdent = 3600;
82kXR_int32 XrdXrootdMonitor::currWindow = 0;
83int XrdXrootdMonitor::rdrTOD = 0;
84int XrdXrootdMonitor::rdrWin = 0;
85int XrdXrootdMonitor::rdrNum = 3;
86kXR_int32 XrdXrootdMonitor::sizeWindow = 60;
87char XrdXrootdMonitor::monINFO = 0;
88char XrdXrootdMonitor::monIO = 0;
89char XrdXrootdMonitor::monFILE = 0;
90char XrdXrootdMonitor::monREDR = 0;
91char XrdXrootdMonitor::monUSER = 0;
92char XrdXrootdMonitor::monAUTH = 0;
93char XrdXrootdMonitor::monACTIVE = 0;
94char XrdXrootdMonitor::monFSTAT = 0;
95char XrdXrootdMonitor::monCLOCK = 0;
96
97/******************************************************************************/
98/* G l o b a l s */
99/******************************************************************************/
100
102
103namespace XrdXrootdMonInfo
104{
105
106inline static int32_t InitStartTime()
107{
108 return htonl( time( 0 ) );
109}
110
112XrdSysError *eDest = 0;
113char *monHost = 0;
114char *kySID = 0;
115long long mySID = 0;
116int32_t startTime = InitStartTime();
117int kySIDSZ = 0;
119
120char *SidCGI[4] = {0};
121int LidCGI[4] = {0};
122char *SidJSON[4]= {0}; // 0:sidsite 1:sidhostid 2:sidinst 3:sidfull
123int LidJSON[4]= {0};
124}
125
126using namespace XrdXrootdMonInfo;
127
128/******************************************************************************/
129/* L o c a l D e f i n e s */
130/******************************************************************************/
131
132#define setTMark(TM_mb, TM_en, TM_tm) \
133 TM_mb->info[TM_en].arg0.val = mySID; \
134 TM_mb->info[TM_en].arg0.id[0] = XROOTD_MON_WINDOW; \
135 TM_mb->info[TM_en].arg1.Window = \
136 TM_mb->info[TM_en].arg2.Window = static_cast<kXR_int32>(ntohl(TM_tm));
137
138#define setTMurk(TM_mb, TM_en, TM_tm) \
139 TM_mb->info[TM_en].arg0.Window = rdrWin; \
140 TM_mb->info[TM_en].arg1.Window = static_cast<kXR_int32>(TM_tm);
141
142/******************************************************************************/
143/* L o c a l C l a s s e s */
144/******************************************************************************/
145/******************************************************************************/
146/* X r d X r o o t d M o n i t o r _ I d e n t */
147/******************************************************************************/
148
150{
151public:
152
153void DoIt() {
154 if (idInt >= 0)
155 {if (doIdnt) XrdXrootdMonitor::Ident();
156 if (doHail) doHail = XrdXrootdMonitor::Hello::Hail();
157 }
158 if ((doIdnt || doHail) && idInt > 0)
159 Sched->Schedule((XrdJob *)this, time(0)+idInt);
160 }
161
162 XrdXrootdMonitor_Ident(int idt, bool ison) : XrdJob("monitor ident"),
163 idInt(idt), doIdnt(ison), doHail(true) {}
165
166private:
167int idInt;
168bool doIdnt;
169bool doHail;
170};
171
172/******************************************************************************/
173/* C l a s s X r d X r o o t d M o n i t o r _ T i c k */
174/******************************************************************************/
175
177{
178public:
179
180void DoIt() {
181#ifndef NODEBUG
182 const char *TraceID = "MonTick";
183#endif
184 time_t Now = XrdXrootdMonitor::Tick();
185 if (Window && Now)
186 Sched->Schedule((XrdJob *)this, Now+Window);
187 else {TRACE(DEBUG, "Monitor clock stopping.");}
188 }
189
190void Set(XrdScheduler *sp, int intvl) {Sched = sp; Window = intvl;}
191
192 XrdXrootdMonitor_Tick() : XrdJob("monitor window clock"),
193 Sched(0), Window(0) {}
195
196private:
197XrdScheduler *Sched; // System scheduler
198int Window;
199};
200
201/******************************************************************************/
202/* C l a s s X r d X r o o t d M o n i t o r L o c k */
203/******************************************************************************/
204
206{
207public:
208
209static void Lock() {monLock.Lock();}
210
211static void UnLock() {monLock.UnLock();}
212
214 {if (theMonitor != XrdXrootdMonitor::altMon) unLock = 0;
215 else {unLock = 1; monLock.Lock();}
216 }
217 ~XrdXrootdMonitorLock() {if (unLock) monLock.UnLock();}
218
219private:
220
221static XrdSysMutex monLock;
222 char unLock;
223};
224
225XrdSysMutex XrdXrootdMonitorLock::monLock;
226
227/******************************************************************************/
228/* X r d X r o o t d M o n i t o r : : H e l l o */
229/******************************************************************************/
230
231XrdXrootdMonitor::Hello::Hello(const char *dest, char mode)
232 : Next(0), theDest(0), theMode(0)
233{
234 if (dest)
235 {Hello *nP = First;
236 while(nP) {if (!strcmp(dest, nP->theDest) && mode == theMode) return;
237 nP = nP->Next;
238 }
239 Next = First;
240 First = this;
241 theDest = strdup(dest);
242 theMode = mode;
243 }
244}
245
246/******************************************************************************/
247/* X r d X r o o t d M o n i t o r : : H e l l o : : H a i l */
248/******************************************************************************/
249
250XrdXrootdMonitor::Hello *XrdXrootdMonitor::Hello::First = 0;
251
253{
254 Hello *nP = First;
255
256// Call all the registered ident methods
257//
258 while(nP) {nP->Ident(); nP = nP->Next;}
259
260// Indicate whether or not anything would have been sent
261//
262 return First != 0;
263}
264
265/******************************************************************************/
266/* X r d X r o o t d M o n i t o r : : U s e r : : D i s a b l e */
267/******************************************************************************/
268
270{
271 if (Agent)
272 {XrdXrootdMonitor::unAlloc(Agent); Agent = 0;}
273 Fops = Iops = 0;
274}
275
276/******************************************************************************/
277/* X r d X r o o t d M o n i t o r : : U s e r : : E n a b l e */
278/******************************************************************************/
279
281{
282 if (Agent || (Agent = XrdXrootdMonitor::Alloc(1)))
283 {Iops = XrdXrootdMonitor::monIO;
284 Fops = XrdXrootdMonitor::monFILE;
285 } else Iops = Fops = 0;
286}
287
288/******************************************************************************/
289/* X r d X r o o t d M o n i t o r : : U s e r : : R e g i s t e r */
290/******************************************************************************/
291
292void XrdXrootdMonitor::User::Register(const char *Uname,
293 const char *Hname,
294 const char *Pname, unsigned int xSID)
295{
296#ifndef NODEBUG
297 const char *TraceID = "Monitor";
298#endif
299 char *dotP, *colonP, *atP;
300 char uBuff[1024], tBuff[1024], sBuff[64];
301
302// Decode the user name as a.b:c@d and remap it for monitoring as
303// <protocol>/a.{b|xSID}:<kySID>@host
304//
305 snprintf(tBuff, sizeof(tBuff), "%s", Uname);
306 if ((dotP = index(tBuff, '.')) && (colonP = index(dotP+1, ':')) &&
307 (atP = index(colonP+1, '@')))
308 {*dotP = 0; *colonP = 0; *atP = 0;
309 if (xSID)
310 {snprintf(sBuff, sizeof(sBuff), " %u", xSID);
311 dotP = sBuff;
312 }
313
314 int n = snprintf(uBuff, sizeof(uBuff), "%s/%s.%s:%s@%s", Pname, tBuff,
315 dotP+1, kySID, atP+1);
316
317 if (n < 0 || n >= (int) sizeof(uBuff))
318 TRACE(LOGIN, "Login ID was truncated: " << uBuff);
319
320 if (xSID) {TRACE(LOGIN,"Register remap "<<Uname<<" -> "<<uBuff);}
321 } else snprintf(uBuff, sizeof(uBuff), "%s/%s", Pname, Uname);
322
323// Generate a monitor identity for this user. We do not assign a dictioary
324// identifier unless this entry is reported.
325//
326 Agent = XrdXrootdMonitor::Alloc();
327 Did = 0;
328 Len = strlen(uBuff);
329 Name = strdup(uBuff);
330 Iops = XrdXrootdMonitor::monIO;
331 Fops = XrdXrootdMonitor::monFILE;
332}
333
334/******************************************************************************/
335/* R e p o r t */
336/******************************************************************************/
337
338void XrdXrootdMonitor::User::Report(int eCode, int aCode)
339{
340 char buff[1024];
341
342 snprintf(buff, sizeof(buff), "&Uc=%u&Ec=%d&Ac=%d", ntohl(Did), eCode, aCode);
343
344 XrdXrootdMonitor::Map(XROOTD_MON_MAPUEAC,*this,buff);
345}
346
347/******************************************************************************/
348
349bool XrdXrootdMonitor::User::Report(WhatInfo infoT, const char *info)
350{
351 char buff[4096];
352
353// Currently we support only the token external report
354//
355 if (infoT != TokenInfo) return false;
356
357 snprintf(buff, sizeof(buff), "&Uc=%u%s%s", ntohl(Did),
358 (*info == '&' ? "" : "&"), info);
359
360 XrdXrootdMonitor::Map(XROOTD_MON_MAPTOKN,*this,buff);
361
362 return true;
363}
364/******************************************************************************/
365/* C o n s t r u c t o r */
366/******************************************************************************/
367
369{
370 kXR_int32 localWindow;
371
372// Initialize last window to force a mark as well as the local window
373//
374 lastWindow = 0;
375 localWindow = currWindow;
376
377// Allocate a monitor buffer
378//
379 if (posix_memalign((void **)&monBuff, getpagesize(), monBlen))
380 eDest->Emsg("Monitor", "Unable to allocate monitor buffer.");
381 else {nextEnt = 1;
382 setTMark(monBuff, 0, localWindow);
383 }
384}
385
386/******************************************************************************/
387/* D e s t r u c t o r */
388/******************************************************************************/
389
390XrdXrootdMonitor::~XrdXrootdMonitor()
391{
392// Release buffer
393 if (monBuff) {Flush(); free(monBuff);}
394}
395
396/******************************************************************************/
397/* a p p I D */
398/******************************************************************************/
399
401{
402 static const int apInfoSize = sizeof(XrdXrootdMonTrace)-4;
403
404// Application ID's are only meaningful for io event recording
405//
406 if (this == altMon || !*id) return;
407
408// Fill out the monitor record
409//
410 if (lastWindow != currWindow) Mark();
411 else if (nextEnt == lastEnt) Flush();
412 monBuff->info[nextEnt].arg0.id[0] = XROOTD_MON_APPID;
413 strncpy((char *)(&(monBuff->info[nextEnt])+4), id, apInfoSize);
414}
415
416/******************************************************************************/
417/* A l l o c */
418/******************************************************************************/
419
420XrdXrootdMonitor *XrdXrootdMonitor::Alloc(int force)
421{
423 int lastVal;
424
425// If enabled, create a new object (if possible). If we are not monitoring
426// i/o then return the global object.
427//
428// if (!isEnabled || (isEnabled < 0 && !force)) mp = 0;
429 if (!isEnabled) mp = 0;
430 else if (!monIO) mp = altMon;
431 else if ((mp = new XrdXrootdMonitor()))
432 if (!(mp->monBuff)) {delete mp; mp = 0;}
433
434// Check if we should turn on the monitor clock
435//
436 if (mp && isEnabled < 0)
437 {windowMutex.Lock();
438 lastVal = numMonitor; numMonitor++;
439 if (!lastVal && !monREDR) startClock();
440 windowMutex.UnLock();
441 }
442
443// All done
444//
445 return mp;
446}
447
448/******************************************************************************/
449/* C l o s e */
450/******************************************************************************/
451
452void XrdXrootdMonitor::Close(kXR_unt32 dictid, long long rTot, long long wTot)
453{
454 XrdXrootdMonitorLock mLock(this);
455 unsigned int rVal, wVal;
456
457// Fill out the monitor record (we allow the compiler to correctly cast data)
458//
459 if (lastWindow != currWindow) Mark();
460 else if (nextEnt == lastEnt) Flush();
461 monBuff->info[nextEnt].arg0.id[0] = XROOTD_MON_CLOSE;
462 monBuff->info[nextEnt].arg0.id[1] = do_Shift(rTot, rVal);
463 monBuff->info[nextEnt].arg0.rTot[1] = htonl(rVal);
464 monBuff->info[nextEnt].arg0.id[2] = do_Shift(wTot, wVal);
465 monBuff->info[nextEnt].arg0.id[3] = 0;
466 monBuff->info[nextEnt].arg1.wTot = htonl(wVal);
467 monBuff->info[nextEnt++].arg2.dictid = dictid;
468
469// Check if we need to duplicate this entry
470//
471 if (altMon && this != altMon) altMon->Dup(&monBuff->info[nextEnt-1]);
472}
473
474/******************************************************************************/
475/* C o p y T e x t */
476/******************************************************************************/
477
478int XrdXrootdMonitor::CopyText(char *buff, int room, const char *text, int tLen)
479{
480// A record that binds text to a dictid must fit its buffer. So truncate the
481// text, rather than drop the record, and null pad the rest of the buffer. At
482// least one null byte always ends the text. The caller gives the length of
483// the text, because it needs the length to size the record.
484//
485 if (room <= 0) return 0;
486 if (tLen > room - 1) tLen = room - 1;
487 memcpy(buff, text, tLen);
488 memset(buff + tLen, 0, room - tLen);
489 return tLen;
490}
491
492/******************************************************************************/
493/* D e f a u l t s */
494/******************************************************************************/
495
496// This version must be called after the subsequent version!
497
498void XrdXrootdMonitor::Defaults(char *dest1, int mode1, char *dest2, int mode2)
499{
500 int mmode;
501
502// If there are no destination then only g-stream events may be enabled.
503// Otherwise, sort out the destinations relative to modes.
504//
505 if (!dest1 && !dest2) {isEnabled = 0; return;}
506 if (!dest1) {dest1 = dest2; dest2 = 0; mode1 |= mode2; mode2 = 0;}
507
508// Set the default destinations (caller supplied strdup'd strings)
509//
510 if (Dest1) free(Dest1);
511 Dest1 = dest1; monMode1 = mode1;
512 if (Dest2) free(Dest2);
513 Dest2 = dest2; monMode2 = mode2;
514
515// Set overall monitor mode
516//
517 mmode = mode1 | mode2;
518 monACTIVE = (mmode ? 1 : 0);
519 isEnabled = (mmode & XROOTD_MON_ALL ? 1 :-1);
520 monIO = (mmode & XROOTD_MON_IO ? 1 : 0);
521 monIO = (mmode & XROOTD_MON_IOV ? 2 : monIO);
522 monINFO = (mmode & XROOTD_MON_INFO ? 1 : 0);
523 monFILE = (mmode & XROOTD_MON_FILE ? 1 : 0) | monIO;
524 monREDR = (mmode & XROOTD_MON_REDR ? 1 : 0);
525 monUSER = (mmode & XROOTD_MON_USER ? 1 : 0);
526 monAUTH = (mmode & XROOTD_MON_AUTH ? 1 : 0);
527 monFSTAT = (mmode & XROOTD_MON_FSTA && monFSTAT ? 1 : 0);
528
529// Compute whether or not we need the clock running
530//
531 if (monREDR || (isEnabled > 0 && (monIO || monFILE))) monCLOCK = 1;
532
533// Check where user information should go
534//
535 if (((mode1 & XROOTD_MON_IO) && (mode1 & XROOTD_MON_USER))
536 || ((mode2 & XROOTD_MON_IO) && (mode2 & XROOTD_MON_USER)))
537 {if ((!(mode1 & XROOTD_MON_IO) && (mode1 & XROOTD_MON_USER))
538 || (!(mode2 & XROOTD_MON_IO) && (mode2 & XROOTD_MON_USER))) monUSER = 3;
539 else monUSER = 2;
540 }
541
542// If we are monitoring redirections then set an envar saying how often idents
543// should be sent (this also tips off other layers to handle such monitoring)
544//
545 if (monREDR) XrdOucEnv::Export("XRDMONRDR", monIdent);
546}
547
548/******************************************************************************/
549
550void XrdXrootdMonitor::Defaults(int msz, int rsz, int wsz,
551 int flush, int flash, int idt, int rnm,
552 int fbsz, int fsint, int fsopt, int fsion)
553{
554
555// Set default window size and flush time
556//
557 sizeWindow = (wsz <= 0 ? 60 : wsz);
558 autoFlush = (flush <= 0 ? 600 : flush);
559 autoFlash = (flash <= 0 ? 0 : flash);
560 monIdent = idt;
561 rdrNum = (rnm <= 0 || rnm > rdrMax ? 3 : rnm);
562 rdrWin = (sizeWindow > 16777215 ? 16777215 : sizeWindow);
563 rdrWin = htonl(rdrWin);
564
565// Set the fstat defaults
566//
567 XrdXrootdMonFile::Defaults(fsint, fsopt, fsion, fbsz);
568 monFSTAT = fsint != 0;
569
570// Set default monitor buffer size. The configuration accepts up to 65535
571// bytes, but the buffer goes out as one datagram, so limit it to maxDgram.
572//
573 if (msz <= 0) msz = 16384;
574 else if (msz < 1024) msz = 1024;
575 else {if (msz > maxDgram) msz = maxDgram;
576 msz = msz/sizeof(XrdXrootdMonTrace)*sizeof(XrdXrootdMonTrace);
577 }
578 lastEnt = (msz-sizeof(XrdXrootdMonHeader))/sizeof(XrdXrootdMonTrace);
579 monBlen = (lastEnt*sizeof(XrdXrootdMonTrace))+sizeof(XrdXrootdMonHeader);
580 lastEnt--;
581
582// Set default monitor redirect buffer size
583//
584 if (rsz <= 0) rsz = 32768;
585 else if (rsz < 2048) rsz = 2048;
586 lastRnt = (rsz-(sizeof(XrdXrootdMonHeader) + 16))/sizeof(XrdXrootdMonRedir);
587 monRlen = (lastRnt*sizeof(XrdXrootdMonRedir))+sizeof(XrdXrootdMonHeader)+16;
588 lastRnt--;
589}
590
591/******************************************************************************/
592/* D i s c */
593/******************************************************************************/
594
595void XrdXrootdMonitor::Disc(kXR_unt32 dictid, int csec, char Flags)
596{
597 XrdXrootdMonitorLock mLock(this);
598
599// Check if this should not be included in the io trace
600//
601 if (this != altMon && monUSER == 1 && altMon)
602 {altMon->Disc(dictid, csec); return;}
603
604// Fill out the monitor record (let compiler cast the data correctly)
605//
606 if (lastWindow != currWindow) Mark();
607 else if (nextEnt == lastEnt) Flush();
608 monBuff->info[nextEnt].arg0.rTot[0] = 0;
609 monBuff->info[nextEnt].arg0.id[0] = XROOTD_MON_DISC;
610 monBuff->info[nextEnt].arg0.id[1] = Flags;
611 monBuff->info[nextEnt].arg1.wTot = htonl(csec);
612 monBuff->info[nextEnt++].arg2.dictid = dictid;
613
614// Check if we need to duplicate this entry
615//
616 if (altMon && this != altMon && monUSER == 3)
617 altMon->Dup(&monBuff->info[nextEnt-1]);
618}
619
620/******************************************************************************/
621/* D u p */
622/******************************************************************************/
623
624void XrdXrootdMonitor::Dup(XrdXrootdMonTrace *mrec)
625{
626 XrdXrootdMonitorLock mLock(this);
627
628// Fill out the monitor record
629//
630 if (lastWindow != currWindow) Mark();
631 else if (nextEnt == lastEnt) Flush();
632 memcpy(&monBuff->info[nextEnt],(const void *)mrec,sizeof(XrdXrootdMonTrace));
633 nextEnt++;
634}
635
636/******************************************************************************/
637/* Private: F e t c h */
638/******************************************************************************/
639
640XrdXrootdMonitor::MonRdrBuff *XrdXrootdMonitor::Fetch()
641{
642 MonRdrBuff *bP;
643
644// Get the next available stream and promote another one
645//
646 rdrMutex.Lock();
647 if ((bP = rdrMP)) rdrMP = rdrMP->Next;
648 rdrMutex.UnLock();
649 return bP;
650}
651
652/******************************************************************************/
653/* I n i t */
654/******************************************************************************/
655
657 const char *iHost, const char *iProg,
658 const char *iName, int Port)
659{
660 const char *cgID0 = "&site=%s";
661 const char *cgID1 = "&host=%s";
662 const char *cgID2 = "&port=%d&inst=%s";
663 const char *cgID3 = "&pgm=%s&ver=%s";
664
665 const char *jsID0 = "\"src\":{\"site\":\"%s\"}";
666 const char *jsID1 = "%s\"host\":\"%s\"}";
667 const char *jsID2 = "%s\"port\":%d,\"inst\":\"%s\"}";
668 const char *jsID3 = "%s\"pgm\":\"%s\",\"ver\":\"%s\"}";
669
670 XrdXrootdMonMap *mP;
671 char iBuff[1024], iMuff[2048], iPuff[1024];
672 int n, i, j;
673
674// Set static variables
675//
676 Sched = sp;
677 eDest = errp;
678
679// Generate our server ID (the version is not part of he fingerprint)
680//
681 strcpy(iBuff, "=/");
682 kySID = XrdOucUtils::Ident(mySID, iBuff+2, sizeof(iBuff)-2,
683 iHost, iProg, iName, Port);
684 n = strlen(iBuff);
685 snprintf(iBuff+n, sizeof(iBuff)-n, "&ver=%s", XrdVERSION);
686
687 kySIDSZ = strlen(kySID);
688 monHost = strdup(iHost);
689
690// Ignore array bounds warning from gcc 12 triggered because the allocated
691// memory for the XrdXrootdMonMap is smaller than sizeof(XrdXrootdMonMap)
692#if defined(__GNUC__) && __GNUC__ >= 12
693#pragma GCC diagnostic push
694#pragma GCC diagnostic ignored "-Warray-bounds"
695#endif
696// Create identification record
697//
698 idLen = strlen(iBuff) + sizeof(XrdXrootdMonHeader) + sizeof(kXR_int32);
699 idRec = (char *)malloc(idLen+1);
700 mP = (XrdXrootdMonMap *)idRec;
701 fillHeader(&(mP->hdr), XROOTD_MON_MAPIDNT, idLen);
702 mP->hdr.pseq = 0;
703 mP->dictid = 0;
704 strcpy(mP->info, iBuff);
705#if defined(__GNUC__) && __GNUC__ >= 12
706#pragma GCC diagnostic pop
707#endif
708
709// Generate a CGI version of all the variations
710//
711 const char *Site (getenv("XRDSITE") ? getenv("XRDSITE") : "");
712 i = snprintf(iPuff, sizeof(iPuff), cgID0, Site);
713 SidCGI[0] = strdup(iPuff);
714 LidCGI[0] = strlen(iPuff);
715
716 n = sizeof(iPuff)-i; j = i;
717 i = snprintf(iPuff+j, n, cgID1, iHost);
718 SidCGI[1] = strdup(iPuff);
719 LidCGI[1] = strlen(iPuff);
720
721 n -= i; j += i;
722 i = snprintf(iPuff+j, n, cgID2, Port, iName);
723 SidCGI[2] = strdup(iPuff);
724 LidCGI[2] = strlen(iPuff);
725
726 n -= i; j += i;
727 snprintf(iPuff+j, n, cgID3, iProg, XrdVERSION);
728 SidCGI[3] = strdup(iPuff);
729 LidCGI[3] = strlen(iPuff);
730
731// Generate a JSON version of all the variations.
732//
733 n = snprintf(iPuff, sizeof(iPuff), jsID0, Site);
734 SidJSON[0] = strdup(iPuff);
735 LidJSON[0] = strlen(iPuff);
736
737 strcpy(iPuff+n-1, ",");
738 n = snprintf(iMuff, sizeof(iMuff), jsID1, iPuff, iHost);
739 SidJSON[1] = strdup(iMuff);
740 LidJSON[1] = strlen(iMuff);
741
742 strcpy(iMuff+n-1, ",");
743 n = snprintf(iPuff, sizeof(iPuff), jsID2, iMuff, Port, iName);
744 SidJSON[2] = strdup(iPuff);
745 LidJSON[2] = strlen(iPuff);
746
747 strcpy(iPuff+n-1, ",");
748 snprintf(iMuff, sizeof(iMuff), jsID3, iPuff, iProg, XrdVERSION);
749 SidJSON[3] = strdup(iMuff);
750 LidJSON[3] = strlen(iMuff);
751}
752
753/******************************************************************************/
754
756{
757 static XrdXrootdMonitor_Ident MonIdent(monIdent, isEnabled);
758 int i, Now = time(0);
759 bool aOK;
760
761// Setup the primary destination
762//
763 if (Dest1)
764 {InetDest1 = new XrdNetMsg(eDest, Dest1, &aOK, true);
765 if (!aOK)
766 {eDest->Emsg("Monitor", "Unable to setup primary monitor collector.");
767 return 0;
768 }
769 }
770
771// Setup the secondary destination
772//
773 if (Dest2)
774 {InetDest2 = new XrdNetMsg(eDest, Dest2, &aOK, true);
775 if (!aOK)
776 {eDest->Emsg("Monitor","Unable to setup secondary monitor collector.");
777 return 0;
778 }
779 }
780
781// Now schedule the first identification record
782//
783 if (Sched && monIdent >= 0) Sched->Schedule((XrdJob *)&MonIdent);
784
785// There is nothing more to do unless we have been enabled via Defaults()
786//
787 if (!isEnabled) return 1;
788
789// If there is a destination that is only collecting file events, then
790// allocate a global monitor object but don't start the timer just yet.
791//
792 if ((monMode1 && !(monMode1 & XROOTD_MON_IO))
793 || (monMode2 && !(monMode2 & XROOTD_MON_IO)))
794 if (!(altMon = new XrdXrootdMonitor()) || !altMon->monBuff)
795 {if (altMon) {delete altMon; altMon = 0;}
796 eDest->Emsg("Monitor","allocate monitor; insufficient storage.");
797 return 0;
798 }
799
800// Turn on the monitoring clock if we need it running all the time
801//
802 if (monCLOCK) startClock();
803
804// If we are monitoring file stats then start that up
805//
806 if (!Sched || !monFSTAT) monFSTAT = 0;
807 else if (!XrdXrootdMonFile::Init()) return 0;
808
809// If we are not monitoring redirections, we are done!
810//
811 if (!monREDR) return 1;
812
813// Allocate as many redirection monitors as requested
814//
815 for (i = 0; i < rdrNum; i++)
816 {if (posix_memalign((void **)&rdrMon[i].Buff, getpagesize(),monRlen))
817 {eDest->Emsg("Monitor", "Unable to allocate monitor rdr buffer.");
818 return 0;
819 }
820 rdrMon[i].Buff->sID = mySID;
821 rdrMon[i].Buff->sXX[0] = XROOTD_MON_REDSID;
822 rdrMon[i].Next = (i ? &rdrMon[i-1] : &rdrMon[0]);
823 rdrMon[i].nextEnt = 0;
824 rdrMon[i].flushIt = Now + autoFlush;
825 rdrMon[i].lastTOD = 0;
826 }
827 rdrMon[0].Next = &rdrMon[i-1];
828 rdrMP = &rdrMon[0];
829
830// All done
831//
832 return 1;
833}
834
835/******************************************************************************/
836/* G e t D i c t I D */
837/******************************************************************************/
838
840{
841 static XrdSysMutex seqMutex;
842 static unsigned int monSeqID = 1;
843 unsigned int mySeqID;
844
845// Assign a unique ID for this entry
846//
847 seqMutex.Lock();
848 mySeqID = monSeqID++;
849 seqMutex.UnLock();
850
851// Return the ID
852//
853 if (hbo) return mySeqID;
854 return htonl(mySeqID);
855}
856
857/******************************************************************************/
858/* Private: M a p */
859/******************************************************************************/
860
861kXR_unt32 XrdXrootdMonitor::Map(char code, XrdXrootdMonitor::User &uInfo,
862 const char *path)
863{
864 XrdXrootdMonMap map;
865 const int room = sizeof(map.info);
866 int size, montype;
867
868// Copy in the username and path. The record is a fixed-size object, so the
869// size must come from what was copied, not from the source. Otherwise Send()
870// puts whatever follows the record on the wire. Send() sends only size bytes,
871// so the room for each text ends after its null byte, and no padding occurs.
872//
873 map.dictid = GetDictID();
874 size = CopyText(map.info, std::min(uInfo.Len + 1, room),
875 uInfo.Name, uInfo.Len);
876 if (path && size < room - 2)
877 {int pLen = strlen(path);
878 map.info[size++] = '\n';
879 size += CopyText(map.info + size, std::min(pLen + 1, room - size),
880 path, pLen);
881 }
882
883// Fill in the header
884//
885 size = sizeof(XrdXrootdMonHeader)+sizeof(kXR_int32)+size;
886 fillHeader(&map.hdr, code, size);
887
888// Route the packet to all destinations that need them
889//
890 if (code == XROOTD_MON_MAPPATH) montype = XROOTD_MON_PATH;
891 else if (code == XROOTD_MON_MAPUSER
892 || code == XROOTD_MON_MAPTOKN
893 || code == XROOTD_MON_MAPUEAC) montype = XROOTD_MON_USER;
894 else montype = XROOTD_MON_INFO;
895 Send(montype, (void *)&map, size);
896
897// Return the dictionary id
898//
899 return map.dictid;
900}
901
902/******************************************************************************/
903/* O p e n */
904/******************************************************************************/
905
906void XrdXrootdMonitor::Open(kXR_unt32 dictid, off_t fsize)
907{
908 XrdXrootdMonitorLock mLock(this);
909
910 if (lastWindow != currWindow) Mark();
911 else if (nextEnt == lastEnt) Flush();
912 h2nll(fsize, monBuff->info[nextEnt].arg0.val);
913 monBuff->info[nextEnt].arg0.id[0] = XROOTD_MON_OPEN;
914 monBuff->info[nextEnt].arg1.buflen = 0;
915 monBuff->info[nextEnt++].arg2.dictid = dictid;
916
917// Check if we need to duplicate this entry
918//
919 if (altMon && this != altMon) altMon->Dup(&monBuff->info[nextEnt-1]);
920}
921
922/******************************************************************************/
923/* R e d i r e c t */
924/******************************************************************************/
925
926int XrdXrootdMonitor::Redirect(kXR_unt32 mID, const char *hName, int Port,
927 char opC, const char *Path)
928{
930 MonRdrBuff *mP = Fetch();
931 int n, slots, hLen, pLen, room;
932 char *dest;
933
934// Take care of the server's name which might actually be a path
935//
936 if (*hName == '/') {Path = hName; hName = ""; hLen = 0;}
937 else {const char *quest = index(hName, '?');
938 hLen = (quest ? quest - hName : strlen(hName));
939 if (hLen > 256) hLen = 256;
940 }
941
942// Take care of the path. Only the truncated length may be copied, as the
943// path can be longer than the slots that hold it. CopyText() then ends the
944// path with a null byte and null pads the rest of the slots.
945//
946 pLen = strlen(Path);
947 if (pLen > 1024) pLen = 1024;
948
949// Compute number of entries needed here
950//
951 n = (hLen + 1 + pLen + 1); // "<host>:<path>\0"
952 slots = n / sizeof(XrdXrootdMonRedir);
953 if (n % sizeof(XrdXrootdMonRedir)) slots++;
954 room = slots * sizeof(XrdXrootdMonRedir) - (hLen+1);
955
956// Obtain a lock on this buffer
957//
958 if (!mP) return 0;
959 mP->Mutex.Lock();
960
961// If we don't have enough slots, flush this buffer. Note that we account for
962// the ending timing mark here (an extra slot).
963//
964 if (mP->nextEnt + slots + 2 >= lastRnt) Flush(mP);
965
966// Check if we need a timing mark
967//
968 if (mP->lastTOD != rdrTOD)
969 {mP->lastTOD = rdrTOD;
970 setTMurk(mP->Buff, mP->nextEnt, mP->lastTOD);
971 mP->nextEnt++;
972 }
973
974// Fill out the buffer
975//
976 mtP = &(mP->Buff->info[mP->nextEnt]);
977 mtP->arg0.rdr.Type = XROOTD_MON_REDIRECT | opC;
978 mtP->arg0.rdr.Dent = static_cast<char>(slots);
979 mtP->arg0.rdr.Port = htons(static_cast<short>(Port));
980 mtP->arg1.dictid = mID;
981 dest = (char *)(mtP+1);
982 strncpy(dest, hName,hLen); dest += hLen; *dest++ = ':';
983 CopyText(dest, room, Path, pLen);
984
985// Adjust pointer and return
986//
987 mP->nextEnt = mP->nextEnt + (slots+1);
988 mP->Mutex.UnLock();
989 return 0;
990}
991
992
993/******************************************************************************/
994/* T i c k */
995/******************************************************************************/
996
998{
999 time_t Now = time(0);
1000 int nextFlush;
1001
1002// We can safely set the window as we are the only ones doing so and memory
1003// access is atomic as long as it sits within a cache line (which it does).
1004//
1005 currWindow = static_cast<kXR_int32>(Now);
1006 rdrTOD = htonl(currWindow);
1007 nextFlush = currWindow + autoFlush;
1008
1009// Check to see if we should flush the alternate monitor
1010//
1011 if (altMon && currWindow >= FlushTime)
1013 if (currWindow >= FlushTime)
1014 {if (altMon->nextEnt > 1) altMon->Flush();
1015 else FlushTime = nextFlush;
1016 }
1018 }
1019
1020// Now check to see if we need to flush redirect buffers
1021//
1022 if (monREDR)
1023 {int n = rdrNum;
1024 while(n--)
1025 {rdrMon[n].Mutex.Lock();
1026 if (rdrMon[n].nextEnt == 0) rdrMon[n].flushIt = nextFlush;
1027 else if (rdrMon[n].flushIt <= currWindow) Flush(&rdrMon[n]);
1028 rdrMon[n].Mutex.UnLock();
1029 }
1030 }
1031
1032// All done. Stop the clock if there is no reason for it to be running. The
1033// clock always runs if we are monitoring redirects or all clients. Otherwise,
1034// the clock only runs if we have a one or more client-specific monitors.
1035//
1036 if (!monREDR && isEnabled < 0)
1037 {windowMutex.Lock();
1038 if (!numMonitor) Now = 0;
1039 windowMutex.UnLock();
1040 }
1041 return Now;
1042}
1043
1044/******************************************************************************/
1045/* u n A l l o c */
1046/******************************************************************************/
1047
1048void XrdXrootdMonitor::unAlloc(XrdXrootdMonitor *monp)
1049{
1050
1051// We must delete this object if we are de-allocating the local monitor.
1052//
1053 if (monp != altMon) delete monp;
1054
1055// Decrease number being monitored if in selective mode
1056//
1057 if (isEnabled < 0)
1058 {windowMutex.Lock();
1059 numMonitor--;
1060 windowMutex.UnLock();
1061 }
1062}
1063
1064/******************************************************************************/
1065/* P r i v a t e M e t h o d s */
1066/******************************************************************************/
1067/******************************************************************************/
1068/* d o _ S h i f t */
1069/******************************************************************************/
1070
1071unsigned char XrdXrootdMonitor::do_Shift(long long xTot, unsigned int &xVal)
1072{
1073 const long long smask = 0x7fffffff00000000LL;
1074 const long long xmask = 0x7fffffffffffffffLL;
1075 unsigned char xshift = 0;
1076
1077 xTot &= xmask;
1078 while(xTot & smask) {xTot = xTot >> 1LL; xshift++;}
1079 xVal = static_cast<unsigned int>(xTot);
1080
1081 return xshift;
1082}
1083
1084/******************************************************************************/
1085/* f i l l H e a d e r */
1086/******************************************************************************/
1087
1088void XrdXrootdMonitor::fillHeader(XrdXrootdMonHeader *hdr,
1089 const char id, int size)
1090{
1091
1092// Fill in the header
1093//
1094 hdr->code = static_cast<kXR_char>(id);
1095// hdr->pseq = static_cast<kXR_char>(myseq); // Filled in Send()
1096 hdr->plen = htons(static_cast<uint16_t>(size));
1097 hdr->stod = startTime;
1098}
1099
1100/******************************************************************************/
1101/* F l u s h */
1102/******************************************************************************/
1103
1104void XrdXrootdMonitor::Flush()
1105{
1106 int size;
1107 kXR_int32 localWindow, now;
1108
1109// Do not flush if the buffer is empty
1110//
1111 if (nextEnt <= 1) return;
1112
1113// Get the current window marker. No need for locks as simple memory accesses
1114// are sufficiently synchrnozed for our purposes.
1115//
1116 localWindow = currWindow;
1117
1118// Fill in the header and in the process we will have the current time
1119//
1120 size = (nextEnt+1)*sizeof(XrdXrootdMonTrace)+sizeof(XrdXrootdMonHeader);
1121 fillHeader(&monBuff->hdr, XROOTD_MON_MAPTRCE, size);
1122
1123// Punt on the right ending time. We are trying to keep same-sized windows
1124// This was corrected by Matevz Tadel, as before we were using real time which
1125// could have been far into the future due to simple inactivity. So, Place the
1126// computed ending timing mark.
1127//
1128 now = lastWindow + sizeWindow;
1129 setTMark(monBuff, nextEnt, now);
1130
1131// Send off the buffer and reinitialize it
1132//
1133 if (this != altMon) Send(XROOTD_MON_IO, (void *)monBuff, size);
1134 else {Send(XROOTD_MON_FILE, (void *)monBuff, size);
1135 FlushTime = localWindow + autoFlush;
1136 }
1137 setTMark(monBuff, 0, localWindow);
1138 nextEnt = 1;
1139}
1140
1141/******************************************************************************/
1142
1143void XrdXrootdMonitor::Flush(XrdXrootdMonitor::MonRdrBuff *mP)
1144{
1145 int size;
1146
1147// Reset flush time but do not flush an empty buffer. We use the current time
1148// to make sure a record atleast sits in the buffer a full flush period.
1149//
1150 mP->flushIt = static_cast<int>(time(0)) + autoFlush;
1151 if (mP->nextEnt <= 1) return;
1152
1153// Set ending timing mark and force a new one on the next fill
1154//
1155 setTMurk(mP->Buff, mP->nextEnt, rdrTOD);
1156 mP->lastTOD = 0;
1157
1158// Fill in the header and in the process we will have the current time
1159//
1160 size = (mP->nextEnt+1)*sizeof(XrdXrootdMonRedir)+sizeof(XrdXrootdMonHeader)+8;
1161 fillHeader(&(mP->Buff->hdr), XROOTD_MON_MAPREDR, size);
1162
1163// Send off the buffer and reinitialize it
1164//
1165 Send(XROOTD_MON_REDR, (void *)(mP->Buff), size);
1166 mP->nextEnt = 0;
1167}
1168
1169/******************************************************************************/
1170/* M a r k */
1171/******************************************************************************/
1172
1173void XrdXrootdMonitor::Mark()
1174{
1175 kXR_int32 localWindow;
1176
1177// Get the current window marker. Since simple memory accesses are sufficiently
1178// synchronized, no need to lock this.
1179//
1180 localWindow = currWindow;
1181
1182// Using an update provided by Matevz Tadel, UCSD, if this is an I/O buffer
1183// mark then we will also flush the I/O buffer if all the following hold:
1184// a) flushing enabled, b) buffer not empty, and c) covers the flush time.
1185// We would normally do this during Tick() but that would require too much
1186// locking in the middle of an I/O path, so we do psudo timed flushing.
1187//
1188 if (this != altMon && autoFlash && nextEnt > 1)
1189 {kXR_int32 bufStartWindow =
1190 static_cast<kXR_int32>(ntohl(monBuff->info[0].arg2.Window));
1191 if (localWindow - bufStartWindow >= autoFlash)
1192 {Flush();
1193 lastWindow = localWindow;
1194 return;
1195 }
1196 }
1197
1198// Now, optimize placing the window mark in the buffer. Using another MT fix we
1199// set the end of the previous window to be lastwindow + sizeWindow (instead of
1200// localWindow) to prevent windows from being wrongly zero sized.
1201//
1202 if (monBuff->info[nextEnt-1].arg0.id[0] == XROOTD_MON_WINDOW)
1203 {
1204 monBuff->info[nextEnt-1].arg2.Window =
1205 static_cast<kXR_int32>(htonl(localWindow));
1206 }
1207 else if (nextEnt+8 > lastEnt)
1208 {
1209 Flush();
1210 }
1211 else
1212 {
1213 monBuff->info[nextEnt].arg0.val = mySID;
1214 monBuff->info[nextEnt].arg0.id[0] = XROOTD_MON_WINDOW;
1215 monBuff->info[nextEnt].arg1.Window =
1216 static_cast<kXR_int32>(htonl(lastWindow + sizeWindow));
1217 monBuff->info[nextEnt].arg2.Window =
1218 static_cast<kXR_int32>(htonl(localWindow));
1219 nextEnt++;
1220 }
1221 lastWindow = localWindow;
1222}
1223
1224/******************************************************************************/
1225/* S e n d */
1226/******************************************************************************/
1227
1228int XrdXrootdMonitor::Send(int monMode, void *buff, int blen, bool setseq)
1229{
1230#ifndef NODEBUG
1231 const char *TraceID = "Monitor";
1232#endif
1233 static XrdSysMutex sendMutex;
1234 static int seq1=0, seq2=0;
1235 XrdXrootdMonHeader *mHdr=0;
1236 int rc1, rc2;
1237
1238// If we are to set sequence numbers, recast the buffer. We are assured that
1239// the buffer always starts with the standard monitor header.
1240//
1241 if (setseq) mHdr = static_cast<XrdXrootdMonHeader*>(buff);
1242
1243 sendMutex.Lock();
1244 if (monMode & monMode1 && InetDest1)
1245 {if (mHdr) mHdr->pseq = (seq1++) & 0xff;
1246 rc1 = InetDest1->Send((char *)buff, blen);
1247 TRACE(DEBUG,blen <<" bytes sent to " <<Dest1 <<" rc=" <<rc1);
1248 }
1249 else rc1 = 0;
1250 if (monMode & monMode2 && InetDest2)
1251 {if (mHdr) mHdr->pseq = (seq2++) & 0xff;
1252 rc2 = InetDest2->Send((char *)buff, blen);
1253 TRACE(DEBUG,blen <<" bytes sent to " <<Dest2 <<" rc=" <<rc2);
1254 }
1255 else rc2 = 0;
1256 sendMutex.UnLock();
1257
1258 return (rc1 ? rc1 : rc2);
1259}
1260
1261/******************************************************************************/
1262/* s t a r t C l o c k */
1263/******************************************************************************/
1264
1265void XrdXrootdMonitor::startClock()
1266{
1267 static XrdXrootdMonitor_Tick MonTick;
1268 time_t Now;
1269
1270// Start the clock, Caller must have windowMutex locked, if necessary.
1271//
1272 Now = time(0);
1273 currWindow = static_cast<kXR_int32>(Now);
1274 rdrTOD = htonl(currWindow);
1275 MonTick.Set(Sched, sizeWindow);
1276 FlushTime = autoFlush + currWindow;
1277 if (Sched) Sched->Schedule((XrdJob *)&MonTick, Now+sizeWindow);
1278}
int kXR_int32
Definition XPtypes.hh:89
unsigned int kXR_unt32
Definition XPtypes.hh:90
unsigned char kXR_char
Definition XPtypes.hh:65
#define DEBUG(x)
static XrdSysError eDest(0,"crypto_")
XrdOucString Path
#define TRACE(act, x)
Definition XrdTrace.hh:63
XrdSysTrace XrdXrootdTrace
const kXR_char XROOTD_MON_DISC
const kXR_char XROOTD_MON_MAPUEAC
const kXR_char XROOTD_MON_WINDOW
XrdXrootdMonTrace info[sizeof(XrdXrootdMonTrace)]
const kXR_char XROOTD_MON_MAPUSER
const kXR_char XROOTD_MON_APPID
const kXR_char XROOTD_MON_REDSID
const kXR_char XROOTD_MON_MAPIDNT
const kXR_char XROOTD_MON_MAPTRCE
char info[1024+256]
const kXR_char XROOTD_MON_CLOSE
const kXR_char XROOTD_MON_MAPPATH
const kXR_char XROOTD_MON_OPEN
XrdXrootdMonHeader hdr
const kXR_char XROOTD_MON_REDIRECT
const kXR_char XROOTD_MON_MAPTOKN
const kXR_char XROOTD_MON_MAPREDR
#define setTMurk(TM_mb, TM_en, TM_tm)
#define setTMark(TM_mb, TM_en, TM_tm)
#define XROOTD_MON_IOV
#define XROOTD_MON_INFO
#define XROOTD_MON_ALL
#define XROOTD_MON_AUTH
#define XROOTD_MON_IO
#define XROOTD_MON_USER
#define XROOTD_MON_FSTA
#define XROOTD_MON_PATH
#define XROOTD_MON_FILE
#define XROOTD_MON_REDR
friend class XrdScheduler
Definition XrdJob.hh:44
XrdJob(const char *desc="")
Definition XrdJob.hh:51
static int Export(const char *Var, const char *Val)
Definition XrdOucEnv.cc:170
static char * Ident(long long &mySID, char *iBuff, int iBlen, const char *iHost, const char *iProg, const char *iName, int Port)
static void Defaults(int intv, int opts, int iocnt, int fbsz)
XrdXrootdMonitorLock(XrdXrootdMonitor *theMonitor)
Hello(const char *dest, char mode)
void Register(const char *Uname, const char *Hname, const char *Pname, unsigned int xSID=0)
void Report(const char *Info)
XrdXrootdMonitor * Agent
XrdXrootdMonitor_Ident(int idt, bool ison)
void Set(XrdScheduler *sp, int intvl)
static int CopyText(char *buff, int room, const char *text, int tLen)
static const int rdrMax
static XrdXrootdMonitor * altMon
static void Defaults(char *dest1, int m1, char *dest2, int m2)
void appID(char *id)
static time_t Tick()
static constexpr int maxDgram
void Disc(kXR_unt32 dictid, int csec, char Flags=0)
void Close(kXR_unt32 dictid, long long rTot, long long wTot)
static int Send(int mmode, void *buff, int size, bool setseq=true)
void Open(kXR_unt32 dictid, off_t fsize)
static kXR_unt32 GetDictID(bool hbo=false)
XrdScheduler * Sched
static int32_t InitStartTime()
XrdXrootdMonHeader hdr
XrdXrootdMonRedir info[sizeof(XrdXrootdMonRedir)]
union XrdXrootdMonRedir::@017044370107177241030156067342362323316131075335 arg0
union XrdXrootdMonRedir::@124330332126055120131203275034312305071227313005 arg1