Imported Upstream version 3.2
[platform/upstream/libwebsockets.git] / lib / abstract / transports / raw-skt.c
1 /*
2  * libwebsockets lib/abstract/transports/raw-skt.c
3  *
4  * Copyright (C) 2019 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 "core/private.h"
23 #include "abstract/private.h"
24
25 typedef struct lws_abstxp_raw_skt_priv {
26         struct lws_abs *abs;
27         struct lws *wsi;
28
29         lws_dll2_t same_abs_transport_list;
30
31         uint8_t established:1;
32         uint8_t connecting:1;
33 } abs_raw_skt_priv_t;
34
35 struct vhd {
36         lws_dll2_owner_t owner;
37 };
38
39 static int
40 heartbeat_cb(struct lws_dll2 *d, void *user)
41 {
42         abs_raw_skt_priv_t *priv = lws_container_of(d, abs_raw_skt_priv_t,
43                                                     same_abs_transport_list);
44
45         if (priv->abs->ap->heartbeat)
46                 priv->abs->ap->heartbeat(priv->abs->api);
47
48         return 0;
49 }
50
51 static int
52 callback_abs_client_raw_skt(struct lws *wsi, enum lws_callback_reasons reason,
53                             void *user, void *in, size_t len)
54 {
55         abs_raw_skt_priv_t *priv = (abs_raw_skt_priv_t *)user;
56         struct vhd *vhd = (struct vhd *)
57                 lws_protocol_vh_priv_get(lws_get_vhost(wsi),
58                                          lws_get_protocol(wsi));
59
60         switch (reason) {
61         case LWS_CALLBACK_PROTOCOL_INIT:
62                 vhd = lws_protocol_vh_priv_zalloc(lws_get_vhost(wsi),
63                                 lws_get_protocol(wsi), sizeof(struct vhd));
64                 if (!vhd)
65                         return 1;
66                 lws_timed_callback_vh_protocol(lws_get_vhost(wsi),
67                                                lws_get_protocol(wsi),
68                                                LWS_CALLBACK_USER, 1);
69                 break;
70
71         case LWS_CALLBACK_USER:
72                 /*
73                  * This comes at 1Hz without a wsi context, so there is no
74                  * valid priv.  We need to track the live abstract objects that
75                  * are using our abstract protocol, and pass the heartbeat
76                  * through to the ones that care.
77                  */
78                 if (!vhd)
79                         break;
80
81                 lws_dll2_foreach_safe(&vhd->owner, NULL, heartbeat_cb);
82
83                 lws_timed_callback_vh_protocol(lws_get_vhost(wsi),
84                                                lws_get_protocol(wsi),
85                                                LWS_CALLBACK_USER, 1);
86                 break;
87
88         case LWS_CALLBACK_RAW_CONNECTED:
89                 lwsl_debug("LWS_CALLBACK_RAW_CONNECTED\n");
90                 priv->connecting = 0;
91                 priv->established = 1;
92                 if (priv->abs->ap->accept)
93                         priv->abs->ap->accept(priv->abs->api);
94                 if (wsi->seq)
95                         /*
96                          * we are bound to a sequencer who wants to know about
97                          * our lifecycle events
98                          */
99
100                         lws_seq_queue_event(wsi->seq, LWSSEQ_WSI_CONNECTED,
101                                                   wsi, NULL);
102                 break;
103
104         case LWS_CALLBACK_CLIENT_CONNECTION_ERROR:
105                 lwsl_user("CONNECTION_ERROR\n");
106                 if (in)
107                         lwsl_user("   %s\n", (const char *)in);
108
109                 if (wsi->seq)
110                         /*
111                          * we are bound to a sequencer who wants to know about
112                          * our lifecycle events
113                          */
114
115                         lws_seq_queue_event(wsi->seq, LWSSEQ_WSI_CONN_FAIL,
116                                             wsi, NULL);
117
118                 goto close_path;
119
120                 /* fallthru */
121         case LWS_CALLBACK_RAW_CLOSE:
122                 if (!user)
123                         break;
124
125                 if (wsi->seq)
126                         /*
127                          * we are bound to a sequencer who wants to know about
128                          * our lifecycle events
129                          */
130
131                         lws_seq_queue_event(wsi->seq, LWSSEQ_WSI_CONN_CLOSE,
132                                             wsi, NULL);
133
134 close_path:
135                 lwsl_debug("LWS_CALLBACK_RAW_CLOSE\n");
136                 priv->established = 0;
137                 priv->connecting = 0;
138                 if (priv->abs && priv->abs->ap->closed)
139                         priv->abs->ap->closed(priv->abs->api);
140                 lws_set_wsi_user(wsi, NULL);
141                 break;
142
143         case LWS_CALLBACK_RAW_RX:
144                 lwsl_debug("LWS_CALLBACK_RAW_RX (%d)\n", (int)len);
145                 return !!priv->abs->ap->rx(priv->abs->api, in, len);
146
147         case LWS_CALLBACK_RAW_WRITEABLE:
148                 lwsl_debug("LWS_CALLBACK_RAW_WRITEABLE\n");
149                 priv->abs->ap->writeable(priv->abs->api,
150                                 lws_get_peer_write_allowance(priv->wsi));
151                 break;
152
153         case LWS_CALLBACK_RAW_SKT_BIND_PROTOCOL:
154                 lws_dll2_add_tail(&priv->same_abs_transport_list, &vhd->owner);
155                 break;
156
157         case LWS_CALLBACK_RAW_SKT_DROP_PROTOCOL:
158                 lws_dll2_remove(&priv->same_abs_transport_list);
159                 break;
160
161         default:
162                 break;
163         }
164
165         return 0;
166 }
167
168 static int
169 lws_atcrs_close(lws_abs_transport_inst_t *ati)
170 {
171         abs_raw_skt_priv_t *priv = (abs_raw_skt_priv_t *)ati;
172         struct lws *wsi = priv->wsi;
173
174         if (!priv->wsi)
175                 return 0;
176
177         if (!lws_raw_transaction_completed(priv->wsi))
178                 return 0;
179
180         priv->wsi = NULL;
181         lws_set_timeout(wsi, 1, LWS_TO_KILL_SYNC);
182
183         /* priv is destroyed in the CLOSE callback */
184
185         return 0;
186 }
187
188
189 const struct lws_protocols protocol_abs_client_raw_skt = {
190         "lws-abs-cli-raw-skt", callback_abs_client_raw_skt,
191         0, 1024, 1024, NULL, 0
192 };
193
194 static int
195 lws_atcrs_tx(lws_abs_transport_inst_t *ati, uint8_t *buf, size_t len)
196 {
197         abs_raw_skt_priv_t *priv = (abs_raw_skt_priv_t *)ati;
198
199         if (!priv->wsi) {
200                 lwsl_err("%s: NULL priv->wsi\n", __func__);
201                 return 1;
202         }
203
204         lwsl_debug("%s: priv %p, wsi %p, ro %p\n", __func__,
205                         priv, priv->wsi, priv->wsi->role_ops);
206
207         if (lws_write(priv->wsi, buf, len, LWS_WRITE_RAW) < 0)
208                 lws_atcrs_close(ati);
209
210         return 0;
211 }
212
213 #if !defined(LWS_WITHOUT_CLIENT)
214 static int
215 lws_atcrs_client_conn(const lws_abs_t *abs)
216 {
217         abs_raw_skt_priv_t *priv = (abs_raw_skt_priv_t *)abs->ati;
218         struct lws_client_connect_info i;
219         const lws_token_map_t *tm;
220
221         if (priv->connecting)
222                 return 0;
223
224         if (priv->established) {
225                 lws_set_timeout(priv->wsi, PENDING_TIMEOUT_CLIENT_CONN_IDLE, 5);
226
227                 return 0;
228         }
229
230         memset(&i, 0, sizeof(i));
231
232         /* address and port are passed-in using the abstract transport tokens */
233
234         tm = lws_abs_get_token(abs->at_tokens, LTMI_PEER_V_DNS_ADDRESS);
235         if (!tm) {
236                 lwsl_notice("%s: raw_skt needs LTMI_PEER_V_DNS_ADDRESS\n",
237                             __func__);
238
239                 return 1;
240         }
241         i.address = tm->u.value;
242
243         tm = lws_abs_get_token(abs->at_tokens, LTMI_PEER_LV_PORT);
244         if (!tm) {
245                 lwsl_notice("%s: raw_skt needs LTMI_PEER_LV_PORT\n", __func__);
246
247                 return 1;
248         }
249         i.port = tm->u.lvalue;
250
251         /* optional */
252         i.ssl_connection = 0;
253         tm = lws_abs_get_token(abs->at_tokens, LTMI_PEER_LV_TLS_FLAGS);
254         if (tm)
255                 i.ssl_connection = tm->u.lvalue;
256
257
258         lwsl_debug("%s: raw_skt priv %p connecting to %s:%u %p\n",
259                    __func__, priv, i.address, i.port, abs->vh->context);
260
261         i.path = "";
262         i.method = "RAW";
263         i.vhost = abs->vh;
264         i.userdata = priv;
265         i.host = i.address;
266         i.pwsi = &priv->wsi;
267         i.origin = i.address;
268         i.context = abs->vh->context;
269         i.local_protocol_name = "lws-abs-cli-raw-skt";
270         i.seq = abs->seq;
271         i.opaque_user_data = abs->opaque_user_data;
272
273         priv->wsi = lws_client_connect_via_info(&i);
274         if (!priv->wsi)
275                 return 1;
276
277         priv->connecting = 1;
278
279         return 0;
280 }
281 #endif
282
283 static int
284 lws_atcrs_ask_for_writeable(lws_abs_transport_inst_t *ati)
285 {
286         abs_raw_skt_priv_t *priv = (abs_raw_skt_priv_t *)ati;
287
288         if (!priv->wsi || !priv->established)
289                 return 1;
290
291         lws_callback_on_writable(priv->wsi);
292
293         return 0;
294 }
295
296 static int
297 lws_atcrs_create(struct lws_abs *ai)
298 {
299         abs_raw_skt_priv_t *at = (abs_raw_skt_priv_t *)ai->ati;
300
301         memset(at, 0, sizeof(*at));
302         at->abs = ai;
303
304         return 0;
305 }
306
307 static void
308 lws_atcrs_destroy(lws_abs_transport_inst_t **pati)
309 {
310         /*
311          * We don't free anything because the abstract layer combined our
312          * allocation with that of the instance, and it will free the whole
313          * thing after this.
314          */
315         *pati = NULL;
316 }
317
318 static int
319 lws_atcrs_set_timeout(lws_abs_transport_inst_t *ati, int reason, int secs)
320 {
321         abs_raw_skt_priv_t *priv = (abs_raw_skt_priv_t *)ati;
322
323         lws_set_timeout(priv->wsi, reason, secs);
324
325         return 0;
326 }
327
328 static int
329 lws_atcrs_state(lws_abs_transport_inst_t *ati)
330 {
331         abs_raw_skt_priv_t *priv = (abs_raw_skt_priv_t *)ati;
332
333         if (!priv || !priv->wsi || (!priv->established && !priv->connecting))
334                 return 0;
335
336         return 1;
337 }
338
339 const lws_abs_transport_t lws_abs_transport_cli_raw_skt = {
340         .name                   = "raw_skt",
341         .alloc                  = sizeof(abs_raw_skt_priv_t),
342
343         .create                 = lws_atcrs_create,
344         .destroy                = lws_atcrs_destroy,
345
346         .tx                     = lws_atcrs_tx,
347 #if defined(LWS_WITHOUT_CLIENT)
348         .client_conn            = NULL,
349 #else
350         .client_conn            = lws_atcrs_client_conn,
351 #endif
352         .close                  = lws_atcrs_close,
353         .ask_for_writeable      = lws_atcrs_ask_for_writeable,
354         .set_timeout            = lws_atcrs_set_timeout,
355         .state                  = lws_atcrs_state,
356 };