FS-9952: Initial json rpc messaging

This commit is contained in:
colm 2017-01-23 14:30:19 -05:00 committed by Mike Jerris
parent e4b7b2038f
commit c60a42009d
4 changed files with 405 additions and 2 deletions

View File

@ -10,7 +10,7 @@ lib_LTLIBRARIES = libks.la
libks_la_SOURCES = src/ks.c src/ks_string.c src/ks_json.c src/cJSON.c src/cJSON_Utils.c src/ks_thread.c src/ks_thread_pool.c src/ks_mutex.c src/ks_config.c
libks_la_SOURCES += src/ks_log.c src/ks_socket.c src/ks_buffer.c src/ks_pool.c src/simclist.c
libks_la_SOURCES += src/ks_time.c src/ks_printf.c src/ks_hash.c src/ks_q.c src/ks_dso.c # src/ks_dht.c
libks_la_SOURCES += src/ks_ssl.c src/kws.c src/ks_rng.c
libks_la_SOURCES += src/ks_ssl.c src/kws.c src/ks_rng.c src/ks_rpcmessage.c
libks_la_SOURCES += src/utp/utp_api.cpp src/utp/utp_callbacks.cpp src/utp/utp_hash.cpp src/utp/utp_internal.cpp
libks_la_SOURCES += src/utp/utp_packedsockaddr.cpp src/utp/utp_utils.cpp src/ks_bencode.c
libks_la_SOURCES += src/dht/ks_dht.c src/dht/ks_dht_datagram.c src/dht/ks_dht_endpoint.c src/dht/ks_dht_message.c src/dht/ks_dht_transaction.c
@ -29,7 +29,8 @@ library_include_HEADERS = src/include/ks_config.h src/include/ks.h src/include/k
library_include_HEADERS += src/include/ks_thread_pool.h src/include/ks_cJSON.h src/include/ks_cJSON_Utils.h
library_include_HEADERS += src/include/ks_pool.h src/include/simclist.h src/include/ks_time.h src/include/ks_q.h src/include/ks_socket.h
library_include_HEADERS += src/include/ks_dso.h src/include/ks_platform.h src/include/ks_types.h # src/include/ks_rng.h src/include/ks_dht.h
library_include_HEADERS += src/include/ks_printf.h src/include/ks_hash.h src/include/ks_ssl.h src/include/kws.h
library_include_HEADERS += src/include/ks_printf.h src/include/ks_hash.h src/include/ks_ssl.h src/include/kws.h
library_include_HEADERS += src/include/ks_rpcmessage.h
library_include_HEADERS += src/utp/utp_internal.h src/utp/utp.h src/utp/utp_types.h src/utp/utp_callbacks.h src/utp/utp_templates.h
library_include_HEADERS += src/utp/utp_hash.h src/utp/utp_packedsockaddr.h src/utp/utp_utils.h src/include/ks_utp.h src/include/ks_acl.h

View File

@ -0,0 +1,91 @@
/*
* 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.
*/
#ifndef _KS_RPCMESSAGE_H_
#define _KS_RPCMESSAGE_H_
#include "ks.h"
KS_BEGIN_EXTERN_C
typedef struct ks_rpcmessaging_handle_s ks_rpcmessaging_handle_t;
typedef ks_status_t (*jrpc_func_t)(ks_rpcmessaging_handle_t* handle, cJSON *params, cJSON **responseP);
KS_DECLARE(ks_rpcmessaging_handle_t *) ks_rpcmessage_init(ks_pool_t* pool, ks_rpcmessaging_handle_t** handleP);
KS_DECLARE(void) ks_rpcmessage_deinit(ks_rpcmessaging_handle_t** handleP);
KS_DECLARE(cJSON *)ks_rpcmessage_new_request(ks_rpcmessaging_handle_t* handle,
const char *method,
cJSON **parmsP,
cJSON **requestP);
KS_DECLARE(cJSON *)ks_rpcmessage_new_response(ks_rpcmessaging_handle_t* handle,
const cJSON *request,
cJSON *result,
cJSON **responseP);
KS_DECLARE(ks_status_t)ks_rpcmessage_namespace(ks_rpcmessaging_handle_t* handle, const char* namespace);
KS_DECLARE(ks_status_t)ks_rpcmessage_register_function(ks_rpcmessaging_handle_t* handle, const char *command, jrpc_func_t func);
KS_DECLARE(jrpc_func_t) ks_rpcmessage_find_function(ks_rpcmessaging_handle_t* handle, const char *command);
KS_DECLARE(ks_status_t) ks_rpcmessage_process_request(ks_rpcmessaging_handle_t* handle,
uint8_t *data,
ks_size_t size,
cJSON **responseP);
KS_DECLARE(ks_status_t) ks_rpcmessage_process_jsonrequest(ks_rpcmessaging_handle_t* handle, cJSON *request, cJSON **responseP);
KS_END_EXTERN_C
#endif /* defined(_KS_RPCMESSAGE_H_) */
/* 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:
*/

