23
23
#include "private-libwebsockets.h"
29
#ifdef LWS_BUILTIN_GETIFADDRS
30
#include <getifaddrs.h>
35
#include <sys/socket.h>
39
#ifdef LWS_OPENSSL_SUPPORT
42
libwebsockets_decode_ssl_error(void)
25
int lws_context_init_server(struct lws_context_creation_info *info,
26
struct libwebsocket_context *context)
47
while ((err = ERR_get_error()) != 0) {
48
ERR_error_string_n(err, buf, sizeof(buf));
49
lwsl_err("*** %s\n", buf);
30
struct sockaddr_in sin;
31
socklen_t len = sizeof(sin);
33
struct libwebsocket *wsi;
35
struct sockaddr_in6 serv_addr6;
37
struct sockaddr_in serv_addr4;
40
/* set up our external listening socket we serve on */
42
if (info->port == CONTEXT_PORT_NO_LISTEN)
46
if (LWS_IPV6_ENABLED(context))
47
sockfd = socket(AF_INET6, SOCK_STREAM, 0);
50
sockfd = socket(AF_INET, SOCK_STREAM, 0);
53
lwsl_err("ERROR opening socket\n");
58
* allow us to restart even if old sockets in TIME_WAIT
60
setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR,
61
(const void *)&opt, sizeof(opt));
63
lws_plat_set_socket_options(context, sockfd);
66
if (LWS_IPV6_ENABLED(context)) {
67
v = (struct sockaddr *)&serv_addr6;
68
n = sizeof(struct sockaddr_in6);
69
bzero((char *) &serv_addr6, sizeof(serv_addr6));
70
serv_addr6.sin6_addr = in6addr_any;
71
serv_addr6.sin6_family = AF_INET6;
72
serv_addr6.sin6_port = htons(info->port);
76
v = (struct sockaddr *)&serv_addr4;
77
n = sizeof(serv_addr4);
78
bzero((char *) &serv_addr4, sizeof(serv_addr4));
79
serv_addr4.sin_addr.s_addr = INADDR_ANY;
80
serv_addr4.sin_family = AF_INET;
83
if (interface_to_sa(context, info->iface,
84
(struct sockaddr_in *)v, n) < 0) {
85
lwsl_err("Unable to find interface %s\n",
87
compatible_close(sockfd);
92
serv_addr4.sin_port = htons(info->port);
95
n = bind(sockfd, v, n);
97
lwsl_err("ERROR on binding to port %d (%d %d)\n",
98
info->port, n, LWS_ERRNO);
99
compatible_close(sockfd);
103
if (getsockname(sockfd, (struct sockaddr *)&sin, &len) == -1)
104
lwsl_warn("getsockname: %s\n", strerror(LWS_ERRNO));
106
info->port = ntohs(sin.sin_port);
108
context->listen_port = info->port;
110
wsi = (struct libwebsocket *)malloc(sizeof(struct libwebsocket));
112
lwsl_err("Out of mem\n");
113
compatible_close(sockfd);
116
memset(wsi, 0, sizeof(struct libwebsocket));
118
wsi->mode = LWS_CONNMODE_SERVER_LISTENER;
120
insert_wsi_socket_into_fds(context, wsi);
122
context->listen_service_modulo = LWS_LISTEN_SERVICE_MODULO;
123
context->listen_service_count = 0;
124
context->listen_service_fd = sockfd;
126
listen(sockfd, LWS_SOMAXCONN);
127
lwsl_notice(" Listening on port %d\n", info->port);
55
interface_to_sa(const char *ifname, struct sockaddr_in *addr, size_t addrlen)
133
_libwebsocket_rx_flow_control(struct libwebsocket *wsi)
63
struct sockaddr_in *sin;
66
for (ifc = ifr; ifc != NULL; ifc = ifc->ifa_next) {
67
if (strcmp(ifc->ifa_name, ifname))
69
if (ifc->ifa_addr == NULL)
71
sin = (struct sockaddr_in *)ifc->ifa_addr;
72
if (sin->sin_family != AF_INET)
74
memcpy(addr, sin, addrlen);
135
struct libwebsocket_context *context = wsi->protocol->owning_server;
137
/* there is no pending change */
138
if (!(wsi->u.ws.rxflow_change_to & LWS_RXFLOW_PENDING_CHANGE))
141
/* stuff is still buffered, not ready to really accept new input */
142
if (wsi->u.ws.rxflow_buffer) {
143
/* get ourselves called back to deal with stashed buffer */
144
libwebsocket_callback_on_writable(context, wsi);
148
/* pending is cleared, we can change rxflow state */
150
wsi->u.ws.rxflow_change_to &= ~LWS_RXFLOW_PENDING_CHANGE;
152
lwsl_info("rxflow: wsi %p change_to %d\n", wsi,
153
wsi->u.ws.rxflow_change_to & LWS_RXFLOW_ALLOW);
155
/* adjust the pollfd for this wsi */
157
if (wsi->u.ws.rxflow_change_to & LWS_RXFLOW_ALLOW) {
158
if (lws_change_pollfd(wsi, 0, LWS_POLLIN)) {
159
lwsl_info("%s: fail\n", __func__);
163
if (lws_change_pollfd(wsi, LWS_POLLIN, 0))
170
int lws_handshake_server(struct libwebsocket_context *context,
171
struct libwebsocket *wsi, unsigned char **buf, size_t len)
173
struct allocated_headers *ah;
174
char *uri_ptr = NULL;
176
char content_length_str[32];
179
/* LWS_CONNMODE_WS_SERVING */
182
if (libwebsocket_parse(context, wsi, *(*buf)++)) {
183
lwsl_info("libwebsocket_parse failed\n");
187
if (wsi->u.hdr.parser_state != WSI_PARSING_COMPLETE)
190
lwsl_parser("libwebsocket_parse sees parsing complete\n");
192
wsi->mode = LWS_CONNMODE_PRE_WS_SERVING_ACCEPT;
193
libwebsocket_set_timeout(wsi, NO_PENDING_TIMEOUT, 0);
195
/* is this websocket protocol or normal http 1.0? */
197
if (!lws_hdr_total_length(wsi, WSI_TOKEN_UPGRADE) ||
198
!lws_hdr_total_length(wsi, WSI_TOKEN_CONNECTION)) {
200
/* it's not websocket.... shall we accept it as http? */
202
if (!lws_hdr_total_length(wsi, WSI_TOKEN_GET_URI) &&
203
!lws_hdr_total_length(wsi, WSI_TOKEN_POST_URI) &&
204
!lws_hdr_total_length(wsi, WSI_TOKEN_OPTIONS_URI)) {
205
lwsl_warn("Missing URI in HTTP request\n");
209
if (lws_hdr_total_length(wsi, WSI_TOKEN_GET_URI) &&
210
lws_hdr_total_length(wsi, WSI_TOKEN_POST_URI)) {
211
lwsl_warn("GET and POST methods?\n");
215
if (libwebsocket_ensure_user_space(wsi))
218
if (lws_hdr_total_length(wsi, WSI_TOKEN_GET_URI)) {
219
uri_ptr = lws_hdr_simple_ptr(wsi, WSI_TOKEN_GET_URI);
220
uri_len = lws_hdr_total_length(wsi, WSI_TOKEN_GET_URI);
221
lwsl_info("HTTP GET request for '%s'\n",
222
lws_hdr_simple_ptr(wsi, WSI_TOKEN_GET_URI));
225
if (lws_hdr_total_length(wsi, WSI_TOKEN_POST_URI)) {
226
lwsl_info("HTTP POST request for '%s'\n",
227
lws_hdr_simple_ptr(wsi, WSI_TOKEN_POST_URI));
228
uri_ptr = lws_hdr_simple_ptr(wsi, WSI_TOKEN_POST_URI);
229
uri_len = lws_hdr_total_length(wsi, WSI_TOKEN_POST_URI);
231
if (lws_hdr_total_length(wsi, WSI_TOKEN_OPTIONS_URI)) {
232
lwsl_info("HTTP OPTIONS request for '%s'\n",
233
lws_hdr_simple_ptr(wsi, WSI_TOKEN_OPTIONS_URI));
234
uri_ptr = lws_hdr_simple_ptr(wsi, WSI_TOKEN_OPTIONS_URI);
235
uri_len = lws_hdr_total_length(wsi, WSI_TOKEN_OPTIONS_URI);
239
* Hm we still need the headers so the
240
* callback can look at leaders like the URI, but we
241
* need to transition to http union state.... hold a
242
* copy of u.hdr.ah and deallocate afterwards
246
/* union transition */
247
memset(&wsi->u, 0, sizeof(wsi->u));
248
wsi->mode = LWS_CONNMODE_HTTP_SERVING_ACCEPTED;
249
wsi->state = WSI_STATE_HTTP;
250
wsi->u.http.fd = LWS_INVALID_FILE;
252
/* expose it at the same offset as u.hdr */
255
/* HTTP header had a content length? */
257
wsi->u.http.content_length = 0;
258
if (lws_hdr_total_length(wsi, WSI_TOKEN_POST_URI))
259
wsi->u.http.content_length = 100 * 1024 * 1024;
261
if (lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_CONTENT_LENGTH)) {
262
lws_hdr_copy(wsi, content_length_str,
263
sizeof(content_length_str) - 1,
264
WSI_TOKEN_HTTP_CONTENT_LENGTH);
265
wsi->u.http.content_length = atoi(content_length_str);
268
if (wsi->u.http.content_length > 0) {
269
wsi->u.http.body_index = 0;
270
n = wsi->protocol->rx_buffer_size;
272
n = LWS_MAX_SOCKET_IO_BUF;
273
wsi->u.http.post_buffer = malloc(n);
274
if (!wsi->u.http.post_buffer) {
275
lwsl_err("Unable to allocate post buffer\n");
282
if (wsi->protocol->callback)
283
n = wsi->protocol->callback(context, wsi,
284
LWS_CALLBACK_FILTER_HTTP_CONNECTION,
285
wsi->user_space, uri_ptr, uri_len);
289
* if there is content supposed to be coming,
290
* put a timeout on it having arrived
292
libwebsocket_set_timeout(wsi,
293
PENDING_TIMEOUT_HTTP_CONTENT,
296
if (wsi->protocol->callback)
297
n = wsi->protocol->callback(context, wsi,
299
wsi->user_space, uri_ptr, uri_len);
303
/* now drop the header info we kept a pointer to */
306
/* not possible to continue to use past here */
307
wsi->u.http.ah = NULL;
310
lwsl_info("LWS_CALLBACK_HTTP closing\n");
311
return 1; /* struct ah ptr already nuked */
315
* (if callback didn't start sending a file)
316
* deal with anything else as body, whether
317
* there was a content-length or not
320
if (wsi->state != WSI_STATE_HTTP_ISSUING_FILE)
321
wsi->state = WSI_STATE_HTTP_BODY;
322
return 2; /* goto http_postbody; */
326
lwsl_err("NULL protocol at libwebsocket_read\n");
331
* Make sure user side is happy about protocol
334
while (wsi->protocol->callback) {
336
if (!lws_hdr_total_length(wsi, WSI_TOKEN_PROTOCOL)) {
337
if (wsi->protocol->name == NULL)
340
if (wsi->protocol->name && strcmp(
341
lws_hdr_simple_ptr(wsi,
343
wsi->protocol->name) == 0)
349
/* we didn't find a protocol he wanted? */
351
if (wsi->protocol->callback == NULL) {
352
if (lws_hdr_simple_ptr(wsi, WSI_TOKEN_PROTOCOL) ==
354
lwsl_info("no protocol -> prot 0 handler\n");
355
wsi->protocol = &context->protocols[0];
357
lwsl_err("Req protocol %s not supported\n",
358
lws_hdr_simple_ptr(wsi, WSI_TOKEN_PROTOCOL));
363
/* allocate wsi->user storage */
364
if (libwebsocket_ensure_user_space(wsi))
368
* Give the user code a chance to study the request and
369
* have the opportunity to deny it
372
if ((wsi->protocol->callback)(wsi->protocol->owning_server, wsi,
373
LWS_CALLBACK_FILTER_PROTOCOL_CONNECTION,
375
lws_hdr_simple_ptr(wsi, WSI_TOKEN_PROTOCOL), 0)) {
376
lwsl_warn("User code denied connection\n");
382
* Perform the handshake according to the protocol version the
386
switch (wsi->ietf_spec_revision) {
388
lwsl_parser("lws_parse calling handshake_04\n");
389
if (handshake_0405(context, wsi)) {
390
lwsl_info("hs0405 has failed the connection\n");
396
lwsl_warn("Unknown client spec version %d\n",
397
wsi->ietf_spec_revision);
401
/* drop the header info -- no bail_nuke_ah after this */
406
wsi->mode = LWS_CONNMODE_WS_SERVING;
408
/* union transition */
409
memset(&wsi->u, 0, sizeof(wsi->u));
410
wsi->u.ws.rxflow_change_to = LWS_RXFLOW_ALLOW;
413
* create the frame buffer for this connection according to the
414
* size mentioned in the protocol definition. If 0 there, use
415
* a big default for compatibility
418
n = wsi->protocol->rx_buffer_size;
420
n = LWS_MAX_SOCKET_IO_BUF;
421
n += LWS_SEND_BUFFER_PRE_PADDING + LWS_SEND_BUFFER_POST_PADDING;
422
wsi->u.ws.rx_user_buffer = malloc(n);
423
if (!wsi->u.ws.rx_user_buffer) {
424
lwsl_err("Out of Mem allocating rx buffer %d\n", n);
427
lwsl_info("Allocating RX buffer %d\n", n);
429
if (setsockopt(wsi->sock, SOL_SOCKET, SO_SNDBUF, (const char *)&n, sizeof n)) {
430
lwsl_warn("Failed to set SNDBUF to %d", n);
434
lwsl_parser("accepted v%02d connection\n",
435
wsi->ietf_spec_revision);
436
} /* while all chars are handled */
441
/* drop the header info */
83
447
struct libwebsocket *
119
479
new_wsi->user_space = NULL;
120
480
new_wsi->ietf_spec_revision = 0;
483
* outermost create notification for wsi
484
* no user_space because no protocol selection
486
context->protocols[0].callback(context, new_wsi,
487
LWS_CALLBACK_WSI_CREATE, NULL, NULL, 0);
125
492
int lws_server_socket_service(struct libwebsocket_context *context,
126
struct libwebsocket *wsi, struct pollfd *pollfd)
493
struct libwebsocket *wsi, struct libwebsocket_pollfd *pollfd)
128
struct libwebsocket *new_wsi;
495
struct libwebsocket *new_wsi = NULL;
131
498
struct sockaddr_in cli_addr;
134
#ifdef LWS_OPENSSL_SUPPORT
141
502
switch (wsi->mode) {
143
504
case LWS_CONNMODE_HTTP_SERVING:
505
case LWS_CONNMODE_HTTP_SERVING_ACCEPTED:
145
507
/* handle http headers coming in */
509
/* pending truncated sends have uber priority */
511
if (wsi->truncated_send_malloc) {
512
if (pollfd->revents & LWS_POLLOUT)
513
if (lws_issue_raw(wsi, wsi->truncated_send_malloc +
514
wsi->truncated_send_offset,
515
wsi->truncated_send_len) < 0) {
516
lwsl_info("closing from socket service\n");
520
* we can't afford to allow input processing send
521
* something new, so spin around he event loop until
522
* he doesn't have any partials
147
527
/* any incoming data ready? */
149
if (pollfd->revents & POLLIN) {
151
#ifdef LWS_OPENSSL_SUPPORT
153
len = SSL_read(wsi->ssl,
154
context->service_buffer,
155
sizeof(context->service_buffer));
158
len = recv(pollfd->fd,
159
context->service_buffer,
160
sizeof(context->service_buffer), 0);
163
lwsl_debug("Socket read returned %d\n", len);
164
if (errno != EINTR && errno != EAGAIN)
165
libwebsocket_close_and_free_session(
167
LWS_CLOSE_STATUS_NOSTATUS);
529
if (pollfd->revents & LWS_POLLIN) {
530
len = lws_ssl_capable_read(wsi,
531
context->service_buffer,
532
sizeof(context->service_buffer));
171
535
lwsl_info("lws_server_skt_srv: read 0 len\n");
172
536
/* lwsl_info(" state=%d\n", wsi->state); */
173
537
if (!wsi->hdr_parsing_completed)
174
538
free(wsi->u.hdr.ah);
540
case LWS_SSL_CAPABLE_ERROR:
175
541
libwebsocket_close_and_free_session(
176
context, wsi, LWS_CLOSE_STATUS_NOSTATUS);
180
n = libwebsocket_read(context, wsi,
181
context->service_buffer, len);
543
LWS_CLOSE_STATUS_NOSTATUS);
545
case LWS_SSL_CAPABLE_MORE_SERVICE:
549
/* just ignore incoming if waiting for close */
550
if (wsi->state != WSI_STATE_FLUSHING_STORED_SEND_BEFORE_CLOSE) {
552
/* hm this may want to send (via HTTP callback for example) */
554
n = libwebsocket_read(context, wsi,
555
context->service_buffer, len);
560
/* hum he may have used up the writability above */
187
565
/* this handles POLLOUT for http serving fragments */
189
if (!(pollfd->revents & POLLOUT))
567
if (!(pollfd->revents & LWS_POLLOUT))
193
pollfd->events &= ~POLLOUT;
571
if (lws_change_pollfd(wsi, LWS_POLLOUT, 0))
574
lws_libev_io(context, wsi, LWS_EV_STOP | LWS_EV_WRITE);
195
if (wsi->state != WSI_STATE_HTTP_ISSUING_FILE)
576
if (wsi->state != WSI_STATE_HTTP_ISSUING_FILE) {
577
n = user_callback_handle_rxflow(
578
wsi->protocol->callback,
579
wsi->protocol->owning_server,
580
wsi, LWS_CALLBACK_HTTP_WRITEABLE,
585
libwebsocket_close_and_free_session(
586
context, wsi, LWS_CLOSE_STATUS_NOSTATUS);
198
590
/* nonzero for completion or error */
199
591
if (libwebsockets_serve_http_file_fragment(context, wsi))
251
643
new_wsi->sock = accept_fd;
253
#ifdef LWS_OPENSSL_SUPPORT
255
if (!context->use_ssl) {
645
/* the transport is accepted... give him time to negotiate */
646
libwebsocket_set_timeout(new_wsi,
647
PENDING_TIMEOUT_ESTABLISH_WITH_SERVER,
651
* A new connection was accepted. Give the user a chance to
652
* set properties of the newly created wsi. There's no protocol
653
* selected yet so we issue this to protocols[0]
656
(context->protocols[0].callback)(context, new_wsi,
657
LWS_CALLBACK_SERVER_NEW_CLIENT_INSTANTIATED, NULL, NULL, 0);
659
lws_libev_accept(context, new_wsi, accept_fd);
661
if (!LWS_SSL_ENABLED(context)) {
258
662
lwsl_debug("accepted new conn port %u on fd=%d\n",
259
663
ntohs(cli_addr.sin_port), accept_fd);
261
665
insert_wsi_socket_into_fds(context, new_wsi);
263
#ifdef LWS_OPENSSL_SUPPORT
266
new_wsi->ssl = SSL_new(context->ssl_ctx);
267
if (new_wsi->ssl == NULL) {
268
lwsl_err("SSL_new failed: %s\n",
269
ERR_error_string(SSL_get_error(
270
new_wsi->ssl, 0), NULL));
271
libwebsockets_decode_ssl_error();
273
compatible_close(accept_fd);
277
SSL_set_ex_data(new_wsi->ssl,
278
openssl_websocket_private_data_index, context);
280
SSL_set_fd(new_wsi->ssl, accept_fd);
283
CyaSSL_set_using_nonblock(new_wsi->ssl, 1);
285
bio = SSL_get_rbio(new_wsi->ssl);
287
BIO_set_nbio(bio, 1); /* nonblocking */
289
lwsl_notice("NULL rbio\n");
290
bio = SSL_get_wbio(new_wsi->ssl);
292
BIO_set_nbio(bio, 1); /* nonblocking */
294
lwsl_notice("NULL rbio\n");
298
* we are not accepted yet, but we need to enter ourselves
299
* as a live connection. That way we can retry when more
300
* pieces come if we're not sorted yet
304
wsi->mode = LWS_CONNMODE_SSL_ACK_PENDING;
305
insert_wsi_socket_into_fds(context, wsi);
307
libwebsocket_set_timeout(wsi, PENDING_TIMEOUT_SSL_ACCEPT,
310
lwsl_info("inserted SSL accept into fds, trying SSL_accept\n");
314
case LWS_CONNMODE_SSL_ACK_PENDING:
316
pollfd->events &= ~POLLOUT;
318
/* external POLL support via protocol 0 */
319
context->protocols[0].callback(context, wsi,
320
LWS_CALLBACK_CLEAR_MODE_POLL_FD,
321
(void *)(long)wsi->sock, NULL, POLLOUT);
323
lws_latency_pre(context, wsi);
324
n = SSL_accept(wsi->ssl);
325
lws_latency(context, wsi,
326
"SSL_accept LWS_CONNMODE_SSL_ACK_PENDING\n", n, n == 1);
329
m = SSL_get_error(wsi->ssl, n);
330
lwsl_debug("SSL_accept failed %d / %s\n",
331
m, ERR_error_string(m, NULL));
333
if (m == SSL_ERROR_WANT_READ) {
335
wsi->position_in_fds_table].events |= POLLIN;
337
/* external POLL support via protocol 0 */
338
context->protocols[0].callback(context, wsi,
339
LWS_CALLBACK_SET_MODE_POLL_FD,
340
(void *)(long)wsi->sock, NULL, POLLIN);
341
lwsl_info("SSL_ERROR_WANT_READ\n");
344
if (m == SSL_ERROR_WANT_WRITE) {
346
wsi->position_in_fds_table].events |= POLLOUT;
348
/* external POLL support via protocol 0 */
349
context->protocols[0].callback(context, wsi,
350
LWS_CALLBACK_SET_MODE_POLL_FD,
351
(void *)(long)wsi->sock, NULL, POLLOUT);
354
lwsl_debug("SSL_accept failed skt %u: %s\n",
356
ERR_error_string(m, NULL));
357
libwebsocket_close_and_free_session(context, wsi,
358
LWS_CLOSE_STATUS_NOSTATUS);
362
/* OK, we are accepted */
364
libwebsocket_set_timeout(wsi, NO_PENDING_TIMEOUT, 0);
366
wsi->mode = LWS_CONNMODE_HTTP_SERVING;
368
lwsl_debug("accepted new SSL conn\n");
673
if (lws_server_socket_service_ssl(context, &wsi, new_wsi, accept_fd, pollfd))
679
libwebsocket_close_and_free_session(context, wsi,
680
LWS_CLOSE_STATUS_NOSTATUS);
685
static const char *err400[] = {
691
"Method Not Allowed",
693
"Proxy Auth Required",
698
"Precondition Failed",
699
"Request Entity Too Large",
700
"Request URI too Long",
701
"Unsupported Media Type",
702
"Requested Range Not Satisfiable",
706
static const char *err500[] = {
707
"Internal Server Error",
710
"Service Unavailable",
712
"HTTP Version Not Supported"
716
* libwebsockets_return_http_status() - Return simple http status
717
* @context: libwebsockets context
718
* @wsi: Websocket instance (available from user callback)
719
* @code: Status index, eg, 404
720
* @html_body: User-readable HTML description, or NULL
722
* Helper to report HTTP errors back to the client cleanly and
725
LWS_VISIBLE int libwebsockets_return_http_status(
726
struct libwebsocket_context *context, struct libwebsocket *wsi,
727
unsigned int code, const char *html_body)
730
const char *description = "";
735
if (code >= 400 && code < (400 + ARRAY_SIZE(err400)))
736
description = err400[code - 400];
737
if (code >= 500 && code < (500 + ARRAY_SIZE(err500)))
738
description = err500[code - 500];
740
n = sprintf((char *)context->service_buffer,
741
"HTTP/1.0 %u %s\x0d\x0a"
742
"Server: libwebsockets\x0d\x0a"
743
"Content-Type: text/html\x0d\x0a\x0d\x0a"
745
code, description, code, description, html_body);
747
lwsl_info((const char *)context->service_buffer);
749
m = libwebsocket_write(wsi, context->service_buffer, n, LWS_WRITE_HTTP);
755
* libwebsockets_serve_http_file() - Send a file back to the client using http
756
* @context: libwebsockets context
757
* @wsi: Websocket instance (available from user callback)
758
* @file: The file to issue over http
759
* @content_type: The http content type, eg, text/html
760
* @other_headers: NULL or pointer to \0-terminated other header string
762
* This function is intended to be called from the callback in response
763
* to http requests from the client. It allows the callback to issue
764
* local files down the http link in a single step.
766
* Returning <0 indicates error and the wsi should be closed. Returning
767
* >0 indicates the file was completely sent and the wsi should be closed.
768
* ==0 indicates the file transfer is started and needs more service later,
769
* the wsi should be left alone.
772
LWS_VISIBLE int libwebsockets_serve_http_file(
773
struct libwebsocket_context *context,
774
struct libwebsocket *wsi, const char *file,
775
const char *content_type, const char *other_headers)
777
unsigned char *p = context->service_buffer;
781
wsi->u.http.fd = lws_plat_open_file(file, &wsi->u.http.filelen);
783
if (wsi->u.http.fd == LWS_INVALID_FILE) {
784
lwsl_err("Unable to open '%s'\n", file);
785
libwebsockets_return_http_status(context, wsi,
786
HTTP_STATUS_NOT_FOUND, NULL);
790
p += sprintf((char *)p,
791
"HTTP/1.0 200 OK\x0d\x0aServer: libwebsockets\x0d\x0a""Content-Type: %s\x0d\x0a",
794
n = strlen(other_headers);
795
memcpy(p, other_headers, n);
798
p += sprintf((char *)p,
799
"Content-Length: %lu\x0d\x0a\x0d\x0a", wsi->u.http.filelen);
801
ret = libwebsocket_write(wsi, context->service_buffer,
802
p - context->service_buffer, LWS_WRITE_HTTP);
803
if (ret != (p - context->service_buffer)) {
804
lwsl_err("_write returned %d from %d\n", ret, (p - context->service_buffer));
808
wsi->u.http.filepos = 0;
809
wsi->state = WSI_STATE_HTTP_ISSUING_FILE;
811
return libwebsockets_serve_http_file_fragment(context, wsi);
815
int libwebsocket_interpret_incoming_packet(struct libwebsocket *wsi,
816
unsigned char *buf, size_t len)
822
lwsl_parser("received %d byte packet\n", (int)len);
823
lwsl_hexdump(buf, len);
826
/* let the rx protocol state machine have as much as it needs */
830
* we were accepting input but now we stopped doing so
832
if (!(wsi->u.ws.rxflow_change_to & LWS_RXFLOW_ALLOW)) {
833
/* his RX is flowcontrolled, don't send remaining now */
834
if (!wsi->u.ws.rxflow_buffer) {
835
/* a new rxflow, buffer it and warn caller */
836
lwsl_info("new rxflow input buffer len %d\n",
838
wsi->u.ws.rxflow_buffer =
839
(unsigned char *)malloc(len - n);
840
wsi->u.ws.rxflow_len = len - n;
841
wsi->u.ws.rxflow_pos = 0;
842
memcpy(wsi->u.ws.rxflow_buffer,
845
/* rxflow while we were spilling prev rxflow */
846
lwsl_info("stalling in existing rxflow buf\n");
851
/* account for what we're using in rxflow buffer */
852
if (wsi->u.ws.rxflow_buffer)
853
wsi->u.ws.rxflow_pos++;
855
/* process the byte */
856
m = libwebsocket_rx_sm(wsi, buf[n++]);
865
lws_server_get_canonical_hostname(struct libwebsocket_context *context,
866
struct lws_context_creation_info *info)
868
if (info->options & LWS_SERVER_OPTION_SKIP_SERVER_CANONICAL_NAME)
871
/* find canonical hostname */
872
gethostname((char *)context->canonical_hostname,
873
sizeof(context->canonical_hostname) - 1);
875
lwsl_notice(" canonical_hostname = %s\n", context->canonical_hostname);