221 lines
6 KiB
C
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;
|
|
}
|