Skip to content

Commit

Permalink
add configurable limit on number of stored frozen peers
Browse files Browse the repository at this point in the history
  • Loading branch information
zugz committed May 19, 2019
1 parent d26b11d commit 306dd1f
Show file tree
Hide file tree
Showing 6 changed files with 178 additions and 7 deletions.
22 changes: 22 additions & 0 deletions auto_tests/conference_test.c
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
#include <time.h>
#include <stdint.h>

#include "../toxcore/util.h"

#include "check_compat.h"

#define NUM_GROUP_TOX 16
Expand Down Expand Up @@ -199,6 +201,18 @@ static void run_conference_tests(Tox **toxes, State *state)
* fails due to disconnections too short to trigger freezing */
const bool check_name_change_propagation = false;

/* each peer should freeze at least its two friends, but freezing more
* should not be necessary */
const uint32_t max_frozen = max_u32(2, NUM_DISCONNECT / 2);
printf("restricting number of frozen peers to %u\n", max_frozen);

for (uint16_t i = 0; i < NUM_GROUP_TOX; ++i) {
Tox_Err_Conference_Set_Max_Offline err;
tox_conference_set_max_offline(toxes[i], 0, max_frozen, &err);
ck_assert_msg(err == TOX_ERR_CONFERENCE_SET_MAX_OFFLINE_OK,
"tox #%u failed to set max offline: err = %d", state[i].index, err);
}

printf("letting random toxes timeout\n");
bool disconnected[NUM_GROUP_TOX] = {0};
bool restarting[NUM_GROUP_TOX] = {0};
Expand Down Expand Up @@ -243,6 +257,7 @@ static void run_conference_tests(Tox **toxes, State *state)
free(save[i]);

set_mono_time_callback(toxes[i], &state[i]);
tox_conference_set_max_offline(toxes[i], 0, max_frozen, nullptr);
}
}

Expand All @@ -256,6 +271,13 @@ static void run_conference_tests(Tox **toxes, State *state)
}
}

for (uint16_t i = 0; i < NUM_GROUP_TOX; ++i) {
const uint32_t num_frozen = tox_conference_offline_peer_count(toxes[i], 0, nullptr);
ck_assert_msg(num_frozen <= max_frozen,
"tox #%u has too many offline peers: %u\n",
state[i].index, num_frozen);
}

printf("reconnecting toxes\n");

