diff --git a/dap-sdk/core/include/dap_common.h b/dap-sdk/core/include/dap_common.h index 9452a02cbed7a7c64a2559f3f8abb8eceb0311cf..874a5dc568b5c008beefcfcfbeeeb7d9e6c5a460 100755 --- a/dap-sdk/core/include/dap_common.h +++ b/dap-sdk/core/include/dap_common.h @@ -40,6 +40,19 @@ typedef uint8_t byte_t; +// Stuffs an integer into a pointer type +#define DAP_INT_TO_POINTER(i) ((void*) (long) (i)) +// Extracts an integer from a pointer +#define DAP_POINTER_TO_INT(p) ((int) (long) (p)) +// Stuffs an unsigned integer into a pointer type +#define DAP_UINT_TO_POINTER(u) ((void*) (unsigned long) (u)) +// Extracts an unsigned integer from a pointer +#define DAP_POINTER_TO_UINT(p) ((unsigned int) (unsigned long) (p)) +// Stuffs a size_t into a pointer type +#define DAP_SIZE_TO_POINTER(s) ((void*) (size_t) (s)) +// Extracts a size_t from a pointer +#define DAP_POINTER_TO_SIZE(p) ((size_t) (p)) + #if defined(__GNUC__) ||defined (__clang__) #define DAP_ALIGN_PACKED __attribute__((aligned(1),packed)) #else diff --git a/dap-sdk/net/core/dap_timerfd.c b/dap-sdk/net/core/dap_timerfd.c new file mode 100644 index 0000000000000000000000000000000000000000..dec3016a0dd01ae237383a6e8b0728d912cdf44f --- /dev/null +++ b/dap-sdk/net/core/dap_timerfd.c @@ -0,0 +1,152 @@ +/* + * Authors: + * Alexander Lysikov <alexander.lysikov@demlabs.net> + * DeM Labs Inc. https://demlabs.net + * Kelvin Project https://github.com/kelvinblockchain + * Copyright (c) 2020 + * All rights reserved. + + 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 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/>. + */ + +#include <stdint.h> +#include <stdbool.h> +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <sys/time.h> +#include <sys/timerfd.h> +#include <inttypes.h> + +#include "dap_common.h" +#include "dap_events_socket.h" +#include "dap_timerfd.h" + +#define LOG_TAG "dap_timerfd" + +void callback_timerfd_read(struct dap_events_socket *a_event_sock, void * arg) +{ + uint64_t l_ptiu64; + size_t l_read_ret; + do { + l_read_ret = dap_events_socket_read(a_event_sock, &l_ptiu64, sizeof(l_ptiu64)); + + if(l_read_ret > 0) { + dap_timerfd_t *l_timerfd = a_event_sock->_inheritor; + //printf("\nread() returned %d, %d\n", l_ptiu64, l_read_ret); + struct itimerspec l_ts; + // first expiration in 0 seconds after times start + l_ts.it_interval.tv_sec = 0; + l_ts.it_interval.tv_nsec = 0; + // timeout for timer + l_ts.it_value.tv_sec = l_timerfd->timeout_ms / 1000; + l_ts.it_value.tv_nsec = (l_timerfd->timeout_ms % 1000) * 1000000; + if(timerfd_settime(l_timerfd->tfd, 0, &l_ts, NULL) < 0) { + log_it(L_WARNING, "callback_timerfd_read() failed: timerfd_settime() errno=%d\n", errno); + } + // run user's callback + if(l_timerfd->callback) + l_timerfd->callback(l_timerfd->callback_arg); + } + } while(l_read_ret > 0); + dap_events_socket_set_readable(a_event_sock, true); +} + +/** + * @brief dap_events_socket_init Init clients module + * @return Zero if ok others if no + */ +int dap_timerfd_init() +{ + log_it(L_NOTICE, "Initialized timerfd"); + return 0; +} + +/** + * @brief dap_timerfd_start + * @param a_timeout_ms + * @param a_callback + * @return new allocated dap_timerfd_t structure or NULL if error + */ +dap_timerfd_t* dap_timerfd_start(uint64_t a_timeout_ms, dap_timerfd_callback_t *a_callback, void *a_callback_arg) +{ + struct itimerspec l_ts; + int l_tfd = timerfd_create(CLOCK_MONOTONIC, 0); + if(l_tfd == -1) { + log_it(L_WARNING, "dap_timerfd_start() failed: timerfd_create() errno=%d\n", errno); + return NULL; + } + // first expiration in 0 seconds after times start + l_ts.it_interval.tv_sec = 0; + l_ts.it_interval.tv_nsec = 0; + // timeout for timer + l_ts.it_value.tv_sec = a_timeout_ms / 1000; + l_ts.it_value.tv_nsec = (a_timeout_ms % 1000) * 1000000; + if(timerfd_settime(l_tfd, 0, &l_ts, NULL) < 0) { + log_it(L_WARNING, "dap_timerfd_start() failed: timerfd_settime() errno=%d\n", errno); + close(l_tfd); + return NULL; + } + + // create dap_timerfd_t structure + dap_timerfd_t *l_timerfd = DAP_NEW(dap_timerfd_t); + + // create events_socket for timer file descriptor + static dap_events_socket_callbacks_t l_s_callbacks = { + .read_callback = callback_timerfd_read, + .write_callback = NULL, + .error_callback = NULL, + .delete_callback = NULL + }; + dap_events_socket_t * l_events_socket = dap_events_socket_wrap_no_add(NULL, l_tfd, &l_s_callbacks); + l_events_socket->type = DESCRIPTOR_TYPE_FILE; + dap_events_socket_create_after(l_events_socket); + // pass l_timerfd to events_socket + l_events_socket->_inheritor = l_timerfd; + + // fill out dap_timerfd_t structure + l_timerfd->timeout_ms = a_timeout_ms; + l_timerfd->tfd = l_tfd; + l_timerfd->events_socket = l_events_socket; + l_timerfd->callback = a_callback; + l_timerfd->callback_arg = a_callback_arg; + return l_timerfd; +} + +/** + * @brief dap_timerfd_stop + * @param a_tfd + * @param a_callback + * @return 0 or <0 if error + */ +int dap_timerfd_delete(dap_timerfd_t *l_timerfd) +{ + if(!l_timerfd || l_timerfd->tfd < 1 || !l_timerfd->events_socket) { + return -1; + } + + if(close(l_timerfd->tfd) == -1) { + log_it(L_WARNING, "dap_timerfd_stop() failed to close timerfd: errno=%d\n", errno); + return -2; + } + + dap_events_socket_kill_socket(l_timerfd->events_socket); + l_timerfd->events_socket = NULL; + DAP_DELETE(l_timerfd); + return 0; +} + diff --git a/dap-sdk/net/core/include/dap_timerfd.h b/dap-sdk/net/core/include/dap_timerfd.h new file mode 100644 index 0000000000000000000000000000000000000000..a658606e8395a69668ae11d1fa430c35e5e011dd --- /dev/null +++ b/dap-sdk/net/core/include/dap_timerfd.h @@ -0,0 +1,51 @@ +/* + * Authors: + * Alexander Lysikov <alexander.lysikov@demlabs.net> + * DeM Labs Inc. https://demlabs.net + * Kelvin Project https://github.com/kelvinblockchain + * Copyright (c) 2020 + * All rights reserved. + + 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 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/>. + */ + +#include <stdint.h> +#include <stdbool.h> +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <sys/time.h> +#include <sys/timerfd.h> +#include <inttypes.h> + +#include "dap_common.h" +#include "dap_events_socket.h" + +typedef void (*dap_timerfd_callback_t)(void * arg); // Callback for timer + +typedef struct dap_timerfd { + uint64_t timeout_ms; + int tfd; //timer file descriptor + dap_events_socket_t *events_socket; + dap_timerfd_callback_t callback; + void *callback_arg; +} dap_timerfd_t; + +int dap_timerfd_init(); +dap_timerfd_t* dap_timerfd_start(uint64_t a_timeout_ms, dap_timerfd_callback_t *a_callback, void *callback_arg); +int dap_timerfd_delete(dap_timerfd_t *l_timerfd); + diff --git a/modules/channel/chain-net-srv/dap_stream_ch_chain_net_srv.c b/modules/channel/chain-net-srv/dap_stream_ch_chain_net_srv.c index 694be366df353fc5786cacaa283489c6e94aff2c..ddd9ad790d4ae25e45da02c3385ab112e9d4dc33 100644 --- a/modules/channel/chain-net-srv/dap_stream_ch_chain_net_srv.c +++ b/modules/channel/chain-net-srv/dap_stream_ch_chain_net_srv.c @@ -21,7 +21,11 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License along with any CellFrame SDK based project. If not, see <http://www.gnu.org/licenses/>. */ + +#include <sys/time.h> #include "dap_common.h" +#include "dap_hash.h" +#include "rand/dap_rand.h" #include "dap_chain.h" #include "dap_chain_datum_tx.h" @@ -42,17 +46,16 @@ along with any CellFrame SDK based project. If not, see <http://www.gnu.org/lic #include "dap_stream_ch_pkt.h" #include "dap_stream_ch_chain_net_srv.h" #include "dap_stream_ch_chain_net_srv_pkt.h" - #include "dap_stream_ch_proc.h" +#include "dap_stream_ch_chain_net_srv.h" #define LOG_TAG "dap_stream_ch_chain_net_srv" -typedef struct dap_stream_ch_chain_net_srv { - pthread_mutex_t mutex; - dap_chain_net_srv_uid_t srv_uid; -} dap_stream_ch_chain_net_srv_t; -#define DAP_STREAM_CH_CHAIN_NET_SRV(a) ((dap_stream_ch_chain_net_srv_t *) ((a)->internal) ) +uint8_t dap_stream_ch_chain_net_srv_get_id() +{ + return 'R'; +} static void s_stream_ch_new(dap_stream_ch_t* ch , void* arg); static void s_stream_ch_delete(dap_stream_ch_t* ch , void* arg); @@ -146,6 +149,61 @@ void s_stream_ch_packet_in(dap_stream_ch_t* a_ch , void* a_arg) if(l_ch_pkt ) { switch (l_ch_pkt->hdr.type) { + // for send test data + case DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_CHECK_REQUEST:{ + int l_err_code = 0; + dap_stream_ch_chain_net_srv_pkt_test_t *l_request = (dap_stream_ch_chain_net_srv_pkt_request_t*) l_ch_pkt->data; + size_t l_request_size = l_request->data_size + sizeof(dap_stream_ch_chain_net_srv_pkt_test_t); + if(l_ch_pkt->hdr.size != l_request_size) { + log_it(L_WARNING, "Wrong request size, less or more than required"); + break; + } + + gettimeofday(&l_request->recv_time2, NULL); + //printf("\n%lu.%06lu \n", (unsigned long) l_request->recv_time2.tv_sec, (unsigned long) l_request->recv_time2.tv_usec); + dap_chain_hash_fast_t l_data_hash; + dap_hash_fast(l_request->data, l_request->data_size, &l_data_hash); + if(l_request->data_size>0 && !dap_hash_fast_compare(&l_data_hash, &(l_request->data_hash))){ + l_err_code+=2; + } + + // create data to send back + dap_stream_ch_chain_net_srv_pkt_test_t *l_request_out = DAP_NEW_Z_SIZE(dap_stream_ch_chain_net_srv_pkt_test_t, sizeof(dap_stream_ch_chain_net_srv_pkt_test_t) + l_request->data_size_recv); + // copy info from recv message + memcpy(l_request_out,l_request, sizeof(dap_stream_ch_chain_net_srv_pkt_test_t)); + l_request_out->data_size = l_request->data_size_recv; + randombytes(l_request_out->data, l_request_out->data_size); + l_request_out->err_code = l_err_code; + dap_hash_fast(l_request_out->data, l_request_out->data_size, &l_request_out->data_hash); + memcpy(l_request_out->ip_send, a_ch->stream->conn->s_ip, sizeof(l_request_out->ip_send)); + gettimeofday(&l_request_out->send_time2, NULL); + + // send response + if(dap_stream_ch_pkt_write(a_ch, DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_CHECK_RESPONSE, l_request_out, l_request_out->data_size + sizeof(dap_stream_ch_chain_net_srv_pkt_test_t))) { + dap_stream_ch_set_ready_to_write(a_ch, true); + } + DAP_DELETE(l_request_out); + + } + break; + // for receive test data. + case DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_CHECK_RESPONSE: { + dap_stream_ch_chain_net_srv_pkt_test_t *l_request = (dap_stream_ch_chain_net_srv_pkt_request_t *) l_ch_pkt->data; + size_t l_request_size = l_request->data_size + sizeof(dap_stream_ch_chain_net_srv_pkt_test_t); + if(l_ch_pkt->hdr.size != l_request_size) { + log_it(L_WARNING, "Wrong request size, less or more than required"); + break; + } + gettimeofday(&l_request->recv_time1, NULL); + dap_chain_hash_fast_t l_data_hash; + dap_hash_fast(l_request->data, l_request->data_size, &l_data_hash); + if(!dap_hash_fast_compare(&l_data_hash, &(l_request->data_hash))) { + l_request->err_code += 4; + } + dap_stream_ch_set_ready_to_write(a_ch, false); + } + break; + // only for server case DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_REQUEST:{ if (l_ch_pkt->hdr.size < sizeof(dap_stream_ch_chain_net_srv_pkt_request_hdr_t) ){ @@ -577,6 +635,8 @@ void s_stream_ch_packet_in(dap_stream_ch_t* a_ch , void* a_arg) } break; default: log_it( L_WARNING, "Unknown packet type 0x%02X", l_ch_pkt->hdr.type); } + if(l_ch_chain_net_srv->notify_callback) + l_ch_chain_net_srv->notify_callback(l_ch_chain_net_srv, l_ch_pkt->hdr.type, l_ch_pkt, l_ch_chain_net_srv->notify_callback_arg); } } diff --git a/modules/channel/chain-net-srv/dap_stream_ch_chain_net_srv.h b/modules/channel/chain-net-srv/dap_stream_ch_chain_net_srv.h new file mode 100644 index 0000000000000000000000000000000000000000..f6b83f171919a1d99abfff45a5cfa156cb3a5380 --- /dev/null +++ b/modules/channel/chain-net-srv/dap_stream_ch_chain_net_srv.h @@ -0,0 +1,47 @@ +/* + * Authors: + * Alexander Lysikov <alexander.lysikov@demlabs.net> + * Cellframe https://cellframe.net + * DeM Labs Inc. https://demlabs.net + * Copyright (c) 2020 + * All rights reserved. + + This file is part of CellFrame SDK the open source project + + CellFrame SDK 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. + + CellFrame SDK 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 CellFrame SDK based project. If not, see <http://www.gnu.org/licenses/>. + */ + +#pragma once + +#include <pthread.h> +#include "dap_stream_ch.h" +#include "dap_stream_ch_pkt.h" + +typedef struct dap_stream_ch_chain_net_srv dap_stream_ch_chain_net_srv_t; + +typedef void (*dap_stream_ch_chain_net_srv_callback_packet_t)(dap_stream_ch_chain_net_srv_t *, uint8_t, + dap_stream_ch_pkt_t *, void *); + +typedef struct dap_stream_ch_chain_net_srv { + pthread_mutex_t mutex; + dap_chain_net_srv_uid_t srv_uid; + dap_stream_ch_chain_net_srv_callback_packet_t notify_callback; + void *notify_callback_arg; +} dap_stream_ch_chain_net_srv_t; + +#define DAP_STREAM_CH_CHAIN_NET_SRV(a) ((dap_stream_ch_chain_net_srv_t *) ((a)->internal) ) + +void dap_stream_ch_chain_net_srv_set_srv_uid(dap_stream_ch_t* a_ch, dap_chain_net_srv_uid_t a_srv_uid); +uint8_t dap_stream_ch_chain_net_srv_get_id(); + diff --git a/modules/net/CMakeLists.txt b/modules/net/CMakeLists.txt index 9c3c877a0e8c713e8567edfa7f758ec57af7ceaf..e5d055725660d5a26b7aa656d5037c7616204d48 100644 --- a/modules/net/CMakeLists.txt +++ b/modules/net/CMakeLists.txt @@ -39,12 +39,12 @@ endif() add_library(${PROJECT_NAME} STATIC ${DAP_CHAIN_NET_SRCS} ${DAP_CHAIN_NET_HEADERS} ${IPUTILS_SRCS} ${IPUTILS_HEADERS}) if(WIN32) - target_link_libraries(dap_chain_net dap_core dap_crypto dap_client dap_stream_ch_chain dap_stream_ch_chain_net dap_chain dap_chain_crypto dap_chain_wallet dap_chain_net_srv + target_link_libraries(dap_chain_net dap_core dap_crypto dap_client dap_stream_ch_chain dap_stream_ch_chain_net dap_stream_ch_chain_net_srv dap_chain dap_chain_crypto dap_chain_wallet dap_chain_net_srv dap_chain_mempool dap_chain_global_db dap_chain_net_srv_stake) endif() if(UNIX) - target_link_libraries(${PROJECT_NAME} dap_core dap_crypto dap_client dap_stream_ch_chain dap_stream_ch_chain_net dap_chain + target_link_libraries(${PROJECT_NAME} dap_core dap_crypto dap_client dap_stream_ch_chain dap_stream_ch_chain_net dap_stream_ch_chain_net_srv dap_chain dap_chain_wallet dap_chain_net_srv dap_chain_mempool dap_chain_global_db dap_chain_net_srv_stake resolv ) diff --git a/modules/net/dap_chain_net.c b/modules/net/dap_chain_net.c index f208c1eaa5774bc90f506f7d6e2d57ef8738f44b..3df5696454e679022a615867a307813dfea5a1a6 100644 --- a/modules/net/dap_chain_net.c +++ b/modules/net/dap_chain_net.c @@ -57,6 +57,7 @@ #include "dap_string.h" #include "dap_strfuncs.h" #include "dap_file_utils.h" +#include "dap_enc_base58.h" #include "dap_config.h" #include "dap_hash.h" #include "dap_cert.h" diff --git a/modules/net/dap_chain_node_client.c b/modules/net/dap_chain_node_client.c index 1c3fe94d75e7944768ed291173f5714867dc825a..3c21deb1aeeac66b011c7baa30676b1fe13067ca 100644 --- a/modules/net/dap_chain_node_client.c +++ b/modules/net/dap_chain_node_client.c @@ -29,6 +29,7 @@ #include <errno.h> #include <assert.h> #include <string.h> +#include <json-c/json.h> #ifdef WIN32 #include <winsock2.h> @@ -48,11 +49,13 @@ #include "dap_client_pvt.h" #include "dap_chain_global_db_remote.h" #include "dap_chain_global_db_hist.h" +#include "dap_chain_net_srv_common.h" #include "dap_stream_ch_pkt.h" #include "dap_stream_ch_chain.h" #include "dap_stream_ch_chain_pkt.h" #include "dap_stream_ch_chain_net.h" #include "dap_stream_ch_chain_net_pkt.h" +#include "dap_stream_ch_chain_net_srv.h" #include "dap_stream_pkt.h" //#include "dap_chain_common.h" @@ -248,6 +251,7 @@ static void s_ch_chain_callback_notify_packet_in2(dap_stream_ch_chain_net_t* a_c } } + /** * @brief s_ch_chain_callback_notify_packet_in - for dap_stream_ch_chain * @param a_ch_chain @@ -410,6 +414,8 @@ static void s_ch_chain_callback_notify_packet_in(dap_stream_ch_chain_t* a_ch_cha } } + + /** * @brief s_ch_chain_callback_notify_packet_in * @param a_ch_chain @@ -445,6 +451,86 @@ static void s_ch_chain_callback_notify_packet_out(dap_stream_ch_chain_t* a_ch_ch } } +static int save_stat_to_database(dap_stream_ch_chain_net_srv_pkt_test_t *a_request, dap_chain_node_client_t * a_node_client) +{ + int l_ret = 0; + if(!a_request) + return -1; + long l_t1_ms = (long) a_request->send_time1.tv_sec * 1000 + a_request->send_time1.tv_usec / 1000; + long l_t2_ms = (long) a_request->recv_time1.tv_sec * 1000 + a_request->recv_time1.tv_usec / 1000; + struct json_object *jobj = json_object_new_object(); + time_t l_cur_t = time(NULL); + char buf[1024]; + dap_time_to_str_rfc822( buf, sizeof(buf), l_cur_t ); + json_object_object_add(jobj, "time_save", json_object_new_int64(l_cur_t)); + json_object_object_add(jobj, "time_save_str", json_object_new_string(buf)); + json_object_object_add(jobj, "time_connect", json_object_new_int(a_request->time_connect_ms)); + json_object_object_add(jobj, "time_transmit", json_object_new_int(l_t2_ms-l_t1_ms)); + json_object_object_add(jobj, "ip_send", json_object_new_string(a_request->ip_send)); + json_object_object_add(jobj, "ip_recv", json_object_new_string(a_request->ip_recv)); + json_object_object_add(jobj, "time_len_send", json_object_new_int(a_request->data_size_send)); + json_object_object_add(jobj, "time_len_recv", json_object_new_int(a_request->data_size_recv)); + json_object_object_add(jobj, "err_code", json_object_new_int(a_request->err_code)); + const char* json_str = json_object_to_json_string(jobj); + // save statistics + char *l_group = NULL; + dap_chain_net_t * l_net = dap_chain_net_by_id(a_request->net_id); + if(l_net) { + l_group = dap_strdup_printf("%s.orders-test-stat", l_net->pub.gdb_groups_prefix); + } + if(l_group) { + dap_store_obj_t *l_obj = dap_chain_global_db_get_last(l_group); + int64_t l_key = 0; + if(l_obj) { + l_key = strtoll(l_obj->key, NULL, 16); + } + char *l_key_str = dap_strdup_printf("%06x", ++l_key); + if(!dap_chain_global_db_gr_set(dap_strdup(l_key_str), (uint8_t *) json_str, strlen(json_str) + 1, l_group)) { + l_ret = -1; + } + DAP_DELETE(l_key_str); + DAP_DELETE(l_group); + } + else + l_ret = -2; + json_object_put(jobj); + return l_ret; +} +/** + * @brief s_ch_chain_callback_notify_packet_R - Callback for channel 'R' + * @param a_ch_chain + * @param a_pkt_type + * @param a_pkt + * @param a_arg + */ +static void s_ch_chain_callback_notify_packet_R(dap_stream_ch_chain_net_srv_t* a_ch_chain, uint8_t a_pkt_type, dap_stream_ch_pkt_t *a_pkt, void * a_arg) +{ + dap_chain_node_client_t * l_node_client = (dap_chain_node_client_t *) a_arg; + switch (a_pkt_type) { + // get new generated current node address + case DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_CHECK_RESPONSE: { + dap_stream_ch_chain_net_srv_pkt_test_t *l_request = (dap_stream_ch_chain_net_srv_pkt_request_t *) a_pkt->data; + size_t l_request_size = l_request->data_size + sizeof(dap_stream_ch_chain_net_srv_pkt_test_t); + if(a_pkt->hdr.size != l_request_size) { + log_it(L_WARNING, "Wrong request size, less or more than required"); + break; + } + // todo to write result to database + save_stat_to_database(l_request, l_node_client); + //... + pthread_mutex_lock(&l_node_client->wait_mutex); + l_node_client->state = NODE_CLIENT_STATE_CHECKED; + pthread_mutex_unlock(&l_node_client->wait_mutex); +#ifndef _WIN32 + pthread_cond_signal(&l_node_client->wait_cond); +#else + SetEvent( l_node_client->wait_cond ); +#endif + break; + } + } +} + /** * Create connection to server * @@ -658,17 +744,25 @@ int dap_chain_node_client_set_callbacks(dap_client_t *a_client, uint8_t a_ch_id) if(l_client_internal) l_ch = dap_client_get_stream_ch(a_client, a_ch_id); if(l_ch) { + // C if(a_ch_id == dap_stream_ch_chain_get_id()) { dap_stream_ch_chain_t * l_ch_chain = DAP_STREAM_CH_CHAIN(l_ch); l_ch_chain->callback_notify_packet_out = s_ch_chain_callback_notify_packet_out; l_ch_chain->callback_notify_packet_in = s_ch_chain_callback_notify_packet_in; l_ch_chain->callback_notify_arg = l_node_client; } + // N if(a_ch_id == dap_stream_ch_chain_net_get_id()) { dap_stream_ch_chain_net_t *l_ch_chain = DAP_STREAM_CH_CHAIN_NET(l_ch); l_ch_chain->notify_callback = s_ch_chain_callback_notify_packet_in2; l_ch_chain->notify_callback_arg = l_node_client; } + // R + if(a_ch_id == dap_stream_ch_chain_net_srv_get_id()) { + dap_stream_ch_chain_net_srv_t * l_ch_chain = DAP_STREAM_CH_CHAIN_NET_SRV(l_ch); + l_ch_chain->notify_callback = s_ch_chain_callback_notify_packet_R; + l_ch_chain->notify_callback_arg = l_node_client; + } l_ret = 0; } else { } diff --git a/modules/net/include/dap_chain_node_client.h b/modules/net/include/dap_chain_node_client.h index 4a5eb2e307768a133a46050a280d871b4bff22e2..de35fd3d8adb6f41621de7678c5203c57bf6d149 100644 --- a/modules/net/include/dap_chain_node_client.h +++ b/modules/net/include/dap_chain_node_client.h @@ -44,6 +44,7 @@ typedef enum dap_chain_node_client_state { NODE_CLIENT_STATE_SYNC_GDB = 101, NODE_CLIENT_STATE_SYNC_CHAINS = 102, NODE_CLIENT_STATE_SYNCED = 103, + NODE_CLIENT_STATE_CHECKED = 104, } dap_chain_node_client_state_t; typedef struct dap_chain_node_client dap_chain_node_client_t; diff --git a/modules/net/srv/dap_chain_net_srv_common.c b/modules/net/srv/dap_chain_net_srv_common.c index 23618345a63e6462533f0fe4356e49009212b198..601f847236016b51f787520f9edf1d238714a40f 100644 --- a/modules/net/srv/dap_chain_net_srv_common.c +++ b/modules/net/srv/dap_chain_net_srv_common.c @@ -46,7 +46,4 @@ #include "dap_stream.h" #include "dap_chain_net_srv_common.h" -uint8_t dap_stream_ch_chain_net_srv_get_id() -{ - return 'R'; -} + diff --git a/modules/net/srv/dap_chain_net_srv_order.c b/modules/net/srv/dap_chain_net_srv_order.c index 9d536c535ac465ede1ecfc1315a0b0690169dc5c..e3df6bfad4021dbb823a9a984b305cd960c78f2c 100644 --- a/modules/net/srv/dap_chain_net_srv_order.c +++ b/modules/net/srv/dap_chain_net_srv_order.c @@ -489,6 +489,19 @@ void dap_chain_net_srv_order_dump_to_string(dap_chain_net_srv_order_t *a_order,d dap_string_append_printf(a_str_out, " ext: 0x%s\n", l_ext_out); else dap_string_append_printf(a_str_out, " ext: 0x0\n"); + // order state +/* { + int l_order_state = get_order_state(a_order->node_addr); + // if order is not tested + if(l_order_state == -1) + dap_string_append_printf(a_str_out, " \"State\":\"unknown\"\n"); + // if order off-line + else if(l_order_state == 1) + dap_string_append_printf(a_str_out, " \"State\":\"available\"\n"); + // if order on-line + else + dap_string_append_printf(a_str_out, " \"State\":\"not available\"\n"); + }*/ DAP_DELETE(l_hash_str); DAP_DELETE(l_ext_out); } diff --git a/modules/net/srv/include/dap_chain_net_srv_common.h b/modules/net/srv/include/dap_chain_net_srv_common.h index 673e65959d98c908713d00f39ad2f76561c934b6..d45ace6791a839ce7019b8b642c7de519b4fc737 100755 --- a/modules/net/srv/include/dap_chain_net_srv_common.h +++ b/modules/net/srv/include/dap_chain_net_srv_common.h @@ -98,6 +98,9 @@ typedef struct dap_chain_net_srv_price #define DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_DATA 0x30 #define DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_RESPONSE_SUCCESS 0xf0 #define DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_RESPONSE_ERROR 0xff +// for connection testing +#define DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_CHECK_REQUEST 0x40 +#define DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_CHECK_RESPONSE 0x41 #define DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_RESPONSE_ERROR_CODE_UNDEFINED 0x00000000 #define DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_RESPONSE_ERROR_CODE_SERVICE_NOT_FOUND 0x00000100 @@ -163,7 +166,25 @@ typedef struct dap_stream_ch_chain_net_srv_pkt_error{ uint32_t code; // error code } DAP_ALIGN_PACKED dap_stream_ch_chain_net_srv_pkt_error_t; - +// data packet for connectiont test +typedef struct dap_stream_ch_chain_net_srv_pkt_test{ + uint32_t usage_id; + dap_chain_net_id_t net_id; + dap_chain_net_srv_uid_t srv_uid; + int32_t time_connect_ms; + struct timeval recv_time1; + struct timeval recv_time2; + struct timeval send_time1; + struct timeval send_time2; + char ip_send[16]; + char ip_recv[16]; + int32_t err_code; + size_t data_size_send; + size_t data_size_recv; + size_t data_size; + dap_chain_hash_fast_t data_hash; + uint8_t data[]; +} DAP_ALIGN_PACKED dap_stream_ch_chain_net_srv_pkt_test_t; DAP_STATIC_INLINE const char * dap_chain_net_srv_price_unit_uid_to_str( dap_chain_net_srv_price_unit_uid_t a_uid ) diff --git a/modules/service/vpn/dap_chain_net_srv_vpn_cmd.c b/modules/service/vpn/dap_chain_net_srv_vpn_cmd.c index 01a18e9f0d56708000f00ff5ed3d7baefd032d39..ce9f46417292427b0b42e8359cd9dbe1e8dddc0f 100644 --- a/modules/service/vpn/dap_chain_net_srv_vpn_cmd.c +++ b/modules/service/vpn/dap_chain_net_srv_vpn_cmd.c @@ -12,9 +12,19 @@ int com_vpn_client(int a_argc, char ** a_argv, void *arg_func, char **a_str_repl { #ifndef _WIN32 enum { - CMD_NONE, CMD_INIT, CMD_START, CMD_STOP, CMD_STATUS + CMD_NONE, CMD_INIT, CMD_START, CMD_STOP, CMD_STATUS, CMD_CHECK, CMD_CHECK_RESULT }; int l_arg_index = 1; + + const char * l_hash_out_type = NULL; + dap_chain_node_cli_find_option_val(a_argv, l_arg_index, a_argc, "-H", &l_hash_out_type); + if(!l_hash_out_type) + l_hash_out_type = "base58"; + if(dap_strcmp(l_hash_out_type,"hex") && dap_strcmp(l_hash_out_type,"base58")) { + dap_chain_node_cli_set_reply_text(a_str_reply, "invalid parameter -H, valid values: -H <hex | base58>"); + return -1; + } + // find net dap_chain_net_t *l_net = NULL; if(dap_chain_node_cli_cmd_values_parse_net_chain(&l_arg_index, a_argc, a_argv, a_str_reply, NULL, &l_net) < 0) @@ -33,6 +43,12 @@ int com_vpn_client(int a_argc, char ** a_argv, void *arg_func, char **a_str_repl else if(dap_chain_node_cli_find_option_val(a_argv, l_arg_index, min(a_argc, l_arg_index + 1), "status", NULL)) { cmd_num = CMD_STATUS; } + else if(dap_chain_node_cli_find_option_val(a_argv, l_arg_index, min(a_argc, l_arg_index + 1), "check", NULL)) { + cmd_num = CMD_CHECK; + if(dap_chain_node_cli_find_option_val(a_argv, min(a_argc, l_arg_index + 1), min(a_argc, l_arg_index + 2), "result", NULL)) { + cmd_num = CMD_CHECK_RESULT; + } + } if(cmd_num == CMD_NONE) { if(!a_argv[1]) dap_chain_node_cli_set_reply_text(a_str_reply, "invalid parameters"); @@ -43,6 +59,55 @@ int com_vpn_client(int a_argc, char ** a_argv, void *arg_func, char **a_str_repl switch (cmd_num) { + case CMD_CHECK_RESULT: { + char *l_str = dap_chain_net_vpn_client_check_result(l_net, l_hash_out_type); + dap_chain_node_cli_set_reply_text(a_str_reply, l_str); + DAP_DELETE(l_str); + } + break; + case CMD_CHECK: { + const char * l_str_addr = NULL; // for example, "192.168.100.93" + const char * l_str_port = NULL; // for example, "8079" + dap_chain_node_cli_find_option_val(a_argv, l_arg_index, a_argc, "-addr", &l_str_addr); + if(!l_str_addr) { + dap_chain_node_cli_set_reply_text(a_str_reply, + "VPN server address not defined, use -addr <vpn server ipv4 address> parameter"); + break; + } + dap_chain_node_cli_find_option_val(a_argv, l_arg_index, a_argc, "-port", &l_str_port); + int l_srv_port = (l_str_port) ? (int) strtoll(l_str_port, 0, 10) : 0; + if(!l_srv_port) { + dap_chain_node_cli_set_reply_text(a_str_reply, + "VPN server port not defined, use -port <vpn server port> parameter"); + break; + } + size_t l_data_size_to_send = 10240; + size_t l_data_size_to_recv = 0;// no recv data, only send + // default timeout 10ms + int l_timeout_test_ms = dap_config_get_item_int32_default( g_config,"cdb", "servers_list_check_timeout", 20) * 1000;// read settings + // start node check + int l_res = dap_chain_net_vpn_client_check(l_net, l_str_addr, NULL, l_srv_port, l_data_size_to_send, l_data_size_to_recv, l_timeout_test_ms); + if(!l_res){ + l_data_size_to_send = 0;// no send data, only recv + size_t l_data_size_to_recv = 10240; + int l_timeout_test_ms = -1;// default timeout + int l_res = dap_chain_net_vpn_client_check(l_net, l_str_addr, NULL, l_srv_port, l_data_size_to_send, l_data_size_to_recv, l_timeout_test_ms); + } + switch (l_res) { + case 0: + dap_chain_node_cli_set_reply_text(a_str_reply, "tested VPN server successfully"); + break; + case -2: + case -3: + dap_chain_node_cli_set_reply_text(a_str_reply, "Can't connect to VPN server"); + break; + default: + dap_chain_node_cli_set_reply_text(a_str_reply, "Can't recognize error code=%d", l_res); + break; + } + return l_res; + } + break; case CMD_INIT: { const char * l_str_token = NULL; // token name const char * l_str_value_datoshi = NULL; diff --git a/modules/service/vpn/dap_chain_net_vpn_client.c b/modules/service/vpn/dap_chain_net_vpn_client.c index ef7b2d77df63ed27bc32567ec122c3f7730ca794..24c919c9bb47247b1a97167966c23ec9824f55a6 100644 --- a/modules/service/vpn/dap_chain_net_vpn_client.c +++ b/modules/service/vpn/dap_chain_net_vpn_client.c @@ -38,8 +38,10 @@ #include "dap_common.h" #include "dap_config.h" #include "dap_strfuncs.h" +#include "rand/dap_rand.h" #include "dap_client.h" +#include "dap_enc_base58.h" #include "dap_chain_node_client.h" #include "dap_stream_ch_proc.h" @@ -47,6 +49,7 @@ #include "dap_chain_common.h" #include "dap_chain_mempool.h" +#include "dap_chain_node_cli.h" #include "dap_chain_net_srv_vpn.h" #include "dap_chain_net_srv_vpn_cdb.h" // for DAP_CHAIN_NET_SRV_VPN_CDB_GDB_PREFIX #include "dap_chain_net_vpn_client.h" @@ -56,6 +59,7 @@ //#include "dap_stream_ch_chain_net_srv.h" #include "dap_chain_net_vpn_client_tun.h" #include "dap_chain_net_srv_vpn_cmd.h" +#include "dap_chain_net_srv_vpn_cdb_server_list.h" //#include "dap_chain_net_vpn_client_data.h" /* @@ -303,6 +307,167 @@ int dap_chain_net_vpn_client_get_wallet_info(dap_chain_net_t *a_net, char **a_wa return 0; } + +char *dap_chain_net_vpn_client_check_result(dap_chain_net_t *a_net, const char* a_hash_out_type) +{ + + + dap_chain_net_srv_order_t * l_orders = NULL; + size_t l_orders_num = 0; + dap_chain_net_srv_uid_t l_srv_uid = { { 0 } }; + uint64_t l_price_min = 0, l_price_max = 0; + dap_chain_net_srv_price_unit_uid_t l_price_unit = { { 0 } }; + dap_chain_net_srv_order_direction_t l_direction = SERV_DIR_UNDEFINED; + dap_string_t *l_string_ret = dap_string_new(""); + + if(dap_chain_net_srv_order_find_all_by(a_net, l_direction, l_srv_uid, l_price_unit, NULL, l_price_min, l_price_max, &l_orders, &l_orders_num) == 0){ + size_t l_orders_size = 0; + for(size_t i = 0; i < l_orders_num; i++) { + dap_chain_net_srv_order_t *l_order = (dap_chain_net_srv_order_t *) (((byte_t*) l_orders) + l_orders_size); + //dap_chain_net_srv_order_dump_to_string(l_order, l_string_ret, l_hash_out_type); + dap_chain_hash_fast_t l_hash; + char *l_hash_str; + dap_hash_fast(l_order, dap_chain_net_srv_order_get_size(l_order), &l_hash); + if(!dap_strcmp(a_hash_out_type, "hex")) + l_hash_str = dap_chain_hash_fast_to_str_new(&l_hash); + else + l_hash_str = dap_enc_base58_encode_hash_to_str(&l_hash); + int l_state = get_order_state(l_order->node_addr); + const char *l_state_str; + switch (l_state) + { + case 0: + l_state_str = "Not available"; + break; + case 1: + l_state_str = "Available"; + break; + default: + l_state_str = "Unknown"; + } + dap_string_append_printf(l_string_ret, "Order %s: State %s\n", l_hash_str, l_state_str); + DAP_DELETE(l_hash_str); + l_orders_size += dap_chain_net_srv_order_get_size(l_order); + //dap_string_append(l_string_ret, "\n"); + } + } + // return str from dap_string_t + return dap_string_free(l_string_ret, false); +} + +/** + * Check VPN server + * + * return: 0 Ok, <0 Error + */ +int dap_chain_net_vpn_client_check(dap_chain_net_t *a_net, const char *a_ipv4_str, const char *a_ipv6_str, int a_port, size_t a_data_size_to_send, size_t a_data_size_to_recv, int a_timeout_test_ms) +{ + // default 10k + if(a_data_size_to_send==-1) + a_data_size_to_send = 10240; + if(a_data_size_to_recv==-1) + a_data_size_to_recv = 10240; + // default 10 sec = 10000 ms + if(a_timeout_test_ms==-1) + a_timeout_test_ms = 10000; + // default 5 sec = 5000 ms + int l_timeout_conn_ms = 5000; + + int l_ret = 0; + if(!a_ipv4_str) // && !a_ipv6_str) + return -1; + if(!s_node_info) + s_node_info = DAP_NEW_Z(dap_chain_node_info_t); + s_node_info->hdr.ext_port = a_port; + + + // measuring connection time + struct timeval l_t; + gettimeofday(&l_t, NULL);//get_cur_time_msec + long l_t1 = (long) l_t.tv_sec * 1000 + l_t.tv_usec / 1000; + + dap_client_stage_t l_stage_target = STAGE_STREAM_STREAMING; //DAP_CLIENT_STAGE_STREAM_CTL;//STAGE_STREAM_STREAMING; + const char l_active_channels[] = { dap_stream_ch_chain_net_srv_get_id(), 0 }; //only R, without S + if(a_ipv4_str) + inet_pton(AF_INET, a_ipv4_str, &(s_node_info->hdr.ext_addr_v4)); + if(a_ipv6_str) + inet_pton(AF_INET6, a_ipv6_str, &(s_node_info->hdr.ext_addr_v6)); + + s_vpn_client = dap_chain_client_connect(s_node_info, l_stage_target, l_active_channels); + if(!s_vpn_client) { + log_it(L_ERROR, "Can't connect to VPN server=%s:%d", a_ipv4_str, a_port); + // clean client struct + dap_chain_node_client_close(s_vpn_client); + DAP_DELETE(s_node_info); + s_node_info = NULL; + return -2; + } + // wait connected + int l_timeout_ms = l_timeout_conn_ms; //5 sec = 5000 ms + int l_res = dap_chain_node_client_wait(s_vpn_client, NODE_CLIENT_STATE_CONNECTED, l_timeout_ms); + if(l_res) { + log_it(L_ERROR, "No response from VPN server=%s:%d", a_ipv4_str, a_port); + // clean client struct + dap_chain_node_client_close(s_vpn_client); + DAP_DELETE(s_node_info); + s_node_info = NULL; + return -3; + } + + gettimeofday(&l_t, NULL); + long l_t2 = (long) l_t.tv_sec * 1000 + l_t.tv_usec / 1000; + int l_dtime_connect_ms = l_t2-l_t1; + + //l_ret = dap_chain_net_vpn_client_tun_init(a_ipv4_str); + + // send first packet to server + { + uint8_t l_ch_id = dap_stream_ch_chain_net_srv_get_id(); // Channel id for chain net request = 'R' + dap_stream_ch_t *l_ch = dap_client_get_stream_ch(s_vpn_client->client, l_ch_id); + if(l_ch) { + dap_stream_ch_chain_net_srv_pkt_test_t *l_request = DAP_NEW_Z_SIZE(dap_stream_ch_chain_net_srv_pkt_test_t, sizeof(dap_stream_ch_chain_net_srv_pkt_test_t) + a_data_size_to_send); + l_request->net_id.uint64 = a_net->pub.id.uint64; + l_request->srv_uid.uint64 = DAP_CHAIN_NET_SRV_VPN_ID; + l_request->data_size_send = a_data_size_to_send; + l_request->data_size_recv = a_data_size_to_recv; + l_request->data_size = a_data_size_to_send; + randombytes(l_request->data, a_data_size_to_send); + dap_chain_hash_fast_t l_data_hash; + dap_hash_fast(l_request->data, l_request->data_size, &l_request->data_hash); + if(a_ipv4_str) + memcpy(l_request->ip_recv, a_ipv4_str, min(sizeof(l_request->ip_recv), strlen(a_ipv4_str))); + + l_request->time_connect_ms = l_dtime_connect_ms; + gettimeofday(&l_request->send_time1, NULL); + size_t l_request_size = l_request->data_size + sizeof(dap_stream_ch_chain_net_srv_pkt_test_t); + dap_stream_ch_pkt_write(l_ch, DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_CHECK_REQUEST, l_request, l_request_size); + dap_stream_ch_set_ready_to_write(l_ch, true); + DAP_DELETE(l_request); + } + } + // wait testing + //int timeout_test_ms = 10000; //10 sec = 10000 ms + a_timeout_test_ms -=l_dtime_connect_ms; + // timeout not less then 5 sec + if(a_timeout_test_ms<5000) + a_timeout_test_ms = 5000; + l_res = dap_chain_node_client_wait(s_vpn_client, NODE_CLIENT_STATE_CHECKED, a_timeout_test_ms); + if(l_res) { + log_it(L_ERROR, "No response from VPN server=%s:%d", a_ipv4_str, a_port); + } + else{ + log_it(L_NOTICE, "Got response from VPN server=%s:%d", a_ipv4_str, a_port); + } + // clean client struct + dap_chain_node_client_close(s_vpn_client); + DAP_DELETE(s_node_info); + s_node_info = NULL; + if(l_res) + return -3; + return l_ret; +} + + /** * Start VPN client * @@ -728,7 +893,13 @@ int dap_chain_net_vpn_client_init(dap_config_t * g_config) // vpn client command dap_chain_node_cli_cmd_item_create ("vpn_client", com_vpn_client, NULL, "VPN client control", - "vpn_client [start -addr <server address> -port <server port>| stop | status] -net <net name>\n"); + "vpn_client [start -addr <server address> -port <server port>| stop | status] -net <net name>\n" + "vpn_client init -w <wallet name> -token <token name> -value <value> -net <net name>\n" + "vpn_client stop -net <net name>\n" + "vpn_client status -net <net name>\n" + "vpn_client check -addr <ip addr> -port <port> -net <net name>\n" + "vpn_client check result -net <net name> [-H hex|base58(default)]\n" + ); return dap_chain_net_srv_client_vpn_init(g_config); diff --git a/modules/service/vpn/include/dap_chain_net_srv_vpn_cdb_server_list.h b/modules/service/vpn/include/dap_chain_net_srv_vpn_cdb_server_list.h index 6aaacc975870a5f18986c1754649272a6a9731e0..ce8da913514d543fe562a4385887d21575d83a9c 100644 --- a/modules/service/vpn/include/dap_chain_net_srv_vpn_cdb_server_list.h +++ b/modules/service/vpn/include/dap_chain_net_srv_vpn_cdb_server_list.h @@ -31,6 +31,8 @@ struct dap_http; +int get_order_state(dap_chain_node_addr_t a_node_addr); + int dap_chain_net_srv_vpn_cdb_server_list_init(void); void dap_chain_net_srv_vpn_cdb_server_list_deinit(void); void dap_chain_net_srv_vpn_cdb_server_list_add_proc(struct dap_http * sh, const char * url); diff --git a/modules/service/vpn/include/dap_chain_net_vpn_client.h b/modules/service/vpn/include/dap_chain_net_vpn_client.h index 4f613e02c8c88dd41c320e0c2a901948b87fe60c..c97f694c0adbdc5e1243d759b2ba1c63dc8d5246 100644 --- a/modules/service/vpn/include/dap_chain_net_vpn_client.h +++ b/modules/service/vpn/include/dap_chain_net_vpn_client.h @@ -42,6 +42,9 @@ dap_stream_ch_t* dap_chain_net_vpn_client_get_stream_ch(void); int dap_chain_net_vpn_client_update(dap_chain_net_t *a_net, const char *a_wallet_name, const char *a_str_token, uint64_t a_value_datoshi); int dap_chain_net_vpn_client_get_wallet_info(dap_chain_net_t *a_net, char **a_wallet_name, char **a_str_token, uint64_t *a_value_datoshi); +char *dap_chain_net_vpn_client_check_result(dap_chain_net_t *a_net, const char* a_hash_out_type); +int dap_chain_net_vpn_client_check(dap_chain_net_t *a_net, const char *a_ipv4_str, const char *a_ipv6_str, int a_port, size_t a_data_size_to_send, size_t a_data_size_to_recv, int a_timeout_test_ms); + int dap_chain_net_vpn_client_start(dap_chain_net_t *a_net, const char *a_ipv4_str, const char *a_ipv6_str, int a_port); int dap_chain_net_vpn_client_stop(void); dap_chain_net_vpn_client_status_t dap_chain_net_vpn_client_status(void);