Coverage Report

Created: 2026-08-08 06:05

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libwebsockets/lib/roles/ws/ops-ws.c
Line
Count
Source
1
/*
2
 * libwebsockets - small server side websockets and web server implementation
3
 *
4
 * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
5
 *
6
 * Permission is hereby granted, free of charge, to any person obtaining a copy
7
 * of this software and associated documentation files (the "Software"), to
8
 * deal in the Software without restriction, including without limitation the
9
 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10
 * sell copies of the Software, and to permit persons to whom the Software is
11
 * furnished to do so, subject to the following conditions:
12
 *
13
 * The above copyright notice and this permission notice shall be included in
14
 * all copies or substantial portions of the Software.
15
 *
16
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22
 * IN THE SOFTWARE.
23
 */
24
25
#include <private-lib-core.h>
26
27
#if defined(LWS_WITH_HTTP_PROXY)
28
static void
29
lws_ws_proxy_est_cb(lws_sorted_usec_list_t *sul)
30
{
31
  struct lws *wsi = lws_container_of(sul, struct lws, sul_ws_proxy_est);
32
33
  lwsi_set_state(wsi, LRS_ESTABLISHED);
34
35
  if (wsi->a.protocol->callback)
36
    if (wsi->a.protocol->callback(wsi, LWS_CALLBACK_ESTABLISHED,
37
              wsi->user_space,
38
#ifdef LWS_WITH_TLS
39
              wsi->tls.ssl,
40
#else
41
              NULL,
42
#endif
43
              wsi->h23_stream_carries_ws))
44
      lws_wsi_close(wsi, LWS_TO_KILL_ASYNC);
45
}
46
#endif
47
48
#define LWS_CPYAPP(ptr, str) { strcpy(ptr, str); ptr += strlen(str); }
49
50
/*
51
 * client-parser.c: lws_ws_client_rx_sm() needs to be roughly kept in
52
 *   sync with changes here, esp related to ext draining
53
 *
54
 * Notice this returns either LWS_HPI_RET_HANDLED or LWS_HPI_RET_PLEASE_CLOSE_ME
55
 */
