]> git.ipfire.org Git - thirdparty/freeswitch.git/commitdiff
FS-9952: Rewrote core code to utilize state machine driven system based on discussion...
authorShane Bryldt <astaelan@gmail.com>
Thu, 9 Feb 2017 17:08:07 +0000 (17:08 +0000)
committerMike Jerris <mike@jerris.com>
Wed, 22 Mar 2017 21:42:49 +0000 (17:42 -0400)
15 files changed:
libs/libblade/Makefile.am
libs/libblade/src/blade_connection.c [new file with mode: 0644]
libs/libblade/src/blade_identity.c [new file with mode: 0644]
libs/libblade/src/blade_module.c [new file with mode: 0644]
libs/libblade/src/blade_module_wss.c [new file with mode: 0644]
libs/libblade/src/blade_peer.c [deleted file]
libs/libblade/src/blade_service.c [deleted file]
libs/libblade/src/blade_stack.c
libs/libblade/src/include/blade.h
libs/libblade/src/include/blade_connection.h [new file with mode: 0644]
libs/libblade/src/include/blade_identity.h [moved from libs/libblade/src/include/blade_service.h with 70% similarity]
libs/libblade/src/include/blade_module.h [moved from libs/libblade/src/include/blade_peer.h with 67% similarity]
libs/libblade/src/include/blade_stack.h
libs/libblade/src/include/blade_types.h
libs/libblade/test/bladec [deleted file]

index 12ef174b65b2f57e02191cf12cccf5e074f7e595..c9343ff9fc7eff79649eba15edf2847fcd2df08f 100644 (file)
@@ -11,14 +11,16 @@ libunqlite_la_CFLAGS    = -DUNQLITE_ENABLE_THREADS
 libunqlite_la_LIBADD    = -lpthread
 
 lib_LTLIBRARIES                = libblade.la
-libblade_la_SOURCES     = src/blade.c src/blade_stack.c src/blade_peer.c src/blade_service.c src/bpcp.c src/blade_datastore.c
+libblade_la_SOURCES     = src/blade.c src/blade_stack.c src/bpcp.c src/blade_datastore.c
 libblade_la_SOURCES    += src/blade_message.c src/blade_rpcproto.c
+libblade_la_SOURCES    += src/blade_identity.c src/blade_module.c src/blade_connection.c src/blade_module_wss.c
 libblade_la_CFLAGS     = $(AM_CFLAGS) $(AM_CPPFLAGS)
 libblade_la_LDFLAGS     = -version-info 0:1:0 -lncurses -lpthread -lm -lconfig $(AM_LDFLAGS)
 libblade_la_LIBADD      = libunqlite.la
 library_includedir     = $(prefix)/include
-library_include_HEADERS = src/include/blade.h src/include/blade_types.h src/include/blade_stack.h src/include/blade_peer.h src/include/blade_service.h
+library_include_HEADERS = src/include/blade.h src/include/blade_types.h src/include/blade_stack.h
 library_include_HEADERS += src/include/bpcp.h src/include/blade_datastore.h src/include/blade_message.h src/include/blade_rpcproto.h
+library_include_HEADERS += src/include/blade_identity.h src/include/blade_module.h src/include/blade_connection.h
 library_include_HEADERS += src/include/unqlite.h test/tap.h
 
 tests: libblade.la
