adoption: make union for socket and file fds
authorAndy Green <andy@warmcat.com>
Mon, 27 Feb 2017 04:55:56 +0000 (12:55 +0800)
committerAndy Green <andy@warmcat.com>
Wed, 1 Mar 2017 02:01:53 +0000 (10:01 +0800)
This lets lws support adopting raw file FDs and raw socket fds.

A test plugin creates a FIFO and prints data sent on it, using
the lws event loop.

20 files changed:
CMakeLists.txt
lib/client-handshake.c
lib/client.c
lib/libev.c
lib/libuv.c
lib/libwebsockets.c
lib/libwebsockets.h
lib/lws-plat-esp32.c
lib/lws-plat-esp8266.c
lib/lws-plat-optee.c
lib/lws-plat-unix.c
lib/lws-plat-win.c
lib/output.c
lib/pollfd.c
lib/private-libwebsockets.h
lib/server.c
lib/service.c
lib/ssl-client.c
lib/ssl.c
plugins/protocol_lws_raw_test.c [new file with mode: 0644]

index 579a29c..95f473e 100644 (file)
@@ -1340,6 +1340,10 @@ if (NOT LWS_WITHOUT_TESTAPPS)
                              "plugins/protocol_post_demo.c" "" "")
                create_plugin(protocol_lws_table_dirlisting
                              "plugins/generic-table/protocol_table_dirlisting.c" "" "")
+               if (NOT WIN32)
+                     create_plugin(protocol_lws_raw_test
+                             "plugins/protocol_lws_raw_test.c" "" "")
+               endif()
 
 if (LWS_WITH_SERVER_STATUS)
                create_plugin(protocol_lws_server_status
index 3339a1d..acb8044 100644 (file)
@@ -169,34 +169,34 @@ lws_client_connect_2(struct lws *wsi)
                        freeaddrinfo(result);
        }
 
