mirror of
https://gitlab.isc.org/isc-projects/kea
synced 2025-08-29 04:57:52 +00:00
[3902] UnixControlClient moved to lib/testutils
This commit is contained in:
parent
c0d2c32d02
commit
c6b6ea4048
@ -113,6 +113,7 @@ dhcp6_unittests_LDADD += $(top_builddir)/src/lib/util/libkea-util.la
|
||||
dhcp6_unittests_LDADD += $(top_builddir)/src/lib/util/io/libkea-util-io.la
|
||||
dhcp6_unittests_LDADD += $(top_builddir)/src/bin/cfgrpt/libcfgrpt.la
|
||||
dhcp6_unittests_LDADD += $(top_builddir)/src/lib/stats/libkea-stats.la
|
||||
dhcp6_unittests_LDADD += $(top_builddir)/src/lib/testutils/libkea-testutils.la
|
||||
|
||||
endif
|
||||
|
||||
|
@ -19,6 +19,7 @@
|
||||
#include <dhcpsrv/cfgmgr.h>
|
||||
#include <dhcp6/ctrl_dhcp6_srv.h>
|
||||
#include <hooks/hooks_manager.h>
|
||||
#include <testutils/unix_control_client.h>
|
||||
|
||||
#include "marker_file.h"
|
||||
#include "test_libraries.h"
|
||||
@ -39,150 +40,6 @@ using namespace isc::hooks;
|
||||
|
||||
namespace {
|
||||
|
||||
/// Class that acts as a UnixCommandSocket client
|
||||
/// It can connect to an open UnixCommandSocket and exchange ControlChannel
|
||||
/// commands and responses.
|
||||
class UnixControlClient {
|
||||
public:
|
||||
UnixControlClient() {
|
||||
socket_fd_ = -1;
|
||||
}
|
||||
|
||||
~UnixControlClient() {
|
||||
disconnectFromServer();
|
||||
}
|
||||
|
||||
/// @brief Closes the Control Channel socket
|
||||
void disconnectFromServer() {
|
||||
if (socket_fd_ >= 0) {
|
||||
static_cast<void>(close(socket_fd_));
|
||||
socket_fd_ = -1;
|
||||
}
|
||||
}
|
||||
|
||||
/// @brief Connects to a Unix socket at the given path
|
||||
/// @param socket_path pathname of the socket to open
|
||||
/// @return true if the connect was successful, false otherwise
|
||||
bool connectToServer(const std::string& socket_path) {
|
||||
// Create UNIX socket
|
||||
socket_fd_ = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||
if (socket_fd_ < 0) {
|
||||
const char* errmsg = strerror(errno);
|
||||
ADD_FAILURE() << "Failed to open unix stream socket: " << errmsg;
|
||||
return (false);
|
||||
}
|
||||
|
||||
struct sockaddr_un srv_addr;
|
||||
if (socket_path.size() > sizeof(srv_addr.sun_path) - 1) {
|
||||
ADD_FAILURE() << "Socket path specified (" << socket_path
|
||||
<< ") is larger than " << (sizeof(srv_addr.sun_path) - 1)
|
||||
<< " allowed.";
|
||||
disconnectFromServer();
|
||||
return (false);
|
||||
}
|
||||
|
||||
// Prepare socket address
|
||||
memset(&srv_addr, 0, sizeof(srv_addr));
|
||||
srv_addr.sun_family = AF_UNIX;
|
||||
strncpy(srv_addr.sun_path, socket_path.c_str(),
|
||||
sizeof(srv_addr.sun_path));
|
||||
socklen_t len = sizeof(srv_addr);
|
||||
|
||||
// Connect to the specified UNIX socket
|
||||
int status = connect(socket_fd_, (struct sockaddr*)&srv_addr, len);
|
||||
if (status == -1) {
|
||||
const char* errmsg = strerror(errno);
|
||||
ADD_FAILURE() << "Failed to connect unix socket: fd=" << socket_fd_
|
||||
<< ", path=" << socket_path << " : " << errmsg;
|
||||
disconnectFromServer();
|
||||
return (false);
|
||||
}
|
||||
|
||||
return (true);
|
||||
}
|
||||
|
||||
/// @brief Sends the given command across the open Control Channel
|
||||
/// @param command the command text to execute in JSON form
|
||||
/// @return true if the send succeeds, false otherwise
|
||||
bool sendCommand(const std::string& command) {
|
||||
// Send command
|
||||
int bytes_sent = send(socket_fd_, command.c_str(), command.length(), 0);
|
||||
if (bytes_sent < command.length()) {
|
||||
const char* errmsg = strerror(errno);
|
||||
ADD_FAILURE() << "Failed to send " << command.length()
|
||||
<< " bytes, send() returned " << bytes_sent
|
||||
<< " : " << errmsg;
|
||||
return (false);
|
||||
}
|
||||
|
||||
return (true);
|
||||
}
|
||||
|
||||
/// @brief Reads the response text from the open Control Channel
|
||||
/// @param response variable into which the received response should be
|
||||
/// placed.
|
||||
/// @return true if data was successfully read from the socket,
|
||||
/// false otherwise
|
||||
bool getResponse(std::string& response) {
|
||||
// Receive response
|
||||
// @todo implement select check to see if data is waiting
|
||||
char buf[65536];
|
||||
memset(buf, 0, sizeof(buf));
|
||||
switch (selectCheck()) {
|
||||
case -1: {
|
||||
const char* errmsg = strerror(errno);
|
||||
ADD_FAILURE() << "getResponse - select failed: " << errmsg;
|
||||
return (false);
|
||||
}
|
||||
case 0:
|
||||
ADD_FAILURE() << "No response data sent";
|
||||
return (false);
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
int bytes_rcvd = recv(socket_fd_, buf, sizeof(buf), 0);
|
||||
if (bytes_rcvd < 0) {
|
||||
const char* errmsg = strerror(errno);
|
||||
ADD_FAILURE() << "Failed to receive a response. recv() returned "
|
||||
<< bytes_rcvd << " : " << errmsg;
|
||||
return (false);
|
||||
}
|
||||
|
||||
if (bytes_rcvd >= sizeof(buf)) {
|
||||
ADD_FAILURE() << "Response size too large: " << bytes_rcvd;
|
||||
return (false);
|
||||
}
|
||||
|
||||
// Convert the response to a string
|
||||
response = string(buf, bytes_rcvd);
|
||||
return (true);
|
||||
}
|
||||
|
||||
|
||||
/// @brief Uses select to poll the Control Channel for data waiting
|
||||
/// @return -1 on error, 0 if no data is available, 1 if data is ready
|
||||
int selectCheck() {
|
||||
int maxfd = 0;
|
||||
|
||||
fd_set read_fds;
|
||||
FD_ZERO(&read_fds);
|
||||
|
||||
// Add this socket to listening set
|
||||
FD_SET(socket_fd_, &read_fds);
|
||||
maxfd = socket_fd_;
|
||||
|
||||
struct timeval select_timeout;
|
||||
select_timeout.tv_sec = 0;
|
||||
select_timeout.tv_usec = 0;
|
||||
|
||||
return (select(maxfd + 1, &read_fds, NULL, NULL, &select_timeout));
|
||||
}
|
||||
|
||||
/// @brief Retains the fd of the open socket
|
||||
int socket_fd_;
|
||||
};
|
||||
|
||||
|
||||
class NakedControlledDhcpv6Srv: public ControlledDhcpv6Srv {
|
||||
|
@ -11,6 +11,7 @@ noinst_LTLIBRARIES = libkea-testutils.la
|
||||
|
||||
libkea_testutils_la_SOURCES = srv_test.h srv_test.cc
|
||||
libkea_testutils_la_SOURCES += dnsmessage_test.h dnsmessage_test.cc
|
||||
libkea_testutils_la_SOURCES += unix_control_client.h unix_control_client.cc
|
||||
libkea_testutils_la_SOURCES += mockups.h
|
||||
libkea_testutils_la_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
|
||||
libkea_testutils_la_LIBADD = $(top_builddir)/src/lib/asiolink/libkea-asiolink.la
|
||||
|
150
src/lib/testutils/unix_control_client.cc
Normal file
150
src/lib/testutils/unix_control_client.cc
Normal file
@ -0,0 +1,150 @@
|
||||
// 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 <testutils/unix_control_client.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
|
||||
namespace isc {
|
||||
namespace dhcp {
|
||||
namespace test {
|
||||
|
||||
UnixControlClient::UnixControlClient() {
|
||||
socket_fd_ = -1;
|
||||
}
|
||||
|
||||
UnixControlClient::~UnixControlClient() {
|
||||
disconnectFromServer();
|
||||
}
|
||||
|
||||
/// @brief Closes the Control Channel socket
|
||||
void UnixControlClient::disconnectFromServer() {
|
||||
if (socket_fd_ >= 0) {
|
||||
static_cast<void>(close(socket_fd_));
|
||||
socket_fd_ = -1;
|
||||
}
|
||||
}
|
||||
|
||||
bool UnixControlClient::connectToServer(const std::string& socket_path) {
|
||||
// Create UNIX socket
|
||||
socket_fd_ = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||
if (socket_fd_ < 0) {
|
||||
const char* errmsg = strerror(errno);
|
||||
ADD_FAILURE() << "Failed to open unix stream socket: " << errmsg;
|
||||
return (false);
|
||||
}
|
||||
|
||||
struct sockaddr_un srv_addr;
|
||||
if (socket_path.size() > sizeof(srv_addr.sun_path) - 1) {
|
||||
ADD_FAILURE() << "Socket path specified (" << socket_path
|
||||
<< ") is larger than " << (sizeof(srv_addr.sun_path) - 1)
|
||||
<< " allowed.";
|
||||
disconnectFromServer();
|
||||
return (false);
|
||||
}
|
||||
|
||||
// Prepare socket address
|
||||
memset(&srv_addr, 0, sizeof(srv_addr));
|
||||
srv_addr.sun_family = AF_UNIX;
|
||||
strncpy(srv_addr.sun_path, socket_path.c_str(),
|
||||
sizeof(srv_addr.sun_path));
|
||||
socklen_t len = sizeof(srv_addr);
|
||||
|
||||
// Connect to the specified UNIX socket
|
||||
int status = connect(socket_fd_, (struct sockaddr*)&srv_addr, len);
|
||||
if (status == -1) {
|
||||
const char* errmsg = strerror(errno);
|
||||
ADD_FAILURE() << "Failed to connect unix socket: fd=" << socket_fd_
|
||||
<< ", path=" << socket_path << " : " << errmsg;
|
||||
disconnectFromServer();
|
||||
return (false);
|
||||
}
|
||||
|
||||
return (true);
|
||||
}
|
||||
|
||||
bool UnixControlClient::sendCommand(const std::string& command) {
|
||||
// Send command
|
||||
int bytes_sent = send(socket_fd_, command.c_str(), command.length(), 0);
|
||||
if (bytes_sent < command.length()) {
|
||||
const char* errmsg = strerror(errno);
|
||||
ADD_FAILURE() << "Failed to send " << command.length()
|
||||
<< " bytes, send() returned " << bytes_sent
|
||||
<< " : " << errmsg;
|
||||
return (false);
|
||||
}
|
||||
|
||||
return (true);
|
||||
}
|
||||
|
||||
bool UnixControlClient::getResponse(std::string& response) {
|
||||
// Receive response
|
||||
char buf[65536];
|
||||
memset(buf, 0, sizeof(buf));
|
||||
switch (selectCheck()) {
|
||||
case -1: {
|
||||
const char* errmsg = strerror(errno);
|
||||
ADD_FAILURE() << "getResponse - select failed: " << errmsg;
|
||||
return (false);
|
||||
}
|
||||
case 0:
|
||||
ADD_FAILURE() << "No response data sent";
|
||||
return (false);
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
int bytes_rcvd = recv(socket_fd_, buf, sizeof(buf), 0);
|
||||
if (bytes_rcvd < 0) {
|
||||
const char* errmsg = strerror(errno);
|
||||
ADD_FAILURE() << "Failed to receive a response. recv() returned "
|
||||
<< bytes_rcvd << " : " << errmsg;
|
||||
return (false);
|
||||
}
|
||||
|
||||
if (bytes_rcvd >= sizeof(buf)) {
|
||||
ADD_FAILURE() << "Response size too large: " << bytes_rcvd;
|
||||
return (false);
|
||||
}
|
||||
|
||||
// Convert the response to a string
|
||||
response = std::string(buf, bytes_rcvd);
|
||||
return (true);
|
||||
}
|
||||
|
||||
int UnixControlClient::selectCheck() {
|
||||
int maxfd = 0;
|
||||
|
||||
fd_set read_fds;
|
||||
FD_ZERO(&read_fds);
|
||||
|
||||
// Add this socket to listening set
|
||||
FD_SET(socket_fd_, &read_fds);
|
||||
maxfd = socket_fd_;
|
||||
|
||||
struct timeval select_timeout;
|
||||
select_timeout.tv_sec = 0;
|
||||
select_timeout.tv_usec = 0;
|
||||
|
||||
return (select(maxfd + 1, &read_fds, NULL, NULL, &select_timeout));
|
||||
}
|
||||
|
||||
};
|
||||
};
|
||||
};
|
71
src/lib/testutils/unix_control_client.h
Normal file
71
src/lib/testutils/unix_control_client.h
Normal file
@ -0,0 +1,71 @@
|
||||
// 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.
|
||||
|
||||
#ifndef UNIX_CONTROL_CLIENT_H
|
||||
#define UNIX_CONTROL_CLIENT_H
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace isc {
|
||||
namespace dhcp {
|
||||
namespace test {
|
||||
|
||||
/// @brief Class that acts as a UnixCommandSocket client
|
||||
///
|
||||
/// This class is expected to be used unit-tests that attempt to communicate
|
||||
/// with the servers that use control channel (see src/lib/config/command_mgr.h)
|
||||
/// It can connect to an open UnixCommandSocket and exchange ControlChannel
|
||||
/// commands and responses.
|
||||
class UnixControlClient {
|
||||
public:
|
||||
|
||||
/// @brief Default constructor
|
||||
UnixControlClient();
|
||||
|
||||
/// @brief Destructor
|
||||
~UnixControlClient();
|
||||
|
||||
/// @brief Closes the Control Channel socket
|
||||
void disconnectFromServer();
|
||||
|
||||
/// @brief Connects to a Unix socket at the given path
|
||||
/// @param socket_path pathname of the socket to open
|
||||
/// @return true if the connect was successful, false otherwise
|
||||
bool connectToServer(const std::string& socket_path);
|
||||
|
||||
/// @brief Sends the given command across the open Control Channel
|
||||
/// @param command the command text to execute in JSON form
|
||||
/// @return true if the send succeeds, false otherwise
|
||||
bool sendCommand(const std::string& command);
|
||||
|
||||
/// @brief Reads the response text from the open Control Channel
|
||||
/// @param response variable into which the received response should be
|
||||
/// placed.
|
||||
/// @return true if data was successfully read from the socket,
|
||||
/// false otherwise
|
||||
bool getResponse(std::string& response);
|
||||
|
||||
/// @brief Uses select to poll the Control Channel for data waiting
|
||||
/// @return -1 on error, 0 if no data is available, 1 if data is ready
|
||||
int selectCheck();
|
||||
|
||||
/// @brief Retains the fd of the open socket
|
||||
int socket_fd_;
|
||||
};
|
||||
|
||||
}; // end of isc::dhcp::test namespace
|
||||
}; // end of isc::dhcp namespace
|
||||
}; // end of isc namespace
|
||||
|
||||
#endif // UNIX_CONTROL_CLIENT_H
|
Loading…
x
Reference in New Issue
Block a user