Coverage Report

Created: 2026-04-12 06:57

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libwebsockets/lib/roles/raw-skt/ops-raw-skt.c
Line
Count
Source
1
/*
2
 * libwebsockets - small server side websockets and web server implementation
3
 *
4
 * Copyright (C) 2010 - 2020 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_CLIENT)
28
static int
29
lws_raw_skt_connect(struct lws *wsi)
30
0
{
31
0
  int n;
32
0
#if defined(LWS_WITH_TLS)
33
0
  const char *cce = NULL;
34
0
  char ccebuf[128];
35
36
0
#if !defined(LWS_WITH_SYS_ASYNC_DNS)
37
0
  switch (lws_client_create_tls(wsi, &cce, 1)) {
38
#else
39
  switch (lws_client_create_tls(wsi, &cce, 0)) {
40
#endif
41
0
  case CCTLS_RETURN_ERROR:
42
0
    lws_inform_client_conn_fail(wsi, (void *)cce, strlen(cce));
43
0
    return -1;
44
0
  case CCTLS_RETURN_RETRY:
45
0
    return 0;
46
0
  case CCTLS_RETURN_DONE:
47
0
    break;
48
0
  }
49
50
0
  if (wsi->tls.use_ssl & LCCSCF_USE_SSL) {
51
0
    n = lws_ssl_client_connect2(wsi, ccebuf, sizeof(ccebuf));
52
0
    if (n < 0) {
53
0
      lws_inform_client_conn_fail(wsi, (void *)ccebuf,
54
0
                strlen(ccebuf));
55
56
0
      return -1;
57
0
    }
58
0
    if (n != 1)
59
0
      return 0; /* wait */
60
0
  }
61
0
#endif
62
63
0
  if (!wsi->hdr_parsing_completed) {
64
0
    n = user_callback_handle_rxflow(wsi->a.protocol->callback,
65
0
        wsi, wsi->role_ops->adoption_cb[lwsi_role_server(wsi)],
66
0
        wsi->user_space, NULL, 0);
67
0
    if (n) {
68
0
      lws_inform_client_conn_fail(wsi, (void *)"user", 4);
69
0
      return 1;
70
0
    }
71
0
  }
72
73
0
  lws_set_timeout(wsi, NO_PENDING_TIMEOUT, 0);
74
0
  lwsi_set_state(wsi, LRS_ESTABLISHED);
75
76
0
  return 1; /* success */
77
0
}
78
#endif
79
80
static lws_handling_result_t
81
rops_handle_POLLIN_raw_skt(struct lws_context_per_thread *pt, struct lws *wsi,
82
         struct lws_pollfd *pollfd)
