Coverage Report

Created: 2026-07-14 08:11

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/kea/src/lib/testutils/unix_control_client.cc
Line
Count
Source
1
// Copyright (C) 2015-2026 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 <util/ready_check.h>
12
#include <unistd.h>
13
#include <sys/socket.h>
14
#include <sys/un.h>
15
#include <errno.h>
16
#include <string.h>
17
18
namespace isc {
19
namespace dhcp {
20
namespace test {
21
22
4
UnixControlClient::UnixControlClient() {
23
4
    socket_fd_ = -1;
24
4
}
25
26
0
UnixControlClient::~UnixControlClient() {
27
0
    disconnectFromServer();
28
0
}
29
30
    /// @brief Closes the Control Channel socket
31
6.84k
void UnixControlClient::disconnectFromServer() {
32
6.84k
    if (socket_fd_ >= 0) {
33
6.84k
        static_cast<void>(close(socket_fd_));
34
6.84k
        socket_fd_ = -1;
35
6.84k
    }
36
6.84k
}
37
38
6.84k
bool UnixControlClient::connectToServer(const std::string& socket_path) {
39
    // Create UNIX socket
40
6.84k
    socket_fd_ = socket(AF_UNIX, SOCK_STREAM, 0);
41
6.84k
    if (socket_fd_ < 0) {
42
0
        const char* errmsg = strerror(errno);
43
0
        ADD_FAILURE() << "Failed to open unix stream socket: " << errmsg;
44
0
        return (false);
45
0
    }
46
47
6.84k
    struct sockaddr_un srv_addr;
48
6.84k
    if (socket_path.size() > sizeof(srv_addr.sun_path) - 1) {
49
0
        ADD_FAILURE() << "Socket path specified (" << socket_path
50
0
                      << ") is larger than " << (sizeof(srv_addr.sun_path) - 1)
51
0
                      << " allowed.";
52
0
        disconnectFromServer();
53
0
        return (false);
54
0
    }
55
56
    // Prepare socket address
57
6.84k
    memset(&srv_addr, 0, sizeof(srv_addr));
58
6.84k
    srv_addr.sun_family = AF_UNIX;
59
6.84k
    strncpy(srv_addr.sun_path, socket_path.c_str(),
60
6.84k
            sizeof(srv_addr.sun_path) - 1);
61
6.84k
    socklen_t len = sizeof(srv_addr);
62
63
    // Connect to the specified UNIX socket
64
6.84k
    int status = connect(socket_fd_, reinterpret_cast<struct sockaddr*>(&srv_addr), len);
65
6.84k
    if (status == -1) {
66
0
        const char* errmsg = strerror(errno);
67
0
        ADD_FAILURE() << "Failed to connect unix socket: fd=" << socket_fd_
68
0
                      << ", path=" << socket_path << " : " << errmsg;
69
0
        disconnectFromServer();
70
0
        return (false);
71
0
    }
72
73
6.84k
    return (true);
74
6.84k
}
75
76
6.84k
bool UnixControlClient::sendCommand(const std::string& command) {
77
6.84k
    if (socket_fd_ < 0) {
78
0
        ADD_FAILURE() << "send command with closed socket";
79
0
        return (false);
80
0
    }
81
    // Send command
82
6.84k
    int bytes_sent = send(socket_fd_, command.c_str(), command.length(), 0);
83
6.84k
    if (bytes_sent < static_cast<int>(command.length())) {
84
96
        const char* errmsg = strerror(errno);
85
96
        ADD_FAILURE() << "Failed to send " << command.length()
86
96
                      << " bytes, send() returned " << bytes_sent
87
96
                      << " : " << errmsg;
88
96
        return (false);
89
96
    }
90
91
6.74k
    return (true);
92
6.84k
}
93
94
bool UnixControlClient::getResponse(std::string& response,
95
6.84k
                                    const unsigned int timeout_sec) {
96
    // Receive response
97
6.84k
    char buf[65536];
98
6.84k
    memset(buf, 0, sizeof(buf));
99
6.84k
    switch (selectCheck(timeout_sec)) {
100
0
    case -1: {
101
0
        const char* errmsg = strerror(errno);
102
0
        ADD_FAILURE() << "getResponse - select failed: " << errmsg;
103
0
        return (false);
104
0
    }
105
973
    case 0:
106
973
        return (false);
107
108
5.86k
    default:
109
5.86k
        break;
110
6.84k
    }
111
112
5.86k
    int bytes_rcvd = recv(socket_fd_, buf, sizeof(buf), 0);
113
5.86k
    if (bytes_rcvd < 0) {
114
0
        const char* errmsg = strerror(errno);
115
0
        ADD_FAILURE() << "Failed to receive a response. recv() returned "
116
0
                      << bytes_rcvd << " : " << errmsg;
117
0
        return (false);
118
0
    }
119
120
    // Convert the response to a string
121
5.86k
    response = std::string(buf, bytes_rcvd);
122
5.86k
    return (true);
123
5.86k
}
124
125
6.84k
int UnixControlClient::selectCheck(const unsigned int timeout_sec) {
126
6.84k
    if (socket_fd_ < 0) {
127
0
        ADD_FAILURE() << "select check with closed socket";
128
0
        return (-1);
129
0
    }
130
6.84k
    if (socket_fd_ >= FD_SETSIZE) {
131
0
        ADD_FAILURE() << "select check with out of bound socket";
132
0
        return (-1);
133
0
    }
134
135
6.84k
    return (util::selectCheck(socket_fd_, timeout_sec));
136
6.84k
}
137
138
}
139
}
140
}