From aa63c1330c49ee1c4b675037e2e54516950203a2 Mon Sep 17 00:00:00 2001 From: zugz Date: Wed, 25 Jul 2018 08:46:28 +0100 Subject: [PATCH] Fix problems with initial connections and name-setting in conferences * test names in conference_test * raise error on attempt to invite friend to group before we are connected * revise handling of temporary invited connections We are now careful not to prematurely delete a connection to a peer established during the invitation process; namely, before we have sufficient other connections and have confirmed that we have an alternative route to the peer. * process out-of-order messages from a peer * don't reset names when handling a Peer Response --- auto_tests/conference_simple_test.c | 34 ++++--- auto_tests/conference_test.c | 141 ++++++++++++++++++++-------- toxcore/group.c | 141 +++++++++++++++++++++------- toxcore/group.h | 18 +++- toxcore/tox.api.h | 4 + toxcore/tox.c | 4 + toxcore/tox.h | 5 + 7 files changed, 260 insertions(+), 87 deletions(-) diff --git a/auto_tests/conference_simple_test.c b/auto_tests/conference_simple_test.c index 8d95bba8..f2bede30 100644 --- a/auto_tests/conference_simple_test.c +++ b/auto_tests/conference_simple_test.c @@ -13,6 +13,7 @@ typedef struct State { uint32_t id; bool self_online; bool friend_online; + bool invited_next; bool joined; uint32_t conference; @@ -55,19 +56,6 @@ static void handle_conference_invite(Tox *tox, uint32_t friend_number, TOX_CONFE fprintf(stderr, "tox%d Joined conference %d\n", state->id, state->conference); state->joined = true; } - - // We're tox2, so now we invite tox3. - if (state->id == 2) { - TOX_ERR_CONFERENCE_INVITE err; - tox_conference_invite(tox, 1, state->conference, &err); - - if (err != TOX_ERR_CONFERENCE_INVITE_OK) { - fprintf(stderr, "ERROR: %d\n", err); - exit(EXIT_FAILURE); - } - - fprintf(stderr, "tox2 invited tox3\n"); - } } static void handle_conference_message(Tox *tox, uint32_t conference_number, uint32_t peer_number, @@ -99,6 +87,25 @@ static void handle_conference_peer_list_changed(Tox *tox, uint32_t conference_nu fprintf(stderr, "tox%d has %d peers online\n", state->id, count); state->peers = count; + + // We're tox2, so now we invite tox3. + if (state->id == 2 && !state->invited_next) { + // TODO(zugz): neater way to determine whether we are connected, and when + // we become so + TOX_ERR_CONFERENCE_PEER_QUERY peer_err; + tox_conference_peer_number_is_ours(tox, 0, 0, &peer_err); + + if (peer_err != TOX_ERR_CONFERENCE_PEER_QUERY_OK) { + return; + } + + TOX_ERR_CONFERENCE_INVITE err; + tox_conference_invite(tox, 1, state->conference, &err); + ck_assert_msg(err == TOX_ERR_CONFERENCE_INVITE_OK, "tox2 failed to invite tox3: err = %d", err); + + state->invited_next = true; + fprintf(stderr, "tox2 invited tox3\n"); + } } int main(void) @@ -195,6 +202,7 @@ int main(void) TOX_ERR_CONFERENCE_INVITE err; tox_conference_invite(tox1, 0, state1.conference, &err); ck_assert_msg(err == TOX_ERR_CONFERENCE_INVITE_OK, "failed to invite a friend: err = %d", err); + state1.invited_next = true; fprintf(stderr, "tox1 invited tox2\n"); } diff --git a/auto_tests/conference_test.c b/auto_tests/conference_test.c index 2bdee78f..fd4f41b4 100644 --- a/auto_tests/conference_test.c +++ b/auto_tests/conference_test.c @@ -15,30 +15,39 @@ #include "../toxcore/util.h" #include "check_compat.h" -#define NUM_GROUP_TOX 5 +#define NUM_GROUP_TOX 16 #define GROUP_MESSAGE "Install Gentoo" +#define NAME_FORMAT_STR "Tox #%4u" +#define NAMELEN 9 +#define NAME_FORMAT "%9s" + +typedef struct State { + uint32_t id; + bool invited_next; +} State; + static void handle_self_connection_status( Tox *tox, TOX_CONNECTION connection_status, void *user_data) { - const uint16_t id = *(uint16_t *)user_data; + const State *state = (State *)user_data; if (connection_status != TOX_CONNECTION_NONE) { - printf("tox #%d: is now connected\n", id); + printf("tox #%u: is now connected\n", state->id); } else { - printf("tox #%d: is now disconnected\n", id); + printf("tox #%u: is now disconnected\n", state->id); } } static void handle_friend_connection_status( Tox *tox, uint32_t friendnumber, TOX_CONNECTION connection_status, void *user_data) { - const uint16_t id = *(uint16_t *)user_data; + const State *state = (State *)user_data; if (connection_status != TOX_CONNECTION_NONE) { - printf("tox #%d: is now connected to friend %d\n", id, friendnumber); + printf("tox #%u: is now connected to friend %u\n", state->id, friendnumber); } else { - printf("tox #%d: is now disconnected from friend %d\n", id, friendnumber); + printf("tox #%u: is now disconnected from friend %u\n", state->id, friendnumber); } } @@ -46,26 +55,44 @@ static void handle_conference_invite( Tox *tox, uint32_t friendnumber, TOX_CONFERENCE_TYPE type, const uint8_t *data, size_t length, void *user_data) { - const uint16_t id = *(uint16_t *)user_data; - ck_assert_msg(type == TOX_CONFERENCE_TYPE_TEXT, "tox #%d: wrong conference type: %d", id, type); + const State *state = (State *)user_data; + ck_assert_msg(type == TOX_CONFERENCE_TYPE_TEXT, "tox #%u: wrong conference type: %d", state->id, type); TOX_ERR_CONFERENCE_JOIN err; uint32_t g_num = tox_conference_join(tox, friendnumber, data, length, &err); - ck_assert_msg(err == TOX_ERR_CONFERENCE_JOIN_OK, "tox #%d: error joining group: %d", id, err); - ck_assert_msg(g_num == 0, "tox #%d: group number was not 0", id); + ck_assert_msg(err == TOX_ERR_CONFERENCE_JOIN_OK, "tox #%u: error joining group: %d", state->id, err); + ck_assert_msg(g_num == 0, "tox #%u: group number was not 0", state->id); // Try joining again. We should only be allowed to join once. tox_conference_join(tox, friendnumber, data, length, &err); ck_assert_msg(err != TOX_ERR_CONFERENCE_JOIN_OK, - "tox #%d: joining groupchat twice should be impossible.", id); + "tox #%u: joining groupchat twice should be impossible.", state->id); +} - if (tox_self_get_friend_list_size(tox) > 1) { - printf("tox #%d: inviting next friend\n", id); - ck_assert_msg(tox_conference_invite(tox, 1, g_num, nullptr) != 0, "failed to invite friend"); - } else { - printf("tox #%d was the last tox, no further invites happening\n", id); +static void handle_conference_peer_list_changed( + Tox *tox, uint32_t conference_number, void *user_data) +{ + State *state = (State *)user_data; + + if (state->invited_next || tox_self_get_friend_list_size(tox) <= 1) { + return; } + + // TODO(zugz): neater way to determine whether we are connected, and when + // we become so + TOX_ERR_CONFERENCE_PEER_QUERY peer_err; + tox_conference_peer_number_is_ours(tox, 0, 0, &peer_err); + + if (peer_err != TOX_ERR_CONFERENCE_PEER_QUERY_OK) { + return; + } + + TOX_ERR_CONFERENCE_INVITE err; + tox_conference_invite(tox, 1, 0, &err); + ck_assert_msg(err == TOX_ERR_CONFERENCE_INVITE_OK, "tox #%u failed to invite next friend: err = %d", state->id, err); + printf("tox #%u: invited next friend\n", state->id); + state->invited_next = true; } static uint16_t num_recv; @@ -79,7 +106,7 @@ static void handle_conference_message( } } -static void run_conference_tests(Tox **toxes, uint32_t *tox_index) +static void run_conference_tests(Tox **toxes, State *state) { for (uint16_t i = 0; i < NUM_GROUP_TOX; ++i) { tox_callback_conference_message(toxes[i], &handle_conference_message); @@ -96,7 +123,7 @@ static void run_conference_tests(Tox **toxes, uint32_t *tox_index) for (uint8_t j = 0; j < 20; ++j) { for (uint16_t i = 0; i < NUM_GROUP_TOX; ++i) { - tox_iterate(toxes[i], &tox_index[i]); + tox_iterate(toxes[i], &state[i]); } c_sleep(25); @@ -105,12 +132,27 @@ static void run_conference_tests(Tox **toxes, uint32_t *tox_index) c_sleep(25); ck_assert_msg(num_recv == NUM_GROUP_TOX, "failed to recv group messages"); + for (uint16_t i = 0; i < NUM_GROUP_TOX; ++i) { + for (uint16_t j = 0; j < NUM_GROUP_TOX; ++j) { + const size_t len = tox_conference_peer_get_name_size(toxes[i], 0, j, nullptr); + ck_assert_msg(len == NAMELEN, "name of #%u according to #%u has incorrect length %u", state[j].id, state[i].id, + (unsigned int)len); + uint8_t name[NAMELEN]; + tox_conference_peer_get_name(toxes[i], 0, j, name, nullptr); + char expected_name[NAMELEN + 1]; + snprintf(expected_name, NAMELEN + 1, NAME_FORMAT_STR, state[j].id); + ck_assert_msg(memcmp(name, expected_name, NAMELEN) == 0, + "name of #%u according to #%u is \"" NAME_FORMAT "\"; expected \"%s\"", + state[j].id, state[i].id, name, expected_name); + } + } + for (uint16_t k = NUM_GROUP_TOX; k != 0 ; --k) { tox_conference_delete(toxes[k - 1], 0, nullptr); for (uint8_t j = 0; j < 10; ++j) { for (uint16_t i = 0; i < NUM_GROUP_TOX; ++i) { - tox_iterate(toxes[i], &tox_index[i]); + tox_iterate(toxes[i], &state[i]); } c_sleep(50); @@ -130,7 +172,8 @@ static void test_many_group(void) const time_t test_start_time = time(nullptr); Tox *toxes[NUM_GROUP_TOX]; - uint32_t tox_index[NUM_GROUP_TOX]; + State state[NUM_GROUP_TOX]; + memset(state, 0, NUM_GROUP_TOX * sizeof(State)); time_t cur_time = time(nullptr); struct Tox_Options *opts = tox_options_new(nullptr); tox_options_set_start_port(opts, 33445); @@ -140,13 +183,18 @@ static void test_many_group(void) for (uint16_t i = 0; i < NUM_GROUP_TOX; ++i) { TOX_ERR_NEW err; - tox_index[i] = i + 1; - toxes[i] = tox_new_log(opts, &err, &tox_index[i]); + state[i].id = i + 1; + toxes[i] = tox_new_log(opts, &err, &state[i]); ck_assert_msg(toxes[i] != nullptr, "failed to create tox instance %u: error %d", i, err); tox_callback_self_connection_status(toxes[i], &handle_self_connection_status); tox_callback_friend_connection_status(toxes[i], &handle_friend_connection_status); tox_callback_conference_invite(toxes[i], &handle_conference_invite); + tox_callback_conference_peer_list_changed(toxes[i], &handle_conference_peer_list_changed); + + char name[NAMELEN + 1]; + snprintf(name, NAMELEN + 1, NAME_FORMAT_STR, state[i].id); + tox_self_set_name(toxes[i], (const uint8_t *)name, NAMELEN, nullptr); if (i != 0) { uint8_t dht_key[TOX_PUBLIC_KEY_SIZE]; @@ -181,11 +229,11 @@ static void test_many_group(void) online_count = 0; for (uint16_t i = 0; i < NUM_GROUP_TOX; ++i) { - tox_iterate(toxes[i], &tox_index[i]); + tox_iterate(toxes[i], &state[i]); online_count += tox_friend_get_connection_status(toxes[i], 0, nullptr) != TOX_CONNECTION_NONE; } - printf("currently %d toxes are online\n", online_count); + printf("currently %u toxes are online\n", online_count); fflush(stdout); c_sleep(1000); @@ -194,40 +242,57 @@ static void test_many_group(void) printf("friends connected, took %d seconds\n", (int)(time(nullptr) - cur_time)); ck_assert_msg(tox_conference_new(toxes[0], nullptr) != UINT32_MAX, "failed to create group"); - printf("tox #%d: inviting its first friend\n", tox_index[0]); + printf("tox #%u: inviting its first friend\n", state[0].id); ck_assert_msg(tox_conference_invite(toxes[0], 0, 0, nullptr) != 0, "failed to invite friend"); + state[0].invited_next = true; ck_assert_msg(tox_conference_set_title(toxes[0], 0, (const uint8_t *)"Gentoo", sizeof("Gentoo") - 1, nullptr) != 0, "failed to set group title"); - // One iteration for all the invitations to happen. - for (uint16_t i = 0; i < NUM_GROUP_TOX; ++i) { - tox_iterate(toxes[i], &tox_index[i]); + + printf("waiting for invitations to be made\n"); + uint16_t invited_count = 0; + + while (invited_count != NUM_GROUP_TOX - 1) { + invited_count = 0; + + for (uint16_t i = 0; i < NUM_GROUP_TOX; ++i) { + tox_iterate(toxes[i], &state[i]); + invited_count += state[i].invited_next; + } + + c_sleep(50); } cur_time = time(nullptr); printf("waiting for all toxes to be in the group\n"); - unsigned invited_count = 0; + uint16_t fully_connected_count = 0; - while (invited_count != NUM_GROUP_TOX) { - invited_count = 0; + while (fully_connected_count != NUM_GROUP_TOX) { + fully_connected_count = 0; printf("current peer counts: ["); for (uint16_t i = 0; i < NUM_GROUP_TOX; ++i) { - tox_iterate(toxes[i], &tox_index[i]); - uint32_t peer_count = tox_conference_peer_count(toxes[i], 0, nullptr); - invited_count += peer_count == NUM_GROUP_TOX; + tox_iterate(toxes[i], &state[i]); + TOX_ERR_CONFERENCE_PEER_QUERY err; + uint32_t peer_count = tox_conference_peer_count(toxes[i], 0, &err); + + if (err != TOX_ERR_CONFERENCE_PEER_QUERY_OK) { + peer_count = 0; + } + + fully_connected_count += peer_count == NUM_GROUP_TOX; if (i != 0) { printf(", "); } - printf("%d", peer_count); + printf("%u", peer_count); } printf("]\n"); fflush(stdout); - c_sleep(1000); + c_sleep(200); } for (uint16_t i = 0; i < NUM_GROUP_TOX; ++i) { @@ -246,7 +311,7 @@ static void test_many_group(void) printf("group connected, took %d seconds\n", (int)(time(nullptr) - cur_time)); - run_conference_tests(toxes, tox_index); + run_conference_tests(toxes, state); printf("tearing down toxes\n"); diff --git a/toxcore/group.c b/toxcore/group.c index 826ea239..317b885f 100644 --- a/toxcore/group.c +++ b/toxcore/group.c @@ -405,8 +405,12 @@ static int connect_to_closest(Group_Chats *g_c, uint32_t groupnumber, void *user get_friendcon_public_keys(real_pk, dht_temp_pk, g_c->fr_c, g->close[i].number); if (!pk_in_closest_peers(g, real_pk)) { - g->close[i].type = GROUPCHAT_CLOSE_NONE; - kill_friend_connection(g_c->fr_c, g->close[i].number); + g->close[i].closest = false; + + if (!g->close[i].introducer && !g->close[i].introduced) { + g->close[i].type = GROUPCHAT_CLOSE_NONE; + kill_friend_connection(g_c->fr_c, g->close[i].number); + } } } @@ -618,6 +622,8 @@ static int setnick(Group_Chats *g_c, uint32_t groupnumber, int peer_index, const return -1; } + g->group[peer_index].nick_updated = true; + /* same name as already stored? */ if (g->group[peer_index].nick_len == nick_len) { if (nick_len == 0 || !memcmp(g->group[peer_index].nick, nick, nick_len)) { @@ -740,7 +746,7 @@ static int add_conn_to_groupchat(Group_Chats *g_c, int friendcon_id, uint32_t gr } if (g->close[i].number == (uint32_t)friendcon_id) { - g->close[i].closest = closest; + g->close[i].closest |= closest; return i; /* Already in list. */ } } @@ -756,6 +762,8 @@ static int add_conn_to_groupchat(Group_Chats *g_c, int friendcon_id, uint32_t gr g->close[ind].type = GROUPCHAT_CLOSE_CONNECTION; g->close[ind].number = friendcon_id; g->close[ind].closest = closest; + g->close[ind].introducer = false; + g->close[ind].introduced = false; // TODO(irungentoo): friend_connection_callbacks(g_c->m->fr_c, friendcon_id, GROUPCHAT_CALLBACK_INDEX, &g_handle_status, &g_handle_packet, &handle_lossy, g_c, friendcon_id); @@ -1062,6 +1070,7 @@ static unsigned int send_lossy_group_peer(Friend_Connections *fr_c, int friendco * return 0 on success. * return -1 if groupnumber is invalid. * return -2 if invite packet failed to send. + * return -3 if we are not connected to the group chat. */ int invite_friend(Group_Chats *g_c, uint32_t friendnumber, uint32_t groupnumber) { @@ -1071,6 +1080,10 @@ int invite_friend(Group_Chats *g_c, uint32_t friendnumber, uint32_t groupnumber) return -1; } + if (g->status != GROUPCHAT_STATUS_CONNECTED) { + return -3; + } + uint8_t invite[INVITE_PACKET_SIZE]; invite[0] = INVITE_ID; uint16_t groupchat_num = net_htons((uint16_t)groupnumber); @@ -1081,7 +1094,6 @@ int invite_friend(Group_Chats *g_c, uint32_t friendnumber, uint32_t groupnumber) return 0; } - wipe_group_chat(g_c, groupnumber); return -2; } @@ -1148,6 +1160,7 @@ int join_groupchat(Group_Chats *g_c, uint32_t friendnumber, uint8_t expected_typ g->close[close_index].group_number = other_groupnum; g->close[close_index].type = GROUPCHAT_CLOSE_ONLINE; g->number_joined = friendcon_id; + g->close[close_index].introducer = true; } send_peer_query(g_c, friendcon_id, other_groupnum); @@ -1503,6 +1516,7 @@ static void handle_friend_invite_packet(Messenger *m, uint32_t friendnumber, con if (close_index != -1) { g->close[close_index].group_number = other_groupnum; g->close[close_index].type = GROUPCHAT_CLOSE_ONLINE; + g->close[close_index].introduced = true; } group_new_peer_send(g_c, groupnum, peer_number, real_pk, temp_pk); @@ -1606,21 +1620,6 @@ static int handle_packet_online(Group_Chats *g_c, int friendcon_id, const uint8_ g->close[index].type = GROUPCHAT_CLOSE_ONLINE; send_packet_online(g_c->fr_c, friendcon_id, groupnumber, g->identifier); - if (g->number_joined != -1 && count_close_connected(g) >= DESIRED_CLOSE_CONNECTIONS) { - int fr_close_index = friend_in_close(g, g->number_joined); - - if (fr_close_index == -1) { - return -1; - } - - if (!g->close[fr_close_index].closest) { - g->close[fr_close_index].type = GROUPCHAT_CLOSE_NONE; - send_peer_kill(g_c, g->close[fr_close_index].number, g->close[fr_close_index].group_number); - kill_friend_connection(g_c->fr_c, g->close[fr_close_index].number); - g->number_joined = -1; - } - } - return 0; } @@ -1729,11 +1728,6 @@ static int handle_send_peers(Group_Chats *g_c, uint32_t groupnumber, const uint8 memcpy(&peer_num, d, sizeof(peer_num)); peer_num = net_ntohs(peer_num); d += sizeof(uint16_t); - int peer_index = addpeer(g_c, groupnumber, d, d + CRYPTO_PUBLIC_KEY_SIZE, peer_num, userdata, true); - - if (peer_index == -1) { - return -1; - } if (g->status == GROUPCHAT_STATUS_VALID && public_key_cmp(d, nc_get_self_public_key(g_c->m->net_crypto)) == 0) { @@ -1742,6 +1736,12 @@ static int handle_send_peers(Group_Chats *g_c, uint32_t groupnumber, const uint8 group_name_send(g_c, groupnumber, g_c->m->name, g_c->m->name_length); } + int peer_index = addpeer(g_c, groupnumber, d, d + CRYPTO_PUBLIC_KEY_SIZE, peer_num, userdata, true); + + if (peer_index == -1) { + return -1; + } + d += CRYPTO_PUBLIC_KEY_SIZE * 2; uint8_t name_length = *d; d += 1; @@ -1750,7 +1750,10 @@ static int handle_send_peers(Group_Chats *g_c, uint32_t groupnumber, const uint8 return -1; } - setnick(g_c, groupnumber, peer_index, d, name_length, userdata, true); + if (!g->group[peer_index].nick_updated) { + setnick(g_c, groupnumber, peer_index, d, name_length, userdata, true); + } + d += name_length; } @@ -2037,6 +2040,58 @@ int send_group_lossy_packet(const Group_Chats *g_c, uint32_t groupnumber, const return 0; } +static Message_Info *find_message_slot_or_reject(uint32_t message_number, uint8_t message_id, Group_Peer *peer) +{ + const bool ignore_older = (message_id == GROUP_MESSAGE_NAME_ID || message_id == GROUP_MESSAGE_TITLE_ID); + + Message_Info *i; + + for (i = peer->last_message_infos; i < peer->last_message_infos + peer->num_last_message_infos; ++i) { + if (message_number > i->message_number) { + break; + } + + if (message_number == i->message_number) { + return nullptr; + } + + if (ignore_older && message_id == i->message_id) { + return nullptr; + } + } + + return i; +} + +/* Stores message info in peer->last_message_infos. + * + * return true if message should be processed; + * return false otherwise. + */ +static bool check_message_info(uint32_t message_number, uint8_t message_id, Group_Peer *peer) +{ + Message_Info *const i = find_message_slot_or_reject(message_number, message_id, peer); + + if (i == nullptr) { + return false; + } + + if (i == peer->last_message_infos + MAX_LAST_MESSAGE_INFOS) { + return false; + } + + if (peer->num_last_message_infos < MAX_LAST_MESSAGE_INFOS) { + ++peer->num_last_message_infos; + } + + memmove(i + 1, i, ((peer->last_message_infos + peer->num_last_message_infos - 1) - i) * sizeof(Message_Info)); + + i->message_number = message_number; + i->message_id = message_id; + + return true; +} + static void handle_message_packet_group(Group_Chats *g_c, uint32_t groupnumber, const uint8_t *data, uint16_t length, int close_index, void *userdata) { @@ -2063,23 +2118,41 @@ static void handle_message_packet_group(Group_Chats *g_c, uint32_t groupnumber, return; } + if (g->number_joined != -1 && count_close_connected(g) >= DESIRED_CLOSE_CONNECTIONS) { + const int fr_close_index = friend_in_close(g, g->number_joined); + + if (fr_close_index >= 0 && fr_close_index != close_index && !g->close[fr_close_index].closest) { + uint8_t real_pk[CRYPTO_PUBLIC_KEY_SIZE]; + get_friendcon_public_keys(real_pk, nullptr, g_c->fr_c, g->close[fr_close_index].number); + + if (id_equal(g->group[index].real_pk, real_pk)) { + /* Received message from peer relayed via another peer, so + * the introduction was successful */ + g->number_joined = -1; + g->close[fr_close_index].introducer = false; + + if (!g->close[fr_close_index].closest && !g->close[fr_close_index].introduced) { + g->close[fr_close_index].type = GROUPCHAT_CLOSE_NONE; + send_peer_kill(g_c, g->close[fr_close_index].number, g->close[fr_close_index].group_number); + kill_friend_connection(g_c->fr_c, g->close[fr_close_index].number); + } + } + } + } + uint32_t message_number; memcpy(&message_number, data + sizeof(uint16_t), sizeof(message_number)); message_number = net_ntohl(message_number); - if (g->group[index].last_message_number == 0) { - g->group[index].last_message_number = message_number; - } else if (message_number - g->group[index].last_message_number > 64 || - message_number == g->group[index].last_message_number) { - return; - } - - g->group[index].last_message_number = message_number; - uint8_t message_id = data[sizeof(uint16_t) + sizeof(message_number)]; const uint8_t *msg_data = data + sizeof(uint16_t) + sizeof(message_number) + 1; uint16_t msg_data_len = length - (sizeof(uint16_t) + sizeof(message_number) + 1); + // FIXME(zugz) update discussion of message numbers in the spec + if (!check_message_info(message_number, message_id, &g->group[index])) { + return; + } + switch (message_id) { case GROUP_MESSAGE_PING_ID: { if (msg_data_len != 0) { diff --git a/toxcore/group.h b/toxcore/group.h index 9b4541c4..970cf7fb 100644 --- a/toxcore/group.h +++ b/toxcore/group.h @@ -39,15 +39,26 @@ typedef enum Groupchat_Type { #define MAX_LOSSY_COUNT 256 +typedef struct Message_Info { + uint32_t message_number; + uint8_t message_id; +} Message_Info; + +#define MAX_LAST_MESSAGE_INFOS 8 + typedef struct Group_Peer { uint8_t real_pk[CRYPTO_PUBLIC_KEY_SIZE]; uint8_t temp_pk[CRYPTO_PUBLIC_KEY_SIZE]; uint64_t last_recv; - uint32_t last_message_number; + + Message_Info + last_message_infos[MAX_LAST_MESSAGE_INFOS]; /* received messages, strictly decreasing in message_number */ + uint8_t num_last_message_infos; uint8_t nick[MAX_NAME_LENGTH]; uint8_t nick_len; + bool nick_updated; uint16_t peer_number; @@ -70,7 +81,9 @@ typedef enum Groupchat_Close_Type { typedef struct Groupchat_Close { uint8_t type; /* GROUPCHAT_CLOSE_* */ - uint8_t closest; + bool closest; /* connected to peer because it is one of our closest peers */ + bool introducer; /* connected to peer because it introduced us to the group */ + bool introduced; /* connected to peer because we introduced it to the group */ uint32_t number; uint16_t group_number; } Groupchat_Close; @@ -91,6 +104,7 @@ typedef struct Group_c { Group_Peer *group; uint32_t numpeers; + /* TODO(zugz) rename close to something more accurate - "connected"? */ Groupchat_Close close[MAX_GROUP_CONNECTIONS]; uint8_t real_pk[CRYPTO_PUBLIC_KEY_SIZE]; diff --git a/toxcore/tox.api.h b/toxcore/tox.api.h index 6cb3145b..7cc58e3b 100644 --- a/toxcore/tox.api.h +++ b/toxcore/tox.api.h @@ -2306,6 +2306,10 @@ namespace conference { * The invite packet failed to send. */ FAIL_SEND, + /** + * The client is not connected to the conference. + */ + NO_CONNECTION, } diff --git a/toxcore/tox.c b/toxcore/tox.c index 101494cc..750a52fa 100644 --- a/toxcore/tox.c +++ b/toxcore/tox.c @@ -1290,6 +1290,10 @@ bool tox_conference_invite(Tox *tox, uint32_t friend_number, uint32_t conference case -2: SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_INVITE_FAIL_SEND); return false; + + case -3: + SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_INVITE_NO_CONNECTION); + return false; } SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_INVITE_OK); diff --git a/toxcore/tox.h b/toxcore/tox.h index 4c83ca23..35ff19e7 100644 --- a/toxcore/tox.h +++ b/toxcore/tox.h @@ -2613,6 +2613,11 @@ typedef enum TOX_ERR_CONFERENCE_INVITE { */ TOX_ERR_CONFERENCE_INVITE_FAIL_SEND, + /** + * The client is not connected to the conference. + */ + TOX_ERR_CONFERENCE_INVITE_NO_CONNECTION, + } TOX_ERR_CONFERENCE_INVITE;