#include <dhcpsrv/host_mgr.h>
#include <radius_access.h>
#include <radius_log.h>
+#include <radius_status.h>
#include <radius_utils.h>
#include <util/multi_threading_mgr.h>
#include <stdio.h>
}
}
+void
+RadiusAccess::setIdleTimer() {
+ MultiThreadingLock lock(idle_timer_mutex_);
+ cancelIdleTimer();
+ if (idle_timer_interval_ <= 0) {
+ return;
+ }
+ // Cope to one day.
+ long secs = idle_timer_interval_;
+ if (secs > 24*60*60) {
+ secs = 24*60*60;
+ }
+ idle_timer_.reset(new IntervalTimer(RadiusImpl::instance().getIOContext()));
+ idle_timer_->setup(RadiusAccess::IdleTimerCallback,
+ secs * 1000, IntervalTimer::REPEATING);
+}
+
+void
+RadiusAccess::IdleTimerCallback() {
+ AttributesPtr send_attrs;
+ RadiusAuthStatusPtr handler(new RadiusAuthStatus(send_attrs, 0));
+ RadiusImpl::instance().registerExchange(handler->getExchange());
+ handler->start();
+}
+
} // end of namespace isc::radius
} // end of namespace isc
/// @brief Pending RADIUS access requests - IPv6.
RadiusAuthPendingRequests<dhcp::Pkt6Ptr> requests6_;
+ /// @brief Set idle timer.
+ ///
+ /// @note: The caller must hold the idle timer mutex.
+ void setIdleTimer();
+
+ /// @brief Idle timer callback.
+ static void IdleTimerCallback();
+
};
} // end of namespace isc::radius
#include <dhcpsrv/subnet.h>
#include <radius_accounting.h>
#include <radius_log.h>
+#include <radius_status.h>
#include <radius_utils.h>
#include <util/multi_threading_mgr.h>
#include <stdio.h>
const CallbackAcct& callback)
: env_(env), acct_() {
acct_.reset(new RadiusAsyncAcct(env_.subnet_id_, env_.send_attrs_, callback));
- MultiThreadingLock lock(mutex_);
RadiusImpl::instance().registerExchange(acct_->getExchange());
+ MultiThreadingLock lock(mutex_);
++counter_;
}
record_count_ = 0;
}
+void
+RadiusAccounting::setIdleTimer() {
+ MultiThreadingLock lock(idle_timer_mutex_);
+ cancelIdleTimer();
+ if (idle_timer_interval_ <= 0) {
+ return;
+ }
+ // Cope to one day.
+ long secs = idle_timer_interval_;
+ if (secs > 24*60*60) {
+ secs = 24*60*60;
+ }
+ idle_timer_.reset(new IntervalTimer(RadiusImpl::instance().getIOContext()));
+ idle_timer_->setup(RadiusAccounting::IdleTimerCallback,
+ secs * 1000, IntervalTimer::REPEATING);
+}
+
+void
+RadiusAccounting::IdleTimerCallback() {
+ AttributesPtr send_attrs;
+ RadiusAcctStatusPtr handler(new RadiusAcctStatus(send_attrs, 0));
+ RadiusImpl::instance().registerExchange(handler->getExchange());
+ handler->start();
+}
+
} // end of namespace isc::radius
} // end of namespace isc
/// in the increasing timestamp order.
void storeToFile();
+ /// @brief Set idle timer.
+ ///
+ /// @note: The caller must hold the idle timer mutex.
+ void setIdleTimer();
+
+ /// @brief Idle timer callback.
+ static void IdleTimerCallback();
+
protected:
/// @brief Create timestamps file name.
/// @brief Keywords for service configuration.
const set<string>
RadiusServiceParser::SERVICE_KEYWORDS = {
- "servers", "attributes", "peer-updates", "max-pending-requests"
+ "servers", "attributes", "peer-updates", "max-pending-requests",
+ "idle-timer-interval"
};
void
}
service->max_pending_requests_ = max_pending_requests->intValue();
}
+
+ // idle-timer-interval.
+ const ConstElementPtr& idle_timer_interval =
+ srv_cfg->get("idle-timer-interval");
+ if (idle_timer_interval) {
+ if (idle_timer_interval->getType() != Element::integer) {
+ isc_throw(BadValue, "expected idle-timer-interval to be "
+ << "integer, but got "
+ << Element::typeToName(idle_timer_interval->getType())
+ << " instead");
+ }
+ if (idle_timer_interval->intValue() < 0) {
+ isc_throw(BadValue, "expected idle-timer-interval to be "
+ << "positive, but got "
+ << idle_timer_interval->intValue()
+ << " instead");
+ }
+ service->idle_timer_interval_ = idle_timer_interval->intValue();
+ }
} catch (const std::exception& ex) {
isc_throw(ConfigError, ex.what() << " (parsing "
<< service->name_ << ")");
LOG_DEBUG(radius_logger, RADIUS_DBG_TRACE,
RADIUS_AUTHENTICATION_SYNC_ACCEPTED)
.arg(recv_attrs ? recv_attrs->toText() : "no attributes");
+ RadiusImpl::instance().auth_->setIdleTimer();
} else if (result == REJECT_RC) {
LOG_DEBUG(radius_logger, RADIUS_DBG_TRACE,
RADIUS_AUTHENTICATION_SYNC_REJECTED)
.arg(recv_attrs ? recv_attrs->toText() : "no attributes");
+ RadiusImpl::instance().auth_->setIdleTimer();
} else {
LOG_DEBUG(radius_logger, RADIUS_DBG_TRACE,
RADIUS_AUTHENTICATION_SYNC_FAILED)
LOG_DEBUG(radius_logger, RADIUS_DBG_TRACE,
RADIUS_AUTHENTICATION_ASYNC_ACCEPTED)
.arg(recv_attrs ? recv_attrs->toText() : "no attributes");
+ RadiusImpl::instance().auth_->setIdleTimer();
} else if (result == REJECT_RC) {
LOG_DEBUG(radius_logger, RADIUS_DBG_TRACE,
RADIUS_AUTHENTICATION_ASYNC_REJECTED)
.arg(recv_attrs ? recv_attrs->toText() : "no attributes");
+ RadiusImpl::instance().auth_->setIdleTimer();
} else {
LOG_DEBUG(radius_logger, RADIUS_DBG_TRACE,
RADIUS_AUTHENTICATION_ASYNC_FAILED)
if (result == OK_RC) {
LOG_DEBUG(radius_logger, RADIUS_DBG_TRACE,
RADIUS_ACCOUNTING_SYNC_SUCCEED);
+ RadiusImpl::instance().acct_->setIdleTimer();
} else {
LOG_DEBUG(radius_logger, RADIUS_DBG_TRACE,
RADIUS_ACCOUNTING_SYNC_FAILED)
if (result == OK_RC) {
LOG_DEBUG(radius_logger, RADIUS_DBG_TRACE,
RADIUS_ACCOUNTING_ASYNC_SUCCEED);
+ RadiusImpl::instance().acct_->setIdleTimer();
} else {
LOG_DEBUG(radius_logger, RADIUS_DBG_TRACE,
RADIUS_ACCOUNTING_ASYNC_FAILED)
#include <config.h>
#include <radius_service.h>
+#include <util/multi_threading_mgr.h>
using namespace std;
using namespace isc;
using namespace isc::data;
+using namespace isc::util;
namespace isc {
namespace radius {
RadiusService::RadiusService(const std::string& name)
: name_(name), enabled_(false), peer_updates_(true),
- max_pending_requests_(0) {
+ max_pending_requests_(0), idle_timer_interval_(), idle_timer_() {
+}
+
+RadiusService::~RadiusService() {
+ MultiThreadingLock lock(idle_timer_mutex_);
+ cancelIdleTimer();
}
ElementPtr
// attributes.
result->set("attributes", attributes_.toElement());
+ // idle-timer-interval.
+ result->set("idle-timer-interval", Element::create(idle_timer_interval_));
+
return (result);
}
+void
+RadiusService::cancelIdleTimer() {
+ if (idle_timer_) {
+ idle_timer_->cancel();
+ idle_timer_.reset();
+ }
+}
+
} // end of namespace isc::radius
} // end of namespace isc
#ifndef RADIUS_SERVICE_H
#define RADIUS_SERVICE_H
-#include <cc/cfg_to_element.h>
-#include <cc/data.h>
#include <client_server.h>
#include <cfg_attribute.h>
+#include <asiolink/asio_wrapper.h>
+#include <asiolink/interval_timer.h>
+#include <cc/cfg_to_element.h>
+#include <cc/data.h>
#include <boost/noncopyable.hpp>
#include <boost/shared_ptr.hpp>
+#include <mutex>
namespace isc {
namespace radius {
/// @param name service name.
explicit RadiusService(const std::string& name);
- /// @brief Default destructor.
- virtual ~RadiusService() = default;
+ /// @brief Destructor.
+ virtual ~RadiusService();
/// @brief Unparse service configuration.
///
/// @brief Maximum number of pending requests.
size_t max_pending_requests_;
+
+ /// @brief Idle timer interval in seconds.
+ long idle_timer_interval_;
+
+ /// @brief Idle timer.
+ asiolink::IntervalTimerPtr idle_timer_;
+
+ /// @brief Idle timer mutex.
+ std::mutex idle_timer_mutex_;
+
+ /// @brief Cancel idle timer.
+ ///
+ /// @note: The caller must hold the idle timer mutex.
+ void cancelIdleTimer();
};
/// @brief Type of pointers to Radius service.
if (result == OK_RC) {
LOG_DEBUG(radius_logger, RADIUS_DBG_TRACE,
RADIUS_AUTHENTICATION_STATUS_SUCCEED);
+ RadiusImpl::instance().auth_->setIdleTimer();
} else {
LOG_DEBUG(radius_logger, RADIUS_DBG_TRACE,
RADIUS_AUTHENTICATION_STATUS_FAILED)
if (result == OK_RC) {
LOG_DEBUG(radius_logger, RADIUS_DBG_TRACE,
RADIUS_ACCOUNTING_STATUS_SUCCEED);
+ RadiusImpl::instance().acct_->setIdleTimer();
} else {
LOG_DEBUG(radius_logger, RADIUS_DBG_TRACE,
RADIUS_ACCOUNTING_STATUS_FAILED)
EXPECT_NO_THROW(impl_.init(config));
string expected = "{ "
"\"access\": {"
- " \"attributes\": [ ]"
+ " \"attributes\": [ ],"
+ " \"idle-timer-interval\": 0"
"}, "
"\"accounting\": {"
- " \"attributes\": [ ]"
+ " \"attributes\": [ ],"
+ " \"idle-timer-interval\": 0"
"}, "
"\"bindaddr\": \"*\", "
"\"canonical-mac-address\": false, "
EXPECT_NO_THROW(impl_.init(config));
string expected = "{ "
"\"access\": {"
- " \"attributes\": [ ]"
+ " \"attributes\": [ ],"
+ " \"idle-timer-interval\": 0"
"}, "
"\"accounting\": {"
- " \"attributes\": [ ]"
+ " \"attributes\": [ ],"
+ " \"idle-timer-interval\": 0"
"}, "
"\"bindaddr\": \"127.0.0.1\", "
"\"canonical-mac-address\": true, "
" \"name\": \"User-Name\", "
" \"type\": 1, "
" \"data\": \"foobar\" "
- "} ] }";
+ "} ],"
+ "\"idle-timer-interval\": 0"
+ "}";
runToElementTest<RadiusService>(expected, *impl_.auth_);
// Needs a server to be enabled.
expected = "{ "
"\"attributes\": [ ], "
+ "\"idle-timer-interval\": 0,"
"\"servers\": [ {"
" \"deadtime\": 0, "
" \"local-address\": \"127.0.0.1\", "
expected = "{ "
"\"attributes\": [ ], "
+ "\"idle-timer-interval\": 0,"
"\"servers\": [ {"
" \"deadtime\": 0, "
" \"local-address\": \"127.0.0.1\", "
EXPECT_NO_THROW_LOG(impl_.reset());
}
+// Verify that idle-timer-interval can be configured and that proper errors
+// are reported in negative cases.
+TEST_F(ConfigTest, idleTimerInterval) {
+ ElementPtr config;
+
+ config = Element::fromJSON(R"({
+ "access": {
+ "idle-timer-interval": -1
+ }
+ })");
+ EXPECT_THROW_MSG(impl_.init(config), ConfigError,
+ "expected idle-timer-interval to be positive, but got "
+ "-1 instead (parsing access)");
+ EXPECT_NO_THROW_LOG(impl_.reset());
+
+ config = Element::fromJSON(R"({
+ "accounting": {
+ "idle-timer-interval": false
+ }
+ })");
+ EXPECT_THROW_MSG(impl_.init(config), ConfigError,
+ "expected idle-timer-interval to be integer, but got "
+ "boolean instead (parsing accounting)");
+ EXPECT_NO_THROW_LOG(impl_.reset());
+
+ config = Element::fromJSON(R"({
+ "access": {
+ "idle-timer-interval": 10
+ }
+ })");
+ EXPECT_NO_THROW_LOG(impl_.init(config));
+ EXPECT_EQ(10, impl_.auth_->idle_timer_interval_);
+ EXPECT_NO_THROW_LOG(impl_.reset());
+
+ config = Element::createMap();
+ EXPECT_NO_THROW_LOG(impl_.init(config));
+ EXPECT_EQ(0, impl_.auth_->idle_timer_interval_);
+ EXPECT_NO_THROW_LOG(impl_.reset());
+}
+
} // end of anonymous namespace