namespace isc {
namespace radius {
-UdpClient::UdpClient(const IOServicePtr& io_service, size_t thread_pool_size)
+UdpClient::UdpClient(const IOServicePtr& io_service, unsigned thread_pool_size)
: io_service_(io_service), thread_pool_size_(thread_pool_size) {
// Do nothing in ST mode.
if (thread_pool_size == 0) {
stop();
}
-size_t
+unsigned
UdpClient::getThreadPoolSize() const {
return (thread_pool_size_);
}
ConstElementPtr const& dhcp_config(
CfgMgr::instance().getStagingCfg()->getDHCPMultiThreading());
bool multi_threaded(false);
+ unsigned thread_pool_size(0);
uint32_t dhcp_threads(0);
uint32_t dummy_queue_size(0);
CfgMultiThreading::extract(dhcp_config, multi_threaded, dhcp_threads,
if (multi_threaded) {
// When threads are configured as zero, use the same number as DHCP
// threads. If that is also zero, auto-detect.
- unsigned thread_pool_size(thread_pool_size_);
if (thread_pool_size_ == 0) {
if (dhcp_threads == 0) {
uint32_t const hardware_threads(
MultiThreadingMgr::detectThreadCount());
if (hardware_threads == 0) {
// Keep it single-threaded.
- return;
+ multi_threaded = false;
+ thread_pool_size = 0;
} else {
thread_pool_size = hardware_threads;
}
} else {
thread_pool_size = dhcp_threads;
}
+ } else {
+ thread_pool_size = thread_pool_size_;
}
+ }
+ if (multi_threaded) {
// Schedule a start of the services. This ensures we begin after
// the dust has settled and Kea MT mode has been firmly established.
io_service_->post([this, thread_pool_size]() {
return (common_ && common_->enabled_);
}
+const Servers&
+RadiusImpl::getAccessServers() const {
+ if (proto_ != PW_PROTO_TLS) {
+ return (auth_->servers_);
+ } else {
+ return (common_->servers_);
+ }
+}
+
+const Servers&
+RadiusImpl::getAccountingServers() const {
+ if (proto_ != PW_PROTO_TLS) {
+ return (acct_->servers_);
+ } else {
+ return (common_->servers_);
+ }
+}
+
void
RadiusImpl::setAccessIdleTimer() {
if (shutdown_) {
/// The value 0 means that MT is disabled.
/// deferred until a subsequent call to @ref start().
UdpClient(const asiolink::IOServicePtr& io_service,
- size_t thread_pool_size = 0);
+ unsigned thread_pool_size = 0);
/// @brief Destructor.
~UdpClient();
/// @brief the maximum size of the thread pool.
///
/// @return the maximum size of the thread pool.
- size_t getThreadPoolSize() const;
+ unsigned getThreadPoolSize() const;
/// @brief Register Exchange.
///
/// @return true is accounting is served, false otherwise.
bool serveAccounting() const;
+ /// @brief Get servers for access.
+ ///
+ /// @return Servers to use with access servers.
+ const Servers& getAccessServers() const;
+
+ /// @brief Get servers for accounting.
+ ///
+ /// @return Servers to use with accounting servers.
+ const Servers& getAccountingServers() const;
+
/// @brief Set the access idle timer.
void setAccessIdleTimer();
extern const isc::log::MessageID RADIUS_SESSION_HISTORY_STORED = "RADIUS_SESSION_HISTORY_STORED";
extern const isc::log::MessageID RADIUS_SESSION_HISTORY_STORE_FAILED = "RADIUS_SESSION_HISTORY_STORE_FAILED";
extern const isc::log::MessageID RADIUS_THREAD_POOL_STARTED = "RADIUS_THREAD_POOL_STARTED";
+extern const isc::log::MessageID RADIUS_TLS_STATUS = "RADIUS_TLS_STATUS";
+extern const isc::log::MessageID RADIUS_TLS_STATUS_ERROR = "RADIUS_TLS_STATUS_ERROR";
+extern const isc::log::MessageID RADIUS_TLS_STATUS_FAILED = "RADIUS_TLS_STATUS_FAILED";
+extern const isc::log::MessageID RADIUS_TLS_STATUS_SUCCEED = "RADIUS_TLS_STATUS_SUCCEED";
} // namespace radius
} // namespace isc
"RADIUS_SESSION_HISTORY_STORED", "Storing to the session history file succeeded: stored %1 records",
"RADIUS_SESSION_HISTORY_STORE_FAILED", "Writing to the session history file %1 failed: %2 (stored %3 over %4 records)",
"RADIUS_THREAD_POOL_STARTED", "RADIUS thread pool started with %1 threads.",
+ "RADIUS_TLS_STATUS", "send Status-Server with %1",
+ "RADIUS_TLS_STATUS_ERROR", "received error response to Status-Server: %1 (%2) with %3",
+ "RADIUS_TLS_STATUS_FAILED", "Status-Server failed: return code %1 (%2)",
+ "RADIUS_TLS_STATUS_SUCCEED", "received valid response to Status-Server",
NULL
};
extern const isc::log::MessageID RADIUS_SESSION_HISTORY_STORED;
extern const isc::log::MessageID RADIUS_SESSION_HISTORY_STORE_FAILED;
extern const isc::log::MessageID RADIUS_THREAD_POOL_STARTED;
+extern const isc::log::MessageID RADIUS_TLS_STATUS;
+extern const isc::log::MessageID RADIUS_TLS_STATUS_ERROR;
+extern const isc::log::MessageID RADIUS_TLS_STATUS_FAILED;
+extern const isc::log::MessageID RADIUS_TLS_STATUS_SUCCEED;
} // namespace radius
} // namespace isc
% RADIUS_THREAD_POOL_STARTED RADIUS thread pool started with %1 threads.
This informational message is issued when the thread pool is started.
The number of threads is displayed.
+
+% RADIUS_TLS_STATUS send Status-Server with %1
+Logged at debug log level 40.
+This debug message is issued when starting to send a Status-Server message
+to common TLS servers. The message attributes are logged.
+
+% RADIUS_TLS_STATUS_ERROR received error response to Status-Server: %1 (%2) with %3
+This error message indicates that a valid response to Status-Server message
+was received from common TLS servers but with an unexpected code or an
+Error-Cause attribute. The response details are logged.
+
+% RADIUS_TLS_STATUS_FAILED Status-Server failed: return code %1 (%2)
+Logged at debug log level 40.
+This debug message is issued when no valid response to Status-Server message
+was received from common TLS servers.
+
+% RADIUS_TLS_STATUS_SUCCEED received valid response to Status-Server
+Logged at debug log level 40.
+This debug message indicates that a valid response to Status-Server message
+was received from common TLS servers.
unsigned maxretries = RadiusImpl::instance().retries_;
Servers servers;
if (code == PW_ACCESS_REQUEST) {
- servers = RadiusImpl::instance().auth_->servers_;
+ servers = RadiusImpl::instance().getAccessServers();
} else {
- servers = RadiusImpl::instance().acct_->servers_;
+ servers = RadiusImpl::instance().getAccountingServers();
}
if (sync) {
exchange_.reset(new Exchange(request, maxretries, servers));
namespace radius {
/// @brief Type of callback for authentication termination.
+///
/// First argument is the result code, second is the attribute collection
/// from server response.
typedef std::function<void(int, AttributesPtr)> CallbackAuth;
/// @brief Type of callback for accounting termination.
+///
/// The argument is the result code.
typedef std::function<void(int)> CallbackAcct;
uint32_t getNASPort(uint32_t subnet_id);
/// @brief Base class for communication with servers.
+///
/// It represents the common part of authentication/authorization and
/// accounting communication.
class RadiusRequest {
virtual ~RadiusRequest() = default;
/// @brief Start communication.
+ ///
/// In synchronous mode it returns when exchange(s) is(are) finished,
/// in asynchronous mode it initiates the (first) exchange.
virtual void start() {
}
/// @brief Get the error code.
+ ///
+ /// @return The error code.
int getRC() const {
return (exchange_->getRC());
}
#include <radius_accounting.h>
#include <radius_status.h>
#include <radius_log.h>
+#include <radius_tls.h>
#include <sstream>
using namespace isc::asiolink;
RadiusImpl::instance().unregisterExchange(exchange);
}
+RadiusTlsStatus::RadiusTlsStatus(const AttributesPtr& send_attrs,
+ const CallbackStatus& handler)
+ : RadiusStatus() {
+ AttributesPtr attrs;
+ if (send_attrs) {
+ attrs.reset(new Attributes(*send_attrs));
+ } else {
+ attrs.reset(new Attributes());
+ }
+ MessagePtr request(new Message(PW_STATUS_SERVER, 0, vector<uint8_t>(),
+ "to-be-set", attrs));
+ unsigned maxretries = RadiusImpl::instance().retries_;
+ Servers servers = RadiusImpl::instance().common_->servers_;
+ exchange_.reset(new Exchange(RadiusImpl::instance().getIOContext(),
+ request, maxretries, servers,
+ std::bind(&RadiusTlsStatus::invokeCallback,
+ handler, ph::_1)));
+}
+
+void
+RadiusTlsStatus::start() {
+ AttributesPtr send_attrs;
+ MessagePtr request = exchange_->getRequest();
+ if (request) {
+ send_attrs = request->getAttributes();
+ }
+ LOG_DEBUG(radius_logger, RADIUS_DBG_TRACE, RADIUS_TLS_STATUS)
+ .arg(send_attrs ? send_attrs->toText() : "no attributes");
+
+ RadiusStatus::start();
+}
+
+void
+RadiusTlsStatus::invokeCallback(const CallbackAcct& callback,
+ const ExchangePtr exchange) {
+ // Should not happen...
+ if (!exchange) {
+ return;
+ }
+ int result = exchange->getRC();
+ if (result == OK_RC) {
+ LOG_DEBUG(radius_logger, RADIUS_DBG_TRACE, RADIUS_TLS_STATUS_SUCCEED);
+ RadiusImpl::instance().setAccessIdleTimer();
+
+ MessagePtr response = exchange->getResponse();
+ AttributesPtr resp_attrs;
+ uint8_t code = 0;
+ if (response) {
+ resp_attrs = response->getAttributes();
+ code = response->getCode();
+ }
+ if (((code != 0) && (code != PW_ACCESS_ACCEPT)) ||
+ (resp_attrs && (resp_attrs->count(PW_ERROR_CAUSE) > 0))) {
+ LOG_ERROR(radius_logger, RADIUS_TLS_STATUS_ERROR)
+ .arg(msgCodeToText(code))
+ .arg(static_cast<unsigned>(code))
+ .arg(resp_attrs ? resp_attrs->toText() : "no attributes");
+ }
+ } else {
+ LOG_DEBUG(radius_logger, RADIUS_DBG_TRACE, RADIUS_TLS_STATUS_FAILED)
+ .arg(result)
+ .arg(exchangeRCtoText(result));
+ }
+
+ if (callback) {
+ try {
+ callback(result);
+ } catch (...) {
+ }
+ }
+}
+
} // end of namespace radius
} // end of namespace isc
namespace radius {
/// @brief Type of callback for status termination.
+///
/// The argument is the result code.
typedef std::function<void(int)> CallbackStatus;
virtual ~RadiusStatus() = default;
/// @brief Start communication.
+ ///
/// Initiates the (first) exchange.
virtual void start() {
exchange_->start();
};
/// @brief class for communication with access servers.
+///
/// Only the asynchronous variant is defined.
class RadiusAuthStatus : public RadiusStatus {
public:
typedef boost::shared_ptr<RadiusAuthStatus> RadiusAuthStatusPtr;
/// @brief class for communication with accounting servers.
+///
/// Only the asynchronous variant is defined.
class RadiusAcctStatus : public RadiusStatus {
public:
/// @brief Pointer to accounting status.
typedef boost::shared_ptr<RadiusAcctStatus> RadiusAcctStatusPtr;
+/// @brief class for communication with common TLS servers.
+///
+/// Only the asynchronous variant is defined.
+class RadiusTlsStatus : public RadiusStatus {
+public:
+
+ /// @brief Constructor.
+ ///
+ /// @param send_attrs Attributes to send.
+ /// @param handler Termination handler.
+ RadiusTlsStatus(const AttributesPtr& send_attrs,
+ const CallbackStatus& handler);
+
+ /// @brief Destructor.
+ virtual ~RadiusTlsStatus() = default;
+
+ /// @brief Start communication.
+ virtual void start() override;
+
+ /// @brief Invoke access status callback
+ ///
+ /// @param callback Termination callback
+ /// @param exchange the exchange.
+ static void invokeCallback(const CallbackStatus& callback,
+ const ExchangePtr exchange);
+};
+
+/// @brief Pointer to access status.
+typedef boost::shared_ptr<RadiusTlsStatus> RadiusTlsStatusPtr;
+
} // end of namespace radius
} // end of namespace isc
#endif // RADIUS_STATUS_H
void
RadiusTls::IdleTimerCallback() {
AttributesPtr send_attrs;
- RadiusAuthStatusPtr handler(new RadiusAuthStatus(send_attrs, 0));
- RadiusImpl::instance().registerExchange(handler->getExchange());
+ RadiusTlsStatusPtr handler(new RadiusTlsStatus(send_attrs, 0));
handler->start();
}