diff --git a/libs/libblade/src/blade_connection.c b/libs/libblade/src/blade_connection.c
new file mode 100644 (file)
index 0000000..3ac3366
--- /dev/null
@@ -0,0 +1,251 @@
+/*
+ * Copyright (c) 2017, Shane Bryldt
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 
+ * * Neither the name of the original author; nor the names of any contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ * 
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "blade.h"
+
+struct blade_connection_s {
+       blade_handle_t *handle;
+       ks_pool_t *pool;
+
+       void *transport_data;
+       blade_transport_callbacks_t *transport_callbacks;
+
+       ks_bool_t shutdown;
+       // @todo add auto generated UUID
+    ks_thread_t *state_thread;
+       blade_connection_state_t state;
+       
+       ks_q_t *sending;
+       ks_q_t *receiving;
+};
+
+void *blade_connection_state_thread(ks_thread_t *thread, void *data);
+
+
+KS_DECLARE(ks_status_t) blade_connection_create(blade_connection_t **bcP,
+                                                                                               blade_handle_t *bh,
+                                                                                               void *transport_data,
+                                                                                               blade_transport_callbacks_t *transport_callbacks)
+{
+       blade_connection_t *bc = NULL;
+       ks_pool_t *pool = NULL;
+
+       ks_assert(bcP);
+       ks_assert(bh);
+       ks_assert(transport_data);
+       ks_assert(transport_callbacks);
+
+       pool = blade_handle_pool_get(bh);
+
+       bc = ks_pool_alloc(pool, sizeof(blade_connection_t));
+       bc->handle = bh;
+       bc->pool = pool;
+       bc->transport_data = transport_data;
+       bc->transport_callbacks = transport_callbacks;
+       ks_q_create(&bc->sending, pool, 0);
+       ks_q_create(&bc->receiving, pool, 0);
+       *bcP = bc;
+
+       return KS_STATUS_SUCCESS;
+}
+
+KS_DECLARE(ks_status_t) blade_connection_destroy(blade_connection_t **bcP)
+{
+       blade_connection_t *bc = NULL;
+       
+       ks_assert(bcP);
+       ks_assert(*bcP);
+
+       bc = *bcP;
+
+       blade_connection_shutdown(bc);
+
+       ks_q_destroy(&bc->sending);
+       ks_q_destroy(&bc->receiving);
+
+       ks_pool_free(bc->pool, bcP);
+
+       return KS_STATUS_SUCCESS;
+}
+
+KS_DECLARE(ks_status_t) blade_connection_startup(blade_connection_t *bc)
+{
+       ks_assert(bc);
+
+       blade_connection_state_set(bc, BLADE_CONNECTION_STATE_NONE);
+
+    if (ks_thread_create_ex(&bc->state_thread,
+                                                       blade_connection_state_thread,
+                                                       bc,
+                                                       KS_THREAD_FLAG_DEFAULT,
+                                                       KS_THREAD_DEFAULT_STACK,
+                                                       KS_PRI_NORMAL,
+                                                       bc->pool) != KS_STATUS_SUCCESS) {
+               // @todo error logging
+               blade_connection_disconnect(bc);
+               return KS_STATUS_FAIL;
+       }
+       
+       return KS_STATUS_SUCCESS;
+}
+
+KS_DECLARE(ks_status_t) blade_connection_shutdown(blade_connection_t *bc)
+{
+       ks_assert(bc);
+
+       if (bc->state_thread) {
+               bc->shutdown = KS_TRUE;
+               ks_thread_join(bc->state_thread);
+               ks_pool_free(bc->pool, &bc->state_thread);
+               bc->shutdown = KS_FALSE;
+       }
+
+       //while (ks_q_trypop(bc->sending, (void **)&message) == KS_STATUS_SUCCESS && message) blade_message_discard(&message);
+       //while (ks_q_trypop(bc->receiving, (void **)&message) == KS_STATUS_SUCCESS && message) blade_message_discard(&message);
+
+       return KS_STATUS_SUCCESS;
+}
+
+KS_DECLARE(void *) blade_connection_transport_get(blade_connection_t *bc)
+{
+       ks_assert(bc);
+
+       return bc->transport_data;
+}
+
+KS_DECLARE(void) blade_connection_state_set(blade_connection_t *bc, blade_connection_state_t state)
+{
+       ks_assert(bc);
+
+       bc->transport_callbacks->onstate(bc, state, BLADE_CONNECTION_STATE_CONDITION_PRE);
+       bc->state = state;
+}
+
+KS_DECLARE(void) blade_connection_disconnect(blade_connection_t *bc)
+{
+       ks_assert(bc);
+
+       blade_connection_state_set(bc, BLADE_CONNECTION_STATE_DISCONNECT);
+}
+
+KS_DECLARE(ks_status_t) blade_connection_sending_push(blade_connection_t *bc, blade_identity_t *target, cJSON *json)
+{
+       ks_assert(bc);
+       ks_assert(json);
+
+       // @todo need internal envelope to wrap an identity object and a json object just for the queue
+
+       return KS_STATUS_SUCCESS;
+}
+
+KS_DECLARE(ks_status_t) blade_connection_sending_pop(blade_connection_t *bc, blade_identity_t **target, cJSON **json)
+{
+       ks_assert(bc);
+       ks_assert(json);
+
+       // @todo need internal envelope to wrap an identity object and a json object just for the queue
+       
+       return KS_STATUS_SUCCESS;
+}
+
+KS_DECLARE(ks_status_t) blade_connection_receiving_push(blade_connection_t *bc, cJSON *json)
+{
+       ks_assert(bc);
+       ks_assert(json);
+
+       return ks_q_push(bc->receiving, json);
+}
+
+KS_DECLARE(ks_status_t) blade_connection_receiving_pop(blade_connection_t *bc, cJSON **json)
+{
+       ks_assert(bc);
+       ks_assert(json);
+       
+       return ks_q_trypop(bc->receiving, (void **)json);
+}
+
+void *blade_connection_state_thread(ks_thread_t *thread, void *data)
+{
+       blade_connection_t *bc = NULL;
+       blade_connection_state_hook_t hook;
+
+       ks_assert(thread);
+       ks_assert(data);
+
+       bc = (blade_connection_t *)data;
+
+       while (!bc->shutdown) {
+               // @todo need to get messages from the transport into receiving queue, and pop messages from sending queue to write out using transport
+               // sending is relatively easy, but receiving cannot occur universally due to cases like kws_init() blocking and expecting data to be on the wire
+               // and other transports may have similar behaviours, but CONNECTIN, ATTACH, and READY require async message passing into application layer
+               // and sending whenever the response hits the queue
+               
+               // @todo it's possible that onstate could handle receiving and sending messages during the appropriate states, but this means some states
+               // like CONNECTIN which may send and receive multiple messages require BYPASSing until the application layer updates the state or disconnects
+               
+               hook = bc->transport_callbacks->onstate(bc, bc->state, BLADE_CONNECTION_STATE_CONDITION_POST);
+               if (hook == BLADE_CONNECTION_STATE_HOOK_DISCONNECT)
+                       blade_connection_disconnect(bc);
+               else if (hook == BLADE_CONNECTION_STATE_HOOK_SUCCESS) {
+                       // @todo pop from sending queue, and pass to transport callback to send out
+                       switch (bc->state) {
+                       case BLADE_CONNECTION_STATE_NEW:
+                               blade_connection_state_set(bc, BLADE_CONNECTION_STATE_CONNECT);
+                               break;
+                       case BLADE_CONNECTION_STATE_CONNECT:
+                               blade_connection_state_set(bc, BLADE_CONNECTION_STATE_ATTACH);
+                               break;
+                       case BLADE_CONNECTION_STATE_ATTACH:
+                               blade_connection_state_set(bc, BLADE_CONNECTION_STATE_READY);
+                               break;
+                       case BLADE_CONNECTION_STATE_DETACH:
+                               blade_connection_disconnect(bc);
+                               break;
+                       default: break;
+                       }
+               }
+       }
+
+       return NULL;
+}
+       
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet:
+ */
diff --git a/libs/libblade/src/blade_identity.c b/libs/libblade/src/blade_identity.c
new file mode 100644 (file)
index 0000000..3e814e8
--- /dev/null
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2017, Shane Bryldt
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 
+ * * Neither the name of the original author; nor the names of any contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ * 
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "blade.h"
+
+struct blade_identity_s {
+       ks_pool_t *pool;
+
+       const char *uri;
+       // @todo breakdown of uri into constituent parts
+};
+
+
+KS_DECLARE(ks_status_t) blade_identity_create(blade_identity_t **biP, ks_pool_t *pool)
+{
+       blade_identity_t *bi = NULL;
+
+       ks_assert(biP);
+       ks_assert(pool);
+
+       bi = ks_pool_alloc(pool, sizeof(blade_identity_t));
+       bi->pool = pool;
+       *biP = bi;
+
+       return KS_STATUS_SUCCESS;
+}
+
+KS_DECLARE(ks_status_t) blade_identity_destroy(blade_identity_t **biP)
+{
+       blade_identity_t *bi = NULL;
+       
+       ks_assert(biP);
+       ks_assert(*biP);
+
+       bi = *biP;
+
+       ks_pool_free(bi->pool, biP);
+
+       return KS_STATUS_SUCCESS;
+}
+
+KS_DECLARE(ks_status_t) blade_identity_parse(blade_identity_t *bi, const char *uri)
+{
+       ks_assert(bi);
+       ks_assert(uri);
+
+       if (bi->uri) ks_pool_free(bi->pool, &bi->uri);
+       
+       return KS_STATUS_SUCCESS;
+}
+
+KS_DECLARE(ks_status_t) blade_identity_uri(blade_identity_t *bi, const char **uri)
+{
+       ks_assert(bi);
+       ks_assert(uri);
+
+       *uri = bi->uri;
+       return KS_STATUS_SUCCESS;
+}
+       
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet:
+ */
diff --git a/libs/libblade/src/blade_module.c b/libs/libblade/src/blade_module.c
new file mode 100644 (file)
index 0000000..a874e45
--- /dev/null
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 2017, Shane Bryldt
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 
+ * * Neither the name of the original author; nor the names of any contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ * 
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "blade.h"
+
+struct blade_module_s {
+       blade_handle_t *handle;
+       ks_pool_t *pool;
+
+       void *module_data;
+       blade_module_callbacks_t *module_callbacks;
+};
+
+
+KS_DECLARE(ks_status_t) blade_module_create(blade_module_t **bmP, blade_handle_t *bh, void *module_data, blade_module_callbacks_t *module_callbacks)
+{
+       blade_module_t *bm = NULL;
+       ks_pool_t *pool = NULL;
+
+       ks_assert(bmP);
+       ks_assert(bh);
+       ks_assert(module_data);
+       ks_assert(module_callbacks);
+
+       pool = blade_handle_pool_get(bh);
+
+       bm = ks_pool_alloc(pool, sizeof(blade_module_t));
+       bm->handle = bh;
+       bm->pool = pool;
+       bm->module_data = module_data;
+       bm->module_callbacks = module_callbacks;
+       *bmP = bm;
+
+       return KS_STATUS_SUCCESS;
+}
+
+KS_DECLARE(ks_status_t) blade_module_destroy(blade_module_t **bmP)
+{
+       blade_module_t *bm = NULL;
+
+       ks_assert(bmP);
+       ks_assert(*bmP);
+
+       bm = *bmP;
+
+       ks_pool_free(bm->pool, bmP);
+
+       return KS_STATUS_SUCCESS;
+}
+
+KS_DECLARE(void *) blade_module_data_get(blade_module_t *bm)
+{
+       ks_assert(bm);
+
+       return bm->module_data;
+}
+
+       
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet:
+ */
diff --git a/libs/libblade/src/blade_module_wss.c b/libs/libblade/src/blade_module_wss.c
new file mode 100644 (file)
index 0000000..3efe430
--- /dev/null
@@ -0,0 +1,655 @@
+/*
+ * Copyright (c) 2017, Shane Bryldt
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 
+ * * Neither the name of the original author; nor the names of any contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ * 
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "blade.h"
+
+#define BLADE_MODULE_WSS_ENDPOINTS_MULTIHOME_MAX 16
+
+typedef struct blade_module_wss_s blade_module_wss_t;
+typedef struct blade_transport_wss_s blade_transport_wss_t;
+
+struct blade_module_wss_s {
+       blade_handle_t *handle;
+       ks_pool_t *pool;
+       ks_thread_pool_t *tpool;
+       blade_module_t *module;
+       blade_module_callbacks_t *module_callbacks;
+       blade_transport_callbacks_t *transport_callbacks;
+
+       ks_sockaddr_t config_wss_endpoints_ipv4[BLADE_MODULE_WSS_ENDPOINTS_MULTIHOME_MAX];
+       ks_sockaddr_t config_wss_endpoints_ipv6[BLADE_MODULE_WSS_ENDPOINTS_MULTIHOME_MAX];
+       int32_t config_wss_endpoints_ipv4_length;
+       int32_t config_wss_endpoints_ipv6_length;
+       int32_t config_wss_endpoints_backlog;
+
+       ks_bool_t shutdown;
+
+       ks_thread_t *listeners_thread;
+       struct pollfd *listeners_poll;
+       int32_t listeners_count;
+
+       list_t connected;
+       ks_q_t *disconnected;
+};
+
+struct blade_transport_wss_s {
+       blade_module_wss_t *module;
+       ks_pool_t *pool;
+
+       ks_socket_t sock;
+       kws_t *kws;
+};
+
+
+
+ks_status_t blade_module_wss_create(blade_module_wss_t **bm_wssP, blade_handle_t *bh);
+ks_status_t blade_module_wss_destroy(blade_module_wss_t **bm_wssP);
+
+ks_status_t blade_module_wss_onload(blade_module_t **bmP, blade_handle_t *bh);
+ks_status_t blade_module_wss_onunload(blade_module_t *bm);
+ks_status_t blade_module_wss_onstartup(blade_module_t *bm, config_setting_t *config);
+ks_status_t blade_module_wss_onshutdown(blade_module_t *bm);
+
+ks_status_t blade_module_wss_listen(blade_module_wss_t *bm, ks_sockaddr_t *addr);
+void *blade_module_wss_listeners_thread(ks_thread_t *thread, void *data);
+
+
+ks_status_t blade_transport_wss_create(blade_transport_wss_t **bt_wssP, blade_module_wss_t *bm_wss, ks_socket_t sock);
+ks_status_t blade_transport_wss_destroy(blade_transport_wss_t **bt_wssP);
+
+ks_status_t blade_transport_wss_onconnect(blade_connection_t **bcP, blade_module_t *bm, blade_identity_t *target);
+blade_connection_rank_t blade_transport_wss_onrank(blade_connection_t *bc, blade_identity_t *target);
+blade_connection_state_hook_t blade_transport_wss_onstate(blade_connection_t *bc, blade_connection_state_t state, blade_connection_state_condition_t condition);
+
+
+
+static blade_module_callbacks_t g_module_wss_callbacks =
+{
+       blade_module_wss_onload,
+       blade_module_wss_onunload,
+       blade_module_wss_onstartup,
+       blade_module_wss_onshutdown,
+};
+
+static blade_transport_callbacks_t g_transport_wss_callbacks =
+{
+       blade_transport_wss_onconnect,
+       blade_transport_wss_onrank,
+       blade_transport_wss_onstate,
+};
+
+
+
+ks_status_t blade_module_wss_create(blade_module_wss_t **bm_wssP, blade_handle_t *bh)
+{
+       blade_module_wss_t *bm_wss = NULL;
+       
+       ks_assert(bm_wssP);
+       ks_assert(bh);
+
+    bm_wss = ks_pool_alloc(bm_wss->pool, sizeof(blade_module_wss_t));
+       bm_wss->handle = bh;
+       bm_wss->pool = blade_handle_pool_get(bh);
+       bm_wss->tpool = blade_handle_tpool_get(bh);
+
+       blade_module_create(&bm_wss->module, bh, bm_wss, &g_module_wss_callbacks);
+       bm_wss->module_callbacks = &g_module_wss_callbacks;
+       bm_wss->transport_callbacks = &g_transport_wss_callbacks;
+       list_init(&bm_wss->connected);
+       ks_q_create(&bm_wss->disconnected, bm_wss->pool, 0);
+       ks_assert(bm_wss->disconnected);
+
+       *bm_wssP = bm_wss;
+
+       return KS_STATUS_SUCCESS;
+}
+
+ks_status_t blade_module_wss_destroy(blade_module_wss_t **bm_wssP)
+{
+       blade_module_wss_t *bm_wss = NULL;
+       
+       ks_assert(bm_wssP);
+       ks_assert(*bm_wssP);
+
+       bm_wss = *bm_wssP;
+
+       blade_module_wss_onshutdown(bm_wss->module);
+       
+       blade_module_destroy(&bm_wss->module);
+
+       list_destroy(&bm_wss->connected);
+       ks_q_destroy(&bm_wss->disconnected);
+
+       ks_pool_free(bm_wss->pool, bm_wssP);
+
+       return KS_STATUS_SUCCESS;
+}
+
+ks_status_t blade_module_wss_onload(blade_module_t **bmP, blade_handle_t *bh)
+{
+       blade_module_wss_t *bm_wss = NULL;
+
+       ks_assert(bmP);
+       ks_assert(bh);
+
+       blade_module_wss_create(&bm_wss, bh);
+       ks_assert(bm_wss);
+
+       *bmP = bm_wss->module;
+       
+       return KS_STATUS_SUCCESS;
+}
+
+ks_status_t blade_module_wss_onunload(blade_module_t *bm)
+{
+       blade_module_wss_t *bm_wss = NULL;
+
+       ks_assert(bm);
+
+       bm_wss = blade_module_data_get(bm);
+       
+       blade_module_wss_destroy(&bm_wss);
+       
+       return KS_STATUS_SUCCESS;
+}
+
+ks_status_t blade_module_wss_config(blade_module_wss_t *bm_wss, config_setting_t *config)
+{
+       config_setting_t *wss = NULL;
+       config_setting_t *wss_endpoints = NULL;
+       config_setting_t *wss_endpoints_ipv4 = NULL;
+       config_setting_t *wss_endpoints_ipv6 = NULL;
+       config_setting_t *wss_ssl = NULL;
+    config_setting_t *element;
+       config_setting_t *tmp1;
+       config_setting_t *tmp2;
+       ks_sockaddr_t config_wss_endpoints_ipv4[BLADE_MODULE_WSS_ENDPOINTS_MULTIHOME_MAX];
+       ks_sockaddr_t config_wss_endpoints_ipv6[BLADE_MODULE_WSS_ENDPOINTS_MULTIHOME_MAX];
+       int32_t config_wss_endpoints_ipv4_length = 0;
+       int32_t config_wss_endpoints_ipv6_length = 0;
+       int32_t config_wss_endpoints_backlog = 8;
+
+       ks_assert(bm_wss);
+       ks_assert(config);
+
+       if (!config_setting_is_group(config)) {
+               ks_log(KS_LOG_DEBUG, "!config_setting_is_group(config)\n");
+               return KS_STATUS_FAIL;
+       }
+
+       wss = config_setting_get_member(config, "wss");
+       if (!wss) {
+               ks_log(KS_LOG_DEBUG, "!wss\n");
+               return KS_STATUS_FAIL;
+       }
+       wss_endpoints = config_setting_get_member(wss, "endpoints");
+       if (!wss_endpoints) {
+               ks_log(KS_LOG_DEBUG, "!wss_endpoints\n");
+               return KS_STATUS_FAIL;
+       }
+       wss_endpoints_ipv4 = config_lookup_from(wss_endpoints, "ipv4");
+       wss_endpoints_ipv6 = config_lookup_from(wss_endpoints, "ipv6");
+       if (wss_endpoints_ipv4) {
+               if (config_setting_type(wss_endpoints_ipv4) != CONFIG_TYPE_LIST) return KS_STATUS_FAIL;
+               if ((config_wss_endpoints_ipv4_length = config_setting_length(wss_endpoints_ipv4)) > BLADE_MODULE_WSS_ENDPOINTS_MULTIHOME_MAX)
+                       return KS_STATUS_FAIL;
+               
+               for (int32_t index = 0; index < config_wss_endpoints_ipv4_length; ++index) {
+                       element = config_setting_get_elem(wss_endpoints_ipv4, index);
+            tmp1 = config_lookup_from(element, "address");
+            tmp2 = config_lookup_from(element, "port");
+                       if (!tmp1 || !tmp2) return KS_STATUS_FAIL;
+                       if (config_setting_type(tmp1) != CONFIG_TYPE_STRING) return KS_STATUS_FAIL;
+                       if (config_setting_type(tmp2) != CONFIG_TYPE_INT) return KS_STATUS_FAIL;
+                       
+                       if (ks_addr_set(&config_wss_endpoints_ipv4[index],
+                                                       config_setting_get_string(tmp1),
+                                                       config_setting_get_int(tmp2),
+                                                       AF_INET) != KS_STATUS_SUCCESS) return KS_STATUS_FAIL;
+                       ks_log(KS_LOG_DEBUG,
+                                  "Binding to IPV4 %s on port %d\n",
+                                  ks_addr_get_host(&config_wss_endpoints_ipv4[index]),
+                                  ks_addr_get_port(&config_wss_endpoints_ipv4[index]));
+               }
+       }
+       if (wss_endpoints_ipv6) {
+               if (config_setting_type(wss_endpoints_ipv6) != CONFIG_TYPE_LIST) return KS_STATUS_FAIL;
+               if ((config_wss_endpoints_ipv6_length = config_setting_length(wss_endpoints_ipv6)) > BLADE_MODULE_WSS_ENDPOINTS_MULTIHOME_MAX)
+                       return KS_STATUS_FAIL;
+               
+               for (int32_t index = 0; index < config_wss_endpoints_ipv6_length; ++index) {
+                       element = config_setting_get_elem(wss_endpoints_ipv6, index);
+            tmp1 = config_lookup_from(element, "address");
+            tmp2 = config_lookup_from(element, "port");
+                       if (!tmp1 || !tmp2) return KS_STATUS_FAIL;
+                       if (config_setting_type(tmp1) != CONFIG_TYPE_STRING) return KS_STATUS_FAIL;
+                       if (config_setting_type(tmp2) != CONFIG_TYPE_INT) return KS_STATUS_FAIL;
+                       
+                       
+                       if (ks_addr_set(&config_wss_endpoints_ipv6[index],
+                                                       config_setting_get_string(tmp1),
+                                                       config_setting_get_int(tmp2),
+                                                       AF_INET6) != KS_STATUS_SUCCESS) return KS_STATUS_FAIL;
+                       ks_log(KS_LOG_DEBUG,
+                                  "Binding to IPV6 %s on port %d\n",
+                                  ks_addr_get_host(&config_wss_endpoints_ipv6[index]),
+                                  ks_addr_get_port(&config_wss_endpoints_ipv6[index]));
+               }
+       }
+       if (config_wss_endpoints_ipv4_length + config_wss_endpoints_ipv6_length <= 0) return KS_STATUS_FAIL;
+       tmp1 = config_lookup_from(wss_endpoints, "backlog");
+       if (tmp1) {
+               if (config_setting_type(tmp1) != CONFIG_TYPE_INT) return KS_STATUS_FAIL;
+               config_wss_endpoints_backlog = config_setting_get_int(tmp1);
+       }
+       wss_ssl = config_setting_get_member(wss, "ssl");
+       if (wss_ssl) {
+               // @todo: SSL stuffs from wss_ssl into config_wss_ssl envelope
+       }
+
+
+       // Configuration is valid, now assign it to the variables that are used
+       // If the configuration was invalid, then this does not get changed
+       for (int32_t index = 0; index < config_wss_endpoints_ipv4_length; ++index)
+               bm_wss->config_wss_endpoints_ipv4[index] = config_wss_endpoints_ipv4[index];
+       for (int32_t index = 0; index < config_wss_endpoints_ipv6_length; ++index)
+               bm_wss->config_wss_endpoints_ipv6[index] = config_wss_endpoints_ipv6[index];
+       bm_wss->config_wss_endpoints_ipv4_length = config_wss_endpoints_ipv4_length;
+       bm_wss->config_wss_endpoints_ipv6_length = config_wss_endpoints_ipv6_length;
+       bm_wss->config_wss_endpoints_backlog = config_wss_endpoints_backlog;
+       //bm_wss->config_wss_ssl = config_wss_ssl;
+
+       return KS_STATUS_SUCCESS;
+}
+
+ks_status_t blade_module_wss_onstartup(blade_module_t *bm, config_setting_t *config)
+{
+       blade_module_wss_t *bm_wss = NULL;
+       
+       ks_assert(bm);
+       ks_assert(config);
+
+       bm_wss = (blade_module_wss_t *)blade_module_data_get(bm);
+
+    if (blade_module_wss_config(bm_wss, config) != KS_STATUS_SUCCESS) {
+               ks_log(KS_LOG_DEBUG, "blade_module_wss_config failed\n");
+               return KS_STATUS_FAIL;
+       }
+
+       for (int32_t index = 0; index < bm_wss->config_wss_endpoints_ipv4_length; ++index) {
+               if (blade_module_wss_listen(bm_wss, &bm_wss->config_wss_endpoints_ipv4[index]) != KS_STATUS_SUCCESS) {
+                       ks_log(KS_LOG_DEBUG, "blade_module_wss_listen (v4) failed\n");
+                       return KS_STATUS_FAIL;
+               }
+       }
+       for (int32_t index = 0; index < bm_wss->config_wss_endpoints_ipv6_length; ++index) {
+               if (blade_module_wss_listen(bm_wss, &bm_wss->config_wss_endpoints_ipv6[index]) != KS_STATUS_SUCCESS) {
+                       ks_log(KS_LOG_DEBUG, "blade_module_wss_listen (v6) failed\n");
+                       return KS_STATUS_FAIL;
+               }
+       }
+
+       if (ks_thread_create_ex(&bm_wss->listeners_thread,
+                                                       blade_module_wss_listeners_thread,
+                                                       bm_wss,
+                                                       KS_THREAD_FLAG_DEFAULT,
+                                                       KS_THREAD_DEFAULT_STACK,
+                                                       KS_PRI_NORMAL,
+                                                       bm_wss->pool) != KS_STATUS_SUCCESS) return KS_STATUS_FAIL;
+       
+       return KS_STATUS_SUCCESS;
+}
+
+ks_status_t blade_module_wss_onshutdown(blade_module_t *bm)
+{
+       blade_module_wss_t *bm_wss = NULL;
+       blade_transport_wss_t *bt_wss = NULL;
+       blade_connection_t *bc = NULL;
+       
+       ks_assert(bm);
+
+       bm_wss = (blade_module_wss_t *)blade_module_data_get(bm);
+
+       if (bm_wss->listeners_thread) {
+               bm_wss->shutdown = KS_TRUE;
+               ks_thread_join(bm_wss->listeners_thread);
+               ks_pool_free(bm_wss->pool, &bm_wss->listeners_thread);
+               bm_wss->shutdown = KS_FALSE;
+       }
+
+       for (int32_t index = 0; index < bm_wss->listeners_count; ++index) {
+               ks_socket_t sock = bm_wss->listeners_poll[index].fd;
+               ks_socket_shutdown(sock, SHUT_RDWR);
+               ks_socket_close(&sock);
+       }
+       bm_wss->listeners_count = 0;
+       if (bm_wss->listeners_poll) ks_pool_free(bm_wss->pool, &bm_wss->listeners_poll);
+
+       while (ks_q_trypop(bm_wss->disconnected, (void **)&bc) == KS_STATUS_SUCCESS) ;
+       list_iterator_start(&bm_wss->connected);
+       while (list_iterator_hasnext(&bm_wss->connected)) {
+               bc = (blade_connection_t *)list_iterator_next(&bm_wss->connected);
+               bt_wss = (blade_transport_wss_t *)blade_connection_transport_get(bc);
+
+               blade_connection_destroy(&bc);
+               blade_transport_wss_destroy(&bt_wss);
+       }
+       list_iterator_stop(&bm_wss->connected);
+       list_clear(&bm_wss->connected);
+
+       return KS_STATUS_SUCCESS;
+}
+
+ks_status_t blade_module_wss_listen(blade_module_wss_t *bm_wss, ks_sockaddr_t *addr)
+{
+       ks_socket_t listener = KS_SOCK_INVALID;
+       int32_t listener_index = -1;
+       ks_status_t ret = KS_STATUS_SUCCESS;
+       
+       ks_assert(bm_wss);
+       ks_assert(addr);
+
+       if ((listener = socket(addr->family, SOCK_STREAM, IPPROTO_TCP)) == KS_SOCK_INVALID) {
+               ks_log(KS_LOG_DEBUG, "listener == KS_SOCK_INVALID\n");
+               ret = KS_STATUS_FAIL;
+               goto done;
+       }
+
+       ks_socket_option(listener, SO_REUSEADDR, KS_TRUE);
+       ks_socket_option(listener, TCP_NODELAY, KS_TRUE);
+       if (addr->family == AF_INET6) ks_socket_option(listener, IPV6_V6ONLY, KS_TRUE);
+
+       if (ks_addr_bind(listener, addr) != KS_STATUS_SUCCESS) {
+               ks_log(KS_LOG_DEBUG, "ks_addr_bind(listener, addr) != KS_STATUS_SUCCESS\n");
+               ret = KS_STATUS_FAIL;
+               goto done;
+       }
+
+       if (listen(listener, bm_wss->config_wss_endpoints_backlog) != 0) {
+               ks_log(KS_LOG_DEBUG, "listen(listener, backlog) != 0\n");
+               ret = KS_STATUS_FAIL;
+               goto done;
+       }
+
+       listener_index = bm_wss->listeners_count++;
+       bm_wss->listeners_poll = (struct pollfd *)ks_pool_resize(bm_wss->pool,
+                                                                                                                        bm_wss->listeners_poll,
+                                                                                                                        sizeof(struct pollfd) * bm_wss->listeners_count);
+       ks_assert(bm_wss->listeners_poll);
+       bm_wss->listeners_poll[listener_index].fd = listener;
+       bm_wss->listeners_poll[listener_index].events = POLLIN | POLLERR;
+
+ done:
+       if (ret != KS_STATUS_SUCCESS) {
+               if (listener != KS_SOCK_INVALID) {
+                       ks_socket_shutdown(listener, SHUT_RDWR);
+                       ks_socket_close(&listener);
+               }
+       }
+       return ret;
+}
+
+void *blade_module_wss_listeners_thread(ks_thread_t *thread, void *data)
+{
+       blade_module_wss_t *bm_wss = NULL;
+       blade_transport_wss_t *bt_wss = NULL;
+       blade_connection_t *bc = NULL;
+
+       ks_assert(thread);
+       ks_assert(data);
+
+       bm_wss = (blade_module_wss_t *)data;
+
+       while (!bm_wss->shutdown) {
+               // @todo take exact timeout from a setting in config_wss_endpoints
+               if (ks_poll(bm_wss->listeners_poll, bm_wss->listeners_count, 100) > 0) {
+                       for (int32_t index = 0; index < bm_wss->listeners_count; ++index) {
+                               ks_socket_t sock = KS_SOCK_INVALID;
+
+                               if (!(bm_wss->listeners_poll[index].revents & POLLIN)) continue;
+                               if (bm_wss->listeners_poll[index].revents & POLLERR) {
+                                       // @todo: error handling, just skip the listener for now, it might recover, could skip X times before closing?
+                                       continue;
+                               }
+
+                               if ((sock = accept(bm_wss->listeners_poll[index].fd, NULL, NULL)) == KS_SOCK_INVALID) {
+                                       // @todo: error handling, just skip the socket for now as most causes are because remote side became unreachable
+                                       continue;
+                               }
+
+                               blade_transport_wss_create(&bt_wss, bm_wss, sock);
+                               ks_assert(bt_wss);
+                               
+                blade_connection_create(&bc, bm_wss->handle, bt_wss, bm_wss->transport_callbacks);
+                               ks_assert(bc);
+
+                               blade_connection_startup(bc);
+
+                               list_append(&bm_wss->connected, bc);
+
+                               blade_connection_state_set(bc, BLADE_CONNECTION_STATE_NEW);
+                       }
+               }
+
+               while (ks_q_trypop(bm_wss->disconnected, (void **)&bc) == KS_STATUS_SUCCESS) {
+                       bt_wss = (blade_transport_wss_t *)blade_connection_transport_get(bc);
+
+                       list_delete(&bm_wss->connected, bc);
+
+                       blade_connection_destroy(&bc);
+                       blade_transport_wss_destroy(&bt_wss);
+               }
+       }
+
+    return NULL;
+}
+
+
+
+ks_status_t blade_transport_wss_create(blade_transport_wss_t **bt_wssP, blade_module_wss_t *bm_wss, ks_socket_t sock)
+{
+       blade_transport_wss_t *bt_wss = NULL;
+
+       ks_assert(bt_wssP);
+       ks_assert(bm_wss);
+       ks_assert(sock != KS_SOCK_INVALID);
+
+    bt_wss = ks_pool_alloc(bm_wss->pool, sizeof(blade_transport_wss_t));
+       bt_wss->module = bm_wss;
+       bt_wss->pool = bm_wss->pool;
+       bt_wss->sock = sock;
+
+       *bt_wssP = bt_wss;
+       
+       return KS_STATUS_SUCCESS;
+}
+
+ks_status_t blade_transport_wss_destroy(blade_transport_wss_t **bt_wssP)
+{
+       blade_transport_wss_t *bt_wss = NULL;
+       
+       ks_assert(bt_wssP);
+       ks_assert(*bt_wssP);
+
+       bt_wss = *bt_wssP;
+
+       if (bt_wss->kws) kws_destroy(&bt_wss->kws);
+       else ks_socket_close(&bt_wss->sock);
+       
+       ks_pool_free(bt_wss->pool, bt_wssP);
+       
+       return KS_STATUS_SUCCESS;
+}
+
+ks_status_t blade_transport_wss_onconnect(blade_connection_t **bcP, blade_module_t *bm, blade_identity_t *target)
+{
+       ks_assert(bcP);
+       ks_assert(bm);
+       ks_assert(target);
+
+       *bcP = NULL;
+
+       // @todo connect-out equivilent of accept
+
+       return KS_STATUS_SUCCESS;
+}
+
+blade_connection_rank_t blade_transport_wss_onrank(blade_connection_t *bc, blade_identity_t *target)
+{
+       ks_assert(bc);
+       ks_assert(target);
+       
+       return KS_STATUS_SUCCESS;
+}
+
+ks_status_t blade_transport_wss_read(blade_transport_wss_t *bt_wss, cJSON **json)
+{
+       // @todo get exact timeout from service config?
+       int32_t poll_flags = ks_wait_sock(bt_wss->sock, 100, KS_POLL_READ | KS_POLL_ERROR);
+
+       *json = NULL;
+
+       if (poll_flags & KS_POLL_ERROR) {
+               // @todo error logging
+               return KS_STATUS_FAIL;
+       }
+       if (poll_flags & KS_POLL_READ) {
+               kws_opcode_t opcode;
+               uint8_t *frame_data = NULL;
+               ks_size_t frame_data_len = kws_read_frame(bt_wss->kws, &opcode, &frame_data);
+
+               if (frame_data_len <= 0) {
+                       // @todo error logging, strerror(ks_errno())
+                       // 0 means socket closed with WS_NONE, which closes websocket with no additional reason
+                       // -1 means socket closed with a general failure
+                       // -2 means nonblocking wait
+                       // other values are based on WS_XXX reasons
+                       // negative values are based on reasons, except for -1 is but -2 is nonblocking wait, and
+                       return KS_STATUS_FAIL;
+               }
+
+               //if (blade_handle_message_claim(blade_service_handle(peer->service), &message, frame_data, frame_data_len) != KS_STATUS_SUCCESS || !message) {
+               // @todo error logging
+               //      return KS_STATUS_FAIL;
+               //}
+                               
+               // @todo convert frame_data to cJSON safely, make sure data is null-terminated at frame_data_len
+               if (!(*json = cJSON_Parse((char *)frame_data))) {
+                       return KS_STATUS_FAIL;
+               }
+       }
+       return KS_STATUS_SUCCESS;
+}
+
+ks_status_t blade_transport_wss_write(blade_transport_wss_t *bt_wss, cJSON *json)
+{
+       //blade_message_get(message, &target, &json);
+       char *json_str = cJSON_PrintUnformatted(json);
+       ks_size_t json_str_len = 0;
+       if (!json_str) {
+               // @todo error logging
+               return KS_STATUS_FAIL;
+       }
+       json_str_len = strlen(json_str) + 1;
+       kws_write_frame(bt_wss->kws, WSOC_TEXT, json_str, json_str_len);
+
+       return KS_STATUS_SUCCESS;
+}
+
+blade_connection_state_hook_t blade_transport_wss_onstate(blade_connection_t *bc, blade_connection_state_t state, blade_connection_state_condition_t condition)
+{
+       blade_transport_wss_t *bt_wss = NULL;
+       //cJSON *json = NULL;
+
+       ks_assert(bc);
+
+       bt_wss = (blade_transport_wss_t *)blade_connection_transport_get(bc);
+
+       switch (state) {
+       case BLADE_CONNECTION_STATE_DISCONNECT:
+               {
+                       if (condition == BLADE_CONNECTION_STATE_CONDITION_POST) {
+                               ks_q_push(bt_wss->module->disconnected, bc);
+                               blade_connection_state_set(bc, BLADE_CONNECTION_STATE_NONE);
+                       }
+                       break;
+               }
+       case BLADE_CONNECTION_STATE_NEW:
+               {
+                       if (condition == BLADE_CONNECTION_STATE_CONDITION_POST) {
+                               // @todo: SSL init stuffs based on data from peer->service->config_websockets_ssl to pass into kws_init
+                               if (kws_init(&bt_wss->kws, bt_wss->sock, NULL, NULL, KWS_BLOCK, bt_wss->pool) != KS_STATUS_SUCCESS) {
+                                       // @todo error logging
+                                       return BLADE_CONNECTION_STATE_HOOK_DISCONNECT;
+                               }
+                       }
+                       break;
+               }
+       case BLADE_CONNECTION_STATE_CONNECT:
+               {
+                       // @todo abstract read message and write message, so these can be called from connection and processed from there
+                       
+                       //if (blade_transport_wss_read(bt_wss, &json) != KS_STATUS_SUCCESS) return BLADE_CONNECTION_STATEHOOK_DISCONNECT;
+
+                       //if (json) {
+                               // @todo processing connectin messages for identity registration
+                       //      cJSON_Delete(json);
+                               //blade_connection_receiving_push(conn, json);
+                       //}
+
+                       // @todo wrap identity + json into an envelope for queueing through the connection
+                       //while (blade_connection_sending_pop(bc, (void **)&json) == KS_STATUS_SUCCESS && json) {
+                       //      ks_status_t ret = blade_transport_wss_write(bt_wss, json);
+                       //      cJSON_Delete(json);
+                       //      if (ret != KS_STATUS_SUCCESS) return BLADE_CONNECTION_STATE_HOOK_DISCONNECT;
+                       //}
+                       return BLADE_CONNECTION_STATE_HOOK_SUCCESS;
+                       //break;
+               }
+       default: break;
+       }
+       
+       return BLADE_CONNECTION_STATE_HOOK_SUCCESS;
+}
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet:
+ */
diff --git a/libs/libblade/src/blade_peer.c b/libs/libblade/src/blade_peer.c
deleted file mode 100644 (file)
index 5ec3d6b..0000000
+++ /dev/null
@@ -1,278 +0,0 @@
-/*
- * Copyright (c) 2007-2014, Anthony Minessale II
- * All rights reserved.
- * 
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 
- * * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 
- * * Neither the name of the original author; nor the names of any contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- * 
- * 
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER
- * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "blade.h"
-
-struct blade_peer_s {
-       ks_pool_t *pool;
-       ks_thread_pool_t *tpool;
-       blade_service_t *service;
-
-       ks_socket_t sock;
-       ks_bool_t shutdown;
-       blade_peerstate_t state;
-       blade_peerreason_t reason;
-       
-       kws_t *kws;
-       ks_thread_t *kws_thread;
-
-       ks_q_t *messages_sending;
-       ks_q_t *messages_receiving;
-};
-
-
-void *blade_peer_kws_thread(ks_thread_t *thread, void *data);
-
-
-KS_DECLARE(ks_status_t) blade_peer_destroy(blade_peer_t **bpP)
-{
-       blade_peer_t *bp = NULL;
-
-       ks_assert(bpP);
-
-       bp = *bpP;
-       *bpP = NULL;
-
-       ks_assert(bp);
-
-       blade_peer_shutdown(bp);
-
-       ks_q_destroy(&bp->messages_sending);
-       ks_q_destroy(&bp->messages_receiving);
-
-       ks_pool_free(bp->pool, &bp);
-
-       return KS_STATUS_SUCCESS;
-}
-
-KS_DECLARE(ks_status_t) blade_peer_create(blade_peer_t **bpP, ks_pool_t *pool, ks_thread_pool_t *tpool, blade_service_t *service)
-{
-       blade_peer_t *bp = NULL;
-
-       ks_assert(bpP);
-       ks_assert(pool);
-       ks_assert(tpool);
-       ks_assert(service);
-
-       bp = ks_pool_alloc(pool, sizeof(*bp));
-       bp->pool = pool;
-       bp->tpool = tpool;
-       bp->service = service;
-       bp->state = BLADE_PEERSTATE_CONNECTING;
-       bp->reason = BLADE_PEERREASON_NORMAL;
-       ks_q_create(&bp->messages_sending, pool, 0);
-       ks_q_create(&bp->messages_receiving, pool, 0);
-       *bpP = bp;
-
-       return KS_STATUS_SUCCESS;
-}
-
-KS_DECLARE(ks_status_t) blade_peer_startup(blade_peer_t *bp, ks_socket_t sock)
-{
-       kws_t *kws = NULL;
-       
-       ks_assert(bp);
-       ks_assert(kws);
-
-       // @todo: consider using a recycle queue for blade_peer_t in blade_service_t, just need to call startup then
-       
-       blade_peer_shutdown(bp);
-       
-       bp->sock = sock;
-       bp->state = BLADE_PEERSTATE_CONNECTING;
-       bp->reason = BLADE_PEERREASON_NORMAL;
-
-    if (ks_thread_create_ex(&bp->kws_thread,
-                                                       blade_peer_kws_thread,
-                                                       bp,
-                                                       KS_THREAD_FLAG_DEFAULT,
-                                                       KS_THREAD_DEFAULT_STACK,
-                                                       KS_PRI_NORMAL,
-                                                       bp->pool) != KS_STATUS_SUCCESS) {
-               // @todo error logging
-               blade_peer_disconnect(bp, BLADE_PEERREASON_ERROR);
-               return KS_STATUS_FAIL;
-       }
-       
-       return KS_STATUS_SUCCESS;
-}
-
-KS_DECLARE(ks_status_t) blade_peer_shutdown(blade_peer_t *bp)
-{
-       blade_message_t *message = NULL;
-       
-       ks_assert(bp);
-
-       bp->shutdown = KS_TRUE;
-       
-       if (bp->kws_thread) {
-               ks_thread_join(bp->kws_thread);
-               ks_pool_free(bp->pool, &bp->kws_thread);
-       }
-
-       while (ks_q_trypop(bp->messages_sending, (void **)&message) == KS_STATUS_SUCCESS && message) blade_message_discard(&message);
-       while (ks_q_trypop(bp->messages_receiving, (void **)&message) == KS_STATUS_SUCCESS && message) blade_message_discard(&message);
-
-       if (bp->kws) kws_destroy(&bp->kws);
-       else if (bp->sock != KS_SOCK_INVALID) ks_socket_close(&bp->sock);
-       bp->sock = KS_SOCK_INVALID;
-       
-       bp->shutdown = KS_FALSE;
-       return KS_STATUS_SUCCESS;
-}
-
-KS_DECLARE(void) blade_peer_disconnect(blade_peer_t *bp, blade_peerreason_t reason)
-{
-       ks_assert(bp);
-
-       // @todo check if already disconnecting for another reason, avoid resetting to get initial reason for disconnect?
-       bp->reason = reason;
-       bp->state = BLADE_PEERSTATE_DISCONNECTING;
-}
-
-KS_DECLARE(blade_peerstate_t) blade_peer_state(blade_peer_t *bp)
-{
-       ks_assert(bp);
-       return bp->state;
-}
-
-KS_DECLARE(ks_status_t) blade_peer_message_pop(blade_peer_t *peer, blade_message_t **message)
-{
-       ks_assert(peer);
-       ks_assert(message);
-
-       *message = NULL;
-       return ks_q_trypop(peer->messages_receiving, (void **)message);
-}
-
-KS_DECLARE(ks_status_t) blade_peer_message_push(blade_peer_t *peer, void *data, ks_size_t data_length)
-{
-       blade_message_t *message = NULL;
-
-       ks_assert(peer);
-       ks_assert(data);
-       ks_assert(data_length > 0);
-       
-       if (blade_handle_message_claim(blade_service_handle(peer->service), &message, data, data_length) != KS_STATUS_SUCCESS || !message) {
-               // @todo error logging
-               blade_peer_disconnect(peer, BLADE_PEERREASON_ERROR);
-               return KS_STATUS_FAIL;
-       }
-       ks_q_push(peer->messages_sending, message);
-       return KS_STATUS_SUCCESS;
-}
-
-void *blade_peer_kws_thread(ks_thread_t *thread, void *data)
-{
-       blade_peer_t *peer = NULL;
-       kws_opcode_t opcode;
-       uint8_t *frame_data = NULL;
-       ks_size_t frame_data_len = 0;
-       blade_message_t *message = NULL;
-       int32_t poll_flags = 0;
-
-       ks_assert(thread);
-       ks_assert(data);
-
-       peer = (blade_peer_t *)data;
-
-       // @todo consider using an INITIALIZING state to track when there is problems during initialization (specifically SSL negotiations)?
-       // @todo should stack be notified with an internal event callback here before logic layer initialization starts (IE, before SSL negotiations)?
-       peer->state = BLADE_PEERSTATE_RUNNING;
-       
-       // @todo: SSL init stuffs based on data from peer->service->config_websockets_ssl to pass into kws_init
-       
-       if (kws_init(&peer->kws, peer->sock, NULL, NULL, KWS_BLOCK, peer->pool) != KS_STATUS_SUCCESS) {
-               // @todo error logging
-               blade_peer_disconnect(peer, BLADE_PEERREASON_ERROR);
-               return NULL;
-       }
-
-       blade_service_peer_state_callback(peer->service, peer, BLADE_PEERSTATE_RUNNING);
-       
-       while (!peer->shutdown) {
-               // @todo get exact timeout from service config?
-               poll_flags = ks_wait_sock(peer->sock, 100, KS_POLL_READ | KS_POLL_ERROR);
-
-               if (poll_flags & KS_POLL_ERROR) {
-                       // @todo error logging
-                       blade_peer_disconnect(peer, BLADE_PEERREASON_ERROR);
-                       break;
-               }
-
-               if (poll_flags & KS_POLL_READ) {
-                       frame_data_len = kws_read_frame(peer->kws, &opcode, &frame_data);
-                       
-                       if (frame_data_len <= 0) {
-                               // @todo error logging, strerror(ks_errno())
-                               // 0 means socket closed with WS_NONE, which closes websocket with no additional reason
-                               // -1 means socket closed with a general failure
-                               // -2 means nonblocking wait
-                               // other values are based on WS_XXX reasons
-                               // negative values are based on reasons, except for -1 is but -2 is nonblocking wait, and
-                       
-                               blade_peer_disconnect(peer, BLADE_PEERREASON_ERROR);
-                               break;
-                       }
-
-                       if (blade_handle_message_claim(blade_service_handle(peer->service), &message, frame_data, frame_data_len) != KS_STATUS_SUCCESS || !message) {
-                               // @todo error logging
-                               blade_peer_disconnect(peer, BLADE_PEERREASON_ERROR);
-                               break;
-                       }
-               
-                       ks_q_push(peer->messages_receiving, message);
-                       blade_service_peer_state_callback(peer->service, peer, BLADE_PEERSTATE_RECEIVING);
-               }
-
-               // @todo consider only sending one message at a time and use shorter polling timeout to prevent any considerable blocking if send buffers get full
-               while (ks_q_trypop(peer->messages_sending, (void **)&message) == KS_STATUS_SUCCESS && message) {
-                       blade_message_get(message, (void **)&frame_data, &frame_data_len);
-                       // @todo may need to get the WSOC_TEXT from the message if using WSOC_BINARY is desired later
-                       kws_write_frame(peer->kws, WSOC_TEXT, frame_data, frame_data_len);
-               }
-       }
-       
-       return NULL;
-}
-       
-/* For Emacs:
- * Local Variables:
- * mode:c
- * indent-tabs-mode:t
- * tab-width:4
- * c-basic-offset:4
- * End:
- * For VIM:
- * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet:
- */
diff --git a/libs/libblade/src/blade_service.c b/libs/libblade/src/blade_service.c
deleted file mode 100644 (file)
index 4eabd66..0000000
+++ /dev/null
@@ -1,428 +0,0 @@
-/*
- * Copyright (c) 2007-2014, Anthony Minessale II
- * All rights reserved.
- * 
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 
- * * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 
- * * Neither the name of the original author; nor the names of any contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- * 
- * 
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER
- * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "blade.h"
-
-#define BLADE_SERVICE_WEBSOCKETS_ENDPOINTS_MULTIHOME_MAX 16
-
-struct blade_service_s {
-       ks_pool_t *pool;
-       ks_thread_pool_t *tpool;
-       blade_handle_t *handle;
-       blade_service_peer_state_callback_t peer_state_callback;
-
-       ks_sockaddr_t config_websockets_endpoints_ipv4[BLADE_SERVICE_WEBSOCKETS_ENDPOINTS_MULTIHOME_MAX];
-       ks_sockaddr_t config_websockets_endpoints_ipv6[BLADE_SERVICE_WEBSOCKETS_ENDPOINTS_MULTIHOME_MAX];
-       int32_t config_websockets_endpoints_ipv4_length;
-       int32_t config_websockets_endpoints_ipv6_length;
-       int32_t config_websockets_endpoints_backlog;
-
-       ks_bool_t shutdown;
-       
-       struct pollfd *listeners_poll;
-       int32_t listeners_size;
-       int32_t listeners_length;
-       ks_thread_t *listeners_thread;
-       
-       list_t connected;
-};
-
-
-void *blade_service_listeners_thread(ks_thread_t *thread, void *data);
-ks_status_t blade_service_listen(blade_service_t *bs, ks_sockaddr_t *addr);
-
-
-KS_DECLARE(ks_status_t) blade_service_destroy(blade_service_t **bsP)
-{
-       blade_service_t *bs = NULL;
-
-       ks_assert(bsP);
-
-       bs = *bsP;
-       *bsP = NULL;
-
-       ks_assert(bs);
-
-       blade_service_shutdown(bs);
-       
-       list_destroy(&bs->connected);
-
-       ks_pool_free(bs->pool, &bs);
-
-       return KS_STATUS_SUCCESS;
-}
-
-KS_DECLARE(ks_status_t) blade_service_create(blade_service_t **bsP,
-                                                                                        ks_pool_t *pool,
-                                                                                        ks_thread_pool_t *tpool,
-                                                                                        blade_handle_t *handle,
-                                                                                        blade_service_peer_state_callback_t peer_state_callback)
-{
-       blade_service_t *bs = NULL;
-
-       ks_assert(bsP);
-       ks_assert(pool);
-       ks_assert(tpool);
-       ks_assert(handle);
-
-       bs = ks_pool_alloc(pool, sizeof(*bs));
-       bs->pool = pool;
-       bs->tpool = tpool;
-       bs->handle = handle;
-       bs->peer_state_callback = peer_state_callback;
-       list_init(&bs->connected);
-       *bsP = bs;
-
-       return KS_STATUS_SUCCESS;
-}
-
-KS_DECLARE(blade_handle_t *) blade_service_handle(blade_service_t *bs)
-{
-       ks_assert(bs);
-       return bs->handle;
-}
-
-ks_status_t blade_service_config(blade_service_t *bs, config_setting_t *config)
-{
-       config_setting_t *websockets = NULL;
-       config_setting_t *websockets_endpoints = NULL;
-       config_setting_t *websockets_endpoints_ipv4 = NULL;
-       config_setting_t *websockets_endpoints_ipv6 = NULL;
-       config_setting_t *websockets_ssl = NULL;
-    config_setting_t *element;
-       config_setting_t *tmp1;
-       config_setting_t *tmp2;
-       ks_sockaddr_t config_websockets_endpoints_ipv4[BLADE_SERVICE_WEBSOCKETS_ENDPOINTS_MULTIHOME_MAX];
-       ks_sockaddr_t config_websockets_endpoints_ipv6[BLADE_SERVICE_WEBSOCKETS_ENDPOINTS_MULTIHOME_MAX];
-       int32_t config_websockets_endpoints_ipv4_length = 0;
-       int32_t config_websockets_endpoints_ipv6_length = 0;
-       int32_t config_websockets_endpoints_backlog = 8;
-
-       ks_assert(bs);
-
-       if (!config) {
-               ks_log(KS_LOG_DEBUG, "!config\n");
-               return KS_STATUS_FAIL;
-       }
-       if (!config_setting_is_group(config)) {
-               ks_log(KS_LOG_DEBUG, "!config_setting_is_group(config)\n");
-               return KS_STATUS_FAIL;
-       }
-
-       websockets = config_setting_get_member(config, "websockets");
-       if (!websockets) {
-               ks_log(KS_LOG_DEBUG, "!websockets\n");
-               return KS_STATUS_FAIL;
-       }
-       websockets_endpoints = config_setting_get_member(websockets, "endpoints");
-       if (!websockets_endpoints) {
-               ks_log(KS_LOG_DEBUG, "!websockets_endpoints\n");
-               return KS_STATUS_FAIL;
-       }
-       websockets_endpoints_ipv4 = config_lookup_from(websockets_endpoints, "ipv4");
-       websockets_endpoints_ipv6 = config_lookup_from(websockets_endpoints, "ipv6");
-       if (websockets_endpoints_ipv4) {
-               if (config_setting_type(websockets_endpoints_ipv4) != CONFIG_TYPE_LIST) return KS_STATUS_FAIL;
-               if ((config_websockets_endpoints_ipv4_length = config_setting_length(websockets_endpoints_ipv4)) > BLADE_SERVICE_WEBSOCKETS_ENDPOINTS_MULTIHOME_MAX)
-                       return KS_STATUS_FAIL;
-               
-               for (int32_t index = 0; index < config_websockets_endpoints_ipv4_length; ++index) {
-                       element = config_setting_get_elem(websockets_endpoints_ipv4, index);
-            tmp1 = config_lookup_from(element, "address");
-            tmp2 = config_lookup_from(element, "port");
-                       if (!tmp1 || !tmp2) return KS_STATUS_FAIL;
-                       if (config_setting_type(tmp1) != CONFIG_TYPE_STRING) return KS_STATUS_FAIL;
-                       if (config_setting_type(tmp2) != CONFIG_TYPE_INT) return KS_STATUS_FAIL;
-                       
-                       if (ks_addr_set(&config_websockets_endpoints_ipv4[index],
-                                                       config_setting_get_string(tmp1),
-                                                       config_setting_get_int(tmp2),
-                                                       AF_INET) != KS_STATUS_SUCCESS) return KS_STATUS_FAIL;
-                       ks_log(KS_LOG_DEBUG,
-                                  "Binding to IPV4 %s on port %d\n",
-                                  ks_addr_get_host(&config_websockets_endpoints_ipv4[index]),
-                                  ks_addr_get_port(&config_websockets_endpoints_ipv4[index]));
-               }
-       }
-       if (websockets_endpoints_ipv6) {
-               if (config_setting_type(websockets_endpoints_ipv6) != CONFIG_TYPE_LIST) return KS_STATUS_FAIL;
-               if ((config_websockets_endpoints_ipv6_length = config_setting_length(websockets_endpoints_ipv6)) > BLADE_SERVICE_WEBSOCKETS_ENDPOINTS_MULTIHOME_MAX)
-                       return KS_STATUS_FAIL;
-               
-               for (int32_t index = 0; index < config_websockets_endpoints_ipv6_length; ++index) {
-                       element = config_setting_get_elem(websockets_endpoints_ipv6, index);
-            tmp1 = config_lookup_from(element, "address");
-            tmp2 = config_lookup_from(element, "port");
-                       if (!tmp1 || !tmp2) return KS_STATUS_FAIL;
-                       if (config_setting_type(tmp1) != CONFIG_TYPE_STRING) return KS_STATUS_FAIL;
-                       if (config_setting_type(tmp2) != CONFIG_TYPE_INT) return KS_STATUS_FAIL;
-                       
-                       if (ks_addr_set(&config_websockets_endpoints_ipv6[index],
-                                                       config_setting_get_string(tmp1),
-                                                       config_setting_get_int(tmp2),
-                                                       AF_INET6) != KS_STATUS_SUCCESS) return KS_STATUS_FAIL;
-                       ks_log(KS_LOG_DEBUG,
-                                  "Binding to IPV6 %s on port %d\n",
-                                  ks_addr_get_host(&config_websockets_endpoints_ipv6[index]),
-                                  ks_addr_get_port(&config_websockets_endpoints_ipv6[index]));
-               }
-       }
-       if (config_websockets_endpoints_ipv4_length + config_websockets_endpoints_ipv6_length <= 0) return KS_STATUS_FAIL;
-       tmp1 = config_lookup_from(websockets_endpoints, "backlog");
-       if (tmp1) {
-               if (config_setting_type(tmp1) != CONFIG_TYPE_INT) return KS_STATUS_FAIL;
-               config_websockets_endpoints_backlog = config_setting_get_int(tmp1);
-       }
-       websockets_ssl = config_setting_get_member(websockets, "ssl");
-       if (websockets_ssl) {
-               // @todo: SSL stuffs from websockets_ssl into config_websockets_ssl envelope
-       }
-
-
-       // Configuration is valid, now assign it to the variables that are used
-       // If the configuration was invalid, then this does not get changed from the current config when reloading a new config
-       for (int32_t index = 0; index < config_websockets_endpoints_ipv4_length; ++index)
-               bs->config_websockets_endpoints_ipv4[index] = config_websockets_endpoints_ipv4[index];
-       for (int32_t index = 0; index < config_websockets_endpoints_ipv6_length; ++index)
-               bs->config_websockets_endpoints_ipv6[index] = config_websockets_endpoints_ipv6[index];
-       bs->config_websockets_endpoints_ipv4_length = config_websockets_endpoints_ipv4_length;
-       bs->config_websockets_endpoints_ipv6_length = config_websockets_endpoints_ipv6_length;
-       bs->config_websockets_endpoints_backlog = config_websockets_endpoints_backlog;
-       //bs->config_websockets_ssl = config_websockets_ssl;
-
-       return KS_STATUS_SUCCESS;
-}
-
-KS_DECLARE(ks_status_t) blade_service_startup(blade_service_t *bs, config_setting_t *config)
-{
-       ks_assert(bs);
-
-       blade_service_shutdown(bs);
-
-       // @todo: If the configuration is invalid, and this is a case of reloading a new config, then the service shutdown shouldn't occur
-       // but the service may use configuration that changes before we shutdown if it is read successfully, may require a config reader/writer mutex?
-       
-    if (blade_service_config(bs, config) != KS_STATUS_SUCCESS) {
-               ks_log(KS_LOG_DEBUG, "blade_service_config failed\n");
-               return KS_STATUS_FAIL;
-       }
-
-       for (int32_t index = 0; index < bs->config_websockets_endpoints_ipv4_length; ++index) {
-               if (blade_service_listen(bs, &bs->config_websockets_endpoints_ipv4[index]) != KS_STATUS_SUCCESS) {
-                       ks_log(KS_LOG_DEBUG, "blade_service_listen (v4) failed\n");
-                       return KS_STATUS_FAIL;
-               }
-       }
-       for (int32_t index = 0; index < bs->config_websockets_endpoints_ipv6_length; ++index) {
-               if (blade_service_listen(bs, &bs->config_websockets_endpoints_ipv6[index]) != KS_STATUS_SUCCESS) {
-                       ks_log(KS_LOG_DEBUG, "blade_service_listen (v6) failed\n");
-                       return KS_STATUS_FAIL;
-               }
-       }
-
-       if (ks_thread_create_ex(&bs->listeners_thread,
-                                                       blade_service_listeners_thread,
-                                                       bs,
-                                                       KS_THREAD_FLAG_DEFAULT,
-                                                       KS_THREAD_DEFAULT_STACK,
-                                                       KS_PRI_NORMAL,
-                                                       bs->pool) != KS_STATUS_SUCCESS) return KS_STATUS_FAIL;
-       
-       return KS_STATUS_SUCCESS;
-}
-
-KS_DECLARE(ks_status_t) blade_service_shutdown(blade_service_t *bs)
-{
-       ks_assert(bs);
-
-       // @todo 1 more callback for blade_service_state_callback_t? providing event up the stack on service startup, shutdown, and service errors?
-       
-       bs->shutdown = KS_TRUE;
-       
-       if (bs->listeners_thread) {
-               ks_thread_join(bs->listeners_thread);
-               ks_pool_free(bs->pool, &bs->listeners_thread);
-       }
-
-       for (int32_t index = 0; index < bs->listeners_length; ++index) {
-               ks_socket_t sock = bs->listeners_poll[index].fd;
-               ks_socket_shutdown(sock, SHUT_RDWR);
-               ks_socket_close(&sock);
-       }
-       bs->listeners_length = 0;
-
-       list_iterator_start(&bs->connected);
-       while (list_iterator_hasnext(&bs->connected)) {
-               blade_peer_t *peer = (blade_peer_t *)list_iterator_next(&bs->connected);
-               blade_peer_destroy(&peer); // @todo determine if NOT receiving the DISCONNECTING event callback for these will matter, as service is being shutdown
-       }
-       list_iterator_stop(&bs->connected);
-       list_clear(&bs->connected);
-
-       bs->shutdown = KS_FALSE;
-       return KS_STATUS_SUCCESS;
-}
-
-KS_DECLARE(void) blade_service_peer_state_callback(blade_service_t *bs, blade_peer_t *bp, blade_peerstate_t state)
-{
-       ks_assert(bs);
-       ks_assert(bp);
-
-       if (bs->peer_state_callback) bs->peer_state_callback(bs, bp, state);
-}
-
-ks_status_t blade_service_listen(blade_service_t *bs, ks_sockaddr_t *addr)
-{
-       ks_socket_t listener = KS_SOCK_INVALID;
-       int32_t listener_index = -1;
-       ks_status_t ret = KS_STATUS_SUCCESS;
-       
-       ks_assert(bs);
-       ks_assert(addr);
-
-       if ((listener = socket(addr->family, SOCK_STREAM, IPPROTO_TCP)) == KS_SOCK_INVALID) {
-               ks_log(KS_LOG_DEBUG, "listener == KS_SOCK_INVALID\n");
-               ret = KS_STATUS_FAIL;
-               goto done;
-       }
-
-       ks_socket_option(listener, SO_REUSEADDR, KS_TRUE);
-       ks_socket_option(listener, TCP_NODELAY, KS_TRUE);
-       if (addr->family == AF_INET6) ks_socket_option(listener, IPV6_V6ONLY, KS_TRUE);
-
-       if (ks_addr_bind(listener, addr) != KS_STATUS_SUCCESS) {
-               ks_log(KS_LOG_DEBUG, "ks_addr_bind(listener, addr) != KS_STATUS_SUCCESS\n");
-               ret = KS_STATUS_FAIL;
-               goto done;
-       }
-
-       if (listen(listener, bs->config_websockets_endpoints_backlog) != 0) {
-               ks_log(KS_LOG_DEBUG, "listen(listener, backlog) != 0\n");
-               ret = KS_STATUS_FAIL;
-               goto done;
-       }
-
-       listener_index = bs->listeners_length++;
-       if (bs->listeners_length > bs->listeners_size) {
-               bs->listeners_size = bs->listeners_length;
-               bs->listeners_poll = (struct pollfd *)ks_pool_resize(bs->pool, bs->listeners_poll, sizeof(struct pollfd) * bs->listeners_size);
-               ks_assert(bs->listeners_poll);
-       }
-       bs->listeners_poll[listener_index].fd = listener;
-       bs->listeners_poll[listener_index].events = POLLIN | POLLERR;
-
- done:
-       if (ret != KS_STATUS_SUCCESS) {
-               if (listener != KS_SOCK_INVALID) {
-                       ks_socket_shutdown(listener, SHUT_RDWR);
-                       ks_socket_close(&listener);
-               }
-       }
-       return ret;
-}
-
-void *blade_service_listeners_thread(ks_thread_t *thread, void *data)
-{
-       blade_service_t *service = NULL;
-
-       ks_assert(thread);
-       ks_assert(data);
-
-       service = (blade_service_t *)data;
-
-       ks_log(KS_LOG_DEBUG, "Service running\n");
-       
-       // @todo 1 more callback for blade_service_state_callback_t? providing event up the stack on service startup, shutdown, and service errors?
-       
-       while (!service->shutdown) {
-               // @todo take exact timeout from a setting in config_service_endpoints
-               if (ks_poll(service->listeners_poll, service->listeners_length, 100) > 0) {
-                       for (int32_t index = 0; index < service->listeners_length; ++index) {
-                               ks_socket_t sock = KS_SOCK_INVALID;
-                               blade_peer_t *peer = NULL;
-
-                               if (!(service->listeners_poll[index].revents & POLLIN)) continue;
-                               if (service->listeners_poll[index].revents & POLLERR) {
-                                       // @todo: error handling, just skip the listener for now, it might recover, could skip X sanity times before closing?
-                                       continue;
-                               }
-
-                               if ((sock = accept(service->listeners_poll[index].fd, NULL, NULL)) == KS_SOCK_INVALID) {
-                                       // @todo: error handling, just skip the socket for now as most causes are because the remote side suddenly became unreachable
-                                       continue;
-                               }
-
-                               // @todo consider a recycle queue of peers per service, and only have to call startup when one is already available
-                               // blade_service_peer_claim(service, &peer);
-                               blade_peer_create(&peer, service->pool, service->tpool, service);
-                               ks_assert(peer);
-
-                               // @todo call state callback with connecting enum state
-                               blade_service_peer_state_callback(service, peer, BLADE_PEERSTATE_CONNECTING);
-                               
-                               blade_peer_startup(peer, sock);
-                               
-                               list_append(&service->connected, peer);
-                       }
-               }
-
-               list_iterator_start(&service->connected);
-               while (list_iterator_hasnext(&service->connected)) {
-                       blade_peer_t *peer = (blade_peer_t *)list_iterator_next(&service->connected);
-                       // @todo expose accessor for disconnecting, after changing it into the state callback enum
-                       // ensure that every way kws_close might occur leads back to disconnecting = KS_TRUE for this to universally process disconnects
-                       if (blade_peer_state(peer) == BLADE_PEERSTATE_DISCONNECTING) {
-                               // @todo check if there is an iterator based remove function, or indexed iteration to use list_delete_at()
-                               list_delete(&service->connected, peer);
-                               blade_service_peer_state_callback(service, peer, BLADE_PEERSTATE_DISCONNECTING);
-
-                               // @todo switch to blade_peer_shutdown(&peer) and blade_peer_discard(&peer) after introducing recycling of peers
-                               blade_peer_destroy(&peer);
-                       }
-               }
-               list_iterator_stop(&service->connected);
-       }
-       
-       return NULL;
-}
-
-/* For Emacs:
- * Local Variables:
- * mode:c
- * indent-tabs-mode:t
- * tab-width:4
- * c-basic-offset:4
- * End:
- * For VIM:
- * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet:
- */
index 8504af02c4e52846957e74ecf26ce0be06fc56c4..aeac8682db6179b2c83adb15e76a96c248fc5854 100644 (file)
@@ -48,7 +48,6 @@ struct blade_handle_s {
        config_setting_t *config_datastore;
 
        ks_q_t *messages_discarded;
-       blade_service_t *service;
 
        blade_datastore_t *datastore;
 };
