Skip to content

Commit

Permalink
fix: Allow peers to reconnect to group chats using a password
Browse files Browse the repository at this point in the history
This commit deprecates the tox_group_reconnect groupchat API function and
modifies the tox_group_join function to automatically reconnect to groups
when it's called with a chat_id that designates a group that it's already
a member of.

This allows clients to implement group rejoin functionality that lets peers
rejoin/reconnect to groups with a passed password argument, which may be
necessary if the group password changes while a peer is offline. This fixes
the bug described in #2806.
  • Loading branch information
JFreegman committed Dec 20, 2024
1 parent 11ab1d2 commit fc06506
Show file tree
Hide file tree
Showing 5 changed files with 67 additions and 43 deletions.
6 changes: 3 additions & 3 deletions auto_tests/group_general_test.c
Original file line number Diff line number Diff line change
Expand Up @@ -392,9 +392,9 @@ static void group_announce_test(AutoTox *autotoxes)
ck_assert(s_err == TOX_ERR_GROUP_SELF_STATUS_SET_OK);

fprintf(stderr, "Peer 0 reconnecting...\n");
Tox_Err_Group_Reconnect r_err;
tox_group_reconnect(tox0, groupnumber, &r_err);
ck_assert(r_err == TOX_ERR_GROUP_RECONNECT_OK);
Tox_Err_Group_Join err_rejoin;
tox_group_join(tox0, chat_id, (const uint8_t *)PEER0_NICK, PEER0_NICK_LEN, nullptr, 0, &err_rejoin);
ck_assert(err_rejoin == TOX_ERR_GROUP_JOIN_OK);

