1d4afb5ceSopenharmony_ci/*
2d4afb5ceSopenharmony_ci * ws protocol handler plugin for "lws-minimal"
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 version holds a single message at a time, which may be lost if a new
10d4afb5ceSopenharmony_ci * message comes.  See the minimal-ws-server-ring sample for the same thing
11d4afb5ceSopenharmony_ci * but using an lws_ring ringbuffer to hold up to 8 messages at a time.
12d4afb5ceSopenharmony_ci */
13d4afb5ceSopenharmony_ci
14d4afb5ceSopenharmony_ci#if !defined (LWS_PLUGIN_STATIC)
15d4afb5ceSopenharmony_ci#define LWS_DLL
16d4afb5ceSopenharmony_ci#define LWS_INTERNAL
17d4afb5ceSopenharmony_ci#include <libwebsockets.h>
18d4afb5ceSopenharmony_ci#endif
19d4afb5ceSopenharmony_ci
20d4afb5ceSopenharmony_ci#include <string.h>
21d4afb5ceSopenharmony_ci
22d4afb5ceSopenharmony_ci/* one of these created for each message */
23d4afb5ceSopenharmony_ci
24d4afb5ceSopenharmony_cistruct msg {
25d4afb5ceSopenharmony_ci	void *payload; /* is malloc'd */
26d4afb5ceSopenharmony_ci	size_t len;
27d4afb5ceSopenharmony_ci};
28d4afb5ceSopenharmony_ci
29d4afb5ceSopenharmony_ci/* one of these is created for each client connecting to us */
30d4afb5ceSopenharmony_ci
31d4afb5ceSopenharmony_cistruct per_session_data__minimal {
32d4afb5ceSopenharmony_ci	struct per_session_data__minimal *pss_list;
33d4afb5ceSopenharmony_ci	struct lws *wsi;
34d4afb5ceSopenharmony_ci	int last; /* the last message number we sent */
35d4afb5ceSopenharmony_ci};
36d4afb5ceSopenharmony_ci
37d4afb5ceSopenharmony_ci/* one of these is created for each vhost our protocol is used with */
38d4afb5ceSopenharmony_ci
39d4afb5ceSopenharmony_cistruct per_vhost_data__minimal {
40d4afb5ceSopenharmony_ci	struct lws_context *context;
41d4afb5ceSopenharmony_ci	struct lws_vhost *vhost;
42d4afb5ceSopenharmony_ci	const struct lws_protocols *protocol;
43d4afb5ceSopenharmony_ci
44d4afb5ceSopenharmony_ci	struct per_session_data__minimal *pss_list; /* linked-list of live pss*/
45d4afb5ceSopenharmony_ci
46d4afb5ceSopenharmony_ci	struct msg amsg; /* the one pending message... */
47d4afb5ceSopenharmony_ci	int current; /* the current message number we are caching */
48d4afb5ceSopenharmony_ci};
49d4afb5ceSopenharmony_ci
50d4afb5ceSopenharmony_ci/* destroys the message when everyone has had a copy of it */
51d4afb5ceSopenharmony_ci
52d4afb5ceSopenharmony_cistatic void
53d4afb5ceSopenharmony_ci__minimal_destroy_message(void *_msg)
54d4afb5ceSopenharmony_ci{
55d4afb5ceSopenharmony_ci	struct msg *msg = _msg;
56d4afb5ceSopenharmony_ci
57d4afb5ceSopenharmony_ci	free(msg->payload);
58d4afb5ceSopenharmony_ci	msg->payload = NULL;
59d4afb5ceSopenharmony_ci	msg->len = 0;
60d4afb5ceSopenharmony_ci}
61d4afb5ceSopenharmony_ci
62d4afb5ceSopenharmony_cistatic int
63d4afb5ceSopenharmony_cicallback_minimal(struct lws *wsi, enum lws_callback_reasons reason,
64d4afb5ceSopenharmony_ci			void *user, void *in, size_t len)
65d4afb5ceSopenharmony_ci{
66d4afb5ceSopenharmony_ci	struct per_session_data__minimal *pss =
67d4afb5ceSopenharmony_ci			(struct per_session_data__minimal *)user;
68d4afb5ceSopenharmony_ci	struct per_vhost_data__minimal *vhd =
69d4afb5ceSopenharmony_ci			(struct per_vhost_data__minimal *)
70d4afb5ceSopenharmony_ci			lws_protocol_vh_priv_get(lws_get_vhost(wsi),
71d4afb5ceSopenharmony_ci					lws_get_protocol(wsi));
72d4afb5ceSopenharmony_ci	int m;
73d4afb5ceSopenharmony_ci
74d4afb5ceSopenharmony_ci	switch (reason) {
75d4afb5ceSopenharmony_ci	case LWS_CALLBACK_PROTOCOL_INIT:
76d4afb5ceSopenharmony_ci		vhd = lws_protocol_vh_priv_zalloc(lws_get_vhost(wsi),
77d4afb5ceSopenharmony_ci				lws_get_protocol(wsi),
78d4afb5ceSopenharmony_ci				sizeof(struct per_vhost_data__minimal));
79d4afb5ceSopenharmony_ci		vhd->context = lws_get_context(wsi);
80d4afb5ceSopenharmony_ci		vhd->protocol = lws_get_protocol(wsi);
81d4afb5ceSopenharmony_ci		vhd->vhost = lws_get_vhost(wsi);
82d4afb5ceSopenharmony_ci		break;
83d4afb5ceSopenharmony_ci
84d4afb5ceSopenharmony_ci	case LWS_CALLBACK_ESTABLISHED:
85d4afb5ceSopenharmony_ci		/* add ourselves to the list of live pss held in the vhd */
86d4afb5ceSopenharmony_ci		lws_ll_fwd_insert(pss, pss_list, vhd->pss_list);
87d4afb5ceSopenharmony_ci		pss->wsi = wsi;
88d4afb5ceSopenharmony_ci		pss->last = vhd->current;
89d4afb5ceSopenharmony_ci		break;
90d4afb5ceSopenharmony_ci
91d4afb5ceSopenharmony_ci	case LWS_CALLBACK_CLOSED:
92d4afb5ceSopenharmony_ci		/* remove our closing pss from the list of live pss */
93d4afb5ceSopenharmony_ci		lws_ll_fwd_remove(struct per_session_data__minimal, pss_list,
94d4afb5ceSopenharmony_ci				  pss, vhd->pss_list);
95d4afb5ceSopenharmony_ci		break;
96d4afb5ceSopenharmony_ci
97d4afb5ceSopenharmony_ci	case LWS_CALLBACK_SERVER_WRITEABLE:
98d4afb5ceSopenharmony_ci		if (!vhd->amsg.payload)
99d4afb5ceSopenharmony_ci			break;
100d4afb5ceSopenharmony_ci
101d4afb5ceSopenharmony_ci		if (pss->last == vhd->current)
102d4afb5ceSopenharmony_ci			break;
103d4afb5ceSopenharmony_ci
104d4afb5ceSopenharmony_ci		/* notice we allowed for LWS_PRE in the payload already */
105d4afb5ceSopenharmony_ci		m = lws_write(wsi, ((unsigned char *)vhd->amsg.payload) +
106d4afb5ceSopenharmony_ci			      LWS_PRE, vhd->amsg.len, LWS_WRITE_TEXT);
107d4afb5ceSopenharmony_ci		if (m < (int)vhd->amsg.len) {
108d4afb5ceSopenharmony_ci			lwsl_err("ERROR %d writing to ws\n", m);
109d4afb5ceSopenharmony_ci			return -1;
110d4afb5ceSopenharmony_ci		}
111d4afb5ceSopenharmony_ci
112d4afb5ceSopenharmony_ci		pss->last = vhd->current;
113d4afb5ceSopenharmony_ci		break;
114d4afb5ceSopenharmony_ci
115d4afb5ceSopenharmony_ci	case LWS_CALLBACK_RECEIVE:
116d4afb5ceSopenharmony_ci		if (vhd->amsg.payload)
117d4afb5ceSopenharmony_ci			__minimal_destroy_message(&vhd->amsg);
118d4afb5ceSopenharmony_ci
119d4afb5ceSopenharmony_ci		vhd->amsg.len = len;
120d4afb5ceSopenharmony_ci		/* notice we over-allocate by LWS_PRE */
121d4afb5ceSopenharmony_ci		vhd->amsg.payload = malloc(LWS_PRE + len);
122d4afb5ceSopenharmony_ci		if (!vhd->amsg.payload) {
123d4afb5ceSopenharmony_ci			lwsl_user("OOM: dropping\n");
124d4afb5ceSopenharmony_ci			break;
125d4afb5ceSopenharmony_ci		}
126d4afb5ceSopenharmony_ci
127d4afb5ceSopenharmony_ci		memcpy((char *)vhd->amsg.payload + LWS_PRE, in, len);
128d4afb5ceSopenharmony_ci		vhd->current++;
129d4afb5ceSopenharmony_ci
130d4afb5ceSopenharmony_ci		/*
131d4afb5ceSopenharmony_ci		 * let everybody know we want to write something on them
132d4afb5ceSopenharmony_ci		 * as soon as they are ready
133d4afb5ceSopenharmony_ci		 */
134d4afb5ceSopenharmony_ci		lws_start_foreach_llp(struct per_session_data__minimal **,
135d4afb5ceSopenharmony_ci				      ppss, vhd->pss_list) {
136d4afb5ceSopenharmony_ci			lws_callback_on_writable((*ppss)->wsi);
137d4afb5ceSopenharmony_ci		} lws_end_foreach_llp(ppss, pss_list);
138d4afb5ceSopenharmony_ci		break;
139d4afb5ceSopenharmony_ci
140d4afb5ceSopenharmony_ci	default:
141d4afb5ceSopenharmony_ci		break;
142d4afb5ceSopenharmony_ci	}
143d4afb5ceSopenharmony_ci
144d4afb5ceSopenharmony_ci	return 0;
145d4afb5ceSopenharmony_ci}
146d4afb5ceSopenharmony_ci
147d4afb5ceSopenharmony_ci#define LWS_PLUGIN_PROTOCOL_MINIMAL \
148d4afb5ceSopenharmony_ci	{ \
149d4afb5ceSopenharmony_ci		"lws-minimal", \
150d4afb5ceSopenharmony_ci		callback_minimal, \
151d4afb5ceSopenharmony_ci		sizeof(struct per_session_data__minimal), \
152d4afb5ceSopenharmony_ci		128, \
153d4afb5ceSopenharmony_ci		0, NULL, 0 \
154d4afb5ceSopenharmony_ci	}
155