56
57
lws_handling_result_t
58
lws_ws_rx_sm(struct lws *wsi, char already_processed, unsigned char c)
59
0
{
60
0
  lws_handling_result_t ret = LWS_HPI_RET_HANDLED;
61
0
  int callback_action = LWS_CALLBACK_RECEIVE;
62
0
  struct lws_ext_pm_deflate_rx_ebufs pmdrx;
63
0
  unsigned short close_code;
64
0
  unsigned char *pp;
65
0
  int n = 0;
66
#if !defined(LWS_WITHOUT_EXTENSIONS)
67
  int rx_draining_ext = 0;
68
  int lin;
69
#endif
70
71
0
  pmdrx.eb_in.token = NULL;
72
0
  pmdrx.eb_in.len = 0;
73
0
  pmdrx.eb_out.token = NULL;
74
0
  pmdrx.eb_out.len = 0;
75
76
0
  switch (wsi->lws_rx_parse_state) {
77
0
  case LWS_RXPS_NEW:
78
#if !defined(LWS_WITHOUT_EXTENSIONS)
79
    if (wsi->ws->rx_draining_ext) {
80
      pmdrx.eb_in.token = NULL;
81
      pmdrx.eb_in.len = 0;
82
      pmdrx.eb_out.token = NULL;
83
      pmdrx.eb_out.len = 0;
84
      lws_remove_wsi_from_draining_ext_list(wsi);
85
      rx_draining_ext = 1;
86
      lwsl_debug("%s: doing draining flow\n", __func__);
87
88
      goto drain_extension;
89
    }
90
#endif
91
0
    switch (wsi->ws->ietf_spec_revision) {
92
0
    case 13:
93
      /*
94
       * no prepended frame key any more
95
       */
96
0
      wsi->ws->all_zero_nonce = 1;
97
0
      goto handle_first;
98
99
0
    default:
100
0
      lwsl_warn("lws_ws_rx_sm: unknown spec version %d\n",
101
0
          wsi->ws->ietf_spec_revision);
102
0
      break;
103
0
    }
104
0
    break;
105
0
  case LWS_RXPS_04_mask_1:
106
0
    wsi->ws->mask[1] = c;
107
0
    if (c)
108
0
      wsi->ws->all_zero_nonce = 0;
109
0
    wsi->lws_rx_parse_state = LWS_RXPS_04_mask_2;
110
0
    break;
111
0
  case LWS_RXPS_04_mask_2:
112
0
    wsi->ws->mask[2] = c;
113
0
    if (c)
114
0
      wsi->ws->all_zero_nonce = 0;
115
0
    wsi->lws_rx_parse_state = LWS_RXPS_04_mask_3;
116
0
    break;
117
0
  case LWS_RXPS_04_mask_3:
118
0
    wsi->ws->mask[3] = c;
119
0
    if (c)
120
0
      wsi->ws->all_zero_nonce = 0;
121
122
    /*
123
     * start from the zero'th byte in the XOR key buffer since
124
     * this is the start of a frame with a new key
125
     */
126
127
0
    wsi->ws->mask_idx = 0;
128
129
0
    wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_1;
130
0
    break;
131
132
  /*
133
   *  04 logical framing from the spec (all this is masked when incoming
134
   *  and has to be unmasked)
135
   *
136
   * We ignore the possibility of extension data because we don't
137
   * negotiate any extensions at the moment.
138
   *
139
   *    0                   1                   2                   3
140
   *    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
141
   *   +-+-+-+-+-------+-+-------------+-------------------------------+
142
   *   |F|R|R|R| opcode|R| Payload len |    Extended payload length    |
143
   *   |I|S|S|S|  (4)  |S|     (7)     |             (16/63)           |
144
   *   |N|V|V|V|       |V|             |   (if payload len==126/127)   |
145
   *   | |1|2|3|       |4|             |                               |
146
   *   +-+-+-+-+-------+-+-------------+ - - - - - - - - - - - - - - - +
147
   *   |     Extended payload length continued, if payload len == 127  |
148
   *   + - - - - - - - - - - - - - - - +-------------------------------+
149
   *   |                               |         Extension data        |
150
   *   +-------------------------------+ - - - - - - - - - - - - - - - +
151
   *   :                                                               :
152
   *   +---------------------------------------------------------------+
153
   *   :                       Application data                        :
154
   *   +---------------------------------------------------------------+
155
   *
156
   *  We pass payload through to userland as soon as we get it, ignoring
157
   *  FIN.  It's up to userland to buffer it up if it wants to see a
158
   *  whole unfragmented block of the original size (which may be up to
159
   *  2^63 long!)
160
   */
161
162
0
  case LWS_RXPS_04_FRAME_HDR_1:
163
0
handle_first:
164
165
0
    wsi->ws->opcode = c & 0xf;
166
0
    wsi->ws->rsv = c & 0x70;
167
0
    wsi->ws->final = !!((c >> 7) & 1);
168
0
    wsi->ws->defeat_check_utf8 = 0;
169
170
0
    if (((wsi->ws->opcode) & 8) && !wsi->ws->final) {
171
0
      lws_close_reason(wsi, LWS_CLOSE_STATUS_PROTOCOL_ERR,
172
0
          (uint8_t *)"frag ctl", 8);
173
0
      goto ret_asking_close;
174
0
    }
175
176
0
    switch (wsi->ws->opcode) {
177
0
    case LWSWSOPC_TEXT_FRAME:
178
0
      wsi->ws->check_utf8 = !lws_check_opt(
179
0
        wsi->a.context->options,
180
0
        LWS_SERVER_OPTION_DISABLE_UTF8_VALIDATION);
181
      /* fallthru */
182
0
    case LWSWSOPC_BINARY_FRAME:
183
0
      if (wsi->ws->opcode == LWSWSOPC_BINARY_FRAME)
184
0
        wsi->ws->check_utf8 = 0;
185
0
      if (wsi->ws->continuation_possible) {
186
0
        lws_close_reason(wsi,
187
0
          LWS_CLOSE_STATUS_PROTOCOL_ERR,
188
0
          (uint8_t *)"bad cont", 8);
189
0
        goto ret_asking_close;
190
0
      }
191
0
      wsi->ws->rsv_first_msg = (c & 0x70);
192
#if !defined(LWS_WITHOUT_EXTENSIONS)
193
      /*
194
       *  set the expectation that we will have to
195
       * fake up the zlib trailer to the inflator for this
196
       * frame
197
       */
198
      wsi->ws->pmd_trailer_application = !!(c & 0x40);
199
#endif
200
0
      wsi->ws->frame_is_binary =
201
0
           wsi->ws->opcode == LWSWSOPC_BINARY_FRAME;
202
0
      wsi->ws->first_fragment = 1;
203
0
      wsi->ws->continuation_possible = !wsi->ws->final;
204
0
      break;
205
0
    case LWSWSOPC_CONTINUATION:
206
0
      if (!wsi->ws->continuation_possible) {
207
0
        lws_close_reason(wsi,
208
0
          LWS_CLOSE_STATUS_PROTOCOL_ERR,
209
0
          (uint8_t *)"bad cont", 8);
210
0
        goto ret_asking_close;
211
0
      }
212
0
      break;
213
0
    case LWSWSOPC_PING:
214
0
    case LWSWSOPC_PONG:
215
0
      wsi->ws->defeat_check_utf8 = 1;
216
0
      break;
217
0
    case LWSWSOPC_CLOSE:
218
0
      wsi->ws->check_utf8 = 0;
219
0
      wsi->ws->utf8 = 0;
220
0
      break;
221
0
    case 3:
222
0
    case 4:
223
0
    case 5:
224
0
    case 6:
225
0
    case 7:
226
0
    case 0xb:
227
0
    case 0xc:
228
0
    case 0xd:
229
0
    case 0xe:
230
0
    case 0xf:
231
0
      lws_close_reason(wsi, LWS_CLOSE_STATUS_PROTOCOL_ERR,
232
0
          (uint8_t *)"bad opc", 7);
233
0
      lwsl_info("illegal opcode\n");
234
0
      goto ret_asking_close;
235
0
    }
236
237
0
    if (wsi->ws->owed_a_fin &&
238
0
        (wsi->ws->opcode == LWSWSOPC_TEXT_FRAME ||
239
0
         wsi->ws->opcode == LWSWSOPC_BINARY_FRAME)) {
240
0
      lwsl_info("hey you owed us a FIN\n");
241
0
      lws_close_reason(wsi, LWS_CLOSE_STATUS_PROTOCOL_ERR,
242
0
          (uint8_t *)"bad fin", 7);
243
0
      goto ret_asking_close;
244
0
    }
245
0
    if ((!(wsi->ws->opcode & 8)) && wsi->ws->final) {
246
0
      wsi->ws->continuation_possible = 0;
247
0
      wsi->ws->owed_a_fin = 0;
248
0
    }
249
250
0
    if (!wsi->ws->final)
251
0
      wsi->ws->owed_a_fin = 1;
252
253
0
    wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN;
254
0
    if (wsi->ws->rsv &&
255
0
        (
256
#if !defined(LWS_WITHOUT_EXTENSIONS)
257
            !wsi->ws->count_act_ext ||
258
#endif
259
0
            (wsi->ws->rsv & ~0x40))) {
260
0
      lws_close_reason(wsi, LWS_CLOSE_STATUS_PROTOCOL_ERR,
261
0
           (uint8_t *)"rsv bits", 8);
262
0
      goto ret_asking_close;
263
0
    }
264
0
    break;
265
266
0
  case LWS_RXPS_04_FRAME_HDR_LEN:
267
268
0
    wsi->ws->this_frame_masked = !!(c & 0x80);
269
270
0
#if defined(LWS_WITH_SERVER)
271
0
    if (lwsi_role_server(wsi) && !wsi->ws->this_frame_masked) {
272
0
      lws_close_reason(wsi, LWS_CLOSE_STATUS_PROTOCOL_ERR,
273
0
           (uint8_t *)"client unmasked", 15);
274
0
      goto ret_asking_close;
275
0
    }
276
0
#endif
277
278
0
    switch (c & 0x7f) {
279
0
    case 126:
280
      /* control frames are not allowed to have big lengths */
281
0
      if (wsi->ws->opcode & 8)
282
0
        goto illegal_ctl_length;
283
284
0
      wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN16_2;
285
0
      break;
286
0
    case 127:
287
      /* control frames are not allowed to have big lengths */
288
0
      if (wsi->ws->opcode & 8)
289
0
        goto illegal_ctl_length;
290
291
0
      wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_8;
292
0
      break;
293
0
    default:
294
0
      wsi->ws->rx_packet_length = c & 0x7f;
295
296
297
0
      if (wsi->ws->this_frame_masked)
298
0
        wsi->lws_rx_parse_state =
299
0
            LWS_RXPS_07_COLLECT_FRAME_KEY_1;
300
0
      else
301
0
        if (wsi->ws->rx_packet_length) {
302
0
          wsi->lws_rx_parse_state =
303
0
          LWS_RXPS_WS_FRAME_PAYLOAD;
304
0
        } else {
305
0
          wsi->lws_rx_parse_state = LWS_RXPS_NEW;
306
0
          goto spill;
307
0
        }
308
0
      break;
309
0
    }
310
0
    break;
311
312
0
  case LWS_RXPS_04_FRAME_HDR_LEN16_2:
313
0
    wsi->ws->rx_packet_length = (size_t)(c << 8);
314
0
    wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN16_1;
315
0
    break;
316
317
0
  case LWS_RXPS_04_FRAME_HDR_LEN16_1:
318
0
    wsi->ws->rx_packet_length |= c;
319
0
    if (wsi->ws->this_frame_masked)
320
0
      wsi->lws_rx_parse_state =
321
0
          LWS_RXPS_07_COLLECT_FRAME_KEY_1;
322
0
    else {
323
0
      wsi->lws_rx_parse_state =
324
0
        LWS_RXPS_WS_FRAME_PAYLOAD;
325
0
    }
326
0
    break;
327
328
0
  case LWS_RXPS_04_FRAME_HDR_LEN64_8:
329
0
    if (c & 0x80) {
330
0
      lwsl_warn("b63 of length must be zero\n");
331
      /* kill the connection */
332
0
      goto ret_asking_close;
333
0
    }
334
0
#if defined __LP64__
335
0
    wsi->ws->rx_packet_length = ((size_t)c) << 56;
336
#else
337
    wsi->ws->rx_packet_length = 0;
338
#endif
339
0
    wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_7;
340
0
    break;
341
342
0
  case LWS_RXPS_04_FRAME_HDR_LEN64_7:
343
0
#if defined __LP64__
344
0
    wsi->ws->rx_packet_length |= ((size_t)c) << 48;
345
0
#endif
346
0
    wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_6;
347
0
    break;
348
349
0
  case LWS_RXPS_04_FRAME_HDR_LEN64_6:
350
0
#if defined __LP64__
351
0
    wsi->ws->rx_packet_length |= ((size_t)c) << 40;
352
0
#endif
353
0
    wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_5;
354
0
    break;
355
356
0
  case LWS_RXPS_04_FRAME_HDR_LEN64_5:
357
0
#if defined __LP64__
358
0
    wsi->ws->rx_packet_length |= ((size_t)c) << 32;
359
0
#endif
360
0
    wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_4;
361
0
    break;
362
363
0
  case LWS_RXPS_04_FRAME_HDR_LEN64_4:
364
0
    wsi->ws->rx_packet_length |= ((size_t)c) << 24;
365
0
    wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_3;
366
0
    break;
367
368
0
  case LWS_RXPS_04_FRAME_HDR_LEN64_3:
369
0
    wsi->ws->rx_packet_length |= ((size_t)c) << 16;
370
0
    wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_2;
371
0
    break;
372
373
0
  case LWS_RXPS_04_FRAME_HDR_LEN64_2:
374
0
    wsi->ws->rx_packet_length |= ((size_t)c) << 8;
375
0
    wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_1;
376
0
    break;
377
378
0
        case LWS_RXPS_04_FRAME_HDR_LEN64_1:
379
0
                wsi->ws->rx_packet_length |= ((size_t)c);
380
0
                if (wsi->ws->rx_packet_length > 0x10000000ull) {
381
0
                        lwsl_err("huge ws frame\n");
382
0
                        goto ret_asking_close;
383
0
                }
384
0
                if (wsi->ws->this_frame_masked)
385
0
      wsi->lws_rx_parse_state =
386
0
          LWS_RXPS_07_COLLECT_FRAME_KEY_1;
387
0
    else
388
0
      wsi->lws_rx_parse_state = LWS_RXPS_WS_FRAME_PAYLOAD;
389
0
    break;
390
391
0
  case LWS_RXPS_07_COLLECT_FRAME_KEY_1:
392
0
    wsi->ws->mask[0] = c;
393
0
    if (c)
394
0
      wsi->ws->all_zero_nonce = 0;
395
0
    wsi->lws_rx_parse_state = LWS_RXPS_07_COLLECT_FRAME_KEY_2;
396
0
    break;
397
398
0
  case LWS_RXPS_07_COLLECT_FRAME_KEY_2:
399
0
    wsi->ws->mask[1] = c;
400
0
    if (c)
401
0
      wsi->ws->all_zero_nonce = 0;
402
0
    wsi->lws_rx_parse_state = LWS_RXPS_07_COLLECT_FRAME_KEY_3;
403
0
    break;
404
405
0
  case LWS_RXPS_07_COLLECT_FRAME_KEY_3:
406
0
    wsi->ws->mask[2] = c;
407
0
    if (c)
408
0
      wsi->ws->all_zero_nonce = 0;
409
0
    wsi->lws_rx_parse_state = LWS_RXPS_07_COLLECT_FRAME_KEY_4;
410
0
    break;
411
412
0
  case LWS_RXPS_07_COLLECT_FRAME_KEY_4:
413
0
    wsi->ws->mask[3] = c;
414
0
    if (c)
415
0
      wsi->ws->all_zero_nonce = 0;
416
0
    wsi->lws_rx_parse_state = LWS_RXPS_WS_FRAME_PAYLOAD;
417
0
    wsi->ws->mask_idx = 0;
418
0
    if (wsi->ws->rx_packet_length == 0) {
419
0
      wsi->lws_rx_parse_state = LWS_RXPS_NEW;
420
0
      goto spill;
421
0
    }
422
0
    break;
423
424
425
0
  case LWS_RXPS_WS_FRAME_PAYLOAD:
426
0
    assert(wsi->ws->rx_ubuf);
427
428
0
    if (wsi->ws->rx_ubuf_head + LWS_PRE >= wsi->ws->rx_ubuf_alloc) {
429
0
      lwsl_err("Attempted overflow \n");
430
0
      goto ret_asking_close;
431
0
    }
432
0
    if (!(already_processed & ALREADY_PROCESSED_IGNORE_CHAR)) {
433
0
      if (wsi->ws->all_zero_nonce)
434
0
        wsi->ws->rx_ubuf[LWS_PRE +
435
0
                         (wsi->ws->rx_ubuf_head++)] = c;
436
0
      else
437
0
        wsi->ws->rx_ubuf[LWS_PRE +
438
0
                         (wsi->ws->rx_ubuf_head++)] =
439
0
           c ^ wsi->ws->mask[(wsi->ws->mask_idx++) & 3];
440
441
0
      --wsi->ws->rx_packet_length;
442
0
    }
443
444
0
    if (!wsi->ws->rx_packet_length) {
445
0
      lwsl_debug("%s: ws fragment length exhausted\n",
446
0
           __func__);
447
      /* spill because we have the whole frame */
448
0
      wsi->lws_rx_parse_state = LWS_RXPS_NEW;
449
0
      goto spill;
450
0
    }
451
#if !defined(LWS_WITHOUT_EXTENSIONS)
452
    if (wsi->ws->rx_draining_ext) {
453
      lwsl_debug("%s: UNTIL_EXHAUSTED draining\n", __func__);
454
      goto drain_extension;
455
    }
456
#endif
457
    /*
458
     * if there's no protocol max frame size given, we are
459
     * supposed to default to context->pt_serv_buf_size
460
     */
461
0
    if (!wsi->a.protocol->rx_buffer_size &&
462
0
        wsi->ws->rx_ubuf_head != wsi->a.context->pt_serv_buf_size)
463
0
      break;
464
465
0
    if (wsi->a.protocol->rx_buffer_size &&
466
0
        wsi->ws->rx_ubuf_head != wsi->a.protocol->rx_buffer_size)
467
0
      break;
468
469
    /* spill because we filled our rx buffer */
470
0
spill:
471
    /*
472
     * is this frame a control packet we should take care of at this
473
     * layer?  If so service it and hide it from the user callback
474
     */
475
476
0
    lwsl_parser("spill on %s\n", wsi->a.protocol->name);
477
478
0
    switch (wsi->ws->opcode) {
479
0
    case LWSWSOPC_CLOSE:
480
481
0
      if (wsi->ws->peer_has_sent_close)
482
0
        break;
483
484
0
      wsi->ws->peer_has_sent_close = 1;
485
486
0
      pp = &wsi->ws->rx_ubuf[LWS_PRE];
487
0
      if (lws_check_opt(wsi->a.context->options,
488
0
            LWS_SERVER_OPTION_VALIDATE_UTF8) &&
489
0
          wsi->ws->rx_ubuf_head > 2 &&
490
0
          lws_check_utf8(&wsi->ws->utf8, pp + 2,
491
0
             wsi->ws->rx_ubuf_head - 2)) {
492
0
        lwsl_notice("utf8 error\n");
493
0
        return LWS_HPI_RET_PLEASE_CLOSE_ME;
494
0
      }
495
496
      /* is this an acknowledgment of our close? */
497
0
      if (lwsi_state(wsi) == LRS_AWAITING_CLOSE_ACK) {
498
        /*
499
         * fine he has told us he is closing too, let's
500
         * finish our close
501
         */
502
0
        lwsl_parser("seen client close ack\n");
503
0
        goto ret_asking_close;
504
0
      }
505
0
      if (lwsi_state(wsi) == LRS_RETURNED_CLOSE)
506
        /* if he sends us 2 CLOSE, kill him */
507
0
        goto ret_asking_close;
508
509
0
      if (lws_partial_buffered(wsi)) {
510
        /*
511
         * if we're in the middle of something,
512
         * we can't do a normal close response and
513
         * have to just close our end.
514
         */
515
0
        wsi->socket_is_permanently_unusable = 1;
516
0
        lwsl_parser("Closing on peer close "
517
0
              "due to pending tx\n");
518
0
        goto ret_asking_close;
519
0
      }
520
521
0
      if (wsi->ws->rx_ubuf_head >= 2) {
522
0
        close_code = (unsigned short)((pp[0] << 8) | pp[1]);
523
0
        if (close_code < 1000 ||
524
0
            close_code == 1004 ||
525
0
            close_code == 1005 ||
526
0
            close_code == 1006 ||
527
0
            close_code == 1012 ||
528
0
            close_code == 1013 ||
529
0
            close_code == 1014 ||
530
0
            close_code == 1015 ||
531
0
            (close_code >= 1016 && close_code < 3000)
532
0
        ) {
533
0
          pp[0] = (LWS_CLOSE_STATUS_PROTOCOL_ERR >> 8) & 0xff;
534
0
          pp[1] = LWS_CLOSE_STATUS_PROTOCOL_ERR & 0xff;
535
0
        }
536
0
      }
537
538
0
      if (user_callback_handle_rxflow(
539
0
          wsi->a.protocol->callback, wsi,
540
0
          LWS_CALLBACK_WS_PEER_INITIATED_CLOSE,
541
0
          wsi->user_space,
542
0
          &wsi->ws->rx_ubuf[LWS_PRE],
543
0
          wsi->ws->rx_ubuf_head))
544
0
        goto ret_asking_close;
545
546
0
      lwsl_parser("server sees client close packet\n");
547
0
      lwsi_set_state(wsi, LRS_RETURNED_CLOSE);
548
      /* deal with the close packet contents as a PONG */
549
0
      wsi->ws->payload_is_close = 1;
550
0
      goto process_as_ping;
551
552
0
    case LWSWSOPC_PING:
553
0
      lwsl_info("received %d byte ping, sending pong\n",
554
0
             (int)wsi->ws->rx_ubuf_head);
555
556
0
      if (wsi->ws->pong_pending_flag) {
557
        /*
558
         * there is already a pending pong payload
559
         * we should just log and drop
560
         */
561
0
        lwsl_parser("DROP PING since one pending\n");
562
0
        goto ping_drop;
563
0
      }
564
0
process_as_ping:
565
      /* control packets can only be < 128 bytes long */
566
0
      if (wsi->ws->rx_ubuf_head > 128 - 3) {
567
0
        lwsl_parser("DROP PING payload too large\n");
568
0
        goto ping_drop;
569
0
      }
570
571
      /* stash the pong payload */
572
0
      memcpy(wsi->ws->pong_payload_buf + LWS_PRE,
573
0
             &wsi->ws->rx_ubuf[LWS_PRE],
574
0
        wsi->ws->rx_ubuf_head);
575
576
0
      wsi->ws->pong_payload_len = (uint8_t)wsi->ws->rx_ubuf_head;
577
0
      wsi->ws->pong_pending_flag = 1;
578
579
      /* get it sent as soon as possible */
580
0
      lws_callback_on_writable(wsi);
581
0
ping_drop:
582
0
      wsi->ws->rx_ubuf_head = 0;
583
584
0
      return LWS_HPI_RET_HANDLED;
585
586
0
    case LWSWSOPC_PONG:
587
0
      lwsl_info("received pong\n");
588
0
      lwsl_hexdump(&wsi->ws->rx_ubuf[LWS_PRE],
589
0
                   wsi->ws->rx_ubuf_head);
590
591
0
      lws_validity_confirmed(wsi);
592
593
      /* issue it */
594
0
      callback_action = LWS_CALLBACK_RECEIVE_PONG;
595
0
      break;
596
597
0
    case LWSWSOPC_TEXT_FRAME:
598
0
    case LWSWSOPC_BINARY_FRAME:
599
0
    case LWSWSOPC_CONTINUATION:
600
0
      break;
601
602
0
    default:
603
0
      lwsl_parser("unknown opc %x\n", wsi->ws->opcode);
604
605
0
      goto ret_asking_close;
606
0
    }
607
608
    /*
609
     * No it's real payload, pass it up to the user callback.
610
     *
611
     * We have been statefully collecting it in the
612
     * LWS_RXPS_WS_FRAME_PAYLOAD clause above.
613
     *
614
     * It's nicely buffered with the pre-padding taken care of
615
     * so it can be sent straight out again using lws_write.
616
     *
617
     * However, now we have a chunk of it, we want to deal with it
618
     * all here.  Since this may be input to permessage-deflate and
619
     * there are block limits on that for input and output, we may
620
     * need to iterate.
621
     */
622
623
0
    pmdrx.eb_in.token = &wsi->ws->rx_ubuf[LWS_PRE];
624
0
    pmdrx.eb_in.len = (int)wsi->ws->rx_ubuf_head;
625
626
    /* for the non-pm-deflate case */
627
628
0
    pmdrx.eb_out = pmdrx.eb_in;
629
630
0
    if (wsi->ws->opcode == LWSWSOPC_PONG && !pmdrx.eb_in.len)
631
0
      goto already_done;
632
#if !defined(LWS_WITHOUT_EXTENSIONS)
633
drain_extension:
634
#endif
635
636
0
    do {
637
638
//      lwsl_notice("%s: pmdrx.eb_in.len: %d\n", __func__,
639
//          (int)pmdrx.eb_in.len);
640
641
0
      if (lwsi_state(wsi) == LRS_RETURNED_CLOSE ||
642
0
          lwsi_state(wsi) == LRS_AWAITING_CLOSE_ACK)
643
0
        goto already_done;
644
645
0
      n = PMDR_DID_NOTHING;
646
647
#if !defined(LWS_WITHOUT_EXTENSIONS)
648
      lin = pmdrx.eb_in.len;
649
      //if (lin)
650
      //  lwsl_hexdump_notice(ebuf.token, ebuf.len);
651
      lwsl_ext("%s: +++ passing %d %p to ext\n", __func__,
652
          pmdrx.eb_in.len, pmdrx.eb_in.token);
653
654
      n = lws_ext_cb_active(wsi, LWS_EXT_CB_PAYLOAD_RX, &pmdrx, 0);
655
      lwsl_debug("%s: ext says %d / ebuf.len %d\n", __func__,
656
           n, pmdrx.eb_out.len);
657
      if (wsi->ws->rx_draining_ext)
658
        already_processed &= (char)~ALREADY_PROCESSED_NO_CB;
659
#endif
660
661
      /*
662
       * ebuf may be pointing somewhere completely different
663
       * now, it's the output
664
       */
665
#if !defined(LWS_WITHOUT_EXTENSIONS)
666
      if (n < 0) {
667
        /*
668
         * we may rely on this to get RX, just drop
669
         * connection
670
         */
671
        wsi->socket_is_permanently_unusable = 1;
672
673
        goto ret_asking_close;
674
      }
675
      if (n == PMDR_DID_NOTHING)
676
        /* ie, not PMDR_NOTHING_WE_SHOULD_DO */
677
        break;
678
#endif
679
0
      lwsl_debug("%s: post ext ret %d, ebuf in %d / out %d\n",
680
0
            __func__, n, pmdrx.eb_in.len,
681
0
            pmdrx.eb_out.len);
682
683
#if !defined(LWS_WITHOUT_EXTENSIONS)
684
      if (rx_draining_ext && !pmdrx.eb_out.len) {
685
        lwsl_debug("   --- ending drain on 0 read\n");
686
        goto already_done;
687
      }
688
689
      if (n == PMDR_HAS_PENDING)
690
        /*
691
         * extension had more...
692
         * main loop will come back
693
         */
694
        lws_add_wsi_to_draining_ext_list(wsi);
695
      else
696
        lws_remove_wsi_from_draining_ext_list(wsi);
697
698
      rx_draining_ext = wsi->ws->rx_draining_ext;
699
#endif
700
701
0
      if (pmdrx.eb_out.len &&
702
0
          wsi->ws->check_utf8 && !wsi->ws->defeat_check_utf8) {
703
0
        if (lws_check_utf8(&wsi->ws->utf8,
704
0
               pmdrx.eb_out.token,
705
0
               (unsigned int)pmdrx.eb_out.len)) {
706
0
          lws_close_reason(wsi,
707
0
            LWS_CLOSE_STATUS_INVALID_PAYLOAD,
708
0
            (uint8_t *)"bad utf8", 8);
709
0
          lwsl_notice("utf8 error\n");
710
0
          lwsl_hexdump_notice(pmdrx.eb_out.token,
711
0
                  (size_t)pmdrx.eb_out.len);
712
713
0
          return LWS_HPI_RET_PLEASE_CLOSE_ME;
714
0
        }
715
716
        /* we are ending partway through utf-8 character? */
717
0
        if (!wsi->ws->rx_packet_length &&
718
0
            wsi->ws->final && wsi->ws->utf8
719
#if !defined(LWS_WITHOUT_EXTENSIONS)
720
            /* if ext not negotiated, going to be UNKNOWN */
721
            && (n == PMDR_EMPTY_FINAL || n == PMDR_UNKNOWN)
722
#endif
723
0
        ) {
724
0
          lwsl_info("FINAL utf8 error\n");
725
0
          lws_close_reason(wsi,
726
0
            LWS_CLOSE_STATUS_INVALID_PAYLOAD,
727
0
            (uint8_t *)"partial utf8", 12);
728
0
          lwsl_notice("utf8 error\n");
729
0
          lwsl_hexdump_notice(pmdrx.eb_out.token,
730
0
                  (size_t)pmdrx.eb_out.len);
731
732
0
          return LWS_HPI_RET_PLEASE_CLOSE_ME;
733
0
        }
734
0
      }
735
736
      /* if pmd not enabled, in == out */
737
738
0
      if (n == PMDR_DID_NOTHING
739
#if !defined(LWS_WITHOUT_EXTENSIONS)
740
          ||
741
          n == PMDR_NOTHING_WE_SHOULD_DO ||
742
          n == PMDR_UNKNOWN
743
#endif
744
0
          )
745
0
        pmdrx.eb_in.len -= pmdrx.eb_out.len;
746
747
0
  if (!wsi->wsistate_pre_close &&
748
0
          (pmdrx.eb_out.len >= 0 ||
749
0
           callback_action == LWS_CALLBACK_RECEIVE_PONG ||
750
0
                   n == PMDR_EMPTY_FINAL)) {
751
0
        if (pmdrx.eb_out.len)
752
0
          pmdrx.eb_out.token[pmdrx.eb_out.len] = '\0';
753
754
0
        if (wsi->a.protocol->callback &&
755
0
            !(already_processed & ALREADY_PROCESSED_NO_CB)) {
756
0
          int _ret;
757
758
0
          if (callback_action ==
759
0
                  LWS_CALLBACK_RECEIVE_PONG)
760
0
            lwsl_info("Doing pong callback\n");
761
762
0
          _ret = user_callback_handle_rxflow(
763
0
            wsi->a.protocol->callback, wsi,
764
0
            (enum lws_callback_reasons)
765
0
                   callback_action,
766
0
            wsi->user_space,
767
0
            pmdrx.eb_out.token,
768
0
            (size_t)pmdrx.eb_out.len);
769
770
0
          if (_ret)
771
0
            ret = LWS_HPI_RET_PLEASE_CLOSE_ME;
772
0
        }
773
0
        wsi->ws->first_fragment = 0;
774
0
      }
775
776
#if !defined(LWS_WITHOUT_EXTENSIONS)
777
      if (!lin)
778
        break;
779
#endif
780
781
0
    } while (pmdrx.eb_in.len
782
#if !defined(LWS_WITHOUT_EXTENSIONS)
783
        || rx_draining_ext
784
#endif
785
0
    );
786
787
0
already_done:
788
0
    wsi->ws->rx_ubuf_head = 0;
789
0
    break;
790
0
  }
791
792
0
  return ret;
793
794
0
illegal_ctl_length:
795
796
0
  lwsl_warn("Control frame with xtended length is illegal\n");
797
798
0
ret_asking_close:
799
800
  /* kill the connection */
801
802
0
  return LWS_HPI_RET_PLEASE_CLOSE_ME;
803
0
}
804
805
806
size_t
807
lws_remaining_packet_payload(struct lws *wsi)
808
0
{
809
0
  return wsi->ws->rx_packet_length;
810
0
}
811
812
int lws_frame_is_binary(struct lws *wsi)
813
0
{
814
0
  return wsi->ws->frame_is_binary;
815
0
}
816
817
void
818
lws_add_wsi_to_draining_ext_list(struct lws *wsi)
819
0
{
820
#if !defined(LWS_WITHOUT_EXTENSIONS)
821
  struct lws_context_per_thread *pt = &wsi->a.context->pt[(int)wsi->tsi];
822
823
  if (wsi->ws->rx_draining_ext)
824
    return;
825
826
  lwsl_debug("%s: RX EXT DRAINING: Adding to list\n", __func__);
827
828
  wsi->ws->rx_draining_ext = 1;
829
  wsi->ws->rx_draining_ext_list = pt->ws.rx_draining_ext_list;
830
  pt->ws.rx_draining_ext_list = wsi;
831
#endif
832
0
}
833
834
void
835
lws_remove_wsi_from_draining_ext_list(struct lws *wsi)
836
0
{
837
#if !defined(LWS_WITHOUT_EXTENSIONS)
838
  struct lws_context_per_thread *pt = &wsi->a.context->pt[(int)wsi->tsi];
839
  struct lws **w = &pt->ws.rx_draining_ext_list;
840
841
  if (!wsi->ws->rx_draining_ext)
842
    return;
843
844
  lwsl_debug("%s: RX EXT DRAINING: Removing from list\n", __func__);
845
846
  wsi->ws->rx_draining_ext = 0;
847
848
  /* remove us from context draining ext list */
849
  while (*w) {
850
    if (*w == wsi) {
851
      /* if us, point it instead to who we were pointing to */
852
      *w = wsi->ws->rx_draining_ext_list;
853
      break;
854
    }
855
    w = &((*w)->ws->rx_draining_ext_list);
856
  }
857
  wsi->ws->rx_draining_ext_list = NULL;
858
#endif
859
0
}
860
861
static int
862
lws_0405_frame_mask_generate(struct lws *wsi)
863
0
{
864
0
  size_t n;
865
  /* fetch the per-frame nonce */
866
867
0
  n = lws_get_random(lws_get_context(wsi), wsi->ws->mask, 4);
868
0
  if (n != 4) {
869
0
    lwsl_parser("Unable to read from random device %s %d\n",
870
0
          SYSTEM_RANDOM_FILEPATH, (int)n);
871
0
    return 1;
872
0
  }
873
874
  /* start masking from first byte of masking key buffer */
875
0
  wsi->ws->mask_idx = 0;
876
877
0
  return 0;
878
0
}
879
880
int
881
lws_server_init_wsi_for_ws(struct lws *wsi)
882
0
{
883
0
  int n;
884
885
#if defined(LWS_WITH_HTTP_PROXY)
886
  if (!wsi->proxied_ws_parent) 
887
    lwsi_set_state(wsi, LRS_ESTABLISHED);
888
#endif
889
890
  /*
891
   * create the frame buffer for this connection according to the
892
   * size mentioned in the protocol definition.  If 0 there, use
893
   * a big default for compatibility
894
   */
895
896
0
  n = (int)wsi->a.protocol->rx_buffer_size;
897
0
  if (!n)
898
0
    n = (int)wsi->a.context->pt_serv_buf_size;
899
0
  n += LWS_PRE;
900
0
  wsi->ws->rx_ubuf = lws_malloc((unsigned int)n + 4 /* 0x0000ffff zlib */, "rx_ubuf");
901
0
  if (!wsi->ws->rx_ubuf) {
902
0
    lwsl_err("Out of Mem allocating rx buffer %d\n", n);
903
0
    return 1;
904
0
  }
905
0
  wsi->ws->rx_ubuf_alloc = (uint32_t)n;
906
907
  /* notify user code that we're ready to roll */
908
909
0
  if (wsi->a.protocol->callback) {
910
#if defined(LWS_WITH_HTTP_PROXY)
911
    if (wsi->proxied_ws_parent) {
912
      lws_sul_schedule(wsi->a.context, wsi->tsi,
913
           &wsi->sul_ws_proxy_est,
914
           lws_ws_proxy_est_cb, 5000);
915
      goto validity;
916
    }
917
#endif
918
0
    if (wsi->a.protocol->callback(wsi, LWS_CALLBACK_ESTABLISHED,
919
0
              wsi->user_space,
920
0
#ifdef LWS_WITH_TLS
921
0
              wsi->tls.ssl,
922
#else
923
              NULL,
924
#endif
925
0
              wsi->h23_stream_carries_ws))
926
0
      return 1;
927
0
  }
928
#if defined(LWS_WITH_HTTP_PROXY)
929
validity:
930
#endif
931
932
0
  lws_validity_confirmed(wsi);
933
0
  lwsl_debug("ws established\n");
934
935
0
  return 0;
936
0
}
937
938
939
int
940
lws_ws_sending_multifragment(struct lws *wsi)
941
0
{
942
0
  return wsi->ws->last_valid && !wsi->ws->last_fin;
943
0
}
944
945
int
946
lws_is_final_fragment(struct lws *wsi)
947
0
{
948
#if !defined(LWS_WITHOUT_EXTENSIONS)
949
  lwsl_debug("%s: final %d, rx pk length %ld, draining %ld\n", __func__,
950
       wsi->ws->final, (long)wsi->ws->rx_packet_length,
951
       (long)wsi->ws->rx_draining_ext);
952
  return wsi->ws->final && !wsi->ws->rx_packet_length &&
953
         !wsi->ws->rx_draining_ext;
954
#else
955
0
  return wsi->ws->final && !wsi->ws->rx_packet_length;
956
0
#endif
957
0
}
958
959
int
960
lws_is_first_fragment(struct lws *wsi)
961
0
{
962
0
  return wsi->ws->first_fragment;
963
0
}
964
965
unsigned char
966
lws_get_reserved_bits(struct lws *wsi)
967
0
{
968
0
  return wsi->ws->rsv;
969
0
}
970
971
uint8_t
972
lws_get_opcode(struct lws *wsi)
973
0
{
974
0
  return wsi->ws->opcode;
975
0
}
976
977
int
978
lws_get_close_length(struct lws *wsi)
979
0
{
980
0
  return wsi->ws->close_in_ping_buffer_len;
981
0
}
982
983
unsigned char *
984
lws_get_close_payload(struct lws *wsi)
985
0
{
986
0
  return &wsi->ws->ping_payload_buf[LWS_PRE];
987
0
}
988
989
void
990
lws_close_reason(struct lws *wsi, enum lws_close_status status,
991
     unsigned char *buf, size_t len)
