|
@@ -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 {
|