1
0
Fork 0
knot/tests/libknot/test_control.c
Daniel Baumann 70063ca008
Adding upstream version 3.4.6.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
2025-06-21 13:47:52 +02:00

221 lines
6 KiB
C

/* Copyright (C) 2024 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include <stdlib.h>
#include <string.h>
#include <sys/wait.h>
#include <unistd.h>
#include <tap/basic.h>
#include <tap/files.h>
#define CTL_BUFF_SIZE 18
#include "libknot/control/control.c"
#define fake_ok(condition, msg, ...) \
if (!(condition)) { \
if (msg != NULL) { \
printf("error: " msg "\n", ##__VA_ARGS__); \
} \
exit(-1); \
}
static void ctl_client(const char *socket, size_t argc, knot_ctl_data_t *argv)
{
knot_ctl_t *ctl = knot_ctl_alloc();
fake_ok(ctl != NULL, "Allocate control");
int ret;
for (int i = 0; i < 20; i++) {
ret = knot_ctl_connect(ctl, socket);
if (ret == KNOT_EOK) {
break;
}
usleep(100000);
}
fake_ok(ret == KNOT_EOK, "Connect to socket");
diag("BEGIN: Client -> Server");
if (argc > 0) {
for (size_t i = 0; i < argc; i++) {
if (argv[i][KNOT_CTL_IDX_CMD] != NULL &&
argv[i][KNOT_CTL_IDX_CMD][0] == '\0') {
ret = knot_ctl_send(ctl, KNOT_CTL_TYPE_BLOCK, NULL);
fake_ok(ret == KNOT_EOK, "Client send data block end type");
} else {
ret = knot_ctl_send(ctl, KNOT_CTL_TYPE_DATA, &argv[i]);
fake_ok(ret == KNOT_EOK, "Client send data %zu", i);
}
}
}
ret = knot_ctl_send(ctl, KNOT_CTL_TYPE_END, NULL);
fake_ok(ret == KNOT_EOK, "Client send final data");
diag("END: Client -> Server");
diag("BEGIN: Client <- Server");
size_t count = 0;
knot_ctl_data_t data;
knot_ctl_type_t type = KNOT_CTL_TYPE_DATA;
while ((ret = knot_ctl_receive(ctl, &type, &data)) == KNOT_EOK) {
if (type == KNOT_CTL_TYPE_END) {
break;
}
if (argv[count][KNOT_CTL_IDX_CMD] != NULL &&
argv[count][KNOT_CTL_IDX_CMD][0] == '\0') {
fake_ok(type == KNOT_CTL_TYPE_BLOCK, "Receive block end type");
} else {
fake_ok(type == KNOT_CTL_TYPE_DATA, "Check data type");
for (size_t i = 0; i < KNOT_CTL_IDX__COUNT; i++) {
fake_ok((data[i] == NULL && argv[count][i] == NULL) ||
(data[i] != NULL && argv[count][i] != NULL),
"Client compare input item occupation %zu", i);
if (data[i] == NULL) {
continue;
}
fake_ok(strcmp(data[i], argv[count][i]) == 0,
"Client compare input item '%s", argv[count][i]);
}
}
count++;
}
fake_ok(ret == KNOT_EOK, "Receive OK check");
fake_ok(type == KNOT_CTL_TYPE_END, "Receive EOF type");
fake_ok(count == argc, "Client compare input count '%zu'", argc);
diag("END: Client <- Server");
knot_ctl_close(ctl);
knot_ctl_free(ctl);
}
static void ctl_server(const char *socket, size_t argc, knot_ctl_data_t *argv)
{
knot_ctl_t *ctl = knot_ctl_alloc();
ok(ctl != NULL, "Allocate control");
int ret = knot_ctl_bind(ctl, socket, 5);
is_int(KNOT_EOK, ret, "Bind control socket");
ret = knot_ctl_accept(ctl);
is_int(KNOT_EOK, ret, "Accept a connection");
diag("BEGIN: Server <- Client");
size_t count = 0;
knot_ctl_data_t data;
knot_ctl_type_t type = KNOT_CTL_TYPE_DATA;
while ((ret = knot_ctl_receive(ctl, &type, &data)) == KNOT_EOK) {
if (type == KNOT_CTL_TYPE_END) {
break;
}
if (argv[count][KNOT_CTL_IDX_CMD] != NULL &&
argv[count][KNOT_CTL_IDX_CMD][0] == '\0') {
ok(type == KNOT_CTL_TYPE_BLOCK, "Receive block end type");
} else {
ok(type == KNOT_CTL_TYPE_DATA, "Check data type");
for (size_t i = 0; i < KNOT_CTL_IDX__COUNT; i++) {
ok((data[i] == NULL && argv[count][i] == NULL) ||
(data[i] != NULL && argv[count][i] != NULL),
"Server compare input item occupation %zu", i);
if (data[i] == NULL) {
continue;
}
ok(strcmp(data[i], argv[count][i]) == 0,
"Server compare input item '%s", argv[count][i]);
}
}
count++;
}
is_int(KNOT_EOK, ret, "Receive OK check");
ok(type == KNOT_CTL_TYPE_END, "Receive EOF type");
ok(count == argc, "Server compare input count '%zu'", argc);
diag("END: Server <- Client");
diag("BEGIN: Server -> Client");
if (argc > 0) {
for (size_t i = 0; i < argc; i++) {
if (argv[i][KNOT_CTL_IDX_CMD] != NULL &&
argv[i][KNOT_CTL_IDX_CMD][0] == '\0') {
ret = knot_ctl_send(ctl, KNOT_CTL_TYPE_BLOCK, NULL);
is_int(KNOT_EOK, ret, "Client send data block end type");
} else {
ret = knot_ctl_send(ctl, KNOT_CTL_TYPE_DATA, &argv[i]);
is_int(KNOT_EOK, ret, "Server send data %zu", i);
}
}
}
ret = knot_ctl_send(ctl, KNOT_CTL_TYPE_END, NULL);
is_int(KNOT_EOK, ret, "Server send final data");
diag("END: Server -> Client");
knot_ctl_close(ctl);
knot_ctl_unbind(ctl);
knot_ctl_free(ctl);
}
static void test_client_server_client(void)
{
char *socket = test_mktemp();
ok(socket != NULL, "Make a temporary socket file '%s'", socket);
size_t data_len = 5;
knot_ctl_data_t data[] = {
{ "command", "error", "section", "item", "identifier",
"zone", "owner", "ttl", "type", "data" },
{ [KNOT_CTL_IDX_DATA] = "\x01\x02" },
{ [KNOT_CTL_IDX_CMD] = "\0" }, // This means block end in this test!
{ NULL },
{ [KNOT_CTL_IDX_ERROR] = "Ultra long message" }
};
// Fork a client process.
pid_t child_pid = fork();
if (child_pid == -1) {
ok(child_pid >= 0, "Process fork");
return;
}
if (child_pid == 0) {
ctl_client(socket, data_len, data);
free(socket);
return;
} else {
ctl_server(socket, data_len, data);
}
int status = 0;
wait(&status);
ok(WIFEXITED(status), "Wait for client");
test_rm_rf(socket);
free(socket);
}
int main(int argc, char *argv[])
{
plan_lazy();
diag("Client -> Server -> Client");
test_client_server_client();
return 0;
}