992
0
{
993
0
  unsigned char *p, *start;
994
0
  int budget = sizeof(wsi->ws->ping_payload_buf) - LWS_PRE;
995
996
0
  assert(lwsi_role_ws(wsi));
997
998
0
  start = p = &wsi->ws->ping_payload_buf[LWS_PRE];
999
1000
0
  *p++ = (uint8_t)((((int)status) >> 8) & 0xff);
1001
0
  *p++ = (uint8_t)(((int)status) & 0xff);
1002
1003
0
  if (buf)
1004
0
    while (len-- && p < start + budget)
1005
0
      *p++ = *buf++;
1006
1007
0
  wsi->ws->close_in_ping_buffer_len = (uint8_t)lws_ptr_diff(p, start);
1008
0
}
1009
1010
static int
1011
lws_is_ws_with_ext(struct lws *wsi)
1012
0
{
1013
0
#if defined(LWS_WITHOUT_EXTENSIONS)
1014
0
  return 0;
1015
#else
1016
  return lwsi_role_ws(wsi) && !!wsi->ws->count_act_ext;
1017
#endif
1018
0
}
1019
1020
static lws_handling_result_t
1021
rops_handle_POLLIN_ws(struct lws_context_per_thread *pt, struct lws *wsi,
1022
           struct lws_pollfd *pollfd)
