1d4afb5ceSopenharmony_ci/*
2d4afb5ceSopenharmony_ci * lws-minimal-dbus-ws-proxy-testclient
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 acts as a test client over DBUS, opening a session with
10d4afb5ceSopenharmony_ci * minimal-dbus-ws-proxy and sending and receiving data on the libwebsockets
11d4afb5ceSopenharmony_ci * mirror demo page.
12d4afb5ceSopenharmony_ci */
13d4afb5ceSopenharmony_ci
14d4afb5ceSopenharmony_ci#include <stdbool.h>
15d4afb5ceSopenharmony_ci#include <string.h>
16d4afb5ceSopenharmony_ci#include <stdio.h>
17d4afb5ceSopenharmony_ci#include <stdlib.h>
18d4afb5ceSopenharmony_ci#include <unistd.h>
19d4afb5ceSopenharmony_ci#include <signal.h>
20d4afb5ceSopenharmony_ci
21d4afb5ceSopenharmony_ci#include <libwebsockets.h>
22d4afb5ceSopenharmony_ci#include <libwebsockets/lws-dbus.h>
23d4afb5ceSopenharmony_ci
24d4afb5ceSopenharmony_ci/*
25d4afb5ceSopenharmony_ci * These are the various states our connection can be in, both with regards
26d4afb5ceSopenharmony_ci * to the direct connection to the proxy, and the state of the onward ws
27d4afb5ceSopenharmony_ci * connection the proxy opens at our request.
28d4afb5ceSopenharmony_ci */
29d4afb5ceSopenharmony_ci
30d4afb5ceSopenharmony_cienum lws_dbus_client_state {
31d4afb5ceSopenharmony_ci	LDCS_NOTHING,		  /* no connection yet */
32d4afb5ceSopenharmony_ci	LDCS_CONN,		  /* conn to proxy */
33d4afb5ceSopenharmony_ci	LDCS_CONN_WAITING_ONWARD, /* conn to proxy, awaiting proxied conn */
34d4afb5ceSopenharmony_ci	LDCS_CONN_ONWARD,	  /* conn to proxy and onward conn OK */
35d4afb5ceSopenharmony_ci	LDCS_CONN_CLOSED,	  /* conn to proxy but onward conn closed */
36d4afb5ceSopenharmony_ci	LDCS_CLOSED,		  /* connection to proxy is closed */
37d4afb5ceSopenharmony_ci};
38d4afb5ceSopenharmony_ci
39d4afb5ceSopenharmony_ci/*
40d4afb5ceSopenharmony_ci * our expanded dbus context
41d4afb5ceSopenharmony_ci */
42d4afb5ceSopenharmony_ci
43d4afb5ceSopenharmony_cistruct lws_dbus_ctx_wsproxy_client {
44d4afb5ceSopenharmony_ci	struct lws_dbus_ctx ctx;
45d4afb5ceSopenharmony_ci
46d4afb5ceSopenharmony_ci	lws_sorted_usec_list_t sul;
47d4afb5ceSopenharmony_ci
48d4afb5ceSopenharmony_ci	enum lws_dbus_client_state state;
49d4afb5ceSopenharmony_ci};
50d4afb5ceSopenharmony_ci
51d4afb5ceSopenharmony_cistatic struct lws_dbus_ctx_wsproxy_client *dbus_ctx;
52d4afb5ceSopenharmony_cistatic struct lws_context *context;
53d4afb5ceSopenharmony_cistatic int interrupted, autoexit_budget = -1, count_rx, count_tx;
54d4afb5ceSopenharmony_ci
55d4afb5ceSopenharmony_ci#define THIS_INTERFACE	 "org.libwebsockets.wsclientproxy"
56d4afb5ceSopenharmony_ci#define THIS_OBJECT	 "/org/libwebsockets/wsclientproxy"
57d4afb5ceSopenharmony_ci#define THIS_BUSNAME	 "org.libwebsockets.wsclientproxy"
58d4afb5ceSopenharmony_ci
59d4afb5ceSopenharmony_ci#define THIS_LISTEN_PATH "unix:abstract=org.libwebsockets.wsclientproxy"
60d4afb5ceSopenharmony_ci
61d4afb5ceSopenharmony_cistatic void
62d4afb5ceSopenharmony_cistate_transition(struct lws_dbus_ctx_wsproxy_client *dcwc,
63d4afb5ceSopenharmony_ci		 enum lws_dbus_client_state state)
64d4afb5ceSopenharmony_ci{
65d4afb5ceSopenharmony_ci	lwsl_notice("%s: %p: from state %d -> %d\n", __func__,
66d4afb5ceSopenharmony_ci		    dcwc,dcwc->state, state);
67d4afb5ceSopenharmony_ci	dcwc->state = state;
68d4afb5ceSopenharmony_ci}
69d4afb5ceSopenharmony_ci
70d4afb5ceSopenharmony_cistatic DBusHandlerResult
71d4afb5ceSopenharmony_cifilter(DBusConnection *conn, DBusMessage *message, void *data)
72d4afb5ceSopenharmony_ci{
73d4afb5ceSopenharmony_ci	struct lws_dbus_ctx_wsproxy_client *dcwc =
74d4afb5ceSopenharmony_ci			(struct lws_dbus_ctx_wsproxy_client *)data;
75d4afb5ceSopenharmony_ci	const char *str;
76d4afb5ceSopenharmony_ci
77d4afb5ceSopenharmony_ci	if (!dbus_message_get_args(message, NULL,
78d4afb5ceSopenharmony_ci				   DBUS_TYPE_STRING, &str,
79d4afb5ceSopenharmony_ci				   DBUS_TYPE_INVALID))
80d4afb5ceSopenharmony_ci		return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
81d4afb5ceSopenharmony_ci
82d4afb5ceSopenharmony_ci	/* received ws data */
83d4afb5ceSopenharmony_ci
84d4afb5ceSopenharmony_ci	if (dbus_message_is_signal(message, THIS_INTERFACE, "Receive")) {
85d4afb5ceSopenharmony_ci		lwsl_user("%s: Received '%s'\n", __func__, str);
86d4afb5ceSopenharmony_ci		count_rx++;
87d4afb5ceSopenharmony_ci	}
88d4afb5ceSopenharmony_ci
89d4afb5ceSopenharmony_ci	/* proxy ws connection failed */
90d4afb5ceSopenharmony_ci
91d4afb5ceSopenharmony_ci	if (dbus_message_is_signal(message, THIS_INTERFACE, "Status") &&
92d4afb5ceSopenharmony_ci	    !strcmp(str, "ws client connection error"))
93d4afb5ceSopenharmony_ci		state_transition(dcwc, LDCS_CONN_CLOSED);
94d4afb5ceSopenharmony_ci
95d4afb5ceSopenharmony_ci	/* proxy ws connection succeeded */
96d4afb5ceSopenharmony_ci
97d4afb5ceSopenharmony_ci	if (dbus_message_is_signal(message, THIS_INTERFACE, "Status") &&
98d4afb5ceSopenharmony_ci	    !strcmp(str, "ws client connection established"))
99d4afb5ceSopenharmony_ci		state_transition(dcwc, LDCS_CONN_ONWARD);
100d4afb5ceSopenharmony_ci
101d4afb5ceSopenharmony_ci	/* proxy ws connection has closed */
102d4afb5ceSopenharmony_ci
103d4afb5ceSopenharmony_ci	if (dbus_message_is_signal(message, THIS_INTERFACE, "Status") &&
104d4afb5ceSopenharmony_ci	    !strcmp(str, "ws client connection closed"))
105d4afb5ceSopenharmony_ci		state_transition(dcwc, LDCS_CONN_CLOSED);
106d4afb5ceSopenharmony_ci
107d4afb5ceSopenharmony_ci	return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
108d4afb5ceSopenharmony_ci}
109d4afb5ceSopenharmony_ci
110d4afb5ceSopenharmony_cistatic void
111d4afb5ceSopenharmony_cidestroy_dbus_client_conn(struct lws_dbus_ctx_wsproxy_client **pdcwc)
112d4afb5ceSopenharmony_ci{
113d4afb5ceSopenharmony_ci	struct lws_dbus_ctx_wsproxy_client *dcwc = *pdcwc;
114d4afb5ceSopenharmony_ci
115d4afb5ceSopenharmony_ci	if (!dcwc || !dcwc->ctx.conn)
116d4afb5ceSopenharmony_ci		return;
117d4afb5ceSopenharmony_ci
118d4afb5ceSopenharmony_ci	lwsl_notice("%s\n", __func__);
119d4afb5ceSopenharmony_ci
120d4afb5ceSopenharmony_ci	dbus_connection_remove_filter(dcwc->ctx.conn, filter, &dcwc->ctx);
121d4afb5ceSopenharmony_ci	dbus_connection_close(dcwc->ctx.conn);
122d4afb5ceSopenharmony_ci	dbus_connection_unref(dcwc->ctx.conn);
123d4afb5ceSopenharmony_ci
124d4afb5ceSopenharmony_ci	free(dcwc);
125d4afb5ceSopenharmony_ci
126d4afb5ceSopenharmony_ci	*pdcwc = NULL;
127d4afb5ceSopenharmony_ci}
128d4afb5ceSopenharmony_ci
129d4afb5ceSopenharmony_ci/*
130d4afb5ceSopenharmony_ci * This callback is coming when lws has noticed the fd took a POLLHUP.  The
131d4afb5ceSopenharmony_ci * ctx has effectively gone out of scope before this, and the connection can
132d4afb5ceSopenharmony_ci * be cleaned up and the ctx freed.
133d4afb5ceSopenharmony_ci */
134d4afb5ceSopenharmony_ci
135d4afb5ceSopenharmony_cistatic void
136d4afb5ceSopenharmony_cicb_closing(struct lws_dbus_ctx *ctx)
137d4afb5ceSopenharmony_ci{
138d4afb5ceSopenharmony_ci	struct lws_dbus_ctx_wsproxy_client *dcwc =
139d4afb5ceSopenharmony_ci			(struct lws_dbus_ctx_wsproxy_client *)ctx;
140d4afb5ceSopenharmony_ci
141d4afb5ceSopenharmony_ci	lwsl_err("%s: closing\n", __func__);
142d4afb5ceSopenharmony_ci
143d4afb5ceSopenharmony_ci	if (dcwc == dbus_ctx)
144d4afb5ceSopenharmony_ci		dbus_ctx = NULL;
145d4afb5ceSopenharmony_ci
146d4afb5ceSopenharmony_ci	destroy_dbus_client_conn(&dcwc);
147d4afb5ceSopenharmony_ci
148d4afb5ceSopenharmony_ci	interrupted = 1;
149d4afb5ceSopenharmony_ci}
150d4afb5ceSopenharmony_ci
151d4afb5ceSopenharmony_cistatic struct lws_dbus_ctx_wsproxy_client *
152d4afb5ceSopenharmony_cicreate_dbus_client_conn(struct lws_vhost *vh, int tsi, const char *ads)
153d4afb5ceSopenharmony_ci{
154d4afb5ceSopenharmony_ci	struct lws_dbus_ctx_wsproxy_client *dcwc;
155d4afb5ceSopenharmony_ci	DBusError e;
156d4afb5ceSopenharmony_ci
157d4afb5ceSopenharmony_ci	dcwc = malloc(sizeof(*dcwc));
158d4afb5ceSopenharmony_ci	if (!dcwc)
159d4afb5ceSopenharmony_ci		return NULL;
160d4afb5ceSopenharmony_ci
161d4afb5ceSopenharmony_ci	memset(dcwc, 0, sizeof(*dcwc));
162d4afb5ceSopenharmony_ci
163d4afb5ceSopenharmony_ci	dcwc->state = LDCS_NOTHING;
164d4afb5ceSopenharmony_ci	dcwc->ctx.vh = vh;
165d4afb5ceSopenharmony_ci	dcwc->ctx.tsi = tsi;
166d4afb5ceSopenharmony_ci
167d4afb5ceSopenharmony_ci        dbus_error_init(&e);
168d4afb5ceSopenharmony_ci
169d4afb5ceSopenharmony_ci        lwsl_user("%s: connecting to '%s'\n", __func__, ads);
170d4afb5ceSopenharmony_ci#if 1
171d4afb5ceSopenharmony_ci	/* connect to our daemon bus */
172d4afb5ceSopenharmony_ci
173d4afb5ceSopenharmony_ci        dcwc->ctx.conn = dbus_connection_open_private(ads, &e);
174d4afb5ceSopenharmony_ci	if (!dcwc->ctx.conn) {
175d4afb5ceSopenharmony_ci		lwsl_err("%s: Failed to connect: %s\n",
176d4afb5ceSopenharmony_ci			 __func__, e.message);
177d4afb5ceSopenharmony_ci		goto fail;
178d4afb5ceSopenharmony_ci	}
179d4afb5ceSopenharmony_ci#else
180d4afb5ceSopenharmony_ci	/* connect to the SYSTEM bus */
181d4afb5ceSopenharmony_ci
182d4afb5ceSopenharmony_ci	dcwc->ctx.conn = dbus_bus_get(DBUS_BUS_SYSTEM, &e);
183d4afb5ceSopenharmony_ci	if (!dcwc->ctx.conn) {
184d4afb5ceSopenharmony_ci		lwsl_err("%s: Failed to get a session DBus connection: %s\n",
185d4afb5ceSopenharmony_ci			 __func__, e.message);
186d4afb5ceSopenharmony_ci		goto fail;
187d4afb5ceSopenharmony_ci	}
188d4afb5ceSopenharmony_ci#endif
189d4afb5ceSopenharmony_ci	dbus_connection_set_exit_on_disconnect(dcwc->ctx.conn, 0);
190d4afb5ceSopenharmony_ci
191d4afb5ceSopenharmony_ci	if (!dbus_connection_add_filter(dcwc->ctx.conn, filter,
192d4afb5ceSopenharmony_ci					&dcwc->ctx, NULL)) {
193d4afb5ceSopenharmony_ci		lwsl_err("%s: Failed to add filter\n", __func__);
194d4afb5ceSopenharmony_ci		goto fail;
195d4afb5ceSopenharmony_ci	}
196d4afb5ceSopenharmony_ci
197d4afb5ceSopenharmony_ci	/*
198d4afb5ceSopenharmony_ci	 * This is the part that binds the connection to lws watcher and
199d4afb5ceSopenharmony_ci	 * timeout handling provided by lws
200d4afb5ceSopenharmony_ci	 */
201d4afb5ceSopenharmony_ci
202d4afb5ceSopenharmony_ci	if (lws_dbus_connection_setup(&dcwc->ctx, dcwc->ctx.conn, cb_closing)) {
203d4afb5ceSopenharmony_ci		lwsl_err("%s: connection bind to lws failed\n", __func__);
204d4afb5ceSopenharmony_ci		goto fail;
205d4afb5ceSopenharmony_ci	}
206d4afb5ceSopenharmony_ci
207d4afb5ceSopenharmony_ci	state_transition(dcwc, LDCS_CONN);
208d4afb5ceSopenharmony_ci
209d4afb5ceSopenharmony_ci	lwsl_notice("%s: created OK\n", __func__);
210d4afb5ceSopenharmony_ci
211d4afb5ceSopenharmony_ci	return dcwc;
212d4afb5ceSopenharmony_ci
213d4afb5ceSopenharmony_cifail:
214d4afb5ceSopenharmony_ci	dbus_error_free(&e);
215d4afb5ceSopenharmony_ci
216d4afb5ceSopenharmony_ci	free(dcwc);
217d4afb5ceSopenharmony_ci
218d4afb5ceSopenharmony_ci	return NULL;
219d4afb5ceSopenharmony_ci}
220d4afb5ceSopenharmony_ci
221d4afb5ceSopenharmony_ci
222d4afb5ceSopenharmony_civoid sigint_handler(int sig)
223d4afb5ceSopenharmony_ci{
224d4afb5ceSopenharmony_ci	interrupted = 1;
225d4afb5ceSopenharmony_ci}
226d4afb5ceSopenharmony_ci
227d4afb5ceSopenharmony_ci/*
228d4afb5ceSopenharmony_ci * This gets called if we timed out waiting for the dbus server reply, or the
229d4afb5ceSopenharmony_ci * reply arrived.
230d4afb5ceSopenharmony_ci */
231d4afb5ceSopenharmony_ci
232d4afb5ceSopenharmony_cistatic void
233d4afb5ceSopenharmony_cipending_call_notify(DBusPendingCall *pending, void *data)
234d4afb5ceSopenharmony_ci{
235d4afb5ceSopenharmony_ci	const char *payload;
236d4afb5ceSopenharmony_ci	DBusMessage *msg;
237d4afb5ceSopenharmony_ci
238d4afb5ceSopenharmony_ci	if (!dbus_pending_call_get_completed(pending)) {
239d4afb5ceSopenharmony_ci		lwsl_err("%s: timed out waiting for reply\n", __func__);
240d4afb5ceSopenharmony_ci
241d4afb5ceSopenharmony_ci		goto bail;
242d4afb5ceSopenharmony_ci	}
243d4afb5ceSopenharmony_ci
244d4afb5ceSopenharmony_ci	msg = dbus_pending_call_steal_reply(pending);
245d4afb5ceSopenharmony_ci	if (!msg)
246d4afb5ceSopenharmony_ci		goto bail;
247d4afb5ceSopenharmony_ci
248d4afb5ceSopenharmony_ci	if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &payload,
249d4afb5ceSopenharmony_ci					      DBUS_TYPE_INVALID)) {
250d4afb5ceSopenharmony_ci		goto bail1;
251d4afb5ceSopenharmony_ci	}
252d4afb5ceSopenharmony_ci
253d4afb5ceSopenharmony_ci	lwsl_user("%s: received '%s'\n", __func__, payload);
254d4afb5ceSopenharmony_ci
255d4afb5ceSopenharmony_cibail1:
256d4afb5ceSopenharmony_ci	dbus_message_unref(msg);
257d4afb5ceSopenharmony_cibail:
258d4afb5ceSopenharmony_ci	dbus_pending_call_unref(pending);
259d4afb5ceSopenharmony_ci}
260d4afb5ceSopenharmony_ci
261d4afb5ceSopenharmony_cistatic int
262d4afb5ceSopenharmony_ciremote_method_call(struct lws_dbus_ctx_wsproxy_client *dcwc)
263d4afb5ceSopenharmony_ci{
264d4afb5ceSopenharmony_ci	char _uri[96];
265d4afb5ceSopenharmony_ci	const char *subprotocol = "lws-mirror-protocol", *uri = _uri;
266d4afb5ceSopenharmony_ci	DBusMessage *msg;
267d4afb5ceSopenharmony_ci	int ret = 1;
268d4afb5ceSopenharmony_ci
269d4afb5ceSopenharmony_ci	/*
270d4afb5ceSopenharmony_ci	 * make our own private mirror session... because others may run this
271d4afb5ceSopenharmony_ci	 * at the same time against libwebsockets.org... as happened 2019-03-14
272d4afb5ceSopenharmony_ci	 * and broke travis tests :-)
273d4afb5ceSopenharmony_ci	 */
274d4afb5ceSopenharmony_ci
275d4afb5ceSopenharmony_ci	lws_snprintf(_uri, sizeof(_uri), "wss://libwebsockets.org/?mirror=dbt-%d",
276d4afb5ceSopenharmony_ci			(int)getpid());
277d4afb5ceSopenharmony_ci
278d4afb5ceSopenharmony_ci	msg = dbus_message_new_method_call(
279d4afb5ceSopenharmony_ci			/* dest */	  THIS_BUSNAME,
280d4afb5ceSopenharmony_ci			/* object-path */ THIS_OBJECT,
281d4afb5ceSopenharmony_ci			/* interface */   THIS_INTERFACE,
282d4afb5ceSopenharmony_ci			/* method */	  "Connect");
283d4afb5ceSopenharmony_ci	if (!msg)
284d4afb5ceSopenharmony_ci		return 1;
285d4afb5ceSopenharmony_ci
286d4afb5ceSopenharmony_ci	if (!dbus_message_append_args(msg, DBUS_TYPE_STRING, &uri,
287d4afb5ceSopenharmony_ci					   DBUS_TYPE_STRING, &subprotocol,
288d4afb5ceSopenharmony_ci					   DBUS_TYPE_INVALID))
289d4afb5ceSopenharmony_ci		goto bail;
290d4afb5ceSopenharmony_ci
291d4afb5ceSopenharmony_ci	lwsl_user("%s: requesting proxy connection %s %s\n", __func__,
292d4afb5ceSopenharmony_ci			uri, subprotocol);
293d4afb5ceSopenharmony_ci
294d4afb5ceSopenharmony_ci	if (!dbus_connection_send_with_reply(dcwc->ctx.conn, msg, &dcwc->ctx.pc,
295d4afb5ceSopenharmony_ci					     DBUS_TIMEOUT_USE_DEFAULT)) {
296d4afb5ceSopenharmony_ci		lwsl_err("%s: unable to send\n", __func__);
297d4afb5ceSopenharmony_ci
298d4afb5ceSopenharmony_ci		goto bail;
299d4afb5ceSopenharmony_ci	}
300d4afb5ceSopenharmony_ci
301d4afb5ceSopenharmony_ci	dbus_pending_call_set_notify(dcwc->ctx.pc, pending_call_notify,
302d4afb5ceSopenharmony_ci				     &dcwc->ctx, NULL);
303d4afb5ceSopenharmony_ci
304d4afb5ceSopenharmony_ci	state_transition(dcwc, LDCS_CONN_WAITING_ONWARD);
305d4afb5ceSopenharmony_ci
306d4afb5ceSopenharmony_ci	ret = 0;
307d4afb5ceSopenharmony_ci
308d4afb5ceSopenharmony_cibail:
309d4afb5ceSopenharmony_ci	dbus_message_unref(msg);
310d4afb5ceSopenharmony_ci
311d4afb5ceSopenharmony_ci	return ret;
312d4afb5ceSopenharmony_ci}
313d4afb5ceSopenharmony_ci
314d4afb5ceSopenharmony_cistatic void
315d4afb5ceSopenharmony_cisul_timer(struct lws_sorted_usec_list *sul)
316d4afb5ceSopenharmony_ci{
317d4afb5ceSopenharmony_ci	char payload[64];
318d4afb5ceSopenharmony_ci	const char *ws_pkt = payload;
319d4afb5ceSopenharmony_ci	DBusMessage *msg;
320d4afb5ceSopenharmony_ci
321d4afb5ceSopenharmony_ci	if (!dbus_ctx || dbus_ctx->state != LDCS_CONN_ONWARD)
322d4afb5ceSopenharmony_ci		goto again;
323d4afb5ceSopenharmony_ci
324d4afb5ceSopenharmony_ci	if (autoexit_budget > 0) {
325d4afb5ceSopenharmony_ci		if (!--autoexit_budget) {
326d4afb5ceSopenharmony_ci			lwsl_notice("reached autoexit budget\n");
327d4afb5ceSopenharmony_ci			interrupted = 1;
328d4afb5ceSopenharmony_ci			return;
329d4afb5ceSopenharmony_ci		}
330d4afb5ceSopenharmony_ci	}
331d4afb5ceSopenharmony_ci
332d4afb5ceSopenharmony_ci	msg = dbus_message_new_method_call(THIS_BUSNAME, THIS_OBJECT,
333d4afb5ceSopenharmony_ci					   THIS_INTERFACE, "Send");
334d4afb5ceSopenharmony_ci	if (!msg)
335d4afb5ceSopenharmony_ci		goto again;
336d4afb5ceSopenharmony_ci
337d4afb5ceSopenharmony_ci	lws_snprintf(payload, sizeof(payload), "d #%06X %d %d %d %d;",
338d4afb5ceSopenharmony_ci		     rand() & 0xffffff, rand() % 480, rand() % 300,
339d4afb5ceSopenharmony_ci		     rand() % 480, rand() % 300);
340d4afb5ceSopenharmony_ci
341d4afb5ceSopenharmony_ci	if (!dbus_message_append_args(msg, DBUS_TYPE_STRING, &ws_pkt,
342d4afb5ceSopenharmony_ci					   DBUS_TYPE_INVALID)) {
343d4afb5ceSopenharmony_ci		dbus_message_unref(msg);
344d4afb5ceSopenharmony_ci		goto again;
345d4afb5ceSopenharmony_ci	}
346d4afb5ceSopenharmony_ci
347d4afb5ceSopenharmony_ci	if (!dbus_connection_send_with_reply(dbus_ctx->ctx.conn, msg,
348d4afb5ceSopenharmony_ci					     &dbus_ctx->ctx.pc,
349d4afb5ceSopenharmony_ci					    DBUS_TIMEOUT_USE_DEFAULT)) {
350d4afb5ceSopenharmony_ci		lwsl_err("%s: unable to send\n", __func__);
351d4afb5ceSopenharmony_ci		dbus_message_unref(msg);
352d4afb5ceSopenharmony_ci		goto again;
353d4afb5ceSopenharmony_ci	}
354d4afb5ceSopenharmony_ci
355d4afb5ceSopenharmony_ci	dbus_message_unref(msg);
356d4afb5ceSopenharmony_ci	dbus_pending_call_set_notify(dbus_ctx->ctx.pc,
357d4afb5ceSopenharmony_ci				     pending_call_notify,
358d4afb5ceSopenharmony_ci				     &dbus_ctx->ctx, NULL);
359d4afb5ceSopenharmony_ci	count_tx++;
360d4afb5ceSopenharmony_ci
361d4afb5ceSopenharmony_ciagain:
362d4afb5ceSopenharmony_ci	lws_sul_schedule(context, 0, &dbus_ctx->sul, sul_timer, 2 * LWS_US_PER_SEC);
363d4afb5ceSopenharmony_ci}
364d4afb5ceSopenharmony_ci
365d4afb5ceSopenharmony_ciint main(int argc, const char **argv)
366d4afb5ceSopenharmony_ci{
367d4afb5ceSopenharmony_ci	struct lws_vhost *vh;
368d4afb5ceSopenharmony_ci	struct lws_context_creation_info info;
369d4afb5ceSopenharmony_ci	const char *p;
370d4afb5ceSopenharmony_ci	int n = 0, logs = LLL_USER | LLL_ERR | LLL_WARN | LLL_NOTICE
371d4afb5ceSopenharmony_ci			/* for LLL_ verbosity above NOTICE to be built into lws,
372d4afb5ceSopenharmony_ci			 * lws must have been configured and built with
373d4afb5ceSopenharmony_ci			 * -DCMAKE_BUILD_TYPE=DEBUG instead of =RELEASE */
374d4afb5ceSopenharmony_ci			/* | LLL_INFO */ /* | LLL_PARSER */ /* | LLL_HEADER */
375d4afb5ceSopenharmony_ci			/* | LLL_EXT */ /* | LLL_CLIENT */ /* | LLL_LATENCY */
376d4afb5ceSopenharmony_ci			/* | LLL_DEBUG */ /* | LLL_THREAD */;
377d4afb5ceSopenharmony_ci
378d4afb5ceSopenharmony_ci	signal(SIGINT, sigint_handler);
379d4afb5ceSopenharmony_ci
380d4afb5ceSopenharmony_ci	if ((p = lws_cmdline_option(argc, argv, "-d")))
381d4afb5ceSopenharmony_ci		logs = atoi(p);
382d4afb5ceSopenharmony_ci
383d4afb5ceSopenharmony_ci	if ((p = lws_cmdline_option(argc, argv, "-x")))
384d4afb5ceSopenharmony_ci		autoexit_budget = atoi(p);
385d4afb5ceSopenharmony_ci
386d4afb5ceSopenharmony_ci	lws_set_log_level(logs, NULL);
387d4afb5ceSopenharmony_ci	lwsl_user("LWS minimal DBUS ws proxy testclient\n");
388d4afb5ceSopenharmony_ci
389d4afb5ceSopenharmony_ci	memset(&info, 0, sizeof info); /* otherwise uninitialized garbage */
390d4afb5ceSopenharmony_ci	info.options = LWS_SERVER_OPTION_EXPLICIT_VHOSTS;
391d4afb5ceSopenharmony_ci	context = lws_create_context(&info);
392d4afb5ceSopenharmony_ci	if (!context) {
393d4afb5ceSopenharmony_ci		lwsl_err("lws init failed\n");
394d4afb5ceSopenharmony_ci		return 1;
395d4afb5ceSopenharmony_ci	}
396d4afb5ceSopenharmony_ci
397d4afb5ceSopenharmony_ci	info.options |=
398d4afb5ceSopenharmony_ci		LWS_SERVER_OPTION_HTTP_HEADERS_SECURITY_BEST_PRACTICES_ENFORCE;
399d4afb5ceSopenharmony_ci
400d4afb5ceSopenharmony_ci	vh = lws_create_vhost(context, &info);
401d4afb5ceSopenharmony_ci	if (!vh)
402d4afb5ceSopenharmony_ci		goto bail;
403d4afb5ceSopenharmony_ci
404d4afb5ceSopenharmony_ci	dbus_ctx = create_dbus_client_conn(vh, 0, THIS_LISTEN_PATH);
405d4afb5ceSopenharmony_ci	if (!dbus_ctx)
406d4afb5ceSopenharmony_ci		goto bail1;
407d4afb5ceSopenharmony_ci
408d4afb5ceSopenharmony_ci	lws_sul_schedule(context, 0, &dbus_ctx->sul, sul_timer, LWS_US_PER_SEC);
409d4afb5ceSopenharmony_ci
410d4afb5ceSopenharmony_ci
411d4afb5ceSopenharmony_ci	if (remote_method_call(dbus_ctx))
412d4afb5ceSopenharmony_ci		goto bail2;
413d4afb5ceSopenharmony_ci
414d4afb5ceSopenharmony_ci	/* lws event loop (default poll one) */
415d4afb5ceSopenharmony_ci
416d4afb5ceSopenharmony_ci	while (n >= 0 && !interrupted)
417d4afb5ceSopenharmony_ci		n = lws_service(context, 0);
418d4afb5ceSopenharmony_ci
419d4afb5ceSopenharmony_cibail2:
420d4afb5ceSopenharmony_ci	destroy_dbus_client_conn(&dbus_ctx);
421d4afb5ceSopenharmony_ci
422d4afb5ceSopenharmony_cibail1:
423d4afb5ceSopenharmony_ci	/* this is required for valgrind-cleanliness */
424d4afb5ceSopenharmony_ci	dbus_shutdown();
425d4afb5ceSopenharmony_ci	lws_context_destroy(context);
426d4afb5ceSopenharmony_ci
427d4afb5ceSopenharmony_ci	lwsl_notice("Exiting cleanly, rx: %d, tx: %d\n", count_rx, count_tx);
428d4afb5ceSopenharmony_ci
429d4afb5ceSopenharmony_ci	return 0;
430d4afb5ceSopenharmony_ci
431d4afb5ceSopenharmony_cibail:
432d4afb5ceSopenharmony_ci	lwsl_err("%s: failed to start\n", __func__);
433d4afb5ceSopenharmony_ci	lws_context_destroy(context);
434d4afb5ceSopenharmony_ci
435d4afb5ceSopenharmony_ci	return 1;
436d4afb5ceSopenharmony_ci}
437