Skip to content
Snippets Groups Projects
dap_chain_node_cli_cmd.c 94.3 KiB
Newer Older
dmitriy.gerasimov's avatar
dmitriy.gerasimov committed
 * Dmitriy A. Gearasimov <gerasimov.dmitriy@demlabs.net>
 * Alexander Lysikov <alexander.lysikov@demlabs.net>
 * DeM Labs Inc.   https://demlabs.net
dmitriy.gerasimov's avatar
dmitriy.gerasimov committed
 * Kelvin Project https://github.com/kelvinblockchain
 * Copyright  (c) 2019
dmitriy.gerasimov's avatar
dmitriy.gerasimov committed
 * All rights reserved.

 This file is part of DAP (Deus Applications Prototypes) the open source project

Aleksandr Lysikov's avatar
Aleksandr Lysikov committed
 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.

 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/>.
 */
ANTA's avatar
ANTA committed
#include <stdlib.h>
#include <stdio.h>
ANTA's avatar
ANTA committed
#include <time.h>
#include <stdlib.h>
ANTA's avatar
ANTA committed
#include <stddef.h>
#include <stdint.h>
#include <string.h>
#include <stdbool.h>
#include <errno.h>
#include <assert.h>
#include <ctype.h>
#include <dirent.h>
ANTA's avatar
ANTA committed
#ifdef WIN32
#undef _WIN32_WINNT
#define _WIN32_WINNT 0x0600
#include <winsock2.h>
#include <windows.h>
#include <mswsock.h>
#include <ws2tcpip.h>
#include <io.h>
#include <wepoll.h>
#include <pthread.h>
#else
#include <sys/types.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#endif

#include "iputils/iputils.h"

#include "uthash.h"
#include "utlist.h"

#include "dap_string.h"
#include "dap_hash.h"
#include "dap_chain_common.h"
#include "dap_strfuncs.h"
#include "dap_list.h"
#include "dap_string.h"
#include "dap_chain_cert.h"
#include "dap_chain_wallet.h"
#include "dap_chain_node.h"
#include "dap_chain_global_db.h"
Dmitriy A. Gerasimov's avatar
Dmitriy A. Gerasimov committed
#include "dap_chain_node_client.h"
#include "dap_chain_node_remote.h"
#include "dap_chain_node_cli_cmd.h"
#include "dap_chain_net_srv.h"
#include "dap_chain_datum.h"
#include "dap_chain_datum_tx_items.h"
#include "dap_chain_ledger.h"
#include "dap_chain_mempool.h"
#include "dap_chain_global_db.h"
#include "dap_chain_global_db_remote.h"
#include "dap_stream_ch_chain_net.h"
#include "dap_stream_ch_chain.h"
#include "dap_stream_ch_chain_pkt.h"
#include "dap_stream_ch_chain_net_pkt.h"
#define LOG_TAG "chain_node_cli_cmd"
/**
 * Find in base addr by alias
 *
 * return addr, NULL if not found
 */
dap_chain_node_addr_t* dap_chain_node_addr_get_by_alias( dap_chain_net_t * a_net, const char *a_alias)
    dap_chain_node_addr_t *l_addr = NULL;
    if(!a_alias)
        return NULL;
    const char *a_key = a_alias;
    size_t l_addr_size = 0;
    l_addr = (dap_chain_node_addr_t*) (void*) dap_chain_global_db_gr_get(a_key, &l_addr_size, a_net->pub.gdb_nodes_aliases);
    if(l_addr_size != sizeof(dap_chain_node_addr_t)) {
//        l_addr = DAP_NEW_Z(dap_chain_node_addr_t);
//        if(hex2bin((char*) l_addr, (const unsigned char *) addr_str, sizeof(dap_chain_node_addr_t) * 2) == -1) {
        DAP_DELETE(l_addr);
//            l_addr = NULL;
//        }
//    DAP_DELETE(addr_str);
    return l_addr;
/**
 * Find in base alias by addr
 *
 * return list of addr, NULL if not found
static dap_list_t* get_aliases_by_name(dap_chain_net_t * l_net, dap_chain_node_addr_t *a_addr)
        return NULL;
    dap_list_t *list_aliases = NULL;
    size_t data_size = 0;
    // read all aliases
    dap_global_db_obj_t *objs = dap_chain_global_db_gr_load(l_net->pub.gdb_nodes_aliases, &data_size);
    if(!objs || !data_size)
        return NULL;
    for(size_t i = 0; i < data_size; i++) {
        //dap_chain_node_addr_t addr_i;
        dap_global_db_obj_t *obj = objs + i;
        if(!obj)
            break;
        dap_chain_node_addr_t *l_addr = (dap_chain_node_addr_t*) (void*) obj->value;
        if(l_addr && obj->value_len == sizeof(dap_chain_node_addr_t) && a_addr->uint64 == l_addr->uint64) {
            list_aliases = dap_list_prepend(list_aliases, strdup(obj->key));
    }
    dap_chain_global_db_objs_delete(objs, data_size);
    return list_aliases;
static dap_chain_node_addr_t* node_info_get_addr(dap_chain_net_t * a_net, dap_chain_node_info_t *a_node_info,
        dap_chain_node_addr_t *a_addr, const char *a_alias_str)
    dap_chain_node_addr_t *l_address = NULL;
    if(a_alias_str && !a_addr->uint64) {
        l_address = dap_chain_node_addr_get_by_alias(a_net, a_alias_str);
    if(a_addr->uint64) {
        l_address = DAP_NEW(dap_chain_node_addr_t);
        l_address->uint64 = a_addr->uint64;
/**
 * Read node from base
 */
static dap_chain_node_info_t* node_info_read_and_reply(dap_chain_net_t * a_net, dap_chain_node_addr_t *a_address, char **a_str_reply)
    char *l_key = dap_chain_node_addr_to_hash_str(a_address);
        dap_chain_node_cli_set_reply_text(a_str_reply, "can't calculate hash of addr");
        return NULL;
    }
    size_t node_info_size = 0;
    dap_chain_node_info_t *node_info;
    // read node
    node_info = (dap_chain_node_info_t *) dap_chain_global_db_gr_get(l_key, &node_info_size, a_net->pub.gdb_nodes);
        dap_chain_node_cli_set_reply_text(a_str_reply, "node not found in base");
        return NULL;
    }
    size_t node_info_size_must_be = dap_chain_node_info_get_size(node_info);
    if(node_info_size_must_be != node_info_size) {
        dap_chain_node_cli_set_reply_text(a_str_reply, "node has bad size in base=%u (must be %u)", node_info_size,
Aleksandr Lysikov's avatar
Aleksandr Lysikov committed
                node_info_size_must_be);
        DAP_DELETE(node_info);
        DAP_DELETE(l_key);
        return NULL;

//    dap_chain_node_info_t *node_info = dap_chain_node_info_deserialize(str, (str) ? strlen(str) : 0);
//    if(!node_info) {
//        set_reply_text(str_reply, "node has invalid format in base");
//    }
//    DAP_DELETE(str);
    DAP_DELETE(l_key);
    return node_info;
}

