Kea  1.9.9-git
dhcp6/client_handler.cc
Go to the documentation of this file.
1 // Copyright (C) 2020 Internet Systems Consortium, Inc. ("ISC")
2 //
3 // This Source Code Form is subject to the terms of the Mozilla Public
4 // License, v. 2.0. If a copy of the MPL was not distributed with this
5 // file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 
7 #include <config.h>
8 
9 #include <dhcp6/client_handler.h>
10 #include <dhcp6/dhcp6_log.h>
11 #include <exceptions/exceptions.h>
12 #include <stats/stats_mgr.h>
14 
15 using namespace std;
16 using namespace isc::util;
17 
18 namespace isc {
19 namespace dhcp {
20 
21 ClientHandler::Client::Client(Pkt6Ptr query, DuidPtr client_id)
22  : query_(query), thread_(this_thread::get_id()) {
23  // Sanity checks.
24  if (!query) {
25  isc_throw(InvalidParameter, "null query in ClientHandler");
26  }
27  if (!client_id) {
28  isc_throw(InvalidParameter, "null client-id in ClientHandler");
29  }
30 
31  duid_ = client_id->getDuid();
32 }
33 
34 mutex ClientHandler::mutex_;
35 
36 ClientHandler::ClientContainer ClientHandler::clients_;
37 
38 ClientHandler::ClientPtr
39 ClientHandler::lookup(const DuidPtr& duid) {
40  // Sanity check.
41  if (!duid) {
42  isc_throw(InvalidParameter, "null duid in ClientHandler::lookup");
43  }
44 
45  auto it = clients_.find(duid->getDuid());
46  if (it == clients_.end()) {
47  return (ClientPtr());
48  }
49  return (*it);
50 }
51 
52 void
53 ClientHandler::add(const ClientPtr& client) {
54  // Sanity check.
55  if (!client) {
56  isc_throw(InvalidParameter, "null client in ClientHandler::add");
57  }
58 
59  // Assume insert will never fail so not checking its result.
60  clients_.insert(client);
61 }
62 
63 void
64 ClientHandler::del(const DuidPtr& duid) {
65  // Sanity check.
66  if (!duid) {
67  isc_throw(InvalidParameter, "null duid in ClientHandler::del");
68  }
69 
70  // Assume erase will never fail so not checking its result.
71  clients_.erase(duid->getDuid());
72 }
73 
74 ClientHandler::ClientHandler() : client_(), locked_() {
75 }
76 
78  if (locked_) {
79  lock_guard<mutex> lk(mutex_);
80  unLock();
81  }
82 }
83 
84 bool
86  // Sanity checks.
87  if (!query) {
88  isc_throw(InvalidParameter, "null query in ClientHandler::tryLock");
89  }
90  if (locked_) {
91  isc_throw(Unexpected, "already handling in ClientHandler::tryLock");
92  }
93 
94  const DuidPtr& duid = query->getClientId();
95  if (!duid) {
96  // Can't do something useful: cross fingers.
97  return (true);
98  }
99  if (duid->getDuid().empty()) {
100  // A lot of code assumes this will never happen...
101  isc_throw(Unexpected, "empty DUID in ClientHandler::tryLock");
102  }
103 
104  ClientPtr holder;
105  Pkt6Ptr next_query;
106  client_.reset(new Client(query, duid));
107 
108  {
109  // Try to acquire the lock and return the holder when it failed.
110  lock_guard<mutex> lk(mutex_);
111  holder = lookup(duid);
112  if (!holder) {
113  locked_ = duid;
114  lock();
115  return (true);
116  }
117  // This query can be a duplicate so put the continuation.
118  if (cont) {
119  next_query = holder->next_query_;
120  holder->next_query_ = query;
121  holder->cont_ = cont;
122  }
123  }
124 
125  if (cont) {
126  if (next_query) {
127  // Logging a warning as it is supposed to be a rare event
128  // with well behaving clients...
130  .arg(next_query->toText())
131  .arg(this_thread::get_id())
132  .arg(holder->query_->toText())
133  .arg(holder->thread_);
134  stats::StatsMgr::instance().addValue("pkt6-receive-drop",
135  static_cast<int64_t>(1));
136  }
137  } else {
138  // Logging a warning as it is supposed to be a rare event
139  // with well behaving clients...
141  .arg(query->toText())
142  .arg(this_thread::get_id())
143  .arg(holder->query_->toText())
144  .arg(holder->thread_);
145  stats::StatsMgr::instance().addValue("pkt6-receive-drop",
146  static_cast<int64_t>(1));
147  }
148  return (false);
149 }
150 
151 void
152 ClientHandler::lock() {
153  // Sanity check.
154  if (!locked_) {
155  isc_throw(Unexpected, "nothing to lock in ClientHandler::lock");
156  }
157 
158  add(client_);
159 }
160 
161 void
162 ClientHandler::unLock() {
163  // Sanity check.
164  if (!locked_) {
165  isc_throw(Unexpected, "nothing to unlock in ClientHandler::unLock");
166  }
167 
168  del(locked_);
169  locked_.reset();
170 
171  if (!client_ || !client_->cont_) {
172  return;
173  }
174 
175  // Try to process next query. As the caller holds the mutex of
176  // the handler class the continuation will be resumed after.
177  MultiThreadingMgr& mt_mgr = MultiThreadingMgr::instance();
178  if (mt_mgr.getMode()) {
179  if (!mt_mgr.getThreadPool().addFront(client_->cont_)) {
181  }
182  }
183 }
184 
185 } // namespace dhcp
186 } // namespace isc
#define LOG_WARN(LOGGER, MESSAGE)
Macro to conveniently test warn output and log it.
Definition: macros.h:26
boost::shared_ptr< DUID > DuidPtr
Definition: duid.h:20
const isc::log::MessageID DHCP6_PACKET_DROP_DUPLICATE
A generic exception that is thrown if a parameter given to a method or function is considered invalid...
const int DBG_DHCP6_BASIC
Debug level used to trace basic operations within the code.
Definition: dhcp6_log.h:30
STL namespace.
Multi Threading Manager.
const isc::log::MessageID DHCP6_PACKET_QUEUE_FULL
static StatsMgr & instance()
Statistics Manager accessor method.
bool addFront(const WorkItemPtr &item)
add a work item to the thread pool at front
Definition: thread_pool.h:105
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
boost::shared_ptr< Pkt6 > Pkt6Ptr
A pointer to Pkt6 packet.
Definition: pkt6.h:28
Definition: edns.h:19
ClientHandler()
Public interface.
A generic exception that is thrown when an unexpected error condition occurs.
bool getMode() const
Get the multi-threading mode.
virtual ~ClientHandler()
Destructor.
void addValue(const std::string &name, const int64_t value)
Records incremental integer observation.
Defines the logger used by the top-level component of kea-dhcp-ddns.
ThreadPool< std::function< void()> > & getThreadPool()
Get the dhcp thread pool.
bool tryLock(Pkt4Ptr query, ContinuationPtr cont=ContinuationPtr())
Tries to acquires a client.
#define LOG_DEBUG(LOGGER, LEVEL, MESSAGE)
Macro to conveniently test debug output and log it.
Definition: macros.h:14
isc::log::Logger bad_packet6_logger(DHCP6_BAD_PACKET_LOGGER_NAME)
Logger for rejected packets.
Definition: dhcp6_log.h:93
boost::shared_ptr< Continuation > ContinuationPtr
Define the type of shared pointers to continuations.
isc::log::Logger dhcp6_logger(DHCP6_APP_LOGGER_NAME)
Base logger for DHCPv6 server.
Definition: dhcp6_log.h:87