Kea 2.5.5
d2_queue_mgr.cc
Go to the documentation of this file.
1// Copyright (C) 2013-2021 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#include <d2/d2_queue_mgr.h>
9#include <d2srv/d2_log.h>
10#include <dhcp_ddns/ncr_udp.h>
11
12namespace isc {
13namespace d2 {
14
15// Makes constant visible to Google test macros.
17
18D2QueueMgr::D2QueueMgr(asiolink::IOServicePtr& io_service, const size_t max_queue_size)
19 : io_service_(io_service), max_queue_size_(max_queue_size),
20 mgr_state_(NOT_INITTED), target_stop_state_(NOT_INITTED) {
21 if (!io_service_) {
22 isc_throw(D2QueueMgrError, "IOServicePtr cannot be null");
23 }
24
25 // Use setter to do validation.
26 setMaxQueueSize(max_queue_size);
27}
28
30}
31
32void
35 try {
36 // Note that error conditions must be handled here without throwing
37 // exceptions. Remember this is the application level "link" in the
38 // callback chain. Throwing an exception here will "break" the
39 // io_service "run" we are operating under. With that in mind,
40 // if we hit a problem, we will stop the listener transition to
41 // the appropriate stopped state. Upper layer(s) must monitor our
42 // state as well as our queue size.
43 switch (result) {
45 // Receive was successful, attempt to queue the request.
46 if (getQueueSize() < getMaxQueueSize()) {
47 // There's room on the queue, add to the end
48 enqueue(ncr);
49
50 // Log that we got the request
54 .arg(ncr->getRequestId());
55 return;
56 }
57
58 // Queue is full, stop the listener.
59 // Note that we can move straight to a STOPPED state as there
60 // is no receive in progress.
62 .arg(max_queue_size_);
64 break;
65
67 if (mgr_state_ == STOPPING) {
68 // This is confirmation that the listener has stopped and its
69 // callback will not be called again, unless its restarted.
70 updateStopState();
71 } else {
72 // We should not get a receive complete status of stopped
73 // unless we canceled the read as part of stopping. Therefore
74 // this is unexpected so we will treat it as a receive error.
75 // This is most likely an unforeseen programmatic issue.
77 .arg(mgr_state_);
79 }
80
81 break;
82
83 default:
84 // Receive failed, stop the listener.
85 // Note that we can move straight to a STOPPED state as there
86 // is no receive in progress.
89 break;
90 }
91 } catch (const std::exception& ex) {
92 // On the outside chance a throw occurs, let's log it and swallow it.
94 .arg(ex.what());
95 }
96}
97
98void
100 const uint32_t port,
102 const bool reuse_address) {
103
104 if (listener_) {
106 "D2QueueMgr listener is already initialized");
107 }
108
109 // Instantiate a UDP listener and set state to INITTED.
110 // Note UDP listener constructor does not throw.
111 listener_.reset(new dhcp_ddns::
112 NameChangeUDPListener(ip_address, port, format, *this,
113 reuse_address));
114 mgr_state_ = INITTED;
115}
116
117void
119 // We can't listen if we haven't initialized the listener yet.
120 if (!listener_) {
121 isc_throw(D2QueueMgrError, "D2QueueMgr "
122 "listener is not initialized, cannot start listening");
123 }
124
125 // If we are already listening, we do not want to "reopen" the listener
126 // and really we shouldn't be trying.
127 if (mgr_state_ == RUNNING) {
128 isc_throw(D2QueueMgrError, "D2QueueMgr "
129 "cannot call startListening from the RUNNING state");
130 }
131
132 // Instruct the listener to start listening and set state accordingly.
133 try {
134 listener_->startListening(*io_service_);
135 mgr_state_ = RUNNING;
136 } catch (const isc::Exception& ex) {
137 isc_throw(D2QueueMgrError, "D2QueueMgr listener start failed: "
138 << ex.what());
139 }
140
143}
144
145void
146D2QueueMgr::stopListening(const State target_stop_state) {
147 if (listener_) {
148 // Enforce only valid "stop" states.
149 // This is purely a programmatic error and should never happen.
150 if (target_stop_state != STOPPED &&
151 target_stop_state != STOPPED_QUEUE_FULL &&
152 target_stop_state != STOPPED_RECV_ERROR) {
154 "D2QueueMgr invalid value for stop state: "
155 << target_stop_state);
156 }
157
158 // Remember the state we want to achieve.
159 target_stop_state_ = target_stop_state;
160
161 // Instruct the listener to stop. If the listener reports that it
162 // has IO pending, then we transition to STOPPING to wait for the
163 // cancellation event. Otherwise, we can move directly to the targeted
164 // state.
165 listener_->stopListening();
166 if (listener_->isIoPending()) {
167 mgr_state_ = STOPPING;
168 } else {
169 updateStopState();
170 }
171 }
172}
173
174void
175D2QueueMgr::updateStopState() {
176 mgr_state_ = target_stop_state_;
179}
180
181
182void
184 // Force our managing layer(s) to stop us properly first.
185 if (mgr_state_ == RUNNING) {
187 "D2QueueMgr cannot delete listener while state is RUNNING");
188 }
189
190 listener_.reset();
191 mgr_state_ = NOT_INITTED;
192}
193
196 if (getQueueSize() == 0) {
198 "D2QueueMgr peek attempted on an empty queue");
199 }
200
201 return (ncr_queue_.front());
202}
203
205D2QueueMgr::peekAt(const size_t index) const {
206 if (index >= getQueueSize()) {
208 "D2QueueMgr peek beyond end of queue attempted"
209 << " index: " << index << " queue size: " << getQueueSize());
210 }
211
212 return (ncr_queue_.at(index));
213}
214
215void
216D2QueueMgr::dequeueAt(const size_t index) {
217 if (index >= getQueueSize()) {
219 "D2QueueMgr dequeue beyond end of queue attempted"
220 << " index: " << index << " queue size: " << getQueueSize());
221 }
222
223 RequestQueue::iterator pos = ncr_queue_.begin() + index;
224 ncr_queue_.erase(pos);
225}
226
227
228void
230 if (getQueueSize() == 0) {
232 "D2QueueMgr dequeue attempted on an empty queue");
233 }
234
235 ncr_queue_.pop_front();
236}
237
238void
240 ncr_queue_.push_back(ncr);
241}
242
243void
245 ncr_queue_.clear();
246}
247
248void
249D2QueueMgr::setMaxQueueSize(const size_t new_queue_max) {
250 if (new_queue_max < 1) {
252 "D2QueueMgr maximum queue size must be greater than zero");
253 }
254
255 if (new_queue_max < getQueueSize()) {
256 isc_throw(D2QueueMgrError, "D2QueueMgr maximum queue size value cannot"
257 " be less than the current queue size :" << getQueueSize());
258 }
259
260 max_queue_size_ = new_queue_max;
261}
262
263} // namespace isc::d2
264} // namespace isc
This is a base class for exceptions thrown from the DNS library module.
virtual const char * what() const
Returns a C-style character string of the cause of the exception.
Thrown if the queue manager encounters a general error.
Definition: d2_queue_mgr.h:28
Thrown if a queue index is beyond the end of the queue.
Definition: d2_queue_mgr.h:60
Thrown if the request queue empty and a read is attempted.
Definition: d2_queue_mgr.h:53
const dhcp_ddns::NameChangeRequestPtr & peek() const
Returns the entry at the front of the queue.
D2QueueMgr(asiolink::IOServicePtr &io_service, const size_t max_queue_size=MAX_QUEUE_DEFAULT)
Constructor.
Definition: d2_queue_mgr.cc:18
virtual ~D2QueueMgr()
Destructor.
Definition: d2_queue_mgr.cc:29
size_t getMaxQueueSize() const
Returns the maximum number of entries allowed in the queue.
Definition: d2_queue_mgr.h:253
static const size_t MAX_QUEUE_DEFAULT
Maximum number of entries allowed in the request queue.
Definition: d2_queue_mgr.h:137
void dequeue()
Removes the entry at the front of the queue.
State
Defines the list of possible states for D2QueueMgr.
Definition: d2_queue_mgr.h:140
const dhcp_ddns::NameChangeRequestPtr & peekAt(const size_t index) const
Returns the entry at a given position in the queue.
void removeListener()
Deletes the current listener.
void enqueue(dhcp_ddns::NameChangeRequestPtr &ncr)
Adds a request to the end of the queue.
void startListening()
Starts actively listening for requests.
void setMaxQueueSize(const size_t max_queue_size)
Sets the maximum number of entries allowed in the queue.
size_t getQueueSize() const
Returns the number of entries in the queue.
Definition: d2_queue_mgr.h:248
virtual void operator()(const dhcp_ddns::NameChangeListener::Result result, dhcp_ddns::NameChangeRequestPtr &ncr)
Function operator implementing the NCR receive callback.
Definition: d2_queue_mgr.cc:33
void clearQueue()
Removes all entries from the queue.
void initUDPListener(const isc::asiolink::IOAddress &ip_address, const uint32_t port, const dhcp_ddns::NameChangeFormat format, const bool reuse_address=false)
Initializes the listener as a UDP listener.
Definition: d2_queue_mgr.cc:99
void dequeueAt(const size_t index)
Removes the entry at a given position in the queue.
void stopListening(const State target_stop_state=STOPPED)
Stops listening for requests.
Result
Defines the outcome of an asynchronous NCR receive.
Definition: ncr_io.h:171
This file defines the class D2QueueMgr.
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
#define LOG_ERROR(LOGGER, MESSAGE)
Macro to conveniently test error output and log it.
Definition: macros.h:32
#define LOG_DEBUG(LOGGER, LEVEL, MESSAGE)
Macro to conveniently test debug output and log it.
Definition: macros.h:14
const isc::log::MessageID DHCP_DDNS_QUEUE_MGR_RECV_ERROR
Definition: d2_messages.h:60
const isc::log::MessageID DHCP_DDNS_QUEUE_MGR_QUEUE_RECEIVE
Definition: d2_messages.h:57
const isc::log::MessageID DHCP_DDNS_QUEUE_MGR_UNEXPECTED_HANDLER_ERROR
Definition: d2_messages.h:68
const isc::log::MessageID DHCP_DDNS_QUEUE_MGR_UNEXPECTED_STOP
Definition: d2_messages.h:69
const isc::log::MessageID DHCP_DDNS_QUEUE_MGR_STARTED
Definition: d2_messages.h:63
isc::log::Logger dhcp_to_d2_logger("dhcp-to-d2")
Definition: d2_log.h:19
isc::log::Logger d2_logger("dhcpddns")
Defines the logger used within D2.
Definition: d2_log.h:18
const isc::log::MessageID DHCP_DDNS_QUEUE_MGR_QUEUE_FULL
Definition: d2_messages.h:56
const isc::log::MessageID DHCP_DDNS_QUEUE_MGR_STOPPED
Definition: d2_messages.h:65
NameChangeFormat
Defines the list of data wire formats supported.
Definition: ncr_msg.h:60
boost::shared_ptr< NameChangeRequest > NameChangeRequestPtr
Defines a pointer to a NameChangeRequest.
Definition: ncr_msg.h:242
const int DBGLVL_TRACE_BASIC
Trace basic operations.
Definition: log_dbglevels.h:69
const int DBGLVL_START_SHUT
This is given a value of 0 as that is the level selected if debugging is enabled without giving a lev...
Definition: log_dbglevels.h:50
const int DBGLVL_TRACE_DETAIL_DATA
Trace data associated with detailed operations.
Definition: log_dbglevels.h:78
std::string format(const std::string &format, const std::vector< std::string > &args)
Apply Formatting.
Definition: strutil.cc:157
Defines the logger used by the top-level component of kea-lfc.
This file provides UDP socket based implementation for sending and receiving NameChangeRequests.