diff options
Diffstat (limited to 'toxcore')
-rw-r--r-- | toxcore/DHT.c | 326 | ||||
-rw-r--r-- | toxcore/DHT.h | 40 | ||||
-rw-r--r-- | toxcore/LAN_discovery.c | 11 | ||||
-rw-r--r-- | toxcore/Makefile.inc | 2 | ||||
-rw-r--r-- | toxcore/Messenger.c | 339 | ||||
-rw-r--r-- | toxcore/Messenger.h | 36 | ||||
-rw-r--r-- | toxcore/assoc.c | 926 | ||||
-rw-r--r-- | toxcore/assoc.h | 93 | ||||
-rw-r--r-- | toxcore/friend_requests.c | 10 | ||||
-rw-r--r-- | toxcore/friend_requests.h | 10 | ||||
-rw-r--r-- | toxcore/group_chats.c | 204 | ||||
-rw-r--r-- | toxcore/group_chats.h | 45 | ||||
-rw-r--r-- | toxcore/network.c | 18 | ||||
-rw-r--r-- | toxcore/network.h | 14 | ||||
-rw-r--r-- | toxcore/ping.c | 31 | ||||
-rw-r--r-- | toxcore/ping.h | 4 | ||||
-rw-r--r-- | toxcore/tox.c | 135 | ||||
-rw-r--r-- | toxcore/tox.h | 140 |
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 | ||
118 | static 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 | */ |
376 | static uint32_t get_close_nodes(DHT *dht, uint8_t *client_id, Node_format *nodes_list, sa_family_t sa_family, | 354 | static 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 | ||
368 | static 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 */ | ||
455 | static int replace_good( Client_data *list, | 491 | static 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 | */ |
508 | void addto_lists(DHT *dht, IP_Port ip_port, uint8_t *client_id) | 554 | int 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 | */ |
546 | static void returnedip_ports(DHT *dht, IP_Port ip_port, uint8_t *client_id, uint8_t *nodeclient_id) | 600 | static 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 | ||
1058 | static void do_ping_and_sendnode_requests(DHT *dht, uint64_t *lastgetnode, uint8_t *client_id, | 1167 | /* returns number of nodes not in kill-timeout */ |
1168 | static 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 | */ |
1113 | static void do_Close(DHT *dht) | 1228 | static 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 | ||
1119 | void DHT_bootstrap(DHT *dht, IP_Port ip_port, uint8_t *public_key) | 1254 | void 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 | } |
1123 | int DHT_bootstrap_from_address(DHT *dht, const char *address, uint8_t ipv6enabled, | 1266 | int 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 | } |
1860 | void kill_DHT(DHT *dht) | 2005 | void 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 | |||
52 | typedef struct { | ||
53 | IP_Port ip_port; | ||
54 | uint64_t timestamp; | ||
55 | } IPPTs; | ||
56 | |||
41 | typedef struct { | 57 | typedef 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 { | |||
113 | typedef struct { | 129 | typedef 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 | ||
129 | Client_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 | */ |
248 | int DHT_isconnected(DHT *dht); | 266 | int DHT_isconnected(DHT *dht); |
249 | 267 | ||
250 | void addto_lists(DHT *dht, IP_Port ip_port, uint8_t *client_id); | 268 | int 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 | ||
32 | libtoxcore_la_CFLAGS = -I$(top_srcdir) \ | 34 | libtoxcore_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 | */ | ||
713 | static 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 | } |
758 | static 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 | */ | ||
788 | void 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 | ||
794 | static 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 | |||
804 | static 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 | ||
815 | static 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 | ||
961 | int group_message_send(Messenger *m, int groupnumber, uint8_t *message, uint32_t length) | 1023 | int 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 | */ | ||
1037 | int 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 | */ | ||
1053 | int 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 | |||
978 | static int handle_group(void *object, IP_Port source, uint8_t *packet, uint32_t length) | 1061 | static 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_ | |||
1078 | int new_filesender(Messenger *m, int friendnumber, uint64_t filesize, uint8_t *filename, uint16_t filename_length) | 1161 | int 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 | */ |
1108 | int file_control(Messenger *m, int friendnumber, uint8_t send_receive, uint8_t filenumber, uint8_t message_id, | 1191 | int 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 | */ |
1196 | int file_data(Messenger *m, int friendnumber, uint8_t filenumber, uint8_t *data, uint16_t length) | 1279 | int 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*/ | ||
1458 | static 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. */ |
1375 | static void LANdiscovery(Messenger *m) | 1469 | static 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 | */ | ||
1546 | static 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. */ |
1442 | void do_friends(Messenger *m) | 1560 | void 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. */ | ||
2305 | uint32_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. */ | ||
2324 | uint32_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 | |||
455 | void m_callback_group_message(Messenger *m, void (*function)(Messenger *m, int, int, uint8_t *, uint16_t, void *), | 457 | void 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 | */ | ||
465 | void 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 | ||
498 | int group_message_send(Messenger *m, int groupnumber, uint8_t *message, uint32_t length); | 507 | int 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 | */ | ||
512 | int 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 | */ | ||
522 | int 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 | */ |
634 | int get_friendlist(Messenger *m, int **out_list, uint32_t *out_list_length); | 658 | int 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. */ | ||
663 | uint32_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. */ | ||
670 | uint32_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 */ | ||
53 | typedef uint16_t bucket_t; | ||
54 | typedef uint32_t hash_t; | ||
55 | typedef uint16_t usecnt_t; | ||
56 | |||
57 | /* abbreviations ... */ | ||
58 | typedef Assoc_distance_relative_callback dist_rel_cb; | ||
59 | typedef Assoc_distance_absolute_callback dist_abs_cb; | ||
60 | |||
61 | /* | ||
62 | * Client_data wrapped with additional data | ||
63 | */ | ||
64 | typedef 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 | |||
81 | typedef struct candidates_bucket { | ||
82 | Client_entry *list; /* hashed list */ | ||
83 | } candidates_bucket; | ||
84 | |||
85 | struct 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 */ | ||
102 | static 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 */ | ||
120 | static 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 */ | ||
135 | static 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 */ | ||
157 | static 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 */ | ||
168 | static 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. */ | ||
195 | static 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 */ | ||
212 | static 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 */ | ||
240 | static 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 */ | ||
255 | static 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 */ | ||
270 | static 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() */ | ||
313 | static 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 | |||
319 | static 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 | |||
339 | static bucket_t candidates_id_bucket(Assoc *assoc, uint8_t *id) | ||
340 | { | ||
341 | return id_bucket(id, assoc->candidates_bucket_bits); | ||
342 | } | ||
343 | |||
344 | static 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 | |||
364 | static 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 | |||
396 | static 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 | |||
453 | static 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 | |||
506 | static 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 | */ | ||
551 | uint8_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 | |||
601 | uint8_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 | |||
744 | static 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 | |||
758 | static 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 */ | ||
770 | Assoc *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 | |||
844 | Assoc *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 */ | ||
852 | void 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 */ | ||
862 | void 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 | |||
873 | static char buffer[CLIENT_ID_SIZE * 2 + 1]; | ||
874 | static 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 | |||
888 | void 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 | |||
15 | typedef struct Assoc Assoc; | ||
16 | |||
17 | /*****************************************************************************/ | ||
18 | |||
19 | /* custom distance handler, if it's not ID-distance based | ||
20 | * return values exactly like id_closest() */ | ||
21 | typedef 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 */ | ||
28 | typedef 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 */ | ||
35 | uint8_t Assoc_add_entry(Assoc *assoc, uint8_t *id, IPPTs *ippts_send, IP_Port *ipp_recv, uint8_t used); | ||
36 | |||
37 | /*****************************************************************************/ | ||
38 | |||
39 | typedef enum AssocCloseEntriesFlags { | ||
40 | ProtoIPv4 = 1, | ||
41 | ProtoIPv6 = 2, | ||
42 | LANOk = 4, | ||
43 | } AssocCloseEntriesFlags; | ||
44 | |||
45 | typedef 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 | */ | ||
67 | uint8_t Assoc_get_close_entries(Assoc *assoc, Assoc_close_entries *close_entries); | ||
68 | |||
69 | /*****************************************************************************/ | ||
70 | |||
71 | /* create: default sizes (6, 5 => 320 entries) */ | ||
72 | Assoc *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) */ | ||
81 | Assoc *new_Assoc(size_t bits, size_t entries, uint8_t *public_id); | ||
82 | |||
83 | /* public_id changed (loaded), update which entry isn't stored */ | ||
84 | void Assoc_self_client_id_changed(Assoc *assoc, uint8_t *public_id); | ||
85 | |||
86 | /* destroy */ | ||
87 | void kill_Assoc(Assoc *assoc); | ||
88 | |||
89 | #ifdef LOGGING | ||
90 | void 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. */ | ||
100 | void 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. */ |
101 | static void addto_receivedlist(Friend_Requests *fr, uint8_t *client_id) | 107 | static 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); | |||
53 | uint32_t get_nospam(Friend_Requests *fr); | 55 | uint32_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 | */ |
58 | void callback_friendrequest(Friend_Requests *fr, void (*function)(uint8_t *, uint8_t *, uint16_t, void *), | 60 | void 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 | */ | ||
67 | void 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. */ |
62 | void friendreq_init(Friend_Requests *fr, Net_Crypto *c); | 70 | void 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 | */ |
227 | static int delpeer(Group_Chat *chat, uint8_t *client_id) | 233 | static 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 | ||
293 | static 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 | ||
278 | static int send_getnodes(Group_Chat *chat, IP_Port ip_port, int peernum) | 316 | static 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) |
444 | static void send_names_new_peer(Group_Chat *chat); | ||
378 | 445 | ||
379 | static int handle_data(Group_Chat *chat, uint8_t *data, uint32_t len) | 446 | static 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 | */ | ||
612 | static 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 | |||
620 | int 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 | |||
524 | uint32_t group_newpeer(Group_Chat *chat, uint8_t *client_id) | 631 | uint32_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 | ||
644 | void 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 | |||
650 | uint32_t group_numpeers(Group_Chat *chat) | ||
651 | { | ||
652 | return chat->numpeers; | ||
653 | } | ||
654 | |||
655 | uint32_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 | |||
537 | Group_Chat *new_groupchat(Networking_Core *net) | 664 | Group_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 | ||
723 | static 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 | } | ||
728 | static 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 | |||
592 | void do_groupchat(Group_Chat *chat) | 742 | void 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 | ||
601 | void kill_groupchat(Group_Chat *chat) | 752 | void 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 | |||
88 | void callback_groupmessage(Group_Chat *chat, void (*function)(Group_Chat *chat, int, uint8_t *, uint16_t, void *), | 97 | void 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 | */ | ||
106 | typedef enum { | ||
107 | CHAT_CHANGE_PEER_ADD, | ||
108 | CHAT_CHANGE_PEER_DEL, | ||
109 | CHAT_CHANGE_PEER_NAME, | ||
110 | } CHAT_CHANGE; | ||
111 | |||
112 | void 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 | */ |
96 | uint32_t group_sendmessage(Group_Chat *chat, uint8_t *message, uint32_t length); | 119 | uint32_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 | */ | ||
126 | int 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); | |||
112 | Group_Chat *new_groupchat(Networking_Core *net); | 141 | Group_Chat *new_groupchat(Networking_Core *net); |
113 | 142 | ||
114 | 143 | ||
144 | /* Return the number of peers in the group chat. | ||
145 | */ | ||
146 | uint32_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 | */ | ||
154 | uint32_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 | ||
311 | int networking_wait_prepare(Networking_Core *net, uint32_t sendqueue_length, uint8_t *data, uint16_t *lenptr) | 311 | int 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 */ |
44 | typedef short sa_family_t; | 44 | typedef 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 | ||
137 | typedef struct { | 149 | typedef 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 | ||
48 | typedef struct { | 50 | struct 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 | ||
65 | static bool is_ping_timeout(uint64_t time) | 61 | static 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__ | ||
30 | typedef struct PING PING; | 27 | typedef 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 | */ |
40 | void tox_getaddress(Tox *tox, uint8_t *address) | 40 | void 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 | */ |
63 | int tox_addfriend(Tox *tox, uint8_t *address, uint8_t *data, uint16_t length) | 63 | int 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 | */ |
74 | int tox_addfriend_norequest(Tox *tox, uint8_t *client_id) | 74 | int 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 | */ |
83 | int tox_getfriend_id(Tox *tox, uint8_t *client_id) | 83 | int 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 | */ |
95 | int tox_getclient_id(Tox *tox, int friend_id, uint8_t *client_id) | 95 | int 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. */ |
102 | int tox_delfriend(Tox *tox, int friendnumber) | 102 | int 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 | */ |
114 | int tox_get_friend_connectionstatus(Tox *tox, int friendnumber) | 114 | int 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 | */ |
140 | uint32_t tox_sendmessage(Tox *tox, int friendnumber, uint8_t *message, uint32_t length) | 140 | uint32_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 | ||
146 | uint32_t tox_sendmessage_withid(Tox *tox, int friendnumber, uint32_t theid, uint8_t *message, uint32_t length) | 146 | uint32_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 | */ |
162 | uint32_t tox_sendaction(Tox *tox, int friendnumber, uint8_t *action, uint32_t length) | 162 | uint32_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 | ||
168 | uint32_t tox_sendaction_withid(Tox *tox, int friendnumber, uint32_t theid, uint8_t *action, uint32_t length) | 168 | uint32_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 | */ |
182 | int tox_setname(Tox *tox, uint8_t *name, uint16_t length) | 182 | int 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 | */ |
196 | uint16_t tox_getselfname(Tox *tox, uint8_t *name, uint16_t nlen) | 196 | uint16_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 | */ |
208 | int tox_getname(Tox *tox, int friendnumber, uint8_t *name) | 208 | int 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 | */ |
219 | int tox_set_statusmessage(Tox *tox, uint8_t *status, uint16_t length) | 219 | int 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 | ||
225 | int tox_set_userstatus(Tox *tox, TOX_USERSTATUS status) | 225 | int 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 | */ |
234 | int tox_get_statusmessage_size(Tox *tox, int friendnumber) | 234 | int 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 | */ |
244 | int tox_copy_statusmessage(Tox *tox, int friendnumber, uint8_t *buf, uint32_t maxlen) | 244 | int 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 | ||
250 | int tox_copy_self_statusmessage(Tox *tox, uint8_t *buf, uint32_t maxlen) | 250 | int 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 | */ |
261 | TOX_USERSTATUS tox_get_userstatus(Tox *tox, int friendnumber) | 261 | TOX_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 | ||
267 | TOX_USERSTATUS tox_get_selfuserstatus(Tox *tox) | 267 | TOX_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. */ |
297 | uint32_t tox_copy_friendlist(Tox *tox, int *out_list, uint32_t list_size) | 297 | uint32_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 | */ |
306 | void tox_callback_friendrequest(Tox *tox, void (*function)(uint8_t *, uint8_t *, uint16_t, void *), void *userdata) | 306 | void 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 | */ |
316 | void tox_callback_friendmessage(Tox *tox, void (*function)(Messenger *tox, int, uint8_t *, uint16_t, void *), | 316 | void 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 | */ |
336 | void tox_callback_namechange(Tox *tox, void (*function)(Messenger *tox, int, uint8_t *, uint16_t, void *), | 336 | void 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 | */ |
347 | void tox_callback_statusmessage(Tox *tox, void (*function)(Messenger *tox, int, uint8_t *, uint16_t, void *), | 347 | void 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 | */ |
357 | void tox_callback_userstatus(Tox *tox, void (*_function)(Tox *tox, int, TOX_USERSTATUS, void *), void *userdata) | 357 | void 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 | */ |
391 | void tox_callback_connectionstatus(Tox *tox, void (*function)(Messenger *tox, int, uint8_t, void *), void *userdata) | 391 | void 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 | |||
425 | void 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 | */ | ||
496 | int 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 | */ | ||
510 | int 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. */ | ||
519 | uint32_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. */ | ||
530 | uint32_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 | */ |
489 | void tox_callback_file_sendrequest(Tox *tox, void (*function)(Messenger *tox, int, uint8_t, uint64_t, uint8_t *, | 544 | void 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 | */ |
525 | int tox_new_filesender(Tox *tox, int friendnumber, uint64_t filesize, uint8_t *filename, uint16_t filename_length) | 580 | int 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 | */ |
536 | int tox_file_sendcontrol(Tox *tox, int friendnumber, uint8_t send_receive, uint8_t filenumber, uint8_t message_id, | 591 | int 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 | */ |
547 | int tox_file_senddata(Tox *tox, int friendnumber, uint8_t filenumber, uint8_t *data, uint16_t length) | 602 | int 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 | */ |
558 | int tox_filedata_size(Tox *tox, int friendnumber) | 613 | int 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 | */ |
570 | uint64_t tox_file_dataremaining(Tox *tox, int friendnumber, uint8_t filenumber, uint8_t send_receive) | 625 | uint64_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 | */ |
132 | void tox_getaddress(Tox *tox, uint8_t *address); | 132 | void 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 | */ |
150 | int tox_addfriend(Tox *tox, uint8_t *address, uint8_t *data, uint16_t length); | 150 | int 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 | */ |
157 | int tox_addfriend_norequest(Tox *tox, uint8_t *client_id); | 157 | int 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 */ |
161 | int tox_getfriend_id(Tox *tox, uint8_t *client_id); | 161 | int 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 | */ |
168 | int tox_getclient_id(Tox *tox, int friend_id, uint8_t *client_id); | 168 | int tox_get_client_id(Tox *tox, int friend_id, uint8_t *client_id); |
169 | 169 | ||
170 | /* Remove a friend. */ | 170 | /* Remove a friend. */ |
171 | int tox_delfriend(Tox *tox, int friendnumber); | 171 | int 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 | */ |
179 | int tox_get_friend_connectionstatus(Tox *tox, int friendnumber); | 179 | int 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 | */ |
198 | uint32_t tox_sendmessage(Tox *tox, int friendnumber, uint8_t *message, uint32_t length); | 198 | uint32_t tox_send_message(Tox *tox, int friendnumber, uint8_t *message, uint32_t length); |
199 | uint32_t tox_sendmessage_withid(Tox *tox, int friendnumber, uint32_t theid, uint8_t *message, uint32_t length); | 199 | uint32_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 | */ |
211 | uint32_t tox_sendaction(Tox *tox, int friendnumber, uint8_t *action, uint32_t length); | 211 | uint32_t tox_send_action(Tox *tox, int friendnumber, uint8_t *action, uint32_t length); |
212 | uint32_t tox_sendaction_withid(Tox *tox, int friendnumber, uint32_t theid, uint8_t *action, uint32_t length); | 212 | uint32_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 | */ |
222 | int tox_setname(Tox *tox, uint8_t *name, uint16_t length); | 222 | int 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 | */ |
233 | uint16_t tox_getselfname(Tox *tox, uint8_t *name, uint16_t nlen); | 233 | uint16_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 | */ |
241 | int tox_getname(Tox *tox, int friendnumber, uint8_t *name); | 241 | int 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 | */ |
249 | int tox_set_statusmessage(Tox *tox, uint8_t *status, uint16_t length); | 249 | int tox_set_status_message(Tox *tox, uint8_t *status, uint16_t length); |
250 | int tox_set_userstatus(Tox *tox, TOX_USERSTATUS status); | 250 | int 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 | */ |
255 | int tox_get_statusmessage_size(Tox *tox, int friendnumber); | 255 | int 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 | */ |
264 | int tox_copy_statusmessage(Tox *tox, int friendnumber, uint8_t *buf, uint32_t maxlen); | 264 | int tox_get_status_message(Tox *tox, int friendnumber, uint8_t *buf, uint32_t maxlen); |
265 | int tox_copy_self_statusmessage(Tox *tox, uint8_t *buf, uint32_t maxlen); | 265 | int 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 | */ |
272 | TOX_USERSTATUS tox_get_userstatus(Tox *tox, int friendnumber); | 272 | TOX_USERSTATUS tox_get_user_status(Tox *tox, int friendnumber); |
273 | TOX_USERSTATUS tox_get_selfuserstatus(Tox *tox); | 273 | TOX_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. */ |
290 | uint32_t tox_copy_friendlist(Tox *tox, int *out_list, uint32_t list_size); | 290 | uint32_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 | */ |
295 | void tox_callback_friendrequest(Tox *tox, void (*function)(uint8_t *, uint8_t *, uint16_t, void *), void *userdata); | 295 | void 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 | */ |
300 | void tox_callback_friendmessage(Tox *tox, void (*function)(Tox *tox, int, uint8_t *, uint16_t, void *), | 300 | void 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 | */ |
312 | void tox_callback_namechange(Tox *tox, void (*function)(Tox *tox, int, uint8_t *, uint16_t, void *), | 312 | void 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 | */ |
319 | void tox_callback_statusmessage(Tox *tox, void (*function)(Tox *tox, int, uint8_t *, uint16_t, void *), | 319 | void 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 | */ |
325 | void tox_callback_userstatus(Tox *tox, void (*function)(Tox *tox, int, TOX_USERSTATUS, void *), void *userdata); | 325 | void 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 | */ |
349 | void tox_callback_connectionstatus(Tox *tox, void (*function)(Tox *tox, int, uint8_t, void *), void *userdata); | 349 | void 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 | |||
363 | void tox_callback_group_message(Tox *tox, void (*function)(Tox *tox, int, int, uint8_t *, uint16_t, void *), | 363 | void 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 | */ | ||
371 | typedef enum { | ||
372 | TOX_CHAT_CHANGE_PEER_ADD, | ||
373 | TOX_CHAT_CHANGE_PEER_DEL, | ||
374 | TOX_CHAT_CHANGE_PEER_NAME, | ||
375 | } TOX_CHAT_CHANGE; | ||
376 | |||
377 | void 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 | */ |
399 | int tox_join_groupchat(Tox *tox, int friendnumber, uint8_t *friend_group_public_key); | 412 | int 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 | */ |
406 | int tox_group_message_send(Tox *tox, int groupnumber, uint8_t *message, uint32_t length); | 418 | int 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 | */ | ||
423 | int 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 | */ | ||
433 | int 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. */ | ||
438 | uint32_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. */ | ||
445 | uint32_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 | */ |
448 | void tox_callback_file_sendrequest(Tox *tox, void (*function)(Tox *m, int, uint8_t, uint64_t, uint8_t *, uint16_t, | 487 | void 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 | */ |
476 | int tox_new_filesender(Tox *tox, int friendnumber, uint64_t filesize, uint8_t *filename, uint16_t filename_length); | 515 | int 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 | */ |
486 | int tox_file_sendcontrol(Tox *tox, int friendnumber, uint8_t send_receive, uint8_t filenumber, uint8_t message_id, | 525 | int 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 | */ |
494 | int tox_file_senddata(Tox *tox, int friendnumber, uint8_t filenumber, uint8_t *data, uint16_t length); | 533 | int 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 | */ |
501 | int tox_filedata_size(Tox *tox, int friendnumber); | 540 | int 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 | */ |
510 | uint64_t tox_file_dataremaining(Tox *tox, int friendnumber, uint8_t filenumber, uint8_t send_receive); | 549 | uint64_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 |