mirror of
https://github.com/irungentoo/toxcore.git
synced 2024-03-22 13:30:51 +08:00
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
This commit is contained in:
parent
3a4987da18
commit
aa63c1330c
|
@ -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");
|
||||
}
|
||||
|
||||
|
|
|
@ -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");
|
||||
|
||||
|
|
141
toxcore/group.c
141
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) {
|
||||
|
|
|
@ -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];
|
||||
|
|
|
@ -2306,6 +2306,10 @@ namespace conference {
|
|||
* The invite packet failed to send.
|
||||
*/
|
||||
FAIL_SEND,
|
||||
/**
|
||||
* The client is not connected to the conference.
|
||||
*/
|
||||
NO_CONNECTION,
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user