1023
0
{
1024
0
  unsigned int pending = 0;
1025
0
  struct lws_tokens ebuf;
1026
0
  char buffered = 0;
1027
0
  int n = 0, m, sanity = 10000;
1028
1029
0
  if (!wsi->ws) {
1030
0
    lwsl_err("ws role wsi with no ws\n");
1031
0
    return LWS_HPI_RET_PLEASE_CLOSE_ME;
1032
0
  }
1033
1034
  // lwsl_notice("%s: %s\n", __func__, wsi->a.protocol->name);
1035
1036
  //lwsl_info("%s: wsistate 0x%x, pollout %d\n", __func__,
1037
  //     wsi->wsistate, pollfd->revents & LWS_POLLOUT);
1038
1039
  /*
1040
   * something went wrong with parsing the handshake, and
1041
   * we ended up back in the event loop without completing it
1042
   */
1043
0
  if (lwsi_state(wsi) == LRS_PRE_WS_SERVING_ACCEPT) {
1044
0
    wsi->socket_is_permanently_unusable = 1;
1045
0
    return LWS_HPI_RET_PLEASE_CLOSE_ME;
1046
0
  }
1047
1048
0
  ebuf.token = NULL;
1049
0
  ebuf.len = 0;
1050
1051
0
  if (lwsi_state(wsi) == LRS_WAITING_CONNECT) {
1052
0
#if defined(LWS_WITH_CLIENT)
1053
0
    if ((pollfd->revents & LWS_POLLOUT) &&
1054
0
        lws_handle_POLLOUT_event(wsi, pollfd)) {
1055
0
      lwsl_debug("POLLOUT event closed it\n");
1056
0
      return LWS_HPI_RET_PLEASE_CLOSE_ME;
1057
0
    }
1058
1059
0
    n = lws_http_client_socket_service(wsi, pollfd);
1060
0
    if (n)
1061
0
      return LWS_HPI_RET_WSI_ALREADY_DIED;
1062
0
#endif
1063
0
    return LWS_HPI_RET_HANDLED;
1064
0
  }
1065
1066
  /* 1: something requested a callback when it was OK to write */
1067
1068
0
  if ((pollfd->revents & LWS_POLLOUT) &&
1069
0
      lwsi_state_can_handle_POLLOUT(wsi) &&
1070
0
      lws_handle_POLLOUT_event(wsi, pollfd)) {
1071
0
    if (lwsi_state(wsi) == LRS_RETURNED_CLOSE)
1072
0
      lwsi_set_state(wsi, LRS_FLUSHING_BEFORE_CLOSE);
1073
1074
0
    return LWS_HPI_RET_PLEASE_CLOSE_ME;
1075
0
  }
1076
1077
0
  if (lwsi_state(wsi) == LRS_RETURNED_CLOSE ||
1078
0
      lwsi_state(wsi) == LRS_WAITING_TO_SEND_CLOSE) {
1079
    /*
1080
     * we stopped caring about anything except control
1081
     * packets.  Force flow control off, defeat tx
1082
     * draining.
1083
     */
1084
0
    lws_rx_flow_control(wsi, 1);
1085
#if !defined(LWS_WITHOUT_EXTENSIONS)
1086
    if (wsi->ws)
1087
      wsi->ws->tx_draining_ext = 0;
1088
#endif
1089
0
  }
1090
#if !defined(LWS_WITHOUT_EXTENSIONS)
1091
  if (wsi->ws->tx_draining_ext) {
1092
    if (lws_handle_POLLOUT_event(wsi, pollfd))
1093
      return LWS_HPI_RET_PLEASE_CLOSE_ME;
1094
    //lwsl_notice("%s: tx drain\n", __func__);
1095
    /*
1096
     * We cannot deal with new RX until the TX ext path has
1097
     * been drained.  It's because new rx will, eg, crap on
1098
     * the wsi rx buf that may be needed to retain state.
1099
     *
1100
     * TX ext drain path MUST go through event loop to avoid
1101
     * blocking.
1102
     */
1103
    lws_callback_on_writable(wsi);
1104
    return LWS_HPI_RET_HANDLED;
1105
  }
1106
#endif
1107
0
  if ((pollfd->revents & LWS_POLLIN) && lws_is_flowcontrolled(wsi)) {
1108
    /* We cannot deal with any kind of new RX because we are
1109
     * RX-flowcontrolled.
1110
     */
1111
0
    lwsl_info("%s: flowcontrolled, ignoring rx\n", __func__);
1112
1113
0
    if (__lws_change_pollfd(wsi, LWS_POLLIN, 0))
1114
0
      return LWS_HPI_RET_PLEASE_CLOSE_ME;
1115
1116
0
    return LWS_HPI_RET_HANDLED;
1117
0
  }
1118
1119
0
  if (lws_is_flowcontrolled(wsi))
1120
0
    return LWS_HPI_RET_HANDLED;
1121
1122
#if !defined(LWS_WITHOUT_EXTENSIONS)
1123
  /* 2: RX Extension needs to be drained
1124
   */
1125
1126
  if (wsi->ws->rx_draining_ext) {
1127
1128
    lwsl_debug("%s: RX EXT DRAINING: Service\n", __func__);
1129
#if defined(LWS_WITH_CLIENT)
1130
    if (lwsi_role_client(wsi)) {
1131
      if (lws_ws_client_rx_sm(wsi, 0)  == LWS_HPI_RET_PLEASE_CLOSE_ME)
1132
        /* we closed wsi */
1133
        return LWS_HPI_RET_PLEASE_CLOSE_ME;
1134
    } else
1135
#endif
1136
      n = (int)lws_ws_rx_sm(wsi, ALREADY_PROCESSED_IGNORE_CHAR, 0);
1137
1138
    return LWS_HPI_RET_HANDLED;
1139
  }
1140
1141
  if (wsi->ws->rx_draining_ext)
1142
    /*
1143
     * We have RX EXT content to drain, but can't do it
1144
     * right now.  That means we cannot do anything lower
1145
     * priority either.
1146
     */
1147
    return LWS_HPI_RET_HANDLED;
1148
#endif
1149
1150
  /* 3: buflist needs to be drained
1151
   */
1152
0
  do {
1153
  //lws_buflist_describe(&wsi->buflist, wsi, __func__);
1154
0
  ebuf.len = (int)lws_buflist_next_segment_len(&wsi->buflist,
1155
0
                 &ebuf.token);
1156
0
  if (ebuf.len) {
1157
0
    lwsl_info("draining buflist (len %d)\n", ebuf.len);
1158
0
    buffered = 1;
1159
0
    goto drain;
1160
0
  }
1161
1162
0
  if (!(pollfd->revents & pollfd->events & LWS_POLLIN) && !wsi->http.ah)
1163
0
    return LWS_HPI_RET_HANDLED;
1164
1165
0
  if (lws_is_flowcontrolled(wsi)) {
1166
0
    lwsl_info("%s: %p should be rxflow (bm 0x%x)..\n",
1167
0
          __func__, wsi, wsi->rxflow_bitmap);
1168
0
    return LWS_HPI_RET_HANDLED;
1169
0
  }
1170
1171
0
  if (!(lwsi_role_client(wsi) &&
1172
0
        (lwsi_state(wsi) != LRS_ESTABLISHED &&
1173
0
         lwsi_state(wsi) != LRS_AWAITING_CLOSE_ACK &&
1174
0
         lwsi_state(wsi) != LRS_H2_WAITING_TO_SEND_HEADERS))) {
1175
    /*
1176
     * In case we are going to react to this rx by scheduling
1177
     * writes, we need to restrict the amount of rx to the size
1178
     * the protocol reported for rx buffer.
1179
     *
1180
     * Otherwise we get a situation we have to absorb possibly a
1181
     * lot of reads before we get a chance to drain them by writing
1182
     * them, eg, with echo type tests in autobahn.
1183
     */
1184
1185
0
    buffered = 0;
1186
0
    ebuf.token = pt->serv_buf;
1187
0
    if (lwsi_role_ws(wsi))
1188
0
      ebuf.len = (int)wsi->ws->rx_ubuf_alloc;
1189
0
    else
1190
0
      ebuf.len = (int)wsi->a.context->pt_serv_buf_size;
1191
1192
0
    if ((unsigned int)ebuf.len > wsi->a.context->pt_serv_buf_size)
1193
0
      ebuf.len = (int)wsi->a.context->pt_serv_buf_size;
1194
1195
0
    if ((int)pending > ebuf.len)
1196
0
      pending = (unsigned int)ebuf.len;
1197
1198
#if defined(LWS_WITH_LATENCY)
1199
    lws_usec_t _ws_capread_start = lws_now_usecs();
1200
#endif
1201
1202
0
    ebuf.len = lws_ssl_capable_read(wsi, ebuf.token,
1203
0
            (size_t)(pending ? pending :
1204
0
            (unsigned int)ebuf.len));
1205
1206
#if defined(LWS_WITH_LATENCY)
1207
    {
1208
      unsigned int ms = (unsigned int)((lws_now_usecs() - _ws_capread_start) / 1000);
1209
      if (ms > 2)
1210
        lws_latency_note(pt, _ws_capread_start, 2000, "wscaprd:%dms", ms);
1211
    }
1212
#endif
1213
1214
0
    switch (ebuf.len) {
1215
0
    case 0:
1216
0
      lwsl_info("%s: zero length read\n",
1217
0
          __func__);
1218
0
      return LWS_HPI_RET_PLEASE_CLOSE_ME;
1219
0
    case LWS_SSL_CAPABLE_MORE_SERVICE_READ:
1220
0
    case LWS_SSL_CAPABLE_MORE_SERVICE_WRITE:
1221
0
      lwsl_info("SSL Capable more service\n");
1222
0
      return LWS_HPI_RET_HANDLED;
1223
0
    case LWS_SSL_CAPABLE_ERROR:
1224
0
      lwsl_info("%s: LWS_SSL_CAPABLE_ERROR\n",
1225
0
          __func__);
1226
0
      return LWS_HPI_RET_PLEASE_CLOSE_ME;
1227
0
    }
1228
1229
    /*
1230
     * coverity thinks ssl_capable_read() may read over
1231
     * 2GB.  Dissuade it...
1232
     */
1233
0
    ebuf.len &= 0x7fffffff;
1234
0
  }
1235
1236
0
drain:
1237
1238
  /*
1239
   * give any active extensions a chance to munge the buffer
1240
   * before parse.  We pass in a pointer to an lws_tokens struct
1241
   * prepared with the default buffer and content length that's in
1242
   * there.  Rather than rewrite the default buffer, extensions
1243
   * that expect to grow the buffer can adapt .token to
1244
   * point to their own per-connection buffer in the extension
1245
   * user allocation.  By default with no extensions or no
1246
   * extension callback handling, just the normal input buffer is
1247
   * used then so it is efficient.
1248
   */
1249
0
  m = 0;
1250
0
  do {
1251
1252
    /* service incoming data */
1253
    //lws_buflist_describe(&wsi->buflist, wsi, __func__);
1254
0
    if (ebuf.len > 0) {
1255
#if defined(LWS_WITH_LATENCY)
1256
      lws_usec_t _ws_read_start = lws_now_usecs();
1257
#endif
1258
0
#if defined(LWS_ROLE_H2)
1259
0
      if (lwsi_role_h2(wsi) && lwsi_state(wsi) != LRS_BODY &&
1260
0
          lwsi_state(wsi) != LRS_DISCARD_BODY)
1261
0
        n = lws_read_h2(wsi, ebuf.token,
1262
0
               (unsigned int)ebuf.len);
1263
0
      else
1264
0
#endif
1265
0
        n = lws_read_h1(wsi, ebuf.token,
1266
0
               (unsigned int)ebuf.len);
1267
1268
#if defined(LWS_WITH_LATENCY)
1269
      {
1270
        unsigned int ms = (unsigned int)((lws_now_usecs() - _ws_read_start) / 1000);
1271
        if (ms > 2)
1272
          lws_latency_note(pt, _ws_read_start, 2000, "wsrd:%dms", ms);
1273
      }
1274
#endif
1275
1276
0
      if (n < 0) {
1277
        /* we closed wsi */
1278
0
        return LWS_HPI_RET_WSI_ALREADY_DIED;
1279
0
      }
1280
      //lws_buflist_describe(&wsi->buflist, wsi, __func__);
1281
      //lwsl_notice("%s: consuming %d / %d\n", __func__, n, ebuf.len);
1282
0
      if (ebuf.len < 0 ||
1283
0
          lws_buflist_aware_finished_consuming(wsi, &ebuf, n,
1284
0
              buffered, __func__))
1285
0
        return LWS_HPI_RET_PLEASE_CLOSE_ME;
1286
0
    }
1287
1288
0
    ebuf.token = NULL;
1289
0
    ebuf.len = 0;
1290
0
  } while (m);
1291
1292
0
  if (lws_is_flowcontrolled(wsi))
1293
0
    return LWS_HPI_RET_HANDLED;
1294
1295
0
  if (wsi->http.ah
1296
0
#if defined(LWS_WITH_CLIENT)
1297
0
      && !wsi->client_h2_alpn
1298
0
#endif
1299
0
      ) {
1300
0
    lwsl_info("%s: %p: detaching ah\n", __func__, wsi);
1301
0
    lws_header_table_detach(wsi, 0);
1302
0
  }
1303
1304
0
  pending = (unsigned int)lws_ssl_pending(wsi);
1305
1306
0
  if (!pending && lws_buflist_next_segment_len(&wsi->buflist, NULL))
1307
0
    return LWS_HPI_RET_HANDLED;
1308
1309
0
#if defined(LWS_WITH_CLIENT)
1310
0
  if (!pending && (wsi->flags & LCCSCF_PRIORITIZE_READS) &&
1311
0
      lws_buflist_total_len(&wsi->buflist))
1312
0
    pending = 9999999;
1313
0
#endif
1314
1315
0
  if (pending) {
1316
0
    if (lws_is_ws_with_ext(wsi))
1317
0
      pending = pending > wsi->ws->rx_ubuf_alloc ?
1318
0
        wsi->ws->rx_ubuf_alloc : pending;
1319
0
    else
1320
0
      pending = pending > wsi->a.context->pt_serv_buf_size ?
1321
0
        wsi->a.context->pt_serv_buf_size : pending;
1322
0
    if (--sanity) {
1323
#if !defined(LWS_WITHOUT_EXTENSIONS)
1324
      while (wsi->ws->rx_draining_ext) {
1325
        // RX Extension needs to be drained before next read
1326
        if (lws_ws_rx_sm(wsi, ALREADY_PROCESSED_IGNORE_CHAR, 0) ==
1327
              LWS_HPI_RET_PLEASE_CLOSE_ME)
1328
          return LWS_HPI_RET_PLEASE_CLOSE_ME;
1329
      }
1330
#endif
1331
0
    } else {
1332
0
      static lws_log_ratelimit_t rl = { 0, 0 };
1333
      /*
1334
       * Something has gone wrong, we are spinning...
1335
       * let's bail on this connection
1336
       */
1337
0
      lwsl_ratelimit_err(&rl, 1 * LWS_US_PER_SEC,
1338
0
             "ws %s: dropping connection due to sanity loop limit\n",
1339
0
             lws_wsi_tag(wsi));
1340
0
      return LWS_HPI_RET_PLEASE_CLOSE_ME;
1341
0
    }
1342
0
  }
1343
0
  } while (pending);
1344
1345
0
  if (buffered && /* were draining, now nothing left */
1346
0
      !lws_buflist_next_segment_len(&wsi->buflist, NULL)) {
1347
0
    lwsl_info("%s: %p flow buf: drained\n", __func__, wsi);
1348
    /* having drained the rxflow buffer, can rearm POLLIN */
1349
#if !defined(LWS_WITH_SERVER)
1350
    n =
1351
#endif
1352
0
    __lws_rx_flow_control(wsi);
1353
    /* n ignored, needed for NO_SERVER case */
1354
0
  }
1355
1356
  /* n = 0 */
1357
0
  return LWS_HPI_RET_HANDLED;
1358
0
}
1359
1360
1361
lws_handling_result_t
1362
rops_handle_POLLOUT_ws(struct lws *wsi)
1363
0
{
1364
0
  int write_type = LWS_WRITE_PONG;
1365
#if !defined(LWS_WITHOUT_EXTENSIONS)
1366
  struct lws_ext_pm_deflate_rx_ebufs pmdrx;
1367
  int ret, m;
1368
#endif
1369
0
  int n;
1370
1371
#if !defined(LWS_WITHOUT_EXTENSIONS)
1372
  lwsl_debug("%s: %s: wsi->ws->tx_draining_ext %d\n", __func__,
1373
      wsi->a.protocol->name, wsi->ws->tx_draining_ext);
1374
#endif
1375
1376
  /* Priority 3: pending control packets (pong or close)
1377
   *
1378
   * 3a: close notification packet requested from close api
1379
   */
1380
1381
0
  if (lwsi_state(wsi) == LRS_WAITING_TO_SEND_CLOSE) {
1382
0
    lwsl_debug("sending close packet\n");
1383
0
    lwsl_hexdump_debug(&wsi->ws->ping_payload_buf[LWS_PRE],
1384
0
           wsi->ws->close_in_ping_buffer_len);
1385
0
    wsi->waiting_to_send_close_frame = 0;
1386
0
    n = lws_write(wsi, &wsi->ws->ping_payload_buf[LWS_PRE],
1387
0
            wsi->ws->close_in_ping_buffer_len,
1388
0
            LWS_WRITE_CLOSE);
1389
0
    if (n >= 0) {
1390
0
      if (wsi->close_needs_ack) {
1391
0
        lwsi_set_state(wsi, LRS_AWAITING_CLOSE_ACK);
1392
0
        lws_set_timeout(wsi, PENDING_TIMEOUT_CLOSE_ACK,
1393
0
            5);
1394
0
        lwsl_debug("sent close, await ack\n");
1395
1396
0
        return LWS_HP_RET_BAIL_OK;
1397
0
      }
1398
0
      wsi->close_needs_ack = 0;
1399
0
      lwsi_set_state(wsi, LRS_RETURNED_CLOSE);
1400
0
    }
1401
1402
0
    return LWS_HP_RET_BAIL_DIE;
1403
0
  }
1404
1405
  /* else, the send failed and we should just hang up */
1406
1407
0
  if ((lwsi_role_ws(wsi) && wsi->ws->pong_pending_flag) ||
1408
0
      (lwsi_state(wsi) == LRS_RETURNED_CLOSE &&
1409
0
       wsi->ws->payload_is_close)) {
1410
1411
0
    if (wsi->ws->payload_is_close)
1412
0
      write_type = LWS_WRITE_CLOSE;
1413
0
    else {
1414
0
      if (wsi->wsistate_pre_close) {
1415
        /* we started close flow, forget pong */
1416
0
        wsi->ws->pong_pending_flag = 0;
1417
0
        return LWS_HP_RET_BAIL_OK;
1418
0
      }
1419
0
      lwsl_info("issuing pong %d on %s\n",
1420
0
          wsi->ws->pong_payload_len, lws_wsi_tag(wsi));
1421
0
    }
1422
1423
0
    n = lws_write(wsi, &wsi->ws->pong_payload_buf[LWS_PRE],
1424
0
            wsi->ws->pong_payload_len, (enum lws_write_protocol)write_type);
1425
0
    if (n < 0)
1426
0
      return LWS_HP_RET_BAIL_DIE;
1427
1428
    /* well he is sent, mark him done */
1429
0
    wsi->ws->pong_pending_flag = 0;
1430
0
    if (wsi->ws->payload_is_close) {
1431
      // assert(0);
1432
      /* oh... a close frame was it... then we are done */
1433
0
      return LWS_HP_RET_BAIL_DIE;
1434
0
    }
1435
1436
    /* otherwise for PING, leave POLLOUT active either way */
1437
0
    return LWS_HP_RET_BAIL_OK;
1438
0
  }
1439
1440
0
  if (!wsi->socket_is_permanently_unusable &&
1441
0
      wsi->ws->send_check_ping) {
1442
1443
0
    lwsl_info("%s: issuing ping on wsi %s: %s %s h2: %d\n", __func__,
1444
0
        lws_wsi_tag(wsi),
1445
0
        wsi->role_ops->name, wsi->a.protocol->name,
1446
0
        wsi->mux_substream);
1447
1448
0
    wsi->ws->send_check_ping = 0;
1449
0
    n = lws_write(wsi, &wsi->ws->ping_payload_buf[LWS_PRE],
1450
0
            8, LWS_WRITE_PING);
1451
0
    if (n < 0)
1452
0
      return LWS_HP_RET_BAIL_DIE;
1453
1454
0
    return LWS_HP_RET_BAIL_OK;
1455
0
  }
1456
1457
  /* Priority 4: if we are closing, not allowed to send more data frags
1458
   *         which means user callback or tx ext flush banned now
1459
   */
1460
0
  if (lwsi_state(wsi) == LRS_RETURNED_CLOSE)
1461
0
    return LWS_HP_RET_USER_SERVICE;
1462
1463
#if !defined(LWS_WITHOUT_EXTENSIONS)
1464
  /* Priority 5: Tx path extension with more to send
1465
   *
1466
   *         These are handled as new fragments each time around
1467
   *         So while we must block new writeable callback to enforce
1468
   *         payload ordering, but since they are always complete
1469
   *         fragments control packets can interleave OK.
1470
   */
1471
  if (wsi->ws->tx_draining_ext) {
1472
    lwsl_ext("SERVICING TX EXT DRAINING\n");
1473
    if (lws_write(wsi, NULL, 0, LWS_WRITE_CONTINUATION) < 0)
1474
      return LWS_HP_RET_BAIL_DIE;
1475
    /* leave POLLOUT active */
1476
    return LWS_HP_RET_BAIL_OK;
1477
  }
1478
1479
  /* Priority 6: extensions
1480
   */
1481
  if (!wsi->ws->extension_data_pending && !wsi->ws->tx_draining_ext) {
1482
    lwsl_ext("%s: !wsi->ws->extension_data_pending\n", __func__);
1483
    return LWS_HP_RET_USER_SERVICE;
1484
  }
1485
1486
  /*
1487
   * Check in on the active extensions, see if they had pending stuff to
1488
   * spill... they need to get the first look-in otherwise sequence will
1489
   * be disordered.
1490
   *
1491
   * coming here with a NULL, zero-length ebuf means just spill pending
1492
   */
1493
1494
  ret = 1;
1495
  if (wsi->role_ops == &role_ops_raw_skt
1496
#if defined(LWS_ROLE_RAW_FILE)
1497
    || wsi->role_ops == &role_ops_raw_file
1498
#endif
1499
      )
1500
    ret = 0;
1501
1502
  while (ret == 1) {
1503
1504
    /* default to nobody has more to spill */
1505
1506
    ret = 0;
1507
    pmdrx.eb_in.token = NULL;
1508
    pmdrx.eb_in.len = 0;
1509
1510
    /* give every extension a chance to spill */
1511
1512
    m = lws_ext_cb_active(wsi, LWS_EXT_CB_PACKET_TX_PRESEND,
1513
              &pmdrx, 0);
1514
    if (m < 0) {
1515
      lwsl_err("ext reports fatal error\n");
1516
      return LWS_HP_RET_BAIL_DIE;
1517
    }
1518
    if (m)
1519
      /*
1520
       * at least one extension told us he has more
1521
       * to spill, so we will go around again after
1522
       */
1523
      ret = 1;
1524
1525
    /* assuming they gave us something to send, send it */
1526
1527
    if (pmdrx.eb_in.len) {
1528
      n = lws_issue_raw(wsi, (unsigned char *)pmdrx.eb_in.token,
1529
          (unsigned int)pmdrx.eb_in.len);
1530
      if (n < 0) {
1531
        lwsl_info("closing from POLLOUT spill\n");
1532
        return LWS_HP_RET_BAIL_DIE;
1533
      }
1534
      /*
1535
       * Keep amount spilled small to minimize chance of this
1536
       */
1537
      if (n != pmdrx.eb_in.len) {
1538
        lwsl_err("Unable to spill ext %d vs %d\n",
1539
            pmdrx.eb_in.len, n);
1540
        return LWS_HP_RET_BAIL_DIE;
1541
      }
1542
    } else
1543
      continue;
1544
1545
    /* no extension has more to spill */
1546
1547
    if (!ret)
1548
      continue;
1549
1550
    /*
1551
     * There's more to spill from an extension, but we just sent
1552
     * something... did that leave the pipe choked?
1553
     */
1554
1555
    if (!lws_send_pipe_choked(wsi))
1556
      /* no we could add more */
1557
      continue;
1558
1559
    lwsl_info("choked in POLLOUT service\n");
1560
1561
    /*
1562
     * Yes, he's choked.  Leave the POLLOUT masked on so we will
1563
     * come back here when he is unchoked.  Don't call the user
1564
     * callback to enforce ordering of spilling, he'll get called
1565
     * when we come back here and there's nothing more to spill.
1566
     */
1567
1568
    return LWS_HP_RET_BAIL_OK;
1569
  }
1570
1571
  wsi->ws->extension_data_pending = 0;
1572
#endif
1573
1574
0
  return LWS_HP_RET_USER_SERVICE;
1575
0
}
1576
1577
static int
1578
rops_service_flag_pending_ws(struct lws_context *context, int tsi)
1579
0
{
1580
#if !defined(LWS_WITHOUT_EXTENSIONS)
1581
  struct lws_context_per_thread *pt = &context->pt[tsi];
1582
  struct lws *wsi;
1583
  int forced = 0;
1584
1585
  /* POLLIN faking (the pt lock is taken by the parent) */
1586
1587
  /*
1588
   * 1) For all guys with already-available ext data to drain, if they are
1589
   * not flowcontrolled, fake their POLLIN status
1590
   */
1591
  wsi = pt->ws.rx_draining_ext_list;
1592
  while (wsi && wsi->position_in_fds_table != LWS_NO_FDS_POS) {
1593
    pt->fds[wsi->position_in_fds_table].revents =
1594
      (short)((short)pt->fds[wsi->position_in_fds_table].revents |
1595
      (short)(pt->fds[wsi->position_in_fds_table].events & LWS_POLLIN));
1596
    if (pt->fds[wsi->position_in_fds_table].revents & LWS_POLLIN)
1597
      forced = 1;
1598
1599
    wsi = wsi->ws->rx_draining_ext_list;
1600
  }
1601
1602
  return forced;
1603
#else
1604
0
  return 0;
1605
0
#endif
1606
0
}
1607
1608
static int
1609
rops_close_via_role_protocol_ws(struct lws *wsi, enum lws_close_status reason)
1610
0
{
1611
0
  if (!wsi->ws)
1612
0
    return 0;
1613
1614
0
  if (!wsi->ws->close_in_ping_buffer_len && /* already a reason */
1615
0
       (reason == LWS_CLOSE_STATUS_NOSTATUS ||
1616
0
        reason == LWS_CLOSE_STATUS_NOSTATUS_CONTEXT_DESTROY))
1617
0
    return 0;
1618
1619
0
  lwsl_debug("%s: sending close indication...\n", __func__);
1620
1621
  /* if no prepared close reason, use 1000 and no aux data */
1622
1623
0
  if (!wsi->ws->close_in_ping_buffer_len) {
1624
0
    wsi->ws->close_in_ping_buffer_len = 2;
1625
0
    wsi->ws->ping_payload_buf[LWS_PRE] = (reason >> 8) & 0xff;
1626
0
    wsi->ws->ping_payload_buf[LWS_PRE + 1] = reason & 0xff;
1627
0
  }
1628
1629
0
  wsi->waiting_to_send_close_frame = 1;
1630
0
  wsi->close_needs_ack = 1;
1631
0
  lwsi_set_state(wsi, LRS_WAITING_TO_SEND_CLOSE);
1632
0
  __lws_set_timeout(wsi, PENDING_TIMEOUT_CLOSE_SEND, 5);
1633
1634
0
  lws_callback_on_writable(wsi);
1635
1636
0
  return 1;
1637
0
}
1638
1639
static int
1640
rops_close_role_ws(struct lws_context_per_thread *pt, struct lws *wsi)
1641
0
{
1642
0
  if (!wsi->ws)
1643
0
    return 0;
1644
1645
#if !defined(LWS_WITHOUT_EXTENSIONS)
1646
1647
  if (wsi->ws->rx_draining_ext) {
1648
    struct lws **w = &pt->ws.rx_draining_ext_list;
1649
1650
    wsi->ws->rx_draining_ext = 0;
1651
    /* remove us from context draining ext list */
1652
    while (*w) {
1653
      if (*w == wsi) {
1654
        *w = wsi->ws->rx_draining_ext_list;
1655
        break;
1656
      }
1657
      w = &((*w)->ws->rx_draining_ext_list);
1658
    }
1659
    wsi->ws->rx_draining_ext_list = NULL;
1660
  }
1661
1662
  if (wsi->ws->tx_draining_ext) {
1663
    struct lws **w = &pt->ws.tx_draining_ext_list;
1664
    lwsl_ext("%s: CLEARING tx_draining_ext\n", __func__);
1665
    wsi->ws->tx_draining_ext = 0;
1666
    /* remove us from context draining ext list */
1667
    while (*w) {
1668
      if (*w == wsi) {
1669
        *w = wsi->ws->tx_draining_ext_list;
1670
        break;
1671
      }
1672
      w = &((*w)->ws->tx_draining_ext_list);
1673
    }
1674
    wsi->ws->tx_draining_ext_list = NULL;
1675
  }
1676
#endif
1677
0
  lws_free_set_NULL(wsi->ws->rx_ubuf);
1678
1679
0
  wsi->ws->pong_payload_len = 0;
1680
0
  wsi->ws->pong_pending_flag = 0;
1681
1682
  /* deallocate any active extension contexts */
1683
1684
0
  if (lws_ext_cb_active(wsi, LWS_EXT_CB_DESTROY, NULL, 0) < 0)
1685
0
    lwsl_warn("extension destruction failed\n");
1686
1687
0
  return 0;
1688
0
}
1689
1690
static int
1691
rops_write_role_protocol_ws(struct lws *wsi, unsigned char *buf, size_t len,
1692
          enum lws_write_protocol *wp)
