From cf9bb9428f0065cf0ca8ef2c726933b4db2385f1 Mon Sep 17 00:00:00 2001 From: "Evgeny Grin (Karlson2k)" Date: Wed, 1 Mar 2017 23:43:00 +0300 Subject: Watch "upgraded" sockets for OOB data and disconnects. Currently states are only monitored. States processing have to be added. --- src/microhttpd/daemon.c | 281 ++++++++++++++++++++++++++++------------------ src/microhttpd/response.c | 6 +- 2 files changed, 176 insertions(+), 111 deletions(-) diff --git a/src/microhttpd/daemon.c b/src/microhttpd/daemon.c index 5646fcfb..e0d0b522 100644 --- a/src/microhttpd/daemon.c +++ b/src/microhttpd/daemon.c @@ -681,82 +681,179 @@ MHD_get_fdset (struct MHD_Daemon *daemon, * @param urh upgrade handle to wait for * @param[out] rs read set to initialize * @param[out] ws write set to initialize + * @param[out] es except set to initialize * @param[out] max_fd maximum FD to update * @param fd_setsize value of FD_SETSIZE - * @return #MHD_YES on success, #MHD_NO on error + * @return true on success, false on error */ -static int +static bool urh_to_fdset (struct MHD_UpgradeResponseHandle *urh, fd_set *rs, fd_set *ws, + fd_set *es, MHD_socket *max_fd, unsigned int fd_setsize) { - if ( (urh->out_buffer_used < urh->out_buffer_size) && - (MHD_INVALID_SOCKET != urh->mhd.socket) && - (! MHD_add_to_fd_set_ (urh->mhd.socket, - rs, - max_fd, - fd_setsize)) ) - return MHD_NO; - if ( (0 != urh->in_buffer_used) && - (! urh->was_closed) && - (MHD_INVALID_SOCKET != urh->mhd.socket) && - (! MHD_add_to_fd_set_ (urh->mhd.socket, - ws, - max_fd, - fd_setsize)) ) - return MHD_NO; - if ( (urh->in_buffer_used < urh->in_buffer_size) && - (! urh->was_closed) && - (MHD_INVALID_SOCKET != urh->connection->socket_fd) && - (! MHD_add_to_fd_set_ (urh->connection->socket_fd, - rs, - max_fd, - fd_setsize)) ) - return MHD_NO; - if ( (0 != urh->out_buffer_used) && - (MHD_INVALID_SOCKET != urh->connection->socket_fd) && - (! MHD_add_to_fd_set_ (urh->connection->socket_fd, - ws, - max_fd, - fd_setsize)) ) - return MHD_NO; - return MHD_YES; + const MHD_socket conn_sckt = urh->connection->socket_fd; + const MHD_socket mhd_sckt = urh->mhd.socket; + bool res = true; + + if (MHD_INVALID_SOCKET != conn_sckt) + { + if ( (urh->in_buffer_used < urh->in_buffer_size) && + (! MHD_add_to_fd_set_ (conn_sckt, + rs, + max_fd, + fd_setsize)) ) + res = false; + if ( (0 != urh->out_buffer_used) && + (! MHD_add_to_fd_set_ (conn_sckt, + ws, + max_fd, + fd_setsize)) ) + res = false; + if (0 != urh->in_buffer_size) + MHD_add_to_fd_set_ (conn_sckt, + es, + max_fd, + fd_setsize); + } + if (MHD_INVALID_SOCKET != mhd_sckt) + { + if ( (urh->out_buffer_used < urh->out_buffer_size) && + (! MHD_add_to_fd_set_ (mhd_sckt, + rs, + max_fd, + fd_setsize)) ) + res = false; + if ( (0 != urh->in_buffer_used) && + (! MHD_add_to_fd_set_ (mhd_sckt, + ws, + max_fd, + fd_setsize)) ) + res = false; + if (0 != urh->out_buffer_size) + MHD_add_to_fd_set_ (mhd_sckt, + es, + max_fd, + fd_setsize); + } + + return res; } /** - * Update the @a urh based on the ready FDs in the @a rs and @a ws. + * Update the @a urh based on the ready FDs in + * the @a rs, @a ws, and @a es. * * @param urh upgrade handle to update * @param rs read result from select() * @param ws write result from select() + * @param ws except result from select() */ static void urh_from_fdset (struct MHD_UpgradeResponseHandle *urh, const fd_set *rs, - const fd_set *ws) + const fd_set *ws, + const fd_set *es,) { - const MHD_socket mhd_sckt = urh->mhd.socket; const MHD_socket conn_sckt = urh->connection->socket_fd; + const MHD_socket mhd_sckt = urh->mhd.socket; + + urh->app.celi = MHD_EPOLL_STATE_UNREADY; + urh->mhd.celi = MHD_EPOLL_STATE_UNREADY; + + if (MHD_INVALID_SOCKET != conn_sckt) + { + if (FD_ISSET (conn_sckt, rs)) + urh->app.celi |= MHD_EPOLL_STATE_READ_READY; + if (FD_ISSET (conn_sckt, ws)) + urh->app.celi |= MHD_EPOLL_STATE_WRITE_READY; + if (FD_ISSET (conn_sckt, es)) + urh->app.celi |= MHD_EPOLL_STATE_ERROR; + } + if ((MHD_INVALID_SOCKET != mhd_sckt)) + { + if (FD_ISSET (mhd_sckt, rs)) + urh->mhd.celi |= MHD_EPOLL_STATE_READ_READY; + if (FD_ISSET (mhd_sckt, ws)) + urh->mhd.celi |= MHD_EPOLL_STATE_WRITE_READY; + if (FD_ISSET (mhd_sckt, es)) + urh->mhd.celi |= MHD_EPOLL_STATE_ERROR; + } +} + + +/** + * Set required 'event' members in 'pollfd' elements, + * assuming that @a p[0].fd is MHD side of socketpair + * and @a p[1].fd is TLS connected socket. + * + * @param urh upgrade handle to watch for + * @param p pollfd array to update + */ +static void +urh_update_pollfd(struct MHD_UpgradeResponseHandle *urh, + struct pollfd p[2]) +{ + p[0].events = 0; + p[1].events = 0; + if (urh->in_buffer_used < urh->in_buffer_size) + p[0].events |= POLLIN | MHD_POLL_EVENTS_ERR_DISC; + if (0 != urh->out_buffer_used) + p[0].events |= POLLOUT | MHD_POLL_EVENTS_ERR_DISC; + if (0 != urh->in_buffer_size) + p[0].events |= MHD_POLL_EVENTS_ERR_DISC; + if (urh->out_buffer_used < urh->out_buffer_size) + p[1].events |= POLLIN | MHD_POLL_EVENTS_ERR_DISC; + if (0 != urh->in_buffer_used) + p[1].events |= POLLOUT | MHD_POLL_EVENTS_ERR_DISC; + if (0 != urh->out_buffer_size) + p[1].events |= MHD_POLL_EVENTS_ERR_DISC; +} + - if ((MHD_INVALID_SOCKET != conn_sckt) && - FD_ISSET (conn_sckt, rs)) +/** + * Set @a p to watch for @a urh. + * + * @param urh upgrade handle to watch for + * @param p pollfd array to set + */ +static void +urh_to_pollfd(struct MHD_UpgradeResponseHandle *urh, + struct pollfd p[2]) +{ + p[0].fd = urh->connection->socket_fd; + p[1].fd = urh->mhd.socket; + urh_update_pollfd(urh, p); +} + + +/** + * Update ready state in @a urh based on pollfd. + * @param urh upgrade handle to update + * @param p 'poll()' processed pollfd. + */ +static void +urh_from_pollfd(struct MHD_UpgradeResponseHandle *urh, + struct pollfd p[2]) +{ + if (0 != (p[0].revents & POLLIN)) urh->app.celi |= MHD_EPOLL_STATE_READ_READY; - if ((MHD_INVALID_SOCKET != conn_sckt) && - FD_ISSET (conn_sckt, ws)) + if (0 != (p[0].revents & POLLOUT)) urh->app.celi |= MHD_EPOLL_STATE_WRITE_READY; - if ((MHD_INVALID_SOCKET != mhd_sckt) && - FD_ISSET (mhd_sckt, rs)) + if (0 != (p[0].revents & MHD_POLL_REVENTS_ERR_DISC)) + urh->app.celi |= MHD_EPOLL_STATE_ERROR; + if (0 != (p[1].revents & POLLIN)) urh->mhd.celi |= MHD_EPOLL_STATE_READ_READY; - if ((MHD_INVALID_SOCKET != mhd_sckt) && - FD_ISSET (mhd_sckt, ws)) + if (0 != (p[1].revents & POLLOUT)) urh->mhd.celi |= MHD_EPOLL_STATE_WRITE_READY; + if (0 != (p[1].revents & MHD_POLL_REVENTS_ERR_DISC)) + urh->mhd.celi |= MHD_EPOLL_STATE_ERROR; } #endif /* HTTPS_SUPPORT && UPGRADE_SUPPORT */ - /** * Obtain the `select()` sets for this daemon. * Daemon's FDs will be added to fd_sets. To get only @@ -891,6 +988,7 @@ MHD_get_fdset2 (struct MHD_Daemon *daemon, urh_to_fdset (urh, read_fd_set, write_fd_set, + except_fd_set, max_fd, fd_setsize)) result = MHD_NO; @@ -1362,19 +1460,22 @@ thread_main_connection_upgrade (struct MHD_Connection *con) /* use select */ fd_set rs; fd_set ws; + fd_set es; MHD_socket max_fd; int num_ready; - int result; + bool result; FD_ZERO (&rs); FD_ZERO (&ws); + FD_ZERO (&es); max_fd = MHD_INVALID_SOCKET; result = urh_to_fdset (urh, &rs, &ws, + &es, &max_fd, FD_SETSIZE); - if (MHD_NO == result) + if (! result) { #ifdef HAVE_MESSAGES MHD_DLOG (con->daemon, @@ -1399,7 +1500,7 @@ thread_main_connection_upgrade (struct MHD_Connection *con) num_ready = MHD_SYS_select_ (max_fd + 1, &rs, &ws, - NULL, + &es, tvp); } else @@ -1420,7 +1521,8 @@ thread_main_connection_upgrade (struct MHD_Connection *con) } urh_from_fdset (urh, &rs, - &ws); + &ws + &es); process_urh (urh); if ( (0 == urh->in_buffer_size) && (0 == urh->out_buffer_size) && @@ -1433,38 +1535,29 @@ thread_main_connection_upgrade (struct MHD_Connection *con) else if (0 != (daemon->options & MHD_USE_TLS)) { /* use poll() */ + struct pollfd p[2]; + memset (p, + 0, + sizeof (p)); + p[0].fd = urh->connection->socket_fd; + p[1].fd = urh->mhd.socket; while ( (MHD_CONNECTION_UPGRADE == con->state) || (0 != urh->out_buffer_used) ) { - struct pollfd p[2]; - unsigned int timeout; + int timeout; - memset (p, - 0, - sizeof (struct pollfd) * 2); - p[0].fd = urh->connection->socket_fd; - p[1].fd = urh->mhd.socket; - if (urh->in_buffer_used < urh->in_buffer_size) - p[0].events |= POLLIN; - if (0 != urh->out_buffer_used) - p[0].events |= POLLOUT; - if (urh->out_buffer_used < urh->out_buffer_size) - p[1].events |= POLLIN; - if (0 != urh->in_buffer_used) - p[1].events |= POLLOUT; + urh_update_pollfd(urh, p); if ( (con->tls_read_ready) && (urh->in_buffer_used < urh->in_buffer_size)) timeout = 0; /* No need to wait if incoming data is already pending in TLS buffers. */ else - timeout = UINT_MAX; + timeout = -1; - /* FIXME: does this check really needed? */ - if ( (0 != (p[0].events | p[1].events)) && - (MHD_sys_poll_ (p, - 2, - timeout) < 0) ) + if (MHD_sys_poll_ (p, + 2, + timeout) < 0) { const int err = MHD_socket_get_error_ (); @@ -1477,14 +1570,7 @@ thread_main_connection_upgrade (struct MHD_Connection *con) #endif break; } - if (0 != (p[0].revents & POLLIN)) - urh->app.celi |= MHD_EPOLL_STATE_READ_READY; - if (0 != (p[0].revents & POLLOUT)) - urh->app.celi |= MHD_EPOLL_STATE_WRITE_READY; - if (0 != (p[1].revents & POLLIN)) - urh->mhd.celi |= MHD_EPOLL_STATE_READ_READY; - if (0 != (p[1].revents & POLLOUT)) - urh->mhd.celi |= MHD_EPOLL_STATE_WRITE_READY; + urh_from_pollfd(urh, p); process_urh (urh); if ( (0 == urh->in_buffer_size) && (0 == urh->out_buffer_size) && @@ -3153,7 +3239,8 @@ MHD_run_from_select (struct MHD_Daemon *daemon, /* update urh state based on select() output */ urh_from_fdset (urh, read_fd_set, - write_fd_set); + write_fd_set, + except_fd_set); /* call generic forwarding function for passing data */ process_urh (urh); /* Finished forwarding? */ @@ -3448,18 +3535,8 @@ MHD_poll_all (struct MHD_Daemon *daemon, #if defined(HTTPS_SUPPORT) && defined(UPGRADE_SUPPORT) for (urh = daemon->urh_tail; NULL != urh; urh = urh->prev) { - p[poll_server+i].fd = urh->connection->socket_fd; - if (urh->in_buffer_used < urh->in_buffer_size) - p[poll_server+i].events |= POLLIN; - if (0 != urh->out_buffer_used) - p[poll_server+i].events |= POLLOUT; - i++; - p[poll_server+i].fd = urh->mhd.socket; - if (urh->out_buffer_used < urh->out_buffer_size) - p[poll_server+i].events |= POLLIN; - if (0 != urh->in_buffer_used) - p[poll_server+i].events |= POLLOUT; - i++; + urh_to_pollfd(urh, &(p[poll_server+i])); + i += 2; } #endif /* HTTPS_SUPPORT && UPGRADE_SUPPORT */ if (0 == poll_server + num_connections) @@ -3528,23 +3605,11 @@ MHD_poll_all (struct MHD_Daemon *daemon, * from 'daemon->urh_head' list. */ urhn = urh->prev; /* Check for fd mismatch. FIXME: required for safety? */ - if (p[poll_server+i].fd == urh->connection->socket_fd) - { - if (0 != (p[poll_server+i].revents & POLLIN)) - urh->app.celi |= MHD_EPOLL_STATE_READ_READY; - if (0 != (p[poll_server+i].revents & POLLOUT)) - urh->app.celi |= MHD_EPOLL_STATE_WRITE_READY; - } - i++; - /* Check for fd mismatch. FIXME: required for safety? */ - if (p[poll_server+i].fd == urh->mhd.socket) - { - if (0 != (p[poll_server+i].revents & POLLIN)) - urh->mhd.celi |= MHD_EPOLL_STATE_READ_READY; - if (0 != (p[poll_server+i].revents & POLLOUT)) - urh->mhd.celi |= MHD_EPOLL_STATE_WRITE_READY; - } - i++; + if ((p[poll_server+i].fd != urh->connection->socket_fd) || + (p[poll_server+i+1].fd != urh->mhd.socket)) + break; + urh_from_pollfd(urh, &(p[poll_server+i])); + i += 2; process_urh (urh); /* Finished forwarding? */ if ( (0 == urh->in_buffer_size) && diff --git a/src/microhttpd/response.c b/src/microhttpd/response.c index 498174e6..26ad649b 100644 --- a/src/microhttpd/response.c +++ b/src/microhttpd/response.c @@ -852,7 +852,7 @@ MHD_response_execute_upgrade_ (struct MHD_Response *response, EXTRA_CHECK (-1 != daemon->epoll_upgrade_fd); /* First, add network socket */ - event.events = EPOLLIN | EPOLLOUT; + event.events = EPOLLIN | EPOLLOUT | EPOLLPRI; event.data.ptr = &urh->app; if (0 != epoll_ctl (daemon->epoll_upgrade_fd, EPOLL_CTL_ADD, @@ -871,14 +871,14 @@ MHD_response_execute_upgrade_ (struct MHD_Response *response, } /* Second, add our end of the UNIX socketpair() */ - event.events = EPOLLIN | EPOLLOUT; + event.events = EPOLLIN | EPOLLOUT | EPOLLPRI; event.data.ptr = &urh->mhd; if (0 != epoll_ctl (daemon->epoll_upgrade_fd, EPOLL_CTL_ADD, urh->mhd.socket, &event)) { - event.events = EPOLLIN | EPOLLOUT; + event.events = EPOLLIN | EPOLLOUT | EPOLLPRI; event.data.ptr = &urh->app; if (0 != epoll_ctl (daemon->epoll_upgrade_fd, EPOLL_CTL_DEL, -- cgit v1.2.3