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 context->protocols[0].callback(context, wsi,
216 LWS_CALLBACK_LOCK_POLL,
217 wsi->user_space, (void *)(long)wsi->sock, 0);
219 pollfd->events &= ~POLLOUT;
221 /* external POLL support via protocol 0 */
222 context->protocols[0].callback(context, wsi,
223 LWS_CALLBACK_CLEAR_MODE_POLL_FD,
224 wsi->user_space, (void *)(long)wsi->sock, POLLOUT);
226 context->protocols[0].callback(context, wsi,
227 LWS_CALLBACK_UNLOCK_POLL,
228 wsi->user_space, (void *)(long)wsi->sock, 0);
231 if (wsi->state != WSI_STATE_HTTP_ISSUING_FILE) {
232 n = user_callback_handle_rxflow(
233 wsi->protocol->callback,
234 wsi->protocol->owning_server,
235 wsi, LWS_CALLBACK_HTTP_WRITEABLE,
240 libwebsocket_close_and_free_session(
241 context, wsi, LWS_CLOSE_STATUS_NOSTATUS);
245 /* nonzero for completion or error */
246 if (libwebsockets_serve_http_file_fragment(context, wsi))
247 libwebsocket_close_and_free_session(context, wsi,
248 LWS_CLOSE_STATUS_NOSTATUS);
251 case LWS_CONNMODE_SERVER_LISTENER:
253 /* pollin means a client has connected to us then */
255 if (!(pollfd->revents & POLLIN))
258 /* listen socket got an unencrypted connection... */
260 clilen = sizeof(cli_addr);
261 lws_latency_pre(context, wsi);
262 accept_fd = accept(pollfd->fd, (struct sockaddr *)&cli_addr,
264 lws_latency(context, wsi,
265 "unencrypted accept LWS_CONNMODE_SERVER_LISTENER",
266 accept_fd, accept_fd >= 0);
268 if (errno == EAGAIN || errno == EWOULDBLOCK) {
269 lwsl_debug("accept asks to try again\n");
272 lwsl_warn("ERROR on accept: %s\n", strerror(errno));
276 lws_set_socket_options(context, accept_fd);
279 * look at who we connected to and give user code a chance
280 * to reject based on client IP. There's no protocol selected
281 * yet so we issue this to protocols[0]
284 if ((context->protocols[0].callback)(context, wsi,
285 LWS_CALLBACK_FILTER_NETWORK_CONNECTION,
286 NULL, (void *)(long)accept_fd, 0)) {
287 lwsl_debug("Callback denied network connection\n");
288 compatible_close(accept_fd);
292 new_wsi = libwebsocket_create_new_server_wsi(context);
293 if (new_wsi == NULL) {
294 compatible_close(accept_fd);
298 new_wsi->sock = accept_fd;
300 #ifdef LWS_OPENSSL_SUPPORT
302 if (!context->use_ssl) {
305 lwsl_debug("accepted new conn port %u on fd=%d\n",
306 ntohs(cli_addr.sin_port), accept_fd);
308 insert_wsi_socket_into_fds(context, new_wsi);
310 #ifdef LWS_OPENSSL_SUPPORT
313 new_wsi->ssl = SSL_new(context->ssl_ctx);
314 if (new_wsi->ssl == NULL) {
315 lwsl_err("SSL_new failed: %s\n",
316 ERR_error_string(SSL_get_error(
317 new_wsi->ssl, 0), NULL));
318 libwebsockets_decode_ssl_error();
320 compatible_close(accept_fd);
324 SSL_set_ex_data(new_wsi->ssl,
325 openssl_websocket_private_data_index, context);
327 SSL_set_fd(new_wsi->ssl, accept_fd);
330 CyaSSL_set_using_nonblock(new_wsi->ssl, 1);
332 bio = SSL_get_rbio(new_wsi->ssl);
334 BIO_set_nbio(bio, 1); /* nonblocking */
336 lwsl_notice("NULL rbio\n");
337 bio = SSL_get_wbio(new_wsi->ssl);
339 BIO_set_nbio(bio, 1); /* nonblocking */
341 lwsl_notice("NULL rbio\n");
345 * we are not accepted yet, but we need to enter ourselves
346 * as a live connection. That way we can retry when more
347 * pieces come if we're not sorted yet
351 wsi->mode = LWS_CONNMODE_SSL_ACK_PENDING;
352 insert_wsi_socket_into_fds(context, wsi);
354 libwebsocket_set_timeout(wsi, PENDING_TIMEOUT_SSL_ACCEPT,
357 lwsl_info("inserted SSL accept into fds, trying SSL_accept\n");
361 case LWS_CONNMODE_SSL_ACK_PENDING:
363 context->protocols[0].callback(context, wsi,
364 LWS_CALLBACK_LOCK_POLL,
365 wsi->user_space, (void *)(long)wsi->sock, 0);
367 pollfd->events &= ~POLLOUT;
369 /* external POLL support via protocol 0 */
370 context->protocols[0].callback(context, wsi,
371 LWS_CALLBACK_CLEAR_MODE_POLL_FD,
372 wsi->user_space, (void *)(long)wsi->sock, POLLOUT);
374 context->protocols[0].callback(context, wsi,
375 LWS_CALLBACK_UNLOCK_POLL,
376 wsi->user_space, (void *)(long)wsi->sock, 0);
378 lws_latency_pre(context, wsi);
380 n = recv(wsi->sock, context->service_buffer,
381 sizeof(context->service_buffer), MSG_PEEK);
384 * optionally allow non-SSL connect on SSL listening socket
385 * This is disabled by default, if enabled it goes around any
386 * SSL-level access control (eg, client-side certs) so leave
387 * it disabled unless you know it's not a problem for you
390 if (context->allow_non_ssl_on_ssl_port && n >= 1 &&
391 context->service_buffer[0] >= ' ') {
393 * TLS content-type for Handshake is 0x16
394 * TLS content-type for ChangeCipherSpec Record is 0x14
396 * A non-ssl session will start with the HTTP method in
397 * ASCII. If we see it's not a legit SSL handshake
398 * kill the SSL for this connection and try to handle
399 * as a HTTP connection upgrade directly.
402 SSL_shutdown(wsi->ssl);
408 /* normal SSL connection processing path */
410 n = SSL_accept(wsi->ssl);
411 lws_latency(context, wsi,
412 "SSL_accept LWS_CONNMODE_SSL_ACK_PENDING\n", n, n == 1);
415 m = SSL_get_error(wsi->ssl, n);
416 lwsl_debug("SSL_accept failed %d / %s\n",
417 m, ERR_error_string(m, NULL));
419 if (m == SSL_ERROR_WANT_READ) {
420 context->protocols[0].callback(context, wsi,
421 LWS_CALLBACK_LOCK_POLL,
422 wsi->user_space, (void *)(long)wsi->sock, 0);
424 wsi->position_in_fds_table].events |= POLLIN;
426 /* external POLL support via protocol 0 */
427 context->protocols[0].callback(context, wsi,
428 LWS_CALLBACK_SET_MODE_POLL_FD,
430 (void *)(long)wsi->sock, POLLIN);
431 context->protocols[0].callback(context, wsi,
432 LWS_CALLBACK_UNLOCK_POLL,
433 wsi->user_space, (void *)(long)wsi->sock, 0);
434 lwsl_info("SSL_ERROR_WANT_READ\n");
437 if (m == SSL_ERROR_WANT_WRITE) {
438 context->protocols[0].callback(context, wsi,
439 LWS_CALLBACK_LOCK_POLL,
440 wsi->user_space, (void *)(long)wsi->sock, 0);
442 wsi->position_in_fds_table].events |= POLLOUT;
443 /* external POLL support via protocol 0 */
444 context->protocols[0].callback(context, wsi,
445 LWS_CALLBACK_SET_MODE_POLL_FD,
447 (void *)(long)wsi->sock, POLLOUT);
448 context->protocols[0].callback(context, wsi,
449 LWS_CALLBACK_UNLOCK_POLL,
450 wsi->user_space, (void *)(long)wsi->sock, 0);
453 lwsl_debug("SSL_accept failed skt %u: %s\n",
455 ERR_error_string(m, NULL));
456 libwebsocket_close_and_free_session(context, wsi,
457 LWS_CLOSE_STATUS_NOSTATUS);
462 /* OK, we are accepted */
464 libwebsocket_set_timeout(wsi, NO_PENDING_TIMEOUT, 0);
466 wsi->mode = LWS_CONNMODE_HTTP_SERVING;
468 lwsl_debug("accepted new SSL conn\n");
479 static const char *err400[] = {
485 "Method Not Allowed",
487 "Proxy Auth Required",
492 "Precondition Failed",
493 "Request Entity Too Large",
494 "Request URI too Long",
495 "Unsupported Media Type",
496 "Requested Range Not Satisfiable",
500 static const char *err500[] = {
501 "Internal Server Error",
504 "Service Unavailable",
506 "HTTP Version Not Supported"
510 * libwebsockets_return_http_status() - Return simple http status
511 * @context: libwebsockets context
512 * @wsi: Websocket instance (available from user callback)
513 * @code: Status index, eg, 404
514 * @html_body: User-readable HTML description, or NULL
516 * Helper to report HTTP errors back to the client cleanly and
519 LWS_VISIBLE int libwebsockets_return_http_status(
520 struct libwebsocket_context *context, struct libwebsocket *wsi,
521 unsigned int code, const char *html_body)
524 const char *description = "";
529 if (code >= 400 && code < (400 + ARRAY_SIZE(err400)))
530 description = err400[code - 400];
531 if (code >= 500 && code < (500 + ARRAY_SIZE(err500)))
532 description = err500[code - 500];
534 n = sprintf((char *)context->service_buffer,
535 "HTTP/1.0 %u %s\x0d\x0a"
536 "Server: libwebsockets\x0d\x0a"
537 "Mime-Type: text/html\x0d\x0a\x0d\x0a"
539 code, description, code, description, html_body);
541 lwsl_info((const char *)context->service_buffer);
543 m = libwebsocket_write(wsi, context->service_buffer, n, LWS_WRITE_HTTP);
549 * libwebsockets_serve_http_file() - Send a file back to the client using http
550 * @context: libwebsockets context
551 * @wsi: Websocket instance (available from user callback)
552 * @file: The file to issue over http
553 * @content_type: The http content type, eg, text/html
554 * @other_headers: NULL or pointer to \0-terminated other header string
556 * This function is intended to be called from the callback in response
557 * to http requests from the client. It allows the callback to issue
558 * local files down the http link in a single step.
560 * Returning <0 indicates error and the wsi should be closed. Returning
561 * >0 indicates the file was completely sent and the wsi should be closed.
562 * ==0 indicates the file transfer is started and needs more service later,
563 * the wsi should be left alone.
566 LWS_VISIBLE int libwebsockets_serve_http_file(
567 struct libwebsocket_context *context,
568 struct libwebsocket *wsi, const char *file,
569 const char *content_type, const char *other_headers)
571 struct stat stat_buf;
572 unsigned char *p = context->service_buffer;
576 wsi->u.http.fd = open(file, O_RDONLY
582 if (wsi->u.http.fd < 1) {
583 lwsl_err("Unable to open '%s'\n", file);
584 libwebsockets_return_http_status(context, wsi,
585 HTTP_STATUS_NOT_FOUND, NULL);
590 fstat(wsi->u.http.fd, &stat_buf);
591 wsi->u.http.filelen = stat_buf.st_size;
592 p += sprintf((char *)p,
593 "HTTP/1.0 200 OK\x0d\x0aServer: libwebsockets\x0d\x0a""Content-Type: %s\x0d\x0a",
596 n = strlen(other_headers);
597 memcpy(p, other_headers, n);
600 p += sprintf((char *)p,
601 "Content-Length: %u\x0d\x0a\x0d\x0a",
602 (unsigned int)stat_buf.st_size);
604 ret = libwebsocket_write(wsi, context->service_buffer,
605 p - context->service_buffer, LWS_WRITE_HTTP);
606 if (ret != (p - context->service_buffer)) {
607 lwsl_err("_write returned %d from %d\n", ret, (p - context->service_buffer));
611 wsi->u.http.filepos = 0;
612 wsi->state = WSI_STATE_HTTP_ISSUING_FILE;
614 return libwebsockets_serve_http_file_fragment(context, wsi);