1
0
Fork 0
mirror of https://github.com/warmcat/libwebsockets.git synced 2025-03-09 00:00:04 +01:00

libev port

merged by andy@warmcat.com via https://github.com/gaby64/libwebsockets-libev

To use, you need to both

 - cmake ---> -DLWS_USE_LIBEV=1

 - info->options must have LWS_SERVER_OPTION_LIBEV set when creating the context

this is so a single library can be built for distros to support apps that use
normal polling and apps that use libev polling.
This commit is contained in:
Andrew Canaday 2014-03-23 13:25:07 +08:00 committed by Andy Green
parent 03203aba93
commit 9769f4f293
7 changed files with 256 additions and 24 deletions

View file

@ -52,6 +52,7 @@ option(LWS_WITHOUT_DEBUG "Don't compile debug related code" OFF)
option(LWS_WITHOUT_EXTENSIONS "Don't compile with extensions" OFF)
option(LWS_WITH_LATENCY "Build latency measuring code into the library" OFF)
option(LWS_WITHOUT_DAEMONIZE "Don't build the daemonization api" OFF)
option(LWS_WITH_LIBEV "Compile without support for libev" OFF)
# Allow the user to override installation directories.
set(LWS_INSTALL_LIB_DIR lib CACHE PATH "Installation directory for libraries")
@ -115,6 +116,11 @@ else()
set(_DEBUG 1)
endif()
if (LWS_WITH_LIBEV)
set(LWS_USE_LIBEV 1)
set(LWS_NO_EXTERNAL_POLL 1)
endif()
if (MINGW)
set(LWS_MINGW_SUPPORT 1)
endif()
@ -458,6 +464,10 @@ if (LWS_WITH_SSL)
endif()
endif(LWS_WITH_SSL)
if (LWS_WITH_LIBEV)
list(APPEND LIB_LIST "ev")
endif(LWS_WITH_LIBEV)
#
# Platform specific libs.
#
@ -866,6 +876,7 @@ message(" LWS_WITHOUT_DEBUG = ${LWS_WITHOUT_DEBUG}")
message(" LWS_WITHOUT_EXTENSIONS = ${LWS_WITHOUT_EXTENSIONS}")
message(" LWS_WITH_LATENCY = ${LWS_WITH_LATENCY}")
message(" LWS_WITHOUT_DAEMONIZE = ${LWS_WITHOUT_DAEMONIZE}")
message(" LWS_USE_LIBEV = ${LWS_USE_LIBEV}")
message("---------------------------------------------------------------------")
# These will be available to parent projects including libwebsockets using add_subdirectory()

View file

@ -39,6 +39,10 @@ If you will use another thread for this, take a lot of care about managing
your list of live wsi by doing it from ESTABLISHED and CLOSED callbacks
(with your own locking).
If you configure cmake with -DLWS_WITH_LIBEV=1 then the code allowing the libev
eventloop instead of the default poll() one will also be compiled in. But to
use it, you must also set the LWS_SERVER_OPTION_LIBEV flag on the context
creation info struct options member.
User api changes

View file

@ -26,6 +26,9 @@
/* Turn off websocket extensions */
#cmakedefine LWS_NO_EXTENSIONS
/* Enable libev io loop */
#cmakedefine LWS_USE_LIBEV
/* Turn on latency measuring code */
#cmakedefine LWS_LATENCY

View file