83
0
{
84
#if defined(LWS_WITH_SOCKS5)
85
  const char *cce = NULL;
86
#endif
87
0
  struct lws_tokens ebuf;
88
0
  int n = 0, buffered = 0;
89
#if defined(LWS_WITH_LATENCY)
90
  lws_usec_t _raw_skt_start = lws_now_usecs();
91
#endif
92
93
  /* pending truncated sends have uber priority */
94
95
0
  if (lws_has_buffered_out(wsi)) {
96
0
    if (!(pollfd->revents & LWS_POLLOUT))
97
0
      return LWS_HPI_RET_HANDLED;
98
99
    /* drain the output buflist */
100
0
    if (lws_issue_raw(wsi, NULL, 0) < 0)
101
0
      goto fail;
102
    /*
103
     * we can't afford to allow input processing to send
104
     * something new, so spin around he event loop until
105
     * he doesn't have any partials
106
     */
107
0
    return LWS_HPI_RET_HANDLED;
108
0
  }
109
110
111
0
#if defined(LWS_WITH_SERVER)
112
0
  if (!lwsi_role_client(wsi) &&  lwsi_state(wsi) != LRS_ESTABLISHED) {
113
114
0
    lwsl_wsi_debug(wsi, "wsistate 0x%x\n", (int)wsi->wsistate);
115
116
0
    if (lwsi_state(wsi) != LRS_SSL_INIT)
117
0
      if (lws_server_socket_service_ssl(wsi,
118
0
                LWS_SOCK_INVALID,
119
0
        !!(pollfd->revents & pollfd->events & LWS_POLLIN)))
120
0
        return LWS_HPI_RET_PLEASE_CLOSE_ME;
121
122
0
    return LWS_HPI_RET_HANDLED;
123
0
  }
124
0
#endif
125
126
0
  if ((pollfd->revents & pollfd->events & LWS_POLLIN) &&
127
0
      !(wsi->favoured_pollin &&
128
0
        (pollfd->revents & pollfd->events & LWS_POLLOUT))) {
129
130
0
    lwsl_wsi_debug(wsi, "POLLIN: state 0x%x", lwsi_state(wsi));
131
132
0
    switch (lwsi_state(wsi)) {
133
134
        /* any tunnel has to have been established... */
135
0
    case LRS_SSL_ACK_PENDING:
136
0
      goto nope;
137
        /* we are actually connected */
138
0
    case LRS_WAITING_CONNECT:
139
0
      goto nope;
140
141
0
    case LRS_WAITING_SSL:
142
0
#if defined(LWS_WITH_CLIENT)
143
0
      n = lws_raw_skt_connect(wsi);
144
0
      if (n < 0)
145
0
        goto fail;
146
0
#endif
147
0
      break;
148
149
#if defined(LWS_WITH_SOCKS5)
150
151
    /* SOCKS Greeting Reply */
152
    case LRS_WAITING_SOCKS_GREETING_REPLY:
153
    case LRS_WAITING_SOCKS_AUTH_REPLY:
154
    case LRS_WAITING_SOCKS_CONNECT_REPLY:
155
156
      switch (lws_socks5c_handle_state(wsi, pollfd, &cce)) {
157
      case LW5CHS_RET_RET0:
158
        goto nope;
159
      case LW5CHS_RET_BAIL3:
160
        lws_inform_client_conn_fail(wsi, (void *)cce, strlen(cce));
161
        goto fail;
162
      case LW5CHS_RET_STARTHS:
163
        lwsi_set_state(wsi, LRS_ESTABLISHED);
164
        lws_client_connect_4_established(wsi, NULL, 0);
165
166
        /*
167
         * Now we got the socks5 connection, we need to
168
         * go down the tls path on it now if that's what
169
         * we want
170
         */
171
        goto post_rx;
172
173
      default:
174
        break;
175
      }
176
      goto post_rx;
177
#endif
178
0
    default:
179
0
      ebuf.token = NULL;
180
0
      ebuf.len = (int) wsi->a.protocol->rx_buffer_size;
181
182
0
      buffered = lws_buflist_aware_read(pt, wsi, &ebuf, 1, __func__);
183
0
      switch (ebuf.len) {
184
0
      case 0:
185
0
        if (wsi->unix_skt)
186
0
          break;
187
0
        lwsl_wsi_info(wsi, "read 0 len");
188
0
        wsi->seen_zero_length_recv = 1;
189
0
        if (lws_change_pollfd(wsi, LWS_POLLIN, 0))
190
0
          goto fail;
191
192
        /*
193
         * we need to go to fail here, since it's the only
194
         * chance we get to understand that the socket has
195
         * closed
196
         */
197
        // goto try_pollout;
198
0
        goto fail;
199
200
0
      case LWS_SSL_CAPABLE_ERROR:
201
0
        goto fail;
202
0
      case LWS_SSL_CAPABLE_MORE_SERVICE:
203
0
    case LWS_SSL_CAPABLE_MORE_SERVICE_READ:
204
0
    case LWS_SSL_CAPABLE_MORE_SERVICE_WRITE:
205
0
        goto try_pollout;
206
0
      }
207
208
0
#if defined(LWS_WITH_UDP)
209
0
      if (lws_fi(&wsi->fic, "udp_rx_loss")) {
210
0
        n = ebuf.len;
211
0
        goto post_rx;
212
0
      }
213
0
#endif
214
215
0
      n = user_callback_handle_rxflow(wsi->a.protocol->callback,
216
0
              wsi, LWS_CALLBACK_RAW_RX,
217
0
              wsi->user_space, ebuf.token,
218
0
              (unsigned int)ebuf.len);
219
0
#if defined(LWS_WITH_UDP) || defined(LWS_WITH_SOCKS5)
220
0
post_rx:
221
0
#endif
222
0
      if (n < 0) {
223
0
        lwsl_wsi_info(wsi, "LWS_CALLBACK_RAW_RX_fail");
224
0
        goto fail;
225
0
      }
226
227
0
      if (lws_buflist_aware_finished_consuming(wsi, &ebuf, ebuf.len,
228
0
                 buffered, __func__))
229
0
        return LWS_HPI_RET_PLEASE_CLOSE_ME;
230
231
0
      goto try_pollout;
232
0
    }
233
0
  }
234
0
nope:
235
0
  if (wsi->favoured_pollin &&
236
0
      (pollfd->revents & pollfd->events & LWS_POLLOUT))
237
    /* we balanced the last favouring of pollin */
238
0
    wsi->favoured_pollin = 0;
239
240
0
try_pollout:
241
242
0
  if (!(pollfd->revents & LWS_POLLOUT))
243
0
    return LWS_HPI_RET_HANDLED;
244
245
0
#if defined(LWS_WITH_CLIENT)
246
0
  if (lwsi_state(wsi) == LRS_WAITING_CONNECT) {
247
0
      if (!lws_client_connect_3_connect(wsi, NULL, NULL, 0, NULL))
248
0
    return LWS_HPI_RET_WSI_ALREADY_DIED;
249
250
0
      if (lws_raw_skt_connect(wsi) < 0)
251
0
        goto fail;
252
0
  }
253
0
#endif
254
255
0
  if (lwsi_state(wsi) == LRS_WAITING_SSL)
256
0
    return LWS_HPI_RET_HANDLED;
257
258
  /* one shot */
259
0
  if (lws_change_pollfd(wsi, LWS_POLLOUT, 0))
260
0
    goto fail;
261
262
  /* clear back-to-back write detection */
263
0
  wsi->could_have_pending = 0;
264
265
0
  n = user_callback_handle_rxflow(wsi->a.protocol->callback,
266
0
      wsi, LWS_CALLBACK_RAW_WRITEABLE,
267
0
      wsi->user_space, NULL, 0);
268
0
  if (n < 0) {
269
0
    lwsl_info("writeable_fail\n");
270
0
    goto fail;
271
0
  }
272
273
#if defined(LWS_WITH_LATENCY)
274
    {
275
      unsigned int ms = (unsigned int)((lws_now_usecs() - _raw_skt_start) / 1000);
276
      if (ms > 2)
277
        lws_latency_note(pt, _raw_skt_start, 2000, "rawskt:%dms", ms);
278
    }
279
#endif
280
281
0
  return LWS_HPI_RET_HANDLED;
282
283
0
fail:
284
0
  lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS, "raw svc fail");
