Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/lib/libcasper/tests/cap_main_test.c
288947 views
1
/*-
2
* SPDX-License-Identifier: BSD-2-Clause
3
*
4
* Copyright (c) 2026 Mariusz Zaborski <[email protected]>
5
*
6
* Redistribution and use in source and binary forms, with or without
7
* modification, are permitted provided that the following conditions
8
* are met:
9
* 1. Redistributions of source code must retain the above copyright
10
* notice, this list of conditions and the following disclaimer.
11
* 2. Redistributions in binary form must reproduce the above copyright
12
* notice, this list of conditions and the following disclaimer in the
13
* documentation and/or other materials provided with the distribution.
14
*
15
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
16
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
19
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25
* SUCH DAMAGE.
26
*/
27
28
#include <sys/resource.h>
29
#include <sys/select.h>
30
31
#include <errno.h>
32
#include <inttypes.h>
33
#include <stdlib.h>
34
#include <string.h>
35
36
#include <libcasper.h>
37
38
#include <atf-c.h>
39
40
#define NCONNECTIONS (FD_SETSIZE + 64)
41
#define FD_HEADROOM 64
42
43
/* Test that file descriptors past FD_SETSIZE (1024) work. */
44
ATF_TC_WITHOUT_HEAD(many_connections);
45
ATF_TC_BODY(many_connections, tc)
46
{
47
struct rlimit rl;
48
cap_channel_t *chan;
49
cap_channel_t **clones;
50
size_t i;
51
52
if (getrlimit(RLIMIT_NOFILE, &rl) != 0)
53
atf_tc_skip("getrlimit: %s", strerror(errno));
54
if (rl.rlim_max < NCONNECTIONS + FD_HEADROOM)
55
atf_tc_skip("RLIMIT_NOFILE hard cap %ju below required %d",
56
(uintmax_t)rl.rlim_max, NCONNECTIONS + FD_HEADROOM);
57
rl.rlim_cur = rl.rlim_max;
58
ATF_REQUIRE_MSG(setrlimit(RLIMIT_NOFILE, &rl) == 0,
59
"setrlimit: %s", strerror(errno));
60
61
chan = cap_init();
62
ATF_REQUIRE_MSG(chan != NULL, "cap_init failed: %s", strerror(errno));
63
64
clones = calloc(NCONNECTIONS, sizeof(*clones));
65
ATF_REQUIRE(clones != NULL);
66
67
/*
68
* Every cap_clone(3) adds one more connection to the helper.
69
* After this loop the helper is watching more fds than an
70
* fd_set can hold.
71
*/
72
for (i = 0; i < NCONNECTIONS; i++) {
73
clones[i] = cap_clone(chan);
74
ATF_REQUIRE_MSG(clones[i] != NULL,
75
"cap_clone failed at %zu/%d: %s",
76
i, NCONNECTIONS, strerror(errno));
77
}
78
79
for (i = 0; i < NCONNECTIONS; i++)
80
cap_close(clones[i]);
81
free(clones);
82
cap_close(chan);
83
}
84
85
#define CHURN_CONNECTIONS 50
86
#define CHURN_CLOSE_STEP 5
87
88
/* Test that gaps in the file descriptor list do not break casper. */
89
ATF_TC_WITHOUT_HEAD(connection_churn);
90
ATF_TC_BODY(connection_churn, tc)
91
{
92
cap_channel_t *chan, *survivor, *extra;
93
cap_channel_t *clones[CHURN_CONNECTIONS];
94
size_t i, survivor_idx;
95
96
chan = cap_init();
97
ATF_REQUIRE_MSG(chan != NULL, "cap_init failed: %s", strerror(errno));
98
99
for (i = 0; i < CHURN_CONNECTIONS; i++) {
100
clones[i] = cap_clone(chan);
101
ATF_REQUIRE_MSG(clones[i] != NULL,
102
"cap_clone failed at %zu: %s", i, strerror(errno));
103
}
104
105
/*
106
* Close every Nth clone.
107
*/
108
for (i = 0; i < CHURN_CONNECTIONS; i += CHURN_CLOSE_STEP) {
109
cap_close(clones[i]);
110
clones[i] = NULL;
111
}
112
113
/*
114
* Force a poll() cycle: the helper handles POLLIN on chan and
115
* POLLHUP on the closed clones in the same walk.
116
*/
117
extra = cap_clone(chan);
118
ATF_REQUIRE_MSG(extra != NULL, "cap_clone after churn failed: %s",
119
strerror(errno));
120
121
/* A surviving clone must still round-trip. */
122
survivor_idx = 1;
123
survivor = cap_clone(clones[survivor_idx]);
124
ATF_REQUIRE_MSG(survivor != NULL,
125
"cap_clone on survivor failed: %s", strerror(errno));
126
127
cap_close(survivor);
128
cap_close(extra);
129
for (i = 0; i < CHURN_CONNECTIONS; i++) {
130
if (clones[i] != NULL)
131
cap_close(clones[i]);
132
}
133
cap_close(chan);
134
}
135
136
ATF_TP_ADD_TCS(tp)
137
{
138
139
ATF_TP_ADD_TC(tp, many_connections);
140
ATF_TP_ADD_TC(tp, connection_churn);
141
return (atf_no_error());
142
}
143
144