Commit 16ccf1ae authored by Tomek Mrugalski's avatar Tomek Mrugalski 🛰
Browse files

[3880] CommandSocketFactory implemented.

parent 68886478
......@@ -25,9 +25,9 @@ CommandMgr::CommandMgr() {
boost::bind(&CommandMgr::listCommandsHandler, this, _1, _2));
}
void CommandMgr::configureCtrlSocket(const isc::data::ConstElementPtr& socket_info) {
int CommandMgr::openCtrlSocket(const isc::data::ConstElementPtr& socket_info) {
if (socket_info_) {
isc_throw(CommandSocketError, "There is already a control socket open");
isc_throw(SocketError, "There is already a control socket open");
}
socket_ = CommandSocketFactory::create(socket_info);
......@@ -38,10 +38,11 @@ void CommandMgr::configureCtrlSocket(const isc::data::ConstElementPtr& socket_in
}
void CommandMgr::closeCtrlSocket() {
CommandSocketFactory::close(socket_, socket_info_);
socket_ = 0;
socket_info_.reset();
if (socket_info_) {
CommandSocketFactory::close(socket_, socket_info_);
socket_ = 0;
socket_info_.reset();
}
}
CommandMgr&
......
......@@ -39,15 +39,6 @@ public:
isc::Exception(file, line, what) { };
};
/// @brief An exception indicating that operation on the command socket failed
class CommandSocketError : public Exception {
public:
CommandSocketError(const char* file, size_t line, const char* what) :
isc::Exception(file, line, what) { };
};
/// @brief Commands Manager, responsible for processing external commands
///
/// Commands Manager is a generic interface for handling external commands.
......@@ -96,7 +87,7 @@ public:
/// @return the only existing instance of the manager
static CommandMgr& instance();
/// @brief Configured control socket with paramters specified in socket_info
/// @brief Opens control socket with paramters specified in socket_info
///
/// Currently supported types are:
/// - unix (required parameters: socket-type: unix, socket-name:/unix/path)
......@@ -104,7 +95,8 @@ public:
/// @throw CommandSocketError if socket creation fails
///
/// @param socket_info describes control socket parameters
void configureCtrlSocket(const isc::data::ConstElementPtr& socket_info);
/// @return socket descriptor of the socket created
int openCtrlSocket(const isc::data::ConstElementPtr& socket_info);
/// @brief Shuts down any open control sockets
void closeCtrlSocket();
......
......@@ -13,18 +13,88 @@
// PERFORMANCE OF THIS SOFTWARE.
#include <config/command_socket_factory.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <string.h>
int createUnixSocket(const std::string& file_name) {
int fd = socket(AF_UNIX, SOCK_STREAM, 0);
if (fd == -1) {
isc_throw(isc::config::SocketError, "Failed to create AF_UNIX socket.");
}
/// @todo: Do we need any setsockopt here?
struct sockaddr_un addr;
memset(&addr, 0, sizeof(addr));
addr.sun_family = AF_UNIX;
strncpy(addr.sun_path, file_name.c_str(), sizeof(addr.sun_path)-1);
if (bind(fd, (struct sockaddr*)&addr, sizeof(addr))) {
isc_throw(isc::config::SocketError, "Failed to bind socket " << fd
<< " to " << file_name);
}
return (fd);
}
void closeUnixSocket(int socket_fd, const std::string& file_name) {
close(socket_fd);
unlink(file_name.c_str());
}
using namespace isc::data;
namespace isc {
namespace config {
int
CommandSocketFactory::create(const isc::data::ConstElementPtr& socket_info) {
if(!socket_info) {
isc_throw(BadSocketInfo, "Missing socket_info parameters, can't create socket.");
}
ConstElementPtr type = socket_info->get("socket-type");
if (!type) {
isc_throw(BadSocketInfo, "Mandatory 'socket-type' parameter missing");
}
ConstElementPtr name = socket_info->get("socket-name");
if (!name) {
isc_throw(BadSocketInfo, "Mandatory 'socket-name' parameter missing");
}
if (type->stringValue() == "unix") {
return (createUnixSocket(name->stringValue()));
} else {
isc_throw(BadSocketInfo, "Specified socket type ('" + type->stringValue()
+ "') is not supported.");
}
}
int CommandSocketFactory::close(int socket_fd,
const isc::data::ConstElementPtr& socket_info) {
void CommandSocketFactory::close(int socket_fd,
const isc::data::ConstElementPtr& socket_info) {
if(!socket_info) {
isc_throw(BadSocketInfo, "Missing socket_info parameters, can't create socket.");
}
ConstElementPtr type = socket_info->get("socket-type");
if (!type) {
isc_throw(BadSocketInfo, "Mandatory 'socket-type' parameter missing");
}
ConstElementPtr name = socket_info->get("socket-name");
if (!name) {
isc_throw(BadSocketInfo, "Mandatory 'socket-name' parameter missing");
}
if (type->stringValue() == "unix") {
return (closeUnixSocket(socket_fd, name->stringValue()));
} else {
isc_throw(BadSocketInfo, "Specified socket type ('" + type->stringValue()
+ "') is not supported.");
}
}
};
......
......@@ -20,6 +20,21 @@
namespace isc {
namespace config {
/// @brief An exception indicating that specified socket parameters are invalid
class BadSocketInfo : public Exception {
public:
BadSocketInfo(const char* file, size_t line, const char* what) :
isc::Exception(file, line, what) { };
};
/// @brief An exception indicating a problem with socket operation
class SocketError : public Exception {
public:
SocketError(const char* file, size_t line, const char* what) :
isc::Exception(file, line, what) { };
};
/// A factory class for opening command socket
///
/// This class provides an interface for opening command socket.
......@@ -46,7 +61,7 @@ public:
/// closing.
/// @param socket_fd file descriptor of the socket
/// @param socket_info structure that was used to open the socket
static int close(int socket_fd, const isc::data::ConstElementPtr& socket_info);
static void close(int socket_fd, const isc::data::ConstElementPtr& socket_info);
};
......
......@@ -18,6 +18,7 @@ TESTS =
if HAVE_GTEST
TESTS += run_unittests
run_unittests_SOURCES = module_spec_unittests.cc
run_unittests_SOURCES += command_socket_factory_unittests.cc
run_unittests_SOURCES += config_data_unittests.cc run_unittests.cc
run_unittests_SOURCES += command_mgr_unittests.cc
......
// Copyright (C) 2015 Internet Systems Consortium, Inc. ("ISC")
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
#include <gtest/gtest.h>
#include <cc/data.h>
#include <config/command_mgr.h>
#include <config/command_socket_factory.h>
using namespace isc::config;
using namespace isc::data;
// Test class for Command Manager
class CommandSocketFactoryTest : public ::testing::Test {
public:
/// Default constructor
CommandSocketFactoryTest() {
unlink(SOCKET_NAME);
}
/// Default destructor
~CommandSocketFactoryTest() {
unlink(SOCKET_NAME);
}
static const char* SOCKET_NAME;
};
const char* CommandSocketFactoryTest::SOCKET_NAME = "test-socket";
TEST_F(CommandSocketFactoryTest, unixCreate) {
// Null pointer is obviously a bad idea.
EXPECT_THROW(CommandSocketFactory::create(ConstElementPtr()),
isc::config::BadSocketInfo);
// So is passing no parameters.
ElementPtr socket_info = Element::createMap();
EXPECT_THROW(CommandSocketFactory::create(socket_info),
isc::config::BadSocketInfo);
// We don't support ipx sockets
socket_info->set("socket-type", Element::create("ipx"));
EXPECT_THROW(CommandSocketFactory::create(socket_info),
isc::config::BadSocketInfo);
socket_info->set("socket-type", Element::create("unix"));
EXPECT_THROW(CommandSocketFactory::create(socket_info),
isc::config::BadSocketInfo);
socket_info->set("socket-name", Element::create(SOCKET_NAME));
int fd;
EXPECT_NO_THROW(fd = CommandSocketFactory::create(socket_info));
EXPECT_NE(-1, fd);
// It should be possible to close the socket.
EXPECT_NO_THROW(CommandSocketFactory::close(fd, socket_info));
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment