summaryrefslogtreecommitdiff
path: root/toxcore
diff options
context:
space:
mode:
Diffstat (limited to 'toxcore')
-rw-r--r--toxcore/DHT.c326
-rw-r--r--toxcore/DHT.h40
-rw-r--r--toxcore/LAN_discovery.c11
-rw-r--r--toxcore/Makefile.inc2
-rw-r--r--toxcore/Messenger.c339
-rw-r--r--toxcore/Messenger.h36
-rw-r--r--toxcore/assoc.c926
-rw-r--r--toxcore/assoc.h93
-rw-r--r--toxcore/friend_requests.c10
-rw-r--r--toxcore/friend_requests.h10
-rw-r--r--toxcore/group_chats.c204
-rw-r--r--toxcore/group_chats.h45
-rw-r--r--toxcore/network.c18
-rw-r--r--toxcore/network.h14
-rw-r--r--toxcore/ping.c31
-rw-r--r--toxcore/ping.h4
-rw-r--r--toxcore/tox.c135
-rw-r--r--toxcore/tox.h140
18 files changed, 2068 insertions, 316 deletions
diff --git a/toxcore/DHT.c b/toxcore/DHT.c
index 5f4aa228..242cbea2 100644
--- a/toxcore/DHT.c
+++ b/toxcore/DHT.c
@@ -28,34 +28,27 @@
28#endif 28#endif
29 29
30#include "DHT.h" 30#include "DHT.h"
31#include "network.h" 31#include "assoc.h"
32#include "ping.h" 32#include "ping.h"
33
34#include "network.h"
35#include "LAN_discovery.h"
33#include "misc_tools.h" 36#include "misc_tools.h"
34#include "util.h" 37#include "util.h"
35#include "LAN_discovery.h"
36
37/* The number of seconds for a non responsive node to become bad. */
38#define BAD_NODE_TIMEOUT 70
39 38
40/* The max number of nodes to send with send nodes. */ 39/* The max number of nodes to send with send nodes. */
41#define MAX_SENT_NODES 8 40#define MAX_SENT_NODES 8
42 41
43/* Ping timeout in seconds */
44#define PING_TIMEOUT 3
45
46/* The timeout after which a node is discarded completely. */ 42/* The timeout after which a node is discarded completely. */
47#define KILL_NODE_TIMEOUT 300 43#define KILL_NODE_TIMEOUT 300
48 44
49/* Ping interval in seconds for each node in our lists. */
50#define PING_INTERVAL 60
51
52/* Ping interval in seconds for each random sending of a get nodes request. */ 45/* Ping interval in seconds for each random sending of a get nodes request. */
53#define GET_NODE_INTERVAL 5 46#define GET_NODE_INTERVAL 5
54 47
55#define MAX_PUNCHING_PORTS 128 48#define MAX_PUNCHING_PORTS 32
56 49
57/* Interval in seconds between punching attempts*/ 50/* Interval in seconds between punching attempts*/
58#define PUNCH_INTERVAL 10 51#define PUNCH_INTERVAL 3
59 52
60#define NAT_PING_REQUEST 0 53#define NAT_PING_REQUEST 0
61#define NAT_PING_RESPONSE 1 54#define NAT_PING_RESPONSE 1
@@ -115,21 +108,6 @@ static int client_id_cmp(ClientPair p1, ClientPair p2)
115 return c; 108 return c;
116} 109}
117 110
118static int client_in_list(Client_data *list, uint32_t length, uint8_t *client_id)
119{
120 uint32_t i;
121
122 for (i = 0; i < length; i++)
123
124 /* Dead nodes are considered dead (not in the list)*/
125 if (!is_timeout(list[i].assoc4.timestamp, KILL_NODE_TIMEOUT) ||
126 !is_timeout(list[i].assoc6.timestamp, KILL_NODE_TIMEOUT))
127 if (id_equal(list[i].client_id, client_id))
128 return 1;
129
130 return 0;
131}
132
133/* Check if client with client_id is already in list of length length. 111/* Check if client with client_id is already in list of length length.
134 * If it is then set its corresponding timestamp to current time. 112 * If it is then set its corresponding timestamp to current time.
135 * If the id is already in the list with a different ip_port, update it. 113 * If the id is already in the list with a different ip_port, update it.
@@ -373,8 +351,7 @@ static void get_close_nodes_inner(DHT *dht, uint8_t *client_id, Node_format *nod
373 * 351 *
374 * want_good : do we want only good nodes as checked with the hardening returned or not? 352 * want_good : do we want only good nodes as checked with the hardening returned or not?
375 */ 353 */
376static uint32_t get_close_nodes(DHT *dht, uint8_t *client_id, Node_format *nodes_list, sa_family_t sa_family, 354static int get_somewhat_close_nodes(DHT *dht, uint8_t *client_id, Node_format *nodes_list, sa_family_t sa_family, uint8_t is_LAN, uint8_t want_good)
377 uint8_t is_LAN, uint8_t want_good)
378{ 355{
379 uint32_t num_nodes = 0, i; 356 uint32_t num_nodes = 0, i;
380 get_close_nodes_inner(dht, client_id, nodes_list, sa_family, 357 get_close_nodes_inner(dht, client_id, nodes_list, sa_family,
@@ -388,6 +365,53 @@ static uint32_t get_close_nodes(DHT *dht, uint8_t *client_id, Node_format *nodes
388 return num_nodes; 365 return num_nodes;
389} 366}
390 367
368static int get_close_nodes(DHT *dht, uint8_t *client_id, Node_format *nodes_list, sa_family_t sa_family, uint8_t is_LAN, uint8_t want_good)
369{
370 if (!dht->assoc)
371 return get_somewhat_close_nodes(dht, client_id, nodes_list, sa_family, is_LAN, want_good);
372
373 Client_data *result[MAX_SENT_NODES];
374
375 Assoc_close_entries request;
376 memset(&request, 0, sizeof(request));
377 request.count = MAX_SENT_NODES;
378 request.count_good = MAX_SENT_NODES;
379 request.result = result;
380 request.wanted_id = client_id;
381 request.flags = (is_LAN ? LANOk : 0) + (sa_family == AF_INET ? ProtoIPv4 : ProtoIPv6);
382
383 uint8_t num_found = Assoc_get_close_entries(dht->assoc, &request);
384
385 if (!num_found)
386 return get_somewhat_close_nodes(dht, client_id, nodes_list, sa_family, is_LAN, want_good);
387
388 uint8_t i, num_returned = 0;
389
390 for (i = 0; i < num_found; i++) {
391 Client_data *client = result[i];
392
393 if (client) {
394 id_copy(nodes_list[i].client_id, client->client_id);
395
396 if (sa_family == AF_INET)
397 if (ipport_isset(&client->assoc4.ip_port)) {
398 nodes_list[i].ip_port = client->assoc4.ip_port;
399 num_returned++;
400 continue;
401 }
402
403 if (sa_family == AF_INET6)
404 if (ipport_isset(&client->assoc6.ip_port)) {
405 nodes_list[i].ip_port = client->assoc6.ip_port;
406 num_returned++;
407 continue;
408 }
409 }
410 }
411
412 return num_returned;
413}
414
391/* Replace first bad (or empty) node with this one. 415/* Replace first bad (or empty) node with this one.
392 * 416 *
393 * return 0 if successful. 417 * return 0 if successful.
@@ -406,21 +430,31 @@ static int replace_bad( Client_data *list,
406 for (i = 0; i < length; ++i) { 430 for (i = 0; i < length; ++i) {
407 /* If node is bad */ 431 /* If node is bad */
408 Client_data *client = &list[i]; 432 Client_data *client = &list[i];
409 IPPTsPng *ipptp = NULL;
410 433
411 if (ip_port.ip.family == AF_INET) 434 if (is_timeout(client->assoc4.timestamp, BAD_NODE_TIMEOUT) &&
412 ipptp = &client->assoc4; 435 is_timeout(client->assoc6.timestamp, BAD_NODE_TIMEOUT)) {
413 else 436
414 ipptp = &client->assoc6; 437 IPPTsPng *ipptp_write = NULL;
438 IPPTsPng *ipptp_clear = NULL;
439
440 if (ip_port.ip.family == AF_INET) {
441 ipptp_write = &client->assoc4;
442 ipptp_clear = &client->assoc6;
443 } else {
444 ipptp_write = &client->assoc6;
445 ipptp_clear = &client->assoc4;
446 }
415 447
416 if (is_timeout(ipptp->timestamp, BAD_NODE_TIMEOUT)) {
417 memcpy(client->client_id, client_id, CLIENT_ID_SIZE); 448 memcpy(client->client_id, client_id, CLIENT_ID_SIZE);
418 ipptp->ip_port = ip_port; 449 ipptp_write->ip_port = ip_port;
419 ipptp->timestamp = unix_time(); 450 ipptp_write->timestamp = unix_time();
451
452 ip_reset(&ipptp_write->ret_ip_port.ip);
453 ipptp_write->ret_ip_port.port = 0;
454 ipptp_write->ret_timestamp = 0;
420 455
421 ip_reset(&ipptp->ret_ip_port.ip); 456 /* zero out other address */
422 ipptp->ret_ip_port.port = 0; 457 memset(ipptp_clear, 0, sizeof(*ipptp_clear));
423 ipptp->ret_timestamp = 0;
424 458
425 return 0; 459 return 0;
426 } 460 }
@@ -451,7 +485,9 @@ static void sort_list(Client_data *list, uint32_t length, uint8_t *comp_client_i
451 list[i] = pairs[i].c2; 485 list[i] = pairs[i].c2;
452} 486}
453 487
454/* Replace the first good node that is further to the comp_client_id than that of the client_id in the list */ 488/* Replace the first good node that is further to the comp_client_id than that of the client_id in the list
489 *
490 * returns 0 when the item was stored, 1 otherwise */
455static int replace_good( Client_data *list, 491static int replace_good( Client_data *list,
456 uint32_t length, 492 uint32_t length,
457 uint8_t *client_id, 493 uint8_t *client_id,
@@ -482,20 +518,28 @@ static int replace_good( Client_data *list,
482 assert(replace >= 0 && replace < length); 518 assert(replace >= 0 && replace < length);
483#endif 519#endif
484 Client_data *client = &list[replace]; 520 Client_data *client = &list[replace];
485 IPPTsPng *ipptp = NULL; 521 IPPTsPng *ipptp_write = NULL;
522 IPPTsPng *ipptp_clear = NULL;
486 523
487 if (ip_port.ip.family == AF_INET) 524 if (ip_port.ip.family == AF_INET) {
488 ipptp = &client->assoc4; 525 ipptp_write = &client->assoc4;
489 else 526 ipptp_clear = &client->assoc6;
490 ipptp = &client->assoc6; 527 } else {
528 ipptp_write = &client->assoc6;
529 ipptp_clear = &client->assoc4;
530 }
491 531
492 memcpy(client->client_id, client_id, CLIENT_ID_SIZE); 532 memcpy(client->client_id, client_id, CLIENT_ID_SIZE);
493 ipptp->ip_port = ip_port; 533 ipptp_write->ip_port = ip_port;
494 ipptp->timestamp = unix_time(); 534 ipptp_write->timestamp = unix_time();
535
536 ip_reset(&ipptp_write->ret_ip_port.ip);
537 ipptp_write->ret_ip_port.port = 0;
538 ipptp_write->ret_timestamp = 0;
539
540 /* zero out other address */
541 memset(ipptp_clear, 0, sizeof(*ipptp_clear));
495 542
496 ip_reset(&ipptp->ret_ip_port.ip);
497 ipptp->ret_ip_port.port = 0;
498 ipptp->ret_timestamp = 0;
499 return 0; 543 return 0;
500 } 544 }
501 545
@@ -504,10 +548,12 @@ static int replace_good( Client_data *list,
504 548
505/* Attempt to add client with ip_port and client_id to the friends client list 549/* Attempt to add client with ip_port and client_id to the friends client list
506 * and close_clientlist. 550 * and close_clientlist.
551 *
552 * returns 1+ if the item is used in any list, 0 else
507 */ 553 */
508void addto_lists(DHT *dht, IP_Port ip_port, uint8_t *client_id) 554int addto_lists(DHT *dht, IP_Port ip_port, uint8_t *client_id)
509{ 555{
510 uint32_t i; 556 uint32_t i, used = 0;
511 557
512 /* convert IPv4-in-IPv6 to IPv4 */ 558 /* convert IPv4-in-IPv6 to IPv4 */
513 if ((ip_port.ip.family == AF_INET6) && IN6_IS_ADDR_V4MAPPED(&ip_port.ip.ip6.in6_addr)) { 559 if ((ip_port.ip.family == AF_INET6) && IN6_IS_ADDR_V4MAPPED(&ip_port.ip.ip6.in6_addr)) {
@@ -521,10 +567,13 @@ void addto_lists(DHT *dht, IP_Port ip_port, uint8_t *client_id)
521 if (!client_or_ip_port_in_list(dht->close_clientlist, LCLIENT_LIST, client_id, ip_port)) { 567 if (!client_or_ip_port_in_list(dht->close_clientlist, LCLIENT_LIST, client_id, ip_port)) {
522 if (replace_bad(dht->close_clientlist, LCLIENT_LIST, client_id, ip_port)) { 568 if (replace_bad(dht->close_clientlist, LCLIENT_LIST, client_id, ip_port)) {
523 /* If we can't replace bad nodes we try replacing good ones. */ 569 /* If we can't replace bad nodes we try replacing good ones. */
524 replace_good(dht->close_clientlist, LCLIENT_LIST, client_id, ip_port, 570 if (!replace_good(dht->close_clientlist, LCLIENT_LIST, client_id, ip_port,
525 dht->c->self_public_key); 571 dht->c->self_public_key))
526 } 572 used++;
527 } 573 } else
574 used++;
575 } else
576 used++;
528 577
529 for (i = 0; i < dht->num_friends; ++i) { 578 for (i = 0; i < dht->num_friends; ++i) {
530 if (!client_or_ip_port_in_list(dht->friends_list[i].client_list, 579 if (!client_or_ip_port_in_list(dht->friends_list[i].client_list,
@@ -533,17 +582,22 @@ void addto_lists(DHT *dht, IP_Port ip_port, uint8_t *client_id)
533 if (replace_bad(dht->friends_list[i].client_list, MAX_FRIEND_CLIENTS, 582 if (replace_bad(dht->friends_list[i].client_list, MAX_FRIEND_CLIENTS,
534 client_id, ip_port)) { 583 client_id, ip_port)) {
535 /* If we can't replace bad nodes we try replacing good ones. */ 584 /* If we can't replace bad nodes we try replacing good ones. */
536 replace_good(dht->friends_list[i].client_list, MAX_FRIEND_CLIENTS, 585 if (!replace_good(dht->friends_list[i].client_list, MAX_FRIEND_CLIENTS,
537 client_id, ip_port, dht->friends_list[i].client_id); 586 client_id, ip_port, dht->friends_list[i].client_id))
538 } 587 used++;
539 } 588 } else
589 used++;
590 } else
591 used++;
540 } 592 }
593
594 return used;
541} 595}
542 596
543/* If client_id is a friend or us, update ret_ip_port 597/* If client_id is a friend or us, update ret_ip_port
544 * nodeclient_id is the id of the node that sent us this info. 598 * nodeclient_id is the id of the node that sent us this info.
545 */ 599 */
546static void returnedip_ports(DHT *dht, IP_Port ip_port, uint8_t *client_id, uint8_t *nodeclient_id) 600static int returnedip_ports(DHT *dht, IP_Port ip_port, uint8_t *client_id, uint8_t *nodeclient_id)
547{ 601{
548 uint32_t i, j; 602 uint32_t i, j;
549 uint64_t temp_time = unix_time(); 603 uint64_t temp_time = unix_time();
@@ -565,10 +619,9 @@ static void returnedip_ports(DHT *dht, IP_Port ip_port, uint8_t *client_id, uint
565 dht->close_clientlist[i].assoc6.ret_timestamp = temp_time; 619 dht->close_clientlist[i].assoc6.ret_timestamp = temp_time;
566 } 620 }
567 621
568 return; 622 return 1;
569 } 623 }
570 } 624 }
571
572 } else { 625 } else {
573 for (i = 0; i < dht->num_friends; ++i) { 626 for (i = 0; i < dht->num_friends; ++i) {
574 if (id_equal(client_id, dht->friends_list[i].client_id)) { 627 if (id_equal(client_id, dht->friends_list[i].client_id)) {
@@ -582,13 +635,14 @@ static void returnedip_ports(DHT *dht, IP_Port ip_port, uint8_t *client_id, uint
582 dht->friends_list[i].client_list[j].assoc6.ret_timestamp = temp_time; 635 dht->friends_list[i].client_list[j].assoc6.ret_timestamp = temp_time;
583 } 636 }
584 637
585 return; 638 return 1;
586 } 639 }
587 } 640 }
588 } 641 }
589 } 642 }
590
591 } 643 }
644
645 return 0;
592} 646}
593 647
594#define NODES_ENCRYPTED_MESSAGE_LENGTH (crypto_secretbox_NONCEBYTES + sizeof(uint64_t) + sizeof(Node_format) + sizeof(Node_format) + crypto_secretbox_MACBYTES) 648#define NODES_ENCRYPTED_MESSAGE_LENGTH (crypto_secretbox_NONCEBYTES + sizeof(uint64_t) + sizeof(Node_format) + sizeof(Node_format) + crypto_secretbox_MACBYTES)
@@ -870,7 +924,16 @@ static int handle_sendnodes_core(void *object, IP_Port source, uint8_t *packet,
870 return 1; 924 return 1;
871 925
872 /* store the address the *request* was sent to */ 926 /* store the address the *request* was sent to */
873 addto_lists(dht, source, packet + 1); 927 int used = addto_lists(dht, source, packet + 1);
928
929 if (dht->assoc) {
930 IPPTs ippts;
931
932 ippts.ip_port = source;
933 ippts.timestamp = unix_time();
934
935 Assoc_add_entry(dht->assoc, packet + 1, &ippts, &source, used ? 1 : 0);
936 }
874 937
875 *num_nodes_out = num_nodes; 938 *num_nodes_out = num_nodes;
876 939
@@ -890,24 +953,30 @@ static int handle_sendnodes(void *object, IP_Port source, uint8_t *packet, uint3
890 &sendback_node)) 953 &sendback_node))
891 return 1; 954 return 1;
892 955
956
893 Node4_format *nodes4_list = (Node4_format *)(plain); 957 Node4_format *nodes4_list = (Node4_format *)(plain);
894 uint32_t i;
895 958
896 IP_Port ipp; 959 uint64_t time_now = unix_time();
897 ipp.ip.family = AF_INET; 960 IPPTs ippts;
961 ippts.ip_port.ip.family = AF_INET;
962 ippts.timestamp = time_now;
963
964 uint32_t i;
898 965
899 Node_format nodes_list[MAX_SENT_NODES]; 966 Node_format nodes_list[MAX_SENT_NODES];
900 967
901 for (i = 0; i < num_nodes; i++) 968 for (i = 0; i < num_nodes; i++)
902 if ((nodes4_list[i].ip_port.ip.uint32 != 0) && (nodes4_list[i].ip_port.ip.uint32 != (uint32_t)~0)) { 969 if ((nodes4_list[i].ip_port.ip.uint32 != 0) && (nodes4_list[i].ip_port.ip.uint32 != (uint32_t)~0)) {
903 ipp.ip.ip4.uint32 = nodes4_list[i].ip_port.ip.uint32; 970 ippts.ip_port.ip.ip4.uint32 = nodes4_list[i].ip_port.ip.uint32;
904 ipp.port = nodes4_list[i].ip_port.port; 971 ippts.ip_port.port = nodes4_list[i].ip_port.port;
905 972
906 send_ping_request(dht->ping, ipp, nodes4_list[i].client_id); 973 send_ping_request(dht->ping, ippts.ip_port, nodes4_list[i].client_id);
907 returnedip_ports(dht, ipp, nodes4_list[i].client_id, packet + 1); 974 int used = returnedip_ports(dht, ippts.ip_port, nodes4_list[i].client_id, packet + 1);
908 975
909 memcpy(nodes_list[i].client_id, nodes4_list[i].client_id, CLIENT_ID_SIZE); 976 memcpy(nodes_list[i].client_id, nodes4_list[i].client_id, CLIENT_ID_SIZE);
910 ipport_copy(&nodes_list[i].ip_port, &ipp); 977 ipport_copy(&nodes_list[i].ip_port, &ippts.ip_port);
978 if (dht->assoc)
979 Assoc_add_entry(dht->assoc, nodes4_list[i].client_id, &ippts, NULL, used ? 1 : 0);
911 } 980 }
912 981
913 send_hardening_getnode_res(dht, &sendback_node, packet + 1, nodes_list, num_nodes); 982 send_hardening_getnode_res(dht, &sendback_node, packet + 1, nodes_list, num_nodes);
@@ -928,13 +997,22 @@ static int handle_sendnodes_ipv6(void *object, IP_Port source, uint8_t *packet,
928 return 1; 997 return 1;
929 998
930 Node_format *nodes_list = (Node_format *)(plain); 999 Node_format *nodes_list = (Node_format *)(plain);
1000 uint64_t time_now = unix_time();
931 uint32_t i; 1001 uint32_t i;
932 send_hardening_getnode_res(dht, &sendback_node, packet + 1, nodes_list, num_nodes); 1002 send_hardening_getnode_res(dht, &sendback_node, packet + 1, nodes_list, num_nodes);
933 1003
934 for (i = 0; i < num_nodes; i++) 1004 for (i = 0; i < num_nodes; i++)
935 if (ipport_isset(&nodes_list[i].ip_port)) { 1005 if (ipport_isset(&nodes_list[i].ip_port)) {
936 send_ping_request(dht->ping, nodes_list[i].ip_port, nodes_list[i].client_id); 1006 send_ping_request(dht->ping, nodes_list[i].ip_port, nodes_list[i].client_id);
937 returnedip_ports(dht, nodes_list[i].ip_port, nodes_list[i].client_id, packet + 1); 1007 int used = returnedip_ports(dht, nodes_list[i].ip_port, nodes_list[i].client_id, packet + 1);
1008
1009 if (dht->assoc) {
1010 IPPTs ippts;
1011 ippts.ip_port = nodes_list[i].ip_port;
1012 ippts.timestamp = time_now;
1013
1014 Assoc_add_entry(dht->assoc, nodes_list[i].client_id, &ippts, NULL, used ? 1 : 0);
1015 }
938 } 1016 }
939 1017
940 return 0; 1018 return 0;
@@ -983,7 +1061,38 @@ int DHT_addfriend(DHT *dht, uint8_t *client_id)
983 1061
984 dht->friends_list[dht->num_friends].nat.NATping_id = ((uint64_t)random_int() << 32) + random_int(); 1062 dht->friends_list[dht->num_friends].nat.NATping_id = ((uint64_t)random_int() << 32) + random_int();
985 ++dht->num_friends; 1063 ++dht->num_friends;
986 get_bunchnodes(dht, dht->close_clientlist, LCLIENT_LIST, MAX_FRIEND_CLIENTS, client_id);/*TODO: make this better?*/ 1064
1065 if (dht->assoc) {
1066 /* get up to MAX_FRIEND_CLIENTS connectable nodes */
1067 DHT_Friend *friend = &dht->friends_list[dht->num_friends - 1];
1068
1069 Assoc_close_entries close_entries;
1070 memset(&close_entries, 0, sizeof(close_entries));
1071 close_entries.wanted_id = client_id;
1072 close_entries.count_good = MAX_FRIEND_CLIENTS / 2;
1073 close_entries.count = MAX_FRIEND_CLIENTS;
1074 close_entries.result = calloc(MAX_FRIEND_CLIENTS, sizeof(*close_entries.result));
1075
1076 uint8_t i, found = Assoc_get_close_entries(dht->assoc, &close_entries);
1077
1078 for (i = 0; i < found; i++)
1079 memcpy(&friend->client_list[i], close_entries.result[i], sizeof(*close_entries.result[i]));
1080
1081 if (found) {
1082 /* send getnodes to the "best" entry */
1083 Client_data *client = &friend->client_list[0];
1084
1085 if (ipport_isset(&client->assoc4.ip_port))
1086 getnodes(dht, client->assoc4.ip_port, client->client_id, friend->client_id, NULL);
1087
1088 if (ipport_isset(&client->assoc6.ip_port))
1089 getnodes(dht, client->assoc6.ip_port, client->client_id, friend->client_id, NULL);
1090 }
1091 }
1092
1093 /*TODO: make this better?*/
1094 get_bunchnodes(dht, dht->close_clientlist, LCLIENT_LIST, MAX_FRIEND_CLIENTS, client_id);
1095
987 return 0; 1096 return 0;
988} 1097}
989 1098
@@ -1055,10 +1164,12 @@ int DHT_getfriendip(DHT *dht, uint8_t *client_id, IP_Port *ip_port)
1055 return -1; 1164 return -1;
1056} 1165}
1057 1166
1058static void do_ping_and_sendnode_requests(DHT *dht, uint64_t *lastgetnode, uint8_t *client_id, 1167/* returns number of nodes not in kill-timeout */
1168static uint8_t do_ping_and_sendnode_requests(DHT *dht, uint64_t *lastgetnode, uint8_t *client_id,
1059 Client_data *list, uint32_t list_count) 1169 Client_data *list, uint32_t list_count)
1060{ 1170{
1061 uint32_t i; 1171 uint32_t i;
1172 uint8_t not_kill = 0;
1062 uint64_t temp_time = unix_time(); 1173 uint64_t temp_time = unix_time();
1063 1174
1064 uint32_t num_nodes = 0; 1175 uint32_t num_nodes = 0;
@@ -1073,6 +1184,8 @@ static void do_ping_and_sendnode_requests(DHT *dht, uint64_t *lastgetnode, uint8
1073 1184
1074 for (a = 0, assoc = &client->assoc6; a < 2; a++, assoc = &client->assoc4) 1185 for (a = 0, assoc = &client->assoc6; a < 2; a++, assoc = &client->assoc4)
1075 if (!is_timeout(assoc->timestamp, KILL_NODE_TIMEOUT)) { 1186 if (!is_timeout(assoc->timestamp, KILL_NODE_TIMEOUT)) {
1187 not_kill++;
1188
1076 if (is_timeout(assoc->last_pinged, PING_INTERVAL)) { 1189 if (is_timeout(assoc->last_pinged, PING_INTERVAL)) {
1077 send_ping_request(dht->ping, assoc->ip_port, client->client_id ); 1190 send_ping_request(dht->ping, assoc->ip_port, client->client_id );
1078 assoc->last_pinged = temp_time; 1191 assoc->last_pinged = temp_time;
@@ -1093,6 +1206,8 @@ static void do_ping_and_sendnode_requests(DHT *dht, uint64_t *lastgetnode, uint8
1093 client_id, NULL); 1206 client_id, NULL);
1094 *lastgetnode = temp_time; 1207 *lastgetnode = temp_time;
1095 } 1208 }
1209
1210 return not_kill;
1096} 1211}
1097 1212
1098/* Ping each client in the "friends" list every PING_INTERVAL seconds. Send a get nodes request 1213/* Ping each client in the "friends" list every PING_INTERVAL seconds. Send a get nodes request
@@ -1112,12 +1227,40 @@ static void do_DHT_friends(DHT *dht)
1112 */ 1227 */
1113static void do_Close(DHT *dht) 1228static void do_Close(DHT *dht)
1114{ 1229{
1115 do_ping_and_sendnode_requests(dht, &dht->close_lastgetnodes, dht->c->self_public_key, 1230 uint8_t not_killed = do_ping_and_sendnode_requests(dht, &dht->close_lastgetnodes, dht->c->self_public_key,
1116 dht->close_clientlist, LCLIENT_LIST); 1231 dht->close_clientlist, LCLIENT_LIST);
1232
1233 if (!not_killed) {
1234 /* all existing nodes are at least KILL_NODE_TIMEOUT,
1235 * which means we are mute, as we only send packets to
1236 * nodes NOT in KILL_NODE_TIMEOUT
1237 *
1238 * so: reset all nodes to be BAD_NODE_TIMEOUT, but not
1239 * KILL_NODE_TIMEOUT, so we at least keep trying pings */
1240 uint64_t badonly = unix_time() - BAD_NODE_TIMEOUT;
1241 size_t i, a;
1242
1243 for (i = 0; i < LCLIENT_LIST; i++) {
1244 Client_data *client = &dht->close_clientlist[i];
1245 IPPTsPng *assoc;
1246
1247 for (a = 0, assoc = &client->assoc4; a < 2; a++, assoc = &client->assoc6)
1248 if (assoc->timestamp)
1249 assoc->timestamp = badonly;
1250 }
1251 }
1117} 1252}
1118 1253
1119void DHT_bootstrap(DHT *dht, IP_Port ip_port, uint8_t *public_key) 1254void DHT_bootstrap(DHT *dht, IP_Port ip_port, uint8_t *public_key)
1120{ 1255{
1256 if (dht->assoc) {
1257 IPPTs ippts;
1258 ippts.ip_port = ip_port;
1259 ippts.timestamp = 0;
1260
1261 Assoc_add_entry(dht->assoc, public_key, &ippts, NULL, 0);
1262 }
1263
1121 getnodes(dht, ip_port, public_key, dht->c->self_public_key, NULL); 1264 getnodes(dht, ip_port, public_key, dht->c->self_public_key, NULL);
1122} 1265}
1123int DHT_bootstrap_from_address(DHT *dht, const char *address, uint8_t ipv6enabled, 1266int DHT_bootstrap_from_address(DHT *dht, const char *address, uint8_t ipv6enabled,
@@ -1191,30 +1334,25 @@ static int friend_iplist(DHT *dht, IP_Port *ip_portlist, uint16_t friend_num)
1191 int num_ipv4s = 0; 1334 int num_ipv4s = 0;
1192 IP_Port ipv6s[MAX_FRIEND_CLIENTS]; 1335 IP_Port ipv6s[MAX_FRIEND_CLIENTS];
1193 int num_ipv6s = 0; 1336 int num_ipv6s = 0;
1194 uint8_t connected;
1195 int i; 1337 int i;
1196 1338
1197 for (i = 0; i < MAX_FRIEND_CLIENTS; ++i) { 1339 for (i = 0; i < MAX_FRIEND_CLIENTS; ++i) {
1198 client = &(friend->client_list[i]); 1340 client = &(friend->client_list[i]);
1199 connected = 0;
1200 1341
1201 /* If ip is not zero and node is good. */ 1342 /* If ip is not zero and node is good. */
1202 if (ip_isset(&client->assoc4.ret_ip_port.ip) && !is_timeout(client->assoc4.ret_timestamp, BAD_NODE_TIMEOUT)) { 1343 if (ip_isset(&client->assoc4.ret_ip_port.ip) && !is_timeout(client->assoc4.ret_timestamp, BAD_NODE_TIMEOUT)) {
1203 ipv4s[num_ipv4s] = client->assoc4.ret_ip_port; 1344 ipv4s[num_ipv4s] = client->assoc4.ret_ip_port;
1204 ++num_ipv4s; 1345 ++num_ipv4s;
1205
1206 connected = 1;
1207 } 1346 }
1208 1347
1209 if (ip_isset(&client->assoc6.ret_ip_port.ip) && !is_timeout(client->assoc6.ret_timestamp, BAD_NODE_TIMEOUT)) { 1348 if (ip_isset(&client->assoc6.ret_ip_port.ip) && !is_timeout(client->assoc6.ret_timestamp, BAD_NODE_TIMEOUT)) {
1210 ipv6s[num_ipv6s] = client->assoc6.ret_ip_port; 1349 ipv6s[num_ipv6s] = client->assoc6.ret_ip_port;
1211 ++num_ipv6s; 1350 ++num_ipv6s;
1212
1213 connected = 1;
1214 } 1351 }
1215 1352
1216 if (connected && id_equal(client->client_id, friend->client_id)) 1353 if (id_equal(client->client_id, friend->client_id))
1217 return 0; /* direct connectivity */ 1354 if (!is_timeout(client->assoc6.timestamp, BAD_NODE_TIMEOUT) || !is_timeout(client->assoc4.timestamp, BAD_NODE_TIMEOUT))
1355 return 0; /* direct connectivity */
1218 } 1356 }
1219 1357
1220#ifdef FRIEND_IPLIST_PAD 1358#ifdef FRIEND_IPLIST_PAD
@@ -1498,7 +1636,7 @@ static void punch_holes(DHT *dht, IP ip, uint16_t *port_list, uint16_t numports,
1498 uint16_t firstport = port_list[0]; 1636 uint16_t firstport = port_list[0];
1499 1637
1500 for (i = 0; i < numports; ++i) { 1638 for (i = 0; i < numports; ++i) {
1501 if (firstport != port_list[0]) 1639 if (firstport != port_list[i])
1502 break; 1640 break;
1503 } 1641 }
1504 1642
@@ -1844,6 +1982,8 @@ DHT *new_DHT(Net_Crypto *c)
1844 cryptopacket_registerhandler(c, CRYPTO_PACKET_HARDENING, &handle_hardening, dht); 1982 cryptopacket_registerhandler(c, CRYPTO_PACKET_HARDENING, &handle_hardening, dht);
1845 1983
1846 new_symmetric_key(dht->secret_symmetric_key); 1984 new_symmetric_key(dht->secret_symmetric_key);
1985 dht->assoc = new_Assoc_default(dht->c->self_public_key);
1986
1847 return dht; 1987 return dht;
1848} 1988}
1849 1989
@@ -1851,14 +1991,20 @@ void do_DHT(DHT *dht)
1851{ 1991{
1852 unix_time_update(); 1992 unix_time_update();
1853 1993
1994 if (dht->last_run == unix_time()) {
1995 return;
1996 }
1997
1854 do_Close(dht); 1998 do_Close(dht);
1855 do_DHT_friends(dht); 1999 do_DHT_friends(dht);
1856 do_NAT(dht); 2000 do_NAT(dht);
1857 do_toping(dht->ping); 2001 do_toping(dht->ping);
1858 do_hardening(dht); 2002 do_hardening(dht);
2003 dht->last_run = unix_time();
1859} 2004}
1860void kill_DHT(DHT *dht) 2005void kill_DHT(DHT *dht)
1861{ 2006{
2007 kill_Assoc(dht->assoc);
1862 kill_ping(dht->ping); 2008 kill_ping(dht->ping);
1863 free(dht->friends_list); 2009 free(dht->friends_list);
1864 free(dht); 2010 free(dht);
diff --git a/toxcore/DHT.h b/toxcore/DHT.h
index f4651515..f82d9d76 100644
--- a/toxcore/DHT.h
+++ b/toxcore/DHT.h
@@ -38,6 +38,22 @@
38/* Maximum newly announced nodes to ping per TIME_TOPING seconds. */ 38/* Maximum newly announced nodes to ping per TIME_TOPING seconds. */
39#define MAX_TOPING 16 39#define MAX_TOPING 16
40 40
41/* Ping timeout in seconds */
42#define PING_TIMEOUT 3
43
44/* Ping interval in seconds for each node in our lists. */
45#define PING_INTERVAL 60
46
47/* The number of seconds for a non responsive node to become bad. */
48#define PINGS_MISSED_NODE_GOES_BAD 3
49#define PING_ROUNDTRIP 2
50#define BAD_NODE_TIMEOUT (PING_INTERVAL + PINGS_MISSED_NODE_GOES_BAD * PING_INTERVAL + PING_ROUNDTRIP)
51
52typedef struct {
53 IP_Port ip_port;
54 uint64_t timestamp;
55} IPPTs;
56
41typedef struct { 57typedef struct {
42 /* Node routes request correctly (true (1) or false/didn't check (0)) */ 58 /* Node routes request correctly (true (1) or false/didn't check (0)) */
43 uint8_t routes_requests_ok; 59 uint8_t routes_requests_ok;
@@ -113,20 +129,22 @@ typedef struct {
113typedef struct { 129typedef struct {
114 Net_Crypto *c; 130 Net_Crypto *c;
115 131
116 Client_data close_clientlist[LCLIENT_LIST]; 132 Client_data close_clientlist[LCLIENT_LIST];
117 DHT_Friend *friends_list; 133 uint64_t close_lastgetnodes;
118 uint16_t num_friends;
119 uint64_t close_lastgetnodes;
120
121 void *ping;
122 134
123 /* Note: this key should not be/is not used to transmit any sensitive materials */ 135 /* Note: this key should not be/is not used to transmit any sensitive materials */
124 uint8_t secret_symmetric_key[crypto_secretbox_KEYBYTES]; 136 uint8_t secret_symmetric_key[crypto_secretbox_KEYBYTES];
125} DHT;
126/*----------------------------------------------------------------------------------*/
127 137
138 DHT_Friend *friends_list;
139 uint16_t num_friends;
140
141 struct PING *ping;
142
143 struct Assoc *assoc;
128 144
129Client_data *DHT_get_close_list(DHT *dht); 145 uint64_t last_run;
146} DHT;
147/*----------------------------------------------------------------------------------*/
130 148
131/* Add a new friend to the friends list. 149/* Add a new friend to the friends list.
132 * client_id must be CLIENT_ID_SIZE bytes long. 150 * client_id must be CLIENT_ID_SIZE bytes long.
@@ -247,7 +265,7 @@ void kill_DHT(DHT *dht);
247 */ 265 */
248int DHT_isconnected(DHT *dht); 266int DHT_isconnected(DHT *dht);
249 267
250void addto_lists(DHT *dht, IP_Port ip_port, uint8_t *client_id); 268int addto_lists(DHT *dht, IP_Port ip_port, uint8_t *client_id);
251
252 269
253#endif 270#endif
271
diff --git a/toxcore/LAN_discovery.c b/toxcore/LAN_discovery.c
index eb0b95a1..eadec9ec 100644
--- a/toxcore/LAN_discovery.c
+++ b/toxcore/LAN_discovery.c
@@ -109,7 +109,7 @@ static uint32_t send_broadcasts(Networking_Core *net, uint16_t port, uint8_t *da
109 int i; 109 int i;
110 110
111 for (i = 0; i < broadcast_count; i++) 111 for (i = 0; i < broadcast_count; i++)
112 sendpacket(net, broadcast_ip_port[i], data, 1 + crypto_box_PUBLICKEYBYTES); 112 sendpacket(net, broadcast_ip_port[i], data, length);
113 113
114 return 1; 114 return 1;
115} 115}
@@ -176,6 +176,11 @@ int LAN_ip(IP ip)
176 && ip4.uint8[2] != 255) 176 && ip4.uint8[2] != 255)
177 return 0; 177 return 0;
178 178
179 /* RFC 6598: 100.64.0.0 to 100.127.255.255 (100.64.0.0/10)
180 * (shared address space to stack another layer of NAT) */
181 if ((ip4.uint8[0] == 100) && ((ip4.uint8[1] & 0xC0) == 0x40))
182 return 0;
183
179 } else if (ip.family == AF_INET6) { 184 } else if (ip.family == AF_INET6) {
180 185
181 /* autogenerated for each interface: FE80::* (up to FEBF::*) 186 /* autogenerated for each interface: FE80::* (up to FEBF::*)
@@ -191,6 +196,10 @@ int LAN_ip(IP ip)
191 ip4.ip4.uint32 = ip.ip6.uint32[3]; 196 ip4.ip4.uint32 = ip.ip6.uint32[3];
192 return LAN_ip(ip4); 197 return LAN_ip(ip4);
193 } 198 }
199
200 /* localhost in IPv6 (::1) */
201 if (IN6_IS_ADDR_LOOPBACK(&ip.ip6.in6_addr))
202 return 0;
194 } 203 }
195 204
196 return -1; 205 return -1;
diff --git a/toxcore/Makefile.inc b/toxcore/Makefile.inc
index 116a3e29..8208c548 100644
--- a/toxcore/Makefile.inc
+++ b/toxcore/Makefile.inc
@@ -27,6 +27,8 @@ libtoxcore_la_SOURCES = ../toxcore/DHT.h \
27 ../toxcore/util.c \ 27 ../toxcore/util.c \
28 ../toxcore/group_chats.h \ 28 ../toxcore/group_chats.h \
29 ../toxcore/group_chats.c \ 29 ../toxcore/group_chats.c \
30 ../toxcore/assoc.h \
31 ../toxcore/assoc.c \
30 ../toxcore/misc_tools.h 32 ../toxcore/misc_tools.h
31 33
32libtoxcore_la_CFLAGS = -I$(top_srcdir) \ 34libtoxcore_la_CFLAGS = -I$(top_srcdir) \
diff --git a/toxcore/Messenger.c b/toxcore/Messenger.c
index 08e3c70c..32234784 100644
--- a/toxcore/Messenger.c
+++ b/toxcore/Messenger.c
@@ -26,9 +26,11 @@
26#endif 26#endif
27 27
28#include "Messenger.h" 28#include "Messenger.h"
29#include "assoc.h"
29#include "network.h" 30#include "network.h"
30#include "util.h" 31#include "util.h"
31 32
33
32#define MIN(a,b) (((a)<(b))?(a):(b)) 34#define MIN(a,b) (((a)<(b))?(a):(b))
33 35
34 36
@@ -435,6 +437,10 @@ int setname(Messenger *m, uint8_t *name, uint16_t length)
435 for (i = 0; i < m->numfriends; ++i) 437 for (i = 0; i < m->numfriends; ++i)
436 m->friendlist[i].name_sent = 0; 438 m->friendlist[i].name_sent = 0;
437 439
440 for (i = 0; i < m->numchats; i++)
441 if (m->chats[i] != NULL)
442 set_nick(m->chats[i], name, length); /* TODO: remove this (group nicks should not be tied to the global one) */
443
438 return 0; 444 return 0;
439} 445}
440 446
@@ -701,6 +707,23 @@ int write_cryptpacket_id(Messenger *m, int friendnumber, uint8_t packet_id, uint
701 707
702/**********GROUP CHATS************/ 708/**********GROUP CHATS************/
703 709
710/* return 1 if the groupnumber is not valid.
711 * return 0 if the groupnumber is valid.
712 */
713static uint8_t groupnumber_not_valid(Messenger *m, int groupnumber)
714{
715 if ((unsigned int)groupnumber >= m->numchats)
716 return 1;
717
718 if (m->chats == NULL)
719 return 1;
720
721 if (m->chats[groupnumber] == NULL)
722 return 1;
723 return 0;
724}
725
726
704/* returns valid ip port of connected friend on success 727/* returns valid ip port of connected friend on success
705 * returns zeroed out IP_Port on failure 728 * returns zeroed out IP_Port on failure
706 */ 729 */
@@ -728,8 +751,9 @@ static int group_num(Messenger *m, uint8_t *group_public_key)
728 uint32_t i; 751 uint32_t i;
729 752
730 for (i = 0; i < m->numchats; ++i) { 753 for (i = 0; i < m->numchats; ++i) {
731 if (id_equal(m->chats[i]->self_public_key, group_public_key)) 754 if (m->chats[i] != NULL)
732 return i; 755 if (id_equal(m->chats[i]->self_public_key, group_public_key))
756 return i;
733 } 757 }
734 758
735 return -1; 759 return -1;
@@ -755,20 +779,51 @@ void m_callback_group_message(Messenger *m, void (*function)(Messenger *m, int,
755 m->group_message = function; 779 m->group_message = function;
756 m->group_message_userdata = userdata; 780 m->group_message_userdata = userdata;
757} 781}
758static void group_message_function(Group_Chat *chat, int peer_number, uint8_t *message, uint16_t length, void *userdata) 782
783/* Set callback function for peer name list changes.
784 *
785 * It gets called every time the name list changes(new peer/name, deleted peer)
786 * Function(Tox *tox, int groupnumber, void *userdata)
787 */
788void m_callback_group_namelistchange(Messenger *m, void (*function)(Messenger *m, int, int, uint8_t, void *), void *userdata)
759{ 789{
760 Messenger *m = userdata; 790 m->group_namelistchange = function;
761 uint32_t i; 791 m->group_namelistchange_userdata = userdata;
792}
762 793
794static int get_chat_num(Messenger *m, Group_Chat *chat)
795{
796 uint32_t i;
763 for (i = 0; i < m->numchats; ++i) { //TODO: remove this 797 for (i = 0; i < m->numchats; ++i) { //TODO: remove this
764 if (m->chats[i] == chat) 798 if (m->chats[i] == chat)
765 break; 799 return i;
766 } 800 }
801 return -1;
802}
803
804static void group_message_function(Group_Chat *chat, int peer_number, uint8_t *message, uint16_t length, void *userdata)
805{
806 Messenger *m = userdata;
807 int i = get_chat_num(m, chat);
808 if (i == -1)
809 return;
767 810
768 if (m->group_message) 811 if (m->group_message)
769 (*m->group_message)(m, i, peer_number, message, length, m->group_message_userdata); 812 (*m->group_message)(m, i, peer_number, message, length, m->group_message_userdata);
770} 813}
771 814
815static void group_namelistchange_function(Group_Chat *chat, int peer, uint8_t change, void *userdata)
816{
817 Messenger *m = userdata;
818 int i = get_chat_num(m, chat);
819 if (i == -1)
820 return;
821
822 if (m->group_namelistchange)
823 (*m->group_namelistchange)(m, i, peer, change, m->group_namelistchange_userdata);
824}
825
826
772/* Creates a new groupchat and puts it in the chats array. 827/* Creates a new groupchat and puts it in the chats array.
773 * 828 *
774 * return group number on success. 829 * return group number on success.
@@ -786,6 +841,9 @@ int add_groupchat(Messenger *m)
786 return -1; 841 return -1;
787 842
788 callback_groupmessage(newchat, &group_message_function, m); 843 callback_groupmessage(newchat, &group_message_function, m);
844 callback_namelistchange(newchat, &group_namelistchange_function, m);
845 /* TODO: remove this (group nicks should not be tied to the global one) */
846 set_nick(newchat, m->name, m->name_length);
789 m->chats[i] = newchat; 847 m->chats[i] = newchat;
790 return i; 848 return i;
791 } 849 }
@@ -804,6 +862,9 @@ int add_groupchat(Messenger *m)
804 862
805 m->chats = temp; 863 m->chats = temp;
806 callback_groupmessage(temp[m->numchats], &group_message_function, m); 864 callback_groupmessage(temp[m->numchats], &group_message_function, m);
865 callback_namelistchange(temp[m->numchats], &group_namelistchange_function, m);
866 /* TODO: remove this (group nicks should not be tied to the global one) */
867 set_nick(temp[m->numchats], m->name, m->name_length);
807 ++m->numchats; 868 ++m->numchats;
808 return (m->numchats - 1); 869 return (m->numchats - 1);
809} 870}
@@ -953,6 +1014,7 @@ int join_groupchat(Messenger *m, int friendnumber, uint8_t *friend_group_public_
953 return -1; 1014 return -1;
954} 1015}
955 1016
1017
956/* send a group message 1018/* send a group message
957 * return 0 on success 1019 * return 0 on success
958 * return -1 on failure 1020 * return -1 on failure
@@ -960,13 +1022,7 @@ int join_groupchat(Messenger *m, int friendnumber, uint8_t *friend_group_public_
960 1022
961int group_message_send(Messenger *m, int groupnumber, uint8_t *message, uint32_t length) 1023int group_message_send(Messenger *m, int groupnumber, uint8_t *message, uint32_t length)
962{ 1024{
963 if ((unsigned int)groupnumber >= m->numchats) 1025 if (groupnumber_not_valid(m, groupnumber))
964 return -1;
965
966 if (m->chats == NULL)
967 return -1;
968
969 if (m->chats[groupnumber] == NULL)
970 return -1; 1026 return -1;
971 1027
972 if (group_sendmessage(m->chats[groupnumber], message, length) > 0) 1028 if (group_sendmessage(m->chats[groupnumber], message, length) > 0)
@@ -975,6 +1031,33 @@ int group_message_send(Messenger *m, int groupnumber, uint8_t *message, uint32_t
975 return -1; 1031 return -1;
976} 1032}
977 1033
1034/* Return the number of peers in the group chat on success.
1035 * return -1 on failure
1036 */
1037int group_number_peers(Messenger *m, int groupnumber)
1038{
1039 if (groupnumber_not_valid(m, groupnumber))
1040 return -1;
1041
1042 return group_numpeers(m->chats[groupnumber]);
1043}
1044
1045/* List all the peers in the group chat.
1046 *
1047 * Copies the names of the peers to the name[length][MAX_NICK_BYTES] array.
1048 *
1049 * returns the number of peers on success.
1050 *
1051 * return -1 on failure.
1052 */
1053int group_names(Messenger *m, int groupnumber, uint8_t names[][MAX_NICK_BYTES], uint16_t length)
1054{
1055 if (groupnumber_not_valid(m, groupnumber))
1056 return -1;
1057
1058 return group_client_names(m->chats[groupnumber], names, length);
1059}
1060
978static int handle_group(void *object, IP_Port source, uint8_t *packet, uint32_t length) 1061static int handle_group(void *object, IP_Port source, uint8_t *packet, uint32_t length)
979{ 1062{
980 Messenger *m = object; 1063 Messenger *m = object;
@@ -1078,7 +1161,7 @@ int file_sendrequest(Messenger *m, int friendnumber, uint8_t filenumber, uint64_
1078int new_filesender(Messenger *m, int friendnumber, uint64_t filesize, uint8_t *filename, uint16_t filename_length) 1161int new_filesender(Messenger *m, int friendnumber, uint64_t filesize, uint8_t *filename, uint16_t filename_length)
1079{ 1162{
1080 if (friend_not_valid(m, friendnumber)) 1163 if (friend_not_valid(m, friendnumber))
1081 return 0; 1164 return -1;
1082 1165
1083 uint32_t i; 1166 uint32_t i;
1084 1167
@@ -1102,28 +1185,28 @@ int new_filesender(Messenger *m, int friendnumber, uint64_t filesize, uint8_t *f
1102/* Send a file control request. 1185/* Send a file control request.
1103 * send_receive is 0 if we want the control packet to target a sending file, 1 if it targets a receiving file. 1186 * send_receive is 0 if we want the control packet to target a sending file, 1 if it targets a receiving file.
1104 * 1187 *
1105 * return 1 on success 1188 * return 0 on success
1106 * return 0 on failure 1189 * return -1 on failure
1107 */ 1190 */
1108int file_control(Messenger *m, int friendnumber, uint8_t send_receive, uint8_t filenumber, uint8_t message_id, 1191int file_control(Messenger *m, int friendnumber, uint8_t send_receive, uint8_t filenumber, uint8_t message_id,
1109 uint8_t *data, uint16_t length) 1192 uint8_t *data, uint16_t length)
1110{ 1193{
1111 if (length > MAX_DATA_SIZE - 3) 1194 if (length > MAX_DATA_SIZE - 3)
1112 return 0; 1195 return -1;
1113 1196
1114 if (friend_not_valid(m, friendnumber)) 1197 if (friend_not_valid(m, friendnumber))
1115 return 0; 1198 return -1;
1116 1199
1117 if (send_receive == 1) { 1200 if (send_receive == 1) {
1118 if (m->friendlist[friendnumber].file_receiving[filenumber].status == FILESTATUS_NONE) 1201 if (m->friendlist[friendnumber].file_receiving[filenumber].status == FILESTATUS_NONE)
1119 return 0; 1202 return -1;
1120 } else { 1203 } else {
1121 if (m->friendlist[friendnumber].file_sending[filenumber].status == FILESTATUS_NONE) 1204 if (m->friendlist[friendnumber].file_sending[filenumber].status == FILESTATUS_NONE)
1122 return 0; 1205 return -1;
1123 } 1206 }
1124 1207
1125 if (send_receive > 1) 1208 if (send_receive > 1)
1126 return 0; 1209 return -1;
1127 1210
1128 uint8_t packet[MAX_DATA_SIZE]; 1211 uint8_t packet[MAX_DATA_SIZE];
1129 packet[0] = send_receive; 1212 packet[0] = send_receive;
@@ -1133,7 +1216,7 @@ int file_control(Messenger *m, int friendnumber, uint8_t send_receive, uint8_t f
1133 1216
1134 if (message_id == FILECONTROL_RESUME_BROKEN) { 1217 if (message_id == FILECONTROL_RESUME_BROKEN) {
1135 if (length != sizeof(uint64_t)) 1218 if (length != sizeof(uint64_t))
1136 return 0; 1219 return -1;
1137 1220
1138 uint8_t remaining[sizeof(uint64_t)]; 1221 uint8_t remaining[sizeof(uint64_t)];
1139 memcpy(remaining, data, sizeof(uint64_t)); 1222 memcpy(remaining, data, sizeof(uint64_t));
@@ -1181,32 +1264,32 @@ int file_control(Messenger *m, int friendnumber, uint8_t send_receive, uint8_t f
1181 break; 1264 break;
1182 } 1265 }
1183 1266
1184 return 1;
1185 } else {
1186 return 0; 1267 return 0;
1268 } else {
1269 return -1;
1187 } 1270 }
1188} 1271}
1189 1272
1190#define MIN_SLOTS_FREE 4 1273#define MIN_SLOTS_FREE 4
1191/* Send file data. 1274/* Send file data.
1192 * 1275 *
1193 * return 1 on success 1276 * return 0 on success
1194 * return 0 on failure 1277 * return -1 on failure
1195 */ 1278 */
1196int file_data(Messenger *m, int friendnumber, uint8_t filenumber, uint8_t *data, uint16_t length) 1279int file_data(Messenger *m, int friendnumber, uint8_t filenumber, uint8_t *data, uint16_t length)
1197{ 1280{
1198 if (length > MAX_DATA_SIZE - 1) 1281 if (length > MAX_DATA_SIZE - 1)
1199 return 0; 1282 return -1;
1200 1283
1201 if (friend_not_valid(m, friendnumber)) 1284 if (friend_not_valid(m, friendnumber))
1202 return 0; 1285 return -1;
1203 1286
1204 if (m->friendlist[friendnumber].file_sending[filenumber].status != FILESTATUS_TRANSFERRING) 1287 if (m->friendlist[friendnumber].file_sending[filenumber].status != FILESTATUS_TRANSFERRING)
1205 return 0; 1288 return -1;
1206 1289
1207 /* Prevent file sending from filling up the entire buffer preventing messages from being sent. */ 1290 /* Prevent file sending from filling up the entire buffer preventing messages from being sent. */
1208 if (crypto_num_free_sendqueue_slots(m->net_crypto, m->friendlist[friendnumber].crypt_connection_id) < MIN_SLOTS_FREE) 1291 if (crypto_num_free_sendqueue_slots(m->net_crypto, m->friendlist[friendnumber].crypt_connection_id) < MIN_SLOTS_FREE)
1209 return 0; 1292 return -1;
1210 1293
1211 uint8_t packet[MAX_DATA_SIZE]; 1294 uint8_t packet[MAX_DATA_SIZE];
1212 packet[0] = filenumber; 1295 packet[0] = filenumber;
@@ -1214,10 +1297,10 @@ int file_data(Messenger *m, int friendnumber, uint8_t filenumber, uint8_t *data,
1214 1297
1215 if (write_cryptpacket_id(m, friendnumber, PACKET_ID_FILE_DATA, packet, length + 1)) { 1298 if (write_cryptpacket_id(m, friendnumber, PACKET_ID_FILE_DATA, packet, length + 1)) {
1216 m->friendlist[friendnumber].file_sending[filenumber].transferred += length; 1299 m->friendlist[friendnumber].file_sending[filenumber].transferred += length;
1217 return 1; 1300 return 0;
1218 } 1301 }
1219 1302
1220 return 0; 1303 return -1;
1221 1304
1222} 1305}
1223 1306
@@ -1371,6 +1454,17 @@ int m_msi_packet(Messenger *m, int friendnumber, uint8_t *data, uint16_t length)
1371 return write_cryptpacket_id(m, friendnumber, PACKET_ID_MSI, data, length); 1454 return write_cryptpacket_id(m, friendnumber, PACKET_ID_MSI, data, length);
1372} 1455}
1373 1456
1457/* Function to filter out some friend requests*/
1458static int friend_already_added(uint8_t *client_id, void *data)
1459{
1460 Messenger *m = data;
1461
1462 if (getfriend_id(m, client_id) == -1)
1463 return 0;
1464
1465 return -1;
1466}
1467
1374/* Send a LAN discovery packet every LAN_DISCOVERY_INTERVAL seconds. */ 1468/* Send a LAN discovery packet every LAN_DISCOVERY_INTERVAL seconds. */
1375static void LANdiscovery(Messenger *m) 1469static void LANdiscovery(Messenger *m)
1376{ 1470{
@@ -1420,6 +1514,8 @@ Messenger *new_messenger(uint8_t ipv6enabled)
1420 friendreq_init(&(m->fr), m->net_crypto); 1514 friendreq_init(&(m->fr), m->net_crypto);
1421 LANdiscovery_init(m->dht); 1515 LANdiscovery_init(m->dht);
1422 set_nospam(&(m->fr), random_int()); 1516 set_nospam(&(m->fr), random_int());
1517 set_filter_function(&(m->fr), &friend_already_added, m);
1518
1423 networking_registerhandler(m->net, NET_PACKET_GROUP_CHATS, &handle_group, m); 1519 networking_registerhandler(m->net, NET_PACKET_GROUP_CHATS, &handle_group, m);
1424 1520
1425 return m; 1521 return m;
@@ -1431,6 +1527,10 @@ void kill_messenger(Messenger *m)
1431 /* FIXME TODO: ideally cleanupMessenger will mirror initMessenger. 1527 /* FIXME TODO: ideally cleanupMessenger will mirror initMessenger.
1432 * This requires the other modules to expose cleanup functions. 1528 * This requires the other modules to expose cleanup functions.
1433 */ 1529 */
1530 uint32_t i, numchats = m->numchats;
1531 for (i = 0; i < numchats; ++i)
1532 del_groupchat(m, i);
1533
1434 kill_DHT(m->dht); 1534 kill_DHT(m->dht);
1435 kill_net_crypto(m->net_crypto); 1535 kill_net_crypto(m->net_crypto);
1436 kill_networking(m->net); 1536 kill_networking(m->net);
@@ -1438,6 +1538,24 @@ void kill_messenger(Messenger *m)
1438 free(m); 1538 free(m);
1439} 1539}
1440 1540
1541/* Check for and handle a timed-out friend request. If the request has
1542 * timed-out then the friend status is set back to FRIEND_ADDED.
1543 * i: friendlist index of the timed-out friend
1544 * t: time
1545 */
1546static void check_friend_request_timed_out(Messenger *m, uint32_t i, uint64_t t)
1547{
1548 Friend *f = &m->friendlist[i];
1549
1550 if (f->friendrequest_lastsent + f->friendrequest_timeout < t) {
1551 set_friend_status(m, i, FRIEND_ADDED);
1552 /* Double the default timeout everytime if friendrequest is assumed
1553 * to have been sent unsuccessfully.
1554 */
1555 f->friendrequest_timeout *= 2;
1556 }
1557}
1558
1441/* TODO: Make this function not suck. */ 1559/* TODO: Make this function not suck. */
1442void do_friends(Messenger *m) 1560void do_friends(Messenger *m)
1443{ 1561{
@@ -1465,13 +1583,7 @@ void do_friends(Messenger *m)
1465 /* If we didn't connect to friend after successfully sending him a friend request the request is deemed 1583 /* If we didn't connect to friend after successfully sending him a friend request the request is deemed
1466 * unsuccessful so we set the status back to FRIEND_ADDED and try again. 1584 * unsuccessful so we set the status back to FRIEND_ADDED and try again.
1467 */ 1585 */
1468 if (m->friendlist[i].friendrequest_lastsent + m->friendlist[i].friendrequest_timeout < temp_time) { 1586 check_friend_request_timed_out(m, i, temp_time);
1469 set_friend_status(m, i, FRIEND_ADDED);
1470 /* Double the default timeout everytime if friendrequest is assumed to have been
1471 * sent unsuccessfully.
1472 */
1473 m->friendlist[i].friendrequest_timeout *= 2;
1474 }
1475 } 1587 }
1476 1588
1477 IP_Port friendip; 1589 IP_Port friendip;
@@ -1539,12 +1651,15 @@ void do_friends(Messenger *m)
1539 if (data_length >= MAX_NAME_LENGTH || data_length == 0) 1651 if (data_length >= MAX_NAME_LENGTH || data_length == 0)
1540 break; 1652 break;
1541 1653
1542 memcpy(m->friendlist[i].name, data, data_length); 1654 /* Make sure the NULL terminator is present. */
1543 m->friendlist[i].name_length = data_length; 1655 data[data_length - 1] = 0;
1544 m->friendlist[i].name[data_length - 1] = 0; /* Make sure the NULL terminator is present. */
1545 1656
1657 /* inform of namechange before we overwrite the old name */
1546 if (m->friend_namechange) 1658 if (m->friend_namechange)
1547 m->friend_namechange(m, i, m->friendlist[i].name, data_length, m->friend_namechange_userdata); 1659 m->friend_namechange(m, i, data, data_length, m->friend_namechange_userdata);
1660
1661 memcpy(m->friendlist[i].name, data, data_length);
1662 m->friendlist[i].name_length = data_length;
1548 1663
1549 break; 1664 break;
1550 } 1665 }
@@ -1658,7 +1773,7 @@ void do_friends(Messenger *m)
1658 break; 1773 break;
1659 1774
1660 group_newpeer(m->chats[groupnum], data + crypto_box_PUBLICKEYBYTES); 1775 group_newpeer(m->chats[groupnum], data + crypto_box_PUBLICKEYBYTES);
1661 1776 chat_bootstrap(m->chats[groupnum], get_friend_ipport(m, i), data + crypto_box_PUBLICKEYBYTES);
1662 break; 1777 break;
1663 } 1778 }
1664 1779
@@ -1808,6 +1923,18 @@ void do_messenger(Messenger *m)
1808 1923
1809 if (unix_time() > lastdump + DUMPING_CLIENTS_FRIENDS_EVERY_N_SECONDS) { 1924 if (unix_time() > lastdump + DUMPING_CLIENTS_FRIENDS_EVERY_N_SECONDS) {
1810 loglog(" = = = = = = = = \n"); 1925 loglog(" = = = = = = = = \n");
1926 Assoc_status(m->dht->assoc);
1927
1928 if (m->numchats > 0) {
1929 size_t c;
1930
1931 for (c = 0; c < m->numchats; c++) {
1932 loglog("---------------- \n");
1933 Assoc_status(m->chats[c]->assoc);
1934 }
1935 }
1936
1937 loglog(" = = = = = = = = \n");
1811 1938
1812 lastdump = unix_time(); 1939 lastdump = unix_time();
1813 uint32_t client, last_pinged; 1940 uint32_t client, last_pinged;
@@ -1833,7 +1960,30 @@ void do_messenger(Messenger *m)
1833 1960
1834 loglog(" = = = = = = = = \n"); 1961 loglog(" = = = = = = = = \n");
1835 1962
1836 uint32_t num_friends = MIN(m->numfriends, m->dht->num_friends); 1963 uint32_t friend, dhtfriend;
1964
1965 /* dht contains additional "friends" (requests) */
1966 uint32_t num_dhtfriends = m->dht->num_friends;
1967 int32_t m2dht[num_dhtfriends];
1968 int32_t dht2m[num_dhtfriends];
1969
1970 for (friend = 0; friend < num_dhtfriends; friend++) {
1971 m2dht[friend] = -1;
1972 dht2m[friend] = -1;
1973
1974 if (friend >= m->numfriends)
1975 continue;
1976
1977 for (dhtfriend = 0; dhtfriend < m->dht->num_friends; dhtfriend++)
1978 if (id_equal(m->friendlist[friend].client_id, m->dht->friends_list[dhtfriend].client_id)) {
1979 m2dht[friend] = dhtfriend;
1980 break;
1981 }
1982 }
1983
1984 for (friend = 0; friend < num_dhtfriends; friend++)
1985 if (m2dht[friend] >= 0)
1986 dht2m[m2dht[friend]] = friend;
1837 1987
1838 if (m->numfriends != m->dht->num_friends) { 1988 if (m->numfriends != m->dht->num_friends) {
1839 sprintf(logbuffer, "Friend num in DHT %u != friend num in msger %u\n", 1989 sprintf(logbuffer, "Friend num in DHT %u != friend num in msger %u\n",
@@ -1841,33 +1991,33 @@ void do_messenger(Messenger *m)
1841 loglog(logbuffer); 1991 loglog(logbuffer);
1842 } 1992 }
1843 1993
1844 uint32_t friend, ping_lastrecv; 1994 uint32_t ping_lastrecv;
1845 1995 Friend *msgfptr;
1846 for (friend = 0; friend < num_friends; friend++) { 1996 DHT_Friend *dhtfptr;
1847 Friend *msgfptr = &m->friendlist[friend];
1848 DHT_Friend *dhtfptr = &m->dht->friends_list[friend];
1849 1997
1850 if (memcmp(msgfptr->client_id, dhtfptr->client_id, CLIENT_ID_SIZE)) { 1998 for (friend = 0; friend < num_dhtfriends; friend++) {
1851 if (sizeof(logbuffer) > 2 * CLIENT_ID_SIZE + 64) { 1999 if (dht2m[friend] >= 0)
1852 sprintf(logbuffer, "F[%2u] ID(m) %s != ID(d) ", friend, 2000 msgfptr = &m->friendlist[dht2m[friend]];
1853 ID2String(msgfptr->client_id)); 2001 else
1854 strcat(logbuffer + strlen(logbuffer), ID2String(dhtfptr->client_id)); 2002 msgfptr = NULL;
1855 strcat(logbuffer + strlen(logbuffer), "\n");
1856 } else
1857 sprintf(logbuffer, "F[%2u] ID(m) != ID(d) ", friend);
1858 2003
1859 loglog(logbuffer); 2004 dhtfptr = &m->dht->friends_list[friend];
1860 }
1861 2005
1862 ping_lastrecv = lastdump - msgfptr->ping_lastrecv; 2006 if (msgfptr) {
2007 ping_lastrecv = lastdump - msgfptr->ping_lastrecv;
1863 2008
1864 if (ping_lastrecv > 999) 2009 if (ping_lastrecv > 999)
1865 ping_lastrecv = 999; 2010 ping_lastrecv = 999;
1866 2011
1867 snprintf(logbuffer, sizeof(logbuffer), "F[%2u] <%s> %02u [%03u] %s\n", 2012 snprintf(logbuffer, sizeof(logbuffer), "F[%2u:%2u] <%s> %02i [%03u] %s\n",
1868 friend, msgfptr->name, msgfptr->crypt_connection_id, 2013 dht2m[friend], friend, msgfptr->name, msgfptr->crypt_connection_id,
1869 ping_lastrecv, ID2String(msgfptr->client_id)); 2014 ping_lastrecv, ID2String(msgfptr->client_id));
1870 loglog(logbuffer); 2015 loglog(logbuffer);
2016 } else {
2017 snprintf(logbuffer, sizeof(logbuffer), "F[--:%2u] %s\n",
2018 friend, ID2String(dhtfptr->client_id));
2019 loglog(logbuffer);
2020 }
1871 2021
1872 for (client = 0; client < MAX_FRIEND_CLIENTS; client++) { 2022 for (client = 0; client < MAX_FRIEND_CLIENTS; client++) {
1873 Client_data *cptr = &dhtfptr->client_list[client]; 2023 Client_data *cptr = &dhtfptr->client_list[client];
@@ -1995,6 +2145,9 @@ static int messenger_load_state_callback(void *outer, uint8_t *data, uint32_t le
1995 if (length == crypto_box_PUBLICKEYBYTES + crypto_box_SECRETKEYBYTES + sizeof(uint32_t)) { 2145 if (length == crypto_box_PUBLICKEYBYTES + crypto_box_SECRETKEYBYTES + sizeof(uint32_t)) {
1996 set_nospam(&(m->fr), *(uint32_t *)data); 2146 set_nospam(&(m->fr), *(uint32_t *)data);
1997 load_keys(m->net_crypto, &data[sizeof(uint32_t)]); 2147 load_keys(m->net_crypto, &data[sizeof(uint32_t)]);
2148
2149 if (m->dht->assoc)
2150 Assoc_self_client_id_changed(m->dht->assoc, m->net_crypto->self_public_key);
1998 } else 2151 } else
1999 return -1; /* critical */ 2152 return -1; /* critical */
2000 2153
@@ -2100,12 +2253,12 @@ uint32_t copy_friendlist(Messenger *m, int *out_list, uint32_t list_size)
2100 uint32_t ret = 0; 2253 uint32_t ret = 0;
2101 2254
2102 for (i = 0; i < m->numfriends; i++) { 2255 for (i = 0; i < m->numfriends; i++) {
2103 if (i >= list_size) { 2256 if (ret >= list_size) {
2104 break; /* Abandon ship */ 2257 break; /* Abandon ship */
2105 } 2258 }
2106 2259
2107 if (m->friendlist[i].status > 0) { 2260 if (m->friendlist[i].status > 0) {
2108 out_list[i] = i; 2261 out_list[ret] = i;
2109 ret++; 2262 ret++;
2110 } 2263 }
2111 } 2264 }
@@ -2146,3 +2299,51 @@ int get_friendlist(Messenger *m, int **out_list, uint32_t *out_list_length)
2146 return 0; 2299 return 0;
2147} 2300}
2148 2301
2302/* Return the number of chats in the instance m.
2303 * You should use this to determine how much memory to allocate
2304 * for copy_chatlist. */
2305uint32_t count_chatlist(Messenger *m)
2306{
2307 uint32_t ret = 0;
2308 uint32_t i;
2309
2310 for (i = 0; i < m->numchats; i++) {
2311 if (m->chats[i]) {
2312 ret++;
2313 }
2314 }
2315
2316 return ret;
2317}
2318
2319/* Copy a list of valid chat IDs into the array out_list.
2320 * If out_list is NULL, returns 0.
2321 * Otherwise, returns the number of elements copied.
2322 * If the array was too small, the contents
2323 * of out_list will be truncated to list_size. */
2324uint32_t copy_chatlist(Messenger *m, int *out_list, uint32_t list_size)
2325{
2326 if (!out_list)
2327 return 0;
2328
2329 if (m->numchats == 0) {
2330 return 0;
2331 }
2332
2333 uint32_t i;
2334 uint32_t ret = 0;
2335
2336 for (i = 0; i < m->numchats; i++) {
2337 if (ret >= list_size) {
2338 break; /* Abandon ship */
2339 }
2340
2341 if (m->chats[i]) {
2342 out_list[ret] = i;
2343 ret++;
2344 }
2345 }
2346
2347 return ret;
2348}
2349
diff --git a/toxcore/Messenger.h b/toxcore/Messenger.h
index 10ac0eae..6fc23db4 100644
--- a/toxcore/Messenger.h
+++ b/toxcore/Messenger.h
@@ -198,6 +198,8 @@ typedef struct Messenger {
198 void *group_invite_userdata; 198 void *group_invite_userdata;
199 void (*group_message)(struct Messenger *m, int, int, uint8_t *, uint16_t, void *); 199 void (*group_message)(struct Messenger *m, int, int, uint8_t *, uint16_t, void *);
200 void *group_message_userdata; 200 void *group_message_userdata;
201 void (*group_namelistchange)(struct Messenger *m, int, int, uint8_t, void *);
202 void *group_namelistchange_userdata;
201 203
202 void (*file_sendrequest)(struct Messenger *m, int, uint8_t, uint64_t, uint8_t *, uint16_t, void *); 204 void (*file_sendrequest)(struct Messenger *m, int, uint8_t, uint64_t, uint8_t *, uint16_t, void *);
203 void *file_sendrequest_userdata; 205 void *file_sendrequest_userdata;
@@ -455,6 +457,13 @@ void m_callback_group_invite(Messenger *m, void (*function)(Messenger *m, int, u
455void m_callback_group_message(Messenger *m, void (*function)(Messenger *m, int, int, uint8_t *, uint16_t, void *), 457void m_callback_group_message(Messenger *m, void (*function)(Messenger *m, int, int, uint8_t *, uint16_t, void *),
456 void *userdata); 458 void *userdata);
457 459
460/* Set callback function for peer name list changes.
461 *
462 * It gets called every time the name list changes(new peer/name, deleted peer)
463 * Function(Tox *tox, int groupnumber, void *userdata)
464 */
465void m_callback_group_namelistchange(Messenger *m, void (*function)(Messenger *m, int, int, uint8_t, void *), void *userdata);
466
458/* Creates a new groupchat and puts it in the chats array. 467/* Creates a new groupchat and puts it in the chats array.
459 * 468 *
460 * return group number on success. 469 * return group number on success.
@@ -497,6 +506,21 @@ int join_groupchat(Messenger *m, int friendnumber, uint8_t *friend_group_public_
497 506
498int group_message_send(Messenger *m, int groupnumber, uint8_t *message, uint32_t length); 507int group_message_send(Messenger *m, int groupnumber, uint8_t *message, uint32_t length);
499 508
509/* Return the number of peers in the group chat on success.
510 * return -1 on failure
511 */
512int group_number_peers(Messenger *m, int groupnumber);
513
514/* List all the peers in the group chat.
515 *
516 * Copies the names of the peers to the name[length][MAX_NICK_BYTES] array.
517 *
518 * returns the number of peers on success.
519 *
520 * return -1 on failure.
521 */
522int group_names(Messenger *m, int groupnumber, uint8_t names[][MAX_NICK_BYTES], uint16_t length);
523
500/****************FILE SENDING*****************/ 524/****************FILE SENDING*****************/
501 525
502 526
@@ -633,5 +657,17 @@ uint32_t copy_friendlist(Messenger *m, int *out_list, uint32_t list_size);
633 */ 657 */
634int get_friendlist(Messenger *m, int **out_list, uint32_t *out_list_length); 658int get_friendlist(Messenger *m, int **out_list, uint32_t *out_list_length);
635 659
660/* Return the number of chats in the instance m.
661 * You should use this to determine how much memory to allocate
662 * for copy_chatlist. */
663uint32_t count_chatlist(Messenger *m);
664
665/* Copy a list of valid chat IDs into the array out_list.
666 * If out_list is NULL, returns 0.
667 * Otherwise, returns the number of elements copied.
668 * If the array was too small, the contents
669 * of out_list will be truncated to list_size. */
670uint32_t copy_chatlist(Messenger *m, int *out_list, uint32_t list_size);
671
636#endif 672#endif
637 673
diff --git a/toxcore/assoc.c b/toxcore/assoc.c
new file mode 100644
index 00000000..4dc91671
--- /dev/null
+++ b/toxcore/assoc.c
@@ -0,0 +1,926 @@
1
2#ifdef HAVE_CONFIG_H
3#include "config.h"
4#endif
5
6#include "DHT.h"
7#include "assoc.h"
8#include "ping.h"
9
10#include "LAN_discovery.h"
11
12#include <assert.h>
13#include "util.h"
14
15/*
16 * BASIC OVERVIEW:
17 *
18 * Hash: The client_id is hashed with a local hash function.
19 * Hashes are used in multiple places for searching.
20 * Bucket: The first n bits of the client_id are used to
21 * select a bucket. This speeds up sorting, but the more
22 * important reason is to enforce a spread in the space of
23 * client_ids available.
24 *
25 *
26 * Candidates:
27 *
28 * Candidates are kept in buckets of hash tables. The hash
29 * function is calculated from the client_id. Up to
30 * HASH_COLLIDE_COUNT alternative positions are tried if
31 * the inital position is already used by a different entry.
32 * The collision function is multiplicative, not additive.
33 *
34 * A new candidate can bump an existing candidate, if it is
35 * more "desirable": Seen beats Heard.
36 */
37
38/* candidates: alternative places for the same hash value */
39#define HASH_COLLIDE_COUNT 5
40
41/* bucket size shall be co-prime to this */
42#define HASH_COLLIDE_PRIME 101
43
44/* candidates: bump entries: timeout values for seen/heard to be considered of value */
45#define CANDIDATES_SEEN_TIMEOUT 1800
46#define CANDIDATES_HEARD_TIMEOUT 600
47
48/* distance/index: index size & access mask */
49#define DISTANCE_INDEX_INDEX_BITS (64 - DISTANCE_INDEX_DISTANCE_BITS)
50#define DISTANCE_INDEX_INDEX_MASK ((1 << DISTANCE_INDEX_INDEX_BITS) - 1)
51
52/* types to stay consistent */
53typedef uint16_t bucket_t;
54typedef uint32_t hash_t;
55typedef uint16_t usecnt_t;
56
57/* abbreviations ... */
58typedef Assoc_distance_relative_callback dist_rel_cb;
59typedef Assoc_distance_absolute_callback dist_abs_cb;
60
61/*
62 * Client_data wrapped with additional data
63 */
64typedef struct Client_entry {
65 hash_t hash;
66
67 /* shortcuts & rumors: timers and data */
68 uint64_t used_at;
69 uint64_t seen_at;
70 uint64_t heard_at;
71
72 uint16_t seen_family;
73 uint16_t heard_family;
74
75 IP_Port assoc_heard4;
76 IP_Port assoc_heard6;
77
78 Client_data client;
79} Client_entry;
80
81typedef struct candidates_bucket {
82 Client_entry *list; /* hashed list */
83} candidates_bucket;
84
85struct Assoc {
86 hash_t self_hash; /* hash of self_client_id */
87 uint8_t self_client_id[CLIENT_ID_SIZE]; /* don't store entries for this */
88
89 /* association centralization: clients not in use */
90 size_t candidates_bucket_bits;
91 size_t candidates_bucket_count;
92 size_t candidates_bucket_size;
93 candidates_bucket *candidates;
94};
95
96/*****************************************************************************/
97/* HELPER FUNCTIONS */
98/*****************************************************************************/
99
100/* the complete distance would be CLIENT_ID_SIZE long...
101 * returns DISTANCE_INDEX_DISTANCE_BITS valid bits */
102static uint64_t id_distance(Assoc *assoc, void *callback_data, uint8_t *id_ref, uint8_t *id_test)
103{
104 /* with BIG_ENDIAN, this would be a one-liner... */
105 uint64_t retval = 0;
106
107 uint8_t pos = 0, bits = DISTANCE_INDEX_DISTANCE_BITS;
108
109 while (bits > 8) {
110 uint8_t distance = abs((int8_t)id_ref[pos] ^ (int8_t)id_test[pos]);
111 retval = (retval << 8) | distance;
112 bits -= 8;
113 pos++;
114 }
115
116 return (retval << bits) | ((id_ref[pos] ^ id_test[pos]) >> (8 - bits));
117}
118
119/* qsort() callback for a sorting by id_distance() values */
120static int dist_index_comp(const void *a, const void *b)
121{
122 const uint64_t *_a = a;
123 const uint64_t *_b = b;
124
125 if (*_a < *_b)
126 return -1;
127
128 if (*_a > *_b)
129 return 1;
130
131 return 0;
132}
133
134/* get actual entry to a distance_index */
135static Client_entry *dist_index_entry(Assoc *assoc, uint64_t dist_ind)
136{
137 if ((dist_ind & DISTANCE_INDEX_INDEX_MASK) == DISTANCE_INDEX_INDEX_MASK)
138 return NULL;
139
140 size_t total = assoc->candidates_bucket_count * assoc->candidates_bucket_size;
141 uint32_t index = dist_ind & DISTANCE_INDEX_INDEX_MASK;
142
143 if (index < total) {
144 bucket_t b_id = index / assoc->candidates_bucket_size;
145 candidates_bucket *cnd_bckt = &assoc->candidates[b_id];
146 size_t b_ix = index % assoc->candidates_bucket_size;
147 Client_entry *entry = &cnd_bckt->list[b_ix];
148
149 if (entry->hash)
150 return entry;
151 }
152
153 return NULL;
154}
155
156/* get actual entry's client_id to a distance_index */
157static uint8_t *dist_index_id(Assoc *assoc, uint64_t dist_ind)
158{
159 Client_entry *entry = dist_index_entry(assoc, dist_ind);
160
161 if (entry)
162 return entry->client.client_id;
163
164 return NULL;
165}
166
167/* sorts first .. last, i.e. last is included */
168static void dist_index_bubble(Assoc *assoc, uint64_t *dist_list, size_t first, size_t last, uint8_t *id,
169 void *custom_data, Assoc_distance_relative_callback dist_rel_func)
170{
171 size_t i, k;
172
173 for (i = first; i <= last; i++) {
174 uint8_t *id1 = dist_index_id(assoc, dist_list[i]);
175
176 for (k = i + 1; k <= last; k++) {
177 uint8_t *id2 = dist_index_id(assoc, dist_list[k]);
178
179 if (id1 && id2)
180 if (dist_rel_func(assoc, custom_data, id, id1, id2) == 2) {
181 uint64_t swap = dist_list[i];
182 dist_list[i] = dist_list[k];
183 dist_list[k] = swap;
184 }
185 }
186 }
187}
188
189/* TODO: Check that there isn't a function like this elsewhere hidden.
190 * E.g. the one which creates a handshake_id isn't usable for this, it must
191 * always map the same ID to the same hash.
192 *
193 * Result is NOT MAPPED to CANDIDATES_TO_KEEP range, i.e. map before using
194 * it for list access. */
195static hash_t id_hash(Assoc *assoc, uint8_t *id)
196{
197 uint32_t i, res = 0x19a64e82;
198
199 for (i = 0; i < CLIENT_ID_SIZE; i++)
200 res = ((res << 1) ^ id[i]) + (res >> 31);
201
202 /* can't have zero as hash, a) marks an unused spot,
203 * b) collision function is multiplicative */
204 if (!(res % assoc->candidates_bucket_size))
205 res++;
206
207 return res;
208}
209
210/* up to HASH_COLLIDE_COUNT calls to different spots,
211 * result IS mapped to CANDIDATES_TO_KEEP range */
212static hash_t hash_collide(Assoc *assoc, hash_t hash)
213{
214 uint64_t hash64 = hash % assoc->candidates_bucket_size;
215 hash64 = (hash64 * HASH_COLLIDE_PRIME) % assoc->candidates_bucket_size;
216
217 hash_t retval = hash64;
218
219 /* this should never happen when CANDIDATES_TO_KEEP is prime and hash not a multiple
220 * (id_hash() checks for a multiple and returns a different hash in that case)
221 *
222 * ( 1 .. (prime - 1) is a group over multiplication and every number has its inverse
223 * in the group, so no multiplication should ever end on zero as long neither
224 * of the two factors was zero-equivalent )
225 *
226 * BUT: because the usage of the word "never" invokes Murphy's law, catch it */
227 if (!retval) {
228#ifdef DEBUG
229 fprintf(stderr, "assoc::hash_collide: hash %u, bucket size %u => %u!", hash, (uint)assoc->candidates_bucket_size,
230 retval);
231 assert(retval != 0);
232#endif
233 retval = 1;
234 }
235
236 return retval;
237}
238
239/* returns the "seen" assoc related to the ipp */
240static IPPTsPng *entry_assoc(Client_entry *cl_entry, IP_Port *ipp)
241{
242 if (!cl_entry)
243 return NULL;
244
245 if (ipp->ip.family == AF_INET)
246 return &cl_entry->client.assoc4;
247
248 if (ipp->ip.family == AF_INET6)
249 return &cl_entry->client.assoc6;
250
251 return NULL;
252}
253
254/* returns the "heard" assoc related to the ipp */
255static IP_Port *entry_heard_get(Client_entry *entry, IP_Port *ipp)
256{
257 if (ipp->ip.family == AF_INET)
258 return &entry->assoc_heard4;
259 else if (ipp->ip.family == AF_INET6)
260 return &entry->assoc_heard6;
261 else
262 return NULL;
263}
264
265/* store a "heard" entry
266 * overwrites empty entry, does NOT overwrite non-LAN ip with
267 * LAN ip
268 *
269 * returns 1 if the entry did change */
270static int entry_heard_store(Client_entry *entry, IPPTs *ippts)
271{
272 if (!entry || !ippts)
273 return 0;
274
275 if (!ipport_isset(&ippts->ip_port))
276 return 0;
277
278 IP_Port *heard, *ipp = &ippts->ip_port;
279
280 if (ipp->ip.family == AF_INET)
281 heard = &entry->assoc_heard4;
282 else if (ipp->ip.family == AF_INET6)
283 heard = &entry->assoc_heard6;
284 else
285 return 0;
286
287 if (ipport_equal(ipp, heard))
288 return 0;
289
290 if (!ipport_isset(heard)) {
291 *heard = *ipp;
292 entry->heard_at = ippts->timestamp;
293 entry->heard_family = ipp->ip.family;
294 return 1;
295 }
296
297 /* don't destroy a good address with a crappy one
298 * (unless we're very timed out) */
299 uint8_t LAN_ipp = LAN_ip(ipp->ip) == 0;
300 uint8_t LAN_entry = LAN_ip(heard->ip) == 0;
301
302 if (LAN_ipp && !LAN_entry && !is_timeout(entry->heard_at, CANDIDATES_HEARD_TIMEOUT))
303 return 0;
304
305 *heard = *ipp;
306 entry->heard_at = ippts->timestamp;
307 entry->heard_family = ipp->ip.family;
308
309 return 1;
310}
311
312/* maps Assoc callback signature to id_closest() */
313static int assoc_id_closest(Assoc *assoc, void *callback_data, uint8_t *client_id, uint8_t *client_id1,
314 uint8_t *client_id2)
315{
316 return id_closest(client_id, client_id1, client_id2);
317}
318
319static bucket_t id_bucket(uint8_t *id, uint8_t bits)
320{
321 /* return the first "bits" bits of id */
322 bucket_t retval = 0;
323
324 uint8_t pos = 0;
325
326 while (bits > 8) {
327 retval = (retval << 8) | id[pos++];
328 bits -= 8;
329 }
330
331 return (retval << bits) | (id[pos] >> (8 - bits));
332}
333
334/*****************************************************************************/
335/* CANDIDATES FUNCTIONS */
336/*****************************************************************************/
337
338
339static bucket_t candidates_id_bucket(Assoc *assoc, uint8_t *id)
340{
341 return id_bucket(id, assoc->candidates_bucket_bits);
342}
343
344static uint8_t candidates_search(Assoc *assoc, uint8_t *id, hash_t hash, Client_entry **entryptr)
345{
346 bucket_t bucket = candidates_id_bucket(assoc, id);
347 candidates_bucket *cnd_bckt = &assoc->candidates[bucket];
348 size_t coll, pos = hash % assoc->candidates_bucket_size;
349
350 for (coll = 0; coll < HASH_COLLIDE_COUNT; pos = hash_collide(assoc, pos) , coll++) {
351 Client_entry *entry = &cnd_bckt->list[pos];
352
353 if (entry->hash == hash)
354 if (id_equal(entry->client.client_id, id)) {
355 *entryptr = entry;
356 return 1;
357 }
358 }
359
360 *entryptr = NULL;
361 return 0;
362}
363
364static void candidates_update_assoc(Assoc *assoc, Client_entry *entry, uint8_t used, IPPTs *ippts_send,
365 IP_Port *ipp_recv)
366{
367 if (!assoc || !entry || !ippts_send)
368 return;
369
370 IPPTsPng *ipptsp = entry_assoc(entry, &ippts_send->ip_port);
371
372 if (!ipptsp)
373 return;
374
375 if (used)
376 entry->used_at = unix_time();
377
378 /* do NOT do anything related to wanted, that's handled outside,
379 * just update the assoc (in the most sensible way)
380 */
381 if (ipp_recv) {
382 ipptsp->ip_port = ippts_send->ip_port;
383 ipptsp->timestamp = ippts_send->timestamp;
384 ipptsp->ret_ip_port = *ipp_recv;
385 ipptsp->ret_timestamp = unix_time();
386
387 entry->seen_at = unix_time();
388 entry->seen_family = ippts_send->ip_port.ip.family;
389
390 return;
391 }
392
393 entry_heard_store(entry, ippts_send);
394}
395
396static uint8_t candidates_create_internal(Assoc *assoc, hash_t hash, uint8_t *id, uint8_t seen,
397 uint8_t used, bucket_t *bucketptr, size_t *posptr)
398{
399 if (!assoc || !id || !bucketptr || !posptr)
400 return 0;
401
402 bucket_t bucket = candidates_id_bucket(assoc, id);
403 candidates_bucket *cnd_bckt = &assoc->candidates[bucket];
404
405 size_t coll, pos = hash % assoc->candidates_bucket_size, check;
406 size_t pos_check[6];
407
408 memset(pos_check, 0, sizeof(pos_check));
409
410 for (coll = 0; coll < HASH_COLLIDE_COUNT; pos = hash_collide(assoc, pos) , coll++) {
411 Client_entry *entry = &cnd_bckt->list[pos];
412
413 /* unset */
414 if (!entry->hash) {
415 *bucketptr = bucket;
416 *posptr = pos;
417
418 return 1;
419 }
420
421 /* 0. bad
422 * 1. seen bad, heard good
423 * 2. seen good
424 * 3. used */
425 if (!is_timeout(entry->used_at, BAD_NODE_TIMEOUT))
426 check = 3;
427
428 if (!is_timeout(entry->seen_at, CANDIDATES_SEEN_TIMEOUT))
429 check = 2;
430 else if (!is_timeout(entry->heard_at, CANDIDATES_HEARD_TIMEOUT))
431 check = 1;
432 else
433 check = 0;
434
435 if (!pos_check[check])
436 pos_check[check] = pos + 1;
437 }
438
439 /* used > seen > heard > bad */
440 size_t i, pos_max = used ? 3 : (seen ? 2 : 1);
441
442 for (i = 0; i < pos_max; i++)
443 if (pos_check[i]) {
444 *bucketptr = bucket;
445 *posptr = pos_check[i] - 1;
446
447 return 1;
448 }
449
450 return 0;
451}
452
453static uint8_t candidates_create_new(Assoc *assoc, hash_t hash, uint8_t *id, uint8_t used,
454 IPPTs *ippts_send, IP_Port *ipp_recv)
455{
456 if (!assoc || !id || !ippts_send)
457 return 0;
458
459 bucket_t bucket;
460 size_t pos;
461
462 if (!candidates_create_internal(assoc, hash, id, ipp_recv != NULL, used, &bucket, &pos))
463 return 0;
464
465 candidates_bucket *cnd_bckt = &assoc->candidates[bucket];
466 Client_entry *entry = &cnd_bckt->list[pos];
467 memset(entry, 0, sizeof(*entry));
468 IPPTsPng *ipptsp = entry_assoc(entry, &ippts_send->ip_port);
469
470 if (!ipptsp)
471 return 0;
472
473 entry->hash = hash;
474 id_copy(entry->client.client_id, id);
475
476 if (used)
477 entry->used_at = unix_time();
478
479 if (ipp_recv && !ipport_isset(ipp_recv))
480 ipp_recv = NULL;
481
482 if (ipp_recv) {
483 entry->seen_at = ippts_send->timestamp;
484 entry->seen_family = ippts_send->ip_port.ip.family;
485
486 ipptsp->ip_port = ippts_send->ip_port;
487 ipptsp->timestamp = ippts_send->timestamp;
488 ipptsp->ret_ip_port = *ipp_recv;
489 ipptsp->ret_timestamp = unix_time();
490 } else {
491 IP_Port *heard = entry_heard_get(entry, &ippts_send->ip_port);
492
493 if (heard) {
494 entry->heard_at = ippts_send->timestamp;
495 entry->heard_family = ippts_send->ip_port.ip.family;
496
497 *heard = ippts_send->ip_port;
498 }
499 }
500
501 return 1;
502}
503
504/*****************************************************************************/
505
506static void client_id_self_update(Assoc *assoc)
507{
508 if (assoc->self_hash || !assoc->self_client_id)
509 return;
510
511 if (!assoc->self_hash) {
512 size_t i, sum = 0;
513
514 for (i = 0; i < crypto_box_PUBLICKEYBYTES; i++)
515 sum |= assoc->self_client_id[i];
516
517 if (!sum)
518 return;
519
520 assoc->self_hash = id_hash(assoc, assoc->self_client_id);
521 }
522
523#ifdef LOGGING
524 loglog("assoc: id is now set, purging cache of self-references...\n");
525#endif
526
527 /* if we already added some (or loaded some) entries,
528 * look and remove if we find a match
529 */
530 bucket_t b_id = candidates_id_bucket(assoc, assoc->self_client_id);
531 candidates_bucket *cnd_bckt = &assoc->candidates[b_id];
532 size_t i, pos = assoc->self_hash % assoc->candidates_bucket_size;
533
534 for (i = 0; i < HASH_COLLIDE_COUNT; pos = hash_collide(assoc, pos), i++) {
535 Client_entry *entry = &cnd_bckt->list[pos];
536
537 if (entry->hash == assoc->self_hash)
538 if (id_equal(entry->client.client_id, assoc->self_client_id))
539 entry->hash = 0;
540 }
541}
542
543/*****************************************************************************/
544/* TRIGGER FUNCTIONS */
545/*****************************************************************************/
546
547/* Central entry point for new associations: add a new candidate to the cache
548 * seen should be 0 (zero), if the candidate was announced by someone else,
549 * seen should be 1 (one), if there is confirmed connectivity (a definite response)
550 */
551uint8_t Assoc_add_entry(Assoc *assoc, uint8_t *id, IPPTs *ippts_send, IP_Port *ipp_recv, uint8_t used)
552{
553 if (!assoc || !id || !ippts_send)
554 return 0;
555
556 if (!assoc->self_hash) {
557 client_id_self_update(assoc);
558
559 if (!assoc->self_hash)
560 return 0;
561 }
562
563 if (!ipport_isset(&ippts_send->ip_port))
564 return 0;
565
566 if (ipp_recv && !ipport_isset(ipp_recv))
567 ipp_recv = NULL;
568
569 hash_t hash = id_hash(assoc, id);
570
571 if (hash == assoc->self_hash)
572 if (id_equal(id, assoc->self_client_id))
573 return 0;
574
575 /* if it's new:
576 * callback, if there's desire, add to clients, else to candidates
577 *
578 * if it's "old":
579 * if it's client: refresh
580 * if it's candidate:
581 * if !ipp_recv, refresh
582 * if ipp_recv: callback, if there's desire, move to candidates
583 */
584 Client_entry *cnd_entry;
585
586 if (!candidates_search(assoc, id, hash, &cnd_entry)) {
587 if (candidates_create_new(assoc, hash, id, used, ippts_send, ipp_recv))
588 return 1;
589 else
590 return 0;
591 } else {
592 candidates_update_assoc(assoc, cnd_entry, used, ippts_send, ipp_recv);
593 return 2;
594 }
595}
596
597/*****************************************************************************/
598/* MAIN USE */
599/*****************************************************************************/
600
601uint8_t Assoc_get_close_entries(Assoc *assoc, Assoc_close_entries *state)
602{
603 if (!assoc || !state || !state->wanted_id || !state->result)
604 return 0;
605
606 if (!assoc->self_hash) {
607 client_id_self_update(assoc);
608
609 if (!assoc->self_hash)
610 return 0;
611 }
612
613 if (!state->distance_relative_func)
614 state->distance_relative_func = assoc_id_closest;
615
616 if (!state->distance_absolute_func)
617 state->distance_absolute_func = id_distance;
618
619 size_t dist_list_len = assoc->candidates_bucket_count * assoc->candidates_bucket_size;
620 uint64_t dist_list[dist_list_len];
621 memset(dist_list, ~0, dist_list_len * sizeof(dist_list[0]));
622 bucket_t b;
623 size_t i;
624
625 for (b = 0; b < assoc->candidates_bucket_count; b++) {
626 candidates_bucket *cnd_bckt = &assoc->candidates[b];
627
628 for (i = 0; i < assoc->candidates_bucket_size; i++) {
629 Client_entry *entry = &cnd_bckt->list[i];
630
631 if (entry->hash) {
632 if (state->flags & ProtoIPv4) {
633 if (!ipport_isset(&entry->client.assoc4.ip_port))
634 continue;
635
636 if (!(state->flags & LANOk))
637 if (!LAN_ip(entry->client.assoc4.ip_port.ip))
638 continue;
639 }
640
641 if (state->flags & ProtoIPv6) {
642 if (!ipport_isset(&entry->client.assoc6.ip_port))
643 continue;
644
645 if (!(state->flags & LANOk))
646 if (!LAN_ip(entry->client.assoc6.ip_port.ip))
647 continue;
648 }
649
650 uint64_t dist = state->distance_absolute_func(assoc, state->custom_data, state->wanted_id, entry->client.client_id);
651 uint32_t index = b * assoc->candidates_bucket_size + i;
652 dist_list[index] = (dist << DISTANCE_INDEX_INDEX_BITS) | index;
653 }
654 }
655 }
656
657 qsort(dist_list, dist_list_len, sizeof(dist_list[0]), dist_index_comp);
658
659 /* ok, ok, it's not *perfectly* sorted, because we used an absolute distance
660 * go over the result and see if we need to "smoothen things out"
661 * because those should be only very few and short streaks, the worst regularly
662 * used sorting function aka bubble sort is used */
663 uint64_t dist_prev = ~0;
664 size_t ind_prev = ~0, ind_curr;
665 size_t len = 1;
666
667 for (ind_curr = 0; ind_curr < dist_list_len; ind_curr++) {
668 /* sorted increasingly, so an invalid entry marks the end */
669 if ((dist_list[ind_curr] & DISTANCE_INDEX_INDEX_MASK) == DISTANCE_INDEX_INDEX_MASK)
670 break;
671
672 uint64_t dist_curr = dist_list[ind_curr] >> DISTANCE_INDEX_INDEX_BITS;
673
674 if (dist_prev == dist_curr)
675 len++;
676 else {
677 if (len > 1)
678 dist_index_bubble(assoc, dist_list, ind_prev, ind_curr - 1, state->wanted_id, state->custom_data,
679 state->distance_relative_func);
680
681 dist_prev = dist_curr;
682 ind_prev = ind_curr;
683 len = 1;
684 }
685 }
686
687 if (len > 1)
688 dist_index_bubble(assoc, dist_list, ind_prev, ind_curr - 1, state->wanted_id, state->custom_data,
689 state->distance_relative_func);
690
691 /* ok, now dist_list is a strictly ascending sorted list of nodes
692 * a) extract CLOSE_QUOTA_USED clients, not timed out
693 * b) extract (1 - QUOTA) (better!) clients & candidates, not timed out
694 * c) save candidates which would be better, if contact can be established */
695 size_t client_quota_good = 0, pos = 0;
696 size_t client_quota_max = state->count_good;
697
698 ssize_t taken_last = - 1;
699
700 for (i = 0; (i < dist_list_len) && (pos < state->count); i++) {
701 Client_entry *entry = dist_index_entry(assoc, dist_list[i]);
702
703 if (entry && entry->hash) {
704 if (client_quota_good >= client_quota_max) {
705 state->result[pos++] = &entry->client;
706 taken_last = i;
707 } else {
708 if (state->flags & (ProtoIPv4 | ProtoIPv6)) {
709 if ((state->flags & ProtoIPv4) && is_timeout(entry->client.assoc4.timestamp, BAD_NODE_TIMEOUT))
710 continue;
711
712 if ((state->flags & ProtoIPv6) && is_timeout(entry->client.assoc6.timestamp, BAD_NODE_TIMEOUT))
713 continue;
714 } else if (is_timeout(entry->seen_at, BAD_NODE_TIMEOUT))
715 continue;
716
717 state->result[pos++] = &entry->client;
718 client_quota_good++;
719 taken_last = i;
720 }
721 }
722 }
723
724 /* if we had not enough valid entries the list might still not be filled.
725 *
726 * start again from last taken client, but leave out any requirement
727 */
728 if (pos < state->count) {
729 for (i = taken_last + 1; (i < dist_list_len) && (pos < state->count); i++) {
730 Client_entry *entry = dist_index_entry(assoc, dist_list[i]);
731
732 if (entry && entry->hash)
733 state->result[pos++] = &entry->client;
734 }
735 }
736
737 return pos;
738}
739
740/*****************************************************************************/
741/* GLOBAL STRUCTURE FUNCTIONS */
742/*****************************************************************************/
743
744static uint8_t odd_min9_is_prime(size_t value)
745{
746 size_t i = 3;
747
748 while (i * i <= value) {
749 if (!(value % i))
750 return 0;
751
752 i += 2;
753 }
754
755 return 1;
756}
757
758static size_t prime_upto_min9(size_t limit)
759{
760 /* even => odd */
761 limit = limit - (1 - (limit % 2));
762
763 while (!odd_min9_is_prime(limit))
764 limit -= 2;
765
766 return limit;
767}
768
769/* create */
770Assoc *new_Assoc(size_t bits, size_t entries, uint8_t *public_id)
771{
772 if (!public_id)
773 return NULL;
774
775 Assoc *assoc = calloc(1, sizeof(*assoc));
776
777 if (!assoc)
778 return NULL;
779
780 /*
781 * bits must be in [ 2 .. 15 ]
782 * entries must be a prime
783 */
784 if (bits < 2)
785 bits = 2;
786 else if (bits > 15)
787 bits = 15;
788
789 assoc->candidates_bucket_bits = bits;
790 assoc->candidates_bucket_count = 1U << bits;
791
792 if (entries < 25) {
793 if (entries <= 6)
794 entries = 5;
795 else {
796 entries = entries - (1 - (entries % 2)); /* even => odd */
797
798 /* 7..23: all odds but 9&15 are prime */
799 if (!(entries % 3)) /* 9, 15 */
800 entries -= 2; /* 7, 13 */
801 }
802 } else if (entries > ((1 << 17) - 1)) /* 130k+ */
803 entries = (1 << 17) - 1;
804 else {
805 /* 9+: test and find a prime less or equal */
806 size_t entries_test = prime_upto_min9(entries);
807
808 if (entries_test == HASH_COLLIDE_PRIME) /* disallowed */
809 entries_test = prime_upto_min9(entries_test - 1);
810
811 if (entries_test != entries) {
812#ifdef LOGGING
813 sprintf(logbuffer, "new_Assoc(): trimmed %i to %i.\n", (int)entries, (int)entries_test);
814 loglog(logbuffer);
815#endif
816 entries = (size_t)entries_test;
817 }
818 }
819
820 assoc->candidates_bucket_size = entries;
821
822 /* allocation: preferably few blobs */
823 size_t bckt, cix;
824 Client_entry *clients = malloc(sizeof(*clients) * assoc->candidates_bucket_count * assoc->candidates_bucket_size);
825 candidates_bucket *lists = malloc(sizeof(*lists) * assoc->candidates_bucket_count);
826
827 for (bckt = 0; bckt < assoc->candidates_bucket_count; bckt++) {
828 candidates_bucket *list = &lists[bckt];
829
830 list->list = &clients[bckt * assoc->candidates_bucket_size];
831
832 for (cix = 0; cix < assoc->candidates_bucket_size; cix++)
833 list->list[cix].hash = 0;
834 }
835
836 assoc->candidates = lists;
837
838 id_copy(assoc->self_client_id, public_id);
839 client_id_self_update(assoc);
840
841 return assoc;
842}
843
844Assoc *new_Assoc_default(uint8_t *public_id)
845{
846 /* original 8, 251 averages to ~32k entries... probably the whole DHT :D
847 * 320 entries is fine, hopefully */
848 return new_Assoc(6, 15, public_id);
849}
850
851/* own client_id, assocs for this have to be ignored */
852void Assoc_self_client_id_changed(Assoc *assoc, uint8_t *id)
853{
854 if (assoc && id) {
855 assoc->self_hash = 0;
856 id_copy(assoc->self_client_id, id);
857 client_id_self_update(assoc);
858 }
859}
860
861/* destroy */
862void kill_Assoc(Assoc *assoc)
863{
864 if (assoc) {
865 free(assoc->candidates->list);
866 free(assoc->candidates);
867 free(assoc);
868 }
869}
870
871#ifdef LOGGING
872
873static char buffer[CLIENT_ID_SIZE * 2 + 1];
874static char *idpart2str(uint8_t *id, size_t len)
875{
876 if (len > CLIENT_ID_SIZE)
877 len = CLIENT_ID_SIZE;
878
879 size_t i;
880
881 for (i = 0; i < len; i++)
882 sprintf(buffer + i * 2, "%02hhx", id[i]);
883
884 buffer[len * 2] = 0;
885 return buffer;
886}
887
888void Assoc_status(Assoc *assoc)
889{
890 if (!assoc) {
891 loglog("Assoc status: no assoc\n");
892 return;
893 }
894
895 loglog("[b:p] hash => [id...] used, seen, heard\n");
896
897 size_t bid, cid, total = 0;
898
899 for (bid = 0; bid < assoc->candidates_bucket_count; bid++) {
900 candidates_bucket *bucket = &assoc->candidates[bid];
901
902 for (cid = 0; cid < assoc->candidates_bucket_size; cid++) {
903 Client_entry *entry = &bucket->list[cid];
904
905 if (entry->hash) {
906 sprintf(logbuffer, "[%3i:%3i] %08x => [%s...] %i, %i(%c), %i(%c)\n",
907 (int)bid, (int)cid, entry->hash, idpart2str(entry->client.client_id, 8),
908 entry->used_at ? (int)(unix_time() - entry->used_at) : 0,
909 entry->seen_at ? (int)(unix_time() - entry->seen_at) : 0,
910 entry->seen_at ? (entry->seen_family == AF_INET ? '4' : (entry->seen_family == AF_INET6 ? '6' : '?')) : '?',
911 entry->heard_at ? (int)(unix_time() - entry->heard_at) : 0,
912 entry->heard_at ? (entry->heard_family == AF_INET ? '4' : (entry->heard_family == AF_INET6 ? '6' : '?')) : '?');
913 loglog(logbuffer);
914 total++;
915 }
916 }
917 }
918
919 if (total) {
920 sprintf(logbuffer, "Total: %i entries, table usage %i%%.\n", (int)total,
921 (int)(total * 100 / (assoc->candidates_bucket_count * assoc->candidates_bucket_size)));
922 loglog(logbuffer);
923 }
924}
925
926#endif
diff --git a/toxcore/assoc.h b/toxcore/assoc.h
new file mode 100644
index 00000000..d3055ce3
--- /dev/null
+++ b/toxcore/assoc.h
@@ -0,0 +1,93 @@
1
2#ifndef __ASSOC_H__
3#define __ASSOC_H__
4
5/* used by rendezvous */
6#define ASSOC_AVAILABLE
7
8/* For the legalese parts, see tox.h. */
9
10/*
11 * Module to store currently unused ID <=> IP associations
12 * for a potential future use
13 */
14
15typedef struct Assoc Assoc;
16
17/*****************************************************************************/
18
19/* custom distance handler, if it's not ID-distance based
20 * return values exactly like id_closest() */
21typedef int (*Assoc_distance_relative_callback)(Assoc *assoc, void *callback_data, uint8_t *client_id,
22 uint8_t *client_id1, uint8_t *client_id2);
23
24#define DISTANCE_INDEX_DISTANCE_BITS 44
25
26/* absolute distance: can be same for different client_id_check values
27 * return value should have DISTANCE_INDEX_DISTANCE_BITS valid bits */
28typedef uint64_t (*Assoc_distance_absolute_callback)(Assoc *assoc, void *callback_data,
29 uint8_t *client_id_ref, uint8_t *client_id_check);
30
31/*****************************************************************************/
32
33/* Central entry point for new associations: add a new candidate to the cache
34 * returns 1 if entry is stored, 2 if existing entry was updated, 0 else */
35uint8_t Assoc_add_entry(Assoc *assoc, uint8_t *id, IPPTs *ippts_send, IP_Port *ipp_recv, uint8_t used);
36
37/*****************************************************************************/
38
39typedef enum AssocCloseEntriesFlags {
40 ProtoIPv4 = 1,
41 ProtoIPv6 = 2,
42 LANOk = 4,
43} AssocCloseEntriesFlags;
44
45typedef struct Assoc_close_entries {
46 void *custom_data; /* given to distance functions */
47 uint8_t *wanted_id; /* the target client_id */
48 uint8_t flags; /* additional flags */
49
50 Assoc_distance_relative_callback distance_relative_func;
51 Assoc_distance_absolute_callback distance_absolute_func;
52
53 uint8_t count_good; /* that many should be "good" w.r.t. timeout */
54 uint8_t count; /* allocated number of close_indices */
55 Client_data **result;
56} Assoc_close_entries;
57
58/* find up to close_count nodes to put into close_nodes_used of ID_Nodes
59 * the distance functions can be NULL, then standard distance functions will be used
60 * the caller is responsible for allocating close_indices of sufficient size
61 *
62 * returns 0 on error
63 * returns the number of found nodes and the list of indices usable by Assoc_client()
64 * the caller is assumed to be registered from Assoc_register_callback()
65 * if they aren't, they should copy the Client_data and call Assoc_client_drop()
66 */
67uint8_t Assoc_get_close_entries(Assoc *assoc, Assoc_close_entries *close_entries);
68
69/*****************************************************************************/
70
71/* create: default sizes (6, 5 => 320 entries) */
72Assoc *new_Assoc_default(uint8_t *public_id);
73
74/* create: customized sizes
75 * total is (2^bits) * entries
76 * bits should be between 2 and 15 (else it's trimmed)
77 * entries will be reduced to the closest prime smaller or equal
78 *
79 * preferably bits should be large and entries small to ensure spread
80 * in the search space (e. g. 5, 5 is preferable to 2, 41) */
81Assoc *new_Assoc(size_t bits, size_t entries, uint8_t *public_id);
82
83/* public_id changed (loaded), update which entry isn't stored */
84void Assoc_self_client_id_changed(Assoc *assoc, uint8_t *public_id);
85
86/* destroy */
87void kill_Assoc(Assoc *assoc);
88
89#ifdef LOGGING
90void Assoc_status(Assoc *assoc);
91#endif
92
93#endif /* !__ASSOC_H__ */
diff --git a/toxcore/friend_requests.c b/toxcore/friend_requests.c
index 67977c23..589bd315 100644
--- a/toxcore/friend_requests.c
+++ b/toxcore/friend_requests.c
@@ -96,6 +96,12 @@ void callback_friendrequest(Friend_Requests *fr, void (*function)(uint8_t *, uin
96 fr->handle_friendrequest_isset = 1; 96 fr->handle_friendrequest_isset = 1;
97 fr->handle_friendrequest_userdata = userdata; 97 fr->handle_friendrequest_userdata = userdata;
98} 98}
99/* Set the function used to check if a friend request should be displayed to the user or not. */
100void set_filter_function(Friend_Requests *fr, int (*function)(uint8_t *, void *), void *userdata)
101{
102 fr->filter_function = function;
103 fr->filter_function_userdata = userdata;
104}
99 105
100/* Add to list of received friend requests. */ 106/* Add to list of received friend requests. */
101static void addto_receivedlist(Friend_Requests *fr, uint8_t *client_id) 107static void addto_receivedlist(Friend_Requests *fr, uint8_t *client_id)
@@ -141,6 +147,10 @@ static int friendreq_handlepacket(void *object, IP_Port source, uint8_t *source_
141 if (memcmp(packet, &fr->nospam, sizeof(fr->nospam)) != 0) 147 if (memcmp(packet, &fr->nospam, sizeof(fr->nospam)) != 0)
142 return 1; 148 return 1;
143 149
150 if (fr->filter_function)
151 if ((*fr->filter_function)(source_pubkey, fr->filter_function_userdata) != 0)
152 return 1;
153
144 addto_receivedlist(fr, source_pubkey); 154 addto_receivedlist(fr, source_pubkey);
145 (*fr->handle_friendrequest)(source_pubkey, packet + 4, length - 4, fr->handle_friendrequest_userdata); 155 (*fr->handle_friendrequest)(source_pubkey, packet + 4, length - 4, fr->handle_friendrequest_userdata);
146 return 0; 156 return 0;
diff --git a/toxcore/friend_requests.h b/toxcore/friend_requests.h
index b5c46056..c655669d 100644
--- a/toxcore/friend_requests.h
+++ b/toxcore/friend_requests.h
@@ -34,6 +34,8 @@ typedef struct {
34 uint8_t handle_friendrequest_isset; 34 uint8_t handle_friendrequest_isset;
35 void *handle_friendrequest_userdata; 35 void *handle_friendrequest_userdata;
36 36
37 int (*filter_function)(uint8_t *, void *);
38 void *filter_function_userdata;
37 /* NOTE: The following is just a temporary fix for the multiple friend requests received at the same time problem. 39 /* NOTE: The following is just a temporary fix for the multiple friend requests received at the same time problem.
38 * TODO: Make this better (This will most likely tie in with the way we will handle spam.) 40 * TODO: Make this better (This will most likely tie in with the way we will handle spam.)
39 */ 41 */
@@ -53,11 +55,17 @@ void set_nospam(Friend_Requests *fr, uint32_t num);
53uint32_t get_nospam(Friend_Requests *fr); 55uint32_t get_nospam(Friend_Requests *fr);
54 56
55/* Set the function that will be executed when a friend request for us is received. 57/* Set the function that will be executed when a friend request for us is received.
56 * Function format is function(uint8_t * public_key, uint8_t * data, uint16_t length) 58 * Function format is function(uint8_t * public_key, uint8_t * data, uint16_t length, void * userdata)
57 */ 59 */
58void callback_friendrequest(Friend_Requests *fr, void (*function)(uint8_t *, uint8_t *, uint16_t, void *), 60void callback_friendrequest(Friend_Requests *fr, void (*function)(uint8_t *, uint8_t *, uint16_t, void *),
59 void *userdata); 61 void *userdata);
60 62
63/* Set the function used to check if a friend request should be displayed to the user or not.
64 * Function format is int function(uint8_t * public_key, void * userdata)
65 * It must return 0 if the request is ok (anything else if it is bad.)
66 */
67void set_filter_function(Friend_Requests *fr, int (*function)(uint8_t *, void *), void *userdata);
68
61/* Sets up friendreq packet handlers. */ 69/* Sets up friendreq packet handlers. */
62void friendreq_init(Friend_Requests *fr, Net_Crypto *c); 70void friendreq_init(Friend_Requests *fr, Net_Crypto *c);
63 71
diff --git a/toxcore/group_chats.c b/toxcore/group_chats.c
index 6ad41c7f..16d8f344 100644
--- a/toxcore/group_chats.c
+++ b/toxcore/group_chats.c
@@ -27,6 +27,8 @@
27#endif 27#endif
28 28
29#include "group_chats.h" 29#include "group_chats.h"
30#include "assoc.h"
31#include "LAN_discovery.h"
30#include "util.h" 32#include "util.h"
31 33
32#define GROUPCHAT_MAXDATA_LENGTH (MAX_DATA_SIZE - (1 + crypto_box_PUBLICKEYBYTES * 2 + crypto_box_NONCEBYTES)) 34#define GROUPCHAT_MAXDATA_LENGTH (MAX_DATA_SIZE - (1 + crypto_box_PUBLICKEYBYTES * 2 + crypto_box_NONCEBYTES))
@@ -53,7 +55,6 @@ typedef struct {
53 55
54} sendnodes_data; 56} sendnodes_data;
55 57
56
57/* 58/*
58 * check if peer with client_id is in peer array. 59 * check if peer with client_id is in peer array.
59 * 60 *
@@ -211,43 +212,61 @@ static int addpeer(Group_Chat *chat, uint8_t *client_id)
211 212
212 memset(&(temp[chat->numpeers]), 0, sizeof(Group_Peer)); 213 memset(&(temp[chat->numpeers]), 0, sizeof(Group_Peer));
213 chat->group = temp; 214 chat->group = temp;
215
214 id_copy(chat->group[chat->numpeers].client_id, client_id); 216 id_copy(chat->group[chat->numpeers].client_id, client_id);
215 chat->group[chat->numpeers].last_recv = unix_time(); 217 chat->group[chat->numpeers].last_recv = unix_time();
216 chat->group[chat->numpeers].last_recv_msgping = unix_time(); 218 chat->group[chat->numpeers].last_recv_msgping = unix_time();
217 ++chat->numpeers; 219 ++chat->numpeers;
220
221 if (chat->peer_namelistchange != NULL)
222 (*chat->peer_namelistchange)(chat, chat->numpeers - 1, CHAT_CHANGE_PEER_ADD, chat->group_namelistchange_userdata);
223
218 return (chat->numpeers - 1); 224 return (chat->numpeers - 1);
219} 225}
220 226
221/* 227/*
222 * Delete a peer to the group chat. 228 * Delete a peer from the group chat.
223 * 229 *
224 * return 0 if success 230 * return 0 if success
225 * return -1 if error. 231 * return -1 if error.
226 */ 232 */
227static int delpeer(Group_Chat *chat, uint8_t *client_id) 233static int delpeer(Group_Chat *chat, int peernum)
228{ 234{
235 if ((uint32_t)peernum >= chat->numpeers)
236 return -1;
237
229 uint32_t i; 238 uint32_t i;
239 for (i = 0; i < GROUP_CLOSE_CONNECTIONS; ++i) { /* If peer is in close list, time it out forcefully. */
240 if (id_equal(chat->close[i].client_id, chat->group[peernum].client_id)) {
241 chat->close[i].last_recv = 0;
242 break;
243 }
244 }
245
230 Group_Peer *temp; 246 Group_Peer *temp;
247 --chat->numpeers;
231 248
232 for (i = 0; i < chat->numpeers; ++i) { 249 if (chat->numpeers == 0) {
233 /* Equal */ 250 free(chat->group);
234 if (id_equal(chat->group[i].client_id, client_id)) { 251 chat->group = NULL;
235 --chat->numpeers; 252 return 0;
253 }
254
255 if (chat->numpeers != (uint32_t)peernum)
256 memcpy(&chat->group[peernum], &chat->group[chat->numpeers], sizeof(Group_Peer));
236 257
237 if (chat->numpeers != i) 258 temp = realloc(chat->group, sizeof(Group_Peer) * (chat->numpeers));
238 id_copy(chat->group[i].client_id, chat->group[chat->numpeers].client_id);
239 259
240 temp = realloc(chat->group, sizeof(Group_Peer) * (chat->numpeers)); 260 if (temp == NULL)
261 return -1;
241 262
242 if (temp == NULL) 263 chat->group = temp;
243 return -1;
244 264
245 chat->group = temp; 265 if (chat->peer_namelistchange != NULL) {
246 return 0; 266 (*chat->peer_namelistchange)(chat, peernum, CHAT_CHANGE_PEER_DEL, chat->group_namelistchange_userdata);
247 }
248 } 267 }
249 268
250 return -1; 269 return 0;
251} 270}
252 271
253/* Copy the name of peernum to name. 272/* Copy the name of peernum to name.
@@ -262,25 +281,44 @@ int group_peername(Group_Chat *chat, int peernum, uint8_t *name)
262 return -1; 281 return -1;
263 282
264 if (chat->group[peernum].nick_len == 0) { 283 if (chat->group[peernum].nick_len == 0) {
265 memcpy(name, "NSA Agent", 10); /* Kindly remind the user that someone with no name might be an NSA agent.*/ 284 /* memcpy(name, "NSA agent", 10); */ /* Srsly? */ /* Kindly remind the user that someone with no name might be a moronic NSA agent.*/
266 return 10; 285 name[0] = 0;
286 return 0;
267 } 287 }
268 288
269 memcpy(name, chat->group[peernum].nick, chat->group[peernum].nick_len); 289 memcpy(name, chat->group[peernum].nick, chat->group[peernum].nick_len);
270 return chat->group[peernum].nick_len; 290 return chat->group[peernum].nick_len;
271} 291}
272 292
293static void setnick(Group_Chat *chat, int peernum, uint8_t *contents, uint16_t contents_len)
294{
295 if (contents_len > MAX_NICK_BYTES || contents_len == 0)
296 return;
297
298 /* same name as already stored? */
299 if (chat->group[peernum].nick_len == contents_len)
300 if (!memcmp(chat->group[peernum].nick, contents, contents_len))
301 return;
302
303 memcpy(chat->group[peernum].nick, contents, contents_len);
304 /* Force null termination */
305 chat->group[peernum].nick[contents_len - 1] = 0;
306 chat->group[peernum].nick_len = contents_len;
307
308 if (chat->peer_namelistchange != NULL)
309 (*chat->peer_namelistchange)(chat, peernum, CHAT_CHANGE_PEER_NAME, chat->group_namelistchange_userdata);
310}
273 311
274/* min time between pings sent to one peer in seconds */ 312/* min time between pings sent to one peer in seconds */
275/* TODO: move this to global section */ 313/* TODO: move this to global section */
276#define PING_TIMEOUT 5 314#define GROUP_PING_TIMEOUT 5
277 315
278static int send_getnodes(Group_Chat *chat, IP_Port ip_port, int peernum) 316static int send_getnodes(Group_Chat *chat, IP_Port ip_port, int peernum)
279{ 317{
280 if ((uint32_t)peernum >= chat->numpeers) 318 if ((uint32_t)peernum >= chat->numpeers)
281 return -1; 319 return -1;
282 320
283 if (!is_timeout(chat->group[peernum].last_pinged, PING_TIMEOUT)) 321 if (!is_timeout(chat->group[peernum].last_pinged, GROUP_PING_TIMEOUT))
284 return -1; 322 return -1;
285 323
286 getnodes_data contents; 324 getnodes_data contents;
@@ -288,6 +326,15 @@ static int send_getnodes(Group_Chat *chat, IP_Port ip_port, int peernum)
288 326
289 chat->group[peernum].last_pinged = unix_time(); 327 chat->group[peernum].last_pinged = unix_time();
290 chat->group[peernum].pingid = contents.pingid; 328 chat->group[peernum].pingid = contents.pingid;
329 chat->group[peernum].ping_via = ip_port;
330
331 if (chat->assoc) {
332 IPPTs ippts;
333 ippts.timestamp = unix_time();
334 ippts.ip_port = ip_port;
335
336 Assoc_add_entry(chat->assoc, chat->group[peernum].client_id, &ippts, NULL, 1);
337 }
291 338
292 return send_groupchatpacket(chat, ip_port, chat->group[peernum].client_id, (uint8_t *)&contents, sizeof(contents), 339 return send_groupchatpacket(chat, ip_port, chat->group[peernum].client_id, (uint8_t *)&contents, sizeof(contents),
293 CRYPTO_PACKET_GROUP_CHAT_GET_NODES); 340 CRYPTO_PACKET_GROUP_CHAT_GET_NODES);
@@ -343,7 +390,7 @@ static int handle_sendnodes(Group_Chat *chat, IP_Port source, int peernum, uint8
343 if ((len - sizeof(uint64_t)) % sizeof(groupchat_nodes) != 0) 390 if ((len - sizeof(uint64_t)) % sizeof(groupchat_nodes) != 0)
344 return 1; 391 return 1;
345 392
346 if (is_timeout(chat->group[peernum].last_pinged, PING_TIMEOUT)) 393 if (is_timeout(chat->group[peernum].last_pinged, GROUP_PING_TIMEOUT))
347 return 1; 394 return 1;
348 395
349 sendnodes_data contents; 396 sendnodes_data contents;
@@ -355,6 +402,9 @@ static int handle_sendnodes(Group_Chat *chat, IP_Port source, int peernum, uint8
355 uint16_t numnodes = (len - sizeof(contents.pingid)) / sizeof(groupchat_nodes); 402 uint16_t numnodes = (len - sizeof(contents.pingid)) / sizeof(groupchat_nodes);
356 uint32_t i; 403 uint32_t i;
357 404
405 IPPTs ippts_send;
406 ippts_send.timestamp = unix_time();
407
358 for (i = 0; i < numnodes; ++i) { 408 for (i = 0; i < numnodes; ++i) {
359 if (peer_okping(chat, contents.nodes[i].client_id) > 0) { 409 if (peer_okping(chat, contents.nodes[i].client_id) > 0) {
360 int peern = peer_in_chat(chat, contents.nodes[i].client_id); 410 int peern = peer_in_chat(chat, contents.nodes[i].client_id);
@@ -367,14 +417,31 @@ static int handle_sendnodes(Group_Chat *chat, IP_Port source, int peernum, uint8
367 continue; 417 continue;
368 418
369 send_getnodes(chat, contents.nodes[i].ip_port, peern); 419 send_getnodes(chat, contents.nodes[i].ip_port, peern);
420
421 if (chat->assoc) {
422 ippts_send.ip_port = contents.nodes[i].ip_port;
423 Assoc_add_entry(chat->assoc, contents.nodes[i].client_id, &ippts_send, NULL, 0);
424 }
370 } 425 }
371 } 426 }
372 427
373 add_closepeer(chat, chat->group[peernum].client_id, source); 428 int ok = add_closepeer(chat, chat->group[peernum].client_id, source);
429
430 if (chat->assoc) {
431 ippts_send.ip_port = chat->group[peernum].ping_via;
432 ippts_send.timestamp = chat->group[peernum].last_pinged;
433
434 IP_Port ipp_recv;
435 ipp_recv = source;
436
437 Assoc_add_entry(chat->assoc, contents.nodes[i].client_id, &ippts_send, &ipp_recv, ok == 0 ? 1 : 0);
438 }
439
374 return 0; 440 return 0;
375} 441}
376 442
377#define GROUP_DATA_MIN_SIZE (crypto_box_PUBLICKEYBYTES + sizeof(uint32_t) + 1) 443#define GROUP_DATA_MIN_SIZE (crypto_box_PUBLICKEYBYTES + sizeof(uint32_t) + 1)
444static void send_names_new_peer(Group_Chat *chat);
378 445
379static int handle_data(Group_Chat *chat, uint8_t *data, uint32_t len) 446static int handle_data(Group_Chat *chat, uint8_t *data, uint32_t len)
380{ 447{
@@ -385,7 +452,8 @@ static int handle_data(Group_Chat *chat, uint8_t *data, uint32_t len)
385 int peernum = peer_in_chat(chat, data); 452 int peernum = peer_in_chat(chat, data);
386 453
387 if (peernum == -1) { /*NOTE: This is just for testing and will be removed later.*/ 454 if (peernum == -1) { /*NOTE: This is just for testing and will be removed later.*/
388 peernum = addpeer(chat, data); 455 if (data[crypto_box_PUBLICKEYBYTES + sizeof(uint32_t)] != GROUP_CHAT_QUIT)
456 peernum = addpeer(chat, data);
389 } 457 }
390 458
391 if (peernum == -1) 459 if (peernum == -1)
@@ -427,6 +495,21 @@ static int handle_data(Group_Chat *chat, uint8_t *data, uint32_t len)
427 return 1; 495 return 1;
428 496
429 addpeer(chat, contents); 497 addpeer(chat, contents);
498 send_names_new_peer(chat);
499 break;
500
501 case GROUP_CHAT_QUIT: /* If peer tells us he is quitting */
502 if (contents_len != 0)
503 return 1;
504
505 delpeer(chat, peernum);
506 break;
507
508 case GROUP_CHAT_PEER_NICK:
509 if (contents_len > MAX_NICK_BYTES || contents_len == 0)
510 return 1;
511
512 setnick(chat, peernum, contents, contents_len);
430 break; 513 break;
431 514
432 case GROUP_CHAT_CHAT_MESSAGE: /* If message is chat message */ 515 case GROUP_CHAT_CHAT_MESSAGE: /* If message is chat message */
@@ -521,6 +604,30 @@ uint32_t group_sendmessage(Group_Chat *chat, uint8_t *message, uint32_t length)
521 return send_data(chat, message, length, GROUP_CHAT_CHAT_MESSAGE); //TODO: better return values? 604 return send_data(chat, message, length, GROUP_CHAT_CHAT_MESSAGE); //TODO: better return values?
522} 605}
523 606
607/*
608 * Send id/nick combo to the group.
609 *
610 * returns the number of peers it has sent it to.
611 */
612static uint32_t group_send_nick(Group_Chat *chat, uint8_t *nick, uint16_t nick_len)
613{
614 if (nick_len > MAX_NICK_BYTES)
615 return 0;
616
617 return send_data(chat, nick, nick_len, GROUP_CHAT_PEER_NICK);
618}
619
620int set_nick(Group_Chat *chat, uint8_t *nick, uint16_t nick_len)
621{
622 if (nick_len > MAX_NICK_BYTES || nick_len == 0)
623 return -1;
624
625 memcpy(chat->nick, nick, nick_len);
626 chat->nick_len = nick_len;
627 group_send_nick(chat, chat->nick, chat->nick_len);
628 return 0;
629}
630
524uint32_t group_newpeer(Group_Chat *chat, uint8_t *client_id) 631uint32_t group_newpeer(Group_Chat *chat, uint8_t *client_id)
525{ 632{
526 addpeer(chat, client_id); 633 addpeer(chat, client_id);
@@ -534,6 +641,26 @@ void callback_groupmessage(Group_Chat *chat, void (*function)(Group_Chat *chat,
534 chat->group_message_userdata = userdata; 641 chat->group_message_userdata = userdata;
535} 642}
536 643
644void callback_namelistchange(Group_Chat *chat, void (*function)(Group_Chat *chat, int peer, uint8_t change, void *), void *userdata)
645{
646 chat->peer_namelistchange = function;
647 chat->group_namelistchange_userdata = userdata;
648}
649
650uint32_t group_numpeers(Group_Chat *chat)
651{
652 return chat->numpeers;
653}
654
655uint32_t group_client_names(Group_Chat *chat, uint8_t names[][MAX_NICK_BYTES], uint16_t length)
656{
657 uint32_t i;
658 for (i = 0; i < chat->numpeers && i < length; ++i) {
659 group_peername(chat, i, names[i]);
660 }
661 return i;
662}
663
537Group_Chat *new_groupchat(Networking_Core *net) 664Group_Chat *new_groupchat(Networking_Core *net)
538{ 665{
539 unix_time_update(); 666 unix_time_update();
@@ -544,6 +671,10 @@ Group_Chat *new_groupchat(Networking_Core *net)
544 Group_Chat *chat = calloc(1, sizeof(Group_Chat)); 671 Group_Chat *chat = calloc(1, sizeof(Group_Chat));
545 chat->net = net; 672 chat->net = net;
546 crypto_box_keypair(chat->self_public_key, chat->self_secret_key); 673 crypto_box_keypair(chat->self_public_key, chat->self_secret_key);
674
675 /* (2^4) * 5 = 80 entries seems to be a moderate size */
676 chat->assoc = new_Assoc(4, 5, chat->self_public_key);
677
547 return chat; 678 return chat;
548} 679}
549 680
@@ -554,7 +685,6 @@ static void ping_close(Group_Chat *chat)
554 uint32_t i; 685 uint32_t i;
555 686
556 for (i = 0; i < GROUP_CLOSE_CONNECTIONS; ++i) { 687 for (i = 0; i < GROUP_CLOSE_CONNECTIONS; ++i) {
557 /* previous condition was always true, assuming this is the wanted one: */
558 if (!is_timeout(chat->close[i].last_recv, BAD_GROUPNODE_TIMEOUT)) { 688 if (!is_timeout(chat->close[i].last_recv, BAD_GROUPNODE_TIMEOUT)) {
559 int peernum = peer_in_chat(chat, chat->close[i].client_id); 689 int peernum = peer_in_chat(chat, chat->close[i].client_id);
560 690
@@ -583,12 +713,32 @@ static void del_dead_peers(Group_Chat *chat)
583 uint32_t i; 713 uint32_t i;
584 714
585 for (i = 0; i < chat->numpeers; ++i) { 715 for (i = 0; i < chat->numpeers; ++i) {
586 if (is_timeout(chat->group[i].last_recv_msgping, GROUP_PING_INTERVAL * 2)) { 716 if (is_timeout(chat->group[i].last_recv_msgping, GROUP_PING_INTERVAL * 4)) {
587 delpeer(chat, chat->group[i].client_id); 717 delpeer(chat, i);
588 } 718 }
589 } 719 }
590} 720}
591 721
722#define NICK_SEND_INTERVAL 180
723static void send_names_new_peer(Group_Chat *chat)
724{
725 group_send_nick(chat, chat->nick, chat->nick_len);
726 chat->last_sent_nick = (unix_time() - NICK_SEND_INTERVAL) + 10;
727}
728static void send_names(Group_Chat *chat)
729{
730 /* send own nick from time to time, to let newly added peers be informed
731 * first time only: use a shorter timeframe, because we might not be in our own
732 * peer list yet */
733 if (is_timeout(chat->last_sent_nick, 180))
734 if (group_send_nick(chat, chat->nick, chat->nick_len) > 0) {
735 if (!chat->last_sent_nick)
736 chat->last_sent_nick = (unix_time() - NICK_SEND_INTERVAL) + 10;
737 else
738 chat->last_sent_nick = unix_time();
739 }
740}
741
592void do_groupchat(Group_Chat *chat) 742void do_groupchat(Group_Chat *chat)
593{ 743{
594 unix_time_update(); 744 unix_time_update();
@@ -596,10 +746,12 @@ void do_groupchat(Group_Chat *chat)
596 ping_group(chat); 746 ping_group(chat);
597 /* TODO: Maybe run this less? */ 747 /* TODO: Maybe run this less? */
598 del_dead_peers(chat); 748 del_dead_peers(chat);
749 send_names(chat);
599} 750}
600 751
601void kill_groupchat(Group_Chat *chat) 752void kill_groupchat(Group_Chat *chat)
602{ 753{
754 send_data(chat, 0, 0, GROUP_CHAT_QUIT);
603 free(chat->group); 755 free(chat->group);
604 free(chat); 756 free(chat);
605} 757}
diff --git a/toxcore/group_chats.h b/toxcore/group_chats.h
index b3f2e5a8..33773785 100644
--- a/toxcore/group_chats.h
+++ b/toxcore/group_chats.h
@@ -33,6 +33,7 @@ typedef struct {
33 uint8_t client_id[crypto_box_PUBLICKEYBYTES]; 33 uint8_t client_id[crypto_box_PUBLICKEYBYTES];
34 uint64_t pingid; 34 uint64_t pingid;
35 uint64_t last_pinged; 35 uint64_t last_pinged;
36 IP_Port ping_via;
36 37
37 uint64_t last_recv; 38 uint64_t last_recv;
38 uint64_t last_recv_msgping; 39 uint64_t last_recv_msgping;
@@ -46,7 +47,6 @@ typedef struct {
46 uint8_t client_id[crypto_box_PUBLICKEYBYTES]; 47 uint8_t client_id[crypto_box_PUBLICKEYBYTES];
47 IP_Port ip_port; 48 IP_Port ip_port;
48 uint64_t last_recv; 49 uint64_t last_recv;
49
50} Group_Close; 50} Group_Close;
51 51
52#define GROUP_CLOSE_CONNECTIONS 6 52#define GROUP_CLOSE_CONNECTIONS 6
@@ -63,12 +63,22 @@ typedef struct Group_Chat {
63 uint32_t message_number; 63 uint32_t message_number;
64 void (*group_message)(struct Group_Chat *m, int, uint8_t *, uint16_t, void *); 64 void (*group_message)(struct Group_Chat *m, int, uint8_t *, uint16_t, void *);
65 void *group_message_userdata; 65 void *group_message_userdata;
66 void (*peer_namelistchange)(struct Group_Chat *m, int peer, uint8_t change, void *);
67 void *group_namelistchange_userdata;
68
66 uint64_t last_sent_ping; 69 uint64_t last_sent_ping;
67 70
71 uint8_t nick[MAX_NICK_BYTES];
72 uint16_t nick_len;
73 uint64_t last_sent_nick;
74
75 struct Assoc *assoc;
68} Group_Chat; 76} Group_Chat;
69 77
70#define GROUP_CHAT_PING 0 78#define GROUP_CHAT_PING 0
71#define GROUP_CHAT_NEW_PEER 16 79#define GROUP_CHAT_NEW_PEER 16
80#define GROUP_CHAT_QUIT 24
81#define GROUP_CHAT_PEER_NICK 48
72#define GROUP_CHAT_CHAT_MESSAGE 64 82#define GROUP_CHAT_CHAT_MESSAGE 64
73 83
74/* Copy the name of peernum to name. 84/* Copy the name of peernum to name.
@@ -84,9 +94,22 @@ int group_peername(Group_Chat *chat, int peernum, uint8_t *name);
84 * 94 *
85 * format of function is: function(Group_Chat *chat, peer number, message, message length, userdata) 95 * format of function is: function(Group_Chat *chat, peer number, message, message length, userdata)
86 */ 96 */
87
88void callback_groupmessage(Group_Chat *chat, void (*function)(Group_Chat *chat, int, uint8_t *, uint16_t, void *), 97void callback_groupmessage(Group_Chat *chat, void (*function)(Group_Chat *chat, int, uint8_t *, uint16_t, void *),
89 void *userdata); 98 void *userdata);
99/*
100 * Set callback function for peer name list changes.
101 *
102 * It gets called every time the name list changes(new peer/name, deleted peer)
103 *
104 * format of function is: function(Group_Chat *chat, userdata)
105 */
106typedef enum {
107 CHAT_CHANGE_PEER_ADD,
108 CHAT_CHANGE_PEER_DEL,
109 CHAT_CHANGE_PEER_NAME,
110} CHAT_CHANGE;
111
112void callback_namelistchange(Group_Chat *chat, void (*function)(Group_Chat *chat, int peer, uint8_t change, void *), void *userdata);
90 113
91/* 114/*
92 * Send a message to the group. 115 * Send a message to the group.
@@ -95,6 +118,12 @@ void callback_groupmessage(Group_Chat *chat, void (*function)(Group_Chat *chat,
95 */ 118 */
96uint32_t group_sendmessage(Group_Chat *chat, uint8_t *message, uint32_t length); 119uint32_t group_sendmessage(Group_Chat *chat, uint8_t *message, uint32_t length);
97 120
121/*
122 * Set our nick for this group.
123 *
124 * returns -1 on failure, 0 on success.
125 */
126int set_nick(Group_Chat *chat, uint8_t *nick, uint16_t nick_len);
98 127
99/* 128/*
100 * Tell everyone about a new peer (a person we are inviting for example.) 129 * Tell everyone about a new peer (a person we are inviting for example.)
@@ -112,6 +141,18 @@ uint32_t group_newpeer(Group_Chat *chat, uint8_t *client_id);
112Group_Chat *new_groupchat(Networking_Core *net); 141Group_Chat *new_groupchat(Networking_Core *net);
113 142
114 143
144/* Return the number of peers in the group chat.
145 */
146uint32_t group_numpeers(Group_Chat *chat);
147
148/* List all the peers in the group chat.
149 *
150 * Copies the names of the peers to the name[length][MAX_NICK_BYTES] array.
151 *
152 * returns the number of peers.
153 */
154uint32_t group_client_names(Group_Chat *chat, uint8_t names[][MAX_NICK_BYTES], uint16_t length);
155
115/* Kill a group chat 156/* Kill a group chat
116 * 157 *
117 * Frees the memory and everything. 158 * Frees the memory and everything.
diff --git a/toxcore/network.c b/toxcore/network.c
index 5cbc4695..951475f8 100644
--- a/toxcore/network.c
+++ b/toxcore/network.c
@@ -310,9 +310,12 @@ typedef struct {
310 310
311int networking_wait_prepare(Networking_Core *net, uint32_t sendqueue_length, uint8_t *data, uint16_t *lenptr) 311int networking_wait_prepare(Networking_Core *net, uint32_t sendqueue_length, uint8_t *data, uint16_t *lenptr)
312{ 312{
313 if ((data == NULL) || (*lenptr < sizeof(select_info))) { 313 if ((data == NULL) || !lenptr || (*lenptr < sizeof(select_info))) {
314 *lenptr = sizeof(select_info); 314 if (lenptr) {
315 return 0; 315 *lenptr = sizeof(select_info);
316 return 0;
317 } else
318 return -1;
316 } 319 }
317 320
318 *lenptr = sizeof(select_info); 321 *lenptr = sizeof(select_info);
@@ -404,6 +407,10 @@ static int at_startup(void)
404 if (at_startup_ran != 0) 407 if (at_startup_ran != 0)
405 return 0; 408 return 0;
406 409
410#ifndef VANILLA_NACL
411 sodium_init();
412#endif
413
407#ifdef WIN32 414#ifdef WIN32
408 WSADATA wsaData; 415 WSADATA wsaData;
409 416
@@ -678,12 +685,7 @@ int ip_equal(IP *a, IP *b)
678 if (a->family == AF_INET) 685 if (a->family == AF_INET)
679 return (a->ip4.in_addr.s_addr == b->ip4.in_addr.s_addr); 686 return (a->ip4.in_addr.s_addr == b->ip4.in_addr.s_addr);
680 else if (a->family == AF_INET6) 687 else if (a->family == AF_INET6)
681#ifdef WIN32
682 return IN6_ADDR_EQUAL(&a->ip6.in6_addr, &b->ip6.in6_addr);
683
684#else
685 return IN6_ARE_ADDR_EQUAL(&a->ip6.in6_addr, &b->ip6.in6_addr); 688 return IN6_ARE_ADDR_EQUAL(&a->ip6.in6_addr, &b->ip6.in6_addr);
686#endif
687 else 689 else
688 return 0; 690 return 0;
689 } 691 }
diff --git a/toxcore/network.h b/toxcore/network.h
index bb851dcb..88cfaf17 100644
--- a/toxcore/network.h
+++ b/toxcore/network.h
@@ -43,6 +43,18 @@ typedef unsigned int sock_t;
43/* sa_family_t is the sockaddr_in / sockaddr_in6 family field */ 43/* sa_family_t is the sockaddr_in / sockaddr_in6 family field */
44typedef short sa_family_t; 44typedef short sa_family_t;
45 45
46#ifndef IN6_ARE_ADDR_EQUAL
47#ifdef IN6_ADDR_EQUAL
48#define IN6_ARE_ADDR_EQUAL(a,b) IN6_ADDR_EQUAL(a,b)
49#else
50#define IN6_ARE_ADDR_EQUAL(a,b) \
51 ((((__const uint32_t *) (a))[0] == ((__const uint32_t *) (b))[0]) \
52 && (((__const uint32_t *) (a))[1] == ((__const uint32_t *) (b))[1]) \
53 && (((__const uint32_t *) (a))[2] == ((__const uint32_t *) (b))[2]) \
54 && (((__const uint32_t *) (a))[3] == ((__const uint32_t *) (b))[3]))
55#endif
56#endif
57
46#ifndef EWOULDBLOCK 58#ifndef EWOULDBLOCK
47#define EWOULDBLOCK WSAEWOULDBLOCK 59#define EWOULDBLOCK WSAEWOULDBLOCK
48#endif 60#endif
@@ -134,7 +146,7 @@ typedef union {
134 uint8_t uint8[8]; 146 uint8_t uint8[8];
135} IP4_Port; 147} IP4_Port;
136 148
137typedef struct { 149typedef struct IP_Port {
138 IP ip; 150 IP ip;
139 uint16_t port; 151 uint16_t port;
140} IP_Port; 152} IP_Port;
diff --git a/toxcore/ping.c b/toxcore/ping.c
index 80e85a45..e3db6ed1 100644
--- a/toxcore/ping.c
+++ b/toxcore/ping.c
@@ -27,14 +27,16 @@
27#include "config.h" 27#include "config.h"
28#endif 28#endif
29 29
30#include <stdbool.h>
31#include <stdint.h> 30#include <stdint.h>
32 31
33#include "net_crypto.h"
34#include "DHT.h" 32#include "DHT.h"
33#include "assoc.h"
34#include "ping.h"
35
36#include "network.h"
37#include "util.h"
35 38
36#define PING_NUM_MAX 384 39#define PING_NUM_MAX 384
37#define PING_TIMEOUT 5 // 5s
38 40
39/* Ping newly announced nodes to ping per TIME_TOPING seconds*/ 41/* Ping newly announced nodes to ping per TIME_TOPING seconds*/
40#define TIME_TOPING 5 42#define TIME_TOPING 5
@@ -45,7 +47,7 @@ typedef struct {
45 uint64_t timestamp; 47 uint64_t timestamp;
46} pinged_t; 48} pinged_t;
47 49
48typedef struct { 50struct PING {
49 Net_Crypto *c; 51 Net_Crypto *c;
50 52
51 pinged_t pings[PING_NUM_MAX]; 53 pinged_t pings[PING_NUM_MAX];
@@ -54,15 +56,9 @@ typedef struct {
54 56
55 Node_format toping[MAX_TOPING]; 57 Node_format toping[MAX_TOPING];
56 uint64_t last_toping; 58 uint64_t last_toping;
57} PING; 59};
58
59#define __PING_C__
60
61#include "network.h"
62#include "util.h"
63#include "ping.h"
64 60
65static bool is_ping_timeout(uint64_t time) 61static int is_ping_timeout(uint64_t time)
66{ 62{
67 return is_timeout(time, PING_TIMEOUT); 63 return is_timeout(time, PING_TIMEOUT);
68} 64}
@@ -265,7 +261,16 @@ static int handle_ping_response(void *_dht, IP_Port source, uint8_t *packet, uin
265 return 1; 261 return 1;
266 262
267 /* Associate client_id with the ip the request was sent to */ 263 /* Associate client_id with the ip the request was sent to */
268 addto_lists(dht, ping->pings[ping_index - 1].ip_port, packet + 1); 264 int used = addto_lists(dht, ping->pings[ping_index - 1].ip_port, packet + 1);
265
266 if (dht->assoc) {
267 IPPTs ippts;
268 ippts.ip_port = ping->pings[ping_index - 1].ip_port;
269 ippts.timestamp = ping->pings[ping_index - 1].timestamp;
270
271 Assoc_add_entry(dht->assoc, packet + 1, &ippts, &source, used > 0 ? 1 : 0);
272 }
273
269 return 0; 274 return 0;
270} 275}
271 276
diff --git a/toxcore/ping.h b/toxcore/ping.h
index c2437e1b..00e1c697 100644
--- a/toxcore/ping.h
+++ b/toxcore/ping.h
@@ -24,11 +24,7 @@
24#ifndef __PING_H__ 24#ifndef __PING_H__
25#define __PING_H__ 25#define __PING_H__
26 26
27#include <stdbool.h>
28
29#ifndef __PING_C__
30typedef struct PING PING; 27typedef struct PING PING;
31#endif
32 28
33/* Add nodes to the toping list. 29/* Add nodes to the toping list.
34 * All nodes in this list are pinged every TIME_TOPING seconds 30 * All nodes in this list are pinged every TIME_TOPING seconds
diff --git a/toxcore/tox.c b/toxcore/tox.c
index 6a0c6a62..487f2517 100644
--- a/toxcore/tox.c
+++ b/toxcore/tox.c
@@ -37,7 +37,7 @@ typedef struct Messenger Tox;
37 * Format: [client_id (32 bytes)][nospam number (4 bytes)][checksum (2 bytes)] 37 * Format: [client_id (32 bytes)][nospam number (4 bytes)][checksum (2 bytes)]
38 * 38 *
39 */ 39 */
40void tox_getaddress(Tox *tox, uint8_t *address) 40void tox_get_address(Tox *tox, uint8_t *address)
41{ 41{
42 Messenger *m = tox; 42 Messenger *m = tox;
43 getaddress(m, address); 43 getaddress(m, address);
@@ -60,7 +60,7 @@ void tox_getaddress(Tox *tox, uint8_t *address)
60 * (the nospam for that friend was set to the new one). 60 * (the nospam for that friend was set to the new one).
61 * return FAERR_NOMEM if increasing the friend list size fails. 61 * return FAERR_NOMEM if increasing the friend list size fails.
62 */ 62 */
63int tox_addfriend(Tox *tox, uint8_t *address, uint8_t *data, uint16_t length) 63int tox_add_friend(Tox *tox, uint8_t *address, uint8_t *data, uint16_t length)
64{ 64{
65 Messenger *m = tox; 65 Messenger *m = tox;
66 return m_addfriend(m, address, data, length); 66 return m_addfriend(m, address, data, length);
@@ -71,7 +71,7 @@ int tox_addfriend(Tox *tox, uint8_t *address, uint8_t *data, uint16_t length)
71 * return the friend number if success. 71 * return the friend number if success.
72 * return -1 if failure. 72 * return -1 if failure.
73 */ 73 */
74int tox_addfriend_norequest(Tox *tox, uint8_t *client_id) 74int tox_add_friend_norequest(Tox *tox, uint8_t *client_id)
75{ 75{
76 Messenger *m = tox; 76 Messenger *m = tox;
77 return m_addfriend_norequest(m, client_id); 77 return m_addfriend_norequest(m, client_id);
@@ -80,7 +80,7 @@ int tox_addfriend_norequest(Tox *tox, uint8_t *client_id)
80/* return the friend id associated to that client id. 80/* return the friend id associated to that client id.
81 * return -1 if no such friend. 81 * return -1 if no such friend.
82 */ 82 */
83int tox_getfriend_id(Tox *tox, uint8_t *client_id) 83int tox_get_friend_id(Tox *tox, uint8_t *client_id)
84{ 84{
85 Messenger *m = tox; 85 Messenger *m = tox;
86 return getfriend_id(m, client_id); 86 return getfriend_id(m, client_id);
@@ -92,14 +92,14 @@ int tox_getfriend_id(Tox *tox, uint8_t *client_id)
92 * return 0 if success. 92 * return 0 if success.
93 * return -1 if failure. 93 * return -1 if failure.
94 */ 94 */
95int tox_getclient_id(Tox *tox, int friend_id, uint8_t *client_id) 95int tox_get_client_id(Tox *tox, int friend_id, uint8_t *client_id)
96{ 96{
97 Messenger *m = tox; 97 Messenger *m = tox;
98 return getclient_id(m, friend_id, client_id); 98 return getclient_id(m, friend_id, client_id);
99} 99}
100 100
101/* Remove a friend. */ 101/* Remove a friend. */
102int tox_delfriend(Tox *tox, int friendnumber) 102int tox_del_friend(Tox *tox, int friendnumber)
103{ 103{
104 Messenger *m = tox; 104 Messenger *m = tox;
105 return m_delfriend(m, friendnumber); 105 return m_delfriend(m, friendnumber);
@@ -111,7 +111,7 @@ int tox_delfriend(Tox *tox, int friendnumber)
111 * return 0 if friend is not connected to us (Offline). 111 * return 0 if friend is not connected to us (Offline).
112 * return -1 on failure. 112 * return -1 on failure.
113 */ 113 */
114int tox_get_friend_connectionstatus(Tox *tox, int friendnumber) 114int tox_get_friend_connection_status(Tox *tox, int friendnumber)
115{ 115{
116 Messenger *m = tox; 116 Messenger *m = tox;
117 return m_get_friend_connectionstatus(m, friendnumber); 117 return m_get_friend_connectionstatus(m, friendnumber);
@@ -137,13 +137,13 @@ int tox_friend_exists(Tox *tox, int friendnumber)
137 * m_sendmessage_withid will send a message with the id of your choosing, 137 * m_sendmessage_withid will send a message with the id of your choosing,
138 * however we can generate an id for you by calling plain m_sendmessage. 138 * however we can generate an id for you by calling plain m_sendmessage.
139 */ 139 */
140uint32_t tox_sendmessage(Tox *tox, int friendnumber, uint8_t *message, uint32_t length) 140uint32_t tox_send_message(Tox *tox, int friendnumber, uint8_t *message, uint32_t length)
141{ 141{
142 Messenger *m = tox; 142 Messenger *m = tox;
143 return m_sendmessage(m, friendnumber, message, length); 143 return m_sendmessage(m, friendnumber, message, length);
144} 144}
145 145
146uint32_t tox_sendmessage_withid(Tox *tox, int friendnumber, uint32_t theid, uint8_t *message, uint32_t length) 146uint32_t tox_send_message_withid(Tox *tox, int friendnumber, uint32_t theid, uint8_t *message, uint32_t length)
147{ 147{
148 Messenger *m = tox; 148 Messenger *m = tox;
149 return m_sendmessage_withid(m, friendnumber, theid, message, length); 149 return m_sendmessage_withid(m, friendnumber, theid, message, length);
@@ -159,13 +159,13 @@ uint32_t tox_sendmessage_withid(Tox *tox, int friendnumber, uint32_t theid, uint
159 * m_sendaction_withid will send an action message with the id of your choosing, 159 * m_sendaction_withid will send an action message with the id of your choosing,
160 * however we can generate an id for you by calling plain m_sendaction. 160 * however we can generate an id for you by calling plain m_sendaction.
161 */ 161 */
162uint32_t tox_sendaction(Tox *tox, int friendnumber, uint8_t *action, uint32_t length) 162uint32_t tox_send_action(Tox *tox, int friendnumber, uint8_t *action, uint32_t length)
163{ 163{
164 Messenger *m = tox; 164 Messenger *m = tox;
165 return m_sendaction(m, friendnumber, action, length); 165 return m_sendaction(m, friendnumber, action, length);
166} 166}
167 167
168uint32_t tox_sendaction_withid(Tox *tox, int friendnumber, uint32_t theid, uint8_t *action, uint32_t length) 168uint32_t tox_send_action_withid(Tox *tox, int friendnumber, uint32_t theid, uint8_t *action, uint32_t length)
169{ 169{
170 Messenger *m = tox; 170 Messenger *m = tox;
171 return m_sendaction_withid(m, friendnumber, theid, action, length); 171 return m_sendaction_withid(m, friendnumber, theid, action, length);
@@ -179,7 +179,7 @@ uint32_t tox_sendaction_withid(Tox *tox, int friendnumber, uint32_t theid, uint8
179 * return 0 if success. 179 * return 0 if success.
180 * return -1 if failure. 180 * return -1 if failure.
181 */ 181 */
182int tox_setname(Tox *tox, uint8_t *name, uint16_t length) 182int tox_set_name(Tox *tox, uint8_t *name, uint16_t length)
183{ 183{
184 Messenger *m = tox; 184 Messenger *m = tox;
185 return setname(m, name, length); 185 return setname(m, name, length);
@@ -193,7 +193,7 @@ int tox_setname(Tox *tox, uint8_t *name, uint16_t length)
193 * return length of the name. 193 * return length of the name.
194 * return 0 on error. 194 * return 0 on error.
195 */ 195 */
196uint16_t tox_getselfname(Tox *tox, uint8_t *name, uint16_t nlen) 196uint16_t tox_get_self_name(Tox *tox, uint8_t *name, uint16_t nlen)
197{ 197{
198 Messenger *m = tox; 198 Messenger *m = tox;
199 return getself_name(m, name, nlen); 199 return getself_name(m, name, nlen);
@@ -205,7 +205,7 @@ uint16_t tox_getselfname(Tox *tox, uint8_t *name, uint16_t nlen)
205 * return length of name (with the NULL terminator) if success. 205 * return length of name (with the NULL terminator) if success.
206 * return -1 if failure. 206 * return -1 if failure.
207 */ 207 */
208int tox_getname(Tox *tox, int friendnumber, uint8_t *name) 208int tox_get_name(Tox *tox, int friendnumber, uint8_t *name)
209{ 209{
210 Messenger *m = tox; 210 Messenger *m = tox;
211 return getname(m, friendnumber, name); 211 return getname(m, friendnumber, name);
@@ -216,13 +216,13 @@ int tox_getname(Tox *tox, int friendnumber, uint8_t *name)
216 * 216 *
217 * return 0 on success, -1 on failure. 217 * return 0 on success, -1 on failure.
218 */ 218 */
219int tox_set_statusmessage(Tox *tox, uint8_t *status, uint16_t length) 219int tox_set_status_message(Tox *tox, uint8_t *status, uint16_t length)
220{ 220{
221 Messenger *m = tox; 221 Messenger *m = tox;
222 return m_set_statusmessage(m, status, length); 222 return m_set_statusmessage(m, status, length);
223} 223}
224 224
225int tox_set_userstatus(Tox *tox, TOX_USERSTATUS status) 225int tox_set_user_status(Tox *tox, TOX_USERSTATUS status)
226{ 226{
227 Messenger *m = tox; 227 Messenger *m = tox;
228 return m_set_userstatus(m, (USERSTATUS)status); 228 return m_set_userstatus(m, (USERSTATUS)status);
@@ -231,7 +231,7 @@ int tox_set_userstatus(Tox *tox, TOX_USERSTATUS status)
231/* return the length of friendnumber's status message, including null. 231/* return the length of friendnumber's status message, including null.
232 * Pass it into malloc. 232 * Pass it into malloc.
233 */ 233 */
234int tox_get_statusmessage_size(Tox *tox, int friendnumber) 234int tox_get_status_message_size(Tox *tox, int friendnumber)
235{ 235{
236 Messenger *m = tox; 236 Messenger *m = tox;
237 return m_get_statusmessage_size(m, friendnumber); 237 return m_get_statusmessage_size(m, friendnumber);
@@ -241,13 +241,13 @@ int tox_get_statusmessage_size(Tox *tox, int friendnumber)
241 * Get the size you need to allocate from m_get_statusmessage_size. 241 * Get the size you need to allocate from m_get_statusmessage_size.
242 * The self variant will copy our own status message. 242 * The self variant will copy our own status message.
243 */ 243 */
244int tox_copy_statusmessage(Tox *tox, int friendnumber, uint8_t *buf, uint32_t maxlen) 244int tox_get_status_message(Tox *tox, int friendnumber, uint8_t *buf, uint32_t maxlen)
245{ 245{
246 Messenger *m = tox; 246 Messenger *m = tox;
247 return m_copy_statusmessage(m, friendnumber, buf, maxlen); 247 return m_copy_statusmessage(m, friendnumber, buf, maxlen);
248} 248}
249 249
250int tox_copy_self_statusmessage(Tox *tox, uint8_t *buf, uint32_t maxlen) 250int tox_get_self_status_message(Tox *tox, uint8_t *buf, uint32_t maxlen)
251{ 251{
252 Messenger *m = tox; 252 Messenger *m = tox;
253 return m_copy_self_statusmessage(m, buf, maxlen); 253 return m_copy_self_statusmessage(m, buf, maxlen);
@@ -258,13 +258,13 @@ int tox_copy_self_statusmessage(Tox *tox, uint8_t *buf, uint32_t maxlen)
258 * As above, the self variant will return our own USERSTATUS. 258 * As above, the self variant will return our own USERSTATUS.
259 * If friendnumber is invalid, this shall return USERSTATUS_INVALID. 259 * If friendnumber is invalid, this shall return USERSTATUS_INVALID.
260 */ 260 */
261TOX_USERSTATUS tox_get_userstatus(Tox *tox, int friendnumber) 261TOX_USERSTATUS tox_get_user_status(Tox *tox, int friendnumber)
262{ 262{
263 Messenger *m = tox; 263 Messenger *m = tox;
264 return (TOX_USERSTATUS)m_get_userstatus(m, friendnumber); 264 return (TOX_USERSTATUS)m_get_userstatus(m, friendnumber);
265} 265}
266 266
267TOX_USERSTATUS tox_get_selfuserstatus(Tox *tox) 267TOX_USERSTATUS tox_get_self_user_status(Tox *tox)
268{ 268{
269 Messenger *m = tox; 269 Messenger *m = tox;
270 return (TOX_USERSTATUS)m_get_self_userstatus(m); 270 return (TOX_USERSTATUS)m_get_self_userstatus(m);
@@ -294,7 +294,7 @@ uint32_t tox_count_friendlist(Tox *tox)
294 * Otherwise, returns the number of elements copied. 294 * Otherwise, returns the number of elements copied.
295 * If the array was too small, the contents 295 * If the array was too small, the contents
296 * of out_list will be truncated to list_size. */ 296 * of out_list will be truncated to list_size. */
297uint32_t tox_copy_friendlist(Tox *tox, int *out_list, uint32_t list_size) 297uint32_t tox_get_friendlist(Tox *tox, int *out_list, uint32_t list_size)
298{ 298{
299 Messenger *m = tox; 299 Messenger *m = tox;
300 return copy_friendlist(m, out_list, list_size); 300 return copy_friendlist(m, out_list, list_size);
@@ -303,7 +303,7 @@ uint32_t tox_copy_friendlist(Tox *tox, int *out_list, uint32_t list_size)
303/* Set the function that will be executed when a friend request is received. 303/* Set the function that will be executed when a friend request is received.
304 * Function format is function(uint8_t * public_key, uint8_t * data, uint16_t length) 304 * Function format is function(uint8_t * public_key, uint8_t * data, uint16_t length)
305 */ 305 */
306void tox_callback_friendrequest(Tox *tox, void (*function)(uint8_t *, uint8_t *, uint16_t, void *), void *userdata) 306void tox_callback_friend_request(Tox *tox, void (*function)(uint8_t *, uint8_t *, uint16_t, void *), void *userdata)
307{ 307{
308 Messenger *m = tox; 308 Messenger *m = tox;
309 m_callback_friendrequest(m, function, userdata); 309 m_callback_friendrequest(m, function, userdata);
@@ -313,7 +313,7 @@ void tox_callback_friendrequest(Tox *tox, void (*function)(uint8_t *, uint8_t *,
313/* Set the function that will be executed when a message from a friend is received. 313/* Set the function that will be executed when a message from a friend is received.
314 * Function format is: function(int friendnumber, uint8_t * message, uint32_t length) 314 * Function format is: function(int friendnumber, uint8_t * message, uint32_t length)
315 */ 315 */
316void tox_callback_friendmessage(Tox *tox, void (*function)(Messenger *tox, int, uint8_t *, uint16_t, void *), 316void tox_callback_friend_message(Tox *tox, void (*function)(Messenger *tox, int, uint8_t *, uint16_t, void *),
317 void *userdata) 317 void *userdata)
318{ 318{
319 Messenger *m = tox; 319 Messenger *m = tox;
@@ -333,7 +333,7 @@ void tox_callback_action(Tox *tox, void (*function)(Messenger *tox, int, uint8_t
333 * function(int friendnumber, uint8_t *newname, uint16_t length) 333 * function(int friendnumber, uint8_t *newname, uint16_t length)
334 * You are not responsible for freeing newname. 334 * You are not responsible for freeing newname.
335 */ 335 */
336void tox_callback_namechange(Tox *tox, void (*function)(Messenger *tox, int, uint8_t *, uint16_t, void *), 336void tox_callback_name_change(Tox *tox, void (*function)(Messenger *tox, int, uint8_t *, uint16_t, void *),
337 void *userdata) 337 void *userdata)
338{ 338{
339 Messenger *m = tox; 339 Messenger *m = tox;
@@ -344,7 +344,7 @@ void tox_callback_namechange(Tox *tox, void (*function)(Messenger *tox, int, uin
344 * function(int friendnumber, uint8_t *newstatus, uint16_t length) 344 * function(int friendnumber, uint8_t *newstatus, uint16_t length)
345 * You are not responsible for freeing newstatus. 345 * You are not responsible for freeing newstatus.
346 */ 346 */
347void tox_callback_statusmessage(Tox *tox, void (*function)(Messenger *tox, int, uint8_t *, uint16_t, void *), 347void tox_callback_status_message(Tox *tox, void (*function)(Messenger *tox, int, uint8_t *, uint16_t, void *),
348 void *userdata) 348 void *userdata)
349{ 349{
350 Messenger *m = tox; 350 Messenger *m = tox;
@@ -354,7 +354,7 @@ void tox_callback_statusmessage(Tox *tox, void (*function)(Messenger *tox, int,
354/* Set the callback for status type changes. 354/* Set the callback for status type changes.
355 * function(int friendnumber, USERSTATUS kind) 355 * function(int friendnumber, USERSTATUS kind)
356 */ 356 */
357void tox_callback_userstatus(Tox *tox, void (*_function)(Tox *tox, int, TOX_USERSTATUS, void *), void *userdata) 357void tox_callback_user_status(Tox *tox, void (*_function)(Tox *tox, int, TOX_USERSTATUS, void *), void *userdata)
358{ 358{
359 Messenger *m = tox; 359 Messenger *m = tox;
360 typedef void (*function_type)(Messenger *, int, USERSTATUS, void *); 360 typedef void (*function_type)(Messenger *, int, USERSTATUS, void *);
@@ -388,7 +388,7 @@ void tox_callback_read_receipt(Tox *tox, void (*function)(Messenger *tox, int, u
388 * being previously online" part. It's assumed that when adding friends, 388 * being previously online" part. It's assumed that when adding friends,
389 * their connection status is offline. 389 * their connection status is offline.
390 */ 390 */
391void tox_callback_connectionstatus(Tox *tox, void (*function)(Messenger *tox, int, uint8_t, void *), void *userdata) 391void tox_callback_connection_status(Tox *tox, void (*function)(Messenger *tox, int, uint8_t, void *), void *userdata)
392{ 392{
393 Messenger *m = tox; 393 Messenger *m = tox;
394 m_callback_connectionstatus(m, function, userdata); 394 m_callback_connectionstatus(m, function, userdata);
@@ -415,6 +415,19 @@ void tox_callback_group_message(Tox *tox, void (*function)(Messenger *tox, int,
415 Messenger *m = tox; 415 Messenger *m = tox;
416 m_callback_group_message(m, function, userdata); 416 m_callback_group_message(m, function, userdata);
417} 417}
418
419/* Set callback function for peer name list changes.
420 *
421 * It gets called every time the name list changes(new peer/name, deleted peer)
422 * Function(Tox *tox, int groupnumber, void *userdata)
423 */
424
425void tox_callback_group_namelist_change(Tox *tox, void (*function)(Tox *tox, int, int, uint8_t, void *), void *userdata)
426{
427 Messenger *m = tox;
428 m_callback_group_namelistchange(m, function, userdata);
429}
430
418/* Creates a new groupchat and puts it in the chats array. 431/* Creates a new groupchat and puts it in the chats array.
419 * 432 *
420 * return group number on success. 433 * return group number on success.
@@ -477,6 +490,48 @@ int tox_group_message_send(Tox *tox, int groupnumber, uint8_t *message, uint32_t
477 return group_message_send(m, groupnumber, message, length); 490 return group_message_send(m, groupnumber, message, length);
478} 491}
479 492
493/* Return the number of peers in the group chat on success.
494 * return -1 on failure
495 */
496int tox_group_number_peers(Tox *tox, int groupnumber)
497{
498 Messenger *m = tox;
499 return group_number_peers(m, groupnumber);
500}
501
502/* List all the peers in the group chat.
503 *
504 * Copies the names of the peers to the name[length][MAX_NICK_BYTES] array.
505 *
506 * returns the number of peers on success.
507 *
508 * return -1 on failure.
509 */
510int tox_group_get_names(Tox *tox, int groupnumber, uint8_t names[][TOX_MAX_NAME_LENGTH], uint16_t length)
511{
512 Messenger *m = tox;
513 return group_names(m, groupnumber, names, length);
514}
515
516/* Return the number of chats in the instance m.
517 * You should use this to determine how much memory to allocate
518 * for copy_chatlist. */
519uint32_t tox_count_chatlist(Tox *tox)
520{
521 Messenger *m = tox;
522 return count_chatlist(m);
523}
524
525/* Copy a list of valid chat IDs into the array out_list.
526 * If out_list is NULL, returns 0.
527 * Otherwise, returns the number of elements copied.
528 * If the array was too small, the contents
529 * of out_list will be truncated to list_size. */
530uint32_t tox_get_chatlist(Tox *tox, int *out_list, uint32_t list_size)
531{
532 Messenger *m = tox;
533 return copy_chatlist(m, out_list, list_size);
534}
480 535
481 536
482/****************FILE SENDING FUNCTIONS*****************/ 537/****************FILE SENDING FUNCTIONS*****************/
@@ -486,7 +541,7 @@ int tox_group_message_send(Tox *tox, int groupnumber, uint8_t *message, uint32_t
486 * 541 *
487 * Function(Tox *tox, int friendnumber, uint8_t filenumber, uint64_t filesize, uint8_t *filename, uint16_t filename_length, void *userdata) 542 * Function(Tox *tox, int friendnumber, uint8_t filenumber, uint64_t filesize, uint8_t *filename, uint16_t filename_length, void *userdata)
488 */ 543 */
489void tox_callback_file_sendrequest(Tox *tox, void (*function)(Messenger *tox, int, uint8_t, uint64_t, uint8_t *, 544void tox_callback_file_send_request(Tox *tox, void (*function)(Messenger *tox, int, uint8_t, uint64_t, uint8_t *,
490 uint16_t, 545 uint16_t,
491 void *), void *userdata) 546 void *), void *userdata)
492{ 547{
@@ -522,7 +577,7 @@ void tox_callback_file_data(Tox *tox, void (*function)(Messenger *tox, int, uint
522 * return file number on success 577 * return file number on success
523 * return -1 on failure 578 * return -1 on failure
524 */ 579 */
525int tox_new_filesender(Tox *tox, int friendnumber, uint64_t filesize, uint8_t *filename, uint16_t filename_length) 580int tox_new_file_sender(Tox *tox, int friendnumber, uint64_t filesize, uint8_t *filename, uint16_t filename_length)
526{ 581{
527 Messenger *m = tox; 582 Messenger *m = tox;
528 return new_filesender(m, friendnumber, filesize, filename, filename_length); 583 return new_filesender(m, friendnumber, filesize, filename, filename_length);
@@ -530,10 +585,10 @@ int tox_new_filesender(Tox *tox, int friendnumber, uint64_t filesize, uint8_t *f
530/* Send a file control request. 585/* Send a file control request.
531 * send_receive is 0 if we want the control packet to target a sending file, 1 if it targets a receiving file. 586 * send_receive is 0 if we want the control packet to target a sending file, 1 if it targets a receiving file.
532 * 587 *
533 * return 1 on success 588 * return 0 on success
534 * return 0 on failure 589 * return -1 on failure
535 */ 590 */
536int tox_file_sendcontrol(Tox *tox, int friendnumber, uint8_t send_receive, uint8_t filenumber, uint8_t message_id, 591int tox_file_send_control(Tox *tox, int friendnumber, uint8_t send_receive, uint8_t filenumber, uint8_t message_id,
537 uint8_t *data, uint16_t length) 592 uint8_t *data, uint16_t length)
538{ 593{
539 Messenger *m = tox; 594 Messenger *m = tox;
@@ -541,21 +596,21 @@ int tox_file_sendcontrol(Tox *tox, int friendnumber, uint8_t send_receive, uint8
541} 596}
542/* Send file data. 597/* Send file data.
543 * 598 *
544 * return 1 on success 599 * return 0 on success
545 * return 0 on failure 600 * return -1 on failure
546 */ 601 */
547int tox_file_senddata(Tox *tox, int friendnumber, uint8_t filenumber, uint8_t *data, uint16_t length) 602int tox_file_send_data(Tox *tox, int friendnumber, uint8_t filenumber, uint8_t *data, uint16_t length)
548{ 603{
549 Messenger *m = tox; 604 Messenger *m = tox;
550 return file_data(m, friendnumber, filenumber, data, length); 605 return file_data(m, friendnumber, filenumber, data, length);
551} 606}
552 607
553/* Returns the recommended/maximum size of the filedata you send with tox_file_senddata() 608/* Returns the recommended/maximum size of the filedata you send with tox_file_send_data()
554 * 609 *
555 * return size on success 610 * return size on success
556 * return 0 on failure (currently will never return 0) 611 * return -1 on failure (currently will never return -1)
557 */ 612 */
558int tox_filedata_size(Tox *tox, int friendnumber) 613int tox_file_data_size(Tox *tox, int friendnumber)
559{ 614{
560 return MAX_DATA_SIZE - crypto_box_MACBYTES - 3; 615 return MAX_DATA_SIZE - crypto_box_MACBYTES - 3;
561} 616}
@@ -567,7 +622,7 @@ int tox_filedata_size(Tox *tox, int friendnumber)
567 * return number of bytes remaining to be sent/received on success 622 * return number of bytes remaining to be sent/received on success
568 * return 0 on failure 623 * return 0 on failure
569 */ 624 */
570uint64_t tox_file_dataremaining(Tox *tox, int friendnumber, uint8_t filenumber, uint8_t send_receive) 625uint64_t tox_file_data_remaining(Tox *tox, int friendnumber, uint8_t filenumber, uint8_t send_receive)
571{ 626{
572 Messenger *m = tox; 627 Messenger *m = tox;
573 return file_dataremaining(m, friendnumber, filenumber, send_receive); 628 return file_dataremaining(m, friendnumber, filenumber, send_receive);
diff --git a/toxcore/tox.h b/toxcore/tox.h
index 13e9c7a9..9f84876e 100644
--- a/toxcore/tox.h
+++ b/toxcore/tox.h
@@ -129,7 +129,7 @@ typedef struct Tox Tox;
129/* return FRIEND_ADDRESS_SIZE byte address to give to others. 129/* return FRIEND_ADDRESS_SIZE byte address to give to others.
130 * format: [client_id (32 bytes)][nospam number (4 bytes)][checksum (2 bytes)] 130 * format: [client_id (32 bytes)][nospam number (4 bytes)][checksum (2 bytes)]
131 */ 131 */
132void tox_getaddress(Tox *tox, uint8_t *address); 132void tox_get_address(Tox *tox, uint8_t *address);
133 133
134/* Add a friend. 134/* Add a friend.
135 * Set the data that will be sent along with friend request. 135 * Set the data that will be sent along with friend request.
@@ -147,28 +147,28 @@ void tox_getaddress(Tox *tox, uint8_t *address);
147 * (the nospam for that friend was set to the new one). 147 * (the nospam for that friend was set to the new one).
148 * return TOX_FAERR_NOMEM if increasing the friend list size fails. 148 * return TOX_FAERR_NOMEM if increasing the friend list size fails.
149 */ 149 */
150int tox_addfriend(Tox *tox, uint8_t *address, uint8_t *data, uint16_t length); 150int tox_add_friend(Tox *tox, uint8_t *address, uint8_t *data, uint16_t length);
151 151
152 152
153/* Add a friend without sending a friendrequest. 153/* Add a friend without sending a friendrequest.
154 * return the friend number if success. 154 * return the friend number if success.
155 * return -1 if failure. 155 * return -1 if failure.
156 */ 156 */
157int tox_addfriend_norequest(Tox *tox, uint8_t *client_id); 157int tox_add_friend_norequest(Tox *tox, uint8_t *client_id);
158 158
159/* return the friend id associated to that client id. 159/* return the friend id associated to that client id.
160 return -1 if no such friend */ 160 return -1 if no such friend */
161int tox_getfriend_id(Tox *tox, uint8_t *client_id); 161int tox_get_friend_id(Tox *tox, uint8_t *client_id);
162 162
163/* Copies the public key associated to that friend id into client_id buffer. 163/* Copies the public key associated to that friend id into client_id buffer.
164 * Make sure that client_id is of size CLIENT_ID_SIZE. 164 * Make sure that client_id is of size CLIENT_ID_SIZE.
165 * return 0 if success. 165 * return 0 if success.
166 * return -1 if failure. 166 * return -1 if failure.
167 */ 167 */
168int tox_getclient_id(Tox *tox, int friend_id, uint8_t *client_id); 168int tox_get_client_id(Tox *tox, int friend_id, uint8_t *client_id);
169 169
170/* Remove a friend. */ 170/* Remove a friend. */
171int tox_delfriend(Tox *tox, int friendnumber); 171int tox_del_friend(Tox *tox, int friendnumber);
172 172
173/* Checks friend's connecting status. 173/* Checks friend's connecting status.
174 * 174 *
@@ -176,7 +176,7 @@ int tox_delfriend(Tox *tox, int friendnumber);
176 * return 0 if friend is not connected to us (Offline). 176 * return 0 if friend is not connected to us (Offline).
177 * return -1 on failure. 177 * return -1 on failure.
178 */ 178 */
179int tox_get_friend_connectionstatus(Tox *tox, int friendnumber); 179int tox_get_friend_connection_status(Tox *tox, int friendnumber);
180 180
181/* Checks if there exists a friend with given friendnumber. 181/* Checks if there exists a friend with given friendnumber.
182 * 182 *
@@ -195,8 +195,8 @@ int tox_friend_exists(Tox *tox, int friendnumber);
195 * m_sendmessage_withid will send a message with the id of your choosing, 195 * m_sendmessage_withid will send a message with the id of your choosing,
196 * however we can generate an id for you by calling plain m_sendmessage. 196 * however we can generate an id for you by calling plain m_sendmessage.
197 */ 197 */
198uint32_t tox_sendmessage(Tox *tox, int friendnumber, uint8_t *message, uint32_t length); 198uint32_t tox_send_message(Tox *tox, int friendnumber, uint8_t *message, uint32_t length);
199uint32_t tox_sendmessage_withid(Tox *tox, int friendnumber, uint32_t theid, uint8_t *message, uint32_t length); 199uint32_t tox_send_message_withid(Tox *tox, int friendnumber, uint32_t theid, uint8_t *message, uint32_t length);
200 200
201/* Send an action to an online friend. 201/* Send an action to an online friend.
202 * 202 *
@@ -208,8 +208,8 @@ uint32_t tox_sendmessage_withid(Tox *tox, int friendnumber, uint32_t theid, uint
208 * m_sendaction_withid will send an action message with the id of your choosing, 208 * m_sendaction_withid will send an action message with the id of your choosing,
209 * however we can generate an id for you by calling plain m_sendaction. 209 * however we can generate an id for you by calling plain m_sendaction.
210 */ 210 */
211uint32_t tox_sendaction(Tox *tox, int friendnumber, uint8_t *action, uint32_t length); 211uint32_t tox_send_action(Tox *tox, int friendnumber, uint8_t *action, uint32_t length);
212uint32_t tox_sendaction_withid(Tox *tox, int friendnumber, uint32_t theid, uint8_t *action, uint32_t length); 212uint32_t tox_send_action_withid(Tox *tox, int friendnumber, uint32_t theid, uint8_t *action, uint32_t length);
213 213
214/* Set our nickname. 214/* Set our nickname.
215 * name must be a string of maximum MAX_NAME_LENGTH length. 215 * name must be a string of maximum MAX_NAME_LENGTH length.
@@ -219,7 +219,7 @@ uint32_t tox_sendaction_withid(Tox *tox, int friendnumber, uint32_t theid, uint8
219 * return 0 if success. 219 * return 0 if success.
220 * return -1 if failure. 220 * return -1 if failure.
221 */ 221 */
222int tox_setname(Tox *tox, uint8_t *name, uint16_t length); 222int tox_set_name(Tox *tox, uint8_t *name, uint16_t length);
223 223
224/* 224/*
225 * Get your nickname. 225 * Get your nickname.
@@ -230,7 +230,7 @@ int tox_setname(Tox *tox, uint8_t *name, uint16_t length);
230 * return length of name. 230 * return length of name.
231 * return 0 on error. 231 * return 0 on error.
232 */ 232 */
233uint16_t tox_getselfname(Tox *tox, uint8_t *name, uint16_t nlen); 233uint16_t tox_get_self_name(Tox *tox, uint8_t *name, uint16_t nlen);
234 234
235/* Get name of friendnumber and put it in name. 235/* Get name of friendnumber and put it in name.
236 * name needs to be a valid memory location with a size of at least MAX_NAME_LENGTH (128) bytes. 236 * name needs to be a valid memory location with a size of at least MAX_NAME_LENGTH (128) bytes.
@@ -238,7 +238,7 @@ uint16_t tox_getselfname(Tox *tox, uint8_t *name, uint16_t nlen);
238 * return length of name (with the NULL terminator) if success. 238 * return length of name (with the NULL terminator) if success.
239 * return -1 if failure. 239 * return -1 if failure.
240 */ 240 */
241int tox_getname(Tox *tox, int friendnumber, uint8_t *name); 241int tox_get_name(Tox *tox, int friendnumber, uint8_t *name);
242 242
243/* Set our user status. 243/* Set our user status.
244 * You are responsible for freeing status after. 244 * You are responsible for freeing status after.
@@ -246,13 +246,13 @@ int tox_getname(Tox *tox, int friendnumber, uint8_t *name);
246 * returns 0 on success. 246 * returns 0 on success.
247 * returns -1 on failure. 247 * returns -1 on failure.
248 */ 248 */
249int tox_set_statusmessage(Tox *tox, uint8_t *status, uint16_t length); 249int tox_set_status_message(Tox *tox, uint8_t *status, uint16_t length);
250int tox_set_userstatus(Tox *tox, TOX_USERSTATUS status); 250int tox_set_user_status(Tox *tox, TOX_USERSTATUS status);
251 251
252/* return the length of friendnumber's status message, including null. 252/* return the length of friendnumber's status message, including null.
253 * Pass it into malloc 253 * Pass it into malloc
254 */ 254 */
255int tox_get_statusmessage_size(Tox *tox, int friendnumber); 255int tox_get_status_message_size(Tox *tox, int friendnumber);
256 256
257/* Copy friendnumber's status message into buf, truncating if size is over maxlen. 257/* Copy friendnumber's status message into buf, truncating if size is over maxlen.
258 * Get the size you need to allocate from m_get_statusmessage_size. 258 * Get the size you need to allocate from m_get_statusmessage_size.
@@ -261,16 +261,16 @@ int tox_get_statusmessage_size(Tox *tox, int friendnumber);
261 * returns the length of the copied data on success 261 * returns the length of the copied data on success
262 * retruns -1 on failure. 262 * retruns -1 on failure.
263 */ 263 */
264int tox_copy_statusmessage(Tox *tox, int friendnumber, uint8_t *buf, uint32_t maxlen); 264int tox_get_status_message(Tox *tox, int friendnumber, uint8_t *buf, uint32_t maxlen);
265int tox_copy_self_statusmessage(Tox *tox, uint8_t *buf, uint32_t maxlen); 265int tox_get_self_status_message(Tox *tox, uint8_t *buf, uint32_t maxlen);
266 266
267/* return one of USERSTATUS values. 267/* return one of USERSTATUS values.
268 * Values unknown to your application should be represented as USERSTATUS_NONE. 268 * Values unknown to your application should be represented as USERSTATUS_NONE.
269 * As above, the self variant will return our own USERSTATUS. 269 * As above, the self variant will return our own USERSTATUS.
270 * If friendnumber is invalid, this shall return USERSTATUS_INVALID. 270 * If friendnumber is invalid, this shall return USERSTATUS_INVALID.
271 */ 271 */
272TOX_USERSTATUS tox_get_userstatus(Tox *tox, int friendnumber); 272TOX_USERSTATUS tox_get_user_status(Tox *tox, int friendnumber);
273TOX_USERSTATUS tox_get_selfuserstatus(Tox *tox); 273TOX_USERSTATUS tox_get_self_user_status(Tox *tox);
274 274
275/* Sets whether we send read receipts for friendnumber. 275/* Sets whether we send read receipts for friendnumber.
276 * This function is not lazy, and it will fail if yesno is not (0 or 1). 276 * This function is not lazy, and it will fail if yesno is not (0 or 1).
@@ -287,17 +287,17 @@ uint32_t tox_count_friendlist(Tox *tox);
287 * Otherwise, returns the number of elements copied. 287 * Otherwise, returns the number of elements copied.
288 * If the array was too small, the contents 288 * If the array was too small, the contents
289 * of out_list will be truncated to list_size. */ 289 * of out_list will be truncated to list_size. */
290uint32_t tox_copy_friendlist(Tox *tox, int *out_list, uint32_t list_size); 290uint32_t tox_get_friendlist(Tox *tox, int *out_list, uint32_t list_size);
291 291
292/* Set the function that will be executed when a friend request is received. 292/* Set the function that will be executed when a friend request is received.
293 * Function format is function(uint8_t * public_key, uint8_t * data, uint16_t length) 293 * Function format is function(uint8_t * public_key, uint8_t * data, uint16_t length)
294 */ 294 */
295void tox_callback_friendrequest(Tox *tox, void (*function)(uint8_t *, uint8_t *, uint16_t, void *), void *userdata); 295void tox_callback_friend_request(Tox *tox, void (*function)(uint8_t *, uint8_t *, uint16_t, void *), void *userdata);
296 296
297/* Set the function that will be executed when a message from a friend is received. 297/* Set the function that will be executed when a message from a friend is received.
298 * Function format is: function(int friendnumber, uint8_t * message, uint32_t length) 298 * Function format is: function(int friendnumber, uint8_t * message, uint32_t length)
299 */ 299 */
300void tox_callback_friendmessage(Tox *tox, void (*function)(Tox *tox, int, uint8_t *, uint16_t, void *), 300void tox_callback_friend_message(Tox *tox, void (*function)(Tox *tox, int, uint8_t *, uint16_t, void *),
301 void *userdata); 301 void *userdata);
302 302
303/* Set the function that will be executed when an action from a friend is received. 303/* Set the function that will be executed when an action from a friend is received.
@@ -309,20 +309,20 @@ void tox_callback_action(Tox *tox, void (*function)(Tox *tox, int, uint8_t *, ui
309 * function(int friendnumber, uint8_t *newname, uint16_t length) 309 * function(int friendnumber, uint8_t *newname, uint16_t length)
310 * You are not responsible for freeing newname 310 * You are not responsible for freeing newname
311 */ 311 */
312void tox_callback_namechange(Tox *tox, void (*function)(Tox *tox, int, uint8_t *, uint16_t, void *), 312void tox_callback_name_change(Tox *tox, void (*function)(Tox *tox, int, uint8_t *, uint16_t, void *),
313 void *userdata); 313 void *userdata);
314 314
315/* Set the callback for status message changes. 315/* Set the callback for status message changes.
316 * function(int friendnumber, uint8_t *newstatus, uint16_t length) 316 * function(int friendnumber, uint8_t *newstatus, uint16_t length)
317 * You are not responsible for freeing newstatus. 317 * You are not responsible for freeing newstatus.
318 */ 318 */
319void tox_callback_statusmessage(Tox *tox, void (*function)(Tox *tox, int, uint8_t *, uint16_t, void *), 319void tox_callback_status_message(Tox *tox, void (*function)(Tox *tox, int, uint8_t *, uint16_t, void *),
320 void *userdata); 320 void *userdata);
321 321
322/* Set the callback for status type changes. 322/* Set the callback for status type changes.
323 * function(int friendnumber, USERSTATUS kind) 323 * function(int friendnumber, USERSTATUS kind)
324 */ 324 */
325void tox_callback_userstatus(Tox *tox, void (*function)(Tox *tox, int, TOX_USERSTATUS, void *), void *userdata); 325void tox_callback_user_status(Tox *tox, void (*function)(Tox *tox, int, TOX_USERSTATUS, void *), void *userdata);
326 326
327/* Set the callback for read receipts. 327/* Set the callback for read receipts.
328 * function(int friendnumber, uint32_t receipt) 328 * function(int friendnumber, uint32_t receipt)
@@ -346,7 +346,7 @@ void tox_callback_read_receipt(Tox *tox, void (*function)(Tox *tox, int, uint32_
346 * being previously online" part. it's assumed that when adding friends, 346 * being previously online" part. it's assumed that when adding friends,
347 * their connection status is offline. 347 * their connection status is offline.
348 */ 348 */
349void tox_callback_connectionstatus(Tox *tox, void (*function)(Tox *tox, int, uint8_t, void *), void *userdata); 349void tox_callback_connection_status(Tox *tox, void (*function)(Tox *tox, int, uint8_t, void *), void *userdata);
350 350
351/**********GROUP CHAT FUNCTIONS: WARNING WILL BREAK A LOT************/ 351/**********GROUP CHAT FUNCTIONS: WARNING WILL BREAK A LOT************/
352 352
@@ -363,6 +363,19 @@ void tox_callback_group_invite(Tox *tox, void (*function)(Tox *tox, int, uint8_t
363void tox_callback_group_message(Tox *tox, void (*function)(Tox *tox, int, int, uint8_t *, uint16_t, void *), 363void tox_callback_group_message(Tox *tox, void (*function)(Tox *tox, int, int, uint8_t *, uint16_t, void *),
364 void *userdata); 364 void *userdata);
365 365
366/* Set callback function for peer name list changes.
367 *
368 * It gets called every time the name list changes(new peer/name, deleted peer)
369 * Function(Tox *tox, int groupnumber, int peernumber, TOX_CHAT_CHANGE change, void *userdata)
370 */
371typedef enum {
372 TOX_CHAT_CHANGE_PEER_ADD,
373 TOX_CHAT_CHANGE_PEER_DEL,
374 TOX_CHAT_CHANGE_PEER_NAME,
375} TOX_CHAT_CHANGE;
376
377void tox_callback_group_namelist_change(Tox *tox, void (*function)(Tox *tox, int, int, uint8_t, void *), void *userdata);
378
366/* Creates a new groupchat and puts it in the chats array. 379/* Creates a new groupchat and puts it in the chats array.
367 * 380 *
368 * return group number on success. 381 * return group number on success.
@@ -398,31 +411,57 @@ int tox_invite_friend(Tox *tox, int friendnumber, int groupnumber);
398 */ 411 */
399int tox_join_groupchat(Tox *tox, int friendnumber, uint8_t *friend_group_public_key); 412int tox_join_groupchat(Tox *tox, int friendnumber, uint8_t *friend_group_public_key);
400 413
401
402/* send a group message 414/* send a group message
403 * return 0 on success 415 * return 0 on success
404 * return -1 on failure 416 * return -1 on failure
405 */ 417 */
406int tox_group_message_send(Tox *tox, int groupnumber, uint8_t *message, uint32_t length); 418int tox_group_message_send(Tox *tox, int groupnumber, uint8_t *message, uint32_t length);
407 419
420/* Return the number of peers in the group chat on success.
421 * return -1 on failure
422 */
423int tox_group_number_peers(Tox *tox, int groupnumber);
424
425/* List all the peers in the group chat.
426 *
427 * Copies the names of the peers to the name[length][TOX_MAX_NAME_LENGTH] array.
428 *
429 * returns the number of peers on success.
430 *
431 * return -1 on failure.
432 */
433int tox_group_get_names(Tox *tox, int groupnumber, uint8_t names[][TOX_MAX_NAME_LENGTH], uint16_t length);
434
435/* Return the number of chats in the instance m.
436 * You should use this to determine how much memory to allocate
437 * for copy_chatlist. */
438uint32_t tox_count_chatlist(Tox *tox);
439
440/* Copy a list of valid chat IDs into the array out_list.
441 * If out_list is NULL, returns 0.
442 * Otherwise, returns the number of elements copied.
443 * If the array was too small, the contents
444 * of out_list will be truncated to list_size. */
445uint32_t tox_get_chatlist(Tox *tox, int *out_list, uint32_t list_size);
446
408 447
409/****************FILE SENDING FUNCTIONS*****************/ 448/****************FILE SENDING FUNCTIONS*****************/
410/* NOTE: This how to will be updated. 449/* NOTE: This how to will be updated.
411 * 450 *
412 * HOW TO SEND FILES CORRECTLY: 451 * HOW TO SEND FILES CORRECTLY:
413 * 1. Use tox_new_filesender(...) to create a new file sender. 452 * 1. Use tox_new_file_sender(...) to create a new file sender.
414 * 2. Wait for the callback set with tox_callback_file_control(...) to be called with receive_send == 1 and control_type == TOX_FILECONTROL_ACCEPT 453 * 2. Wait for the callback set with tox_callback_file_control(...) to be called with receive_send == 1 and control_type == TOX_FILECONTROL_ACCEPT
415 * 3. Send the data with tox_file_senddata(...) with chunk size tox_filedata_size(...) 454 * 3. Send the data with tox_file_send_data(...) with chunk size tox_file_data_size(...)
416 * 4. When sending is done, send a tox_file_sendcontrol(...) with send_receive = 0 and message_id = TOX_FILECONTROL_FINISHED 455 * 4. When sending is done, send a tox_file_send_control(...) with send_receive = 0 and message_id = TOX_FILECONTROL_FINISHED
417 * 456 *
418 * HOW TO RECEIVE FILES CORRECTLY: 457 * HOW TO RECEIVE FILES CORRECTLY:
419 * 1. wait for the callback set with tox_callback_file_sendrequest(...) 458 * 1. wait for the callback set with tox_callback_file_send_request(...)
420 * 2. accept or refuse the connection with tox_file_sendcontrol(...) with send_receive = 1 and message_id = TOX_FILECONTROL_ACCEPT or TOX_FILECONTROL_KILL 459 * 2. accept or refuse the connection with tox_file_send_control(...) with send_receive = 1 and message_id = TOX_FILECONTROL_ACCEPT or TOX_FILECONTROL_KILL
421 * 3. save all the data received with the callback set with tox_callback_file_data(...) to a file. 460 * 3. save all the data received with the callback set with tox_callback_file_data(...) to a file.
422 * 4. when the callback set with tox_callback_file_control(...) is called with receive_send == 0 and control_type == TOX_FILECONTROL_FINISHED 461 * 4. when the callback set with tox_callback_file_control(...) is called with receive_send == 0 and control_type == TOX_FILECONTROL_FINISHED
423 * the file is done transferring. 462 * the file is done transferring.
424 * 463 *
425 * tox_file_dataremaining(...) can be used to know how many bytes are left to send/receive. 464 * tox_file_data_remaining(...) can be used to know how many bytes are left to send/receive.
426 * 465 *
427 * If the connection breaks during file sending (The other person goes offline without pausing the sending and then comes back) 466 * If the connection breaks during file sending (The other person goes offline without pausing the sending and then comes back)
428 * the reciever must send a control packet with receive_send == 0 message_id = TOX_FILECONTROL_RESUME_BROKEN and the data being 467 * the reciever must send a control packet with receive_send == 0 message_id = TOX_FILECONTROL_RESUME_BROKEN and the data being
@@ -445,7 +484,7 @@ enum {
445 * 484 *
446 * Function(Tox *tox, int friendnumber, uint8_t filenumber, uint64_t filesize, uint8_t *filename, uint16_t filename_length, void *userdata) 485 * Function(Tox *tox, int friendnumber, uint8_t filenumber, uint64_t filesize, uint8_t *filename, uint16_t filename_length, void *userdata)
447 */ 486 */
448void tox_callback_file_sendrequest(Tox *tox, void (*function)(Tox *m, int, uint8_t, uint64_t, uint8_t *, uint16_t, 487void tox_callback_file_send_request(Tox *tox, void (*function)(Tox *m, int, uint8_t, uint64_t, uint8_t *, uint16_t,
449 void *), void *userdata); 488 void *), void *userdata);
450 489
451/* Set the callback for file control requests. 490/* Set the callback for file control requests.
@@ -473,32 +512,32 @@ void tox_callback_file_data(Tox *tox, void (*function)(Tox *m, int, uint8_t, uin
473 * return file number on success 512 * return file number on success
474 * return -1 on failure 513 * return -1 on failure
475 */ 514 */
476int tox_new_filesender(Tox *tox, int friendnumber, uint64_t filesize, uint8_t *filename, uint16_t filename_length); 515int tox_new_file_sender(Tox *tox, int friendnumber, uint64_t filesize, uint8_t *filename, uint16_t filename_length);
477 516
478/* Send a file control request. 517/* Send a file control request.
479 * 518 *
480 * send_receive is 0 if we want the control packet to target a file we are currently sending, 519 * send_receive is 0 if we want the control packet to target a file we are currently sending,
481 * 1 if it targets a file we are currently receiving. 520 * 1 if it targets a file we are currently receiving.
482 * 521 *
483 * return 1 on success 522 * return 0 on success
484 * return 0 on failure 523 * return -1 on failure
485 */ 524 */
486int tox_file_sendcontrol(Tox *tox, int friendnumber, uint8_t send_receive, uint8_t filenumber, uint8_t message_id, 525int tox_file_send_control(Tox *tox, int friendnumber, uint8_t send_receive, uint8_t filenumber, uint8_t message_id,
487 uint8_t *data, uint16_t length); 526 uint8_t *data, uint16_t length);
488 527
489/* Send file data. 528/* Send file data.
490 * 529 *
491 * return 1 on success 530 * return 0 on success
492 * return 0 on failure 531 * return -1 on failure
493 */ 532 */
494int tox_file_senddata(Tox *tox, int friendnumber, uint8_t filenumber, uint8_t *data, uint16_t length); 533int tox_file_send_data(Tox *tox, int friendnumber, uint8_t filenumber, uint8_t *data, uint16_t length);
495 534
496/* Returns the recommended/maximum size of the filedata you send with tox_file_senddata() 535/* Returns the recommended/maximum size of the filedata you send with tox_file_send_data()
497 * 536 *
498 * return size on success 537 * return size on success
499 * return 0 on failure (currently will never return 0) 538 * return -1 on failure (currently will never return -1)
500 */ 539 */
501int tox_filedata_size(Tox *tox, int friendnumber); 540int tox_file_data_size(Tox *tox, int friendnumber);
502 541
503/* Give the number of bytes left to be sent/received. 542/* Give the number of bytes left to be sent/received.
504 * 543 *
@@ -507,7 +546,7 @@ int tox_filedata_size(Tox *tox, int friendnumber);
507 * return number of bytes remaining to be sent/received on success 546 * return number of bytes remaining to be sent/received on success
508 * return 0 on failure 547 * return 0 on failure
509 */ 548 */
510uint64_t tox_file_dataremaining(Tox *tox, int friendnumber, uint8_t filenumber, uint8_t send_receive); 549uint64_t tox_file_data_remaining(Tox *tox, int friendnumber, uint8_t filenumber, uint8_t send_receive);
511 550
512/***************END OF FILE SENDING FUNCTIONS******************/ 551/***************END OF FILE SENDING FUNCTIONS******************/
513 552
@@ -567,10 +606,11 @@ void tox_do(Tox *tox);
567 * Prepares the data required to call tox_wait_execute() asynchronously 606 * Prepares the data required to call tox_wait_execute() asynchronously
568 * 607 *
569 * data[] is reserved and kept by the caller 608 * data[] is reserved and kept by the caller
570 * len is in/out: in = reserved data[], out = required data[] 609 * *lenptr is in/out: in = reserved data[], out = required data[]
571 * 610 *
572 * returns 1 on success 611 * returns 1 on success
573 * returns 0 on failure (length is insufficient) 612 * returns 0 if *lenptr is insufficient
613 * returns -1 if lenptr is NULL
574 * 614 *
575 * 615 *
576 * tox_wait_execute(): function can be called asynchronously 616 * tox_wait_execute(): function can be called asynchronously