From 393433ce9910c3dffed9090c7965654f23a8e7a8 Mon Sep 17 00:00:00 2001 From: mannol Date: Sat, 15 Feb 2014 20:44:33 +0100 Subject: Public header ready to go --- toxcore/DHT.c | 10 +-- toxcore/Messenger.c | 158 ++++++++++++++++++++++++++++++++++++++++++++-- toxcore/Messenger.h | 34 ++++++++++ toxcore/event.c | 1 + toxcore/friend_requests.c | 3 + toxcore/group_chats.c | 30 ++++++++- toxcore/network.c | 4 +- toxcore/network.h | 9 +++ toxcore/onion.c | 24 +++++++ toxcore/onion.h | 1 + toxcore/onion_announce.c | 2 +- toxcore/onion_client.c | 29 ++++++++- toxcore/onion_client.h | 2 + toxcore/tox.c | 7 ++ toxcore/tox.h | 10 +++ 15 files changed, 308 insertions(+), 16 deletions(-) (limited to 'toxcore') 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 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) { + memset(nodes_list, 0, MAX_SENT_NODES * sizeof(Node_format)); #ifdef ENABLE_ASSOC_DHT if (!dht->assoc) @@ -1249,9 +1250,9 @@ int DHT_delfriend(DHT *dht, uint8_t *client_id) --dht->num_friends; if (dht->num_friends != i) { - memcpy( dht->friends_list[i].client_id, - dht->friends_list[dht->num_friends].client_id, - CLIENT_ID_SIZE ); + memcpy( &dht->friends_list[i], + &dht->friends_list[dht->num_friends], + sizeof(DHT_Friend) ); } if (dht->num_friends == 0) { @@ -1553,7 +1554,7 @@ int route_tofriend(DHT *dht, uint8_t *friend_id, uint8_t *packet, uint32_t lengt IP_Port ip_list[MAX_FRIEND_CLIENTS]; int ip_num = friend_iplist(dht, ip_list, num); - if (ip_num < (MAX_FRIEND_CLIENTS / 2)) + if (ip_num < (MAX_FRIEND_CLIENTS / 4)) return 0; /* Reason for that? */ 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, num = length / sizeof(DHT_Friend); for (i = 0; i < num; ++i) { - DHT_addfriend(dht, friend_list[i].client_id); for (j = 0; j < MAX_FRIEND_CLIENTS; ++j) { 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) return (unsigned int)friendnumber >= m->numfriends; } +static int add_online_friend(Messenger *m, int friendnumber) +{ + if (friend_not_valid(m, friendnumber)) + return -1; + + IP_Port temp_ip_port = get_friend_ipport(m, friendnumber); + + if (temp_ip_port.port == 0) + return -1; + + uint32_t i; + + for (i = 0; i < m->numonline_friends; ++i) { + if (m->online_friendlist[i].friend_num == (uint32_t)friendnumber) + return 0; + } + + Online_Friend *temp; + temp = realloc(m->online_friendlist, sizeof(Online_Friend) * (m->numonline_friends + 1)); + + if (temp == NULL) + return -1; + + m->online_friendlist = temp; + m->online_friendlist[m->numonline_friends].friend_num = friendnumber; + m->online_friendlist[m->numonline_friends].ip_port = temp_ip_port; + ++m->numonline_friends; + return 0; +} + + +static int remove_online_friend(Messenger *m, int friendnumber) +{ + uint32_t i; + Online_Friend *temp; + + for (i = 0; i < m->numonline_friends; ++i) { + /* Equal */ + if (m->online_friendlist[i].friend_num == (uint32_t)friendnumber) { + --m->numonline_friends; + + if (m->numonline_friends != i) { + memcpy( &m->online_friendlist[i], + &m->online_friendlist[m->numonline_friends], + sizeof(Online_Friend) ); + } + + if (m->numonline_friends == 0) { + free(m->online_friendlist); + m->online_friendlist = NULL; + return 0; + } + + temp = realloc(m->online_friendlist, sizeof(Online_Friend) * (m->numonline_friends)); + + if (temp == NULL) + return -1; + + m->online_friendlist = temp; + return 0; + } + } + + return -1; +} /* Set the size of the friend list to numfriends. * * return -1 if realloc fails. @@ -273,6 +338,9 @@ int m_delfriend(Messenger *m, int friendnumber) if (friend_not_valid(m, friendnumber)) return -1; + if (m->friendlist[friendnumber].status == FRIEND_ONLINE) + remove_online_friend(m, friendnumber); + onion_delfriend(m->onion_c, m->friendlist[friendnumber].onion_friendnum); crypto_kill(m->net_crypto, m->friendlist[friendnumber].crypt_connection_id); free(m->friendlist[friendnumber].statusmessage); @@ -650,12 +718,17 @@ void m_callback_connectionstatus(Messenger *m, void (*function)(Messenger *m, in m->friend_connectionstatuschange = function; m->friend_connectionstatuschange_userdata = userdata; } + +void m_callback_connectionstatus_internal_av(Messenger *m, void (*function)(Messenger *m, int, uint8_t, void *), + void *userdata) +{ + m->friend_connectionstatuschange_internal = function; + m->friend_connectionstatuschange_internal_userdata = userdata; +} + static void break_files(Messenger *m, int friendnumber); static void check_friend_connectionstatus(Messenger *m, int friendnumber, uint8_t status) { - if (!m->friend_connectionstatuschange) - return; - if (status == NOFRIEND) return; @@ -665,10 +738,19 @@ static void check_friend_connectionstatus(Messenger *m, int friendnumber, uint8_ onion_set_friend_online(m->onion_c, m->friendlist[friendnumber].onion_friendnum, is_online); if (is_online != was_online) { - if (was_online) + if (was_online) { break_files(m, friendnumber); + remove_online_friend(m, friendnumber); + } else { + add_online_friend(m, friendnumber); + } + + if (m->friend_connectionstatuschange) + m->friend_connectionstatuschange(m, friendnumber, is_online, m->friend_connectionstatuschange_userdata); - m->friend_connectionstatuschange(m, friendnumber, is_online, m->friend_connectionstatuschange_userdata); + if (m->friend_connectionstatuschange_internal) + m->friend_connectionstatuschange_internal(m, friendnumber, is_online, + m->friend_connectionstatuschange_internal_userdata); } } @@ -814,6 +896,8 @@ static void group_message_function(Group_Chat *chat, int peer_number, uint8_t *m if (i == -1) return; + message[length - 1] = 0; /* Force NULL terminator */ + if (m->group_message) (*m->group_message)(m, i, peer_number, message, length, m->group_message_userdata); } @@ -826,6 +910,8 @@ static void group_action_function(Group_Chat *chat, int peer_number, uint8_t *ac if (i == -1) return; + action[length - 1] = 0; /* Force NULL terminator */ + if (m->group_action) (*m->group_action)(m, i, peer_number, action, length, m->group_action_userdata); } @@ -1489,6 +1575,60 @@ int m_msi_packet(Messenger *m, int friendnumber, uint8_t *data, uint16_t length) return write_cryptpacket_id(m, friendnumber, PACKET_ID_MSI, data, length); } +static int friendnum_from_ip_port(Messenger *m, IP_Port ip_port) +{ + uint32_t i; + + for (i = 0; i < m->numonline_friends; ++i) { + if (ipport_equal(&m->online_friendlist[i].ip_port, &ip_port)) + return m->online_friendlist[i].friend_num; + } + + return -1; +} + +static int handle_custom_user_packet(void *object, IP_Port source, uint8_t *packet, uint32_t length) +{ + Messenger *m = object; + int friend_num = friendnum_from_ip_port(m, source); + + if (friend_num == -1) + return 1; + + if (m->friendlist[friend_num].packethandlers[packet[0] % TOTAL_USERPACKETS].function) + return m->friendlist[friend_num].packethandlers[packet[0] % TOTAL_USERPACKETS].function( + m->friendlist[friend_num].packethandlers[packet[0] % TOTAL_USERPACKETS].object, source, packet, length); + + return 1; +} + + +int custom_user_packet_registerhandler(Messenger *m, int friendnumber, uint8_t byte, packet_handler_callback cb, + void *object) +{ + if (friend_not_valid(m, friendnumber)) + return -1; + + if (byte < NET_PACKET_CUSTOM_RANGE_START || byte >= NET_PACKET_CUSTOM_RANGE_END) + return -1; + + m->friendlist[friendnumber].packethandlers[byte % TOTAL_USERPACKETS].function = cb; + m->friendlist[friendnumber].packethandlers[byte % TOTAL_USERPACKETS].object = object; + networking_registerhandler(m->net, byte, handle_custom_user_packet, m); + return 0; +} + +int send_custom_user_packet(Messenger *m, int friendnumber, uint8_t *data, uint32_t length) +{ + IP_Port ip_port = get_friend_ipport(m, friendnumber); + + if (ip_port.port == 0) + return -1; + + return sendpacket(m->net, ip_port, data, length); +} + + /* Function to filter out some friend requests*/ static int friend_already_added(uint8_t *client_id, void *data) { @@ -1841,6 +1981,8 @@ void do_friends(Messenger *m) m->friendlist[i].file_receiving[filenumber].size = filesize; m->friendlist[i].file_receiving[filenumber].transferred = 0; + data[data_length - 1] = 0; /* Force NULL terminate file name. */ + if (m->file_sendrequest) (*m->file_sendrequest)(m, i, filenumber, filesize, data + 1 + sizeof(uint64_t), data_length - 1 - sizeof(uint64_t), m->file_sendrequest_userdata); @@ -2360,6 +2502,12 @@ uint32_t count_friendlist(Messenger *m) return ret; } +/* Return the number of online friends in the instance m. */ +uint32_t get_num_online_friends(Messenger *m) +{ + return m->numonline_friends; +} + /* Copy a list of valid friend IDs into the array out_list. * If out_list is NULL, returns 0. * 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 { struct File_Transfers file_receiving[MAX_CONCURRENT_FILE_PIPES]; int invited_groups[MAX_INVITED_GROUPS]; uint16_t invited_groups_num; + + Packet_Handles packethandlers[TOTAL_USERPACKETS]; } Friend; +typedef struct { + uint32_t friend_num; + IP_Port ip_port; +} Online_Friend; + typedef struct Messenger { Networking_Core *net; @@ -179,6 +186,9 @@ typedef struct Messenger { Friend *friendlist; uint32_t numfriends; + Online_Friend *online_friendlist; + uint32_t numonline_friends; + Group_Chat **chats; uint32_t numchats; @@ -200,6 +210,8 @@ typedef struct Messenger { void *friend_statuschange_userdata; void (*friend_connectionstatuschange)(struct Messenger *m, int, uint8_t, void *); void *friend_connectionstatuschange_userdata; + void (*friend_connectionstatuschange_internal)(struct Messenger *m, int, uint8_t, void *); + void *friend_connectionstatuschange_internal_userdata; void (*group_invite)(struct Messenger *m, int, uint8_t *, void *); void *group_invite_userdata; @@ -450,6 +462,9 @@ void m_callback_read_receipt(Messenger *m, void (*function)(Messenger *m, int, u * It's assumed that when adding friends, their connection status is offline. */ void m_callback_connectionstatus(Messenger *m, void (*function)(Messenger *m, int, uint8_t, void *), void *userdata); +/* Same as previous but for internal A/V core usage only */ +void m_callback_connectionstatus_internal_av(Messenger *m, void (*function)(Messenger *m, int, uint8_t, void *), + void *userdata); /**********GROUP CHATS************/ @@ -627,6 +642,22 @@ int m_msi_packet(Messenger *m, int friendnumber, uint8_t *data, uint16_t length) /**********************************************/ +/* Set handlers for custom user packets (RTP packets for example.) + * + * return -1 on failure. + * return 0 on success. + */ +int custom_user_packet_registerhandler(Messenger *m, int friendnumber, uint8_t byte, packet_handler_callback cb, + void *object); + +/* High level function to send custom user packets. + * + * return -1 on failure. + * return number of bytes sent on success. + */ +int send_custom_user_packet(Messenger *m, int friendnumber, uint8_t *data, uint32_t length); + +/**********************************************/ /* Run this at startup. * return allocated instance of Messenger on success. * return 0 if there are problems. @@ -682,6 +713,9 @@ int messenger_load_encrypted(Messenger *m, uint8_t *data, uint32_t length, uint8 * for copy_friendlist. */ uint32_t count_friendlist(Messenger *m); +/* Return the number of online friends in the instance m. */ +uint32_t get_num_online_friends(Messenger *m); + /* Copy a list of valid friend IDs into the array out_list. * If out_list is NULL, returns 0. * 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 @@ #include "event.h" #include "util.h" +#include "network.h" #define _GNU_SOURCE 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 return 1; addto_receivedlist(fr, source_pubkey); + + packet[length - 1] = 0; /* Force NULL terminator. */ + (*fr->handle_friendrequest)(source_pubkey, packet + 4, length - 4, fr->handle_friendrequest_userdata); return 0; } 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) return -1; } +/* Compares client_id1 and client_id2 with client_id. + * + * return 0 if both are same distance. + * return 1 if client_id1 is closer. + * return 2 if client_id2 is closer. + */ +static int id_closest_groupchats(uint8_t *id, uint8_t *id1, uint8_t *id2) +{ + size_t i; + uint8_t distance1, distance2; + + for (i = 0; i < CLIENT_ID_SIZE; ++i) { + + distance1 = abs(((int8_t *)id)[i] - ((int8_t *)id1)[i]); + distance2 = abs(((int8_t *)id)[i] - ((int8_t *)id2)[i]); + + if (distance1 < distance2) + return 1; + + if (distance1 > distance2) + return 2; + } + + return 0; +} + #define BAD_GROUPNODE_TIMEOUT 30 /* @@ -100,7 +126,7 @@ static int peer_okping(Group_Chat *chat, uint8_t *client_id) if (id_equal(chat->close[i].client_id, client_id)) return -1; - if (id_closest(chat->self_public_key, chat->close[i].client_id, client_id) == 2) + if (id_closest_groupchats(chat->self_public_key, chat->close[i].client_id, client_id) == 2) ++j; } @@ -137,7 +163,7 @@ static int add_closepeer(Group_Chat *chat, uint8_t *client_id, IP_Port ip_port) } for (i = 0; i < GROUP_CLOSE_CONNECTIONS; ++i) { /* Replace nodes if given one is closer. */ - if (id_closest(chat->self_public_key, chat->close[i].client_id, client_id) == 2) { + if (id_closest_groupchats(chat->self_public_key, chat->close[i].client_id, client_id) == 2) { id_copy(chat->close[i].client_id, client_id); chat->close[i].ip_port = ip_port; 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) addr6->sin6_scope_id = 0; portptr = &addr6->sin6_port; - } else + } else { + free(temp); return NULL; + } if (ip.family == AF_INET6) { 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; #define NET_PACKET_LAN_DISCOVERY 33 /* LAN discovery packet ID. */ #define NET_PACKET_GROUP_CHATS 48 /* Group chats packet ID. */ +/* Range of ids that custom user packets can use. */ +#define NET_PACKET_CUSTOM_RANGE_START 64 +#define NET_PACKET_CUSTOM_RANGE_END 96 + +#define TOTAL_USERPACKETS (NET_PACKET_CUSTOM_RANGE_END - NET_PACKET_CUSTOM_RANGE_START) + /* See: docs/Prevent_Tracking.txt and onion.{c, h} */ #define NET_PACKET_ONION_SEND_INITIAL 128 #define NET_PACKET_ONION_SEND_1 129 @@ -143,6 +149,9 @@ typedef int sock_t; #define NET_PACKET_ONION_RECV_2 141 #define NET_PACKET_ONION_RECV_1 142 +/* Only used for bootstrap servers */ +#define BOOTSTRAP_INFO_PACKET_ID 240 + #define TOX_PORTRANGE_FROM 33445 #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 @@ #endif #include "onion.h" +#include "util.h" #define MAX_ONION_SIZE MAX_DATA_SIZE @@ -36,6 +37,16 @@ #define SEND_2 ONION_SEND_2 #define SEND_1 ONION_SEND_1 +/* Change symmetric keys every hour to make paths expire eventually. */ +#define KEY_REFRESH_INTERVAL (60 * 60) +static void change_symmetric_key(Onion *onion) +{ + if (is_timeout(onion->timestamp, KEY_REFRESH_INTERVAL)) { + new_symmetric_key(onion->secret_symmetric_key); + onion->timestamp = unix_time(); + } +} + /* Create and send a onion packet. * * 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 if (length <= 1 + SEND_1) return 1; + change_symmetric_key(onion); + uint8_t plain[MAX_ONION_SIZE]; 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 if (length <= 1 + SEND_2) return 1; + change_symmetric_key(onion); + uint8_t plain[MAX_ONION_SIZE]; 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 if (length <= 1 + SEND_3) return 1; + change_symmetric_key(onion); + uint8_t plain[MAX_ONION_SIZE]; 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 if (length <= 1 + RETURN_3) return 1; + change_symmetric_key(onion); + uint8_t plain[sizeof(IP_Port) + RETURN_2]; int len = decrypt_data_symmetric(onion->secret_symmetric_key, packet + 1, packet + 1 + crypto_secretbox_NONCEBYTES, 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 if (length <= 1 + RETURN_2) return 1; + change_symmetric_key(onion); + uint8_t plain[sizeof(IP_Port) + RETURN_1]; int len = decrypt_data_symmetric(onion->secret_symmetric_key, packet + 1, packet + 1 + crypto_secretbox_NONCEBYTES, 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 if (length <= 1 + RETURN_1) return 1; + change_symmetric_key(onion); + IP_Port send_to; 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) onion->dht = dht; onion->net = dht->c->lossless_udp->net; new_symmetric_key(onion->secret_symmetric_key); + onion->timestamp = unix_time(); networking_registerhandler(onion->net, NET_PACKET_ONION_SEND_INITIAL, &handle_send_initial, onion); 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 { DHT *dht; Networking_Core *net; uint8_t secret_symmetric_key[crypto_secretbox_KEYBYTES]; + uint64_t timestamp; } Onion; #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) return NULL; onion_a->dht = dht; - onion_a->net = dht->c->lossless_udp->net; + onion_a->net = dht->net; new_symmetric_key(onion_a->secret_bytes); 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 crypto_box_PUBLICKEYBYTES) != 0) { DHT_delfriend(onion_c->dht, onion_c->friends_list[friend_num].fake_client_id); + onion_c->friends_list[friend_num].last_seen = unix_time(); + if (DHT_addfriend(onion_c->dht, data + 1 + sizeof(uint64_t)) == 1) { return 1; } @@ -712,6 +714,9 @@ int onion_set_friend_online(Onion_Client *onion_c, int friend_num, uint8_t is_on if ((uint32_t)friend_num >= onion_c->num_friends) return -1; + if (is_online == 0 && onion_c->friends_list[friend_num].is_online == 1) + onion_c->friends_list[friend_num].last_seen = unix_time(); + onion_c->friends_list[friend_num].is_online = is_online; /* This should prevent some clock related issues */ @@ -767,7 +772,7 @@ static void do_friend(Onion_Client *onion_c, uint16_t friendnum) } if (count != MAX_ONION_CLIENTS) { - if (count < rand() % MAX_ONION_CLIENTS) { + if (count < (uint32_t)rand() % MAX_ONION_CLIENTS) { Node_format nodes_list[MAX_SENT_NODES]; uint32_t num_nodes = get_close_nodes(onion_c->dht, onion_c->friends_list[friendnum].real_client_id, nodes_list, rand() % 2 ? AF_INET : AF_INET6, 1, 0); @@ -788,6 +793,25 @@ static void do_friend(Onion_Client *onion_c, uint16_t friendnum) } } + +/* Timeout before which a peer is considered dead and removed from the DHT search. */ +#define DEAD_ONION_TIMEOUT (10 * 60) + +static void cleanup_friend(Onion_Client *onion_c, uint16_t friendnum) +{ + if (friendnum >= onion_c->num_friends) + return; + + if (onion_c->friends_list[friendnum].status == 0) + return; + + if (onion_c->friends_list[friendnum].is_fake_clientid && !onion_c->friends_list[friendnum].is_online + && is_timeout(onion_c->friends_list[friendnum].last_seen, DEAD_ONION_TIMEOUT)) { + onion_c->friends_list[friendnum].is_fake_clientid = 0; + DHT_delfriend(onion_c->dht, onion_c->friends_list[friendnum].fake_client_id); + } +} + /* Function to call when onion data packet with contents beginning with byte is received. */ void oniondata_registerhandler(Onion_Client *onion_c, uint8_t byte, oniondata_handler_callback cb, void *object) { @@ -823,7 +847,7 @@ static void do_announce(Onion_Client *onion_c) } if (count != MAX_ONION_CLIENTS) { - if (count < rand() % MAX_ONION_CLIENTS) { + if (count < (uint32_t)rand() % MAX_ONION_CLIENTS) { Node_format nodes_list[MAX_SENT_NODES]; uint32_t num_nodes = get_close_nodes(onion_c->dht, onion_c->dht->c->self_public_key, nodes_list, rand() % 2 ? AF_INET : AF_INET6, 1, 0); @@ -845,6 +869,7 @@ void do_onion_client(Onion_Client *onion_c) for (i = 0; i < onion_c->num_friends; ++i) { do_friend(onion_c, i); + cleanup_friend(onion_c, i); } 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 { uint64_t last_fakeid_dht_sent; uint64_t last_noreplay; + + uint64_t last_seen; } Onion_Friend; 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) return count_friendlist(m); } +/* Return the number of online friends in the instance m. */ +uint32_t tox_get_num_online_friends(Tox *tox) +{ + Messenger *m = tox; + return get_num_online_friends(m); +} + /* Copy a list of valid friend IDs into the array out_list. * If out_list is NULL, returns 0. * 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; typedef struct Tox Tox; #endif +/* NOTE: Strings in Tox are all UTF-8, also the last byte in all strings must be NULL (0). + * + * The length when passing those strings to the core includes that NULL character. + * + * If you send non NULL terminated strings Tox will force NULL terminates them when it receives them. + */ + /* return TOX_FRIEND_ADDRESS_SIZE byte address to give to others. * format: [client_id (32 bytes)][nospam number (4 bytes)][checksum (2 bytes)] */ @@ -284,6 +291,9 @@ void tox_set_sends_receipts(Tox *tox, int friendnumber, int yesno); * for copy_friendlist. */ uint32_t tox_count_friendlist(Tox *tox); +/* Return the number of online friends in the instance m. */ +uint32_t tox_get_num_online_friends(Tox *tox); + /* Copy a list of valid friend IDs into the array out_list. * If out_list is NULL, returns 0. * Otherwise, returns the number of elements copied. -- cgit v1.2.3