Exemple #1
0
LWS_VISIBLE int libwebsockets_serve_http_file(
		struct libwebsocket_context *context,
			struct libwebsocket *wsi, const char *file,
			   const char *content_type, const char *other_headers,
			   int other_headers_len)
{
	unsigned char *response = context->service_buffer + LWS_SEND_BUFFER_PRE_PADDING;
	unsigned char *p = response;
	unsigned char *end = p + sizeof(context->service_buffer) -
					LWS_SEND_BUFFER_PRE_PADDING;
	int ret = 0;

	wsi->u.http.fd = lws_plat_open_file(file, &wsi->u.http.filelen);

	if (wsi->u.http.fd == LWS_INVALID_FILE) {
		lwsl_err("Unable to open '%s'\n", file);
		libwebsockets_return_http_status(context, wsi,
						HTTP_STATUS_NOT_FOUND, NULL);
		return -1;
	}

	if (lws_add_http_header_status(context, wsi, 200, &p, end))
		return -1;
	if (lws_add_http_header_by_token(context, wsi, WSI_TOKEN_HTTP_SERVER, (unsigned char *)"libwebsockets", 13, &p, end))
		return -1;
	if (lws_add_http_header_by_token(context, wsi, WSI_TOKEN_HTTP_CONTENT_TYPE, (unsigned char *)content_type, strlen(content_type), &p, end))
		return -1;
	if (lws_add_http_header_content_length(context, wsi, wsi->u.http.filelen, &p, end))
		return -1;

	if (other_headers) {
		if ((end - p) < other_headers_len)
			return -1;
		memcpy(p, other_headers, other_headers_len);
		p += other_headers_len;
	}

	if (lws_finalize_http_header(context, wsi, &p, end))
		return -1;
	
	ret = libwebsocket_write(wsi, response,
				   p - response, LWS_WRITE_HTTP_HEADERS);
	if (ret != (p - response)) {
		lwsl_err("_write returned %d from %d\n", ret, (p - response));
		return -1;
	}

	wsi->u.http.filepos = 0;
	wsi->state = WSI_STATE_HTTP_ISSUING_FILE;

	return libwebsockets_serve_http_file_fragment(context, wsi);
}
Exemple #2
0
LWS_VISIBLE int libwebsockets_serve_http_file(
		struct libwebsocket_context *context,
			struct libwebsocket *wsi, const char *file,
			   const char *content_type, const char *other_headers)
{
	struct stat stat_buf;
	unsigned char *p = context->service_buffer;
	int ret = 0;
	int n;

	wsi->u.http.fd = open(file, O_RDONLY
#ifdef WIN32
			 | _O_BINARY
#endif
	);

	if (wsi->u.http.fd < 1) {
		lwsl_err("Unable to open '%s'\n", file);
		libwebsockets_return_http_status(context, wsi,
						HTTP_STATUS_NOT_FOUND, NULL);
		wsi->u.http.fd = -1;
		return -1;
	}

	fstat(wsi->u.http.fd, &stat_buf);
	wsi->u.http.filelen = stat_buf.st_size;
	p += sprintf((char *)p,
"HTTP/1.0 200 OK\x0d\x0aServer: pilight\x0d\x0a""Content-Type: %s\x0d\x0a",
								  content_type);
	if (other_headers) {
		n = strlen(other_headers);
		memcpy(p, other_headers, n);
		p += n;
	}
	p += sprintf((char *)p,
		"Content-Length: %u\x0d\x0a\x0d\x0a",
					(unsigned int)stat_buf.st_size);

	ret = libwebsocket_write(wsi, context->service_buffer,
				   p - context->service_buffer, LWS_WRITE_HTTP);
	if (ret != (p - context->service_buffer)) {
		lwsl_err("_write returned %d from %d\n", ret, (p - context->service_buffer));
		return -1;
	}

	wsi->u.http.filepos = 0;
	wsi->state = WSI_STATE_HTTP_ISSUING_FILE;

	return libwebsockets_serve_http_file_fragment(context, wsi);
}
Exemple #3
0
LWS_VISIBLE int libwebsockets_serve_http_file(
    struct libwebsocket_context *context,
    struct libwebsocket *wsi, const char *file,
    const char *content_type, const char *other_headers)
{
    unsigned char *p = context->service_buffer;
    int ret = 0;
    int n;

    wsi->u.http.fd = lws_plat_open_file(file, &wsi->u.http.filelen);

    if (wsi->u.http.fd == LWS_INVALID_FILE) {
        lwsl_err("Unable to open '%s'\n", file);
        libwebsockets_return_http_status(context, wsi,
                                         HTTP_STATUS_NOT_FOUND, NULL);
        return -1;
    }

    p += sprintf((char *)p,
                 "HTTP/1.0 200 OK\x0d\x0aServer: libwebsockets\x0d\x0a""Content-Type: %s\x0d\x0a",
                 content_type);
    if (other_headers) {
        n = strlen(other_headers);
        memcpy(p, other_headers, n);
        p += n;
    }
    p += sprintf((char *)p,
                 "Content-Length: %lu\x0d\x0a\x0d\x0a", wsi->u.http.filelen);

    ret = libwebsocket_write(wsi, context->service_buffer,
                             p - context->service_buffer, LWS_WRITE_HTTP);
    if (ret != (p - context->service_buffer)) {
        lwsl_err("_write returned %d from %d\n", ret, (p - context->service_buffer));
        return -1;
    }

    wsi->u.http.filepos = 0;
    wsi->state = WSI_STATE_HTTP_ISSUING_FILE;

    return libwebsockets_serve_http_file_fragment(context, wsi);
}
Exemple #4
0
int lws_server_socket_service(struct libwebsocket_context *context,
                              struct libwebsocket *wsi, struct libwebsocket_pollfd *pollfd)
{
    struct libwebsocket *new_wsi = NULL;
    int accept_fd = 0;
    socklen_t clilen;
    struct sockaddr_in cli_addr;
    int n;
    int len;