do {
Expand Down
100 changes: 93 additions & 7 deletions toxcore/group.c
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,8 @@ static bool realloc_conferences(Group_Chats *g_c, uint16_t num)
static void setup_conference(Group_c *g)
{
memset(g, 0, sizeof(Group_c));

g->maxfrozen = MAX_FROZEN_DEFAULT;
}

/* Create a new empty groupchat connection.
Expand Down Expand Up @@ -644,8 +646,8 @@ static int addpeer(Group_Chats *g_c, uint32_t groupnumber, const uint8_t *real_p
id_copy(g->group[g->numpeers].temp_pk, temp_pk);
g->group[g->numpeers].temp_pk_updated = true;
g->group[g->numpeers].peer_number = peer_number;

g->group[g->numpeers].last_active = mono_time_get(g_c->mono_time);
g->group[g->numpeers].is_friend = (getfriend_id(g_c->m, real_pk) != -1);
++g->numpeers;

add_to_closest(g_c, groupnumber, real_pk, temp_pk);
Expand Down Expand Up @@ -752,6 +754,56 @@ static int delpeer(Group_Chats *g_c, uint32_t groupnumber, int peer_index, void
return 0;
}

static int cmp_u64(uint64_t a, uint64_t b)
{
return (a > b) - (a < b);
}

/* Order peers with friends first and with more recently active earlier */
static int cmp_frozen(const void *a, const void *b)
{
const Group_Peer *pa = (const Group_Peer *) a;
const Group_Peer *pb = (const Group_Peer *) b;

if (pa->is_friend ^ pb->is_friend) {
return pa->is_friend ? -1 : 1;
}

return cmp_u64(pb->last_active, pa->last_active);
}

/* Delete frozen peers as necessary to ensure at most g->maxfrozen remain.
*
* return true if any frozen peers are removed.
*/
static bool delete_old_frozen(Group_c *g)
{
if (g->numfrozen <= g->maxfrozen) {
return false;
}

if (g->maxfrozen == 0) {
free(g->frozen);
g->frozen = nullptr;
g->numfrozen = 0;
return true;
}

qsort(g->frozen, g->numfrozen, sizeof(Group_Peer), cmp_frozen);

Group_Peer *temp = (Group_Peer *)realloc(g->frozen, sizeof(Group_Peer) * g->maxfrozen);

if (temp == nullptr) {
return false;
}

g->frozen = temp;

g->numfrozen = g->maxfrozen;

return true;
}

static bool try_send_rejoin(Group_Chats *g_c, uint32_t groupnumber, const uint8_t *real_pk);

static int freeze_peer(Group_Chats *g_c, uint32_t groupnumber, int peer_index, void *userdata)
Expand All @@ -762,8 +814,6 @@ static int freeze_peer(Group_Chats *g_c, uint32_t groupnumber, int peer_index, v
return -1;
}

try_send_rejoin(g_c, groupnumber, g->group[peer_index].real_pk);

Group_Peer *temp = (Group_Peer *)realloc(g->frozen, sizeof(Group_Peer) * (g->numfrozen + 1));

if (temp == nullptr) {
Expand All @@ -773,9 +823,18 @@ static int freeze_peer(Group_Chats *g_c, uint32_t groupnumber, int peer_index, v
g->frozen = temp;
g->frozen[g->numfrozen] = g->group[peer_index];
g->frozen[g->numfrozen].object = nullptr;

if (delpeer(g_c, groupnumber, peer_index, userdata, true) != 0) {
return -1;
}

try_send_rejoin(g_c, groupnumber, g->frozen[g->numfrozen].real_pk);

++g->numfrozen;

return delpeer(g_c, groupnumber, peer_index, userdata, true);
delete_old_frozen(g);

return 0;
}


Expand Down Expand Up @@ -1236,6 +1295,24 @@ int group_frozen_last_active(const Group_Chats *g_c, uint32_t groupnumber, int p
return 0;
}

/* Set maximum number of frozen peers.
*
* return 0 on success.
* return -1 if groupnumber is invalid.
*/
int group_set_max_frozen(const Group_Chats *g_c, uint32_t groupnumber, uint32_t maxfrozen)
{
Group_c *g = get_group_c(g_c, groupnumber);

if (!g) {
return -1;
}

g->maxfrozen = maxfrozen;
delete_old_frozen(g);
return 0;
}

/* List all the (frozen, if frozen is true) peers in the group chat.
*
* Copies the names of the peers to the name[length][MAX_NAME_LENGTH] array.
Expand Down Expand Up @@ -3208,10 +3285,12 @@ static State_Load_Status load_conferences(Group_Chats *g_c, const uint8_t *data,
lendian_bytes_to_host32(&g->numfrozen, data);
data += sizeof(uint32_t);

g->frozen = (Group_Peer *)malloc(sizeof(Group_Peer) * g->numfrozen);
if (g->numfrozen > 0) {
g->frozen = (Group_Peer *)malloc(sizeof(Group_Peer) * g->numfrozen);

if (g->frozen == nullptr) {
return STATE_LOAD_STATUS_ERROR;
if (g->frozen == nullptr) {
return STATE_LOAD_STATUS_ERROR;
}
}

g->title_len = *data;
Expand Down Expand Up @@ -3252,6 +3331,13 @@ static State_Load_Status load_conferences(Group_Chats *g_c, const uint8_t *data,

memcpy(peer->nick, data, peer->nick_len);
data += peer->nick_len;

// NOTE: this relies on friends being loaded before conferences.
peer->is_friend = (getfriend_id(g_c->m, peer->real_pk) != -1);
}

if (g->numfrozen > g->maxfrozen) {
g->maxfrozen = g->numfrozen;
}

g->status = GROUPCHAT_STATUS_CONNECTED;
Expand Down
13 changes: 13 additions & 0 deletions toxcore/group.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ typedef struct Group_Peer {
uint8_t real_pk[CRYPTO_PUBLIC_KEY_SIZE];
uint8_t temp_pk[CRYPTO_PUBLIC_KEY_SIZE];
bool temp_pk_updated;
bool is_friend;

uint64_t last_active;

Expand Down Expand Up @@ -106,6 +107,9 @@ typedef void peer_on_join_cb(void *object, uint32_t conference_number, uint32_t
typedef void peer_on_leave_cb(void *object, uint32_t conference_number, void *peer_object);
typedef void group_on_delete_cb(void *object, uint32_t conference_number);

// maximum number of frozen peers to store; group_set_max_frozen() overrides.
#define MAX_FROZEN_DEFAULT 128

typedef struct Group_c {
uint8_t status;

Expand All @@ -118,6 +122,8 @@ typedef struct Group_c {
Group_Peer *frozen;
uint32_t numfrozen;

uint32_t maxfrozen;

/* TODO(zugz) rename close to something more accurate - "connected"? */
Groupchat_Close close[MAX_GROUP_CONNECTIONS];

Expand Down Expand Up @@ -284,6 +290,13 @@ int group_peername(const Group_Chats *g_c, uint32_t groupnumber, int peernumber,
int group_frozen_last_active(const Group_Chats *g_c, uint32_t groupnumber, int peernumber,
uint64_t *last_active);

/* Set maximum number of frozen peers.
*
* return 0 on success.
* return -1 if groupnumber is invalid.
*/
int group_set_max_frozen(const Group_Chats *g_c, uint32_t groupnumber, uint32_t maxfrozen);

/* invite friendnumber to groupnumber
*
* return 0 on success.
Expand Down
12 changes: 12 additions & 0 deletions toxcore/tox.api.h
Original file line number Diff line number Diff line change
Expand Up @@ -2374,6 +2374,17 @@ namespace conference {

}

/**
* Set maximum number of offline peers to store, overriding the default.
*/
bool set_max_offline(uint32_t conference_number, uint32_t max_offline_peers) {
/**
* The conference number passed did not designate a valid conference.
*/
CONFERENCE_NOT_FOUND,
}


/**
* Invites a friend to a conference.
*
Expand Down Expand Up @@ -2806,6 +2817,7 @@ typedef TOX_ERR_FILE_SEND_CHUNK Tox_Err_File_Send_Chunk;
typedef TOX_ERR_CONFERENCE_NEW Tox_Err_Conference_New;
typedef TOX_ERR_CONFERENCE_DELETE Tox_Err_Conference_Delete;
typedef TOX_ERR_CONFERENCE_PEER_QUERY Tox_Err_Conference_Peer_Query;
typedef TOX_ERR_CONFERENCE_SET_MAX_OFFLINE Tox_Err_Conference_Set_Max_Offline;
typedef TOX_ERR_CONFERENCE_BY_ID Tox_Err_Conference_By_Id;
typedef TOX_ERR_CONFERENCE_BY_UID Tox_Err_Conference_By_Uid;
typedef TOX_ERR_CONFERENCE_INVITE Tox_Err_Conference_Invite;
Expand Down
16 changes: 16 additions & 0 deletions toxcore/tox.c
Original file line number Diff line number Diff line change
Expand Up @@ -1742,6 +1742,22 @@ uint64_t tox_conference_offline_peer_get_last_active(const Tox *tox, uint32_t co
return last_active;
}

bool tox_conference_set_max_offline(Tox *tox, uint32_t conference_number,
uint32_t max_offline_peers,
Tox_Err_Conference_Set_Max_Offline *error)
{
const Messenger *m = tox->m;
const int ret = group_set_max_frozen(m->conferences_object, conference_number, max_offline_peers);

if (ret == -1) {
SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_SET_MAX_OFFLINE_CONFERENCE_NOT_FOUND);
return false;
}

SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_SET_MAX_OFFLINE_OK);
return true;
}

bool tox_conference_invite(Tox *tox, uint32_t friend_number, uint32_t conference_number,
Tox_Err_Conference_Invite *error)
{
Expand Down
22 changes: 22 additions & 0 deletions toxcore/tox.h
Original file line number Diff line number Diff line change
Expand Up @@ -2673,6 +2673,27 @@ bool tox_conference_offline_peer_get_public_key(const Tox *tox, uint32_t confere
uint64_t tox_conference_offline_peer_get_last_active(const Tox *tox, uint32_t conference_number,
uint32_t offline_peer_number, TOX_ERR_CONFERENCE_PEER_QUERY *error);

typedef enum TOX_ERR_CONFERENCE_SET_MAX_OFFLINE {

/**
* The function returned successfully.
*/
TOX_ERR_CONFERENCE_SET_MAX_OFFLINE_OK,

/**
* The conference number passed did not designate a valid conference.
*/
TOX_ERR_CONFERENCE_SET_MAX_OFFLINE_CONFERENCE_NOT_FOUND,

} TOX_ERR_CONFERENCE_SET_MAX_OFFLINE;


/**
* Set maximum number of offline peers to store, overriding the default.
*/
bool tox_conference_set_max_offline(Tox *tox, uint32_t conference_number, uint32_t max_offline_peers,
TOX_ERR_CONFERENCE_SET_MAX_OFFLINE *error);

typedef enum TOX_ERR_CONFERENCE_INVITE {

/**
Expand Down Expand Up @@ -3191,6 +3212,7 @@ typedef TOX_ERR_FILE_SEND_CHUNK Tox_Err_File_Send_Chunk;
typedef TOX_ERR_CONFERENCE_NEW Tox_Err_Conference_New;
typedef TOX_ERR_CONFERENCE_DELETE Tox_Err_Conference_Delete;
typedef TOX_ERR_CONFERENCE_PEER_QUERY Tox_Err_Conference_Peer_Query;
typedef TOX_ERR_CONFERENCE_SET_MAX_OFFLINE Tox_Err_Conference_Set_Max_Offline;
typedef TOX_ERR_CONFERENCE_BY_ID Tox_Err_Conference_By_Id;
typedef TOX_ERR_CONFERENCE_BY_UID Tox_Err_Conference_By_Uid;
typedef TOX_ERR_CONFERENCE_INVITE Tox_Err_Conference_Invite;
Expand Down

0 comments on commit 306dd1f

Please sign in to comment.