diff options
Diffstat (limited to 'src/lib/testutils/unix_control_client.cc')
-rw-r--r-- | src/lib/testutils/unix_control_client.cc | 139 |
1 files changed, 139 insertions, 0 deletions
diff --git a/src/lib/testutils/unix_control_client.cc b/src/lib/testutils/unix_control_client.cc new file mode 100644 index 0000000..f0f8dfa --- /dev/null +++ b/src/lib/testutils/unix_control_client.cc @@ -0,0 +1,139 @@ +// Copyright (C) 2015-2019 Internet Systems Consortium, Inc. ("ISC") +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <config.h> + +#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) - 1); + 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, + const unsigned int timeout_sec) { + // Receive response + char buf[65536]; + memset(buf, 0, sizeof(buf)); + switch (selectCheck(timeout_sec)) { + case -1: { + const char* errmsg = strerror(errno); + ADD_FAILURE() << "getResponse - select failed: " << errmsg; + return (false); + } + case 0: + 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); + } + + // Convert the response to a string + response = std::string(buf, bytes_rcvd); + return (true); +} + +int UnixControlClient::selectCheck(const unsigned int timeout_sec) { + 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 = static_cast<time_t>(timeout_sec); + select_timeout.tv_usec = 0; + + return (select(maxfd + 1, &read_fds, NULL, NULL, &select_timeout)); +} + +}; +}; +}; |