2 * Copyright (c) 2005 Andrey Simonenko
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD$");
30 #include <sys/types.h>
31 #include <sys/limits.h>
32 #include <sys/socket.h>
46 #include "uc_common.h"
47 #include "t_cmsgcred.h"
48 #include "t_bintime.h"
49 #include "t_generic.h"
50 #include "t_peercred.h"
51 #include "t_timeval.h"
52 #include "t_sockcred.h"
53 #include "t_cmsgcred_sockcred.h"
54 #include "t_cmsg_len.h"
55 #include "t_timespec_real.h"
56 #include "t_timespec_mono.h"
59 * There are tables with tests descriptions and pointers to test
60 * functions. Each t_*() function returns 0 if its test passed,
61 * -1 if its test failed, -2 if some system error occurred.
62 * If a test function returns -2, then a program exits.
64 * If a test function forks a client process, then it waits for its
65 * termination. If a return code of a client process is not equal
66 * to zero, or if a client process was terminated by a signal, then
67 * a test function returns -1 or -2 depending on exit status of
70 * Each function which can block, is run under TIMEOUT. If timeout
71 * occurs, then a test function returns -2 or a client process exits
72 * with a non-zero return code.
80 static const struct test_func test_stream_tbl[] = {
87 .desc = "Sending, receiving cmsgcred"
91 .desc = "Receiving sockcred (listening socket)"
95 .desc = "Receiving sockcred (accepted socket)"
98 .func = t_cmsgcred_sockcred,
99 .desc = "Sending cmsgcred, receiving sockcred"
103 .desc = "Sending, receiving timeval"
107 .desc = "Sending, receiving bintime"
110 * The testcase fails on 64-bit architectures (amd64), but passes on 32-bit
111 * architectures (i386); see bug 206543
116 .desc = "Check cmsghdr.cmsg_len"
121 .desc = "Check LOCAL_PEERCRED socket option"
123 #if defined(SCM_REALTIME)
125 .func = t_timespec_real,
126 .desc = "Sending, receiving realtime"
129 #if defined(SCM_MONOTONIC)
131 .func = t_timespec_mono,
132 .desc = "Sending, receiving monotonic time (uptime)"
137 #define TEST_STREAM_TBL_SIZE \
138 (sizeof(test_stream_tbl) / sizeof(test_stream_tbl[0]))
140 static const struct test_func test_dgram_tbl[] = {
147 .desc = "Sending, receiving cmsgcred"
150 .func = t_sockcred_2,
151 .desc = "Receiving sockcred"
154 .func = t_cmsgcred_sockcred,
155 .desc = "Sending cmsgcred, receiving sockcred"
159 .desc = "Sending, receiving timeval"
163 .desc = "Sending, receiving bintime"
168 .desc = "Check cmsghdr.cmsg_len"
171 #if defined(SCM_REALTIME)
173 .func = t_timespec_real,
174 .desc = "Sending, receiving realtime"
177 #if defined(SCM_MONOTONIC)
179 .func = t_timespec_mono,
180 .desc = "Sending, receiving monotonic time (uptime)"
185 #define TEST_DGRAM_TBL_SIZE \
186 (sizeof(test_dgram_tbl) / sizeof(test_dgram_tbl[0]))
188 static bool failed_flag = false;
190 struct uc_cfg uc_cfg;
192 static char work_dir[] = _PATH_TMP "unix_cmsg.XXXXXXX";
194 #define IPC_MSG_NUM_DEF 5
195 #define IPC_MSG_NUM_MAX 10
196 #define IPC_MSG_SIZE_DEF 7
197 #define IPC_MSG_SIZE_MAX 128
204 printf("usage: %s [-dh] [-n num] [-s size] [-t type] "
205 "[-z value] [testno]\n", getprogname());
208 printf("\n Options are:\n\
209 -d Output debugging information\n\
210 -h Output the help message and exit\n\
211 -n num Number of messages to send\n\
212 -s size Specify size of data for IPC\n\
213 -t type Specify socket type (stream, dgram) for tests\n\
214 -z value Do not send data in a message (bit 0x1), do not send\n\
215 data array associated with a cmsghdr structure (bit 0x2)\n\
216 testno Run one test by its number (require the -t option)\n\n");
217 printf(" Available tests for stream sockets:\n");
218 for (i = 0; i < TEST_STREAM_TBL_SIZE; ++i)
219 printf(" %u: %s\n", i, test_stream_tbl[i].desc);
220 printf("\n Available tests for datagram sockets:\n");
221 for (i = 0; i < TEST_DGRAM_TBL_SIZE; ++i)
222 printf(" %u: %s\n", i, test_dgram_tbl[i].desc);
226 run_tests(int type, u_int testno1)
228 const struct test_func *tf;
229 u_int i, testno2, failed_num;
231 uc_cfg.sock_type = type;
232 if (type == SOCK_STREAM) {
233 uc_cfg.sock_type_str = "SOCK_STREAM";
234 tf = test_stream_tbl;
235 i = TEST_STREAM_TBL_SIZE - 1;
237 uc_cfg.sock_type_str = "SOCK_DGRAM";
239 i = TEST_DGRAM_TBL_SIZE - 1;
247 uc_output("Running tests for %s sockets:\n", uc_cfg.sock_type_str);
249 for (i = testno1, tf += testno1; i <= testno2; ++tf, ++i) {
250 uc_output(" %u: %s\n", i, tf->desc);
251 switch (tf->func()) {
256 uc_logmsgx("some system error or timeout occurred");
264 if (testno1 != testno2) {
266 uc_output("-- all tests passed!\n");
268 uc_output("-- %u test%s failed!\n",
269 failed_num, failed_num == 1 ? "" : "s");
272 uc_output("-- test passed!\n");
274 uc_output("-- test failed!\n");
283 struct sigaction sigact;
287 uc_cfg.proc_name = "SERVER";
289 sigact.sa_handler = SIG_IGN;
291 sigemptyset(&sigact.sa_mask);
292 if (sigaction(SIGPIPE, &sigact, (struct sigaction *)NULL) < 0) {
293 uc_logmsg("init: sigaction");
297 if (uc_cfg.ipc_msg.buf_size == 0)
298 uc_cfg.ipc_msg.buf_send = uc_cfg.ipc_msg.buf_recv = NULL;
300 uc_cfg.ipc_msg.buf_send = malloc(uc_cfg.ipc_msg.buf_size);
301 uc_cfg.ipc_msg.buf_recv = malloc(uc_cfg.ipc_msg.buf_size);
302 if (uc_cfg.ipc_msg.buf_send == NULL || uc_cfg.ipc_msg.buf_recv == NULL) {
303 uc_logmsg("init: malloc");
306 for (idx = 0; idx < uc_cfg.ipc_msg.buf_size; ++idx)
307 uc_cfg.ipc_msg.buf_send[idx] = (char)idx;
310 uc_cfg.proc_cred.uid = getuid();
311 uc_cfg.proc_cred.euid = geteuid();
312 uc_cfg.proc_cred.gid = getgid();
313 uc_cfg.proc_cred.egid = getegid();
314 uc_cfg.proc_cred.gid_num = getgroups(0, (gid_t *)NULL);
315 if (uc_cfg.proc_cred.gid_num < 0) {
316 uc_logmsg("init: getgroups");
319 uc_cfg.proc_cred.gid_arr = malloc(uc_cfg.proc_cred.gid_num *
320 sizeof(*uc_cfg.proc_cred.gid_arr));
321 if (uc_cfg.proc_cred.gid_arr == NULL) {
322 uc_logmsg("init: malloc");
325 if (getgroups(uc_cfg.proc_cred.gid_num, uc_cfg.proc_cred.gid_arr) < 0) {
326 uc_logmsg("init: getgroups");
330 memset(&uc_cfg.serv_addr_sun, 0, sizeof(uc_cfg.serv_addr_sun));
331 rv = snprintf(uc_cfg.serv_addr_sun.sun_path, sizeof(uc_cfg.serv_addr_sun.sun_path),
332 "%s/%s", work_dir, uc_cfg.proc_name);
334 uc_logmsg("init: snprintf");
337 if ((size_t)rv >= sizeof(uc_cfg.serv_addr_sun.sun_path)) {
338 uc_logmsgx("init: not enough space for socket pathname");
341 uc_cfg.serv_addr_sun.sun_family = PF_LOCAL;
342 uc_cfg.serv_addr_sun.sun_len = SUN_LEN(&uc_cfg.serv_addr_sun);
348 main(int argc, char *argv[])
351 u_int testno, zvalue;
353 bool dgram_flag, stream_flag;
355 memset(&uc_cfg, '\0', sizeof(uc_cfg));
356 uc_cfg.debug = false;
357 uc_cfg.server_flag = true;
358 uc_cfg.send_data_flag = true;
359 uc_cfg.send_array_flag = true;
360 uc_cfg.ipc_msg.buf_size = IPC_MSG_SIZE_DEF;
361 uc_cfg.ipc_msg.msg_num = IPC_MSG_NUM_DEF;
362 dgram_flag = stream_flag = false;
363 while ((opt = getopt(argc, argv, "dhn:s:t:z:")) != -1)
370 return (EXIT_SUCCESS);
372 uc_cfg.ipc_msg.msg_num = strtonum(optarg, 1,
373 IPC_MSG_NUM_MAX, &errstr);
375 errx(EXIT_FAILURE, "option -n: number is %s",
379 uc_cfg.ipc_msg.buf_size = strtonum(optarg, 0,
380 IPC_MSG_SIZE_MAX, &errstr);
382 errx(EXIT_FAILURE, "option -s: number is %s",
386 if (strcmp(optarg, "stream") == 0)
388 else if (strcmp(optarg, "dgram") == 0)
391 errx(EXIT_FAILURE, "option -t: "
392 "wrong socket type");
395 zvalue = strtonum(optarg, 0, 3, &errstr);
397 errx(EXIT_FAILURE, "option -z: number is %s",
400 uc_cfg.send_data_flag = false;
402 uc_cfg.send_array_flag = false;
406 return (EXIT_FAILURE);
410 if (optind + 1 != argc)
411 errx(EXIT_FAILURE, "too many arguments");
412 testno = strtonum(argv[optind], 0, UINT_MAX, &errstr);
414 errx(EXIT_FAILURE, "test number is %s", errstr);
415 if (stream_flag && testno >= TEST_STREAM_TBL_SIZE)
416 errx(EXIT_FAILURE, "given test %u for stream "
417 "sockets does not exist", testno);
418 if (dgram_flag && testno >= TEST_DGRAM_TBL_SIZE)
419 errx(EXIT_FAILURE, "given test %u for datagram "
420 "sockets does not exist", testno);
424 if (!dgram_flag && !stream_flag) {
426 errx(EXIT_FAILURE, "particular test number "
427 "can be used with the -t option only");
428 dgram_flag = stream_flag = true;
431 if (mkdtemp(work_dir) == NULL)
432 err(EXIT_FAILURE, "mkdtemp(%s)", work_dir);
439 if (run_tests(SOCK_STREAM, testno) < 0)
442 if (run_tests(SOCK_DGRAM, testno) < 0)
447 if (rmdir(work_dir) < 0) {
448 uc_logmsg("rmdir(%s)", work_dir);
451 return (failed_flag ? EXIT_FAILURE : rv);