XRootD
Loading...
Searching...
No Matches
XrdNetPMarkCfg.cc File Reference
#include <map>
#include <set>
#include <string>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include "XrdNet/XrdNetMsg.hh"
#include "XrdNet/XrdNetPMarkCfg.hh"
#include "XrdNet/XrdNetPMarkFF.hh"
#include "XrdNet/XrdNetUtils.hh"
#include "XrdOuc/XrdOuca2x.hh"
#include "XrdOuc/XrdOucJson.hh"
#include "XrdOuc/XrdOucMapP2X.hh"
#include "XrdOuc/XrdOucProg.hh"
#include "XrdOuc/XrdOucStream.hh"
#include "XrdOuc/XrdOucString.hh"
#include "XrdOuc/XrdOucUtils.hh"
#include "XrdSec/XrdSecEntity.hh"
#include "XrdSys/XrdSysError.hh"
#include "XrdSys/XrdSysPthread.hh"
#include "XrdSys/XrdSysTimer.hh"
#include "XrdSys/XrdSysTrace.hh"
+ Include dependency graph for XrdNetPMarkCfg.cc:

Go to the source code of this file.

Classes

struct  XrdNetPMarkConfig::CfgInfo
 
class  XrdNetPMarkConfig::ExpInfo
 
class  XrdNetPMarkConfig::MapInfo
 

Namespaces

namespace  XrdNetPMarkConfig
 

Macros

#define DBGID(tid, txt)    if (doDebug) SYSTRACE(Trace->, tid, epName, 0, txt)
 
#define DEBUG(txt)    if (doDebug) SYSTRACE(Trace->, 0, epName, 0, txt)
 
#define EPName(ep)   const char *epName = ep
 
#define TRACE(txt)    if (doTrace) SYSTRACE(Trace->, client.tident, epName, 0, txt)
 

Typedefs

using json = nlohmann::json
 

Variables

bool XrdNetPMarkConfig::addFLFF = false
 
CfgInfoXrdNetPMarkConfig::Cfg = 0
 
char XrdNetPMarkConfig::chkDom = domRmt
 
bool XrdNetPMarkConfig::doDebug = false
 
static const int XrdNetPMarkConfig::domAny = 0
 
static const int XrdNetPMarkConfig::domLcl = 1
 
static const int XrdNetPMarkConfig::domRmt = 2
 
bool XrdNetPMarkConfig::doTrace = false
 
XrdSysErrorXrdNetPMarkConfig::eDest = 0
 
ExpInfoXrdNetPMarkConfig::expDflt = 0
 
std::map< std::string, ExpInfoXrdNetPMarkConfig::expMap
 
char * XrdNetPMarkConfig::ffDest = 0
 
int XrdNetPMarkConfig::ffEcho = 0
 
static const int XrdNetPMarkConfig::ffPORT = 10514
 
int XrdNetPMarkConfig::ffPortD = 0
 
int XrdNetPMarkConfig::ffPortO = 0
 
const char * XrdNetPMarkConfig::myDomain = ""
 
const char * XrdNetPMarkConfig::myHostName = "-"
 
XrdNetMsgXrdNetPMarkConfig::netMsg = 0
 
XrdNetMsgXrdNetPMarkConfig::netOrg = 0
 
bool XrdNetPMarkConfig::noFail = true
 
XrdOucMapP2X< ExpInfo * > XrdNetPMarkConfig::p2eMap
 
XrdSchedulerXrdNetPMarkConfig::Sched = 0
 
XrdSysTraceXrdNetPMarkConfig::Trace = 0
 
bool XrdNetPMarkConfig::tryPath = false
 
bool XrdNetPMarkConfig::tryVO = false
 
bool XrdNetPMarkConfig::useDefs = false
 
signed char XrdNetPMarkConfig::useFFly = -1
 
bool XrdNetPMarkConfig::useFLbl = false
 
bool XrdNetPMarkConfig::useSTag = true
 
std::map< std::string, ExpInfo * > XrdNetPMarkConfig::v2eMap
 

Macro Definition Documentation

◆ DBGID

#define DBGID (   tid,
  txt 
)     if (doDebug) SYSTRACE(Trace->, tid, epName, 0, txt)

Definition at line 68 of file XrdNetPMarkCfg.cc.

