Skip to content

Commit 4402841

Browse files
committed
clientContextImpl: Cap the number and age of beacons
Each beacon has an associated mutex. If we allocate too many beacons on resource constrained systems, i.e. RTEMS, we may run out of resources and crash.
1 parent f1268ad commit 4402841

File tree

2 files changed

+100
-0
lines changed

2 files changed

+100
-0
lines changed

src/remote/pv/beaconHandler.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,12 @@
2626
#include <pv/remote.h>
2727
#include <pv/pvAccess.h>
2828

29+
namespace
30+
{
31+
class InternalClientContextImpl;
32+
class BeaconCleanupHandler;
33+
}
34+
2935
namespace epics {
3036
namespace pvAccess {
3137

@@ -85,6 +91,10 @@ class BeaconHandler
8591
* First beacon flag.
8692
*/
8793
bool _first;
94+
/**
95+
* Callback for cleaning up the beacon
96+
*/
97+
std::shared_ptr<BeaconCleanupHandler> _callback;
8898

8999
/**
90100
* Update beacon.
@@ -100,6 +110,8 @@ class BeaconHandler
100110
ServerGUID const &guid,
101111
epics::pvData::int16 sequentalID,
102112
epics::pvData::int16 changeCount);
113+
114+
friend class ::InternalClientContextImpl;
103115
};
104116

105117
}

src/remoteClient/clientContextImpl.cpp

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,9 @@ using std::tr1::static_pointer_cast;
4949
using namespace std;
5050
using namespace epics::pvData;
5151

52+
static const float maxBeaconLifetime = 180.f * 2.f;
53+
static const int maxTrackedBeacons = 20000;
54+
5255
namespace epics {
5356
namespace pvAccess {
5457

@@ -3038,7 +3041,43 @@ enum ContextState {
30383041
};
30393042

30403043

3044+
/**
3045+
* Handles cleanup of old beacons.
3046+
*/
3047+
class BeaconCleanupHandler
3048+
{
3049+
public:
3050+
POINTER_DEFINITIONS(BeaconCleanupHandler);
30413051

3052+
class Callback : public TimerCallback
3053+
{
3054+
public:
3055+
Callback(BeaconCleanupHandler& handler) : m_handler(handler)
3056+
{
3057+
}
3058+
3059+
virtual void callback() OVERRIDE FINAL;
3060+
virtual void timerStopped() OVERRIDE FINAL;
3061+
3062+
BeaconCleanupHandler& m_handler;
3063+
};
3064+
3065+
BeaconCleanupHandler(InternalClientContextImpl& impl, osiSockAddr addr);
3066+
~BeaconCleanupHandler();
3067+
3068+
/**
3069+
* Set the last time used to the current time
3070+
*/
3071+
void touch() { epicsTimeGetCurrent(&m_lastTime); }
3072+
3073+
private:
3074+
void remove();
3075+
3076+
std::shared_ptr<Callback> m_callback;
3077+
osiSockAddr m_from;
3078+
InternalClientContextImpl& m_impl;
3079+
epicsTimeStamp m_lastTime;
3080+
};
30423081

30433082
class InternalClientContextImpl :
30443083
public ClientContextImpl,
@@ -4351,12 +4390,25 @@ class InternalClientContextImpl :
43514390
BeaconHandler::shared_pointer handler;
43524391
if (it == m_beaconHandlers.end())
43534392
{
4393+
/* If we're tracking too many beacons, we'll just ignore this one */
4394+
if (m_beaconHandlers.size() >= maxTrackedBeacons)
4395+
{
4396+
char ipa[64];
4397+
sockAddrToDottedIP(&responseFrom->sa, ipa, sizeof(ipa));
4398+
LOG(logLevelWarn, "Tracked beacon limit reached (%d), ignoring %s\n", maxTrackedBeacons, ipa);
4399+
return nullptr;
4400+
}
4401+
43544402
// stores weak_ptr
43554403
handler.reset(new BeaconHandler(internal_from_this(), responseFrom));
4404+
handler->_callback = std::make_shared<BeaconCleanupHandler>(*this, *responseFrom);
43564405
m_beaconHandlers[*responseFrom] = handler;
43574406
}
43584407
else
4408+
{
43594409
handler = it->second;
4410+
handler->_callback->touch(); /* Update the callback's latest use time */
4411+
}
43604412
return handler;
43614413
}
43624414

@@ -4556,8 +4608,44 @@ class InternalClientContextImpl :
45564608
Configuration::shared_pointer m_configuration;
45574609

45584610
TransportRegistry::transportVector_t m_flushTransports;
4611+
4612+
friend class BeaconCleanupHandler;
45594613
};
45604614

4615+
4616+
BeaconCleanupHandler::BeaconCleanupHandler(InternalClientContextImpl& impl, osiSockAddr addr) :
4617+
m_callback(std::make_shared<Callback>(*this)),
4618+
m_from(addr),
4619+
m_impl(impl)
4620+
{
4621+
m_impl.m_timer->schedulePeriodic(m_callback, maxBeaconLifetime, maxBeaconLifetime);
4622+
}
4623+
4624+
BeaconCleanupHandler::~BeaconCleanupHandler()
4625+
{
4626+
m_impl.m_timer->cancel(m_callback);
4627+
}
4628+
4629+
void BeaconCleanupHandler::Callback::callback()
4630+
{
4631+
epicsTimeStamp ts;
4632+
epicsTimeGetCurrent(&ts);
4633+
if (epicsTimeDiffInSeconds(&ts, &m_handler.m_lastTime) > maxBeaconLifetime)
4634+
m_handler.remove();
4635+
}
4636+
4637+
void BeaconCleanupHandler::Callback::timerStopped()
4638+
{
4639+
m_handler.remove();
4640+
}
4641+
4642+
void BeaconCleanupHandler::remove()
4643+
{
4644+
Lock guard(m_impl.m_beaconMapMutex);
4645+
m_impl.m_timer->cancel(m_callback);
4646+
m_impl.m_beaconHandlers.erase(m_from); /* Erase the beacon entirely */
4647+
}
4648+
45614649
size_t InternalClientContextImpl::num_instances;
45624650
size_t InternalClientContextImpl::InternalChannelImpl::num_instances;
45634651
size_t InternalClientContextImpl::InternalChannelImpl::num_active;

0 commit comments

Comments
 (0)