1693
0
{
1694
#if !defined(LWS_WITHOUT_EXTENSIONS)
1695
  struct lws_context_per_thread *pt = &wsi->a.context->pt[(int)wsi->tsi];
1696
  enum lws_write_protocol wpt;
1697
#endif
1698
0
  struct lws_ext_pm_deflate_rx_ebufs pmdrx;
1699
0
  int masked7 = lwsi_role_client(wsi);
1700
0
  unsigned char is_masked_bit = 0;
1701
0
  unsigned char *dropmask = NULL;
1702
0
  size_t orig_len = len;
1703
0
  int pre = 0, n = 0;
1704
1705
  // lwsl_err("%s: wp 0x%x len %d\n", __func__, *wp, (int)len);
1706
#if !defined(LWS_WITHOUT_EXTENSIONS)
1707
  if (wsi->ws->tx_draining_ext) {
1708
    /* remove us from the list */
1709
    struct lws **w = &pt->ws.tx_draining_ext_list;
1710
1711
    lwsl_ext("%s: CLEARING tx_draining_ext\n", __func__);
1712
    wsi->ws->tx_draining_ext = 0;
1713
    /* remove us from context draining ext list */
1714
    while (*w) {
1715
      if (*w == wsi) {
1716
        *w = wsi->ws->tx_draining_ext_list;
1717
        break;
1718
      }
1719
      w = &((*w)->ws->tx_draining_ext_list);
1720
    }
1721
    wsi->ws->tx_draining_ext_list = NULL;
1722
1723
    wpt = *wp;
1724
    *wp = (wsi->ws->tx_draining_stashed_wp & 0xc0) |
1725
        LWS_WRITE_CONTINUATION;
1726
1727
    /*
1728
     * When we are just flushing (len == 0), we can trust the
1729
     * stashed wp info completely.  Otherwise adjust it to the
1730
     * FIN status of the incoming packet.
1731
     */
1732
1733
    if (!(wpt & LWS_WRITE_NO_FIN) && len)
1734
      *wp &= (enum lws_write_protocol)~LWS_WRITE_NO_FIN;
1735
1736
    lwsl_ext("FORCED draining wp to 0x%02X "
1737
       "(stashed 0x%02X, incoming 0x%02X)\n", *wp,
1738
       wsi->ws->tx_draining_stashed_wp, wpt);
1739
    // assert(0);
1740
  }
1741
#endif
1742
1743
0
  if (((*wp) & 0x1f) == LWS_WRITE_HTTP ||
1744
0
      ((*wp) & 0x1f) == LWS_WRITE_HTTP_FINAL ||
1745
0
      ((*wp) & 0x1f) == LWS_WRITE_HTTP_HEADERS_CONTINUATION ||
1746
0
      ((*wp) & 0x1f) == LWS_WRITE_HTTP_HEADERS)
1747
0
    goto send_raw;
1748
1749
1750
1751
  /* if we are continuing a frame that already had its header done */
1752
1753
0
  if (wsi->ws->inside_frame) {
1754
0
    lwsl_debug("INSIDE FRAME\n");
1755
0
    goto do_more_inside_frame;
1756
0
  }
1757
1758
0
  wsi->ws->clean_buffer = 1;
1759
1760
  /*
1761
   * give a chance to the extensions to modify payload
1762
   * the extension may decide to produce unlimited payload erratically
1763
   * (eg, compression extension), so we require only that if he produces
1764
   * something, it will be a complete fragment of the length known at
1765
   * the time (just the fragment length known), and if he has
1766
   * more we will come back next time he is writeable and allow him to
1767
   * produce more fragments until he's drained.
1768
   *
1769
   * This allows what is sent each time it is writeable to be limited to
1770
   * a size that can be sent without partial sends or blocking, allows
1771
   * interleaving of control frames and other connection service.
1772
   */
1773
1774
0
  pmdrx.eb_in.token = buf;
1775
0
  pmdrx.eb_in.len = (int)len;
1776
1777
  /* for the non-pm-deflate case */
1778
1779
0
  pmdrx.eb_out = pmdrx.eb_in;
1780
1781
0
  switch ((int)*wp) {
1782
0
  case LWS_WRITE_PING:
1783
0
  case LWS_WRITE_PONG:
1784
0
  case LWS_WRITE_CLOSE:
1785
0
    break;
1786
0
  default:
1787
#if !defined(LWS_WITHOUT_EXTENSIONS)
1788
    n = lws_ext_cb_active(wsi, (int)LWS_EXT_CB_PAYLOAD_TX, &pmdrx, (int)*wp);
1789
    if (n < 0)
1790
      return -1;
1791
    lwsl_ext("%s: defl ext ret %d, ext in remaining %d, "
1792
          "out %d compressed (wp 0x%x)\n", __func__, n,
1793
          (int)pmdrx.eb_in.len, (int)pmdrx.eb_out.len, *wp);
1794
1795
    if (n == PMDR_HAS_PENDING) {
1796
      lwsl_ext("%s: HAS PENDING: write drain len %d "
1797
            "(wp 0x%x) SETTING tx_draining_ext "
1798
            "(remaining in %d)\n", __func__,
1799
            (int)pmdrx.eb_out.len, *wp,
1800
            (int)pmdrx.eb_in.len);
1801
      /* extension requires further draining */
1802
      wsi->ws->tx_draining_ext = 1;
1803
      wsi->ws->tx_draining_ext_list =
1804
          pt->ws.tx_draining_ext_list;
1805
      pt->ws.tx_draining_ext_list = wsi;
1806
      /* we must come back to do more */
1807
      lws_callback_on_writable(wsi);
1808
      /*
1809
       * keep a copy of the write type for the overall
1810
       * action that has provoked generation of these
1811
       * fragments, so the last guy can use its FIN state.
1812
       */
1813
      wsi->ws->tx_draining_stashed_wp = (uint8_t)*wp;
1814
      /*
1815
       * Despite what we may have thought, this is definitely
1816
       * NOT the last fragment, because the extension asserted
1817
       * he has more coming.  For example, the extension may
1818
       * be compressing, and has saved up everything until the
1819
       * end, where the output is larger than one chunk.
1820
       *
1821
       * Make sure this intermediate one doesn't actually
1822
       * go out with a FIN.
1823
       */
1824
      *wp |= LWS_WRITE_NO_FIN;
1825
    }
1826
#endif
1827
0
    if (pmdrx.eb_out.len && wsi->ws->stashed_write_pending) {
1828
0
      wsi->ws->stashed_write_pending = 0;
1829
0
      *wp = (unsigned int)(((*wp) & 0xc0) | (unsigned int)wsi->ws->stashed_write_type);
1830
0
    }
1831
0
  }
1832
1833
  /*
1834
   * an extension did something we need to keep... for example, if
1835
   * compression extension, it has already updated its state according
1836
   * to this being issued
1837
   */
1838
0
  if (buf != pmdrx.eb_out.token) {
1839
    /*
1840
     * ext might eat it, but not have anything to issue yet.
1841
     * In that case we have to follow his lead, but stash and
1842
     * replace the write type that was lost here the first time.
1843
     */
1844
0
    if (len && !pmdrx.eb_out.len) {
1845
0
      if (!wsi->ws->stashed_write_pending)
1846
0
        wsi->ws->stashed_write_type =
1847
0
            (char)(*wp) & 0x3f;
1848
0
      wsi->ws->stashed_write_pending = 1;
1849
0
      return (int)len;
1850
0
    }
1851
    /*
1852
     * extension recreated it:
1853
     * need to buffer this if not all sent
1854
     */
1855
0
    wsi->ws->clean_buffer = 0;
1856
0
  }
1857
1858
0
  buf = pmdrx.eb_out.token;
1859
0
  len = (unsigned int)pmdrx.eb_out.len;
1860
1861
0
  if (!buf) {
1862
0
    lwsl_err("null buf (%d)\n", (int)len);
1863
0
    return -1;
1864
0
  }
1865
1866
0
  switch (wsi->ws->ietf_spec_revision) {
1867
0
  case 13:
1868
0
    if (masked7) {
1869
0
      pre += 4;
1870
0
      dropmask = &buf[0 - pre];
1871
0
      is_masked_bit = 0x80;
1872
0
    }
1873
1874
0
    switch ((*wp) & 0xf) {
1875
0
    case LWS_WRITE_TEXT:
1876
0
      n = LWSWSOPC_TEXT_FRAME;
1877
0
      if (wsi->ws->last_valid && !wsi->ws->last_fin) {
1878
0
        lwsl_wsi_err(wsi, "Sending TEXT after previous frame that lacked FIN");
1879
0
        assert(0);
1880
0
      }
1881
0
      wsi->ws->last_valid = 1;
1882
0
      wsi->ws->last_opcode = (uint8_t)n;
1883
0
      wsi->ws->last_fin = !((*wp) & LWS_WRITE_NO_FIN);
1884
0
      break;
1885
0
    case LWS_WRITE_BINARY:
1886
0
      n = LWSWSOPC_BINARY_FRAME;
1887
0
      if (wsi->ws->last_valid && !wsi->ws->last_fin) {
1888
0
        lwsl_wsi_err(wsi, "Sending BINARY after previous frame that lacked FIN");
1889
0
        assert(0);
1890
0
      }
1891
0
      wsi->ws->last_valid = 1;
1892
0
      wsi->ws->last_opcode = (uint8_t)n;
1893
0
      wsi->ws->last_fin = !((*wp) & LWS_WRITE_NO_FIN);
1894
0
      break;
1895
0
    case LWS_WRITE_CONTINUATION:
1896
0
      n = LWSWSOPC_CONTINUATION;
1897
0
      if (wsi->ws->last_valid && wsi->ws->last_fin) {
1898
0
        lwsl_wsi_err(wsi, "Sending CONTINUATION after previous frame that had FIN");
1899
0
        assert(0);
1900
0
      }
1901
0
      if (!wsi->ws->last_valid) {
1902
0
        lwsl_wsi_err(wsi, "Sending CONTINUATION as first frame");
1903
0
        assert(0);
1904
0
      }
1905
0
      wsi->ws->last_valid = 1;
1906
0
      wsi->ws->last_opcode = (uint8_t)n;
1907
0
      wsi->ws->last_fin = !((*wp) & LWS_WRITE_NO_FIN);
1908
0
      break;
1909
1910
0
    case LWS_WRITE_CLOSE:
1911
0
      n = LWSWSOPC_CLOSE;
1912
0
      break;
1913
0
    case LWS_WRITE_PING:
1914
0
      n = LWSWSOPC_PING;
1915
0
      break;
1916
0
    case LWS_WRITE_PONG:
1917
0
      n = LWSWSOPC_PONG;
1918
0
      break;
1919
0
    default:
1920
0
      lwsl_warn("lws_write: unknown write opc / wp\n");
1921
0
      return -1;
1922
0
    }
1923
1924
0
    if (!((*wp) & LWS_WRITE_NO_FIN))
1925
0
      n |= 1 << 7;
1926
1927
0
    if (len < 126) {
1928
0
      pre += 2;
1929
0
      buf[-pre] = (uint8_t)n;
1930
0
      buf[-pre + 1] = (unsigned char)(len | is_masked_bit);
1931
0
    } else {
1932
0
      if (len < 65536) {
1933
0
        pre += 4;
1934
0
        buf[-pre] = (uint8_t)n;
1935
0
        buf[-pre + 1] = (uint8_t)(126 | is_masked_bit);
1936
0
        buf[-pre + 2] = (unsigned char)(len >> 8);
1937
0
        buf[-pre + 3] = (unsigned char)len;
1938
0
      } else {
1939
0
        pre += 10;
1940
0
        buf[-pre] = (uint8_t)n;
1941
0
        buf[-pre + 1] = (uint8_t)(127 | is_masked_bit);
1942
0
#if defined __LP64__
1943
0
          buf[-pre + 2] = (len >> 56) & 0x7f;
1944
0
          buf[-pre + 3] = (uint8_t)(len >> 48);
1945
0
          buf[-pre + 4] = (uint8_t)(len >> 40);
1946
0
          buf[-pre + 5] = (uint8_t)(len >> 32);
1947
#else
1948
          buf[-pre + 2] = 0;
1949
          buf[-pre + 3] = 0;
1950
          buf[-pre + 4] = 0;
1951
          buf[-pre + 5] = 0;
1952
#endif
1953
0
        buf[-pre + 6] = (unsigned char)(len >> 24);
1954
0
        buf[-pre + 7] = (unsigned char)(len >> 16);
1955
0
        buf[-pre + 8] = (unsigned char)(len >> 8);
1956
0
        buf[-pre + 9] = (unsigned char)len;
1957
0
      }
1958
0
    }
1959
0
    break;
1960
0
  }
1961
1962
0
do_more_inside_frame:
1963
1964
  /*
1965
   * Deal with masking if we are in client -> server direction and
1966
   * the wp demands it
1967
   */
1968
1969
0
  if (masked7) {
1970
0
    if (!wsi->ws->inside_frame)
1971
0
      if (lws_0405_frame_mask_generate(wsi)) {
1972
0
        lwsl_err("frame mask generation failed\n");
1973
0
        return -1;
1974
0
      }
1975
1976
    /*
1977
     * in v7, just mask the payload
1978
     */
1979
0
    if (dropmask) { /* never set if already inside frame */
1980
0
      for (n = 4; n < (int)len + 4; n++)
1981
0
        dropmask[n] = dropmask[n] ^ wsi->ws->mask[
1982
0
          (wsi->ws->mask_idx++) & 3];
1983
1984
      /* copy the frame nonce into place */
1985
0
      memcpy(dropmask, wsi->ws->mask, 4);
1986
0
    }
1987
0
  }
1988
1989
0
  if (lwsi_role_h2_ENCAPSULATION(wsi)) {
1990
0
    struct lws *encap = lws_get_network_wsi(wsi);
1991
1992
0
    assert(encap != wsi);
1993
1994
#if !defined(LWS_WITHOUT_EXTENSIONS)
1995
    /*
1996
     * The h1 path fires LWS_EXT_CB_PACKET_TX_PRESEND from
1997
     * lws_issue_raw_ext_access(); this encapsulated path used to
1998
     * bypass it, so permessage-deflate never got to set RSV1 (or
1999
     * fix up the first-frame opcode) on the compressed frame it
2000
     * already produced above -- peers then treated the deflated
2001
     * payload as plain text.  Give active extensions the same
2002
     * look at the assembled frame here.
2003
     */
2004
    {
2005
      struct lws_tokens ebuf;
2006
2007
      ebuf.token = buf - pre;
2008
      ebuf.len = (int)(len + (unsigned int)pre);
2009
2010
      if (lws_ext_cb_active(wsi, LWS_EXT_CB_PACKET_TX_PRESEND,
2011
                &ebuf, 0) < 0)
2012
        return -1;
2013
    }
2014
#endif
2015
2016
0
    n = lws_rops_func_fidx(encap->role_ops,
2017
0
           LWS_ROPS_write_role_protocol).
2018
0
          write_role_protocol(wsi, buf - pre,
2019
0
                  len + (unsigned int)pre, wp);
2020
0
    if (n < 0)
2021
0
      return n;
2022
2023
    /*
2024
     * The lws_write() contract is to report how much of the
2025
     * CALLER's payload was accepted.  len here is the
2026
     * post-extension (eg, permessage-deflate compressed) frame
2027
     * size, which is routinely SMALLER than what the caller
2028
     * passed in -- returning it (as this path used to) makes
2029
     * well-behaved callers conclude the write failed short and
2030
     * kill the connection.  The h1 path returns orig_len for
2031
     * exactly this reason; do the same.
2032
     */
2033
0
    return (int)orig_len;
2034
0
  }
2035
2036
0
  switch ((*wp) & 0x1f) {
2037
0
  case LWS_WRITE_TEXT:
2038
0
  case LWS_WRITE_BINARY:
2039
0
  case LWS_WRITE_CONTINUATION:
2040
0
    if (!wsi->h23_stream_carries_ws) {
2041
2042
      /*
2043
       * give any active extensions a chance to munge the
2044
       * buffer before send.  We pass in a pointer to an
2045
       * lws_tokens struct prepared with the default buffer
2046
       * and content length that's in there.  Rather than
2047
       * rewrite the default buffer, extensions that expect
2048
       * to grow the buffer can adapt .token to point to their
2049
       * own per-connection buffer in the extension user
2050
       * allocation.  By default with no extensions or no
2051
       * extension callback handling, just the normal input
2052
       * buffer is used then so it is efficient.
2053
       *
2054
       * callback returns 1 in case it wants to spill more
2055
       * buffers
2056
       *
2057
       * This takes care of holding the buffer if send is
2058
       * incomplete, ie, if wsi->ws->clean_buffer is 0
2059
       * (meaning an extension meddled with the buffer).  If
2060
       * wsi->ws->clean_buffer is 1, it will instead return
2061
       * to the user code how much OF THE USER BUFFER was
2062
       * consumed.
2063
       */
2064
2065
0
      n = lws_issue_raw_ext_access(wsi, buf - pre, len + (unsigned int)pre);
2066
0
      wsi->ws->inside_frame = 1;
2067
0
      if (n <= 0)
2068
0
        return n;
2069
2070
0
      if (n == (int)len + pre) {
2071
        /* everything in the buffer was handled
2072
         * (or rebuffered...) */
2073
0
        wsi->ws->inside_frame = 0;
2074
0
        return (int)orig_len;
2075
0
      }
2076
2077
      /*
2078
       * it is how many bytes of user buffer got sent... may
2079
       * be < orig_len in which case callback when writable
2080
       * has already been arranged and user code can call
2081
       * lws_write() again with the rest later.
2082
       */
2083
2084
0
      return n - pre;
2085
0
    }
2086
0
    break;
2087
0
  default:
2088
0
    break;
2089
0
  }
2090
2091
0
send_raw:
2092
0
  return lws_issue_raw(wsi, (unsigned char *)buf - pre, len + (unsigned int)pre);
2093
0
}
2094
2095
static int
2096
rops_close_kill_connection_ws(struct lws *wsi, enum lws_close_status reason)
2097
0
{
2098
  /* deal with ws encapsulation in h2 */
2099
0
#if defined(LWS_WITH_HTTP2)
2100
0
  if (wsi->mux_substream && wsi->h23_stream_carries_ws)
2101
0
    return lws_rops_func_fidx(&role_ops_h2,
2102
0
           LWS_ROPS_close_kill_connection).
2103
0
        close_kill_connection(wsi, reason);
2104
2105
0
  return 0;
2106
#else
2107
  return 0;
2108
#endif
2109
0
}
2110
2111
static int
2112
rops_callback_on_writable_ws(struct lws *wsi)
2113
0
{
2114
0
#if defined(LWS_WITH_HTTP2)
2115
0
  if (lwsi_role_h2_ENCAPSULATION(wsi)) {
2116
    /* we know then that it has an h2 parent */
2117
0
    struct lws *enc = lws_rops_func_fidx(&role_ops_h2,
2118
0
                 LWS_ROPS_encapsulation_parent).
2119
0
                 encapsulation_parent(wsi);
2120
2121
0
    assert(enc);
2122
0
    if (!enc)
2123
      /*
2124
       * Mid-teardown: close_kill_connection already unlinked
2125
       * us from the h2 parent (the close callback fires
2126
       * after that).  Nothing can be scheduled any more; on
2127
       * release builds the assert above is compiled out and
2128
       * this used to segfault.
2129
       */
2130
0
      return 1;
2131
0
    if (lws_rops_func_fidx(enc->role_ops,
2132
0
               LWS_ROPS_callback_on_writable).
2133
0
            callback_on_writable(wsi))
2134
0
      return 1;
2135
0
  }
2136
0
#endif
2137
0
  return 0;
2138
0
}
2139
2140
static int
2141
rops_tx_credit_ws(struct lws *wsi, char peer_to_us, int add)
2142
0
{
2143
0
#if defined(LWS_WITH_HTTP2)
2144
  /*
2145
   * ws-over-h2: flow control belongs to the encapsulating h2 stream.
2146
   * Delegate so lws_get_peer_write_allowance() reports the stream's
2147
   * real tx window and so lws_wsi_tx_credit() can grant manual rx
2148
   * credit (LCCSCF_H2_MANUAL_RXFLOW) on a ws-upgraded stream.
2149
   */
2150
0
  if (lwsi_role_h2_ENCAPSULATION(wsi))
2151
0
    return lws_rops_func_fidx(&role_ops_h2, LWS_ROPS_tx_credit).
2152
0
          tx_credit(wsi, peer_to_us, add);
2153
0
#endif
2154
0
  (void)peer_to_us;
2155
0
  (void)add;
2156
2157
0
  return -1; /* no guidance, like the rops being absent */
2158
0
}
2159
2160
static int
2161
rops_init_vhost_ws(struct lws_vhost *vh,
2162
       const struct lws_context_creation_info *info)
