From 3853a30acf67bf07fcbb7254eafd31da8f749a32 Mon Sep 17 00:00:00 2001 From: Jfreegman Date: Mon, 9 Sep 2013 06:41:33 -0400 Subject: initialize name_length --- toxcore/Messenger.c | 6 ++++-- toxcore/tox.c | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) (limited to 'toxcore') diff --git a/toxcore/Messenger.c b/toxcore/Messenger.c index 07893e02..3757faf3 100644 --- a/toxcore/Messenger.c +++ b/toxcore/Messenger.c @@ -346,7 +346,7 @@ static int m_sendname(Messenger *m, int friendnumber, uint8_t *name, uint16_t le return write_cryptpacket_id(m, friendnumber, PACKET_ID_NICKNAME, name, length); } -/* Set the name of a friend. +/* Set the name and name_length of a friend. * * return 0 if success. * return -1 if failure. @@ -356,7 +356,9 @@ static int setfriendname(Messenger *m, int friendnumber, uint8_t *name) if (friend_not_valid(m, friendnumber)) return -1; - memcpy(m->friendlist[friendnumber].name, name, MAX_NAME_LENGTH); + uint16_t len = strlen(name) + 1; + m->friendlist[friendnumber].name_length = len; + memcpy(m->friendlist[friendnumber].name, name, len); return 0; } diff --git a/toxcore/tox.c b/toxcore/tox.c index 83b19e9b..54bbd9f0 100644 --- a/toxcore/tox.c +++ b/toxcore/tox.c @@ -184,7 +184,7 @@ uint16_t tox_getselfname(void *tox, uint8_t *name, uint16_t nlen) /* Get name of friendnumber and put it in name. * name needs to be a valid memory location with a size of at least MAX_NAME_LENGTH (128) bytes. * - * return 0 if success. + * return length of name (with the NULL terminator) if success. * return -1 if failure. */ int tox_getname(void *tox, int friendnumber, uint8_t *name) -- cgit v1.2.3 From 5a1897162b16ec8aeccef2428e663748ab7852f5 Mon Sep 17 00:00:00 2001 From: Jfreegman Date: Mon, 9 Sep 2013 07:11:30 -0400 Subject: a better way --- toxcore/Messenger.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'toxcore') diff --git a/toxcore/Messenger.c b/toxcore/Messenger.c index 3757faf3..eb40cf10 100644 --- a/toxcore/Messenger.c +++ b/toxcore/Messenger.c @@ -351,12 +351,11 @@ static int m_sendname(Messenger *m, int friendnumber, uint8_t *name, uint16_t le * return 0 if success. * return -1 if failure. */ -static int setfriendname(Messenger *m, int friendnumber, uint8_t *name) +static int setfriendname(Messenger *m, int friendnumber, uint8_t *name, uint8_t len) { if (friend_not_valid(m, friendnumber)) return -1; - uint16_t len = strlen(name) + 1; m->friendlist[friendnumber].name_length = len; memcpy(m->friendlist[friendnumber].name, name, len); return 0; @@ -1029,7 +1028,7 @@ int Messenger_load(Messenger *m, uint8_t *data, uint32_t length) for (i = 0; i < num; ++i) { if (temp[i].status >= 3) { int fnum = m_addfriend_norequest(m, temp[i].client_id); - setfriendname(m, fnum, temp[i].name); + setfriendname(m, fnum, temp[i].name, temp[i].name_length); /* set_friend_statusmessage(fnum, temp[i].statusmessage, temp[i].statusmessage_length); */ } else if (temp[i].status != 0) { /* TODO: This is not a good way to do this. */ -- cgit v1.2.3 From 7e84ba460688f54a4ccb33b6c3395e090a36cc89 Mon Sep 17 00:00:00 2001 From: Jfreegman Date: Mon, 9 Sep 2013 07:14:47 -0400 Subject: wrong type --- toxcore/Messenger.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'toxcore') diff --git a/toxcore/Messenger.c b/toxcore/Messenger.c index eb40cf10..b712d142 100644 --- a/toxcore/Messenger.c +++ b/toxcore/Messenger.c @@ -351,7 +351,7 @@ static int m_sendname(Messenger *m, int friendnumber, uint8_t *name, uint16_t le * return 0 if success. * return -1 if failure. */ -static int setfriendname(Messenger *m, int friendnumber, uint8_t *name, uint8_t len) +static int setfriendname(Messenger *m, int friendnumber, uint8_t *name, uint16_t len) { if (friend_not_valid(m, friendnumber)) return -1; -- cgit v1.2.3 From c137ec9d4d37dedf4d2a40d8c573eed4239a8ec1 Mon Sep 17 00:00:00 2001 From: irungentoo Date: Mon, 9 Sep 2013 14:16:53 -0400 Subject: move group chats to /toxcore --- testing/experiment/group_chats.c | 575 -------------------------------- testing/experiment/group_chats.h | 123 ------- testing/experiment/group_chats_test.c | 2 +- testing/experiment/group_chats_test1.c | 2 +- toxcore/group_chats.c | 579 +++++++++++++++++++++++++++++++++ toxcore/group_chats.h | 123 +++++++ 6 files changed, 704 insertions(+), 700 deletions(-) delete mode 100644 testing/experiment/group_chats.c delete mode 100644 testing/experiment/group_chats.h create mode 100644 toxcore/group_chats.c create mode 100644 toxcore/group_chats.h (limited to 'toxcore') diff --git a/testing/experiment/group_chats.c b/testing/experiment/group_chats.c deleted file mode 100644 index 0698ebf8..00000000 --- a/testing/experiment/group_chats.c +++ /dev/null @@ -1,575 +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 . - * - */ - -#include "group_chats.h" - - -#define GROUPCHAT_MAXDATA_LENGTH (MAX_DATA_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; - -/* 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(uint8_t *id, uint8_t *id1, uint8_t *id2) -{ - size_t i; - uint8_t distance1, distance2; - - for (i = 0; i < CLIENT_ID_SIZE; ++i) { - - distance1 = abs(((int8_t *)id)[i] ^ ((int8_t *)id1)[i]); - distance2 = abs(((int8_t *)id)[i] ^ ((int8_t *)id2)[i]); - - if (distance1 < distance2) - return 1; - - if (distance1 > distance2) - return 2; - } - - return 0; -} - - -/* - * 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(Group_Chat *chat, uint8_t *client_id) -{ - uint32_t i; - - for (i = 0; i < chat->numpeers; ++i) { - /* Equal */ - if (memcmp(chat->group[i].client_id, client_id, crypto_box_PUBLICKEYBYTES) == 0) - return i; - } - - return -1; -} - -#define BAD_NODE_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(Group_Chat *chat, uint8_t *client_id) -{ - uint32_t i, j = 0; - uint64_t temp_time = unix_time(); - - if (memcmp(chat->self_public_key, client_id, crypto_box_PUBLICKEYBYTES) == 0) - return -1; - - for (i = 0; i < GROUP_CLOSE_CONNECTIONS; ++i) { - if (chat->close[i].last_recv + BAD_NODE_TIMEOUT < temp_time) { - ++j; - continue; - } - - /* Equal */ - if (memcmp(chat->close[i].client_id, client_id, crypto_box_PUBLICKEYBYTES) == 0) - return -1; - - if (id_closest(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, uint8_t *client_id, IP_Port ip_port) -{ - uint32_t i; - uint64_t temp_time = unix_time(); - - for (i = 0; i < GROUP_CLOSE_CONNECTIONS; ++i) { /* Check if node is already in list, if it is update its last_recv */ - if (memcmp(chat->close[i].client_id, client_id, crypto_box_PUBLICKEYBYTES) == 0) { - chat->close[i].last_recv = temp_time; - return 0; - } - } - - for (i = 0; i < GROUP_CLOSE_CONNECTIONS; ++i) { /* Try replacing bad nodes first */ - if (chat->close[i].last_recv + BAD_NODE_TIMEOUT < temp_time) { - memcpy(chat->close[i].client_id, client_id, crypto_box_PUBLICKEYBYTES); - chat->close[i].ip_port = ip_port; - chat->close[i].last_recv = temp_time; - return 0; - } - } - - for (i = 0; i < GROUP_CLOSE_CONNECTIONS; ++i) { /* Replace nodes if given one is closer. */ - if (id_closest(chat->self_public_key, chat->close[i].client_id, client_id) == 2) { - memcpy(chat->close[i].client_id, client_id, crypto_box_PUBLICKEYBYTES); - chat->close[i].ip_port = ip_port; - chat->close[i].last_recv = temp_time; - return 0; - } - } - - return -1; -} - -static int send_groupchatpacket(Group_Chat *chat, IP_Port ip_port, uint8_t *public_key, uint8_t *data, uint32_t length, - uint8_t request_id) -{ - if (memcmp(chat->self_public_key, public_key, crypto_box_PUBLICKEYBYTES) == 0) - return -1; - - uint8_t packet[MAX_DATA_SIZE]; - int len = create_request(chat->self_public_key, chat->self_secret_key, packet, public_key, data, length, request_id); - packet[0] = 48; - - if (len == -1) - return -1; - - if (sendpacket(chat->net->sock, 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(Group_Chat *chat, uint8_t *data, uint16_t length, uint8_t request_id) -{ - uint16_t sent = 0; - uint32_t i; - uint64_t temp_time = unix_time(); - - for (i = 0; i < GROUP_CLOSE_CONNECTIONS; ++i) { - if (chat->close[i].ip_port.ip.uint32 != 0 && chat->close[i].last_recv + BAD_NODE_TIMEOUT > temp_time) { - 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, 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)); - memset(&(temp[chat->numpeers]), 0, sizeof(Group_Peer)); - - if (temp == NULL) - return -1; - - chat->group = temp; - memcpy(chat->group[chat->numpeers].client_id, client_id, crypto_box_PUBLICKEYBYTES); - ++chat->numpeers; - return (chat->numpeers - 1); -} - -/* - * Delete a peer to the group chat. - * - * return 0 if success - * return -1 if error. - */ -static int delpeer(Group_Chat *chat, uint8_t *client_id) -{ - uint32_t i; - Group_Peer *temp; - - for (i = 0; i < chat->numpeers; ++i) { - /* Equal */ - if (memcmp(chat->group[i].client_id, client_id, crypto_box_PUBLICKEYBYTES) == 0) { - --chat->numpeers; - - if (chat->numpeers != i) { - memcpy( chat->group[i].client_id, - chat->group[chat->numpeers].client_id, - crypto_box_PUBLICKEYBYTES ); - } - - temp = realloc(chat->group, sizeof(Group_Peer) * (chat->numpeers)); - - if (temp == NULL) - return -1; - - chat->group = temp; - return 0; - } - } - - return -1; -} -/* min time between pings sent to one peer in seconds */ -#define PING_TIMEOUT 5 -static int send_getnodes(Group_Chat *chat, IP_Port ip_port, int peernum) -{ - if ((uint32_t)peernum >= chat->numpeers) - return -1; - - uint64_t temp_time = unix_time(); - - getnodes_data contents; - - if (chat->group[peernum].last_pinged + PING_TIMEOUT > temp_time) - return -1; - - contents.pingid = ((uint64_t)random_int() << 32) + random_int(); - chat->group[peernum].last_pinged = temp_time; - chat->group[peernum].pingid = contents.pingid; - return send_groupchatpacket(chat, ip_port, chat->group[peernum].client_id, (uint8_t *)&contents, sizeof(contents), 48); -} - -static int send_sendnodes(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; - uint64_t temp_time = unix_time(); - - for (i = 0; i < GROUP_CLOSE_CONNECTIONS; ++i) { - if (chat->close[i].last_recv + BAD_NODE_TIMEOUT > temp_time) { - memcpy(contents.nodes[j].client_id, chat->close[i].client_id, crypto_box_PUBLICKEYBYTES); - contents.nodes[j].ip_port = chat->close[i].ip_port; - ++j; - } - } - - return send_groupchatpacket(chat, ip_port, chat->group[peernum].client_id, (uint8_t *)&contents, - sizeof(contents.pingid) + sizeof(groupchat_nodes) * j, 49); -} - -static int handle_getnodes(Group_Chat *chat, IP_Port source, int peernum, 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, 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 (chat->group[peernum].last_pinged + PING_TIMEOUT < unix_time()) - 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; - - 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; - - send_getnodes(chat, contents.nodes[i].ip_port, peern); - } - } - - add_closepeer(chat, chat->group[peernum].client_id, source); - return 0; -} -#define GROUP_DATA_MIN_SIZE (crypto_box_PUBLICKEYBYTES + sizeof(uint32_t) + 1) -static int handle_data(Group_Chat *chat, 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) - return 1; - - uint64_t temp_time = unix_time(); - /* Spam prevention (1 message per peer per second limit.) - - if (chat->group[peernum].last_recv == temp_time) - return 1; - - chat->group[peernum].last_recv = temp_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; - 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 0: /* If message is ping */ - if (contents_len != 0) - return 1; - - chat->group[peernum].last_recv_msgping = temp_time; - - case 16: /* If message is new peer */ - if (contents_len != crypto_box_PUBLICKEYBYTES) - return 1; - - addpeer(chat, contents); - break; - - case 64: /* If message is chat message */ - if (chat->group_message != NULL) - (*chat->group_message)(chat, peernum, contents, contents_len, chat->group_message_userdata); - - break; - - default: - handled = 0; - break; - - } - - if (handled == 1) { - sendto_allpeers(chat, data, len, 50); - return 0; - } - - return 1; -} - -static uint8_t send_data(Group_Chat *chat, uint8_t *data, uint32_t len, uint8_t message_id) -{ - if (len + GROUP_DATA_MIN_SIZE > MAX_DATA_SIZE) /*NOTE: not the real maximum len.*/ - return 1; - - uint8_t packet[MAX_DATA_SIZE]; - ++chat->message_number; - - if (chat->message_number == 0) - chat->message_number = 1; - - uint32_t message_num = htonl(chat->message_number); -//TODO - memcpy(packet, chat->self_public_key, crypto_box_PUBLICKEYBYTES); - memcpy(packet + crypto_box_PUBLICKEYBYTES, &message_num, sizeof(message_num)); - 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, 50); -} -/* - * Handle get nodes group packet. - * - * return 0 if handled correctly. - * return 1 if error. - */ - -int handle_groupchatpacket(Group_Chat *chat, IP_Port source, uint8_t *packet, uint32_t length) -{ - if (length > MAX_DATA_SIZE) - return 1; - - uint8_t public_key[crypto_box_PUBLICKEYBYTES]; - uint8_t data[MAX_DATA_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 (memcmp(chat->self_public_key, public_key, crypto_box_PUBLICKEYBYTES) == 0) - return 1; - - int peernum = peer_in_chat(chat, public_key); - - if (peernum == -1) - return 1; - - switch (number) { - case 48: - return handle_getnodes(chat, source, peernum, data, len); - - case 49: - return handle_sendnodes(chat, source, peernum, data, len); - - case 50: - return handle_data(chat, data, len); - - default: - return 1; - } - - return 1; -} - -uint32_t group_sendmessage(Group_Chat *chat, uint8_t *message, uint32_t length) -{ - return send_data(chat, message, length, 64); //TODO: better return values? -} - -uint32_t group_newpeer(Group_Chat *chat, uint8_t *client_id) -{ - addpeer(chat, client_id); - return send_data(chat, client_id, crypto_box_PUBLICKEYBYTES, 16); //TODO: better return values? -} - -void callback_groupmessage(Group_Chat *chat, void (*function)(Group_Chat *chat, int, uint8_t *, uint16_t, void *), - void *userdata) -{ - chat->group_message = function; - chat->group_message_userdata = userdata; -} - -Group_Chat *new_groupchat(Networking_Core *net) -{ - 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); - return chat; -} - -#define NODE_PING_INTERVAL 10 - -static void ping_close(Group_Chat *chat) -{ - uint32_t i; - uint64_t temp_time = unix_time(); - - for (i = 0; i < GROUP_CLOSE_CONNECTIONS; ++i) { - if (chat->close[i].last_recv < temp_time + BAD_NODE_TIMEOUT) { - int peernum = peer_in_chat(chat, chat->close[i].client_id); - - if (peernum == -1) - continue; - - if (chat->group[peernum].last_pinged + NODE_PING_INTERVAL < temp_time) - send_getnodes(chat, chat->close[i].ip_port, peernum); - } - } -} - -void do_groupchat(Group_Chat *chat) -{ - ping_close(chat); -} - -void kill_groupchat(Group_Chat *chat) -{ - free(chat->group); - free(chat); -} - -void chat_bootstrap(Group_Chat *chat, IP_Port ip_port, uint8_t *client_id) -{ - send_getnodes(chat, ip_port, addpeer(chat, client_id)); -} diff --git a/testing/experiment/group_chats.h b/testing/experiment/group_chats.h deleted file mode 100644 index 3330ce10..00000000 --- a/testing/experiment/group_chats.h +++ /dev/null @@ -1,123 +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 - -#include "../../toxcore/net_crypto.h" - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct { - uint8_t client_id[crypto_box_PUBLICKEYBYTES]; - uint64_t pingid; - uint64_t last_pinged; - - uint64_t last_recv; - uint64_t last_recv_msgping; - uint32_t last_message_number; -} 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, uint8_t *, uint16_t, void *); - void *group_message_userdata; - -} Group_Chat; - -/* - * 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, uint8_t *, uint16_t, void *), - void *userdata); - -/* - * Send a message to the group. - * - */ -uint32_t group_sendmessage(Group_Chat *chat, uint8_t *message, uint32_t length); - - -/* - * Tell everyone about a new peer (a person we are inviting for example.) - * - */ -uint32_t group_newpeer(Group_Chat *chat, 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); - - -/* 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, uint8_t *packet, uint32_t length); - - -void chat_bootstrap(Group_Chat *chat, IP_Port ip_port, uint8_t *client_id); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/testing/experiment/group_chats_test.c b/testing/experiment/group_chats_test.c index 9ddf5e85..900da79c 100644 --- a/testing/experiment/group_chats_test.c +++ b/testing/experiment/group_chats_test.c @@ -1,4 +1,4 @@ -#include "group_chats.h" +#include "../../toxcore/group_chats.h" #define NUM_CHATS 8 #ifdef WIN32 diff --git a/testing/experiment/group_chats_test1.c b/testing/experiment/group_chats_test1.c index f66c2d24..efd9ae84 100644 --- a/testing/experiment/group_chats_test1.c +++ b/testing/experiment/group_chats_test1.c @@ -1,4 +1,4 @@ -#include "group_chats.h" +#include "../../toxcore/group_chats.h" #define NUM_CHATS 8 #ifdef WIN32 diff --git a/toxcore/group_chats.c b/toxcore/group_chats.c new file mode 100644 index 00000000..3c134348 --- /dev/null +++ b/toxcore/group_chats.c @@ -0,0 +1,579 @@ +/* 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 . + * + */ + +#include "group_chats.h" + + +#define GROUPCHAT_MAXDATA_LENGTH (MAX_DATA_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; + +/* 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(uint8_t *id, uint8_t *id1, uint8_t *id2) +{ + size_t i; + uint8_t distance1, distance2; + + for (i = 0; i < CLIENT_ID_SIZE; ++i) { + + distance1 = abs(((int8_t *)id)[i] ^ ((int8_t *)id1)[i]); + distance2 = abs(((int8_t *)id)[i] ^ ((int8_t *)id2)[i]); + + if (distance1 < distance2) + return 1; + + if (distance1 > distance2) + return 2; + } + + return 0; +} + + +/* + * 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(Group_Chat *chat, uint8_t *client_id) +{ + uint32_t i; + + for (i = 0; i < chat->numpeers; ++i) { + /* Equal */ + if (memcmp(chat->group[i].client_id, client_id, crypto_box_PUBLICKEYBYTES) == 0) + return i; + } + + return -1; +} + +#define BAD_NODE_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(Group_Chat *chat, uint8_t *client_id) +{ + uint32_t i, j = 0; + uint64_t temp_time = unix_time(); + + if (memcmp(chat->self_public_key, client_id, crypto_box_PUBLICKEYBYTES) == 0) + return -1; + + for (i = 0; i < GROUP_CLOSE_CONNECTIONS; ++i) { + if (chat->close[i].last_recv + BAD_NODE_TIMEOUT < temp_time) { + ++j; + continue; + } + + /* Equal */ + if (memcmp(chat->close[i].client_id, client_id, crypto_box_PUBLICKEYBYTES) == 0) + return -1; + + if (id_closest(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, uint8_t *client_id, IP_Port ip_port) +{ + uint32_t i; + uint64_t temp_time = unix_time(); + + for (i = 0; i < GROUP_CLOSE_CONNECTIONS; ++i) { /* Check if node is already in list, if it is update its last_recv */ + if (memcmp(chat->close[i].client_id, client_id, crypto_box_PUBLICKEYBYTES) == 0) { + chat->close[i].last_recv = temp_time; + return 0; + } + } + + for (i = 0; i < GROUP_CLOSE_CONNECTIONS; ++i) { /* Try replacing bad nodes first */ + if (chat->close[i].last_recv + BAD_NODE_TIMEOUT < temp_time) { + memcpy(chat->close[i].client_id, client_id, crypto_box_PUBLICKEYBYTES); + chat->close[i].ip_port = ip_port; + chat->close[i].last_recv = temp_time; + return 0; + } + } + + for (i = 0; i < GROUP_CLOSE_CONNECTIONS; ++i) { /* Replace nodes if given one is closer. */ + if (id_closest(chat->self_public_key, chat->close[i].client_id, client_id) == 2) { + memcpy(chat->close[i].client_id, client_id, crypto_box_PUBLICKEYBYTES); + chat->close[i].ip_port = ip_port; + chat->close[i].last_recv = temp_time; + return 0; + } + } + + return -1; +} + +static int send_groupchatpacket(Group_Chat *chat, IP_Port ip_port, uint8_t *public_key, uint8_t *data, uint32_t length, + uint8_t request_id) +{ + if (memcmp(chat->self_public_key, public_key, crypto_box_PUBLICKEYBYTES) == 0) + return -1; + + uint8_t packet[MAX_DATA_SIZE]; + int len = create_request(chat->self_public_key, chat->self_secret_key, packet, public_key, data, length, request_id); + packet[0] = 48; + + if (len == -1) + return -1; + + if (sendpacket(chat->net->sock, 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(Group_Chat *chat, uint8_t *data, uint16_t length, uint8_t request_id) +{ + uint16_t sent = 0; + uint32_t i; + uint64_t temp_time = unix_time(); + + for (i = 0; i < GROUP_CLOSE_CONNECTIONS; ++i) { + if (chat->close[i].ip_port.ip.uint32 != 0 && chat->close[i].last_recv + BAD_NODE_TIMEOUT > temp_time) { + 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, 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)); + memset(&(temp[chat->numpeers]), 0, sizeof(Group_Peer)); + + if (temp == NULL) + return -1; + + chat->group = temp; + memcpy(chat->group[chat->numpeers].client_id, client_id, crypto_box_PUBLICKEYBYTES); + ++chat->numpeers; + return (chat->numpeers - 1); +} + +/* + * Delete a peer to the group chat. + * + * return 0 if success + * return -1 if error. + */ +static int delpeer(Group_Chat *chat, uint8_t *client_id) +{ + uint32_t i; + Group_Peer *temp; + + for (i = 0; i < chat->numpeers; ++i) { + /* Equal */ + if (memcmp(chat->group[i].client_id, client_id, crypto_box_PUBLICKEYBYTES) == 0) { + --chat->numpeers; + + if (chat->numpeers != i) { + memcpy( chat->group[i].client_id, + chat->group[chat->numpeers].client_id, + crypto_box_PUBLICKEYBYTES ); + } + + temp = realloc(chat->group, sizeof(Group_Peer) * (chat->numpeers)); + + if (temp == NULL) + return -1; + + chat->group = temp; + return 0; + } + } + + return -1; +} +/* min time between pings sent to one peer in seconds */ +#define PING_TIMEOUT 5 +static int send_getnodes(Group_Chat *chat, IP_Port ip_port, int peernum) +{ + if ((uint32_t)peernum >= chat->numpeers) + return -1; + + uint64_t temp_time = unix_time(); + + getnodes_data contents; + + if (chat->group[peernum].last_pinged + PING_TIMEOUT > temp_time) + return -1; + + contents.pingid = ((uint64_t)random_int() << 32) + random_int(); + chat->group[peernum].last_pinged = temp_time; + chat->group[peernum].pingid = contents.pingid; + return send_groupchatpacket(chat, ip_port, chat->group[peernum].client_id, (uint8_t *)&contents, sizeof(contents), 48); +} + +static int send_sendnodes(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; + uint64_t temp_time = unix_time(); + + for (i = 0; i < GROUP_CLOSE_CONNECTIONS; ++i) { + if (chat->close[i].last_recv + BAD_NODE_TIMEOUT > temp_time) { + memcpy(contents.nodes[j].client_id, chat->close[i].client_id, crypto_box_PUBLICKEYBYTES); + contents.nodes[j].ip_port = chat->close[i].ip_port; + ++j; + } + } + + return send_groupchatpacket(chat, ip_port, chat->group[peernum].client_id, (uint8_t *)&contents, + sizeof(contents.pingid) + sizeof(groupchat_nodes) * j, 49); +} + +static int handle_getnodes(Group_Chat *chat, IP_Port source, int peernum, 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, 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 (chat->group[peernum].last_pinged + PING_TIMEOUT < unix_time()) + 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; + + 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; + + send_getnodes(chat, contents.nodes[i].ip_port, peern); + } + } + + add_closepeer(chat, chat->group[peernum].client_id, source); + return 0; +} +#define GROUP_DATA_MIN_SIZE (crypto_box_PUBLICKEYBYTES + sizeof(uint32_t) + 1) +static int handle_data(Group_Chat *chat, 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.*/ + peernum = addpeer(chat, data); + } + + if (peernum == -1) + return 1; + + uint64_t temp_time = unix_time(); + /* Spam prevention (1 message per peer per second limit.) + + if (chat->group[peernum].last_recv == temp_time) + return 1; + + chat->group[peernum].last_recv = temp_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; + 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 0: /* If message is ping */ + if (contents_len != 0) + return 1; + + chat->group[peernum].last_recv_msgping = temp_time; + + case 16: /* If message is new peer */ + if (contents_len != crypto_box_PUBLICKEYBYTES) + return 1; + + addpeer(chat, contents); + break; + + case 64: /* If message is chat message */ + if (chat->group_message != NULL) + (*chat->group_message)(chat, peernum, contents, contents_len, chat->group_message_userdata); + + break; + + default: + handled = 0; + break; + + } + + if (handled == 1) { + sendto_allpeers(chat, data, len, 50); + return 0; + } + + return 1; +} + +static uint8_t send_data(Group_Chat *chat, uint8_t *data, uint32_t len, uint8_t message_id) +{ + if (len + GROUP_DATA_MIN_SIZE > MAX_DATA_SIZE) /*NOTE: not the real maximum len.*/ + return 1; + + uint8_t packet[MAX_DATA_SIZE]; + ++chat->message_number; + + if (chat->message_number == 0) + chat->message_number = 1; + + uint32_t message_num = htonl(chat->message_number); +//TODO + memcpy(packet, chat->self_public_key, crypto_box_PUBLICKEYBYTES); + memcpy(packet + crypto_box_PUBLICKEYBYTES, &message_num, sizeof(message_num)); + 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, 50); +} +/* + * Handle get nodes group packet. + * + * return 0 if handled correctly. + * return 1 if error. + */ + +int handle_groupchatpacket(Group_Chat *chat, IP_Port source, uint8_t *packet, uint32_t length) +{ + if (length > MAX_DATA_SIZE) + return 1; + + uint8_t public_key[crypto_box_PUBLICKEYBYTES]; + uint8_t data[MAX_DATA_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 (memcmp(chat->self_public_key, public_key, crypto_box_PUBLICKEYBYTES) == 0) + return 1; + + int peernum = peer_in_chat(chat, public_key); + + if (peernum == -1) + return 1; + + switch (number) { + case 48: + return handle_getnodes(chat, source, peernum, data, len); + + case 49: + return handle_sendnodes(chat, source, peernum, data, len); + + case 50: + return handle_data(chat, data, len); + + default: + return 1; + } + + return 1; +} + +uint32_t group_sendmessage(Group_Chat *chat, uint8_t *message, uint32_t length) +{ + return send_data(chat, message, length, 64); //TODO: better return values? +} + +uint32_t group_newpeer(Group_Chat *chat, uint8_t *client_id) +{ + addpeer(chat, client_id); + return send_data(chat, client_id, crypto_box_PUBLICKEYBYTES, 16); //TODO: better return values? +} + +void callback_groupmessage(Group_Chat *chat, void (*function)(Group_Chat *chat, int, uint8_t *, uint16_t, void *), + void *userdata) +{ + chat->group_message = function; + chat->group_message_userdata = userdata; +} + +Group_Chat *new_groupchat(Networking_Core *net) +{ + 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); + return chat; +} + +#define NODE_PING_INTERVAL 10 + +static void ping_close(Group_Chat *chat) +{ + uint32_t i; + uint64_t temp_time = unix_time(); + + for (i = 0; i < GROUP_CLOSE_CONNECTIONS; ++i) { + if (chat->close[i].last_recv < temp_time + BAD_NODE_TIMEOUT) { + int peernum = peer_in_chat(chat, chat->close[i].client_id); + + if (peernum == -1) + continue; + + if (chat->group[peernum].last_pinged + NODE_PING_INTERVAL < temp_time) + send_getnodes(chat, chat->close[i].ip_port, peernum); + } + } +} + +void do_groupchat(Group_Chat *chat) +{ + ping_close(chat); +} + +void kill_groupchat(Group_Chat *chat) +{ + free(chat->group); + free(chat); +} + +void chat_bootstrap(Group_Chat *chat, IP_Port ip_port, uint8_t *client_id) +{ + send_getnodes(chat, ip_port, addpeer(chat, client_id)); +} diff --git a/toxcore/group_chats.h b/toxcore/group_chats.h new file mode 100644 index 00000000..7af13d8d --- /dev/null +++ b/toxcore/group_chats.h @@ -0,0 +1,123 @@ +/* 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 + +#include "net_crypto.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct { + uint8_t client_id[crypto_box_PUBLICKEYBYTES]; + uint64_t pingid; + uint64_t last_pinged; + + uint64_t last_recv; + uint64_t last_recv_msgping; + uint32_t last_message_number; +} 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, uint8_t *, uint16_t, void *); + void *group_message_userdata; + +} Group_Chat; + +/* + * 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, uint8_t *, uint16_t, void *), + void *userdata); + +/* + * Send a message to the group. + * + */ +uint32_t group_sendmessage(Group_Chat *chat, uint8_t *message, uint32_t length); + + +/* + * Tell everyone about a new peer (a person we are inviting for example.) + * + */ +uint32_t group_newpeer(Group_Chat *chat, 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); + + +/* 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, uint8_t *packet, uint32_t length); + + +void chat_bootstrap(Group_Chat *chat, IP_Port ip_port, uint8_t *client_id); + +#ifdef __cplusplus +} +#endif + +#endif -- cgit v1.2.3 From 1f5bfab3278164293dd798ca24ead081c54708da Mon Sep 17 00:00:00 2001 From: irungentoo Date: Mon, 9 Sep 2013 14:44:43 -0400 Subject: Start of group chats integration into the core. --- toxcore/Makefile.inc | 2 ++ toxcore/Messenger.h | 4 ++++ 2 files changed, 6 insertions(+) (limited to 'toxcore') diff --git a/toxcore/Makefile.inc b/toxcore/Makefile.inc index 5a9002ef..025f23c8 100644 --- a/toxcore/Makefile.inc +++ b/toxcore/Makefile.inc @@ -25,6 +25,8 @@ libtoxcore_la_SOURCES = ../toxcore/DHT.h \ ../toxcore/tox.c \ ../toxcore/util.h \ ../toxcore/util.c \ + ../toxcore/group_chats.h \ + ../toxcore/group_chats.c \ ../toxcore/misc_tools.h libtoxcore_la_CFLAGS = -I$(top_srcdir) \ diff --git a/toxcore/Messenger.h b/toxcore/Messenger.h index c512245c..40617d08 100644 --- a/toxcore/Messenger.h +++ b/toxcore/Messenger.h @@ -30,6 +30,7 @@ #include "DHT.h" #include "friend_requests.h" #include "LAN_discovery.h" +#include "group_chats.h" #define MAX_NAME_LENGTH 128 #define MAX_STATUSMESSAGE_LENGTH 1007 @@ -133,6 +134,9 @@ typedef struct Messenger { Friend *friendlist; uint32_t numfriends; + Group_Chat *chats; + uint32_t numchats; + uint64_t last_LANdiscovery; void (*friend_message)(struct Messenger *m, int, uint8_t *, uint16_t, void *); -- cgit v1.2.3