1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
6 #include "pretty-print.h"
9 #include "varlink-idl.h"
10 #include "varlink-io.systemd.h"
11 #include "varlink-io.systemd.Credentials.h"
12 #include "varlink-io.systemd.Journal.h"
13 #include "varlink-io.systemd.ManagedOOM.h"
14 #include "varlink-io.systemd.PCRExtend.h"
15 #include "varlink-io.systemd.Resolve.Monitor.h"
16 #include "varlink-io.systemd.Resolve.h"
17 #include "varlink-io.systemd.UserDatabase.h"
18 #include "varlink-io.systemd.oom.h"
19 #include "varlink-io.systemd.service.h"
20 #include "varlink-io.systemd.sysext.h"
21 #include "varlink-org.varlink.service.h"
23 static VARLINK_DEFINE_ENUM_TYPE(
25 VARLINK_DEFINE_ENUM_VALUE(foo
),
26 VARLINK_DEFINE_ENUM_VALUE(bar
),
27 VARLINK_DEFINE_ENUM_VALUE(baz
));
29 static VARLINK_DEFINE_STRUCT_TYPE(
31 VARLINK_DEFINE_FIELD(x
, VARLINK_INT
, 0));
33 static VARLINK_DEFINE_STRUCT_TYPE(
36 VARLINK_DEFINE_FIELD(bbb
, VARLINK_BOOL
, 0),
37 VARLINK_DEFINE_FIELD(bbbn
, VARLINK_BOOL
, VARLINK_NULLABLE
),
38 VARLINK_DEFINE_FIELD(bbba
, VARLINK_BOOL
, VARLINK_ARRAY
),
39 VARLINK_DEFINE_FIELD(bbbna
, VARLINK_BOOL
, VARLINK_NULLABLE
|VARLINK_ARRAY
),
40 VARLINK_DEFINE_FIELD(bbbm
, VARLINK_BOOL
, VARLINK_MAP
),
41 VARLINK_DEFINE_FIELD(bbbnm
, VARLINK_BOOL
, VARLINK_NULLABLE
|VARLINK_MAP
),
43 VARLINK_DEFINE_FIELD(iii
, VARLINK_INT
, 0),
44 VARLINK_DEFINE_FIELD(iiin
, VARLINK_INT
, VARLINK_NULLABLE
),
45 VARLINK_DEFINE_FIELD(iiia
, VARLINK_INT
, VARLINK_ARRAY
),
46 VARLINK_DEFINE_FIELD(iiina
, VARLINK_INT
, VARLINK_NULLABLE
|VARLINK_ARRAY
),
47 VARLINK_DEFINE_FIELD(iiim
, VARLINK_INT
, VARLINK_MAP
),
48 VARLINK_DEFINE_FIELD(iiinm
, VARLINK_INT
, VARLINK_NULLABLE
|VARLINK_MAP
),
50 VARLINK_DEFINE_FIELD(fff
, VARLINK_FLOAT
, 0),
51 VARLINK_DEFINE_FIELD(fffn
, VARLINK_FLOAT
, VARLINK_NULLABLE
),
52 VARLINK_DEFINE_FIELD(fffa
, VARLINK_FLOAT
, VARLINK_ARRAY
),
53 VARLINK_DEFINE_FIELD(fffna
, VARLINK_FLOAT
, VARLINK_NULLABLE
|VARLINK_ARRAY
),
54 VARLINK_DEFINE_FIELD(fffm
, VARLINK_FLOAT
, VARLINK_MAP
),
55 VARLINK_DEFINE_FIELD(fffnm
, VARLINK_FLOAT
, VARLINK_NULLABLE
|VARLINK_MAP
),
57 VARLINK_DEFINE_FIELD(sss
, VARLINK_STRING
, 0),
58 VARLINK_DEFINE_FIELD(sssn
, VARLINK_STRING
, VARLINK_NULLABLE
),
59 VARLINK_DEFINE_FIELD(sssa
, VARLINK_STRING
, VARLINK_ARRAY
),
60 VARLINK_DEFINE_FIELD(sssna
, VARLINK_STRING
, VARLINK_NULLABLE
|VARLINK_ARRAY
),
61 VARLINK_DEFINE_FIELD(sssm
, VARLINK_STRING
, VARLINK_MAP
),
62 VARLINK_DEFINE_FIELD(sssnm
, VARLINK_STRING
, VARLINK_NULLABLE
|VARLINK_MAP
),
64 VARLINK_DEFINE_FIELD(ooo
, VARLINK_OBJECT
, 0),
65 VARLINK_DEFINE_FIELD(ooon
, VARLINK_OBJECT
, VARLINK_NULLABLE
),
66 VARLINK_DEFINE_FIELD(oooa
, VARLINK_OBJECT
, VARLINK_ARRAY
),
67 VARLINK_DEFINE_FIELD(ooona
, VARLINK_OBJECT
, VARLINK_NULLABLE
|VARLINK_ARRAY
),
68 VARLINK_DEFINE_FIELD(ooom
, VARLINK_OBJECT
, VARLINK_MAP
),
69 VARLINK_DEFINE_FIELD(ooonm
, VARLINK_OBJECT
, VARLINK_NULLABLE
|VARLINK_MAP
),
71 VARLINK_DEFINE_FIELD_BY_TYPE(eee
, EnumTest
, 0),
72 VARLINK_DEFINE_FIELD_BY_TYPE(eeen
, EnumTest
, VARLINK_NULLABLE
),
73 VARLINK_DEFINE_FIELD_BY_TYPE(eeea
, EnumTest
, VARLINK_ARRAY
),
74 VARLINK_DEFINE_FIELD_BY_TYPE(eeena
, EnumTest
, VARLINK_NULLABLE
|VARLINK_ARRAY
),
75 VARLINK_DEFINE_FIELD_BY_TYPE(eeem
, EnumTest
, VARLINK_MAP
),
76 VARLINK_DEFINE_FIELD_BY_TYPE(eeenm
, EnumTest
, VARLINK_NULLABLE
|VARLINK_MAP
),
78 VARLINK_DEFINE_FIELD_BY_TYPE(nnn
, NestedStructTest
, 0),
79 VARLINK_DEFINE_FIELD_BY_TYPE(nnnn
, NestedStructTest
, VARLINK_NULLABLE
),
80 VARLINK_DEFINE_FIELD_BY_TYPE(nnna
, NestedStructTest
, VARLINK_ARRAY
),
81 VARLINK_DEFINE_FIELD_BY_TYPE(nnnna
, NestedStructTest
, VARLINK_NULLABLE
|VARLINK_ARRAY
),
82 VARLINK_DEFINE_FIELD_BY_TYPE(nnnm
, NestedStructTest
, VARLINK_MAP
),
83 VARLINK_DEFINE_FIELD_BY_TYPE(nnnnm
, NestedStructTest
, VARLINK_NULLABLE
|VARLINK_MAP
));
85 static VARLINK_DEFINE_METHOD(
87 VARLINK_DEFINE_INPUT(x
, VARLINK_BOOL
, 0),
88 VARLINK_DEFINE_INPUT_BY_TYPE(y
, EnumTest
, 0),
89 VARLINK_DEFINE_INPUT_BY_TYPE(z
, StructTest
, 0),
90 VARLINK_DEFINE_OUTPUT(x
, VARLINK_BOOL
, 0),
91 VARLINK_DEFINE_OUTPUT_BY_TYPE(y
, EnumTest
, 0),
92 VARLINK_DEFINE_OUTPUT_BY_TYPE(z
, StructTest
, 0));
94 static VARLINK_DEFINE_ERROR(
96 VARLINK_DEFINE_FIELD(x
, VARLINK_BOOL
, 0),
97 VARLINK_DEFINE_FIELD_BY_TYPE(y
, EnumTest
, 0),
98 VARLINK_DEFINE_FIELD_BY_TYPE(z
, StructTest
, 0));
100 static VARLINK_DEFINE_INTERFACE(
104 &vl_type_NestedStructTest
,
106 &vl_method_MethodTest
,
107 &vl_error_ErrorTest
);
109 static void test_parse_format_one(const VarlinkInterface
*iface
) {
110 _cleanup_(varlink_interface_freep
) VarlinkInterface
*parsed
= NULL
;
111 _cleanup_free_
char *text
= NULL
, *text2
= NULL
;
115 assert_se(varlink_idl_dump(stdout
, /* use_colors=*/ true, iface
) >= 0);
116 assert_se(varlink_idl_consistent(iface
, LOG_ERR
) >= 0);
117 assert_se(varlink_idl_format(iface
, &text
) >= 0);
118 assert_se(varlink_idl_parse(text
, NULL
, NULL
, &parsed
) >= 0);
119 assert_se(varlink_idl_consistent(parsed
, LOG_ERR
) >= 0);
120 assert_se(varlink_idl_format(parsed
, &text2
) >= 0);
121 assert_se(streq(text
, text2
));
125 test_parse_format_one(&vl_interface_org_varlink_service
);
127 test_parse_format_one(&vl_interface_io_systemd_UserDatabase
);
129 test_parse_format_one(&vl_interface_io_systemd_Journal
);
131 test_parse_format_one(&vl_interface_io_systemd_Resolve
);
133 test_parse_format_one(&vl_interface_io_systemd_Resolve_Monitor
);
135 test_parse_format_one(&vl_interface_io_systemd_ManagedOOM
);
137 test_parse_format_one(&vl_interface_io_systemd_oom
);
139 test_parse_format_one(&vl_interface_io_systemd
);
141 test_parse_format_one(&vl_interface_io_systemd_PCRExtend
);
143 test_parse_format_one(&vl_interface_io_systemd_service
);
145 test_parse_format_one(&vl_interface_io_systemd_sysext
);
147 test_parse_format_one(&vl_interface_io_systemd_Credentials
);
149 test_parse_format_one(&vl_interface_xyz_test
);
153 _cleanup_(varlink_interface_freep
) VarlinkInterface
*parsed
= NULL
;
155 /* This one has (nested) enonymous enums and structs */
156 static const char text
[] =
157 "interface quu.waa\n"
158 "type Fooenum ( a, b, c )\n"
159 "type Barstruct ( a : (x, y, z), b : (x : int), c: (f, ff, fff), d: object, e : (sub : (subsub: (subsubsub: string, subsubsub2: (iii, ooo)))))"
162 assert_se(varlink_idl_parse(text
, NULL
, NULL
, &parsed
) >= 0);
163 test_parse_format_one(parsed
);
165 assert_se(varlink_idl_parse("interface org.freedesktop.Foo\n"
166 "type Foo (b: bool, c: foo, c: int)", NULL
, NULL
, NULL
) == -ENETUNREACH
); /* unresolved type */
167 assert_se(varlink_idl_parse("interface org.freedesktop.Foo\n"
168 "type Foo ()", NULL
, NULL
, NULL
) == -EBADMSG
); /* empty struct/enum */
172 TEST(interface_name_is_valid
) {
173 assert_se(!varlink_idl_interface_name_is_valid(NULL
));
174 assert_se(!varlink_idl_interface_name_is_valid(""));
175 assert_se(!varlink_idl_interface_name_is_valid(","));
176 assert_se(!varlink_idl_interface_name_is_valid("."));
177 assert_se(!varlink_idl_interface_name_is_valid("-"));
178 assert_se(varlink_idl_interface_name_is_valid("a"));
179 assert_se(varlink_idl_interface_name_is_valid("a.a"));
180 assert_se(!varlink_idl_interface_name_is_valid("-.a"));
181 assert_se(!varlink_idl_interface_name_is_valid("-a.a"));
182 assert_se(!varlink_idl_interface_name_is_valid("a-.a"));
183 assert_se(varlink_idl_interface_name_is_valid("a-a.a"));
184 assert_se(!varlink_idl_interface_name_is_valid("a-a.a-"));
185 assert_se(!varlink_idl_interface_name_is_valid("a-a.-a"));
186 assert_se(!varlink_idl_interface_name_is_valid("a-a.-"));
187 assert_se(varlink_idl_interface_name_is_valid("a-a.a-a"));
188 assert_se(varlink_idl_interface_name_is_valid("io.systemd.Foobar"));
191 TEST(symbol_name_is_valid
) {
192 assert_se(!varlink_idl_symbol_name_is_valid(NULL
));
193 assert_se(!varlink_idl_symbol_name_is_valid(""));
194 assert_se(!varlink_idl_symbol_name_is_valid("_"));
195 assert_se(!varlink_idl_symbol_name_is_valid("_foo"));
196 assert_se(varlink_idl_symbol_name_is_valid("Foofoo"));
197 assert_se(varlink_idl_symbol_name_is_valid("Foo"));
198 assert_se(varlink_idl_symbol_name_is_valid("Foo0"));
199 assert_se(!varlink_idl_symbol_name_is_valid("0Foo"));
200 assert_se(!varlink_idl_symbol_name_is_valid("foo"));
201 assert_se(varlink_idl_symbol_name_is_valid("Foo0foo"));
202 assert_se(!varlink_idl_symbol_name_is_valid("bool"));
203 assert_se(!varlink_idl_symbol_name_is_valid("int"));
204 assert_se(!varlink_idl_symbol_name_is_valid("float"));
205 assert_se(!varlink_idl_symbol_name_is_valid("string"));
206 assert_se(!varlink_idl_symbol_name_is_valid("object"));
209 TEST(field_name_is_valid
) {
210 assert_se(!varlink_idl_field_name_is_valid(NULL
));
211 assert_se(!varlink_idl_field_name_is_valid(""));
212 assert_se(!varlink_idl_field_name_is_valid("_"));
213 assert_se(!varlink_idl_field_name_is_valid("_foo"));
214 assert_se(!varlink_idl_field_name_is_valid("_foo_"));
215 assert_se(!varlink_idl_field_name_is_valid("foo_"));
216 assert_se(varlink_idl_field_name_is_valid("foo_foo"));
217 assert_se(varlink_idl_field_name_is_valid("f_o_o_f_o_o"));
218 assert_se(!varlink_idl_field_name_is_valid("foo__foo"));
219 assert_se(varlink_idl_field_name_is_valid("Foofoo"));
220 assert_se(varlink_idl_field_name_is_valid("Foo"));
221 assert_se(varlink_idl_field_name_is_valid("Foo0"));
222 assert_se(!varlink_idl_field_name_is_valid("0Foo"));
223 assert_se(varlink_idl_field_name_is_valid("foo"));
224 assert_se(varlink_idl_field_name_is_valid("Foo0foo"));
225 assert_se(varlink_idl_field_name_is_valid("foo0foo"));
228 TEST(validate_json
) {
230 _cleanup_(varlink_interface_freep
) VarlinkInterface
*parsed
= NULL
;
232 /* This one has (nested) enonymous enums and structs */
233 static const char text
[] =
234 "interface validate.test\n"
235 "method Mymethod ( a:string, b:int, c:?bool, d:[]int, e:?[string]bool, f:?(piff, paff), g:(f:float) ) -> ()\n";
237 assert_se(varlink_idl_parse(text
, NULL
, NULL
, &parsed
) >= 0);
238 test_parse_format_one(parsed
);
240 _cleanup_(json_variant_unrefp
) JsonVariant
*v
= NULL
;
242 assert_se(json_build(&v
, JSON_BUILD_OBJECT(
243 JSON_BUILD_PAIR("a", JSON_BUILD_STRING("x")),
244 JSON_BUILD_PAIR("b", JSON_BUILD_UNSIGNED(44)),
245 JSON_BUILD_PAIR("d", JSON_BUILD_ARRAY(JSON_BUILD_UNSIGNED(5), JSON_BUILD_UNSIGNED(7), JSON_BUILD_UNSIGNED(107))),
246 JSON_BUILD_PAIR("g", JSON_BUILD_OBJECT(JSON_BUILD_PAIR("f", JSON_BUILD_REAL(0.5f
)))))) >= 0);
248 json_variant_dump(v
, JSON_FORMAT_PRETTY_AUTO
|JSON_FORMAT_COLOR_AUTO
, stdout
, NULL
);
250 const VarlinkSymbol
* symbol
= ASSERT_PTR(varlink_idl_find_symbol(parsed
, VARLINK_METHOD
, "Mymethod"));
252 assert_se(varlink_idl_validate_method_call(symbol
, v
, NULL
) >= 0);
255 static int test_recursive_one(unsigned depth
) {
256 _cleanup_(varlink_interface_freep
) VarlinkInterface
*parsed
= NULL
;
257 _cleanup_free_
char *pre
= NULL
, *post
= NULL
, *text
= NULL
;
258 static const char header
[] =
259 "interface recursive.test\n"
262 /* Generate a chain of nested structures, i.e. a: (a: (... (int))...) */
263 pre
= strrep("a:(", depth
);
264 post
= strrep(")", depth
);
268 text
= strjoin(header
, pre
, "int", post
, ")");
272 return varlink_idl_parse(text
, NULL
, NULL
, &parsed
);
276 assert_se(test_recursive_one(32) >= 0);
277 assert_se(test_recursive_one(64) >= 0);
279 /* We should handle this gracefully without a stack overflow */
280 assert_se(test_recursive_one(65) < 0);
281 assert_se(test_recursive_one(20000) < 0 );
284 static int test_method(Varlink
*link
, JsonVariant
*parameters
, VarlinkMethodFlags flags
, void *userdata
) {
285 JsonVariant
*foo
= json_variant_by_key(parameters
, "foo"), *bar
= json_variant_by_key(parameters
, "bar");
287 return varlink_replyb(link
,
289 JSON_BUILD_PAIR_UNSIGNED("waldo", json_variant_unsigned(foo
) * json_variant_unsigned(bar
)),
290 JSON_BUILD_PAIR_UNSIGNED("quux", json_variant_unsigned(foo
) + json_variant_unsigned(bar
))));
293 static int done_method(Varlink
*link
, JsonVariant
*parameters
, VarlinkMethodFlags flags
, void *userdata
) {
294 assert_se(sd_event_exit(varlink_get_event(link
), 0) >= 0);
298 static VARLINK_DEFINE_METHOD(
300 VARLINK_DEFINE_INPUT(foo
, VARLINK_INT
, 0),
301 VARLINK_DEFINE_INPUT(bar
, VARLINK_INT
, 0),
302 VARLINK_DEFINE_INPUT(optional
, VARLINK_STRING
, VARLINK_NULLABLE
),
303 VARLINK_DEFINE_OUTPUT(waldo
, VARLINK_INT
, 0),
304 VARLINK_DEFINE_OUTPUT(quux
, VARLINK_INT
, 0));
306 static VARLINK_DEFINE_METHOD(Done
);
308 static VARLINK_DEFINE_INTERFACE(
311 &vl_method_TestMethod
,
315 static void* server_thread(void *userdata
) {
316 _cleanup_(varlink_server_unrefp
) VarlinkServer
*server
= NULL
;
317 _cleanup_(sd_event_unrefp
) sd_event
*event
= NULL
;
319 assert_se(varlink_server_new(&server
, 0) >= 0);
320 assert_se(varlink_server_add_interface(server
, &vl_interface_xyz
) >= 0);
321 assert_se(varlink_server_bind_method(server
, "xyz.TestMethod", test_method
) >= 0);
322 assert_se(varlink_server_bind_method(server
, "xyz.Done", done_method
) >= 0);
324 assert_se(sd_event_new(&event
) >= 0);
325 assert_se(varlink_server_attach_event(server
, event
, 0) >= 0);
327 assert_se(varlink_server_add_connection(server
, PTR_TO_FD(userdata
), NULL
) >= 0);
329 assert_se(sd_event_loop(event
) >= 0);
333 TEST(validate_method_call
) {
334 _cleanup_close_pair_
int fd
[2] = EBADF_PAIR
;
335 _cleanup_(varlink_unrefp
) Varlink
*v
= NULL
;
338 assert_se(socketpair(AF_UNIX
, SOCK_STREAM
|SOCK_CLOEXEC
|SOCK_NONBLOCK
, 0, fd
) >= 0);
339 assert_se(pthread_create(&t
, NULL
, server_thread
, FD_TO_PTR(TAKE_FD(fd
[1]))) == 0);
340 assert_se(varlink_connect_fd(&v
, TAKE_FD(fd
[0])) >= 0);
342 JsonVariant
*reply
= NULL
;
343 const char *error_id
= NULL
;
344 assert_se(varlink_callb(v
, "xyz.TestMethod", &reply
, &error_id
, NULL
,
346 JSON_BUILD_PAIR_UNSIGNED("foo", 8),
347 JSON_BUILD_PAIR_UNSIGNED("bar", 9))) >= 0);
349 _cleanup_(json_variant_unrefp
) JsonVariant
*expected_reply
= NULL
;
350 assert_se(json_build(&expected_reply
,
352 JSON_BUILD_PAIR_UNSIGNED("waldo", 8*9),
353 JSON_BUILD_PAIR_UNSIGNED("quux", 8+9))) >= 0);
355 assert_se(!error_id
);
357 json_variant_dump(reply
, JSON_FORMAT_PRETTY_AUTO
|JSON_FORMAT_COLOR_AUTO
, NULL
, NULL
);
358 json_variant_dump(expected_reply
, JSON_FORMAT_PRETTY_AUTO
|JSON_FORMAT_COLOR_AUTO
, NULL
, NULL
);
359 assert_se(json_variant_equal(reply
, expected_reply
));
361 assert_se(varlink_callb(v
, "xyz.TestMethod", &reply
, &error_id
, NULL
,
363 JSON_BUILD_PAIR_UNSIGNED("foo", 9),
364 JSON_BUILD_PAIR_UNSIGNED("bar", 8),
365 JSON_BUILD_PAIR_STRING("optional", "pfft"))) >= 0);
367 assert_se(!error_id
);
368 assert_se(json_variant_equal(reply
, expected_reply
));
370 assert_se(varlink_callb(v
, "xyz.TestMethod", &reply
, &error_id
, NULL
,
372 JSON_BUILD_PAIR_UNSIGNED("foo", 8),
373 JSON_BUILD_PAIR_UNSIGNED("bar", 9),
374 JSON_BUILD_PAIR_STRING("zzz", "pfft"))) >= 0);
375 assert_se(streq_ptr(error_id
, VARLINK_ERROR_INVALID_PARAMETER
));
377 assert_se(varlink_callb(v
, "xyz.TestMethod", &reply
, &error_id
, NULL
,
379 JSON_BUILD_PAIR_STRING("foo", "wuff"),
380 JSON_BUILD_PAIR_UNSIGNED("bar", 9))) >= 0);
381 assert_se(streq_ptr(error_id
, VARLINK_ERROR_INVALID_PARAMETER
));
383 assert_se(varlink_send(v
, "xyz.Done", NULL
) >= 0);
384 assert_se(varlink_flush(v
) >= 0);
385 assert_se(pthread_join(t
, NULL
) == 0);
388 DEFINE_TEST_MAIN(LOG_DEBUG
);