    switch (wsi->mode) {

    case LWS_CONNMODE_HTTP_SERVING:
    case LWS_CONNMODE_HTTP_SERVING_ACCEPTED:

        /* handle http headers coming in */

        /* pending truncated sends have uber priority */

        if (wsi->truncated_send_malloc) {
            if (pollfd->revents & LWS_POLLOUT)
                if (lws_issue_raw(wsi, wsi->truncated_send_malloc +
                                  wsi->truncated_send_offset,
                                  wsi->truncated_send_len) < 0) {
                    lwsl_info("closing from socket service\n");
                    return -1;
                }
            /*
             * we can't afford to allow input processing send
             * something new, so spin around he event loop until
             * he doesn't have any partials
             */
            break;
        }

        /* any incoming data ready? */

        if (pollfd->revents & LWS_POLLIN) {
            len = lws_ssl_capable_read(wsi,
                                       context->service_buffer,
                                       sizeof(context->service_buffer));
            switch (len) {
            case 0:
                lwsl_info("lws_server_skt_srv: read 0 len\n");
                /* lwsl_info("   state=%d\n", wsi->state); */
                if (!wsi->hdr_parsing_completed)
                    free(wsi->u.hdr.ah);
            /* fallthru */
            case LWS_SSL_CAPABLE_ERROR:
                libwebsocket_close_and_free_session(
                    context, wsi,
                    LWS_CLOSE_STATUS_NOSTATUS);
                return 0;
            case LWS_SSL_CAPABLE_MORE_SERVICE:
                break;
            }

            /* just ignore incoming if waiting for close */
            if (wsi->state != WSI_STATE_FLUSHING_STORED_SEND_BEFORE_CLOSE) {

                /* hm this may want to send (via HTTP callback for example) */
                n = libwebsocket_read(context, wsi,
                                      context->service_buffer, len);
                if (n < 0)
                    /* we closed wsi */
                    return 0;

                /* hum he may have used up the writability above */
                break;
            }
        }

        /* this handles POLLOUT for http serving fragments */

        if (!(pollfd->revents & LWS_POLLOUT))
            break;

        /* one shot */
        if (lws_change_pollfd(wsi, LWS_POLLOUT, 0))
            goto fail;

        lws_libev_io(context, wsi, LWS_EV_STOP | LWS_EV_WRITE);

        if (wsi->state != WSI_STATE_HTTP_ISSUING_FILE) {
            n = user_callback_handle_rxflow(
                    wsi->protocol->callback,
                    wsi->protocol->owning_server,
                    wsi, LWS_CALLBACK_HTTP_WRITEABLE,
                    wsi->user_space,
                    NULL,
                    0);
            if (n < 0)
                libwebsocket_close_and_free_session(
                    context, wsi, LWS_CLOSE_STATUS_NOSTATUS);
            break;
        }

        /* nonzero for completion or error */
        if (libwebsockets_serve_http_file_fragment(context, wsi))
            libwebsocket_close_and_free_session(context, wsi,
                                                LWS_CLOSE_STATUS_NOSTATUS);
        break;

    case LWS_CONNMODE_SERVER_LISTENER:

        /* pollin means a client has connected to us then */

        if (!(pollfd->revents & LWS_POLLIN))
            break;

        /* listen socket got an unencrypted connection... */

        clilen = sizeof(cli_addr);
        lws_latency_pre(context, wsi);
        accept_fd  = accept(pollfd->fd, (struct sockaddr *)&cli_addr,
                            &clilen);
        lws_latency(context, wsi,
                    "unencrypted accept LWS_CONNMODE_SERVER_LISTENER",
                    accept_fd, accept_fd >= 0);
        if (accept_fd < 0) {
            if (LWS_ERRNO == LWS_EAGAIN || LWS_ERRNO == LWS_EWOULDBLOCK) {
                lwsl_debug("accept asks to try again\n");
                break;
            }
            lwsl_warn("ERROR on accept: %s\n", strerror(LWS_ERRNO));
            break;
        }

        lws_plat_set_socket_options(context, accept_fd);

        /*
         * look at who we connected to and give user code a chance
         * to reject based on client IP.  There's no protocol selected
         * yet so we issue this to protocols[0]
         */

        if ((context->protocols[0].callback)(context, wsi,
                                             LWS_CALLBACK_FILTER_NETWORK_CONNECTION,
                                             NULL, (void *)(long)accept_fd, 0)) {
            lwsl_debug("Callback denied network connection\n");
            compatible_close(accept_fd);
            break;
        }

        new_wsi = libwebsocket_create_new_server_wsi(context);
        if (new_wsi == NULL) {
            compatible_close(accept_fd);
            break;
        }

        new_wsi->sock = accept_fd;

        /* the transport is accepted... give him time to negotiate */
        libwebsocket_set_timeout(new_wsi,
                                 PENDING_TIMEOUT_ESTABLISH_WITH_SERVER,
                                 AWAITING_TIMEOUT);

        /*
         * A new connection was accepted. Give the user a chance to
         * set properties of the newly created wsi. There's no protocol
         * selected yet so we issue this to protocols[0]
         */

        (context->protocols[0].callback)(context, new_wsi,
                                         LWS_CALLBACK_SERVER_NEW_CLIENT_INSTANTIATED, NULL, NULL, 0);

        lws_libev_accept(context, new_wsi, accept_fd);

        if (!LWS_SSL_ENABLED(context)) {
            lwsl_debug("accepted new conn  port %u on fd=%d\n",
                       ntohs(cli_addr.sin_port), accept_fd);

            insert_wsi_socket_into_fds(context, new_wsi);
        }
        break;

    default:
        break;
    }

