summaryrefslogtreecommitdiff
path: root/testing/hstox/driver.c
diff options
context:
space:
mode:
authoriphydf <iphydf@users.noreply.github.com>2018-01-15 00:31:06 +0000
committeriphydf <iphydf@users.noreply.github.com>2018-01-15 11:29:51 +0000
commitcec5fea71bff1ba46be6bc126efb85c28a169f9e (patch)
treef87083521fa5f5328bb1342f691eefa49c60b396 /testing/hstox/driver.c
parent402664f58d3b076a3715ddf0fdb6bb49c70c57b4 (diff)
Remove hstox test for now.
This isn't adding value. We're going to redo the whole rpc test framework in the future, after a lot of refactoring that the hstox test currently just stands in the way of.
Diffstat (limited to 'testing/hstox/driver.c')
-rw-r--r--testing/hstox/driver.c270
1 files changed, 0 insertions, 270 deletions
diff --git a/testing/hstox/driver.c b/testing/hstox/driver.c
deleted file mode 100644
index 6d1b8e0e..00000000
--- a/testing/hstox/driver.c
+++ /dev/null
@@ -1,270 +0,0 @@
1#define _POSIX_C_SOURCE 200809L
2#include <errno.h>
3#include <fcntl.h>
4#include <netdb.h>
5#include <signal.h>
6#include <signal.h>
7#include <stdarg.h>
8#include <stdio.h>
9#include <string.h>
10#include <sys/stat.h>
11#include <sys/socket.h>
12#include <sys/types.h>
13#include <netinet/in.h>
14#include <unistd.h>
15
16#include "driver.h"
17#include "errors.h"
18#include "methods.h"
19#include "util.h"
20
21#include <sodium.h>
22
23static void __attribute__((__noreturn__)) handle_interrupt(int signum)
24{
25 fprintf(stderr, "caught signal %d; exiting cleanly.\n", signum);
26 exit(0);
27}
28
29static int protocol_error(msgpack_packer *pk, char const *fmt, ...)
30{
31 msgpack_pack_array(pk, 4); // 4 elements in the array
32 msgpack_pack_uint8(pk, 1); // 1. type = response
33 // 2. We don't know the msgid, because the packet we received is not a valid
34 // msgpack-rpc packet.
35 msgpack_pack_uint64(pk, 0);
36
37 // 3. Error message.
38 va_list ap;
39 va_start(ap, fmt);
40 int res = msgpack_pack_vstringf(pk, fmt, ap);
41 va_end(ap);
42
43 // 4. No success result.
44 msgpack_pack_array(pk, 0);
45
46 return res;
47}
48
49static bool type_check(msgpack_packer *pk, msgpack_object req, int index,
50 msgpack_object_type type)
51{
52 if (req.via.array.ptr[index].type != type) {
53 protocol_error(pk, "element %d should be %s, but is %s", index, type_name(type),
54 type_name(req.via.array.ptr[index].type));
55 return false;
56 }
57
58 return true;
59}
60
61static int close_ptr(int *fd)
62{
63 if (fd && *fd >= 0) {
64 close(*fd);
65 }
66}
67
68static int write_sample_input(msgpack_object req)
69{
70 static unsigned int n;
71
72 char filename[256];
73 msgpack_object_str name = req.via.array.ptr[2].via.str;
74 snprintf(filename, sizeof filename - name.size, "test-inputs/%04u-", n++);
75
76 assert(sizeof filename - strlen(filename) > name.size + 4);
77 memcpy(filename + strlen(filename) + name.size, ".mp", 4);
78 memcpy(filename + strlen(filename), name.ptr, name.size);
79
80 int fd __attribute__((__cleanup__(close_ptr))) = open(filename, O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR);
81
82 if (fd < 0)
83 // If we can't open the sample file, we just don't write it.
84 {
85 return E_OK;
86 }
87
88 check_return(E_WRITE, ftruncate(fd, 0));
89
90 msgpack_sbuffer sbuf __attribute__((__cleanup__(msgpack_sbuffer_destroy))) = {0};
91 msgpack_sbuffer_init(&sbuf);
92
93 msgpack_packer pk;
94 msgpack_packer_init(&pk, &sbuf, msgpack_sbuffer_write);
95
96 msgpack_pack_object(&pk, req);
97
98 check_return(E_WRITE, write(fd, sbuf.data, sbuf.size));
99 check_return(E_WRITE, close(fd));
100
101 return E_OK;
102}
103
104static int handle_request(struct settings cfg, int write_fd, msgpack_object req)
105{
106 if (cfg.trace) {
107 fprintf(stderr, "input: ");
108 msgpack_object_print(stderr, req);
109 fprintf(stderr, "\n");
110 }
111
112 msgpack_sbuffer sbuf __attribute__((__cleanup__(msgpack_sbuffer_destroy))) = {0}; /* buffer */
113 msgpack_sbuffer_init(&sbuf); /* initialize buffer */
114
115 msgpack_packer pk; /* packer */
116 msgpack_packer_init(&pk, &sbuf, msgpack_sbuffer_write); /* initialize packer */
117
118 if (req.type != MSGPACK_OBJECT_ARRAY) {
119 protocol_error(&pk, "expected array, but got %s", type_name(req.type));
120 } else if (req.via.array.size != 4) {
121 protocol_error(&pk, "array length should be 4, but is %d", req.via.array.size);
122 } else if (type_check(&pk, req, 0, MSGPACK_OBJECT_POSITIVE_INTEGER) &&
123 type_check(&pk, req, 1, MSGPACK_OBJECT_POSITIVE_INTEGER) &&
124 type_check(&pk, req, 2, MSGPACK_OBJECT_STR) &&
125 type_check(&pk, req, 3, MSGPACK_OBJECT_ARRAY)) {
126 if (cfg.collect_samples) {
127 propagate(write_sample_input(req));
128 }
129
130 uint64_t msgid = req.via.array.ptr[1].via.u64;
131 msgpack_object_str name = req.via.array.ptr[2].via.str;
132 msgpack_object_array args = req.via.array.ptr[3].via.array;
133
134 msgpack_pack_array(&pk, 4); // 4 elements in the array
135 msgpack_pack_uint8(&pk, 1); // 1. type = response
136 msgpack_pack_uint64(&pk, msgid); // 2. msgid
137
138 if (name.size == (sizeof "rpc.capabilities") - 1 &&
139 memcmp(name.ptr, "rpc.capabilities", name.size) == 0) {
140 // 3. Error.
141 msgpack_pack_string(&pk, "capabilities negiotiation not implemented");
142 // 4. No result.
143 msgpack_pack_nil(&pk);
144 } else {
145 // if error is null, this writes 3. no error, and 4. result
146 char const *error =
147 call_method(name, args, &pk);
148
149 if (error) {
150 if (cfg.debug) {
151 fprintf(stderr, "error '%s' in request: ", error);
152 msgpack_object_print(stderr, req);
153 fprintf(stderr, "\n");
154 }
155
156 msgpack_pack_string(&pk, error);
157 msgpack_pack_array(&pk, 0);
158 }
159 }
160 }
161
162 check_return(E_WRITE, write(write_fd, sbuf.data, sbuf.size));
163
164 if (cfg.trace) {
165 fprintf(stderr, "result: ");
166 msgpack_unpacked res __attribute__((__cleanup__(msgpack_unpacked_destroy)));
167 msgpack_unpacked_init(&res);
168 msgpack_unpack_next(&res, sbuf.data, sbuf.size, NULL);
169 msgpack_object_print(stderr, res.data);
170 fprintf(stderr, "\n");
171 }
172
173 return E_OK;
174}
175
176int communicate(struct settings cfg, int read_fd, int write_fd)
177{
178 msgpack_unpacker unp __attribute__((__cleanup__(msgpack_unpacker_destroy)));
179 msgpack_unpacker_init(&unp, 128);
180
181 while (true) {
182 char buf[64];
183 int size = check_return(E_READ, read(read_fd, buf, sizeof buf));
184
185 if (size == 0) {
186 break;
187 }
188
189 if (msgpack_unpacker_buffer_capacity(&unp) < size &&
190 !msgpack_unpacker_reserve_buffer(&unp, size)) {
191 return E_NOMEM;
192 }
193
194 memcpy(msgpack_unpacker_buffer(&unp), buf, size);
195 msgpack_unpacker_buffer_consumed(&unp, size);
196
197 msgpack_unpacked req __attribute__((__cleanup__(msgpack_unpacked_destroy))) = {0};
198 msgpack_unpacked_init(&req);
199
200 switch (msgpack_unpacker_next(&unp, &req)) {
201 case MSGPACK_UNPACK_SUCCESS:
202 propagate(handle_request(cfg, write_fd, req.data));
203 break;
204
205 case MSGPACK_UNPACK_EXTRA_BYTES:
206 fprintf(stderr, "EXTRA_BYTES\n");
207 break;
208
209 case MSGPACK_UNPACK_CONTINUE:
210 break;
211
212 case MSGPACK_UNPACK_PARSE_ERROR:
213 return E_PARSE;
214
215 case MSGPACK_UNPACK_NOMEM_ERROR:
216 return E_NOMEM;
217 }
218 }
219
220 return E_OK;
221}
222
223static int closep(int *fd)
224{
225 return close(*fd);
226}
227
228static int run_tests(struct settings cfg, int port)
229{
230 int listen_fd __attribute__((__cleanup__(closep))) = 0;
231 listen_fd = check_return(E_SOCKET, socket(AF_INET, SOCK_STREAM, 0));
232 check_return(E_SOCKET, setsockopt(listen_fd, SOL_SOCKET, SO_REUSEADDR, &(int) {
233 1
234 }, sizeof(int)));
235
236 struct sockaddr_in servaddr = {0};
237 servaddr.sin_family = AF_INET;
238 servaddr.sin_addr.s_addr = htons(INADDR_ANY);
239 servaddr.sin_port = htons(port);
240
241 check_return(E_BIND, bind(listen_fd, (struct sockaddr *)&servaddr, sizeof servaddr));
242 check_return(E_LISTEN, listen(listen_fd, 10));
243
244 while (true) {
245 int comm_fd __attribute__((__cleanup__(closep))) = 0;
246 comm_fd = check_return(E_ACCEPT, accept(listen_fd, NULL, NULL));
247 propagate(communicate(cfg, comm_fd, comm_fd));
248 }
249
250 return E_OK;
251}
252
253uint32_t network_main(struct settings cfg, uint16_t port, unsigned int timeout)
254{
255 signal(SIGALRM, handle_interrupt);
256 signal(SIGINT, handle_interrupt);
257 check_return(E_SODIUM, sodium_init());
258
259 // Kill the process after `timeout` seconds so we don't get lingering
260 // processes bound to the test port when something goes wrong with a test run.
261 alarm(timeout);
262
263 int result = run_tests(cfg, port);
264
265 if (result == E_OK) {
266 return E_OK;
267 }
268
269 return result | (errno << 8);
270}