| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812 |
- /*
- *
- * Embedded Linux library
- *
- * Copyright (C) 2011-2014 Intel Corporation. All rights reserved.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- *
- */
- #ifdef HAVE_CONFIG_H
- #include <config.h>
- #endif
- #define _GNU_SOURCE
- #include <stdio.h>
- #include <fcntl.h>
- #include <unistd.h>
- #include <stdlib.h>
- #include <string.h>
- #include <sys/socket.h>
- #include <sys/un.h>
- #include <errno.h>
- #include "util.h"
- #include "io.h"
- #include "idle.h"
- #include "queue.h"
- #include "hashmap.h"
- #include "dbus.h"
- #include "private.h"
- #include "useful.h"
- #include "dbus-private.h"
- #define DEFAULT_SYSTEM_BUS_ADDRESS "unix:path=/var/run/dbus/system_bus_socket"
- #define DBUS_SERVICE_DBUS "org.freedesktop.DBus"
- #define DBUS_PATH_DBUS "/org/freedesktop/DBus"
- #define DBUS_MAXIMUM_MATCH_RULE_LENGTH 1024
- enum auth_state {
- WAITING_FOR_OK,
- WAITING_FOR_AGREE_UNIX_FD,
- SETUP_DONE
- };
- struct l_dbus_ops {
- char version;
- bool (*send_message)(struct l_dbus *bus,
- struct l_dbus_message *message);
- struct l_dbus_message *(*recv_message)(struct l_dbus *bus);
- void (*free)(struct l_dbus *bus);
- struct _dbus_name_ops name_ops;
- struct _dbus_filter_ops filter_ops;
- uint32_t (*name_acquire)(struct l_dbus *dbus, const char *name,
- bool allow_replacement, bool replace_existing,
- bool queue, l_dbus_name_acquire_func_t callback,
- void *user_data);
- };
- struct l_dbus {
- struct l_io *io;
- char *guid;
- bool negotiate_unix_fd;
- bool support_unix_fd;
- bool is_ready;
- char *unique_name;
- unsigned int next_id;
- uint32_t next_serial;
- struct l_queue *message_queue;
- struct l_hashmap *message_list;
- struct l_hashmap *signal_list;
- l_dbus_ready_func_t ready_handler;
- l_dbus_destroy_func_t ready_destroy;
- void *ready_data;
- l_dbus_disconnect_func_t disconnect_handler;
- l_dbus_destroy_func_t disconnect_destroy;
- void *disconnect_data;
- l_dbus_debug_func_t debug_handler;
- l_dbus_destroy_func_t debug_destroy;
- void *debug_data;
- struct _dbus_object_tree *tree;
- struct _dbus_name_cache *name_cache;
- struct _dbus_filter *filter;
- bool name_notify_enabled;
- const struct l_dbus_ops *driver;
- };
- struct l_dbus_classic {
- struct l_dbus super;
- void *auth_command;
- enum auth_state auth_state;
- struct l_hashmap *match_strings;
- int *fd_buf;
- unsigned int num_fds;
- };
- struct message_callback {
- uint32_t serial;
- struct l_dbus_message *message;
- l_dbus_message_func_t callback;
- l_dbus_destroy_func_t destroy;
- void *user_data;
- };
- struct signal_callback {
- unsigned int id;
- l_dbus_message_func_t callback;
- l_dbus_destroy_func_t destroy;
- void *user_data;
- };
- static void message_queue_destroy(void *data)
- {
- struct message_callback *callback = data;
- l_dbus_message_unref(callback->message);
- if (callback->destroy)
- callback->destroy(callback->user_data);
- l_free(callback);
- }
- static void message_list_destroy(void *value)
- {
- message_queue_destroy(value);
- }
- static void signal_list_destroy(void *value)
- {
- struct signal_callback *callback = value;
- if (callback->destroy)
- callback->destroy(callback->user_data);
- l_free(callback);
- }
- static bool message_write_handler(struct l_io *io, void *user_data)
- {
- struct l_dbus *dbus = user_data;
- struct l_dbus_message *message;
- struct message_callback *callback;
- const void *header, *body;
- size_t header_size, body_size;
- callback = l_queue_pop_head(dbus->message_queue);
- if (!callback)
- return false;
- message = callback->message;
- if (_dbus_message_get_type(message) == DBUS_MESSAGE_TYPE_METHOD_CALL &&
- callback->callback == NULL)
- l_dbus_message_set_no_reply(message, true);
- _dbus_message_set_serial(message, callback->serial);
- if (!dbus->driver->send_message(dbus, message)) {
- message_queue_destroy(callback);
- return false;
- }
- header = _dbus_message_get_header(message, &header_size);
- body = _dbus_message_get_body(message, &body_size);
- l_util_hexdump_two(false, header, header_size, body, body_size,
- dbus->debug_handler, dbus->debug_data);
- if (callback->callback == NULL) {
- message_queue_destroy(callback);
- goto done;
- }
- l_hashmap_insert(dbus->message_list,
- L_UINT_TO_PTR(callback->serial), callback);
- done:
- if (l_queue_isempty(dbus->message_queue))
- return false;
- /* Only continue sending messges if the connection is ready */
- return dbus->is_ready;
- }
- static void handle_method_return(struct l_dbus *dbus,
- struct l_dbus_message *message)
- {
- struct message_callback *callback;
- uint32_t reply_serial;
- reply_serial = _dbus_message_get_reply_serial(message);
- if (reply_serial == 0)
- return;
- callback = l_hashmap_remove(dbus->message_list,
- L_UINT_TO_PTR(reply_serial));
- if (!callback)
- return;
- if (callback->callback)
- callback->callback(message, callback->user_data);
- message_queue_destroy(callback);
- }
- static void handle_error(struct l_dbus *dbus, struct l_dbus_message *message)
- {
- struct message_callback *callback;
- uint32_t reply_serial;
- reply_serial = _dbus_message_get_reply_serial(message);
- if (reply_serial == 0)
- return;
- callback = l_hashmap_remove(dbus->message_list,
- L_UINT_TO_PTR(reply_serial));
- if (!callback)
- return;
- if (callback->callback)
- callback->callback(message, callback->user_data);
- message_queue_destroy(callback);
- }
- static void process_signal(const void *key, void *value, void *user_data)
- {
- struct signal_callback *callback = value;
- struct l_dbus_message *message = user_data;
- if (callback->callback)
- callback->callback(message, callback->user_data);
- }
- static void handle_signal(struct l_dbus *dbus, struct l_dbus_message *message)
- {
- l_hashmap_foreach(dbus->signal_list, process_signal, message);
- }
- static bool message_read_handler(struct l_io *io, void *user_data)
- {
- struct l_dbus *dbus = user_data;
- struct l_dbus_message *message;
- const void *header, *body;
- size_t header_size, body_size;
- enum dbus_message_type msgtype;
- message = dbus->driver->recv_message(dbus);
- if (!message)
- return true;
- header = _dbus_message_get_header(message, &header_size);
- body = _dbus_message_get_body(message, &body_size);
- l_util_hexdump_two(true, header, header_size, body, body_size,
- dbus->debug_handler, dbus->debug_data);
- msgtype = _dbus_message_get_type(message);
- switch (msgtype) {
- case DBUS_MESSAGE_TYPE_METHOD_RETURN:
- handle_method_return(dbus, message);
- break;
- case DBUS_MESSAGE_TYPE_ERROR:
- handle_error(dbus, message);
- break;
- case DBUS_MESSAGE_TYPE_SIGNAL:
- handle_signal(dbus, message);
- break;
- case DBUS_MESSAGE_TYPE_METHOD_CALL:
- if (!_dbus_object_tree_dispatch(dbus->tree, dbus, message)) {
- struct l_dbus_message *error;
- error = l_dbus_message_new_error(message,
- "org.freedesktop.DBus.Error.NotFound",
- "No matching method found");
- l_dbus_send(dbus, error);
- }
- break;
- }
- l_dbus_message_unref(message);
- return true;
- }
- static uint32_t send_message(struct l_dbus *dbus, bool priority,
- struct l_dbus_message *message,
- l_dbus_message_func_t function,
- void *user_data, l_dbus_destroy_func_t destroy)
- {
- struct message_callback *callback;
- enum dbus_message_type type;
- const char *path;
- type = _dbus_message_get_type(message);
- if ((type == DBUS_MESSAGE_TYPE_METHOD_RETURN ||
- type == DBUS_MESSAGE_TYPE_ERROR) &&
- _dbus_message_get_reply_serial(message) == 0) {
- l_dbus_message_unref(message);
- return 0;
- }
- /* Default empty signature for method return messages */
- if (type == DBUS_MESSAGE_TYPE_METHOD_RETURN &&
- !l_dbus_message_get_signature(message))
- l_dbus_message_set_arguments(message, "");
- callback = l_new(struct message_callback, 1);
- callback->serial = dbus->next_serial++;
- callback->message = message;
- callback->callback = function;
- callback->destroy = destroy;
- callback->user_data = user_data;
- if (priority) {
- l_queue_push_head(dbus->message_queue, callback);
- l_io_set_write_handler(dbus->io, message_write_handler,
- dbus, NULL);
- return callback->serial;
- }
- path = l_dbus_message_get_path(message);
- if (path)
- _dbus_object_tree_signals_flush(dbus, path);
- l_queue_push_tail(dbus->message_queue, callback);
- if (dbus->is_ready)
- l_io_set_write_handler(dbus->io, message_write_handler,
- dbus, NULL);
- return callback->serial;
- }
- static void bus_ready(struct l_dbus *dbus)
- {
- dbus->is_ready = true;
- if (dbus->ready_handler)
- dbus->ready_handler(dbus->ready_data);
- l_io_set_read_handler(dbus->io, message_read_handler, dbus, NULL);
- /* Check for messages added before the connection was ready */
- if (l_queue_isempty(dbus->message_queue))
- return;
- l_io_set_write_handler(dbus->io, message_write_handler, dbus, NULL);
- }
- static void hello_callback(struct l_dbus_message *message, void *user_data)
- {
- struct l_dbus *dbus = user_data;
- const char *signature;
- const char *unique_name;
- signature = l_dbus_message_get_signature(message);
- if (!signature || strcmp(signature, "s")) {
- close(l_io_get_fd(dbus->io));
- return;
- }
- if (!l_dbus_message_get_arguments(message, "s", &unique_name)) {
- close(l_io_get_fd(dbus->io));
- return;
- }
- dbus->unique_name = l_strdup(unique_name);
- bus_ready(dbus);
- }
- static bool auth_write_handler(struct l_io *io, void *user_data)
- {
- struct l_dbus_classic *classic = user_data;
- struct l_dbus *dbus = &classic->super;
- ssize_t written, len;
- int fd;
- fd = l_io_get_fd(io);
- if (!classic->auth_command)
- return false;
- len = strlen(classic->auth_command);
- if (!len)
- return false;
- written = L_TFR(send(fd, classic->auth_command, len, 0));
- if (written < 0)
- return false;
- l_util_hexdump(false, classic->auth_command, written,
- dbus->debug_handler, dbus->debug_data);
- if (written < len) {
- memmove(classic->auth_command, classic->auth_command + written,
- len + 1 - written);
- return true;
- }
- l_free(classic->auth_command);
- classic->auth_command = NULL;
- if (classic->auth_state == SETUP_DONE) {
- struct l_dbus_message *message;
- l_io_set_read_handler(dbus->io, message_read_handler,
- dbus, NULL);
- message = l_dbus_message_new_method_call(dbus,
- DBUS_SERVICE_DBUS,
- DBUS_PATH_DBUS,
- L_DBUS_INTERFACE_DBUS,
- "Hello");
- l_dbus_message_set_arguments(message, "");
- send_message(dbus, true, message, hello_callback, dbus, NULL);
- return true;
- }
- return false;
- }
- static bool auth_read_handler(struct l_io *io, void *user_data)
- {
- struct l_dbus_classic *classic = user_data;
- struct l_dbus *dbus = &classic->super;
- char buffer[64];
- char *ptr, *end;
- ssize_t offset, len;
- int fd;
- fd = l_io_get_fd(io);
- ptr = buffer;
- offset = 0;
- while (1) {
- len = L_TFR(recv(fd, ptr + offset,
- sizeof(buffer) - offset,
- MSG_DONTWAIT));
- if (len < 0) {
- if (errno != EAGAIN)
- return false;
- break;
- }
- offset += len;
- }
- ptr = buffer;
- len = offset;
- if (!ptr || len < 3)
- return true;
- end = strstr(ptr, "\r\n");
- if (!end)
- return true;
- if (end - ptr + 2 != len)
- return true;
- l_util_hexdump(true, ptr, len, dbus->debug_handler, dbus->debug_data);
- *end = '\0';
- switch (classic->auth_state) {
- case WAITING_FOR_OK:
- if (!strncmp(ptr, "OK ", 3)) {
- enum auth_state state;
- const char *command;
- if (dbus->negotiate_unix_fd) {
- command = "NEGOTIATE_UNIX_FD\r\n";
- state = WAITING_FOR_AGREE_UNIX_FD;
- } else {
- command = "BEGIN\r\n";
- state = SETUP_DONE;
- }
- l_free(dbus->guid);
- dbus->guid = l_strdup(ptr + 3);
- classic->auth_command = l_strdup(command);
- classic->auth_state = state;
- break;
- } else if (!strncmp(ptr, "REJECTED ", 9)) {
- static const char *command = "AUTH ANONYMOUS\r\n";
- dbus->negotiate_unix_fd = true;
- classic->auth_command = l_strdup(command);
- classic->auth_state = WAITING_FOR_OK;
- }
- break;
- case WAITING_FOR_AGREE_UNIX_FD:
- if (!strncmp(ptr, "AGREE_UNIX_FD", 13)) {
- static const char *command = "BEGIN\r\n";
- dbus->support_unix_fd = true;
- classic->auth_command = l_strdup(command);
- classic->auth_state = SETUP_DONE;
- break;
- } else if (!strncmp(ptr, "ERROR", 5)) {
- static const char *command = "BEGIN\r\n";
- dbus->support_unix_fd = false;
- classic->auth_command = l_strdup(command);
- classic->auth_state = SETUP_DONE;
- break;
- }
- break;
- case SETUP_DONE:
- break;
- }
- l_io_set_write_handler(io, auth_write_handler, dbus, NULL);
- return true;
- }
- static void disconnect_handler(struct l_io *io, void *user_data)
- {
- struct l_dbus *dbus = user_data;
- dbus->is_ready = false;
- l_util_debug(dbus->debug_handler, dbus->debug_data, "disconnect");
- if (dbus->disconnect_handler)
- dbus->disconnect_handler(dbus->disconnect_data);
- }
- static void dbus_init(struct l_dbus *dbus, int fd)
- {
- dbus->io = l_io_new(fd);
- l_io_set_close_on_destroy(dbus->io, true);
- l_io_set_disconnect_handler(dbus->io, disconnect_handler, dbus, NULL);
- dbus->is_ready = false;
- dbus->next_id = 1;
- dbus->next_serial = 1;
- dbus->message_queue = l_queue_new();
- dbus->message_list = l_hashmap_new();
- dbus->signal_list = l_hashmap_new();
- dbus->tree = _dbus_object_tree_new();
- }
- static void classic_free(struct l_dbus *dbus)
- {
- struct l_dbus_classic *classic =
- l_container_of(dbus, struct l_dbus_classic, super);
- unsigned int i;
- for (i = 0; i < classic->num_fds; i++)
- close(classic->fd_buf[i]);
- l_free(classic->fd_buf);
- l_free(classic->auth_command);
- l_hashmap_destroy(classic->match_strings, l_free);
- l_free(classic);
- }
- static bool classic_send_message(struct l_dbus *dbus,
- struct l_dbus_message *message)
- {
- int fd = l_io_get_fd(dbus->io);
- struct msghdr msg;
- struct iovec iov[2], *iovpos;
- ssize_t r;
- int *fds = NULL;
- uint32_t num_fds = 0;
- struct cmsghdr *cmsg;
- int iovlen;
- iov[0].iov_base = _dbus_message_get_header(message, &iov[0].iov_len);
- iov[1].iov_base = _dbus_message_get_body(message, &iov[1].iov_len);
- if (dbus->support_unix_fd)
- fds = _dbus_message_get_fds(message, &num_fds);
- iovpos = iov;
- iovlen = 2;
- while (1) {
- memset(&msg, 0, sizeof(msg));
- msg.msg_iov = iovpos;
- msg.msg_iovlen = iovlen;
- if (num_fds) {
- msg.msg_control =
- alloca(CMSG_SPACE(num_fds * sizeof(int)));
- msg.msg_controllen = CMSG_LEN(num_fds * sizeof(int));
- cmsg = CMSG_FIRSTHDR(&msg);
- cmsg->cmsg_len = msg.msg_controllen;
- cmsg->cmsg_level = SOL_SOCKET;
- cmsg->cmsg_type = SCM_RIGHTS;
- memcpy(CMSG_DATA(cmsg), fds, num_fds * sizeof(int));
- }
- r = L_TFR(sendmsg(fd, &msg, 0));
- if (r < 0)
- return false;
- while ((size_t) r >= iovpos->iov_len) {
- r -= iovpos->iov_len;
- iovpos++;
- iovlen--;
- if (!iovlen)
- break;
- }
- if (!iovlen)
- break;
- iovpos->iov_base += r;
- iovpos->iov_len -= r;
- /* The FDs have been transmitted, don't retransmit */
- num_fds = 0;
- }
- return true;
- }
- static struct l_dbus_message *classic_recv_message(struct l_dbus *dbus)
- {
- struct l_dbus_classic *classic =
- l_container_of(dbus, struct l_dbus_classic, super);
- int fd = l_io_get_fd(dbus->io);
- struct dbus_header hdr;
- struct msghdr msg;
- struct iovec iov[2], *iovpos;
- struct cmsghdr *cmsg;
- ssize_t len, r;
- void *header, *body;
- size_t header_size, body_size;
- union {
- uint8_t bytes[CMSG_SPACE(16 * sizeof(int))];
- struct cmsghdr align;
- } fd_buf;
- int *fds = NULL;
- uint32_t num_fds = 0;
- int iovlen;
- struct l_dbus_message *message;
- unsigned int i;
- len = recv(fd, &hdr, DBUS_HEADER_SIZE, MSG_PEEK | MSG_DONTWAIT);
- if (len != DBUS_HEADER_SIZE)
- return NULL;
- header_size = align_len(DBUS_HEADER_SIZE + hdr.dbus1.field_length, 8);
- header = l_malloc(header_size);
- body_size = hdr.dbus1.body_length;
- body = l_malloc(body_size);
- iov[0].iov_base = header;
- iov[0].iov_len = header_size;
- iov[1].iov_base = body;
- iov[1].iov_len = body_size;
- iovpos = iov;
- iovlen = 2;
- while (1) {
- memset(&msg, 0, sizeof(msg));
- msg.msg_iov = iovpos;
- msg.msg_iovlen = iovlen;
- msg.msg_control = &fd_buf;
- msg.msg_controllen = sizeof(fd_buf);
- r = L_TFR(recvmsg(fd, &msg,
- MSG_CMSG_CLOEXEC | MSG_WAITALL));
- if (r < 0)
- goto cmsg_fail;
- for (cmsg = CMSG_FIRSTHDR(&msg); cmsg;
- cmsg = CMSG_NXTHDR(&msg, cmsg)) {
- if (cmsg->cmsg_level != SOL_SOCKET ||
- cmsg->cmsg_type != SCM_RIGHTS)
- continue;
- num_fds = (cmsg->cmsg_len - CMSG_LEN(0)) / sizeof(int);
- fds = (void *) CMSG_DATA(cmsg);
- /* Set FD_CLOEXEC on all file descriptors */
- for (i = 0; i < num_fds; i++) {
- long flags;
- flags = fcntl(fds[i], F_GETFD, NULL);
- if (flags < 0)
- continue;
- if (!(flags & FD_CLOEXEC))
- fcntl(fds[i], F_SETFD,
- flags | FD_CLOEXEC);
- }
- classic->fd_buf = l_realloc(classic->fd_buf,
- (classic->num_fds + num_fds) *
- sizeof(int));
- memcpy(classic->fd_buf + classic->num_fds, fds,
- num_fds * sizeof(int));
- classic->num_fds += num_fds;
- }
- while ((size_t) r >= iovpos->iov_len) {
- r -= iovpos->iov_len;
- iovpos++;
- iovlen--;
- if (!iovlen)
- break;
- }
- if (!iovlen)
- break;
- iovpos->iov_base += r;
- iovpos->iov_len -= r;
- }
- if (hdr.endian != DBUS_NATIVE_ENDIAN) {
- l_util_debug(dbus->debug_handler,
- dbus->debug_data, "Endianness incorrect");
- goto bad_msg;
- }
- if (hdr.version != 1) {
- l_util_debug(dbus->debug_handler,
- dbus->debug_data, "Protocol version incorrect");
- goto bad_msg;
- }
- num_fds = _dbus_message_unix_fds_from_header(header, header_size);
- if (num_fds > classic->num_fds)
- goto bad_msg;
- message = dbus_message_build(header, header_size, body, body_size,
- classic->fd_buf, num_fds);
- if (message && num_fds) {
- if (classic->num_fds > num_fds) {
- memmove(classic->fd_buf, classic->fd_buf + num_fds,
- (classic->num_fds - num_fds) * sizeof(int));
- classic->num_fds -= num_fds;
- } else {
- l_free(classic->fd_buf);
- classic->fd_buf = NULL;
- classic->num_fds = 0;
- }
- }
- if (message)
- return message;
- bad_msg:
- cmsg_fail:
- for (i = 0; i < classic->num_fds; i++)
- close(classic->fd_buf[i]);
- l_free(classic->fd_buf);
- classic->fd_buf = NULL;
- classic->num_fds = 0;
- l_free(header);
- l_free(body);
- return NULL;
- }
- static bool classic_add_match(struct l_dbus *dbus, unsigned int id,
- const struct _dbus_filter_condition *rule,
- int rule_len)
- {
- struct l_dbus_classic *classic =
- l_container_of(dbus, struct l_dbus_classic, super);
- char *match_str;
- struct l_dbus_message *message;
- match_str = _dbus_filter_rule_to_str(rule, rule_len);
- l_hashmap_insert(classic->match_strings, L_UINT_TO_PTR(id), match_str);
- message = l_dbus_message_new_method_call(dbus,
- DBUS_SERVICE_DBUS,
- DBUS_PATH_DBUS,
- L_DBUS_INTERFACE_DBUS,
- "AddMatch");
- l_dbus_message_set_arguments(message, "s", match_str);
- send_message(dbus, false, message, NULL, NULL, NULL);
- return true;
- }
- static bool classic_remove_match(struct l_dbus *dbus, unsigned int id)
- {
- struct l_dbus_classic *classic =
- l_container_of(dbus, struct l_dbus_classic, super);
- char *match_str = l_hashmap_remove(classic->match_strings,
- L_UINT_TO_PTR(id));
- struct l_dbus_message *message;
- if (!match_str)
- return false;
- message = l_dbus_message_new_method_call(dbus,
- DBUS_SERVICE_DBUS,
- DBUS_PATH_DBUS,
- L_DBUS_INTERFACE_DBUS,
- "RemoveMatch");
- l_dbus_message_set_arguments(message, "s", match_str);
- send_message(dbus, false, message, NULL, NULL, NULL);
- l_free(match_str);
- return true;
- }
- static void name_owner_changed_cb(struct l_dbus_message *message,
- void *user_data)
- {
- struct l_dbus *dbus = user_data;
- char *name, *old, *new;
- if (!l_dbus_message_get_arguments(message, "sss", &name, &old, &new))
- return;
- _dbus_name_cache_notify(dbus->name_cache, name, new);
- }
- struct get_name_owner_request {
- struct l_dbus_message *message;
- struct l_dbus *dbus;
- };
- static void get_name_owner_reply_cb(struct l_dbus_message *reply,
- void *user_data)
- {
- struct get_name_owner_request *req = user_data;
- const char *name, *owner;
- /* No name owner yet */
- if (l_dbus_message_is_error(reply))
- return;
- /* Shouldn't happen */
- if (!l_dbus_message_get_arguments(reply, "s", &owner))
- return;
- /* Shouldn't happen */
- if (!l_dbus_message_get_arguments(req->message, "s", &name))
- return;
- _dbus_name_cache_notify(req->dbus->name_cache, name, owner);
- }
- static bool classic_get_name_owner(struct l_dbus *bus, const char *name)
- {
- struct get_name_owner_request *req;
- /* Name resolution is not performed for DBUS_SERVICE_DBUS */
- if (!strcmp(name, DBUS_SERVICE_DBUS))
- return false;
- req = l_new(struct get_name_owner_request, 1);
- req->dbus = bus;
- req->message = l_dbus_message_new_method_call(bus,
- DBUS_SERVICE_DBUS,
- DBUS_PATH_DBUS,
- L_DBUS_INTERFACE_DBUS,
- "GetNameOwner");
- l_dbus_message_set_arguments(req->message, "s", name);
- send_message(bus, false, req->message, get_name_owner_reply_cb,
- req, l_free);
- if (!bus->name_notify_enabled) {
- static struct _dbus_filter_condition rule[] = {
- { L_DBUS_MATCH_TYPE, "signal" },
- { L_DBUS_MATCH_SENDER, DBUS_SERVICE_DBUS },
- { L_DBUS_MATCH_PATH, DBUS_PATH_DBUS },
- { L_DBUS_MATCH_INTERFACE, L_DBUS_INTERFACE_DBUS },
- { L_DBUS_MATCH_MEMBER, "NameOwnerChanged" },
- };
- if (!bus->filter)
- bus->filter = _dbus_filter_new(bus,
- &bus->driver->filter_ops,
- bus->name_cache);
- _dbus_filter_add_rule(bus->filter, rule, L_ARRAY_SIZE(rule),
- name_owner_changed_cb, bus);
- bus->name_notify_enabled = true;
- }
- return true;
- }
- struct name_request {
- l_dbus_name_acquire_func_t callback;
- void *user_data;
- struct l_dbus *dbus;
- };
- enum dbus_name_flag {
- DBUS_NAME_FLAG_ALLOW_REPLACEMENT = 0x1,
- DBUS_NAME_FLAG_REPLACE_EXISTING = 0x2,
- DBUS_NAME_FLAG_DO_NOT_QUEUE = 0x4,
- };
- enum dbus_name_reply {
- DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER = 1,
- DBUS_REQUEST_NAME_REPLY_IN_QUEUE = 2,
- DBUS_REQUEST_NAME_REPLY_EXISTS = 3,
- DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER = 4,
- };
- static void request_name_reply_cb(struct l_dbus_message *reply, void *user_data)
- {
- struct name_request *req = user_data;
- bool success = false, queued = false;
- uint32_t retval;
- if (!req->callback)
- return;
- /* No name owner yet */
- if (l_dbus_message_is_error(reply))
- goto call_back;
- /* Shouldn't happen */
- if (!l_dbus_message_get_arguments(reply, "u", &retval))
- goto call_back;
- success = (retval == DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) ||
- (retval == DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER) ||
- (retval == DBUS_REQUEST_NAME_REPLY_IN_QUEUE);
- queued = (retval == DBUS_REQUEST_NAME_REPLY_IN_QUEUE);
- call_back:
- req->callback(req->dbus, success, queued, req->user_data);
- }
- static uint32_t classic_name_acquire(struct l_dbus *dbus, const char *name,
- bool allow_replacement,
- bool replace_existing, bool queue,
- l_dbus_name_acquire_func_t callback,
- void *user_data)
- {
- struct name_request *req;
- struct l_dbus_message *message;
- uint32_t flags = 0;
- req = l_new(struct name_request, 1);
- req->dbus = dbus;
- req->user_data = user_data;
- req->callback = callback;
- message = l_dbus_message_new_method_call(dbus, DBUS_SERVICE_DBUS,
- DBUS_PATH_DBUS,
- L_DBUS_INTERFACE_DBUS,
- "RequestName");
- if (allow_replacement)
- flags |= DBUS_NAME_FLAG_ALLOW_REPLACEMENT;
- if (replace_existing)
- flags |= DBUS_NAME_FLAG_REPLACE_EXISTING;
- if (!queue)
- flags |= DBUS_NAME_FLAG_DO_NOT_QUEUE;
- l_dbus_message_set_arguments(message, "su", name, flags);
- return send_message(dbus, false, message, request_name_reply_cb,
- req, free);
- }
- static const struct l_dbus_ops classic_ops = {
- .version = 1,
- .send_message = classic_send_message,
- .recv_message = classic_recv_message,
- .free = classic_free,
- .name_ops = {
- .get_name_owner = classic_get_name_owner,
- },
- .filter_ops = {
- .add_match = classic_add_match,
- .remove_match = classic_remove_match,
- },
- .name_acquire = classic_name_acquire,
- };
- static struct l_dbus *setup_dbus1(int fd, const char *guid)
- {
- static const unsigned char creds = 0x00;
- char uid[6], hexuid[12], *ptr = hexuid;
- struct l_dbus *dbus;
- struct l_dbus_classic *classic;
- ssize_t written;
- unsigned int i;
- if (snprintf(uid, sizeof(uid), "%d", geteuid()) < 1) {
- close(fd);
- return NULL;
- }
- for (i = 0; i < strlen(uid); i++)
- ptr += sprintf(ptr, "%02x", uid[i]);
- /* Send special credentials-passing nul byte */
- written = L_TFR(send(fd, &creds, 1, 0));
- if (written < 1) {
- close(fd);
- return NULL;
- }
- classic = l_new(struct l_dbus_classic, 1);
- dbus = &classic->super;
- dbus->driver = &classic_ops;
- classic->match_strings = l_hashmap_new();
- dbus_init(dbus, fd);
- dbus->guid = l_strdup(guid);
- classic->auth_command = l_strdup_printf("AUTH EXTERNAL %s\r\n", hexuid);
- classic->auth_state = WAITING_FOR_OK;
- dbus->negotiate_unix_fd = true;
- dbus->support_unix_fd = false;
- l_io_set_read_handler(dbus->io, auth_read_handler, dbus, NULL);
- l_io_set_write_handler(dbus->io, auth_write_handler, dbus, NULL);
- return dbus;
- }
- static struct l_dbus *setup_unix(char *params)
- {
- char *path = NULL, *guid = NULL;
- bool abstract = false;
- struct sockaddr_un addr;
- size_t len;
- int fd;
- while (params) {
- char *key = strsep(¶ms, ",");
- char *value;
- if (!key)
- break;
- value = strchr(key, '=');
- if (!value)
- continue;
- *value++ = '\0';
- if (!strcmp(key, "path")) {
- path = value;
- abstract = false;
- } else if (!strcmp(key, "abstract")) {
- path = value;
- abstract = true;
- } else if (!strcmp(key, "guid"))
- guid = value;
- }
- if (!path)
- return NULL;
- fd = socket(PF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);
- if (fd < 0)
- return NULL;
- memset(&addr, 0, sizeof(addr));
- addr.sun_family = AF_UNIX;
- len = strlen(path);
- if (abstract) {
- if (len > sizeof(addr.sun_path) - 1) {
- close(fd);
- return NULL;
- }
- addr.sun_path[0] = '\0';
- strncpy(addr.sun_path + 1, path, sizeof(addr.sun_path) - 2);
- len++;
- } else {
- if (len > sizeof(addr.sun_path)) {
- close(fd);
- return NULL;
- }
- strncpy(addr.sun_path, path, sizeof(addr.sun_path) - 1);
- }
- if (connect(fd, (struct sockaddr *) &addr,
- sizeof(addr.sun_family) + len) < 0) {
- close(fd);
- return NULL;
- }
- return setup_dbus1(fd, guid);
- }
- static struct l_dbus *setup_address(const char *address)
- {
- struct l_dbus *dbus = NULL;
- char *address_copy;
- address_copy = strdupa(address);
- while (address_copy) {
- char *transport = strsep(&address_copy, ";");
- char *params;
- if (!transport)
- break;
- params = strchr(transport, ':');
- if (params)
- *params++ = '\0';
- if (!strcmp(transport, "unix")) {
- /* Function will modify params string */
- dbus = setup_unix(params);
- break;
- }
- }
- return dbus;
- }
- LIB_EXPORT struct l_dbus *l_dbus_new(const char *address)
- {
- if (unlikely(!address))
- return NULL;
- return setup_address(address);
- }
- LIB_EXPORT struct l_dbus *l_dbus_new_default(enum l_dbus_bus bus)
- {
- const char *address;
- switch (bus) {
- case L_DBUS_SYSTEM_BUS:
- address = getenv("DBUS_SYSTEM_BUS_ADDRESS");
- if (!address)
- address = DEFAULT_SYSTEM_BUS_ADDRESS;
- break;
- case L_DBUS_SESSION_BUS:
- address = getenv("DBUS_SESSION_BUS_ADDRESS");
- if (!address)
- return NULL;
- break;
- default:
- return NULL;
- }
- return setup_address(address);
- }
- LIB_EXPORT void l_dbus_destroy(struct l_dbus *dbus)
- {
- if (unlikely(!dbus))
- return;
- if (dbus->ready_destroy)
- dbus->ready_destroy(dbus->ready_data);
- _dbus_filter_free(dbus->filter);
- _dbus_name_cache_free(dbus->name_cache);
- l_hashmap_destroy(dbus->signal_list, signal_list_destroy);
- l_hashmap_destroy(dbus->message_list, message_list_destroy);
- l_queue_destroy(dbus->message_queue, message_queue_destroy);
- l_io_destroy(dbus->io);
- if (dbus->disconnect_destroy)
- dbus->disconnect_destroy(dbus->disconnect_data);
- if (dbus->debug_destroy)
- dbus->debug_destroy(dbus->debug_data);
- l_free(dbus->guid);
- l_free(dbus->unique_name);
- _dbus_object_tree_free(dbus->tree);
- dbus->driver->free(dbus);
- }
- LIB_EXPORT bool l_dbus_set_ready_handler(struct l_dbus *dbus,
- l_dbus_ready_func_t function,
- void *user_data, l_dbus_destroy_func_t destroy)
- {
- if (unlikely(!dbus))
- return false;
- if (dbus->ready_destroy)
- dbus->ready_destroy(dbus->ready_data);
- dbus->ready_handler = function;
- dbus->ready_destroy = destroy;
- dbus->ready_data = user_data;
- return true;
- }
- LIB_EXPORT bool l_dbus_set_disconnect_handler(struct l_dbus *dbus,
- l_dbus_disconnect_func_t function,
- void *user_data, l_dbus_destroy_func_t destroy)
- {
- if (unlikely(!dbus))
- return false;
- if (dbus->disconnect_destroy)
- dbus->disconnect_destroy(dbus->disconnect_data);
- dbus->disconnect_handler = function;
- dbus->disconnect_destroy = destroy;
- dbus->disconnect_data = user_data;
- return true;
- }
- LIB_EXPORT bool l_dbus_set_debug(struct l_dbus *dbus,
- l_dbus_debug_func_t function,
- void *user_data, l_dbus_destroy_func_t destroy)
- {
- if (unlikely(!dbus))
- return false;
- if (dbus->debug_destroy)
- dbus->debug_destroy(dbus->debug_data);
- dbus->debug_handler = function;
- dbus->debug_destroy = destroy;
- dbus->debug_data = user_data;
- /* l_io_set_debug(dbus->io, function, user_data, NULL); */
- return true;
- }
- LIB_EXPORT uint32_t l_dbus_send_with_reply(struct l_dbus *dbus,
- struct l_dbus_message *message,
- l_dbus_message_func_t function,
- void *user_data,
- l_dbus_destroy_func_t destroy)
- {
- if (unlikely(!dbus || !message))
- return 0;
- return send_message(dbus, false, message, function, user_data, destroy);
- }
- LIB_EXPORT uint32_t l_dbus_send(struct l_dbus *dbus,
- struct l_dbus_message *message)
- {
- if (unlikely(!dbus || !message))
- return 0;
- return send_message(dbus, false, message, NULL, NULL, NULL);
- }
- static bool remove_entry(void *data, void *user_data)
- {
- struct message_callback *callback = data;
- uint32_t serial = L_PTR_TO_UINT(user_data);
- if (callback->serial == serial) {
- message_queue_destroy(callback);
- return true;
- }
- return false;
- }
- LIB_EXPORT bool l_dbus_cancel(struct l_dbus *dbus, uint32_t serial)
- {
- struct message_callback *callback;
- unsigned int count;
- if (unlikely(!dbus || !serial))
- return false;
- callback = l_hashmap_remove(dbus->message_list, L_UINT_TO_PTR(serial));
- if (callback) {
- message_queue_destroy(callback);
- return true;
- }
- count = l_queue_foreach_remove(dbus->message_queue, remove_entry,
- L_UINT_TO_PTR(serial));
- if (!count)
- return false;
- return true;
- }
- LIB_EXPORT unsigned int l_dbus_register(struct l_dbus *dbus,
- l_dbus_message_func_t function,
- void *user_data, l_dbus_destroy_func_t destroy)
- {
- struct signal_callback *callback;
- if (unlikely(!dbus))
- return 0;
- callback = l_new(struct signal_callback, 1);
- callback->id = dbus->next_id++;
- callback->callback = function;
- callback->destroy = destroy;
- callback->user_data = user_data;
- l_hashmap_insert(dbus->signal_list,
- L_UINT_TO_PTR(callback->id), callback);
- return callback->id;
- }
- LIB_EXPORT bool l_dbus_unregister(struct l_dbus *dbus, unsigned int id)
- {
- struct signal_callback *callback;
- if (unlikely(!dbus || !id))
- return false;
- callback = l_hashmap_remove(dbus->signal_list, L_UINT_TO_PTR(id));
- if (!callback)
- return false;
- signal_list_destroy(callback);
- return true;
- }
- LIB_EXPORT uint32_t l_dbus_method_call(struct l_dbus *dbus,
- const char *destination, const char *path,
- const char *interface, const char *method,
- l_dbus_message_func_t setup,
- l_dbus_message_func_t function,
- void *user_data, l_dbus_destroy_func_t destroy)
- {
- struct l_dbus_message *message;
- if (unlikely(!dbus))
- return 0;
- message = l_dbus_message_new_method_call(dbus, destination, path,
- interface, method);
- if (setup)
- setup(message, user_data);
- else
- l_dbus_message_set_arguments(message, "");
- return send_message(dbus, false, message, function, user_data, destroy);
- }
- uint8_t _dbus_get_version(struct l_dbus *dbus)
- {
- return dbus->driver->version;
- }
- int _dbus_get_fd(struct l_dbus *dbus)
- {
- return l_io_get_fd(dbus->io);
- }
- struct _dbus_object_tree *_dbus_get_tree(struct l_dbus *dbus)
- {
- return dbus->tree;
- }
- /**
- * l_dbus_register_interface:
- * @dbus: D-Bus connection as returned by @l_dbus_new*
- * @interface: interface name string
- * @setup_func: function that sets up the methods, signals and properties by
- * using the #dbus-service.h API.
- * @destroy: optional destructor to be called every time an instance of this
- * interface is being removed from an object on this bus.
- * @handle_old_style_properties: whether to automatically handle SetProperty and
- * GetProperties for any properties registered by
- * @setup_func.
- *
- * Registers an interface. If successful the interface can then be added
- * to any number of objects with @l_dbus_object_add_interface.
- *
- * Returns: whether the interface was successfully registered
- **/
- LIB_EXPORT bool l_dbus_register_interface(struct l_dbus *dbus,
- const char *interface,
- l_dbus_interface_setup_func_t setup_func,
- l_dbus_destroy_func_t destroy,
- bool handle_old_style_properties)
- {
- if (unlikely(!dbus))
- return false;
- if (unlikely(!dbus->tree))
- return false;
- return _dbus_object_tree_register_interface(dbus->tree, interface,
- setup_func, destroy,
- handle_old_style_properties);
- }
- LIB_EXPORT bool l_dbus_unregister_interface(struct l_dbus *dbus,
- const char *interface)
- {
- if (unlikely(!dbus))
- return false;
- if (unlikely(!dbus->tree))
- return false;
- return _dbus_object_tree_unregister_interface(dbus->tree, interface);
- }
- /**
- * l_dbus_register_object:
- * @dbus: D-Bus connection
- * @path: new object path
- * @user_data: user pointer to be passed to @destroy if any
- * @destroy: optional destructor to be called when object dropped from the tree
- * @...: NULL-terminated list of 0 or more interfaces to be present on the
- * object from the moment of creation. For every interface the interface
- * name string is expected followed by the @user_data pointer same as
- * would be passed as @l_dbus_object_add_interface's last two parameters.
- *
- * Create a new D-Bus object on the tree visible to D-Bus peers. For example:
- * success = l_dbus_register_object(bus, "/org/example/ExampleManager",
- * NULL, NULL,
- * "org.example.Manager",
- * manager_data,
- * NULL);
- *
- * Returns: whether the object path was successfully registered
- **/
- LIB_EXPORT bool l_dbus_register_object(struct l_dbus *dbus, const char *path,
- void *user_data,
- l_dbus_destroy_func_t destroy, ...)
- {
- va_list args;
- const char *interface;
- void *if_user_data;
- bool r = true;
- if (unlikely(!dbus))
- return false;
- if (unlikely(!dbus->tree))
- return false;
- if (!_dbus_object_tree_new_object(dbus->tree, path, user_data, destroy))
- return false;
- va_start(args, destroy);
- while ((interface = va_arg(args, const char *))) {
- if_user_data = va_arg(args, void *);
- if (!_dbus_object_tree_add_interface(dbus->tree, path,
- interface,
- if_user_data)) {
- _dbus_object_tree_object_destroy(dbus->tree, path);
- r = false;
- break;
- }
- }
- va_end(args);
- return r;
- }
- LIB_EXPORT bool l_dbus_unregister_object(struct l_dbus *dbus,
- const char *object)
- {
- if (unlikely(!dbus))
- return false;
- if (unlikely(!dbus->tree))
- return false;
- return _dbus_object_tree_object_destroy(dbus->tree, object);
- }
- /**
- * l_dbus_object_add_interface:
- * @dbus: D-Bus connection
- * @object: object path as passed to @l_dbus_register_object
- * @interface: interface name as passed to @l_dbus_register_interface
- * @user_data: user data pointer to be passed to any method and property
- * callbacks provided by the @setup_func and to the @destroy
- * callback as passed to @l_dbus_register_interface
- *
- * Creates an instance of given interface at the given path in the
- * connection's object tree. If no object was registered at this path
- * before @l_dbus_register_object gets called automatically.
- *
- * The addition of an interface to the object may trigger a query of
- * all the properties on this interface and
- * #org.freedesktop.DBus.ObjectManager.InterfacesAdded signals.
- *
- * Returns: whether the interface was successfully added.
- **/
- LIB_EXPORT bool l_dbus_object_add_interface(struct l_dbus *dbus,
- const char *object,
- const char *interface,
- void *user_data)
- {
- if (unlikely(!dbus))
- return false;
- if (unlikely(!dbus->tree))
- return false;
- return _dbus_object_tree_add_interface(dbus->tree, object, interface,
- user_data);
- }
- LIB_EXPORT bool l_dbus_object_remove_interface(struct l_dbus *dbus,
- const char *object,
- const char *interface)
- {
- if (unlikely(!dbus))
- return false;
- if (unlikely(!dbus->tree))
- return false;
- return _dbus_object_tree_remove_interface(dbus->tree, object,
- interface);
- }
- LIB_EXPORT void *l_dbus_object_get_data(struct l_dbus *dbus, const char *object,
- const char *interface)
- {
- if (unlikely(!dbus))
- return false;
- if (unlikely(!dbus->tree))
- return false;
- return _dbus_object_tree_get_interface_data(dbus->tree, object,
- interface);
- }
- LIB_EXPORT bool l_dbus_object_manager_enable(struct l_dbus *dbus,
- const char *root)
- {
- if (unlikely(!dbus))
- return false;
- if (unlikely(!dbus->tree))
- return false;
- return _dbus_object_tree_add_interface(dbus->tree, root,
- L_DBUS_INTERFACE_OBJECT_MANAGER,
- dbus);
- }
- LIB_EXPORT unsigned int l_dbus_add_disconnect_watch(struct l_dbus *dbus,
- const char *name,
- l_dbus_watch_func_t disconnect_func,
- void *user_data,
- l_dbus_destroy_func_t destroy)
- {
- return l_dbus_add_service_watch(dbus, name, NULL, disconnect_func,
- user_data, destroy);
- }
- LIB_EXPORT unsigned int l_dbus_add_service_watch(struct l_dbus *dbus,
- const char *name,
- l_dbus_watch_func_t connect_func,
- l_dbus_watch_func_t disconnect_func,
- void *user_data,
- l_dbus_destroy_func_t destroy)
- {
- if (!name)
- return 0;
- if (!dbus->name_cache)
- dbus->name_cache = _dbus_name_cache_new(dbus,
- &dbus->driver->name_ops);
- return _dbus_name_cache_add_watch(dbus->name_cache, name, connect_func,
- disconnect_func, user_data,
- destroy);
- }
- LIB_EXPORT bool l_dbus_remove_watch(struct l_dbus *dbus, unsigned int id)
- {
- if (!dbus->name_cache)
- return false;
- return _dbus_name_cache_remove_watch(dbus->name_cache, id);
- }
- /**
- * l_dbus_add_signal_watch:
- * @dbus: D-Bus connection
- * @sender: bus name to match the signal sender against or NULL to
- * match any sender
- * @path: object path to match the signal path against or NULL to
- * match any path
- * @interface: interface name to match the signal interface against
- * or NULL to match any interface
- * @member: name to match the signal name against or NULL to match any
- * signal
- * @...: a list of further conditions to be met by the signal followed
- * by three more mandatory parameters:
- * enum l_dbus_match_type list_end_marker,
- * l_dbus_message_func callback,
- * void *user_data,
- * The value L_DBUS_MATCH_NONE must be passed as the end of list
- * marker, followed by the signal match callback and user_data.
- * In the list, every condition is a pair of parameters:
- * enum l_dbus_match_type match_type, const char *value.
- *
- * Subscribe to a group of signals based on a set of conditions that
- * compare the signal's header fields and string arguments against given
- * values. For example:
- * signal_id = l_dbus_add_signal_watch(bus, "org.example", "/"
- * "org.example.Manager",
- * "PropertyChanged",
- * L_DBUS_MATCH_ARGUMENT(0),
- * "ExampleProperty",
- * L_DBUS_MATCH_NONE
- * manager_property_change_cb,
- * NULL);
- *
- * Returns: a non-zero signal filter identifier that can be passed to
- * l_dbus_remove_signal_watch to remove this filter rule, or
- * zero on failure.
- **/
- LIB_EXPORT unsigned int l_dbus_add_signal_watch(struct l_dbus *dbus,
- const char *sender,
- const char *path,
- const char *interface,
- const char *member, ...)
- {
- struct _dbus_filter_condition *rule;
- int rule_len;
- va_list args;
- const char *value;
- l_dbus_message_func_t signal_func;
- enum l_dbus_match_type type;
- void *user_data;
- unsigned int id;
- va_start(args, member);
- rule_len = 0;
- while ((type = va_arg(args, enum l_dbus_match_type)) !=
- L_DBUS_MATCH_NONE)
- rule_len++;
- va_end(args);
- rule = l_new(struct _dbus_filter_condition, rule_len + 5);
- rule_len = 0;
- rule[rule_len].type = L_DBUS_MATCH_TYPE;
- rule[rule_len++].value = "signal";
- if (sender) {
- rule[rule_len].type = L_DBUS_MATCH_SENDER;
- rule[rule_len++].value = sender;
- }
- if (path) {
- rule[rule_len].type = L_DBUS_MATCH_PATH;
- rule[rule_len++].value = path;
- }
- if (interface) {
- rule[rule_len].type = L_DBUS_MATCH_INTERFACE;
- rule[rule_len++].value = interface;
- }
- if (member) {
- rule[rule_len].type = L_DBUS_MATCH_MEMBER;
- rule[rule_len++].value = member;
- }
- va_start(args, member);
- while (true) {
- type = va_arg(args, enum l_dbus_match_type);
- if (type == L_DBUS_MATCH_NONE)
- break;
- value = va_arg(args, const char *);
- rule[rule_len].type = type;
- rule[rule_len++].value = value;
- }
- signal_func = va_arg(args, l_dbus_message_func_t);
- user_data = va_arg(args, void *);
- va_end(args);
- if (!dbus->filter) {
- if (!dbus->name_cache)
- dbus->name_cache = _dbus_name_cache_new(dbus,
- &dbus->driver->name_ops);
- dbus->filter = _dbus_filter_new(dbus,
- &dbus->driver->filter_ops,
- dbus->name_cache);
- }
- id = _dbus_filter_add_rule(dbus->filter, rule, rule_len,
- signal_func, user_data);
- l_free(rule);
- return id;
- }
- LIB_EXPORT bool l_dbus_remove_signal_watch(struct l_dbus *dbus, unsigned int id)
- {
- if (!dbus->filter)
- return false;
- return _dbus_filter_remove_rule(dbus->filter, id);
- }
- /**
- * l_dbus_name_acquire:
- * @dbus: D-Bus connection
- * @name: Well-known bus name to be acquired
- * @allow_replacement: Whether to allow another peer's name request to
- * take the name ownership away from this connection
- * @replace_existing: Whether to allow D-Bus to take the name's ownership
- * away from another peer in case the name is already
- * owned and allows replacement. Ignored if name is
- * currently free.
- * @queue: Whether to allow the name request to be queued by D-Bus in
- * case it cannot be acquired now, rather than to return a failure.
- * @callback: Callback to receive the request result when done.
- *
- * Acquire a well-known bus name (service name) on the bus.
- *
- * Returns: a non-zero request serial that can be passed to l_dbus_cancel
- * while waiting for the callback or zero if the callback has
- * has happened while l_dbus_name_acquire was running.
- **/
- LIB_EXPORT uint32_t l_dbus_name_acquire(struct l_dbus *dbus, const char *name,
- bool allow_replacement, bool replace_existing,
- bool queue, l_dbus_name_acquire_func_t callback,
- void *user_data)
- {
- return dbus->driver->name_acquire(dbus, name, allow_replacement,
- replace_existing, queue,
- callback, user_data);
- }
|