]> git.ipfire.org Git - thirdparty/freeswitch.git/commitdiff
FS-9952: Initial json rpc messaging
authorcolm <colm@freeswitch1>
Wed, 25 Jan 2017 19:52:22 +0000 (14:52 -0500)
committerMike Jerris <mike@jerris.com>
Wed, 22 Mar 2017 21:42:48 +0000 (17:42 -0400)
libs/libks/src/include/ks_rpcmessage.h
libs/libks/src/ks_rpcmessage.c
libs/libks/test/testmessages.c [new file with mode: 0644]

index 45c3def89c765891ec5decef6b12609eb5dbc315..c897f06a82af63af87cffb93b6ee725b8f1d779e 100644 (file)
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
+/* 
+ * Usage notes 
+ *
+ *   ks_rpcmessaging_handle_t *handle;
+ *
+ *   ks_rpcmessage_init(pool, &handle);
+ *   
+ *   ks_rpcmessage_version(handle, version);
+ *   ks_rpcmessage_namespace(handle, application_namespace);
+ *   ks_rpcmessage_register_function(handle, "invite", handle_invite_message);
+ *   ks_rpcmessage_register_function(handle, "media",  handle_media_message);
+ *
+ *   ...
+ *   cJSON* request = NULL;
+ *   cJSON* parms   = NULL;
+ *   cJSON* response  = NULL;
+ *
+ *   request  = ks_rpcmessage_create_request(h, "invite", &parms, &request);
+ *   cJSON_AddStringToObject(parms, "hello", "cruel world");
+ *   ... and send
+ *   
+ *   
+ * static ks_status_t  handle_..._message(ks_rpcmessaging_handle_t* handle, cJSON *msg, cJSON **response)
+ * {
+ *       cJSON *respvalue = cJSON_CreateNumber(1);
+ *       cJSON *x  = *response = ks_rpcmessage_create_response(h, msg, &respvalue, response);
+ *       if ( x == NULL) { 
+ *           return KS_STATUS_FAIL;
+ *        } 
+ *        ...
+ *        return KS_STATUS_SUCCESS;
+ * }
+
+ *
+ *
+ *     
+ *   
+ *
+ *
+ *   ...
+ *   ks_rpcmessage_deinit(&handle);
+ *
+ */            
+
+
+
+
 #ifndef _KS_RPCMESSAGE_H_
 #define _KS_RPCMESSAGE_H_
 
@@ -43,36 +90,45 @@ KS_BEGIN_EXTERN_C
 
 
 typedef struct ks_rpcmessaging_handle_s ks_rpcmessaging_handle_t;
+typedef uint32_t ks_rpcmessage_id;
 
 
-
-typedef  ks_status_t (*jrpc_func_t)(ks_rpcmessaging_handle_t* handle, cJSON *params, cJSON **responseP);
-
+typedef  ks_status_t (*jrpc_func_t)(ks_rpcmessaging_handle_t* handle, cJSON *request, cJSON **responseP);
+typedef  ks_status_t (*jrpc_resp_func_t)(ks_rpcmessaging_handle_t* handle, cJSON *response);
 
 
 
 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, 
+KS_DECLARE(ks_status_t)ks_rpcmessage_namespace(ks_rpcmessaging_handle_t* handle, const char* namespace, const char* version);
+
+KS_DECLARE(ks_rpcmessage_id)ks_rpcmessage_create_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, 
+KS_DECLARE(ks_rpcmessage_id)ks_rpcmessage_create_response(ks_rpcmessaging_handle_t* handle, 
                                                                                        const cJSON *request, 
-                                                                                       cJSON *result
+                                                                                       cJSON **resultP
                                                                                        cJSON **responseP);
+KS_DECLARE(ks_rpcmessage_id)ks_rpcmessage_create_errorresponse(ks_rpcmessaging_handle_t* handle,
+                                            const cJSON *request,
+                                            cJSON **errorP,
+                                            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,
+                                                                                               jrpc_resp_func_t respfunc);
 
-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(jrpc_resp_func_t) ks_rpcmessage_find_response_function(ks_rpcmessaging_handle_t* handle, const char *command);
 
