Kea 2.7.8
http_command_mgr.cc
Go to the documentation of this file.
1// Copyright (C) 2024-2025 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
10#include <config/command_mgr.h>
11#include <config/config_log.h>
15#include <config/timeouts.h>
16#include <sstream>
17#include <vector>
18
19using namespace isc;
20using namespace isc::asiolink;
21using namespace isc::config;
22using namespace isc::data;
23using namespace isc::dhcp;
24using namespace isc::http;
25using namespace std;
26
27namespace isc {
28namespace config {
29
88
89void
91 if (!config) {
92 isc_throw(BadSocketInfo, "Missing config parameters, can't create socket.");
93 }
94
95 if (config->getType() != Element::list) {
96 isc_throw(DhcpConfigError, "expected list type ("
97 << config->getPosition() << ")");
98 }
99
100 for (auto const& socket : config->listValue()) {
101 openCommandSocket(socket);
102 }
103
104 auto copy = sockets_;
105 for (auto const& data : copy) {
106 if (data.second->usable_) {
107 // If the connection can be used (just created) or reused, keep it
108 // in the list and clear the flag. It will be marked again on next
109 // configuration event if needed.
110 data.second->usable_ = false;
111 } else {
112 // If the connection can not be reused, stop it and remove it from the list.
113 closeCommandSocket(data.second, true);
114 }
115 }
116}
117
118void
120 if (!config) {
121 isc_throw(BadSocketInfo, "Missing config parameters, can't create socket.");
122 }
123
124 HttpCommandConfigPtr cmd_config(new HttpCommandConfig(config));
125
126 IOAddress server_address = cmd_config->getSocketAddress();
127 uint16_t server_port = cmd_config->getSocketPort();
128
129 // Search for the specific connection and reuse the existing one if found.
130 auto it = sockets_.find(std::make_pair(server_address, server_port));
131 if (it != sockets_.end()) {
132 auto listener = it->second->listener_;
133 if (listener) {
134 // Reconfig keeping the same address and port.
135 if (listener->getTlsContext()) {
136 if (cmd_config->getTrustAnchor().empty()) {
137 // Can not switch from HTTPS to HTTP
139 .arg(server_address.toText())
140 .arg(server_port);
142 "Can not switch from HTTPS to HTTP sockets using the same address and port.");
143 } else {
144 // Apply TLS settings each time.
145 TlsContextPtr tls_context;
146 TlsContext::configure(tls_context,
147 TlsRole::SERVER,
148 cmd_config->getTrustAnchor(),
149 cmd_config->getCertFile(),
150 cmd_config->getKeyFile(),
151 cmd_config->getCertRequired());
152 // Overwrite the authentication setup, the http headers and the emulation flag
153 // in the response creator config.
154 it->second->config_->setAuthConfig(cmd_config->getAuthConfig());
155 it->second->config_->setHttpHeaders(cmd_config->getHttpHeaders());
156 it->second->config_->setEmulateAgentResponse(cmd_config->getEmulateAgentResponse());
157 listener->setTlsContext(tls_context);
159 .arg(server_address.toText())
160 .arg(server_port);
161 }
162 } else {
163 if (!cmd_config->getTrustAnchor().empty()) {
164 // Can not switch from HTTP to HTTPS
166 .arg(server_address.toText())
167 .arg(server_port);
169 "Can not switch from HTTP to HTTPS sockets using the same address and port.");
170 } else {
171 // Overwrite the authentication setup, the http headers and the emulation flag
172 // in the response creator config.
173 it->second->config_->setAuthConfig(cmd_config->getAuthConfig());
174 it->second->config_->setHttpHeaders(cmd_config->getHttpHeaders());
175 it->second->config_->setEmulateAgentResponse(cmd_config->getEmulateAgentResponse());
177 .arg(server_address.toText())
178 .arg(server_port);
179 }
180 }
181 }
182 // If the connection can be reused, mark it as usable.
183 it->second->usable_ = true;
184 return;
185 }
186
187 // Connection not found so it needs to be created.
188 // When TLS is enabled configure it.
189 bool use_https = false;
190 TlsContextPtr tls_context;
191 if (!cmd_config->getCertFile().empty()) {
192 TlsContext::configure(tls_context,
193 TlsRole::SERVER,
194 cmd_config->getTrustAnchor(),
195 cmd_config->getCertFile(),
196 cmd_config->getKeyFile(),
197 cmd_config->getCertRequired());
198 use_https = true;
199 }
200
201 // Create response creator factory first. It will be used to
202 // generate response creators. Each response creator will be used
203 // to generate answer to specific request.
205
206 // Create HTTP listener. It will open up a TCP socket and be
207 // prepared to accept incoming connection.
208 HttpListenerPtr http_listener
210 server_address,
211 server_port,
212 tls_context,
213 rfc,
216
217 // Pass the use external socket flag.
218 http_listener->addExternalSockets(use_external_);
219
220 // Instruct the HTTP listener to actually open socket, install
221 // callback and start listening.
222 http_listener->start();
223
224 HttpSocketInfoPtr socket_info(new HttpSocketInfo());
225 socket_info->config_ = cmd_config;
226 socket_info->listener_ = http_listener;
227
228 sockets_[std::make_pair(server_address, server_port)] = socket_info;
229
230 // Ok, seems we're good to go.
232 .arg(use_https ? "HTTPS" : "HTTP")
233 .arg(server_address.toText())
234 .arg(server_port);
235}
236
237void
239 bool use_https = false;
240 if (info) {
241 ostringstream ep;
242 use_https = !info->config_->getCertFile().empty();
243 ep << "bound to address " << info->config_->getSocketAddress()
244 << " port " << info->config_->getSocketPort();
245
247 .arg(use_https ? "HTTPS" : "HTTP")
248 .arg(ep.str());
249 info->listener_->stop();
250 if (remove) {
251 auto it = sockets_.find(std::make_pair(info->config_->getSocketAddress(), info->config_->getSocketPort()));
252 if (it != sockets_.end()) {
253 sockets_.erase(it);
254 }
255 }
256 // We have stopped listeners but there may be some pending handlers
257 // related to these listeners. Need to invoke these handlers.
258 try {
259 io_service_->pollOne();
260 } catch (...) {
261 }
262 } else {
263 closeCommandSockets(remove);
264 }
265}
266
267void
269 auto copy = sockets_;
270 for (auto const& data : copy) {
271 closeCommandSocket(data.second, remove);
272 }
273}
274
277 // Return the most recent listener or null.
278 if (info) {
279 auto it = sockets_.find(std::make_pair(info->config_->getSocketAddress(), info->config_->getSocketPort()));
280 if (it != sockets_.end()) {
281 return (it->second->listener_);
282 }
283 } else if (sockets_.size()) {
284 return (sockets_.begin()->second->listener_);
285 }
286 return (ConstHttpListenerPtr());
287}
288
291 static HttpCommandMgr http_cmd_mgr;
292 return (http_cmd_mgr);
293}
294
295HttpCommandMgr::HttpCommandMgr() : impl_(new HttpCommandMgrImpl()) {
296}
297
298void
300 impl_->io_service_ = io_service;
301}
302
303void
305 impl_->timeout_ = timeout;
306}
307
308void
310 impl_->idle_timeout_ = timeout;
311}
312
313void
315 impl_->use_external_ = use_external;
316}
317
318void
320 impl_->openCommandSocket(config);
321}
322
323void
325 impl_->openCommandSockets(config);
326}
327
328void
330 impl_->closeCommandSocket(info, remove);
331}
332
333void
335 impl_->closeCommandSockets();
336}
337
340 return (impl_->getHttpListener(info));
341}
342
343} // end of isc::config
344} // end of isc
A generic exception that is thrown if a parameter given to a method is considered invalid in that con...
An exception indicating that specified socket parameters are invalid.
Definition command_mgr.h:17
HTTP command config aka HTTP control socket info class.
Implementation of the HttpCommandMgr.
bool use_external_
Use external sockets flag.
std::map< std::pair< IOAddress, uint16_t >, HttpSocketInfoPtr > sockets_
The HTTP/HTTPS socket data (configuration, listener, etc.).
void openCommandSockets(const isc::data::ConstElementPtr config)
Open http control sockets using configuration.
long idle_timeout_
Idle connection timeout.
IOServicePtr io_service_
Pointer to the IO service.
void closeCommandSockets(bool remove=true)
Close control socket.
void closeCommandSocket(HttpSocketInfoPtr info, bool remove)
Close control socket.
void openCommandSocket(const isc::data::ConstElementPtr config)
Open http control socket using configuration.
long timeout_
Connection timeout.
ConstHttpListenerPtr getHttpListener(HttpSocketInfoPtr info) const
Returns a const pointer to the HTTP listener.
HTTP Commands Manager implementation for the Kea servers.
void openCommandSocket(const isc::data::ConstElementPtr config)
Open http control socket using configuration.
void setIdleConnectionTimeout(const long timeout)
Override default idle connection timeout.
isc::http::ConstHttpListenerPtr getHttpListener(HttpSocketInfoPtr info=HttpSocketInfoPtr()) const
Returns a const pointer to the HTTP listener.
void closeCommandSockets()
Close http control sockets.
void setConnectionTimeout(const long timeout)
Override default connection timeout.
void addExternalSockets(bool use_external=true)
Use external sockets flag.
static HttpCommandMgr & instance()
HttpCommandMgr is a singleton class.
void setIOService(const asiolink::IOServicePtr &io_service)
Sets IO service to be used by the http command manager.
void openCommandSockets(const isc::data::ConstElementPtr config)
Open http control sockets using configuration.
void closeCommandSocket(HttpSocketInfoPtr info=HttpSocketInfoPtr(), bool remove=true)
Close http control socket.
HTTP response creator factory for HTTP control socket.
To be removed. Please use ConfigError instead.
HTTP listener.
Definition listener.h:52
#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_INFO(LOGGER, MESSAGE)
Macro to conveniently test info output and log it.
Definition macros.h:20
const isc::log::MessageID HTTP_COMMAND_MGR_HTTPS_SERVICE_UPDATED
constexpr long TIMEOUT_AGENT_IDLE_CONNECTION_TIMEOUT
Timeout for the idle connection to be closed.
Definition timeouts.h:24
const isc::log::MessageID HTTP_COMMAND_MGR_SERVICE_STARTED
boost::shared_ptr< HttpSocketInfo > HttpSocketInfoPtr
Pointer to a HttpSocketInfo object.
const isc::log::MessageID HTTP_COMMAND_MGR_SERVICE_STOPPING
const isc::log::MessageID HTTP_COMMAND_MGR_HTTP_SERVICE_REUSE_FAILED
const isc::log::MessageID HTTP_COMMAND_MGR_HTTP_SERVICE_UPDATED
boost::shared_ptr< HttpCommandConfig > HttpCommandConfigPtr
Pointer to a HttpCommandConfig object.
isc::log::Logger command_logger("commands")
Command processing Logger.
Definition config_log.h:21
const isc::log::MessageID HTTP_COMMAND_MGR_HTTPS_SERVICE_REUSE_FAILED
constexpr long TIMEOUT_AGENT_RECEIVE_COMMAND
Timeout for the Control Agent to receive command over the RESTful interface.
Definition timeouts.h:21
ElementPtr copy(ConstElementPtr from, int level)
Copy the data up to a nesting level.
Definition data.cc:1420
boost::shared_ptr< const Element > ConstElementPtr
Definition data.h:29
@ info
Definition db_log.h:120
boost::shared_ptr< const HttpListener > ConstHttpListenerPtr
Pointer to the const HttpListener.
Definition listener.h:159
boost::shared_ptr< HttpListener > HttpListenerPtr
Pointer to the HttpListener.
Definition listener.h:156
boost::shared_ptr< HttpResponseCreatorFactory > HttpResponseCreatorFactoryPtr
Pointer to the HttpResponseCreatorFactory.
Defines the logger used by the top-level component of kea-lfc.
Structure used to store HTTP/HTTPS connection data.
Idle connection timeout.
Definition listener.h:67
HTTP request timeout value.
Definition listener.h:56