blob: cad68976935361c70a98d3016295d40d6c7ccb59 [file] [log] [blame]
Andy Greenb429d482013-01-16 12:21:29 +08001/*
2 * libwebsockets - small server side websockets and web server implementation
3 *
Andy Green27e770b2014-03-23 11:21:51 +08004 * Copyright (C) 2010-2014 Andy Green <andy@warmcat.com>
Andy Greenb429d482013-01-16 12:21:29 +08005 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation:
9 * version 2.1 of the License.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19 * MA 02110-1301 USA
20 */
21
22#include "private-libwebsockets.h"
23
Andy Greenb429d482013-01-16 12:21:29 +080024static int
25libwebsocket_0405_frame_mask_generate(struct libwebsocket *wsi)
26{
Andy Greenb429d482013-01-16 12:21:29 +080027 int n;
28
29 /* fetch the per-frame nonce */
30
31 n = libwebsockets_get_random(wsi->protocol->owning_server,
Andy Greenb5b23192013-02-11 17:13:32 +080032 wsi->u.ws.frame_masking_nonce_04, 4);
Andy Greenb429d482013-01-16 12:21:29 +080033 if (n != 4) {
34 lwsl_parser("Unable to read from random device %s %d\n",
35 SYSTEM_RANDOM_FILEPATH, n);
36 return 1;
37 }
38
39 /* start masking from first byte of masking key buffer */
Andy Green623a98d2013-01-21 11:04:23 +080040 wsi->u.ws.frame_mask_index = 0;
Andy Greenb429d482013-01-16 12:21:29 +080041
Andy Greenb429d482013-01-16 12:21:29 +080042 return 0;
43}
44
Andy Greencf3590e2013-01-16 14:35:27 +080045#ifdef _DEBUG
Andy Greenb429d482013-01-16 12:21:29 +080046
Peter Pentchev9a4fef72013-03-30 09:52:21 +080047LWS_VISIBLE void lwsl_hexdump(void *vbuf, size_t len)
Andy Greenb429d482013-01-16 12:21:29 +080048{
49 int n;
50 int m;
51 int start;
Andy Greencf3590e2013-01-16 14:35:27 +080052 unsigned char *buf = (unsigned char *)vbuf;
53 char line[80];
54 char *p;
Andy Greenb429d482013-01-16 12:21:29 +080055
56 lwsl_parser("\n");
57
58 for (n = 0; n < len;) {
59 start = n;
Andy Greencf3590e2013-01-16 14:35:27 +080060 p = line;
Andy Greenb429d482013-01-16 12:21:29 +080061
Andy Greencf3590e2013-01-16 14:35:27 +080062 p += sprintf(p, "%04X: ", start);
Andy Greenb429d482013-01-16 12:21:29 +080063
64 for (m = 0; m < 16 && n < len; m++)
Andy Greencf3590e2013-01-16 14:35:27 +080065 p += sprintf(p, "%02X ", buf[n++]);
Andy Greenb429d482013-01-16 12:21:29 +080066 while (m++ < 16)
Andy Greencf3590e2013-01-16 14:35:27 +080067 p += sprintf(p, " ");
Andy Greenb429d482013-01-16 12:21:29 +080068
Andy Greencf3590e2013-01-16 14:35:27 +080069 p += sprintf(p, " ");
Andy Greenb429d482013-01-16 12:21:29 +080070
71 for (m = 0; m < 16 && (start + m) < len; m++) {
Andy Green3182ece2013-01-20 17:08:31 +080072 if (buf[start + m] >= ' ' && buf[start + m] < 127)
Andy Greencf3590e2013-01-16 14:35:27 +080073 *p++ = buf[start + m];
Andy Greenb429d482013-01-16 12:21:29 +080074 else
Andy Greencf3590e2013-01-16 14:35:27 +080075 *p++ = '.';
Andy Greenb429d482013-01-16 12:21:29 +080076 }
77 while (m++ < 16)
Andy Greencf3590e2013-01-16 14:35:27 +080078 *p++ = ' ';
Andy Greenb429d482013-01-16 12:21:29 +080079
Andy Greencf3590e2013-01-16 14:35:27 +080080 *p++ = '\n';
81 *p = '\0';
Andy Green3182ece2013-01-20 17:08:31 +080082 lwsl_debug("%s", line);
Andy Greenb429d482013-01-16 12:21:29 +080083 }
84 lwsl_debug("\n");
85}
86
Andy Greencf3590e2013-01-16 14:35:27 +080087#endif
88
Andy Greenfc7c5e42013-02-23 10:50:10 +080089/*
Andy Green1f4267b2013-10-17 08:09:19 +080090 * notice this returns number of bytes consumed, or -1
Andy Greenfc7c5e42013-02-23 10:50:10 +080091 */
92
Andy Greenb429d482013-01-16 12:21:29 +080093int lws_issue_raw(struct libwebsocket *wsi, unsigned char *buf, size_t len)
94{
Andy Greene000a702013-01-29 12:37:35 +080095 struct libwebsocket_context *context = wsi->protocol->owning_server;
Andy Greenb429d482013-01-16 12:21:29 +080096 int n;
mroszko793e7c02013-12-10 21:15:00 +080097 size_t real_len = len;
98
Andy Green3182ece2013-01-20 17:08:31 +080099#ifndef LWS_NO_EXTENSIONS
Andy Greenb429d482013-01-16 12:21:29 +0800100 int m;
Andy Green2764eba2013-12-09 14:16:17 +0800101
Andy Greene254d952014-03-23 11:41:15 +0800102 if (wsi->truncated_send_len && (buf < wsi->truncated_send_malloc ||
Andy Green27e770b2014-03-23 11:21:51 +0800103 buf > (wsi->truncated_send_malloc +
104 wsi->truncated_send_len +
105 wsi->truncated_send_offset))) {
106 lwsl_err("****** %x Sending new, pending truncated ...\n", wsi);
Andy Green2764eba2013-12-09 14:16:17 +0800107 assert(0);
108 }
Andy Greenb429d482013-01-16 12:21:29 +0800109
110 /*
111 * one of the extensions is carrying our data itself? Like mux?
112 */
113
114 for (n = 0; n < wsi->count_active_extensions; n++) {
115 /*
116 * there can only be active extensions after handshake completed
117 * so we can rely on protocol being set already in here
118 */
119 m = wsi->active_extensions[n]->callback(
120 wsi->protocol->owning_server,
121 wsi->active_extensions[n], wsi,
122 LWS_EXT_CALLBACK_PACKET_TX_DO_SEND,
123 wsi->active_extensions_user[n], &buf, len);
124 if (m < 0) {
125 lwsl_ext("Extension reports fatal error\n");
126 return -1;
127 }
128 if (m) /* handled */ {
129/* lwsl_ext("ext sent it\n"); */
Andy Green1f4267b2013-10-17 08:09:19 +0800130 n = m;
131 goto handle_truncated_send;
Andy Greenb429d482013-01-16 12:21:29 +0800132 }
133 }
Andy Green3182ece2013-01-20 17:08:31 +0800134#endif
Andy Green1f4267b2013-10-17 08:09:19 +0800135 if (wsi->sock < 0)
136 lwsl_warn("** error invalid sock but expected to send\n");
Andy Greenb429d482013-01-16 12:21:29 +0800137
138 /*
139 * nope, send it on the socket directly
140 */
141
142#if 0
143 lwsl_debug(" TX: ");
Andy Green0303db42013-01-17 14:46:43 +0800144 lws_hexdump(buf, len);
Andy Greenb429d482013-01-16 12:21:29 +0800145#endif
146
Andy Green2764eba2013-12-09 14:16:17 +0800147#if 0
148 /* test partial send support by forcing multiple sends on everything */
149 len = len / 2;
150 if (!len)
151 len = 1;
152#endif
153
Andy Greene000a702013-01-29 12:37:35 +0800154 lws_latency_pre(context, wsi);
Andy Greenb429d482013-01-16 12:21:29 +0800155#ifdef LWS_OPENSSL_SUPPORT
156 if (wsi->ssl) {
157 n = SSL_write(wsi->ssl, buf, len);
Andy Greene000a702013-01-29 12:37:35 +0800158 lws_latency(context, wsi, "SSL_write lws_issue_raw", n, n >= 0);
Andy Greenb429d482013-01-16 12:21:29 +0800159 if (n < 0) {
Andy Green28b12ad2014-03-23 12:02:52 +0800160 n = SSL_get_error(wsi->ssl, n);
161 if (n == SSL_ERROR_WANT_READ ||
162 n == SSL_ERROR_WANT_WRITE) {
Andy Green2764eba2013-12-09 14:16:17 +0800163 n = 0;
164 goto handle_truncated_send;
Andy Green28b12ad2014-03-23 12:02:52 +0800165
Andy Green2764eba2013-12-09 14:16:17 +0800166 }
Andy Greenb429d482013-01-16 12:21:29 +0800167 lwsl_debug("ERROR writing to socket\n");
168 return -1;
169 }
170 } else {
171#endif
172 n = send(wsi->sock, buf, len, MSG_NOSIGNAL);
Andy Greene000a702013-01-29 12:37:35 +0800173 lws_latency(context, wsi, "send lws_issue_raw", n, n == len);
Andy Greenfc7c5e42013-02-23 10:50:10 +0800174 if (n < 0) {
Patrick Gansterer2dbd8372014-02-28 12:37:52 +0100175 if (LWS_ERRNO == LWS_EAGAIN || LWS_ERRNO == LWS_EINTR) {
Andy Green2764eba2013-12-09 14:16:17 +0800176 n = 0;
177 goto handle_truncated_send;
178 }
Andy Greenb5b23192013-02-11 17:13:32 +0800179 lwsl_debug("ERROR writing len %d to skt %d\n", len, n);
Andy Greenb429d482013-01-16 12:21:29 +0800180 return -1;
181 }
182#ifdef LWS_OPENSSL_SUPPORT
183 }
184#endif
Andy Green1f4267b2013-10-17 08:09:19 +0800185
186handle_truncated_send:
187
188 /*
189 * already handling a truncated send?
190 */
Andy Greene254d952014-03-23 11:41:15 +0800191 if (wsi->truncated_send_len) {
Andy Green27e770b2014-03-23 11:21:51 +0800192 lwsl_info("***** %x partial send moved on by %d (vs %d)\n",
193 wsi, n, real_len);
Andy Green2764eba2013-12-09 14:16:17 +0800194 wsi->truncated_send_offset += n;
195 wsi->truncated_send_len -= n;
Andy Green1f4267b2013-10-17 08:09:19 +0800196
Andy Green2764eba2013-12-09 14:16:17 +0800197 if (!wsi->truncated_send_len) {
198 lwsl_info("***** %x partial send completed\n", wsi);
Andy Greene254d952014-03-23 11:41:15 +0800199 /* done with it, but don't free it */
Andy Green2764eba2013-12-09 14:16:17 +0800200 n = real_len;
Andy Green1f4267b2013-10-17 08:09:19 +0800201 } else
202 libwebsocket_callback_on_writable(
203 wsi->protocol->owning_server, wsi);
204
205 return n;
206 }
207
Andy Green2764eba2013-12-09 14:16:17 +0800208 if (n < real_len) {
Andy Green0c0bf4a2013-10-18 19:23:06 +0800209 if (wsi->u.ws.clean_buffer)
Andy Green1f4267b2013-10-17 08:09:19 +0800210 /*
211 * This buffer unaffected by extension rewriting.
212 * It means the user code is expected to deal with
213 * partial sends. (lws knows the header was already
214 * sent, so on next send will just resume sending
215 * payload)
216 */
Andy Green0c0bf4a2013-10-18 19:23:06 +0800217 return n;
Andy Green1f4267b2013-10-17 08:09:19 +0800218
219 /*
220 * Newly truncated send. Buffer the remainder (it will get
221 * first priority next time the socket is writable)
222 */
Andy Green27e770b2014-03-23 11:21:51 +0800223 lwsl_info("***** %x new partial sent %d from %d total\n",
224 wsi, n, real_len);
Andy Green1f4267b2013-10-17 08:09:19 +0800225
Andy Greene254d952014-03-23 11:41:15 +0800226 /*
227 * - if we still have a suitable malloc lying around, use it
228 * - or, if too small, reallocate it
229 * - or, if no buffer, create it
230 */
231 if (!wsi->truncated_send_malloc ||
232 real_len - n > wsi->truncated_send_allocation) {
233 if (wsi->truncated_send_malloc)
234 free(wsi->truncated_send_malloc);
Andy Green1f4267b2013-10-17 08:09:19 +0800235
Andy Greene254d952014-03-23 11:41:15 +0800236 wsi->truncated_send_allocation = real_len - n;
237 wsi->truncated_send_malloc = malloc(real_len - n);
238 if (!wsi->truncated_send_malloc) {
239 lwsl_err(
240 "truncated send: unable to malloc %d\n",
241 real_len - n);
242 return -1;
243 }
244 }
Andy Green2764eba2013-12-09 14:16:17 +0800245 wsi->truncated_send_offset = 0;
246 wsi->truncated_send_len = real_len - n;
247 memcpy(wsi->truncated_send_malloc, buf + n, real_len - n);
Andy Green1f4267b2013-10-17 08:09:19 +0800248
249 libwebsocket_callback_on_writable(
250 wsi->protocol->owning_server, wsi);
251
Andy Green2764eba2013-12-09 14:16:17 +0800252 return real_len;
Andy Green1f4267b2013-10-17 08:09:19 +0800253 }
254
Andy Greenfc7c5e42013-02-23 10:50:10 +0800255 return n;
Andy Greenb429d482013-01-16 12:21:29 +0800256}
257
Andy Green3182ece2013-01-20 17:08:31 +0800258#ifdef LWS_NO_EXTENSIONS
259int
260lws_issue_raw_ext_access(struct libwebsocket *wsi,
261 unsigned char *buf, size_t len)
262{
263 return lws_issue_raw(wsi, buf, len);
264}
265#else
Andy Greenb429d482013-01-16 12:21:29 +0800266int
267lws_issue_raw_ext_access(struct libwebsocket *wsi,
268 unsigned char *buf, size_t len)
269{
270 int ret;
271 struct lws_tokens eff_buf;
272 int m;
273 int n;
274
275 eff_buf.token = (char *)buf;
276 eff_buf.token_len = len;
277
278 /*
279 * while we have original buf to spill ourselves, or extensions report
280 * more in their pipeline
281 */
282
283 ret = 1;
284 while (ret == 1) {
285
286 /* default to nobody has more to spill */
287
288 ret = 0;
289
290 /* show every extension the new incoming data */
291
292 for (n = 0; n < wsi->count_active_extensions; n++) {
293 m = wsi->active_extensions[n]->callback(
294 wsi->protocol->owning_server,
295 wsi->active_extensions[n], wsi,
296 LWS_EXT_CALLBACK_PACKET_TX_PRESEND,
297 wsi->active_extensions_user[n], &eff_buf, 0);
298 if (m < 0) {
299 lwsl_ext("Extension: fatal error\n");
300 return -1;
301 }
302 if (m)
303 /*
304 * at least one extension told us he has more
305 * to spill, so we will go around again after
306 */
307 ret = 1;
308 }
309
Andy Green1f4267b2013-10-17 08:09:19 +0800310 if ((char *)buf != eff_buf.token)
Andy Green27e770b2014-03-23 11:21:51 +0800311 /*
312 * extension recreated it:
313 * need to buffer this if not all sent
314 */
315 wsi->u.ws.clean_buffer = 0;
Andy Green1f4267b2013-10-17 08:09:19 +0800316
Andy Greenb429d482013-01-16 12:21:29 +0800317 /* assuming they left us something to send, send it */
318
Andy Greenfc7c5e42013-02-23 10:50:10 +0800319 if (eff_buf.token_len) {
320 n = lws_issue_raw(wsi, (unsigned char *)eff_buf.token,
321 eff_buf.token_len);
322 if (n < 0)
Andy Greenb429d482013-01-16 12:21:29 +0800323 return -1;
Andy Greenfc7c5e42013-02-23 10:50:10 +0800324
Andy Green1f4267b2013-10-17 08:09:19 +0800325 /* always either sent it all or privately buffered */
Andy Greenfc7c5e42013-02-23 10:50:10 +0800326 }
Andy Greenb429d482013-01-16 12:21:29 +0800327
328 lwsl_parser("written %d bytes to client\n", eff_buf.token_len);
329
Andy Green1f4267b2013-10-17 08:09:19 +0800330 /* no extension has more to spill? Then we can go */
Andy Greenb429d482013-01-16 12:21:29 +0800331
332 if (!ret)
333 break;
334
335 /* we used up what we had */
336
337 eff_buf.token = NULL;
338 eff_buf.token_len = 0;
339
340 /*
341 * Did that leave the pipe choked?
Andy Green1f4267b2013-10-17 08:09:19 +0800342 * Or we had to hold on to some of it?
Andy Greenb429d482013-01-16 12:21:29 +0800343 */
344
Andy Green1f4267b2013-10-17 08:09:19 +0800345 if (!lws_send_pipe_choked(wsi) &&
Andy Greene254d952014-03-23 11:41:15 +0800346 !wsi->truncated_send_len)
Andy Green1f4267b2013-10-17 08:09:19 +0800347 /* no we could add more, lets's do that */
Andy Greenb429d482013-01-16 12:21:29 +0800348 continue;
349
350 lwsl_debug("choked\n");
351
352 /*
353 * Yes, he's choked. Don't spill the rest now get a callback
354 * when he is ready to send and take care of it there
355 */
356 libwebsocket_callback_on_writable(
357 wsi->protocol->owning_server, wsi);
358 wsi->extension_data_pending = 1;
359 ret = 0;
360 }
361
Andy Greenfc7c5e42013-02-23 10:50:10 +0800362 return len;
Andy Greenb429d482013-01-16 12:21:29 +0800363}
Andy Green3182ece2013-01-20 17:08:31 +0800364#endif
Andy Greenb429d482013-01-16 12:21:29 +0800365
366/**
367 * libwebsocket_write() - Apply protocol then write data to client
368 * @wsi: Websocket instance (available from user callback)
369 * @buf: The data to send. For data being sent on a websocket
370 * connection (ie, not default http), this buffer MUST have
371 * LWS_SEND_BUFFER_PRE_PADDING bytes valid BEFORE the pointer
372 * and an additional LWS_SEND_BUFFER_POST_PADDING bytes valid
373 * in the buffer after (buf + len). This is so the protocol
374 * header and trailer data can be added in-situ.
375 * @len: Count of the data bytes in the payload starting from buf
376 * @protocol: Use LWS_WRITE_HTTP to reply to an http connection, and one
377 * of LWS_WRITE_BINARY or LWS_WRITE_TEXT to send appropriate
378 * data on a websockets connection. Remember to allow the extra
379 * bytes before and after buf if LWS_WRITE_BINARY or LWS_WRITE_TEXT
380 * are used.
381 *
382 * This function provides the way to issue data back to the client
383 * for both http and websocket protocols.
384 *
385 * In the case of sending using websocket protocol, be sure to allocate
386 * valid storage before and after buf as explained above. This scheme
387 * allows maximum efficiency of sending data and protocol in a single
388 * packet while not burdening the user code with any protocol knowledge.
Andy Greenfc7c5e42013-02-23 10:50:10 +0800389 *
390 * Return may be -1 for a fatal error needing connection close, or a
391 * positive number reflecting the amount of bytes actually sent. This
392 * can be less than the requested number of bytes due to OS memory
393 * pressure at any given time.
Andy Greenb429d482013-01-16 12:21:29 +0800394 */
395
Peter Pentchev9a4fef72013-03-30 09:52:21 +0800396LWS_VISIBLE int libwebsocket_write(struct libwebsocket *wsi, unsigned char *buf,
Andy Greenb429d482013-01-16 12:21:29 +0800397 size_t len, enum libwebsocket_write_protocol protocol)
398{
399 int n;
400 int pre = 0;
401 int post = 0;
Andy Green5738c0e2013-01-21 09:53:35 +0800402 int masked7 = wsi->mode == LWS_CONNMODE_WS_CLIENT;
Andy Greenb429d482013-01-16 12:21:29 +0800403 unsigned char *dropmask = NULL;
404 unsigned char is_masked_bit = 0;
Andy Greenfc7c5e42013-02-23 10:50:10 +0800405 size_t orig_len = len;
Andy Green3182ece2013-01-20 17:08:31 +0800406#ifndef LWS_NO_EXTENSIONS
Andy Greenb429d482013-01-16 12:21:29 +0800407 struct lws_tokens eff_buf;
408 int m;
Andy Green3182ece2013-01-20 17:08:31 +0800409#endif
Andy Greenb429d482013-01-16 12:21:29 +0800410
Andy Green1f4267b2013-10-17 08:09:19 +0800411 if (len == 0 && protocol != LWS_WRITE_CLOSE &&
412 protocol != LWS_WRITE_PING && protocol != LWS_WRITE_PONG) {
Andy Greenb429d482013-01-16 12:21:29 +0800413 lwsl_warn("zero length libwebsocket_write attempt\n");
414 return 0;
415 }
416
417 if (protocol == LWS_WRITE_HTTP)
418 goto send_raw;
419
420 /* websocket protocol, either binary or text */
421
422 if (wsi->state != WSI_STATE_ESTABLISHED)
423 return -1;
424
Andy Green1f4267b2013-10-17 08:09:19 +0800425 /* if we are continuing a frame that already had its header done */
426
427 if (wsi->u.ws.inside_frame)
428 goto do_more_inside_frame;
429
430 /* if he wants all partials buffered, never have a clean_buffer */
431 wsi->u.ws.clean_buffer = !wsi->protocol->no_buffer_all_partial_tx;
432
Andy Green3182ece2013-01-20 17:08:31 +0800433#ifndef LWS_NO_EXTENSIONS
Andy Green1f4267b2013-10-17 08:09:19 +0800434 /*
435 * give a chance to the extensions to modify payload
436 * pre-TX mangling is not allowed to truncate
437 */
Andy Greenb429d482013-01-16 12:21:29 +0800438 eff_buf.token = (char *)buf;
439 eff_buf.token_len = len;
440
Andy Green0303db42013-01-17 14:46:43 +0800441 switch (protocol) {
442 case LWS_WRITE_PING:
443 case LWS_WRITE_PONG:
444 case LWS_WRITE_CLOSE:
445 break;
446 default:
Andy Greenf7248f82013-01-16 14:35:12 +0800447
448 for (n = 0; n < wsi->count_active_extensions; n++) {
449 m = wsi->active_extensions[n]->callback(
450 wsi->protocol->owning_server,
451 wsi->active_extensions[n], wsi,
452 LWS_EXT_CALLBACK_PAYLOAD_TX,
453 wsi->active_extensions_user[n], &eff_buf, 0);
454 if (m < 0)
455 return -1;
456 }
Andy Greenb429d482013-01-16 12:21:29 +0800457 }
458
Andy Green1f4267b2013-10-17 08:09:19 +0800459 /*
460 * an extension did something we need to keep... for example, if
461 * compression extension, it has already updated its state according
462 * to this being issued
463 */
464 if ((char *)buf != eff_buf.token)
Andy Green27e770b2014-03-23 11:21:51 +0800465 /*
466 * extension recreated it:
467 * need to buffer this if not all sent
468 */
469 wsi->u.ws.clean_buffer = 0;
Andy Green1f4267b2013-10-17 08:09:19 +0800470
Andy Greenb429d482013-01-16 12:21:29 +0800471 buf = (unsigned char *)eff_buf.token;
472 len = eff_buf.token_len;
Andy Green3182ece2013-01-20 17:08:31 +0800473#endif
Andy Greenb429d482013-01-16 12:21:29 +0800474
475 switch (wsi->ietf_spec_revision) {
Andy Greenb429d482013-01-16 12:21:29 +0800476 case 13:
Andy Green1f4267b2013-10-17 08:09:19 +0800477
Andy Greenb429d482013-01-16 12:21:29 +0800478 if (masked7) {
479 pre += 4;
480 dropmask = &buf[0 - pre];
481 is_masked_bit = 0x80;
482 }
Andy Green5738c0e2013-01-21 09:53:35 +0800483
Andy Greenb429d482013-01-16 12:21:29 +0800484 switch (protocol & 0xf) {
485 case LWS_WRITE_TEXT:
Andy Green5738c0e2013-01-21 09:53:35 +0800486 n = LWS_WS_OPCODE_07__TEXT_FRAME;
Andy Greenb429d482013-01-16 12:21:29 +0800487 break;
488 case LWS_WRITE_BINARY:
Andy Green5738c0e2013-01-21 09:53:35 +0800489 n = LWS_WS_OPCODE_07__BINARY_FRAME;
Andy Greenb429d482013-01-16 12:21:29 +0800490 break;
491 case LWS_WRITE_CONTINUATION:
Andy Green5738c0e2013-01-21 09:53:35 +0800492 n = LWS_WS_OPCODE_07__CONTINUATION;
Andy Greenb429d482013-01-16 12:21:29 +0800493 break;
494
495 case LWS_WRITE_CLOSE:
Andy Green5738c0e2013-01-21 09:53:35 +0800496 n = LWS_WS_OPCODE_07__CLOSE;
Andy Greenb429d482013-01-16 12:21:29 +0800497
498 /*
Andy Green5738c0e2013-01-21 09:53:35 +0800499 * 06+ has a 2-byte status code in network order
500 * we can do this because we demand post-buf
Andy Greenb429d482013-01-16 12:21:29 +0800501 */
502
Andy Green623a98d2013-01-21 11:04:23 +0800503 if (wsi->u.ws.close_reason) {
Andy Green5738c0e2013-01-21 09:53:35 +0800504 /* reason codes count as data bytes */
505 buf -= 2;
Andy Green623a98d2013-01-21 11:04:23 +0800506 buf[0] = wsi->u.ws.close_reason >> 8;
507 buf[1] = wsi->u.ws.close_reason;
Andy Green5738c0e2013-01-21 09:53:35 +0800508 len += 2;
Andy Greenb429d482013-01-16 12:21:29 +0800509 }
510 break;
511 case LWS_WRITE_PING:
Andy Green5738c0e2013-01-21 09:53:35 +0800512 n = LWS_WS_OPCODE_07__PING;
Andy Greenb429d482013-01-16 12:21:29 +0800513 break;
514 case LWS_WRITE_PONG:
Andy Green5738c0e2013-01-21 09:53:35 +0800515 n = LWS_WS_OPCODE_07__PONG;
Andy Greenb429d482013-01-16 12:21:29 +0800516 break;
517 default:
Andy Greenb5b23192013-02-11 17:13:32 +0800518 lwsl_warn("lws_write: unknown write opc / protocol\n");
Andy Greenb429d482013-01-16 12:21:29 +0800519 return -1;
520 }
521
522 if (!(protocol & LWS_WRITE_NO_FIN))
523 n |= 1 << 7;
524
525 if (len < 126) {
526 pre += 2;
527 buf[-pre] = n;
528 buf[-pre + 1] = len | is_masked_bit;
529 } else {
530 if (len < 65536) {
531 pre += 4;
532 buf[-pre] = n;
533 buf[-pre + 1] = 126 | is_masked_bit;
534 buf[-pre + 2] = len >> 8;
535 buf[-pre + 3] = len;
536 } else {
537 pre += 10;
538 buf[-pre] = n;
539 buf[-pre + 1] = 127 | is_masked_bit;
540#if defined __LP64__
541 buf[-pre + 2] = (len >> 56) & 0x7f;
542 buf[-pre + 3] = len >> 48;
543 buf[-pre + 4] = len >> 40;
544 buf[-pre + 5] = len >> 32;
545#else
546 buf[-pre + 2] = 0;
547 buf[-pre + 3] = 0;
548 buf[-pre + 4] = 0;
549 buf[-pre + 5] = 0;
550#endif
551 buf[-pre + 6] = len >> 24;
552 buf[-pre + 7] = len >> 16;
553 buf[-pre + 8] = len >> 8;
554 buf[-pre + 9] = len;
555 }
556 }
557 break;
558 }
559
Andy Green1f4267b2013-10-17 08:09:19 +0800560do_more_inside_frame:
561
Andy Greenb429d482013-01-16 12:21:29 +0800562 /*
563 * Deal with masking if we are in client -> server direction and
564 * the protocol demands it
565 */
566
Andy Green5738c0e2013-01-21 09:53:35 +0800567 if (wsi->mode == LWS_CONNMODE_WS_CLIENT) {
Andy Greenb429d482013-01-16 12:21:29 +0800568
Andy Green1f4267b2013-10-17 08:09:19 +0800569 if (!wsi->u.ws.inside_frame)
570 if (libwebsocket_0405_frame_mask_generate(wsi)) {
Andy Green27e770b2014-03-23 11:21:51 +0800571 lwsl_err("frame mask generation failed\n");
Andy Green1f4267b2013-10-17 08:09:19 +0800572 return -1;
573 }
Andy Greenb429d482013-01-16 12:21:29 +0800574
Andy Green5738c0e2013-01-21 09:53:35 +0800575 /*
576 * in v7, just mask the payload
577 */
Nikolay Dimitrova8268e72013-12-21 10:22:17 +0800578 if (dropmask) { /* never set if already inside frame */
579 for (n = 4; n < (int)len + 4; n++)
580 dropmask[n] = dropmask[n] ^
Andy Greenb5b23192013-02-11 17:13:32 +0800581 wsi->u.ws.frame_masking_nonce_04[
582 (wsi->u.ws.frame_mask_index++) & 3];
Andy Green5738c0e2013-01-21 09:53:35 +0800583
Andy Green5738c0e2013-01-21 09:53:35 +0800584 /* copy the frame nonce into place */
Andy Green1f4267b2013-10-17 08:09:19 +0800585 memcpy(dropmask, wsi->u.ws.frame_masking_nonce_04, 4);
Nikolay Dimitrova8268e72013-12-21 10:22:17 +0800586 }
Andy Greenb429d482013-01-16 12:21:29 +0800587 }
588
589send_raw:
590
591#if 0
Andy Green8ea19552014-02-15 16:00:37 +0800592 lwsl_debug("send %ld: ", len + pre + post);
593 lwsl_hexdump(&buf[-pre], len + pre + post);
Andy Greenb429d482013-01-16 12:21:29 +0800594#endif
595
Andy Green0303db42013-01-17 14:46:43 +0800596 switch (protocol) {
597 case LWS_WRITE_CLOSE:
Andy Greenb5b23192013-02-11 17:13:32 +0800598/* lwsl_hexdump(&buf[-pre], len + post); */
Andy Green0303db42013-01-17 14:46:43 +0800599 case LWS_WRITE_HTTP:
600 case LWS_WRITE_PONG:
601 case LWS_WRITE_PING:
Andy Greenfc7c5e42013-02-23 10:50:10 +0800602 return lws_issue_raw(wsi, (unsigned char *)buf - pre,
603 len + pre + post);
Andy Green0303db42013-01-17 14:46:43 +0800604 default:
605 break;
Andy Greenb429d482013-01-16 12:21:29 +0800606 }
607
Andy Green1f4267b2013-10-17 08:09:19 +0800608 wsi->u.ws.inside_frame = 1;
609
Andy Greenb429d482013-01-16 12:21:29 +0800610 /*
611 * give any active extensions a chance to munge the buffer
612 * before send. We pass in a pointer to an lws_tokens struct
613 * prepared with the default buffer and content length that's in
614 * there. Rather than rewrite the default buffer, extensions
615 * that expect to grow the buffer can adapt .token to
616 * point to their own per-connection buffer in the extension
617 * user allocation. By default with no extensions or no
618 * extension callback handling, just the normal input buffer is
619 * used then so it is efficient.
620 *
621 * callback returns 1 in case it wants to spill more buffers
Andy Green1f4267b2013-10-17 08:09:19 +0800622 *
623 * This takes care of holding the buffer if send is incomplete, ie,
624 * if wsi->u.ws.clean_buffer is 0 (meaning an extension meddled with
625 * the buffer). If wsi->u.ws.clean_buffer is 1, it will instead
626 * return to the user code how much OF THE USER BUFFER was consumed.
Andy Greenb429d482013-01-16 12:21:29 +0800627 */
628
Andy Greenfc7c5e42013-02-23 10:50:10 +0800629 n = lws_issue_raw_ext_access(wsi, buf - pre, len + pre + post);
630 if (n < 0)
631 return n;
632
Andy Green1f4267b2013-10-17 08:09:19 +0800633 if (n == len + pre + post) {
634 /* everything in the buffer was handled (or rebuffered...) */
635 wsi->u.ws.inside_frame = 0;
636 return orig_len;
637 }
638
639 /*
640 * it is how many bytes of user buffer got sent... may be < orig_len
641 * in which case callback when writable has already been arranged
642 * and user code can call libwebsocket_write() again with the rest
643 * later.
644 */
645
646 return n - (pre + post);
Andy Greenb429d482013-01-16 12:21:29 +0800647}
648
Peter Pentchev9a4fef72013-03-30 09:52:21 +0800649LWS_VISIBLE int libwebsockets_serve_http_file_fragment(
Andy Greenb5b23192013-02-11 17:13:32 +0800650 struct libwebsocket_context *context, struct libwebsocket *wsi)
Andy Greenb8b247d2013-01-22 07:20:08 +0800651{
Patrick Gansterer81338aa2014-02-27 03:21:50 +0100652#if defined(WIN32) || defined(_WIN32)
653 DWORD n;
654#else
655 int n;
656#endif
657 int m;
Andy Greenb8b247d2013-01-22 07:20:08 +0800658
659 while (!lws_send_pipe_choked(wsi)) {
Andy Green2764eba2013-12-09 14:16:17 +0800660
Andy Greene254d952014-03-23 11:41:15 +0800661 if (wsi->truncated_send_len) {
Andy Green2764eba2013-12-09 14:16:17 +0800662 lws_issue_raw(wsi, wsi->truncated_send_malloc +
663 wsi->truncated_send_offset,
Andy Green27e770b2014-03-23 11:21:51 +0800664 wsi->truncated_send_len);
Andy Green2764eba2013-12-09 14:16:17 +0800665 continue;
666 }
667
668 if (wsi->u.http.filepos == wsi->u.http.filelen)
669 goto all_sent;
670
Patrick Gansterer81338aa2014-02-27 03:21:50 +0100671#if defined(WIN32) || defined(_WIN32)
672 if (!ReadFile(wsi->u.http.fd, context->service_buffer,
Andy Green27e770b2014-03-23 11:21:51 +0800673 sizeof(context->service_buffer), &n, NULL))
Patrick Gansterer81338aa2014-02-27 03:21:50 +0100674 return -1; /* caller will close */
675#else
Andy Greenb5b23192013-02-11 17:13:32 +0800676 n = read(wsi->u.http.fd, context->service_buffer,
677 sizeof(context->service_buffer));
Patrick Gansterer81338aa2014-02-27 03:21:50 +0100678
679 if (n < 0)
680 return -1; /* caller will close */
681#endif
682 if (n) {
Andy Greenfc7c5e42013-02-23 10:50:10 +0800683 m = libwebsocket_write(wsi, context->service_buffer, n,
Andy Greenb5b23192013-02-11 17:13:32 +0800684 LWS_WRITE_HTTP);
Andy Greenfc7c5e42013-02-23 10:50:10 +0800685 if (m < 0)
686 return -1;
687
David Gauchard6c582282013-06-29 10:24:16 +0800688 wsi->u.http.filepos += m;
Patrick Gansterer81338aa2014-02-27 03:21:50 +0100689 if (m != n) {
Andy Greenfc7c5e42013-02-23 10:50:10 +0800690 /* adjust for what was not sent */
Patrick Gansterer81338aa2014-02-27 03:21:50 +0100691#if defined(WIN32) || defined(_WIN32)
Andy Green27e770b2014-03-23 11:21:51 +0800692 SetFilePointer(wsi->u.http.fd, m - n,
693 NULL, FILE_CURRENT);
Patrick Gansterer81338aa2014-02-27 03:21:50 +0100694#else
Andy Greenfc7c5e42013-02-23 10:50:10 +0800695 lseek(wsi->u.http.fd, m - n, SEEK_CUR);
Patrick Gansterer81338aa2014-02-27 03:21:50 +0100696#endif
697 }
Andy Greenb8b247d2013-01-22 07:20:08 +0800698 }
Andy Green2764eba2013-12-09 14:16:17 +0800699all_sent:
Andy Greene254d952014-03-23 11:41:15 +0800700 if (!wsi->truncated_send_len &&
Andy Green2764eba2013-12-09 14:16:17 +0800701 wsi->u.http.filepos == wsi->u.http.filelen) {
Andy Greenb8b247d2013-01-22 07:20:08 +0800702 wsi->state = WSI_STATE_HTTP;
703
704 if (wsi->protocol->callback)
David Gauchard6c582282013-06-29 10:24:16 +0800705 /* ignore callback returned value */
706 user_callback_handle_rxflow(
Andy Greenb5b23192013-02-11 17:13:32 +0800707 wsi->protocol->callback, context, wsi,
708 LWS_CALLBACK_HTTP_FILE_COMPLETION,
709 wsi->user_space, NULL, 0);
David Gauchard6c582282013-06-29 10:24:16 +0800710 return 1; /* >0 indicates completed */
Andy Greenb8b247d2013-01-22 07:20:08 +0800711 }
712 }
713
Andy Green2764eba2013-12-09 14:16:17 +0800714 lwsl_info("choked before able to send whole file (post)\n");
Andy Greenb8b247d2013-01-22 07:20:08 +0800715 libwebsocket_callback_on_writable(context, wsi);
716
David Gauchard6c582282013-06-29 10:24:16 +0800717 return 0; /* indicates further processing must be done */
Andy Greenb8b247d2013-01-22 07:20:08 +0800718}