Coverage Report

Created: 2024-09-08 06:10

/src/libwebsockets/lib/core-net/output.c
Line
Count
Source (jump to first uncovered line)
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
/*
28
 * notice this returns number of bytes consumed, or -1
29
 */
30
int
31
lws_issue_raw(struct lws *wsi, unsigned char *buf, size_t len)
32
0
{
33
0
  struct lws_context *context = lws_get_context(wsi);
34
0
  size_t real_len = len;
35
0
  unsigned int n, m;
36
37
  /*
38
   * If you're looking to dump data being sent down the tls tunnel, see
39
   * lws_ssl_capable_write() in lib/tls/mbedtls/mbedtls-ssl.c or
40
   * lib/tls/openssl/openssl-ssl.c.
41
   *
42
   * There's also a corresponding lws_ssl_capable_read() in those files
43
   * where you can enable a dump of decrypted data as soon as it was
44
   * read.
45
   */
46
47
  /* just ignore sends after we cleared the truncation buffer */
48
0
  if (lwsi_state(wsi) == LRS_FLUSHING_BEFORE_CLOSE &&
49
0
      !lws_has_buffered_out(wsi)
50
#if defined(LWS_WITH_HTTP_STREAM_COMPRESSION)
51
      && !wsi->http.comp_ctx.may_have_more
52
#endif
53
0
      )
54
0
    return (int)len;
55
56
0
  if (buf && lws_has_buffered_out(wsi)) {
57
0
    lwsl_wsi_info(wsi, "** prot: %s, incr buflist_out by %lu",
58
0
           wsi->a.protocol->name, (unsigned long)len);
59
60
    /*
61
     * already buflist ahead of this, add it on the tail of the
62
     * buflist, then ignore it for now and act like we're flushing
63
     * the buflist...
64
     */
65
66
0
    if (lws_buflist_append_segment(&wsi->buflist_out, buf, len))
67
0
      return -1;
68
69
0
    buf = NULL;
70
0
    len = 0;
71
0
  }
72
73
0
  if (wsi->buflist_out) {
74
    /* we have to drain the earliest buflist_out stuff first */
75
76
0
    len = lws_buflist_next_segment_len(&wsi->buflist_out, &buf);
77
0
    real_len = len;
78
79
0
    lwsl_wsi_debug(wsi, "draining %d", (int)len);
80
0
  }
81
82
0
  if (!len || !buf)
83
0
    return 0;
84
85
0
  if (!wsi->mux_substream && !lws_socket_is_valid(wsi->desc.sockfd))
86
0
    lwsl_wsi_err(wsi, "invalid sock");
87
88
  /* limit sending */
89
0
  if (wsi->a.protocol->tx_packet_size)
90
0
    n = (unsigned int)wsi->a.protocol->tx_packet_size;
91
0
  else {
92
0
    n = (unsigned int)wsi->a.protocol->rx_buffer_size;
93
0
    if (!n)
94
0
      n = context->pt_serv_buf_size;
95
0
  }
96
0
  n += LWS_PRE + 4;
97
0
  if (n > len)
98
0
    n = (unsigned int)len;
99
100
  /* nope, send it on the socket directly */
101
102
0
  if (lws_fi(&wsi->fic, "sendfail"))
103
0
    m = (unsigned int)LWS_SSL_CAPABLE_ERROR;
104
0
  else
105
0
    m = (unsigned int)lws_ssl_capable_write(wsi, buf, n);
106
107
0
  lwsl_wsi_info(wsi, "ssl_capable_write (%d) says %d", n, m);
108
109
  /* something got written, it can have been truncated now */
110
0
  wsi->could_have_pending = 1;
111
112
0
  switch ((int)m) {
113
0
  case LWS_SSL_CAPABLE_ERROR:
114
    /* we're going to close, let close know sends aren't possible */
115
0
    wsi->socket_is_permanently_unusable = 1;
116
0
    return -1;
117
0
  case LWS_SSL_CAPABLE_MORE_SERVICE:
118
    /*
119
     * nothing got sent, not fatal.  Retry the whole thing later,
120
     * ie, implying treat it was a truncated send so it gets
121
     * retried
122
     */
123
0
    m = 0;
124
0
    break;
125
0
  }
126
127
0
  if ((int)m < 0)
128
0
    m = 0;
129
130
  /*
131
   * we were sending this from buflist_out?  Then not sending everything
132
   * is a small matter of advancing ourselves only by the amount we did
133
   * send in the buflist.
134
   */
135
0
  if (lws_has_buffered_out(wsi)) {
136
0
    if (m) {
137
0
      lwsl_wsi_info(wsi, "partial adv %d (vs %ld)",
138
0
             m, (long)real_len);
139
0
      lws_buflist_use_segment(&wsi->buflist_out, m);
140
0
    }
141
142
0
    if (!lws_has_buffered_out(wsi)) {
143
0
      lwsl_wsi_info(wsi, "buflist_out flushed");
144
145
0
      m = (unsigned int)real_len;
146
0
      if (lwsi_state(wsi) == LRS_FLUSHING_BEFORE_CLOSE) {
147
0
        lwsl_wsi_info(wsi, "*signalling to close now");
148
0
        return -1; /* retry closing now */
149
0
      }
150
151
0
      if (wsi->close_when_buffered_out_drained) {
152
0
        wsi->close_when_buffered_out_drained = 0;
153
0
        return -1;
154
0
      }
155
156
0
#if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
157
0
#if defined(LWS_WITH_SERVER)
158
0
      if (wsi->http.deferred_transaction_completed) {
159
0
        lwsl_wsi_notice(wsi, "partial completed, doing "
160
0
              "deferred transaction completed");
161
0
        wsi->http.deferred_transaction_completed = 0;
162
0
        return lws_http_transaction_completed(wsi) ?
163
0
              -1 : (int)real_len;
164
0
      }
165
0
#endif
166
0
#endif
167
0
#if defined(LWS_ROLE_WS)
168
      /* Since buflist_out flushed, we're not inside a frame any more */
169
0
      if (wsi->ws)
170
0
        wsi->ws->inside_frame = 0;
171
0
#endif
172
0
    }
173
    /* always callback on writeable */
174
0
    lws_callback_on_writable(wsi);
175
176
0
    return (int)m;
177
0
  }
178
179
#if defined(LWS_WITH_HTTP_STREAM_COMPRESSION)
180
  if (wsi->http.comp_ctx.may_have_more)
181
    lws_callback_on_writable(wsi);
182
#endif
183
184
0
  if (m == real_len)
185
    /* what we just sent went out cleanly */
186
0
    return (int)m;
187
188
  /*
189
   * We were not able to send everything... and we were not sending from
190
   * an existing buflist_out.  So we are starting a fresh buflist_out, by
191
   * buffering the unsent remainder on it.
192
   * (it will get first priority next time the socket is writable).
193
   */
194
0
  lwsl_wsi_debug(wsi, "new partial sent %d from %lu total",
195
0
          m, (unsigned long)real_len);
196
197
0
  if (lws_buflist_append_segment(&wsi->buflist_out, buf + m,
198
0
               real_len - m) < 0)
199
0
    return -1;
200
201
0
#if defined(LWS_WITH_UDP)
202
0
  if (lws_wsi_is_udp(wsi))
203
    /* stash original destination for fulfilling UDP partials */
204
0
    wsi->udp->sa46_pending = wsi->udp->sa46;
205
0
#endif
206
207
  /* since something buffered, force it to get another chance to send */
208
0
  lws_callback_on_writable(wsi);
209
210
0
  return (int)real_len;
211
0
}
212
213
int
214
lws_write(struct lws *wsi, unsigned char *buf, size_t len,
215
    enum lws_write_protocol wp)