@ -63,7 +63,13 @@ static int log_level = LLL_ERR | LLL_WARN | LLL_NOTICE;
static void lwsl_emit_stderr(int level, const char *line);
static void (*lwsl_emit)(int level, const char *line) = lwsl_emit_stderr;
static const char *library_version = LWS_LIBRARY_VERSION " " LWS_BUILD_HASH;
#ifdef LWS_USE_LIBEV
#define _LWS_EV_TAG " libev"
#else
#define _LWS_EV_TAG
#endif /* LWS_USE_LIBEV */
static const char *library_version =
LWS_LIBRARY_VERSION " " LWS_BUILD_HASH _LWS_EV_TAG;
static const char * const log_level_names[] = {
"ERR",
@ -173,6 +179,11 @@ insert_wsi_socket_into_fds(struct libwebsocket_context *context,
wsi->position_in_fds_table = context->fds_count;
context->fds[context->fds_count].fd = wsi->sock;
context->fds[context->fds_count].events = POLLIN;
#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 */
context->fds[context->fds_count++].revents = 0;
/* external POLL support via protocol 0 */
@ -431,6 +442,13 @@ just_kill_connection:
* delete socket from the internal poll list if still present
*/
#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 */
remove_wsi_socket_from_fds(context, wsi);
wsi->state = WSI_STATE_DEAD_SOCKET;
@ -865,9 +883,14 @@ user_service:
#endif
/* one shot */
if (pollfd)
if (pollfd) {
lws_change_pollfd(wsi, POLLOUT, 0);
#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 */
}
#ifndef LWS_NO_EXTENSIONS
notify_action:
#endif
@ -974,6 +997,7 @@ libwebsocket_service_fd(struct libwebsocket_context *context,
time(&now);
/* TODO: if using libev, we should probably use timeout watchers... */
if (context->last_timeout_check_s != now) {
context->last_timeout_check_s = now;
@ -1240,6 +1264,36 @@ handled:
return n;
}
#ifdef LWS_USE_LIBEV
LWS_VISIBLE void
libwebsocket_accept_cb(struct ev_loop *loop, struct ev_io *watcher, int revents)
{
struct 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 |= POLLIN;
if (revents & EV_WRITE)
eventfd.revents |= 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);
}
#endif /* LWS_USE_LIBEV */
/**
* libwebsocket_context_destroy() - Destroy the websocket context
@ -1394,6 +1448,10 @@ libwebsocket_service(struct libwebsocket_context *context, int timeout_ms)
if (context == NULL)
return 1;
#ifdef LWS_USE_LIBEV
if (context->io_loop && LWS_LIBEV_ENABLED(context))
ev_run(context->io_loop, 0);
#endif /* LWS_USE_LIBEV */
context->service_tid = context->protocols[0].callback(context, NULL,
LWS_CALLBACK_GET_THREAD_ID, NULL, NULL, 0);
n = poll(context->fds, context->fds_count, timeout_ms);
@ -1453,6 +1511,64 @@ libwebsocket_cancel_service(struct libwebsocket_context *context)
#endif
}
#ifdef LWS_USE_LIBEV
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 */
#ifndef LWS_NO_EXTENSIONS
int
lws_any_extension_handled(struct libwebsocket_context *context,
@ -1584,6 +1700,10 @@ libwebsocket_callback_on_writable(struct libwebsocket_context *context,
}
lws_change_pollfd(wsi, 0, POLLOUT);
#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 */
return 1;
}
@ -2036,6 +2156,14 @@ libwebsocket_create_context(struct lws_context_creation_info *info)
free(context);
return NULL;
}
#ifdef LWS_USE_LIBEV
if (LWS_LIBEV_ENABLED(context)) {
context->w_accept.context = context;
context->w_sigint.context = context;
}
#endif /* LWS_USE_LIBEV */
context->lws_lookup = (struct libwebsocket **)
malloc(sizeof(struct libwebsocket *) * context->max_fds);
if (context->lws_lookup == NULL) {
@ -2049,23 +2177,25 @@ libwebsocket_create_context(struct lws_context_creation_info *info)
memset(context->lws_lookup, 0, sizeof(struct libwebsocket *) *
context->max_fds);
#ifdef _WIN32
context->fds_count = 0;
#else
if (pipe(context->dummy_pipe_fds)) {
lwsl_err("Unable to create pipe\n");
free(context->lws_lookup);
free(context->fds);
free(context);
return NULL;
}
if (!LWS_LIBEV_ENABLED(context)) {
#ifdef _WIN32
context->fds_count = 0;
#else
if (pipe(context->dummy_pipe_fds)) {
lwsl_err("Unable to create pipe\n");
free(context->lws_lookup);
free(context->fds);
free(context);
return NULL;
}
/* use the read end of pipe as first item */
context->fds[0].fd = context->dummy_pipe_fds[0];
context->fds[0].events = POLLIN;
context->fds[0].revents = 0;
context->fds_count = 1;
#endif
/* use the read end of pipe as first item */
context->fds[0].fd = context->dummy_pipe_fds[0];
context->fds[0].events = POLLIN;
context->fds[0].revents = 0;
context->fds_count = 1;
#endif
}
#ifndef LWS_NO_EXTENSIONS
context->extensions = info->extensions;
@ -2140,7 +2270,7 @@ libwebsocket_create_context(struct lws_context_creation_info *info)
}
#ifndef LWS_NO_SERVER
if (info->port) {
if (info->port != CONTEXT_PORT_NO_LISTEN) {
#ifdef LWS_OPENSSL_SUPPORT
context->use_ssl = info->ssl_cert_filepath != NULL &&
@ -2405,7 +2535,7 @@ libwebsocket_create_context(struct lws_context_creation_info *info)
#ifndef LWS_NO_SERVER
/* set up our external listening socket we serve on */
if (info->port) {
if (info->port != CONTEXT_PORT_NO_LISTEN) {
int sockfd;
sockfd = socket(AF_INET, SOCK_STREAM, 0);
@ -2454,6 +2584,15 @@ libwebsocket_create_context(struct lws_context_creation_info *info)
compatible_close(sockfd);
goto bail;
}
struct sockaddr_in sin;
socklen_t len = sizeof(sin);
if (getsockname(sockfd, (struct sockaddr *)&sin, &len) == -1)
perror("getsockname");
else
info->port = ntohs(sin.sin_port);
context->listen_port = info->port;
wsi = (struct libwebsocket *)malloc(
sizeof(struct libwebsocket));
@ -2524,7 +2663,7 @@ libwebsocket_create_context(struct lws_context_creation_info *info)
*/
m = LWS_EXT_CALLBACK_CLIENT_CONTEXT_CONSTRUCT;
if (info->port)
if (info->port != CONTEXT_PORT_NO_LISTEN)
m = LWS_EXT_CALLBACK_SERVER_CONTEXT_CONSTRUCT;
if (info->extensions) {

View file

@ -80,13 +80,17 @@ typedef SSIZE_T ssize_t;
#endif
#ifdef LWS_USE_LIBEV
#include <ev.h>
#endif /* LWS_USE_LIBEV */
#include <assert.h>
#ifndef LWS_EXTERN
#define LWS_EXTERN extern
#endif
#define CONTEXT_PORT_NO_LISTEN 0
#define CONTEXT_PORT_NO_LISTEN -1
#define MAX_MUX_RECURSION 2
enum lws_log_levels {
@ -144,7 +148,8 @@ LWS_VISIBLE LWS_EXTERN void lwsl_hexdump(void *buf, size_t len);
enum libwebsocket_context_options {
LWS_SERVER_OPTION_REQUIRE_VALID_OPENSSL_CLIENT_CERT = 2,
LWS_SERVER_OPTION_SKIP_SERVER_CANONICAL_NAME = 4,
LWS_SERVER_OPTION_ALLOW_NON_SSL_ON_SSL_PORT = 8
LWS_SERVER_OPTION_ALLOW_NON_SSL_ON_SSL_PORT = 8,
LWS_SERVER_OPTION_LIBEV = 16
};
enum libwebsocket_callback_reasons {
@ -968,6 +973,20 @@ libwebsocket_service(struct libwebsocket_context *context, int timeout_ms);
LWS_VISIBLE LWS_EXTERN void
libwebsocket_cancel_service(struct libwebsocket_context *context);
#ifdef LWS_USE_LIBEV
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);
#endif /* LWS_USE_LIBEV */
LWS_VISIBLE LWS_EXTERN int
libwebsocket_service_fd(struct libwebsocket_context *context,
struct pollfd *pollfd);

View file

@ -92,6 +92,10 @@
#include <netinet/tcp.h>
#include <arpa/inet.h>
#include <poll.h>
#ifdef LWS_USE_LIBEV
#include <ev.h>
#endif /* LWS_USE_LIBEV */
#include <sys/mman.h>
#include <sys/time.h>
@ -265,10 +269,27 @@ enum {
struct libwebsocket_protocols;
struct libwebsocket;
#ifdef LWS_USE_LIBEV
struct lws_io_watcher {
struct ev_io watcher;
struct libwebsocket_context* context;
};
struct lws_signal_watcher {
struct ev_signal watcher;
struct libwebsocket_context* context;
};
#endif /* LWS_USE_LIBEV */
struct libwebsocket_context {
struct pollfd *fds;
struct libwebsocket **lws_lookup; /* fd to wsi */
int fds_count;
#ifdef LWS_USE_LIBEV
struct ev_loop* io_loop;
struct lws_io_watcher w_accept;
struct lws_signal_watcher w_sigint;
#endif /* LWS_USE_LIBEV */
int max_fds;
int listen_port;
const char *iface;
@ -327,6 +348,13 @@ struct libwebsocket_context {
void *user_space;
};
#ifdef LWS_USE_LIBEV
#define LWS_LIBEV_ENABLED(context) (context->options & LWS_SERVER_OPTION_LIBEV)
#else
#define LWS_LIBEV_ENABLED(context) (0)
#endif
enum uri_path_states {
URIPS_IDLE,
URIPS_SEEN_SLASH,
@ -415,6 +443,10 @@ struct libwebsocket {
/* lifetime members */
#ifdef LWS_USE_LIBEV
struct lws_io_watcher w_read;
struct lws_io_watcher w_write;
#endif /* LWS_USE_LIBEV */
const struct libwebsocket_protocols *protocol;
#ifndef LWS_NO_EXTENSIONS
struct libwebsocket_extension *

View file

@ -188,6 +188,9 @@ int lws_server_socket_service(struct libwebsocket_context *context,
/* one shot */
lws_change_pollfd(wsi, POLLOUT, 0);
#ifdef LWS_USE_LIBEV
ev_io_stop(context->io_loop,(struct ev_io*)&(wsi->w_write));
#endif /* LWS_USE_LIBEV */
if (wsi->state != WSI_STATE_HTTP_ISSUING_FILE) {
n = user_callback_handle_rxflow(
@ -272,6 +275,18 @@ 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
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 */
#ifdef LWS_OPENSSL_SUPPORT
new_wsi->ssl = NULL;
@ -338,6 +353,9 @@ int lws_server_socket_service(struct libwebsocket_context *context,
case LWS_CONNMODE_SSL_ACK_PENDING:
lws_change_pollfd(wsi, POLLOUT, 0);
#ifdef LWS_USE_LIBEV
ev_io_stop(context->io_loop,(struct ev_io*)&(wsi->w_write));
#endif /* LWS_USE_LIBEV */
lws_latency_pre(context, wsi);
@ -382,11 +400,17 @@ int lws_server_socket_service(struct libwebsocket_context *context,
if (m == SSL_ERROR_WANT_READ) {
lws_change_pollfd(wsi, 0, POLLIN);
#ifdef LWS_USE_LIBEV
ev_io_start(context->io_loop,(struct ev_io*)&(wsi->w_read));
#endif /* LWS_USE_LIBEV */
lwsl_info("SSL_ERROR_WANT_READ\n");
break;
}
if (m == SSL_ERROR_WANT_WRITE) {
lws_change_pollfd(wsi, 0, POLLOUT);
#ifdef LWS_USE_LIBEV
ev_io_start(context->io_loop,(struct ev_io*)&(wsi->w_write));
#endif /* LWS_USE_LIBEV */
break;
}
lwsl_debug("SSL_accept failed skt %u: %s\n",