Branch data Line data Source code
1 : : /* SPDX-License-Identifier: LGPL-2.1+ */
2 : :
3 : : #include <fcntl.h>
4 : : #include <poll.h>
5 : : #include <pthread.h>
6 : :
7 : : #include "sd-event.h"
8 : :
9 : : #include "fd-util.h"
10 : : #include "json.h"
11 : : #include "rm-rf.h"
12 : : #include "strv.h"
13 : : #include "tmpfile-util.h"
14 : : #include "user-util.h"
15 : : #include "varlink.h"
16 : :
17 : : /* Let's pick some high value, that is higher than the largest listen() backlog, but leaves enough room below
18 : : the typical RLIMIT_NOFILE value of 1024 so that we can process both sides of each socket in our
19 : : process. Or in other words: "OVERLOAD_CONNECTIONS * 2 + x < 1024" should hold, for some small x that
20 : : should cover any auxiliary fds, the listener server fds, stdin/stdout/stderr and whatever else. */
21 : : #define OVERLOAD_CONNECTIONS 333
22 : :
23 : : static int n_done = 0;
24 : : static int block_write_fd = -1;
25 : :
26 : 8 : static int method_something(Varlink *link, JsonVariant *parameters, VarlinkMethodFlags flags, void *userdata) {
27 : 8 : _cleanup_(json_variant_unrefp) JsonVariant *ret = NULL;
28 : : JsonVariant *a, *b;
29 : : intmax_t x, y;
30 : : int r;
31 : :
32 : 8 : a = json_variant_by_key(parameters, "a");
33 [ - + ]: 8 : if (!a)
34 : 0 : return varlink_error(link, "io.test.BadParameters", NULL);
35 : :
36 : 8 : x = json_variant_integer(a);
37 : :
38 : 8 : b = json_variant_by_key(parameters, "b");
39 [ - + ]: 8 : if (!b)
40 : 0 : return varlink_error(link, "io.test.BadParameters", NULL);
41 : :
42 : 8 : y = json_variant_integer(b);
43 : :
44 : 8 : r = json_build(&ret, JSON_BUILD_OBJECT(JSON_BUILD_PAIR("sum", JSON_BUILD_INTEGER(x + y))));
45 [ - + ]: 8 : if (r < 0)
46 : 0 : return r;
47 : :
48 : 8 : return varlink_reply(link, ret);
49 : : }
50 : :
51 : 4 : static int method_done(Varlink *link, JsonVariant *parameters, VarlinkMethodFlags flags, void *userdata) {
52 : :
53 [ + - ]: 4 : if (++n_done == 2)
54 : 4 : sd_event_exit(varlink_get_event(link), EXIT_FAILURE);
55 : :
56 : 4 : return 0;
57 : : }
58 : :
59 : 4 : static int reply(Varlink *link, JsonVariant *parameters, const char *error_id, VarlinkReplyFlags flags, void *userdata) {
60 : : JsonVariant *sum;
61 : :
62 : 4 : sum = json_variant_by_key(parameters, "sum");
63 : :
64 [ - + ]: 4 : assert_se(json_variant_integer(sum) == 7+22);
65 : :
66 [ - + ]: 4 : if (++n_done == 2)
67 : 0 : sd_event_exit(varlink_get_event(link), EXIT_FAILURE);
68 : :
69 : 4 : return 0;
70 : : }
71 : :
72 : 524 : static int on_connect(VarlinkServer *s, Varlink *link, void *userdata) {
73 : 524 : uid_t uid = UID_INVALID;
74 : :
75 [ - + ]: 524 : assert(s);
76 [ - + ]: 524 : assert(link);
77 : :
78 [ - + ]: 524 : assert_se(varlink_get_peer_uid(link, &uid) >= 0);
79 [ - + ]: 524 : assert_se(getuid() == uid);
80 : :
81 : 524 : return 0;
82 : : }
83 : :
84 : 4 : static int overload_reply(Varlink *link, JsonVariant *parameters, const char *error_id, VarlinkReplyFlags flags, void *userdata) {
85 : :
86 : : /* This method call reply should always be called with a disconnection, since the method call should
87 : : * be talking to an overloaded server */
88 : :
89 [ + - ]: 4 : log_debug("Over reply triggered with error: %s", strna(error_id));
90 [ - + ]: 4 : assert_se(streq(error_id, VARLINK_ERROR_DISCONNECTED));
91 : 4 : sd_event_exit(varlink_get_event(link), 0);
92 : :
93 : 4 : return 0;
94 : : }
95 : :
96 : 4 : static void flood_test(const char *address) {
97 : 4 : _cleanup_(varlink_flush_close_unrefp) Varlink *c = NULL;
98 : 4 : _cleanup_(sd_event_unrefp) sd_event *e = NULL;
99 : 4 : _cleanup_free_ Varlink **connections = NULL;
100 : : size_t k;
101 : 4 : char x = 'x';
102 : :
103 [ + - ]: 4 : log_debug("Flooding server...");
104 : :
105 : : /* Block the main event loop while we flood */
106 [ - + ]: 4 : assert_se(write(block_write_fd, &x, sizeof(x)) == sizeof(x));
107 : :
108 [ - + ]: 4 : assert_se(sd_event_default(&e) >= 0);
109 : :
110 : : /* Flood the server with connections */
111 [ - + ]: 4 : assert_se(connections = new0(Varlink*, OVERLOAD_CONNECTIONS));
112 [ + + ]: 1336 : for (k = 0; k < OVERLOAD_CONNECTIONS; k++) {
113 : 1332 : _cleanup_free_ char *t = NULL;
114 [ + - ]: 1332 : log_debug("connection %zu", k);
115 [ - + ]: 1332 : assert_se(varlink_connect_address(connections + k, address) >= 0);
116 : :
117 [ - + ]: 1332 : assert_se(asprintf(&t, "flood-%zu", k) >= 0);
118 [ - + ]: 1332 : assert_se(varlink_set_description(connections[k], t) >= 0);
119 [ - + ]: 1332 : assert_se(varlink_attach_event(connections[k], e, k) >= 0);
120 [ - + ]: 1332 : assert_se(varlink_sendb(connections[k], "io.test.Rubbish", JSON_BUILD_OBJECT(JSON_BUILD_PAIR("id", JSON_BUILD_INTEGER(k)))) >= 0);
121 : : }
122 : :
123 : : /* Then, create one more, which should fail */
124 [ + - ]: 4 : log_debug("Creating overload connection...");
125 [ - + ]: 4 : assert_se(varlink_connect_address(&c, address) >= 0);
126 [ - + ]: 4 : assert_se(varlink_set_description(c, "overload-client") >= 0);
127 [ - + ]: 4 : assert_se(varlink_attach_event(c, e, k) >= 0);
128 [ - + ]: 4 : assert_se(varlink_bind_reply(c, overload_reply) >= 0);
129 [ - + ]: 4 : assert_se(varlink_invokeb(c, "io.test.Overload", JSON_BUILD_OBJECT(JSON_BUILD_PAIR("foo", JSON_BUILD_STRING("bar")))) >= 0);
130 : :
131 : : /* Unblock it */
132 [ + - ]: 4 : log_debug("Unblocking server...");
133 : 4 : block_write_fd = safe_close(block_write_fd);
134 : :
135 : : /* This loop will terminate as soon as the overload reply callback is called */
136 [ - + ]: 4 : assert_se(sd_event_loop(e) >= 0);
137 : :
138 : : /* And close all connections again */
139 [ + + ]: 1336 : for (k = 0; k < OVERLOAD_CONNECTIONS; k++)
140 : 1332 : connections[k] = varlink_unref(connections[k]);
141 : 4 : }
142 : :
143 : 4 : static void *thread(void *arg) {
144 : 4 : _cleanup_(varlink_flush_close_unrefp) Varlink *c = NULL;
145 : 8 : _cleanup_(json_variant_unrefp) JsonVariant *i = NULL;
146 : 4 : JsonVariant *o = NULL;
147 : : const char *e;
148 : :
149 [ - + ]: 4 : assert_se(json_build(&i, JSON_BUILD_OBJECT(JSON_BUILD_PAIR("a", JSON_BUILD_INTEGER(88)),
150 : : JSON_BUILD_PAIR("b", JSON_BUILD_INTEGER(99)))) >= 0);
151 : :
152 [ - + ]: 4 : assert_se(varlink_connect_address(&c, arg) >= 0);
153 [ - + ]: 4 : assert_se(varlink_set_description(c, "thread-client") >= 0);
154 : :
155 [ - + ]: 4 : assert_se(varlink_call(c, "io.test.DoSomething", i, &o, &e, NULL) >= 0);
156 [ - + ]: 4 : assert_se(json_variant_integer(json_variant_by_key(o, "sum")) == 88 + 99);
157 [ - + ]: 4 : assert_se(!e);
158 : :
159 [ - + ]: 4 : assert_se(varlink_callb(c, "io.test.IDontExist", &o, &e, NULL, JSON_BUILD_OBJECT(JSON_BUILD_PAIR("x", JSON_BUILD_REAL(5.5)))) >= 0);
160 [ - + ]: 4 : assert_se(streq_ptr(json_variant_string(json_variant_by_key(o, "method")), "io.test.IDontExist"));
161 [ - + ]: 4 : assert_se(streq(e, VARLINK_ERROR_METHOD_NOT_FOUND));
162 : :
163 : 4 : flood_test(arg);
164 : :
165 [ - + ]: 4 : assert_se(varlink_send(c, "io.test.Done", NULL) >= 0);
166 : :
167 : 4 : return NULL;
168 : : }
169 : :
170 : 4 : static int block_fd_handler(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
171 : : char c;
172 : :
173 [ - + ]: 4 : assert_se(fd_nonblock(fd, false) >= 0);
174 : :
175 [ - + ]: 4 : assert_se(read(fd, &c, sizeof(c)) == sizeof(c));
176 : : /* When a character is written to this pipe we'll block until the pipe is closed. */
177 : :
178 [ - + ]: 4 : assert_se(read(fd, &c, sizeof(c)) == 0);
179 : :
180 [ - + ]: 4 : assert_se(fd_nonblock(fd, true) >= 0);
181 : :
182 [ - + ]: 4 : assert_se(sd_event_source_set_enabled(s, SD_EVENT_OFF) >= 0);
183 : :
184 : 4 : return 0;
185 : : }
186 : :
187 : 4 : int main(int argc, char *argv[]) {
188 : 4 : _cleanup_(sd_event_source_unrefp) sd_event_source *block_event = NULL;
189 : 4 : _cleanup_(varlink_server_unrefp) VarlinkServer *s = NULL;
190 : 4 : _cleanup_(varlink_flush_close_unrefp) Varlink *c = NULL;
191 : 4 : _cleanup_(rm_rf_physical_and_freep) char *tmpdir = NULL;
192 : 4 : _cleanup_(json_variant_unrefp) JsonVariant *v = NULL;
193 : 4 : _cleanup_(sd_event_unrefp) sd_event *e = NULL;
194 : 8 : _cleanup_(close_pairp) int block_fds[2] = { -1, -1 };
195 : : pthread_t t;
196 : : const char *sp;
197 : :
198 : 4 : log_set_max_level(LOG_DEBUG);
199 : 4 : log_open();
200 : :
201 [ - + ]: 4 : assert_se(mkdtemp_malloc("/tmp/varlink-test-XXXXXX", &tmpdir) >= 0);
202 [ + + + - : 20 : sp = strjoina(tmpdir, "/socket");
- + - + +
+ + - ]
203 : :
204 [ - + ]: 4 : assert_se(sd_event_default(&e) >= 0);
205 : :
206 [ - + ]: 4 : assert_se(pipe2(block_fds, O_NONBLOCK|O_CLOEXEC) >= 0);
207 [ - + ]: 4 : assert_se(sd_event_add_io(e, &block_event, block_fds[0], EPOLLIN, block_fd_handler, NULL) >= 0);
208 [ - + ]: 4 : assert_se(sd_event_source_set_priority(block_event, SD_EVENT_PRIORITY_IMPORTANT) >= 0);
209 : 4 : block_write_fd = TAKE_FD(block_fds[1]);
210 : :
211 [ - + ]: 4 : assert_se(varlink_server_new(&s, VARLINK_SERVER_ACCOUNT_UID) >= 0);
212 [ - + ]: 4 : assert_se(varlink_server_set_description(s, "our-server") >= 0);
213 : :
214 [ - + ]: 4 : assert_se(varlink_server_bind_method(s, "io.test.DoSomething", method_something) >= 0);
215 [ - + ]: 4 : assert_se(varlink_server_bind_method(s, "io.test.Done", method_done) >= 0);
216 [ - + ]: 4 : assert_se(varlink_server_bind_connect(s, on_connect) >= 0);
217 [ - + ]: 4 : assert_se(varlink_server_listen_address(s, sp, 0600) >= 0);
218 [ - + ]: 4 : assert_se(varlink_server_attach_event(s, e, 0) >= 0);
219 [ - + ]: 4 : assert_se(varlink_server_set_connections_max(s, OVERLOAD_CONNECTIONS) >= 0);
220 : :
221 [ - + ]: 4 : assert_se(varlink_connect_address(&c, sp) >= 0);
222 [ - + ]: 4 : assert_se(varlink_set_description(c, "main-client") >= 0);
223 [ - + ]: 4 : assert_se(varlink_bind_reply(c, reply) >= 0);
224 : :
225 [ - + ]: 4 : assert_se(json_build(&v, JSON_BUILD_OBJECT(JSON_BUILD_PAIR("a", JSON_BUILD_INTEGER(7)),
226 : : JSON_BUILD_PAIR("b", JSON_BUILD_INTEGER(22)))) >= 0);
227 : :
228 [ - + ]: 4 : assert_se(varlink_invoke(c, "io.test.DoSomething", v) >= 0);
229 : :
230 [ - + ]: 4 : assert_se(varlink_attach_event(c, e, 0) >= 0);
231 : :
232 [ - + ]: 4 : assert_se(pthread_create(&t, NULL, thread, (void*) sp) == 0);
233 : :
234 [ - + ]: 4 : assert_se(sd_event_loop(e) >= 0);
235 : :
236 [ - + ]: 4 : assert_se(pthread_join(t, NULL) == 0);
237 : :
238 : 4 : return 0;
239 : : }
|