216
0
{
217
0
  int m;
218
219
0
  if ((int)len < 0) {
220
0
    lwsl_wsi_err(wsi, "suspicious len int %d, ulong %lu",
221
0
          (int)len, (unsigned long)len);
222
0
    return -1;
223
0
  }
224
225
#ifdef LWS_WITH_ACCESS_LOG
226
  wsi->http.access_log.sent += len;
227
#endif
228
229
0
  assert(wsi->role_ops);
230
231
0
  if (!lws_rops_fidx(wsi->role_ops, LWS_ROPS_write_role_protocol))
232
0
    m = lws_issue_raw(wsi, buf, len);
233
0
  else
234
0
    m = lws_rops_func_fidx(wsi->role_ops, LWS_ROPS_write_role_protocol).
235
0
        write_role_protocol(wsi, buf, len, &wp);
236
237
#if defined(LWS_WITH_SYS_METRICS)
238
  if (wsi->a.vhost)
239
    lws_metric_event(wsi->a.vhost->mt_traffic_tx, (char)
240
         (m < 0 ? METRES_NOGO : METRES_GO), len);
241
#endif
242
243
0
  return m;
244
0
}
245
246
int
247
lws_ssl_capable_read_no_ssl(struct lws *wsi, unsigned char *buf, size_t len)
248
0
{
249
0
  int n = 0, en;
250
251
0
  errno = 0;
252
0
#if defined(LWS_WITH_UDP)
253
0
  if (lws_wsi_is_udp(wsi)) {
254
0
    socklen_t slt = sizeof(wsi->udp->sa46);
255
256
0
    n = (int)recvfrom(wsi->desc.sockfd, (char *)buf,
257
#if defined(WIN32)
258
        (int)
259
#endif
260
0
        len, 0,
261
0
        sa46_sockaddr(&wsi->udp->sa46), &slt);
262
0
  } else
263
0
#endif
264
0
    n = (int)recv(wsi->desc.sockfd, (char *)buf,
265
#if defined(WIN32)
266
        (int)
267
#endif
268
0
        len, 0);
269
0
  en = LWS_ERRNO;
270
0
  if (n >= 0) {
271
272
0
    if (!n && wsi->unix_skt)
273
0
      goto do_err;
274
275
    /*
276
     * See https://libwebsockets.org/
277
     * pipermail/libwebsockets/2019-March/007857.html
278
     */
279
0
    if (!n && !wsi->unix_skt)
280
0
      goto do_err;
281
282
#if defined(LWS_WITH_SYS_METRICS) && defined(LWS_WITH_SERVER)
283
    if (wsi->a.vhost)
284
      lws_metric_event(wsi->a.vhost->mt_traffic_rx,
285
           METRES_GO /* rx */, (unsigned int)n);
286
#endif
287
288
0
    return n;
289
0
  }
290
291
0
  if (en == LWS_EAGAIN ||
292
0
      en == LWS_EWOULDBLOCK ||
293
0
      en == LWS_EINTR)
294
0
    return LWS_SSL_CAPABLE_MORE_SERVICE;
295
296
0
do_err:
297
#if defined(LWS_WITH_SYS_METRICS) && defined(LWS_WITH_SERVER)
298
  if (wsi->a.vhost)
299
    lws_metric_event(wsi->a.vhost->mt_traffic_rx, METRES_NOGO, 0u);
300
#endif
301
302
0
  lwsl_wsi_info(wsi, "error on reading from skt : %d, errno %d", n, en);
303
304
0
  return LWS_SSL_CAPABLE_ERROR;
305
0
}
306
307
int
308
lws_ssl_capable_write_no_ssl(struct lws *wsi, unsigned char *buf, size_t len)
309
0
{
310
0
  int n = 0;
311
#if defined(LWS_PLAT_OPTEE)
312
  ssize_t send(int sockfd, const void *buf, size_t len, int flags);
313
#endif
314
315
0
#if defined(LWS_WITH_UDP)
316
0
  if (lws_wsi_is_udp(wsi)) {
317
318
0
    if (lws_fi(&wsi->fic, "udp_tx_loss")) {
319
      /* pretend it was sent */
320
0
      n = (int)(ssize_t)len;
321
0
      goto post_send;
322
0
    }
323
324
0
    if (lws_has_buffered_out(wsi))
325
0
      n = (int)sendto(wsi->desc.sockfd, (const char *)buf,
326
#if defined(WIN32)
327
        (int)
328
#endif
329
0
           len, 0, sa46_sockaddr(&wsi->udp->sa46_pending),
330
0
           sa46_socklen(&wsi->udp->sa46_pending));
331
0
    else
332
0
      n = (int)sendto(wsi->desc.sockfd, (const char *)buf,
333
#if defined(WIN32)
334
        (int)
335
#endif
336
0
           len, 0, sa46_sockaddr(&wsi->udp->sa46),
337
0
           sa46_socklen(&wsi->udp->sa46));
338
0
  } else
339
0
#endif
340
0
    if (wsi->role_ops->file_handle)
341
0
      n = (int)write((int)(lws_intptr_t)wsi->desc.filefd, buf,
342
#if defined(WIN32)
343
        (int)
344
#endif
345
0
          len);
346
0
    else
347
0
      n = (int)send(wsi->desc.sockfd, (char *)buf,
348
#if defined(WIN32)
349
        (int)
350
#endif
351
0
          len, MSG_NOSIGNAL);
352
//  lwsl_info("%s: sent len %d result %d", __func__, len, n);
353
354
0
#if defined(LWS_WITH_UDP)
355
0
post_send:
356
0
#endif
357
0
  if (n >= 0)
358
0
    return n;
359
360
0
  if (LWS_ERRNO == LWS_EAGAIN ||
361
0
      LWS_ERRNO == LWS_EWOULDBLOCK ||
362
0
      LWS_ERRNO == LWS_EINTR) {
363
0
    if (LWS_ERRNO == LWS_EWOULDBLOCK) {
364
0
      lws_set_blocking_send(wsi);
365
0
    }
366
367
0
    return LWS_SSL_CAPABLE_MORE_SERVICE;
368
0
  }
369
370
0
  lwsl_wsi_debug(wsi, "ERROR writing len %d to skt fd %d err %d / errno %d",
371
0
          (int)(ssize_t)len, wsi->desc.sockfd, n, LWS_ERRNO);
372
373
0
  return LWS_SSL_CAPABLE_ERROR;
374
0
}
375
376
int
377
lws_ssl_pending_no_ssl(struct lws *wsi)
378
0
{
379
0
  (void)wsi;
380
#if defined(LWS_PLAT_FREERTOS)
381
  return 100;
382
#else
383
0
  return 0;
384
0
#endif
385
0
}