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

event-lib-glib

Adds support for glib event library.
This commit is contained in:
Andy Green 2020-02-07 11:39:32 +00:00
parent 2cb705f71f
commit af2f1f9a87
27 changed files with 1143 additions and 20 deletions

View file

@ -50,6 +50,7 @@ option(LWS_WITH_HTTP_BROTLI "Also offer brotli http stream compression (requires
option(LWS_WITH_ACME "Enable support for ACME automatic cert acquisition + maintenance (letsencrypt etc)" OFF)
option(LWS_WITH_HUBBUB "Enable libhubbub rewriting support" OFF)
option(LWS_WITH_ALSA "Enable alsa audio example" OFF)
option(LWS_WITH_GTK "Enable gtk example" OFF)
option(LWS_WITH_FTS "Full Text Search support" OFF)
option(LWS_WITH_SYS_ASYNC_DNS "Nonblocking internal IPv4 + IPv6 DNS resolver" OFF)
option(LWS_WITH_SYS_NTPCLIENT "Build in tiny ntpclient good for tls date validation and run via lws_system" OFF)
@ -69,6 +70,8 @@ option(LWS_SSL_CLIENT_USE_OS_CA_CERTS "SSL support should make use of the OS-ins
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)
#
# Static / Dynamic build options
#
@ -204,6 +207,7 @@ if(LWS_WITH_DISTRO_RECOMMENDED)
set(LWS_WITH_RANGES 1)
set(LWS_WITH_ACME 1)
set(LWS_WITH_SERVER_STATUS 1)
set(LWS_WITH_GLIB 1)
set(LWS_WITH_LIBUV 1)
set(LWS_WITH_LIBEV 1)
# libev + libevent cannot coexist at build-time
@ -365,7 +369,7 @@ if (LWS_WITH_MBEDTLS)
include_directories(lib/tls/mbedtls/wrapper/include)
endif()
include_directories(include plugins lib/core lib/core-net lib/event-libs include/abstract lib/tls lib/roles lib/event-libs/libuv lib/event-libs/poll lib/event-libs/libevent lib/event-libs/libev lib/jose/jwe lib/jose/jws lib/jose lib/misc lib/roles/http lib/roles/http/compression lib/roles/h1 lib/roles/h2 lib/roles/ws lib/roles/cgi lib/roles/dbus lib/roles/raw-proxy lib/abstract lib/system/async-dns)
include_directories(include plugins lib/core lib/core-net lib/event-libs include/abstract lib/tls lib/roles lib/event-libs/libuv lib/event-libs/poll lib/event-libs/libevent lib/event-libs/glib lib/event-libs/libev lib/jose/jwe lib/jose/jws lib/jose lib/misc lib/roles/http lib/roles/http/compression lib/roles/h1 lib/roles/h2 lib/roles/ws lib/roles/cgi lib/roles/dbus lib/roles/raw-proxy lib/abstract lib/system/async-dns)
if (LWS_PLAT_FREERTOS)
include_directories(lib/plat/freertos lib/plat/freertos/esp32)
@ -544,6 +548,9 @@ set(LWS_SQLITE3_LIBRARIES CACHE PATH "Path to the sqlite3 library")
set(LWS_SQLITE3_INCLUDE_DIRS CACHE PATH "Path to the sqlite3 include directory")
set(LWS_LIBEVENT_INCLUDE_DIRS CACHE PATH "Path to the libevent include directory")
set(LWS_LIBEVENT_LIBRARIES CACHE PATH "Path to the libevent library")
set(LWS_GLIB_INCLUDE_DIRS CACHE PATH "Path to the glib include directory")
set(LWS_GLIB_LIBRARIES CACHE PATH "Path to the glib library")
if (NOT LWS_WITH_SSL)
@ -654,6 +661,15 @@ if (LWS_WITH_LIBEVENT)
endif()
endif()
if (LWS_WITH_GLIB)
if ("${LWS_GLIB_LIBRARIES}" STREQUAL "" OR "${LWS_GLIB_INCLUDE_DIRS}" STREQUAL "")
else()
set(LIBGLIB_LIBRARIES ${LWS_GLIB_LIBRARIES})
set(LIBGLIB_INCLUDE_DIRS ${LWS_GLIB_INCLUDE_DIRS})
set(LIBGLIB_FOUND 1)
endif()
endif()
if (LWS_WITH_SQLITE3)
if ("${LWS_SQLITE3_LIBRARIES}" STREQUAL "" OR "${LWS_SQLITE3_INCLUDE_DIRS}" STREQUAL "")
else()
@ -1454,6 +1470,12 @@ if (LWS_WITH_LIBEVENT AND LWS_WITH_NETWORK)
lib/event-libs/libevent/libevent.c)
endif()
if (LWS_WITH_GLIB AND LWS_WITH_NETWORK)
list(APPEND SOURCES
lib/event-libs/glib/glib.c)
endif()
if (LWS_WITH_LIBEV AND LWS_WITH_NETWORK)
list(APPEND SOURCES
lib/event-libs/libev/libev.c)
@ -1893,6 +1915,30 @@ if (LWS_WITH_LIBEVENT)
list(APPEND LIB_LIST ${LIBEVENT_LIBRARIES})
endif(LWS_WITH_LIBEVENT)
if (LWS_WITH_GLIB)
include (FindPkgConfig)
if (NOT GLIB_FOUND)
find_path(GLIB_INCLUDE_DIRS NAMES glib-2.0/glib.h)
find_library(GLIB_LIBRARIES NAMES glib-2.0)
if(GLIB_INCLUDE_DIRS AND GLIB_LIBRARIES)
set(GLIB_FOUND 1)
endif()
if (GLIB_INCLUDE_DIRS)
set(GLIB_INCLUDE_DIRS "${GLIB_INCLUDE_DIRS}/glib-2.0")
endif()
endif()
PKG_SEARCH_MODULE(LWS_GLIB2 glib-2.0)
if (LWS_GLIB2_FOUND)
list(APPEND GLIB_INCLUDE_DIRS "${LWS_GLIB2_INCLUDE_DIRS}")
endif()
message("glib include dir: ${GLIB_INCLUDE_DIRS}")
message("glib libraries: ${GLIB_LIBRARIES}")
include_directories("${GLIB_INCLUDE_DIRS}")
list(APPEND LIB_LIST ${GLIB_LIBRARIES})
endif(LWS_WITH_GLIB)
if (LWS_WITH_SQLITE3)
if (NOT SQLITE3_FOUND)
find_path(SQLITE3_INCLUDE_DIRS NAMES sqlite3.h)
@ -2462,7 +2508,7 @@ if (LWS_WITH_GENERIC_SESSIONS AND LWS_ROLE_WS AND LWS_WITH_TLS)
target_link_libraries(protocol_lws_messageboard sqlite3 )
endif(WIN32)
endif(LWS_WITH_GENERIC_SESSIONS AND LWS_ROLE_WS)
endif(LWS_WITH_GENERIC_SESSIONS AND LWS_ROLE_WS AND LWS_WITH_TLS)
endif(LWS_WITH_PLUGINS AND LWS_WITH_SHARED)
@ -2790,6 +2836,7 @@ message(" LWS_WITHOUT_DAEMONIZE = ${LWS_WITHOUT_DAEMONIZE}")
message(" LWS_WITH_LIBEV = ${LWS_WITH_LIBEV}")
message(" LWS_WITH_LIBUV = ${LWS_WITH_LIBUV}")
message(" LWS_WITH_LIBEVENT = ${LWS_WITH_LIBEVENT}")
message(" LWS_WITH_GLIB = ${LWS_WITH_GLIB}")
message(" LWS_IPV6 = ${LWS_IPV6}")
message(" LWS_UNIX_SOCK = ${LWS_UNIX_SOCK}")
message(" LWS_WITH_HTTP2 = ${LWS_WITH_HTTP2}")

