From aca2d618435388fb3029c9db6d9ea1c5ba427cbe Mon Sep 17 00:00:00 2001 From: irungentoo Date: Thu, 25 Sep 2014 15:10:54 -0400 Subject: Some code written for new group chats. --- toxcore/Makefile.inc | 2 ++ 1 file changed, 2 insertions(+) (limited to 'toxcore/Makefile.inc') diff --git a/toxcore/Makefile.inc b/toxcore/Makefile.inc index 8e39f96e..ded80681 100644 --- a/toxcore/Makefile.inc +++ b/toxcore/Makefile.inc @@ -29,6 +29,8 @@ libtoxcore_la_SOURCES = ../toxcore/DHT.h \ ../toxcore/util.c \ ../toxcore/group_chats.h \ ../toxcore/group_chats.c \ + ../toxcore/group.h \ + ../toxcore/group.c \ ../toxcore/assoc.h \ ../toxcore/assoc.c \ ../toxcore/onion.h \ -- cgit v1.2.3 From d67624bf99d03ecb754a5f406a971ad41de1cd04 Mon Sep 17 00:00:00 2001 From: irungentoo Date: Thu, 25 Sep 2014 16:48:18 -0400 Subject: Removed groupchats from core. --- toxcore/Makefile.inc | 2 - toxcore/Messenger.c | 538 ++------------------------------ toxcore/Messenger.h | 130 ++------ toxcore/group_chats.c | 837 -------------------------------------------------- toxcore/group_chats.h | 199 ------------ toxcore/network.h | 1 - toxcore/tox.c | 30 +- 7 files changed, 57 insertions(+), 1680 deletions(-) delete mode 100644 toxcore/group_chats.c delete mode 100644 toxcore/group_chats.h (limited to 'toxcore/Makefile.inc') diff --git a/toxcore/Makefile.inc b/toxcore/Makefile.inc index ded80681..8af793c8 100644 --- a/toxcore/Makefile.inc +++ b/toxcore/Makefile.inc @@ -27,8 +27,6 @@ libtoxcore_la_SOURCES = ../toxcore/DHT.h \ ../toxcore/tox.c \ ../toxcore/util.h \ ../toxcore/util.c \ - ../toxcore/group_chats.h \ - ../toxcore/group_chats.c \ ../toxcore/group.h \ ../toxcore/group.c \ ../toxcore/assoc.h \ diff --git a/toxcore/Messenger.c b/toxcore/Messenger.c index 99b95f67..edb34364 100644 --- a/toxcore/Messenger.c +++ b/toxcore/Messenger.c @@ -492,10 +492,6 @@ int setname(Messenger *m, const uint8_t *name, uint16_t length) for (i = 0; i < m->numfriends; ++i) m->friendlist[i].name_sent = 0; - for (i = 0; i < m->numchats; i++) - if (m->chats[i] != NULL) - set_nick(m->chats[i], name, length); /* TODO: remove this (group nicks should not be tied to the global one) */ - return 0; } @@ -1015,459 +1011,47 @@ static int write_cryptpacket_id(const Messenger *m, int32_t friendnumber, uint8_ /**********GROUP CHATS************/ -/* return 1 if the groupnumber is not valid. - * return 0 if the groupnumber is valid. - */ -static uint8_t groupnumber_not_valid(const Messenger *m, int groupnumber) -{ - if ((unsigned int)groupnumber >= m->numchats) - return 1; - - if (m->chats == NULL) - return 1; - - if (m->chats[groupnumber] == NULL) - return 1; - - return 0; -} - - -/* returns valid ip port of connected friend on success - * returns zeroed out IP_Port on failure - */ -static IP_Port get_friend_ipport(const Messenger *m, int32_t friendnumber) -{ - IP_Port zero; - memset(&zero, 0, sizeof(zero)); - - if (friend_not_valid(m, friendnumber)) - return zero; - - int crypt_id = m->friendlist[friendnumber].crypt_connection_id; - - uint8_t direct_connected; - - if (crypto_connection_status(m->net_crypto, crypt_id, &direct_connected) != CRYPTO_CONN_ESTABLISHED) - return zero; - - if (direct_connected == 0) - return zero; - - return m->net_crypto->crypto_connections[crypt_id].ip_port; -} - -/* returns the group number of the chat with public key group_public_key. - * returns -1 on failure. - */ -static int group_num(const Messenger *m, const uint8_t *group_public_key) -{ - uint32_t i; - - for (i = 0; i < m->numchats; ++i) { - if (m->chats[i] != NULL) - if (id_equal(m->chats[i]->self_public_key, group_public_key)) - return i; - } - - return -1; -} /* Set the callback for group invites. * - * Function(Messenger *m, int32_t friendnumber, uint8_t *group_public_key, void *userdata) + * Function(Messenger *m, int32_t friendnumber, uint8_t *data, uint16_t length, uint32_t number) */ -void m_callback_group_invite(Messenger *m, void (*function)(Messenger *m, int32_t, const uint8_t *, void *), - void *userdata) +void m_callback_group_invite(Messenger *m, void (*function)(Messenger *m, int32_t, const uint8_t *, uint16_t, uint32_t), uint32_t number) { m->group_invite = function; - m->group_invite_userdata = userdata; + m->group_invite_number = number; } /* Set the callback for group messages. * - * Function(Tox *tox, int groupnumber, int friendgroupnumber, uint8_t * message, uint16_t length, void *userdata) + * Function(Messenger *m, int32_t friendnumber, uint8_t *data, uint16_t length, uint32_t number) */ -void m_callback_group_message(Messenger *m, void (*function)(Messenger *m, int, int, const uint8_t *, uint16_t, void *), - void *userdata) +void m_callback_group_message(Messenger *m, void (*function)(Messenger *m, int32_t, const uint8_t *, uint16_t, uint32_t), uint32_t number) { m->group_message = function; - m->group_message_userdata = userdata; + m->group_message_number = number; } -/* Set the callback for group actions. +/* Send a group invite packet. * - * Function(Tox *tox, int groupnumber, int friendgroupnumber, uint8_t * message, uint16_t length, void *userdata) - */ -void m_callback_group_action(Messenger *m, void (*function)(Messenger *m, int, int, const uint8_t *, uint16_t, void *), - void *userdata) -{ - m->group_action = function; - m->group_action_userdata = userdata; -} - -/* Set callback function for peer name list changes. - * - * It gets called every time the name list changes(new peer/name, deleted peer) - * Function(Tox *tox, int groupnumber, void *userdata) - */ -void m_callback_group_namelistchange(Messenger *m, void (*function)(Messenger *m, int, int, uint8_t, void *), - void *userdata) -{ - m->group_namelistchange = function; - m->group_namelistchange_userdata = userdata; -} - -static int get_chat_num(const Messenger *m, const Group_Chat *chat) -{ - uint32_t i; - - for (i = 0; i < m->numchats; ++i) { //TODO: remove this - if (m->chats[i] == chat) - return i; - } - - return -1; -} - -static void group_message_function(Group_Chat *chat, int peer_number, const uint8_t *message, uint16_t length, - void *userdata) -{ - Messenger *m = userdata; - int i = get_chat_num(m, chat); - - if (i == -1) - return; - - uint8_t message_terminated[length + 1]; - memcpy(message_terminated, message, length); - message_terminated[length] = 0; /* Force NULL terminator */ - - if (m->group_message) - (*m->group_message)(m, i, peer_number, message_terminated, length, m->group_message_userdata); -} - -static void group_action_function(Group_Chat *chat, int peer_number, const uint8_t *action, uint16_t length, - void *userdata) -{ - Messenger *m = userdata; - int i = get_chat_num(m, chat); - - if (i == -1) - return; - - uint8_t action_terminated[length + 1]; - memcpy(action_terminated, action, length); - action_terminated[length] = 0; /* Force NULL terminator */ - - if (m->group_action) - (*m->group_action)(m, i, peer_number, action_terminated, length, m->group_action_userdata); -} - -static void group_namelistchange_function(Group_Chat *chat, int peer, uint8_t change, void *userdata) -{ - Messenger *m = userdata; - int i = get_chat_num(m, chat); - - if (i == -1) - return; - - if (m->group_namelistchange) - (*m->group_namelistchange)(m, i, peer, change, m->group_namelistchange_userdata); -} - - -/* Creates a new groupchat and puts it in the chats array. - * - * return group number on success. - * return -1 on failure. - */ -int add_groupchat(Messenger *m) -{ - uint32_t i; - - for (i = 0; i < m->numchats; ++i) { - if (m->chats[i] == NULL) { - Group_Chat *newchat = new_groupchat(m->net); - - if (newchat == NULL) - return -1; - - callback_groupmessage(newchat, &group_message_function, m); - callback_groupaction(newchat, &group_action_function, m); - callback_namelistchange(newchat, &group_namelistchange_function, m); - /* TODO: remove this (group nicks should not be tied to the global one) */ - set_nick(newchat, m->name, m->name_length); - m->chats[i] = newchat; - return i; - } - } - - Group_Chat **temp; - temp = realloc(m->chats, sizeof(Group_Chat *) * (m->numchats + 1)); - - if (temp == NULL) - return -1; - - m->chats = temp; - temp[m->numchats] = new_groupchat(m->net); - - if (temp[m->numchats] == NULL) - return -1; - - callback_groupmessage(temp[m->numchats], &group_message_function, m); - callback_groupaction(temp[m->numchats], &group_action_function, m); - callback_namelistchange(temp[m->numchats], &group_namelistchange_function, m); - /* TODO: remove this (group nicks should not be tied to the global one) */ - set_nick(temp[m->numchats], m->name, m->name_length); - ++m->numchats; - return (m->numchats - 1); -} - -/* Delete a groupchat from the chats array. - * - * return 0 on success. - * return -1 if failure. - */ -int del_groupchat(Messenger *m, int groupnumber) -{ - if ((unsigned int)groupnumber >= m->numchats) - return -1; - - if (m->chats == NULL) - return -1; - - if (m->chats[groupnumber] == NULL) - return -1; - - kill_groupchat(m->chats[groupnumber]); - m->chats[groupnumber] = NULL; - - uint32_t i; - - for (i = m->numchats; i != 0; --i) { - if (m->chats[i - 1] != NULL) - break; - } - - m->numchats = i; - - if (i == 0) { - free(m->chats); - m->chats = NULL; - } else { - Group_Chat **temp = realloc(m->chats, sizeof(Group_Chat *) * i); - - if (temp != NULL) - m->chats = temp; - } - - return 0; -} - -/* Copy the name of peernumber who is in groupnumber to name. - * name must be at least MAX_NICK_BYTES long. - * - * return length of name if success - * return -1 if failure - */ -int m_group_peername(const Messenger *m, int groupnumber, int peernumber, uint8_t *name) -{ - if ((unsigned int)groupnumber >= m->numchats) - return -1; - - if (m->chats == NULL) - return -1; - - if (m->chats[groupnumber] == NULL) - return -1; - - return group_peername(m->chats[groupnumber], peernumber, name); -} - -/* Store the fact that we invited a specific friend. - */ -static void group_store_friendinvite(Messenger *m, int32_t friendnumber, int groupnumber) -{ - /* Add 1 to the groupchat number because 0 (default value in invited_groups) is a valid groupchat number */ - m->friendlist[friendnumber].invited_groups[m->friendlist[friendnumber].invited_groups_num % MAX_INVITED_GROUPS] = - groupnumber + 1; - ++m->friendlist[friendnumber].invited_groups_num; -} - -/* return 1 if that friend was invited to the group - * return 0 if the friend was not or error. - */ -static uint8_t group_invited(const Messenger *m, int32_t friendnumber, int groupnumber) -{ - - uint32_t i; - uint16_t num = MAX_INVITED_GROUPS; - - if (MAX_INVITED_GROUPS > m->friendlist[friendnumber].invited_groups_num) - num = m->friendlist[friendnumber].invited_groups_num; - - for (i = 0; i < num; ++i) { - if (m->friendlist[friendnumber].invited_groups[i] == groupnumber + 1) { - return 1; - } - } - - return 0; -} - -/* invite friendnumber to groupnumber - * return 0 on success - * return -1 on failure - */ -int invite_friend(Messenger *m, int32_t friendnumber, int groupnumber) -{ - if (friend_not_valid(m, friendnumber) || (unsigned int)groupnumber >= m->numchats) - return -1; - - if (m->chats == NULL) - return -1; - - if (m->friendlist[friendnumber].status == NOFRIEND || m->chats[groupnumber] == NULL) - return -1; - - group_store_friendinvite(m, friendnumber, groupnumber); - - if (write_cryptpacket_id(m, friendnumber, PACKET_ID_INVITE_GROUPCHAT, m->chats[groupnumber]->self_public_key, - crypto_box_PUBLICKEYBYTES, 0) == 0) - return -1; - - return 0; -} - - -/* Join a group (you need to have been invited first.) - * - * returns group number on success - * returns -1 on failure. - */ -int join_groupchat(Messenger *m, int32_t friendnumber, const uint8_t *friend_group_public_key) -{ - if (friend_not_valid(m, friendnumber)) - return -1; - - uint8_t data[crypto_box_PUBLICKEYBYTES * 2]; - int groupnum = add_groupchat(m); - - if (groupnum == -1) - return -1; - - IP_Port friend_ip = get_friend_ipport(m, friendnumber); - - if (friend_ip.ip.family == 0) { - del_groupchat(m, groupnum); - return -1; - } - - id_copy(data, friend_group_public_key); - id_copy(data + crypto_box_PUBLICKEYBYTES, m->chats[groupnum]->self_public_key); - - if (write_cryptpacket_id(m, friendnumber, PACKET_ID_JOIN_GROUPCHAT, data, sizeof(data), 0)) { - chat_bootstrap_nonlazy(m->chats[groupnum], get_friend_ipport(m, friendnumber), - friend_group_public_key); //TODO: check if ip returned is zero? - return groupnum; - } - - del_groupchat(m, groupnum); - return -1; -} - - -/* send a group message - * return 0 on success - * return -1 on failure - */ -int group_message_send(const Messenger *m, int groupnumber, const uint8_t *message, uint32_t length) -{ - if (groupnumber_not_valid(m, groupnumber)) - return -1; - - if (group_sendmessage(m->chats[groupnumber], message, length) > 0) - return 0; - - return -1; -} - -/* send a group action - * return 0 on success - * return -1 on failure - */ -int group_action_send(const Messenger *m, int groupnumber, const uint8_t *action, uint32_t length) -{ - if (groupnumber_not_valid(m, groupnumber)) - return -1; - - if (group_sendaction(m->chats[groupnumber], action, length) > 0) - return 0; - - return -1; -} - -/* Return the number of peers in the group chat on success. - * return -1 on failure + * return 1 on success + * return 0 on failure */ -int group_number_peers(const Messenger *m, int groupnumber) +int send_group_invite_packet(const Messenger *m, int32_t friendnumber, const uint8_t *data, uint16_t length) { - if (groupnumber_not_valid(m, groupnumber)) - return -1; - - return group_numpeers(m->chats[groupnumber]); + return write_cryptpacket_id(m, friendnumber, PACKET_ID_INVITE_GROUPCHAT, data, length, 0); } -/* List all the peers in the group chat. - * - * Copies the names of the peers to the name[length][MAX_NICK_BYTES] array. +/* Send a group message packet. * - * Copies the lengths of the names to lengths[length] - * - * returns the number of peers on success. - * - * return -1 on failure. + * return 1 on success + * return 0 on failure */ -int group_names(const Messenger *m, int groupnumber, uint8_t names[][MAX_NICK_BYTES], uint16_t lengths[], - uint16_t length) -{ - if (groupnumber_not_valid(m, groupnumber)) - return -1; - - return group_client_names(m->chats[groupnumber], names, lengths, length); -} - -static int handle_group(void *object, IP_Port source, const uint8_t *packet, uint32_t length) +int send_group_message_packet(const Messenger *m, int32_t friendnumber, const uint8_t *data, uint16_t length) { - Messenger *m = object; - - if (length < crypto_box_PUBLICKEYBYTES + 1) { - return 1; - } - - uint32_t i; - - for (i = 0; i < m->numchats; ++i) { - if (m->chats[i] == NULL) - continue; - - if (id_equal(packet + 1, m->chats[i]->self_public_key)) - return handle_groupchatpacket(m->chats[i], source, packet, length); - } - - return 1; + return write_cryptpacket_id(m, friendnumber, PACKET_ID_MESSAGE_GROUPCHAT, data, length, 0); } -static void do_allgroupchats(Messenger *m) -{ - uint32_t i; - - for (i = 0; i < m->numchats; ++i) { - if (m->chats[i] != NULL) - do_groupchat(m->chats[i]); - } -} /****************FILE SENDING*****************/ @@ -2061,21 +1645,13 @@ Messenger *new_messenger(Messenger_Options *options) set_nospam(&(m->fr), random_int()); set_filter_function(&(m->fr), &friend_already_added, m); - networking_registerhandler(m->net, NET_PACKET_GROUP_CHATS, &handle_group, m); - return m; } /* Run this before closing shop. */ void kill_messenger(Messenger *m) { - /* FIXME TODO: ideally cleanupMessenger will mirror initMessenger. - * This requires the other modules to expose cleanup functions. - */ - uint32_t i, numchats = m->numchats; - - for (i = 0; i < numchats; ++i) - del_groupchat(m, i); + uint32_t i; kill_onion(m->onion); kill_onion_announce(m->onion_a); @@ -2599,30 +2175,21 @@ static int handle_packet(void *object, int i, uint8_t *temp, uint16_t len) } case PACKET_ID_INVITE_GROUPCHAT: { - if (data_length != crypto_box_PUBLICKEYBYTES) + if (data_length == 0) break; if (m->group_invite) - (*m->group_invite)(m, i, data, m->group_invite_userdata); + (*m->group_invite)(m, i, temp, len, m->group_invite_number); break; } - case PACKET_ID_JOIN_GROUPCHAT: { - if (data_length != crypto_box_PUBLICKEYBYTES * 2) - break; - - int groupnum = group_num(m, data); - - if (groupnum == -1) - break; - - if (!group_invited(m, i, groupnum)) + case PACKET_ID_MESSAGE_GROUPCHAT: { + if (data_length == 0) break; - group_newpeer(m->chats[groupnum], data + crypto_box_PUBLICKEYBYTES); - /* This is just there to speedup joining. */ - chat_bootstrap(m->chats[groupnum], get_friend_ipport(m, i), data + crypto_box_PUBLICKEYBYTES); + if (m->group_message) + (*m->group_message)(m, i, temp, len, m->group_message_number); break; } @@ -2902,7 +2469,6 @@ void do_messenger(Messenger *m) do_net_crypto(m->net_crypto); do_onion_client(m->onion_c); do_friends(m); - do_allgroupchats(m); LANdiscovery(m); #ifdef LOGGING @@ -2913,16 +2479,6 @@ void do_messenger(Messenger *m) Assoc_status(m->dht->assoc); #endif - if (m->numchats > 0) { - size_t c; - - for (c = 0; c < m->numchats; c++) { - if (m->chats[c]) - Assoc_status(m->chats[c]->assoc); - } - } - - lastdump = unix_time(); uint32_t client, last_pinged; @@ -3429,51 +2985,3 @@ int get_friendlist(const Messenger *m, int32_t **out_list, uint32_t *out_list_le return 0; } - -/* Return the number of chats in the instance m. - * You should use this to determine how much memory to allocate - * for copy_chatlist. */ -uint32_t count_chatlist(const Messenger *m) -{ - uint32_t ret = 0; - uint32_t i; - - for (i = 0; i < m->numchats; i++) { - if (m->chats[i]) { - ret++; - } - } - - return ret; -} - -/* Copy a list of valid chat IDs into the array out_list. - * If out_list is NULL, returns 0. - * Otherwise, returns the number of elements copied. - * If the array was too small, the contents - * of out_list will be truncated to list_size. */ -uint32_t copy_chatlist(const Messenger *m, int *out_list, uint32_t list_size) -{ - if (!out_list) - return 0; - - if (m->numchats == 0) { - return 0; - } - - uint32_t i; - uint32_t ret = 0; - - for (i = 0; i < m->numchats; i++) { - if (ret >= list_size) { - break; /* Abandon ship */ - } - - if (m->chats[i]) { - out_list[ret] = i; - ret++; - } - } - - return ret; -} diff --git a/toxcore/Messenger.h b/toxcore/Messenger.h index e6877002..82edd17f 100644 --- a/toxcore/Messenger.h +++ b/toxcore/Messenger.h @@ -30,7 +30,6 @@ #include "DHT.h" #include "friend_requests.h" #include "LAN_discovery.h" -#include "group_chats.h" #include "onion_client.h" #define MAX_NAME_LENGTH 128 @@ -61,12 +60,9 @@ #define PACKET_ID_FILE_SENDREQUEST 80 #define PACKET_ID_FILE_CONTROL 81 #define PACKET_ID_FILE_DATA 82 -#define PACKET_ID_INVITE_GROUPCHAT 144 -#define PACKET_ID_JOIN_GROUPCHAT 145 -#define PACKET_ID_ACCEPT_GROUPCHAT 146 +#define PACKET_ID_INVITE_GROUPCHAT 96 +#define PACKET_ID_MESSAGE_GROUPCHAT 97 -/* Max number of groups we can invite someone at the same time to. */ -#define MAX_INVITED_GROUPS 64 /* Max number of tcp relays sent to friends */ #define MAX_SHARED_RELAYS 16 @@ -227,8 +223,6 @@ typedef struct { uint64_t share_relays_lastsent; struct File_Transfers file_sending[MAX_CONCURRENT_FILE_PIPES]; struct File_Transfers file_receiving[MAX_CONCURRENT_FILE_PIPES]; - int invited_groups[MAX_INVITED_GROUPS]; - uint16_t invited_groups_num; AVATAR_SENDDATA avatar_send_data; AVATAR_RECEIVEDATA *avatar_recv_data; // We are receiving avatar data from this friend. @@ -274,9 +268,6 @@ typedef struct Messenger { uint32_t numonline_friends; - Group_Chat **chats; - uint32_t numchats; - uint64_t last_LANdiscovery; #define NUM_SAVED_TCP_RELAYS 8 @@ -308,14 +299,11 @@ typedef struct Messenger { void *avatar_data_recv_userdata; void (*avatar_data_recv)(struct Messenger *m, int32_t, uint8_t, uint8_t *, uint8_t *, uint32_t, void *); - void (*group_invite)(struct Messenger *m, int32_t, const uint8_t *, void *); - void *group_invite_userdata; - void (*group_message)(struct Messenger *m, int, int, const uint8_t *, uint16_t, void *); - void *group_message_userdata; - void (*group_action)(struct Messenger *m, int, int, const uint8_t *, uint16_t, void *); - void *group_action_userdata; - void (*group_namelistchange)(struct Messenger *m, int, int, uint8_t, void *); - void *group_namelistchange_userdata; + void *group_chat_object; /* Set by new_groupchats()*/ + void (*group_invite)(struct Messenger *m, int32_t, const uint8_t *, uint16_t, uint32_t); + uint32_t group_invite_number; + void (*group_message)(struct Messenger *m, int32_t, const uint8_t *, uint16_t, uint32_t); + uint32_t group_message_number; void (*file_sendrequest)(struct Messenger *m, int32_t, uint8_t, uint64_t, const uint8_t *, uint16_t, void *); void *file_sendrequest_userdata; @@ -747,97 +735,29 @@ void m_callback_avatar_data(Messenger *m, void (*function)(Messenger *m, int32_t /* Set the callback for group invites. * - * Function(Messenger *m, int32_t friendnumber, uint8_t *group_public_key, void *userdata) + * Function(Messenger *m, int32_t friendnumber, uint8_t *data, uint16_t length, uint32_t number) */ -void m_callback_group_invite(Messenger *m, void (*function)(Messenger *m, int32_t, const uint8_t *, void *), - void *userdata); +void m_callback_group_invite(Messenger *m, void (*function)(Messenger *m, int32_t, const uint8_t *, uint16_t, uint32_t), uint32_t number); /* Set the callback for group messages. * - * Function(Tox *tox, int groupnumber, int friendgroupnumber, uint8_t * message, uint16_t length, void *userdata) - */ -void m_callback_group_message(Messenger *m, void (*function)(Messenger *m, int, int, const uint8_t *, uint16_t, void *), - void *userdata); - -/* Set the callback for group actions. - * - * Function(Tox *tox, int groupnumber, int friendgroupnumber, uint8_t * message, uint16_t length, void *userdata) - */ -void m_callback_group_action(Messenger *m, void (*function)(Messenger *m, int, int, const uint8_t *, uint16_t, void *), - void *userdata); - -/* Set callback function for peer name list changes. - * - * It gets called every time the name list changes(new peer/name, deleted peer) - * Function(Tox *tox, int groupnumber, void *userdata) - */ -void m_callback_group_namelistchange(Messenger *m, void (*function)(Messenger *m, int, int, uint8_t, void *), - void *userdata); - -/* Creates a new groupchat and puts it in the chats array. - * - * return group number on success. - * return -1 on failure. - */ -int add_groupchat(Messenger *m); - -/* Delete a groupchat from the chats array. - * - * return 0 on success. - * return -1 if failure. - */ -int del_groupchat(Messenger *m, int groupnumber); - -/* Copy the name of peernumber who is in groupnumber to name. - * name must be at least MAX_NICK_BYTES long. - * - * return length of name if success - * return -1 if failure - */ -int m_group_peername(const Messenger *m, int groupnumber, int peernumber, uint8_t *name); - -/* invite friendnumber to groupnumber - * return 0 on success - * return -1 on failure + * Function(Messenger *m, int32_t friendnumber, uint8_t *data, uint16_t length, uint32_t number) */ -int invite_friend(Messenger *m, int32_t friendnumber, int groupnumber); +void m_callback_group_message(Messenger *m, void (*function)(Messenger *m, int32_t, const uint8_t *, uint16_t, uint32_t), uint32_t number); -/* Join a group (you need to have been invited first.) +/* Send a group invite packet. * - * returns group number on success - * returns -1 on failure. - */ -int join_groupchat(Messenger *m, int32_t friendnumber, const uint8_t *friend_group_public_key); - -/* send a group message - * return 0 on success - * return -1 on failure - */ -int group_message_send(const Messenger *m, int groupnumber, const uint8_t *message, uint32_t length); - -/* send a group action - * return 0 on success - * return -1 on failure - */ -int group_action_send(const Messenger *m, int groupnumber, const uint8_t *action, uint32_t length); - -/* Return the number of peers in the group chat on success. - * return -1 on failure + * return 1 on success + * return 0 on failure */ -int group_number_peers(const Messenger *m, int groupnumber); +int send_group_invite_packet(const Messenger *m, int32_t friendnumber, const uint8_t *data, uint16_t length); -/* List all the peers in the group chat. - * - * Copies the names of the peers to the name[length][MAX_NICK_BYTES] array. - * - * Copies the lengths of the names to lengths[length] +/* Send a group message packet. * - * returns the number of peers on success. - * - * return -1 on failure. + * return 1 on success + * return 0 on failure */ -int group_names(const Messenger *m, int groupnumber, uint8_t names[][MAX_NICK_BYTES], uint16_t lengths[], - uint16_t length); +int send_group_message_packet(const Messenger *m, int32_t friendnumber, const uint8_t *data, uint16_t length); /****************FILE SENDING*****************/ @@ -1013,16 +933,4 @@ uint32_t copy_friendlist(const Messenger *m, int32_t *out_list, uint32_t list_si */ int get_friendlist(const Messenger *m, int **out_list, uint32_t *out_list_length); -/* Return the number of chats in the instance m. - * You should use this to determine how much memory to allocate - * for copy_chatlist. */ -uint32_t count_chatlist(const Messenger *m); - -/* Copy a list of valid chat IDs into the array out_list. - * If out_list is NULL, returns 0. - * Otherwise, returns the number of elements copied. - * If the array was too small, the contents - * of out_list will be truncated to list_size. */ -uint32_t copy_chatlist(const Messenger *m, int *out_list, uint32_t list_size); - #endif diff --git a/toxcore/group_chats.c b/toxcore/group_chats.c deleted file mode 100644 index 949ec53a..00000000 --- a/toxcore/group_chats.c +++ /dev/null @@ -1,837 +0,0 @@ -/* group_chats.c - * - * An implementation of massive text only group chats. - * - * - * Copyright (C) 2013 Tox project All Rights Reserved. - * - * This file is part of Tox. - * - * Tox is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Tox is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Tox. If not, see . - * - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "DHT.h" -#include "assoc.h" -#include "group_chats.h" -#include "LAN_discovery.h" -#include "util.h" - -#define GROUPCHAT_MAXDATA_LENGTH (MAX_CRYPTO_REQUEST_SIZE - (1 + crypto_box_PUBLICKEYBYTES * 2 + crypto_box_NONCEBYTES)) -#define GROUPCHAT_MAXPLAINDATA_LENGTH (GROUPCHAT_MAXDATA_LENGTH - crypto_box_MACBYTES) - -#define GROUP_MAX_SENDNODES (GROUP_CLOSE_CONNECTIONS * 2) - -typedef struct { - uint64_t pingid; - //uint8_t client_id[crypto_box_PUBLICKEYBYTES]; - -} getnodes_data; - -typedef struct { - uint8_t client_id[crypto_box_PUBLICKEYBYTES]; - IP_Port ip_port; - -} groupchat_nodes; - -typedef struct { - uint64_t pingid; - groupchat_nodes nodes[GROUP_CLOSE_CONNECTIONS]; - //uint8_t client_id[crypto_box_PUBLICKEYBYTES]; - -} sendnodes_data; - -/* - * check if peer with client_id is in peer array. - * - * return peer number if peer is in chat. - * return -1 if peer is not in chat. - * - * TODO: make this more efficient. - */ - -static int peer_in_chat(const Group_Chat *chat, const uint8_t *client_id) -{ - uint32_t i; - - for (i = 0; i < chat->numpeers; ++i) - if (id_equal(chat->group[i].client_id, client_id)) - return i; - - 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(const uint8_t *id, const uint8_t *id1, const 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 - -/* - * Check if peer is closer to us that the other peers in the list and if the peer is in the list. - * Return the number of peers it is closer to if it is not in the closelist. - * Return -1 if the peer is in the closelist. - */ - -static int peer_okping(const Group_Chat *chat, const uint8_t *client_id) -{ - uint32_t i, j = 0; - - if (id_equal(chat->self_public_key, client_id)) - return -1; - - for (i = 0; i < GROUP_CLOSE_CONNECTIONS; ++i) { - if (is_timeout(chat->close[i].last_recv, BAD_GROUPNODE_TIMEOUT)) { - ++j; - continue; - } - - /* Equal */ - if (id_equal(chat->close[i].client_id, client_id)) - return -1; - - if (id_closest_groupchats(chat->self_public_key, chat->close[i].client_id, client_id) == 2) - ++j; - } - - return j; -} - - - -/* Attempt to add a peer to the close list. - * Update last_recv if it is in list. - * Attempt to add it to list if it is not. - * - * Return 0 if success. - * Return -1 if peer was not put in list/updated. - */ -static int add_closepeer(Group_Chat *chat, const uint8_t *client_id, IP_Port ip_port) -{ - uint32_t i; - - for (i = 0; i < GROUP_CLOSE_CONNECTIONS; ++i) { /* Check if node is already in list, if it is update its last_recv */ - if (id_equal(chat->close[i].client_id, client_id)) { - chat->close[i].last_recv = unix_time(); - return 0; - } - } - - for (i = 0; i < GROUP_CLOSE_CONNECTIONS; ++i) { /* Try replacing bad nodes first */ - if (is_timeout(chat->close[i].last_recv, BAD_GROUPNODE_TIMEOUT)) { - id_copy(chat->close[i].client_id, client_id); - chat->close[i].ip_port = ip_port; - chat->close[i].last_recv = unix_time(); - return 0; - } - } - - for (i = 0; i < GROUP_CLOSE_CONNECTIONS; ++i) { /* Replace nodes if given one is closer. */ - 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(); - return 0; - } - } - - return -1; -} - -static int send_groupchatpacket(const Group_Chat *chat, IP_Port ip_port, const uint8_t *public_key, const uint8_t *data, - uint32_t length, uint8_t request_id) -{ - if (id_equal(chat->self_public_key, public_key)) - return -1; - - uint8_t packet[MAX_CRYPTO_REQUEST_SIZE]; - int len = create_request(chat->self_public_key, chat->self_secret_key, packet, public_key, data, length, request_id); - packet[0] = NET_PACKET_GROUP_CHATS; - - if (len == -1) - return -1; - - if (sendpacket(chat->net, ip_port, packet, len) == len) - return 0; - - return -1; - -} - -/* - * Send data to all peers in close peer list. - * - * return the number of peers the packet was sent to. - */ -static uint8_t sendto_allpeers(const Group_Chat *chat, const uint8_t *data, uint16_t length, uint8_t request_id) -{ - uint16_t sent = 0; - uint32_t i; - - for (i = 0; i < GROUP_CLOSE_CONNECTIONS; ++i) { - if (ip_isset(&chat->close[i].ip_port.ip) && - !is_timeout(chat->close[i].last_recv, BAD_GROUPNODE_TIMEOUT)) { - if (send_groupchatpacket(chat, chat->close[i].ip_port, chat->close[i].client_id, - data, length, request_id) == 0) - ++sent; - } - } - - return sent; -} - - -/* - * Add a peer to the group chat. - * - * return peernum if success or peer already in chat. - * return -1 if error. - */ -static int addpeer(Group_Chat *chat, const uint8_t *client_id) -{ - int peernum = peer_in_chat(chat, client_id); - - if (peernum != -1) - return peernum; - - Group_Peer *temp; - temp = realloc(chat->group, sizeof(Group_Peer) * (chat->numpeers + 1)); - - if (temp == NULL) - return -1; - - memset(&(temp[chat->numpeers]), 0, sizeof(Group_Peer)); - chat->group = temp; - - id_copy(chat->group[chat->numpeers].client_id, client_id); - chat->group[chat->numpeers].last_recv = unix_time(); - chat->group[chat->numpeers].last_recv_msgping = unix_time(); - ++chat->numpeers; - - if (chat->peer_namelistchange != NULL) - (*chat->peer_namelistchange)(chat, chat->numpeers - 1, CHAT_CHANGE_PEER_ADD, chat->group_namelistchange_userdata); - - return (chat->numpeers - 1); -} - -/* - * Set a peer from the group chat to deleted. - * - * return 0 if success - * return -1 if error. - */ -static int del_peer_set(Group_Chat *chat, int peernum) -{ - if ((uint32_t)peernum >= chat->numpeers) - return -1; - - chat->group[peernum].deleted = 1; - chat->group[peernum].deleted_time = unix_time(); - return 0; -} - -/* - * Delete a peer from the group chat. - * - * return 0 if success - * return -1 if error. - */ -static int delpeer(Group_Chat *chat, int peernum) -{ - if ((uint32_t)peernum >= chat->numpeers) - return -1; - - uint32_t i; - - for (i = 0; i < GROUP_CLOSE_CONNECTIONS; ++i) { /* If peer is in close list, time it out forcefully. */ - if (id_equal(chat->close[i].client_id, chat->group[peernum].client_id)) { - chat->close[i].last_recv = 0; - break; - } - } - - Group_Peer *temp; - --chat->numpeers; - - if (chat->numpeers == 0) { - free(chat->group); - chat->group = NULL; - return 0; - } - - if (chat->numpeers != (uint32_t)peernum) - memcpy(&chat->group[peernum], &chat->group[chat->numpeers], sizeof(Group_Peer)); - - temp = realloc(chat->group, sizeof(Group_Peer) * (chat->numpeers)); - - if (temp == NULL) - return -1; - - chat->group = temp; - - if (chat->peer_namelistchange != NULL) { - (*chat->peer_namelistchange)(chat, peernum, CHAT_CHANGE_PEER_DEL, chat->group_namelistchange_userdata); - } - - return 0; -} - -/* Copy the name of peernum to name. - * name must be at least MAX_NICK_BYTES long. - * - * return length of name if success - * return -1 if failure - */ -int group_peername(const Group_Chat *chat, int peernum, uint8_t *name) -{ - if ((uint32_t)peernum >= chat->numpeers) - return -1; - - if (chat->group[peernum].nick_len == 0) { - /* memcpy(name, "NSA agent", 10); */ /* Srsly? */ /* Kindly remind the user that someone with no name might be a moronic NSA agent.*/ - name[0] = 0; - return 0; - } - - memcpy(name, chat->group[peernum].nick, chat->group[peernum].nick_len); - return chat->group[peernum].nick_len; -} - -static void setnick(Group_Chat *chat, int peernum, const uint8_t *contents, uint16_t contents_len) -{ - if (contents_len > MAX_NICK_BYTES || contents_len == 0) - return; - - /* same name as already stored? */ - if (chat->group[peernum].nick_len == contents_len) - if (!memcmp(chat->group[peernum].nick, contents, contents_len)) - return; - - memcpy(chat->group[peernum].nick, contents, contents_len); - chat->group[peernum].nick_len = contents_len; - - if (chat->peer_namelistchange != NULL) - (*chat->peer_namelistchange)(chat, peernum, CHAT_CHANGE_PEER_NAME, chat->group_namelistchange_userdata); -} - -/* min time between pings sent to one peer in seconds */ -/* TODO: move this to global section */ -#define GROUP_PING_TIMEOUT 5 - -static int send_getnodes(const Group_Chat *chat, IP_Port ip_port, int peernum) -{ - if ((uint32_t)peernum >= chat->numpeers) - return -1; - - if (!is_timeout(chat->group[peernum].last_pinged, GROUP_PING_TIMEOUT)) - return -1; - - getnodes_data contents; - contents.pingid = random_64b(); - - chat->group[peernum].last_pinged = unix_time(); - chat->group[peernum].pingid = contents.pingid; - chat->group[peernum].ping_via = ip_port; - - if (chat->assoc) { - IPPTs ippts; - ippts.timestamp = unix_time(); - ippts.ip_port = ip_port; - - Assoc_add_entry(chat->assoc, chat->group[peernum].client_id, &ippts, NULL, 1); - } - - return send_groupchatpacket(chat, ip_port, chat->group[peernum].client_id, (uint8_t *)&contents, sizeof(contents), - CRYPTO_PACKET_GROUP_CHAT_GET_NODES); -} - -static int send_sendnodes(const Group_Chat *chat, IP_Port ip_port, int peernum, uint64_t pingid) -{ - if ((uint32_t)peernum >= chat->numpeers) - return -1; - - sendnodes_data contents; - contents.pingid = pingid; - uint32_t i, j = 0; - - for (i = 0; i < GROUP_CLOSE_CONNECTIONS; ++i) { - if (!is_timeout(chat->close[i].last_recv, BAD_GROUPNODE_TIMEOUT)) { - id_copy(contents.nodes[j].client_id, chat->close[i].client_id); - contents.nodes[j].ip_port = chat->close[i].ip_port; - to_net_family(&contents.nodes[j].ip_port.ip); - ++j; - } - } - - return send_groupchatpacket(chat, ip_port, chat->group[peernum].client_id, (uint8_t *)&contents, - sizeof(contents.pingid) + sizeof(groupchat_nodes) * j, CRYPTO_PACKET_GROUP_CHAT_SEND_NODES); -} - -static int handle_getnodes(const Group_Chat *chat, IP_Port source, int peernum, const uint8_t *data, uint32_t len) -{ - if (len != sizeof(getnodes_data)) - return 1; - - if ((uint32_t)peernum >= chat->numpeers) - return 1; - - getnodes_data contents; - memcpy(&contents, data, sizeof(contents)); - send_sendnodes(chat, source, peernum, contents.pingid); - - if (peer_okping(chat, chat->group[peernum].client_id) > 0) - send_getnodes(chat, source, peernum); - - return 0; -} - -static int handle_sendnodes(Group_Chat *chat, IP_Port source, int peernum, const uint8_t *data, uint32_t len) -{ - if ((uint32_t)peernum >= chat->numpeers) - return 1; - - if (len > sizeof(sendnodes_data) || len < sizeof(uint64_t)) - return 1; - - if ((len - sizeof(uint64_t)) % sizeof(groupchat_nodes) != 0) - return 1; - - if (is_timeout(chat->group[peernum].last_pinged, GROUP_PING_TIMEOUT)) - return 1; - - sendnodes_data contents; - memcpy(&contents, data, len); - - if (contents.pingid != chat->group[peernum].pingid) - return 1; - - uint16_t numnodes = (len - sizeof(contents.pingid)) / sizeof(groupchat_nodes); - uint32_t i; - - IPPTs ippts_send; - ippts_send.timestamp = unix_time(); - - for (i = 0; i < numnodes; ++i) { - if (peer_okping(chat, contents.nodes[i].client_id) > 0) { - int peern = peer_in_chat(chat, contents.nodes[i].client_id); - - if (peern == -1) { /*NOTE: This is just for testing and will be removed later.*/ - peern = addpeer(chat, contents.nodes[i].client_id); - } - - if (peern == -1) - continue; - - to_host_family(&contents.nodes[i].ip_port.ip); - send_getnodes(chat, contents.nodes[i].ip_port, peern); - - if (chat->assoc) { - ippts_send.ip_port = contents.nodes[i].ip_port; - Assoc_add_entry(chat->assoc, contents.nodes[i].client_id, &ippts_send, NULL, 0); - } - } - } - - add_closepeer(chat, chat->group[peernum].client_id, source); - - return 0; -} - -#define GROUP_DATA_MIN_SIZE (crypto_box_PUBLICKEYBYTES + sizeof(uint32_t) + 1) -static void send_names_new_peer(Group_Chat *chat); - -static int handle_data(Group_Chat *chat, const uint8_t *data, uint32_t len) -{ - if (len < GROUP_DATA_MIN_SIZE) - return 1; - -//TODO: - int peernum = peer_in_chat(chat, data); - - if (peernum == -1) { /*NOTE: This is just for testing and will be removed later.*/ - if (data[crypto_box_PUBLICKEYBYTES + sizeof(uint32_t)] != GROUP_CHAT_QUIT) - peernum = addpeer(chat, data); - } - - if (peernum == -1) - return 1; - - if (chat->group[peernum].deleted) - return 1; - - /* Spam prevention (1 message per peer per second limit.) - - if (chat->group[peernum].last_recv == temp_time) - return 1; - */ - chat->group[peernum].last_recv = unix_time(); - - uint32_t message_num; - memcpy(&message_num, data + crypto_box_PUBLICKEYBYTES, sizeof(uint32_t)); - message_num = ntohl(message_num); - - if (chat->group[peernum].last_message_number == 0) { - chat->group[peernum].last_message_number = message_num; - } else if (message_num - chat->group[peernum].last_message_number > 64 || - message_num == chat->group[peernum].last_message_number) - return 1; - - chat->group[peernum].last_message_number = message_num; - - int handled = 1; - const uint8_t *contents = data + GROUP_DATA_MIN_SIZE; - uint16_t contents_len = len - GROUP_DATA_MIN_SIZE; - - switch (data[crypto_box_PUBLICKEYBYTES + sizeof(message_num)]) { - case GROUP_CHAT_PING: /* If message is ping */ - if (contents_len != 0) - return 1; - - chat->group[peernum].last_recv_msgping = unix_time(); - break; - - case GROUP_CHAT_NEW_PEER: /* If message is new peer */ - if (contents_len != crypto_box_PUBLICKEYBYTES) - return 1; - - addpeer(chat, contents); - send_names_new_peer(chat); - break; - - case GROUP_CHAT_QUIT: /* If peer tells us he is quitting */ - if (contents_len != 0) - return 1; - - del_peer_set(chat, peernum); - break; - - case GROUP_CHAT_PEER_NICK: - if (contents_len > MAX_NICK_BYTES || contents_len == 0) - return 1; - - setnick(chat, peernum, contents, contents_len); - break; - - case GROUP_CHAT_CHAT_MESSAGE: /* If message is chat message */ - if (chat->group_message != NULL) - (*chat->group_message)(chat, peernum, contents, contents_len, chat->group_message_userdata); - - break; - - case GROUP_CHAT_ACTION: /* if message is a peer action */ - if (chat->group_action != NULL) - (*chat->group_action)(chat, peernum, contents, contents_len, chat->group_action_userdata); - - break; - - default: - handled = 0; - break; - - } - - if (handled == 1) { - sendto_allpeers(chat, data, len, CRYPTO_PACKET_GROUP_CHAT_BROADCAST); - return 0; - } - - return 1; -} - -static uint8_t send_data(Group_Chat *chat, const uint8_t *data, uint32_t len, uint8_t message_id) -{ - if (len + GROUP_DATA_MIN_SIZE > MAX_CRYPTO_REQUEST_SIZE) /*NOTE: not the real maximum len.*/ - return 1; - - uint8_t packet[MAX_CRYPTO_REQUEST_SIZE]; - ++chat->message_number; - - if (chat->message_number == 0) - chat->message_number = 1; - - uint32_t message_num = htonl(chat->message_number); -//TODO - id_copy(packet, chat->self_public_key); - memcpy(packet + crypto_box_PUBLICKEYBYTES, &message_num, sizeof(message_num)); - - if (len != 0) - memcpy(packet + GROUP_DATA_MIN_SIZE, data, len); - - packet[crypto_box_PUBLICKEYBYTES + sizeof(message_num)] = message_id; - return sendto_allpeers(chat, packet, len + GROUP_DATA_MIN_SIZE, CRYPTO_PACKET_GROUP_CHAT_BROADCAST); -} -/* - * Handle get nodes group packet. - * - * return 0 if handled correctly. - * return 1 if error. - */ - -int handle_groupchatpacket(Group_Chat *chat, IP_Port source, const uint8_t *packet, uint32_t length) -{ - if (length > MAX_CRYPTO_REQUEST_SIZE) - return 1; - - uint8_t public_key[crypto_box_PUBLICKEYBYTES]; - uint8_t data[MAX_CRYPTO_REQUEST_SIZE]; - uint8_t number; - int len = handle_request(chat->self_public_key, chat->self_secret_key, public_key, data, &number, packet, length); - - if (len <= 0) - return 1; - - if (id_equal(chat->self_public_key, public_key)) - return 1; - - int peernum = peer_in_chat(chat, public_key); - - if (peernum == -1) - return 1; - - switch (number) { - case CRYPTO_PACKET_GROUP_CHAT_GET_NODES: - return handle_getnodes(chat, source, peernum, data, len); - - case CRYPTO_PACKET_GROUP_CHAT_SEND_NODES: - return handle_sendnodes(chat, source, peernum, data, len); - - case CRYPTO_PACKET_GROUP_CHAT_BROADCAST: - return handle_data(chat, data, len); - - default: - return 1; - } - - return 1; -} - -uint32_t group_sendmessage(Group_Chat *chat, const uint8_t *message, uint32_t length) -{ - return send_data(chat, message, length, GROUP_CHAT_CHAT_MESSAGE); //TODO: better return values? -} - -uint32_t group_sendaction(Group_Chat *chat, const uint8_t *action, uint32_t length) -{ - return send_data(chat, action, length, GROUP_CHAT_ACTION); -} - -/* - * Send id/nick combo to the group. - * - * returns the number of peers it has sent it to. - */ -static uint32_t group_send_nick(Group_Chat *chat, uint8_t *nick, uint16_t nick_len) -{ - if (nick_len > MAX_NICK_BYTES) - return 0; - - return send_data(chat, nick, nick_len, GROUP_CHAT_PEER_NICK); -} - -int set_nick(Group_Chat *chat, const uint8_t *nick, uint16_t nick_len) -{ - if (nick_len > MAX_NICK_BYTES || nick_len == 0) - return -1; - - memcpy(chat->nick, nick, nick_len); - chat->nick_len = nick_len; - group_send_nick(chat, chat->nick, chat->nick_len); - return 0; -} - -uint32_t group_newpeer(Group_Chat *chat, const uint8_t *client_id) -{ - addpeer(chat, client_id); - return send_data(chat, client_id, crypto_box_PUBLICKEYBYTES, GROUP_CHAT_NEW_PEER); //TODO: better return values? -} - -void callback_groupmessage(Group_Chat *chat, void (*function)(Group_Chat *chat, int, const uint8_t *, uint16_t, void *), - void *userdata) -{ - chat->group_message = function; - chat->group_message_userdata = userdata; -} - -void callback_groupaction(Group_Chat *chat, void (*function)(Group_Chat *chat, int, const uint8_t *, uint16_t, void *), - void *userdata) -{ - chat->group_action = function; - chat->group_action_userdata = userdata; -} - -void callback_namelistchange(Group_Chat *chat, void (*function)(Group_Chat *chat, int peer, uint8_t change, void *), - void *userdata) -{ - chat->peer_namelistchange = function; - chat->group_namelistchange_userdata = userdata; -} - -uint32_t group_numpeers(const Group_Chat *chat) -{ - return chat->numpeers; -} - -uint32_t group_client_names(const Group_Chat *chat, uint8_t names[][MAX_NICK_BYTES], uint16_t lengths[], - uint16_t length) -{ - uint32_t i; - - for (i = 0; i < chat->numpeers && i < length; ++i) { - lengths[i] = group_peername(chat, i, names[i]); - } - - return i; -} - -Group_Chat *new_groupchat(Networking_Core *net) -{ - unix_time_update(); - - if (net == 0) - return 0; - - Group_Chat *chat = calloc(1, sizeof(Group_Chat)); - chat->net = net; - crypto_box_keypair(chat->self_public_key, chat->self_secret_key); - - /* (2^4) * 5 = 80 entries seems to be a moderate size */ - chat->assoc = new_Assoc(4, 5, chat->self_public_key); - - return chat; -} - -#define NODE_PING_INTERVAL 10 - -static void ping_close(Group_Chat *chat) -{ - uint32_t i; - - for (i = 0; i < GROUP_CLOSE_CONNECTIONS; ++i) { - if (!is_timeout(chat->close[i].last_recv, BAD_GROUPNODE_TIMEOUT)) { - int peernum = peer_in_chat(chat, chat->close[i].client_id); - - if (peernum == -1) - continue; - - if (is_timeout(chat->group[peernum].last_pinged, NODE_PING_INTERVAL)) - send_getnodes(chat, chat->close[i].ip_port, peernum); - } - } -} - -/* Interval in seconds to send ping messages */ -#define GROUP_PING_INTERVAL 30 - -static void ping_group(Group_Chat *chat) -{ - if (is_timeout(chat->last_sent_ping, GROUP_PING_INTERVAL)) { - if (send_data(chat, 0, 0, GROUP_CHAT_PING) != 0) /* Ping */ - chat->last_sent_ping = unix_time(); - } -} - -#define DEL_PEER_DELAY 3 -static void del_dead_peers(Group_Chat *chat) -{ - uint32_t i; - - for (i = 0; i < chat->numpeers; ++i) { - if (is_timeout(chat->group[i].last_recv_msgping, GROUP_PING_INTERVAL * 4)) { - delpeer(chat, i); - } - - if (chat->group == NULL || i >= chat->numpeers) - break; - - if (chat->group[i].deleted) { - if (is_timeout(chat->group[i].deleted_time, DEL_PEER_DELAY)) - delpeer(chat, i); - } - } -} - -#define NICK_SEND_INTERVAL 180 -static void send_names_new_peer(Group_Chat *chat) -{ - group_send_nick(chat, chat->nick, chat->nick_len); - chat->last_sent_nick = (unix_time() - NICK_SEND_INTERVAL) + 15; -} -static void send_names(Group_Chat *chat) -{ - /* send own nick from time to time, to let newly added peers be informed - * first time only: use a shorter timeframe, because we might not be in our own - * peer list yet */ - if (is_timeout(chat->last_sent_nick, 180)) - if (group_send_nick(chat, chat->nick, chat->nick_len) > 0) { - if (!chat->last_sent_nick) - chat->last_sent_nick = (unix_time() - NICK_SEND_INTERVAL) + 10; - else - chat->last_sent_nick = unix_time(); - } -} - -void do_groupchat(Group_Chat *chat) -{ - unix_time_update(); - ping_close(chat); - ping_group(chat); - /* TODO: Maybe run this less? */ - del_dead_peers(chat); - send_names(chat); -} - -void kill_groupchat(Group_Chat *chat) -{ - send_data(chat, 0, 0, GROUP_CHAT_QUIT); - kill_Assoc(chat->assoc); - free(chat->group); - free(chat); -} - -void chat_bootstrap(Group_Chat *chat, IP_Port ip_port, const uint8_t *client_id) -{ - send_getnodes(chat, ip_port, addpeer(chat, client_id)); -} - -void chat_bootstrap_nonlazy(Group_Chat *chat, IP_Port ip_port, const uint8_t *client_id) -{ - send_getnodes(chat, ip_port, addpeer(chat, client_id)); - add_closepeer(chat, client_id, ip_port); -} diff --git a/toxcore/group_chats.h b/toxcore/group_chats.h deleted file mode 100644 index 1a7a2e04..00000000 --- a/toxcore/group_chats.h +++ /dev/null @@ -1,199 +0,0 @@ -/* group_chats.h - * - * An implementation of massive text only group chats. - * - * - * Copyright (C) 2013 Tox project All Rights Reserved. - * - * This file is part of Tox. - * - * Tox is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Tox is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Tox. If not, see . - * - */ - -#ifndef GROUP_CHATS_H -#define GROUP_CHATS_H - -#define MAX_NICK_BYTES 128 - -typedef struct { - uint8_t client_id[crypto_box_PUBLICKEYBYTES]; - uint64_t pingid; - uint64_t last_pinged; - IP_Port ping_via; - - uint64_t last_recv; - uint64_t last_recv_msgping; - uint32_t last_message_number; - - uint8_t nick[MAX_NICK_BYTES]; - uint16_t nick_len; - - uint8_t deleted; - uint64_t deleted_time; -} Group_Peer; - -typedef struct { - uint8_t client_id[crypto_box_PUBLICKEYBYTES]; - IP_Port ip_port; - uint64_t last_recv; -} Group_Close; - -#define GROUP_CLOSE_CONNECTIONS 6 - -typedef struct Group_Chat { - Networking_Core *net; - uint8_t self_public_key[crypto_box_PUBLICKEYBYTES]; - uint8_t self_secret_key[crypto_box_SECRETKEYBYTES]; - - Group_Peer *group; - Group_Close close[GROUP_CLOSE_CONNECTIONS]; - uint32_t numpeers; - - uint32_t message_number; - void (*group_message)(struct Group_Chat *m, int, const uint8_t *, uint16_t, void *); - void *group_message_userdata; - void (*group_action)(struct Group_Chat *m, int, const uint8_t *, uint16_t, void *); - void *group_action_userdata; - void (*peer_namelistchange)(struct Group_Chat *m, int peer, uint8_t change, void *); - void *group_namelistchange_userdata; - - uint64_t last_sent_ping; - - uint8_t nick[MAX_NICK_BYTES]; - uint16_t nick_len; - uint64_t last_sent_nick; - - struct Assoc *assoc; -} Group_Chat; - -#define GROUP_CHAT_PING 0 -#define GROUP_CHAT_NEW_PEER 16 -#define GROUP_CHAT_QUIT 24 -#define GROUP_CHAT_PEER_NICK 48 -#define GROUP_CHAT_CHAT_MESSAGE 64 -#define GROUP_CHAT_ACTION 63 - -/* Copy the name of peernum to name. - * name must be at least MAX_NICK_BYTES long. - * - * return length of name if success - * return -1 if failure - */ -int group_peername(const Group_Chat *chat, int peernum, uint8_t *name); - -/* - * Set callback function for chat messages. - * - * format of function is: function(Group_Chat *chat, peer number, message, message length, userdata) - */ -void callback_groupmessage(Group_Chat *chat, void (*function)(Group_Chat *chat, int, const uint8_t *, uint16_t, void *), - void *userdata); - -/* - * Set callback function for actions. - * - * format of function is: function(Group_Chat *chat, peer number, action, action length, userdata) - */ -void callback_groupaction(Group_Chat *chat, void (*function)(Group_Chat *chat, int, const uint8_t *, uint16_t, void *), - void *userdata); - -/* - * Set callback function for peer name list changes. - * - * It gets called every time the name list changes(new peer/name, deleted peer) - * - * format of function is: function(Group_Chat *chat, userdata) - */ -typedef enum { - CHAT_CHANGE_PEER_ADD, - CHAT_CHANGE_PEER_DEL, - CHAT_CHANGE_PEER_NAME, -} CHAT_CHANGE; - -void callback_namelistchange(Group_Chat *chat, void (*function)(Group_Chat *chat, int peer, uint8_t change, void *), - void *userdata); - -/* - * Send a message to the group. - * - * returns the number of peers it has sent it to. - */ -uint32_t group_sendmessage(Group_Chat *chat, const uint8_t *message, uint32_t length); - -/* - * Send an action to the group. - * - * returns the number of peers it has sent it to. - */ -uint32_t group_sendaction(Group_Chat *chat, const uint8_t *action, uint32_t length); - -/* - * Set our nick for this group. - * - * returns -1 on failure, 0 on success. - */ -int set_nick(Group_Chat *chat, const uint8_t *nick, uint16_t nick_len); - -/* - * Tell everyone about a new peer (a person we are inviting for example.) - * - */ -uint32_t group_newpeer(Group_Chat *chat, const uint8_t *client_id); - - -/* Create a new group chat. - * - * Returns a new group chat instance if success. - * - * Returns a NULL pointer if fail. - */ -Group_Chat *new_groupchat(Networking_Core *net); - - -/* Return the number of peers in the group chat. - */ -uint32_t group_numpeers(const Group_Chat *chat); - -/* List all the peers in the group chat. - * - * Copies the names of the peers to the name[length][MAX_NICK_BYTES] array. - * - * returns the number of peers. - */ -uint32_t group_client_names(const Group_Chat *chat, uint8_t names[][MAX_NICK_BYTES], uint16_t lengths[], - uint16_t length); - -/* Kill a group chat - * - * Frees the memory and everything. - */ -void kill_groupchat(Group_Chat *chat); - -/* - * This is the main loop. - */ -void do_groupchat(Group_Chat *chat); - -/* if we receive a group chat packet we call this function so it can be handled. - return 0 if packet is handled correctly. - return 1 if it didn't handle the packet or if the packet was shit. */ -int handle_groupchatpacket(Group_Chat *chat, IP_Port source, const uint8_t *packet, uint32_t length); - - -void chat_bootstrap(Group_Chat *chat, IP_Port ip_port, const uint8_t *client_id); -void chat_bootstrap_nonlazy(Group_Chat *chat, IP_Port ip_port, const uint8_t *client_id); - - -#endif diff --git a/toxcore/network.h b/toxcore/network.h index b250604e..6e1f2244 100644 --- a/toxcore/network.h +++ b/toxcore/network.h @@ -105,7 +105,6 @@ typedef int sock_t; #define NET_PACKET_CRYPTO_DATA 27 /* Crypto data packet */ #define NET_PACKET_CRYPTO 32 /* Encrypted data packet ID. */ #define NET_PACKET_LAN_DISCOVERY 33 /* LAN discovery packet ID. */ -#define NET_PACKET_GROUP_CHATS 48 /* Group chats packet ID. */ /* See: docs/Prevent_Tracking.txt and onion.{c, h} */ #define NET_PACKET_ONION_SEND_INITIAL 128 diff --git a/toxcore/tox.c b/toxcore/tox.c index e8ec593b..39a63fd9 100644 --- a/toxcore/tox.c +++ b/toxcore/tox.c @@ -550,7 +550,7 @@ void tox_callback_group_invite(Tox *tox, void (*function)(Messenger *tox, int32_ void *userdata) { Messenger *m = tox; - m_callback_group_invite(m, function, userdata); + //m_callback_group_invite(m, function, userdata); } /* Set the callback for group messages. @@ -561,7 +561,7 @@ void tox_callback_group_message(Tox *tox, void (*function)(Messenger *tox, int, void *userdata) { Messenger *m = tox; - m_callback_group_message(m, function, userdata); + //m_callback_group_message(m, function, userdata); } /* Set the callback for group actions. @@ -572,7 +572,7 @@ void tox_callback_group_action(Tox *tox, void (*function)(Messenger *tox, int, i void *userdata) { Messenger *m = tox; - m_callback_group_action(m, function, userdata); + //m_callback_group_action(m, function, userdata); } /* Set callback function for peer name list changes. @@ -583,7 +583,7 @@ void tox_callback_group_action(Tox *tox, void (*function)(Messenger *tox, int, i void tox_callback_group_namelist_change(Tox *tox, void (*function)(Tox *tox, int, int, uint8_t, void *), void *userdata) { Messenger *m = tox; - m_callback_group_namelistchange(m, function, userdata); + //m_callback_group_namelistchange(m, function, userdata); } /* Creates a new groupchat and puts it in the chats array. @@ -594,7 +594,7 @@ void tox_callback_group_namelist_change(Tox *tox, void (*function)(Tox *tox, int int tox_add_groupchat(Tox *tox) { Messenger *m = tox; - return add_groupchat(m); + //return add_groupchat(m); } /* Delete a groupchat from the chats array. * @@ -604,7 +604,7 @@ int tox_add_groupchat(Tox *tox) int tox_del_groupchat(Tox *tox, int groupnumber) { Messenger *m = tox; - return del_groupchat(m, groupnumber); + //return del_groupchat(m, groupnumber); } /* Copy the name of peernumber who is in groupnumber to name. @@ -616,7 +616,7 @@ int tox_del_groupchat(Tox *tox, int groupnumber) int tox_group_peername(const Tox *tox, int groupnumber, int peernumber, uint8_t *name) { const Messenger *m = tox; - return m_group_peername(m, groupnumber, peernumber, name); + //return m_group_peername(m, groupnumber, peernumber, name); } /* invite friendnumber to groupnumber * return 0 on success @@ -625,7 +625,7 @@ int tox_group_peername(const Tox *tox, int groupnumber, int peernumber, uint8_t int tox_invite_friend(Tox *tox, int32_t friendnumber, int groupnumber) { Messenger *m = tox; - return invite_friend(m, friendnumber, groupnumber); + //return invite_friend(m, friendnumber, groupnumber); } /* Join a group (you need to have been invited first.) * @@ -635,7 +635,7 @@ int tox_invite_friend(Tox *tox, int32_t friendnumber, int groupnumber) int tox_join_groupchat(Tox *tox, int32_t friendnumber, const uint8_t *friend_group_public_key) { Messenger *m = tox; - return join_groupchat(m, friendnumber, friend_group_public_key); + //return join_groupchat(m, friendnumber, friend_group_public_key); } /* send a group message @@ -645,7 +645,7 @@ int tox_join_groupchat(Tox *tox, int32_t friendnumber, const uint8_t *friend_gro int tox_group_message_send(Tox *tox, int groupnumber, const uint8_t *message, uint32_t length) { Messenger *m = tox; - return group_message_send(m, groupnumber, message, length); + //return group_message_send(m, groupnumber, message, length); } /* send a group action @@ -655,7 +655,7 @@ int tox_group_message_send(Tox *tox, int groupnumber, const uint8_t *message, ui int tox_group_action_send(Tox *tox, int groupnumber, const uint8_t *action, uint32_t length) { Messenger *m = tox; - return group_action_send(m, groupnumber, action, length); + //return group_action_send(m, groupnumber, action, length); } /* Return the number of peers in the group chat on success. @@ -664,7 +664,7 @@ int tox_group_action_send(Tox *tox, int groupnumber, const uint8_t *action, uint int tox_group_number_peers(const Tox *tox, int groupnumber) { const Messenger *m = tox; - return group_number_peers(m, groupnumber); + //return group_number_peers(m, groupnumber); } /* List all the peers in the group chat. @@ -681,7 +681,7 @@ int tox_group_get_names(const Tox *tox, int groupnumber, uint8_t names[][TOX_MAX uint16_t length) { const Messenger *m = tox; - return group_names(m, groupnumber, names, lengths, length); + //return group_names(m, groupnumber, names, lengths, length); } /* Return the number of chats in the instance m. @@ -690,7 +690,7 @@ int tox_group_get_names(const Tox *tox, int groupnumber, uint8_t names[][TOX_MAX uint32_t tox_count_chatlist(const Tox *tox) { const Messenger *m = tox; - return count_chatlist(m); + //return count_chatlist(m); } /* Copy a list of valid chat IDs into the array out_list. @@ -701,7 +701,7 @@ uint32_t tox_count_chatlist(const Tox *tox) uint32_t tox_get_chatlist(const Tox *tox, int *out_list, uint32_t list_size) { const Messenger *m = tox; - return copy_chatlist(m, out_list, list_size); + //return copy_chatlist(m, out_list, list_size); } -- cgit v1.2.3 From 6c71bb7e64c557d13e7eea4102f1e0bb41ec172f Mon Sep 17 00:00:00 2001 From: irungentoo Date: Sat, 27 Sep 2014 18:25:03 -0400 Subject: Moved all the connection stuff from messenger to friend_connection. Messenger was doing way do many things. friend_connection takes care of finding and establishing a connection to friends. --- toxcore/DHT.h | 2 +- toxcore/Makefile.inc | 2 + toxcore/Messenger.c | 245 +++---------------- toxcore/Messenger.h | 27 +-- toxcore/friend_connection.c | 565 ++++++++++++++++++++++++++++++++++++++++++++ toxcore/friend_connection.h | 140 +++++++++++ 6 files changed, 745 insertions(+), 236 deletions(-) create mode 100644 toxcore/friend_connection.c create mode 100644 toxcore/friend_connection.h (limited to 'toxcore/Makefile.inc') diff --git a/toxcore/DHT.h b/toxcore/DHT.h index 5339d3e6..e1e14cd9 100644 --- a/toxcore/DHT.h +++ b/toxcore/DHT.h @@ -122,7 +122,7 @@ typedef struct { uint64_t NATping_timestamp; } NAT; -#define DHT_FRIEND_MAX_LOCKS 2 +#define DHT_FRIEND_MAX_LOCKS 32 typedef struct { uint8_t client_id[CLIENT_ID_SIZE]; diff --git a/toxcore/Makefile.inc b/toxcore/Makefile.inc index 8af793c8..9fd1f94a 100644 --- a/toxcore/Makefile.inc +++ b/toxcore/Makefile.inc @@ -19,6 +19,8 @@ libtoxcore_la_SOURCES = ../toxcore/DHT.h \ ../toxcore/friend_requests.c \ ../toxcore/LAN_discovery.h \ ../toxcore/LAN_discovery.c \ + ../toxcore/friend_connection.h \ + ../toxcore/friend_connection.c \ ../toxcore/Messenger.h \ ../toxcore/Messenger.c \ ../toxcore/ping.h \ diff --git a/toxcore/Messenger.c b/toxcore/Messenger.c index 8faa7f03..04830260 100644 --- a/toxcore/Messenger.c +++ b/toxcore/Messenger.c @@ -153,73 +153,9 @@ void getaddress(const Messenger *m, uint8_t *address) memcpy(address + crypto_box_PUBLICKEYBYTES + sizeof(nospam), &checksum, sizeof(checksum)); } -/* callback for recv TCP relay nodes. */ -static int tcp_relay_node_callback(void *object, uint32_t number, IP_Port ip_port, const uint8_t *public_key) -{ - Messenger *m = object; - - if (friend_not_valid(m, number)) - return -1; - - if (m->friendlist[number].crypt_connection_id != -1) { - return add_tcp_relay_peer(m->net_crypto, m->friendlist[number].crypt_connection_id, ip_port, public_key); - } else { - return add_tcp_relay(m->net_crypto, ip_port, public_key); - } -} - -static int friend_new_connection(Messenger *m, int32_t friendnumber, const uint8_t *real_public_key); -/* Callback for DHT ip_port changes. */ -static void dht_ip_callback(void *data, int32_t number, IP_Port ip_port) -{ - Messenger *m = data; - - if (friend_not_valid(m, number)) - return; - - if (m->friendlist[number].crypt_connection_id == -1) { - friend_new_connection(m, number, m->friendlist[number].client_id); - } - - set_direct_ip_port(m->net_crypto, m->friendlist[number].crypt_connection_id, ip_port); - m->friendlist[number].dht_ip_port = ip_port; - m->friendlist[number].dht_ip_port_lastrecv = unix_time(); -} - -/* Callback for dht public key changes. */ -static void dht_pk_callback(void *data, int32_t number, const uint8_t *dht_public_key) -{ - Messenger *m = data; - - if (friend_not_valid(m, number)) - return; - - m->friendlist[number].dht_ping_lastrecv = unix_time(); - - if (memcmp(m->friendlist[number].dht_temp_pk, dht_public_key, crypto_box_PUBLICKEYBYTES) == 0) - return; - - if (m->friendlist[number].dht_lock) { - if (DHT_delfriend(m->dht, m->friendlist[number].dht_temp_pk, m->friendlist[number].dht_lock) != 0) { - printf("a. Could not delete dht peer. Please report this.\n"); - return; - } - - m->friendlist[number].dht_lock = 0; - } - - DHT_addfriend(m->dht, dht_public_key, dht_ip_callback, data, number, &m->friendlist[number].dht_lock); - - if (m->friendlist[number].crypt_connection_id == -1) { - friend_new_connection(m, number, m->friendlist[number].client_id); - } - - set_connection_dht_public_key(m->net_crypto, m->friendlist[number].crypt_connection_id, dht_public_key); - onion_set_friend_DHT_pubkey(m->onion_c, m->friendlist[number].onion_friendnum, dht_public_key); - - memcpy(m->friendlist[number].dht_temp_pk, dht_public_key, crypto_box_PUBLICKEYBYTES); -} - +static int handle_status(void *object, int i, uint8_t status); +static int handle_packet(void *object, int i, uint8_t *temp, uint16_t len); +static int handle_custom_lossy_packet(void *object, int friend_num, const uint8_t *packet, uint16_t length); /* * Add a friend. @@ -283,18 +219,17 @@ int32_t m_addfriend(Messenger *m, const uint8_t *address, const uint8_t *data, u memset(&(m->friendlist[m->numfriends]), 0, sizeof(Friend)); - int32_t onion_friendnum = onion_addfriend(m->onion_c, client_id); + int friendcon_id = new_friend_connection(m->fr_c, client_id); - if (onion_friendnum == -1) - return FAERR_UNKNOWN; + if (friendcon_id == -1) + return -1; uint32_t i; for (i = 0; i <= m->numfriends; ++i) { if (m->friendlist[i].status == NOFRIEND) { - m->friendlist[i].onion_friendnum = onion_friendnum; m->friendlist[i].status = FRIEND_ADDED; - m->friendlist[i].crypt_connection_id = -1; + m->friendlist[i].friendcon_id = friendcon_id; m->friendlist[i].friendrequest_lastsent = 0; m->friendlist[i].friendrequest_timeout = FRIENDREQUEST_TIMEOUT; id_copy(m->friendlist[i].client_id, client_id); @@ -311,8 +246,9 @@ int32_t m_addfriend(Messenger *m, const uint8_t *address, const uint8_t *data, u m->friendlist[i].message_id = 0; m->friendlist[i].receives_read_receipts = 1; /* Default: YES. */ memcpy(&(m->friendlist[i].friendrequest_nospam), address + crypto_box_PUBLICKEYBYTES, sizeof(uint32_t)); - recv_tcp_relay_handler(m->onion_c, onion_friendnum, &tcp_relay_node_callback, m, i); - onion_dht_pk_callback(m->onion_c, onion_friendnum, &dht_pk_callback, m, i); + friend_connection_callbacks(m->fr_c, friendcon_id, MESSENGER_CALLBACK_INDEX, &handle_status, &handle_packet, + &handle_custom_lossy_packet, m, i); + if (m->numfriends == i) ++m->numfriends; @@ -341,18 +277,17 @@ int32_t m_addfriend_norequest(Messenger *m, const uint8_t *client_id) memset(&(m->friendlist[m->numfriends]), 0, sizeof(Friend)); - int32_t onion_friendnum = onion_addfriend(m->onion_c, client_id); + int friendcon_id = new_friend_connection(m->fr_c, client_id); - if (onion_friendnum == -1) + if (friendcon_id == -1) return -1; uint32_t i; for (i = 0; i <= m->numfriends; ++i) { if (m->friendlist[i].status == NOFRIEND) { - m->friendlist[i].onion_friendnum = onion_friendnum; m->friendlist[i].status = FRIEND_CONFIRMED; - m->friendlist[i].crypt_connection_id = -1; + m->friendlist[i].friendcon_id = friendcon_id; m->friendlist[i].friendrequest_lastsent = 0; id_copy(m->friendlist[i].client_id, client_id); m->friendlist[i].statusmessage = calloc(1, 1); @@ -365,8 +300,8 @@ int32_t m_addfriend_norequest(Messenger *m, const uint8_t *client_id) m->friendlist[i].is_typing = 0; m->friendlist[i].message_id = 0; m->friendlist[i].receives_read_receipts = 1; /* Default: YES. */ - recv_tcp_relay_handler(m->onion_c, onion_friendnum, &tcp_relay_node_callback, m, i); - onion_dht_pk_callback(m->onion_c, onion_friendnum, &dht_pk_callback, m, i); + friend_connection_callbacks(m->fr_c, friendcon_id, MESSENGER_CALLBACK_INDEX, &handle_status, &handle_packet, + &handle_custom_lossy_packet, m, i); if (m->numfriends == i) ++m->numfriends; @@ -391,16 +326,11 @@ int m_delfriend(Messenger *m, int32_t friendnumber) if (m->friendlist[friendnumber].status == FRIEND_ONLINE) remove_online_friend(m, friendnumber); - onion_delfriend(m->onion_c, m->friendlist[friendnumber].onion_friendnum); - - if (m->friendlist[friendnumber].dht_lock) { - DHT_delfriend(m->dht, m->friendlist[friendnumber].dht_temp_pk, m->friendlist[friendnumber].dht_lock); - } - - crypto_kill(m->net_crypto, m->friendlist[friendnumber].crypt_connection_id); free(m->friendlist[friendnumber].statusmessage); free(m->friendlist[friendnumber].avatar_recv_data); remove_request_received(&(m->fr), m->friendlist[friendnumber].client_id); + friend_connection_callbacks(m->fr_c, m->friendlist[friendnumber].friendcon_id, MESSENGER_CALLBACK_INDEX, 0, 0, 0, 0, 0); + kill_friend_connection(m->fr_c, m->friendlist[friendnumber].friendcon_id); memset(&(m->friendlist[friendnumber]), 0, sizeof(Friend)); uint32_t i; @@ -867,16 +797,6 @@ static int send_user_istyping(const Messenger *m, int32_t friendnumber, uint8_t return write_cryptpacket_id(m, friendnumber, PACKET_ID_TYPING, &typing, sizeof(typing), 0); } -static int send_ping(const Messenger *m, int32_t friendnumber) -{ - int ret = write_cryptpacket_id(m, friendnumber, PACKET_ID_ALIVE, 0, 0, 0); - - if (ret == 1) - m->friendlist[friendnumber].ping_lastsent = unix_time(); - - return ret; -} - static int send_relays(const Messenger *m, int32_t friendnumber) { Node_format nodes[MAX_SHARED_RELAYS]; @@ -1023,8 +943,6 @@ static void check_friend_connectionstatus(Messenger *m, int32_t friendnumber, ui const uint8_t was_online = m->friendlist[friendnumber].status == FRIEND_ONLINE; const uint8_t is_online = status == FRIEND_ONLINE; - onion_set_friend_online(m->onion_c, m->friendlist[friendnumber].onion_friendnum, is_online); - if (is_online != was_online) { if (was_online) { break_files(m, friendnumber); @@ -1065,8 +983,8 @@ static int write_cryptpacket_id(const Messenger *m, int32_t friendnumber, uint8_ if (length != 0) memcpy(packet + 1, data, length); - return write_cryptpacket(m->net_crypto, m->friendlist[friendnumber].crypt_connection_id, packet, length + 1, - congestion_control) != -1; + return write_cryptpacket(m->net_crypto, friend_connection_crypt_connection_id(m->fr_c, + m->friendlist[friendnumber].friendcon_id), packet, length + 1, congestion_control) != -1; } /**********GROUP CHATS************/ @@ -1311,8 +1229,8 @@ int file_data(const Messenger *m, int32_t friendnumber, uint8_t filenumber, cons if (m->friendlist[friendnumber].file_sending[filenumber].status != FILESTATUS_TRANSFERRING) return -1; - /* Prevent file sending from filling up the entire buffer preventing messages from being sent. */ - if (crypto_num_free_sendqueue_slots(m->net_crypto, m->friendlist[friendnumber].crypt_connection_id) < MIN_SLOTS_FREE) + /* Prevent file sending from filling up the entire buffer preventing messages from being sent. TODO: remove */ + if (crypto_num_free_sendqueue_slots(m->net_crypto, friend_connection_crypt_connection_id(m->fr_c, m->friendlist[friendnumber].friendcon_id)) < MIN_SLOTS_FREE) return -1; uint8_t packet[MAX_CRYPTO_DATA_SIZE]; @@ -1518,10 +1436,8 @@ int send_custom_lossy_packet(const Messenger *m, int32_t friendnumber, const uin if (m->friendlist[friendnumber].status != FRIEND_ONLINE) return -1; - if (m->friendlist[friendnumber].crypt_connection_id == -1) - return -1; - - return send_lossy_cryptpacket(m->net_crypto, m->friendlist[friendnumber].crypt_connection_id, data, length); + return send_lossy_cryptpacket(m->net_crypto, friend_connection_crypt_connection_id(m->fr_c, + m->friendlist[friendnumber].friendcon_id), data, length); } static int handle_custom_lossless_packet(void *object, int friend_num, const uint8_t *packet, uint16_t length) @@ -1579,10 +1495,8 @@ int send_custom_lossless_packet(const Messenger *m, int32_t friendnumber, const if (m->friendlist[friendnumber].status != FRIEND_ONLINE) return -1; - if (m->friendlist[friendnumber].crypt_connection_id == -1) - return -1; - - if (write_cryptpacket(m->net_crypto, m->friendlist[friendnumber].crypt_connection_id, data, length, 1) == -1) { + if (write_cryptpacket(m->net_crypto, friend_connection_crypt_connection_id(m->fr_c, + m->friendlist[friendnumber].friendcon_id), data, length, 1) == -1) { return -1; } else { return 0; @@ -1609,42 +1523,6 @@ static void LANdiscovery(Messenger *m) } } -static int handle_status(void *object, int i, uint8_t status); -static int handle_packet(void *object, int i, uint8_t *temp, uint16_t len); - -static int handle_new_connections(void *object, New_Connection *n_c) -{ - Messenger *m = object; - int friend_id = getfriend_id(m, n_c->public_key); - - if (friend_id != -1) { - if (m->friendlist[friend_id].crypt_connection_id != -1) - return -1; - - int id = accept_crypto_connection(m->net_crypto, n_c); - connection_status_handler(m->net_crypto, id, &handle_status, m, friend_id); - connection_data_handler(m->net_crypto, id, &handle_packet, m, friend_id); - connection_lossy_data_handler(m->net_crypto, id, &handle_custom_lossy_packet, m, friend_id); - m->friendlist[friend_id].crypt_connection_id = id; - set_friend_status(m, friend_id, FRIEND_CONFIRMED); - - if (n_c->source.ip.family != AF_INET && n_c->source.ip.family != AF_INET6) { - set_direct_ip_port(m->net_crypto, m->friendlist[friend_id].crypt_connection_id, m->friendlist[friend_id].dht_ip_port); - } else { - m->friendlist[friend_id].dht_ip_port = n_c->source; - m->friendlist[friend_id].dht_ip_port_lastrecv = unix_time(); - } - - dht_pk_callback(m, friend_id, n_c->dht_public_key); - - nc_dht_pk_callback(m->net_crypto, id, &dht_pk_callback, m, friend_id); - return 0; - } - - return -1; -} - - /* Run this at startup. */ Messenger *new_messenger(Messenger_Options *options) { @@ -1691,13 +1569,13 @@ Messenger *new_messenger(Messenger_Options *options) return NULL; } - new_connection_handler(m->net_crypto, &handle_new_connections, m); - m->onion = new_onion(m->dht); m->onion_a = new_onion_announce(m->dht); m->onion_c = new_onion_client(m->net_crypto); + m->fr_c = new_friend_connections(m->onion_c); if (!(m->onion && m->onion_a && m->onion_c)) { + kill_friend_connections(m->fr_c); kill_onion(m->onion); kill_onion_announce(m->onion_a); kill_onion_client(m->onion_c); @@ -1722,6 +1600,7 @@ void kill_messenger(Messenger *m) { uint32_t i; + kill_friend_connections(m->fr_c); kill_onion(m->onion); kill_onion_announce(m->onion_a); kill_onion_client(m->onion_c); @@ -1769,10 +1648,6 @@ static int handle_status(void *object, int i, uint8_t status) m->friendlist[i].statusmessage_sent = 0; m->friendlist[i].ping_lastrecv = temp_time; } else { /* Went offline. */ - m->friendlist[i].crypt_connection_id = -1; - - m->friendlist[i].dht_ping_lastrecv = temp_time; - if (m->friendlist[i].status == FRIEND_ONLINE) { set_friend_status(m, i, FRIEND_CONFIRMED); } @@ -2072,11 +1947,6 @@ static int handle_packet(void *object, int i, uint8_t *temp, uint16_t len) return -1; switch (packet_id) { - case PACKET_ID_ALIVE: { - m->friendlist[i].ping_lastrecv = temp_time; - break; - } - case PACKET_ID_NICKNAME: { if (data_length > MAX_NAME_LENGTH || data_length == 0) break; @@ -2359,29 +2229,6 @@ static int handle_packet(void *object, int i, uint8_t *temp, uint16_t len) return 0; } -static int friend_new_connection(Messenger *m, int32_t friendnumber, const uint8_t *real_public_key) -{ - if (friend_not_valid(m, friendnumber)) - return -1; - - if (m->friendlist[friendnumber].crypt_connection_id != -1) { - return -1; - } - - int id = new_crypto_connection(m->net_crypto, real_public_key); - - if (id == -1) - return -1; - - m->friendlist[friendnumber].crypt_connection_id = id; - connection_status_handler(m->net_crypto, id, &handle_status, m, friendnumber); - connection_data_handler(m->net_crypto, id, &handle_packet, m, friendnumber); - connection_lossy_data_handler(m->net_crypto, id, &handle_custom_lossy_packet, m, friendnumber); - nc_dht_pk_callback(m->net_crypto, id, &dht_pk_callback, m, friendnumber); - - return 0; -} - /* TODO: Make this function not suck. */ void do_friends(Messenger *m) { @@ -2407,27 +2254,7 @@ void do_friends(Messenger *m) * unsuccessful so we set the status back to FRIEND_ADDED and try again. */ check_friend_request_timed_out(m, i, temp_time); - - } else { - if (m->friendlist[i].dht_ping_lastrecv + FRIEND_DHT_TIMEOUT < temp_time) { - if (m->friendlist[i].dht_lock) { - DHT_delfriend(m->dht, m->friendlist[i].dht_temp_pk, m->friendlist[i].dht_lock); - m->friendlist[i].dht_lock = 0; - } - } - - if (m->friendlist[i].dht_ip_port_lastrecv + FRIEND_DHT_TIMEOUT < temp_time) { - m->friendlist[i].dht_ip_port.ip.family = 0; - } } - - if (friend_new_connection(m, i, m->friendlist[i].client_id) == 0) { - if (m->friendlist[i].dht_lock) - set_connection_dht_public_key(m->net_crypto, m->friendlist[i].crypt_connection_id, m->friendlist[i].dht_temp_pk); - - set_direct_ip_port(m->net_crypto, m->friendlist[i].crypt_connection_id, m->friendlist[i].dht_ip_port); - } - } if (m->friendlist[i].status == FRIEND_ONLINE) { /* friend is online. */ @@ -2456,17 +2283,6 @@ void do_friends(Messenger *m) m->friendlist[i].user_istyping_sent = 1; } - if (m->friendlist[i].ping_lastsent + FRIEND_PING_INTERVAL < temp_time) { - send_ping(m, i); - } - - if (m->friendlist[i].ping_lastrecv + FRIEND_CONNECTION_TIMEOUT < temp_time) { - /* If we stopped receiving ping packets, kill it. */ - crypto_kill(m->net_crypto, m->friendlist[i].crypt_connection_id); - m->friendlist[i].crypt_connection_id = -1; - set_friend_status(m, i, FRIEND_CONFIRMED); - } - if (m->friendlist[i].share_relays_lastsent + FRIEND_SHARE_RELAYS_INTERVAL < temp_time) { send_relays(m, i); } @@ -2536,6 +2352,7 @@ void do_messenger(Messenger *m) do_net_crypto(m->net_crypto); do_onion_client(m->onion_c); + do_friend_connections(m->fr_c); do_friends(m); LANdiscovery(m); @@ -2616,8 +2433,8 @@ void do_messenger(Messenger *m) if (ping_lastrecv > 999) ping_lastrecv = 999; - LOGGER_INFO("F[%2u:%2u] <%s> %02i [%03u] %s", - dht2m[friend], friend, msgfptr->name, msgfptr->crypt_connection_id, + LOGGER_INFO("F[%2u:%2u] <%s> [%03u] %s", + dht2m[friend], friend, msgfptr->name, ping_lastrecv, ID2String(msgfptr->client_id)); } else { LOGGER_INFO("F[--:%2u] %s", friend, ID2String(dhtfptr->client_id)); diff --git a/toxcore/Messenger.h b/toxcore/Messenger.h index 60d00225..454c31cb 100644 --- a/toxcore/Messenger.h +++ b/toxcore/Messenger.h @@ -26,11 +26,9 @@ #ifndef MESSENGER_H #define MESSENGER_H -#include "net_crypto.h" -#include "DHT.h" #include "friend_requests.h" #include "LAN_discovery.h" -#include "onion_client.h" +#include "friend_connection.h" #define MAX_NAME_LENGTH 128 /* TODO: this must depend on other variable. */ @@ -41,8 +39,7 @@ #define FRIEND_ADDRESS_SIZE (crypto_box_PUBLICKEYBYTES + sizeof(uint32_t) + sizeof(uint16_t)) -/* NOTE: Packet ids below 16 must never be used. */ -#define PACKET_ID_ALIVE 16 +/* NOTE: Packet ids below 17 must never be used. */ #define PACKET_ID_SHARE_RELAYS 17 #define PACKET_ID_NICKNAME 48 #define PACKET_ID_STATUSMESSAGE 49 @@ -104,15 +101,9 @@ enum { /* Default start timeout in seconds between friend requests. */ #define FRIENDREQUEST_TIMEOUT 5; -/* Interval between the sending of ping packets. */ -#define FRIEND_PING_INTERVAL 6 - /* Interval between the sending of tcp relay information */ #define FRIEND_SHARE_RELAYS_INTERVAL (5 * 60) -/* If no packets are received from friend in this time interval, kill the connection. */ -#define FRIEND_CONNECTION_TIMEOUT (FRIEND_PING_INTERVAL * 3) - /* Must be < MAX_CRYPTO_DATA_SIZE */ #define AVATAR_DATA_MAX_CHUNK_SIZE (MAX_CRYPTO_DATA_SIZE-1) @@ -120,7 +111,6 @@ enum { #define AVATAR_DATA_TRANSFER_LIMIT (10*AVATAR_MAX_DATA_LENGTH) #define AVATAR_DATA_TRANSFER_TIMEOUT (60) /* 164kB every 60 seconds is not a lot */ -#define FRIEND_DHT_TIMEOUT BAD_NODE_TIMEOUT /* Time before friend is removed from the DHT after last hearing about him. */ /* USERSTATUS - * Represents userstatuses someone can have. @@ -197,14 +187,8 @@ enum { typedef struct { uint8_t client_id[crypto_box_PUBLICKEYBYTES]; + int friendcon_id; - uint8_t dht_temp_pk[crypto_box_PUBLICKEYBYTES]; - uint16_t dht_lock; - IP_Port dht_ip_port; - uint64_t dht_ping_lastrecv, dht_ip_port_lastrecv; - - uint32_t onion_friendnum; - int crypt_connection_id; uint64_t friendrequest_lastsent; // Time at which the last friend request was sent. uint32_t friendrequest_timeout; // The timeout between successful friendrequest sending attempts. uint8_t status; // 0 if no friend, 1 if added, 2 if friend request sent, 3 if confirmed friend, 4 if online. @@ -225,8 +209,7 @@ typedef struct { uint32_t message_id; // a semi-unique id used in read receipts. uint8_t receives_read_receipts; // shall we send read receipts to this person? uint32_t friendrequest_nospam; // The nospam number used in the friend request. - uint64_t ping_lastrecv; - uint64_t ping_lastsent; + uint64_t ping_lastrecv;//TODO remove uint64_t share_relays_lastsent; struct File_Transfers file_sending[MAX_CONCURRENT_FILE_PIPES]; struct File_Transfers file_receiving[MAX_CONCURRENT_FILE_PIPES]; @@ -256,6 +239,8 @@ typedef struct Messenger { Onion_Announce *onion_a; Onion_Client *onion_c; + Friend_Connections *fr_c; + Friend_Requests fr; uint8_t name[MAX_NAME_LENGTH]; uint16_t name_length; diff --git a/toxcore/friend_connection.c b/toxcore/friend_connection.c new file mode 100644 index 00000000..09dea4c3 --- /dev/null +++ b/toxcore/friend_connection.c @@ -0,0 +1,565 @@ +/* friend_connection.c + * + * Connection to friends. + * + * Copyright (C) 2014 Tox project All Rights Reserved. + * + * This file is part of Tox. + * + * Tox is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Tox is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Tox. If not, see . + * + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "friend_connection.h" +#include "util.h" + +/* return 1 if the friendcon_id is not valid. + * return 0 if the friendcon_id is valid. + */ +static uint8_t friendconn_id_not_valid(const Friend_Connections *fr_c, int friendcon_id) +{ + if ((unsigned int)friendcon_id >= fr_c->num_cons) + return 1; + + if (fr_c->conns == NULL) + return 1; + + if (fr_c->conns[friendcon_id].status == FRIENDCONN_STATUS_NONE) + return 1; + + return 0; +} + + +/* Set the size of the friend connections list to num. + * + * return -1 if realloc fails. + * return 0 if it succeeds. + */ +static int realloc_friendconns(Friend_Connections *fr_c, uint32_t num) +{ + if (num == 0) { + free(fr_c->conns); + fr_c->conns = NULL; + return 0; + } + + Friend_Conn *newgroup_cons = realloc(fr_c->conns, num * sizeof(Friend_Conn)); + + if (newgroup_cons == NULL) + return -1; + + fr_c->conns = newgroup_cons; + return 0; +} + +/* Create a new empty friend connection. + * + * return -1 on failure. + * return friendcon_id on success. + */ +static int create_friend_conn(Friend_Connections *fr_c) +{ + uint32_t i; + + for (i = 0; i < fr_c->num_cons; ++i) { + if (fr_c->conns[i].status == FRIENDCONN_STATUS_NONE) + return i; + } + + int id = -1; + + if (realloc_friendconns(fr_c, fr_c->num_cons + 1) == 0) { + id = fr_c->num_cons; + ++fr_c->num_cons; + memset(&(fr_c->conns[id]), 0, sizeof(Friend_Conn)); + } + + return id; +} + +/* Wipe a friend connection. + * + * return -1 on failure. + * return 0 on success. + */ +static int wipe_friend_conn(Friend_Connections *fr_c, int friendcon_id) +{ + if (friendconn_id_not_valid(fr_c, friendcon_id)) + return -1; + + uint32_t i; + memset(&(fr_c->conns[friendcon_id]), 0 , sizeof(Friend_Conn)); + + for (i = fr_c->num_cons; i != 0; --i) { + if (fr_c->conns[i - 1].status != FRIENDCONN_STATUS_NONE) + break; + } + + if (fr_c->num_cons != i) { + fr_c->num_cons = i; + realloc_friendconns(fr_c, fr_c->num_cons); + } + + return 0; +} + +static Friend_Conn *get_conn(const Friend_Connections *fr_c, int friendcon_id) +{ + if (friendconn_id_not_valid(fr_c, friendcon_id)) + return 0; + + return &fr_c->conns[friendcon_id]; +} + +/* return friendcon_id corresponding to the real public key on success. + * return -1 on failure. + */ +int getfriend_conn_id_pk(Friend_Connections *fr_c, const uint8_t *real_pk) +{ + uint32_t i; + + for (i = 0; i < fr_c->num_cons; ++i) { + Friend_Conn *friend_con = get_conn(fr_c, i); + + if (friend_con) { + if (memcmp(friend_con->real_public_key, real_pk, crypto_box_PUBLICKEYBYTES) == 0) + return i; + } + } + + return -1; +} + +/* callback for recv TCP relay nodes. */ +static int tcp_relay_node_callback(void *object, uint32_t number, IP_Port ip_port, const uint8_t *public_key) +{ + Friend_Connections *fr_c = object; + Friend_Conn *friend_con = get_conn(fr_c, number); + + if (!friend_con) + return -1; + + if (friend_con->crypt_connection_id != -1) { + return add_tcp_relay_peer(fr_c->net_crypto, friend_con->crypt_connection_id, ip_port, public_key); + } else { + return add_tcp_relay(fr_c->net_crypto, ip_port, public_key); + } +} + +static int friend_new_connection(Friend_Connections *fr_c, int friendcon_id); +/* Callback for DHT ip_port changes. */ +static void dht_ip_callback(void *object, int32_t number, IP_Port ip_port) +{ + Friend_Connections *fr_c = object; + Friend_Conn *friend_con = get_conn(fr_c, number); + + if (!friend_con) + return; + + if (friend_con->crypt_connection_id == -1) { + friend_new_connection(fr_c, number); + } + + set_direct_ip_port(fr_c->net_crypto, friend_con->crypt_connection_id, ip_port); + friend_con->dht_ip_port = ip_port; + friend_con->dht_ip_port_lastrecv = unix_time(); +} + +/* Callback for dht public key changes. */ +static void dht_pk_callback(void *object, int32_t number, const uint8_t *dht_public_key) +{ + Friend_Connections *fr_c = object; + Friend_Conn *friend_con = get_conn(fr_c, number); + + if (!friend_con) + return; + + friend_con->dht_ping_lastrecv = unix_time(); + + if (memcmp(friend_con->dht_temp_pk, dht_public_key, crypto_box_PUBLICKEYBYTES) == 0) + return; + + if (friend_con->dht_lock) { + if (DHT_delfriend(fr_c->dht, friend_con->dht_temp_pk, friend_con->dht_lock) != 0) { + printf("a. Could not delete dht peer. Please report this.\n"); + return; + } + + friend_con->dht_lock = 0; + } + + DHT_addfriend(fr_c->dht, dht_public_key, dht_ip_callback, object, number, &friend_con->dht_lock); + + if (friend_con->crypt_connection_id == -1) { + friend_new_connection(fr_c, number); + } + + set_connection_dht_public_key(fr_c->net_crypto, friend_con->crypt_connection_id, dht_public_key); + onion_set_friend_DHT_pubkey(fr_c->onion_c, friend_con->onion_friendnum, dht_public_key); + + memcpy(friend_con->dht_temp_pk, dht_public_key, crypto_box_PUBLICKEYBYTES); +} + +static int handle_status(void *object, int number, uint8_t status) +{ + Friend_Connections *fr_c = object; + Friend_Conn *friend_con = get_conn(fr_c, number); + + if (!friend_con) + return -1; + + if (status) { /* Went online. */ + friend_con->status = FRIENDCONN_STATUS_CONNECTED; + friend_con->ping_lastrecv = unix_time(); + onion_set_friend_online(fr_c->onion_c, friend_con->onion_friendnum, status); + } else { /* Went offline. */ + friend_con->status = FRIENDCONN_STATUS_CONNECTING; + friend_con->crypt_connection_id = -1; + friend_con->dht_ping_lastrecv = unix_time(); + } + + unsigned int i; + + for (i = 0; i < MAX_FRIEND_CONNECTION_CALLBACKS; ++i) { + if (friend_con->callbacks[i].status_callback) + friend_con->callbacks[i].status_callback(friend_con->callbacks[i].status_callback_object, + friend_con->callbacks[i].status_callback_id, status); + } + + return 0; +} + +static int handle_packet(void *object, int number, uint8_t *data, uint16_t length) +{ + if (length == 0) + return -1; + + Friend_Connections *fr_c = object; + Friend_Conn *friend_con = get_conn(fr_c, number); + + if (!friend_con) + return -1; + + if (data[0] == PACKET_ID_ALIVE) { + friend_con->ping_lastrecv = unix_time(); + return 0; + } + + unsigned int i; + + for (i = 0; i < MAX_FRIEND_CONNECTION_CALLBACKS; ++i) { + if (friend_con->callbacks[i].data_callback) + friend_con->callbacks[i].data_callback(friend_con->callbacks[i].data_callback_object, + friend_con->callbacks[i].data_callback_id, data, length); + } + + return 0; +} + +static int handle_lossy_packet(void *object, int number, const uint8_t *data, uint16_t length) +{ + if (length == 0) + return -1; + + Friend_Connections *fr_c = object; + Friend_Conn *friend_con = get_conn(fr_c, number); + + if (!friend_con) + return -1; + + unsigned int i; + + for (i = 0; i < MAX_FRIEND_CONNECTION_CALLBACKS; ++i) { + if (friend_con->callbacks[i].lossy_data_callback) + friend_con->callbacks[i].lossy_data_callback(friend_con->callbacks[i].lossy_data_callback_object, + friend_con->callbacks[i].lossy_data_callback_id, data, length); + } + + return 0; +} + +static int handle_new_connections(void *object, New_Connection *n_c) +{ + Friend_Connections *fr_c = object; + int friendcon_id = getfriend_conn_id_pk(fr_c, n_c->public_key); + Friend_Conn *friend_con = get_conn(fr_c, friendcon_id); + + if (friend_con) { + + if (friend_con->crypt_connection_id != -1) + return -1; + + int id = accept_crypto_connection(fr_c->net_crypto, n_c); + connection_status_handler(fr_c->net_crypto, id, &handle_status, fr_c, friendcon_id); + connection_data_handler(fr_c->net_crypto, id, &handle_packet, fr_c, friendcon_id); + connection_lossy_data_handler(fr_c->net_crypto, id, &handle_lossy_packet, fr_c, friendcon_id); + friend_con->crypt_connection_id = id; + + if (n_c->source.ip.family != AF_INET && n_c->source.ip.family != AF_INET6) { + set_direct_ip_port(fr_c->net_crypto, friend_con->crypt_connection_id, friend_con->dht_ip_port); + } else { + friend_con->dht_ip_port = n_c->source; + friend_con->dht_ip_port_lastrecv = unix_time(); + } + + dht_pk_callback(fr_c, friendcon_id, n_c->dht_public_key); + + nc_dht_pk_callback(fr_c->net_crypto, id, &dht_pk_callback, fr_c, friendcon_id); + return 0; + } + + return -1; +} + +static int friend_new_connection(Friend_Connections *fr_c, int friendcon_id) +{ + Friend_Conn *friend_con = get_conn(fr_c, friendcon_id); + + if (!friend_con) + return -1; + + if (friend_con->crypt_connection_id != -1) { + return -1; + } + + int id = new_crypto_connection(fr_c->net_crypto, friend_con->real_public_key); + + if (id == -1) + return -1; + + friend_con->crypt_connection_id = id; + connection_status_handler(fr_c->net_crypto, id, &handle_status, fr_c, friendcon_id); + connection_data_handler(fr_c->net_crypto, id, &handle_packet, fr_c, friendcon_id); + connection_lossy_data_handler(fr_c->net_crypto, id, &handle_lossy_packet, fr_c, friendcon_id); + nc_dht_pk_callback(fr_c->net_crypto, id, &dht_pk_callback, fr_c, friendcon_id); + + return 0; +} + +static int send_ping(const Friend_Connections *fr_c, int friendcon_id) +{ + Friend_Conn *friend_con = get_conn(fr_c, friendcon_id); + + if (!friend_con) + return -1; + + uint8_t ping = PACKET_ID_ALIVE; + int64_t ret = write_cryptpacket(fr_c->net_crypto, friend_con->crypt_connection_id, &ping, sizeof(ping), 0); + + if (ret != -1) { + friend_con->ping_lastsent = unix_time(); + return 0; + } + + return -1; +} + +/* Set the callbacks for the friend connection. + * index is the index (0 to (MAX_FRIEND_CONNECTION_CALLBACKS - 1)) we want the callback to set in the array. + * + * return 0 on success. + * return -1 on failure + */ +int friend_connection_callbacks(Friend_Connections *fr_c, int friendcon_id, unsigned int index, + int (*status_callback)(void *object, int id, uint8_t status), int (*data_callback)(void *object, int id, uint8_t *data, + uint16_t length), int (*lossy_data_callback)(void *object, int id, const uint8_t *data, uint16_t length), void *object, + int number) +{ + Friend_Conn *friend_con = get_conn(fr_c, friendcon_id); + + if (!friend_con) + return -1; + + if (index >= MAX_FRIEND_CONNECTION_CALLBACKS) + return -1; + + friend_con->callbacks[index].status_callback = status_callback; + friend_con->callbacks[index].data_callback = data_callback; + friend_con->callbacks[index].lossy_data_callback = lossy_data_callback; + + friend_con->callbacks[index].status_callback_object = + friend_con->callbacks[index].data_callback_object = + friend_con->callbacks[index].lossy_data_callback_object = object; + + friend_con->callbacks[index].status_callback_id = + friend_con->callbacks[index].data_callback_id = + friend_con->callbacks[index].lossy_data_callback_id = number; + return 0; +} + +/* return the crypt_connection_id for the connection. + * + * return crypt_connection_id on success. + * return -1 on failure. + */ +int friend_connection_crypt_connection_id(Friend_Connections *fr_c, int friendcon_id) +{ + Friend_Conn *friend_con = get_conn(fr_c, friendcon_id); + + if (!friend_con) + return -1; + + return friend_con->crypt_connection_id; +} + +/* Create a new friend connection. + * If one to that real public key already exists, increase lock count and return it. + * + * return -1 on failure. + * return connection id on success. + */ +int new_friend_connection(Friend_Connections *fr_c, const uint8_t *real_public_key) +{ + int friendcon_id = getfriend_conn_id_pk(fr_c, real_public_key); + + if (friendcon_id != -1) { + ++fr_c->conns[friendcon_id].lock_count; + return friendcon_id; + } + + friendcon_id = create_friend_conn(fr_c); + + if (friendcon_id == -1) + return -1; + + int32_t onion_friendnum = onion_addfriend(fr_c->onion_c, real_public_key); + + if (onion_friendnum == -1) + return -1; + + Friend_Conn *friend_con = &fr_c->conns[friendcon_id]; + + friend_con->crypt_connection_id = -1; + friend_con->status = FRIENDCONN_STATUS_CONNECTING; + memcpy(friend_con->real_public_key, real_public_key, crypto_box_PUBLICKEYBYTES); + friend_con->onion_friendnum = onion_friendnum; + + recv_tcp_relay_handler(fr_c->onion_c, onion_friendnum, &tcp_relay_node_callback, fr_c, friendcon_id); + onion_dht_pk_callback(fr_c->onion_c, onion_friendnum, &dht_pk_callback, fr_c, friendcon_id); + + return friendcon_id; +} + +/* Kill a friend connection. + * + * return -1 on failure. + * return 0 on success. + */ +int kill_friend_connection(Friend_Connections *fr_c, int friendcon_id) +{ + Friend_Conn *friend_con = get_conn(fr_c, friendcon_id); + + if (!friend_con) + return -1; + + if (friend_con->lock_count) { + --friend_con->lock_count; + return 0; + } + + onion_delfriend(fr_c->onion_c, friend_con->onion_friendnum); + crypto_kill(fr_c->net_crypto, friend_con->crypt_connection_id); + + if (friend_con->dht_lock) { + DHT_delfriend(fr_c->dht, friend_con->dht_temp_pk, friend_con->dht_lock); + } + + return wipe_friend_conn(fr_c, friendcon_id); +} + + +/* Create new friend_connections instance. */ +Friend_Connections *new_friend_connections(Onion_Client *onion_c) +{ + if (!onion_c) + return NULL; + + Friend_Connections *temp = calloc(1, sizeof(Friend_Connections)); + + if (temp == NULL) + return NULL; + + temp->dht = onion_c->dht; + temp->net_crypto = onion_c->c; + temp->onion_c = onion_c; + + new_connection_handler(temp->net_crypto, &handle_new_connections, temp); + + return temp; +} + +/* main friend_connections loop. */ +void do_friend_connections(Friend_Connections *fr_c) +{ + uint32_t i; + uint64_t temp_time = unix_time(); + + for (i = 0; i < fr_c->num_cons; ++i) { + Friend_Conn *friend_con = get_conn(fr_c, i); + + if (friend_con) { + if (friend_con->status == FRIENDCONN_STATUS_CONNECTING) { + if (friend_con->dht_ping_lastrecv + FRIEND_DHT_TIMEOUT < temp_time) { + if (friend_con->dht_lock) { + DHT_delfriend(fr_c->dht, friend_con->dht_temp_pk, friend_con->dht_lock); + friend_con->dht_lock = 0; + } + } + + if (friend_con->dht_ip_port_lastrecv + FRIEND_DHT_TIMEOUT < temp_time) { + friend_con->dht_ip_port.ip.family = 0; + } + + if (friend_con->dht_lock) { + if (friend_new_connection(fr_c, i) == 0) { + set_connection_dht_public_key(fr_c->net_crypto, friend_con->crypt_connection_id, friend_con->dht_temp_pk); + set_direct_ip_port(fr_c->net_crypto, friend_con->crypt_connection_id, friend_con->dht_ip_port); + } + } + + } else if (friend_con->status == FRIENDCONN_STATUS_CONNECTED) { + if (friend_con->ping_lastsent + FRIEND_PING_INTERVAL < temp_time) { + send_ping(fr_c, i); + } + + if (friend_con->ping_lastrecv + FRIEND_CONNECTION_TIMEOUT < temp_time) { + /* If we stopped receiving ping packets, kill it. */ + crypto_kill(fr_c->net_crypto, friend_con->crypt_connection_id); + friend_con->crypt_connection_id = -1; + handle_status(fr_c, i, 0); /* Going offline. */ + } + } + } + } +} + +/* Free everything related with friend_connections. */ +void kill_friend_connections(Friend_Connections *fr_c) +{ + if (!fr_c) + return; + + uint32_t i; + + for (i = 0; i < fr_c->num_cons; ++i) { + kill_friend_connection(fr_c, i); + } + + free(fr_c); +} diff --git a/toxcore/friend_connection.h b/toxcore/friend_connection.h new file mode 100644 index 00000000..62b82dc2 --- /dev/null +++ b/toxcore/friend_connection.h @@ -0,0 +1,140 @@ +/* friend_connection.h + * + * Connection to friends. + * + * Copyright (C) 2014 Tox project All Rights Reserved. + * + * This file is part of Tox. + * + * Tox is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Tox is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Tox. If not, see . + * + */ + + +#ifndef FRIEND_CONNECTION_H +#define FRIEND_CONNECTION_H + +#include "net_crypto.h" +#include "DHT.h" +#include "LAN_discovery.h" +#include "onion_client.h" + + +#define MAX_FRIEND_CONNECTION_CALLBACKS 2 +#define MESSENGER_CALLBACK_INDEX 0 +#define GROUPCHAT_CALLBACK_INDEX 1 + +#define PACKET_ID_ALIVE 16 + +/* Interval between the sending of ping packets. */ +#define FRIEND_PING_INTERVAL 6 + +/* If no packets are received from friend in this time interval, kill the connection. */ +#define FRIEND_CONNECTION_TIMEOUT (FRIEND_PING_INTERVAL * 3) + +/* Time before friend is removed from the DHT after last hearing about him. */ +#define FRIEND_DHT_TIMEOUT BAD_NODE_TIMEOUT + + +enum { + FRIENDCONN_STATUS_NONE, + FRIENDCONN_STATUS_CONNECTING, + FRIENDCONN_STATUS_CONNECTED +}; + +typedef struct { + uint8_t status; + + uint8_t real_public_key[crypto_box_PUBLICKEYBYTES]; + uint8_t dht_temp_pk[crypto_box_PUBLICKEYBYTES]; + uint16_t dht_lock; + IP_Port dht_ip_port; + uint64_t dht_ping_lastrecv, dht_ip_port_lastrecv; + + int onion_friendnum; + int crypt_connection_id; + + uint64_t ping_lastrecv, ping_lastsent; + + struct { + int (*status_callback)(void *object, int id, uint8_t status); + void *status_callback_object; + int status_callback_id; + + int (*data_callback)(void *object, int id, uint8_t *data, uint16_t length); + void *data_callback_object; + int data_callback_id; + + int (*lossy_data_callback)(void *object, int id, const uint8_t *data, uint16_t length); + void *lossy_data_callback_object; + int lossy_data_callback_id; + } callbacks[MAX_FRIEND_CONNECTION_CALLBACKS]; + + uint16_t lock_count; +} Friend_Conn; + + +typedef struct { + Net_Crypto *net_crypto; + DHT *dht; + Onion_Client *onion_c; + + Friend_Conn *conns; + uint32_t num_cons; + +} Friend_Connections; + +/* Set the callbacks for the friend connection. + * index is the index (0 to (MAX_FRIEND_CONNECTION_CALLBACKS - 1)) we want the callback to set in the array. + * + * return 0 on success. + * return -1 on failure + */ +int friend_connection_callbacks(Friend_Connections *fr_c, int friendcon_id, unsigned int index, + int (*status_callback)(void *object, int id, uint8_t status), int (*data_callback)(void *object, int id, uint8_t *data, + uint16_t length), int (*lossy_data_callback)(void *object, int id, const uint8_t *data, uint16_t length), void *object, + int number); + +/* return the crypt_connection_id for the connection. + * + * return crypt_connection_id on success. + * return -1 on failure. + */ +int friend_connection_crypt_connection_id(Friend_Connections *fr_c, int friendcon_id); + +/* Create a new friend connection. + * If one to that real public key already exists, increase lock count and return it. + * + * return -1 on failure. + * return connection id on success. + */ +int new_friend_connection(Friend_Connections *fr_c, const uint8_t *real_public_key); + +/* Kill a friend connection. + * + * return -1 on failure. + * return 0 on success. + */ +int kill_friend_connection(Friend_Connections *fr_c, int friendcon_id); + +/* Create new friend_connections instance. */ +Friend_Connections *new_friend_connections(Onion_Client *onion_c); + +/* main friend_connections loop. */ +void do_friend_connections(Friend_Connections *fr_c); + +/* Free everything related with friend_connections. */ +void kill_friend_connections(Friend_Connections *fr_c); + +#endif -- cgit v1.2.3