From be8d791b5e5e601207011c0454371dcb97e28b53 Mon Sep 17 00:00:00 2001 From: Andy Green Date: Mon, 27 Feb 2017 12:55:56 +0800 Subject: [PATCH] adoption: make union for socket and file fds 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. --- CMakeLists.txt | 4 + lib/client-handshake.c | 32 +++--- lib/client.c | 4 +- lib/libev.c | 14 ++- lib/libuv.c | 14 ++- lib/libwebsockets.c | 50 +++++---- lib/libwebsockets.h | 46 ++++++-- lib/lws-plat-esp32.c | 4 +- lib/lws-plat-esp8266.c | 18 ++-- lib/lws-plat-optee.c | 2 +- lib/lws-plat-unix.c | 2 +- lib/lws-plat-win.c | 12 +-- lib/output.c | 8 +- lib/pollfd.c | 28 ++--- lib/private-libwebsockets.h | 13 ++- lib/server.c | 125 +++++++++++++++------- lib/service.c | 40 +++++-- lib/ssl-client.c | 2 +- lib/ssl.c | 4 +- plugins/protocol_lws_raw_test.c | 227 ++++++++++++++++++++++++++++++++++++++++ 20 files changed, 499 insertions(+), 150 deletions(-) create mode 100644 plugins/protocol_lws_raw_test.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 579a29c..95f473e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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 diff --git a/lib/client-handshake.c b/lib/client-handshake.c index 3339a1d..acb8044 100644 --- a/lib/client-handshake.c +++ b/lib/client-handshake.c @@ -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 diff --git a/lib/client.c b/lib/client.c index d42a47e..57b79f4 100755 --- a/lib/client.c +++ b/lib/client.c @@ -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"; diff --git a/lib/libev.c b/lib/libev.c index 39242bb..3f882b2 100644 --- a/lib/libev.c +++ b/lib/libev.c @@ -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 diff --git a/lib/libuv.c b/lib/libuv.c index 5572e0a..24f24ce 100644 --- a/lib/libuv.c +++ b/lib/libuv.c @@ -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 diff --git a/lib/libwebsockets.c b/lib/libwebsockets.c index 9c99086..cdc6c28 100755 --- a/lib/libwebsockets.c +++ b/lib/libwebsockets.c @@ -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); diff --git a/lib/libwebsockets.h b/lib/libwebsockets.h index a9ee567..9d69dd7 100644 --- a/lib/libwebsockets.h +++ b/lib/libwebsockets.h @@ -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; diff --git a/lib/lws-plat-esp32.c b/lib/lws-plat-esp32.c index 1c7bb95..bf550be 100644 --- a/lib/lws-plat-esp32.c +++ b/lib/lws-plat-esp32.c @@ -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; diff --git a/lib/lws-plat-esp8266.c b/lib/lws-plat-esp8266.c index 497fba1..f868fbc 100644 --- a/lib/lws-plat-esp8266.c +++ b/lib/lws-plat-esp8266.c @@ -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)) diff --git a/lib/lws-plat-optee.c b/lib/lws-plat-optee.c index 20cab5c..c6d42b5 100644 --- a/lib/lws-plat-optee.c +++ b/lib/lws-plat-optee.c @@ -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; diff --git a/lib/lws-plat-unix.c b/lib/lws-plat-unix.c index da9940d..ae82941 100644 --- a/lib/lws-plat-unix.c +++ b/lib/lws-plat-unix.c @@ -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; diff --git a/lib/lws-plat-win.c b/lib/lws-plat-win.c index d7f413d..98f420a 100644 --- a/lib/lws-plat-win.c +++ b/lib/lws-plat-win.c @@ -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; diff --git a/lib/output.c b/lib/output.c index 1e47549..09ceecc 100644 --- a/lib/output.c +++ b/lib/output.c @@ -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 diff --git a/lib/pollfd.c b/lib/pollfd.c index c6b658d..028d96a 100644 --- a/lib/pollfd.c +++ b/lib/pollfd.c @@ -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; } diff --git a/lib/private-libwebsockets.h b/lib/private-libwebsockets.h index 1f72f6a..8d94c0d 100644 --- a/lib/private-libwebsockets.h +++ b/lib/private-libwebsockets.h @@ -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 diff --git a/lib/server.c b/lib/server.c index 2416220..ddf7228 100644 --- a/lib/server.c +++ b/lib/server.c @@ -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 */ diff --git a/lib/service.c b/lib/service.c index 931e8d3..48726c1 100644 --- a/lib/service.c +++ b/lib/service.c @@ -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 || diff --git a/lib/ssl-client.c b/lib/ssl-client.c index b204495..6cbfd78 100644 --- a/lib/ssl-client.c +++ b/lib/ssl-client.c @@ -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 diff --git a/lib/ssl.c b/lib/ssl.c index 9ae6b66..3b6c4a0 100644 --- 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 index 0000000..1655750 --- /dev/null +++ b/plugins/protocol_lws_raw_test.c @@ -0,0 +1,227 @@ +/* + * ws protocol handler plugin for testing raw file and raw socket + * + * Copyright (C) 2010-2017 Andy Green + * + * 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 + +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 -- 2.7.4