View File

@ -0,0 +1,306 @@
/*
* 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 <ks.h>
#include <ks_rpcmessage.h>
#define KS_RPCMESSAGE_NAMESPACE_LENGTH 16
struct ks_rpcmessaging_handle_s
{
ks_hash_t *method_hash;
ks_mutex_t *id_mutex;
uint32_t message_id;
ks_pool_t *pool;
char namespace[KS_RPCMESSAGE_NAMESPACE_LENGTH+2];
};
static uint32_t ks_rpcmessage_next_id(ks_rpcmessaging_handle_t* handle)
{
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;
}
KS_DECLARE(ks_rpcmessaging_handle_t*) ks_rpcmessage_init(ks_pool_t* pool, ks_rpcmessaging_handle_t** handleP)
{
ks_rpcmessaging_handle_t *handle = (ks_rpcmessaging_handle_t *)ks_pool_alloc(pool, sizeof(ks_rpcmessaging_handle_t));
*handleP = handle;
ks_hash_create(&handle->method_hash,
KS_HASH_MODE_CASE_SENSITIVE,
KS_HASH_FLAG_RWLOCK + KS_HASH_FLAG_DUP_CHECK + KS_HASH_FLAG_FREE_KEY,
pool);
ks_mutex_create(&handle->id_mutex, KS_MUTEX_FLAG_DEFAULT, pool);
strcpy(handle->namespace, "global.");
handle->pool = pool;
return handle;
}
KS_DECLARE(void) ks_rpcmessage_deinit(ks_rpcmessaging_handle_t** handleP)
{
ks_rpcmessaging_handle_t *handle = *handleP;
ks_hash_destroy(&handle->method_hash);
ks_pool_free(handle->pool, handleP);
return;
}
static cJSON *ks_rpcmessage_new(uint32_t id)
{
cJSON *obj = cJSON_CreateObject();
cJSON_AddItemToObject(obj, "jsonrpc", cJSON_CreateString("2.0"));
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, "jsonrpc", cJSON_CreateString("2.0"));
if (msgid) {
cJSON_AddItemToObject(obj, "id", cJSON_Duplicate(msgid, 0));
}
return obj;
}
KS_DECLARE(cJSON *) ks_rpcmessage_new_request(ks_rpcmessaging_handle_t* handle,
const char *command,
cJSON **paramsP,
cJSON **request)
{
cJSON *msg, *params = NULL;
*request = NULL;
if (!ks_rpcmessage_find_function(handle, command)) {
ks_log(KS_LOG_ERROR, "Attempt to create unknown message type : %s, namespace %s\n", command, handle->namespace);
return NULL;
}
msg = ks_rpcmessage_new(ks_rpcmessage_next_id(handle));
if (paramsP && *paramsP) {
params = *paramsP;
}
if (!params) {
params = cJSON_CreateObject();
}
cJSON_AddItemToObject(msg, "method", cJSON_CreateString(command));
cJSON_AddItemToObject(msg, "params", params);
if (paramsP) {
*paramsP = params;
}
return msg;
}
KS_DECLARE(cJSON *) ks_rpcmessage_new_response(ks_rpcmessaging_handle_t* handle,
const cJSON *request,
cJSON *result,
cJSON **pmsg)
{
cJSON *respmsg = NULL;
cJSON *msgid = cJSON_GetObjectItem(request, "id");
cJSON *command = cJSON_GetObjectItem(request, "method");
if (!msgid || !command) {
return NULL;
}
*pmsg = respmsg = ks_rpcmessage_dup(msgid);
cJSON_AddItemToObject(respmsg, "method", cJSON_Duplicate(command, 0));
if (result) {
cJSON_AddItemToObject(respmsg, "result", result);
}
return respmsg;
}
KS_DECLARE(ks_status_t) ks_rpcmessage_namespace(ks_rpcmessaging_handle_t* handle, const char* namespace)
{
strncpy(handle->namespace, namespace, sizeof(KS_RPCMESSAGE_NAMESPACE_LENGTH));
handle->namespace[KS_RPCMESSAGE_NAMESPACE_LENGTH] = 0;
ks_log(KS_LOG_DEBUG, "Setting message namespace value %s", handle->namespace);
strcat( handle->namespace, ".");
return KS_STATUS_SUCCESS;
}
KS_DECLARE(ks_status_t) ks_rpcmessage_register_function(ks_rpcmessaging_handle_t* handle, const char *command, jrpc_func_t func)
{
char fqcommand[256];
memset(fqcommand, 0, sizeof(fqcommand));
if (handle->namespace[0] != 0) {
strcpy(fqcommand, handle->namespace);
}
strcat(fqcommand, command);
int lkey = strlen(fqcommand)+1;
if (lkey < 16) {
lkey = 16;
}
char *key = (char*)ks_pool_alloc(handle->pool, lkey);
strcpy(key, fqcommand);
ks_hash_write_lock(handle->method_hash);
ks_hash_insert(handle->method_hash, key, (void *) (intptr_t)func);
ks_hash_write_unlock(handle->method_hash);
ks_log(KS_LOG_DEBUG, "Message %s registered (%s)\n", command, fqcommand);
return KS_STATUS_SUCCESS;
}
KS_DECLARE(jrpc_func_t) ks_rpcmessage_find_function(ks_rpcmessaging_handle_t* handle, const char *command)
{
char fqcommand[256];
memset(fqcommand, 0, sizeof(fqcommand));
if (handle->namespace[0] != 0) {
strcpy(fqcommand, handle->namespace);
}
strcat(fqcommand, command);
ks_hash_read_lock(handle->method_hash);
jrpc_func_t func = (jrpc_func_t) (intptr_t) ks_hash_search(handle->method_hash, fqcommand, KS_UNLOCKED);
ks_hash_read_unlock(handle->method_hash);
return func;
}
KS_DECLARE(ks_status_t) ks_rpcmessage_process_jsonrequest(ks_rpcmessaging_handle_t* handle, cJSON *request, cJSON **responseP)
{
const char *command = cJSON_GetObjectCstr(request, "method");
cJSON *error = NULL;
cJSON *response = NULL;
*responseP = NULL;
if (!command) {
error = cJSON_CreateString("Command not found");
}
//todo - add more checks ?
if (error) {
*responseP = response = ks_rpcmessage_new_request(handle, 0, &error, &response);
return KS_STATUS_FAIL;
}
jrpc_func_t func = ks_rpcmessage_find_function(handle, command);
if (!func) {
error = cJSON_CreateString("Command not supported");
}
return func(handle, request, responseP);
}
KS_DECLARE(ks_status_t) ks_rpcmessage_process_request(ks_rpcmessaging_handle_t* handle,
uint8_t *data,
ks_size_t size,
cJSON **responseP)
{
cJSON *response = NULL;
cJSON *error = NULL;
cJSON *request = cJSON_Parse((char*)data);
if (!request) {
error = cJSON_CreateString("Invalid json format");
*responseP = response = ks_rpcmessage_new_request(handle, 0, &error, &response);
return KS_STATUS_FAIL;
}
ks_status_t status = ks_rpcmessage_process_jsonrequest(handle, request, responseP);
cJSON_Delete(request);
return status;
}
/* 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:
*/

View File

@ -4,6 +4,11 @@ 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)