]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/libsystemd-bus/sd-bus.c
bus: calculate iovec for messages only when we need it
[thirdparty/systemd.git] / src / libsystemd-bus / sd-bus.c
CommitLineData
de1c301e
LP
1/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3/***
4 This file is part of systemd.
5
6 Copyright 2013 Lennart Poettering
7
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
12
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20***/
21
22#include <endian.h>
23#include <assert.h>
24#include <stdlib.h>
25#include <unistd.h>
26#include <netdb.h>
27#include <sys/poll.h>
28#include <byteswap.h>
29
30#include "util.h"
31#include "macro.h"
2fd9ae2e 32#include "strv.h"
0a72c2bd 33#include "set.h"
de1c301e
LP
34
35#include "sd-bus.h"
36#include "bus-internal.h"
37#include "bus-message.h"
38#include "bus-type.h"
a7e3212d 39#include "bus-socket.h"
392d5b37 40#include "bus-control.h"
de1c301e 41
e3017af9
LP
42static int bus_poll(sd_bus *bus, bool need_more, uint64_t timeout_usec);
43
de1c301e
LP
44static void bus_free(sd_bus *b) {
45 struct filter_callback *f;
a652755d 46 struct object_callback *c;
89ffcd2a 47 unsigned i;
de1c301e
LP
48
49 assert(b);
50
e82c9509 51 sd_bus_close(b);
de1c301e
LP
52
53 free(b->rbuffer);
89ffcd2a 54 free(b->unique_name);
2181a7f5 55 free(b->auth_buffer);
89ffcd2a
LP
56 free(b->address);
57
2fd9ae2e
LP
58 free(b->exec_path);
59 strv_free(b->exec_argv);
60
2c93b4ef
LP
61 close_many(b->fds, b->n_fds);
62 free(b->fds);
63
89ffcd2a
LP
64 for (i = 0; i < b->rqueue_size; i++)
65 sd_bus_message_unref(b->rqueue[i]);
de1c301e 66 free(b->rqueue);
89ffcd2a
LP
67
68 for (i = 0; i < b->wqueue_size; i++)
69 sd_bus_message_unref(b->wqueue[i]);
de1c301e 70 free(b->wqueue);
de1c301e
LP
71
72 hashmap_free_free(b->reply_callbacks);
e3017af9 73 prioq_free(b->reply_callbacks_prioq);
de1c301e
LP
74
75 while ((f = b->filter_callbacks)) {
76 LIST_REMOVE(struct filter_callback, callbacks, b->filter_callbacks, f);
77 free(f);
78 }
79
a652755d
LP
80 while ((c = hashmap_steal_first(b->object_callbacks))) {
81 free(c->path);
82 free(c);
83 }
84
85 hashmap_free(b->object_callbacks);
86
392d5b37
LP
87 bus_match_free(&b->match_callbacks);
88
de1c301e
LP
89 free(b);
90}
91
021a1e78 92int sd_bus_new(sd_bus **ret) {
de1c301e
LP
93 sd_bus *r;
94
021a1e78
LP
95 if (!ret)
96 return -EINVAL;
97
de1c301e
LP
98 r = new0(sd_bus, 1);
99 if (!r)
021a1e78 100 return -ENOMEM;
de1c301e
LP
101
102 r->n_ref = 1;
e82c9509 103 r->input_fd = r->output_fd = -1;
de1c301e 104 r->message_version = 1;
021a1e78 105 r->negotiate_fds = true;
de1c301e
LP
106
107 /* We guarantee that wqueue always has space for at least one
108 * entry */
109 r->wqueue = new(sd_bus_message*, 1);
110 if (!r->wqueue) {
111 free(r);
021a1e78 112 return -ENOMEM;
de1c301e
LP
113 }
114
021a1e78
LP
115 *ret = r;
116 return 0;
117}
118
119int sd_bus_set_address(sd_bus *bus, const char *address) {
120 char *a;
121
122 if (!bus)
123 return -EINVAL;
124 if (bus->state != BUS_UNSET)
125 return -EPERM;
126 if (!address)
127 return -EINVAL;
128
129 a = strdup(address);
130 if (!a)
131 return -ENOMEM;
132
133 free(bus->address);
134 bus->address = a;
135
136 return 0;
137}
138
e82c9509 139int sd_bus_set_fd(sd_bus *bus, int input_fd, int output_fd) {
021a1e78
LP
140 if (!bus)
141 return -EINVAL;
142 if (bus->state != BUS_UNSET)
143 return -EPERM;
e82c9509
LP
144 if (input_fd < 0)
145 return -EINVAL;
146 if (output_fd < 0)
021a1e78
LP
147 return -EINVAL;
148
e82c9509
LP
149 bus->input_fd = input_fd;
150 bus->output_fd = output_fd;
021a1e78
LP
151 return 0;
152}
153
2fd9ae2e
LP
154int sd_bus_set_exec(sd_bus *bus, const char *path, char *const argv[]) {
155 char *p, **a;
156
157 if (!bus)
158 return -EINVAL;
159 if (bus->state != BUS_UNSET)
160 return -EPERM;
161 if (!path)
162 return -EINVAL;
163 if (strv_isempty(argv))
164 return -EINVAL;
165
166 p = strdup(path);
167 if (!p)
168 return -ENOMEM;
169
170 a = strv_copy(argv);
171 if (!a) {
172 free(p);
173 return -ENOMEM;
174 }
175
176 free(bus->exec_path);
177 strv_free(bus->exec_argv);
178
179 bus->exec_path = p;
180 bus->exec_argv = a;
181
182 return 0;
183}
184
94bbf1ba 185int sd_bus_set_bus_client(sd_bus *bus, int b) {
021a1e78
LP
186 if (!bus)
187 return -EINVAL;
188 if (bus->state != BUS_UNSET)
189 return -EPERM;
190
94bbf1ba 191 bus->bus_client = !!b;
021a1e78
LP
192 return 0;
193}
194
195int sd_bus_set_negotiate_fds(sd_bus *bus, int b) {
196 if (!bus)
197 return -EINVAL;
198 if (bus->state != BUS_UNSET)
199 return -EPERM;
200
201 bus->negotiate_fds = !!b;
202 return 0;
203}
de1c301e 204
98178d39 205int sd_bus_set_server(sd_bus *bus, int b, sd_id128_t server_id) {
2181a7f5
LP
206 if (!bus)
207 return -EINVAL;
98178d39 208 if (!b && !sd_id128_equal(server_id, SD_ID128_NULL))
2181a7f5
LP
209 return -EINVAL;
210 if (bus->state != BUS_UNSET)
211 return -EPERM;
212
213 bus->is_server = !!b;
98178d39 214 bus->server_id = server_id;
2181a7f5
LP
215 return 0;
216}
217
218int sd_bus_set_anonymous(sd_bus *bus, int b) {
219 if (!bus)
220 return -EINVAL;
221 if (bus->state != BUS_UNSET)
222 return -EPERM;
223
224 bus->anonymous_auth = !!b;
225 return 0;
226}
227
e3017af9 228static int hello_callback(sd_bus *bus, int error, sd_bus_message *reply, void *userdata) {
de1c301e
LP
229 const char *s;
230 int r;
231
232 assert(bus);
021a1e78 233 assert(bus->state == BUS_HELLO);
e3017af9
LP
234
235 if (error != 0)
236 return -error;
237
de1c301e
LP
238 assert(reply);
239
de1c301e
LP
240 r = sd_bus_message_read(reply, "s", &s);
241 if (r < 0)
242 return r;
243
dafb7591
LP
244 if (!service_name_is_valid(s) || s[0] != ':')
245 return -EBADMSG;
246
de1c301e
LP
247 bus->unique_name = strdup(s);
248 if (!bus->unique_name)
249 return -ENOMEM;
250
dafb7591
LP
251 bus->state = BUS_RUNNING;
252
de1c301e
LP
253 return 1;
254}
255
256static int bus_send_hello(sd_bus *bus) {
257 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
258 int r;
259
260 assert(bus);
261
94bbf1ba 262 if (!bus->bus_client)
021a1e78
LP
263 return 0;
264
de1c301e
LP
265 r = sd_bus_message_new_method_call(
266 bus,
267 "org.freedesktop.DBus",
268 "/",
269 "org.freedesktop.DBus",
270 "Hello",
271 &m);
272 if (r < 0)
273 return r;
274
9d373862 275 return sd_bus_send_with_reply(bus, m, hello_callback, NULL, 0, &bus->hello_serial);
de1c301e
LP
276}
277
a7e3212d 278int bus_start_running(sd_bus *bus) {
de1c301e
LP
279 assert(bus);
280
94bbf1ba 281 if (bus->bus_client) {
de1c301e 282 bus->state = BUS_HELLO;
e3017af9 283 return 1;
de1c301e
LP
284 }
285
286 bus->state = BUS_RUNNING;
e3017af9 287 return 1;
de1c301e
LP
288}
289
290static int parse_address_key(const char **p, const char *key, char **value) {
291 size_t l, n = 0;
292 const char *a;
293 char *r = NULL;
294
295 assert(p);
296 assert(*p);
de1c301e
LP
297 assert(value);
298
2fd9ae2e
LP
299 if (key) {
300 l = strlen(key);
301 if (strncmp(*p, key, l) != 0)
302 return 0;
de1c301e 303
2fd9ae2e
LP
304 if ((*p)[l] != '=')
305 return 0;
de1c301e 306
2fd9ae2e
LP
307 if (*value)
308 return -EINVAL;
de1c301e 309
2fd9ae2e
LP
310 a = *p + l + 1;
311 } else
312 a = *p;
313
314 while (*a != ';' && *a != ',' && *a != 0) {
de1c301e
LP
315 char c, *t;
316
317 if (*a == '%') {
318 int x, y;
319
320 x = unhexchar(a[1]);
321 if (x < 0) {
322 free(r);
323 return x;
324 }
325
326 y = unhexchar(a[2]);
327 if (y < 0) {
328 free(r);
329 return y;
330 }
331
de1c301e 332 c = (char) ((x << 4) | y);
89ffcd2a
LP
333 a += 3;
334 } else {
de1c301e 335 c = *a;
89ffcd2a
LP
336 a++;
337 }
de1c301e 338
89ffcd2a 339 t = realloc(r, n + 2);
de1c301e
LP
340 if (!t) {
341 free(r);
342 return -ENOMEM;
343 }
344
345 r = t;
346 r[n++] = c;
347 }
348
89ffcd2a
LP
349 if (!r) {
350 r = strdup("");
351 if (!r)
352 return -ENOMEM;
353 } else
354 r[n] = 0;
355
356 if (*a == ',')
357 a++;
358
de1c301e 359 *p = a;
2fd9ae2e
LP
360
361 free(*value);
de1c301e 362 *value = r;
2fd9ae2e 363
de1c301e
LP
364 return 1;
365}
366
367static void skip_address_key(const char **p) {
368 assert(p);
369 assert(*p);
370
89ffcd2a
LP
371 *p += strcspn(*p, ",");
372
373 if (**p == ',')
374 (*p) ++;
de1c301e
LP
375}
376
2fd9ae2e
LP
377static int parse_unix_address(sd_bus *b, const char **p, char **guid) {
378 _cleanup_free_ char *path = NULL, *abstract = NULL;
379 size_t l;
de1c301e
LP
380 int r;
381
382 assert(b);
2fd9ae2e
LP
383 assert(p);
384 assert(*p);
385 assert(guid);
de1c301e 386
2fd9ae2e
LP
387 while (**p != 0 && **p != ';') {
388 r = parse_address_key(p, "guid", guid);
389 if (r < 0)
390 return r;
391 else if (r > 0)
392 continue;
de1c301e 393
2fd9ae2e
LP
394 r = parse_address_key(p, "path", &path);
395 if (r < 0)
396 return r;
397 else if (r > 0)
398 continue;
de1c301e 399
2fd9ae2e
LP
400 r = parse_address_key(p, "abstract", &abstract);
401 if (r < 0)
402 return r;
403 else if (r > 0)
404 continue;
de1c301e 405
2fd9ae2e
LP
406 skip_address_key(p);
407 }
de1c301e 408
2fd9ae2e
LP
409 if (!path && !abstract)
410 return -EINVAL;
de1c301e 411
2fd9ae2e
LP
412 if (path && abstract)
413 return -EINVAL;
414
415 if (path) {
416 l = strlen(path);
417 if (l > sizeof(b->sockaddr.un.sun_path))
418 return -E2BIG;
de1c301e 419
2fd9ae2e
LP
420 b->sockaddr.un.sun_family = AF_UNIX;
421 strncpy(b->sockaddr.un.sun_path, path, sizeof(b->sockaddr.un.sun_path));
422 b->sockaddr_size = offsetof(struct sockaddr_un, sun_path) + l;
423 } else if (abstract) {
424 l = strlen(abstract);
425 if (l > sizeof(b->sockaddr.un.sun_path) - 1)
426 return -E2BIG;
427
428 b->sockaddr.un.sun_family = AF_UNIX;
429 b->sockaddr.un.sun_path[0] = 0;
430 strncpy(b->sockaddr.un.sun_path+1, abstract, sizeof(b->sockaddr.un.sun_path)-1);
431 b->sockaddr_size = offsetof(struct sockaddr_un, sun_path) + 1 + l;
432 }
433
434 return 0;
435}
436
437static int parse_tcp_address(sd_bus *b, const char **p, char **guid) {
438 _cleanup_free_ char *host = NULL, *port = NULL, *family = NULL;
2fd9ae2e 439 int r;
b92bea5d
ZJS
440 struct addrinfo *result, hints = {
441 .ai_socktype = SOCK_STREAM,
442 .ai_flags = AI_ADDRCONFIG,
443 };
2fd9ae2e
LP
444
445 assert(b);
446 assert(p);
447 assert(*p);
448 assert(guid);
449
450 while (**p != 0 && **p != ';') {
451 r = parse_address_key(p, "guid", guid);
452 if (r < 0)
453 return r;
454 else if (r > 0)
455 continue;
456
457 r = parse_address_key(p, "host", &host);
458 if (r < 0)
459 return r;
460 else if (r > 0)
461 continue;
462
463 r = parse_address_key(p, "port", &port);
464 if (r < 0)
465 return r;
466 else if (r > 0)
467 continue;
468
469 r = parse_address_key(p, "family", &family);
470 if (r < 0)
471 return r;
472 else if (r > 0)
473 continue;
474
475 skip_address_key(p);
476 }
477
478 if (!host || !port)
479 return -EINVAL;
480
2fd9ae2e
LP
481 if (family) {
482 if (streq(family, "ipv4"))
483 hints.ai_family = AF_INET;
484 else if (streq(family, "ipv6"))
485 hints.ai_family = AF_INET6;
486 else
487 return -EINVAL;
488 }
489
490 r = getaddrinfo(host, port, &hints, &result);
491 if (r == EAI_SYSTEM)
492 return -errno;
493 else if (r != 0)
494 return -EADDRNOTAVAIL;
495
496 memcpy(&b->sockaddr, result->ai_addr, result->ai_addrlen);
497 b->sockaddr_size = result->ai_addrlen;
498
499 freeaddrinfo(result);
500
501 return 0;
502}
503
504static int parse_exec_address(sd_bus *b, const char **p, char **guid) {
505 char *path = NULL;
506 unsigned n_argv = 0, j;
507 char **argv = NULL;
508 int r;
509
510 assert(b);
511 assert(p);
512 assert(*p);
513 assert(guid);
514
515 while (**p != 0 && **p != ';') {
516 r = parse_address_key(p, "guid", guid);
517 if (r < 0)
518 goto fail;
519 else if (r > 0)
520 continue;
521
522 r = parse_address_key(p, "path", &path);
523 if (r < 0)
524 goto fail;
525 else if (r > 0)
526 continue;
527
528 if (startswith(*p, "argv")) {
529 unsigned ul;
530
531 errno = 0;
532 ul = strtoul(*p + 4, (char**) p, 10);
8333c77e 533 if (errno > 0 || **p != '=' || ul > 256) {
2fd9ae2e
LP
534 r = -EINVAL;
535 goto fail;
536 }
537
538 (*p) ++;
539
540 if (ul >= n_argv) {
541 char **x;
542
543 x = realloc(argv, sizeof(char*) * (ul + 2));
544 if (!x) {
545 r = -ENOMEM;
546 goto fail;
547 }
548
549 memset(x + n_argv, 0, sizeof(char*) * (ul - n_argv + 2));
550
551 argv = x;
552 n_argv = ul + 1;
553 }
554
555 r = parse_address_key(p, NULL, argv + ul);
de1c301e 556 if (r < 0)
2fd9ae2e 557 goto fail;
de1c301e 558
2fd9ae2e 559 continue;
de1c301e
LP
560 }
561
2fd9ae2e
LP
562 skip_address_key(p);
563 }
de1c301e 564
5a0f6033
LP
565 if (!path) {
566 r = -EINVAL;
2fd9ae2e 567 goto fail;
5a0f6033 568 }
de1c301e 569
2fd9ae2e
LP
570 /* Make sure there are no holes in the array, with the
571 * exception of argv[0] */
572 for (j = 1; j < n_argv; j++)
573 if (!argv[j]) {
574 r = -EINVAL;
575 goto fail;
576 }
577
578 if (argv && argv[0] == NULL) {
579 argv[0] = strdup(path);
580 if (!argv[0]) {
581 r = -ENOMEM;
582 goto fail;
583 }
584 }
de1c301e 585
2fd9ae2e
LP
586 b->exec_path = path;
587 b->exec_argv = argv;
588 return 0;
de1c301e 589
2fd9ae2e
LP
590fail:
591 for (j = 0; j < n_argv; j++)
592 free(argv[j]);
593
594 free(argv);
595 free(path);
596 return r;
597}
598
599static void bus_reset_parsed_address(sd_bus *b) {
600 assert(b);
601
602 zero(b->sockaddr);
603 b->sockaddr_size = 0;
604 strv_free(b->exec_argv);
605 free(b->exec_path);
606 b->exec_path = NULL;
607 b->exec_argv = NULL;
98178d39 608 b->server_id = SD_ID128_NULL;
2fd9ae2e
LP
609}
610
611static int bus_parse_next_address(sd_bus *b) {
612 _cleanup_free_ char *guid = NULL;
613 const char *a;
614 int r;
615
616 assert(b);
617
618 if (!b->address)
619 return 0;
620 if (b->address[b->address_index] == 0)
621 return 0;
622
623 bus_reset_parsed_address(b);
624
625 a = b->address + b->address_index;
de1c301e 626
2fd9ae2e 627 while (*a != 0) {
de1c301e 628
2fd9ae2e
LP
629 if (*a == ';') {
630 a++;
631 continue;
de1c301e
LP
632 }
633
2fd9ae2e
LP
634 if (startswith(a, "unix:")) {
635 a += 5;
de1c301e 636
2fd9ae2e 637 r = parse_unix_address(b, &a, &guid);
de1c301e
LP
638 if (r < 0)
639 return r;
2fd9ae2e 640 break;
de1c301e 641
2fd9ae2e 642 } else if (startswith(a, "tcp:")) {
de1c301e 643
2fd9ae2e
LP
644 a += 4;
645 r = parse_tcp_address(b, &a, &guid);
de1c301e
LP
646 if (r < 0)
647 return r;
de1c301e 648
2fd9ae2e
LP
649 break;
650
651 } else if (startswith(a, "unixexec:")) {
652
653 a += 9;
654 r = parse_exec_address(b, &a, &guid);
de1c301e
LP
655 if (r < 0)
656 return r;
de1c301e 657
2fd9ae2e 658 break;
de1c301e 659
de1c301e
LP
660 }
661
2fd9ae2e
LP
662 a = strchr(a, ';');
663 if (!a)
664 return 0;
de1c301e
LP
665 }
666
667 if (guid) {
98178d39 668 r = sd_id128_from_string(guid, &b->server_id);
de1c301e
LP
669 if (r < 0)
670 return r;
671 }
672
2fd9ae2e 673 b->address_index = a - b->address;
de1c301e
LP
674 return 1;
675}
676
a7e3212d 677static int bus_start_address(sd_bus *b) {
2fd9ae2e
LP
678 int r;
679
680 assert(b);
681
682 for (;;) {
e82c9509 683 sd_bus_close(b);
2fd9ae2e
LP
684
685 if (b->sockaddr.sa.sa_family != AF_UNSPEC) {
a7e3212d
LP
686
687 r = bus_socket_connect(b);
2fd9ae2e
LP
688 if (r >= 0)
689 return r;
690
691 b->last_connect_error = -r;
692
693 } else if (b->exec_path) {
694
a7e3212d 695 r = bus_socket_exec(b);
2fd9ae2e
LP
696 if (r >= 0)
697 return r;
698
699 b->last_connect_error = -r;
700 }
701
702 r = bus_parse_next_address(b);
703 if (r < 0)
704 return r;
705 if (r == 0)
706 return b->last_connect_error ? -b->last_connect_error : -ECONNREFUSED;
de1c301e
LP
707 }
708}
709
a7e3212d
LP
710int bus_next_address(sd_bus *b) {
711 assert(b);
712
713 bus_reset_parsed_address(b);
714 return bus_start_address(b);
715}
716
021a1e78
LP
717static int bus_start_fd(sd_bus *b) {
718 int r;
719
720 assert(b);
e82c9509
LP
721 assert(b->input_fd >= 0);
722 assert(b->output_fd >= 0);
021a1e78 723
e82c9509 724 r = fd_nonblock(b->input_fd, true);
021a1e78
LP
725 if (r < 0)
726 return r;
727
e82c9509 728 r = fd_cloexec(b->input_fd, true);
021a1e78
LP
729 if (r < 0)
730 return r;
731
e82c9509
LP
732 if (b->input_fd != b->output_fd) {
733 r = fd_nonblock(b->output_fd, true);
734 if (r < 0)
735 return r;
736
737 r = fd_cloexec(b->output_fd, true);
738 if (r < 0)
739 return r;
740 }
741
a7e3212d 742 return bus_socket_take_fd(b);
021a1e78
LP
743}
744
745int sd_bus_start(sd_bus *bus) {
746 int r;
747
748 if (!bus)
749 return -EINVAL;
750 if (bus->state != BUS_UNSET)
751 return -EPERM;
752
753 bus->state = BUS_OPENING;
754
2181a7f5
LP
755 if (bus->is_server && bus->bus_client)
756 return -EINVAL;
757
e82c9509 758 if (bus->input_fd >= 0)
021a1e78 759 r = bus_start_fd(bus);
3d339fec 760 else if (bus->address || bus->sockaddr.sa.sa_family != AF_UNSPEC || bus->exec_path)
a7e3212d 761 r = bus_start_address(bus);
021a1e78
LP
762 else
763 return -EINVAL;
764
765 if (r < 0)
766 return r;
767
768 return bus_send_hello(bus);
769}
770
de1c301e
LP
771int sd_bus_open_system(sd_bus **ret) {
772 const char *e;
773 sd_bus *b;
774 int r;
775
776 if (!ret)
777 return -EINVAL;
778
021a1e78
LP
779 r = sd_bus_new(&b);
780 if (r < 0)
781 return r;
782
de1c301e
LP
783 e = getenv("DBUS_SYSTEM_BUS_ADDRESS");
784 if (e) {
021a1e78 785 r = sd_bus_set_address(b, e);
de1c301e 786 if (r < 0)
021a1e78 787 goto fail;
89ffcd2a 788 } else {
89ffcd2a
LP
789 b->sockaddr.un.sun_family = AF_UNIX;
790 strncpy(b->sockaddr.un.sun_path, "/run/dbus/system_bus_socket", sizeof(b->sockaddr.un.sun_path));
791 b->sockaddr_size = offsetof(struct sockaddr_un, sun_path) + sizeof("/run/dbus/system_bus_socket") - 1;
89ffcd2a 792 }
de1c301e 793
94bbf1ba 794 b->bus_client = true;
021a1e78
LP
795
796 r = sd_bus_start(b);
797 if (r < 0)
798 goto fail;
de1c301e
LP
799
800 *ret = b;
801 return 0;
021a1e78
LP
802
803fail:
804 bus_free(b);
805 return r;
de1c301e
LP
806}
807
808int sd_bus_open_user(sd_bus **ret) {
809 const char *e;
810 sd_bus *b;
811 size_t l;
812 int r;
813
814 if (!ret)
815 return -EINVAL;
816
021a1e78
LP
817 r = sd_bus_new(&b);
818 if (r < 0)
819 return r;
820
de1c301e
LP
821 e = getenv("DBUS_SESSION_BUS_ADDRESS");
822 if (e) {
021a1e78 823 r = sd_bus_set_address(b, e);
de1c301e 824 if (r < 0)
021a1e78 825 goto fail;
89ffcd2a
LP
826 } else {
827 e = getenv("XDG_RUNTIME_DIR");
021a1e78
LP
828 if (!e) {
829 r = -ENOENT;
830 goto fail;
831 }
de1c301e 832
89ffcd2a 833 l = strlen(e);
021a1e78
LP
834 if (l + 4 > sizeof(b->sockaddr.un.sun_path)) {
835 r = -E2BIG;
836 goto fail;
837 }
de1c301e 838
89ffcd2a
LP
839 b->sockaddr.un.sun_family = AF_UNIX;
840 memcpy(mempcpy(b->sockaddr.un.sun_path, e, l), "/bus", 4);
841 b->sockaddr_size = offsetof(struct sockaddr_un, sun_path) + l + 4;
de1c301e
LP
842 }
843
94bbf1ba 844 b->bus_client = true;
de1c301e 845
021a1e78 846 r = sd_bus_start(b);
2571ead1
LP
847 if (r < 0)
848 goto fail;
de1c301e
LP
849
850 *ret = b;
851 return 0;
2571ead1
LP
852
853fail:
021a1e78 854 bus_free(b);
2571ead1 855 return r;
de1c301e
LP
856}
857
858void sd_bus_close(sd_bus *bus) {
859 if (!bus)
860 return;
de1c301e 861
e82c9509
LP
862 if (bus->input_fd >= 0)
863 close_nointr_nofail(bus->input_fd);
864 if (bus->output_fd >= 0 && bus->output_fd != bus->input_fd)
865 close_nointr_nofail(bus->output_fd);
866
867 bus->input_fd = bus->output_fd = -1;
de1c301e
LP
868}
869
870sd_bus *sd_bus_ref(sd_bus *bus) {
871 if (!bus)
872 return NULL;
873
874 assert(bus->n_ref > 0);
875
876 bus->n_ref++;
877 return bus;
878}
879
880sd_bus *sd_bus_unref(sd_bus *bus) {
881 if (!bus)
882 return NULL;
883
884 assert(bus->n_ref > 0);
885 bus->n_ref--;
886
887 if (bus->n_ref <= 0)
888 bus_free(bus);
889
890 return NULL;
891}
892
e3017af9
LP
893int sd_bus_is_open(sd_bus *bus) {
894 if (!bus)
895 return -EINVAL;
896
e82c9509 897 return bus->state != BUS_UNSET && bus->input_fd >= 0;
e3017af9
LP
898}
899
d728d708
LP
900int sd_bus_can_send(sd_bus *bus, char type) {
901 int r;
902
de1c301e
LP
903 if (!bus)
904 return -EINVAL;
e82c9509 905 if (bus->output_fd < 0)
021a1e78 906 return -ENOTCONN;
de1c301e 907
d728d708 908 if (type == SD_BUS_TYPE_UNIX_FD) {
021a1e78
LP
909 if (!bus->negotiate_fds)
910 return 0;
911
20902f3e 912 r = bus_ensure_running(bus);
d728d708
LP
913 if (r < 0)
914 return r;
de1c301e 915
d728d708
LP
916 return bus->can_fds;
917 }
918
919 return bus_type_is_valid(type);
de1c301e
LP
920}
921
98178d39 922int sd_bus_get_server_id(sd_bus *bus, sd_id128_t *server_id) {
d728d708 923 int r;
de1c301e
LP
924
925 if (!bus)
926 return -EINVAL;
98178d39 927 if (!server_id)
d728d708 928 return -EINVAL;
de1c301e 929
20902f3e 930 r = bus_ensure_running(bus);
d728d708
LP
931 if (r < 0)
932 return r;
de1c301e 933
98178d39 934 *server_id = bus->server_id;
d728d708 935 return 0;
de1c301e
LP
936}
937
938static int bus_seal_message(sd_bus *b, sd_bus_message *m) {
939 assert(m);
940
89ffcd2a
LP
941 if (m->header->version > b->message_version)
942 return -EPERM;
943
de1c301e
LP
944 if (m->sealed)
945 return 0;
946
9a17484d 947 return bus_message_seal(m, ++b->serial);
de1c301e
LP
948}
949
de1c301e 950static int dispatch_wqueue(sd_bus *bus) {
e3017af9 951 int r, ret = 0;
de1c301e
LP
952
953 assert(bus);
89ffcd2a 954 assert(bus->state == BUS_RUNNING || bus->state == BUS_HELLO);
de1c301e 955
e82c9509 956 if (bus->output_fd < 0)
de1c301e
LP
957 return -ENOTCONN;
958
959 while (bus->wqueue_size > 0) {
960
a7e3212d 961 r = bus_socket_write_message(bus, bus->wqueue[0], &bus->windex);
de1c301e
LP
962 if (r < 0) {
963 sd_bus_close(bus);
964 return r;
965 } else if (r == 0)
e3017af9
LP
966 /* Didn't do anything this time */
967 return ret;
2100fa10 968 else if (bus->windex >= bus_message_size(bus->wqueue[0])) {
de1c301e
LP
969 /* Fully written. Let's drop the entry from
970 * the queue.
971 *
972 * This isn't particularly optimized, but
973 * well, this is supposed to be our worst-case
974 * buffer only, and the socket buffer is
975 * supposed to be our primary buffer, and if
976 * it got full, then all bets are off
977 * anyway. */
978
979 sd_bus_message_unref(bus->wqueue[0]);
980 bus->wqueue_size --;
981 memmove(bus->wqueue, bus->wqueue + 1, sizeof(sd_bus_message*) * bus->wqueue_size);
982 bus->windex = 0;
983
e3017af9 984 ret = 1;
de1c301e
LP
985 }
986 }
987
e3017af9 988 return ret;
de1c301e
LP
989}
990
991static int dispatch_rqueue(sd_bus *bus, sd_bus_message **m) {
2bf938c1 992 sd_bus_message *z = NULL;
e3017af9 993 int r, ret = 0;
de1c301e
LP
994
995 assert(bus);
996 assert(m);
89ffcd2a 997 assert(bus->state == BUS_RUNNING || bus->state == BUS_HELLO);
de1c301e 998
e82c9509 999 if (bus->input_fd < 0)
de1c301e
LP
1000 return -ENOTCONN;
1001
1002 if (bus->rqueue_size > 0) {
1003 /* Dispatch a queued message */
1004
1005 *m = bus->rqueue[0];
1006 bus->rqueue_size --;
1007 memmove(bus->rqueue, bus->rqueue + 1, sizeof(sd_bus_message*) * bus->rqueue_size);
1008 return 1;
1009 }
1010
1011 /* Try to read a new message */
e3017af9 1012 do {
a7e3212d 1013 r = bus_socket_read_message(bus, &z);
e3017af9
LP
1014 if (r < 0) {
1015 sd_bus_close(bus);
1016 return r;
1017 }
1018 if (r == 0)
1019 return ret;
de1c301e 1020
e3017af9
LP
1021 r = 1;
1022 } while (!z);
1023
1024 *m = z;
1025 return 1;
de1c301e
LP
1026}
1027
1028int sd_bus_send(sd_bus *bus, sd_bus_message *m, uint64_t *serial) {
1029 int r;
1030
1031 if (!bus)
1032 return -EINVAL;
021a1e78
LP
1033 if (bus->state == BUS_UNSET)
1034 return -ENOTCONN;
e82c9509 1035 if (bus->output_fd < 0)
de1c301e
LP
1036 return -ENOTCONN;
1037 if (!m)
1038 return -EINVAL;
021a1e78
LP
1039
1040 if (m->n_fds > 0) {
1041 r = sd_bus_can_send(bus, SD_BUS_TYPE_UNIX_FD);
1042 if (r < 0)
1043 return r;
1044 if (r == 0)
1045 return -ENOTSUP;
1046 }
de1c301e 1047
29f6aadd
LP
1048 /* If the serial number isn't kept, then we know that no reply
1049 * is expected */
1050 if (!serial && !m->sealed)
1051 m->header->flags |= SD_BUS_MESSAGE_NO_REPLY_EXPECTED;
1052
de1c301e
LP
1053 r = bus_seal_message(bus, m);
1054 if (r < 0)
1055 return r;
1056
5407f2de
LP
1057 /* If this is a reply and no reply was requested, then let's
1058 * suppress this, if we can */
1059 if (m->dont_send && !serial)
1060 return 0;
1061
89ffcd2a 1062 if ((bus->state == BUS_RUNNING || bus->state == BUS_HELLO) && bus->wqueue_size <= 0) {
de1c301e
LP
1063 size_t idx = 0;
1064
a7e3212d 1065 r = bus_socket_write_message(bus, m, &idx);
de1c301e
LP
1066 if (r < 0) {
1067 sd_bus_close(bus);
1068 return r;
2100fa10 1069 } else if (idx < bus_message_size(m)) {
de1c301e
LP
1070 /* Wasn't fully written. So let's remember how
1071 * much was written. Note that the first entry
1072 * of the wqueue array is always allocated so
1073 * that we always can remember how much was
1074 * written. */
1075 bus->wqueue[0] = sd_bus_message_ref(m);
1076 bus->wqueue_size = 1;
1077 bus->windex = idx;
1078 }
1079 } else {
1080 sd_bus_message **q;
1081
1082 /* Just append it to the queue. */
1083
25220239 1084 if (bus->wqueue_size >= BUS_WQUEUE_MAX)
de1c301e
LP
1085 return -ENOBUFS;
1086
1087 q = realloc(bus->wqueue, sizeof(sd_bus_message*) * (bus->wqueue_size + 1));
1088 if (!q)
1089 return -ENOMEM;
1090
1091 bus->wqueue = q;
1092 q[bus->wqueue_size ++] = sd_bus_message_ref(m);
1093 }
1094
1095 if (serial)
1096 *serial = BUS_MESSAGE_SERIAL(m);
1097
1098 return 0;
1099}
1100
1101static usec_t calc_elapse(uint64_t usec) {
1102 if (usec == (uint64_t) -1)
1103 return 0;
1104
1105 if (usec == 0)
e3017af9 1106 usec = BUS_DEFAULT_TIMEOUT;
de1c301e
LP
1107
1108 return now(CLOCK_MONOTONIC) + usec;
1109}
1110
e3017af9
LP
1111static int timeout_compare(const void *a, const void *b) {
1112 const struct reply_callback *x = a, *y = b;
1113
1114 if (x->timeout != 0 && y->timeout == 0)
1115 return -1;
1116
1117 if (x->timeout == 0 && y->timeout != 0)
1118 return 1;
1119
1120 if (x->timeout < y->timeout)
1121 return -1;
1122
1123 if (x->timeout > y->timeout)
1124 return 1;
1125
1126 return 0;
1127}
1128
de1c301e
LP
1129int sd_bus_send_with_reply(
1130 sd_bus *bus,
1131 sd_bus_message *m,
52f3ba91 1132 sd_bus_message_handler_t callback,
de1c301e
LP
1133 void *userdata,
1134 uint64_t usec,
1135 uint64_t *serial) {
1136
1137 struct reply_callback *c;
1138 int r;
1139
1140 if (!bus)
1141 return -EINVAL;
021a1e78
LP
1142 if (bus->state == BUS_UNSET)
1143 return -ENOTCONN;
e82c9509 1144 if (bus->output_fd < 0)
de1c301e
LP
1145 return -ENOTCONN;
1146 if (!m)
1147 return -EINVAL;
1148 if (!callback)
1149 return -EINVAL;
89ffcd2a 1150 if (m->header->type != SD_BUS_MESSAGE_TYPE_METHOD_CALL)
de1c301e 1151 return -EINVAL;
89ffcd2a
LP
1152 if (m->header->flags & SD_BUS_MESSAGE_NO_REPLY_EXPECTED)
1153 return -EINVAL;
1154
1155 r = hashmap_ensure_allocated(&bus->reply_callbacks, uint64_hash_func, uint64_compare_func);
1156 if (r < 0)
1157 return r;
de1c301e 1158
e3017af9
LP
1159 if (usec != (uint64_t) -1) {
1160 r = prioq_ensure_allocated(&bus->reply_callbacks_prioq, timeout_compare);
1161 if (r < 0)
1162 return r;
1163 }
1164
de1c301e
LP
1165 r = bus_seal_message(bus, m);
1166 if (r < 0)
1167 return r;
1168
eba8617e 1169 c = new0(struct reply_callback, 1);
de1c301e
LP
1170 if (!c)
1171 return -ENOMEM;
1172
1173 c->callback = callback;
1174 c->userdata = userdata;
1175 c->serial = BUS_MESSAGE_SERIAL(m);
1176 c->timeout = calc_elapse(usec);
1177
1178 r = hashmap_put(bus->reply_callbacks, &c->serial, c);
1179 if (r < 0) {
1180 free(c);
1181 return r;
1182 }
1183
e3017af9
LP
1184 if (c->timeout != 0) {
1185 r = prioq_put(bus->reply_callbacks_prioq, c, &c->prioq_idx);
1186 if (r < 0) {
1187 c->timeout = 0;
1188 sd_bus_send_with_reply_cancel(bus, c->serial);
1189 return r;
1190 }
1191 }
1192
de1c301e
LP
1193 r = sd_bus_send(bus, m, serial);
1194 if (r < 0) {
e3017af9 1195 sd_bus_send_with_reply_cancel(bus, c->serial);
de1c301e
LP
1196 return r;
1197 }
1198
1199 return r;
1200}
1201
1202int sd_bus_send_with_reply_cancel(sd_bus *bus, uint64_t serial) {
e3017af9 1203 struct reply_callback *c;
de1c301e
LP
1204
1205 if (!bus)
1206 return -EINVAL;
1207 if (serial == 0)
1208 return -EINVAL;
1209
1210 c = hashmap_remove(bus->reply_callbacks, &serial);
1211 if (!c)
1212 return 0;
1213
e3017af9
LP
1214 if (c->timeout != 0)
1215 prioq_remove(bus->reply_callbacks_prioq, c, &c->prioq_idx);
1216
de1c301e
LP
1217 free(c);
1218 return 1;
1219}
1220
20902f3e 1221int bus_ensure_running(sd_bus *bus) {
89ffcd2a
LP
1222 int r;
1223
1224 assert(bus);
1225
e82c9509 1226 if (bus->input_fd < 0)
021a1e78
LP
1227 return -ENOTCONN;
1228 if (bus->state == BUS_UNSET)
1229 return -ENOTCONN;
1230
d728d708
LP
1231 if (bus->state == BUS_RUNNING)
1232 return 1;
89ffcd2a
LP
1233
1234 for (;;) {
1235 r = sd_bus_process(bus, NULL);
1236 if (r < 0)
1237 return r;
d728d708
LP
1238 if (bus->state == BUS_RUNNING)
1239 return 1;
e3017af9
LP
1240 if (r > 0)
1241 continue;
89ffcd2a
LP
1242
1243 r = sd_bus_wait(bus, (uint64_t) -1);
1244 if (r < 0)
1245 return r;
1246 }
1247}
1248
de1c301e
LP
1249int sd_bus_send_with_reply_and_block(
1250 sd_bus *bus,
1251 sd_bus_message *m,
1252 uint64_t usec,
1253 sd_bus_error *error,
1254 sd_bus_message **reply) {
1255
1256 int r;
1257 usec_t timeout;
1258 uint64_t serial;
1259 bool room = false;
1260
1261 if (!bus)
1262 return -EINVAL;
e82c9509 1263 if (bus->output_fd < 0)
de1c301e 1264 return -ENOTCONN;
021a1e78
LP
1265 if (bus->state == BUS_UNSET)
1266 return -ENOTCONN;
de1c301e
LP
1267 if (!m)
1268 return -EINVAL;
89ffcd2a 1269 if (m->header->type != SD_BUS_MESSAGE_TYPE_METHOD_CALL)
de1c301e 1270 return -EINVAL;
89ffcd2a 1271 if (m->header->flags & SD_BUS_MESSAGE_NO_REPLY_EXPECTED)
de1c301e 1272 return -EINVAL;
89ffcd2a
LP
1273 if (bus_error_is_dirty(error))
1274 return -EINVAL;
1275
20902f3e 1276 r = bus_ensure_running(bus);
89ffcd2a
LP
1277 if (r < 0)
1278 return r;
de1c301e
LP
1279
1280 r = sd_bus_send(bus, m, &serial);
1281 if (r < 0)
1282 return r;
1283
1284 timeout = calc_elapse(usec);
1285
1286 for (;;) {
1287 usec_t left;
e3017af9 1288 sd_bus_message *incoming = NULL;
de1c301e
LP
1289
1290 if (!room) {
1291 sd_bus_message **q;
1292
25220239
LP
1293 if (bus->rqueue_size >= BUS_RQUEUE_MAX)
1294 return -ENOBUFS;
1295
de1c301e
LP
1296 /* Make sure there's room for queuing this
1297 * locally, before we read the message */
1298
1299 q = realloc(bus->rqueue, (bus->rqueue_size + 1) * sizeof(sd_bus_message*));
1300 if (!q)
1301 return -ENOMEM;
1302
1303 bus->rqueue = q;
1304 room = true;
1305 }
1306
a7e3212d 1307 r = bus_socket_read_message(bus, &incoming);
de1c301e
LP
1308 if (r < 0)
1309 return r;
e3017af9 1310 if (incoming) {
89ffcd2a 1311
de1c301e
LP
1312 if (incoming->reply_serial == serial) {
1313 /* Found a match! */
1314
1315 if (incoming->header->type == SD_BUS_MESSAGE_TYPE_METHOD_RETURN) {
b7f247e0
LP
1316
1317 if (reply)
1318 *reply = incoming;
1319 else
1320 sd_bus_message_unref(incoming);
1321
de1c301e
LP
1322 return 0;
1323 }
1324
1325 if (incoming->header->type == SD_BUS_MESSAGE_TYPE_METHOD_ERROR) {
1326 int k;
1327
1328 r = sd_bus_error_copy(error, &incoming->error);
1329 if (r < 0) {
1330 sd_bus_message_unref(incoming);
1331 return r;
1332 }
1333
1334 k = bus_error_to_errno(&incoming->error);
1335 sd_bus_message_unref(incoming);
1336 return k;
1337 }
1338
1339 sd_bus_message_unref(incoming);
1340 return -EIO;
1341 }
1342
1343 /* There's already guaranteed to be room for
1344 * this, so need to resize things here */
1345 bus->rqueue[bus->rqueue_size ++] = incoming;
1346 room = false;
1347
1348 /* Try to read more, right-away */
1349 continue;
1350 }
e3017af9
LP
1351 if (r != 0)
1352 continue;
de1c301e
LP
1353
1354 if (timeout > 0) {
1355 usec_t n;
1356
1357 n = now(CLOCK_MONOTONIC);
1358 if (n >= timeout)
1359 return -ETIMEDOUT;
1360
1361 left = timeout - n;
1362 } else
1363 left = (uint64_t) -1;
1364
e3017af9 1365 r = bus_poll(bus, true, left);
de1c301e
LP
1366 if (r < 0)
1367 return r;
1368
1369 r = dispatch_wqueue(bus);
1370 if (r < 0)
1371 return r;
1372 }
1373}
1374
1375int sd_bus_get_fd(sd_bus *bus) {
1376 if (!bus)
1377 return -EINVAL;
e82c9509 1378 if (bus->input_fd < 0)
89ffcd2a 1379 return -ENOTCONN;
e82c9509
LP
1380 if (bus->input_fd != bus->output_fd)
1381 return -EPERM;
de1c301e 1382
e82c9509 1383 return bus->input_fd;
de1c301e
LP
1384}
1385
1386int sd_bus_get_events(sd_bus *bus) {
1387 int flags = 0;
1388
1389 if (!bus)
1390 return -EINVAL;
021a1e78
LP
1391 if (bus->state == BUS_UNSET)
1392 return -ENOTCONN;
e82c9509 1393 if (bus->input_fd < 0)
89ffcd2a 1394 return -ENOTCONN;
de1c301e
LP
1395
1396 if (bus->state == BUS_OPENING)
1397 flags |= POLLOUT;
89ffcd2a
LP
1398 else if (bus->state == BUS_AUTHENTICATING) {
1399
2181a7f5 1400 if (bus_socket_auth_needs_write(bus))
89ffcd2a
LP
1401 flags |= POLLOUT;
1402
1403 flags |= POLLIN;
1404
1405 } else if (bus->state == BUS_RUNNING || bus->state == BUS_HELLO) {
de1c301e
LP
1406 if (bus->rqueue_size <= 0)
1407 flags |= POLLIN;
1408 if (bus->wqueue_size > 0)
1409 flags |= POLLOUT;
1410 }
1411
1412 return flags;
1413}
1414
e3017af9
LP
1415int sd_bus_get_timeout(sd_bus *bus, uint64_t *timeout_usec) {
1416 struct reply_callback *c;
1417
1418 if (!bus)
1419 return -EINVAL;
1420 if (!timeout_usec)
1421 return -EINVAL;
021a1e78
LP
1422 if (bus->state == BUS_UNSET)
1423 return -ENOTCONN;
e82c9509 1424 if (bus->input_fd < 0)
e3017af9
LP
1425 return -ENOTCONN;
1426
1427 if (bus->state == BUS_AUTHENTICATING) {
1428 *timeout_usec = bus->auth_timeout;
1429 return 1;
1430 }
1431
adee69fa
LP
1432 if (bus->state != BUS_RUNNING && bus->state != BUS_HELLO) {
1433 *timeout_usec = (uint64_t) -1;
e3017af9 1434 return 0;
adee69fa 1435 }
e3017af9
LP
1436
1437 c = prioq_peek(bus->reply_callbacks_prioq);
adee69fa
LP
1438 if (!c) {
1439 *timeout_usec = (uint64_t) -1;
e3017af9 1440 return 0;
adee69fa 1441 }
e3017af9
LP
1442
1443 *timeout_usec = c->timeout;
1444 return 1;
1445}
1446
1447static int process_timeout(sd_bus *bus) {
e3017af9
LP
1448 struct reply_callback *c;
1449 usec_t n;
1450 int r;
1451
1452 assert(bus);
1453
1454 c = prioq_peek(bus->reply_callbacks_prioq);
1455 if (!c)
1456 return 0;
1457
1458 n = now(CLOCK_MONOTONIC);
1459 if (c->timeout > n)
1460 return 0;
1461
1462 assert_se(prioq_pop(bus->reply_callbacks_prioq) == c);
1463 hashmap_remove(bus->reply_callbacks, &c->serial);
1464
1465 r = c->callback(bus, ETIMEDOUT, NULL, c->userdata);
1466 free(c);
1467
1468 return r < 0 ? r : 1;
1469}
1470
9d373862
LP
1471static int process_hello(sd_bus *bus, sd_bus_message *m) {
1472 assert(bus);
1473 assert(m);
1474
1475 if (bus->state != BUS_HELLO)
1476 return 0;
1477
1478 /* Let's make sure the first message on the bus is the HELLO
1479 * reply. But note that we don't actually parse the message
2181a7f5
LP
1480 * here (we leave that to the usual handling), we just verify
1481 * we don't let any earlier msg through. */
9d373862
LP
1482
1483 if (m->header->type != SD_BUS_MESSAGE_TYPE_METHOD_RETURN &&
1484 m->header->type != SD_BUS_MESSAGE_TYPE_METHOD_ERROR)
1485 return -EIO;
1486
1487 if (m->reply_serial != bus->hello_serial)
1488 return -EIO;
1489
1490 return 0;
1491}
1492
a652755d
LP
1493static int process_reply(sd_bus *bus, sd_bus_message *m) {
1494 struct reply_callback *c;
1495 int r;
1496
1497 assert(bus);
1498 assert(m);
1499
1500 if (m->header->type != SD_BUS_MESSAGE_TYPE_METHOD_RETURN &&
1501 m->header->type != SD_BUS_MESSAGE_TYPE_METHOD_ERROR)
1502 return 0;
1503
1504 c = hashmap_remove(bus->reply_callbacks, &m->reply_serial);
1505 if (!c)
1506 return 0;
1507
1508 if (c->timeout != 0)
1509 prioq_remove(bus->reply_callbacks_prioq, c, &c->prioq_idx);
1510
1511 r = c->callback(bus, 0, m, c->userdata);
1512 free(c);
1513
1514 return r;
1515}
1516
1517static int process_filter(sd_bus *bus, sd_bus_message *m) {
1518 struct filter_callback *l;
1519 int r;
1520
392d5b37
LP
1521 assert(bus);
1522 assert(m);
1523
7286037f
LP
1524 do {
1525 bus->filter_callbacks_modified = false;
1526
1527 LIST_FOREACH(callbacks, l, bus->filter_callbacks) {
1528
1529 if (bus->filter_callbacks_modified)
1530 break;
1531
1532 /* Don't run this more than once per iteration */
1533 if (l->last_iteration == bus->iteration_counter)
1534 continue;
1535
1536 l->last_iteration = bus->iteration_counter;
1537
1538 r = l->callback(bus, 0, m, l->userdata);
1539 if (r != 0)
1540 return r;
1541
1542 }
1543
1544 } while (bus->filter_callbacks_modified);
a652755d
LP
1545
1546 return 0;
1547}
1548
392d5b37 1549static int process_match(sd_bus *bus, sd_bus_message *m) {
7286037f
LP
1550 int r;
1551
392d5b37
LP
1552 assert(bus);
1553 assert(m);
1554
7286037f
LP
1555 do {
1556 bus->match_callbacks_modified = false;
1557
1558 r = bus_match_run(bus, &bus->match_callbacks, 0, m);
1559 if (r != 0)
1560 return r;
1561
1562 } while (bus->match_callbacks_modified);
1563
1564 return 0;
392d5b37
LP
1565}
1566
b9bf7e2b
LP
1567static int process_builtin(sd_bus *bus, sd_bus_message *m) {
1568 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
1569 int r;
1570
1571 assert(bus);
1572 assert(m);
1573
1574 if (m->header->type != SD_BUS_MESSAGE_TYPE_METHOD_CALL)
1575 return 0;
1576
1577 if (!streq_ptr(m->interface, "org.freedesktop.DBus.Peer"))
1578 return 0;
1579
1580 if (m->header->flags & SD_BUS_MESSAGE_NO_REPLY_EXPECTED)
1581 return 1;
1582
1583 if (streq_ptr(m->member, "Ping"))
1584 r = sd_bus_message_new_method_return(bus, m, &reply);
1585 else if (streq_ptr(m->member, "GetMachineId")) {
1586 sd_id128_t id;
1587 char sid[33];
1588
1589 r = sd_id128_get_machine(&id);
1590 if (r < 0)
1591 return r;
1592
1593 r = sd_bus_message_new_method_return(bus, m, &reply);
1594 if (r < 0)
1595 return r;
1596
1597 r = sd_bus_message_append(reply, "s", sd_id128_to_string(id, sid));
1598 } else {
c784c5ce 1599 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
b9bf7e2b
LP
1600
1601 sd_bus_error_set(&error,
1602 "org.freedesktop.DBus.Error.UnknownMethod",
1603 "Unknown method '%s' on interface '%s'.", m->member, m->interface);
1604
1605 r = sd_bus_message_new_method_error(bus, m, &error, &reply);
1606 }
1607
1608 if (r < 0)
1609 return r;
1610
1611 r = sd_bus_send(bus, reply, NULL);
1612 if (r < 0)
1613 return r;
1614
1615 return 1;
1616}
1617
a652755d 1618static int process_object(sd_bus *bus, sd_bus_message *m) {
c784c5ce 1619 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
a652755d
LP
1620 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
1621 struct object_callback *c;
e3017af9 1622 int r;
a652755d 1623 bool found = false;
7286037f 1624 size_t pl;
e3017af9
LP
1625
1626 assert(bus);
1627 assert(m);
1628
a652755d
LP
1629 if (m->header->type != SD_BUS_MESSAGE_TYPE_METHOD_CALL)
1630 return 0;
e3017af9 1631
a652755d
LP
1632 if (hashmap_isempty(bus->object_callbacks))
1633 return 0;
e3017af9 1634
7286037f 1635 pl = strlen(m->path);
a652755d 1636
7286037f
LP
1637 do {
1638 char p[pl+1];
e3017af9 1639
7286037f 1640 bus->object_callbacks_modified = false;
a652755d 1641
7286037f
LP
1642 c = hashmap_get(bus->object_callbacks, m->path);
1643 if (c && c->last_iteration != bus->iteration_counter) {
a652755d 1644
7286037f 1645 c->last_iteration = bus->iteration_counter;
a652755d 1646
a652755d 1647 r = c->callback(bus, 0, m, c->userdata);
e3017af9
LP
1648 if (r != 0)
1649 return r;
a652755d
LP
1650
1651 found = true;
e3017af9 1652 }
7286037f
LP
1653
1654 /* Look for fallback prefixes */
1655 strcpy(p, m->path);
1656 for (;;) {
1657 char *e;
1658
1659 if (bus->object_callbacks_modified)
1660 break;
1661
1662 e = strrchr(p, '/');
1663 if (e == p || !e)
1664 break;
1665
1666 *e = 0;
1667
1668 c = hashmap_get(bus->object_callbacks, p);
1669 if (c && c->last_iteration != bus->iteration_counter && c->is_fallback) {
1670
1671 c->last_iteration = bus->iteration_counter;
1672
1673 r = c->callback(bus, 0, m, c->userdata);
1674 if (r != 0)
1675 return r;
1676
1677 found = true;
1678 }
1679 }
1680
1681 } while (bus->object_callbacks_modified);
e3017af9 1682
0a72c2bd
LP
1683 /* We found some handlers but none wanted to take this, then
1684 * return this -- with one exception, we can handle
1685 * introspection minimally ourselves */
1686 if (!found || sd_bus_message_is_method_call(m, "org.freedesktop.DBus.Introspectable", "Introspect"))
a652755d
LP
1687 return 0;
1688
1689 sd_bus_error_set(&error,
1690 "org.freedesktop.DBus.Error.UnknownMethod",
1691 "Unknown method '%s' or interface '%s'.", m->member, m->interface);
1692
1693 r = sd_bus_message_new_method_error(bus, m, &error, &reply);
1694 if (r < 0)
1695 return r;
1696
1697 r = sd_bus_send(bus, reply, NULL);
1698 if (r < 0)
1699 return r;
e3017af9 1700
a652755d
LP
1701 return 1;
1702}
1703
0a72c2bd
LP
1704static int process_introspect(sd_bus *bus, sd_bus_message *m) {
1705 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
1706 _cleanup_free_ char *introspection = NULL;
1707 _cleanup_set_free_free_ Set *s = NULL;
1708 _cleanup_fclose_ FILE *f = NULL;
1709 struct object_callback *c;
1710 Iterator i;
1711 size_t size = 0;
1712 char *node;
1713 int r;
1714
1715 assert(bus);
1716 assert(m);
1717
1718 if (!sd_bus_message_is_method_call(m, "org.freedesktop.DBus.Introspectable", "Introspect"))
1719 return 0;
1720
1721 if (!m->path)
1722 return 0;
1723
1724 s = set_new(string_hash_func, string_compare_func);
1725 if (!s)
1726 return -ENOMEM;
1727
1728 HASHMAP_FOREACH(c, bus->object_callbacks, i) {
1729 const char *e;
1730 char *a, *p;
1731
1732 if (streq(c->path, "/"))
1733 continue;
1734
1735 if (streq(m->path, "/"))
1736 e = c->path;
1737 else {
1738 e = startswith(c->path, m->path);
1739 if (!e || *e != '/')
1740 continue;
1741 }
1742
1743 a = strdup(e+1);
1744 if (!a)
1745 return -ENOMEM;
1746
1747 p = strchr(a, '/');
1748 if (p)
1749 *p = 0;
1750
1751 r = set_put(s, a);
1752 if (r < 0) {
1753 free(a);
1754
1755 if (r != -EEXIST)
1756 return r;
1757 }
1758 }
1759
1760 f = open_memstream(&introspection, &size);
1761 if (!f)
1762 return -ENOMEM;
1763
1764 fputs(SD_BUS_INTROSPECT_DOCTYPE, f);
1765 fputs("<node>\n", f);
1766 fputs(SD_BUS_INTROSPECT_INTERFACE_PEER, f);
1767 fputs(SD_BUS_INTROSPECT_INTERFACE_INTROSPECTABLE, f);
1768
1769 while ((node = set_steal_first(s))) {
1770 fprintf(f, " <node name=\"%s\"/>\n", node);
1771 free(node);
1772 }
1773
1774 fputs("</node>\n", f);
1775
1776 fflush(f);
1777
1778 if (ferror(f))
1779 return -ENOMEM;
1780
1781 r = sd_bus_message_new_method_return(bus, m, &reply);
1782 if (r < 0)
1783 return r;
1784
1785 r = sd_bus_message_append(reply, "s", introspection);
1786 if (r < 0)
1787 return r;
1788
1789 r = sd_bus_send(bus, reply, NULL);
1790 if (r < 0)
1791 return r;
1792
1793 return 1;
1794}
1795
a652755d
LP
1796static int process_message(sd_bus *bus, sd_bus_message *m) {
1797 int r;
1798
1799 assert(bus);
1800 assert(m);
1801
7286037f
LP
1802 bus->iteration_counter++;
1803
9d373862
LP
1804 r = process_hello(bus, m);
1805 if (r != 0)
1806 return r;
1807
a652755d
LP
1808 r = process_reply(bus, m);
1809 if (r != 0)
1810 return r;
1811
1812 r = process_filter(bus, m);
1813 if (r != 0)
1814 return r;
1815
392d5b37
LP
1816 r = process_match(bus, m);
1817 if (r != 0)
1818 return r;
1819
a652755d
LP
1820 r = process_builtin(bus, m);
1821 if (r != 0)
1822 return r;
1823
0a72c2bd
LP
1824 r = process_object(bus, m);
1825 if (r != 0)
1826 return r;
1827
1828 return process_introspect(bus, m);
e3017af9
LP
1829}
1830
a7e3212d
LP
1831static int process_running(sd_bus *bus, sd_bus_message **ret) {
1832 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
de1c301e
LP
1833 int r;
1834
a7e3212d
LP
1835 assert(bus);
1836 assert(bus->state == BUS_RUNNING || bus->state == BUS_HELLO);
de1c301e 1837
a7e3212d
LP
1838 r = process_timeout(bus);
1839 if (r != 0)
1840 goto null_message;
de1c301e 1841
a7e3212d
LP
1842 r = dispatch_wqueue(bus);
1843 if (r != 0)
1844 goto null_message;
de1c301e 1845
a7e3212d
LP
1846 r = dispatch_rqueue(bus, &m);
1847 if (r < 0)
1848 return r;
1849 if (!m)
1850 goto null_message;
de1c301e 1851
a7e3212d
LP
1852 r = process_message(bus, m);
1853 if (r != 0)
1854 goto null_message;
de1c301e 1855
a7e3212d
LP
1856 if (ret) {
1857 *ret = m;
1858 m = NULL;
1859 return 1;
1860 }
de1c301e 1861
a7e3212d
LP
1862 if (m->header->type == SD_BUS_MESSAGE_TYPE_METHOD_CALL) {
1863 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
c784c5ce 1864 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
de1c301e 1865
a7e3212d 1866 sd_bus_error_set(&error, "org.freedesktop.DBus.Error.UnknownObject", "Unknown object '%s'.", m->path);
de1c301e 1867
a7e3212d
LP
1868 r = sd_bus_message_new_method_error(bus, m, &error, &reply);
1869 if (r < 0)
1870 return r;
de1c301e 1871
a7e3212d
LP
1872 r = sd_bus_send(bus, reply, NULL);
1873 if (r < 0)
1874 return r;
1875 }
e3017af9 1876
a7e3212d 1877 return 1;
de1c301e 1878
a7e3212d
LP
1879null_message:
1880 if (r >= 0 && ret)
1881 *ret = NULL;
de1c301e 1882
a7e3212d
LP
1883 return r;
1884}
e3017af9 1885
a7e3212d
LP
1886int sd_bus_process(sd_bus *bus, sd_bus_message **ret) {
1887 int r;
de1c301e 1888
a7e3212d
LP
1889 /* Returns 0 when we didn't do anything. This should cause the
1890 * caller to invoke sd_bus_wait() before returning the next
1891 * time. Returns > 0 when we did something, which possibly
1892 * means *ret is filled in with an unprocessed message. */
de1c301e 1893
a7e3212d
LP
1894 if (!bus)
1895 return -EINVAL;
e82c9509 1896 if (bus->input_fd < 0)
a7e3212d 1897 return -ENOTCONN;
de1c301e 1898
6807947e
LP
1899 /* We don't allow recursively invoking sd_bus_process(). */
1900 if (bus->processing)
1901 return -EBUSY;
1902
a7e3212d 1903 switch (bus->state) {
de1c301e 1904
a7e3212d
LP
1905 case BUS_UNSET:
1906 return -ENOTCONN;
de1c301e 1907
a7e3212d
LP
1908 case BUS_OPENING:
1909 r = bus_socket_process_opening(bus);
1910 if (r < 0)
1911 return r;
1912 if (ret)
1913 *ret = NULL;
1914 return r;
b9bf7e2b 1915
a7e3212d 1916 case BUS_AUTHENTICATING:
89ffcd2a 1917
a7e3212d
LP
1918 r = bus_socket_process_authenticating(bus);
1919 if (r < 0)
1920 return r;
1921 if (ret)
1922 *ret = NULL;
1923 return r;
89ffcd2a 1924
a7e3212d
LP
1925 case BUS_RUNNING:
1926 case BUS_HELLO:
89ffcd2a 1927
6807947e
LP
1928 bus->processing = true;
1929 r = process_running(bus, ret);
1930 bus->processing = false;
1931
1932 return r;
de1c301e
LP
1933 }
1934
89ffcd2a 1935 assert_not_reached("Unknown state");
de1c301e
LP
1936}
1937
e3017af9 1938static int bus_poll(sd_bus *bus, bool need_more, uint64_t timeout_usec) {
b92bea5d 1939 struct pollfd p[2] = {};
e82c9509 1940 int r, e, n;
de1c301e 1941 struct timespec ts;
e3017af9
LP
1942 usec_t until, m;
1943
1944 assert(bus);
de1c301e 1945
e82c9509 1946 if (bus->input_fd < 0)
89ffcd2a
LP
1947 return -ENOTCONN;
1948
de1c301e
LP
1949 e = sd_bus_get_events(bus);
1950 if (e < 0)
1951 return e;
1952
e3017af9
LP
1953 if (need_more)
1954 e |= POLLIN;
1955
1956 r = sd_bus_get_timeout(bus, &until);
1957 if (r < 0)
1958 return r;
1959 if (r == 0)
1960 m = (uint64_t) -1;
1961 else {
e82c9509
LP
1962 usec_t nw;
1963 nw = now(CLOCK_MONOTONIC);
1964 m = until > nw ? until - nw : 0;
e3017af9
LP
1965 }
1966
1967 if (timeout_usec != (uint64_t) -1 && (m == (uint64_t) -1 || timeout_usec < m))
1968 m = timeout_usec;
1969
e82c9509 1970 p[0].fd = bus->input_fd;
e82c9509
LP
1971 if (bus->output_fd == bus->input_fd) {
1972 p[0].events = e;
1973 n = 1;
1974 } else {
1975 p[0].events = e & POLLIN;
1976 p[1].fd = bus->output_fd;
1977 p[1].events = e & POLLOUT;
1978 n = 2;
1979 }
de1c301e 1980
e82c9509 1981 r = ppoll(p, n, m == (uint64_t) -1 ? NULL : timespec_store(&ts, m), NULL);
de1c301e 1982 if (r < 0)
89ffcd2a 1983 return -errno;
de1c301e 1984
e3017af9
LP
1985 return r > 0 ? 1 : 0;
1986}
1987
1988int sd_bus_wait(sd_bus *bus, uint64_t timeout_usec) {
1989
1990 if (!bus)
1991 return -EINVAL;
021a1e78
LP
1992 if (bus->state == BUS_UNSET)
1993 return -ENOTCONN;
e82c9509 1994 if (bus->input_fd < 0)
e3017af9
LP
1995 return -ENOTCONN;
1996 if (bus->rqueue_size > 0)
1997 return 0;
1998
1999 return bus_poll(bus, false, timeout_usec);
de1c301e
LP
2000}
2001
2002int sd_bus_flush(sd_bus *bus) {
2003 int r;
2004
2005 if (!bus)
2006 return -EINVAL;
021a1e78
LP
2007 if (bus->state == BUS_UNSET)
2008 return -ENOTCONN;
e82c9509 2009 if (bus->output_fd < 0)
de1c301e
LP
2010 return -ENOTCONN;
2011
20902f3e 2012 r = bus_ensure_running(bus);
89ffcd2a
LP
2013 if (r < 0)
2014 return r;
2015
2016 if (bus->wqueue_size <= 0)
de1c301e
LP
2017 return 0;
2018
2019 for (;;) {
2020 r = dispatch_wqueue(bus);
2021 if (r < 0)
2022 return r;
2023
89ffcd2a 2024 if (bus->wqueue_size <= 0)
de1c301e
LP
2025 return 0;
2026
e3017af9 2027 r = bus_poll(bus, false, (uint64_t) -1);
de1c301e
LP
2028 if (r < 0)
2029 return r;
2030 }
2031}
2032
52f3ba91 2033int sd_bus_add_filter(sd_bus *bus, sd_bus_message_handler_t callback, void *userdata) {
de1c301e
LP
2034 struct filter_callback *f;
2035
2036 if (!bus)
2037 return -EINVAL;
2038 if (!callback)
2039 return -EINVAL;
2040
eba8617e 2041 f = new0(struct filter_callback, 1);
de1c301e
LP
2042 if (!f)
2043 return -ENOMEM;
2044 f->callback = callback;
2045 f->userdata = userdata;
2046
7286037f 2047 bus->filter_callbacks_modified = true;
de1c301e
LP
2048 LIST_PREPEND(struct filter_callback, callbacks, bus->filter_callbacks, f);
2049 return 0;
2050}
2051
52f3ba91 2052int sd_bus_remove_filter(sd_bus *bus, sd_bus_message_handler_t callback, void *userdata) {
de1c301e
LP
2053 struct filter_callback *f;
2054
2055 if (!bus)
2056 return -EINVAL;
2057 if (!callback)
2058 return -EINVAL;
2059
2060 LIST_FOREACH(callbacks, f, bus->filter_callbacks) {
2061 if (f->callback == callback && f->userdata == userdata) {
7286037f 2062 bus->filter_callbacks_modified = true;
de1c301e
LP
2063 LIST_REMOVE(struct filter_callback, callbacks, bus->filter_callbacks, f);
2064 free(f);
2065 return 1;
2066 }
2067 }
2068
2069 return 0;
2070}
a652755d
LP
2071
2072static int bus_add_object(
2073 sd_bus *bus,
2074 bool fallback,
2075 const char *path,
52f3ba91 2076 sd_bus_message_handler_t callback,
a652755d
LP
2077 void *userdata) {
2078
2079 struct object_callback *c;
2080 int r;
2081
2082 if (!bus)
2083 return -EINVAL;
2084 if (!path)
2085 return -EINVAL;
2086 if (!callback)
2087 return -EINVAL;
2088
2089 r = hashmap_ensure_allocated(&bus->object_callbacks, string_hash_func, string_compare_func);
2090 if (r < 0)
2091 return r;
2092
eba8617e 2093 c = new0(struct object_callback, 1);
a652755d
LP
2094 if (!c)
2095 return -ENOMEM;
2096
2097 c->path = strdup(path);
531991b6 2098 if (!c->path) {
a652755d
LP
2099 free(c);
2100 return -ENOMEM;
2101 }
2102
2103 c->callback = callback;
2104 c->userdata = userdata;
2105 c->is_fallback = fallback;
2106
7286037f 2107 bus->object_callbacks_modified = true;
a652755d
LP
2108 r = hashmap_put(bus->object_callbacks, c->path, c);
2109 if (r < 0) {
2110 free(c->path);
2111 free(c);
2112 return r;
2113 }
2114
2115 return 0;
2116}
2117
2118static int bus_remove_object(
2119 sd_bus *bus,
2120 bool fallback,
2121 const char *path,
52f3ba91 2122 sd_bus_message_handler_t callback,
a652755d
LP
2123 void *userdata) {
2124
2125 struct object_callback *c;
2126
2127 if (!bus)
2128 return -EINVAL;
2129 if (!path)
2130 return -EINVAL;
2131 if (!callback)
2132 return -EINVAL;
2133
2134 c = hashmap_get(bus->object_callbacks, path);
2135 if (!c)
2136 return 0;
2137
2138 if (c->callback != callback || c->userdata != userdata || c->is_fallback != fallback)
2139 return 0;
2140
7286037f 2141 bus->object_callbacks_modified = true;
a652755d
LP
2142 assert_se(c == hashmap_remove(bus->object_callbacks, c->path));
2143
2144 free(c->path);
2145 free(c);
2146
2147 return 1;
2148}
2149
52f3ba91 2150int sd_bus_add_object(sd_bus *bus, const char *path, sd_bus_message_handler_t callback, void *userdata) {
a652755d
LP
2151 return bus_add_object(bus, false, path, callback, userdata);
2152}
2153
52f3ba91 2154int sd_bus_remove_object(sd_bus *bus, const char *path, sd_bus_message_handler_t callback, void *userdata) {
a652755d
LP
2155 return bus_remove_object(bus, false, path, callback, userdata);
2156}
2157
52f3ba91 2158int sd_bus_add_fallback(sd_bus *bus, const char *prefix, sd_bus_message_handler_t callback, void *userdata) {
a652755d
LP
2159 return bus_add_object(bus, true, prefix, callback, userdata);
2160}
2161
52f3ba91 2162int sd_bus_remove_fallback(sd_bus *bus, const char *prefix, sd_bus_message_handler_t callback, void *userdata) {
a652755d
LP
2163 return bus_remove_object(bus, true, prefix, callback, userdata);
2164}
392d5b37 2165
52f3ba91 2166int sd_bus_add_match(sd_bus *bus, const char *match, sd_bus_message_handler_t callback, void *userdata) {
392d5b37
LP
2167 int r = 0;
2168
2169 if (!bus)
2170 return -EINVAL;
2171 if (!match)
2172 return -EINVAL;
2173
2174 if (bus->bus_client) {
2175 r = bus_add_match_internal(bus, match);
2176 if (r < 0)
2177 return r;
2178 }
2179
2180 if (callback) {
7286037f 2181 bus->match_callbacks_modified = true;
392d5b37
LP
2182 r = bus_match_add(&bus->match_callbacks, match, callback, userdata, NULL);
2183 if (r < 0) {
2184
2185 if (bus->bus_client)
2186 bus_remove_match_internal(bus, match);
2187 }
2188 }
2189
2190 return r;
2191}
2192
52f3ba91 2193int sd_bus_remove_match(sd_bus *bus, const char *match, sd_bus_message_handler_t callback, void *userdata) {
392d5b37
LP
2194 int r = 0, q = 0;
2195
2196 if (!bus)
2197 return -EINVAL;
2198 if (!match)
2199 return -EINVAL;
2200
2201 if (bus->bus_client)
2202 r = bus_remove_match_internal(bus, match);
2203
7286037f
LP
2204 if (callback) {
2205 bus->match_callbacks_modified = true;
392d5b37 2206 q = bus_match_remove(&bus->match_callbacks, match, callback, userdata);
7286037f 2207 }
392d5b37
LP
2208
2209 if (r < 0)
2210 return r;
2211 return q;
2212}
917b5dc7
LP
2213
2214int sd_bus_emit_signal(
2215 sd_bus *bus,
2216 const char *path,
2217 const char *interface,
2218 const char *member,
2219 const char *types, ...) {
2220
2221 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
2222 va_list ap;
2223 int r;
2224
2225 if (!bus)
2226 return -EINVAL;
2227
2228 r = sd_bus_message_new_signal(bus, path, interface, member, &m);
2229 if (r < 0)
2230 return r;
2231
2232 va_start(ap, types);
2233 r = bus_message_append_ap(m, types, ap);
2234 va_end(ap);
2235 if (r < 0)
2236 return r;
2237
2238 return sd_bus_send(bus, m, NULL);
2239}
2240
2241int sd_bus_call_method(
2242 sd_bus *bus,
2243 const char *destination,
2244 const char *path,
2245 const char *interface,
2246 const char *member,
2247 sd_bus_error *error,
2248 sd_bus_message **reply,
2249 const char *types, ...) {
2250
2251 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
2252 va_list ap;
2253 int r;
2254
2255 if (!bus)
2256 return -EINVAL;
2257
2258 r = sd_bus_message_new_method_call(bus, destination, path, interface, member, &m);
2259 if (r < 0)
2260 return r;
2261
2262 va_start(ap, types);
2263 r = bus_message_append_ap(m, types, ap);
2264 va_end(ap);
2265 if (r < 0)
2266 return r;
2267
2268 return sd_bus_send_with_reply_and_block(bus, m, 0, error, reply);
2269}
f10dda3b
LP
2270
2271int sd_bus_reply_method_return(
2272 sd_bus *bus,
2273 sd_bus_message *call,
2274 const char *types, ...) {
2275
2276 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
2277 va_list ap;
2278 int r;
2279
2280 if (!bus)
2281 return -EINVAL;
2282 if (!call)
2283 return -EINVAL;
2284 if (!call->sealed)
2285 return -EPERM;
2286 if (call->header->type != SD_BUS_MESSAGE_TYPE_METHOD_CALL)
2287 return -EINVAL;
2288
2289 if (call->header->flags & SD_BUS_MESSAGE_NO_REPLY_EXPECTED)
2290 return 0;
2291
2292 r = sd_bus_message_new_method_return(bus, call, &m);
2293 if (r < 0)
2294 return r;
2295
2296 va_start(ap, types);
2297 r = bus_message_append_ap(m, types, ap);
2298 va_end(ap);
2299 if (r < 0)
2300 return r;
2301
2302 return sd_bus_send(bus, m, NULL);
2303}
2304
2305int sd_bus_reply_method_error(
2306 sd_bus *bus,
2307 sd_bus_message *call,
2308 const sd_bus_error *e) {
2309
2310 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
2311 int r;
2312
2313 if (!bus)
2314 return -EINVAL;
2315 if (!call)
2316 return -EINVAL;
2317 if (!call->sealed)
2318 return -EPERM;
2319 if (call->header->type != SD_BUS_MESSAGE_TYPE_METHOD_CALL)
2320 return -EINVAL;
2321 if (!sd_bus_error_is_set(e))
2322 return -EINVAL;
2323
2324 if (call->header->flags & SD_BUS_MESSAGE_NO_REPLY_EXPECTED)
2325 return 0;
2326
2327 r = sd_bus_message_new_method_error(bus, call, e, &m);
2328 if (r < 0)
2329 return r;
2330
2331 return sd_bus_send(bus, m, NULL);
2332}