78{
79class MapInfo
80 {public:
81 std::string Name; // Activity name
82 int Code; // Act code for role/user
83
84 MapInfo() : Code(0) {}
85 MapInfo(const char *name, int code) : Name(name), Code(code) {}
86 ~MapInfo() {}
87};
88
89class ExpInfo
90 {public:
91 std::map<std::string, int> actMap;
92 std::map<std::string, MapInfo> r2aMap;
93 std::map<std::string, MapInfo> u2aMap;
94 short Code;
95 short dAct = -1;
96 bool Roles = false;
97 bool Users = false;
98 bool inUse = false;
99
100 ExpInfo(int code=0) : Code(code) {}
101 ~ExpInfo() {}
102 };
103
104// Permanent maps to determine the experiment
105//
106std::map<std::string, ExpInfo> expMap;
108std::map<std::string, ExpInfo*> v2eMap;
109
110// Other configuration values
111//
112XrdSysError *eDest = 0;
113XrdNetMsg *netMsg = 0; // UDP object for collector
114XrdNetMsg *netOrg = 0; // UDP object for origin
116XrdSysTrace *Trace = 0;
117const char *myHostName = "-";
118const char *myDomain = "";
119
120
121ExpInfo *expDflt = 0;
122
123char *ffDest = 0;
124int ffEcho = 0;
125static
126const int ffPORT = 10514; // The default port
127int ffPortD = 0; // The dest port to use
128int ffPortO = 0; // The reply port to use
129
130static const int domAny = 0;
131static const int domLcl = 1;
132static const int domRmt = 2;
133
134char chkDom = domRmt;
135bool tryPath = false;
136bool tryVO = false;
137bool useDefs = false;
138
139bool useFLbl = false;
140signed char useFFly = -1;
141bool addFLFF = false;
142bool useSTag = true;
143
144bool noFail = true;
145bool doDebug = false;
146bool doTrace = false;
147
148struct CfgInfo
151
152 static const int pgmOptN = 6;
153 const char *pgmOpts[pgmOptN] = {0};
154
155 int defsTO =30;
156 std::set<std::string> x2aSet;
157 std::set<std::string> x2eSet;
158
159 CfgInfo() {}
160 ~CfgInfo() {}
161 };
162
163CfgInfo *Cfg = 0;
164}
165using namespace XrdNetPMarkConfig;
166
167/******************************************************************************/
168/* S t a t i c M e m b e r s */
169/******************************************************************************/
170
171/******************************************************************************/
172/* B e g i n */
173/******************************************************************************/
174
176 const char *path,
177 const char *cgi,
178 const char *app)
179{
180 EPName("PMBegin");
181 XrdOucString altApp;
182 int eCode, aCode;
183
184// If we need to screen out domains, do that
185//
186 if (chkDom)
187 {XrdNetAddrInfo &addrInfo = *client.addrInfo;
188 char domType = (addrInfo.isPrivate() ? domLcl : domRmt);
189 if (domType == domRmt && *myDomain)
190 {const char *urName = addrInfo.Name();
191 if (urName && XrdNetAddrInfo::isHostName(urName))
192 {const char *dot = index(urName, '.');
193 if (dot && !strcmp(dot+1, myDomain)) domType = domLcl;
194 }
195 }
196 if (domType != chkDom)
197 {DBGID(client.tident, "Skipping sending flow info; unwanted domain");
198 return 0;
199 }
200 }
201
202// Now get the experiment and activity code. If we can't get at least the
203// experiment code, then proceed without marking the flow.
204//
205 if (!getCodes(client, path, cgi, eCode, aCode))
206 {TRACE("Unable to determine experiment; flow not marked.");
207 return 0;
208 }
209
210// Obtain the appname overridefrom the cgi
211//
212 if (cgi) // 01234567890123
213 {const char *apP = strstr(cgi, "pmark.appname=");
214 if (apP)
215 {apP += 14;
216 const char* aP = apP;
217 while(*aP && *aP != '&') aP++;
218 int apLen = aP - apP;
219 if (apLen > 0)
220 {altApp = "";
221 altApp.insert(apP, 0, apLen);
222 app = altApp.c_str();
223 }
224 }
225 }
226
227// Continue with successor function to complete the logic
228//
229 XrdNetPMark::Handle handle(app, eCode, aCode);
230 return Begin(*client.addrInfo, handle, client.tident);
231}
232
233/******************************************************************************/
234
236 XrdNetPMark::Handle &handle,
237 const char *tident)
238{
239
240// If we are allowed to use the flow label set on the incoming connection
241// then try to do so. This is only valid for IPv6 connections. Currently,
242// this is not implemented.
243//
244// if (useFLbl && addrInfo.isIPType(XrdNetAddrInfo::IPv6)
245// && !addrInfo.isMapped())
246// {
247// TODO???
248// }
249
250// If we are allowed to use firefly, return a firefly handle
251//
252 if (handle.Valid() && useFFly)
253 {XrdNetPMarkFF *pmFF = new XrdNetPMarkFF(handle, tident);
254 if (pmFF->Start(addrInfo)) return pmFF;
255 delete pmFF;
256 }
257
258// All done, nothing will be pmarked
259//
260 return 0;
261}
262
263/******************************************************************************/
264/* C o n f i g */
265/******************************************************************************/
266
268 XrdSysTrace *trc, bool &fatal)
269{
270 class DelCfgInfo
271 {public: DelCfgInfo(CfgInfo *&cfg) : cfgInfo(cfg) {}
272 ~DelCfgInfo() {if (cfgInfo) {delete cfgInfo; cfgInfo = 0;}}
273 private:
274 CfgInfo *&cfgInfo;
275 } cleanup(Cfg);
276
277// If we have not been configured then simply retrn nil
278//
279 if (!Cfg)
280 {useFFly = false;
281 return 0;
282 }
283
284// Save the message handler
285//
286 eDest = eLog;
287 Sched = sched;
288 Trace = trc;
289 fatal = false;
290
291// If firefly is enabled, make sure we have an ffdest
292//
293 if (useFFly < 0)
294 {if (ffPortD || ffPortO)
295 {useFFly = true;
296 if (!ffPortO) ffPortO = ffPORT;
297 } else {
298 useFFly = false;
299 eLog->Say("Config warning: firefly disabled; "
300 "configuration incomplete!");
301 return 0;
302 }
303 } else if (useFFly && !ffPortO) ffPortO = ffPORT;
304
305// Resolve trace and debug settings
306//
307 if (doDebug) doTrace = true;
308
309// Check if we need a defsfile, if so, construct the map.
310//
311 if (Cfg->x2aSet.size() == 0 && Cfg->x2eSet.size() == 0)
312 {if (Cfg->defsFile.length())
313 eLog->Say("Config warning: ignoring defsfile; "
314 "no mappings have been specified!");
315 useDefs = false;
316 } else {
317 if (!Cfg->defsFile.length())
318 {eLog->Say("Config invalid: pmark mappings cannot be resolved "
319 "without specifying defsfile!");
320 fatal = true;
321 return 0;
322 }
323 useDefs = true;
324 if (!ConfigDefs())
325 {if (useDefs)
326 {fatal = true;
327 return 0;
328 }
329 eLog->Say("Config warning: pmark ignoring defsfile; "
330 "unable to process and nofail is in effect!");
331 }
332 }
333
334// At this point either we still enabled or not. We can be disabled for a
335// number of reasons and appropriate messages will have been issued.
336//
337 if (!useFFly) return 0;
338
339// Create a netmsg object for firefly reporting if a dest was specified
340//
341 bool aOK = false;
342 if (ffDest)
343 {XrdNetAddr spec;
344 char buff[1024];
345 const char *eTxt = spec.Set(ffDest, -ffPortD);
346 if (eTxt)
347 {snprintf(buff, sizeof(buff), "%s:%d; %s", ffDest, ffPortD, eTxt);
348 eLog->Emsg("Config", "pmark unable to create UDP tunnel to", buff);
349 useFFly = false;
350 fatal = true;
351 return 0;
352 }
353 if (spec.Format(buff, sizeof(buff)))
354 netMsg = new XrdNetMsg(eDest, buff, &aOK);
355 if (!aOK)
356 {eLog->Emsg("Config", "pmark unable to create UDP tunnel to", ffDest);
357 fatal = true;
358 delete netMsg;
359 netMsg = 0;
360 useFFly= false;
361 return 0;
362 }
363 }
364
365// Handle the firefly messages to origin
366//
367 if (ffPortO)
368 {netOrg = new XrdNetMsg(eDest, 0, &aOK);
369 if (!aOK)
370 {eLog->Emsg("Config","pmark unable to create origin UDP tunnel");
371 fatal = true;
372 useFFly= false;
373 return 0;
374 }
375 }
376
377// Get our host name.
378//
379 myHostName = XrdNetUtils::MyHostName("-"); // Never deleted!
380
381// Setup for domain checking
382//
383 if (chkDom)
384 {const char *dot = index(myHostName, '.');
385 if (dot) myDomain = dot+1;
386 else eDest->Say("Config warning: Unable to determine local domain; "
387 " domain check restricted to IP address type!");
388 }
389
390// Finally, we are done. Return the packet markling stub.
391//
392 return new XrdNetPMarkCfg;
393}
394
395/******************************************************************************/
396/* Private: C o n f i g D e f s */
397/******************************************************************************/
398
399namespace
400{
401bool Recover()
402{
403 if (!noFail) return false;
404 useDefs = false;
405 return true;
406}
407}
408
409bool XrdNetPMarkCfg::ConfigDefs()
410{
411 class Const2Char
412 {public:
413 char *data;
414 Const2Char(const char *str) : data(strdup(str)) {}
415 ~Const2Char() {free(data);}
416 };
417 EPName("ConfigDefs");
418 std::set<std::string>::iterator it;
419 std::map<std::string, ExpInfo>::iterator itE;
420 bool isDload, aOK = true;
421
422// If we need tp fetch the file, do so.
423//
424 if ((isDload = !(Cfg->defsFile.beginswith('/'))) && !FetchFile())
425 return Recover();
426
427// Now parse the defsfile (it is a json file)
428//
429 aOK = LoadFile();
430
431// Get rid of the defsfile if we dowloaded it
432//
433 if (isDload) unlink(Cfg->defsFile.c_str());
434
435// Only continue if all is well
436//
437 if (!aOK) return Recover();
438
439// Configure the experiment mapping
440//
441 for (it = Cfg->x2eSet.begin(); it != Cfg->x2eSet.end(); it++)
442 {Const2Char pv(it->c_str());
443 if (!ConfigPV2E(pv.data)) aOK = false;
444 }
445 Cfg->x2eSet.clear();
446
447// Configure the activity mapping
448//
449 for (it = Cfg->x2aSet.begin(); it != Cfg->x2aSet.end(); it++)
450 {Const2Char ru(it->c_str());
451 if (!ConfigRU2A(ru.data)) aOK = false;
452 }
453 Cfg->x2aSet.clear();
454
455// Eliminate any experiment that we will not be using. This is will restrict
456// flow marking to url passed information as there will be no internal deduction
457//
458 itE = expMap.begin();
459 while(itE != expMap.end())
460 {if (itE->second.inUse)
461 {itE->second.Roles = itE->second.r2aMap.size() != 0;
462 itE->second.Users = itE->second.u2aMap.size() != 0;
463 itE++;
464 } else {
465 DEBUG("Deleting unused experiment '"<<itE->first.c_str()<<"'");
466 itE = expMap.erase(itE);
467 }
468 }
469 if (aOK && expMap.size() == 0)
470 {useDefs = false; useFFly = false;
471 if (useSTag)
472 {eDest->Say("Config warning: No experiments referenced; "
473 "packet marking restricted to scitagged url's!");
474 } else {
475 eDest->Say("Config warning: No experiments referenced and scitags "
476 "not enabled; packet marking has been disabled!");
477 useFFly = false;
478 }
479 } else if (!aOK)
480 {useFFly = false; useDefs = false;
481 } else {tryPath = !p2eMap.isEmpty();
482 tryVO = v2eMap.size() != 0;
483 if (doTrace) Display();
484 }
485 return aOK;
486}
487
488/******************************************************************************/
489/* Private: C o n f i g P V 2 E */
490/******************************************************************************/
491
492namespace
493{
494void Complain(const char *rWho, const char *rName,
495 const char *uWho, const char *uName, const char *eName=0)
496{
497 char *et0P = 0, eText0[256], eText1[256], eText2[256];
498 if (eName)
499 {snprintf(eText0, sizeof(eText0), "experiment %s", eName);
500 et0P = eText0;
501 }
502 snprintf(eText1, sizeof(eText1), "%s '%s'", rWho, rName);
503 snprintf(eText2, sizeof(eText2), "%s '%s'", uWho, uName);
504 eDest->Say("Config failure: ",et0P, eText1," references undefined ",eText2);
505}
506}
507
508// Note: info contains {path <path> | vo <voname> | default default} >exname>
509
510bool XrdNetPMarkCfg::ConfigPV2E(char *info)
511{
512 std::map<std::string, ExpInfo >::iterator itE;
513 std::map<std::string, ExpInfo*>::iterator itV;
514 char *eName, *xName, *xType = info;
515 xName = index(info, ' '); *xName = 0; xName++; // path | vo name
516 eName = index(xName, ' '); *eName = 0; eName++; // experiment name
517
518 if ((itE = expMap.find(std::string(eName))) == expMap.end())
519 {Complain(xType, xName, "experiment", eName);
520 return false;
521 }
522 itE->second.inUse = true;
523
524 if (*xType == 'd')
525 {expDflt = &itE->second;
526 return true;
527 }
528
529 if (*xType == 'p')
530 {XrdOucMapP2X<ExpInfo*> *p2nP = p2eMap.Find(xName);
531 if (p2nP)
532 {p2nP->RepName(eName);
533 p2nP->RepValu(&(itE->second));
534 } else {
536 (xName, eName, &(itE->second)));
537 p2eMap.Insert(px);
538 }
539 } else {
540 itV = v2eMap.find(std::string(xName));
541 if (itV != v2eMap.end()) itV->second = &(itE->second);
542 else v2eMap[xName] = &(itE->second);
543 }
544
545 return true;
546}
547
548/******************************************************************************/
549/* Private: C o n f i g R U 2 A */
550/******************************************************************************/
551
552// Note: info contains <ename> {dflt dflt | {{role | user} <xname>}} <aname>
553
554bool XrdNetPMarkCfg::ConfigRU2A(char *info)
555{
556 std::map<std::string, int>::iterator itA;
557 std::map<std::string, ExpInfo>::iterator itE;
558 std::map<std::string, MapInfo>::iterator itX;
559 char *aName, *eName, *xName, *xType;
560 eName = info; // experiment name
561 xType = index(info, ' '); *xType = 0; xType++; // dflt | role | user
562 xName = index(xType, ' '); *xName = 0; xName++; // role name | user name
563 aName = index(xName, ' '); *aName = 0; aName++; // activity name
564
565 if ((itE = expMap.find(std::string(eName))) == expMap.end())
566 {Complain(xType, xName, "experiment", eName);
567 return false;
568 }
569
570 itA = itE->second.actMap.find(std::string(aName));
571 if (itA == itE->second.actMap.end())
572 {Complain(xType, xName, "activity", aName, eName);
573 return false;
574 }
575
576 if (*xType == 'd') itE->second.dAct = itA->second;
577 else {std::map<std::string, MapInfo> &xMap =
578 (*xType == 'r' ? itE->second.r2aMap : itE->second.u2aMap);
579
580 itX = xMap.find(std::string(xName));
581 if (itX != xMap.end())
582 {itX->second.Name = aName; itX->second.Code = itA->second;}
583 else xMap[std::string(xName)] = MapInfo(aName, itA->second);
584 }
585
586 return true;
587}
588
589/******************************************************************************/
590/* Private: D i s p l a y */
591/******************************************************************************/
592
593namespace
594{
595const char *Code2S(int code)
596{
597 static char buff[16];
598 snprintf(buff, sizeof(buff), " [%d]", code);
599 return buff;
600}
601
602void ShowActs(std::map<std::string, MapInfo>& map, const char *hdr,
603 const char *mName)
604{
605 std::map<std::string, MapInfo>::iterator it;
606
607 for (it = map.begin(); it != map.end(); it++)
608 {eDest->Say(hdr, mName, it->first.c_str(), " activity ",
609 it->second.Name.c_str(), Code2S(it->second.Code));
610 }
611}
612}
613
614void XrdNetPMarkCfg::Display()
615{
616 std::map<std::string, ExpInfo>::iterator itE;
617 std::map<int, std::vector<const char*>> pvRefs;
618 const char *hdr = " ", *hdrplu = " ++ ";
619 char buff[80];
620
621// Build map from path to experiment
622//
623 std::map<int, std::vector<const char*>>::iterator it2E;
625
626 while(p2e)
627 {ExpInfo *expinfo = p2e->theValu();
628 if ((it2E = pvRefs.find(expinfo->Code)) != pvRefs.end())
629 it2E->second.push_back(p2e->thePath());
630 else {std::vector<const char*> vec;
631 vec.push_back(p2e->thePath());
632 pvRefs[expinfo->Code] = vec;
633 }
634 p2e = p2e->theNext();
635 }
636
637// Add in the vo references
638//
639 std::map<std::string, ExpInfo*>::iterator itV;
640 for (itV = v2eMap.begin(); itV != v2eMap.end(); itV++)
641 {int eCode = itV->second->Code;
642 if ((it2E = pvRefs.find(eCode)) != pvRefs.end())
643 it2E->second.push_back(itV->first.c_str());
644 else {std::vector<const char*> vec;
645 vec.push_back(itV->first.c_str());
646 pvRefs[eCode] = vec;
647 }
648 }
649
650
651// Indicate the number of experiments
652//
653 snprintf(buff, sizeof(buff), "%d", static_cast<int>(expMap.size()));
654 const char *txt = (expMap.size() == 1 ? " expirement " : " experiments ");
655 eDest->Say("Config pmark results: ", buff, txt, "directly referenced:");
656
657// Display information
658//
659 for (itE = expMap.begin(); itE != expMap.end(); itE++)
660 {int expCode = itE->second.Code;
661 eDest->Say(hdr, itE->first.c_str(), Code2S(expCode),
662 (&itE->second == expDflt ? " (default)" : 0));
663 if ((it2E = pvRefs.find(expCode)) != pvRefs.end())
664 {std::vector<const char*> &vec = it2E->second;
665 for (int i = 0; i < (int)vec.size(); i++)
666 {const char *rType = (*vec[i] == '/' ? "path " : "vorg ");
667 eDest->Say(hdrplu, rType, vec[i]);
668 }
669 }
670 if (itE->second.u2aMap.size() != 0)
671 ShowActs(itE->second.u2aMap, hdrplu, "user ");
672 if (itE->second.r2aMap.size() != 0)
673 ShowActs(itE->second.r2aMap, hdrplu, "role ");
674 if (itE->second.dAct >= 0)
675 {std::map<std::string, int>::iterator itA;
676 int aCode = itE->second.dAct;
677 for (itA = itE->second.actMap.begin();
678 itA != itE->second.actMap.end(); itA++)
679 {if (aCode == itA->second)
680 {eDest->Say(hdrplu, "Default activity ",
681 itA->first.c_str(), Code2S(aCode));
682 break;
683 }
684 }
685 if (itA == itE->second.actMap.end()) itE->second.dAct = -1;
686 }
687 }
688}
689
690/******************************************************************************/
691/* Private: E x t r a c t */
692/******************************************************************************/
693
694const char *XrdNetPMarkCfg::Extract(const char *sVec, char *buff, int blen)
695{
696 const char *space;
697
698// If there is only one token in sVec then return it.
699//
700 if (!(space = index(sVec, ' '))) return sVec;
701
702// Extract out the token using the supplied buffer
703//
704 int n = space - sVec;
705 if (!n || n >= blen) return 0;
706 snprintf(buff, blen, "%.*s", n, sVec);
707 return buff;
708}
709
710/******************************************************************************/
711/* Private: F e t c h F i l e */
712/******************************************************************************/
713
714bool XrdNetPMarkCfg::FetchFile()
715{
716 EPName("FetchFile");
717 XrdOucProg fetchJob(eDest);
718 char tmo[16], outfile[512];
719 int rc;
720
721// Setup the job
722//
723 if ((rc = fetchJob.Setup(Cfg->pgmPath.c_str(), eDest)))
724 {eDest->Emsg("Config", rc, "setup job to fetch defsfile");
725 return false;
726 }
727
728// Create the output file name (it willl be written to /tmp)
729//
730 snprintf(outfile, sizeof(outfile), "/tmp/XrdPMark-%ld.json",
731 static_cast<long>(getpid()));
732 unlink(outfile);
733
734// Insert the timeout value argument list and complete it.
735//
736 snprintf(tmo, sizeof(tmo), "%d", Cfg->defsTO);
737 Cfg->pgmOpts[1] = tmo; // 0:-x 1:tmo 2:-y 3:-z 4:outfile 5:defsfile
738 Cfg->pgmOpts[4] = outfile;
739 Cfg->pgmOpts[5] = Cfg->defsFile.c_str();
740
741// Do some debugging
742//
743 if (doDebug)
744 {for (int i = 0; i < CfgInfo::pgmOptN; i++)
745 {Cfg->pgmPath += ' '; Cfg->pgmPath += Cfg->pgmOpts[i];}
746 DEBUG("Running: " <<Cfg->pgmPath.c_str());
747 }
748
749// Run the appropriate fetch command
750//
751 rc = fetchJob.Run(Cfg->pgmOpts, CfgInfo::pgmOptN);
752 if (rc)
753 {snprintf(outfile, sizeof(outfile), "failed with rc=%d", rc);
754 eDest->Emsg("Config", "Fetch via", Cfg->pgmPath.c_str(), outfile);
755 return false;
756 }
757
758// Set the actual output file
759//
760 Cfg->defsFile = outfile;
761 return true;
762}
763
764/******************************************************************************/
765/* Private: g e t C o d e s */
766/******************************************************************************/
767
768bool XrdNetPMarkCfg::getCodes(XrdSecEntity &client, const char *path,
769 const char *cgi, int &ecode, int &acode)
770{
771 ExpInfo* expP = 0;
772
773// If we are allowed to use scitags, then try that first
774//
775 if (useSTag && cgi && XrdNetPMark::getEA(cgi, ecode, acode)) return true;
776
777// If we can use the definitions (i.e. in error) return w/o packet marking
778//
779 if (!useDefs) return false;
780
781// Try to use the path argument.
782//
783 if (tryPath && path)
784 {XrdOucMapP2X<ExpInfo*> *p2nP = p2eMap.Match(path);
785 if (p2nP) expP = p2nP->theValu();
786 }
787
788// If the path did not succeed, then try the vo
789//
790 if (!expP && tryVO && client.vorg)
791 {std::map<std::string, ExpInfo*>::iterator itV;
792 char voBuff[256];
793 const char *VO = Extract(client.vorg, voBuff, sizeof(voBuff));
794 if (VO && (itV = v2eMap.find(std::string(client.vorg))) != v2eMap.end())
795 expP = itV->second;
796 }
797
798// If there is no experiment yet, use the default if one exists
799//
800 if (!expP && expDflt) expP = expDflt;
801
802// If we still have no experiment then fail. We cannot packet mark.
803//
804 if (!expP) return false;
805 ecode = expP->Code;
806
807// If there are user to activity mappings, see if we can use that
808//
809 if (expP->Users && client.name)
810 {std::map<std::string, MapInfo>::iterator itU;
811 itU = expP->u2aMap.find(std::string(client.name));
812 if (itU != expP->u2aMap.end())
813 {acode = itU->second.Code;
814 return true;
815 }
816 }
817
818// If there are role to activity mappings, see if we can use that
819//
820 if (expP->Roles && client.role)
821 {std::map<std::string, MapInfo>::iterator itR;
822 char roBuff[256];
823 const char *RO = Extract(client.role, roBuff, sizeof(roBuff));
824 if (RO)
825 {itR = expP->r2aMap.find(std::string(client.role));
826 if (itR != expP->r2aMap.end())
827 {acode = itR->second.Code;
828 return true;
829 }
830 }
831 }
832
833// If a default activity exists, return that. Otherwise, it's unspecified.
834//
835 acode = (expP->dAct >= 0 ? expP->dAct : 0);
836 return true;
837}
838
839/******************************************************************************/
840/* Private: L o a d F i l e */
841/******************************************************************************/
842
843using json = nlohmann::json;
844
845namespace
846{
847const char *MsgTrim(const char *msg)
848{
849 const char *sP;
850 if ((sP = index(msg, ' ')) && *(sP+1)) return sP+1;
851 return msg;
852}
853}
854
855bool XrdNetPMarkCfg::LoadFile()
856{
857 struct fBuff {char *buff; fBuff() : buff(0) {}
858 ~fBuff() {if (buff) free(buff);}
859 } defs;
860 int rc;
861
862// The json file is relatively small so read the whole thing in
863//
864 if (!(defs.buff = XrdOucUtils::getFile(Cfg->defsFile.c_str(), rc)))
865 {eDest->Emsg("Config", rc, "read defsfile", Cfg->defsFile.c_str());
866 return false;
867 }
868
869// Parse the file and return result. The parser may throw an exception
870// so we will catch it here.
871//
872 try {bool result = LoadJson(defs.buff);
873 return result;
874 } catch (json::exception& e)
875 {eDest->Emsg("Config", "Unable to process defsfile;",
876 MsgTrim(e.what()));
877 }
878 return false;
879}
880
881/******************************************************************************/
882/* Private: L o a d J s o n */
883/******************************************************************************/
884
885bool XrdNetPMarkCfg::LoadJson(char *buff)
886{
887 json j;
888 std::map<std::string, ExpInfo>::iterator itE;
889
890// Parse the file; caller will catch any exceptions
891//
892 j = json::parse(buff);
893
894// Extract out modification data
895//
896 std::string modDate;
897 json j_mod = j["modified"];
898 if (j_mod != 0) modDate = j_mod.get<std::string>();
899 else modDate = "*unspecified*";
900
901 eDest->Say("Config using pmark defsfile '", Cfg->defsFile.c_str(),
902 "' last modified on ", modDate.c_str());
903
904// Extract out the experiments
905//
906 json j_exp = j["experiments"];
907 if (j_exp == 0)
908 {eDest->Emsg("Config", "The defsfile does not define any experiments!");
909 return false;
910 }
911
912// Now iterate through all of the experiments and the activities within
913// and define our local maps for each.
914//
915 for (auto it : j_exp)
916 {std::string expName = it["expName"].get<std::string>();
917 if (expName.empty()) continue;
918 if (!it["expId"].is_number() || it["expId"] < minExpID || it["expId"] > maxExpID)
919 {eDest->Say("Config warning: ignoring experiment '", expName.c_str(),
920 "'; associated ID is invalid.");
921 continue;
922 }
923 expMap[expName] = ExpInfo(it["expId"].get<int>());
924
925 if ((itE = expMap.find(expName)) == expMap.end())
926 {eDest->Say("Config warning: ignoring experiment '", expName.c_str(),
927 "'; map insertion failed!");
928 continue;
929 }
930
931 json j_acts = it["activities"];
932 if (j_acts == 0)
933 {eDest->Say("Config warning: ignoring experiment '", expName.c_str(),
934 "'; has no activities!");
935 continue;
936 }
937
938 for (unsigned int i = 0; i < j_acts.size(); i++)
939 {std::string actName = j_acts[i]["activityName"].get<std::string>();
940 if (actName.empty()) continue;
941 if (!j_acts[i]["activityId"].is_number()
942 || j_acts[i]["activityId"] < minActID
943 || j_acts[i]["activityId"] > maxActID)
944 {eDest->Say("Config warning:", "ignoring ", expName.c_str(),
945 " actitivity '", actName.c_str(),
946 "'; associated ID is invalid.");
947 continue;
948 }
949 itE->second.actMap[actName] = j_acts[i]["activityId"].get<int>();
950 }
951 }
952
953// Make sure we have at least one experiment defined
954//
955 if (!expMap.size())
956 {eDest->Say("Config warning: unable to define any experiments via defsfile!");
957 return false;
958 }
959 return true;
960}
961
962/******************************************************************************/
963/* P a r s e */
964/******************************************************************************/
965
967{
968// Parse pmark directive parameters:
969//
970// [[no]debug] [defsfile [[no]fail] {<path> | {curl | wget} [tmo] <url>}]
971// [domain {any | local | remote}] [[no]fail] [ffdest <udpdest>]
972// [ffecho <intvl>]
973// [map2act <ename> {default | {role | user} <name>} <aname>]
974// [map2exp {default | {path <path> | vo <vo>} <ename>}] [[no]trace]
975// [use {[no]flowlabel | flowlabel+ff | [no]firefly | [no]scitag}
976//
977// <udpdest>: {origin[:<port>] | <host>[:port]} [,<udpdest>]
978//
979 std::string name;
980 char *val;
981
982// If this is the first time here, allocate config info object
983//
984 if (!Cfg) Cfg = new CfgInfo;
985
986// Make sure we have something to parse
987//
988 if (!(val = Config.GetWord()))
989 {eLog->Say("Config invalid: pmark argument not specified"); return 1;}
990
991// Parse the directive options
992//
993do{if (!strcmp("debug", val) || !strcmp("nodebug", val))
994 {doDebug = (*val != 'n');
995 continue;
996 }
997
998 if (!strcmp("defsfile", val))
999 {if (!(val = Config.GetWord()))
1000 {eLog->Say("Config invalid: pmark defsfile value not specified");
1001 return 1;
1002 }
1003
1004 if (!strcmp("fail", val) || !strcmp("nofail", val))
1005 {noFail = (*val == 'n');
1006 if (!(val = Config.GetWord()))
1007 {eLog->Say("Config invalid: pmark defsfile locationnot specified");
1008 return 1;
1009 }
1010 }
1011
1012 if (*val == '/')
1013 {Cfg->defsFile = val;
1014 continue;
1015 }
1016
1017 if (strcmp("curl", val) && strcmp("wget", val))
1018 {eLog->Say("Config invalid: unknown defsfile transfer agent '",val,"'");
1019 return 1;
1020 }
1021 if (!XrdOucUtils::findPgm(val, Cfg->pgmPath))
1022 {eLog->Say("Config invalid: defsfile transfer agent '",val,"' not found.");
1023 return 1;
1024 }
1025
1026 if (*val == 'c')
1027 {Cfg->pgmOpts[0]="-m"; Cfg->pgmOpts[2]="-s"; Cfg->pgmOpts[3]="-o";
1028 } else {
1029 Cfg->pgmOpts[0]="-T"; Cfg->pgmOpts[2]="-q"; Cfg->pgmOpts[3]="-O";
1030 }
1031
1032 val = Config.GetWord();
1033 if (val && isdigit(*val))
1034 {if (XrdOuca2x::a2tm(*eLog,"defsfile timeout",val,&Cfg->defsTO,10))
1035 return 1;
1036 val = Config.GetWord();
1037 }
1038
1039 if (!val) {eLog->Say("Config invalid: pmark defsfile url not specified");
1040 return 1;
1041 }
1042 Cfg->defsFile = val;
1043 continue;
1044 }
1045
1046 if (!strcmp("domain", val))
1047 {if (!(val = Config.GetWord()))
1048 {eLog->Say("Config invalid: pmark domain value not specified");
1049 return 1;
1050 }
1051 if (!strcmp(val, "any" )
1052 || !strcmp(val, "all" )) chkDom = domAny;
1053 else if (!strcmp(val, "local" )) chkDom = domLcl;
1054 else if (!strcmp(val, "remote")) chkDom = domRmt;
1055 else {eLog->Say("Config invalid: pmark invalid domain determinant '",
1056 val, "'");
1057 return 1;
1058 }
1059 continue;
1060 }
1061
1062 if (!strcmp("fail", val) || !strcmp("nofail", val))
1063 {noFail = (*val == 'n');
1064 continue;
1065 }
1066
1067 // We accept 'origin' as a dest for backward compatibility. That is the
1068 // enforced default should 'use firefly' be specified.
1069 //
1070 if (!strcmp("ffdest", val))
1071 {const char *addtxt = "";
1072 char *colon, *comma;
1073 int xPort;
1074 val = Config.GetWord();
1075 do {if (!val || *val == 0 || *val == ',' || *val == ':')
1076 {eLog->Say("Config invalid: pmark ffdest value not specified",
1077 addtxt); return 1;
1078 }
1079 if ((comma = index(val, ','))) *comma++ = 0;
1080 if ((colon = index(val, ':')))
1081 {*colon++ = 0;
1082 if ((xPort = XrdOuca2x::a2p(*eLog, "udp", colon, false)) <= 0)
1083 return 1;
1084 } else xPort = ffPORT;
1085 if (!strcmp(val, "origin")) ffPortO = xPort;
1086 else {if (ffDest) free(ffDest);
1087 ffDest = strdup(val);
1088 ffPortD = xPort;
1089 }
1090 addtxt = " after comma";
1091 } while((val = comma));
1092 if (useFFly < 0) useFFly = 1;
1093 continue;
1094 }
1095
1096 if (!strcmp("ffecho", val))
1097 {if (!(val = Config.GetWord()))
1098 {eLog->Say("Config invalid: pmark ffecho value not specified");
1099 return 1;
1100 }
1101 if (XrdOuca2x::a2tm(*eLog,"ffecho interval", val, &ffEcho, 0)) return 1;
1102 if (ffEcho < 30) ffEcho = 0;
1103 continue;
1104 }
1105
1106 if (!strcmp("map2act", val))
1107 {if (!(val = Config.GetWord()))
1108 {eLog->Say("Config invalid: pmark activity experiment not specified");
1109 return 1;
1110 }
1111 name = val;
1112
1113 if (!(val = Config.GetWord()))
1114 {eLog->Say("Config invalid: pmark activity determinant not specified");
1115 return 1;
1116 }
1117
1118 const char *adet;
1119 if (!strcmp(val, "default")) adet = "dflt";
1120 else if (!strcmp(val, "role")) adet = "role";
1121 else if (!strcmp(val, "user")) adet = "user";
1122 else {eLog->Say("Config invalid: pmark invalid activity determinant '",
1123 val, "'");
1124 return 1;
1125 }
1126 name += ' '; name += val;
1127
1128 if (*adet != 'd' && !(val = Config.GetWord()))
1129 {eLog->Say("Config invalid: pmark activity", adet, "not specified");
1130 return 1;
1131 }
1132 name += ' '; name += val;
1133
1134 if (!(val = Config.GetWord()))
1135 {eLog->Say("Config invalid: pmark", adet, "activity not specified");
1136 return 1;
1137 }
1138 name += ' '; name += val;
1139
1140 Cfg->x2aSet.insert(name);
1141 continue;
1142 }
1143
1144 if (!strcmp("map2exp", val))
1145 {if (!(val = Config.GetWord()))
1146 {eLog->Say("Config invalid: pmark map2exp type not specified");
1147 return 1;
1148 }
1149 if (strcmp("default", val) && strcmp("path", val)
1150 && strcmp("vo", val) && strcmp("vorg", val))
1151 {eLog->Say("Config invalid: invalid pmark map2exp type, '",val,"'.");
1152 return 1;
1153 }
1154 name = val;
1155
1156 if (*val != 'd' && !(val = Config.GetWord()))
1157 {eLog->Say("Config invalid: pmark map2exp ", name.c_str(),
1158 "not specified");
1159 return 1;
1160 }
1161 name += ' '; name += val;
1162
1163 if (!(val = Config.GetWord()))
1164 {eLog->Say("Config invalid: pmark map2exp expirement not specified");
1165 return 1;
1166 }
1167 name += ' '; name += val;
1168
1169 Cfg->x2eSet.insert(name);
1170 continue;
1171 }
1172
1173 if (!strcmp("trace", val) || !strcmp("notrace", val))
1174 {doTrace = (*val != 'n');
1175 continue;
1176 }
1177
1178 if (!strcmp("use", val))
1179 {if (!(val = Config.GetWord()))
1180 {eLog->Say("Config invalid: pmark use argument not specified");
1181 return 1;
1182 }
1183 bool argOK = false;
1184 char *arg;
1185 do {bool theval = strncmp(val, "no", 2) != 0;
1186 arg = (!theval ? val += 2 : val);
1187 if (!strcmp("flowlabel", arg))
1188 {useFLbl = theval; addFLFF = false; argOK = true;}
1189 else if (!strcmp("flowlabel+ff", arg))
1190 {addFLFF = useFLbl = theval; argOK = true;}
1191 else if (!strcmp("firefly", arg))
1192 {useFFly = (theval ? 1 : 0); argOK = true;}
1193 else if (!strcmp("scitag", arg)) {useSTag = theval; argOK = true;}
1194 else if (argOK) {Config.RetToken(); break;}
1195 else {eLog->Say("Config invalid: 'use ",val,"' is invalid");
1196 return 1;
1197 }
1198 } while((val = Config.GetWord()));
1199 if (!val) break;
1200 continue;
1201 }
1202
1203 eLog->Say("Config warning: ignoring unknown pmark argument'",val,"'.");
1204
1205 } while ((val = Config.GetWord()));
1206
1207 return 0;
1208}
#define tident
#define DEBUG(x)
static XrdSysError eDest(0,"crypto_")
#define EPName(ep)
nlohmann::json json
#define DBGID(tid, txt)
#define unlink(a)
Definition XrdPosix.hh:113
#define TRACE(act, x)
Definition XrdTrace.hh:63
static bool isHostName(const char *name)
int Format(char *bAddr, int bLen, fmtUse fmtType=fmtAuto, int fmtOpts=0)
const char * Name(const char *eName=0, const char **eText=0)
const char * Set(const char *hSpec, int pNum=PortInSpec)
static int Parse(XrdSysError *eLog, XrdOucStream &Config)
static XrdNetPMark * Config(XrdSysError *eLog, XrdScheduler *sched, XrdSysTrace *trc, bool &fatal)
XrdNetPMark::Handle * Begin(XrdSecEntity &Client, const char *path=0, const char *cgi=0, const char *app=0) override
std::map< std::string, int > actMap
std::map< std::string, MapInfo > u2aMap
std::map< std::string, MapInfo > r2aMap
bool Start(XrdNetAddrInfo &addr)
static bool getEA(const char *cgi, int &ecode, int &acode)
static const int maxExpID
static const int minActID
static const int maxActID
static const int minExpID
static char * MyHostName(const char *eName="*unknown*", const char **eText=0)
const char * thePath()
void RepName(const char *newname)
void Insert(XrdOucMapP2X< T > *newp)
XrdOucMapP2X< T > * Match(const char *pd, const int pl=0)
XrdOucMapP2X< T > * Find(const char *path)
XrdOucMapP2X< T > * theNext()
void RepValu(T arg)
void insert(const int i, int start=-1)
bool beginswith(char c)
int length() const
const char * c_str() const
static bool findPgm(const char *pgm, XrdOucString &path)
static char * getFile(const char *path, int &rc, int maxsz=10240, bool notempty=true)
static int a2tm(XrdSysError &, const char *emsg, const char *item, int *val, int minv=-1, int maxv=-1)
Definition XrdOuca2x.cc:288
static int a2p(XrdSysError &, const char *ptype, const char *val, bool anyOK=true)
Definition XrdOuca2x.cc:140
char * vorg
Entity's virtual organization(s)
XrdNetAddrInfo * addrInfo
Entity's connection details.
const char * tident
Trace identifier always preset.
char * name
Entity's name.
char * role
Entity's role(s)
int Emsg(const char *esfx, int ecode, const char *text1, const char *text2=0)
void Say(const char *text1, const char *text2=0, const char *txt3=0, const char *text4=0, const char *text5=0, const char *txt6=0)
XrdSysTrace * Trace
std::map< std::string, ExpInfo > expMap
static const int domLcl
std::map< std::string, ExpInfo * > v2eMap
static const int ffPORT
XrdScheduler * Sched
XrdSysError * eDest
const char * myDomain
const char * myHostName
XrdOucMapP2X< ExpInfo * > p2eMap
static const int domAny
static const int domRmt
XrdSysError * eLog
std::set< std::string > x2eSet
const char * pgmOpts[pgmOptN]
std::set< std::string > x2aSet

◆ DEBUG

#define DEBUG (   txt)     if (doDebug) SYSTRACE(Trace->, 0, epName, 0, txt)

Definition at line 65 of file XrdNetPMarkCfg.cc.

◆ EPName

#define EPName (   ep)    const char *epName = ep

Definition at line 71 of file XrdNetPMarkCfg.cc.

◆ TRACE

#define TRACE (   txt)     if (doTrace) SYSTRACE(Trace->, client.tident, epName, 0, txt)

Definition at line 62 of file XrdNetPMarkCfg.cc.

Typedef Documentation

◆ json

using json = nlohmann::json

Definition at line 843 of file XrdNetPMarkCfg.cc.