| Kea 3.0.2-git

unix_control_client.cc
Go to the documentation of this file.
1// Copyright (C) 2015-2025 Internet Systems Consortium, Inc. ("ISC")
2//
3// This Source Code Form is subject to the terms of the Mozilla Public
4// License, v. 2.0. If a copy of the MPL was not distributed with this
5// file, You can obtain one at http://mozilla.org/MPL/2.0/.
6
7#include <config.h>
8
9#include <gtest/gtest.h>
10#include <testutils/unix_control_client.h>
11#include <unistd.h>
12#include <sys/socket.h>
13#include <sys/un.h>
14#include <errno.h>
15#include <string.h>
16
17 namespace isc {
18 namespace dhcp {
19 namespace test {
20
21 UnixControlClient::UnixControlClient() {
22 socket_fd_ = -1;
23}
24
25 UnixControlClient::~UnixControlClient() {
26 disconnectFromServer();
27}
28
30 void UnixControlClient::disconnectFromServer() {
31 if (socket_fd_ >= 0) {
32 static_cast<void>(close(socket_fd_));
33 socket_fd_ = -1;
34 }
35}
36
37 bool UnixControlClient::connectToServer(const std::string& socket_path) {
38 // Create UNIX socket
39 socket_fd_ = socket(AF_UNIX, SOCK_STREAM, 0);
40 if (socket_fd_ < 0) {
41 const char* errmsg = strerror(errno);
42 ADD_FAILURE() << "Failed to open unix stream socket: " << errmsg;
43 return (false);
44 }
45
46 struct sockaddr_un srv_addr;
47 if (socket_path.size() > sizeof(srv_addr.sun_path) - 1) {
48 ADD_FAILURE() << "Socket path specified (" << socket_path
49 << ") is larger than " << (sizeof(srv_addr.sun_path) - 1)
50 << " allowed.";
51 disconnectFromServer();
52 return (false);
53 }
54
55 // Prepare socket address
56 memset(&srv_addr, 0, sizeof(srv_addr));
57 srv_addr.sun_family = AF_UNIX;
58 strncpy(srv_addr.sun_path, socket_path.c_str(),
59 sizeof(srv_addr.sun_path) - 1);
60 socklen_t len = sizeof(srv_addr);
61
62 // Connect to the specified UNIX socket
63 int status = connect(socket_fd_, (struct sockaddr*)&srv_addr, len);
64 if (status == -1) {
65 const char* errmsg = strerror(errno);
66 ADD_FAILURE() << "Failed to connect unix socket: fd=" << socket_fd_
67 << ", path=" << socket_path << " : " << errmsg;
68 disconnectFromServer();
69 return (false);
70 }
71
72 return (true);
73}
74
75 bool UnixControlClient::sendCommand(const std::string& command) {
76 if (socket_fd_ < 0) {
77 ADD_FAILURE() << "send command with closed socket";
78 return (false);
79 }
80 switch (selectCheck(3, false, true)) {
81 case -1: {
82 const char* errmsg = strerror(errno);
83 ADD_FAILURE() << "sendCommand - select failed: " << errmsg;
84 return (false);
85 }
86 case 0:
87 return (false);
88
89 default:
90 break;
91 }
92 // Send command
93 int bytes_sent = send(socket_fd_, command.c_str(), command.length(), 0);
94 if (bytes_sent < static_cast<int>(command.length())) {
95 const char* errmsg = strerror(errno);
96 ADD_FAILURE() << "Failed to send " << command.length()
97 << " bytes, send() returned " << bytes_sent
98 << " : " << errmsg;
99 return (false);
100 }
101
102 return (true);
103}
104
105 bool UnixControlClient::getResponse(std::string& response,
106 const unsigned int timeout_sec) {
107 // Receive response
108 char buf[65536];
109 memset(buf, 0, sizeof(buf));
110 switch (selectCheck(timeout_sec, true, false)) {
111 case -1: {
112 const char* errmsg = strerror(errno);
113 ADD_FAILURE() << "getResponse - select failed: " << errmsg;
114 return (false);
115 }
116 case 0:
117 return (false);
118
119 default:
120 break;
121 }
122
123 int bytes_rcvd = recv(socket_fd_, buf, sizeof(buf), 0);
124 if (bytes_rcvd < 0) {
125 const char* errmsg = strerror(errno);
126 ADD_FAILURE() << "Failed to receive a response. recv() returned "
127 << bytes_rcvd << " : " << errmsg;
128 return (false);
129 }
130
131 // Convert the response to a string
132 response = std::string(buf, bytes_rcvd);
133 return (true);
134}
135
136 int UnixControlClient::selectCheck(const unsigned int timeout_sec,
137 bool read_check,
138 bool write_check) {
139 if (socket_fd_ < 0) {
140 ADD_FAILURE() << "select check with closed socket";
141 return -1;
142 }
143 if (socket_fd_ > 1023) {
144 ADD_FAILURE() << "select check with out of bound socket";
145 return -1;
146 }
147 int maxfd = 0;
148
149 fd_set read_fds;
150 FD_ZERO(&read_fds);
151
152 fd_set write_fds;
153 FD_ZERO(&write_fds);
154
155 maxfd = socket_fd_;
156
157 // Add this socket to read set
158 FD_SET(socket_fd_, &read_fds);
159
160 // Add this socket to write set
161 FD_SET(socket_fd_, &write_fds);
162
163 struct timeval select_timeout;
164 select_timeout.tv_sec = static_cast<time_t>(timeout_sec);
165 select_timeout.tv_usec = 0;
166
167 fd_set* read_p = 0;
168 fd_set* write_p = 0;
169
170 if (read_check) {
171 read_p = &read_fds;
172 }
173
174 if (write_check) {
175 write_p = &write_fds;
176 }
177
178 return (select(maxfd + 1, read_p, write_p, NULL, &select_timeout));
179}
180
181}
182}
183}
isc::dhcp::test::UnixControlClient::UnixControlClient
UnixControlClient()
Default constructor.
Definition unix_control_client.cc:21
isc::dhcp::test::UnixControlClient::disconnectFromServer
void disconnectFromServer()
Closes the Control Channel socket.
Definition unix_control_client.cc:30
isc::dhcp::test::UnixControlClient::~UnixControlClient
~UnixControlClient()
Destructor.
Definition unix_control_client.cc:25
isc::dhcp::test::UnixControlClient::socket_fd_
int socket_fd_
Retains the fd of the open socket.
Definition unix_control_client.h:61
isc::dhcp::test::UnixControlClient::selectCheck
int selectCheck(const unsigned int timeout_sec, bool read_check, bool write_check)
Uses select to poll the Control Channel for data waiting.
Definition unix_control_client.cc:136
isc::dhcp::test::UnixControlClient::getResponse
bool getResponse(std::string &response, const unsigned int timeout_sec=0)
Reads the response text from the open Control Channel.
Definition unix_control_client.cc:105
isc::dhcp::test::UnixControlClient::sendCommand
bool sendCommand(const std::string &command)
Sends the given command across the open Control Channel.
Definition unix_control_client.cc:75
isc::dhcp::test::UnixControlClient::connectToServer
bool connectToServer(const std::string &socket_path)
Connects to a Unix socket at the given path.
Definition unix_control_client.cc:37
isc::dhcp::test
Definition log_utils.cc:15
isc::dhcp
Definition dhcp4/client_handler.cc:20
isc
Defines the logger used by the top-level component of kea-lfc.
Definition agent_parser.cc:148
unix_control_client.h