View file

@ -16,6 +16,20 @@ various scenarios, CC0-licensed (public domain) for cut-and-paste, allow you to
News
----
## libglib native event loop support
glib's event loop joins libuv, libevent and libev support in lws for both the
`lws_context` creating and owning the loop object for its lifetime, and for
an already-existing "foreign loop" where the `lws_context` is created, attaches,
detaches, and is destroyed without affecting the loop.
This allows direct, lock-free integration of lws functionality with, eg, a GTK app's
existing `GMainLoop` / glib `g_main_loop`. Just select `-DLWS_WITH_GLIB=1` at cmake
time to enable. The -eventlib minimal examples also support --glib option to
select using the glib loop at runtime.
There's also a gtk example that is built if lws cmake has `-DLWS_WITH_GTK=1`.
## `lws_system` helper for attaching code to a single event loop from another thread
`lws_system` ops struct now has a member that enables other threads (in the

View file

@ -110,6 +110,8 @@
#cmakedefine LWS_WITH_FTS
#cmakedefine LWS_WITH_GENCRYPTO
#cmakedefine LWS_WITH_GENERIC_SESSIONS
#cmakedefine LWS_WITH_GLIB
#cmakedefine LWS_WITH_GTK
#cmakedefine LWS_WITH_HTTP2
#cmakedefine LWS_WITH_HTTP_BROTLI
#cmakedefine LWS_WITH_HTTP_PROXY

View file

@ -218,6 +218,9 @@
* poll mode.
*/
#define LWS_SERVER_OPTION_GLIB (1ll << 33)
/**< (CTX) Use glib event loop */
/****** add new things just above ---^ ******/

View file

@ -507,7 +507,7 @@ just_kill_connection:
if (!wsi->socket_is_permanently_unusable &&
lws_socket_is_valid(wsi->desc.sockfd) &&
lwsi_state(wsi) != LRS_SHUTDOWN &&
context->event_loop_ops->periodic_events_available) {
(context->event_loop_ops->flags & LELOF_ISPOLL)) {
__lws_change_pollfd(wsi, LWS_POLLOUT, LWS_POLLIN);
lwsi_set_state(wsi, LRS_SHUTDOWN);
__lws_set_timeout(wsi, PENDING_TIMEOUT_SHUTDOWN_FLUSH,

View file

@ -73,7 +73,8 @@ _lws_change_pollfd(struct lws *wsi, int _and, int _or, struct lws_pollargs *pa)
#if !defined(LWS_WITH_LIBUV) && \
!defined(LWS_WITH_LIBEV) && \
!defined(LWS_WITH_LIBEVENT)
!defined(LWS_WITH_LIBEVENT) && \
!defined(LWS_WITH_GLIB)
/*
* This only applies when we use the default poll() event loop.
*

View file

@ -429,6 +429,9 @@ struct lws_context_per_thread {
#if defined(LWS_WITH_LIBEVENT)
struct lws_pt_eventlibs_libevent event;
#endif
#if defined(LWS_WITH_GLIB)
struct lws_pt_eventlibs_glib glib;
#endif
#if defined(LWS_WITH_LIBEV) || defined(LWS_WITH_LIBUV) || \
defined(LWS_WITH_LIBEVENT)
@ -649,7 +652,7 @@ struct lws {
/* lifetime members */
#if defined(LWS_WITH_LIBEV) || defined(LWS_WITH_LIBUV) || \
defined(LWS_WITH_LIBEVENT)
defined(LWS_WITH_LIBEVENT) || defined(LWS_WITH_GLIB)
struct lws_io_watcher w_read;
#endif
#if defined(LWS_WITH_LIBEV) || defined(LWS_WITH_LIBEVENT)

View file

@ -409,6 +409,13 @@ lws_create_context(const struct lws_context_creation_info *info)
goto fail_event_libs;
#endif
if (lws_check_opt(context->options, LWS_SERVER_OPTION_GLIB))
#if defined(LWS_WITH_GLIB)
context->event_loop_ops = &event_loop_ops_glib;
#else
goto fail_event_libs;
#endif
if (!context->event_loop_ops)
goto fail_event_libs;

View file

@ -207,6 +207,9 @@ struct lws_io_watcher {
#endif
#ifdef LWS_WITH_LIBEVENT
struct lws_io_watcher_libevent event;
#endif
#ifdef LWS_WITH_GLIB
struct lws_io_watcher_glib glib;
#endif
struct lws_context *context;
@ -222,6 +225,9 @@ struct lws_signal_watcher {
#endif
#ifdef LWS_WITH_LIBEVENT
struct lws_signal_watcher_libevent event;
#endif
#ifdef LWS_WITH_LIBEVENT
struct lws_signal_watcher_glib glib;
#endif
struct lws_context *context;
};
@ -339,6 +345,9 @@ struct lws_context {
#if defined(LWS_WITH_LIBEVENT)
struct lws_context_eventlibs_libevent event;
#endif
#if defined(LWS_WITH_GLIB)
struct lws_context_eventlibs_glib glib;
#endif
#if defined(LWS_WITH_TLS)
struct lws_context_tls tls;

464
lib/event-libs/glib/glib.c Normal file
View file

@ -0,0 +1,464 @@
/*
* libwebsockets - small server side websockets and web server implementation
*
* Copyright (C) 2010 - 2020 Andy Green <andy@warmcat.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include "private-lib-core.h"
#include <glib-unix.h>
#define wsi_to_subclass(_w) ((_w)->w_read.glib.source)
#define wsi_to_gsource(_w) ((GSource *)wsi_to_subclass(_w))
#define pt_to_loop(_pt) ((_pt)->glib.loop)
#define pt_to_g_main_context(_pt) g_main_loop_get_context(pt_to_loop(_pt))
static gboolean
lws_glib_idle_timer_cb(void *p);
static gboolean
lws_glib_hrtimer_cb(void *p);
static gboolean
lws_glib_check(GSource *src)
{
struct lws_io_watcher_glib_subclass *sub =
(struct lws_io_watcher_glib_subclass *)src;
return !!g_source_query_unix_fd(src, sub->tag);
}
/*
* These helpers attach only to the main_context that belongs to the pt's glib
* mainloop. The simpler g_timeout_add() and g_idle_add() are forbidden
* because they implicitly choose the default main context to attach to
* instead of specifically the loop bound to the pt.
*
* https://developer.gnome.org/programming-guidelines/unstable/main-contexts.html.en#what-is-gmaincontext
*/
static int
lws_glib_set_idle(struct lws_context_per_thread *pt)
{
GSource *gis;
if (pt->glib.idle_tag)
return 0;
gis = g_idle_source_new();
if (!gis)
return 1;
g_source_set_callback(gis, lws_glib_idle_timer_cb, pt, NULL);
pt->glib.idle_tag = g_source_attach(gis, pt_to_g_main_context(pt));
return 0;
}
static int
lws_glib_set_timeout(struct lws_context_per_thread *pt, unsigned int ms)
{
GSource *gts;
gts = g_timeout_source_new(ms);
if (!gts)
return 1;
g_source_set_callback(gts, lws_glib_hrtimer_cb, pt, NULL);
pt->glib.hrtimer_tag = g_source_attach(gts, pt_to_g_main_context(pt));
return 0;
}
static gboolean
lws_glib_dispatch(GSource *src, GSourceFunc x, gpointer userData)
{
struct lws_io_watcher_glib_subclass *sub =
(struct lws_io_watcher_glib_subclass *)src;
struct lws_context_per_thread *pt;
struct lws_pollfd eventfd;
GIOCondition cond;
cond = g_source_query_unix_fd(src, sub->tag);
eventfd.revents = cond;
/* translate from glib event namespace to platform */
if (cond & G_IO_IN)
eventfd.revents |= LWS_POLLIN;
if (cond & G_IO_OUT)
eventfd.revents |= LWS_POLLOUT;
if (cond & G_IO_ERR)
eventfd.revents |= LWS_POLLHUP;
if (cond & G_IO_HUP)
eventfd.revents |= LWS_POLLHUP;
eventfd.events = eventfd.revents;
eventfd.fd = sub->wsi->desc.sockfd;
lwsl_debug("%s: wsi %p: fd %d, events %d\n", __func__, sub->wsi,
eventfd.fd, eventfd.revents);
pt = &sub->wsi->context->pt[(int)sub->wsi->tsi];
if (pt->is_destroyed)
return G_SOURCE_CONTINUE;
lws_service_fd_tsi(sub->wsi->context, &eventfd, sub->wsi->tsi);
if (!pt->glib.idle_tag)
lws_glib_set_idle(pt);
if (pt->destroy_self)
lws_context_destroy(pt->context);
return G_SOURCE_CONTINUE;
}
static const GSourceFuncs lws_glib_source_ops = {
.prepare = NULL,
.check = lws_glib_check,
.dispatch = lws_glib_dispatch,
.finalize = NULL,
};
/*
* This is the callback for a timer object that is set to the earliest scheduled
* lws event... it services any lws scheduled events that are ready, and then
* resets the event loop timer to the earliest remaining event, if any.
*/
static gboolean
lws_glib_hrtimer_cb(void *p)
{
struct lws_context_per_thread *pt = (struct lws_context_per_thread *)p;
unsigned int ms;
lws_usec_t us;
lws_pt_lock(pt, __func__);
us = __lws_sul_service_ripe(&pt->pt_sul_owner, lws_now_usecs());
if (us) {
ms = us / LWS_US_PER_MS;
if (!ms)
ms = 1;
lws_glib_set_timeout(pt, ms);
}
lws_pt_unlock(pt);
lws_glib_set_idle(pt);
return FALSE; /* stop it repeating */
}
static gboolean
lws_glib_idle_timer_cb(void *p)
{
struct lws_context_per_thread *pt = (struct lws_context_per_thread *)p;
if (pt->is_destroyed)
return FALSE;
lws_service_do_ripe_rxflow(pt);
lws_glib_hrtimer_cb(pt);
/*
* 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);
/* still somebody left who wants forced service? */
if (!lws_service_adjust_timeout(pt->context, 1, pt->tid))
return TRUE;
}
if (pt->destroy_self)
lws_context_destroy(pt->context);
/*
* For glib, this disables the idle callback. Otherwise we keep
* coming back here immediately endlessly.
*
* We reenable the idle callback on the next network or scheduled event
*/
pt->glib.idle_tag = 0;
return FALSE;
}
void
lws_glib_sigint_cb(void *ctx)
{
struct lws_context_per_thread *pt = ctx;
pt->inside_service = 1;
if (pt->context->eventlib_signal_cb) {
pt->context->eventlib_signal_cb(NULL, 0);
return;
}
if (!pt->event_loop_foreign)
g_main_loop_quit(pt_to_loop(pt));
}
static int
elops_init_context_glib(struct lws_context *context,
const struct lws_context_creation_info *info)
{
int n;
context->eventlib_signal_cb = info->signal_cb;
for (n = 0; n < context->count_threads; n++)
context->pt[n].w_sigint.context = context;
return 0;
}
static int
elops_accept_glib(struct lws *wsi)
{
struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi];
int fd;
assert(!wsi_to_subclass(wsi));
wsi_to_subclass(wsi) = (struct lws_io_watcher_glib_subclass *)
g_source_new((GSourceFuncs *)&lws_glib_source_ops,
sizeof(*wsi_to_subclass(wsi)));
if (!wsi_to_subclass(wsi))
return 1;
wsi->w_read.context = wsi->context;
wsi_to_subclass(wsi)->wsi = wsi;
if (wsi->role_ops->file_handle)
fd = wsi->desc.filefd;
else
fd = wsi->desc.sockfd;
wsi_to_subclass(wsi)->tag = g_source_add_unix_fd(wsi_to_gsource(wsi),
fd, (GIOCondition)LWS_POLLIN);
wsi->w_read.actual_events = LWS_POLLIN;
g_source_set_callback(wsi_to_gsource(wsi),
G_SOURCE_FUNC(lws_service_fd), wsi->context, NULL);
g_source_attach(wsi_to_gsource(wsi), pt_to_g_main_context(pt));
return 0;
}
static int
elops_init_pt_glib(struct lws_context *context, void *_loop, int tsi)
{
struct lws_context_per_thread *pt = &context->pt[tsi];
struct lws_vhost *vh = context->vhost_list;
GMainLoop *loop = (GMainLoop *)_loop;
if (!loop)
loop = g_main_loop_new(NULL, 0);
else
context->pt[tsi].event_loop_foreign = 1;
if (!loop) {
lwsl_err("%s: creating glib loop failed\n", __func__);
return -1;
}
pt->glib.loop = loop;
/*
* Initialize all events with the listening sockets
* and register a callback for read operations
*/
while (vh) {
if (vh->lserv_wsi)
elops_accept_glib(vh->lserv_wsi);
vh = vh->vhost_next;
}
lws_glib_set_idle(pt);
/* Register the signal watcher unless it's a foreign loop */
if (pt->event_loop_foreign)
return 0;
pt->glib.sigint_tag = g_unix_signal_add(SIGINT,
G_SOURCE_FUNC(lws_glib_sigint_cb), pt);
return 0;
}
/*
* We are changing the event wait for this guy
*/
static void
elops_io_glib(struct lws *wsi, int flags)
{
struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi];
GIOCondition cond = wsi->w_read.actual_events | G_IO_ERR;
if (!pt_to_loop(pt) || wsi->context->being_destroyed || pt->is_destroyed)
return;
/*
* We are being given individual set / clear operations using
* LWS_EV_ common namespace, convert them to glib namespace bitfield
*/
if (flags & LWS_EV_READ) {
if (flags & LWS_EV_STOP)
cond &= ~(G_IO_IN | G_IO_HUP);
else
cond |= G_IO_IN | G_IO_HUP;
}
if (flags & LWS_EV_WRITE) {
if (flags & LWS_EV_STOP)
cond &= ~G_IO_OUT;
else
cond |= G_IO_OUT;
}
wsi->w_read.actual_events = cond;
lwsl_debug("%s: wsi %p, fd %d, 0x%x/0x%x\n", __func__, wsi,
wsi->desc.sockfd, flags, (int)cond);
g_source_modify_unix_fd(wsi_to_gsource(wsi), wsi_to_subclass(wsi)->tag,
cond);
}
static void
elops_run_pt_glib(struct lws_context *context, int tsi)
{
struct lws_context_per_thread *pt = &context->pt[tsi];
if (pt_to_loop(pt))
g_main_loop_run(pt_to_loop(pt));
}
static void
elops_destroy_wsi_glib(struct lws *wsi)
{
struct lws_context_per_thread *pt;
if (!wsi)
return;
pt = &wsi->context->pt[(int)wsi->tsi];
if (pt->is_destroyed)
return;
if (!wsi_to_gsource(wsi))
return;
if (wsi_to_subclass(wsi)->tag) {
g_source_remove_unix_fd(wsi_to_gsource(wsi),
wsi_to_subclass(wsi)->tag);
wsi_to_subclass(wsi)->tag = NULL;
}
g_source_destroy(wsi_to_gsource(wsi));
wsi_to_subclass(wsi) = NULL;
}
static void
elops_destroy_pt_glib(struct lws_context *context, int tsi)
{
struct lws_context_per_thread *pt = &context->pt[tsi];
struct lws_vhost *vh = context->vhost_list;
if (!pt_to_loop(pt))
return;
/*
* Free all events with the listening sockets
*/
while (vh) {
if (vh->lserv_wsi)
elops_destroy_wsi_glib(vh->lserv_wsi);
vh = vh->vhost_next;
}
if (pt->glib.hrtimer_tag)
g_source_remove(pt->glib.hrtimer_tag);
if (!pt->event_loop_foreign) {
g_main_loop_quit(pt_to_loop(pt));
g_source_remove(pt->glib.sigint_tag);
g_main_loop_unref(pt_to_loop(pt));
}
pt_to_loop(pt) = NULL;
}
static int
elops_destroy_context2_glib(struct lws_context *context)
{
struct lws_context_per_thread *pt = &context->pt[0];
int n;
for (n = 0; n < (int)context->count_threads; n++) {
if (!pt->event_loop_foreign)
g_main_loop_quit(pt_to_loop(pt));
pt++;
}
return 0;
}
static int
elops_wsi_logical_close_glib(struct lws *wsi)
{
elops_destroy_wsi_glib(wsi);
return 0;
}
struct lws_event_loop_ops event_loop_ops_glib = {
/* name */ "glib",
/* init_context */ elops_init_context_glib,
/* destroy_context1 */ NULL,
/* destroy_context2 */ elops_destroy_context2_glib,
/* init_vhost_listen_wsi */ elops_accept_glib,
/* init_pt */ elops_init_pt_glib,
/* wsi_logical_close */ elops_wsi_logical_close_glib,
/* check_client_connect_ok */ NULL,
/* close_handle_manually */ NULL,
/* accept */ elops_accept_glib,
/* io */ elops_io_glib,
/* run_pt */ elops_run_pt_glib,
/* destroy_pt */ elops_destroy_pt_glib,
/* destroy wsi */ elops_destroy_wsi_glib,
/* flags */ LELOF_DESTROY_FINAL,
};

View file

@ -0,0 +1,54 @@
/*
* libwebsockets - small server side websockets and web server implementation
*
* Copyright (C) 2010 - 2020 Andy Green <andy@warmcat.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#if defined(LWS_WITH_GLIB)
#include <glib-2.0/glib.h>
#endif /* LWS_WITH_GLIB */
struct lws_pt_eventlibs_glib {
GMainLoop *loop;
guint hrtimer_tag;
guint sigint_tag;
guint idle_tag;
};
struct lws_io_watcher_glib_subclass {
GSource base;
struct lws *wsi;
gpointer tag;
};
/*
* One of these is embedded in each wsi
*/
struct lws_io_watcher_glib {
struct lws_io_watcher_glib_subclass *source; /* these are created and destroyed by glib */
};
struct lws_context_eventlibs_glib {
//int placeholder;
};
extern struct lws_event_loop_ops event_loop_ops_glib;

View file

@ -382,5 +382,5 @@ struct lws_event_loop_ops event_loop_ops_ev = {
/* destroy_pt */ elops_destroy_pt_ev,
/* destroy wsi */ elops_destroy_wsi_ev,
/* periodic_events_available */ 0,
/* flags */ 0,
};

View file

@ -453,5 +453,5 @@ struct lws_event_loop_ops event_loop_ops_event = {
/* destroy_pt */ elops_destroy_pt_event,
/* destroy wsi */ elops_destroy_wsi_event,
/* periodic_events_available */ 0,
/* flags */ 0,
};

View file

@ -976,5 +976,5 @@ struct lws_event_loop_ops event_loop_ops_uv = {
/* destroy_pt */ elops_destroy_pt_uv,
/* destroy wsi */ NULL,
/* periodic_events_available */ 0,
/* flags */ 0,
};

View file

@ -42,5 +42,5 @@ struct lws_event_loop_ops event_loop_ops_poll = {
/* destroy_pt */ NULL,
/* destroy wsi */ NULL,
/* periodic_events_available */ 1,
/* flags */ LELOF_ISPOLL,
};

View file

@ -24,6 +24,11 @@
* This is included from private-lib-core.h
*/
enum lws_event_lib_ops_flags {
LELOF_ISPOLL = (1 >> 0),
LELOF_DESTROY_FINAL = (1 >> 1),
};
struct lws_event_loop_ops {
const char *name;
/* event loop-specific context init during context creation */
@ -54,7 +59,7 @@ struct lws_event_loop_ops {
/* called just before wsi is freed */
void (*destroy_wsi)(struct lws *wsi);
unsigned int periodic_events_available:1;
uint8_t flags;
};
/* bring in event libs private declarations */
@ -71,6 +76,10 @@ struct lws_event_loop_ops {
#include "private-lib-event-libs-libevent.h"
#endif
#if defined(LWS_WITH_GLIB)
#include "private-lib-event-libs-glib.h"
#endif
#if defined(LWS_WITH_LIBEV)
#include "private-lib-event-libs-libev.h"
#endif

View file

@ -2341,8 +2341,8 @@ lws_http_transaction_completed(struct lws *wsi)
* until we can verify POLLOUT. The part of this that confirms POLLOUT
* with no partials is in lws_server_socket_service() below.
*/
lwsl_debug("%s: %p: setting DEF_ACT from 0x%x\n", __func__,
wsi, (int)wsi->wsistate);
lwsl_debug("%s: %p: setting DEF_ACT from 0x%x: %p\n", __func__,
wsi, (int)wsi->wsistate, wsi->buflist);
lwsi_set_state(wsi, LRS_DEFERRING_ACTION);
wsi->http.tx_content_length = 0;
wsi->http.tx_content_remain = 0;

View file

@ -0,0 +1,102 @@
project(lws-minimal-gtk)
cmake_minimum_required(VERSION 2.8)
include(CheckCSourceCompiles)
set(SAMP lws-minimal-gtk)
set(SRCS main.c)
# If we are being built as part of lws, confirm current build config supports
# reqconfig, else skip building ourselves.
#
# If we are being built externally, confirm installed lws was configured to
# support reqconfig, else error out with a helpful message about the problem.
#
MACRO(require_lws_config reqconfig _val result)
if (DEFINED ${reqconfig})
if (${reqconfig})
set (rq 1)
else()
set (rq 0)
endif()
else()
set(rq 0)
endif()
if (${_val} EQUAL ${rq})
set(SAME 1)
else()
set(SAME 0)
endif()
if (LWS_WITH_MINIMAL_EXAMPLES AND NOT ${SAME})
if (${_val})
message("${SAMP}: skipping as lws being built without ${reqconfig}")
else()
message("${SAMP}: skipping as lws built with ${reqconfig}")
endif()
set(${result} 0)
else()
if (LWS_WITH_MINIMAL_EXAMPLES)
set(MET ${SAME})
else()
CHECK_C_SOURCE_COMPILES("#include <libwebsockets.h>\nint main(void) {\n#if defined(${reqconfig})\n return 0;\n#else\n fail;\n#endif\n return 0;\n}\n" HAS_${reqconfig})
if (NOT DEFINED HAS_${reqconfig} OR NOT HAS_${reqconfig})
set(HAS_${reqconfig} 0)
else()
set(HAS_${reqconfig} 1)
endif()
if ((HAS_${reqconfig} AND ${_val}) OR (NOT HAS_${reqconfig} AND NOT ${_val}))
set(MET 1)
else()
set(MET 0)
endif()
endif()
if (NOT MET)
if (${_val})
message(FATAL_ERROR "This project requires lws must have been configured with ${reqconfig}")
else()
message(FATAL_ERROR "Lws configuration of ${reqconfig} is incompatible with this project")
endif()
endif()
endif()
ENDMACRO()
set(requirements 1)
require_lws_config(LWS_ROLE_H1 1 requirements)
require_lws_config(LWS_WITH_SERVER 1 requirements)
require_lws_config(LWS_WITH_GLIB 1 requirements)
require_lws_config(LWS_WITH_GTK 1 requirements)
if (requirements)
# gtk pieces
include (FindPkgConfig)
set(LWS_GTK_INCLUDE_DIRS CACHE PATH "Path to the gtk include directory")
set(LWS_GTK_LIBRARIES CACHE PATH "Path to the gtk library")
PKG_SEARCH_MODULE(LWS_GTK2 gtk+-3.0)
if (LWS_GTK2_FOUND)
list(APPEND LWS_GTK_INCLUDE_DIRS "${LWS_GTK2_INCLUDE_DIRS}")
list(APPEND LWS_GTK_LIBRARIES "${LWS_GTK2_LIBRARIES}")
endif()
message("gtk include dir: ${LWS_GTK_INCLUDE_DIRS}")
message("gtk libraries: ${LWS_GTK_LIBRARIES}")
include_directories("${LWS_GTK_INCLUDE_DIRS}")
set(extralibs ${extralibs} ${LWS_GTK_LIBRARIES})
message("Extra libs: ${extralibs}")
add_executable(${SAMP} ${SRCS})
if (websockets_shared)
target_link_libraries(${SAMP} websockets_shared ${extralibs})
add_dependencies(${SAMP} websockets_shared)
else()
target_link_libraries(${SAMP} websockets ${extralibs})
endif()
endif()

View file

@ -0,0 +1,32 @@
# lws minimal http client gtk
The application goes to https://warmcat.com and receives the page data,
from inside a gtk app using gtk / glib main loop directly.
## build
```
$ cmake . && make
```
## usage
```
$
t1_main: started
[2020/02/08 18:04:07:6647] N: Loading client CA for verification ./warmcat.com.cer
[2020/02/08 18:04:07:7744] U: Connected to 46.105.127.147, http response: 200
[2020/02/08 18:04:07:7762] U: RECEIVE_CLIENT_HTTP_READ: read 4087
[2020/02/08 18:04:07:7762] U: RECEIVE_CLIENT_HTTP_READ: read 4096
[2020/02/08 18:04:07:7928] U: RECEIVE_CLIENT_HTTP_READ: read 4087
[2020/02/08 18:04:07:7929] U: RECEIVE_CLIENT_HTTP_READ: read 4096
[2020/02/08 18:04:07:7956] U: RECEIVE_CLIENT_HTTP_READ: read 4087
[2020/02/08 18:04:07:7956] U: RECEIVE_CLIENT_HTTP_READ: read 4096
[2020/02/08 18:04:07:7956] U: RECEIVE_CLIENT_HTTP_READ: read 1971
[2020/02/08 18:04:07:7956] U: LWS_CALLBACK_COMPLETED_CLIENT_HTTP
Hello World
$
```

View file

@ -0,0 +1,210 @@
#include <gtk/gtk.h>
#include <libwebsockets.h>
static int status = 0;
static void
print_hello(GtkWidget *widget, gpointer data)
{
g_print("Hello World\n");
}
static void
activate(GtkApplication *app, gpointer user_data)
{
GtkWidget *window;
GtkWidget *button, *bbox;
window = gtk_application_window_new(app);
gtk_window_set_title(GTK_WINDOW(window), "mywindow");
gtk_window_set_default_size(GTK_WINDOW(window), 200, 200);
bbox = gtk_button_box_new(GTK_ORIENTATION_HORIZONTAL);
gtk_container_add(GTK_CONTAINER(window), bbox);
button = gtk_button_new_with_label("Hello World");
g_signal_connect(button, "clicked", G_CALLBACK(print_hello), NULL);
g_signal_connect_swapped(button, "clicked",
G_CALLBACK(gtk_widget_destroy), window);
gtk_container_add(GTK_CONTAINER(bbox), button);
gtk_widget_show_all(window);
}
static int
system_notify_cb(lws_state_manager_t *mgr, lws_state_notify_link_t *link,
int current, int target)
{
struct lws_context *context = mgr->parent;
struct lws_client_connect_info i;
if (current != LWS_SYSTATE_OPERATIONAL ||
target != LWS_SYSTATE_OPERATIONAL)
return 0;
lwsl_notice("%s: operational\n", __func__);
memset(&i, 0, sizeof i); /* otherwise uninitialized garbage */
i.context = context;
i.ssl_connection = LCCSCF_USE_SSL | LCCSCF_H2_QUIRK_OVERFLOWS_TXCR |
LCCSCF_H2_QUIRK_NGHTTP2_END_STREAM;
i.port = 443;
i.address = "warmcat.com";
i.path = "/";
i.host = i.address;
i.origin = i.address;
i.method = "GET";
i.protocol = "http";
return !lws_client_connect_via_info(&i);
}
static int
callback_http(struct lws *wsi, enum lws_callback_reasons reason,
void *user, void *in, size_t len)
{
switch (reason) {
/* because we are protocols[0] ... */
case LWS_CALLBACK_CLIENT_CONNECTION_ERROR:
lwsl_err("CLIENT_CONNECTION_ERROR: %s\n",
in ? (char *)in : "(null)");
break;
case LWS_CALLBACK_ESTABLISHED_CLIENT_HTTP:
{
char buf[128];
lws_get_peer_simple(wsi, buf, sizeof(buf));
status = lws_http_client_http_response(wsi);
lwsl_user("Connected to %s, http response: %d\n",
buf, status);
}
break;
/* chunks of chunked content, with header removed */
case LWS_CALLBACK_RECEIVE_CLIENT_HTTP_READ:
lwsl_user("RECEIVE_CLIENT_HTTP_READ: read %d\n", (int)len);
return 0; /* don't passthru */
/* uninterpreted http content */
case LWS_CALLBACK_RECEIVE_CLIENT_HTTP:
{
char buffer[1024 + LWS_PRE];
char *px = buffer + LWS_PRE;
int lenx = sizeof(buffer) - LWS_PRE;
if (lws_http_client_read(wsi, &px, &lenx) < 0)
return -1;
}
return 0; /* don't passthru */
case LWS_CALLBACK_COMPLETED_CLIENT_HTTP:
lwsl_user("LWS_CALLBACK_COMPLETED_CLIENT_HTTP\n");
lws_cancel_service(lws_get_context(wsi)); /* abort poll wait */
break;
case LWS_CALLBACK_CLOSED_CLIENT_HTTP:
lws_cancel_service(lws_get_context(wsi)); /* abort poll wait */
break;
default:
break;
}
return lws_callback_http_dummy(wsi, reason, user, in, len);
}
static const struct lws_protocols protocols[] = {
{
"http",
callback_http,
0,
0,
},
{ NULL, NULL, 0, 0 }
};
static gpointer
t1_main (gpointer user_data)
{
lws_state_notify_link_t notifier = { {}, system_notify_cb, "app" };
lws_state_notify_link_t *na[] = { &notifier, NULL };
GMainContext *t1_mc = (GMainContext *)user_data;
struct lws_context_creation_info info;
struct lws_context *context;
void *foreign_loops[1];
GMainLoop *ml;
g_print("%s: started\n", __func__);
g_main_context_push_thread_default(t1_mc);
ml = g_main_loop_new(t1_mc, FALSE);
/* attach our lws activities to the main loop of this thread */
lws_set_log_level(LLL_USER | LLL_ERR | LLL_WARN | LLL_NOTICE, NULL);
memset(&info, 0, sizeof info);
info.port = CONTEXT_PORT_NO_LISTEN;
info.options = LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT |
LWS_SERVER_OPTION_GLIB;
info.protocols = protocols;
foreign_loops[0] = (void *)ml;
info.foreign_loops = foreign_loops;
info.register_notifier_list = na;
#if defined(LWS_WITH_MBEDTLS)
/*
* OpenSSL uses the system trust store. mbedTLS has to be told which
* CA to trust explicitly.
*/
info.client_ssl_ca_filepath = "./warmcat.com.cer";
#endif
context = lws_create_context(&info);
if (!context) {
lwsl_err("lws init failed\n");
return NULL;
}
/*
* We created the lws_context and bound it to this thread's main loop,
* let's run the thread's main loop now...
*/
g_main_loop_run(ml);
g_main_loop_unref(ml);
g_main_context_pop_thread_default(t1_mc);
g_main_context_unref(t1_mc);
g_print("%s: ending\n", __func__);
lws_context_destroy(context);
return NULL;
}
int
main(int argc, char **argv)
{
GMainContext *t1_mc = g_main_context_new();
GtkApplication *app;
GThread *t1;
int status;
t1 = g_thread_new ("t1", t1_main, g_main_context_ref (t1_mc));
(void)t1;
app = gtk_application_new("org.gtk.example", G_APPLICATION_FLAGS_NONE);
g_signal_connect(app, "activate", G_CALLBACK(activate), NULL);
status = g_application_run(G_APPLICATION(app), argc, argv);
g_object_unref(app);
return status;
}

View file

@ -0,0 +1,58 @@
-----BEGIN CERTIFICATE-----
MIIFUDCCBDigAwIBAgISA4mJfIm3iCGbU9+o8YQa+4nUMA0GCSqGSIb3DQEBCwUA
MEoxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MSMwIQYDVQQD
ExpMZXQncyBFbmNyeXB0IEF1dGhvcml0eSBYMzAeFw0xOTA5MDcwNzA5MjNaFw0x
OTEyMDYwNzA5MjNaMBYxFDASBgNVBAMTC3dhcm1jYXQuY29tMIIBIjANBgkqhkiG
9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwnEoH9JW3GvpadpxHGZPb5wv1Q6KfAIMWtdq
YCOfotFxaYULuzHVxmrTTgmEqJr+eBqUBkXKmGuRR/9UipOmTu5j02qFyWHotFdF
ZGyp//8z+Rle9Qt1nL68oNIZLDtWkybh5x00b1uo4eyEszXUaa0aLqKP3lH7Q4jI
aSVARZ8snrJR640Gp3ByudvNTYkGz469bpWzRC/8wSNtzzY02DvHs1GxQx9tMXw+
BbtUxeP7lpYFKEFBjgZaIKLv+4g8ItJIuO7gMSzG2JfpQHxdhrlhxpx7dsaMUcyM
nnYXysNL5JG3KEMhkxbtdpCaEQ8jLSPbl/rnF/+mgce+lSjMuQIDAQABo4ICYjCC
Al4wDgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcD
AjAMBgNVHRMBAf8EAjAAMB0GA1UdDgQWBBSI9ai12zLFeNTEDHKI9Ghkqcpa2TAf
BgNVHSMEGDAWgBSoSmpjBH3duubRObemRWXv86jsoTBvBggrBgEFBQcBAQRjMGEw
LgYIKwYBBQUHMAGGImh0dHA6Ly9vY3NwLmludC14My5sZXRzZW5jcnlwdC5vcmcw
LwYIKwYBBQUHMAKGI2h0dHA6Ly9jZXJ0LmludC14My5sZXRzZW5jcnlwdC5vcmcv
MBYGA1UdEQQPMA2CC3dhcm1jYXQuY29tMEwGA1UdIARFMEMwCAYGZ4EMAQIBMDcG
CysGAQQBgt8TAQEBMCgwJgYIKwYBBQUHAgEWGmh0dHA6Ly9jcHMubGV0c2VuY3J5
cHQub3JnMIIBBgYKKwYBBAHWeQIEAgSB9wSB9ADyAHcAY/Lbzeg7zCzPC3KEJ1dr
M6SNYXePvXWmOLHHaFRL2I0AAAFtCsVHHAAABAMASDBGAiEAy0q1cR4VwPL3iviL
cBWN67kjJRXk+DwhodmeoM3kb3gCIQC2soAHFs0Umo+0RNdFrL41+hMuidh2cXbb
Ovc6nh5tOQB3AOJpS64m6OlACeiGG7Y7g9Q+5/50iPukjyiTAZ3d8dv+AAABbQrF
R48AAAQDAEgwRgIhANqKQm4t9by263CJ7/DLOaZCjtcK29KgJjPwhv08UMn1AiEA
h35nGTASR8/E7xz+56ZUleqD7U1ABFgWZRZskIzsFO8wDQYJKoZIhvcNAQELBQAD
ggEBADDJBVbKe2LPHmi8k2vxErB3Y0Ty+3gwgPEXKYtEvQ7tos89eE+QmOXAzH5J
GwRarFf7kzmKeJv04tMebiEtshpap47oJfxCxfrtpja8hP8Cdu/v/Ae6eEzu3yet
0N08GJdxQKfgCFaoGUptbaF2RCIZS12SVcX4TPpdP+xaiZdmIx4dGM6tReQ8+y8B
10b4Hi2+d/zW0W1z6+FAemU6yleWriJDUik5oas9XZF5LAAMDb/WgF5eIB6P9CUG
LuAO8lWlk9nBgXvMLTxZ74SJb17H4kFEIrIjvABNshz5gBW8xw9nfr5YIfANtwEj
BDsq06Df3UORYVs/j3T97gPAEZ4=
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIEkjCCA3qgAwIBAgIQCgFBQgAAAVOFc2oLheynCDANBgkqhkiG9w0BAQsFADA/
MSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT
DkRTVCBSb290IENBIFgzMB4XDTE2MDMxNzE2NDA0NloXDTIxMDMxNzE2NDA0Nlow
SjELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUxldCdzIEVuY3J5cHQxIzAhBgNVBAMT
GkxldCdzIEVuY3J5cHQgQXV0aG9yaXR5IFgzMIIBIjANBgkqhkiG9w0BAQEFAAOC
AQ8AMIIBCgKCAQEAnNMM8FrlLke3cl03g7NoYzDq1zUmGSXhvb418XCSL7e4S0EF
q6meNQhY7LEqxGiHC6PjdeTm86dicbp5gWAf15Gan/PQeGdxyGkOlZHP/uaZ6WA8
SMx+yk13EiSdRxta67nsHjcAHJyse6cF6s5K671B5TaYucv9bTyWaN8jKkKQDIZ0
Z8h/pZq4UmEUEz9l6YKHy9v6Dlb2honzhT+Xhq+w3Brvaw2VFn3EK6BlspkENnWA
a6xK8xuQSXgvopZPKiAlKQTGdMDQMc2PMTiVFrqoM7hD8bEfwzB/onkxEz0tNvjj
/PIzark5McWvxI0NHWQWM6r6hCm21AvA2H3DkwIDAQABo4IBfTCCAXkwEgYDVR0T
AQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAYYwfwYIKwYBBQUHAQEEczBxMDIG
CCsGAQUFBzABhiZodHRwOi8vaXNyZy50cnVzdGlkLm9jc3AuaWRlbnRydXN0LmNv
bTA7BggrBgEFBQcwAoYvaHR0cDovL2FwcHMuaWRlbnRydXN0LmNvbS9yb290cy9k
c3Ryb290Y2F4My5wN2MwHwYDVR0jBBgwFoAUxKexpHsscfrb4UuQdf/EFWCFiRAw
VAYDVR0gBE0wSzAIBgZngQwBAgEwPwYLKwYBBAGC3xMBAQEwMDAuBggrBgEFBQcC
ARYiaHR0cDovL2Nwcy5yb290LXgxLmxldHNlbmNyeXB0Lm9yZzA8BgNVHR8ENTAz
MDGgL6AthitodHRwOi8vY3JsLmlkZW50cnVzdC5jb20vRFNUUk9PVENBWDNDUkwu
Y3JsMB0GA1UdDgQWBBSoSmpjBH3duubRObemRWXv86jsoTANBgkqhkiG9w0BAQsF
AAOCAQEA3TPXEfNjWDjdGBX7CVW+dla5cEilaUcne8IkCJLxWh9KEik3JHRRHGJo
uM2VcGfl96S8TihRzZvoroed6ti6WqEBmtzw3Wodatg+VyOeph4EYpr/1wXKtx8/
wApIvJSwtmVi4MFU5aMqrSDE6ea73Mj2tcMyo5jMd6jmeWUHK8so/joWUoHOUgwu
X4Po1QYz+3dszkDqMp4fklxBwXRsW10KXzPMTZ+sOPAveyxindmjkW8lGy+QsRlG
PfZ+G6Z6h7mjem0Y+iWlkYcV4PIWL1iwBi8saCbGS5jN2p8M+X+Q7UNKEkROb3N6
KOqkqm57TH2H3eDJAkSnh6/DNFu0Qg==
-----END CERTIFICATE-----

View file

@ -342,7 +342,10 @@ int main(int argc, const char **argv)
if (lws_cmdline_option(argc, argv, "--ev"))
info.options |= LWS_SERVER_OPTION_LIBEV;
else
signal(SIGINT, sigint_handler);
if (lws_cmdline_option(argc, argv, "--glib"))
info.options |= LWS_SERVER_OPTION_GLIB;
else
signal(SIGINT, sigint_handler);
staggered = !!lws_cmdline_option(argc, argv, "-s");
if ((p = lws_cmdline_option(argc, argv, "-d")))

View file

@ -170,7 +170,10 @@ int main(int argc, const char **argv)
if (lws_cmdline_option(argc, argv, "--ev"))
info.options |= LWS_SERVER_OPTION_LIBEV;
else
signal(SIGINT, sigint_handler);
if (lws_cmdline_option(argc, argv, "--glib"))
info.options |= LWS_SERVER_OPTION_GLIB;
else
signal(SIGINT, sigint_handler);
context = lws_create_context(&info);
if (!context) {

View file

@ -5,6 +5,7 @@ include(CheckCSourceCompiles)
set(SAMP lws-minimal-http-server-eventlib-foreign)
set(SRCS minimal-http-server-eventlib-foreign.c)
# If we are being built as part of lws, confirm current build config supports
# reqconfig, else skip building ourselves.
#
@ -66,9 +67,13 @@ set(requirements 1)
require_lws_config(LWS_ROLE_H1 1 requirements)
require_lws_config(LWS_WITH_SERVER 1 requirements)
CHECK_C_SOURCE_COMPILES("#include <libwebsockets.h>\nint main(void) {\n#if defined(LWS_WITH_LIBUV)\n return 0;\n#else\n fail;\n#endif\n return 0;\n}\n" LWS_WITH_LIBUV)
CHECK_C_SOURCE_COMPILES("#include <libwebsockets.h>\nint main(void) {\n#if defined(LWS_WITH_LIBEVENT)\n return 0;\n#else\n fail;\n#endif\n return 0;\n}\n" LWS_WITH_LIBEVENT)
CHECK_C_SOURCE_COMPILES("#include <libwebsockets.h>\nint main(void) {\n#if defined(LWS_WITH_LIBEV)\n return 0;\n#else\n fail;\n#endif\n return 0;\n}\n" LWS_WITH_LIBEV)
CHECK_C_SOURCE_COMPILES("#include <libwebsockets.h>\nint main(void) {\n#if defined(LWS_WITH_GLIB)\n return 0;\n#else\n fail;\n#endif\n return 0;\n}\n" LWS_WITH_GLIB)
if (LWS_WITH_LIBUV)
set(extralibs ${extralibs} uv)
@ -79,10 +84,33 @@ endif()
if (LWS_WITH_LIBEV)
set(extralibs ${extralibs} ev)
endif()
if (LWS_WITH_GLIB)
set(LWS_GLIB_INCLUDE_DIRS CACHE PATH "Path to the glib include directory")
set(LWS_GLIB_LIBRARIES CACHE PATH "Path to the glib library")
include (FindPkgConfig)
if (NOT GLIB_FOUND)
find_path(GLIB_INCLUDE_DIRS NAMES glib-2.0/glib.h)
find_library(GLIB_LIBRARIES NAMES glib-2.0)
if(GLIB_INCLUDE_DIRS AND GLIB_LIBRARIES)
set(GLIB_FOUND 1)
endif()
if (GLIB_INCLUDE_DIRS)
set(GLIB_INCLUDE_DIRS "${GLIB_INCLUDE_DIRS}/glib-2.0")
endif()
endif()
PKG_SEARCH_MODULE(LWS_GLIB2 glib-2.0)
if (LWS_GLIB2_FOUND)
list(APPEND GLIB_INCLUDE_DIRS "${LWS_GLIB2_INCLUDE_DIRS}")
endif()
message("glib include dir: ${GLIB_INCLUDE_DIRS}")
message("glib libraries: ${GLIB_LIBRARIES}")
include_directories("${GLIB_INCLUDE_DIRS}")
set(extralibs ${extralibs} ${GLIB_LIBRARIES})
endif()
message("Extra libs: ${extralibs}")
if (NOT LWS_WITH_LIBUV AND NOT LWS_WITH_LIBEVENT AND NOT LWS_WITH_LIBEV)
if (NOT LWS_WITH_LIBUV AND NOT LWS_WITH_LIBEVENT AND NOT LWS_WITH_LIBEV AND NOT LWS_WITH_GLIB)
set(requirements 0)
endif()

View file

@ -1,7 +1,7 @@
/*
* lws-minimal-http-server-eventlib-foreign
*
* Written in 2010-2019 by Andy Green <andy@warmcat.com>
* Written in 2010-2020 by Andy Green <andy@warmcat.com>
*
* This file is made available under the Creative Commons CC0 1.0
* Universal Public Domain Dedication.
@ -205,6 +205,59 @@ foreign_event_loop_cleanup_libevent(void)
#endif
#if defined(LWS_WITH_GLIB)
#include <glib-2.0/glib.h>
#include <glib-unix.h>
static GMainLoop *loop_glib;
static guint timer_outer_glib;
static guint sighandler_glib;
static int
timer_cb_glib(void *p)
{
foreign_timer_service(loop_glib);
return 1;
}
static void
signal_cb_glib(void *p)
{
signal_cb(SIGINT);
}
static void
foreign_event_loop_init_and_run_glib(void)
{
/* we create and start our "foreign loop" */
loop_glib = g_main_loop_new(NULL, 0);
sighandler_glib = g_unix_signal_add(SIGINT,
G_SOURCE_FUNC(signal_cb_glib), NULL);
timer_outer_glib = g_timeout_add(1000, timer_cb_glib, NULL);
g_main_loop_run(loop_glib);
}
static void
foreign_event_loop_stop_glib(void)
{
g_main_loop_quit(loop_glib);
}
static void
foreign_event_loop_cleanup_glib(void)
{
/* cleanup the foreign loop assets */
g_source_remove(sighandler_glib);
g_main_loop_unref(loop_glib);
}
#endif
#if defined(LWS_WITH_LIBEV)
static struct ev_loop *loop_ev;
@ -315,6 +368,10 @@ foreign_timer_service(void *foreign_loop)
#if defined(LWS_WITH_LIBEV)
if (info.options & LWS_SERVER_OPTION_LIBEV)
foreign_event_loop_stop_libev();
#endif
#if defined(LWS_WITH_GLIB)
if (info.options & LWS_SERVER_OPTION_GLIB)
foreign_event_loop_stop_glib();
#endif
break;
default:
@ -368,9 +425,12 @@ int main(int argc, const char **argv)
else
if (lws_cmdline_option(argc, argv, "--ev"))
info.options |= LWS_SERVER_OPTION_LIBEV;
else {
else
if (lws_cmdline_option(argc, argv, "--glib"))
info.options |= LWS_SERVER_OPTION_GLIB;
else {
lwsl_err("This app only makes sense when used\n");
lwsl_err(" with a foreign loop, --uv, --event, or --ev\n");
lwsl_err(" with a foreign loop, --uv, --event, --glib, or --ev\n");
return 1;
}
@ -401,6 +461,10 @@ int main(int argc, const char **argv)
if (info.options & LWS_SERVER_OPTION_LIBEV)
foreign_event_loop_init_and_run_libev();
#endif
#if defined(LWS_WITH_GLIB)
if (info.options & LWS_SERVER_OPTION_GLIB)
foreign_event_loop_init_and_run_glib();
#endif
lws_context_destroy(context);
@ -418,6 +482,10 @@ int main(int argc, const char **argv)
if (info.options & LWS_SERVER_OPTION_LIBEV)
foreign_event_loop_cleanup_libev();
#endif
#if defined(LWS_WITH_LIBEV)
if (info.options & LWS_SERVER_OPTION_GLIB)
foreign_event_loop_cleanup_glib();
#endif
lwsl_user("%s: exiting...\n", __func__);

View file

@ -130,7 +130,10 @@ int main(int argc, const char **argv)
if (lws_cmdline_option(argc, argv, "--ev"))
info.options |= LWS_SERVER_OPTION_LIBEV;
else
signal(SIGINT, sigint_handler);
if (lws_cmdline_option(argc, argv, "--glib"))
info.options |= LWS_SERVER_OPTION_GLIB;
else
signal(SIGINT, sigint_handler);
context = lws_create_context(&info);
if (!context) {

View file

@ -101,7 +101,10 @@ int main(int argc, const char **argv)
if (lws_cmdline_option(argc, argv, "--ev"))
info.options |= LWS_SERVER_OPTION_LIBEV;
else
signal(SIGINT, sigint_handler);
if (lws_cmdline_option(argc, argv, "--glib"))
info.options |= LWS_SERVER_OPTION_GLIB;
else
signal(SIGINT, sigint_handler);
context = lws_create_context(&info);
if (!context) {