Skip to content

Commit af310b4

Browse files
committed
[#3478] Finished server side
1 parent 4a600e7 commit af310b4

File tree

5 files changed

+123
-13
lines changed

5 files changed

+123
-13
lines changed

src/bin/d2/d2_process.cc

+3
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,9 @@ D2Process::init() {
8282

8383
// Set the HTTP authentication default realm.
8484
HttpCommandConfig::DEFAULT_AUTHENTICATION_REALM = "kea-dhcp-ddns-server";
85+
86+
// D2 server does not use the interface manager.
87+
HttpCommandMgr::instance().addExternalSockets(false);
8588
};
8689

8790
void

src/lib/config/http_command_mgr.cc

+16-1
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,8 @@ class HttpCommandMgrImpl {
3232
HttpCommandMgrImpl()
3333
: io_service_(), timeout_(TIMEOUT_AGENT_RECEIVE_COMMAND),
3434
idle_timeout_(TIMEOUT_AGENT_IDLE_CONNECTION_TIMEOUT),
35-
current_config_(), http_listeners_(), active_(0) {
35+
current_config_(), http_listeners_(), active_(0),
36+
use_external_(true) {
3637
}
3738

3839
/// @brief Configure control socket from configuration.
@@ -66,6 +67,9 @@ class HttpCommandMgrImpl {
6667

6768
/// @brief Number of active listeners (0 or 1).
6869
size_t active_;
70+
71+
/// @brief Use external sockets flag.
72+
bool use_external_;
6973
};
7074

7175
void
@@ -116,10 +120,12 @@ HttpCommandMgrImpl::configure(HttpCommandConfigPtr config) {
116120
config->getCertRequired());
117121
use_https = true;
118122
}
123+
119124
// Create response creator factory first. It will be used to
120125
// generate response creators. Each response creator will be used
121126
// to generate answer to specific request.
122127
HttpResponseCreatorFactoryPtr rfc(new HttpCommandResponseCreatorFactory(config));
128+
123129
// Create HTTP listener. It will open up a TCP socket and be
124130
// prepared to accept incoming connection.
125131
HttpListenerPtr http_listener
@@ -130,6 +136,10 @@ HttpCommandMgrImpl::configure(HttpCommandConfigPtr config) {
130136
rfc,
131137
HttpListener::RequestTimeout(timeout_),
132138
HttpListener::IdleTimeout(idle_timeout_)));
139+
140+
// Pass the use external socket flag.
141+
http_listener->addExternalSockets(use_external_);
142+
133143
// Instruct the HTTP listener to actually open socket, install
134144
// callback and start listening.
135145
http_listener->start();
@@ -222,6 +232,11 @@ HttpCommandMgr::setIdleConnectionTimeout(const long timeout) {
222232
impl_->idle_timeout_ = timeout;
223233
}
224234

235+
void
236+
HttpCommandMgr::addExternalSockets(bool use_external) {
237+
impl_->use_external_ = use_external;
238+
}
239+
225240
void
226241
HttpCommandMgr::configure(HttpCommandConfigPtr config) {
227242
impl_->configure(config);

src/lib/config/http_command_mgr.h

+8
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,14 @@ class HttpCommandMgr : public HookedCommandMgr, public boost::noncopyable {
4848
/// @param timeout New connection timeout in milliseconds.
4949
void setIdleConnectionTimeout(const long timeout);
5050

51+
/// @brief Use external sockets flag.
52+
///
53+
/// Add sockets as external sockets of the interface manager
54+
/// so available I/O on them makes a waiting select to return.
55+
///
56+
/// @param use_external True (default) add external sockets.
57+
void addExternalSockets(bool use_external = true);
58+
5159
/// @brief Configure control socket from configuration.
5260
///
5361
/// @param config Configuration of the control socket.

src/lib/config/tests/http_command_mgr_unittests.cc

+84-1
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#include <cc/command_interpreter.h>
1313
#include <config/http_command_mgr.h>
1414
#include <config/command_mgr.h>
15+
#include <dhcp/iface_mgr.h>
1516
#include <http/response.h>
1617
#include <http/response_parser.h>
1718
#include <http/testutils/test_http_client.h>
@@ -80,6 +81,7 @@ class HttpCommandMgrTest : public ::testing::Test {
8081
}
8182
test_timer_.cancel();
8283
resetState();
84+
IfaceMgr::instance().deleteAllExternalSockets();
8385
}
8486

8587
/// @brief Resets state.
@@ -98,6 +100,7 @@ class HttpCommandMgrTest : public ::testing::Test {
98100
io_service_->stopAndPoll();
99101
HttpCommandMgr::instance().setIOService(IOServicePtr());
100102
}
103+
HttpCommandMgr::instance().addExternalSockets(true);
101104
}
102105

103106
/// @brief Constructs a complete HTTP POST given a request body.
@@ -203,7 +206,7 @@ class HttpCommandMgrTest : public ::testing::Test {
203206

204207
/// Verifies the configure and close of HttpCommandMgr.
205208
TEST_F(HttpCommandMgrTest, basic) {
206-
// Make sure we can confiugure one.
209+
// Make sure we can configure one.
207210
ASSERT_NO_THROW_LOG(HttpCommandMgr::instance().configure(http_config_));
208211
auto listener = HttpCommandMgr::instance().getHttpListener();
209212
ASSERT_TRUE(listener);
@@ -230,6 +233,30 @@ TEST_F(HttpCommandMgrTest, basic) {
230233
EXPECT_FALSE(HttpCommandMgr::instance().getHttpListener());
231234
}
232235

236+
/// Verifies the use external socket flag of HttpCommandMgr.
237+
TEST_F(HttpCommandMgrTest, useExternal) {
238+
// Default is to use external sockets.
239+
ASSERT_NO_THROW_LOG(HttpCommandMgr::instance().configure(http_config_));
240+
auto listener = HttpCommandMgr::instance().getHttpListener();
241+
ASSERT_TRUE(listener);
242+
int fd = listener->getNative();
243+
EXPECT_NE(-1, fd);
244+
EXPECT_TRUE(IfaceMgr::instance().isExternalSocket(fd));
245+
ASSERT_NO_THROW_LOG(HttpCommandMgr::instance().close());
246+
247+
// Change to no external sockets.
248+
HttpCommandMgr::instance().addExternalSockets(false);
249+
250+
// Retry: now the listener is not added as an external socket
251+
// to the interface manager.
252+
ASSERT_NO_THROW_LOG(HttpCommandMgr::instance().configure(http_config_));
253+
listener = HttpCommandMgr::instance().getHttpListener();
254+
ASSERT_TRUE(listener);
255+
fd = listener->getNative();
256+
EXPECT_NE(-1, fd);
257+
EXPECT_FALSE(IfaceMgr::instance().isExternalSocket(fd));
258+
}
259+
233260
/// Verifies the configure and close of HttpCommandMgr with TLS.
234261
TEST_F(HttpCommandMgrTest, basicTls) {
235262
string ca_dir(string(TEST_CA_DIR));
@@ -266,6 +293,37 @@ TEST_F(HttpCommandMgrTest, basicTls) {
266293
EXPECT_FALSE(HttpCommandMgr::instance().getHttpListener());
267294
}
268295

296+
/// Verifies the use external socket flag of HttpCommandMgr with TLS.
297+
TEST_F(HttpCommandMgrTest, useExternalTls) {
298+
string ca_dir(string(TEST_CA_DIR));
299+
// Setup TLS for the manager.
300+
http_config_->setSocketType("https");
301+
http_config_->setTrustAnchor(ca_dir + string("/kea-ca.crt"));
302+
http_config_->setCertFile(ca_dir + string("/kea-server.crt"));
303+
http_config_->setKeyFile(ca_dir + string("/kea-server.key"));
304+
305+
// Default is to use external sockets.
306+
ASSERT_NO_THROW_LOG(HttpCommandMgr::instance().configure(http_config_));
307+
auto listener = HttpCommandMgr::instance().getHttpListener();
308+
ASSERT_TRUE(listener);
309+
int fd = listener->getNative();
310+
EXPECT_NE(-1, fd);
311+
EXPECT_TRUE(IfaceMgr::instance().isExternalSocket(fd));
312+
ASSERT_NO_THROW_LOG(HttpCommandMgr::instance().close());
313+
314+
// Change to no external sockets.
315+
HttpCommandMgr::instance().addExternalSockets(false);
316+
317+
// Retry: now the listener is not added as an external socket
318+
// to the interface manager.
319+
ASSERT_NO_THROW_LOG(HttpCommandMgr::instance().configure(http_config_));
320+
listener = HttpCommandMgr::instance().getHttpListener();
321+
ASSERT_TRUE(listener);
322+
fd = listener->getNative();
323+
EXPECT_NE(-1, fd);
324+
EXPECT_FALSE(IfaceMgr::instance().isExternalSocket(fd));
325+
}
326+
269327
// This test verifies that an HTTP connection can be established and used to
270328
// transmit an HTTP request and receive the response.
271329
TEST_F(HttpCommandMgrTest, command) {
@@ -288,4 +346,29 @@ TEST_F(HttpCommandMgrTest, command) {
288346
EXPECT_EQ(hr->getBody(), "[ { \"arguments\": [ \"bar\" ], \"result\": 0 } ]");
289347
}
290348

349+
// This test verifies that an HTTP connection can be established and used to
350+
// transmit an HTTP request and receive the response (no external sockets).
351+
TEST_F(HttpCommandMgrTest, commandNoExternal) {
352+
// Change to no external sockets.
353+
HttpCommandMgr::instance().addExternalSockets(false);
354+
355+
// Configure.
356+
ASSERT_NO_THROW_LOG(HttpCommandMgr::instance().configure(http_config_));
357+
EXPECT_TRUE(HttpCommandMgr::instance().getHttpListener());
358+
359+
// Now let's send a "foo" command. This should create a client, connect
360+
// to our listener, post our request and retrieve our reply.
361+
ASSERT_NO_THROW(startRequest("{\"command\": \"foo\"}"));
362+
ASSERT_TRUE(client_);
363+
ASSERT_NO_THROW(runIOService());
364+
ASSERT_TRUE(client_);
365+
366+
// Parse the response into an HttpResponse.
367+
HttpResponsePtr hr;
368+
ASSERT_NO_THROW_LOG(hr = parseResponse(client_->getResponse()));
369+
370+
// We should have a response from our command handler.
371+
EXPECT_EQ(hr->getBody(), "[ { \"arguments\": [ \"bar\" ], \"result\": 0 } ]");
372+
}
373+
291374
} // end of anonymous namespace

src/lib/http/connection.cc

+12-11
Original file line numberDiff line numberDiff line change
@@ -278,17 +278,6 @@ HttpConnection::asyncAccept() {
278278
}
279279
tls_acceptor->asyncAccept(*tls_socket_, cb);
280280
}
281-
if (use_external_) {
282-
auto& iface_mgr = IfaceMgr::instance ();
283-
if (tcp_socket_) {
284-
iface_mgr.addExternalSocket(tcp_socket_->getNative(), 0);
285-
}
286-
if (tls_socket_) {
287-
iface_mgr.addExternalSocket(tls_socket_->getNative(), 0);
288-
}
289-
watch_socket_.reset(new WatchSocket());
290-
iface_mgr.addExternalSocket(watch_socket_->getSelectFd(), 0);
291-
}
292281
} catch (const std::exception& ex) {
293282
isc_throw(HttpConnectionError, "unable to start accepting TCP "
294283
"connections: " << ex.what());
@@ -442,6 +431,18 @@ HttpConnection::acceptorCallback(const boost::system::error_code& ec) {
442431
.arg(static_cast<unsigned>(request_timeout_/1000));
443432
}
444433

434+
if (use_external_) {
435+
auto& iface_mgr = IfaceMgr::instance ();
436+
if (tcp_socket_) {
437+
iface_mgr.addExternalSocket(tcp_socket_->getNative(), 0);
438+
}
439+
if (tls_socket_) {
440+
iface_mgr.addExternalSocket(tls_socket_->getNative(), 0);
441+
}
442+
watch_socket_.reset(new WatchSocket());
443+
iface_mgr.addExternalSocket(watch_socket_->getSelectFd(), 0);
444+
}
445+
445446
setupRequestTimer();
446447
doHandshake();
447448
}

0 commit comments

Comments
 (0)