-       if (!lws_socket_is_valid(wsi->sock)) {
+       if (!lws_socket_is_valid(wsi->desc.sockfd)) {
 
 #ifdef LWS_USE_IPV6
                if (LWS_IPV6_ENABLED(wsi->vhost))
-                       wsi->sock = socket(AF_INET6, SOCK_STREAM, 0);
+                       wsi->desc.sockfd = socket(AF_INET6, SOCK_STREAM, 0);
                else
 #endif
-                       wsi->sock = socket(AF_INET, SOCK_STREAM, 0);
+                       wsi->desc.sockfd = socket(AF_INET, SOCK_STREAM, 0);
 
-               if (!lws_socket_is_valid(wsi->sock)) {
+               if (!lws_socket_is_valid(wsi->desc.sockfd)) {
                        lwsl_warn("Unable to open socket\n");
                        cce = "unable to open socket";
                        goto oom4;
                }
 
-               if (lws_plat_set_socket_options(wsi->vhost, wsi->sock)) {
+               if (lws_plat_set_socket_options(wsi->vhost, wsi->desc.sockfd)) {
                        lwsl_err("Failed to set wsi socket options\n");
-                       compatible_close(wsi->sock);
+                       compatible_close(wsi->desc.sockfd);
                        cce = "set socket opts failed";
                        goto oom4;
                }
 
                wsi->mode = LWSCM_WSCL_WAITING_CONNECT;
 
-               lws_libev_accept(wsi, wsi->sock);
-               lws_libuv_accept(wsi, wsi->sock);
+               lws_libev_accept(wsi, wsi->desc);
+               lws_libuv_accept(wsi, wsi->desc);
                if (insert_wsi_socket_into_fds(context, wsi)) {
-                       compatible_close(wsi->sock);
+                       compatible_close(wsi->desc.sockfd);
                        cce = "insert wsi failed";
                        goto oom4;
                }
@@ -217,7 +217,7 @@ lws_client_connect_2(struct lws *wsi)
                lws_set_timeout(wsi, PENDING_TIMEOUT_AWAITING_CONNECT_RESPONSE,
                                AWAITING_TIMEOUT);
 
-               n = lws_socket_bind(wsi->vhost, wsi->sock, 0, wsi->vhost->iface);
+               n = lws_socket_bind(wsi->vhost, wsi->desc.sockfd, 0, wsi->vhost->iface);
                if (n < 0) {
                        cce = "unable to bind socket";
                        goto failed;
@@ -235,7 +235,7 @@ lws_client_connect_2(struct lws *wsi)
                n = sizeof(struct sockaddr);
        }
 
-       if (connect(wsi->sock, v, n) == -1 || LWS_ERRNO == LWS_EISCONN) {
+       if (connect(wsi->desc.sockfd, v, n) == -1 || LWS_ERRNO == LWS_EISCONN) {
                if (LWS_ERRNO == LWS_EALREADY ||
                    LWS_ERRNO == LWS_EINPROGRESS ||
                    LWS_ERRNO == LWS_EWOULDBLOCK
@@ -287,7 +287,7 @@ lws_client_connect_2(struct lws *wsi)
                        goto failed;
                wsi->c_port = wsi->vhost->http_proxy_port;
 
-               n = send(wsi->sock, (char *)pt->serv_buf, plen,
+               n = send(wsi->desc.sockfd, (char *)pt->serv_buf, plen,
                         MSG_NOSIGNAL);
                if (n < 0) {
                        lwsl_debug("ERROR writing to proxy socket\n");
@@ -317,7 +317,7 @@ lws_client_connect_2(struct lws *wsi)
                        AWAITING_TIMEOUT);
 
        wsi->mode = LWSCM_WSCL_ISSUE_HANDSHAKE;
-       pfd.fd = wsi->sock;
+       pfd.fd = wsi->desc.sockfd;
        pfd.events = LWS_POLLIN;
        pfd.revents = LWS_POLLIN;
 
@@ -411,10 +411,10 @@ lws_client_reset(struct lws **pwsi, int ssl, const char *address, int port,
 
        /* close the connection by hand */
 
-       compatible_close(wsi->sock);
+       compatible_close(wsi->desc.sockfd);
        remove_wsi_socket_from_fds(wsi);
 
-       wsi->sock = LWS_SOCK_INVALID;
+       wsi->desc.sockfd = LWS_SOCK_INVALID;
        wsi->state = LWSS_CLIENT_UNCONNECTED;
        wsi->protocol = NULL;
        wsi->pending_timeout = NO_PENDING_TIMEOUT;
@@ -581,7 +581,7 @@ lws_client_connect_via_info(struct lws_client_connect_info *i)
        wsi->context = i->context;
        /* assert the mode and union status (hdr) clearly */
        lws_union_transition(wsi, LWSCM_HTTP_CLIENT);
-       wsi->sock = LWS_SOCK_INVALID;
+       wsi->desc.sockfd = LWS_SOCK_INVALID;
 
        /* 1) fill up the wsi with stuff from the connect_info as far as it
         * can go.  It's because not only is our connection async, we might
index d42a47e..57b79f4 100755 (executable)
@@ -114,7 +114,7 @@ lws_client_socket_service(struct lws_context *context, struct lws *wsi,
                        return 0;
                }
 
-               n = recv(wsi->sock, sb, context->pt_serv_buf_size, 0);
+               n = recv(wsi->desc.sockfd, sb, context->pt_serv_buf_size, 0);
                if (n < 0) {
                        if (LWS_ERRNO == LWS_EAGAIN) {
                                lwsl_debug("Proxy read returned EAGAIN... retrying\n");
@@ -952,7 +952,7 @@ check_accept:
        wsi->u.ws.rx_ubuf_alloc = n;
        lwsl_info("Allocating client RX buffer %d\n", n);
 
-       if (setsockopt(wsi->sock, SOL_SOCKET, SO_SNDBUF, (const char *)&n,
+       if (setsockopt(wsi->desc.sockfd, SOL_SOCKET, SO_SNDBUF, (const char *)&n,
                       sizeof n)) {
                lwsl_warn("Failed to set SNDBUF to %d", n);
                cce = "HS: SO_SNDBUF failed";
index 39242bb..3f882b2 100644 (file)
@@ -97,7 +97,7 @@ lws_ev_initloop(struct lws_context *context, struct ev_loop *loop, int tsi)
        while (vh) {
                if (vh->lserv_wsi) {
                        vh->lserv_wsi->w_read.context = context;
-                       ev_io_init(w_accept, lws_accept_cb, vh->lserv_wsi->sock,
+                       ev_io_init(w_accept, lws_accept_cb, vh->lserv_wsi->desc.sockfd,
                                  EV_READ);
                }
                vh = vh->vhost_next;
@@ -160,19 +160,25 @@ lws_libev_destroyloop(struct lws_context *context, int tsi)
 }
 
 LWS_VISIBLE void
-lws_libev_accept(struct lws *new_wsi, int accept_fd)
+lws_libev_accept(struct lws *new_wsi, lws_sock_file_fd_type desc)
 {
        struct lws_context *context = lws_get_context(new_wsi);
        struct ev_io *r = &new_wsi->w_read.ev_watcher;
        struct ev_io *w = &new_wsi->w_write.ev_watcher;
+       int fd;
 
        if (!LWS_LIBEV_ENABLED(context))
                return;
 
+       if (wsi->mode == LWSCM_RAW_FILEDESC)
+               fd = desc.filefd;
+       else
+               fd = desc.sockfd;
+
        new_wsi->w_read.context = context;
        new_wsi->w_write.context = context;
-       ev_io_init(r, lws_accept_cb, accept_fd, EV_READ);
-       ev_io_init(w, lws_accept_cb, accept_fd, EV_WRITE);
+       ev_io_init(r, lws_accept_cb, fd, EV_READ);
+       ev_io_init(w, lws_accept_cb, fd, EV_WRITE);
 }
 
 LWS_VISIBLE void
index 5572e0a..24f24ce 100644 (file)
@@ -164,10 +164,10 @@ lws_uv_initvhost(struct lws_vhost* vh, struct lws* wsi)
 
        wsi->w_read.context = vh->context;
        n = uv_poll_init_socket(pt->io_loop_uv,
-                               &wsi->w_read.uv_watcher, wsi->sock);
+                               &wsi->w_read.uv_watcher, wsi->desc.sockfd);
        if (n) {
                lwsl_err("uv_poll_init failed %d, sockfd=%p\n",
-                                n, (void *)(long)wsi->sock);
+                                n, (void *)(long)wsi->desc.sockfd);
 
                return -1;
        }
@@ -318,7 +318,7 @@ lws_libuv_destroyloop(struct lws_context *context, int tsi)
 }
 
 void
-lws_libuv_accept(struct lws *wsi, lws_sockfd_type accept_fd)
+lws_libuv_accept(struct lws *wsi, lws_sock_file_fd_type desc)
 {
        struct lws_context *context = lws_get_context(wsi);
        struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi];
@@ -329,8 +329,12 @@ lws_libuv_accept(struct lws *wsi, lws_sockfd_type accept_fd)
        lwsl_debug("%s: new wsi %p\n", __func__, wsi);
 
        wsi->w_read.context = context;
-
-       uv_poll_init_socket(pt->io_loop_uv, &wsi->w_read.uv_watcher, accept_fd);
+       if (wsi->mode == LWSCM_RAW_FILEDESC)
+               uv_poll_init(pt->io_loop_uv, &wsi->w_read.uv_watcher,
+                            desc.filefd);
+       else
+               uv_poll_init_socket(pt->io_loop_uv, &wsi->w_read.uv_watcher,
+                                   desc.sockfd);
 }
 
 void
index 9c99086..cdc6c28 100755 (executable)
@@ -154,6 +154,15 @@ lws_close_free_wsi(struct lws *wsi, enum lws_close_status reason)
        if (!wsi)
                return;
 
+       if (wsi->mode == LWSCM_RAW_FILEDESC) {
+               remove_wsi_socket_from_fds(wsi);
+               wsi->protocol->callback(wsi,
+                       LWS_CALLBACK_RAW_CLOSE_FILE, wsi->user_space, NULL, 0);
+               lws_free_wsi(wsi);
+
+               return;
+       }
+
        lws_access_log(wsi);
 #if defined(LWS_WITH_ESP8266)
        if (wsi->premature_rx)
@@ -222,7 +231,7 @@ lws_close_free_wsi(struct lws *wsi, enum lws_close_status reason)
 #endif
 
        if (wsi->mode == LWSCM_RAW) {
-               wsi->vhost->protocols->callback(wsi,
+               wsi->protocol->callback(wsi,
                        LWS_CALLBACK_RAW_CLOSE, wsi->user_space, NULL, 0);
                wsi->socket_is_permanently_unusable = 1;
                goto just_kill_connection;
@@ -438,17 +447,17 @@ just_kill_connection:
 #ifdef LWS_OPENSSL_SUPPORT
                if (lws_is_ssl(wsi) && wsi->ssl)
                {
-                       lwsl_info("%s: shutting down SSL connection: %p (ssl %p, sock %d, state %d)\n", __func__, wsi, wsi->ssl, (int)(long)wsi->sock, wsi->state);
+                       lwsl_info("%s: shutting down SSL connection: %p (ssl %p, sock %d, state %d)\n", __func__, wsi, wsi->ssl, (int)(long)wsi->desc.sockfd, wsi->state);
                        n = SSL_shutdown(wsi->ssl);
                        if (n == 0) /* Complete bidirectional SSL shutdown */
                                n = SSL_shutdown(wsi->ssl);
-                       n = shutdown(wsi->sock, SHUT_WR);
+                       n = shutdown(wsi->desc.sockfd, SHUT_WR);
                }
                else
 #endif
                {
-                       lwsl_info("%s: shutting down connection: %p (sock %d, state %d)\n", __func__, wsi, (int)(long)wsi->sock, wsi->state);
-                       n = shutdown(wsi->sock, SHUT_WR);
+                       lwsl_info("%s: shutting down connection: %p (sock %d, state %d)\n", __func__, wsi, (int)(long)wsi->desc.sockfd, wsi->state);
+                       n = shutdown(wsi->desc.sockfd, SHUT_WR);
                }
                if (n)
                        lwsl_debug("closing: shutdown (state %d) ret %d\n", wsi->state, LWS_ERRNO);
@@ -470,7 +479,7 @@ just_kill_connection:
 #endif
 
        lwsl_info("%s: real just_kill_connection: %p (sockfd %d)\n", __func__,
-                 wsi, wsi->sock);
+                 wsi, wsi->desc.sockfd);
        
 #ifdef LWS_WITH_HTTP_PROXY
        if (wsi->rw) {
@@ -487,11 +496,11 @@ just_kill_connection:
        lws_remove_from_timeout_list(wsi);
 
        /* checking return redundant since we anyway close */
-       if (wsi->sock != LWS_SOCK_INVALID)
+       if (wsi->desc.sockfd != LWS_SOCK_INVALID)
                remove_wsi_socket_from_fds(wsi);
 
 #if defined(LWS_WITH_ESP8266)
-       espconn_disconnect(wsi->sock);
+       espconn_disconnect(wsi->desc.sockfd);
 #endif
 
        wsi->state = LWSS_DEAD_SOCKET;
@@ -606,18 +615,18 @@ lws_close_free_wsi_final(struct lws *wsi)
 {
        int n;
 
-       if (!lws_ssl_close(wsi) && lws_socket_is_valid(wsi->sock)) {
+       if (!lws_ssl_close(wsi) && lws_socket_is_valid(wsi->desc.sockfd)) {
 #if LWS_POSIX
-               //lwsl_err("*** closing sockfd %d\n", wsi->sock);
-               n = compatible_close(wsi->sock);
+               //lwsl_err("*** closing sockfd %d\n", wsi->desc.sockfd);
+               n = compatible_close(wsi->desc.sockfd);
                if (n)
                        lwsl_debug("closing: close ret %d\n", LWS_ERRNO);
 
 #else
-               compatible_close(wsi->sock);
+               compatible_close(wsi->desc.sockfd);
                (void)n;
 #endif
-               wsi->sock = LWS_SOCK_INVALID;
+               wsi->desc.sockfd = LWS_SOCK_INVALID;
        }
 
        /* outermost destroy notification for wsi (user_space still intact) */
@@ -786,7 +795,7 @@ lws_get_peer_simple(struct lws *wsi, char *name, int namelen)
        }
 
        olen = len;
-       if (getpeername(wsi->sock, p, &len) < 0 || len > olen) {
+       if (getpeername(wsi->desc.sockfd, p, &len) < 0 || len > olen) {
                lwsl_warn("getpeername: %s\n", strerror(LWS_ERRNO));
                return NULL;
        }
@@ -974,7 +983,7 @@ lws_now_secs(void)
 LWS_VISIBLE int
 lws_get_socket_fd(struct lws *wsi)
 {
-       return wsi->sock;
+       return wsi->desc.sockfd;
 }
 
 #endif
@@ -1976,7 +1985,7 @@ lws_create_basic_wsi(struct lws_context *context, int tsi)
        new_wsi->protocol = context->vhost_list->protocols;
        new_wsi->user_space = NULL;
        new_wsi->ietf_spec_revision = 0;
-       new_wsi->sock = LWS_SOCK_INVALID;
+       new_wsi->desc.sockfd = LWS_SOCK_INVALID;
        context->count_wsi_allocated++;
 
        return new_wsi;
@@ -2024,7 +2033,7 @@ lws_cgi(struct lws *wsi, const char * const *exec_array, int script_uri_path_len
 //                      cgi->pipe_fds[n][!!(n == 0)], cgi->pipe_fds[n][!(n == 0)]);
 
                /* read side is 0, stdin we want the write side, others read */
-               cgi->stdwsi[n]->sock = cgi->pipe_fds[n][!!(n == 0)];
+               cgi->stdwsi[n]->desc.sockfd = cgi->pipe_fds[n][!!(n == 0)];
                if (fcntl(cgi->pipe_fds[n][!!(n == 0)], F_SETFL, O_NONBLOCK) < 0) {
                        lwsl_err("%s: setting NONBLOCK failed\n", __func__);
                        goto bail2;
@@ -2032,7 +2041,7 @@ lws_cgi(struct lws *wsi, const char * const *exec_array, int script_uri_path_len
        }
 
        for (n = 0; n < 3; n++) {
-               lws_libuv_accept(cgi->stdwsi[n], cgi->stdwsi[n]->sock);
+               lws_libuv_accept(cgi->stdwsi[n], cgi->stdwsi[n]->desc);
                if (insert_wsi_socket_into_fds(wsi->context, cgi->stdwsi[n]))
                        goto bail3;
                cgi->stdwsi[n]->parent = wsi;
@@ -2045,8 +2054,9 @@ lws_cgi(struct lws *wsi, const char * const *exec_array, int script_uri_path_len
        lws_change_pollfd(cgi->stdwsi[LWS_STDERR], LWS_POLLOUT, LWS_POLLIN);
 
        lwsl_debug("%s: fds in %d, out %d, err %d\n", __func__,
-                  cgi->stdwsi[LWS_STDIN]->sock, cgi->stdwsi[LWS_STDOUT]->sock,
-                  cgi->stdwsi[LWS_STDERR]->sock);
+                  cgi->stdwsi[LWS_STDIN]->desc.sockfd,
+                  cgi->stdwsi[LWS_STDOUT]->desc.sockfd,
+                  cgi->stdwsi[LWS_STDERR]->desc.sockfd);
 
        lws_set_timeout(wsi, PENDING_TIMEOUT_CGI, timeout_secs);
 
index a9ee567..9d69dd7 100644 (file)
@@ -1059,12 +1059,20 @@ enum lws_callback_reasons {
        LWS_CALLBACK_RAW_WRITEABLE                              = 61,
        /**< RAW mode connection may be written */
        LWS_CALLBACK_RAW_ADOPT                                  = 62,
-       /**< RAW mode connection was adopted (equivalent to 'created') */
+       /**< RAW mode connection was adopted (equivalent to 'wsi created') */
+       LWS_CALLBACK_RAW_ADOPT_FILE                             = 63,
+       /**< RAW mode file was adopted (equivalent to 'wsi created') */
+       LWS_CALLBACK_RAW_RX_FILE                                = 64,
+       /**< RAW mode file has something to read */
+       LWS_CALLBACK_RAW_WRITEABLE_FILE                         = 65,
+       /**< RAW mode file is writeable */
+       LWS_CALLBACK_RAW_CLOSE_FILE                             = 66,
+       /**< RAW mode wsi that adopted a file is closing */
 
        /****** add new things just above ---^ ******/
 
        LWS_CALLBACK_USER = 1000,
-       /**<  user code can use any including above without fear of clashes */
+       /**<  user code can use any including above without fear of clashes */
 };
 
 
@@ -3703,23 +3711,37 @@ lws_adopt_socket(struct lws_context *context, lws_sockfd_type accept_fd);
  */
 LWS_VISIBLE LWS_EXTERN struct lws *
 lws_adopt_socket_vhost(struct lws_vhost *vh, lws_sockfd_type accept_fd);
+
+typedef enum {
+       LWS_ADOPT_HTTP = 1,             /* absent implies RAW */
+       LWS_ADOPT_SOCKET = 2,           /* absent implies file descriptor */
+       LWS_ADOPT_ALLOW_SSL = 4         /* if set requires LWS_ADOPT_SOCKET */
+} lws_adoption_type;
+
+typedef union {
+       lws_sockfd_type sockfd;
+       lws_filefd_type filefd;
+} lws_sock_file_fd_type;
+
 /*
-* lws_adopt_socket_vhost2() - adopt foreign socket as if listen socket accepted it
-* for vhost, allow control over defeat SSL and raw transport mode
+* lws_adopt_descriptor_vhost() - adopt foreign socket or file descriptor
+* if socket descriptor, should already have been accepted from listen socket
+*
 * \param vhost: lws vhost
-* \param accept_fd: fd of already-accepted socket to adopt
-* \param allow_ssl: 0 = no SSL even if vhost supports, 1 = SSL if vhost supports
-* \param raw: 0 = http[s]/wss[s], 1 = raw mode semantics
+* \param type: OR-ed combinations of lws_adoption_type flags
+* \param fd: union with either .sockfd or .filefd set
+* \param vh_prot_name: NULL or vh protocol name to bind raw connection to
 *
 * Either returns new wsi bound to accept_fd, or closes accept_fd and
 * returns NULL, having cleaned up any new wsi pieces.
 *
-* LWS adopts the socket in http serving mode, it's ready to accept an upgrade
-* to ws or just serve http.
+* If LWS_ADOPT_SOCKET is set, LWS adopts the socket in http serving mode, it's
+* ready to accept an upgrade to ws or just serve http.
 */
 LWS_VISIBLE struct lws *
-lws_adopt_socket_vhost2(struct lws_vhost *vh, lws_sockfd_type accept_fd,
-                       int allow_ssl, int raw);
+lws_adopt_descriptor_vhost(struct lws_vhost *vh, lws_adoption_type type,
+                          lws_sock_file_fd_type fd, const char *vh_prot_name);
+
 
 /**
  * lws_adopt_socket_readbuf() - adopt foreign socket and first rx as if listen socket accepted it
@@ -4254,7 +4276,9 @@ struct lws_fop_fd {
 };
 #if defined(WIN32) || defined(_WIN32)
 /* ... */
+#if !defined(ssize_t)
 typedef SSIZE_T ssize_t;
+#endif
 /* !!! >:-[  */
 typedef unsigned __int32 uint32_t;
 typedef unsigned __int8 uint8_t;
index 1c7bb95..bf550be 100644 (file)
@@ -30,9 +30,9 @@ lws_send_pipe_choked(struct lws *wsi)
                return 1;
 
        FD_ZERO(&writefds);
-       FD_SET(wsi->sock, &writefds);
+       FD_SET(wsi->desc.sockfd, &writefds);
 
-       if (select(wsi->sock + 1, NULL, &writefds, NULL, &tv) < 1)
+       if (select(wsi->desc.sockfd + 1, NULL, &writefds, NULL, &tv) < 1)
                return 1;
 
        return 0;
index 497fba1..f868fbc 100644 (file)
@@ -72,7 +72,7 @@ lws_ssl_capable_write_no_ssl(struct lws *wsi, unsigned char *buf, int len)
        //lwsl_notice("%s: wsi %p: len %d\n", __func__, wsi, len);      
        
        wsi->pending_send_completion++;
-       espconn_send(wsi->sock, buf, len);
+       espconn_send(wsi->desc.sockfd, buf, len);
        
        return len;
 }
@@ -247,7 +247,7 @@ esp8266_create_tcp_listen_socket(struct lws_vhost *vh)
 const char *
 lws_plat_get_peer_simple(struct lws *wsi, char *name, int namelen)
 {
-       unsigned char *p = wsi->sock->proto.tcp->remote_ip;
+       unsigned char *p = wsi->desc.sockfd->proto.tcp->remote_ip;
 
        lws_snprintf(name, namelen, "%u.%u.%u.%u", p[0], p[1], p[2], p[3]);
 
@@ -493,7 +493,7 @@ esp8266_tcp_stream_accept(lws_sockfd_type fd, struct lws *wsi)
        fd->reverse = wsi;
 
        for (n = 0; n < wsi->context->max_fds ; n++)
-               if (wsi->context->connpool[n] == wsi->sock)
+               if (wsi->context->connpool[n] == wsi->desc.sockfd)
                        wsi->position_in_fds_table = n;
 }
 
@@ -555,7 +555,7 @@ lws_plat_insert_socket_into_fds(struct lws_context *context, struct lws *wsi)
        struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi];
 
        context->connpool[wsi->position_in_fds_table + context->max_fds] = (lws_sockfd_type)wsi;
-       wsi->sock->reverse = wsi;
+       wsi->desc.sockfd->reverse = wsi;
        pt->fds_count++;
 }
 
@@ -567,13 +567,13 @@ lws_plat_delete_socket_from_fds(struct lws_context *context,
        int n;
        
        for (n = 0; n < wsi->context->max_fds; n++)
-               if (wsi->context->connpool[n] == wsi->sock) {
+               if (wsi->context->connpool[n] == wsi->desc.sockfd) {
                        wsi->context->connpool[n] = NULL;
                        wsi->context->connpool[n + wsi->context->max_fds] = NULL;
                        lwsl_notice(" freed connpool %d\n", n);
                }
        
-       wsi->sock->reverse = NULL;
+       wsi->desc.sockfd->reverse = NULL;
        pt->fds_count--;
 }
 
@@ -596,17 +596,17 @@ lws_plat_change_pollfd(struct lws_context *context,
                        lwsl_notice("replaying buffered rx: wsi %p\n", wsi);
                        p = wsi->premature_rx;
                        wsi->premature_rx = NULL;
-                       esp8266_cb_rx(wsi->sock,
+                       esp8266_cb_rx(wsi->desc.sockfd,
                                      (char *)p + wsi->prem_rx_pos,
                                      wsi->prem_rx_size - wsi->prem_rx_pos);
                        wsi->prem_rx_size = 0;
                        wsi->prem_rx_pos = 0;
                        lws_free(p);
                }
-               if (espconn_recv_unhold(wsi->sock) < 0)
+               if (espconn_recv_unhold(wsi->desc.sockfd) < 0)
                        return -1;
        } else
-               if (espconn_recv_hold(wsi->sock) < 0)
+               if (espconn_recv_hold(wsi->desc.sockfd) < 0)
                        return -1;
        
        if (!(pfd->events & LWS_POLLOUT))
index 20cab5c..c6d42b5 100644 (file)
@@ -29,7 +29,7 @@ lws_send_pipe_choked(struct lws *wsi)
        if (wsi->trunc_len)
                return 1;
 
-       fds.fd = wsi->sock;
+       fds.fd = wsi->desc.sockfd;
        fds.events = POLLOUT;
        fds.revents = 0;
 
index da9940d..ae82941 100644 (file)
@@ -35,7 +35,7 @@ lws_send_pipe_choked(struct lws *wsi)
        if (wsi->trunc_len)
                return 1;
 
-       fds.fd = wsi->sock;
+       fds.fd = wsi->desc.sockfd;
        fds.events = POLLOUT;
        fds.revents = 0;
 
index d7f413d..98f420a 100644 (file)
@@ -50,7 +50,7 @@ wsi_from_fd(const struct lws_context *context, lws_sockfd_type fd)
        int n = 0;
 
        for (n = 0; n < context->fd_hashtable[h].length; n++)
-               if (context->fd_hashtable[h].wsi[n]->sock == fd)
+               if (context->fd_hashtable[h].wsi[n]->desc.sockfd == fd)
                        return context->fd_hashtable[h].wsi[n];
 
        return NULL;
@@ -59,7 +59,7 @@ wsi_from_fd(const struct lws_context *context, lws_sockfd_type fd)
 int
 insert_wsi(struct lws_context *context, struct lws *wsi)
 {
-       int h = LWS_FD_HASH(wsi->sock);
+       int h = LWS_FD_HASH(wsi->desc.sockfd);
 
        if (context->fd_hashtable[h].length == (getdtablesize() - 1)) {
                lwsl_err("hash table overflow\n");
@@ -78,7 +78,7 @@ delete_from_fd(struct lws_context *context, lws_sockfd_type fd)
        int n = 0;
 
        for (n = 0; n < context->fd_hashtable[h].length; n++)
-               if (context->fd_hashtable[h].wsi[n]->sock == fd) {
+               if (context->fd_hashtable[h].wsi[n]->desc.sockfd == fd) {
                        while (n < context->fd_hashtable[h].length) {
                                context->fd_hashtable[h].wsi[n] =
                                                context->fd_hashtable[h].wsi[n + 1];
@@ -417,7 +417,7 @@ lws_plat_insert_socket_into_fds(struct lws_context *context, struct lws *wsi)
 
        pt->fds[pt->fds_count++].revents = 0;
        pt->events[pt->fds_count] = pt->events[0];
-       WSAEventSelect(wsi->sock, pt->events[0],
+       WSAEventSelect(wsi->desc.sockfd, pt->events[0],
                           LWS_POLLIN | LWS_POLLHUP | FD_CONNECT);
 }
 
@@ -441,7 +441,7 @@ lws_plat_check_connection_error(struct lws *wsi)
        int optVal;
        int optLen = sizeof(int);
 
-       if (getsockopt(wsi->sock, SOL_SOCKET, SO_ERROR,
+       if (getsockopt(wsi->desc.sockfd, SOL_SOCKET, SO_ERROR,
                           (char*)&optVal, &optLen) != SOCKET_ERROR && optVal &&
                optVal != LWS_EALREADY && optVal != LWS_EINPROGRESS &&
                optVal != LWS_EWOULDBLOCK && optVal != WSAEINVAL) {
@@ -465,7 +465,7 @@ lws_plat_change_pollfd(struct lws_context *context,
        if ((pfd->events & LWS_POLLOUT))
                networkevents |= LWS_POLLOUT;
 
-       if (WSAEventSelect(wsi->sock,
+       if (WSAEventSelect(wsi->desc.sockfd,
                        pt->events[0],
                                                   networkevents) != SOCKET_ERROR)
                return 0;
index 1e47549..09ceecc 100644 (file)
@@ -133,7 +133,7 @@ int lws_issue_raw(struct lws *wsi, unsigned char *buf, size_t len)
                goto handle_truncated_send;
        }
 
-       if (!lws_socket_is_valid(wsi->sock))
+       if (!lws_socket_is_valid(wsi->desc.sockfd))
                lwsl_warn("** error invalid sock but expected to send\n");
 
        /* limit sending */
@@ -744,7 +744,7 @@ lws_ssl_capable_read_no_ssl(struct lws *wsi, unsigned char *buf, int len)
 {
        int n;
 
-       n = recv(wsi->sock, (char *)buf, len, 0);
+       n = recv(wsi->desc.sockfd, (char *)buf, len, 0);
        if (n >= 0) {
                if (wsi->vhost)
                        wsi->vhost->conn_stats.rx += n;
@@ -767,7 +767,7 @@ lws_ssl_capable_write_no_ssl(struct lws *wsi, unsigned char *buf, int len)
        int n = 0;
 
 #if LWS_POSIX
-       n = send(wsi->sock, (char *)buf, len, MSG_NOSIGNAL);
+       n = send(wsi->desc.sockfd, (char *)buf, len, MSG_NOSIGNAL);
 //     lwsl_info("%s: sent len %d result %d", __func__, len, n);
        if (n >= 0)
                return n;
@@ -789,7 +789,7 @@ lws_ssl_capable_write_no_ssl(struct lws *wsi, unsigned char *buf, int len)
        // !!!
 #endif
 
-       lwsl_debug("ERROR writing len %d to skt fd %d err %d / errno %d\n", len, wsi->sock, n, LWS_ERRNO);
+       lwsl_debug("ERROR writing len %d to skt fd %d err %d / errno %d\n", len, wsi->desc.sockfd, n, LWS_ERRNO);
        return LWS_SSL_CAPABLE_ERROR;
 }
 #endif
index c6b658d..028d96a 100644 (file)
@@ -39,7 +39,7 @@ _lws_change_pollfd(struct lws *wsi, int _and, int _or, struct lws_pollargs *pa)
               wsi->position_in_fds_table < pt->fds_count);
 
        pfd = &pt->fds[wsi->position_in_fds_table];
-       pa->fd = wsi->sock;
+       pa->fd = wsi->desc.sockfd;
        pa->prev_events = pfd->events;
        pa->events = pfd->events = (pfd->events & ~_and) | _or;
 
@@ -132,13 +132,13 @@ lws_accept_modulation(struct lws_context_per_thread *pt, int allow)
 int
 insert_wsi_socket_into_fds(struct lws_context *context, struct lws *wsi)
 {
-       struct lws_pollargs pa = { wsi->sock, LWS_POLLIN, 0 };
+       struct lws_pollargs pa = { wsi->desc.sockfd, LWS_POLLIN, 0 };
        struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi];
        int ret = 0;
 
 
        lwsl_debug("%s: %p: tsi=%d, sock=%d, pos-in-fds=%d\n",
-                 __func__, wsi, wsi->tsi, wsi->sock, pt->fds_count);
+                 __func__, wsi, wsi->tsi, wsi->desc.sockfd, pt->fds_count);
 
        if ((unsigned int)pt->fds_count >= context->fd_limit_per_thread) {
                lwsl_err("Too many fds (%d vs %d)\n", context->max_fds,
@@ -147,16 +147,16 @@ insert_wsi_socket_into_fds(struct lws_context *context, struct lws *wsi)
        }
 
 #if !defined(_WIN32) && !defined(LWS_WITH_ESP8266)
-       if (wsi->sock >= context->max_fds) {
+       if (wsi->desc.sockfd >= context->max_fds) {
                lwsl_err("Socket fd %d is too high (%d)\n",
-                        wsi->sock, context->max_fds);
+                        wsi->desc.sockfd, context->max_fds);
                return 1;
        }
 #endif
 
        assert(wsi);
        assert(wsi->vhost);
-       assert(lws_socket_is_valid(wsi->sock));
+       assert(lws_socket_is_valid(wsi->desc.sockfd));
 
        if (wsi->vhost->protocols[0].callback(wsi, LWS_CALLBACK_LOCK_POLL,
                                           wsi->user_space, (void *) &pa, 1))
@@ -172,7 +172,7 @@ insert_wsi_socket_into_fds(struct lws_context *context, struct lws *wsi)
 
        // lwsl_notice("%s: %p: setting posinfds %d\n", __func__, wsi, wsi->position_in_fds_table);
 
-       pt->fds[wsi->position_in_fds_table].fd = wsi->sock;
+       pt->fds[wsi->position_in_fds_table].fd = wsi->desc.sockfd;
 #if LWS_POSIX
        pt->fds[wsi->position_in_fds_table].events = LWS_POLLIN;
 #else
@@ -204,7 +204,7 @@ int
 remove_wsi_socket_from_fds(struct lws *wsi)
 {
        struct lws_context *context = wsi->context;
-       struct lws_pollargs pa = { wsi->sock, 0, 0 };
+       struct lws_pollargs pa = { wsi->desc.sockfd, 0, 0 };
 #if !defined(LWS_WITH_ESP8266)
        struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi];
        struct lws *end_wsi;
@@ -213,8 +213,8 @@ remove_wsi_socket_from_fds(struct lws *wsi)
        int m, ret = 0;
 
 #if !defined(_WIN32) && !defined(LWS_WITH_ESP8266)
-       if (wsi->sock > context->max_fds) {
-               lwsl_err("fd %d too high (%d)\n", wsi->sock, context->max_fds);
+       if (wsi->desc.sockfd > context->max_fds) {
+               lwsl_err("fd %d too high (%d)\n", wsi->desc.sockfd, context->max_fds);
                return 1;
        }
 #endif
@@ -259,7 +259,7 @@ remove_wsi_socket_from_fds(struct lws *wsi)
        lws_pt_lock(pt);
 
        lwsl_debug("%s: wsi=%p, sock=%d, fds pos=%d, end guy pos=%d, endfd=%d\n",
-                 __func__, wsi, wsi->sock, wsi->position_in_fds_table,
+                 __func__, wsi, wsi->desc.sockfd, wsi->position_in_fds_table,
                  pt->fds_count, pt->fds[pt->fds_count].fd);
 
        /* have the last guy take up the now vacant slot */
@@ -278,12 +278,12 @@ remove_wsi_socket_from_fds(struct lws *wsi)
                end_wsi->position_in_fds_table = m;
 
        /* deletion guy's lws_lookup entry needs nuking */
-       delete_from_fd(context, wsi->sock);
+       delete_from_fd(context, wsi->desc.sockfd);
        /* removed wsi has no position any more */
        wsi->position_in_fds_table = -1;
 
        /* remove also from external POLL support via protocol 0 */
-       if (lws_socket_is_valid(wsi->sock))
+       if (lws_socket_is_valid(wsi->desc.sockfd))
                if (wsi->vhost->protocols[0].callback(wsi, LWS_CALLBACK_DEL_POLL_FD,
                                                   wsi->user_space, (void *) &pa, 0))
                        ret = -1;
@@ -396,7 +396,7 @@ network_sock:
                return 1;
 
        if (wsi->position_in_fds_table < 0) {
-               lwsl_err("%s: failed to find socket %d\n", __func__, wsi->sock);
+               lwsl_err("%s: failed to find socket %d\n", __func__, wsi->desc.sockfd);
                return -1;
        }
 
index 1f72f6a..8d94c0d 100644 (file)
@@ -543,7 +543,8 @@ enum connection_mode {
        /* special internal types */
        LWSCM_SERVER_LISTENER,
        LWSCM_CGI, /* stdin, stdout, stderr for another cgi master wsi */
-       LWSCM_RAW, /* raw */
+       LWSCM_RAW, /* raw with bulk handling */
+       LWSCM_RAW_FILEDESC, /* raw without bulk handling */
 
        /* HTTP Client related */
        LWSCM_HTTP_CLIENT = LWSCM_FLAG_IMPLIES_CALLBACK_CLOSED_CLIENT_HTTP,
@@ -928,8 +929,7 @@ enum {
 
 #if defined(LWS_USE_LIBEV)
 LWS_EXTERN void
-lws_libev_accept(struct lws *new_wsi, lws_sockfd_type accept_fd);
-LWS_EXTERN void
+lws_libev_accept(struct lws *new_wsi, lws_sock_file_fd_type desc);
 lws_libev_io(struct lws *wsi, int flags);
 LWS_EXTERN int
 lws_libev_init_fd_table(struct lws_context *context);
@@ -956,7 +956,7 @@ LWS_EXTERN void lws_feature_status_libev(struct lws_context_creation_info *info)
 
 #if defined(LWS_USE_LIBUV)
 LWS_EXTERN void
-lws_libuv_accept(struct lws *new_wsi, lws_sockfd_type accept_fd);
+lws_libuv_accept(struct lws *new_wsi, lws_sock_file_fd_type desc);
 LWS_EXTERN void
 lws_libuv_io(struct lws *wsi, int flags);
 LWS_EXTERN int
@@ -1408,8 +1408,7 @@ struct lws {
        unsigned long action_start;
        unsigned long latency_start;
 #endif
-       /* pointer / int */
-       lws_sockfd_type sock;
+       lws_sock_file_fd_type desc; /* .filefd / .sockfd */
 
        /* ints */
        int position_in_fds_table;
@@ -1562,7 +1561,7 @@ LWS_EXTERN int
 delete_from_fd(struct lws_context *context, lws_sockfd_type fd);
 #else
 #define wsi_from_fd(A,B)  A->lws_lookup[B]
-#define insert_wsi(A,B)   assert(A->lws_lookup[B->sock] == 0); A->lws_lookup[B->sock]=B
+#define insert_wsi(A,B)   assert(A->lws_lookup[B->desc.sockfd] == 0); A->lws_lookup[B->desc.sockfd]=B
 #define delete_from_fd(A,B) A->lws_lookup[B]=0
 #endif
 
index 2416220..ddf7228 100644 (file)
@@ -142,7 +142,7 @@ lws_context_init_server(struct lws_context_creation_info *info,
                goto bail;
        }
        wsi->context = vhost->context;
-       wsi->sock = sockfd;
+       wsi->desc.sockfd = sockfd;
        wsi->mode = LWSCM_SERVER_LISTENER;
        wsi->protocol = vhost->protocols;
        wsi->tsi = m;
@@ -161,7 +161,7 @@ lws_context_init_server(struct lws_context_creation_info *info,
        vhost->lserv_wsi = wsi;
 
 #if LWS_POSIX
-       n = listen(wsi->sock, LWS_SOMAXCONN);
+       n = listen(wsi->desc.sockfd, LWS_SOMAXCONN);
        if (n < 0) {
                lwsl_err("listen failed with error %d\n", LWS_ERRNO);
                vhost->lserv_wsi = NULL;
@@ -172,7 +172,7 @@ lws_context_init_server(struct lws_context_creation_info *info,
        } /* for each thread able to independently listen */
 #else
 #if defined(LWS_WITH_ESP8266)
-       esp8266_tcp_stream_bind(wsi->sock, info->port, wsi);
+       esp8266_tcp_stream_bind(wsi->desc.sockfd, info->port, wsi);
 #endif
 #endif
        if (!lws_check_opt(info->options, LWS_SERVER_OPTION_EXPLICIT_VHOSTS)) {
@@ -1502,7 +1502,7 @@ upgrade_ws:
                wsi->u.ws.rx_ubuf_alloc = n;
                lwsl_debug("Allocating RX buffer %d\n", n);
 #if LWS_POSIX && !defined(LWS_WITH_ESP32)
-               if (setsockopt(wsi->sock, SOL_SOCKET, SO_SNDBUF,
+               if (setsockopt(wsi->desc.sockfd, SOL_SOCKET, SO_SNDBUF,
                               (const char *)&n, sizeof n)) {
                        lwsl_warn("Failed to set SNDBUF to %d", n);
                        return 1;
@@ -1611,7 +1611,7 @@ lws_create_new_server_wsi(struct lws_vhost *vhost)
        new_wsi->protocol = vhost->protocols;
        new_wsi->user_space = NULL;
        new_wsi->ietf_spec_revision = 0;
-       new_wsi->sock = LWS_SOCK_INVALID;
+       new_wsi->desc.sockfd = LWS_SOCK_INVALID;
        vhost->context->count_wsi_allocated++;
 
        /*
@@ -1686,33 +1686,56 @@ lws_http_transaction_completed(struct lws *wsi)
        return 0;
 }
 
+/* if not a socket, it's a raw, non-ssl file descriptor */
+
 LWS_VISIBLE struct lws *
-lws_adopt_socket_vhost2(struct lws_vhost *vh, lws_sockfd_type accept_fd,
-                       int allow_ssl, int raw)
+lws_adopt_descriptor_vhost(struct lws_vhost *vh, lws_adoption_type type,
+                          lws_sock_file_fd_type fd, const char *vh_prot_name)
 {
        struct lws_context *context = vh->context;
        struct lws *new_wsi = lws_create_new_server_wsi(vh);
-       int n;
+       int n, ssl = 0;
 
        if (!new_wsi) {
-               compatible_close(accept_fd);
+               if (type & LWS_ADOPT_SOCKET)
+                       compatible_close(fd.sockfd);
                return NULL;
        }
 
-       lwsl_debug("%s: new wsi %p, sockfd %d, cb %p\n", __func__, new_wsi,
-                  accept_fd, context->vhost_list->protocols[0].callback);
+       new_wsi->desc = fd;
+       new_wsi->protocol = &context->vhost_list->
+                       protocols[vh->default_protocol_index];
+
+       if (!(type & LWS_ADOPT_SOCKET)) {
+               new_wsi->protocol = lws_vhost_name_to_protocol(new_wsi->vhost,
+                               vh_prot_name);
+               if (!new_wsi->protocol) {
+                       lwsl_err("Protocol %s not enabled on vhost %s\n",
+                                vh_prot_name, new_wsi->vhost->name);
+                       lws_free(new_wsi);
+
+                       return NULL;
+               }
+       }
+       if (type & LWS_ADOPT_SOCKET) {
+
+               lwsl_debug("%s: new wsi %p, sockfd %d\n", __func__, new_wsi,
+                          (int)(size_t)fd.sockfd);
 
-       new_wsi->sock = accept_fd;
 
-       /* the transport is accepted... give him time to negotiate */
-       lws_set_timeout(new_wsi, PENDING_TIMEOUT_ESTABLISH_WITH_SERVER,
-                       context->timeout_secs);
+               /* the transport is accepted... give him time to negotiate */
+               lws_set_timeout(new_wsi, PENDING_TIMEOUT_ESTABLISH_WITH_SERVER,
+                               context->timeout_secs);
 
 #if LWS_POSIX == 0
 #if defined(LWS_WITH_ESP8266)
-       esp8266_tcp_stream_accept(accept_fd, new_wsi);
+               esp8266_tcp_stream_accept(accept_fd, new_wsi);
 #endif
 #endif
+       } else  //* file desc */
+               lwsl_debug("%s: new wsi %p, filefd %d\n", __func__, new_wsi,
+                          (int)(size_t)fd.filefd);
+
        /*
         * A new connection was accepted. Give the user a chance to
         * set properties of the newly created wsi. There's no protocol
@@ -1720,45 +1743,65 @@ lws_adopt_socket_vhost2(struct lws_vhost *vh, lws_sockfd_type accept_fd,
         * itself by default protocols[0]
         */
        n = LWS_CALLBACK_SERVER_NEW_CLIENT_INSTANTIATED;
-       if (raw)
-               n = LWS_CALLBACK_RAW_ADOPT;
-       if ((context->vhost_list->protocols[vh->default_protocol_index].callback)(
+       if (!(type & LWS_ADOPT_HTTP)) {
+               if (!(type & LWS_ADOPT_SOCKET))
+                       n = LWS_CALLBACK_RAW_ADOPT_FILE;
+               else
+                       n = LWS_CALLBACK_RAW_ADOPT;
+       }
+       if ((new_wsi->protocol->callback)(
                        new_wsi, n, NULL, NULL, 0)) {
-               /* force us off the timeout list by hand */
-               lws_set_timeout(new_wsi, NO_PENDING_TIMEOUT, 0);
-               compatible_close(new_wsi->sock);
+               if (type & LWS_ADOPT_SOCKET) {
+                       /* force us off the timeout list by hand */
+                       lws_set_timeout(new_wsi, NO_PENDING_TIMEOUT, 0);
+                       compatible_close(new_wsi->desc.sockfd);
+               }
                lws_free(new_wsi);
                return NULL;
        }
 
-       lws_libev_accept(new_wsi, new_wsi->sock);
-       lws_libuv_accept(new_wsi, new_wsi->sock);
-
-       if (!LWS_SSL_ENABLED(new_wsi->vhost) || allow_ssl == 0) {
-               if (raw)
-                       new_wsi->mode = LWSCM_RAW;
-               if (insert_wsi_socket_into_fds(context, new_wsi)) {
-                       lwsl_err("%s: fail inserting socket\n", __func__);
-                       goto fail;
+       if (!LWS_SSL_ENABLED(new_wsi->vhost) || !(type & LWS_ADOPT_ALLOW_SSL) ||
+           !(type & LWS_ADOPT_SOCKET)) {
+               /* non-SSL */
+               if (!(type & LWS_ADOPT_HTTP)) {
+                       if (!(type & LWS_ADOPT_SOCKET))
+                               new_wsi->mode = LWSCM_RAW_FILEDESC;
+                       else
+                               new_wsi->mode = LWSCM_RAW;
                }
        } else {
-               if (raw)
+               /* SSL */
+               if (!(type & LWS_ADOPT_HTTP))
                        new_wsi->mode = LWSCM_SSL_INIT_RAW;
                else
                        new_wsi->mode = LWSCM_SSL_INIT;
-               if (lws_server_socket_service_ssl(new_wsi, accept_fd)) {
+
+               ssl = 1;
+       }
+
+       lws_libev_accept(new_wsi, new_wsi->desc);
+       lws_libuv_accept(new_wsi, new_wsi->desc);
+
+       if (!ssl) {
+               if (insert_wsi_socket_into_fds(context, new_wsi)) {
+                       lwsl_err("%s: fail inserting socket\n", __func__);
+                       goto fail;
+               }
+       } else
+               if (lws_server_socket_service_ssl(new_wsi, fd.sockfd)) {
                        lwsl_err("%s: fail ssl negotiation\n", __func__);
                        goto fail;
                }
-       }
 
-       if (!lws_header_table_attach(new_wsi, 0))
-               lwsl_debug("Attached ah immediately\n");
+       if (type & LWS_ADOPT_HTTP)
+               if (!lws_header_table_attach(new_wsi, 0))
+                       lwsl_debug("Attached ah immediately\n");
 
        return new_wsi;
 
 fail:
-       lws_close_free_wsi(new_wsi, LWS_CLOSE_STATUS_NOSTATUS);
+       if (type & LWS_ADOPT_SOCKET)
+               lws_close_free_wsi(new_wsi, LWS_CLOSE_STATUS_NOSTATUS);
 
        return NULL;
 }
@@ -1766,13 +1809,17 @@ fail:
 LWS_VISIBLE struct lws *
 lws_adopt_socket_vhost(struct lws_vhost *vh, lws_sockfd_type accept_fd)
 {
-       return lws_adopt_socket_vhost2(vh, accept_fd, 1, 0);
+       lws_sock_file_fd_type fd;
+
+       fd.sockfd = accept_fd;
+       return lws_adopt_descriptor_vhost(vh, LWS_ADOPT_SOCKET |
+                       LWS_ADOPT_HTTP | LWS_ADOPT_ALLOW_SSL, fd, NULL);
 }
 
 LWS_VISIBLE struct lws *
 lws_adopt_socket(struct lws_context *context, lws_sockfd_type accept_fd)
 {
-       return lws_adopt_socket_vhost2(context->vhost_list, accept_fd, 1, 0);
+       return lws_adopt_socket_vhost(context->vhost_list, accept_fd);
 }
 
 /* Common read-buffer adoption for lws_adopt_*_readbuf */
index 931e8d3..48726c1 100644 (file)
@@ -30,6 +30,9 @@ lws_calllback_as_writeable(struct lws *wsi)
        case LWSCM_RAW:
                n = LWS_CALLBACK_RAW_WRITEABLE;
                break;
+       case LWSCM_RAW_FILEDESC:
+               n = LWS_CALLBACK_RAW_WRITEABLE_FILE;
+               break;
        case LWSCM_WS_CLIENT:
                n = LWS_CALLBACK_CLIENT_WRITEABLE;
                break;
@@ -198,7 +201,7 @@ lws_handle_POLLOUT_event(struct lws *wsi, struct lws_pollfd *pollfd)
         */
 
        ret = 1;
-       if (wsi->mode == LWSCM_RAW)
+       if (wsi->mode == LWSCM_RAW || wsi->mode == LWSCM_RAW_FILEDESC)
                ret = 0;
        while (ret == 1) {
 
@@ -366,7 +369,7 @@ lws_service_timeout_check(struct lws *wsi, unsigned int sec)
         */
        if ((time_t)sec > wsi->pending_timeout_limit) {
 //#if LWS_POSIX
-               if (wsi->sock != LWS_SOCK_INVALID && wsi->position_in_fds_table >= 0)
+               if (wsi->desc.sockfd != LWS_SOCK_INVALID && wsi->position_in_fds_table >= 0)
                        n = pt->fds[wsi->position_in_fds_table].events;
 
                /* no need to log normal idle keepalive timeout */
@@ -734,7 +737,7 @@ lws_service_fd_tsi(struct lws_context *context, struct lws_pollfd *pollfd, int t
                while (wsi) {
                        /* we have to take copies, because he may be deleted */
                        wsi1 = wsi->timeout_list;
-                       tmp_fd = wsi->sock;
+                       tmp_fd = wsi->desc.sockfd;
                        if (lws_service_timeout_check(wsi, (unsigned int)now)) {
                                /* he did time out... */
                                if (tmp_fd == our_fd)
@@ -863,17 +866,42 @@ lws_service_fd_tsi(struct lws_context *context, struct lws_pollfd *pollfd, int t
                        return 1;
                goto handled;
 
+       case LWSCM_RAW_FILEDESC:
+       case LWSCM_RAW:
+               if (pollfd->revents & LWS_POLLOUT) {
+                       n = lws_calllback_as_writeable(wsi);
+                       if (lws_change_pollfd(wsi, LWS_POLLOUT, 0)) {
+                               lwsl_info("failed at set pollfd\n");
+                               return 1;
+                       }
+                       if (n)
+                               goto close_and_handled;
+               }
+               n = LWS_CALLBACK_RAW_RX;
+               if (wsi->mode == LWSCM_RAW_FILEDESC)
+                       n = LWS_CALLBACK_RAW_RX_FILE;
+
+               if (pollfd->revents & LWS_POLLIN) {
+                       if (user_callback_handle_rxflow(
+                                       wsi->protocol->callback,
+                                       wsi, n,
+                                       wsi->user_space, NULL, 0)) {
+                               lwsl_debug("raw rx callback closed it\n");
+                               goto close_and_handled;
+                       }
+               }
+               n = 0;
+               goto handled;
+
        case LWSCM_WS_SERVING:
        case LWSCM_WS_CLIENT:
        case LWSCM_HTTP2_SERVING:
        case LWSCM_HTTP_CLIENT_ACCEPTED:
-       case LWSCM_RAW:
 
                /* 1: something requested a callback when it was OK to write */
 
                if ((pollfd->revents & LWS_POLLOUT) &&
-                   ((wsi->mode == LWSCM_RAW) ||
-                   (wsi->state == LWSS_ESTABLISHED ||
+                   ((wsi->state == LWSS_ESTABLISHED ||
                     wsi->state == LWSS_HTTP2_ESTABLISHED ||
                     wsi->state == LWSS_HTTP2_ESTABLISHED_PRE_SETTINGS ||
                     wsi->state == LWSS_RETURNED_CLOSE_ALREADY ||
index b204495..6cbfd78 100644 (file)
@@ -184,7 +184,7 @@ lws_ssl_client_bio_create(struct lws *wsi)
 #endif
 #endif /* USE_WOLFSSL */
 
-       wsi->client_bio = BIO_new_socket(wsi->sock, BIO_NOCLOSE);
+       wsi->client_bio = BIO_new_socket(wsi->desc.sockfd, BIO_NOCLOSE);
        SSL_set_bio(wsi->ssl, wsi->client_bio, wsi->client_bio);
 
 #ifdef USE_WOLFSSL
index 9ae6b66..3b6c4a0 100644 (file)
--- a/lib/ssl.c
+++ b/lib/ssl.c
@@ -470,7 +470,7 @@ lws_server_socket_service_ssl(struct lws *wsi, lws_sockfd_type accept_fd)
 
                lws_latency_pre(context, wsi);
 
-               n = recv(wsi->sock, (char *)pt->serv_buf, context->pt_serv_buf_size,
+               n = recv(wsi->desc.sockfd, (char *)pt->serv_buf, context->pt_serv_buf_size,
                         MSG_PEEK);
 
                /*
@@ -550,7 +550,7 @@ go_again:
                        break;
                }
 
-                lwsl_err("SSL_accept failed socket %u: %s\n", wsi->sock,
+                lwsl_err("SSL_accept failed socket %u: %s\n", wsi->desc.sockfd,
                          lws_ssl_get_error_string(m, n, buf, sizeof(buf)));
                lws_ssl_elaborate_error();
                goto fail;
diff --git a/plugins/protocol_lws_raw_test.c b/plugins/protocol_lws_raw_test.c
new file mode 100644 (file)
index 0000000..1655750
--- /dev/null
@@ -0,0 +1,227 @@
+/*
+ * ws protocol handler plugin for testing raw file and raw socket
+ *
+ * Copyright (C) 2010-2017 Andy Green <andy@warmcat.com>
+ *
+ * This file is made available under the Creative Commons CC0 1.0
+ * Universal Public Domain Dedication.
+ *
+ * The person who associated a work with this deed has dedicated
+ * the work to the public domain by waiving all of his or her rights
+ * to the work worldwide under copyright law, including all related
+ * and neighboring rights, to the extent allowed by law. You can copy,
+ * modify, distribute and perform the work, even for commercial purposes,
+ * all without asking permission.
+ *
+ * These test plugins are intended to be adapted for use in your code, which
+ * may be proprietary.  So unlike the library itself, they are licensed
+ * Public Domain.
+ *
+ * Enable on a vhost like this
+ *
+ *        "protocol-lws-raw-test": {
+ *                 "status": "ok",
+ *                 "fifo-path": "/tmp/lws-test-raw"
+ *        },
+ *
+ * Then you can feed it data through the FIFO like this
+ *
+ *  $ sudo sh -c "echo hello > /tmp/lws-test-raw"
+ *
+ * This plugin simply prints the data.  But it does it through the lws event loop /
+ * service poll.
+ */
+
+#if !defined (LWS_PLUGIN_STATIC)
+#define LWS_DLL
+#define LWS_INTERNAL
+#include "../lib/libwebsockets.h"
+#endif
+
+#include <string.h>
+
+struct per_vhost_data__raw_test {
+       struct lws_context *context;
+       struct lws_vhost *vhost;
+       const struct lws_protocols *protocol;
+       char fifo_path[100];
+       int fifo;
+       char zero_length_read;
+};
+
+struct per_session_data__raw_test {
+       int number;
+};
+
+static int
+callback_raw_test(struct lws *wsi, enum lws_callback_reasons reason,
+                       void *user, void *in, size_t len)
+{
+       struct per_session_data__raw_test *pss =
+                       (struct per_session_data__raw_test *)user;
+       struct per_vhost_data__raw_test *vhd =
+                       (struct per_vhost_data__raw_test *)
+                       lws_protocol_vh_priv_get(lws_get_vhost(wsi),
+                                       lws_get_protocol(wsi));
+       lws_sock_file_fd_type u;
+
+       (void)pss;
+
+       switch (reason) {
+       case LWS_CALLBACK_PROTOCOL_INIT:
+               vhd = lws_protocol_vh_priv_zalloc(lws_get_vhost(wsi),
+                               lws_get_protocol(wsi),
+                               sizeof(struct per_vhost_data__raw_test));
+               vhd->context = lws_get_context(wsi);
+               vhd->protocol = lws_get_protocol(wsi);
+               vhd->vhost = lws_get_vhost(wsi);
+               {
+                       const struct lws_protocol_vhost_options *pvo =
+                                       (const struct lws_protocol_vhost_options *)in;
+                       while (pvo) {
+                               if (!strcmp(pvo->name, "fifo-path"))
+                                       strncpy(vhd->fifo_path, pvo->value, sizeof(vhd->fifo_path) - 1);
+                               pvo = pvo->next;
+                       }
+                       if (vhd->fifo_path[0] == '\0') {
+                               lwsl_err("Missing pvo \"fifo-path\"\n");
+                               return 1;
+                       }
+               }
+               unlink(vhd->fifo_path);
+               if (mkfifo(vhd->fifo_path, 0666)) {
+                       lwsl_err("mkfifo failed\n");
+                       return 1;
+               }
+               vhd->fifo = open(vhd->fifo_path, O_NONBLOCK | O_RDONLY);
+               if (vhd->fifo == -1) {
+                       lwsl_err("opening fifo failed\n");
+                       unlink(vhd->fifo_path);
+                       return 1;
+               }
+               lwsl_notice("FIFO %s created\n", vhd->fifo_path);
+               u.filefd = vhd->fifo;
+               if (!lws_adopt_descriptor_vhost(vhd->vhost, 0, u, "protocol-lws-raw-test")) {
+                       lwsl_err("Failed to adopt fifo descriptor\n");
+                       close(vhd->fifo);
+                       unlink(vhd->fifo_path);
+                       return 1;
+               }
+               break;
+
+       case LWS_CALLBACK_PROTOCOL_DESTROY:
+               if (!vhd)
+                       break;
+               if (vhd->fifo >- 0) {
+                       close(vhd->fifo);
+                       unlink(vhd->fifo_path);
+               }
+               break;
+
+       case LWS_CALLBACK_RAW_ADOPT_FILE:
+               lwsl_notice("LWS_CALLBACK_RAW_ADOPT_FILE\n");
+               break;
+
+
+       case LWS_CALLBACK_RAW_RX_FILE:
+               lwsl_notice("LWS_CALLBACK_RAW_RX_FILE\n");
+               {
+                       char buf[256];
+                       int n;
+                       
+                       n = read(vhd->fifo, buf, sizeof(buf) - 1);
+                       if (n < 0) {
+                               lwsl_err("FIFO read failed\n");
+                               return 1;
+                       }
+                       /*
+                        * When nobody opened the other side of the FIFO, the FIFO fd acts well and
+                        * only signals POLLIN when somebody opened and wrote to it.
+                        *
+                        * But if the other side of the FIFO closed it, we will see an endless
+                        * POLLIN and 0 available to read.
+                        *
+                        * The only way to handle it is to reopen the FIFO our side and wait for a
+                        * new peer.  This is a quirk of FIFOs not of LWS.
+                        */
+                       if (n == 0) { /* peer closed - do reopen in close processing */
+                               vhd->zero_length_read = 1;
+                               return 1;
+                       }
+                       buf[n] = '\0';
+                       lwsl_info("read %d\n", n);
+                       puts(buf);
+               }
+               break;
+
+       case LWS_CALLBACK_RAW_CLOSE_FILE:
+               lwsl_notice("LWS_CALLBACK_RAW_CLOSE_FILE\n");
+               if (vhd->zero_length_read) {
+                       vhd->zero_length_read = 0;
+                       close(vhd->fifo);
+                       /* the wsi that adopted the fifo file is closing... reopen the fifo and readopt */
+                       vhd->fifo = open(vhd->fifo_path, O_NONBLOCK | O_RDONLY);
+                       if (vhd->fifo == -1) {
+                               lwsl_err("opening fifo failed\n");
+                               return 1;
+                       }
+                       lwsl_notice("FIFO %s reopened\n", vhd->fifo_path);
+                       u.filefd = vhd->fifo;
+                       if (!lws_adopt_descriptor_vhost(vhd->vhost, 0, u, "protocol-lws-raw-test")) {
+                               lwsl_err("Failed to adopt fifo descriptor\n");
+                               close(vhd->fifo);
+                               return 1;
+                       }
+               }
+               break;
+
+       case LWS_CALLBACK_RAW_WRITEABLE_FILE:
+               lwsl_notice("LWS_CALLBACK_RAW_WRITEABLE_FILE\n");
+               break;
+
+       default:
+               break;
+       }
+
+       return 0;
+}
+
+#define LWS_PLUGIN_PROTOCOL_RAW_TEST \
+       { \
+               "protocol-lws-raw-test", \
+               callback_raw_test, \
+               sizeof(struct per_session_data__raw_test), \
+               1024, /* rx buf size must be >= permessage-deflate rx size */ \
+       }
+
+#if !defined (LWS_PLUGIN_STATIC)
+               
+static const struct lws_protocols protocols[] = {
+       LWS_PLUGIN_PROTOCOL_RAW_TEST
+};
+
+LWS_EXTERN LWS_VISIBLE int
+init_protocol_lws_raw_test(struct lws_context *context,
+                            struct lws_plugin_capability *c)
+{
+       if (c->api_magic != LWS_PLUGIN_API_MAGIC) {
+               lwsl_err("Plugin API %d, library API %d", LWS_PLUGIN_API_MAGIC,
+                        c->api_magic);
+               return 1;
+       }
+
+       c->protocols = protocols;
+       c->count_protocols = ARRAY_SIZE(protocols);
+       c->extensions = NULL;
+       c->count_extensions = 0;
+
+       return 0;
+}
+
+LWS_EXTERN LWS_VISIBLE int
+destroy_protocol_lws_raw_test(struct lws_context *context)
+{
+       return 0;
+}
+
+#endif