1 /* Copyright (C) 2019 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
2
3 This program is free software: you can redistribute it and/or modify
4 it under the terms of the GNU General Public License as published by
5 the Free Software Foundation, either version 3 of the License, or
6 (at your option) any later version.
7
8 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 GNU General Public License for more details.
12
13 You should have received a copy of the GNU General Public License
14 along with this program. If not, see <https://www.gnu.org/licenses/>.
15 */
16
17 #include <stdlib.h>
18 #include <string.h>
19 #include <sys/wait.h>
20 #include <unistd.h>
21 #include <tap/basic.h>
22 #include <tap/files.h>
23
24 #define CTL_BUFF_SIZE 18
25 #include "libknot/control/control.c"
26
27 #define fake_ok(condition, msg, ...) \
28 if (!(condition)) { \
29 if (msg != NULL) { \
30 printf("error: " msg "\n", ##__VA_ARGS__); \
31 } \
32 exit(-1); \
33 }
34
ctl_client(const char * socket,size_t argc,knot_ctl_data_t * argv)35 static void ctl_client(const char *socket, size_t argc, knot_ctl_data_t *argv)
36 {
37 knot_ctl_t *ctl = knot_ctl_alloc();
38 fake_ok(ctl != NULL, "Allocate control");
39
40 int ret;
41 for (int i = 0; i < 20; i++) {
42 ret = knot_ctl_connect(ctl, socket);
43 if (ret == KNOT_EOK) {
44 break;
45 }
46 usleep(100000);
47 }
48 fake_ok(ret == KNOT_EOK, "Connect to socket");
49
50 diag("BEGIN: Client -> Server");
51
52 if (argc > 0) {
53 for (size_t i = 0; i < argc; i++) {
54 if (argv[i][KNOT_CTL_IDX_CMD] != NULL &&
55 argv[i][KNOT_CTL_IDX_CMD][0] == '\0') {
56 ret = knot_ctl_send(ctl, KNOT_CTL_TYPE_BLOCK, NULL);
57 fake_ok(ret == KNOT_EOK, "Client send data block end type");
58 } else {
59 ret = knot_ctl_send(ctl, KNOT_CTL_TYPE_DATA, &argv[i]);
60 fake_ok(ret == KNOT_EOK, "Client send data %zu", i);
61 }
62 }
63 }
64
65 ret = knot_ctl_send(ctl, KNOT_CTL_TYPE_END, NULL);
66 fake_ok(ret == KNOT_EOK, "Client send final data");
67
68 diag("END: Client -> Server");
69 diag("BEGIN: Client <- Server");
70
71 size_t count = 0;
72 knot_ctl_data_t data;
73 knot_ctl_type_t type = KNOT_CTL_TYPE_DATA;
74 while ((ret = knot_ctl_receive(ctl, &type, &data)) == KNOT_EOK) {
75 if (type == KNOT_CTL_TYPE_END) {
76 break;
77 }
78 if (argv[count][KNOT_CTL_IDX_CMD] != NULL &&
79 argv[count][KNOT_CTL_IDX_CMD][0] == '\0') {
80 fake_ok(type == KNOT_CTL_TYPE_BLOCK, "Receive block end type");
81 } else {
82 fake_ok(type == KNOT_CTL_TYPE_DATA, "Check data type");
83 for (size_t i = 0; i < KNOT_CTL_IDX__COUNT; i++) {
84 fake_ok((data[i] == NULL && argv[count][i] == NULL) ||
85 (data[i] != NULL && argv[count][i] != NULL),
86 "Client compare input item occupation %zu", i);
87 if (data[i] == NULL) {
88 continue;
89 }
90
91 fake_ok(strcmp(data[i], argv[count][i]) == 0,
92 "Client compare input item '%s", argv[count][i]);
93 }
94 }
95 count++;
96 }
97 fake_ok(ret == KNOT_EOK, "Receive OK check");
98 fake_ok(type == KNOT_CTL_TYPE_END, "Receive EOF type");
99 fake_ok(count == argc, "Client compare input count '%zu'", argc);
100
101 diag("END: Client <- Server");
102
103 knot_ctl_close(ctl);
104 knot_ctl_free(ctl);
105 }
106
ctl_server(const char * socket,size_t argc,knot_ctl_data_t * argv)107 static void ctl_server(const char *socket, size_t argc, knot_ctl_data_t *argv)
108 {
109 knot_ctl_t *ctl = knot_ctl_alloc();
110 ok(ctl != NULL, "Allocate control");
111
112 int ret = knot_ctl_bind(ctl, socket);
113 is_int(KNOT_EOK, ret, "Bind control socket");
114
115 ret = knot_ctl_accept(ctl);
116 is_int(KNOT_EOK, ret, "Accept a connection");
117
118 diag("BEGIN: Server <- Client");
119
120 size_t count = 0;
121 knot_ctl_data_t data;
122 knot_ctl_type_t type = KNOT_CTL_TYPE_DATA;
123 while ((ret = knot_ctl_receive(ctl, &type, &data)) == KNOT_EOK) {
124 if (type == KNOT_CTL_TYPE_END) {
125 break;
126 }
127 if (argv[count][KNOT_CTL_IDX_CMD] != NULL &&
128 argv[count][KNOT_CTL_IDX_CMD][0] == '\0') {
129 ok(type == KNOT_CTL_TYPE_BLOCK, "Receive block end type");
130 } else {
131 ok(type == KNOT_CTL_TYPE_DATA, "Check data type");
132 for (size_t i = 0; i < KNOT_CTL_IDX__COUNT; i++) {
133 ok((data[i] == NULL && argv[count][i] == NULL) ||
134 (data[i] != NULL && argv[count][i] != NULL),
135 "Server compare input item occupation %zu", i);
136 if (data[i] == NULL) {
137 continue;
138 }
139
140 ok(strcmp(data[i], argv[count][i]) == 0,
141 "Server compare input item '%s", argv[count][i]);
142 }
143 }
144 count++;
145 }
146 is_int(KNOT_EOK, ret, "Receive OK check");
147 ok(type == KNOT_CTL_TYPE_END, "Receive EOF type");
148 ok(count == argc, "Server compare input count '%zu'", argc);
149
150 diag("END: Server <- Client");
151 diag("BEGIN: Server -> Client");
152
153 if (argc > 0) {
154 for (size_t i = 0; i < argc; i++) {
155 if (argv[i][KNOT_CTL_IDX_CMD] != NULL &&
156 argv[i][KNOT_CTL_IDX_CMD][0] == '\0') {
157 ret = knot_ctl_send(ctl, KNOT_CTL_TYPE_BLOCK, NULL);
158 is_int(KNOT_EOK, ret, "Client send data block end type");
159 } else {
160 ret = knot_ctl_send(ctl, KNOT_CTL_TYPE_DATA, &argv[i]);
161 is_int(KNOT_EOK, ret, "Server send data %zu", i);
162 }
163 }
164 }
165
166 ret = knot_ctl_send(ctl, KNOT_CTL_TYPE_END, NULL);
167 is_int(KNOT_EOK, ret, "Server send final data");
168
169 diag("END: Server -> Client");
170
171 knot_ctl_close(ctl);
172 knot_ctl_unbind(ctl);
173 knot_ctl_free(ctl);
174 }
175
test_client_server_client(void)176 static void test_client_server_client(void)
177 {
178 char *socket = test_mktemp();
179 ok(socket != NULL, "Make a temporary socket file '%s'", socket);
180
181 size_t data_len = 5;
182 knot_ctl_data_t data[] = {
183 { "command", "error", "section", "item", "identifier",
184 "zone", "owner", "ttl", "type", "data" },
185 { [KNOT_CTL_IDX_DATA] = "\x01\x02" },
186 { [KNOT_CTL_IDX_CMD] = "\0" }, // This means block end in this test!
187 { NULL },
188 { [KNOT_CTL_IDX_ERROR] = "Ultra long message" }
189 };
190
191 // Fork a client process.
192 pid_t child_pid = fork();
193 if (child_pid == -1) {
194 ok(child_pid >= 0, "Process fork");
195 return;
196 }
197 if (child_pid == 0) {
198 ctl_client(socket, data_len, data);
199 free(socket);
200 return;
201 } else {
202 ctl_server(socket, data_len, data);
203 }
204
205 int status = 0;
206 wait(&status);
207 ok(WIFEXITED(status), "Wait for client");
208
209 test_rm_rf(socket);
210 free(socket);
211 }
212
main(int argc,char * argv[])213 int main(int argc, char *argv[])
214 {
215 plan_lazy();
216
217 diag("Client -> Server -> Client");
218 test_client_server_client();
219
220 return 0;
221 }
222