mirror of
https://github.com/signalwire/freeswitch.git
synced 2025-04-13 15:50:59 +00:00
FS-9952: Initial json rpc messaging
This commit is contained in:
parent
e4b7b2038f
commit
c60a42009d
@ -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
|
||||
|
||||
|
91
libs/libks/src/include/ks_rpcmessage.h
Normal file
91
libs/libks/src/include/ks_rpcmessage.h
Normal 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:
|
||||
*/
|
306
libs/libks/src/ks_rpcmessage.c
Normal file
306
libs/libks/src/ks_rpcmessage.c
Normal 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:
|
||||
*/
|
@ -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)
|
||||
|
Loading…
x
Reference in New Issue
Block a user