@@ -143,7 +142,7 @@ ks_status_t blade_handle_config(blade_handle_t *bh, config_setting_t *config)
        return KS_STATUS_SUCCESS;
 }
 
-KS_DECLARE(ks_status_t) blade_handle_startup(blade_handle_t *bh, config_setting_t *config, blade_service_peer_state_callback_t service_peer_state_callback)
+KS_DECLARE(ks_status_t) blade_handle_startup(blade_handle_t *bh, config_setting_t *config)
 {
        ks_assert(bh);
 
@@ -152,15 +151,6 @@ KS_DECLARE(ks_status_t) blade_handle_startup(blade_handle_t *bh, config_setting_
                return KS_STATUS_FAIL;
        }
 
-       if (bh->config_service && !blade_handle_service_available(bh)) {
-               blade_service_create(&bh->service, bh->pool, bh->tpool, bh, service_peer_state_callback);
-               ks_assert(bh->service);
-               if (blade_service_startup(bh->service, bh->config_service) != KS_STATUS_SUCCESS) {
-                       ks_log(KS_LOG_DEBUG, "blade_service_startup failed\n");
-                       return KS_STATUS_FAIL;
-               }
-       }
-       
        if (bh->config_datastore && !blade_handle_datastore_available(bh)) {
                blade_datastore_create(&bh->datastore, bh->pool, bh->tpool);
                ks_assert(bh->datastore);
@@ -177,13 +167,23 @@ KS_DECLARE(ks_status_t) blade_handle_shutdown(blade_handle_t *bh)
 {
        ks_assert(bh);
 
-       if (blade_handle_service_available(bh)) blade_service_destroy(&bh->service);
-       
        if (blade_handle_datastore_available(bh)) blade_datastore_destroy(&bh->datastore);
        
        return KS_STATUS_SUCCESS;
 }
 
+KS_DECLARE(ks_pool_t *) blade_handle_pool_get(blade_handle_t *bh)
+{
+       ks_assert(bh);
+       return bh->pool;
+}
+
+KS_DECLARE(ks_thread_pool_t *) blade_handle_tpool_get(blade_handle_t *bh)
+{
+       ks_assert(bh);
+       return bh->tpool;
+}
+
 KS_DECLARE(ks_status_t) blade_handle_message_claim(blade_handle_t *bh, blade_message_t **message, void *data, ks_size_t data_length)
 {
        blade_message_t *msg = NULL;
@@ -218,12 +218,7 @@ KS_DECLARE(ks_status_t) blade_handle_message_discard(blade_handle_t *bh, blade_m
        return KS_STATUS_SUCCESS;
 }
 
-KS_DECLARE(ks_bool_t) blade_handle_service_available(blade_handle_t *bh)
-{
-       ks_assert(bh);
 
-       return bh->service != NULL;
-}
 
 KS_DECLARE(ks_bool_t) blade_handle_datastore_available(blade_handle_t *bh)
 {
index f8a3a4459f076bf06d9aadcb6172aa9d229794d9..d7a6a7cac179c9db898874eea38fa1fc9b3ca3ab 100644 (file)
 #include "unqlite.h"
 #include "blade_types.h"
 #include "blade_stack.h"
-#include "blade_peer.h"
-#include "blade_service.h"
 #include "blade_message.h"
 #include "blade_datastore.h"
 #include "bpcp.h"
 
+#include "blade_identity.h"
+#include "blade_module.h"
+#include "blade_connection.h"
+
 KS_BEGIN_EXTERN_C
 
 KS_DECLARE(ks_status_t) blade_init(void);
diff --git a/libs/libblade/src/include/blade_connection.h b/libs/libblade/src/include/blade_connection.h
new file mode 100644 (file)
index 0000000..d48ec8c
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2017, Shane Bryldt
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 
+ * * Neither the name of the original author; nor the names of any contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ * 
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _BLADE_CONNECTION_H_
+#define _BLADE_CONNECTION_H_
+#include <blade.h>
+
+KS_BEGIN_EXTERN_C
+KS_DECLARE(ks_status_t) blade_connection_create(blade_connection_t **bcP,
+                                                                                               blade_handle_t *bh,
+                                                                                               void *transport_data,
+                                                                                               blade_transport_callbacks_t *transport_callbacks);
+KS_DECLARE(ks_status_t) blade_connection_destroy(blade_connection_t **bcP);
+KS_DECLARE(ks_status_t) blade_connection_startup(blade_connection_t *bc);
+KS_DECLARE(ks_status_t) blade_connection_shutdown(blade_connection_t *bc);
+KS_DECLARE(void *) blade_connection_transport_get(blade_connection_t *bc);
+KS_DECLARE(void) blade_connection_state_set(blade_connection_t *bc, blade_connection_state_t state);
+KS_DECLARE(void) blade_connection_disconnect(blade_connection_t *bc);
+KS_DECLARE(blade_connection_rank_t) blade_connection_rank(blade_connection_t *bc, blade_identity_t *target);
+KS_DECLARE(ks_status_t) blade_connection_sending_push(blade_connection_t *bc, blade_identity_t *target, cJSON *json);
+KS_DECLARE(ks_status_t) blade_connection_sending_pop(blade_connection_t *bc, blade_identity_t **target, cJSON **json);
+KS_DECLARE(ks_status_t) blade_connection_receiving_push(blade_connection_t *bc, cJSON *json);
+KS_DECLARE(ks_status_t) blade_connection_receiving_pop(blade_connection_t *bc, cJSON **json);
+KS_END_EXTERN_C
+
+#endif
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet:
+ */
similarity index 70%
rename from libs/libblade/src/include/blade_service.h
rename to libs/libblade/src/include/blade_identity.h
index a5fa890b48fb163c72f0d0de9e0b9fc1ccc0838e..41d0341b06c29aa4c6708120b411a36d6078ba17 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2007-2014, Anthony Minessale II
+ * Copyright (c) 2017, Shane Bryldt
  * All rights reserved.
  * 
  * Redistribution and use in source and binary forms, with or without
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-#ifndef _BLADE_SERVICE_H_
-#define _BLADE_SERVICE_H_
+#ifndef _BLADE_IDENTITY_H_
+#define _BLADE_IDENTITY_H_
 #include <blade.h>
 
 KS_BEGIN_EXTERN_C
-KS_DECLARE(ks_status_t) blade_service_create(blade_service_t **bsP,
-                                                                                        ks_pool_t *pool,
-                                                                                        ks_thread_pool_t *tpool,
-                                                                                        blade_handle_t *handle,
-                                                                                        blade_service_peer_state_callback_t peer_state_callback);
-KS_DECLARE(ks_status_t) blade_service_destroy(blade_service_t **bsP);
-KS_DECLARE(blade_handle_t *) blade_service_handle(blade_service_t *bs);
-KS_DECLARE(ks_status_t) blade_service_startup(blade_service_t *bs, config_setting_t *config);
-KS_DECLARE(ks_status_t) blade_service_shutdown(blade_service_t *bs);
-KS_DECLARE(void) blade_service_peer_state_callback(blade_service_t *bs, blade_peer_t *bp, blade_peerstate_t state);
+KS_DECLARE(ks_status_t) blade_identity_create(blade_identity_t **biP, ks_pool_t *pool);
+KS_DECLARE(ks_status_t) blade_identity_destroy(blade_identity_t **biP);
+KS_DECLARE(ks_status_t) blade_identity_parse(blade_identity_t *bi, const char *uri);
+KS_DECLARE(ks_status_t) blade_identity_uri(blade_identity_t *bi, const char **uri);
 KS_END_EXTERN_C
 
 #endif
similarity index 67%
rename from libs/libblade/src/include/blade_peer.h
rename to libs/libblade/src/include/blade_module.h
index a5cf304b46324f854fed7eb5590469e73d4cbd38..ef2ba88de78dab428802eec9dfe6af30998e23ac 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2007-2014, Anthony Minessale II
+ * Copyright (c) 2017, Shane Bryldt
  * All rights reserved.
  * 
  * Redistribution and use in source and binary forms, with or without
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-#ifndef _BLADE_PEER_H_
-#define _BLADE_PEER_H_
+#ifndef _BLADE_MODULE_H_
+#define _BLADE_MODULE_H_
 #include <blade.h>
 
 KS_BEGIN_EXTERN_C
-KS_DECLARE(ks_status_t) blade_peer_create(blade_peer_t **bpP, ks_pool_t *pool, ks_thread_pool_t *tpool, blade_service_t *service);
-KS_DECLARE(ks_status_t) blade_peer_destroy(blade_peer_t **bpP);
-KS_DECLARE(ks_status_t) blade_peer_startup(blade_peer_t *bp, ks_socket_t sock);
-KS_DECLARE(ks_status_t) blade_peer_shutdown(blade_peer_t *bp);
-KS_DECLARE(void) blade_peer_disconnect(blade_peer_t *bp, blade_peerreason_t reason);
-KS_DECLARE(blade_peerstate_t) blade_peer_state(blade_peer_t *bp);
-KS_DECLARE(blade_peerreason_t) blade_peer_reason(blade_peer_t *bp);
-KS_DECLARE(ks_status_t) blade_peer_message_pop(blade_peer_t *peer, blade_message_t **message);
-KS_DECLARE(ks_status_t) blade_peer_message_push(blade_peer_t *peer, void *data, ks_size_t data_length);
+KS_DECLARE(ks_status_t) blade_module_create(blade_module_t **bmP, blade_handle_t *bh, void *module_data, blade_module_callbacks_t *module_callbacks);
+KS_DECLARE(ks_status_t) blade_module_destroy(blade_module_t **bmP);
+KS_DECLARE(void *) blade_module_data_get(blade_module_t *bm);
 KS_END_EXTERN_C
 
 #endif
index ff44f230e97a9ee7ad877c4a1aa04e37c4f131a0..04daa932d64876b3a62d1c4aa058e53a2f6c4e8a 100644 (file)
 KS_BEGIN_EXTERN_C
 KS_DECLARE(ks_status_t) blade_handle_destroy(blade_handle_t **bhP);
 KS_DECLARE(ks_status_t) blade_handle_create(blade_handle_t **bhP, ks_pool_t *pool, ks_thread_pool_t *tpool);
-KS_DECLARE(ks_status_t) blade_handle_startup(blade_handle_t *bh, config_setting_t *config, blade_service_peer_state_callback_t service_peer_state_callback);
+KS_DECLARE(ks_status_t) blade_handle_startup(blade_handle_t *bh, config_setting_t *config);
 KS_DECLARE(ks_status_t) blade_handle_shutdown(blade_handle_t *bh);
+KS_DECLARE(ks_pool_t *) blade_handle_pool_get(blade_handle_t *bh);
+KS_DECLARE(ks_thread_pool_t *) blade_handle_tpool_get(blade_handle_t *bh);
 
 KS_DECLARE(ks_status_t) blade_handle_message_claim(blade_handle_t *bh, blade_message_t **message, void *data, ks_size_t data_length);
 KS_DECLARE(ks_status_t) blade_handle_message_discard(blade_handle_t *bh, blade_message_t **message);
 
-KS_DECLARE(ks_bool_t) blade_handle_service_available(blade_handle_t *bh);
-
 KS_DECLARE(ks_bool_t) blade_handle_datastore_available(blade_handle_t *bh);
 KS_DECLARE(ks_status_t) blade_handle_datastore_store(blade_handle_t *bh, const void *key, int32_t key_length, const void *data, int64_t data_length);
 KS_DECLARE(ks_status_t) blade_handle_datastore_fetch(blade_handle_t *bh,
index b534fde6fdbefe894b840496e6ad1ba0ecf257df..cc2c05419709bd818b75e82f556d2b7d9bc2fbaa 100644 (file)
 
 KS_BEGIN_EXTERN_C
 
-typedef enum {
-       BLADE_PEERSTATE_CONNECTING,
-       BLADE_PEERSTATE_DISCONNECTING,
-       BLADE_PEERSTATE_RUNNING,
-       BLADE_PEERSTATE_RECEIVING,
-} blade_peerstate_t;
-
-typedef enum {
-       BLADE_PEERREASON_NORMAL,
-       BLADE_PEERREASON_ERROR,
-       // @todo populate more reasons for disconnecting as neccessary
-} blade_peerreason_t;
-
 typedef struct blade_handle_s blade_handle_t;
-typedef struct blade_peer_s blade_peer_t;
-typedef struct blade_service_s blade_service_t;
+typedef struct blade_identity_s blade_identity_t;
+typedef struct blade_module_s blade_module_t;
+typedef struct blade_module_callbacks_s blade_module_callbacks_t;
+typedef struct blade_transport_callbacks_s blade_transport_callbacks_t;
+typedef struct blade_connection_s blade_connection_t;
+
 typedef struct blade_message_s blade_message_t;
 typedef struct blade_datastore_s blade_datastore_t;
 
-typedef void (*blade_service_peer_state_callback_t)(blade_service_t *bs, blade_peer_t *bp, blade_peerstate_t state);
 typedef ks_bool_t (*blade_datastore_fetch_callback_t)(blade_datastore_t *bds, const void *data, uint32_t data_length, void *userdata);
 
+
+
+typedef enum {
+       BLADE_CONNECTION_STATE_NONE,
+       BLADE_CONNECTION_STATE_DISCONNECT,
+       BLADE_CONNECTION_STATE_NEW,
+       BLADE_CONNECTION_STATE_CONNECT,
+       BLADE_CONNECTION_STATE_ATTACH,
+       BLADE_CONNECTION_STATE_DETACH,
+       BLADE_CONNECTION_STATE_READY,
+} blade_connection_state_t;
+
+typedef enum {
+       BLADE_CONNECTION_DIRECTION_IN,
+       BLADE_CONNECTION_DIRECTION_OUT,
+} blade_connection_direction_t;
+
+typedef enum {
+       BLADE_CONNECTION_STATE_CONDITION_PRE,
+       BLADE_CONNECTION_STATE_CONDITION_POST,
+} blade_connection_state_condition_t;
+
+typedef enum {
+       BLADE_CONNECTION_STATE_HOOK_SUCCESS,
+       BLADE_CONNECTION_STATE_HOOK_DISCONNECT,
+       BLADE_CONNECTION_STATE_HOOK_BYPASS,
+} blade_connection_state_hook_t;
+
+typedef enum {
+       BLADE_CONNECTION_RANK_POOR,
+       BLADE_CONNECTION_RANK_AVERAGE,
+       BLADE_CONNECTION_RANK_GOOD,
+       BLADE_CONNECTION_RANK_GREAT,
+} blade_connection_rank_t;
+
+typedef ks_status_t (*blade_module_load_callback_t)(blade_module_t **bmP, blade_handle_t *bh);
+typedef ks_status_t (*blade_module_unload_callback_t)(blade_module_t *bm);
+typedef ks_status_t (*blade_module_startup_callback_t)(blade_module_t *bm, config_setting_t *config);
+typedef ks_status_t (*blade_module_shutdown_callback_t)(blade_module_t *bm);
+
+struct blade_module_callbacks_s {
+       blade_module_load_callback_t onload;
+       blade_module_unload_callback_t onunload;
+       blade_module_startup_callback_t onstartup;
+       blade_module_shutdown_callback_t onshutdown;
+};
+
+
+typedef ks_status_t (*blade_transport_connect_callback_t)(blade_connection_t **bcP, blade_module_t *bm, blade_identity_t *target);
+typedef blade_connection_rank_t (*blade_transport_rank_callback_t)(blade_connection_t *bc, blade_identity_t *target);
+typedef blade_connection_state_hook_t (*blade_transport_state_callback_t)(blade_connection_t *bc,
+                                                                                                                                                 blade_connection_state_t state,
+                                                                                                                                                 blade_connection_state_condition_t condition);
+
+struct blade_transport_callbacks_s {
+       blade_transport_connect_callback_t onconnect;
+       blade_transport_rank_callback_t onrank;
+       blade_transport_state_callback_t onstate;
+};
+
+
 KS_END_EXTERN_C
 
 #endif
diff --git a/libs/libblade/test/bladec b/libs/libblade/test/bladec
deleted file mode 100755 (executable)
index 805d650..0000000
+++ /dev/null
@@ -1,228 +0,0 @@
-#! /bin/bash
-
-# bladec - temporary wrapper script for .libs/bladec
-# Generated by libtool (GNU libtool) 2.4.2 Debian-2.4.2-1.11
-#
-# The bladec program cannot be directly executed until all the libtool
-# libraries that it depends on are installed.
-#
-# This wrapper script should never be moved out of the build directory.
-# If it is, it will not operate correctly.
-
-# Sed substitution that helps us do robust quoting.  It backslashifies
-# metacharacters that are still active within double-quoted strings.
-sed_quote_subst='s/\([`"$\\]\)/\\\1/g'
-
-# Be Bourne compatible
-if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then
-  emulate sh
-  NULLCMD=:
-  # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which
-  # is contrary to our usage.  Disable this feature.
-  alias -g '${1+"$@"}'='"$@"'
-  setopt NO_GLOB_SUBST
-else
-  case `(set -o) 2>/dev/null` in *posix*) set -o posix;; esac
-fi
-BIN_SH=xpg4; export BIN_SH # for Tru64
-DUALCASE=1; export DUALCASE # for MKS sh
-
-# The HP-UX ksh and POSIX shell print the target directory to stdout
-# if CDPATH is set.
-(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
-
-relink_command="(cd /usr/src/freeswitch/libs/libblade/test; { test -z \"\${LIBRARY_PATH+set}\" || unset LIBRARY_PATH || { LIBRARY_PATH=; export LIBRARY_PATH; }; }; { test -z \"\${COMPILER_PATH+set}\" || unset COMPILER_PATH || { COMPILER_PATH=; export COMPILER_PATH; }; }; { test -z \"\${GCC_EXEC_PREFIX+set}\" || unset GCC_EXEC_PREFIX || { GCC_EXEC_PREFIX=; export GCC_EXEC_PREFIX; }; }; { test -z \"\${LD_RUN_PATH+set}\" || unset LD_RUN_PATH || { LD_RUN_PATH=; export LD_RUN_PATH; }; }; { test -z \"\${LD_LIBRARY_PATH+set}\" || unset LD_LIBRARY_PATH || { LD_LIBRARY_PATH=; export LD_LIBRARY_PATH; }; }; PATH=/usr/lib/ccache:/usr/lib/ccache:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/opt/bin:/usr/local/bin:/usr/local/sbin:/usr/local/freeswitch/bin:/opt/bin:/usr/local/bin:/usr/local/sbin:/usr/local/freeswitch/bin; export PATH; gcc -fPIC -Wall -std=c99 -pedantic -DUSE_SCHED_SETSCHEDULER=1 -DKS_API_VISIBILITY=1 -fvisibility=hidden -Werror -DHAVE_PTHREAD_SETSCHEDPARAM=1 -DHAVE_OPENSSL -fsanitize=address -fno-omit-frame-pointer -I/usr/src/freeswitch/libs/libblade/src/include -g -ggdb -O0 -g -O2 -fsanitize=address -o \$progdir/\$file bladec-bladec.o bladec-tap.o  -L/usr/src/freeswitch/libs/libblade/../libks/.libs/ /usr/src/freeswitch/libs/libblade/../libks/.libs//libks.so -lsodium /usr/src/freeswitch/libs/libblade/.libs/libblade.so -lconfig -lm -lpthread -lssl -lcrypto -Wl,-rpath -Wl,/usr/src/freeswitch/libs/libblade/../libks/.libs/ -Wl,-rpath -Wl,/usr/src/freeswitch/libs/libblade/.libs)"
-
-# This environment variable determines our operation mode.
-if test "$libtool_install_magic" = "%%%MAGIC variable%%%"; then
-  # install mode needs the following variables:
-  generated_by_libtool_version='2.4.2'
-  notinst_deplibs=' /usr/src/freeswitch/libs/libblade/../libks/.libs//libks.la /usr/src/freeswitch/libs/libblade/libblade.la'
-else
-  # When we are sourced in execute mode, $file and $ECHO are already set.
-  if test "$libtool_execute_magic" != "%%%MAGIC variable%%%"; then
-    file="$0"
-
-# A function that is used when there is no print builtin or printf.
-func_fallback_echo ()
-{
-  eval 'cat <<_LTECHO_EOF
-$1
-_LTECHO_EOF'
-}
-    ECHO="printf %s\\n"
-  fi
-
-# Very basic option parsing. These options are (a) specific to
-# the libtool wrapper, (b) are identical between the wrapper
-# /script/ and the wrapper /executable/ which is used only on
-# windows platforms, and (c) all begin with the string --lt-
-# (application programs are unlikely to have options which match
-# this pattern).
-#
-# There are only two supported options: --lt-debug and
-# --lt-dump-script. There is, deliberately, no --lt-help.
-#
-# The first argument to this parsing function should be the
-# script's ../libtool value, followed by no.
-lt_option_debug=
-func_parse_lt_options ()
-{
-  lt_script_arg0=$0
-  shift
-  for lt_opt
-  do
-    case "$lt_opt" in
-    --lt-debug) lt_option_debug=1 ;;
-    --lt-dump-script)
-        lt_dump_D=`$ECHO "X$lt_script_arg0" | /bin/sed -e 's/^X//' -e 's%/[^/]*$%%'`
-        test "X$lt_dump_D" = "X$lt_script_arg0" && lt_dump_D=.
-        lt_dump_F=`$ECHO "X$lt_script_arg0" | /bin/sed -e 's/^X//' -e 's%^.*/%%'`
-        cat "$lt_dump_D/$lt_dump_F"
-        exit 0
-      ;;
-    --lt-*)
-        $ECHO "Unrecognized --lt- option: '$lt_opt'" 1>&2
-        exit 1
-      ;;
-    esac
-  done
-
-  # Print the debug banner immediately:
-  if test -n "$lt_option_debug"; then
-    echo "bladec:bladec:${LINENO}: libtool wrapper (GNU libtool) 2.4.2 Debian-2.4.2-1.11" 1>&2
-  fi
-}
-
-# Used when --lt-debug. Prints its arguments to stdout
-# (redirection is the responsibility of the caller)
-func_lt_dump_args ()
-{
-  lt_dump_args_N=1;
-  for lt_arg
-  do
-    $ECHO "bladec:bladec:${LINENO}: newargv[$lt_dump_args_N]: $lt_arg"
-    lt_dump_args_N=`expr $lt_dump_args_N + 1`
-  done
-}
-
-# Core function for launching the target application
-func_exec_program_core ()
-{
-
-      if test -n "$lt_option_debug"; then
-        $ECHO "bladec:bladec:${LINENO}: newargv[0]: $progdir/$program" 1>&2
-        func_lt_dump_args ${1+"$@"} 1>&2
-      fi
-      exec "$progdir/$program" ${1+"$@"}
-
-      $ECHO "$0: cannot exec $program $*" 1>&2
-      exit 1
-}
-
-# A function to encapsulate launching the target application
-# Strips options in the --lt-* namespace from $@ and
-# launches target application with the remaining arguments.
-func_exec_program ()
-{
-  case " $* " in
-  *\ --lt-*)
-    for lt_wr_arg
-    do
-      case $lt_wr_arg in
-      --lt-*) ;;
-      *) set x "$@" "$lt_wr_arg"; shift;;
-      esac
-      shift
-    done ;;
-  esac
-  func_exec_program_core ${1+"$@"}
-}
-
-  # Parse options
-  func_parse_lt_options "$0" ${1+"$@"}
-
-  # Find the directory that this script lives in.
-  thisdir=`$ECHO "$file" | /bin/sed 's%/[^/]*$%%'`
-  test "x$thisdir" = "x$file" && thisdir=.
-
-  # Follow symbolic links until we get to the real thisdir.
-  file=`ls -ld "$file" | /bin/sed -n 's/.*-> //p'`
-  while test -n "$file"; do
-    destdir=`$ECHO "$file" | /bin/sed 's%/[^/]*$%%'`
-
-    # If there was a directory component, then change thisdir.
-    if test "x$destdir" != "x$file"; then
-      case "$destdir" in
-      [\\/]* | [A-Za-z]:[\\/]*) thisdir="$destdir" ;;
-      *) thisdir="$thisdir/$destdir" ;;
-      esac
-    fi
-
-    file=`$ECHO "$file" | /bin/sed 's%^.*/%%'`
-    file=`ls -ld "$thisdir/$file" | /bin/sed -n 's/.*-> //p'`
-  done
-
-  # Usually 'no', except on cygwin/mingw when embedded into
-  # the cwrapper.
-  WRAPPER_SCRIPT_BELONGS_IN_OBJDIR=no
-  if test "$WRAPPER_SCRIPT_BELONGS_IN_OBJDIR" = "yes"; then
-    # special case for '.'
-    if test "$thisdir" = "."; then
-      thisdir=`pwd`
-    fi
-    # remove .libs from thisdir
-    case "$thisdir" in
-    *[\\/].libs ) thisdir=`$ECHO "$thisdir" | /bin/sed 's%[\\/][^\\/]*$%%'` ;;
-    .libs )   thisdir=. ;;
-    esac
-  fi
-
-  # Try to get the absolute directory name.
-  absdir=`cd "$thisdir" && pwd`
-  test -n "$absdir" && thisdir="$absdir"
-
-  program=lt-'bladec'
-  progdir="$thisdir/.libs"
-
-  if test ! -f "$progdir/$program" ||
-     { file=`ls -1dt "$progdir/$program" "$progdir/../$program" 2>/dev/null | /bin/sed 1q`; \
-       test "X$file" != "X$progdir/$program"; }; then
-
-    file="$$-$program"
-
-    if test ! -d "$progdir"; then
-      mkdir "$progdir"
-    else
-      rm -f "$progdir/$file"
-    fi
-
-    # relink executable if necessary
-    if test -n "$relink_command"; then
-      if relink_command_output=`eval $relink_command 2>&1`; then :
-      else
-       printf %s\n "$relink_command_output" >&2
-       rm -f "$progdir/$file"
-       exit 1
-      fi
-    fi
-
-    mv -f "$progdir/$file" "$progdir/$program" 2>/dev/null ||
-    { rm -f "$progdir/$program";
-      mv -f "$progdir/$file" "$progdir/$program"; }
-    rm -f "$progdir/$file"
-  fi
-
-  if test -f "$progdir/$program"; then
-    if test "$libtool_execute_magic" != "%%%MAGIC variable%%%"; then
-      # Run the actual program with our arguments.
-      func_exec_program ${1+"$@"}
-    fi
-  else
-    # The program doesn't exist.
-    $ECHO "$0: error: \`$progdir/$program' does not exist" 1>&2
-    $ECHO "This script is just a wrapper for $program." 1>&2
-    $ECHO "See the libtool documentation for more information." 1>&2
-    exit 1
-  fi
-fi