diff --git a/.gitignore b/.gitignore index 1fb8b7e098..c73d646a27 100644 --- a/.gitignore +++ b/.gitignore @@ -62,3 +62,9 @@ doc /q/ /b1/ /destdir/ + +/.idea/ + +/cmake-build-debug/ + +/cmake-build-release/ diff --git a/CMakeLists-implied-options.txt b/CMakeLists-implied-options.txt index 975a231f19..812a1c0ddb 100644 --- a/CMakeLists-implied-options.txt +++ b/CMakeLists-implied-options.txt @@ -87,6 +87,7 @@ if(LWS_WITH_DISTRO_RECOMMENDED) set(LWS_WITH_LIBUV 1) # libuv set(LWS_WITH_LIBEV 1) # libev set(LWS_WITH_LIBEVENT 1) # libevent + set(LWS_WITH_SDEVENT 0) # sd-event set(LWS_WITH_EVLIB_PLUGINS 1) # event libraries created as plugins / individual packages set(LWS_WITHOUT_EXTENSIONS 0) # libz set(LWS_ROLE_DBUS 1) # dbus-related libs @@ -117,7 +118,8 @@ endif() if (LWS_WITH_LIBEV OR LWS_WITH_LIBUV OR LWS_WITH_LIBEVENT OR - LWS_WITH_GLIB) + LWS_WITH_GLIB OR + LWS_WITH_SDEVENT) set(LWS_WITH_EVENT_LIBS 1) else() unset(LWS_WITH_EVENT_LIBS) diff --git a/CMakeLists.txt b/CMakeLists.txt index a97fd1add2..abf691d4dc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -58,7 +58,7 @@ set(LWS_WITH_POLL 1) if (ESP_PLATFORM) set(LWS_ESP_PLATFORM 1) - set(CMAKE_TOOLCHAIN_FILE contrib/cross-esp32.cmake) + #set(CMAKE_TOOLCHAIN_FILE contrib/cross-esp32.cmake) set(LWIP_PROVIDE_ERRNO 1) endif() @@ -66,6 +66,18 @@ endif() project(libwebsockets C) include(CTest) +if (ESP_PLATFORM) + include_directories( + ${IDF_PATH}/components/freertos/port/xtensa/include/ + ${IDF_PATH}/components/hal/include + ${IDF_PATH}/components/soc/${CONFIG_IDF_TARGET}/include/ + ${IDF_PATH}/components/soc/include/ + ${IDF_PATH}/components/esp_hw_support/include + ${IDF_PATH}/components/hal/${CONFIG_IDF_TARGET}/include/ + ) +endif() + + # # Select features recommended for PC distro packaging # @@ -152,6 +164,7 @@ option(LWS_WITH_LIBEV "Compile with support for libev" OFF) option(LWS_WITH_LIBUV "Compile with support for libuv" OFF) option(LWS_WITH_LIBEVENT "Compile with support for libevent" OFF) option(LWS_WITH_GLIB "Compile with support for glib event loop" OFF) +option(LWS_WITH_SDEVENT "Compile with support for sd-event loop" OFF) if (UNIX) # since v4.1, on unix platforms default is build any event libs as runtime plugins @@ -338,7 +351,7 @@ set(CPACK_RPM_PACKAGE_LICENSE "MIT") set(CPACK_PACKAGE_NAME "${PACKAGE}") set(CPACK_PACKAGE_VERSION_MAJOR "4") set(CPACK_PACKAGE_VERSION_MINOR "1") -set(CPACK_PACKAGE_VERSION_PATCH_NUMBER "4") +set(CPACK_PACKAGE_VERSION_PATCH_NUMBER "6") set(CPACK_PACKAGE_VERSION_PATCH "${CPACK_PACKAGE_VERSION_PATCH_NUMBER}-${LWS_BUILD_HASH}") set(CPACK_PACKAGE_RELEASE 1) @@ -835,13 +848,7 @@ else() set(DEF_INSTALL_CMAKE_DIR lib${LIB_SUFFIX}/cmake/libwebsockets) endif() -if (DEFINED REL_INCLUDE_DIR) - set(LWS__INCLUDE_DIRS "\${LWS_CMAKE_DIR}/${REL_INCLUDE_DIR}") -endif() -configure_file(${PROJECT_SOURCE_DIR}/cmake/libwebsockets-config.cmake.in - ${PROJECT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/libwebsockets-config.cmake - @ONLY) # Generate version info for both build-tree and install-tree. configure_file(${PROJECT_SOURCE_DIR}/cmake/libwebsockets-config-version.cmake.in @@ -938,6 +945,14 @@ file(RELATIVE_PATH "${LWS_ABSOLUTE_INSTALL_CMAKE_DIR}" "${LWS_ABSOLUTE_INSTALL_INCLUDE_DIR}") # Calculate the relative directory from the cmake dir. +if (DEFINED REL_INCLUDE_DIR) + set(LWS__INCLUDE_DIRS "\${LWS_CMAKE_DIR}/${REL_INCLUDE_DIR}") +endif() + +configure_file(${PROJECT_SOURCE_DIR}/cmake/libwebsockets-config.cmake.in + ${PROJECT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/libwebsockets-config.cmake + @ONLY) + set_target_properties(${LWS_LIBRARIES} PROPERTIES PUBLIC_HEADER "${HDR_PUBLIC}") diff --git a/cmake/lws_config.h.in b/cmake/lws_config.h.in index 69d1877588..b28577b4b3 100644 --- a/cmake/lws_config.h.in +++ b/cmake/lws_config.h.in @@ -150,6 +150,7 @@ #cmakedefine LWS_WITH_LIBEV #cmakedefine LWS_WITH_LIBEVENT #cmakedefine LWS_WITH_LIBUV +#cmakedefine LWS_WITH_SDEVENT #cmakedefine LWS_WITH_LWSAC #cmakedefine LWS_LOGS_TIMESTAMP #cmakedefine LWS_WITH_MBEDTLS diff --git a/include/libwebsockets/lws-context-vhost.h b/include/libwebsockets/lws-context-vhost.h index 8e08128525..5fbc4fd009 100644 --- a/include/libwebsockets/lws-context-vhost.h +++ b/include/libwebsockets/lws-context-vhost.h @@ -230,6 +230,9 @@ /**< (CTX) Disable lws_system state, eg, because we are a secure streams * proxy client that is not trying to track system state by itself. */ +#define LWS_SERVER_OPTION_SDEVENT (1ll << 36) + /**< (CTX) Use sd-event loop */ + /****** add new things just above ---^ ******/ diff --git a/lib/core-net/dummy-callback.c b/lib/core-net/dummy-callback.c index 8e7c782c0a..aa0d3730f0 100644 --- a/lib/core-net/dummy-callback.c +++ b/lib/core-net/dummy-callback.c @@ -294,7 +294,7 @@ lws_callback_http_dummy(struct lws *wsi, enum lws_callback_reasons reason, case LWS_CALLBACK_HTTP_BODY_COMPLETION: #if defined(LWS_WITH_HTTP_PROXY) if (wsi->child_list) { - lwsl_user("%s: LWS_CALLBACK_HTTP_BODY_COMPLETION: %d\n", __func__, (int)len); + lwsl_info("%s: LWS_CALLBACK_HTTP_BODY_COMPLETION: %d\n", __func__, (int)len); break; } #endif @@ -308,7 +308,7 @@ lws_callback_http_dummy(struct lws *wsi, enum lws_callback_reasons reason, #if defined(LWS_WITH_HTTP_PROXY) case LWS_CALLBACK_HTTP_BODY: if (wsi->child_list) { - lwsl_user("%s: LWS_CALLBACK_HTTP_BODY: stashing %d\n", __func__, (int)len); + lwsl_info("%s: LWS_CALLBACK_HTTP_BODY: stashing %d\n", __func__, (int)len); if (lws_buflist_append_segment(&wsi->http.buflist_post_body, in, len) < 0) return -1; lws_callback_on_writable(wsi->child_list); @@ -790,7 +790,7 @@ lws_callback_http_dummy(struct lws *wsi, enum lws_callback_reasons reason, lwsl_notice("LWS_CALLBACK_CGI_STDIN_DATA: " "sent %d only %d went", n, args->len); - lwsl_notice("%s: proxied %d bytes\n", __func__, n); + lwsl_info("%s: proxied %d bytes\n", __func__, n); if (wsi->http.cgi->post_in_expected && args->stdwsi[LWS_STDIN] && args->stdwsi[LWS_STDIN]->desc.filefd > 0) { @@ -807,7 +807,7 @@ lws_callback_http_dummy(struct lws *wsi, enum lws_callback_reasons reason, * if no content-length)... */ - lwsl_notice("%s: expected POST in end: " + lwsl_info("%s: expected POST in end: " "closing stdin wsi %p, fd %d\n", __func__, siwsi, siwsi->desc.sockfd); diff --git a/lib/core/context.c b/lib/core/context.c index 7a20fefaf1..b9e4da6fb2 100644 --- a/lib/core/context.c +++ b/lib/core/context.c @@ -340,6 +340,7 @@ static const struct lws_evlib_map { { LWS_SERVER_OPTION_LIBEVENT, "evlib_event" }, { LWS_SERVER_OPTION_GLIB, "evlib_glib" }, { LWS_SERVER_OPTION_LIBEV, "evlib_ev" }, + { LWS_SERVER_OPTION_SDEVENT, "evlib_sd" }, }; static const char * const dlist[] = { LWS_INSTALL_LIBDIR, @@ -380,6 +381,9 @@ lws_create_context(const struct lws_context_creation_info *info) #if defined(LWS_WITH_EVLIB_PLUGINS) && defined(LWS_WITH_EVENT_LIBS) struct lws_plugin *evlib_plugin_list = NULL; #endif +#if defined(LWS_WITH_LIBUV) + char fatal_exit_defer = 0; +#endif if (lpf) { lpf+= 2; @@ -459,6 +463,11 @@ lws_create_context(const struct lws_context_creation_info *info) goto bail; } +#if defined(LWS_WITH_LIBUV) + if (!n) /* libuv */ + fatal_exit_defer = !!info->foreign_loops; +#endif + if (!evlib_plugin_list) { lwsl_err("%s: unable to load evlib plugin %s\n", __func__, map[n].name); @@ -487,6 +496,7 @@ lws_create_context(const struct lws_context_creation_info *info) if (lws_check_opt(info->options, LWS_SERVER_OPTION_LIBUV)) { extern const lws_plugin_evlib_t evlib_uv; plev = &evlib_uv; + fatal_exit_defer = !!info->foreign_loops; } #endif @@ -511,6 +521,13 @@ lws_create_context(const struct lws_context_creation_info *info) } #endif +#if defined(LWS_WITH_SDEVENT) + if (lws_check_opt(info->options, LWS_SERVER_OPTION_SDEVENT)) { + extern const lws_plugin_evlib_t evlib_sd; + plev = &evlib_sd; + } +#endif + #endif /* with event libs */ #endif /* not with ev plugins */ @@ -699,7 +716,7 @@ lws_create_context(const struct lws_context_creation_info *info) if (n == -1) { lwsl_err("Get RLIMIT_NOFILE failed!\n"); - return NULL; + goto free_context_fail; } context->max_fds = rt.rlim_cur; #else @@ -723,7 +740,7 @@ lws_create_context(const struct lws_context_creation_info *info) lwsl_err("%s: problem getting process max files\n", __func__); - return NULL; + goto free_context_fail; } #endif @@ -959,13 +976,19 @@ lws_create_context(const struct lws_context_creation_info *info) context->fd_limit_per_thread; #endif + + /* + * Past here, we may have added handles to the event lib + * loop and if libuv, have to take care about how to unpick them... + */ + if (lws_plat_init(context, info)) - goto bail; + goto bail_libuv_aware; #if defined(LWS_WITH_NETWORK) if (context->event_loop_ops->init_context) if (context->event_loop_ops->init_context(context, info)) - goto bail; + goto bail_libuv_aware; if (context->event_loop_ops->init_pt) @@ -976,11 +999,11 @@ lws_create_context(const struct lws_context_creation_info *info) lp = info->foreign_loops[n]; if (context->event_loop_ops->init_pt(context, lp, n)) - goto bail; + goto bail_libuv_aware; } if (lws_create_event_pipes(context)) - goto bail; + goto bail_libuv_aware; #endif lws_context_init_ssl_library(info); @@ -1053,18 +1076,18 @@ lws_create_context(const struct lws_context_creation_info *info) if (!vh) { lwsl_err("%s: failed to create system vhost\n", __func__); - goto bail; + goto bail_libuv_aware; } context->vhost_system = vh; if (lws_protocol_init_vhost(vh, NULL)) { lwsl_err("%s: failed to init system vhost\n", __func__); - goto bail; + goto bail_libuv_aware; } #if defined(LWS_WITH_SYS_ASYNC_DNS) if (lws_async_dns_init(context)) - goto bail; + goto bail_libuv_aware; #endif } #endif @@ -1124,17 +1147,17 @@ lws_create_context(const struct lws_context_creation_info *info) LWS_SERVER_OPTION_EXPLICIT_VHOSTS)); if (lws_ss_policy_parse_begin(context, 0)) - goto bail; + goto bail_libuv_aware; n = lws_ss_policy_parse(context, (uint8_t *)context->pss_policies_json, strlen(context->pss_policies_json)); if (n != LEJP_CONTINUE && n < 0) - goto bail; + goto bail_libuv_aware; if (lws_ss_policy_set(context, "hardcoded")) { lwsl_err("%s: policy set failed\n", __func__); - goto bail; + goto bail_libuv_aware; } } else #else @@ -1143,7 +1166,7 @@ lws_create_context(const struct lws_context_creation_info *info) if (lws_ss_policy_set(context, "hardcoded")) { lwsl_err("%s: policy set failed\n", __func__); - goto bail; + goto bail_libuv_aware; } } //else #endif @@ -1162,7 +1185,7 @@ lws_create_context(const struct lws_context_creation_info *info) */ if (!lws_check_opt(info->options, LWS_SERVER_OPTION_EXPLICIT_VHOSTS)) if (lws_plat_drop_app_privileges(context, 1)) - goto bail; + goto bail_libuv_aware; #if defined(LWS_WITH_SYS_STATE) /* @@ -1186,6 +1209,14 @@ lws_create_context(const struct lws_context_creation_info *info) #if defined(LWS_WITH_NETWORK) fail_clean_pipes: + +#if defined(LWS_WITH_LIBUV) + if (fatal_exit_defer) { + lws_context_destroy(context); + return context; + } +#endif + for (n = 0; n < context->count_threads; n++) lws_destroy_event_pipe(context->pt[n].pipe_wsi); @@ -1201,9 +1232,18 @@ lws_create_context(const struct lws_context_creation_info *info) return NULL; +bail_libuv_aware: + lws_context_destroy(context); +#if defined(LWS_WITH_LIBUV) + return fatal_exit_defer ? context : NULL; +#else + return NULL; +#endif + fail_event_libs: lwsl_err("Requested event library support not configured\n"); +free_context_fail: lws_free(context); return NULL; diff --git a/lib/event-libs/CMakeLists.txt b/lib/event-libs/CMakeLists.txt index d501bbcb39..df785edd69 100644 --- a/lib/event-libs/CMakeLists.txt +++ b/lib/event-libs/CMakeLists.txt @@ -91,6 +91,10 @@ if (LWS_WITH_LIBEV) set(LWS_HAVE_EVBACKEND_IOURING ${LWS_HAVE_EVBACKEND_IOURING} PARENT_SCOPE) endif() +if (LWS_WITH_SDEVENT) + add_subdir_include_directories(sdevent) +endif() + # diff --git a/lib/event-libs/libevent/libevent.c b/lib/event-libs/libevent/libevent.c index 1a9fc6c770..eade5b5464 100644 --- a/lib/event-libs/libevent/libevent.c +++ b/lib/event-libs/libevent/libevent.c @@ -29,7 +29,7 @@ #define wsi_to_priv_event(_w) ((struct lws_wsi_eventlibs_libevent *)(_w)->evlib_wsi) static void -lws_event_hrtimer_cb(int fd, short event, void *p) +lws_event_hrtimer_cb(evutil_socket_t fd, short event, void *p) { struct lws_context_per_thread *pt = (struct lws_context_per_thread *)p; struct lws_pt_eventlibs_libevent *ptpr = pt_to_priv_event(pt); @@ -48,7 +48,7 @@ lws_event_hrtimer_cb(int fd, short event, void *p) } static void -lws_event_idle_timer_cb(int fd, short event, void *p) +lws_event_idle_timer_cb(evutil_socket_t fd, short event, void *p) { struct lws_context_per_thread *pt = (struct lws_context_per_thread *)p; struct lws_pt_eventlibs_libevent *ptpr = pt_to_priv_event(pt); @@ -255,7 +255,7 @@ elops_accept_event(struct lws *wsi) struct lws_context_per_thread *pt; struct lws_pt_eventlibs_libevent *ptpr; struct lws_wsi_eventlibs_libevent *wpr = wsi_to_priv_event(wsi); - int fd; + evutil_socket_t fd; wpr->w_read.context = context; wpr->w_write.context = context; @@ -265,7 +265,7 @@ elops_accept_event(struct lws *wsi) ptpr = pt_to_priv_event(pt); if (wsi->role_ops->file_handle) - fd = wsi->desc.filefd; + fd = (ev_intptr_t) wsi->desc.filefd; else fd = wsi->desc.sockfd; @@ -404,7 +404,7 @@ elops_init_vhost_listen_wsi_event(struct lws *wsi) struct lws_context_per_thread *pt; struct lws_pt_eventlibs_libevent *ptpr; struct lws_wsi_eventlibs_libevent *w; - int fd; + evutil_socket_t fd; if (!wsi) { assert(0); @@ -420,7 +420,7 @@ elops_init_vhost_listen_wsi_event(struct lws *wsi) ptpr = pt_to_priv_event(pt); if (wsi->role_ops->file_handle) - fd = wsi->desc.filefd; + fd = (evutil_socket_t) wsi->desc.filefd; else fd = wsi->desc.sockfd; diff --git a/lib/event-libs/sdevent/CMakeLists.txt b/lib/event-libs/sdevent/CMakeLists.txt new file mode 100644 index 0000000000..c4222d3881 --- /dev/null +++ b/lib/event-libs/sdevent/CMakeLists.txt @@ -0,0 +1,44 @@ +# The strategy is to only export to PARENT_SCOPE +# +# - changes to LIB_LIST +# - includes via include_directories +# +# and keep everything else private + +include_directories(.) + +# configure or find systemd library +set(LIB_SYSTEMD_LIBRARIES CACHE PATH "Path to the libsystemd library") +if ("${LWS_SYSTEMD_LIBRARIES}" STREQUAL "") + if (NOT LIB_SYSTEMD_FOUND) + find_path(LIBSYSTEMD_INCLUDE_DIRS NAMES systemd/sd-event.h) + find_library(LIBSYSTEMD_LIBRARIES NAMES systemd) + endif() +else() + set(LIBSYSTEMD_LIBRARIES ${LWS_SYSTEMD_LIBRARIES}) + set(LIBSYSTEMD_INCLUDE_DIRS ${LWS_LIBSYSTEMD_INCLUDE_DIRS}) +endif() +message("libsystemd include dir: ${LIBSYSTEMD_INCLUDE_DIRS}") +message("libsystemd libraries: ${LIBSYSTEMD_LIBRARIES}") + +if (LWS_WITH_EVLIB_PLUGINS) + + create_evlib_plugin( + evlib_sd + sdevent.c + private-lib-event-libs-sdevent.h + ${LIBSYSTEMD_LIBRARIES} + ) + +else() + + list(APPEND LIB_LIST ${LIBSYSTEMD_LIBRARIES}) + list(APPEND SOURCES event-libs/sdevent/sdevent.c) + +endif() + +# +# Keep explicit parent scope exports at end +# + +exports_to_parent_scope() diff --git a/lib/event-libs/sdevent/private-lib-event-libs-sdevent.h b/lib/event-libs/sdevent/private-lib-event-libs-sdevent.h new file mode 100644 index 0000000000..b530d7052f --- /dev/null +++ b/lib/event-libs/sdevent/private-lib-event-libs-sdevent.h @@ -0,0 +1,3 @@ +#include + +extern const struct lws_event_loop_ops event_loop_ops_sdevent; diff --git a/lib/event-libs/sdevent/sdevent.c b/lib/event-libs/sdevent/sdevent.c new file mode 100644 index 0000000000..aff2283878 --- /dev/null +++ b/lib/event-libs/sdevent/sdevent.c @@ -0,0 +1,399 @@ +#include + +#include +#include "private-lib-event-libs-sdevent.h" + +#define pt_to_priv_sd(_pt) ((struct lws_pt_eventlibs_sdevent *)(_pt)->evlib_pt) +#define wsi_to_priv_sd(_w) ((struct lws_wsi_watcher_sdevent *)(_w)->evlib_wsi) + +struct lws_context_eventlibs_sdevent { +}; + +struct lws_pt_eventlibs_sdevent { + struct lws_context_per_thread *pt; + struct sd_event *io_loop; + struct sd_event_source *sultimer; + struct sd_event_source *idletimer; +}; + +struct lws_vh_eventlibs_sdevent { +}; + +struct lws_wsi_watcher_sdevent { + struct sd_event_source *source; + uint32_t events; +}; + +static int sultimer_handler(sd_event_source *s, uint64_t usec, void *userdata) { + struct lws_context_per_thread *pt = (struct lws_context_per_thread*) userdata; + + lws_usec_t us; + + lws_context_lock(pt->context, __func__); + lws_pt_lock(pt, __func__); + us = __lws_sul_service_ripe(pt->pt_sul_owner, LWS_COUNT_PT_SUL_OWNERS, + lws_now_usecs()); + if (us) { + uint64_t alarmTime; + sd_event_now(sd_event_source_get_event(s), CLOCK_MONOTONIC, &alarmTime); + alarmTime += us; + sd_event_source_set_time(pt_to_priv_sd(pt)->sultimer, alarmTime); + sd_event_source_set_enabled(pt_to_priv_sd(pt)->sultimer, SD_EVENT_ONESHOT); + } + + lws_pt_unlock(pt); + lws_context_unlock(pt->context); + + return 0; +} + +static int idle_handler(sd_event_source *s, uint64_t usec, void *userdata) { + struct lws_context_per_thread *pt = (struct lws_context_per_thread*) userdata; + + lws_usec_t us; + + lws_service_do_ripe_rxflow(pt); + + lws_context_lock(pt->context, __func__); + lws_pt_lock(pt, __func__); + + /* + * is there anybody with pending stuff that needs service forcing? + */ + if (!lws_service_adjust_timeout(pt->context, 1, pt->tid)) { + /* -1 timeout means just do forced service */ + _lws_plat_service_forced_tsi(pt->context, pt->tid); + } + + /* account for sultimer */ + + us = __lws_sul_service_ripe(pt->pt_sul_owner, LWS_COUNT_PT_SUL_OWNERS, + lws_now_usecs()); + + if (us) { + uint64_t alarmTime; + sd_event_now(sd_event_source_get_event(s), CLOCK_MONOTONIC, &alarmTime); + alarmTime += us; + sd_event_source_set_time(pt_to_priv_sd(pt)->sultimer, alarmTime); + sd_event_source_set_enabled(pt_to_priv_sd(pt)->sultimer, SD_EVENT_ONESHOT); + } + + sd_event_source_set_enabled(pt_to_priv_sd(pt)->idletimer, SD_EVENT_OFF); + + lws_pt_unlock(pt); + lws_context_unlock(pt->context); + + return 0; +} + +static int sock_accept_handler(sd_event_source *s, int fd, uint32_t revents, void *userdata) { + struct lws *wsi = (struct lws*) userdata; + struct lws_context *context = wsi->a.context; + struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi]; + struct lws_pollfd eventfd; + + lws_context_lock(pt->context, __func__); + lws_pt_lock(pt, __func__); + + if (pt->is_destroyed) + goto bail; + + eventfd.fd = fd; + eventfd.events = 0; + eventfd.revents = 0; + + if (revents & EPOLLIN) { + eventfd.events |= LWS_POLLIN; + eventfd.revents |= LWS_POLLIN; + } + + if (revents & EPOLLOUT) { + eventfd.events |= LWS_POLLOUT; + eventfd.revents |= LWS_POLLOUT; + } + + lws_pt_unlock(pt); + lws_context_unlock(pt->context); + + lws_service_fd_tsi(context, &eventfd, wsi->tsi); + + if (pt->destroy_self) { + lws_context_destroy(pt->context); + return -1; + } + + // fire idle handler + struct sd_event_source *idletimer = pt_to_priv_sd(pt)->idletimer; + if (idletimer) { + sd_event_source_set_time(idletimer, (uint64_t) 0); + sd_event_source_set_enabled(idletimer, SD_EVENT_ON); + } + + // allow further events + // Note: do not move the assignment up, lws_service_fd_tsi may invalidate it! + struct sd_event_source *watcher = wsi_to_priv_sd(wsi)->source; + if (watcher) { + sd_event_source_set_enabled(watcher, SD_EVENT_ONESHOT); + } + + return 0; + +bail: + lws_pt_unlock(pt); + lws_context_unlock(pt->context); + + return -1; +} + +static void io_sd(struct lws *wsi, int flags) { + struct lws_context_per_thread *pt = &wsi->a.context->pt[(int)wsi->tsi]; + + // only manipulate if there is an event source and if the pt is still alive + if (!pt_to_priv_sd(pt)->io_loop || !wsi_to_priv_sd(wsi)->source || pt->is_destroyed) { + return; + } + + // assert that the requested flags do not contain anything unexpected + if (!((flags & (LWS_EV_START | LWS_EV_STOP)) && + (flags & (LWS_EV_READ | LWS_EV_WRITE)))) { + lwsl_err("%s: assert: flags %d", __func__, flags); + assert(0); + } + + // we are overdoing a bit here, so it resembles the structure in libuv.c + if (flags & LWS_EV_START) { + if (flags & LWS_EV_WRITE) + wsi_to_priv_sd(wsi)->events |= EPOLLOUT; + + if (flags & LWS_EV_READ) + wsi_to_priv_sd(wsi)->events |= EPOLLIN; + + sd_event_source_set_io_events(wsi_to_priv_sd(wsi)->source, wsi_to_priv_sd(wsi)->events); + sd_event_source_set_enabled(wsi_to_priv_sd(wsi)->source, SD_EVENT_ONESHOT); + } else { + if (flags & LWS_EV_WRITE) + wsi_to_priv_sd(wsi)->events &= ~EPOLLOUT; + + if (flags & LWS_EV_READ) + wsi_to_priv_sd(wsi)->events &= ~EPOLLIN; + + sd_event_source_set_io_events(wsi_to_priv_sd(wsi)->source, wsi_to_priv_sd(wsi)->events); + + if (!(wsi_to_priv_sd(wsi)->events & (EPOLLIN | EPOLLOUT))) + sd_event_source_set_enabled(wsi_to_priv_sd(wsi)->source, SD_EVENT_ONESHOT); + else + sd_event_source_set_enabled(wsi_to_priv_sd(wsi)->source, SD_EVENT_OFF); + } +} + +static int init_vhost_listen_wsi_sd(struct lws *wsi) { + if (!wsi) + return 0; + + struct lws_context_per_thread *pt = &wsi->a.context->pt[(int)wsi->tsi]; + + void *userdata = wsi; + + sd_event_add_io( + pt_to_priv_sd(pt)->io_loop, + &wsi_to_priv_sd(wsi)->source, + wsi->desc.sockfd, + wsi_to_priv_sd(wsi)->events, + sock_accept_handler, + userdata + ); + + io_sd(wsi, LWS_EV_START | LWS_EV_READ); + + return 0; +} + +static int init_pt_sd(struct lws_context *context, void *_loop, int tsi) { + struct lws_context_per_thread *pt = &context->pt[tsi]; + struct lws_pt_eventlibs_sdevent *ptpriv = pt_to_priv_sd(pt); + + struct sd_event *loop = (struct sd_event *)_loop; + int first = 1; // we are the first that create and initialize the loop + + ptpriv->pt = pt; + + // make sure we have an event loop + if (!ptpriv->io_loop) { + if (!loop) { + if (sd_event_default(&loop) < 0) { + lwsl_err("cannot get/create event loop, possibly out-of-memory\n"); + return -1; + } + pt->event_loop_foreign = 0; + } else { + sd_event_ref(loop); + pt->event_loop_foreign = 1; + } + + ptpriv->io_loop = loop; + + } else { + first = 0; // the loop was initialized before, we do not need to do full initialization + } + + // initialize accept/read for vhosts + // Note: default vhost usually not included here + for (struct lws_vhost *vh = context->vhost_list; vh; vh = vh->vhost_next) { + // call lws_event_loop_ops->init_vhost_listen_wsi + if (init_vhost_listen_wsi_sd(vh->lserv_wsi) == -1) { + return -1; + } + } + + if (first) { + + if (0 > sd_event_add_time( + loop, + &ptpriv->sultimer, + CLOCK_MONOTONIC, + UINT64_MAX, + 0, + sultimer_handler, + (void*) pt + )) { + return -1; + } + + if (0 > sd_event_add_time( + loop, + &ptpriv->idletimer, + CLOCK_MONOTONIC, + 0, + 0, + idle_handler, + (void*) pt + )) { + return -1; + } + + sd_event_source_set_enabled(ptpriv->idletimer, SD_EVENT_ON); + + if (0 > sd_event_source_set_priority( + ptpriv->idletimer, + SD_EVENT_PRIORITY_IDLE + )) { + return -1; + } + } + + return 0; +} + +static void wsi_destroy_sd(struct lws *wsi) { + if (wsi) { + io_sd(wsi, LWS_EV_STOP | (LWS_EV_READ | LWS_EV_WRITE)); + + if (wsi_to_priv_sd(wsi)->source) { + sd_event_source_set_enabled(wsi_to_priv_sd(wsi)->source, SD_EVENT_OFF); + sd_event_source_unref(wsi_to_priv_sd(wsi)->source); + wsi_to_priv_sd(wsi)->source = NULL; + } + } +} + +static int wsi_logical_close_sd(struct lws *wsi) { + wsi_destroy_sd(wsi); + return 0; +} + +static int sock_accept_sd(struct lws *wsi) { + struct lws_context_per_thread *pt = &wsi->a.context->pt[(int)wsi->tsi]; + + void *userdata = wsi; + + if (wsi->role_ops->file_handle) + sd_event_add_io( + pt_to_priv_sd(pt)->io_loop, + &wsi_to_priv_sd(wsi)->source, + wsi->desc.filefd, + wsi_to_priv_sd(wsi)->events, + sock_accept_handler, + userdata + ); + else + sd_event_add_io( + pt_to_priv_sd(pt)->io_loop, + &wsi_to_priv_sd(wsi)->source, + wsi->desc.sockfd, + wsi_to_priv_sd(wsi)->events, + sock_accept_handler, + userdata + ); + + return 0; +} + +static void run_pt_sd(struct lws_context *context, int tsi) { + struct lws_context_per_thread *pt = &context->pt[tsi]; + struct lws_pt_eventlibs_sdevent *ptpriv = pt_to_priv_sd(pt); + if(ptpriv->io_loop) { + sd_event_run(ptpriv->io_loop, (uint64_t) -1); + } +} + +static void destroy_pt_sd(struct lws_context *context, int tsi) { + struct lws_context_per_thread *pt = &context->pt[tsi]; + struct lws_pt_eventlibs_sdevent *ptpriv = pt_to_priv_sd(pt); + + for (struct lws_vhost *vh = context->vhost_list; vh; vh = vh->vhost_next) { + if (vh->lserv_wsi) { + wsi_logical_close_sd(vh->lserv_wsi); + } + if (ptpriv->sultimer) { + sd_event_source_set_enabled(ptpriv->sultimer, SD_EVENT_OFF); + sd_event_source_unref(ptpriv->sultimer); + ptpriv->sultimer = NULL; + } + if (ptpriv->idletimer) { + sd_event_source_set_enabled(ptpriv->idletimer, SD_EVENT_OFF); + sd_event_source_unref(ptpriv->idletimer); + ptpriv->idletimer = NULL; + } + if (ptpriv->io_loop) { + sd_event_unref(ptpriv->io_loop); + ptpriv->io_loop = NULL; + } + } +} + +const struct lws_event_loop_ops event_loop_ops_sdevent = { + .name = "sdevent", + .init_context = NULL, + .destroy_context1 = NULL, + .destroy_context2 = NULL, + .init_vhost_listen_wsi = init_vhost_listen_wsi_sd, + .init_pt = init_pt_sd, + .wsi_logical_close = wsi_logical_close_sd, + .check_client_connect_ok = NULL, + .close_handle_manually = NULL, + .sock_accept = sock_accept_sd, + .io = io_sd, + .run_pt = run_pt_sd, + .destroy_pt = destroy_pt_sd, + .destroy_wsi = wsi_destroy_sd, + + .flags = 0, + + .evlib_size_ctx = sizeof(struct lws_context_eventlibs_sdevent), + .evlib_size_pt = sizeof(struct lws_pt_eventlibs_sdevent), + .evlib_size_vh = sizeof(struct lws_vh_eventlibs_sdevent), + .evlib_size_wsi = sizeof(struct lws_wsi_watcher_sdevent), +}; + +#if defined(LWS_WITH_EVLIB_PLUGINS) +LWS_VISIBLE +#endif +const lws_plugin_evlib_t evlib_sd = { + .hdr = { + "systemd event loop", + "lws_evlib_plugin", + LWS_PLUGIN_API_MAGIC + }, + + .ops = &event_loop_ops_sdevent +}; diff --git a/lib/plat/windows/CMakeLists.txt b/lib/plat/windows/CMakeLists.txt index 68b71cd645..c26c8e7714 100644 --- a/lib/plat/windows/CMakeLists.txt +++ b/lib/plat/windows/CMakeLists.txt @@ -50,7 +50,7 @@ if (LWS_WITH_SPAWN) endif() if (LWS_WITH_ZLIB AND LWS_WITH_BUNDLED_ZLIB) - set(WIN32_ZLIB_PATH "win32port/zlib") + set(WIN32_ZLIB_PATH "${CMAKE_CURRENT_SOURCE_DIR}/../../../win32port/zlib") set(ZLIB_SRCS ${WIN32_ZLIB_PATH}/adler32.c ${WIN32_ZLIB_PATH}/compress.c @@ -68,7 +68,7 @@ if (LWS_WITH_ZLIB AND LWS_WITH_BUNDLED_ZLIB) ${WIN32_ZLIB_PATH}/zutil.c) add_library(zlib_internal STATIC ${ZLIB_SRCS}) set(ZLIB_INCLUDE_DIRS ${WIN32_ZLIB_PATH}) - get_property(ZLIB_LIBRARIES TARGET zlib_internal PROPERTY LOCATION) + set(ZLIB_LIBRARIES "") set(ZLIB_FOUND 1) # Make sure zlib_internal is compiled before the libs. foreach (lib ${LWS_LIBRARIES}) diff --git a/lib/roles/cgi/cgi-server.c b/lib/roles/cgi/cgi-server.c index f37a2b4b73..6100a8b987 100644 --- a/lib/roles/cgi/cgi-server.c +++ b/lib/roles/cgi/cgi-server.c @@ -621,7 +621,9 @@ lws_cgi_write_split_stdout_headers(struct lws *wsi) lwsl_debug("%s: freed cgi headers\n", __func__); if (wsi->http.cgi->post_in_expected) { - lwsl_notice("%s: post data still expected, asking for writeable\n", __func__); + lwsl_info("%s: post data still expected, " + "asking for writeable\n", + __func__); lws_callback_on_writable(wsi); } diff --git a/lib/roles/cgi/ops-cgi.c b/lib/roles/cgi/ops-cgi.c index 40370e1a4f..dff70f6678 100644 --- a/lib/roles/cgi/ops-cgi.c +++ b/lib/roles/cgi/ops-cgi.c @@ -47,7 +47,7 @@ rops_handle_POLLIN_cgi(struct lws_context_per_thread *pt, struct lws *wsi, } if (!wsi->parent) { - lwsl_notice("%s: stdwsi content with parent\n", + lwsl_debug("%s: stdwsi content with parent\n", __func__); return LWS_HPI_RET_HANDLED; diff --git a/lib/roles/h2/http2.c b/lib/roles/h2/http2.c index cce4208ee7..35458499ea 100644 --- a/lib/roles/h2/http2.c +++ b/lib/roles/h2/http2.c @@ -953,8 +953,16 @@ lws_h2_parse_frame_header(struct lws *wsi) if (h2n->we_told_goaway && h2n->sid > h2n->highest_sid) h2n->type = LWS_H2_FRAME_TYPE_COUNT; /* ie, IGNORE */ - if (h2n->type == LWS_H2_FRAME_TYPE_COUNT) - return 0; + if (h2n->type >= LWS_H2_FRAME_TYPE_COUNT) { + lwsl_info("%s: ignoring unknown frame type %d (len %d)\n", __func__, h2n->type, (unsigned int)h2n->length); + /* we MUST ignore frames we don't understand */ + h2n->type = LWS_H2_FRAME_TYPE_COUNT; + } + + /* + * Even if we have decided to logically ignore this frame, we must + * consume the correct "frame length" amount of data to retain sync + */ if (h2n->length > h2n->our_set.s[H2SET_MAX_FRAME_SIZE]) { /* @@ -1003,7 +1011,7 @@ lws_h2_parse_frame_header(struct lws *wsi) } } - if (h2n->swsi && h2n->sid && + if (h2n->swsi && h2n->sid && h2n->type != LWS_H2_FRAME_TYPE_COUNT && !(http2_rx_validity[h2n->swsi->h2.h2_state] & (1 << h2n->type))) { lwsl_info("%s: wsi %p, State: %s, ILLEGAL cmdrx %d (OK 0x%x)\n", __func__, h2n->swsi, @@ -1020,7 +1028,8 @@ lws_h2_parse_frame_header(struct lws *wsi) return 0; } - if (h2n->cont_exp && (h2n->cont_exp_sid != h2n->sid || + if (h2n->cont_exp && h2n->type != LWS_H2_FRAME_TYPE_COUNT && + (h2n->cont_exp_sid != h2n->sid || h2n->type != LWS_H2_FRAME_TYPE_CONTINUATION)) { lwsl_info("%s: expected cont on sid %u (got %d on sid %u)\n", __func__, (unsigned int)h2n->cont_exp_sid, h2n->type, @@ -1322,6 +1331,10 @@ lws_h2_parse_frame_header(struct lws *wsi) lwsl_info("LWS_H2_FRAME_TYPE_WINDOW_UPDATE\n"); break; case LWS_H2_FRAME_TYPE_COUNT: + if (h2n->length == 0) + lws_h2_parse_end_of_frame(wsi); + else + lwsl_debug("%s: going on to deal with unknown frame remaining len %d\n", __func__, (unsigned int)h2n->length); break; default: lwsl_info("%s: ILLEGAL FRAME TYPE %d\n", __func__, h2n->type); @@ -1870,7 +1883,7 @@ lws_h2_parser(struct lws *wsi, unsigned char *in, lws_filepos_t inlen, c = *in++; - // lwsl_notice("%s: 0x%x\n", __func__, c); + lwsl_debug("%s: 0x%x, count %u, len %u (type %d)\n", __func__, c, (unsigned int)h2n->count, (unsigned int)h2n->length, h2n->type); switch (lwsi_state(wsi)) { case LRS_H2_AWAIT_PREFACE: @@ -1900,6 +1913,7 @@ lws_h2_parser(struct lws *wsi, unsigned char *in, lws_filepos_t inlen, case LRS_H2_WAITING_TO_SEND_HEADERS: case LRS_ESTABLISHED: case LRS_H2_AWAIT_SETTINGS: + if (h2n->frame_state != LWS_H2_FRAME_HEADER_LENGTH) goto try_frame_start; @@ -1908,6 +1922,12 @@ lws_h2_parser(struct lws *wsi, unsigned char *in, lws_filepos_t inlen, */ h2n->count++; + if (h2n->type == LWS_H2_FRAME_TYPE_COUNT) { /* IGNORING FRAME */ + lwsl_debug("%s: consuming for ignored %u %u\n", __func__, (unsigned int)h2n->count, (unsigned int)h2n->length); + goto frame_end; + } + + if (h2n->flags & LWS_H2_FLAG_PADDED && !h2n->pad_length) { /* @@ -2236,6 +2256,8 @@ lws_h2_parser(struct lws *wsi, unsigned char *in, lws_filepos_t inlen, break; case LWS_H2_FRAME_TYPE_COUNT: /* IGNORING FRAME */ + lwsl_debug("%s: consuming for ignored %u %u\n", __func__, (unsigned int)h2n->count, (unsigned int)h2n->length); + h2n->count++; break; default: @@ -2247,13 +2269,13 @@ lws_h2_parser(struct lws *wsi, unsigned char *in, lws_filepos_t inlen, frame_end: if (h2n->count > h2n->length) { - lwsl_notice("%s: count > length %u %u\n", + lwsl_notice("%s: count > length %u %u (type %d)\n", __func__, (unsigned int)h2n->count, - (unsigned int)h2n->length); - goto fail; - } - if (h2n->count != h2n->length) - break; + (unsigned int)h2n->length, h2n->type); + + } else + if (h2n->count != h2n->length) + break; /* * end of frame just happened @@ -2297,12 +2319,16 @@ lws_h2_parser(struct lws *wsi, unsigned char *in, lws_filepos_t inlen, } } - if (h2n->frame_state == LWS_H2_FRAME_HEADER_LENGTH) - if (lws_h2_parse_frame_header(wsi)) - goto fail; + if (h2n->frame_state == LWS_H2_FRAME_HEADER_LENGTH && + lws_h2_parse_frame_header(wsi)) + goto fail; break; default: + if (h2n->type == LWS_H2_FRAME_TYPE_COUNT) { /* IGNORING FRAME */ + lwsl_debug("%s: consuming for ignored %u %u\n", __func__, (unsigned int)h2n->count, (unsigned int)h2n->length); + h2n->count++; + } break; } } diff --git a/lib/roles/http/client/client-http.c b/lib/roles/http/client/client-http.c index 3f535cc556..c2e0704e3e 100644 --- a/lib/roles/http/client/client-http.c +++ b/lib/roles/http/client/client-http.c @@ -197,7 +197,7 @@ lws_client_socket_service(struct lws *wsi, struct lws_pollfd *pollfd) lws_set_timeout(wsi, NO_PENDING_TIMEOUT, 0); - /* fallthru */ + /* fallthrough */ #endif diff --git a/lib/roles/http/server/fops-zip.c b/lib/roles/http/server/fops-zip.c index d79dacbecd..015563b057 100644 --- a/lib/roles/http/server/fops-zip.c +++ b/lib/roles/http/server/fops-zip.c @@ -144,6 +144,9 @@ enum { LWS_FZ_ERR_SEEK_COMPRESSED, }; +#define eff_size(_priv) (_priv->hdr.method == ZIP_COMPRESSION_METHOD_STORE ? \ + _priv->hdr.uncomp_size : _priv->hdr.comp_size) + static uint16_t get_u16(void *p) { @@ -341,7 +344,7 @@ lws_fops_zip_open(const struct lws_plat_file_ops *fops, const char *vfs_path, priv->zip_fop_fd = fops->LWS_FOP_OPEN(fops, rp, NULL, &local_flags); if (!priv->zip_fop_fd) { - lwsl_err("unable to open zip %s\n", rp); + lwsl_err("%s: unable to open zip %s\n", __func__, rp); goto bail1; } @@ -526,11 +529,8 @@ lws_fops_zip_read(lws_fop_fd_t fd, lws_filepos_t *amount, uint8_t *buf, spin: if (!priv->inflate.avail_in) { rlen = sizeof(priv->rbuf); - if (rlen > priv->hdr.comp_size - - (cur - priv->content_start)) - rlen = priv->hdr.comp_size - - (priv->hdr.comp_size - - priv->content_start); + if (rlen > eff_size(priv) - (cur - priv->content_start)) + rlen = eff_size(priv) - (cur - priv->content_start); if (priv->zip_fop_fd->fops->LWS_FOP_READ( priv->zip_fop_fd, &ramount, priv->rbuf, @@ -632,14 +632,15 @@ lws_fops_zip_read(lws_fop_fd_t fd, lws_filepos_t *amount, uint8_t *buf, lwsl_info("%s: store\n", __func__); - if (len > priv->hdr.uncomp_size - (cur - priv->content_start)) - len = priv->hdr.comp_size - (priv->hdr.comp_size - - priv->content_start); + if (len > eff_size(priv) - cur) + len = eff_size(priv) - cur; if (priv->zip_fop_fd->fops->LWS_FOP_READ(priv->zip_fop_fd, amount, buf, len)) return LWS_FZ_ERR_READ_CONTENT; + fd->pos += *amount; + return 0; } diff --git a/lib/roles/http/server/lws-spa.c b/lib/roles/http/server/lws-spa.c index fdf146dee0..ef85f69f76 100644 --- a/lib/roles/http/server/lws-spa.c +++ b/lib/roles/http/server/lws-spa.c @@ -145,7 +145,7 @@ lws_urldecode_s_create(struct lws_spa *spa, struct lws *wsi, char *out, s->mime_boundary[m++] = *p++; s->mime_boundary[m] = '\0'; - lwsl_notice("boundary '%s'\n", s->mime_boundary); + // lwsl_notice("boundary '%s'\n", s->mime_boundary); } } } @@ -598,7 +598,7 @@ lws_spa_create_via_info(struct lws *wsi, const lws_spa_create_info_t *i) goto bail5; } - lwsl_notice("%s: Created SPA %p\n", __func__, spa); + // lwsl_notice("%s: Created SPA %p\n", __func__, spa); return spa; diff --git a/lib/secure-streams/secure-streams-client.c b/lib/secure-streams/secure-streams-client.c index 68781f9a9b..f724431bf6 100644 --- a/lib/secure-streams/secure-streams-client.c +++ b/lib/secure-streams/secure-streams-client.c @@ -512,12 +512,8 @@ lws_sspc_destroy(lws_sspc_handle_t **ph) if (h->dsh) lws_dsh_destroy(&h->dsh); - if (h->cwsi) { - struct lws *wsi = h->cwsi; + if (h->cwsi) h->cwsi = NULL; - if (wsi) - lws_set_timeout(wsi, 1, LWS_TO_KILL_SYNC); - } /* clean out any pending metadata changes that didn't make it */ diff --git a/lib/secure-streams/secure-streams-serialize.c b/lib/secure-streams/secure-streams-serialize.c index 021945e43e..fd4e4034bd 100644 --- a/lib/secure-streams/secure-streams-serialize.c +++ b/lib/secure-streams/secure-streams-serialize.c @@ -684,10 +684,19 @@ lws_ss_deserialize_parse(struct lws_ss_serialization_parser *par, parser); h->txc.peer_tx_cr_est -= n; - if (client_pss_to_sspc_h(pss, ssi)) + if (client_pss_to_sspc_h(pss, ssi)) { /* we still have an sspc handle */ - ssi->rx(client_pss_to_userdata(pss), + int ret = ssi->rx(client_pss_to_userdata(pss), (uint8_t *)cp, n, flags); + switch (ret) { + case LWSSSSRET_OK: + break; + case LWSSSSRET_DISCONNECT_ME: + goto hangup; + case LWSSSSRET_DESTROY_ME: + return LWSSSSRET_DESTROY_ME; + } + } #if defined(LWS_WITH_DETAILED_LATENCY) if (lws_det_lat_active(context)) { diff --git a/lib/system/async-dns/async-dns.c b/lib/system/async-dns/async-dns.c index 68faeec4ab..6be8782d77 100644 --- a/lib/system/async-dns/async-dns.c +++ b/lib/system/async-dns/async-dns.c @@ -88,8 +88,16 @@ lws_async_dns_complete(lws_adns_q_t *q, lws_adns_cache_t *c) __func__, q, c, c->refcount, c->refcount + 1); c->refcount++; } - w->adns_cb(w, (const char *)&q[1], c ? c->results : NULL, 0, - q->opaque); + lws_set_timeout(w, NO_PENDING_TIMEOUT, 0); + /* + * This may decide to close / delete w + */ + if (w->adns_cb(w, (const char *)&q[1], c ? c->results : NULL, 0, + q->opaque) == NULL) + lwsl_notice("%s: failed\n", __func__); + // lws_close_free_wsi(w, LWS_CLOSE_STATUS_NOSTATUS, + // "adopt udp2 fail"); + } lws_end_foreach_dll_safe(d, d1); if (q->standalone_cb) { @@ -582,7 +590,8 @@ lws_async_dns_query(struct lws_context *context, int tsi, const char *name, m = c->results ? LADNS_RET_FOUND : LADNS_RET_FAILED; if (c->results) c->refcount++; - cb(wsi, name, c->results, m, opaque); + if (cb(wsi, name, c->results, m, opaque) == NULL) + return LADNS_RET_FAILED_WSI_CLOSED; return m; } diff --git a/minimal-examples/http-server/minimal-http-server-eventlib-demos/minimal-http-server-eventlib-demos.c b/minimal-examples/http-server/minimal-http-server-eventlib-demos/minimal-http-server-eventlib-demos.c index f079972beb..dd8e637ce1 100644 --- a/minimal-examples/http-server/minimal-http-server-eventlib-demos/minimal-http-server-eventlib-demos.c +++ b/minimal-examples/http-server/minimal-http-server-eventlib-demos/minimal-http-server-eventlib-demos.c @@ -41,10 +41,30 @@ static struct lws_protocols protocols[] = { * mount handlers for sections of the URL space */ -static const struct lws_http_mount mount_ziptest = { +static const struct lws_http_mount mount_ziptest_uncomm = { NULL, /* linked-list pointer to next*/ + "/uncommziptest", /* mountpoint in URL namespace on this vhost */ + "./mount-origin/candide-uncompressed.zip", /* handler */ + NULL, /* default filename if none given */ + NULL, + NULL, + NULL, + NULL, + 0, + 0, + 0, + 0, + 0, + 0, + LWSMPRO_FILE, /* origin points to a callback */ + 14, /* strlen("/ziptest"), ie length of the mountpoint */ + NULL, + + { NULL, NULL } // sentinel +}, mount_ziptest = { + (struct lws_http_mount *)&mount_ziptest_uncomm, /* linked-list pointer to next*/ "/ziptest", /* mountpoint in URL namespace on this vhost */ - "candide.zip", /* handler */ + "./mount-origin/candide.zip", /* handler */ NULL, /* default filename if none given */ NULL, NULL, @@ -61,9 +81,7 @@ static const struct lws_http_mount mount_ziptest = { NULL, { NULL, NULL } // sentinel -}; - -static const struct lws_http_mount mount_post = { +}, mount_post = { (struct lws_http_mount *)&mount_ziptest, /* linked-list pointer to next*/ "/formtest", /* mountpoint in URL namespace on this vhost */ "protocol-post-demo", /* handler */ @@ -83,10 +101,7 @@ static const struct lws_http_mount mount_post = { NULL, { NULL, NULL } // sentinel -}; - - -static const struct lws_http_mount mount = { +}, mount = { /* .mount_next */ &mount_post, /* linked-list "next" */ /* .mountpoint */ "/", /* mountpoint URL */ /* .origin */ "./mount-origin", /* serve from dir */ diff --git a/minimal-examples/http-server/minimal-http-server-eventlib-demos/mount-origin/candide-uncompressed.zip b/minimal-examples/http-server/minimal-http-server-eventlib-demos/mount-origin/candide-uncompressed.zip new file mode 100644 index 0000000000..55856bce1d Binary files /dev/null and b/minimal-examples/http-server/minimal-http-server-eventlib-demos/mount-origin/candide-uncompressed.zip differ diff --git a/minimal-examples/http-server/minimal-http-server-eventlib-foreign/CMakeLists.txt b/minimal-examples/http-server/minimal-http-server-eventlib-foreign/CMakeLists.txt index 75b5fba4b3..6b5a77045f 100644 --- a/minimal-examples/http-server/minimal-http-server-eventlib-foreign/CMakeLists.txt +++ b/minimal-examples/http-server/minimal-http-server-eventlib-foreign/CMakeLists.txt @@ -72,6 +72,16 @@ if (LWS_WITH_GLIB) set(extralibs ${extralibs} ${GLIB_LIBRARIES}) list(APPEND SRCS glib.c) endif() +if (LWS_WITH_SDEVENT) + find_path(LIBSYSTEMD_INCLUDE_DIRS NAMES systemd/sd-event.h) + find_library(LIBSYSTEMD_LIBRARIES NAMES systemd) + message("libsystemd include dir: ${LIBSYSTEMD_INCLUDE_DIRS}") + message("libsystemd libraries: ${LIBSYSTEMD_LIBRARIES}") + include_directories("${LIBSYSTEMD_INCLUDE_DIRS}") + set(extralibs ${extralibs} ${LIBSYSTEMD_LIBRARIES}) + list(APPEND SRCS libsdevent.c) +endif() + message("Extra libs: ${extralibs}") diff --git a/minimal-examples/http-server/minimal-http-server-eventlib-foreign/README.md b/minimal-examples/http-server/minimal-http-server-eventlib-foreign/README.md index 4c21fa1a91..0a4aa5f896 100644 --- a/minimal-examples/http-server/minimal-http-server-eventlib-foreign/README.md +++ b/minimal-examples/http-server/minimal-http-server-eventlib-foreign/README.md @@ -6,6 +6,7 @@ Commandline option|Meaning --uv|Use the libuv event library (lws must have been configured with `-DLWS_WITH_LIBUV=1`) --event|Use the libevent library (lws must have been configured with `-DLWS_WITH_LIBEVENT=1`) --ev|Use the libev event library (lws must have been configured with `-DLWS_WITH_LIBEV=1`) +--sd|Use the systemd event library (lws must have been configured with `-DLWS_WITH_SDEVENT=1`) Notice libevent and libev cannot coexist in the one library. But all the other combinations are OK. diff --git a/minimal-examples/http-server/minimal-http-server-eventlib-foreign/libsdevent.c b/minimal-examples/http-server/minimal-http-server-eventlib-foreign/libsdevent.c new file mode 100644 index 0000000000..67aeb5f85f --- /dev/null +++ b/minimal-examples/http-server/minimal-http-server-eventlib-foreign/libsdevent.c @@ -0,0 +1,85 @@ +/* + * lws-minimal-http-server-eventlib-foreign + * + * Written in 2020 by Christian Fuchs + * + * This file is made available under the Creative Commons CC0 1.0 + * Universal Public Domain Dedication. + * + * The sdevent specific code + */ + +#include + +#include +#include + +#include + +#include "private.h" + +static struct sd_event *sd_loop; + +static sd_event_source *sd_timer; +static sd_event_source *sd_signal; + +static int +timer_cb_sd(sd_event_source* source, + uint64_t now, + void* user) +{ + foreign_timer_service(sd_loop); + + if (sd_timer) { + sd_event_source_set_time(sd_timer, now + 1000000); + sd_event_source_set_enabled(sd_timer, SD_EVENT_ON); + } +} + +static int +signal_cb_sd(sd_event_source* source, + const struct signalfd_siginfo *si, + void* user) +{ + signal_cb(si->ssi_signo); + return 0; +} + +static void +foreign_event_loop_init_and_run_libsdevent(void) +{ + /* we create and start our "foreign loop" */ + + sd_event_default(&sd_loop); + sd_event_add_signal(sd_loop, &sd_signal, SIGINT, signal_cb_sd, NULL); + uint64_t now; + sd_event_now(sd_loop, CLOCK_MONOTONIC, &now); + sd_event_add_time(sd_loop, &sd_timer, CLOCK_MONOTONIC, now, (uint64_t) 1000, timer_cb_sd, NULL); + + sd_event_loop(sd_loop); +} + +static void +foreign_event_loop_stop_libsdevent(void) +{ + sd_event_exit(sd_loop, 0); +} + +static void +foreign_event_loop_cleanup_libsdevent(void) +{ + sd_event_source_set_enabled(sd_timer, SD_EVENT_OFF); + sd_timer = sd_event_source_unref(sd_timer); + + sd_event_source_set_enabled(sd_signal, SD_EVENT_OFF); + sd_signal = sd_event_source_unref(sd_signal); + + sd_loop = sd_event_unref(sd_loop); +} + +const struct ops ops_sdevent = { + foreign_event_loop_init_and_run_libsdevent, + foreign_event_loop_stop_libsdevent, + foreign_event_loop_cleanup_libsdevent +}; + diff --git a/minimal-examples/http-server/minimal-http-server-eventlib-foreign/minimal-http-server-eventlib-foreign.c b/minimal-examples/http-server/minimal-http-server-eventlib-foreign/minimal-http-server-eventlib-foreign.c index de289fb4af..9942d6abda 100644 --- a/minimal-examples/http-server/minimal-http-server-eventlib-foreign/minimal-http-server-eventlib-foreign.c +++ b/minimal-examples/http-server/minimal-http-server-eventlib-foreign/minimal-http-server-eventlib-foreign.c @@ -196,10 +196,17 @@ int main(int argc, const char **argv) ops = &ops_glib; lwsl_notice("%s: using glib loop\n", __func__); } else +#endif +#if defined(LWS_WITH_SDEVENT) + if (lws_cmdline_option(argc, argv, "--sd")) { + info.options |= LWS_SERVER_OPTION_SDEVENT; + ops = &ops_sdevent; + lwsl_notice("%s: using sd-event loop\n", __func__); + } else #endif { lwsl_err("This app only makes sense when used\n"); - lwsl_err(" with a foreign loop, --uv, --event, --glib, or --ev\n"); + lwsl_err(" with a foreign loop, --uv, --event, --glib, --ev or --sd\n"); return 1; } diff --git a/minimal-examples/http-server/minimal-http-server-eventlib-foreign/private.h b/minimal-examples/http-server/minimal-http-server-eventlib-foreign/private.h index 71dfd2191a..8f41c47219 100644 --- a/minimal-examples/http-server/minimal-http-server-eventlib-foreign/private.h +++ b/minimal-examples/http-server/minimal-http-server-eventlib-foreign/private.h @@ -12,4 +12,4 @@ extern int lifetime, reported; void foreign_timer_service(void *foreign_loop); void signal_cb(int signum); -extern const struct ops ops_libuv, ops_libevent, ops_glib, ops_libev; +extern const struct ops ops_libuv, ops_libevent, ops_glib, ops_libev, ops_sdevent; diff --git a/test-apps/test-server.c b/test-apps/test-server.c index 30b2fda04a..af55f9fd27 100644 --- a/test-apps/test-server.c +++ b/test-apps/test-server.c @@ -255,13 +255,15 @@ static const struct lws_extension exts[] = { #endif /* - * mount handlers for sections of the URL space + * mount a filesystem directory into the URL space at / + * point it to our /usr/share directory with our assets in + * stuff from here is autoserved by the library */ -static const struct lws_http_mount mount_ziptest = { +static const struct lws_http_mount mount_ziptest_uncomm = { NULL, /* linked-list pointer to next*/ - "/ziptest", /* mountpoint in URL namespace on this vhost */ - LOCAL_RESOURCE_PATH"/candide.zip", /* handler */ + "/uncommziptest", /* mountpoint in URL namespace on this vhost */ + LOCAL_RESOURCE_PATH"/candide-uncompressed.zip", /* handler */ NULL, /* default filename if none given */ NULL, NULL, @@ -274,16 +276,14 @@ static const struct lws_http_mount mount_ziptest = { 0, 0, LWSMPRO_FILE, /* origin points to a callback */ - 8, /* strlen("/ziptest"), ie length of the mountpoint */ + 14, /* strlen("/ziptest"), ie length of the mountpoint */ NULL, { NULL, NULL } // sentinel -}; - -static const struct lws_http_mount mount_post = { - (struct lws_http_mount *)&mount_ziptest, /* linked-list pointer to next*/ - "/formtest", /* mountpoint in URL namespace on this vhost */ - "protocol-post-demo", /* handler */ +}, mount_ziptest = { + (struct lws_http_mount *)&mount_ziptest_uncomm, /* linked-list pointer to next*/ + "/ziptest", /* mountpoint in URL namespace on this vhost */ + LOCAL_RESOURCE_PATH"/candide.zip", /* handler */ NULL, /* default filename if none given */ NULL, NULL, @@ -295,24 +295,16 @@ static const struct lws_http_mount mount_post = { 0, 0, 0, - LWSMPRO_CALLBACK, /* origin points to a callback */ - 9, /* strlen("/formtest"), ie length of the mountpoint */ + LWSMPRO_FILE, /* origin points to a callback */ + 8, /* strlen("/ziptest"), ie length of the mountpoint */ NULL, { NULL, NULL } // sentinel -}; - -/* - * mount a filesystem directory into the URL space at / - * point it to our /usr/share directory with our assets in - * stuff from here is autoserved by the library - */ - -static const struct lws_http_mount mount = { - (struct lws_http_mount *)&mount_post, /* linked-list pointer to next*/ - "/", /* mountpoint in URL namespace on this vhost */ - LOCAL_RESOURCE_PATH, /* where to go on the filesystem for that */ - "test.html", /* default filename if none given */ +}, mount_post = { + (struct lws_http_mount *)&mount_ziptest, /* linked-list pointer to next*/ + "/formtest", /* mountpoint in URL namespace on this vhost */ + "protocol-post-demo", /* handler */ + NULL, /* default filename if none given */ NULL, NULL, NULL, @@ -323,13 +315,32 @@ static const struct lws_http_mount mount = { 0, 0, 0, - LWSMPRO_FILE, /* mount type is a directory in a filesystem */ - 1, /* strlen("/"), ie length of the mountpoint */ + LWSMPRO_CALLBACK, /* origin points to a callback */ + 9, /* strlen("/formtest"), ie length of the mountpoint */ NULL, { NULL, NULL } // sentinel +}, mount = { + /* .mount_next */ &mount_post, /* linked-list "next" */ + /* .mountpoint */ "/", /* mountpoint URL */ + /* .origin */ LOCAL_RESOURCE_PATH, /* serve from dir */ + /* .def */ "test.html", /* default filename */ + /* .protocol */ NULL, + /* .cgienv */ NULL, + /* .extra_mimetypes */ NULL, + /* .interpret */ NULL, + /* .cgi_timeout */ 0, + /* .cache_max_age */ 0, + /* .auth_mask */ 0, + /* .cache_reusable */ 0, + /* .cache_revalidate */ 0, + /* .cache_intermediaries */ 0, + /* .origin_protocol */ LWSMPRO_FILE, /* files in a dir */ + /* .mountpoint_len */ 1, /* char count */ + /* .basic_auth_login_file */ NULL, }; + static const struct lws_protocol_vhost_options pvo_options = { NULL, NULL, diff --git a/win32port/win32helpers/gettimeofday.c b/win32port/win32helpers/gettimeofday.c index 08385c2320..be5ac11ea9 100644 --- a/win32port/win32helpers/gettimeofday.c +++ b/win32port/win32helpers/gettimeofday.c @@ -1,11 +1,12 @@ -#include -#include //I've omitted context line - -#include "gettimeofday.h" - -int gettimeofday(struct timeval *tv, struct timezone *tz) -{ - FILETIME ft; +#include +#include + +#include "gettimeofday.h" + +#ifndef LWS_MINGW_SUPPORT +int gettimeofday(struct timeval *tv, struct timezone *tz) +{ + FILETIME ft; unsigned __int64 tmpres = 0; static int tzflag; @@ -19,11 +20,11 @@ int gettimeofday(struct timeval *tv, struct timezone *tz) /*converting file time to unix epoch*/ tmpres /= 10; /*convert into microseconds*/ tmpres -= DELTA_EPOCH_IN_MICROSECS; - tv->tv_sec = (long)(tmpres / 1000000UL); - tv->tv_usec = (long)(tmpres % 1000000UL); - } - - if (NULL != tz) { + tv->tv_sec = (long)(tmpres / 1000000UL); + tv->tv_usec = (long)(tmpres % 1000000UL); + } + + if (NULL != tz) { if (!tzflag) { _tzset(); tzflag++; @@ -31,6 +32,7 @@ int gettimeofday(struct timeval *tv, struct timezone *tz) tz->tz_minuteswest = _timezone / 60; tz->tz_dsttime = _daylight; } - - return 0; -} + + return 0; +} +#endif diff --git a/win32port/win32helpers/gettimeofday.h b/win32port/win32helpers/gettimeofday.h index 33e7a750fe..4531fa80af 100644 --- a/win32port/win32helpers/gettimeofday.h +++ b/win32port/win32helpers/gettimeofday.h @@ -10,11 +10,11 @@ #endif #ifdef LWS_MINGW_SUPPORT - #include + #include #endif -#ifndef _TIMEZONE_DEFINED -struct timezone +#ifndef _TIMEZONE_DEFINED +struct timezone { int tz_minuteswest; /* minutes W of Greenwich */ int tz_dsttime; /* type of dst correction */ @@ -22,6 +22,8 @@ struct timezone #endif +#ifndef LWS_MINGW_SUPPORT int gettimeofday(struct timeval *tv, struct timezone *tz); +#endif #endif