@@ -49,6 +49,9 @@ using std::tr1::static_pointer_cast;
4949using namespace std ;
5050using namespace epics ::pvData;
5151
52+ static const float maxBeaconLifetime = 180 .f * 2 .f;
53+ static const int maxTrackedBeacons = 20000 ;
54+
5255namespace epics {
5356namespace 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
30433082class 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+
45614649size_t InternalClientContextImpl::num_instances;
45624650size_t InternalClientContextImpl::InternalChannelImpl::num_instances;
45634651size_t InternalClientContextImpl::InternalChannelImpl::num_active;
0 commit comments