/**
static bool node_info_save_and_reply(dap_chain_net_t * a_net, dap_chain_node_info_t *node_info, char **str_reply)
{
    if(!node_info || !node_info->hdr.address.uint64) {
dmitriy.gerasimov's avatar
dmitriy.gerasimov committed
        dap_chain_node_cli_set_reply_text(str_reply, "node addr not found");
        return false;
    }
    char *a_key = dap_chain_node_addr_to_hash_str(&node_info->hdr.address);
dmitriy.gerasimov's avatar
dmitriy.gerasimov committed
        dap_chain_node_cli_set_reply_text(str_reply, "can't calculate hash for addr");
        return NULL;
    }
    //char *a_value = dap_chain_node_info_serialize(node_info, NULL);
    size_t node_info_size = dap_chain_node_info_get_size(node_info);
    bool res = dap_chain_global_db_gr_set(a_key, (const uint8_t *) node_info, node_info_size,a_net->pub.gdb_nodes);
    DAP_DELETE(a_key);
    //DAP_DELETE(a_value);
    return res;
}
/**
 * Handler of command 'global_db node add'
 *
 * str_reply[out] for reply
 * return 0 Ok, -1 error
 */
static int node_info_add_with_reply(dap_chain_net_t * a_net, dap_chain_node_info_t *a_node_info, const char *a_alias_str,
        const char *a_cell_str, const char *a_ipv4_str, const char *a_ipv6_str, char **a_str_reply)
    if(!a_node_info->hdr.address.uint64) {
        dap_chain_node_cli_set_reply_text(a_str_reply, "not found -addr parameter");
        return -1;
    }
    if(!a_cell_str) {
        dap_chain_node_cli_set_reply_text(a_str_reply, "not found -cell parameter");
        return -1;
    }
    if(a_ipv4_str)
        inet_pton(AF_INET, a_ipv4_str, &(a_node_info->hdr.ext_addr_v4));
    if(a_ipv6_str)
        inet_pton(AF_INET6, a_ipv6_str, &(a_node_info->hdr.ext_addr_v6));
    // check match addr to cell or no
    /*dap_chain_node_addr_t *addr = dap_chain_node_gen_addr(&node_info->hdr.cell_id);
     if(!dap_chain_node_check_addr(&node_info->hdr.address, &node_info->hdr.cell_id)) {
     set_reply_text(str_reply, "cell does not match addr");
     return -1;
     }*/
        // add alias
        if(!dap_chain_node_alias_register( a_net, a_alias_str, &a_node_info->hdr.address)) {
            log_it(L_WARNING, "can't save alias %s", a_alias_str);
            dap_chain_node_cli_set_reply_text(a_str_reply, "alias '%s' can't be mapped to addr=0x%lld",
                    a_alias_str, a_node_info->hdr.address.uint64);

    // write to base
    bool res = node_info_save_and_reply(a_net,a_node_info, a_str_reply);
        dap_chain_node_cli_set_reply_text(a_str_reply, "node added");
        return -1;
    if(res)
        return 0;
    return -1;
}

/**
 * Handler of command 'global_db node add'
 *
 * str_reply[out] for reply
 * return 0 Ok, -1 error
 */
