2 * libwebsockets - small server side websockets and web server implementation
4 * Copyright (C) 2010-2013 Andy Green <andy@warmcat.com>
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.
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.
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,
23 #include "private-libwebsockets.h"
25 #if defined(WIN32) || defined(_WIN32)
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)
47 while ((err = ERR_get_error()) != 0) {
48 ERR_error_string_n(err, buf, sizeof(buf));
49 lwsl_err("*** %lu %s\n", err, buf);
55 interface_to_sa(const char *ifname, struct sockaddr_in *addr, size_t addrlen)
58 #if defined(WIN32) || defined(_WIN32)
63 struct sockaddr_in *sin;
66 for (ifc = ifr; ifc != NULL && rc; ifc = ifc->ifa_next) {
67 if (ifc->ifa_addr == NULL)
69 lwsl_info(" interface %s vs %s\n", ifc->ifa_name, ifname);
70 if (strcmp(ifc->ifa_name, ifname))
72 sin = (struct sockaddr_in *)ifc->ifa_addr;
73 if (sin->sin_family != AF_INET)
75 memcpy(addr, sin, addrlen);
85 libwebsocket_create_new_server_wsi(struct libwebsocket_context *context)
87 struct libwebsocket *new_wsi;
89 new_wsi = (struct libwebsocket *)malloc(sizeof(struct libwebsocket));
90 if (new_wsi == NULL) {
91 lwsl_err("Out of memory for new connection\n");
95 memset(new_wsi, 0, sizeof(struct libwebsocket));
96 #ifndef LWS_NO_EXTENSIONS
97 new_wsi->count_active_extensions = 0;
99 new_wsi->pending_timeout = NO_PENDING_TIMEOUT;
101 /* intialize the instance struct */
103 new_wsi->state = WSI_STATE_HTTP;
104 new_wsi->mode = LWS_CONNMODE_HTTP_SERVING;
105 new_wsi->hdr_parsing_completed = 0;
107 if (lws_allocate_header_table(new_wsi)) {
113 * these can only be set once the protocol is known
114 * we set an unestablished connection's protocol pointer
115 * to the start of the supported list, so it can look
116 * for matching ones during the handshake
118 new_wsi->protocol = context->protocols;
119 new_wsi->user_space = NULL;
120 new_wsi->ietf_spec_revision = 0;
125 int lws_server_socket_service(struct libwebsocket_context *context,
126 struct libwebsocket *wsi, struct pollfd *pollfd)
128 struct libwebsocket *new_wsi;
131 struct sockaddr_in cli_addr;
134 #ifdef LWS_OPENSSL_SUPPORT
143 case LWS_CONNMODE_HTTP_SERVING:
144 case LWS_CONNMODE_HTTP_SERVING_ACCEPTED:
146 /* handle http headers coming in */
148 /* pending truncated sends have uber priority */
150 if (wsi->truncated_send_malloc) {
151 if (pollfd->revents & POLLOUT)
152 lws_issue_raw(wsi, wsi->truncated_send_malloc +
153 wsi->truncated_send_offset,
154 wsi->truncated_send_len);
156 * we can't afford to allow input processing send
157 * something new, so spin around he event loop until
158 * he doesn't have any partials
163 /* any incoming data ready? */
165 if (pollfd->revents & POLLIN) {
167 #ifdef LWS_OPENSSL_SUPPORT
169 len = SSL_read(wsi->ssl,
170 context->service_buffer,
171 sizeof(context->service_buffer));
174 len = recv(pollfd->fd,
175 context->service_buffer,
176 sizeof(context->service_buffer), 0);
179 lwsl_debug("Socket read returned %d\n", len);
180 if (errno != EINTR && errno != EAGAIN)
181 libwebsocket_close_and_free_session(
183 LWS_CLOSE_STATUS_NOSTATUS);
187 lwsl_info("lws_server_skt_srv: read 0 len\n");
188 /* lwsl_info(" state=%d\n", wsi->state); */
189 if (!wsi->hdr_parsing_completed)
191 libwebsocket_close_and_free_session(
192 context, wsi, LWS_CLOSE_STATUS_NOSTATUS);
196 /* hm this may want to send (via HTTP callback for example) */
198 n = libwebsocket_read(context, wsi,
199 context->service_buffer, len);
204 /* hum he may have used up the writability above */
209 /* this handles POLLOUT for http serving fragments */
211 if (!(pollfd->revents & POLLOUT))
215 pollfd->events &= ~POLLOUT;
217 if (wsi->state != WSI_STATE_HTTP_ISSUING_FILE) {
218 n = user_callback_handle_rxflow(
219 wsi->protocol->callback,
220 wsi->protocol->owning_server,
221 wsi, LWS_CALLBACK_HTTP_WRITEABLE,
226 libwebsocket_close_and_free_session(
227 context, wsi, LWS_CLOSE_STATUS_NOSTATUS);
231 /* nonzero for completion or error */
232 if (libwebsockets_serve_http_file_fragment(context, wsi))
233 libwebsocket_close_and_free_session(context, wsi,
234 LWS_CLOSE_STATUS_NOSTATUS);
237 case LWS_CONNMODE_SERVER_LISTENER:
239 /* pollin means a client has connected to us then */
241 if (!(pollfd->revents & POLLIN))
244 /* listen socket got an unencrypted connection... */
246 clilen = sizeof(cli_addr);
247 lws_latency_pre(context, wsi);
248 accept_fd = accept(pollfd->fd, (struct sockaddr *)&cli_addr,
250 lws_latency(context, wsi,
251 "unencrypted accept LWS_CONNMODE_SERVER_LISTENER",
252 accept_fd, accept_fd >= 0);
254 if (errno == EAGAIN || errno == EWOULDBLOCK) {
255 lwsl_debug("accept asks to try again\n");
258 lwsl_warn("ERROR on accept: %s\n", strerror(errno));
262 lws_set_socket_options(context, accept_fd);
265 * look at who we connected to and give user code a chance
266 * to reject based on client IP. There's no protocol selected
267 * yet so we issue this to protocols[0]
270 if ((context->protocols[0].callback)(context, wsi,
271 LWS_CALLBACK_FILTER_NETWORK_CONNECTION,
272 NULL, (void *)(long)accept_fd, 0)) {
273 lwsl_debug("Callback denied network connection\n");
274 compatible_close(accept_fd);
278 new_wsi = libwebsocket_create_new_server_wsi(context);
279 if (new_wsi == NULL) {
280 compatible_close(accept_fd);
284 new_wsi->sock = accept_fd;
286 #ifdef LWS_OPENSSL_SUPPORT
288 if (!context->use_ssl) {
291 lwsl_debug("accepted new conn port %u on fd=%d\n",
292 ntohs(cli_addr.sin_port), accept_fd);
294 insert_wsi_socket_into_fds(context, new_wsi);
296 #ifdef LWS_OPENSSL_SUPPORT
299 new_wsi->ssl = SSL_new(context->ssl_ctx);
300 if (new_wsi->ssl == NULL) {
301 lwsl_err("SSL_new failed: %s\n",
302 ERR_error_string(SSL_get_error(
303 new_wsi->ssl, 0), NULL));
304 libwebsockets_decode_ssl_error();
306 compatible_close(accept_fd);
310 SSL_set_ex_data(new_wsi->ssl,
311 openssl_websocket_private_data_index, context);
313 SSL_set_fd(new_wsi->ssl, accept_fd);
316 CyaSSL_set_using_nonblock(new_wsi->ssl, 1);
318 bio = SSL_get_rbio(new_wsi->ssl);
320 BIO_set_nbio(bio, 1); /* nonblocking */
322 lwsl_notice("NULL rbio\n");
323 bio = SSL_get_wbio(new_wsi->ssl);
325 BIO_set_nbio(bio, 1); /* nonblocking */
327 lwsl_notice("NULL rbio\n");
331 * we are not accepted yet, but we need to enter ourselves
332 * as a live connection. That way we can retry when more
333 * pieces come if we're not sorted yet
337 wsi->mode = LWS_CONNMODE_SSL_ACK_PENDING;
338 insert_wsi_socket_into_fds(context, wsi);
340 libwebsocket_set_timeout(wsi, PENDING_TIMEOUT_SSL_ACCEPT,
343 lwsl_info("inserted SSL accept into fds, trying SSL_accept\n");
347 case LWS_CONNMODE_SSL_ACK_PENDING:
349 pollfd->events &= ~POLLOUT;
351 /* external POLL support via protocol 0 */
352 context->protocols[0].callback(context, wsi,
353 LWS_CALLBACK_CLEAR_MODE_POLL_FD,
354 wsi->user_space, (void *)(long)wsi->sock, POLLOUT);
356 lws_latency_pre(context, wsi);
358 n = recv(wsi->sock, context->service_buffer,
359 sizeof(context->service_buffer), MSG_PEEK);
362 * optionally allow non-SSL connect on SSL listening socket
363 * This is disabled by default, if enabled it goes around any
364 * SSL-level access control (eg, client-side certs) so leave
365 * it disabled unless you know it's not a problem for you
368 if (context->allow_non_ssl_on_ssl_port && n >= 1 &&
369 context->service_buffer[0] >= ' ') {
371 * TLS content-type for Handshake is 0x16
372 * TLS content-type for ChangeCipherSpec Record is 0x14
374 * A non-ssl session will start with the HTTP method in
375 * ASCII. If we see it's not a legit SSL handshake
376 * kill the SSL for this connection and try to handle
377 * as a HTTP connection upgrade directly.
380 SSL_shutdown(wsi->ssl);
386 /* normal SSL connection processing path */
388 n = SSL_accept(wsi->ssl);
389 lws_latency(context, wsi,
390 "SSL_accept LWS_CONNMODE_SSL_ACK_PENDING\n", n, n == 1);
393 m = SSL_get_error(wsi->ssl, n);
394 lwsl_debug("SSL_accept failed %d / %s\n",
395 m, ERR_error_string(m, NULL));
397 if (m == SSL_ERROR_WANT_READ) {
399 wsi->position_in_fds_table].events |= POLLIN;
401 /* external POLL support via protocol 0 */
402 context->protocols[0].callback(context, wsi,
403 LWS_CALLBACK_SET_MODE_POLL_FD,
405 (void *)(long)wsi->sock, POLLIN);
406 lwsl_info("SSL_ERROR_WANT_READ\n");
409 if (m == SSL_ERROR_WANT_WRITE) {
411 wsi->position_in_fds_table].events |= POLLOUT;
412 /* external POLL support via protocol 0 */
413 context->protocols[0].callback(context, wsi,
414 LWS_CALLBACK_SET_MODE_POLL_FD,
416 (void *)(long)wsi->sock, POLLOUT);
419 lwsl_debug("SSL_accept failed skt %u: %s\n",
421 ERR_error_string(m, NULL));
422 libwebsocket_close_and_free_session(context, wsi,
423 LWS_CLOSE_STATUS_NOSTATUS);
428 /* OK, we are accepted */
430 libwebsocket_set_timeout(wsi, NO_PENDING_TIMEOUT, 0);
432 wsi->mode = LWS_CONNMODE_HTTP_SERVING;
434 lwsl_debug("accepted new SSL conn\n");
445 static const char *err400[] = {
451 "Method Not Allowed",
453 "Proxy Auth Required",
458 "Precondition Failed",
459 "Request Entity Too Large",
460 "Request URI too Long",
461 "Unsupported Media Type",
462 "Requested Range Not Satisfiable",
466 static const char *err500[] = {
467 "Internal Server Error",
470 "Service Unavailable",
472 "HTTP Version Not Supported"
476 * libwebsockets_return_http_status() - Return simple http status
477 * @context: libwebsockets context
478 * @wsi: Websocket instance (available from user callback)
479 * @code: Status index, eg, 404
480 * @html_body: User-readable HTML description, or NULL
482 * Helper to report HTTP errors back to the client cleanly and
485 LWS_VISIBLE int libwebsockets_return_http_status(
486 struct libwebsocket_context *context, struct libwebsocket *wsi,
487 unsigned int code, const char *html_body)
490 const char *description = "";
495 if (code >= 400 && code < (400 + ARRAY_SIZE(err400)))
496 description = err400[code - 400];
497 if (code >= 500 && code < (500 + ARRAY_SIZE(err500)))
498 description = err500[code - 500];
500 n = sprintf((char *)context->service_buffer,
501 "HTTP/1.0 %u %s\x0d\x0a"
502 "Server: libwebsockets\x0d\x0a"
503 "Mime-Type: text/html\x0d\x0a\x0d\x0a"
505 code, description, code, description, html_body);
507 lwsl_info((const char *)context->service_buffer);
509 m = libwebsocket_write(wsi, context->service_buffer, n, LWS_WRITE_HTTP);
515 * libwebsockets_serve_http_file() - Send a file back to the client using http
516 * @context: libwebsockets context
517 * @wsi: Websocket instance (available from user callback)
518 * @file: The file to issue over http
519 * @content_type: The http content type, eg, text/html
520 * @other_headers: NULL or pointer to \0-terminated other header string
522 * This function is intended to be called from the callback in response
523 * to http requests from the client. It allows the callback to issue
524 * local files down the http link in a single step.
526 * Returning <0 indicates error and the wsi should be closed. Returning
527 * >0 indicates the file was completely sent and the wsi should be closed.
528 * ==0 indicates the file transfer is started and needs more service later,
529 * the wsi should be left alone.
532 LWS_VISIBLE int libwebsockets_serve_http_file(
533 struct libwebsocket_context *context,
534 struct libwebsocket *wsi, const char *file,
535 const char *content_type, const char *other_headers)
537 struct stat stat_buf;
538 unsigned char *p = context->service_buffer;
542 wsi->u.http.fd = open(file, O_RDONLY
548 if (wsi->u.http.fd < 1) {
549 lwsl_err("Unable to open '%s'\n", file);
550 libwebsockets_return_http_status(context, wsi,
551 HTTP_STATUS_NOT_FOUND, NULL);
556 fstat(wsi->u.http.fd, &stat_buf);
557 wsi->u.http.filelen = stat_buf.st_size;
558 p += sprintf((char *)p,
559 "HTTP/1.0 200 OK\x0d\x0aServer: libwebsockets\x0d\x0a""Content-Type: %s\x0d\x0a",
562 n = strlen(other_headers);
563 memcpy(p, other_headers, n);
566 p += sprintf((char *)p,
567 "Content-Length: %u\x0d\x0a\x0d\x0a",
568 (unsigned int)stat_buf.st_size);
570 ret = libwebsocket_write(wsi, context->service_buffer,
571 p - context->service_buffer, LWS_WRITE_HTTP);
572 if (ret != (p - context->service_buffer)) {
573 lwsl_err("_write returned %d from %d\n", ret, (p - context->service_buffer));
577 wsi->u.http.filepos = 0;
578 wsi->state = WSI_STATE_HTTP_ISSUING_FILE;
580 return libwebsockets_serve_http_file_fragment(context, wsi);