diff --git a/src/XrdXrootd/XrdXrootdConfig.cc b/src/XrdXrootd/XrdXrootdConfig.cc index e54ae79c066..e7763ae5b2c 100644 --- a/src/XrdXrootd/XrdXrootdConfig.cc +++ b/src/XrdXrootd/XrdXrootdConfig.cc @@ -481,6 +481,7 @@ int XrdXrootdProtocol::Config(const char *ConfigFN) else if TS_Xeq("redirect", xred); else if TS_Xeq("seclib", xsecl); else if TS_Xeq("trace", xtrace); + else if TS_Xeq("limit", xlimit); else {eDest.Say("Config warning: ignoring unknown directive '",var,"'."); Config.Echo(); continue; @@ -1547,3 +1548,42 @@ int XrdXrootdProtocol::xtrace(XrdOucStream &Config) XrdXrootdTrace->What = trval; return 0; } + +/******************************************************************************/ +/* x l i m i t */ +/******************************************************************************/ + +/* Function: xlimit + + Purpose: To parse the directive: limit [prepare ] [noerror] + + prepare The maximum number of prepares that are allowed + during the course of a single connection + + noerror When possible, do not issue an error when a limit + is hit. + + Output: 0 upon success or 1 upon failure. +*/ +int XrdXrootdProtocol::xlimit(XrdOucStream &Config) +{ + int plimit = -1; + const char *word; + +// Look for various limits set +// + while ( (word = Config.GetWord()) ) { + if (!strcmp(word, "prepare")) { + if (!(word = Config.GetWord())) + { + eDest.Emsg("Config", "'limit prepare' value not specified"); + return 1; + } + if (XrdOuca2x::a2i(eDest, "limit prepare", word, &plimit, 0)) { return 1; } + } else if (!strcmp(word, "noerror")) { + LimitError = false; + } + } + if (plimit >= 0) {PrepareLimit = plimit;} + return 0; +} diff --git a/src/XrdXrootd/XrdXrootdProtocol.cc b/src/XrdXrootd/XrdXrootdProtocol.cc index b9b94f18edb..2a6c085c356 100644 --- a/src/XrdXrootd/XrdXrootdProtocol.cc +++ b/src/XrdXrootd/XrdXrootdProtocol.cc @@ -118,6 +118,9 @@ int XrdXrootdProtocol::myPID = static_cast(getpid()); int XrdXrootdProtocol::myRole = 0; int XrdXrootdProtocol::myRolf = 0; +int XrdXrootdProtocol::PrepareLimit = -1; +bool XrdXrootdProtocol::LimitError = true; + struct XrdXrootdProtocol::RD_Table XrdXrootdProtocol::Route[RD_Num]; /******************************************************************************/ @@ -846,4 +849,5 @@ void XrdXrootdProtocol::Reset() rdType = 0; memset(&Entity, 0, sizeof(Entity)); memset(Stream, 0, sizeof(Stream)); + PrepareCount = 0; } diff --git a/src/XrdXrootd/XrdXrootdProtocol.hh b/src/XrdXrootd/XrdXrootdProtocol.hh index 0139cad1ecb..fad143f3ed2 100644 --- a/src/XrdXrootd/XrdXrootdProtocol.hh +++ b/src/XrdXrootd/XrdXrootdProtocol.hh @@ -222,6 +222,7 @@ static void xred_set(RD_func func, char *rHost[2], int rPort[2]); static bool xred_xok(int func, char *rHost[2], int rPort[2]); static int xsecl(XrdOucStream &Config); static int xtrace(XrdOucStream &Config); +static int xlimit(XrdOucStream &Config); static XrdObjectQ ProtStack; XrdObject ProtLink; @@ -389,6 +390,13 @@ char doWrite; char doWriteC; char rvSeq; +// Track usage limts. +// +static bool LimitError; // Indicates that hitting a limit should result in an error response. + // If false, when possible, silently ignore errors. +int PrepareCount; +static int PrepareLimit; + // Buffers to handle client requests // XrdXrootdReqID ReqID; diff --git a/src/XrdXrootd/XrdXrootdXeq.cc b/src/XrdXrootd/XrdXrootdXeq.cc index de6dbf368a7..4f8b68fe979 100644 --- a/src/XrdXrootd/XrdXrootdXeq.cc +++ b/src/XrdXrootd/XrdXrootdXeq.cc @@ -1416,6 +1416,16 @@ int XrdXrootdProtocol::do_Prepare() XrdXrootdPrepArgs pargs(0, 0); XrdSfsPrep fsprep; +// Apply prepare limits, as necessary. + if ((PrepareLimit >= 0) && (++PrepareCount > PrepareLimit)) { + if (LimitError) { + return Response.Send(kXR_noserver, + "Surpassed this connection's prepare limit."); + } else { + return Response.Send(); + } + } + // Grab the options // opts = Request.prepare.options;