2828#include <string.h>
2929#include <stdbool.h>
3030
31+ /*--- memory management hooks ---*/
32+
33+ // Global memory function pointers, default to standard library functions
34+ static mjrpc_malloc_func g_mjrpc_malloc = malloc ;
35+ static mjrpc_free_func g_mjrpc_free = free ;
36+ static mjrpc_strdup_func g_mjrpc_strdup = strdup ;
37+
3138/*--- utility ---*/
3239
3340enum method_state
@@ -54,7 +61,8 @@ static int resize(mjrpc_handle_t* handle)
5461
5562 handle -> capacity *= 2 ;
5663 handle -> size = 0 ;
57- handle -> methods = (struct mjrpc_method * ) calloc (handle -> capacity , sizeof (struct mjrpc_method ));
64+ handle -> methods =
65+ (struct mjrpc_method * ) g_mjrpc_malloc (handle -> capacity * sizeof (struct mjrpc_method ));
5866 if (handle -> methods == NULL )
5967 {
6068 handle -> capacity = old_capacity ;
@@ -67,10 +75,10 @@ static int resize(mjrpc_handle_t* handle)
6775 if (old_methods [i ].state == OCCUPIED )
6876 {
6977 mjrpc_add_method (handle , old_methods [i ].func , old_methods [i ].name , old_methods [i ].arg );
70- free (old_methods [i ].name );
78+ g_mjrpc_free (old_methods [i ].name );
7179 }
7280 }
73- free (old_methods );
81+ g_mjrpc_free (old_methods );
7482 return MJRPC_RET_OK ;
7583}
7684
@@ -107,8 +115,8 @@ static cJSON* invoke_callback(const mjrpc_handle_t* handle, const char* method_n
107115 ctx .error_message = NULL ;
108116 if (!method_get ((mjrpc_handle_t * ) handle , method_name , & func , & arg ) || !func )
109117 {
110- return mjrpc_response_error (JSON_RPC_CODE_METHOD_NOT_FOUND , strdup ( "Method not found." ),
111- id );
118+ return mjrpc_response_error (JSON_RPC_CODE_METHOD_NOT_FOUND ,
119+ g_mjrpc_strdup ( "Method not found." ), id );
112120 }
113121 ctx .data = arg ;
114122 returned = func (& ctx , params , id );
@@ -144,9 +152,9 @@ static cJSON* rpc_handle_obj_req(const mjrpc_handle_t* handle, const cJSON* requ
144152 const cJSON * version = cJSON_GetObjectItem (request , "jsonrpc" );
145153 if (version == NULL || version -> type != cJSON_String ||
146154 strcmp ("2.0" , version -> valuestring ) != 0 )
147- return mjrpc_response_error (JSON_RPC_CODE_INVALID_REQUEST ,
148- strdup ( "Invalid request received: JSONRPC version error." ) ,
149- id_copy );
155+ return mjrpc_response_error (
156+ JSON_RPC_CODE_INVALID_REQUEST ,
157+ g_mjrpc_strdup ( "Invalid request received: JSONRPC version error." ), id_copy );
150158
151159 const cJSON * method = cJSON_GetObjectItem (request , "method" );
152160 if (method != NULL && method -> type == cJSON_String )
@@ -156,12 +164,12 @@ static cJSON* rpc_handle_obj_req(const mjrpc_handle_t* handle, const cJSON* requ
156164 return invoke_callback (handle , method -> valuestring , params , id_copy );
157165 }
158166 return mjrpc_response_error (JSON_RPC_CODE_INVALID_REQUEST ,
159- strdup ("Invalid request received: No 'method' member." ),
167+ g_mjrpc_strdup ("Invalid request received: No 'method' member." ),
160168 id_copy );
161169 }
162170 // Invalid id type
163171 return mjrpc_response_error (JSON_RPC_CODE_INVALID_REQUEST ,
164- strdup ("Invalid request received: 'id' member type error." ),
172+ g_mjrpc_strdup ("Invalid request received: 'id' member type error." ),
165173 cJSON_CreateNull ());
166174}
167175
@@ -243,7 +251,7 @@ cJSON* mjrpc_response_error(int code, char* message, cJSON* id)
243251 if (id == NULL )
244252 {
245253 if (message )
246- free (message );
254+ g_mjrpc_free (message );
247255 return NULL ;
248256 }
249257
@@ -266,7 +274,7 @@ cJSON* mjrpc_response_error(int code, char* message, cJSON* id)
266274 if (message )
267275 {
268276 cJSON_AddStringToObject (error_root , "message" , message );
269- free (message );
277+ g_mjrpc_free (message );
270278 }
271279 else
272280 {
@@ -286,15 +294,16 @@ mjrpc_handle_t* mjrpc_create_handle(size_t initial_capacity)
286294{
287295 if (initial_capacity == 0 )
288296 initial_capacity = DEFAULT_INITIAL_CAPACITY ;
289- mjrpc_handle_t * handle = malloc (sizeof (mjrpc_handle_t ));
297+ mjrpc_handle_t * handle = g_mjrpc_malloc (sizeof (mjrpc_handle_t ));
290298 if (handle == NULL )
291299 return NULL ;
292300 handle -> capacity = initial_capacity ;
293301 handle -> size = 0 ;
294- handle -> methods = (struct mjrpc_method * ) calloc (handle -> capacity , sizeof (struct mjrpc_method ));
302+ handle -> methods =
303+ (struct mjrpc_method * ) g_mjrpc_malloc (handle -> capacity * sizeof (struct mjrpc_method ));
295304 if (handle -> methods == NULL )
296305 {
297- free (handle );
306+ g_mjrpc_free (handle );
298307 return NULL ;
299308 }
300309 return handle ;
@@ -308,13 +317,13 @@ int mjrpc_destroy_handle(mjrpc_handle_t* handle)
308317 {
309318 if (handle -> methods [i ].state == OCCUPIED )
310319 {
311- free (handle -> methods [i ].name );
320+ g_mjrpc_free (handle -> methods [i ].name );
312321 if (handle -> methods [i ].arg != NULL )
313- free (handle -> methods [i ].arg );
322+ g_mjrpc_free (handle -> methods [i ].arg );
314323 }
315324 }
316- free (handle -> methods );
317- free (handle );
325+ g_mjrpc_free (handle -> methods );
326+ g_mjrpc_free (handle );
318327 return MJRPC_RET_OK ;
319328}
320329
@@ -345,7 +354,7 @@ int mjrpc_add_method(mjrpc_handle_t* handle, mjrpc_func function_pointer, const
345354 index = (index + probe_count * probe_count ) % handle -> capacity ;
346355 }
347356
348- handle -> methods [index ].name = strdup (method_name );
357+ handle -> methods [index ].name = g_mjrpc_strdup (method_name );
349358 handle -> methods [index ].func = function_pointer ;
350359 handle -> methods [index ].arg = arg2func ;
351360 handle -> methods [index ].state = OCCUPIED ;
@@ -365,9 +374,9 @@ int mjrpc_del_method(mjrpc_handle_t* handle, const char* name)
365374 if (handle -> methods [index ].state == OCCUPIED &&
366375 strcmp (handle -> methods [index ].name , name ) == 0 )
367376 {
368- free (handle -> methods [index ].name );
377+ g_mjrpc_free (handle -> methods [index ].name );
369378 if (handle -> methods [index ].arg != NULL )
370- free (handle -> methods [index ].arg );
379+ g_mjrpc_free (handle -> methods [index ].arg );
371380 handle -> methods [index ].state = DELETED ;
372381 handle -> size -- ;
373382 return MJRPC_RET_OK ;
@@ -410,7 +419,8 @@ cJSON* mjrpc_process_cjson(mjrpc_handle_t* handle, const cJSON* request_cjson, i
410419 * ret_code = ret ;
411420 return mjrpc_response_error (
412421 JSON_RPC_CODE_PARSE_ERROR ,
413- strdup ("Invalid request received: Not a JSON formatted request." ), cJSON_CreateNull ());
422+ g_mjrpc_strdup ("Invalid request received: Not a JSON formatted request." ),
423+ cJSON_CreateNull ());
414424 }
415425
416426 cJSON * cjson_return = NULL ;
@@ -422,7 +432,7 @@ cJSON* mjrpc_process_cjson(mjrpc_handle_t* handle, const cJSON* request_cjson, i
422432 ret = MJRPC_RET_ERROR_EMPTY_REQUEST ;
423433 cjson_return = mjrpc_response_error (
424434 JSON_RPC_CODE_PARSE_ERROR ,
425- strdup ("Invalid request received: Empty JSON array." ), cJSON_CreateNull ());
435+ g_mjrpc_strdup ("Invalid request received: Empty JSON array." ), cJSON_CreateNull ());
426436 }
427437 else
428438 {
@@ -441,7 +451,7 @@ cJSON* mjrpc_process_cjson(mjrpc_handle_t* handle, const cJSON* request_cjson, i
441451 ret = MJRPC_RET_ERROR_EMPTY_REQUEST ;
442452 cjson_return = mjrpc_response_error (
443453 JSON_RPC_CODE_PARSE_ERROR ,
444- strdup ("Invalid request received: Empty JSON object." ), cJSON_CreateNull ());
454+ g_mjrpc_strdup ("Invalid request received: Empty JSON object." ), cJSON_CreateNull ());
445455 }
446456 else
447457 {
@@ -456,10 +466,37 @@ cJSON* mjrpc_process_cjson(mjrpc_handle_t* handle, const cJSON* request_cjson, i
456466 {
457467 cjson_return = mjrpc_response_error (
458468 JSON_RPC_CODE_PARSE_ERROR ,
459- strdup ("Invalid request received: Not a JSON object or array." ), cJSON_CreateNull ());
469+ g_mjrpc_strdup ("Invalid request received: Not a JSON object or array." ),
470+ cJSON_CreateNull ());
460471 ret = MJRPC_RET_ERROR_NOT_OBJ_ARY ;
461472 }
462473 if (ret_code )
463474 * ret_code = ret ;
464475 return cjson_return ;
465476}
477+
478+ int mjrpc_set_memory_hooks (mjrpc_malloc_func malloc_func , mjrpc_free_func free_func ,
479+ mjrpc_strdup_func strdup_func )
480+ {
481+ // If all parameters are NULL, reset to default functions
482+ if (malloc_func == NULL && free_func == NULL && strdup_func == NULL )
483+ {
484+ g_mjrpc_malloc = malloc ;
485+ g_mjrpc_free = free ;
486+ g_mjrpc_strdup = strdup ;
487+ return MJRPC_RET_OK ;
488+ }
489+
490+ // If any parameter is not NULL, all must be provided
491+ if (malloc_func == NULL || free_func == NULL || strdup_func == NULL )
492+ {
493+ return MJRPC_RET_ERROR_INVALID_PARAM ;
494+ }
495+
496+ // Set custom functions
497+ g_mjrpc_malloc = malloc_func ;
498+ g_mjrpc_free = free_func ;
499+ g_mjrpc_strdup = strdup_func ;
500+
501+ return MJRPC_RET_OK ;
502+ }
0 commit comments