int add_method_entry(struct method_lookup *lookup, const char *method, rpc_method_impl_t target_method_impl, void *data) { int i; for(i = 0; i < METHOD_LOOKUP_CACHE_SIZE; i++) { if(!lookup->cached_method_name[i]) { lookup->cached_method_name[i] = private_strdup(method); lookup->cached_target_method_impl[i] = target_method_impl; lookup->cached_satellite_data[i] = data; break; } } if(i == METHOD_LOOKUP_CACHE_SIZE) { struct method_entry *entry = (struct method_entry *)malloc( sizeof(struct method_entry)); if(!entry) { return 1; } entry->method_name = private_strdup(method); entry->target_method_impl = target_method_impl; entry->satellite_data = data; entry->next = NULL; if(lookup->head == NULL) { lookup->head = entry; } else { struct method_entry *iter = lookup->head; while(iter->next != NULL) { iter = iter->next; } iter->next = entry; } } return 0; }
/** * \brief Gets the file name without the path component. * \param path Path string. * \return New string or NULL. */ char* lisys_path_basename ( const char* path) { char* ptr; ptr = strrchr (path, '/'); if (ptr == NULL) return private_strdup (path); return private_strdup (ptr + 1); }
struct method_t *make_request_vote_rpc_method(struct request_vote_input_t *input) { struct data_t **params = (struct data_t **)malloc( sizeof(struct data_t *)*REQUEST_VOTE_PARAM_COUNT); if(!params) { DBG_LOG(LOG_FATAL, "memory allocation failed"); return NULL; } params[0] = uint64_to_data_t(input->term); params[1] = uint32_to_data_t(input->candidate_id); params[2] = uint64_to_data_t(input->last_log_index); params[3] = uint64_to_data_t(input->last_log_term); char *method_name = private_strdup(REQUEST_VOTE_RPC); struct method_t *request_vote = (struct method_t *)malloc(sizeof(struct method_t)); if(!request_vote) { DBG_LOG(LOG_FATAL, "memory allocation failed"); if(method_name) free(method_name); for(int i = 0; i < REQUEST_VOTE_PARAM_COUNT; i++) { if(params[i]) { free_data_t(params[i]); } } free(params); return NULL; } request_vote->name = method_name; request_vote->params = params; request_vote->nparams = REQUEST_VOTE_PARAM_COUNT; return request_vote; }
struct data_t *deserialize_data(json_t *json_data) { struct data_t *data = (struct data_t *)malloc(sizeof(struct data_t)); if(json_is_integer(json_data)) { data->type = RPC_INT; data->value = (json_int_t *)malloc(sizeof(json_int_t)); *(json_int_t *)data->value = json_integer_value(json_data); } else if(json_is_real(json_data)) { data->type = RPC_REAL; data->value = (double *)malloc(sizeof(double)); *(double *)data->value = json_real_value(json_data); } else if(json_is_string(json_data)) { data->type = RPC_STRING; data->value = private_strdup(json_string_value(json_data)); } else if(json_is_array(json_data)) { data->type = RPC_VECTOR; data->length = json_array_size(json_data); data->child = (struct data_t **)malloc(sizeof(struct data_t *)*data->length); for(int i = 0; i < data->length; i++) { data->child[i] = deserialize_data(json_array_get(json_data, i)); } } else { return NULL; } return data; }
//deserializes the method which serialized at caller //returns method name to be called and the params/nparams //are the arguments to the method call //returns NULL on error struct method_t *deserialize_method_call(const char *serialized) { json_t *root; json_error_t parse_error; root = json_loads(serialized, 0, &parse_error); if(!root || !json_is_object(root)) { if(root) json_decref(root); return NULL; } json_t *json_method_name = json_object_get(root, METHOD_JSON_KEY); json_t *json_method_params = json_object_get(root, PARAMS_JSON_KEY); if(!json_method_name || !json_method_params) { json_decref(root); return NULL; } char *method_name = NULL; if(!json_is_string(json_method_name)) { json_decref(root); return NULL; } method_name = private_strdup(json_string_value(json_method_name)); struct data_t *envelope = deserialize_data(json_method_params); if(!envelope || envelope->type != RPC_VECTOR) { free(method_name); json_decref(root); return NULL; } struct method_t *mtd = (struct method_t *) malloc(sizeof(struct method_t)); if(!mtd) { free(method_name); free_data_t(envelope); json_decref(root); return NULL; } mtd->name = method_name; mtd->params = envelope->child; mtd->nparams = envelope->length; free(envelope); json_decref(root); return mtd; }
// method result is expected in following format // { // "result-type" : "<SUCCESS/ERROR>", // "result" : <error string or actual result> // } // return value or error needs to be freed struct data_t *deserialize_result(const char *serialized, char **error) { json_t *root; json_error_t parse_error; root = json_loads(serialized, 0, &parse_error); if(!root || !json_is_object(root)) { if(root) json_decref(root); return NULL; } json_t *result_type = json_object_get(root, RESULT_TYPE_JSON_KEY); json_t *result = json_object_get(root, RESULT_JSON_KEY); if(!result_type || !result) { json_decref(root); return NULL; } if(!json_is_string(result_type)) { json_decref(root); return NULL; } if(0 == strcmp("SUCCESS", json_string_value(result_type))) { struct data_t *data = deserialize_data(result); json_decref(root); return data; } else { if(!json_is_string(result)) { json_decref(root); return NULL; } *error = private_strdup(json_string_value(result)); json_decref(root); } return NULL; }
struct method_t *make_append_entries_rpc_method(struct append_entries_input_t *input) { struct data_t **params = (struct data_t **)malloc(sizeof(struct data_t *)*APPEND_ENTRIES_PARAM_COUNT); if(!params) { DBG_LOG(LOG_FATAL, "memory allocation failed"); return NULL; } params[0] = uint64_to_data_t(input->term); params[1] = uint32_to_data_t(input->leader_id); params[2] = uint64_to_data_t(input->prev_log_index); params[3] = uint64_to_data_t(input->prev_log_term); params[4] = uint64_to_data_t(input->leader_commit_index); struct data_t *entries_array = (struct data_t *)malloc(sizeof(struct data_t)); if(entries_array) { entries_array->type = RPC_VECTOR; entries_array->length = input->nentries; entries_array->child = (struct data_t **)malloc( sizeof(struct data_t *)*input->nentries); if(entries_array->child) { int alldone = 1; for(int i = 0; i < input->nentries; i++) { entries_array->child[i] = log_to_data_t(input->entries[i]); if(!entries_array->child[i]) { entries_array->length = i; alldone = 0; break; } } if(alldone) { params[5] = entries_array; } else { free_data_t(entries_array); } } else { free(entries_array); } } char *method_name = private_strdup(APPEND_ENTRIES_RPC); //none of the above allocation failure are handled assuming if //one fails the subsequent allocation will also fail including //allocation of append_entries hence all of them handled together // below struct method_t *append_entries = (struct method_t *)malloc( sizeof(struct method_t)); if(!append_entries) { DBG_LOG(LOG_FATAL, "memory allocation failed"); if(method_name) free(method_name); for(int i = 0; i < APPEND_ENTRIES_PARAM_COUNT; i++) { if(params[i]) { free_data_t(params[i]); } } free(params); return NULL; } append_entries->name = method_name; append_entries->params = params; append_entries->nparams = APPEND_ENTRIES_PARAM_COUNT; return append_entries; }