diff --git a/CMakeLists.txt b/CMakeLists.txt index 8aca4ea6..4b1c7494 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -324,6 +324,12 @@ if (NOT LWS_WITHOUT_EXTENSIONS) ) endif() +if (LWS_WITH_LIBEV) + list(APPEND SOURCES + lib/libev.c + ) +endif(LWS_WITH_LIBEV) + # Add helper files for Windows. if (WIN32) set(WIN32_HELPERS_PATH win32port/win32helpers) diff --git a/lib/context.c b/lib/context.c index 92383bf8..fd89ae3e 100644 --- a/lib/context.c +++ b/lib/context.c @@ -91,14 +91,7 @@ libwebsocket_create_context(struct lws_context_creation_info *info) #else lwsl_notice("IPV6 not compiled in\n"); #endif -#ifdef LWS_USE_LIBEV - if (info->options & LWS_SERVER_OPTION_LIBEV) - lwsl_notice("libev support compiled in and enabled\n"); - else - lwsl_notice("libev support compiled in but disabled\n"); -#else - lwsl_notice("libev support not compiled in\n"); -#endif + lws_feature_status_libev(info); lwsl_info(" LWS_MAX_HEADER_LEN: %u\n", LWS_MAX_HEADER_LEN); lwsl_info(" LWS_MAX_PROTOCOLS: %u\n", LWS_MAX_PROTOCOLS); #ifndef LWS_NO_EXTENSIONS diff --git a/lib/libev.c b/lib/libev.c new file mode 100644 index 00000000..b75c5ec4 --- /dev/null +++ b/lib/libev.c @@ -0,0 +1,175 @@ +/* + * libwebsockets - small server side websockets and web server implementation + * + * Copyright (C) 2010-2014 Andy Green + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation: + * version 2.1 of the License. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ + +#include "private-libwebsockets.h" + +void lws_feature_status_libev(struct lws_context_creation_info *info) +{ + if (info->options & LWS_SERVER_OPTION_LIBEV) + lwsl_notice("libev support compiled in and enabled\n"); + else + lwsl_notice("libev support compiled in but disabled\n"); +} + +static void +libwebsocket_accept_cb(struct ev_loop *loop, struct ev_io *watcher, int revents) +{ + struct libwebsocket_pollfd eventfd; + struct lws_io_watcher *lws_io = (struct lws_io_watcher *)watcher; + struct libwebsocket_context *context = lws_io->context; + + if (revents & EV_ERROR) + return; + + eventfd.fd = watcher->fd; + eventfd.revents = EV_NONE; + if (revents & EV_READ) + eventfd.revents |= LWS_POLLIN; + + if (revents & EV_WRITE) + eventfd.revents |= LWS_POLLOUT; + + libwebsocket_service_fd(context, &eventfd); +} + +LWS_VISIBLE void +libwebsocket_sigint_cb(struct ev_loop *loop, + struct ev_signal *watcher, int revents) +{ + ev_break(loop, EVBREAK_ALL); +} + +LWS_VISIBLE int +libwebsocket_initloop( + struct libwebsocket_context *context, + struct ev_loop *loop) +{ + int status = 0; + int backend; + const char * backend_name; + struct ev_io *w_accept = (ev_io *)&context->w_accept; + struct ev_signal *w_sigint = (ev_signal *)&context->w_sigint; + + if (!loop) + loop = ev_default_loop(0); + + context->io_loop = loop; + + /* + * Initialize the accept w_accept with the listening socket + * and register a callback for read operations: + */ + ev_io_init(w_accept, libwebsocket_accept_cb, + context->listen_service_fd, EV_READ); + ev_io_start(context->io_loop,w_accept); + ev_signal_init(w_sigint, libwebsocket_sigint_cb, SIGINT); + ev_signal_start(context->io_loop,w_sigint); + backend = ev_backend(loop); + + switch (backend) { + case EVBACKEND_SELECT: + backend_name = "select"; + break; + case EVBACKEND_POLL: + backend_name = "poll"; + break; + case EVBACKEND_EPOLL: + backend_name = "epoll"; + break; + case EVBACKEND_KQUEUE: + backend_name = "kqueue"; + break; + case EVBACKEND_DEVPOLL: + backend_name = "/dev/poll"; + break; + case EVBACKEND_PORT: + backend_name = "Solaris 10 \"port\""; + break; + default: + backend_name = "Unknown libev backend"; + break; + }; + + lwsl_notice(" libev backend: %s\n", backend_name); + + return status; +} + +LWS_VISIBLE void +lws_libev_accept(struct libwebsocket_context *context, + struct libwebsocket *new_wsi, int accept_fd) +{ + struct ev_io *r = &new_wsi->w_read.watcher; + struct ev_io *w = &new_wsi->w_write.watcher; + + if (!LWS_LIBEV_ENABLED(context)) + return; + + new_wsi->w_read.context = context; + new_wsi->w_write.context = context; + ev_io_init(r, libwebsocket_accept_cb, accept_fd, EV_READ); + ev_io_init(w, libwebsocket_accept_cb, accept_fd, EV_WRITE); +} + +LWS_VISIBLE void +lws_libev_io(struct libwebsocket_context *context, + struct libwebsocket *wsi, int flags) +{ + if (!LWS_LIBEV_ENABLED(context)) + return; + + if (!context->io_loop) + return; + + assert((flags & (LWS_EV_START | LWS_EV_STOP)) && + (flags & (LWS_EV_READ | LWS_EV_WRITE))); + + if (flags & LWS_EV_START) { + if (flags & LWS_EV_WRITE) + ev_io_start(context->io_loop, &wsi->w_write.watcher); + if (flags & LWS_EV_READ) + ev_io_start(context->io_loop, &wsi->w_read.watcher); + } else { + if (flags & LWS_EV_WRITE) + ev_io_stop(context->io_loop, &wsi->w_write.watcher); + if (flags & LWS_EV_READ) + ev_io_stop(context->io_loop, &wsi->w_read.watcher); + } +} + +LWS_VISIBLE int +lws_libev_init_fd_table(struct libwebsocket_context *context) +{ + if (!LWS_LIBEV_ENABLED(context)) + return 0; + + context->w_accept.context = context; + context->w_sigint.context = context; + + return 1; +} + +LWS_VISIBLE void +lws_libev_run(struct libwebsocket_context *context) +{ + if (context->io_loop && LWS_LIBEV_ENABLED(context)) + ev_run(context->io_loop, 0); +} diff --git a/lib/libwebsockets.h b/lib/libwebsockets.h index c5b17013..03ead6ed 100644 --- a/lib/libwebsockets.h +++ b/lib/libwebsockets.h @@ -982,10 +982,6 @@ LWS_VISIBLE LWS_EXTERN int libwebsocket_initloop( struct libwebsocket_context *context, struct ev_loop *loop); -LWS_VISIBLE void -libwebsocket_accept_cb(struct ev_loop *loop, struct ev_io *watcher, - int revents); - LWS_VISIBLE void libwebsocket_sigint_cb( struct ev_loop *loop, struct ev_signal *watcher, int revents); diff --git a/lib/lws-plat-unix.c b/lib/lws-plat-unix.c index de094c74..279a3be4 100644 --- a/lib/lws-plat-unix.c +++ b/lib/lws-plat-unix.c @@ -54,93 +54,6 @@ static void lws_sigusr2(int sig) { } -#ifdef LWS_USE_LIBEV -LWS_VISIBLE void -libwebsocket_accept_cb(struct ev_loop *loop, struct ev_io *watcher, int revents) -{ - struct libwebsocket_pollfd eventfd; - struct lws_io_watcher *lws_io = (struct lws_io_watcher*)watcher; - struct libwebsocket_context *context = lws_io->context; - - if (revents & EV_ERROR) - return; - - eventfd.fd = watcher->fd; - eventfd.revents = EV_NONE; - if (revents & EV_READ) - eventfd.revents |= LWS_POLLIN; - - if (revents & EV_WRITE) - eventfd.revents |= LWS_POLLOUT; - - libwebsocket_service_fd(context,&eventfd); -} - -LWS_VISIBLE void -libwebsocket_sigint_cb( - struct ev_loop *loop, struct ev_signal* watcher, int revents) -{ - ev_break(loop, EVBREAK_ALL); -} - -LWS_VISIBLE int -libwebsocket_initloop( - struct libwebsocket_context *context, - struct ev_loop *loop) -{ - int status = 0; - int backend; - const char * backend_name; - struct ev_io *w_accept = (ev_io *)&context->w_accept; - struct ev_signal *w_sigint = (ev_signal *)&context->w_sigint; - - if (!loop) - loop = ev_default_loop(0); - - context->io_loop = loop; - - /* - * Initialize the accept w_accept with the listening socket - * and register a callback for read operations: - */ - ev_io_init(w_accept, libwebsocket_accept_cb, - context->listen_service_fd, EV_READ); - ev_io_start(context->io_loop,w_accept); - ev_signal_init(w_sigint, libwebsocket_sigint_cb, SIGINT); - ev_signal_start(context->io_loop,w_sigint); - backend = ev_backend(loop); - - switch (backend) { - case EVBACKEND_SELECT: - backend_name = "select"; - break; - case EVBACKEND_POLL: - backend_name = "poll"; - break; - case EVBACKEND_EPOLL: - backend_name = "epoll"; - break; - case EVBACKEND_KQUEUE: - backend_name = "kqueue"; - break; - case EVBACKEND_DEVPOLL: - backend_name = "/dev/poll"; - break; - case EVBACKEND_PORT: - backend_name = "Solaris 10 \"port\""; - break; - default: - backend_name = "Unknown libev backend"; - break; - }; - - lwsl_notice(" libev backend: %s\n", backend_name); - - return status; -} - -#endif /* LWS_USE_LIBEV */ - /** * libwebsocket_cancel_service() - Cancel servicing of pending websocket activity * @context: Websocket context @@ -187,13 +100,11 @@ lws_plat_service(struct libwebsocket_context *context, int timeout_ms) /* stay dead once we are dead */ - if (context == NULL) + if (!context) return 1; -#ifdef LWS_USE_LIBEV - if (context->io_loop && LWS_LIBEV_ENABLED(context)) - ev_run(context->io_loop, 0); -#endif /* LWS_USE_LIBEV */ + lws_libev_run(context); + context->service_tid = context->protocols[0].callback(context, NULL, LWS_CALLBACK_GET_THREAD_ID, NULL, NULL, 0); @@ -305,13 +216,10 @@ lws_plat_drop_app_privileges(struct lws_context_creation_info *info) LWS_VISIBLE int lws_plat_init_fd_tables(struct libwebsocket_context *context) { -#ifdef LWS_USE_LIBEV - if (LWS_LIBEV_ENABLED(context)) { - context->w_accept.context = context; - context->w_sigint.context = context; + if (lws_libev_init_fd_table(context)) + /* libev handled it instead */ return 0; - } -#endif + if (pipe(context->dummy_pipe_fds)) { lwsl_err("Unable to create pipe\n"); return 1; @@ -433,10 +341,7 @@ LWS_VISIBLE void lws_plat_insert_socket_into_fds(struct libwebsocket_context *context, struct libwebsocket *wsi) { -#ifdef LWS_USE_LIBEV - if (context && context->io_loop && LWS_LIBEV_ENABLED(context)) - ev_io_start(context->io_loop, (struct ev_io *)&wsi->w_read); -#endif /* LWS_USE_LIBEV */ + lws_libev_io(context, wsi, LWS_EV_START | LWS_EV_READ); context->fds[context->fds_count++].revents = 0; } diff --git a/lib/pollfd.c b/lib/pollfd.c index ee5bf912..3995a378 100644 --- a/lib/pollfd.c +++ b/lib/pollfd.c @@ -74,12 +74,7 @@ remove_wsi_socket_from_fds(struct libwebsocket_context *context, int m; struct libwebsocket_pollargs pa = { wsi->sock, 0, 0 }; -#ifdef LWS_USE_LIBEV - if (LWS_LIBEV_ENABLED(context)) { - ev_io_stop(context->io_loop, (struct ev_io *)&wsi->w_read); - ev_io_stop(context->io_loop, (struct ev_io *)&wsi->w_write); - } -#endif /* LWS_USE_LIBEV */ + lws_libev_io(context, wsi, LWS_EV_STOP | LWS_EV_READ | LWS_EV_WRITE); if (!--context->fds_count) { context->protocols[0].callback(context, wsi, @@ -164,8 +159,10 @@ lws_change_pollfd(struct libwebsocket *wsi, int _and, int _or) */ if (pa.prev_events != pa.events) { - if (lws_plat_change_pollfd(context, wsi, pfd)) + if (lws_plat_change_pollfd(context, wsi, pfd)) { + lwsl_info("%s failed\n", __func__); return 1; + } sampled_tid = context->service_tid; if (sampled_tid) { @@ -208,10 +205,7 @@ libwebsocket_callback_on_writable(struct libwebsocket_context *context, if (lws_change_pollfd(wsi, 0, LWS_POLLOUT)) return -1; -#ifdef LWS_USE_LIBEV - if (LWS_LIBEV_ENABLED(context)) - ev_io_start(context->io_loop, (struct ev_io *)&wsi->w_write); -#endif /* LWS_USE_LIBEV */ + lws_libev_io(context, wsi, LWS_EV_START | LWS_EV_WRITE); return 1; } diff --git a/lib/private-libwebsockets.h b/lib/private-libwebsockets.h index 94bd2270..8cfab08b 100644 --- a/lib/private-libwebsockets.h +++ b/lib/private-libwebsockets.h @@ -434,10 +434,34 @@ struct libwebsocket_context { void *user_space; }; +enum { + LWS_EV_READ = (1 << 0), + LWS_EV_WRITE = (1 << 1), + LWS_EV_START = (1 << 2), + LWS_EV_STOP = (1 << 3), +}; + #ifdef LWS_USE_LIBEV #define LWS_LIBEV_ENABLED(context) (context->options & LWS_SERVER_OPTION_LIBEV) +LWS_EXTERN void lws_feature_status_libev(struct lws_context_creation_info *info); +LWS_EXTERN void +lws_libev_accept(struct libwebsocket_context *context, + struct libwebsocket *new_wsi, int accept_fd); +LWS_EXTERN void +lws_libev_io(struct libwebsocket_context *context, + struct libwebsocket *wsi, int flags); +LWS_EXTERN int +lws_libev_init_fd_table(struct libwebsocket_context *context); +LWS_EXTERN void +lws_libev_run(struct libwebsocket_context *context); #else #define LWS_LIBEV_ENABLED(context) (0) +#define lws_feature_status_libev(_a) \ + lwsl_notice("libev support not compiled in\n") +#define lws_libev_accept(_a, _b, _c) (0) +#define lws_libev_io(_a, _b, _c) (0) +#define lws_libev_init_fd_table(_a) (0) +#define lws_libev_run(_a) (0) #endif #ifdef LWS_USE_IPV6 diff --git a/lib/server.c b/lib/server.c index 2d2ffb30..e58632a7 100644 --- a/lib/server.c +++ b/lib/server.c @@ -154,8 +154,10 @@ _libwebsocket_rx_flow_control(struct libwebsocket *wsi) /* adjust the pollfd for this wsi */ if (wsi->u.ws.rxflow_change_to & LWS_RXFLOW_ALLOW) { - if (lws_change_pollfd(wsi, 0, LWS_POLLIN)) + if (lws_change_pollfd(wsi, 0, LWS_POLLIN)) { + lwsl_info("%s: fail\n", __func__); return -1; + } } else if (lws_change_pollfd(wsi, LWS_POLLIN, 0)) return -1; @@ -566,11 +568,8 @@ int lws_server_socket_service(struct libwebsocket_context *context, /* one shot */ if (lws_change_pollfd(wsi, LWS_POLLOUT, 0)) goto fail; -#ifdef LWS_USE_LIBEV - if (LWS_LIBEV_ENABLED(context)) - ev_io_stop(context->io_loop, - (struct ev_io *)&wsi->w_write); -#endif /* LWS_USE_LIBEV */ + + lws_libev_io(context, wsi, LWS_EV_STOP | LWS_EV_WRITE); if (wsi->state != WSI_STATE_HTTP_ISSUING_FILE) { n = user_callback_handle_rxflow( @@ -655,20 +654,7 @@ int lws_server_socket_service(struct libwebsocket_context *context, (context->protocols[0].callback)(context, new_wsi, LWS_CALLBACK_SERVER_NEW_CLIENT_INSTANTIATED, NULL, NULL, 0); -#ifdef LWS_USE_LIBEV - if (LWS_LIBEV_ENABLED(context)) { - new_wsi->w_read.context = context; - new_wsi->w_write.context = context; - /* - new_wsi->w_read.wsi = new_wsi; - new_wsi->w_write.wsi = new_wsi; - */ - struct ev_io* w_read = (struct ev_io*)&(new_wsi->w_read); - struct ev_io* w_write = (struct ev_io*)&(new_wsi->w_write); - ev_io_init(w_read,libwebsocket_accept_cb,accept_fd,EV_READ); - ev_io_init(w_write,libwebsocket_accept_cb,accept_fd,EV_WRITE); - } -#endif /* LWS_USE_LIBEV */ + lws_libev_accept(context, new_wsi, accept_fd); #ifdef LWS_OPENSSL_SUPPORT new_wsi->ssl = NULL; @@ -737,11 +723,8 @@ int lws_server_socket_service(struct libwebsocket_context *context, if (lws_change_pollfd(wsi, LWS_POLLOUT, 0)) goto fail; -#ifdef LWS_USE_LIBEV - if (LWS_LIBEV_ENABLED(context)) - ev_io_stop(context->io_loop, - (struct ev_io *)&wsi->w_write); -#endif /* LWS_USE_LIBEV */ + + lws_libev_io(context, wsi, LWS_EV_STOP | LWS_EV_WRITE); lws_latency_pre(context, wsi); @@ -787,22 +770,18 @@ int lws_server_socket_service(struct libwebsocket_context *context, if (m == SSL_ERROR_WANT_READ) { if (lws_change_pollfd(wsi, 0, LWS_POLLIN)) goto fail; -#ifdef LWS_USE_LIBEV - if (LWS_LIBEV_ENABLED(context)) - ev_io_start(context->io_loop, - (struct ev_io *)&wsi->w_read); -#endif /* LWS_USE_LIBEV */ + + lws_libev_io(context, wsi, LWS_EV_START | LWS_EV_READ); + lwsl_info("SSL_ERROR_WANT_READ\n"); break; } if (m == SSL_ERROR_WANT_WRITE) { if (lws_change_pollfd(wsi, 0, LWS_POLLOUT)) goto fail; -#ifdef LWS_USE_LIBEV - if (LWS_LIBEV_ENABLED(context)) - ev_io_start(context->io_loop, - (struct ev_io *)&wsi->w_write); -#endif /* LWS_USE_LIBEV */ + + lws_libev_io(context, wsi, + LWS_EV_START | LWS_EV_WRITE); break; } lwsl_debug("SSL_accept failed skt %u: %s\n", diff --git a/lib/service.c b/lib/service.c index 9aa743e5..409c2d23 100644 --- a/lib/service.c +++ b/lib/service.c @@ -145,11 +145,8 @@ user_service: if (pollfd) { if (lws_change_pollfd(wsi, LWS_POLLOUT, 0)) return 1; -#ifdef LWS_USE_LIBEV - if (LWS_LIBEV_ENABLED(context)) - ev_io_stop(context->io_loop, - (struct ev_io *)&wsi->w_write); -#endif /* LWS_USE_LIBEV */ + + lws_libev_io(context, wsi, LWS_EV_STOP | LWS_EV_WRITE); } notify_action: diff --git a/test-server/test-server.c b/test-server/test-server.c index d2e56b42..bd76ec86 100644 --- a/test-server/test-server.c +++ b/test-server/test-server.c @@ -743,7 +743,8 @@ static struct option options[] = { { "allow-non-ssl", no_argument, NULL, 'a' }, { "interface", required_argument, NULL, 'i' }, { "closetest", no_argument, NULL, 'c' }, -#ifndef LWS_NO_DAEMONIZE + { "libev", no_argument, NULL, 'e' }, + #ifndef LWS_NO_DAEMONIZE { "daemonize", no_argument, NULL, 'D' }, #endif { "resource_path", required_argument, NULL, 'r' }, @@ -774,10 +775,13 @@ int main(int argc, char **argv) info.port = 7681; while (n >= 0) { - n = getopt_long(argc, argv, "ci:hsap:d:Dr:", options, NULL); + n = getopt_long(argc, argv, "eci:hsap:d:Dr:", options, NULL); if (n < 0) continue; switch (n) { + case 'e': + opts |= LWS_SERVER_OPTION_LIBEV; + break; #ifndef LWS_NO_DAEMONIZE case 'D': daemonize = 1;