summaryrefslogtreecommitdiff
path: root/toxcore
diff options
context:
space:
mode:
authorzugz <mbays+tox@sdf.org>2018-07-25 08:43:48 +0100
committerzugz (tox) <mbays+tox@sdf.org>2018-09-05 20:56:26 +0200
commit1b2322284f0b688af3a349fe4331be15a565084c (patch)
tree7651c11b4ec1edd927151e9655727fb0b2365a7c /toxcore
parent6872c14e1a02445d945623ee6e85230c5d7ecbce (diff)
Add mechanism for recovering from disconnections in conferences
* add freezing and unfreezing of peers * add rejoin packet * revise handling of temporary invited connections * rename "peer kill" packet to "peer leave" packet * test rejoining in conference test * use custom clock in conference test
Diffstat (limited to 'toxcore')
-rw-r--r--toxcore/group.c613
-rw-r--r--toxcore/group.h26
-rw-r--r--toxcore/net_crypto.h1
3 files changed, 489 insertions, 151 deletions
diff --git a/toxcore/group.c b/toxcore/group.c
index 4c77c0d4..c019c0eb 100644
--- a/toxcore/group.c
+++ b/toxcore/group.c
@@ -60,10 +60,10 @@ typedef enum Invite_Id {
60#define ONLINE_PACKET_DATA_SIZE (sizeof(uint16_t) + 1 + GROUP_ID_LENGTH) 60#define ONLINE_PACKET_DATA_SIZE (sizeof(uint16_t) + 1 + GROUP_ID_LENGTH)
61 61
62typedef enum Peer_Id { 62typedef enum Peer_Id {
63 PEER_KILL_ID = 1, 63 PEER_INTRODUCED_ID = 1,
64 PEER_QUERY_ID = 8, 64 PEER_QUERY_ID = 8,
65 PEER_RESPONSE_ID = 9, 65 PEER_RESPONSE_ID = 9,
66 PEER_TITLE_ID = 10, 66 PEER_TITLE_ID = 10,
67} Peer_Id; 67} Peer_Id;
68 68
69#define MIN_MESSAGE_PACKET_LEN (sizeof(uint16_t) * 2 + sizeof(uint32_t) + 1) 69#define MIN_MESSAGE_PACKET_LEN (sizeof(uint16_t) * 2 + sizeof(uint32_t) + 1)
@@ -232,7 +232,7 @@ int32_t conference_by_id(const Group_Chats *g_c, const uint8_t *id)
232/* 232/*
233 * check if peer with peer_number is in peer array. 233 * check if peer with peer_number is in peer array.
234 * 234 *
235 * return peer number if peer is in chat. 235 * return peer index if peer is in chat.
236 * return -1 if peer is not in chat. 236 * return -1 if peer is not in chat.
237 * 237 *
238 * TODO(irungentoo): make this more efficient. 238 * TODO(irungentoo): make this more efficient.
@@ -267,10 +267,6 @@ typedef enum Groupchat_Closest {
267 GROUPCHAT_CLOSEST_REMOVED 267 GROUPCHAT_CLOSEST_REMOVED
268} Groupchat_Closest; 268} Groupchat_Closest;
269 269
270static int friend_in_close(Group_c *g, int friendcon_id);
271static int add_conn_to_groupchat(Group_Chats *g_c, int friendcon_id, uint32_t groupnumber, uint8_t closest,
272 uint8_t lock);
273
274static int add_to_closest(Group_Chats *g_c, uint32_t groupnumber, const uint8_t *real_pk, const uint8_t *temp_pk) 270static int add_to_closest(Group_Chats *g_c, uint32_t groupnumber, const uint8_t *real_pk, const uint8_t *temp_pk)
275{ 271{
276 Group_c *g = get_group_c(g_c, groupnumber); 272 Group_c *g = get_group_c(g_c, groupnumber);
@@ -371,6 +367,11 @@ static unsigned int pk_in_closest_peers(Group_c *g, uint8_t *real_pk)
371 return 0; 367 return 0;
372} 368}
373 369
370static int add_conn_to_groupchat(Group_Chats *g_c, int friendcon_id, uint32_t groupnumber, uint8_t reason,
371 uint8_t lock);
372
373static void remove_conn_reason(Group_Chats *g_c, uint32_t groupnumber, uint16_t i, uint8_t reason);
374
374static int send_packet_online(Friend_Connections *fr_c, int friendcon_id, uint16_t group_num, uint8_t type, 375static int send_packet_online(Friend_Connections *fr_c, int friendcon_id, uint16_t group_num, uint8_t type,
375 uint8_t *id); 376 uint8_t *id);
376 377
@@ -397,7 +398,7 @@ static int connect_to_closest(Group_Chats *g_c, uint32_t groupnumber, void *user
397 continue; 398 continue;
398 } 399 }
399 400
400 if (!g->close[i].closest) { 401 if (!(g->close[i].reasons & GROUPCHAT_CLOSE_REASON_CLOSEST)) {
401 continue; 402 continue;
402 } 403 }
403 404
@@ -406,12 +407,7 @@ static int connect_to_closest(Group_Chats *g_c, uint32_t groupnumber, void *user
406 get_friendcon_public_keys(real_pk, dht_temp_pk, g_c->fr_c, g->close[i].number); 407 get_friendcon_public_keys(real_pk, dht_temp_pk, g_c->fr_c, g->close[i].number);
407 408
408 if (!pk_in_closest_peers(g, real_pk)) { 409 if (!pk_in_closest_peers(g, real_pk)) {
409 g->close[i].closest = false; 410 remove_conn_reason(g_c, groupnumber, i, GROUPCHAT_CLOSE_REASON_CLOSEST);
410
411 if (!g->close[i].introducer && !g->close[i].introduced) {
412 g->close[i].type = GROUPCHAT_CLOSE_NONE;
413 kill_friend_connection(g_c->fr_c, g->close[i].number);
414 }
415 } 411 }
416 } 412 }
417 413
@@ -435,7 +431,7 @@ static int connect_to_closest(Group_Chats *g_c, uint32_t groupnumber, void *user
435 set_dht_temp_pk(g_c->fr_c, friendcon_id, g->closest_peers[i].temp_pk, userdata); 431 set_dht_temp_pk(g_c->fr_c, friendcon_id, g->closest_peers[i].temp_pk, userdata);
436 } 432 }
437 433
438 add_conn_to_groupchat(g_c, friendcon_id, groupnumber, 1, lock); 434 add_conn_to_groupchat(g_c, friendcon_id, groupnumber, GROUPCHAT_CLOSE_REASON_CLOSEST, lock);
439 435
440 if (friend_con_connected(g_c->fr_c, friendcon_id) == FRIENDCONN_STATUS_CONNECTED) { 436 if (friend_con_connected(g_c->fr_c, friendcon_id) == FRIENDCONN_STATUS_CONNECTED) {
441 send_packet_online(g_c->fr_c, friendcon_id, groupnumber, g->type, g->id); 437 send_packet_online(g_c->fr_c, friendcon_id, groupnumber, g->type, g->id);
@@ -447,7 +443,96 @@ static int connect_to_closest(Group_Chats *g_c, uint32_t groupnumber, void *user
447 return 0; 443 return 0;
448} 444}
449 445
450/* Add a peer to the group chat. 446static int get_frozen_index(Group_c *g, uint16_t peer_number)
447{
448 for (uint32_t i = 0; i < g->numfrozen; ++i) {
449 if (g->frozen[i].peer_number == peer_number) {
450 return i;
451 }
452 }
453
454 return -1;
455}
456
457/* Update last_active timestamp on peer, and thaw the peer if it is frozen.
458 *
459 * return peer index if peer is in the conference.
460 * return -1 otherwise, and on error.
461 */
462static int note_peer_active(Group_Chats *g_c, uint32_t groupnumber, uint16_t peer_number, void *userdata)
463{
464 Group_c *g = get_group_c(g_c, groupnumber);
465
466 if (!g) {
467 return -1;
468 }
469
470 const int peer_index = get_peer_index(g, peer_number);
471
472 if (peer_index != -1) {
473 g->group[peer_index].last_active = mono_time_get(g_c->mono_time);
474 return peer_index;
475 }
476
477 const int frozen_index = get_frozen_index(g, peer_number);
478
479 if (frozen_index == -1) {
480 return -1;
481 }
482
483 /* Now thaw the peer */
484
485 Group_Peer *temp = (Group_Peer *)realloc(g->group, sizeof(Group_Peer) * (g->numpeers + 1));
486
487 if (temp == nullptr) {
488 return -1;
489 }
490
491 g->group = temp;
492 g->group[g->numpeers] = g->frozen[frozen_index];
493 g->group[g->numpeers].temp_pk_updated = false;
494 g->group[g->numpeers].last_active = mono_time_get(g_c->mono_time);
495
496 add_to_closest(g_c, groupnumber, g->group[g->numpeers].real_pk, g->group[g->numpeers].temp_pk);
497
498 ++g->numpeers;
499
500 --g->numfrozen;
501
502 if (g->numfrozen == 0) {
503 free(g->frozen);
504 g->frozen = nullptr;
505 } else {
506 if (g->numfrozen != (uint32_t)frozen_index) {
507 g->frozen[frozen_index] = g->frozen[g->numfrozen];
508 }
509
510 Group_Peer *frozen_temp = (Group_Peer *)realloc(g->frozen, sizeof(Group_Peer) * (g->numfrozen));
511
512 if (frozen_temp == nullptr) {
513 return -1;
514 }
515
516 g->frozen = frozen_temp;
517 }
518
519 if (g_c->peer_list_changed_callback) {
520 g_c->peer_list_changed_callback(g_c->m, groupnumber, userdata);
521 }
522
523 if (g->peer_on_join) {
524 g->peer_on_join(g->object, groupnumber, g->numpeers - 1);
525 }
526
527 g->need_send_name = true;
528
529 return g->numpeers - 1;
530}
531
532/* Add a peer to the group chat, or update an existing peer.
533 *
534 * fresh indicates whether we should consider this information on the peer to
535 * be current, and so should update temp_pk and consider the peer active.
451 * 536 *
452 * do_gc_callback indicates whether we want to trigger callbacks set by the client 537 * do_gc_callback indicates whether we want to trigger callbacks set by the client
453 * via the public API. This should be set to false if this function is called 538 * via the public API. This should be set to false if this function is called
@@ -457,7 +542,7 @@ static int connect_to_closest(Group_Chats *g_c, uint32_t groupnumber, void *user
457 * return -1 if error. 542 * return -1 if error.
458 */ 543 */
459static int addpeer(Group_Chats *g_c, uint32_t groupnumber, const uint8_t *real_pk, const uint8_t *temp_pk, 544static int addpeer(Group_Chats *g_c, uint32_t groupnumber, const uint8_t *real_pk, const uint8_t *temp_pk,
460 uint16_t peer_number, void *userdata, bool do_gc_callback) 545 uint16_t peer_number, void *userdata, bool fresh, bool do_gc_callback)
461{ 546{
462 Group_c *g = get_group_c(g_c, groupnumber); 547 Group_c *g = get_group_c(g_c, groupnumber);
463 548
@@ -465,23 +550,35 @@ static int addpeer(Group_Chats *g_c, uint32_t groupnumber, const uint8_t *real_p
465 return -1; 550 return -1;
466 } 551 }
467 552
468 // TODO(irungentoo): 553 const int peer_index = fresh ?
469 int peer_index = peer_in_chat(g, real_pk); 554 note_peer_active(g_c, groupnumber, peer_number, userdata) :
555 get_peer_index(g, peer_number);
470 556
471 if (peer_index != -1) { 557 if (peer_index != -1) {
472 id_copy(g->group[peer_index].temp_pk, temp_pk); 558 if (!id_equal(g->group[peer_index].real_pk, real_pk)) {
473
474 if (g->group[peer_index].peer_number != peer_number) {
475 return -1; 559 return -1;
476 } 560 }
477 561
562 if (fresh || !g->group[peer_index].temp_pk_updated) {
563 id_copy(g->group[peer_index].temp_pk, temp_pk);
564 g->group[peer_index].temp_pk_updated = true;
565 }
566
478 return peer_index; 567 return peer_index;
479 } 568 }
480 569
481 peer_index = get_peer_index(g, peer_number); 570 if (!fresh) {
571 const int frozen_index = get_frozen_index(g, peer_number);
482 572
483 if (peer_index != -1) { 573 if (frozen_index != -1) {
484 return -1; 574 if (!id_equal(g->frozen[frozen_index].real_pk, real_pk)) {
575 return -1;
576 }
577
578 id_copy(g->frozen[frozen_index].temp_pk, temp_pk);
579
580 return -1;
581 }
485 } 582 }
486 583
487 Group_Peer *temp = (Group_Peer *)realloc(g->group, sizeof(Group_Peer) * (g->numpeers + 1)); 584 Group_Peer *temp = (Group_Peer *)realloc(g->group, sizeof(Group_Peer) * (g->numpeers + 1));
@@ -495,9 +592,10 @@ static int addpeer(Group_Chats *g_c, uint32_t groupnumber, const uint8_t *real_p
495 592
496 id_copy(g->group[g->numpeers].real_pk, real_pk); 593 id_copy(g->group[g->numpeers].real_pk, real_pk);
497 id_copy(g->group[g->numpeers].temp_pk, temp_pk); 594 id_copy(g->group[g->numpeers].temp_pk, temp_pk);
595 g->group[g->numpeers].temp_pk_updated = true;
498 g->group[g->numpeers].peer_number = peer_number; 596 g->group[g->numpeers].peer_number = peer_number;
499 597
500 g->group[g->numpeers].last_recv = mono_time_get(g_c->mono_time); 598 g->group[g->numpeers].last_active = mono_time_get(g_c->mono_time);
501 ++g->numpeers; 599 ++g->numpeers;
502 600
503 add_to_closest(g_c, groupnumber, real_pk, temp_pk); 601 add_to_closest(g_c, groupnumber, real_pk, temp_pk);
@@ -539,13 +637,24 @@ static int remove_close_conn(Group_Chats *g_c, uint32_t groupnumber, int friendc
539} 637}
540 638
541 639
640static void remove_from_closest(Group_c *g, int peer_index)
641{
642 for (uint32_t i = 0; i < DESIRED_CLOSE_CONNECTIONS; ++i) {
643 if (g->closest_peers[i].entry && id_equal(g->closest_peers[i].real_pk, g->group[peer_index].real_pk)) {
644 g->closest_peers[i].entry = 0;
645 g->changed = GROUPCHAT_CLOSEST_REMOVED;
646 break;
647 }
648 }
649}
650
542/* 651/*
543 * Delete a peer from the group chat. 652 * Delete a peer from the group chat.
544 * 653 *
545 * return 0 if success 654 * return 0 if success
546 * return -1 if error. 655 * return -1 if error.
547 */ 656 */
548static int delpeer(Group_Chats *g_c, uint32_t groupnumber, int peer_index, void *userdata) 657static int delpeer(Group_Chats *g_c, uint32_t groupnumber, int peer_index, void *userdata, bool keep_connection)
549{ 658{
550 Group_c *g = get_group_c(g_c, groupnumber); 659 Group_c *g = get_group_c(g_c, groupnumber);
551 660
@@ -553,19 +662,11 @@ static int delpeer(Group_Chats *g_c, uint32_t groupnumber, int peer_index, void
553 return -1; 662 return -1;
554 } 663 }
555 664
556 uint32_t i; 665 remove_from_closest(g, peer_index);
557 666
558 for (i = 0; i < DESIRED_CLOSE_CONNECTIONS; ++i) { /* If peer is in closest_peers list, remove it. */ 667 const int friendcon_id = getfriend_conn_id_pk(g_c->fr_c, g->group[peer_index].real_pk);
559 if (g->closest_peers[i].entry && id_equal(g->closest_peers[i].real_pk, g->group[peer_index].real_pk)) {
560 g->closest_peers[i].entry = 0;
561 g->changed = GROUPCHAT_CLOSEST_REMOVED;
562 break;
563 }
564 }
565 668
566 int friendcon_id = getfriend_conn_id_pk(g_c->fr_c, g->group[peer_index].real_pk); 669 if (friendcon_id != -1 && !keep_connection) {
567
568 if (friendcon_id != -1) {
569 remove_close_conn(g_c, groupnumber, friendcon_id); 670 remove_close_conn(g_c, groupnumber, friendcon_id);
570 } 671 }
571 672
@@ -578,7 +679,7 @@ static int delpeer(Group_Chats *g_c, uint32_t groupnumber, int peer_index, void
578 g->group = nullptr; 679 g->group = nullptr;
579 } else { 680 } else {
580 if (g->numpeers != (uint32_t)peer_index) { 681 if (g->numpeers != (uint32_t)peer_index) {
581 memcpy(&g->group[peer_index], &g->group[g->numpeers], sizeof(Group_Peer)); 682 g->group[peer_index] = g->group[g->numpeers];
582 } 683 }
583 684
584 Group_Peer *temp = (Group_Peer *)realloc(g->group, sizeof(Group_Peer) * (g->numpeers)); 685 Group_Peer *temp = (Group_Peer *)realloc(g->group, sizeof(Group_Peer) * (g->numpeers));
@@ -601,6 +702,28 @@ static int delpeer(Group_Chats *g_c, uint32_t groupnumber, int peer_index, void
601 return 0; 702 return 0;
602} 703}
603 704
705static int freeze_peer(Group_Chats *g_c, uint32_t groupnumber, int peer_index, void *userdata)
706{
707 Group_c *g = get_group_c(g_c, groupnumber);
708
709 if (!g) {
710 return -1;
711 }
712
713 Group_Peer *temp = (Group_Peer *)realloc(g->frozen, sizeof(Group_Peer) * (g->numfrozen + 1));
714
715 if (temp == nullptr) {
716 return -1;
717 }
718
719 g->frozen = temp;
720 g->frozen[g->numfrozen] = g->group[peer_index];
721 ++g->numfrozen;
722
723 return delpeer(g_c, groupnumber, peer_index, userdata, true);
724}
725
726
604/* Set the nick for a peer. 727/* Set the nick for a peer.
605 * 728 *
606 * do_gc_callback indicates whether we want to trigger callbacks set by the client 729 * do_gc_callback indicates whether we want to trigger callbacks set by the client
@@ -666,6 +789,8 @@ static int settitle(Group_Chats *g_c, uint32_t groupnumber, int peer_index, cons
666 memcpy(g->title, title, title_len); 789 memcpy(g->title, title, title_len);
667 g->title_len = title_len; 790 g->title_len = title_len;
668 791
792 g->title_fresh = true;
793
669 if (g_c->title_callback) { 794 if (g_c->title_callback) {
670 g_c->title_callback(g_c->m, groupnumber, peer_index, title, title_len, userdata); 795 g_c->title_callback(g_c->m, groupnumber, peer_index, title, title_len, userdata);
671 } 796 }
@@ -673,7 +798,29 @@ static int settitle(Group_Chats *g_c, uint32_t groupnumber, int peer_index, cons
673 return 0; 798 return 0;
674} 799}
675 800
676static void set_conns_type_close(Group_Chats *g_c, uint32_t groupnumber, int friendcon_id, uint8_t type) 801/* Check if the group has no online connection, and freeze all peers if so */
802static void check_disconnected(Group_Chats *g_c, uint32_t groupnumber, void *userdata)
803{
804 Group_c *g = get_group_c(g_c, groupnumber);
805
806 if (!g) {
807 return;
808 }
809
810 for (uint32_t i = 0; i < MAX_GROUP_CONNECTIONS; ++i) {
811 if (g->close[i].type == GROUPCHAT_CLOSE_ONLINE) {
812 return;
813 }
814 }
815
816 for (uint32_t i = 0; i < g->numpeers; ++i) {
817 while (i < g->numpeers && !id_equal(g->group[i].real_pk, g->real_pk)) {
818 freeze_peer(g_c, groupnumber, i, userdata);
819 }
820 }
821}
822
823static void set_conns_type_close(Group_Chats *g_c, uint32_t groupnumber, int friendcon_id, uint8_t type, void *userdata)
677{ 824{
678 Group_c *g = get_group_c(g_c, groupnumber); 825 Group_c *g = get_group_c(g_c, groupnumber);
679 826
@@ -696,14 +843,38 @@ static void set_conns_type_close(Group_Chats *g_c, uint32_t groupnumber, int fri
696 send_packet_online(g_c->fr_c, friendcon_id, groupnumber, g->type, g->id); 843 send_packet_online(g_c->fr_c, friendcon_id, groupnumber, g->type, g->id);
697 } else { 844 } else {
698 g->close[i].type = type; 845 g->close[i].type = type;
846 check_disconnected(g_c, groupnumber, userdata);
699 } 847 }
700 } 848 }
701} 849}
702/* Set the type for all close connections with friendcon_id */ 850/* Set the type for all close connections with friendcon_id */
703static void set_conns_status_groups(Group_Chats *g_c, int friendcon_id, uint8_t type) 851static void set_conns_status_groups(Group_Chats *g_c, int friendcon_id, uint8_t type, void *userdata)
852{
853 for (uint16_t i = 0; i < g_c->num_chats; ++i) {
854 set_conns_type_close(g_c, i, friendcon_id, type, userdata);
855 }
856}
857
858static bool try_send_rejoin(Group_Chats *g_c, uint32_t groupnumber, const uint8_t *real_pk);
859
860static void rejoin_frozen_friend(Group_Chats *g_c, int friendcon_id)
704{ 861{
862 uint8_t real_pk[CRYPTO_PUBLIC_KEY_SIZE];
863 get_friendcon_public_keys(real_pk, nullptr, g_c->fr_c, friendcon_id);
864
705 for (uint16_t i = 0; i < g_c->num_chats; ++i) { 865 for (uint16_t i = 0; i < g_c->num_chats; ++i) {
706 set_conns_type_close(g_c, i, friendcon_id, type); 866 Group_c *g = get_group_c(g_c, i);
867
868 if (!g) {
869 continue;
870 }
871
872 for (uint32_t j = 0; j < g->numfrozen; ++j) {
873 if (id_equal(g->frozen[j].real_pk, real_pk)) {
874 try_send_rejoin(g_c, i, real_pk);
875 break;
876 }
877 }
707 } 878 }
708} 879}
709 880
@@ -712,9 +883,10 @@ static int g_handle_status(void *object, int friendcon_id, uint8_t status, void
712 Group_Chats *g_c = (Group_Chats *)object; 883 Group_Chats *g_c = (Group_Chats *)object;
713 884
714 if (status) { /* Went online */ 885 if (status) { /* Went online */
715 set_conns_status_groups(g_c, friendcon_id, GROUPCHAT_CLOSE_ONLINE); 886 set_conns_status_groups(g_c, friendcon_id, GROUPCHAT_CLOSE_ONLINE, userdata);
887 rejoin_frozen_friend(g_c, friendcon_id);
716 } else { /* Went offline */ 888 } else { /* Went offline */
717 set_conns_status_groups(g_c, friendcon_id, GROUPCHAT_CLOSE_CONNECTION); 889 set_conns_status_groups(g_c, friendcon_id, GROUPCHAT_CLOSE_CONNECTION, userdata);
718 // TODO(irungentoo): remove timedout connections? 890 // TODO(irungentoo): remove timedout connections?
719 } 891 }
720 892
@@ -729,7 +901,7 @@ static int handle_lossy(void *object, int friendcon_id, const uint8_t *data, uin
729 * return close index on success 901 * return close index on success
730 * return -1 on failure. 902 * return -1 on failure.
731 */ 903 */
732static int add_conn_to_groupchat(Group_Chats *g_c, int friendcon_id, uint32_t groupnumber, uint8_t closest, 904static int add_conn_to_groupchat(Group_Chats *g_c, int friendcon_id, uint32_t groupnumber, uint8_t reason,
733 uint8_t lock) 905 uint8_t lock)
734{ 906{
735 Group_c *g = get_group_c(g_c, groupnumber); 907 Group_c *g = get_group_c(g_c, groupnumber);
@@ -738,40 +910,81 @@ static int add_conn_to_groupchat(Group_Chats *g_c, int friendcon_id, uint32_t gr
738 return -1; 910 return -1;
739 } 911 }
740 912
741 uint16_t i, ind = MAX_GROUP_CONNECTIONS; 913 uint16_t empty = MAX_GROUP_CONNECTIONS;
914 uint16_t ind = MAX_GROUP_CONNECTIONS;
742 915
743 for (i = 0; i < MAX_GROUP_CONNECTIONS; ++i) { 916 for (uint16_t i = 0; i < MAX_GROUP_CONNECTIONS; ++i) {
744 if (g->close[i].type == GROUPCHAT_CLOSE_NONE) { 917 if (g->close[i].type == GROUPCHAT_CLOSE_NONE) {
745 ind = i; 918 empty = i;
746 continue; 919 continue;
747 } 920 }
748 921
749 if (g->close[i].number == (uint32_t)friendcon_id) { 922 if (g->close[i].number == (uint32_t)friendcon_id) {
750 g->close[i].closest |= closest; 923 ind = i; /* Already in list. */
751 return i; /* Already in list. */ 924 break;
925 }
926 }
927
928 if (ind == MAX_GROUP_CONNECTIONS && empty != MAX_GROUP_CONNECTIONS) {
929 if (lock) {
930 friend_connection_lock(g_c->fr_c, friendcon_id);
752 } 931 }
932
933 g->close[empty].type = GROUPCHAT_CLOSE_CONNECTION;
934 g->close[empty].number = friendcon_id;
935 g->close[empty].reasons = 0;
936 // TODO(irungentoo):
937 friend_connection_callbacks(g_c->m->fr_c, friendcon_id, GROUPCHAT_CALLBACK_INDEX, &g_handle_status, &g_handle_packet,
938 &handle_lossy, g_c, friendcon_id);
939 ind = empty;
753 } 940 }
754 941
755 if (ind == MAX_GROUP_CONNECTIONS) { 942 if (ind == MAX_GROUP_CONNECTIONS) {
756 return -1; 943 return -1;
757 } 944 }
758 945
759 if (lock) { 946 if (!(g->close[ind].reasons & reason)) {
760 friend_connection_lock(g_c->fr_c, friendcon_id); 947 g->close[ind].reasons |= reason;
761 }
762 948
763 g->close[ind].type = GROUPCHAT_CLOSE_CONNECTION; 949 if (reason == GROUPCHAT_CLOSE_REASON_INTRODUCER) {
764 g->close[ind].number = friendcon_id; 950 ++g->num_introducer_connections;
765 g->close[ind].closest = closest; 951 }
766 g->close[ind].introducer = false; 952 }
767 g->close[ind].introduced = false;
768 // TODO(irungentoo):
769 friend_connection_callbacks(g_c->m->fr_c, friendcon_id, GROUPCHAT_CALLBACK_INDEX, &g_handle_status, &g_handle_packet,
770 &handle_lossy, g_c, friendcon_id);
771 953
772 return ind; 954 return ind;
773} 955}
774 956
957static unsigned int send_peer_introduced(Group_Chats *g_c, int friendcon_id, uint16_t group_num);
958
959/* Removes reason for keeping connection.
960 *
961 * Kills connection if this was the last reason.
962 */
963static void remove_conn_reason(Group_Chats *g_c, uint32_t groupnumber, uint16_t i, uint8_t reason)
964{
965 Group_c *g = get_group_c(g_c, groupnumber);
966
967 if (!g) {
968 return;
969 }
970
971 if (!(g->close[i].reasons & reason)) {
972 return;
973 }
974
975 g->close[i].reasons &= ~reason;
976
977 if (reason == GROUPCHAT_CLOSE_REASON_INTRODUCER) {
978 --g->num_introducer_connections;
979 send_peer_introduced(g_c, g->close[i].number, g->close[i].group_number);
980 }
981
982 if (g->close[i].reasons == 0) {
983 kill_friend_connection(g_c->fr_c, g->close[i].number);
984 g->close[i].type = GROUPCHAT_CLOSE_NONE;
985 }
986}
987
775/* Creates a new groupchat and puts it in the chats array. 988/* Creates a new groupchat and puts it in the chats array.
776 * 989 *
777 * type is one of GROUPCHAT_TYPE_* 990 * type is one of GROUPCHAT_TYPE_*
@@ -781,7 +994,7 @@ static int add_conn_to_groupchat(Group_Chats *g_c, int friendcon_id, uint32_t gr
781 */ 994 */
782int add_groupchat(Group_Chats *g_c, uint8_t type) 995int add_groupchat(Group_Chats *g_c, uint8_t type)
783{ 996{
784 int32_t groupnumber = create_group_chat(g_c); 997 const int32_t groupnumber = create_group_chat(g_c);
785 998
786 if (groupnumber == -1) { 999 if (groupnumber == -1) {
787 return -1; 1000 return -1;
@@ -790,12 +1003,12 @@ int add_groupchat(Group_Chats *g_c, uint8_t type)
790 Group_c *g = &g_c->chats[groupnumber]; 1003 Group_c *g = &g_c->chats[groupnumber];
791 1004
792 g->status = GROUPCHAT_STATUS_CONNECTED; 1005 g->status = GROUPCHAT_STATUS_CONNECTED;
793 g->number_joined = -1;
794 g->type = type; 1006 g->type = type;
795 new_symmetric_key(g->id); 1007 new_symmetric_key(g->id);
796 g->peer_number = 0; /* Founder is peer 0. */ 1008 g->peer_number = 0; /* Founder is peer 0. */
797 memcpy(g->real_pk, nc_get_self_public_key(g_c->m->net_crypto), CRYPTO_PUBLIC_KEY_SIZE); 1009 memcpy(g->real_pk, nc_get_self_public_key(g_c->m->net_crypto), CRYPTO_PUBLIC_KEY_SIZE);
798 int peer_index = addpeer(g_c, groupnumber, g->real_pk, dht_get_self_public_key(g_c->m->dht), 0, nullptr, false); 1010 const int peer_index = addpeer(g_c, groupnumber, g->real_pk, dht_get_self_public_key(g_c->m->dht), 0, nullptr, true,
1011 false);
799 1012
800 if (peer_index == -1) { 1013 if (peer_index == -1) {
801 return -1; 1014 return -1;
@@ -838,6 +1051,7 @@ int del_groupchat(Group_Chats *g_c, uint32_t groupnumber)
838 } 1051 }
839 1052
840 free(g->group); 1053 free(g->group);
1054 free(g->frozen);
841 1055
842 if (g->group_on_delete) { 1056 if (g->group_on_delete) {
843 g->group_on_delete(g->object, groupnumber); 1057 g->group_on_delete(g->object, groupnumber);
@@ -1087,7 +1301,7 @@ int invite_friend(Group_Chats *g_c, uint32_t friendnumber, uint32_t groupnumber)
1087 1301
1088 uint8_t invite[INVITE_PACKET_SIZE]; 1302 uint8_t invite[INVITE_PACKET_SIZE];
1089 invite[0] = INVITE_ID; 1303 invite[0] = INVITE_ID;
1090 uint16_t groupchat_num = net_htons((uint16_t)groupnumber); 1304 const uint16_t groupchat_num = net_htons((uint16_t)groupnumber);
1091 memcpy(invite + 1, &groupchat_num, sizeof(groupchat_num)); 1305 memcpy(invite + 1, &groupchat_num, sizeof(groupchat_num));
1092 invite[1 + sizeof(groupchat_num)] = g->type; 1306 invite[1 + sizeof(groupchat_num)] = g->type;
1093 memcpy(invite + 1 + sizeof(groupchat_num) + 1, g->id, GROUP_ID_LENGTH); 1307 memcpy(invite + 1 + sizeof(groupchat_num) + 1, g->id, GROUP_ID_LENGTH);
@@ -1099,6 +1313,39 @@ int invite_friend(Group_Chats *g_c, uint32_t friendnumber, uint32_t groupnumber)
1099 return -2; 1313 return -2;
1100} 1314}
1101 1315
1316/* Send a rejoin packet to a peer if we have a friend connection to the peer.
1317 * return true if a packet was sent.
1318 * return false otherwise.
1319 */
1320static bool try_send_rejoin(Group_Chats *g_c, uint32_t groupnumber, const uint8_t *real_pk)
1321{
1322 Group_c *g = get_group_c(g_c, groupnumber);
1323
1324 if (!g) {
1325 return false;
1326 }
1327
1328 const int friendcon_id = getfriend_conn_id_pk(g_c->fr_c, real_pk);
1329
1330 if (friendcon_id == -1) {
1331 return false;
1332 }
1333
1334 uint8_t packet[1 + 1 + GROUP_ID_LENGTH];
1335 packet[0] = PACKET_ID_REJOIN_CONFERENCE;
1336 packet[1] = g->type;
1337 memcpy(packet + 2, g->id, GROUP_ID_LENGTH);
1338
1339 if (write_cryptpacket(friendconn_net_crypto(g_c->fr_c), friend_connection_crypt_connection_id(g_c->fr_c, friendcon_id),
1340 packet, sizeof(packet), 0) == -1) {
1341 return false;
1342 }
1343
1344 add_conn_to_groupchat(g_c, friendcon_id, groupnumber, GROUPCHAT_CLOSE_REASON_INTRODUCER, 1);
1345
1346 return true;
1347}
1348
1102static unsigned int send_peer_query(Group_Chats *g_c, int friendcon_id, uint16_t group_num); 1349static unsigned int send_peer_query(Group_Chats *g_c, int friendcon_id, uint16_t group_num);
1103 1350
1104/* Join a group (you need to have been invited first.) 1351/* Join a group (you need to have been invited first.)
@@ -1123,7 +1370,7 @@ int join_groupchat(Group_Chats *g_c, uint32_t friendnumber, uint8_t expected_typ
1123 return -2; 1370 return -2;
1124 } 1371 }
1125 1372
1126 int friendcon_id = getfriendcon_id(g_c->m, friendnumber); 1373 const int friendcon_id = getfriendcon_id(g_c->m, friendnumber);
1127 1374
1128 if (friendcon_id == -1) { 1375 if (friendcon_id == -1) {
1129 return -3; 1376 return -3;
@@ -1133,7 +1380,7 @@ int join_groupchat(Group_Chats *g_c, uint32_t friendnumber, uint8_t expected_typ
1133 return -4; 1380 return -4;
1134 } 1381 }
1135 1382
1136 int groupnumber = create_group_chat(g_c); 1383 const int groupnumber = create_group_chat(g_c);
1137 1384
1138 if (groupnumber == -1) { 1385 if (groupnumber == -1) {
1139 return -5; 1386 return -5;
@@ -1141,9 +1388,8 @@ int join_groupchat(Group_Chats *g_c, uint32_t friendnumber, uint8_t expected_typ
1141 1388
1142 Group_c *g = &g_c->chats[groupnumber]; 1389 Group_c *g = &g_c->chats[groupnumber];
1143 1390
1144 uint16_t group_num = net_htons(groupnumber); 1391 const uint16_t group_num = net_htons(groupnumber);
1145 g->status = GROUPCHAT_STATUS_VALID; 1392 g->status = GROUPCHAT_STATUS_VALID;
1146 g->number_joined = -1;
1147 memcpy(g->real_pk, nc_get_self_public_key(g_c->m->net_crypto), CRYPTO_PUBLIC_KEY_SIZE); 1393 memcpy(g->real_pk, nc_get_self_public_key(g_c->m->net_crypto), CRYPTO_PUBLIC_KEY_SIZE);
1148 1394
1149 uint8_t response[INVITE_RESPONSE_PACKET_SIZE]; 1395 uint8_t response[INVITE_RESPONSE_PACKET_SIZE];
@@ -1157,13 +1403,11 @@ int join_groupchat(Group_Chats *g_c, uint32_t friendnumber, uint8_t expected_typ
1157 other_groupnum = net_ntohs(other_groupnum); 1403 other_groupnum = net_ntohs(other_groupnum);
1158 g->type = data[sizeof(uint16_t)]; 1404 g->type = data[sizeof(uint16_t)];
1159 memcpy(g->id, data + sizeof(uint16_t) + 1, GROUP_ID_LENGTH); 1405 memcpy(g->id, data + sizeof(uint16_t) + 1, GROUP_ID_LENGTH);
1160 int close_index = add_conn_to_groupchat(g_c, friendcon_id, groupnumber, 0, 1); 1406 const int close_index = add_conn_to_groupchat(g_c, friendcon_id, groupnumber, GROUPCHAT_CLOSE_REASON_INTRODUCER, 1);
1161 1407
1162 if (close_index != -1) { 1408 if (close_index != -1) {
1163 g->close[close_index].group_number = other_groupnum; 1409 g->close[close_index].group_number = other_groupnum;
1164 g->close[close_index].type = GROUPCHAT_CLOSE_ONLINE; 1410 g->close[close_index].type = GROUPCHAT_CLOSE_ONLINE;
1165 g->number_joined = friendcon_id;
1166 g->close[close_index].introducer = true;
1167 } 1411 }
1168 1412
1169 send_peer_query(g_c, friendcon_id, other_groupnum); 1413 send_peer_query(g_c, friendcon_id, other_groupnum);
@@ -1420,6 +1664,25 @@ int group_title_get(const Group_Chats *g_c, uint32_t groupnumber, uint8_t *title
1420 return g->title_len; 1664 return g->title_len;
1421} 1665}
1422 1666
1667static bool get_peer_number(const Group_c *g, const uint8_t *real_pk, uint16_t *peer_number)
1668{
1669 const int peer_index = peer_in_chat(g, real_pk);
1670
1671 if (peer_index >= 0) {
1672 *peer_number = g->group[peer_index].peer_number;
1673 return true;
1674 }
1675
1676 for (uint32_t i = 0; i < g->numfrozen; ++i) {
1677 if (id_equal(g->frozen[i].real_pk, real_pk)) {
1678 *peer_number = g->frozen[i].peer_number;
1679 return true;
1680 }
1681 }
1682
1683 return false;
1684}
1685
1423static void handle_friend_invite_packet(Messenger *m, uint32_t friendnumber, const uint8_t *data, uint16_t length, 1686static void handle_friend_invite_packet(Messenger *m, uint32_t friendnumber, const uint8_t *data, uint16_t length,
1424 void *userdata) 1687 void *userdata)
1425{ 1688{
@@ -1430,7 +1693,7 @@ static void handle_friend_invite_packet(Messenger *m, uint32_t friendnumber, con
1430 } 1693 }
1431 1694
1432 const uint8_t *invite_data = data + 1; 1695 const uint8_t *invite_data = data + 1;
1433 uint16_t invite_length = length - 1; 1696 const uint16_t invite_length = length - 1;
1434 1697
1435 switch (data[0]) { 1698 switch (data[0]) {
1436 case INVITE_ID: { 1699 case INVITE_ID: {
@@ -1438,7 +1701,7 @@ static void handle_friend_invite_packet(Messenger *m, uint32_t friendnumber, con
1438 return; 1701 return;
1439 } 1702 }
1440 1703
1441 int groupnumber = get_group_num(g_c, data[1 + sizeof(uint16_t)], data + 1 + sizeof(uint16_t) + 1); 1704 const int groupnumber = get_group_num(g_c, data[1 + sizeof(uint16_t)], data + 1 + sizeof(uint16_t) + 1);
1442 1705
1443 if (groupnumber == -1) { 1706 if (groupnumber == -1) {
1444 if (g_c->invite_callback) { 1707 if (g_c->invite_callback) {
@@ -1480,7 +1743,7 @@ static void handle_friend_invite_packet(Messenger *m, uint32_t friendnumber, con
1480 1743
1481 unsigned int tries = 0; 1744 unsigned int tries = 0;
1482 1745
1483 while (get_peer_index(g, peer_number) != -1) { 1746 while (get_peer_index(g, peer_number) != -1 || get_frozen_index(g, peer_number) != -1) {
1484 peer_number = random_u16(); 1747 peer_number = random_u16();
1485 ++tries; 1748 ++tries;
1486 1749
@@ -1502,19 +1765,19 @@ static void handle_friend_invite_packet(Messenger *m, uint32_t friendnumber, con
1502 uint8_t real_pk[CRYPTO_PUBLIC_KEY_SIZE], temp_pk[CRYPTO_PUBLIC_KEY_SIZE]; 1765 uint8_t real_pk[CRYPTO_PUBLIC_KEY_SIZE], temp_pk[CRYPTO_PUBLIC_KEY_SIZE];
1503 get_friendcon_public_keys(real_pk, temp_pk, g_c->fr_c, friendcon_id); 1766 get_friendcon_public_keys(real_pk, temp_pk, g_c->fr_c, friendcon_id);
1504 1767
1505 addpeer(g_c, groupnum, real_pk, temp_pk, peer_number, userdata, true); 1768 addpeer(g_c, groupnum, real_pk, temp_pk, peer_number, userdata, true, true);
1506 int close_index = add_conn_to_groupchat(g_c, friendcon_id, groupnum, 0, 1); 1769 const int close_index = add_conn_to_groupchat(g_c, friendcon_id, groupnum, GROUPCHAT_CLOSE_REASON_INTRODUCING, 1);
1507 1770
1508 if (close_index != -1) { 1771 if (close_index != -1) {
1509 g->close[close_index].group_number = other_groupnum; 1772 g->close[close_index].group_number = other_groupnum;
1510 g->close[close_index].type = GROUPCHAT_CLOSE_ONLINE; 1773 g->close[close_index].type = GROUPCHAT_CLOSE_ONLINE;
1511 g->close[close_index].introduced = true;
1512 } 1774 }
1513 1775
1514 group_new_peer_send(g_c, groupnum, peer_number, real_pk, temp_pk); 1776 group_new_peer_send(g_c, groupnum, peer_number, real_pk, temp_pk);
1515 break; 1777 break;
1516 } 1778 }
1517 1779
1780
1518 default: 1781 default:
1519 return; 1782 return;
1520 } 1783 }
@@ -1572,7 +1835,7 @@ static int send_packet_online(Friend_Connections *fr_c, int friendcon_id, uint16
1572 sizeof(packet), 0) != -1; 1835 sizeof(packet), 0) != -1;
1573} 1836}
1574 1837
1575static unsigned int send_peer_kill(Group_Chats *g_c, int friendcon_id, uint16_t group_num); 1838static int ping_groupchat(Group_Chats *g_c, uint32_t groupnumber);
1576 1839
1577static int handle_packet_online(Group_Chats *g_c, int friendcon_id, const uint8_t *data, uint16_t length) 1840static int handle_packet_online(Group_Chats *g_c, int friendcon_id, const uint8_t *data, uint16_t length)
1578{ 1841{
@@ -1580,7 +1843,7 @@ static int handle_packet_online(Group_Chats *g_c, int friendcon_id, const uint8_
1580 return -1; 1843 return -1;
1581 } 1844 }
1582 1845
1583 int groupnumber = get_group_num(g_c, data[sizeof(uint16_t)], data + sizeof(uint16_t) + 1); 1846 const int groupnumber = get_group_num(g_c, data[sizeof(uint16_t)], data + sizeof(uint16_t) + 1);
1584 1847
1585 if (groupnumber == -1) { 1848 if (groupnumber == -1) {
1586 return -1; 1849 return -1;
@@ -1596,7 +1859,7 @@ static int handle_packet_online(Group_Chats *g_c, int friendcon_id, const uint8_
1596 return -1; 1859 return -1;
1597 } 1860 }
1598 1861
1599 int index = friend_in_close(g, friendcon_id); 1862 const int index = friend_in_close(g, friendcon_id);
1600 1863
1601 if (index == -1) { 1864 if (index == -1) {
1602 return -1; 1865 return -1;
@@ -1606,7 +1869,7 @@ static int handle_packet_online(Group_Chats *g_c, int friendcon_id, const uint8_
1606 return -1; 1869 return -1;
1607 } 1870 }
1608 1871
1609 if (count_close_connected(g) == 0) { 1872 if (count_close_connected(g) == 0 || (g->close[index].reasons & GROUPCHAT_CLOSE_REASON_INTRODUCER)) {
1610 send_peer_query(g_c, friendcon_id, other_groupnum); 1873 send_peer_query(g_c, friendcon_id, other_groupnum);
1611 } 1874 }
1612 1875
@@ -1614,18 +1877,68 @@ static int handle_packet_online(Group_Chats *g_c, int friendcon_id, const uint8_
1614 g->close[index].type = GROUPCHAT_CLOSE_ONLINE; 1877 g->close[index].type = GROUPCHAT_CLOSE_ONLINE;
1615 send_packet_online(g_c->fr_c, friendcon_id, groupnumber, g->type, g->id); 1878 send_packet_online(g_c->fr_c, friendcon_id, groupnumber, g->type, g->id);
1616 1879
1880 if (g->close[index].reasons & GROUPCHAT_CLOSE_REASON_INTRODUCING) {
1881 uint8_t real_pk[CRYPTO_PUBLIC_KEY_SIZE], temp_pk[CRYPTO_PUBLIC_KEY_SIZE];
1882 get_friendcon_public_keys(real_pk, temp_pk, g_c->fr_c, friendcon_id);
1883
1884 const int peer_index = peer_in_chat(g, real_pk);
1885
1886 if (peer_index != -1) {
1887 group_new_peer_send(g_c, groupnumber, g->group[peer_index].peer_number, real_pk, temp_pk);
1888 }
1889
1890 g->need_send_name = true;
1891 }
1892
1893 ping_groupchat(g_c, groupnumber);
1894
1617 return 0; 1895 return 0;
1618} 1896}
1619 1897
1898static int handle_packet_rejoin(Group_Chats *g_c, int friendcon_id, const uint8_t *data, uint16_t length,
1899 void *userdata)
1900{
1901 if (length < 1 + GROUP_ID_LENGTH) {
1902 return -1;
1903 }
1904
1905 const int32_t groupnum = get_group_num(g_c, *data, data + 1);
1906
1907 Group_c *g = get_group_c(g_c, groupnum);
1908
1909 if (!g) {
1910 return -1;
1911 }
1912
1913 uint8_t real_pk[CRYPTO_PUBLIC_KEY_SIZE], temp_pk[CRYPTO_PUBLIC_KEY_SIZE];
1914 get_friendcon_public_keys(real_pk, temp_pk, g_c->fr_c, friendcon_id);
1915
1916 uint16_t peer_number;
1917
1918 if (!get_peer_number(g, real_pk, &peer_number)) {
1919 return -1;
1920 }
1921
1922 addpeer(g_c, groupnum, real_pk, temp_pk, peer_number, userdata, true, true);
1923 const int close_index = add_conn_to_groupchat(g_c, friendcon_id, groupnum, GROUPCHAT_CLOSE_REASON_INTRODUCING, 1);
1924
1925 if (close_index != -1) {
1926 send_packet_online(g_c->fr_c, friendcon_id, groupnum, g->type, g->id);
1927 }
1928
1929 return 0;
1930}
1931
1932
1620// we could send title with invite, but then if it changes between sending and accepting inv, joinee won't see it 1933// we could send title with invite, but then if it changes between sending and accepting inv, joinee won't see it
1621 1934
1622/* return 1 on success. 1935/* return 1 on success.
1623 * return 0 on failure 1936 * return 0 on failure
1624 */ 1937 */
1625static unsigned int send_peer_kill(Group_Chats *g_c, int friendcon_id, uint16_t group_num) 1938static unsigned int send_peer_introduced(Group_Chats *g_c, int friendcon_id, uint16_t group_num)
1626{ 1939{
1627 uint8_t packet[1]; 1940 uint8_t packet[1];
1628 packet[0] = PEER_KILL_ID; 1941 packet[0] = PEER_INTRODUCED_ID;
1629 return send_packet_group_peer(g_c->fr_c, friendcon_id, PACKET_ID_DIRECT_CONFERENCE, group_num, packet, sizeof(packet)); 1942 return send_packet_group_peer(g_c->fr_c, friendcon_id, PACKET_ID_DIRECT_CONFERENCE, group_num, packet, sizeof(packet));
1630} 1943}
1631 1944
@@ -1671,7 +1984,7 @@ static unsigned int send_peers(Group_Chats *g_c, uint32_t groupnumber, int frien
1671 p = response_packet + 1; 1984 p = response_packet + 1;
1672 } 1985 }
1673 1986
1674 uint16_t peer_num = net_htons(g->group[i].peer_number); 1987 const uint16_t peer_num = net_htons(g->group[i].peer_number);
1675 memcpy(p, &peer_num, sizeof(peer_num)); 1988 memcpy(p, &peer_num, sizeof(peer_num));
1676 p += sizeof(peer_num); 1989 p += sizeof(peer_num);
1677 memcpy(p, g->group[i].real_pk, CRYPTO_PUBLIC_KEY_SIZE); 1990 memcpy(p, g->group[i].real_pk, CRYPTO_PUBLIC_KEY_SIZE);
@@ -1732,17 +2045,17 @@ static int handle_send_peers(Group_Chats *g_c, uint32_t groupnumber, const uint8
1732 g_c->connected_callback(g_c->m, groupnumber, userdata); 2045 g_c->connected_callback(g_c->m, groupnumber, userdata);
1733 } 2046 }
1734 2047
1735 group_name_send(g_c, groupnumber, g_c->m->name, g_c->m->name_length); 2048 g->need_send_name = true;
1736 } 2049 }
1737 2050
1738 int peer_index = addpeer(g_c, groupnumber, d, d + CRYPTO_PUBLIC_KEY_SIZE, peer_num, userdata, true); 2051 const int peer_index = addpeer(g_c, groupnumber, d, d + CRYPTO_PUBLIC_KEY_SIZE, peer_num, userdata, false, true);
1739 2052
1740 if (peer_index == -1) { 2053 if (peer_index == -1) {
1741 return -1; 2054 return -1;
1742 } 2055 }
1743 2056
1744 d += CRYPTO_PUBLIC_KEY_SIZE * 2; 2057 d += CRYPTO_PUBLIC_KEY_SIZE * 2;
1745 uint8_t name_length = *d; 2058 const uint8_t name_length = *d;
1746 d += 1; 2059 d += 1;
1747 2060
1748 if (name_length > (length - (d - data)) || name_length > MAX_NAME_LENGTH) { 2061 if (name_length > (length - (d - data)) || name_length > MAX_NAME_LENGTH) {
@@ -1767,17 +2080,14 @@ static void handle_direct_packet(Group_Chats *g_c, uint32_t groupnumber, const u
1767 } 2080 }
1768 2081
1769 switch (data[0]) { 2082 switch (data[0]) {
1770 case PEER_KILL_ID: { 2083 case PEER_INTRODUCED_ID: {
1771 Group_c *g = get_group_c(g_c, groupnumber); 2084 Group_c *g = get_group_c(g_c, groupnumber);
1772 2085
1773 if (!g) { 2086 if (!g) {
1774 return; 2087 return;
1775 } 2088 }
1776 2089
1777 if (!g->close[close_index].closest) { 2090 remove_conn_reason(g_c, groupnumber, close_index, GROUPCHAT_CLOSE_REASON_INTRODUCING);
1778 g->close[close_index].type = GROUPCHAT_CLOSE_NONE;
1779 kill_friend_connection(g_c->fr_c, g->close[close_index].number);
1780 }
1781 } 2091 }
1782 2092
1783 break; 2093 break;
@@ -1801,7 +2111,15 @@ static void handle_direct_packet(Group_Chats *g_c, uint32_t groupnumber, const u
1801 break; 2111 break;
1802 2112
1803 case PEER_TITLE_ID: { 2113 case PEER_TITLE_ID: {
1804 settitle(g_c, groupnumber, -1, data + 1, length - 1, userdata); 2114 Group_c *g = get_group_c(g_c, groupnumber);
2115
2116 if (!g) {
2117 break;
2118 }
2119
2120 if (!g->title_fresh) {
2121 settitle(g_c, groupnumber, -1, data + 1, length - 1, userdata);
2122 }
1805 } 2123 }
1806 2124
1807 break; 2125 break;
@@ -1868,7 +2186,7 @@ static unsigned int send_lossy_all_close(const Group_Chats *g_c, uint32_t groupn
1868 continue; 2186 continue;
1869 } 2187 }
1870 2188
1871 if (g->close[i].closest) { 2189 if (g->close[i].reasons & GROUPCHAT_CLOSE_REASON_CLOSEST) {
1872 connected_closest[num_connected_closest] = i; 2190 connected_closest[num_connected_closest] = i;
1873 ++num_connected_closest; 2191 ++num_connected_closest;
1874 continue; 2192 continue;
@@ -1891,7 +2209,7 @@ static unsigned int send_lossy_all_close(const Group_Chats *g_c, uint32_t groupn
1891 uint8_t real_pk[CRYPTO_PUBLIC_KEY_SIZE] = {0}; 2209 uint8_t real_pk[CRYPTO_PUBLIC_KEY_SIZE] = {0};
1892 uint8_t dht_temp_pk[CRYPTO_PUBLIC_KEY_SIZE] = {0}; 2210 uint8_t dht_temp_pk[CRYPTO_PUBLIC_KEY_SIZE] = {0};
1893 get_friendcon_public_keys(real_pk, dht_temp_pk, g_c->fr_c, g->close[connected_closest[i]].number); 2211 get_friendcon_public_keys(real_pk, dht_temp_pk, g_c->fr_c, g->close[connected_closest[i]].number);
1894 uint64_t comp_val = calculate_comp_value(g->real_pk, real_pk); 2212 const uint64_t comp_val = calculate_comp_value(g->real_pk, real_pk);
1895 2213
1896 if (comp_val < comp_val_old) { 2214 if (comp_val < comp_val_old) {
1897 to_send = connected_closest[i]; 2215 to_send = connected_closest[i];
@@ -1911,7 +2229,7 @@ static unsigned int send_lossy_all_close(const Group_Chats *g_c, uint32_t groupn
1911 uint8_t real_pk[CRYPTO_PUBLIC_KEY_SIZE] = {0}; 2229 uint8_t real_pk[CRYPTO_PUBLIC_KEY_SIZE] = {0};
1912 uint8_t dht_temp_pk[CRYPTO_PUBLIC_KEY_SIZE] = {0}; 2230 uint8_t dht_temp_pk[CRYPTO_PUBLIC_KEY_SIZE] = {0};
1913 get_friendcon_public_keys(real_pk, dht_temp_pk, g_c->fr_c, g->close[connected_closest[i]].number); 2231 get_friendcon_public_keys(real_pk, dht_temp_pk, g_c->fr_c, g->close[connected_closest[i]].number);
1914 uint64_t comp_val = calculate_comp_value(real_pk, g->real_pk); 2232 const uint64_t comp_val = calculate_comp_value(real_pk, g->real_pk);
1915 2233
1916 if (comp_val < comp_val_old) { 2234 if (comp_val < comp_val_old) {
1917 to_send_other = connected_closest[i]; 2235 to_send_other = connected_closest[i];
@@ -1957,7 +2275,7 @@ static int send_message_group(const Group_Chats *g_c, uint32_t groupnumber, uint
1957 } 2275 }
1958 2276
1959 VLA(uint8_t, packet, sizeof(uint16_t) + sizeof(uint32_t) + 1 + len); 2277 VLA(uint8_t, packet, sizeof(uint16_t) + sizeof(uint32_t) + 1 + len);
1960 uint16_t peer_num = net_htons(g->peer_number); 2278 const uint16_t peer_num = net_htons(g->peer_number);
1961 memcpy(packet, &peer_num, sizeof(peer_num)); 2279 memcpy(packet, &peer_num, sizeof(peer_num));
1962 2280
1963 ++g->message_number; 2281 ++g->message_number;
@@ -1966,7 +2284,7 @@ static int send_message_group(const Group_Chats *g_c, uint32_t groupnumber, uint
1966 ++g->message_number; 2284 ++g->message_number;
1967 } 2285 }
1968 2286
1969 uint32_t message_num = net_htonl(g->message_number); 2287 const uint32_t message_num = net_htonl(g->message_number);
1970 memcpy(packet + sizeof(uint16_t), &message_num, sizeof(message_num)); 2288 memcpy(packet + sizeof(uint16_t), &message_num, sizeof(message_num));
1971 2289
1972 packet[sizeof(uint16_t) + sizeof(uint32_t)] = message_id; 2290 packet[sizeof(uint16_t) + sizeof(uint32_t)] = message_id;
@@ -1986,7 +2304,7 @@ static int send_message_group(const Group_Chats *g_c, uint32_t groupnumber, uint
1986 */ 2304 */
1987int group_message_send(const Group_Chats *g_c, uint32_t groupnumber, const uint8_t *message, uint16_t length) 2305int group_message_send(const Group_Chats *g_c, uint32_t groupnumber, const uint8_t *message, uint16_t length)
1988{ 2306{
1989 int ret = send_message_group(g_c, groupnumber, PACKET_ID_MESSAGE, message, length); 2307 const int ret = send_message_group(g_c, groupnumber, PACKET_ID_MESSAGE, message, length);
1990 2308
1991 if (ret > 0) { 2309 if (ret > 0) {
1992 return 0; 2310 return 0;
@@ -2001,7 +2319,7 @@ int group_message_send(const Group_Chats *g_c, uint32_t groupnumber, const uint8
2001 */ 2319 */
2002int group_action_send(const Group_Chats *g_c, uint32_t groupnumber, const uint8_t *action, uint16_t length) 2320int group_action_send(const Group_Chats *g_c, uint32_t groupnumber, const uint8_t *action, uint16_t length)
2003{ 2321{
2004 int ret = send_message_group(g_c, groupnumber, PACKET_ID_ACTION, action, length); 2322 const int ret = send_message_group(g_c, groupnumber, PACKET_ID_ACTION, action, length);
2005 2323
2006 if (ret > 0) { 2324 if (ret > 0) {
2007 return 0; 2325 return 0;
@@ -2025,9 +2343,9 @@ int send_group_lossy_packet(const Group_Chats *g_c, uint32_t groupnumber, const
2025 } 2343 }
2026 2344
2027 VLA(uint8_t, packet, sizeof(uint16_t) * 2 + length); 2345 VLA(uint8_t, packet, sizeof(uint16_t) * 2 + length);
2028 uint16_t peer_number = net_htons(g->peer_number); 2346 const uint16_t peer_number = net_htons(g->peer_number);
2029 memcpy(packet, &peer_number, sizeof(uint16_t)); 2347 memcpy(packet, &peer_number, sizeof(uint16_t));
2030 uint16_t message_num = net_htons(g->lossy_message_number); 2348 const uint16_t message_num = net_htons(g->lossy_message_number);
2031 memcpy(packet + sizeof(uint16_t), &message_num, sizeof(uint16_t)); 2349 memcpy(packet + sizeof(uint16_t), &message_num, sizeof(uint16_t));
2032 memcpy(packet + sizeof(uint16_t) * 2, data, length); 2350 memcpy(packet + sizeof(uint16_t) * 2, data, length);
2033 2351
@@ -2108,33 +2426,31 @@ static void handle_message_packet_group(Group_Chats *g_c, uint32_t groupnumber,
2108 memcpy(&peer_number, data, sizeof(uint16_t)); 2426 memcpy(&peer_number, data, sizeof(uint16_t));
2109 peer_number = net_ntohs(peer_number); 2427 peer_number = net_ntohs(peer_number);
2110 2428
2111 int index = get_peer_index(g, peer_number); 2429 const int index = note_peer_active(g_c, groupnumber, peer_number, userdata);
2112 2430
2113 if (index == -1) { 2431 if (index == -1) {
2114 /* We don't know the peer this packet came from so we query the list of peers from that peer. 2432 /* If we don't know the peer this packet came from, then we query the
2115 (They would not have relayed it if they didn't know the peer.) */ 2433 * list of peers from the relaying peer.
2434 * (They would not have relayed it if they didn't know the peer.) */
2116 send_peer_query(g_c, g->close[close_index].number, g->close[close_index].group_number); 2435 send_peer_query(g_c, g->close[close_index].number, g->close[close_index].group_number);
2117 return; 2436 return;
2118 } 2437 }
2119 2438
2120 if (g->number_joined != -1 && count_close_connected(g) >= DESIRED_CLOSE_CONNECTIONS) { 2439 if (g->num_introducer_connections > 0 && count_close_connected(g) > DESIRED_CLOSE_CONNECTIONS) {
2121 const int fr_close_index = friend_in_close(g, g->number_joined); 2440 for (uint32_t i = 0; i < MAX_GROUP_CONNECTIONS; ++i) {
2441 if (g->close[i].type == GROUPCHAT_CLOSE_NONE
2442 || !(g->close[i].reasons & GROUPCHAT_CLOSE_REASON_INTRODUCER)
2443 || i == close_index) {
2444 continue;
2445 }
2122 2446
2123 if (fr_close_index >= 0 && fr_close_index != close_index && !g->close[fr_close_index].closest) {
2124 uint8_t real_pk[CRYPTO_PUBLIC_KEY_SIZE]; 2447 uint8_t real_pk[CRYPTO_PUBLIC_KEY_SIZE];
2125 get_friendcon_public_keys(real_pk, nullptr, g_c->fr_c, g->close[fr_close_index].number); 2448 get_friendcon_public_keys(real_pk, nullptr, g_c->fr_c, g->close[i].number);
2126 2449
2127 if (id_equal(g->group[index].real_pk, real_pk)) { 2450 if (id_equal(g->group[index].real_pk, real_pk)) {
2128 /* Received message from peer relayed via another peer, so 2451 /* Received message from peer relayed via another peer, so
2129 * the introduction was successful */ 2452 * the introduction was successful */
2130 g->number_joined = -1; 2453 remove_conn_reason(g_c, groupnumber, i, GROUPCHAT_CLOSE_REASON_INTRODUCER);
2131 g->close[fr_close_index].introducer = false;
2132
2133 if (!g->close[fr_close_index].closest && !g->close[fr_close_index].introduced) {
2134 g->close[fr_close_index].type = GROUPCHAT_CLOSE_NONE;
2135 send_peer_kill(g_c, g->close[fr_close_index].number, g->close[fr_close_index].group_number);
2136 kill_friend_connection(g_c->fr_c, g->close[fr_close_index].number);
2137 }
2138 } 2454 }
2139 } 2455 }
2140 } 2456 }
@@ -2143,24 +2459,17 @@ static void handle_message_packet_group(Group_Chats *g_c, uint32_t groupnumber,
2143 memcpy(&message_number, data + sizeof(uint16_t), sizeof(message_number)); 2459 memcpy(&message_number, data + sizeof(uint16_t), sizeof(message_number));
2144 message_number = net_ntohl(message_number); 2460 message_number = net_ntohl(message_number);
2145 2461
2146 uint8_t message_id = data[sizeof(uint16_t) + sizeof(message_number)]; 2462 const uint8_t message_id = data[sizeof(uint16_t) + sizeof(message_number)];
2147 const uint8_t *msg_data = data + sizeof(uint16_t) + sizeof(message_number) + 1; 2463 const uint8_t *msg_data = data + sizeof(uint16_t) + sizeof(message_number) + 1;
2148 uint16_t msg_data_len = length - (sizeof(uint16_t) + sizeof(message_number) + 1); 2464 const uint16_t msg_data_len = length - (sizeof(uint16_t) + sizeof(message_number) + 1);
2149 2465
2150 // FIXME(zugz) update discussion of message numbers in the spec
2151 if (!check_message_info(message_number, message_id, &g->group[index])) { 2466 if (!check_message_info(message_number, message_id, &g->group[index])) {
2152 return; 2467 return;
2153 } 2468 }
2154 2469
2155 switch (message_id) { 2470 switch (message_id) {
2156 case GROUP_MESSAGE_PING_ID: { 2471 case GROUP_MESSAGE_PING_ID:
2157 if (msg_data_len != 0) { 2472 break;
2158 return;
2159 }
2160
2161 g->group[index].last_recv = mono_time_get(g_c->mono_time);
2162 }
2163 break;
2164 2473
2165 case GROUP_MESSAGE_NEW_PEER_ID: { 2474 case GROUP_MESSAGE_NEW_PEER_ID: {
2166 if (msg_data_len != GROUP_MESSAGE_NEW_PEER_LENGTH) { 2475 if (msg_data_len != GROUP_MESSAGE_NEW_PEER_LENGTH) {
@@ -2171,7 +2480,7 @@ static void handle_message_packet_group(Group_Chats *g_c, uint32_t groupnumber,
2171 memcpy(&new_peer_number, msg_data, sizeof(uint16_t)); 2480 memcpy(&new_peer_number, msg_data, sizeof(uint16_t));
2172 new_peer_number = net_ntohs(new_peer_number); 2481 new_peer_number = net_ntohs(new_peer_number);
2173 addpeer(g_c, groupnumber, msg_data + sizeof(uint16_t), msg_data + sizeof(uint16_t) + CRYPTO_PUBLIC_KEY_SIZE, 2482 addpeer(g_c, groupnumber, msg_data + sizeof(uint16_t), msg_data + sizeof(uint16_t) + CRYPTO_PUBLIC_KEY_SIZE,
2174 new_peer_number, userdata, true); 2483 new_peer_number, userdata, true, true);
2175 } 2484 }
2176 break; 2485 break;
2177 2486
@@ -2185,7 +2494,7 @@ static void handle_message_packet_group(Group_Chats *g_c, uint32_t groupnumber,
2185 kill_peer_number = net_ntohs(kill_peer_number); 2494 kill_peer_number = net_ntohs(kill_peer_number);
2186 2495
2187 if (peer_number == kill_peer_number) { 2496 if (peer_number == kill_peer_number) {
2188 delpeer(g_c, groupnumber, index, userdata); 2497 delpeer(g_c, groupnumber, index, userdata, false);
2189 } else { 2498 } else {
2190 return; 2499 return;
2191 // TODO(irungentoo): 2500 // TODO(irungentoo):
@@ -2260,6 +2569,10 @@ static int g_handle_packet(void *object, int friendcon_id, const uint8_t *data,
2260 return handle_packet_online(g_c, friendcon_id, data + 1, length - 1); 2569 return handle_packet_online(g_c, friendcon_id, data + 1, length - 1);
2261 } 2570 }
2262 2571
2572 if (data[0] == PACKET_ID_REJOIN_CONFERENCE) {
2573 return handle_packet_rejoin(g_c, friendcon_id, data + 1, length - 1, userdata);
2574 }
2575
2263 if (data[0] != PACKET_ID_DIRECT_CONFERENCE && data[0] != PACKET_ID_MESSAGE_CONFERENCE) { 2576 if (data[0] != PACKET_ID_DIRECT_CONFERENCE && data[0] != PACKET_ID_MESSAGE_CONFERENCE) {
2264 return -1; 2577 return -1;
2265 } 2578 }
@@ -2273,7 +2586,7 @@ static int g_handle_packet(void *object, int friendcon_id, const uint8_t *data,
2273 return -1; 2586 return -1;
2274 } 2587 }
2275 2588
2276 int index = friend_in_close(g, friendcon_id); 2589 const int index = friend_in_close(g, friendcon_id);
2277 2590
2278 if (index == -1) { 2591 if (index == -1) {
2279 return -1; 2592 return -1;
@@ -2335,7 +2648,7 @@ static unsigned int lossy_packet_not_received(Group_c *g, int peer_index, uint16
2335 return -1; 2648 return -1;
2336 } 2649 }
2337 2650
2338 uint16_t top_distance = message_number - g->group[peer_index].top_lossy_number; 2651 const uint16_t top_distance = message_number - g->group[peer_index].top_lossy_number;
2339 2652
2340 if (top_distance >= MAX_LOSSY_COUNT) { 2653 if (top_distance >= MAX_LOSSY_COUNT) {
2341 crypto_memzero(g->group[peer_index].recv_lossy, sizeof(g->group[peer_index].recv_lossy)); 2654 crypto_memzero(g->group[peer_index].recv_lossy, sizeof(g->group[peer_index].recv_lossy));
@@ -2384,7 +2697,7 @@ static int handle_lossy(void *object, int friendcon_id, const uint8_t *data, uin
2384 return -1; 2697 return -1;
2385 } 2698 }
2386 2699
2387 int index = friend_in_close(g, friendcon_id); 2700 const int index = friend_in_close(g, friendcon_id);
2388 2701
2389 if (index == -1) { 2702 if (index == -1) {
2390 return -1; 2703 return -1;
@@ -2394,7 +2707,7 @@ static int handle_lossy(void *object, int friendcon_id, const uint8_t *data, uin
2394 return -1; 2707 return -1;
2395 } 2708 }
2396 2709
2397 int peer_index = get_peer_index(g, peer_number); 2710 const int peer_index = get_peer_index(g, peer_number);
2398 2711
2399 if (peer_index == -1) { 2712 if (peer_index == -1) {
2400 return -1; 2713 return -1;
@@ -2406,7 +2719,7 @@ static int handle_lossy(void *object, int friendcon_id, const uint8_t *data, uin
2406 2719
2407 const uint8_t *lossy_data = data + 1 + sizeof(uint16_t) * 3; 2720 const uint8_t *lossy_data = data + 1 + sizeof(uint16_t) * 3;
2408 uint16_t lossy_length = length - (1 + sizeof(uint16_t) * 3); 2721 uint16_t lossy_length = length - (1 + sizeof(uint16_t) * 3);
2409 uint8_t message_id = lossy_data[0]; 2722 const uint8_t message_id = lossy_data[0];
2410 ++lossy_data; 2723 ++lossy_data;
2411 --lossy_length; 2724 --lossy_length;
2412 2725
@@ -2517,7 +2830,7 @@ static int ping_groupchat(Group_Chats *g_c, uint32_t groupnumber)
2517 return 0; 2830 return 0;
2518} 2831}
2519 2832
2520static int groupchat_clear_timedout(Group_Chats *g_c, uint32_t groupnumber, void *userdata) 2833static int groupchat_freeze_timedout(Group_Chats *g_c, uint32_t groupnumber, void *userdata)
2521{ 2834{
2522 Group_c *g = get_group_c(g_c, groupnumber); 2835 Group_c *g = get_group_c(g_c, groupnumber);
2523 2836
@@ -2526,16 +2839,20 @@ static int groupchat_clear_timedout(Group_Chats *g_c, uint32_t groupnumber, void
2526 } 2839 }
2527 2840
2528 for (uint32_t i = 0; i < g->numpeers; ++i) { 2841 for (uint32_t i = 0; i < g->numpeers; ++i) {
2529 if (g->peer_number != g->group[i].peer_number 2842 if (g->group[i].peer_number == g->peer_number) {
2530 && mono_time_is_timeout(g_c->mono_time, g->group[i].last_recv, GROUP_PING_INTERVAL * 3)) { 2843 continue;
2531 delpeer(g_c, groupnumber, i, userdata);
2532 } 2844 }
2533 2845
2534 if (g->group == nullptr || i >= g->numpeers) { 2846 if (mono_time_is_timeout(g_c->mono_time, g->group[i].last_active, GROUP_PING_INTERVAL * 3)) {
2535 break; 2847 try_send_rejoin(g_c, groupnumber, g->group[i].real_pk);
2848 freeze_peer(g_c, groupnumber, i, userdata);
2536 } 2849 }
2537 } 2850 }
2538 2851
2852 if (g->numpeers <= 1) {
2853 g->title_fresh = false;
2854 }
2855
2539 return 0; 2856 return 0;
2540} 2857}
2541 2858
@@ -2552,6 +2869,7 @@ void send_name_all_groups(Group_Chats *g_c)
2552 2869
2553 if (g->status == GROUPCHAT_STATUS_CONNECTED) { 2870 if (g->status == GROUPCHAT_STATUS_CONNECTED) {
2554 group_name_send(g_c, i, g_c->m->name, g_c->m->name_length); 2871 group_name_send(g_c, i, g_c->m->name, g_c->m->name_length);
2872 g->need_send_name = false;
2555 } 2873 }
2556 } 2874 }
2557} 2875}
@@ -2591,7 +2909,12 @@ void do_groupchats(Group_Chats *g_c, void *userdata)
2591 if (g->status == GROUPCHAT_STATUS_CONNECTED) { 2909 if (g->status == GROUPCHAT_STATUS_CONNECTED) {
2592 connect_to_closest(g_c, i, userdata); 2910 connect_to_closest(g_c, i, userdata);
2593 ping_groupchat(g_c, i); 2911 ping_groupchat(g_c, i);
2594 groupchat_clear_timedout(g_c, i, userdata); 2912 groupchat_freeze_timedout(g_c, i, userdata);
2913
2914 if (g->need_send_name) {
2915 group_name_send(g_c, i, g_c->m->name, g_c->m->name_length);
2916 g->need_send_name = false;
2917 }
2595 } 2918 }
2596 } 2919 }
2597 2920
diff --git a/toxcore/group.h b/toxcore/group.h
index 68488e27..110f5d44 100644
--- a/toxcore/group.h
+++ b/toxcore/group.h
@@ -49,12 +49,13 @@ typedef struct Message_Info {
49typedef struct Group_Peer { 49typedef 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 53
53 uint64_t last_recv; 54 uint64_t last_active;
54 55
55 Message_Info 56 Message_Info
56 last_message_infos[MAX_LAST_MESSAGE_INFOS]; /* received messages, strictly decreasing in message_number */ 57 last_message_infos[MAX_LAST_MESSAGE_INFOS]; /* received messages, strictly decreasing in message_number */
57 uint8_t num_last_message_infos; 58 uint8_t num_last_message_infos;
58 59
59 uint8_t nick[MAX_NAME_LENGTH]; 60 uint8_t nick[MAX_NAME_LENGTH];
60 uint8_t nick_len; 61 uint8_t nick_len;
@@ -79,11 +80,18 @@ typedef enum Groupchat_Close_Type {
79 GROUPCHAT_CLOSE_ONLINE 80 GROUPCHAT_CLOSE_ONLINE
80} Groupchat_Close_Type; 81} Groupchat_Close_Type;
81 82
83/* Connection is to one of the closest DESIRED_CLOSE_CONNECTIONS peers */
84#define GROUPCHAT_CLOSE_REASON_CLOSEST (1 << 0)
85
86/* Connection is to a peer we are introducing to the conference */
87#define GROUPCHAT_CLOSE_REASON_INTRODUCING (1 << 1)
88
89/* Connection is to a peer who is introducing us to the conference */
90#define GROUPCHAT_CLOSE_REASON_INTRODUCER (1 << 2)
91
82typedef struct Groupchat_Close { 92typedef struct Groupchat_Close {
83 uint8_t type; /* GROUPCHAT_CLOSE_* */ 93 uint8_t type; /* GROUPCHAT_CLOSE_* */
84 bool closest; /* connected to peer because it is one of our closest peers */ 94 uint8_t reasons; /* bit field with flags GROUPCHAT_CLOSE_REASON_* */
85 bool introducer; /* connected to peer because it introduced us to the group */
86 bool introduced; /* connected to peer because we introduced it to the group */
87 uint32_t number; 95 uint32_t number;
88 uint16_t group_number; 96 uint16_t group_number;
89} Groupchat_Close; 97} Groupchat_Close;
@@ -101,9 +109,15 @@ typedef void group_on_delete_cb(void *object, uint32_t conference_number);
101typedef struct Group_c { 109typedef struct Group_c {
102 uint8_t status; 110 uint8_t status;
103 111
112 bool need_send_name;
113 bool title_fresh;
114
104 Group_Peer *group; 115 Group_Peer *group;
105 uint32_t numpeers; 116 uint32_t numpeers;
106 117
118 Group_Peer *frozen;
119 uint32_t numfrozen;
120
107 /* TODO(zugz) rename close to something more accurate - "connected"? */ 121 /* TODO(zugz) rename close to something more accurate - "connected"? */
108 Groupchat_Close close[MAX_GROUP_CONNECTIONS]; 122 Groupchat_Close close[MAX_GROUP_CONNECTIONS];
109 123
@@ -123,7 +137,7 @@ typedef struct Group_c {
123 137
124 uint64_t last_sent_ping; 138 uint64_t last_sent_ping;
125 139
126 int number_joined; /* friendcon_id of person that invited us to the chat. (-1 means none) */ 140 uint32_t num_introducer_connections;
127 141
128 void *object; 142 void *object;
129 143
diff --git a/toxcore/net_crypto.h b/toxcore/net_crypto.h
index 7a2ff1ff..9fd47014 100644
--- a/toxcore/net_crypto.h
+++ b/toxcore/net_crypto.h
@@ -78,6 +78,7 @@
78#define PACKET_ID_ONLINE_PACKET 97 78#define PACKET_ID_ONLINE_PACKET 97
79#define PACKET_ID_DIRECT_CONFERENCE 98 79#define PACKET_ID_DIRECT_CONFERENCE 98
80#define PACKET_ID_MESSAGE_CONFERENCE 99 80#define PACKET_ID_MESSAGE_CONFERENCE 99
81#define PACKET_ID_REJOIN_CONFERENCE 100
81#define PACKET_ID_LOSSY_CONFERENCE 199 82#define PACKET_ID_LOSSY_CONFERENCE 199
82 83
83/*** Crypto connections. ***/ 84/*** Crypto connections. ***/