From e658892793c42b2d058eed0937025ef2ddaaa372 Mon Sep 17 00:00:00 2001 From: jin-eld Date: Sun, 4 Aug 2013 15:10:37 +0300 Subject: Rename core directory because of autoconf name clash While doing the checks configure might generate "core" files and will then try to remove them. Having a "core" directory generates an error while runing the configure script. There's no workaround but to rename the core directory. --- core/CMakeLists.txt | 45 -- core/DHT.c | 1264 ------------------------------------------------ core/DHT.h | 193 -------- core/LAN_discovery.c | 152 ------ core/LAN_discovery.h | 55 --- core/Lossless_UDP.c | 842 -------------------------------- core/Lossless_UDP.h | 222 --------- core/Messenger.c | 1020 -------------------------------------- core/Messenger.h | 351 -------------- core/friend_requests.c | 141 ------ core/friend_requests.h | 70 --- core/net_crypto.c | 771 ----------------------------- core/net_crypto.h | 200 -------- core/network.c | 218 --------- core/network.h | 159 ------ core/packets.h | 31 -- core/ping.c | 229 --------- core/ping.h | 17 - core/tox.c | 374 -------------- core/tox.h | 289 ----------- core/util.c | 45 -- core/util.h | 12 - 22 files changed, 6700 deletions(-) delete mode 100644 core/CMakeLists.txt delete mode 100644 core/DHT.c delete mode 100644 core/DHT.h delete mode 100644 core/LAN_discovery.c delete mode 100644 core/LAN_discovery.h delete mode 100644 core/Lossless_UDP.c delete mode 100644 core/Lossless_UDP.h delete mode 100644 core/Messenger.c delete mode 100644 core/Messenger.h delete mode 100644 core/friend_requests.c delete mode 100644 core/friend_requests.h delete mode 100644 core/net_crypto.c delete mode 100644 core/net_crypto.h delete mode 100644 core/network.c delete mode 100644 core/network.h delete mode 100644 core/packets.h delete mode 100644 core/ping.c delete mode 100644 core/ping.h delete mode 100644 core/tox.c delete mode 100644 core/tox.h delete mode 100644 core/util.c delete mode 100644 core/util.h (limited to 'core') diff --git a/core/CMakeLists.txt b/core/CMakeLists.txt deleted file mode 100644 index ecbb65c2..00000000 --- a/core/CMakeLists.txt +++ /dev/null @@ -1,45 +0,0 @@ -cmake_minimum_required(VERSION 2.6.0) -project(toxcore C) - -set(core_sources - DHT.c - network.c - Lossless_UDP.c - net_crypto.c - friend_requests.c - LAN_discovery.c - Messenger.c - util.c - ping.c - tox.c) - -set(core_headers - DHT.h - network.h - Lossless_UDP.h - net_crypto.h - friend_requests.h - LAN_discovery.h - Messenger.h - util.h - ping.h) - -add_library(toxcore SHARED ${core_sources}) -add_library(toxcore_static ${core_sources}) -set_target_properties(toxcore_static PROPERTIES OUTPUT_NAME toxcore) - -target_link_libraries(toxcore ${LINK_CRYPTO_LIBRARY}) - -install(TARGETS toxcore toxcore_static DESTINATION lib) -install(FILES ${core_headers} DESTINATION include) - -if(WIN32) - target_link_libraries(toxcore ws2_32) -endif() - -execute_process(COMMAND git rev-list HEAD --count OUTPUT_VARIABLE COMMIT) - -# Write pkgconfig-file: -include(InstallPkgConfigFile) -install_pkg_config_file(toxcore CFLAGS LIBS -ltoxcore REQUIRES VERSION 0.1.1_r${COMMIT}) - diff --git a/core/DHT.c b/core/DHT.c deleted file mode 100644 index 533425c4..00000000 --- a/core/DHT.c +++ /dev/null @@ -1,1264 +0,0 @@ -/* DHT.c - * - * An implementation of the DHT as seen in http://wiki.tox.im/index.php/DHT - * - * Copyright (C) 2013 Tox project All Rights Reserved. - * - * This file is part of Tox. - * - * Tox 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. - * - * Tox 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 Tox. If not, see . - * - */ - -/*----------------------------------------------------------------------------------*/ - -#include "DHT.h" -#include "packets.h" -#include "ping.h" - -/* the number of seconds for a non responsive node to become bad. */ -#define BAD_NODE_TIMEOUT 70 - -/* the max number of nodes to send with send nodes. */ -#define MAX_SENT_NODES 8 - -/* ping timeout in seconds */ -#define PING_TIMEOUT 5 - -/* The timeout after which a node is discarded completely. */ -#define Kill_NODE_TIMEOUT 300 - -/* ping interval in seconds for each node in our lists. */ -#define PING_INTERVAL 60 - -/* ping interval in seconds for each random sending of a get nodes request. */ -#define GET_NODE_INTERVAL 10 - -#define MAX_PUNCHING_PORTS 32 - -/*Interval in seconds between punching attempts*/ -#define PUNCH_INTERVAL 10 - -/*Ping newly announced nodes to ping per TIME_TOPING seconds*/ -#define TIME_TOPING 5 - -#define NAT_PING_REQUEST 0 -#define NAT_PING_RESPONSE 1 - - -Client_data *DHT_get_close_list(DHT *dht) -{ - return dht->close_clientlist; -} - -/* Compares client_id1 and client_id2 with client_id - * return 0 if both are same distance - * return 1 if client_id1 is closer - * return 2 if client_id2 is closer - */ -static int id_closest(uint8_t *id, uint8_t *id1, uint8_t *id2) -{ - size_t i; - uint8_t distance1, distance2; - - for (i = 0; i < CLIENT_ID_SIZE; ++i) { - - distance1 = abs(id[i] ^ id1[i]); - distance2 = abs(id[i] ^ id2[i]); - - if (distance1 < distance2) - return 1; - - if (distance1 > distance2) - return 2; - } - - return 0; -} - -static int ipport_equal(IP_Port a, IP_Port b) -{ - return (a.ip.i == b.ip.i) && (a.port == b.port); -} - -static int id_equal(uint8_t *a, uint8_t *b) -{ - return memcmp(a, b, CLIENT_ID_SIZE) == 0; -} - -static int is_timeout(uint64_t time_now, uint64_t timestamp, uint64_t timeout) -{ - return timestamp + timeout <= time_now; -} - -/* check if client with client_id is already in list of length length. - * if it is then set its corresponding timestamp to current time. - * if the id is already in the list with a different ip_port, update it. - * return True(1) or False(0) - * - * TODO: maybe optimize this. - */ -static int client_in_list(Client_data *list, uint32_t length, uint8_t *client_id, IP_Port ip_port) -{ - uint32_t i; - uint64_t temp_time = unix_time(); - - for (i = 0; i < length; ++i) { - /*If ip_port is assigned to a different client_id replace it*/ - if (ipport_equal(list[i].ip_port, ip_port)) { - memcpy(list[i].client_id, client_id, CLIENT_ID_SIZE); - } - - if (id_equal(list[i].client_id, client_id)) { - /* Refresh the client timestamp. */ - list[i].timestamp = temp_time; - list[i].ip_port.ip.i = ip_port.ip.i; - list[i].ip_port.port = ip_port.port; - return 1; - } - } - - return 0; -} - -/* check if client with client_id is already in node format list of length length. - * return True(1) or False(0) - */ -static int client_in_nodelist(Node_format *list, uint32_t length, uint8_t *client_id) -{ - uint32_t i; - - for (i = 0; i < length; ++i) { - if (id_equal(list[i].client_id, client_id)) - return 1; - } - - return 0; -} - -/* Returns the friend number from the client_id, or -1 if a failure occurs - */ -static int friend_number(DHT *dht, uint8_t *client_id) -{ - uint32_t i; - - for (i = 0; i < dht->num_friends; ++i) { - if (id_equal(dht->friends_list[i].client_id, client_id)) - return i; - } - - return -1; -} - -/* Find MAX_SENT_NODES nodes closest to the client_id for the send nodes request: - * put them in the nodes_list and return how many were found. - * - * TODO: For the love of based Allah make this function cleaner and much more efficient. - */ -static int get_close_nodes(DHT *dht, uint8_t *client_id, Node_format *nodes_list) -{ - uint32_t i, j, k; - uint64_t temp_time = unix_time(); - int num_nodes = 0, closest, tout, inlist; - - for (i = 0; i < LCLIENT_LIST; ++i) { - tout = is_timeout(temp_time, dht->close_clientlist[i].timestamp, BAD_NODE_TIMEOUT); - inlist = client_in_nodelist(nodes_list, MAX_SENT_NODES, dht->close_clientlist[i].client_id); - - /* if node isn't good or is already in list. */ - if (tout || inlist) - continue; - - if (num_nodes < MAX_SENT_NODES) { - - memcpy( nodes_list[num_nodes].client_id, - dht->close_clientlist[i].client_id, - CLIENT_ID_SIZE ); - - nodes_list[num_nodes].ip_port = dht->close_clientlist[i].ip_port; - num_nodes++; - - } else { - - for (j = 0; j < MAX_SENT_NODES; ++j) { - closest = id_closest( client_id, - nodes_list[j].client_id, - dht->close_clientlist[i].client_id ); - - if (closest == 2) { - memcpy( nodes_list[j].client_id, - dht->close_clientlist[i].client_id, - CLIENT_ID_SIZE); - - nodes_list[j].ip_port = dht->close_clientlist[i].ip_port; - break; - } - } - } - } - - for (i = 0; i < dht->num_friends; ++i) { - for (j = 0; j < MAX_FRIEND_CLIENTS; ++j) { - - tout = is_timeout(temp_time, dht->friends_list[i].client_list[j].timestamp, BAD_NODE_TIMEOUT); - inlist = client_in_nodelist( nodes_list, - MAX_SENT_NODES, - dht->friends_list[i].client_list[j].client_id); - - /* if node isn't good or is already in list. */ - if (tout || inlist) - continue; - - if (num_nodes < MAX_SENT_NODES) { - - memcpy( nodes_list[num_nodes].client_id, - dht->friends_list[i].client_list[j].client_id, - CLIENT_ID_SIZE); - - nodes_list[num_nodes].ip_port = dht->friends_list[i].client_list[j].ip_port; - num_nodes++; - } else { - for (k = 0; k < MAX_SENT_NODES; ++k) { - - closest = id_closest( client_id, - nodes_list[k].client_id, - dht->friends_list[i].client_list[j].client_id ); - - if (closest == 2) { - memcpy( nodes_list[k].client_id, - dht->friends_list[i].client_list[j].client_id, - CLIENT_ID_SIZE ); - - nodes_list[k].ip_port = dht->friends_list[i].client_list[j].ip_port; - break; - } - } - } - } - } - - return num_nodes; -} - -/* replace first bad (or empty) node with this one - * return 0 if successful - * return 1 if not (list contains no bad nodes) - */ -static int replace_bad( Client_data *list, - uint32_t length, - uint8_t *client_id, - IP_Port ip_port ) -{ - uint32_t i; - uint64_t temp_time = unix_time(); - - for (i = 0; i < length; ++i) { - /* if node is bad */ - if (is_timeout(temp_time, list[i].timestamp, BAD_NODE_TIMEOUT)) { - memcpy(list[i].client_id, client_id, CLIENT_ID_SIZE); - list[i].ip_port = ip_port; - list[i].timestamp = temp_time; - list[i].ret_ip_port.ip.i = 0; - list[i].ret_ip_port.port = 0; - list[i].ret_timestamp = 0; - return 0; - } - } - - return 1; -} -/*Sort the list. It will be sorted from furthest to closest. - TODO: this is innefficient and needs to be optimized.*/ -static void sort_list(Client_data *list, uint32_t length, uint8_t *comp_client_id) -{ - if (length == 0) - return; - - uint32_t i, count; - - while (1) { - count = 0; - - for (i = 0; i < (length - 1); ++i) { - if (id_closest(comp_client_id, list[i].client_id, list[i + 1].client_id) == 1) { - Client_data temp = list[i + 1]; - list[i + 1] = list[i]; - list[i] = temp; - ++count; - } - } - - if (count == 0) - return; - } -} - - -/* replace the first good node that is further to the comp_client_id than that of the client_id in the list */ -static int replace_good( Client_data *list, - uint32_t length, - uint8_t *client_id, - IP_Port ip_port, - uint8_t *comp_client_id ) -{ - uint32_t i; - uint64_t temp_time = unix_time(); - sort_list(list, length, comp_client_id); - - for (i = 0; i < length; ++i) - if (id_closest(comp_client_id, list[i].client_id, client_id) == 2) { - memcpy(list[i].client_id, client_id, CLIENT_ID_SIZE); - list[i].ip_port = ip_port; - list[i].timestamp = temp_time; - list[i].ret_ip_port.ip.i = 0; - list[i].ret_ip_port.port = 0; - list[i].ret_timestamp = 0; - return 0; - } - - return 1; -} - -/* Attempt to add client with ip_port and client_id to the friends client list - * and close_clientlist - */ -void addto_lists(DHT *dht, IP_Port ip_port, uint8_t *client_id) -{ - uint32_t i; - - /* NOTE: current behavior if there are two clients with the same id is - * to replace the first ip by the second. - */ - if (!client_in_list(dht->close_clientlist, LCLIENT_LIST, client_id, ip_port)) { - if (replace_bad(dht->close_clientlist, LCLIENT_LIST, client_id, ip_port)) { - /* if we can't replace bad nodes we try replacing good ones */ - replace_good( dht->close_clientlist, - LCLIENT_LIST, - client_id, - ip_port, - dht->c->self_public_key ); - } - } - - for (i = 0; i < dht->num_friends; ++i) { - if (!client_in_list( dht->friends_list[i].client_list, - MAX_FRIEND_CLIENTS, - client_id, - ip_port )) { - - if (replace_bad( dht->friends_list[i].client_list, - MAX_FRIEND_CLIENTS, - client_id, - ip_port )) { - /* if we can't replace bad nodes we try replacing good ones. */ - replace_good( dht->friends_list[i].client_list, - MAX_FRIEND_CLIENTS, - client_id, - ip_port, - dht->friends_list[i].client_id ); - } - } - } -} - -/* If client_id is a friend or us, update ret_ip_port - * nodeclient_id is the id of the node that sent us this info - */ -static void returnedip_ports(DHT *dht, IP_Port ip_port, uint8_t *client_id, uint8_t *nodeclient_id) -{ - uint32_t i, j; - uint64_t temp_time = unix_time(); - - if (id_equal(client_id, dht->c->self_public_key)) { - - for (i = 0; i < LCLIENT_LIST; ++i) { - if (id_equal(nodeclient_id, dht->close_clientlist[i].client_id)) { - dht->close_clientlist[i].ret_ip_port = ip_port; - dht->close_clientlist[i].ret_timestamp = temp_time; - return; - } - } - - } else { - - for (i = 0; i < dht->num_friends; ++i) { - if (id_equal(client_id, dht->friends_list[i].client_id)) { - - for (j = 0; j < MAX_FRIEND_CLIENTS; ++j) { - if (id_equal(nodeclient_id, dht->friends_list[i].client_list[j].client_id)) { - dht->friends_list[i].client_list[j].ret_ip_port = ip_port; - dht->friends_list[i].client_list[j].ret_timestamp = temp_time; - return; - } - } - } - } - - } -} - -/* Same as last function but for get_node requests. */ -static int is_gettingnodes(DHT *dht, IP_Port ip_port, uint64_t ping_id) -{ - uint32_t i; - uint8_t pinging; - uint64_t temp_time = unix_time(); - - for (i = 0; i < LSEND_NODES_ARRAY; ++i ) { - if (!is_timeout(temp_time, dht->send_nodes[i].timestamp, PING_TIMEOUT)) { - pinging = 0; - - if (ip_port.ip.i != 0 && ipport_equal(dht->send_nodes[i].ip_port, ip_port)) - ++pinging; - - if (ping_id != 0 && dht->send_nodes[i].ping_id == ping_id) - ++pinging; - - if (pinging == (ping_id != 0) + (ip_port.ip.i != 0)) - return 1; - } - } - - return 0; -} - -/* Same but for get node requests */ -static uint64_t add_gettingnodes(DHT *dht, IP_Port ip_port) -{ - uint32_t i, j; - uint64_t ping_id = ((uint64_t)random_int() << 32) + random_int(); - uint64_t temp_time = unix_time(); - - for (i = 0; i < PING_TIMEOUT; ++i ) { - for (j = 0; j < LSEND_NODES_ARRAY; ++j ) { - if (is_timeout(temp_time, dht->send_nodes[j].timestamp, PING_TIMEOUT - i)) { - dht->send_nodes[j].timestamp = temp_time; - dht->send_nodes[j].ip_port = ip_port; - dht->send_nodes[j].ping_id = ping_id; - return ping_id; - } - } - } - - return 0; -} - -/* send a getnodes request */ -static int getnodes(DHT *dht, IP_Port ip_port, uint8_t *public_key, uint8_t *client_id) -{ - /* check if packet is gonna be sent to ourself */ - if (id_equal(public_key, dht->c->self_public_key) || is_gettingnodes(dht, ip_port, 0)) - return 1; - - uint64_t ping_id = add_gettingnodes(dht, ip_port); - - if (ping_id == 0) - return 1; - - uint8_t data[1 + CLIENT_ID_SIZE + crypto_box_NONCEBYTES + sizeof(ping_id) + CLIENT_ID_SIZE + ENCRYPTION_PADDING]; - uint8_t plain[sizeof(ping_id) + CLIENT_ID_SIZE]; - uint8_t encrypt[sizeof(ping_id) + CLIENT_ID_SIZE + ENCRYPTION_PADDING]; - uint8_t nonce[crypto_box_NONCEBYTES]; - random_nonce(nonce); - - memcpy(plain, &ping_id, sizeof(ping_id)); - memcpy(plain + sizeof(ping_id), client_id, CLIENT_ID_SIZE); - - int len = encrypt_data( public_key, - dht->c->self_secret_key, - nonce, - plain, - sizeof(ping_id) + CLIENT_ID_SIZE, - encrypt ); - - if (len != sizeof(ping_id) + CLIENT_ID_SIZE + ENCRYPTION_PADDING) - return -1; - - data[0] = NET_PACKET_GET_NODES; - memcpy(data + 1, dht->c->self_public_key, CLIENT_ID_SIZE); - memcpy(data + 1 + CLIENT_ID_SIZE, nonce, crypto_box_NONCEBYTES); - memcpy(data + 1 + CLIENT_ID_SIZE + crypto_box_NONCEBYTES, encrypt, len); - - return sendpacket(dht->c->lossless_udp->net->sock, ip_port, data, sizeof(data)); -} - -/* send a send nodes response */ -static int sendnodes(DHT *dht, IP_Port ip_port, uint8_t *public_key, uint8_t *client_id, uint64_t ping_id) -{ - /* check if packet is gonna be sent to ourself */ - if (id_equal(public_key, dht->c->self_public_key)) - return 1; - - uint8_t data[1 + CLIENT_ID_SIZE + crypto_box_NONCEBYTES + sizeof(ping_id) - + sizeof(Node_format) * MAX_SENT_NODES + ENCRYPTION_PADDING]; - - Node_format nodes_list[MAX_SENT_NODES]; - int num_nodes = get_close_nodes(dht, client_id, nodes_list); - - if (num_nodes == 0) - return 0; - - uint8_t plain[sizeof(ping_id) + sizeof(Node_format) * MAX_SENT_NODES]; - uint8_t encrypt[sizeof(ping_id) + sizeof(Node_format) * MAX_SENT_NODES + ENCRYPTION_PADDING]; - uint8_t nonce[crypto_box_NONCEBYTES]; - random_nonce(nonce); - - memcpy(plain, &ping_id, sizeof(ping_id)); - memcpy(plain + sizeof(ping_id), nodes_list, num_nodes * sizeof(Node_format)); - - int len = encrypt_data( public_key, - dht->c->self_secret_key, - nonce, - plain, - sizeof(ping_id) + num_nodes * sizeof(Node_format), - encrypt ); - - if (len != sizeof(ping_id) + num_nodes * sizeof(Node_format) + ENCRYPTION_PADDING) - return -1; - - data[0] = NET_PACKET_SEND_NODES; - memcpy(data + 1, dht->c->self_public_key, CLIENT_ID_SIZE); - memcpy(data + 1 + CLIENT_ID_SIZE, nonce, crypto_box_NONCEBYTES); - memcpy(data + 1 + CLIENT_ID_SIZE + crypto_box_NONCEBYTES, encrypt, len); - - return sendpacket(dht->c->lossless_udp->net->sock, ip_port, data, 1 + CLIENT_ID_SIZE + crypto_box_NONCEBYTES + len); -} - -static int handle_getnodes(void *object, IP_Port source, uint8_t *packet, uint32_t length) -{ - DHT *dht = object; - uint64_t ping_id; - - if (length != ( 1 + CLIENT_ID_SIZE + crypto_box_NONCEBYTES - + sizeof(ping_id) + CLIENT_ID_SIZE + ENCRYPTION_PADDING )) - return 1; - - /* check if packet is from ourself. */ - if (id_equal(packet + 1, dht->c->self_public_key)) - return 1; - - uint8_t plain[sizeof(ping_id) + CLIENT_ID_SIZE]; - - int len = decrypt_data( packet + 1, - dht->c->self_secret_key, - packet + 1 + CLIENT_ID_SIZE, - packet + 1 + CLIENT_ID_SIZE + crypto_box_NONCEBYTES, - sizeof(ping_id) + CLIENT_ID_SIZE + ENCRYPTION_PADDING, - plain ); - - if (len != sizeof(ping_id) + CLIENT_ID_SIZE) - return 1; - - memcpy(&ping_id, plain, sizeof(ping_id)); - sendnodes(dht, source, packet + 1, plain + sizeof(ping_id), ping_id); - - //send_ping_request(dht, source, (clientid_t*) (packet + 1)); /* TODO: make this smarter? */ - - return 0; -} - -static int handle_sendnodes(void *object, IP_Port source, uint8_t *packet, uint32_t length) -{ - DHT *dht = object; - uint64_t ping_id; - uint32_t cid_size = 1 + CLIENT_ID_SIZE; - cid_size += crypto_box_NONCEBYTES + sizeof(ping_id) + ENCRYPTION_PADDING; - - if (length > (cid_size + sizeof(Node_format) * MAX_SENT_NODES) || - ((length - cid_size) % sizeof(Node_format)) != 0 || - (length < cid_size + sizeof(Node_format))) - return 1; - - uint32_t num_nodes = (length - cid_size) / sizeof(Node_format); - uint8_t plain[sizeof(ping_id) + sizeof(Node_format) * MAX_SENT_NODES]; - - int len = decrypt_data( - packet + 1, - dht->c->self_secret_key, - packet + 1 + CLIENT_ID_SIZE, - packet + 1 + CLIENT_ID_SIZE + crypto_box_NONCEBYTES, - sizeof(ping_id) + num_nodes * sizeof(Node_format) + ENCRYPTION_PADDING, plain ); - - if (len != sizeof(ping_id) + num_nodes * sizeof(Node_format)) - return 1; - - memcpy(&ping_id, plain, sizeof(ping_id)); - - if (!is_gettingnodes(dht, source, ping_id)) - return 1; - - Node_format nodes_list[MAX_SENT_NODES]; - memcpy(nodes_list, plain + sizeof(ping_id), num_nodes * sizeof(Node_format)); - - addto_lists(dht, source, packet + 1); - - uint32_t i; - - for (i = 0; i < num_nodes; ++i) { - send_ping_request(dht->ping, dht->c, nodes_list[i].ip_port, (clientid_t *) &nodes_list[i].client_id); - returnedip_ports(dht, nodes_list[i].ip_port, nodes_list[i].client_id, packet + 1); - } - - return 0; -} - -/*----------------------------------------------------------------------------------*/ -/*------------------------END of packet handling functions--------------------------*/ - -int DHT_addfriend(DHT *dht, uint8_t *client_id) -{ - if (friend_number(dht, client_id) != -1) /*Is friend already in DHT?*/ - return 1; - - DHT_Friend *temp; - temp = realloc(dht->friends_list, sizeof(DHT_Friend) * (dht->num_friends + 1)); - - if (temp == NULL) - return 1; - - dht->friends_list = temp; - memset(&dht->friends_list[dht->num_friends], 0, sizeof(DHT_Friend)); - memcpy(dht->friends_list[dht->num_friends].client_id, client_id, CLIENT_ID_SIZE); - - dht->friends_list[dht->num_friends].NATping_id = ((uint64_t)random_int() << 32) + random_int(); - ++dht->num_friends; - return 0; -} - -int DHT_delfriend(DHT *dht, uint8_t *client_id) -{ - uint32_t i; - DHT_Friend *temp; - - for (i = 0; i < dht->num_friends; ++i) { - /* Equal */ - if (id_equal(dht->friends_list[i].client_id, client_id)) { - --dht->num_friends; - - if (dht->num_friends != i) { - memcpy( dht->friends_list[i].client_id, - dht->friends_list[dht->num_friends].client_id, - CLIENT_ID_SIZE ); - } - - if (dht->num_friends == 0) { - free(dht->friends_list); - dht->friends_list = NULL; - return 0; - } - - temp = realloc(dht->friends_list, sizeof(DHT_Friend) * (dht->num_friends)); - - if (temp == NULL) - return 1; - - dht->friends_list = temp; - return 0; - } - } - - return 1; -} - -/* TODO: Optimize this. */ -IP_Port DHT_getfriendip(DHT *dht, uint8_t *client_id) -{ - uint32_t i, j; - uint64_t temp_time = unix_time(); - IP_Port empty = {{{0}}, 0}; - - for (i = 0; i < dht->num_friends; ++i) { - /* Equal */ - if (id_equal(dht->friends_list[i].client_id, client_id)) { - for (j = 0; j < MAX_FRIEND_CLIENTS; ++j) { - if (id_equal(dht->friends_list[i].client_list[j].client_id, client_id) - && !is_timeout(temp_time, dht->friends_list[i].client_list[j].timestamp, BAD_NODE_TIMEOUT)) - return dht->friends_list[i].client_list[j].ip_port; - } - - return empty; - } - } - - empty.ip.i = 1; - return empty; -} - -/* Ping each client in the "friends" list every PING_INTERVAL seconds. Send a get nodes request - * every GET_NODE_INTERVAL seconds to a random good node for each "friend" in our "friends" list. - */ -static void do_DHT_friends(DHT *dht) -{ - uint32_t i, j; - uint64_t temp_time = unix_time(); - uint32_t rand_node; - uint32_t index[MAX_FRIEND_CLIENTS]; - - for (i = 0; i < dht->num_friends; ++i) { - uint32_t num_nodes = 0; - - for (j = 0; j < MAX_FRIEND_CLIENTS; ++j) { - /* if node is not dead. */ - if (!is_timeout(temp_time, dht->friends_list[i].client_list[j].timestamp, Kill_NODE_TIMEOUT)) { - if ((dht->friends_list[i].client_list[j].last_pinged + PING_INTERVAL) <= temp_time) { - send_ping_request(dht->ping, dht->c, dht->friends_list[i].client_list[j].ip_port, - (clientid_t *) &dht->friends_list[i].client_list[j].client_id ); - dht->friends_list[i].client_list[j].last_pinged = temp_time; - } - - /* if node is good. */ - if (!is_timeout(temp_time, dht->friends_list[i].client_list[j].timestamp, BAD_NODE_TIMEOUT)) { - index[num_nodes] = j; - ++num_nodes; - } - } - } - - if (dht->friends_list[i].lastgetnode + GET_NODE_INTERVAL <= temp_time && num_nodes != 0) { - rand_node = rand() % num_nodes; - getnodes(dht, dht->friends_list[i].client_list[index[rand_node]].ip_port, - dht->friends_list[i].client_list[index[rand_node]].client_id, - dht->friends_list[i].client_id ); - dht->friends_list[i].lastgetnode = temp_time; - } - } -} - -/* Ping each client in the close nodes list every PING_INTERVAL seconds. - * Send a get nodes request every GET_NODE_INTERVAL seconds to a random good node in the list. - */ -static void do_Close(DHT *dht) -{ - uint32_t i; - uint64_t temp_time = unix_time(); - uint32_t num_nodes = 0; - uint32_t rand_node; - uint32_t index[LCLIENT_LIST]; - - for (i = 0; i < LCLIENT_LIST; ++i) { - /* if node is not dead. */ - if (!is_timeout(temp_time, dht->close_clientlist[i].timestamp, Kill_NODE_TIMEOUT)) { - if ((dht->close_clientlist[i].last_pinged + PING_INTERVAL) <= temp_time) { - send_ping_request(dht->ping, dht->c, dht->close_clientlist[i].ip_port, - (clientid_t *) &dht->close_clientlist[i].client_id ); - dht->close_clientlist[i].last_pinged = temp_time; - } - - /* if node is good. */ - if (!is_timeout(temp_time, dht->close_clientlist[i].timestamp, BAD_NODE_TIMEOUT)) { - index[num_nodes] = i; - ++num_nodes; - } - } - } - - if (dht->close_lastgetnodes + GET_NODE_INTERVAL <= temp_time && num_nodes != 0) { - rand_node = rand() % num_nodes; - getnodes(dht, dht->close_clientlist[index[rand_node]].ip_port, - dht->close_clientlist[index[rand_node]].client_id, - dht->c->self_public_key ); - dht->close_lastgetnodes = temp_time; - } -} - -void DHT_bootstrap(DHT *dht, IP_Port ip_port, uint8_t *public_key) -{ - getnodes(dht, ip_port, public_key, dht->c->self_public_key); - send_ping_request(dht->ping, dht->c, ip_port, (clientid_t *) public_key); -} - -/* send the given packet to node with client_id - * returns -1 if failure - */ -int route_packet(DHT *dht, uint8_t *client_id, uint8_t *packet, uint32_t length) -{ - uint32_t i; - - for (i = 0; i < LCLIENT_LIST; ++i) { - if (id_equal(client_id, dht->close_clientlist[i].client_id)) - return sendpacket(dht->c->lossless_udp->net->sock, dht->close_clientlist[i].ip_port, packet, length); - } - - return -1; -} - -/* Puts all the different ips returned by the nodes for a friend_num into array ip_portlist - * ip_portlist must be at least MAX_FRIEND_CLIENTS big - * returns the number of ips returned - * return 0 if we are connected to friend or if no ips were found. - * returns -1 if no such friend - */ -static int friend_iplist(DHT *dht, IP_Port *ip_portlist, uint16_t friend_num) -{ - int num_ips = 0; - uint32_t i; - uint64_t temp_time = unix_time(); - - if (friend_num >= dht->num_friends) - return -1; - - DHT_Friend *friend = &dht->friends_list[friend_num]; - Client_data *client; - - for (i = 0; i < MAX_FRIEND_CLIENTS; ++i) { - client = &friend->client_list[i]; - - /*If ip is not zero and node is good */ - if (client->ret_ip_port.ip.i != 0 && !is_timeout(temp_time, client->ret_timestamp, BAD_NODE_TIMEOUT)) { - - if (id_equal(client->client_id, friend->client_id)) - return 0; - - ip_portlist[num_ips] = client->ret_ip_port; - ++num_ips; - } - } - - return num_ips; -} - - -/* Send the following packet to everyone who tells us they are connected to friend_id - * returns the number of nodes it sent the packet to - * - * Only works if more than (MAX_FRIEND_CLIENTS / 2) return an ip for friend. - */ -int route_tofriend(DHT *dht, uint8_t *friend_id, uint8_t *packet, uint32_t length) -{ - int num = friend_number(dht, friend_id); - - if (num == -1) - return 0; - - uint32_t i, sent = 0; - - IP_Port ip_list[MAX_FRIEND_CLIENTS]; - int ip_num = friend_iplist(dht, ip_list, num); - - if (ip_num < (MAX_FRIEND_CLIENTS / 2)) - return 0; - - uint64_t temp_time = unix_time(); - DHT_Friend *friend = &dht->friends_list[num]; - Client_data *client; - - for (i = 0; i < MAX_FRIEND_CLIENTS; ++i) { - client = &friend->client_list[i]; - - /*If ip is not zero and node is good */ - if (client->ret_ip_port.ip.i != 0 && !is_timeout(temp_time, client->ret_timestamp, BAD_NODE_TIMEOUT)) { - if (sendpacket(dht->c->lossless_udp->net->sock, client->ip_port, packet, length) == length) - ++sent; - } - } - - return sent; -} - -/* Send the following packet to one random person who tells us they are connected to friend_id -* returns the number of nodes it sent the packet to -*/ -static int routeone_tofriend(DHT *dht, uint8_t *friend_id, uint8_t *packet, uint32_t length) -{ - int num = friend_number(dht, friend_id); - - if (num == -1) - return 0; - - DHT_Friend *friend = &dht->friends_list[num]; - Client_data *client; - - IP_Port ip_list[MAX_FRIEND_CLIENTS]; - int n = 0; - uint32_t i; - uint64_t temp_time = unix_time(); - - for (i = 0; i < MAX_FRIEND_CLIENTS; ++i) { - client = &friend->client_list[i]; - - /*If ip is not zero and node is good */ - if (client->ret_ip_port.ip.i != 0 && !is_timeout(temp_time, client->ret_timestamp, BAD_NODE_TIMEOUT)) { - ip_list[n] = client->ip_port; - ++n; - } - } - - if (n < 1) - return 0; - - if (sendpacket(dht->c->lossless_udp->net->sock, ip_list[rand() % n], packet, length) == length) - return 1; - - return 0; -} - -/* Puts all the different ips returned by the nodes for a friend_id into array ip_portlist - * ip_portlist must be at least MAX_FRIEND_CLIENTS big - * returns the number of ips returned - * return 0 if we are connected to friend or if no ips were found. - * returns -1 if no such friend - */ -int friend_ips(DHT *dht, IP_Port *ip_portlist, uint8_t *friend_id) -{ - uint32_t i; - - for (i = 0; i < dht->num_friends; ++i) { - /* Equal */ - if (id_equal(dht->friends_list[i].client_id, friend_id)) - return friend_iplist(dht, ip_portlist, i); - } - - return -1; -} - -/*----------------------------------------------------------------------------------*/ -/*---------------------BEGINNING OF NAT PUNCHING FUNCTIONS--------------------------*/ - -static int send_NATping(DHT *dht, uint8_t *public_key, uint64_t ping_id, uint8_t type) -{ - uint8_t data[sizeof(uint64_t) + 1]; - uint8_t packet[MAX_DATA_SIZE]; - - int num = 0; - - data[0] = type; - memcpy(data + 1, &ping_id, sizeof(uint64_t)); - /* 254 is NAT ping request packet id */ - int len = create_request(dht->c->self_public_key, dht->c->self_secret_key, packet, public_key, data, - sizeof(uint64_t) + 1, CRYPTO_PACKET_NAT_PING); - - if (len == -1) - return -1; - - if (type == 0) /*If packet is request use many people to route it*/ - num = route_tofriend(dht, public_key, packet, len); - else if (type == 1) /*If packet is response use only one person to route it*/ - num = routeone_tofriend(dht, public_key, packet, len); - - if (num == 0) - return -1; - - return num; -} - -/* Handle a received ping request for */ -static int handle_NATping(void *object, IP_Port source, uint8_t *source_pubkey, uint8_t *packet, uint32_t length) -{ - DHT *dht = object; - uint64_t ping_id; - memcpy(&ping_id, packet + 1, sizeof(uint64_t)); - - int friendnumber = friend_number(dht, source_pubkey); - - if (friendnumber == -1) - return 1; - - DHT_Friend *friend = &dht->friends_list[friendnumber]; - - if (packet[0] == NAT_PING_REQUEST) { - /* 1 is reply */ - send_NATping(dht, source_pubkey, ping_id, NAT_PING_RESPONSE); - friend->recvNATping_timestamp = unix_time(); - return 0; - } else if (packet[0] == NAT_PING_RESPONSE) { - if (friend->NATping_id == ping_id) { - friend->NATping_id = ((uint64_t)random_int() << 32) + random_int(); - friend->hole_punching = 1; - return 0; - } - } - - return 1; -} - -/* Get the most common ip in the ip_portlist - * Only return ip if it appears in list min_num or more - * len must not be bigger than MAX_FRIEND_CLIENTS - * return ip of 0 if failure - */ -static IP NAT_commonip(IP_Port *ip_portlist, uint16_t len, uint16_t min_num) -{ - IP zero = {{0}}; - - if (len > MAX_FRIEND_CLIENTS) - return zero; - - uint32_t i, j; - uint16_t numbers[MAX_FRIEND_CLIENTS] = {0}; - - for (i = 0; i < len; ++i) { - for (j = 0; j < len; ++j) { - if (ip_portlist[i].ip.i == ip_portlist[j].ip.i) - ++numbers[i]; - } - - if (numbers[i] >= min_num) - return ip_portlist[i].ip; - } - - return zero; -} - -/* Return all the ports for one ip in a list - * portlist must be at least len long - * where len is the length of ip_portlist - * returns the number of ports and puts the list of ports in portlist - */ -static uint16_t NAT_getports(uint16_t *portlist, IP_Port *ip_portlist, uint16_t len, IP ip) -{ - uint32_t i; - uint16_t num = 0; - - for (i = 0; i < len; ++i) { - if (ip_portlist[i].ip.i == ip.i) { - portlist[num] = ntohs(ip_portlist[i].port); - ++num; - } - } - - return num; -} - -static void punch_holes(DHT *dht, IP ip, uint16_t *port_list, uint16_t numports, uint16_t friend_num) -{ - if (numports > MAX_FRIEND_CLIENTS || numports == 0) - return; - - uint32_t i; - uint32_t top = dht->friends_list[friend_num].punching_index + MAX_PUNCHING_PORTS; - - for (i = dht->friends_list[friend_num].punching_index; i != top; i++) { - /*TODO: improve port guessing algorithm*/ - uint16_t port = port_list[(i / 2) % numports] + (i / (2 * numports)) * ((i % 2) ? -1 : 1); - IP_Port pinging = {ip, htons(port)}; - send_ping_request(dht->ping, dht->c, pinging, (clientid_t *) &dht->friends_list[friend_num].client_id); - } - - dht->friends_list[friend_num].punching_index = i; -} - -static void do_NAT(DHT *dht) -{ - uint32_t i; - uint64_t temp_time = unix_time(); - - for (i = 0; i < dht->num_friends; ++i) { - IP_Port ip_list[MAX_FRIEND_CLIENTS]; - int num = friend_iplist(dht, ip_list, i); - - /*If already connected or friend is not online don't try to hole punch*/ - if (num < MAX_FRIEND_CLIENTS / 2) - continue; - - if (dht->friends_list[i].NATping_timestamp + PUNCH_INTERVAL < temp_time) { - send_NATping(dht, dht->friends_list[i].client_id, dht->friends_list[i].NATping_id, NAT_PING_REQUEST); - dht->friends_list[i].NATping_timestamp = temp_time; - } - - if (dht->friends_list[i].hole_punching == 1 && - dht->friends_list[i].punching_timestamp + PUNCH_INTERVAL < temp_time && - dht->friends_list[i].recvNATping_timestamp + PUNCH_INTERVAL * 2 >= temp_time) { - - IP ip = NAT_commonip(ip_list, num, MAX_FRIEND_CLIENTS / 2); - - if (ip.i == 0) - continue; - - uint16_t port_list[MAX_FRIEND_CLIENTS]; - uint16_t numports = NAT_getports(port_list, ip_list, num, ip); - punch_holes(dht, ip, port_list, numports, i); - - dht->friends_list[i].punching_timestamp = temp_time; - dht->friends_list[i].hole_punching = 0; - } - } -} - -/*----------------------------------------------------------------------------------*/ -/*-----------------------END OF NAT PUNCHING FUNCTIONS------------------------------*/ - - -/* Add nodes to the toping list - all nodes in this list are pinged every TIME_TOPING seconds - and are then removed from the list. - if the list is full the nodes farthest from our client_id are replaced - the purpose of this list is to enable quick integration of new nodes into the - network while preventing amplification attacks. - return 0 if node was added - return -1 if node was not added */ -int add_toping(DHT *dht, uint8_t *client_id, IP_Port ip_port) -{ - if (ip_port.ip.i == 0) - return -1; - - uint32_t i; - - for (i = 0; i < MAX_TOPING; ++i) { - if (dht->toping[i].ip_port.ip.i == 0) { - memcpy(dht->toping[i].client_id, client_id, CLIENT_ID_SIZE); - dht->toping[i].ip_port.ip.i = ip_port.ip.i; - dht->toping[i].ip_port.port = ip_port.port; - return 0; - } - } - - for (i = 0; i < MAX_TOPING; ++i) { - if (id_closest(dht->c->self_public_key, dht->toping[i].client_id, client_id) == 2) { - memcpy(dht->toping[i].client_id, client_id, CLIENT_ID_SIZE); - dht->toping[i].ip_port.ip.i = ip_port.ip.i; - dht->toping[i].ip_port.port = ip_port.port; - return 0; - } - } - - return -1; -} - -/*Ping all the valid nodes in the toping list every TIME_TOPING seconds - this function must be run at least once every TIME_TOPING seconds*/ -static void do_toping(DHT *dht) -{ - uint64_t temp_time = unix_time(); - - if (!is_timeout(temp_time, dht->last_toping, TIME_TOPING)) - return; - - dht->last_toping = temp_time; - uint32_t i; - - for (i = 0; i < MAX_TOPING; ++i) { - if (dht->toping[i].ip_port.ip.i == 0) - return; - - send_ping_request(dht->ping, dht->c, dht->toping[i].ip_port, (clientid_t *) dht->toping[i].client_id); - dht->toping[i].ip_port.ip.i = 0; - } -} - - -DHT *new_DHT(Net_Crypto *c) -{ - if (c == NULL) - return NULL; - - DHT *temp = calloc(1, sizeof(DHT)); - - if (temp == NULL) - return NULL; - - temp->ping = new_ping(); - - if (temp->ping == NULL) { - kill_DHT(temp); - return NULL; - } - - temp->c = c; - networking_registerhandler(c->lossless_udp->net, NET_PACKET_PING_REQUEST, &handle_ping_request, temp); - networking_registerhandler(c->lossless_udp->net, NET_PACKET_PING_RESPONSE, &handle_ping_response, temp); - networking_registerhandler(c->lossless_udp->net, NET_PACKET_GET_NODES, &handle_getnodes, temp); - networking_registerhandler(c->lossless_udp->net, NET_PACKET_SEND_NODES, &handle_sendnodes, temp); - init_cryptopackets(temp); - cryptopacket_registerhandler(c, CRYPTO_PACKET_NAT_PING, &handle_NATping, temp); - return temp; -} - -void do_DHT(DHT *dht) -{ - do_Close(dht); - do_DHT_friends(dht); - do_NAT(dht); - do_toping(dht); -} -void kill_DHT(DHT *dht) -{ - kill_ping(dht->ping); - free(dht->friends_list); - free(dht); -} - -/* get the size of the DHT (for saving) */ -uint32_t DHT_size(DHT *dht) -{ - return sizeof(dht->close_clientlist) + sizeof(DHT_Friend) * dht->num_friends; -} - -/* save the DHT in data where data is an array of size DHT_size() */ -void DHT_save(DHT *dht, uint8_t *data) -{ - memcpy(data, dht->close_clientlist, sizeof(dht->close_clientlist)); - memcpy(data + sizeof(dht->close_clientlist), dht->friends_list, sizeof(DHT_Friend) * dht->num_friends); -} - -/* load the DHT from data of size size; - * return -1 if failure - * return 0 if success - */ -int DHT_load(DHT *dht, uint8_t *data, uint32_t size) -{ - if (size < sizeof(dht->close_clientlist)) - return -1; - - if ((size - sizeof(dht->close_clientlist)) % sizeof(DHT_Friend) != 0) - return -1; - - uint32_t i, j; - uint16_t temp; - /* uint64_t temp_time = unix_time(); */ - - Client_data *client; - - temp = (size - sizeof(dht->close_clientlist)) / sizeof(DHT_Friend); - - if (temp != 0) { - DHT_Friend *tempfriends_list = (DHT_Friend *)(data + sizeof(dht->close_clientlist)); - - for (i = 0; i < temp; ++i) { - DHT_addfriend(dht, tempfriends_list[i].client_id); - - for (j = 0; j < MAX_FRIEND_CLIENTS; ++j) { - client = &tempfriends_list[i].client_list[j]; - - if (client->timestamp != 0) - getnodes(dht, client->ip_port, client->client_id, tempfriends_list[i].client_id); - } - } - } - - Client_data *tempclose_clientlist = (Client_data *)data; - - for (i = 0; i < LCLIENT_LIST; ++i) { - if (tempclose_clientlist[i].timestamp != 0) - DHT_bootstrap(dht, tempclose_clientlist[i].ip_port, - tempclose_clientlist[i].client_id ); - } - - return 0; -} - -/* returns 0 if we are not connected to the DHT - * returns 1 if we are - */ -int DHT_isconnected(DHT *dht) -{ - uint32_t i; - uint64_t temp_time = unix_time(); - - for (i = 0; i < LCLIENT_LIST; ++i) { - if (!is_timeout(temp_time, dht->close_clientlist[i].timestamp, BAD_NODE_TIMEOUT)) - return 1; - } - - return 0; -} diff --git a/core/DHT.h b/core/DHT.h deleted file mode 100644 index 6295581b..00000000 --- a/core/DHT.h +++ /dev/null @@ -1,193 +0,0 @@ -/* DHT.h - * - * An implementation of the DHT as seen in http://wiki.tox.im/index.php/DHT - * - * Copyright (C) 2013 Tox project All Rights Reserved. - * - * This file is part of Tox. - * - * Tox 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. - * - * Tox 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 Tox. If not, see . - * - */ - -#ifndef DHT_H -#define DHT_H - -#include "net_crypto.h" - -#ifdef __cplusplus -extern "C" { -#endif - - -/* size of the client_id in bytes */ -#define CLIENT_ID_SIZE crypto_box_PUBLICKEYBYTES - -/* maximum number of clients stored per friend. */ -#define MAX_FRIEND_CLIENTS 8 - -/* A list of the clients mathematically closest to ours. */ -#define LCLIENT_LIST 32 - -/* The list of ip ports along with the ping_id of what we sent them and a timestamp */ -#define LPING_ARRAY 256 //NOTE Deprecated (doesn't do anything) - -#define LSEND_NODES_ARRAY LPING_ARRAY/2 - -/*Maximum newly announced nodes to ping per TIME_TOPING seconds*/ -#define MAX_TOPING 16 - -typedef struct { - uint8_t client_id[CLIENT_ID_SIZE]; - IP_Port ip_port; - uint64_t timestamp; - uint64_t last_pinged; - - /* Returned by this node. Either our friend or us */ - IP_Port ret_ip_port; - uint64_t ret_timestamp; -} Client_data; - -/*----------------------------------------------------------------------------------*/ - -typedef struct { - uint8_t client_id[CLIENT_ID_SIZE]; - Client_data client_list[MAX_FRIEND_CLIENTS]; - - /* time at which the last get_nodes request was sent. */ - uint64_t lastgetnode; - - /* Symetric NAT hole punching stuff */ - - /* 1 if currently hole punching, otherwise 0 */ - uint8_t hole_punching; - uint32_t punching_index; - uint64_t punching_timestamp; - uint64_t recvNATping_timestamp; - uint64_t NATping_id; - uint64_t NATping_timestamp; -} DHT_Friend; - -typedef struct { - uint8_t client_id[CLIENT_ID_SIZE]; - IP_Port ip_port; -} Node_format; - -typedef struct { - IP_Port ip_port; - uint64_t ping_id; - uint64_t timestamp; -} Pinged; - -/*----------------------------------------------------------------------------------*/ -typedef struct { - Net_Crypto *c; - Client_data close_clientlist[LCLIENT_LIST]; - DHT_Friend *friends_list; - uint16_t num_friends; - Pinged send_nodes[LSEND_NODES_ARRAY]; - Node_format toping[MAX_TOPING]; - uint64_t last_toping; - uint64_t close_lastgetnodes; - void *ping; -} DHT; -/*----------------------------------------------------------------------------------*/ - -Client_data *DHT_get_close_list(DHT *dht); - -/* Add a new friend to the friends list - client_id must be CLIENT_ID_SIZE bytes long. - returns 0 if success - returns 1 if failure (friends list is full) */ -int DHT_addfriend(DHT *dht, uint8_t *client_id); - -/* Delete a friend from the friends list - client_id must be CLIENT_ID_SIZE bytes long. - returns 0 if success - returns 1 if failure (client_id not in friends list) */ -int DHT_delfriend(DHT *dht, uint8_t *client_id); - -/* Get ip of friend - client_id must be CLIENT_ID_SIZE bytes long. - ip must be 4 bytes long. - port must be 2 bytes long. - returns ip if success - returns ip of 0 if failure (This means the friend is either offline or we have not found him yet.) - returns ip of 1 if friend is not in list. */ -IP_Port DHT_getfriendip(DHT *dht, uint8_t *client_id); - -/* Run this function at least a couple times per second (It's the main loop) */ -void do_DHT(DHT *dht); - -/* Use this function to bootstrap the client - Sends a get nodes request to the given node with ip port and public_key */ -void DHT_bootstrap(DHT *dht, IP_Port ip_port, uint8_t *public_key); - -/* Add nodes to the toping list - all nodes in this list are pinged every TIME_TOPING seconds - and are then removed from the list. - if the list is full the nodes farthest from our client_id are replaced - the purpose of this list is to enable quick integration of new nodes into the - network while preventing amplification attacks. - return 0 if node was added - return -1 if node was not added */ -int add_toping(DHT *dht, uint8_t *client_id, IP_Port ip_port); - -/* ROUTING FUNCTIONS */ - -/* send the given packet to node with client_id - returns -1 if failure */ -int route_packet(DHT *dht, uint8_t *client_id, uint8_t *packet, uint32_t length); - -/* Send the following packet to everyone who tells us they are connected to friend_id - returns the number of nodes it sent the packet to */ -int route_tofriend(DHT *dht, uint8_t *friend_id, uint8_t *packet, uint32_t length); - -/* NAT PUNCHING FUNCTIONS */ - -/* Puts all the different ips returned by the nodes for a friend_id into array ip_portlist - ip_portlist must be at least MAX_FRIEND_CLIENTS big - returns the number of ips returned - returns -1 if no such friend*/ -int friend_ips(DHT *dht, IP_Port *ip_portlist, uint8_t *friend_id); - -/* SAVE/LOAD functions */ - -/* get the size of the DHT (for saving) */ -uint32_t DHT_size(DHT *dht); - -/* save the DHT in data where data is an array of size DHT_size() */ -void DHT_save(DHT *dht, uint8_t *data); - -/* init DHT */ -DHT *new_DHT(Net_Crypto *c); - -void kill_DHT(DHT *dht); - -/* load the DHT from data of size size; - return -1 if failure - return 0 if success */ -int DHT_load(DHT *dht, uint8_t *data, uint32_t size); - -/* returns 0 if we are not connected to the DHT - returns 1 if we are */ -int DHT_isconnected(DHT *dht); - -void addto_lists(DHT *dht, IP_Port ip_port, uint8_t *client_id); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/core/LAN_discovery.c b/core/LAN_discovery.c deleted file mode 100644 index 49f52ce7..00000000 --- a/core/LAN_discovery.c +++ /dev/null @@ -1,152 +0,0 @@ -/* LAN_discovery.c - * - * LAN discovery implementation. - * - * Copyright (C) 2013 Tox project All Rights Reserved. - * - * This file is part of Tox. - * - * Tox 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. - * - * Tox 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 Tox. If not, see . - * - */ - -#include "LAN_discovery.h" - -#define MAX_INTERFACES 16 - -#ifdef __linux -/* get the first working broadcast address that's not from "lo" - * returns higher than 0 on success - * returns 0 on error */ -static uint32_t get_broadcast(void) -{ - /* not sure how many platforms this will - * run on, so it's wrapped in __linux for now */ - struct sockaddr_in *sock_holder = NULL; - struct ifreq i_faces[MAX_INTERFACES]; - struct ifconf ifconf; - int count = 0; - int sock = 0; - int i = 0; - - /* configure ifconf for the ioctl call */ - if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) { - perror("[!] get_broadcast: socket() error"); - return 0; - } - - memset(i_faces, 0, sizeof(struct ifreq) * MAX_INTERFACES); - - ifconf.ifc_buf = (char *)i_faces; - ifconf.ifc_len = sizeof(i_faces); - count = ifconf.ifc_len / sizeof(struct ifreq); - - if (ioctl(sock, SIOCGIFCONF, &ifconf) < 0) { - perror("get_broadcast: ioctl() error"); - return 0; - } - - for (i = 0; i < count; i++) { - /* skip the loopback interface, as it's useless */ - if (strcmp(i_faces[i].ifr_name, "lo") != 0) { - if (ioctl(sock, SIOCGIFBRDADDR, &i_faces[i]) < 0) { - perror("[!] get_broadcast: ioctl error"); - return 0; - } - - /* just to clarify where we're getting the values from */ - sock_holder = (struct sockaddr_in *)&i_faces[i].ifr_broadaddr; - break; - } - } - - close(sock); - - if (sock_holder == NULL) { - perror("[!] no broadcast device found"); - return 0; - } - - return sock_holder->sin_addr.s_addr; -} -#endif - -/* Return the broadcast ip */ -static IP broadcast_ip(void) -{ - IP ip; -#ifdef __linux - ip.i = get_broadcast(); - - if (ip.i == 0) - /* error errored, but try anyway? */ - ip.i = ~0; - -#else - ip.i = ~0; -#endif - return ip; -} - -/*return 0 if ip is a LAN ip - return -1 if it is not */ -static int LAN_ip(IP ip) -{ - if (ip.c[0] == 127)/* Loopback */ - return 0; - - if (ip.c[0] == 10)/* 10.0.0.0 to 10.255.255.255 range */ - return 0; - - if (ip.c[0] == 172 && ip.c[1] >= 16 && ip.c[1] <= 31)/* 172.16.0.0 to 172.31.255.255 range */ - return 0; - - if (ip.c[0] == 192 && ip.c[1] == 168) /* 192.168.0.0 to 192.168.255.255 range */ - return 0; - - if (ip.c[0] == 169 && ip.c[1] == 254 && ip.c[2] != 0 && ip.c[2] != 255)/* 169.254.1.0 to 169.254.254.255 range */ - return 0; - - return -1; -} - -static int handle_LANdiscovery(void *object, IP_Port source, uint8_t *packet, uint32_t length) -{ - DHT *dht = object; - - if (LAN_ip(source.ip) == -1) - return 1; - - if (length != crypto_box_PUBLICKEYBYTES + 1) - return 1; - - DHT_bootstrap(dht, source, packet + 1); - return 0; -} - - -int send_LANdiscovery(uint16_t port, Net_Crypto *c) -{ - uint8_t data[crypto_box_PUBLICKEYBYTES + 1]; - data[0] = NET_PACKET_LAN_DISCOVERY; - memcpy(data + 1, c->self_public_key, crypto_box_PUBLICKEYBYTES); - IP_Port ip_port = {broadcast_ip(), port}; - return sendpacket(c->lossless_udp->net->sock, ip_port, data, 1 + crypto_box_PUBLICKEYBYTES); -} - - -void LANdiscovery_init(DHT *dht) -{ - networking_registerhandler(dht->c->lossless_udp->net, NET_PACKET_LAN_DISCOVERY, &handle_LANdiscovery, dht); -} diff --git a/core/LAN_discovery.h b/core/LAN_discovery.h deleted file mode 100644 index 5a790331..00000000 --- a/core/LAN_discovery.h +++ /dev/null @@ -1,55 +0,0 @@ -/* LAN_discovery.h - * - * LAN discovery implementation. - * - * Copyright (C) 2013 Tox project All Rights Reserved. - * - * This file is part of Tox. - * - * Tox 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. - * - * Tox 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 Tox. If not, see . - * - */ - - -#ifndef LAN_DISCOVERY_H -#define LAN_DISCOVERY_H - - -#include "DHT.h" - -/* used for get_broadcast() */ -#ifdef __linux -#include -#include -#include -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -/*Send a LAN discovery pcaket to the broadcast address with port port*/ -int send_LANdiscovery(uint16_t port, Net_Crypto *c); - - -/* sets up packet handlers */ -void LANdiscovery_init(DHT *dht); - - - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/core/Lossless_UDP.c b/core/Lossless_UDP.c deleted file mode 100644 index c30eb903..00000000 --- a/core/Lossless_UDP.c +++ /dev/null @@ -1,842 +0,0 @@ -/* Lossless_UDP.c - * - * An implementation of the Lossless_UDP protocol as seen in http://wiki.tox.im/index.php/Lossless_UDP - * - * Copyright (C) 2013 Tox project All Rights Reserved. - * - * This file is part of Tox. - * - * Tox 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. - * - * Tox 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 Tox. If not, see . - * - */ - -/* - * TODO: clean this file a bit. - * There are a couple of useless variables to get rid of. - */ - -#include "Lossless_UDP.h" - - -/* Functions */ - -/* - * Get connection id from IP_Port - * Return -1 if there are no connections like we are looking for - * Return id if it found it - */ -int getconnection_id(Lossless_UDP *ludp, IP_Port ip_port) -{ - uint32_t i; - - for (i = 0; i < ludp->connections_length; ++i) { - if (ludp->connections[i].ip_port.ip.i == ip_port.ip.i && - ludp->connections[i].ip_port.port == ip_port.port && - ludp->connections[i].status > 0) - return i; - } - - return -1; -} - - -/* - * Generate a handshake_id which depends on the ip_port. - * This function will always give one unique handshake_id per ip_port. - * - * TODO: make this better - */ -static uint32_t handshake_id(Lossless_UDP *ludp, IP_Port source) -{ - uint32_t id = 0, i; - - for (i = 0; i < 6; ++i) { - if (ludp->randtable[i][((uint8_t *)&source)[i]] == 0) - ludp->randtable[i][((uint8_t *)&source)[i]] = random_int(); - - id ^= ludp->randtable[i][((uint8_t *)&source)[i]]; - } - - if (id == 0) /* id can't be zero */ - id = 1; - - return id; -} - -/* - * Change the hanshake id associated with that ip_port - * - * TODO: make this better - */ -static void change_handshake(Lossless_UDP *ludp, IP_Port source) -{ - uint8_t rand = random_int() % 4; - ludp->randtable[rand][((uint8_t *)&source)[rand]] = random_int(); -} - -/* - * Initialize a new connection to ip_port - * Returns an integer corresponding to the connection idt - * Return -1 if it could not initialize the connectiont - * If there already was an existing connection to that ip_port return its number. - */ -int new_connection(Lossless_UDP *ludp, IP_Port ip_port) -{ - int connect = getconnection_id(ludp, ip_port); - - if (connect != -1) - return connect; - - if (ludp->connections_number == ludp->connections_length) { - Connection *temp; - temp = realloc(ludp->connections, sizeof(Connection) * (ludp->connections_length + 1)); - - if (temp == NULL) - return -1; - - memset(&temp[ludp->connections_length], 0, sizeof(Connection)); - ++ludp->connections_length; - ludp->connections = temp; - } - - uint32_t i; - - for (i = 0; i < ludp->connections_length; ++i) { - if (ludp->connections[i].status == 0) { - memset(&ludp->connections[i], 0, sizeof(Connection)); - uint32_t handshake_id1 = handshake_id(ludp, ip_port); - - ludp->connections[i] = (Connection) { - .ip_port = ip_port, - .status = 1, - .inbound = 0, - .handshake_id1 = handshake_id1, - .sent_packetnum = handshake_id1, - .sendbuff_packetnum = handshake_id1, - .successful_sent = handshake_id1, - .SYNC_rate = SYNC_RATE, - .data_rate = DATA_SYNC_RATE, - .last_recvSYNC = current_time(), - .last_sent = current_time(), - .killat = ~0, - .send_counter = 0, - /* add randomness to timeout to prevent connections getting stuck in a loop. */ - .timeout = CONNEXION_TIMEOUT + rand() % CONNEXION_TIMEOUT - }; - ++ludp->connections_number; - - return i; - } - } - - return -1; -} - -/* - * Initialize a new inbound connection from ip_port - * Returns an integer corresponding to the connection id. - * Return -1 if it could not initialize the connection. - */ -static int new_inconnection(Lossless_UDP *ludp, IP_Port ip_port) -{ - if (getconnection_id(ludp, ip_port) != -1) - return -1; - - if (ludp->connections_number == ludp->connections_length) { - Connection *temp; - temp = realloc(ludp->connections, sizeof(Connection) * (ludp->connections_length + 1)); - - if (temp == NULL) - return -1; - - memset(&temp[ludp->connections_length], 0, sizeof(Connection)); - ++ludp->connections_length; - ludp->connections = temp; - } - - uint32_t i; - - for (i = 0; i < ludp->connections_length; ++i) { - if (ludp->connections[i].status == 0) { - memset(&ludp->connections[i], 0, sizeof(Connection)); - uint64_t timeout = CONNEXION_TIMEOUT + rand() % CONNEXION_TIMEOUT; - - ludp->connections[i] = (Connection) { - .ip_port = ip_port, - .status = 2, - .inbound = 2, - .SYNC_rate = SYNC_RATE, - .data_rate = DATA_SYNC_RATE, - .last_recvSYNC = current_time(), - .last_sent = current_time(), - .send_counter = 127, - - /* add randomness to timeout to prevent connections getting stuck in a loop. */ - .timeout = timeout, - - /* if this connection isn't handled within the timeout kill it. */ - .killat = current_time() + 1000000UL * timeout - }; - ++ludp->connections_number; - return i; - } - } - - return -1; -} - -/* - * Returns an integer corresponding to the next connection in our incoming connection list. - * Return -1 if there are no new incoming connections in the list. - */ -int incoming_connection(Lossless_UDP *ludp) -{ - uint32_t i; - - for (i = 0; i < ludp->connections_length; ++i) { - if (ludp->connections[i].inbound == 2) { - ludp->connections[i].inbound = 1; - return i; - } - } - - return -1; -} - -/* Try to free some memory from the connections array. */ -static void free_connections(Lossless_UDP *ludp) -{ - uint32_t i; - - for (i = ludp->connections_length; i != 0; --i) - if (ludp->connections[i - 1].status != 0) - break; - - if (ludp->connections_length == i) - return; - - if (i == 0) { - free(ludp->connections); - ludp->connections = NULL; - ludp->connections_length = i; - return; - } - - Connection *temp; - temp = realloc(ludp->connections, sizeof(Connection) * i); - - if (temp == NULL && i != 0) - return; - - ludp->connections = temp; - ludp->connections_length = i; -} - -/* - * Return -1 if it could not kill the connection. - * Return 0 if killed successfully - */ -int kill_connection(Lossless_UDP *ludp, int connection_id) -{ - if (connection_id >= 0 && connection_id < ludp->connections_length) { - if (ludp->connections[connection_id].status > 0) { - ludp->connections[connection_id].status = 0; - change_handshake(ludp, ludp->connections[connection_id].ip_port); - --ludp->connections_number; - free_connections(ludp); - return 0; - } - } - - return -1; -} - -/* - * Kill connection in seconds. - * Return -1 if it can not kill the connection. - * Return 0 if it will kill it. - */ -int kill_connection_in(Lossless_UDP *ludp, int connection_id, uint32_t seconds) -{ - if (connection_id >= 0 && connection_id < ludp->connections_length) { - if (ludp->connections[connection_id].status > 0) { - ludp->connections[connection_id].killat = current_time() + 1000000UL * seconds; - return 0; - } - } - - return -1; -} - -/* - * Check if connection is connected: - * Return 0 no. - * Return 1 if attempting handshake. - * Return 2 if handshake is done. - * Return 3 if fully connected. - * Return 4 if timed out and waiting to be killed. - */ -int is_connected(Lossless_UDP *ludp, int connection_id) -{ - if (connection_id >= 0 && connection_id < ludp->connections_length) - return ludp->connections[connection_id].status; - - return 0; -} - -/* returns the ip_port of the corresponding connection. */ -IP_Port connection_ip(Lossless_UDP *ludp, int connection_id) -{ - if (connection_id >= 0 && connection_id < ludp->connections_length) - return ludp->connections[connection_id].ip_port; - - IP_Port zero = {{{0}}, 0}; - return zero; -} - -/* returns the number of packets in the queue waiting to be successfully sent. */ -uint32_t sendqueue(Lossless_UDP *ludp, int connection_id) -{ - if (connection_id < 0 || connection_id >= ludp->connections_length) - return 0; - - return ludp->connections[connection_id].sendbuff_packetnum - ludp->connections[connection_id].successful_sent; -} - -/* returns the number of packets in the queue waiting to be successfully read with read_packet(...) */ -uint32_t recvqueue(Lossless_UDP *ludp, int connection_id) -{ - if (connection_id < 0 || connection_id >= ludp->connections_length) - return 0; - - return ludp->connections[connection_id].recv_packetnum - ludp->connections[connection_id].successful_read; -} - -/* returns the id of the next packet in the queue - return -1 if no packet in queue */ -char id_packet(Lossless_UDP *ludp, int connection_id) -{ - if (connection_id < 0 || connection_id >= ludp->connections_length) - return -1; - - if (recvqueue(ludp, connection_id) != 0 && ludp->connections[connection_id].status != 0) - return ludp->connections[connection_id].recvbuffer[ludp->connections[connection_id].successful_read % - MAX_QUEUE_NUM].data[0]; - - return -1; -} - -/* return 0 if there is no received data in the buffer. - return length of received packet if successful */ -int read_packet(Lossless_UDP *ludp, int connection_id, uint8_t *data) -{ - if (recvqueue(ludp, connection_id) != 0) { - uint16_t index = ludp->connections[connection_id].successful_read % MAX_QUEUE_NUM; - uint16_t size = ludp->connections[connection_id].recvbuffer[index].size; - memcpy(data, ludp->connections[connection_id].recvbuffer[index].data, size); - ++ludp->connections[connection_id].successful_read; - ludp->connections[connection_id].recvbuffer[index].size = 0; - return size; - } - - return 0; -} - -/* - * Return 0 if data could not be put in packet queue - * Return 1 if data was put into the queue - */ -int write_packet(Lossless_UDP *ludp, int connection_id, uint8_t *data, uint32_t length) -{ - if (length > MAX_DATA_SIZE || length == 0) - return 0; - - if (sendqueue(ludp, connection_id) < BUFFER_PACKET_NUM) { - uint32_t index = ludp->connections[connection_id].sendbuff_packetnum % MAX_QUEUE_NUM; - memcpy(ludp->connections[connection_id].sendbuffer[index].data, data, length); - ludp->connections[connection_id].sendbuffer[index].size = length; - ludp->connections[connection_id].sendbuff_packetnum++; - return 1; - } - - return 0; -} - -/* put the packet numbers the we are missing in requested and return the number */ -uint32_t missing_packets(Lossless_UDP *ludp, int connection_id, uint32_t *requested) -{ - uint32_t number = 0; - uint32_t i; - uint32_t temp; - - /* don't request packets if the buffer is full. */ - if (recvqueue(ludp, connection_id) >= (BUFFER_PACKET_NUM - 1)) - return 0; - - for (i = ludp->connections[connection_id].recv_packetnum; i != ludp->connections[connection_id].osent_packetnum; i++) { - if (ludp->connections[connection_id].recvbuffer[i % MAX_QUEUE_NUM].size == 0) { - temp = htonl(i); - memcpy(requested + number, &temp, 4); - ++number; - } - } - - if (number == 0) - ludp->connections[connection_id].recv_packetnum = ludp->connections[connection_id].osent_packetnum; - - return number; -} - -/* - * BEGIN Packet sending functions - * One per packet type. - * see http://wiki.tox.im/index.php/Lossless_UDP for more information. - */ - -static int send_handshake(Lossless_UDP *ludp, IP_Port ip_port, uint32_t handshake_id1, uint32_t handshake_id2) -{ - uint8_t packet[1 + 4 + 4]; - uint32_t temp; - - packet[0] = NET_PACKET_HANDSHAKE; - temp = htonl(handshake_id1); - memcpy(packet + 1, &temp, 4); - temp = htonl(handshake_id2); - memcpy(packet + 5, &temp, 4); - - return sendpacket(ludp->net->sock, ip_port, packet, sizeof(packet)); -} - -static int send_SYNC(Lossless_UDP *ludp, uint32_t connection_id) -{ - uint8_t packet[(BUFFER_PACKET_NUM * 4 + 4 + 4 + 2)]; - uint16_t index = 0; - - IP_Port ip_port = ludp->connections[connection_id].ip_port; - uint8_t counter = ludp->connections[connection_id].send_counter; - uint32_t recv_packetnum = htonl(ludp->connections[connection_id].recv_packetnum); - uint32_t sent_packetnum = htonl(ludp->connections[connection_id].sent_packetnum); - - uint32_t requested[BUFFER_PACKET_NUM]; - uint32_t number = missing_packets(ludp, connection_id, requested); - - packet[0] = NET_PACKET_SYNC; - index += 1; - memcpy(packet + index, &counter, 1); - index += 1; - memcpy(packet + index, &recv_packetnum, 4); - index += 4; - memcpy(packet + index, &sent_packetnum, 4); - index += 4; - memcpy(packet + index, requested, 4 * number); - - return sendpacket(ludp->net->sock, ip_port, packet, (number * 4 + 4 + 4 + 2)); - -} - -static int send_data_packet(Lossless_UDP *ludp, uint32_t connection_id, uint32_t packet_num) -{ - uint32_t index = packet_num % MAX_QUEUE_NUM; - uint32_t temp; - uint8_t packet[1 + 4 + MAX_DATA_SIZE]; - packet[0] = NET_PACKET_DATA; - temp = htonl(packet_num); - memcpy(packet + 1, &temp, 4); - memcpy(packet + 5, ludp->connections[connection_id].sendbuffer[index].data, - ludp->connections[connection_id].sendbuffer[index].size); - return sendpacket(ludp->net->sock, ludp->connections[connection_id].ip_port, packet, - 1 + 4 + ludp->connections[connection_id].sendbuffer[index].size); -} - -/* sends 1 data packet */ -static int send_DATA(Lossless_UDP *ludp, uint32_t connection_id) -{ - int ret; - uint32_t buffer[BUFFER_PACKET_NUM]; - - if (ludp->connections[connection_id].num_req_paquets > 0) { - ret = send_data_packet(ludp, connection_id, ludp->connections[connection_id].req_packets[0]); - ludp->connections[connection_id].num_req_paquets--; - memcpy(buffer, ludp->connections[connection_id].req_packets + 1, ludp->connections[connection_id].num_req_paquets * 4); - memcpy(ludp->connections[connection_id].req_packets, buffer, ludp->connections[connection_id].num_req_paquets * 4); - return ret; - } - - if (ludp->connections[connection_id].sendbuff_packetnum != ludp->connections[connection_id].sent_packetnum) { - ret = send_data_packet(ludp, connection_id, ludp->connections[connection_id].sent_packetnum); - ludp->connections[connection_id].sent_packetnum++; - return ret; - } - - return 0; -} - -/* - * END of packet sending functions - * - * - * BEGIN Packet handling functions - * One to handle each type of packets we receive - */ - - -/* Return 0 if handled correctly, 1 if packet is bad. */ -static int handle_handshake(void *object, IP_Port source, uint8_t *packet, uint32_t length) -{ - Lossless_UDP *ludp = object; - - if (length != (1 + 4 + 4)) - return 1; - - uint32_t temp; - uint32_t handshake_id1, handshake_id2; - - int connection = getconnection_id(ludp, source); - memcpy(&temp, packet + 1, 4); - handshake_id1 = ntohl(temp); - memcpy(&temp, packet + 5, 4); - handshake_id2 = ntohl(temp); - - if (handshake_id2 == 0 && is_connected(ludp, connection) < 3) { - send_handshake(ludp, source, handshake_id(ludp, source), handshake_id1); - return 0; - } - - if (is_connected(ludp, connection) != 1) - return 1; - - /* if handshake_id2 is what we sent previously as handshake_id1 */ - if (handshake_id2 == ludp->connections[connection].handshake_id1) { - ludp->connections[connection].status = 2; - /* NOTE: is this necessary? - ludp->connections[connection].handshake_id2 = handshake_id1; */ - ludp->connections[connection].orecv_packetnum = handshake_id2; - ludp->connections[connection].osent_packetnum = handshake_id1; - ludp->connections[connection].recv_packetnum = handshake_id1; - ludp->connections[connection].successful_read = handshake_id1; - } - - return 0; -} - -/* returns 1 if sync packet is valid 0 if not. */ -static int SYNC_valid(uint32_t length) -{ - if (length < 4 + 4 + 2) - return 0; - - if (length > (BUFFER_PACKET_NUM * 4 + 4 + 4 + 2) || - ((length - 4 - 4 - 2) % 4) != 0) - return 0; - - return 1; -} - -/* case 1 in handle_SYNC: */ -static int handle_SYNC1(Lossless_UDP *ludp, IP_Port source, uint32_t recv_packetnum, uint32_t sent_packetnum) -{ - if (handshake_id(ludp, source) == recv_packetnum) { - int x = new_inconnection(ludp, source); - - if (x != -1) { - ludp->connections[x].orecv_packetnum = recv_packetnum; - ludp->connections[x].sent_packetnum = recv_packetnum; - ludp->connections[x].sendbuff_packetnum = recv_packetnum; - ludp->connections[x].successful_sent = recv_packetnum; - ludp->connections[x].osent_packetnum = sent_packetnum; - ludp->connections[x].recv_packetnum = sent_packetnum; - ludp->connections[x].successful_read = sent_packetnum; - - return x; - } - } - - return -1; -} - -/* case 2 in handle_SYNC: */ -static int handle_SYNC2(Lossless_UDP *ludp, int connection_id, uint8_t counter, uint32_t recv_packetnum, - uint32_t sent_packetnum) -{ - if (recv_packetnum == ludp->connections[connection_id].orecv_packetnum) { - /* && sent_packetnum == ludp->connections[connection_id].osent_packetnum) */ - ludp->connections[connection_id].status = 3; - ludp->connections[connection_id].recv_counter = counter; - ++ludp->connections[connection_id].send_counter; - send_SYNC(ludp, connection_id); - return 0; - } - - return 1; -} -/* case 3 in handle_SYNC: */ -static int handle_SYNC3(Lossless_UDP *ludp, int connection_id, uint8_t counter, uint32_t recv_packetnum, - uint32_t sent_packetnum, - uint32_t *req_packets, - uint16_t number) -{ - uint8_t comp_counter = (counter - ludp->connections[connection_id].recv_counter ); - uint32_t i, temp; - /* uint32_t comp_1 = (recv_packetnum - ludp->connections[connection_id].successful_sent); - uint32_t comp_2 = (sent_packetnum - ludp->connections[connection_id].successful_read); */ - uint32_t comp_1 = (recv_packetnum - ludp->connections[connection_id].orecv_packetnum); - uint32_t comp_2 = (sent_packetnum - ludp->connections[connection_id].osent_packetnum); - - /* packet valid */ - if (comp_1 <= BUFFER_PACKET_NUM && - comp_2 <= BUFFER_PACKET_NUM && - comp_counter < 10 && comp_counter != 0) { - - ludp->connections[connection_id].orecv_packetnum = recv_packetnum; - ludp->connections[connection_id].osent_packetnum = sent_packetnum; - ludp->connections[connection_id].successful_sent = recv_packetnum; - ludp->connections[connection_id].last_recvSYNC = current_time(); - ludp->connections[connection_id].recv_counter = counter; - - ++ludp->connections[connection_id].send_counter; - - for (i = 0; i < number; ++i) { - temp = ntohl(req_packets[i]); - memcpy(ludp->connections[connection_id].req_packets + i, &temp, 4 * number); - } - - ludp->connections[connection_id].num_req_paquets = number; - return 0; - } - - return 1; -} - -static int handle_SYNC(void *object, IP_Port source, uint8_t *packet, uint32_t length) -{ - Lossless_UDP *ludp = object; - - if (!SYNC_valid(length)) - return 1; - - int connection = getconnection_id(ludp, source); - uint8_t counter; - uint32_t temp; - uint32_t recv_packetnum, sent_packetnum; - uint32_t req_packets[BUFFER_PACKET_NUM]; - uint16_t number = (length - 4 - 4 - 2) / 4; - - memcpy(&counter, packet + 1, 1); - memcpy(&temp, packet + 2, 4); - recv_packetnum = ntohl(temp); - memcpy(&temp, packet + 6, 4); - sent_packetnum = ntohl(temp); - - if (number != 0) - memcpy(req_packets, packet + 10, 4 * number); - - if (connection == -1) - return handle_SYNC1(ludp, source, recv_packetnum, sent_packetnum); - - if (ludp->connections[connection].status == 2) - return handle_SYNC2(ludp, connection, counter, - recv_packetnum, sent_packetnum); - - if (ludp->connections[connection].status == 3) - return handle_SYNC3(ludp, connection, counter, recv_packetnum, - sent_packetnum, req_packets, number); - - return 0; -} - -/* - * Add a packet to the received buffer and set the recv_packetnum of the - * connection to its proper value. Return 1 if data was too big, 0 if not. - */ -static int add_recv(Lossless_UDP *ludp, int connection_id, uint32_t data_num, uint8_t *data, uint16_t size) -{ - if (size > MAX_DATA_SIZE) - return 1; - - uint32_t i; - uint32_t maxnum = ludp->connections[connection_id].successful_read + BUFFER_PACKET_NUM; - uint32_t sent_packet = data_num - ludp->connections[connection_id].osent_packetnum; - - for (i = ludp->connections[connection_id].recv_packetnum; i != maxnum; ++i) { - if (i == data_num) { - memcpy(ludp->connections[connection_id].recvbuffer[i % MAX_QUEUE_NUM].data, data, size); - - ludp->connections[connection_id].recvbuffer[i % MAX_QUEUE_NUM].size = size; - ludp->connections[connection_id].last_recvdata = current_time(); - - if (sent_packet < BUFFER_PACKET_NUM) { - ludp->connections[connection_id].osent_packetnum = data_num; - } - - break; - } - } - - for (i = ludp->connections[connection_id].recv_packetnum; i != maxnum; ++i) { - if (ludp->connections[connection_id].recvbuffer[i % MAX_QUEUE_NUM].size != 0) - ludp->connections[connection_id].recv_packetnum = i; - else - break; - } - - return 0; -} - -static int handle_data(void *object, IP_Port source, uint8_t *packet, uint32_t length) -{ - Lossless_UDP *ludp = object; - int connection = getconnection_id(ludp, source); - - if (connection == -1) - return 1; - - /* Drop the data packet if connection is not connected. */ - if (ludp->connections[connection].status != 3) - return 1; - - if (length > 1 + 4 + MAX_DATA_SIZE || length < 1 + 4 + 1) - return 1; - - uint32_t temp; - uint32_t number; - uint16_t size = length - 1 - 4; - - memcpy(&temp, packet + 1, 4); - number = ntohl(temp); - - return add_recv(ludp, connection, number, packet + 5, size); -} - -/* - * END of packet handling functions - */ - -Lossless_UDP *new_lossless_udp(Networking_Core *net) -{ - if (net == NULL) - return NULL; - - Lossless_UDP *temp = calloc(1, sizeof(Lossless_UDP)); - - if (temp == NULL) - return NULL; - - temp->net = net; - networking_registerhandler(net, NET_PACKET_HANDSHAKE, &handle_handshake, temp); - networking_registerhandler(net, NET_PACKET_SYNC, &handle_SYNC, temp); - networking_registerhandler(net, NET_PACKET_DATA, &handle_data, temp); - return temp; -} - -/* - * Send handshake requests - * handshake packets are sent at the same rate as SYNC packets - */ -static void do_new(Lossless_UDP *ludp) -{ - uint32_t i; - uint64_t temp_time = current_time(); - - for (i = 0; i < ludp->connections_length; ++i) { - if (ludp->connections[i].status == 1) - if ((ludp->connections[i].last_sent + (1000000UL / ludp->connections[i].SYNC_rate)) <= temp_time) { - send_handshake(ludp, ludp->connections[i].ip_port, ludp->connections[i].handshake_id1, 0); - ludp->connections[i].last_sent = temp_time; - } - - /* kill all timed out connections */ - if (ludp->connections[i].status > 0 && - (ludp->connections[i].last_recvSYNC + ludp->connections[i].timeout * 1000000UL) < temp_time && - ludp->connections[i].status != 4) { - ludp->connections[i].status = 4; - /* kill_connection(i); */ - } - - if (ludp->connections[i].status > 0 && ludp->connections[i].killat < temp_time) - kill_connection(ludp, i); - } -} - -static void do_SYNC(Lossless_UDP *ludp) -{ - uint32_t i; - uint64_t temp_time = current_time(); - - for (i = 0; i < ludp->connections_length; ++i) { - if (ludp->connections[i].status == 2 || ludp->connections[i].status == 3) - if ((ludp->connections[i].last_SYNC + (1000000UL / ludp->connections[i].SYNC_rate)) <= temp_time) { - send_SYNC(ludp, i); - ludp->connections[i].last_SYNC = temp_time; - } - } -} - -static void do_data(Lossless_UDP *ludp) -{ - uint32_t i; - uint64_t j; - uint64_t temp_time = current_time(); - - for (i = 0; i < ludp->connections_length; ++i) - if (ludp->connections[i].status == 3 && sendqueue(ludp, i) != 0) - if ((ludp->connections[i].last_sent + (1000000UL / ludp->connections[i].data_rate)) <= temp_time) { - for (j = ludp->connections[i].last_sent; j < temp_time; j += (1000000UL / ludp->connections[i].data_rate)) - send_DATA(ludp, i); - - ludp->connections[i].last_sent = temp_time; - } -} - -#define MAX_SYNC_RATE 10 - -/* - * Automatically adjusts send rates of packets for optimal transmission. - * - * TODO: flow control. - */ -static void adjust_rates(Lossless_UDP *ludp) -{ - uint32_t i; - uint64_t temp_time = current_time(); - - for (i = 0; i < ludp->connections_length; ++i) { - if (ludp->connections[i].status == 1 || ludp->connections[i].status == 2) - ludp->connections[i].SYNC_rate = MAX_SYNC_RATE; - - if (ludp->connections[i].status == 3) { - if (sendqueue(ludp, i) != 0) { - ludp->connections[i].data_rate = (BUFFER_PACKET_NUM - ludp->connections[i].num_req_paquets) * MAX_SYNC_RATE; - ludp->connections[i].SYNC_rate = MAX_SYNC_RATE; - } else if (ludp->connections[i].last_recvdata + 1000000UL > temp_time) - ludp->connections[i].SYNC_rate = MAX_SYNC_RATE; - else - ludp->connections[i].SYNC_rate = SYNC_RATE; - } - } -} - -/* Call this function a couple times per second It's the main loop. */ -void do_lossless_udp(Lossless_UDP *ludp) -{ - do_new(ludp); - do_SYNC(ludp); - do_data(ludp); - adjust_rates(ludp); -} - -void kill_lossless_udp(Lossless_UDP *ludp) -{ - free(ludp->connections); - free(ludp); -} diff --git a/core/Lossless_UDP.h b/core/Lossless_UDP.h deleted file mode 100644 index 176e86ce..00000000 --- a/core/Lossless_UDP.h +++ /dev/null @@ -1,222 +0,0 @@ -/* Lossless_UDP.h - * - * An implementation of the Lossless_UDP protocol as seen in http://wiki.tox.im/index.php/Lossless_UDP - * - * Copyright (C) 2013 Tox project All Rights Reserved. - * - * This file is part of Tox. - * - * Tox 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. - * - * Tox 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 Tox. If not, see . - * - */ - -#ifndef LOSSLESS_UDP_H -#define LOSSLESS_UDP_H - -#include "network.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/* maximum length of the data in the data packets */ -#define MAX_DATA_SIZE 1024 - -/* maximum data packets in sent and receive queues. */ -#define MAX_QUEUE_NUM 16 - -/* maximum number of data packets in the buffer */ -#define BUFFER_PACKET_NUM (16-1) - -/* timeout per connection is randomly set between CONNEXION_TIMEOUT and 2*CONNEXION_TIMEOUT */ -#define CONNEXION_TIMEOUT 5 - -/* initial amount of sync/hanshake packets to send per second. */ -#define SYNC_RATE 2 - -/* initial send rate of data. */ -#define DATA_SYNC_RATE 30 - -typedef struct { - uint8_t data[MAX_DATA_SIZE]; - uint16_t size; -} Data; - -typedef struct { - IP_Port ip_port; - - /* - * 0 if connection is dead, 1 if attempting handshake, - * 2 if handshake is done (we start sending SYNC packets) - * 3 if we are sending SYNC packets and can send data - * 4 if the connection has timed out. - */ - uint8_t status; - - /* - * 1 or 2 if connection was initiated by someone else, 0 if not. - * 2 if incoming_connection() has not returned it yet, 1 if it has. - */ - uint8_t inbound; - - uint16_t SYNC_rate; /* current SYNC packet send rate packets per second. */ - uint16_t data_rate; /* current data packet send rate packets per second. */ - - uint64_t last_SYNC; /* time our last SYNC packet was sent. */ - uint64_t last_sent; /* time our last data or handshake packet was sent. */ - uint64_t last_recvSYNC; /* time we last received a SYNC packet from the other */ - uint64_t last_recvdata; /* time we last received a DATA packet from the other */ - uint64_t killat; /* time to kill the connection */ - - Data sendbuffer[MAX_QUEUE_NUM]; /* packet send buffer. */ - Data recvbuffer[MAX_QUEUE_NUM]; /* packet receive buffer. */ - - uint32_t handshake_id1; - uint32_t handshake_id2; - - /* number of data packets received (also used as handshake_id1) */ - uint32_t recv_packetnum; - - /* number of packets received by the other peer */ - uint32_t orecv_packetnum; - - /* number of data packets sent */ - uint32_t sent_packetnum; - - /* number of packets sent by the other peer. */ - uint32_t osent_packetnum; - - /* number of latest packet written onto the sendbuffer */ - uint32_t sendbuff_packetnum; - - /* we know all packets before that number were successfully sent */ - uint32_t successful_sent; - - /* packet number of last packet read with the read_packet function */ - uint32_t successful_read; - - /* list of currently requested packet numbers(by the other person) */ - uint32_t req_packets[BUFFER_PACKET_NUM]; - - /* total number of currently requested packets(by the other person) */ - uint16_t num_req_paquets; - - uint8_t recv_counter; - uint8_t send_counter; - uint8_t timeout; /* connection timeout in seconds. */ -} Connection; - -typedef struct { - Networking_Core *net; - Connection *connections; - - uint32_t connections_length; /* Length of connections array */ - uint32_t connections_number; /* Number of connections in connections array */ - - /* table of random numbers used in handshake_id. */ - uint32_t randtable[6][256]; - -} Lossless_UDP; - -/* - * Initialize a new connection to ip_port - * Returns an integer corresponding to the connection id. - * Return -1 if it could not initialize the connection. - * Return number if there already was an existing connection to that ip_port. - */ -int new_connection(Lossless_UDP *ludp, IP_Port ip_port); - -/* - * Get connection id from IP_Port. - * Return -1 if there are no connections like we are looking for. - * Return id if it found it . - */ -int getconnection_id(Lossless_UDP *ludp, IP_Port ip_port); - -/* - * Returns an int corresponding to the next connection in our imcoming connection list - * Return -1 if there are no new incoming connections in the list. - */ -int incoming_connection(Lossless_UDP *ludp); - -/* - * Return -1 if it could not kill the connection. - * Return 0 if killed successfully - */ -int kill_connection(Lossless_UDP *ludp, int connection_id); - -/* - * Kill connection in seconds seconds. - * Return -1 if it can not kill the connection. - * Return 0 if it will kill it - */ -int kill_connection_in(Lossless_UDP *ludp, int connection_id, uint32_t seconds); - -/* - * Returns the ip_port of the corresponding connection. - * Return 0 if there is no such connection. - */ -IP_Port connection_ip(Lossless_UDP *ludp, int connection_id); - -/* - * Returns the id of the next packet in the queue - * Return -1 if no packet in queue - */ -char id_packet(Lossless_UDP *ludp, int connection_id); - -/* - * Return 0 if there is no received data in the buffer. - * Return length of received packet if successful - */ -int read_packet(Lossless_UDP *ludp, int connection_id, uint8_t *data); - -/* - * Return 0 if data could not be put in packet queue - * Return 1 if data was put into the queue - */ -int write_packet(Lossless_UDP *ludp, int connection_id, uint8_t *data, uint32_t length); - -/* Returns the number of packets in the queue waiting to be successfully sent. */ -uint32_t sendqueue(Lossless_UDP *ludp, int connection_id); - -/* - * returns the number of packets in the queue waiting to be successfully - * read with read_packet(...) - */ -uint32_t recvqueue(Lossless_UDP *ludp, int connection_id); - -/* Check if connection is connected: - * Return 0 no. - * Return 1 if attempting handshake. - * Return 2 if handshake is done. - * Return 3 if fully connected. - * Return 4 if timed out and wating to be killed. - */ -int is_connected(Lossless_UDP *ludp, int connection_id); - -/* Call this function a couple times per second It's the main loop. */ -void do_lossless_udp(Lossless_UDP *ludp); - -/* - * This function sets up LosslessUDP packet handling. - */ -Lossless_UDP *new_lossless_udp(Networking_Core *net); - -void kill_lossless_udp(Lossless_UDP *ludp); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/core/Messenger.c b/core/Messenger.c deleted file mode 100644 index c5dd8a40..00000000 --- a/core/Messenger.c +++ /dev/null @@ -1,1020 +0,0 @@ -/* Messenger.c - * - * An implementation of a simple text chat only messenger on the tox network core. - * - * Copyright (C) 2013 Tox project All Rights Reserved. - * - * This file is part of Tox. - * - * Tox 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. - * - * Tox 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 Tox. If not, see . - * - */ - -#include "Messenger.h" - -#define MIN(a,b) (((a)<(b))?(a):(b)) - -static void set_friend_status(Messenger *m, int friendnumber, uint8_t status); -static int write_cryptpacket_id(Messenger *m, int friendnumber, uint8_t packet_id, uint8_t *data, uint32_t length); - -/* 1 if we are online - 0 if we are offline - static uint8_t online; */ - -/* set the size of the friend list to numfriends - return -1 if realloc fails */ -int realloc_friendlist(Messenger *m, uint32_t num) -{ - if (num == 0) { - free(m->friendlist); - m->friendlist = NULL; - return 0; - } - - Friend *newfriendlist = realloc(m->friendlist, num * sizeof(Friend)); - - if (newfriendlist == NULL) - return -1; - - m->friendlist = newfriendlist; - return 0; -} - -/* return the friend id associated to that public key. - return -1 if no such friend */ -int getfriend_id(Messenger *m, uint8_t *client_id) -{ - uint32_t i; - - for (i = 0; i < m->numfriends; ++i) { - if (m->friendlist[i].status > 0) - if (memcmp(client_id, m->friendlist[i].client_id, crypto_box_PUBLICKEYBYTES) == 0) - return i; - } - - return -1; -} - -/* copies the public key associated to that friend id into client_id buffer. - make sure that client_id is of size CLIENT_ID_SIZE. - return 0 if success - return -1 if failure. */ -int getclient_id(Messenger *m, int friend_id, uint8_t *client_id) -{ - if (friend_id >= m->numfriends || friend_id < 0) - return -1; - - if (m->friendlist[friend_id].status > 0) { - memcpy(client_id, m->friendlist[friend_id].client_id, CLIENT_ID_SIZE); - return 0; - } - - return -1; -} -/* - * returns a uint16_t that represents the checksum of address of length len - * - * TODO: Another checksum algorithm might be better. - */ -static uint16_t address_checksum(uint8_t *address, uint32_t len) -{ - uint8_t checksum[2] = {0}; - uint16_t check; - uint32_t i; - - for (i = 0; i < len; ++i) - checksum[i % 2] ^= address[i]; - - memcpy(&check, checksum, sizeof(check)); - return check; -} - -/* - * returns a FRIEND_ADDRESS_SIZE byte address to give to others. - * format: [client_id (32 bytes)][nospam number (4 bytes)][checksum (2 bytes)] - * - */ -void getaddress(Messenger *m, uint8_t *address) -{ - memcpy(address, m->net_crypto->self_public_key, crypto_box_PUBLICKEYBYTES); - uint32_t nospam = get_nospam(&(m->fr)); - memcpy(address + crypto_box_PUBLICKEYBYTES, &nospam, sizeof(nospam)); - uint16_t checksum = address_checksum(address, FRIEND_ADDRESS_SIZE - sizeof(checksum)); - memcpy(address + crypto_box_PUBLICKEYBYTES + sizeof(nospam), &checksum, sizeof(checksum)); -} - -/* - * add a friend - * set the data that will be sent along with friend request - * address is the address of the friend (returned by getaddress of the friend you wish to add) it must be FRIEND_ADDRESS_SIZE bytes. TODO: add checksum. - * data is the data and length is the length - * returns the friend number if success - * return FA_TOOLONG if message length is too long - * return FAERR_NOMESSAGE if no message (message length must be >= 1 byte) - * return FAERR_OWNKEY if user's own key - * return FAERR_ALREADYSENT if friend request already sent or already a friend - * return FAERR_UNKNOWN for unknown error - * return FAERR_BADCHECKSUM if bad checksum in address - * return FAERR_SETNEWNOSPAM if the friend was already there but the nospam was different - * (the nospam for that friend was set to the new one) - * return FAERR_NOMEM if increasing the friend list size fails - */ -int m_addfriend(Messenger *m, uint8_t *address, uint8_t *data, uint16_t length) -{ - if (length >= (MAX_DATA_SIZE - crypto_box_PUBLICKEYBYTES - - crypto_box_NONCEBYTES - crypto_box_BOXZEROBYTES - + crypto_box_ZEROBYTES)) - return FAERR_TOOLONG; - - uint8_t client_id[crypto_box_PUBLICKEYBYTES]; - memcpy(client_id, address, crypto_box_PUBLICKEYBYTES); - uint16_t check, checksum = address_checksum(address, FRIEND_ADDRESS_SIZE - sizeof(checksum)); - memcpy(&check, address + crypto_box_PUBLICKEYBYTES + sizeof(uint32_t), sizeof(check)); - - if (check != checksum) - return FAERR_BADCHECKSUM; - - if (length < 1) - return FAERR_NOMESSAGE; - - if (memcmp(client_id, m->net_crypto->self_public_key, crypto_box_PUBLICKEYBYTES) == 0) - return FAERR_OWNKEY; - - int friend_id = getfriend_id(m, client_id); - - if (friend_id != -1) { - uint32_t nospam; - memcpy(&nospam, address + crypto_box_PUBLICKEYBYTES, sizeof(nospam)); - - if (m->friendlist[friend_id].friendrequest_nospam == nospam) - return FAERR_ALREADYSENT; - - m->friendlist[friend_id].friendrequest_nospam = nospam; - return FAERR_SETNEWNOSPAM; - } - - /* resize the friend list if necessary */ - if (realloc_friendlist(m, m->numfriends + 1) != 0) - return FAERR_NOMEM; - - memset(&(m->friendlist[m->numfriends]), 0, sizeof(Friend)); - - uint32_t i; - - for (i = 0; i <= m->numfriends; ++i) { - if (m->friendlist[i].status == NOFRIEND) { - DHT_addfriend(m->dht, client_id); - m->friendlist[i].status = FRIEND_ADDED; - m->friendlist[i].crypt_connection_id = -1; - m->friendlist[i].friendrequest_lastsent = 0; - m->friendlist[i].friendrequest_timeout = FRIENDREQUEST_TIMEOUT; - memcpy(m->friendlist[i].client_id, client_id, CLIENT_ID_SIZE); - m->friendlist[i].statusmessage = calloc(1, 1); - m->friendlist[i].statusmessage_length = 1; - m->friendlist[i].userstatus = USERSTATUS_NONE; - memcpy(m->friendlist[i].info, data, length); - m->friendlist[i].info_size = length; - m->friendlist[i].message_id = 0; - m->friendlist[i].receives_read_receipts = 1; /* default: YES */ - memcpy(&(m->friendlist[i].friendrequest_nospam), address + crypto_box_PUBLICKEYBYTES, sizeof(uint32_t)); - - if (m->numfriends == i) - ++ m->numfriends; - - return i; - } - } - - return FAERR_UNKNOWN; -} - -int m_addfriend_norequest(Messenger *m, uint8_t *client_id) -{ - if (getfriend_id(m, client_id) != -1) - return -1; - - /* resize the friend list if necessary */ - if (realloc_friendlist(m, m->numfriends + 1) != 0) - return FAERR_NOMEM; - - memset(&(m->friendlist[m->numfriends]), 0, sizeof(Friend)); - - uint32_t i; - - for (i = 0; i <= m->numfriends; ++i) { - if (m->friendlist[i].status == NOFRIEND) { - DHT_addfriend(m->dht, client_id); - m->friendlist[i].status = FRIEND_CONFIRMED; - m->friendlist[i].crypt_connection_id = -1; - m->friendlist[i].friendrequest_lastsent = 0; - memcpy(m->friendlist[i].client_id, client_id, CLIENT_ID_SIZE); - m->friendlist[i].statusmessage = calloc(1, 1); - m->friendlist[i].statusmessage_length = 1; - m->friendlist[i].userstatus = USERSTATUS_NONE; - m->friendlist[i].message_id = 0; - m->friendlist[i].receives_read_receipts = 1; /* default: YES */ - - if (m->numfriends == i) - ++ m->numfriends; - - return i; - } - } - - return -1; -} - -/* remove a friend - return 0 if success - return -1 if failure */ -int m_delfriend(Messenger *m, int friendnumber) -{ - if (friendnumber >= m->numfriends || friendnumber < 0) - return -1; - - DHT_delfriend(m->dht, m->friendlist[friendnumber].client_id); - crypto_kill(m->net_crypto, m->friendlist[friendnumber].crypt_connection_id); - free(m->friendlist[friendnumber].statusmessage); - memset(&(m->friendlist[friendnumber]), 0, sizeof(Friend)); - uint32_t i; - - for (i = m->numfriends; i != 0; --i) { - if (m->friendlist[i - 1].status != NOFRIEND) - break; - } - - m->numfriends = i; - - if (realloc_friendlist(m, m->numfriends) != 0) - return FAERR_NOMEM; - - return 0; -} - -/* return FRIEND_ONLINE if friend is online - return FRIEND_CONFIRMED if friend is confirmed - return FRIEND_REQUESTED if the friend request was sent - return FRIEND_ADDED if the friend was added - return NOFRIEND if there is no friend with that number */ -int m_friendstatus(Messenger *m, int friendnumber) -{ - if (friendnumber < 0 || friendnumber >= m->numfriends) - return NOFRIEND; - - return m->friendlist[friendnumber].status; -} - -/* send a text chat message to an online friend - return the message id if packet was successfully put into the send queue - return 0 if it was not */ -uint32_t m_sendmessage(Messenger *m, int friendnumber, uint8_t *message, uint32_t length) -{ - if (friendnumber < 0 || friendnumber >= m->numfriends) - return 0; - - uint32_t msgid = ++m->friendlist[friendnumber].message_id; - - if (msgid == 0) - msgid = 1; /* otherwise, false error */ - - if (m_sendmessage_withid(m, friendnumber, msgid, message, length)) { - return msgid; - } - - return 0; -} - -uint32_t m_sendmessage_withid(Messenger *m, int friendnumber, uint32_t theid, uint8_t *message, uint32_t length) -{ - if (length >= (MAX_DATA_SIZE - sizeof(theid))) - return 0; - - uint8_t temp[MAX_DATA_SIZE]; - theid = htonl(theid); - memcpy(temp, &theid, sizeof(theid)); - memcpy(temp + sizeof(theid), message, length); - return write_cryptpacket_id(m, friendnumber, PACKET_ID_MESSAGE, temp, length + sizeof(theid)); -} - -/* send an action to an online friend - return 1 if packet was successfully put into the send queue - return 0 if it was not */ -int m_sendaction(Messenger *m, int friendnumber, uint8_t *action, uint32_t length) -{ - return write_cryptpacket_id(m, friendnumber, PACKET_ID_ACTION, action, length); -} - -/* send a name packet to friendnumber - length is the length with the NULL terminator*/ -static int m_sendname(Messenger *m, int friendnumber, uint8_t *name, uint16_t length) -{ - if (length > MAX_NAME_LENGTH || length == 0) - return 0; - - return write_cryptpacket_id(m, friendnumber, PACKET_ID_NICKNAME, name, length); -} - -/* set the name of a friend - return 0 if success - return -1 if failure */ -static int setfriendname(Messenger *m, int friendnumber, uint8_t *name) -{ - if (friendnumber >= m->numfriends || friendnumber < 0) - return -1; - - memcpy(m->friendlist[friendnumber].name, name, MAX_NAME_LENGTH); - return 0; -} - -/* Set our nickname - name must be a string of maximum MAX_NAME_LENGTH length. - length must be at least 1 byte - length is the length of name with the NULL terminator - return 0 if success - return -1 if failure */ -int setname(Messenger *m, uint8_t *name, uint16_t length) -{ - if (length > MAX_NAME_LENGTH || length == 0) - return -1; - - memcpy(m->name, name, length); - m->name_length = length; - uint32_t i; - - for (i = 0; i < m->numfriends; ++i) - m->friendlist[i].name_sent = 0; - - return 0; -} - -/* get our nickname - put it in name - name needs to be a valid memory location with a size of at least MAX_NAME_LENGTH bytes. - return the length of the name */ -uint16_t getself_name(Messenger *m, uint8_t *name, uint16_t nlen) -{ - uint16_t len; - - if (name == NULL || nlen == 0) { - return 0; - } - - len = MIN(nlen, m->name_length); - memcpy(name, m->name, m->name_length); - - return len; -} - -/* get name of friendnumber - put it in name - name needs to be a valid memory location with a size of at least MAX_NAME_LENGTH bytes. - return 0 if success - return -1 if failure */ -int getname(Messenger *m, int friendnumber, uint8_t *name) -{ - if (friendnumber >= m->numfriends || friendnumber < 0) - return -1; - - memcpy(name, m->friendlist[friendnumber].name, MAX_NAME_LENGTH); - return 0; -} - -int m_set_statusmessage(Messenger *m, uint8_t *status, uint16_t length) -{ - if (length > MAX_STATUSMESSAGE_LENGTH) - return -1; - - memcpy(m->statusmessage, status, length); - m->statusmessage_length = length; - - uint32_t i; - - for (i = 0; i < m->numfriends; ++i) - m->friendlist[i].statusmessage_sent = 0; - - return 0; -} - -int m_set_userstatus(Messenger *m, USERSTATUS status) -{ - if (status >= USERSTATUS_INVALID) { - return -1; - } - - m->userstatus = status; - uint32_t i; - - for (i = 0; i < m->numfriends; ++i) - m->friendlist[i].userstatus_sent = 0; - - return 0; -} - -/* return the size of friendnumber's user status - guaranteed to be at most MAX_STATUSMESSAGE_LENGTH */ -int m_get_statusmessage_size(Messenger *m, int friendnumber) -{ - if (friendnumber >= m->numfriends || friendnumber < 0) - return -1; - - return m->friendlist[friendnumber].statusmessage_length; -} - -/* copy the user status of friendnumber into buf, truncating if needed to maxlen - bytes, use m_get_statusmessage_size to find out how much you need to allocate */ -int m_copy_statusmessage(Messenger *m, int friendnumber, uint8_t *buf, uint32_t maxlen) -{ - if (friendnumber >= m->numfriends || friendnumber < 0) - return -1; - - memset(buf, 0, maxlen); - memcpy(buf, m->friendlist[friendnumber].statusmessage, MIN(maxlen, MAX_STATUSMESSAGE_LENGTH) - 1); - return 0; -} - -int m_copy_self_statusmessage(Messenger *m, uint8_t *buf, uint32_t maxlen) -{ - memset(buf, 0, maxlen); - memcpy(buf, m->statusmessage, MIN(maxlen, MAX_STATUSMESSAGE_LENGTH) - 1); - return 0; -} - -USERSTATUS m_get_userstatus(Messenger *m, int friendnumber) -{ - if (friendnumber >= m->numfriends || friendnumber < 0) - return USERSTATUS_INVALID; - - USERSTATUS status = m->friendlist[friendnumber].userstatus; - - if (status >= USERSTATUS_INVALID) { - status = USERSTATUS_NONE; - } - - return status; -} - -USERSTATUS m_get_self_userstatus(Messenger *m) -{ - return m->userstatus; -} - -static int send_statusmessage(Messenger *m, int friendnumber, uint8_t *status, uint16_t length) -{ - return write_cryptpacket_id(m, friendnumber, PACKET_ID_STATUSMESSAGE, status, length); -} - -static int send_userstatus(Messenger *m, int friendnumber, USERSTATUS status) -{ - uint8_t stat = status; - return write_cryptpacket_id(m, friendnumber, PACKET_ID_USERSTATUS, &stat, sizeof(stat)); -} - -static int send_ping(Messenger *m, int friendnumber) -{ - m->friendlist[friendnumber].ping_lastsent = unix_time(); - return write_cryptpacket_id(m, friendnumber, PACKET_ID_PING, 0, 0); -} - -static int set_friend_statusmessage(Messenger *m, int friendnumber, uint8_t *status, uint16_t length) -{ - if (friendnumber >= m->numfriends || friendnumber < 0) - return -1; - - uint8_t *newstatus = calloc(length, 1); - memcpy(newstatus, status, length); - free(m->friendlist[friendnumber].statusmessage); - m->friendlist[friendnumber].statusmessage = newstatus; - m->friendlist[friendnumber].statusmessage_length = length; - return 0; -} - -static void set_friend_userstatus(Messenger *m, int friendnumber, USERSTATUS status) -{ - m->friendlist[friendnumber].userstatus = status; -} - -/* Sets whether we send read receipts for friendnumber. */ -void m_set_sends_receipts(Messenger *m, int friendnumber, int yesno) -{ - if (yesno != 0 || yesno != 1) - return; - - if (friendnumber >= m->numfriends || friendnumber < 0) - return; - - m->friendlist[friendnumber].receives_read_receipts = yesno; -} - -/* static void (*friend_request)(uint8_t *, uint8_t *, uint16_t); */ -/* set the function that will be executed when a friend request is received. */ -void m_callback_friendrequest(Messenger *m, void (*function)(uint8_t *, uint8_t *, uint16_t, void *), void *userdata) -{ - callback_friendrequest(&(m->fr), function, userdata); -} - -/* set the function that will be executed when a message from a friend is received. */ -void m_callback_friendmessage(Messenger *m, void (*function)(Messenger *m, int, uint8_t *, uint16_t, void *), - void *userdata) -{ - m->friend_message = function; - m->friend_message_userdata = userdata; -} - -void m_callback_action(Messenger *m, void (*function)(Messenger *m, int, uint8_t *, uint16_t, void *), void *userdata) -{ - m->friend_action = function; - m->friend_action_userdata = userdata; -} - -void m_callback_namechange(Messenger *m, void (*function)(Messenger *m, int, uint8_t *, uint16_t, void *), - void *userdata) -{ - m->friend_namechange = function; - m->friend_namechange_userdata = userdata; -} - -void m_callback_statusmessage(Messenger *m, void (*function)(Messenger *m, int, uint8_t *, uint16_t, void *), - void *userdata) -{ - m->friend_statusmessagechange = function; - m->friend_statuschange_userdata = userdata; -} - -void m_callback_userstatus(Messenger *m, void (*function)(Messenger *m, int, USERSTATUS, void *), void *userdata) -{ - m->friend_userstatuschange = function; - m->friend_userstatuschange_userdata = userdata; -} - -void m_callback_read_receipt(Messenger *m, void (*function)(Messenger *m, int, uint32_t, void *), void *userdata) -{ - m->read_receipt = function; - m->read_receipt_userdata = userdata; -} - -void m_callback_connectionstatus(Messenger *m, void (*function)(Messenger *m, int, uint8_t, void *), void *userdata) -{ - m->friend_connectionstatuschange = function; - m->friend_connectionstatuschange_userdata = userdata; -} - -static void check_friend_connectionstatus(Messenger *m, int friendnumber, uint8_t status) -{ - if (!m->friend_connectionstatuschange) - return; - - if (status == NOFRIEND) - return; - - const uint8_t was_connected = m->friendlist[friendnumber].status == FRIEND_ONLINE; - const uint8_t is_connected = status == FRIEND_ONLINE; - - if (is_connected != was_connected) - m->friend_connectionstatuschange(m, friendnumber, is_connected, m->friend_connectionstatuschange_userdata); -} - -void set_friend_status(Messenger *m, int friendnumber, uint8_t status) -{ - check_friend_connectionstatus(m, friendnumber, status); - m->friendlist[friendnumber].status = status; -} - -int write_cryptpacket_id(Messenger *m, int friendnumber, uint8_t packet_id, uint8_t *data, uint32_t length) -{ - if (friendnumber < 0 || friendnumber >= m->numfriends) - return 0; - - if (length >= MAX_DATA_SIZE || m->friendlist[friendnumber].status != FRIEND_ONLINE) - return 0; - - uint8_t packet[length + 1]; - packet[0] = packet_id; - - if (length != 0) - memcpy(packet + 1, data, length); - - return write_cryptpacket(m->net_crypto, m->friendlist[friendnumber].crypt_connection_id, packet, length + 1); -} - -/*Interval in seconds between LAN discovery packet sending*/ -#define LAN_DISCOVERY_INTERVAL 60 -#define PORT 33445 - -/*Send a LAN discovery packet every LAN_DISCOVERY_INTERVAL seconds*/ -static void LANdiscovery(Messenger *m) -{ - if (m->last_LANdiscovery + LAN_DISCOVERY_INTERVAL < unix_time()) { - send_LANdiscovery(htons(PORT), m->net_crypto); - m->last_LANdiscovery = unix_time(); - } -} - -/* run this at startup */ -Messenger *initMessenger(void) -{ - Messenger *m = calloc(1, sizeof(Messenger)); - - if ( ! m ) - return NULL; - - IP ip; - ip.i = 0; - m->net = new_networking(ip, PORT); - - if (m->net == NULL) { - free(m); - return NULL; - } - - m->net_crypto = new_net_crypto(m->net); - - if (m->net_crypto == NULL) { - kill_networking(m->net); - free(m); - return NULL; - } - - m->dht = new_DHT(m->net_crypto); - - if (m->dht == NULL) { - kill_net_crypto(m->net_crypto); - kill_networking(m->net); - free(m); - return NULL; - } - - new_keys(m->net_crypto); - m_set_statusmessage(m, (uint8_t *)"Online", sizeof("Online")); - - friendreq_init(&(m->fr), m->net_crypto); - LANdiscovery_init(m->dht); - set_nospam(&(m->fr), random_int()); - - return m; -} - -/* run this before closing shop */ -void cleanupMessenger(Messenger *m) -{ - /* FIXME TODO ideally cleanupMessenger will mirror initMessenger - * this requires the other modules to expose cleanup functions - */ - kill_DHT(m->dht); - kill_net_crypto(m->net_crypto); - kill_networking(m->net); - free(m->friendlist); - free(m); -} - -//TODO: make this function not suck. -void doFriends(Messenger *m) -{ - /* TODO: add incoming connections and some other stuff. */ - uint32_t i; - int len; - uint8_t temp[MAX_DATA_SIZE]; - uint64_t temp_time = unix_time(); - - for (i = 0; i < m->numfriends; ++i) { - if (m->friendlist[i].status == FRIEND_ADDED) { - int fr = send_friendrequest(m->dht, m->friendlist[i].client_id, m->friendlist[i].friendrequest_nospam, - m->friendlist[i].info, - m->friendlist[i].info_size); - - if (fr >= 0) { - set_friend_status(m, i, FRIEND_REQUESTED); - m->friendlist[i].friendrequest_lastsent = temp_time; - } - } - - if (m->friendlist[i].status == FRIEND_REQUESTED - || m->friendlist[i].status == FRIEND_CONFIRMED) { /* friend is not online */ - if (m->friendlist[i].status == FRIEND_REQUESTED) { - /* If we didn't connect to friend after successfully sending him a friend request the request is deemed - unsuccessful so we set the status back to FRIEND_ADDED and try again.*/ - if (m->friendlist[i].friendrequest_lastsent + m->friendlist[i].friendrequest_timeout < temp_time) { - set_friend_status(m, i, FRIEND_ADDED); - /* Double the default timeout everytime if friendrequest is assumed to have been - sent unsuccessfully. */ - m->friendlist[i].friendrequest_timeout *= 2; - } - } - - IP_Port friendip = DHT_getfriendip(m->dht, m->friendlist[i].client_id); - - switch (is_cryptoconnected(m->net_crypto, m->friendlist[i].crypt_connection_id)) { - case 0: - if (friendip.ip.i > 1) - m->friendlist[i].crypt_connection_id = crypto_connect(m->net_crypto, m->friendlist[i].client_id, friendip); - - break; - - case 3: /* Connection is established */ - set_friend_status(m, i, FRIEND_ONLINE); - m->friendlist[i].name_sent = 0; - m->friendlist[i].userstatus_sent = 0; - m->friendlist[i].statusmessage_sent = 0; - m->friendlist[i].ping_lastrecv = temp_time; - break; - - case 4: - crypto_kill(m->net_crypto, m->friendlist[i].crypt_connection_id); - m->friendlist[i].crypt_connection_id = -1; - break; - - default: - break; - } - } - - while (m->friendlist[i].status == FRIEND_ONLINE) { /* friend is online */ - if (m->friendlist[i].name_sent == 0) { - if (m_sendname(m, i, m->name, m->name_length)) - m->friendlist[i].name_sent = 1; - } - - if (m->friendlist[i].statusmessage_sent == 0) { - if (send_statusmessage(m, i, m->statusmessage, m->statusmessage_length)) - m->friendlist[i].statusmessage_sent = 1; - } - - if (m->friendlist[i].userstatus_sent == 0) { - if (send_userstatus(m, i, m->userstatus)) - m->friendlist[i].userstatus_sent = 1; - } - - if (m->friendlist[i].ping_lastsent + FRIEND_PING_INTERVAL < temp_time) { - send_ping(m, i); - } - - len = read_cryptpacket(m->net_crypto, m->friendlist[i].crypt_connection_id, temp); - uint8_t packet_id = temp[0]; - uint8_t *data = temp + 1; - int data_length = len - 1; - - if (len > 0) { - switch (packet_id) { - case PACKET_ID_PING: { - m->friendlist[i].ping_lastrecv = temp_time; - break; - } - - case PACKET_ID_NICKNAME: { - if (data_length >= MAX_NAME_LENGTH || data_length == 0) - break; - - if (m->friend_namechange) - m->friend_namechange(m, i, data, data_length, m->friend_namechange_userdata); - - memcpy(m->friendlist[i].name, data, data_length); - m->friendlist[i].name[data_length - 1] = 0; /* make sure the NULL terminator is present. */ - break; - } - - case PACKET_ID_STATUSMESSAGE: { - if (data_length == 0) - break; - - uint8_t *status = calloc(MIN(data_length, MAX_STATUSMESSAGE_LENGTH), 1); - memcpy(status, data, MIN(data_length, MAX_STATUSMESSAGE_LENGTH)); - - if (m->friend_statusmessagechange) - m->friend_statusmessagechange(m, i, status, MIN(data_length, MAX_STATUSMESSAGE_LENGTH), - m->friend_statuschange_userdata); - - set_friend_statusmessage(m, i, status, MIN(data_length, MAX_STATUSMESSAGE_LENGTH)); - free(status); - break; - } - - case PACKET_ID_USERSTATUS: { - if (data_length != 1) - break; - - USERSTATUS status = data[0]; - - if (m->friend_userstatuschange) - m->friend_userstatuschange(m, i, status, m->friend_userstatuschange_userdata); - - set_friend_userstatus(m, i, status); - break; - } - - case PACKET_ID_MESSAGE: { - uint8_t *message_id = data; - uint8_t message_id_length = 4; - uint8_t *message = data + message_id_length; - uint16_t message_length = data_length - message_id_length; - - if (m->friendlist[i].receives_read_receipts) { - write_cryptpacket_id(m, i, PACKET_ID_RECEIPT, message_id, message_id_length); - } - - if (m->friend_message) - (*m->friend_message)(m, i, message, message_length, m->friend_message_userdata); - - break; - } - - case PACKET_ID_ACTION: { - if (m->friend_action) - (*m->friend_action)(m, i, data, data_length, m->friend_action_userdata); - - break; - } - - case PACKET_ID_RECEIPT: { - uint32_t msgid; - - if (data_length < sizeof(msgid)) - break; - - memcpy(&msgid, data, sizeof(msgid)); - msgid = ntohl(msgid); - - if (m->read_receipt) - (*m->read_receipt)(m, i, msgid, m->read_receipt_userdata); - - break; - } - } - } else { - if (is_cryptoconnected(m->net_crypto, - m->friendlist[i].crypt_connection_id) == 4) { /* if the connection timed out, kill it */ - crypto_kill(m->net_crypto, m->friendlist[i].crypt_connection_id); - m->friendlist[i].crypt_connection_id = -1; - set_friend_status(m, i, FRIEND_CONFIRMED); - } - - break; - } - - if (m->friendlist[i].ping_lastrecv + FRIEND_CONNECTION_TIMEOUT < temp_time) { - /* if we stopped recieving ping packets kill it */ - crypto_kill(m->net_crypto, m->friendlist[i].crypt_connection_id); - m->friendlist[i].crypt_connection_id = -1; - set_friend_status(m, i, FRIEND_CONFIRMED); - } - } - } -} - -void doInbound(Messenger *m) -{ - uint8_t secret_nonce[crypto_box_NONCEBYTES]; - uint8_t public_key[crypto_box_PUBLICKEYBYTES]; - uint8_t session_key[crypto_box_PUBLICKEYBYTES]; - int inconnection = crypto_inbound(m->net_crypto, public_key, secret_nonce, session_key); - - if (inconnection != -1) { - int friend_id = getfriend_id(m, public_key); - - if (friend_id != -1) { - crypto_kill(m->net_crypto, m->friendlist[friend_id].crypt_connection_id); - m->friendlist[friend_id].crypt_connection_id = - accept_crypto_inbound(m->net_crypto, inconnection, public_key, secret_nonce, session_key); - - set_friend_status(m, friend_id, FRIEND_CONFIRMED); - } - } -} - -/* the main loop that needs to be run at least 20 times per second. */ -void doMessenger(Messenger *m) -{ - networking_poll(m->net); - - do_DHT(m->dht); - do_net_crypto(m->net_crypto); - doInbound(m); - doFriends(m); - LANdiscovery(m); -} - -/* returns the size of the messenger data (for saving) */ -uint32_t Messenger_size(Messenger *m) -{ - return crypto_box_PUBLICKEYBYTES + crypto_box_SECRETKEYBYTES - + sizeof(uint32_t) // nospam - + sizeof(uint32_t) // DHT size - + DHT_size(m->dht) // DHT itself - + sizeof(uint32_t) // Friendlist size - + sizeof(Friend) * m->numfriends // Friendlist itself - + sizeof(uint16_t) // Own nickname length - + m->name_length // Own nickname - ; -} - -/* save the messenger in data of size Messenger_size() */ -void Messenger_save(Messenger *m, uint8_t *data) -{ - save_keys(m->net_crypto, data); - data += crypto_box_PUBLICKEYBYTES + crypto_box_SECRETKEYBYTES; - uint32_t nospam = get_nospam(&(m->fr)); - memcpy(data, &nospam, sizeof(nospam)); - data += sizeof(nospam); - uint32_t size = DHT_size(m->dht); - memcpy(data, &size, sizeof(size)); - data += sizeof(size); - DHT_save(m->dht, data); - data += size; - size = sizeof(Friend) * m->numfriends; - memcpy(data, &size, sizeof(size)); - data += sizeof(size); - memcpy(data, m->friendlist, sizeof(Friend) * m->numfriends); - data += size; - uint16_t small_size = m->name_length; - memcpy(data, &small_size, sizeof(small_size)); - data += sizeof(small_size); - memcpy(data, m->name, small_size); -} - -/* load the messenger from data of size length. */ -int Messenger_load(Messenger *m, uint8_t *data, uint32_t length) -{ - if (length == ~0) - return -1; - - if (length < crypto_box_PUBLICKEYBYTES + crypto_box_SECRETKEYBYTES + sizeof(uint32_t) * 3) - return -1; - - length -= crypto_box_PUBLICKEYBYTES + crypto_box_SECRETKEYBYTES + sizeof(uint32_t) * 3; - load_keys(m->net_crypto, data); - data += crypto_box_PUBLICKEYBYTES + crypto_box_SECRETKEYBYTES; - uint32_t nospam; - memcpy(&nospam, data, sizeof(nospam)); - set_nospam(&(m->fr), nospam); - data += sizeof(nospam); - uint32_t size; - memcpy(&size, data, sizeof(size)); - data += sizeof(size); - - if (length < size) - return -1; - - length -= size; - - if (DHT_load(m->dht, data, size) == -1) - return -1; - - data += size; - memcpy(&size, data, sizeof(size)); - data += sizeof(size); - - if (length < size || size % sizeof(Friend) != 0) - return -1; - - Friend *temp = malloc(size); - memcpy(temp, data, size); - - uint16_t num = size / sizeof(Friend); - - uint32_t i; - - for (i = 0; i < num; ++i) { - if (temp[i].status >= 3) { - int fnum = m_addfriend_norequest(m, temp[i].client_id); - setfriendname(m, fnum, temp[i].name); - /* set_friend_statusmessage(fnum, temp[i].statusmessage, temp[i].statusmessage_length); */ - } else if (temp[i].status != 0) { - /* TODO: this is not a good way to do this. */ - uint8_t address[FRIEND_ADDRESS_SIZE]; - memcpy(address, temp[i].client_id, crypto_box_PUBLICKEYBYTES); - memcpy(address + crypto_box_PUBLICKEYBYTES, &(temp[i].friendrequest_nospam), sizeof(uint32_t)); - uint16_t checksum = address_checksum(address, FRIEND_ADDRESS_SIZE - sizeof(checksum)); - memcpy(address + crypto_box_PUBLICKEYBYTES + sizeof(uint32_t), &checksum, sizeof(checksum)); - m_addfriend(m, address, temp[i].info, temp[i].info_size); - } - } - - free(temp); - data += size; - length -= size; - - uint16_t small_size; - - if (length < sizeof(small_size)) - return -1; - - memcpy(&small_size, data, sizeof(small_size)); - data += sizeof(small_size); - length -= sizeof(small_size); - - if (length != small_size) - return -1; - - setname(m, data, small_size); - - return 0; -} diff --git a/core/Messenger.h b/core/Messenger.h deleted file mode 100644 index e808529f..00000000 --- a/core/Messenger.h +++ /dev/null @@ -1,351 +0,0 @@ -/* Messenger.h - * - * An implementation of a simple text chat only messenger on the tox network core. - * - * NOTE: All the text in the messages must be encoded using UTF-8 - * - * Copyright (C) 2013 Tox project All Rights Reserved. - * - * This file is part of Tox. - * - * Tox 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. - * - * Tox 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 Tox. If not, see . - * - */ - -#ifndef MESSENGER_H -#define MESSENGER_H - -#include "net_crypto.h" -#include "DHT.h" -#include "friend_requests.h" -#include "LAN_discovery.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#define MAX_NAME_LENGTH 128 -#define MAX_STATUSMESSAGE_LENGTH 128 - -#define FRIEND_ADDRESS_SIZE (crypto_box_PUBLICKEYBYTES + sizeof(uint32_t) + sizeof(uint16_t)) - -#define PACKET_ID_PING 0 -#define PACKET_ID_NICKNAME 48 -#define PACKET_ID_STATUSMESSAGE 49 -#define PACKET_ID_USERSTATUS 50 -#define PACKET_ID_RECEIPT 65 -#define PACKET_ID_MESSAGE 64 -#define PACKET_ID_ACTION 63 - - -/* status definitions */ -enum { - NOFRIEND, - FRIEND_ADDED, - FRIEND_REQUESTED, - FRIEND_CONFIRMED, - FRIEND_ONLINE, -}; - -/* errors for m_addfriend - * FAERR - Friend Add Error */ -enum { - FAERR_TOOLONG = -1, - FAERR_NOMESSAGE = -2, - FAERR_OWNKEY = -3, - FAERR_ALREADYSENT = -4, - FAERR_UNKNOWN = -5, - FAERR_BADCHECKSUM = -6, - FAERR_SETNEWNOSPAM = -7, - FAERR_NOMEM = -8 -}; - -/* don't assume MAX_STATUSMESSAGE_LENGTH will stay at 128, it may be increased - to an absurdly large number later */ - -/* Default start timeout in seconds between friend requests */ -#define FRIENDREQUEST_TIMEOUT 5; - -/* interval between the sending of ping packets.*/ -#define FRIEND_PING_INTERVAL 5 - -/* If no packets are recieved from friend in this time interval, kill the connection.*/ -#define FRIEND_CONNECTION_TIMEOUT (FRIEND_PING_INTERVAL * 2) - -/* USERSTATUS - * Represents userstatuses someone can have. */ - -typedef enum { - USERSTATUS_NONE, - USERSTATUS_AWAY, - USERSTATUS_BUSY, - USERSTATUS_INVALID -} -USERSTATUS; - -typedef struct { - uint8_t client_id[CLIENT_ID_SIZE]; - int crypt_connection_id; - uint64_t friendrequest_lastsent; /* time at which the last friend request was sent. */ - uint32_t friendrequest_timeout; /* The timeout between successful friendrequest sending attempts */ - uint8_t status; /* 0 if no friend, 1 if added, 2 if friend request sent, 3 if confirmed friend, 4 if online. */ - uint8_t info[MAX_DATA_SIZE]; /* the data that is sent during the friend requests we do */ - uint8_t name[MAX_NAME_LENGTH]; - uint8_t name_sent; /* 0 if we didn't send our name to this friend 1 if we have. */ - uint8_t *statusmessage; - uint16_t statusmessage_length; - uint8_t statusmessage_sent; - USERSTATUS userstatus; - uint8_t userstatus_sent; - uint16_t info_size; /* length of the info */ - uint32_t message_id; /* a semi-unique id used in read receipts */ - uint8_t receives_read_receipts; /* shall we send read receipts to this person? */ - uint32_t friendrequest_nospam; /*The nospam number used in the friend request*/ - uint64_t ping_lastrecv; - uint64_t ping_lastsent; -} Friend; - -typedef struct Messenger { - - Networking_Core *net; - Net_Crypto *net_crypto; - DHT *dht; - Friend_Requests fr; - uint8_t name[MAX_NAME_LENGTH]; - uint16_t name_length; - - uint8_t statusmessage[MAX_STATUSMESSAGE_LENGTH]; - uint16_t statusmessage_length; - - USERSTATUS userstatus; - - Friend *friendlist; - uint32_t numfriends; - - uint64_t last_LANdiscovery; - - void (*friend_message)(struct Messenger *m, int, uint8_t *, uint16_t, void *); - void *friend_message_userdata; - void (*friend_action)(struct Messenger *m, int, uint8_t *, uint16_t, void *); - void *friend_action_userdata; - void (*friend_namechange)(struct Messenger *m, int, uint8_t *, uint16_t, void *); - void *friend_namechange_userdata; - void (*friend_statusmessagechange)(struct Messenger *m, int, uint8_t *, uint16_t, void *); - void *friend_statusmessagechange_userdata; - void (*friend_userstatuschange)(struct Messenger *m, int, USERSTATUS, void *); - void *friend_userstatuschange_userdata; - void (*read_receipt)(struct Messenger *m, int, uint32_t, void *); - void *read_receipt_userdata; - void (*friend_statuschange)(struct Messenger *m, int, uint8_t, void *); - void *friend_statuschange_userdata; - void (*friend_connectionstatuschange)(struct Messenger *m, int, uint8_t, void *); - void *friend_connectionstatuschange_userdata; - - -} Messenger; - -/* - * returns a FRIEND_ADDRESS_SIZE byte address to give to others. - * format: [client_id (32 bytes)][nospam number (4 bytes)][checksum (2 bytes)] - * - */ -void getaddress(Messenger *m, uint8_t *address); - -/* - * add a friend - * set the data that will be sent along with friend request - * address is the address of the friend (returned by getaddress of the friend you wish to add) it must be FRIEND_ADDRESS_SIZE bytes. TODO: add checksum. - * data is the data and length is the length - * returns the friend number if success - * return -1 if message length is too long - * return -2 if no message (message length must be >= 1 byte) - * return -3 if user's own key - * return -4 if friend request already sent or already a friend - * return -5 for unknown error - * return -6 if bad checksum in address - * return -7 if the friend was already there but the nospam was different - * (the nospam for that friend was set to the new one) - * return -8 if increasing the friend list size fails - */ -int m_addfriend(Messenger *m, uint8_t *address, uint8_t *data, uint16_t length); - - -/* add a friend without sending a friendrequest. - returns the friend number if success - return -1 if failure. */ -int m_addfriend_norequest(Messenger *m, uint8_t *client_id); - -/* return the friend id associated to that client id. - return -1 if no such friend */ -int getfriend_id(Messenger *m, uint8_t *client_id); - -/* copies the public key associated to that friend id into client_id buffer. - make sure that client_id is of size CLIENT_ID_SIZE. - return 0 if success - return -1 if failure */ -int getclient_id(Messenger *m, int friend_id, uint8_t *client_id); - -/* remove a friend */ -int m_delfriend(Messenger *m, int friendnumber); - -/* return 4 if friend is online - return 3 if friend is confirmed - return 2 if the friend request was sent - return 1 if the friend was added - return 0 if there is no friend with that number */ -int m_friendstatus(Messenger *m, int friendnumber); - -/* send a text chat message to an online friend - returns the message id if packet was successfully put into the send queue - return 0 if it was not - you will want to retain the return value, it will be passed to your read receipt callback - if one is received. - m_sendmessage_withid will send a message with the id of your choosing, - however we can generate an id for you by calling plain m_sendmessage. */ -uint32_t m_sendmessage(Messenger *m, int friendnumber, uint8_t *message, uint32_t length); -uint32_t m_sendmessage_withid(Messenger *m, int friendnumber, uint32_t theid, uint8_t *message, uint32_t length); - -/* send an action to an online friend - returns 1 if packet was successfully put into the send queue - return 0 if it was not */ -int m_sendaction(Messenger *m, int friendnumber, uint8_t *action, uint32_t length); - -/* Set our nickname - name must be a string of maximum MAX_NAME_LENGTH length. - length must be at least 1 byte - length is the length of name with the NULL terminator - return 0 if success - return -1 if failure */ -int setname(Messenger *m, uint8_t *name, uint16_t length); - -/* - Get your nickname. - m The messanger context to use. - name Pointer to a string for the name. - nlen The length of the string buffer. - returns Return the length of the name, 0 on error. -*/ -uint16_t getself_name(Messenger *m, uint8_t *name, uint16_t nlen); - -/* get name of friendnumber - put it in name - name needs to be a valid memory location with a size of at least MAX_NAME_LENGTH (128) bytes. - return 0 if success - return -1 if failure */ -int getname(Messenger *m, int friendnumber, uint8_t *name); - -/* set our user status - you are responsible for freeing status after - returns 0 on success, -1 on failure */ -int m_set_statusmessage(Messenger *m, uint8_t *status, uint16_t length); -int m_set_userstatus(Messenger *m, USERSTATUS status); - -/* return the length of friendnumber's status message, - including null - pass it into malloc */ -int m_get_statusmessage_size(Messenger *m, int friendnumber); - -/* copy friendnumber's status message into buf, truncating if size is over maxlen - get the size you need to allocate from m_get_statusmessage_size - The self variant will copy our own status message. */ -int m_copy_statusmessage(Messenger *m, int friendnumber, uint8_t *buf, uint32_t maxlen); -int m_copy_self_statusmessage(Messenger *m, uint8_t *buf, uint32_t maxlen); - -/* Return one of USERSTATUS values. - * Values unknown to your application should be represented as USERSTATUS_NONE. - * As above, the self variant will return our own USERSTATUS. - * If friendnumber is invalid, this shall return USERSTATUS_INVALID. */ -USERSTATUS m_get_userstatus(Messenger *m, int friendnumber); -USERSTATUS m_get_self_userstatus(Messenger *m); - -/* Sets whether we send read receipts for friendnumber. - * This function is not lazy, and it will fail if yesno is not (0 or 1).*/ -void m_set_sends_receipts(Messenger *m, int friendnumber, int yesno); - -/* set the function that will be executed when a friend request is received. - function format is function(uint8_t * public_key, uint8_t * data, uint16_t length) */ -void m_callback_friendrequest(Messenger *m, void (*function)(uint8_t *, uint8_t *, uint16_t, void *), void *userdata); - -/* set the function that will be executed when a message from a friend is received. - function format is: function(int friendnumber, uint8_t * message, uint32_t length) */ -void m_callback_friendmessage(Messenger *m, void (*function)(Messenger *m, int, uint8_t *, uint16_t, void *), - void *userdata); - -/* set the function that will be executed when an action from a friend is received. - function format is: function(int friendnumber, uint8_t * action, uint32_t length) */ -void m_callback_action(Messenger *m, void (*function)(Messenger *m, int, uint8_t *, uint16_t, void *), void *userdata); - -/* set the callback for name changes - function(int friendnumber, uint8_t *newname, uint16_t length) - you are not responsible for freeing newname */ -void m_callback_namechange(Messenger *m, void (*function)(Messenger *m, int, uint8_t *, uint16_t, void *), - void *userdata); - -/* set the callback for status message changes - function(int friendnumber, uint8_t *newstatus, uint16_t length) - you are not responsible for freeing newstatus */ -void m_callback_statusmessage(Messenger *m, void (*function)(Messenger *m, int, uint8_t *, uint16_t, void *), - void *userdata); - -/* set the callback for status type changes - function(int friendnumber, USERSTATUS kind) */ -void m_callback_userstatus(Messenger *m, void (*function)(Messenger *m, int, USERSTATUS, void *), void *userdata); - -/* set the callback for read receipts - function(int friendnumber, uint32_t receipt) - if you are keeping a record of returns from m_sendmessage, - receipt might be one of those values, and that means the message - has been received on the other side. since core doesn't - track ids for you, receipt may not correspond to any message - in that case, you should discard it. */ -void m_callback_read_receipt(Messenger *m, void (*function)(Messenger *m, int, uint32_t, void *), void *userdata); - -/* set the callback for connection status changes - function(int friendnumber, uint8_t status) - status: - 0 -- friend went offline after being previously online - 1 -- friend went online - note that this callback is not called when adding friends, thus the "after - being previously online" part. it's assumed that when adding friends, - their connection status is offline. */ -void m_callback_connectionstatus(Messenger *m, void (*function)(Messenger *m, int, uint8_t, void *), void *userdata); - -/* run this at startup - * returns allocated instance of Messenger on success - * returns 0 if there are problems */ -Messenger *initMessenger(void); - -/* run this before closing shop - * free all datastructures */ -void cleanupMessenger(Messenger *M); - -/* the main loop that needs to be run at least 200 times per second */ -void doMessenger(Messenger *m); - -/* SAVING AND LOADING FUNCTIONS: */ - -/* returns the size of the messenger data (for saving) */ -uint32_t Messenger_size(Messenger *m); - -/* save the messenger in data (must be allocated memory of size Messenger_size()) */ -void Messenger_save(Messenger *m, uint8_t *data); - -/* load the messenger from data of size length */ -int Messenger_load(Messenger *m, uint8_t *data, uint32_t length); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/core/friend_requests.c b/core/friend_requests.c deleted file mode 100644 index d8c6858b..00000000 --- a/core/friend_requests.c +++ /dev/null @@ -1,141 +0,0 @@ -/* friend_requests.c - * - * Handle friend requests. - * - * Copyright (C) 2013 Tox project All Rights Reserved. - * - * This file is part of Tox. - * - * Tox 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. - * - * Tox 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 Tox. If not, see . - * - */ - -#include "friend_requests.h" - -/* Try to send a friendrequest to peer with public_key - data is the data in the request and length is the length. - return -1 if failure. - return 0 if it sent the friend request directly to the friend. - return the number of peers it was routed through if it did not send it directly.*/ -int send_friendrequest(DHT *dht, uint8_t *public_key, uint32_t nospam_num, uint8_t *data, uint32_t length) -{ - if (length + sizeof(nospam_num) > MAX_DATA_SIZE) - return -1; - - uint8_t temp[MAX_DATA_SIZE]; - memcpy(temp, &nospam_num, sizeof(nospam_num)); - memcpy(temp + sizeof(nospam_num), data, length); - uint8_t packet[MAX_DATA_SIZE]; - int len = create_request(dht->c->self_public_key, dht->c->self_secret_key, packet, public_key, temp, - length + sizeof(nospam_num), - CRYPTO_PACKET_FRIEND_REQ); - - if (len == -1) - return -1; - - IP_Port ip_port = DHT_getfriendip(dht, public_key); - - if (ip_port.ip.i == 1) - return -1; - - if (ip_port.ip.i != 0) { - if (sendpacket(dht->c->lossless_udp->net->sock, ip_port, packet, len) != -1) - return 0; - - return -1; - } - - int num = route_tofriend(dht, public_key, packet, len); - - if (num == 0) - return -1; - - return num; -} - - -/* - * Set and get the nospam variable used to prevent one type of friend request spam - */ -void set_nospam(Friend_Requests *fr, uint32_t num) -{ - fr->nospam = num; -} - -uint32_t get_nospam(Friend_Requests *fr) -{ - return fr->nospam; -} - - -/* set the function that will be executed when a friend request is received. */ -void callback_friendrequest(Friend_Requests *fr, void (*function)(uint8_t *, uint8_t *, uint16_t, void *), - void *userdata) -{ - fr->handle_friendrequest = function; - fr->handle_friendrequest_isset = 1; - fr->handle_friendrequest_userdata = userdata; -} - -/*Add to list of received friend requests*/ -static void addto_receivedlist(Friend_Requests *fr, uint8_t *client_id) -{ - if (fr->received_requests_index >= MAX_RECEIVED_STORED) - fr->received_requests_index = 0; - - memcpy(fr->received_requests[fr->received_requests_index], client_id, crypto_box_PUBLICKEYBYTES); - ++fr->received_requests_index; -} - -/* Check if a friend request was already received - return 0 if not, 1 if we did */ -static int request_received(Friend_Requests *fr, uint8_t *client_id) -{ - uint32_t i; - - for (i = 0; i < MAX_RECEIVED_STORED; ++i) { - if (memcmp(fr->received_requests[i], client_id, crypto_box_PUBLICKEYBYTES) == 0) - return 1; - } - - return 0; -} - - -static int friendreq_handlepacket(void *object, IP_Port source, uint8_t *source_pubkey, uint8_t *packet, - uint32_t length) -{ - Friend_Requests *fr = object; - - if (fr->handle_friendrequest_isset == 0) - return 1; - - if (length <= sizeof(fr->nospam)) - return 1; - - if (request_received(fr, source_pubkey)) - return 1; - - if (memcmp(packet, &fr->nospam, sizeof(fr->nospam)) != 0) - return 1; - - addto_receivedlist(fr, source_pubkey); - (*fr->handle_friendrequest)(source_pubkey, packet + 4, length - 4, fr->handle_friendrequest_userdata); - return 0; -} - -void friendreq_init(Friend_Requests *fr, Net_Crypto *c) -{ - cryptopacket_registerhandler(c, CRYPTO_PACKET_FRIEND_REQ, &friendreq_handlepacket, fr); -} diff --git a/core/friend_requests.h b/core/friend_requests.h deleted file mode 100644 index 2ebd557b..00000000 --- a/core/friend_requests.h +++ /dev/null @@ -1,70 +0,0 @@ -/* friend_requests.h - * - * Handle friend requests. - * - * Copyright (C) 2013 Tox project All Rights Reserved. - * - * This file is part of Tox. - * - * Tox 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. - * - * Tox 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 Tox. If not, see . - * - */ - -#ifndef FRIEND_REQUESTS_H -#define FRIEND_REQUESTS_H - -#include "DHT.h" -#include "net_crypto.h" - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct { - uint32_t nospam; - void (*handle_friendrequest)(uint8_t *, uint8_t *, uint16_t, void *); - uint8_t handle_friendrequest_isset; - void *handle_friendrequest_userdata; - - /*NOTE: the following is just a temporary fix for the multiple friend requests received at the same time problem - TODO: Make this better (This will most likely tie in with the way we will handle spam.)*/ - -#define MAX_RECEIVED_STORED 32 - - uint8_t received_requests[MAX_RECEIVED_STORED][crypto_box_PUBLICKEYBYTES]; - uint16_t received_requests_index; -} Friend_Requests; - -/* Try to send a friendrequest to peer with public_key - data is the data in the request and length is the length. */ -int send_friendrequest(DHT *dht, uint8_t *public_key, uint32_t nospam_num, uint8_t *data, uint32_t length); -/* - * Set and get the nospam variable used to prevent one type of friend request spam - */ -void set_nospam(Friend_Requests *fr, uint32_t num); -uint32_t get_nospam(Friend_Requests *fr); - -/* set the function that will be executed when a friend request for us is received. - function format is function(uint8_t * public_key, uint8_t * data, uint16_t length) */ -void callback_friendrequest(Friend_Requests *fr, void (*function)(uint8_t *, uint8_t *, uint16_t, void *), - void *userdata); - -/* sets up friendreq packet handlers */ -void friendreq_init(Friend_Requests *fr, Net_Crypto *c); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/core/net_crypto.c b/core/net_crypto.c deleted file mode 100644 index f421c37d..00000000 --- a/core/net_crypto.c +++ /dev/null @@ -1,771 +0,0 @@ -/* net_crypto.c - * - * Functions for the core network crypto. - * See also: http://wiki.tox.im/index.php/DHT - * - * NOTE: This code has to be perfect. We don't mess around with encryption. - * - * Copyright (C) 2013 Tox project All Rights Reserved. - * - * This file is part of Tox. - * - * Tox 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. - * - * Tox 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 Tox. If not, see . - * - */ - -#include "net_crypto.h" - -#define CONN_NO_CONNECTION 0 -#define CONN_HANDSHAKE_SENT 1 -#define CONN_NOT_CONFIRMED 2 -#define CONN_ESTABLISHED 3 -#define CONN_TIMED_OUT 4 - -/* Use this instead of memcmp; not vulnerable to timing attacks. */ -uint8_t crypto_iszero(uint8_t *mem, uint32_t length) -{ - uint8_t check = 0; - uint32_t i; - - for (i = 0; i < length; ++i) { - check |= mem[i]; - } - - return check; // We return zero if mem is made out of zeroes. -} - -/* Precomputes the shared key from their public_key and our secret_key. - This way we can avoid an expensive elliptic curve scalar multiply for each - encrypt/decrypt operation. - enc_key has to be crypto_box_BEFORENMBYTES bytes long. */ -void encrypt_precompute(uint8_t *public_key, uint8_t *secret_key, uint8_t *enc_key) -{ - crypto_box_beforenm(enc_key, public_key, secret_key); -} - -/* Fast encrypt. Depends on enc_key from encrypt_precompute. */ -int encrypt_data_fast(uint8_t *enc_key, uint8_t *nonce, - uint8_t *plain, uint32_t length, uint8_t *encrypted) -{ - if (length + crypto_box_MACBYTES > MAX_DATA_SIZE || length == 0) - return -1; - - uint8_t temp_plain[MAX_DATA_SIZE + crypto_box_ZEROBYTES] = {0}; - uint8_t temp_encrypted[MAX_DATA_SIZE + crypto_box_BOXZEROBYTES]; - - memcpy(temp_plain + crypto_box_ZEROBYTES, plain, length); /* pad the message with 32 0 bytes. */ - - crypto_box_afternm(temp_encrypted, temp_plain, length + crypto_box_ZEROBYTES, nonce, enc_key); - - if (crypto_iszero(temp_encrypted, crypto_box_BOXZEROBYTES) != 0) - return -1; - - /* unpad the encrypted message */ - memcpy(encrypted, temp_encrypted + crypto_box_BOXZEROBYTES, length + crypto_box_MACBYTES); - return length - crypto_box_BOXZEROBYTES + crypto_box_ZEROBYTES; -} - -/* Fast decrypt. Depends on enc_ley from encrypt_precompute. */ -int decrypt_data_fast(uint8_t *enc_key, uint8_t *nonce, - uint8_t *encrypted, uint32_t length, uint8_t *plain) -{ - if (length > MAX_DATA_SIZE || length <= crypto_box_BOXZEROBYTES) - return -1; - - uint8_t temp_plain[MAX_DATA_SIZE + crypto_box_ZEROBYTES]; - uint8_t temp_encrypted[MAX_DATA_SIZE + crypto_box_BOXZEROBYTES] = {0}; - - memcpy(temp_encrypted + crypto_box_BOXZEROBYTES, encrypted, length); /* pad the message with 16 0 bytes. */ - - if (crypto_box_open_afternm(temp_plain, temp_encrypted, length + crypto_box_BOXZEROBYTES, - nonce, enc_key) == -1) - return -1; - - /* if decryption is successful the first crypto_box_ZEROBYTES of the message will be zero - apparently memcmp should not be used so we do this instead:*/ - if (crypto_iszero(temp_plain, crypto_box_ZEROBYTES) != 0) - return -1; - - /* unpad the plain message */ - memcpy(plain, temp_plain + crypto_box_ZEROBYTES, length - crypto_box_MACBYTES); - return length - crypto_box_ZEROBYTES + crypto_box_BOXZEROBYTES; -} - -int encrypt_data(uint8_t *public_key, uint8_t *secret_key, uint8_t *nonce, - uint8_t *plain, uint32_t length, uint8_t *encrypted) -{ - uint8_t k[crypto_box_BEFORENMBYTES]; - encrypt_precompute(public_key, secret_key, k); - return encrypt_data_fast(k, nonce, plain, length, encrypted); -} - -int decrypt_data(uint8_t *public_key, uint8_t *secret_key, uint8_t *nonce, - uint8_t *encrypted, uint32_t length, uint8_t *plain) -{ - uint8_t k[crypto_box_BEFORENMBYTES]; - encrypt_precompute(public_key, secret_key, k); - return decrypt_data_fast(k, nonce, encrypted, length, plain); -} - -/* increment the given nonce by 1 */ -static void increment_nonce(uint8_t *nonce) -{ - uint32_t i; - - for (i = 0; i < crypto_box_NONCEBYTES; ++i) { - ++nonce[i]; - - if (nonce[i] != 0) - break; - } -} - -/* fill the given nonce with random bytes. */ -void random_nonce(uint8_t *nonce) -{ - uint32_t i, temp; - - for (i = 0; i < crypto_box_NONCEBYTES / 4; ++i) { - temp = random_int(); - memcpy(nonce + 4 * i, &temp, 4); - } -} - -/* return 0 if there is no received data in the buffer - return -1 if the packet was discarded. - return length of received data if successful */ -int read_cryptpacket(Net_Crypto *c, int crypt_connection_id, uint8_t *data) -{ - if (crypt_connection_id < 0 || crypt_connection_id >= c->crypto_connections_length) - return 0; - - if (c->crypto_connections[crypt_connection_id].status != CONN_ESTABLISHED) - return 0; - - uint8_t temp_data[MAX_DATA_SIZE]; - int length = read_packet(c->lossless_udp, c->crypto_connections[crypt_connection_id].number, temp_data); - - if (length == 0) - return 0; - - if (temp_data[0] != 3) - return -1; - - int len = decrypt_data_fast(c->crypto_connections[crypt_connection_id].shared_key, - c->crypto_connections[crypt_connection_id].recv_nonce, - temp_data + 1, length - 1, data); - - if (len != -1) { - increment_nonce(c->crypto_connections[crypt_connection_id].recv_nonce); - return len; - } - - return -1; -} - -/* return 0 if data could not be put in packet queue - return 1 if data was put into the queue */ -int write_cryptpacket(Net_Crypto *c, int crypt_connection_id, uint8_t *data, uint32_t length) -{ - if (crypt_connection_id < 0 || crypt_connection_id >= c->crypto_connections_length) - return 0; - - if (length - crypto_box_BOXZEROBYTES + crypto_box_ZEROBYTES > MAX_DATA_SIZE - 1) - return 0; - - if (c->crypto_connections[crypt_connection_id].status != CONN_ESTABLISHED) - return 0; - - uint8_t temp_data[MAX_DATA_SIZE]; - int len = encrypt_data_fast(c->crypto_connections[crypt_connection_id].shared_key, - c->crypto_connections[crypt_connection_id].sent_nonce, - data, length, temp_data + 1); - - if (len == -1) - return 0; - - temp_data[0] = 3; - - if (write_packet(c->lossless_udp, c->crypto_connections[crypt_connection_id].number, temp_data, len + 1) == 0) - return 0; - - increment_nonce(c->crypto_connections[crypt_connection_id].sent_nonce); - return 1; -} - -/* create a request to peer. - send_public_key and send_secret_key are the pub/secret keys of the sender - recv_public_key is public key of reciever - packet must be an array of MAX_DATA_SIZE big. - Data represents the data we send with the request with length being the length of the data. - request_id is the id of the request (32 = friend request, 254 = ping request) - returns -1 on failure - returns the length of the created packet on success */ -int create_request(uint8_t *send_public_key, uint8_t *send_secret_key, uint8_t *packet, uint8_t *recv_public_key, - uint8_t *data, uint32_t length, uint8_t request_id) -{ - if (MAX_DATA_SIZE < length + 1 + crypto_box_PUBLICKEYBYTES * 2 + crypto_box_NONCEBYTES + 1 + ENCRYPTION_PADDING) - return -1; - - uint8_t nonce[crypto_box_NONCEBYTES]; - uint8_t temp[MAX_DATA_SIZE]; - memcpy(temp + 1, data, length); - temp[0] = request_id; - random_nonce(nonce); - int len = encrypt_data(recv_public_key, send_secret_key, nonce, temp, length + 1, - 1 + crypto_box_PUBLICKEYBYTES * 2 + crypto_box_NONCEBYTES + packet); - - if (len == -1) - return -1; - - packet[0] = NET_PACKET_CRYPTO; - memcpy(packet + 1, recv_public_key, crypto_box_PUBLICKEYBYTES); - memcpy(packet + 1 + crypto_box_PUBLICKEYBYTES, send_public_key, crypto_box_PUBLICKEYBYTES); - memcpy(packet + 1 + crypto_box_PUBLICKEYBYTES * 2, nonce, crypto_box_NONCEBYTES); - - return len + 1 + crypto_box_PUBLICKEYBYTES * 2 + crypto_box_NONCEBYTES; -} - -/* puts the senders public key in the request in public_key, the data from the request - in data if a friend or ping request was sent to us and returns the length of the data. - packet is the request packet and length is its length - return -1 if not valid request. */ -static int handle_request(Net_Crypto *c, uint8_t *public_key, uint8_t *data, uint8_t *request_id, uint8_t *packet, - uint16_t length) -{ - - if (length > crypto_box_PUBLICKEYBYTES * 2 + crypto_box_NONCEBYTES + 1 + ENCRYPTION_PADDING && - length <= MAX_DATA_SIZE + ENCRYPTION_PADDING && - memcmp(packet + 1, c->self_public_key, crypto_box_PUBLICKEYBYTES) == 0) { - memcpy(public_key, packet + 1 + crypto_box_PUBLICKEYBYTES, crypto_box_PUBLICKEYBYTES); - uint8_t nonce[crypto_box_NONCEBYTES]; - uint8_t temp[MAX_DATA_SIZE]; - memcpy(nonce, packet + 1 + crypto_box_PUBLICKEYBYTES * 2, crypto_box_NONCEBYTES); - int len1 = decrypt_data(public_key, c->self_secret_key, nonce, - packet + 1 + crypto_box_PUBLICKEYBYTES * 2 + crypto_box_NONCEBYTES, - length - (crypto_box_PUBLICKEYBYTES * 2 + crypto_box_NONCEBYTES + 1), temp); - - if (len1 == -1 || len1 == 0) - return -1; - - request_id[0] = temp[0]; - --len1; - memcpy(data, temp + 1, len1); - return len1; - } else - return -1; -} - -void cryptopacket_registerhandler(Net_Crypto *c, uint8_t byte, cryptopacket_handler_callback cb, void *object) -{ - c->cryptopackethandlers[byte].function = cb; - c->cryptopackethandlers[byte].object = object; -} - -static int cryptopacket_handle(void *object, IP_Port source, uint8_t *packet, uint32_t length) -{ - DHT *dht = object; - - if (packet[0] == NET_PACKET_CRYPTO) { - if (length <= crypto_box_PUBLICKEYBYTES * 2 + crypto_box_NONCEBYTES + 1 + ENCRYPTION_PADDING || - length > MAX_DATA_SIZE + ENCRYPTION_PADDING) - return 1; - - if (memcmp(packet + 1, dht->c->self_public_key, crypto_box_PUBLICKEYBYTES) == 0) {// check if request is for us. - uint8_t public_key[crypto_box_PUBLICKEYBYTES]; - uint8_t data[MAX_DATA_SIZE]; - uint8_t number; - int len = handle_request(dht->c, public_key, data, &number, packet, length); - - if (len == -1 || len == 0) - return 1; - - if (!dht->c->cryptopackethandlers[number].function) return 1; - - dht->c->cryptopackethandlers[number].function(dht->c->cryptopackethandlers[number].object, source, public_key, data, - len); - - } else { /* if request is not for us, try routing it. */ - if (route_packet(dht, packet + 1, packet, length) == length) //NOTE - return 0; - } - } - - return 1; -} - -/* Send a crypto handshake packet containing an encrypted secret nonce and session public key - to peer with connection_id and public_key - the packet is encrypted with a random nonce which is sent in plain text with the packet */ -static int send_cryptohandshake(Net_Crypto *c, int connection_id, uint8_t *public_key, uint8_t *secret_nonce, - uint8_t *session_key) -{ - uint8_t temp_data[MAX_DATA_SIZE]; - uint8_t temp[crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES]; - uint8_t nonce[crypto_box_NONCEBYTES]; - - random_nonce(nonce); - memcpy(temp, secret_nonce, crypto_box_NONCEBYTES); - memcpy(temp + crypto_box_NONCEBYTES, session_key, crypto_box_PUBLICKEYBYTES); - - int len = encrypt_data(public_key, c->self_secret_key, nonce, temp, crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES, - 1 + crypto_box_PUBLICKEYBYTES + crypto_box_NONCEBYTES + temp_data); - - if (len == -1) - return 0; - - temp_data[0] = 2; - memcpy(temp_data + 1, c->self_public_key, crypto_box_PUBLICKEYBYTES); - memcpy(temp_data + 1 + crypto_box_PUBLICKEYBYTES, nonce, crypto_box_NONCEBYTES); - return write_packet(c->lossless_udp, connection_id, temp_data, - len + 1 + crypto_box_PUBLICKEYBYTES + crypto_box_NONCEBYTES); -} - -/* Extract secret nonce, session public key and public_key from a packet(data) with length length - return 1 if successful - return 0 if failure */ -static int handle_cryptohandshake(Net_Crypto *c, uint8_t *public_key, uint8_t *secret_nonce, - uint8_t *session_key, uint8_t *data, uint16_t length) -{ - int pad = (- crypto_box_BOXZEROBYTES + crypto_box_ZEROBYTES); - - if (length != 1 + crypto_box_PUBLICKEYBYTES + crypto_box_NONCEBYTES - + crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES + pad) { - return 0; - } - - if (data[0] != 2) - return 0; - - uint8_t temp[crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES]; - - memcpy(public_key, data + 1, crypto_box_PUBLICKEYBYTES); - - int len = decrypt_data(public_key, c->self_secret_key, data + 1 + crypto_box_PUBLICKEYBYTES, - data + 1 + crypto_box_PUBLICKEYBYTES + crypto_box_NONCEBYTES, - crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES + pad, temp); - - if (len != crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES) - return 0; - - memcpy(secret_nonce, temp, crypto_box_NONCEBYTES); - memcpy(session_key, temp + crypto_box_NONCEBYTES, crypto_box_PUBLICKEYBYTES); - return 1; -} - -/* get crypto connection id from public key of peer - return -1 if there are no connections like we are looking for - return id if it found it */ -static int getcryptconnection_id(Net_Crypto *c, uint8_t *public_key) -{ - uint32_t i; - - for (i = 0; i < c->crypto_connections_length; ++i) { - if (c->crypto_connections[i].status != CONN_NO_CONNECTION) - if (memcmp(public_key, c->crypto_connections[i].public_key, crypto_box_PUBLICKEYBYTES) == 0) - return i; - } - - return -1; -} - -/* set the size of the friend list to numfriends - return -1 if realloc fails */ -int realloc_cryptoconnection(Net_Crypto *c, uint32_t num) -{ - if (num == 0) { - free(c->crypto_connections); - c->crypto_connections = NULL; - return 0; - } - - Crypto_Connection *newcrypto_connections = realloc(c->crypto_connections, num * sizeof(Crypto_Connection)); - - if (newcrypto_connections == NULL) - return -1; - - c->crypto_connections = newcrypto_connections; - return 0; -} - -/* Start a secure connection with other peer who has public_key and ip_port - returns -1 if failure - returns crypt_connection_id of the initialized connection if everything went well. */ -int crypto_connect(Net_Crypto *c, uint8_t *public_key, IP_Port ip_port) -{ - uint32_t i; - int id = getcryptconnection_id(c, public_key); - - if (id != -1) { - IP_Port c_ip = connection_ip(c->lossless_udp, c->crypto_connections[id].number); - - if (c_ip.ip.i == ip_port.ip.i && c_ip.port == ip_port.port) - return -1; - } - - if (realloc_cryptoconnection(c, c->crypto_connections_length + 1) == -1) - return -1; - - memset(&(c->crypto_connections[c->crypto_connections_length]), 0, sizeof(Crypto_Connection)); - c->crypto_connections[c->crypto_connections_length].number = ~0; - - for (i = 0; i <= c->crypto_connections_length; ++i) { - if (c->crypto_connections[i].status == CONN_NO_CONNECTION) { - int id = new_connection(c->lossless_udp, ip_port); - - if (id == -1) - return -1; - - c->crypto_connections[i].number = id; - c->crypto_connections[i].status = CONN_HANDSHAKE_SENT; - random_nonce(c->crypto_connections[i].recv_nonce); - memcpy(c->crypto_connections[i].public_key, public_key, crypto_box_PUBLICKEYBYTES); - crypto_box_keypair(c->crypto_connections[i].sessionpublic_key, c->crypto_connections[i].sessionsecret_key); - - if (c->crypto_connections_length == i) - ++c->crypto_connections_length; - - if (send_cryptohandshake(c, id, public_key, c->crypto_connections[i].recv_nonce, - c->crypto_connections[i].sessionpublic_key) == 1) { - increment_nonce(c->crypto_connections[i].recv_nonce); - return i; - } - - return -1; /* this should never happen. */ - } - } - - return -1; -} - -/* handle an incoming connection - return -1 if no crypto inbound connection - return incoming connection id (Lossless_UDP one) if there is an incoming crypto connection - Put the public key of the peer in public_key, the secret_nonce from the handshake into secret_nonce - and the session public key for the connection in session_key - to accept it see: accept_crypto_inbound(...) - to refuse it just call kill_connection(...) on the connection id */ -int crypto_inbound(Net_Crypto *c, uint8_t *public_key, uint8_t *secret_nonce, uint8_t *session_key) -{ - uint32_t i; - - for (i = 0; i < MAX_INCOMING; ++i) { - if (c->incoming_connections[i] != -1) { - if (is_connected(c->lossless_udp, c->incoming_connections[i]) == 4 - || is_connected(c->lossless_udp, c->incoming_connections[i]) == 0) { - kill_connection(c->lossless_udp, c->incoming_connections[i]); - c->incoming_connections[i] = -1; - continue; - } - - if (id_packet(c->lossless_udp, c->incoming_connections[i]) == 2) { - uint8_t temp_data[MAX_DATA_SIZE]; - uint16_t len = read_packet(c->lossless_udp, c->incoming_connections[i], temp_data); - - if (handle_cryptohandshake(c, public_key, secret_nonce, session_key, temp_data, len)) { - int connection_id = c->incoming_connections[i]; - c->incoming_connections[i] = -1; /* remove this connection from the incoming connection list. */ - return connection_id; - } - } - } - } - - return -1; -} - -/* kill a crypto connection - return 0 if killed successfully - return 1 if there was a problem. */ -int crypto_kill(Net_Crypto *c, int crypt_connection_id) -{ - if (crypt_connection_id < 0 || crypt_connection_id >= c->crypto_connections_length) - return 1; - - if (c->crypto_connections[crypt_connection_id].status != CONN_NO_CONNECTION) { - c->crypto_connections[crypt_connection_id].status = CONN_NO_CONNECTION; - kill_connection(c->lossless_udp, c->crypto_connections[crypt_connection_id].number); - memset(&(c->crypto_connections[crypt_connection_id]), 0 , sizeof(Crypto_Connection)); - c->crypto_connections[crypt_connection_id].number = ~0; - uint32_t i; - - for (i = c->crypto_connections_length; i != 0; --i) { - if (c->crypto_connections[i - 1].status != CONN_NO_CONNECTION) - break; - } - - c->crypto_connections_length = i; - realloc_cryptoconnection(c, c->crypto_connections_length); - return 0; - } - - return 1; -} - -/* accept an incoming connection using the parameters provided by crypto_inbound - return -1 if not successful - returns the crypt_connection_id if successful */ -int accept_crypto_inbound(Net_Crypto *c, int connection_id, uint8_t *public_key, uint8_t *secret_nonce, - uint8_t *session_key) -{ - uint32_t i; - - if (connection_id == -1) - return -1; - - /* - if(getcryptconnection_id(public_key) != -1) - { - return -1; - }*/ - if (realloc_cryptoconnection(c, c->crypto_connections_length + 1) == -1) - return -1; - - memset(&(c->crypto_connections[c->crypto_connections_length]), 0, sizeof(Crypto_Connection)); - c->crypto_connections[c->crypto_connections_length].number = ~0; - - for (i = 0; i <= c->crypto_connections_length; ++i) { - if (c->crypto_connections[i].status == CONN_NO_CONNECTION) { - c->crypto_connections[i].number = connection_id; - c->crypto_connections[i].status = CONN_NOT_CONFIRMED; - random_nonce(c->crypto_connections[i].recv_nonce); - memcpy(c->crypto_connections[i].sent_nonce, secret_nonce, crypto_box_NONCEBYTES); - memcpy(c->crypto_connections[i].peersessionpublic_key, session_key, crypto_box_PUBLICKEYBYTES); - increment_nonce(c->crypto_connections[i].sent_nonce); - memcpy(c->crypto_connections[i].public_key, public_key, crypto_box_PUBLICKEYBYTES); - - crypto_box_keypair(c->crypto_connections[i].sessionpublic_key, c->crypto_connections[i].sessionsecret_key); - - if (c->crypto_connections_length == i) - ++c->crypto_connections_length; - - if (send_cryptohandshake(c, connection_id, public_key, c->crypto_connections[i].recv_nonce, - c->crypto_connections[i].sessionpublic_key) == 1) { - increment_nonce(c->crypto_connections[i].recv_nonce); - uint32_t zero = 0; - encrypt_precompute(c->crypto_connections[i].peersessionpublic_key, - c->crypto_connections[i].sessionsecret_key, - c->crypto_connections[i].shared_key); - c->crypto_connections[i].status = - CONN_ESTABLISHED; /* connection status needs to be 3 for write_cryptpacket() to work */ - write_cryptpacket(c, i, ((uint8_t *)&zero), sizeof(zero)); - c->crypto_connections[i].status = CONN_NOT_CONFIRMED; /* set it to its proper value right after. */ - return i; - } - - return -1; /* this should never happen. */ - } - } - - return -1; -} - -/* return 0 if no connection, 1 we have sent a handshake, 2 if connection is not confirmed yet - (we have received a handshake but no empty data packet), 3 if the connection is established. - 4 if the connection is timed out and waiting to be killed */ -int is_cryptoconnected(Net_Crypto *c, int crypt_connection_id) -{ - if (crypt_connection_id >= 0 && crypt_connection_id < c->crypto_connections_length) - return c->crypto_connections[crypt_connection_id].status; - - return CONN_NO_CONNECTION; -} - -void new_keys(Net_Crypto *c) -{ - crypto_box_keypair(c->self_public_key, c->self_secret_key); -} - -/* save the public and private keys to the keys array - Length must be crypto_box_PUBLICKEYBYTES + crypto_box_SECRETKEYBYTES */ -void save_keys(Net_Crypto *c, uint8_t *keys) -{ - memcpy(keys, c->self_public_key, crypto_box_PUBLICKEYBYTES); - memcpy(keys + crypto_box_PUBLICKEYBYTES, c->self_secret_key, crypto_box_SECRETKEYBYTES); -} - -/* load the public and private keys from the keys array - Length must be crypto_box_PUBLICKEYBYTES + crypto_box_SECRETKEYBYTES */ -void load_keys(Net_Crypto *c, uint8_t *keys) -{ - memcpy(c->self_public_key, keys, crypto_box_PUBLICKEYBYTES); - memcpy(c->self_secret_key, keys + crypto_box_PUBLICKEYBYTES, crypto_box_SECRETKEYBYTES); -} - -/* TODO: optimize this - adds an incoming connection to the incoming_connection list. - returns 0 if successful - returns 1 if failure */ -static int new_incoming(Net_Crypto *c, int id) -{ - uint32_t i; - - for (i = 0; i < MAX_INCOMING; ++i) { - if (c->incoming_connections[i] == -1) { - c->incoming_connections[i] = id; - return 0; - } - } - - return 1; -} - -/* TODO: optimize this - handle all new incoming connections. */ -static void handle_incomings(Net_Crypto *c) -{ - int income; - - while (1) { - income = incoming_connection(c->lossless_udp); - - if (income == -1 || new_incoming(c, income) ) - break; - } -} - -/* handle received packets for not yet established crypto connections. */ -static void receive_crypto(Net_Crypto *c) -{ - uint32_t i; - - for (i = 0; i < c->crypto_connections_length; ++i) { - if (c->crypto_connections[i].status == CONN_HANDSHAKE_SENT) { - uint8_t temp_data[MAX_DATA_SIZE]; - uint8_t secret_nonce[crypto_box_NONCEBYTES]; - uint8_t public_key[crypto_box_PUBLICKEYBYTES]; - uint8_t session_key[crypto_box_PUBLICKEYBYTES]; - uint16_t len; - - if (id_packet(c->lossless_udp, c->crypto_connections[i].number) == 2) { /* handle handshake packet. */ - len = read_packet(c->lossless_udp, c->crypto_connections[i].number, temp_data); - - if (handle_cryptohandshake(c, public_key, secret_nonce, session_key, temp_data, len)) { - if (memcmp(public_key, c->crypto_connections[i].public_key, crypto_box_PUBLICKEYBYTES) == 0) { - memcpy(c->crypto_connections[i].sent_nonce, secret_nonce, crypto_box_NONCEBYTES); - memcpy(c->crypto_connections[i].peersessionpublic_key, session_key, crypto_box_PUBLICKEYBYTES); - increment_nonce(c->crypto_connections[i].sent_nonce); - uint32_t zero = 0; - encrypt_precompute(c->crypto_connections[i].peersessionpublic_key, - c->crypto_connections[i].sessionsecret_key, - c->crypto_connections[i].shared_key); - c->crypto_connections[i].status = - CONN_ESTABLISHED; /* connection status needs to be 3 for write_cryptpacket() to work */ - write_cryptpacket(c, i, ((uint8_t *)&zero), sizeof(zero)); - c->crypto_connections[i].status = CONN_NOT_CONFIRMED; /* set it to its proper value right after. */ - } - } - } else if (id_packet(c->lossless_udp, - c->crypto_connections[i].number) != -1) { // This should not happen kill the connection if it does - crypto_kill(c, i); - return; - } - } - - if (c->crypto_connections[i].status == CONN_NOT_CONFIRMED) { - if (id_packet(c->lossless_udp, c->crypto_connections[i].number) == 3) { - uint8_t temp_data[MAX_DATA_SIZE]; - uint8_t data[MAX_DATA_SIZE]; - int length = read_packet(c->lossless_udp, c->crypto_connections[i].number, temp_data); - int len = decrypt_data(c->crypto_connections[i].peersessionpublic_key, - c->crypto_connections[i].sessionsecret_key, - c->crypto_connections[i].recv_nonce, temp_data + 1, length - 1, data); - uint32_t zero = 0; - - if (len == sizeof(uint32_t) && memcmp(((uint8_t *)&zero), data, sizeof(uint32_t)) == 0) { - increment_nonce(c->crypto_connections[i].recv_nonce); - encrypt_precompute(c->crypto_connections[i].peersessionpublic_key, - c->crypto_connections[i].sessionsecret_key, - c->crypto_connections[i].shared_key); - c->crypto_connections[i].status = CONN_ESTABLISHED; - - /* connection is accepted so we disable the auto kill by setting it to about 1 month from now. */ - kill_connection_in(c->lossless_udp, c->crypto_connections[i].number, 3000000); - } else { - crypto_kill(c, i); // This should not happen kill the connection if it does - return; - } - } else if (id_packet(c->lossless_udp, c->crypto_connections[i].number) != -1) - /* This should not happen - kill the connection if it does */ - crypto_kill(c, i); - - return; - } - } -} - -/* run this to (re)initialize net_crypto - sets all the global connection variables to their default values. */ -Net_Crypto *new_net_crypto(Networking_Core *net) -{ - if (net == NULL) - return NULL; - - Net_Crypto *temp = calloc(1, sizeof(Net_Crypto)); - - if (temp == NULL) - return NULL; - - temp->lossless_udp = new_lossless_udp(net); - - if (temp->lossless_udp == NULL) - return NULL; - - memset(temp->incoming_connections, -1 , sizeof(int) * MAX_INCOMING); - return temp; -} - -void init_cryptopackets(void *dht) -{ - DHT *s_dht = dht; - networking_registerhandler(s_dht->c->lossless_udp->net, NET_PACKET_CRYPTO, &cryptopacket_handle, s_dht); -} - -static void kill_timedout(Net_Crypto *c) -{ - uint32_t i; - - for (i = 0; i < c->crypto_connections_length; ++i) { - if (c->crypto_connections[i].status != CONN_NO_CONNECTION - && is_connected(c->lossless_udp, c->crypto_connections[i].number) == 4) - c->crypto_connections[i].status = CONN_TIMED_OUT; - else if (is_connected(c->lossless_udp, c->crypto_connections[i].number) == 4) { - kill_connection(c->lossless_udp, c->crypto_connections[i].number); - c->crypto_connections[i].number = ~0; - } - } -} - -/* main loop */ -void do_net_crypto(Net_Crypto *c) -{ - do_lossless_udp(c->lossless_udp); - handle_incomings(c); - receive_crypto(c); - kill_timedout(c); -} - -void kill_net_crypto(Net_Crypto *c) -{ - uint32_t i; - - for (i = 0; i < c->crypto_connections_length; ++i) { - crypto_kill(c, i); - } - - kill_lossless_udp(c->lossless_udp); - memset(c, 0, sizeof(Net_Crypto)); - free(c); -} diff --git a/core/net_crypto.h b/core/net_crypto.h deleted file mode 100644 index 81670993..00000000 --- a/core/net_crypto.h +++ /dev/null @@ -1,200 +0,0 @@ -/* net_crypto.h - * - * Functions for the core network crypto. - * - * Copyright (C) 2013 Tox project All Rights Reserved. - * - * This file is part of Tox. - * - * Tox 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. - * - * Tox 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 Tox. If not, see . - * - */ - -#ifndef NET_CRYPTO_H -#define NET_CRYPTO_H - -#include "Lossless_UDP.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#define MAX_INCOMING 64 - -#define CRYPTO_PACKET_FRIEND_REQ 32 /* Friend request crypto packet ID */ -#define CRYPTO_PACKET_NAT_PING 254 /* NAT ping crypto packet ID */ - -typedef struct { - uint8_t public_key[crypto_box_PUBLICKEYBYTES]; /* the real public key of the peer. */ - uint8_t recv_nonce[crypto_box_NONCEBYTES]; /* nonce of received packets */ - uint8_t sent_nonce[crypto_box_NONCEBYTES]; /* nonce of sent packets. */ - uint8_t sessionpublic_key[crypto_box_PUBLICKEYBYTES]; /* our public key for this session. */ - uint8_t sessionsecret_key[crypto_box_SECRETKEYBYTES]; /* our private key for this session. */ - uint8_t peersessionpublic_key[crypto_box_PUBLICKEYBYTES]; /* The public key of the peer. */ - uint8_t shared_key[crypto_box_BEFORENMBYTES]; /* the precomputed shared key from encrypt_precompute */ - uint8_t status; /* 0 if no connection, 1 we have sent a handshake, 2 if connexion is not confirmed yet - (we have received a handshake but no empty data packet), 3 if the connection is established. - 4 if the connection is timed out. */ - uint16_t number; /* Lossless_UDP connection number corresponding to this connection. */ - -} Crypto_Connection; - -typedef int (*cryptopacket_handler_callback)(void *object, IP_Port ip_port, uint8_t *source_pubkey, uint8_t *data, - uint32_t len); - -typedef struct { - cryptopacket_handler_callback function; - void *object; -} Cryptopacket_Handles; - -typedef struct { - Lossless_UDP *lossless_udp; - - Crypto_Connection *crypto_connections; - - uint32_t crypto_connections_length; /* Length of connections array */ - - /* Our public and secret keys. */ - uint8_t self_public_key[crypto_box_PUBLICKEYBYTES]; - uint8_t self_secret_key[crypto_box_SECRETKEYBYTES]; - - /* keeps track of the connection numbers for friends request so we can check later if they were sent */ - int incoming_connections[MAX_INCOMING]; - - Cryptopacket_Handles cryptopackethandlers[256]; -} Net_Crypto; - -#include "DHT.h" - -#define ENCRYPTION_PADDING (crypto_box_ZEROBYTES - crypto_box_BOXZEROBYTES) - -/* returns zero if the buffer contains only zeros */ -uint8_t crypto_iszero(uint8_t *buffer, uint32_t blen); - -/* encrypts plain of length length to encrypted of length + 16 using the - public key(32 bytes) of the receiver and the secret key of the sender and a 24 byte nonce - return -1 if there was a problem. - return length of encrypted data if everything was fine. */ -int encrypt_data(uint8_t *public_key, uint8_t *secret_key, uint8_t *nonce, - uint8_t *plain, uint32_t length, uint8_t *encrypted); - - -/* decrypts encrypted of length length to plain of length length - 16 using the - public key(32 bytes) of the sender, the secret key of the receiver and a 24 byte nonce - return -1 if there was a problem(decryption failed) - return length of plain data if everything was fine. */ -int decrypt_data(uint8_t *public_key, uint8_t *secret_key, uint8_t *nonce, - uint8_t *encrypted, uint32_t length, uint8_t *plain); - -/* Fast encrypt/decrypt operations. Use if this is not a one-time communication. - encrypt_precompute does the shared-key generation once so it does not have - to be preformed on every encrypt/decrypt. */ -void encrypt_precompute(uint8_t *public_key, uint8_t *secret_key, uint8_t *enc_key); - -/* Fast encrypt. Depends on enc_key from encrypt_precompute. */ -int encrypt_data_fast(uint8_t *enc_key, uint8_t *nonce, - uint8_t *plain, uint32_t length, uint8_t *encrypted); - -/* Fast decrypt. Depends on enc_ley from encrypt_precompute. */ -int decrypt_data_fast(uint8_t *enc_key, uint8_t *nonce, - uint8_t *encrypted, uint32_t length, uint8_t *plain); - - -/* fill the given nonce with random bytes. */ -void random_nonce(uint8_t *nonce); - -/* return 0 if there is no received data in the buffer - return -1 if the packet was discarded. - return length of received data if successful */ -int read_cryptpacket(Net_Crypto *c, int crypt_connection_id, uint8_t *data); - -/* return 0 if data could not be put in packet queue - return 1 if data was put into the queue */ -int write_cryptpacket(Net_Crypto *c, int crypt_connection_id, uint8_t *data, uint32_t length); - -/* create a request to peer. - send_public_key and send_secret_key are the pub/secret keys of the sender - recv_public_key is public key of reciever - packet must be an array of MAX_DATA_SIZE big. - Data represents the data we send with the request with length being the length of the data. - request_id is the id of the request (32 = friend request, 254 = ping request) - returns -1 on failure - returns the length of the created packet on success */ -int create_request(uint8_t *send_public_key, uint8_t *send_secret_key, uint8_t *packet, uint8_t *recv_public_key, - uint8_t *data, uint32_t length, uint8_t request_id); - - -/* Function to call when request beginning with byte is received */ -void cryptopacket_registerhandler(Net_Crypto *c, uint8_t byte, cryptopacket_handler_callback cb, void *object); - -/* Start a secure connection with other peer who has public_key and ip_port - returns -1 if failure - returns crypt_connection_id of the initialized connection if everything went well. */ -int crypto_connect(Net_Crypto *c, uint8_t *public_key, IP_Port ip_port); - -/* kill a crypto connection - return 0 if killed successfully - return 1 if there was a problem. */ -int crypto_kill(Net_Crypto *c, int crypt_connection_id); - -/* handle an incoming connection - return -1 if no crypto inbound connection - return incoming connection id (Lossless_UDP one) if there is an incoming crypto connection - Put the public key of the peer in public_key, the secret_nonce from the handshake into secret_nonce - and the session public key for the connection in session_key - to accept it see: accept_crypto_inbound(...) - to refuse it just call kill_connection(...) on the connection id */ -int crypto_inbound(Net_Crypto *c, uint8_t *public_key, uint8_t *secret_nonce, uint8_t *session_key); - -/* accept an incoming connection using the parameters provided by crypto_inbound - return -1 if not successful - returns the crypt_connection_id if successful */ -int accept_crypto_inbound(Net_Crypto *c, int connection_id, uint8_t *public_key, uint8_t *secret_nonce, - uint8_t *session_key); - -/* return 0 if no connection, 1 we have sent a handshake, 2 if connexion is not confirmed yet - (we have received a handshake but no empty data packet), 3 if the connection is established. - 4 if the connection is timed out and waiting to be killed */ -int is_cryptoconnected(Net_Crypto *c, int crypt_connection_id); - - -/* Generate our public and private keys - Only call this function the first time the program starts. */ -void new_keys(Net_Crypto *c); - -/* save the public and private keys to the keys array - Length must be crypto_box_PUBLICKEYBYTES + crypto_box_SECRETKEYBYTES */ -void save_keys(Net_Crypto *c, uint8_t *keys); - -/* load the public and private keys from the keys array - Length must be crypto_box_PUBLICKEYBYTES + crypto_box_SECRETKEYBYTES */ -void load_keys(Net_Crypto *c, uint8_t *keys); - -/* create new instance of Net_Crypto - sets all the global connection variables to their default values. */ -Net_Crypto *new_net_crypto(Networking_Core *net); - -/* main loop */ -void do_net_crypto(Net_Crypto *c); - -void kill_net_crypto(Net_Crypto *c); - -/* Init the cryptopacket handling */ -void init_cryptopackets(void *dht); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/core/network.c b/core/network.c deleted file mode 100644 index 2bcf7d61..00000000 --- a/core/network.c +++ /dev/null @@ -1,218 +0,0 @@ -/* network.h - * - * Functions for the core networking. - * - * Copyright (C) 2013 Tox project All Rights Reserved. - * - * This file is part of Tox. - * - * Tox 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. - * - * Tox 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 Tox. If not, see . - * - */ - -#include "network.h" - -/* returns current UNIX time in microseconds (us). */ -uint64_t current_time(void) -{ - uint64_t time; -#ifdef WIN32 - /* This probably works fine */ - FILETIME ft; - GetSystemTimeAsFileTime(&ft); - time = ft.dwHighDateTime; - time <<= 32; - time |= ft.dwLowDateTime; - time -= 116444736000000000UL; - return time / 10; -#else - struct timeval a; - gettimeofday(&a, NULL); - time = 1000000UL * a.tv_sec + a.tv_usec; - return time; -#endif -} - -/* return a random number - NOTE: this function should probably not be used where cryptographic randomness is absolutely necessary */ -uint32_t random_int(void) -{ -#ifndef VANILLA_NACL - //NOTE: this function comes from libsodium - return randombytes_random(); -#else - return random(); -#endif -} - -/* Basic network functions: - Function to send packet(data) of length length to ip_port */ -int sendpacket(int sock, IP_Port ip_port, uint8_t *data, uint32_t length) -{ - ADDR addr = {AF_INET, ip_port.port, ip_port.ip}; - return sendto(sock, (char *) data, length, 0, (struct sockaddr *)&addr, sizeof(addr)); -} - -/* Function to receive data, ip and port of sender is put into ip_port - the packet data into data - the packet length into length. - dump all empty packets. */ -static int receivepacket(int sock, IP_Port *ip_port, uint8_t *data, uint32_t *length) -{ - ADDR addr; -#ifdef WIN32 - int addrlen = sizeof(addr); -#else - uint32_t addrlen = sizeof(addr); -#endif - (*(int32_t *)length) = recvfrom(sock, (char *) data, MAX_UDP_PACKET_SIZE, 0, (struct sockaddr *)&addr, &addrlen); - - if (*(int32_t *)length <= 0) - return -1; /* nothing received or empty packet */ - - ip_port->ip = addr.ip; - ip_port->port = addr.port; - return 0; -} - -void networking_registerhandler(Networking_Core *net, uint8_t byte, packet_handler_callback cb, void *object) -{ - net->packethandlers[byte].function = cb; - net->packethandlers[byte].object = object; -} - -void networking_poll(Networking_Core *net) -{ - IP_Port ip_port; - uint8_t data[MAX_UDP_PACKET_SIZE]; - uint32_t length; - - while (receivepacket(net->sock, &ip_port, data, &length) != -1) { - if (length < 1) continue; - - if (!(net->packethandlers[data[0]].function)) continue; - - net->packethandlers[data[0]].function(net->packethandlers[data[0]].object, ip_port, data, length); - } -} - -uint8_t at_startup_ran; -static int at_startup(void) -{ - if (at_startup_ran != 0) - return 0; - -#ifdef WIN32 - WSADATA wsaData; - - if (WSAStartup(MAKEWORD(2, 2), &wsaData) != NO_ERROR) - return -1; - -#else - srandom((uint32_t)current_time()); -#endif - srand((uint32_t)current_time()); - at_startup_ran = 1; - return 0; -} - -/* TODO: put this somewhere -static void at_shutdown(void) -{ -#ifdef WIN32 - WSACleanup(); -#endif -} -*/ - -/* initialize networking - bind to ip and port - ip must be in network order EX: 127.0.0.1 = (7F000001) - port is in host byte order (this means don't worry about it) - returns Networking_Core object if no problems - returns NULL if there are problems */ -Networking_Core *new_networking(IP ip, uint16_t port) -{ - if (at_startup() != 0) - return NULL; - - /* initialize our socket */ - Networking_Core *temp = calloc(1, sizeof(Networking_Core)); - - if (temp == NULL) - return NULL; - - temp->sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); - - /* Check for socket error */ -#ifdef WIN32 - - if (temp->sock == INVALID_SOCKET) { /* MSDN recommends this */ - free(temp); - return NULL; - } - -#else - - if (temp->sock < 0) { - free(temp); - return NULL; - } - -#endif - - /* Functions to increase the size of the send and receive UDP buffers - NOTE: uncomment if necessary */ - /* - int n = 1024 * 1024 * 2; - if(setsockopt(sock, SOL_SOCKET, SO_RCVBUF, (char*)&n, sizeof(n)) == -1) - { - return -1; - } - - if(setsockopt(sock, SOL_SOCKET, SO_SNDBUF, (char*)&n, sizeof(n)) == -1) - return -1; - */ - - /* Enable broadcast on socket */ - int broadcast = 1; - setsockopt(temp->sock, SOL_SOCKET, SO_BROADCAST, (char *)&broadcast, sizeof(broadcast)); - - /* Set socket nonblocking */ -#ifdef WIN32 - /* I think this works for windows */ - u_long mode = 1; - /* ioctl(sock, FIONBIO, &mode); */ - ioctlsocket(temp->sock, FIONBIO, &mode); -#else - fcntl(temp->sock, F_SETFL, O_NONBLOCK, 1); -#endif - - /* Bind our socket to port PORT and address 0.0.0.0 */ - ADDR addr = {AF_INET, htons(port), ip}; - bind(temp->sock, (struct sockaddr *)&addr, sizeof(addr)); - return temp; -} - -/* function to cleanup networking stuff */ -void kill_networking(Networking_Core *net) -{ -#ifdef WIN32 - closesocket(net->sock); -#else - close(net->sock); -#endif - free(net); - return; -} diff --git a/core/network.h b/core/network.h deleted file mode 100644 index 3547f79b..00000000 --- a/core/network.h +++ /dev/null @@ -1,159 +0,0 @@ -/* network.h - * - * Datatypes, functions and includes for the core networking. - * - * Copyright (C) 2013 Tox project All Rights Reserved. - * - * This file is part of Tox. - * - * Tox 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. - * - * Tox 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 Tox. If not, see . - * - */ - -#ifndef NETWORK_H -#define NETWORK_H - -#include -#include -#include -#include -#include - -#ifdef WIN32 /* Put win32 includes here */ -#ifndef WINVER -//Windows XP -#define WINVER 0x0501 -#endif -#include -#include -#include - -#undef VANILLA_NACL /* make sure on windows we use libsodium */ - -#else //Linux includes - -#include -#include -#include -#include -#include -#include -#include -#include - -#endif - -#ifndef VANILLA_NACL -/* we use libsodium by default */ -#include -#else -#include -#define crypto_box_MACBYTES (crypto_box_ZEROBYTES - crypto_box_BOXZEROBYTES) -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -#define MAX_UDP_PACKET_SIZE 65507 - -#define NET_PACKET_PING_REQUEST 0 /* Ping request packet ID */ -#define NET_PACKET_PING_RESPONSE 1 /* Ping response packet ID */ -#define NET_PACKET_GET_NODES 2 /* Get nodes request packet ID */ -#define NET_PACKET_SEND_NODES 3 /* Send nodes response packet ID */ -#define NET_PACKET_HANDSHAKE 16 /* Handshake packet ID */ -#define NET_PACKET_SYNC 17 /* SYNC packet ID */ -#define NET_PACKET_DATA 18 /* Data packet ID */ -#define NET_PACKET_CRYPTO 32 /* Encrypted data packet ID */ -#define NET_PACKET_LAN_DISCOVERY 33 /* LAN discovery packet ID */ - - -/* Current time, unix format */ -#define unix_time() ((uint64_t)time(NULL)) - - -typedef union { - uint8_t c[4]; - uint16_t s[2]; - uint32_t i; -} IP; - -typedef struct { - IP ip; - uint16_t port; - /* not used for anything right now */ - uint16_t padding; -} IP_Port; - -typedef struct { - int16_t family; - uint16_t port; - IP ip; - uint8_t zeroes[8]; -#ifdef ENABLE_IPV6 - uint8_t zeroes2[12]; -#endif -} ADDR; - -/* Function to receive data, ip and port of sender is put into ip_port - the packet data into data - the packet length into length. */ -typedef int (*packet_handler_callback)(void *object, IP_Port ip_port, uint8_t *data, uint32_t len); - -typedef struct { - packet_handler_callback function; - void *object; -} Packet_Handles; - -typedef struct { - Packet_Handles packethandlers[256]; - /* our UDP socket */ - int sock; -} Networking_Core; - -/* returns current time in milleseconds since the epoch. */ -uint64_t current_time(void); - -/* return a random number - NOTE: this function should probably not be used where cryptographic randomness is absolutely necessary */ -uint32_t random_int(void); - -/* Basic network functions: */ - -/* Function to send packet(data) of length length to ip_port */ -int sendpacket(int sock, IP_Port ip_port, uint8_t *data, uint32_t length); - -/* Function to call when packet beginning with byte is received */ -void networking_registerhandler(Networking_Core *net, uint8_t byte, packet_handler_callback cb, void *object); - -/* call this several times a second */ -void networking_poll(Networking_Core *net); - -/* initialize networking - bind to ip and port - ip must be in network order EX: 127.0.0.1 = (7F000001) - port is in host byte order (this means don't worry about it) - returns 0 if no problems - returns -1 if there were problems */ -Networking_Core *new_networking(IP ip, uint16_t port); - -/* function to cleanup networking stuff(doesn't do much right now) */ -void kill_networking(Networking_Core *net); - - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/core/packets.h b/core/packets.h deleted file mode 100644 index 4f410fb3..00000000 --- a/core/packets.h +++ /dev/null @@ -1,31 +0,0 @@ -/* - * packet.h -- Packet structure - * - * This file is donated to the Tox Project. - * Copyright 2013 plutooo - */ - -typedef struct { - uint8_t id[CLIENT_ID_SIZE]; - -} __attribute__((packed)) clientid_t; - -// Ping packet -typedef struct { - uint8_t packet_id; - clientid_t client_id; - uint8_t nonce[crypto_box_NONCEBYTES]; - uint64_t ping_id; - uint8_t padding[ENCRYPTION_PADDING]; - -} __attribute__((packed)) pingreq_t; - -// Pong packet -typedef struct { - uint8_t packet_id; - clientid_t client_id; - uint8_t nonce[crypto_box_NONCEBYTES]; - uint64_t ping_id; - uint8_t padding[ENCRYPTION_PADDING]; - -} __attribute__((packed)) pingres_t; diff --git a/core/ping.c b/core/ping.c deleted file mode 100644 index 55d4d261..00000000 --- a/core/ping.c +++ /dev/null @@ -1,229 +0,0 @@ -/* - * ping.c -- Buffered pinging using cyclic arrays. - * - * This file is donated to the Tox Project. - * Copyright 2013 plutooo - */ - -#include -#include - -#include "DHT.h" -#include "net_crypto.h" -#include "packets.h" -#include "network.h" -#include "util.h" - -#define PING_NUM_MAX 256 -#define PING_TIMEOUT 5 // 5s - -typedef struct { - IP_Port ipp; - uint64_t id; - uint64_t timestamp; -} pinged_t; - -typedef struct { - pinged_t pings[PING_NUM_MAX]; - size_t num_pings; - size_t pos_pings; -} PING; - -void *new_ping(void) -{ - return calloc(1, sizeof(PING)); -} - -void kill_ping(void *ping) -{ - free(ping); -} - -static bool is_timeout(uint64_t time) -{ - return (time + PING_TIMEOUT) < now(); -} - -static void remove_timeouts(void *ping) // O(n) -{ - PING *png = ping; - size_t i, id; - size_t new_pos = png->pos_pings; - size_t new_num = png->num_pings; - - // Loop through buffer, oldest first - for (i = 0; i < png->num_pings; i++) { - id = (png->pos_pings + i) % PING_NUM_MAX; - - if (is_timeout(png->pings[id].timestamp)) { - new_pos++; - new_num--; - } - // Break here because list is sorted. - else { - break; - } - } - - png->num_pings = new_num; - png->pos_pings = new_pos % PING_NUM_MAX; -} - -uint64_t add_ping(void *ping, IP_Port ipp) // O(n) -{ - PING *png = ping; - size_t p; - - remove_timeouts(ping); - - // Remove oldest ping if full buffer - if (png->num_pings == PING_NUM_MAX) { - png->num_pings--; - png->pos_pings = (png->pos_pings + 1) % PING_NUM_MAX; - } - - // Insert new ping at end of list - p = (png->pos_pings + png->num_pings) % PING_NUM_MAX; - - png->pings[p].ipp = ipp; - png->pings[p].timestamp = now(); - png->pings[p].id = random_64b(); - - png->num_pings++; - return png->pings[p].id; -} - -bool is_pinging(void *ping, IP_Port ipp, uint64_t ping_id) // O(n) TODO: replace this with something else. -{ - PING *png = ping; - - if (ipp.ip.i == 0 && ping_id == 0) - return false; - - size_t i, id; - - remove_timeouts(ping); - - for (i = 0; i < png->num_pings; i++) { - id = (png->pos_pings + i) % PING_NUM_MAX; - - // ping_id = 0 means match any id - if ((ipp_eq(png->pings[id].ipp, ipp) || ipp.ip.i == 0) && (png->pings[id].id == ping_id || ping_id == 0)) { - return true; - } - } - - return false; -} - -int send_ping_request(void *ping, Net_Crypto *c, IP_Port ipp, clientid_t *client_id) -{ - pingreq_t pk; - int rc; - uint64_t ping_id; - - if (is_pinging(ping, ipp, 0) || id_eq(client_id, (clientid_t *)c->self_public_key)) - return 1; - - // Generate random ping_id - ping_id = add_ping(ping, ipp); - - pk.packet_id = NET_PACKET_PING_REQUEST; - id_cpy(&pk.client_id, (clientid_t *)c->self_public_key); // Our pubkey - random_nonce((uint8_t *) &pk.nonce); // Generate random nonce - - // Encrypt ping_id using recipient privkey - rc = encrypt_data((uint8_t *) client_id, - c->self_secret_key, - (uint8_t *) &pk.nonce, - (uint8_t *) &ping_id, sizeof(ping_id), - (uint8_t *) &pk.ping_id); - - if (rc != sizeof(ping_id) + ENCRYPTION_PADDING) - return 1; - - return sendpacket(c->lossless_udp->net->sock, ipp, (uint8_t *) &pk, sizeof(pk)); -} - -int send_ping_response(Net_Crypto *c, IP_Port ipp, clientid_t *client_id, uint64_t ping_id) -{ - pingres_t pk; - int rc; - - if (id_eq(client_id, (clientid_t *)c->self_public_key)) - return 1; - - pk.packet_id = NET_PACKET_PING_RESPONSE; - id_cpy(&pk.client_id, (clientid_t *)c->self_public_key); // Our pubkey - random_nonce((uint8_t *) &pk.nonce); // Generate random nonce - - // Encrypt ping_id using recipient privkey - rc = encrypt_data((uint8_t *) client_id, - c->self_secret_key, - (uint8_t *) &pk.nonce, - (uint8_t *) &ping_id, sizeof(ping_id), - (uint8_t *) &pk.ping_id); - - if (rc != sizeof(ping_id) + ENCRYPTION_PADDING) - return 1; - - return sendpacket(c->lossless_udp->net->sock, ipp, (uint8_t *) &pk, sizeof(pk)); -} - -int handle_ping_request(void *object, IP_Port source, uint8_t *packet, uint32_t length) -{ - DHT *dht = object; - pingreq_t *p = (pingreq_t *) packet; - int rc; - uint64_t ping_id; - - if (length != sizeof(pingreq_t) || id_eq(&p->client_id, (clientid_t *)dht->c->self_public_key)) - return 1; - - // Decrypt ping_id - rc = decrypt_data((uint8_t *) &p->client_id, - dht->c->self_secret_key, - (uint8_t *) &p->nonce, - (uint8_t *) &p->ping_id, - sizeof(ping_id) + ENCRYPTION_PADDING, - (uint8_t *) &ping_id); - - if (rc != sizeof(ping_id)) - return 1; - - // Send response - send_ping_response(dht->c, source, &p->client_id, ping_id); - add_toping(dht, (uint8_t *) &p->client_id, source); - - return 0; -} - -int handle_ping_response(void *object, IP_Port source, uint8_t *packet, uint32_t length) -{ - DHT *dht = object; - pingres_t *p = (pingres_t *) packet; - int rc; - uint64_t ping_id; - - if (length != sizeof(pingres_t) || id_eq(&p->client_id, (clientid_t *)dht->c->self_public_key)) - return 1; - - // Decrypt ping_id - rc = decrypt_data((uint8_t *) &p->client_id, - dht->c->self_secret_key, - (uint8_t *) &p->nonce, - (uint8_t *) &p->ping_id, - sizeof(ping_id) + ENCRYPTION_PADDING, - (uint8_t *) &ping_id); - - if (rc != sizeof(ping_id)) - return 1; - - // Make sure ping_id is correct - if (!is_pinging(dht->ping, source, ping_id)) - return 1; - - // Associate source ip with client_id - addto_lists(dht, source, (uint8_t *) &p->client_id); - return 0; -} diff --git a/core/ping.h b/core/ping.h deleted file mode 100644 index c04ec80e..00000000 --- a/core/ping.h +++ /dev/null @@ -1,17 +0,0 @@ -/* - * ping.h -- Buffered pinging using cyclic arrays. - * - * This file is donated to the Tox Project. - * Copyright 2013 plutooo - */ - -#include - -void *new_ping(void); -void kill_ping(void *ping); -uint64_t add_ping(void *ping, IP_Port ipp); -bool is_pinging(void *ping, IP_Port ipp, uint64_t ping_id); -int send_ping_request(void *ping, Net_Crypto *c, IP_Port ipp, clientid_t *client_id); -int send_ping_response(Net_Crypto *c, IP_Port ipp, clientid_t *client_id, uint64_t ping_id); -int handle_ping_request(void *object, IP_Port source, uint8_t *packet, uint32_t length); -int handle_ping_response(void *object, IP_Port source, uint8_t *packet, uint32_t length); diff --git a/core/tox.c b/core/tox.c deleted file mode 100644 index a97e52bc..00000000 --- a/core/tox.c +++ /dev/null @@ -1,374 +0,0 @@ -/* tox.c - * - * The Tox public API. - * - * Copyright (C) 2013 Tox project All Rights Reserved. - * - * This file is part of Tox. - * - * Tox 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. - * - * Tox 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 Tox. If not, see . - * - */ - -#include "Messenger.h" -/* - * returns a FRIEND_ADDRESS_SIZE byte address to give to others. - * format: [client_id (32 bytes)][nospam number (4 bytes)][checksum (2 bytes)] - * - */ -void tox_getaddress(void *tox, uint8_t *address) -{ - Messenger *m = tox; - getaddress(m, address); -} - -/* - * add a friend - * set the data that will be sent along with friend request - * address is the address of the friend (returned by getaddress of the friend you wish to add) it must be FRIEND_ADDRESS_SIZE bytes. TODO: add checksum. - * data is the data and length is the length - * returns the friend number if success - * return FA_TOOLONG if message length is too long - * return FAERR_NOMESSAGE if no message (message length must be >= 1 byte) - * return FAERR_OWNKEY if user's own key - * return FAERR_ALREADYSENT if friend request already sent or already a friend - * return FAERR_UNKNOWN for unknown error - * return FAERR_BADCHECKSUM if bad checksum in address - * return FAERR_SETNEWNOSPAM if the friend was already there but the nospam was different - * (the nospam for that friend was set to the new one) - * return FAERR_NOMEM if increasing the friend list size fails - */ -int tox_addfriend(void *tox, uint8_t *address, uint8_t *data, uint16_t length) -{ - Messenger *m = tox; - return m_addfriend(m, address, data, length); -} - -/* add a friend without sending a friendrequest. - returns the friend number if success - return -1 if failure. */ -int tox_addfriend_norequest(void *tox, uint8_t *client_id) -{ - Messenger *m = tox; - return m_addfriend_norequest(m, client_id); -} - -/* return the friend id associated to that client id. - return -1 if no such friend */ -int tox_getfriend_id(void *tox, uint8_t *client_id) -{ - Messenger *m = tox; - return getfriend_id(m, client_id); -} - -/* copies the public key associated to that friend id into client_id buffer. - make sure that client_id is of size CLIENT_ID_SIZE. - return 0 if success - return -1 if failure */ -int tox_getclient_id(void *tox, int friend_id, uint8_t *client_id) -{ - Messenger *m = tox; - return getclient_id(m, friend_id, client_id); -} - -/* remove a friend */ -int tox_delfriend(void *tox, int friendnumber) -{ - Messenger *m = tox; - return m_delfriend(m, friendnumber); -} - -/* return 4 if friend is online - return 3 if friend is confirmed - return 2 if the friend request was sent - return 1 if the friend was added - return 0 if there is no friend with that number */ -int tox_friendstatus(void *tox, int friendnumber) -{ - Messenger *m = tox; - return m_friendstatus(m, friendnumber); -} - -/* send a text chat message to an online friend - returns the message id if packet was successfully put into the send queue - return 0 if it was not - you will want to retain the return value, it will be passed to your read receipt callback - if one is received. - m_sendmessage_withid will send a message with the id of your choosing, - however we can generate an id for you by calling plain m_sendmessage. */ -uint32_t tox_sendmessage(void *tox, int friendnumber, uint8_t *message, uint32_t length) -{ - Messenger *m = tox; - return m_sendmessage(m, friendnumber, message, length); -} - -uint32_t tox_sendmessage_withid(void *tox, int friendnumber, uint32_t theid, uint8_t *message, uint32_t length) -{ - Messenger *m = tox; - return m_sendmessage_withid(m, friendnumber, theid, message, length); -} - -/* send an action to an online friend - returns 1 if packet was successfully put into the send queue - return 0 if it was not */ -int tox_sendaction(void *tox, int friendnumber, uint8_t *action, uint32_t length) -{ - Messenger *m = tox; - return m_sendaction(m, friendnumber, action, length); -} - -/* Set our nickname - name must be a string of maximum MAX_NAME_LENGTH length. - length must be at least 1 byte - length is the length of name with the NULL terminator - return 0 if success - return -1 if failure */ -int tox_setname(void *tox, uint8_t *name, uint16_t length) -{ - Messenger *m = tox; - return setname(m, name, length); -} - -/* - Get your nickname. - m The messanger context to use. - name Pointer to a string for the name. - nlen The length of the string buffer. - returns Return the length of the name, 0 on error. -*/ -uint16_t tox_getselfname(void *tox, uint8_t *name, uint16_t nlen) -{ - Messenger *m = tox; - return getself_name(m, name, nlen); -} - -/* get name of friendnumber - put it in name - name needs to be a valid memory location with a size of at least MAX_NAME_LENGTH (128) bytes. - return 0 if success - return -1 if failure */ -int tox_getname(void *tox, int friendnumber, uint8_t *name) -{ - Messenger *m = tox; - return getname(m, friendnumber, name); -} - -/* set our user status - you are responsible for freeing status after - returns 0 on success, -1 on failure */ -int tox_set_statusmessage(void *tox, uint8_t *status, uint16_t length) -{ - Messenger *m = tox; - return m_set_statusmessage(m, status, length); -} - -int tox_set_userstatus(void *tox, USERSTATUS status) -{ - Messenger *m = tox; - return m_set_userstatus(m, status); -} - -/* return the length of friendnumber's status message, - including null - pass it into malloc */ -int tox_get_statusmessage_size(void *tox, int friendnumber) -{ - Messenger *m = tox; - return m_get_statusmessage_size(m, friendnumber); -} - -/* copy friendnumber's status message into buf, truncating if size is over maxlen - get the size you need to allocate from m_get_statusmessage_size - The self variant will copy our own status message. */ -int tox_copy_statusmessage(void *tox, int friendnumber, uint8_t *buf, uint32_t maxlen) -{ - Messenger *m = tox; - return m_copy_statusmessage(m, friendnumber, buf, maxlen); -} - -int tox_copy_self_statusmessage(void *tox, uint8_t *buf, uint32_t maxlen) -{ - Messenger *m = tox; - return m_copy_self_statusmessage(m, buf, maxlen); -} - -/* Return one of USERSTATUS values. - * Values unknown to your application should be represented as USERSTATUS_NONE. - * As above, the self variant will return our own USERSTATUS. - * If friendnumber is invalid, this shall return USERSTATUS_INVALID. */ -USERSTATUS tox_get_userstatus(void *tox, int friendnumber) -{ - Messenger *m = tox; - return m_get_userstatus(m, friendnumber); -} - -USERSTATUS tox_get_selfuserstatus(void *tox) -{ - Messenger *m = tox; - return m_get_self_userstatus(m); -} - - -/* Sets whether we send read receipts for friendnumber. - * This function is not lazy, and it will fail if yesno is not (0 or 1).*/ -void tox_set_sends_receipts(void *tox, int friendnumber, int yesno) -{ - Messenger *m = tox; - m_set_sends_receipts(m, friendnumber, yesno); -} - - -/* set the function that will be executed when a friend request is received. - function format is function(uint8_t * public_key, uint8_t * data, uint16_t length) */ -void tox_callback_friendrequest(void *tox, void (*function)(uint8_t *, uint8_t *, uint16_t, void *), void *userdata) -{ - Messenger *m = tox; - m_callback_friendrequest(m, function, userdata); -} - - -/* set the function that will be executed when a message from a friend is received. - function format is: function(int friendnumber, uint8_t * message, uint32_t length) */ -void tox_callback_friendmessage(void *tox, void (*function)(Messenger *tox, int, uint8_t *, uint16_t, void *), - void *userdata) -{ - Messenger *m = tox; - m_callback_friendmessage(m, function, userdata); -} - -/* set the function that will be executed when an action from a friend is received. - function format is: function(int friendnumber, uint8_t * action, uint32_t length) */ -void tox_callback_action(void *tox, void (*function)(Messenger *tox, int, uint8_t *, uint16_t, void *), void *userdata) -{ - Messenger *m = tox; - m_callback_action(m, function, userdata); -} - -/* set the callback for name changes - function(int friendnumber, uint8_t *newname, uint16_t length) - you are not responsible for freeing newname */ -void tox_callback_namechange(void *tox, void (*function)(Messenger *tox, int, uint8_t *, uint16_t, void *), - void *userdata) -{ - Messenger *m = tox; - m_callback_namechange(m, function, userdata); -} - -/* set the callback for status message changes - function(int friendnumber, uint8_t *newstatus, uint16_t length) - you are not responsible for freeing newstatus */ -void tox_callback_statusmessage(void *tox, void (*function)(Messenger *tox, int, uint8_t *, uint16_t, void *), - void *userdata) -{ - Messenger *m = tox; - m_callback_statusmessage(m, function, userdata); -} - -/* set the callback for status type changes - function(int friendnumber, USERSTATUS kind) */ -void tox_callback_userstatus(void *tox, void (*function)(Messenger *tox, int, USERSTATUS, void *), void *userdata) -{ - Messenger *m = tox; - m_callback_userstatus(m, function, userdata); -} - -/* set the callback for read receipts - function(int friendnumber, uint32_t receipt) - if you are keeping a record of returns from m_sendmessage, - receipt might be one of those values, and that means the message - has been received on the other side. since core doesn't - track ids for you, receipt may not correspond to any message - in that case, you should discard it. */ -void tox_callback_read_receipt(void *tox, void (*function)(Messenger *tox, int, uint32_t, void *), void *userdata) -{ - Messenger *m = tox; - m_callback_read_receipt(m, function, userdata); -} - -/* set the callback for connection status changes - function(int friendnumber, uint8_t status) - status: - 0 -- friend went offline after being previously online - 1 -- friend went online - note that this callback is not called when adding friends, thus the "after - being previously online" part. it's assumed that when adding friends, - their connection status is offline. */ -void tox_callback_connectionstatus(void *tox, void (*function)(Messenger *tox, int, uint8_t, void *), void *userdata) -{ - Messenger *m = tox; - m_callback_connectionstatus(m, function, userdata); -} - -/* Use this function to bootstrap the client - Sends a get nodes request to the given node with ip port and public_key */ -void tox_bootstrap(void *tox, IP_Port ip_port, uint8_t *public_key) -{ - Messenger *m = tox; - DHT_bootstrap(m->dht, ip_port, public_key); -} - -/* returns 0 if we are not connected to the DHT - returns 1 if we are */ -int tox_isconnected(void *tox) -{ - Messenger *m = tox; - return DHT_isconnected(m->dht); -} - -/* run this at startup - * returns allocated instance of tox on success - * returns 0 if there are problems */ -void *tox_new(void) -{ - return initMessenger(); -} - -/* run this before closing shop - * free all datastructures */ -void tox_kill(void *tox) -{ - Messenger *m = tox; - cleanupMessenger(m); -} - -/* the main loop that needs to be run at least 20 times per second */ -void tox_do(void *tox) -{ - Messenger *m = tox; - doMessenger(m); -} - -/* SAVING AND LOADING FUNCTIONS: */ - -/* returns the size of the messenger data (for saving) */ -uint32_t tox_size(void *tox) -{ - Messenger *m = tox; - return Messenger_size(m); -} - -/* save the messenger in data (must be allocated memory of size Messenger_size()) */ -void tox_save(void *tox, uint8_t *data) -{ - Messenger *m = tox; - Messenger_save(m, data); -} - -/* load the messenger from data of size length */ -int tox_load(void *tox, uint8_t *data, uint32_t length) -{ - Messenger *m = tox; - return Messenger_load(m, data, length); -} - diff --git a/core/tox.h b/core/tox.h deleted file mode 100644 index bdfac1d6..00000000 --- a/core/tox.h +++ /dev/null @@ -1,289 +0,0 @@ -/* tox.h - * - * The Tox public API. - * - * Copyright (C) 2013 Tox project All Rights Reserved. - * - * This file is part of Tox. - * - * Tox 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. - * - * Tox 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 Tox. If not, see . - * - */ - -#ifndef TOX_H -#define TOX_H - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -#define TOX_MAX_NAME_LENGTH 128 -#define TOX_MAX_STATUSMESSAGE_LENGTH 128 -#define TOX_CLIENT_ID_SIZE 32 - -#define TOX_FRIEND_ADDRESS_SIZE (TOX_CLIENT_ID_SIZE + sizeof(uint32_t) + sizeof(uint16_t)) - - -typedef union { - uint8_t c[4]; - uint16_t s[2]; - uint32_t i; -} tox_IP; - -typedef struct { - tox_IP ip; - uint16_t port; - /* not used for anything right now */ - uint16_t padding; -} tox_IP_Port; - -/* status definitions */ -enum { - TOX_NOFRIEND, - TOX_FRIEND_ADDED, - TOX_FRIEND_REQUESTED, - TOX_FRIEND_CONFIRMED, - TOX_FRIEND_ONLINE, -}; - -/* errors for m_addfriend - * FAERR - Friend Add Error */ -enum { - TOX_FAERR_TOOLONG = -1, - TOX_FAERR_NOMESSAGE = -2, - TOX_FAERR_OWNKEY = -3, - TOX_FAERR_ALREADYSENT = -4, - TOX_FAERR_UNKNOWN = -5, - TOX_FAERR_BADCHECKSUM = -6, - TOX_FAERR_SETNEWNOSPAM = -7, - TOX_FAERR_NOMEM = -8 -}; -/* USERSTATUS - * Represents userstatuses someone can have. */ - -typedef enum { - TOX_USERSTATUS_NONE, - TOX_USERSTATUS_AWAY, - TOX_USERSTATUS_BUSY, - TOX_USERSTATUS_INVALID -} -TOX_USERSTATUS; - -typedef void Tox; - -/* - * returns a FRIEND_ADDRESS_SIZE byte address to give to others. - * format: [client_id (32 bytes)][nospam number (4 bytes)][checksum (2 bytes)] - * - */ -void tox_getaddress(Tox *tox, uint8_t *address); - -/* - * add a friend - * set the data that will be sent along with friend request - * address is the address of the friend (returned by getaddress of the friend you wish to add) it must be FRIEND_ADDRESS_SIZE bytes. TODO: add checksum. - * data is the data and length is the length - * returns the friend number if success - * return TOX_FA_TOOLONG if message length is too long - * return TOX_FAERR_NOMESSAGE if no message (message length must be >= 1 byte) - * return TOX_FAERR_OWNKEY if user's own key - * return TOX_FAERR_ALREADYSENT if friend request already sent or already a friend - * return TOX_FAERR_UNKNOWN for unknown error - * return TOX_FAERR_BADCHECKSUM if bad checksum in address - * return TOX_FAERR_SETNEWNOSPAM if the friend was already there but the nospam was different - * (the nospam for that friend was set to the new one) - * return TOX_FAERR_NOMEM if increasing the friend list size fails - */ -int tox_addfriend(Tox *tox, uint8_t *address, uint8_t *data, uint16_t length); - - -/* add a friend without sending a friendrequest. - returns the friend number if success - return -1 if failure. */ -int tox_addfriend_norequest(Tox *tox, uint8_t *client_id); - -/* return the friend id associated to that client id. - return -1 if no such friend */ -int tox_getfriend_id(Tox *tox, uint8_t *client_id); - -/* copies the public key associated to that friend id into client_id buffer. - make sure that client_id is of size CLIENT_ID_SIZE. - return 0 if success - return -1 if failure */ -int tox_getclient_id(Tox *tox, int friend_id, uint8_t *client_id); - -/* remove a friend */ -int tox_delfriend(Tox *tox, int friendnumber); - -/* return TOX_FRIEND_ONLINE if friend is online - return TOX_FRIEND_CONFIRMED if friend is confirmed - return TOX_FRIEND_REQUESTED if the friend request was sent - return TOX_FRIEND_ADDED if the friend was added - return TOX_NOFRIEND if there is no friend with that number */ -int tox_friendstatus(Tox *tox, int friendnumber); - -/* send a text chat message to an online friend - returns the message id if packet was successfully put into the send queue - return 0 if it was not - you will want to retain the return value, it will be passed to your read receipt callback - if one is received. - m_sendmessage_withid will send a message with the id of your choosing, - however we can generate an id for you by calling plain m_sendmessage. */ -uint32_t tox_sendmessage(Tox *tox, int friendnumber, uint8_t *message, uint32_t length); -uint32_t tox_sendmessage_withid(Tox *tox, int friendnumber, uint32_t theid, uint8_t *message, uint32_t length); - -/* send an action to an online friend - returns 1 if packet was successfully put into the send queue - return 0 if it was not */ -int tox_sendaction(Tox *tox, int friendnumber, uint8_t *action, uint32_t length); - -/* Set our nickname - name must be a string of maximum MAX_NAME_LENGTH length. - length must be at least 1 byte - length is the length of name with the NULL terminator - return 0 if success - return -1 if failure */ -int tox_setname(Tox *tox, uint8_t *name, uint16_t length); - -/* - Get your nickname. - m The messanger context to use. - name Pointer to a string for the name. - nlen The length of the string buffer. - returns Return the length of the name, 0 on error. -*/ -uint16_t tox_getselfname(Tox *tox, uint8_t *name, uint16_t nlen); - -/* get name of friendnumber - put it in name - name needs to be a valid memory location with a size of at least MAX_NAME_LENGTH (128) bytes. - return 0 if success - return -1 if failure */ -int tox_getname(Tox *tox, int friendnumber, uint8_t *name); - -/* set our user status - you are responsible for freeing status after - returns 0 on success, -1 on failure */ -int tox_set_statusmessage(Tox *tox, uint8_t *status, uint16_t length); -int tox_set_userstatus(Tox *tox, TOX_USERSTATUS status); - -/* return the length of friendnumber's status message, - including null - pass it into malloc */ -int tox_get_statusmessage_size(Tox *tox, int friendnumber); - -/* copy friendnumber's status message into buf, truncating if size is over maxlen - get the size you need to allocate from m_get_statusmessage_size - The self variant will copy our own status message. */ -int tox_copy_statusmessage(Tox *tox, int friendnumber, uint8_t *buf, uint32_t maxlen); -int tox_copy_self_statusmessage(Tox *tox, uint8_t *buf, uint32_t maxlen); - -/* Return one of USERSTATUS values. - * Values unknown to your application should be represented as USERSTATUS_NONE. - * As above, the self variant will return our own USERSTATUS. - * If friendnumber is invalid, this shall return USERSTATUS_INVALID. */ -TOX_USERSTATUS tox_get_userstatus(Tox *tox, int friendnumber); -TOX_USERSTATUS tox_get_selfuserstatus(Tox *tox); - -/* Sets whether we send read receipts for friendnumber. - * This function is not lazy, and it will fail if yesno is not (0 or 1).*/ -void tox_set_sends_receipts(Tox *tox, int friendnumber, int yesno); - -/* set the function that will be executed when a friend request is received. - function format is function(uint8_t * public_key, uint8_t * data, uint16_t length) */ -void tox_callback_friendrequest(Tox *tox, void (*function)(uint8_t *, uint8_t *, uint16_t, void *), void *userdata); - -/* set the function that will be executed when a message from a friend is received. - function format is: function(int friendnumber, uint8_t * message, uint32_t length) */ -void tox_callback_friendmessage(Tox *tox, void (*function)(Tox *tox, int, uint8_t *, uint16_t, void *), - void *userdata); - -/* set the function that will be executed when an action from a friend is received. - function format is: function(int friendnumber, uint8_t * action, uint32_t length) */ -void tox_callback_action(Tox *tox, void (*function)(Tox *tox, int, uint8_t *, uint16_t, void *), void *userdata); - -/* set the callback for name changes - function(int friendnumber, uint8_t *newname, uint16_t length) - you are not responsible for freeing newname */ -void tox_callback_namechange(Tox *tox, void (*function)(Tox *tox, int, uint8_t *, uint16_t, void *), - void *userdata); - -/* set the callback for status message changes - function(int friendnumber, uint8_t *newstatus, uint16_t length) - you are not responsible for freeing newstatus */ -void tox_callback_statusmessage(Tox *tox, void (*function)(Tox *tox, int, uint8_t *, uint16_t, void *), - void *userdata); - -/* set the callback for status type changes - function(int friendnumber, USERSTATUS kind) */ -void tox_callback_userstatus(Tox *tox, void (*function)(Tox *tox, int, TOX_USERSTATUS, void *), void *userdata); - -/* set the callback for read receipts - function(int friendnumber, uint32_t receipt) - if you are keeping a record of returns from m_sendmessage, - receipt might be one of those values, and that means the message - has been received on the other side. since core doesn't - track ids for you, receipt may not correspond to any message - in that case, you should discard it. */ -void tox_callback_read_receipt(Tox *tox, void (*function)(Tox *tox, int, uint32_t, void *), void *userdata); - -/* set the callback for connection status changes - function(int friendnumber, uint8_t status) - status: - 0 -- friend went offline after being previously online - 1 -- friend went online - note that this callback is not called when adding friends, thus the "after - being previously online" part. it's assumed that when adding friends, - their connection status is offline. */ -void tox_callback_connectionstatus(Tox *tox, void (*function)(Tox *tox, int, uint8_t, void *), void *userdata); - -/* Use this function to bootstrap the client - Sends a get nodes request to the given node with ip port and public_key */ -void tox_bootstrap(Tox *tox, tox_IP_Port ip_port, uint8_t *public_key); - -/* returns 0 if we are not connected to the DHT - returns 1 if we are */ -int tox_isconnected(Tox *tox); - -/* run this at startup - * returns allocated instance of tox on success - * returns 0 if there are problems */ -Tox *tox_new(void); - -/* run this before closing shop - * free all datastructures */ -void tox_kill(Tox *tox); - -/* the main loop that needs to be run at least 20 times per second */ -void tox_do(Tox *tox); - -/* SAVING AND LOADING FUNCTIONS: */ - -/* returns the size of the messenger data (for saving) */ -uint32_t tox_size(Tox *tox); - -/* save the messenger in data (must be allocated memory of size Messenger_size()) */ -void tox_save(Tox *tox, uint8_t *data); - -/* load the messenger from data of size length */ -int tox_load(Tox *tox, uint8_t *data, uint32_t length); - - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/core/util.c b/core/util.c deleted file mode 100644 index 6f346db1..00000000 --- a/core/util.c +++ /dev/null @@ -1,45 +0,0 @@ -/* - * util.c -- Utilities. - * - * This file is donated to the Tox Project. - * Copyright 2013 plutooo - */ - -#include -#include -#include - -#include "DHT.h" -#include "packets.h" - -uint64_t now() -{ - return time(NULL); -} - -uint64_t random_64b() -{ - uint64_t r; - - // This is probably not random enough? - r = random_int(); - r <<= 32; - r |= random_int(); - - return r; -} - -bool ipp_eq(IP_Port a, IP_Port b) -{ - return (a.ip.i == b.ip.i) && (a.port == b.port); -} - -bool id_eq(clientid_t *dest, clientid_t *src) -{ - return memcmp(dest, src, sizeof(clientid_t)) == 0; -} - -void id_cpy(clientid_t *dest, clientid_t *src) -{ - memcpy(dest, src, sizeof(clientid_t)); -} diff --git a/core/util.h b/core/util.h deleted file mode 100644 index 5209c2ca..00000000 --- a/core/util.h +++ /dev/null @@ -1,12 +0,0 @@ -/* - * util.h -- Utilities. - * - * This file is donated to the Tox Project. - * Copyright 2013 plutooo - */ - -uint64_t now(); -uint64_t random_64b(); -bool ipp_eq(IP_Port a, IP_Port b); -bool id_eq(clientid_t *dest, clientid_t *src); -void id_cpy(clientid_t *dest, clientid_t *src); -- cgit v1.2.3