#include <hooks/hooks_manager.h>
#include <log/logger_support.h>
#include <stats/stats_mgr.h>
+#include <testutils/io_utils.h>
#include <testutils/unix_control_client.h>
#include "marker_file.h"
EXPECT_EQ(1, subnets->size());
// Create a valid config with two subnets and no command channel.
- // It should succeed but client will not receive a the response
+ // It should succeed, client should still receive the response
os.str("");
os << set_config_txt << ","
<< args_txt
<< "}\n" // close dhcp4
<< "}}";
+ /* Verify the control channel socket exists */
+ ASSERT_TRUE(fileExists(socket_path_));
+
// Send the set-config command
sendUnixCommand(os.str(), response);
- // With no command channel, no response
- EXPECT_EQ("", response);
+ /* Verify the control channel socket no longer exists */
+ EXPECT_FALSE(fileExists(socket_path_));
+
+ // With no command channel, should still receive the response.
+ EXPECT_EQ("{ \"result\": 0, \"text\": \"Configuration successful.\" }",
+ response);
// Check that the config was not lost
subnets = CfgMgr::instance().getCurrentCfg()->getCfgSubnets4()->getAll();
#include <log/logger_support.h>
#include <stats/stats_mgr.h>
#include <testutils/unix_control_client.h>
+#include <testutils/io_utils.h>
#include "marker_file.h"
#include "test_libraries.h"
#include <gtest/gtest.h>
#include <sys/select.h>
+#include <sys/stat.h>
#include <sys/ioctl.h>
#include <cstdlib>
<< "}\n" // close dhcp6
<< "}}";
+ /* Verify the control channel socket exists */
+ ASSERT_TRUE(fileExists(socket_path_));
+
// Send the set-config command
sendUnixCommand(os.str(), response);
- // With no command channel, no response
- EXPECT_EQ("", response);
+ /* Verify the control channel socket no longer exists */
+ EXPECT_FALSE(fileExists(socket_path_));
+
+ // With no command channel, should still receive the response.
+ EXPECT_EQ("{ \"result\": 0, \"text\": \"Configuration successful.\" }",
+ response);
// Check that the config was not lost
subnets = CfgMgr::instance().getCurrentCfg()->getCfgSubnets6()->getAll();
#include <dhcp/iface_mgr.h>
#include <config/config_log.h>
#include <boost/bind.hpp>
+#include <unistd.h>
using namespace isc::data;
return;
}
+ // Duplicate the connection's socket in the event, the command causes the
+ // channel to close (like a reconfig). This permits us to always have
+ // a socket on which to respond. If for some reason we can't fall back
+ // to the connection socket.
+ int rsp_fd = dup(sockfd);
+ if (rsp_fd < 0 ) {
+ // Highly unlikely
+ const char* errmsg = strerror(errno);
+ LOG_DEBUG(command_logger, DBG_COMMAND, COMMAND_SOCKET_DUP_WARN)
+ .arg(errmsg);
+ rsp_fd = sockfd;
+ }
+
LOG_DEBUG(command_logger, DBG_COMMAND, COMMAND_SOCKET_READ).arg(rval).arg(sockfd);
// Ok, we received something. Let's see if we can make any sense of it.
if (!rsp) {
LOG_WARN(command_logger, COMMAND_RESPONSE_ERROR);
+ // Only close the dupped socket if it's different (should be)
+ if (rsp_fd != sockfd) {
+ close(rsp_fd);
+ }
+
return;
}
}
// Send the data back over socket.
- rval = write(sockfd, txt.c_str(), len);
+ rval = write(rsp_fd, txt.c_str(), len);
+ int saverr = errno;
LOG_DEBUG(command_logger, DBG_COMMAND, COMMAND_SOCKET_WRITE).arg(len).arg(sockfd);
// Response transmission failed. Since the response failed, it doesn't
// make sense to send any status codes. Let's log it and be done with
// it.
- LOG_ERROR(command_logger, COMMAND_SOCKET_WRITE_FAIL).arg(len).arg(sockfd);
+ LOG_ERROR(command_logger, COMMAND_SOCKET_WRITE_FAIL)
+ .arg(len).arg(sockfd).arg(strerror(saverr));
+ }
+
+ // Only close the dupped socket if it's different (should be)
+ if (rsp_fd != sockfd) {
+ close(rsp_fd);
}
}
on just created socket. That socket was created for accepting specific
incoming connection. Additional information may be provided as third parameter.
+% COMMAND_SOCKET_DUP_WARN Failed to duplicate socket for response: %1
+This debug message indicates that the commandReader was unable to duplicate
+the connection socket prior to executing the command. This is most likely a
+system resource issue. The command should still be processed and the response
+sent, unless the command caused the command channel to be closed (e.g. a
+reconfiguration command).
+
% COMMAND_SOCKET_READ Received %1 bytes over command socket %2
This debug message indicates that specified number of bytes was received
over command socket identified by specified file descriptor.
This debug message indicates that the specified number of bytes was sent
over command socket identifier by the specified file descriptor.
-% COMMAND_SOCKET_WRITE_FAIL Error while writing %1 bytes to command socket %2
+% COMMAND_SOCKET_WRITE_FAIL Error while writing %1 bytes to command socket %2 : %3
This error message indicates that an error was encountered while
attempting to send a response to the command socket.
namespace test {
bool fileExists(const std::string& file_path) {
- std::ifstream fs(file_path.c_str());
- const bool file_exists = fs.good();
- fs.close();
- return (file_exists);
+ struct stat statbuf;
+ return(stat(file_path.c_str(), &statbuf) == 0);
}
std::string readFile(const std::string& file_path) {
#define TEST_IO_UTILS_H
#include <string>
+#include <sys/stat.h>
namespace isc {
namespace dhcp {