diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-13 12:15:43 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-13 12:15:43 +0000 |
commit | f5f56e1a1c4d9e9496fcb9d81131066a964ccd23 (patch) | |
tree | 49e44c6f87febed37efb953ab5485aa49f6481a7 /src/bin/dhcp6/client_handler.cc | |
parent | Initial commit. (diff) | |
download | isc-kea-f5f56e1a1c4d9e9496fcb9d81131066a964ccd23.tar.xz isc-kea-f5f56e1a1c4d9e9496fcb9d81131066a964ccd23.zip |
Adding upstream version 2.4.1.upstream/2.4.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/bin/dhcp6/client_handler.cc')
-rw-r--r-- | src/bin/dhcp6/client_handler.cc | 191 |
1 files changed, 191 insertions, 0 deletions
diff --git a/src/bin/dhcp6/client_handler.cc b/src/bin/dhcp6/client_handler.cc new file mode 100644 index 0000000..54fc9d8 --- /dev/null +++ b/src/bin/dhcp6/client_handler.cc @@ -0,0 +1,191 @@ +// Copyright (C) 2020-2023 Internet Systems Consortium, Inc. ("ISC") +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <config.h> + +#include <dhcp6/client_handler.h> +#include <dhcp6/dhcp6_log.h> +#include <exceptions/exceptions.h> +#include <stats/stats_mgr.h> +#include <util/multi_threading_mgr.h> + +using namespace std; +using namespace isc::util; +using namespace isc::log; + +namespace isc { +namespace dhcp { + +ClientHandler::Client::Client(Pkt6Ptr query, DuidPtr client_id) + : query_(query), thread_(this_thread::get_id()) { + // Sanity checks. + if (!query) { + isc_throw(InvalidParameter, "null query in ClientHandler"); + } + if (!client_id) { + isc_throw(InvalidParameter, "null client-id in ClientHandler"); + } + + duid_ = client_id->getDuid(); +} + +mutex ClientHandler::mutex_; + +ClientHandler::ClientContainer ClientHandler::clients_; + +ClientHandler::ClientPtr +ClientHandler::lookup(const DuidPtr& duid) { + // Sanity check. + if (!duid) { + isc_throw(InvalidParameter, "null duid in ClientHandler::lookup"); + } + + auto it = clients_.find(duid->getDuid()); + if (it == clients_.end()) { + return (ClientPtr()); + } + return (*it); +} + +void +ClientHandler::add(const ClientPtr& client) { + // Sanity check. + if (!client) { + isc_throw(InvalidParameter, "null client in ClientHandler::add"); + } + + // Assume insert will never fail so not checking its result. + clients_.insert(client); +} + +void +ClientHandler::del(const DuidPtr& duid) { + // Sanity check. + if (!duid) { + isc_throw(InvalidParameter, "null duid in ClientHandler::del"); + } + + // Assume erase will never fail so not checking its result. + clients_.erase(duid->getDuid()); +} + +ClientHandler::ClientHandler() : client_(), locked_() { +} + +ClientHandler::~ClientHandler() { + if (locked_) { + lock_guard<mutex> lk(mutex_); + unLock(); + } +} + +bool +ClientHandler::tryLock(Pkt6Ptr query, ContinuationPtr cont) { + // Sanity checks. + if (!query) { + isc_throw(InvalidParameter, "null query in ClientHandler::tryLock"); + } + if (locked_) { + isc_throw(Unexpected, "already handling in ClientHandler::tryLock"); + } + + const DuidPtr& duid = query->getClientId(); + if (!duid) { + // Can't do something useful: cross fingers. + return (true); + } + if (duid->getDuid().empty()) { + // A lot of code assumes this will never happen... + isc_throw(Unexpected, "empty DUID in ClientHandler::tryLock"); + } + + ClientPtr holder; + Pkt6Ptr next_query; + client_.reset(new Client(query, duid)); + + { + // Try to acquire the lock and return the holder when it failed. + lock_guard<mutex> lk(mutex_); + holder = lookup(duid); + if (!holder) { + locked_ = duid; + lock(); + return (true); + } + // This query can be a duplicate so put the continuation. + if (cont) { + next_query = holder->next_query_; + holder->next_query_ = query; + holder->cont_ = cont; + } + } + + if (cont) { + if (next_query) { + // Logging a warning as it is supposed to be a rare event + // with well behaving clients... + LOG_DEBUG(bad_packet6_logger, DBGLVL_PKT_HANDLING, DHCP6_PACKET_DROP_DUPLICATE) + .arg(next_query->makeLabel(next_query->getClientId(), nullptr)) + .arg(next_query->toText()) + .arg(this_thread::get_id()) + .arg(holder->query_->makeLabel(holder->query_->getClientId(), nullptr)) + .arg(holder->query_->toText()) + .arg(holder->thread_); + stats::StatsMgr::instance().addValue("pkt6-receive-drop", + static_cast<int64_t>(1)); + } + } else { + // Logging a warning as it is supposed to be a rare event + // with well behaving clients... + LOG_DEBUG(bad_packet6_logger, DBGLVL_PKT_HANDLING, DHCP6_PACKET_DROP_DUPLICATE) + .arg(query->makeLabel(query->getClientId(), nullptr)) + .arg(query->toText()) + .arg(this_thread::get_id()) + .arg(holder->query_->makeLabel(holder->query_->getClientId(), nullptr)) + .arg(holder->query_->toText()) + .arg(holder->thread_); + stats::StatsMgr::instance().addValue("pkt6-receive-drop", + static_cast<int64_t>(1)); + } + return (false); +} + +void +ClientHandler::lock() { + // Sanity check. + if (!locked_) { + isc_throw(Unexpected, "nothing to lock in ClientHandler::lock"); + } + + add(client_); +} + +void +ClientHandler::unLock() { + // Sanity check. + if (!locked_) { + isc_throw(Unexpected, "nothing to unlock in ClientHandler::unLock"); + } + + del(locked_); + locked_.reset(); + + if (!client_ || !client_->cont_) { + return; + } + + // Try to process next query. As the caller holds the mutex of + // the handler class the continuation will be resumed after. + MultiThreadingMgr& mt_mgr = MultiThreadingMgr::instance(); + if (mt_mgr.getMode()) { + if (!mt_mgr.getThreadPool().addFront(client_->cont_)) { + LOG_DEBUG(dhcp6_logger, DBG_DHCP6_BASIC, DHCP6_PACKET_QUEUE_FULL); + } + } +} + +} // namespace dhcp +} // namespace isc |