From 0b5d4c5f31a11cd34001416f8a912ee481a8f864 Mon Sep 17 00:00:00 2001 From: mkind Date: Thu, 6 Oct 2016 07:20:20 +0200 Subject: [PATCH 01/41] incrementing version number --- src/version.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/version.h b/src/version.h index 124db07..db4ad00 100644 --- a/src/version.h +++ b/src/version.h @@ -21,7 +21,7 @@ #define VERSION_MAJOR 0 #define VERSION_MINOR 1 -#define VERSION_REVISION 5 +#define VERSION_REVISION 6 #define VERSION STRINGIFY(VERSION_MAJOR) "." \ STRINGIFY(VERSION_MINOR) "." \ From 2d6fa5d45b54052ae8a82c66be4018d212ae803a Mon Sep 17 00:00:00 2001 From: Stephan Zeisberg Date: Fri, 21 Oct 2016 22:21:18 +0200 Subject: [PATCH 02/41] Add memdup functions to util module * memdup without nul-terminate * memdup with nul-terminate --- src/rpc/msgpack/message.c | 469 ------------------ src/rpc/msgpack/pack.c | 208 -------- src/rpc/msgpack/sb-msgpack-rpc.h | 104 ---- src/rpc/msgpack/unpack.c | 140 ------ src/util.c | 27 + .../unit/message-deserialize-error-response.c | 156 ------ test/unit/message-deserialize-request.c | 157 ------ test/unit/message-deserialize-response.c | 152 ------ test/unit/message-is-request.c | 76 --- test/unit/message-is-response.c | 76 --- test/unit/message-serialize-error-response.c | 43 -- test/unit/message-serialize-request.c | 77 --- test/unit/message-serialize-response.c | 65 --- test/unit/pack-array.c | 61 --- test/unit/pack-bool.c | 37 -- test/unit/pack-float.c | 36 -- test/unit/pack-int.c | 53 -- test/unit/pack-nil.c | 36 -- test/unit/pack-string.c | 38 -- test/unit/pack-uint.c | 53 -- test/unit/regression-issue-60.c | 47 -- test/unit/unpack-array.c | 78 --- test/unit/unpack-string.c | 42 -- test/unit/unpack-uint.c | 45 -- 24 files changed, 27 insertions(+), 2249 deletions(-) delete mode 100644 src/rpc/msgpack/message.c delete mode 100644 src/rpc/msgpack/pack.c delete mode 100644 src/rpc/msgpack/sb-msgpack-rpc.h delete mode 100644 src/rpc/msgpack/unpack.c delete mode 100644 test/unit/message-deserialize-error-response.c delete mode 100644 test/unit/message-deserialize-request.c delete mode 100644 test/unit/message-deserialize-response.c delete mode 100644 test/unit/message-is-request.c delete mode 100644 test/unit/message-is-response.c delete mode 100644 test/unit/message-serialize-error-response.c delete mode 100644 test/unit/message-serialize-request.c delete mode 100644 test/unit/message-serialize-response.c delete mode 100644 test/unit/pack-array.c delete mode 100644 test/unit/pack-bool.c delete mode 100644 test/unit/pack-float.c delete mode 100644 test/unit/pack-int.c delete mode 100644 test/unit/pack-nil.c delete mode 100644 test/unit/pack-string.c delete mode 100644 test/unit/pack-uint.c delete mode 100644 test/unit/regression-issue-60.c delete mode 100644 test/unit/unpack-array.c delete mode 100644 test/unit/unpack-string.c delete mode 100644 test/unit/unpack-uint.c diff --git a/src/rpc/msgpack/message.c b/src/rpc/msgpack/message.c deleted file mode 100644 index cfadb58..0000000 --- a/src/rpc/msgpack/message.c +++ /dev/null @@ -1,469 +0,0 @@ -/** - * Copyright (C) 2015 splone UG - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ - -#include -#include - -#include "rpc/msgpack/sb-msgpack-rpc.h" -#include "sb-common.h" - -bool message_is_request(msgpack_object *obj) -{ - if (!obj) - return (false); - - /* check if type is mspack_object_params */ - if (obj->type != MSGPACK_OBJECT_ARRAY) - return (false); - - msgpack_object_array *params = &obj->via.array; - - return (params->size == MESSAGE_REQUEST_ARRAY_SIZE && - params->ptr[0].type == MSGPACK_OBJECT_POSITIVE_INTEGER && - params->ptr[0].via.u64 == MESSAGE_TYPE_REQUEST); -} - - -bool message_is_response(msgpack_object *obj) -{ - if (!obj) - return (false); - - /* check if type is mspack_object_array */ - if (obj->type != MSGPACK_OBJECT_ARRAY) - return (false); - - msgpack_object_array *array = &obj->via.array; - - /* check if message is a response */ - return (array->size == MESSAGE_RESPONSE_ARRAY_SIZE && - array->ptr[0].type == MSGPACK_OBJECT_POSITIVE_INTEGER && - array->ptr[0].via.u64 == MESSAGE_TYPE_RESPONSE); -} - - -int message_serialize_error_response(msgpack_packer *pk, - struct api_error *api_error, uint32_t msgid) -{ - struct message_object *err_data; - array err_array; - - if (!pk || !api_error || !api_error->isset) - return (-1); - - msgpack_pack_array(pk, 4); - - pack_uint8(pk, MESSAGE_TYPE_RESPONSE); - pack_uint32(pk, msgid); - - err_array.size = 2; - err_array.obj = CALLOC(2, struct message_object); - - if (!err_array.obj) { - LOG_WARNING("Couldn't allocate memory for err_array object"); - return (-1); - } - - err_data = &err_array.obj[0]; - err_data->type = OBJECT_TYPE_INT; - err_data->data.integer = api_error->type; - - err_data = &err_array.obj[1]; - err_data->type = OBJECT_TYPE_STR; - err_data->data.string = cstring_to_string(api_error->msg); - - if (!err_data->data.string.str) { - LOG_WARNING("Couldn't allocate memory for string in err_array object"); - return (-1); - } - - if (pack_params(pk, err_array) == -1) - return (-1); - - pack_nil(pk); - - FREE(err_array.obj); - - return (0); -} - - -int message_serialize_response(struct message_response *res, - msgpack_packer *pk) -{ - if (!pk || !res) - return (-1); - - msgpack_pack_array(pk, 4); - pack_uint8(pk, MESSAGE_TYPE_RESPONSE); - pack_uint32(pk, res->msgid); - pack_nil(pk); - - if (pack_params(pk, res->params) == -1) - return (-1); - - return (0); -} - - -int message_serialize_request(struct message_request *req, - msgpack_packer *pk) -{ - if (!pk || !req) - return (-1); - - msgpack_pack_array(pk, 4); - pack_uint8(pk, MESSAGE_TYPE_REQUEST); - pack_uint32(pk, req->msgid); - - if (req->method.str == NULL || (pack_string(pk, req->method) == -1)) - return (-1); - - if (pack_params(pk, req->params) == -1) - return (-1); - - return (0); -} - - -int message_deserialize_request(struct message_request *req, - msgpack_object *obj, struct api_error *api_error) -{ - msgpack_object *type, *msgid, *method, *params; - uint64_t tmp_type; - uint64_t tmp_msgid; - - if (!api_error) - return (-1); - - if (!req || !obj) { - error_set(api_error, API_ERROR_TYPE_VALIDATION, "Error"); - return (-1); - } - - /* type */ - if (obj->via.array.ptr[0].type != MSGPACK_OBJECT_POSITIVE_INTEGER) { - error_set(api_error, API_ERROR_TYPE_VALIDATION, "type field has wrong type"); - return (-1); - } - - type = &obj->via.array.ptr[0]; - if (!type) { - error_set(api_error, API_ERROR_TYPE_VALIDATION, "unpack type failed"); - return (-1); - } - - tmp_type = unpack_uint(type); - - if (tmp_type != MESSAGE_TYPE_REQUEST) { - error_set(api_error, API_ERROR_TYPE_VALIDATION, "type must be 0 or 1"); - return (-1); - } - - /* message id */ - msgid = &obj->via.array.ptr[1]; - - if (!msgid || msgid->type != MSGPACK_OBJECT_POSITIVE_INTEGER) { - error_set(api_error, API_ERROR_TYPE_VALIDATION, "illegal msgid"); - return (-1); - } - - tmp_msgid = unpack_uint(msgid); - - if (tmp_msgid >= UINT32_MAX) { - error_set(api_error, API_ERROR_TYPE_VALIDATION, "invalid msgid"); - return (-1); - } - - req->msgid = (uint32_t)tmp_msgid; - - /* method */ - if (obj->via.array.ptr[2].type != MSGPACK_OBJECT_STR) { - error_set(api_error, API_ERROR_TYPE_VALIDATION, "method field has wrong type"); - return (-1); - } - - method = &obj->via.array.ptr[2]; - - if (!method) { - error_set(api_error, API_ERROR_TYPE_VALIDATION, "unpack method failed"); - return (-1); - } - - req->method = unpack_string(method); - - if (!req->method.str) { - error_set(api_error, API_ERROR_TYPE_VALIDATION, "Error unpacking method"); - return (-1); - } - - /* params */ - if (obj->via.array.ptr[3].type != MSGPACK_OBJECT_ARRAY) { - free_string(req->method); - error_set(api_error, API_ERROR_TYPE_VALIDATION, "params field has wrong type"); - return (-1); - } - - params = &obj->via.array.ptr[3]; - - if (!params) { - free_string(req->method); - error_set(api_error, API_ERROR_TYPE_VALIDATION, "unpack params failed"); - return (-1); - } - - if (unpack_params(params, &req->params) == -1) { - free_string(req->method); - error_set(api_error, API_ERROR_TYPE_VALIDATION, "Error unpacking params"); - return (-1); - } - - return (0); -} - -bool message_is_error_response(msgpack_object *obj) -{ - return (obj->via.array.ptr[2].type != MSGPACK_OBJECT_NIL); -} - -uint64_t message_get_id(msgpack_object *obj) -{ - return (obj->via.array.ptr[1].via.u64); -} - -int message_deserialize_response(struct message_response *res, - msgpack_object *obj, struct api_error *api_error) -{ - msgpack_object *type, *msgid, *params; - uint64_t tmp_msgid; - - if (!api_error) - return (-1); - - if (!res || !obj) { - error_set(api_error, API_ERROR_TYPE_VALIDATION, "Error"); - return (-1); - } - - /* type */ - if (obj->via.array.ptr[0].type != MSGPACK_OBJECT_POSITIVE_INTEGER) { - error_set(api_error, API_ERROR_TYPE_VALIDATION, "type field has wrong type"); - return (-1); - } - - type = &obj->via.array.ptr[0]; - - if (!type) { - error_set(api_error, API_ERROR_TYPE_VALIDATION, "unpack type failed"); - return (-1); - } - - if (unpack_uint(type) != MESSAGE_TYPE_RESPONSE) { - error_set(api_error, API_ERROR_TYPE_VALIDATION, "type must be 1"); - return (-1); - } - - /* message id */ - msgid = &obj->via.array.ptr[1]; - - if (!msgid || msgid->type != MSGPACK_OBJECT_POSITIVE_INTEGER) { - error_set(api_error, API_ERROR_TYPE_VALIDATION, "illegal msgid"); - return (-1); - } - - tmp_msgid = unpack_uint(msgid); - - if (tmp_msgid >= UINT32_MAX) { - error_set(api_error, API_ERROR_TYPE_VALIDATION, "invalid msgid"); - return (-1); - } - - res->msgid = (uint32_t)tmp_msgid; - - /* nil */ - if (obj->via.array.ptr[2].type != MSGPACK_OBJECT_NIL) { - error_set(api_error, API_ERROR_TYPE_VALIDATION, "nil field has wrong type"); - return (-1); - } - - /* params */ - if (obj->via.array.ptr[3].type != MSGPACK_OBJECT_ARRAY) { - error_set(api_error, API_ERROR_TYPE_VALIDATION, "params field has wrong type"); - return (-1); - } - - params = &obj->via.array.ptr[3]; - - if (!params) { - error_set(api_error, API_ERROR_TYPE_VALIDATION, "unpack params failed"); - return (-1); - } - - if (unpack_params(params, &res->params) == -1) { - error_set(api_error, API_ERROR_TYPE_VALIDATION, "Error unpacking params"); - return (-1); - } - - return (0); -} - -int message_deserialize_error_response(struct message_response *res, - msgpack_object *obj, struct api_error *api_error) -{ - msgpack_object *type, *msgid, *params; - uint64_t tmp_msgid; - - if (!api_error) - return (-1); - - if (!res || !obj) { - error_set(api_error, API_ERROR_TYPE_VALIDATION, "Error"); - return (-1); - } - - /* type */ - if (obj->via.array.ptr[0].type != MSGPACK_OBJECT_POSITIVE_INTEGER) { - error_set(api_error, API_ERROR_TYPE_VALIDATION, "type field has wrong type"); - return (-1); - } - - type = &obj->via.array.ptr[0]; - - if (!type) { - error_set(api_error, API_ERROR_TYPE_VALIDATION, "unpack type failed"); - return (-1); - } - - if (unpack_uint(type) != MESSAGE_TYPE_RESPONSE) { - error_set(api_error, API_ERROR_TYPE_VALIDATION, "type must be 1"); - return (-1); - } - - /* message id */ - msgid = &obj->via.array.ptr[1]; - - if (!msgid || msgid->type != MSGPACK_OBJECT_POSITIVE_INTEGER) { - error_set(api_error, API_ERROR_TYPE_VALIDATION, "illegal msgid"); - return (-1); - } - - tmp_msgid = unpack_uint(msgid); - - if (tmp_msgid >= UINT32_MAX) { - error_set(api_error, API_ERROR_TYPE_VALIDATION, "invalid msgid"); - return (-1); - } - - res->msgid = (uint32_t)tmp_msgid; - - /* params */ - if (obj->via.array.ptr[2].type != MSGPACK_OBJECT_ARRAY) { - error_set(api_error, API_ERROR_TYPE_VALIDATION, "params field has wrong type"); - return (-1); - } - - params = &obj->via.array.ptr[2]; - - if (!params) { - error_set(api_error, API_ERROR_TYPE_VALIDATION, "unpack params failed"); - return (-1); - } - - if (unpack_params(params, &res->params) == -1) { - error_set(api_error, API_ERROR_TYPE_VALIDATION, "Error unpacking params"); - return (-1); - } - - /* nil */ - if (obj->via.array.ptr[3].type != MSGPACK_OBJECT_NIL) { - free_params(res->params); - error_set(api_error, API_ERROR_TYPE_VALIDATION, "nil field has wrong type"); - return (-1); - } - - return (0); -} - - -static void free_message_object(message_object obj) -{ - switch (obj.type) { - case OBJECT_TYPE_NIL: - break; - case OBJECT_TYPE_INT: - break; - case OBJECT_TYPE_UINT: - break; - case OBJECT_TYPE_BIN: - /* FALLTHROUGH */ - case OBJECT_TYPE_STR: - free_string(obj.data.string); - break; - case OBJECT_TYPE_BOOL: - break; - case OBJECT_TYPE_FLOAT: - break; - case OBJECT_TYPE_ARRAY: - free_params(obj.data.params); - break; - default: - return; - } -} - -struct message_object message_object_copy(struct message_object obj) -{ - switch (obj.type) { - case OBJECT_TYPE_NIL: - /* FALLTHROUGH */ - case OBJECT_TYPE_BOOL: - /* FALLTHROUGH */ - case OBJECT_TYPE_INT: - /* FALLTHROUGH */ - case OBJECT_TYPE_UINT: - /* FALLTHROUGH */ - case OBJECT_TYPE_FLOAT: - return obj; - case OBJECT_TYPE_BIN: - /* FALLTHROUGH */ - case OBJECT_TYPE_STR: - return (struct message_object) {.type = OBJECT_TYPE_STR, .data.string = - cstring_copy_string(obj.data.string.str) }; - case OBJECT_TYPE_ARRAY: { - array array = ARRAY_INIT; - - for (size_t i = 0; i < obj.data.params.size; i++) { - kv_push(struct message_object, array, - message_object_copy(obj.data.params.obj[i])); - } - - return (struct message_object) {.type = OBJECT_TYPE_ARRAY, - .data.params = array}; - } - default: - abort(); - } -} - - -void free_params(array params) -{ - for (size_t i = 0; i < params.size; i++) - free_message_object(params.obj[i]); - - if (params.obj) - FREE(params.obj); -} diff --git a/src/rpc/msgpack/pack.c b/src/rpc/msgpack/pack.c deleted file mode 100644 index a967fe5..0000000 --- a/src/rpc/msgpack/pack.c +++ /dev/null @@ -1,208 +0,0 @@ -/** - * Copyright (C) 2015 splone UG - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ - -#include -#include -#include -#include -#include -#include -#include - -#include "rpc/msgpack/sb-msgpack-rpc.h" -#include "sb-common.h" - - -int pack_string(msgpack_packer *pk, string str) -{ - if (!pk) - return (-1); - - msgpack_pack_bin(pk, str.length); - msgpack_pack_bin_body(pk, str.str, str.length); - - return (0); -} - - -int pack_uint8(msgpack_packer *pk, uint8_t uinteger) -{ - if (!pk) - return (-1); - - msgpack_pack_uint8(pk, uinteger); - - return (0); -} - - -int pack_uint16(msgpack_packer *pk, uint16_t uinteger) -{ - if (!pk) - return (-1); - - msgpack_pack_uint16(pk, uinteger); - - return (0); -} - - -int pack_uint32(msgpack_packer *pk, uint32_t uinteger) -{ - if (!pk) - return (-1); - - msgpack_pack_uint32(pk, uinteger); - - return (0); -} - - -int pack_uint64(msgpack_packer *pk, uint64_t uinteger) -{ - if (!pk) - return (-1); - - msgpack_pack_uint64(pk, uinteger); - - return (0); -} - - -int pack_int8(msgpack_packer *pk, int8_t integer) -{ - if (!pk) - return (-1); - - msgpack_pack_int8(pk, integer); - - return (0); -} - - -int pack_int16(msgpack_packer *pk, int16_t integer) -{ - if (!pk) - return (-1); - - msgpack_pack_int16(pk, integer); - - return (0); -} - - -int pack_int32(msgpack_packer *pk, int32_t integer) -{ - if (!pk) - return (-1); - - msgpack_pack_int32(pk, integer); - - return (0); -} - - -int pack_int64(msgpack_packer *pk, int64_t integer) -{ - if (!pk) - return (-1); - - msgpack_pack_int64(pk, integer); - - return (0); -} - - -int pack_bool(msgpack_packer *pk, bool boolean) -{ - if (!pk) - return (-1); - - if (boolean) - msgpack_pack_true(pk); - else - msgpack_pack_false(pk); - - return (0); -} - - -int pack_float(msgpack_packer *pk, double floating) -{ - if (!pk) - return (-1); - - msgpack_pack_double(pk, floating); - - return (0); -} - - -int pack_nil(msgpack_packer *pk) -{ - if (!pk) - return (-1); - - msgpack_pack_nil(pk); - - return (0); -} - - -int pack_params(msgpack_packer *pk, array params) -{ - size_t i; - - if (!pk) - return (-1); - - msgpack_pack_array(pk, params.size); - - for (i = 0; i < params.size; i++) { - message_object *object = ¶ms.obj[i]; - message_object_type type = object->type; - - switch (type) { - case (OBJECT_TYPE_NIL): - pack_nil(pk); - continue; - case (OBJECT_TYPE_INT): - pack_int64(pk, object->data.integer); - continue; - case (OBJECT_TYPE_UINT): - pack_uint64(pk, object->data.uinteger); - continue; - case (OBJECT_TYPE_BOOL): - pack_bool(pk, object->data.boolean); - continue; - case (OBJECT_TYPE_FLOAT): - pack_float(pk, object->data.floating); - continue; - case (OBJECT_TYPE_ARRAY): - pack_params(pk, object->data.params); - continue; - case (OBJECT_TYPE_STR): - /* FALLTHROUGH */ - case (OBJECT_TYPE_BIN): - pack_string(pk, object->data.string); - continue; - default: - return (-1); - } - } - - return (0); -} diff --git a/src/rpc/msgpack/sb-msgpack-rpc.h b/src/rpc/msgpack/sb-msgpack-rpc.h deleted file mode 100644 index ea776b0..0000000 --- a/src/rpc/msgpack/sb-msgpack-rpc.h +++ /dev/null @@ -1,104 +0,0 @@ -/** - * Copyright (C) 2015 splone UG - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ - -#pragma once - -#include -#include -#include -#include -#include -#include - -#include "rpc/sb-rpc.h" -#include "sb-common.h" - - -/* - * Message Format: - * - * - Request - - * - * msgpack - Array - * ---------------------------------------------------- - * | 0 (type) | id (request_id) | method | arguments | - * ---------------------------------------------------- - * - * - Response - - * - * msgpack - Array - * -------------------------------------------------------------------- - * | 1 (type) | id (request_id) | Error Code or Null | result or Null | - * -------------------------------------------------------------------- - */ - -/* Functions */ - -int message_unpack_type(msgpack_object *obj, struct message_request *req, - struct api_error *api_error); -int message_unpack_validate_type(msgpack_object *ptr, - struct api_error *api_error); -int message_unpack_validate_msgid(msgpack_object *ptr, - struct api_error *api_error); -int message_unpack_validate_status(msgpack_object *ptr, - struct api_error *api_error); -int message_unpack_validate_result(msgpack_object *ptr, - struct api_error *api_error); -int message_unpack_msgid(msgpack_object *obj, struct message_request *req, - struct api_error *api_error); -int message_unpack_status(msgpack_object *obj, struct message_response *res, - struct api_error *api_error); -int message_unpack_result(msgpack_object *obj, struct message_request *req, - struct api_error *api_error); -int message_unpack_method(msgpack_object *obj, struct message_request *req, - struct api_error *api_error); -int message_unpack_validate_method(msgpack_object *ptr, - struct api_error *api_error); -int message_unpack_validate_args(msgpack_object *ptr, - struct api_error *api_error); -int message_unpack_args(msgpack_object *obj, struct message_request *req, - array *params, struct api_error *api_error); -int message_pack_type(msgpack_packer *pk, uint8_t type); -int message_pack_method(msgpack_packer *pk, char *method); -int message_pack_params(msgpack_packer *pk, - array *params); -int message_pack_msgid(msgpack_packer *pk, uint32_t msgid); - - - -string unpack_string(msgpack_object *obj); -char * unpack_bin(msgpack_object *obj); -int64_t unpack_int(msgpack_object *obj); -uint64_t unpack_uint(msgpack_object *obj); -bool unpack_boolean(msgpack_object *obj); -double unpack_float(msgpack_object *obj); -int unpack_params(msgpack_object *obj, array *params); - - - -int pack_string(msgpack_packer *pk, string str); -int pack_uint8(msgpack_packer *pk, uint8_t uinteger); -int pack_uint16(msgpack_packer *pk, uint16_t uinteger); -int pack_uint32(msgpack_packer *pk, uint32_t uinteger); -int pack_uint64(msgpack_packer *pk, uint64_t uinteger); -int pack_int8(msgpack_packer *pk, int8_t integer); -int pack_int16(msgpack_packer *pk, int16_t integer); -int pack_int32(msgpack_packer *pk, int32_t integer); -int pack_int64(msgpack_packer *pk, int64_t integer); -int pack_nil(msgpack_packer *pk); -int pack_bool(msgpack_packer *pk, bool boolean); -int pack_float(msgpack_packer *pk, double floating); -int pack_params(msgpack_packer *pk, array params); diff --git a/src/rpc/msgpack/unpack.c b/src/rpc/msgpack/unpack.c deleted file mode 100644 index 98e0082..0000000 --- a/src/rpc/msgpack/unpack.c +++ /dev/null @@ -1,140 +0,0 @@ -/** - * Copyright (C) 2015 splone UG - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ - -#include -#include -#include -#include -#include -#include - -#include "rpc/msgpack/sb-msgpack-rpc.h" -#include "sb-common.h" - -string unpack_string(msgpack_object *obj) -{ - string str; - char *ret = MALLOC_ARRAY(obj->via.bin.size + 1, char); - - if (!ret || !obj->via.bin.ptr) { - str = (string) { - .str = NULL, .length = 0 - }; - return (str); - } - - ret[obj->via.bin.size] = '\0'; - memcpy(ret, obj->via.bin.ptr, obj->via.bin.size); - - str = (string) { - .str = ret, .length = obj->via.bin.size - }; - - return (str); -} - - -int64_t unpack_int(msgpack_object *obj) -{ - return (obj->via.i64); -} - - -uint64_t unpack_uint(msgpack_object *obj) -{ - return (obj->via.u64); -} - - -bool unpack_boolean(msgpack_object *obj) -{ - return (obj->via.boolean); -} - - -double unpack_float(msgpack_object *obj) -{ - return (obj->via.f64); -} - - -int unpack_params(msgpack_object *obj, array *params) -{ - struct message_object *elem; - msgpack_object *tmp; - - if (!params) - return (-1); - - /* if array is empty return success */ - if (obj->via.array.size <= 0) { - params->obj = NULL; - params->size = 0; - return (0); - } - - params->obj = CALLOC(obj->via.array.size, struct message_object); - params->size = obj->via.array.size; - - if (!params->obj) - return (-1); - - for (size_t i = 0; i < params->size; i++) { - tmp = &obj->via.array.ptr[i]; - elem = ¶ms->obj[i]; - - switch (tmp->type) { - case MSGPACK_OBJECT_POSITIVE_INTEGER: - elem->type = OBJECT_TYPE_UINT; - elem->data.uinteger = unpack_uint(tmp); - continue; - case MSGPACK_OBJECT_NEGATIVE_INTEGER: - elem->type = OBJECT_TYPE_INT; - elem->data.integer = unpack_int(tmp); - continue; - case MSGPACK_OBJECT_STR: - /* FALLTHROUGH */ - case MSGPACK_OBJECT_BIN: - elem->type = OBJECT_TYPE_STR; - elem->data.string = unpack_string(tmp); - continue; - case MSGPACK_OBJECT_BOOLEAN: - elem->type = OBJECT_TYPE_BOOL; - elem->data.boolean = unpack_boolean(tmp); - continue; - case MSGPACK_OBJECT_NIL: - elem->type = OBJECT_TYPE_NIL; - continue; - case MSGPACK_OBJECT_FLOAT: - elem->type = OBJECT_TYPE_FLOAT; - elem->data.floating = unpack_float(tmp); - continue; - case MSGPACK_OBJECT_ARRAY: - elem->type = OBJECT_TYPE_ARRAY; - if (unpack_params(tmp, &elem->data.params) == -1) - return (-1); - continue; - case MSGPACK_OBJECT_MAP: - /* FALLTHROUGH */ - case MSGPACK_OBJECT_EXT: - return (-1); - default: - return (-1); - } - } - - return (0); -} diff --git a/src/util.c b/src/util.c index f8a383f..bfd5993 100644 --- a/src/util.c +++ b/src/util.c @@ -250,6 +250,33 @@ char * box_strndup(const char *s, size_t n) return (dup); } +/** Allocate a chunk of len bytes, with the same contents as the + * len bytes starting at mem. */ +void * sb_memdup(const void *mem, size_t len) +{ + char *duplicate; + sbassert(mem); + + duplicate = MALLOC_ARRAY(len, char); + memcpy(duplicate, mem, len); + + return duplicate; +} + +/** As sb_memdup(), but add an extra 0 byte at the end of the resulting + * memory. */ +void * sb_memdup_nulterm(const void *mem, size_t len) +{ + char *duplicate; + + sbassert(mem); + duplicate = MALLOC_ARRAY((len + 1), char); + memcpy(duplicate, mem, len); + duplicate[len] = '\0'; + + return duplicate; +} + /** Minimal sscanf replacement: parse buf according to pattern * and store the results in the corresponding argument fields. Differs from * sscanf in that: diff --git a/test/unit/message-deserialize-error-response.c b/test/unit/message-deserialize-error-response.c deleted file mode 100644 index c86929e..0000000 --- a/test/unit/message-deserialize-error-response.c +++ /dev/null @@ -1,156 +0,0 @@ -/** - * Copyright (C) 2016 splone UG - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ - -#include - -#include "sb-common.h" -#include "rpc/msgpack/sb-msgpack-rpc.h" -#include "helper-unix.h" - - -void unit_message_deserialize_error_response(UNUSED(void **state)) -{ - struct api_error error = ERROR_INIT; - msgpack_sbuffer sbuf; - msgpack_packer pk; - msgpack_zone mempool; - msgpack_object deserialized; - struct message_response response; - - msgpack_sbuffer_init(&sbuf); - msgpack_zone_init(&mempool, 2048); - - /* positiv test */ - msgpack_packer_init(&pk, &sbuf, msgpack_sbuffer_write); - msgpack_pack_array(&pk, 4); - msgpack_pack_uint8(&pk, 1); - msgpack_pack_uint32(&pk, 1234); - msgpack_pack_array(&pk, 1); - msgpack_pack_uint8(&pk, 0); - msgpack_pack_nil(&pk); - msgpack_unpack(sbuf.data, sbuf.size, NULL, &mempool, &deserialized); - - assert_int_equal(0, message_deserialize_error_response(&response, - &deserialized, &error)); - - assert_true(message_is_error_response(&deserialized)); - - msgpack_sbuffer_clear(&sbuf); - - free_params(response.params); - - /* wrong type type */ - msgpack_packer_init(&pk, &sbuf, msgpack_sbuffer_write); - msgpack_pack_array(&pk, 4); - msgpack_pack_nil(&pk); - msgpack_pack_uint32(&pk, 1234); - msgpack_pack_array(&pk, 1); - msgpack_pack_uint8(&pk, 0); - msgpack_pack_nil(&pk); - msgpack_unpack(sbuf.data, sbuf.size, NULL, &mempool, &deserialized); - - assert_int_not_equal(0, message_deserialize_error_response(&response, - &deserialized, &error)); - - msgpack_sbuffer_clear(&sbuf); - - /* wrong type */ - msgpack_packer_init(&pk, &sbuf, msgpack_sbuffer_write); - msgpack_pack_array(&pk, 4); - msgpack_pack_uint8(&pk, 0); - msgpack_pack_uint32(&pk, 1234); - msgpack_pack_array(&pk, 1); - msgpack_pack_uint8(&pk, 0); - msgpack_pack_nil(&pk); - msgpack_unpack(sbuf.data, sbuf.size, NULL, &mempool, &deserialized); - - assert_int_not_equal(0, message_deserialize_error_response(&response, - &deserialized, &error)); - - msgpack_sbuffer_clear(&sbuf); - - /* wrong msgid */ - msgpack_packer_init(&pk, &sbuf, msgpack_sbuffer_write); - msgpack_pack_array(&pk, 4); - msgpack_pack_uint8(&pk, 1); - msgpack_pack_int(&pk, -1234); - msgpack_pack_array(&pk, 1); - msgpack_pack_uint8(&pk, 0); - msgpack_pack_nil(&pk); - msgpack_unpack(sbuf.data, sbuf.size, NULL, &mempool, &deserialized); - - assert_int_not_equal(0, message_deserialize_error_response(&response, - &deserialized, &error)); - - msgpack_sbuffer_clear(&sbuf); - - /* wrong msgid value*/ - msgpack_packer_init(&pk, &sbuf, msgpack_sbuffer_write); - msgpack_pack_array(&pk, 4); - msgpack_pack_uint8(&pk, 1); - msgpack_pack_uint32(&pk, UINT32_MAX); - msgpack_pack_array(&pk, 1); - msgpack_pack_uint8(&pk, 0); - msgpack_pack_nil(&pk); - msgpack_unpack(sbuf.data, sbuf.size, NULL, &mempool, &deserialized); - - assert_int_not_equal(0, message_deserialize_error_response(&response, - &deserialized, &error)); - - msgpack_sbuffer_clear(&sbuf); - - /* wrong params */ - msgpack_packer_init(&pk, &sbuf, msgpack_sbuffer_write); - msgpack_pack_array(&pk, 4); - msgpack_pack_uint8(&pk, 1); - msgpack_pack_uint32(&pk, 1234); - msgpack_pack_nil(&pk); - msgpack_pack_nil(&pk); - msgpack_unpack(sbuf.data, sbuf.size, NULL, &mempool, &deserialized); - - assert_int_not_equal(0, message_deserialize_error_response(&response, - &deserialized, &error)); - - msgpack_sbuffer_clear(&sbuf); - - /* wrong params */ - msgpack_packer_init(&pk, &sbuf, msgpack_sbuffer_write); - msgpack_pack_array(&pk, 4); - msgpack_pack_uint8(&pk, 1); - msgpack_pack_uint32(&pk, 1234); - msgpack_pack_array(&pk, 1); - msgpack_pack_uint8(&pk, 0); - msgpack_pack_array(&pk, 1); - msgpack_pack_uint8(&pk, 0); - msgpack_unpack(sbuf.data, sbuf.size, NULL, &mempool, &deserialized); - - assert_int_not_equal(0, message_deserialize_error_response(&response, - &deserialized, &error)); - - msgpack_sbuffer_clear(&sbuf); - - /* null input params */ - /* null input params */ - assert_int_not_equal(0, message_deserialize_error_response(&response, - &deserialized, NULL)); - assert_int_not_equal(0, message_deserialize_error_response(&response, NULL, - &error)); - assert_int_not_equal(0, message_deserialize_error_response(NULL, - &deserialized, &error)); - - msgpack_zone_destroy(&mempool); - msgpack_sbuffer_destroy(&sbuf); -} diff --git a/test/unit/message-deserialize-request.c b/test/unit/message-deserialize-request.c deleted file mode 100644 index abe134c..0000000 --- a/test/unit/message-deserialize-request.c +++ /dev/null @@ -1,157 +0,0 @@ -/** - * Copyright (C) 2016 splone UG - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ - -#include - -#include "sb-common.h" -#include "rpc/msgpack/sb-msgpack-rpc.h" -#include "helper-unix.h" - - -void unit_message_deserialize_request(UNUSED(void **state)) -{ - struct api_error error = ERROR_INIT; - msgpack_sbuffer sbuf; - msgpack_packer pk; - msgpack_zone mempool; - msgpack_object deserialized; - struct message_request request; - - msgpack_sbuffer_init(&sbuf); - msgpack_zone_init(&mempool, 2048); - - /* positiv test */ - msgpack_packer_init(&pk, &sbuf, msgpack_sbuffer_write); - msgpack_pack_array(&pk, 4); - msgpack_pack_uint8(&pk, 0); - msgpack_pack_uint32(&pk, 1234); - msgpack_pack_str(&pk, 4); - msgpack_pack_str_body(&pk, "test", 4); - msgpack_pack_array(&pk, 1); - msgpack_pack_uint8(&pk, 0); - msgpack_unpack(sbuf.data, sbuf.size, NULL, &mempool, &deserialized); - - assert_int_equal(0, message_deserialize_request(&request, &deserialized, - &error)); - - msgpack_sbuffer_clear(&sbuf); - - free_string(request.method); - free_params(request.params); - - /* wrong type type*/ - msgpack_packer_init(&pk, &sbuf, msgpack_sbuffer_write); - msgpack_pack_array(&pk, 4); - msgpack_pack_nil(&pk); - msgpack_pack_uint32(&pk, 1234); - msgpack_pack_str(&pk, 4); - msgpack_pack_str_body(&pk, "test", 4); - msgpack_pack_array(&pk, 1); - msgpack_pack_uint8(&pk, 0); - msgpack_unpack(sbuf.data, sbuf.size, NULL, &mempool, &deserialized); - - assert_int_not_equal(0, message_deserialize_request(&request, &deserialized, - &error)); - - /* wrong type */ - msgpack_packer_init(&pk, &sbuf, msgpack_sbuffer_write); - msgpack_pack_array(&pk, 4); - msgpack_pack_uint8(&pk, 1); - msgpack_pack_uint32(&pk, 1234); - msgpack_pack_str(&pk, 4); - msgpack_pack_str_body(&pk, "test", 4); - msgpack_pack_array(&pk, 1); - msgpack_pack_uint8(&pk, 0); - msgpack_unpack(sbuf.data, sbuf.size, NULL, &mempool, &deserialized); - - assert_int_not_equal(0, message_deserialize_request(&request, &deserialized, - &error)); - - msgpack_sbuffer_clear(&sbuf); - - /* wrong msgid */ - msgpack_packer_init(&pk, &sbuf, msgpack_sbuffer_write); - msgpack_pack_array(&pk, 4); - msgpack_pack_uint8(&pk, 0); - msgpack_pack_int(&pk, -1234); - msgpack_pack_str(&pk, 4); - msgpack_pack_str_body(&pk, "test", 4); - msgpack_pack_array(&pk, 1); - msgpack_pack_uint8(&pk, 0); - msgpack_unpack(sbuf.data, sbuf.size, NULL, &mempool, &deserialized); - - assert_int_not_equal(0, message_deserialize_request(&request, &deserialized, - &error)); - - msgpack_sbuffer_clear(&sbuf); - - /* wrong msgid value*/ - msgpack_packer_init(&pk, &sbuf, msgpack_sbuffer_write); - msgpack_pack_array(&pk, 4); - msgpack_pack_uint8(&pk, 0); - msgpack_pack_uint32(&pk, UINT32_MAX); - msgpack_pack_str(&pk, 4); - msgpack_pack_str_body(&pk, "test", 4); - msgpack_pack_array(&pk, 1); - msgpack_pack_uint8(&pk, 0); - msgpack_unpack(sbuf.data, sbuf.size, NULL, &mempool, &deserialized); - - assert_int_not_equal(0, message_deserialize_request(&request, &deserialized, - &error)); - - msgpack_sbuffer_clear(&sbuf); - - /* wrong method */ - msgpack_packer_init(&pk, &sbuf, msgpack_sbuffer_write); - msgpack_pack_array(&pk, 4); - msgpack_pack_uint8(&pk, 0); - msgpack_pack_int(&pk, 1234); - msgpack_pack_nil(&pk); - msgpack_pack_array(&pk, 1); - msgpack_pack_uint8(&pk, 0); - msgpack_unpack(sbuf.data, sbuf.size, NULL, &mempool, &deserialized); - - assert_int_not_equal(0, message_deserialize_request(&request, &deserialized, - &error)); - - msgpack_sbuffer_clear(&sbuf); - - /* wrong params */ - msgpack_packer_init(&pk, &sbuf, msgpack_sbuffer_write); - msgpack_pack_array(&pk, 4); - msgpack_pack_uint8(&pk, 0); - msgpack_pack_int(&pk, 1234); - msgpack_pack_str(&pk, 4); - msgpack_pack_str_body(&pk, "test", 4); - msgpack_pack_nil(&pk); - msgpack_unpack(sbuf.data, sbuf.size, NULL, &mempool, &deserialized); - - assert_int_not_equal(0, message_deserialize_request(&request, &deserialized, - &error)); - - msgpack_sbuffer_clear(&sbuf); - - /* null input params */ - assert_int_not_equal(0, message_deserialize_request(&request, &deserialized, - NULL)); - assert_int_not_equal(0, message_deserialize_request(&request, NULL, - &error)); - assert_int_not_equal(0, message_deserialize_request(NULL, &deserialized, - &error)); - - msgpack_zone_destroy(&mempool); - msgpack_sbuffer_destroy(&sbuf); -} diff --git a/test/unit/message-deserialize-response.c b/test/unit/message-deserialize-response.c deleted file mode 100644 index 6dde481..0000000 --- a/test/unit/message-deserialize-response.c +++ /dev/null @@ -1,152 +0,0 @@ -/** - * Copyright (C) 2016 splone UG - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ - -#include - -#include "sb-common.h" -#include "rpc/msgpack/sb-msgpack-rpc.h" -#include "helper-unix.h" - - -void unit_message_deserialize_response(UNUSED(void **state)) -{ - struct api_error error = ERROR_INIT; - msgpack_sbuffer sbuf; - msgpack_packer pk; - msgpack_zone mempool; - msgpack_object deserialized; - struct message_response response; - - msgpack_sbuffer_init(&sbuf); - msgpack_zone_init(&mempool, 2048); - - /* positiv test */ - msgpack_packer_init(&pk, &sbuf, msgpack_sbuffer_write); - msgpack_pack_array(&pk, 4); - msgpack_pack_uint8(&pk, 1); - msgpack_pack_uint32(&pk, 1234); - msgpack_pack_nil(&pk); - msgpack_pack_array(&pk, 1); - msgpack_pack_uint8(&pk, 0); - msgpack_unpack(sbuf.data, sbuf.size, NULL, &mempool, &deserialized); - - assert_int_equal(0, message_deserialize_response(&response, &deserialized, - &error)); - - msgpack_sbuffer_clear(&sbuf); - - free_params(response.params); - - /* wrong type type */ - msgpack_packer_init(&pk, &sbuf, msgpack_sbuffer_write); - msgpack_pack_array(&pk, 4); - msgpack_pack_nil(&pk); - msgpack_pack_uint32(&pk, 1234); - msgpack_pack_nil(&pk); - msgpack_pack_array(&pk, 1); - msgpack_pack_uint8(&pk, 0); - msgpack_unpack(sbuf.data, sbuf.size, NULL, &mempool, &deserialized); - - assert_int_not_equal(0, message_deserialize_response(&response, &deserialized, - &error)); - - msgpack_sbuffer_clear(&sbuf); - - /* wrong type */ - msgpack_packer_init(&pk, &sbuf, msgpack_sbuffer_write); - msgpack_pack_array(&pk, 4); - msgpack_pack_uint8(&pk, 0); - msgpack_pack_uint32(&pk, 1234); - msgpack_pack_nil(&pk); - msgpack_pack_array(&pk, 1); - msgpack_pack_uint8(&pk, 0); - msgpack_unpack(sbuf.data, sbuf.size, NULL, &mempool, &deserialized); - - assert_int_not_equal(0, message_deserialize_response(&response, &deserialized, - &error)); - - msgpack_sbuffer_clear(&sbuf); - - /* wrong msgid */ - msgpack_packer_init(&pk, &sbuf, msgpack_sbuffer_write); - msgpack_pack_array(&pk, 4); - msgpack_pack_uint8(&pk, 1); - msgpack_pack_int(&pk, -1234); - msgpack_pack_nil(&pk); - msgpack_pack_array(&pk, 1); - msgpack_pack_uint8(&pk, 0); - msgpack_unpack(sbuf.data, sbuf.size, NULL, &mempool, &deserialized); - - assert_int_not_equal(0, message_deserialize_response(&response, &deserialized, - &error)); - - msgpack_sbuffer_clear(&sbuf); - - /* wrong msgid value*/ - msgpack_packer_init(&pk, &sbuf, msgpack_sbuffer_write); - msgpack_pack_array(&pk, 4); - msgpack_pack_uint8(&pk, 1); - msgpack_pack_uint32(&pk, UINT32_MAX); - msgpack_pack_nil(&pk); - msgpack_pack_array(&pk, 1); - msgpack_pack_uint8(&pk, 0); - msgpack_unpack(sbuf.data, sbuf.size, NULL, &mempool, &deserialized); - - assert_int_not_equal(0, message_deserialize_response(&response, &deserialized, - &error)); - - msgpack_sbuffer_clear(&sbuf); - - /* wrong nil */ - msgpack_packer_init(&pk, &sbuf, msgpack_sbuffer_write); - msgpack_pack_array(&pk, 4); - msgpack_pack_uint8(&pk, 1); - msgpack_pack_uint32(&pk, 1234); - msgpack_pack_uint8(&pk, 1); - msgpack_pack_array(&pk, 1); - msgpack_pack_uint8(&pk, 0); - msgpack_unpack(sbuf.data, sbuf.size, NULL, &mempool, &deserialized); - - assert_int_not_equal(0, message_deserialize_response(&response, &deserialized, - &error)); - - msgpack_sbuffer_clear(&sbuf); - - /* wrong params */ - msgpack_packer_init(&pk, &sbuf, msgpack_sbuffer_write); - msgpack_pack_array(&pk, 4); - msgpack_pack_uint8(&pk, 1); - msgpack_pack_uint32(&pk, 1234); - msgpack_pack_nil(&pk); - msgpack_pack_nil(&pk); - msgpack_unpack(sbuf.data, sbuf.size, NULL, &mempool, &deserialized); - - assert_int_not_equal(0, message_deserialize_response(&response, &deserialized, - &error)); - - msgpack_sbuffer_clear(&sbuf); - - /* null input params */ - assert_int_not_equal(0, message_deserialize_response(&response, &deserialized, - NULL)); - assert_int_not_equal(0, message_deserialize_response(&response, NULL, - &error)); - assert_int_not_equal(0, message_deserialize_response(NULL, &deserialized, - &error)); - - msgpack_zone_destroy(&mempool); - msgpack_sbuffer_destroy(&sbuf); -} diff --git a/test/unit/message-is-request.c b/test/unit/message-is-request.c deleted file mode 100644 index 8760e24..0000000 --- a/test/unit/message-is-request.c +++ /dev/null @@ -1,76 +0,0 @@ -/** - * Copyright (C) 2016 splone UG - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ - -#include - -#include "sb-common.h" -#include "rpc/msgpack/sb-msgpack-rpc.h" -#include "helper-unix.h" - - -void unit_message_is_request(UNUSED(void **state)) -{ - msgpack_sbuffer sbuf; - msgpack_packer pk; - msgpack_zone mempool; - msgpack_object deserialized; - - msgpack_sbuffer_init(&sbuf); - msgpack_zone_init(&mempool, 2048); - - /* positiv test */ - msgpack_packer_init(&pk, &sbuf, msgpack_sbuffer_write); - msgpack_pack_array(&pk, 4); - msgpack_pack_uint8(&pk, 0); - msgpack_pack_uint8(&pk, 0); - msgpack_pack_uint8(&pk, 0); - msgpack_pack_uint8(&pk, 0); - msgpack_unpack(sbuf.data, sbuf.size, NULL, &mempool, &deserialized); - - assert_true(message_is_request(&deserialized)); - - msgpack_sbuffer_clear(&sbuf); - - /* wrong type test */ - msgpack_packer_init(&pk, &sbuf, msgpack_sbuffer_write); - msgpack_pack_array(&pk, 4); - msgpack_pack_uint8(&pk, 1); - msgpack_pack_uint8(&pk, 1); - msgpack_pack_uint8(&pk, 1); - msgpack_pack_uint8(&pk, 1); - msgpack_unpack(sbuf.data, sbuf.size, NULL, &mempool, &deserialized); - - assert_false(message_is_request(&deserialized)); - - msgpack_sbuffer_clear(&sbuf); - - /* no array test */ - msgpack_packer_init(&pk, &sbuf, msgpack_sbuffer_write); - msgpack_pack_uint8(&pk, 1); - msgpack_unpack(sbuf.data, sbuf.size, NULL, &mempool, &deserialized); - - assert_false(message_is_request(&deserialized)); - - msgpack_sbuffer_clear(&sbuf); - - /* NULL test */ - assert_false(message_is_request(NULL)); - - msgpack_sbuffer_clear(&sbuf); - - msgpack_zone_destroy(&mempool); - msgpack_sbuffer_destroy(&sbuf); -} diff --git a/test/unit/message-is-response.c b/test/unit/message-is-response.c deleted file mode 100644 index 5ad9402..0000000 --- a/test/unit/message-is-response.c +++ /dev/null @@ -1,76 +0,0 @@ -/** - * Copyright (C) 2016 splone UG - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ - -#include - -#include "sb-common.h" -#include "rpc/msgpack/sb-msgpack-rpc.h" -#include "helper-unix.h" - - -void unit_message_is_response(UNUSED(void **state)) -{ - msgpack_sbuffer sbuf; - msgpack_packer pk; - msgpack_zone mempool; - msgpack_object deserialized; - - msgpack_sbuffer_init(&sbuf); - msgpack_zone_init(&mempool, 2048); - - /* positiv test */ - msgpack_packer_init(&pk, &sbuf, msgpack_sbuffer_write); - msgpack_pack_array(&pk, 4); - msgpack_pack_uint8(&pk, 1); - msgpack_pack_uint8(&pk, 0); - msgpack_pack_uint8(&pk, 0); - msgpack_pack_uint8(&pk, 0); - msgpack_unpack(sbuf.data, sbuf.size, NULL, &mempool, &deserialized); - - assert_true(message_is_response(&deserialized)); - - msgpack_sbuffer_clear(&sbuf); - - /* wrong type test */ - msgpack_packer_init(&pk, &sbuf, msgpack_sbuffer_write); - msgpack_pack_array(&pk, 4); - msgpack_pack_uint8(&pk, 0); - msgpack_pack_uint8(&pk, 1); - msgpack_pack_uint8(&pk, 1); - msgpack_pack_uint8(&pk, 1); - msgpack_unpack(sbuf.data, sbuf.size, NULL, &mempool, &deserialized); - - assert_false(message_is_response(&deserialized)); - - msgpack_sbuffer_clear(&sbuf); - - /* no array test */ - msgpack_packer_init(&pk, &sbuf, msgpack_sbuffer_write); - msgpack_pack_uint8(&pk, 1); - msgpack_unpack(sbuf.data, sbuf.size, NULL, &mempool, &deserialized); - - assert_false(message_is_response(&deserialized)); - - msgpack_sbuffer_clear(&sbuf); - - /* NULL test */ - assert_false(message_is_response(NULL)); - - msgpack_sbuffer_clear(&sbuf); - - msgpack_zone_destroy(&mempool); - msgpack_sbuffer_destroy(&sbuf); -} diff --git a/test/unit/message-serialize-error-response.c b/test/unit/message-serialize-error-response.c deleted file mode 100644 index 6dace64..0000000 --- a/test/unit/message-serialize-error-response.c +++ /dev/null @@ -1,43 +0,0 @@ -/** - * Copyright (C) 2016 splone UG - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ - -#include - -#include "sb-common.h" -#include "rpc/msgpack/sb-msgpack-rpc.h" -#include "helper-unix.h" - - -void unit_message_serialize_error_response(UNUSED(void **state)) -{ - msgpack_sbuffer sbuf; - struct api_error error = ERROR_INIT; - msgpack_packer pk; - - error_set(&error, API_ERROR_TYPE_VALIDATION, "test error"); - - msgpack_sbuffer_init(&sbuf); - - /* positiv test */ - msgpack_packer_init(&pk, &sbuf, msgpack_sbuffer_write); - assert_int_equal(0, message_serialize_error_response(&pk, &error, 1234)); - msgpack_sbuffer_clear(&sbuf); - - /* null check */ - assert_int_not_equal(0, message_serialize_error_response(NULL, NULL, 1234)); - - msgpack_sbuffer_destroy(&sbuf); -} diff --git a/test/unit/message-serialize-request.c b/test/unit/message-serialize-request.c deleted file mode 100644 index 371e32a..0000000 --- a/test/unit/message-serialize-request.c +++ /dev/null @@ -1,77 +0,0 @@ -/** - * Copyright (C) 2016 splone UG - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ - -#include - -#include "sb-common.h" -#include "rpc/msgpack/sb-msgpack-rpc.h" -#include "helper-unix.h" - - -void unit_message_serialize_request(UNUSED(void **state)) -{ - msgpack_sbuffer sbuf; - msgpack_packer pk; - struct message_request request; - array params; - - params.size = 1; - params.obj = CALLOC(1, struct message_object); - params.obj[0].type = OBJECT_TYPE_UINT; - params.obj[0].data.uinteger = 1234; - - msgpack_sbuffer_init(&sbuf); - - /* positiv test */ - msgpack_packer_init(&pk, &sbuf, msgpack_sbuffer_write); - request.msgid = 1234; - request.method = (string) {.str = "test method", - .length = sizeof("test method") - 1}; - request.params = params; - assert_int_equal(0, message_serialize_request(&request, &pk)); - msgpack_sbuffer_clear(&sbuf); - - /* no valid string */ - msgpack_packer_init(&pk, &sbuf, msgpack_sbuffer_write); - request.msgid = 1234; - request.method = (string) STRING_INIT; - request.params = params; - assert_int_not_equal(0, message_serialize_request(&request, &pk)); - msgpack_sbuffer_clear(&sbuf); - - free_params(request.params); - - params.size = 1; - params.obj = CALLOC(1, struct message_object); - params.obj[0].type = 1000; - params.obj[0].data.uinteger = 1234; - - /* no valid params */ - msgpack_packer_init(&pk, &sbuf, msgpack_sbuffer_write); - request.msgid = 1234; - request.method = (string) {.str = "test method", - .length = sizeof("test method") - 1}; - request.params = params; - assert_int_not_equal(0, message_serialize_request(&request, &pk)); - msgpack_sbuffer_clear(&sbuf); - - free_params(request.params); - - /* null check */ - assert_int_not_equal(0, message_serialize_request(NULL, NULL)); - - msgpack_sbuffer_destroy(&sbuf); -} diff --git a/test/unit/message-serialize-response.c b/test/unit/message-serialize-response.c deleted file mode 100644 index 8809e86..0000000 --- a/test/unit/message-serialize-response.c +++ /dev/null @@ -1,65 +0,0 @@ -/** - * Copyright (C) 2016 splone UG - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ - -#include - -#include "sb-common.h" -#include "rpc/msgpack/sb-msgpack-rpc.h" -#include "helper-unix.h" - - -void unit_message_serialize_response(UNUSED(void **state)) -{ - msgpack_sbuffer sbuf; - msgpack_packer pk; - struct message_response response; - array params; - - params.size = 1; - params.obj = CALLOC(1, struct message_object); - params.obj[0].type = OBJECT_TYPE_UINT; - params.obj[0].data.uinteger = 1234; - - msgpack_sbuffer_init(&sbuf); - - /* positiv test */ - msgpack_packer_init(&pk, &sbuf, msgpack_sbuffer_write); - response.msgid = 1234; - response.params = params; - assert_int_equal(0, message_serialize_response(&response, &pk)); - msgpack_sbuffer_clear(&sbuf); - - free_params(response.params); - - params.size = 1; - params.obj = CALLOC(1, struct message_object); - params.obj[0].type = 1000; - params.obj[0].data.uinteger = 1234; - - /* no valid params */ - msgpack_packer_init(&pk, &sbuf, msgpack_sbuffer_write); - response.msgid = 1234; - response.params = params; - assert_int_not_equal(0, message_serialize_response(&response, &pk)); - msgpack_sbuffer_clear(&sbuf); - - free_params(response.params); - - /* null check */ - assert_int_not_equal(0, message_serialize_response(NULL, NULL)); - - msgpack_sbuffer_destroy(&sbuf); -} diff --git a/test/unit/pack-array.c b/test/unit/pack-array.c deleted file mode 100644 index 2bf5767..0000000 --- a/test/unit/pack-array.c +++ /dev/null @@ -1,61 +0,0 @@ -/** - * Copyright (C) 2015 splone UG - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ - -#include - -#include "sb-common.h" -#include "rpc/msgpack/sb-msgpack-rpc.h" -#include "helper-unix.h" - - -void unit_pack_array(UNUSED(void **state)) -{ - array params = ARRAY_INIT; - msgpack_sbuffer sbuf; - msgpack_packer pk; - - params.size = 5; - params.obj = CALLOC(params.size, struct message_object); - - params.obj[0].type = OBJECT_TYPE_UINT; - params.obj[0].data.uinteger = 5; - - params.obj[1].type = OBJECT_TYPE_INT; - params.obj[1].data.uinteger = 5; - - params.obj[2].type = OBJECT_TYPE_ARRAY; - params.obj[2].data.params.size = 1; - params.obj[2].data.params.obj = CALLOC(params.obj[2].data.params.size, - struct message_object); - params.obj[2].data.params.obj[0].type = OBJECT_TYPE_INT; - params.obj[2].data.params.obj[0].data.uinteger = 6; - - params.obj[3].type = OBJECT_TYPE_BOOL; - params.obj[3].data.boolean = true; - - params.obj[4].type = OBJECT_TYPE_FLOAT; - params.obj[4].data.floating = 1.2345; - - msgpack_sbuffer_init(&sbuf); - msgpack_packer_init(&pk, &sbuf, msgpack_sbuffer_write); - - assert_int_equal(0, pack_params(&pk, params)); - assert_int_not_equal(0, pack_params(NULL, params)); - - msgpack_sbuffer_destroy(&sbuf); - - free_params(params); -} diff --git a/test/unit/pack-bool.c b/test/unit/pack-bool.c deleted file mode 100644 index 4b31bca..0000000 --- a/test/unit/pack-bool.c +++ /dev/null @@ -1,37 +0,0 @@ -/** - * Copyright (C) 2015 splone UG - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ - -#include - -#include "sb-common.h" -#include "rpc/msgpack/sb-msgpack-rpc.h" -#include "helper-unix.h" - - -void unit_pack_bool(UNUSED(void **state)) -{ - msgpack_sbuffer sbuf; - msgpack_packer pk; - - msgpack_sbuffer_init(&sbuf); - msgpack_packer_init(&pk, &sbuf, msgpack_sbuffer_write); - - assert_int_equal(0, pack_bool(&pk, true)); - assert_int_equal(0, pack_bool(&pk, false)); - assert_int_not_equal(0, pack_bool(NULL, true)); - - msgpack_sbuffer_destroy(&sbuf); -} diff --git a/test/unit/pack-float.c b/test/unit/pack-float.c deleted file mode 100644 index f590c6d..0000000 --- a/test/unit/pack-float.c +++ /dev/null @@ -1,36 +0,0 @@ -/** - * Copyright (C) 2015 splone UG - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ - -#include - -#include "sb-common.h" -#include "rpc/msgpack/sb-msgpack-rpc.h" -#include "helper-unix.h" - - -void unit_pack_float(UNUSED(void **state)) -{ - msgpack_sbuffer sbuf; - msgpack_packer pk; - - msgpack_sbuffer_init(&sbuf); - msgpack_packer_init(&pk, &sbuf, msgpack_sbuffer_write); - - assert_int_equal(0, pack_float(&pk, 1.234)); - assert_int_not_equal(0, pack_float(NULL, 1.234)); - - msgpack_sbuffer_destroy(&sbuf); -} diff --git a/test/unit/pack-int.c b/test/unit/pack-int.c deleted file mode 100644 index 86e98b2..0000000 --- a/test/unit/pack-int.c +++ /dev/null @@ -1,53 +0,0 @@ -/** - * Copyright (C) 2015 splone UG - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ - -#include - -#include "sb-common.h" -#include "rpc/msgpack/sb-msgpack-rpc.h" -#include "helper-unix.h" - - -void unit_pack_int(UNUSED(void **state)) -{ - msgpack_sbuffer sbuf; - msgpack_packer pk; - - msgpack_sbuffer_init(&sbuf); - msgpack_packer_init(&pk, &sbuf, msgpack_sbuffer_write); - - assert_int_equal(0, pack_int8(&pk, 0)); - assert_int_equal(0, pack_int8(&pk, 1)); - assert_int_equal(0, pack_int8(&pk, 11)); - assert_int_not_equal(0, pack_int8(NULL, 11)); - - assert_int_equal(0, pack_int16(&pk, 0)); - assert_int_equal(0, pack_int16(&pk, 1)); - assert_int_equal(0, pack_int16(&pk, 11)); - assert_int_not_equal(0, pack_int16(NULL, 11)); - - assert_int_equal(0, pack_int32(&pk, 0)); - assert_int_equal(0, pack_int32(&pk, 1)); - assert_int_equal(0, pack_int32(&pk, 11)); - assert_int_not_equal(0, pack_int32(NULL, 11)); - - assert_int_equal(0, pack_int64(&pk, 0)); - assert_int_equal(0, pack_int64(&pk, 1)); - assert_int_equal(0, pack_int64(&pk, 11)); - assert_int_not_equal(0, pack_int64(NULL, 11)); - - msgpack_sbuffer_destroy(&sbuf); -} diff --git a/test/unit/pack-nil.c b/test/unit/pack-nil.c deleted file mode 100644 index b027c88..0000000 --- a/test/unit/pack-nil.c +++ /dev/null @@ -1,36 +0,0 @@ -/** - * Copyright (C) 2015 splone UG - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ - -#include - -#include "sb-common.h" -#include "rpc/msgpack/sb-msgpack-rpc.h" -#include "helper-unix.h" - - -void unit_pack_nil(UNUSED(void **state)) -{ - msgpack_sbuffer sbuf; - msgpack_packer pk; - - msgpack_sbuffer_init(&sbuf); - msgpack_packer_init(&pk, &sbuf, msgpack_sbuffer_write); - - assert_int_equal(0, pack_nil(&pk)); - assert_int_not_equal(0, pack_nil(NULL)); - - msgpack_sbuffer_destroy(&sbuf); -} diff --git a/test/unit/pack-string.c b/test/unit/pack-string.c deleted file mode 100644 index 7079a6e..0000000 --- a/test/unit/pack-string.c +++ /dev/null @@ -1,38 +0,0 @@ -/** - * Copyright (C) 2015 splone UG - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ - -#include - -#include "sb-common.h" -#include "rpc/msgpack/sb-msgpack-rpc.h" -#include "helper-unix.h" - - -void unit_pack_string(UNUSED(void **state)) -{ - string key = cstring_copy_string("TeiwieDoowuiMeix6SooxieFievee2io3ohhu5uo5ughu8cieja4iu6chuirija"); - msgpack_sbuffer sbuf; - msgpack_packer pk; - - msgpack_sbuffer_init(&sbuf); - msgpack_packer_init(&pk, &sbuf, msgpack_sbuffer_write); - - assert_int_equal(0, pack_string(&pk, key)); - assert_int_not_equal(0, pack_string(NULL, key)); - - msgpack_sbuffer_destroy(&sbuf); - free_string(key); -} diff --git a/test/unit/pack-uint.c b/test/unit/pack-uint.c deleted file mode 100644 index 2253f87..0000000 --- a/test/unit/pack-uint.c +++ /dev/null @@ -1,53 +0,0 @@ -/** - * Copyright (C) 2015 splone UG - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ - -#include - -#include "sb-common.h" -#include "rpc/msgpack/sb-msgpack-rpc.h" -#include "helper-unix.h" - - -void unit_pack_uint(UNUSED(void **state)) -{ - msgpack_sbuffer sbuf; - msgpack_packer pk; - - msgpack_sbuffer_init(&sbuf); - msgpack_packer_init(&pk, &sbuf, msgpack_sbuffer_write); - - assert_int_equal(0, pack_uint8(&pk, 0)); - assert_int_equal(0, pack_uint8(&pk, 1)); - assert_int_equal(0, pack_uint8(&pk, 11)); - assert_int_not_equal(0, pack_uint8(NULL, 11)); - - assert_int_equal(0, pack_uint16(&pk, 0)); - assert_int_equal(0, pack_uint16(&pk, 1)); - assert_int_equal(0, pack_uint16(&pk, 11)); - assert_int_not_equal(0, pack_uint16(NULL, 11)); - - assert_int_equal(0, pack_uint32(&pk, 0)); - assert_int_equal(0, pack_uint32(&pk, 1)); - assert_int_equal(0, pack_uint32(&pk, 11)); - assert_int_not_equal(0, pack_uint32(NULL, 11)); - - assert_int_equal(0, pack_uint64(&pk, 0)); - assert_int_equal(0, pack_uint64(&pk, 1)); - assert_int_equal(0, pack_uint64(&pk, 11)); - assert_int_not_equal(0, pack_uint64(NULL, 11)); - - msgpack_sbuffer_destroy(&sbuf); -} diff --git a/test/unit/regression-issue-60.c b/test/unit/regression-issue-60.c deleted file mode 100644 index a3ec4cd..0000000 --- a/test/unit/regression-issue-60.c +++ /dev/null @@ -1,47 +0,0 @@ -/** - * Copyright (C) 2015 splone UG - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ - -#include - -#include "sb-common.h" -#include "rpc/msgpack/sb-msgpack-rpc.h" -#include "helper-unix.h" - -void unit_regression_issue_60(UNUSED(void **state)) -{ - array params; - struct msgpack_object deserialized; - msgpack_unpacked result; - msgpack_sbuffer sbuf; - msgpack_packer pk; - - size_t off = 0; - - msgpack_sbuffer_init(&sbuf); - msgpack_packer_init(&pk, &sbuf, msgpack_sbuffer_write); - - msgpack_pack_array(&pk, 0); - - msgpack_unpacked_init(&result); - msgpack_unpack_next(&result, sbuf.data, sbuf.size, &off); - msgpack_sbuffer_destroy(&sbuf); - - deserialized = result.data; - - assert_int_equal(0, unpack_params(&deserialized, ¶ms)); - free_params(params); - msgpack_unpacked_destroy(&result); -} diff --git a/test/unit/unpack-array.c b/test/unit/unpack-array.c deleted file mode 100644 index da2e2da..0000000 --- a/test/unit/unpack-array.c +++ /dev/null @@ -1,78 +0,0 @@ -/** - * Copyright (C) 2015 splone UG - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ - -#include - -#include "sb-common.h" -#include "rpc/msgpack/sb-msgpack-rpc.h" -#include "helper-unix.h" - - -static msgpack_object deserialized; - -void init_unpack_array(msgpack_object_type type) -{ - size_t off = 0; - - msgpack_sbuffer sbuf; - msgpack_sbuffer_init(&sbuf); - msgpack_packer pk; - msgpack_packer_init(&pk, &sbuf, msgpack_sbuffer_write); - - msgpack_pack_array(&pk, 3); - if (type == MSGPACK_OBJECT_NIL) { - msgpack_pack_nil(&pk); - } else if (type == MSGPACK_OBJECT_POSITIVE_INTEGER) { - msgpack_pack_int(&pk, 1); - } else if (type == MSGPACK_OBJECT_BOOLEAN) { - msgpack_pack_true(&pk); - } else if (type == MSGPACK_OBJECT_MAP) { - msgpack_pack_map(&pk, 1); - } else if (type == MSGPACK_OBJECT_ARRAY) { - msgpack_pack_array(&pk, 3); - msgpack_pack_int(&pk, 1); - msgpack_pack_int(&pk, 1); - msgpack_pack_int(&pk, 1); - } else if (type == MSGPACK_OBJECT_FLOAT) { - msgpack_pack_double(&pk, 1.2); - } - msgpack_pack_true(&pk); - msgpack_pack_str(&pk, 7); - msgpack_pack_str_body(&pk, "example", 7); - - msgpack_unpacked result; - - msgpack_unpacked_init(&result); - msgpack_unpack_next(&result, sbuf.data, sbuf.size, &off); - msgpack_sbuffer_destroy(&sbuf); - deserialized = result.data; -} - -void unit_unpack_array(UNUSED(void **state)) -{ - array params; - - init_unpack_array(MSGPACK_OBJECT_NIL); - assert_int_equal(0, unpack_params(&deserialized, ¶ms)); - init_unpack_array(MSGPACK_OBJECT_ARRAY); - assert_int_equal(0, unpack_params(&deserialized, ¶ms)); - init_unpack_array(MSGPACK_OBJECT_FLOAT); - assert_int_equal(0, unpack_params(&deserialized, ¶ms)); - init_unpack_array(MSGPACK_OBJECT_MAP); - assert_int_equal(0, unpack_params(&deserialized, ¶ms)); - init_unpack_array(MSGPACK_OBJECT_POSITIVE_INTEGER); - assert_int_equal(0, unpack_params(&deserialized, ¶ms)); -} diff --git a/test/unit/unpack-string.c b/test/unit/unpack-string.c deleted file mode 100644 index ffe2c34..0000000 --- a/test/unit/unpack-string.c +++ /dev/null @@ -1,42 +0,0 @@ -/** - * Copyright (C) 2015 splone UG - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ - -#include - -#include "sb-common.h" -#include "rpc/msgpack/sb-msgpack-rpc.h" -#include "helper-unix.h" - - -void unit_unpack_string(UNUSED(void **state)) -{ - msgpack_sbuffer sbuf; - msgpack_sbuffer_init(&sbuf); - msgpack_packer pk; - msgpack_packer_init(&pk, &sbuf, msgpack_sbuffer_write); - - msgpack_pack_str(&pk, 64); - msgpack_pack_str_body( - &pk, - "TeiwieDoowuiMeix6SooxieFievee2io3ohhu5uo5ughu8cieja4iu6chuirijae", - 64); - - msgpack_object deserialized; - msgpack_unpack(sbuf.data, sbuf.size, NULL, NULL, &deserialized); - msgpack_sbuffer_destroy(&sbuf); - - assert_non_null(unpack_string(&deserialized).str); -} diff --git a/test/unit/unpack-uint.c b/test/unit/unpack-uint.c deleted file mode 100644 index f9463b2..0000000 --- a/test/unit/unpack-uint.c +++ /dev/null @@ -1,45 +0,0 @@ -/** - * Copyright (C) 2015 splone UG - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ - -#include - -#include "sb-common.h" -#include "rpc/msgpack/sb-msgpack-rpc.h" -#include "helper-unix.h" - - -static msgpack_object deserialized; - -void init_unpack_uint(uint64_t type) -{ - msgpack_sbuffer sbuf; - msgpack_sbuffer_init(&sbuf); - msgpack_packer pk; - msgpack_packer_init(&pk, &sbuf, msgpack_sbuffer_write); - - msgpack_pack_uint64(&pk, type); - - msgpack_unpack(sbuf.data, sbuf.size, NULL, NULL, &deserialized); - msgpack_sbuffer_destroy(&sbuf); -} - -void unit_unpack_uint(UNUSED(void **state)) -{ - init_unpack_uint(0); - assert_int_equal(0, unpack_uint(&deserialized)); - init_unpack_uint(1); - assert_int_equal(1, unpack_uint(&deserialized)); -} From e9077a38c628bdd6af8c86c829f562ee28712aed Mon Sep 17 00:00:00 2001 From: Stephan Zeisberg Date: Fri, 21 Oct 2016 22:23:25 +0200 Subject: [PATCH 03/41] Replace message serialize/deserialize and pack/unpack The msgpack helper functions implemented in msgpack/helper.c do the serializing and deserializing of msgpack-rcp messages from or to the object structure. This adds also the support for msgpack dictionary type. The api helper functions implemented in api/helpers.c help when constructing/freeing a object-message structure. --- src/api/helpers.c | 128 ++++++++++ src/api/helpers.h | 45 ++++ src/rpc/msgpack/helpers.c | 496 ++++++++++++++++++++++++++++++++++++++ src/rpc/msgpack/helpers.h | 45 ++++ 4 files changed, 714 insertions(+) create mode 100644 src/api/helpers.c create mode 100644 src/api/helpers.h create mode 100644 src/rpc/msgpack/helpers.c create mode 100644 src/rpc/msgpack/helpers.h diff --git a/src/api/helpers.c b/src/api/helpers.c new file mode 100644 index 0000000..d0f1b25 --- /dev/null +++ b/src/api/helpers.c @@ -0,0 +1,128 @@ +/** + * Copyright (C) 2015 splone UG + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + * This file incorporates code covered by the following terms: + * + * Copyright Neovim contributors. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + #include + #include + + #include "api/sb-api.h" + #include "api/helpers.h" + #include "sb-common.h" + +void api_free_string(string value) +{ + if (!value.str) { + return; + } + + FREE(value.str); +} + +void api_free_object(object value) +{ + switch (value.type) { + case OBJECT_TYPE_NIL: + case OBJECT_TYPE_BOOL: + case OBJECT_TYPE_INT: + case OBJECT_TYPE_UINT: + case OBJECT_TYPE_FLOAT: + break; + + case OBJECT_TYPE_STR: + api_free_string(value.data.string); + break; + + case OBJECT_TYPE_ARRAY: + api_free_array(value.data.array); + break; + + case OBJECT_TYPE_DICTIONARY: + api_free_dictionary(value.data.dictionary); + break; + + default: + abort(); + } +} + +void api_free_array(array value) +{ + for (size_t i = 0; i < value.size; i++) { + api_free_object(value.items[i]); + } + + FREE(value.items); +} + +void api_free_dictionary(dictionary value) +{ + for (size_t i = 0; i < value.size; i++) { + api_free_string(value.items[i].key); + api_free_object(value.items[i].value); + } + + FREE(value.items); +} + +/// Creates a deep clone of an object +object copy_object(object obj) +{ + switch (obj.type) { + case OBJECT_TYPE_NIL: + case OBJECT_TYPE_BOOL: + case OBJECT_TYPE_INT: + case OBJECT_TYPE_UINT: + case OBJECT_TYPE_FLOAT: + return obj; + + case OBJECT_TYPE_STR: + return STRING_OBJ(cstring_copy_string(obj.data.string.str)); + + case OBJECT_TYPE_ARRAY: { + array rv = ARRAY_DICT_INIT; + for (size_t i = 0; i < obj.data.array.size; i++) { + ADD(rv, copy_object(obj.data.array.items[i])); + } + return ARRAY_OBJ(rv); + } + + case OBJECT_TYPE_DICTIONARY: { + dictionary rv = ARRAY_DICT_INIT; + for (size_t i = 0; i < obj.data.dictionary.size; i++) { + key_value_pair item = obj.data.dictionary.items[i]; + PUT(rv, item.key.str, copy_object(item.value)); + } + return DICTIONARY_OBJ(rv); + } + default: + abort(); + } +} diff --git a/src/api/helpers.h b/src/api/helpers.h new file mode 100644 index 0000000..f015fc4 --- /dev/null +++ b/src/api/helpers.h @@ -0,0 +1,45 @@ +#pragma once + +#include "sb-common.h" + +#define OBJECT_INIT { .type = OBJECT_TYPE_NIL } + +#define OBJECT_OBJ(o) o + +#define BOOLEAN_OBJ(b) ((object) { \ + .type = OBJECT_TYPE_BOOL, \ + .data.boolean = b }) + +#define INTEGER_OBJ(i) ((object) { \ + .type = OBJECT_TYPE_INT, \ + .data.integer = i }) + +#define UINTEGER_OBJ(i) ((object) { \ + .type = OBJECT_TYPE_UINT, \ + .data.uinteger = i }) + +#define FLOATING_OBJ(f) ((object) { \ + .type = OBJECT_TYPE_FLOAT, \ + .data.floating = f }) + +#define STRING_OBJ(s) ((object) { \ + .type = OBJECT_TYPE_STR, \ + .data.string = s }) + +#define ARRAY_OBJ(a) ((object) { \ + .type = OBJECT_TYPE_ARRAY, \ + .data.array = a }) + +#define DICTIONARY_OBJ(d) ((object) { \ + .type = OBJECT_TYPE_DICTIONARY, \ + .data.dictionary = d }) + +#define NIL ((object) {.type = OBJECT_TYPE_NIL}) + +#define PUT(dict, k, v) \ + kv_push(dict, ((key_value_pair) { .key = cstring_to_string(k), .value = v })) + +#define ADD(array, item) \ + kv_push(array, item) + +#define STATIC_CSTR_AS_STRING(s) ((string) {.str = s, .length = sizeof(s) - 1}) diff --git a/src/rpc/msgpack/helpers.c b/src/rpc/msgpack/helpers.c new file mode 100644 index 0000000..77ec406 --- /dev/null +++ b/src/rpc/msgpack/helpers.c @@ -0,0 +1,496 @@ +#include "rpc/sb-rpc.h" +#include "api/helpers.h" +#include "rpc/msgpack/helpers.h" +#include "sb-common.h" + +STATIC bool msgpack_rpc_to_string(const msgpack_object *const obj, + string *const arg); +STATIC bool msgpack_rpc_is_notification(msgpack_object *req); +STATIC msgpack_object *msgpack_rpc_msg_id(msgpack_object *req); + +typedef struct { + const msgpack_object *mobj; + object *aobj; + bool container; + size_t idx; +} msgpack_to_api_object_stack_item; + +bool msgpack_rpc_to_object(const msgpack_object *const obj, object *const arg) +{ + bool ret = true; + kvec_t(msgpack_to_api_object_stack_item) stack = KV_INITIAL_VALUE; + kv_push(stack, ((msgpack_to_api_object_stack_item) { obj, arg, false, 0 })); + + while (ret && kv_size(stack)) { + msgpack_to_api_object_stack_item cur = kv_last(stack); + + if (!cur.container) { + *cur.aobj = NIL; + } + + switch (cur.mobj->type) { + case MSGPACK_OBJECT_NIL: { + break; + } + case MSGPACK_OBJECT_BOOLEAN: { + *cur.aobj = BOOLEAN_OBJ(cur.mobj->via.boolean); + break; + } + case MSGPACK_OBJECT_NEGATIVE_INTEGER: { + sbassert(sizeof(int64_t) == sizeof(cur.mobj->via.i64)); + *cur.aobj = INTEGER_OBJ(cur.mobj->via.i64); + break; + } + case MSGPACK_OBJECT_POSITIVE_INTEGER: { + sbassert(sizeof(uint64_t) == sizeof(cur.mobj->via.u64)); + *cur.aobj = UINTEGER_OBJ(cur.mobj->via.u64); + break; + } + case MSGPACK_OBJECT_FLOAT: { + sbassert(sizeof(double) == sizeof(cur.mobj->via.f64)); + *cur.aobj = FLOATING_OBJ(cur.mobj->via.f64); + break; + } + case MSGPACK_OBJECT_STR: { + *cur.aobj = STRING_OBJ(((string) { + .length = cur.mobj->via.str.size, + .str = (cur.mobj->via.str.ptr == NULL || cur.mobj->via.str.size == 0 + ? NULL : box_strndup(cur.mobj->via.str.ptr, + cur.mobj->via.str.size)), + })); + break; + } + case MSGPACK_OBJECT_BIN: { + *cur.aobj = STRING_OBJ(((string) { + .length = cur.mobj->via.bin.size, + .str = (cur.mobj->via.bin.ptr == NULL || cur.mobj->via.bin.size == 0 + ? NULL : box_strndup(cur.mobj->via.bin.ptr, cur.mobj->via.bin.size)), + })); + break; + } + + case MSGPACK_OBJECT_ARRAY: { + const size_t size = cur.mobj->via.array.size; + + if (cur.container) { + if (cur.idx >= size) { + (void)kv_pop(stack); + } else { + const size_t idx = cur.idx; + cur.idx++; + kv_last(stack) = cur; + kv_push(stack, ((msgpack_to_api_object_stack_item) { + .mobj = &cur.mobj->via.array.ptr[idx], + .aobj = &cur.aobj->data.array.items[idx], + .container = false, + })); + } + } else { + *cur.aobj = ARRAY_OBJ(((array) { + .size = size, + .capacity = size, + .items = (size > 0 + ? calloc(size, sizeof(*cur.aobj->data.array.items)) : NULL), + })); + cur.container = true; + kv_last(stack) = cur; + } + break; + } + case MSGPACK_OBJECT_MAP: { + const size_t size = cur.mobj->via.map.size; + + if (cur.container) { + if (cur.idx >= size) { + (void)kv_pop(stack); + } else { + const size_t idx = cur.idx; + cur.idx++; + kv_last(stack) = cur; + const msgpack_object *const key = &cur.mobj->via.map.ptr[idx].key; + switch (key->type) { + case MSGPACK_OBJECT_STR: { + cur.aobj->data.dictionary.items[idx].key = ((string) { + .length = key->via.str.size, + .str = (key->via.str.ptr == NULL || key->via.str.size == 0 + ? NULL : box_strndup(key->via.str.ptr, key->via.str.size)), + }); + break; + } + case MSGPACK_OBJECT_BIN: { + cur.aobj->data.dictionary.items[idx].key = ((string) { + .length = key->via.bin.size, + .str = (key->via.bin.ptr == NULL || key->via.bin.size == 0 + ? NULL : box_strndup(key->via.bin.ptr, key->via.bin.size)), + }); + break; + } + case MSGPACK_OBJECT_NIL: + case MSGPACK_OBJECT_BOOLEAN: + case MSGPACK_OBJECT_POSITIVE_INTEGER: + case MSGPACK_OBJECT_NEGATIVE_INTEGER: + case MSGPACK_OBJECT_FLOAT: + case MSGPACK_OBJECT_EXT: + case MSGPACK_OBJECT_MAP: + case MSGPACK_OBJECT_ARRAY: { + ret = false; + break; + } + } + if (ret) { + kv_push(stack, ((msgpack_to_api_object_stack_item) { + .mobj = &cur.mobj->via.map.ptr[idx].val, + .aobj = &cur.aobj->data.dictionary.items[idx].value, + .container = false, + })); + } + } + } else { + *cur.aobj = DICTIONARY_OBJ(((dictionary) { + .size = size, + .capacity = size, + .items = (size > 0 + ? calloc(size, sizeof(*cur.aobj->data.dictionary.items)) + : NULL), + })); + cur.container = true; + kv_last(stack) = cur; + } + break; + } + case MSGPACK_OBJECT_EXT: { + break; + } + } + if (!cur.container) { + (void)kv_pop(stack); + } + } + + kv_destroy(stack); + + return ret; +} + +STATIC bool msgpack_rpc_to_string(const msgpack_object *const obj, + string *const arg) +{ + if (obj->type == MSGPACK_OBJECT_BIN || obj->type == MSGPACK_OBJECT_STR) { + arg->str = obj->via.bin.ptr != NULL + ? box_strndup(obj->via.bin.ptr, obj->via.bin.size) + : NULL; + arg->length = obj->via.bin.size; + return true; + } + return false; +} + +bool msgpack_rpc_to_array(const msgpack_object *const obj, array *const arg) +{ + if (obj->type != MSGPACK_OBJECT_ARRAY) { + return false; + } + + arg->size = obj->via.array.size; + arg->items = CALLOC(obj->via.array.size, object); + + for (uint32_t i = 0; i < obj->via.array.size; i++) { + if (!msgpack_rpc_to_object(obj->via.array.ptr + i, &arg->items[i])) { + return false; + } + } + + return true; +} + +bool msgpack_rpc_to_dictionary(const msgpack_object *const obj, + dictionary *const arg) +{ + if (obj->type != MSGPACK_OBJECT_MAP) { + return false; + } + + arg->size = obj->via.array.size; + arg->items = CALLOC(obj->via.map.size, key_value_pair); + + + for (uint32_t i = 0; i < obj->via.map.size; i++) { + if (!msgpack_rpc_to_string(&obj->via.map.ptr[i].key, + &arg->items[i].key)) { + return false; + } + + if (!msgpack_rpc_to_object(&obj->via.map.ptr[i].val, + &arg->items[i].value)) { + return false; + } + } + + return true; +} + +void msgpack_rpc_from_boolean(bool result, msgpack_packer *res) +{ + if (result) { + msgpack_pack_true(res); + } else { + msgpack_pack_false(res); + } +} + +void msgpack_rpc_from_integer(int64_t result, msgpack_packer *res) +{ + msgpack_pack_int64(res, result); +} + +void msgpack_rpc_from_uinteger(uint64_t result, msgpack_packer *res) +{ + msgpack_pack_uint64(res, result); +} + +void msgpack_rpc_from_float(double result, msgpack_packer *res) +{ + msgpack_pack_double(res, result); +} + +void msgpack_rpc_from_string(string result, msgpack_packer *res) +{ + msgpack_pack_str(res, result.length); + msgpack_pack_str_body(res, result.str, result.length); +} + +typedef struct { + const object *obj; + bool container; + size_t idx; +} api_to_msgpack_object_stack_item; + +void msgpack_rpc_from_object(const object result, msgpack_packer *const res) +{ + kvec_t(api_to_msgpack_object_stack_item) stack = KV_INITIAL_VALUE; + kv_push(stack, ((api_to_msgpack_object_stack_item) {&result, false, 0})); + + while (kv_size(stack)) { + api_to_msgpack_object_stack_item cur = kv_last(stack); + + switch (cur.obj->type) { + case OBJECT_TYPE_NIL: { + msgpack_pack_nil(res); + break; + } + case OBJECT_TYPE_BOOL: { + msgpack_rpc_from_boolean(cur.obj->data.boolean, res); + break; + } + case OBJECT_TYPE_INT: { + msgpack_rpc_from_integer(cur.obj->data.integer, res); + break; + } + case OBJECT_TYPE_UINT: { + msgpack_rpc_from_uinteger(cur.obj->data.uinteger, res); + break; + } + case OBJECT_TYPE_FLOAT: { + msgpack_rpc_from_float(cur.obj->data.floating, res); + break; + } + case OBJECT_TYPE_STR: { + msgpack_rpc_from_string(cur.obj->data.string, res); + break; + } + case OBJECT_TYPE_ARRAY: { + const size_t size = cur.obj->data.array.size; + + if (cur.container) { + if (cur.idx >= size) { + (void)kv_pop(stack); + } else { + const size_t idx = cur.idx; + cur.idx++; + kv_last(stack) = cur; + kv_push(stack, ((api_to_msgpack_object_stack_item) { + .obj = &cur.obj->data.array.items[idx], + .container = false, + })); + } + } else { + msgpack_pack_array(res, size); + cur.container = true; + kv_last(stack) = cur; + } + break; + } + case OBJECT_TYPE_DICTIONARY: { + const size_t size = cur.obj->data.dictionary.size; + if (cur.container) { + if (cur.idx >= size) { + (void)kv_pop(stack); + } else { + const size_t idx = cur.idx; + cur.idx++; + kv_last(stack) = cur; + msgpack_rpc_from_string(cur.obj->data.dictionary.items[idx].key, + res); + kv_push(stack, ((api_to_msgpack_object_stack_item) { + .obj = &cur.obj->data.dictionary.items[idx].value, + .container = false, + })); + } + } else { + msgpack_pack_map(res, size); + cur.container = true; + kv_last(stack) = cur; + } + break; + } + } + if (!cur.container) { + (void)kv_pop(stack); + } + } + kv_destroy(stack); +} + +void msgpack_rpc_from_array(array result, msgpack_packer *res) +{ + msgpack_pack_array(res, result.size); + + for (size_t i = 0; i < result.size; i++) { + msgpack_rpc_from_object(result.items[i], res); + } +} + +void msgpack_rpc_from_dictionary(dictionary result, msgpack_packer *res) +{ + msgpack_pack_map(res, result.size); + + for (size_t i = 0; i < result.size; i++) { + msgpack_rpc_from_string(result.items[i].key, res); + msgpack_rpc_from_object(result.items[i].value, res); + } +} + +void msgpack_rpc_serialize_request(uint64_t request_id, + string method, + array args, + msgpack_packer *pac) +{ + msgpack_pack_array(pac, request_id ? 4 : 3); + msgpack_pack_int(pac, request_id ? 0 : 2); + + if (request_id) { + msgpack_pack_uint64(pac, request_id); + } + + msgpack_rpc_from_string(method, pac); + msgpack_rpc_from_array(args, pac); +} + +void msgpack_rpc_serialize_response(uint64_t response_id, + struct api_error *err, + object arg, + msgpack_packer *pac) +{ + msgpack_pack_array(pac, 4); + msgpack_pack_int(pac, 1); + msgpack_pack_uint64(pac, response_id); + + if (err->isset) { + // error represented by a [type, message] array + msgpack_pack_array(pac, 2); + msgpack_rpc_from_integer(err->type, pac); + msgpack_rpc_from_string(cstring_to_string(err->msg), pac); + // Nil result + msgpack_pack_nil(pac); + } else { + // Nil error + msgpack_pack_nil(pac); + // Return value + msgpack_rpc_from_object(arg, pac); + } +} + +STATIC bool msgpack_rpc_is_notification(msgpack_object *req) +{ + return req->via.array.ptr[0].via.u64 == 2; +} + +msgpack_object *msgpack_rpc_method(msgpack_object *req) +{ + msgpack_object *obj = req->via.array.ptr + + (msgpack_rpc_is_notification(req) ? 1 : 2); + return obj->type == MSGPACK_OBJECT_STR || obj->type == MSGPACK_OBJECT_BIN ? + obj : NULL; +} + +msgpack_object *msgpack_rpc_args(msgpack_object *req) +{ + msgpack_object *obj = req->via.array.ptr + + (msgpack_rpc_is_notification(req) ? 2 : 3); + return obj->type == MSGPACK_OBJECT_ARRAY ? obj : NULL; +} + +STATIC msgpack_object *msgpack_rpc_msg_id(msgpack_object *req) +{ + if (msgpack_rpc_is_notification(req)) { + return NULL; + } + msgpack_object *obj = &req->via.array.ptr[1]; + return obj->type == MSGPACK_OBJECT_POSITIVE_INTEGER ? obj : NULL; +} + +void msgpack_rpc_validate(uint64_t *response_id, + msgpack_object *req, + struct api_error *err) +{ + // response id not known yet + + *response_id = UINT64_MAX; + // Validate the basic structure of the msgpack-rpc payload + if (req->type != MSGPACK_OBJECT_ARRAY) { + error_set(err, API_ERROR_TYPE_VALIDATION, "Message is not an array"); + return; + } + + if (req->via.array.size == 0) { + error_set(err, API_ERROR_TYPE_VALIDATION, "Message is empty"); + return; + } + + if (req->via.array.ptr[0].type != MSGPACK_OBJECT_POSITIVE_INTEGER) { + error_set(err, API_ERROR_TYPE_VALIDATION, "Message type must be an integer"); + return; + } + + uint64_t type = req->via.array.ptr[0].via.u64; + if (type != MESSAGE_TYPE_REQUEST && type != MESSAGE_TYPE_NOTIFICATION) { + error_set(err, API_ERROR_TYPE_VALIDATION, "Unknown message type"); + return; + } + + if ((type == MESSAGE_TYPE_REQUEST && req->via.array.size != 4) + || (type == MESSAGE_TYPE_NOTIFICATION && req->via.array.size != 3)) { + error_set(err, API_ERROR_TYPE_VALIDATION, + "Request array size should be 4 (request) or 3 (notification)"); + return; + } + + if (type == MESSAGE_TYPE_REQUEST) { + msgpack_object *id_obj = msgpack_rpc_msg_id(req); + if (!id_obj) { + error_set(err, API_ERROR_TYPE_VALIDATION, "ID must be a positive integer"); + return; + } + *response_id = id_obj->via.u64; + } + + if (!msgpack_rpc_method(req)) { + error_set(err, API_ERROR_TYPE_VALIDATION, "Method must be a string"); + return; + } + + if (!msgpack_rpc_args(req)) { + error_set(err, API_ERROR_TYPE_VALIDATION, "Parameters must be an array"); + return; + } +} diff --git a/src/rpc/msgpack/helpers.h b/src/rpc/msgpack/helpers.h new file mode 100644 index 0000000..7cb7d7d --- /dev/null +++ b/src/rpc/msgpack/helpers.h @@ -0,0 +1,45 @@ +#pragma once + +#include "rpc/sb-rpc.h" + +bool msgpack_rpc_to_object(const msgpack_object *const obj, object *const arg); + +//STATIC bool msgpack_rpc_to_string(const msgpack_object *const obj, +// string *const arg); + +bool msgpack_rpc_to_array(const msgpack_object *const obj, array *const arg); + +bool msgpack_rpc_to_dictionary(const msgpack_object *const obj, + dictionary *const arg); + +void msgpack_rpc_from_boolean(bool result, msgpack_packer *res); + +void msgpack_rpc_from_integer(int64_t result, msgpack_packer *res); +void msgpack_rpc_from_uinteger(uint64_t result, msgpack_packer *res); + +void msgpack_rpc_from_float(double result, msgpack_packer *res); + +void msgpack_rpc_from_string(string result, msgpack_packer *res); + +void msgpack_rpc_from_object(const object result, msgpack_packer *const res); + +void msgpack_rpc_from_array(array result, msgpack_packer *res); + +void msgpack_rpc_from_dictionary(dictionary result, msgpack_packer *res); + +void msgpack_rpc_serialize_request(uint64_t request_id, string method, + array args, msgpack_packer *pac); + +void msgpack_rpc_serialize_response(uint64_t response_id, struct api_error *err, + object arg, msgpack_packer *pac); + +//STATIC bool msgpack_rpc_is_notification(msgpack_object *req); + +msgpack_object *msgpack_rpc_method(msgpack_object *req); + +msgpack_object *msgpack_rpc_args(msgpack_object *req); + +//STATIC msgpack_object *msgpack_rpc_msg_id(msgpack_object *req); + +void msgpack_rpc_validate(uint64_t *response_id, msgpack_object *req, + struct api_error *err); From 71d87f0fcadf7e244af32b6002195d251e1e64b9 Mon Sep 17 00:00:00 2001 From: Stephan Zeisberg Date: Fri, 21 Oct 2016 22:29:25 +0200 Subject: [PATCH 04/41] Major api function simplification using the new helper modules --- src/api/register.c | 17 ++++------- src/api/result.c | 61 ++++++++----------------------------- src/api/run.c | 75 +++++++++++----------------------------------- src/api/sb-api.h | 16 ++++++---- 4 files changed, 46 insertions(+), 123 deletions(-) diff --git a/src/api/register.c b/src/api/register.c index ae2e91a..b9bbd25 100644 --- a/src/api/register.c +++ b/src/api/register.c @@ -19,13 +19,12 @@ #include "rpc/db/sb-db.h" #include "api/sb-api.h" +#include "api/helpers.h" -int api_register(string name, string desc, - string author, string license, array functions, uint64_t con_id, - uint32_t msgid, char *pluginkey, struct api_error *api_error) +int api_register(string name, string desc, string author, string license, + array functions, char *pluginkey, struct api_error *api_error) { - struct message_object *func; - array params = ARRAY_INIT; + object *func; if (functions.size == 0) { error_set(api_error, API_ERROR_TYPE_VALIDATION, @@ -40,7 +39,7 @@ int api_register(string name, string desc, } for (size_t i = 0; i < functions.size; i++) { - func = &functions.obj[i]; + func = &functions.items[i]; if (func->type != OBJECT_TYPE_ARRAY) { error_set(api_error, API_ERROR_TYPE_VALIDATION, @@ -48,7 +47,7 @@ int api_register(string name, string desc, continue; } - if (db_function_add(pluginkey, &func->data.params) == -1) { + if (db_function_add(pluginkey, &func->data.array) == -1) { error_set(api_error, API_ERROR_TYPE_VALIDATION, "Failed to register function in database."); continue; @@ -58,9 +57,5 @@ int api_register(string name, string desc, if (api_error->isset) return (-1); - if (connection_send_response(con_id, msgid, params, api_error) < 0) { - return (-1); - }; - return (0); } diff --git a/src/api/result.c b/src/api/result.c index 965e583..98fa922 100644 --- a/src/api/result.c +++ b/src/api/result.c @@ -18,83 +18,48 @@ #include #include "api/sb-api.h" +#include "api/helpers.h" #include "sb-common.h" -int api_result(char *targetpluginkey, uint64_t callid, - struct message_object args, uint64_t con_id, uint32_t msgid, +int api_result(char *targetpluginkey, uint64_t callid, array args, struct api_error *api_error) { - struct message_object *data; - struct message_object *meta; - array result_params; - array result_response_params; string result; - struct callinfo cinfo; + object res; if (!api_error) return (-1); - result_params.size = 2; - result_params.obj = CALLOC(2, struct message_object); + array meta = ARRAY_DICT_INIT; + ADD(meta, UINTEGER_OBJ(callid)); - if (!result_params.obj) - return (-1); - - /* data refs to first result_params parameter */ - meta = &result_params.obj[0]; - - meta->type = OBJECT_TYPE_ARRAY; - - /* meta = [nil, callid] */ - meta->data.params.size = 1; - meta->data.params.obj = CALLOC(1, struct message_object); - - if (!meta->data.params.obj) - return (-1); - - /* add callid */ - data = &meta->data.params.obj[0]; - data->type = OBJECT_TYPE_UINT; - data->data.uinteger = callid; - - /* add function parameters, data refs to third result_params parameter */ - data = &result_params.obj[1]; - - data->type = OBJECT_TYPE_ARRAY; - data->data.params = message_object_copy(args).data.params; + array request = ARRAY_DICT_INIT; + ADD(request, ARRAY_OBJ(meta)); + ADD(request, copy_object(ARRAY_OBJ(args))); /* send request */ result = (string) {.str = "result", .length = sizeof("result") - 1}; - cinfo = connection_send_request(targetpluginkey, result, result_params, + res = connection_send_request(targetpluginkey, result, request, api_error); if (api_error->isset) return (-1); - if (cinfo.response.params.size != 1) { + if (res.data.array.size != 1) { error_set(api_error, API_ERROR_TYPE_VALIDATION, "Error dispatching result API response. Either response is broken " "or it just has wrong params size."); return (-1); } - if (!(cinfo.response.params.obj[0].type == OBJECT_TYPE_UINT && - callid == cinfo.response.params.obj[0].data.uinteger)) { + if (!(res.data.array.items[0].type == OBJECT_TYPE_UINT && + callid == res.data.array.items[0].data.uinteger)) { error_set(api_error, API_ERROR_TYPE_VALIDATION, "Error dispatching run API response. Invalid callid"); return (-1); } - result_response_params.size = 1; - result_response_params.obj = CALLOC(1, struct message_object); - result_response_params.obj[0].type = OBJECT_TYPE_UINT; - result_response_params.obj[0].data.uinteger = callid; - - if (connection_send_response(con_id, msgid, result_response_params, api_error) < 0) { - return (-1); - }; - - free_params(cinfo.response.params); + api_free_array(res.data.array); return (0); } diff --git a/src/api/run.c b/src/api/run.c index 9f9b6d9..6e530f7 100644 --- a/src/api/run.c +++ b/src/api/run.c @@ -19,17 +19,14 @@ #include "rpc/db/sb-db.h" #include "api/sb-api.h" +#include "api/helpers.h" + int api_run(char *targetpluginkey, string function_name, uint64_t callid, - struct message_object args, uint64_t con_id, - uint32_t msgid, struct api_error *api_error) + array args, struct api_error *api_error) { - struct message_object *data; - struct message_object *meta; - array run_params; - array run_response_params; string run; - struct callinfo cinfo; + object result; if (!api_error) return (-1); @@ -39,82 +36,44 @@ int api_run(char *targetpluginkey, string function_name, uint64_t callid, return (-1); } - if (db_function_verify(targetpluginkey, function_name, &args.data.params) == -1) { + if (db_function_verify(targetpluginkey, function_name, &args) == -1) { error_set(api_error, API_ERROR_TYPE_VALIDATION, "run() verification failed."); return (-1); } - run_params.size = 3; - run_params.obj = CALLOC(3, struct message_object); - - if (!run_params.obj) - return (-1); - - /* data refs to first run_params parameter */ - meta = &run_params.obj[0]; - - meta->type = OBJECT_TYPE_ARRAY; - - /* meta = [nil, callid] */ - meta->data.params.size = 2; - meta->data.params.obj = CALLOC(2, struct message_object); - - if (!meta->data.params.obj) - return (-1); + array meta = ARRAY_DICT_INIT; + ADD(meta, OBJECT_OBJ((object) OBJECT_INIT)); + ADD(meta, UINTEGER_OBJ(callid)); - /* add nil */ - data = &meta->data.params.obj[0]; - data->type = OBJECT_TYPE_NIL; - - /* add callid */ - data = &meta->data.params.obj[1]; - data->type = OBJECT_TYPE_UINT; - data->data.uinteger = callid; - - /* add function name, data refs to second run_params parameter */ - data = &run_params.obj[1]; - data->type = OBJECT_TYPE_STR; - data->data.string = cstring_copy_string(function_name.str); - - /* add function parameters, data refs to third run_params parameter */ - data = &run_params.obj[2]; - - data->type = OBJECT_TYPE_ARRAY; - data->data.params = message_object_copy(args).data.params; + array request = ARRAY_DICT_INIT; + ADD(request, ARRAY_OBJ(meta)); + ADD(request, STRING_OBJ(cstring_copy_string(function_name.str))); + ADD(request, copy_object(ARRAY_OBJ(args))); /* send request */ run = (string) {.str = "run", .length = sizeof("run") - 1}; - cinfo = connection_send_request(targetpluginkey, run, run_params, + result = connection_send_request(targetpluginkey, run, request, api_error); if (api_error->isset) return (-1); - if (cinfo.response.params.size != 1) { + if (result.data.array.size != 1) { error_set(api_error, API_ERROR_TYPE_VALIDATION, "Error dispatching run API response. Either response is broken " "or it just has wrong params size."); return (-1); } - if (!(cinfo.response.params.obj[0].type == OBJECT_TYPE_UINT && - callid == cinfo.response.params.obj[0].data.uinteger)) { + if (!(result.data.array.items[0].type == OBJECT_TYPE_UINT && + callid == result.data.array.items[0].data.uinteger)) { error_set(api_error, API_ERROR_TYPE_VALIDATION, "Error dispatching run API response. Invalid callid"); return (-1); } - run_response_params.size = 1; - run_response_params.obj = CALLOC(1, struct message_object); - run_response_params.obj[0].type = OBJECT_TYPE_UINT; - run_response_params.obj[0].data.uinteger = callid; - - if (connection_send_response(con_id, msgid, run_response_params, api_error) < 0) { - return (-1); - }; - - free_params(cinfo.response.params); + api_free_array(result.data.array); return (0); } diff --git a/src/api/sb-api.h b/src/api/sb-api.h index 0bc16e1..3da8c5b 100644 --- a/src/api/sb-api.h +++ b/src/api/sb-api.h @@ -34,8 +34,8 @@ * @return 0 in case of success otherwise 1 */ int api_register(string name, string desc, - string author, string license, array functions, uint64_t con_id, - uint32_t msgid, char *pluginkey, struct api_error *api_error); + string author, string license, array functions, char *pluginkey, + struct api_error *api_error); /** * Run a plugin function @@ -47,8 +47,7 @@ * @return 0 in case of success otherwise -1 */ int api_run(char *targetpluginkey, string function_name, uint64_t callid, - struct message_object args, uint64_t con_id, uint32_t msgid, - struct api_error *api_error); + array args, struct api_error *api_error); /** * Generates an API key using /dev/urandom. The length of the key @@ -58,6 +57,11 @@ int api_run(char *targetpluginkey, string function_name, uint64_t callid, */ int api_get_key(string key); -int api_result(char *targetpluginkey, uint64_t callid, - struct message_object args, uint64_t con_id, uint32_t msgid, +int api_result(char *targetpluginkey, uint64_t callid, array args, struct api_error *api_error); + +void api_free_string(string value); +void api_free_object(object value); +void api_free_array(array value); +void api_free_dictionary(dictionary value); +object copy_object(object obj); From 277b93103909c5a51bfa3f2cedf0732fead2d769 Mon Sep 17 00:00:00 2001 From: Stephan Zeisberg Date: Fri, 21 Oct 2016 22:30:28 +0200 Subject: [PATCH 05/41] Include missing NULL checks --- src/filesystem.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/filesystem.c b/src/filesystem.c index eb15693..ab21939 100644 --- a/src/filesystem.c +++ b/src/filesystem.c @@ -153,6 +153,9 @@ int filesystem_save_sync(const char *fn, const void *x, size_t xlen) int fd; int r; + if (!x) + return -1; + fd = filesystem_open_write(fn); if (fd == -1) @@ -174,6 +177,9 @@ int filesystem_load(const char *fn, void *x, size_t xlen) int fd; int r; + if (!x) + return -1; + fd = filesystem_open_read(fn); if (fd == -1) From fb6b70aa8f22bfb4e9b758cfaa7d152af28050b2 Mon Sep 17 00:00:00 2001 From: Stephan Zeisberg Date: Fri, 21 Oct 2016 22:31:49 +0200 Subject: [PATCH 06/41] Remove tests from old module and adapt tests to new helper modules This commit removes tests (pack/unpack/message) which are now deprecated because of the new helper module. I also tried to simplify the run/register/result tests and i fixed every memleak produced from these tests. --- test/functional/db-function-flush-args.c | 44 +-- test/functional/db-function-register.c | 39 +-- test/functional/db-function-verify.c | 33 +- test/functional/dispatch-handle-register.c | 375 +++++++++++---------- test/functional/dispatch-handle-result.c | 293 ++++++++++------ test/functional/dispatch-handle-run.c | 255 +++++++++----- test/helper-all.c | 238 +------------ test/helper-all.h | 30 -- test/helper-validate.c | 200 +++-------- test/test-list.h | 35 -- test/unit/server-start.c | 1 + test/unit/server-stop.c | 1 + test/wrapper-functions.c | 18 +- 13 files changed, 679 insertions(+), 883 deletions(-) diff --git a/test/functional/db-function-flush-args.c b/test/functional/db-function-flush-args.c index 298e7c4..85d7289 100644 --- a/test/functional/db-function-flush-args.c +++ b/test/functional/db-function-flush-args.c @@ -20,6 +20,7 @@ #include "helper-all.h" #include "rpc/db/sb-db.h" #include "sb-common.h" +#include "api/sb-api.h" #include "helper-unix.h" @@ -59,23 +60,23 @@ void functional_db_function_flush_args(UNUSED(void **state)) ssize_t argc = 0; params.size = 4; - params.obj = CALLOC(params.size, struct message_object); + params.items = CALLOC(params.size, object); - params.obj[0].type = OBJECT_TYPE_STR; - params.obj[0].data.string = name; + params.items[0].type = OBJECT_TYPE_STR; + params.items[0].data.string = name; - params.obj[1].type = OBJECT_TYPE_STR; - params.obj[1].data.string = desc; + params.items[1].type = OBJECT_TYPE_STR; + params.items[1].data.string = desc; - params.obj[2].type = OBJECT_TYPE_ARRAY; - params.obj[2].data.params.size = 1; - params.obj[2].data.params.obj = CALLOC(params.obj[2].data.params.size, - struct message_object); - params.obj[2].data.params.obj[0].type = OBJECT_TYPE_INT; - params.obj[2].data.params.obj[0].data.uinteger = 6; + params.items[2].type = OBJECT_TYPE_ARRAY; + params.items[2].data.array.size = 1; + params.items[2].data.array.items = CALLOC(params.items[2].data.array.size, + object); + params.items[2].data.array.items[0].type = OBJECT_TYPE_INT; + params.items[2].data.array.items[0].data.uinteger = 6; connect_and_create(pluginkey); - args = ¶ms.obj[2].data.params; + args = ¶ms.items[2].data.array; /* register function */ assert_int_equal(0, db_function_add(pluginkey, ¶ms)); @@ -96,14 +97,15 @@ void functional_db_function_flush_args(UNUSED(void **state)) /* now test with two arguments */ - free_params(params.obj[2].data.params); - params.obj[2].data.params.size = 2; - params.obj[2].data.params.obj = CALLOC(params.obj[2].data.params.size, - struct message_object); - params.obj[2].data.params.obj[0].type = OBJECT_TYPE_INT; - params.obj[2].data.params.obj[0].data.uinteger = 6; - params.obj[2].data.params.obj[0].type = OBJECT_TYPE_INT; - params.obj[2].data.params.obj[0].data.uinteger = 12; + api_free_array(params.items[2].data.array); + + params.items[2].data.array.size = 2; + params.items[2].data.array.items = CALLOC(params.items[2].data.array.size, + object); + params.items[2].data.array.items[0].type = OBJECT_TYPE_INT; + params.items[2].data.array.items[0].data.uinteger = 6; + params.items[2].data.array.items[0].type = OBJECT_TYPE_INT; + params.items[2].data.array.items[0].data.uinteger = 12; assert_int_equal(0, db_function_add(pluginkey, ¶ms)); argc = db_function_get_argc(pluginkey, name); @@ -117,5 +119,5 @@ void functional_db_function_flush_args(UNUSED(void **state)) db_close(); - free_params(params); + api_free_array(params); } diff --git a/test/functional/db-function-register.c b/test/functional/db-function-register.c index 0c2a522..482f93b 100644 --- a/test/functional/db-function-register.c +++ b/test/functional/db-function-register.c @@ -19,6 +19,7 @@ #include "helper-all.h" #include "rpc/sb-rpc.h" +#include "api/sb-api.h" #include "sb-common.h" #include "helper-unix.h" @@ -33,20 +34,20 @@ void functional_db_function_add(UNUSED(void **state)) array params; params.size = 4; - params.obj = CALLOC(params.size, struct message_object); + params.items = CALLOC(params.size, object); - params.obj[0].type = OBJECT_TYPE_STR; - params.obj[0].data.string = name; + params.items[0].type = OBJECT_TYPE_STR; + params.items[0].data.string = name; - params.obj[1].type = OBJECT_TYPE_STR; - params.obj[1].data.string = desc; + params.items[1].type = OBJECT_TYPE_STR; + params.items[1].data.string = desc; - params.obj[2].type = OBJECT_TYPE_ARRAY; - params.obj[2].data.params.size = 1; - params.obj[2].data.params.obj = CALLOC(params.obj[2].data.params.size, - struct message_object); - params.obj[2].data.params.obj[0].type = OBJECT_TYPE_INT; - params.obj[2].data.params.obj[0].data.uinteger = 6; + params.items[2].type = OBJECT_TYPE_ARRAY; + params.items[2].data.array.size = 1; + params.items[2].data.array.items = CALLOC(params.items[2].data.array.size, + object); + params.items[2].data.array.items[0].type = OBJECT_TYPE_INT; + params.items[2].data.array.items[0].data.uinteger = 6; connect_and_create(pluginkey); @@ -59,23 +60,23 @@ void functional_db_function_add(UNUSED(void **state)) /* function without arguments should work */ params.size = 4; - params.obj[2].data.params.size = 0; + params.items[2].data.array.size = 0; assert_int_equal(0, db_function_add(pluginkey, ¶ms)); /* function without name should not work */ params.size = 4; - params.obj[2].data.params.size = 1; - params.obj[0].data.string = cstring_copy_string(""); + params.items[2].data.array.size = 1; + params.items[0].data.string = cstring_copy_string(""); assert_int_not_equal(0, db_function_add(pluginkey, ¶ms)); - free_string(params.obj[0].data.string); + free_string(params.items[0].data.string); /* function without description should work */ - params.obj[0].data.string = name; - params.obj[1].data.string = cstring_copy_string(""); + params.items[0].data.string = name; + params.items[1].data.string = cstring_copy_string(""); assert_int_equal(0, db_function_add(pluginkey, ¶ms)); db_close(); - free_params(params); - free_string(desc); + api_free_array(params); + api_free_string(desc); } diff --git a/test/functional/db-function-verify.c b/test/functional/db-function-verify.c index 280bd6c..e351876 100644 --- a/test/functional/db-function-verify.c +++ b/test/functional/db-function-verify.c @@ -20,6 +20,7 @@ #include "helper-all.h" #include "rpc/sb-rpc.h" +#include "api/sb-api.h" #include "sb-common.h" #include "helper-unix.h" @@ -33,22 +34,22 @@ void functional_db_function_verify(UNUSED(void **state)) array params, *args; params.size = 4; - params.obj = CALLOC(params.size, struct message_object); + params.items = CALLOC(params.size, object); - params.obj[0].type = OBJECT_TYPE_STR; - params.obj[0].data.string = name; + params.items[0].type = OBJECT_TYPE_STR; + params.items[0].data.string = name; - params.obj[1].type = OBJECT_TYPE_STR; - params.obj[1].data.string = desc; + params.items[1].type = OBJECT_TYPE_STR; + params.items[1].data.string = desc; - params.obj[2].type = OBJECT_TYPE_ARRAY; - params.obj[2].data.params.size = 1; - params.obj[2].data.params.obj = CALLOC(params.obj[2].data.params.size, - struct message_object); - params.obj[2].data.params.obj[0].type = OBJECT_TYPE_INT; - params.obj[2].data.params.obj[0].data.uinteger = 6; + params.items[2].type = OBJECT_TYPE_ARRAY; + params.items[2].data.array.size = 1; + params.items[2].data.array.items = CALLOC(params.items[2].data.array.size, + object); + params.items[2].data.array.items[0].type = OBJECT_TYPE_INT; + params.items[2].data.array.items[0].data.uinteger = 6; - args = ¶ms.obj[2].data.params; + args = ¶ms.items[2].data.array; connect_and_create(pluginkey); @@ -73,11 +74,11 @@ void functional_db_function_verify(UNUSED(void **state)) /* verifying an existing function with wrong arguments' type */ args->size = 1; - args->obj[0].type = OBJECT_TYPE_UINT; - args->obj[0].data.integer = -1; + args->items[0].type = OBJECT_TYPE_UINT; + args->items[0].data.integer = -1; assert_int_not_equal(0, db_function_verify(pluginkey, name, args)); - free_params(params); - free_string(invalid_name); + api_free_array(params); + api_free_string(invalid_name); db_close(); } diff --git a/test/functional/dispatch-handle-register.c b/test/functional/dispatch-handle-register.c index 89faeb5..358562d 100644 --- a/test/functional/dispatch-handle-register.c +++ b/test/functional/dispatch-handle-register.c @@ -19,209 +19,232 @@ #include "sb-common.h" #include "tweetnacl.h" #include "rpc/sb-rpc.h" -#include "rpc/msgpack/sb-msgpack-rpc.h" +#include "api/helpers.h" +#include "api/sb-api.h" +#ifdef __linux__ +#include +#endif #include "helper-unix.h" #include "helper-all.h" #include "helper-validate.h" -void functional_dispatch_handle_register(UNUSED(void **state)) +static array api_register_valid(void) { - connection_request_event_info info; - struct message_request *request; - array *meta, *functions, *func1, *func2, *args; - struct api_error *err = MALLOC(struct api_error); - char pluginkey[PLUGINKEY_STRING_SIZE] = "012345789ABCDEFH"; + array registermeta = ARRAY_DICT_INIT; + ADD(registermeta, STRING_OBJ(cstring_copy_string("register"))); + ADD(registermeta, STRING_OBJ(cstring_copy_string("register a plugin"))); + ADD(registermeta, STRING_OBJ(cstring_copy_string("stze"))); + ADD(registermeta, STRING_OBJ(cstring_copy_string("none"))); + + array registerfunc1args = ARRAY_DICT_INIT; + ADD(registerfunc1args, INTEGER_OBJ(1234)); + ADD(registerfunc1args, STRING_OBJ(cstring_copy_string("func1 arg"))); + + array registerfunc1 = ARRAY_DICT_INIT; + ADD(registerfunc1, STRING_OBJ(cstring_copy_string("my function name"))); + ADD(registerfunc1, STRING_OBJ(cstring_copy_string("my function description"))); + ADD(registerfunc1, ARRAY_OBJ(registerfunc1args)); + + array registerfunc2 = ARRAY_DICT_INIT; + ADD(registerfunc2, STRING_OBJ(cstring_copy_string("my sec function name"))); + ADD(registerfunc2, STRING_OBJ(cstring_copy_string("my sec function description"))); + ADD(registerfunc2, ARRAY_OBJ(ARRAY_DICT_INIT)); + + array registerfunctions = ARRAY_DICT_INIT; + ADD(registerfunctions, ARRAY_OBJ(registerfunc1)); + ADD(registerfunctions, ARRAY_OBJ(registerfunc2)); + + array request = ARRAY_DICT_INIT; + ADD(request, ARRAY_OBJ(registermeta)); + ADD(request, ARRAY_OBJ(registerfunctions)); + + return request; +} + +static array api_register_wrong_args_size(void) +{ + array registermeta = ARRAY_DICT_INIT; + ADD(registermeta, STRING_OBJ(cstring_copy_string("register"))); + ADD(registermeta, STRING_OBJ(cstring_copy_string("register a plugin"))); + ADD(registermeta, STRING_OBJ(cstring_copy_string("stze"))); + ADD(registermeta, STRING_OBJ(cstring_copy_string("none"))); + + array request = ARRAY_DICT_INIT; + ADD(request, ARRAY_OBJ(registermeta)); + + return request; +} - string name = cstring_copy_string("register"); - string description = cstring_copy_string("register a plugin"); - string author = cstring_copy_string("test"); - string license = cstring_copy_string("none"); +static array api_register_wrong_args_type(void) +{ + array registerfunc1 = ARRAY_DICT_INIT; + ADD(registerfunc1, STRING_OBJ(cstring_copy_string("my function name"))); + ADD(registerfunc1, STRING_OBJ(cstring_copy_string("my function description"))); + ADD(registerfunc1, ARRAY_OBJ(ARRAY_DICT_INIT)); - info.request.msgid = 1; + array registerfunc2 = ARRAY_DICT_INIT; + ADD(registerfunc2, STRING_OBJ(cstring_copy_string("my sec function name"))); + ADD(registerfunc2, STRING_OBJ(cstring_copy_string("my sec function description"))); + ADD(registerfunc2, ARRAY_OBJ(ARRAY_DICT_INIT)); - request = &info.request; - assert_non_null(request); + array registerfunctions = ARRAY_DICT_INIT; + ADD(registerfunctions, ARRAY_OBJ(registerfunc1)); + ADD(registerfunctions, ARRAY_OBJ(registerfunc2)); - info.api_error = *err; - assert_non_null(err); + array request = ARRAY_DICT_INIT; + ADD(request, STRING_OBJ(cstring_copy_string("wrong"))); + ADD(request, ARRAY_OBJ(registerfunctions)); - info.api_error.isset = false; + return request; +} - info.con = CALLOC(1, struct connection); - info.con->closed = true; - info.con->id = 1234; - strlcpy(info.con->cc.pluginkeystring, pluginkey, PLUGINKEY_STRING_SIZE+1); - assert_non_null(info.con); +static array api_register_wrong_meta_size(void) +{ + array registermeta = ARRAY_DICT_INIT; + ADD(registermeta, STRING_OBJ(cstring_copy_string("register"))); + ADD(registermeta, STRING_OBJ(cstring_copy_string("register a plugin"))); + ADD(registermeta, STRING_OBJ(cstring_copy_string("stze"))); + + array registerfunc1 = ARRAY_DICT_INIT; + ADD(registerfunc1, STRING_OBJ(cstring_copy_string("my function name"))); + ADD(registerfunc1, STRING_OBJ(cstring_copy_string("my function description"))); + ADD(registerfunc1, ARRAY_OBJ(ARRAY_DICT_INIT)); + + array registerfunc2 = ARRAY_DICT_INIT; + ADD(registerfunc2, STRING_OBJ(cstring_copy_string("my sec function name"))); + ADD(registerfunc2, STRING_OBJ(cstring_copy_string("my sec function description"))); + ADD(registerfunc2, ARRAY_OBJ(ARRAY_DICT_INIT)); + + array registerfunctions = ARRAY_DICT_INIT; + ADD(registerfunctions, ARRAY_OBJ(registerfunc1)); + ADD(registerfunctions, ARRAY_OBJ(registerfunc2)); + + array request = ARRAY_DICT_INIT; + ADD(request, ARRAY_OBJ(registermeta)); + ADD(request, ARRAY_OBJ(registerfunctions)); + + return request; +} - connect_and_create(info.con->cc.pluginkeystring); +static array api_register_missing_function_description(void) +{ + array registermeta = ARRAY_DICT_INIT; + ADD(registermeta, STRING_OBJ(cstring_copy_string("register"))); + ADD(registermeta, STRING_OBJ(cstring_copy_string("register a plugin"))); + ADD(registermeta, STRING_OBJ(cstring_copy_string("stze"))); + ADD(registermeta, STRING_OBJ(cstring_copy_string("none"))); + + array registerfunc1 = ARRAY_DICT_INIT; + ADD(registerfunc1, STRING_OBJ(cstring_copy_string("my function name"))); + ADD(registerfunc1, OBJECT_OBJ((object) OBJECT_INIT)); + ADD(registerfunc1, ARRAY_OBJ(ARRAY_DICT_INIT)); + + array registerfunc2 = ARRAY_DICT_INIT; + ADD(registerfunc2, STRING_OBJ(cstring_copy_string("my sec function name"))); + ADD(registerfunc2, STRING_OBJ(cstring_copy_string("my sec function description"))); + ADD(registerfunc2, ARRAY_OBJ(ARRAY_DICT_INIT)); + + array registerfunctions = ARRAY_DICT_INIT; + ADD(registerfunctions, ARRAY_OBJ(registerfunc1)); + ADD(registerfunctions, ARRAY_OBJ(registerfunc2)); + + array request = ARRAY_DICT_INIT; + ADD(request, ARRAY_OBJ(registermeta)); + ADD(request, ARRAY_OBJ(registerfunctions)); + + return request; +} + +static array api_register_empty_functions(void) +{ + array registermeta = ARRAY_DICT_INIT; + ADD(registermeta, STRING_OBJ(cstring_copy_string("register"))); + ADD(registermeta, STRING_OBJ(cstring_copy_string("register a plugin"))); + ADD(registermeta, STRING_OBJ(cstring_copy_string("stze"))); + ADD(registermeta, STRING_OBJ(cstring_copy_string("none"))); + + array registerfunctions = ARRAY_DICT_INIT; + + array request = ARRAY_DICT_INIT; + ADD(request, ARRAY_OBJ(registermeta)); + ADD(request, ARRAY_OBJ(registerfunctions)); + + return request; +} + +void functional_dispatch_handle_register(UNUSED(void **state)) +{ + struct connection *con; + array request; + struct api_error error = ERROR_INIT; + char pluginkey[PLUGINKEY_STRING_SIZE] = "012345789ABCDEFH"; + + con = CALLOC(1, struct connection); + con->closed = true; + con->id = 1234; + con->msgid = 4321; + strlcpy(con->cc.pluginkeystring, pluginkey, PLUGINKEY_STRING_SIZE+1); + assert_non_null(con); + + connect_and_create(con->cc.pluginkeystring); assert_int_equal(0, connection_init()); - connection_hashmap_put(info.con->id, info.con); - - /* first level arrays: - * - * [meta] args->obj[0] - * [functions] args->obj[1] - */ - request->params.size = 2; - request->params.obj = CALLOC(2, struct message_object); - request->params.obj[0].type = OBJECT_TYPE_ARRAY; - request->params.obj[1].type = OBJECT_TYPE_ARRAY; - - /* meta array: - * - * [name] - * [desciption] - * [author] - * [license] - */ - meta = &request->params.obj[0].data.params; - meta->size = 4; - meta->obj = CALLOC(meta->size, struct message_object); - meta->obj[0].type = OBJECT_TYPE_STR; - meta->obj[0].data.string = name; - meta->obj[1].type = OBJECT_TYPE_STR; - meta->obj[1].data.string = description; - meta->obj[2].type = OBJECT_TYPE_STR; - meta->obj[2].data.string = author; - meta->obj[3].type = OBJECT_TYPE_STR; - meta->obj[3].data.string = license; - - functions = &request->params.obj[1].data.params; - functions->size = 2; - functions->obj = CALLOC(functions->size, struct message_object); - functions->obj[0].type = OBJECT_TYPE_ARRAY; - functions->obj[1].type = OBJECT_TYPE_ARRAY; - - func1 = &functions->obj[0].data.params; - func1->size = 3; - func1->obj = CALLOC(3, struct message_object); - func1->obj[0].type = OBJECT_TYPE_STR; - func1->obj[0].data.string = cstring_copy_string("my function name"); - func1->obj[1].type = OBJECT_TYPE_STR; - func1->obj[1].data.string = cstring_copy_string("my function description"); - func1->obj[2].type = OBJECT_TYPE_ARRAY; - func1->obj[2].data.params.size = 0; - - func2 = &functions->obj[1].data.params; - func2->size = 3; - func2->obj = CALLOC(3, struct message_object); - func2->obj[0].type = OBJECT_TYPE_STR; - func2->obj[0].data.string = cstring_copy_string("my snd function name"); - func2->obj[1].type = OBJECT_TYPE_STR; - func2->obj[1].data.string = cstring_copy_string("my snd function description"); - func2->obj[2].type = OBJECT_TYPE_ARRAY; - func2->obj[2].data.params.size = 0; + connection_hashmap_put(con->id, con); /* a valid request has to trigger the corresponding response */ - assert_false(info.api_error.isset); - expect_check(__wrap_crypto_write, &deserialized, validate_register_response, NULL); - assert_int_equal(0, handle_register(info.con->id, &info.request, info.con->cc.pluginkeystring, &info.api_error)); + request = api_register_valid(); + assert_false(error.isset); + handle_register(con->id, 123, con->cc.pluginkeystring, request, &error); + assert_false(error.isset); + api_free_array(request); /* payload does not consist of two arrays, meta and func */ - request->params.size = 1; - assert_false(info.api_error.isset); - assert_int_not_equal(0, handle_register(info.con->id, &info.request, info.con->cc.pluginkeystring, &info.api_error)); - assert_true(info.api_error.isset); - assert_true(info.api_error.type == API_ERROR_TYPE_VALIDATION); - info.api_error.isset = false; - request->params.size = 2; + request = api_register_wrong_args_size(); + assert_false(error.isset); + handle_register(con->id, 123, con->cc.pluginkeystring, request, &error); + assert_true(error.isset); + assert_true(error.type == API_ERROR_TYPE_VALIDATION); + error.isset = false; + api_free_array(request); /* object has wrong type */ - request->params.obj[0].type = OBJECT_TYPE_STR; - assert_false(info.api_error.isset); - assert_int_not_equal(0, handle_register(info.con->id, &info.request, info.con->cc.pluginkeystring, &info.api_error)); - assert_true(info.api_error.isset); - assert_true(info.api_error.type == API_ERROR_TYPE_VALIDATION); - info.api_error.isset = false; - request->params.obj[0].type = OBJECT_TYPE_ARRAY; + request = api_register_wrong_args_type(); + assert_false(error.isset); + handle_register(con->id, 123, con->cc.pluginkeystring, request, &error); + assert_true(error.isset); + assert_true(error.type == API_ERROR_TYPE_VALIDATION); + error.isset = false; + api_free_array(request); /* meta has wrong size */ - meta->size = 3; - assert_false(info.api_error.isset); - assert_int_not_equal(0, handle_register(info.con->id, &info.request, info.con->cc.pluginkeystring, &info.api_error)); - assert_true(info.api_error.isset); - assert_true(info.api_error.type == API_ERROR_TYPE_VALIDATION); - info.api_error.isset = false; - meta->size = 4; - - /* plugin name is very long and contains same random bytes. since - * there are no real constrains for the plugin name, this should work. - */ - size_t len = 8096; - unsigned char *buf = MALLOC_ARRAY(len, unsigned char); - assert_non_null(buf); - randombytes(buf, len); - meta->obj[0].data.string.str = (char*) buf; - meta->obj[0].data.string.length = len; - assert_false(info.api_error.isset); - expect_check(__wrap_crypto_write, &deserialized, validate_register_response, NULL); - assert_int_equal(0, handle_register(info.con->id, &info.request, info.con->cc.pluginkeystring, &info.api_error)); - assert_false(info.api_error.isset); - meta->obj[0].data.string = name; - FREE(buf); + request = api_register_wrong_meta_size(); + assert_false(error.isset); + handle_register(con->id, 123, con->cc.pluginkeystring, request, &error); + assert_true(error.isset); + assert_true(error.type == API_ERROR_TYPE_VALIDATION); + error.isset = false; + api_free_array(request); /* no function description field should fail */ - func1->obj[1].type = OBJECT_TYPE_NIL; - assert_false(info.api_error.isset); - assert_int_not_equal(0, handle_register(info.con->id, &info.request, info.con->cc.pluginkeystring, &info.api_error)); - assert_true(info.api_error.isset); - assert_true(info.api_error.type == API_ERROR_TYPE_VALIDATION); - func1->obj[1].type = OBJECT_TYPE_STR; - info.api_error.isset = false; - - /* very long function description should work so far */ - string func_desc = func1->obj[1].data.string; - len = 8096; - buf = MALLOC_ARRAY(len, unsigned char); - assert_non_null(buf); - randombytes(buf, len); - func1->obj[1].data.string.str = (char*) buf; - func1->obj[1].data.string.length = len; - assert_false(info.api_error.isset); - expect_check(__wrap_crypto_write, &deserialized, validate_register_response, NULL); - assert_int_equal(0, handle_register(info.con->id, &info.request, info.con->cc.pluginkeystring, &info.api_error)); - assert_false(info.api_error.isset); - func1->obj[1].data.string = func_desc; - FREE(buf); + request = api_register_missing_function_description(); + assert_false(error.isset); + handle_register(con->id, 123, con->cc.pluginkeystring, request, &error); + assert_true(error.isset); + assert_true(error.type == API_ERROR_TYPE_VALIDATION); + error.isset = false; + api_free_array(request); /* registering w/o function, should not work */ - functions->size = 0; - assert_false(info.api_error.isset); - assert_int_not_equal(0, handle_register(info.con->id, &info.request, info.con->cc.pluginkeystring, &info.api_error)); - assert_true(info.api_error.isset); - assert_true(info.api_error.type == API_ERROR_TYPE_VALIDATION); - info.api_error.isset = false; - functions->size = 1; - - /* registering function with arguments, should work. the arguments - * remain for the following tests. */ - args = &func1->obj[2].data.params; - args->size = 2; - args->obj = CALLOC(args->size, struct message_object); - args->obj[0].type = OBJECT_TYPE_INT; - args->obj[0].data.integer = 5; - args->obj[1].type = OBJECT_TYPE_STR; - args->obj[1].data.string = cstring_copy_string("foobar"); - assert_false(info.api_error.isset); - expect_check(__wrap_crypto_write, &deserialized, validate_register_response, NULL); - assert_int_equal(0, handle_register(info.con->id, &info.request, info.con->cc.pluginkeystring, &info.api_error)); - assert_false(info.api_error.isset); - info.api_error.isset = false; - - /* registering only one function must work */ - functions->size = 1; - assert_false(info.api_error.isset); - expect_check(__wrap_crypto_write, &deserialized, validate_register_response, NULL); - assert_int_equal(0, handle_register(info.con->id, &info.request, info.con->cc.pluginkeystring, &info.api_error)); - assert_false(info.api_error.isset); - info.api_error.isset = false; - functions->size = 2; - - free_params(request->params); + request = api_register_empty_functions(); + assert_false(error.isset); + handle_register(con->id, 123, con->cc.pluginkeystring, request, &error); + assert_true(error.isset); + assert_true(error.type == API_ERROR_TYPE_VALIDATION); + error.isset = false; + api_free_array(request); + connection_teardown(); - FREE(err); - FREE(info.con); + FREE(con); db_close(); } diff --git a/test/functional/dispatch-handle-result.c b/test/functional/dispatch-handle-result.c index 3918a9b..181d4d2 100644 --- a/test/functional/dispatch-handle-result.c +++ b/test/functional/dispatch-handle-result.c @@ -18,155 +18,238 @@ #include "helper-all.h" #include "sb-common.h" -#include "rpc/msgpack/sb-msgpack-rpc.h" #include "rpc/sb-rpc.h" +#include "api/helpers.h" +#include "api/sb-api.h" +#ifdef __linux__ +#include +#endif #include "helper-all.h" #include "helper-unix.h" #include "helper-validate.h" -static struct plugin *prepare_test(connection_request_event_info *info) +static array api_result_valid(struct plugin * plugin) { - struct api_error err = ERROR_INIT; - info->api_error = err; + array meta = ARRAY_DICT_INIT; + ADD(meta, UINTEGER_OBJ(plugin->callid)); - /* create test plugin that is used for the tests */ - struct plugin *plugin = helper_get_example_plugin(); - helper_register_plugin(plugin); + array args = ARRAY_DICT_INIT; + ADD(args, STRING_OBJ(cstring_copy_string(plugin->function->args[0].str))); + ADD(args, STRING_OBJ(cstring_copy_string(plugin->function->args[1].str))); - /* establish fake connection to plugin */ - info->con = CALLOC(1, struct connection); - info->con->closed = true; - connection_hashmap_put(info->con->id, info->con); - strlcpy(info->con->cc.pluginkeystring, plugin->key.str, plugin->key.length+1); - assert_non_null(info->con); + array request = ARRAY_DICT_INIT; + ADD(request, ARRAY_OBJ(meta)); + ADD(request, ARRAY_OBJ(args)); - expect_check(__wrap_crypto_write, &deserialized, validate_run_request, plugin); - expect_check(__wrap_crypto_write, &deserialized, validate_run_response, plugin); + return request; +} + +static array api_result_wrong_args_size_small(struct plugin * plugin) +{ + array meta = ARRAY_DICT_INIT; + ADD(meta, UINTEGER_OBJ(plugin->callid)); + + array request = ARRAY_DICT_INIT; + ADD(request, ARRAY_OBJ(meta)); + + return request; +} + +static array api_result_wrong_args_size_big(struct plugin * plugin) +{ + array meta = ARRAY_DICT_INIT; + ADD(meta, UINTEGER_OBJ(plugin->callid)); + + array args = ARRAY_DICT_INIT; + ADD(args, STRING_OBJ(cstring_copy_string(plugin->function->args[0].str))); + ADD(args, STRING_OBJ(cstring_copy_string(plugin->function->args[1].str))); + + array wrong = ARRAY_DICT_INIT; + + array request = ARRAY_DICT_INIT; + ADD(request, ARRAY_OBJ(meta)); + ADD(request, ARRAY_OBJ(args)); + ADD(request, ARRAY_OBJ(wrong)); + + return request; +} + +static array api_result_wrong_meta_size(struct plugin * plugin) +{ + array meta = ARRAY_DICT_INIT; + ADD(meta, UINTEGER_OBJ(plugin->callid)); + ADD(meta, STRING_OBJ(cstring_copy_string("wrong"))); + + array args = ARRAY_DICT_INIT; + ADD(args, STRING_OBJ(cstring_copy_string(plugin->function->args[0].str))); + ADD(args, STRING_OBJ(cstring_copy_string(plugin->function->args[1].str))); + + array request = ARRAY_DICT_INIT; + ADD(request, ARRAY_OBJ(meta)); + ADD(request, ARRAY_OBJ(args)); + + return request; +} + +static array api_result_wrong_meta_type(struct plugin * plugin) +{ + array args = ARRAY_DICT_INIT; + ADD(args, STRING_OBJ(cstring_copy_string(plugin->function->args[0].str))); + ADD(args, STRING_OBJ(cstring_copy_string(plugin->function->args[1].str))); + + array request = ARRAY_DICT_INIT; + ADD(request, STRING_OBJ(cstring_copy_string("wrong"))); + ADD(request, ARRAY_OBJ(args)); + + return request; +} + +static array api_result_wrong_meta_callid_type(struct plugin * plugin) +{ + array meta = ARRAY_DICT_INIT; + ADD(meta, STRING_OBJ(cstring_copy_string("wrong"))); - helper_build_run_request(&info->request, plugin - ,OBJECT_TYPE_ARRAY /* meta array type */ - ,2 /* meta size */ - ,OBJECT_TYPE_STR /* target plugin key */ - ,OBJECT_TYPE_NIL /* call id type */ - ,OBJECT_TYPE_STR /* function name */ - ,OBJECT_TYPE_ARRAY /* arguments */ - ); + array args = ARRAY_DICT_INIT; + ADD(args, STRING_OBJ(cstring_copy_string(plugin->function->args[0].str))); + ADD(args, STRING_OBJ(cstring_copy_string(plugin->function->args[1].str))); - assert_int_equal(0, handle_run(info->con->id, &info->request, info->con->cc.pluginkeystring, &info->api_error)); - free_params(info->request.params); + array request = ARRAY_DICT_INIT; + ADD(request, ARRAY_OBJ(meta)); + ADD(request, ARRAY_OBJ(args)); - return plugin; + return request; } + void functional_dispatch_handle_result(UNUSED(void **state)) { - connection_request_event_info info; - struct plugin *plugin; + struct api_error error = ERROR_INIT; + array request = ARRAY_DICT_INIT; + struct connection *con; - plugin = prepare_test(&info); + /* create test plugin that is used for the tests */ + struct plugin *plugin = helper_get_example_plugin(); - expect_check(__wrap_crypto_write, &deserialized, validate_result_request, NULL); - expect_check(__wrap_crypto_write, &deserialized, validate_result_response, NULL); + con = CALLOC(1, struct connection); + con->closed = true; + con->id = (uint64_t) randommod(281474976710656LL); + con->msgid = 4321; - /* - * The following asserts verifies a legitim run call. In detail, it - * verifies, that the forwarded run request by the server is of proper - * format. - * */ - helper_build_result_request(&info.request, plugin - ,OBJECT_TYPE_ARRAY /* meta array type */ - ,1 /* meta array size */ - ,OBJECT_TYPE_UINT /* call id type */ - ,OBJECT_TYPE_ARRAY /* arguments */ - ); - - assert_int_equal(0, handle_result(info.con->id, &info.request, info.con->cc.pluginkeystring, &info.api_error)); + assert_non_null(con); - /* - * The following asserts verify, that the handle_result method cancels - * as soon as illegitim result calls are processed. A API_ERROR must be - * set in order inform the caller later on. - */ + strlcpy(con->cc.pluginkeystring, plugin->key.str, plugin->key.length+1); - /* size of payload too small */ - info.request.params.size = 1; + array registermeta = ARRAY_DICT_INIT; + ADD(registermeta, STRING_OBJ(cstring_copy_string(plugin->name.str))); + ADD(registermeta, STRING_OBJ(cstring_copy_string(plugin->description.str))); + ADD(registermeta, STRING_OBJ(cstring_copy_string(plugin->author.str))); + ADD(registermeta, STRING_OBJ(cstring_copy_string(plugin->license.str))); - assert_int_not_equal(0, handle_result(info.con->id, &info.request, info.con->cc.pluginkeystring, &info.api_error)); - assert_true(info.api_error.isset); - assert_true(info.api_error.type == API_ERROR_TYPE_VALIDATION); - info.api_error.isset = false; + array registerarguments = ARRAY_DICT_INIT; + ADD(registerarguments, STRING_OBJ(cstring_copy_string(plugin->function->args[0].str))); + ADD(registerarguments, STRING_OBJ(cstring_copy_string(plugin->function->args[1].str))); - /* size of payload too big */ - info.request.params.size = 3; + array registerfunc1 = ARRAY_DICT_INIT; + ADD(registerfunc1, STRING_OBJ(cstring_copy_string(plugin->function->name.str))); + ADD(registerfunc1, STRING_OBJ(cstring_copy_string(plugin->function->description.str))); + ADD(registerfunc1, ARRAY_OBJ(registerarguments)); - assert_int_not_equal(0, handle_result(info.con->id, &info.request, info.con->cc.pluginkeystring, &info.api_error)); - assert_true(info.api_error.isset); - assert_true(info.api_error.type == API_ERROR_TYPE_VALIDATION); - info.api_error.isset = false; + array registerfunctions = ARRAY_DICT_INIT; + ADD(registerfunctions, ARRAY_OBJ(registerfunc1)); - info.request.params.size = 2; + array registerrequest = ARRAY_DICT_INIT; + ADD(registerrequest, ARRAY_OBJ(registermeta)); + ADD(registerrequest, ARRAY_OBJ(registerfunctions)); - /* wrong meta size */ - helper_request_set_meta_size(&info.request, - OBJECT_TYPE_ARRAY, 2); + connect_to_db(); + assert_int_equal(0, connection_init()); - assert_int_not_equal(0, handle_result(info.con->id, &info.request, info.con->cc.pluginkeystring, &info.api_error)); - assert_true(info.api_error.isset); - assert_true(info.api_error.type == API_ERROR_TYPE_VALIDATION); - info.api_error.isset = false; + error.isset = false; - helper_request_set_meta_size(&info.request, - OBJECT_TYPE_ARRAY, 1); + con->refcount++; - /* wrong meta type */ - helper_request_set_meta_size(&info.request, - OBJECT_TYPE_STR, 1); + connection_hashmap_put(con->id, con); + pluginkeys_hashmap_put(con->cc.pluginkeystring, con->id); - assert_int_not_equal(0, handle_result(info.con->id, &info.request, info.con->cc.pluginkeystring, &info.api_error)); - assert_true(info.api_error.isset); - assert_true(info.api_error.type == API_ERROR_TYPE_VALIDATION); - info.api_error.isset = false; + handle_register(con->id, 123, con->cc.pluginkeystring, registerrequest, + &error); + assert_false(error.isset); + api_free_array(registerrequest); - helper_request_set_meta_size(&info.request, - OBJECT_TYPE_ARRAY, 1); + expect_check(__wrap_crypto_write, &deserialized, validate_run_request, plugin); - /* wrong callid type */ - helper_request_set_callid(&info.request, OBJECT_TYPE_STR); + // RUN API CALL + array runmeta = ARRAY_DICT_INIT; + ADD(runmeta, STRING_OBJ(cstring_copy_string(plugin->key.str))); + ADD(runmeta, OBJECT_OBJ((object) OBJECT_INIT)); - assert_int_not_equal(0, handle_result(info.con->id, &info.request, info.con->cc.pluginkeystring, &info.api_error)); - assert_true(info.api_error.isset); - assert_true(info.api_error.type == API_ERROR_TYPE_VALIDATION); - info.api_error.isset = false; + array runargs = ARRAY_DICT_INIT; + ADD(runargs, STRING_OBJ(cstring_copy_string(plugin->function->args[0].str))); + ADD(runargs, STRING_OBJ(cstring_copy_string(plugin->function->args[1].str))); - helper_request_set_callid(&info.request, OBJECT_TYPE_UINT); + array runrequest = ARRAY_DICT_INIT; + ADD(runrequest, ARRAY_OBJ(runmeta)); + ADD(runrequest, STRING_OBJ(cstring_copy_string(plugin->function->name.str))); + ADD(runrequest, ARRAY_OBJ(runargs)); - /* wrong callid */ - info.request.params.obj[0].data.params.obj[0].data.uinteger = 0; + handle_run(con->id, 1234, con->cc.pluginkeystring, runrequest, &error); + api_free_array(runrequest); + + expect_check(__wrap_crypto_write, &deserialized, validate_result_request, NULL); - assert_int_not_equal(0, handle_result(info.con->id, &info.request, info.con->cc.pluginkeystring, &info.api_error)); - assert_true(info.api_error.isset); - assert_true(info.api_error.type == API_ERROR_TYPE_VALIDATION); - info.api_error.isset = false; + request = api_result_valid(plugin); + handle_result(con->id, 1234, con->cc.pluginkeystring, request, &error); + assert_false(error.isset); + api_free_array(request); + /* + * The following asserts verify, that the handle_result method cancels + * as soon as illegitim result calls are processed. A API_ERROR must be + * set in order inform the caller later on. + */ - info.request.params.obj[0].data.params.obj[0].data.uinteger = plugin->callid; + /* size of payload too small */ + request = api_result_wrong_args_size_small(plugin); + handle_result(con->id, 1234, con->cc.pluginkeystring, request, &error); + assert_true(error.isset); + assert_true(error.type == API_ERROR_TYPE_VALIDATION); + error.isset = false; + api_free_array(request); - /* wrong argument type */ - helper_request_set_args_size(&info.request, - OBJECT_TYPE_STR, 2); + /* size of payload too big */ + request = api_result_wrong_args_size_big(plugin); + handle_result(con->id, 1234, con->cc.pluginkeystring, request, &error); + assert_true(error.isset); + assert_true(error.type == API_ERROR_TYPE_VALIDATION); + error.isset = false; + api_free_array(request); - assert_int_not_equal(0, handle_result(info.con->id, &info.request, info.con->cc.pluginkeystring, &info.api_error)); - assert_true(info.api_error.isset); - assert_true(info.api_error.type == API_ERROR_TYPE_VALIDATION); - info.api_error.isset = false; + /* wrong meta size */ + request = api_result_wrong_meta_size(plugin); + handle_result(con->id, 1234, con->cc.pluginkeystring, request, &error); + assert_true(error.isset); + assert_true(error.type == API_ERROR_TYPE_VALIDATION); + error.isset = false; + api_free_array(request); - helper_request_set_args_size(&info.request, - OBJECT_TYPE_ARRAY, 2); + /* wrong meta type */ + request = api_result_wrong_meta_type(plugin); + handle_result(con->id, 1234, con->cc.pluginkeystring, request, &error); + assert_true(error.isset); + assert_true(error.type == API_ERROR_TYPE_VALIDATION); + error.isset = false; + api_free_array(request); + /* wrong callid type */ + request = api_result_wrong_meta_callid_type(plugin); + handle_result(con->id, 1234, con->cc.pluginkeystring, request, &error); + assert_true(error.isset); + assert_true(error.type == API_ERROR_TYPE_VALIDATION); + error.isset = false; + api_free_array(request); - free_params(info.request.params); helper_free_plugin(plugin); connection_teardown(); - FREE(info.con); + FREE(con); db_close(); } diff --git a/test/functional/dispatch-handle-run.c b/test/functional/dispatch-handle-run.c index 48f1d11..c3330a0 100644 --- a/test/functional/dispatch-handle-run.c +++ b/test/functional/dispatch-handle-run.c @@ -17,132 +17,205 @@ #include #include "sb-common.h" -#include "rpc/msgpack/sb-msgpack-rpc.h" #include "rpc/sb-rpc.h" +#include "api/helpers.h" +#include "api/sb-api.h" +#ifdef __linux__ +#include +#endif #include "helper-unix.h" #include "helper-all.h" #include "helper-validate.h" -static struct plugin *prepare_test(connection_request_event_info *info) +static array api_run_valid(struct plugin *plugin) { - struct api_error err = ERROR_INIT; - info->api_error = err; + array meta = ARRAY_DICT_INIT; + ADD(meta, STRING_OBJ(cstring_copy_string(plugin->key.str))); + ADD(meta, OBJECT_OBJ((object) OBJECT_INIT)); - /* create test plugin that is used for the tests */ - struct plugin *plugin = helper_get_example_plugin(); - helper_register_plugin(plugin); + array args = ARRAY_DICT_INIT; + ADD(args, STRING_OBJ(cstring_copy_string(plugin->function->args[0].str))); + ADD(args, STRING_OBJ(cstring_copy_string(plugin->function->args[1].str))); + + array request = ARRAY_DICT_INIT; + ADD(request, ARRAY_OBJ(meta)); + ADD(request, STRING_OBJ(cstring_copy_string(plugin->function->name.str))); + ADD(request, ARRAY_OBJ(args)); + + return request; +} + +static array api_run_call_not_registered_function(struct plugin *plugin) +{ + array meta = ARRAY_DICT_INIT; + ADD(meta, STRING_OBJ(cstring_copy_string(plugin->key.str))); + ADD(meta, OBJECT_OBJ((object) OBJECT_INIT)); + + array args = ARRAY_DICT_INIT; + ADD(args, STRING_OBJ(cstring_copy_string(plugin->function->args[0].str))); + ADD(args, STRING_OBJ(cstring_copy_string(plugin->function->args[1].str))); + + array request = ARRAY_DICT_INIT; + ADD(request, ARRAY_OBJ(meta)); + ADD(request, STRING_OBJ(cstring_copy_string("wrong"))); + ADD(request, ARRAY_OBJ(args)); + + return request; +} + +static array api_run_wrong_meta_type(struct plugin *plugin) +{ + array args = ARRAY_DICT_INIT; + ADD(args, STRING_OBJ(cstring_copy_string(plugin->function->args[0].str))); + ADD(args, STRING_OBJ(cstring_copy_string(plugin->function->args[1].str))); + + array request = ARRAY_DICT_INIT; + ADD(request, STRING_OBJ(cstring_copy_string("wrong"))); + ADD(request, STRING_OBJ(cstring_copy_string(plugin->function->name.str))); + ADD(request, ARRAY_OBJ(args)); + + return request; +} + +static array api_run_wrong_meta_size(struct plugin *plugin) +{ + array meta = ARRAY_DICT_INIT; + ADD(meta, STRING_OBJ(cstring_copy_string(plugin->key.str))); + + array args = ARRAY_DICT_INIT; + ADD(args, STRING_OBJ(cstring_copy_string(plugin->function->args[0].str))); + ADD(args, STRING_OBJ(cstring_copy_string(plugin->function->args[1].str))); + + array request = ARRAY_DICT_INIT; + ADD(request, ARRAY_OBJ(meta)); + ADD(request, STRING_OBJ(cstring_copy_string(plugin->function->name.str))); + ADD(request, ARRAY_OBJ(args)); + + return request; +} + +static array api_run_wrong_pluginkey_type(struct plugin *plugin) +{ + array meta = ARRAY_DICT_INIT; + ADD(meta, OBJECT_OBJ((object) OBJECT_INIT)); + ADD(meta, OBJECT_OBJ((object) OBJECT_INIT)); + + array args = ARRAY_DICT_INIT; + ADD(args, STRING_OBJ(cstring_copy_string(plugin->function->args[0].str))); + ADD(args, STRING_OBJ(cstring_copy_string(plugin->function->args[1].str))); - /* establish fake connection to plugin */ - info->con = CALLOC(1, struct connection); - info->con->closed = true; - info->con->id = 12345; - connection_hashmap_put(info->con->id, info->con); - strlcpy(info->con->cc.pluginkeystring, plugin->key.str, plugin->key.length+1); - assert_non_null(info->con); + array request = ARRAY_DICT_INIT; + ADD(request, ARRAY_OBJ(meta)); + ADD(request, STRING_OBJ(cstring_copy_string(plugin->function->name.str))); + ADD(request, ARRAY_OBJ(args)); - return plugin; + return request; } void functional_dispatch_handle_run(UNUSED(void **state)) { - connection_request_event_info info; - struct plugin *plugin; + struct plugin *plugin = helper_get_example_plugin(); + struct connection *con; + struct api_error error = ERROR_INIT; + array request; - plugin = prepare_test(&info); + con = CALLOC(1, struct connection); + con->closed = true; + con->id = (uint64_t) randommod(281474976710656LL); + con->msgid = 4321; - expect_check(__wrap_crypto_write, &deserialized, validate_run_request, plugin); - expect_check(__wrap_crypto_write, &deserialized, validate_run_response, plugin); + assert_non_null(con); - /* - * The following asserts verifies a legitim run call. In detail, it - * verifies, that the forwarded run request by the server is of proper - * format. - * */ - helper_build_run_request(&info.request, plugin - ,OBJECT_TYPE_ARRAY /* meta array type */ - ,2 /* meta size */ - ,OBJECT_TYPE_STR /* target plugin key */ - ,OBJECT_TYPE_NIL /* call id type */ - ,OBJECT_TYPE_STR /* function name */ - ,OBJECT_TYPE_ARRAY /* arguments */ - ); - - //nfo.con->id, &info.request, info.con->cc.pluginkeystring, &info.api_error - - assert_int_equal(0, handle_run(info.con->id, &info.request, info.con->cc.pluginkeystring, &info.api_error)); - assert_false(info.api_error.isset); + strlcpy(con->cc.pluginkeystring, plugin->key.str, plugin->key.length+1); - /* - * The following asserts verify, that the handle_run method cancels - * as soon as illegitim run calls are processed. A API_ERROR must be - * set in order inform the caller later on. - */ + array registermeta = ARRAY_DICT_INIT; + ADD(registermeta, STRING_OBJ(cstring_copy_string(plugin->name.str))); + ADD(registermeta, STRING_OBJ(cstring_copy_string(plugin->description.str))); + ADD(registermeta, STRING_OBJ(cstring_copy_string(plugin->author.str))); + ADD(registermeta, STRING_OBJ(cstring_copy_string(plugin->license.str))); - /* calling not registered function should fail */ - helper_request_set_function_name(&info.request, OBJECT_TYPE_STR, - "invalid funcion name"); + array registerarguments = ARRAY_DICT_INIT; + ADD(registerarguments, STRING_OBJ(cstring_copy_string(plugin->function->args[0].str))); + ADD(registerarguments, STRING_OBJ(cstring_copy_string(plugin->function->args[1].str))); - assert_int_not_equal(0, handle_run(info.con->id, &info.request, info.con->cc.pluginkeystring, &info.api_error)); - assert_true(info.api_error.isset); - assert_true(info.api_error.type == API_ERROR_TYPE_VALIDATION); - info.api_error.isset = false; + array registerfunc1 = ARRAY_DICT_INIT; + ADD(registerfunc1, STRING_OBJ(cstring_copy_string(plugin->function->name.str))); + ADD(registerfunc1, STRING_OBJ(cstring_copy_string(plugin->function->description.str))); + ADD(registerfunc1, ARRAY_OBJ(registerarguments)); - /* reset to correct request */ - helper_request_set_function_name(&info.request, OBJECT_TYPE_STR, - plugin->function->name.str); + array registerfunctions = ARRAY_DICT_INIT; + ADD(registerfunctions, ARRAY_OBJ(registerfunc1)); - /* meta object has wrong type */ - helper_request_set_meta_size(&info.request, OBJECT_TYPE_STR, 2); + array registerrequest = ARRAY_DICT_INIT; + ADD(registerrequest, ARRAY_OBJ(registermeta)); + ADD(registerrequest, ARRAY_OBJ(registerfunctions)); - assert_false(info.api_error.isset); - assert_int_not_equal(0, handle_run(info.con->id, &info.request, info.con->cc.pluginkeystring, &info.api_error)); - assert_true(info.api_error.isset); - assert_true(info.api_error.type == API_ERROR_TYPE_VALIDATION); - info.api_error.isset = false; + connect_to_db(); + assert_int_equal(0, connection_init()); - /* reset to correct request */ - helper_request_set_meta_size(&info.request, OBJECT_TYPE_ARRAY, 2); + error.isset = false; - /* meta has wrong size */ - helper_request_set_meta_size(&info.request, OBJECT_TYPE_ARRAY, 3); + con->refcount++; - assert_false(info.api_error.isset); - assert_int_not_equal(0, handle_run(info.con->id, &info.request, info.con->cc.pluginkeystring, &info.api_error)); - assert_true(info.api_error.isset); - assert_true(info.api_error.type == API_ERROR_TYPE_VALIDATION); - info.api_error.isset = false; + connection_hashmap_put(con->id, con); + pluginkeys_hashmap_put(con->cc.pluginkeystring, con->id); - /* reset to correct request */ - helper_request_set_meta_size(&info.request, OBJECT_TYPE_ARRAY, 2); + handle_register(con->id, 123, con->cc.pluginkeystring, registerrequest, + &error); + assert_false(error.isset); + api_free_array(registerrequest); - /* target plugin key has wrong type */ - helper_request_set_pluginkey_type(&info.request, OBJECT_TYPE_ARRAY, plugin->key.str); + expect_check(__wrap_crypto_write, &deserialized, validate_run_request, plugin); - assert_false(info.api_error.isset); - assert_int_not_equal(0, handle_run(info.con->id, &info.request, info.con->cc.pluginkeystring, &info.api_error)); - assert_true(info.api_error.isset); - assert_true(info.api_error.type == API_ERROR_TYPE_VALIDATION); - info.api_error.isset = false; + request = api_run_valid(plugin); + handle_run(con->id, 123, con->cc.pluginkeystring, request, &error); + assert_false(error.isset); + api_free_array(request); - /* reset to correct request */ - helper_request_set_pluginkey_type(&info.request, OBJECT_TYPE_STR, plugin->key.str); - array *meta = &info.request.params.obj[0].data.params; - free_string(meta->obj[0].data.string); + /* + * The following asserts verify, that the handle_run method cancels + * as soon as illegitim run calls are processed. A API_ERROR must be + * set in order inform the caller later on. + */ - /* call_id has wrong type */ - helper_request_set_callid(&info.request, OBJECT_TYPE_BIN); + /* calling not registered function should fail */ + request = api_run_call_not_registered_function(plugin); + handle_run(con->id, 123, con->cc.pluginkeystring, request, &error); + assert_true(error.isset); + assert_true(error.type == API_ERROR_TYPE_VALIDATION); + error.isset = false; + api_free_array(request); - assert_false(info.api_error.isset); - assert_int_not_equal(0, handle_run(info.con->id, &info.request, info.con->cc.pluginkeystring, &info.api_error)); - assert_true(info.api_error.isset); - assert_true(info.api_error.type == API_ERROR_TYPE_VALIDATION); + /* meta object has wrong type */ + request = api_run_wrong_meta_type(plugin); + assert_false(error.isset); + handle_run(con->id, 123, con->cc.pluginkeystring, request, &error); + assert_true(error.isset); + assert_true(error.type == API_ERROR_TYPE_VALIDATION); + error.isset = false; + api_free_array(request); - /* reset to correct request */ - helper_request_set_callid(&info.request, OBJECT_TYPE_NIL); + /* meta has wrong size */ + request = api_run_wrong_meta_size(plugin); + assert_false(error.isset); + handle_run(con->id, 123, con->cc.pluginkeystring, request, &error); + assert_true(error.isset); + assert_true(error.type == API_ERROR_TYPE_VALIDATION); + error.isset = false; + api_free_array(request); + + /* target plugin key has wrong type */ + request = api_run_wrong_pluginkey_type(plugin); + assert_false(error.isset); + handle_run(con->id, 123, con->cc.pluginkeystring, request, &error); + assert_true(error.isset); + assert_true(error.type == API_ERROR_TYPE_VALIDATION); + error.isset = false; + api_free_array(request); - free_params(info.request.params); helper_free_plugin(plugin); connection_teardown(); + FREE(con); db_close(); } diff --git a/test/helper-all.c b/test/helper-all.c index ac3152c..850d7d9 100644 --- a/test/helper-all.c +++ b/test/helper-all.c @@ -18,6 +18,8 @@ #include "sb-common.h" #include "rpc/db/sb-db.h" +#include "api/helpers.h" +#include "api/sb-api.h" #include "helper-unix.h" #include "helper-all.h" @@ -76,26 +78,26 @@ struct plugin *helper_get_example_plugin(void) LOG_ERROR("[test] Failed to alloc mem for example plugin.\n"); p->key = (string) {.str = "0123456789ABCDEF", - .length = sizeof("0123456789ABCDEF") - 1}; + .length = sizeof("0123456789ABCDEF") - 1}; p->name = (string) {.str = "plugin name", - .length = sizeof("plugin name") - 1}; + .length = sizeof("plugin name") - 1}; p->description = (string) {.str = "plugin desc", - .length = sizeof("plugin desc") - 1}; + .length = sizeof("plugin desc") - 1}; p->license = (string) {.str = "plugin license", - .length = sizeof("plugin license") - 1}; + .length = sizeof("plugin license") - 1}; p->author = (string) {.str = "plugin author", - .length = sizeof("plugin author") - 1}; + .length = sizeof("plugin author") - 1}; p->callid = 0; f->name = (string) {.str = "function name", - .length = sizeof("function name") - 1}; + .length = sizeof("function name") - 1}; f->description = (string) {.str = "function desc", - .length = sizeof("function desc") - 1}; + .length = sizeof("function desc") - 1}; f->args[0] = (string) {.str = "arg 1", - .length = sizeof("arg 1") - 1}; + .length = sizeof("arg 1") - 1}; f->args[1] = (string) {.str = "arg 2", - .length = sizeof("arg 2") - 1}; + .length = sizeof("arg 2") - 1}; p->function = f; return p; @@ -106,221 +108,3 @@ void helper_free_plugin(struct plugin *p) FREE(p->function); FREE(p); } - - -/* Builds a register call and executes handle_register in order - * to register the plugin. */ -void helper_register_plugin(struct plugin *p) -{ - connection_request_event_info info; - struct message_request *register_request; - array *meta, *functions, *func1, *args; - struct api_error err = ERROR_INIT; - - info.request.msgid = 1; - register_request = &info.request; - assert_non_null(register_request); - - info.api_error = err; - - info.con = CALLOC(1, struct connection); - info.con->closed = true; - info.con->msgid = 1; - info.con->id = (uint64_t) randommod(281474976710656LL); - - assert_non_null(info.con); - - strlcpy(info.con->cc.pluginkeystring, p->key.str, p->key.length+1); - - connect_to_db(); - assert_int_equal(0, connection_init()); - - /* first level arrays: - * - * [meta] args->obj[0] - * [functions] args->obj[1] - */ - register_request->params.size = 2; - register_request->params.obj = CALLOC(2, struct message_object); - register_request->params.obj[0].type = OBJECT_TYPE_ARRAY; - register_request->params.obj[1].type = OBJECT_TYPE_ARRAY; - - /* meta array: - * - * [name] - * [desciption] - * [author] - * [license] - */ - meta = ®ister_request->params.obj[0].data.params; - meta->size = 4; - meta->obj = CALLOC(meta->size, struct message_object); - meta->obj[0].type = OBJECT_TYPE_STR; - meta->obj[0].data.string = cstring_copy_string(p->name.str); - meta->obj[1].type = OBJECT_TYPE_STR; - meta->obj[1].data.string = cstring_copy_string(p->description.str); - meta->obj[2].type = OBJECT_TYPE_STR; - meta->obj[2].data.string = cstring_copy_string(p->author.str); - meta->obj[3].type = OBJECT_TYPE_STR; - meta->obj[3].data.string = cstring_copy_string(p->license.str); - - functions = ®ister_request->params.obj[1].data.params; - functions->size = 1; - functions->obj = CALLOC(functions->size, struct message_object); - functions->obj[0].type = OBJECT_TYPE_ARRAY; - - func1 = &functions->obj[0].data.params; - func1->size = 3; - func1->obj = CALLOC(3, struct message_object); - func1->obj[0].type = OBJECT_TYPE_STR; - func1->obj[0].data.string = cstring_copy_string(p->function->name.str); - func1->obj[1].type = OBJECT_TYPE_STR; - func1->obj[1].data.string = cstring_copy_string(p->function->description.str); - func1->obj[2].type = OBJECT_TYPE_ARRAY; - - /* function arguments */ - args = &func1->obj[2].data.params; - args->size = 2; - args->obj = CALLOC(2, struct message_object); - args->obj[0].type = OBJECT_TYPE_STR; - args->obj[0].data.string = cstring_copy_string(p->function->args[0].str); - args->obj[1].type = OBJECT_TYPE_STR; - args->obj[1].data.string = cstring_copy_string(p->function->args[1].str); - - /* before running function, it must be registered successfully */ - info.api_error.isset = false; - expect_check(__wrap_crypto_write, &deserialized, - validate_register_response, - NULL); - - info.con->refcount++; - - connection_hashmap_put(info.con->id, info.con); - pluginkeys_hashmap_put(info.con->cc.pluginkeystring, info.con->id); - - assert_int_equal(0, handle_register(info.con->id, &info.request, - info.con->cc.pluginkeystring, &info.api_error)); - assert_false(info.api_error.isset); - - //hashmap_put(uint64_t, ptr_t)(connections, info.con->id, info.con); - free_params(register_request->params); - //FREE(args->obj); - //FREE(func1->obj); - //FREE(functions->obj); - //FREE(meta->obj); - //FREE(register_request->params.obj); -} - -/* Builds a run request */ -void helper_build_run_request(struct message_request *rr, - struct plugin *plugin, - message_object_type metaarraytype, - size_t metasize, - message_object_type metaclientidtype, - message_object_type metacallidtype, - message_object_type functionnametype, - message_object_type argstype -) -{ - array argsarray = ARRAY_INIT; - array *meta; - - rr->msgid = 1; - - rr->params.size = 3; - rr->params.obj = CALLOC(rr->params.size, struct message_object); - rr->params.obj[0].type = metaarraytype; - - meta = &rr->params.obj[0].data.params; - meta->size = metasize; - meta->obj = CALLOC(meta->size, struct message_object); - meta->obj[0].type = metaclientidtype; - meta->obj[0].data.string = cstring_copy_string(plugin->key.str); - meta->obj[1].type = metacallidtype; - - rr->params.obj[1].type = functionnametype; - rr->params.obj[1].data.string = cstring_copy_string(plugin->function->name.str); - - argsarray.size = 2; - argsarray.obj = CALLOC(argsarray.size, struct message_object); - argsarray.obj[0].type = OBJECT_TYPE_STR; /* first argument */ - argsarray.obj[0].data.string = cstring_copy_string(plugin->function->args[0].str); - argsarray.obj[1].type = OBJECT_TYPE_STR; /* second argument */ - argsarray.obj[1].data.string = cstring_copy_string(plugin->function->args[1].str); - - rr->params.obj[2].type = argstype; - rr->params.obj[2].data.params = argsarray; -} - - -void helper_build_result_request(struct message_request *rr, - struct plugin *plugin, - message_object_type metaarraytype, - size_t metasize, - message_object_type metacallidtype, - message_object_type argstype) -{ - array argsarray = ARRAY_INIT; - array *meta; - - rr->msgid = 1; - - rr->params.size = 2; - rr->params.obj = CALLOC(rr->params.size, struct message_object); - rr->params.obj[0].type = metaarraytype; - meta = &rr->params.obj[0].data.params; - meta->size = metasize; - meta->obj = CALLOC(meta->size, struct message_object); - meta->obj[0].type = metacallidtype; - meta->obj[0].data.uinteger = plugin->callid; - - argsarray.size = 2; - argsarray.obj = CALLOC(argsarray.size, struct message_object); - argsarray.obj[0].type = OBJECT_TYPE_STR; /* first argument */ - argsarray.obj[0].data.string = cstring_copy_string(plugin->function->args[0].str); - argsarray.obj[1].type = OBJECT_TYPE_STR; /* second argument */ - argsarray.obj[1].data.string = cstring_copy_string(plugin->function->args[1].str); - - rr->params.obj[1].type = argstype; - rr->params.obj[1].data.params = argsarray; -} - -void helper_request_set_callid(struct message_request *rr, - message_object_type callidtype) -{ - array *meta = &rr->params.obj[0].data.params; - - meta->obj[0].type = callidtype; -} - -void helper_request_set_meta_size(struct message_request *rr, - message_object_type metatype, uint64_t metasize) -{ - rr->params.obj[0].type = metatype; - rr->params.obj[0].data.params.size = metasize; -} - -void helper_request_set_args_size(struct message_request *rr, - message_object_type argstype, uint64_t argssize) -{ - rr->params.obj[1].type = argstype; - rr->params.obj[1].data.params.size = argssize; -} - -void helper_request_set_function_name(struct message_request *rr, - message_object_type nametype, char *name) -{ - free_string(rr->params.obj[1].data.string); - rr->params.obj[1].type = nametype; - rr->params.obj[1].data.string = cstring_copy_string(name); -} - -void helper_request_set_pluginkey_type(struct message_request *rr, - message_object_type pluginkeytype, char *pluginkey) -{ - array *meta = &rr->params.obj[0].data.params; - - free_string(meta->obj[0].data.string); - meta->obj[0].data.string = cstring_copy_string(pluginkey); - meta->obj[0].type = pluginkeytype; -} diff --git a/test/helper-all.h b/test/helper-all.h index 9974492..1931b9f 100644 --- a/test/helper-all.h +++ b/test/helper-all.h @@ -44,33 +44,3 @@ void register_test_function(void); struct plugin *helper_get_example_plugin(void); void helper_free_plugin(struct plugin *p); void helper_register_plugin(struct plugin *p); - -/* some helper functions to build and manipulate requests */ -void helper_request_set_args_size(struct message_request *rr, - message_object_type argstype, uint64_t argssize); -void helper_request_set_meta_size(struct message_request *rr, - message_object_type metatype, uint64_t metasize); -void helper_request_set_callid(struct message_request *rr, - message_object_type callidtype); -void helper_request_set_pluginkey_type(struct message_request *rr, - message_object_type pluginkeytype, char *pluginkey); -void helper_request_set_function_name(struct message_request *rr, - message_object_type nametype, char *name); - - -void helper_build_result_request(struct message_request *rr, - struct plugin *plugin, - message_object_type metaarraytype, - size_t metasize, - message_object_type metacallidtype, - message_object_type argstype); -void helper_build_run_request(struct message_request *rr, - struct plugin *plugin, - message_object_type metaarraytype, - size_t metasize, - message_object_type metaclientidtype, - message_object_type metacallidtype, - message_object_type functionnametype, - message_object_type argstype); - - diff --git a/test/helper-validate.c b/test/helper-validate.c index aac08e5..aa5a189 100644 --- a/test/helper-validate.c +++ b/test/helper-validate.c @@ -15,244 +15,130 @@ */ #include "rpc/db/sb-db.h" -#include "rpc/msgpack/sb-msgpack-rpc.h" +#include "api/helpers.h" +#include "rpc/msgpack/helpers.h" #include "helper-unix.h" #include "helper-all.h" -int validate_register_response(const unsigned long data1, - UNUSED(const unsigned long data2)) -{ - struct msgpack_object *deserialized = (struct msgpack_object *) data1; - struct message_object request; - array params; - - wrap_crypto_write = true; - - assert_int_equal(0, unpack_params(deserialized, ¶ms)); - - /* msgpack request needs to be 1 */ - assert_true(params.obj[0].type == OBJECT_TYPE_UINT); - assert_int_equal(1, params.obj[0].data.uinteger); - - /* msg id which is random */ - assert_true(params.obj[1].type == OBJECT_TYPE_UINT); - - /* next field is NIL */ - assert_true(params.obj[2].type == OBJECT_TYPE_NIL); - - /* followed by an empty array */ - request = params.obj[3]; - assert_true(request.type == OBJECT_TYPE_ARRAY); - assert_int_equal(0, request.data.params.size); - - free_params(params); - - return (1); -} int validate_run_request(const unsigned long data1, UNUSED(const unsigned long data2)) { struct msgpack_object *deserialized = (struct msgpack_object *) data1; struct plugin *p = (struct plugin *) data2; - struct message_object meta, request, func, args; - array params; - assert_int_equal(0, unpack_params(deserialized, ¶ms)); + array message; + object request, meta, func, args; + + msgpack_rpc_to_array(deserialized, &message); /* msgpack request needs to be 0 */ - assert_true(params.obj[0].type == OBJECT_TYPE_UINT); - assert_int_equal(0, params.obj[0].data.uinteger); + assert_true(message.items[0].type == OBJECT_TYPE_UINT); + assert_int_equal(0, message.items[0].data.uinteger); /* msg id which is random */ - assert_true(params.obj[1].type == OBJECT_TYPE_UINT); + assert_true(message.items[1].type == OBJECT_TYPE_UINT); /* run call */ - assert_true(params.obj[2].type == OBJECT_TYPE_STR); - assert_string_equal(params.obj[2].data.string.str, "run"); + assert_true(message.items[2].type == OBJECT_TYPE_STR); + assert_string_equal(message.items[2].data.string.str, "run"); /* first level arrays: * * [meta] args->obj[0] * [functions] args->obj[1] */ - request = params.obj[3]; + request = message.items[3]; assert_true(request.type == OBJECT_TYPE_ARRAY); - assert_int_equal(3, request.data.params.size); + assert_int_equal(3, request.data.array.size); - meta = request.data.params.obj[0]; + meta = request.data.array.items[0]; assert_true(meta.type == OBJECT_TYPE_ARRAY); - assert_int_equal(2, meta.data.params.size); + assert_int_equal(2, meta.data.array.size); /* client2 id should be nil */ - assert_true(meta.data.params.obj[0].type == OBJECT_TYPE_NIL); + assert_true(meta.data.array.items[0].type == OBJECT_TYPE_NIL); /* verify that the server sent a proper callid */ - assert_true(meta.data.params.obj[1].type == OBJECT_TYPE_UINT); + assert_true(meta.data.array.items[1].type == OBJECT_TYPE_UINT); /* since the callid must be forwarded to the client1, the original * sender of the rpc call, we need to push the callid on the cmocka test * stack. this allows verifying of it later on */ - uint64_t callid = meta.data.params.obj[1].data.uinteger; + uint64_t callid = meta.data.array.items[1].data.uinteger; will_return(__wrap_loop_wait_for_response, OBJECT_TYPE_UINT); will_return(__wrap_loop_wait_for_response, callid); - expect_value(validate_run_response, response.data.params.obj[0].data.uinteger, callid); + p->callid = callid; /* the function to call on client2 side */ - func = request.data.params.obj[1]; + func = request.data.array.items[1]; assert_true(func.type == OBJECT_TYPE_STR); assert_string_equal(func.data.string.str, p->function->name.str); /* the function arguments to pass to client2 side */ - assert_true(request.data.params.obj[2].type == OBJECT_TYPE_ARRAY); - assert_int_equal(2, request.data.params.obj[2].data.params.size); + assert_true(request.data.array.items[2].type == OBJECT_TYPE_ARRAY); + assert_int_equal(2, request.data.array.items[2].data.array.size); - args = request.data.params.obj[2]; - assert_true(args.data.params.obj[0].type == OBJECT_TYPE_STR); - assert_string_equal(args.data.params.obj[0].data.string.str, p->function->args[0].str); + args = request.data.array.items[2]; + assert_true(args.data.array.items[0].type == OBJECT_TYPE_STR); + assert_string_equal(args.data.array.items[0].data.string.str, p->function->args[0].str); - assert_true(args.data.params.obj[1].type == OBJECT_TYPE_STR); - assert_string_equal(args.data.params.obj[1].data.string.str, p->function->args[1].str); + assert_true(args.data.array.items[1].type == OBJECT_TYPE_STR); + assert_string_equal(args.data.array.items[1].data.string.str, p->function->args[1].str); - free_params(params); + api_free_array(message); return (1); } -int validate_run_response(const unsigned long data1, - UNUSED(const unsigned long data2)) -{ - struct msgpack_object *deserialized = (struct msgpack_object *) data1; - struct message_object response; - struct plugin *p = (struct plugin *) data2; - array params; - - wrap_crypto_write = true; - - assert_int_equal(0, unpack_params(deserialized, ¶ms)); - - /* msgpack response needs to be 1 */ - assert_true(params.obj[0].type == OBJECT_TYPE_UINT); - assert_int_equal(1, params.obj[0].data.uinteger); - - /* msg id which is random */ - assert_true(params.obj[1].type == OBJECT_TYPE_UINT); - - /* method should be NIL */ - assert_true(params.obj[2].type == OBJECT_TYPE_NIL); - - /* first level arrays: - * - * [meta] args->obj[0] - */ - response = params.obj[3]; - assert_true(response.type == OBJECT_TYPE_ARRAY); - assert_int_equal(1, response.data.params.size); - - /* the server must send a call id, store the callid for further - * validation */ - assert_true(response.data.params.obj[0].type == OBJECT_TYPE_UINT); - check_expected(response.data.params.obj[0].data.uinteger); - //TODO validate callid against plugin->callid - if (p) { - assert_true(response.data.params.obj[0].data.uinteger == p->callid); - } - - free_params(params); - - return (1); -} - int validate_result_request(const unsigned long data1, UNUSED(const unsigned long data2)) { struct msgpack_object *deserialized = (struct msgpack_object *) data1; - struct message_object meta, request; - array params; + array message; + object meta, request; - assert_int_equal(0, unpack_params(deserialized, ¶ms)); + msgpack_rpc_to_array(deserialized, &message); /* msgpack request needs to be 0 */ - assert_true(params.obj[0].type == OBJECT_TYPE_UINT); - assert_int_equal(0, params.obj[0].data.uinteger); + assert_true(message.items[0].type == OBJECT_TYPE_UINT); + assert_int_equal(0, message.items[0].data.uinteger); /* msg id which is random */ - assert_true(params.obj[1].type == OBJECT_TYPE_UINT); + assert_true(message.items[1].type == OBJECT_TYPE_UINT); /* run call */ - assert_true(params.obj[2].type == OBJECT_TYPE_STR); - assert_string_equal(params.obj[2].data.string.str, "result"); + assert_true(message.items[2].type == OBJECT_TYPE_STR); + assert_string_equal(message.items[2].data.string.str, "result"); /* first level arrays: * * [meta] args->obj[0] * [functions] args->obj[1] */ - request = params.obj[3]; + request = message.items[3]; assert_true(request.type == OBJECT_TYPE_ARRAY); - assert_int_equal(2, request.data.params.size); + assert_int_equal(2, request.data.array.size); - meta = request.data.params.obj[0]; + meta = request.data.array.items[0]; assert_true(meta.type == OBJECT_TYPE_ARRAY); - assert_int_equal(1, meta.data.params.size); + assert_int_equal(1, meta.data.array.size); /* client2 id should be nil */ - assert_true(meta.data.params.obj[0].type == OBJECT_TYPE_UINT); + assert_true(meta.data.array.items[0].type == OBJECT_TYPE_UINT); /* since the callid must be forwarded to the client1, the original * sender of the rpc call, we need to push the callid on the cmocka test * stack. this allows verifying of it later on */ - uint64_t callid = meta.data.params.obj[0].data.uinteger; + uint64_t callid = meta.data.array.items[0].data.uinteger; will_return(__wrap_loop_wait_for_response, OBJECT_TYPE_UINT); will_return(__wrap_loop_wait_for_response, callid); - expect_value(validate_result_response, response.data.params.obj[0].data.uinteger, callid); - free_params(params); + api_free_array(message); return (1); } - -int validate_result_response(const unsigned long data1, - UNUSED(const unsigned long data2)) -{ - struct msgpack_object *deserialized = (struct msgpack_object *) data1; - struct message_object response; - array params; - - wrap_crypto_write = true; - - assert_int_equal(0, unpack_params(deserialized, ¶ms)); - - /* msgpack response needs to be 1 */ - assert_true(params.obj[0].type == OBJECT_TYPE_UINT); - assert_int_equal(1, params.obj[0].data.uinteger); - - /* msg id which is random */ - assert_true(params.obj[1].type == OBJECT_TYPE_UINT); - - /* method should be NIL */ - assert_true(params.obj[2].type == OBJECT_TYPE_NIL); - - /* first level arrays: - * - * [meta] args->obj[0] - */ - response = params.obj[3]; - assert_true(response.type == OBJECT_TYPE_ARRAY); - assert_int_equal(1, response.data.params.size); - - /* the server must send a call id, store the callid for further - * validation */ - assert_true(response.data.params.obj[0].type == OBJECT_TYPE_UINT); - check_expected(response.data.params.obj[0].data.uinteger); - - free_params(params); - - return (1); -} - - diff --git a/test/test-list.h b/test/test-list.h index 28c9532..54ae98f 100644 --- a/test/test-list.h +++ b/test/test-list.h @@ -20,28 +20,9 @@ void unit_server_start(void **state); void unit_server_stop(void **state); -void unit_pack_string(void **state); -void unit_pack_int(void **state); -void unit_pack_uint(void **state); -void unit_pack_array(void **state); -void unit_pack_nil(void **state); -void unit_pack_float(void **state); -void unit_pack_bool(void **state); -void unit_unpack_string(void **state); -void unit_unpack_uint(void **state); -void unit_unpack_array(void **state); void unit_dispatch_table_get(void **state); void unit_event_queue_put(void **state); void unit_event_queue_get(void **state); -void unit_regression_issue_60(void **state); -void unit_message_deserialize_request(void **state); -void unit_message_deserialize_response(void **state); -void unit_message_deserialize_error_response(void **state); -void unit_message_serialize_request(void **state); -void unit_message_serialize_response(void **state); -void unit_message_serialize_error_response(void **state); -void unit_message_is_request(void **state); -void unit_message_is_response(void **state); void functional_client_connect(void **state); void functional_db_connect(void **state); @@ -63,23 +44,7 @@ const struct CMUnitTest tests[] = { cmocka_unit_test(unit_dispatch_table_get), cmocka_unit_test(unit_server_start), cmocka_unit_test(unit_server_stop), - cmocka_unit_test(unit_pack_string), - cmocka_unit_test(unit_pack_int), - cmocka_unit_test(unit_pack_uint), - cmocka_unit_test(unit_pack_nil), - cmocka_unit_test(unit_pack_float), - cmocka_unit_test(unit_pack_bool), - cmocka_unit_test(unit_pack_array), - cmocka_unit_test(unit_regression_issue_60), cmocka_unit_test(unit_event_queue_put), - cmocka_unit_test(unit_message_deserialize_request), - cmocka_unit_test(unit_message_deserialize_response), - cmocka_unit_test(unit_message_deserialize_error_response), - cmocka_unit_test(unit_message_serialize_request), - cmocka_unit_test(unit_message_serialize_response), - cmocka_unit_test(unit_message_serialize_error_response), - cmocka_unit_test(unit_message_is_request), - cmocka_unit_test(unit_message_is_response), cmocka_unit_test(functional_db_connect), cmocka_unit_test(functional_db_plugin_add), cmocka_unit_test(functional_db_pluginkey_verify), diff --git a/test/unit/server-start.c b/test/unit/server-start.c index abbb227..b00dd80 100644 --- a/test/unit/server-start.c +++ b/test/unit/server-start.c @@ -17,6 +17,7 @@ #include #include +#include "helper-all.h" #include "sb-common.h" #include "rpc/sb-rpc.h" #include "helper-unix.h" diff --git a/test/unit/server-stop.c b/test/unit/server-stop.c index 53dbf6c..4ec297e 100644 --- a/test/unit/server-stop.c +++ b/test/unit/server-stop.c @@ -15,6 +15,7 @@ */ #include "sb-common.h" +#include "helper-all.h" #include "rpc/sb-rpc.h" #include "helper-unix.h" #include "rpc/db/sb-db.h" diff --git a/test/wrapper-functions.c b/test/wrapper-functions.c index 585f976..7d825ac 100644 --- a/test/wrapper-functions.c +++ b/test/wrapper-functions.c @@ -2,6 +2,8 @@ #include #include #include "rpc/sb-rpc.h" +#include "rpc/msgpack/helpers.h" +#include "api/helpers.h" #include "helper-unix.h" #include "helper-all.h" @@ -42,7 +44,7 @@ int __wrap_outputstream_write(UNUSED(outputstream *ostream), char *buffer, size_ break; case 'M': /* message packet */ - assert_int_equal(0, validate_crypto_write(buffer, len)); + assert_int_equal(0, validate_crypto_write((unsigned char*)buffer, len)); break; default: LOG_WARNING("Illegal identifier suffix."); @@ -58,9 +60,13 @@ void __wrap_loop_wait_for_response(UNUSED(struct connection *con), assert_non_null(cinfo); /* The callid and the message_params type are determined by the unit test. */ - cinfo->response.params.size = 1; - cinfo->response.params.obj = CALLOC(cinfo->response.params.size, - struct message_object); - cinfo->response.params.obj[0].type = (message_object_type)mock(); - cinfo->response.params.obj[0].data.uinteger = (uint64_t)mock(); + + cinfo->result = ARRAY_OBJ(((array) { + .size = 1, + .capacity = 1, + .items = calloc(1, sizeof(object)), + })); + + cinfo->result.data.array.items[0].type = (object_type)mock(); + cinfo->result.data.array.items[0].data.uinteger = (uint64_t)mock(); } From 3491fb8a05560ef1d0a102ce93d0dfc49be2f3b4 Mon Sep 17 00:00:00 2001 From: Stephan Zeisberg Date: Fri, 21 Oct 2016 22:37:22 +0200 Subject: [PATCH 07/41] Refactor rpc modules and add support for subscribe/unsubscribe/broadcast This commit cleans up the rpc stack and introduces an event subscribe/unsubscribe and broadcast mechanism. --- src/api/broadcast.c | 37 +++ src/api/sb-api.h | 4 + src/api/subscribe.c | 38 +++ src/api/unsubscribe.c | 38 +++ src/kvec.h | 151 +++++++++--- src/rpc/connection/connection.c | 394 +++++++++++++++++++++++-------- src/rpc/connection/connection.h | 4 +- src/rpc/connection/dispatch.c | 395 ++++++++++++++++++++++---------- src/rpc/connection/loop.c | 8 +- src/rpc/db/function.c | 25 +- src/rpc/sb-rpc.h | 140 +++++++---- src/sb-common.h | 8 +- 12 files changed, 923 insertions(+), 319 deletions(-) create mode 100644 src/api/broadcast.c create mode 100644 src/api/subscribe.c create mode 100644 src/api/unsubscribe.c diff --git a/src/api/broadcast.c b/src/api/broadcast.c new file mode 100644 index 0000000..1dd80fb --- /dev/null +++ b/src/api/broadcast.c @@ -0,0 +1,37 @@ +/** + * Copyright (C) 2015 splone UG + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +#include +#include + +#include "rpc/db/sb-db.h" +#include "api/sb-api.h" +#include "api/helpers.h" + + +int api_broadcast(string eventname, array args, struct api_error *api_error) +{ + if (!api_error) + return -1; + + if (!connection_send_event(0, eventname.str, args)) { + error_set(api_error, API_ERROR_TYPE_VALIDATION, + "Broadcasting event failed"); + return -1; + } + + return 0; +} diff --git a/src/api/sb-api.h b/src/api/sb-api.h index 3da8c5b..0b464a9 100644 --- a/src/api/sb-api.h +++ b/src/api/sb-api.h @@ -55,6 +55,10 @@ int api_run(char *targetpluginkey, string function_name, uint64_t callid, * @param[in] key string to store the API key. * @return 0 in case of success otherwise -1 */ + +int api_broadcast(string eventname, array args, struct api_error *api_error); +int api_subscribe(uint64_t id, string event, struct api_error *api_error); +int api_unsubscribe(uint64_t id, string event, struct api_error *api_error); int api_get_key(string key); int api_result(char *targetpluginkey, uint64_t callid, array args, diff --git a/src/api/subscribe.c b/src/api/subscribe.c new file mode 100644 index 0000000..3e9c50a --- /dev/null +++ b/src/api/subscribe.c @@ -0,0 +1,38 @@ +/** + * Copyright (C) 2015 splone UG + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +#include +#include + +#include "rpc/db/sb-db.h" +#include "api/sb-api.h" +#include "api/helpers.h" + + +int api_subscribe(uint64_t con_id, string event, struct api_error *api_error) +{ + if (!api_error) + return -1; + + size_t length = (event.length < METHOD_MAXLEN ? event.length : METHOD_MAXLEN); + char e[METHOD_MAXLEN + 1]; + memcpy(e, event.str, length); + e[length] = '\000'; + + connection_subscribe(con_id, e); + + return 0; +} diff --git a/src/api/unsubscribe.c b/src/api/unsubscribe.c new file mode 100644 index 0000000..4ac6b4d --- /dev/null +++ b/src/api/unsubscribe.c @@ -0,0 +1,38 @@ +/** + * Copyright (C) 2015 splone UG + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +#include +#include + +#include "rpc/db/sb-db.h" +#include "api/sb-api.h" +#include "api/helpers.h" + + +int api_unsubscribe(uint64_t con_id, string event, struct api_error *api_error) +{ + if (!api_error) + return -1; + + size_t length = (event.length < METHOD_MAXLEN ? event.length : METHOD_MAXLEN); + char e[METHOD_MAXLEN + 1]; + memcpy(e, event.str, length); + e[length] = '\000'; + + connection_unsubscribe(con_id, e); + + return 0; +} diff --git a/src/kvec.h b/src/kvec.h index 31d2e14..2d087d0 100644 --- a/src/kvec.h +++ b/src/kvec.h @@ -49,42 +49,129 @@ int main() { #define AC_KVEC_H #include +#include -#define kv_roundup32(x) (--(x), (x)|=(x)>>1, (x)|=(x)>>2, (x)|=(x)>>4, (x)|=(x)>>8, (x)|=(x)>>16, ++(x)) +#include "sb-common.h" -#define kvec_t(type) struct { size_t size, capacity; type *obj; } -#define kv_init(v) ((v).size = (v).capacity = 0, (v).obj = 0) -#define kv_destroy(v) free((v).obj) -#define kv_A(v, i) ((v).obj[(i)]) -#define kv_pop(v) ((v).obj[--(v).size]) +#define kv_roundup32(x) \ + ((--(x)), \ + ((x)|=(x)>>1, (x)|=(x)>>2, (x)|=(x)>>4, (x)|=(x)>>8, (x)|=(x)>>16), \ + (++(x))) + +#define KV_INITIAL_VALUE { .size = 0, .capacity = 0, .items = NULL } + +#define kvec_t(type) \ + struct { \ + size_t size; \ + size_t capacity; \ + type *items; \ + } + +#define kv_init(v) ((v).size = (v).capacity = 0, (v).items = 0) +#define kv_destroy(v) free((v).items) +#define kv_A(v, i) ((v).items[(i)]) +#define kv_pop(v) ((v).items[--(v).size]) #define kv_size(v) ((v).size) #define kv_max(v) ((v).capacity) +#define kv_last(v) kv_A(v, kv_size(v) - 1) + +#define kv_resize(v, s) \ + ((v).capacity = (s), \ + (v).items = realloc((v).items, sizeof((v).items[0]) * (v).capacity)) + +#define kv_resize_full(v) \ + kv_resize(v, (v).capacity ? (v).capacity << 1 : 8) + +#define kv_copy(v1, v0) \ + do { \ + if ((v1).capacity < (v0).size) { \ + kv_resize(v1, (v0).size); \ + } \ + (v1).size = (v0).size; \ + memcpy((v1).items, (v0).items, sizeof((v1).items[0]) * (v0).size); \ + } while (0) \ + +#define kv_pushp(v) \ + ((((v).size == (v).capacity) ? (kv_resize_full(v), 0) : 0), \ + ((v).items + ((v).size++))) + +#define kv_push(v, x) \ + (*kv_pushp(v) = (x)) + +#define kv_a(v, i) \ + (((v).capacity <= (size_t) (i) \ + ? ((v).capacity = (v).size = (i) + 1, \ + kv_roundup32((v).capacity), \ + kv_resize((v), (v).capacity), 0) \ + : ((v).size <= (size_t) (i) \ + ? (v).size = (i) + 1 \ + : 0)), \ + (v).items[(i)]) + +#define kvec_withinit_t(type, INIT_SIZE) \ + struct { \ + size_t size; \ + size_t capacity; \ + type *items; \ + type init_array[INIT_SIZE]; \ + } + +#define kvi_init(v) \ + ((v).capacity = ARRAY_SIZE((v).init_array), \ + (v).size = 0, \ + (v).items = (v).init_array) + +/// Move data to a new destination and free source +static inline void *_memcpy_free(void *const restrict dest, + void *const restrict src, + const size_t size) +{ + memcpy(dest, src, size); + free(src); + return dest; +} + -#define kv_resize(type, v, s) ((v).capacity = (s), (v).obj = (type*)realloc((v).obj, sizeof(type) * (v).capacity)) - -#define kv_copy(type, v1, v0) do { \ - if ((v1).capacity < (v0).size) kv_resize(type, v1, (v0).size); \ - (v1).size = (v0).size; \ - memcpy((v1).obj, (v0).obj, sizeof(type) * (v0).size); \ - } while (0) \ - -#define kv_push(type, v, x) do { \ - if ((v).size == (v).capacity) { \ - (v).capacity = (v).capacity? (v).capacity<<1 : 8; \ - (v).obj = (type*)realloc((v).obj, sizeof(type) * (v).capacity); \ - } \ - (v).obj[(v).size++] = (x); \ - } while (0) - -#define kv_pushp(type, v) (((v).size == (v).capacity)? \ - ((v).capacity = ((v).capacity? (v).capacity<<1 : 8), \ - (v).obj = (type*)realloc((v).obj, sizeof(type) * (v).capacity), 0) \ - : 0), ((v).obj + ((v).size++)) - -#define kv_a(type, v, i) (((v).capacity <= (size_t)(i)? \ - ((v).capacity = (v).size = (i) + 1, kv_roundup32((v).capacity), \ - (v).obj = (type*)realloc((v).obj, sizeof(type) * (v).capacity), 0) \ - : (v).size <= (size_t)(i)? (v).size = (i) + 1 \ - : 0), (v).obj[(i)]) +#define kvi_resize(v, s) \ + ((v).capacity = ((s) > ARRAY_SIZE((v).init_array) \ + ? (s) \ + : ARRAY_SIZE((v).init_array)), \ + (v).items = ((v).capacity == ARRAY_SIZE((v).init_array) \ + ? ((v).items == (v).init_array \ + ? (v).items \ + : _memcpy_free((v).init_array, (v).items, \ + (v).size * sizeof((v).items[0]))) \ + : ((v).items == (v).init_array \ + ? memcpy(xmalloc((v).capacity * sizeof((v).items[0])), \ + (v).items, \ + (v).size * sizeof((v).items[0])) \ + : realloc((v).items, \ + (v).capacity * sizeof((v).items[0]))))) + +/// Resize vector with preallocated array when it is full +/// +/// @param[out] v Vector to resize. +#define kvi_resize_full(v) \ + /* ARRAY_SIZE((v).init_array) is the minimal capacity of this vector. */ \ + /* Thus when vector is full capacity may not be zero and it is safe */ \ + /* not to bother with checking whether (v).capacity is 0. But now */ \ + /* capacity is not guaranteed to have size that is a power of 2, it is */ \ + /* hard to fix this here and is not very necessary if users will use */ \ + /* 2^x initial array size. */ \ + kvi_resize(v, (v).capacity << 1) + +#define kvi_pushp(v) \ + ((((v).size == (v).capacity) ? (kvi_resize_full(v), 0) : 0), \ + ((v).items + ((v).size++))) + +#define kvi_push(v, x) \ + (*kvi_pushp(v) = (x)) + +#define kvi_destroy(v) \ + do { \ + if ((v).items != (v).init_array) { \ + FREE((v).items); \ + } \ + } while (0) #endif diff --git a/src/rpc/connection/connection.c b/src/rpc/connection/connection.c index 40267bd..8a8b9c4 100644 --- a/src/rpc/connection/connection.c +++ b/src/rpc/connection/connection.c @@ -40,16 +40,21 @@ #include #include #include +#ifdef __linux__ +#include +#endif #include "tweetnacl.h" #include "rpc/sb-rpc.h" #include "rpc/connection/connection.h" +#include "rpc/msgpack/helpers.h" #include "api/sb-api.h" +#include "api/helpers.h" -STATIC int parse_cb(inputstream *istream, void *data, bool eof); +STATIC void parse_cb(inputstream *istream, void *data, bool eof); STATIC void close_cb(uv_handle_t *handle); STATIC void timer_cb(uv_timer_t *timer); -STATIC int connection_handle_request(struct connection *con, +STATIC void connection_handle_request(struct connection *con, msgpack_object *obj); STATIC void connection_handle_response(struct connection *con, msgpack_object *obj); @@ -60,10 +65,13 @@ STATIC int is_valid_rpc_response(msgpack_object *obj, struct connection *con); STATIC void free_connection(struct connection *con); STATIC void incref(struct connection *con); STATIC void decref(struct connection *con); +STATIC void unsubscribe(struct connection *con, char *event); +STATIC void send_delayed_notifications(struct connection *con); static uint64_t next_con_id = 1; static hashmap(uint64_t, ptr_t) *connections = NULL; static hashmap(cstr_t, uint64_t) *pluginkeys = NULL; +static hashmap(cstr_t, ptr_t) *event_strings = NULL; static msgpack_sbuffer sbuf; equeue *equeue_root; uv_loop_t loop; @@ -72,11 +80,12 @@ int connection_init(void) { connections = hashmap_new(uint64_t, ptr_t)(); pluginkeys = hashmap_new(cstr_t, uint64_t)(); + event_strings = hashmap_new(cstr_t, ptr_t)(); if (dispatch_table_init() == -1) return (-1); - if (!connections || !pluginkeys) + if (!connections || !pluginkeys || !event_strings) return (-1); msgpack_sbuffer_init(&sbuf); @@ -95,8 +104,10 @@ int connection_teardown(void) connection_close(con); }); + hashmap_free(uint64_t, ptr_t)(connections); hashmap_free(cstr_t, uint64_t)(pluginkeys); + hashmap_free(cstr_t, ptr_t)(event_strings); dispatch_teardown(); msgpack_sbuffer_destroy(&sbuf); @@ -125,6 +136,8 @@ int connection_create(uv_stream_t *stream) con->streams.write = outputstream_new(1024 * 1024); con->streams.uv = stream; con->cc.nonce = (uint64_t) randommod(281474976710656LL); + con->subscribed_events = hashmap_new(cstr_t, ptr_t)(); + con->pending_requests = 0; if (ISODD(con->cc.nonce)) { con->cc.nonce++; @@ -148,6 +161,7 @@ int connection_create(uv_stream_t *stream) con->packet.pos = 0; kv_init(con->callvector); + kv_init(con->delayed_notifications); inputstream_set(con->streams.read, stream); inputstream_start(con->streams.read); @@ -158,6 +172,90 @@ int connection_create(uv_stream_t *stream) return (0); } +void connection_subscribe(uint64_t id, char *event) +{ + struct connection *con; + + if (!(con = hashmap_get(uint64_t, ptr_t)(connections, id)) || con->closed) + abort(); + + char *event_string = hashmap_get(cstr_t, ptr_t)(event_strings, event); + + if (!event_string) { + event_string = box_strdup(event); + hashmap_put(cstr_t, ptr_t)(event_strings, event_string, event_string); + } + + hashmap_put(cstr_t, ptr_t)(con->subscribed_events, event_string, event_string); +} + +void connection_unsubscribe(uint64_t id, char *event) +{ + struct connection *con; + + if (!(con = hashmap_get(uint64_t, ptr_t)(connections, id)) || con->closed) + abort(); + + unsubscribe(con, event); +} + +STATIC void broadcast_event(char *name, array args) +{ + kvec_t(struct connection *) subscribed = KV_INITIAL_VALUE; + struct connection *con; + msgpack_packer packer; + + hashmap_foreach_value(connections, con, { + if (hashmap_has(cstr_t, ptr_t)(con->subscribed_events, name)) { + kv_push(subscribed, con); + } + }); + + if (!kv_size(subscribed)) { + api_free_array(args); + goto end; + } + + string method = {.length = strlen(name), .str = name}; + + msgpack_packer_init(&packer, &sbuf, msgpack_sbuffer_write); + msgpack_rpc_serialize_request(0, method, args, &packer); + api_free_array(args); + + for (size_t i = 0; i < kv_size(subscribed); i++) { + con = kv_A(subscribed, i); + + if (con->pending_requests) { + wbuffer *rv = MALLOC(wbuffer); + rv->size = sbuf.size; + rv->data = sb_memdup_nulterm(sbuf.data, sbuf.size); + kv_push(con->delayed_notifications, rv); + } else { + crypto_write(&con->cc, sbuf.data, sbuf.size, con->streams.write); + } + } + + msgpack_sbuffer_clear(&sbuf); + +end: + kv_destroy(subscribed); +} + +STATIC void unsubscribe(struct connection *con, char *event) +{ + char *event_string = hashmap_get(cstr_t, ptr_t)(event_strings, event); + hashmap_del(cstr_t, ptr_t)(con->subscribed_events, event_string); + + hashmap_foreach_value(connections, con, { + if (hashmap_has(cstr_t, ptr_t)(con->subscribed_events, event_string)) { + return; + } + }); + + hashmap_del(cstr_t, ptr_t)(event_strings, event_string); + FREE(event_string); +} + STATIC void incref(struct connection *con) { con->refcount++; @@ -171,12 +269,12 @@ STATIC void decref(struct connection *con) } -int connection_hashmap_put(uint64_t id, struct connection *con) +void connection_hashmap_put(uint64_t id, struct connection *con) { hashmap_put(uint64_t, ptr_t)(connections, id, con); } -int pluginkeys_hashmap_put(char *pluginkey, uint64_t id) +void pluginkeys_hashmap_put(char *pluginkey, uint64_t id) { hashmap_put(cstr_t, uint64_t)(pluginkeys, pluginkey, id); } @@ -186,7 +284,15 @@ STATIC void free_connection(struct connection *con) hashmap_del(uint64_t, ptr_t)(connections, con->id); hashmap_del(cstr_t, uint64_t)(pluginkeys, con->cc.pluginkeystring); msgpack_unpacker_free(con->mpac); + + char *event_string; + hashmap_foreach_value(con->subscribed_events, event_string, { + unsubscribe(con, event_string); + }); + + hashmap_free(cstr_t, ptr_t)(con->subscribed_events); kv_destroy(con->callvector); + kv_destroy(con->delayed_notifications); equeue_free(con->queue); if (con->packet.data) @@ -203,13 +309,14 @@ STATIC void timer_cb(uv_timer_t *timer) STATIC void connection_close(struct connection *con) { - int is_closing; uv_handle_t *handle; uv_handle_t *timer_handle; if (con->closed) return; + con->closed = true; + timer_handle = (uv_handle_t*) &con->minutekey_timer; if (timer_handle) { uv_close(timer_handle, NULL); @@ -223,10 +330,6 @@ STATIC void connection_close(struct connection *con) if (handle) uv_close(handle, close_cb); - kv_destroy(con->callvector); - - con->closed = 0; - decref(con); } @@ -250,7 +353,31 @@ STATIC void reset_parser(struct connection *con) reset_packet(con); } -STATIC int parse_cb(inputstream *istream, void *data, bool eof) +STATIC bool is_rpc_response(msgpack_object *obj) +{ + return obj->type == MSGPACK_OBJECT_ARRAY + && obj->via.array.size == 4 + && obj->via.array.ptr[0].type == MSGPACK_OBJECT_POSITIVE_INTEGER + && obj->via.array.ptr[0].via.u64 == 1 + && obj->via.array.ptr[1].type == MSGPACK_OBJECT_POSITIVE_INTEGER; +} + +STATIC void send_error(struct connection *con, uint64_t id, char *err) +{ + struct api_error e = ERROR_INIT; + + error_set(&e, API_ERROR_TYPE_VALIDATION, "%s", err); + + msgpack_packer pac; + msgpack_packer_init(&pac, &sbuf, msgpack_sbuffer_write); + msgpack_rpc_serialize_response(id, &e, NIL, &pac); + + crypto_write(&con->cc, sbuf.data, sbuf.size, con->streams.write); + + msgpack_sbuffer_clear(&sbuf); +} + +STATIC void parse_cb(inputstream *istream, void *data, bool eof) { unsigned char *packet; unsigned char hellopacket[192]; @@ -269,7 +396,7 @@ STATIC int parse_cb(inputstream *istream, void *data, bool eof) if (eof) { connection_close(con); - goto fail; + goto end; } if (con->cc.state == TUNNEL_INITIAL) { @@ -278,7 +405,7 @@ STATIC int parse_cb(inputstream *istream, void *data, bool eof) con->streams.write) != 0) LOG_WARNING("establishing crypto tunnel failed at hello-cookie packet"); - goto fail; + goto end; } else if (con->cc.state == TUNNEL_COOKIE_SENT) { size = inputstream_read(istream, initiatepacket, 256); if (crypto_recv_initiate(&con->cc, initiatepacket) != 0) { @@ -293,7 +420,7 @@ STATIC int parse_cb(inputstream *istream, void *data, bool eof) pending = inputstream_pending(istream); if (pending <= 0 || con->cc.state != TUNNEL_ESTABLISHED) - goto fail; + goto end; if (con->packet.end <= 0) { packet = inputstream_get_read(istream, &read); @@ -301,7 +428,7 @@ STATIC int parse_cb(inputstream *istream, void *data, bool eof) /* read the packet length */ if (crypto_verify_header(&con->cc, packet, &con->packet.length)) { reset_packet(con); - goto fail; + goto end; } con->packet.end = con->packet.length; @@ -309,13 +436,13 @@ STATIC int parse_cb(inputstream *istream, void *data, bool eof) if (!con->packet.data) { LOG_ERROR("Failed to alloc mem for con packet."); - goto fail; + goto end; } if (msgpack_unpacker_reserve_buffer(con->mpac, MAX(read, con->packet.end)) == false) { LOG_ERROR("Failed to reserve mem msgpack buffer."); - goto fail; + goto end; }; /* get decrypted message start position */ @@ -333,7 +460,7 @@ STATIC int parse_cb(inputstream *istream, void *data, bool eof) if (crypto_read(&con->cc, con->packet.data, con->unpackbuf + consumedlen, con->packet.length, &plaintextlen) != 0) { reset_parser(con); - goto fail; + goto end; } consumedlen += plaintextlen; @@ -341,12 +468,12 @@ STATIC int parse_cb(inputstream *istream, void *data, bool eof) if (packet == NULL) { reset_parser(con); - goto fail; + goto end; } if (crypto_verify_header(&con->cc, packet, &con->packet.length)) { reset_parser(con); - goto fail; + goto end; } con->packet.end = con->packet.length; @@ -355,14 +482,13 @@ STATIC int parse_cb(inputstream *istream, void *data, bool eof) } if (con->packet.end > 0 && read == 0) { - decref(con); - return (0); + goto end; } if (crypto_read(&con->cc, con->packet.data, con->unpackbuf + consumedlen, con->packet.length, &plaintextlen) != 0) { reset_parser(con); - goto fail; + goto end; } consumedlen += plaintextlen; @@ -377,9 +503,9 @@ STATIC int parse_cb(inputstream *istream, void *data, bool eof) /* deserialize objects, one by one */ while ((ret = msgpack_unpacker_next(con->mpac, &result)) == MSGPACK_UNPACK_SUCCESS) { - if (message_is_request(&result.data)) - connection_handle_request(con, &result.data); - else if (message_is_response(&result.data)) { + bool is_response = is_rpc_response(&result.data); + + if (is_response) { if (is_valid_rpc_response(&result.data, con)) { connection_handle_response(con, &result.data); } else { @@ -387,35 +513,77 @@ STATIC int parse_cb(inputstream *istream, void *data, bool eof) "request id. Ensure the client is properly " "synchronized"); } - } else { - LOG_WARNING("invalid msgpack object"); - msgpack_object_print(stdout, result.data); + + msgpack_unpacked_destroy(&result); + goto end; } + + connection_handle_request(con, &result.data); } - decref(con); + if (ret == MSGPACK_UNPACK_NOMEM_ERROR) { + decref(con); + exit(2); + } - return (0); + if (ret == MSGPACK_UNPACK_PARSE_ERROR) { + send_error(con, 0, "Invalid msgpack payload. " + "This error can also happen when deserializing " + "an object with high level of nesting"); + } -fail: +end: decref(con); - return (-1); } -struct callinfo connection_send_request(char *pluginkey, string method, - array params, struct api_error *api_error) +bool connection_send_event(uint64_t id, char *name, array args) +{ + msgpack_packer packer; + struct connection *con = NULL; + + if (id && (!(con = hashmap_get(uint64_t, ptr_t)(connections, id)) + || con->closed)) { + api_free_array(args); + return false; + } + + if (con) { + string method = cstring_to_string(name); + msgpack_packer_init(&packer, &sbuf, msgpack_sbuffer_write); + msgpack_rpc_serialize_request(0, method, args, &packer); + api_free_array(args); + + if (con->pending_requests) { + wbuffer *rv = MALLOC(wbuffer); + rv->size = sbuf.size; + rv->data = sb_memdup_nulterm(sbuf.data, sbuf.size); + kv_push(con->delayed_notifications, rv); + } else { + crypto_write(&con->cc, sbuf.data, sbuf.size, con->streams.write); + } + + msgpack_sbuffer_clear(&sbuf); + } else { + broadcast_event(name, args); + } + + return true; +} + + +object connection_send_request(char *pluginkey, string method, + array args, struct api_error *err) { uint64_t id; struct connection *con; msgpack_packer packer; - struct message_request request; id = hashmap_get(cstr_t, uint64_t)(pluginkeys, pluginkey); if (id == 0) { - free_params(params); - error_set(api_error, API_ERROR_TYPE_VALIDATION, "plugin not registered"); - return CALLINFO_INIT; + api_free_array(args); + error_set(err, API_ERROR_TYPE_VALIDATION, "plugin not registered"); + return NIL; } con = hashmap_get(uint64_t, ptr_t)(connections, id); @@ -425,44 +593,78 @@ struct callinfo connection_send_request(char *pluginkey, string method, * the initial connection from the sender. */ if (!con) { - free_params(params); - error_set(api_error, API_ERROR_TYPE_VALIDATION, "plugin not registered"); - return CALLINFO_INIT; + api_free_array(args); + error_set(err, API_ERROR_TYPE_VALIDATION, "plugin not registered"); + return NIL; } incref(con); - request.msgid = con->msgid++; - request.method = method; - request.params = params; msgpack_packer_init(&packer, &sbuf, msgpack_sbuffer_write); - message_serialize_request(&request, &packer); - free_params(params); + msgpack_rpc_serialize_request(con->msgid++, method, args, &packer); + + api_free_array(args); LOG_VERBOSE(VERBOSE_LEVEL_0, "sending request: method = %s, callinfo id = %u\n", - method, request.msgid); + method.str, con->msgid); if (crypto_write(&con->cc, sbuf.data, sbuf.size, con->streams.write) != 0) - return CALLINFO_INIT; + return NIL; - struct callinfo cinfo = (struct callinfo) {request.msgid, false, false,((struct message_response) {0, ARRAY_INIT})}; + msgpack_sbuffer_clear(&sbuf); + + struct callinfo cinfo = (struct callinfo) { con->msgid, false, false, NIL }; loop_wait_for_response(con, &cinfo); - msgpack_sbuffer_clear(&sbuf); + if (cinfo.errored) { + if (cinfo.result.type == OBJECT_TYPE_STR) { + error_set(err, API_ERROR_TYPE_EXCEPTION, "%s", + cinfo.result.data.string.str); + } else if (cinfo.result.type == OBJECT_TYPE_ARRAY) { + array array = cinfo.result.data.array; + + if (array.size == 2 && array.items[0].type == OBJECT_TYPE_INT + && (array.items[0].data.integer == API_ERROR_TYPE_EXCEPTION + || array.items[0].data.integer == API_ERROR_TYPE_VALIDATION) + && array.items[1].type == OBJECT_TYPE_STR) { + err->type = (api_error_type) array.items[0].data.integer; + strlcpy(err->msg, array.items[1].data.string.str, sizeof(err->msg)); + err->isset = true; + } else { + error_set(err, API_ERROR_TYPE_EXCEPTION, "%s", "unknown error"); + } + } else { + error_set(err, API_ERROR_TYPE_EXCEPTION, "%s", "unknown error"); + } + + api_free_object(cinfo.result); + } + + if (!con->pending_requests) { + send_delayed_notifications(con); + } decref(con); - if (cinfo.errorresponse) - return CALLINFO_INIT; + return cinfo.errored ? NIL : cinfo.result; +} + +STATIC void send_delayed_notifications(struct connection *con) +{ + for (size_t i = 0; i < kv_size(con->delayed_notifications); i++) { + wbuffer *buffer = kv_A(con->delayed_notifications, i); + crypto_write(&con->cc, buffer->data, buffer->size, con->streams.write); + FREE(buffer->data); + FREE(buffer); + } - return cinfo; + kv_size(con->delayed_notifications) = 0; } int connection_send_response(uint64_t con_id, uint32_t msgid, - array params, struct api_error *api_error) + object arg, struct api_error *api_error) { msgpack_packer packer; - struct message_response response; struct connection *con; con = hashmap_get(uint64_t, ptr_t)(connections, con_id); @@ -476,11 +678,8 @@ int connection_send_response(uint64_t con_id, uint32_t msgid, return (-1); } - response.msgid = msgid; - response.params = params; - msgpack_packer_init(&packer, &sbuf, msgpack_sbuffer_write); - message_serialize_response(&response, &packer); + msgpack_rpc_serialize_response(msgid, api_error, arg, &packer); if (api_error->isset) { return (-1); @@ -491,44 +690,48 @@ int connection_send_response(uint64_t con_id, uint32_t msgid, } msgpack_sbuffer_clear(&sbuf); - free_params(params); + api_free_object(arg); return 0; } -STATIC int connection_handle_request(struct connection *con, +STATIC void connection_handle_request(struct connection *con, msgpack_object *obj) { + array args = ARRAY_DICT_INIT; + uint64_t msgid; dispatch_info dispatcher; + msgpack_object *method; struct api_error api_error = ERROR_INIT; connection_request_event_info eventinfo; api_event event; - if (!obj || !con) - return (-1); + msgpack_rpc_validate(&msgid, obj, &api_error); - if (message_deserialize_request(&eventinfo.request, obj, &api_error) != 0) { - /* request wasn't parsed correctly, send error with pseudo RESPONSE ID*/ - eventinfo.request.msgid = MESSAGE_RESPONSE_UNKNOWN; - eventinfo.request.method = cstring_copy_string("error"); + if (api_error.isset) { + send_error(con, msgid, "Invalid message from connection, closed"); } - LOG_VERBOSE(VERBOSE_LEVEL_0, "received request: method = %s\n", - eventinfo.request.method.str); + method = msgpack_rpc_method(obj); - dispatcher = dispatch_table_get(eventinfo.request.method); + if (method) { + dispatcher = msgpack_rpc_get_handler_for(method->via.bin.ptr, + method->via.bin.size); + } else { + dispatcher.func = msgpack_rpc_handle_missing_method; + dispatcher.async = true; + } - if (dispatcher.func == NULL) { - LOG_VERBOSE(VERBOSE_LEVEL_0, "could not dispatch method\n"); - error_set(&api_error, API_ERROR_TYPE_VALIDATION, "could not dispatch method"); - dispatcher.func = handle_error; + if (!msgpack_rpc_to_array(msgpack_rpc_args(obj), &args)) { + dispatcher.func = msgpack_rpc_handle_invalid_arguments; dispatcher.async = true; } eventinfo.con = con; - eventinfo.api_error = api_error; eventinfo.dispatcher = dispatcher; + eventinfo.args = args; + eventinfo.msgid = msgid; incref(con); @@ -541,41 +744,41 @@ STATIC int connection_handle_request(struct connection *con, /* TODO: move this call to a suitable place (main?) */ equeue_run_events(equeue_root); } - - return (0); } STATIC void connection_request_event(connection_request_event_info *eventinfo) { + object result; msgpack_packer packer; struct connection *con; + struct api_error error = ERROR_INIT; con = eventinfo->con; + array args = eventinfo->args; + uint64_t msgid = eventinfo->msgid; + dispatch_info handler = eventinfo->dispatcher; - eventinfo->dispatcher.func(con->id, &eventinfo->request, - con->cc.pluginkeystring, &eventinfo->api_error); + result = handler.func(con->id, msgid, con->cc.pluginkeystring, args, &error); - if (eventinfo->api_error.isset) { + if (eventinfo->msgid != UINT64_MAX) { msgpack_packer_init(&packer, &sbuf, msgpack_sbuffer_write); - message_serialize_error_response(&packer, &eventinfo->api_error, - eventinfo->request.msgid); - + msgpack_rpc_serialize_response(msgid, &error, result, &packer); crypto_write(&eventinfo->con->cc, sbuf.data, sbuf.size, eventinfo->con->streams.write); - msgpack_sbuffer_clear(&sbuf); + } else { + api_free_object(result); } - free_params(eventinfo->request.params); - free_string(eventinfo->request.method); + api_free_array(args); decref(con); } STATIC int is_valid_rpc_response(msgpack_object *obj, struct connection *con) { - uint64_t msg_id = message_get_id(obj); + uint64_t msg_id = obj->via.array.ptr[1].via.u64; return kv_size(con->callvector) && msg_id == kv_A(con->callvector, kv_size(con->callvector) - 1)->msgid; @@ -586,20 +789,19 @@ STATIC void connection_handle_response(struct connection *con, msgpack_object *obj) { struct callinfo *cinfo; - struct api_error api_error = { .isset = false }; cinfo = kv_A(con->callvector, kv_size(con->callvector) - 1); LOG_VERBOSE(VERBOSE_LEVEL_0, "received response: callinfo id = %u\n", cinfo->msgid); - cinfo->hasresponse = true; - cinfo->errorresponse = message_is_error_response(obj); + cinfo->returned = true; + cinfo->errored = (obj->via.array.ptr[2].type != MSGPACK_OBJECT_NIL); - if (cinfo->errorresponse) { - message_deserialize_error_response(&cinfo->response, obj, &api_error); + if (cinfo->errored) { + msgpack_rpc_to_object(&obj->via.array.ptr[2], &cinfo->result); } else { - message_deserialize_response(&cinfo->response, obj, &api_error); + msgpack_rpc_to_object(&obj->via.array.ptr[3], &cinfo->result); } } @@ -609,8 +811,8 @@ STATIC void call_set_error(struct connection *con, UNUSED(char *msg)) for (size_t i = 0; i < kv_size(con->callvector); i++) { cinfo = kv_A(con->callvector, i); - cinfo->errorresponse = true; - cinfo->hasresponse = true; + cinfo->errored = true; + cinfo->returned = true; } connection_close(con); diff --git a/src/rpc/connection/connection.h b/src/rpc/connection/connection.h index 9d0a414..1788bcb 100644 --- a/src/rpc/connection/connection.h +++ b/src/rpc/connection/connection.h @@ -19,12 +19,12 @@ #include "rpc/sb-rpc.h" STATIC void close_cb(uv_handle_t *handle); -STATIC int connection_handle_request(struct connection *con, +STATIC void connection_handle_request(struct connection *con, msgpack_object *obj); STATIC void connection_handle_response(struct connection *con, msgpack_object *obj); STATIC void connection_request_event(connection_request_event_info *info); STATIC void connection_close(struct connection *con); -STATIC int parse_cb(inputstream *istream, void *data, bool eof); +STATIC void parse_cb(inputstream *istream, void *data, bool eof); STATIC int is_valid_rpc_response(msgpack_object *obj, struct connection *con); STATIC void call_set_error(struct connection *con, char *msg); diff --git a/src/rpc/connection/dispatch.c b/src/rpc/connection/dispatch.c index ce6bdd1..64cd2ad 100644 --- a/src/rpc/connection/dispatch.c +++ b/src/rpc/connection/dispatch.c @@ -34,16 +34,29 @@ #include "rpc/sb-rpc.h" #include "api/sb-api.h" +#include "api/helpers.h" #include "sb-common.h" static msgpack_sbuffer sbuf; static hashmap(string, dispatch_info) *dispatch_table = NULL; static hashmap(uint64_t, ptr_t) *callids = NULL; -int handle_error(uint64_t con_id, struct message_request *request, - char *pluginkey, struct api_error *error) +object msgpack_rpc_handle_missing_method(UNUSED(uint64_t channel_id), + UNUSED(uint64_t msgid), UNUSED(char *pluginkey), UNUSED(array args), + struct api_error *error) { - return (0); + snprintf(error->msg, sizeof(error->msg), "Invalid method name"); + error->isset = true; + return NIL; +} + +object msgpack_rpc_handle_invalid_arguments(UNUSED(uint64_t channel_id), + UNUSED(uint64_t msgid), UNUSED(char *pluginkey), UNUSED(array args), + struct api_error *error) +{ + snprintf(error->msg, sizeof(error->msg), "Invalid method arguments"); + error->isset = true; + return NIL; } /* @@ -53,29 +66,31 @@ int handle_error(uint64_t con_id, struct message_request *request, * @param api_error `struct api_error` error object-instance * @return 0 if success, -1 otherwise */ -int handle_register(uint64_t con_id, struct message_request *request, - char *pluginkey, struct api_error *error) +object handle_register(UNUSED(uint64_t con_id), UNUSED(uint64_t msgid), + char *pluginkey, array args, struct api_error *error) { - array *meta = NULL; - array functions; + array rv = ARRAY_DICT_INIT; + object ret = ARRAY_OBJ(rv); + array meta = ARRAY_DICT_INIT; + array functions = ARRAY_DICT_INIT; string name, description, author, license; - if (!error || !request) - return (-1); + if (!error) + goto end; /* check params size */ - if (request->params.size != 2) { + if (args.size != 2) { error_set(error, API_ERROR_TYPE_VALIDATION, "Error dispatching register API request. Invalid params size"); - return (-1); + goto end; } - if (request->params.obj[0].type == OBJECT_TYPE_ARRAY) - meta = &request->params.obj[0].data.params; + if (args.items[0].type == OBJECT_TYPE_ARRAY) + meta = args.items[0].data.array; else { error_set(error, API_ERROR_TYPE_VALIDATION, "Error dispatching register API request. meta params has wrong type"); - return (-1); + goto end; } /* @@ -83,240 +98,353 @@ int handle_register(uint64_t con_id, struct message_request *request, * [name, description, author, license] */ - if (!meta) { - error_set(error, API_ERROR_TYPE_VALIDATION, - "Error dispatching register API request. meta params is NULL"); - return (-1); - } - - if (meta->size != 4) { + if (meta.size != 4) { error_set(error, API_ERROR_TYPE_VALIDATION, "Error dispatching register API request. Invalid meta params size"); - return (-1); + goto end; } /* extract meta information */ - if ((meta->obj[0].type != OBJECT_TYPE_STR) || - (meta->obj[1].type != OBJECT_TYPE_STR) || - (meta->obj[2].type != OBJECT_TYPE_STR) || - (meta->obj[3].type != OBJECT_TYPE_STR)) { + if ((meta.items[0].type != OBJECT_TYPE_STR) || + (meta.items[1].type != OBJECT_TYPE_STR) || + (meta.items[2].type != OBJECT_TYPE_STR) || + (meta.items[3].type != OBJECT_TYPE_STR)) { error_set(error, API_ERROR_TYPE_VALIDATION, "Error dispatching register API request. meta element has wrong type"); - return (-1); + goto end; } - if (!meta->obj[0].data.string.str || !meta->obj[1].data.string.str || - !meta->obj[2].data.string.str || !meta->obj[3].data.string.str) { + if (!meta.items[0].data.string.str || !meta.items[1].data.string.str || + !meta.items[2].data.string.str || !meta.items[3].data.string.str) { error_set(error, API_ERROR_TYPE_VALIDATION, "Error dispatching register API request. Invalid meta params size"); - return (-1); + goto end; } - name = meta->obj[0].data.string; - description = meta->obj[1].data.string; - author = meta->obj[2].data.string; - license = meta->obj[3].data.string; + name = meta.items[0].data.string; + description = meta.items[1].data.string; + author = meta.items[2].data.string; + license = meta.items[3].data.string; - if (request->params.obj[1].type != OBJECT_TYPE_ARRAY) { + if (args.items[1].type == OBJECT_TYPE_ARRAY) { + functions = args.items[1].data.array; + } else { error_set(error, API_ERROR_TYPE_VALIDATION, "Error dispatching register API request. functions has wrong type"); - return (-1); + goto end; } - functions = request->params.obj[1].data.params; - - if (api_register(name, description, author, license, - functions, con_id, request->msgid, pluginkey, error) == -1) { + if (api_register(name, description, author, license, functions, pluginkey, + error) == -1) { if (!error->isset) error_set(error, API_ERROR_TYPE_VALIDATION, "Error running register API request."); - return (-1); + goto end; } - return (0); +end: + return ret; } -int handle_run(uint64_t con_id, struct message_request *request, - char *pluginkey, struct api_error *error) +object handle_run(UNUSED(uint64_t con_id), UNUSED(uint64_t msgid), + char *pluginkey, array args, struct api_error *error) { + array rv = ARRAY_DICT_INIT; + array meta = ARRAY_DICT_INIT; + array runargs = ARRAY_DICT_INIT; + string function_name = STRING_INIT; + object ret = ARRAY_OBJ(rv); uint64_t callid; - array *meta = NULL; - string function_name; char *targetpluginkey; - struct message_object args_object; - - if (!error || !request) - return (-1); + if (!error) + goto end; /* check params size */ - if (request->params.size != 3) { + if (args.size != 3) { error_set(error, API_ERROR_TYPE_VALIDATION, "Error dispatching run API request. Invalid params size"); - return (-1); + goto end; } - if (request->params.obj[0].type == OBJECT_TYPE_ARRAY) - meta = &request->params.obj[0].data.params; + if (args.items[0].type == OBJECT_TYPE_ARRAY) + meta = args.items[0].data.array; else { error_set(error, API_ERROR_TYPE_VALIDATION, "Error dispatching run API request. meta params has wrong type"); - return (-1); - } - - if (!meta) { - error_set(error, API_ERROR_TYPE_VALIDATION, - "Error dispatching run API request. meta params is NULL"); - return (-1); + goto end; } /* meta = [targetpluginkey, nil]*/ - if (meta->size != 2) { + if (meta.size != 2) { error_set(error, API_ERROR_TYPE_VALIDATION, "Error dispatching run API request. Invalid meta params size"); - return (-1); + goto end; } /* extract meta information */ - if (meta->obj[0].type != OBJECT_TYPE_STR) { + if (meta.items[0].type != OBJECT_TYPE_STR) { error_set(error, API_ERROR_TYPE_VALIDATION, "Error dispatching run API request. meta elements have wrong type"); - return (-1); + goto end; } - if (!meta->obj[0].data.string.str || - meta->obj[0].data.string.length+1 != PLUGINKEY_STRING_SIZE) { + if (!meta.items[0].data.string.str || + meta.items[0].data.string.length + 1 != PLUGINKEY_STRING_SIZE) { error_set(error, API_ERROR_TYPE_VALIDATION, "Error dispatching run API request. Invalid meta params size"); - return (-1); + goto end; } - targetpluginkey = meta->obj[0].data.string.str; + targetpluginkey = meta.items[0].data.string.str; to_upper(targetpluginkey); - if (meta->obj[1].type != OBJECT_TYPE_NIL) { + if (meta.items[1].type != OBJECT_TYPE_NIL) { error_set(error, API_ERROR_TYPE_VALIDATION, "Error dispatching run API request. meta elements have wrong type"); - return (-1); + goto end; } - if (request->params.obj[1].type != OBJECT_TYPE_STR) { + if (args.items[1].type == OBJECT_TYPE_STR) { + function_name = args.items[1].data.string; + } else { error_set(error, API_ERROR_TYPE_VALIDATION, "Error dispatching run API request. function string has wrong type"); - return (-1); + goto end; } - if (!request->params.obj[1].data.string.str) { - error_set(error, API_ERROR_TYPE_VALIDATION, - "Error dispatching register API request. Invalid meta params size"); - return (-1); - } - - function_name = request->params.obj[1].data.string; - - if (request->params.obj[2].type != OBJECT_TYPE_ARRAY) { + if (args.items[2].type == OBJECT_TYPE_ARRAY) { + runargs = args.items[2].data.array; + } else { error_set(error, API_ERROR_TYPE_VALIDATION, "Error dispatching run API request. function string has wrong type"); - return (-1); + goto end; } - args_object = request->params.obj[2]; callid = (uint64_t) randommod(281474976710656LL); LOG_VERBOSE(VERBOSE_LEVEL_1, "generated callid %lu\n", callid); hashmap_put(uint64_t, ptr_t)(callids, callid, pluginkey); - if (api_run(targetpluginkey, function_name, callid, args_object, con_id, - request->msgid, error) == -1) { + if (api_run(targetpluginkey, function_name, callid, runargs, error) == -1) { if (false == error->isset) error_set(error, API_ERROR_TYPE_VALIDATION, "Error executing run API request."); - return (-1); + goto end; } - return (0); + ret = ARRAY_OBJ(((array) { + .size = 1, + .capacity = 1, + .items = &UINTEGER_OBJ(callid) + })); + +end: + return ret; } -int handle_result(uint64_t con_id, struct message_request *request, - char *pluginkey, struct api_error *error) +object handle_result(UNUSED(uint64_t con_id), UNUSED(uint64_t msgid), + UNUSED(char *pluginkey), array args, struct api_error *error) { + array rv = ARRAY_DICT_INIT; + array meta = ARRAY_DICT_INIT; + array resultargs = ARRAY_DICT_INIT; + object ret = ARRAY_OBJ(rv); uint64_t callid; - array *meta = NULL; - struct message_object args_object; char * targetpluginkey; - if (!error || !request) - return (-1); + if (!error) + goto end; /* check params size */ - if (request->params.size != 2) { + if (args.size != 2) { error_set(error, API_ERROR_TYPE_VALIDATION, "Error dispatching result API request. Invalid params size"); - return (-1); + goto end; } - if (request->params.obj[0].type == OBJECT_TYPE_ARRAY) - meta = &request->params.obj[0].data.params; + if (args.items[0].type == OBJECT_TYPE_ARRAY) + meta = args.items[0].data.array; else { error_set(error, API_ERROR_TYPE_VALIDATION, "Error dispatching result API request. meta params has wrong type"); - return (-1); - } - - if (!meta) { - error_set(error, API_ERROR_TYPE_VALIDATION, - "Error dispatching result API request. meta params is NULL"); - return (-1); + goto end; } /* meta = [callid]*/ - if (meta->size != 1) { + if (meta.size != 1) { error_set(error, API_ERROR_TYPE_VALIDATION, "Error dispatching result API request. Invalid meta params size"); - return (-1); + goto end; } /* extract meta information */ - if (meta->obj[0].type != OBJECT_TYPE_UINT) { + if (meta.items[0].type == OBJECT_TYPE_UINT) { + callid = meta.items[0].data.uinteger; + } else { error_set(error, API_ERROR_TYPE_VALIDATION, "Error dispatching result API request. meta elements have wrong type"); - return (-1); + goto end; } - callid = meta->obj[0].data.uinteger; - - if (request->params.obj[1].type != OBJECT_TYPE_ARRAY) { + if (args.items[1].type == OBJECT_TYPE_ARRAY) { + resultargs = args.items[1].data.array; + } else { error_set(error, API_ERROR_TYPE_VALIDATION, "Error dispatching result API request. function string has wrong type"); - return (-1); + goto end; } - args_object = request->params.obj[1]; - targetpluginkey = hashmap_get(uint64_t, ptr_t)(callids, callid); if (!targetpluginkey) { error_set(error, API_ERROR_TYPE_VALIDATION, "Failed to find target's key associated with given callid."); - return (-1); + goto end; } - if (api_result(targetpluginkey, callid, args_object, con_id, request->msgid, - error) == -1) { + if (api_result(targetpluginkey, callid, resultargs, error) == -1) { if (false == error->isset) error_set(error, API_ERROR_TYPE_VALIDATION, "Error executing result API request."); - return (-1); + goto end; } hashmap_del(uint64_t, ptr_t)(callids, callid); - return (0); + ret = ARRAY_OBJ(((array) { + .size = 1, + .capacity = 1, + .items = &UINTEGER_OBJ(callid) + })); + +end: + return ret; } + +object handle_broadcast(UNUSED(uint64_t con_id), UNUSED(uint64_t msgid), + UNUSED(char *pluginkey), array args, struct api_error *error) +{ + array rv = ARRAY_DICT_INIT; + array eventargs = ARRAY_DICT_INIT; + object ret = ARRAY_OBJ(rv); + string eventname = STRING_INIT; + + if (!error) + goto end; + + /* check params size */ + if (args.size != 2) { + error_set(error, API_ERROR_TYPE_VALIDATION, + "Error dispatching broadcast API request. Invalid params size"); + goto end; + } + + if (args.items[0].type == OBJECT_TYPE_STR) + eventname = args.items[0].data.string; + else { + error_set(error, API_ERROR_TYPE_VALIDATION, + "Error dispatching broadcast API request. event name has wrong type"); + goto end; + } + + if (args.items[1].type == OBJECT_TYPE_ARRAY) + eventargs = args.items[0].data.array; + else { + error_set(error, API_ERROR_TYPE_VALIDATION, + "Error dispatching broadcast API request. event args has wrong type"); + goto end; + } + + if (api_broadcast(eventname, eventargs, error) == -1) { + if (false == error->isset) + error_set(error, API_ERROR_TYPE_VALIDATION, + "Error executing broadcast API request."); + goto end; + } + +end: + return ret; +} + + +object handle_subscribe(uint64_t con_id, UNUSED(uint64_t msgid), + UNUSED(char *pluginkey), array args, struct api_error *error) +{ + array rv = ARRAY_DICT_INIT; + object ret = ARRAY_OBJ(rv); + string eventname = STRING_INIT; + + if (!error) + goto end; + + /* check params size */ + if (args.size != 1) { + error_set(error, API_ERROR_TYPE_VALIDATION, + "Error dispatching broadcast API request. Invalid params size"); + goto end; + } + + if (args.items[0].type == OBJECT_TYPE_STR) + eventname = args.items[0].data.string; + else { + error_set(error, API_ERROR_TYPE_VALIDATION, + "Error dispatching broadcast API request. event name has wrong type"); + goto end; + } + + if (api_subscribe(con_id, eventname, error) == -1) { + if (false == error->isset) + error_set(error, API_ERROR_TYPE_VALIDATION, + "Error executing broadcast API request."); + goto end; + } + +end: + return ret; +} + +object handle_unsubscribe(uint64_t con_id, UNUSED(uint64_t msgid), + UNUSED(char *pluginkey), array args, struct api_error *error) +{ + array rv = ARRAY_DICT_INIT; + object ret = ARRAY_OBJ(rv); + string eventname = STRING_INIT; + + if (!error) + goto end; + + /* check params size */ + if (args.size != 1) { + error_set(error, API_ERROR_TYPE_VALIDATION, + "Error dispatching broadcast API request. Invalid params size"); + goto end; + } + + if (args.items[0].type == OBJECT_TYPE_STR) + eventname = args.items[0].data.string; + else { + error_set(error, API_ERROR_TYPE_VALIDATION, + "Error dispatching broadcast API request. event name has wrong type"); + goto end; + } + + if (api_unsubscribe(con_id, eventname, error) == -1) { + if (false == error->isset) + error_set(error, API_ERROR_TYPE_VALIDATION, + "Error executing broadcast API request."); + goto end; + } + +end: + return ret; +} + + void dispatch_table_put(string method, dispatch_info info) { hashmap_put(string, dispatch_info)(dispatch_table, method, info); @@ -337,6 +465,19 @@ int dispatch_teardown(void) return (0); } +dispatch_info msgpack_rpc_get_handler_for(const char *name, size_t name_len) +{ + string m = { .str = (char *)name, .length = name_len }; + dispatch_info rv = + hashmap_get(string, dispatch_info)(dispatch_table, m); + + if (!rv.func) { + rv.func = msgpack_rpc_handle_missing_method; + } + + return rv; +} + int dispatch_table_init(void) { @@ -344,10 +485,15 @@ int dispatch_table_init(void) .name = (string) {.str = "register", .length = sizeof("register") - 1}}; dispatch_info run_info = {.func = handle_run, .async = true, .name = (string) {.str = "run", .length = sizeof("run") - 1}}; - dispatch_info error_info = {.func = handle_error, .async = true, - .name = (string) {.str = "error", .length = sizeof("error") - 1}}; dispatch_info result_info = {.func = handle_result, .async = true, .name = (string) {.str = "result", .length = sizeof("result") - 1,}}; + dispatch_info broadcast_info = {.func = handle_broadcast, .async = true, + .name = (string) {.str = "broadcast", .length = sizeof("broadcast") - 1,}}; + dispatch_info subscribe_info = {.func = handle_subscribe, .async = false, + .name = (string) {.str = "subscribe", .length = sizeof("subscribe") - 1,}}; + dispatch_info unsubscribe_info = {.func = handle_unsubscribe, .async = false, + .name = (string) {.str = "unsubscribe", .length = sizeof("unsubscribe") - 1,}}; + msgpack_sbuffer_init(&sbuf); @@ -359,9 +505,10 @@ int dispatch_table_init(void) dispatch_table_put(register_info.name, register_info); dispatch_table_put(run_info.name, run_info); - dispatch_table_put(error_info.name, error_info); dispatch_table_put(result_info.name, result_info); - + dispatch_table_put(broadcast_info.name, broadcast_info); + dispatch_table_put(subscribe_info.name, subscribe_info); + dispatch_table_put(unsubscribe_info.name, unsubscribe_info); return (0); } diff --git a/src/rpc/connection/loop.c b/src/rpc/connection/loop.c index cd008fa..e245b9a 100644 --- a/src/rpc/connection/loop.c +++ b/src/rpc/connection/loop.c @@ -59,13 +59,13 @@ void loop_wait_for_response(struct connection *con, { /* push callinfo to connection callinfo vector */ - kv_push(struct callinfo *, con->callvector, cinfo); - con->pendingcalls++; + kv_push(con->callvector, cinfo); + con->pending_requests++; /* wait until requestinfo returned, in time process events */ - loop_poll_events_until(con, &cinfo->hasresponse); + loop_poll_events_until(con, &cinfo->returned); /* delete last from callinfo vector */ kv_pop(con->callvector); - con->pendingcalls--; + con->pending_requests--; } diff --git a/src/rpc/db/function.c b/src/rpc/db/function.c index d5e5714..264ccfd 100644 --- a/src/rpc/db/function.c +++ b/src/rpc/db/function.c @@ -52,7 +52,7 @@ static int db_function_add_meta(char *pluginkey, string name, string desc) { redisReply *reply; - if (!rc) + if (!rc || !name.str || !desc.str) return (-1); reply = redisCommand(rc, "HSET %s:func:%s:meta desc %s", pluginkey, @@ -71,7 +71,7 @@ static int db_function_add_meta(char *pluginkey, string name, string desc) static int db_function_add_args(char *pluginkey, string name, - message_object_type type) + object_type type) { redisReply *reply; @@ -103,6 +103,9 @@ static int db_function_flush_args(char *pluginkey, string name) /* if start > end, the result will be an empty list (which causes * key to be removed) */ + printf("name: %s\n", name.str); + printf("pluginkey: %s\n", pluginkey); + reply = redisCommand(rc, "LTRIM %s:func:%s:args %i %i", pluginkey, name.str, start, end); @@ -122,13 +125,13 @@ static int db_function_flush_args(char *pluginkey, string name) int db_function_add(char *pluginkey, array *func) { - struct message_object *name_elem, *desc_elem, *args, *arg; + object *name_elem, *desc_elem, *args, *arg; string name, desc; if (!func || !rc || (func->size <= 2)) return (-1); - name_elem = &func->obj[0]; + name_elem = &func->items[0]; if (!name_elem) { LOG_WARNING("Illegal function name pointer."); @@ -144,7 +147,7 @@ int db_function_add(char *pluginkey, array *func) return (-1); } - desc_elem = &func->obj[1]; + desc_elem = &func->items[1]; if (!desc_elem) { LOG_WARNING("Illegal function description pointer."); @@ -164,12 +167,12 @@ int db_function_add(char *pluginkey, array *func) if (db_function_add_meta(pluginkey, name, desc) == -1) return (-1); - args = &func->obj[2]; + args = &func->items[2]; db_function_flush_args(pluginkey, name); - for (size_t i = 0; i < args->data.params.size; i++) { - arg = &args->data.params.obj[i]; + for (size_t i = 0; i < args->data.array.size; i++) { + arg = &args->data.array.items[i]; if (db_function_add_args(pluginkey, name, arg->type) == -1) { LOG_WARNING("Failed to add function arguments!"); @@ -284,15 +287,15 @@ static int db_function_typecheck(char *pluginkey, string name, return (-1); } - if(val == OBJECT_TYPE_INT && args->obj[k].type == OBJECT_TYPE_UINT){ + if(val == OBJECT_TYPE_INT && args->items[k].type == OBJECT_TYPE_UINT){ /* Any positive integer will be treated as an unsigned int * (see unpack/pack.c) and might be a valid signed integer */ - if(args->obj[k].data.uinteger > INT64_MAX){ + if(args->items[k].data.uinteger > INT64_MAX){ LOG_WARNING("run() function argument has wrong type."); freeReplyObject(reply); return (-1); } - } else if (val != args->obj[k].type){ + } else if (val != args->items[k].type){ LOG_WARNING("run() function argument has wrong type."); freeReplyObject(reply); return (-1); diff --git a/src/rpc/sb-rpc.h b/src/rpc/sb-rpc.h index 8e1c9fc..ca5421e 100644 --- a/src/rpc/sb-rpc.h +++ b/src/rpc/sb-rpc.h @@ -43,7 +43,7 @@ /* Typedefs */ typedef struct outputstream outputstream; typedef struct inputstream inputstream; -typedef int (*inputstream_cb)(inputstream *inputstream, void *data, bool eof); +typedef void (*inputstream_cb)(inputstream *inputstream, void *data, bool eof); typedef struct api_event api_event; typedef struct equeue equeue; typedef struct queue_entry queue_entry; @@ -53,13 +53,13 @@ typedef struct connection_request_event_info connection_request_event_info; #define MESSAGE_REQUEST_ARRAY_SIZE 4 #define MESSAGE_RESPONSE_ARRAY_SIZE 4 -#define MESSAGE_TYPE_REQUEST 0 -#define MESSAGE_TYPE_RESPONSE 1 #define MESSAGE_RESPONSE_UNKNOWN UINT32_MAX +#define METHOD_MAXLEN 512 + #define STREAM_BUFFER_SIZE 0xffff -#define CALLINFO_INIT (struct callinfo) {0, false, false,((struct message_response) {0, ARRAY_INIT})} +#define CALLINFO_INIT (struct callinfo) {0, false, false, NIL} /* @@ -73,6 +73,14 @@ typedef struct connection_request_event_info connection_request_event_info; /* Enums */ +typedef enum { + MESSAGE_TYPE_REQUEST, + MESSAGE_TYPE_RESPONSE, + MESSAGE_TYPE_NOTIFICATION +} message_type; + +typedef struct object object; + typedef enum { OBJECT_TYPE_NIL, OBJECT_TYPE_INT, @@ -80,9 +88,9 @@ typedef enum { OBJECT_TYPE_BOOL, OBJECT_TYPE_FLOAT, OBJECT_TYPE_STR, - OBJECT_TYPE_BIN, OBJECT_TYPE_ARRAY, -} message_object_type; + OBJECT_TYPE_DICTIONARY +} object_type; typedef enum { TUNNEL_INITIAL, @@ -92,14 +100,22 @@ typedef enum { /* Structs */ +typedef struct key_value_pair key_value_pair; + typedef struct { - message_object *obj; + object *items; size_t size; size_t capacity; } array; -struct message_object { - message_object_type type; +typedef struct { + key_value_pair *items; + size_t size; + size_t capacity; +} dictionary; + +struct object { + object_type type; union { int64_t integer; uint64_t uinteger; @@ -107,7 +123,8 @@ struct message_object { char *bin; bool boolean; double floating; - array params; + array array; + dictionary dictionary; } data; }; @@ -122,6 +139,12 @@ struct message_response { array params; }; +struct key_value_pair { + string key; + object value; +}; + + /***************************************************************************** * The following crypto_context structure should be considered PRIVATE to * * the rpc connection layer. No non-rpc connection layer code should be * @@ -131,6 +154,23 @@ struct message_response { #define PLUGINKEY_STRING_SIZE ((PLUGINKEY_SIZE * 2) + 1) #define CLIENTLONGTERMPK_ARRAY_SIZE 32 +typedef object (*apidispatchwrapper)(uint64_t con_id, uint64_t msgid, + char *pluginkey, array args, struct api_error *error); + +typedef struct { + apidispatchwrapper func; + bool async; + string name; +} dispatch_info; + +/* hashmap declarations */ +MAP_DECLS(uint64_t, string) +MAP_DECLS(string, ptr_t) +MAP_DECLS(uint64_t, ptr_t) /* maps callid <> pluginkey */ +MAP_DECLS(cstr_t, ptr_t) /* maps pluginkey <> connection */ +MAP_DECLS(string, dispatch_info) +MAP_DECLS(cstr_t, uint64_t) + struct crypto_context { crypto_state state; uint64_t nonce; @@ -144,10 +184,18 @@ struct crypto_context { char pluginkeystring[PLUGINKEY_STRING_SIZE]; }; +typedef struct wbuffer wbuffer; + +struct wbuffer { + size_t size; + size_t refcount; + char *data; +}; + struct connection { uint64_t id; uint32_t msgid; - uint32_t pendingcalls; + size_t pending_requests; size_t refcount; msgpack_unpacker *mpac; msgpack_sbuffer *sbuf; @@ -160,6 +208,7 @@ struct connection { uv_stream_t *uv; } streams; kvec_t(struct callinfo *) callvector; + kvec_t(wbuffer *) delayed_notifications; struct crypto_context cc; struct { uint64_t start; @@ -169,25 +218,16 @@ struct connection { unsigned char *data; } packet; uv_timer_t minutekey_timer; + hashmap(cstr_t, ptr_t) *subscribed_events; }; struct callinfo { uint32_t msgid; - bool hasresponse; - bool errorresponse; - struct message_response response; + bool returned; + bool errored; + object result; }; -typedef int (*apidispatchwrapper)(uint64_t con_id, - struct message_request *request, char *pluginkey, - struct api_error *error); - -typedef struct { - apidispatchwrapper func; - bool async; - string name; -} dispatch_info; - struct outputstream { uv_stream_t *stream; size_t curmem; @@ -216,9 +256,9 @@ struct inputstream { /* this structure holds a request and all information to send a response */ struct connection_request_event_info { struct connection *con; - struct message_request request; dispatch_info dispatcher; - struct api_error api_error; + array args; + uint64_t msgid; }; /* this structure holds the request event information and a callback to a @@ -246,14 +286,6 @@ struct queue_entry { TAILQ_ENTRY(queue_entry) node; }; -/* hashmap declarations */ -MAP_DECLS(uint64_t, string) -MAP_DECLS(string, ptr_t) -MAP_DECLS(uint64_t, ptr_t) /* maps callid <> pluginkey */ -MAP_DECLS(cstr_t, ptr_t) /* maps pluginkey <> connection */ -MAP_DECLS(string, dispatch_info) -MAP_DECLS(cstr_t, uint64_t) - /* define global root event queue */ extern equeue *equeue_root; @@ -276,15 +308,18 @@ int connection_init(void); */ int connection_create(uv_stream_t *stream); -struct callinfo connection_send_request(char *pluginkey, string method, - array params, struct api_error *api_error); +object connection_send_request(char *pluginkey, string method, + array args, struct api_error *err); int connection_send_response(uint64_t con_id, uint32_t msgid, - array params, struct api_error *api_error); -int connection_hashmap_put(uint64_t id, struct connection *con); -int pluginkeys_hashmap_put(char *pluginkey, uint64_t id); + object arg, struct api_error *api_error); +void connection_hashmap_put(uint64_t id, struct connection *con); +void pluginkeys_hashmap_put(char *pluginkey, uint64_t id); void loop_wait_for_response(struct connection *con, struct callinfo *cinfo); int connection_teardown(void); +void connection_subscribe(uint64_t id, char *event); +void connection_unsubscribe(uint64_t id, char *event); +bool connection_send_event(uint64_t id, char *name, array args); /** * Create a new `outputstream` instance. A `outputstream` instance contains the @@ -478,16 +513,18 @@ inputstream * streamhandle_get_inputstream(uv_handle_t *handle); int dispatch_table_init(void); int dispatch_teardown(void); dispatch_info dispatch_table_get(string method); +dispatch_info msgpack_rpc_get_handler_for(const char *name, size_t name_len); void dispatch_table_put(string method, dispatch_info info); -int handle_run(uint64_t con_id, struct message_request *request, - char *pluginkey, struct api_error *error); -int handle_result(uint64_t con_id, struct message_request *request, - char *pluginkey, struct api_error *error); -int handle_register(uint64_t con_id, struct message_request *request, - char *pluginkey, struct api_error *error); -int handle_error(uint64_t con_id, struct message_request *request, - char *pluginkey, struct api_error *error); - +object handle_run(uint64_t con_id, uint64_t msgid, char *pluginkey, + array args, struct api_error *error); +object handle_result(uint64_t con_id, uint64_t msgid, char *pluginkey, + array args, struct api_error *error); +object handle_register(uint64_t con_id, uint64_t msgid, char *pluginkey, + array args, struct api_error *error); +object msgpack_rpc_handle_invalid_arguments(uint64_t channel_id, + uint64_t msgid, char *pluginkey, array args, struct api_error *error); +object msgpack_rpc_handle_missing_method(uint64_t channel_id, + uint64_t msgid, char *pluginkey, array args, struct api_error *error); /* Message Functions */ void free_params(array params); @@ -508,6 +545,7 @@ void message_dispatch(msgpack_object *req, msgpack_packer *res); uint64_t message_get_id(msgpack_object *obj); bool message_is_error_response(msgpack_object *obj); struct message_object message_object_copy(struct message_object obj); +object copy_object(object obj); @@ -601,3 +639,9 @@ uint64_t uint64_unpack(const unsigned char *x); * returns -1 in case of error otherwise 0 */ int byte_isequal(const void *yv, long long ylen, const void *xv); + +void msgpack_rpc_serialize_response(uint64_t response_id, struct api_error *err, + object arg, msgpack_packer *pac); + +void msgpack_rpc_serialize_request(uint64_t request_id, string method, + array args, msgpack_packer *pac); diff --git a/src/sb-common.h b/src/sb-common.h index a2284cd..bcaf497 100644 --- a/src/sb-common.h +++ b/src/sb-common.h @@ -83,7 +83,8 @@ #define API_ERROR_MESSAGE_LEN 512 typedef enum { - API_ERROR_TYPE_VALIDATION, + API_ERROR_TYPE_EXCEPTION, + API_ERROR_TYPE_VALIDATION } api_error_type; typedef struct { @@ -442,7 +443,8 @@ define UNUSED(x) x #define BOX_ADDR_BUF_LEN 48 -#define ARRAY_INIT {.size = 0, .capacity = 0, .obj = NULL} +#define ARRAY_INIT {.size = 0, .capacity = 0, .items = NULL} +#define ARRAY_DICT_INIT {.size = 0, .capacity = 0, .items = NULL} #define STRING_INIT {.str = NULL, .length = 0} #define ERROR_INIT {.isset = false} @@ -526,6 +528,8 @@ uint64_t parse_units(const char *val, struct unit_table_t *u, int *ok); const char * eat_whitespace(const char *s); char * box_strdup(const char *s); char * box_strndup(const char *s, size_t n); +void * sb_memdup(const void *mem, size_t len); +void * sb_memdup_nulterm(const void *mem, size_t len); int box_sscanf(const char *buf, const char *pattern, ...); int box_vsscanf(const char *buf, const char *pattern, va_list ap); From 4e037f1fb32a66188657fdb31bd6c7317c3aa5bd Mon Sep 17 00:00:00 2001 From: Stephan Zeisberg Date: Fri, 21 Oct 2016 22:39:25 +0200 Subject: [PATCH 08/41] Update CMakeLists.txt --- CMakeLists.txt | 41 ++++++++++++++--------------------------- 1 file changed, 14 insertions(+), 27 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 75973e6..43bd875 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -127,6 +127,11 @@ set(SPLONEBOX-SOURCES src/api/register.c src/api/result.c src/api/run.c + src/api/broadcast.c + src/api/subscribe.c + src/api/unsubscribe.c + src/api/helpers.c + src/api/helpers.h src/rpc/sb-rpc.h src/rpc/connection/event.c src/rpc/connection/event.h @@ -144,10 +149,8 @@ set(SPLONEBOX-SOURCES src/rpc/connection/crypto.c src/rpc/connection/crypto.h src/rpc/connection/loop.c - src/rpc/msgpack/sb-msgpack-rpc.h - src/rpc/msgpack/message.c - src/rpc/msgpack/pack.c - src/rpc/msgpack/unpack.c + src/rpc/msgpack/helpers.c + src/rpc/msgpack/helpers.h src/rpc/db/sb-db.h src/rpc/db/connect.c src/rpc/db/plugin.c @@ -209,6 +212,11 @@ set(TEST-SOURCES src/api/register.c src/api/run.c src/api/result.c + src/api/broadcast.c + src/api/subscribe.c + src/api/unsubscribe.c + src/api/helpers.c + src/api/helpers.h src/rpc/sb-rpc.h src/rpc/connection/event.c src/rpc/connection/event.h @@ -226,10 +234,8 @@ set(TEST-SOURCES src/rpc/connection/crypto.c src/rpc/connection/crypto.h src/rpc/connection/loop.c - src/rpc/msgpack/sb-msgpack-rpc.h - src/rpc/msgpack/message.c - src/rpc/msgpack/pack.c - src/rpc/msgpack/unpack.c + src/rpc/msgpack/helpers.c + src/rpc/msgpack/helpers.h src/rpc/db/sb-db.h src/rpc/db/connect.c src/rpc/db/plugin.c @@ -245,28 +251,9 @@ set(TEST-SOURCES test/helper-validate.h test/unit/server-start.c test/unit/server-stop.c - test/unit/pack-string.c - test/unit/pack-int.c - test/unit/pack-uint.c - test/unit/pack-array.c - test/unit/pack-nil.c - test/unit/pack-float.c - test/unit/pack-bool.c - test/unit/regression-issue-60.c - test/unit/unpack-string.c - test/unit/unpack-uint.c - test/unit/unpack-array.c test/unit/dispatch-table-get.c test/unit/event-queue-put.c test/unit/event-queue-get.c - test/unit/message-deserialize-request.c - test/unit/message-deserialize-response.c - test/unit/message-deserialize-error-response.c - test/unit/message-serialize-request.c - test/unit/message-serialize-response.c - test/unit/message-serialize-error-response.c - test/unit/message-is-request.c - test/unit/message-is-response.c test/functional/db-connect.c test/functional/db-plugin-add.c test/functional/db-pluginkey-verify.c From 7d4f4af7fc466b7fd09f05b2bf9eea11f688c7ce Mon Sep 17 00:00:00 2001 From: Stephan Zeisberg Date: Sat, 22 Oct 2016 18:01:21 +0200 Subject: [PATCH 09/41] Add functional tests for subscribe and unsubscribe --- CMakeLists.txt | 1 + src/rpc/sb-rpc.h | 4 ++++ test/test-list.h | 2 ++ 3 files changed, 7 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 43bd875..6af2d0c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -265,6 +265,7 @@ set(TEST-SOURCES test/functional/dispatch-handle-register.c test/functional/dispatch-handle-run.c test/functional/dispatch-handle-result.c + test/functional/dispatch-handle-subscribe.c test/functional/crypto.c test/functional/confparse.c test/functional/db-whitelist.c diff --git a/src/rpc/sb-rpc.h b/src/rpc/sb-rpc.h index ca5421e..81ef862 100644 --- a/src/rpc/sb-rpc.h +++ b/src/rpc/sb-rpc.h @@ -521,6 +521,10 @@ object handle_result(uint64_t con_id, uint64_t msgid, char *pluginkey, array args, struct api_error *error); object handle_register(uint64_t con_id, uint64_t msgid, char *pluginkey, array args, struct api_error *error); +object handle_subscribe(uint64_t con_id, uint64_t msgid, char *pluginkey, + array args, struct api_error *error); +object handle_unsubscribe(uint64_t con_id, uint64_t msgid, char *pluginkey, + array args, struct api_error *error); object msgpack_rpc_handle_invalid_arguments(uint64_t channel_id, uint64_t msgid, char *pluginkey, array args, struct api_error *error); object msgpack_rpc_handle_missing_method(uint64_t channel_id, diff --git a/test/test-list.h b/test/test-list.h index 54ae98f..1f68fab 100644 --- a/test/test-list.h +++ b/test/test-list.h @@ -36,6 +36,7 @@ void functional_filesystem_save_sync(void **state); void functional_dispatch_handle_register(void **state); void functional_dispatch_handle_run(void **state); void functional_dispatch_handle_result(void **state); +void functional_dispatch_handle_subscribe(void **state); void functional_crypto(void **state); void functional_confparse(void **state); void functional_db_whitelist(void **state); @@ -56,6 +57,7 @@ const struct CMUnitTest tests[] = { cmocka_unit_test(functional_dispatch_handle_register), cmocka_unit_test(functional_dispatch_handle_run), cmocka_unit_test(functional_dispatch_handle_result), + cmocka_unit_test(functional_dispatch_handle_subscribe), cmocka_unit_test(functional_crypto), cmocka_unit_test(functional_confparse), cmocka_unit_test(functional_db_whitelist), From 1ecdc380f33de6860fdf298483e397f397b81124 Mon Sep 17 00:00:00 2001 From: Stephan Zeisberg Date: Sat, 22 Oct 2016 18:04:26 +0200 Subject: [PATCH 10/41] Revert "Add functional tests for subscribe and unsubscribe" This reverts commit 7d4f4af7fc466b7fd09f05b2bf9eea11f688c7ce. --- CMakeLists.txt | 1 - src/rpc/sb-rpc.h | 4 ---- test/test-list.h | 2 -- 3 files changed, 7 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 6af2d0c..43bd875 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -265,7 +265,6 @@ set(TEST-SOURCES test/functional/dispatch-handle-register.c test/functional/dispatch-handle-run.c test/functional/dispatch-handle-result.c - test/functional/dispatch-handle-subscribe.c test/functional/crypto.c test/functional/confparse.c test/functional/db-whitelist.c diff --git a/src/rpc/sb-rpc.h b/src/rpc/sb-rpc.h index 81ef862..ca5421e 100644 --- a/src/rpc/sb-rpc.h +++ b/src/rpc/sb-rpc.h @@ -521,10 +521,6 @@ object handle_result(uint64_t con_id, uint64_t msgid, char *pluginkey, array args, struct api_error *error); object handle_register(uint64_t con_id, uint64_t msgid, char *pluginkey, array args, struct api_error *error); -object handle_subscribe(uint64_t con_id, uint64_t msgid, char *pluginkey, - array args, struct api_error *error); -object handle_unsubscribe(uint64_t con_id, uint64_t msgid, char *pluginkey, - array args, struct api_error *error); object msgpack_rpc_handle_invalid_arguments(uint64_t channel_id, uint64_t msgid, char *pluginkey, array args, struct api_error *error); object msgpack_rpc_handle_missing_method(uint64_t channel_id, diff --git a/test/test-list.h b/test/test-list.h index 1f68fab..54ae98f 100644 --- a/test/test-list.h +++ b/test/test-list.h @@ -36,7 +36,6 @@ void functional_filesystem_save_sync(void **state); void functional_dispatch_handle_register(void **state); void functional_dispatch_handle_run(void **state); void functional_dispatch_handle_result(void **state); -void functional_dispatch_handle_subscribe(void **state); void functional_crypto(void **state); void functional_confparse(void **state); void functional_db_whitelist(void **state); @@ -57,7 +56,6 @@ const struct CMUnitTest tests[] = { cmocka_unit_test(functional_dispatch_handle_register), cmocka_unit_test(functional_dispatch_handle_run), cmocka_unit_test(functional_dispatch_handle_result), - cmocka_unit_test(functional_dispatch_handle_subscribe), cmocka_unit_test(functional_crypto), cmocka_unit_test(functional_confparse), cmocka_unit_test(functional_db_whitelist), From c6fa3f0699d4742de13b55a8c829297a42cb72ce Mon Sep 17 00:00:00 2001 From: Stephan Zeisberg Date: Sat, 22 Oct 2016 18:10:01 +0200 Subject: [PATCH 11/41] Add functional tests for subscribe/unsubscribe --- CMakeLists.txt | 1 + src/rpc/sb-rpc.h | 4 + test/functional/dispatch-handle-subscribe.c | 150 ++++++++++++++++++++ test/test-list.h | 2 + 4 files changed, 157 insertions(+) create mode 100644 test/functional/dispatch-handle-subscribe.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 43bd875..6af2d0c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -265,6 +265,7 @@ set(TEST-SOURCES test/functional/dispatch-handle-register.c test/functional/dispatch-handle-run.c test/functional/dispatch-handle-result.c + test/functional/dispatch-handle-subscribe.c test/functional/crypto.c test/functional/confparse.c test/functional/db-whitelist.c diff --git a/src/rpc/sb-rpc.h b/src/rpc/sb-rpc.h index ca5421e..81ef862 100644 --- a/src/rpc/sb-rpc.h +++ b/src/rpc/sb-rpc.h @@ -521,6 +521,10 @@ object handle_result(uint64_t con_id, uint64_t msgid, char *pluginkey, array args, struct api_error *error); object handle_register(uint64_t con_id, uint64_t msgid, char *pluginkey, array args, struct api_error *error); +object handle_subscribe(uint64_t con_id, uint64_t msgid, char *pluginkey, + array args, struct api_error *error); +object handle_unsubscribe(uint64_t con_id, uint64_t msgid, char *pluginkey, + array args, struct api_error *error); object msgpack_rpc_handle_invalid_arguments(uint64_t channel_id, uint64_t msgid, char *pluginkey, array args, struct api_error *error); object msgpack_rpc_handle_missing_method(uint64_t channel_id, diff --git a/test/functional/dispatch-handle-subscribe.c b/test/functional/dispatch-handle-subscribe.c new file mode 100644 index 0000000..fccd6f0 --- /dev/null +++ b/test/functional/dispatch-handle-subscribe.c @@ -0,0 +1,150 @@ +/** + * Copyright (C) 2015 splone UG + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +#include + +#include "sb-common.h" +#include "rpc/sb-rpc.h" +#include "api/helpers.h" +#include "api/sb-api.h" +#ifdef __linux__ +#include +#endif + +#include "helper-unix.h" +#include "helper-all.h" +#include "helper-validate.h" + +static array api_subscribe_valid(void) +{ + array request = ARRAY_DICT_INIT; + ADD(request, STRING_OBJ(cstring_copy_string("testname"))); + + return request; +} + +static array api_subscribe_wrong_args_size(void) +{ + array request = ARRAY_DICT_INIT; + ADD(request, STRING_OBJ(cstring_copy_string("testname"))); + ADD(request, STRING_OBJ(cstring_copy_string("wrong"))); + + return request; +} + +static array api_subscribe_wrong_args_type(void) +{ + array request = ARRAY_DICT_INIT; + ADD(request, OBJECT_OBJ((object) OBJECT_INIT)); + + return request; +} + +void functional_dispatch_handle_subscribe(UNUSED(void **state)) +{ + struct plugin *plugin = helper_get_example_plugin(); + struct connection *con1; + struct connection *con2; + struct api_error error = ERROR_INIT; + array request; + + con1 = CALLOC(1, struct connection); + con1->id = (uint64_t) randommod(281474976710656LL); + con1->msgid = 4321; + con1->subscribed_events = hashmap_new(cstr_t, ptr_t)(); + + con2 = CALLOC(1, struct connection); + con2->id = (uint64_t) randommod(281474976710656LL); + con2->msgid = 4321; + con2->subscribed_events = hashmap_new(cstr_t, ptr_t)(); + + assert_non_null(con1); + assert_non_null(con2); + + strlcpy(con1->cc.pluginkeystring, "ABCD", sizeof("ABCD") - 1); + strlcpy(con2->cc.pluginkeystring, "EFGH", sizeof("EFGH") - 1); + + connect_to_db(); + assert_int_equal(0, connection_init()); + + con1->refcount++; + con2->refcount++; + + connection_hashmap_put(con1->id, con1); + connection_hashmap_put(con2->id, con2); + pluginkeys_hashmap_put(con1->cc.pluginkeystring, con1->id); + pluginkeys_hashmap_put(con2->cc.pluginkeystring, con2->id); + + + + //expect_check(__wrap_crypto_write, &deserialized, validate_run_request, plugin); + + request = api_subscribe_valid(); + handle_subscribe(con1->id, 123, con1->cc.pluginkeystring, request, &error); + assert_false(error.isset); + api_free_array(request); + + request = api_subscribe_valid(); + handle_subscribe(con2->id, 123, con2->cc.pluginkeystring, request, &error); + assert_false(error.isset); + api_free_array(request); + + request = api_subscribe_valid(); + handle_unsubscribe(con1->id, 123, con1->cc.pluginkeystring, request, &error); + assert_false(error.isset); + api_free_array(request); + + request = api_subscribe_valid(); + handle_unsubscribe(con2->id, 123, con2->cc.pluginkeystring, request, &error); + assert_false(error.isset); + api_free_array(request); + + request = api_subscribe_wrong_args_size(); + handle_subscribe(con1->id, 123, con1->cc.pluginkeystring, request, &error); + assert_true(error.isset); + error.isset = false; + api_free_array(request); + + request = api_subscribe_wrong_args_type(); + handle_subscribe(con1->id, 123, con1->cc.pluginkeystring, request, &error); + assert_true(error.isset); + error.isset = false; + api_free_array(request); + + request = api_subscribe_wrong_args_size(); + handle_unsubscribe(con1->id, 123, con1->cc.pluginkeystring, request, &error); + assert_true(error.isset); + error.isset = false; + api_free_array(request); + + request = api_subscribe_wrong_args_type(); + handle_unsubscribe(con1->id, 123, con1->cc.pluginkeystring, request, &error); + assert_true(error.isset); + error.isset = false; + api_free_array(request); + + con1->closed = true; + con2->closed = true; + + hashmap_free(cstr_t, ptr_t)(con1->subscribed_events); + hashmap_free(cstr_t, ptr_t)(con2->subscribed_events); + + helper_free_plugin(plugin); + connection_teardown(); + FREE(con1); + FREE(con2); + db_close(); +} diff --git a/test/test-list.h b/test/test-list.h index 54ae98f..1f68fab 100644 --- a/test/test-list.h +++ b/test/test-list.h @@ -36,6 +36,7 @@ void functional_filesystem_save_sync(void **state); void functional_dispatch_handle_register(void **state); void functional_dispatch_handle_run(void **state); void functional_dispatch_handle_result(void **state); +void functional_dispatch_handle_subscribe(void **state); void functional_crypto(void **state); void functional_confparse(void **state); void functional_db_whitelist(void **state); @@ -56,6 +57,7 @@ const struct CMUnitTest tests[] = { cmocka_unit_test(functional_dispatch_handle_register), cmocka_unit_test(functional_dispatch_handle_run), cmocka_unit_test(functional_dispatch_handle_result), + cmocka_unit_test(functional_dispatch_handle_subscribe), cmocka_unit_test(functional_crypto), cmocka_unit_test(functional_confparse), cmocka_unit_test(functional_db_whitelist), From 6d523a599c8ec9c34355d16ca0455cf99eaeccfd Mon Sep 17 00:00:00 2001 From: Stephan Zeisberg Date: Sun, 23 Oct 2016 00:42:24 +0200 Subject: [PATCH 12/41] Add functional test for broadcast API call --- CMakeLists.txt | 1 + src/api/broadcast.c | 6 +- src/rpc/connection/dispatch.c | 2 +- src/rpc/sb-rpc.h | 2 + test/functional/dispatch-handle-broadcast.c | 157 ++++++++++++++++++++ test/test-list.h | 2 + 6 files changed, 167 insertions(+), 3 deletions(-) create mode 100644 test/functional/dispatch-handle-broadcast.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 6af2d0c..3ded446 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -266,6 +266,7 @@ set(TEST-SOURCES test/functional/dispatch-handle-run.c test/functional/dispatch-handle-result.c test/functional/dispatch-handle-subscribe.c + test/functional/dispatch-handle-broadcast.c test/functional/crypto.c test/functional/confparse.c test/functional/db-whitelist.c diff --git a/src/api/broadcast.c b/src/api/broadcast.c index 1dd80fb..a6b0e68 100644 --- a/src/api/broadcast.c +++ b/src/api/broadcast.c @@ -22,12 +22,14 @@ #include "api/helpers.h" -int api_broadcast(string eventname, array args, struct api_error *api_error) +int api_broadcast(string event, array args, struct api_error *api_error) { if (!api_error) return -1; - if (!connection_send_event(0, eventname.str, args)) { + object o = copy_object(ARRAY_OBJ(args)); + + if (!connection_send_event(0, event.str, o.data.array)) { error_set(api_error, API_ERROR_TYPE_VALIDATION, "Broadcasting event failed"); return -1; diff --git a/src/rpc/connection/dispatch.c b/src/rpc/connection/dispatch.c index 64cd2ad..5089ff4 100644 --- a/src/rpc/connection/dispatch.c +++ b/src/rpc/connection/dispatch.c @@ -353,7 +353,7 @@ object handle_broadcast(UNUSED(uint64_t con_id), UNUSED(uint64_t msgid), } if (args.items[1].type == OBJECT_TYPE_ARRAY) - eventargs = args.items[0].data.array; + eventargs = args.items[1].data.array; else { error_set(error, API_ERROR_TYPE_VALIDATION, "Error dispatching broadcast API request. event args has wrong type"); diff --git a/src/rpc/sb-rpc.h b/src/rpc/sb-rpc.h index 81ef862..1aa66c2 100644 --- a/src/rpc/sb-rpc.h +++ b/src/rpc/sb-rpc.h @@ -525,6 +525,8 @@ object handle_subscribe(uint64_t con_id, uint64_t msgid, char *pluginkey, array args, struct api_error *error); object handle_unsubscribe(uint64_t con_id, uint64_t msgid, char *pluginkey, array args, struct api_error *error); +object handle_broadcast(uint64_t con_id, uint64_t msgid, char *pluginkey, + array args, struct api_error *error); object msgpack_rpc_handle_invalid_arguments(uint64_t channel_id, uint64_t msgid, char *pluginkey, array args, struct api_error *error); object msgpack_rpc_handle_missing_method(uint64_t channel_id, diff --git a/test/functional/dispatch-handle-broadcast.c b/test/functional/dispatch-handle-broadcast.c new file mode 100644 index 0000000..2c3d31e --- /dev/null +++ b/test/functional/dispatch-handle-broadcast.c @@ -0,0 +1,157 @@ +/** + * Copyright (C) 2015 splone UG + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +#include + +#include "sb-common.h" +#include "rpc/sb-rpc.h" +#include "api/helpers.h" +#include "api/sb-api.h" +#ifdef __linux__ +#include +#endif + +#include "helper-unix.h" +#include "helper-all.h" +#include "helper-validate.h" + +static array api_broadcast_valid(void) +{ + array args = ARRAY_DICT_INIT; + ADD(args, STRING_OBJ(cstring_copy_string("abc"))); + ADD(args, STRING_OBJ(cstring_copy_string("def"))); + + array request = ARRAY_DICT_INIT; + ADD(request, STRING_OBJ(cstring_copy_string("testname"))); + ADD(request, ARRAY_OBJ(args)); + + return request; +} + +static array api_subscribe_valid(void) +{ + array request = ARRAY_DICT_INIT; + ADD(request, STRING_OBJ(cstring_copy_string("testname"))); + + return request; +} + +int validate_broadcast(const unsigned long data1, + UNUSED(const unsigned long data2)) +{ + struct msgpack_object *deserialized = (struct msgpack_object *) data1; + array message; + + msgpack_rpc_to_array(deserialized, &message); + + assert_true(message.items[0].type == OBJECT_TYPE_UINT); + assert_int_equal(2, message.items[0].data.uinteger); + + assert_true(message.items[1].type == OBJECT_TYPE_STR); + assert_string_equal(message.items[1].data.string.str, "testname"); + + assert_true(message.items[2].type == OBJECT_TYPE_ARRAY); + assert_int_equal(2, message.items[2].data.array.size); + + assert_true(message.items[2].data.array.items[0].type == OBJECT_TYPE_STR); + assert_string_equal(message.items[2].data.array.items[0].data.string.str, + "abc"); + + assert_true(message.items[2].data.array.items[1].type == OBJECT_TYPE_STR); + assert_string_equal(message.items[2].data.array.items[1].data.string.str, + "def"); + + api_free_array(message); + + return 1; +} + + +void functional_dispatch_handle_broadcast(UNUSED(void **state)) +{ + struct plugin *plugin = helper_get_example_plugin(); + struct connection *con1; + struct connection *con2; + struct api_error error = ERROR_INIT; + array request; + + con1 = CALLOC(1, struct connection); + con1->id = (uint64_t) randommod(281474976710656LL); + con1->msgid = 4321; + con1->subscribed_events = hashmap_new(cstr_t, ptr_t)(); + + con2 = CALLOC(1, struct connection); + con2->id = (uint64_t) randommod(281474976710656LL); + con2->msgid = 4321; + con2->subscribed_events = hashmap_new(cstr_t, ptr_t)(); + + assert_non_null(con1); + assert_non_null(con2); + + strlcpy(con1->cc.pluginkeystring, "ABCD", sizeof("ABCD") - 1); + strlcpy(con2->cc.pluginkeystring, "EFGH", sizeof("EFGH") - 1); + + connect_to_db(); + assert_int_equal(0, connection_init()); + + con1->refcount++; + con2->refcount++; + + connection_hashmap_put(con1->id, con1); + connection_hashmap_put(con2->id, con2); + pluginkeys_hashmap_put(con1->cc.pluginkeystring, con1->id); + pluginkeys_hashmap_put(con2->cc.pluginkeystring, con2->id); + + expect_check(__wrap_crypto_write, &deserialized, validate_broadcast, NULL); + expect_check(__wrap_crypto_write, &deserialized, validate_broadcast, NULL); + + request = api_subscribe_valid(); + handle_subscribe(con1->id, 123, con1->cc.pluginkeystring, request, &error); + assert_false(error.isset); + api_free_array(request); + + request = api_subscribe_valid(); + handle_subscribe(con2->id, 123, con2->cc.pluginkeystring, request, &error); + assert_false(error.isset); + api_free_array(request); + + request = api_broadcast_valid(); + handle_broadcast(con2->id, 123, con2->cc.pluginkeystring, request, &error); + assert_false(error.isset); + api_free_array(request); + + request = api_subscribe_valid(); + handle_unsubscribe(con1->id, 123, con1->cc.pluginkeystring, request, &error); + assert_false(error.isset); + api_free_array(request); + + request = api_subscribe_valid(); + handle_unsubscribe(con2->id, 123, con2->cc.pluginkeystring, request, &error); + assert_false(error.isset); + api_free_array(request); + + con1->closed = true; + con2->closed = true; + + hashmap_free(cstr_t, ptr_t)(con1->subscribed_events); + hashmap_free(cstr_t, ptr_t)(con2->subscribed_events); + + helper_free_plugin(plugin); + connection_teardown(); + FREE(con1); + FREE(con2); + db_close(); +} diff --git a/test/test-list.h b/test/test-list.h index 1f68fab..b568dcc 100644 --- a/test/test-list.h +++ b/test/test-list.h @@ -37,6 +37,7 @@ void functional_dispatch_handle_register(void **state); void functional_dispatch_handle_run(void **state); void functional_dispatch_handle_result(void **state); void functional_dispatch_handle_subscribe(void **state); +void functional_dispatch_handle_broadcast(void **state); void functional_crypto(void **state); void functional_confparse(void **state); void functional_db_whitelist(void **state); @@ -58,6 +59,7 @@ const struct CMUnitTest tests[] = { cmocka_unit_test(functional_dispatch_handle_run), cmocka_unit_test(functional_dispatch_handle_result), cmocka_unit_test(functional_dispatch_handle_subscribe), + cmocka_unit_test(functional_dispatch_handle_broadcast), cmocka_unit_test(functional_crypto), cmocka_unit_test(functional_confparse), cmocka_unit_test(functional_db_whitelist), From 1b9072b36385823d4ae06b0f097ed71ab933bdc8 Mon Sep 17 00:00:00 2001 From: Stephan Zeisberg Date: Sun, 23 Oct 2016 00:44:11 +0200 Subject: [PATCH 13/41] Make request event handler more generic --- src/rpc/connection/connection.c | 20 +++++++++++--------- src/rpc/connection/connection.h | 2 +- src/rpc/connection/event.c | 2 +- src/rpc/sb-rpc.h | 6 ++++-- src/sb-common.h | 7 ++++--- 5 files changed, 21 insertions(+), 16 deletions(-) diff --git a/src/rpc/connection/connection.c b/src/rpc/connection/connection.c index 8a8b9c4..74acf13 100644 --- a/src/rpc/connection/connection.c +++ b/src/rpc/connection/connection.c @@ -58,7 +58,7 @@ STATIC void connection_handle_request(struct connection *con, msgpack_object *obj); STATIC void connection_handle_response(struct connection *con, msgpack_object *obj); -STATIC void connection_request_event(connection_request_event_info *info); +STATIC void connection_request_event(void **argv); STATIC void connection_close(struct connection *con); STATIC void call_set_error(struct connection *con, char *msg); STATIC int is_valid_rpc_response(msgpack_object *obj, struct connection *con); @@ -704,7 +704,6 @@ STATIC void connection_handle_request(struct connection *con, dispatch_info dispatcher; msgpack_object *method; struct api_error api_error = ERROR_INIT; - connection_request_event_info eventinfo; api_event event; msgpack_rpc_validate(&msgid, obj, &api_error); @@ -728,18 +727,19 @@ STATIC void connection_handle_request(struct connection *con, dispatcher.async = true; } - eventinfo.con = con; - eventinfo.dispatcher = dispatcher; - eventinfo.args = args; - eventinfo.msgid = msgid; + connection_request_event_info *eventinfo = MALLOC(connection_request_event_info); + eventinfo->con = con; + eventinfo->dispatcher = dispatcher; + eventinfo->args = args; + eventinfo->msgid = msgid; incref(con); if (dispatcher.async) - connection_request_event(&eventinfo); + connection_request_event((void**)&eventinfo); else { event.handler = connection_request_event; - event.info = eventinfo; + event.info = (void**)&eventinfo; equeue_put(con->queue, event); /* TODO: move this call to a suitable place (main?) */ equeue_run_events(equeue_root); @@ -747,8 +747,9 @@ STATIC void connection_handle_request(struct connection *con, } -STATIC void connection_request_event(connection_request_event_info *eventinfo) +STATIC void connection_request_event(void **argv) { + connection_request_event_info *eventinfo = argv[0]; object result; msgpack_packer packer; struct connection *con; @@ -774,6 +775,7 @@ STATIC void connection_request_event(connection_request_event_info *eventinfo) api_free_array(args); decref(con); + FREE(eventinfo); } STATIC int is_valid_rpc_response(msgpack_object *obj, struct connection *con) diff --git a/src/rpc/connection/connection.h b/src/rpc/connection/connection.h index 1788bcb..7088b37 100644 --- a/src/rpc/connection/connection.h +++ b/src/rpc/connection/connection.h @@ -23,7 +23,7 @@ STATIC void connection_handle_request(struct connection *con, msgpack_object *obj); STATIC void connection_handle_response(struct connection *con, msgpack_object *obj); -STATIC void connection_request_event(connection_request_event_info *info); +STATIC void connection_request_event(void **argv); STATIC void connection_close(struct connection *con); STATIC void parse_cb(inputstream *istream, void *data, bool eof); STATIC int is_valid_rpc_response(msgpack_object *obj, struct connection *con); diff --git a/src/rpc/connection/event.c b/src/rpc/connection/event.c index 6d997d3..511897c 100644 --- a/src/rpc/connection/event.c +++ b/src/rpc/connection/event.c @@ -179,6 +179,6 @@ void equeue_run_events(equeue *queue) event = equeue_get(queue); if (event.handler) - event.handler(&event.info); + event.handler(event.info); } } diff --git a/src/rpc/sb-rpc.h b/src/rpc/sb-rpc.h index 1aa66c2..57640d8 100644 --- a/src/rpc/sb-rpc.h +++ b/src/rpc/sb-rpc.h @@ -263,9 +263,11 @@ struct connection_request_event_info { /* this structure holds the request event information and a callback to a handler function */ +typedef void (*argv_callback)(void **argv); + struct api_event { - connection_request_event_info info; - void (*handler)(connection_request_event_info *info); + argv_callback handler; + void **info; }; TAILQ_HEAD(queue, queue_entry); diff --git a/src/sb-common.h b/src/sb-common.h index bcaf497..bcc76e9 100644 --- a/src/sb-common.h +++ b/src/sb-common.h @@ -397,9 +397,10 @@ define UNUSED(x) x #define REALLOC_ARRAY(pointer, number, type) \ ((type *)reallocarray(pointer, number, sizeof(type))) -#define FREE(pointer) do { \ - free(pointer); \ - pointer = NULL; \ +#define FREE(p) do { \ + if (PREDICT_LIKELY((p)!=NULL)) \ + free(p); \ + p= NULL; \ } while (0) #define LOG(...) \ From 98ac2207d38c462a9352f030dac12befe7310858 Mon Sep 17 00:00:00 2001 From: Stephan Zeisberg Date: Sun, 23 Oct 2016 00:51:21 +0200 Subject: [PATCH 14/41] Add more functional tests of broadcast API call --- test/functional/dispatch-handle-broadcast.c | 40 +++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/test/functional/dispatch-handle-broadcast.c b/test/functional/dispatch-handle-broadcast.c index 2c3d31e..1622912 100644 --- a/test/functional/dispatch-handle-broadcast.c +++ b/test/functional/dispatch-handle-broadcast.c @@ -19,6 +19,7 @@ #include "sb-common.h" #include "rpc/sb-rpc.h" #include "api/helpers.h" +#include "rpc/msgpack/helpers.h" #include "api/sb-api.h" #ifdef __linux__ #include @@ -41,6 +42,33 @@ static array api_broadcast_valid(void) return request; } +static array api_broadcast_wrong_args_size(void) +{ + array args = ARRAY_DICT_INIT; + ADD(args, STRING_OBJ(cstring_copy_string("abc"))); + ADD(args, STRING_OBJ(cstring_copy_string("def"))); + + array request = ARRAY_DICT_INIT; + ADD(request, STRING_OBJ(cstring_copy_string("testname"))); + ADD(request, ARRAY_OBJ(args)); + ADD(request, STRING_OBJ(cstring_copy_string("wrong"))); + + return request; +} + +static array api_broadcast_wrong_args_type(void) +{ + array args = ARRAY_DICT_INIT; + ADD(args, STRING_OBJ(cstring_copy_string("abc"))); + ADD(args, STRING_OBJ(cstring_copy_string("def"))); + + array request = ARRAY_DICT_INIT; + ADD(request, OBJECT_OBJ((object) OBJECT_INIT)); + ADD(request, ARRAY_OBJ(args)); + + return request; +} + static array api_subscribe_valid(void) { array request = ARRAY_DICT_INIT; @@ -133,6 +161,18 @@ void functional_dispatch_handle_broadcast(UNUSED(void **state)) assert_false(error.isset); api_free_array(request); + request = api_broadcast_wrong_args_size(); + handle_broadcast(con2->id, 123, con2->cc.pluginkeystring, request, &error); + assert_true(error.isset); + error.isset = false; + api_free_array(request); + + request = api_broadcast_wrong_args_type(); + handle_broadcast(con2->id, 123, con2->cc.pluginkeystring, request, &error); + assert_true(error.isset); + error.isset = false; + api_free_array(request); + request = api_subscribe_valid(); handle_unsubscribe(con1->id, 123, con1->cc.pluginkeystring, request, &error); assert_false(error.isset); From 1841e2211cd88a6ebd02e1ae8dbefb7ee8407bca Mon Sep 17 00:00:00 2001 From: Stephan Zeisberg Date: Sun, 23 Oct 2016 13:53:35 +0200 Subject: [PATCH 15/41] Add functional tests for new helper modules. --- CMakeLists.txt | 1 + src/api/helpers.h | 2 +- test/functional/msgpack-rpc-helper.c | 92 ++++++++++++++++++++++++++++ test/test-list.h | 2 + 4 files changed, 96 insertions(+), 1 deletion(-) create mode 100644 test/functional/msgpack-rpc-helper.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 3ded446..b18d8cf 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -270,6 +270,7 @@ set(TEST-SOURCES test/functional/crypto.c test/functional/confparse.c test/functional/db-whitelist.c + test/functional/msgpack-rpc-helper.c ) if(CLANG_ADDRESS_SANITIZER OR CLANG_MEMORY_SANITIZER OR CLANG_TSAN) diff --git a/src/api/helpers.h b/src/api/helpers.h index f015fc4..e312a3b 100644 --- a/src/api/helpers.h +++ b/src/api/helpers.h @@ -37,7 +37,7 @@ #define NIL ((object) {.type = OBJECT_TYPE_NIL}) #define PUT(dict, k, v) \ - kv_push(dict, ((key_value_pair) { .key = cstring_to_string(k), .value = v })) + kv_push(dict, ((key_value_pair) { .key = cstring_copy_string(k), .value = v })) #define ADD(array, item) \ kv_push(array, item) diff --git a/test/functional/msgpack-rpc-helper.c b/test/functional/msgpack-rpc-helper.c new file mode 100644 index 0000000..5a2f689 --- /dev/null +++ b/test/functional/msgpack-rpc-helper.c @@ -0,0 +1,92 @@ +/** + * Copyright (C) 2015 splone UG + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +#include "helper-unix.h" +#include "sb-common.h" +#include "api/helpers.h" +#include "rpc/msgpack/helpers.h" + + +void functional_msgpack_rpc_helper(UNUSED(void **state)) +{ + msgpack_sbuffer sbuf; + msgpack_packer pk; + + msgpack_sbuffer_init(&sbuf); + msgpack_packer_init(&pk, &sbuf, msgpack_sbuffer_write); + + // declare test object with all available types + array test = ARRAY_DICT_INIT; + + dictionary dict_test = ARRAY_DICT_INIT; + + dictionary dict_abc = ARRAY_DICT_INIT; + PUT(dict_abc, "123", INTEGER_OBJ(123)); + PUT(dict_abc, "456", STRING_OBJ(cstring_copy_string("456"))); + + dictionary dict_def = ARRAY_DICT_INIT; + PUT(dict_def, "789", INTEGER_OBJ(789)); + PUT(dict_def, "987", STRING_OBJ(cstring_copy_string("987"))); + + dictionary dict_ghi = ARRAY_DICT_INIT; + PUT(dict_ghi, "654", INTEGER_OBJ(654)); + PUT(dict_ghi, "321", STRING_OBJ(cstring_copy_string("321"))); + + PUT(dict_test, "abc", DICTIONARY_OBJ(dict_abc)); + PUT(dict_test, "def", DICTIONARY_OBJ(dict_def)); + PUT(dict_test, "ghi", DICTIONARY_OBJ(dict_ghi)); + + array array_abc = ARRAY_DICT_INIT; + ADD(array_abc, OBJECT_OBJ((object) OBJECT_INIT)); + ADD(array_abc, FLOATING_OBJ(1.2345)); + ADD(array_abc, UINTEGER_OBJ(1234)); + ADD(array_abc, INTEGER_OBJ(-1234)); + + array array_def = ARRAY_DICT_INIT; + ADD(array_def, STRING_OBJ(cstring_copy_string("test"))); + ADD(array_def, BOOLEAN_OBJ(true)); + ADD(array_def, BOOLEAN_OBJ(false)); + + ADD(test, ARRAY_OBJ(array_abc)); + ADD(test, ARRAY_OBJ(array_def)); + ADD(test, DICTIONARY_OBJ(dict_test)); + + object serialize_object = ARRAY_OBJ(test); + + msgpack_rpc_from_object(serialize_object, &pk); + api_free_object(serialize_object); + + msgpack_zone mempool; + msgpack_zone_init(&mempool, 2048); + + msgpack_object deserialized; + msgpack_unpack(sbuf.data, sbuf.size, NULL, &mempool, &deserialized); + + array deserialized_array; + assert_true(msgpack_rpc_to_array(&deserialized, &deserialized_array)); + api_free_array(deserialized_array); + + object deserialized_object; + assert_true(msgpack_rpc_to_object(&deserialized, &deserialized_object)); + api_free_object(deserialized_object); + + //api_free_object(serialize_object); + //api_free_array(deserialized_array); + //api_free_object(deserialized_object); + + msgpack_zone_destroy(&mempool); + msgpack_sbuffer_destroy(&sbuf); +} diff --git a/test/test-list.h b/test/test-list.h index b568dcc..630b302 100644 --- a/test/test-list.h +++ b/test/test-list.h @@ -38,6 +38,7 @@ void functional_dispatch_handle_run(void **state); void functional_dispatch_handle_result(void **state); void functional_dispatch_handle_subscribe(void **state); void functional_dispatch_handle_broadcast(void **state); +void functional_msgpack_rpc_helper(void **state); void functional_crypto(void **state); void functional_confparse(void **state); void functional_db_whitelist(void **state); @@ -60,6 +61,7 @@ const struct CMUnitTest tests[] = { cmocka_unit_test(functional_dispatch_handle_result), cmocka_unit_test(functional_dispatch_handle_subscribe), cmocka_unit_test(functional_dispatch_handle_broadcast), + cmocka_unit_test(functional_msgpack_rpc_helper), cmocka_unit_test(functional_crypto), cmocka_unit_test(functional_confparse), cmocka_unit_test(functional_db_whitelist), From bd4878185340d022cd84512c672d2925271a2ca0 Mon Sep 17 00:00:00 2001 From: Stephan Zeisberg Date: Sun, 23 Oct 2016 15:02:17 +0200 Subject: [PATCH 16/41] Add additional tests to msgpack helper functional test --- test/functional/msgpack-rpc-helper.c | 114 +++++++++++++++++++++++---- 1 file changed, 98 insertions(+), 16 deletions(-) diff --git a/test/functional/msgpack-rpc-helper.c b/test/functional/msgpack-rpc-helper.c index 5a2f689..7ef67e3 100644 --- a/test/functional/msgpack-rpc-helper.c +++ b/test/functional/msgpack-rpc-helper.c @@ -19,16 +19,8 @@ #include "api/helpers.h" #include "rpc/msgpack/helpers.h" - -void functional_msgpack_rpc_helper(UNUSED(void **state)) +static object helper_valid_object_all_type(void) { - msgpack_sbuffer sbuf; - msgpack_packer pk; - - msgpack_sbuffer_init(&sbuf); - msgpack_packer_init(&pk, &sbuf, msgpack_sbuffer_write); - - // declare test object with all available types array test = ARRAY_DICT_INIT; dictionary dict_test = ARRAY_DICT_INIT; @@ -64,29 +56,119 @@ void functional_msgpack_rpc_helper(UNUSED(void **state)) ADD(test, ARRAY_OBJ(array_def)); ADD(test, DICTIONARY_OBJ(dict_test)); - object serialize_object = ARRAY_OBJ(test); + return ARRAY_OBJ(test); +} + +static object helper_valid_notification_object(void) +{ + array notification = ARRAY_DICT_INIT; + + array args = ARRAY_DICT_INIT; + ADD(args, STRING_OBJ(cstring_copy_string("test"))); + ADD(args, BOOLEAN_OBJ(true)); + ADD(args, BOOLEAN_OBJ(false)); + + ADD(notification, UINTEGER_OBJ(2)); + ADD(notification, STRING_OBJ(cstring_copy_string("test"))); + ADD(notification, ARRAY_OBJ(args)); + + return ARRAY_OBJ(notification); +} + +static object helper_valid_request_object(void) +{ + array request = ARRAY_DICT_INIT; + + array args = ARRAY_DICT_INIT; + ADD(args, STRING_OBJ(cstring_copy_string("test"))); + ADD(args, BOOLEAN_OBJ(true)); + ADD(args, BOOLEAN_OBJ(false)); + + ADD(request, UINTEGER_OBJ(0)); + ADD(request, UINTEGER_OBJ(1234)); + ADD(request, STRING_OBJ(cstring_copy_string("test"))); + ADD(request, ARRAY_OBJ(args)); + return ARRAY_OBJ(request); +} + + +void functional_msgpack_rpc_helper(UNUSED(void **state)) +{ + struct api_error err = ERROR_INIT; + msgpack_sbuffer sbuf; + msgpack_packer pk; + + msgpack_sbuffer_init(&sbuf); + msgpack_packer_init(&pk, &sbuf, msgpack_sbuffer_write); + + // declare test object with all available types + + object serialize_object = helper_valid_object_all_type(); msgpack_rpc_from_object(serialize_object, &pk); - api_free_object(serialize_object); msgpack_zone mempool; msgpack_zone_init(&mempool, 2048); msgpack_object deserialized; msgpack_unpack(sbuf.data, sbuf.size, NULL, &mempool, &deserialized); + msgpack_sbuffer_clear(&sbuf); array deserialized_array; assert_true(msgpack_rpc_to_array(&deserialized, &deserialized_array)); - api_free_array(deserialized_array); object deserialized_object; assert_true(msgpack_rpc_to_object(&deserialized, &deserialized_object)); - api_free_object(deserialized_object); - //api_free_object(serialize_object); - //api_free_array(deserialized_array); - //api_free_object(deserialized_object); + // test response serialize without error set + msgpack_rpc_serialize_response(1234, &err, deserialized_object, &pk); + msgpack_sbuffer_clear(&sbuf); + + // test response serialize with error set + error_set(&err, API_ERROR_TYPE_EXCEPTION, "Error Error Error"); + msgpack_rpc_serialize_response(1234, &err, deserialized_object, &pk); + msgpack_sbuffer_clear(&sbuf); + + // notification helper tests + err.isset = false; + object notification_object = helper_valid_notification_object(); + msgpack_rpc_from_object(notification_object, &pk); + msgpack_object deserialized_not; + msgpack_unpack(sbuf.data, sbuf.size, NULL, &mempool, &deserialized_not); + assert_true(msgpack_rpc_is_notification(&deserialized_not)); + assert_null(msgpack_rpc_msg_id(&deserialized_not)); + uint64_t msgid_not = 1234; + msgpack_rpc_validate(&msgid_not, &deserialized_not, &err); + assert_false(err.isset); + msgpack_object *deserialized_not_args = msgpack_rpc_args(&deserialized_not); + assert_non_null(deserialized_not_args); + msgpack_object *deserialized_not_method = msgpack_rpc_method(&deserialized_not); + assert_non_null(deserialized_not_method); + msgpack_sbuffer_clear(&sbuf); + + // notification helper tests + err.isset = false; + object request_object = helper_valid_request_object(); + msgpack_rpc_from_object(request_object, &pk); + msgpack_object deserialized_req; + msgpack_unpack(sbuf.data, sbuf.size, NULL, &mempool, &deserialized_req); + assert_false(msgpack_rpc_is_notification(&deserialized_req)); + assert_non_null(msgpack_rpc_msg_id(&deserialized_req)); + uint64_t msgid_req = 1234; + msgpack_rpc_validate(&msgid_req, &deserialized_req, &err); + assert_false(err.isset); + msgpack_object *deserialized_req_args = msgpack_rpc_args(&deserialized_req); + assert_non_null(deserialized_req_args); + msgpack_object *deserialized_req_method = msgpack_rpc_method(&deserialized_req); + assert_non_null(deserialized_req_method); + + msgpack_sbuffer_clear(&sbuf); + api_free_object(serialize_object); + api_free_array(deserialized_array); + api_free_object(deserialized_object); + api_free_object(notification_object); + api_free_object(request_object); msgpack_zone_destroy(&mempool); msgpack_sbuffer_destroy(&sbuf); } From 8b6489d9ae352264f3b458bf496dc14d41f275b8 Mon Sep 17 00:00:00 2001 From: Stephan Zeisberg Date: Mon, 31 Oct 2016 16:51:35 +0100 Subject: [PATCH 17/41] Pre-increment msgid before sending packet --- src/rpc/connection/connection.c | 8 +++++--- src/rpc/sb-rpc.h | 2 +- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/rpc/connection/connection.c b/src/rpc/connection/connection.c index 74acf13..d704ac2 100644 --- a/src/rpc/connection/connection.c +++ b/src/rpc/connection/connection.c @@ -600,8 +600,10 @@ object connection_send_request(char *pluginkey, string method, incref(con); + uint64_t msgid = con->msgid++; + msgpack_packer_init(&packer, &sbuf, msgpack_sbuffer_write); - msgpack_rpc_serialize_request(con->msgid++, method, args, &packer); + msgpack_rpc_serialize_request(msgid, method, args, &packer); api_free_array(args); @@ -612,7 +614,7 @@ object connection_send_request(char *pluginkey, string method, msgpack_sbuffer_clear(&sbuf); - struct callinfo cinfo = (struct callinfo) { con->msgid, false, false, NIL }; + struct callinfo cinfo = (struct callinfo) { msgid, false, false, NIL }; loop_wait_for_response(con, &cinfo); @@ -794,7 +796,7 @@ STATIC void connection_handle_response(struct connection *con, cinfo = kv_A(con->callvector, kv_size(con->callvector) - 1); - LOG_VERBOSE(VERBOSE_LEVEL_0, "received response: callinfo id = %u\n", + LOG_VERBOSE(VERBOSE_LEVEL_0, "received response: callinfo id = %lu\n", cinfo->msgid); cinfo->returned = true; diff --git a/src/rpc/sb-rpc.h b/src/rpc/sb-rpc.h index 57640d8..c7c2d25 100644 --- a/src/rpc/sb-rpc.h +++ b/src/rpc/sb-rpc.h @@ -222,7 +222,7 @@ struct connection { }; struct callinfo { - uint32_t msgid; + uint64_t msgid; bool returned; bool errored; object result; From dce4b8f5d2273a62a12921fc48de43235ba27b91 Mon Sep 17 00:00:00 2001 From: Stephan Zeisberg Date: Tue, 8 Nov 2016 14:17:55 +0100 Subject: [PATCH 18/41] Fix overwriting connection in hashmap --- src/rpc/connection/connection.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/rpc/connection/connection.c b/src/rpc/connection/connection.c index d704ac2..7a9fef0 100644 --- a/src/rpc/connection/connection.c +++ b/src/rpc/connection/connection.c @@ -413,6 +413,15 @@ STATIC void parse_cb(inputstream *istream, void *data, bool eof) con->cc.state = TUNNEL_INITIAL; } + if (hashmap_has(cstr_t, uint64_t)(pluginkeys, + con->cc.pluginkeystring)) { + LOG_WARNING("pluginkey already registered, closing connection"); + sbmemzero(con->cc.pluginkeystring, + sizeof con->cc.pluginkeystring); + connection_close(con); + goto end; + } + hashmap_put(cstr_t, uint64_t)(pluginkeys, con->cc.pluginkeystring, con->id); } From bf434e452675c62028c84e4b18dec11d4ec88444 Mon Sep 17 00:00:00 2001 From: Stephan Zeisberg Date: Mon, 14 Nov 2016 13:40:28 +0100 Subject: [PATCH 19/41] Include msgpack/libuv static cmake build scripts from neovim --- CMakeLists.txt | 16 +- Makefile | 59 +++++-- cmake/FindLIBUV.cmake | 105 +++++++++++- cmake/FindMSGPACK.cmake | 58 ++++++- third-party/CMakeLists.txt | 108 ++++++++++++ third-party/cmake/BuildLibuv.cmake | 102 +++++++++++ third-party/cmake/BuildMsgpack.cmake | 79 +++++++++ .../cmake/DownloadAndExtractFile.cmake | 162 ++++++++++++++++++ third-party/cmake/RemoveFiles.cmake | 5 + 9 files changed, 659 insertions(+), 35 deletions(-) create mode 100644 third-party/CMakeLists.txt create mode 100644 third-party/cmake/BuildLibuv.cmake create mode 100644 third-party/cmake/BuildMsgpack.cmake create mode 100644 third-party/cmake/DownloadAndExtractFile.cmake create mode 100644 third-party/cmake/RemoveFiles.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index b18d8cf..1e1c8e6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,6 +7,16 @@ option(CLANG_MEMORY_SANITIZER "Enable clang memory sanitizer." OFF) option(CLANG_THREAD_SANITIZER "Enable clang thread sanitizer." OFF) option(CLANG_ANALYZER "Enable clang static analyzer." OFF) +# Prefer our bundled versions of dependencies. +set(DEPS_PREFIX "${CMAKE_CURRENT_SOURCE_DIR}/.deps/usr" CACHE PATH "Path prefix for finding dependencies") +if(CMAKE_CROSSCOMPILING AND NOT UNIX) + list(INSERT CMAKE_FIND_ROOT_PATH 0 ${DEPS_PREFIX}) + list(INSERT CMAKE_PREFIX_PATH 0 ${DEPS_PREFIX}/../host/bin) +else() + list(INSERT CMAKE_PREFIX_PATH 0 ${DEPS_PREFIX}) + set(ENV{PKG_CONFIG_PATH} "$ENV{PKG_CONFIG_PATH}:${DEPS_PREFIX}/lib/pkgconfig") +endif() + list(APPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake") if(NOT CMAKE_BUILD_TYPE) @@ -279,7 +289,11 @@ endif() include_directories(${PROJECT_SOURCE_DIR}/src) include_directories(${PROJECT_SOURCE_DIR}/test) -include_directories(${BSD_INCLUDE_DIRS} ${LIBUV_INCLUDE_DIRS} ${MSGPACK_INCLUDE_DIRS} ${HIREDIS_INCLUDE_DIRS} ${CMOCKA_INCLUDE_DIRS}) +include_directories(SYSTEM ${BSD_INCLUDE_DIRS}) +include_directories(SYSTEM ${LIBUV_INCLUDE_DIRS}) +include_directories(SYSTEM ${MSGPACK_INCLUDE_DIRS}) +include_directories(SYSTEM ${HIREDIS_INCLUDE_DIRS}) +include_directories(SYSTEM ${CMOCKA_INCLUDE_DIRS}) # sb target add_executable(sb ${SPLONEBOX-SOURCES}) diff --git a/Makefile b/Makefile index a19af4e..a56f388 100644 --- a/Makefile +++ b/Makefile @@ -26,35 +26,56 @@ endif BUILD_CMD = $(BUILD_TOOL) $(VERBOSE_FLAG) +USE_BUNDLED_DEPS ?= + +ifneq (,$(USE_BUNDLED_DEPS)) + BUNDLED_CMAKE_FLAG := -DUSE_BUNDLED=$(USE_BUNDLED_DEPS) +endif + all: sb test sb-makekey sb-pluginkey -sb: - test -d $(BUILD_DIR) || mkdir $(BUILD_DIR) - cd out && cmake -G '$(BUILD_TYPE)' $(FLAGS) $(EXTRA_FLAGS) .. - $(BUILD_CMD) -C out sb +sb: build/.ran-cmake deps + +$(BUILD_CMD) -C build sb + +cmake: + touch CMakeLists.txt + $(MAKE) build/.ran-cmake + +build/.ran-cmake: | deps + cd build && cmake -G '$(BUILD_TYPE)' $(CMAKE_FLAGS) $(CMAKE_EXTRA_FLAGS) .. + touch $@ + +deps: | build/.ran-third-party-cmake +ifeq ($(call filter-true,$(USE_BUNDLED_DEPS)),) + +$(BUILD_CMD) -C .deps +endif + +build/.ran-third-party-cmake: +ifeq ($(call filter-true,$(USE_BUNDLED_DEPS)),) + mkdir -p .deps + cd .deps && \ + cmake -G '$(BUILD_TYPE)' $(BUNDLED_CMAKE_FLAG) $(BUNDLED_LUA_CMAKE_FLAG) \ + $(DEPS_CMAKE_FLAGS) ../third-party +endif + mkdir -p build + touch $@ -test: - test -d $(BUILD_DIR) || mkdir $(BUILD_DIR) - cd out && cmake -G '$(BUILD_TYPE)' $(FLAGS) $(EXTRA_FLAGS) .. - $(BUILD_CMD) -C out sb-test +test: build/.ran-cmake deps + +$(BUILD_CMD) -C build sb-test -sb-makekey: - test -d $(BUILD_DIR) || mkdir $(BUILD_DIR) - cd out && cmake -G '$(BUILD_TYPE)' $(FLAGS) $(EXTRA_FLAGS) .. - $(BUILD_CMD) -C out sb-makekey +sb-makekey: build/.ran-cmake deps + +$(BUILD_CMD) -C build sb-makekey -sb-pluginkey: - test -d $(BUILD_DIR) || mkdir $(BUILD_DIR) - cd out && cmake -G '$(BUILD_TYPE)' $(FLAGS) $(EXTRA_FLAGS) .. - $(BUILD_CMD) -C out sb-pluginkey +sb-pluginkey: build/.ran-cmake deps + +$(BUILD_CMD) -C build sb-pluginkey clean: - +test -d out && $(BUILD_CMD) -C out clean || true + +test -d build && $(BUILD_CMD) -C build clean || true distclean: clean - rm -rf out + rm -rf .deps build install: | sb +$(BUILD_CMD) -C out install -.PHONY: test clean distclean sb install sb-makekey +.PHONY: test clean distclean sb install sb-makekey deps cmake diff --git a/cmake/FindLIBUV.cmake b/cmake/FindLIBUV.cmake index 5affbc2..dcdd5e4 100644 --- a/cmake/FindLIBUV.cmake +++ b/cmake/FindLIBUV.cmake @@ -1,17 +1,108 @@ -find_package(PkgConfig) -if (PKG_CONFIG_FOUND) - pkg_check_modules(SHARED_LIBUV REQUIRED libuv) +# - Try to find libuv +# Once done, this will define +# +# LIBUV_FOUND - system has libuv +# LIBUV_INCLUDE_DIRS - the libuv include directories +# LIBUV_LIBRARIES - link these to use libuv +# +# Set the LIBUV_USE_STATIC variable to specify if static libraries should +# be preferred to shared ones. + +if(NOT LIBUV_USE_BUNDLED) + find_package(PkgConfig) + if (PKG_CONFIG_FOUND) + pkg_check_modules(PC_LIBUV QUIET libuv) + endif() +else() + set(PC_LIBUV_INCLUDEDIR) + set(PC_LIBUV_INCLUDE_DIRS) + set(PC_LIBUV_LIBDIR) + set(PC_LIBUV_LIBRARY_DIRS) + set(LIMIT_SEARCH NO_DEFAULT_PATH) endif() find_path(LIBUV_INCLUDE_DIR uv.h - HINTS ${SHARED_LIBUV_INCLUDEDIR} ${SHARED_LIBUV_INCLUDE_DIRS} + HINTS ${PC_LIBUV_INCLUDEDIR} ${PC_LIBUV_INCLUDE_DIRS} ${LIMIT_SEARCH}) -find_library(LIBUV_LIBRARY NAMES uv - HINTS ${SHARED_LIBUV_LIBDIR} ${SHARED_LIBUV_LIBRARY_DIRS} +# If we're asked to use static linkage, add libuv.a as a preferred library name. +if(LIBUV_USE_STATIC) + list(APPEND LIBUV_NAMES + "${CMAKE_STATIC_LIBRARY_PREFIX}uv${CMAKE_STATIC_LIBRARY_SUFFIX}") +endif(LIBUV_USE_STATIC) + +if(MSVC) + list(APPEND LIBUV_NAMES libuv) +else() + list(APPEND LIBUV_NAMES uv) +endif() + +find_library(LIBUV_LIBRARY NAMES ${LIBUV_NAMES} + HINTS ${PC_LIBUV_LIBDIR} ${PC_LIBUV_LIBRARY_DIRS} ${LIMIT_SEARCH}) mark_as_advanced(LIBUV_INCLUDE_DIR LIBUV_LIBRARY) -set(LIBUV_LIBRARIES ${LIBUV_LIBRARY} ${SHARED_LIBUV_LIBRARIES}) +if(PC_LIBUV_LIBRARIES) + list(REMOVE_ITEM PC_LIBUV_LIBRARIES uv) +endif() + +set(LIBUV_LIBRARIES ${LIBUV_LIBRARY} ${PC_LIBUV_LIBRARIES}) set(LIBUV_INCLUDE_DIRS ${LIBUV_INCLUDE_DIR}) + +# Deal with the fact that libuv.pc is missing important dependency information. + +include(CheckLibraryExists) + +check_library_exists(dl dlopen "dlfcn.h" HAVE_LIBDL) +if(HAVE_LIBDL) + list(APPEND LIBUV_LIBRARIES dl) +endif() + +check_library_exists(kstat kstat_lookup "kstat.h" HAVE_LIBKSTAT) +if(HAVE_LIBKSTAT) + list(APPEND LIBUV_LIBRARIES kstat) +endif() + +check_library_exists(kvm kvm_open "kvm.h" HAVE_LIBKVM) +if(HAVE_LIBKVM) + list(APPEND LIBUV_LIBRARIES kvm) +endif() + +check_library_exists(nsl gethostbyname "nsl.h" HAVE_LIBNSL) +if(HAVE_LIBNSL) + list(APPEND LIBUV_LIBRARIES nsl) +endif() + +check_library_exists(perfstat perfstat_cpu "libperfstat.h" HAVE_LIBPERFSTAT) +if(HAVE_LIBPERFSTAT) + list(APPEND LIBUV_LIBRARIES perfstat) +endif() + +check_library_exists(rt clock_gettime "time.h" HAVE_LIBRT) +if(HAVE_LIBRT) + list(APPEND LIBUV_LIBRARIES rt) +endif() + +check_library_exists(sendfile sendfile "" HAVE_LIBSENDFILE) +if(HAVE_LIBSENDFILE) + list(APPEND LIBUV_LIBRARIES sendfile) +endif() + +if(WIN32) + # check_library_exists() does not work for Win32 API calls in X86 due to name + # mangling calling conventions + list(APPEND LIBUV_LIBRARIES iphlpapi) + list(APPEND LIBUV_LIBRARIES psapi) + list(APPEND LIBUV_LIBRARIES userenv) + list(APPEND LIBUV_LIBRARIES ws2_32) +endif() + +include(FindPackageHandleStandardArgs) + +# handle the QUIETLY and REQUIRED arguments and set LIBUV_FOUND to TRUE +# if all listed variables are TRUE +find_package_handle_standard_args(LibUV DEFAULT_MSG + LIBUV_LIBRARY LIBUV_INCLUDE_DIR) + +mark_as_advanced(LIBUV_INCLUDE_DIR LIBUV_LIBRARY) diff --git a/cmake/FindMSGPACK.cmake b/cmake/FindMSGPACK.cmake index ac4006e..1774f59 100644 --- a/cmake/FindMSGPACK.cmake +++ b/cmake/FindMSGPACK.cmake @@ -1,21 +1,63 @@ -find_package(PkgConfig) -if (PKG_CONFIG_FOUND) - pkg_search_module(SHARED_MSGPACK QUIET +if(NOT MSGPACK_USE_BUNDLED) + find_package(PkgConfig) + if (PKG_CONFIG_FOUND) + pkg_search_module(PC_MSGPACK QUIET msgpackc>=${Msgpack_FIND_VERSION} msgpack>=${Msgpack_FIND_VERSION}) + endif() +else() + set(PC_MSGPACK_INCLUDEDIR) + set(PC_MSGPACK_INCLUDE_DIRS) + set(PC_MSGPACK_LIBDIR) + set(PC_MSGPACK_LIBRARY_DIRS) + set(LIMIT_SEARCH NO_DEFAULT_PATH) endif() -find_path(MSGPACK_INCLUDE_DIR msgpack.h - HINTS ${SHARED_MSGPACK_INCLUDEDIR} ${SHARED_MSGPACK_INCLUDE_DIRS} +set(MSGPACK_DEFINITIONS ${PC_MSGPACK_CFLAGS_OTHER}) + +find_path(MSGPACK_INCLUDE_DIR msgpack/version_master.h + HINTS ${PC_MSGPACK_INCLUDEDIR} ${PC_MSGPACK_INCLUDE_DIRS} ${LIMIT_SEARCH}) - -list(APPEND MSGPACK_NAMES msgpackc msgpack) + +if(MSGPACK_INCLUDE_DIR) + file(READ ${MSGPACK_INCLUDE_DIR}/msgpack/version_master.h msgpack_version_h) + string(REGEX REPLACE ".*MSGPACK_VERSION_MAJOR +([0-9]+).*" "\\1" MSGPACK_VERSION_MAJOR "${msgpack_version_h}") + string(REGEX REPLACE ".*MSGPACK_VERSION_MINOR +([0-9]+).*" "\\1" MSGPACK_VERSION_MINOR "${msgpack_version_h}") + string(REGEX REPLACE ".*MSGPACK_VERSION_REVISION +([0-9]+).*" "\\1" MSGPACK_VERSION_REVISION "${msgpack_version_h}") + set(MSGPACK_VERSION_STRING "${MSGPACK_VERSION_MAJOR}.${MSGPACK_VERSION_MINOR}.${MSGPACK_VERSION_REVISION}") +else() + set(MSGPACK_VERSION_STRING) +endif() + +# If we're asked to use static linkage, add libmsgpack{,c}.a as a preferred library name. +if(MSGPACK_USE_STATIC) + list(APPEND MSGPACK_NAMES + "${CMAKE_STATIC_LIBRARY_PREFIX}msgpackc${CMAKE_STATIC_LIBRARY_SUFFIX}" + "${CMAKE_STATIC_LIBRARY_PREFIX}msgpack${CMAKE_STATIC_LIBRARY_SUFFIX}") +endif() + +if(MSVC) + # The import library for the msgpack DLL has a different name + list(APPEND MSGPACK_NAMES msgpack_import) +else() + list(APPEND MSGPACK_NAMES msgpackc msgpack) +endif() find_library(MSGPACK_LIBRARY NAMES ${MSGPACK_NAMES} - HINTS ${SHARED_MSGPACK_LIBDIR} ${SHARED_MSGPACK_LIBRARY_DIRS} + # Check each directory for all names to avoid using headers/libraries from + # different places. + NAMES_PER_DIR + HINTS ${PC_MSGPACK_LIBDIR} ${PC_MSGPACK_LIBRARY_DIRS} ${LIMIT_SEARCH}) mark_as_advanced(MSGPACK_INCLUDE_DIR MSGPACK_LIBRARY) set(MSGPACK_LIBRARIES ${MSGPACK_LIBRARY}) set(MSGPACK_INCLUDE_DIRS ${MSGPACK_INCLUDE_DIR}) + +include(FindPackageHandleStandardArgs) +# handle the QUIETLY and REQUIRED arguments and set MSGPACK_FOUND to TRUE +# if all listed variables are TRUE +find_package_handle_standard_args(Msgpack + REQUIRED_VARS MSGPACK_LIBRARY MSGPACK_INCLUDE_DIR + VERSION_VAR MSGPACK_VERSION_STRING) diff --git a/third-party/CMakeLists.txt b/third-party/CMakeLists.txt new file mode 100644 index 0000000..2322ccc --- /dev/null +++ b/third-party/CMakeLists.txt @@ -0,0 +1,108 @@ +# This is not meant to be included by the top-level. +cmake_minimum_required (VERSION 2.8.7) +project(SPLONEBOX_DEPS) + +# Point CMake at any custom modules we may ship +list(APPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake") + +# In Windows/MSVC CMAKE_BUILD_TYPE changes the paths/linking of the build +# recipes (libuv, msgpack), make sure it is set +if(NOT CMAKE_BUILD_TYPE) + set(CMAKE_BUILD_TYPE Release) +endif() + +set(DEPS_INSTALL_DIR "${CMAKE_BINARY_DIR}/usr" CACHE PATH "Dependencies install directory.") +set(DEPS_BIN_DIR "${DEPS_INSTALL_DIR}/bin" CACHE PATH "Dependencies binary install directory.") +set(DEPS_LIB_DIR "${DEPS_INSTALL_DIR}/lib" CACHE PATH "Dependencies library install directory.") +set(DEPS_BUILD_DIR "${CMAKE_BINARY_DIR}/build" CACHE PATH "Dependencies build directory.") +set(DEPS_DOWNLOAD_DIR "${DEPS_BUILD_DIR}/downloads" CACHE PATH "Dependencies download directory.") + +option(USE_BUNDLED "Use bundled dependencies." ON) + +option(USE_BUNDLED_LIBUV "Use the bundled libuv." ${USE_BUNDLED}) +option(USE_BUNDLED_MSGPACK "Use the bundled msgpack." ${USE_BUNDLED}) + +#XXX(tarruda): Lua is only used for debugging the functional test client, no +# build it unless explicitly requested +option(USE_BUNDLED_LUA "Use the bundled version of lua." OFF) + +if(USE_BUNDLED AND (NOT WIN32)) + option(USE_BUNDLED_GPERF "Use the bundled version of gperf." ON) +else() + option(USE_BUNDLED_GPERF "Use the bundled version of gperf." OFF) +endif() + +option(USE_EXISTING_SRC_DIR "Skip download of deps sources in case of existing source directory." OFF) + +if(UNIX) + find_program(MAKE_PRG NAMES gmake make) + if(MAKE_PRG) + execute_process( + COMMAND "${MAKE_PRG}" --version + OUTPUT_VARIABLE MAKE_VERSION_INFO) + if(NOT "${OUTPUT_VARIABLE}" MATCHES ".*GNU.*") + unset(MAKE_PRG) + endif() + endif() + if(NOT MAKE_PRG) + message(FATAL_ERROR "GNU Make is required to build the dependencies.") + else() + message(STATUS "Found GNU Make at ${MAKE_PRG}") + endif() +endif() + +# When using make, use the $(MAKE) variable to avoid warning about the job +# server. +if(CMAKE_GENERATOR MATCHES "Makefiles") + set(MAKE_PRG "$(MAKE)") +endif() + +if(CMAKE_C_COMPILER_ARG1) + set(DEPS_C_COMPILER "${CMAKE_C_COMPILER} ${CMAKE_C_COMPILER_ARG1}") +else() + set(DEPS_C_COMPILER "${CMAKE_C_COMPILER}") +endif() + +# Cross compiling: use these for dependencies built for the +# HOST system, when not crosscompiling these should be the +# same as DEPS_*. Except when targeting Unix in which case +# want all the dependencies to use the same compiler. +if(CMAKE_CROSSCOMPILING AND NOT UNIX) + set(HOSTDEPS_INSTALL_DIR "${CMAKE_BINARY_DIR}/host") + set(HOSTDEPS_BIN_DIR "${HOSTDEPS_INSTALL_DIR}/bin") + set(HOSTDEPS_LIB_DIR "${HOSTDEPS_INSTALL_DIR}/lib") + set(HOSTDEPS_C_COMPILER "${HOST_C_COMPILER}") +else() + set(HOSTDEPS_INSTALL_DIR "${DEPS_INSTALL_DIR}") + set(HOSTDEPS_BIN_DIR "${DEPS_BIN_DIR}") + set(HOSTDEPS_LIB_DIR "${DEPS_LIB_DIR}") + set(HOSTDEPS_C_COMPILER "${DEPS_C_COMPILER}") +endif() + +include(ExternalProject) + +set(LIBUV_URL https://github.com/libuv/libuv/archive/v1.10.0.tar.gz) +set(LIBUV_SHA256 50f4ed57d65af4ab634e2cbdd90c49213020e15b4d77d3631feb633cbba9239f) + +set(MSGPACK_URL https://github.com/msgpack/msgpack-c/archive/cpp-2.0.0.tar.gz) +set(MSGPACK_SHA256 eb20b4bf15f20bad149ec82fffac74f16de2a8a797e321a3f8189d63263a511e) + +if(USE_BUNDLED_LIBUV) + include(BuildLibuv) +endif() + +if(USE_BUNDLED_MSGPACK) + include(BuildMsgpack) +endif() + + +add_custom_target(clean-shared-libraries + COMMAND ${CMAKE_COMMAND} + -DREMOVE_FILE_GLOB=${DEPS_INSTALL_DIR}/lib/${CMAKE_SHARED_LIBRARY_PREFIX}*${CMAKE_SHARED_LIBRARY_SUFFIX}* + -P ${PROJECT_SOURCE_DIR}/cmake/RemoveFiles.cmake + DEPENDS ${THIRD_PARTY_DEPS} +) + +add_custom_target(third-party ALL + COMMAND ${CMAKE_COMMAND} -E touch .third-party + DEPENDS clean-shared-libraries) diff --git a/third-party/cmake/BuildLibuv.cmake b/third-party/cmake/BuildLibuv.cmake new file mode 100644 index 0000000..5482f28 --- /dev/null +++ b/third-party/cmake/BuildLibuv.cmake @@ -0,0 +1,102 @@ +include(CMakeParseArguments) + +# BuildLibuv(TARGET targetname CONFIGURE_COMMAND ... BUILD_COMMAND ... INSTALL_COMMAND ...) +# Reusable function to build libuv, wraps ExternalProject_Add. +# Failing to pass a command argument will result in no command being run +function(BuildLibuv) + cmake_parse_arguments(_libuv + "BUILD_IN_SOURCE" + "TARGET" + "CONFIGURE_COMMAND;BUILD_COMMAND;INSTALL_COMMAND" + ${ARGN}) + + if(NOT _libuv_CONFIGURE_COMMAND AND NOT _libuv_BUILD_COMMAND + AND NOT _libuv_INSTALL_COMMAND) + message(FATAL_ERROR "Must pass at least one of CONFIGURE_COMMAND, BUILD_COMMAND, INSTALL_COMMAND") + endif() + if(NOT _libuv_TARGET) + set(_libuv_TARGET "libuv") + endif() + + ExternalProject_Add(${_libuv_TARGET} + PREFIX ${DEPS_BUILD_DIR} + URL ${LIBUV_URL} + DOWNLOAD_DIR ${DEPS_DOWNLOAD_DIR}/libuv + DOWNLOAD_COMMAND ${CMAKE_COMMAND} + -DPREFIX=${DEPS_BUILD_DIR} + -DDOWNLOAD_DIR=${DEPS_DOWNLOAD_DIR}/libuv + -DURL=${LIBUV_URL} + -DEXPECTED_SHA256=${LIBUV_SHA256} + -DTARGET=${_libuv_TARGET} + -DUSE_EXISTING_SRC_DIR=${USE_EXISTING_SRC_DIR} + -P ${CMAKE_CURRENT_SOURCE_DIR}/cmake/DownloadAndExtractFile.cmake + BUILD_IN_SOURCE ${_libuv_BUILD_IN_SOURCE} + CONFIGURE_COMMAND "${_libuv_CONFIGURE_COMMAND}" + BUILD_COMMAND "${_libuv_BUILD_COMMAND}" + INSTALL_COMMAND "${_libuv_INSTALL_COMMAND}") +endfunction() + +set(UNIX_CFGCMD sh ${DEPS_BUILD_DIR}/src/libuv/autogen.sh && + ${DEPS_BUILD_DIR}/src/libuv/configure --with-pic --disable-shared + --prefix=${DEPS_INSTALL_DIR} --libdir=${DEPS_INSTALL_DIR}/lib + CC=${DEPS_C_COMPILER}) + +if(UNIX) + BuildLibuv( + CONFIGURE_COMMAND ${UNIX_CFGCMD} + INSTALL_COMMAND ${MAKE_PRG} V=1 install) + +elseif(MINGW AND CMAKE_CROSSCOMPILING) + # Build libuv for the host + BuildLibuv(TARGET libuv_host + CONFIGURE_COMMAND sh ${DEPS_BUILD_DIR}/src/libuv_host/autogen.sh && ${DEPS_BUILD_DIR}/src/libuv_host/configure --with-pic --disable-shared --prefix=${HOSTDEPS_INSTALL_DIR} CC=${HOST_C_COMPILER} + INSTALL_COMMAND ${MAKE_PRG} V=1 install) + + # Build libuv for the target + BuildLibuv( + CONFIGURE_COMMAND ${UNIX_CFGCMD} --host=${CROSS_TARGET} + INSTALL_COMMAND ${MAKE_PRG} V=1 install) + +elseif(MINGW) + + # Native MinGW + BuildLibUv(BUILD_IN_SOURCE + BUILD_COMMAND ${CMAKE_MAKE_PROGRAM} -f Makefile.mingw + INSTALL_COMMAND ${CMAKE_COMMAND} -E make_directory ${DEPS_INSTALL_DIR}/lib + COMMAND ${CMAKE_COMMAND} -E copy ${DEPS_BUILD_DIR}/src/libuv/libuv.a ${DEPS_INSTALL_DIR}/lib + COMMAND ${CMAKE_COMMAND} -E make_directory ${DEPS_INSTALL_DIR}/include + COMMAND ${CMAKE_COMMAND} -E copy_directory ${DEPS_BUILD_DIR}/src/libuv/include ${DEPS_INSTALL_DIR}/include + ) + +elseif(WIN32 AND MSVC) + + find_package(PythonInterp 2.6 REQUIRED) + if(NOT PYTHONINTERP_FOUND OR PYTHON_VERSION_MAJOR GREATER 2) + message(FATAL_ERROR "Python2 is required to build libuv on windows, use -DPYTHON_EXECUTABLE to set a python interpreter") + endif() + + string(FIND ${CMAKE_GENERATOR} Win64 VS_WIN64) + if(VS_WIN64 EQUAL -1) + set(VS_ARCH x86) + else() + set(VS_ARCH x64) + endif() + string(TOLOWER ${CMAKE_BUILD_TYPE} LOWERCASE_BUILD_TYPE) + set(UV_OUTPUT_DIR ${DEPS_BUILD_DIR}/src/libuv/${CMAKE_BUILD_TYPE}) + BuildLibUv( + BUILD_COMMAND set PYTHON=${PYTHON_EXECUTABLE} COMMAND ${DEPS_BUILD_DIR}/src/libuv/vcbuild.bat shared ${LOWERCASE_BUILD_TYPE} ${VS_ARCH} + INSTALL_COMMAND ${CMAKE_COMMAND} -E make_directory ${DEPS_INSTALL_DIR}/lib + COMMAND ${CMAKE_COMMAND} -E make_directory ${DEPS_INSTALL_DIR}/bin + COMMAND ${CMAKE_COMMAND} -E copy ${UV_OUTPUT_DIR}/libuv.lib ${DEPS_INSTALL_DIR}/lib + # Some applications (lua-client/luarocks) look for uv.lib instead of libuv.lib + COMMAND ${CMAKE_COMMAND} -E copy ${UV_OUTPUT_DIR}/libuv.lib ${DEPS_INSTALL_DIR}/lib/uv.lib + COMMAND ${CMAKE_COMMAND} -E copy ${UV_OUTPUT_DIR}/libuv.dll ${DEPS_INSTALL_DIR}/bin/ + COMMAND ${CMAKE_COMMAND} -E copy ${UV_OUTPUT_DIR}/libuv.dll ${DEPS_INSTALL_DIR}/bin/uv.dll + COMMAND ${CMAKE_COMMAND} -E make_directory ${DEPS_INSTALL_DIR}/include + COMMAND ${CMAKE_COMMAND} -E copy_directory ${DEPS_BUILD_DIR}/src/libuv/include ${DEPS_INSTALL_DIR}/include) + +else() + message(FATAL_ERROR "Trying to build libuv in an unsupported system ${CMAKE_SYSTEM_NAME}/${CMAKE_C_COMPILER_ID}") +endif() + +list(APPEND THIRD_PARTY_DEPS libuv) diff --git a/third-party/cmake/BuildMsgpack.cmake b/third-party/cmake/BuildMsgpack.cmake new file mode 100644 index 0000000..6b38508 --- /dev/null +++ b/third-party/cmake/BuildMsgpack.cmake @@ -0,0 +1,79 @@ +include(CMakeParseArguments) + +# BuildMsgpack(CONFIGURE_COMMAND ... BUILD_COMMAND ... INSTALL_COMMAND ...) +# Reusable function to build msgpack, wraps ExternalProject_Add. +# Failing to pass a command argument will result in no command being run +function(BuildMsgpack) + cmake_parse_arguments(_msgpack + "" + "" + "CONFIGURE_COMMAND;BUILD_COMMAND;INSTALL_COMMAND" + ${ARGN}) + + if(NOT _msgpack_CONFIGURE_COMMAND AND NOT _msgpack_BUILD_COMMAND + AND NOT _msgpack_INSTALL_COMMAND) + message(FATAL_ERROR "Must pass at least one of CONFIGURE_COMMAND, BUILD_COMMAND, INSTALL_COMMAND") + endif() + + ExternalProject_Add(msgpack + PREFIX ${DEPS_BUILD_DIR} + URL ${MSGPACK_URL} + DOWNLOAD_DIR ${DEPS_DOWNLOAD_DIR}/msgpack + DOWNLOAD_COMMAND ${CMAKE_COMMAND} + -DPREFIX=${DEPS_BUILD_DIR} + -DDOWNLOAD_DIR=${DEPS_DOWNLOAD_DIR}/msgpack + -DURL=${MSGPACK_URL} + -DEXPECTED_SHA256=${MSGPACK_SHA256} + -DTARGET=msgpack + -DUSE_EXISTING_SRC_DIR=${USE_EXISTING_SRC_DIR} + -P ${CMAKE_CURRENT_SOURCE_DIR}/cmake/DownloadAndExtractFile.cmake + CONFIGURE_COMMAND "${_msgpack_CONFIGURE_COMMAND}" + BUILD_COMMAND "${_msgpack_BUILD_COMMAND}" + INSTALL_COMMAND "${_msgpack_INSTALL_COMMAND}") +endfunction() + +set(MSGPACK_CONFIGURE_COMMAND ${CMAKE_COMMAND} ${DEPS_BUILD_DIR}/src/msgpack + -DMSGPACK_ENABLE_CXX=OFF + -DMSGPACK_BUILD_TESTS=OFF + -DCMAKE_INSTALL_PREFIX=${DEPS_INSTALL_DIR} + -DCMAKE_C_COMPILER=${CMAKE_C_COMPILER} + -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} + "-DCMAKE_C_FLAGS:STRING=${CMAKE_C_COMPILER_ARG1} -fPIC" + -DCMAKE_GENERATOR=${CMAKE_GENERATOR}) + +set(MSGPACK_BUILD_COMMAND ${CMAKE_COMMAND} --build . --config ${CMAKE_BUILD_TYPE}) +set(MSGPACK_INSTALL_COMMAND ${CMAKE_COMMAND} --build . --target install --config ${CMAKE_BUILD_TYPE}) + +if(MINGW AND CMAKE_CROSSCOMPILING) + get_filename_component(TOOLCHAIN ${CMAKE_TOOLCHAIN_FILE} REALPATH) + set(MSGPACK_CONFIGURE_COMMAND ${CMAKE_COMMAND} ${DEPS_BUILD_DIR}/src/msgpack + -DMSGPACK_ENABLE_CXX=OFF + -DMSGPACK_BUILD_TESTS=OFF + -DCMAKE_INSTALL_PREFIX=${DEPS_INSTALL_DIR} + # Pass toolchain + -DCMAKE_TOOLCHAIN_FILE=${TOOLCHAIN} + -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} + # Hack to avoid -rdynamic in Mingw + -DCMAKE_SHARED_LIBRARY_LINK_C_FLAGS="") +elseif(MSVC) + # Same as Unix without fPIC + set(MSGPACK_CONFIGURE_COMMAND ${CMAKE_COMMAND} ${DEPS_BUILD_DIR}/src/msgpack + -DMSGPACK_ENABLE_CXX=OFF + -DMSGPACK_BUILD_TESTS=OFF + -DCMAKE_INSTALL_PREFIX=${DEPS_INSTALL_DIR} + -DCMAKE_C_COMPILER=${CMAKE_C_COMPILER} + "-DCMAKE_C_FLAGS:STRING=${CMAKE_C_COMPILER_ARG1}" + -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} + # Make sure we use the same generator, otherwise we may + # accidentaly end up using different MSVC runtimes + -DCMAKE_GENERATOR=${CMAKE_GENERATOR}) + # Place the DLL in the bin folder + set(MSGPACK_INSTALL_COMMAND ${MSGPACK_INSTALL_COMMAND} + COMMAND ${CMAKE_COMMAND} -E copy ${DEPS_INSTALL_DIR}/lib/msgpack.dll ${DEPS_INSTALL_DIR}/bin) +endif() + +BuildMsgpack(CONFIGURE_COMMAND ${MSGPACK_CONFIGURE_COMMAND} + BUILD_COMMAND ${MSGPACK_BUILD_COMMAND} + INSTALL_COMMAND ${MSGPACK_INSTALL_COMMAND}) + +list(APPEND THIRD_PARTY_DEPS msgpack) diff --git a/third-party/cmake/DownloadAndExtractFile.cmake b/third-party/cmake/DownloadAndExtractFile.cmake new file mode 100644 index 0000000..24e431b --- /dev/null +++ b/third-party/cmake/DownloadAndExtractFile.cmake @@ -0,0 +1,162 @@ +if(NOT DEFINED PREFIX) + message(FATAL_ERROR "PREFIX must be defined.") +endif() + +if(NOT DEFINED URL) + message(FATAL_ERROR "URL must be defined.") +endif() + +if(NOT DEFINED DOWNLOAD_DIR) + message(FATAL_ERROR "DOWNLOAD_DIR must be defined.") +endif() + +if(NOT DEFINED EXPECTED_SHA256) + message(FATAL_ERROR "EXPECTED_SHA256 must be defined.") +endif() + +if(NOT DEFINED TARGET) + message(FATAL_ERROR "TARGET must be defined.") +endif() + +set(SRC_DIR ${PREFIX}/src/${TARGET}) + +# Check whether the source has been downloaded. If true, skip it. +# Useful for external downloads like homebrew. +if(USE_EXISTING_SRC_DIR) + if(EXISTS "${SRC_DIR}" AND IS_DIRECTORY "${SRC_DIR}") + file(GLOB EXISTED_FILES "${SRC_DIR}/*") + if(EXISTED_FILES) + message(STATUS "${SRC_DIR} is found and not empty, skipping download and extraction. ") + return() + endif() + endif() + message(FATAL_ERROR "USE_EXISTING_SRC_DIR set to ON, but '${SRC_DIR}' does not exist or is empty.") +endif() + +# Taken from ExternalProject_Add. Let's hope we can drop this one day when +# ExternalProject_Add allows you to disable SHOW_PROGRESS on the file download. +if(TIMEOUT) + set(timeout_args TIMEOUT ${timeout}) + set(timeout_msg "${timeout} seconds") +else() + set(timeout_args "# no TIMEOUT") + set(timeout_msg "none") +endif() + +string(REGEX MATCH "[^/\\?]*$" fname "${URL}") +if(NOT "${fname}" MATCHES "(\\.|=)(bz2|tar|tgz|tar\\.gz|zip)$") + string(REGEX MATCH "([^/\\?]+(\\.|=)(bz2|tar|tgz|tar\\.gz|zip))/.*$" match_result "${URL}") + set(fname "${CMAKE_MATCH_1}") +endif() +if(NOT "${fname}" MATCHES "(\\.|=)(bz2|tar|tgz|tar\\.gz|zip)$") + message(FATAL_ERROR "Could not extract tarball filename from url:\n ${url}") +endif() +string(REPLACE ";" "-" fname "${fname}") + +set(file ${DOWNLOAD_DIR}/${fname}) +message(STATUS "file: ${file}") + +message(STATUS "downloading... + src='${URL}' + dst='${file}' + timeout='${timeout_msg}'") + +file(DOWNLOAD ${URL} ${file} + ${timeout_args} + ${hash_args} + STATUS status + LOG log) + +list(GET status 0 status_code) +list(GET status 1 status_string) + +if(NOT status_code EQUAL 0) + message(FATAL_ERROR "error: downloading '${URL}' failed + status_code: ${status_code} + status_string: ${status_string} + log: ${log} +") +endif() + +set(NULL_SHA256 "0000000000000000000000000000000000000000000000000000000000000000") + +# Allow users to use "SKIP" or "skip" as the sha256 to skip checking the hash. +# You can still use the all zeros hash too. +if((EXPECTED_SHA256 STREQUAL "SKIP") OR (EXPECTED_SHA256 STREQUAL "skip")) + set(EXPECTED_SHA256 ${NULL_SHA256}) +endif() + +# We could avoid computing the SHA256 entirely if a NULL_SHA256 was given, +# but we want to warn users of an empty file. +file(SHA256 ${file} ACTUAL_SHA256) +if(ACTUAL_SHA256 STREQUAL "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855") + # File was empty. It's likely due to lack of SSL support. + message(FATAL_ERROR + "Failed to download ${URL}. The file is empty and likely means CMake " + "was built without SSL support. Please use a version of CMake with " + "proper SSL support. See " + "https://github.com/neovim/neovim/wiki/Building-Neovim#build-prerequisites " + "for more information.") +elseif((NOT EXPECTED_SHA256 STREQUAL NULL_SHA256) AND + (NOT EXPECTED_SHA256 STREQUAL ACTUAL_SHA256)) + # Wasn't a NULL SHA256 and we didn't match, so we fail. + message(FATAL_ERROR + "Failed to download ${URL}. Expected a SHA256 of " + "${EXPECTED_SHA256} but got ${ACTUAL_SHA256} instead.") +endif() + +message(STATUS "downloading... done") + +# Slurped from a generated extract-TARGET.cmake file. +message(STATUS "extracting... + src='${file}' + dst='${SRC_DIR}'") + +if(NOT EXISTS "${file}") + message(FATAL_ERROR "error: file to extract does not exist: '${file}'") +endif() + +# Prepare a space for extracting: +# +set(i 1234) +while(EXISTS "${SRC_DIR}/../ex-${TARGET}${i}") + math(EXPR i "${i} + 1") +endwhile() +set(ut_dir "${SRC_DIR}/../ex-${TARGET}${i}") +file(MAKE_DIRECTORY "${ut_dir}") + +# Extract it: +# +message(STATUS "extracting... [tar xfz]") +execute_process(COMMAND ${CMAKE_COMMAND} -E tar xfz ${file} + WORKING_DIRECTORY ${ut_dir} + RESULT_VARIABLE rv) + +if(NOT rv EQUAL 0) + message(STATUS "extracting... [error clean up]") + file(REMOVE_RECURSE "${ut_dir}") + message(FATAL_ERROR "error: extract of '${file}' failed") +endif() + +# Analyze what came out of the tar file: +# +message(STATUS "extracting... [analysis]") +file(GLOB contents "${ut_dir}/*") +list(LENGTH contents n) +if(NOT n EQUAL 1 OR NOT IS_DIRECTORY "${contents}") + set(contents "${ut_dir}") +endif() + +# Move "the one" directory to the final directory: +# +message(STATUS "extracting... [rename]") +file(REMOVE_RECURSE ${SRC_DIR}) +get_filename_component(contents ${contents} ABSOLUTE) +file(RENAME ${contents} ${SRC_DIR}) + +# Clean up: +# +message(STATUS "extracting... [clean up]") +file(REMOVE_RECURSE "${ut_dir}") + +message(STATUS "extracting... done") diff --git a/third-party/cmake/RemoveFiles.cmake b/third-party/cmake/RemoveFiles.cmake new file mode 100644 index 0000000..88e2bc7 --- /dev/null +++ b/third-party/cmake/RemoveFiles.cmake @@ -0,0 +1,5 @@ +file(GLOB_RECURSE FILES_TO_REMOVE ${REMOVE_FILE_GLOB}) + +if(FILES_TO_REMOVE) + file(REMOVE ${FILES_TO_REMOVE}) +endif() From be624ab25965707b42d53070c1c5dfa17a359262 Mon Sep 17 00:00:00 2001 From: Stephan Zeisberg Date: Mon, 14 Nov 2016 13:53:42 +0100 Subject: [PATCH 20/41] Switch to multiqueue neovim implementation and refactor uv loop handling This commit has lots of changes, but actually only the event queue implementation changed to the multiqueue implementation from neovim (which is more generic). Second change is a refactoring of the event loop implementation, which was implemented in unusable way and now is easy usable. --- CMakeLists.txt | 10 +- src/main.c | 17 +- src/queue.h | 796 ++------------------ src/rpc/connection/connection.c | 19 +- src/rpc/connection/connection.h | 49 +- src/rpc/connection/event.c | 240 +++--- src/rpc/connection/event.h | 20 +- src/rpc/connection/loop.c | 115 ++- src/rpc/connection/server.c | 10 +- src/rpc/sb-rpc.h | 145 +--- src/sb-common.h | 3 - src/signal.c | 3 +- test/functional/dispatch-handle-broadcast.c | 1 + test/functional/dispatch-handle-register.c | 1 + test/functional/dispatch-handle-result.c | 1 + test/functional/dispatch-handle-run.c | 1 + test/functional/dispatch-handle-subscribe.c | 1 + test/helper-validate.c | 8 +- test/main.c | 2 + test/test-list.h | 3 - test/unit/server-start.c | 9 +- test/unit/server-stop.c | 9 +- test/wrapper-functions.c | 5 +- 23 files changed, 416 insertions(+), 1052 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 1e1c8e6..fdd815d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -107,8 +107,10 @@ file(GLOB MANPAGES # splonebox target sources set(SPLONEBOX-SOURCES src/main.c + src/main.h src/sb-common.h src/khash.h + src/klist.h src/kvec.h src/queue.h src/string.c @@ -159,6 +161,7 @@ set(SPLONEBOX-SOURCES src/rpc/connection/crypto.c src/rpc/connection/crypto.h src/rpc/connection/loop.c + src/rpc/connection/loop.h src/rpc/msgpack/helpers.c src/rpc/msgpack/helpers.h src/rpc/db/sb-db.h @@ -193,8 +196,10 @@ set(SB-MAKEKEY-SOURCES # splonebox test(s) sources set(TEST-SOURCES + src/main.h src/sb-common.h src/khash.h + src/klist.h src/queue.h src/string.c src/reallocarray.c @@ -244,6 +249,7 @@ set(TEST-SOURCES src/rpc/connection/crypto.c src/rpc/connection/crypto.h src/rpc/connection/loop.c + src/rpc/connection/loop.h src/rpc/msgpack/helpers.c src/rpc/msgpack/helpers.h src/rpc/db/sb-db.h @@ -262,8 +268,6 @@ set(TEST-SOURCES test/unit/server-start.c test/unit/server-stop.c test/unit/dispatch-table-get.c - test/unit/event-queue-put.c - test/unit/event-queue-get.c test/functional/db-connect.c test/functional/db-plugin-add.c test/functional/db-pluginkey-verify.c @@ -315,7 +319,7 @@ add_executable(sb-test ${TEST-SOURCES}) add_executable(sb-pluginkey ${SB-PLUGINKEY-SOURCES}) # wrap some functions for testing -set_property(TARGET sb-test APPEND_STRING PROPERTY LINK_FLAGS "-Wl,--wrap=outputstream_write,--wrap=loop_wait_for_response,--wrap=crypto_write ") +set_property(TARGET sb-test APPEND_STRING PROPERTY LINK_FLAGS "-Wl,--wrap=outputstream_write,--wrap=loop_process_events_until,--wrap=crypto_write ") set_property(TARGET sb-test APPEND_STRING PROPERTY COMPILE_FLAGS "-DBOX_UNIT_TESTS ") target_link_libraries(sb-test diff --git a/src/main.c b/src/main.c index 86eaa07..7919003 100644 --- a/src/main.c +++ b/src/main.c @@ -22,9 +22,10 @@ #include "tweetnacl.h" #include "rpc/sb-rpc.h" #include "rpc/db/sb-db.h" +#include "main.h" int8_t verbose_level; -uv_loop_t loop; +loop main_loop; int main(int argc, char **argv) { @@ -38,7 +39,7 @@ int main(int argc, char **argv) abort(); } - uv_loop_init(&loop); + loop_init(&main_loop, NULL); crypto_init(); @@ -60,12 +61,6 @@ int main(int argc, char **argv) abort(); } - /* initialize event queue */ - if (event_initialize() == -1) { - LOG_ERROR("Failed to initialize event queue."); - abort(); - } - /* initialize connections */ if (connection_init() == -1) { LOG_ERROR("Failed to initialise connections."); @@ -85,9 +80,9 @@ int main(int argc, char **argv) server_start_pipe(globaloptions->ApiNamedPipeListen); } - uv_run(&loop, UV_RUN_DEFAULT); - - options_free(globaloptions); + for (;;) { + LOOP_PROCESS_EVENTS_UNTIL(&main_loop, main_loop.events, 2000, false); + } return (0); } diff --git a/src/queue.h b/src/queue.h index 1be9e9c..1c52ad8 100644 --- a/src/queue.h +++ b/src/queue.h @@ -1,753 +1,85 @@ -/*- - * Copyright (c) 1991, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. 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. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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. - * - * @(#)queue.h 8.5 (Berkeley) 8/20/94 - * $FreeBSD$ - */ -#ifndef _SYS_QUEUE_H_ -#define _SYS_QUEUE_H_ +// Copyright (c) 2013, Ben Noordhuis +// +// Permission to use, copy, modify, and/or distribute this software for any +// purpose with or without fee is hereby granted, provided that the above +// copyright notice and this permission notice appear in all copies. +// +// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -#include +#pragma once -/* - * This file defines four types of data structures: singly-linked lists, - * singly-linked tail queues, lists and tail queues. - * - * A singly-linked list is headed by a single forward pointer. The elements - * are singly linked for minimum space and pointer manipulation overhead at - * the expense of O(n) removal for arbitrary elements. New elements can be - * added to the list after an existing element or at the head of the list. - * Elements being removed from the head of the list should use the explicit - * macro for this purpose for optimum efficiency. A singly-linked list may - * only be traversed in the forward direction. Singly-linked lists are ideal - * for applications with large datasets and few or no removals or for - * implementing a LIFO queue. - * - * A singly-linked tail queue is headed by a pair of pointers, one to the - * head of the list and the other to the tail of the list. The elements are - * singly linked for minimum space and pointer manipulation overhead at the - * expense of O(n) removal for arbitrary elements. New elements can be added - * to the list after an existing element, at the head of the list, or at the - * end of the list. Elements being removed from the head of the tail queue - * should use the explicit macro for this purpose for optimum efficiency. - * A singly-linked tail queue may only be traversed in the forward direction. - * Singly-linked tail queues are ideal for applications with large datasets - * and few or no removals or for implementing a FIFO queue. - * - * A list is headed by a single forward pointer (or an array of forward - * pointers for a hash table header). The elements are doubly linked - * so that an arbitrary element can be removed without a need to - * traverse the list. New elements can be added to the list before - * or after an existing element or at the head of the list. A list - * may be traversed in either direction. - * - * A tail queue is headed by a pair of pointers, one to the head of the - * list and the other to the tail of the list. The elements are doubly - * linked so that an arbitrary element can be removed without a need to - * traverse the list. New elements can be added to the list before or - * after an existing element, at the head of the list, or at the end of - * the list. A tail queue may be traversed in either direction. - * - * For details on the use of these macros, see the queue(3) manual page. - * - * - * SLIST LIST STAILQ TAILQ - * _HEAD + + + + - * _CLASS_HEAD + + + + - * _HEAD_INITIALIZER + + + + - * _ENTRY + + + + - * _CLASS_ENTRY + + + + - * _INIT + + + + - * _EMPTY + + + + - * _FIRST + + + + - * _NEXT + + + + - * _PREV - + - + - * _LAST - - + + - * _FOREACH + + + + - * _FOREACH_FROM + + + + - * _FOREACH_SAFE + + + + - * _FOREACH_FROM_SAFE + + + + - * _FOREACH_REVERSE - - - + - * _FOREACH_REVERSE_FROM - - - + - * _FOREACH_REVERSE_SAFE - - - + - * _FOREACH_REVERSE_FROM_SAFE - - - + - * _INSERT_HEAD + + + + - * _INSERT_BEFORE - + - + - * _INSERT_AFTER + + + + - * _INSERT_TAIL - - + + - * _CONCAT - - + + - * _REMOVE_AFTER + - + - - * _REMOVE_HEAD + - + - - * _REMOVE + + + + - * _SWAP + + + + - * - */ -#ifdef QUEUE_MACRO_DEBUG -/* Store the last 2 places the queue element or head was altered */ -struct qm_trace { - unsigned long lastline; - unsigned long prevline; - const char *lastfile; - const char *prevfile; -}; +#include -#define TRACEBUF struct qm_trace trace; -#define TRACEBUF_INITIALIZER { __LINE__, 0, __FILE__, NULL } , -#define TRASHIT(x) do {(x) = (void *)-1;} while (0) -#define QMD_SAVELINK(name, link) void **name = (void *)&(link) +typedef struct _queue { + struct _queue *next; + struct _queue *prev; +} QUEUE; -#define QMD_TRACE_HEAD(head) do { \ - (head)->trace.prevline = (head)->trace.lastline; \ - (head)->trace.prevfile = (head)->trace.lastfile; \ - (head)->trace.lastline = __LINE__; \ - (head)->trace.lastfile = __FILE__; \ -} while (0) +// Public macros. +#define QUEUE_DATA(ptr, type, field) \ + ((type *)(void *)((char *)(ptr) - offsetof(type, field))) -#define QMD_TRACE_ELEM(elem) do { \ - (elem)->trace.prevline = (elem)->trace.lastline; \ - (elem)->trace.prevfile = (elem)->trace.lastfile; \ - (elem)->trace.lastline = __LINE__; \ - (elem)->trace.lastfile = __FILE__; \ -} while (0) +#define QUEUE_FOREACH(q, h) \ + for ( /* NOLINT(readability/braces) */ \ + (q) = (h)->next; (q) != (h); (q) = (q)->next) -#else -#define QMD_TRACE_ELEM(elem) -#define QMD_TRACE_HEAD(head) -#define QMD_SAVELINK(name, link) -#define TRACEBUF -#define TRACEBUF_INITIALIZER -#define TRASHIT(x) -#endif /* QUEUE_MACRO_DEBUG */ - -#ifdef __cplusplus -/* - * In C++ there can be structure lists and class lists: - */ -#define QUEUE_TYPEOF(type) type -#else -#define QUEUE_TYPEOF(type) struct type -#endif - -/* - * Singly-linked List declarations. - */ -#define SLIST_HEAD(name, type) \ -struct name { \ - struct type *slh_first; /* first element */ \ -} - -#define SLIST_CLASS_HEAD(name, type) \ -struct name { \ - class type *slh_first; /* first element */ \ -} - -#define SLIST_HEAD_INITIALIZER(head) \ - { NULL } - -#define SLIST_ENTRY(type) \ -struct { \ - struct type *sle_next; /* next element */ \ -} - -#define SLIST_CLASS_ENTRY(type) \ -struct { \ - class type *sle_next; /* next element */ \ -} - -/* - * Singly-linked List functions. - */ -#define SLIST_EMPTY(head) ((head)->slh_first == NULL) - -#define SLIST_FIRST(head) ((head)->slh_first) - -#define SLIST_FOREACH(var, head, field) \ - for ((var) = SLIST_FIRST((head)); \ - (var); \ - (var) = SLIST_NEXT((var), field)) - -#define SLIST_FOREACH_FROM(var, head, field) \ - for ((var) = ((var) ? (var) : SLIST_FIRST((head))); \ - (var); \ - (var) = SLIST_NEXT((var), field)) - -#define SLIST_FOREACH_SAFE(var, head, field, tvar) \ - for ((var) = SLIST_FIRST((head)); \ - (var) && ((tvar) = SLIST_NEXT((var), field), 1); \ - (var) = (tvar)) - -#define SLIST_FOREACH_FROM_SAFE(var, head, field, tvar) \ - for ((var) = ((var) ? (var) : SLIST_FIRST((head))); \ - (var) && ((tvar) = SLIST_NEXT((var), field), 1); \ - (var) = (tvar)) - -#define SLIST_FOREACH_PREVPTR(var, varp, head, field) \ - for ((varp) = &SLIST_FIRST((head)); \ - ((var) = *(varp)) != NULL; \ - (varp) = &SLIST_NEXT((var), field)) - -#define SLIST_INIT(head) do { \ - SLIST_FIRST((head)) = NULL; \ -} while (0) - -#define SLIST_INSERT_AFTER(slistelm, elm, field) do { \ - SLIST_NEXT((elm), field) = SLIST_NEXT((slistelm), field); \ - SLIST_NEXT((slistelm), field) = (elm); \ -} while (0) - -#define SLIST_INSERT_HEAD(head, elm, field) do { \ - SLIST_NEXT((elm), field) = SLIST_FIRST((head)); \ - SLIST_FIRST((head)) = (elm); \ -} while (0) - -#define SLIST_NEXT(elm, field) ((elm)->field.sle_next) - -#define SLIST_REMOVE(head, elm, type, field) do { \ - QMD_SAVELINK(oldnext, (elm)->field.sle_next); \ - if (SLIST_FIRST((head)) == (elm)) { \ - SLIST_REMOVE_HEAD((head), field); \ - } \ - else { \ - QUEUE_TYPEOF(type) *curelm = SLIST_FIRST(head); \ - while (SLIST_NEXT(curelm, field) != (elm)) \ - curelm = SLIST_NEXT(curelm, field); \ - SLIST_REMOVE_AFTER(curelm, field); \ - } \ - TRASHIT(*oldnext); \ -} while (0) - -#define SLIST_REMOVE_AFTER(elm, field) do { \ - SLIST_NEXT(elm, field) = \ - SLIST_NEXT(SLIST_NEXT(elm, field), field); \ -} while (0) - -#define SLIST_REMOVE_HEAD(head, field) do { \ - SLIST_FIRST((head)) = SLIST_NEXT(SLIST_FIRST((head)), field); \ -} while (0) - -#define SLIST_SWAP(head1, head2, type) do { \ - QUEUE_TYPEOF(type) *swap_first = SLIST_FIRST(head1); \ - SLIST_FIRST(head1) = SLIST_FIRST(head2); \ - SLIST_FIRST(head2) = swap_first; \ -} while (0) - -/* - * Singly-linked Tail queue declarations. - */ -#define STAILQ_HEAD(name, type) \ -struct name { \ - struct type *stqh_first;/* first element */ \ - struct type **stqh_last;/* addr of last next element */ \ -} - -#define STAILQ_CLASS_HEAD(name, type) \ -struct name { \ - class type *stqh_first; /* first element */ \ - class type **stqh_last; /* addr of last next element */ \ -} - -#define STAILQ_HEAD_INITIALIZER(head) \ - { NULL, &(head).stqh_first } - -#define STAILQ_ENTRY(type) \ -struct { \ - struct type *stqe_next; /* next element */ \ -} - -#define STAILQ_CLASS_ENTRY(type) \ -struct { \ - class type *stqe_next; /* next element */ \ -} - -/* - * Singly-linked Tail queue functions. - */ -#define STAILQ_CONCAT(head1, head2) do { \ - if (!STAILQ_EMPTY((head2))) { \ - *(head1)->stqh_last = (head2)->stqh_first; \ - (head1)->stqh_last = (head2)->stqh_last; \ - STAILQ_INIT((head2)); \ - } \ -} while (0) - -#define STAILQ_EMPTY(head) ((head)->stqh_first == NULL) - -#define STAILQ_FIRST(head) ((head)->stqh_first) - -#define STAILQ_FOREACH(var, head, field) \ - for((var) = STAILQ_FIRST((head)); \ - (var); \ - (var) = STAILQ_NEXT((var), field)) - -#define STAILQ_FOREACH_FROM(var, head, field) \ - for ((var) = ((var) ? (var) : STAILQ_FIRST((head))); \ - (var); \ - (var) = STAILQ_NEXT((var), field)) - -#define STAILQ_FOREACH_SAFE(var, head, field, tvar) \ - for ((var) = STAILQ_FIRST((head)); \ - (var) && ((tvar) = STAILQ_NEXT((var), field), 1); \ - (var) = (tvar)) - -#define STAILQ_FOREACH_FROM_SAFE(var, head, field, tvar) \ - for ((var) = ((var) ? (var) : STAILQ_FIRST((head))); \ - (var) && ((tvar) = STAILQ_NEXT((var), field), 1); \ - (var) = (tvar)) - -#define STAILQ_INIT(head) do { \ - STAILQ_FIRST((head)) = NULL; \ - (head)->stqh_last = &STAILQ_FIRST((head)); \ -} while (0) - -#define STAILQ_INSERT_AFTER(head, tqelm, elm, field) do { \ - if ((STAILQ_NEXT((elm), field) = STAILQ_NEXT((tqelm), field)) == NULL)\ - (head)->stqh_last = &STAILQ_NEXT((elm), field); \ - STAILQ_NEXT((tqelm), field) = (elm); \ -} while (0) - -#define STAILQ_INSERT_HEAD(head, elm, field) do { \ - if ((STAILQ_NEXT((elm), field) = STAILQ_FIRST((head))) == NULL) \ - (head)->stqh_last = &STAILQ_NEXT((elm), field); \ - STAILQ_FIRST((head)) = (elm); \ -} while (0) - -#define STAILQ_INSERT_TAIL(head, elm, field) do { \ - STAILQ_NEXT((elm), field) = NULL; \ - *(head)->stqh_last = (elm); \ - (head)->stqh_last = &STAILQ_NEXT((elm), field); \ -} while (0) - -#define STAILQ_LAST(head, type, field) \ - (STAILQ_EMPTY((head)) ? NULL : \ - __containerof((head)->stqh_last, \ - QUEUE_TYPEOF(type), field.stqe_next)) - -#define STAILQ_NEXT(elm, field) ((elm)->field.stqe_next) - -#define STAILQ_REMOVE(head, elm, type, field) do { \ - QMD_SAVELINK(oldnext, (elm)->field.stqe_next); \ - if (STAILQ_FIRST((head)) == (elm)) { \ - STAILQ_REMOVE_HEAD((head), field); \ - } \ - else { \ - QUEUE_TYPEOF(type) *curelm = STAILQ_FIRST(head); \ - while (STAILQ_NEXT(curelm, field) != (elm)) \ - curelm = STAILQ_NEXT(curelm, field); \ - STAILQ_REMOVE_AFTER(head, curelm, field); \ - } \ - TRASHIT(*oldnext); \ -} while (0) - -#define STAILQ_REMOVE_AFTER(head, elm, field) do { \ - if ((STAILQ_NEXT(elm, field) = \ - STAILQ_NEXT(STAILQ_NEXT(elm, field), field)) == NULL) \ - (head)->stqh_last = &STAILQ_NEXT((elm), field); \ -} while (0) - -#define STAILQ_REMOVE_HEAD(head, field) do { \ - if ((STAILQ_FIRST((head)) = \ - STAILQ_NEXT(STAILQ_FIRST((head)), field)) == NULL) \ - (head)->stqh_last = &STAILQ_FIRST((head)); \ -} while (0) - -#define STAILQ_SWAP(head1, head2, type) do { \ - QUEUE_TYPEOF(type) *swap_first = STAILQ_FIRST(head1); \ - QUEUE_TYPEOF(type) **swap_last = (head1)->stqh_last; \ - STAILQ_FIRST(head1) = STAILQ_FIRST(head2); \ - (head1)->stqh_last = (head2)->stqh_last; \ - STAILQ_FIRST(head2) = swap_first; \ - (head2)->stqh_last = swap_last; \ - if (STAILQ_EMPTY(head1)) \ - (head1)->stqh_last = &STAILQ_FIRST(head1); \ - if (STAILQ_EMPTY(head2)) \ - (head2)->stqh_last = &STAILQ_FIRST(head2); \ -} while (0) - - -/* - * List declarations. - */ -#define LIST_HEAD(name, type) \ -struct name { \ - struct type *lh_first; /* first element */ \ +// ffi.cdef is unable to swallow `bool` in place of `int` here. +static inline int QUEUE_EMPTY(const QUEUE *const q) +{ + return q == q->next; } -#define LIST_CLASS_HEAD(name, type) \ -struct name { \ - class type *lh_first; /* first element */ \ -} +#define QUEUE_HEAD(q) (q)->next -#define LIST_HEAD_INITIALIZER(head) \ - { NULL } - -#define LIST_ENTRY(type) \ -struct { \ - struct type *le_next; /* next element */ \ - struct type **le_prev; /* address of previous next element */ \ +static inline void QUEUE_INIT(QUEUE *const q) +{ + q->next = q; + q->prev = q; } -#define LIST_CLASS_ENTRY(type) \ -struct { \ - class type *le_next; /* next element */ \ - class type **le_prev; /* address of previous next element */ \ +static inline void QUEUE_ADD(QUEUE *const h, QUEUE *const n) +{ + h->prev->next = n->next; + n->next->prev = h->prev; + h->prev = n->prev; + h->prev->next = h; } -/* - * List functions. - */ - -#if (defined(_KERNEL) && defined(INVARIANTS)) -#define QMD_LIST_CHECK_HEAD(head, field) do { \ - if (LIST_FIRST((head)) != NULL && \ - LIST_FIRST((head))->field.le_prev != \ - &LIST_FIRST((head))) \ - panic("Bad list head %p first->prev != head", (head)); \ -} while (0) - -#define QMD_LIST_CHECK_NEXT(elm, field) do { \ - if (LIST_NEXT((elm), field) != NULL && \ - LIST_NEXT((elm), field)->field.le_prev != \ - &((elm)->field.le_next)) \ - panic("Bad link elm %p next->prev != elm", (elm)); \ -} while (0) - -#define QMD_LIST_CHECK_PREV(elm, field) do { \ - if (*(elm)->field.le_prev != (elm)) \ - panic("Bad link elm %p prev->next != elm", (elm)); \ -} while (0) -#else -#define QMD_LIST_CHECK_HEAD(head, field) -#define QMD_LIST_CHECK_NEXT(elm, field) -#define QMD_LIST_CHECK_PREV(elm, field) -#endif /* (_KERNEL && INVARIANTS) */ - -#define LIST_EMPTY(head) ((head)->lh_first == NULL) - -#define LIST_FIRST(head) ((head)->lh_first) - -#define LIST_FOREACH(var, head, field) \ - for ((var) = LIST_FIRST((head)); \ - (var); \ - (var) = LIST_NEXT((var), field)) - -#define LIST_FOREACH_FROM(var, head, field) \ - for ((var) = ((var) ? (var) : LIST_FIRST((head))); \ - (var); \ - (var) = LIST_NEXT((var), field)) - -#define LIST_FOREACH_SAFE(var, head, field, tvar) \ - for ((var) = LIST_FIRST((head)); \ - (var) && ((tvar) = LIST_NEXT((var), field), 1); \ - (var) = (tvar)) - -#define LIST_FOREACH_FROM_SAFE(var, head, field, tvar) \ - for ((var) = ((var) ? (var) : LIST_FIRST((head))); \ - (var) && ((tvar) = LIST_NEXT((var), field), 1); \ - (var) = (tvar)) - -#define LIST_INIT(head) do { \ - LIST_FIRST((head)) = NULL; \ -} while (0) - -#define LIST_INSERT_AFTER(listelm, elm, field) do { \ - QMD_LIST_CHECK_NEXT(listelm, field); \ - if ((LIST_NEXT((elm), field) = LIST_NEXT((listelm), field)) != NULL)\ - LIST_NEXT((listelm), field)->field.le_prev = \ - &LIST_NEXT((elm), field); \ - LIST_NEXT((listelm), field) = (elm); \ - (elm)->field.le_prev = &LIST_NEXT((listelm), field); \ -} while (0) - -#define LIST_INSERT_BEFORE(listelm, elm, field) do { \ - QMD_LIST_CHECK_PREV(listelm, field); \ - (elm)->field.le_prev = (listelm)->field.le_prev; \ - LIST_NEXT((elm), field) = (listelm); \ - *(listelm)->field.le_prev = (elm); \ - (listelm)->field.le_prev = &LIST_NEXT((elm), field); \ -} while (0) - -#define LIST_INSERT_HEAD(head, elm, field) do { \ - QMD_LIST_CHECK_HEAD((head), field); \ - if ((LIST_NEXT((elm), field) = LIST_FIRST((head))) != NULL) \ - LIST_FIRST((head))->field.le_prev = &LIST_NEXT((elm), field);\ - LIST_FIRST((head)) = (elm); \ - (elm)->field.le_prev = &LIST_FIRST((head)); \ -} while (0) - -#define LIST_NEXT(elm, field) ((elm)->field.le_next) - -#define LIST_PREV(elm, head, type, field) \ - ((elm)->field.le_prev == &LIST_FIRST((head)) ? NULL : \ - __containerof((elm)->field.le_prev, \ - QUEUE_TYPEOF(type), field.le_next)) - -#define LIST_REMOVE(elm, field) do { \ - QMD_SAVELINK(oldnext, (elm)->field.le_next); \ - QMD_SAVELINK(oldprev, (elm)->field.le_prev); \ - QMD_LIST_CHECK_NEXT(elm, field); \ - QMD_LIST_CHECK_PREV(elm, field); \ - if (LIST_NEXT((elm), field) != NULL) \ - LIST_NEXT((elm), field)->field.le_prev = \ - (elm)->field.le_prev; \ - *(elm)->field.le_prev = LIST_NEXT((elm), field); \ - TRASHIT(*oldnext); \ - TRASHIT(*oldprev); \ -} while (0) - -#define LIST_SWAP(head1, head2, type, field) do { \ - QUEUE_TYPEOF(type) *swap_tmp = LIST_FIRST(head1); \ - LIST_FIRST((head1)) = LIST_FIRST((head2)); \ - LIST_FIRST((head2)) = swap_tmp; \ - if ((swap_tmp = LIST_FIRST((head1))) != NULL) \ - swap_tmp->field.le_prev = &LIST_FIRST((head1)); \ - if ((swap_tmp = LIST_FIRST((head2))) != NULL) \ - swap_tmp->field.le_prev = &LIST_FIRST((head2)); \ -} while (0) - -/* - * Tail queue declarations. - */ -#define TAILQ_HEAD(name, type) \ -struct name { \ - struct type *tqh_first; /* first element */ \ - struct type **tqh_last; /* addr of last next element */ \ - TRACEBUF \ +static inline void QUEUE_SPLIT(QUEUE *const h, QUEUE *const q, QUEUE *const n) +{ + n->prev = h->prev; + n->prev->next = n; + n->next = q; + h->prev = q->prev; + h->prev->next = h; + q->prev = n; } -#define TAILQ_CLASS_HEAD(name, type) \ -struct name { \ - class type *tqh_first; /* first element */ \ - class type **tqh_last; /* addr of last next element */ \ - TRACEBUF \ +static inline void QUEUE_INSERT_HEAD(QUEUE *const h, QUEUE *const q) +{ + q->next = h->next; + q->prev = h; + q->next->prev = q; + h->next = q; } -#define TAILQ_HEAD_INITIALIZER(head) \ - { NULL, &(head).tqh_first, TRACEBUF_INITIALIZER } - -#define TAILQ_ENTRY(type) \ -struct { \ - struct type *tqe_next; /* next element */ \ - struct type **tqe_prev; /* address of previous next element */ \ - TRACEBUF \ +static inline void QUEUE_INSERT_TAIL(QUEUE *const h, QUEUE *const q) +{ + q->next = h; + q->prev = h->prev; + q->prev->next = q; + h->prev = q; } -#define TAILQ_CLASS_ENTRY(type) \ -struct { \ - class type *tqe_next; /* next element */ \ - class type **tqe_prev; /* address of previous next element */ \ - TRACEBUF \ +static inline void QUEUE_REMOVE(QUEUE *const q) +{ + q->prev->next = q->next; + q->next->prev = q->prev; } - -/* - * Tail queue functions. - */ -#if (defined(_KERNEL) && defined(INVARIANTS)) -#define QMD_TAILQ_CHECK_HEAD(head, field) do { \ - if (!TAILQ_EMPTY(head) && \ - TAILQ_FIRST((head))->field.tqe_prev != \ - &TAILQ_FIRST((head))) \ - panic("Bad tailq head %p first->prev != head", (head)); \ -} while (0) - -#define QMD_TAILQ_CHECK_TAIL(head, field) do { \ - if (*(head)->tqh_last != NULL) \ - panic("Bad tailq NEXT(%p->tqh_last) != NULL", (head)); \ -} while (0) - -#define QMD_TAILQ_CHECK_NEXT(elm, field) do { \ - if (TAILQ_NEXT((elm), field) != NULL && \ - TAILQ_NEXT((elm), field)->field.tqe_prev != \ - &((elm)->field.tqe_next)) \ - panic("Bad link elm %p next->prev != elm", (elm)); \ -} while (0) - -#define QMD_TAILQ_CHECK_PREV(elm, field) do { \ - if (*(elm)->field.tqe_prev != (elm)) \ - panic("Bad link elm %p prev->next != elm", (elm)); \ -} while (0) -#else -#define QMD_TAILQ_CHECK_HEAD(head, field) -#define QMD_TAILQ_CHECK_TAIL(head, headname) -#define QMD_TAILQ_CHECK_NEXT(elm, field) -#define QMD_TAILQ_CHECK_PREV(elm, field) -#endif /* (_KERNEL && INVARIANTS) */ - -#define TAILQ_CONCAT(head1, head2, field) do { \ - if (!TAILQ_EMPTY(head2)) { \ - *(head1)->tqh_last = (head2)->tqh_first; \ - (head2)->tqh_first->field.tqe_prev = (head1)->tqh_last; \ - (head1)->tqh_last = (head2)->tqh_last; \ - TAILQ_INIT((head2)); \ - QMD_TRACE_HEAD(head1); \ - QMD_TRACE_HEAD(head2); \ - } \ -} while (0) - -#define TAILQ_EMPTY(head) ((head)->tqh_first == NULL) - -#define TAILQ_FIRST(head) ((head)->tqh_first) - -#define TAILQ_FOREACH(var, head, field) \ - for ((var) = TAILQ_FIRST((head)); \ - (var); \ - (var) = TAILQ_NEXT((var), field)) - -#define TAILQ_FOREACH_FROM(var, head, field) \ - for ((var) = ((var) ? (var) : TAILQ_FIRST((head))); \ - (var); \ - (var) = TAILQ_NEXT((var), field)) - -#define TAILQ_FOREACH_SAFE(var, head, field, tvar) \ - for ((var) = TAILQ_FIRST((head)); \ - (var) && ((tvar) = TAILQ_NEXT((var), field), 1); \ - (var) = (tvar)) - -#define TAILQ_FOREACH_FROM_SAFE(var, head, field, tvar) \ - for ((var) = ((var) ? (var) : TAILQ_FIRST((head))); \ - (var) && ((tvar) = TAILQ_NEXT((var), field), 1); \ - (var) = (tvar)) - -#define TAILQ_FOREACH_REVERSE(var, head, headname, field) \ - for ((var) = TAILQ_LAST((head), headname); \ - (var); \ - (var) = TAILQ_PREV((var), headname, field)) - -#define TAILQ_FOREACH_REVERSE_FROM(var, head, headname, field) \ - for ((var) = ((var) ? (var) : TAILQ_LAST((head), headname)); \ - (var); \ - (var) = TAILQ_PREV((var), headname, field)) - -#define TAILQ_FOREACH_REVERSE_SAFE(var, head, headname, field, tvar) \ - for ((var) = TAILQ_LAST((head), headname); \ - (var) && ((tvar) = TAILQ_PREV((var), headname, field), 1); \ - (var) = (tvar)) - -#define TAILQ_FOREACH_REVERSE_FROM_SAFE(var, head, headname, field, tvar) \ - for ((var) = ((var) ? (var) : TAILQ_LAST((head), headname)); \ - (var) && ((tvar) = TAILQ_PREV((var), headname, field), 1); \ - (var) = (tvar)) - -#define TAILQ_INIT(head) do { \ - TAILQ_FIRST((head)) = NULL; \ - (head)->tqh_last = &TAILQ_FIRST((head)); \ - QMD_TRACE_HEAD(head); \ -} while (0) - -#define TAILQ_INSERT_AFTER(head, listelm, elm, field) do { \ - QMD_TAILQ_CHECK_NEXT(listelm, field); \ - if ((TAILQ_NEXT((elm), field) = TAILQ_NEXT((listelm), field)) != NULL)\ - TAILQ_NEXT((elm), field)->field.tqe_prev = \ - &TAILQ_NEXT((elm), field); \ - else { \ - (head)->tqh_last = &TAILQ_NEXT((elm), field); \ - QMD_TRACE_HEAD(head); \ - } \ - TAILQ_NEXT((listelm), field) = (elm); \ - (elm)->field.tqe_prev = &TAILQ_NEXT((listelm), field); \ - QMD_TRACE_ELEM(&(elm)->field); \ - QMD_TRACE_ELEM(&(listelm)->field); \ -} while (0) - -#define TAILQ_INSERT_BEFORE(listelm, elm, field) do { \ - QMD_TAILQ_CHECK_PREV(listelm, field); \ - (elm)->field.tqe_prev = (listelm)->field.tqe_prev; \ - TAILQ_NEXT((elm), field) = (listelm); \ - *(listelm)->field.tqe_prev = (elm); \ - (listelm)->field.tqe_prev = &TAILQ_NEXT((elm), field); \ - QMD_TRACE_ELEM(&(elm)->field); \ - QMD_TRACE_ELEM(&(listelm)->field); \ -} while (0) - -#define TAILQ_INSERT_HEAD(head, elm, field) do { \ - QMD_TAILQ_CHECK_HEAD(head, field); \ - if ((TAILQ_NEXT((elm), field) = TAILQ_FIRST((head))) != NULL) \ - TAILQ_FIRST((head))->field.tqe_prev = \ - &TAILQ_NEXT((elm), field); \ - else \ - (head)->tqh_last = &TAILQ_NEXT((elm), field); \ - TAILQ_FIRST((head)) = (elm); \ - (elm)->field.tqe_prev = &TAILQ_FIRST((head)); \ - QMD_TRACE_HEAD(head); \ - QMD_TRACE_ELEM(&(elm)->field); \ -} while (0) - -#define TAILQ_INSERT_TAIL(head, elm, field) do { \ - QMD_TAILQ_CHECK_TAIL(head, field); \ - TAILQ_NEXT((elm), field) = NULL; \ - (elm)->field.tqe_prev = (head)->tqh_last; \ - *(head)->tqh_last = (elm); \ - (head)->tqh_last = &TAILQ_NEXT((elm), field); \ - QMD_TRACE_HEAD(head); \ - QMD_TRACE_ELEM(&(elm)->field); \ -} while (0) - -#define TAILQ_LAST(head, headname) \ - (*(((struct headname *)((head)->tqh_last))->tqh_last)) - -#define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next) - -#define TAILQ_PREV(elm, headname, field) \ - (*(((struct headname *)((elm)->field.tqe_prev))->tqh_last)) - -#define TAILQ_REMOVE(head, elm, field) do { \ - QMD_SAVELINK(oldnext, (elm)->field.tqe_next); \ - QMD_SAVELINK(oldprev, (elm)->field.tqe_prev); \ - QMD_TAILQ_CHECK_NEXT(elm, field); \ - QMD_TAILQ_CHECK_PREV(elm, field); \ - if ((TAILQ_NEXT((elm), field)) != NULL) \ - TAILQ_NEXT((elm), field)->field.tqe_prev = \ - (elm)->field.tqe_prev; \ - else { \ - (head)->tqh_last = (elm)->field.tqe_prev; \ - QMD_TRACE_HEAD(head); \ - } \ - *(elm)->field.tqe_prev = TAILQ_NEXT((elm), field); \ - TRASHIT(*oldnext); \ - TRASHIT(*oldprev); \ - QMD_TRACE_ELEM(&(elm)->field); \ -} while (0) - -#define TAILQ_SWAP(head1, head2, type, field) do { \ - QUEUE_TYPEOF(type) *swap_first = (head1)->tqh_first; \ - QUEUE_TYPEOF(type) **swap_last = (head1)->tqh_last; \ - (head1)->tqh_first = (head2)->tqh_first; \ - (head1)->tqh_last = (head2)->tqh_last; \ - (head2)->tqh_first = swap_first; \ - (head2)->tqh_last = swap_last; \ - if ((swap_first = (head1)->tqh_first) != NULL) \ - swap_first->field.tqe_prev = &(head1)->tqh_first; \ - else \ - (head1)->tqh_last = &(head1)->tqh_first; \ - if ((swap_first = (head2)->tqh_first) != NULL) \ - swap_first->field.tqe_prev = &(head2)->tqh_first; \ - else \ - (head2)->tqh_last = &(head2)->tqh_first; \ -} while (0) - -#endif /* !_SYS_QUEUE_H_ */ diff --git a/src/rpc/connection/connection.c b/src/rpc/connection/connection.c index 7a9fef0..a021215 100644 --- a/src/rpc/connection/connection.c +++ b/src/rpc/connection/connection.c @@ -73,8 +73,6 @@ static hashmap(uint64_t, ptr_t) *connections = NULL; static hashmap(cstr_t, uint64_t) *pluginkeys = NULL; static hashmap(cstr_t, ptr_t) *event_strings = NULL; static msgpack_sbuffer sbuf; -equeue *equeue_root; -uv_loop_t loop; int connection_init(void) { @@ -131,7 +129,7 @@ int connection_create(uv_stream_t *stream) con->refcount = 1; con->mpac = msgpack_unpacker_new(MSGPACK_UNPACKER_INIT_BUFFER_SIZE); con->closed = false; - con->queue = equeue_new(equeue_root); + con->events = multiqueue_new_child(main_loop.events); con->streams.read = inputstream_new(parse_cb, STREAM_BUFFER_SIZE, con); con->streams.write = outputstream_new(1024 * 1024); con->streams.uv = stream; @@ -150,7 +148,7 @@ int connection_create(uv_stream_t *stream) randombytes(con->cc.minutekey, sizeof con->cc.minutekey); randombytes(con->cc.lastminutekey, sizeof con->cc.lastminutekey); con->minutekey_timer.data = &con->cc; - r = uv_timer_init(&loop, &con->minutekey_timer); + r = uv_timer_init(&main_loop.uv, &con->minutekey_timer); sbassert(r == 0); r = uv_timer_start(&con->minutekey_timer, timer_cb, 60000, 60000); sbassert(r == 0); @@ -293,7 +291,7 @@ STATIC void free_connection(struct connection *con) hashmap_free(cstr_t, ptr_t)(con->subscribed_events); kv_destroy(con->callvector); kv_destroy(con->delayed_notifications); - equeue_free(con->queue); + multiqueue_free(con->events); if (con->packet.data) FREE(con->packet.data); @@ -320,7 +318,7 @@ STATIC void connection_close(struct connection *con) timer_handle = (uv_handle_t*) &con->minutekey_timer; if (timer_handle) { uv_close(timer_handle, NULL); - uv_run(&loop, UV_RUN_ONCE); + uv_run(&main_loop.uv, UV_RUN_ONCE); } inputstream_free(con->streams.read); @@ -625,7 +623,7 @@ object connection_send_request(char *pluginkey, string method, struct callinfo cinfo = (struct callinfo) { msgid, false, false, NIL }; - loop_wait_for_response(con, &cinfo); + loop_process_events_until(&main_loop, con, &cinfo); if (cinfo.errored) { if (cinfo.result.type == OBJECT_TYPE_STR) { @@ -715,7 +713,6 @@ STATIC void connection_handle_request(struct connection *con, dispatch_info dispatcher; msgpack_object *method; struct api_error api_error = ERROR_INIT; - api_event event; msgpack_rpc_validate(&msgid, obj, &api_error); @@ -749,11 +746,7 @@ STATIC void connection_handle_request(struct connection *con, if (dispatcher.async) connection_request_event((void**)&eventinfo); else { - event.handler = connection_request_event; - event.info = (void**)&eventinfo; - equeue_put(con->queue, event); - /* TODO: move this call to a suitable place (main?) */ - equeue_run_events(equeue_root); + multiqueue_put(con->events, connection_request_event, 1, eventinfo); } } diff --git a/src/rpc/connection/connection.h b/src/rpc/connection/connection.h index 7088b37..4a8b485 100644 --- a/src/rpc/connection/connection.h +++ b/src/rpc/connection/connection.h @@ -16,15 +16,42 @@ #pragma once -#include "rpc/sb-rpc.h" +#include // for msgpack_sbuffer +#include // for msgpack_unpacker +#include // for bool +#include // for size_t +#include // for uint64_t, uint32_t +#include // for uv_stream_t, uv_timer_t +#include "kvec.h" // for kvec_t +#include "rpc/connection/event.h" // for multiqueue +#include "rpc/sb-rpc.h" // for crypto_context, hashmap_cstr_t_ptr_t +#include "sb-common.h" // for hashmap -STATIC void close_cb(uv_handle_t *handle); -STATIC void connection_handle_request(struct connection *con, - msgpack_object *obj); -STATIC void connection_handle_response(struct connection *con, - msgpack_object *obj); -STATIC void connection_request_event(void **argv); -STATIC void connection_close(struct connection *con); -STATIC void parse_cb(inputstream *istream, void *data, bool eof); -STATIC int is_valid_rpc_response(msgpack_object *obj, struct connection *con); -STATIC void call_set_error(struct connection *con, char *msg); +struct connection { + uint64_t id; + uint32_t msgid; + size_t pending_requests; + size_t refcount; + msgpack_unpacker *mpac; + msgpack_sbuffer *sbuf; + char *unpackbuf; + bool closed; + multiqueue *events; + struct { + inputstream *read; + outputstream *write; + uv_stream_t *uv; + } streams; + kvec_t(struct callinfo *) callvector; + kvec_t(wbuffer *) delayed_notifications; + struct crypto_context cc; + struct { + uint64_t start; + uint64_t end; + uint64_t pos; + uint64_t length; + unsigned char *data; + } packet; + uv_timer_t minutekey_timer; + hashmap(cstr_t, ptr_t) *subscribed_events; +}; diff --git a/src/rpc/connection/event.c b/src/rpc/connection/event.c index 511897c..1f52b4d 100644 --- a/src/rpc/connection/event.c +++ b/src/rpc/connection/event.c @@ -29,156 +29,164 @@ * limitations under the License. */ -#include - -#include "sb-common.h" -#include "rpc/sb-rpc.h" #include "rpc/connection/event.h" - -equeue *equeue_root; - -int event_initialize(void) +#include // for bool, false, true +#include // for NULL +#include "queue.h" // for QUEUE_REMOVE, QUEUE, QUEUE_EMPTY, QUEUE_INSER... +#include "sb-common.h" // for sbassert, FREE, MALLOC + +typedef struct multiqueue_item multiqueueitem; + +struct multiqueue_item { + union { + multiqueue *queue; + struct { + event event; + multiqueueitem *parent; + } item; + } data; + bool link; // true: current item is just a link to a node in a child queue + QUEUE node; +}; + +struct multiqueue { + multiqueue *parent; + QUEUE headtail; + put_callback put_cb; + void *data; +}; + +static multiqueue *multiqueue_new(multiqueue *parent, put_callback put_cb, void *data); +static event multiqueue_remove(multiqueue *this); +static void multiqueue_push(multiqueue *this, event event); +static multiqueueitem *multiqueue_node_data(QUEUE *q); + +static event NILEVENT = { .handler = NULL, .argv = {NULL} }; + +multiqueue *multiqueue_new_parent(put_callback put_cb, void *data) { - /* initialize event root queue */ - equeue_root = equeue_new(NULL); - - if (!equeue_root) - return (-1); - - return 0; + return multiqueue_new(NULL, put_cb, data); } - -equeue *equeue_new(equeue *root) +multiqueue *multiqueue_new_child(multiqueue *parent) { - equeue *queue = MALLOC(equeue); - - if (!queue) - return (NULL); - - queue->root = root; - - TAILQ_INIT(&queue->head); - - return (queue); + sbassert(!parent->parent); + return multiqueue_new(parent, NULL, NULL); } - -/** - * check if queue is empty - * - * @params queue queue instance - */ -bool equeue_empty(equeue *queue) +static multiqueue *multiqueue_new(multiqueue *parent, put_callback put_cb, + void *data) { - return (TAILQ_EMPTY(&queue->head)); + multiqueue *rv = MALLOC(multiqueue); + QUEUE_INIT(&rv->headtail); + rv->parent = parent; + rv->put_cb = put_cb; + rv->data = data; + return rv; } - -int equeue_put(equeue *queue, api_event event) +void multiqueue_free(multiqueue *this) { - if (!queue) - return (-1); - - /* disallow `put` to root queue */ - if (!queue->root) - return (-1); - - queue_entry *entry = MALLOC(queue_entry); - entry->data.entry.event = event; - TAILQ_INSERT_TAIL(&queue->head, entry, node); - - entry->data.entry.root = MALLOC(queue_entry); - entry->data.entry.root->data.queue = queue; - TAILQ_INSERT_TAIL(&queue->root->head, entry->data.entry.root, node); + sbassert(this); + while (!QUEUE_EMPTY(&this->headtail)) { + QUEUE *q = QUEUE_HEAD(&this->headtail); + multiqueueitem *item = multiqueue_node_data(q); + if (this->parent) { + QUEUE_REMOVE(&item->data.item.parent->node); + FREE(item->data.item.parent); + } + QUEUE_REMOVE(q); + FREE(item); + } - return (0); + FREE(this); } - -api_event equeue_get(equeue *queue) +event multiqueue_get(multiqueue *this) { - api_event event; - queue_entry *entry; + return multiqueue_empty(this) ? NILEVENT : multiqueue_remove(this); +} - if (equeue_empty(queue)) { - event.handler = NULL; - return (event); +void multiqueue_put_event(multiqueue *this, event event) +{ + sbassert(this); + multiqueue_push(this, event); + if (this->parent && this->parent->put_cb) { + this->parent->put_cb(this->parent, this->parent->data); } +} - if (queue->root) { - entry = dequeue_child(queue); - } else { - entry = dequeue_child_from_root(queue); +void multiqueue_process_events(multiqueue *this) +{ + sbassert(this); + while (!multiqueue_empty(this)) { + event event = multiqueue_get(this); + if (event.handler) { + event.handler(event.argv); + } } - - event = entry->data.entry.event; - - FREE(entry); - - return (event); } - -STATIC queue_entry *dequeue_child(equeue *queue) +bool multiqueue_empty(multiqueue *this) { - queue_entry *entry; - - entry = TAILQ_FIRST(&queue->head); - TAILQ_REMOVE(&queue->head, entry, node); - TAILQ_REMOVE(&queue->root->head, entry->data.entry.root, node); - - FREE(entry->data.entry.root); - - return (entry); + sbassert(this); + return QUEUE_EMPTY(&this->headtail); } - -STATIC queue_entry *dequeue_child_from_root(equeue *queue) +void multiqueue_replace_parent(multiqueue *this, multiqueue *new_parent) { - queue_entry *entry, *centry; - equeue *cqueue; - - entry = TAILQ_FIRST(&queue->head); - TAILQ_REMOVE(&queue->head, entry, node); - cqueue = entry->data.queue; - centry = TAILQ_FIRST(&cqueue->head); - TAILQ_REMOVE(&cqueue->head, centry, node); - - FREE(entry); - - return (centry); + sbassert(multiqueue_empty(this)); + this->parent = new_parent; } - -void equeue_free(equeue *queue) +static event multiqueue_remove(multiqueue *this) { - queue_entry *entry; - - if (queue->root) { - while (!equeue_empty(queue)) { - entry = dequeue_child(queue); - FREE(entry); - } + sbassert(!multiqueue_empty(this)); + QUEUE *h = QUEUE_HEAD(&this->headtail); + QUEUE_REMOVE(h); + multiqueueitem *item = multiqueue_node_data(h); + event rv; + + if (item->link) { + sbassert(!this->parent); + // remove the next node in the linked queue + multiqueue *linked = item->data.queue; + sbassert(!multiqueue_empty(linked)); + multiqueueitem *child = + multiqueue_node_data(QUEUE_HEAD(&linked->headtail)); + QUEUE_REMOVE(&child->node); + rv = child->data.item.event; + FREE(child); } else { - while (!equeue_empty(queue)) { - entry = dequeue_child_from_root(queue); - FREE(entry); + if (this->parent) { + // remove the corresponding link node in the parent queue + QUEUE_REMOVE(&item->data.item.parent->node); + FREE(item->data.item.parent); } + rv = item->data.item.event; } - FREE(queue); + FREE(item); + return rv; } - -void equeue_run_events(equeue *queue) +static void multiqueue_push(multiqueue *this, event event) { - api_event event; - - while (!equeue_empty(queue)) { - event = equeue_get(queue); - - if (event.handler) - event.handler(event.info); + multiqueueitem *item = MALLOC(multiqueueitem); + item->link = false; + item->data.item.event = event; + QUEUE_INSERT_TAIL(&this->headtail, &item->node); + + if (this->parent) { + // push link node to the parent queue + item->data.item.parent = MALLOC(multiqueueitem); + item->data.item.parent->link = true; + item->data.item.parent->data.queue = this; + QUEUE_INSERT_TAIL(&this->parent->headtail, &item->data.item.parent->node); } } + +static multiqueueitem *multiqueue_node_data(QUEUE *q) +{ + return QUEUE_DATA(q, multiqueueitem, node); +} diff --git a/src/rpc/connection/event.h b/src/rpc/connection/event.h index 9b09f3a..00054a4 100644 --- a/src/rpc/connection/event.h +++ b/src/rpc/connection/event.h @@ -16,7 +16,21 @@ #pragma once -#include "rpc/sb-rpc.h" +#include // for bool +#include "rpc/sb-rpc.h" // for event -STATIC queue_entry *dequeue_child(equeue *queue); -STATIC queue_entry *dequeue_child_from_root(equeue *queue); + +typedef struct multiqueue multiqueue; +typedef void (*put_callback)(multiqueue *multiq, void *data); + +multiqueue *multiqueue_new_parent(put_callback put_cb, void *data); +multiqueue *multiqueue_new_child(multiqueue *parent); +void multiqueue_free(multiqueue *this); +event multiqueue_get(multiqueue *this); +void multiqueue_put_event(multiqueue *this, event event); +void multiqueue_process_events(multiqueue *this); +bool multiqueue_empty(multiqueue *this); +void multiqueue_replace_parent(multiqueue *this, multiqueue *new_parent); + +#define multiqueue_put(q, h, ...) \ + multiqueue_put_event(q, event_create(1, h, __VA_ARGS__)); diff --git a/src/rpc/connection/loop.c b/src/rpc/connection/loop.c index e245b9a..c987bc0 100644 --- a/src/rpc/connection/loop.c +++ b/src/rpc/connection/loop.c @@ -30,42 +30,117 @@ * limitations under the License. */ -#include +#include "rpc/connection/loop.h" +#include // for bool +#include // for NULL, abort +#include "rpc/sb-rpc.h" // for event -#include "rpc/sb-rpc.h" -#include "sb-common.h" +static void async_cb(uv_async_t *handle); +static void timer_cb(uv_timer_t *handle); -static inline void loop_poll_events_until(struct connection *con, - bool *condition); -equeue *equeue_root; -uv_loop_t loop; +void loop_init(UNUSED(loop *loop), UNUSED(void *data)) +{ + uv_loop_init(&loop->uv); + loop->recursive = 0; + loop->uv.data = loop; + loop->children = kl_init(WatcherPtr); + loop->children_stop_requests = 0; + loop->events = multiqueue_new_parent(loop_on_put, loop); + loop->fast_events = multiqueue_new_child(loop->events); + loop->thread_events = multiqueue_new_parent(NULL, NULL); + uv_mutex_init(&loop->mutex); + uv_async_init(&loop->uv, &loop->async, async_cb); + uv_signal_init(&loop->uv, &loop->children_watcher); + uv_timer_init(&loop->uv, &loop->children_kill_timer); + uv_timer_init(&loop->uv, &loop->poll_timer); +} -static inline void loop_poll_events_until(struct connection *con, - bool *condition) +void loop_poll_events(loop *loop, int ms) { - while (!*condition) { - if (con->queue && !equeue_empty(con->queue)) { - equeue_run_events(con->queue); - } else { - uv_run(&loop, UV_RUN_ONCE); - equeue_run_events(equeue_root); - } + if (loop->recursive++) { + abort(); } + + uv_run_mode mode = UV_RUN_ONCE; + + if (ms > 0) { + uv_timer_start(&loop->poll_timer, timer_cb, (uint64_t)ms, (uint64_t)ms); + } else if (ms == 0) { + mode = UV_RUN_NOWAIT; + } + + uv_run(&loop->uv, mode); + + if (ms > 0) { + uv_timer_stop(&loop->poll_timer); + } + + loop->recursive--; // Can re-enter uv_run now + multiqueue_process_events(loop->fast_events); } +// Schedule an event from another thread +void loop_schedule(loop *loop, event event) +{ + uv_mutex_lock(&loop->mutex); + multiqueue_put_event(loop->thread_events, event); + uv_async_send(&loop->async); + uv_mutex_unlock(&loop->mutex); +} -void loop_wait_for_response(struct connection *con, - struct callinfo *cinfo) +void loop_on_put(UNUSED(multiqueue *queue), void *data) { + loop *loop = data; + // Sometimes libuv will run pending callbacks(timer for example) before + // blocking for a poll. If this happens and the callback pushes a event to one + // of the queues, the event would only be processed after the poll + // returns(user hits a key for example). To avoid this scenario, we call + // uv_stop when a event is enqueued. + uv_stop(&loop->uv); +} +void loop_close(loop *loop, bool wait) +{ + uv_mutex_destroy(&loop->mutex); + uv_close((uv_handle_t *)&loop->children_watcher, NULL); + uv_close((uv_handle_t *)&loop->children_kill_timer, NULL); + uv_close((uv_handle_t *)&loop->poll_timer, NULL); + uv_close((uv_handle_t *)&loop->async, NULL); + do { + uv_run(&loop->uv, wait ? UV_RUN_DEFAULT : UV_RUN_NOWAIT); + } while (uv_loop_close(&loop->uv) && wait); + multiqueue_free(loop->fast_events); + multiqueue_free(loop->thread_events); + multiqueue_free(loop->events); + kl_destroy(WatcherPtr, loop->children); +} + +static void async_cb(uv_async_t *handle) +{ + loop *l = handle->loop->data; + uv_mutex_lock(&l->mutex); + while (!multiqueue_empty(l->thread_events)) { + event ev = multiqueue_get(l->thread_events); + multiqueue_put_event(l->fast_events, ev); + } + uv_mutex_unlock(&l->mutex); +} + +static void timer_cb(UNUSED(uv_timer_t *handle)) +{ +} + +void loop_process_events_until(loop *loop, struct connection *con, + struct callinfo *cinfo) +{ /* push callinfo to connection callinfo vector */ kv_push(con->callvector, cinfo); con->pending_requests++; /* wait until requestinfo returned, in time process events */ - loop_poll_events_until(con, &cinfo->returned); + LOOP_PROCESS_EVENTS_UNTIL(loop, con->events, -1, cinfo->returned); /* delete last from callinfo vector */ - kv_pop(con->callvector); + (void)kv_pop(con->callvector); con->pending_requests--; } diff --git a/src/rpc/connection/server.c b/src/rpc/connection/server.c index 8d53cf8..3f8cf30 100644 --- a/src/rpc/connection/server.c +++ b/src/rpc/connection/server.c @@ -48,8 +48,6 @@ struct server { static hashmap(cstr_t, ptr_t) *servers = NULL; -uv_loop_t loop; - int server_init(void) { servers = hashmap_new(cstr_t, ptr_t)(); @@ -86,7 +84,7 @@ int server_start_tcp(boxaddr *addr, uint16_t port) box_addr_to_sockaddr(addr, port, &server->socket.tcp.addr, sizeof(struct sockaddr_in)); - uv_tcp_init(&loop, &server->socket.tcp.handle); + uv_tcp_init(&main_loop.uv, &server->socket.tcp.handle); result = uv_tcp_bind(&server->socket.tcp.handle, (const struct sockaddr *)&server->socket.tcp.addr, 0); @@ -138,7 +136,7 @@ int server_start_pipe(char *name) return (-1); } - uv_pipe_init(&loop, &server->socket.pipe.handle, 0); + uv_pipe_init(&main_loop.uv, &server->socket.pipe.handle, 0); result = uv_pipe_bind(&server->socket.pipe.handle, server->socket.pipe.addr); if (result) { @@ -220,9 +218,9 @@ STATIC void connection_cb(uv_stream_t *server_stream, int status) return; if (server->type == SERVER_TYPE_TCP) - uv_tcp_init(&loop, (uv_tcp_t *)client); + uv_tcp_init(&main_loop.uv, (uv_tcp_t *)client); else - uv_pipe_init(&loop, (uv_pipe_t *)client, 0); + uv_pipe_init(&main_loop.uv, (uv_pipe_t *)client, 0); result = uv_accept(server_stream, client); diff --git a/src/rpc/sb-rpc.h b/src/rpc/sb-rpc.h index c7c2d25..b8b27ee 100644 --- a/src/rpc/sb-rpc.h +++ b/src/rpc/sb-rpc.h @@ -45,8 +45,6 @@ typedef struct outputstream outputstream; typedef struct inputstream inputstream; typedef void (*inputstream_cb)(inputstream *inputstream, void *data, bool eof); typedef struct api_event api_event; -typedef struct equeue equeue; -typedef struct queue_entry queue_entry; typedef struct message_object message_object; typedef struct connection_request_event_info connection_request_event_info; @@ -192,35 +190,6 @@ struct wbuffer { char *data; }; -struct connection { - uint64_t id; - uint32_t msgid; - size_t pending_requests; - size_t refcount; - msgpack_unpacker *mpac; - msgpack_sbuffer *sbuf; - char *unpackbuf; - bool closed; - equeue *queue; - struct { - inputstream *read; - outputstream *write; - uv_stream_t *uv; - } streams; - kvec_t(struct callinfo *) callvector; - kvec_t(wbuffer *) delayed_notifications; - struct crypto_context cc; - struct { - uint64_t start; - uint64_t end; - uint64_t pos; - uint64_t length; - unsigned char *data; - } packet; - uv_timer_t minutekey_timer; - hashmap(cstr_t, ptr_t) *subscribed_events; -}; - struct callinfo { uint64_t msgid; bool returned; @@ -261,36 +230,39 @@ struct connection_request_event_info { uint64_t msgid; }; -/* this structure holds the request event information and a callback to a - handler function */ -typedef void (*argv_callback)(void **argv); +#define EVENT_HANDLER_MAX_ARGC 6 -struct api_event { +typedef void (*argv_callback)(void **argv); +typedef struct message { + int priority; argv_callback handler; - void **info; -}; - -TAILQ_HEAD(queue, queue_entry); - -struct equeue { - struct queue head; - equeue *root; -}; - -struct queue_entry { - union { - equeue *queue; - struct { - queue_entry *root; - api_event event; - } entry; - } data; - TAILQ_ENTRY(queue_entry) node; -}; - -/* define global root event queue */ -extern equeue *equeue_root; - + void *argv[EVENT_HANDLER_MAX_ARGC]; +} event; + +typedef void(*event_scheduler)(event event, void *data); + +#define VA_EVENT_INIT(event, p, h, a) \ + do { \ + sbassert(a <= EVENT_HANDLER_MAX_ARGC); \ + (event)->priority = p; \ + (event)->handler = h; \ + if (a) { \ + va_list args; \ + va_start(args, a); \ + for (int i = 0; i < a; i++) { \ + (event)->argv[i] = va_arg(args, void *); \ + } \ + va_end(args); \ + } \ + } while (0) + +static inline event event_create(int priority, argv_callback cb, int argc, ...) +{ + sbassert(argc <= EVENT_HANDLER_MAX_ARGC); + event event; + VA_EVENT_INIT(&event, priority, cb, argc); + return event; +} /* Functions */ @@ -450,61 +422,6 @@ int server_start_pipe(char *name); int server_stop(char * endpoint); int server_close(void); -int event_initialize(void); - -/** - * create a new queue or child queue - * - * @params root if NULL a root queue is created, if not NULL a child queue for - * `root` is created - * @returns queue instance - */ -equeue * equeue_new(equeue *root); - -/** - * get a queue element - * - * this function first checks if the passed queue is empty, if yes it return - * an empty event object. if it's not empty the first queue entry will be - * returned and removed from the queue. - * - * if the queue entry is a child, the first child queue entry is returned and - * removed from the child queue. after that, the child queue entry associated - * event is returned. - * - * if the queue entry is no child. the queue entry associated event is returned - * - * @param queue queue instance - */ -api_event equeue_get(equeue *queue); - -/** - * put an event in a queue - * - * @param queue queue instance - * @param event event to enqueue - */ -int equeue_put(equeue *queue, api_event event); - -/** - * run all events of a queue - * - * @params queue queue instance - */ -void equeue_run_events(equeue *queue); - -/** - * free queue - * - * @params queue queue instance - */ -void equeue_free(equeue *queue); - -bool equeue_empty(equeue *queue); - - - - void streamhandle_set_inputstream(uv_handle_t *handle, inputstream *inputstream); void streamhandle_set_outputstream(uv_handle_t *handle, diff --git a/src/sb-common.h b/src/sb-common.h index bcc76e9..18b2c6d 100644 --- a/src/sb-common.h +++ b/src/sb-common.h @@ -236,9 +236,6 @@ typedef const char * cstr_t; /* verbosity global */ extern int8_t verbose_level; -/* uv loop global */ -extern uv_loop_t loop; - /* address parsing helper inline functions */ /** Helper: given a hex digit, return its value, or -1 if it isn't hex. */ static inline int hex_decode_digit(char c) diff --git a/src/signal.c b/src/signal.c index b362072..1268c04 100644 --- a/src/signal.c +++ b/src/signal.c @@ -15,6 +15,7 @@ */ #include "sb-common.h" +#include "main.h" static void signal_sigint_cb(uv_signal_t *uvhandle, int signum); @@ -23,7 +24,7 @@ uv_signal_t sigint; int signal_init(void) { /* SIGINT */ - if (uv_signal_init(&loop, &sigint) != 0) { + if (uv_signal_init(&main_loop.uv, &sigint) != 0) { return (-1); } diff --git a/test/functional/dispatch-handle-broadcast.c b/test/functional/dispatch-handle-broadcast.c index 1622912..89234fa 100644 --- a/test/functional/dispatch-handle-broadcast.c +++ b/test/functional/dispatch-handle-broadcast.c @@ -20,6 +20,7 @@ #include "rpc/sb-rpc.h" #include "api/helpers.h" #include "rpc/msgpack/helpers.h" +#include "rpc/connection/connection.h" #include "api/sb-api.h" #ifdef __linux__ #include diff --git a/test/functional/dispatch-handle-register.c b/test/functional/dispatch-handle-register.c index 358562d..8eb1f38 100644 --- a/test/functional/dispatch-handle-register.c +++ b/test/functional/dispatch-handle-register.c @@ -19,6 +19,7 @@ #include "sb-common.h" #include "tweetnacl.h" #include "rpc/sb-rpc.h" +#include "rpc/connection/connection.h" #include "api/helpers.h" #include "api/sb-api.h" #ifdef __linux__ diff --git a/test/functional/dispatch-handle-result.c b/test/functional/dispatch-handle-result.c index 181d4d2..f077fea 100644 --- a/test/functional/dispatch-handle-result.c +++ b/test/functional/dispatch-handle-result.c @@ -19,6 +19,7 @@ #include "helper-all.h" #include "sb-common.h" #include "rpc/sb-rpc.h" +#include "rpc/connection/connection.h" #include "api/helpers.h" #include "api/sb-api.h" #ifdef __linux__ diff --git a/test/functional/dispatch-handle-run.c b/test/functional/dispatch-handle-run.c index c3330a0..d29e767 100644 --- a/test/functional/dispatch-handle-run.c +++ b/test/functional/dispatch-handle-run.c @@ -18,6 +18,7 @@ #include "sb-common.h" #include "rpc/sb-rpc.h" +#include "rpc/connection/connection.h" #include "api/helpers.h" #include "api/sb-api.h" #ifdef __linux__ diff --git a/test/functional/dispatch-handle-subscribe.c b/test/functional/dispatch-handle-subscribe.c index fccd6f0..9ee0e47 100644 --- a/test/functional/dispatch-handle-subscribe.c +++ b/test/functional/dispatch-handle-subscribe.c @@ -18,6 +18,7 @@ #include "sb-common.h" #include "rpc/sb-rpc.h" +#include "rpc/connection/connection.h" #include "api/helpers.h" #include "api/sb-api.h" #ifdef __linux__ diff --git a/test/helper-validate.c b/test/helper-validate.c index aa5a189..9fc7ce8 100644 --- a/test/helper-validate.c +++ b/test/helper-validate.c @@ -67,8 +67,8 @@ int validate_run_request(const unsigned long data1, * sender of the rpc call, we need to push the callid on the cmocka test * stack. this allows verifying of it later on */ uint64_t callid = meta.data.array.items[1].data.uinteger; - will_return(__wrap_loop_wait_for_response, OBJECT_TYPE_UINT); - will_return(__wrap_loop_wait_for_response, callid); + will_return(__wrap_loop_process_events_until, OBJECT_TYPE_UINT); + will_return(__wrap_loop_process_events_until, callid); p->callid = callid; @@ -135,8 +135,8 @@ int validate_result_request(const unsigned long data1, * stack. this allows verifying of it later on */ uint64_t callid = meta.data.array.items[0].data.uinteger; - will_return(__wrap_loop_wait_for_response, OBJECT_TYPE_UINT); - will_return(__wrap_loop_wait_for_response, callid); + will_return(__wrap_loop_process_events_until, OBJECT_TYPE_UINT); + will_return(__wrap_loop_process_events_until, callid); api_free_array(message); diff --git a/test/main.c b/test/main.c index 75895c6..c406bf0 100644 --- a/test/main.c +++ b/test/main.c @@ -17,8 +17,10 @@ #include "test-list.h" #include "helper-unix.h" #include "sb-common.h" +#include "main.h" int8_t verbose_level; +loop main_loop; int main(UNUSED(int argc), UNUSED(char **argv)) { diff --git a/test/test-list.h b/test/test-list.h index 630b302..a8408f4 100644 --- a/test/test-list.h +++ b/test/test-list.h @@ -21,8 +21,6 @@ void unit_server_start(void **state); void unit_server_stop(void **state); void unit_dispatch_table_get(void **state); -void unit_event_queue_put(void **state); -void unit_event_queue_get(void **state); void functional_client_connect(void **state); void functional_db_connect(void **state); @@ -47,7 +45,6 @@ const struct CMUnitTest tests[] = { cmocka_unit_test(unit_dispatch_table_get), cmocka_unit_test(unit_server_start), cmocka_unit_test(unit_server_stop), - cmocka_unit_test(unit_event_queue_put), cmocka_unit_test(functional_db_connect), cmocka_unit_test(functional_db_plugin_add), cmocka_unit_test(functional_db_pluginkey_verify), diff --git a/test/unit/server-start.c b/test/unit/server-start.c index b00dd80..544d279 100644 --- a/test/unit/server-start.c +++ b/test/unit/server-start.c @@ -22,8 +22,7 @@ #include "rpc/sb-rpc.h" #include "helper-unix.h" #include "rpc/db/sb-db.h" - -uv_loop_t loop; +#include "main.h" void unit_server_start(UNUSED(void **state)) { @@ -40,7 +39,7 @@ void unit_server_start(UNUSED(void **state)) srand((unsigned)time(NULL)); assert_int_equal(0, server_init()); - uv_loop_init(&loop); + loop_init(&main_loop, NULL); snprintf(buf1, 19, "/tmp/splnbx-%d", rand() % (999999 + 1 - 100000) + 100000); assert_int_equal(0, server_start_pipe(buf1)); @@ -59,8 +58,8 @@ void unit_server_start(UNUSED(void **state)) server_close(); - uv_run(&loop, UV_RUN_ONCE); - uv_loop_close(&loop); + uv_run(&main_loop.uv, UV_RUN_ONCE); + uv_loop_close(&main_loop.uv); db_close(); } diff --git a/test/unit/server-stop.c b/test/unit/server-stop.c index 4ec297e..4dc5632 100644 --- a/test/unit/server-stop.c +++ b/test/unit/server-stop.c @@ -19,15 +19,14 @@ #include "rpc/sb-rpc.h" #include "helper-unix.h" #include "rpc/db/sb-db.h" - -uv_loop_t loop; +#include "main.h" void unit_server_stop(UNUSED(void **state)) { boxaddr addr; uint16_t port; - uv_loop_init(&loop); + loop_init(&main_loop, NULL); connect_to_db(); box_addr_port_lookup("127.0.0.1:11111", &addr, &port); @@ -39,8 +38,8 @@ void unit_server_stop(UNUSED(void **state)) server_close(); - uv_run(&loop, UV_RUN_ONCE); - uv_loop_close(&loop); + uv_run(&main_loop.uv, UV_RUN_ONCE); + uv_loop_close(&main_loop.uv); db_close(); } diff --git a/test/wrapper-functions.c b/test/wrapper-functions.c index 7d825ac..0d09863 100644 --- a/test/wrapper-functions.c +++ b/test/wrapper-functions.c @@ -3,6 +3,7 @@ #include #include "rpc/sb-rpc.h" #include "rpc/msgpack/helpers.h" +#include "rpc/connection/loop.h" #include "api/helpers.h" #include "helper-unix.h" #include "helper-all.h" @@ -54,8 +55,8 @@ int __wrap_outputstream_write(UNUSED(outputstream *ostream), char *buffer, size_ return (0); } -void __wrap_loop_wait_for_response(UNUSED(struct connection *con), - struct callinfo *cinfo) +void __wrap_loop_process_events_until(UNUSED(loop *loop), + UNUSED(struct connection *con), struct callinfo *cinfo) { assert_non_null(cinfo); From c0b30be54669e28480d01ab198985ea54aadc2e3 Mon Sep 17 00:00:00 2001 From: Stephan Zeisberg Date: Mon, 14 Nov 2016 13:59:53 +0100 Subject: [PATCH 21/41] Gardening with include what you use --- src/rpc/connection/connection.c | 41 ++++++++++++++++++--------------- src/rpc/connection/crypto.c | 14 ++++++----- src/rpc/connection/dispatch.c | 15 +++++++----- src/rpc/connection/server.c | 23 ++++++++++-------- src/rpc/connection/server.h | 3 ++- 5 files changed, 54 insertions(+), 42 deletions(-) diff --git a/src/rpc/connection/connection.c b/src/rpc/connection/connection.c index a021215..c00ebb8 100644 --- a/src/rpc/connection/connection.c +++ b/src/rpc/connection/connection.c @@ -30,26 +30,30 @@ * limitations under the License. */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include "rpc/connection/connection.h" #ifdef __linux__ -#include +#include // for strlcpy #endif +#include // for msgpack_object, msgpack_object_union +#include // for msgpack_packer_init, msgpack_packer +#include // for msgpack_sbuffer, msgpack_sbuffer_c... +#include // for msgpack_unpacked, msgpack_unpacked... +#include // for true, bool, false +#include // for NULL, size_t +#include // for uint64_t, UINT64_MAX, uint32_t +#include // for abort, exit, realloc +#include // for strlen +#include // for uv_handle_t, uv_close, uv_timer_t +#include "api/helpers.h" // for NIL +#include "api/sb-api.h" // for api_free_array, api_free_object +#include "khash.h" // for __i, khint32_t +#include "main.h" // for main_loop +#include "rpc/connection/event.h" // for multiqueue_free, multiqueue_new_child +#include "rpc/connection/loop.h" // for loop, LOOP_PROCESS_EVENTS_UNTIL +#include "rpc/msgpack/helpers.h" // for msgpack_rpc_serialize_request, msg... +#include "rpc/sb-rpc.h" // for callinfo, crypto_context, object +#include "tweetnacl.h" // for randombytes -#include "tweetnacl.h" -#include "rpc/sb-rpc.h" -#include "rpc/connection/connection.h" -#include "rpc/msgpack/helpers.h" -#include "api/sb-api.h" -#include "api/helpers.h" STATIC void parse_cb(inputstream *istream, void *data, bool eof); STATIC void close_cb(uv_handle_t *handle); @@ -499,8 +503,7 @@ STATIC void parse_cb(inputstream *istream, void *data, bool eof) } consumedlen += plaintextlen; - reset_packet(con); - FREE(con->packet.data); + reset_parser(con); } msgpack_unpacker_buffer_consumed(con->mpac, consumedlen); diff --git a/src/rpc/connection/crypto.c b/src/rpc/connection/crypto.c index f45c1b5..5638732 100644 --- a/src/rpc/connection/crypto.c +++ b/src/rpc/connection/crypto.c @@ -1,10 +1,12 @@ -#include -#include -#include "sb-common.h" -#include "rpc/sb-rpc.h" -#include "rpc/db/sb-db.h" #include "rpc/connection/crypto.h" -#include "tweetnacl.h" +#include // for uint64_t +#include // for exit +#include // for memcpy, NULL, size_t +#include // for close +#include "rpc/db/sb-db.h" // for db_authorized_verify, db_authorized_whitel... +#include "rpc/sb-rpc.h" // for crypto_context, outputstream_write, output... +#include "sb-common.h" // for sbmemzero, sbassert, FREE, ISODD, STATIC +#include "tweetnacl.h" // for crypto_box_NONCEBYTES, crypto_box_open_aft... #define CRYPTO_PREFIX_SPLONEBOXCLIENT "splonebox-client" #define CRYPTO_PREFIX_SPLONEBOXSERVER "splonebox-server" diff --git a/src/rpc/connection/dispatch.c b/src/rpc/connection/dispatch.c index 5089ff4..634e0ba 100644 --- a/src/rpc/connection/dispatch.c +++ b/src/rpc/connection/dispatch.c @@ -30,12 +30,15 @@ * limitations under the License. */ -#include - -#include "rpc/sb-rpc.h" -#include "api/sb-api.h" -#include "api/helpers.h" -#include "sb-common.h" +#include // for msgpack_sbuffer_init, msgpack_sbuffer +#include // for false, true +#include // for uint64_t +#include // for snprintf +#include // for NULL, size_t +#include "api/helpers.h" // for ARRAY_OBJ, ADD, NIL, UINTEGER_OBJ +#include "api/sb-api.h" // for api_broadcast, api_register, api_result +#include "rpc/sb-rpc.h" // for object, array, object::(anonymous), dis... +#include "sb-common.h" // for ::API_ERROR_TYPE_VALIDATION, error_set static msgpack_sbuffer sbuf; static hashmap(string, dispatch_info) *dispatch_table = NULL; diff --git a/src/rpc/connection/server.c b/src/rpc/connection/server.c index 3f8cf30..b04184e 100644 --- a/src/rpc/connection/server.c +++ b/src/rpc/connection/server.c @@ -14,18 +14,21 @@ * along with this program. If not, see . */ -#include -#include +#include "rpc/connection/server.h" #ifdef __linux__ -#include +#include // for strlcpy #endif -#include - -#include "sb-common.h" -#include "rpc/sb-rpc.h" -#include "rpc/db/sb-db.h" -#include "rpc/connection/server.h" - +#include // for getnameinfo, NI_MAXHOST, NI_MAXSERV +#include // for sockaddr_in +#include // for NULL, size_t +#include // for uint16_t +#include // for sockaddr +#include "khash.h" // for __i, khint32_t +#include "main.h" // for main_loop +#include "rpc/connection/loop.h" // for loop +#include "rpc/db/sb-db.h" // for db_authorized_set_whitelist_all +#include "rpc/sb-rpc.h" // for hashmap_cstr_t_ptr_t, hashmap_cstr_... +#include "sb-common.h" // for fmt_addr, ::SERVER_TYPE_TCP, LOG_ERROR #define ADDRESS_MAX_SIZE 256 #define MAX_CONNECTIONS 16 diff --git a/src/rpc/connection/server.h b/src/rpc/connection/server.h index e79eaa6..77c8590 100644 --- a/src/rpc/connection/server.h +++ b/src/rpc/connection/server.h @@ -16,7 +16,8 @@ #pragma once -#include "rpc/sb-rpc.h" +#include // for uv_handle_t, uv_stream_t +#include "sb-common.h" // for STATIC STATIC void connection_cb(uv_stream_t *server_stream, int status); STATIC void client_free_cb(uv_handle_t *handle); From effa41f2ac660320b3e7b585dee17e0c913e6035 Mon Sep 17 00:00:00 2001 From: Stephan Zeisberg Date: Mon, 14 Nov 2016 14:00:17 +0100 Subject: [PATCH 22/41] Fix bug which produced wrong responses --- src/rpc/connection/dispatch.c | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/src/rpc/connection/dispatch.c b/src/rpc/connection/dispatch.c index 634e0ba..65b90df 100644 --- a/src/rpc/connection/dispatch.c +++ b/src/rpc/connection/dispatch.c @@ -238,11 +238,8 @@ object handle_run(UNUSED(uint64_t con_id), UNUSED(uint64_t msgid), goto end; } - ret = ARRAY_OBJ(((array) { - .size = 1, - .capacity = 1, - .items = &UINTEGER_OBJ(callid) - })); + ADD(rv, UINTEGER_OBJ(callid)); + ret = ARRAY_OBJ(rv); end: return ret; @@ -318,11 +315,8 @@ object handle_result(UNUSED(uint64_t con_id), UNUSED(uint64_t msgid), hashmap_del(uint64_t, ptr_t)(callids, callid); - ret = ARRAY_OBJ(((array) { - .size = 1, - .capacity = 1, - .items = &UINTEGER_OBJ(callid) - })); + ADD(rv, UINTEGER_OBJ(callid)); + ret = ARRAY_OBJ(rv); end: return ret; @@ -484,11 +478,11 @@ dispatch_info msgpack_rpc_get_handler_for(const char *name, size_t name_len) int dispatch_table_init(void) { - dispatch_info register_info = {.func = handle_register, .async = true, + dispatch_info register_info = {.func = handle_register, .async = false, .name = (string) {.str = "register", .length = sizeof("register") - 1}}; - dispatch_info run_info = {.func = handle_run, .async = true, + dispatch_info run_info = {.func = handle_run, .async = false, .name = (string) {.str = "run", .length = sizeof("run") - 1}}; - dispatch_info result_info = {.func = handle_result, .async = true, + dispatch_info result_info = {.func = handle_result, .async = false, .name = (string) {.str = "result", .length = sizeof("result") - 1,}}; dispatch_info broadcast_info = {.func = handle_broadcast, .async = true, .name = (string) {.str = "broadcast", .length = sizeof("broadcast") - 1,}}; From 3b2a18f633f546f32e435726697d146d3dc30bdc Mon Sep 17 00:00:00 2001 From: Stephan Zeisberg Date: Mon, 14 Nov 2016 14:01:35 +0100 Subject: [PATCH 23/41] Add missing header files --- src/klist.h | 134 ++++++++++++++++++++++++++++++++++++++ src/main.h | 21 ++++++ src/rpc/connection/loop.h | 109 +++++++++++++++++++++++++++++++ 3 files changed, 264 insertions(+) create mode 100644 src/klist.h create mode 100644 src/main.h create mode 100644 src/rpc/connection/loop.h diff --git a/src/klist.h b/src/klist.h new file mode 100644 index 0000000..d6d576c --- /dev/null +++ b/src/klist.h @@ -0,0 +1,134 @@ +/* The MIT License + Copyright (c) 2008-2009, by Attractive Chaos + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + "Software"), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. +*/ + +#ifndef _AC_KLIST_H +#define _AC_KLIST_H + +#include +#include +#include "sb-common.h" + +#define KMEMPOOL_INIT(name, kmptype_t, kmpfree_f) \ + typedef struct { \ + size_t cnt, n, max; \ + kmptype_t **buf; \ + } kmp_##name##_t; \ + static inline kmp_##name##_t *kmp_init_##name(void) { \ + return CALLOC(1, kmp_##name##_t); \ + } \ + static inline void kmp_destroy_##name(kmp_##name##_t *mp) { \ + size_t k; \ + for (k = 0; k < mp->n; k++) { \ + kmpfree_f(mp->buf[k]); FREE(mp->buf[k]); \ + } \ + FREE(mp->buf); FREE(mp); \ + } \ + static inline kmptype_t *kmp_alloc_##name(kmp_##name##_t *mp) { \ + mp->cnt++; \ + if (mp->n == 0) { \ + return CALLOC(1, kmptype_t); \ + } \ + return mp->buf[--mp->n]; \ + } \ + static inline void kmp_free_##name(kmp_##name##_t *mp, kmptype_t *p) { \ + mp->cnt--; \ + if (mp->n == mp->max) { \ + mp->max = mp->max ? (mp->max << 1) : 16; \ + mp->buf = REALLOC_ARRAY(mp->buf, mp->max, kmptype_t *); \ + } \ + mp->buf[mp->n++] = p; \ + } + +#define kmempool_t(name) kmp_##name##_t +#define kmp_init(name) kmp_init_##name() +#define kmp_destroy(name, mp) kmp_destroy_##name(mp) +#define kmp_alloc(name, mp) kmp_alloc_##name(mp) +#define kmp_free(name, mp, p) kmp_free_##name(mp, p) + +#define KLIST_INIT(name, kltype_t, kmpfree_t) \ + struct __kl1_##name { \ + kltype_t data; \ + struct __kl1_##name *next; \ + }; \ + typedef struct __kl1_##name kl1_##name; \ + KMEMPOOL_INIT(name, kl1_##name, kmpfree_t) \ + typedef struct { \ + kl1_##name *head, *tail; \ + kmp_##name##_t *mp; \ + size_t size; \ + } kl_##name##_t; \ + static inline kl_##name##_t *kl_init_##name(void) { \ + kl_##name##_t *kl = CALLOC(1, kl_##name##_t); \ + kl->mp = kmp_init(name); \ + kl->head = kl->tail = kmp_alloc(name, kl->mp); \ + kl->head->next = 0; \ + return kl; \ + } \ + static inline void kl_destroy_##name(kl_##name##_t *kl) { \ + kl1_##name *p; \ + for (p = kl->head; p != kl->tail; p = p->next) { \ + kmp_free(name, kl->mp, p); \ + } \ + kmp_free(name, kl->mp, p); \ + kmp_destroy(name, kl->mp); \ + FREE(kl); \ + } \ + static inline void kl_push_##name(kl_##name##_t *kl, kltype_t d) { \ + kl1_##name *q, *p = kmp_alloc(name, kl->mp); \ + q = kl->tail; p->next = 0; kl->tail->next = p; kl->tail = p; \ + kl->size++; \ + q->data = d; \ + } \ + static inline kltype_t kl_shift_at_##name(kl_##name##_t *kl, \ + kl1_##name **n) { \ + assert((*n)->next); \ + kl1_##name *p; \ + kl->size--; \ + p = *n; \ + *n = (*n)->next; \ + if (p == kl->head) { \ + kl->head = *n; \ + } \ + kltype_t d = p->data; \ + kmp_free(name, kl->mp, p); \ + return d; \ + } + +#define kliter_t(name) kl1_##name +#define klist_t(name) kl_##name##_t +#define kl_val(iter) ((iter)->data) +#define kl_next(iter) ((iter)->next) +#define kl_begin(kl) ((kl)->head) +#define kl_end(kl) ((kl)->tail) + +#define kl_init(name) kl_init_##name() +#define kl_destroy(name, kl) kl_destroy_##name(kl) +#define kl_push(name, kl, d) kl_push_##name(kl, d) +#define kl_shift_at(name, kl, node) kl_shift_at_##name(kl, node) +#define kl_shift(name, kl) kl_shift_at(name, kl, &kl->head) +#define kl_empty(kl) ((kl)->size == 0) +// Iteration macros. It's ok to modify the list while iterating as long as a +// `break` statement is executed before the next iteration. +#define kl_iter(name, kl, p) kl_iter_at(name, kl, p, NULL) +#define kl_iter_at(name, kl, p, h) \ + for (kl1_##name **p = h ? h : &kl->head; *p != kl->tail; p = &(*p)->next) + +#endif diff --git a/src/main.h b/src/main.h new file mode 100644 index 0000000..eacfddb --- /dev/null +++ b/src/main.h @@ -0,0 +1,21 @@ +/** + * Copyright (C) 2015 splone UG + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + + #pragma once + +#include "rpc/connection/loop.h" + +extern loop main_loop; diff --git a/src/rpc/connection/loop.h b/src/rpc/connection/loop.h new file mode 100644 index 0000000..4b09734 --- /dev/null +++ b/src/rpc/connection/loop.h @@ -0,0 +1,109 @@ +/** + * Copyright (C) 2015 splone UG + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + * This file incorporates code covered by the following terms: + * + * Copyright Neovim contributors. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + #pragma once + +#include // for bool +#include // for size_t +#include // for uint64_t +#include // for uv_mutex_t +#include // for uv_hrtime, uv_timer_t, uv_asy... +#include "klist.h" // for mp, kl, k, p, KLIST_INIT, kli... +#include "kvec.h" // for connection::(anonymous), kv_pop +#include "rpc/connection/connection.h" // for connection +#include "rpc/connection/event.h" // for multiqueue, multiqueue_empty +#include "rpc/sb-rpc.h" // for callinfo, event + + +typedef void * WatcherPtr; + +#define _noop(x) +KLIST_INIT(WatcherPtr, WatcherPtr, _noop) + +typedef struct loop { + uv_loop_t uv; + multiqueue *events, *fast_events, *thread_events; + klist_t(WatcherPtr) *children; + uv_signal_t children_watcher; + uv_timer_t children_kill_timer, poll_timer; + size_t children_stop_requests; + uv_async_t async; + uv_mutex_t mutex; + int recursive; +} loop; + +#define CREATE_EVENT(multiqueue, handler, argc, ...) \ + do { \ + if (multiqueue) { \ + multiqueue_put((multiqueue), (handler), argc, __VA_ARGS__); \ + } else { \ + void *argv[argc] = { __VA_ARGS__ }; \ + (handler)(argv); \ + } \ + } while (0) + +// Poll for events until a condition or timeout +#define LOOP_PROCESS_EVENTS_UNTIL(loop, multiqueue, timeout, condition) \ + do { \ + int remaining = timeout; \ + uint64_t before = (remaining > 0) ? uv_hrtime() : 0; \ + while (!(condition)) { \ + LOOP_PROCESS_EVENTS(loop, multiqueue, remaining); \ + if (remaining == 0) { \ + break; \ + } else if (remaining > 0) { \ + uint64_t now = uv_hrtime(); \ + remaining -= (int) ((now - before) / 1000000); \ + before = now; \ + if (remaining <= 0) { \ + break; \ + } \ + } \ + } \ + } while (0) + +#define LOOP_PROCESS_EVENTS(loop, multiqueue, timeout) \ + do { \ + if (multiqueue && !multiqueue_empty(multiqueue)) { \ + multiqueue_process_events(multiqueue); \ + } else { \ + loop_poll_events(loop, timeout); \ + } \ + } while (0) + +void loop_init(loop *loop, void *data); +void loop_poll_events(loop *loop, int ms); +void loop_schedule(loop *loop, event event); +void loop_on_put(multiqueue *queue, void *data); +void loop_close(loop *loop, bool wait); +void loop_process_events_until(loop *loop, struct connection *con, + struct callinfo *cinfo); From 123465bc2860a7e832bd98a22b0de5b186e74487 Mon Sep 17 00:00:00 2001 From: Stephan Zeisberg Date: Mon, 14 Nov 2016 14:14:58 +0100 Subject: [PATCH 24/41] Try to make travis happy and downgrade msgpack from 2.0.0 to 1.4.2 --- third-party/CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/third-party/CMakeLists.txt b/third-party/CMakeLists.txt index 2322ccc..80e3321 100644 --- a/third-party/CMakeLists.txt +++ b/third-party/CMakeLists.txt @@ -84,8 +84,8 @@ include(ExternalProject) set(LIBUV_URL https://github.com/libuv/libuv/archive/v1.10.0.tar.gz) set(LIBUV_SHA256 50f4ed57d65af4ab634e2cbdd90c49213020e15b4d77d3631feb633cbba9239f) -set(MSGPACK_URL https://github.com/msgpack/msgpack-c/archive/cpp-2.0.0.tar.gz) -set(MSGPACK_SHA256 eb20b4bf15f20bad149ec82fffac74f16de2a8a797e321a3f8189d63263a511e) +set(MSGPACK_URL https://github.com/msgpack/msgpack-c/archive/cpp-1.4.2.tar.gz) +set(MSGPACK_SHA256 c739aab4f9ec1cc4352e1520fe0d0ec9271e98c2815e0e25fe4c6a2eb61a56ad) if(USE_BUNDLED_LIBUV) include(BuildLibuv) From f66c4df9dcfa44e678f5d893a3114d130680f7bf Mon Sep 17 00:00:00 2001 From: Stephan Zeisberg Date: Mon, 14 Nov 2016 14:17:09 +0100 Subject: [PATCH 25/41] Remove unused unit tests --- test/unit/event-queue-get.c | 39 --------------------------------- test/unit/event-queue-put.c | 43 ------------------------------------- 2 files changed, 82 deletions(-) delete mode 100644 test/unit/event-queue-get.c delete mode 100644 test/unit/event-queue-put.c diff --git a/test/unit/event-queue-get.c b/test/unit/event-queue-get.c deleted file mode 100644 index f697075..0000000 --- a/test/unit/event-queue-get.c +++ /dev/null @@ -1,39 +0,0 @@ -/** - * Copyright (C) 2015 splone UG - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ - -#include "sb-common.h" -#include "rpc/sb-rpc.h" -#include "helper-unix.h" - -equeue *equeue_root; -equeue *equeue_child_one; -static api_event events; - -void unit_event_queue_get(UNUSED(void **state)) -{ - equeue_root = equeue_new(NULL); - assert_non_null(equeue_root); - equeue_child_one = equeue_new(equeue_root); - assert_non_null(equeue_child_one); - - assert_int_not_equal(0, equeue_put(equeue_child_one, events)); - assert_false(TAILQ_EMPTY(&equeue_root->head)); - equeue_get(equeue_child_one); - assert_true(TAILQ_EMPTY(&equeue_root->head)); - - equeue_free(equeue_root); - equeue_free(equeue_child_one); -} diff --git a/test/unit/event-queue-put.c b/test/unit/event-queue-put.c deleted file mode 100644 index 5218f70..0000000 --- a/test/unit/event-queue-put.c +++ /dev/null @@ -1,43 +0,0 @@ -/** - * Copyright (C) 2015 splone UG - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ - -#include "sb-common.h" -#include "rpc/sb-rpc.h" -#include "helper-unix.h" - - -equeue *equeue_root; -equeue *equeue_child_one; -equeue *equeue_child_two; -static api_event events; - -void unit_event_queue_put(UNUSED(void **state)) -{ - equeue_root = equeue_new(NULL); - assert_non_null(equeue_root); - equeue_child_one = equeue_new(equeue_root); - assert_non_null(equeue_child_one); - equeue_child_two = equeue_new(equeue_root); - assert_non_null(equeue_child_two); - - assert_int_not_equal(0, equeue_put(equeue_root, events)); - assert_int_not_equal(0, equeue_put(NULL, events)); - assert_int_equal(0, equeue_put(equeue_child_one, events)); - - equeue_free(equeue_root); - equeue_free(equeue_child_one); - equeue_free(equeue_child_two); -} From b1c2e22cb8c9c04ea6423c3aa1d7d46e29e6cbc2 Mon Sep 17 00:00:00 2001 From: Stephan Zeisberg Date: Mon, 14 Nov 2016 14:23:40 +0100 Subject: [PATCH 26/41] Revert "Try to make travis happy and downgrade msgpack from 2.0.0 to 1.4.2" This reverts commit 123465bc2860a7e832bd98a22b0de5b186e74487. --- third-party/CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/third-party/CMakeLists.txt b/third-party/CMakeLists.txt index 80e3321..2322ccc 100644 --- a/third-party/CMakeLists.txt +++ b/third-party/CMakeLists.txt @@ -84,8 +84,8 @@ include(ExternalProject) set(LIBUV_URL https://github.com/libuv/libuv/archive/v1.10.0.tar.gz) set(LIBUV_SHA256 50f4ed57d65af4ab634e2cbdd90c49213020e15b4d77d3631feb633cbba9239f) -set(MSGPACK_URL https://github.com/msgpack/msgpack-c/archive/cpp-1.4.2.tar.gz) -set(MSGPACK_SHA256 c739aab4f9ec1cc4352e1520fe0d0ec9271e98c2815e0e25fe4c6a2eb61a56ad) +set(MSGPACK_URL https://github.com/msgpack/msgpack-c/archive/cpp-2.0.0.tar.gz) +set(MSGPACK_SHA256 eb20b4bf15f20bad149ec82fffac74f16de2a8a797e321a3f8189d63263a511e) if(USE_BUNDLED_LIBUV) include(BuildLibuv) From d403633fdd28dc93d632ab0913cc070809663b7a Mon Sep 17 00:00:00 2001 From: Stephan Zeisberg Date: Mon, 14 Nov 2016 14:45:18 +0100 Subject: [PATCH 27/41] Try to make travis happy and downgrade msgpack version from 2.0.0 to 1.0.0 --- third-party/CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/third-party/CMakeLists.txt b/third-party/CMakeLists.txt index 2322ccc..3321498 100644 --- a/third-party/CMakeLists.txt +++ b/third-party/CMakeLists.txt @@ -84,8 +84,8 @@ include(ExternalProject) set(LIBUV_URL https://github.com/libuv/libuv/archive/v1.10.0.tar.gz) set(LIBUV_SHA256 50f4ed57d65af4ab634e2cbdd90c49213020e15b4d77d3631feb633cbba9239f) -set(MSGPACK_URL https://github.com/msgpack/msgpack-c/archive/cpp-2.0.0.tar.gz) -set(MSGPACK_SHA256 eb20b4bf15f20bad149ec82fffac74f16de2a8a797e321a3f8189d63263a511e) +set(MSGPACK_URL https://github.com/msgpack/msgpack-c/archive/cpp-1.0.0.tar.gz) +set(MSGPACK_SHA256 afda64ca445203bb7092372b822bae8b2539fdcebbfc3f753f393628c2bcfe7d) if(USE_BUNDLED_LIBUV) include(BuildLibuv) From cebf5ed8a5548ab94111cef00d61e3ce8e884775 Mon Sep 17 00:00:00 2001 From: Stephan Zeisberg Date: Mon, 14 Nov 2016 14:51:03 +0100 Subject: [PATCH 28/41] Update travis config to new output dir structure --- .ci/after_success.sh | 2 +- .travis.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.ci/after_success.sh b/.ci/after_success.sh index cb41432..e256689 100755 --- a/.ci/after_success.sh +++ b/.ci/after_success.sh @@ -4,5 +4,5 @@ set -e set -o pipefail if [[ -n "${GCOV}" ]]; then - coveralls -e test -e out/CMakeFiles/CompilerIdC/CMakeCCompilerId.c -e out/CMakeFiles/CompilerIdCXX/CMakeCXXCompilerId.cpp --gcov "$(which "${GCOV}")" --encoding iso-8859-1 -b out || echo 'coveralls upload failed.' + coveralls -e test -e build/CMakeFiles/CompilerIdC/CMakeCCompilerId.c -e build/CMakeFiles/CompilerIdCXX/CMakeCXXCompilerId.cpp --gcov "$(which "${GCOV}")" --encoding iso-8859-1 -b build || echo 'coveralls upload failed.' fi diff --git a/.travis.yml b/.travis.yml index beec4b0..23d921b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -53,5 +53,5 @@ addons: - libhiredis-dev before_script: redis-server redis-test.conf -script: make sb && make test && make sb-makekey && ./out/bin/sb-makekey && ./out/bin/sb-test +script: make sb && make test && make sb-makekey && ./build/bin/sb-makekey && ./build/bin/sb-test after_success: .ci/after_success.sh From d037c41989309cae0b4779cfe5d1c1514a44c4a1 Mon Sep 17 00:00:00 2001 From: Stephan Zeisberg Date: Tue, 15 Nov 2016 10:06:12 +0100 Subject: [PATCH 29/41] Fix some gcc wshadow warnings --- CMakeLists.txt | 2 + src/rpc/connection/event-defs.h | 70 +++++++++++++++++++++++++++++++++ src/rpc/connection/event.c | 16 ++++---- src/rpc/connection/event.h | 22 +++++++++-- src/rpc/connection/loop.c | 4 +- src/rpc/connection/loop.h | 3 +- src/rpc/sb-rpc.h | 34 ---------------- 7 files changed, 103 insertions(+), 48 deletions(-) create mode 100644 src/rpc/connection/event-defs.h diff --git a/CMakeLists.txt b/CMakeLists.txt index fdd815d..ac7f4d1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -147,6 +147,7 @@ set(SPLONEBOX-SOURCES src/rpc/sb-rpc.h src/rpc/connection/event.c src/rpc/connection/event.h + src/rpc/connection/event-defs.h src/rpc/connection/streamhandle.c src/rpc/connection/streamhandle.h src/rpc/connection/inputstream.c @@ -235,6 +236,7 @@ set(TEST-SOURCES src/rpc/sb-rpc.h src/rpc/connection/event.c src/rpc/connection/event.h + src/rpc/connection/event-defs.h src/rpc/connection/streamhandle.c src/rpc/connection/streamhandle.h src/rpc/connection/inputstream.c diff --git a/src/rpc/connection/event-defs.h b/src/rpc/connection/event-defs.h new file mode 100644 index 0000000..1e5b0de --- /dev/null +++ b/src/rpc/connection/event-defs.h @@ -0,0 +1,70 @@ +/** + * Copyright (C) 2015 splone UG + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + * This file incorporates code covered by the following terms: + * + * Copyright Neovim contributors. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include "sb-common.h" + +#define EVENT_HANDLER_MAX_ARGC 6 + +typedef void (*argv_callback)(void **argv); +typedef struct message { + int priority; + argv_callback handler; + void *argv[EVENT_HANDLER_MAX_ARGC]; +} event; + +typedef void(*event_scheduler)(event e, void *data); + +#define VA_EVENT_INIT(event, p, h, a) \ + do { \ + sbassert(a <= EVENT_HANDLER_MAX_ARGC); \ + (event)->priority = p; \ + (event)->handler = h; \ + if (a) { \ + va_list args; \ + va_start(args, a); \ + for (int i = 0; i < a; i++) { \ + (event)->argv[i] = va_arg(args, void *); \ + } \ + va_end(args); \ + } \ + } while (0) + +static inline event event_create(int priority, argv_callback cb, int argc, ...) +{ + sbassert(argc <= EVENT_HANDLER_MAX_ARGC); + event e; + VA_EVENT_INIT(&e, priority, cb, argc); + return e; +} diff --git a/src/rpc/connection/event.c b/src/rpc/connection/event.c index 1f52b4d..bccc6cc 100644 --- a/src/rpc/connection/event.c +++ b/src/rpc/connection/event.c @@ -58,7 +58,7 @@ struct multiqueue { static multiqueue *multiqueue_new(multiqueue *parent, put_callback put_cb, void *data); static event multiqueue_remove(multiqueue *this); -static void multiqueue_push(multiqueue *this, event event); +static void multiqueue_push(multiqueue *this, event e); static multiqueueitem *multiqueue_node_data(QUEUE *q); static event NILEVENT = { .handler = NULL, .argv = {NULL} }; @@ -107,10 +107,10 @@ event multiqueue_get(multiqueue *this) return multiqueue_empty(this) ? NILEVENT : multiqueue_remove(this); } -void multiqueue_put_event(multiqueue *this, event event) +void multiqueue_put_event(multiqueue *this, event e) { sbassert(this); - multiqueue_push(this, event); + multiqueue_push(this, e); if (this->parent && this->parent->put_cb) { this->parent->put_cb(this->parent, this->parent->data); } @@ -120,9 +120,9 @@ void multiqueue_process_events(multiqueue *this) { sbassert(this); while (!multiqueue_empty(this)) { - event event = multiqueue_get(this); - if (event.handler) { - event.handler(event.argv); + event e = multiqueue_get(this); + if (e.handler) { + e.handler(e.argv); } } } @@ -170,11 +170,11 @@ static event multiqueue_remove(multiqueue *this) return rv; } -static void multiqueue_push(multiqueue *this, event event) +static void multiqueue_push(multiqueue *this, event e) { multiqueueitem *item = MALLOC(multiqueueitem); item->link = false; - item->data.item.event = event; + item->data.item.event = e; QUEUE_INSERT_TAIL(&this->headtail, &item->node); if (this->parent) { diff --git a/src/rpc/connection/event.h b/src/rpc/connection/event.h index 00054a4..a09351d 100644 --- a/src/rpc/connection/event.h +++ b/src/rpc/connection/event.h @@ -1,5 +1,5 @@ /** - * Copyright (C) 2016 splone UG + * Copyright (C) 2015 splone UG * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License, version 3, @@ -12,12 +12,28 @@ * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . + * + * This file incorporates code covered by the following terms: + * + * Copyright Neovim contributors. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ #pragma once #include // for bool -#include "rpc/sb-rpc.h" // for event +#include "rpc/connection/event-defs.h" typedef struct multiqueue multiqueue; @@ -27,7 +43,7 @@ multiqueue *multiqueue_new_parent(put_callback put_cb, void *data); multiqueue *multiqueue_new_child(multiqueue *parent); void multiqueue_free(multiqueue *this); event multiqueue_get(multiqueue *this); -void multiqueue_put_event(multiqueue *this, event event); +void multiqueue_put_event(multiqueue *this, event e); void multiqueue_process_events(multiqueue *this); bool multiqueue_empty(multiqueue *this); void multiqueue_replace_parent(multiqueue *this, multiqueue *new_parent); diff --git a/src/rpc/connection/loop.c b/src/rpc/connection/loop.c index c987bc0..e5ca1e9 100644 --- a/src/rpc/connection/loop.c +++ b/src/rpc/connection/loop.c @@ -80,10 +80,10 @@ void loop_poll_events(loop *loop, int ms) } // Schedule an event from another thread -void loop_schedule(loop *loop, event event) +void loop_schedule(loop *loop, event e) { uv_mutex_lock(&loop->mutex); - multiqueue_put_event(loop->thread_events, event); + multiqueue_put_event(loop->thread_events, e); uv_async_send(&loop->async); uv_mutex_unlock(&loop->mutex); } diff --git a/src/rpc/connection/loop.h b/src/rpc/connection/loop.h index 4b09734..997f357 100644 --- a/src/rpc/connection/loop.h +++ b/src/rpc/connection/loop.h @@ -41,6 +41,7 @@ #include "kvec.h" // for connection::(anonymous), kv_pop #include "rpc/connection/connection.h" // for connection #include "rpc/connection/event.h" // for multiqueue, multiqueue_empty +#include "rpc/connection/event-defs.h" #include "rpc/sb-rpc.h" // for callinfo, event @@ -102,7 +103,7 @@ typedef struct loop { void loop_init(loop *loop, void *data); void loop_poll_events(loop *loop, int ms); -void loop_schedule(loop *loop, event event); +void loop_schedule(loop *loop, event e); void loop_on_put(multiqueue *queue, void *data); void loop_close(loop *loop, bool wait); void loop_process_events_until(loop *loop, struct connection *con, diff --git a/src/rpc/sb-rpc.h b/src/rpc/sb-rpc.h index b8b27ee..e9cd89d 100644 --- a/src/rpc/sb-rpc.h +++ b/src/rpc/sb-rpc.h @@ -230,40 +230,6 @@ struct connection_request_event_info { uint64_t msgid; }; -#define EVENT_HANDLER_MAX_ARGC 6 - -typedef void (*argv_callback)(void **argv); -typedef struct message { - int priority; - argv_callback handler; - void *argv[EVENT_HANDLER_MAX_ARGC]; -} event; - -typedef void(*event_scheduler)(event event, void *data); - -#define VA_EVENT_INIT(event, p, h, a) \ - do { \ - sbassert(a <= EVENT_HANDLER_MAX_ARGC); \ - (event)->priority = p; \ - (event)->handler = h; \ - if (a) { \ - va_list args; \ - va_start(args, a); \ - for (int i = 0; i < a; i++) { \ - (event)->argv[i] = va_arg(args, void *); \ - } \ - va_end(args); \ - } \ - } while (0) - -static inline event event_create(int priority, argv_callback cb, int argc, ...) -{ - sbassert(argc <= EVENT_HANDLER_MAX_ARGC); - event event; - VA_EVENT_INIT(&event, priority, cb, argc); - return event; -} - /* Functions */ /** From ae17d1ae508f9c83c7ad472cf9bce26d7106b489 Mon Sep 17 00:00:00 2001 From: Stephan Zeisberg Date: Tue, 15 Nov 2016 10:19:14 +0100 Subject: [PATCH 30/41] Add python 3 to travis yml --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 23d921b..d69808b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -49,6 +49,7 @@ addons: - llvm-3.4-dev - ninja-build - pkg-config + - python3.3-dev - libbsd-dev - libhiredis-dev From 66b9fb982c2a3107ea83cea0b57fc80ebad4a4c2 Mon Sep 17 00:00:00 2001 From: Stephan Zeisberg Date: Tue, 15 Nov 2016 10:33:12 +0100 Subject: [PATCH 31/41] Add travis before install script to update python pip --- .ci/before_install.sh | 28 ++++++++++++++++++++++++++++ .travis.yml | 1 + 2 files changed, 29 insertions(+) create mode 100644 .ci/before_install.sh diff --git a/.ci/before_install.sh b/.ci/before_install.sh new file mode 100644 index 0000000..1bdd89d --- /dev/null +++ b/.ci/before_install.sh @@ -0,0 +1,28 @@ +#!/usr/bin/env bash + +set -e +set -o pipefail + +if [[ -n "${CI_TARGET}" ]]; then + exit +fi + +if [[ "${TRAVIS_OS_NAME}" == osx ]]; then + brew update +fi + +echo "Upgrade Python 2's pip." +pip2.7 -q install --user --upgrade pip + +if [[ "${TRAVIS_OS_NAME}" == osx ]]; then + echo "Install Python 3." + brew install python3 + echo "Upgrade Python 3's pip." + pip3 -q install --user --upgrade pip +else + # TODO: Replace with upgrade when Travis gets python3-pip package. + echo "Install pip for Python 3." + curl -sSL https://bootstrap.pypa.io/get-pip.py -o "${HOME}/get-pip.py" + # After this, pip in PATH will refer to Python 3's pip. + python3.3 "${HOME}/get-pip.py" --user --upgrade +fi diff --git a/.travis.yml b/.travis.yml index d69808b..1dda938 100644 --- a/.travis.yml +++ b/.travis.yml @@ -53,6 +53,7 @@ addons: - libbsd-dev - libhiredis-dev +before_install: .ci/before_install.sh before_script: redis-server redis-test.conf script: make sb && make test && make sb-makekey && ./build/bin/sb-makekey && ./build/bin/sb-test after_success: .ci/after_success.sh From 3b4a74d3b6f742a08cc98b8a625b3110f21aa975 Mon Sep 17 00:00:00 2001 From: Stephan Zeisberg Date: Tue, 15 Nov 2016 10:37:01 +0100 Subject: [PATCH 32/41] Fix git permission for travis before install script --- .ci/before_install.sh | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 .ci/before_install.sh diff --git a/.ci/before_install.sh b/.ci/before_install.sh old mode 100644 new mode 100755 From 7bd1823fa9d23603f0bb8b1a1f5e63b42d566e11 Mon Sep 17 00:00:00 2001 From: Stephan Zeisberg Date: Tue, 15 Nov 2016 10:54:25 +0100 Subject: [PATCH 33/41] Rearange travis before install dependencies --- .ci/before_install.sh | 8 ++++++++ .ci/install.sh | 17 +++++++++++++++++ .travis.yml | 19 ------------------- 3 files changed, 25 insertions(+), 19 deletions(-) mode change 100755 => 100644 .ci/before_install.sh create mode 100644 .ci/install.sh diff --git a/.ci/before_install.sh b/.ci/before_install.sh old mode 100755 new mode 100644 index 1bdd89d..48cdc16 --- a/.ci/before_install.sh +++ b/.ci/before_install.sh @@ -26,3 +26,11 @@ else # After this, pip in PATH will refer to Python 3's pip. python3.3 "${HOME}/get-pip.py" --user --upgrade fi + +# cmocka +wget https://cmocka.org/files/1.0/cmocka-1.0.1.tar.xz +tar -xJvf cmocka-1.0.1.tar.xz +cd cmocka-1.0.1 && mkdir build && cd build +cmake -DCMAKE_INSTALL_PREFIX:PATH=/usr .. && make -j2 && sudo make install +cd ../.. +rm -rf cmocka-1.0.1 diff --git a/.ci/install.sh b/.ci/install.sh new file mode 100644 index 0000000..7e1cb0a --- /dev/null +++ b/.ci/install.sh @@ -0,0 +1,17 @@ +#!/usr/bin/env bash + +set -e +set -o pipefail + +if [[ -n "${CI_TARGET}" ]]; then + exit +fi + +if [[ "${TRAVIS_OS_NAME}" == osx ]]; then + brew install gettext + brew reinstall -s libtool +fi + +# Use default CC to avoid compilation problems when installing Python modules. +echo "Install coveralls for Python 2." +CC=cc pip2.7 -q install --user --upgrade cpp-coveralls diff --git a/.travis.yml b/.travis.yml index 1dda938..f5cd723 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,25 +9,6 @@ matrix: compiler: gcc-5 env: GCOV=gcov-5 EXTRA_FLAGS="-DUSE_COVERAGE=ON" -before_install: - # cmocka - - wget https://cmocka.org/files/1.0/cmocka-1.0.1.tar.xz - - tar -xJvf cmocka-1.0.1.tar.xz - - cd cmocka-1.0.1 && mkdir build && cd build - - cmake -DCMAKE_INSTALL_PREFIX:PATH=/usr .. && make -j2 && sudo make install - - cd ../.. - - rm -rf cmocka-1.0.1 - # libuv - - curl -L https://github.com/libuv/libuv/archive/v1.8.0.tar.gz | tar xzf - - - (cd libuv-1.8.0 && ./autogen.sh && ./configure --prefix=/usr && make && sudo make install) - - rm -rf libuv-1.8.0 - # msgpack-c - - curl -L https://github.com/msgpack/msgpack-c/archive/cpp-1.4.1.tar.gz | tar xzf - - - (cd msgpack-c-cpp-1.4.1 && ./bootstrap && ./configure --prefix=/usr && make && sudo make install) - - rm -rf msgpack-c-cpp-1.4.1 - # coveralls - - pip install --user cpp-coveralls - addons: apt: sources: From 26950aebdb66998d74352be47fe0f81c0ac842e8 Mon Sep 17 00:00:00 2001 From: Stephan Zeisberg Date: Tue, 15 Nov 2016 10:57:22 +0100 Subject: [PATCH 34/41] Fix git permissions for travis install script --- .ci/before_install.sh | 0 .ci/install.sh | 0 2 files changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 .ci/before_install.sh mode change 100644 => 100755 .ci/install.sh diff --git a/.ci/before_install.sh b/.ci/before_install.sh old mode 100644 new mode 100755 diff --git a/.ci/install.sh b/.ci/install.sh old mode 100644 new mode 100755 From 08f4c7f70897210ee1cef7169ff57768fdd432b1 Mon Sep 17 00:00:00 2001 From: Stephan Zeisberg Date: Tue, 15 Nov 2016 12:41:48 +0100 Subject: [PATCH 35/41] Try to fix travis cmocka install failure --- .ci/before_install.sh | 8 -------- .travis.yml | 13 ++++++++++++- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/.ci/before_install.sh b/.ci/before_install.sh index 48cdc16..1bdd89d 100755 --- a/.ci/before_install.sh +++ b/.ci/before_install.sh @@ -26,11 +26,3 @@ else # After this, pip in PATH will refer to Python 3's pip. python3.3 "${HOME}/get-pip.py" --user --upgrade fi - -# cmocka -wget https://cmocka.org/files/1.0/cmocka-1.0.1.tar.xz -tar -xJvf cmocka-1.0.1.tar.xz -cd cmocka-1.0.1 && mkdir build && cd build -cmake -DCMAKE_INSTALL_PREFIX:PATH=/usr .. && make -j2 && sudo make install -cd ../.. -rm -rf cmocka-1.0.1 diff --git a/.travis.yml b/.travis.yml index f5cd723..a679e57 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,6 +9,18 @@ matrix: compiler: gcc-5 env: GCOV=gcov-5 EXTRA_FLAGS="-DUSE_COVERAGE=ON" +before_install: + # cmocka + - wget https://cmocka.org/files/1.0/cmocka-1.0.1.tar.xz + - tar -xJvf cmocka-1.0.1.tar.xz + - cd cmocka-1.0.1 && mkdir build && cd build + - cmake -DCMAKE_INSTALL_PREFIX:PATH=/usr .. && make -j2 && sudo make install + - cd ../.. + - rm -rf cmocka-1.0.1 + - .ci/before_install.sh + +install: .ci/install.sh + addons: apt: sources: @@ -34,7 +46,6 @@ addons: - libbsd-dev - libhiredis-dev -before_install: .ci/before_install.sh before_script: redis-server redis-test.conf script: make sb && make test && make sb-makekey && ./build/bin/sb-makekey && ./build/bin/sb-test after_success: .ci/after_success.sh From 874f15927e2116e07f9f1f02608113fbcfc726ca Mon Sep 17 00:00:00 2001 From: Stephan Zeisberg Date: Tue, 15 Nov 2016 13:36:55 +0100 Subject: [PATCH 36/41] Try to fix gcov cmake flag usage --- .travis.yml | 2 +- Makefile | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index a679e57..f4cc41a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,7 +7,7 @@ matrix: env: EXTRA_FLAGS="-DCLANG_ADDRESS_SANITIZER=ON" - os: linux compiler: gcc-5 - env: GCOV=gcov-5 EXTRA_FLAGS="-DUSE_COVERAGE=ON" + env: GCOV=gcov-5 CMAKE_FLAGS="-DUSE_COVERAGE=ON" before_install: # cmocka diff --git a/Makefile b/Makefile index a56f388..0f8ab3e 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ BUILD_DIR := out CMAKE_BUILD_TYPE ?= Debug -FLAGS := -DCMAKE_BUILD_TYPE=$(CMAKE_BUILD_TYPE) +CMAKE_FLAGS := -DCMAKE_BUILD_TYPE=$(CMAKE_BUILD_TYPE) EXTRA_FLAGS ?= BUILD_TYPE ?= $(shell (type ninja > /dev/null 2>&1 && echo "Ninja") || echo "Unix Makefiles") @@ -26,7 +26,10 @@ endif BUILD_CMD = $(BUILD_TOOL) $(VERBOSE_FLAG) +# Extra CMake flags which extend the default set +CMAKE_EXTRA_FLAGS ?= USE_BUNDLED_DEPS ?= +DEPS_CMAKE_FLAGS ?= ifneq (,$(USE_BUNDLED_DEPS)) BUNDLED_CMAKE_FLAG := -DUSE_BUNDLED=$(USE_BUNDLED_DEPS) From 86cfa482498a2170f347eccc15f4276c782ad2c5 Mon Sep 17 00:00:00 2001 From: mkind Date: Wed, 16 Nov 2016 17:31:28 +0100 Subject: [PATCH 37/41] The check is not needed since the pointer is valid by definition. This holds because it's only used in non-public manner. --- src/api/broadcast.c | 3 --- src/api/run.c | 3 --- src/api/subscribe.c | 3 --- src/api/unsubscribe.c | 3 --- 4 files changed, 12 deletions(-) diff --git a/src/api/broadcast.c b/src/api/broadcast.c index a6b0e68..2136d81 100644 --- a/src/api/broadcast.c +++ b/src/api/broadcast.c @@ -24,9 +24,6 @@ int api_broadcast(string event, array args, struct api_error *api_error) { - if (!api_error) - return -1; - object o = copy_object(ARRAY_OBJ(args)); if (!connection_send_event(0, event.str, o.data.array)) { diff --git a/src/api/run.c b/src/api/run.c index 6e530f7..1119b99 100644 --- a/src/api/run.c +++ b/src/api/run.c @@ -28,9 +28,6 @@ int api_run(char *targetpluginkey, string function_name, uint64_t callid, string run; object result; - if (!api_error) - return (-1); - if (db_plugin_verify(targetpluginkey) == -1) { error_set(api_error, API_ERROR_TYPE_VALIDATION, "API key is invalid."); return (-1); diff --git a/src/api/subscribe.c b/src/api/subscribe.c index 3e9c50a..5fcb55e 100644 --- a/src/api/subscribe.c +++ b/src/api/subscribe.c @@ -24,9 +24,6 @@ int api_subscribe(uint64_t con_id, string event, struct api_error *api_error) { - if (!api_error) - return -1; - size_t length = (event.length < METHOD_MAXLEN ? event.length : METHOD_MAXLEN); char e[METHOD_MAXLEN + 1]; memcpy(e, event.str, length); diff --git a/src/api/unsubscribe.c b/src/api/unsubscribe.c index 4ac6b4d..a0e329d 100644 --- a/src/api/unsubscribe.c +++ b/src/api/unsubscribe.c @@ -24,9 +24,6 @@ int api_unsubscribe(uint64_t con_id, string event, struct api_error *api_error) { - if (!api_error) - return -1; - size_t length = (event.length < METHOD_MAXLEN ? event.length : METHOD_MAXLEN); char e[METHOD_MAXLEN + 1]; memcpy(e, event.str, length); From 1e6ebf97d0c633ee5506ceb7b2ec87d011005b10 Mon Sep 17 00:00:00 2001 From: mkind Date: Thu, 17 Nov 2016 13:15:07 +0100 Subject: [PATCH 38/41] adding sb assertions to api-calls --- src/api/broadcast.c | 2 ++ src/api/register.c | 3 +++ src/api/result.c | 4 ++-- src/api/run.c | 2 ++ src/api/subscribe.c | 3 +++ src/api/unsubscribe.c | 3 +++ 6 files changed, 15 insertions(+), 2 deletions(-) diff --git a/src/api/broadcast.c b/src/api/broadcast.c index 2136d81..22cf640 100644 --- a/src/api/broadcast.c +++ b/src/api/broadcast.c @@ -26,6 +26,8 @@ int api_broadcast(string event, array args, struct api_error *api_error) { object o = copy_object(ARRAY_OBJ(args)); + sbassert(api_error); + if (!connection_send_event(0, event.str, o.data.array)) { error_set(api_error, API_ERROR_TYPE_VALIDATION, "Broadcasting event failed"); diff --git a/src/api/register.c b/src/api/register.c index b9bbd25..86613b1 100644 --- a/src/api/register.c +++ b/src/api/register.c @@ -26,6 +26,9 @@ int api_register(string name, string desc, string author, string license, { object *func; + sbassert(pluginkey); + sbassert(api_error); + if (functions.size == 0) { error_set(api_error, API_ERROR_TYPE_VALIDATION, "Error in register API request. Invalid params size."); diff --git a/src/api/result.c b/src/api/result.c index 98fa922..cd52dc2 100644 --- a/src/api/result.c +++ b/src/api/result.c @@ -27,8 +27,8 @@ int api_result(char *targetpluginkey, uint64_t callid, array args, string result; object res; - if (!api_error) - return (-1); + sbassert(targetpluginkey); + sbassert(api_error); array meta = ARRAY_DICT_INIT; ADD(meta, UINTEGER_OBJ(callid)); diff --git a/src/api/run.c b/src/api/run.c index 1119b99..9d95625 100644 --- a/src/api/run.c +++ b/src/api/run.c @@ -28,6 +28,8 @@ int api_run(char *targetpluginkey, string function_name, uint64_t callid, string run; object result; + sbassert(api_error); + if (db_plugin_verify(targetpluginkey) == -1) { error_set(api_error, API_ERROR_TYPE_VALIDATION, "API key is invalid."); return (-1); diff --git a/src/api/subscribe.c b/src/api/subscribe.c index 5fcb55e..0fe02a7 100644 --- a/src/api/subscribe.c +++ b/src/api/subscribe.c @@ -26,6 +26,9 @@ int api_subscribe(uint64_t con_id, string event, struct api_error *api_error) { size_t length = (event.length < METHOD_MAXLEN ? event.length : METHOD_MAXLEN); char e[METHOD_MAXLEN + 1]; + + sbassert(api_error); + memcpy(e, event.str, length); e[length] = '\000'; diff --git a/src/api/unsubscribe.c b/src/api/unsubscribe.c index a0e329d..de758dc 100644 --- a/src/api/unsubscribe.c +++ b/src/api/unsubscribe.c @@ -26,6 +26,9 @@ int api_unsubscribe(uint64_t con_id, string event, struct api_error *api_error) { size_t length = (event.length < METHOD_MAXLEN ? event.length : METHOD_MAXLEN); char e[METHOD_MAXLEN + 1]; + + sbassert(api_error); + memcpy(e, event.str, length); e[length] = '\000'; From 292f20ffa515823df84a2cec5e5c1f2d7aac06cf Mon Sep 17 00:00:00 2001 From: mkind Date: Thu, 17 Nov 2016 14:41:52 +0100 Subject: [PATCH 39/41] moving declaration at top of function --- src/api/helpers.c | 1 - src/api/run.c | 6 +++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/api/helpers.c b/src/api/helpers.c index d0f1b25..96d75ab 100644 --- a/src/api/helpers.c +++ b/src/api/helpers.c @@ -92,7 +92,6 @@ void api_free_dictionary(dictionary value) FREE(value.items); } -/// Creates a deep clone of an object object copy_object(object obj) { switch (obj.type) { diff --git a/src/api/run.c b/src/api/run.c index 9d95625..a3e7884 100644 --- a/src/api/run.c +++ b/src/api/run.c @@ -27,6 +27,8 @@ int api_run(char *targetpluginkey, string function_name, uint64_t callid, { string run; object result; + array meta = ARRAY_DICT_INIT; + array request = ARRAY_DICT_INIT; sbassert(api_error); @@ -41,12 +43,10 @@ int api_run(char *targetpluginkey, string function_name, uint64_t callid, return (-1); } - array meta = ARRAY_DICT_INIT; ADD(meta, OBJECT_OBJ((object) OBJECT_INIT)); ADD(meta, UINTEGER_OBJ(callid)); - array request = ARRAY_DICT_INIT; - ADD(request, ARRAY_OBJ(meta)); + ADD(request, ARRAY_OBJ(meta)); ADD(request, STRING_OBJ(cstring_copy_string(function_name.str))); ADD(request, copy_object(ARRAY_OBJ(args))); From 65be7cf99a2330c322ab01faa1490a6c50851124 Mon Sep 17 00:00:00 2001 From: mkind Date: Thu, 17 Nov 2016 14:42:24 +0100 Subject: [PATCH 40/41] increasing version number to 0.1.7 --- src/version.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/version.h b/src/version.h index 124db07..3ca89b3 100644 --- a/src/version.h +++ b/src/version.h @@ -21,7 +21,7 @@ #define VERSION_MAJOR 0 #define VERSION_MINOR 1 -#define VERSION_REVISION 5 +#define VERSION_REVISION 7 #define VERSION STRINGIFY(VERSION_MAJOR) "." \ STRINGIFY(VERSION_MINOR) "." \ From 2681567100cb6321b651653e35c39fb0da2b89c9 Mon Sep 17 00:00:00 2001 From: mkind Date: Sun, 26 Nov 2017 21:00:21 +0100 Subject: [PATCH 41/41] introducing memory functions that abort program on failure --- CMakeLists.txt | 8 ++++ src/confparse.c | 10 ++--- src/hashmap.c | 2 +- src/klist.h | 8 ++-- src/mem.c | 47 +++++++++++++++++++++ src/mem.h | 20 +++++++++ src/options.c | 4 +- src/rpc/connection/connection.c | 18 +++----- src/rpc/connection/crypto.c | 19 +++------ src/rpc/connection/event.c | 6 +-- src/rpc/connection/inputstream.c | 7 +-- src/rpc/connection/outputstream.c | 15 ++----- src/rpc/connection/server.c | 15 ++----- src/rpc/connection/streamhandle.c | 5 +-- src/rpc/msgpack/helpers.c | 4 +- src/sb-common.h | 24 +++-------- src/sb-pluginkey.c | 2 +- src/string.c | 2 +- src/util.c | 6 +-- test/functional/crypto.c | 14 ++---- test/functional/db-function-flush-args.c | 10 ++--- test/functional/db-function-register.c | 6 +-- test/functional/db-function-verify.c | 6 +-- test/functional/dispatch-handle-broadcast.c | 4 +- test/functional/dispatch-handle-register.c | 2 +- test/functional/dispatch-handle-result.c | 2 +- test/functional/dispatch-handle-run.c | 2 +- test/functional/dispatch-handle-subscribe.c | 4 +- test/helper-all.c | 7 +-- 29 files changed, 147 insertions(+), 132 deletions(-) create mode 100644 src/mem.c create mode 100644 src/mem.h diff --git a/CMakeLists.txt b/CMakeLists.txt index ac7f4d1..a0c15b6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -135,6 +135,8 @@ set(SPLONEBOX-SOURCES src/address.c src/address.h src/sbmemzero.c + src/mem.c + src/mem.h src/api/sb-api.h src/api/register.c src/api/result.c @@ -176,6 +178,8 @@ set(SPLONEBOX-SOURCES set(SB-PLUGINKEY-SOURCES src/sb-pluginkey.c src/sb-common.h + src/mem.c + src/mem.h src/rpc/sb-rpc.h src/util.c src/confparse.c @@ -187,6 +191,8 @@ set(SB-PLUGINKEY-SOURCES # sb-makekey target sources set(SB-MAKEKEY-SOURCES src/sb-common.h + src/mem.c + src/mem.h src/reallocarray.c src/tweetnacl.c src/tweetnacl.h @@ -221,6 +227,8 @@ set(TEST-SOURCES src/parse.h src/util.c src/util.h + src/mem.c + src/mem.h src/address.c src/address.h src/sbmemzero.c diff --git a/src/confparse.c b/src/confparse.c index 58939fc..c3b19d4 100644 --- a/src/confparse.c +++ b/src/confparse.c @@ -82,7 +82,7 @@ bitarray_init_zero(unsigned int n_bits) { /* round up to the next int. */ size_t sz = (n_bits+BITARRAY_MASK) >> BITARRAY_SHIFT; - return (CALLOC(sz, unsigned int)); + return calloc_or_die(sz, sizeof(unsigned int)); } /** Free the bit array ba. */ @@ -243,7 +243,7 @@ STATIC void reset(const configformat *fmt, void *options, const configvar *var, if (!use_defaults) return; /* all done */ if (var->initvalue) { - c = CALLOC(1, configline); + c = calloc_or_die(1, sizeof(configline)); c->key = box_strdup(var->name); c->value = box_strdup(var->initvalue); if (assign_value(fmt, options, c) < 0) { @@ -338,7 +338,7 @@ STATIC const char * unescape_string(const char *s, char **result, } } end_of_loop: - out = *result = MALLOC_ARRAY((size_t)(cp-s + 1), char); + out = *result = malloc_array_or_die((size_t)(cp-s + 1), sizeof(char)); cp = s+1; while (1) { switch (*cp) @@ -405,7 +405,7 @@ STATIC void line_append(configline **lst, const char *key, const char *val) { configline *newline; - newline = CALLOC(1, configline); + newline = calloc_or_die(1, sizeof(configline)); newline->key = box_strdup(key); newline->value = box_strdup(val); newline->next = NULL; @@ -668,7 +668,7 @@ int confparse_get_lines(const char *string, configline **result, int extended) /* This list can get long, so we keep a pointer to the end of it * rather than using line_append over and over and getting * n^2 performance. */ - *next = CALLOC(1, configline); + *next = calloc_or_die(1, sizeof(configline)); (*next)->key = k; (*next)->value = v; (*next)->next = NULL; diff --git a/src/hashmap.c b/src/hashmap.c index 5b22b32..017c68e 100644 --- a/src/hashmap.c +++ b/src/hashmap.c @@ -59,7 +59,7 @@ \ hashmap(T, U) *hashmap_##T##_##U##_new() \ { \ - hashmap(T, U) *rv = MALLOC(hashmap(T, U)); \ + hashmap(T, U) *rv = malloc_or_die(sizeof(hashmap(T, U))); \ rv->table = kh_init(T##_##U##_map); \ return rv; \ } \ diff --git a/src/klist.h b/src/klist.h index d6d576c..4da2cab 100644 --- a/src/klist.h +++ b/src/klist.h @@ -32,7 +32,7 @@ kmptype_t **buf; \ } kmp_##name##_t; \ static inline kmp_##name##_t *kmp_init_##name(void) { \ - return CALLOC(1, kmp_##name##_t); \ + return calloc_or_die(1, sizeof(kmp_##name##_t)); \ } \ static inline void kmp_destroy_##name(kmp_##name##_t *mp) { \ size_t k; \ @@ -44,7 +44,7 @@ static inline kmptype_t *kmp_alloc_##name(kmp_##name##_t *mp) { \ mp->cnt++; \ if (mp->n == 0) { \ - return CALLOC(1, kmptype_t); \ + return calloc_or_die(1, sizeof(kmptype_t)); \ } \ return mp->buf[--mp->n]; \ } \ @@ -52,7 +52,7 @@ mp->cnt--; \ if (mp->n == mp->max) { \ mp->max = mp->max ? (mp->max << 1) : 16; \ - mp->buf = REALLOC_ARRAY(mp->buf, mp->max, kmptype_t *); \ + mp->buf = realloc_array_or_die(mp->buf, mp->max, sizeof(kmptype_t *)); \ } \ mp->buf[mp->n++] = p; \ } @@ -76,7 +76,7 @@ size_t size; \ } kl_##name##_t; \ static inline kl_##name##_t *kl_init_##name(void) { \ - kl_##name##_t *kl = CALLOC(1, kl_##name##_t); \ + kl_##name##_t *kl = calloc_or_die(1, sizeof(kl_##name##_t)); \ kl->mp = kmp_init(name); \ kl->head = kl->tail = kmp_alloc(name, kl->mp); \ kl->head->next = 0; \ diff --git a/src/mem.c b/src/mem.c new file mode 100644 index 0000000..b838869 --- /dev/null +++ b/src/mem.c @@ -0,0 +1,47 @@ +#include + +#include "sb-common.h" + +void *malloc_or_die(size_t n) +{ + void *p = malloc(n); + if (!p && 0 < n) + LOG_MEMERROR(); + return p; +} + + +void *malloc_array_or_die(size_t nmemb, size_t n) +{ + void *p = reallocarray(NULL, nmemb, n); + if (!p && 0 < n) + LOG_MEMERROR(); + return p; +} + + +void *calloc_or_die(size_t nmemb, size_t n) +{ + void *p = calloc(nmemb, n); + if (!p && 0 < n) + LOG_MEMERROR(); + return p; +} + + +void *realloc_array_or_die(void *ptr, size_t nmemb, size_t n) +{ + void *p = reallocarray(ptr, nmemb, n); + if (!p && 0 < n) + LOG_MEMERROR(); + return p; +} + + +void *realloc_or_die(void *ptr, size_t n) +{ + void *p = realloc(ptr, n); + if (!p && 0 < n) + LOG_MEMERROR(); + return p; +} diff --git a/src/mem.h b/src/mem.h new file mode 100644 index 0000000..fd5ee39 --- /dev/null +++ b/src/mem.h @@ -0,0 +1,20 @@ +#pragma once + +#include + +#define FREE(p) do { \ + if (PREDICT_LIKELY((p)!=NULL)) \ + free(p); \ + p = NULL; \ + } while (0) + +#define MALLOC_TYPE(t) ((t)malloc_or_die(sizeof(t))) + +void *reallocarray(void *optr, size_t nmemb, size_t size); + +void *realloc_array_or_die(void *ptr, size_t nmemb, size_t n); +void *malloc_array_or_die(size_t nmemb, size_t n); +void *malloc_or_die(size_t n); +void *calloc_or_die(size_t nmemb, size_t n); +void *realloc_or_die(void *ptr, size_t n); + diff --git a/src/options.c b/src/options.c index a1eca04..6bc35a8 100644 --- a/src/options.c +++ b/src/options.c @@ -152,7 +152,7 @@ STATIC setoptionerror options_init_from_string(const char *cf) int retval; setoptionerror err = SETOPT_ERR_MISC; - newoptions = CALLOC(1, options); + newoptions = calloc_or_die(1, sizeof(options)); newoptions->magic_ = OR_OPTIONS_MAGIC; options_init(newoptions); @@ -212,7 +212,7 @@ STATIC char *load_boxrc_from_disk(void) return (NULL); } - string = MALLOC_ARRAY((size_t)(statbuf.st_size+1), char); + string = malloc_array_or_die((size_t)(statbuf.st_size+1), sizeof(char)); ssize_t r = filesystem_read_all(fd, string, (size_t)statbuf.st_size); if (r < 0) { diff --git a/src/rpc/connection/connection.c b/src/rpc/connection/connection.c index c00ebb8..8645c43 100644 --- a/src/rpc/connection/connection.c +++ b/src/rpc/connection/connection.c @@ -123,10 +123,7 @@ int connection_create(uv_stream_t *stream) stream->data = NULL; - struct connection *con = MALLOC(struct connection); - - if (con == NULL) - return (-1); + struct connection *con = malloc_or_die(sizeof(struct connection)); con->id = next_con_id++; con->msgid = 1; @@ -228,7 +225,7 @@ STATIC void broadcast_event(char *name, array args) con = kv_A(subscribed, i); if (con->pending_requests) { - wbuffer *rv = MALLOC(wbuffer); + wbuffer *rv = malloc_or_die(sizeof(wbuffer)); rv->size = sbuf.size; rv->data = sb_memdup_nulterm(sbuf.data, sbuf.size); kv_push(con->delayed_notifications, rv); @@ -443,12 +440,7 @@ STATIC void parse_cb(inputstream *istream, void *data, bool eof) } con->packet.end = con->packet.length; - con->packet.data = MALLOC_ARRAY(MAX(con->packet.end, read), unsigned char); - - if (!con->packet.data) { - LOG_ERROR("Failed to alloc mem for con packet."); - goto end; - } + con->packet.data = malloc_array_or_die(MAX(con->packet.end, read), sizeof(unsigned char)); if (msgpack_unpacker_reserve_buffer(con->mpac, MAX(read, con->packet.end)) == false) { @@ -564,7 +556,7 @@ bool connection_send_event(uint64_t id, char *name, array args) api_free_array(args); if (con->pending_requests) { - wbuffer *rv = MALLOC(wbuffer); + wbuffer *rv = malloc_or_die(sizeof(wbuffer)); rv->size = sbuf.size; rv->data = sb_memdup_nulterm(sbuf.data, sbuf.size); kv_push(con->delayed_notifications, rv); @@ -738,7 +730,7 @@ STATIC void connection_handle_request(struct connection *con, dispatcher.async = true; } - connection_request_event_info *eventinfo = MALLOC(connection_request_event_info); + connection_request_event_info *eventinfo = malloc_or_die(sizeof(connection_request_event_info)); eventinfo->con = con; eventinfo->dispatcher = dispatcher; eventinfo->args = args; diff --git a/src/rpc/connection/crypto.c b/src/rpc/connection/crypto.c index 5638732..8562496 100644 --- a/src/rpc/connection/crypto.c +++ b/src/rpc/connection/crypto.c @@ -500,10 +500,7 @@ int crypto_write(struct crypto_context *cc, char *data, * (crypto_box_ZEROBYTES) */ packetlen = length + 56; - packet = MALLOC_ARRAY(packetlen, unsigned char); - - if (packet == NULL) - return -1; + packet = malloc_array_or_die(packetlen, sizeof(unsigned char)); /* update nonce */ nonce_update(cc); @@ -527,11 +524,8 @@ int crypto_write(struct crypto_context *cc, char *data, memcpy(packet + 16, lengthbox + 16, 24); blocklen = length + 32; - block = CALLOC(blocklen, unsigned char); - ciphertext = MALLOC_ARRAY(blocklen, unsigned char); - - if ((block == NULL) || (ciphertext == NULL)) - return -1; + block = calloc_or_die(blocklen, sizeof(unsigned char)); + ciphertext = malloc_array_or_die(blocklen, sizeof(unsigned char)); memcpy(block + 32, data, length); @@ -593,11 +587,8 @@ int crypto_read(struct crypto_context *cc, unsigned char *in, char *out, /* ciphertextlen = length - 8 (id) - 72 (length) - 8 (nonce) + 16 (padding) */ ciphertextlen = length - 24; - block = MALLOC_ARRAY(ciphertextlen, unsigned char); - ciphertextpadded = CALLOC(ciphertextlen, unsigned char); - - if ((block == NULL) || (ciphertextpadded == NULL)) - return -1; + block = malloc_array_or_die(ciphertextlen, sizeof(unsigned char)); + ciphertextpadded = calloc_or_die(ciphertextlen, sizeof(unsigned char)); memcpy(ciphertextpadded + 16, in + 40, blocklen); diff --git a/src/rpc/connection/event.c b/src/rpc/connection/event.c index bccc6cc..8a4fa33 100644 --- a/src/rpc/connection/event.c +++ b/src/rpc/connection/event.c @@ -77,7 +77,7 @@ multiqueue *multiqueue_new_child(multiqueue *parent) static multiqueue *multiqueue_new(multiqueue *parent, put_callback put_cb, void *data) { - multiqueue *rv = MALLOC(multiqueue); + multiqueue *rv = malloc_or_die(sizeof(multiqueue)); QUEUE_INIT(&rv->headtail); rv->parent = parent; rv->put_cb = put_cb; @@ -172,14 +172,14 @@ static event multiqueue_remove(multiqueue *this) static void multiqueue_push(multiqueue *this, event e) { - multiqueueitem *item = MALLOC(multiqueueitem); + multiqueueitem *item = malloc_or_die(sizeof(multiqueueitem)); item->link = false; item->data.item.event = e; QUEUE_INSERT_TAIL(&this->headtail, &item->node); if (this->parent) { // push link node to the parent queue - item->data.item.parent = MALLOC(multiqueueitem); + item->data.item.parent = malloc_or_die(sizeof(multiqueueitem)); item->data.item.parent->link = true; item->data.item.parent->data.queue = this; QUEUE_INSERT_TAIL(&this->parent->headtail, &item->data.item.parent->node); diff --git a/src/rpc/connection/inputstream.c b/src/rpc/connection/inputstream.c index 43df7e7..f05c443 100644 --- a/src/rpc/connection/inputstream.c +++ b/src/rpc/connection/inputstream.c @@ -42,10 +42,7 @@ inputstream *inputstream_new(inputstream_cb cb, uint32_t buffer_size, void *data) { - inputstream *rs = MALLOC(inputstream); - - if (rs == NULL) - return (NULL); + inputstream *rs = malloc_or_die(sizeof(inputstream)); rs->data = data; rs->size = 0; @@ -54,7 +51,7 @@ inputstream *inputstream_new(inputstream_cb cb, uint32_t buffer_size, rs->free_handle = false; /* initialize circular buffer */ - rs->circbuf_start = MALLOC_ARRAY(buffer_size, unsigned char); + rs->circbuf_start = malloc_array_or_die(buffer_size, sizeof(unsigned char)); rs->circbuf_read_pos = rs->circbuf_start; rs->circbuf_write_pos = rs->circbuf_start; rs->circbuf_end = rs->circbuf_start + buffer_size; diff --git a/src/rpc/connection/outputstream.c b/src/rpc/connection/outputstream.c index a4a0b2e..03078aa 100644 --- a/src/rpc/connection/outputstream.c +++ b/src/rpc/connection/outputstream.c @@ -40,10 +40,7 @@ outputstream *outputstream_new(uint32_t maxmem) { - outputstream *ws = MALLOC(outputstream); - - if (ws == NULL) - return (NULL); + outputstream *ws = malloc_or_die(sizeof(outputstream)); ws->maxmem = maxmem; ws->stream = NULL; @@ -78,18 +75,12 @@ int outputstream_write(outputstream *ostream, char *buffer, size_t len) buf.base = buffer; buf.len = len; - data = MALLOC(struct write_request_data); - - if (data == NULL) - return (-1); + data = malloc_or_die(sizeof(struct write_request_data)); data->ostream = ostream; data->buffer = buffer; data->len = len; - req = MALLOC(uv_write_t); - - if (req == NULL) - return (-1); + req = malloc_or_die(sizeof(uv_write_t)); req->data = data; ostream->curmem += len; diff --git a/src/rpc/connection/server.c b/src/rpc/connection/server.c index b04184e..f44956f 100644 --- a/src/rpc/connection/server.c +++ b/src/rpc/connection/server.c @@ -72,16 +72,13 @@ int server_start_tcp(boxaddr *addr, uint16_t port) sbassert(addr); - server = MALLOC(struct server); + server = malloc_or_die(sizeof(struct server)); if (hashmap_has(cstr_t, ptr_t)(servers, fmt_addr(addr))) { LOG("Already listening on %s", fmt_addr(addr)); return (-1); } - if (server == NULL) - return (-1); - uv_stream_t *stream = NULL; box_addr_to_sockaddr(addr, port, &server->socket.tcp.addr, @@ -121,16 +118,13 @@ int server_start_pipe(char *name) sbassert(name); - server = MALLOC(struct server); + server = malloc_or_die(sizeof(struct server)); if (hashmap_has(cstr_t, ptr_t)(servers, name)) { LOG("Already listening on %s", name); return (-1); } - if (server == NULL) - return (-1); - uv_stream_t *stream = NULL; if (strlcpy(server->socket.pipe.addr, name, sizeof(server->socket.pipe.addr)) @@ -215,10 +209,7 @@ STATIC void connection_cb(uv_stream_t *server_stream, int status) hbuflen = sizeof(hbuf); server = server_stream->data; - client = MALLOC(uv_stream_t); - - if (client == NULL) - return; + client = malloc_or_die(sizeof(uv_stream_t)); if (server->type == SERVER_TYPE_TCP) uv_tcp_init(&main_loop.uv, (uv_tcp_t *)client); diff --git a/src/rpc/connection/streamhandle.c b/src/rpc/connection/streamhandle.c index b087adb..bb3478a 100644 --- a/src/rpc/connection/streamhandle.c +++ b/src/rpc/connection/streamhandle.c @@ -74,10 +74,7 @@ STATIC struct streamhandle *init_streamhandle(uv_handle_t *handle) struct streamhandle *hd; if (handle->data == NULL) { - hd = MALLOC(struct streamhandle); - - if (hd == NULL) - return (NULL); + hd = malloc_or_die(sizeof(struct streamhandle)); hd->istream = NULL; hd->ostream = NULL; diff --git a/src/rpc/msgpack/helpers.c b/src/rpc/msgpack/helpers.c index 77ec406..99c775c 100644 --- a/src/rpc/msgpack/helpers.c +++ b/src/rpc/msgpack/helpers.c @@ -192,7 +192,7 @@ bool msgpack_rpc_to_array(const msgpack_object *const obj, array *const arg) } arg->size = obj->via.array.size; - arg->items = CALLOC(obj->via.array.size, object); + arg->items = calloc_or_die(obj->via.array.size, sizeof(object)); for (uint32_t i = 0; i < obj->via.array.size; i++) { if (!msgpack_rpc_to_object(obj->via.array.ptr + i, &arg->items[i])) { @@ -211,7 +211,7 @@ bool msgpack_rpc_to_dictionary(const msgpack_object *const obj, } arg->size = obj->via.array.size; - arg->items = CALLOC(obj->via.map.size, key_value_pair); + arg->items = calloc_or_die(obj->via.map.size, sizeof(key_value_pair)); for (uint32_t i = 0; i < obj->via.map.size; i++) { diff --git a/src/sb-common.h b/src/sb-common.h index 18b2c6d..95c186c 100644 --- a/src/sb-common.h +++ b/src/sb-common.h @@ -78,6 +78,7 @@ #include "queue.h" #include "khash.h" #include "kvec.h" +#include "mem.h" /* Structs */ #define API_ERROR_MESSAGE_LEN 512 @@ -383,23 +384,6 @@ define UNUSED(x) x #define PREDICT_UNLIKELY(exp) (exp) #endif -#define MALLOC(type) ((type *)reallocarray(NULL, 1, sizeof(type))) - -#define MALLOC_ARRAY(number, type) \ - ((type *)reallocarray(NULL, number, sizeof(type))) - -#define CALLOC(number, type) \ - ((type *)calloc(number, sizeof(type))) - -#define REALLOC_ARRAY(pointer, number, type) \ - ((type *)reallocarray(pointer, number, sizeof(type))) - -#define FREE(p) do { \ - if (PREDICT_LIKELY((p)!=NULL)) \ - free(p); \ - p= NULL; \ - } while (0) - #define LOG(...) \ do { \ fprintf(stdout, __VA_ARGS__); \ @@ -423,6 +407,12 @@ define UNUSED(x) x } \ } while (0) +#define LOG_MEMERROR() \ + do { \ + LOG_ERROR("[%s] %s (%d):\tFailed to alloc memory.\n", \ + __FILE__, __func__, __LINE__); \ + } while (0) \ + #if 8 == 8 #define ARCH_64 #elif 8 == 4 diff --git a/src/sb-pluginkey.c b/src/sb-pluginkey.c index 62b984d..e3aeedb 100644 --- a/src/sb-pluginkey.c +++ b/src/sb-pluginkey.c @@ -48,7 +48,7 @@ int main(int argc, char **argv) goto fail; } - pluginkey = MALLOC_ARRAY((PLUGINKEY_SIZE*2) + 1, char); + pluginkey = malloc_array_or_die((PLUGINKEY_SIZE*2) + 1, sizeof(char)); if (!pluginkey) { LOG("Failed to alloc mem for pluginkey_base16_encoded.\n"); goto fail; diff --git a/src/string.c b/src/string.c index bfa27c5..e1a5d41 100644 --- a/src/string.c +++ b/src/string.c @@ -39,7 +39,7 @@ string cstring_copy_string(const char *str) return (string) STRING_INIT; length = strlen(str); - ret = MALLOC_ARRAY(length + 1, char); + ret = malloc_array_or_die(length + 1, sizeof(char)); strlcpy(ret, str, length + 1); diff --git a/src/util.c b/src/util.c index bfd5993..b4fc31a 100644 --- a/src/util.c +++ b/src/util.c @@ -242,7 +242,7 @@ char * box_strndup(const char *s, size_t n) sbassert(s); - dup = MALLOC_ARRAY((n+1), char); + dup = malloc_array_or_die((n+1), sizeof(char)); strncpy(dup, s, n); dup[n]='\0'; @@ -257,7 +257,7 @@ void * sb_memdup(const void *mem, size_t len) char *duplicate; sbassert(mem); - duplicate = MALLOC_ARRAY(len, char); + duplicate = malloc_array_or_die(len, sizeof(char)); memcpy(duplicate, mem, len); return duplicate; @@ -270,7 +270,7 @@ void * sb_memdup_nulterm(const void *mem, size_t len) char *duplicate; sbassert(mem); - duplicate = MALLOC_ARRAY((len + 1), char); + duplicate = malloc_array_or_die((len + 1), sizeof(char)); memcpy(duplicate, mem, len); duplicate[len] = '\0'; diff --git a/test/functional/crypto.c b/test/functional/crypto.c index e5d1c43..0d527ea 100644 --- a/test/functional/crypto.c +++ b/test/functional/crypto.c @@ -46,11 +46,8 @@ int validate_crypto_cookie_packet(unsigned char *buffer, ciphertextlen = 160; blocklen = 144; - block = MALLOC_ARRAY(ciphertextlen, unsigned char); - ciphertextpadded = CALLOC(ciphertextlen, unsigned char); - - if (block == NULL || ciphertextpadded == NULL) - return (-1); + block = malloc_array_or_die(ciphertextlen, sizeof(unsigned char)); + ciphertextpadded = calloc_or_die(ciphertextlen, sizeof(unsigned char)); memcpy(ciphertextpadded + 16, buffer + 24, blocklen); @@ -100,11 +97,8 @@ int validate_crypto_write(unsigned char *buffer, UNUSED(uint64_t length)) ciphertextlen = unpackedlen - 24; blocklen = unpackedlen - 40; - block = MALLOC_ARRAY(ciphertextlen, unsigned char); - ciphertextpadded = CALLOC(ciphertextlen, unsigned char); - - if (block == NULL || ciphertextpadded == NULL) - return (-1); + block = malloc_array_or_die(ciphertextlen, sizeof(unsigned char)); + ciphertextpadded = calloc_or_die(ciphertextlen, sizeof(unsigned char)); memcpy(ciphertextpadded + 16, buffer + 40, blocklen); diff --git a/test/functional/db-function-flush-args.c b/test/functional/db-function-flush-args.c index 85d7289..4ec3a1c 100644 --- a/test/functional/db-function-flush-args.c +++ b/test/functional/db-function-flush-args.c @@ -60,7 +60,7 @@ void functional_db_function_flush_args(UNUSED(void **state)) ssize_t argc = 0; params.size = 4; - params.items = CALLOC(params.size, object); + params.items = calloc_or_die(params.size, sizeof(object)); params.items[0].type = OBJECT_TYPE_STR; params.items[0].data.string = name; @@ -70,8 +70,8 @@ void functional_db_function_flush_args(UNUSED(void **state)) params.items[2].type = OBJECT_TYPE_ARRAY; params.items[2].data.array.size = 1; - params.items[2].data.array.items = CALLOC(params.items[2].data.array.size, - object); + params.items[2].data.array.items = calloc_or_die( + params.items[2].data.array.size, sizeof(object)); params.items[2].data.array.items[0].type = OBJECT_TYPE_INT; params.items[2].data.array.items[0].data.uinteger = 6; @@ -100,8 +100,8 @@ void functional_db_function_flush_args(UNUSED(void **state)) api_free_array(params.items[2].data.array); params.items[2].data.array.size = 2; - params.items[2].data.array.items = CALLOC(params.items[2].data.array.size, - object); + params.items[2].data.array.items = calloc_or_die( + params.items[2].data.array.size, sizeof(object)); params.items[2].data.array.items[0].type = OBJECT_TYPE_INT; params.items[2].data.array.items[0].data.uinteger = 6; params.items[2].data.array.items[0].type = OBJECT_TYPE_INT; diff --git a/test/functional/db-function-register.c b/test/functional/db-function-register.c index 482f93b..d551319 100644 --- a/test/functional/db-function-register.c +++ b/test/functional/db-function-register.c @@ -34,7 +34,7 @@ void functional_db_function_add(UNUSED(void **state)) array params; params.size = 4; - params.items = CALLOC(params.size, object); + params.items = calloc_or_die(params.size, sizeof(object)); params.items[0].type = OBJECT_TYPE_STR; params.items[0].data.string = name; @@ -44,8 +44,8 @@ void functional_db_function_add(UNUSED(void **state)) params.items[2].type = OBJECT_TYPE_ARRAY; params.items[2].data.array.size = 1; - params.items[2].data.array.items = CALLOC(params.items[2].data.array.size, - object); + params.items[2].data.array.items = calloc_or_die( + params.items[2].data.array.size, sizeof(object)); params.items[2].data.array.items[0].type = OBJECT_TYPE_INT; params.items[2].data.array.items[0].data.uinteger = 6; diff --git a/test/functional/db-function-verify.c b/test/functional/db-function-verify.c index e351876..9eba55d 100644 --- a/test/functional/db-function-verify.c +++ b/test/functional/db-function-verify.c @@ -34,7 +34,7 @@ void functional_db_function_verify(UNUSED(void **state)) array params, *args; params.size = 4; - params.items = CALLOC(params.size, object); + params.items = calloc_or_die(params.size, sizeof(object)); params.items[0].type = OBJECT_TYPE_STR; params.items[0].data.string = name; @@ -44,8 +44,8 @@ void functional_db_function_verify(UNUSED(void **state)) params.items[2].type = OBJECT_TYPE_ARRAY; params.items[2].data.array.size = 1; - params.items[2].data.array.items = CALLOC(params.items[2].data.array.size, - object); + params.items[2].data.array.items = calloc_or_die( + params.items[2].data.array.size, sizeof(object)); params.items[2].data.array.items[0].type = OBJECT_TYPE_INT; params.items[2].data.array.items[0].data.uinteger = 6; diff --git a/test/functional/dispatch-handle-broadcast.c b/test/functional/dispatch-handle-broadcast.c index 89234fa..2970a52 100644 --- a/test/functional/dispatch-handle-broadcast.c +++ b/test/functional/dispatch-handle-broadcast.c @@ -117,12 +117,12 @@ void functional_dispatch_handle_broadcast(UNUSED(void **state)) struct api_error error = ERROR_INIT; array request; - con1 = CALLOC(1, struct connection); + con1 = calloc_or_die(1, sizeof(struct connection)); con1->id = (uint64_t) randommod(281474976710656LL); con1->msgid = 4321; con1->subscribed_events = hashmap_new(cstr_t, ptr_t)(); - con2 = CALLOC(1, struct connection); + con2 = calloc_or_die(1, sizeof(struct connection)); con2->id = (uint64_t) randommod(281474976710656LL); con2->msgid = 4321; con2->subscribed_events = hashmap_new(cstr_t, ptr_t)(); diff --git a/test/functional/dispatch-handle-register.c b/test/functional/dispatch-handle-register.c index 8eb1f38..dc6912e 100644 --- a/test/functional/dispatch-handle-register.c +++ b/test/functional/dispatch-handle-register.c @@ -181,7 +181,7 @@ void functional_dispatch_handle_register(UNUSED(void **state)) struct api_error error = ERROR_INIT; char pluginkey[PLUGINKEY_STRING_SIZE] = "012345789ABCDEFH"; - con = CALLOC(1, struct connection); + con = calloc_or_die(1, sizeof(struct connection)); con->closed = true; con->id = 1234; con->msgid = 4321; diff --git a/test/functional/dispatch-handle-result.c b/test/functional/dispatch-handle-result.c index f077fea..105ce31 100644 --- a/test/functional/dispatch-handle-result.c +++ b/test/functional/dispatch-handle-result.c @@ -132,7 +132,7 @@ void functional_dispatch_handle_result(UNUSED(void **state)) /* create test plugin that is used for the tests */ struct plugin *plugin = helper_get_example_plugin(); - con = CALLOC(1, struct connection); + con = calloc_or_die(1, sizeof(struct connection)); con->closed = true; con->id = (uint64_t) randommod(281474976710656LL); con->msgid = 4321; diff --git a/test/functional/dispatch-handle-run.c b/test/functional/dispatch-handle-run.c index d29e767..27ba977 100644 --- a/test/functional/dispatch-handle-run.c +++ b/test/functional/dispatch-handle-run.c @@ -121,7 +121,7 @@ void functional_dispatch_handle_run(UNUSED(void **state)) struct api_error error = ERROR_INIT; array request; - con = CALLOC(1, struct connection); + con = calloc_or_die(1, sizeof(struct connection)); con->closed = true; con->id = (uint64_t) randommod(281474976710656LL); con->msgid = 4321; diff --git a/test/functional/dispatch-handle-subscribe.c b/test/functional/dispatch-handle-subscribe.c index 9ee0e47..254dfa3 100644 --- a/test/functional/dispatch-handle-subscribe.c +++ b/test/functional/dispatch-handle-subscribe.c @@ -62,12 +62,12 @@ void functional_dispatch_handle_subscribe(UNUSED(void **state)) struct api_error error = ERROR_INIT; array request; - con1 = CALLOC(1, struct connection); + con1 = calloc_or_die(1, sizeof(struct connection)); con1->id = (uint64_t) randommod(281474976710656LL); con1->msgid = 4321; con1->subscribed_events = hashmap_new(cstr_t, ptr_t)(); - con2 = CALLOC(1, struct connection); + con2 = calloc_or_die(1, sizeof(struct connection)); con2->id = (uint64_t) randommod(281474976710656LL); con2->msgid = 4321; con2->subscribed_events = hashmap_new(cstr_t, ptr_t)(); diff --git a/test/helper-all.c b/test/helper-all.c index 850d7d9..a2dcd65 100644 --- a/test/helper-all.c +++ b/test/helper-all.c @@ -71,11 +71,8 @@ void connect_and_create(char *pluginkey) struct plugin *helper_get_example_plugin(void) { - struct plugin *p = MALLOC(struct plugin); - struct function *f = MALLOC(struct function); - - if (!p || !f) - LOG_ERROR("[test] Failed to alloc mem for example plugin.\n"); + struct plugin *p = malloc_or_die(sizeof(struct plugin)); + struct function *f = malloc_or_die(sizeof(struct function)); p->key = (string) {.str = "0123456789ABCDEF", .length = sizeof("0123456789ABCDEF") - 1};