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