285
286
0
  return LWS_HPI_RET_WSI_ALREADY_DIED;
287
0
}
288
289
static int
290
rops_adoption_bind_raw_skt(struct lws *wsi, int type, const char *vh_prot_name)
291
0
{
292
293
  // lwsl_notice("%s: bind type %d\n", __func__, type);
294
295
  /* no http but socket... must be raw skt */
296
0
  if ((type & LWS_ADOPT_HTTP) || !(type & LWS_ADOPT_SOCKET) ||
297
0
      ((type & _LWS_ADOPT_FINISH) && (!(type & LWS_ADOPT_FLAG_UDP))))
298
0
    return 0; /* no match */
299
300
0
#if defined(LWS_WITH_UDP)
301
0
  if ((type & LWS_ADOPT_FLAG_UDP) && !wsi->udp) {
302
    /*
303
     * these can be >128 bytes, so just alloc for UDP
304
     */
305
0
    wsi->udp = lws_malloc(sizeof(*wsi->udp), "udp struct");
306
0
    if (!wsi->udp)
307
0
      return 0;
308
0
    memset(wsi->udp, 0, sizeof(*wsi->udp));
309
0
  }
310
0
#endif
311
312
0
  lws_role_transition(wsi, 0, (type & LWS_ADOPT_ALLOW_SSL) ? LRS_SSL_INIT :
313
0
        LRS_ESTABLISHED, &role_ops_raw_skt);
314
315
0
  if (vh_prot_name)
316
0
    lws_bind_protocol(wsi, wsi->a.protocol, __func__);
317
0
  else
318
    /* this is the only time he will transition */
319
0
    lws_bind_protocol(wsi,
320
0
      &wsi->a.vhost->protocols[wsi->a.vhost->raw_protocol_index],
321
0
      __func__);
322
323
0
  return 1; /* bound */
324
0
}
325
326
#if defined(LWS_WITH_CLIENT)
327
static int
328
rops_client_bind_raw_skt(struct lws *wsi,
329
       const struct lws_client_connect_info *i)
