Fix to expose openssl dependency
[platform/upstream/libwebsockets.git] / plugins / protocol_esp32_lws_group.c
1 /*
2  * ESP32 Group protocol handler
3  *
4  * Copyright (C) 2017 Andy Green <andy@warmcat.com>
5  *
6  *  This library is free software; you can redistribute it and/or
7  *  modify it under the terms of the GNU Lesser General Public
8  *  License as published by the Free Software Foundation:
9  *  version 2.1 of the License.
10  *
11  *  This library is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  *  Lesser General Public License for more details.
15  *
16  *  You should have received a copy of the GNU Lesser General Public
17  *  License along with this library; if not, write to the Free Software
18  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19  *  MA  02110-1301  USA*
20  *
21  */
22 #include <string.h>
23 #include <nvs.h>
24 #include <esp_ota_ops.h>
25
26 typedef enum {
27         GROUP_STATE_NONE,
28         GROUP_STATE_INITIAL,
29         GROUP_STATE_MEMBERS,
30         GROUP_STATE_FINAL
31 } group_state;
32
33 struct per_session_data__lws_group {
34         struct per_session_data__lws_group *next;
35         group_state group_state;
36
37         struct lws_group_member *member;
38
39         unsigned char subsequent:1;
40         unsigned char changed_partway:1;
41 };
42
43 struct per_vhost_data__lws_group {
44         struct per_session_data__lws_group *live_pss_list;
45         struct lws_context *context;
46         struct lws_vhost *vhost;
47         const struct lws_protocols *protocol;
48         int count_live_pss;
49 };
50
51 static void render_ip4(char *dest, int len, uint8_t *ip)
52 {
53         snprintf(dest, len, "%u.%u.%u.%u", ip[0], ip[1], ip[2], ip[3]);
54 }
55
56
57
58 static int
59 callback_lws_group(struct lws *wsi, enum lws_callback_reasons reason,
60                    void *user, void *in, size_t len)
61 {
62         struct per_session_data__lws_group *pss =
63                         (struct per_session_data__lws_group *)user;
64         struct per_vhost_data__lws_group *vhd =
65                         (struct per_vhost_data__lws_group *)
66                         lws_protocol_vh_priv_get(lws_get_vhost(wsi),
67                                         lws_get_protocol(wsi));
68         char buffer[1024 + LWS_PRE], ipv4[20];
69         char *start = buffer + LWS_PRE - 1, *p = start,
70                       *end = buffer + sizeof(buffer) - 1;
71         struct lws_group_member *mbr;
72         int n, m;
73
74         switch (reason) {
75
76         case LWS_CALLBACK_PROTOCOL_INIT:
77                 vhd = lws_protocol_vh_priv_zalloc(lws_get_vhost(wsi),
78                                 lws_get_protocol(wsi),
79                                 sizeof(struct per_vhost_data__lws_group));
80                 vhd->context = lws_get_context(wsi);
81                 vhd->protocol = lws_get_protocol(wsi);
82                 vhd->vhost = lws_get_vhost(wsi);
83                 break;
84
85         case LWS_CALLBACK_PROTOCOL_DESTROY:
86                 if (!vhd)
87                         break;
88                 break;
89
90         case LWS_CALLBACK_ESTABLISHED:
91                 lwsl_notice("%s: ESTABLISHED\n", __func__);
92                 vhd->count_live_pss++;
93                 pss->next = vhd->live_pss_list;
94                 vhd->live_pss_list = pss;
95                 pss->group_state = GROUP_STATE_INITIAL;
96                 lws_callback_on_writable(wsi);
97                 break;
98
99         case LWS_CALLBACK_SERVER_WRITEABLE:
100
101                 switch (pss->group_state) {
102
103                 case GROUP_STATE_NONE:
104                         /* fallthru */
105
106                 case GROUP_STATE_INITIAL:
107
108                         p += snprintf((char *)p, end - p,
109                                       "{\n"
110                                       " \"group\":\"%s\","
111                                       " \"members\":[\n",
112                                       lws_esp32.group);
113
114                         n = LWS_WRITE_TEXT | LWS_WRITE_NO_FIN;
115                         pss->group_state = GROUP_STATE_MEMBERS;
116                         pss->subsequent = 0;
117                         pss->changed_partway = 0;
118                         pss->member = lws_esp32.first;
119                         break;
120
121                 case GROUP_STATE_MEMBERS:
122
123                         /* confirm pss->member is still in the list... */
124
125                         mbr = lws_esp32.first;
126                         while (mbr && mbr != pss->member)
127                                 mbr = mbr->next;
128
129                         if (!mbr) { /* no longer exists... */
130                                 if (lws_esp32.first || pss->member)
131                                         pss->changed_partway = 1;
132                                 *p++ = ' ';
133                                 pss->member = NULL;
134
135                                 /*
136                                  * finish the list where we got to, then
137                                  * immediately reissue it
138                                  */
139                         }
140                         
141                         while (end - p > 100 && pss->member) {
142
143                                 if (pss->subsequent)
144                                         *p++ = ',';
145
146                                 pss->subsequent = 1;
147                                 render_ip4(ipv4, sizeof(ipv4), (uint8_t *)&pss->member->addr);
148
149                                 p += snprintf((char *)p, end - p,
150                                               " {\n"
151                                               "  \"mac\":\"%s\",\n"
152                                               "  \"model\":\"%s\",\n"
153                                               "  \"role\":\"%s\",\n"
154                                               "  \"width\":\"%d\",\n"
155                                               "  \"height\":\"%d\",\n"
156                                               "  \"ipv4\":\"%s\"\n"
157                                               " }\n",
158                                                 pss->member->mac,
159                                                 pss->member->model,
160                                                 pss->member->role,
161                                                 pss->member->width,
162                                                 pss->member->height,
163                                                 ipv4
164                                               );
165                                 pss->member = pss->member->next;
166                         }
167
168                         lwsl_notice("%s\n", p);
169
170                         n = LWS_WRITE_CONTINUATION | LWS_WRITE_NO_FIN;
171                         if (!pss->member)
172                                 pss->group_state = GROUP_STATE_FINAL;
173                         break;
174
175                 case GROUP_STATE_FINAL:
176                         n = LWS_WRITE_CONTINUATION;
177                         p += sprintf((char *)p, "],\n \"discard\":\"%d\"}\n",
178                                         pss->changed_partway);
179                         if (pss->changed_partway)
180                                 pss->group_state = GROUP_STATE_INITIAL;
181                         else
182                                 pss->group_state = GROUP_STATE_NONE;
183                         break;
184                 default:
185                         return 0;
186                 }
187 //              lwsl_notice("issue: %d (%d)\n", p - start, n);
188                 m = lws_write(wsi, (unsigned char *)start, p - start, n);
189                 if (m < 0) {
190                         lwsl_err("ERROR %d writing to di socket\n", m);
191                         return -1;
192                 }
193
194                 if (pss->group_state != GROUP_STATE_NONE)
195                         lws_callback_on_writable(wsi);
196
197                 break;
198
199         case LWS_CALLBACK_RECEIVE:
200                 {
201                         break;
202                 }
203
204         case LWS_CALLBACK_CLOSED:
205                 {
206                         struct per_session_data__lws_group **p = &vhd->live_pss_list;
207
208                         while (*p) {
209                                 if ((*p) == pss) {
210                                         *p = pss->next;
211                                         continue;
212                                 }
213
214                                 p = &((*p)->next);
215                         }
216
217                         vhd->count_live_pss--;
218                 }
219                 break;
220
221         case LWS_CALLBACK_HTTP_DROP_PROTOCOL:
222                 /* called when our wsi user_space is going to be destroyed */
223                 break;
224
225         default:
226                 break;
227         }
228
229         return 0;
230 }
231
232 #define LWS_PLUGIN_PROTOCOL_LWS_GROUP \
233         { \
234                 "lws-group", \
235                 callback_lws_group, \
236                 sizeof(struct per_session_data__lws_group), \
237                 1024, 0, NULL, 900 \
238         }
239