diff --git a/dap_chain_node.c b/dap_chain_node.c index 4a837c4d0247ed29e9f794b92f2b8d8dd862d552..76979a5a73167eef0711f926d3a71c689de95389 100644 --- a/dap_chain_node.c +++ b/dap_chain_node.c @@ -5,25 +5,153 @@ This file is part of DAP (Deus Applications Prototypes) the open source project - DAP (Deus Applicaions Prototypes) is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. + DAP (Deus Applicaions Prototypes) is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. - DAP 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 General Public License for more details. + DAP 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 General Public License for more details. - You should have received a copy of the GNU General Public License - along with any DAP based project. If not, see <http://www.gnu.org/licenses/>. -*/ + You should have received a copy of the GNU General Public License + along with any DAP based project. If not, see <http://www.gnu.org/licenses/>. + */ #include <sys/socket.h> #include <netinet/in.h> +#include <string.h> +#include "dap_hash.h" +#include "rand/dap_rand.h" #include "dap_chain_net.h" #include "dap_chain_node.h" #define LOG_TAG "chain_node" +/** + * Generate node address by shard id + */ +dap_chain_node_addr_t* dap_chain_node_gen_addr(dap_chain_shard_id_t *shard_id) +{ + if(!shard_id) + return NULL; + dap_chain_node_addr_t *a_addr = DAP_NEW_Z(dap_chain_node_addr_t); + dap_chain_hash_t a_hash; + dap_hash(shard_id, sizeof(dap_chain_shard_id_t), a_hash.raw, sizeof(a_hash.raw), DAP_HASH_TYPE_KECCAK); + // first 4 bytes is last 4 bytes of shard id hash + memcpy(a_addr->raw, a_hash.raw + sizeof(a_hash.raw) - sizeof(uint64_t) / 2, sizeof(uint64_t) / 2); + // last 4 bytes is random + randombytes(a_addr->raw + sizeof(uint64_t) / 2, sizeof(uint64_t) / 2); + // for LITTLE_ENDIAN (Intel), do nothing, otherwise swap bytes + a_addr->uint64 = le64toh(a_addr->uint64); // a_addr->raw the same a_addr->uint64 + return a_addr; +} + +/** + * Check the validity of the node address by shard id + */ +bool dap_chain_node_check_addr(dap_chain_node_addr_t *addr, dap_chain_shard_id_t *shard_id) +{ + bool ret = false; + if(!addr || !shard_id) + return ret; + // generate new address by shard_id + dap_chain_node_addr_t *tmp_addr = dap_chain_node_gen_addr(shard_id); + if(tmp_addr) { + + if((uint32_t) addr->uint64 == (uint32_t) tmp_addr->uint64) + ret = true; + DAP_DELETE(tmp_addr); + } + return ret; +} + +/** + * Convert binary data to binhex encoded data. + * + * out output buffer, must be twice the number of bytes to encode. + * len is the size of the data in the in[] buffer to encode. + * return the number of bytes encoded, or -1 on error. + */ +int bin2hex(char *out, const unsigned char *in, int len) +{ + int ct = len; + static char hex[] = "0123456789ABCDEF"; + if(!in || !out || len < 0) + return -1; + // hexadecimal lookup table + while(ct-- > 0) + { + *out++ = hex[*in >> 4]; + *out++ = hex[*in++ & 0x0F]; + } + return len; +} + +/** + * Convert binhex encoded data to binary data + * + * len is the size of the data in the in[] buffer to decode, and must be even. + * out outputbuffer must be at least half of "len" in size. + * The buffers in[] and out[] can be the same to allow in-place decoding. + * return the number of bytes encoded, or -1 on error. + */ +int hex2bin(char *out, const unsigned char *in, int len) +{ + // '0'-'9' = 0x30-0x39 + // 'a'-'f' = 0x61-0x66 + // 'A'-'F' = 0x41-0x46 + int ct = len; + if(!in || !out || len < 0 || (len & 1)) + return -1; + while(ct > 0) + { + char ch1 = ((*in >= 'a') ? (*in++ - 'a' + 10) : ((*in >= 'A') ? (*in++ - 'A' + 10) : (*in++ - '0'))) << 4; + char ch2 = ((*in >= 'a') ? (*in++ - 'a' + 10) : ((*in >= 'A') ? (*in++ - 'A' + 10) : (*in++ - '0'))); // ((*in >= 'A') ? (*in++ - 'A' + 10) : (*in++ - '0')); + *out++ = ch1 + ch2; + ct -= 2; + } + return len; +} + +/** + * Serialize dap_chain_node_info_t + * size[out] - length of output string + * return data or NULL if error + */ +uint8_t* dap_chain_node_serialize(dap_chain_node_info_t *node_info, size_t *size) +{ + if(!node_info) + return NULL; + size_t node_info_size = sizeof(dap_chain_node_info_t) + node_info->hdr.uplinks_number * sizeof(dap_chain_addr_t); + size_t node_info_str_size = 2 * node_info_size + 1; + uint8_t *node_info_str = DAP_NEW_Z_SIZE(uint8_t, node_info_str_size); + if(bin2hex(node_info_str, (const unsigned char *) node_info, node_info_size) == -1) { + DAP_DELETE(node_info_str); + return NULL; + } + + if(size) + *size = node_info_str_size; + return node_info_str; +} + +/** + * Deserialize dap_chain_node_info_t + * size[in] - length of input string + * return data or NULL if error + */ +dap_chain_node_info_t* dap_chain_node_deserialize(uint8_t *node_info_str, size_t size) +{ + if(!node_info_str) + return NULL; + dap_chain_node_info_t *node_info = DAP_NEW_Z_SIZE(dap_chain_node_info_t, (size / 2 + 1)); + if(hex2bin((char*) node_info, (const unsigned char *) node_info_str, size) == -1) { + DAP_DELETE(node_info); + return NULL; + } + return node_info; +} + diff --git a/dap_chain_node.h b/dap_chain_node.h index bc93af7fd1d5632038a823026f24e406bb3ff47b..69936ff9a95c6fa88171bfd9d37a94a134715492 100644 --- a/dap_chain_node.h +++ b/dap_chain_node.h @@ -23,6 +23,7 @@ #include <stdint.h> #include <stddef.h> +#include <stdbool.h> #include <sys/socket.h> #include <netinet/in.h> @@ -79,6 +80,7 @@ typedef struct dap_chain_node_info uint32_t uplinks_number; struct in_addr ext_addr_v4; struct in6_addr ext_addr_v6; + char alias[256]; } DAP_ALIGN_PACKED hdr; dap_chain_addr_t uplinks[]; } DAP_ALIGN_PACKED dap_chain_node_info_t; @@ -87,3 +89,49 @@ typedef struct dap_chain_node_publ{ dap_chain_hash_fast_t decl_hash; dap_chain_node_info_t node_info; } DAP_ALIGN_PACKED dap_chain_node_publ_t; + + +/** + * Serialize dap_chain_node_info_t + * size[out] - length of output string + * return data or NULL if error + */ +uint8_t* dap_chain_node_serialize(dap_chain_node_info_t *node_info, size_t *size); + +/** + * Deserialize dap_chain_node_info_t + * size[in] - length of input string + * return data or NULL if error + */ +dap_chain_node_info_t* dap_chain_node_deserialize(uint8_t *node_info_str, size_t size); + +/** + * Generate node addr by shard id + */ +dap_chain_node_addr_t* dap_chain_node_gen_addr(dap_chain_shard_id_t *shard_id); + +/** + * Check the validity of the node address by shard id + */ +bool dap_chain_node_check_addr(dap_chain_node_addr_t *addr, dap_chain_shard_id_t *shard_id); + +/** + * Convert binary data to binhex encoded data. + * + * out output buffer, must be twice the number of bytes to encode. + * len is the size of the data in the in[] buffer to encode. + * return the number of bytes encoded, or -1 on error. + */ +int bin2hex(char *out, const unsigned char *in, int len); + +/** + * Convert binhex encoded data to binary data + * + * len is the size of the data in the in[] buffer to decode, and must be even. + * out outputbuffer must be at least half of "len" in size. + * The buffers in[] and out[] can be the same to allow in-place decoding. + * return the number of bytes encoded, or -1 on error. + */ +int hex2bin(char *out, const unsigned char *in, int len); + + diff --git a/dap_chain_node_cli_cmd.c b/dap_chain_node_cli_cmd.c index dd16ce66e877285b884eebc10fcfc77c31f02d3f..0f65d87086c5e6f28a6aa0c4226ac9a798f5bef2 100644 --- a/dap_chain_node_cli_cmd.c +++ b/dap_chain_node_cli_cmd.c @@ -34,19 +34,11 @@ #include "dap_chain_global_db.h" #include "dap_chain_node_cli_cmd.h" -uint8_t* dap_chain_global_db_node_serialize(dap_chain_node_info_t *node_info, size_t *size) -{ - if(!node_info) - return NULL; - size_t node_info_size = sizeof(dap_chain_node_info_t) + node_info->hdr.uplinks_number * sizeof(dap_chain_addr_t); - size_t a_request_size = 2 * node_info_size + 1; - uint8_t *a_request = DAP_NEW_Z_SIZE(uint8_t, a_request_size); +// Max and min macros +#define max(a,b) ((a) > (b) ? (a) : (b)) +#define min(a,b) ((a) < (b) ? (a) : (b)) - bin2hex(a_request, (const unsigned char *)node_info, node_info_size); - if(size) - *size = a_request_size; - return a_request; -} +#define LOG_TAG "chain_node_cli_cmd" /** * find option value @@ -80,6 +72,73 @@ static int find_option_val(const char** argv, int arg_start, int arg_end, const } return 0; } +/** + * Convert string to digit + */ +static void digit_from_string(const char *num_str, uint8_t *raw, size_t raw_len) +{ + if(!num_str) + return; + uint64_t val; + if(!strncasecmp(num_str, "0x", 2)) { + val = strtoull(num_str + 2, NULL, 16); + } + else { + val = strtoull(num_str, NULL, 10); + } + // for LITTLE_ENDIAN (Intel), do nothing, otherwise swap bytes + val = le64toh(val); + memset(raw, 0, raw_len); + memcpy(raw, &val, min(raw_len, sizeof(uint64_t))); +} + +/** + * Add alias in base + */ +static bool add_alias(const char *alias, dap_chain_node_addr_t *addr) +{ + const char *a_key = alias; + char a_value[2 * sizeof(dap_chain_node_addr_t) + 1]; + if(bin2hex(a_value, (const unsigned char *) addr, sizeof(dap_chain_node_addr_t)) == -1) + return false; + a_value[2 * sizeof(dap_chain_node_addr_t) + 1] = '\0'; + bool res = dap_chain_global_db_gr_set(a_key, a_value, GROUP_ALIAS); + return res; +} + +/** + * Delete alias from base + */ +static bool del_alias(const char *alias, dap_chain_node_addr_t *addr) +{ + const char *a_key = alias; + bool res = dap_chain_global_db_gr_del(a_key, GROUP_ALIAS); + return res; +} + +/** + * Find in base addr by alias + * + * return addr, NULL if not found + */ +static dap_chain_node_addr_t* get_name_by_alias(const char *alias) +{ + dap_chain_node_addr_t *addr = NULL; + if(!alias) + return NULL; + const char *a_key = alias; + char *addr_str = dap_chain_global_db_gr_get(a_key, GROUP_ALIAS); + if(addr_str && strlen(addr_str) == sizeof(dap_chain_node_addr_t) * 2) + { + dap_chain_node_addr_t *addr = DAP_NEW_Z(dap_chain_node_addr_t); + if(hex2bin((char*) addr, (const unsigned char *) addr_str, sizeof(dap_chain_node_addr_t) * 2) == -1) { + DAP_DELETE(addr); + addr = NULL; + } + } + DAP_DELETE(addr_str); + return addr; +} /** * global_db command @@ -88,77 +147,137 @@ static int find_option_val(const char** argv, int arg_start, int arg_end, const */ int com_global_db(int argc, const char ** argv, char **str_reply) { + enum { + CMD_NONE, CMD_ADD, CMD_DEL, CMD_LINK, CMD_DUMP + }; printf("com_global_db\n"); int arg_index = 1; const char *cmd_str = NULL; - // find 'node' parameter +// find 'node' parameter arg_index = find_option_val(argv, arg_index, argc, "node", NULL); - if(!arg_index || argc < 5) { + if(!arg_index || argc < 4) { if(str_reply) *str_reply = g_strdup("parameters are not valid"); return -1; } arg_index++; - // find command (add or del) - int cmd_num = 0; +// find command (add, delete, etc) + int cmd_num = CMD_NONE; if(find_option_val(argv, arg_index, argc, "add", NULL)) { - cmd_num = 1; + cmd_num = CMD_ADD; } else if(find_option_val(argv, arg_index, argc, "del", NULL)) { - cmd_num = 2; + cmd_num = CMD_DEL; + } + else if(find_option_val(argv, arg_index, argc, "link", NULL)) { + cmd_num = CMD_LINK; } - if(!cmd_num) { + else if(find_option_val(argv, arg_index, argc, "dump", NULL)) { + cmd_num = CMD_DUMP; + } + if(cmd_num == CMD_NONE) { if(str_reply) *str_reply = g_strdup_printf("command %s not recognized", argv[1]); return -1; } - const char *addr_str = NULL, *shard_str = NULL, *ipv4_str = NULL, *ipv6_str = NULL; - // find addr & alias + const char *addr_str = NULL, *alias_str = NULL, *shard_str = NULL, *ipv4_str = NULL, *ipv6_str = NULL; +// find addr, alias find_option_val(argv, arg_index, argc, "-addr", &addr_str); + find_option_val(argv, arg_index, argc, "-alias", &alias_str); find_option_val(argv, arg_index, argc, "-shard", &shard_str); find_option_val(argv, arg_index, argc, "-ipv4", &ipv4_str); find_option_val(argv, arg_index, argc, "-ipv6", &ipv6_str); - if(!arg_index || argc < 5) { - if(str_reply) - *str_reply = g_strdup("parameters are not valid"); - return -1; - } - if(!addr_str) { - if(str_reply) - *str_reply = g_strdup("not found -addr parameter"); - return -1; - } + +// struct to write to the global db dap_chain_node_info_t node_info; memset(&node_info, 0, sizeof(dap_chain_node_info_t)); - // store this IP address in dap_addr, dap_addr.uint64 = struct sockaddr_in.sin_addr - inet_pton(AF_INET, addr_str, &(node_info.hdr.address.uint64)); - memcpy(&(node_info.hdr.address.raw), &(node_info.hdr.address.uint64), sizeof(uint64_t)); - // now get it back - //inet_ntop(AF_INET, &(node_info.hdr.address.uint64), str, INET6_ADDRSTRLEN); + switch (cmd_num) + { +// add new node to global_db + case CMD_ADD: - if(shard_str) { - int64_t shard_id = strtoll(shard_str, NULL, 10); - memcpy(&node_info.hdr.shard_id.raw, &shard_id, sizeof(int64_t)); + if(!arg_index || argc < 8) { + if(str_reply) + *str_reply = g_strdup("parameters are not valid"); + return -1; + } + if(!addr_str) { + if(str_reply) + *str_reply = g_strdup("not found -addr parameter"); + return -1; + } + else + digit_from_string(addr_str, node_info.hdr.address.raw, sizeof(node_info.hdr.address.raw)); + if(!shard_str) { + if(str_reply) + *str_reply = g_strdup("not found -shard parameter"); + return -1; + } + else + digit_from_string(shard_str, node_info.hdr.shard_id.raw, sizeof(node_info.hdr.shard_id.raw)); //DAP_CHAIN_SHARD_ID_SIZE); + if(!ipv4_str && !ipv6_str) { + if(str_reply) + *str_reply = g_strdup("not found -ipv4 or -ipv6 parameter"); + return -1; + } + else { + if(ipv4_str) + inet_pton(AF_INET, ipv4_str, &(node_info.hdr.ext_addr_v4)); + if(ipv6_str) + inet_pton(AF_INET6, ipv6_str, &(node_info.hdr.ext_addr_v6)); + } + if(alias_str) { + if(addr_str) { + // add alias + if(!add_alias(alias_str, &node_info.hdr.address)) + log_it(L_WARNING, "can't save alias %s", alias_str); + } + else { + if(str_reply) + *str_reply = g_strdup("alias can't be mapped because -addr is not found"); + return -1; + } + } + + // write to base + char *a_key = dap_chain_global_db_hash((const uint8_t*) &(node_info.hdr.address), + sizeof(dap_chain_node_addr_t)); + char *a_value = dap_chain_node_serialize(&node_info, NULL); + bool res = dap_chain_global_db_gr_set(a_key, a_value, GROUP_NODE); + if(res) { + if(str_reply) + *str_reply = g_strdup_printf("node is added"); + } + else if(str_reply) { + *str_reply = g_strdup_printf("node is not added"); + } + DAP_DELETE(a_value); + if(res) + return 0; + else + return -1; + break; + + case CMD_DEL: + break; + default: + if(str_reply) + *str_reply = g_strdup_printf("command %s not recognized", argv[1]); + return -1; } +// dap_chain_node_addr_t *addr = dap_chain_node_gen_addr(&node_info.hdr.shard_id); +// if(!dap_chain_node_check_addr(&node_info.hdr.address, &node_info.hdr.shard_id)) { +// if(str_reply) +// *str_reply = g_strdup("shard does not match addr"); +// return -1; +// } - //inet_ntop(AF_INET, &(dap_addr.uint64), str, INET_ADDRSTRLEN); - //uint64 +//inet_ntop(AF_INET, &(dap_addr.uint64), str, INET_ADDRSTRLEN); +//uint64 uint64_t timestamp = time(NULL); - char *a_key = dap_chain_global_db_hash((const uint8_t*)&(node_info.hdr.address), sizeof(dap_chain_node_addr_t)); - char *a_value = dap_chain_global_db_node_serialize(&node_info, NULL); - bool res = dap_chain_global_db_set(a_key, a_value); - if(res) { - if(str_reply) - *str_reply = g_strdup_printf("node is %s", (cmd_num == 1) ? "added" : "deleted"); - return 0; - } - else if(str_reply) { - *str_reply = g_strdup_printf("node is not %s", (cmd_num == 1) ? "added" : "deleted"); - } - DAP_DELETE(a_value); return -1; }