while (state1->peer_joined_count != 2 && state0->self_joined_count == 2) {
iterate_all_wait(autotoxes, NUM_GROUP_TOXES, ITERATION_INTERVAL);
Expand Down
91 changes: 55 additions & 36 deletions toxcore/group_chats.c
Original file line number Diff line number Diff line change
Expand Up @@ -7733,10 +7733,52 @@ int gc_group_add(GC_Session *c, Group_Privacy_State privacy_state,
return group_number;
}

int gc_rejoin_group(GC_Session *c, GC_Chat *chat, const uint8_t *passwd, uint16_t passwd_len)
{
if (c == nullptr) {
LOGGER_ERROR(chat->log, "NULL group session pointer.");
return -1;
}

if (passwd != nullptr && passwd_len > 0) {
if (!set_gc_password_local(chat, passwd, passwd_len)) {
LOGGER_WARNING(chat->log, "Failed to set new password during reconnect.");
}
}

chat->time_connected = 0;

if (group_can_handle_packets(chat)) {
send_gc_self_exit(chat, nullptr, 0);
}

for (uint32_t i = 1; i < chat->numpeers; ++i) {
GC_Connection *gconn = get_gc_connection(chat, i);
assert(gconn != nullptr);

gcc_mark_for_deletion(gconn, chat->tcp_conn, GC_EXIT_TYPE_SELF_DISCONNECTED, nullptr, 0);
}

if (is_public_chat(chat)) {
kill_group_friend_connection(c, chat);

if (!m_create_group_connection(c->messenger, chat)) {
LOGGER_WARNING(chat->log, "Failed to create new messenger connection for group");
return -1;
}

chat->update_self_announces = true;
}

chat->connection_state = CS_CONNECTING;

return 0;
}

int gc_group_join(GC_Session *c, const uint8_t *chat_id, const uint8_t *nick, size_t nick_length, const uint8_t *passwd,
uint16_t passwd_len)
{
if (chat_id == nullptr || group_exists(c, chat_id) || getfriend_id(c->messenger, chat_id) != -1) {
if (chat_id == nullptr) {
return -2;
}

Expand All @@ -7748,6 +7790,18 @@ int gc_group_join(GC_Session *c, const uint8_t *chat_id, const uint8_t *nick, si
return -4;
}

GC_Chat *existing_group = gc_get_group_by_public_key(c, chat_id);

// If we're already in the group we try to reconnect to it
if (existing_group != nullptr) {
const int ret = gc_rejoin_group(c, existing_group, passwd, passwd_len);
return ret != 0 ? -6 : ret;
}

if (getfriend_id(c->messenger, chat_id) != -1) {
return -2;
}

const int group_number = create_new_group(c, nick, nick_length, false, GI_PUBLIC);

if (group_number == -1) {
Expand Down Expand Up @@ -7806,41 +7860,6 @@ bool gc_disconnect_from_group(const GC_Session *c, GC_Chat *chat)
return true;
}

int gc_rejoin_group(GC_Session *c, GC_Chat *chat)
{
if (c == nullptr || chat == nullptr) {
return -1;
}

chat->time_connected = 0;

if (group_can_handle_packets(chat)) {
send_gc_self_exit(chat, nullptr, 0);
}

for (uint32_t i = 1; i < chat->numpeers; ++i) {
GC_Connection *gconn = get_gc_connection(chat, i);
assert(gconn != nullptr);

gcc_mark_for_deletion(gconn, chat->tcp_conn, GC_EXIT_TYPE_SELF_DISCONNECTED, nullptr, 0);
}

if (is_public_chat(chat)) {
kill_group_friend_connection(c, chat);

if (!m_create_group_connection(c->messenger, chat)) {
LOGGER_WARNING(chat->log, "Failed to create new messenger connection for group");
return -2;
}

chat->update_self_announces = true;
}

chat->connection_state = CS_CONNECTING;

return 0;
}

bool group_not_added(const GC_Session *c, const uint8_t *chat_id, uint32_t length)
{
if (length < CHAT_ID_SIZE) {
Expand Down
4 changes: 2 additions & 2 deletions toxcore/group_chats.h
Original file line number Diff line number Diff line change
Expand Up @@ -676,8 +676,8 @@ bool gc_disconnect_from_group(const GC_Session *c, GC_Chat *chat);
* Returns -1 if the group handler object or chat object is null.
* Returns -2 if the Messenger friend connection fails to initialize.
*/
non_null()
int gc_rejoin_group(GC_Session *c, GC_Chat *chat);
non_null(1, 2) nullable(3)
int gc_rejoin_group(GC_Session *c, GC_Chat *chat, const uint8_t *passwd, uint16_t passwd_len);

/** @brief Joins a group using the invite data received in a friend's group invite.
*
Expand Down
2 changes: 1 addition & 1 deletion toxcore/tox.c
Original file line number Diff line number Diff line change
Expand Up @@ -3249,7 +3249,7 @@ bool tox_group_reconnect(Tox *tox, uint32_t group_number, Tox_Err_Group_Reconnec
return false;
}

const int ret = gc_rejoin_group(tox->m->group_handler, chat);
const int ret = gc_rejoin_group(tox->m->group_handler, chat, nullptr, 0);
tox_unlock(tox);

switch (ret) {
Expand Down
7 changes: 6 additions & 1 deletion toxcore/tox.h
Original file line number Diff line number Diff line change
Expand Up @@ -3717,12 +3717,15 @@ typedef enum Tox_Err_Group_Join {
const char *tox_err_group_join_to_string(Tox_Err_Group_Join value);

/**
* Joins a group chat with specified Chat ID.
* Joins a group chat with specified Chat ID or reconnects to an existing group.
*
* This function creates a new group chat object, adds it to the chats array,
* and sends a DHT announcement to find peers in the group associated with
* chat_id. Once a peer has been found a join attempt will be initiated.
*
* If a group with the specified Chat ID already exists, this function will attempt
* to reconnect to the group.
*
* @param chat_id The Chat ID of the group you wish to join. This must be
* TOX_GROUP_CHAT_ID_SIZE bytes.
* @param password The password required to join the group. Set to NULL if no
Expand Down Expand Up @@ -3827,6 +3830,8 @@ const char *tox_err_group_reconnect_to_string(Tox_Err_Group_Reconnect value);
* @param group_number The group number of the group we wish to reconnect to.
*
* @return true on success.
*
* @deprecated Use `tox_group_join` instead.
*/
bool tox_group_reconnect(Tox *tox, Tox_Group_Number group_number, Tox_Err_Group_Reconnect *error);

Expand Down

0 comments on commit fc06506

Please sign in to comment.