summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorzugz (tox) <mbays+tox@sdf.org>2019-02-17 00:00:00 +0000
committerzugz (tox) <mbays+tox@sdf.org>2019-05-19 18:51:28 +0200
commit306dd1f21f25d65ffd1c289d28e4450695c83745 (patch)
tree89d91af3ef10a29ae8a8a9ead0d5d7ea15619389
parentd26b11d0c263bd796762374154edc7386dd601d4 (diff)
add configurable limit on number of stored frozen peers
-rw-r--r--auto_tests/conference_test.c22
-rw-r--r--toxcore/group.c100
-rw-r--r--toxcore/group.h13
-rw-r--r--toxcore/tox.api.h12
-rw-r--r--toxcore/tox.c16
-rw-r--r--toxcore/tox.h22
6 files changed, 178 insertions, 7 deletions
diff --git a/auto_tests/conference_test.c b/auto_tests/conference_test.c
index 5f08b823..ec88c82a 100644
--- a/auto_tests/conference_test.c
+++ b/auto_tests/conference_test.c
@@ -10,6 +10,8 @@
10#include <time.h> 10#include <time.h>
11#include <stdint.h> 11#include <stdint.h>
12 12
13#include "../toxcore/util.h"
14
13#include "check_compat.h" 15#include "check_compat.h"
14 16
15#define NUM_GROUP_TOX 16 17#define NUM_GROUP_TOX 16
@@ -199,6 +201,18 @@ static void run_conference_tests(Tox **toxes, State *state)
199 * fails due to disconnections too short to trigger freezing */ 201 * fails due to disconnections too short to trigger freezing */
200 const bool check_name_change_propagation = false; 202 const bool check_name_change_propagation = false;
201 203
204 /* each peer should freeze at least its two friends, but freezing more
205 * should not be necessary */
206 const uint32_t max_frozen = max_u32(2, NUM_DISCONNECT / 2);
207 printf("restricting number of frozen peers to %u\n", max_frozen);
208
209 for (uint16_t i = 0; i < NUM_GROUP_TOX; ++i) {
210 Tox_Err_Conference_Set_Max_Offline err;
211 tox_conference_set_max_offline(toxes[i], 0, max_frozen, &err);
212 ck_assert_msg(err == TOX_ERR_CONFERENCE_SET_MAX_OFFLINE_OK,
213 "tox #%u failed to set max offline: err = %d", state[i].index, err);
214 }
215
202 printf("letting random toxes timeout\n"); 216 printf("letting random toxes timeout\n");
203 bool disconnected[NUM_GROUP_TOX] = {0}; 217 bool disconnected[NUM_GROUP_TOX] = {0};
204 bool restarting[NUM_GROUP_TOX] = {0}; 218 bool restarting[NUM_GROUP_TOX] = {0};
@@ -243,6 +257,7 @@ static void run_conference_tests(Tox **toxes, State *state)
243 free(save[i]); 257 free(save[i]);
244 258
245 set_mono_time_callback(toxes[i], &state[i]); 259 set_mono_time_callback(toxes[i], &state[i]);
260 tox_conference_set_max_offline(toxes[i], 0, max_frozen, nullptr);
246 } 261 }
247 } 262 }
248 263
@@ -256,6 +271,13 @@ static void run_conference_tests(Tox **toxes, State *state)
256 } 271 }
257 } 272 }
258 273
274 for (uint16_t i = 0; i < NUM_GROUP_TOX; ++i) {
275 const uint32_t num_frozen = tox_conference_offline_peer_count(toxes[i], 0, nullptr);
276 ck_assert_msg(num_frozen <= max_frozen,
277 "tox #%u has too many offline peers: %u\n",
278 state[i].index, num_frozen);
279 }
280
259 printf("reconnecting toxes\n"); 281 printf("reconnecting toxes\n");
260 282
261 do { 283 do {
diff --git a/toxcore/group.c b/toxcore/group.c
index 20ee5459..f6f8c704 100644
--- a/toxcore/group.c
+++ b/toxcore/group.c
@@ -118,6 +118,8 @@ static bool realloc_conferences(Group_Chats *g_c, uint16_t num)
118static void setup_conference(Group_c *g) 118static void setup_conference(Group_c *g)
119{ 119{
120 memset(g, 0, sizeof(Group_c)); 120 memset(g, 0, sizeof(Group_c));
121
122 g->maxfrozen = MAX_FROZEN_DEFAULT;
121} 123}
122 124
123/* Create a new empty groupchat connection. 125/* Create a new empty groupchat connection.
@@ -644,8 +646,8 @@ static int addpeer(Group_Chats *g_c, uint32_t groupnumber, const uint8_t *real_p
644 id_copy(g->group[g->numpeers].temp_pk, temp_pk); 646 id_copy(g->group[g->numpeers].temp_pk, temp_pk);
645 g->group[g->numpeers].temp_pk_updated = true; 647 g->group[g->numpeers].temp_pk_updated = true;
646 g->group[g->numpeers].peer_number = peer_number; 648 g->group[g->numpeers].peer_number = peer_number;
647
648 g->group[g->numpeers].last_active = mono_time_get(g_c->mono_time); 649 g->group[g->numpeers].last_active = mono_time_get(g_c->mono_time);
650 g->group[g->numpeers].is_friend = (getfriend_id(g_c->m, real_pk) != -1);
649 ++g->numpeers; 651 ++g->numpeers;
650 652
651 add_to_closest(g_c, groupnumber, real_pk, temp_pk); 653 add_to_closest(g_c, groupnumber, real_pk, temp_pk);
@@ -752,6 +754,56 @@ static int delpeer(Group_Chats *g_c, uint32_t groupnumber, int peer_index, void
752 return 0; 754 return 0;
753} 755}
754 756
757static int cmp_u64(uint64_t a, uint64_t b)
758{
759 return (a > b) - (a < b);
760}
761
762/* Order peers with friends first and with more recently active earlier */
763static int cmp_frozen(const void *a, const void *b)
764{
765 const Group_Peer *pa = (const Group_Peer *) a;
766 const Group_Peer *pb = (const Group_Peer *) b;
767
768 if (pa->is_friend ^ pb->is_friend) {
769 return pa->is_friend ? -1 : 1;
770 }
771
772 return cmp_u64(pb->last_active, pa->last_active);
773}
774
775/* Delete frozen peers as necessary to ensure at most g->maxfrozen remain.
776 *
777 * return true if any frozen peers are removed.
778 */
779static bool delete_old_frozen(Group_c *g)
780{
781 if (g->numfrozen <= g->maxfrozen) {
782 return false;
783 }
784
785 if (g->maxfrozen == 0) {
786 free(g->frozen);
787 g->frozen = nullptr;
788 g->numfrozen = 0;
789 return true;
790 }
791
792 qsort(g->frozen, g->numfrozen, sizeof(Group_Peer), cmp_frozen);
793
794 Group_Peer *temp = (Group_Peer *)realloc(g->frozen, sizeof(Group_Peer) * g->maxfrozen);
795
796 if (temp == nullptr) {
797 return false;
798 }
799
800 g->frozen = temp;
801
802 g->numfrozen = g->maxfrozen;
803
804 return true;
805}
806
755static bool try_send_rejoin(Group_Chats *g_c, uint32_t groupnumber, const uint8_t *real_pk); 807static bool try_send_rejoin(Group_Chats *g_c, uint32_t groupnumber, const uint8_t *real_pk);
756 808
757static int freeze_peer(Group_Chats *g_c, uint32_t groupnumber, int peer_index, void *userdata) 809static int freeze_peer(Group_Chats *g_c, uint32_t groupnumber, int peer_index, void *userdata)
@@ -762,8 +814,6 @@ static int freeze_peer(Group_Chats *g_c, uint32_t groupnumber, int peer_index, v
762 return -1; 814 return -1;
763 } 815 }
764 816
765 try_send_rejoin(g_c, groupnumber, g->group[peer_index].real_pk);
766
767 Group_Peer *temp = (Group_Peer *)realloc(g->frozen, sizeof(Group_Peer) * (g->numfrozen + 1)); 817 Group_Peer *temp = (Group_Peer *)realloc(g->frozen, sizeof(Group_Peer) * (g->numfrozen + 1));
768 818
769 if (temp == nullptr) { 819 if (temp == nullptr) {
@@ -773,9 +823,18 @@ static int freeze_peer(Group_Chats *g_c, uint32_t groupnumber, int peer_index, v
773 g->frozen = temp; 823 g->frozen = temp;
774 g->frozen[g->numfrozen] = g->group[peer_index]; 824 g->frozen[g->numfrozen] = g->group[peer_index];
775 g->frozen[g->numfrozen].object = nullptr; 825 g->frozen[g->numfrozen].object = nullptr;
826
827 if (delpeer(g_c, groupnumber, peer_index, userdata, true) != 0) {
828 return -1;
829 }
830
831 try_send_rejoin(g_c, groupnumber, g->frozen[g->numfrozen].real_pk);
832
776 ++g->numfrozen; 833 ++g->numfrozen;
777 834
778 return delpeer(g_c, groupnumber, peer_index, userdata, true); 835 delete_old_frozen(g);
836
837 return 0;
779} 838}
780 839
781 840
@@ -1236,6 +1295,24 @@ int group_frozen_last_active(const Group_Chats *g_c, uint32_t groupnumber, int p
1236 return 0; 1295 return 0;
1237} 1296}
1238 1297
1298/* Set maximum number of frozen peers.
1299 *
1300 * return 0 on success.
1301 * return -1 if groupnumber is invalid.
1302 */
1303int group_set_max_frozen(const Group_Chats *g_c, uint32_t groupnumber, uint32_t maxfrozen)
1304{
1305 Group_c *g = get_group_c(g_c, groupnumber);
1306
1307 if (!g) {
1308 return -1;
1309 }
1310
1311 g->maxfrozen = maxfrozen;
1312 delete_old_frozen(g);
1313 return 0;
1314}
1315
1239/* List all the (frozen, if frozen is true) peers in the group chat. 1316/* List all the (frozen, if frozen is true) peers in the group chat.
1240 * 1317 *
1241 * Copies the names of the peers to the name[length][MAX_NAME_LENGTH] array. 1318 * Copies the names of the peers to the name[length][MAX_NAME_LENGTH] array.
@@ -3208,10 +3285,12 @@ static State_Load_Status load_conferences(Group_Chats *g_c, const uint8_t *data,
3208 lendian_bytes_to_host32(&g->numfrozen, data); 3285 lendian_bytes_to_host32(&g->numfrozen, data);
3209 data += sizeof(uint32_t); 3286 data += sizeof(uint32_t);
3210 3287
3211 g->frozen = (Group_Peer *)malloc(sizeof(Group_Peer) * g->numfrozen); 3288 if (g->numfrozen > 0) {
3289 g->frozen = (Group_Peer *)malloc(sizeof(Group_Peer) * g->numfrozen);
3212 3290
3213 if (g->frozen == nullptr) { 3291 if (g->frozen == nullptr) {
3214 return STATE_LOAD_STATUS_ERROR; 3292 return STATE_LOAD_STATUS_ERROR;
3293 }
3215 } 3294 }
3216 3295
3217 g->title_len = *data; 3296 g->title_len = *data;
@@ -3252,6 +3331,13 @@ static State_Load_Status load_conferences(Group_Chats *g_c, const uint8_t *data,
3252 3331
3253 memcpy(peer->nick, data, peer->nick_len); 3332 memcpy(peer->nick, data, peer->nick_len);
3254 data += peer->nick_len; 3333 data += peer->nick_len;
3334
3335 // NOTE: this relies on friends being loaded before conferences.
3336 peer->is_friend = (getfriend_id(g_c->m, peer->real_pk) != -1);
3337 }
3338
3339 if (g->numfrozen > g->maxfrozen) {
3340 g->maxfrozen = g->numfrozen;
3255 } 3341 }
3256 3342
3257 g->status = GROUPCHAT_STATUS_CONNECTED; 3343 g->status = GROUPCHAT_STATUS_CONNECTED;
diff --git a/toxcore/group.h b/toxcore/group.h
index 83015273..884ac8f5 100644
--- a/toxcore/group.h
+++ b/toxcore/group.h
@@ -50,6 +50,7 @@ typedef struct Group_Peer {
50 uint8_t real_pk[CRYPTO_PUBLIC_KEY_SIZE]; 50 uint8_t real_pk[CRYPTO_PUBLIC_KEY_SIZE];
51 uint8_t temp_pk[CRYPTO_PUBLIC_KEY_SIZE]; 51 uint8_t temp_pk[CRYPTO_PUBLIC_KEY_SIZE];
52 bool temp_pk_updated; 52 bool temp_pk_updated;
53 bool is_friend;
53 54
54 uint64_t last_active; 55 uint64_t last_active;
55 56
@@ -106,6 +107,9 @@ typedef void peer_on_join_cb(void *object, uint32_t conference_number, uint32_t
106typedef void peer_on_leave_cb(void *object, uint32_t conference_number, void *peer_object); 107typedef void peer_on_leave_cb(void *object, uint32_t conference_number, void *peer_object);
107typedef void group_on_delete_cb(void *object, uint32_t conference_number); 108typedef void group_on_delete_cb(void *object, uint32_t conference_number);
108 109
110// maximum number of frozen peers to store; group_set_max_frozen() overrides.
111#define MAX_FROZEN_DEFAULT 128
112
109typedef struct Group_c { 113typedef struct Group_c {
110 uint8_t status; 114 uint8_t status;
111 115
@@ -118,6 +122,8 @@ typedef struct Group_c {
118 Group_Peer *frozen; 122 Group_Peer *frozen;
119 uint32_t numfrozen; 123 uint32_t numfrozen;
120 124
125 uint32_t maxfrozen;
126
121 /* TODO(zugz) rename close to something more accurate - "connected"? */ 127 /* TODO(zugz) rename close to something more accurate - "connected"? */
122 Groupchat_Close close[MAX_GROUP_CONNECTIONS]; 128 Groupchat_Close close[MAX_GROUP_CONNECTIONS];
123 129
@@ -284,6 +290,13 @@ int group_peername(const Group_Chats *g_c, uint32_t groupnumber, int peernumber,
284int group_frozen_last_active(const Group_Chats *g_c, uint32_t groupnumber, int peernumber, 290int group_frozen_last_active(const Group_Chats *g_c, uint32_t groupnumber, int peernumber,
285 uint64_t *last_active); 291 uint64_t *last_active);
286 292
293/* Set maximum number of frozen peers.
294 *
295 * return 0 on success.
296 * return -1 if groupnumber is invalid.
297 */
298int group_set_max_frozen(const Group_Chats *g_c, uint32_t groupnumber, uint32_t maxfrozen);
299
287/* invite friendnumber to groupnumber 300/* invite friendnumber to groupnumber
288 * 301 *
289 * return 0 on success. 302 * return 0 on success.
diff --git a/toxcore/tox.api.h b/toxcore/tox.api.h
index 2e5c7841..51a6d639 100644
--- a/toxcore/tox.api.h
+++ b/toxcore/tox.api.h
@@ -2375,6 +2375,17 @@ namespace conference {
2375 } 2375 }
2376 2376
2377 /** 2377 /**
2378 * Set maximum number of offline peers to store, overriding the default.
2379 */
2380 bool set_max_offline(uint32_t conference_number, uint32_t max_offline_peers) {
2381 /**
2382 * The conference number passed did not designate a valid conference.
2383 */
2384 CONFERENCE_NOT_FOUND,
2385 }
2386
2387
2388 /**
2378 * Invites a friend to a conference. 2389 * Invites a friend to a conference.
2379 * 2390 *
2380 * We must be connected to the conference, meaning that the conference has not 2391 * We must be connected to the conference, meaning that the conference has not
@@ -2806,6 +2817,7 @@ typedef TOX_ERR_FILE_SEND_CHUNK Tox_Err_File_Send_Chunk;
2806typedef TOX_ERR_CONFERENCE_NEW Tox_Err_Conference_New; 2817typedef TOX_ERR_CONFERENCE_NEW Tox_Err_Conference_New;
2807typedef TOX_ERR_CONFERENCE_DELETE Tox_Err_Conference_Delete; 2818typedef TOX_ERR_CONFERENCE_DELETE Tox_Err_Conference_Delete;
2808typedef TOX_ERR_CONFERENCE_PEER_QUERY Tox_Err_Conference_Peer_Query; 2819typedef TOX_ERR_CONFERENCE_PEER_QUERY Tox_Err_Conference_Peer_Query;
2820typedef TOX_ERR_CONFERENCE_SET_MAX_OFFLINE Tox_Err_Conference_Set_Max_Offline;
2809typedef TOX_ERR_CONFERENCE_BY_ID Tox_Err_Conference_By_Id; 2821typedef TOX_ERR_CONFERENCE_BY_ID Tox_Err_Conference_By_Id;
2810typedef TOX_ERR_CONFERENCE_BY_UID Tox_Err_Conference_By_Uid; 2822typedef TOX_ERR_CONFERENCE_BY_UID Tox_Err_Conference_By_Uid;
2811typedef TOX_ERR_CONFERENCE_INVITE Tox_Err_Conference_Invite; 2823typedef TOX_ERR_CONFERENCE_INVITE Tox_Err_Conference_Invite;
diff --git a/toxcore/tox.c b/toxcore/tox.c
index d59094af..0a575dbf 100644
--- a/toxcore/tox.c
+++ b/toxcore/tox.c
@@ -1742,6 +1742,22 @@ uint64_t tox_conference_offline_peer_get_last_active(const Tox *tox, uint32_t co
1742 return last_active; 1742 return last_active;
1743} 1743}
1744 1744
1745bool tox_conference_set_max_offline(Tox *tox, uint32_t conference_number,
1746 uint32_t max_offline_peers,
1747 Tox_Err_Conference_Set_Max_Offline *error)
1748{
1749 const Messenger *m = tox->m;
1750 const int ret = group_set_max_frozen(m->conferences_object, conference_number, max_offline_peers);
1751
1752 if (ret == -1) {
1753 SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_SET_MAX_OFFLINE_CONFERENCE_NOT_FOUND);
1754 return false;
1755 }
1756
1757 SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_SET_MAX_OFFLINE_OK);
1758 return true;
1759}
1760
1745bool tox_conference_invite(Tox *tox, uint32_t friend_number, uint32_t conference_number, 1761bool tox_conference_invite(Tox *tox, uint32_t friend_number, uint32_t conference_number,
1746 Tox_Err_Conference_Invite *error) 1762 Tox_Err_Conference_Invite *error)
1747{ 1763{
diff --git a/toxcore/tox.h b/toxcore/tox.h
index 30ae7187..ad66305f 100644
--- a/toxcore/tox.h
+++ b/toxcore/tox.h
@@ -2673,6 +2673,27 @@ bool tox_conference_offline_peer_get_public_key(const Tox *tox, uint32_t confere
2673uint64_t tox_conference_offline_peer_get_last_active(const Tox *tox, uint32_t conference_number, 2673uint64_t tox_conference_offline_peer_get_last_active(const Tox *tox, uint32_t conference_number,
2674 uint32_t offline_peer_number, TOX_ERR_CONFERENCE_PEER_QUERY *error); 2674 uint32_t offline_peer_number, TOX_ERR_CONFERENCE_PEER_QUERY *error);
2675 2675
2676typedef enum TOX_ERR_CONFERENCE_SET_MAX_OFFLINE {
2677
2678 /**
2679 * The function returned successfully.
2680 */
2681 TOX_ERR_CONFERENCE_SET_MAX_OFFLINE_OK,
2682
2683 /**
2684 * The conference number passed did not designate a valid conference.
2685 */
2686 TOX_ERR_CONFERENCE_SET_MAX_OFFLINE_CONFERENCE_NOT_FOUND,
2687
2688} TOX_ERR_CONFERENCE_SET_MAX_OFFLINE;
2689
2690
2691/**
2692 * Set maximum number of offline peers to store, overriding the default.
2693 */
2694bool tox_conference_set_max_offline(Tox *tox, uint32_t conference_number, uint32_t max_offline_peers,
2695 TOX_ERR_CONFERENCE_SET_MAX_OFFLINE *error);
2696
2676typedef enum TOX_ERR_CONFERENCE_INVITE { 2697typedef enum TOX_ERR_CONFERENCE_INVITE {
2677 2698
2678 /** 2699 /**
@@ -3191,6 +3212,7 @@ typedef TOX_ERR_FILE_SEND_CHUNK Tox_Err_File_Send_Chunk;
3191typedef TOX_ERR_CONFERENCE_NEW Tox_Err_Conference_New; 3212typedef TOX_ERR_CONFERENCE_NEW Tox_Err_Conference_New;
3192typedef TOX_ERR_CONFERENCE_DELETE Tox_Err_Conference_Delete; 3213typedef TOX_ERR_CONFERENCE_DELETE Tox_Err_Conference_Delete;
3193typedef TOX_ERR_CONFERENCE_PEER_QUERY Tox_Err_Conference_Peer_Query; 3214typedef TOX_ERR_CONFERENCE_PEER_QUERY Tox_Err_Conference_Peer_Query;
3215typedef TOX_ERR_CONFERENCE_SET_MAX_OFFLINE Tox_Err_Conference_Set_Max_Offline;
3194typedef TOX_ERR_CONFERENCE_BY_ID Tox_Err_Conference_By_Id; 3216typedef TOX_ERR_CONFERENCE_BY_ID Tox_Err_Conference_By_Id;
3195typedef TOX_ERR_CONFERENCE_BY_UID Tox_Err_Conference_By_Uid; 3217typedef TOX_ERR_CONFERENCE_BY_UID Tox_Err_Conference_By_Uid;
3196typedef TOX_ERR_CONFERENCE_INVITE Tox_Err_Conference_Invite; 3218typedef TOX_ERR_CONFERENCE_INVITE Tox_Err_Conference_Invite;