330
0
{
331
0
  if (!i) {
332
333
    /* finalize */
334
335
0
    if (!wsi->user_space && wsi->stash->cis[CIS_METHOD])
336
0
      if (lws_ensure_user_space(wsi))
337
0
        return 1;
338
339
0
    return 0;
340
0
  }
341
342
  /* we are a fallback if nothing else matched */
343
344
0
  if (!i->local_protocol_name ||
345
0
      strcmp(i->local_protocol_name, "raw-proxy"))
346
0
    lws_role_transition(wsi, LWSIFR_CLIENT, LRS_UNCONNECTED,
347
0
          &role_ops_raw_skt);
348
349
0
  return 1; /* matched */
350
0
}
351
#endif
352
353
static const lws_rops_t rops_table_raw_skt[] = {
354
  /*  1 */ { .handle_POLLIN   = rops_handle_POLLIN_raw_skt },
355
  /*  2 */ { .adoption_bind   = rops_adoption_bind_raw_skt },
356
#if defined(LWS_WITH_CLIENT)
357
  /*  3 */ { .client_bind     = rops_client_bind_raw_skt },
358
#endif
359
};
360
361
const struct lws_role_ops role_ops_raw_skt = {
362
  /* role name */     "raw-skt",
363
  /* alpn id */     NULL,
364
365
  /* rops_table */    rops_table_raw_skt,
366
  /* rops_idx */      {
367
    /* LWS_ROPS_check_upgrades */
368
    /* LWS_ROPS_pt_init_destroy */    0x00,
369
    /* LWS_ROPS_init_vhost */
370
    /* LWS_ROPS_destroy_vhost */      0x00,
371
    /* LWS_ROPS_service_flag_pending */
372
    /* LWS_ROPS_handle_POLLIN */      0x01,
373
    /* LWS_ROPS_handle_POLLOUT */
374
    /* LWS_ROPS_perform_user_POLLOUT */   0x00,
375
    /* LWS_ROPS_callback_on_writable */
376
    /* LWS_ROPS_tx_credit */      0x00,
377
    /* LWS_ROPS_write_role_protocol */
378
    /* LWS_ROPS_encapsulation_parent */   0x00,
379
    /* LWS_ROPS_alpn_negotiated */
380
    /* LWS_ROPS_close_via_role_protocol */  0x00,
381
    /* LWS_ROPS_close_role */
382
    /* LWS_ROPS_close_kill_connection */    0x00,
383
    /* LWS_ROPS_destroy_role */
384
#if defined(LWS_WITH_SERVER)
385
    /* LWS_ROPS_adoption_bind */      0x02,
386
#else
387
    /* LWS_ROPS_adoption_bind */      0x00,
388
#endif
389
#if defined(LWS_WITH_CLIENT)
390
    /* LWS_ROPS_client_bind */
391
    /* LWS_ROPS_issue_keepalive */    0x30,
392
#else
393
    /* LWS_ROPS_client_bind */
394
    /* LWS_ROPS_issue_keepalive */    0x00,
395
#endif
396
          },
397
398
  /* adoption_cb clnt, srv */ { LWS_CALLBACK_RAW_CONNECTED,
399
            LWS_CALLBACK_RAW_ADOPT },
400
  /* rx_cb clnt, srv */   { LWS_CALLBACK_RAW_RX,
401
            LWS_CALLBACK_RAW_RX },
402
  /* writeable cb clnt, srv */  { LWS_CALLBACK_RAW_WRITEABLE,
403
            LWS_CALLBACK_RAW_WRITEABLE},
404
  /* close cb clnt, srv */  { LWS_CALLBACK_RAW_CLOSE,
405
            LWS_CALLBACK_RAW_CLOSE },
406
  /* protocol_bind cb c, srv */ { LWS_CALLBACK_RAW_SKT_BIND_PROTOCOL,
407
            LWS_CALLBACK_RAW_SKT_BIND_PROTOCOL },
408
  /* protocol_unbind cb c, srv */ { LWS_CALLBACK_RAW_SKT_DROP_PROTOCOL,
409
            LWS_CALLBACK_RAW_SKT_DROP_PROTOCOL },
410
  /* file_handle */   0,
411
};