1d4afb5ceSopenharmony_ci/* 2d4afb5ceSopenharmony_ci * lws-minimal-dbus-client 3d4afb5ceSopenharmony_ci * 4d4afb5ceSopenharmony_ci * Written in 2010-2019 by Andy Green <andy@warmcat.com> 5d4afb5ceSopenharmony_ci * 6d4afb5ceSopenharmony_ci * This file is made available under the Creative Commons CC0 1.0 7d4afb5ceSopenharmony_ci * Universal Public Domain Dedication. 8d4afb5ceSopenharmony_ci * 9d4afb5ceSopenharmony_ci * This demonstrates a minimal session dbus server that uses the lws event loop, 10d4afb5ceSopenharmony_ci * making it possible to integrate it with other lws features. 11d4afb5ceSopenharmony_ci */ 12d4afb5ceSopenharmony_ci 13d4afb5ceSopenharmony_ci#include <stdbool.h> 14d4afb5ceSopenharmony_ci#include <string.h> 15d4afb5ceSopenharmony_ci#include <stdio.h> 16d4afb5ceSopenharmony_ci#include <stdlib.h> 17d4afb5ceSopenharmony_ci#include <unistd.h> 18d4afb5ceSopenharmony_ci#include <signal.h> 19d4afb5ceSopenharmony_ci 20d4afb5ceSopenharmony_ci#include <libwebsockets.h> 21d4afb5ceSopenharmony_ci#include <libwebsockets/lws-dbus.h> 22d4afb5ceSopenharmony_ci 23d4afb5ceSopenharmony_cistatic struct lws_dbus_ctx *dbus_ctx; 24d4afb5ceSopenharmony_cistatic struct lws_context *context; 25d4afb5ceSopenharmony_cistatic int interrupted; 26d4afb5ceSopenharmony_ci 27d4afb5ceSopenharmony_ci#define THIS_INTERFACE "org.libwebsockets.test" 28d4afb5ceSopenharmony_ci#define THIS_OBJECT "/org/libwebsockets/test" 29d4afb5ceSopenharmony_ci#define THIS_BUSNAME "org.libwebsockets.test" 30d4afb5ceSopenharmony_ci 31d4afb5ceSopenharmony_ci#define THIS_LISTEN_PATH "unix:abstract=org.libwebsockets.test" 32d4afb5ceSopenharmony_ci 33d4afb5ceSopenharmony_ci 34d4afb5ceSopenharmony_cistatic DBusHandlerResult 35d4afb5ceSopenharmony_ciclient_message_handler(DBusConnection *conn, DBusMessage *message, void *data) 36d4afb5ceSopenharmony_ci{ 37d4afb5ceSopenharmony_ci const char *str; 38d4afb5ceSopenharmony_ci 39d4afb5ceSopenharmony_ci lwsl_info("%s: Got D-Bus request: %s.%s on %s\n", __func__, 40d4afb5ceSopenharmony_ci dbus_message_get_interface(message), 41d4afb5ceSopenharmony_ci dbus_message_get_member(message), 42d4afb5ceSopenharmony_ci dbus_message_get_path(message)); 43d4afb5ceSopenharmony_ci 44d4afb5ceSopenharmony_ci if (!dbus_message_get_args(message, NULL, 45d4afb5ceSopenharmony_ci DBUS_TYPE_STRING, &str, 46d4afb5ceSopenharmony_ci DBUS_TYPE_INVALID)) 47d4afb5ceSopenharmony_ci return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; 48d4afb5ceSopenharmony_ci 49d4afb5ceSopenharmony_ci lwsl_notice("%s: '%s'\n", __func__, str); 50d4afb5ceSopenharmony_ci 51d4afb5ceSopenharmony_ci return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; 52d4afb5ceSopenharmony_ci} 53d4afb5ceSopenharmony_ci 54d4afb5ceSopenharmony_cistatic void 55d4afb5ceSopenharmony_cidestroy_dbus_client_conn(struct lws_dbus_ctx *ctx) 56d4afb5ceSopenharmony_ci{ 57d4afb5ceSopenharmony_ci if (!ctx || !ctx->conn) 58d4afb5ceSopenharmony_ci return; 59d4afb5ceSopenharmony_ci 60d4afb5ceSopenharmony_ci lwsl_notice("%s\n", __func__); 61d4afb5ceSopenharmony_ci 62d4afb5ceSopenharmony_ci dbus_connection_remove_filter(ctx->conn, client_message_handler, ctx); 63d4afb5ceSopenharmony_ci dbus_connection_close(ctx->conn); 64d4afb5ceSopenharmony_ci dbus_connection_unref(ctx->conn); 65d4afb5ceSopenharmony_ci 66d4afb5ceSopenharmony_ci free(ctx); 67d4afb5ceSopenharmony_ci} 68d4afb5ceSopenharmony_ci 69d4afb5ceSopenharmony_ci/* 70d4afb5ceSopenharmony_ci * This callback is coming when lws has noticed the fd took a POLLHUP. The 71d4afb5ceSopenharmony_ci * ctx has effectively gone out of scope before this, and the connection can 72d4afb5ceSopenharmony_ci * be cleaned up and the ctx freed. 73d4afb5ceSopenharmony_ci */ 74d4afb5ceSopenharmony_ci 75d4afb5ceSopenharmony_cistatic void 76d4afb5ceSopenharmony_cicb_closing(struct lws_dbus_ctx *ctx) 77d4afb5ceSopenharmony_ci{ 78d4afb5ceSopenharmony_ci lwsl_err("%s: closing\n", __func__); 79d4afb5ceSopenharmony_ci 80d4afb5ceSopenharmony_ci if (ctx == dbus_ctx) 81d4afb5ceSopenharmony_ci dbus_ctx = NULL; 82d4afb5ceSopenharmony_ci 83d4afb5ceSopenharmony_ci destroy_dbus_client_conn(ctx); 84d4afb5ceSopenharmony_ci} 85d4afb5ceSopenharmony_ci 86d4afb5ceSopenharmony_cistatic struct lws_dbus_ctx * 87d4afb5ceSopenharmony_cicreate_dbus_client_conn(struct lws_vhost *vh, int tsi, const char *ads) 88d4afb5ceSopenharmony_ci{ 89d4afb5ceSopenharmony_ci struct lws_dbus_ctx *ctx; 90d4afb5ceSopenharmony_ci DBusError err; 91d4afb5ceSopenharmony_ci 92d4afb5ceSopenharmony_ci ctx = malloc(sizeof(*ctx)); 93d4afb5ceSopenharmony_ci if (!ctx) 94d4afb5ceSopenharmony_ci return NULL; 95d4afb5ceSopenharmony_ci 96d4afb5ceSopenharmony_ci memset(ctx, 0, sizeof(*ctx)); 97d4afb5ceSopenharmony_ci 98d4afb5ceSopenharmony_ci ctx->vh = vh; 99d4afb5ceSopenharmony_ci ctx->tsi = tsi; 100d4afb5ceSopenharmony_ci 101d4afb5ceSopenharmony_ci dbus_error_init(&err); 102d4afb5ceSopenharmony_ci 103d4afb5ceSopenharmony_ci /* connect to the daemon bus */ 104d4afb5ceSopenharmony_ci ctx->conn = dbus_connection_open_private(ads, &err); 105d4afb5ceSopenharmony_ci if (!ctx->conn) { 106d4afb5ceSopenharmony_ci lwsl_err("%s: Failed to connect: %s\n", 107d4afb5ceSopenharmony_ci __func__, err.message); 108d4afb5ceSopenharmony_ci goto fail; 109d4afb5ceSopenharmony_ci } 110d4afb5ceSopenharmony_ci 111d4afb5ceSopenharmony_ci dbus_connection_set_exit_on_disconnect(ctx->conn, 0); 112d4afb5ceSopenharmony_ci 113d4afb5ceSopenharmony_ci if (!dbus_connection_add_filter(ctx->conn, client_message_handler, 114d4afb5ceSopenharmony_ci ctx, NULL)) { 115d4afb5ceSopenharmony_ci lwsl_err("%s: Failed to add filter\n", __func__); 116d4afb5ceSopenharmony_ci goto fail; 117d4afb5ceSopenharmony_ci } 118d4afb5ceSopenharmony_ci 119d4afb5ceSopenharmony_ci /* 120d4afb5ceSopenharmony_ci * This is the part that binds the connection to lws watcher and 121d4afb5ceSopenharmony_ci * timeout handling provided by lws 122d4afb5ceSopenharmony_ci */ 123d4afb5ceSopenharmony_ci 124d4afb5ceSopenharmony_ci if (lws_dbus_connection_setup(ctx, ctx->conn, cb_closing)) { 125d4afb5ceSopenharmony_ci lwsl_err("%s: connection bind to lws failed\n", __func__); 126d4afb5ceSopenharmony_ci goto fail; 127d4afb5ceSopenharmony_ci } 128d4afb5ceSopenharmony_ci 129d4afb5ceSopenharmony_ci lwsl_notice("%s: created OK\n", __func__); 130d4afb5ceSopenharmony_ci 131d4afb5ceSopenharmony_ci return ctx; 132d4afb5ceSopenharmony_ci 133d4afb5ceSopenharmony_cifail: 134d4afb5ceSopenharmony_ci dbus_error_free(&err); 135d4afb5ceSopenharmony_ci 136d4afb5ceSopenharmony_ci free(ctx); 137d4afb5ceSopenharmony_ci 138d4afb5ceSopenharmony_ci return NULL; 139d4afb5ceSopenharmony_ci} 140d4afb5ceSopenharmony_ci 141d4afb5ceSopenharmony_ci 142d4afb5ceSopenharmony_civoid sigint_handler(int sig) 143d4afb5ceSopenharmony_ci{ 144d4afb5ceSopenharmony_ci interrupted = 1; 145d4afb5ceSopenharmony_ci} 146d4afb5ceSopenharmony_ci 147d4afb5ceSopenharmony_ci/* 148d4afb5ceSopenharmony_ci * This gets called if we timed out waiting for the server reply, or the 149d4afb5ceSopenharmony_ci * reply arrived. 150d4afb5ceSopenharmony_ci */ 151d4afb5ceSopenharmony_ci 152d4afb5ceSopenharmony_cistatic void 153d4afb5ceSopenharmony_cipending_call_notify(DBusPendingCall *pending, void *data) 154d4afb5ceSopenharmony_ci{ 155d4afb5ceSopenharmony_ci // struct lws_dbus_ctx *ctx = (struct lws_dbus_ctx *)data; 156d4afb5ceSopenharmony_ci const char *payload; 157d4afb5ceSopenharmony_ci DBusMessage *msg; 158d4afb5ceSopenharmony_ci 159d4afb5ceSopenharmony_ci if (!dbus_pending_call_get_completed(pending)) { 160d4afb5ceSopenharmony_ci lwsl_err("%s: timed out waiting for reply\n", __func__); 161d4afb5ceSopenharmony_ci 162d4afb5ceSopenharmony_ci goto bail; 163d4afb5ceSopenharmony_ci } 164d4afb5ceSopenharmony_ci 165d4afb5ceSopenharmony_ci msg = dbus_pending_call_steal_reply(pending); 166d4afb5ceSopenharmony_ci if (!msg) 167d4afb5ceSopenharmony_ci goto bail; 168d4afb5ceSopenharmony_ci 169d4afb5ceSopenharmony_ci if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &payload, 170d4afb5ceSopenharmony_ci DBUS_TYPE_INVALID)) { 171d4afb5ceSopenharmony_ci goto bail1; 172d4afb5ceSopenharmony_ci } 173d4afb5ceSopenharmony_ci 174d4afb5ceSopenharmony_ci lwsl_user("%s: received '%s'\n", __func__, payload); 175d4afb5ceSopenharmony_ci 176d4afb5ceSopenharmony_cibail1: 177d4afb5ceSopenharmony_ci dbus_message_unref(msg); 178d4afb5ceSopenharmony_cibail: 179d4afb5ceSopenharmony_ci dbus_pending_call_unref(pending); 180d4afb5ceSopenharmony_ci} 181d4afb5ceSopenharmony_ci 182d4afb5ceSopenharmony_cistatic int 183d4afb5ceSopenharmony_ciremote_method_call(struct lws_dbus_ctx *ctx) 184d4afb5ceSopenharmony_ci{ 185d4afb5ceSopenharmony_ci DBusMessage *msg; 186d4afb5ceSopenharmony_ci const char *payload = "Hello!"; 187d4afb5ceSopenharmony_ci int ret = 1; 188d4afb5ceSopenharmony_ci 189d4afb5ceSopenharmony_ci msg = dbus_message_new_method_call( 190d4afb5ceSopenharmony_ci /* dest */ THIS_BUSNAME, 191d4afb5ceSopenharmony_ci /* object-path */ THIS_OBJECT, 192d4afb5ceSopenharmony_ci /* interface */ THIS_INTERFACE, 193d4afb5ceSopenharmony_ci /* method */ "Echo"); 194d4afb5ceSopenharmony_ci if (!msg) 195d4afb5ceSopenharmony_ci return 1; 196d4afb5ceSopenharmony_ci 197d4afb5ceSopenharmony_ci if (!dbus_message_append_args(msg, DBUS_TYPE_STRING, &payload, 198d4afb5ceSopenharmony_ci DBUS_TYPE_INVALID)) 199d4afb5ceSopenharmony_ci goto bail; 200d4afb5ceSopenharmony_ci 201d4afb5ceSopenharmony_ci if (!dbus_connection_send_with_reply(ctx->conn, msg, 202d4afb5ceSopenharmony_ci &ctx->pc, 203d4afb5ceSopenharmony_ci DBUS_TIMEOUT_USE_DEFAULT)) { 204d4afb5ceSopenharmony_ci lwsl_err("%s: unable to send\n", __func__); 205d4afb5ceSopenharmony_ci 206d4afb5ceSopenharmony_ci goto bail; 207d4afb5ceSopenharmony_ci } 208d4afb5ceSopenharmony_ci 209d4afb5ceSopenharmony_ci dbus_pending_call_set_notify(ctx->pc, pending_call_notify, ctx, NULL); 210d4afb5ceSopenharmony_ci 211d4afb5ceSopenharmony_ci ret = 0; 212d4afb5ceSopenharmony_ci 213d4afb5ceSopenharmony_cibail: 214d4afb5ceSopenharmony_ci dbus_message_unref(msg); 215d4afb5ceSopenharmony_ci 216d4afb5ceSopenharmony_ci return ret; 217d4afb5ceSopenharmony_ci} 218d4afb5ceSopenharmony_ci 219d4afb5ceSopenharmony_ciint main(int argc, const char **argv) 220d4afb5ceSopenharmony_ci{ 221d4afb5ceSopenharmony_ci struct lws_vhost *vh; 222d4afb5ceSopenharmony_ci struct lws_context_creation_info info; 223d4afb5ceSopenharmony_ci const char *p; 224d4afb5ceSopenharmony_ci int n = 0, logs = LLL_USER | LLL_ERR | LLL_WARN | LLL_NOTICE 225d4afb5ceSopenharmony_ci /* for LLL_ verbosity above NOTICE to be built into lws, 226d4afb5ceSopenharmony_ci * lws must have been configured and built with 227d4afb5ceSopenharmony_ci * -DCMAKE_BUILD_TYPE=DEBUG instead of =RELEASE */ 228d4afb5ceSopenharmony_ci /* | LLL_INFO */ /* | LLL_PARSER */ /* | LLL_HEADER */ 229d4afb5ceSopenharmony_ci /* | LLL_EXT */ /* | LLL_CLIENT */ /* | LLL_LATENCY */ 230d4afb5ceSopenharmony_ci /* | LLL_DEBUG */ /* | LLL_THREAD */; 231d4afb5ceSopenharmony_ci 232d4afb5ceSopenharmony_ci signal(SIGINT, sigint_handler); 233d4afb5ceSopenharmony_ci 234d4afb5ceSopenharmony_ci if ((p = lws_cmdline_option(argc, argv, "-d"))) 235d4afb5ceSopenharmony_ci logs = atoi(p); 236d4afb5ceSopenharmony_ci 237d4afb5ceSopenharmony_ci lws_set_log_level(logs, NULL); 238d4afb5ceSopenharmony_ci lwsl_user("LWS minimal DBUS client\n"); 239d4afb5ceSopenharmony_ci 240d4afb5ceSopenharmony_ci memset(&info, 0, sizeof info); /* otherwise uninitialized garbage */ 241d4afb5ceSopenharmony_ci info.options = LWS_SERVER_OPTION_EXPLICIT_VHOSTS; 242d4afb5ceSopenharmony_ci context = lws_create_context(&info); 243d4afb5ceSopenharmony_ci if (!context) { 244d4afb5ceSopenharmony_ci lwsl_err("lws init failed\n"); 245d4afb5ceSopenharmony_ci return 1; 246d4afb5ceSopenharmony_ci } 247d4afb5ceSopenharmony_ci 248d4afb5ceSopenharmony_ci vh = lws_create_vhost(context, &info); 249d4afb5ceSopenharmony_ci if (!vh) 250d4afb5ceSopenharmony_ci goto bail; 251d4afb5ceSopenharmony_ci 252d4afb5ceSopenharmony_ci dbus_ctx = create_dbus_client_conn(vh, 0, THIS_LISTEN_PATH); 253d4afb5ceSopenharmony_ci if (!dbus_ctx) 254d4afb5ceSopenharmony_ci goto bail1; 255d4afb5ceSopenharmony_ci 256d4afb5ceSopenharmony_ci if (remote_method_call(dbus_ctx)) 257d4afb5ceSopenharmony_ci goto bail2; 258d4afb5ceSopenharmony_ci 259d4afb5ceSopenharmony_ci /* lws event loop (default poll one) */ 260d4afb5ceSopenharmony_ci 261d4afb5ceSopenharmony_ci while (n >= 0 && !interrupted) 262d4afb5ceSopenharmony_ci n = lws_service(context, 0); 263d4afb5ceSopenharmony_ci 264d4afb5ceSopenharmony_cibail2: 265d4afb5ceSopenharmony_ci destroy_dbus_client_conn(dbus_ctx); 266d4afb5ceSopenharmony_ci 267d4afb5ceSopenharmony_cibail1: 268d4afb5ceSopenharmony_ci /* this is required for valgrind-cleanliness */ 269d4afb5ceSopenharmony_ci dbus_shutdown(); 270d4afb5ceSopenharmony_ci lws_context_destroy(context); 271d4afb5ceSopenharmony_ci 272d4afb5ceSopenharmony_ci lwsl_notice("Exiting cleanly\n"); 273d4afb5ceSopenharmony_ci 274d4afb5ceSopenharmony_ci return 0; 275d4afb5ceSopenharmony_ci 276d4afb5ceSopenharmony_cibail: 277d4afb5ceSopenharmony_ci lwsl_err("%s: failed to start\n", __func__); 278d4afb5ceSopenharmony_ci lws_context_destroy(context); 279d4afb5ceSopenharmony_ci 280d4afb5ceSopenharmony_ci return 1; 281d4afb5ceSopenharmony_ci} 282