diff --git a/CMakeLists.txt b/CMakeLists.txt
index 31824282f9fb6d33ec539cf73921e07c30aaf548..ba7dac78355c144c9eff205d1cdc6391392af52a 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -23,6 +23,7 @@ option(LWS_WITH_DISTRO_RECOMMENDED "Enable features recommended for distro packa
 #
 option(LWS_ROLE_H1 "Compile with support for http/1 (needed for ws)" ON)
 option(LWS_ROLE_WS "Compile with support for websockets" ON)
+option(LWS_ROLE_DBUS "Compile with support for DBUS" OFF)
 option(LWS_WITH_HTTP2 "Compile with server support for HTTP/2" OFF)
 option(LWS_WITH_LWSWS "Libwebsockets Webserver" OFF)
 option(LWS_WITH_CGI "Include CGI (spawn process with network-connected stdin/out/err) APIs" OFF)
@@ -129,6 +130,7 @@ if(LWS_WITH_DISTRO_RECOMMENDED)
 	# libev + libevent cannot coexist at build-time
 	set(LWS_WITH_LIBEVENT 0)
 	set(LWS_WITHOUT_EXTENSIONS 0)
+	set(LWS_ROLE_DBUS 1)
 endif()
 
 if(NOT DEFINED CMAKE_BUILD_TYPE)
@@ -681,7 +683,44 @@ CHECK_INCLUDE_FILE(sys/capability.h LWS_HAVE_SYS_CAPABILITY_H)
 CHECK_INCLUDE_FILE(malloc.h LWS_HAVE_MALLOC_H)
 CHECK_INCLUDE_FILE(pthread.h LWS_HAVE_PTHREAD_H)
 
-CHECK_LIBRARY_EXISTS(cap cap_set_flag "" LWS_HAVE_LIBCAP) 
+CHECK_LIBRARY_EXISTS(cap cap_set_flag "" LWS_HAVE_LIBCAP)
+
+if (LWS_ROLE_DBUS)
+	if (NOT LWS_HAVE_LIBDBUS)
+		message(FATAL_ERROR "Install dbus-devel, or libdbus-1-dev etc")
+	endif()
+
+	if (NOT LWS_DBUS_LIB)
+		set(LWS_DBUS_LIB "dbus-1")
+	endif()
+
+	CHECK_LIBRARY_EXISTS(${LWS_DBUS_LIB} dbus_connection_set_watch_functions "" LWS_HAVE_LIBDBUS)
+
+	if (NOT LWS_DBUS_INCLUDE1)
+		# look in fedora and debian / ubuntu place
+		if (EXISTS "/usr/include/dbus-1.0")
+			set(LWS_DBUS_INCLUDE1 "/usr/include/dbus-1.0")
+		else()
+			message(FATAL_ERROR "Set LWS_DBUS_INCLUDE1 to /usr/include/dbus-1.0 or wherever the main dbus includes are")
+		endif()
+	endif()
+
+	if (NOT LWS_DBUS_INCLUDE2)
+		# look in fedora... debian / ubuntu has the ARCH in the path...
+		if (EXISTS "/usr/lib64/dbus-1.0/include")
+			set(LWS_DBUS_INCLUDE2 "/usr/lib64/dbus-1.0/include")
+		else()
+			message(FATAL_ERROR "Set LWS_DBUS_INCLUDE2 to /usr/lib/ARCH-linux-gnu/dbus-1.0/include or wherever dbus-arch-deps.h is on your system")
+		endif()
+	endif()
+
+	set(CMAKE_REQUIRED_INCLUDES ${CMAKE_REQUIRED_INCLUDES};${LWS_DBUS_INCLUDE1};${LWS_DBUS_INCLUDE2})
+
+	CHECK_C_SOURCE_COMPILES("#include <dbus/dbus.h>
+	int main(void) {
+		return 0;
+	}" LWS_DBUS_CHECK_OK)
+endif()
 
 if (LWS_WITH_LIBUV)
 CHECK_INCLUDE_FILE(uv-version.h LWS_HAVE_UV_VERSION_H)
@@ -811,6 +850,11 @@ if (LWS_ROLE_CGI)
 		lib/roles/cgi/ops-cgi.c)
 endif()
 
+if (LWS_ROLE_DBUS)
+	list(APPEND SOURCES
+		lib/roles/dbus/dbus.c)
+endif()
+
 if (LWS_WITH_ACCESS_LOG)
 	list(APPEND SOURCES
 		lib/roles/http/server/access-log.c)
@@ -1416,6 +1460,13 @@ if (LWS_WITH_HUBBUB)
 	list(APPEND LIB_LIST ${LIBHUBBUB_LIBRARIES} )
 endif()
 
+if (LWS_ROLE_DBUS)
+	message("dbus include dir 1: ${LWS_DBUS_INCLUDE1}")
+	message("dbus include dir 2: ${LWS_DBUS_INCLUDE2}")
+	include_directories("${LWS_DBUS_INCLUDE1}")
+	include_directories("${LWS_DBUS_INCLUDE2}")
+	list(APPEND LIB_LIST ${LWS_DBUS_LIB})
+endif()
 
 #
 # Platform specific libs.
diff --git a/cmake/lws_config.h.in b/cmake/lws_config.h.in
index a8e62901f2282da09aa342343b3294bb7bfba637..6c6d1e3ba4dbd5ab426abccbfc092e2af03a3a53 100644
--- a/cmake/lws_config.h.in
+++ b/cmake/lws_config.h.in
@@ -13,6 +13,7 @@
 #cmakedefine LWS_ROLE_RAW
 #cmakedefine LWS_ROLE_H2
 #cmakedefine LWS_ROLE_CGI
+#cmakedefine LWS_ROLE_DBUS
 
 /* Define to 1 to use wolfSSL/CyaSSL as a replacement for OpenSSL.
  * LWS_OPENSSL_SUPPORT needs to be set also for this to work. */
diff --git a/include/libwebsockets/lws-dbus.h b/include/libwebsockets/lws-dbus.h
new file mode 100644
index 0000000000000000000000000000000000000000..63cfd15f18d29e185f748c4d7da450ee0e52bc68
--- /dev/null
+++ b/include/libwebsockets/lws-dbus.h
@@ -0,0 +1,90 @@
+/*
+ * libwebsockets - small server side websockets and web server implementation
+ *
+ * Copyright (C) 2010-2018 Andy Green <andy@warmcat.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License as published by the Free Software Foundation:
+ *  version 2.1 of the License.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ *  MA  02110-1301  USA
+ *
+ * must be included manually as
+ *
+ *  #include <libwebsockets/lws-dbus.h>
+ *
+ * if dbus apis needed
+ */
+
+#if !defined(__LWS_DBUS_H__)
+#define __LWS_DBUS_H__
+
+#include <dbus/dbus.h>
+
+/* helper type to simplify implementing methods as individual functions */
+typedef DBusHandlerResult (*lws_dbus_message_handler)(DBusConnection *conn,
+			   DBusMessage *message, DBusMessage **reply, void *d);
+
+struct lws_dbus_ctx;
+typedef void (*lws_dbus_closing_t)(struct lws_dbus_ctx *ctx);
+
+struct lws_dbus_ctx {
+	struct lws_dll next; /* dbusserver ctx: HEAD of accepted list */
+	struct lws_vhost *vh; /* the vhost we logically bind to in lws */
+	int tsi;	/* the lws thread service index (0 if only one service
+			   thread as is the default */
+	DBusConnection *conn;
+	DBusServer *dbs;
+	DBusWatch *w[4];
+ 	DBusPendingCall *pc;
+
+ 	char hup;
+ 	char timeouts;
+
+ 	/* cb_closing callback will be called after the connection and this
+ 	 * related ctx struct have effectively gone out of scope.
+ 	 *
+ 	 * The callback should close and clean up the connection and free the
+ 	 * ctx.
+ 	 */
+ 	lws_dbus_closing_t cb_closing;
+};
+
+/**
+ * lws_dbus_connection_setup() - bind dbus connection object to lws event loop
+ *
+ * \param ctx: additional information about the connection
+ * \param conn: the DBusConnection object to bind
+ *
+ * This configures a DBusConnection object to use lws for watchers and timeout
+ * operations.
+ */
+LWS_VISIBLE LWS_EXTERN int
+lws_dbus_connection_setup(struct lws_dbus_ctx *ctx, DBusConnection *conn,
+			  lws_dbus_closing_t cb_closing);
+
+/**
+ * lws_dbus_server_listen() - bind dbus connection object to lws event loop
+ *
+ * \param ctx: additional information about the connection
+ * \param ads: the DBUS address to listen on, eg, "unix:abstract=mysocket"
+ * \param err: a DBusError object to take any extra error information
+ * \param new_conn: a callback function to prepare new accepted connections
+ *
+ * This creates a DBusServer and binds it to the lws event loop, and your
+ * callback to accept new connections.
+ */
+LWS_VISIBLE LWS_EXTERN DBusServer *
+lws_dbus_server_listen(struct lws_dbus_ctx *ctx, const char *ads,
+		       DBusError *err, DBusNewConnectionFunction new_conn);
+
+#endif
diff --git a/lib/core/context.c b/lib/core/context.c
index 70d33d47e181a2937c81c1daa86265c709c25a19..cdd1b87e29075bd33f41d132be4072df8ec0e6a9 100644
--- a/lib/core/context.c
+++ b/lib/core/context.c
@@ -34,6 +34,9 @@ const struct lws_role_ops *available_roles[] = {
 #endif
 #if defined(LWS_ROLE_WS)
 	&role_ops_ws,
+#endif
+#if defined(LWS_ROLE_DBUS)
+	&role_ops_dbus,
 #endif
 	NULL
 };
diff --git a/lib/core/libwebsockets.c b/lib/core/libwebsockets.c
index f6dfc375bbab2af1d14c2e7747efec447419727e..2d62259b9678d7763444a7bc7df569d4981e945e 100644
--- a/lib/core/libwebsockets.c
+++ b/lib/core/libwebsockets.c
@@ -962,7 +962,8 @@ __lws_close_free_wsi_final(struct lws *wsi)
 {
 	int n;
 
-	if (lws_socket_is_valid(wsi->desc.sockfd) && !lws_ssl_close(wsi)) {
+	if (!wsi->shadow &&
+	    lws_socket_is_valid(wsi->desc.sockfd) && !lws_ssl_close(wsi)) {
 		lwsl_debug("%s: wsi %p: fd %d\n", __func__, wsi, wsi->desc.sockfd);
 		n = compatible_close(wsi->desc.sockfd);
 		if (n)
diff --git a/lib/core/private.h b/lib/core/private.h
index 9fe93eac3f7b7754333ad3ffbad59777e09aa193..c623c24da24939bbfd717c07cfb6543668624cb8 100644
--- a/lib/core/private.h
+++ b/lib/core/private.h
@@ -386,6 +386,9 @@ struct lws_context_per_thread {
 #if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
 	struct lws_pt_role_http http;
 #endif
+#if defined(LWS_ROLE_DBUS)
+	struct lws_pt_role_dbus dbus;
+#endif
 
 	/* --- event library based members --- */
 
@@ -849,6 +852,9 @@ struct lws {
 #if defined(LWS_ROLE_WS)
 	struct _lws_websocket_related *ws; /* allocated if we upgrade to ws */
 #endif
+#if defined(LWS_ROLE_DBUS)
+	struct _lws_dbus_mode_related dbus;
+#endif
 
 	const struct lws_role_ops *role_ops;
 	lws_wsi_state_t	wsistate;
@@ -962,6 +968,7 @@ struct lws {
 
 	unsigned int could_have_pending:1; /* detect back-to-back writes */
 	unsigned int outer_will_close:1;
+	unsigned int shadow:1; /* we do not control fd lifecycle at all */
 
 #ifdef LWS_WITH_ACCESS_LOG
 	unsigned int access_log_pending:1;
diff --git a/lib/roles/dbus/README.md b/lib/roles/dbus/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..7d479da438942e2f579d950345d78b2c65d68c41
--- /dev/null
+++ b/lib/roles/dbus/README.md
@@ -0,0 +1,83 @@
+# DBUS Role Support
+
+## DBUS-related distro packages
+
+Fedora: dbus-devel
+Debian / Ubuntu: libdbus-1-dev
+
+## Enabling for build at cmake
+
+Fedora example:
+```
+$ cmake .. -DLWS_ROLE_DBUS=1 -DLWS_DBUS_INCLUDE2="/usr/lib64/dbus-1.0/include"
+```
+
+Ubuntu example:
+```
+$ cmake .. -DLWS_ROLE_DBUS=1 -DLWS_DBUS_INCLUDE2="/usr/lib/x86_64-linux-gnu/dbus-1.0/include"
+```
+
+Dbus requires two include paths, which you can force by setting `LWS_DBUS_INCLUDE1`
+and `LWS_DBUS_INCLUDE2`.  Although INCLUDE1 is usually guessable, both can be
+forced to allow cross-build.
+
+If these are not forced, then lws cmake will try to check some popular places,
+for `LWS_DBUS_INCLUDE1`, on both Fedora and Debian / Ubuntu, this is
+`/usr/include/dbus-1.0`... if the directory exists, it is used.
+
+For `LWS_DBUS_INCLUDE2`, it is the arch-specific dbus header which may be
+packaged separately than the main dbus headers.  On Fedora, this is in
+`/usr/lib[64]/dbus-1.0/include`... if not given externally, lws cmake will
+try `/usr/lib64/dbus-1.0/include`.  On Debian / Ubuntu, the package installs
+it in an arch-specific dir like `/usr/lib/x86_64-linux-gnu/dbus-1.0/include`,
+you should force the path.
+
+The library path is usually \[lib\] "dbus-1", but this can also be forced if
+you want to build cross or use a special build, via `LWS_DBUS_LIB`.
+
+## Building against local dbus build
+
+If you built your own local dbus and installed it in /usr/local, then
+this is the incantation to direct lws to use the local version of dbus:
+
+```
+cmake .. -DLWS_ROLE_DBUS=1 -DLWS_DBUS_INCLUDE1="/usr/local/include/dbus-1.0" -DLWS_DBUS_INCLUDE2="/usr/local/lib/dbus-1.0/include" -DLWS_DBUS_LIB="/usr/local/lib/libdbus-1.so"
+```
+
+You'll also need to give the loader a helping hand to do what you want if
+there's a perfectly good dbus lib already in `/usr/lib[64]` using `LD_PRELOAD`
+like this
+
+```
+LD_PRELOAD=/usr/local/lib/libdbus-1.so.3.24.0 myapp
+```
+
+## Lws dbus api exports
+
+Because of the irregular situation with libdbus includes, if lws exports the
+dbus helpers, which use dbus types, as usual from `#include <libwebsockets.h>`
+then if lws was compiled with dbus role support it forces all users to take
+care about the dbus include path mess whether they use dbus themselves or not.
+
+For that reason, if you need access to the lws dbus apis, you must explicitly
+include them by
+
+```
+#include <libwebsockets/lws-dbus.h>
+```
+
+This includes `<dbus/dbus.h>` and so requires the include paths set up.  But
+otherwise non-dbus users that don't include `libwebsockets/lws-dbus.h` don't
+have to care about it.
+
+## DBUS and valgrind
+
+https://cgit.freedesktop.org/dbus/dbus/tree/README.valgrind
+
+1) One-time 6KiB "Still reachable" caused by abstract unix domain socket + libc
+`getgrouplist()` via nss... bug since 2004(!)
+
+https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=273051
+
+
+
diff --git a/lib/roles/dbus/dbus.c b/lib/roles/dbus/dbus.c
new file mode 100644
index 0000000000000000000000000000000000000000..d509cfd3473f766310cc8ccb5a0dc59878474de6
--- /dev/null
+++ b/lib/roles/dbus/dbus.c
@@ -0,0 +1,527 @@
+/*
+ * libwebsockets - dbus role
+ *
+ * Copyright (C) 2010-2018 Andy Green <andy@warmcat.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License as published by the Free Software Foundation:
+ *  version 2.1 of the License.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ *  MA  02110-1301  USA
+ *
+ *
+ * This role for wrapping dbus fds in a wsi + role is unusual in that the
+ * wsi it creates and binds to the role do not have control over the related fd
+ * lifecycle.  In fact dbus doesn't inform us directly about the lifecycle of
+ * the fds it wants to be managed by the lws event loop.
+ *
+ * What it does tell us is when it wants to wait on POLLOUT and / or POLLIN,
+ * and since it should stop any watchers before close, we take the approach to
+ * create a lightweight "shadow" wsi for any fd from dbus that has a POLLIN or
+ * POLLOUT wait active.  When the dbus fd asks to have no wait active, we
+ * destroy the wsi, since this is indistinguishable from dbus close path
+ * behaviour.  If it actually stays alive and later asks to wait again, well no
+ * worries we create a new shadow wsi until it looks like it is closing again.
+ */
+
+#include <core/private.h>
+
+#include <libwebsockets/lws-dbus.h>
+
+/*
+ * retreives existing or creates new shadow wsi for fd owned by dbus stuff.
+ *
+ * Requires vhost lock
+ */
+
+static struct lws *
+__lws_shadow_wsi(struct lws_dbus_ctx *ctx, DBusWatch *w, int fd, int create_ok)
+{
+	struct lws *wsi;
+
+	if (fd < 0 || fd >= (int)ctx->vh->context->fd_limit_per_thread) {
+		lwsl_err("%s: fd %d vs fds_count %d\n", __func__, fd,
+				(int)ctx->vh->context->fd_limit_per_thread);
+		assert(0);
+
+		return NULL;
+	}
+
+	wsi = wsi_from_fd(ctx->vh->context, fd);
+	if (wsi) {
+		assert(wsi->opaque_parent_data == ctx);
+
+		return wsi;
+	}
+
+	if (!create_ok)
+		return NULL;
+
+	wsi = lws_zalloc(sizeof(*wsi), "shadow wsi");
+	if (wsi == NULL) {
+		lwsl_err("Out of mem\n");
+		return NULL;
+	}
+
+	lwsl_info("%s: creating shadow wsi\n", __func__);
+
+	wsi->context = ctx->vh->context;
+	wsi->desc.sockfd = fd;
+	lws_role_transition(wsi, 0, LRS_ESTABLISHED, &role_ops_dbus);
+	wsi->protocol = ctx->vh->protocols;
+	wsi->tsi = ctx->tsi;
+	wsi->shadow = 1;
+	wsi->opaque_parent_data = ctx;
+	ctx->w[0] = w;
+
+	lws_vhost_bind_wsi(ctx->vh, wsi);
+	if (__insert_wsi_socket_into_fds(ctx->vh->context, wsi)) {
+		lwsl_err("inserting wsi socket into fds failed\n");
+		lws_vhost_unbind_wsi(wsi);
+		lws_free(wsi);
+		return NULL;
+	}
+
+	ctx->vh->context->count_wsi_allocated++;
+
+	return wsi;
+}
+
+/*
+ * Requires vhost lock
+ */
+
+static int
+__lws_shadow_wsi_destroy(struct lws_dbus_ctx *ctx, struct lws *wsi)
+{
+	lwsl_info("%s: destroying shadow wsi\n", __func__);
+
+	if (__remove_wsi_socket_from_fds(wsi)) {
+		lwsl_err("%s: unable to remove %d from fds\n", __func__,
+				wsi->desc.sockfd);
+
+		return 1;
+	}
+
+	ctx->vh->context->count_wsi_allocated--;
+	lws_vhost_unbind_wsi(wsi);
+
+	lws_free(wsi);
+
+	return 0;
+}
+
+
+static void
+handle_dispatch_status(DBusConnection *c, DBusDispatchStatus s, void *data)
+{
+	lwsl_info("%s: new dbus dispatch status: %d\n", __func__, s);
+}
+
+/*
+ * These are complicated by the fact libdbus can have two separate DBusWatch
+ * objects for the same fd, to control watching POLLIN and POLLOUT individually.
+ *
+ * However we will actually watch using poll(), where the unit is the fd, and
+ * it has a unified events field with just POLLIN / POLLOUT flags.
+ *
+ * So we have to be prepared for one or two watchers coming in any order.
+ */
+
+static dbus_bool_t
+lws_dbus_add_watch(DBusWatch *w, void *data)
+{
+	struct lws_dbus_ctx *ctx = (struct lws_dbus_ctx *)data;
+	struct lws_context_per_thread *pt = &ctx->vh->context->pt[ctx->tsi];
+	unsigned int flags = 0, lws_flags = 0;
+	struct lws *wsi;
+	int n;
+
+	lws_pt_lock(pt, __func__);
+
+	wsi = __lws_shadow_wsi(ctx, w, dbus_watch_get_unix_fd(w), 1);
+	if (!wsi) {
+		lws_pt_unlock(pt);
+		lwsl_err("%s: unable to get wsi\n", __func__);
+
+		return FALSE;
+	}
+
+	for (n = 0; n < (int)LWS_ARRAY_SIZE(ctx->w); n++)
+		if (w == ctx->w[n])
+			break;
+
+	if (n == (int)LWS_ARRAY_SIZE(ctx->w))
+		for (n = 0; n < (int)LWS_ARRAY_SIZE(ctx->w); n++)
+			if (!ctx->w[n]) {
+				ctx->w[n] = w;
+				break;
+			}
+
+	for (n = 0; n < (int)LWS_ARRAY_SIZE(ctx->w); n++)
+		if (ctx->w[n])
+			flags |= dbus_watch_get_flags(ctx->w[n]);
+
+	if (flags & DBUS_WATCH_READABLE)
+		lws_flags |= LWS_POLLIN;
+	if (flags & DBUS_WATCH_WRITABLE)
+		lws_flags |= LWS_POLLOUT;
+
+	lwsl_info("%s: w %p, fd %d, data %p, flags %d\n", __func__, w,
+		  dbus_watch_get_unix_fd(w), data, lws_flags);
+
+	__lws_change_pollfd(wsi, 0, lws_flags);
+
+	lws_pt_unlock(pt);
+
+	return TRUE;
+}
+
+static int
+check_destroy_shadow_wsi(struct lws_dbus_ctx *ctx, struct lws *wsi)
+{
+	int n;
+
+	if (!wsi)
+		return 0;
+
+	for (n = 0; n < (int)LWS_ARRAY_SIZE(ctx->w); n++)
+		if (ctx->w[n])
+			return 0;
+
+	__lws_shadow_wsi_destroy(ctx, wsi);
+
+	if (!ctx->conn || !ctx->hup || ctx->timeouts)
+		return 0;
+
+	if (dbus_connection_get_dispatch_status(ctx->conn) ==
+						     DBUS_DISPATCH_DATA_REMAINS)
+		return 0;
+
+	if (ctx->cb_closing)
+		ctx->cb_closing(ctx);
+
+	return 1;
+}
+
+static void
+lws_dbus_remove_watch(DBusWatch *w, void *data)
+{
+	struct lws_dbus_ctx *ctx = (struct lws_dbus_ctx *)data;
+	struct lws_context_per_thread *pt = &ctx->vh->context->pt[ctx->tsi];
+	unsigned int flags = 0, lws_flags = 0;
+	struct lws *wsi;
+	int n;
+
+	lws_pt_lock(pt, __func__);
+
+	wsi = __lws_shadow_wsi(ctx, w, dbus_watch_get_unix_fd(w), 0);
+	if (!wsi)
+		goto bail;
+
+	for (n = 0; n < (int)LWS_ARRAY_SIZE(ctx->w); n++)
+		if (w == ctx->w[n]) {
+			ctx->w[n] = NULL;
+			break;
+		}
+
+	for (n = 0; n < (int)LWS_ARRAY_SIZE(ctx->w); n++)
+		if (ctx->w[n])
+			flags |= dbus_watch_get_flags(ctx->w[n]);
+
+	if ((~flags) & DBUS_WATCH_READABLE)
+		lws_flags |= LWS_POLLIN;
+	if ((~flags) & DBUS_WATCH_WRITABLE)
+		lws_flags |= LWS_POLLOUT;
+
+	lwsl_info("%s: w %p, fd %d, data %p, clearing lws flags %d\n",
+		  __func__, w, dbus_watch_get_unix_fd(w), data, lws_flags);
+
+	__lws_change_pollfd(wsi, lws_flags, 0);
+
+bail:
+	lws_pt_unlock(pt);
+}
+
+static void
+lws_dbus_toggle_watch(DBusWatch *w, void *data)
+{
+	if (dbus_watch_get_enabled(w))
+		lws_dbus_add_watch(w, data);
+	else
+		lws_dbus_remove_watch(w, data);
+}
+
+
+static dbus_bool_t
+lws_dbus_add_timeout(DBusTimeout *t, void *data)
+{
+	struct lws_dbus_ctx *ctx = (struct lws_dbus_ctx *)data;
+	struct lws_context_per_thread *pt = &ctx->vh->context->pt[ctx->tsi];
+	int ms = dbus_timeout_get_interval(t);
+	struct lws_role_dbus_timer *dbt;
+	time_t ti = time(NULL);
+
+	if (!dbus_timeout_get_enabled(t))
+		return TRUE;
+
+	if (ms < 1000)
+		ms = 1000;
+
+	dbt = lws_malloc(sizeof(*dbt), "dbus timer");
+	if (!dbt)
+		return FALSE;
+
+	lwsl_info("%s: adding timeout %dms\n", __func__,
+			dbus_timeout_get_interval(t));
+
+	dbt->data = t;
+	dbt->fire = ti + (ms < 1000);
+	dbt->timer_list.prev = NULL;
+	dbt->timer_list.next = NULL;
+	lws_dll_add_front(&dbt->timer_list, &pt->dbus.timer_list_head);
+
+	ctx->timeouts++;
+
+	return TRUE;
+}
+
+static void
+lws_dbus_remove_timeout(DBusTimeout *t, void *data)
+{
+	struct lws_dbus_ctx *ctx = (struct lws_dbus_ctx *)data;
+	struct lws_context_per_thread *pt = &ctx->vh->context->pt[ctx->tsi];
+
+	lwsl_info("%s: t %p, data %p\n", __func__, t, data);
+
+	lws_start_foreach_dll_safe(struct lws_dll *, rdt, nx,
+				   pt->dbus.timer_list_head.next) {
+		struct lws_role_dbus_timer *r = lws_container_of(rdt,
+					struct lws_role_dbus_timer, timer_list);
+		if (t == r->data) {
+			lws_dll_remove(rdt);
+			lws_free(rdt);
+			ctx->timeouts--;
+			break;
+		}
+	} lws_end_foreach_dll_safe(rdt, nx);
+}
+
+static void
+lws_dbus_toggle_timeout(DBusTimeout *t, void *data)
+{
+	if (dbus_timeout_get_enabled(t))
+		lws_dbus_add_timeout(t, data);
+	else
+		lws_dbus_remove_timeout(t, data);
+}
+
+/*
+ * This sets up a connection along the same lines as
+ * dbus_connection_setup_with_g_main(), but for using the lws event loop.
+ */
+
+int
+lws_dbus_connection_setup(struct lws_dbus_ctx *ctx, DBusConnection *conn,
+			  lws_dbus_closing_t cb_closing)
+{
+	int n;
+
+	ctx->conn = conn;
+	ctx->cb_closing = cb_closing;
+	ctx->hup = 0;
+	ctx->timeouts = 0;
+	for (n = 0; n < (int)LWS_ARRAY_SIZE(ctx->w); n++)
+		ctx->w[n] = NULL;
+
+	if (!dbus_connection_set_watch_functions(conn, lws_dbus_add_watch,
+						 lws_dbus_remove_watch,
+						 lws_dbus_toggle_watch,
+						 ctx, NULL)) {
+		lwsl_err("%s: dbus_connection_set_watch_functions fail\n",
+			 __func__);
+		return 1;
+	}
+
+	if (!dbus_connection_set_timeout_functions(conn,
+						   lws_dbus_add_timeout,
+						   lws_dbus_remove_timeout,
+						   lws_dbus_toggle_timeout,
+						   ctx, NULL)) {
+		lwsl_err("%s: dbus_connection_set_timeout_functions fail\n",
+			 __func__);
+		return 1;
+	}
+
+	dbus_connection_set_dispatch_status_function(conn,
+						     handle_dispatch_status,
+						     ctx, NULL);
+
+	return 0;
+}
+
+/*
+ * This wraps dbus_server_listen(), additionally taking care of the event loop
+ * -related setups.
+ */
+
+DBusServer *
+lws_dbus_server_listen(struct lws_dbus_ctx *ctx, const char *ads, DBusError *e,
+		       DBusNewConnectionFunction new_conn)
+{
+	ctx->cb_closing = NULL;
+	ctx->hup = 0;
+	ctx->timeouts = 0;
+
+	ctx->dbs = dbus_server_listen(ads, e);
+	if (!ctx->dbs)
+		return NULL;
+
+	dbus_server_set_new_connection_function(ctx->dbs, new_conn, ctx, NULL);
+
+	if (!dbus_server_set_watch_functions(ctx->dbs, lws_dbus_add_watch,
+					     lws_dbus_remove_watch,
+					     lws_dbus_toggle_watch,
+					     ctx, NULL)) {
+		lwsl_err("%s: dbus_connection_set_watch_functions fail\n",
+			 __func__);
+		goto bail;
+	}
+
+	if (!dbus_server_set_timeout_functions(ctx->dbs, lws_dbus_add_timeout,
+					       lws_dbus_remove_timeout,
+					       lws_dbus_toggle_timeout,
+					       ctx, NULL)) {
+		lwsl_err("%s: dbus_connection_set_timeout_functions fail\n",
+			 __func__);
+		goto bail;
+	}
+
+	return ctx->dbs;
+
+bail:
+	dbus_server_disconnect(ctx->dbs);
+	dbus_server_unref(ctx->dbs);
+
+	return NULL;
+}
+
+
+/*
+ * There shouldn't be a race here with watcher removal and poll wait, because
+ * everything including the dbus activity is serialized in one event loop.
+ *
+ * If it removes the watcher and we remove the wsi and fd entry before this,
+ * actually we can no longer map the fd to this invalidated wsi pointer to call
+ * this.
+ */
+
+static int
+rops_handle_POLLIN_dbus(struct lws_context_per_thread *pt, struct lws *wsi,
+			struct lws_pollfd *pollfd)
+{
+	struct lws_dbus_ctx *ctx =
+			(struct lws_dbus_ctx *)wsi->opaque_parent_data;
+	unsigned int flags = 0;
+	int n;
+
+	if (pollfd->revents & LWS_POLLIN)
+		flags |= DBUS_WATCH_READABLE;
+	if (pollfd->revents & LWS_POLLOUT)
+		flags |= DBUS_WATCH_WRITABLE;
+
+	if (pollfd->revents & (LWS_POLLHUP))
+		ctx->hup = 1;
+
+	/*
+	 * POLLIN + POLLOUT gets us called here on the corresponding shadow
+	 * wsi.  wsi->opaque_parent_data is the watcher handle bound to the wsi
+	 */
+
+	for (n = 0; n < (int)LWS_ARRAY_SIZE(ctx->w); n++)
+		if (ctx->w[n] && !dbus_watch_handle(ctx->w[n], flags))
+			lwsl_err("%s: dbus_watch_handle failed\n", __func__);
+
+	if (ctx->conn) {
+		lwsl_info("%s: conn: flags %d\n", __func__, flags);
+
+		while (dbus_connection_get_dispatch_status(ctx->conn) ==
+						DBUS_DISPATCH_DATA_REMAINS)
+			dbus_connection_dispatch(ctx->conn);
+
+		handle_dispatch_status(NULL, DBUS_DISPATCH_DATA_REMAINS, NULL);
+
+		check_destroy_shadow_wsi(ctx, wsi);
+	} else
+		if (ctx->dbs)
+			/* ??? */
+			lwsl_debug("%s: dbs: %d\n", __func__, flags);
+
+	return LWS_HPI_RET_HANDLED;
+}
+
+static int
+rops_periodic_checks_dbus(struct lws_context *context, int tsi, time_t now)
+{
+	struct lws_context_per_thread *pt = &context->pt[tsi];
+
+	/*
+	 * locking shouldn't be needed here, because periodic_checks is called
+	 * from the tsi-specific service thread context, and only the same
+	 * service thread can modify stuff on the same pt.
+	 */
+
+	lws_start_foreach_dll_safe(struct lws_dll *, rdt, nx,
+				   pt->dbus.timer_list_head.next) {
+		struct lws_role_dbus_timer *r = lws_container_of(rdt,
+					struct lws_role_dbus_timer, timer_list);
+
+		if (now > r->fire) {
+			lwsl_notice("%s: firing timer\n", __func__);
+			dbus_timeout_handle(r->data);
+			lws_dll_remove(rdt);
+			lws_free(rdt);
+		}
+	} lws_end_foreach_dll_safe(rdt, nx);
+
+	return 0;
+}
+
+struct lws_role_ops role_ops_dbus = {
+	/* role name */			"dbus",
+	/* alpn id */			NULL,
+	/* check_upgrades */		NULL,
+	/* init_context */		NULL,
+	/* init_vhost */		NULL,
+	/* destroy_vhost */		NULL,
+	/* periodic_checks */		rops_periodic_checks_dbus,
+	/* service_flag_pending */	NULL,
+	/* handle_POLLIN */		rops_handle_POLLIN_dbus,
+	/* handle_POLLOUT */		NULL,
+	/* perform_user_POLLOUT */	NULL,
+	/* callback_on_writable */	NULL,
+	/* tx_credit */			NULL,
+	/* write_role_protocol */	NULL,
+	/* encapsulation_parent */	NULL,
+	/* alpn_negotiated */		NULL,
+	/* close_via_role_protocol */	NULL,
+	/* close_role */		NULL,
+	/* close_kill_connection */	NULL,
+	/* destroy_role */		NULL,
+	/* adoption_bind */		NULL,
+	/* client_bind */		NULL,
+	/* writeable cb clnt, srv */	{ 0, 0 },
+	/* close cb clnt, srv */	{ 0, 0 },
+	/* protocol_bind_cb c,s */	{ 0, 0 },
+	/* protocol_unbind_cb c,s */	{ 0, 0 },
+	/* file_handle */		0,
+};
diff --git a/lib/roles/dbus/private.h b/lib/roles/dbus/private.h
new file mode 100644
index 0000000000000000000000000000000000000000..c35b50199beed557e577fa838e034be4a9fe0266
--- /dev/null
+++ b/lib/roles/dbus/private.h
@@ -0,0 +1,42 @@
+/*
+ * libwebsockets - small server side websockets and web server implementation
+ *
+ * Copyright (C) 2010 - 2018 Andy Green <andy@warmcat.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License as published by the Free Software Foundation:
+ *  version 2.1 of the License.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ *  MA  02110-1301  USA
+ *
+ *  This is included from core/private.h if LWS_ROLE_DBUS
+ */
+
+#include <dbus/dbus.h>
+
+extern struct lws_role_ops role_ops_dbus;
+
+#define lwsi_role_dbus(wsi) (wsi->role_ops == &role_ops_dbus)
+
+struct lws_role_dbus_timer {
+	struct lws_dll timer_list;
+	void *data;
+	time_t fire;
+};
+
+struct lws_pt_role_dbus {
+	struct lws_dll timer_list_head;
+};
+
+struct _lws_dbus_mode_related {
+	DBusConnection *conn;
+};
diff --git a/lib/roles/private.h b/lib/roles/private.h
index 26f71778610ad5e600063ea450dfa58bac02c160..5f93b86e8fca7b0f31cf67b4452b6408d79c4169 100644
--- a/lib/roles/private.h
+++ b/lib/roles/private.h
@@ -291,6 +291,12 @@ extern struct lws_role_ops role_ops_raw_skt, role_ops_raw_file, role_ops_listen,
  #define lwsi_role_cgi(wsi) (0)
 #endif
 
+#if defined(LWS_ROLE_DBUS)
+ #include "roles/dbus/private.h"
+#else
+ #define lwsi_role_dbus(wsi) (0)
+#endif
+
 enum {
 	LWS_HP_RET_BAIL_OK,
 	LWS_HP_RET_BAIL_DIE,
diff --git a/minimal-examples/README.md b/minimal-examples/README.md
index 525ad1eaf5fcf15e98753b360a7aedec0ca34833..d80dece60f180cea7ccb88efb3196ee44e7ea4b8 100644
--- a/minimal-examples/README.md
+++ b/minimal-examples/README.md
@@ -1,6 +1,7 @@
 |name|demonstrates|
 ---|---
 client-server|Minimal examples providing client and server connections simultaneously
+dbus-server|Minimal examples showing how to integrate DBUS into lws event loop
 http-client|Minimal examples providing an http client
 http-server|Minimal examples providing an http server
 raw|Minimal examples related to adopting raw file or socket descriptors into the event loop
diff --git a/minimal-examples/dbus-client/README.md b/minimal-examples/dbus-client/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..7951825e7fde1a1b4b709feb678387db982d9507
--- /dev/null
+++ b/minimal-examples/dbus-client/README.md
@@ -0,0 +1,4 @@
+|Example|Demonstrates|
+---|---
+minimal-dbus-client|Shows how to connect to a DBusServer dbus server like minimal-dbus-server
+
diff --git a/minimal-examples/dbus-client/minimal-dbus-client/CMakeLists.txt b/minimal-examples/dbus-client/minimal-dbus-client/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..674bb096a79d14b559b1ac711b0caa13ed46fa16
--- /dev/null
+++ b/minimal-examples/dbus-client/minimal-dbus-client/CMakeLists.txt
@@ -0,0 +1,120 @@
+cmake_minimum_required(VERSION 2.8)
+include(CheckCSourceCompiles)
+include(CheckLibraryExists)
+
+set(SAMP lws-minimal-dbus-client)
+set(SRCS minimal-dbus-client.c)
+
+if (NOT LWS_WITH_MINIMAL_EXAMPLES)
+	CHECK_LIBRARY_EXISTS(dbus-1 dbus_connection_set_watch_functions "" LWS_HAVE_LIBDBUS)
+	if (NOT LWS_HAVE_LIBDBUS)
+		message(FATAL_ERROR "Install dbus-devel, or libdbus-1-dev etc")
+	endif()
+
+	if (NOT LWS_DBUS_LIB)
+		set(LWS_DBUS_LIB "dbus-1")
+	endif()
+
+	if (NOT LWS_DBUS_INCLUDE1)
+		# look in fedora and debian / ubuntu place
+		if (EXISTS "/usr/include/dbus-1.0")
+			set(LWS_DBUS_INCLUDE1 "/usr/include/dbus-1.0")
+		else()
+			message(FATAL_ERROR "Set LWS_DBUS_INCLUDE1 to /usr/include/dbus-1.0 or wherever the main dbus includes are")
+		endif()
+	endif()
+
+	if (NOT LWS_DBUS_INCLUDE2)
+		# look in fedora... debian / ubuntu has the ARCH in the path...
+		if (EXISTS "/usr/lib64/dbus-1.0/include")
+			set(LWS_DBUS_INCLUDE2 "/usr/lib64/dbus-1.0/include")
+		else()
+			message(FATAL_ERROR "Set LWS_DBUS_INCLUDE2 to /usr/lib/ARCH-linux-gnu/dbus-1.0/include or wherever dbus-arch-deps.h is on your system")
+		endif()
+	endif()
+
+	set(CMAKE_REQUIRED_INCLUDES ${CMAKE_REQUIRED_INCLUDES};${LWS_DBUS_INCLUDE1};${LWS_DBUS_INCLUDE2})
+
+	if (NOT LWS_DBUS_INCLUDE1 OR NOT LWS_DBUS_INCLUDE2)
+		message(FATAL_ERROR "To build with libdbus, LWS_DBUS_INCLUDE1/2 must be given. See lib/roles/dbus/README.md")
+	endif()
+
+endif()
+
+# 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_DBUS 1 requirements)
+require_lws_config(LWS_WITHOUT_CLIENT 0 requirements)
+
+if (requirements)
+	add_executable(${SAMP} ${SRCS})
+	
+	include_directories("${LWS_DBUS_INCLUDE1}")
+	include_directories("${LWS_DBUS_INCLUDE2}")
+	list(APPEND LIB_LIST dbus-1)
+
+	if (websockets_shared)
+		target_link_libraries(${SAMP} websockets_shared)
+		add_dependencies(${SAMP} websockets_shared ${LWS_DBUS_LIB})
+	else()
+		target_link_libraries(${SAMP} websockets ${LWS_DBUS_LIB})
+	endif()
+endif()
diff --git a/minimal-examples/dbus-client/minimal-dbus-client/README.md b/minimal-examples/dbus-client/minimal-dbus-client/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..42563c61f6b9e99946618bdae0859601737b3e5e
--- /dev/null
+++ b/minimal-examples/dbus-client/minimal-dbus-client/README.md
@@ -0,0 +1,49 @@
+# lws minimal dbus client
+
+This demonstrates nonblocking, asynchronous dbus method calls as the client.
+
+## build
+
+Using libdbus requires additional non-default include paths setting, same as
+is necessary for lws build described in ./lib/roles/dbus/README.md
+
+CMake can guess one path and the library name usually, see the README above
+for details of how to override for custom libdbus and cross build.
+
+Fedora example:
+```
+$ cmake .. -DLWS_DBUS_INCLUDE2="/usr/lib64/dbus-1.0/include"
+$ make
+```
+
+Ubuntu example:
+```
+$ cmake .. -DLWS_DBUS_INCLUDE2="/usr/lib/x86_64-linux-gnu/dbus-1.0/include"
+$ make
+```
+
+## usage
+
+Commandline option|Meaning
+---|---
+-d <loglevel>|Debug verbosity in decimal, eg, -d15
+
+The minimal client connects to the minimal dbus server example, which is
+expected to be listening on its default abstract unix domain socket path.
+
+It call the server Echo method with "Hello!" and returns to the event loop.
+When the reply comes, it prints the returned message.
+
+Afterwards it just sits there receiving unsolicited messages from the server
+example, until closed by the user.
+
+```
+ $ ./lws-minimal-dbus-client
+ctx
+[2018/10/05 06:08:31:4901] NOTICE: pending_call_notify
+[2018/10/05 06:08:31:4929] USER: pending_call_notify: received 'Hello!'
+^C[2018/10/05 06:09:22:4409] NOTICE: destroy_dbus_client_conn
+[2018/10/05 06:09:22:4691] NOTICE: Exiting cleanly
+...
+```
+
diff --git a/minimal-examples/dbus-client/minimal-dbus-client/minimal-dbus-client.c b/minimal-examples/dbus-client/minimal-dbus-client/minimal-dbus-client.c
new file mode 100644
index 0000000000000000000000000000000000000000..7e30d13be00ead46e5b180be0ab5823a17e0cdeb
--- /dev/null
+++ b/minimal-examples/dbus-client/minimal-dbus-client/minimal-dbus-client.c
@@ -0,0 +1,279 @@
+/*
+ * lws-minimal-dbus-client
+ *
+ * Copyright (C) 2018 Andy Green <andy@warmcat.com>
+ *
+ * This file is made available under the Creative Commons CC0 1.0
+ * Universal Public Domain Dedication.
+ *
+ * This demonstrates a minimal session dbus server that uses the lws event loop,
+ * making it possible to integrate it with other lws features.
+ */
+
+#include <stdbool.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <libwebsockets.h>
+#include <libwebsockets/lws-dbus.h>
+
+static struct lws_dbus_ctx *dbus_ctx;
+static struct lws_context *context;
+static int interrupted;
+
+#define THIS_INTERFACE	 "org.libwebsockets.test"
+#define THIS_OBJECT	 "/org/libwebsockets/test"
+#define THIS_BUSNAME	 "org.libwebsockets.test"
+
+#define THIS_LISTEN_PATH "unix:abstract=org.libwebsockets.test"
+
+
+static DBusHandlerResult
+client_message_handler(DBusConnection *conn, DBusMessage *message, void *data)
+{
+	const char *str;
+
+	lwsl_info("%s: Got D-Bus request: %s.%s on %s\n", __func__,
+		  dbus_message_get_interface(message),
+		  dbus_message_get_member(message),
+		  dbus_message_get_path(message));
+
+	if (!dbus_message_get_args(message, NULL, DBUS_TYPE_STRING,
+				   &str, DBUS_TYPE_INVALID))
+		return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+
+	lwsl_notice("%s: '%s'\n", __func__, str);
+
+	return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+}
+
+static void
+destroy_dbus_client_conn(struct lws_dbus_ctx *ctx)
+{
+	if (!ctx || !ctx->conn)
+		return;
+
+	lwsl_notice("%s\n", __func__);
+
+	dbus_connection_remove_filter(ctx->conn, client_message_handler, ctx);
+	dbus_connection_close(ctx->conn);
+	dbus_connection_unref(ctx->conn);
+
+	free(ctx);
+}
+
+/*
+ * This callback is coming when lws has noticed the fd took a POLLHUP.  The
+ * ctx has effectively gone out of scope before this, and the connection can
+ * be cleaned up and the ctx freed.
+ */
+
+static void
+cb_closing(struct lws_dbus_ctx *ctx)
+{
+	lwsl_err("%s: closing\n", __func__);
+
+	if (ctx == dbus_ctx)
+		dbus_ctx = NULL;
+
+	destroy_dbus_client_conn(ctx);
+}
+
+static struct lws_dbus_ctx *
+create_dbus_client_conn(struct lws_vhost *vh, int tsi, const char *ads)
+{
+	struct lws_dbus_ctx *ctx;
+	DBusError err;
+
+	ctx = malloc(sizeof(*ctx));
+	if (!ctx)
+		return NULL;
+
+	memset(ctx, 0, sizeof(*ctx));
+
+	ctx->vh = vh;
+	ctx->tsi = tsi;
+
+        dbus_error_init(&err);
+
+	/* connect to the daemon bus */
+	ctx->conn = dbus_connection_open_private(ads, &err);
+	if (!ctx->conn) {
+		lwsl_err("%s: Failed to connect: %s\n",
+			 __func__, err.message);
+		goto fail;
+	}
+
+	dbus_connection_set_exit_on_disconnect(ctx->conn, 0);
+
+	if (!dbus_connection_add_filter(ctx->conn, client_message_handler,
+					ctx, NULL)) {
+		lwsl_err("%s: Failed to add filter\n", __func__);
+		goto fail;
+	}
+
+	/*
+	 * This is the part that binds the connection to lws watcher and
+	 * timeout handling provided by lws
+	 */
+
+	if (lws_dbus_connection_setup(ctx, ctx->conn, cb_closing)) {
+		lwsl_err("%s: connection bind to lws failed\n", __func__);
+		goto fail;
+	}
+
+	lwsl_notice("%s: created OK\n", __func__);
+
+	return ctx;
+
+fail:
+	dbus_error_free(&err);
+
+	free(ctx);
+
+	return NULL;
+}
+
+
+void sigint_handler(int sig)
+{
+	interrupted = 1;
+}
+
+/*
+ * This gets called if we timed out waiting for the server reply, or the
+ * reply arrived.
+ */
+
+static void
+pending_call_notify(DBusPendingCall *pending, void *data)
+{
+	// struct lws_dbus_ctx *ctx = (struct lws_dbus_ctx *)data;
+	const char *payload;
+	DBusMessage *msg;
+
+	if (!dbus_pending_call_get_completed(pending)) {
+		lwsl_err("%s: timed out waiting for reply\n", __func__);
+
+		goto bail;
+	}
+
+	msg = dbus_pending_call_steal_reply(pending);
+	if (!msg)
+		goto bail;
+
+	if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &payload,
+				   DBUS_TYPE_INVALID)) {
+		goto bail1;
+	}
+
+	lwsl_user("%s: received '%s'\n", __func__, payload);
+
+bail1:
+	dbus_message_unref(msg);
+bail:
+	dbus_pending_call_unref(pending);
+}
+
+static int
+remote_method_call(struct lws_dbus_ctx *ctx)
+{
+	DBusMessage *msg;
+	const char *payload = "Hello!";
+	int ret = 1;
+
+	msg = dbus_message_new_method_call(
+			/* dest */	  THIS_BUSNAME,
+			/* object-path */ THIS_OBJECT,
+			/* interface */   THIS_INTERFACE,
+			/* method */	  "Echo");
+	if (!msg)
+		return 1;
+
+	if (!dbus_message_append_args(msg, DBUS_TYPE_STRING, &payload,
+				      DBUS_TYPE_INVALID))
+		goto bail;
+
+	if (!dbus_connection_send_with_reply(ctx->conn, msg,
+					     &ctx->pc,
+					     DBUS_TIMEOUT_USE_DEFAULT)) {
+		lwsl_err("%s: unable to send\n", __func__);
+
+		goto bail;
+	}
+
+	dbus_pending_call_set_notify(ctx->pc, pending_call_notify, ctx, NULL);
+
+	ret = 0;
+
+bail:
+	dbus_message_unref(msg);
+
+	return ret;
+}
+
+int main(int argc, const char **argv)
+{
+	struct lws_vhost *vh;
+	struct lws_context_creation_info info;
+	const char *p;
+	int n = 0, logs = LLL_USER | LLL_ERR | LLL_WARN | LLL_NOTICE
+			/* for LLL_ verbosity above NOTICE to be built into lws,
+			 * lws must have been configured and built with
+			 * -DCMAKE_BUILD_TYPE=DEBUG instead of =RELEASE */
+			/* | LLL_INFO */ /* | LLL_PARSER */ /* | LLL_HEADER */
+			/* | LLL_EXT */ /* | LLL_CLIENT */ /* | LLL_LATENCY */
+			/* | LLL_DEBUG */ /* | LLL_THREAD */;
+
+	signal(SIGINT, sigint_handler);
+
+	if ((p = lws_cmdline_option(argc, argv, "-d")))
+		logs = atoi(p);
+
+	lws_set_log_level(logs, NULL);
+	lwsl_user("LWS minimal DBUS client\n");
+
+	memset(&info, 0, sizeof info); /* otherwise uninitialized garbage */
+	info.options = LWS_SERVER_OPTION_EXPLICIT_VHOSTS;
+	context = lws_create_context(&info);
+	if (!context) {
+		lwsl_err("lws init failed\n");
+		return 1;
+	}
+
+	vh = lws_create_vhost(context, &info);
+	if (!vh)
+		goto bail;
+
+	dbus_ctx = create_dbus_client_conn(vh, 0, THIS_LISTEN_PATH);
+	if (!dbus_ctx)
+		goto bail1;
+
+	if (remote_method_call(dbus_ctx))
+		goto bail2;
+
+	/* lws event loop (default poll one) */
+
+	while (n >= 0 && !interrupted)
+		n = lws_service(context, 1000);
+
+bail2:
+	destroy_dbus_client_conn(dbus_ctx);
+
+bail1:
+	/* this is required for valgrind-cleanliness */
+	dbus_shutdown();
+	lws_context_destroy(context);
+
+	lwsl_notice("Exiting cleanly\n");
+
+	return 0;
+
+bail:
+	lwsl_err("%s: failed to start\n", __func__);
+	lws_context_destroy(context);
+
+	return 1;
+}
diff --git a/minimal-examples/dbus-server/README.md b/minimal-examples/dbus-server/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..95039204c103c2bd24cb1618b687429d6e4fe541
--- /dev/null
+++ b/minimal-examples/dbus-server/README.md
@@ -0,0 +1,3 @@
+|Example|Demonstrates|
+---|---
+minimal-dbus-server|Shows how to run a DBUS session server using lws event loop
diff --git a/minimal-examples/dbus-server/minimal-dbus-server/CMakeLists.txt b/minimal-examples/dbus-server/minimal-dbus-server/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..7260d5a4d519f63bcdb5cb4d84b396355e816d9b
--- /dev/null
+++ b/minimal-examples/dbus-server/minimal-dbus-server/CMakeLists.txt
@@ -0,0 +1,120 @@
+cmake_minimum_required(VERSION 2.8)
+include(CheckCSourceCompiles)
+include(CheckLibraryExists)
+
+set(SAMP lws-minimal-dbus-server)
+set(SRCS main.c)
+
+if (NOT LWS_WITH_MINIMAL_EXAMPLES)
+	CHECK_LIBRARY_EXISTS(dbus-1 dbus_connection_set_watch_functions "" LWS_HAVE_LIBDBUS)
+	if (NOT LWS_HAVE_LIBDBUS)
+		message(FATAL_ERROR "Install dbus-devel, or libdbus-1-dev etc")
+	endif()
+
+	if (NOT LWS_DBUS_LIB)
+		set(LWS_DBUS_LIB "dbus-1")
+	endif()
+
+	if (NOT LWS_DBUS_INCLUDE1)
+		# look in fedora and debian / ubuntu place
+		if (EXISTS "/usr/include/dbus-1.0")
+			set(LWS_DBUS_INCLUDE1 "/usr/include/dbus-1.0")
+		else()
+			message(FATAL_ERROR "Set LWS_DBUS_INCLUDE1 to /usr/include/dbus-1.0 or wherever the main dbus includes are")
+		endif()
+	endif()
+
+	if (NOT LWS_DBUS_INCLUDE2)
+		# look in fedora... debian / ubuntu has the ARCH in the path...
+		if (EXISTS "/usr/lib64/dbus-1.0/include")
+			set(LWS_DBUS_INCLUDE2 "/usr/lib64/dbus-1.0/include")
+		else()
+			message(FATAL_ERROR "Set LWS_DBUS_INCLUDE2 to /usr/lib/ARCH-linux-gnu/dbus-1.0/include or wherever dbus-arch-deps.h is on your system")
+		endif()
+	endif()
+
+	set(CMAKE_REQUIRED_INCLUDES ${CMAKE_REQUIRED_INCLUDES};${LWS_DBUS_INCLUDE1};${LWS_DBUS_INCLUDE2})
+
+	if (NOT LWS_DBUS_INCLUDE1 OR NOT LWS_DBUS_INCLUDE2)
+		message(FATAL_ERROR "To build with libdbus, LWS_DBUS_INCLUDE1/2 must be given. See lib/roles/dbus/README.md")
+	endif()
+
+endif()
+
+# 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_DBUS 1 requirements)
+require_lws_config(LWS_WITHOUT_SERVER 0 requirements)
+
+if (requirements)
+	add_executable(${SAMP} ${SRCS})
+	
+	include_directories("${LWS_DBUS_INCLUDE1}")
+	include_directories("${LWS_DBUS_INCLUDE2}")
+	list(APPEND LIB_LIST dbus-1)
+
+	if (websockets_shared)
+		target_link_libraries(${SAMP} websockets_shared)
+		add_dependencies(${SAMP} websockets_shared ${LWS_DBUS_LIB})
+	else()
+		target_link_libraries(${SAMP} websockets ${LWS_DBUS_LIB})
+	endif()
+endif()
diff --git a/minimal-examples/dbus-server/minimal-dbus-server/README.md b/minimal-examples/dbus-server/minimal-dbus-server/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..7b61eb14b51a4bc75fae225cfa8587ff40020336
--- /dev/null
+++ b/minimal-examples/dbus-server/minimal-dbus-server/README.md
@@ -0,0 +1,96 @@
+# lws minimal dbus server
+
+## build
+
+Using libdbus requires additional non-default include paths setting, same as
+is necessary for lws build described in ./lib/roles/dbus/README.md
+
+CMake can guess one path and the library name usually, see the README above
+for details of how to override for custom libdbus and cross build.
+
+Fedora example:
+```
+$ cmake .. -DLWS_DBUS_INCLUDE2="/usr/lib64/dbus-1.0/include"
+$ make
+```
+
+Ubuntu example:
+```
+$ cmake .. -DLWS_DBUS_INCLUDE2="/usr/lib/x86_64-linux-gnu/dbus-1.0/include"
+$ make
+```
+
+## usage
+
+Commandline option|Meaning
+---|---
+-d <loglevel>|Debug verbosity in decimal, eg, -d15
+--session | Bind to session bus instead of creating private abstract unix socket
+
+By default the minimal server listens using its own abstract unix socket
+at `unix:abstract=org.libwebsockets.test`.
+
+You can also run it instead as a participant on the session bus, without its own
+unix socket, by giving `--session`.
+
+### Examples using the default private abstract unix socket
+
+```
+ $ ./lws-minimal-dbus-server
+[2018/10/03 07:08:02:6448] USER: LWS minimal dbus server
+[2018/10/03 07:08:02:6693] NOTICE: Creating Vhost 'default' port 0, 1 protocols, IPv6 off
+...
+```
+
+You can communicate with the dbus server over its private abstract socket using, eg
+
+```
+$ gdbus introspect --address unix:abstract=org.libwebsockets.test --dest org.libwebsockets.test --object-path /org/libwebsockets/test
+node /org/example/TestObject {
+  interface org.freedesktop.DBus.Introspectable {
+    methods:
+      Introspect(out s data);
+    signals:
+    properties:
+  };
+  interface org.freedesktop.DBus.Properties {
+    methods:
+      Get(in  s interface,
+...
+```
+
+```
+$ gdbus call --address unix:abstract=org.libwebsockets.test --dest org.libwebsockets.test --object-path /org/libwebsockets/test --method org.libwebsockets.test.Echo HELLO
+('HELLO',)
+```
+
+### Examples using the DBUS session bus
+
+```
+ $ ./lws-minimal-dbus-server --session
+[2018/10/03 07:08:02:6448] USER: LWS minimal dbus server
+[2018/10/03 07:08:02:6693] NOTICE: Creating Vhost 'default' port 0, 1 protocols, IPv6 off
+...
+```
+
+You can communicate with the dbus server over the session bus using, eg
+
+```
+$ gdbus introspect --session --dest org.libwebsockets.test --object-path /org/libwebsockets/test
+node /org/example/TestObject {
+  interface org.freedesktop.DBus.Introspectable {
+    methods:
+      Introspect(out s data);
+    signals:
+    properties:
+  };
+  interface org.freedesktop.DBus.Properties {
+    methods:
+      Get(in  s interface,
+...
+```
+
+```
+$ gdbus call --session --dest org.libwebsockets.test --object-path /org/libwebsockets/test --method org.libwebsockets.test.Echo HELLO
+('HELLO',)
+```
diff --git a/minimal-examples/dbus-server/minimal-dbus-server/main.c b/minimal-examples/dbus-server/minimal-dbus-server/main.c
new file mode 100644
index 0000000000000000000000000000000000000000..863439c427bc64c44d38bde0a0e099f41fcb0757
--- /dev/null
+++ b/minimal-examples/dbus-server/minimal-dbus-server/main.c
@@ -0,0 +1,532 @@
+/*
+ * lws-minimal-dbus-server
+ *
+ * Copyright (C) 2018 Andy Green <andy@warmcat.com>
+ *
+ * This file is made available under the Creative Commons CC0 1.0
+ * Universal Public Domain Dedication.
+ *
+ * This demonstrates a minimal session dbus server that uses the lws event loop,
+ * making it possible to integrate it with other lws features.
+ *
+ * The dbus server parts are based on "Sample code illustrating basic use of
+ * D-BUS" (presumed Public Domain) here:
+ *
+ * https://github.com/fbuihuu/samples-dbus/blob/master/dbus-server.c
+ */
+
+#include <stdbool.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <signal.h>
+
+#include <libwebsockets.h>
+#include <libwebsockets/lws-dbus.h>
+
+static struct lws_context *context;
+static const char *version = "0.1";
+static int interrupted;
+static struct lws_dbus_ctx dbus_ctx, ctx_listener;
+static char session;
+
+#define THIS_INTERFACE	 "org.libwebsockets.test"
+#define THIS_OBJECT	 "/org/libwebsockets/test"
+#define THIS_BUSNAME	 "org.libwebsockets.test"
+
+#define THIS_LISTEN_PATH "unix:abstract=org.libwebsockets.test"
+
+static const char *
+server_introspection_xml =
+	DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE
+	"<node>\n"
+	"  <interface name='" DBUS_INTERFACE_INTROSPECTABLE "'>\n"
+	"    <method name='Introspect'>\n"
+	"      <arg name='data' type='s' direction='out' />\n"
+	"    </method>\n"
+	"  </interface>\n"
+
+	"  <interface name='" DBUS_INTERFACE_PROPERTIES "'>\n"
+	"    <method name='Get'>\n"
+	"      <arg name='interface' type='s' direction='in' />\n"
+	"      <arg name='property'  type='s' direction='in' />\n"
+	"      <arg name='value'     type='s' direction='out' />\n"
+	"    </method>\n"
+	"    <method name='GetAll'>\n"
+	"      <arg name='interface'  type='s'     direction='in'/>\n"
+	"      <arg name='properties' type='a{sv}' direction='out'/>\n"
+	"    </method>\n"
+	"  </interface>\n"
+
+	"  <interface name='"THIS_INTERFACE"'>\n"
+	"    <property name='Version' type='s' access='read' />\n"
+	"    <method name='Ping' >\n"
+	"      <arg type='s' direction='out' />\n"
+	"    </method>\n"
+	"    <method name='Echo'>\n"
+	"      <arg name='string' direction='in' type='s'/>\n"
+	"      <arg type='s' direction='out' />\n"
+	"    </method>\n"
+	"    <method name='EmitSignal'>\n"
+	"    </method>\n"
+	"    <method name='Quit'>\n"
+	"    </method>\n"
+	"    <signal name='OnEmitSignal'>\n"
+	"    </signal>"
+	"  </interface>\n"
+
+	"</node>\n";
+
+static DBusHandlerResult
+dmh_introspect(DBusConnection *c, DBusMessage *m, DBusMessage **reply, void *d)
+{
+	dbus_message_append_args(*reply, DBUS_TYPE_STRING,
+				 &server_introspection_xml, DBUS_TYPE_INVALID);
+
+	return DBUS_HANDLER_RESULT_HANDLED;
+}
+
+static DBusHandlerResult
+dmh_get(DBusConnection *c, DBusMessage *m, DBusMessage **reply, void *d)
+{
+	const char *interface, *property;
+	DBusError err;
+
+	dbus_error_init(&err);
+
+	if (!dbus_message_get_args(m, &err, DBUS_TYPE_STRING, &interface,
+					    DBUS_TYPE_STRING, &property,
+					    DBUS_TYPE_INVALID)) {
+		dbus_message_unref(*reply);
+		*reply = dbus_message_new_error(m, err.name, err.message);
+		dbus_error_free(&err);
+
+		return DBUS_HANDLER_RESULT_HANDLED;
+	}
+
+	if (strcmp(property, "Version")) /* Unknown property */
+		return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+
+	dbus_message_append_args(*reply, DBUS_TYPE_STRING, &version,
+				 DBUS_TYPE_INVALID);
+
+	return DBUS_HANDLER_RESULT_HANDLED;
+}
+
+static DBusHandlerResult
+dmh_getall(DBusConnection *c, DBusMessage *m, DBusMessage **reply, void *d)
+{
+	DBusMessageIter arr, di, iter, va;
+	const char *property = "Version";
+
+	dbus_message_iter_init_append(*reply, &iter);
+	dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "{sv}", &arr);
+
+	/* Append all properties name/value pairs */
+	dbus_message_iter_open_container(&arr, DBUS_TYPE_DICT_ENTRY, NULL, &di);
+	dbus_message_iter_append_basic(&di, DBUS_TYPE_STRING, &property);
+	dbus_message_iter_open_container(&di, DBUS_TYPE_VARIANT, "s", &va);
+	dbus_message_iter_append_basic(&va, DBUS_TYPE_STRING, &version);
+	dbus_message_iter_close_container(&di, &va);
+	dbus_message_iter_close_container(&arr, &di);
+
+	dbus_message_iter_close_container(&iter, &arr);
+
+	return DBUS_HANDLER_RESULT_HANDLED;
+}
+
+static DBusHandlerResult
+dmh_ping(DBusConnection *c, DBusMessage *m, DBusMessage **reply, void *d)
+{
+	const char *pong = "Pong";
+
+	dbus_message_append_args(*reply, DBUS_TYPE_STRING, &pong,
+					 DBUS_TYPE_INVALID);
+
+	return DBUS_HANDLER_RESULT_HANDLED;
+}
+
+static DBusHandlerResult
+dmh_echo(DBusConnection *c, DBusMessage *m, DBusMessage **reply, void *d)
+{
+	const char *msg;
+	DBusError err;
+
+	dbus_error_init(&err);
+
+	if (!dbus_message_get_args(m, &err, DBUS_TYPE_STRING,
+				   &msg, DBUS_TYPE_INVALID)) {
+		dbus_message_unref(*reply);
+		*reply = dbus_message_new_error(m, err.name, err.message);
+		dbus_error_free(&err);
+
+		return DBUS_HANDLER_RESULT_HANDLED;
+	}
+
+	dbus_message_append_args(*reply, DBUS_TYPE_STRING, &msg,
+					 DBUS_TYPE_INVALID);
+
+	return DBUS_HANDLER_RESULT_HANDLED;
+}
+
+static DBusHandlerResult
+dmh_emit_signal(DBusConnection *c, DBusMessage *m, DBusMessage **reply, void *d)
+{
+	DBusMessage *r = dbus_message_new_signal(THIS_OBJECT, THIS_INTERFACE,
+					         "OnEmitSignal");
+
+	if (!r)
+		return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+
+	if (!dbus_connection_send(c, r, NULL))
+		return DBUS_HANDLER_RESULT_NEED_MEMORY;
+
+	/* and send the original empty reply after */
+
+	return DBUS_HANDLER_RESULT_HANDLED;
+}
+
+static DBusHandlerResult
+dmh_emit_quit(DBusConnection *c, DBusMessage *m, DBusMessage **reply, void *d)
+{
+	interrupted = 1;
+
+	return DBUS_HANDLER_RESULT_HANDLED;
+}
+
+struct lws_dbus_methods {
+	const char *inter;
+	const char *call;
+	lws_dbus_message_handler handler;
+} meths[] = {
+	{ DBUS_INTERFACE_INTROSPECTABLE, "Introspect",	dmh_introspect	},
+	{ DBUS_INTERFACE_PROPERTIES,	 "Get",		dmh_get		},
+	{ DBUS_INTERFACE_PROPERTIES,	 "GetAll",	dmh_getall	},
+	{ THIS_INTERFACE,		 "Ping",	dmh_ping	},
+	{ THIS_INTERFACE,		 "Echo",	dmh_echo	},
+	{ THIS_INTERFACE,		 "EmitSignal",	dmh_emit_signal },
+	{ THIS_INTERFACE,		 "Quit",	dmh_emit_quit	},
+};
+
+static DBusHandlerResult
+server_message_handler(DBusConnection *conn, DBusMessage *message, void *data)
+{
+	struct lws_dbus_methods *mp = meths;
+	DBusHandlerResult result;
+        DBusMessage *reply = NULL;
+	size_t n;
+
+	lwsl_info("%s: Got D-Bus request: %s.%s on %s\n", __func__,
+		  dbus_message_get_interface(message),
+		  dbus_message_get_member(message),
+		  dbus_message_get_path(message));
+
+	for (n = 0; n < LWS_ARRAY_SIZE(meths); n++) {
+		if (dbus_message_is_method_call(message, mp->inter, mp->call)) {
+			reply = dbus_message_new_method_return(message);
+			if (!reply)
+				return DBUS_HANDLER_RESULT_NEED_MEMORY;
+
+			result = mp->handler(conn, message, &reply, data);
+
+			if (result == DBUS_HANDLER_RESULT_HANDLED &&
+			    !dbus_connection_send(conn, reply, NULL))
+				result = DBUS_HANDLER_RESULT_NEED_MEMORY;
+
+			dbus_message_unref(reply);
+
+			return result;
+		}
+
+		mp++;
+	}
+
+	return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+}
+
+static const DBusObjectPathVTable server_vtable = {
+	.message_function = server_message_handler
+};
+
+static void
+destroy_dbus_server_conn(struct lws_dbus_ctx *ctx)
+{
+	if (!ctx->conn)
+		return;
+
+	lwsl_notice("%s\n", __func__);
+
+	dbus_connection_unregister_object_path(ctx->conn, THIS_OBJECT);
+	lws_dll_remove(&ctx->next);
+	dbus_connection_unref(ctx->conn);
+}
+
+static void
+cb_closing(struct lws_dbus_ctx *ctx)
+{
+	lwsl_err("%s: closing\n", __func__);
+	destroy_dbus_server_conn(ctx);
+
+	free(ctx);
+}
+
+
+static void
+new_conn(DBusServer *server, DBusConnection *conn, void *data)
+{
+	struct lws_dbus_ctx *conn_ctx, *ctx = (struct lws_dbus_ctx *)data;
+
+	lwsl_notice("%s: vh %s\n", __func__, lws_get_vhost_name(ctx->vh));
+
+	conn_ctx = malloc(sizeof(*conn_ctx));
+	if (!conn_ctx)
+		return;
+
+	memset(conn_ctx, 0, sizeof(*conn_ctx));
+
+	conn_ctx->tsi = ctx->tsi;
+	conn_ctx->vh = ctx->vh;
+	conn_ctx->conn = conn;
+
+	if (lws_dbus_connection_setup(conn_ctx, conn, cb_closing)) {
+		lwsl_err("%s: connection bind to lws failed\n", __func__);
+		goto bail;
+	}
+
+	if (!dbus_connection_register_object_path(conn, THIS_OBJECT,
+						  &server_vtable, conn_ctx)) {
+		lwsl_err("%s: Failed to register object path\n", __func__);
+		goto bail;
+	}
+
+	lws_dll_add_front(&conn_ctx->next, &ctx->next);
+
+	/* we take on responsibility for explicit close / unref with this... */
+	dbus_connection_ref(conn);
+
+	return;
+
+bail:
+	free(conn_ctx);
+}
+
+static int
+create_dbus_listener(const char *ads)
+{
+	DBusError e;
+
+        dbus_error_init(&e);
+
+	if (!lws_dbus_server_listen(&ctx_listener, ads, &e, new_conn)) {
+		lwsl_err("%s: failed\n", __func__);
+		dbus_error_free(&e);
+
+		return 1;
+	}
+
+	return 0;
+}
+
+static int
+create_dbus_server_conn(struct lws_dbus_ctx *ctx, DBusBusType type)
+{
+	DBusError err;
+	int rv;
+
+        dbus_error_init(&err);
+
+	/* connect to the daemon bus */
+	ctx->conn = dbus_bus_get(type, &err);
+	if (!ctx->conn) {
+		lwsl_err("%s: Failed to get a session DBus connection: %s\n",
+			 __func__, err.message);
+		goto fail;
+	}
+
+	/*
+	 * by default dbus will call exit() when this connection closes...
+	 * we have to shut down other things cleanly, so disable that
+	 */
+	dbus_connection_set_exit_on_disconnect(ctx->conn, 0);
+
+	rv = dbus_bus_request_name(ctx->conn, THIS_BUSNAME,
+				   DBUS_NAME_FLAG_REPLACE_EXISTING, &err);
+	if (rv != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) {
+		lwsl_err("%s: Failed to request name on bus: %s\n",
+			 __func__, err.message);
+		goto fail;
+	}
+
+	if (!dbus_connection_register_object_path(ctx->conn, THIS_OBJECT,
+						  &server_vtable, NULL)) {
+		lwsl_err("%s: Failed to register object path for TestObject\n",
+			 __func__);
+		dbus_bus_release_name(ctx->conn, THIS_BUSNAME, &err);
+		goto fail;
+	}
+
+	/*
+	 * This is the part that binds the connection to lws watcher and
+	 * timeout handling provided by lws
+	 */
+
+	if (lws_dbus_connection_setup(ctx, ctx->conn, cb_closing)) {
+		lwsl_err("%s: connection bind to lws failed\n", __func__);
+		goto fail;
+	}
+
+	lwsl_notice("%s: created OK\n", __func__);
+
+	return 0;
+
+fail:
+	dbus_error_free(&err);
+
+	return 1;
+}
+
+/*
+ * Cleanly release the connection
+ */
+
+static void
+destroy_dbus_server_listener(struct lws_dbus_ctx *ctx)
+{
+	dbus_server_disconnect(ctx->dbs);
+
+	lws_start_foreach_dll_safe(struct lws_dll *, rdt, nx,
+				   ctx->next.next) {
+		struct lws_dbus_ctx *r =
+			lws_container_of(rdt, struct lws_dbus_ctx, next);
+
+		dbus_connection_close(r->conn);
+		dbus_connection_unref(r->conn);
+		free(r);
+	} lws_end_foreach_dll_safe(rdt, nx);
+
+	dbus_server_unref(ctx->dbs);
+}
+
+/*
+ * DBUS can send messages outside the usual client-initiated RPC concept.
+ *
+ * You can receive them using a message filter.
+ */
+
+static void
+spam_connected_clients(struct lws_dbus_ctx *ctx)
+{
+
+	/* send connected clients an unsolicited message */
+
+	lws_start_foreach_dll_safe(struct lws_dll *, rdt, nx,
+				   ctx->next.next) {
+		struct lws_dbus_ctx *r =
+			lws_container_of(rdt, struct lws_dbus_ctx, next);
+
+
+		DBusMessage *msg;
+		const char *payload = "Unsolicited message";
+
+		msg = dbus_message_new(DBUS_NUM_MESSAGE_TYPES + 1);
+		if (!msg) {
+			lwsl_err("%s: new message failed\n", __func__);
+		}
+
+		dbus_message_append_args(msg, DBUS_TYPE_STRING, &payload,
+						 DBUS_TYPE_INVALID);
+		if (!dbus_connection_send(r->conn, msg, NULL)) {
+			lwsl_err("%s: unable to send\n", __func__);
+		}
+
+		lwsl_notice("%s\n", __func__);
+
+		dbus_message_unref(msg);
+
+	} lws_end_foreach_dll_safe(rdt, nx);
+
+}
+
+
+void sigint_handler(int sig)
+{
+	interrupted = 1;
+}
+
+int main(int argc, const char **argv)
+{
+	struct lws_context_creation_info info;
+	const char *p;
+	int n = 0, logs = LLL_USER | LLL_ERR | LLL_WARN | LLL_NOTICE
+			/* for LLL_ verbosity above NOTICE to be built into lws,
+			 * lws must have been configured and built with
+			 * -DCMAKE_BUILD_TYPE=DEBUG instead of =RELEASE */
+			/* | LLL_INFO */ /* | LLL_PARSER */ /* | LLL_HEADER */
+			/* | LLL_EXT */ /* | LLL_CLIENT */ /* | LLL_LATENCY */
+			/* | LLL_DEBUG */ /* | LLL_THREAD */;
+
+	signal(SIGINT, sigint_handler);
+
+	if ((p = lws_cmdline_option(argc, argv, "-d")))
+		logs = atoi(p);
+
+	lws_set_log_level(logs, NULL);
+	lwsl_user("LWS minimal DBUS server\n");
+
+	memset(&info, 0, sizeof info); /* otherwise uninitialized garbage */
+	info.options = LWS_SERVER_OPTION_EXPLICIT_VHOSTS;
+	context = lws_create_context(&info);
+	if (!context) {
+		lwsl_err("lws init failed\n");
+		return 1;
+	}
+
+	dbus_ctx.tsi = 0;
+	ctx_listener.tsi = 0;
+	ctx_listener.vh = dbus_ctx.vh = lws_create_vhost(context, &info);
+	if (!dbus_ctx.vh)
+		goto bail;
+
+	session = !!lws_cmdline_option(argc, argv, "--session");
+
+	if (session) {
+		/* create the dbus connection, loosely bound to our lws vhost */
+
+		if (create_dbus_server_conn(&dbus_ctx, DBUS_BUS_SESSION))
+			goto bail;
+	} else {
+		if (create_dbus_listener(THIS_LISTEN_PATH)) {
+			lwsl_err("%s: create_dbus_listener failed\n", __func__);
+			goto bail;
+		}
+	}
+
+	/* lws event loop (default poll one) */
+
+	while (n >= 0 && !interrupted) {
+		if (!session)
+			spam_connected_clients(&ctx_listener);
+		n = lws_service(context, 1000);
+	}
+
+	if (session)
+		destroy_dbus_server_conn(&dbus_ctx);
+	else
+		destroy_dbus_server_listener(&ctx_listener);
+
+	/* this is required for valgrind-cleanliness */
+	dbus_shutdown();
+	lws_context_destroy(context);
+
+	lwsl_notice("Exiting cleanly\n");
+
+	return 0;
+
+bail:
+	lwsl_err("%s: failed to start\n", __func__);
+
+	lws_context_destroy(context);
+
+	return 1;
+}