diff --git a/modules/chain/dap_chain_ch.c b/modules/chain/dap_chain_ch.c index 236806288defa1f0c6aa353b3b6ef391f220c384..0c6111846fcfd374326fb084cd1c113e25f941a7 100644 --- a/modules/chain/dap_chain_ch.c +++ b/modules/chain/dap_chain_ch.c @@ -276,6 +276,8 @@ struct legacy_sync_context *s_legacy_sync_context_create(dap_stream_ch_t *a_ch) .state = DAP_CHAIN_CH_STATE_IDLE, .last_activity = dap_time_now() }; + + dap_stream_ch_uuid_t *l_uuid = DAP_DUP(&a_ch->uuid); if (!l_uuid) { log_it(L_CRITICAL, "%s", c_error_memory_alloc); @@ -1065,8 +1067,6 @@ static bool s_stream_ch_packet_in(dap_stream_ch_t* a_ch, void* a_arg) } l_context->is_type_of_gdb = true; l_context->db_list = l_db_list; - l_context->remote_addr = *(dap_stream_node_addr_t *)l_chain_pkt->data; - l_context->request_hdr = l_chain_pkt->hdr; l_ch_chain->legacy_sync_context = l_context; l_context->state = DAP_CHAIN_CH_STATE_UPDATE_GLOBAL_DB; debug_if(s_debug_legacy, L_DEBUG, "Sync out gdb proc, requested %" DAP_UINT64_FORMAT_U " records from address " NODE_ADDR_FP_STR " (unverified)", 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 aad8bcf09d66040efccf7d5f17d80831dbe4cc40..200158c7a4f00a9c61ba07bc61e5537c465b8589 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 @@ -75,8 +75,15 @@ typedef struct client_statistic_value{ } grace; } client_statistic_value_t; +typedef struct receipt_sign_waiting_args { + dap_stream_worker_t *worker; + dap_stream_ch_uuid_t uuid; + dap_chain_net_srv_usage_t *usage; +} receipt_sign_waiting_args_t; + 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); +static void s_start_receipt_timeout_timer(dap_chain_net_srv_usage_t *a_usage); static bool s_stream_ch_packet_in(dap_stream_ch_t* ch , void* arg); static bool s_stream_ch_packet_out(dap_stream_ch_t* ch , void* arg); @@ -236,6 +243,35 @@ static bool s_unban_client(dap_chain_net_srv_banlist_item_t *a_item) return false; } +static bool s_receipt_timeout_handler(dap_chain_net_srv_usage_t *a_usage) +{ + log_it(L_WARNING, "Waiting receipt signing from client timeout!"); + if (a_usage->receipt_sign_req_cnt < RECEIPT_SIGN_MAX_ATTEMPT - 1){ + // New attempt + a_usage->receipt_sign_req_cnt++; + log_it(L_WARNING, "Try to send receipt again. Attempt %d", a_usage->receipt_sign_req_cnt+1); + if (a_usage->is_waiting_first_receipt_sign ){ + dap_stream_ch_pkt_write_unsafe(a_usage->client->ch, DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_SIGN_REQUEST, + a_usage->receipt, a_usage->receipt->size); + return true; + } else if (a_usage->is_waiting_next_receipt_sign ){ + dap_stream_ch_pkt_write_unsafe(a_usage->client->ch, DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_SIGN_REQUEST, + a_usage->receipt_next, a_usage->receipt_next->size); + return true; + } + } + log_it(L_WARNING, "Receipt signing by client max attempt is reached!"); + a_usage->receipt_sign_req_cnt = 0; + a_usage->is_waiting_first_receipt_sign = false; + a_usage->is_waiting_next_receipt_sign = false; + return false; +} + +static void s_start_receipt_timeout_timer(dap_chain_net_srv_usage_t *a_usage) +{ + a_usage->receipts_timeout_timer = dap_timerfd_start_on_worker(dap_worker_get_current(), 10000, + (dap_timerfd_callback_t)s_receipt_timeout_handler, a_usage); +} /** * @brief create string with usage service statistic * @return string with staticstic @@ -324,6 +360,10 @@ static bool s_service_start(dap_stream_ch_t *a_ch , dap_stream_ch_chain_net_srv_ l_err.net_id.uint64 = a_request->hdr.net_id.uint64; l_err.srv_uid.uint64 = a_request->hdr.srv_uid.uint64; + char *l_user_key = dap_chain_hash_fast_to_str_new(&a_request->hdr.client_pkey_hash); + log_it(L_DEBUG, "Got service request from user %s", l_user_key); + DAP_DELETE(l_user_key); + if (dap_hash_fast_is_blank(&a_request->hdr.order_hash)){ log_it( L_ERROR, "No order hash in request."); l_err.code = DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_RESPONSE_ERROR_CODE_PRICE_NOT_FOUND; @@ -334,6 +374,16 @@ static bool s_service_start(dap_stream_ch_t *a_ch , dap_stream_ch_chain_net_srv_ return false; } + if (dap_hash_fast_is_blank(&a_request->hdr.tx_cond)){ + log_it( L_ERROR, "No transaction hash in request."); + l_err.code = DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_RESPONSE_ERROR_CODE_PRICE_NOT_FOUND; + if(a_ch) + dap_stream_ch_pkt_write_unsafe(a_ch, DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_RESPONSE_ERROR, &l_err, sizeof (l_err)); + if (l_srv && l_srv->callbacks.response_error) + l_srv->callbacks.response_error(l_srv, 0, NULL, &l_err, sizeof(l_err)); + return false; + } + char l_order_hash_str[DAP_CHAIN_HASH_FAST_STR_SIZE] = {}; dap_chain_hash_fast_to_str(&a_request->hdr.order_hash, l_order_hash_str, DAP_CHAIN_HASH_FAST_STR_SIZE); log_it(L_MSG, "Got order with hash %s.", l_order_hash_str); @@ -400,6 +450,7 @@ static bool s_service_start(dap_stream_ch_t *a_ch , dap_stream_ch_chain_net_srv_ l_usage->net = l_net; l_usage->service = l_srv; l_usage->client_pkey_hash = a_request->hdr.client_pkey_hash; + l_usage->receipt_timeout_timer_start_callback = s_start_receipt_timeout_timer; dap_chain_net_srv_price_t * l_price = NULL; bool l_specific_order_free = false; @@ -541,9 +592,11 @@ static bool s_grace_period_start(dap_chain_net_srv_grace_t *a_grace) HASH_FIND(hh, a_grace->usage->service->ban_list, &a_grace->usage->client_pkey_hash, sizeof(dap_chain_hash_fast_t), l_item); pthread_mutex_unlock(&a_grace->usage->service->banlist_mutex); if (l_item) { // client banned - log_it(L_INFO, "Client pkey is banned!"); + char *l_user_key = dap_chain_hash_fast_to_str_new(&a_grace->usage->client_pkey_hash); + log_it(L_DEBUG, "Client %s is banned!", l_user_key); + DAP_DELETE(l_user_key); l_err.code = DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_RESPONSE_ERROR_CODE_RECEIPT_BANNED_PKEY_HASH ; - s_grace_error(a_grace, l_err);; + s_grace_error(a_grace, l_err); return false; } } @@ -552,7 +605,8 @@ static bool s_grace_period_start(dap_chain_net_srv_grace_t *a_grace) if (a_grace->usage->receipt){ // If it is repeated grace char *l_order_hash_str = dap_chain_hash_fast_to_str_new(&a_grace->usage->static_order_hash); - log_it(L_MSG, "Using price from order %s.", l_order_hash_str); + char *l_user_key = dap_chain_hash_fast_to_str_new(&a_grace->usage->client_pkey_hash); + log_it(L_MSG, "Using price from order %s for user %s.", l_order_hash_str, l_user_key); DAP_DELETE(l_order_hash_str); l_price = a_grace->usage->price; @@ -566,6 +620,7 @@ static bool s_grace_period_start(dap_chain_net_srv_grace_t *a_grace) if (!l_item) { log_it(L_CRITICAL, "%s", c_error_memory_alloc); s_grace_error(a_grace, l_err); + DAP_DELETE(l_user_key); return false; } l_item->grace = a_grace; @@ -576,7 +631,8 @@ static bool s_grace_period_start(dap_chain_net_srv_grace_t *a_grace) pthread_mutex_unlock(&a_grace->usage->service->grace_mutex); a_grace->timer = dap_timerfd_start_on_worker(a_grace->stream_worker->worker, a_grace->usage->service->grace_period * 1000, (dap_timerfd_callback_t)s_grace_period_finish, l_item); - log_it(L_INFO, "Start grace timer %s.", a_grace->timer ? "successfuly." : "failed." ); + log_it(L_INFO, "Start grace timer %s for user %s.", a_grace->timer ? "successfuly." : "failed.", l_user_key); + DAP_DELETE(l_user_key); } else { // Else if first grace at service start dap_chain_net_srv_grace_usage_t *l_item = DAP_NEW_Z(dap_chain_net_srv_grace_usage_t); if (!l_item) { @@ -607,8 +663,9 @@ static bool s_grace_period_start(dap_chain_net_srv_grace_t *a_grace) char l_hash_str[DAP_CHAIN_HASH_FAST_STR_SIZE] = { '\0' }; dap_hash_fast_to_str(&a_grace->usage->tx_cond_hash, l_hash_str, sizeof(l_hash_str)); - log_it(L_NOTICE, "Transaction %s can't be found. Start the grace period for %d seconds", l_hash_str, - a_grace->usage->service->grace_period); + char *l_user_key = dap_chain_hash_fast_to_str_new(&a_grace->usage->client_pkey_hash); + log_it(L_NOTICE, "Transaction %s can't be found. Start the grace period for %d seconds for user %s", l_hash_str, + a_grace->usage->service->grace_period, l_user_key); if (a_grace->usage->service->callbacks.response_success) a_grace->usage->service->callbacks.response_success(a_grace->usage->service, a_grace->usage->id, @@ -619,7 +676,8 @@ static bool s_grace_period_start(dap_chain_net_srv_grace_t *a_grace) pthread_mutex_unlock(&a_grace->usage->service->grace_mutex); a_grace->timer = dap_timerfd_start_on_worker(a_grace->stream_worker->worker, a_grace->usage->service->grace_period * 1000, (dap_timerfd_callback_t)s_grace_period_finish, l_item); - log_it(L_INFO, "Start grace timer %s.", a_grace->timer ? "successfuly." : "failed." ); + log_it(L_INFO, "Start grace timer %s for user %s.", a_grace->timer ? "successfuly." : "failed.", l_user_key ); + DAP_DELETE(l_user_key); } } @@ -741,9 +799,11 @@ static bool s_grace_period_start(dap_chain_net_srv_grace_t *a_grace) l_srv_session->limits_bytes = l_remain_service->limits_bytes; break; } - - log_it(L_INFO, "User has %ld %s remain service. Start service without paying.", l_remain_service->limits_ts ? l_remain_service->limits_ts : l_remain_service->limits_bytes, dap_chain_srv_unit_enum_to_str(l_tx_out_cond->subtype.srv_pay.unit.enm)); - + char *l_user_key = dap_chain_hash_fast_to_str_new(&a_grace->usage->client_pkey_hash); + log_it(L_INFO, "User %s has %ld %s remain service. Start service without paying.", l_user_key, + l_remain_service->limits_ts ? l_remain_service->limits_ts : l_remain_service->limits_bytes, + dap_chain_srv_unit_enum_to_str(l_tx_out_cond->subtype.srv_pay.unit.enm)); + DAP_DELETE(l_user_key); size_t l_success_size = sizeof (dap_stream_ch_chain_net_srv_pkt_success_hdr_t ); dap_stream_ch_chain_net_srv_pkt_success_t *l_success = DAP_NEW_Z_SIZE(dap_stream_ch_chain_net_srv_pkt_success_t, l_success_size); @@ -763,7 +823,6 @@ static bool s_grace_period_start(dap_chain_net_srv_grace_t *a_grace) // create and fill first receipt a_grace->usage->receipt = dap_chain_datum_tx_receipt_create( a_grace->usage->service->uid, l_price->units_uid, l_price->units, l_price->value_datoshi, NULL, 0); - if (a_grace->usage->service->callbacks.response_success) a_grace->usage->service->callbacks.response_success(a_grace->usage->service, a_grace->usage->id, a_grace->usage->client, a_grace->usage->receipt, @@ -777,13 +836,19 @@ static bool s_grace_period_start(dap_chain_net_srv_grace_t *a_grace) } } - if (a_grace->usage->receipt_next){ + if (a_grace->usage->receipt_next && !a_grace->usage->is_waiting_first_receipt_sign){ DAP_DEL_Z(a_grace->usage->receipt_next); a_grace->usage->receipt_next = dap_chain_net_srv_issue_receipt(a_grace->usage->service, a_grace->usage->price, NULL, 0); + a_grace->usage->is_waiting_next_receipt_sign = true; + //start timeout timer + a_grace->usage->receipt_timeout_timer_start_callback(a_grace->usage); }else{ a_grace->usage->receipt = dap_chain_net_srv_issue_receipt(a_grace->usage->service, a_grace->usage->price, NULL, 0); dap_stream_ch_pkt_write_unsafe(l_ch, DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_SIGN_REQUEST, a_grace->usage->receipt, a_grace->usage->receipt->size); + a_grace->usage->is_waiting_first_receipt_sign = true; + //start timeout timer + a_grace->usage->receipt_timeout_timer_start_callback(a_grace->usage); } DAP_DELETE(a_grace->request); DAP_DELETE(a_grace); @@ -880,8 +945,8 @@ static bool s_grace_period_finish(dap_chain_net_srv_grace_usage_t *a_grace_item) if (error) { \ l_err.code = error ; \ s_grace_error(l_grace, l_err); \ - } \ - DAP_DELETE(l_grace); \ + } else\ + DAP_DELETE(l_grace); \ DAP_DELETE(a_grace_item); \ return false; \ } \ @@ -1022,8 +1087,11 @@ static bool s_grace_period_finish(dap_chain_net_srv_grace_usage_t *a_grace_item) l_srv_session->limits_bytes = l_remain_service->limits_bytes; break; } - log_it(L_INFO, "User has %ld %s remain service. Start service without paying.", l_remain_service->limits_ts ? l_remain_service->limits_ts : l_remain_service->limits_bytes, dap_chain_srv_unit_enum_to_str(l_tx_out_cond->subtype.srv_pay.unit.enm)); - + char *l_user_key = dap_chain_hash_fast_to_str_new(&l_grace->usage->client_pkey_hash); + log_it(L_INFO, "User %s has %ld %s remain service. Start service without paying.", l_user_key, + l_remain_service->limits_ts ? l_remain_service->limits_ts : l_remain_service->limits_bytes, + dap_chain_srv_unit_enum_to_str(l_tx_out_cond->subtype.srv_pay.unit.enm)); + DAP_DELETE(l_user_key); size_t l_success_size = sizeof (dap_stream_ch_chain_net_srv_pkt_success_hdr_t ); dap_stream_ch_chain_net_srv_pkt_success_t *l_success = DAP_NEW_Z_SIZE(dap_stream_ch_chain_net_srv_pkt_success_t, l_success_size); @@ -1043,7 +1111,7 @@ static bool s_grace_period_finish(dap_chain_net_srv_grace_usage_t *a_grace_item) // create and fill limits and first receipt l_grace->usage->receipt = dap_chain_datum_tx_receipt_create( l_grace->usage->service->uid, l_price->units_uid, l_price->units, l_price->value_datoshi, NULL, 0); - + // l_grace->usage->is_waiting_first_receipt_sign = true; if (l_grace->usage->service->callbacks.response_success) l_grace->usage->service->callbacks.response_success(l_grace->usage->service, l_grace->usage->id, l_grace->usage->client, l_grace->usage->receipt, @@ -1065,6 +1133,9 @@ static bool s_grace_period_finish(dap_chain_net_srv_grace_usage_t *a_grace_item) } else { log_it(L_INFO, "Send first receipt to sign"); l_grace->usage->receipt = dap_chain_net_srv_issue_receipt(l_grace->usage->service, l_grace->usage->price, NULL, 0); + l_grace->usage->is_waiting_first_receipt_sign = true; + // start timeout timer + l_grace->usage->receipt_timeout_timer_start_callback(l_grace->usage); if (l_grace->usage->receipt ) dap_stream_ch_pkt_write_unsafe(l_ch, DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_SIGN_REQUEST, l_grace->usage->receipt, l_grace->usage->receipt->size); @@ -1255,6 +1326,16 @@ static bool s_stream_ch_packet_in(dap_stream_ch_t *a_ch, void *a_arg) case DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_SIGN_RESPONSE: { // Check receipt sign and make tx if success dap_chain_net_srv_usage_t * l_usage = l_srv_session->usage_active; + if (!l_usage->is_waiting_first_receipt_sign && !l_usage->is_waiting_next_receipt_sign){ + break; + } + + if (l_usage->receipts_timeout_timer){ + log_it(L_INFO, "Delete receipt timeout timer."); + dap_timerfd_delete_unsafe(l_usage->receipts_timeout_timer); + l_usage->receipts_timeout_timer = NULL; + } + if (dap_chain_net_get_state(l_usage->net) == NET_STATE_OFFLINE) { log_it(L_ERROR, "Can't pay service because net %s is offline.", l_usage->net->pub.name); l_err.code = DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_RESPONSE_ERROR_CODE_NETWORK_IS_OFFLINE; @@ -1264,7 +1345,7 @@ static bool s_stream_ch_packet_in(dap_stream_ch_t *a_ch, void *a_arg) if (l_ch_pkt->hdr.data_size < sizeof(dap_chain_receipt_info_t)) { log_it(L_ERROR, "Wrong sign response size, %u when expected at least %zu with smth", l_ch_pkt->hdr.data_size, sizeof(dap_chain_receipt_info_t)); - if ( l_usage->receipt_next ){ // If we have receipt next + if ( l_usage->receipt_next && !l_usage->is_waiting_first_receipt_sign && l_usage->is_waiting_next_receipt_sign){ // If we have receipt next DAP_DEL_Z(l_usage->receipt_next); }else if (l_usage->receipt ){ // If we sign first receipt DAP_DEL_Z(l_usage->receipt); @@ -1274,20 +1355,16 @@ static bool s_stream_ch_packet_in(dap_stream_ch_t *a_ch, void *a_arg) dap_chain_datum_tx_receipt_t * l_receipt = (dap_chain_datum_tx_receipt_t *) l_ch_pkt->data; size_t l_receipt_size = l_ch_pkt->hdr.data_size; - if (l_usage->is_grace && l_usage->receipt && !l_usage->receipt_next) - l_usage->is_grace = false; - bool l_is_found = false; - if ( l_usage->receipt_next ){ // If we have receipt next + if ( l_usage->receipt_next && !l_usage->is_waiting_first_receipt_sign && l_usage->is_waiting_next_receipt_sign){ // If we have receipt next if ( memcmp(&l_usage->receipt_next->receipt_info, &l_receipt->receipt_info,sizeof (l_receipt->receipt_info) )==0 ){ l_is_found = true; } - }else if (l_usage->receipt ){ // If we sign first receipt + }else if (l_usage->receipt){ // If we sign first receipt if ( memcmp(&l_usage->receipt->receipt_info, &l_receipt->receipt_info,sizeof (l_receipt->receipt_info) )==0 ){ l_is_found = true; } } - if ( !l_is_found || ! l_usage ){ log_it(L_WARNING, "Can't find receipt in usages thats equal to response receipt"); l_err.code = DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_RESPONSE_ERROR_CODE_RECEIPT_CANT_FIND; @@ -1301,25 +1378,22 @@ static bool s_stream_ch_packet_in(dap_stream_ch_t *a_ch, void *a_arg) l_err.srv_uid.uint64 = l_usage->service->uid.uint64; dap_chain_tx_out_cond_t *l_tx_out_cond = NULL; - if (!l_usage->is_grace) { - if (! l_usage->tx_cond ){ - log_it(L_WARNING, "No tx out in usage"); - l_err.code = DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_RESPONSE_ERROR_CODE_TX_COND_NOT_FOUND ; - dap_stream_ch_pkt_write_unsafe( a_ch, DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_RESPONSE_ERROR, &l_err, sizeof (l_err) ); - if (l_usage->service->callbacks.response_error) - l_usage->service->callbacks.response_error( l_usage->service, l_usage->id, l_usage->client, - &l_err, sizeof (l_err) ); - break; - } - l_tx_out_cond = dap_chain_datum_tx_out_cond_get(l_usage->tx_cond, DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_PAY, NULL ); - if ( ! l_tx_out_cond ){ // No conditioned output - l_err.code = DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_RESPONSE_ERROR_CODE_TX_COND_NO_COND_OUT ; - dap_stream_ch_pkt_write_unsafe( a_ch, DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_RESPONSE_ERROR, &l_err, sizeof (l_err) ); - if (l_usage->service->callbacks.response_error) - l_usage->service->callbacks.response_error( l_usage->service, l_usage->id, l_usage->client,&l_err,sizeof (l_err) ); - break; - } - + if (! l_usage->tx_cond ){ + log_it(L_WARNING, "No tx out in usage"); + l_err.code = DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_RESPONSE_ERROR_CODE_TX_COND_NOT_FOUND ; + dap_stream_ch_pkt_write_unsafe( a_ch, DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_RESPONSE_ERROR, &l_err, sizeof (l_err) ); + if (l_usage->service->callbacks.response_error) + l_usage->service->callbacks.response_error( l_usage->service, l_usage->id, l_usage->client, + &l_err, sizeof (l_err) ); + break; + } + l_tx_out_cond = dap_chain_datum_tx_out_cond_get(l_usage->tx_cond, DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_PAY, NULL ); + if ( ! l_tx_out_cond ){ // No condition output + l_err.code = DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_RESPONSE_ERROR_CODE_TX_COND_NO_COND_OUT ; + dap_stream_ch_pkt_write_unsafe( a_ch, DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_RESPONSE_ERROR, &l_err, sizeof (l_err) ); + if (l_usage->service->callbacks.response_error) + l_usage->service->callbacks.response_error( l_usage->service, l_usage->id, l_usage->client,&l_err,sizeof (l_err) ); + break; } // get a second signature - from the client (first sign in server, second sign in client) dap_sign_t * l_receipt_sign = dap_chain_datum_tx_receipt_sign_get( l_receipt, l_receipt_size, 1); @@ -1343,7 +1417,7 @@ static bool s_stream_ch_packet_in(dap_stream_ch_t *a_ch, void *a_arg) // Update actual receipt bool l_is_first_sign = false; - if (!l_usage->receipt_next && l_usage->receipt) { + if (l_usage->receipt && (!l_usage->receipt_next || l_usage->is_waiting_first_receipt_sign)) { DAP_DELETE(l_usage->receipt); l_usage->receipt = DAP_DUP_SIZE(l_receipt, l_receipt_size); if (!l_usage->receipt) { @@ -1351,7 +1425,7 @@ static bool s_stream_ch_packet_in(dap_stream_ch_t *a_ch, void *a_arg) break; } l_is_first_sign = true; - l_usage->is_active = true; + // l_usage->is_active = true; } else if (l_usage->receipt_next) { DAP_DELETE(l_usage->receipt_next); l_usage->receipt_next = DAP_DUP_SIZE(l_receipt, l_receipt_size); @@ -1359,7 +1433,16 @@ static bool s_stream_ch_packet_in(dap_stream_ch_t *a_ch, void *a_arg) log_it(L_CRITICAL, "%s", c_error_memory_alloc); break; } - l_usage->is_active = true; + // l_usage->is_active = true; + } + + if (!l_usage->is_waiting_first_receipt_sign && l_usage->is_waiting_next_receipt_sign){ + l_usage->is_waiting_next_receipt_sign = false; + } + + if (l_usage->is_grace && l_usage->is_waiting_first_receipt_sign){ + l_usage->is_waiting_first_receipt_sign = false; + l_usage->is_grace = false; } // Store receipt if any problems with transactions @@ -1370,8 +1453,10 @@ static bool s_stream_ch_packet_in(dap_stream_ch_t *a_ch, void *a_arg) if (!l_usage->is_grace) { // Form input transaction char *l_hash_str = dap_hash_fast_to_str_new(&l_usage->tx_cond_hash); - log_it(L_NOTICE, "Trying create input tx cond from tx %s with active receipt", l_hash_str); + char *l_user_key = dap_chain_hash_fast_to_str_new(&l_usage->client_pkey_hash); + log_it(L_NOTICE, "Trying create input tx cond from tx %s with active receipt for user %s", l_hash_str, l_user_key); DAP_DEL_Z(l_hash_str); + DAP_DEL_Z(l_user_key); int ret_status = 0; char *l_tx_in_hash_str = dap_chain_mempool_tx_create_cond_input(l_usage->net, &l_usage->tx_cond_hash, l_usage->price->wallet_addr, l_usage->price->receipt_sign_cert->enc_key, @@ -1481,12 +1566,16 @@ static bool s_stream_ch_packet_in(dap_stream_ch_t *a_ch, void *a_arg) if (l_usage->is_grace) { char l_hash_str[DAP_CHAIN_HASH_FAST_STR_SIZE] = { '\0' }; dap_hash_fast_to_str(&l_usage->tx_cond_hash, l_hash_str, sizeof(l_hash_str)); - log_it(L_NOTICE, "Receipt is OK, but tx transaction %s %s. Start the grace period for %d seconds", l_hash_str, + char *l_user_key = dap_chain_hash_fast_to_str_new(&l_usage->client_pkey_hash); + log_it(L_NOTICE, "Receipt is OK, but tx transaction %s %s. Start the grace period for %d seconds for user %s", l_hash_str, l_usage->is_waiting_new_tx_cond ? "have no enough funds. New tx cond requested": "can't be found", - l_srv->grace_period); + l_srv->grace_period, l_user_key); + DAP_DELETE(l_user_key); } else { dap_hash_fast_to_str(&l_usage->tx_cond_hash, (char*)l_success->custom_data, DAP_CHAIN_HASH_FAST_STR_SIZE); - log_it(L_NOTICE, "Receipt with client sign is accepted, start service providing"); + char *l_user_key = dap_chain_hash_fast_to_str_new(&l_usage->client_pkey_hash); + log_it(L_NOTICE, "Receipt with client %s sign is accepted, start service providing", l_user_key); + DAP_DELETE(l_user_key); } dap_stream_ch_pkt_write_unsafe( a_ch, DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_RESPONSE_SUCCESS, @@ -1606,6 +1695,7 @@ static bool s_stream_ch_packet_in(dap_stream_ch_t *a_ch, void *a_arg) } }else{ if (l_curr_grace_item){ + log_it(L_INFO, "Can't find tx in ledger. Waiting..."); l_curr_grace_item->grace->usage->tx_cond_hash = l_responce->hdr.tx_cond; l_curr_grace_item->grace->request->hdr.tx_cond = l_responce->hdr.tx_cond; pthread_mutex_lock(&l_srv->grace_mutex); @@ -1630,7 +1720,6 @@ static bool s_stream_ch_packet_in(dap_stream_ch_t *a_ch, void *a_arg) dap_stream_ch_pkt_write_unsafe(a_ch, DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_RESPONSE_SUCCESS, l_success, l_success_size); DAP_DELETE(l_success); } break; - default: log_it( L_WARNING, "Unknown packet type 0x%02X", l_ch_pkt->hdr.type); return false; diff --git a/modules/channel/chain-net-srv/include/dap_stream_ch_chain_net_srv_pkt.h b/modules/channel/chain-net-srv/include/dap_stream_ch_chain_net_srv_pkt.h index 3bca41c7ed362b4ebda3893e9fa3c31f0748cfff..057a08d520c45974dae3d365d4fde2cd45ba3a92 100644 --- a/modules/channel/chain-net-srv/include/dap_stream_ch_chain_net_srv_pkt.h +++ b/modules/channel/chain-net-srv/include/dap_stream_ch_chain_net_srv_pkt.h @@ -142,7 +142,6 @@ typedef struct dap_stream_ch_chain_net_srv_pkt_test { uint8_t data[]; } DAP_ALIGN_PACKED dap_stream_ch_chain_net_srv_pkt_test_t; - size_t dap_stream_ch_chain_net_srv_pkt_data_write(dap_stream_ch_t *a_ch, dap_chain_net_srv_uid_t a_srv_uid, uint32_t a_usage_id , const void * a_data, size_t a_data_size); diff --git a/modules/common/dap_chain_datum_tx_receipt.c b/modules/common/dap_chain_datum_tx_receipt.c index c21099f921225284537647f54974dc7b602e3f35..b4e4c836c4632987d4243461d94b071ebd510673 100644 --- a/modules/common/dap_chain_datum_tx_receipt.c +++ b/modules/common/dap_chain_datum_tx_receipt.c @@ -59,6 +59,7 @@ dap_chain_datum_tx_receipt_t * dap_chain_datum_tx_receipt_create( dap_chain_net_ l_ret->exts_size = a_ext_size; memcpy(l_ret->exts_n_signs, a_ext, a_ext_size); } + return l_ret; } @@ -68,6 +69,7 @@ dap_chain_datum_tx_receipt_t *dap_chain_datum_tx_receipt_sign_add(dap_chain_datu log_it(L_ERROR, "NULL receipt, can't add sign"); return NULL; } + dap_sign_t *l_sign = dap_sign_create(a_key, &a_receipt->receipt_info, sizeof(a_receipt->receipt_info), 0); size_t l_sign_size = l_sign ? dap_sign_get_size(l_sign) : 0; if (!l_sign || !l_sign_size) { @@ -84,6 +86,7 @@ dap_chain_datum_tx_receipt_t *dap_chain_datum_tx_receipt_sign_add(dap_chain_datu memcpy((byte_t *)l_receipt + l_receipt->size, l_sign, l_sign_size); l_receipt->size += l_sign_size; DAP_DELETE(l_sign); + return l_receipt; } diff --git a/modules/mempool/dap_chain_mempool.c b/modules/mempool/dap_chain_mempool.c index d559a8eceb40df4dd6dd41fec09c8d2e581b2192..b2980610c5cd2286628bfebcd70f9232bc3a8b33 100644 --- a/modules/mempool/dap_chain_mempool.c +++ b/modules/mempool/dap_chain_mempool.c @@ -938,6 +938,9 @@ char *dap_chain_mempool_tx_create_cond(dap_chain_net_t *a_net, uint256_t l_value_transfer = {}; // how many coins to transfer uint256_t l_value_need = {}; SUM_256_256(a_value, a_value_fee, &l_value_need); + if (l_net_fee_used) { + SUM_256_256(l_value_need, l_net_fee, &l_value_need); + } // where to take coins for service dap_chain_addr_t l_addr_from; dap_chain_addr_fill_from_key(&l_addr_from, a_key_from, a_net->pub.id); diff --git a/modules/net/dap_chain_ledger.c b/modules/net/dap_chain_ledger.c index 1aa8a000bb6e363fb007b9ee9ce98dd911178592..48250421cce50d999ac3f2b5a71bfee49be77d44 100644 --- a/modules/net/dap_chain_ledger.c +++ b/modules/net/dap_chain_ledger.c @@ -3220,7 +3220,7 @@ dap_hash_fast_t *dap_ledger_get_final_chain_tx_hash(dap_ledger_t *a_ledger, dap_ break; // Not found in ledger } int l_out_num = 0; - if (dap_hash_fast_is_blank(&l_item->cache_data.tx_hash_spent_fast[l_out_num]) || !dap_chain_datum_tx_out_cond_get(l_item->tx, a_cond_type, &l_out_num)) + if (!dap_chain_datum_tx_out_cond_get(l_item->tx, a_cond_type, &l_out_num) || dap_hash_fast_is_blank(&l_item->cache_data.tx_hash_spent_fast[l_out_num])) break; // Unused conditional output found, that's what we need else { l_tx_hash = &l_item->cache_data.tx_hash_spent_fast[l_out_num]; diff --git a/modules/net/srv/dap_chain_net_srv.c b/modules/net/srv/dap_chain_net_srv.c index af936ef8a2993c9238854fc1b64779ac7a82c321..de8618dbd6f60b4058fd820b101b887d4dcb7c83 100644 --- a/modules/net/srv/dap_chain_net_srv.c +++ b/modules/net/srv/dap_chain_net_srv.c @@ -97,9 +97,9 @@ int dap_chain_net_srv_init() "net_srv -net <net_name> order find [-direction {sell|buy}] [-srv_uid <service_UID>] [-price_unit <price_unit>]" " [-price_token <token_ticker>] [-price_min <price_minimum>] [-price_max <price_maximum>]\n" "\tOrders list, all or by UID and/or class\n" - "net_srv -net <net_name> order delete -hash <ip_addr>\n" + "net_srv -net <net_name> order delete -hash <order_hash>\n" "\tOrder delete\n" - "net_srv -net <net_name> order dump -hash <ip_addr>\n" + "net_srv -net <net_name> order dump -hash <order_hash>\n" "\tOrder dump info\n" "net_srv -net <net_name> order create -direction {sell|buy} -srv_uid <service_UID> -price <price>\n" " -price_unit <price_unit> -price_token <token_ticker> -units <units> [-node_addr <node_address>] [-tx_cond <TX_cond_hash>]\n" @@ -314,6 +314,17 @@ static int s_cli_net_srv( int argc, char **argv, void **a_str_reply) l_order->continent = l_continent_num;*/ char *l_new_order_hash_str = dap_chain_net_srv_order_save(l_net, l_order, false); if (l_new_order_hash_str) { + const char *l_cert_str = NULL; + dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-cert", &l_cert_str); + if (!l_cert_str) { + dap_cli_server_cmd_set_reply_text(a_str_reply, "Fee order creation requires parameter -cert"); + return -7; + } + dap_cert_t *l_cert = dap_cert_find_by_name(l_cert_str); + if (!l_cert) { + dap_cli_server_cmd_set_reply_text(a_str_reply, "Can't load cert %s", l_cert_str); + return -8; + } // delete prev order if(dap_strcmp(l_new_order_hash_str, l_order_hash_hex_str)) dap_chain_net_srv_order_delete_by_hash_str_sync(l_net, l_order_hash_hex_str); @@ -558,16 +569,14 @@ static int s_cli_net_srv( int argc, char **argv, void **a_str_reply) return -20; } // create order - char *l_order_new_hash_str = dap_chain_net_srv_order_create( - l_net,l_direction, l_srv_uid, l_node_addr,l_tx_cond_hash, &l_price, l_price_unit, - l_price_token, l_expires, (uint8_t *)l_ext, l_ext_len, l_units, l_region_str, l_continent_num, l_key); - if (l_order_new_hash_str) { - dap_cli_server_cmd_set_reply_text(a_str_reply, "Created order %s\n", l_order_new_hash_str); - DAP_DELETE(l_order_new_hash_str); - return 0; - } else { - dap_cli_server_cmd_set_reply_text(a_str_reply, "Error! Can't created order\n"); - return -4; + char * l_order_new_hash_str = dap_chain_net_srv_order_create( + l_net,l_direction, l_srv_uid, l_node_addr,l_tx_cond_hash, &l_price, l_price_unit, + l_price_token, l_expires, (uint8_t *)l_ext, l_ext_len, l_units, l_region_str, l_continent_num, l_key); + if (l_order_new_hash_str) + dap_string_append_printf( l_string_ret, "Created order %s\n", l_order_new_hash_str); + else { + dap_string_append_printf( l_string_ret, "Error! Can't created order\n"); + l_ret = -4; } } else { dap_cli_server_cmd_set_reply_text(a_str_reply, "Missed some required params\n"); @@ -611,7 +620,7 @@ static int s_cli_net_srv( int argc, char **argv, void **a_str_reply) dap_stream_ch_chain_net_srv_remain_service_store_t *l_remain_service = NULL; size_t l_remain_service_size = 0; - char *l_remain_limits_gdb_group = dap_strdup_printf( "%s.0x%016"DAP_UINT64_FORMAT_x".remain_limits.%s", + char *l_remain_limits_gdb_group = dap_strdup_printf( "local.%s.0x%016"DAP_UINT64_FORMAT_x".remain_limits.%s", l_net->pub.gdb_groups_prefix, l_srv_uid.uint64, l_provider_pkey_hash_str); @@ -851,7 +860,7 @@ dap_chain_net_srv_price_t * dap_chain_net_srv_get_price_from_order(dap_chain_net dap_chain_net_srv_order_t *l_order = dap_chain_net_srv_order_find_by_hash(l_net, a_order_hash); if (!l_order){ - log_it(L_ERROR, "Memory allocation error"); + log_it(L_ERROR, "Can't find order!"); return NULL; } @@ -861,8 +870,6 @@ dap_chain_net_srv_price_t * dap_chain_net_srv_get_price_from_order(dap_chain_net DAP_DEL_Z(l_order); return NULL; } - - uint64_t l_max_price_cfg = dap_config_get_item_uint64_default(g_config, a_config_section, "max_price", 0xFFFFFFFFFFFFFFF); if (l_order->node_addr.uint64 != g_node_addr.uint64 && l_order->srv_uid.uint64 != a_srv->uid.uint64) { DAP_DELETE(l_price); @@ -872,7 +879,6 @@ dap_chain_net_srv_price_t * dap_chain_net_srv_get_price_from_order(dap_chain_net l_price->net = l_net; l_price->net_name = dap_strdup(l_net->pub.name); - uint256_t l_max_price = GET_256_FROM_64(l_max_price_cfg); // Change this value when max price wil be calculated if ((IS_ZERO_256(l_order->price) || l_order->units == 0 ) && !a_srv->allow_free_srv){ log_it(L_ERROR, "Invalid order: units count or price unspecified"); DAP_DELETE(l_price); @@ -883,19 +889,6 @@ dap_chain_net_srv_price_t * dap_chain_net_srv_get_price_from_order(dap_chain_net dap_stpcpy(l_price->token, l_order->price_ticker); l_price->units = l_order->units; l_price->units_uid = l_order->price_unit; - if (!IS_ZERO_256(l_max_price)){ - uint256_t l_price_unit = uint256_0; - DIV_256(l_price->value_datoshi, GET_256_FROM_64(l_order->units), &l_price_unit); - if (compare256(l_price_unit, l_max_price)>0){ - char *l_price_unit_str = dap_chain_balance_print(l_price_unit), *l_max_price_str = dap_chain_balance_print(l_max_price); - log_it(L_ERROR, "Unit price exeeds max permitted value: %s > %s", l_price_unit_str, l_max_price_str); - DAP_DELETE(l_price_unit_str); - DAP_DELETE(l_max_price_str); - DAP_DELETE(l_price); - DAP_DEL_Z(l_order); - return NULL; - } - } l_price->wallet_addr = dap_chain_addr_from_str(l_wallet_addr); if(!l_price->wallet_addr){ @@ -1212,7 +1205,7 @@ dap_chain_datum_tx_receipt_t * dap_chain_net_srv_issue_receipt(dap_chain_net_srv } /** - * @brief dap_chain_net_srv_issue_receipt + * @brief s_str_to_price_unit * @param a_str_price_unit * @param a_price_unit * @return 0 if OK, other if error diff --git a/modules/net/srv/dap_chain_net_srv_order.c b/modules/net/srv/dap_chain_net_srv_order.c index d020aefde084f571a8d1dff271a961440e62196b..f8d627ae2faad2cd910eec6d3fd163caa875df86 100644 --- a/modules/net/srv/dap_chain_net_srv_order.c +++ b/modules/net/srv/dap_chain_net_srv_order.c @@ -485,8 +485,6 @@ int dap_chain_net_srv_order_find_all_by(dap_chain_net_t *a_net, const dap_chain_ int dap_chain_net_srv_order_delete_by_hash_str_sync(dap_chain_net_t *a_net, const char *a_hash_str) { int l_ret = -2; - - dap_chain_net_srv_order_t *l_order = NULL; for (int i = 0; a_net && a_hash_str && i < 2; i++) { char *l_gdb_group_str = i ? dap_chain_net_srv_order_get_gdb_group(a_net) : dap_chain_net_srv_order_get_common_group(a_net); diff --git a/modules/net/srv/include/dap_chain_net_srv_order.h b/modules/net/srv/include/dap_chain_net_srv_order.h index ccdce7024a7f1b7b06e8ded12b64bd64dc158403..0898053d89a2700892c6a825dc3596455a925851 100644 --- a/modules/net/srv/include/dap_chain_net_srv_order.h +++ b/modules/net/srv/include/dap_chain_net_srv_order.h @@ -88,8 +88,7 @@ int dap_chain_net_srv_order_find_all_by( dap_list_t** a_output_orders, size_t* a_output_orders_count); -int dap_chain_net_srv_order_delete_by_hash_str_sync(dap_chain_net_t *a_net, const char *a_hash_str); - +int dap_chain_net_srv_order_delete_by_hash_str_sync( dap_chain_net_t *a_net, const char *a_hash_str); /** * @brief dap_chain_net_srv_order_delete_by_hash * @param a_net diff --git a/modules/net/srv/include/dap_chain_net_srv_stream_session.h b/modules/net/srv/include/dap_chain_net_srv_stream_session.h index 4209f0a89991317ebd2ef08106c5194fea3800e2..7df15d24bed608b3ef6a48e588417a780a008410 100644 --- a/modules/net/srv/include/dap_chain_net_srv_stream_session.h +++ b/modules/net/srv/include/dap_chain_net_srv_stream_session.h @@ -33,6 +33,8 @@ along with any CellFrame SDK based project. If not, see <http://www.gnu.org/lic #include "dap_chain_datum_tx_receipt.h" #include "dap_chain_wallet.h" + +#define RECEIPT_SIGN_MAX_ATTEMPT 3 typedef struct dap_chain_net_srv dap_chain_net_srv_t; typedef struct dap_chain_net_srv_client_remote dap_chain_net_srv_client_remote_t; typedef struct dap_chain_net_srv_price dap_chain_net_srv_price_t; @@ -53,6 +55,9 @@ typedef struct dap_chain_net_srv_usage{ dap_chain_hash_fast_t client_pkey_hash; dap_chain_hash_fast_t static_order_hash; dap_timerfd_t *save_limits_timer; + dap_timerfd_t *receipts_timeout_timer; + void (*receipt_timeout_timer_start_callback)(struct dap_chain_net_srv_usage *a_usage); + int receipt_sign_req_cnt; char token_ticker[DAP_CHAIN_TICKER_SIZE_MAX]; bool is_active; bool is_free; @@ -60,6 +65,7 @@ typedef struct dap_chain_net_srv_usage{ bool is_waiting_new_tx_cond; bool is_waiting_new_tx_cond_in_ledger; bool is_waiting_first_receipt_sign; + bool is_waiting_next_receipt_sign; bool is_limits_changed; // UT_hash_handle hh; // } dap_chain_net_srv_usage_t; diff --git a/modules/service/vpn/dap_chain_net_srv_vpn.c b/modules/service/vpn/dap_chain_net_srv_vpn.c index be273aff004cde2f5ccbbdde96354eaf390cdd1a..f62673467990f8263169456c9cd4384936fb3aaf 100644 --- a/modules/service/vpn/dap_chain_net_srv_vpn.c +++ b/modules/service/vpn/dap_chain_net_srv_vpn.c @@ -102,6 +102,10 @@ typedef struct iphdr dap_os_iphdr_t; #include "dap_chain_ledger.h" #include "dap_events.h" +#include "dap_http_simple.h" +#include "http_status_code.h" +#include "json-c/json.h" + #define LOG_TAG "dap_chain_net_srv_vpn" #define SF_MAX_EVENTS 256 @@ -206,6 +210,7 @@ static bool s_ch_packet_out(dap_stream_ch_t* ch, void* arg); static void s_ch_vpn_esocket_assigned(dap_events_socket_t* a_es, dap_worker_t * l_worker); static void s_ch_vpn_esocket_unassigned(dap_events_socket_t* a_es, dap_worker_t * l_worker); +static void s_callback_remain_limits(dap_http_simple_t *a_http_simple , void *arg); //static int srv_ch_sf_raw_write(uint8_t op_code, const void * data, size_t data_size); //static void srv_stream_sf_disconnect(ch_vpn_socket_proxy_t * sf_sock); @@ -891,20 +896,25 @@ static int s_vpn_service_create(dap_config_t * g_config) * @return 0 if everything is okay, lesser then zero if errors */ int dap_chain_net_srv_vpn_init(dap_config_t * g_config) { - s_vpn_tun_init(); + + if(s_vpn_tun_init()){ + log_it(L_CRITICAL, "Error initializing TUN device driver!"); + dap_chain_net_srv_vpn_deinit(); + return -1; + } log_it(L_DEBUG,"Initializing TUN driver..."); if(s_vpn_tun_create(g_config)){ - log_it(L_CRITICAL, "Error initializing TUN device driver!"); + log_it(L_CRITICAL, "Error creating TUN device driver!"); dap_chain_net_srv_vpn_deinit(); - return -1; + return -2; } log_it(L_INFO,"TUN driver configured successfuly"); if (s_vpn_service_create(g_config)){ log_it(L_CRITICAL, "VPN service creating failed"); dap_chain_net_srv_vpn_deinit(); - return -2; + return -3; } dap_stream_ch_proc_add(DAP_STREAM_CH_NET_SRV_ID_VPN, s_ch_vpn_new, s_ch_vpn_delete, s_ch_packet_in, s_ch_packet_out); @@ -913,6 +923,24 @@ int dap_chain_net_srv_vpn_init(dap_config_t * g_config) { dap_cli_server_cmd_add ("vpn_stat", com_vpn_statistics, "VPN statistics", "vpn_stat -net <net_name> [-full]\n" ); + + + dap_server_t *l_server_default = dap_server_get_default(); + if (!l_server_default) { + log_it(L_ERROR,"Server should be enabled, change in config file"); + return -100; + } + + dap_http_server_t * l_http = l_server_default->_inheritor; + if(!l_http){ + return -100; + } + + dap_http_simple_proc_add(l_http, "/remain_limits_vpn",24000, s_callback_remain_limits); + + // add groups with limits into clusters + + return 0; } @@ -990,16 +1018,20 @@ static int s_callback_response_success(dap_chain_net_srv_t * a_srv, uint32_t a_u case SERV_UNIT_SEC:{ l_srv_session->last_update_ts = time(NULL); if (!l_usage_active->is_grace && l_srv_session->limits_ts <= 0){ - log_it(L_INFO,"%"DAP_UINT64_FORMAT_U" seconds more for VPN usage", l_srv_session->limits_ts < 0 ? l_usage_active->receipt->receipt_info.units + l_srv_session->limits_ts : - l_usage_active->receipt->receipt_info.units); + char *l_user_key = dap_chain_hash_fast_to_str_new(&l_usage_active->client_pkey_hash); + log_it(L_INFO,"%"DAP_UINT64_FORMAT_U" seconds more for VPN usage for user %s", l_srv_session->limits_ts < 0 ? l_usage_active->receipt->receipt_info.units + l_srv_session->limits_ts : + l_usage_active->receipt->receipt_info.units, l_user_key); + DAP_DELETE(l_user_key); l_srv_session->limits_ts += (time_t)l_usage_active->receipt->receipt_info.units; } } break; case SERV_UNIT_B:{ if (!l_usage_active->is_grace && l_srv_session->limits_bytes <= 0){ - log_it(L_INFO,"%"DAP_UINT64_FORMAT_U" bytes more for VPN usage", l_srv_session->limits_ts < 0 ? l_usage_active->receipt->receipt_info.units + l_srv_session->limits_ts : - l_usage_active->receipt->receipt_info.units); - l_srv_session->limits_bytes = (uintmax_t) l_usage_active->receipt->receipt_info.units; + char *l_user_key = dap_chain_hash_fast_to_str_new(&l_usage_active->client_pkey_hash); + log_it(L_INFO,"%ld bytes more for VPN usage for user %s", l_srv_session->limits_bytes < 0 ? (intmax_t)l_usage_active->receipt->receipt_info.units + l_srv_session->limits_bytes : + (intmax_t)l_usage_active->receipt->receipt_info.units, l_user_key); + DAP_DELETE(l_user_key); + l_srv_session->limits_bytes += (intmax_t) l_usage_active->receipt->receipt_info.units; } } break; default: { @@ -1081,10 +1113,10 @@ static dap_stream_ch_chain_net_srv_remain_service_store_t* s_callback_get_remain log_it(L_DEBUG, "Can't get server pkey hash."); return NULL; } - char *l_remain_limits_gdb_group = dap_strdup_printf( "%s.0x%016"DAP_UINT64_FORMAT_x".remain_limits.%s", l_net->pub.gdb_groups_prefix, a_srv->uid.uint64, l_server_pkey_hash); + char *l_remain_limits_gdb_group = dap_strdup_printf( "local.%s.0x%016"DAP_UINT64_FORMAT_x".remain_limits.%s", l_net->pub.gdb_groups_prefix, a_srv->uid.uint64, l_server_pkey_hash); DAP_DEL_Z(l_server_pkey_hash); char *l_user_key = dap_chain_hash_fast_to_str_new(&l_usage->client_pkey_hash); - log_it(L_DEBUG, "Checkout user %s in group %s", l_user_key, l_remain_limits_gdb_group); + debug_if(s_debug_more, L_DEBUG, "Checkout user %s in group %s", l_user_key, l_remain_limits_gdb_group); dap_stream_ch_chain_net_srv_remain_service_store_t* l_remain_service = NULL; size_t l_remain_service_size = 0; l_remain_service = (dap_stream_ch_chain_net_srv_remain_service_store_t*) dap_global_db_get_sync(l_remain_limits_gdb_group, l_user_key, &l_remain_service_size, NULL, NULL); @@ -1159,10 +1191,10 @@ static int s_callback_save_remain_service(dap_chain_net_srv_t * a_srv, uint32_t log_it(L_DEBUG, "Can't get server pkey hash."); return -101; } - char *l_remain_limits_gdb_group = dap_strdup_printf( "%s.0x%016"DAP_UINT64_FORMAT_x".remain_limits.%s", l_net->pub.gdb_groups_prefix, a_srv->uid.uint64, l_server_pkey_hash); + char *l_remain_limits_gdb_group = dap_strdup_printf( "local.%s.0x%016"DAP_UINT64_FORMAT_x".remain_limits.%s", l_net->pub.gdb_groups_prefix, a_srv->uid.uint64, l_server_pkey_hash); DAP_DEL_Z(l_server_pkey_hash); char *l_user_key = dap_chain_hash_fast_to_str_new(&l_usage->client_pkey_hash); - log_it(L_DEBUG, "Save user %s remain service into group %s", l_user_key, l_remain_limits_gdb_group); + debug_if(s_debug_more, L_DEBUG, "Save user %s remain service into group %s", l_user_key, l_remain_limits_gdb_group); dap_stream_ch_chain_net_srv_remain_service_store_t l_remain_service = {}; dap_sign_t * l_receipt_sign = NULL; @@ -1171,21 +1203,20 @@ static int s_callback_save_remain_service(dap_chain_net_srv_t * a_srv, uint32_t } // l_remain_service.remain_units_type.enm = l_srv_session->limits_units_type.enm; - switch(l_srv_session->limits_units_type.enm){ - case SERV_UNIT_SEC: - l_remain_service.limits_ts = l_srv_session->limits_ts >= 0 ? l_srv_session->limits_ts : 0; - if(l_receipt_sign) - l_remain_service.limits_ts += l_srv_session->usage_active->receipt_next->receipt_info.units; - break; - case SERV_UNIT_B: - l_remain_service.limits_bytes = l_srv_session->limits_bytes >= 0 ? l_srv_session->limits_bytes : 0; - if (l_receipt_sign) - l_remain_service.limits_bytes += l_srv_session->usage_active->receipt_next->receipt_info.units; - break; - } + l_remain_service.limits_ts = l_srv_session->limits_ts >= 0 ? l_srv_session->limits_ts : 0; + if(l_receipt_sign && l_srv_session->limits_units_type.enm == SERV_UNIT_SEC) + l_remain_service.limits_ts += l_srv_session->usage_active->receipt_next->receipt_info.units; - if(dap_global_db_set_sync(l_remain_limits_gdb_group, l_user_key, &l_remain_service, sizeof(l_remain_service), false)) + l_remain_service.limits_bytes = l_srv_session->limits_bytes >= 0 ? l_srv_session->limits_bytes : 0; + if (l_receipt_sign && l_srv_session->limits_units_type.enm == SERV_UNIT_B) + l_remain_service.limits_bytes += l_srv_session->usage_active->receipt_next->receipt_info.units; + + + + int l_ret = dap_global_db_set_sync(l_remain_limits_gdb_group, l_user_key, &l_remain_service, sizeof(l_remain_service), false); + if(l_ret) { + log_it(L_DEBUG, "Can't save remain limits into GDB. Error code: %d", l_ret); DAP_DELETE(l_remain_limits_gdb_group); DAP_DELETE(l_user_key); return -102; @@ -1356,14 +1387,18 @@ static void s_update_limits(dap_stream_ch_t * a_ch , a_srv_session->limits_ts -= time(NULL) - a_srv_session->last_update_ts; a_usage->is_limits_changed = true; - if(a_srv_session->limits_ts < l_current_limit_ts/2 && !a_usage->receipt_next && !a_usage->is_grace){ + if(a_srv_session->limits_ts && a_srv_session->limits_ts < l_current_limit_ts/2 && + !a_usage->receipt_next && !a_usage->is_waiting_first_receipt_sign){ l_issue_new_receipt = true; } a_srv_session->last_update_ts = time(NULL); - if( a_srv_session->limits_ts <= 0 && !a_usage->is_grace){ - log_it(L_INFO, "Limits by timestamp are over. Switch to the next receipt"); + if( a_srv_session->limits_ts <= 0 && !a_usage->is_grace && + !a_usage->is_waiting_next_receipt_sign && !a_usage->is_waiting_first_receipt_sign){ + char *l_user_key = dap_chain_hash_fast_to_str_new(&a_usage->client_pkey_hash); + log_it(L_INFO, "Limits by timestamp are over for user %s. Switch to the next receipt", l_user_key); + DAP_DELETE(l_user_key); if (a_usage->receipt_next){ dap_sign_t * l_receipt_sign = dap_chain_datum_tx_receipt_sign_get( a_usage->receipt_next, a_usage->receipt_next->size, 1); if ( ! l_receipt_sign ){ @@ -1379,7 +1414,9 @@ static void s_update_limits(dap_stream_ch_t * a_ch , switch( a_usage->receipt->receipt_info.units_type.enm){ case SERV_UNIT_SEC:{ a_srv_session->limits_ts += (time_t)a_usage->receipt->receipt_info.units; - log_it(L_INFO,"%"DAP_UINT64_FORMAT_U" seconds more for VPN usage", a_usage->receipt->receipt_info.units); + char *l_user_key = dap_chain_hash_fast_to_str_new(&a_usage->client_pkey_hash); + log_it(L_INFO,"%"DAP_UINT64_FORMAT_U" seconds more for VPN usage for user %s", a_usage->receipt->receipt_info.units, l_user_key); + DAP_DELETE(l_user_key); } break; default: { log_it(L_WARNING, "VPN doesnt accept serv unit type 0x%08X for limits_ts", a_usage->receipt->receipt_info.units_type.uint32 ); @@ -1389,7 +1426,9 @@ static void s_update_limits(dap_stream_ch_t * a_ch , } } }else if (!a_usage->is_grace){ - log_it( L_NOTICE, "No activate receipt in usage, switch off write callback for channel"); + char *l_user_key = dap_chain_hash_fast_to_str_new(&a_usage->client_pkey_hash); + log_it( L_NOTICE, "No activate receipt in usage for user %s, switch off write callback for channel", l_user_key); + DAP_DELETE(l_user_key); dap_stream_ch_chain_net_srv_pkt_error_t l_err = { }; l_err.code = DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_RESPONSE_ERROR_CODE_RECEIPT_CANT_FIND ; dap_stream_ch_pkt_write_unsafe(a_ch , DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_NOTIFY_STOPPED , &l_err, sizeof(l_err)); @@ -1401,20 +1440,30 @@ static void s_update_limits(dap_stream_ch_t * a_ch , intmax_t current_limit_bytes = 0; if ( a_usage->receipt){// if we have active receipt and a_srv_session->last_update_ts == 0 then we counts units by traffic switch( a_usage->receipt->receipt_info.units_type.enm){ - case SERV_UNIT_B:{ - current_limit_bytes = (uintmax_t) a_usage->receipt->receipt_info.units; - } break; + case SERV_UNIT_B:{ + current_limit_bytes = (uintmax_t) a_usage->receipt->receipt_info.units; + } break; + default: { + log_it(L_WARNING, "VPN doesnt accept serv unit type 0x%08X for limits_ts", a_usage->receipt->receipt_info.units_type.uint32 ); + dap_stream_ch_pkt_write_unsafe( a_ch, DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_NOTIFY_STOPPED , NULL, 0 ); + dap_stream_ch_set_ready_to_write_unsafe(a_ch,false); + dap_stream_ch_set_ready_to_read_unsafe(a_ch,false); + } } } a_srv_session->limits_bytes -= (intmax_t) a_bytes; a_usage->is_limits_changed = true; - if (a_srv_session->limits_bytes && a_srv_session->limits_bytes < current_limit_bytes/2 && ! a_usage->receipt_next){ + if (a_srv_session->limits_bytes && a_srv_session->limits_bytes < current_limit_bytes/2 && + !a_usage->receipt_next && !a_usage->is_waiting_first_receipt_sign){ l_issue_new_receipt = true; } - if (a_srv_session->limits_bytes <= 0 && !a_usage->is_grace){ - log_it(L_INFO, "Limits by traffic is over. Switch to the next receipt"); + if (a_srv_session->limits_bytes <= 0 && !a_usage->is_grace && + !a_usage->is_waiting_next_receipt_sign && !a_usage->is_waiting_first_receipt_sign){ + char *l_user_key = dap_chain_hash_fast_to_str_new(&a_usage->client_pkey_hash); + log_it(L_INFO, "Limits by traffic is over for user %s. Switch to the next receipt", l_user_key); + DAP_DELETE(l_user_key); if (a_usage->receipt_next){ dap_sign_t * l_receipt_sign = dap_chain_datum_tx_receipt_sign_get( a_usage->receipt_next, a_usage->receipt_next->size, 1); if ( ! l_receipt_sign ){ @@ -1430,7 +1479,9 @@ static void s_update_limits(dap_stream_ch_t * a_ch , switch( a_usage->receipt->receipt_info.units_type.enm){ case SERV_UNIT_B:{ a_srv_session->limits_bytes += (uintmax_t) a_usage->receipt->receipt_info.units; - log_it(L_INFO,"%"DAP_UINT64_FORMAT_U" bytes more for VPN usage", a_usage->receipt->receipt_info.units); + char *l_user_key = dap_chain_hash_fast_to_str_new(&a_usage->client_pkey_hash); + log_it(L_INFO,"%"DAP_UINT64_FORMAT_U" bytes more for VPN usage for user", a_usage->receipt->receipt_info.units, l_user_key); + DAP_DELETE(l_user_key); } break; default: { log_it(L_WARNING, "VPN doesnt accept serv unit type 0x%08X for limits_bytes", a_usage->receipt->receipt_info.units_type.uint32 ); @@ -1440,7 +1491,9 @@ static void s_update_limits(dap_stream_ch_t * a_ch , } } }else if (!a_usage->is_grace){ - log_it( L_NOTICE, "No activate receipt in usage, switch off write callback for channel"); + char *l_user_key = dap_chain_hash_fast_to_str_new(&a_usage->client_pkey_hash); + log_it( L_NOTICE, "No activate receipt in usage for user %s, switch off write callback for channel", l_user_key); + DAP_DELETE(l_user_key); dap_stream_ch_chain_net_srv_pkt_error_t l_err = { }; l_err.code = DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_RESPONSE_ERROR_CODE_RECEIPT_CANT_FIND ; dap_stream_ch_pkt_write_unsafe( a_ch , DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_NOTIFY_STOPPED , &l_err, sizeof(l_err)); @@ -1453,9 +1506,14 @@ static void s_update_limits(dap_stream_ch_t * a_ch , // If issue new receipt if ( l_issue_new_receipt && !dap_hash_fast_is_blank(&a_usage->tx_cond_hash)) { if ( a_usage->receipt){ - log_it( L_NOTICE, "Send next receipt to sign"); + char *l_user_key = dap_chain_hash_fast_to_str_new(&a_usage->client_pkey_hash); + log_it( L_NOTICE, "Send next receipt to sign to user %s", l_user_key); + DAP_DELETE(l_user_key); a_usage->receipt_next = dap_chain_net_srv_issue_receipt(a_usage->service, a_usage->price, NULL, 0); - dap_stream_ch_pkt_write_unsafe(a_ch, DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_SIGN_REQUEST, + a_usage->is_waiting_next_receipt_sign = true; + //start timeout timer + a_usage->receipt_timeout_timer_start_callback(a_usage); + dap_stream_ch_pkt_write_unsafe(a_usage->client->ch, DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_SIGN_REQUEST, a_usage->receipt_next, a_usage->receipt_next->size); } } @@ -2081,3 +2139,127 @@ static int s_tun_deattach_queue(int fd) } #endif + + +static void s_callback_remain_limits(dap_http_simple_t *a_http_simple , void *a_arg) +{ + http_status_code_t * l_return_code = (http_status_code_t*)a_arg; + *l_return_code = Http_Status_OK; + strcpy(a_http_simple->reply_mime, "text/text"); + + const char* l_query = a_http_simple->http_client->in_query_string; + uint32_t l_query_length = a_http_simple->http_client->in_query_string_len; + + const char *l_net_id_str = NULL; + const char *l_user_pkey_hash_str = NULL; + dap_chain_net_id_t l_net_id = {}; + // request parsing + // example: net_id=id&user_pkey_hash=pkeyhash + char *l_first_param = DAP_DUP_SIZE(l_query, l_query_length); + char *l_second_param = strchr(l_first_param, '&'); + if (!l_second_param || strlen(l_second_param) == 1){ + dap_http_simple_reply_f(a_http_simple, "Wrong parameters!"); + *l_return_code = Http_Status_OK; + return; + } + *l_second_param++ = '\0'; + + if (strstr(l_first_param, "net_id")){ + if (*(l_first_param + strlen("net_id")) == '='){ + l_net_id_str = l_first_param + strlen("net_id") + 1; + } + } else if (strstr(l_first_param, "user_pkey_hash")) { + if (*(l_first_param + strlen("user_pkey_hash")) == '='){ + l_user_pkey_hash_str = l_first_param + strlen("user_pkey_hash") + 1; + } + } + + if (strstr(l_second_param, "net_id")){ + if (*(l_second_param + strlen("net_id")) == '='){ + l_net_id_str = l_second_param + strlen("net_id") + 1; + } + } else if (strstr(l_second_param, "user_pkey_hash")) { + if (*(l_second_param + strlen("user_pkey_hash")) == '='){ + l_user_pkey_hash_str = l_second_param + strlen("user_pkey_hash") + 1; + } + } + + if (!l_net_id_str || !l_user_pkey_hash_str){ + dap_http_simple_reply_f(a_http_simple, "Wrong parameters!"); + *l_return_code = Http_Status_OK; + return; + } + + l_net_id.uint64 = strtoul(l_net_id_str, NULL, 10); + + dap_stream_ch_chain_net_srv_remain_service_store_t *l_remain_service = NULL; + const char *l_cert_name = dap_config_get_item_str_default(g_config, "srv_vpn", "receipt_sign_cert", NULL); + if (l_cert_name){ + dap_cert_t *l_cert = dap_cert_find_by_name(l_cert_name); + dap_hash_fast_t price_pkey_hash = {}; + size_t l_key_size = 0; + uint8_t *l_pub_key = dap_enc_key_serialize_pub_key(l_cert->enc_key, &l_key_size); + if (!l_pub_key || !l_key_size) + { + log_it(L_ERROR, "Can't get pkey from cert %s.", l_cert_name); + dap_http_simple_reply_f(a_http_simple, "Internal error!"); + *l_return_code = Http_Status_OK; + return; + } + + dap_hash_fast(l_pub_key, l_key_size, &price_pkey_hash); + DAP_DELETE(l_pub_key); + char* l_server_pkey_hash = dap_chain_hash_fast_to_str_new(&price_pkey_hash); + if (!l_server_pkey_hash){ + log_it(L_DEBUG, "Can't get server pkey hash."); + dap_http_simple_reply_f(a_http_simple, "Internal error!"); + *l_return_code = Http_Status_OK; + return; + } + + dap_chain_net_t *l_net = dap_chain_net_by_id(l_net_id); + if(!l_net){ + log_it(L_DEBUG, "Can't find net with id %"DAP_UINT64_FORMAT_U, l_net_id.uint64); + dap_http_simple_reply_f(a_http_simple, "Can't find net with id %"DAP_UINT64_FORMAT_U"!", l_net_id.uint64); + DAP_DEL_Z(l_server_pkey_hash); + *l_return_code = Http_Status_OK; + return; + } + char *l_remain_limits_gdb_group = dap_strdup_printf( "local.%s.0x%016"DAP_UINT64_FORMAT_x".remain_limits.%s", l_net->pub.gdb_groups_prefix, (uint64_t)DAP_CHAIN_NET_SRV_VPN_ID, l_server_pkey_hash); + log_it(L_DEBUG, "Checkout user %s in group %s", l_user_pkey_hash_str, l_remain_limits_gdb_group); + size_t l_remain_service_size = 0; + l_remain_service = (dap_stream_ch_chain_net_srv_remain_service_store_t*) dap_global_db_get_sync(l_remain_limits_gdb_group, l_user_pkey_hash_str, &l_remain_service_size, NULL, NULL); + DAP_DELETE(l_remain_limits_gdb_group); + + // Create JSON responce + json_object *l_json_response = json_object_new_object(); + + json_object *l_new_data = json_object_new_uint64(l_net_id.uint64); + json_object_object_add(l_json_response, "netId", l_new_data); + + l_new_data = json_object_new_uint64((uint64_t)DAP_CHAIN_NET_SRV_VPN_ID); + json_object_object_add(l_json_response, "srvUid", l_new_data); + + l_new_data = json_object_new_string(l_user_pkey_hash_str ? l_user_pkey_hash_str : ""); + json_object_object_add(l_json_response, "userPkeyHash", l_new_data); + + l_new_data = json_object_new_string(l_server_pkey_hash ? l_server_pkey_hash : ""); + json_object_object_add(l_json_response, "serverPkeyHash", l_new_data); + + l_new_data = json_object_new_uint64(l_remain_service ? l_remain_service->limits_bytes : 0); + json_object_object_add(l_json_response, "limitsBytes", l_new_data); + + l_new_data = json_object_new_uint64(l_remain_service ? l_remain_service->limits_ts : 0); + json_object_object_add(l_json_response, "limitsSec", l_new_data); + + const char *output_string = json_object_to_json_string(l_json_response); + dap_http_simple_reply(a_http_simple, (void*)output_string, strlen(output_string)); + strcpy(a_http_simple->reply_mime, "application/json"); + json_object_put(l_json_response); + DAP_DEL_Z(l_server_pkey_hash); + DAP_DEL_Z(l_first_param); + } else { + dap_http_simple_reply_f(a_http_simple, "Internal error!"); + *l_return_code = Http_Status_InternalServerError; + } +} \ No newline at end of file