diff --git a/libs/libblade/Makefile.am b/libs/libblade/Makefile.am index 46e751405f..9346c3249a 100644 --- a/libs/libblade/Makefile.am +++ b/libs/libblade/Makefile.am @@ -11,23 +11,20 @@ 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/bpcp.c src/blade_datastore.c -libblade_la_SOURCES += 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_SOURCES += src/blade_session.c src/blade_protocol.c +libblade_la_SOURCES = src/blade.c src/blade_stack.c +libblade_la_SOURCES += src/blade_datastore.c +libblade_la_SOURCES += src/blade_identity.c src/blade_module.c src/blade_connection.c +libblade_la_SOURCES += src/blade_session.c src/blade_protocol.c src/blade_space.c src/blade_method.c +libblade_la_SOURCES += 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 -library_include_HEADERS += src/include/bpcp.h src/include/blade_datastore.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/blade_session.h src/include/blade_protocol.h +library_include_HEADERS += src/include/blade_datastore.h +library_include_HEADERS += src/include/blade_identity.h src/include/blade_module.h src/include/blade_connection.h +library_include_HEADERS += src/include/blade_session.h src/include/blade_protocol.h src/include/blade_space.h src/include/blade_method.h library_include_HEADERS += src/include/unqlite.h test/tap.h tests: libblade.la $(MAKE) -C test tests - - - - diff --git a/libs/libblade/src/blade_connection.c b/libs/libblade/src/blade_connection.c index 6816d61db9..f8cfaead54 100644 --- a/libs/libblade/src/blade_connection.c +++ b/libs/libblade/src/blade_connection.c @@ -495,6 +495,7 @@ ks_status_t blade_connection_state_on_ready(blade_connection_t *bc) blade_transport_state_callback_t callback = NULL; blade_connection_state_hook_t hook = BLADE_CONNECTION_STATE_HOOK_SUCCESS; cJSON *json = NULL; + blade_session_t *bs = NULL; ks_bool_t done = KS_FALSE; ks_assert(bc); @@ -514,14 +515,18 @@ ks_status_t blade_connection_state_on_ready(blade_connection_t *bc) blade_connection_disconnect(bc); break; } + if (!(done = (json == NULL))) { - blade_session_t *bs = blade_handle_sessions_get(bc->handle, bc->session); - ks_assert(bs); + if (!bs) { + bs = blade_handle_sessions_get(bc->handle, bc->session); + ks_assert(bs); + } blade_session_receiving_push(bs, json); cJSON_Delete(json); json = NULL; } } + if (bs) blade_session_read_unlock(bs); callback = blade_connection_state_callback_lookup(bc, BLADE_CONNECTION_STATE_READY); if (callback) hook = callback(bc, BLADE_CONNECTION_STATE_CONDITION_POST); diff --git a/libs/libblade/src/blade_method.c b/libs/libblade/src/blade_method.c new file mode 100644 index 0000000000..ac09c0d109 --- /dev/null +++ b/libs/libblade/src/blade_method.c @@ -0,0 +1,118 @@ +/* + * 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_method_s { + blade_handle_t *handle; + ks_pool_t *pool; + + blade_space_t *space; + const char *name; + + blade_request_callback_t callback; + // @todo more fun descriptive information about the call for remote registrations +}; + + +KS_DECLARE(ks_status_t) blade_method_create(blade_method_t **bmP, blade_space_t *bs, const char *name, blade_request_callback_t callback) +{ + blade_handle_t *bh = NULL; + blade_method_t *bm = NULL; + ks_pool_t *pool = NULL; + + ks_assert(bmP); + ks_assert(bs); + ks_assert(name); + + bh = blade_space_handle_get(bs); + ks_assert(bh); + + pool = blade_handle_pool_get(bh); + ks_assert(pool); + + bm = ks_pool_alloc(pool, sizeof(blade_method_t)); + bm->handle = bh; + bm->pool = pool; + bm->space = bs; + bm->name = name; // @todo dup and keep copy? should mostly be literals + bm->callback = callback; + + *bmP = bm; + + ks_log(KS_LOG_DEBUG, "Method Created: %s.%s\n", blade_space_path_get(bs), name); + + return KS_STATUS_SUCCESS; +} + +KS_DECLARE(ks_status_t) blade_method_destroy(blade_method_t **bmP) +{ + blade_method_t *bm = NULL; + + ks_assert(bmP); + ks_assert(*bmP); + + bm = *bmP; + + ks_log(KS_LOG_DEBUG, "Method Destroyed: %s.%s\n", blade_space_path_get(bm->space), bm->name); + + ks_pool_free(bm->pool, bmP); + + return KS_STATUS_SUCCESS; +} + +KS_DECLARE(const char *) blade_method_name_get(blade_method_t *bm) +{ + ks_assert(bm); + + return bm->name; +} + +KS_DECLARE(blade_request_callback_t) blade_method_callback_get(blade_method_t *bm) +{ + ks_assert(bm); + + return bm->callback; +} + + +/* 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 index ae5c5e1f96..dc1118cb95 100644 --- a/libs/libblade/src/blade_module_wss.c +++ b/libs/libblade/src/blade_module_wss.c @@ -111,8 +111,10 @@ blade_connection_state_hook_t blade_transport_wss_on_state_connect_inbound(blade blade_connection_state_hook_t blade_transport_wss_on_state_connect_outbound(blade_connection_t *bc, blade_connection_state_condition_t condition); blade_connection_state_hook_t blade_transport_wss_on_state_attach_inbound(blade_connection_t *bc, blade_connection_state_condition_t condition); blade_connection_state_hook_t blade_transport_wss_on_state_attach_outbound(blade_connection_t *bc, blade_connection_state_condition_t condition); -blade_connection_state_hook_t blade_transport_wss_on_state_detach(blade_connection_t *bc, blade_connection_state_condition_t condition); -blade_connection_state_hook_t blade_transport_wss_on_state_ready(blade_connection_t *bc, blade_connection_state_condition_t condition); +blade_connection_state_hook_t blade_transport_wss_on_state_detach_inbound(blade_connection_t *bc, blade_connection_state_condition_t condition); +blade_connection_state_hook_t blade_transport_wss_on_state_detach_outbound(blade_connection_t *bc, blade_connection_state_condition_t condition); +blade_connection_state_hook_t blade_transport_wss_on_state_ready_inbound(blade_connection_t *bc, blade_connection_state_condition_t condition); +blade_connection_state_hook_t blade_transport_wss_on_state_ready_outbound(blade_connection_t *bc, blade_connection_state_condition_t condition); @@ -120,6 +122,9 @@ ks_status_t blade_transport_wss_init_create(blade_transport_wss_init_t **bt_wssi ks_status_t blade_transport_wss_init_destroy(blade_transport_wss_init_t **bt_wssiP); +ks_bool_t blade_test_echo_request_handler(blade_request_t *breq); +ks_bool_t blade_test_echo_response_handler(blade_response_t *bres); + static blade_module_callbacks_t g_module_wss_callbacks = { @@ -144,10 +149,10 @@ static blade_transport_callbacks_t g_transport_wss_callbacks = blade_transport_wss_on_state_connect_outbound, blade_transport_wss_on_state_attach_inbound, blade_transport_wss_on_state_attach_outbound, - blade_transport_wss_on_state_detach, - blade_transport_wss_on_state_detach, - blade_transport_wss_on_state_ready, - blade_transport_wss_on_state_ready, + blade_transport_wss_on_state_detach_inbound, + blade_transport_wss_on_state_detach_outbound, + blade_transport_wss_on_state_ready_inbound, + blade_transport_wss_on_state_ready_outbound, }; @@ -385,6 +390,8 @@ ks_status_t blade_module_wss_config(blade_module_wss_t *bm_wss, config_setting_t KS_DECLARE(ks_status_t) blade_module_wss_on_startup(blade_module_t *bm, config_setting_t *config) { blade_module_wss_t *bm_wss = NULL; + blade_space_t *space = NULL; + blade_method_t *method = NULL; ks_assert(bm); ks_assert(config); @@ -419,6 +426,17 @@ KS_DECLARE(ks_status_t) blade_module_wss_on_startup(blade_module_t *bm, config_s blade_handle_transport_register(bm_wss->handle, bm, BLADE_MODULE_WSS_TRANSPORT_NAME, bm_wss->transport_callbacks); + + blade_space_create(&space, bm_wss->handle, "blade.test"); + ks_assert(space); + + blade_method_create(&method, space, "echo", blade_test_echo_request_handler); + ks_assert(method); + + blade_space_methods_add(space, method); + + blade_handle_space_register(space); + ks_log(KS_LOG_DEBUG, "Started\n"); return KS_STATUS_SUCCESS; @@ -428,6 +446,7 @@ KS_DECLARE(ks_status_t) blade_module_wss_on_shutdown(blade_module_t *bm) { blade_module_wss_t *bm_wss = NULL; blade_connection_t *bc = NULL; + ks_bool_t stopped = KS_FALSE; ks_assert(bm); @@ -440,6 +459,7 @@ KS_DECLARE(ks_status_t) blade_module_wss_on_shutdown(blade_module_t *bm) ks_thread_join(bm_wss->listeners_thread); ks_pool_free(bm_wss->pool, &bm_wss->listeners_thread); bm_wss->shutdown = KS_FALSE; + stopped = KS_TRUE; } for (int32_t index = 0; index < bm_wss->listeners_count; ++index) { @@ -461,7 +481,7 @@ KS_DECLARE(ks_status_t) blade_module_wss_on_shutdown(blade_module_t *bm) while (list_size(&bm_wss->connected) > 0) ks_sleep_ms(100); } - ks_log(KS_LOG_DEBUG, "Stopped\n"); + if (stopped) ks_log(KS_LOG_DEBUG, "Stopped\n"); return KS_STATUS_SUCCESS; } @@ -751,7 +771,6 @@ ks_status_t blade_transport_wss_write(blade_transport_wss_t *bt_wss, cJSON *json ks_status_t blade_transport_wss_on_send(blade_connection_t *bc, cJSON *json) { - ks_status_t ret = KS_STATUS_SUCCESS; blade_transport_wss_t *bt_wss = NULL; ks_assert(bc); @@ -759,11 +778,7 @@ ks_status_t blade_transport_wss_on_send(blade_connection_t *bc, cJSON *json) bt_wss = (blade_transport_wss_t *)blade_connection_transport_get(bc); - ret = blade_transport_wss_write(bt_wss, json); - - cJSON_Delete(json); - - return ret; + return blade_transport_wss_write(bt_wss, json); } ks_status_t blade_transport_wss_read(blade_transport_wss_t *bt_wss, cJSON **json) @@ -814,6 +829,29 @@ ks_status_t blade_transport_wss_on_receive(blade_connection_t *bc, cJSON **json) return blade_transport_wss_read(bt_wss, json); } +ks_status_t blade_transport_wss_rpc_error_send(blade_connection_t *bc, const char *id, int32_t code, const char *message) +{ + ks_status_t ret = KS_STATUS_SUCCESS; + blade_transport_wss_t *bt_wss = NULL; + cJSON *json = NULL; + + ks_assert(bc); + ks_assert(id); + ks_assert(message); + + bt_wss = (blade_transport_wss_t *)blade_connection_transport_get(bc); + + blade_rpc_error_create(blade_connection_pool_get(bc), &json, NULL, id, code, message); + + if (blade_transport_wss_write(bt_wss, json) != KS_STATUS_SUCCESS) { + ks_log(KS_LOG_DEBUG, "Failed to write error message\n"); + ret = KS_STATUS_FAIL; + } + + cJSON_Delete(json); + return ret; +} + blade_connection_state_hook_t blade_transport_wss_on_state_disconnect(blade_connection_t *bc, blade_connection_state_condition_t condition) { blade_transport_wss_t *bt_wss = NULL; @@ -924,10 +962,11 @@ blade_connection_state_hook_t blade_transport_wss_on_state_attach_inbound(blade_ { blade_connection_state_hook_t ret = BLADE_CONNECTION_STATE_HOOK_SUCCESS; blade_transport_wss_t *bt_wss = NULL; + ks_pool_t *pool = NULL; cJSON *json_req = NULL; cJSON *json_res = NULL; - cJSON *params = NULL; - cJSON *result = NULL; + cJSON *json_params = NULL; + cJSON *json_result = NULL; //cJSON *error = NULL; blade_session_t *bs = NULL; blade_handle_t *bh = NULL; @@ -948,6 +987,8 @@ blade_connection_state_hook_t blade_transport_wss_on_state_attach_inbound(blade_ bt_wss = (blade_transport_wss_t *)blade_connection_transport_get(bc); + pool = blade_connection_pool_get(bc); + // @todo very temporary, really need monotonic clock and get timeout delay and sleep delay from config timeout = ks_time_now() + (5 * KS_USEC_PER_SEC); while (blade_transport_wss_read(bt_wss, &json_req) == KS_STATUS_SUCCESS) { @@ -958,6 +999,7 @@ blade_connection_state_hook_t blade_transport_wss_on_state_attach_inbound(blade_ if (!json_req) { ks_log(KS_LOG_DEBUG, "Failed to receive message before timeout\n"); + blade_transport_wss_rpc_error_send(bc, NULL, -32600, "Timeout while expecting request"); ret = BLADE_CONNECTION_STATE_HOOK_DISCONNECT; goto done; } @@ -966,7 +1008,7 @@ blade_connection_state_hook_t blade_transport_wss_on_state_attach_inbound(blade_ jsonrpc = cJSON_GetObjectCstr(json_req, "jsonrpc"); // @todo check for definitions of these keys and fixed values if (!jsonrpc || strcmp(jsonrpc, "2.0")) { ks_log(KS_LOG_DEBUG, "Received message is not the expected protocol\n"); - // @todo send error response before disconnecting, code = -32600 (invalid request) + blade_transport_wss_rpc_error_send(bc, NULL, -32600, "Invalid request, missing 'jsonrpc' field"); ret = BLADE_CONNECTION_STATE_HOOK_DISCONNECT; goto done; } @@ -974,7 +1016,7 @@ blade_connection_state_hook_t blade_transport_wss_on_state_attach_inbound(blade_ id = cJSON_GetObjectCstr(json_req, "id"); // @todo switch to number if we are not using a uuid for message id if (!id) { ks_log(KS_LOG_DEBUG, "Received message is missing 'id'\n"); - // @todo send error response before disconnecting, code = -32600 (invalid request) + blade_transport_wss_rpc_error_send(bc, NULL, -32600, "Invalid request, missing 'id' field"); ret = BLADE_CONNECTION_STATE_HOOK_DISCONNECT; goto done; } @@ -982,14 +1024,14 @@ blade_connection_state_hook_t blade_transport_wss_on_state_attach_inbound(blade_ method = cJSON_GetObjectCstr(json_req, "method"); if (!method || strcasecmp(method, "blade.session.attach")) { ks_log(KS_LOG_DEBUG, "Received message is missing 'method' or is an unexpected method\n"); - // @todo send error response before disconnecting, code = -32601 (method not found) + blade_transport_wss_rpc_error_send(bc, id, -32601, "Missing or unexpected 'method' field"); ret = BLADE_CONNECTION_STATE_HOOK_DISCONNECT; goto done; } - params = cJSON_GetObjectItem(json_req, "params"); - if (params) { - sid = cJSON_GetObjectCstr(params, "session-id"); + json_params = cJSON_GetObjectItem(json_req, "params"); + if (json_params) { + sid = cJSON_GetObjectCstr(json_params, "session-id"); if (sid) { // @todo validate uuid format by parsing, not currently available in uuid functions, send -32602 (invalid params) if invalid ks_log(KS_LOG_DEBUG, "Session (%s) requested\n", sid); @@ -1019,7 +1061,7 @@ blade_connection_state_hook_t blade_transport_wss_on_state_attach_inbound(blade_ if (blade_session_startup(bs) != KS_STATUS_SUCCESS) { ks_log(KS_LOG_DEBUG, "Session (%s) startup failed\n", blade_session_id_get(bs)); - // @todo send error response before disconnecting, code = -32603 (internal error) + blade_transport_wss_rpc_error_send(bc, id, -32603, "Internal error, session could not be started"); blade_session_read_unlock(bs); blade_session_destroy(&bs); ret = BLADE_CONNECTION_STATE_HOOK_DISCONNECT; @@ -1030,17 +1072,14 @@ blade_connection_state_hook_t blade_transport_wss_on_state_attach_inbound(blade_ } // @todo wrapper to generate request and response - json_res = cJSON_CreateObject(); - cJSON_AddStringToObject(json_res, "jsonrpc", "2.0"); - cJSON_AddStringToObject(json_res, "id", id); + blade_rpc_response_create(pool, &json_res, &json_result, id); + ks_assert(json_res); - result = cJSON_CreateObject(); - cJSON_AddStringToObject(result, "session-id", blade_session_id_get(bs)); - cJSON_AddItemToObject(json_res, "result", result); + cJSON_AddStringToObject(json_result, "session-id", blade_session_id_get(bs)); // @todo send response if (blade_transport_wss_write(bt_wss, json_res) != KS_STATUS_SUCCESS) { - ks_log(KS_LOG_DEBUG, "Failed to write message\n"); + ks_log(KS_LOG_DEBUG, "Failed to write response message\n"); ret = BLADE_CONNECTION_STATE_HOOK_DISCONNECT; goto done; } @@ -1064,14 +1103,14 @@ blade_connection_state_hook_t blade_transport_wss_on_state_attach_outbound(blade blade_transport_wss_init_t *bt_wss_init = NULL; ks_pool_t *pool = NULL; cJSON *json_req = NULL; + cJSON *json_params = NULL; cJSON *json_res = NULL; - uuid_t msgid; const char *mid = NULL; ks_time_t timeout; const char *jsonrpc = NULL; const char *id = NULL; - cJSON *error = NULL; - cJSON *result = NULL; + cJSON *json_error = NULL; + cJSON *json_result = NULL; const char *sid = NULL; blade_session_t *bs = NULL; @@ -1087,25 +1126,15 @@ blade_connection_state_hook_t blade_transport_wss_on_state_attach_outbound(blade pool = blade_connection_pool_get(bc); - // @todo wrapper to build a request and response/error - json_req = cJSON_CreateObject(); - cJSON_AddStringToObject(json_req, "jsonrpc", "2.0"); - cJSON_AddStringToObject(json_req, "method", "blade.session.attach"); + blade_rpc_request_create(pool, &json_req, &json_params, &mid, "blade.session.attach"); + ks_assert(json_req); - ks_uuid(&msgid); - mid = ks_uuid_str(pool, &msgid); - cJSON_AddStringToObject(json_req, "id", mid); - - if (bt_wss_init->session_id) { - cJSON *params = cJSON_CreateObject(); - cJSON_AddStringToObject(params, "session-id", bt_wss_init->session_id); - cJSON_AddItemToObject(json_req, "params", params); - } + if (bt_wss_init->session_id) cJSON_AddStringToObject(json_params, "session-id", bt_wss_init->session_id); ks_log(KS_LOG_DEBUG, "Session (%s) requested\n", (bt_wss_init->session_id ? bt_wss_init->session_id : "none")); if (blade_transport_wss_write(bt_wss, json_req) != KS_STATUS_SUCCESS) { - ks_log(KS_LOG_DEBUG, "Failed to write message\n"); + ks_log(KS_LOG_DEBUG, "Failed to write request message\n"); ret = BLADE_CONNECTION_STATE_HOOK_DISCONNECT; goto done; } @@ -1134,26 +1163,26 @@ blade_connection_state_hook_t blade_transport_wss_on_state_attach_outbound(blade id = cJSON_GetObjectCstr(json_res, "id"); // @todo switch to number if we are not using a uuid for message id if (!id || strcasecmp(mid, id)) { - ks_log(KS_LOG_DEBUG, "Received message is missing 'id'\n"); + ks_log(KS_LOG_DEBUG, "Received message has missing or unexpected 'id'\n"); ret = BLADE_CONNECTION_STATE_HOOK_DISCONNECT; goto done; } - error = cJSON_GetObjectItem(json_res, "error"); - if (error) { + json_error = cJSON_GetObjectItem(json_res, "error"); + if (json_error) { ks_log(KS_LOG_DEBUG, "Error message ... add the details\n"); ret = BLADE_CONNECTION_STATE_HOOK_DISCONNECT; goto done; } - result = cJSON_GetObjectItem(json_res, "result"); - if (!result) { + json_result = cJSON_GetObjectItem(json_res, "result"); + if (!json_result) { ks_log(KS_LOG_DEBUG, "Received message is missing 'result'\n"); ret = BLADE_CONNECTION_STATE_HOOK_DISCONNECT; goto done; } - sid = cJSON_GetObjectCstr(result, "session-id"); + sid = cJSON_GetObjectCstr(json_result, "session-id"); if (!sid) { ks_log(KS_LOG_DEBUG, "Received message 'result' is missing 'session-id'\n"); ret = BLADE_CONNECTION_STATE_HOOK_DISCONNECT; @@ -1192,13 +1221,12 @@ blade_connection_state_hook_t blade_transport_wss_on_state_attach_outbound(blade blade_connection_session_set(bc, blade_session_id_get(bs)); done: - if (mid) ks_pool_free(pool, &mid); if (json_req) cJSON_Delete(json_req); if (json_res) cJSON_Delete(json_res); return ret; } -blade_connection_state_hook_t blade_transport_wss_on_state_detach(blade_connection_t *bc, blade_connection_state_condition_t condition) +blade_connection_state_hook_t blade_transport_wss_on_state_detach_inbound(blade_connection_t *bc, blade_connection_state_condition_t condition) { ks_assert(bc); @@ -1207,7 +1235,16 @@ blade_connection_state_hook_t blade_transport_wss_on_state_detach(blade_connecti return BLADE_CONNECTION_STATE_HOOK_SUCCESS; } -blade_connection_state_hook_t blade_transport_wss_on_state_ready(blade_connection_t *bc, blade_connection_state_condition_t condition) +blade_connection_state_hook_t blade_transport_wss_on_state_detach_outbound(blade_connection_t *bc, blade_connection_state_condition_t condition) +{ + ks_assert(bc); + + ks_log(KS_LOG_DEBUG, "State Callback: %d\n", (int32_t)condition); + + return BLADE_CONNECTION_STATE_HOOK_SUCCESS; +} + +blade_connection_state_hook_t blade_transport_wss_on_state_ready_inbound(blade_connection_t *bc, blade_connection_state_condition_t condition) { ks_assert(bc); @@ -1217,6 +1254,60 @@ blade_connection_state_hook_t blade_transport_wss_on_state_ready(blade_connectio return BLADE_CONNECTION_STATE_HOOK_SUCCESS; } +blade_connection_state_hook_t blade_transport_wss_on_state_ready_outbound(blade_connection_t *bc, blade_connection_state_condition_t condition) +{ + ks_assert(bc); + + ks_log(KS_LOG_DEBUG, "State Callback: %d\n", (int32_t)condition); + + if (condition == BLADE_CONNECTION_STATE_CONDITION_PRE) { + blade_session_t *bs = NULL; + cJSON *req = NULL; + + bs = blade_handle_sessions_get(blade_connection_handle_get(bc), blade_connection_session_get(bc)); + ks_assert(bs); + + blade_rpc_request_create(blade_connection_pool_get(bc), &req, NULL, NULL, "blade.test.echo"); + blade_session_send(bs, req, blade_test_echo_response_handler); + + blade_session_read_unlock(bs); + } + + ks_sleep_ms(1000); + return BLADE_CONNECTION_STATE_HOOK_SUCCESS; +} + + + +ks_bool_t blade_test_echo_request_handler(blade_request_t *breq) +{ + blade_session_t *bs = NULL; + cJSON *res = NULL; + + ks_assert(breq); + + ks_log(KS_LOG_DEBUG, "Request Received!\n"); + + bs = blade_handle_sessions_get(breq->handle, breq->session_id); + ks_assert(bs); + + blade_rpc_response_create(breq->pool, &res, NULL, breq->message_id); + blade_session_send(bs, res, NULL); + + blade_session_read_unlock(bs); + + return KS_FALSE; +} + +ks_bool_t blade_test_echo_response_handler(blade_response_t *bres) +{ + ks_assert(bres); + + ks_log(KS_LOG_DEBUG, "Response Received!\n"); + + return KS_FALSE; +} + /* For Emacs: * Local Variables: * mode:c diff --git a/libs/libblade/src/blade_protocol.c b/libs/libblade/src/blade_protocol.c index 830be262f0..092c31f237 100644 --- a/libs/libblade/src/blade_protocol.c +++ b/libs/libblade/src/blade_protocol.c @@ -33,7 +33,11 @@ #include "blade.h" -KS_DECLARE(ks_status_t) blade_request_create(blade_request_t **breqP, blade_handle_t *bh, const char *session_id, cJSON *json) +KS_DECLARE(ks_status_t) blade_request_create(blade_request_t **breqP, + blade_handle_t *bh, + const char *session_id, + cJSON *json, + blade_response_callback_t callback) { blade_request_t *breq = NULL; ks_pool_t *pool = NULL; @@ -50,8 +54,9 @@ KS_DECLARE(ks_status_t) blade_request_create(blade_request_t **breqP, blade_hand breq->handle = bh; breq->pool = pool; breq->session_id = ks_pstrdup(pool, session_id); - breq->message = json; + breq->message = cJSON_Duplicate(json, 1); breq->message_id = cJSON_GetObjectCstr(json, "id"); + breq->callback = callback; *breqP = breq; @@ -95,7 +100,7 @@ KS_DECLARE(ks_status_t) blade_response_create(blade_response_t **bresP, blade_ha bres->pool = pool; bres->session_id = ks_pstrdup(pool, session_id); bres->request = breq; - bres->message = json; + bres->message = cJSON_Duplicate(json, 1); *bresP = bres; @@ -120,6 +125,88 @@ KS_DECLARE(ks_status_t) blade_response_destroy(blade_response_t **bresP) return KS_STATUS_SUCCESS; } +KS_DECLARE(ks_status_t) blade_rpc_request_create(ks_pool_t *pool, cJSON **json, cJSON **params, const char **id, const char *method) +{ + cJSON *root = NULL; + cJSON *p = NULL; + uuid_t msgid; + const char *mid = NULL; + + ks_assert(pool); + ks_assert(json); + ks_assert(method); + + root = cJSON_CreateObject(); + + cJSON_AddStringToObject(root, "jsonrpc", "2.0"); + + ks_uuid(&msgid); + mid = ks_uuid_str(pool, &msgid); + cJSON_AddStringToObject(root, "id", mid); + ks_pool_free(pool, &mid); + + cJSON_AddStringToObject(root, "method", method); + + p = cJSON_CreateObject(); + cJSON_AddItemToObject(root, "params", p); + + *json = root; + if (params) *params = p; + if (id) *id = cJSON_GetObjectCstr(root, "id"); + + return KS_STATUS_SUCCESS; +} + +KS_DECLARE(ks_status_t) blade_rpc_response_create(ks_pool_t *pool, cJSON **json, cJSON **result, const char *id) +{ + cJSON *root = NULL; + cJSON *r = NULL; + + ks_assert(pool); + ks_assert(json); + ks_assert(id); + + root = cJSON_CreateObject(); + + cJSON_AddStringToObject(root, "jsonrpc", "2.0"); + + cJSON_AddStringToObject(root, "id", id); + + r = cJSON_CreateObject(); + cJSON_AddItemToObject(root, "result", r); + + *json = root; + if (result) *result = r; + + return KS_STATUS_SUCCESS; +} + +KS_DECLARE(ks_status_t) blade_rpc_error_create(ks_pool_t *pool, cJSON **json, cJSON **error, const char *id, int32_t code, const char *message) +{ + cJSON *root = NULL; + cJSON *e = NULL; + + ks_assert(pool); + ks_assert(json); + ks_assert(id); + ks_assert(message); + + root = cJSON_CreateObject(); + + cJSON_AddStringToObject(root, "jsonrpc", "2.0"); + + cJSON_AddStringToObject(root, "id", id); + + e = cJSON_CreateObject(); + cJSON_AddNumberToObject(e, "code", code); + cJSON_AddStringToObject(e, "message", message); + cJSON_AddItemToObject(root, "error", e); + + *json = root; + if (error) *error = e; + + return KS_STATUS_SUCCESS; +} /* For Emacs: * Local Variables: diff --git a/libs/libblade/src/blade_rpcproto.c b/libs/libblade/src/blade_rpcproto.c deleted file mode 100644 index bedfd1c505..0000000000 --- a/libs/libblade/src/blade_rpcproto.c +++ /dev/null @@ -1,1178 +0,0 @@ -/* - * Copyright (c) 2017 FreeSWITCH Solutions LLC - * 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. - */ - -#pragma GCC optimize ("O0") - -#include - -/* - * internal shared structure grounded in global - */ -typedef struct blade_rpc_handle_ex { - - ks_hash_t *namespace_hash; /* hash to namespace methods */ - ks_hash_t *template_hash; /* hash to template methods */ - - ks_hash_t *peer_hash; /* hash to peer structure */ - - ks_q_t *event_queue; - ks_bool_t isactive; - ks_pool_t *pool; - -} blade_rpc_handle_ex_t; - - -typedef struct blade_rpc_namespace_s { - - char name[KS_RPCMESSAGE_NAMESPACE_LENGTH+1]; - char version[KS_RPCMESSAGE_VERSION_LENGTH+1]; /* nnn.nn.nn */ - ks_hash_t *method_hash; /* hash to namespace methods */ - -} blade_rpc_namespace_t; - - - - -blade_rpc_handle_ex_t *g_handle = NULL; - - -/* - * callbacks - from blade_rpc_handle_ex->method_hash - */ - -typedef struct blade_rpc_custom_callbackpair_s -{ - jrpc_func_t prefix_request_func; - jrpc_func_t postfix_request_func; - - jrpc_func_t prefix_response_func; - jrpc_func_t postfix_response_func; - -} blade_rpc_custom_callbackpair_t; - - - -typedef struct blade_rpc_callbackpair_s -{ - jrpc_func_t request_func; - - jrpc_func_t response_func; - - blade_rpc_custom_callbackpair_t* custom; - - ks_mutex_t *lock; - - uint16_t command_length; - char command[1]; - -} blade_rpc_callbackpair_t; - - - - - -static void blade_rpc_make_fqcommand(const char* namespace, const char *command, char *fscommand) -{ - memset(fscommand, 0, KS_RPCMESSAGE_FQCOMMAND_LENGTH); - sprintf(fscommand, "%s.%s", namespace, command); - - return; -} - -static void blade_rpc_parse_fqcommand(const char* fscommand, char *namespace, char *command) -{ - memset(command, 0, KS_RPCMESSAGE_COMMAND_LENGTH); - memset(namespace, 0, KS_RPCMESSAGE_NAMESPACE_LENGTH); - - uint32_t len = strlen(fscommand); - - assert(len <= KS_RPCMESSAGE_FQCOMMAND_LENGTH); - ks_bool_t dotfound = KS_FALSE; - - for(int i=0, x=0; inamespace_hash, - KS_HASH_MODE_CASE_SENSITIVE, - KS_HASH_FLAG_RWLOCK + KS_HASH_FLAG_DUP_CHECK, // + KS_HASH_FLAG_FREE_VALUE, - pool); - - ks_hash_create(&g_handle->template_hash, - KS_HASH_MODE_CASE_SENSITIVE, - KS_HASH_FLAG_RWLOCK + KS_HASH_FLAG_DUP_CHECK, // + KS_HASH_FLAG_FREE_VALUE, - pool); - - ks_q_create(&g_handle->event_queue, pool, 1024); - - g_handle->pool = pool; - - /* initialize rpc messaging mechanism */ - ks_rpcmessage_init(pool); - - g_handle->isactive = KS_TRUE; - } - return KS_STATUS_SUCCESS; -} - - -//KS_DECLARE(ks_status_t) blade_rpc_onconnect(ks_pool_t *pool, blade_peer_t* peer) -//{ -// -// -// return KS_STATUS_FAIL; -//} -// -//KS_DECLARE(ks_status_t) blade_rpc_disconnect(blade_peer_t* peer) -//{ -// -// return KS_STATUS_FAIL; -//} - - - -/* - * namespace setup - */ - -/* - * function/callback functions - */ -static blade_rpc_callbackpair_t *blade_rpc_find_callbacks_locked(char *namespace, char *command) -{ - blade_rpc_callbackpair_t *callbacks = NULL; - - blade_rpc_namespace_t *n = ks_hash_search(g_handle->namespace_hash, namespace, KS_UNLOCKED); - if (n) { - - ks_hash_read_lock(n->method_hash); - - callbacks = ks_hash_search(n->method_hash, command, KS_UNLOCKED); - - if (callbacks) { - ks_mutex_lock(callbacks->lock); - } - - ks_hash_read_unlock(n->method_hash); - } - - return callbacks; -} - -static blade_rpc_callbackpair_t *blade_rpc_find_template_locked(char *name, char *command) -{ - blade_rpc_callbackpair_t *callbacks = NULL; - - blade_rpc_namespace_t *n = ks_hash_search(g_handle->template_hash, name, KS_UNLOCKED); - if (n) { - - ks_hash_read_lock(n->method_hash); - callbacks = ks_hash_search(n->method_hash, command, KS_UNLOCKED); - - if (callbacks) { - ks_mutex_lock(callbacks->lock); - } - - ks_hash_read_unlock(n->method_hash); - } - - return callbacks; -} - - - - -static blade_rpc_callbackpair_t *blade_rpc_find_callbacks_locked_fq(char *fqcommand) -{ - blade_rpc_callbackpair_t *callbacks = NULL; - - char command[KS_RPCMESSAGE_COMMAND_LENGTH+1]; - char namespace[KS_RPCMESSAGE_NAMESPACE_LENGTH+1]; - - blade_rpc_parse_fqcommand(fqcommand, namespace, command); - - blade_rpc_namespace_t *n = ks_hash_search(g_handle->namespace_hash, namespace, KS_UNLOCKED); - if (n) { - blade_rpc_make_fqcommand(namespace, command, fqcommand); - ks_hash_read_lock(n->method_hash); - - callbacks = ks_hash_search(n->method_hash, fqcommand, KS_UNLOCKED); - - if (callbacks) { - ks_mutex_lock(callbacks->lock); - } - - ks_hash_read_unlock(n->method_hash); - } - - return callbacks; -} - - -KS_DECLARE(jrpc_func_t) blade_rpc_find_request_function(char *fqcommand) -{ - - blade_rpc_callbackpair_t* callbacks = blade_rpc_find_callbacks_locked_fq(fqcommand); - - if (!callbacks) { - return NULL; - } - - jrpc_func_t f = callbacks->request_func; - - ks_mutex_unlock(callbacks->lock); - - return f; -} - -KS_DECLARE(jrpc_func_t) blade_rpc_find_requestprefix_function(char *fqcommand) -{ - - blade_rpc_callbackpair_t* callbacks = blade_rpc_find_callbacks_locked_fq(fqcommand); - - if (!callbacks || !callbacks->custom) { - return NULL; - } - - jrpc_func_t f = callbacks->custom->prefix_request_func; - - ks_mutex_unlock(callbacks->lock); - - return f; -} - -KS_DECLARE(jrpc_func_t) blade_rpc_find_response_function(char *fqcommand) -{ - - blade_rpc_callbackpair_t* callbacks = blade_rpc_find_callbacks_locked_fq(fqcommand); - - if (!callbacks) { - return NULL; - } - - jrpc_func_t f = callbacks->response_func; - - ks_mutex_unlock(callbacks->lock); - - return f; -} - -KS_DECLARE(jrpc_func_t) blade_rpc_find_responseprefix_function(char *fqcommand) -{ - - blade_rpc_callbackpair_t* callbacks = blade_rpc_find_callbacks_locked_fq(fqcommand); - - if (!callbacks || !callbacks->custom) { - return NULL; - } - - jrpc_func_t f = callbacks->custom->prefix_response_func; - - ks_mutex_unlock(callbacks->lock); - - return f; -} - - -KS_DECLARE(ks_status_t) blade_rpc_declare_namespace(char* namespace, const char* version) -{ - - /* find/insert to namespace hash as needed */ - ks_hash_write_lock(g_handle->namespace_hash); - blade_rpc_namespace_t *n = ks_hash_search(g_handle->namespace_hash, namespace, KS_UNLOCKED); - if (n == NULL) { - n = ks_pool_alloc(g_handle->pool, sizeof (blade_rpc_namespace_t) + strlen(namespace) + 1); - strncpy(n->name, namespace, KS_RPCMESSAGE_NAMESPACE_LENGTH); - strncpy(n->version, version, KS_RPCMESSAGE_VERSION_LENGTH); - ks_hash_create(&n->method_hash, - KS_HASH_MODE_CASE_SENSITIVE, - KS_HASH_FLAG_RWLOCK + KS_HASH_FLAG_DUP_CHECK + KS_HASH_FLAG_FREE_VALUE, - g_handle->pool); - ks_hash_insert(g_handle->namespace_hash, n->name, n); - } - ks_hash_write_unlock(g_handle->namespace_hash); - - ks_log(KS_LOG_DEBUG, "Setting message namespace value %s, version %s\n", namespace, version); - - return KS_STATUS_SUCCESS; -} - - -KS_DECLARE(ks_status_t)blade_rpc_register_function(char *namespace, - char *command, - jrpc_func_t func, - jrpc_func_t respfunc) -{ - if (!func && !respfunc) { - return KS_STATUS_FAIL; - } - - char nskey[KS_RPCMESSAGE_NAMESPACE_LENGTH+1]; - memset(nskey, 0, sizeof(nskey)); - strcpy(nskey, namespace); - - char fqcommand[KS_RPCMESSAGE_FQCOMMAND_LENGTH]; - memset(fqcommand, 0, sizeof(fqcommand)); - -// strcpy(fqcommand, namespace); -// strcpy(fqcommand, "."); - strcat(fqcommand, command); - - int lkey = strlen(command)+1; - - if (lkey < 16) { - lkey = 16; - } - - ks_hash_read_lock(g_handle->namespace_hash); /* lock namespace hash */ - - blade_rpc_namespace_t *n = ks_hash_search(g_handle->namespace_hash, nskey, KS_UNLOCKED); - - if (n == NULL) { - ks_hash_read_unlock(g_handle->namespace_hash); - ks_log(KS_LOG_ERROR, "Unable to find %s namespace\n", namespace); - return KS_STATUS_FAIL; - } - - blade_rpc_callbackpair_t* callbacks = blade_rpc_find_callbacks_locked(nskey, command); - - /* just ignore attempt to re register callbacks */ - /* @todo : should this be smarter, allow override ? */ - if (callbacks != NULL) { - ks_mutex_unlock(callbacks->lock); - ks_hash_read_unlock(g_handle->namespace_hash); - ks_log(KS_LOG_ERROR, "Callbacks already registered for %s namespace\n", namespace); - return KS_STATUS_FAIL; - } - - callbacks = - (blade_rpc_callbackpair_t*)ks_pool_alloc(g_handle->pool, lkey + sizeof(blade_rpc_callbackpair_t)); - - strcpy(callbacks->command, command); - callbacks->command_length = lkey; - callbacks->request_func = func; - callbacks->response_func = respfunc; - ks_mutex_create(&callbacks->lock, KS_MUTEX_FLAG_DEFAULT, g_handle->pool); - - ks_hash_write_lock(n->method_hash); /* lock method hash */ - - ks_hash_insert(n->method_hash, callbacks->command, (void *) callbacks); - - ks_hash_write_unlock(n->method_hash); /* unlock method hash */ - ks_hash_read_unlock(g_handle->namespace_hash); /* unlock namespace hash */ - - ks_log(KS_LOG_DEBUG, "Message %s %s registered\n", namespace, command); - - return KS_STATUS_SUCCESS; - -} - - -KS_DECLARE(ks_status_t)blade_rpc_register_custom_request_function(char *namespace, - char *command, - jrpc_func_t prefix_func, - jrpc_func_t postfix_func) -{ - ks_status_t s = KS_STATUS_FAIL; - - char fqcommand[KS_RPCMESSAGE_FQCOMMAND_LENGTH]; - memset(fqcommand, 0, sizeof(fqcommand)); - strcat(fqcommand, command); - - ks_hash_write_lock(g_handle->namespace_hash); - blade_rpc_callbackpair_t* callbacks = blade_rpc_find_callbacks_locked(namespace, fqcommand); - - if (callbacks) { - - if (!callbacks->custom) { - callbacks->custom = - (blade_rpc_custom_callbackpair_t *)ks_pool_alloc(g_handle->pool, sizeof(blade_rpc_custom_callbackpair_t)); - } - - callbacks->custom->prefix_request_func = prefix_func; - callbacks->custom->postfix_request_func = postfix_func; - ks_mutex_unlock(callbacks->lock); - s = KS_STATUS_SUCCESS; - } - - ks_hash_write_unlock(g_handle->namespace_hash); - return s; -} - -KS_DECLARE(ks_status_t)blade_rpc_register_custom_response_function(char* namespace, - char *command, - jrpc_func_t prefix_func, - jrpc_func_t postfix_func) -{ - ks_status_t s = KS_STATUS_FAIL; - - char fqcommand[KS_RPCMESSAGE_FQCOMMAND_LENGTH]; - memset(fqcommand, 0, sizeof(fqcommand)); - strcat(fqcommand, command); - - ks_hash_write_lock(g_handle->namespace_hash); - blade_rpc_callbackpair_t *callbacks = blade_rpc_find_callbacks_locked(namespace, fqcommand); - - if (callbacks) { - - if (!callbacks->custom) { - callbacks->custom = - (blade_rpc_custom_callbackpair_t *)ks_pool_alloc(g_handle->pool, sizeof(blade_rpc_custom_callbackpair_t)); - } - - callbacks->custom->prefix_response_func = prefix_func; - callbacks->custom->postfix_response_func = postfix_func; - ks_mutex_unlock(callbacks->lock); - s = KS_STATUS_SUCCESS; - } - - ks_hash_write_unlock(g_handle->namespace_hash); - return s; -} - -KS_DECLARE(void) blade_rpc_remove_namespace(char* namespace) -{ - char nskey[KS_RPCMESSAGE_NAMESPACE_LENGTH]; - memset(nskey, 0, sizeof(nskey)); - strcat(nskey, namespace); - - ks_hash_write_lock(g_handle->namespace_hash); - - blade_rpc_namespace_t *n = ks_hash_search(g_handle->namespace_hash, nskey, KS_UNLOCKED); - - ks_hash_iterator_t* it = ks_hash_first(n->method_hash, KS_HASH_FLAG_RWLOCK); - - while (it) { - - const void *key; - void *value; - ks_ssize_t len = strlen(key); - - ks_hash_this(it, &key, &len, &value); - blade_rpc_callbackpair_t *callbacks = (blade_rpc_callbackpair_t *)value; - - ks_mutex_lock(callbacks->lock); - - if (callbacks->custom) { - ks_pool_free(g_handle->pool, callbacks->custom); - } - - it = ks_hash_next(&it); - ks_hash_remove(n->method_hash, (void *)key); - } - - ks_hash_write_unlock(g_handle->namespace_hash); - - return; -} - - -/* - * template functions - * - */ - -KS_DECLARE(ks_status_t) blade_rpc_declare_template(char* templatename, const char* version) -{ - char nskey[KS_RPCMESSAGE_NAMESPACE_LENGTH]; - memset(nskey, 0, sizeof(nskey)); - strcat(nskey, templatename); - - - /* find/insert to namespace hash as needed */ - ks_hash_write_lock(g_handle->template_hash); - blade_rpc_namespace_t *n = ks_hash_search(g_handle->template_hash, nskey, KS_UNLOCKED); - - if (n == NULL) { - n = ks_pool_alloc(g_handle->pool, sizeof (blade_rpc_namespace_t) + strlen(templatename) + 1); - strncpy(n->name, templatename, KS_RPCMESSAGE_NAMESPACE_LENGTH); - strncpy(n->version, version, KS_RPCMESSAGE_VERSION_LENGTH); - ks_hash_create(&n->method_hash, - KS_HASH_MODE_CASE_SENSITIVE, - KS_HASH_FLAG_RWLOCK + KS_HASH_FLAG_DUP_CHECK + KS_HASH_FLAG_FREE_VALUE, - g_handle->pool); - ks_hash_insert(g_handle->template_hash, n->name, n); - } - ks_hash_write_unlock(g_handle->template_hash); - - ks_log(KS_LOG_DEBUG, "Declaring application template namespace %s, version %s\n", templatename, version); - - return KS_STATUS_SUCCESS; -} - -KS_DECLARE(ks_status_t)blade_rpc_register_template_function(char *name, - char *command, - jrpc_func_t func, - jrpc_func_t respfunc) -{ - (void)blade_rpc_find_template_locked; //remove - - if (!func && !respfunc) { - return KS_STATUS_FAIL; - } - - char nskey[KS_RPCMESSAGE_NAMESPACE_LENGTH]; - memset(nskey, 0, sizeof(nskey)); - strcat(nskey, name); - - char fqcommand[KS_RPCMESSAGE_FQCOMMAND_LENGTH]; - memset(fqcommand, 0, sizeof(fqcommand)); - strcat(fqcommand, command); - - int lkey = strlen(fqcommand)+1; - - if (lkey < 16) { - lkey = 16; - } - - ks_hash_read_lock(g_handle->template_hash); /* lock template hash */ - - blade_rpc_namespace_t *n = ks_hash_search(g_handle->template_hash, nskey, KS_UNLOCKED); - - if (n == NULL) { - ks_hash_read_unlock(g_handle->template_hash); - ks_log(KS_LOG_ERROR, "Unable to find %s template\n", name); - return KS_STATUS_FAIL; - } - - ks_hash_read_lock(n->method_hash); - blade_rpc_callbackpair_t* callbacks = ks_hash_search(n->method_hash, fqcommand, KS_UNLOCKED); - ks_hash_read_unlock(n->method_hash); - - /* just ignore attempt to re register callbacks */ - /* as the template may already be in use leading to confusion */ - - if (callbacks != NULL) { - ks_mutex_unlock(callbacks->lock); - ks_hash_read_unlock(g_handle->template_hash); - ks_log(KS_LOG_ERROR, "Callbacks already registered for %s template\n", name); - return KS_STATUS_FAIL; - } - - callbacks = - (blade_rpc_callbackpair_t*)ks_pool_alloc(g_handle->pool, lkey + sizeof(blade_rpc_callbackpair_t)); - - strcpy(callbacks->command, command); - callbacks->command_length = lkey; - callbacks->request_func = func; - callbacks->response_func = respfunc; - - ks_mutex_create(&callbacks->lock, KS_MUTEX_FLAG_DEFAULT, g_handle->pool); - - ks_hash_write_lock(n->method_hash); /* lock method hash */ - - ks_hash_insert(n->method_hash, callbacks->command, (void *) callbacks); - - ks_hash_write_unlock(n->method_hash); /* unlock method hash */ - ks_hash_read_unlock(g_handle->template_hash); /* unlock namespace hash */ - - ks_log(KS_LOG_DEBUG, "Template message %s %s registered\n", name, command); - - return KS_STATUS_SUCCESS; - -} - -KS_DECLARE(ks_status_t)blade_rpc_inherit_template(char *namespace, char* template) -{ - ks_hash_read_lock(g_handle->template_hash); - - char tkey[KS_RPCMESSAGE_NAMESPACE_LENGTH+1]; - memset(tkey, 0, sizeof(tkey)); - strcpy(tkey, template); - - char nskey[KS_RPCMESSAGE_NAMESPACE_LENGTH+1]; - memset(nskey, 0, sizeof(tkey)); - strcpy(nskey, namespace); - - blade_rpc_namespace_t *n = ks_hash_search(g_handle->template_hash, tkey, KS_UNLOCKED); - - if (!n) { - ks_hash_read_unlock(g_handle->template_hash); - ks_log(KS_LOG_ERROR, "Unable to locate template %s\n", template); - return KS_STATUS_FAIL; - } - - ks_hash_read_lock(g_handle->namespace_hash); - - blade_rpc_namespace_t *ns = ks_hash_search(g_handle->namespace_hash, nskey, KS_UNLOCKED); - - if (!ns) { - ks_hash_read_unlock(g_handle->template_hash); - ks_hash_read_unlock(g_handle->namespace_hash); - ks_log(KS_LOG_ERROR, "Unable to locate namespace %s\n", namespace); - return KS_STATUS_FAIL; - } - - ks_hash_write_lock(ns->method_hash); - - ks_hash_iterator_t* it = ks_hash_first(n->method_hash, KS_HASH_FLAG_RWLOCK); - - while (it) { - - const void *key; - void *value; - ks_ssize_t len = strlen(key); - - ks_hash_this(it, &key, &len, &value); - blade_rpc_callbackpair_t *t_callback = (blade_rpc_callbackpair_t *)value; - - ks_mutex_lock(t_callback->lock); - - int lkey = t_callback->command_length; - - blade_rpc_callbackpair_t *callbacks = - (blade_rpc_callbackpair_t*)ks_pool_alloc(g_handle->pool, lkey + sizeof(blade_rpc_callbackpair_t)); - - strcat(callbacks->command, template); - strcat(callbacks->command, "."); - strcat(callbacks->command, t_callback->command); - - callbacks->command_length = lkey; - callbacks->request_func = t_callback->request_func; - callbacks->response_func = t_callback->response_func; - ks_mutex_create(&callbacks->lock, KS_MUTEX_FLAG_DEFAULT, g_handle->pool); - - ks_hash_insert(ns->method_hash, callbacks->command, (void *) callbacks); - - ks_mutex_unlock(t_callback->lock); - - it = ks_hash_next(&it); - } - - - ks_hash_write_lock(ns->method_hash); - - ks_hash_read_unlock(g_handle->namespace_hash); - ks_hash_read_unlock(g_handle->template_hash); - - return KS_STATUS_SUCCESS; -} - - -/* - * create a request message - */ -KS_DECLARE(ks_rpcmessageid_t) blade_rpc_create_request(char *namespace, - char *method, - blade_rpc_fields_t* fields, - cJSON **paramsP, - cJSON **requestP) -{ - cJSON *jversion = NULL; - blade_rpc_callbackpair_t* callbacks = NULL; - - *requestP = NULL; - - ks_hash_read_lock(g_handle->namespace_hash); - blade_rpc_namespace_t *n = ks_hash_search(g_handle->namespace_hash, namespace, KS_UNLOCKED); - - if (n) { - ks_hash_read_lock(n->method_hash); - callbacks = ks_hash_search(n->method_hash, method, KS_UNLOCKED); - if (callbacks) { - jversion = cJSON_CreateString(n->version); - } - ks_hash_read_unlock(n->method_hash); - } - - ks_hash_read_unlock(g_handle->namespace_hash); - - if (!n) { - ks_log(KS_LOG_ERROR, "No namespace %s found\n", namespace); - return 0; - } - - if (!callbacks) { - ks_log(KS_LOG_ERROR, "No method %s.%s found\n", namespace, method); - return 0; - } - - ks_rpcmessageid_t msgid = ks_rpcmessage_create_request(namespace, method, paramsP, requestP); - - if (!msgid || *requestP == NULL) { - ks_log(KS_LOG_ERROR, "Unable to create rpc message for method %s.%s\n", namespace, method); - return 0; - } - - cJSON *jfields = cJSON_CreateObject(); - - cJSON_AddItemToObject(jfields, "version", jversion); - - if (fields->to) { - cJSON_AddStringToObject(jfields, "to", fields->to); - } - - if (fields->from) { - cJSON_AddStringToObject(jfields, "from", fields->from); - } - - if (fields->token) { - cJSON_AddStringToObject(jfields, "token", fields->token); - } - - cJSON_AddItemToObject(*requestP, "blade", jfields); - - return msgid; -} - -KS_DECLARE(ks_rpcmessageid_t) blade_rpc_create_response(cJSON *request, - cJSON **replyP, - cJSON **responseP) -{ - cJSON *jfields = cJSON_GetObjectItem(request, "blade"); - - if (!jfields) { - ks_log(KS_LOG_ERROR, "No blade routing info found. Unable to create response\n"); - return 0; - } - - ks_rpcmessageid_t msgid = ks_rpcmessage_create_response(request, replyP, responseP); - - if (!msgid || *responseP == NULL) { - ks_log(KS_LOG_ERROR, "Unable to create rpc response message\n"); //TODO : Add namespace, method from request - return 0; - } - - const char *to = cJSON_GetObjectCstr(jfields, "to"); - const char *from = cJSON_GetObjectCstr(jfields, "from"); - const char *token = cJSON_GetObjectCstr(jfields, "token"); - const char *version = cJSON_GetObjectCstr(jfields, "version"); - - cJSON *blade = cJSON_CreateObject(); - - if (to) { - cJSON_AddStringToObject(blade, "to", from); - } - - if (from) { - cJSON_AddStringToObject(blade, "from", to); - } - - if (token) { - cJSON_AddStringToObject(blade, "token", token); - } - - if (version) { - cJSON_AddStringToObject(blade, "version", version); - } - - cJSON_AddItemToObject(*responseP, "blade", blade); - - return msgid; -} - -KS_DECLARE(ks_rpcmessageid_t) blade_rpc_create_errorresponse(cJSON *request, - cJSON **errorP, - cJSON **responseP) -{ - ks_rpcmessageid_t msgid = blade_rpc_create_response(request, NULL, responseP); - - if (msgid) { - - if (errorP) { - - if (*errorP) { - cJSON_AddItemToObject(*responseP, "error", *errorP); - } - else { - cJSON *error = cJSON_CreateObject(); - cJSON_AddItemToObject(*responseP, "error", error); - *errorP = error; - } - } - } - - return msgid; -} - - -const char BLADE_JRPC_METHOD[] = "method"; -const char BLADE_JRPC_ID[] = "id"; -const char BLADE_JRPC_FIELDS[] = "blade"; -const char BLADE_JRPC_TO[] = "to"; -const char BLADE_JRPC_FROM[] = "from"; -const char BLADE_JRPC_TOKEN[] = "token"; -const char BLADE_JRPC_VERSION[] = "version"; - -KS_DECLARE(ks_status_t) blade_rpc_parse_message(cJSON *message, - char **namespaceP, - char **methodP, - char **versionP, - uint32_t *idP, - blade_rpc_fields_t **fieldsP) -{ - const char *m = cJSON_GetObjectCstr(message, BLADE_JRPC_METHOD); - cJSON *blade = cJSON_GetObjectItem(message, BLADE_JRPC_FIELDS); - cJSON *jid = cJSON_GetObjectItem(message, BLADE_JRPC_ID); - - *fieldsP = NULL; - *namespaceP = NULL; - *versionP = NULL; - *methodP = NULL; - *idP = 0; - - if (jid) { - *idP = jid->valueint; - } - - if (!m || !blade) { - const char *buffer = cJSON_PrintUnformatted(message); - ks_log(KS_LOG_ERROR, "Unable to locate necessary fields in message:\n%s\n", buffer); - ks_pool_free(g_handle->pool, buffer); - return KS_STATUS_FAIL; - } - - cJSON *jto = cJSON_GetObjectItem(blade, BLADE_JRPC_TO); - cJSON *jfrom = cJSON_GetObjectItem(blade, BLADE_JRPC_FROM); - cJSON *jtoken = cJSON_GetObjectItem(blade, BLADE_JRPC_TOKEN); - - - ks_size_t len = KS_RPCMESSAGE_COMMAND_LENGTH + 1 + - KS_RPCMESSAGE_NAMESPACE_LENGTH + 1 + - KS_RPCMESSAGE_VERSION_LENGTH + 1 + - sizeof(blade_rpc_fields_t) + 1; - - uint32_t lento = 0; - uint32_t lenfrom = 0; - uint32_t lentoken = 0; - - if (jto) { - lento = strlen(jto->valuestring) + 1; - len += lento; - } - - if (jfrom) { - lenfrom += strlen(jfrom->valuestring) + 1; - len += lenfrom; - } - - if (jtoken) { - lentoken += strlen(jtoken->valuestring) + 1; - len += lentoken; - } - - blade_rpc_fields_t *fields = (blade_rpc_fields_t *)ks_pool_alloc(g_handle->pool, len); - - char *namespace = (char*)fields + sizeof(blade_rpc_fields_t); - char *command = namespace + KS_RPCMESSAGE_NAMESPACE_LENGTH + 1; - char *version = command + KS_RPCMESSAGE_COMMAND_LENGTH + 1; - - char *ptr = version + KS_RPCMESSAGE_VERSION_LENGTH + 1; - - if (jto) { - strcpy(ptr, jto->valuestring); - fields->to = ptr; - ptr += strlen(jto->valuestring) + 1; - } - - if (jfrom) { - strcpy(ptr, jfrom->valuestring); - fields->from = ptr; - ptr += strlen(jfrom->valuestring) + 1; - } - - if (jtoken) { - strcpy(ptr, jtoken->valuestring); - fields->token = ptr; - ptr += strlen(jtoken->valuestring) + 1; - } - - blade_rpc_parse_fqcommand(m, namespace, command); - - strcpy(version, cJSON_GetObjectCstr(blade, BLADE_JRPC_VERSION)); - - *fieldsP = fields; - *namespaceP = namespace; - *methodP = command; - *versionP = version; - - return KS_STATUS_SUCCESS; -} - - -/* - * send message - * ------------ - */ - -KS_DECLARE(ks_status_t) blade_rpc_write_data(char *sessionid, char* data, uint32_t size) -{ - - ks_status_t s = KS_STATUS_FAIL; - - // convert to json - cJSON *msg = cJSON_Parse(data); - - if (msg) { - - // ks_status_t blade_peer_message_push(blade_peer_t *peer, void *data, int32_t data_length); - - s = KS_STATUS_SUCCESS; - } - else { - ks_log(KS_LOG_ERROR, "Unable to format outbound message\n"); - } - - - // ks_rpc_write_json - // ks_status_t blade_peer_message_push(blade_peer_t *peer, void *data, int32_t data_length); - return s; -} - - -KS_DECLARE(ks_status_t) blade_rpc_write_json(cJSON* json) -{ - // just push the messages onto the communication manager - // synchronization etc, taken care of by the transport api' - char *data = cJSON_PrintUnformatted(json); - if (data) { - ks_log(KS_LOG_DEBUG, "%s\n", data); - //return blade_rpc_write_data(sessionid, data, strlen(data)); - return KS_STATUS_SUCCESS; - } - ks_log(KS_LOG_ERROR, "Unable to parse json\n"); - return KS_STATUS_FAIL; -} - - - - -/* - * Transport layer callbacks follow below - * -*/ - - - - -/* - * rpc message processing - */ -static ks_status_t blade_rpc_process_jsonmessage_all(cJSON *request) -{ - const char *fqcommand = cJSON_GetObjectCstr(request, "method"); - cJSON *error = NULL; - cJSON *response = NULL; - cJSON *responseP = NULL; - - if (!fqcommand) { - error = cJSON_CreateObject(); - cJSON_AddStringToObject(error, "errormessage", "Command not specified"); - ks_rpcmessage_create_request("rpcprotocol", "unknowncommand", &error, &responseP); - blade_rpc_write_json(responseP); - return KS_STATUS_FAIL; - } - - - char namespace[KS_RPCMESSAGE_NAMESPACE_LENGTH]; - char command[KS_RPCMESSAGE_COMMAND_LENGTH]; - - blade_rpc_parse_fqcommand(fqcommand, namespace, command); - blade_rpc_callbackpair_t* callbacks = blade_rpc_find_callbacks_locked(namespace, command); - - if (!callbacks) { - error = cJSON_CreateObject(); - cJSON_AddStringToObject(error, "errormessage", "Command not supported"); - ks_rpcmessage_create_response(request, &error, &responseP); - blade_rpc_write_json(responseP); - return KS_STATUS_FAIL; - } - - //todo - add more checks ? - - ks_bool_t isrequest = ks_rpcmessage_isrequest(request); - - enum jrpc_status_t jrcs = 0; - - if (isrequest && callbacks->request_func) { - - cJSON *responseP = NULL; - - if (callbacks->custom && callbacks->custom->prefix_request_func) { - jrcs = callbacks->custom->prefix_request_func(request, &responseP); - if ( (jrcs & JRPC_SEND) && responseP) { - blade_rpc_write_json(responseP); - cJSON_Delete(responseP); - responseP = NULL; - } - } - - if ( !(jrcs & JRPC_EXIT) && jrcs != JRPC_ERROR) { - jrcs = callbacks->request_func(request, &responseP); - if ((jrcs & JRPC_SEND) && responseP) { - blade_rpc_write_json(responseP); - cJSON_Delete(responseP); - responseP = NULL; - } - } - - if ( !(jrcs & JRPC_EXIT) && jrcs != JRPC_ERROR && callbacks->custom && callbacks->custom->postfix_request_func) { - jrcs = callbacks->custom->postfix_request_func(request, &responseP); - if ( (jrcs & JRPC_SEND) && responseP) { - blade_rpc_write_json(responseP); - cJSON_Delete(responseP); - responseP = NULL; - } - } - - ks_mutex_unlock(callbacks->lock); - - if (jrcs == JRPC_ERROR) { - return KS_STATUS_FAIL; - } - - return KS_STATUS_SUCCESS; - } - else if (!isrequest && callbacks->response_func) { - - if (callbacks->custom && callbacks->custom->prefix_response_func) { - jrcs = callbacks->custom->prefix_response_func(response, &responseP); - if ( (jrcs & JRPC_SEND) && responseP) { - blade_rpc_write_json(responseP); - cJSON_Delete(responseP); - responseP = NULL; - } - } - - if ( !(jrcs & JRPC_EXIT) && jrcs != JRPC_ERROR) { - jrcs = callbacks->response_func(response, &responseP); - if ( (jrcs & JRPC_SEND) && responseP) { - blade_rpc_write_json(responseP); - cJSON_Delete(responseP); - responseP = NULL; - } - } - - if ( !(jrcs & JRPC_EXIT) && jrcs != JRPC_ERROR && callbacks->custom && callbacks->custom->postfix_response_func) { - jrcs = callbacks->custom->postfix_response_func(response, &responseP); - if ( (jrcs & JRPC_SEND) && responseP) { - blade_rpc_write_json(responseP); - cJSON_Delete(responseP); - responseP = NULL; - } - } - - ks_mutex_unlock(callbacks->lock); - - if (jrcs == JRPC_ERROR) { - return KS_STATUS_FAIL; - } - - return KS_STATUS_SUCCESS; - } - - ks_log(KS_LOG_ERROR, "Unable to find message handler for %s\n", command); - - return KS_STATUS_FAIL; -} - -/* - * -*/ -KS_DECLARE(ks_status_t) blade_rpc_process_jsonmessage(cJSON *request) -{ - ks_status_t respstatus = blade_rpc_process_jsonmessage_all(request); - return respstatus; -} - -KS_DECLARE(ks_status_t) blade_rpc_process_data(const uint8_t *data, - ks_size_t size) -{ - - cJSON *json = cJSON_Parse((const char*)data); - if (json != NULL) { - ks_log( KS_LOG_ERROR, "Unable to parse message\n"); - return KS_STATUS_FAIL; - } - - /* deal with rpc message */ - if (ks_rpcmessage_isrpc(json)) { - ks_status_t respstatus = blade_rpc_process_jsonmessage_all(json); - return respstatus; - } - - ks_log(KS_LOG_ERROR, "Unable to identify message type\n"); - - return KS_STATUS_FAIL; -} - -//KS_DECLARE(ks_status_t) blade_rpc_process_blademessage(blade_message_t *message) -//{ -// uint8_t* data = NULL; -// ks_size_t size = 0; -// -// blade_message_get(message, (void **)&data, &size); -// -// if (data && size>0) { -// ks_status_t s = blade_rpc_process_data(data, size); -// blade_message_discard(&message); -// return s; -// } -// -// ks_log(KS_LOG_ERROR, "Message read failed\n"); -// return KS_STATUS_FAIL; -// -//} - - -/* 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_session.c b/libs/libblade/src/blade_session.c index 58c9b323d1..048baec183 100644 --- a/libs/libblade/src/blade_session.c +++ b/libs/libblade/src/blade_session.c @@ -430,6 +430,7 @@ ks_status_t blade_session_state_on_destroy(blade_session_t *bs) ks_assert(bs); ks_log(KS_LOG_DEBUG, "Session (%s) state destroy\n", bs->id); + blade_handle_sessions_remove(bs); blade_session_destroy(&bs); @@ -483,21 +484,31 @@ ks_status_t blade_session_state_on_ready(blade_session_t *bs) } -KS_DECLARE(ks_status_t) blade_session_send(blade_session_t *bs, cJSON *json) +KS_DECLARE(ks_status_t) blade_session_send(blade_session_t *bs, cJSON *json, blade_response_callback_t callback) { blade_request_t *request = NULL; const char *method = NULL; + const char *id = NULL; ks_assert(bs); ks_assert(json); method = cJSON_GetObjectCstr(json, "method"); + id = cJSON_GetObjectCstr(json, "id"); if (method) { - blade_request_create(&request, bs->handle, bs->id, json); + // @note This is scenario 1 + // 1) Sending a request (client: method caller or consumer) + ks_log(KS_LOG_DEBUG, "Session (%s) sending request (%s) for %s\n", bs->id, id, method); + + blade_request_create(&request, bs->handle, bs->id, json, callback); ks_assert(request); // @todo set request TTL and figure out when requests are checked for expiration (separate thread in the handle?) blade_handle_requests_add(request); + } else { + // @note This is scenario 3 + // 3) Sending a response or error (server: method callee or provider) + ks_log(KS_LOG_DEBUG, "Session (%s) sending response (%s)\n", bs->id, id); } if (list_empty(&bs->connections)) { @@ -516,20 +527,18 @@ KS_DECLARE(ks_status_t) blade_session_send(blade_session_t *bs, cJSON *json) ks_status_t blade_session_process(blade_session_t *bs, cJSON *json) { - ks_status_t ret = KS_STATUS_SUCCESS; blade_request_t *breq = NULL; blade_response_t *bres = NULL; const char *jsonrpc = NULL; const char *id = NULL; const char *method = NULL; + ks_bool_t disconnect = KS_FALSE; ks_assert(bs); ks_assert(json); ks_log(KS_LOG_DEBUG, "Session (%s) processing\n", bs->id); - // @todo teardown the message, convert into a blade_request_t or blade_response_t - // @todo validate the jsonrpc fields jsonrpc = cJSON_GetObjectCstr(json, "jsonrpc"); if (!jsonrpc || strcmp(jsonrpc, "2.0")) { @@ -549,13 +558,50 @@ ks_status_t blade_session_process(blade_session_t *bs, cJSON *json) method = cJSON_GetObjectCstr(json, "method"); if (method) { - // @todo use method to find RPC callbacks + // @note This is scenario 2 + // 2) Receiving a request (server: method callee or provider) + blade_space_t *tmp_space = NULL; + blade_method_t *tmp_method = NULL; + blade_request_callback_t callback = NULL; + char *space_name = ks_pstrdup(bs->pool, method); + char *method_name = strrchr(space_name, '.'); - blade_request_create(&breq, bs->handle, bs->id, json); + ks_log(KS_LOG_DEBUG, "Session (%s) receiving request (%s) for %s\n", bs->id, id, method); + + if (!method_name || method_name == space_name) { + ks_pool_free(bs->pool, (void **)&space_name); + // @todo send error response, code = -32601 (method not found) + // @todo hangup session entirely? + return KS_STATUS_FAIL; + } + *method_name = '\0'; + method_name++; // @todo check if can be postfixed safely on previous assignment, can't recall + + tmp_space = blade_handle_space_lookup(bs->handle, space_name); + if (tmp_space) tmp_method = blade_space_methods_get(tmp_space, method_name); + + ks_pool_free(bs->pool, (void **)&space_name); + + if (!tmp_method) { + // @todo send error response, code = -32601 (method not found) + // @todo hangup session entirely? + return KS_STATUS_FAIL; + } + callback = blade_method_callback_get(tmp_method); + ks_assert(callback); + + blade_request_create(&breq, bs->handle, bs->id, json, NULL); ks_assert(breq); - // @todo call request callback handler + disconnect = callback(breq); + + blade_request_destroy(&breq); } else { + // @note This is scenario 4 + // 4) Receiving a response or error (client: method caller or consumer) + + ks_log(KS_LOG_DEBUG, "Session (%s) receiving response (%s)\n", bs->id, id); + breq = blade_handle_requests_get(bs->handle, id); if (!breq) { // @todo hangup session entirely? @@ -563,18 +609,20 @@ ks_status_t blade_session_process(blade_session_t *bs, cJSON *json) } blade_handle_requests_remove(breq); - method = cJSON_GetObjectCstr(breq->message, "method"); - ks_assert(method); - - // @todo use method to find RPC callbacks - blade_response_create(&bres, bs->handle, bs->id, breq, json); ks_assert(bres); - // @todo call response callback handler + disconnect = breq->callback(bres); + + blade_response_destroy(&bres); } - return ret; + if (disconnect) { + // @todo hangup session entirely? + return KS_STATUS_FAIL; + } + + return KS_STATUS_SUCCESS; } /* For Emacs: diff --git a/libs/libblade/src/blade_space.c b/libs/libblade/src/blade_space.c new file mode 100644 index 0000000000..09a8574c4c --- /dev/null +++ b/libs/libblade/src/blade_space.c @@ -0,0 +1,176 @@ +/* + * 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_space_s { + blade_handle_t *handle; + ks_pool_t *pool; + + const char *path; + ks_hash_t *methods; +}; + + +KS_DECLARE(ks_status_t) blade_space_create(blade_space_t **bsP, blade_handle_t *bh, const char *path) +{ + blade_space_t *bs = NULL; + ks_pool_t *pool = NULL; + + ks_assert(bsP); + ks_assert(bh); + ks_assert(path); + + pool = blade_handle_pool_get(bh); + + bs = ks_pool_alloc(pool, sizeof(blade_space_t)); + bs->handle = bh; + bs->pool = pool; + bs->path = path; // @todo dup and keep copy? should mostly be literals + ks_hash_create(&bs->methods, KS_HASH_MODE_CASE_INSENSITIVE, KS_HASH_FLAG_NOLOCK | KS_HASH_FLAG_DUP_CHECK, bs->pool); + ks_assert(bs); + + *bsP = bs; + + ks_log(KS_LOG_DEBUG, "Space Created: %s\n", path); + + return KS_STATUS_SUCCESS; +} + +KS_DECLARE(ks_status_t) blade_space_destroy(blade_space_t **bsP) +{ + blade_space_t *bs = NULL; + ks_hash_iterator_t *it = NULL; + + ks_assert(bsP); + ks_assert(*bsP); + + bs = *bsP; + + for (it = ks_hash_first(bs->methods, KS_UNLOCKED); it; it = ks_hash_next(&it)) { + void *key = NULL; + blade_method_t *value = NULL; + + ks_hash_this(it, (const void **)&key, NULL, (void **)&value); + blade_method_destroy(&value); + } + + ks_hash_destroy(&bs->methods); + + ks_log(KS_LOG_DEBUG, "Space Destroyed: %s\n", bs->path); + + ks_pool_free(bs->pool, bsP); + + return KS_STATUS_SUCCESS; +} + +KS_DECLARE(blade_handle_t *) blade_space_handle_get(blade_space_t *bs) +{ + ks_assert(bs); + + return bs->handle; +} + +KS_DECLARE(const char *) blade_space_path_get(blade_space_t *bs) +{ + ks_assert(bs); + + return bs->path; +} + +KS_DECLARE(ks_status_t) blade_space_methods_add(blade_space_t *bs, blade_method_t *bm) +{ + ks_status_t ret = KS_STATUS_SUCCESS; + const char *name = NULL; + blade_method_t *bm_old = NULL; + + ks_assert(bs); + ks_assert(bm); + + name = blade_method_name_get(bm); + ks_assert(name); + + ks_hash_write_lock(bs->methods); + bm_old = ks_hash_search(bs->methods, (void *)name, KS_UNLOCKED); + if (bm_old) ks_hash_remove(bs->methods, (void *)name); + ret = ks_hash_insert(bs->methods, (void *)name, (void *)bm); + ks_hash_write_unlock(bs->methods); + + if (bm_old) blade_method_destroy(&bm_old); + + return ret; +} + +KS_DECLARE(ks_status_t) blade_space_methods_remove(blade_space_t *bs, blade_method_t *bm) +{ + ks_status_t ret = KS_STATUS_SUCCESS; + const char *name = NULL; + + ks_assert(bs); + ks_assert(bm); + + name = blade_method_name_get(bm); + ks_assert(name); + + ks_hash_write_lock(bs->methods); + ks_hash_remove(bs->methods, (void *)name); + ks_hash_write_unlock(bs->methods); + + return ret; +} + +KS_DECLARE(blade_method_t *) blade_space_methods_get(blade_space_t *bs, const char *name) +{ + blade_method_t *bm = NULL; + + ks_assert(bs); + ks_assert(name); + + ks_hash_read_lock(bs->methods); + bm = ks_hash_search(bs->methods, (void *)name, KS_UNLOCKED); + ks_hash_read_unlock(bs->methods); + + return bm; +} + + +/* 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 56357344ce..697a8d9feb 100644 --- a/libs/libblade/src/blade_stack.c +++ b/libs/libblade/src/blade_stack.c @@ -48,6 +48,7 @@ struct blade_handle_s { config_setting_t *config_datastore; ks_hash_t *transports; // registered transports exposed by modules, NOT active connections + ks_hash_t *spaces; // registered method spaces exposed by modules //blade_identity_t *identity; blade_datastore_t *datastore; @@ -69,6 +70,7 @@ struct blade_handle_transport_registration_s { blade_transport_callbacks_t *callbacks; }; + KS_DECLARE(ks_status_t) blade_handle_transport_registration_create(blade_handle_transport_registration_t **bhtrP, ks_pool_t *pool, blade_module_t *module, @@ -133,6 +135,8 @@ KS_DECLARE(ks_status_t) blade_handle_create(blade_handle_t **bhP, ks_pool_t *poo ks_hash_create(&bh->transports, KS_HASH_MODE_CASE_INSENSITIVE, KS_HASH_FLAG_NOLOCK | KS_HASH_FLAG_DUP_CHECK, bh->pool); ks_assert(bh->transports); + ks_hash_create(&bh->spaces, KS_HASH_MODE_CASE_INSENSITIVE, KS_HASH_FLAG_NOLOCK | KS_HASH_FLAG_DUP_CHECK, bh->pool); + ks_assert(bh->spaces); ks_hash_create(&bh->connections, KS_HASH_MODE_CASE_INSENSITIVE, KS_HASH_FLAG_NOLOCK | KS_HASH_FLAG_DUP_CHECK, bh->pool); ks_assert(bh->connections); @@ -144,6 +148,8 @@ KS_DECLARE(ks_status_t) blade_handle_create(blade_handle_t **bhP, ks_pool_t *poo *bhP = bh; + ks_log(KS_LOG_DEBUG, "Created\n"); + return KS_STATUS_SUCCESS; } @@ -168,10 +174,13 @@ KS_DECLARE(ks_status_t) blade_handle_destroy(blade_handle_t **bhP) ks_hash_destroy(&bh->requests); ks_hash_destroy(&bh->sessions); ks_hash_destroy(&bh->connections); + ks_hash_destroy(&bh->spaces); ks_hash_destroy(&bh->transports); if (bh->tpool && (flags & BH_MYTPOOL)) ks_thread_pool_destroy(&bh->tpool); + ks_log(KS_LOG_DEBUG, "Destroyed\n"); + ks_pool_free(bh->pool, &bh); if (pool && (flags & BH_MYPOOL)) { @@ -249,13 +258,22 @@ KS_DECLARE(ks_status_t) blade_handle_shutdown(blade_handle_t *bh) blade_session_t *value = NULL; ks_hash_this(it, (const void **)&key, NULL, (void **)&value); - ks_hash_remove(bh->requests, key); + //ks_hash_remove(bh->sessions, key); blade_session_hangup(value); } while (ks_hash_count(bh->sessions) > 0) ks_sleep_ms(100); - // @todo call onshutdown and onunload callbacks for modules from DSOs, which will unregister transports and disconnect remaining unattached connections + // @todo call onshutdown and onunload callbacks for modules from DSOs, which will unregister transports and spaces, and will disconnect remaining + // unattached connections + + for (it = ks_hash_first(bh->spaces, KS_UNLOCKED); it; it = ks_hash_next(&it)) { + void *key = NULL; + blade_space_t *value = NULL; + + ks_hash_this(it, (const void **)&key, NULL, (void **)&value); + blade_handle_space_unregister(value); + } // @todo unload DSOs @@ -316,11 +334,81 @@ KS_DECLARE(ks_status_t) blade_handle_transport_unregister(blade_handle_t *bh, co if (bhtr) ks_hash_remove(bh->transports, (void *)name); ks_hash_write_unlock(bh->transports); - if (bhtr) blade_handle_transport_registration_destroy(&bhtr); + if (bhtr) { + blade_handle_transport_registration_destroy(&bhtr); + ks_log(KS_LOG_DEBUG, "Transport Unregistered: %s\n", name); + } return KS_STATUS_SUCCESS; } +KS_DECLARE(ks_status_t) blade_handle_space_register(blade_space_t *bs) +{ + blade_handle_t *bh = NULL; + const char *path = NULL; + blade_space_t *bs_old = NULL; + + ks_assert(bs); + + bh = blade_space_handle_get(bs); + ks_assert(bh); + + path = blade_space_path_get(bs); + ks_assert(path); + + ks_hash_write_lock(bh->spaces); + bs_old = ks_hash_search(bh->spaces, (void *)path, KS_UNLOCKED); + if (bs_old) ks_hash_remove(bh->spaces, (void *)path); + ks_hash_insert(bh->spaces, (void *)path, bs); + ks_hash_write_unlock(bh->spaces); + + if (bs_old) blade_space_destroy(&bs_old); + + ks_log(KS_LOG_DEBUG, "Space Registered: %s\n", path); + + return KS_STATUS_SUCCESS; +} + +KS_DECLARE(ks_status_t) blade_handle_space_unregister(blade_space_t *bs) +{ + blade_handle_t *bh = NULL; + const char *path = NULL; + + ks_assert(bs); + + bh = blade_space_handle_get(bs); + ks_assert(bh); + + path = blade_space_path_get(bs); + ks_assert(path); + + ks_hash_write_lock(bh->spaces); + bs = ks_hash_search(bh->spaces, (void *)path, KS_UNLOCKED); + if (bs) ks_hash_remove(bh->spaces, (void *)path); + ks_hash_write_unlock(bh->spaces); + + if (bs) { + blade_space_destroy(&bs); + ks_log(KS_LOG_DEBUG, "Space Unregistered: %s\n", path); + } + + return KS_STATUS_SUCCESS; +} + +KS_DECLARE(blade_space_t *) blade_handle_space_lookup(blade_handle_t *bh, const char *path) +{ + blade_space_t *bs = NULL; + + ks_assert(bh); + ks_assert(path); + + ks_hash_read_lock(bh->spaces); + bs = ks_hash_search(bh->spaces, (void *)path, KS_UNLOCKED); + ks_hash_read_unlock(bh->spaces); + + return bs; +} + KS_DECLARE(ks_status_t) blade_handle_connect(blade_handle_t *bh, blade_connection_t **bcP, blade_identity_t *target, const char *session_id) { ks_status_t ret = KS_STATUS_SUCCESS; diff --git a/libs/libblade/src/bpcp.c b/libs/libblade/src/bpcp.c deleted file mode 100644 index f61180ae64..0000000000 --- a/libs/libblade/src/bpcp.c +++ /dev/null @@ -1,108 +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" - - -/* - -Find bootstrap addr. -Make a WSS connection to get validated and get group keys. -Broadcast/Announce existence. - - -HEADER - - 0 1 2 3 - 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 -+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -| Ver |r|R|U|U| Channel no | Packet Length | -+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -| SEQ | -+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -| PAYLOAD ...... | -+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - -r = IS Response -R = IS Retransmission -U = Unused - -PAYLOAD - - 0 1 2 3 - 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 -+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -| Instruction | Datatype | Length | -+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -| PAYLOAD ..... | -+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - - - */ - - -typedef struct bpcp_header_s { - uint32_t header; - uint64_t seq; -} bpcp_header_t; - -typedef struct bpcp_channel_nfo_s { - char *channel_name; - unsigned char key[crypto_generichash_BYTES]; - uint32_t ttl; -} bpcp_channel_nfo_t; - -typedef struct bpcp_handle_s { - ks_socket_t sock; - ks_sockaddr_t local_addr; - ks_sockaddr_t bootstrap_addr; - ks_hash_t *channel_nfo_hash; -} bpcp_handle_t; - -KS_DECLARE(ks_status_t) bpcp_create(bpcp_handle_t **handle, - const char *local_addr, ks_port_t local_port, - const char *bootstrap_addr, ks_port_t bootstrap_port) -{ - 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/include/blade.h b/libs/libblade/src/include/blade.h index 54d744657a..c94c085511 100644 --- a/libs/libblade/src/include/blade.h +++ b/libs/libblade/src/include/blade.h @@ -1,23 +1,23 @@ /* * 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 @@ -46,7 +46,8 @@ #include "blade_session.h" #include "blade_protocol.h" #include "blade_datastore.h" -#include "bpcp.h" +#include "blade_space.h" +#include "blade_method.h" KS_BEGIN_EXTERN_C diff --git a/libs/libblade/src/include/bpcp.h b/libs/libblade/src/include/blade_method.h similarity index 79% rename from libs/libblade/src/include/bpcp.h rename to libs/libblade/src/include/blade_method.h index 46a648abbe..74bf87d13f 100644 --- a/libs/libblade/src/include/bpcp.h +++ b/libs/libblade/src/include/blade_method.h @@ -1,23 +1,23 @@ /* - * 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 * 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 @@ -31,12 +31,15 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef _BPCP_H_ -#define _BPCP_H_ +#ifndef _BLADE_METHOD_H_ +#define _BLADE_METHOD_H_ #include KS_BEGIN_EXTERN_C - +KS_DECLARE(ks_status_t) blade_method_create(blade_method_t **bmP, blade_space_t *bs, const char *name, blade_request_callback_t callback); +KS_DECLARE(ks_status_t) blade_method_destroy(blade_method_t **bmP); +KS_DECLARE(const char *) blade_method_name_get(blade_method_t *bm); +KS_DECLARE(blade_request_callback_t) blade_method_callback_get(blade_method_t *bm); KS_END_EXTERN_C #endif diff --git a/libs/libblade/src/include/blade_protocol.h b/libs/libblade/src/include/blade_protocol.h index ddc4a3cdee..0d3b4c772f 100644 --- a/libs/libblade/src/include/blade_protocol.h +++ b/libs/libblade/src/include/blade_protocol.h @@ -36,10 +36,17 @@ #include KS_BEGIN_EXTERN_C -KS_DECLARE(ks_status_t) blade_request_create(blade_request_t **breqP, blade_handle_t *bh, const char *session_id, cJSON *json); +KS_DECLARE(ks_status_t) blade_request_create(blade_request_t **breqP, + blade_handle_t *bh, + const char *session_id, + cJSON *json, + blade_response_callback_t callback); KS_DECLARE(ks_status_t) blade_request_destroy(blade_request_t **breqP); KS_DECLARE(ks_status_t) blade_response_create(blade_response_t **bresP, blade_handle_t *bh, const char *session_id, blade_request_t *breq, cJSON *json); KS_DECLARE(ks_status_t) blade_response_destroy(blade_response_t **bresP); +KS_DECLARE(ks_status_t) blade_rpc_request_create(ks_pool_t *pool, cJSON **json, cJSON **params, const char **id, const char *method); +KS_DECLARE(ks_status_t) blade_rpc_response_create(ks_pool_t *pool, cJSON **json, cJSON **result, const char *id); +KS_DECLARE(ks_status_t) blade_rpc_error_create(ks_pool_t *pool, cJSON **json, cJSON **error, const char *id, int32_t code, const char *message); KS_END_EXTERN_C #endif diff --git a/libs/libblade/src/include/blade_rpcproto.h b/libs/libblade/src/include/blade_rpcproto.h deleted file mode 100644 index f108c981e6..0000000000 --- a/libs/libblade/src/include/blade_rpcproto.h +++ /dev/null @@ -1,166 +0,0 @@ -/* - * Copyright (c) 2017, FreeSWITCH LLC - * 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_RPCPROTO_H_ -#define _BLADE_RPCPROTO_H_ - -#include -#include - -// temp typedefs to get compile going -//typedef struct blade_peer_s blade_peer_t; -//typedef struct blade_event_s blade_event_t; - -#define KS_RPCMESSAGE_NAMESPACE_LENGTH 16 -#define KS_RPCMESSAGE_COMMAND_LENGTH 238 -#define KS_RPCMESSAGE_FQCOMMAND_LENGTH (KS_RPCMESSAGE_NAMESPACE_LENGTH+KS_RPCMESSAGE_COMMAND_LENGTH+1) -#define KS_RPCMESSAGE_VERSION_LENGTH 9 - - -/* - * contents to add to the "blade" field in rpc - */ - -typedef struct blade_rpc_fields_s { - - const char *to; - const char *from; - const char *token; - -} blade_rpc_fields_t; - - - -enum jrpc_status_t { - JRPC_PASS = (1 << 0), - JRPC_SEND = (1 << 1), - JRPC_EXIT = (1 << 2), - JRPC_SEND_EXIT = JRPC_SEND + JRPC_EXIT, - JRPC_ERROR = (1 << 3) -}; - - -typedef enum jrpc_status_t (*jrpc_func_t) (cJSON *request, cJSON **replyP); - - -/* - * setup - * ----- - */ - -KS_DECLARE(ks_status_t) blade_rpc_init(ks_pool_t *pool); - - -/* - * namespace and call back registration - * ------------------------------------ - */ -KS_DECLARE(ks_status_t) blade_rpc_declare_namespace(char* namespace, const char* version); -KS_DECLARE(ks_status_t) blade_rpc_register_function(char* namespace, - char *command, - jrpc_func_t func, - jrpc_func_t respfunc); -KS_DECLARE(ks_status_t) blade_rpc_register_custom_request_function(char* namespace, - char *command, - jrpc_func_t prefix_func, - jrpc_func_t postfix_func); -KS_DECLARE(ks_status_t) blade_rpc_register_custom_response_function(char *namespace, - char *command, - jrpc_func_t prefix_func, - jrpc_func_t postfix_func); -KS_DECLARE(void) blade_rpc_remove_namespace(char* namespace); - -/* - * template registration and inheritance - * ------------------------------------- - */ -KS_DECLARE(ks_status_t) blade_rpc_declare_template(char* templatename, const char* version); - -KS_DECLARE(ks_status_t)blade_rpc_register_template_function(char *name, - char *command, - jrpc_func_t func, - jrpc_func_t respfunc); - -KS_DECLARE(ks_status_t)blade_rpc_inherit_template(char *namespace, char* template); - - -/* - * create a request message - */ -KS_DECLARE(ks_rpcmessageid_t) blade_rpc_create_request(char *namespace, - char *method, - blade_rpc_fields_t* fields, - cJSON **paramsP, - cJSON **requestP); - -KS_DECLARE(ks_rpcmessageid_t) blade_rpc_create_response(cJSON *request, - cJSON **reply, - cJSON **response); - -KS_DECLARE(ks_rpcmessageid_t) blade_rpc_create_errorresponse(cJSON *request, - cJSON **reply, - cJSON **response); - -KS_DECLARE(ks_status_t) blade_rpc_parse_message(cJSON *message, - char **namespace, - char **method, - char **version, - uint32_t *idP, - blade_rpc_fields_t **fieldsP); - -/* - * peer create/destroy - * ------------------- - */ -//KS_DECLARE(ks_status_t) blade_rpc_onconnect(ks_pool_t *pool, blade_peer_t* peer); -//KS_DECLARE(ks_status_t) blade_rpc_disconnect(blade_peer_t* peer); - -/* - * send message - * ------------ - */ -KS_DECLARE(ks_status_t) blade_rpc_write(char *sessionid, char* data, uint32_t size); //uuid_t ? -KS_DECLARE(ks_status_t) blade_rpc_write_json(cJSON* json); - - -/* - * process inbound message - * ----------------------- - */ -KS_DECLARE(ks_status_t) blade_rpc_process_data(const uint8_t *data, ks_size_t size); - -KS_DECLARE(ks_status_t) blade_rpc_process_jsonmessage(cJSON *request); - - -#endif - diff --git a/libs/libblade/src/include/blade_session.h b/libs/libblade/src/include/blade_session.h index f4e92775b3..e79fbf34b0 100644 --- a/libs/libblade/src/include/blade_session.h +++ b/libs/libblade/src/include/blade_session.h @@ -1,23 +1,23 @@ /* * 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 @@ -52,7 +52,7 @@ KS_DECLARE(void) blade_session_hangup(blade_session_t *bs); KS_DECLARE(ks_bool_t) blade_session_terminating(blade_session_t *bs); KS_DECLARE(ks_status_t) blade_session_connections_add(blade_session_t *bs, const char *id); KS_DECLARE(ks_status_t) blade_session_connections_remove(blade_session_t *bs, const char *id); -KS_DECLARE(ks_status_t) blade_session_send(blade_session_t *bs, cJSON *json); +KS_DECLARE(ks_status_t) blade_session_send(blade_session_t *bs, cJSON *json, blade_response_callback_t callback); KS_DECLARE(ks_status_t) blade_session_sending_push(blade_session_t *bs, cJSON *json); KS_DECLARE(ks_status_t) blade_session_sending_pop(blade_session_t *bs, cJSON **json); KS_DECLARE(ks_status_t) blade_session_receiving_push(blade_session_t *bs, cJSON *json); diff --git a/libs/libks/src/include/ks_rpcmessage.h b/libs/libblade/src/include/blade_space.h similarity index 52% rename from libs/libks/src/include/ks_rpcmessage.h rename to libs/libblade/src/include/blade_space.h index da2157e9d0..65664fdba5 100644 --- a/libs/libks/src/include/ks_rpcmessage.h +++ b/libs/libblade/src/include/blade_space.h @@ -1,23 +1,23 @@ /* - * Copyright (c) 2017, FreeSWITCH Solutions LLC + * 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 @@ -31,56 +31,21 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ - -#ifndef _KS_RPCMESSAGE_H_ -#define _KS_RPCMESSAGE_H_ - -#include "ks.h" +#ifndef _BLADE_SPACE_H_ +#define _BLADE_SPACE_H_ +#include KS_BEGIN_EXTERN_C - -#define KS_RPCMESSAGE_NAMESPACE_LENGTH 16 -#define KS_RPCMESSAGE_COMMAND_LENGTH 238 -#define KS_RPCMESSAGE_FQCOMMAND_LENGTH (KS_RPCMESSAGE_NAMESPACE_LENGTH+KS_RPCMESSAGE_COMMAND_LENGTH+1) -#define KS_RPCMESSAGE_VERSION_LENGTH 9 - - -typedef uint32_t ks_rpcmessageid_t; - - -KS_DECLARE(void) ks_rpcmessage_init(ks_pool_t *pool); - -KS_DECLARE(void*) ks_json_pool_alloc(ks_size_t size); -KS_DECLARE(void) ks_json_pool_free(void *ptr); - - -KS_DECLARE(ks_rpcmessageid_t) ks_rpcmessage_create_request(char *namespace, - char *method, - cJSON **paramsP, - cJSON **requestP); - -KS_DECLARE(ks_size_t) ks_rpc_create_buffer(char *namespace, - char *method, - cJSON **paramsP, - ks_buffer_t *buffer); - -KS_DECLARE(ks_rpcmessageid_t) ks_rpcmessage_create_response( - const cJSON *request, - cJSON **resultP, - cJSON **responseP); - -KS_DECLARE(ks_rpcmessageid_t) ks_rpcmessage_create_errorresponse( - const cJSON *request, - cJSON **errorP, - cJSON **responseP); - -KS_DECLARE(ks_bool_t) ks_rpcmessage_isrequest(cJSON *msg); - -KS_DECLARE(ks_bool_t) ks_rpcmessage_isrpc(cJSON *msg); - +KS_DECLARE(ks_status_t) blade_space_create(blade_space_t **bsP, blade_handle_t *bh, const char *path); +KS_DECLARE(ks_status_t) blade_space_destroy(blade_space_t **bsP); +KS_DECLARE(blade_handle_t *) blade_space_handle_get(blade_space_t *bs); +KS_DECLARE(const char *) blade_space_path_get(blade_space_t *bs); +KS_DECLARE(ks_status_t) blade_space_methods_add(blade_space_t *bs, blade_method_t *bm); +KS_DECLARE(ks_status_t) blade_space_methods_remove(blade_space_t *bs, blade_method_t *bm); +KS_DECLARE(blade_method_t *) blade_space_methods_get(blade_space_t *bs, const char *name); KS_END_EXTERN_C -#endif /* defined(_KS_RPCMESSAGE_H_) */ +#endif /* For Emacs: * Local Variables: diff --git a/libs/libblade/src/include/blade_stack.h b/libs/libblade/src/include/blade_stack.h index ff86af388e..27b45bf93f 100644 --- a/libs/libblade/src/include/blade_stack.h +++ b/libs/libblade/src/include/blade_stack.h @@ -50,6 +50,11 @@ KS_DECLARE(ks_thread_pool_t *) blade_handle_tpool_get(blade_handle_t *bh); KS_DECLARE(ks_status_t) blade_handle_transport_register(blade_handle_t *bh, blade_module_t *bm, const char *name, blade_transport_callbacks_t *callbacks); KS_DECLARE(ks_status_t) blade_handle_transport_unregister(blade_handle_t *bh, const char *name); + +KS_DECLARE(ks_status_t) blade_handle_space_register(blade_space_t *bs); +KS_DECLARE(ks_status_t) blade_handle_space_unregister(blade_space_t *bs); +KS_DECLARE(blade_space_t *) blade_handle_space_lookup(blade_handle_t *bh, const char *path); + KS_DECLARE(ks_status_t) blade_handle_connect(blade_handle_t *bh, blade_connection_t **bcP, blade_identity_t *target, const char *session_id); KS_DECLARE(blade_connection_t *) blade_handle_connections_get(blade_handle_t *bh, const char *cid); diff --git a/libs/libblade/src/include/blade_types.h b/libs/libblade/src/include/blade_types.h index 295217979d..14c908f857 100644 --- a/libs/libblade/src/include/blade_types.h +++ b/libs/libblade/src/include/blade_types.h @@ -47,6 +47,12 @@ typedef struct blade_connection_s blade_connection_t; typedef struct blade_session_s blade_session_t; typedef struct blade_request_s blade_request_t; typedef struct blade_response_s blade_response_t; +typedef struct blade_space_s blade_space_t; +typedef struct blade_method_s blade_method_t; + + +typedef ks_bool_t (*blade_request_callback_t)(blade_request_t *breq); +typedef ks_bool_t (*blade_response_callback_t)(blade_response_t *bres); typedef struct blade_datastore_s blade_datastore_t; @@ -147,6 +153,7 @@ struct blade_request_s { cJSON *message; const char *message_id; // pulled from message for easier keying + blade_response_callback_t callback; // @todo ttl to wait for response before injecting an error response locally // @todo rpc response callback }; diff --git a/libs/libblade/test/Makefile.am b/libs/libblade/test/Makefile.am index e6c8c3902f..328a71ef25 100644 --- a/libs/libblade/test/Makefile.am +++ b/libs/libblade/test/Makefile.am @@ -1,13 +1,8 @@ -AM_CFLAGS += -I$(abs_top_srcdir)/src/include -g -ggdb -O0 +AM_CFLAGS += -I$(abs_top_srcdir)/src/include -g -ggdb -O0 TEST_LDADD = $(abs_top_builddir)/libblade.la -lconfig -lm -lpthread check_PROGRAMS = -check_PROGRAMS += testrpcproto -testrpcproto_SOURCES = testrpcproto.c tap.c -testrpcproto_CFLAGS = $(AM_CFLAGS) -testrpcproto_LDADD = $(TEST_LDADD) - check_PROGRAMS += testbuild testbuild_SOURCES = testbuild.c tap.c testbuild_CFLAGS = $(AM_CFLAGS) diff --git a/libs/libblade/test/testrpcproto.c b/libs/libblade/test/testrpcproto.c deleted file mode 100644 index 2b5f28252f..0000000000 --- a/libs/libblade/test/testrpcproto.c +++ /dev/null @@ -1,724 +0,0 @@ -#pragma GCC diagnostic ignored "-Wunused-but-set-variable" -#pragma GCC diagnostic ignored "-Wunused-variable" -#pragma GCC diagnostic ignored "-Wunused-function" - - -#include - -#pragma GCC optimize ("O0") - - -ks_pool_t *pool; -ks_thread_pool_t *tpool; - - -static ks_thread_t *threads[10]; - -static char idbuffer[51]; - - - -static enum jrpc_status_t process_widget(cJSON *msg, cJSON **response) -{ - printf("entering process_widget\n"); - - char *b0 = cJSON_PrintUnformatted(msg); - printf("Request: %s\n", b0); - ks_pool_free(pool, &b0); - - cJSON *resp = cJSON_CreateObject(); - cJSON_AddNumberToObject(resp, "code", 199); - - //ks_rpcmessageid_t msgid = ks_rpcmessage_create_response(msg, &resp, response); - ks_rpcmessageid_t msgid = blade_rpc_create_response(msg, &resp, response); - - char *b1 = cJSON_PrintUnformatted(*response); //(*response); - printf("Response: msgid %d\n%s\n", msgid, b1); - ks_pool_free(pool, &b1); - - printf("exiting process_wombat\n"); - - return JRPC_SEND; -} - - -static enum jrpc_status_t process_widget_response(cJSON *request, cJSON **msg) -{ - printf("entering process_widget_response\n"); - printf("exiting process_widget_response\n"); - return JRPC_PASS; -} - - - -static enum jrpc_status_t process_wombat(cJSON *msg, cJSON **replyP) -{ - printf("entering process_wombat\n"); - - char *b0 = cJSON_PrintUnformatted(msg); - printf("\nRequest: %s\n\n", b0); - ks_pool_free(pool, &b0); - - cJSON *result = cJSON_CreateObject(); - cJSON_AddNumberToObject(result, "code", 99); - cJSON *response; - -// ks_rpcmessageid_t msgid = ks_rpcmessage_create_response(msg, &result, &response); - ks_rpcmessageid_t msgid = blade_rpc_create_response(msg, &result, &response); - - cJSON *response_copy = cJSON_Duplicate(response, 1); - blade_rpc_process_jsonmessage(response_copy); - - if (msgid != 0) { - char *b1 = cJSON_PrintUnformatted(response); //(*response); - printf("\nResponse: msgid %d\n%s\n\n", msgid, b1); - blade_rpc_write_json(response); - ks_pool_free(pool, &b1); - } - else { - printf("process_wombat: unable to create response \n"); - return JRPC_ERROR; - } - - blade_rpc_fields_t *r_fields; - - char *r_method; - char *r_namespace; - char *r_version; - uint32_t r_id; - - ks_status_t s1 = blade_rpc_parse_message(msg, &r_namespace, &r_method, &r_version, &r_id, &r_fields); - - if (s1 == KS_STATUS_FAIL) { - printf("process_wombat: blade_rpc_parse_message failed\n"); - return JRPC_ERROR; - } - - printf("\nprocess_wombat: blade_rpc_parse_message namespace %s, method %s, id %d, version %s, to %s, from %s, token %s\n\n", - r_namespace, r_method, r_id, r_version, - r_fields->to, r_fields->from, r_fields->token); - - cJSON *parms2 = NULL; - - char to[] = "tony@freeswitch.com/laptop?transport=wss&host=server1.freeswitch.com&port=1234"; - char from[] = "colm@freeswitch.com/laptop?transport=wss&host=server2.freeswitch.com&port=4321"; - char token[] = "abcdefhgjojklmnopqrst"; - - blade_rpc_fields_t fields; - fields.to = to; - fields.from = from; - fields.token = token; - -// msgid = ks_rpcmessage_create_request("app1", "widget", &parms2, replyP); - msgid = blade_rpc_create_request(r_namespace, r_method, &fields, NULL, replyP); - - if (!msgid) { - printf("process wombat: create of next request failed\n"); - return JRPC_ERROR; - } - - b0 = cJSON_PrintUnformatted(*replyP); - - if (!b0) { - printf("process wombat: create of next request cannot be formatted\n"); - return JRPC_ERROR; - } - - - printf("\nprocess wombat: next request\n%s\n\n", b0); - - - printf("\n\nexiting process_wombat with a reply to send\n"); - - return JRPC_SEND; -} - -static enum jrpc_status_t process_wombat_prerequest(cJSON *request, cJSON **msg) -{ - printf("entering process_wombat_prerequest\n"); - printf("exiting process_wombat_prerequest\n"); - return JRPC_SEND; -} - -static enum jrpc_status_t process_wombat_postrequest(cJSON *request, cJSON **msg) -{ - printf("entering process_wombat_postrequest\n"); - printf("exiting process_wombat_postrequest\n"); - return JRPC_PASS; -} - - - -static enum jrpc_status_t process_wombat_response(cJSON *request, cJSON **msg) -{ - printf("entering process_wombat_response\n"); - printf("exiting process_wombat_response\n"); - return JRPC_PASS; -} - -static enum jrpc_status_t process_wombat_preresponse(cJSON *request, cJSON **msg) -{ - - printf("entering process_wombat_preresponse\n"); - - cJSON *response = NULL; - cJSON *result = NULL; - - cJSON *parms2 = NULL; - - //ks_rpcmessageid_t msgid = ks_rpcmessage_create_request("app1", "widget", &parms2, msg); - - printf("exiting process_wombat_preresponse\n"); - return JRPC_SEND; -} - -static enum jrpc_status_t process_wombat_postresponse(cJSON *request, cJSON **msg) -{ - printf("entering process_postwombat_response\n"); - printf("exiting process_postwombat_response\n"); - return JRPC_PASS; -} - - - - -static enum jrpc_status_t process_badbunny( cJSON *msg, cJSON **response) -{ - printf("entering process_badbunny\n"); - - char *b0 = cJSON_PrintUnformatted(msg); - printf("\nRequest: %s\n\n", b0); - ks_pool_free(pool, &b0); - - cJSON *respvalue; - - ks_rpcmessageid_t msgid = ks_rpcmessage_create_errorresponse(msg, &respvalue, response); - - char *b2 = cJSON_PrintUnformatted(*response); - printf("\nRequest: msgid %d\n%s\n\n", msgid, b2); - ks_pool_free(pool, &b2); - - //cJSON *respvalue = cJSON_CreateNumber(1); - - - char *b1 = cJSON_PrintUnformatted(*response); //(*response); - printf("\nResponse: %s\n\n", b1); - ks_pool_free(pool, &b1); - - printf("exiting process_badbunny\n"); - - - return JRPC_SEND; -} - - -void test01() -{ - printf("**** testrpcmessages - test01 start\n"); fflush(stdout); - - blade_rpc_declare_template("temp1", "1.0"); - - blade_rpc_register_template_function("temp1", "widget", process_widget, process_widget_response); - - blade_rpc_declare_namespace("app1", "1.0"); - - blade_rpc_register_function("app1", "wombat", process_wombat, process_wombat_response); - - blade_rpc_register_custom_request_function("app1", "wombat", process_wombat_prerequest, process_wombat_postresponse); - blade_rpc_register_custom_response_function("app1", "wombat", process_wombat_preresponse, process_wombat_postresponse); - - - /* message 1 */ - /* --------- */ - cJSON* request1 = NULL; - cJSON* parms1 = NULL; - - printf("\n\n\n - test01 message1 - basic message\n\n\n"); - - ks_rpcmessageid_t msgid = ks_rpcmessage_create_request("app1", "wombat", &parms1, &request1); - if (msgid == 0) { - printf("test01.1: unable to create message 1\n"); - return; - } - - if (!request1) { - printf("test01.1: No json returned from create request 1\n"); - return; - } - - cJSON_AddStringToObject(parms1, "hello", "cruel world"); - - char *pdata = cJSON_PrintUnformatted(request1); - - if (!pdata) { - printf("test01.1: unable to parse cJSON object\n"); - return; - } - - printf("test01 request:\n%s\n", pdata); - - - blade_rpc_process_jsonmessage(request1); - - cJSON_Delete(request1); - - ks_pool_free(pool, &pdata); - - printf("\ntest01.1 complete\n"); - - - /* message 2 */ - /* --------- */ - - printf("\n\n\n test01 - message2 - test inherit\n\n\n"); - - blade_rpc_inherit_template("app1", "temp1"); - - cJSON* request2 = NULL; - cJSON* parms2 = cJSON_CreateObject(); - - cJSON_AddStringToObject(parms2, "hello2", "cruel world once again"); - - msgid = ks_rpcmessage_create_request("app1", "temp1.widget", &parms2, &request2); - if (msgid == 0) { - printf("test01.2: failed to create a wombat\n"); - return; - } - - if (!request2) { - printf("test01.2: No json returned from create request 1\n"); - return; - } - - pdata = cJSON_PrintUnformatted(request2); - - if (!pdata) { - printf("test01.2: unable to parse cJSON object\n"); - return; - } - - printf("\ntest01 request:\n%s\n\n\n", pdata); - - blade_rpc_process_jsonmessage(request2); - - cJSON_Delete(request2); - ks_pool_free(pool, &pdata); - - printf("\ntest01.2 complete\n"); - - return; - -} - -void test02() -{ - printf("**** testrpcmessages - test02 start\n"); fflush(stdout); - - blade_rpc_declare_namespace("app2", "1.0"); - - blade_rpc_register_function("app2", "wombat", process_wombat, process_wombat_response); - - blade_rpc_inherit_template("app2", "temp1"); - - blade_rpc_register_custom_request_function("app2", "wombat", process_wombat_prerequest, process_wombat_postresponse); - blade_rpc_register_custom_response_function("app2", "wombat", process_wombat_preresponse, process_wombat_postresponse); - - blade_rpc_register_function("app2", "bunny", process_badbunny, NULL); - - char to[] = "tony@freeswitch.com/laptop?transport=wss&host=server1.freeswitch.com&port=1234"; - char from[] = "colm@freeswitch.com/laptop?transport=wss&host=server2.freeswitch.com&port=4321"; - char token[] = "abcdefhgjojklmnopqrst"; - - blade_rpc_fields_t fields; - fields.to = to; - fields.from = from; - fields.token = token; - - - /* test the 4 different ways to handle param messages */ - - cJSON *params1 = NULL; - cJSON *request1; - - ks_rpcmessageid_t msgid = blade_rpc_create_request("app2", "temp1.widget2", &fields, ¶ms1, &request1); - - if (!msgid) { - printf("test02.1: create_request failed\n"); - return; - } - - cJSON_AddStringToObject(params1, "hello", "cruel world"); - - char *pdata = cJSON_PrintUnformatted(request1); - - if (!pdata) { - printf("test02.1: unable to parse cJSON object\n"); - return; - } - - printf("\ntest02.1 request:\n\n%s\n\n\n", pdata); - - printf("\n\n -----------------------------------------\n\n"); - - ks_status_t s1 = blade_rpc_process_jsonmessage(request1); - if (s1 == KS_STATUS_FAIL) { - printf("test02.1: process request1 failed\n"); - return; - } - - printf(" -----------------------------------------\n\n\n\n"); - - ks_pool_free(pool, &pdata); - - cJSON *reply1 = NULL; - cJSON *response1 = NULL; - - ks_rpcmessageid_t msgid2 = blade_rpc_create_response(request1, &reply1, &response1); - - if (!msgid2) { - printf("test02.1: create_response failed\n"); - return; - } - - cJSON_AddNumberToObject(reply1, "code", 10); - cJSON_AddStringToObject(reply1, "farewell", "cruel server"); - - pdata = cJSON_PrintUnformatted(response1); - - if (!pdata) { - printf("test02.1: unable to parse cJSON response object\n"); - return; - } - - printf("\ntest02.1 response:\n\n%s\n\n\n", pdata); - - printf("\n\n -----------------------------------------\n\n"); - - s1 = blade_rpc_process_jsonmessage(response1); - if (s1 == KS_STATUS_FAIL) { - printf("test02.1: process request1 failed\n"); - return; - } - - printf(" -----------------------------------------\n\n\n\n"); - - - ks_pool_free(pool, &pdata); - - printf("**** testrpcmessages - test02 finished\n"); fflush(stdout); - - return; -} - - -void test02a() -{ - printf("**** testrpcmessages - test02a start\n"); fflush(stdout); - - char to[] = "tony@freeswitch.com/laptop?transport=wss&host=server1.freeswitch.com&port=1234"; - char from[] = "colm@freeswitch.com/laptop?transport=wss&host=server2.freeswitch.com&port=4321"; - char token[] = "abcdefhgjojklmnopqrst"; - - blade_rpc_fields_t fields; - fields.to = to; - fields.from = from; - fields.token = token; - - - /* test the 4 different ways to handle param messages */ - - cJSON *request1; - - ks_rpcmessageid_t msgid = blade_rpc_create_request("app2", "wombat", &fields, NULL, &request1); - - if (!msgid) { - printf("test02.1: create_request failed\n"); - return; - } - - char *pdata = cJSON_PrintUnformatted(request1); - - if (!pdata) { - printf("test02.1: unable to parse cJSON object\n"); - return; - } - - printf("\ntest02.1 request:\n\n%s\n\n\n", pdata); - - printf("\n\n -----------------------------------------\n\n"); - - ks_status_t s1 = blade_rpc_process_jsonmessage(request1); - if (s1 == KS_STATUS_FAIL) { - printf("test02.1: process request1 failed\n"); - return; - } - - printf(" -----------------------------------------\n\n\n\n"); - - - - - ks_pool_free(pool, &pdata); - - cJSON *response1 = NULL; - - ks_rpcmessageid_t msgid2 = blade_rpc_create_response(request1, NULL, &response1); - - if (!msgid2) { - printf("test02.1: create_response failed\n"); - return; - } - - pdata = cJSON_PrintUnformatted(response1); - - printf("\ntest02.1 response:\n\n%s\n\n\n", pdata); - - ks_pool_free(pool, &pdata); - - printf("**** testrpcmessages - test02a finished\n\n\n"); fflush(stdout); - - return; -} - - -void test02b() -{ - printf("**** testrpcmessages - test02b start\n"); fflush(stdout); - - char to[] = "tony@freeswitch.com/laptop?transport=wss&host=server1.freeswitch.com&port=1234"; - char from[] = "colm@freeswitch.com/laptop?transport=wss&host=server2.freeswitch.com&port=4321"; - char token[] = "abcdefhgjojklmnopqrst"; - - blade_rpc_fields_t fields; - fields.to = to; - fields.from = from; - fields.token = token; - - - /* test the 4 different ways to handle param messages */ - - cJSON *params1 = cJSON_CreateNumber(4321); - cJSON *request1; - - ks_rpcmessageid_t msgid = blade_rpc_create_request("app2", "temp1.widget", &fields, ¶ms1, &request1); - - if (!msgid) { - printf("test02.1: create_request failed\n"); - return; - } - - char *pdata = cJSON_PrintUnformatted(request1); - - if (!pdata) { - printf("test02.1: unable to parse cJSON object\n"); - return; - } - - printf("\ntest02.1 request:\n\n%s\n\n\n", pdata); - - ks_pool_free(pool, &pdata); - - cJSON *reply1 = cJSON_CreateString("successful"); - cJSON *response1 = NULL; - - ks_rpcmessageid_t msgid2 = blade_rpc_create_response(request1, &reply1, &response1); - - if (!msgid2) { - printf("test02.1: create_response failed\n"); - return; - } - - pdata = cJSON_PrintUnformatted(response1); - - printf("\ntest02.1 response:\n\n%s\n\n\n", pdata); - - ks_pool_free(pool, &pdata); - - printf("**** testrpcmessages - test02b finished\n"); fflush(stdout); - - return; -} - - -void test02c() -{ - - printf("**** testrpcmessages - test02c start\n"); fflush(stdout); - - char to[] = "tony@freeswitch.com/laptop?transport=wss&host=server1.freeswitch.com&port=1234"; - char from[] = "colm@freeswitch.com/laptop?transport=wss&host=server2.freeswitch.com&port=4321"; - char token[] = "abcdefhgjojklmnopqrst"; - - blade_rpc_fields_t fields; - fields.to = to; - fields.from = from; - fields.token = token; - - - /* test the 4 different ways to handle param messages */ - - cJSON *params1 = cJSON_CreateObject(); - - cJSON_AddStringToObject(params1, "string1", "here is a string"); - cJSON_AddNumberToObject(params1, "number1", 4242); - - cJSON *request1; - - ks_rpcmessageid_t msgid = blade_rpc_create_request("app2", "bunny", &fields, ¶ms1, &request1); - - if (!msgid) { - printf("test02.1: create_request failed\n"); - return; - } - - cJSON_AddStringToObject(params1, "hello", "cruel world"); - - char *pdata = cJSON_PrintUnformatted(request1); - - if (!pdata) { - printf("test02.1: unable to parse cJSON object\n"); - return; - } - - printf("\ntest02.1 request:\n\n%s\n\n\n", pdata); - - ks_pool_free(pool, &pdata); - - - cJSON *reply1 = cJSON_CreateObject(); - cJSON_AddNumberToObject(reply1, "code", 10); - cJSON_AddStringToObject(reply1, "farewell", "cruel server"); - - - cJSON *response1 = NULL; - - ks_rpcmessageid_t msgid2 = blade_rpc_create_response(request1, &reply1, &response1); - - if (!msgid2) { - printf("test02.1: create_response failed\n"); - return; - } - - - pdata = cJSON_PrintUnformatted(response1); - - printf("\ntest02.1 response:\n\n%s\n\n\n", pdata); - - ks_pool_free(pool, &pdata); - - printf("**** testrpcmessages - test02c finished\n"); fflush(stdout); - - return; -} - - - - - - - - - - - - - - - - -/* test06 */ -/* ------ */ - -static void *testnodelocking_ex1(ks_thread_t *thread, void *data) -{ - return NULL; -} - -static void *testnodelocking_ex2(ks_thread_t *thread, void *data) -{ - return NULL; -} - - -void test06() -{ - printf("**** testmessages - test06 start\n"); fflush(stdout); - - ks_thread_t *t0; - ks_thread_create(&t0, testnodelocking_ex1, NULL, pool); - - ks_thread_t *t1; - ks_thread_create(&t1, testnodelocking_ex2, NULL, pool); - - ks_thread_join(t1); - ks_thread_join(t0); - - printf("\n\n* **testmessages - test06 -- threads complete\n\n"); fflush(stdout); - - printf("**** testmessages - test06 start\n"); fflush(stdout); - - return; -} - - - -int main(int argc, char *argv[]) { - - printf("testmessages - start\n"); - - int tests[100]; - if (argc == 0) { - tests[0] = 1; - tests[1] = 2; - tests[2] = 3; - tests[3] = 4; - tests[4] = 5; - } - else { - for(int tix=1; tix<100 && tix -#include -#include - -struct -{ - - ks_mutex_t *id_mutex; - uint32_t message_id; - - ks_pool_t *pool; - -} handle = {NULL, 0, NULL}; - -const char PROTOCOL[] = "jsonrpc"; -const char PROTOCOL_VERSION[] = "2.0"; -const char ID[] = "id"; -const char METHOD[] = "method"; -const char PARAMS[] = "params"; -const char ERROR[] = "error"; -const char RESULT[] = "result"; - - - -KS_DECLARE(void*) ks_json_pool_alloc(ks_size_t size) -{ - return ks_pool_alloc(handle.pool, size); -} - -KS_DECLARE(void) ks_json_pool_free(void *ptr) -{ - ks_pool_free(handle.pool, &ptr); -} - - -KS_DECLARE(void) ks_rpcmessage_init(ks_pool_t* pool) -{ - if (!handle.id_mutex) { - ks_mutex_create(&handle.id_mutex, KS_MUTEX_FLAG_DEFAULT, pool); - handle.pool = pool; - - cJSON_Hooks hooks; - hooks.malloc_fn = ks_json_pool_alloc; - hooks.free_fn = ks_json_pool_free; - cJSON_InitHooks(&hooks); - } - return; -} - -static uint32_t ks_rpcmessage_next_id() -{ - uint32_t message_id; - - ks_mutex_lock(handle.id_mutex); - - ++handle.message_id; - - if (!handle.message_id) { - ++handle.message_id; - } - - message_id = handle.message_id; - - ks_mutex_unlock(handle.id_mutex); - - return message_id; -} - - -static cJSON *ks_rpcmessage_new(uint32_t id) -{ - cJSON *obj = cJSON_CreateObject(); - cJSON_AddItemToObject(obj, PROTOCOL, cJSON_CreateString(PROTOCOL_VERSION)); - - if (id) { - cJSON_AddItemToObject(obj, ID, cJSON_CreateNumber(id)); - } - - return obj; -} - -static cJSON *ks_rpcmessage_dup(cJSON *msgid) -{ - cJSON *obj = cJSON_CreateObject(); - cJSON_AddItemToObject(obj, PROTOCOL, cJSON_CreateString(PROTOCOL_VERSION)); - - if (msgid) { - cJSON_AddItemToObject(obj, ID, cJSON_Duplicate(msgid, 0)); - } - - return obj; -} - -KS_DECLARE(ks_bool_t) ks_rpcmessage_isrequest(cJSON *msg) -{ - cJSON *result = cJSON_GetObjectItem(msg, RESULT); - cJSON *error = cJSON_GetObjectItem(msg, ERROR); - - if (result || error) { - return KS_FALSE; - } - - return KS_TRUE; -} - -KS_DECLARE(ks_bool_t) ks_rpcmessage_isrpc(cJSON *msg) -{ - cJSON *rpc = cJSON_GetObjectItem(msg, PROTOCOL); - - if (rpc) { - return KS_FALSE; - } - - return KS_TRUE; -} - - - - -KS_DECLARE(ks_rpcmessageid_t) ks_rpcmessage_create_request(char *namespace, - char *command, - cJSON **paramsP, - cJSON **requestP) -{ - cJSON *msg, *params = NULL; - *requestP = NULL; - - ks_rpcmessageid_t msgid = ks_rpcmessage_next_id(); - msg = ks_rpcmessage_new(msgid); - - if (paramsP) { - - if (*paramsP) { /* parameters have been passed */ - params = *paramsP; - } - else { - params = cJSON_CreateObject(); - *paramsP = params; - } - - cJSON_AddItemToObject(msg, PARAMS, params); - } - - char fqcommand[KS_RPCMESSAGE_FQCOMMAND_LENGTH]; - memset(fqcommand, 0, sizeof(fqcommand)); - - sprintf(fqcommand, "%s.%s", namespace, command); - - cJSON_AddItemToObject(msg, METHOD, cJSON_CreateString(fqcommand)); - - *requestP = msg; - return msgid; -} - -KS_DECLARE(ks_size_t) ks_rpc_create_buffer(char *namespace, - char *method, - cJSON **params, - ks_buffer_t *buffer) -{ - - cJSON *message; - - ks_rpcmessageid_t msgid = ks_rpcmessage_create_request(namespace, method, params, &message); - - if (!msgid) { - return 0; - } - - if ( (*params)->child == NULL) { - cJSON_AddNullToObject(*params, "bladenull"); - } - - const char* b = cJSON_PrintUnformatted(message); - ks_size_t size = strlen(b); - - ks_buffer_write(buffer, b, size); - cJSON_Delete(message); - - return size; -} - - -static ks_rpcmessageid_t ks_rpcmessage_get_messageid(const cJSON *msg, cJSON **cmsgidP) -{ - ks_rpcmessageid_t msgid = 0; - - cJSON *cmsgid = cJSON_GetObjectItem(msg, ID); - - if (cmsgid->type == cJSON_Number) { - msgid = (ks_rpcmessageid_t) cmsgid->valueint; - } - - *cmsgidP = cmsgid; - - return msgid; -} - - -static ks_rpcmessageid_t ks_rpcmessage_new_response( - const cJSON *request, - cJSON **result, - cJSON **pmsg) -{ - cJSON *respmsg = NULL; - cJSON *cmsgid = NULL; - - cJSON *command = cJSON_GetObjectItem(request, METHOD); - - ks_rpcmessageid_t msgid = ks_rpcmessage_get_messageid(request, &cmsgid ); - - if (!msgid || !command) { - return 0; - } - - *pmsg = respmsg = ks_rpcmessage_dup(cmsgid); - - cJSON_AddItemToObject(respmsg, METHOD, cJSON_Duplicate(command, 0)); - - if (result && *result) { - cJSON_AddItemToObject(respmsg, RESULT, *result); - } - - return msgid; -} - - -KS_DECLARE(ks_rpcmessageid_t) ks_rpcmessage_create_response( - const cJSON *request, - cJSON **resultP, - cJSON **responseP) -{ - ks_rpcmessageid_t msgid = ks_rpcmessage_new_response(request, resultP, responseP); - - cJSON *respmsg = *responseP; - - if (msgid) { - - if (resultP && *resultP == NULL) { - cJSON *result = cJSON_CreateObject(); - *resultP = result; - cJSON_AddItemToObject(respmsg, RESULT, result); - } - } - - return msgid; -} - -KS_DECLARE(ks_rpcmessageid_t) ks_rpcmessage_create_errorresponse( - const cJSON *request, - cJSON **errorP, - cJSON **responseP) -{ - ks_rpcmessageid_t msgid = ks_rpcmessage_new_response(request, NULL, responseP); - cJSON *respmsg = *responseP; - - if (msgid) { - - if (errorP && *errorP == NULL) { - cJSON *error = cJSON_CreateObject(); - *errorP = error; - cJSON_AddItemToObject(respmsg, ERROR, error); - } - else if (errorP && *errorP) { - cJSON_AddItemToObject(*responseP, ERROR, *errorP); - } - } - - return msgid; -} - - -/* 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/libks/test/Makefile.am b/libs/libks/test/Makefile.am index 0b85a468c4..cffc18bdcd 100644 --- a/libs/libks/test/Makefile.am +++ b/libs/libks/test/Makefile.am @@ -1,14 +1,9 @@ AM_CFLAGS += -I$(abs_top_srcdir)/src/include -g -ggdb -O0 $(openssl_CFLAGS) TEST_LDADD = $(abs_top_builddir)/libks.la $(openssl_LIBS) -check_PROGRAMS = +check_PROGRAMS = EXTRA_DIST = tap.h -check_PROGRAMS += testmessages -testmessages_SOURCES = testmessages.c tap.c -testmessages_CFLAGS = $(AM_CFLAGS) -testmessages_LDADD = $(TEST_LDADD) - check_PROGRAMS += testbuckets testbuckets_SOURCES = testbuckets.c tap.c testbuckets_CFLAGS = $(AM_CFLAGS) @@ -96,7 +91,7 @@ nodeidgen_LDADD = $(TEST_LDADD) #check_PROGRAMS += libtorrent_example #libtorrent_example_SOURCES = libtorrent-example.c -#libtorrent_example_CFLAGS = $(AM_CFLAGS) +#libtorrent_example_CFLAGS = $(AM_CFLAGS) #libtorrent_example_LDADD = $(abs_top_builddir)/libks.la $(abs_top_builddir)/test/libtorrent.so /usr/lib/x86_64-linux-gnu/libboost_system.a $(openssl_LIBS) -ledit -lpthread -ltorrent-rasterbar -lstdc++ TESTS=$(check_PROGRAMS) @@ -108,4 +103,3 @@ $(abs_top_builddir)/test/libtorrent.so: $(abs_top_builddir)/test/libtorrent.o $(abs_top_builddir)/test/libtorrent.o: $(abs_top_builddir)/test/libtorrent.cpp g++ -c -fPIC -o $(abs_top_builddir)/test/libtorrent.o -I$(abs_top_builddir)/test/ $(abs_top_builddir)/test/libtorrent.cpp - diff --git a/libs/libks/test/testmessages.c b/libs/libks/test/testmessages.c deleted file mode 100644 index 7609cf69ac..0000000000 --- a/libs/libks/test/testmessages.c +++ /dev/null @@ -1,124 +0,0 @@ -#pragma GCC diagnostic ignored "-Wunused-but-set-variable" -#pragma GCC diagnostic ignored "-Wunused-variable" -#pragma GCC diagnostic ignored "-Wunused-function" - -#include "../src/include/ks_rpcmessage.h" - -#pragma GCC optimize ("O0") - - -ks_pool_t *pool; - - -void test01() -{ - printf("**** testrpcmessages - test01 start\n\n"); fflush(stdout); - - cJSON* request1 = NULL; - cJSON* parms1 = NULL; - cJSON* response1 = NULL; - - /*namespace, method, params, **request */ - ks_rpcmessageid_t msgid = ks_rpcmessage_create_request("app1", "func1", &parms1, &request1); - if (msgid == 0) { - printf("message create failed %d\n", msgid); - } - - cJSON_AddStringToObject(parms1, "hello", "cruel world"); - char* data = cJSON_PrintUnformatted(request1); - - printf("test01 request1: %d\n%s\n\n", msgid, data); - ks_json_pool_free(data); - - - /* convert to buffer */ - cJSON* parms2 = NULL; - ks_buffer_t *buffer; - - ks_buffer_create(&buffer, 256, 256, 1024); - - ks_size_t n = ks_rpc_create_buffer("app2", "func2", &parms2, buffer); - - ks_size_t size = ks_buffer_len(buffer); - char *b = (char *)ks_pool_alloc(pool, size+1); - ks_buffer_read(buffer, b, size); - - printf("test01 request2: %zd %zd from ks_buffer\n%s\n\n\n", n, size, b); - - - /* create message 3 */ - - cJSON *parms3 = cJSON_CreateNumber(1); - cJSON *request3 = NULL; - - msgid = ks_rpcmessage_create_request("app1", "badbunny", &parms3, &request3); - data = cJSON_PrintUnformatted(request3); - printf("\ntest01i request: %d\n%s\n\n", msgid, data); - - cJSON *response3 = NULL; - - ks_rpcmessage_create_response(request3, NULL, &response3); - - data = cJSON_PrintUnformatted(response3); - printf("\ntest01 response3: %d\n%s\n\n", msgid, data); - - ks_json_pool_free(data); - cJSON_Delete(request3); - cJSON_Delete(response3); - - printf("**** testrpcmessages - test01 complete\n\n\n"); fflush(stdout); -} - -void test02() -{ - printf("**** testmessages - test02 start\n"); fflush(stdout); - - printf("**** testmessages - test02 finished\n"); fflush(stdout); - - return; -} - - - -int main(int argc, char *argv[]) { - - printf("testmessages - start\n"); - - int tests[100]; - if (argc == 1) { - tests[0] = 1; - } - else { - for(int tix=1; tix<100 && tix