-KS_DECLARE(ks_status_t) ks_rpcmessage_process_request(ks_rpcmessaging_handle_t* handle, 
+KS_DECLARE(ks_status_t) ks_rpcmessage_process_message(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_DECLARE(ks_status_t) ks_rpcmessage_process_jsonmessage(ks_rpcmessaging_handle_t* handle, cJSON *request, cJSON **responseP);
 
 
 KS_END_EXTERN_C
index a28747ef72c409fdd1eaf36b35e4425c444ad4d5..4712c7bd13cb8c410f07b7bd5db615e186180e9a 100644 (file)
@@ -38,7 +38,9 @@
 #include <ks_rpcmessage.h>
 
 #define KS_RPCMESSAGE_NAMESPACE_LENGTH 16
-
+#define KS_PRCMESSAGE_COMMAND_LENGTH  238
+#define KS_PRCMESSAGE_FQCOMMAND_LENGTH KS_RPCMESSAGE_NAMESPACE_LENGTH + 1 + KS_PRCMESSAGE_COMMAND_LENGTH
+#define KS_RPCMESSAGE_VERSION_LENGTH 9
 
 struct ks_rpcmessaging_handle_s
 {
@@ -50,8 +52,17 @@ struct ks_rpcmessaging_handle_s
        ks_pool_t  *pool;
 
        char namespace[KS_RPCMESSAGE_NAMESPACE_LENGTH+2];
+    char version[KS_RPCMESSAGE_VERSION_LENGTH+1];   /* nnn.nn.nn */
 };
 
+typedef struct ks_rpcmessage_callbackpair_s 
+{
+       jrpc_func_t          request_func;
+       jrpc_resp_func_t response_func;
+       uint16_t         command_length;
+       char             command[1]; 
+} ks_rpcmessage_callbackpair_t;
+
 
 static uint32_t ks_rpcmessage_next_id(ks_rpcmessaging_handle_t* handle)
 {
@@ -80,7 +91,7 @@ KS_DECLARE(ks_rpcmessaging_handle_t*) ks_rpcmessage_init(ks_pool_t* pool, ks_rpc
 
        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,
+                                       KS_HASH_FLAG_RWLOCK + KS_HASH_FLAG_DUP_CHECK + KS_HASH_FLAG_FREE_VALUE,
                                        pool);
 
     ks_mutex_create(&handle->id_mutex, KS_MUTEX_FLAG_DEFAULT, pool);
@@ -124,21 +135,36 @@ static cJSON *ks_rpcmessage_dup(cJSON *msgid)
     return obj;
 }
 
+static ks_bool_t ks_rpcmessage_isrequest(cJSON *msg)
+{
+       //cJSON *params = cJSON_GetObjectItem(msg, "param");
+    cJSON *result = cJSON_GetObjectItem(msg, "result");
+    cJSON *error  = cJSON_GetObjectItem(msg, "error");
+
+       if (result || error) {
+               return  KS_FALSE;
+       }
+
+    return KS_TRUE;
+}
+
 
-KS_DECLARE(cJSON *) ks_rpcmessage_new_request(ks_rpcmessaging_handle_t* handle, 
+
+KS_DECLARE(ks_rpcmessage_id) ks_rpcmessage_create_request(ks_rpcmessaging_handle_t* handle, 
                                                                                                const char *command,
                                                                                                cJSON **paramsP,
-                                                                                               cJSON **request)
+                                                                                               cJSON **requestP)
 {
     cJSON *msg, *params = NULL;
-       *request = NULL;
+       *requestP = 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;
+               return 0;
        }
 
-    msg = ks_rpcmessage_new(ks_rpcmessage_next_id(handle));
+       ks_rpcmessage_id msgid = ks_rpcmessage_next_id(handle);
+    msg = ks_rpcmessage_new(msgid);
 
     if (paramsP && *paramsP) {
         params = *paramsP;
@@ -148,54 +174,141 @@ KS_DECLARE(cJSON *) ks_rpcmessage_new_request(ks_rpcmessaging_handle_t* handle,
         params = cJSON_CreateObject();
     }
 
-    cJSON_AddItemToObject(msg, "method", cJSON_CreateString(command));
+    char fqcommand[KS_PRCMESSAGE_FQCOMMAND_LENGTH];
+    memset(fqcommand, 0, sizeof(fqcommand));
+
+    if (handle->namespace[0] != 0) {
+        strcpy(fqcommand, handle->namespace);
+    }
+
+    strcat(fqcommand, command);
+
+    cJSON_AddItemToObject(msg, "method", cJSON_CreateString(fqcommand));
     cJSON_AddItemToObject(msg, "params", params);
 
+    if (handle->version[0] != 0) {
+        cJSON_AddItemToObject(msg, "version", cJSON_CreateString(handle->version));
+    }
+
     if (paramsP) {
         *paramsP = params;
     }
 
-    return msg;
+       *requestP = msg;
+    return msgid;
 }
 
-KS_DECLARE(cJSON *) ks_rpcmessage_new_response(ks_rpcmessaging_handle_t* handle, 
-                                                                                               const cJSON *request, 
-                                                                                               cJSON *result, 
-                                                                                               cJSON **pmsg)
+static ks_rpcmessage_id ks_rpcmessage_get_messageid(const cJSON *msg, cJSON **cmsgidP)
 {
-    cJSON *respmsg = NULL;
-    cJSON *msgid = cJSON_GetObjectItem(request, "id");
-       cJSON *command = cJSON_GetObjectItem(request, "method");
-       
-       if (!msgid || !command) {
-           return NULL;
+       uint32_t msgid = 0;
+
+       cJSON *cmsgid = cJSON_GetObjectItem(msg, "id");
+
+       if (cmsgid->type == cJSON_Number) {
+               msgid = (uint32_t) cmsgid->valueint;
        }
-       
-    *pmsg = respmsg = ks_rpcmessage_dup(msgid);
+       
+       *cmsgidP = cmsgid;      
+
+       return msgid;
+} 
+
+
+static ks_rpcmessage_id ks_rpcmessage_new_response(ks_rpcmessaging_handle_t* handle,
+                                                const cJSON *request,
+                                                cJSON *result,
+                                                cJSON **pmsg)
+{
+    cJSON *respmsg = NULL;
+    cJSON *cmsgid  = NULL;
+    cJSON *command = cJSON_GetObjectItem(request, "method");
+
+       ks_rpcmessage_id 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) {
-           cJSON_AddItemToObject(respmsg, "result", result);
+    if (handle->version[0] != 0) {
+        cJSON_AddItemToObject(respmsg, "version", cJSON_CreateString(handle->version));
+    }
+
+    if (result) {
+        cJSON_AddItemToObject(respmsg, "result", result);
+    }
+
+    return msgid;
+}
+
+
+KS_DECLARE(ks_rpcmessage_id) ks_rpcmessage_create_response(ks_rpcmessaging_handle_t* handle,
+                                                                                               const cJSON *request,
+                                                                                               cJSON **resultP,
+                                                                                               cJSON **responseP)
+{
+       ks_rpcmessage_id msgid = ks_rpcmessage_new_response(handle, request, *resultP, responseP);
+       cJSON *respmsg = *responseP;
+
+    if (msgid) {
+
+               if (*resultP == NULL) {
+                       *resultP = cJSON_CreateObject();
+                       cJSON_AddItemToObject(respmsg, "result", *resultP);
+               }
        }
 
-    return respmsg;
+    return msgid;
 }
 
-KS_DECLARE(ks_status_t) ks_rpcmessage_namespace(ks_rpcmessaging_handle_t* handle, const char* namespace)
+KS_DECLARE(ks_rpcmessage_id) ks_rpcmessage_create_errorresponse(ks_rpcmessaging_handle_t* handle, 
+                                                                                               const cJSON *request, 
+                                                                                               cJSON **errorP, 
+                                                                                               cJSON **responseP)
+{
+       ks_rpcmessage_id msgid = ks_rpcmessage_new_response(handle, request, *errorP, responseP);
+       cJSON *respmsg = *responseP;
+
+       if (msgid) { 
+  
+               if (*errorP == NULL) {
+                       *errorP = cJSON_CreateObject();
+                       cJSON_AddItemToObject(respmsg, "error", *errorP);
+               }
+       }
+
+    return msgid;
+}
+
+KS_DECLARE(ks_status_t) ks_rpcmessage_namespace(ks_rpcmessaging_handle_t* handle, const char* namespace, const char* version)
 {
+       memset(handle->namespace, 0, sizeof(handle->namespace));
+    memset(handle->version, 0, sizeof(handle->version)); 
 
-       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);
+       strncpy(handle->namespace, namespace, KS_RPCMESSAGE_NAMESPACE_LENGTH);
+    strncpy(handle->version, version, KS_RPCMESSAGE_VERSION_LENGTH);
+       handle->namespace[sizeof(handle->namespace) - 1] = 0;
+       handle->version[sizeof(handle->version) -1] = 0;
+
+    ks_log(KS_LOG_DEBUG, "Setting message namespace value %s, version %s", handle->namespace, handle->version);
        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)
+KS_DECLARE(ks_status_t) ks_rpcmessage_register_function(ks_rpcmessaging_handle_t* handle, 
+                                                                                               const char *command, 
+                                                                                               jrpc_func_t func,
+                                                                                               jrpc_resp_func_t respfunc)
 {
-       char fqcommand[256];
+       if (!func && !respfunc) {
+               return KS_STATUS_FAIL;
+       }
+
+       char fqcommand[KS_PRCMESSAGE_FQCOMMAND_LENGTH];
     memset(fqcommand, 0, sizeof(fqcommand));
 
        if (handle->namespace[0] != 0) {
@@ -209,11 +322,17 @@ KS_DECLARE(ks_status_t) ks_rpcmessage_register_function(ks_rpcmessaging_handle_t
                lkey = 16;
        }       
 
-       char *key = (char*)ks_pool_alloc(handle->pool, lkey);
-       strcpy(key, fqcommand);
+       ks_rpcmessage_callbackpair_t* callbacks =
+                       (ks_rpcmessage_callbackpair_t*)ks_pool_alloc(handle->pool, lkey + sizeof(ks_rpcmessage_callbackpair_t));
+
+       strcpy(callbacks->command, fqcommand);
+       callbacks->command_length = lkey;
+       callbacks->request_func = func;
+       callbacks->response_func = respfunc;
 
        ks_hash_write_lock(handle->method_hash);
-       ks_hash_insert(handle->method_hash, key, (void *) (intptr_t)func);
+       ks_hash_insert(handle->method_hash, callbacks->command, (void *) callbacks);
+
        ks_hash_write_unlock(handle->method_hash);
 
        ks_log(KS_LOG_DEBUG, "Message %s registered (%s)\n", command, fqcommand);
@@ -221,27 +340,60 @@ KS_DECLARE(ks_status_t) ks_rpcmessage_register_function(ks_rpcmessaging_handle_t
        return KS_STATUS_SUCCESS;
 }
 
+static ks_rpcmessage_callbackpair_t* ks_rpcmessage_find_function_ex(ks_rpcmessaging_handle_t* handle, char *command)
+{
+       ks_hash_read_lock(handle->method_hash);
+
+        ks_rpcmessage_callbackpair_t* callbacks = ks_hash_search(handle->method_hash, command, KS_UNLOCKED);
+
+       ks_hash_read_unlock(handle->method_hash);
+
+       return callbacks;
+}
+
 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));
+    char fqcommand[KS_PRCMESSAGE_FQCOMMAND_LENGTH];
+    memset(fqcommand, 0, sizeof(fqcommand));
 
     if (handle->namespace[0] != 0) {
         strcpy(fqcommand, handle->namespace);
+               strcat(fqcommand, command);
     }
-
-    strcat(fqcommand, command);
+       else {
+               strcpy(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_rpcmessage_callbackpair_t* callbacks = ks_rpcmessage_find_function_ex(handle, (char *)fqcommand);
 
-       ks_hash_read_unlock(handle->method_hash);
+       if (!callbacks) {
+               return NULL;
+       }
 
-       return func;
+       return callbacks->request_func;
 }
 
-KS_DECLARE(ks_status_t) ks_rpcmessage_process_jsonrequest(ks_rpcmessaging_handle_t* handle, cJSON *request, cJSON **responseP)
+KS_DECLARE(jrpc_resp_func_t) ks_rpcmessage_find_response_function(ks_rpcmessaging_handle_t* handle, const char *command)
+{
+    char fqcommand[KS_PRCMESSAGE_FQCOMMAND_LENGTH];
+    memset(fqcommand, 0, sizeof(fqcommand));
+
+    if (handle->namespace[0] != 0) {
+        strcpy(fqcommand, handle->namespace);
+        strcat(fqcommand, command);
+    }
+    else {
+        strcpy(fqcommand, command);
+    }
+
+    ks_rpcmessage_callbackpair_t* callbacks = ks_rpcmessage_find_function_ex(handle, (char *)fqcommand);
+
+    return callbacks->response_func;
+}
+
+
+KS_DECLARE(ks_status_t) ks_rpcmessage_process_jsonmessage(ks_rpcmessaging_handle_t* handle, cJSON *request, cJSON **responseP)
 {
        const char *command = cJSON_GetObjectCstr(request, "method");
        cJSON *error = NULL;
@@ -255,21 +407,33 @@ KS_DECLARE(ks_status_t) ks_rpcmessage_process_jsonrequest(ks_rpcmessaging_handle
        //todo - add more checks ? 
 
        if (error) {
-               *responseP = response = ks_rpcmessage_new_request(handle, 0, &error, &response);
+               ks_rpcmessage_create_request(handle, 0, &error, &response);
                return KS_STATUS_FAIL;
        }
 
-       jrpc_func_t func = ks_rpcmessage_find_function(handle, command);
-       if (!func) {
+       
+       ks_rpcmessage_callbackpair_t* callbacks = ks_rpcmessage_find_function_ex(handle, (char *)command);
+
+       if (!callbacks) {
                error = cJSON_CreateString("Command not supported");
+               return  KS_STATUS_FAIL;
+       }
+
+       ks_bool_t isrequest = ks_rpcmessage_isrequest(request);
+
+       if (isrequest && callbacks->request_func) {
+               return callbacks->request_func(handle, request, responseP);
+       }
+    else if (!isrequest && callbacks->response_func) {
+               return callbacks->response_func(handle, request);
        }
 
-       return  func(handle, request, responseP);
+       return KS_STATUS_FAIL;
 }
 
 
 
-KS_DECLARE(ks_status_t) ks_rpcmessage_process_request(ks_rpcmessaging_handle_t* handle, 
+KS_DECLARE(ks_status_t) ks_rpcmessage_process_message(ks_rpcmessaging_handle_t* handle, 
                                                                                                                uint8_t *data, 
                                                                                                                ks_size_t size, 
                                                                                                                cJSON **responseP)
@@ -281,11 +445,11 @@ KS_DECLARE(ks_status_t) ks_rpcmessage_process_request(ks_rpcmessaging_handle_t*
 
        if (!request) {
                error = cJSON_CreateString("Invalid json format");
-               *responseP = response = ks_rpcmessage_new_request(handle, 0, &error, &response);
+               ks_rpcmessage_create_request(handle, 0, &error, &response);
                return  KS_STATUS_FAIL; 
        }
 
-       ks_status_t status = ks_rpcmessage_process_jsonrequest(handle, request, responseP);
+       ks_status_t status = ks_rpcmessage_process_jsonmessage(handle, request, responseP);
 
        cJSON_Delete(request);
 
diff --git a/libs/libks/test/testmessages.c b/libs/libks/test/testmessages.c
new file mode 100644 (file)
index 0000000..689173f
--- /dev/null
@@ -0,0 +1,273 @@
+#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;
+ks_thread_pool_t *tpool;
+
+ks_rpcmessaging_handle_t *h;
+
+static ks_thread_t *threads[10];
+
+static char idbuffer[51];
+
+
+static ks_status_t  process_wombat_response(ks_rpcmessaging_handle_t* handle, cJSON *msg)
+{
+          printf("entering process_wombat_response\n");
+          printf("exiting process_wombat_response\n");
+               return KS_STATUS_FAIL;
+}
+
+static ks_status_t  process_wombat(ks_rpcmessaging_handle_t* handle, cJSON *msg, cJSON **response)
+{
+       printf("entering process_wombat\n");
+       
+       char *b0 = cJSON_Print(msg);
+       printf("Request: %s\n", b0);
+       free(b0);
+
+       cJSON *msg_id = cJSON_GetObjectItem(msg, "id");
+       if (msg_id) {
+               if (msg_id->type == cJSON_Number) {
+                       printf("Number int %d double %f\n", msg_id->valueint, msg_id->valuedouble);
+               }
+       }
+       
+       cJSON *respvalue = cJSON_CreateNumber(1);
+
+       ks_rpcmessage_id msgid = ks_rpcmessage_create_response(h, msg, &respvalue, response);
+
+    char *b1 = cJSON_Print(*response);   //(*response);
+    printf("Response: msgid %d\n%s\n", msgid, b1);
+    free(b1);
+
+    printf("exiting process_wombat\n");
+
+       return KS_STATUS_SUCCESS; 
+}
+
+static ks_status_t  process_badbunny(ks_rpcmessaging_handle_t* handle, cJSON *msg, cJSON **response)
+{
+    printf("entering process_badbunny\n");
+
+    char *b0 = cJSON_Print(msg);
+    printf("Request: %s\n", b0);
+    free(b0);
+
+    cJSON *msg_id = cJSON_GetObjectItem(msg, "id");
+    if (msg_id) {
+        if (msg_id->type == cJSON_Number) {
+            printf("Number int %d double %f\n", msg_id->valueint, msg_id->valuedouble);
+        }
+    }
+
+    cJSON *respvalue;
+
+    ks_rpcmessage_id msgid = ks_rpcmessage_create_errorresponse(h, msg, &respvalue, response);
+
+    char *b2 = cJSON_Print(*response);
+    printf("Request: msgid %d\n%s\n", msgid, b2);
+    free(b2);
+
+       //cJSON *respvalue = cJSON_CreateNumber(1);
+       
+
+    char *b1 = cJSON_Print(*response);   //(*response);
+    printf("Response: %s\n", b1);
+    free(b1);
+
+    printf("exiting process_badbunny\n");
+
+
+    return KS_STATUS_SUCCESS;
+}
+
+
+void test01()
+{
+       printf("**** testrpcmessages - test01 start\n"); fflush(stdout);
+
+       ks_rpcmessage_register_function(h, "wombat", process_wombat, process_wombat_response); 
+    ks_rpcmessage_register_function(h, "badbunny", process_badbunny, NULL);
+    ks_rpcmessage_register_function(h, "onewaywombat", NULL, process_wombat_response);
+
+       cJSON* request = NULL;
+       cJSON* parms   = NULL;
+    cJSON* response  = NULL;
+
+       /* try an invalid message */
+
+       ks_rpcmessage_id msgid = ks_rpcmessage_create_request(h, "colm", &parms, &request);
+       if (msgid != 0) {
+               printf("invalid message created %d\n", msgid);
+               printf("request:\n%s\n", cJSON_Print(request));
+       }       
+       
+       /* try a basic message */
+
+    msgid = ks_rpcmessage_create_request(h, "wombat", &parms, &request); 
+       if (msgid == 0) {
+               printf("failed to create a wombat\n");
+               return;
+       }
+
+       cJSON_AddStringToObject(parms, "hello", "cruel world");
+       char* data = cJSON_PrintUnformatted(request);   
+       
+       printf("\ntest01 request: %d\n%s\n\n", msgid, data);
+
+       /* process message */
+       
+       ks_size_t size = strlen(data);
+       ks_status_t status = ks_rpcmessage_process_message(h, (uint8_t*)data, size, &response);
+
+       char* data1 = cJSON_Print(response);
+       ks_size_t size1 = strlen(data1);
+    printf("\ntest01i response: %d\n%s\n\n", msgid, data1);
+       
+       /* process response */
+
+       ks_status_t status1 = ks_rpcmessage_process_message(h, (uint8_t*)data1, size1, &response);
+
+       free(data);
+       free(data1);
+       cJSON_Delete(request);
+
+       /* create message 2 */
+       
+       cJSON *parms1 = cJSON_CreateNumber(1);
+    cJSON *request1  = NULL;
+
+    msgid = ks_rpcmessage_create_request(h, "badbunny", &parms1, &request1);
+
+       data = cJSON_PrintUnformatted(request1);
+       printf("\ntest01i request: %d\n%s\n\n", msgid, data);
+
+       /* process message 2 */
+
+       size = strlen(data);
+       status = ks_rpcmessage_process_message(h, (uint8_t*)data, size, &response);
+       data1 = cJSON_PrintUnformatted(response);
+    printf("\ntest01 response: %d\n%s\n\n", msgid, data1);
+       /* process response 2 - no handler so this should fail */
+
+    size1 = strlen(data1);
+               
+       status = ks_rpcmessage_process_message(h, (uint8_t*)data1, size1, &response);
+       
+       if (status != KS_STATUS_FAIL) {
+               printf("badbunny found a response handler ?\n");
+       }
+
+    free(data);
+    free(data1);
+    cJSON_Delete(request1);
+       
+
+       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;
+}
+
+
+
+
+/* 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<argc; ++tix) {
+                       long i = strtol(argv[tix], NULL, 0);
+                       tests[tix] = i;
+               }
+       }
+
+       ks_init();
+       ks_global_set_default_logger(7);
+
+
+       ks_status_t status;
+
+       status = ks_pool_open(&pool);
+
+
+       for (int tix=0; tix<argc; ++tix) {
+
+               if (tests[tix] == 1) {
+                       ks_rpcmessage_init(pool, &h);
+                       test01();
+                       ks_rpcmessage_deinit(&h);
+                       continue;
+               }
+
+               if (tests[tix] == 2) {
+                       ks_rpcmessage_init(pool, &h);
+                       test02();
+                       ks_rpcmessage_deinit(&h);
+                       continue;
+               }
+
+       }
+
+       return 0;
+}