    if (lws_server_socket_service_ssl(context, &wsi, new_wsi,
                                      accept_fd, pollfd))
        goto fail;

    return 0;

fail:
    libwebsocket_close_and_free_session(context, wsi,
                                        LWS_CLOSE_STATUS_NOSTATUS);
    return 1;
}
Exemple #5
0
int lws_server_socket_service(struct libwebsocket_context *context,
			struct libwebsocket *wsi, struct pollfd *pollfd)
{
	struct libwebsocket *new_wsi;
	int accept_fd;
	socklen_t clilen;
	struct sockaddr_in cli_addr;
	int n;
	ssize_t len;
#ifdef LWS_OPENSSL_SUPPORT
	int m;
#ifndef USE_CYASSL
	BIO *bio;
#endif
#endif

	switch (wsi->mode) {

	case LWS_CONNMODE_HTTP_SERVING:
	case LWS_CONNMODE_HTTP_SERVING_ACCEPTED:

		/* handle http headers coming in */

		/* pending truncated sends have uber priority */

		if (wsi->truncated_send_malloc) {
			if (pollfd->revents & POLLOUT)
				lws_issue_raw(wsi, wsi->truncated_send_malloc +
					wsi->truncated_send_offset,
							wsi->truncated_send_len);
			/*
			 * we can't afford to allow input processing send
			 * something new, so spin around he event loop until
			 * he doesn't have any partials
			 */
			break;
		}

		/* any incoming data ready? */

		if (pollfd->revents & POLLIN) {

	#ifdef LWS_OPENSSL_SUPPORT
			if (wsi->ssl)
				len = SSL_read(wsi->ssl,
					context->service_buffer,
					       sizeof(context->service_buffer));
			else
	#endif
				len = recv(pollfd->fd,
					context->service_buffer,
					sizeof(context->service_buffer), 0);

			if (len < 0) {
				lwsl_debug("Socket read returned %d\n", len);
				if (errno != EINTR && errno != EAGAIN)
					libwebsocket_close_and_free_session(
						context, wsi,
						LWS_CLOSE_STATUS_NOSTATUS);
				return 0;
			}
			if (!len) {
				lwsl_info("lws_server_skt_srv: read 0 len\n");
				/* lwsl_info("   state=%d\n", wsi->state); */
				if (!wsi->hdr_parsing_completed)
					free(wsi->u.hdr.ah);
				libwebsocket_close_and_free_session(
				       context, wsi, LWS_CLOSE_STATUS_NOSTATUS);
				return 0;
			}

			/* hm this may want to send (via HTTP callback for example) */

			n = libwebsocket_read(context, wsi,
						context->service_buffer, len);
			if (n < 0)
				/* we closed wsi */
				return 0;

			/* hum he may have used up the writability above */
			break;
		}

		/* this handles POLLOUT for http serving fragments */

		if (!(pollfd->revents & POLLOUT))
			break;

		/* one shot */
		lws_change_pollfd(wsi, POLLOUT, 0);

		if (wsi->state != WSI_STATE_HTTP_ISSUING_FILE) {
			n = user_callback_handle_rxflow(
					wsi->protocol->callback,
					wsi->protocol->owning_server,
					wsi, LWS_CALLBACK_HTTP_WRITEABLE,
					wsi->user_space,
					NULL,
					0);
			if (n < 0)
				libwebsocket_close_and_free_session(
				       context, wsi, LWS_CLOSE_STATUS_NOSTATUS);
			break;
		}

		/* nonzero for completion or error */
		if (libwebsockets_serve_http_file_fragment(context, wsi))
			libwebsocket_close_and_free_session(context, wsi,
					       LWS_CLOSE_STATUS_NOSTATUS);
		break;

	case LWS_CONNMODE_SERVER_LISTENER:

		/* pollin means a client has connected to us then */

		if (!(pollfd->revents & POLLIN))
			break;

		/* listen socket got an unencrypted connection... */

		clilen = sizeof(cli_addr);
		lws_latency_pre(context, wsi);
		accept_fd  = accept(pollfd->fd, (struct sockaddr *)&cli_addr,
								       &clilen);
		lws_latency(context, wsi,
			"unencrypted accept LWS_CONNMODE_SERVER_LISTENER",
						     accept_fd, accept_fd >= 0);
		if (accept_fd < 0) {
			if (errno == EAGAIN || errno == EWOULDBLOCK) {
				lwsl_debug("accept asks to try again\n");
				break;
			}
			lwsl_warn("ERROR on accept: %s\n", strerror(errno));
			break;
		}

		lws_set_socket_options(context, accept_fd);

		/*
		 * look at who we connected to and give user code a chance
		 * to reject based on client IP.  There's no protocol selected
		 * yet so we issue this to protocols[0]
		 */

		if ((context->protocols[0].callback)(context, wsi,
				LWS_CALLBACK_FILTER_NETWORK_CONNECTION,
					   NULL, (void *)(long)accept_fd, 0)) {
			lwsl_debug("Callback denied network connection\n");
			compatible_close(accept_fd);
			break;
		}

		new_wsi = libwebsocket_create_new_server_wsi(context);
		if (new_wsi == NULL) {
			compatible_close(accept_fd);
			break;
		}

		new_wsi->sock = accept_fd;

#ifdef LWS_OPENSSL_SUPPORT
		new_wsi->ssl = NULL;
		if (!context->use_ssl) {
#endif

			lwsl_debug("accepted new conn  port %u on fd=%d\n",
					  ntohs(cli_addr.sin_port), accept_fd);

			insert_wsi_socket_into_fds(context, new_wsi);
			break;
#ifdef LWS_OPENSSL_SUPPORT
		}

		new_wsi->ssl = SSL_new(context->ssl_ctx);
		if (new_wsi->ssl == NULL) {
			lwsl_err("SSL_new failed: %s\n",
			    ERR_error_string(SSL_get_error(
			    new_wsi->ssl, 0), NULL));
			    libwebsockets_decode_ssl_error();
			free(new_wsi);
			compatible_close(accept_fd);
			break;
		}

		SSL_set_ex_data(new_wsi->ssl,
			openssl_websocket_private_data_index, context);

		SSL_set_fd(new_wsi->ssl, accept_fd);

		#ifdef USE_CYASSL
		CyaSSL_set_using_nonblock(new_wsi->ssl, 1);
		#else
		bio = SSL_get_rbio(new_wsi->ssl);
		if (bio)
			BIO_set_nbio(bio, 1); /* nonblocking */
		else
			lwsl_notice("NULL rbio\n");
		bio = SSL_get_wbio(new_wsi->ssl);
		if (bio)
			BIO_set_nbio(bio, 1); /* nonblocking */
		else
			lwsl_notice("NULL rbio\n");
		#endif

		/*
		 * we are not accepted yet, but we need to enter ourselves
		 * as a live connection.  That way we can retry when more
		 * pieces come if we're not sorted yet
		 */

		wsi = new_wsi;
		wsi->mode = LWS_CONNMODE_SSL_ACK_PENDING;
		insert_wsi_socket_into_fds(context, wsi);

		libwebsocket_set_timeout(wsi, PENDING_TIMEOUT_SSL_ACCEPT,
							AWAITING_TIMEOUT);

		lwsl_info("inserted SSL accept into fds, trying SSL_accept\n");

		/* fallthru */

	case LWS_CONNMODE_SSL_ACK_PENDING:

		lws_change_pollfd(wsi, POLLOUT, 0);

		lws_latency_pre(context, wsi);

		n = recv(wsi->sock, context->service_buffer,
			sizeof(context->service_buffer), MSG_PEEK);

		/*
		 * optionally allow non-SSL connect on SSL listening socket
		 * This is disabled by default, if enabled it goes around any
		 * SSL-level access control (eg, client-side certs) so leave
		 * it disabled unless you know it's not a problem for you
		 */

		if (context->allow_non_ssl_on_ssl_port && n >= 1 &&
					context->service_buffer[0] >= ' ') {
			/*
			 * TLS content-type for Handshake is 0x16
			 * TLS content-type for ChangeCipherSpec Record is 0x14
			 *
			 * A non-ssl session will start with the HTTP method in
			 * ASCII.  If we see it's not a legit SSL handshake
			 * kill the SSL for this connection and try to handle
			 * as a HTTP connection upgrade directly.
			 */
			wsi->use_ssl = 0;
			SSL_shutdown(wsi->ssl);
			SSL_free(wsi->ssl);
			wsi->ssl = NULL;
			goto accepted;
		}

		/* normal SSL connection processing path */

		n = SSL_accept(wsi->ssl);
		lws_latency(context, wsi,
			"SSL_accept LWS_CONNMODE_SSL_ACK_PENDING\n", n, n == 1);

		if (n != 1) {
			m = SSL_get_error(wsi->ssl, n);
			lwsl_debug("SSL_accept failed %d / %s\n",
						  m, ERR_error_string(m, NULL));

			if (m == SSL_ERROR_WANT_READ) {
				lws_change_pollfd(wsi, 0, POLLIN);
				lwsl_info("SSL_ERROR_WANT_READ\n");
				break;
			}
			if (m == SSL_ERROR_WANT_WRITE) {
				lws_change_pollfd(wsi, 0, POLLOUT);
				break;
			}
			lwsl_debug("SSL_accept failed skt %u: %s\n",
				  pollfd->fd,
				  ERR_error_string(m, NULL));
			libwebsocket_close_and_free_session(context, wsi,
						 LWS_CLOSE_STATUS_NOSTATUS);
			break;
		}

accepted:
		/* OK, we are accepted */

		libwebsocket_set_timeout(wsi, NO_PENDING_TIMEOUT, 0);

		wsi->mode = LWS_CONNMODE_HTTP_SERVING;

		lwsl_debug("accepted new SSL conn\n");
		break;
#endif

	default:
		break;
	}
	return 0;
}