summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--toxcore/DHT.c112
-rw-r--r--toxcore/DHT.h37
-rw-r--r--toxcore/group_chats.c25
-rw-r--r--toxcore/ping.c210
-rw-r--r--toxcore/ping.h33
5 files changed, 212 insertions, 205 deletions
diff --git a/toxcore/DHT.c b/toxcore/DHT.c
index bdfe120f..ad4c8a1d 100644
--- a/toxcore/DHT.c
+++ b/toxcore/DHT.c
@@ -56,9 +56,6 @@
56/* Interval in seconds between punching attempts*/ 56/* Interval in seconds between punching attempts*/
57#define PUNCH_INTERVAL 10 57#define PUNCH_INTERVAL 10
58 58
59/* Ping newly announced nodes to ping per TIME_TOPING seconds*/
60#define TIME_TOPING 5
61
62#define NAT_PING_REQUEST 0 59#define NAT_PING_REQUEST 0
63#define NAT_PING_RESPONSE 1 60#define NAT_PING_RESPONSE 1
64 61
@@ -84,7 +81,7 @@ Client_data *DHT_get_close_list(DHT *dht)
84 * return 1 if client_id1 is closer. 81 * return 1 if client_id1 is closer.
85 * return 2 if client_id2 is closer. 82 * return 2 if client_id2 is closer.
86 */ 83 */
87static int id_closest(uint8_t *id, uint8_t *id1, uint8_t *id2) 84int id_closest(uint8_t *id, uint8_t *id1, uint8_t *id2)
88{ 85{
89 size_t i; 86 size_t i;
90 uint8_t distance1, distance2; 87 uint8_t distance1, distance2;
@@ -522,7 +519,6 @@ static void returnedip_ports(DHT *dht, IP_Port ip_port, uint8_t *client_id, uint
522 } 519 }
523} 520}
524 521
525/* Same as last function but for get_node requests. */
526static int is_gettingnodes(DHT *dht, IP_Port ip_port, uint64_t ping_id) 522static int is_gettingnodes(DHT *dht, IP_Port ip_port, uint64_t ping_id)
527{ 523{
528 uint32_t i; 524 uint32_t i;
@@ -533,7 +529,7 @@ static int is_gettingnodes(DHT *dht, IP_Port ip_port, uint64_t ping_id)
533 if (!is_timeout(temp_time, dht->send_nodes[i].timestamp, PING_TIMEOUT)) { 529 if (!is_timeout(temp_time, dht->send_nodes[i].timestamp, PING_TIMEOUT)) {
534 pinging = 0; 530 pinging = 0;
535 531
536 if (ping_id != 0 && dht->send_nodes[i].ping_id == ping_id) 532 if (ping_id != 0 && dht->send_nodes[i].id == ping_id)
537 ++pinging; 533 ++pinging;
538 534
539 if (ip_isset(&ip_port.ip) && ipport_equal(&dht->send_nodes[i].ip_port, &ip_port)) 535 if (ip_isset(&ip_port.ip) && ipport_equal(&dht->send_nodes[i].ip_port, &ip_port))
@@ -559,7 +555,7 @@ static uint64_t add_gettingnodes(DHT *dht, IP_Port ip_port)
559 if (is_timeout(temp_time, dht->send_nodes[j].timestamp, PING_TIMEOUT - i)) { 555 if (is_timeout(temp_time, dht->send_nodes[j].timestamp, PING_TIMEOUT - i)) {
560 dht->send_nodes[j].timestamp = temp_time; 556 dht->send_nodes[j].timestamp = temp_time;
561 dht->send_nodes[j].ip_port = ip_port; 557 dht->send_nodes[j].ip_port = ip_port;
562 dht->send_nodes[j].ping_id = ping_id; 558 dht->send_nodes[j].id = ping_id;
563 return ping_id; 559 return ping_id;
564 } 560 }
565 } 561 }
@@ -830,7 +826,7 @@ static int handle_sendnodes(void *object, IP_Port source, uint8_t *packet, uint3
830 addto_lists(dht, source, packet + 1); 826 addto_lists(dht, source, packet + 1);
831 827
832 for (i = 0; i < num_nodes; ++i) { 828 for (i = 0; i < num_nodes; ++i) {
833 send_ping_request(dht->ping, dht->c, nodes_list[i].ip_port, nodes_list[i].client_id); 829 send_ping_request(dht->ping, nodes_list[i].ip_port, nodes_list[i].client_id);
834 returnedip_ports(dht, nodes_list[i].ip_port, nodes_list[i].client_id, packet + 1); 830 returnedip_ports(dht, nodes_list[i].ip_port, nodes_list[i].client_id, packet + 1);
835 } 831 }
836 832
@@ -877,7 +873,7 @@ static int handle_sendnodes_ipv6(void *object, IP_Port source, uint8_t *packet,
877 addto_lists(dht, source, packet + 1); 873 addto_lists(dht, source, packet + 1);
878 874
879 for (i = 0; i < num_nodes; ++i) { 875 for (i = 0; i < num_nodes; ++i) {
880 send_ping_request(dht->ping, dht->c, nodes_list[i].ip_port, nodes_list[i].client_id); 876 send_ping_request(dht->ping, nodes_list[i].ip_port, nodes_list[i].client_id);
881 returnedip_ports(dht, nodes_list[i].ip_port, nodes_list[i].client_id, packet + 1); 877 returnedip_ports(dht, nodes_list[i].ip_port, nodes_list[i].client_id, packet + 1);
882 } 878 }
883 879
@@ -1006,7 +1002,7 @@ static void do_DHT_friends(DHT *dht)
1006 /* If node is not dead. */ 1002 /* If node is not dead. */
1007 if (!is_timeout(temp_time, dht->friends_list[i].client_list[j].timestamp, Kill_NODE_TIMEOUT)) { 1003 if (!is_timeout(temp_time, dht->friends_list[i].client_list[j].timestamp, Kill_NODE_TIMEOUT)) {
1008 if ((dht->friends_list[i].client_list[j].last_pinged + PING_INTERVAL) <= temp_time) { 1004 if ((dht->friends_list[i].client_list[j].last_pinged + PING_INTERVAL) <= temp_time) {
1009 send_ping_request(dht->ping, dht->c, dht->friends_list[i].client_list[j].ip_port, 1005 send_ping_request(dht->ping, dht->friends_list[i].client_list[j].ip_port,
1010 dht->friends_list[i].client_list[j].client_id ); 1006 dht->friends_list[i].client_list[j].client_id );
1011 dht->friends_list[i].client_list[j].last_pinged = temp_time; 1007 dht->friends_list[i].client_list[j].last_pinged = temp_time;
1012 } 1008 }
@@ -1044,7 +1040,7 @@ static void do_Close(DHT *dht)
1044 /* If node is not dead. */ 1040 /* If node is not dead. */
1045 if (!is_timeout(temp_time, dht->close_clientlist[i].timestamp, Kill_NODE_TIMEOUT)) { 1041 if (!is_timeout(temp_time, dht->close_clientlist[i].timestamp, Kill_NODE_TIMEOUT)) {
1046 if ((dht->close_clientlist[i].last_pinged + PING_INTERVAL) <= temp_time) { 1042 if ((dht->close_clientlist[i].last_pinged + PING_INTERVAL) <= temp_time) {
1047 send_ping_request(dht->ping, dht->c, dht->close_clientlist[i].ip_port, 1043 send_ping_request(dht->ping, dht->close_clientlist[i].ip_port,
1048 dht->close_clientlist[i].client_id ); 1044 dht->close_clientlist[i].client_id );
1049 dht->close_clientlist[i].last_pinged = temp_time; 1045 dht->close_clientlist[i].last_pinged = temp_time;
1050 } 1046 }
@@ -1069,7 +1065,7 @@ static void do_Close(DHT *dht)
1069void DHT_bootstrap(DHT *dht, IP_Port ip_port, uint8_t *public_key) 1065void DHT_bootstrap(DHT *dht, IP_Port ip_port, uint8_t *public_key)
1070{ 1066{
1071 getnodes(dht, ip_port, public_key, dht->c->self_public_key); 1067 getnodes(dht, ip_port, public_key, dht->c->self_public_key);
1072 send_ping_request(dht->ping, dht->c, ip_port, public_key); 1068 send_ping_request(dht->ping, ip_port, public_key);
1073} 1069}
1074int DHT_bootstrap_from_address(DHT *dht, const char *address, uint8_t ipv6enabled, 1070int DHT_bootstrap_from_address(DHT *dht, const char *address, uint8_t ipv6enabled,
1075 uint16_t port, uint8_t *public_key) 1071 uint16_t port, uint8_t *public_key)
@@ -1386,7 +1382,7 @@ static void punch_holes(DHT *dht, IP ip, uint16_t *port_list, uint16_t numports,
1386 IP_Port pinging; 1382 IP_Port pinging;
1387 ip_copy(&pinging.ip, &ip); 1383 ip_copy(&pinging.ip, &ip);
1388 pinging.port = htons(port); 1384 pinging.port = htons(port);
1389 send_ping_request(dht->ping, dht->c, pinging, dht->friends_list[friend_num].client_id); 1385 send_ping_request(dht->ping, pinging, dht->friends_list[friend_num].client_id);
1390 } 1386 }
1391 1387
1392 dht->friends_list[friend_num].punching_index = i; 1388 dht->friends_list[friend_num].punching_index = i;
@@ -1432,94 +1428,34 @@ static void do_NAT(DHT *dht)
1432/*----------------------------------------------------------------------------------*/ 1428/*----------------------------------------------------------------------------------*/
1433/*-----------------------END OF NAT PUNCHING FUNCTIONS------------------------------*/ 1429/*-----------------------END OF NAT PUNCHING FUNCTIONS------------------------------*/
1434 1430
1435
1436/* Add nodes to the toping list.
1437 * All nodes in this list are pinged every TIME_TOPING seconds
1438 * and are then removed from the list.
1439 * If the list is full the nodes farthest from our client_id are replaced.
1440 * The purpose of this list is to enable quick integration of new nodes into the
1441 * network while preventing amplification attacks.
1442 *
1443 * return 0 if node was added.
1444 * return -1 if node was not added.
1445 */
1446int add_toping(DHT *dht, uint8_t *client_id, IP_Port ip_port)
1447{
1448 if (!ip_isset(&ip_port.ip))
1449 return -1;
1450
1451 uint32_t i;
1452
1453 for (i = 0; i < MAX_TOPING; ++i) {
1454 if (!ip_isset(&dht->toping[i].ip_port.ip)) {
1455 memcpy(dht->toping[i].client_id, client_id, CLIENT_ID_SIZE);
1456 ipport_copy(&dht->toping[i].ip_port, &ip_port);
1457 return 0;
1458 }
1459 }
1460
1461 for (i = 0; i < MAX_TOPING; ++i) {
1462 if (id_closest(dht->c->self_public_key, dht->toping[i].client_id, client_id) == 2) {
1463 memcpy(dht->toping[i].client_id, client_id, CLIENT_ID_SIZE);
1464 ipport_copy(&dht->toping[i].ip_port, &ip_port);
1465 return 0;
1466 }
1467 }
1468
1469 return -1;
1470}
1471
1472/* Ping all the valid nodes in the toping list every TIME_TOPING seconds.
1473 * This function must be run at least once every TIME_TOPING seconds.
1474 */
1475static void do_toping(DHT *dht)
1476{
1477 uint64_t temp_time = unix_time();
1478
1479 if (!is_timeout(temp_time, dht->last_toping, TIME_TOPING))
1480 return;
1481
1482 dht->last_toping = temp_time;
1483 uint32_t i;
1484
1485 for (i = 0; i < MAX_TOPING; ++i) {
1486 if (!ip_isset(&dht->toping[i].ip_port.ip))
1487 return;
1488
1489 send_ping_request(dht->ping, dht->c, dht->toping[i].ip_port, dht->toping[i].client_id);
1490 ip_reset(&dht->toping[i].ip_port.ip);
1491 }
1492}
1493
1494
1495DHT *new_DHT(Net_Crypto *c) 1431DHT *new_DHT(Net_Crypto *c)
1496{ 1432{
1497 if (c == NULL) 1433 if (c == NULL)
1498 return NULL; 1434 return NULL;
1499 1435
1500 DHT *temp = calloc(1, sizeof(DHT)); 1436 DHT *dht = calloc(1, sizeof(DHT));
1501 1437
1502 if (temp == NULL) 1438 if (dht == NULL)
1503 return NULL; 1439 return NULL;
1504 1440
1505 temp->ping = new_ping(); 1441 dht->ping = new_ping(dht, c);
1506 1442
1507 if (temp->ping == NULL) { 1443 if (dht->ping == NULL) {
1508 kill_DHT(temp); 1444 kill_DHT(dht);
1509 return NULL; 1445 return NULL;
1510 } 1446 }
1511 1447
1512 temp->c = c; 1448 dht->c = c;
1513 networking_registerhandler(c->lossless_udp->net, NET_PACKET_PING_REQUEST, &handle_ping_request, temp); 1449 networking_registerhandler(c->lossless_udp->net, NET_PACKET_GET_NODES, &handle_getnodes, dht);
1514 networking_registerhandler(c->lossless_udp->net, NET_PACKET_PING_RESPONSE, &handle_ping_response, temp); 1450 networking_registerhandler(c->lossless_udp->net, NET_PACKET_SEND_NODES, &handle_sendnodes, dht);
1515 networking_registerhandler(c->lossless_udp->net, NET_PACKET_GET_NODES, &handle_getnodes, temp);
1516 networking_registerhandler(c->lossless_udp->net, NET_PACKET_SEND_NODES, &handle_sendnodes, temp);
1517#ifdef TOX_ENABLE_IPV6 1451#ifdef TOX_ENABLE_IPV6
1518 networking_registerhandler(c->lossless_udp->net, NET_PACKET_SEND_NODES_IPV6, &handle_sendnodes_ipv6, temp); 1452 networking_registerhandler(c->lossless_udp->net, NET_PACKET_SEND_NODES_IPV6, &handle_sendnodes_ipv6, dht);
1519#endif 1453#endif
1520 init_cryptopackets(temp); 1454
1521 cryptopacket_registerhandler(c, CRYPTO_PACKET_NAT_PING, &handle_NATping, temp); 1455 init_cryptopackets(dht);
1522 return temp; 1456 cryptopacket_registerhandler(c, CRYPTO_PACKET_NAT_PING, &handle_NATping, dht);
1457
1458 return dht;
1523} 1459}
1524 1460
1525void do_DHT(DHT *dht) 1461void do_DHT(DHT *dht)
@@ -1527,7 +1463,7 @@ void do_DHT(DHT *dht)
1527 do_Close(dht); 1463 do_Close(dht);
1528 do_DHT_friends(dht); 1464 do_DHT_friends(dht);
1529 do_NAT(dht); 1465 do_NAT(dht);
1530 do_toping(dht); 1466 do_toping(dht->ping);
1531} 1467}
1532void kill_DHT(DHT *dht) 1468void kill_DHT(DHT *dht)
1533{ 1469{
diff --git a/toxcore/DHT.h b/toxcore/DHT.h
index e6f227f7..7cb3198d 100644
--- a/toxcore/DHT.h
+++ b/toxcore/DHT.h
@@ -26,7 +26,6 @@
26 26
27#include "net_crypto.h" 27#include "net_crypto.h"
28 28
29
30/* Size of the client_id in bytes. */ 29/* Size of the client_id in bytes. */
31#define CLIENT_ID_SIZE crypto_box_PUBLICKEYBYTES 30#define CLIENT_ID_SIZE crypto_box_PUBLICKEYBYTES
32 31
@@ -92,22 +91,23 @@ typedef Node46_format Node_format;
92typedef Node4_format Node_format; 91typedef Node4_format Node_format;
93#endif 92#endif
94 93
94/*----------------------------------------------------------------------------------*/
95
95typedef struct { 96typedef struct {
96 IP_Port ip_port; 97 IP_Port ip_port;
97 uint64_t ping_id; 98 uint64_t id;
98 uint64_t timestamp; 99 uint64_t timestamp;
99} Pinged; 100} pinged_t;
100 101
101/*----------------------------------------------------------------------------------*/
102typedef struct { 102typedef struct {
103 Net_Crypto *c; 103 Net_Crypto *c;
104
104 Client_data close_clientlist[LCLIENT_LIST]; 105 Client_data close_clientlist[LCLIENT_LIST];
105 DHT_Friend *friends_list; 106 DHT_Friend *friends_list;
106 uint16_t num_friends; 107 uint16_t num_friends;
107 Pinged send_nodes[LSEND_NODES_ARRAY];
108 Node_format toping[MAX_TOPING];
109 uint64_t last_toping;
110 uint64_t close_lastgetnodes; 108 uint64_t close_lastgetnodes;
109
110 pinged_t send_nodes[LSEND_NODES_ARRAY];
111 void *ping; 111 void *ping;
112} DHT; 112} DHT;
113/*----------------------------------------------------------------------------------*/ 113/*----------------------------------------------------------------------------------*/
@@ -152,6 +152,14 @@ int DHT_delfriend(DHT *dht, uint8_t *client_id);
152 */ 152 */
153int DHT_getfriendip(DHT *dht, uint8_t *client_id, IP_Port *ip_port); 153int DHT_getfriendip(DHT *dht, uint8_t *client_id, IP_Port *ip_port);
154 154
155/* Compares client_id1 and client_id2 with client_id.
156 *
157 * return 0 if both are same distance.
158 * return 1 if client_id1 is closer.
159 * return 2 if client_id2 is closer.
160 */
161int id_closest(uint8_t *id, uint8_t *id1, uint8_t *id2);
162
155/* Run this function at least a couple times per second (It's the main loop). */ 163/* Run this function at least a couple times per second (It's the main loop). */
156void do_DHT(DHT *dht); 164void do_DHT(DHT *dht);
157 165
@@ -176,17 +184,6 @@ void DHT_bootstrap(DHT *dht, IP_Port ip_port, uint8_t *public_key);
176int DHT_bootstrap_from_address(DHT *dht, const char *address, uint8_t ipv6enabled, 184int DHT_bootstrap_from_address(DHT *dht, const char *address, uint8_t ipv6enabled,
177 uint16_t port, uint8_t *public_key); 185 uint16_t port, uint8_t *public_key);
178 186
179/* Add nodes to the toping list.
180 * All nodes in this list are pinged every TIME_TOPING seconds
181 * and are then removed from the list.
182 * If the list is full the nodes farthest from our client_id are replaced.
183 * The purpose of this list is to enable quick integration of new nodes into the
184 * network while preventing amplification attacks.
185 *
186 * return 0 if node was added.
187 * return -1 if node was not added.
188 */
189int add_toping(DHT *dht, uint8_t *client_id, IP_Port ip_port);
190 187
191/* ROUTING FUNCTIONS */ 188/* ROUTING FUNCTIONS */
192 189
diff --git a/toxcore/group_chats.c b/toxcore/group_chats.c
index dc8e158b..c32b26ba 100644
--- a/toxcore/group_chats.c
+++ b/toxcore/group_chats.c
@@ -53,31 +53,6 @@ typedef struct {
53 53
54} sendnodes_data; 54} sendnodes_data;
55 55
56/* Compares client_id1 and client_id2 with client_id
57 * return 0 if both are same distance
58 * return 1 if client_id1 is closer
59 * return 2 if client_id2 is closer
60 */
61static int id_closest(uint8_t *id, uint8_t *id1, uint8_t *id2)
62{
63 size_t i;
64 uint8_t distance1, distance2;
65
66 for (i = 0; i < CLIENT_ID_SIZE; ++i) {
67
68 distance1 = abs(((int8_t *)id)[i] ^ ((int8_t *)id1)[i]);
69 distance2 = abs(((int8_t *)id)[i] ^ ((int8_t *)id2)[i]);
70
71 if (distance1 < distance2)
72 return 1;
73
74 if (distance1 > distance2)
75 return 2;
76 }
77
78 return 0;
79}
80
81 56
82/* 57/*
83 * check if peer with client_id is in peer array. 58 * check if peer with client_id is in peer array.
diff --git a/toxcore/ping.c b/toxcore/ping.c
index 56ce2f59..09b80f0d 100644
--- a/toxcore/ping.c
+++ b/toxcore/ping.c
@@ -12,53 +12,48 @@
12#include <stdbool.h> 12#include <stdbool.h>
13#include <stdint.h> 13#include <stdint.h>
14 14
15#include "DHT.h"
16#include "net_crypto.h" 15#include "net_crypto.h"
17#include "network.h" 16#include "DHT.h"
18#include "util.h"
19 17
20#define PING_NUM_MAX 256 18#define PING_NUM_MAX 256
21#define PING_TIMEOUT 5 // 5s 19#define PING_TIMEOUT 5 // 5s
22 20
23typedef struct { 21/* Ping newly announced nodes to ping per TIME_TOPING seconds*/
24 IP_Port ipp; 22#define TIME_TOPING 5
25 uint64_t id;
26 uint64_t timestamp;
27} pinged_t;
28 23
29typedef struct { 24typedef struct {
25 Net_Crypto *c;
26
30 pinged_t pings[PING_NUM_MAX]; 27 pinged_t pings[PING_NUM_MAX];
31 size_t num_pings; 28 size_t num_pings;
32 size_t pos_pings; 29 size_t pos_pings;
30
31 Node_format toping[MAX_TOPING];
32 uint64_t last_toping;
33} PING; 33} PING;
34 34
35void *new_ping(void) 35#define __PING_C__
36{
37 return calloc(1, sizeof(PING));
38}
39 36
40void kill_ping(void *ping) 37#include "network.h"
41{ 38#include "util.h"
42 free(ping); 39#include "ping.h"
43}
44 40
45static bool is_timeout(uint64_t time) 41static bool is_ping_timeout(uint64_t time)
46{ 42{
47 return (time + PING_TIMEOUT) < now(); 43 return (time + PING_TIMEOUT) < now();
48} 44}
49 45
50static void remove_timeouts(void *ping) // O(n) 46static void remove_timeouts(PING *ping) // O(n)
51{ 47{
52 PING *png = ping;
53 size_t i, id; 48 size_t i, id;
54 size_t new_pos = png->pos_pings; 49 size_t new_pos = ping->pos_pings;
55 size_t new_num = png->num_pings; 50 size_t new_num = ping->num_pings;
56 51
57 // Loop through buffer, oldest first. 52 // Loop through buffer, oldest first.
58 for (i = 0; i < png->num_pings; i++) { 53 for (i = 0; i < ping->num_pings; i++) {
59 id = (png->pos_pings + i) % PING_NUM_MAX; 54 id = (ping->pos_pings + i) % PING_NUM_MAX;
60 55
61 if (is_timeout(png->pings[id].timestamp)) { 56 if (is_ping_timeout(ping->pings[id].timestamp)) {
62 new_pos++; 57 new_pos++;
63 new_num--; 58 new_num--;
64 } 59 }
@@ -68,37 +63,35 @@ static void remove_timeouts(void *ping) // O(n)
68 } 63 }
69 } 64 }
70 65
71 png->num_pings = new_num; 66 ping->num_pings = new_num;
72 png->pos_pings = new_pos % PING_NUM_MAX; 67 ping->pos_pings = new_pos % PING_NUM_MAX;
73} 68}
74 69
75uint64_t add_ping(void *ping, IP_Port ipp) // O(n) 70static uint64_t add_ping(PING *ping, IP_Port ipp) // O(n)
76{ 71{
77 PING *png = ping;
78 size_t p; 72 size_t p;
79 73
80 remove_timeouts(ping); 74 remove_timeouts(ping);
81 75
82 /* Remove oldest ping if full buffer. */ 76 /* Remove oldest ping if full buffer. */
83 if (png->num_pings == PING_NUM_MAX) { 77 if (ping->num_pings == PING_NUM_MAX) {
84 png->num_pings--; 78 ping->num_pings--;
85 png->pos_pings = (png->pos_pings + 1) % PING_NUM_MAX; 79 ping->pos_pings = (ping->pos_pings + 1) % PING_NUM_MAX;
86 } 80 }
87 81
88 /* Insert new ping at end of list. */ 82 /* Insert new ping at end of list. */
89 p = (png->pos_pings + png->num_pings) % PING_NUM_MAX; 83 p = (ping->pos_pings + ping->num_pings) % PING_NUM_MAX;
90 84
91 png->pings[p].ipp = ipp; 85 ping->pings[p].ip_port = ipp;
92 png->pings[p].timestamp = now(); 86 ping->pings[p].timestamp = now();
93 png->pings[p].id = random_64b(); 87 ping->pings[p].id = random_64b();
94 88
95 png->num_pings++; 89 ping->num_pings++;
96 return png->pings[p].id; 90 return ping->pings[p].id;
97} 91}
98 92
99bool is_pinging(void *ping, IP_Port ipp, uint64_t ping_id) // O(n) TODO: Replace this with something else. 93static bool is_pinging(PING *ping, IP_Port ipp, uint64_t ping_id) // O(n) TODO: Replace this with something else.
100{ 94{
101 PING *png = ping;
102 95
103 /* shouldn't that be an OR ? */ 96 /* shouldn't that be an OR ? */
104 if (!ip_isset(&ipp.ip) && ping_id == 0) 97 if (!ip_isset(&ipp.ip) && ping_id == 0)
@@ -108,12 +101,12 @@ bool is_pinging(void *ping, IP_Port ipp, uint64_t ping_id) // O(n) TODO: Repl
108 101
109 remove_timeouts(ping); 102 remove_timeouts(ping);
110 103
111 for (i = 0; i < png->num_pings; i++) { 104 for (i = 0; i < ping->num_pings; i++) {
112 id = (png->pos_pings + i) % PING_NUM_MAX; 105 id = (ping->pos_pings + i) % PING_NUM_MAX;
113 106
114 /* ping_id = 0 means match any id. */ 107 /* ping_id = 0 means match any id. */
115 if ((!ip_isset(&ipp.ip) || ipport_equal(&png->pings[id].ipp, &ipp)) && 108 if ((!ip_isset(&ipp.ip) || ipport_equal(&ping->pings[id].ip_port, &ipp)) &&
116 (png->pings[id].id == ping_id || ping_id == 0)) { 109 (ping->pings[id].id == ping_id || ping_id == 0)) {
117 return true; 110 return true;
118 } 111 }
119 } 112 }
@@ -123,25 +116,25 @@ bool is_pinging(void *ping, IP_Port ipp, uint64_t ping_id) // O(n) TODO: Repl
123 116
124#define DHT_PING_SIZE (1 + CLIENT_ID_SIZE + crypto_box_NONCEBYTES + sizeof(uint64_t) + ENCRYPTION_PADDING) 117#define DHT_PING_SIZE (1 + CLIENT_ID_SIZE + crypto_box_NONCEBYTES + sizeof(uint64_t) + ENCRYPTION_PADDING)
125 118
126int send_ping_request(void *ping, Net_Crypto *c, IP_Port ipp, uint8_t *client_id) 119int send_ping_request(PING *ping, IP_Port ipp, uint8_t *client_id)
127{ 120{
128 uint8_t pk[DHT_PING_SIZE]; 121 uint8_t pk[DHT_PING_SIZE];
129 int rc; 122 int rc;
130 uint64_t ping_id; 123 uint64_t ping_id;
131 124
132 if (is_pinging(ping, ipp, 0) || id_eq(client_id, c->self_public_key)) 125 if (is_pinging(ping, ipp, 0) || id_eq(client_id, ping->c->self_public_key))
133 return 1; 126 return 1;
134 127
135 // Generate random ping_id. 128 // Generate random ping_id.
136 ping_id = add_ping(ping, ipp); 129 ping_id = add_ping(ping, ipp);
137 130
138 pk[0] = NET_PACKET_PING_REQUEST; 131 pk[0] = NET_PACKET_PING_REQUEST;
139 id_cpy(pk + 1, c->self_public_key); // Our pubkey 132 id_cpy(pk + 1, ping->c->self_public_key); // Our pubkey
140 new_nonce(pk + 1 + CLIENT_ID_SIZE); // Generate new nonce 133 new_nonce(pk + 1 + CLIENT_ID_SIZE); // Generate new nonce
141 134
142 // Encrypt ping_id using recipient privkey 135 // Encrypt ping_id using recipient privkey
143 rc = encrypt_data(client_id, 136 rc = encrypt_data(client_id,
144 c->self_secret_key, 137 ping->c->self_secret_key,
145 pk + 1 + CLIENT_ID_SIZE, 138 pk + 1 + CLIENT_ID_SIZE,
146 (uint8_t *) &ping_id, sizeof(ping_id), 139 (uint8_t *) &ping_id, sizeof(ping_id),
147 pk + 1 + CLIENT_ID_SIZE + crypto_box_NONCEBYTES); 140 pk + 1 + CLIENT_ID_SIZE + crypto_box_NONCEBYTES);
@@ -149,24 +142,24 @@ int send_ping_request(void *ping, Net_Crypto *c, IP_Port ipp, uint8_t *client_id
149 if (rc != sizeof(ping_id) + ENCRYPTION_PADDING) 142 if (rc != sizeof(ping_id) + ENCRYPTION_PADDING)
150 return 1; 143 return 1;
151 144
152 return sendpacket(c->lossless_udp->net, ipp, pk, sizeof(pk)); 145 return sendpacket(ping->c->lossless_udp->net, ipp, pk, sizeof(pk));
153} 146}
154 147
155int send_ping_response(Net_Crypto *c, IP_Port ipp, uint8_t *client_id, uint64_t ping_id) 148static int send_ping_response(PING *ping, IP_Port ipp, uint8_t *client_id, uint64_t ping_id)
156{ 149{
157 uint8_t pk[DHT_PING_SIZE]; 150 uint8_t pk[DHT_PING_SIZE];
158 int rc; 151 int rc;
159 152
160 if (id_eq(client_id, c->self_public_key)) 153 if (id_eq(client_id, ping->c->self_public_key))
161 return 1; 154 return 1;
162 155
163 pk[0] = NET_PACKET_PING_RESPONSE; 156 pk[0] = NET_PACKET_PING_RESPONSE;
164 id_cpy(pk + 1, c->self_public_key); // Our pubkey 157 id_cpy(pk + 1, ping->c->self_public_key); // Our pubkey
165 new_nonce(pk + 1 + CLIENT_ID_SIZE); // Generate new nonce 158 new_nonce(pk + 1 + CLIENT_ID_SIZE); // Generate new nonce
166 159
167 // Encrypt ping_id using recipient privkey 160 // Encrypt ping_id using recipient privkey
168 rc = encrypt_data(client_id, 161 rc = encrypt_data(client_id,
169 c->self_secret_key, 162 ping->c->self_secret_key,
170 pk + 1 + CLIENT_ID_SIZE, 163 pk + 1 + CLIENT_ID_SIZE,
171 (uint8_t *) &ping_id, sizeof(ping_id), 164 (uint8_t *) &ping_id, sizeof(ping_id),
172 pk + 1 + CLIENT_ID_SIZE + crypto_box_NONCEBYTES); 165 pk + 1 + CLIENT_ID_SIZE + crypto_box_NONCEBYTES);
@@ -174,24 +167,25 @@ int send_ping_response(Net_Crypto *c, IP_Port ipp, uint8_t *client_id, uint64_t
174 if (rc != sizeof(ping_id) + ENCRYPTION_PADDING) 167 if (rc != sizeof(ping_id) + ENCRYPTION_PADDING)
175 return 1; 168 return 1;
176 169
177 return sendpacket(c->lossless_udp->net, ipp, pk, sizeof(pk)); 170 return sendpacket(ping->c->lossless_udp->net, ipp, pk, sizeof(pk));
178} 171}
179 172
180int handle_ping_request(void *object, IP_Port source, uint8_t *packet, uint32_t length) 173static int handle_ping_request(void *_dht, IP_Port source, uint8_t *packet, uint32_t length)
181{ 174{
182 DHT *dht = object; 175 DHT *dht = _dht;
183 int rc; 176 int rc;
184 uint64_t ping_id; 177 uint64_t ping_id;
185 178
186 if (length != DHT_PING_SIZE) 179 if (length != DHT_PING_SIZE)
187 return 1; 180 return 1;
188 181
189 if (id_eq(packet + 1, dht->c->self_public_key)) 182 PING *ping = dht->ping;
183 if (id_eq(packet + 1, ping->c->self_public_key))
190 return 1; 184 return 1;
191 185
192 // Decrypt ping_id 186 // Decrypt ping_id
193 rc = decrypt_data(packet + 1, 187 rc = decrypt_data(packet + 1,
194 dht->c->self_secret_key, 188 ping->c->self_secret_key,
195 packet + 1 + CLIENT_ID_SIZE, 189 packet + 1 + CLIENT_ID_SIZE,
196 packet + 1 + CLIENT_ID_SIZE + crypto_box_NONCEBYTES, 190 packet + 1 + CLIENT_ID_SIZE + crypto_box_NONCEBYTES,
197 sizeof(ping_id) + ENCRYPTION_PADDING, 191 sizeof(ping_id) + ENCRYPTION_PADDING,
@@ -201,27 +195,28 @@ int handle_ping_request(void *object, IP_Port source, uint8_t *packet, uint32_t
201 return 1; 195 return 1;
202 196
203 // Send response 197 // Send response
204 send_ping_response(dht->c, source, packet + 1, ping_id); 198 send_ping_response(ping, source, packet + 1, ping_id);
205 add_toping(dht, packet + 1, source); 199 add_toping(ping, packet + 1, source);
206 200
207 return 0; 201 return 0;
208} 202}
209 203
210int handle_ping_response(void *object, IP_Port source, uint8_t *packet, uint32_t length) 204static int handle_ping_response(void *_dht, IP_Port source, uint8_t *packet, uint32_t length)
211{ 205{
212 DHT *dht = object; 206 DHT *dht = _dht;
213 int rc; 207 int rc;
214 uint64_t ping_id; 208 uint64_t ping_id;
215 209
216 if (length != DHT_PING_SIZE) 210 if (length != DHT_PING_SIZE)
217 return 1; 211 return 1;
218 212
219 if (id_eq(packet + 1, dht->c->self_public_key)) 213 PING *ping = dht->ping;
214 if (id_eq(packet + 1, ping->c->self_public_key))
220 return 1; 215 return 1;
221 216
222 // Decrypt ping_id 217 // Decrypt ping_id
223 rc = decrypt_data(packet + 1, 218 rc = decrypt_data(packet + 1,
224 dht->c->self_secret_key, 219 ping->c->self_secret_key,
225 packet + 1 + CLIENT_ID_SIZE, 220 packet + 1 + CLIENT_ID_SIZE,
226 packet + 1 + CLIENT_ID_SIZE + crypto_box_NONCEBYTES, 221 packet + 1 + CLIENT_ID_SIZE + crypto_box_NONCEBYTES,
227 sizeof(ping_id) + ENCRYPTION_PADDING, 222 sizeof(ping_id) + ENCRYPTION_PADDING,
@@ -231,10 +226,97 @@ int handle_ping_response(void *object, IP_Port source, uint8_t *packet, uint32_t
231 return 1; 226 return 1;
232 227
233 /* Make sure ping_id is correct. */ 228 /* Make sure ping_id is correct. */
234 if (!is_pinging(dht->ping, source, ping_id)) 229 if (!is_pinging(ping, source, ping_id))
235 return 1; 230 return 1;
236 231
237 // Associate source ip with client_id 232 // Associate source ip with client_id
238 addto_lists(dht, source, packet + 1); 233 addto_lists(dht, source, packet + 1);
239 return 0; 234 return 0;
240} 235}
236
237
238/* Add nodes to the toping list.
239 * All nodes in this list are pinged every TIME_TOPING seconds
240 * and are then removed from the list.
241 * If the list is full the nodes farthest from our client_id are replaced.
242 * The purpose of this list is to enable quick integration of new nodes into the
243 * network while preventing amplification attacks.
244 *
245 * return 0 if node was added.
246 * return -1 if node was not added.
247 */
248int add_toping(PING *ping, uint8_t *client_id, IP_Port ip_port)
249{
250 if (!ip_isset(&ip_port.ip))
251 return -1;
252
253 uint32_t i;
254
255 for (i = 0; i < MAX_TOPING; ++i) {
256 if (!ip_isset(&ping->toping[i].ip_port.ip)) {
257 memcpy(ping->toping[i].client_id, client_id, CLIENT_ID_SIZE);
258 ipport_copy(&ping->toping[i].ip_port, &ip_port);
259 return 0;
260 }
261 }
262
263 for (i = 0; i < MAX_TOPING; ++i) {
264 if (id_closest(ping->c->self_public_key, ping->toping[i].client_id, client_id) == 2) {
265 memcpy(ping->toping[i].client_id, client_id, CLIENT_ID_SIZE);
266 ipport_copy(&ping->toping[i].ip_port, &ip_port);
267 return 0;
268 }
269 }
270
271 return -1;
272}
273
274
275/* Ping all the valid nodes in the toping list every TIME_TOPING seconds.
276 * This function must be run at least once every TIME_TOPING seconds.
277 */
278static int is_timeout(uint64_t time_now, uint64_t timestamp, uint64_t timeout)
279{
280 return timestamp + timeout <= time_now;
281}
282
283void do_toping(PING *ping)
284{
285 uint64_t temp_time = unix_time();
286
287 if (!is_timeout(temp_time, ping->last_toping, TIME_TOPING))
288 return;
289
290 ping->last_toping = temp_time;
291 uint32_t i;
292
293 for (i = 0; i < MAX_TOPING; ++i) {
294 if (!ip_isset(&ping->toping[i].ip_port.ip))
295 return;
296
297 send_ping_request(ping, ping->toping[i].ip_port, ping->toping[i].client_id);
298 ip_reset(&ping->toping[i].ip_port.ip);
299 }
300}
301
302
303PING *new_ping(DHT *dht, Net_Crypto *c)
304{
305 PING *ping = calloc(1, sizeof(PING));
306 if (ping == NULL)
307 return NULL;
308
309 ping->c = c;
310 networking_registerhandler(ping->c->lossless_udp->net, NET_PACKET_PING_REQUEST, &handle_ping_request, dht);
311 networking_registerhandler(ping->c->lossless_udp->net, NET_PACKET_PING_RESPONSE, &handle_ping_response, dht);
312
313 return ping;
314}
315
316void kill_ping(PING *ping)
317{
318 networking_registerhandler(ping->c->lossless_udp->net, NET_PACKET_PING_REQUEST, NULL, NULL);
319 networking_registerhandler(ping->c->lossless_udp->net, NET_PACKET_PING_RESPONSE, NULL, NULL);
320
321 free(ping);
322}
diff --git a/toxcore/ping.h b/toxcore/ping.h
index 5d080e34..fabb1afd 100644
--- a/toxcore/ping.h
+++ b/toxcore/ping.h
@@ -4,14 +4,31 @@
4 * This file is donated to the Tox Project. 4 * This file is donated to the Tox Project.
5 * Copyright 2013 plutooo 5 * Copyright 2013 plutooo
6 */ 6 */
7#ifndef __PING_H__
8#define __PING_H__
7 9
8#include <stdbool.h> 10#include <stdbool.h>
9 11
10void *new_ping(void); 12#ifndef __PING_C__
11void kill_ping(void *ping); 13typedef struct PING PING;
12uint64_t add_ping(void *ping, IP_Port ipp); 14#endif
13bool is_pinging(void *ping, IP_Port ipp, uint64_t ping_id); 15
14int send_ping_request(void *ping, Net_Crypto *c, IP_Port ipp, uint8_t *client_id); 16/* Add nodes to the toping list.
15int send_ping_response(Net_Crypto *c, IP_Port ipp, uint8_t *client_id, uint64_t ping_id); 17 * All nodes in this list are pinged every TIME_TOPING seconds
16int handle_ping_request(void *object, IP_Port source, uint8_t *packet, uint32_t length); 18 * and are then removed from the list.
17int handle_ping_response(void *object, IP_Port source, uint8_t *packet, uint32_t length); 19 * If the list is full the nodes farthest from our client_id are replaced.
20 * The purpose of this list is to enable quick integration of new nodes into the
21 * network while preventing amplification attacks.
22 *
23 * return 0 if node was added.
24 * return -1 if node was not added.
25 */
26int add_toping(PING *ping, uint8_t *client_id, IP_Port ip_port);
27void do_toping(PING *ping);
28
29PING *new_ping(DHT *dht, Net_Crypto *c);
30void kill_ping(PING *ping);
31
32int send_ping_request(PING *ping, IP_Port ipp, uint8_t *client_id);
33
34#endif /* __PING_H__ */