Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/tools/regression/sockets/unix_cmsg/unix_cmsg.c
96317 views
1
/*-
2
* Copyright (c) 2005 Andrey Simonenko
3
* All rights reserved.
4
*
5
* Redistribution and use in source and binary forms, with or without
6
* modification, are permitted provided that the following conditions
7
* are met:
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.
13
*
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
24
* SUCH DAMAGE.
25
*/
26
27
#include <sys/types.h>
28
#include <sys/limits.h>
29
#include <sys/socket.h>
30
#include <sys/un.h>
31
32
#include <err.h>
33
#include <inttypes.h>
34
#include <paths.h>
35
#include <signal.h>
36
#include <stdarg.h>
37
#include <stdbool.h>
38
#include <stdio.h>
39
#include <stdlib.h>
40
#include <string.h>
41
#include <unistd.h>
42
43
#include "uc_common.h"
44
#include "t_cmsgcred.h"
45
#include "t_bintime.h"
46
#include "t_generic.h"
47
#include "t_peercred.h"
48
#include "t_timeval.h"
49
#include "t_sockcred.h"
50
#include "t_cmsgcred_sockcred.h"
51
#include "t_cmsg_len.h"
52
#include "t_timespec_real.h"
53
#include "t_timespec_mono.h"
54
55
/*
56
* There are tables with tests descriptions and pointers to test
57
* functions. Each t_*() function returns 0 if its test passed,
58
* -1 if its test failed, -2 if some system error occurred.
59
* If a test function returns -2, then a program exits.
60
*
61
* If a test function forks a client process, then it waits for its
62
* termination. If a return code of a client process is not equal
63
* to zero, or if a client process was terminated by a signal, then
64
* a test function returns -1 or -2 depending on exit status of
65
* a client process.
66
*
67
* Each function which can block, is run under TIMEOUT. If timeout
68
* occurs, then a test function returns -2 or a client process exits
69
* with a non-zero return code.
70
*/
71
72
struct test_func {
73
int (*func)(void);
74
const char *desc;
75
};
76
77
static const struct test_func test_stream_tbl[] = {
78
{
79
.func = NULL,
80
.desc = "All tests"
81
},
82
{
83
.func = t_cmsgcred,
84
.desc = "Sending, receiving cmsgcred"
85
},
86
{
87
.func = t_sockcred_1,
88
.desc = "Receiving sockcred (listening socket)"
89
},
90
{
91
.func = t_sockcred_2,
92
.desc = "Receiving sockcred (accepted socket)"
93
},
94
{
95
.func = t_cmsgcred_sockcred,
96
.desc = "Sending cmsgcred, receiving sockcred"
97
},
98
{
99
.func = t_timeval,
100
.desc = "Sending, receiving timeval"
101
},
102
{
103
.func = t_bintime,
104
.desc = "Sending, receiving bintime"
105
},
106
/*
107
* The testcase fails on 64-bit architectures (amd64), but passes on 32-bit
108
* architectures (i386); see bug 206543
109
*/
110
#ifndef __LP64__
111
{
112
.func = t_cmsg_len,
113
.desc = "Check cmsghdr.cmsg_len"
114
},
115
#endif
116
{
117
.func = t_peercred,
118
.desc = "Check LOCAL_PEERCRED socket option"
119
},
120
#if defined(SCM_REALTIME)
121
{
122
.func = t_timespec_real,
123
.desc = "Sending, receiving realtime"
124
},
125
#endif
126
#if defined(SCM_MONOTONIC)
127
{
128
.func = t_timespec_mono,
129
.desc = "Sending, receiving monotonic time (uptime)"
130
}
131
#endif
132
};
133
134
#define TEST_STREAM_TBL_SIZE \
135
(sizeof(test_stream_tbl) / sizeof(test_stream_tbl[0]))
136
137
static const struct test_func test_dgram_tbl[] = {
138
{
139
.func = NULL,
140
.desc = "All tests"
141
},
142
{
143
.func = t_cmsgcred,
144
.desc = "Sending, receiving cmsgcred"
145
},
146
{
147
.func = t_sockcred_2,
148
.desc = "Receiving sockcred"
149
},
150
{
151
.func = t_cmsgcred_sockcred,
152
.desc = "Sending cmsgcred, receiving sockcred"
153
},
154
{
155
.func = t_timeval,
156
.desc = "Sending, receiving timeval"
157
},
158
{
159
.func = t_bintime,
160
.desc = "Sending, receiving bintime"
161
},
162
#ifndef __LP64__
163
{
164
.func = t_cmsg_len,
165
.desc = "Check cmsghdr.cmsg_len"
166
},
167
#endif
168
#if defined(SCM_REALTIME)
169
{
170
.func = t_timespec_real,
171
.desc = "Sending, receiving realtime"
172
},
173
#endif
174
#if defined(SCM_MONOTONIC)
175
{
176
.func = t_timespec_mono,
177
.desc = "Sending, receiving monotonic time (uptime)"
178
}
179
#endif
180
};
181
182
#define TEST_DGRAM_TBL_SIZE \
183
(sizeof(test_dgram_tbl) / sizeof(test_dgram_tbl[0]))
184
185
static bool failed_flag = false;
186
187
struct uc_cfg uc_cfg;
188
189
static char work_dir[] = _PATH_TMP "unix_cmsg.XXXXXXX";
190
191
#define IPC_MSG_NUM_DEF 5
192
#define IPC_MSG_NUM_MAX 10
193
#define IPC_MSG_SIZE_DEF 7
194
#define IPC_MSG_SIZE_MAX 128
195
196
static void
197
usage(bool verbose)
198
{
199
u_int i;
200
201
printf("usage: %s [-dh] [-n num] [-s size] [-t type] "
202
"[-z value] [testno]\n", getprogname());
203
if (!verbose)
204
return;
205
printf("\n Options are:\n\
206
-d Output debugging information\n\
207
-h Output the help message and exit\n\
208
-n num Number of messages to send\n\
209
-s size Specify size of data for IPC\n\
210
-t type Specify socket type (stream, dgram) for tests\n\
211
-z value Do not send data in a message (bit 0x1), do not send\n\
212
data array associated with a cmsghdr structure (bit 0x2)\n\
213
testno Run one test by its number (require the -t option)\n\n");
214
printf(" Available tests for stream sockets:\n");
215
for (i = 0; i < TEST_STREAM_TBL_SIZE; ++i)
216
printf(" %u: %s\n", i, test_stream_tbl[i].desc);
217
printf("\n Available tests for datagram sockets:\n");
218
for (i = 0; i < TEST_DGRAM_TBL_SIZE; ++i)
219
printf(" %u: %s\n", i, test_dgram_tbl[i].desc);
220
}
221
222
static int
223
run_tests(int type, u_int testno1)
224
{
225
const struct test_func *tf;
226
u_int i, testno2, failed_num;
227
228
uc_cfg.sock_type = type;
229
if (type == SOCK_STREAM) {
230
uc_cfg.sock_type_str = "SOCK_STREAM";
231
tf = test_stream_tbl;
232
i = TEST_STREAM_TBL_SIZE - 1;
233
} else {
234
uc_cfg.sock_type_str = "SOCK_DGRAM";
235
tf = test_dgram_tbl;
236
i = TEST_DGRAM_TBL_SIZE - 1;
237
}
238
if (testno1 == 0) {
239
testno1 = 1;
240
testno2 = i;
241
} else
242
testno2 = testno1;
243
244
uc_output("Running tests for %s sockets:\n", uc_cfg.sock_type_str);
245
failed_num = 0;
246
for (i = testno1, tf += testno1; i <= testno2; ++tf, ++i) {
247
uc_output(" %u: %s\n", i, tf->desc);
248
switch (tf->func()) {
249
case -1:
250
++failed_num;
251
break;
252
case -2:
253
uc_logmsgx("some system error or timeout occurred");
254
return (-1);
255
}
256
}
257
258
if (failed_num != 0)
259
failed_flag = true;
260
261
if (testno1 != testno2) {
262
if (failed_num == 0)
263
uc_output("-- all tests passed!\n");
264
else
265
uc_output("-- %u test%s failed!\n",
266
failed_num, failed_num == 1 ? "" : "s");
267
} else {
268
if (failed_num == 0)
269
uc_output("-- test passed!\n");
270
else
271
uc_output("-- test failed!\n");
272
}
273
274
return (0);
275
}
276
277
static int
278
init(void)
279
{
280
struct sigaction sigact;
281
size_t idx;
282
int rv;
283
284
uc_cfg.proc_name = "SERVER";
285
286
sigact.sa_handler = SIG_IGN;
287
sigact.sa_flags = 0;
288
sigemptyset(&sigact.sa_mask);
289
if (sigaction(SIGPIPE, &sigact, (struct sigaction *)NULL) < 0) {
290
uc_logmsg("init: sigaction");
291
return (-1);
292
}
293
294
if (uc_cfg.ipc_msg.buf_size == 0)
295
uc_cfg.ipc_msg.buf_send = uc_cfg.ipc_msg.buf_recv = NULL;
296
else {
297
uc_cfg.ipc_msg.buf_send = malloc(uc_cfg.ipc_msg.buf_size);
298
uc_cfg.ipc_msg.buf_recv = malloc(uc_cfg.ipc_msg.buf_size);
299
if (uc_cfg.ipc_msg.buf_send == NULL || uc_cfg.ipc_msg.buf_recv == NULL) {
300
uc_logmsg("init: malloc");
301
return (-1);
302
}
303
for (idx = 0; idx < uc_cfg.ipc_msg.buf_size; ++idx)
304
uc_cfg.ipc_msg.buf_send[idx] = (char)idx;
305
}
306
307
uc_cfg.proc_cred.uid = getuid();
308
uc_cfg.proc_cred.euid = geteuid();
309
uc_cfg.proc_cred.gid = getgid();
310
uc_cfg.proc_cred.egid = getegid();
311
uc_cfg.proc_cred.gid_num = getgroups(0, (gid_t *)NULL);
312
if (uc_cfg.proc_cred.gid_num < 0) {
313
uc_logmsg("init: getgroups");
314
return (-1);
315
}
316
uc_cfg.proc_cred.gid_arr = malloc(uc_cfg.proc_cred.gid_num *
317
sizeof(*uc_cfg.proc_cred.gid_arr));
318
if (uc_cfg.proc_cred.gid_arr == NULL) {
319
uc_logmsg("init: malloc");
320
return (-1);
321
}
322
if (getgroups(uc_cfg.proc_cred.gid_num, uc_cfg.proc_cred.gid_arr) < 0) {
323
uc_logmsg("init: getgroups");
324
return (-1);
325
}
326
327
memset(&uc_cfg.serv_addr_sun, 0, sizeof(uc_cfg.serv_addr_sun));
328
rv = snprintf(uc_cfg.serv_addr_sun.sun_path, sizeof(uc_cfg.serv_addr_sun.sun_path),
329
"%s/%s", work_dir, uc_cfg.proc_name);
330
if (rv < 0) {
331
uc_logmsg("init: snprintf");
332
return (-1);
333
}
334
if ((size_t)rv >= sizeof(uc_cfg.serv_addr_sun.sun_path)) {
335
uc_logmsgx("init: not enough space for socket pathname");
336
return (-1);
337
}
338
uc_cfg.serv_addr_sun.sun_family = PF_LOCAL;
339
uc_cfg.serv_addr_sun.sun_len = SUN_LEN(&uc_cfg.serv_addr_sun);
340
341
return (0);
342
}
343
344
int
345
main(int argc, char *argv[])
346
{
347
const char *errstr;
348
u_int testno, zvalue;
349
int opt, rv;
350
bool dgram_flag, stream_flag;
351
352
memset(&uc_cfg, '\0', sizeof(uc_cfg));
353
uc_cfg.debug = false;
354
uc_cfg.server_flag = true;
355
uc_cfg.send_data_flag = true;
356
uc_cfg.send_array_flag = true;
357
uc_cfg.ipc_msg.buf_size = IPC_MSG_SIZE_DEF;
358
uc_cfg.ipc_msg.msg_num = IPC_MSG_NUM_DEF;
359
dgram_flag = stream_flag = false;
360
while ((opt = getopt(argc, argv, "dhn:s:t:z:")) != -1)
361
switch (opt) {
362
case 'd':
363
uc_cfg.debug = true;
364
break;
365
case 'h':
366
usage(true);
367
return (EXIT_SUCCESS);
368
case 'n':
369
uc_cfg.ipc_msg.msg_num = strtonum(optarg, 1,
370
IPC_MSG_NUM_MAX, &errstr);
371
if (errstr != NULL)
372
errx(EXIT_FAILURE, "option -n: number is %s",
373
errstr);
374
break;
375
case 's':
376
uc_cfg.ipc_msg.buf_size = strtonum(optarg, 0,
377
IPC_MSG_SIZE_MAX, &errstr);
378
if (errstr != NULL)
379
errx(EXIT_FAILURE, "option -s: number is %s",
380
errstr);
381
break;
382
case 't':
383
if (strcmp(optarg, "stream") == 0)
384
stream_flag = true;
385
else if (strcmp(optarg, "dgram") == 0)
386
dgram_flag = true;
387
else
388
errx(EXIT_FAILURE, "option -t: "
389
"wrong socket type");
390
break;
391
case 'z':
392
zvalue = strtonum(optarg, 0, 3, &errstr);
393
if (errstr != NULL)
394
errx(EXIT_FAILURE, "option -z: number is %s",
395
errstr);
396
if (zvalue & 0x1)
397
uc_cfg.send_data_flag = false;
398
if (zvalue & 0x2)
399
uc_cfg.send_array_flag = false;
400
break;
401
default:
402
usage(false);
403
return (EXIT_FAILURE);
404
}
405
406
if (optind < argc) {
407
if (optind + 1 != argc)
408
errx(EXIT_FAILURE, "too many arguments");
409
testno = strtonum(argv[optind], 0, UINT_MAX, &errstr);
410
if (errstr != NULL)
411
errx(EXIT_FAILURE, "test number is %s", errstr);
412
if (stream_flag && testno >= TEST_STREAM_TBL_SIZE)
413
errx(EXIT_FAILURE, "given test %u for stream "
414
"sockets does not exist", testno);
415
if (dgram_flag && testno >= TEST_DGRAM_TBL_SIZE)
416
errx(EXIT_FAILURE, "given test %u for datagram "
417
"sockets does not exist", testno);
418
} else
419
testno = 0;
420
421
if (!dgram_flag && !stream_flag) {
422
if (testno != 0)
423
errx(EXIT_FAILURE, "particular test number "
424
"can be used with the -t option only");
425
dgram_flag = stream_flag = true;
426
}
427
428
if (mkdtemp(work_dir) == NULL)
429
err(EXIT_FAILURE, "mkdtemp(%s)", work_dir);
430
431
rv = EXIT_FAILURE;
432
if (init() < 0)
433
goto done;
434
435
if (stream_flag)
436
if (run_tests(SOCK_STREAM, testno) < 0)
437
goto done;
438
if (dgram_flag)
439
if (run_tests(SOCK_DGRAM, testno) < 0)
440
goto done;
441
442
rv = EXIT_SUCCESS;
443
done:
444
if (rmdir(work_dir) < 0) {
445
uc_logmsg("rmdir(%s)", work_dir);
446
rv = EXIT_FAILURE;
447
}
448
return (failed_flag ? EXIT_FAILURE : rv);
449
}
450
451