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		pss->pss_list = vhd->pss_list;
87d4afb5ceSopenharmony_ci		vhd->pss_list = pss;
88d4afb5ceSopenharmony_ci		pss->wsi = wsi;
89d4afb5ceSopenharmony_ci		pss->last = vhd->current;
90d4afb5ceSopenharmony_ci		break;
91d4afb5ceSopenharmony_ci
92d4afb5ceSopenharmony_ci	case LWS_CALLBACK_CLOSED:
93d4afb5ceSopenharmony_ci		/* remove our closing pss from the list of live pss */
94d4afb5ceSopenharmony_ci		lws_start_foreach_llp(struct per_session_data__minimal **,
95d4afb5ceSopenharmony_ci				      ppss, vhd->pss_list) {
96d4afb5ceSopenharmony_ci			if (*ppss == pss) {
97d4afb5ceSopenharmony_ci				*ppss = pss->pss_list;
98d4afb5ceSopenharmony_ci				break;
99d4afb5ceSopenharmony_ci			}
100d4afb5ceSopenharmony_ci		} lws_end_foreach_llp(ppss, pss_list);
101d4afb5ceSopenharmony_ci		break;
102d4afb5ceSopenharmony_ci
103d4afb5ceSopenharmony_ci	case LWS_CALLBACK_SERVER_WRITEABLE:
104d4afb5ceSopenharmony_ci		if (!vhd->amsg.payload)
105d4afb5ceSopenharmony_ci			break;
106d4afb5ceSopenharmony_ci
107d4afb5ceSopenharmony_ci		if (pss->last == vhd->current)
108d4afb5ceSopenharmony_ci			break;
109d4afb5ceSopenharmony_ci
110d4afb5ceSopenharmony_ci		/* notice we allowed for LWS_PRE in the payload already */
111d4afb5ceSopenharmony_ci		m = lws_write(wsi, ((unsigned char *)vhd->amsg.payload) +
112d4afb5ceSopenharmony_ci			      LWS_PRE, vhd->amsg.len, LWS_WRITE_TEXT);
113d4afb5ceSopenharmony_ci		if (m < (int)vhd->amsg.len) {
114d4afb5ceSopenharmony_ci			lwsl_err("ERROR %d writing to ws socket\n", m);
115d4afb5ceSopenharmony_ci			return -1;
116d4afb5ceSopenharmony_ci		}
117d4afb5ceSopenharmony_ci
118d4afb5ceSopenharmony_ci		pss->last = vhd->current;
119d4afb5ceSopenharmony_ci		break;
120d4afb5ceSopenharmony_ci
121d4afb5ceSopenharmony_ci	case LWS_CALLBACK_RECEIVE:
122d4afb5ceSopenharmony_ci		if (vhd->amsg.payload)
123d4afb5ceSopenharmony_ci			__minimal_destroy_message(&vhd->amsg);
124d4afb5ceSopenharmony_ci
125d4afb5ceSopenharmony_ci		vhd->amsg.len = len;
126d4afb5ceSopenharmony_ci		/* notice we over-allocate by LWS_PRE */
127d4afb5ceSopenharmony_ci		vhd->amsg.payload = malloc(LWS_PRE + len);
128d4afb5ceSopenharmony_ci		if (!vhd->amsg.payload) {
129d4afb5ceSopenharmony_ci			lwsl_user("OOM: dropping\n");
130d4afb5ceSopenharmony_ci			break;
131d4afb5ceSopenharmony_ci		}
132d4afb5ceSopenharmony_ci
133d4afb5ceSopenharmony_ci		memcpy((char *)vhd->amsg.payload + LWS_PRE, in, len);
134d4afb5ceSopenharmony_ci		vhd->current++;
135d4afb5ceSopenharmony_ci
136d4afb5ceSopenharmony_ci		/*
137d4afb5ceSopenharmony_ci		 * let everybody know we want to write something on them
138d4afb5ceSopenharmony_ci		 * as soon as they are ready
139d4afb5ceSopenharmony_ci		 */
140d4afb5ceSopenharmony_ci		lws_start_foreach_llp(struct per_session_data__minimal **,
141d4afb5ceSopenharmony_ci				      ppss, vhd->pss_list) {
142d4afb5ceSopenharmony_ci			lws_callback_on_writable((*ppss)->wsi);
143d4afb5ceSopenharmony_ci		} lws_end_foreach_llp(ppss, pss_list);
144d4afb5ceSopenharmony_ci		break;
145d4afb5ceSopenharmony_ci
146d4afb5ceSopenharmony_ci	default:
147d4afb5ceSopenharmony_ci		break;
148d4afb5ceSopenharmony_ci	}
149d4afb5ceSopenharmony_ci
150d4afb5ceSopenharmony_ci	return 0;
151d4afb5ceSopenharmony_ci}
152d4afb5ceSopenharmony_ci
153d4afb5ceSopenharmony_ci#define LWS_PLUGIN_PROTOCOL_MINIMAL \
154d4afb5ceSopenharmony_ci	{ \
155d4afb5ceSopenharmony_ci		"lws-minimal", \
156d4afb5ceSopenharmony_ci		callback_minimal, \
157d4afb5ceSopenharmony_ci		sizeof(struct per_session_data__minimal), \
158d4afb5ceSopenharmony_ci		128, \
159d4afb5ceSopenharmony_ci		0, NULL, 0 \
160d4afb5ceSopenharmony_ci	}
161