static void x_request_data(void) { if (g_pg_next >= DATA_PAGES) { if (!g_pg_pending) { x_set_status(x_completed); return; } } else { int b, has_free_buff = 0; for (b = 0; b < BUFF_PAGES; ++b) { if (g_buff_status[b] == x_buff_unused) { has_free_buff = 1; if (!x_buff_attach(b)) { break; } } } if (!has_free_buff) { if ((int)(rtc_current() - g_get_pg_tout_ts) > 0) { x_set_status(x_failed); return; } } } send_data_request(); }
/* Send data of length length to friendnum. * This data will be recieved by the friend using the Onion_Data_Handlers callbacks. * * Even if this function succeeds, the friend might not recieve any data. * * return the number of packets sent on success * return -1 on failure. */ int send_onion_data(Onion_Client *onion_c, int friend_num, uint8_t *data, uint32_t length) { if ((uint32_t)friend_num >= onion_c->num_friends) return -1; if (length + DATA_IN_RESPONSE_MIN_SIZE + ONION_DATA_RESPONSE_MIN_SIZE + ONION_SEND_1 > MAX_DATA_SIZE) return -1; if (length == 0) return -1; uint8_t nonce[crypto_box_NONCEBYTES]; random_nonce(nonce); uint8_t packet[DATA_IN_RESPONSE_MIN_SIZE + length]; memcpy(packet, onion_c->dht->c->self_public_key, crypto_box_PUBLICKEYBYTES); int len = encrypt_data(onion_c->friends_list[friend_num].real_client_id, onion_c->dht->c->self_secret_key, nonce, data, length, packet + crypto_box_PUBLICKEYBYTES); if ((uint32_t)len + crypto_box_PUBLICKEYBYTES != sizeof(packet)) return -1; uint32_t i, good_nodes[MAX_ONION_CLIENTS], num_good = 0, num_nodes = 0; Onion_Path path[MAX_ONION_CLIENTS]; Onion_Node *list_nodes = onion_c->friends_list[friend_num].clients_list; for (i = 0; i < MAX_ONION_CLIENTS; ++i) { if (is_timeout(list_nodes[i].timestamp, ONION_NODE_TIMEOUT)) continue; ++num_nodes; if (list_nodes[i].is_stored) { if (random_path(onion_c->dht, &onion_c->friends_list[friend_num].onion_paths, ~0, &path[num_good]) == -1) continue; good_nodes[num_good] = i; ++num_good; } } if (num_good < (num_nodes / 4) + 1) return -1; uint32_t good = 0; for (i = 0; i < num_good; ++i) { if (send_data_request(onion_c->net, &path[i], list_nodes[good_nodes[i]].ip_port, onion_c->friends_list[friend_num].real_client_id, list_nodes[good_nodes[i]].data_public_key, nonce, packet, sizeof(packet)) == 0) ++good; } return good; }
/* Send data of length length to friendnum. * This data will be recieved by the friend using the Onion_Data_Handlers callbacks. * * Even if this function succeeds, the friend might not recieve any data. * * return the number of packets sent on success * return -1 on failure. */ int send_onion_data(Onion_Client *onion_c, int friend_num, uint8_t *data, uint32_t length) { if ((uint32_t)friend_num >= onion_c->num_friends) return -1; if (length + DATA_IN_RESPONSE_MIN_SIZE + ONION_DATA_RESPONSE_MIN_SIZE + ONION_SEND_1 > MAX_DATA_SIZE) return -1; if (length == 0) return -1; uint8_t nonce[crypto_box_NONCEBYTES]; new_nonce(nonce); uint8_t packet[DATA_IN_RESPONSE_MIN_SIZE + length]; memcpy(packet, onion_c->dht->c->self_public_key, crypto_box_PUBLICKEYBYTES); int len = encrypt_data(onion_c->friends_list[friend_num].real_client_id, onion_c->dht->c->self_secret_key, nonce, data, length, packet + crypto_box_PUBLICKEYBYTES); if ((uint32_t)len + crypto_box_PUBLICKEYBYTES != sizeof(packet)) return -1; uint32_t i, good = 0; Onion_Node *list_nodes = onion_c->friends_list[friend_num].clients_list; for (i = 0; i < MAX_ONION_CLIENTS; ++i) { if (is_timeout(list_nodes[i].timestamp, ONION_NODE_TIMEOUT)) continue; if (memcmp(list_nodes[i].ping_id, zero_ping, ONION_PING_ID_SIZE) == 0) { Node_format nodes[4]; if (random_path(onion_c, nodes) == -1) continue; memcpy(nodes[3].client_id, list_nodes[i].client_id, crypto_box_PUBLICKEYBYTES); nodes[3].ip_port = list_nodes[i].ip_port; if (send_data_request(onion_c->dht, nodes, onion_c->friends_list[friend_num].real_client_id, nonce, packet, sizeof(packet)) == 0) ++good; } } return good; }
static inline void x_request_meta(void) { BUG_ON(!g_pg_pending); send_data_request(); }