/* Send data of length length to friendnum. * This data will be received by the friend using the Onion_Data_Handlers callbacks. * * Even if this function succeeds, the friend might not receive any data. * * return the number of packets sent on success * return -1 on failure. */ int send_onion_data(const Onion_Client *onion_c, int friend_num, const uint8_t *data, uint32_t length) { if ((uint32_t)friend_num >= onion_c->num_friends) return -1; if (length + DATA_IN_RESPONSE_MIN_SIZE > MAX_DATA_REQUEST_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->c->self_public_key, crypto_box_PUBLICKEYBYTES); int len = encrypt_data(onion_c->friends_list[friend_num].real_client_id, onion_c->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, &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) { uint8_t o_packet[ONION_MAX_PACKET_SIZE]; len = create_data_request(o_packet, sizeof(o_packet), onion_c->friends_list[friend_num].real_client_id, list_nodes[good_nodes[i]].data_public_key, nonce, packet, sizeof(packet)); if (len == -1) continue; if (send_onion_packet_tcp_udp(onion_c, &path[i], list_nodes[good_nodes[i]].ip_port, o_packet, len) == 0) ++good; } return good; }
/* Create and send an onion data request packet. * * path is the path the request will take before it is sent to dest. * (if dest knows the person with the public_key they should * send the packet to that person in the form of a response) * * public_key is the real public key of the node which we want to send the data of length length to. * encrypt_public_key is the public key used to encrypt the data packet. * * nonce is the nonce to encrypt this packet with * * return -1 on failure. * return 0 on success. */ int send_data_request(Networking_Core *net, const Onion_Path *path, IP_Port dest, const uint8_t *public_key, const uint8_t *encrypt_public_key, const uint8_t *nonce, const uint8_t *data, uint16_t length) { uint8_t request[ONION_MAX_DATA_SIZE]; int len = create_data_request(request, sizeof(request), public_key, encrypt_public_key, nonce, data, length); if (len == -1) { return -1; } uint8_t packet[ONION_MAX_PACKET_SIZE]; len = create_onion_packet(packet, sizeof(packet), path, dest, request, len); if (len == -1) { return -1; } if (sendpacket(net, path->ip_port1, packet, len) != len) { return -1; } return 0; }