xref: /aosp_15_r20/external/libwebsockets/plugins/protocol_lws_status.c (revision 1c60b9aca93fdbc9b5f19b2d2194c91294b22281)
1*1c60b9acSAndroid Build Coastguard Worker /*
2*1c60b9acSAndroid Build Coastguard Worker  * libwebsockets-test-server - libwebsockets test implementation
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  * The person who associated a work with this deed has dedicated
10*1c60b9acSAndroid Build Coastguard Worker  * the work to the public domain by waiving all of his or her rights
11*1c60b9acSAndroid Build Coastguard Worker  * to the work worldwide under copyright law, including all related
12*1c60b9acSAndroid Build Coastguard Worker  * and neighboring rights, to the extent allowed by law. You can copy,
13*1c60b9acSAndroid Build Coastguard Worker  * modify, distribute and perform the work, even for commercial purposes,
14*1c60b9acSAndroid Build Coastguard Worker  * all without asking permission.
15*1c60b9acSAndroid Build Coastguard Worker  *
16*1c60b9acSAndroid Build Coastguard Worker  * The test apps are intended to be adapted for use in your code, which
17*1c60b9acSAndroid Build Coastguard Worker  * may be proprietary.  So unlike the library itself, they are licensed
18*1c60b9acSAndroid Build Coastguard Worker  * Public Domain.
19*1c60b9acSAndroid Build Coastguard Worker  */
20*1c60b9acSAndroid Build Coastguard Worker 
21*1c60b9acSAndroid Build Coastguard Worker #if !defined (LWS_PLUGIN_STATIC)
22*1c60b9acSAndroid Build Coastguard Worker #if !defined(LWS_DLL)
23*1c60b9acSAndroid Build Coastguard Worker #define LWS_DLL
24*1c60b9acSAndroid Build Coastguard Worker #endif
25*1c60b9acSAndroid Build Coastguard Worker #if !defined(LWS_INTERNAL)
26*1c60b9acSAndroid Build Coastguard Worker #define LWS_INTERNAL
27*1c60b9acSAndroid Build Coastguard Worker #endif
28*1c60b9acSAndroid Build Coastguard Worker #include <libwebsockets.h>
29*1c60b9acSAndroid Build Coastguard Worker #endif
30*1c60b9acSAndroid Build Coastguard Worker 
31*1c60b9acSAndroid Build Coastguard Worker #include <time.h>
32*1c60b9acSAndroid Build Coastguard Worker #include <string.h>
33*1c60b9acSAndroid Build Coastguard Worker #ifdef WIN32
34*1c60b9acSAndroid Build Coastguard Worker #include <io.h>
35*1c60b9acSAndroid Build Coastguard Worker #include <gettimeofday.h>
36*1c60b9acSAndroid Build Coastguard Worker #endif
37*1c60b9acSAndroid Build Coastguard Worker 
38*1c60b9acSAndroid Build Coastguard Worker 
39*1c60b9acSAndroid Build Coastguard Worker typedef enum {
40*1c60b9acSAndroid Build Coastguard Worker 	WALK_NONE,
41*1c60b9acSAndroid Build Coastguard Worker 	WALK_INITIAL,
42*1c60b9acSAndroid Build Coastguard Worker 	WALK_LIST,
43*1c60b9acSAndroid Build Coastguard Worker 	WALK_FINAL
44*1c60b9acSAndroid Build Coastguard Worker } e_walk;
45*1c60b9acSAndroid Build Coastguard Worker 
46*1c60b9acSAndroid Build Coastguard Worker struct per_session_data__lws_status {
47*1c60b9acSAndroid Build Coastguard Worker 	struct per_session_data__lws_status *next;
48*1c60b9acSAndroid Build Coastguard Worker 	struct lws *wsi;
49*1c60b9acSAndroid Build Coastguard Worker 	time_t time_est;
50*1c60b9acSAndroid Build Coastguard Worker 	char user_agent[256];
51*1c60b9acSAndroid Build Coastguard Worker 
52*1c60b9acSAndroid Build Coastguard Worker 	e_walk walk;
53*1c60b9acSAndroid Build Coastguard Worker 	struct per_session_data__lws_status *walk_next;
54*1c60b9acSAndroid Build Coastguard Worker 	unsigned char subsequent:1;
55*1c60b9acSAndroid Build Coastguard Worker 	unsigned char changed_partway:1;
56*1c60b9acSAndroid Build Coastguard Worker 	unsigned char wss_over_h2:1;
57*1c60b9acSAndroid Build Coastguard Worker };
58*1c60b9acSAndroid Build Coastguard Worker 
59*1c60b9acSAndroid Build Coastguard Worker struct per_vhost_data__lws_status {
60*1c60b9acSAndroid Build Coastguard Worker 	struct per_session_data__lws_status *live_pss_list;
61*1c60b9acSAndroid Build Coastguard Worker 	struct lws_context *context;
62*1c60b9acSAndroid Build Coastguard Worker 	struct lws_vhost *vhost;
63*1c60b9acSAndroid Build Coastguard Worker 	const struct lws_protocols *protocol;
64*1c60b9acSAndroid Build Coastguard Worker 	int count_live_pss;
65*1c60b9acSAndroid Build Coastguard Worker };
66*1c60b9acSAndroid Build Coastguard Worker 
67*1c60b9acSAndroid Build Coastguard Worker static void
trigger_resend(struct per_vhost_data__lws_status * vhd)68*1c60b9acSAndroid Build Coastguard Worker trigger_resend(struct per_vhost_data__lws_status *vhd)
69*1c60b9acSAndroid Build Coastguard Worker {
70*1c60b9acSAndroid Build Coastguard Worker 	lws_start_foreach_ll(struct per_session_data__lws_status *, pss,
71*1c60b9acSAndroid Build Coastguard Worker 			     vhd->live_pss_list) {
72*1c60b9acSAndroid Build Coastguard Worker 		if (pss->walk == WALK_NONE) {
73*1c60b9acSAndroid Build Coastguard Worker 			pss->subsequent = 0;
74*1c60b9acSAndroid Build Coastguard Worker 			pss->walk_next = vhd->live_pss_list;
75*1c60b9acSAndroid Build Coastguard Worker 			pss->walk = WALK_INITIAL;
76*1c60b9acSAndroid Build Coastguard Worker 		} else
77*1c60b9acSAndroid Build Coastguard Worker 			pss->changed_partway = 1;
78*1c60b9acSAndroid Build Coastguard Worker 	} lws_end_foreach_ll(pss, next);
79*1c60b9acSAndroid Build Coastguard Worker 
80*1c60b9acSAndroid Build Coastguard Worker 	lws_callback_on_writable_all_protocol(vhd->context, vhd->protocol);
81*1c60b9acSAndroid Build Coastguard Worker }
82*1c60b9acSAndroid Build Coastguard Worker 
83*1c60b9acSAndroid Build Coastguard Worker /* lws-status protocol */
84*1c60b9acSAndroid Build Coastguard Worker 
85*1c60b9acSAndroid Build Coastguard Worker int
callback_lws_status(struct lws * wsi,enum lws_callback_reasons reason,void * user,void * in,size_t len)86*1c60b9acSAndroid Build Coastguard Worker callback_lws_status(struct lws *wsi, enum lws_callback_reasons reason,
87*1c60b9acSAndroid Build Coastguard Worker 		    void *user, void *in, size_t len)
88*1c60b9acSAndroid Build Coastguard Worker {
89*1c60b9acSAndroid Build Coastguard Worker 	struct per_session_data__lws_status *pss =
90*1c60b9acSAndroid Build Coastguard Worker 			(struct per_session_data__lws_status *)user;
91*1c60b9acSAndroid Build Coastguard Worker 	struct per_vhost_data__lws_status *vhd =
92*1c60b9acSAndroid Build Coastguard Worker 			(struct per_vhost_data__lws_status *)
93*1c60b9acSAndroid Build Coastguard Worker 			lws_protocol_vh_priv_get(lws_get_vhost(wsi),
94*1c60b9acSAndroid Build Coastguard Worker 					lws_get_protocol(wsi));
95*1c60b9acSAndroid Build Coastguard Worker 	char buf[LWS_PRE + 384], ip[24], *start = buf + LWS_PRE - 1, *p = start,
96*1c60b9acSAndroid Build Coastguard Worker 	     *end = buf + sizeof(buf) - 1;
97*1c60b9acSAndroid Build Coastguard Worker 	int n, m;
98*1c60b9acSAndroid Build Coastguard Worker 
99*1c60b9acSAndroid Build Coastguard Worker 	switch (reason) {
100*1c60b9acSAndroid Build Coastguard Worker 
101*1c60b9acSAndroid Build Coastguard Worker 	case LWS_CALLBACK_PROTOCOL_INIT:
102*1c60b9acSAndroid Build Coastguard Worker 		vhd = lws_protocol_vh_priv_zalloc(lws_get_vhost(wsi),
103*1c60b9acSAndroid Build Coastguard Worker 				lws_get_protocol(wsi),
104*1c60b9acSAndroid Build Coastguard Worker 				sizeof(struct per_vhost_data__lws_status));
105*1c60b9acSAndroid Build Coastguard Worker 		if (!vhd) {
106*1c60b9acSAndroid Build Coastguard Worker 			lwsl_notice("%s: PROTOCOL_INIT failed\n", __func__);
107*1c60b9acSAndroid Build Coastguard Worker 			return 0;
108*1c60b9acSAndroid Build Coastguard Worker 		}
109*1c60b9acSAndroid Build Coastguard Worker 		vhd->context = lws_get_context(wsi);
110*1c60b9acSAndroid Build Coastguard Worker 		vhd->protocol = lws_get_protocol(wsi);
111*1c60b9acSAndroid Build Coastguard Worker 		vhd->vhost = lws_get_vhost(wsi);
112*1c60b9acSAndroid Build Coastguard Worker 		break;
113*1c60b9acSAndroid Build Coastguard Worker 
114*1c60b9acSAndroid Build Coastguard Worker 	case LWS_CALLBACK_ESTABLISHED:
115*1c60b9acSAndroid Build Coastguard Worker 
116*1c60b9acSAndroid Build Coastguard Worker 		/*
117*1c60b9acSAndroid Build Coastguard Worker 		 * This shows how to stage sending a single ws message in
118*1c60b9acSAndroid Build Coastguard Worker 		 * multiple fragments.  In this case, it lets us trade off
119*1c60b9acSAndroid Build Coastguard Worker 		 * memory needed to make the data vs time to send it.
120*1c60b9acSAndroid Build Coastguard Worker 		 */
121*1c60b9acSAndroid Build Coastguard Worker 
122*1c60b9acSAndroid Build Coastguard Worker 		vhd->count_live_pss++;
123*1c60b9acSAndroid Build Coastguard Worker 		pss->next = vhd->live_pss_list;
124*1c60b9acSAndroid Build Coastguard Worker 		vhd->live_pss_list = pss;
125*1c60b9acSAndroid Build Coastguard Worker 
126*1c60b9acSAndroid Build Coastguard Worker 		pss->wss_over_h2 = !!len;
127*1c60b9acSAndroid Build Coastguard Worker 
128*1c60b9acSAndroid Build Coastguard Worker 		time(&pss->time_est);
129*1c60b9acSAndroid Build Coastguard Worker 		pss->wsi = wsi;
130*1c60b9acSAndroid Build Coastguard Worker 
131*1c60b9acSAndroid Build Coastguard Worker #if defined(LWS_WITH_HTTP_UNCOMMON_HEADERS)
132*1c60b9acSAndroid Build Coastguard Worker 		if (lws_hdr_copy(wsi, pss->user_agent, sizeof(pss->user_agent),
133*1c60b9acSAndroid Build Coastguard Worker 			     WSI_TOKEN_HTTP_USER_AGENT) < 0) /* too big */
134*1c60b9acSAndroid Build Coastguard Worker #endif
135*1c60b9acSAndroid Build Coastguard Worker 			strcpy(pss->user_agent, "unknown");
136*1c60b9acSAndroid Build Coastguard Worker 		trigger_resend(vhd);
137*1c60b9acSAndroid Build Coastguard Worker 		break;
138*1c60b9acSAndroid Build Coastguard Worker 
139*1c60b9acSAndroid Build Coastguard Worker 	case LWS_CALLBACK_SERVER_WRITEABLE:
140*1c60b9acSAndroid Build Coastguard Worker 		switch (pss->walk) {
141*1c60b9acSAndroid Build Coastguard Worker 		case WALK_INITIAL:
142*1c60b9acSAndroid Build Coastguard Worker 			n = LWS_WRITE_TEXT | LWS_WRITE_NO_FIN;
143*1c60b9acSAndroid Build Coastguard Worker 			p += lws_snprintf(p, lws_ptr_diff_size_t(end, p),
144*1c60b9acSAndroid Build Coastguard Worker 				      "{ \"version\":\"%s\","
145*1c60b9acSAndroid Build Coastguard Worker 				      " \"wss_over_h2\":\"%d\","
146*1c60b9acSAndroid Build Coastguard Worker 				      " \"hostname\":\"%s\","
147*1c60b9acSAndroid Build Coastguard Worker 				      " \"wsi\":\"%d\", \"conns\":[",
148*1c60b9acSAndroid Build Coastguard Worker 				      lws_get_library_version(),
149*1c60b9acSAndroid Build Coastguard Worker 				      pss->wss_over_h2,
150*1c60b9acSAndroid Build Coastguard Worker 				      lws_canonical_hostname(vhd->context),
151*1c60b9acSAndroid Build Coastguard Worker 				      vhd->count_live_pss);
152*1c60b9acSAndroid Build Coastguard Worker 			pss->walk = WALK_LIST;
153*1c60b9acSAndroid Build Coastguard Worker 			pss->walk_next = vhd->live_pss_list;
154*1c60b9acSAndroid Build Coastguard Worker 			break;
155*1c60b9acSAndroid Build Coastguard Worker 		case WALK_LIST:
156*1c60b9acSAndroid Build Coastguard Worker 			n = LWS_WRITE_CONTINUATION | LWS_WRITE_NO_FIN;
157*1c60b9acSAndroid Build Coastguard Worker 			if (!pss->walk_next)
158*1c60b9acSAndroid Build Coastguard Worker 				goto walk_final;
159*1c60b9acSAndroid Build Coastguard Worker 
160*1c60b9acSAndroid Build Coastguard Worker 			if (pss->subsequent)
161*1c60b9acSAndroid Build Coastguard Worker 				*p++ = ',';
162*1c60b9acSAndroid Build Coastguard Worker 			pss->subsequent = 1;
163*1c60b9acSAndroid Build Coastguard Worker 
164*1c60b9acSAndroid Build Coastguard Worker 			m = 0;
165*1c60b9acSAndroid Build Coastguard Worker 			lws_start_foreach_ll(struct per_session_data__lws_status *,
166*1c60b9acSAndroid Build Coastguard Worker 					     pss2, vhd->live_pss_list) {
167*1c60b9acSAndroid Build Coastguard Worker 				if (pss2 == pss->walk_next) {
168*1c60b9acSAndroid Build Coastguard Worker 					m = 1;
169*1c60b9acSAndroid Build Coastguard Worker 					break;
170*1c60b9acSAndroid Build Coastguard Worker 				}
171*1c60b9acSAndroid Build Coastguard Worker 			} lws_end_foreach_ll(pss2, next);
172*1c60b9acSAndroid Build Coastguard Worker 
173*1c60b9acSAndroid Build Coastguard Worker 			if (!m) {
174*1c60b9acSAndroid Build Coastguard Worker 				/* our next guy went away */
175*1c60b9acSAndroid Build Coastguard Worker 				pss->walk = WALK_FINAL;
176*1c60b9acSAndroid Build Coastguard Worker 				pss->changed_partway = 1;
177*1c60b9acSAndroid Build Coastguard Worker 				break;
178*1c60b9acSAndroid Build Coastguard Worker 			}
179*1c60b9acSAndroid Build Coastguard Worker 
180*1c60b9acSAndroid Build Coastguard Worker 			strcpy(ip, "unknown");
181*1c60b9acSAndroid Build Coastguard Worker 			lws_get_peer_simple(pss->walk_next->wsi, ip, sizeof(ip));
182*1c60b9acSAndroid Build Coastguard Worker 			p += lws_snprintf(p, lws_ptr_diff_size_t(end, p),
183*1c60b9acSAndroid Build Coastguard Worker 					"{\"peer\":\"%s\",\"time\":\"%ld\","
184*1c60b9acSAndroid Build Coastguard Worker 					"\"ua\":\"%s\"}",
185*1c60b9acSAndroid Build Coastguard Worker 					ip, (unsigned long)pss->walk_next->time_est,
186*1c60b9acSAndroid Build Coastguard Worker 					pss->walk_next->user_agent);
187*1c60b9acSAndroid Build Coastguard Worker 			pss->walk_next = pss->walk_next->next;
188*1c60b9acSAndroid Build Coastguard Worker 			if (!pss->walk_next)
189*1c60b9acSAndroid Build Coastguard Worker 				pss->walk = WALK_FINAL;
190*1c60b9acSAndroid Build Coastguard Worker 			break;
191*1c60b9acSAndroid Build Coastguard Worker 		case WALK_FINAL:
192*1c60b9acSAndroid Build Coastguard Worker walk_final:
193*1c60b9acSAndroid Build Coastguard Worker 			n = LWS_WRITE_CONTINUATION;
194*1c60b9acSAndroid Build Coastguard Worker 			p += lws_snprintf(p, 4, "]}");
195*1c60b9acSAndroid Build Coastguard Worker 			if (pss->changed_partway) {
196*1c60b9acSAndroid Build Coastguard Worker 				pss->changed_partway = 0;
197*1c60b9acSAndroid Build Coastguard Worker 				pss->subsequent = 0;
198*1c60b9acSAndroid Build Coastguard Worker 				pss->walk_next = vhd->live_pss_list;
199*1c60b9acSAndroid Build Coastguard Worker 				pss->walk = WALK_INITIAL;
200*1c60b9acSAndroid Build Coastguard Worker 			} else
201*1c60b9acSAndroid Build Coastguard Worker 				pss->walk = WALK_NONE;
202*1c60b9acSAndroid Build Coastguard Worker 			break;
203*1c60b9acSAndroid Build Coastguard Worker 		default:
204*1c60b9acSAndroid Build Coastguard Worker 			return 0;
205*1c60b9acSAndroid Build Coastguard Worker 		}
206*1c60b9acSAndroid Build Coastguard Worker 
207*1c60b9acSAndroid Build Coastguard Worker 		m = lws_write(wsi, (unsigned char *)start, lws_ptr_diff_size_t(p, start), (unsigned int)n);
208*1c60b9acSAndroid Build Coastguard Worker 		if (m < 0) {
209*1c60b9acSAndroid Build Coastguard Worker 			lwsl_err("ERROR %d writing to di socket\n", m);
210*1c60b9acSAndroid Build Coastguard Worker 			return -1;
211*1c60b9acSAndroid Build Coastguard Worker 		}
212*1c60b9acSAndroid Build Coastguard Worker 
213*1c60b9acSAndroid Build Coastguard Worker 		if (pss->walk != WALK_NONE)
214*1c60b9acSAndroid Build Coastguard Worker 			lws_callback_on_writable(wsi);
215*1c60b9acSAndroid Build Coastguard Worker 		break;
216*1c60b9acSAndroid Build Coastguard Worker 
217*1c60b9acSAndroid Build Coastguard Worker 	case LWS_CALLBACK_RECEIVE:
218*1c60b9acSAndroid Build Coastguard Worker 		lwsl_notice("pmd test: RX len %d\n", (int)len);
219*1c60b9acSAndroid Build Coastguard Worker 		break;
220*1c60b9acSAndroid Build Coastguard Worker 
221*1c60b9acSAndroid Build Coastguard Worker 	case LWS_CALLBACK_CLOSED:
222*1c60b9acSAndroid Build Coastguard Worker 		// lwsl_debug("****** LWS_CALLBACK_CLOSED\n");
223*1c60b9acSAndroid Build Coastguard Worker 		lws_start_foreach_llp(struct per_session_data__lws_status **,
224*1c60b9acSAndroid Build Coastguard Worker 			ppss, vhd->live_pss_list) {
225*1c60b9acSAndroid Build Coastguard Worker 			if (*ppss == pss) {
226*1c60b9acSAndroid Build Coastguard Worker 				*ppss = pss->next;
227*1c60b9acSAndroid Build Coastguard Worker 				break;
228*1c60b9acSAndroid Build Coastguard Worker 			}
229*1c60b9acSAndroid Build Coastguard Worker 		} lws_end_foreach_llp(ppss, next);
230*1c60b9acSAndroid Build Coastguard Worker 
231*1c60b9acSAndroid Build Coastguard Worker 		trigger_resend(vhd);
232*1c60b9acSAndroid Build Coastguard Worker 		break;
233*1c60b9acSAndroid Build Coastguard Worker 
234*1c60b9acSAndroid Build Coastguard Worker 	default:
235*1c60b9acSAndroid Build Coastguard Worker 		break;
236*1c60b9acSAndroid Build Coastguard Worker 	}
237*1c60b9acSAndroid Build Coastguard Worker 
238*1c60b9acSAndroid Build Coastguard Worker 	return 0;
239*1c60b9acSAndroid Build Coastguard Worker }
240*1c60b9acSAndroid Build Coastguard Worker 
241*1c60b9acSAndroid Build Coastguard Worker #define LWS_PLUGIN_PROTOCOL_LWS_STATUS \
242*1c60b9acSAndroid Build Coastguard Worker 	{ \
243*1c60b9acSAndroid Build Coastguard Worker 		"lws-status", \
244*1c60b9acSAndroid Build Coastguard Worker 		callback_lws_status, \
245*1c60b9acSAndroid Build Coastguard Worker 		sizeof(struct per_session_data__lws_status), \
246*1c60b9acSAndroid Build Coastguard Worker 		512, /* rx buf size must be >= permessage-deflate rx size */ \
247*1c60b9acSAndroid Build Coastguard Worker 		0, NULL, 0 \
248*1c60b9acSAndroid Build Coastguard Worker 	}
249*1c60b9acSAndroid Build Coastguard Worker 
250*1c60b9acSAndroid Build Coastguard Worker #if !defined (LWS_PLUGIN_STATIC)
251*1c60b9acSAndroid Build Coastguard Worker 
252*1c60b9acSAndroid Build Coastguard Worker LWS_VISIBLE const struct lws_protocols lws_status_protocols[] = {
253*1c60b9acSAndroid Build Coastguard Worker 	LWS_PLUGIN_PROTOCOL_LWS_STATUS
254*1c60b9acSAndroid Build Coastguard Worker };
255*1c60b9acSAndroid Build Coastguard Worker 
256*1c60b9acSAndroid Build Coastguard Worker LWS_VISIBLE const lws_plugin_protocol_t lws_status = {
257*1c60b9acSAndroid Build Coastguard Worker 	.hdr = {
258*1c60b9acSAndroid Build Coastguard Worker 		"lws status",
259*1c60b9acSAndroid Build Coastguard Worker 		"lws_protocol_plugin",
260*1c60b9acSAndroid Build Coastguard Worker 		LWS_BUILD_HASH,
261*1c60b9acSAndroid Build Coastguard Worker 		LWS_PLUGIN_API_MAGIC
262*1c60b9acSAndroid Build Coastguard Worker 	},
263*1c60b9acSAndroid Build Coastguard Worker 
264*1c60b9acSAndroid Build Coastguard Worker 	.protocols = lws_status_protocols,
265*1c60b9acSAndroid Build Coastguard Worker 	.count_protocols = LWS_ARRAY_SIZE(lws_status_protocols),
266*1c60b9acSAndroid Build Coastguard Worker 	.extensions = NULL,
267*1c60b9acSAndroid Build Coastguard Worker 	.count_extensions = 0,
268*1c60b9acSAndroid Build Coastguard Worker };
269*1c60b9acSAndroid Build Coastguard Worker 
270*1c60b9acSAndroid Build Coastguard Worker #endif
271