1d4afb5ceSopenharmony_ci/*
2d4afb5ceSopenharmony_ci * lws-minimal-dbus-server
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 * The dbus server parts are based on "Sample code illustrating basic use of
13d4afb5ceSopenharmony_ci * D-BUS" (presumed Public Domain) here:
14d4afb5ceSopenharmony_ci *
15d4afb5ceSopenharmony_ci * https://github.com/fbuihuu/samples-dbus/blob/master/dbus-server.c
16d4afb5ceSopenharmony_ci */
17d4afb5ceSopenharmony_ci
18d4afb5ceSopenharmony_ci#include <stdbool.h>
19d4afb5ceSopenharmony_ci#include <string.h>
20d4afb5ceSopenharmony_ci#include <stdio.h>
21d4afb5ceSopenharmony_ci#include <stdlib.h>
22d4afb5ceSopenharmony_ci#include <unistd.h>
23d4afb5ceSopenharmony_ci#include <signal.h>
24d4afb5ceSopenharmony_ci
25d4afb5ceSopenharmony_ci#include <libwebsockets.h>
26d4afb5ceSopenharmony_ci#include <libwebsockets/lws-dbus.h>
27d4afb5ceSopenharmony_ci
28d4afb5ceSopenharmony_cistatic struct lws_context *context;
29d4afb5ceSopenharmony_cistatic const char *version = "0.1";
30d4afb5ceSopenharmony_cistatic int interrupted;
31d4afb5ceSopenharmony_cistatic struct lws_dbus_ctx dbus_ctx, ctx_listener;
32d4afb5ceSopenharmony_cistatic char session;
33d4afb5ceSopenharmony_ci
34d4afb5ceSopenharmony_ci#define THIS_INTERFACE	 "org.libwebsockets.test"
35d4afb5ceSopenharmony_ci#define THIS_OBJECT	 "/org/libwebsockets/test"
36d4afb5ceSopenharmony_ci#define THIS_BUSNAME	 "org.libwebsockets.test"
37d4afb5ceSopenharmony_ci
38d4afb5ceSopenharmony_ci#define THIS_LISTEN_PATH "unix:abstract=org.libwebsockets.test"
39d4afb5ceSopenharmony_ci
40d4afb5ceSopenharmony_cistatic const char *
41d4afb5ceSopenharmony_ciserver_introspection_xml =
42d4afb5ceSopenharmony_ci	DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE
43d4afb5ceSopenharmony_ci	"<node>\n"
44d4afb5ceSopenharmony_ci	"  <interface name='" DBUS_INTERFACE_INTROSPECTABLE "'>\n"
45d4afb5ceSopenharmony_ci	"    <method name='Introspect'>\n"
46d4afb5ceSopenharmony_ci	"      <arg name='data' type='s' direction='out' />\n"
47d4afb5ceSopenharmony_ci	"    </method>\n"
48d4afb5ceSopenharmony_ci	"  </interface>\n"
49d4afb5ceSopenharmony_ci
50d4afb5ceSopenharmony_ci	"  <interface name='" DBUS_INTERFACE_PROPERTIES "'>\n"
51d4afb5ceSopenharmony_ci	"    <method name='Get'>\n"
52d4afb5ceSopenharmony_ci	"      <arg name='interface' type='s' direction='in' />\n"
53d4afb5ceSopenharmony_ci	"      <arg name='property'  type='s' direction='in' />\n"
54d4afb5ceSopenharmony_ci	"      <arg name='value'     type='s' direction='out' />\n"
55d4afb5ceSopenharmony_ci	"    </method>\n"
56d4afb5ceSopenharmony_ci	"    <method name='GetAll'>\n"
57d4afb5ceSopenharmony_ci	"      <arg name='interface'  type='s'     direction='in'/>\n"
58d4afb5ceSopenharmony_ci	"      <arg name='properties' type='a{sv}' direction='out'/>\n"
59d4afb5ceSopenharmony_ci	"    </method>\n"
60d4afb5ceSopenharmony_ci	"  </interface>\n"
61d4afb5ceSopenharmony_ci
62d4afb5ceSopenharmony_ci	"  <interface name='"THIS_INTERFACE"'>\n"
63d4afb5ceSopenharmony_ci	"    <property name='Version' type='s' access='read' />\n"
64d4afb5ceSopenharmony_ci	"    <method name='Ping' >\n"
65d4afb5ceSopenharmony_ci	"      <arg type='s' direction='out' />\n"
66d4afb5ceSopenharmony_ci	"    </method>\n"
67d4afb5ceSopenharmony_ci	"    <method name='Echo'>\n"
68d4afb5ceSopenharmony_ci	"      <arg name='string' direction='in' type='s'/>\n"
69d4afb5ceSopenharmony_ci	"      <arg type='s' direction='out' />\n"
70d4afb5ceSopenharmony_ci	"    </method>\n"
71d4afb5ceSopenharmony_ci	"    <method name='EmitSignal'>\n"
72d4afb5ceSopenharmony_ci	"    </method>\n"
73d4afb5ceSopenharmony_ci	"    <method name='Quit'>\n"
74d4afb5ceSopenharmony_ci	"    </method>\n"
75d4afb5ceSopenharmony_ci	"    <signal name='OnEmitSignal'>\n"
76d4afb5ceSopenharmony_ci	"    </signal>"
77d4afb5ceSopenharmony_ci	"  </interface>\n"
78d4afb5ceSopenharmony_ci
79d4afb5ceSopenharmony_ci	"</node>\n";
80d4afb5ceSopenharmony_ci
81d4afb5ceSopenharmony_cistatic DBusHandlerResult
82d4afb5ceSopenharmony_cidmh_introspect(DBusConnection *c, DBusMessage *m, DBusMessage **reply, void *d)
83d4afb5ceSopenharmony_ci{
84d4afb5ceSopenharmony_ci	dbus_message_append_args(*reply, DBUS_TYPE_STRING,
85d4afb5ceSopenharmony_ci				 &server_introspection_xml, DBUS_TYPE_INVALID);
86d4afb5ceSopenharmony_ci
87d4afb5ceSopenharmony_ci	return DBUS_HANDLER_RESULT_HANDLED;
88d4afb5ceSopenharmony_ci}
89d4afb5ceSopenharmony_ci
90d4afb5ceSopenharmony_cistatic DBusHandlerResult
91d4afb5ceSopenharmony_cidmh_get(DBusConnection *c, DBusMessage *m, DBusMessage **reply, void *d)
92d4afb5ceSopenharmony_ci{
93d4afb5ceSopenharmony_ci	const char *interface, *property;
94d4afb5ceSopenharmony_ci	DBusError err;
95d4afb5ceSopenharmony_ci
96d4afb5ceSopenharmony_ci	dbus_error_init(&err);
97d4afb5ceSopenharmony_ci
98d4afb5ceSopenharmony_ci	if (!dbus_message_get_args(m, &err, DBUS_TYPE_STRING, &interface,
99d4afb5ceSopenharmony_ci					    DBUS_TYPE_STRING, &property,
100d4afb5ceSopenharmony_ci					    DBUS_TYPE_INVALID)) {
101d4afb5ceSopenharmony_ci		dbus_message_unref(*reply);
102d4afb5ceSopenharmony_ci		*reply = dbus_message_new_error(m, err.name, err.message);
103d4afb5ceSopenharmony_ci		dbus_error_free(&err);
104d4afb5ceSopenharmony_ci
105d4afb5ceSopenharmony_ci		return DBUS_HANDLER_RESULT_HANDLED;
106d4afb5ceSopenharmony_ci	}
107d4afb5ceSopenharmony_ci
108d4afb5ceSopenharmony_ci	if (strcmp(property, "Version")) /* Unknown property */
109d4afb5ceSopenharmony_ci		return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
110d4afb5ceSopenharmony_ci
111d4afb5ceSopenharmony_ci	dbus_message_append_args(*reply, DBUS_TYPE_STRING, &version,
112d4afb5ceSopenharmony_ci				 DBUS_TYPE_INVALID);
113d4afb5ceSopenharmony_ci
114d4afb5ceSopenharmony_ci	return DBUS_HANDLER_RESULT_HANDLED;
115d4afb5ceSopenharmony_ci}
116d4afb5ceSopenharmony_ci
117d4afb5ceSopenharmony_cistatic DBusHandlerResult
118d4afb5ceSopenharmony_cidmh_getall(DBusConnection *c, DBusMessage *m, DBusMessage **reply, void *d)
119d4afb5ceSopenharmony_ci{
120d4afb5ceSopenharmony_ci	DBusMessageIter arr, di, iter, va;
121d4afb5ceSopenharmony_ci	const char *property = "Version";
122d4afb5ceSopenharmony_ci
123d4afb5ceSopenharmony_ci	dbus_message_iter_init_append(*reply, &iter);
124d4afb5ceSopenharmony_ci	dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "{sv}", &arr);
125d4afb5ceSopenharmony_ci
126d4afb5ceSopenharmony_ci	/* Append all properties name/value pairs */
127d4afb5ceSopenharmony_ci	dbus_message_iter_open_container(&arr, DBUS_TYPE_DICT_ENTRY, NULL, &di);
128d4afb5ceSopenharmony_ci	dbus_message_iter_append_basic(&di, DBUS_TYPE_STRING, &property);
129d4afb5ceSopenharmony_ci	dbus_message_iter_open_container(&di, DBUS_TYPE_VARIANT, "s", &va);
130d4afb5ceSopenharmony_ci	dbus_message_iter_append_basic(&va, DBUS_TYPE_STRING, &version);
131d4afb5ceSopenharmony_ci	dbus_message_iter_close_container(&di, &va);
132d4afb5ceSopenharmony_ci	dbus_message_iter_close_container(&arr, &di);
133d4afb5ceSopenharmony_ci
134d4afb5ceSopenharmony_ci	dbus_message_iter_close_container(&iter, &arr);
135d4afb5ceSopenharmony_ci
136d4afb5ceSopenharmony_ci	return DBUS_HANDLER_RESULT_HANDLED;
137d4afb5ceSopenharmony_ci}
138d4afb5ceSopenharmony_ci
139d4afb5ceSopenharmony_cistatic DBusHandlerResult
140d4afb5ceSopenharmony_cidmh_ping(DBusConnection *c, DBusMessage *m, DBusMessage **reply, void *d)
141d4afb5ceSopenharmony_ci{
142d4afb5ceSopenharmony_ci	const char *pong = "Pong";
143d4afb5ceSopenharmony_ci
144d4afb5ceSopenharmony_ci	dbus_message_append_args(*reply, DBUS_TYPE_STRING, &pong,
145d4afb5ceSopenharmony_ci					 DBUS_TYPE_INVALID);
146d4afb5ceSopenharmony_ci
147d4afb5ceSopenharmony_ci	return DBUS_HANDLER_RESULT_HANDLED;
148d4afb5ceSopenharmony_ci}
149d4afb5ceSopenharmony_ci
150d4afb5ceSopenharmony_cistatic DBusHandlerResult
151d4afb5ceSopenharmony_cidmh_echo(DBusConnection *c, DBusMessage *m, DBusMessage **reply, void *d)
152d4afb5ceSopenharmony_ci{
153d4afb5ceSopenharmony_ci	const char *msg;
154d4afb5ceSopenharmony_ci	DBusError err;
155d4afb5ceSopenharmony_ci
156d4afb5ceSopenharmony_ci	dbus_error_init(&err);
157d4afb5ceSopenharmony_ci
158d4afb5ceSopenharmony_ci	if (!dbus_message_get_args(m, &err, DBUS_TYPE_STRING,
159d4afb5ceSopenharmony_ci				   &msg, DBUS_TYPE_INVALID)) {
160d4afb5ceSopenharmony_ci		dbus_message_unref(*reply);
161d4afb5ceSopenharmony_ci		*reply = dbus_message_new_error(m, err.name, err.message);
162d4afb5ceSopenharmony_ci		dbus_error_free(&err);
163d4afb5ceSopenharmony_ci
164d4afb5ceSopenharmony_ci		return DBUS_HANDLER_RESULT_HANDLED;
165d4afb5ceSopenharmony_ci	}
166d4afb5ceSopenharmony_ci
167d4afb5ceSopenharmony_ci	dbus_message_append_args(*reply, DBUS_TYPE_STRING, &msg,
168d4afb5ceSopenharmony_ci					 DBUS_TYPE_INVALID);
169d4afb5ceSopenharmony_ci
170d4afb5ceSopenharmony_ci	return DBUS_HANDLER_RESULT_HANDLED;
171d4afb5ceSopenharmony_ci}
172d4afb5ceSopenharmony_ci
173d4afb5ceSopenharmony_cistatic DBusHandlerResult
174d4afb5ceSopenharmony_cidmh_emit_signal(DBusConnection *c, DBusMessage *m, DBusMessage **reply, void *d)
175d4afb5ceSopenharmony_ci{
176d4afb5ceSopenharmony_ci	DBusMessage *r = dbus_message_new_signal(THIS_OBJECT, THIS_INTERFACE,
177d4afb5ceSopenharmony_ci					         "OnEmitSignal");
178d4afb5ceSopenharmony_ci
179d4afb5ceSopenharmony_ci	if (!r)
180d4afb5ceSopenharmony_ci		return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
181d4afb5ceSopenharmony_ci
182d4afb5ceSopenharmony_ci	if (!dbus_connection_send(c, r, NULL))
183d4afb5ceSopenharmony_ci		return DBUS_HANDLER_RESULT_NEED_MEMORY;
184d4afb5ceSopenharmony_ci
185d4afb5ceSopenharmony_ci	/* and send the original empty reply after */
186d4afb5ceSopenharmony_ci
187d4afb5ceSopenharmony_ci	return DBUS_HANDLER_RESULT_HANDLED;
188d4afb5ceSopenharmony_ci}
189d4afb5ceSopenharmony_ci
190d4afb5ceSopenharmony_cistatic DBusHandlerResult
191d4afb5ceSopenharmony_cidmh_emit_quit(DBusConnection *c, DBusMessage *m, DBusMessage **reply, void *d)
192d4afb5ceSopenharmony_ci{
193d4afb5ceSopenharmony_ci	interrupted = 1;
194d4afb5ceSopenharmony_ci
195d4afb5ceSopenharmony_ci	return DBUS_HANDLER_RESULT_HANDLED;
196d4afb5ceSopenharmony_ci}
197d4afb5ceSopenharmony_ci
198d4afb5ceSopenharmony_cistruct lws_dbus_methods {
199d4afb5ceSopenharmony_ci	const char *inter;
200d4afb5ceSopenharmony_ci	const char *call;
201d4afb5ceSopenharmony_ci	lws_dbus_message_handler handler;
202d4afb5ceSopenharmony_ci} meths[] = {
203d4afb5ceSopenharmony_ci	{ DBUS_INTERFACE_INTROSPECTABLE, "Introspect",	dmh_introspect	},
204d4afb5ceSopenharmony_ci	{ DBUS_INTERFACE_PROPERTIES,	 "Get",		dmh_get		},
205d4afb5ceSopenharmony_ci	{ DBUS_INTERFACE_PROPERTIES,	 "GetAll",	dmh_getall	},
206d4afb5ceSopenharmony_ci	{ THIS_INTERFACE,		 "Ping",	dmh_ping	},
207d4afb5ceSopenharmony_ci	{ THIS_INTERFACE,		 "Echo",	dmh_echo	},
208d4afb5ceSopenharmony_ci	{ THIS_INTERFACE,		 "EmitSignal",	dmh_emit_signal },
209d4afb5ceSopenharmony_ci	{ THIS_INTERFACE,		 "Quit",	dmh_emit_quit	},
210d4afb5ceSopenharmony_ci};
211d4afb5ceSopenharmony_ci
212d4afb5ceSopenharmony_cistatic DBusHandlerResult
213d4afb5ceSopenharmony_ciserver_message_handler(DBusConnection *conn, DBusMessage *message, void *data)
214d4afb5ceSopenharmony_ci{
215d4afb5ceSopenharmony_ci	struct lws_dbus_methods *mp = meths;
216d4afb5ceSopenharmony_ci	DBusHandlerResult result;
217d4afb5ceSopenharmony_ci        DBusMessage *reply = NULL;
218d4afb5ceSopenharmony_ci	size_t n;
219d4afb5ceSopenharmony_ci
220d4afb5ceSopenharmony_ci	lwsl_info("%s: Got D-Bus request: %s.%s on %s\n", __func__,
221d4afb5ceSopenharmony_ci		  dbus_message_get_interface(message),
222d4afb5ceSopenharmony_ci		  dbus_message_get_member(message),
223d4afb5ceSopenharmony_ci		  dbus_message_get_path(message));
224d4afb5ceSopenharmony_ci
225d4afb5ceSopenharmony_ci	for (n = 0; n < LWS_ARRAY_SIZE(meths); n++) {
226d4afb5ceSopenharmony_ci		if (dbus_message_is_method_call(message, mp->inter, mp->call)) {
227d4afb5ceSopenharmony_ci			reply = dbus_message_new_method_return(message);
228d4afb5ceSopenharmony_ci			if (!reply)
229d4afb5ceSopenharmony_ci				return DBUS_HANDLER_RESULT_NEED_MEMORY;
230d4afb5ceSopenharmony_ci
231d4afb5ceSopenharmony_ci			result = mp->handler(conn, message, &reply, data);
232d4afb5ceSopenharmony_ci
233d4afb5ceSopenharmony_ci			if (result == DBUS_HANDLER_RESULT_HANDLED &&
234d4afb5ceSopenharmony_ci			    !dbus_connection_send(conn, reply, NULL))
235d4afb5ceSopenharmony_ci				result = DBUS_HANDLER_RESULT_NEED_MEMORY;
236d4afb5ceSopenharmony_ci
237d4afb5ceSopenharmony_ci			dbus_message_unref(reply);
238d4afb5ceSopenharmony_ci
239d4afb5ceSopenharmony_ci			return result;
240d4afb5ceSopenharmony_ci		}
241d4afb5ceSopenharmony_ci
242d4afb5ceSopenharmony_ci		mp++;
243d4afb5ceSopenharmony_ci	}
244d4afb5ceSopenharmony_ci
245d4afb5ceSopenharmony_ci	return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
246d4afb5ceSopenharmony_ci}
247d4afb5ceSopenharmony_ci
248d4afb5ceSopenharmony_cistatic const DBusObjectPathVTable server_vtable = {
249d4afb5ceSopenharmony_ci	.message_function = server_message_handler
250d4afb5ceSopenharmony_ci};
251d4afb5ceSopenharmony_ci
252d4afb5ceSopenharmony_cistatic void
253d4afb5ceSopenharmony_cidestroy_dbus_server_conn(struct lws_dbus_ctx *ctx)
254d4afb5ceSopenharmony_ci{
255d4afb5ceSopenharmony_ci	if (!ctx->conn)
256d4afb5ceSopenharmony_ci		return;
257d4afb5ceSopenharmony_ci
258d4afb5ceSopenharmony_ci	lwsl_notice("%s\n", __func__);
259d4afb5ceSopenharmony_ci
260d4afb5ceSopenharmony_ci	dbus_connection_unregister_object_path(ctx->conn, THIS_OBJECT);
261d4afb5ceSopenharmony_ci	lws_dll2_remove(&ctx->next);
262d4afb5ceSopenharmony_ci	dbus_connection_unref(ctx->conn);
263d4afb5ceSopenharmony_ci}
264d4afb5ceSopenharmony_ci
265d4afb5ceSopenharmony_cistatic void
266d4afb5ceSopenharmony_cicb_closing(struct lws_dbus_ctx *ctx)
267d4afb5ceSopenharmony_ci{
268d4afb5ceSopenharmony_ci	lwsl_err("%s: closing\n", __func__);
269d4afb5ceSopenharmony_ci	destroy_dbus_server_conn(ctx);
270d4afb5ceSopenharmony_ci
271d4afb5ceSopenharmony_ci	free(ctx);
272d4afb5ceSopenharmony_ci}
273d4afb5ceSopenharmony_ci
274d4afb5ceSopenharmony_ci
275d4afb5ceSopenharmony_cistatic void
276d4afb5ceSopenharmony_cinew_conn(DBusServer *server, DBusConnection *conn, void *data)
277d4afb5ceSopenharmony_ci{
278d4afb5ceSopenharmony_ci	struct lws_dbus_ctx *conn_ctx, *ctx = (struct lws_dbus_ctx *)data;
279d4afb5ceSopenharmony_ci
280d4afb5ceSopenharmony_ci	lwsl_notice("%s: vh %s\n", __func__, lws_get_vhost_name(ctx->vh));
281d4afb5ceSopenharmony_ci
282d4afb5ceSopenharmony_ci	conn_ctx = malloc(sizeof(*conn_ctx));
283d4afb5ceSopenharmony_ci	if (!conn_ctx)
284d4afb5ceSopenharmony_ci		return;
285d4afb5ceSopenharmony_ci
286d4afb5ceSopenharmony_ci	memset(conn_ctx, 0, sizeof(*conn_ctx));
287d4afb5ceSopenharmony_ci
288d4afb5ceSopenharmony_ci	conn_ctx->tsi = ctx->tsi;
289d4afb5ceSopenharmony_ci	conn_ctx->vh = ctx->vh;
290d4afb5ceSopenharmony_ci	conn_ctx->conn = conn;
291d4afb5ceSopenharmony_ci
292d4afb5ceSopenharmony_ci	if (lws_dbus_connection_setup(conn_ctx, conn, cb_closing)) {
293d4afb5ceSopenharmony_ci		lwsl_err("%s: connection bind to lws failed\n", __func__);
294d4afb5ceSopenharmony_ci		goto bail;
295d4afb5ceSopenharmony_ci	}
296d4afb5ceSopenharmony_ci
297d4afb5ceSopenharmony_ci	if (!dbus_connection_register_object_path(conn, THIS_OBJECT,
298d4afb5ceSopenharmony_ci						  &server_vtable, conn_ctx)) {
299d4afb5ceSopenharmony_ci		lwsl_err("%s: Failed to register object path\n", __func__);
300d4afb5ceSopenharmony_ci		goto bail;
301d4afb5ceSopenharmony_ci	}
302d4afb5ceSopenharmony_ci
303d4afb5ceSopenharmony_ci	lws_dll2_add_head(&conn_ctx->next, &ctx->owner);
304d4afb5ceSopenharmony_ci
305d4afb5ceSopenharmony_ci	/* we take on responsibility for explicit close / unref with this... */
306d4afb5ceSopenharmony_ci	dbus_connection_ref(conn);
307d4afb5ceSopenharmony_ci
308d4afb5ceSopenharmony_ci	return;
309d4afb5ceSopenharmony_ci
310d4afb5ceSopenharmony_cibail:
311d4afb5ceSopenharmony_ci	free(conn_ctx);
312d4afb5ceSopenharmony_ci}
313d4afb5ceSopenharmony_ci
314d4afb5ceSopenharmony_cistatic int
315d4afb5ceSopenharmony_cicreate_dbus_listener(const char *ads)
316d4afb5ceSopenharmony_ci{
317d4afb5ceSopenharmony_ci	DBusError e;
318d4afb5ceSopenharmony_ci
319d4afb5ceSopenharmony_ci        dbus_error_init(&e);
320d4afb5ceSopenharmony_ci
321d4afb5ceSopenharmony_ci	if (!lws_dbus_server_listen(&ctx_listener, ads, &e, new_conn)) {
322d4afb5ceSopenharmony_ci		lwsl_err("%s: failed\n", __func__);
323d4afb5ceSopenharmony_ci		dbus_error_free(&e);
324d4afb5ceSopenharmony_ci
325d4afb5ceSopenharmony_ci		return 1;
326d4afb5ceSopenharmony_ci	}
327d4afb5ceSopenharmony_ci
328d4afb5ceSopenharmony_ci	return 0;
329d4afb5ceSopenharmony_ci}
330d4afb5ceSopenharmony_ci
331d4afb5ceSopenharmony_cistatic int
332d4afb5ceSopenharmony_cicreate_dbus_server_conn(struct lws_dbus_ctx *ctx, DBusBusType type)
333d4afb5ceSopenharmony_ci{
334d4afb5ceSopenharmony_ci	DBusError err;
335d4afb5ceSopenharmony_ci	int rv;
336d4afb5ceSopenharmony_ci
337d4afb5ceSopenharmony_ci        dbus_error_init(&err);
338d4afb5ceSopenharmony_ci
339d4afb5ceSopenharmony_ci	/* connect to the daemon bus */
340d4afb5ceSopenharmony_ci	ctx->conn = dbus_bus_get(type, &err);
341d4afb5ceSopenharmony_ci	if (!ctx->conn) {
342d4afb5ceSopenharmony_ci		lwsl_err("%s: Failed to get a session DBus connection: %s\n",
343d4afb5ceSopenharmony_ci			 __func__, err.message);
344d4afb5ceSopenharmony_ci		goto fail;
345d4afb5ceSopenharmony_ci	}
346d4afb5ceSopenharmony_ci
347d4afb5ceSopenharmony_ci	/*
348d4afb5ceSopenharmony_ci	 * by default dbus will call exit() when this connection closes...
349d4afb5ceSopenharmony_ci	 * we have to shut down other things cleanly, so disable that
350d4afb5ceSopenharmony_ci	 */
351d4afb5ceSopenharmony_ci	dbus_connection_set_exit_on_disconnect(ctx->conn, 0);
352d4afb5ceSopenharmony_ci
353d4afb5ceSopenharmony_ci	rv = dbus_bus_request_name(ctx->conn, THIS_BUSNAME,
354d4afb5ceSopenharmony_ci				   DBUS_NAME_FLAG_REPLACE_EXISTING, &err);
355d4afb5ceSopenharmony_ci	if (rv != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) {
356d4afb5ceSopenharmony_ci		lwsl_err("%s: Failed to request name on bus: %s\n",
357d4afb5ceSopenharmony_ci			 __func__, err.message);
358d4afb5ceSopenharmony_ci		goto fail;
359d4afb5ceSopenharmony_ci	}
360d4afb5ceSopenharmony_ci
361d4afb5ceSopenharmony_ci	if (!dbus_connection_register_object_path(ctx->conn, THIS_OBJECT,
362d4afb5ceSopenharmony_ci						  &server_vtable, NULL)) {
363d4afb5ceSopenharmony_ci		lwsl_err("%s: Failed to register object path for TestObject\n",
364d4afb5ceSopenharmony_ci			 __func__);
365d4afb5ceSopenharmony_ci		dbus_bus_release_name(ctx->conn, THIS_BUSNAME, &err);
366d4afb5ceSopenharmony_ci		goto fail;
367d4afb5ceSopenharmony_ci	}
368d4afb5ceSopenharmony_ci
369d4afb5ceSopenharmony_ci	/*
370d4afb5ceSopenharmony_ci	 * This is the part that binds the connection to lws watcher and
371d4afb5ceSopenharmony_ci	 * timeout handling provided by lws
372d4afb5ceSopenharmony_ci	 */
373d4afb5ceSopenharmony_ci
374d4afb5ceSopenharmony_ci	if (lws_dbus_connection_setup(ctx, ctx->conn, cb_closing)) {
375d4afb5ceSopenharmony_ci		lwsl_err("%s: connection bind to lws failed\n", __func__);
376d4afb5ceSopenharmony_ci		goto fail;
377d4afb5ceSopenharmony_ci	}
378d4afb5ceSopenharmony_ci
379d4afb5ceSopenharmony_ci	lwsl_notice("%s: created OK\n", __func__);
380d4afb5ceSopenharmony_ci
381d4afb5ceSopenharmony_ci	return 0;
382d4afb5ceSopenharmony_ci
383d4afb5ceSopenharmony_cifail:
384d4afb5ceSopenharmony_ci	dbus_error_free(&err);
385d4afb5ceSopenharmony_ci
386d4afb5ceSopenharmony_ci	return 1;
387d4afb5ceSopenharmony_ci}
388d4afb5ceSopenharmony_ci
389d4afb5ceSopenharmony_ci/*
390d4afb5ceSopenharmony_ci * Cleanly release the connection
391d4afb5ceSopenharmony_ci */
392d4afb5ceSopenharmony_ci
393d4afb5ceSopenharmony_cistatic void
394d4afb5ceSopenharmony_cidestroy_dbus_server_listener(struct lws_dbus_ctx *ctx)
395d4afb5ceSopenharmony_ci{
396d4afb5ceSopenharmony_ci	dbus_server_disconnect(ctx->dbs);
397d4afb5ceSopenharmony_ci
398d4afb5ceSopenharmony_ci	lws_start_foreach_dll_safe(struct lws_dll2 *, rdt, nx,
399d4afb5ceSopenharmony_ci				   ctx->owner.head) {
400d4afb5ceSopenharmony_ci		struct lws_dbus_ctx *r =
401d4afb5ceSopenharmony_ci			lws_container_of(rdt, struct lws_dbus_ctx, next);
402d4afb5ceSopenharmony_ci
403d4afb5ceSopenharmony_ci		dbus_connection_close(r->conn);
404d4afb5ceSopenharmony_ci		dbus_connection_unref(r->conn);
405d4afb5ceSopenharmony_ci		free(r);
406d4afb5ceSopenharmony_ci	} lws_end_foreach_dll_safe(rdt, nx);
407d4afb5ceSopenharmony_ci
408d4afb5ceSopenharmony_ci	dbus_server_unref(ctx->dbs);
409d4afb5ceSopenharmony_ci}
410d4afb5ceSopenharmony_ci
411d4afb5ceSopenharmony_ci/*
412d4afb5ceSopenharmony_ci * DBUS can send messages outside the usual client-initiated RPC concept.
413d4afb5ceSopenharmony_ci *
414d4afb5ceSopenharmony_ci * You can receive them using a message filter.
415d4afb5ceSopenharmony_ci */
416d4afb5ceSopenharmony_ci
417d4afb5ceSopenharmony_cistatic void
418d4afb5ceSopenharmony_cispam_connected_clients(struct lws_dbus_ctx *ctx)
419d4afb5ceSopenharmony_ci{
420d4afb5ceSopenharmony_ci
421d4afb5ceSopenharmony_ci	/* send connected clients an unsolicited message */
422d4afb5ceSopenharmony_ci
423d4afb5ceSopenharmony_ci	lws_start_foreach_dll_safe(struct lws_dll2 *, rdt, nx,
424d4afb5ceSopenharmony_ci				   ctx->owner.head) {
425d4afb5ceSopenharmony_ci		struct lws_dbus_ctx *r =
426d4afb5ceSopenharmony_ci			lws_container_of(rdt, struct lws_dbus_ctx, next);
427d4afb5ceSopenharmony_ci
428d4afb5ceSopenharmony_ci
429d4afb5ceSopenharmony_ci		DBusMessage *msg;
430d4afb5ceSopenharmony_ci		const char *payload = "Unsolicited message";
431d4afb5ceSopenharmony_ci
432d4afb5ceSopenharmony_ci		msg = dbus_message_new(DBUS_NUM_MESSAGE_TYPES + 1);
433d4afb5ceSopenharmony_ci		if (!msg) {
434d4afb5ceSopenharmony_ci			lwsl_err("%s: new message failed\n", __func__);
435d4afb5ceSopenharmony_ci		}
436d4afb5ceSopenharmony_ci
437d4afb5ceSopenharmony_ci		dbus_message_append_args(msg, DBUS_TYPE_STRING, &payload,
438d4afb5ceSopenharmony_ci						 DBUS_TYPE_INVALID);
439d4afb5ceSopenharmony_ci		if (!dbus_connection_send(r->conn, msg, NULL)) {
440d4afb5ceSopenharmony_ci			lwsl_err("%s: unable to send\n", __func__);
441d4afb5ceSopenharmony_ci		}
442d4afb5ceSopenharmony_ci
443d4afb5ceSopenharmony_ci		lwsl_notice("%s\n", __func__);
444d4afb5ceSopenharmony_ci
445d4afb5ceSopenharmony_ci		dbus_message_unref(msg);
446d4afb5ceSopenharmony_ci
447d4afb5ceSopenharmony_ci	} lws_end_foreach_dll_safe(rdt, nx);
448d4afb5ceSopenharmony_ci
449d4afb5ceSopenharmony_ci}
450d4afb5ceSopenharmony_ci
451d4afb5ceSopenharmony_ci
452d4afb5ceSopenharmony_civoid sigint_handler(int sig)
453d4afb5ceSopenharmony_ci{
454d4afb5ceSopenharmony_ci	interrupted = 1;
455d4afb5ceSopenharmony_ci}
456d4afb5ceSopenharmony_ci
457d4afb5ceSopenharmony_ciint main(int argc, const char **argv)
458d4afb5ceSopenharmony_ci{
459d4afb5ceSopenharmony_ci	struct lws_context_creation_info info;
460d4afb5ceSopenharmony_ci	const char *p;
461d4afb5ceSopenharmony_ci	int n = 0, logs = LLL_USER | LLL_ERR | LLL_WARN | LLL_NOTICE
462d4afb5ceSopenharmony_ci			/* for LLL_ verbosity above NOTICE to be built into lws,
463d4afb5ceSopenharmony_ci			 * lws must have been configured and built with
464d4afb5ceSopenharmony_ci			 * -DCMAKE_BUILD_TYPE=DEBUG instead of =RELEASE */
465d4afb5ceSopenharmony_ci			/* | LLL_INFO */ /* | LLL_PARSER */ /* | LLL_HEADER */
466d4afb5ceSopenharmony_ci			/* | LLL_EXT */ /* | LLL_CLIENT */ /* | LLL_LATENCY */
467d4afb5ceSopenharmony_ci			/* | LLL_DEBUG */ /* | LLL_THREAD */;
468d4afb5ceSopenharmony_ci
469d4afb5ceSopenharmony_ci	signal(SIGINT, sigint_handler);
470d4afb5ceSopenharmony_ci
471d4afb5ceSopenharmony_ci	if ((p = lws_cmdline_option(argc, argv, "-d")))
472d4afb5ceSopenharmony_ci		logs = atoi(p);
473d4afb5ceSopenharmony_ci
474d4afb5ceSopenharmony_ci	lws_set_log_level(logs, NULL);
475d4afb5ceSopenharmony_ci	lwsl_user("LWS minimal DBUS server\n");
476d4afb5ceSopenharmony_ci
477d4afb5ceSopenharmony_ci	memset(&info, 0, sizeof info); /* otherwise uninitialized garbage */
478d4afb5ceSopenharmony_ci	info.options = LWS_SERVER_OPTION_EXPLICIT_VHOSTS;
479d4afb5ceSopenharmony_ci	context = lws_create_context(&info);
480d4afb5ceSopenharmony_ci	if (!context) {
481d4afb5ceSopenharmony_ci		lwsl_err("lws init failed\n");
482d4afb5ceSopenharmony_ci		return 1;
483d4afb5ceSopenharmony_ci	}
484d4afb5ceSopenharmony_ci
485d4afb5ceSopenharmony_ci	info.options |=
486d4afb5ceSopenharmony_ci		LWS_SERVER_OPTION_HTTP_HEADERS_SECURITY_BEST_PRACTICES_ENFORCE;
487d4afb5ceSopenharmony_ci
488d4afb5ceSopenharmony_ci	dbus_ctx.tsi = 0;
489d4afb5ceSopenharmony_ci	ctx_listener.tsi = 0;
490d4afb5ceSopenharmony_ci	ctx_listener.vh = dbus_ctx.vh = lws_create_vhost(context, &info);
491d4afb5ceSopenharmony_ci	if (!dbus_ctx.vh)
492d4afb5ceSopenharmony_ci		goto bail;
493d4afb5ceSopenharmony_ci
494d4afb5ceSopenharmony_ci	session = !!lws_cmdline_option(argc, argv, "--session");
495d4afb5ceSopenharmony_ci
496d4afb5ceSopenharmony_ci	if (session) {
497d4afb5ceSopenharmony_ci		/* create the dbus connection, loosely bound to our lws vhost */
498d4afb5ceSopenharmony_ci
499d4afb5ceSopenharmony_ci		if (create_dbus_server_conn(&dbus_ctx, DBUS_BUS_SESSION))
500d4afb5ceSopenharmony_ci			goto bail;
501d4afb5ceSopenharmony_ci	} else {
502d4afb5ceSopenharmony_ci		if (create_dbus_listener(THIS_LISTEN_PATH)) {
503d4afb5ceSopenharmony_ci			lwsl_err("%s: create_dbus_listener failed\n", __func__);
504d4afb5ceSopenharmony_ci			goto bail;
505d4afb5ceSopenharmony_ci		}
506d4afb5ceSopenharmony_ci	}
507d4afb5ceSopenharmony_ci
508d4afb5ceSopenharmony_ci	/* lws event loop (default poll one) */
509d4afb5ceSopenharmony_ci
510d4afb5ceSopenharmony_ci	while (n >= 0 && !interrupted) {
511d4afb5ceSopenharmony_ci		if (!session)
512d4afb5ceSopenharmony_ci			spam_connected_clients(&ctx_listener);
513d4afb5ceSopenharmony_ci		n = lws_service(context, 0);
514d4afb5ceSopenharmony_ci	}
515d4afb5ceSopenharmony_ci
516d4afb5ceSopenharmony_ci	if (session)
517d4afb5ceSopenharmony_ci		destroy_dbus_server_conn(&dbus_ctx);
518d4afb5ceSopenharmony_ci	else
519d4afb5ceSopenharmony_ci		destroy_dbus_server_listener(&ctx_listener);
520d4afb5ceSopenharmony_ci
521d4afb5ceSopenharmony_ci	/* this is required for valgrind-cleanliness */
522d4afb5ceSopenharmony_ci	dbus_shutdown();
523d4afb5ceSopenharmony_ci	lws_context_destroy(context);
524d4afb5ceSopenharmony_ci
525d4afb5ceSopenharmony_ci	lwsl_notice("Exiting cleanly\n");
526d4afb5ceSopenharmony_ci
527d4afb5ceSopenharmony_ci	return 0;
528d4afb5ceSopenharmony_ci
529d4afb5ceSopenharmony_cibail:
530d4afb5ceSopenharmony_ci	lwsl_err("%s: failed to start\n", __func__);
531d4afb5ceSopenharmony_ci
532d4afb5ceSopenharmony_ci	lws_context_destroy(context);
533d4afb5ceSopenharmony_ci
534d4afb5ceSopenharmony_ci	return 1;
535d4afb5ceSopenharmony_ci}
536