2163
0
{
2164
#if !defined(LWS_WITHOUT_EXTENSIONS)
2165
#ifdef LWS_WITH_PLUGINS
2166
  struct lws_plugin *plugin;
2167
  int m;
2168
2169
  if (vh->context->plugin_extension_count) {
2170
2171
    m = 0;
2172
    while (info->extensions && info->extensions[m].callback)
2173
      m++;
2174
2175
    /*
2176
     * give the vhost a unified list of extensions including the
2177
     * ones that came from plugins
2178
     */
2179
    vh->ws.extensions = lws_zalloc(sizeof(struct lws_extension) *
2180
             (unsigned int)(m + vh->context->plugin_extension_count + 1),
2181
             "extensions");
2182
    if (!vh->ws.extensions)
2183
      return 1;
2184
2185
    memcpy((struct lws_extension *)vh->ws.extensions, info->extensions,
2186
           sizeof(struct lws_extension) * (unsigned int)m);
2187
    plugin = vh->context->plugin_list;
2188
    while (plugin) {
2189
      const lws_plugin_protocol_t *plpr =
2190
        (const lws_plugin_protocol_t *)plugin->hdr;
2191
2192
      memcpy((struct lws_extension *)&vh->ws.extensions[m],
2193
        plpr->extensions,
2194
             sizeof(struct lws_extension) *
2195
             (unsigned int)plpr->count_extensions);
2196
      m += plpr->count_extensions;
2197
      plugin = plugin->list;
2198
    }
2199
  } else
2200
#endif
2201
    vh->ws.extensions = info->extensions;
2202
#endif
2203
2204
0
  return 0;
2205
0
}
2206
2207
static int
2208
rops_destroy_vhost_ws(struct lws_vhost *vh)
2209
0
{
2210
#ifdef LWS_WITH_PLUGINS
2211
#if !defined(LWS_WITHOUT_EXTENSIONS)
2212
  if (vh->context->plugin_extension_count)
2213
    lws_free((void *)vh->ws.extensions);
2214
#endif
2215
#endif
2216
2217
0
  return 0;
2218
0
}
2219
2220
#if defined(LWS_WITH_HTTP_PROXY)
2221
static int
2222
ws_destroy_proxy_buf(struct lws_dll2 *d, void *user)
2223
{
2224
  lws_free(d);
2225
2226
  return 0;
2227
}
2228
#endif
2229
2230
static int
2231
rops_destroy_role_ws(struct lws *wsi)
2232
0
{
2233
#if defined(LWS_WITH_HTTP_PROXY)
2234
  lws_dll2_foreach_safe(&wsi->ws->proxy_owner, NULL, ws_destroy_proxy_buf);
2235
#endif
2236
2237
0
  lws_free_set_NULL(wsi->ws);
2238
2239
0
  return 0;
2240
0
}
2241
2242
static int
2243
rops_issue_keepalive_ws(struct lws *wsi, int isvalid)
2244
0
{
2245
0
  uint64_t us;
2246
2247
2248
0
  if (isvalid) {
2249
0
    lwsl_wsi_info(wsi, "confirming validity");
2250
0
    _lws_validity_confirmed_role(wsi);
2251
0
  } else {
2252
0
    us = (uint64_t)lws_now_usecs();
2253
0
    memcpy(&wsi->ws->ping_payload_buf[LWS_PRE], &us, 8);
2254
0
    wsi->ws->send_check_ping = 1;
2255
0
    lwsl_wsi_info(wsi, "requesting send ping on ws");
2256
2257
0
    lws_callback_on_writable(wsi);
2258
0
  }
2259
2260
0
  return 0;
2261
0
}
2262
2263
static const lws_rops_t rops_table_ws[] = {
2264
  /*  1 */ { .init_vhost        = rops_init_vhost_ws },
2265
  /*  2 */ { .destroy_vhost     = rops_destroy_vhost_ws },
2266
  /*  3 */ { .service_flag_pending    = rops_service_flag_pending_ws },
2267
  /*  4 */ { .handle_POLLIN     = rops_handle_POLLIN_ws },
2268
  /*  5 */ { .handle_POLLOUT      = rops_handle_POLLOUT_ws },
2269
  /*  6 */ { .callback_on_writable    = rops_callback_on_writable_ws },
2270
  /*  7 */ { .write_role_protocol     = rops_write_role_protocol_ws },
2271
  /*  8 */ { .close_via_role_protocol = rops_close_via_role_protocol_ws },
2272
  /*  9 */ { .close_role        = rops_close_role_ws },
2273
  /* 10 */ { .close_kill_connection   = rops_close_kill_connection_ws },
2274
  /* 11 */ { .destroy_role      = rops_destroy_role_ws },
2275
  /* 12 */ { .issue_keepalive     = rops_issue_keepalive_ws },
2276
  /* 13 */ { .tx_credit       = rops_tx_credit_ws },
2277
};
2278
2279
const struct lws_role_ops role_ops_ws = {
2280
  /* role name */     "ws",
2281
  /* alpn id */     NULL,
2282
2283
  /* rops_table */    rops_table_ws,
2284
  /* rops_idx */      {
2285
    /* LWS_ROPS_check_upgrades */
2286
    /* LWS_ROPS_pt_init_destroy */    0x00,
2287
    /* LWS_ROPS_init_vhost */
2288
    /* LWS_ROPS_destroy_vhost */      0x12,
2289
    /* LWS_ROPS_service_flag_pending */
2290
    /* LWS_ROPS_handle_POLLIN */      0x34,
2291
    /* LWS_ROPS_handle_POLLOUT */
2292
    /* LWS_ROPS_perform_user_POLLOUT */   0x50,
2293
    /* LWS_ROPS_callback_on_writable */
2294
    /* LWS_ROPS_tx_credit */      0x6d,
2295
    /* LWS_ROPS_write_role_protocol */
2296
    /* LWS_ROPS_encapsulation_parent */   0x70,
2297
    /* LWS_ROPS_alpn_negotiated */
2298
    /* LWS_ROPS_close_via_role_protocol */  0x08,
2299
    /* LWS_ROPS_close_role */
2300
    /* LWS_ROPS_close_kill_connection */    0x9a,
2301
    /* LWS_ROPS_destroy_role */
2302
    /* LWS_ROPS_adoption_bind */      0xb0,
2303
    /* LWS_ROPS_client_bind */
2304
    /* LWS_ROPS_issue_keepalive */    0x0c,
2305
          },
2306
2307
  /* adoption_cb clnt, srv */ { LWS_CALLBACK_SERVER_NEW_CLIENT_INSTANTIATED,
2308
            LWS_CALLBACK_SERVER_NEW_CLIENT_INSTANTIATED },
2309
  /* rx_cb clnt, srv */   { LWS_CALLBACK_CLIENT_RECEIVE,
2310
            LWS_CALLBACK_RECEIVE },
2311
  /* writeable cb clnt, srv */  { LWS_CALLBACK_CLIENT_WRITEABLE,
2312
            LWS_CALLBACK_SERVER_WRITEABLE },
2313
  /* close cb clnt, srv */  { LWS_CALLBACK_CLIENT_CLOSED,
2314
            LWS_CALLBACK_CLOSED },
2315
  /* protocol_bind cb c, srv */ { LWS_CALLBACK_WS_CLIENT_BIND_PROTOCOL,
2316
            LWS_CALLBACK_WS_SERVER_BIND_PROTOCOL },
2317
  /* protocol_unbind cb c, srv */ { LWS_CALLBACK_WS_CLIENT_DROP_PROTOCOL,
2318
            LWS_CALLBACK_WS_SERVER_DROP_PROTOCOL },
2319
  /* file handles */    0
2320
};