/* * Authors: * Dmitriy Gerasimov <naeper@demlabs.net> * Roman Khlopkov <roman.khlopkov@demlabs.net> * Cellframe https://cellframe.net * DeM Labs Inc. https://demlabs.net * Copyright (c) 2017-2022 * 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/>. */ #include "dap_stream_ch_chain_net_srv.h" #include "dap_chain_net_srv.h" #include "dap_chain_net_srv_client.h" #include "dap_common.h" #include "dap_time.h" #define LOG_TAG "dap_chain_net_srv_client" static void s_srv_client_pkt_in(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); static void s_srv_client_callback_connected(dap_chain_node_client_t *a_node_client, void *a_arg); static void s_srv_client_callback_disconnected(dap_chain_node_client_t *a_node_client, void *a_arg); static void s_srv_client_callback_deleted(dap_chain_node_client_t *a_node_client, void *a_arg); dap_chain_net_srv_client_t *dap_chain_net_srv_client_create_n_connect(dap_chain_net_t *a_net, char *a_addr, uint16_t a_port, dap_chain_net_srv_client_callbacks_t *a_callbacks, void *a_callbacks_arg) { dap_chain_net_srv_client_t *l_ret = DAP_NEW_Z(dap_chain_net_srv_client_t); if (a_callbacks) l_ret->callbacks = *a_callbacks; l_ret->callbacks_arg = a_callbacks_arg; dap_chain_node_client_callbacks_t l_callbacks = { .connected = s_srv_client_callback_connected, .disconnected = s_srv_client_callback_disconnected, .delete = s_srv_client_callback_deleted }; dap_chain_node_info_t *l_info = DAP_NEW_Z(dap_chain_node_info_t); inet_pton(AF_INET, a_addr, &l_info->hdr.ext_addr_v4); l_info->hdr.ext_port = a_port; const char l_channels[] = {dap_stream_ch_chain_net_srv_get_id(), '\0'}; l_ret->node_client = dap_chain_node_client_create_n_connect(a_net, l_info, l_channels, &l_callbacks, l_ret); l_ret->node_client->notify_callbacks.srv_pkt_in = (dap_stream_ch_callback_packet_t)s_srv_client_pkt_in; DAP_DELETE(l_info); return l_ret; } ssize_t dap_chain_net_srv_client_write(dap_chain_net_srv_client_t *a_client, uint8_t a_type, void *a_pkt_data, size_t a_pkt_data_size) { if (!a_client || !a_client->net_client || dap_client_get_stage(a_client->net_client) != STAGE_STREAM_STREAMING) return -1; if (a_type == DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_REQUEST) { dap_stream_ch_t *l_ch = dap_client_get_stream_ch_unsafe(a_client->net_client, dap_stream_ch_chain_net_srv_get_id()); dap_stream_ch_chain_net_srv_t *a_ch_chain = DAP_STREAM_CH_CHAIN_NET_SRV(l_ch); dap_stream_ch_chain_net_srv_pkt_request_t *l_request = (dap_stream_ch_chain_net_srv_pkt_request_t *)a_pkt_data; a_ch_chain->srv_uid.uint64 = l_request->hdr.srv_uid.uint64; } dap_stream_worker_t *l_stream_worker = dap_client_get_stream_worker(a_client->net_client); return dap_stream_ch_pkt_write_mt(l_stream_worker, a_client->ch_uuid, a_type, a_pkt_data, a_pkt_data_size); } static void s_srv_client_callback_connected(dap_chain_node_client_t *a_node_client, void *a_arg) { log_it(L_INFO, "Service client connected well"); dap_chain_net_srv_client_t *l_srv_client = (dap_chain_net_srv_client_t *)a_arg; l_srv_client->ch_uuid = a_node_client->ch_chain_net_srv_uuid; l_srv_client->net_client = a_node_client->client; if (l_srv_client->callbacks.connected) l_srv_client->callbacks.connected(l_srv_client, l_srv_client->callbacks_arg); } static void s_srv_client_callback_disconnected(dap_chain_node_client_t *a_node_client, void *a_arg) { UNUSED(a_node_client); log_it(L_INFO, "Service client disconnected"); dap_chain_net_srv_client_t *l_srv_client = (dap_chain_net_srv_client_t *)a_arg; if (l_srv_client->callbacks.disconnected) l_srv_client->callbacks.disconnected(l_srv_client, l_srv_client->callbacks_arg); } static void s_srv_client_callback_deleted(dap_chain_node_client_t *a_node_client, void *a_arg) { UNUSED(a_node_client); log_it(L_INFO, "Service client deleted"); dap_chain_net_srv_client_t *l_srv_client = (dap_chain_net_srv_client_t *)a_arg; if (l_srv_client->callbacks.deleted) l_srv_client->callbacks.deleted(l_srv_client, l_srv_client->callbacks_arg); DAP_DELETE(l_srv_client); } static void s_srv_client_pkt_in(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_net_srv_client_t *l_srv_client = (dap_chain_net_srv_client_t *)a_arg; switch (a_pkt_type) { case DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_CHECK_RESPONSE: { dap_stream_ch_chain_net_srv_pkt_test_t *l_response = (dap_stream_ch_chain_net_srv_pkt_test_t *)a_pkt->data; size_t l_response_size = l_response->data_size + sizeof(dap_stream_ch_chain_net_srv_pkt_test_t); if (a_pkt->hdr.data_size != l_response_size) { log_it(L_WARNING, "Wrong response size %u, required %zu", a_pkt->hdr.data_size, l_response_size); if (l_srv_client->callbacks.error) l_srv_client->callbacks.error(l_srv_client, DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_RESPONSE_ERROR_CODE_WRONG_SIZE, l_srv_client->callbacks_arg); break; } l_response->recv_time1 = dap_nanotime_now(); dap_chain_hash_fast_t l_data_hash; dap_hash_fast(l_response->data, l_response->data_size, &l_data_hash); if (!dap_hash_fast_compare(&l_data_hash, &l_response->data_hash)) { if (l_srv_client->callbacks.error) l_srv_client->callbacks.error(l_srv_client, DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_RESPONSE_ERROR_CODE_WRONG_HASH, l_srv_client->callbacks_arg); break; } if (l_srv_client->callbacks.check) l_srv_client->callbacks.check(l_srv_client, l_response, l_srv_client->callbacks_arg); } break; case DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_SIGN_REQUEST: { log_it(L_NOTICE, "Requested receipt to sign"); dap_chain_datum_tx_receipt_t *l_receipt = (dap_chain_datum_tx_receipt_t *)a_pkt->data; if (a_pkt->hdr.data_size != l_receipt->size) { log_it(L_WARNING, "Wrong response size %u, required %"DAP_UINT64_FORMAT_U, a_pkt->hdr.data_size, l_receipt->size); if (l_srv_client->callbacks.error) l_srv_client->callbacks.error(l_srv_client, DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_RESPONSE_ERROR_CODE_WRONG_SIZE, l_srv_client->callbacks_arg); break; } if (l_srv_client->callbacks.sign) { // Duplicate receipt for realloc can be applied dap_chain_datum_tx_receipt_t *l_rec_cpy = DAP_DUP_SIZE(l_receipt, l_receipt->size); // Sign receipt l_rec_cpy = l_srv_client->callbacks.sign(l_srv_client, l_rec_cpy, l_srv_client->callbacks_arg); if (l_rec_cpy) { dap_stream_ch_pkt_write_unsafe(a_ch_chain->ch, DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_SIGN_RESPONSE, l_rec_cpy, l_rec_cpy->size); DAP_DELETE(l_rec_cpy); } else { log_it(L_ERROR, "Problem with receipt signing, callback.sign returned NULL"); } } } break; case DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_RESPONSE_SUCCESS: { log_it( L_NOTICE, "Responsed with success"); dap_stream_ch_chain_net_srv_pkt_success_t *l_success = (dap_stream_ch_chain_net_srv_pkt_success_t *)a_pkt->data; size_t l_success_size = a_pkt->hdr.data_size; if (l_srv_client->callbacks.success) { l_srv_client->callbacks.success(l_srv_client, l_success, l_success_size, l_srv_client->callbacks_arg); } } break; case DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_RESPONSE_ERROR: { if (a_pkt->hdr.data_size == sizeof (dap_stream_ch_chain_net_srv_pkt_error_t)) { dap_stream_ch_chain_net_srv_pkt_error_t *l_err = (dap_stream_ch_chain_net_srv_pkt_error_t *)a_pkt->data; log_it(L_WARNING, "Remote responsed with error code 0x%08X", l_err->code); if (l_srv_client->callbacks.error) l_srv_client->callbacks.error(l_srv_client, l_err->code, l_srv_client->callbacks_arg); } else { log_it(L_ERROR, "Wrong error response size, %u when expected %zu", a_pkt->hdr.data_size, sizeof ( dap_stream_ch_chain_net_srv_pkt_error_t) ); } } break; case DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_RESPONSE_DATA: { dap_stream_ch_chain_net_srv_pkt_data_t *l_response = (dap_stream_ch_chain_net_srv_pkt_data_t *)a_pkt->data; log_it(L_DEBUG, "Service client got custom data response"); if (l_srv_client->callbacks.data) l_srv_client->callbacks.data(l_srv_client, l_response->data, l_response->hdr.data_size, l_srv_client->callbacks_arg); } default: break; } }