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