/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 | } |