diff options
Diffstat (limited to 'toxcore')
-rw-r--r-- | toxcore/DHT.c | 10 | ||||
-rw-r--r-- | toxcore/Messenger.c | 158 | ||||
-rw-r--r-- | toxcore/Messenger.h | 34 | ||||
-rwxr-xr-x | toxcore/event.c | 1 | ||||
-rw-r--r-- | toxcore/friend_requests.c | 3 | ||||
-rw-r--r-- | toxcore/group_chats.c | 30 | ||||
-rw-r--r-- | toxcore/network.c | 4 | ||||
-rw-r--r-- | toxcore/network.h | 9 | ||||
-rw-r--r-- | toxcore/onion.c | 24 | ||||
-rw-r--r-- | toxcore/onion.h | 1 | ||||
-rw-r--r-- | toxcore/onion_announce.c | 2 | ||||
-rw-r--r-- | toxcore/onion_client.c | 29 | ||||
-rw-r--r-- | toxcore/onion_client.h | 2 | ||||
-rw-r--r-- | toxcore/tox.c | 7 | ||||
-rw-r--r-- | toxcore/tox.h | 10 |
15 files changed, 308 insertions, 16 deletions
diff --git a/toxcore/DHT.c b/toxcore/DHT.c index 02175c2a..982b06c4 100644 --- a/toxcore/DHT.c +++ b/toxcore/DHT.c | |||
@@ -379,6 +379,7 @@ static int get_somewhat_close_nodes(DHT *dht, uint8_t *client_id, Node_format *n | |||
379 | int get_close_nodes(DHT *dht, uint8_t *client_id, Node_format *nodes_list, sa_family_t sa_family, uint8_t is_LAN, | 379 | int get_close_nodes(DHT *dht, uint8_t *client_id, Node_format *nodes_list, sa_family_t sa_family, uint8_t is_LAN, |
380 | uint8_t want_good) | 380 | uint8_t want_good) |
381 | { | 381 | { |
382 | memset(nodes_list, 0, MAX_SENT_NODES * sizeof(Node_format)); | ||
382 | #ifdef ENABLE_ASSOC_DHT | 383 | #ifdef ENABLE_ASSOC_DHT |
383 | 384 | ||
384 | if (!dht->assoc) | 385 | if (!dht->assoc) |
@@ -1249,9 +1250,9 @@ int DHT_delfriend(DHT *dht, uint8_t *client_id) | |||
1249 | --dht->num_friends; | 1250 | --dht->num_friends; |
1250 | 1251 | ||
1251 | if (dht->num_friends != i) { | 1252 | if (dht->num_friends != i) { |
1252 | memcpy( dht->friends_list[i].client_id, | 1253 | memcpy( &dht->friends_list[i], |
1253 | dht->friends_list[dht->num_friends].client_id, | 1254 | &dht->friends_list[dht->num_friends], |
1254 | CLIENT_ID_SIZE ); | 1255 | sizeof(DHT_Friend) ); |
1255 | } | 1256 | } |
1256 | 1257 | ||
1257 | if (dht->num_friends == 0) { | 1258 | if (dht->num_friends == 0) { |
@@ -1553,7 +1554,7 @@ int route_tofriend(DHT *dht, uint8_t *friend_id, uint8_t *packet, uint32_t lengt | |||
1553 | IP_Port ip_list[MAX_FRIEND_CLIENTS]; | 1554 | IP_Port ip_list[MAX_FRIEND_CLIENTS]; |
1554 | int ip_num = friend_iplist(dht, ip_list, num); | 1555 | int ip_num = friend_iplist(dht, ip_list, num); |
1555 | 1556 | ||
1556 | if (ip_num < (MAX_FRIEND_CLIENTS / 2)) | 1557 | if (ip_num < (MAX_FRIEND_CLIENTS / 4)) |
1557 | return 0; /* Reason for that? */ | 1558 | return 0; /* Reason for that? */ |
1558 | 1559 | ||
1559 | DHT_Friend *friend = &dht->friends_list[num]; | 1560 | DHT_Friend *friend = &dht->friends_list[num]; |
@@ -2394,7 +2395,6 @@ static int dht_load_state_callback(void *outer, uint8_t *data, uint32_t length, | |||
2394 | num = length / sizeof(DHT_Friend); | 2395 | num = length / sizeof(DHT_Friend); |
2395 | 2396 | ||
2396 | for (i = 0; i < num; ++i) { | 2397 | for (i = 0; i < num; ++i) { |
2397 | DHT_addfriend(dht, friend_list[i].client_id); | ||
2398 | 2398 | ||
2399 | for (j = 0; j < MAX_FRIEND_CLIENTS; ++j) { | 2399 | for (j = 0; j < MAX_FRIEND_CLIENTS; ++j) { |
2400 | Client_data *client = &friend_list[i].client_list[j]; | 2400 | Client_data *client = &friend_list[i].client_list[j]; |
diff --git a/toxcore/Messenger.c b/toxcore/Messenger.c index c1301767..692d3d0e 100644 --- a/toxcore/Messenger.c +++ b/toxcore/Messenger.c | |||
@@ -43,6 +43,71 @@ static uint8_t friend_not_valid(Messenger *m, int friendnumber) | |||
43 | return (unsigned int)friendnumber >= m->numfriends; | 43 | return (unsigned int)friendnumber >= m->numfriends; |
44 | } | 44 | } |
45 | 45 | ||
46 | static int add_online_friend(Messenger *m, int friendnumber) | ||
47 | { | ||
48 | if (friend_not_valid(m, friendnumber)) | ||
49 | return -1; | ||
50 | |||
51 | IP_Port temp_ip_port = get_friend_ipport(m, friendnumber); | ||
52 | |||
53 | if (temp_ip_port.port == 0) | ||
54 | return -1; | ||
55 | |||
56 | uint32_t i; | ||
57 | |||
58 | for (i = 0; i < m->numonline_friends; ++i) { | ||
59 | if (m->online_friendlist[i].friend_num == (uint32_t)friendnumber) | ||
60 | return 0; | ||
61 | } | ||
62 | |||
63 | Online_Friend *temp; | ||
64 | temp = realloc(m->online_friendlist, sizeof(Online_Friend) * (m->numonline_friends + 1)); | ||
65 | |||
66 | if (temp == NULL) | ||
67 | return -1; | ||
68 | |||
69 | m->online_friendlist = temp; | ||
70 | m->online_friendlist[m->numonline_friends].friend_num = friendnumber; | ||
71 | m->online_friendlist[m->numonline_friends].ip_port = temp_ip_port; | ||
72 | ++m->numonline_friends; | ||
73 | return 0; | ||
74 | } | ||
75 | |||
76 | |||
77 | static int remove_online_friend(Messenger *m, int friendnumber) | ||
78 | { | ||
79 | uint32_t i; | ||
80 | Online_Friend *temp; | ||
81 | |||
82 | for (i = 0; i < m->numonline_friends; ++i) { | ||
83 | /* Equal */ | ||
84 | if (m->online_friendlist[i].friend_num == (uint32_t)friendnumber) { | ||
85 | --m->numonline_friends; | ||
86 | |||
87 | if (m->numonline_friends != i) { | ||
88 | memcpy( &m->online_friendlist[i], | ||
89 | &m->online_friendlist[m->numonline_friends], | ||
90 | sizeof(Online_Friend) ); | ||
91 | } | ||
92 | |||
93 | if (m->numonline_friends == 0) { | ||
94 | free(m->online_friendlist); | ||
95 | m->online_friendlist = NULL; | ||
96 | return 0; | ||
97 | } | ||
98 | |||
99 | temp = realloc(m->online_friendlist, sizeof(Online_Friend) * (m->numonline_friends)); | ||
100 | |||
101 | if (temp == NULL) | ||
102 | return -1; | ||
103 | |||
104 | m->online_friendlist = temp; | ||
105 | return 0; | ||
106 | } | ||
107 | } | ||
108 | |||
109 | return -1; | ||
110 | } | ||
46 | /* Set the size of the friend list to numfriends. | 111 | /* Set the size of the friend list to numfriends. |
47 | * | 112 | * |
48 | * return -1 if realloc fails. | 113 | * return -1 if realloc fails. |
@@ -273,6 +338,9 @@ int m_delfriend(Messenger *m, int friendnumber) | |||
273 | if (friend_not_valid(m, friendnumber)) | 338 | if (friend_not_valid(m, friendnumber)) |
274 | return -1; | 339 | return -1; |
275 | 340 | ||
341 | if (m->friendlist[friendnumber].status == FRIEND_ONLINE) | ||
342 | remove_online_friend(m, friendnumber); | ||
343 | |||
276 | onion_delfriend(m->onion_c, m->friendlist[friendnumber].onion_friendnum); | 344 | onion_delfriend(m->onion_c, m->friendlist[friendnumber].onion_friendnum); |
277 | crypto_kill(m->net_crypto, m->friendlist[friendnumber].crypt_connection_id); | 345 | crypto_kill(m->net_crypto, m->friendlist[friendnumber].crypt_connection_id); |
278 | free(m->friendlist[friendnumber].statusmessage); | 346 | free(m->friendlist[friendnumber].statusmessage); |
@@ -650,12 +718,17 @@ void m_callback_connectionstatus(Messenger *m, void (*function)(Messenger *m, in | |||
650 | m->friend_connectionstatuschange = function; | 718 | m->friend_connectionstatuschange = function; |
651 | m->friend_connectionstatuschange_userdata = userdata; | 719 | m->friend_connectionstatuschange_userdata = userdata; |
652 | } | 720 | } |
721 | |||
722 | void m_callback_connectionstatus_internal_av(Messenger *m, void (*function)(Messenger *m, int, uint8_t, void *), | ||
723 | void *userdata) | ||
724 | { | ||
725 | m->friend_connectionstatuschange_internal = function; | ||
726 | m->friend_connectionstatuschange_internal_userdata = userdata; | ||
727 | } | ||
728 | |||
653 | static void break_files(Messenger *m, int friendnumber); | 729 | static void break_files(Messenger *m, int friendnumber); |
654 | static void check_friend_connectionstatus(Messenger *m, int friendnumber, uint8_t status) | 730 | static void check_friend_connectionstatus(Messenger *m, int friendnumber, uint8_t status) |
655 | { | 731 | { |
656 | if (!m->friend_connectionstatuschange) | ||
657 | return; | ||
658 | |||
659 | if (status == NOFRIEND) | 732 | if (status == NOFRIEND) |
660 | return; | 733 | return; |
661 | 734 | ||
@@ -665,10 +738,19 @@ static void check_friend_connectionstatus(Messenger *m, int friendnumber, uint8_ | |||
665 | onion_set_friend_online(m->onion_c, m->friendlist[friendnumber].onion_friendnum, is_online); | 738 | onion_set_friend_online(m->onion_c, m->friendlist[friendnumber].onion_friendnum, is_online); |
666 | 739 | ||
667 | if (is_online != was_online) { | 740 | if (is_online != was_online) { |
668 | if (was_online) | 741 | if (was_online) { |
669 | break_files(m, friendnumber); | 742 | break_files(m, friendnumber); |
743 | remove_online_friend(m, friendnumber); | ||
744 | } else { | ||
745 | add_online_friend(m, friendnumber); | ||
746 | } | ||
747 | |||
748 | if (m->friend_connectionstatuschange) | ||
749 | m->friend_connectionstatuschange(m, friendnumber, is_online, m->friend_connectionstatuschange_userdata); | ||
670 | 750 | ||
671 | m->friend_connectionstatuschange(m, friendnumber, is_online, m->friend_connectionstatuschange_userdata); | 751 | if (m->friend_connectionstatuschange_internal) |
752 | m->friend_connectionstatuschange_internal(m, friendnumber, is_online, | ||
753 | m->friend_connectionstatuschange_internal_userdata); | ||
672 | } | 754 | } |
673 | } | 755 | } |
674 | 756 | ||
@@ -814,6 +896,8 @@ static void group_message_function(Group_Chat *chat, int peer_number, uint8_t *m | |||
814 | if (i == -1) | 896 | if (i == -1) |
815 | return; | 897 | return; |
816 | 898 | ||
899 | message[length - 1] = 0; /* Force NULL terminator */ | ||
900 | |||
817 | if (m->group_message) | 901 | if (m->group_message) |
818 | (*m->group_message)(m, i, peer_number, message, length, m->group_message_userdata); | 902 | (*m->group_message)(m, i, peer_number, message, length, m->group_message_userdata); |
819 | } | 903 | } |
@@ -826,6 +910,8 @@ static void group_action_function(Group_Chat *chat, int peer_number, uint8_t *ac | |||
826 | if (i == -1) | 910 | if (i == -1) |
827 | return; | 911 | return; |
828 | 912 | ||
913 | action[length - 1] = 0; /* Force NULL terminator */ | ||
914 | |||
829 | if (m->group_action) | 915 | if (m->group_action) |
830 | (*m->group_action)(m, i, peer_number, action, length, m->group_action_userdata); | 916 | (*m->group_action)(m, i, peer_number, action, length, m->group_action_userdata); |
831 | } | 917 | } |
@@ -1489,6 +1575,60 @@ int m_msi_packet(Messenger *m, int friendnumber, uint8_t *data, uint16_t length) | |||
1489 | return write_cryptpacket_id(m, friendnumber, PACKET_ID_MSI, data, length); | 1575 | return write_cryptpacket_id(m, friendnumber, PACKET_ID_MSI, data, length); |
1490 | } | 1576 | } |
1491 | 1577 | ||
1578 | static int friendnum_from_ip_port(Messenger *m, IP_Port ip_port) | ||
1579 | { | ||
1580 | uint32_t i; | ||
1581 | |||
1582 | for (i = 0; i < m->numonline_friends; ++i) { | ||
1583 | if (ipport_equal(&m->online_friendlist[i].ip_port, &ip_port)) | ||
1584 | return m->online_friendlist[i].friend_num; | ||
1585 | } | ||
1586 | |||
1587 | return -1; | ||
1588 | } | ||
1589 | |||
1590 | static int handle_custom_user_packet(void *object, IP_Port source, uint8_t *packet, uint32_t length) | ||
1591 | { | ||
1592 | Messenger *m = object; | ||
1593 | int friend_num = friendnum_from_ip_port(m, source); | ||
1594 | |||
1595 | if (friend_num == -1) | ||
1596 | return 1; | ||
1597 | |||
1598 | if (m->friendlist[friend_num].packethandlers[packet[0] % TOTAL_USERPACKETS].function) | ||
1599 | return m->friendlist[friend_num].packethandlers[packet[0] % TOTAL_USERPACKETS].function( | ||
1600 | m->friendlist[friend_num].packethandlers[packet[0] % TOTAL_USERPACKETS].object, source, packet, length); | ||
1601 | |||
1602 | return 1; | ||
1603 | } | ||
1604 | |||
1605 | |||
1606 | int custom_user_packet_registerhandler(Messenger *m, int friendnumber, uint8_t byte, packet_handler_callback cb, | ||
1607 | void *object) | ||
1608 | { | ||
1609 | if (friend_not_valid(m, friendnumber)) | ||
1610 | return -1; | ||
1611 | |||
1612 | if (byte < NET_PACKET_CUSTOM_RANGE_START || byte >= NET_PACKET_CUSTOM_RANGE_END) | ||
1613 | return -1; | ||
1614 | |||
1615 | m->friendlist[friendnumber].packethandlers[byte % TOTAL_USERPACKETS].function = cb; | ||
1616 | m->friendlist[friendnumber].packethandlers[byte % TOTAL_USERPACKETS].object = object; | ||
1617 | networking_registerhandler(m->net, byte, handle_custom_user_packet, m); | ||
1618 | return 0; | ||
1619 | } | ||
1620 | |||
1621 | int send_custom_user_packet(Messenger *m, int friendnumber, uint8_t *data, uint32_t length) | ||
1622 | { | ||
1623 | IP_Port ip_port = get_friend_ipport(m, friendnumber); | ||
1624 | |||
1625 | if (ip_port.port == 0) | ||
1626 | return -1; | ||
1627 | |||
1628 | return sendpacket(m->net, ip_port, data, length); | ||
1629 | } | ||
1630 | |||
1631 | |||
1492 | /* Function to filter out some friend requests*/ | 1632 | /* Function to filter out some friend requests*/ |
1493 | static int friend_already_added(uint8_t *client_id, void *data) | 1633 | static int friend_already_added(uint8_t *client_id, void *data) |
1494 | { | 1634 | { |
@@ -1841,6 +1981,8 @@ void do_friends(Messenger *m) | |||
1841 | m->friendlist[i].file_receiving[filenumber].size = filesize; | 1981 | m->friendlist[i].file_receiving[filenumber].size = filesize; |
1842 | m->friendlist[i].file_receiving[filenumber].transferred = 0; | 1982 | m->friendlist[i].file_receiving[filenumber].transferred = 0; |
1843 | 1983 | ||
1984 | data[data_length - 1] = 0; /* Force NULL terminate file name. */ | ||
1985 | |||
1844 | if (m->file_sendrequest) | 1986 | if (m->file_sendrequest) |
1845 | (*m->file_sendrequest)(m, i, filenumber, filesize, data + 1 + sizeof(uint64_t), data_length - 1 - sizeof(uint64_t), | 1987 | (*m->file_sendrequest)(m, i, filenumber, filesize, data + 1 + sizeof(uint64_t), data_length - 1 - sizeof(uint64_t), |
1846 | m->file_sendrequest_userdata); | 1988 | m->file_sendrequest_userdata); |
@@ -2360,6 +2502,12 @@ uint32_t count_friendlist(Messenger *m) | |||
2360 | return ret; | 2502 | return ret; |
2361 | } | 2503 | } |
2362 | 2504 | ||
2505 | /* Return the number of online friends in the instance m. */ | ||
2506 | uint32_t get_num_online_friends(Messenger *m) | ||
2507 | { | ||
2508 | return m->numonline_friends; | ||
2509 | } | ||
2510 | |||
2363 | /* Copy a list of valid friend IDs into the array out_list. | 2511 | /* Copy a list of valid friend IDs into the array out_list. |
2364 | * If out_list is NULL, returns 0. | 2512 | * If out_list is NULL, returns 0. |
2365 | * Otherwise, returns the number of elements copied. | 2513 | * Otherwise, returns the number of elements copied. |
diff --git a/toxcore/Messenger.h b/toxcore/Messenger.h index e09b2f30..ccca8fba 100644 --- a/toxcore/Messenger.h +++ b/toxcore/Messenger.h | |||
@@ -155,8 +155,15 @@ typedef struct { | |||
155 | struct File_Transfers file_receiving[MAX_CONCURRENT_FILE_PIPES]; | 155 | struct File_Transfers file_receiving[MAX_CONCURRENT_FILE_PIPES]; |
156 | int invited_groups[MAX_INVITED_GROUPS]; | 156 | int invited_groups[MAX_INVITED_GROUPS]; |
157 | uint16_t invited_groups_num; | 157 | uint16_t invited_groups_num; |
158 | |||
159 | Packet_Handles packethandlers[TOTAL_USERPACKETS]; | ||
158 | } Friend; | 160 | } Friend; |
159 | 161 | ||
162 | typedef struct { | ||
163 | uint32_t friend_num; | ||
164 | IP_Port ip_port; | ||
165 | } Online_Friend; | ||
166 | |||
160 | typedef struct Messenger { | 167 | typedef struct Messenger { |
161 | 168 | ||
162 | Networking_Core *net; | 169 | Networking_Core *net; |
@@ -179,6 +186,9 @@ typedef struct Messenger { | |||
179 | Friend *friendlist; | 186 | Friend *friendlist; |
180 | uint32_t numfriends; | 187 | uint32_t numfriends; |
181 | 188 | ||
189 | Online_Friend *online_friendlist; | ||
190 | uint32_t numonline_friends; | ||
191 | |||
182 | Group_Chat **chats; | 192 | Group_Chat **chats; |
183 | uint32_t numchats; | 193 | uint32_t numchats; |
184 | 194 | ||
@@ -200,6 +210,8 @@ typedef struct Messenger { | |||
200 | void *friend_statuschange_userdata; | 210 | void *friend_statuschange_userdata; |
201 | void (*friend_connectionstatuschange)(struct Messenger *m, int, uint8_t, void *); | 211 | void (*friend_connectionstatuschange)(struct Messenger *m, int, uint8_t, void *); |
202 | void *friend_connectionstatuschange_userdata; | 212 | void *friend_connectionstatuschange_userdata; |
213 | void (*friend_connectionstatuschange_internal)(struct Messenger *m, int, uint8_t, void *); | ||
214 | void *friend_connectionstatuschange_internal_userdata; | ||
203 | 215 | ||
204 | void (*group_invite)(struct Messenger *m, int, uint8_t *, void *); | 216 | void (*group_invite)(struct Messenger *m, int, uint8_t *, void *); |
205 | void *group_invite_userdata; | 217 | void *group_invite_userdata; |
@@ -450,6 +462,9 @@ void m_callback_read_receipt(Messenger *m, void (*function)(Messenger *m, int, u | |||
450 | * It's assumed that when adding friends, their connection status is offline. | 462 | * It's assumed that when adding friends, their connection status is offline. |
451 | */ | 463 | */ |
452 | void m_callback_connectionstatus(Messenger *m, void (*function)(Messenger *m, int, uint8_t, void *), void *userdata); | 464 | void m_callback_connectionstatus(Messenger *m, void (*function)(Messenger *m, int, uint8_t, void *), void *userdata); |
465 | /* Same as previous but for internal A/V core usage only */ | ||
466 | void m_callback_connectionstatus_internal_av(Messenger *m, void (*function)(Messenger *m, int, uint8_t, void *), | ||
467 | void *userdata); | ||
453 | 468 | ||
454 | /**********GROUP CHATS************/ | 469 | /**********GROUP CHATS************/ |
455 | 470 | ||
@@ -627,6 +642,22 @@ int m_msi_packet(Messenger *m, int friendnumber, uint8_t *data, uint16_t length) | |||
627 | 642 | ||
628 | /**********************************************/ | 643 | /**********************************************/ |
629 | 644 | ||
645 | /* Set handlers for custom user packets (RTP packets for example.) | ||
646 | * | ||
647 | * return -1 on failure. | ||
648 | * return 0 on success. | ||
649 | */ | ||
650 | int custom_user_packet_registerhandler(Messenger *m, int friendnumber, uint8_t byte, packet_handler_callback cb, | ||
651 | void *object); | ||
652 | |||
653 | /* High level function to send custom user packets. | ||
654 | * | ||
655 | * return -1 on failure. | ||
656 | * return number of bytes sent on success. | ||
657 | */ | ||
658 | int send_custom_user_packet(Messenger *m, int friendnumber, uint8_t *data, uint32_t length); | ||
659 | |||
660 | /**********************************************/ | ||
630 | /* Run this at startup. | 661 | /* Run this at startup. |
631 | * return allocated instance of Messenger on success. | 662 | * return allocated instance of Messenger on success. |
632 | * return 0 if there are problems. | 663 | * return 0 if there are problems. |
@@ -682,6 +713,9 @@ int messenger_load_encrypted(Messenger *m, uint8_t *data, uint32_t length, uint8 | |||
682 | * for copy_friendlist. */ | 713 | * for copy_friendlist. */ |
683 | uint32_t count_friendlist(Messenger *m); | 714 | uint32_t count_friendlist(Messenger *m); |
684 | 715 | ||
716 | /* Return the number of online friends in the instance m. */ | ||
717 | uint32_t get_num_online_friends(Messenger *m); | ||
718 | |||
685 | /* Copy a list of valid friend IDs into the array out_list. | 719 | /* Copy a list of valid friend IDs into the array out_list. |
686 | * If out_list is NULL, returns 0. | 720 | * If out_list is NULL, returns 0. |
687 | * Otherwise, returns the number of elements copied. | 721 | * Otherwise, returns the number of elements copied. |
diff --git a/toxcore/event.c b/toxcore/event.c index 05e2a03c..2fdc9442 100755 --- a/toxcore/event.c +++ b/toxcore/event.c | |||
@@ -31,6 +31,7 @@ | |||
31 | #include "event.h" | 31 | #include "event.h" |
32 | 32 | ||
33 | #include "util.h" | 33 | #include "util.h" |
34 | #include "network.h" | ||
34 | 35 | ||
35 | #define _GNU_SOURCE | 36 | #define _GNU_SOURCE |
36 | 37 | ||
diff --git a/toxcore/friend_requests.c b/toxcore/friend_requests.c index 5c294c76..9ac72097 100644 --- a/toxcore/friend_requests.c +++ b/toxcore/friend_requests.c | |||
@@ -140,6 +140,9 @@ static int friendreq_handlepacket(void *object, uint8_t *source_pubkey, uint8_t | |||
140 | return 1; | 140 | return 1; |
141 | 141 | ||
142 | addto_receivedlist(fr, source_pubkey); | 142 | addto_receivedlist(fr, source_pubkey); |
143 | |||
144 | packet[length - 1] = 0; /* Force NULL terminator. */ | ||
145 | |||
143 | (*fr->handle_friendrequest)(source_pubkey, packet + 4, length - 4, fr->handle_friendrequest_userdata); | 146 | (*fr->handle_friendrequest)(source_pubkey, packet + 4, length - 4, fr->handle_friendrequest_userdata); |
144 | return 0; | 147 | return 0; |
145 | } | 148 | } |
diff --git a/toxcore/group_chats.c b/toxcore/group_chats.c index 90ffdd14..6dff52ef 100644 --- a/toxcore/group_chats.c +++ b/toxcore/group_chats.c | |||
@@ -75,6 +75,32 @@ static int peer_in_chat(Group_Chat *chat, uint8_t *client_id) | |||
75 | return -1; | 75 | return -1; |
76 | } | 76 | } |
77 | 77 | ||
78 | /* Compares client_id1 and client_id2 with client_id. | ||
79 | * | ||
80 | * return 0 if both are same distance. | ||
81 | * return 1 if client_id1 is closer. | ||
82 | * return 2 if client_id2 is closer. | ||
83 | */ | ||
84 | static int id_closest_groupchats(uint8_t *id, uint8_t *id1, uint8_t *id2) | ||
85 | { | ||
86 | size_t i; | ||
87 | uint8_t distance1, distance2; | ||
88 | |||
89 | for (i = 0; i < CLIENT_ID_SIZE; ++i) { | ||
90 | |||
91 | distance1 = abs(((int8_t *)id)[i] - ((int8_t *)id1)[i]); | ||
92 | distance2 = abs(((int8_t *)id)[i] - ((int8_t *)id2)[i]); | ||
93 | |||
94 | if (distance1 < distance2) | ||
95 | return 1; | ||
96 | |||
97 | if (distance1 > distance2) | ||
98 | return 2; | ||
99 | } | ||
100 | |||
101 | return 0; | ||
102 | } | ||
103 | |||
78 | #define BAD_GROUPNODE_TIMEOUT 30 | 104 | #define BAD_GROUPNODE_TIMEOUT 30 |
79 | 105 | ||
80 | /* | 106 | /* |
@@ -100,7 +126,7 @@ static int peer_okping(Group_Chat *chat, uint8_t *client_id) | |||
100 | if (id_equal(chat->close[i].client_id, client_id)) | 126 | if (id_equal(chat->close[i].client_id, client_id)) |
101 | return -1; | 127 | return -1; |
102 | 128 | ||
103 | if (id_closest(chat->self_public_key, chat->close[i].client_id, client_id) == 2) | 129 | if (id_closest_groupchats(chat->self_public_key, chat->close[i].client_id, client_id) == 2) |
104 | ++j; | 130 | ++j; |
105 | } | 131 | } |
106 | 132 | ||
@@ -137,7 +163,7 @@ static int add_closepeer(Group_Chat *chat, uint8_t *client_id, IP_Port ip_port) | |||
137 | } | 163 | } |
138 | 164 | ||
139 | for (i = 0; i < GROUP_CLOSE_CONNECTIONS; ++i) { /* Replace nodes if given one is closer. */ | 165 | for (i = 0; i < GROUP_CLOSE_CONNECTIONS; ++i) { /* Replace nodes if given one is closer. */ |
140 | if (id_closest(chat->self_public_key, chat->close[i].client_id, client_id) == 2) { | 166 | if (id_closest_groupchats(chat->self_public_key, chat->close[i].client_id, client_id) == 2) { |
141 | id_copy(chat->close[i].client_id, client_id); | 167 | id_copy(chat->close[i].client_id, client_id); |
142 | chat->close[i].ip_port = ip_port; | 168 | chat->close[i].ip_port = ip_port; |
143 | chat->close[i].last_recv = unix_time(); | 169 | chat->close[i].last_recv = unix_time(); |
diff --git a/toxcore/network.c b/toxcore/network.c index 1186a468..839618bf 100644 --- a/toxcore/network.c +++ b/toxcore/network.c | |||
@@ -540,8 +540,10 @@ Networking_Core *new_networking(IP ip, uint16_t port) | |||
540 | addr6->sin6_scope_id = 0; | 540 | addr6->sin6_scope_id = 0; |
541 | 541 | ||
542 | portptr = &addr6->sin6_port; | 542 | portptr = &addr6->sin6_port; |
543 | } else | 543 | } else { |
544 | free(temp); | ||
544 | return NULL; | 545 | return NULL; |
546 | } | ||
545 | 547 | ||
546 | if (ip.family == AF_INET6) { | 548 | if (ip.family == AF_INET6) { |
547 | char ipv6only = 0; | 549 | char ipv6only = 0; |
diff --git a/toxcore/network.h b/toxcore/network.h index 4c7f1a83..aaf89f19 100644 --- a/toxcore/network.h +++ b/toxcore/network.h | |||
@@ -129,6 +129,12 @@ typedef int sock_t; | |||
129 | #define NET_PACKET_LAN_DISCOVERY 33 /* LAN discovery packet ID. */ | 129 | #define NET_PACKET_LAN_DISCOVERY 33 /* LAN discovery packet ID. */ |
130 | #define NET_PACKET_GROUP_CHATS 48 /* Group chats packet ID. */ | 130 | #define NET_PACKET_GROUP_CHATS 48 /* Group chats packet ID. */ |
131 | 131 | ||
132 | /* Range of ids that custom user packets can use. */ | ||
133 | #define NET_PACKET_CUSTOM_RANGE_START 64 | ||
134 | #define NET_PACKET_CUSTOM_RANGE_END 96 | ||
135 | |||
136 | #define TOTAL_USERPACKETS (NET_PACKET_CUSTOM_RANGE_END - NET_PACKET_CUSTOM_RANGE_START) | ||
137 | |||
132 | /* See: docs/Prevent_Tracking.txt and onion.{c, h} */ | 138 | /* See: docs/Prevent_Tracking.txt and onion.{c, h} */ |
133 | #define NET_PACKET_ONION_SEND_INITIAL 128 | 139 | #define NET_PACKET_ONION_SEND_INITIAL 128 |
134 | #define NET_PACKET_ONION_SEND_1 129 | 140 | #define NET_PACKET_ONION_SEND_1 129 |
@@ -143,6 +149,9 @@ typedef int sock_t; | |||
143 | #define NET_PACKET_ONION_RECV_2 141 | 149 | #define NET_PACKET_ONION_RECV_2 141 |
144 | #define NET_PACKET_ONION_RECV_1 142 | 150 | #define NET_PACKET_ONION_RECV_1 142 |
145 | 151 | ||
152 | /* Only used for bootstrap servers */ | ||
153 | #define BOOTSTRAP_INFO_PACKET_ID 240 | ||
154 | |||
146 | 155 | ||
147 | #define TOX_PORTRANGE_FROM 33445 | 156 | #define TOX_PORTRANGE_FROM 33445 |
148 | #define TOX_PORTRANGE_TO 33545 | 157 | #define TOX_PORTRANGE_TO 33545 |
diff --git a/toxcore/onion.c b/toxcore/onion.c index 961f5bd5..578621cc 100644 --- a/toxcore/onion.c +++ b/toxcore/onion.c | |||
@@ -24,6 +24,7 @@ | |||
24 | #endif | 24 | #endif |
25 | 25 | ||
26 | #include "onion.h" | 26 | #include "onion.h" |
27 | #include "util.h" | ||
27 | 28 | ||
28 | #define MAX_ONION_SIZE MAX_DATA_SIZE | 29 | #define MAX_ONION_SIZE MAX_DATA_SIZE |
29 | 30 | ||
@@ -36,6 +37,16 @@ | |||
36 | #define SEND_2 ONION_SEND_2 | 37 | #define SEND_2 ONION_SEND_2 |
37 | #define SEND_1 ONION_SEND_1 | 38 | #define SEND_1 ONION_SEND_1 |
38 | 39 | ||
40 | /* Change symmetric keys every hour to make paths expire eventually. */ | ||
41 | #define KEY_REFRESH_INTERVAL (60 * 60) | ||
42 | static void change_symmetric_key(Onion *onion) | ||
43 | { | ||
44 | if (is_timeout(onion->timestamp, KEY_REFRESH_INTERVAL)) { | ||
45 | new_symmetric_key(onion->secret_symmetric_key); | ||
46 | onion->timestamp = unix_time(); | ||
47 | } | ||
48 | } | ||
49 | |||
39 | /* Create and send a onion packet. | 50 | /* Create and send a onion packet. |
40 | * | 51 | * |
41 | * nodes is a list of 4 nodes, the packet will route through nodes 0, 1, 2 and the data | 52 | * nodes is a list of 4 nodes, the packet will route through nodes 0, 1, 2 and the data |
@@ -126,6 +137,8 @@ static int handle_send_initial(void *object, IP_Port source, uint8_t *packet, ui | |||
126 | if (length <= 1 + SEND_1) | 137 | if (length <= 1 + SEND_1) |
127 | return 1; | 138 | return 1; |
128 | 139 | ||
140 | change_symmetric_key(onion); | ||
141 | |||
129 | uint8_t plain[MAX_ONION_SIZE]; | 142 | uint8_t plain[MAX_ONION_SIZE]; |
130 | 143 | ||
131 | int len = decrypt_data(packet + 1 + crypto_box_NONCEBYTES, onion->dht->self_secret_key, packet + 1, | 144 | int len = decrypt_data(packet + 1 + crypto_box_NONCEBYTES, onion->dht->self_secret_key, packet + 1, |
@@ -170,6 +183,8 @@ static int handle_send_1(void *object, IP_Port source, uint8_t *packet, uint32_t | |||
170 | if (length <= 1 + SEND_2) | 183 | if (length <= 1 + SEND_2) |
171 | return 1; | 184 | return 1; |
172 | 185 | ||
186 | change_symmetric_key(onion); | ||
187 | |||
173 | uint8_t plain[MAX_ONION_SIZE]; | 188 | uint8_t plain[MAX_ONION_SIZE]; |
174 | 189 | ||
175 | int len = decrypt_data(packet + 1 + crypto_box_NONCEBYTES, onion->dht->self_secret_key, packet + 1, | 190 | int len = decrypt_data(packet + 1 + crypto_box_NONCEBYTES, onion->dht->self_secret_key, packet + 1, |
@@ -217,6 +232,8 @@ static int handle_send_2(void *object, IP_Port source, uint8_t *packet, uint32_t | |||
217 | if (length <= 1 + SEND_3) | 232 | if (length <= 1 + SEND_3) |
218 | return 1; | 233 | return 1; |
219 | 234 | ||
235 | change_symmetric_key(onion); | ||
236 | |||
220 | uint8_t plain[MAX_ONION_SIZE]; | 237 | uint8_t plain[MAX_ONION_SIZE]; |
221 | 238 | ||
222 | int len = decrypt_data(packet + 1 + crypto_box_NONCEBYTES, onion->dht->self_secret_key, packet + 1, | 239 | int len = decrypt_data(packet + 1 + crypto_box_NONCEBYTES, onion->dht->self_secret_key, packet + 1, |
@@ -263,6 +280,8 @@ static int handle_recv_3(void *object, IP_Port source, uint8_t *packet, uint32_t | |||
263 | if (length <= 1 + RETURN_3) | 280 | if (length <= 1 + RETURN_3) |
264 | return 1; | 281 | return 1; |
265 | 282 | ||
283 | change_symmetric_key(onion); | ||
284 | |||
266 | uint8_t plain[sizeof(IP_Port) + RETURN_2]; | 285 | uint8_t plain[sizeof(IP_Port) + RETURN_2]; |
267 | int len = decrypt_data_symmetric(onion->secret_symmetric_key, packet + 1, packet + 1 + crypto_secretbox_NONCEBYTES, | 286 | int len = decrypt_data_symmetric(onion->secret_symmetric_key, packet + 1, packet + 1 + crypto_secretbox_NONCEBYTES, |
268 | sizeof(IP_Port) + RETURN_2 + crypto_secretbox_MACBYTES, plain); | 287 | sizeof(IP_Port) + RETURN_2 + crypto_secretbox_MACBYTES, plain); |
@@ -295,6 +314,8 @@ static int handle_recv_2(void *object, IP_Port source, uint8_t *packet, uint32_t | |||
295 | if (length <= 1 + RETURN_2) | 314 | if (length <= 1 + RETURN_2) |
296 | return 1; | 315 | return 1; |
297 | 316 | ||
317 | change_symmetric_key(onion); | ||
318 | |||
298 | uint8_t plain[sizeof(IP_Port) + RETURN_1]; | 319 | uint8_t plain[sizeof(IP_Port) + RETURN_1]; |
299 | int len = decrypt_data_symmetric(onion->secret_symmetric_key, packet + 1, packet + 1 + crypto_secretbox_NONCEBYTES, | 320 | int len = decrypt_data_symmetric(onion->secret_symmetric_key, packet + 1, packet + 1 + crypto_secretbox_NONCEBYTES, |
300 | sizeof(IP_Port) + RETURN_1 + crypto_secretbox_MACBYTES, plain); | 321 | sizeof(IP_Port) + RETURN_1 + crypto_secretbox_MACBYTES, plain); |
@@ -327,6 +348,8 @@ static int handle_recv_1(void *object, IP_Port source, uint8_t *packet, uint32_t | |||
327 | if (length <= 1 + RETURN_1) | 348 | if (length <= 1 + RETURN_1) |
328 | return 1; | 349 | return 1; |
329 | 350 | ||
351 | change_symmetric_key(onion); | ||
352 | |||
330 | IP_Port send_to; | 353 | IP_Port send_to; |
331 | 354 | ||
332 | int len = decrypt_data_symmetric(onion->secret_symmetric_key, packet + 1, packet + 1 + crypto_secretbox_NONCEBYTES, | 355 | int len = decrypt_data_symmetric(onion->secret_symmetric_key, packet + 1, packet + 1 + crypto_secretbox_NONCEBYTES, |
@@ -358,6 +381,7 @@ Onion *new_onion(DHT *dht) | |||
358 | onion->dht = dht; | 381 | onion->dht = dht; |
359 | onion->net = dht->c->lossless_udp->net; | 382 | onion->net = dht->c->lossless_udp->net; |
360 | new_symmetric_key(onion->secret_symmetric_key); | 383 | new_symmetric_key(onion->secret_symmetric_key); |
384 | onion->timestamp = unix_time(); | ||
361 | 385 | ||
362 | networking_registerhandler(onion->net, NET_PACKET_ONION_SEND_INITIAL, &handle_send_initial, onion); | 386 | networking_registerhandler(onion->net, NET_PACKET_ONION_SEND_INITIAL, &handle_send_initial, onion); |
363 | networking_registerhandler(onion->net, NET_PACKET_ONION_SEND_1, &handle_send_1, onion); | 387 | networking_registerhandler(onion->net, NET_PACKET_ONION_SEND_1, &handle_send_1, onion); |
diff --git a/toxcore/onion.h b/toxcore/onion.h index b46dbdfe..a52bcb86 100644 --- a/toxcore/onion.h +++ b/toxcore/onion.h | |||
@@ -29,6 +29,7 @@ typedef struct { | |||
29 | DHT *dht; | 29 | DHT *dht; |
30 | Networking_Core *net; | 30 | Networking_Core *net; |
31 | uint8_t secret_symmetric_key[crypto_secretbox_KEYBYTES]; | 31 | uint8_t secret_symmetric_key[crypto_secretbox_KEYBYTES]; |
32 | uint64_t timestamp; | ||
32 | } Onion; | 33 | } Onion; |
33 | 34 | ||
34 | #define ONION_RETURN_1 (crypto_secretbox_NONCEBYTES + sizeof(IP_Port) + crypto_secretbox_MACBYTES) | 35 | #define ONION_RETURN_1 (crypto_secretbox_NONCEBYTES + sizeof(IP_Port) + crypto_secretbox_MACBYTES) |
diff --git a/toxcore/onion_announce.c b/toxcore/onion_announce.c index 2ca53896..da40584d 100644 --- a/toxcore/onion_announce.c +++ b/toxcore/onion_announce.c | |||
@@ -325,7 +325,7 @@ Onion_Announce *new_onion_announce(DHT *dht) | |||
325 | return NULL; | 325 | return NULL; |
326 | 326 | ||
327 | onion_a->dht = dht; | 327 | onion_a->dht = dht; |
328 | onion_a->net = dht->c->lossless_udp->net; | 328 | onion_a->net = dht->net; |
329 | new_symmetric_key(onion_a->secret_bytes); | 329 | new_symmetric_key(onion_a->secret_bytes); |
330 | 330 | ||
331 | networking_registerhandler(onion_a->net, NET_PACKET_ANNOUNCE_REQUEST, &handle_announce_request, onion_a); | 331 | networking_registerhandler(onion_a->net, NET_PACKET_ANNOUNCE_REQUEST, &handle_announce_request, onion_a); |
diff --git a/toxcore/onion_client.c b/toxcore/onion_client.c index 93697c28..c03dfcea 100644 --- a/toxcore/onion_client.c +++ b/toxcore/onion_client.c | |||
@@ -390,6 +390,8 @@ static int handle_fakeid_announce(void *object, uint8_t *source_pubkey, uint8_t | |||
390 | crypto_box_PUBLICKEYBYTES) != 0) { | 390 | crypto_box_PUBLICKEYBYTES) != 0) { |
391 | DHT_delfriend(onion_c->dht, onion_c->friends_list[friend_num].fake_client_id); | 391 | DHT_delfriend(onion_c->dht, onion_c->friends_list[friend_num].fake_client_id); |
392 | 392 | ||
393 | onion_c->friends_list[friend_num].last_seen = unix_time(); | ||
394 | |||
393 | if (DHT_addfriend(onion_c->dht, data + 1 + sizeof(uint64_t)) == 1) { | 395 | if (DHT_addfriend(onion_c->dht, data + 1 + sizeof(uint64_t)) == 1) { |
394 | return 1; | 396 | return 1; |
395 | } | 397 | } |
@@ -712,6 +714,9 @@ int onion_set_friend_online(Onion_Client *onion_c, int friend_num, uint8_t is_on | |||
712 | if ((uint32_t)friend_num >= onion_c->num_friends) | 714 | if ((uint32_t)friend_num >= onion_c->num_friends) |
713 | return -1; | 715 | return -1; |
714 | 716 | ||
717 | if (is_online == 0 && onion_c->friends_list[friend_num].is_online == 1) | ||
718 | onion_c->friends_list[friend_num].last_seen = unix_time(); | ||
719 | |||
715 | onion_c->friends_list[friend_num].is_online = is_online; | 720 | onion_c->friends_list[friend_num].is_online = is_online; |
716 | 721 | ||
717 | /* This should prevent some clock related issues */ | 722 | /* This should prevent some clock related issues */ |
@@ -767,7 +772,7 @@ static void do_friend(Onion_Client *onion_c, uint16_t friendnum) | |||
767 | } | 772 | } |
768 | 773 | ||
769 | if (count != MAX_ONION_CLIENTS) { | 774 | if (count != MAX_ONION_CLIENTS) { |
770 | if (count < rand() % MAX_ONION_CLIENTS) { | 775 | if (count < (uint32_t)rand() % MAX_ONION_CLIENTS) { |
771 | Node_format nodes_list[MAX_SENT_NODES]; | 776 | Node_format nodes_list[MAX_SENT_NODES]; |
772 | uint32_t num_nodes = get_close_nodes(onion_c->dht, onion_c->friends_list[friendnum].real_client_id, nodes_list, | 777 | uint32_t num_nodes = get_close_nodes(onion_c->dht, onion_c->friends_list[friendnum].real_client_id, nodes_list, |
773 | rand() % 2 ? AF_INET : AF_INET6, 1, 0); | 778 | rand() % 2 ? AF_INET : AF_INET6, 1, 0); |
@@ -788,6 +793,25 @@ static void do_friend(Onion_Client *onion_c, uint16_t friendnum) | |||
788 | 793 | ||
789 | } | 794 | } |
790 | } | 795 | } |
796 | |||
797 | /* Timeout before which a peer is considered dead and removed from the DHT search. */ | ||
798 | #define DEAD_ONION_TIMEOUT (10 * 60) | ||
799 | |||
800 | static void cleanup_friend(Onion_Client *onion_c, uint16_t friendnum) | ||
801 | { | ||
802 | if (friendnum >= onion_c->num_friends) | ||
803 | return; | ||
804 | |||
805 | if (onion_c->friends_list[friendnum].status == 0) | ||
806 | return; | ||
807 | |||
808 | if (onion_c->friends_list[friendnum].is_fake_clientid && !onion_c->friends_list[friendnum].is_online | ||
809 | && is_timeout(onion_c->friends_list[friendnum].last_seen, DEAD_ONION_TIMEOUT)) { | ||
810 | onion_c->friends_list[friendnum].is_fake_clientid = 0; | ||
811 | DHT_delfriend(onion_c->dht, onion_c->friends_list[friendnum].fake_client_id); | ||
812 | } | ||
813 | } | ||
814 | |||
791 | /* Function to call when onion data packet with contents beginning with byte is received. */ | 815 | /* Function to call when onion data packet with contents beginning with byte is received. */ |
792 | void oniondata_registerhandler(Onion_Client *onion_c, uint8_t byte, oniondata_handler_callback cb, void *object) | 816 | void oniondata_registerhandler(Onion_Client *onion_c, uint8_t byte, oniondata_handler_callback cb, void *object) |
793 | { | 817 | { |
@@ -823,7 +847,7 @@ static void do_announce(Onion_Client *onion_c) | |||
823 | } | 847 | } |
824 | 848 | ||
825 | if (count != MAX_ONION_CLIENTS) { | 849 | if (count != MAX_ONION_CLIENTS) { |
826 | if (count < rand() % MAX_ONION_CLIENTS) { | 850 | if (count < (uint32_t)rand() % MAX_ONION_CLIENTS) { |
827 | Node_format nodes_list[MAX_SENT_NODES]; | 851 | Node_format nodes_list[MAX_SENT_NODES]; |
828 | uint32_t num_nodes = get_close_nodes(onion_c->dht, onion_c->dht->c->self_public_key, nodes_list, | 852 | uint32_t num_nodes = get_close_nodes(onion_c->dht, onion_c->dht->c->self_public_key, nodes_list, |
829 | rand() % 2 ? AF_INET : AF_INET6, 1, 0); | 853 | rand() % 2 ? AF_INET : AF_INET6, 1, 0); |
@@ -845,6 +869,7 @@ void do_onion_client(Onion_Client *onion_c) | |||
845 | 869 | ||
846 | for (i = 0; i < onion_c->num_friends; ++i) { | 870 | for (i = 0; i < onion_c->num_friends; ++i) { |
847 | do_friend(onion_c, i); | 871 | do_friend(onion_c, i); |
872 | cleanup_friend(onion_c, i); | ||
848 | } | 873 | } |
849 | 874 | ||
850 | onion_c->last_run = unix_time(); | 875 | onion_c->last_run = unix_time(); |
diff --git a/toxcore/onion_client.h b/toxcore/onion_client.h index 708d9093..36b5b5c3 100644 --- a/toxcore/onion_client.h +++ b/toxcore/onion_client.h | |||
@@ -61,6 +61,8 @@ typedef struct { | |||
61 | uint64_t last_fakeid_dht_sent; | 61 | uint64_t last_fakeid_dht_sent; |
62 | 62 | ||
63 | uint64_t last_noreplay; | 63 | uint64_t last_noreplay; |
64 | |||
65 | uint64_t last_seen; | ||
64 | } Onion_Friend; | 66 | } Onion_Friend; |
65 | 67 | ||
66 | typedef int (*oniondata_handler_callback)(void *object, uint8_t *source_pubkey, uint8_t *data, uint32_t len); | 68 | typedef int (*oniondata_handler_callback)(void *object, uint8_t *source_pubkey, uint8_t *data, uint32_t len); |
diff --git a/toxcore/tox.c b/toxcore/tox.c index 04e412be..f4690080 100644 --- a/toxcore/tox.c +++ b/toxcore/tox.c | |||
@@ -289,6 +289,13 @@ uint32_t tox_count_friendlist(Tox *tox) | |||
289 | return count_friendlist(m); | 289 | return count_friendlist(m); |
290 | } | 290 | } |
291 | 291 | ||
292 | /* Return the number of online friends in the instance m. */ | ||
293 | uint32_t tox_get_num_online_friends(Tox *tox) | ||
294 | { | ||
295 | Messenger *m = tox; | ||
296 | return get_num_online_friends(m); | ||
297 | } | ||
298 | |||
292 | /* Copy a list of valid friend IDs into the array out_list. | 299 | /* Copy a list of valid friend IDs into the array out_list. |
293 | * If out_list is NULL, returns 0. | 300 | * If out_list is NULL, returns 0. |
294 | * Otherwise, returns the number of elements copied. | 301 | * Otherwise, returns the number of elements copied. |
diff --git a/toxcore/tox.h b/toxcore/tox.h index f3118270..447a1146 100644 --- a/toxcore/tox.h +++ b/toxcore/tox.h | |||
@@ -128,6 +128,13 @@ TOX_USERSTATUS; | |||
128 | typedef struct Tox Tox; | 128 | typedef struct Tox Tox; |
129 | #endif | 129 | #endif |
130 | 130 | ||
131 | /* NOTE: Strings in Tox are all UTF-8, also the last byte in all strings must be NULL (0). | ||
132 | * | ||
133 | * The length when passing those strings to the core includes that NULL character. | ||
134 | * | ||
135 | * If you send non NULL terminated strings Tox will force NULL terminates them when it receives them. | ||
136 | */ | ||
137 | |||
131 | /* return TOX_FRIEND_ADDRESS_SIZE byte address to give to others. | 138 | /* return TOX_FRIEND_ADDRESS_SIZE byte address to give to others. |
132 | * format: [client_id (32 bytes)][nospam number (4 bytes)][checksum (2 bytes)] | 139 | * format: [client_id (32 bytes)][nospam number (4 bytes)][checksum (2 bytes)] |
133 | */ | 140 | */ |
@@ -284,6 +291,9 @@ void tox_set_sends_receipts(Tox *tox, int friendnumber, int yesno); | |||
284 | * for copy_friendlist. */ | 291 | * for copy_friendlist. */ |
285 | uint32_t tox_count_friendlist(Tox *tox); | 292 | uint32_t tox_count_friendlist(Tox *tox); |
286 | 293 | ||
294 | /* Return the number of online friends in the instance m. */ | ||
295 | uint32_t tox_get_num_online_friends(Tox *tox); | ||
296 | |||
287 | /* Copy a list of valid friend IDs into the array out_list. | 297 | /* Copy a list of valid friend IDs into the array out_list. |
288 | * If out_list is NULL, returns 0. | 298 | * If out_list is NULL, returns 0. |
289 | * Otherwise, returns the number of elements copied. | 299 | * Otherwise, returns the number of elements copied. |