From c3b7bb583f497157b31ac46294dbdc6d30ddd3a5 Mon Sep 17 00:00:00 2001 From: Shane Bryldt Date: Thu, 9 Feb 2017 17:08:07 +0000 Subject: [PATCH] FS-9952: Rewrote core code to utilize state machine driven system based on discussions, code compiles but completely untested currently --- libs/libblade/Makefile.am | 6 +- libs/libblade/src/blade_connection.c | 251 +++++++ libs/libblade/src/blade_identity.c | 100 +++ libs/libblade/src/blade_module.c | 98 +++ libs/libblade/src/blade_module_wss.c | 655 ++++++++++++++++++ libs/libblade/src/blade_peer.c | 278 -------- libs/libblade/src/blade_service.c | 428 ------------ libs/libblade/src/blade_stack.c | 31 +- libs/libblade/src/include/blade.h | 6 +- libs/libblade/src/include/blade_connection.h | 67 ++ .../{blade_service.h => blade_identity.h} | 20 +- .../include/{blade_peer.h => blade_module.h} | 18 +- libs/libblade/src/include/blade_stack.h | 6 +- libs/libblade/src/include/blade_types.h | 83 ++- libs/libblade/test/bladec | 228 ------ 15 files changed, 1275 insertions(+), 1000 deletions(-) create mode 100644 libs/libblade/src/blade_connection.c create mode 100644 libs/libblade/src/blade_identity.c create mode 100644 libs/libblade/src/blade_module.c create mode 100644 libs/libblade/src/blade_module_wss.c delete mode 100644 libs/libblade/src/blade_peer.c delete mode 100644 libs/libblade/src/blade_service.c create mode 100644 libs/libblade/src/include/blade_connection.h rename libs/libblade/src/include/{blade_service.h => blade_identity.h} (70%) rename libs/libblade/src/include/{blade_peer.h => blade_module.h} (67%) delete mode 100755 libs/libblade/test/bladec diff --git a/libs/libblade/Makefile.am b/libs/libblade/Makefile.am index 12ef174b65..c9343ff9fc 100644 --- a/libs/libblade/Makefile.am +++ b/libs/libblade/Makefile.am @@ -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 index 0000000000..3ac336697f --- /dev/null +++ b/libs/libblade/src/blade_connection.c @@ -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 index 0000000000..3e814e80af --- /dev/null +++ b/libs/libblade/src/blade_identity.c @@ -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 index 0000000000..a874e45ffc --- /dev/null +++ b/libs/libblade/src/blade_module.c @@ -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 index 0000000000..3efe4307af --- /dev/null +++ b/libs/libblade/src/blade_module_wss.c @@ -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 index 5ec3d6ba0d..0000000000 --- a/libs/libblade/src/blade_peer.c +++ /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 index 4eabd669af..0000000000 --- a/libs/libblade/src/blade_service.c +++ /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: - */ diff --git a/libs/libblade/src/blade_stack.c b/libs/libblade/src/blade_stack.c index 8504af02c4..aeac8682db 100644 --- a/libs/libblade/src/blade_stack.c +++ b/libs/libblade/src/blade_stack.c @@ -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) { diff --git a/libs/libblade/src/include/blade.h b/libs/libblade/src/include/blade.h index f8a3a4459f..d7a6a7cac1 100644 --- a/libs/libblade/src/include/blade.h +++ b/libs/libblade/src/include/blade.h @@ -40,12 +40,14 @@ #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 index 0000000000..d48ec8c221 --- /dev/null +++ b/libs/libblade/src/include/blade_connection.h @@ -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 + +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: + */ diff --git a/libs/libblade/src/include/blade_service.h b/libs/libblade/src/include/blade_identity.h similarity index 70% rename from libs/libblade/src/include/blade_service.h rename to libs/libblade/src/include/blade_identity.h index a5fa890b48..41d0341b06 100644 --- a/libs/libblade/src/include/blade_service.h +++ b/libs/libblade/src/include/blade_identity.h @@ -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 @@ -31,21 +31,15 @@ * 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 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 diff --git a/libs/libblade/src/include/blade_peer.h b/libs/libblade/src/include/blade_module.h similarity index 67% rename from libs/libblade/src/include/blade_peer.h rename to libs/libblade/src/include/blade_module.h index a5cf304b46..ef2ba88de7 100644 --- a/libs/libblade/src/include/blade_peer.h +++ b/libs/libblade/src/include/blade_module.h @@ -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 @@ -31,20 +31,14 @@ * 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 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 diff --git a/libs/libblade/src/include/blade_stack.h b/libs/libblade/src/include/blade_stack.h index ff44f230e9..04daa932d6 100644 --- a/libs/libblade/src/include/blade_stack.h +++ b/libs/libblade/src/include/blade_stack.h @@ -43,14 +43,14 @@ 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, diff --git a/libs/libblade/src/include/blade_types.h b/libs/libblade/src/include/blade_types.h index b534fde6fd..cc2c054197 100644 --- a/libs/libblade/src/include/blade_types.h +++ b/libs/libblade/src/include/blade_types.h @@ -37,28 +37,79 @@ 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 index 805d6501b3..0000000000 --- a/libs/libblade/test/bladec +++ /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