summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorzugz (tox) <mbays+tox@sdf.org>2020-03-14 00:00:00 +0000
committerzugz (tox) <mbays+tox@sdf.org>2020-03-18 00:00:00 +0000
commit94c2a5182bafef9fb8943c02d389723bdbc72752 (patch)
tree0be6142e9c1bf5c105200ed80564becbf939b9b2
parentdb07bda7f7b1ab7f5f219a9ed3d7f732b7da66b0 (diff)
clear out old conference connections
This may fix problems with very large conferences. Sadly, it seems infeasible to test large conferences on one machine, so this is entirely theoretical.
-rw-r--r--toxcore/group.c101
1 files changed, 83 insertions, 18 deletions
diff --git a/toxcore/group.c b/toxcore/group.c
index b4248fd8..3e04f181 100644
--- a/toxcore/group.c
+++ b/toxcore/group.c
@@ -663,28 +663,16 @@ static int addpeer(Group_Chats *g_c, uint32_t groupnumber, const uint8_t *real_p
663 return new_index; 663 return new_index;
664} 664}
665 665
666static bool remove_connection(Group_Chats *g_c, Group_c *g, int friendcon_id) 666static void remove_connection(Group_Chats *g_c, Group_c *g, uint16_t i)
667{ 667{
668 for (uint32_t i = 0; i < MAX_GROUP_CONNECTIONS; ++i) { 668 if (g->connections[i].reasons & GROUPCHAT_CONNECTION_REASON_INTRODUCER) {
669 if (g->connections[i].type == GROUPCHAT_CONNECTION_NONE) { 669 --g->num_introducer_connections;
670 continue;
671 }
672
673 if (g->connections[i].number == (unsigned int)friendcon_id) {
674 if (g->connections[i].reasons & GROUPCHAT_CONNECTION_REASON_INTRODUCER) {
675 --g->num_introducer_connections;
676 }
677
678 g->connections[i].type = GROUPCHAT_CONNECTION_NONE;
679 kill_friend_connection(g_c->fr_c, friendcon_id);
680 return true;
681 }
682 } 670 }
683 671
684 return false; 672 kill_friend_connection(g_c->fr_c, g->connections[i].number);
673 g->connections[i].type = GROUPCHAT_CONNECTION_NONE;
685} 674}
686 675
687
688static void remove_from_closest(Group_c *g, int peer_index) 676static void remove_from_closest(Group_c *g, int peer_index)
689{ 677{
690 for (uint32_t i = 0; i < DESIRED_CLOSEST; ++i) { 678 for (uint32_t i = 0; i < DESIRED_CLOSEST; ++i) {
@@ -715,7 +703,16 @@ static bool delpeer(Group_Chats *g_c, uint32_t groupnumber, int peer_index, void
715 const int friendcon_id = getfriend_conn_id_pk(g_c->fr_c, g->group[peer_index].real_pk); 703 const int friendcon_id = getfriend_conn_id_pk(g_c->fr_c, g->group[peer_index].real_pk);
716 704
717 if (friendcon_id != -1) { 705 if (friendcon_id != -1) {
718 remove_connection(g_c, g, friendcon_id); 706 for (uint32_t i = 0; i < MAX_GROUP_CONNECTIONS; ++i) {
707 if (g->connections[i].type == GROUPCHAT_CONNECTION_NONE) {
708 continue;
709 }
710
711 if (g->connections[i].number == (unsigned int)friendcon_id) {
712 remove_connection(g_c, g, i);
713 break;
714 }
715 }
719 } 716 }
720 717
721 --g->numpeers; 718 --g->numpeers;
@@ -3090,6 +3087,73 @@ static bool groupchat_freeze_timedout(Group_Chats *g_c, uint32_t groupnumber, vo
3090 return true; 3087 return true;
3091} 3088}
3092 3089
3090/* Push non-empty slots to start. */
3091static void squash_connections(Group_c *g)
3092{
3093 uint16_t i = 0;
3094
3095 for (uint16_t j = 0; j < MAX_GROUP_CONNECTIONS; ++j) {
3096 if (g->connections[j].type != GROUPCHAT_CONNECTION_NONE) {
3097 g->connections[i] = g->connections[j];
3098 ++i;
3099 }
3100 }
3101
3102 for (; i < MAX_GROUP_CONNECTIONS; ++i) {
3103 g->connections[i].type = GROUPCHAT_CONNECTION_NONE;
3104 }
3105}
3106
3107#define MIN_EMPTY_CONNECTIONS (1 + MAX_GROUP_CONNECTIONS / 10)
3108
3109/* Remove old connections as necessary to ensure we have space for new
3110 * connections. This invalidates connections array indices (which is
3111 * why we do this periodically rather than on adding a connection).
3112 */
3113static void clean_connections(Group_Chats *g_c, Group_c *g)
3114{
3115 uint16_t to_clear = MIN_EMPTY_CONNECTIONS;
3116
3117 for (uint16_t i = 0; i < MAX_GROUP_CONNECTIONS; ++i) {
3118 if (g->connections[i].type == GROUPCHAT_CONNECTION_NONE) {
3119 --to_clear;
3120
3121 if (to_clear == 0) {
3122 break;
3123 }
3124 }
3125 }
3126
3127 for (; to_clear > 0; --to_clear) {
3128 // Remove a connection. Prefer non-closest connections, and given
3129 // that prefer non-online connections, and given that prefer earlier
3130 // slots.
3131 uint16_t i = 0;
3132
3133 while (i < MAX_GROUP_CONNECTIONS
3134 && (g->connections[i].type != GROUPCHAT_CONNECTION_CONNECTING
3135 || (g->connections[i].reasons & GROUPCHAT_CONNECTION_REASON_CLOSEST))) {
3136 ++i;
3137 }
3138
3139 if (i == MAX_GROUP_CONNECTIONS) {
3140 i = 0;
3141
3142 while (i < MAX_GROUP_CONNECTIONS - to_clear
3143 && (g->connections[i].type != GROUPCHAT_CONNECTION_ONLINE
3144 || (g->connections[i].reasons & GROUPCHAT_CONNECTION_REASON_CLOSEST))) {
3145 ++i;
3146 }
3147 }
3148
3149 if (g->connections[i].type != GROUPCHAT_CONNECTION_NONE) {
3150 remove_connection(g_c, g, i);
3151 }
3152 }
3153
3154 squash_connections(g);
3155}
3156
3093/* Send current name (set in messenger) to all online groups. 3157/* Send current name (set in messenger) to all online groups.
3094 */ 3158 */
3095void send_name_all_groups(Group_Chats *g_c) 3159void send_name_all_groups(Group_Chats *g_c)
@@ -3408,6 +3472,7 @@ void do_groupchats(Group_Chats *g_c, void *userdata)
3408 connect_to_closest(g_c, i, userdata); 3472 connect_to_closest(g_c, i, userdata);
3409 ping_groupchat(g_c, i); 3473 ping_groupchat(g_c, i);
3410 groupchat_freeze_timedout(g_c, i, userdata); 3474 groupchat_freeze_timedout(g_c, i, userdata);
3475 clean_connections(g_c, g);
3411 3476
3412 if (g->need_send_name) { 3477 if (g->need_send_name) {
3413 group_name_send(g_c, i, g_c->m->name, g_c->m->name_length); 3478 group_name_send(g_c, i, g_c->m->name, g_c->m->name_length);