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:
zugz 2018-07-25 08:46:28 +01:00 committed by zugz (tox)
parent 3a4987da18
commit aa63c1330c
No known key found for this signature in database
GPG Key ID: 6F2BDA289D04F249
7 changed files with 260 additions and 87 deletions

View File

@ -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");
}

View File

@ -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");

View File

@ -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) {

View File

@ -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];

View File

@ -2306,6 +2306,10 @@ namespace conference {
* The invite packet failed to send.
*/
FAIL_SEND,
/**
* The client is not connected to the conference.
*/
NO_CONNECTION,
}

View File

@ -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);

View File

@ -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;