1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
13 #include "tmpfile-util.h"
14 #include "user-util.h"
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
23 static int n_done
= 0;
24 static int block_write_fd
= -EBADF
;
26 static int method_something(Varlink
*link
, JsonVariant
*parameters
, VarlinkMethodFlags flags
, void *userdata
) {
27 _cleanup_(json_variant_unrefp
) JsonVariant
*ret
= NULL
;
32 a
= json_variant_by_key(parameters
, "a");
34 return varlink_error(link
, "io.test.BadParameters", NULL
);
36 x
= json_variant_integer(a
);
38 b
= json_variant_by_key(parameters
, "b");
40 return varlink_error(link
, "io.test.BadParameters", NULL
);
42 y
= json_variant_integer(b
);
44 r
= json_build(&ret
, JSON_BUILD_OBJECT(JSON_BUILD_PAIR("sum", JSON_BUILD_INTEGER(x
+ y
))));
48 return varlink_reply(link
, ret
);
51 static int method_done(Varlink
*link
, JsonVariant
*parameters
, VarlinkMethodFlags flags
, void *userdata
) {
54 sd_event_exit(varlink_get_event(link
), EXIT_FAILURE
);
59 static int reply(Varlink
*link
, JsonVariant
*parameters
, const char *error_id
, VarlinkReplyFlags flags
, void *userdata
) {
62 sum
= json_variant_by_key(parameters
, "sum");
64 assert_se(json_variant_integer(sum
) == 7+22);
67 sd_event_exit(varlink_get_event(link
), EXIT_FAILURE
);
72 static int on_connect(VarlinkServer
*s
, Varlink
*link
, void *userdata
) {
73 uid_t uid
= UID_INVALID
;
78 assert_se(varlink_get_peer_uid(link
, &uid
) >= 0);
79 assert_se(getuid() == uid
);
84 static int overload_reply(Varlink
*link
, JsonVariant
*parameters
, const char *error_id
, VarlinkReplyFlags flags
, void *userdata
) {
86 /* This method call reply should always be called with a disconnection, since the method call should
87 * be talking to an overloaded server */
89 log_debug("Over reply triggered with error: %s", strna(error_id
));
90 assert_se(streq(error_id
, VARLINK_ERROR_DISCONNECTED
));
91 sd_event_exit(varlink_get_event(link
), 0);
96 static void flood_test(const char *address
) {
97 _cleanup_(varlink_flush_close_unrefp
) Varlink
*c
= NULL
;
98 _cleanup_(sd_event_unrefp
) sd_event
*e
= NULL
;
99 _cleanup_free_ Varlink
**connections
= NULL
;
103 log_debug("Flooding server...");
105 /* Block the main event loop while we flood */
106 assert_se(write(block_write_fd
, &x
, sizeof(x
)) == sizeof(x
));
108 assert_se(sd_event_default(&e
) >= 0);
110 /* Flood the server with connections */
111 assert_se(connections
= new0(Varlink
*, OVERLOAD_CONNECTIONS
));
112 for (k
= 0; k
< OVERLOAD_CONNECTIONS
; k
++) {
113 _cleanup_free_
char *t
= NULL
;
114 log_debug("connection %zu", k
);
115 assert_se(varlink_connect_address(connections
+ k
, address
) >= 0);
117 assert_se(asprintf(&t
, "flood-%zu", k
) >= 0);
118 assert_se(varlink_set_description(connections
[k
], t
) >= 0);
119 assert_se(varlink_attach_event(connections
[k
], e
, k
) >= 0);
120 assert_se(varlink_sendb(connections
[k
], "io.test.Rubbish", JSON_BUILD_OBJECT(JSON_BUILD_PAIR("id", JSON_BUILD_INTEGER(k
)))) >= 0);
123 /* Then, create one more, which should fail */
124 log_debug("Creating overload connection...");
125 assert_se(varlink_connect_address(&c
, address
) >= 0);
126 assert_se(varlink_set_description(c
, "overload-client") >= 0);
127 assert_se(varlink_attach_event(c
, e
, k
) >= 0);
128 assert_se(varlink_bind_reply(c
, overload_reply
) >= 0);
129 assert_se(varlink_invokeb(c
, "io.test.Overload", JSON_BUILD_OBJECT(JSON_BUILD_PAIR("foo", JSON_BUILD_CONST_STRING("bar")))) >= 0);
132 log_debug("Unblocking server...");
133 block_write_fd
= safe_close(block_write_fd
);
135 /* This loop will terminate as soon as the overload reply callback is called */
136 assert_se(sd_event_loop(e
) >= 0);
138 /* And close all connections again */
139 for (k
= 0; k
< OVERLOAD_CONNECTIONS
; k
++)
140 connections
[k
] = varlink_unref(connections
[k
]);
143 static void *thread(void *arg
) {
144 _cleanup_(varlink_flush_close_unrefp
) Varlink
*c
= NULL
;
145 _cleanup_(json_variant_unrefp
) JsonVariant
*i
= NULL
;
146 JsonVariant
*o
= NULL
;
149 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);
152 assert_se(varlink_connect_address(&c
, arg
) >= 0);
153 assert_se(varlink_set_description(c
, "thread-client") >= 0);
155 assert_se(varlink_call(c
, "io.test.DoSomething", i
, &o
, &e
, NULL
) >= 0);
156 assert_se(json_variant_integer(json_variant_by_key(o
, "sum")) == 88 + 99);
159 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 assert_se(streq_ptr(json_variant_string(json_variant_by_key(o
, "method")), "io.test.IDontExist"));
161 assert_se(streq(e
, VARLINK_ERROR_METHOD_NOT_FOUND
));
165 assert_se(varlink_send(c
, "io.test.Done", NULL
) >= 0);
170 static int block_fd_handler(sd_event_source
*s
, int fd
, uint32_t revents
, void *userdata
) {
173 assert_se(fd_nonblock(fd
, false) >= 0);
175 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. */
178 assert_se(read(fd
, &c
, sizeof(c
)) == 0);
180 assert_se(fd_nonblock(fd
, true) >= 0);
182 assert_se(sd_event_source_set_enabled(s
, SD_EVENT_OFF
) >= 0);
187 int main(int argc
, char *argv
[]) {
188 _cleanup_(sd_event_source_unrefp
) sd_event_source
*block_event
= NULL
;
189 _cleanup_(varlink_server_unrefp
) VarlinkServer
*s
= NULL
;
190 _cleanup_(varlink_flush_close_unrefp
) Varlink
*c
= NULL
;
191 _cleanup_(rm_rf_physical_and_freep
) char *tmpdir
= NULL
;
192 _cleanup_(json_variant_unrefp
) JsonVariant
*v
= NULL
;
193 _cleanup_(sd_event_unrefp
) sd_event
*e
= NULL
;
194 _cleanup_(close_pairp
) int block_fds
[2] = { -1, -1 };
198 log_set_max_level(LOG_DEBUG
);
201 assert_se(mkdtemp_malloc("/tmp/varlink-test-XXXXXX", &tmpdir
) >= 0);
202 sp
= strjoina(tmpdir
, "/socket");
204 assert_se(sd_event_default(&e
) >= 0);
206 assert_se(pipe2(block_fds
, O_NONBLOCK
|O_CLOEXEC
) >= 0);
207 assert_se(sd_event_add_io(e
, &block_event
, block_fds
[0], EPOLLIN
, block_fd_handler
, NULL
) >= 0);
208 assert_se(sd_event_source_set_priority(block_event
, SD_EVENT_PRIORITY_IMPORTANT
) >= 0);
209 block_write_fd
= TAKE_FD(block_fds
[1]);
211 assert_se(varlink_server_new(&s
, VARLINK_SERVER_ACCOUNT_UID
) >= 0);
212 assert_se(varlink_server_set_description(s
, "our-server") >= 0);
214 assert_se(varlink_server_bind_method(s
, "io.test.DoSomething", method_something
) >= 0);
215 assert_se(varlink_server_bind_method(s
, "io.test.Done", method_done
) >= 0);
216 assert_se(varlink_server_bind_connect(s
, on_connect
) >= 0);
217 assert_se(varlink_server_listen_address(s
, sp
, 0600) >= 0);
218 assert_se(varlink_server_attach_event(s
, e
, 0) >= 0);
219 assert_se(varlink_server_set_connections_max(s
, OVERLOAD_CONNECTIONS
) >= 0);
221 assert_se(varlink_connect_address(&c
, sp
) >= 0);
222 assert_se(varlink_set_description(c
, "main-client") >= 0);
223 assert_se(varlink_bind_reply(c
, reply
) >= 0);
225 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);
228 assert_se(varlink_invoke(c
, "io.test.DoSomething", v
) >= 0);
230 assert_se(varlink_attach_event(c
, e
, 0) >= 0);
232 assert_se(pthread_create(&t
, NULL
, thread
, (void*) sp
) == 0);
234 assert_se(sd_event_loop(e
) >= 0);
236 assert_se(pthread_join(t
, NULL
) == 0);