static int node_info_del_with_reply(dap_chain_net_t * a_net, dap_chain_node_info_t *a_node_info, const char *alias_str, char **str_reply)
    if(!a_node_info->hdr.address.uint64 && !alias_str) {
dmitriy.gerasimov's avatar
dmitriy.gerasimov committed
        dap_chain_node_cli_set_reply_text(str_reply, "addr not found");
    // check, current node have this addr or no
    uint64_t l_cur_addr = dap_db_get_cur_node_addr();
    if(l_cur_addr && l_cur_addr == a_node_info->hdr.address.uint64) {
dmitriy.gerasimov's avatar
dmitriy.gerasimov committed
        dap_chain_node_cli_set_reply_text(str_reply, "current node cannot be deleted");
    // find addr by alias or addr_str
    dap_chain_node_addr_t *address = node_info_get_addr(a_net, a_node_info, &a_node_info->hdr.address, alias_str);
    if(!address) {
dmitriy.gerasimov's avatar
dmitriy.gerasimov committed
        dap_chain_node_cli_set_reply_text(str_reply, "alias not found");
    char *a_key = dap_chain_node_addr_to_hash_str(address);
    if(a_key)
    {
        // delete node
        bool res = dap_chain_global_db_gr_del(a_key, a_net->pub.gdb_nodes);
        if(res) {
            // delete all aliases for node address
            {
                dap_list_t *list_aliases = get_aliases_by_name(a_net, address);
                dap_list_t *list = list_aliases;
                while(list)
                {
                    const char *alias = (const char *) list->data;
                    dap_chain_node_alias_delete(a_net, alias);
                    list = dap_list_next(list);
                dap_list_free_full(list_aliases, (dap_callback_destroyed_t) free);
            // set text response
dmitriy.gerasimov's avatar
dmitriy.gerasimov committed
            dap_chain_node_cli_set_reply_text(str_reply, "node deleted");
dmitriy.gerasimov's avatar
dmitriy.gerasimov committed
            dap_chain_node_cli_set_reply_text(str_reply, "node not deleted");
        DAP_DELETE(a_key);
        DAP_DELETE(address);
        if(res)
            return 0;
dmitriy.gerasimov's avatar
dmitriy.gerasimov committed
    dap_chain_node_cli_set_reply_text(str_reply, "addr to delete can't be defined");
    DAP_DELETE(address);
    return -1;
}

/**
 * Handler of command 'global_db node link'
 *
 * cmd 'add' or 'del'
 * str_reply[out] for reply
 * return 0 Ok, -1 error
 */
static int link_add_or_del_with_reply(dap_chain_net_t * a_net, dap_chain_node_info_t *a_node_info, const char *cmd, const char *a_alias_str,
        dap_chain_node_addr_t *link, char **a_str_reply)
    if(!a_node_info->hdr.address.uint64 && !a_alias_str) {
        dap_chain_node_cli_set_reply_text(a_str_reply, "addr not found");
        return -1;
    }
    if(!link->uint64) {
        dap_chain_node_cli_set_reply_text(a_str_reply, "link not found");
        return -1;
    }
    // TODO check the presence of link in the node base
    if(0) {
        dap_chain_node_cli_set_reply_text(a_str_reply, "node 0x%016llx not found in base", link->uint64);

    // find addr by alias or addr_str
    dap_chain_node_addr_t *l_address = node_info_get_addr(a_net, a_node_info, &a_node_info->hdr.address, a_alias_str);
    if(!l_address) {
        dap_chain_node_cli_set_reply_text(a_str_reply, "alias not found");
    dap_chain_node_info_t * l_node_info_read = node_info_read_and_reply(a_net, l_address, a_str_reply);
    size_t l_node_info_read_size = dap_chain_node_info_get_size(l_node_info_read);
    if(!l_node_info_read)
        return -1;

    int cmd_int = 0;
    if(!strcmp(cmd, "add"))
        cmd_int = 1;
    else if(!strcmp(cmd, "del"))
        cmd_int = 2;

    // find link in node_info_read
    int index_link = -1;
    for(size_t i = 0; i < l_node_info_read->hdr.links_number; i++) {
        if(l_node_info_read->links[i].uint64 == link->uint64) {
            // link already present
            index_link = (int) i;
    bool res_successful = false; // is successful whether add/del
    // add link
    if(cmd_int == 1) {
        if(index_link == -1) {
            l_node_info_read = DAP_REALLOC(l_node_info_read, l_node_info_read_size += sizeof(*link));
            memcpy(&(l_node_info_read->links[l_node_info_read->hdr.links_number]), link, sizeof(dap_chain_node_addr_t));
            l_node_info_read->hdr.links_number++;
            res_successful = true;
        }
    }
    // delete link
    else if(cmd_int == 2) {
        // move link list to one item prev
        if(index_link >= 0) {
            for(unsigned int j = (unsigned int) index_link; j < (l_node_info_read->hdr.links_number - 1); j++) {
                memcpy(&(l_node_info_read->links[j]), &(l_node_info_read->links[j + 1]), sizeof(dap_chain_node_addr_t));
            l_node_info_read->hdr.links_number--;
            res_successful = true;
            l_node_info_read = DAP_REALLOC(l_node_info_read, l_node_info_read_size -= sizeof(*link));
        }
    }
    // save edited node_info
    if(res_successful) {
        bool res = node_info_save_and_reply(a_net, l_node_info_read, a_str_reply);
        if(res) {
            res_successful = true;
            if(cmd_int == 1)
                dap_chain_node_cli_set_reply_text(a_str_reply, "link added");
            if(cmd_int == 2)
                dap_chain_node_cli_set_reply_text(a_str_reply, "link deleted");
        else {
            res_successful = false;
        }
    else {
        if(cmd_int == 1) {
            if(index_link >= 0)
                dap_chain_node_cli_set_reply_text(a_str_reply, "link not added because it is already present");
                dap_chain_node_cli_set_reply_text(a_str_reply, "link not added");
        }
        if(cmd_int == 2) {
            if(index_link == -1)
                dap_chain_node_cli_set_reply_text(a_str_reply, "link not deleted because not found");
                dap_chain_node_cli_set_reply_text(a_str_reply, "link not deleted");
    DAP_DELETE(l_address);
    DAP_DELETE(l_node_info_read);
    if(res_successful)
        return 0;
    return -1;
}

/**
 * Handler of command 'global_db node dump'
 *
 * str_reply[out] for reply
 * return 0 Ok, -1 error
 */
static int node_info_dump_with_reply(dap_chain_net_t * a_net, dap_chain_node_addr_t * a_addr, bool a_is_full, const char *a_alias, char **a_str_reply)
    dap_string_t *l_string_reply = dap_string_new("Node dump:");
    if((a_addr && a_addr->uint64) || a_alias) {
        dap_chain_node_addr_t *l_addr;
        if(a_addr && a_addr->uint64) {
            l_addr = DAP_NEW(dap_chain_node_addr_t);
            l_addr->uint64 = a_addr->uint64;
        } else if(a_alias) {
            l_addr = dap_chain_node_alias_find(a_net, a_alias);
        if(!l_addr) {
            dap_chain_node_cli_set_reply_text(a_str_reply, "addr not found");
            dap_string_free(l_string_reply, true);
            return -1;
        }
        // read node
        dap_chain_node_info_t *node_info_read = node_info_read_and_reply(a_net, l_addr, a_str_reply);

        // get aliases in form of string
        dap_string_t *aliases_string = dap_string_new(NULL);
        dap_list_t *list_aliases = get_aliases_by_name(a_net, l_addr);
        if(list_aliases)
        {
            dap_list_t *list = list_aliases;
            while(list)
            {
                const char *alias = (const char *) list->data;
                dap_string_append_printf(aliases_string, "\nalias %s", alias);
                list = dap_list_next(list);
            }
            dap_list_free_full(list_aliases, (dap_callback_destroyed_t) free);
        }
        else
            dap_string_append(aliases_string, "\nno aliases");

        const int hostlen = 128;
        char *host4 = (char*) alloca(hostlen);
        char *host6 = (char*) alloca(hostlen);
        struct sockaddr_in sa4 = { .sin_family = AF_INET, .sin_addr = node_info_read->hdr.ext_addr_v4 };
        const char* str_ip4 = inet_ntop(AF_INET, &(((struct sockaddr_in *) &sa4)->sin_addr), host4, hostlen);

        struct sockaddr_in6 sa6 = { .sin6_family = AF_INET6, .sin6_addr = node_info_read->hdr.ext_addr_v6 };
        const char* str_ip6 = inet_ntop(AF_INET6, &(((struct sockaddr_in6 *) &sa6)->sin6_addr), host6, hostlen);

        // get links in form of string
        dap_string_t *links_string = dap_string_new(NULL);
        for(unsigned int i = 0; i < node_info_read->hdr.links_number; i++) {
            dap_chain_node_addr_t link_addr = node_info_read->links[i];
            dap_string_append_printf(links_string, "\nlink%02d address : " NODE_ADDR_FP_STR, i,
                    NODE_ADDR_FP_ARGS_S(link_addr));

        dap_string_append_printf(l_string_reply, "\n");
        // set short reply with node param
        if(!a_is_full)
            dap_string_append_printf(l_string_reply,
                    "node address "NODE_ADDR_FP_STR"\tcell 0x%016llx\tipv4 %s\tnumber of links %u",
                    NODE_ADDR_FP_ARGS_S(node_info_read->hdr.address),
                    node_info_read->hdr.cell_id.uint64, str_ip4,
                    node_info_read->hdr.links_number);
        else
            // set full reply with node param
            dap_string_append_printf(l_string_reply,
                    "node address " NODE_ADDR_FP_STR "\ncell 0x%016llx%s\nipv4 %s\nipv6 %s\nlinks %u%s",
                    NODE_ADDR_FP_ARGS_S(node_info_read->hdr.address),
                    node_info_read->hdr.cell_id.uint64,
                    str_ip4, str_ip6, aliases_string->str,
                    node_info_read->hdr.links_number, links_string->str);
        dap_string_free(aliases_string, true);
        dap_string_free(links_string, true);

        DAP_DELETE(l_addr);
        DAP_DELETE(node_info_read);


        dap_global_db_obj_t *l_objs = NULL;
        size_t l_nodes_count = 0;
        dap_chain_node_info_t *l_node_info;
        dap_string_append(l_string_reply, "\n");
        l_objs = dap_chain_global_db_gr_load( a_net->pub.gdb_nodes, &l_nodes_count);

        if(!l_nodes_count || !l_objs) {
            dap_string_append_printf(l_string_reply, "No records\n");
            dap_string_free(l_string_reply, true);
            l_ret = -1;
        }else {
            dap_string_append_printf(l_string_reply,"Got %u records:\n",l_nodes_count);
            for(size_t i = 0; i < l_nodes_count; i++) {
                dap_chain_node_info_t *node_info =  (dap_chain_node_info_t *) l_objs[i].value;
                // find addr by alias or addr_str
                dap_chain_node_addr_t *address = node_info_get_addr(a_net, node_info, &node_info->hdr.address, a_alias);
                if(!address) {
                    dap_chain_node_cli_set_reply_text(a_str_reply, "alias not found");
                    break;
                }
                // read node
                dap_chain_node_info_t *node_info_read = node_info_read_and_reply( a_net, address, a_str_reply);
                if(!node_info_read) {
                    DAP_DELETE(address);
                    break;
                }
                const int hostlen = 128;
                char *host4 = (char*) alloca(hostlen);
                char *host6 = (char*) alloca(hostlen);
                struct sockaddr_in sa4 = { .sin_family = AF_INET, .sin_addr = node_info_read->hdr.ext_addr_v4 };
                const char* str_ip4 = inet_ntop(AF_INET, &(((struct sockaddr_in *) &sa4)->sin_addr), host4, hostlen);
                struct sockaddr_in6 sa6 = { .sin6_family = AF_INET6, .sin6_addr = node_info_read->hdr.ext_addr_v6 };
                const char* str_ip6 = inet_ntop(AF_INET6, &(((struct sockaddr_in6 *) &sa6)->sin6_addr), host6, hostlen);
                // get aliases in form of string
                dap_string_t *aliases_string = dap_string_new(NULL);
                dap_list_t *list_aliases = get_aliases_by_name(a_net,address);
                if(list_aliases)
                {
                    dap_list_t *list = list_aliases;
                    while(list)
                    {
                        const char *alias = (const char *) list->data;
                        dap_string_append_printf(aliases_string, "\nalias %s", alias);
                        list = dap_list_next(list);
                    }
                    dap_list_free_full(list_aliases, (dap_callback_destroyed_t) free);
                }
                else
                    dap_string_append(aliases_string, "\nno aliases");

                // get links in form of string
                dap_string_t *links_string = dap_string_new(NULL);
                for(unsigned int i = 0; i < node_info_read->hdr.links_number; i++) {
                    dap_chain_node_addr_t link_addr = node_info_read->links[i];
                    dap_string_append_printf(links_string, "\nlink%02d address : " NODE_ADDR_FP_STR, i,
                                             NODE_ADDR_FP_ARGS_S(link_addr) );
                if(i)
                    dap_string_append_printf(l_string_reply, "\n");
                // set short reply with node param
                if(!a_is_full)
                    dap_string_append_printf(l_string_reply,
                            "node address "NODE_ADDR_FP_STR"\tcell 0x%016llx\tipv4 %s\tnumber of links %u",
                            NODE_ADDR_FP_ARGS_S(node_info_read->hdr.address),
                            node_info_read->hdr.cell_id.uint64, str_ip4,
                            node_info_read->hdr.links_number);
                else
                    // set full reply with node param
                    dap_string_append_printf(l_string_reply,
                            "node address " NODE_ADDR_FP_STR "\ncell 0x%016llx%s\nipv4 %s\nipv6 %s\nlinks %u%s",
                            NODE_ADDR_FP_ARGS_S(node_info_read->hdr.address),
                            node_info_read->hdr.cell_id.uint64,
                            str_ip4, str_ip6, aliases_string->str,
                            node_info_read->hdr.links_number, links_string->str);
                dap_string_free(aliases_string, true);
                dap_string_free(links_string, true);

                DAP_DELETE(address);
                DAP_DELETE(node_info_read);
            }
    dap_chain_node_cli_set_reply_text(a_str_reply, l_string_reply->str);
    dap_string_free(l_string_reply, true);
/**
 * global_db command
 *
 * return 0 OK, -1 Err
 */
dmitriy.gerasimov's avatar
dmitriy.gerasimov committed
int com_global_db(int a_argc, char ** a_argv, char **a_str_reply)
    enum {
        CMD_NONE, CMD_ADD, CMD_DEL, CMD_LINK    };
    //printf("com_global_db\n");
    int arg_index = 1;
    // find 'node' as first parameter only
    arg_index = dap_chain_node_cli_find_option_val(a_argv, arg_index, min(a_argc, arg_index + 1), "node", NULL);
    if(!arg_index || a_argc < 3) {
        dap_chain_node_cli_set_reply_text(a_str_reply, "parameters are not valid");
    dap_chain_net_t * l_net = NULL;

    if(dap_chain_node_cli_cmd_values_parse_net_chain(&arg_index, a_argc, a_argv, a_str_reply, NULL, &l_net) < 0)
        return -11;

    int arg_index_n = ++arg_index;
    // find command (add, delete, etc) as second parameter only
    int cmd_num = CMD_NONE;
    if((arg_index_n = dap_chain_node_cli_find_option_val(a_argv, arg_index, min(a_argc, arg_index + 1), "add", NULL))
Aleksandr Lysikov's avatar
Aleksandr Lysikov committed
            != 0) {
        cmd_num = CMD_ADD;
    else if((arg_index_n = dap_chain_node_cli_find_option_val(a_argv, arg_index, min(a_argc, arg_index + 1), "del",
    NULL))
Aleksandr Lysikov's avatar
Aleksandr Lysikov committed
            != 0) {
        cmd_num = CMD_DEL;
    else if((arg_index_n = dap_chain_node_cli_find_option_val(a_argv, arg_index, min(a_argc, arg_index + 1), "link",
    NULL))
Aleksandr Lysikov's avatar
Aleksandr Lysikov committed
            != 0) {
        cmd_num = CMD_LINK;
    }
    if(cmd_num == CMD_NONE) {
        dap_chain_node_cli_set_reply_text(a_str_reply, "command %s not recognized", a_argv[1]);
    //arg_index = arg_index_n; // no need, they are already equal must be
    assert(arg_index == arg_index_n);
    arg_index++;
    const char *l_addr_str = NULL, *alias_str = NULL, *l_cell_str = NULL, *l_link_str = NULL;
    const char *a_ipv4_str = NULL, *a_ipv6_str = NULL;
    // find addr, alias
    dap_chain_node_cli_find_option_val(a_argv, arg_index, a_argc, "-addr", &l_addr_str);
    dap_chain_node_cli_find_option_val(a_argv, arg_index, a_argc, "-alias", &alias_str);
    dap_chain_node_cli_find_option_val(a_argv, arg_index, a_argc, "-cell", &l_cell_str);
    dap_chain_node_cli_find_option_val(a_argv, arg_index, a_argc, "-ipv4", &a_ipv4_str);
    dap_chain_node_cli_find_option_val(a_argv, arg_index, a_argc, "-ipv6", &a_ipv6_str);
    dap_chain_node_cli_find_option_val(a_argv, arg_index, a_argc, "-link", &l_link_str);
    // struct to write to the global db
    dap_chain_node_addr_t l_link = { 0 };
    dap_chain_node_info_t *l_node_info;
    size_t l_node_info_size = sizeof(l_node_info->hdr) + sizeof(l_link);
    l_node_info = DAP_NEW_Z_SIZE(dap_chain_node_info_t, l_node_info_size);

    if(l_addr_str) {
        dap_digit_from_string(l_addr_str, l_node_info->hdr.address.raw, sizeof(l_node_info->hdr.address.raw));
    if(l_cell_str) {
        dap_digit_from_string(l_cell_str, l_node_info->hdr.cell_id.raw, sizeof(l_node_info->hdr.cell_id.raw)); //DAP_CHAIN_CELL_ID_SIZE);
    if(l_link_str) {
        dap_digit_from_string(l_link_str, l_link.raw, sizeof(l_link.raw));
    switch (cmd_num)
    {
    // add new node to global_db
    case CMD_ADD:
        if(!arg_index || a_argc < 8) {
            dap_chain_node_cli_set_reply_text(a_str_reply, "invalid parameters");
            return -1;
        }
        // handler of command 'global_db node add'
        return node_info_add_with_reply(l_net,l_node_info, alias_str, l_cell_str, a_ipv4_str, a_ipv6_str, a_str_reply);
dmitriy.gerasimov's avatar
dmitriy.gerasimov committed
        //break;

    case CMD_DEL:
        // handler of command 'global_db node del'
        return node_info_del_with_reply(l_net,l_node_info, alias_str, a_str_reply);
    case CMD_LINK:
        if(dap_chain_node_cli_find_option_val(a_argv, arg_index, min(a_argc, arg_index + 1), "add", NULL))
            // handler of command 'global_db node link add -addr <node address> -link <node address>'
            return link_add_or_del_with_reply(l_net, l_node_info, "add", alias_str, &l_link, a_str_reply);
        else if(dap_chain_node_cli_find_option_val(a_argv, arg_index, min(a_argc, arg_index + 1), "del", NULL))
            // handler of command 'global_db node link del -addr <node address> -link <node address>'
            return link_add_or_del_with_reply(l_net, l_node_info, "del", alias_str, &l_link, a_str_reply);
            dap_chain_node_cli_set_reply_text(a_str_reply, "command not recognize, supported format:\n"
                    "global_db node link <add|del] [-addr <node address>  | -alias <node alias>] -link <node address>");
            DAP_DELETE(l_node_info);
    default:
        dap_chain_node_cli_set_reply_text(a_str_reply, "command %s not recognized", a_argv[1]);
        return -1;
dmitriy.gerasimov's avatar
dmitriy.gerasimov committed
int com_node(int a_argc, char ** a_argv, char **a_str_reply)
    enum {
        CMD_NONE, CMD_ALIAS, CMD_HANDSHAKE, CMD_CONNECT , CMD_DUMP
    };
    int arg_index = 1;
    int cmd_num = CMD_NONE;
    const char *cmd_str = NULL;
// find  add parameter ('alias' or 'handshake')
    if(dap_chain_node_cli_find_option_val(a_argv, arg_index, min(a_argc, arg_index + 1), "handshake", NULL)) {
        cmd_num = CMD_HANDSHAKE;
    }
    else if(dap_chain_node_cli_find_option_val(a_argv, arg_index, min(a_argc, arg_index + 1), "connect", NULL)) {
        cmd_num = CMD_CONNECT;
    }
    else if(dap_chain_node_cli_find_option_val(a_argv, arg_index, min(a_argc, arg_index + 1), "alias", NULL)) {
        cmd_num = CMD_ALIAS;
    }
    else if(dap_chain_node_cli_find_option_val(a_argv, arg_index, min(a_argc, arg_index + 1), "dump", NULL)) {
        cmd_num = CMD_DUMP;
    }
    arg_index++;
    if(cmd_num == CMD_NONE) {
        dap_chain_node_cli_set_reply_text(a_str_reply, "command %s not recognized", a_argv[1]);
        return -1;
    }
    dap_chain_node_addr_t l_node_addr={0};
    const char *l_addr_str = NULL, *alias_str = NULL;
    // find addr, alias
    dap_chain_node_cli_find_option_val(a_argv, arg_index, a_argc, "-addr", &l_addr_str);
    dap_chain_node_cli_find_option_val(a_argv, arg_index, a_argc, "-alias", &alias_str);
    dap_chain_node_cli_find_option_val(a_argv, arg_index, a_argc, "-net", &l_net_str);
    bool l_is_full = dap_chain_node_cli_find_option_val(a_argv, arg_index, a_argc, "-full", NULL);
    if (l_addr_str)
        if ( dap_chain_node_addr_from_str(&l_node_addr,l_addr_str) != 0 )
            dap_digit_from_string(l_addr_str, l_node_addr.raw, sizeof(l_node_addr.raw));
    if(l_net_str == NULL) {
        dap_chain_node_cli_set_reply_text(a_str_reply, "No -net <net name> option in command %s", a_argv[1]);
        return -11;
    }

    dap_chain_net_t * l_net = dap_chain_net_by_name(l_net_str);
    if(l_net == NULL) {
        dap_chain_node_cli_set_reply_text(a_str_reply, "%s: Can't find such network %s", a_argv[1], l_net_str);

    switch (cmd_num)
    case CMD_DUMP:{
        // handler of command 'global_db node dump'

        return node_info_dump_with_reply(l_net, &l_node_addr , l_is_full, alias_str, a_str_reply);
    // add alias
    case CMD_ALIAS:
        if(alias_str) {
                // add alias
                if(!dap_chain_node_alias_register(l_net, alias_str, &l_node_addr))
                    log_it(L_WARNING, "can't save alias %s", alias_str);
                else {
                    dap_chain_node_cli_set_reply_text(a_str_reply, "alias mapped successfully");
                dap_chain_node_cli_set_reply_text(a_str_reply, "alias can't be mapped because -addr is not found");
                return -1;
            }
            dap_chain_node_cli_set_reply_text(a_str_reply, "alias can't be mapped because -alias is not found");
            return -1;
        }
        break;
        // make connect
    case CMD_CONNECT: {
        // get address from alias if addr not defined
        if(alias_str && !l_node_addr.uint64) {
            dap_chain_node_addr_t *address_tmp = dap_chain_node_addr_get_by_alias(l_net, alias_str);
            if(address_tmp) {
                memcpy(&l_node_addr, address_tmp, sizeof(*address_tmp));
                DAP_DELETE(address_tmp);
                dap_chain_node_cli_set_reply_text(a_str_reply, "no address found by alias");
        if(!l_node_addr.uint64) {
            dap_chain_node_cli_set_reply_text(a_str_reply, "addr not found");
            return -1;
        }
        dap_chain_node_info_t *l_remote_node_info = node_info_read_and_reply(l_net, &l_node_addr, a_str_reply);
        if(!l_remote_node_info) {
            return -1;
        }
        // start connect
        dap_chain_node_client_t *l_node_client = dap_chain_node_client_connect(l_remote_node_info);
        if(!l_node_client) {
            dap_chain_node_cli_set_reply_text(a_str_reply, "can't connect");
            DAP_DELETE(l_remote_node_info);
            return -1;
        }
        // wait connected
        int timeout_ms = 5000; //5 sec = 5000 ms
        int res = dap_chain_node_client_wait(l_node_client, NODE_CLIENT_STATE_CONNECTED, timeout_ms);
        if(res ) {
            dap_chain_node_cli_set_reply_text(a_str_reply, "no response from node: code %d",res);
            // clean client struct
            dap_chain_node_client_close(l_node_client);
            DAP_DELETE(l_remote_node_info);
            return -1;
        }
        log_it(L_NOTICE, "Stream connection established, now lets sync all");
        dap_stream_ch_chain_sync_request_t l_sync_request = { { 0 } };
        dap_stream_ch_t * l_ch_chain = dap_client_get_stream_ch(l_node_client->client, dap_stream_ch_chain_get_id());
        // fill begin id
        l_sync_request.id_start = (uint64_t) dap_db_log_get_last_id_remote(
                l_remote_node_info->hdr.address.uint64);
        // fill end id = 0 - no time limit
        //l_sync_request.ts_end = 0;
Aleksandr Lysikov's avatar
Aleksandr Lysikov committed
        // fill current node address
        l_sync_request.node_addr.uint64 =
                dap_chain_net_get_cur_addr(l_net) ? dap_chain_net_get_cur_addr(l_net)->uint64 :
                                                    dap_db_get_cur_node_addr();
        dap_chain_id_t l_chain_id_null = { { 0 } };
        dap_chain_cell_id_t l_chain_cell_id_null = { { 0 } };
        l_chain_id_null.uint64 = l_net->pub.id.uint64;
        l_chain_cell_id_null.uint64 = dap_chain_net_get_cur_cell(l_net) ? dap_chain_net_get_cur_cell(l_net)->uint64 : 0;

        log_it(L_INFO, "Requested GLOBAL_DB syncronizatoin, %llu:%llu period", l_sync_request.id_start,
                l_sync_request.id_end);
        // copy l_sync_request to current
        //dap_stream_ch_chain_t * l_s_ch_chain = DAP_STREAM_CH_CHAIN(l_ch_chain);
        //l_s_ch_chain->request_net_id.uint64 = l_net->pub.id.uint64;
        //l_s_ch_chain->request_cell_id.uint64 = l_chain_cell_id_null.uint64;
        //memcpy(&l_s_ch_chain->request, &l_sync_request, sizeof(l_sync_request));

        if(0 == dap_stream_ch_chain_pkt_write(l_ch_chain, DAP_STREAM_CH_CHAIN_PKT_TYPE_SYNC_GLOBAL_DB,
                l_net->pub.id, l_chain_id_null, l_chain_cell_id_null, &l_sync_request,
                sizeof(l_sync_request))) {
            dap_chain_node_cli_set_reply_text(a_str_reply, "Error: Cant send sync chains request");
            // clean client struct
            dap_chain_node_client_close(l_node_client);
            DAP_DELETE(l_remote_node_info);
            return -1;
        }
        dap_stream_ch_set_ready_to_write(l_ch_chain, true);
        // wait for finishing of request
        timeout_ms = 120000; // 20 min = 1200 sec = 1 200 000 ms
        // TODO add progress info to console
        res = dap_chain_node_client_wait(l_node_client, NODE_CLIENT_STATE_SYNCED, timeout_ms);
        if ( res <0 ){
            dap_chain_node_client_close(l_node_client);
            DAP_DELETE(l_remote_node_info);
            dap_chain_node_cli_set_reply_text(a_str_reply, "Error: can't sync with node "NODE_ADDR_FP_STR,
                                              NODE_ADDR_FP_ARGS_S(l_node_client->remote_node_addr));

            return -2;
        // Requesting chains
        dap_chain_t *l_chain = NULL;
        DL_FOREACH(l_net->pub.chains, l_chain)
        {
            // send request
            dap_stream_ch_chain_sync_request_t l_sync_request = { { 0 } };
            if(0 == dap_stream_ch_chain_pkt_write(l_ch_chain, DAP_STREAM_CH_CHAIN_PKT_TYPE_SYNC_CHAINS,
                    l_net->pub.id, l_chain->id, l_remote_node_info->hdr.cell_id, &l_sync_request,
                    sizeof(l_sync_request))) {
                dap_chain_node_cli_set_reply_text(a_str_reply, "Error: Cant send sync chains request");
                // clean client struct
                dap_chain_node_client_close(l_node_client);
                DAP_DELETE(l_remote_node_info);
            log_it(L_NOTICE, "Requested syncronization for chain \"%s\"", l_chain->name);
            dap_stream_ch_set_ready_to_write(l_ch_chain, true);

            // wait for finishing of request
            timeout_ms = 120000; // 2 min = 120 sec = 120 000 ms
            // TODO add progress info to console
            res = dap_chain_node_client_wait(l_node_client, NODE_CLIENT_STATE_SYNCED, timeout_ms);
        }
        log_it(L_INFO, "Chains and gdb are synced");
        DAP_DELETE(l_remote_node_info);
        dap_client_disconnect(l_node_client->client);
        l_node_client->client = NULL;
        //dap_chain_node_client_close(l_node_client);
        dap_chain_node_cli_set_reply_text(a_str_reply, "Node sync completed: Chains and gdb are synced");
        return 0;
    }
        // make handshake
    case CMD_HANDSHAKE: {
        // get address from alias if addr not defined
        if(alias_str && !l_node_addr.uint64) {
            dap_chain_node_addr_t *address_tmp = dap_chain_node_addr_get_by_alias(l_net,alias_str);
            if(address_tmp) {
dmitriy.gerasimov's avatar
dmitriy.gerasimov committed
                memcpy(&l_node_addr, address_tmp, sizeof(*address_tmp));
                DAP_DELETE(address_tmp);
                dap_chain_node_cli_set_reply_text(a_str_reply, "no address found by alias");
        if(!l_node_addr.uint64) {
            dap_chain_node_cli_set_reply_text(a_str_reply, "addr not found");
        dap_chain_node_info_t *node_info = node_info_read_and_reply(l_net,&l_node_addr, a_str_reply);
        if(!node_info)
        int timeout_ms = 10000; //10 sec = 10000 ms
        // start handshake
        dap_chain_node_client_t *client = dap_chain_node_client_connect(node_info);
        if(!client) {
            dap_chain_node_cli_set_reply_text(a_str_reply, "can't connect");
            DAP_DELETE(node_info);
        }
        // wait handshake
        int res = dap_chain_node_client_wait(client, NODE_CLIENT_STATE_CONNECTED, timeout_ms);
        if(res != 1) {
            dap_chain_node_cli_set_reply_text(a_str_reply, "no response from node");
            // clean client struct
            dap_chain_node_client_close(client);
            DAP_DELETE(node_info);
        }
        DAP_DELETE(node_info);
        //Add new established connection in the list
        int ret = dap_chain_node_client_list_add(&l_node_addr, client);
        switch (ret)
        {
        case -1:
            dap_chain_node_client_close(client);
            dap_chain_node_cli_set_reply_text(a_str_reply, "connection established, but not saved");
        case -2:
            dap_chain_node_client_close(client);
            dap_chain_node_cli_set_reply_text(a_str_reply, "connection already present");
        dap_chain_node_cli_set_reply_text(a_str_reply, "connection established");
    return 0;
}

/**
 * Traceroute command
 *
 * return 0 OK, -1 Err
 */
dmitriy.gerasimov's avatar
dmitriy.gerasimov committed
int com_traceroute(int argc, char** argv, char **str_reply)
ANTA's avatar
ANTA committed
#ifndef _WIN32
    const char *addr = NULL;
    int hops = 0, time_usec = 0;
    if(argc > 1)
        addr = argv[1];
    iputils_set_verbose();
    int res = (addr) ? traceroute_util(addr, &hops, &time_usec) : -EADDRNOTAVAIL;