summaryrefslogtreecommitdiff
path: root/toxcore
diff options
context:
space:
mode:
authorzugz (tox) <mbays+tox@sdf.org>2018-09-09 23:27:39 +0200
committerzugz (tox) <mbays+tox@sdf.org>2018-11-29 21:52:23 +0100
commit9770880e975a09635a461c46c8fcc193bce57004 (patch)
tree8c7aa3c3ee8d264a3fdd97d8a5c49caa25f5da0b /toxcore
parentcaca350f435cf6a2a3778c64771dafdb7dde8b7a (diff)
Implement conferences saving
* add global friend_connection status callback, used for group rejoining * stop leaving groups on killing tox
Diffstat (limited to 'toxcore')
-rw-r--r--toxcore/Messenger.h3
-rw-r--r--toxcore/friend_connection.c16
-rw-r--r--toxcore/friend_connection.h5
-rw-r--r--toxcore/group.c259
-rw-r--r--toxcore/group.h11
-rw-r--r--toxcore/state.h1
-rw-r--r--toxcore/tox.c1
7 files changed, 287 insertions, 9 deletions
diff --git a/toxcore/Messenger.h b/toxcore/Messenger.h
index 1651315e..a3376e23 100644
--- a/toxcore/Messenger.h
+++ b/toxcore/Messenger.h
@@ -796,6 +796,9 @@ uint8_t *messenger_save(const Messenger *m, uint8_t *data);
796 796
797/* Load a state section. 797/* Load a state section.
798 * 798 *
799 * @param data Data to load.
800 * @param length Length of data.
801 * @param type Type of section (STATE_TYPE_*).
799 * @param status Result of loading section is stored here if the section is handled. 802 * @param status Result of loading section is stored here if the section is handled.
800 * @return true iff section handled. 803 * @return true iff section handled.
801 */ 804 */
diff --git a/toxcore/friend_connection.c b/toxcore/friend_connection.c
index 9c805b45..69533def 100644
--- a/toxcore/friend_connection.c
+++ b/toxcore/friend_connection.c
@@ -85,6 +85,9 @@ struct Friend_Connections {
85 fr_request_cb *fr_request_callback; 85 fr_request_cb *fr_request_callback;
86 void *fr_request_object; 86 void *fr_request_object;
87 87
88 global_status_cb *global_status_callback;
89 void *global_status_callback_object;
90
88 uint64_t last_lan_discovery; 91 uint64_t last_lan_discovery;
89 uint16_t next_lan_port; 92 uint16_t next_lan_port;
90 93
@@ -401,9 +404,11 @@ static int handle_status(void *object, int number, uint8_t status, void *userdat
401 } 404 }
402 405
403 if (status_changed) { 406 if (status_changed) {
404 unsigned int i; 407 if (fr_c->global_status_callback) {
408 fr_c->global_status_callback(fr_c->global_status_callback_object, number, status, userdata);
409 }
405 410
406 for (i = 0; i < MAX_FRIEND_CONNECTION_CALLBACKS; ++i) { 411 for (unsigned i = 0; i < MAX_FRIEND_CONNECTION_CALLBACKS; ++i) {
407 if (friend_con->callbacks[i].status_callback) { 412 if (friend_con->callbacks[i].status_callback) {
408 friend_con->callbacks[i].status_callback( 413 friend_con->callbacks[i].status_callback(
409 friend_con->callbacks[i].callback_object, 414 friend_con->callbacks[i].callback_object,
@@ -716,6 +721,13 @@ int friend_connection_callbacks(Friend_Connections *fr_c, int friendcon_id, unsi
716 return 0; 721 return 0;
717} 722}
718 723
724/* Set global status callback for friend connections. */
725void set_global_status_callback(Friend_Connections *fr_c, global_status_cb *global_status_callback, void *object)
726{
727 fr_c->global_status_callback = global_status_callback;
728 fr_c->global_status_callback_object = object;
729}
730
719/* return the crypt_connection_id for the connection. 731/* return the crypt_connection_id for the connection.
720 * 732 *
721 * return crypt_connection_id on success. 733 * return crypt_connection_id on success.
diff --git a/toxcore/friend_connection.h b/toxcore/friend_connection.h
index 149a4fa7..166c731b 100644
--- a/toxcore/friend_connection.h
+++ b/toxcore/friend_connection.h
@@ -101,10 +101,15 @@ void set_dht_temp_pk(Friend_Connections *fr_c, int friendcon_id, const uint8_t *
101 */ 101 */
102int friend_add_tcp_relay(Friend_Connections *fr_c, int friendcon_id, IP_Port ip_port, const uint8_t *public_key); 102int friend_add_tcp_relay(Friend_Connections *fr_c, int friendcon_id, IP_Port ip_port, const uint8_t *public_key);
103 103
104typedef int global_status_cb(void *object, int id, uint8_t status, void *userdata);
105
104typedef int fc_status_cb(void *object, int id, uint8_t status, void *userdata); 106typedef int fc_status_cb(void *object, int id, uint8_t status, void *userdata);
105typedef int fc_data_cb(void *object, int id, const uint8_t *data, uint16_t length, void *userdata); 107typedef int fc_data_cb(void *object, int id, const uint8_t *data, uint16_t length, void *userdata);
106typedef int fc_lossy_data_cb(void *object, int id, const uint8_t *data, uint16_t length, void *userdata); 108typedef int fc_lossy_data_cb(void *object, int id, const uint8_t *data, uint16_t length, void *userdata);
107 109
110/* Set global status callback for friend connections. */
111void set_global_status_callback(Friend_Connections *fr_c, global_status_cb *global_status_callback, void *object);
112
108/* Set the callbacks for the friend connection. 113/* Set the callbacks for the friend connection.
109 * index is the index (0 to (MAX_FRIEND_CONNECTION_CALLBACKS - 1)) we want the callback to set in the array. 114 * index is the index (0 to (MAX_FRIEND_CONNECTION_CALLBACKS - 1)) we want the callback to set in the array.
110 * 115 *
diff --git a/toxcore/group.c b/toxcore/group.c
index 9ef32b72..99f72336 100644
--- a/toxcore/group.c
+++ b/toxcore/group.c
@@ -27,10 +27,12 @@
27 27
28#include "group.h" 28#include "group.h"
29 29
30#include <assert.h>
30#include <stdlib.h> 31#include <stdlib.h>
31#include <string.h> 32#include <string.h>
32 33
33#include "mono_time.h" 34#include "mono_time.h"
35#include "state.h"
34#include "util.h" 36#include "util.h"
35 37
36/** 38/**
@@ -880,13 +882,23 @@ static void rejoin_frozen_friend(Group_Chats *g_c, int friendcon_id)
880 } 882 }
881} 883}
882 884
885static int g_handle_any_status(void *object, int friendcon_id, uint8_t status, void *userdata)
886{
887 Group_Chats *g_c = (Group_Chats *)object;
888
889 if (status) {
890 rejoin_frozen_friend(g_c, friendcon_id);
891 }
892
893 return 0;
894}
895
883static int g_handle_status(void *object, int friendcon_id, uint8_t status, void *userdata) 896static int g_handle_status(void *object, int friendcon_id, uint8_t status, void *userdata)
884{ 897{
885 Group_Chats *g_c = (Group_Chats *)object; 898 Group_Chats *g_c = (Group_Chats *)object;
886 899
887 if (status) { /* Went online */ 900 if (status) { /* Went online */
888 set_conns_status_groups(g_c, friendcon_id, GROUPCHAT_CLOSE_ONLINE, userdata); 901 set_conns_status_groups(g_c, friendcon_id, GROUPCHAT_CLOSE_ONLINE, userdata);
889 rejoin_frozen_friend(g_c, friendcon_id);
890 } else { /* Went offline */ 902 } else { /* Went offline */
891 set_conns_status_groups(g_c, friendcon_id, GROUPCHAT_CLOSE_CONNECTION, userdata); 903 set_conns_status_groups(g_c, friendcon_id, GROUPCHAT_CLOSE_CONNECTION, userdata);
892 // TODO(irungentoo): remove timedout connections? 904 // TODO(irungentoo): remove timedout connections?
@@ -1021,7 +1033,6 @@ int add_groupchat(Group_Chats *g_c, uint8_t type)
1021 return groupnumber; 1033 return groupnumber;
1022} 1034}
1023 1035
1024static int group_kill_peer_send(const Group_Chats *g_c, uint32_t groupnumber, uint16_t peer_num);
1025/* Delete a groupchat from the chats array. 1036/* Delete a groupchat from the chats array.
1026 * 1037 *
1027 * return 0 on success. 1038 * return 0 on success.
@@ -1035,8 +1046,6 @@ int del_groupchat(Group_Chats *g_c, uint32_t groupnumber)
1035 return -1; 1046 return -1;
1036 } 1047 }
1037 1048
1038 group_kill_peer_send(g_c, groupnumber, g->peer_number);
1039
1040 for (uint32_t i = 0; i < MAX_GROUP_CONNECTIONS; ++i) { 1049 for (uint32_t i = 0; i < MAX_GROUP_CONNECTIONS; ++i) {
1041 if (g->close[i].type == GROUPCHAT_CLOSE_NONE) { 1050 if (g->close[i].type == GROUPCHAT_CLOSE_NONE) {
1042 continue; 1051 continue;
@@ -1587,6 +1596,22 @@ static int group_name_send(const Group_Chats *g_c, uint32_t groupnumber, const u
1587 return -1; 1596 return -1;
1588} 1597}
1589 1598
1599/* send message to announce leaving group
1600 * return true on success
1601 * return false on failure
1602 */
1603bool group_leave(const Group_Chats *g_c, uint32_t groupnumber)
1604{
1605 Group_c *g = get_group_c(g_c, groupnumber);
1606
1607 if (!g) {
1608 return false;
1609 }
1610
1611 return group_kill_peer_send(g_c, groupnumber, g->peer_number) == 0;
1612}
1613
1614
1590/* set the group's title, limited to MAX_NAME_LENGTH 1615/* set the group's title, limited to MAX_NAME_LENGTH
1591 * return 0 on success 1616 * return 0 on success
1592 * return -1 if groupnumber is invalid. 1617 * return -1 if groupnumber is invalid.
@@ -2875,22 +2900,242 @@ void send_name_all_groups(Group_Chats *g_c)
2875 } 2900 }
2876} 2901}
2877 2902
2903#define SAVED_PEER_SIZE_CONSTANT (2 * CRYPTO_PUBLIC_KEY_SIZE + 2 + 1)
2904
2905static uint32_t saved_peer_size(const Group_Peer *peer)
2906{
2907 return SAVED_PEER_SIZE_CONSTANT + peer->nick_len;
2908}
2909
2910static uint8_t *save_peer(const Group_Peer *peer, uint8_t *data)
2911{
2912 memcpy(data, peer->real_pk, CRYPTO_PUBLIC_KEY_SIZE);
2913 data += CRYPTO_PUBLIC_KEY_SIZE;
2914
2915 memcpy(data, peer->temp_pk, CRYPTO_PUBLIC_KEY_SIZE);
2916 data += CRYPTO_PUBLIC_KEY_SIZE;
2917
2918 host_to_lendian_bytes16(data, peer->peer_number);
2919 data += sizeof(uint16_t);
2920
2921 *data = peer->nick_len;
2922 ++data;
2923
2924 memcpy(data, peer->nick, peer->nick_len);
2925 data += peer->nick_len;
2926
2927 return data;
2928}
2929
2930#define SAVED_CONF_SIZE_CONSTANT (1 + GROUP_ID_LENGTH + sizeof(uint32_t) \
2931 + sizeof(uint16_t) + sizeof(uint16_t) + sizeof(uint32_t) + 1)
2932
2933static uint32_t saved_conf_size(const Group_c *g)
2934{
2935 uint32_t len = SAVED_CONF_SIZE_CONSTANT + g->title_len;
2936
2937 for (uint32_t j = 0; j < g->numpeers + g->numfrozen; ++j) {
2938 const Group_Peer *peer = (j < g->numpeers) ? &g->group[j] : &g->frozen[j - g->numpeers];
2939
2940 if (id_equal(peer->real_pk, g->real_pk)) {
2941 continue;
2942 }
2943
2944 len += saved_peer_size(peer);
2945 }
2946
2947 return len;
2948}
2949
2950static uint8_t *save_conf(const Group_c *g, uint8_t *data)
2951{
2952 *data = g->type;
2953 ++data;
2954
2955 memcpy(data, g->id, GROUP_ID_LENGTH);
2956 data += GROUP_ID_LENGTH;
2957
2958 host_to_lendian_bytes32(data, g->message_number);
2959 data += sizeof(uint32_t);
2960
2961 host_to_lendian_bytes16(data, g->lossy_message_number);
2962 data += sizeof(uint16_t);
2963
2964 host_to_lendian_bytes16(data, g->peer_number);
2965 data += sizeof(uint16_t);
2966
2967 host_to_lendian_bytes32(data, g->numpeers - 1 + g->numfrozen);
2968 data += sizeof(uint32_t);
2969
2970 *data = g->title_len;
2971 ++data;
2972
2973 memcpy(data, g->title, g->title_len);
2974 data += g->title_len;
2975
2976#ifndef NDEBUG
2977 bool found_self = false;
2978#endif
2979
2980 for (uint32_t j = 0; j < g->numpeers + g->numfrozen; ++j) {
2981 const Group_Peer *peer = (j < g->numpeers) ? &g->group[j] : &g->frozen[j - g->numpeers];
2982
2983 if (id_equal(peer->real_pk, g->real_pk)) {
2984#ifndef NDEBUG
2985 found_self = true;
2986#endif
2987 continue;
2988 }
2989
2990 data = save_peer(peer, data);
2991 }
2992
2993 assert(found_self);
2994
2995 return data;
2996}
2997
2998static uint32_t conferences_section_size(const Group_Chats *g_c)
2999{
3000 uint32_t len = 0;
3001
3002 for (uint16_t i = 0; i < g_c->num_chats; ++i) {
3003 Group_c *g = get_group_c(g_c, i);
3004
3005 if (!g || g->status != GROUPCHAT_STATUS_CONNECTED) {
3006 continue;
3007 }
3008
3009 len += saved_conf_size(g);
3010 }
3011
3012 return len;
3013}
3014
2878uint32_t conferences_size(const Group_Chats *g_c) 3015uint32_t conferences_size(const Group_Chats *g_c)
2879{ 3016{
2880 return 0; 3017 return 2 * sizeof(uint32_t) + conferences_section_size(g_c);
2881} 3018}
2882 3019
2883uint8_t *conferences_save(const Group_Chats *g_c, uint8_t *data) 3020uint8_t *conferences_save(const Group_Chats *g_c, uint8_t *data)
2884{ 3021{
3022 const uint32_t len = conferences_section_size(g_c);
3023 data = state_write_section_header(data, STATE_COOKIE_TYPE, len, STATE_TYPE_CONFERENCES);
3024
3025 for (uint16_t i = 0; i < g_c->num_chats; ++i) {
3026 Group_c *g = get_group_c(g_c, i);
3027
3028 if (!g || g->status != GROUPCHAT_STATUS_CONNECTED) {
3029 continue;
3030 }
3031
3032 data = save_conf(g, data);
3033 }
3034
2885 return data; 3035 return data;
2886} 3036}
2887 3037
3038static State_Load_Status load_conferences(Group_Chats *g_c, const uint8_t *data, uint32_t length)
3039{
3040 const uint8_t *init_data = data;
3041
3042 while (length >= (uint32_t)(data - init_data) + SAVED_CONF_SIZE_CONSTANT) {
3043 const int groupnumber = create_group_chat(g_c);
3044
3045 if (groupnumber == -1) {
3046 return STATE_LOAD_STATUS_ERROR;
3047 }
3048
3049 Group_c *g = &g_c->chats[groupnumber];
3050
3051 g->type = *data;
3052 ++data;
3053
3054 memcpy(g->id, data, GROUP_ID_LENGTH);
3055 data += GROUP_ID_LENGTH;
3056
3057 lendian_bytes_to_host32(&g->message_number, data);
3058 data += sizeof(uint32_t);
3059
3060 lendian_bytes_to_host16(&g->lossy_message_number, data);
3061 data += sizeof(uint16_t);
3062
3063 lendian_bytes_to_host16(&g->peer_number, data);
3064 data += sizeof(uint16_t);
3065
3066 lendian_bytes_to_host32(&g->numfrozen, data);
3067 data += sizeof(uint32_t);
3068
3069 g->frozen = (Group_Peer *)malloc(sizeof(Group_Peer) * g->numfrozen);
3070
3071 if (g->frozen == nullptr) {
3072 return STATE_LOAD_STATUS_ERROR;
3073 }
3074
3075 g->title_len = *data;
3076 ++data;
3077
3078 if (length < (uint32_t)(data - init_data) + g->title_len) {
3079 return STATE_LOAD_STATUS_ERROR;
3080 }
3081
3082 memcpy(g->title, data, g->title_len);
3083 data += g->title_len;
3084
3085 for (uint32_t j = 0; j < g->numfrozen; ++j) {
3086 if (length < (uint32_t)(data - init_data) + SAVED_PEER_SIZE_CONSTANT) {
3087 return STATE_LOAD_STATUS_ERROR;
3088 }
3089
3090 Group_Peer *peer = &g->frozen[j];
3091 memset(peer, 0, sizeof(Group_Peer));
3092
3093 id_copy(peer->real_pk, data);
3094 data += CRYPTO_PUBLIC_KEY_SIZE;
3095 id_copy(peer->temp_pk, data);
3096 data += CRYPTO_PUBLIC_KEY_SIZE;
3097
3098 lendian_bytes_to_host16(&peer->peer_number, data);
3099 data += sizeof(uint16_t);
3100
3101 peer->nick_len = *data;
3102 ++data;
3103
3104 if (length < (uint32_t)(data - init_data) + peer->nick_len) {
3105 return STATE_LOAD_STATUS_ERROR;
3106 }
3107
3108 memcpy(peer->nick, data, peer->nick_len);
3109 data += peer->nick_len;
3110 }
3111
3112 g->status = GROUPCHAT_STATUS_CONNECTED;
3113 memcpy(g->real_pk, nc_get_self_public_key(g_c->m->net_crypto), CRYPTO_PUBLIC_KEY_SIZE);
3114 const int peer_index = addpeer(g_c, groupnumber, g->real_pk, dht_get_self_public_key(g_c->m->dht), g->peer_number,
3115 nullptr, true, false);
3116
3117 if (peer_index == -1) {
3118 return STATE_LOAD_STATUS_ERROR;
3119 }
3120
3121 setnick(g_c, groupnumber, peer_index, g_c->m->name, g_c->m->name_length, nullptr, false);
3122 }
3123
3124 return STATE_LOAD_STATUS_CONTINUE;
3125}
3126
2888bool conferences_load_state_section(Group_Chats *g_c, const uint8_t *data, uint32_t length, uint16_t type, 3127bool conferences_load_state_section(Group_Chats *g_c, const uint8_t *data, uint32_t length, uint16_t type,
2889 State_Load_Status *status) 3128 State_Load_Status *status)
2890{ 3129{
2891 return false; 3130 if (type != STATE_TYPE_CONFERENCES) {
3131 return false;
3132 }
3133
3134 *status = load_conferences(g_c, data, length);
3135 return true;
2892} 3136}
2893 3137
3138
2894/* Create new groupchat instance. */ 3139/* Create new groupchat instance. */
2895Group_Chats *new_groupchats(Mono_Time *mono_time, Messenger *m) 3140Group_Chats *new_groupchats(Mono_Time *mono_time, Messenger *m)
2896{ 3141{
@@ -2910,6 +3155,8 @@ Group_Chats *new_groupchats(Mono_Time *mono_time, Messenger *m)
2910 m->conferences_object = temp; 3155 m->conferences_object = temp;
2911 m_callback_conference_invite(m, &handle_friend_invite_packet); 3156 m_callback_conference_invite(m, &handle_friend_invite_packet);
2912 3157
3158 set_global_status_callback(m->fr_c, &g_handle_any_status, temp);
3159
2913 return temp; 3160 return temp;
2914} 3161}
2915 3162
diff --git a/toxcore/group.h b/toxcore/group.h
index 8673abdb..148de0c1 100644
--- a/toxcore/group.h
+++ b/toxcore/group.h
@@ -306,6 +306,12 @@ int group_message_send(const Group_Chats *g_c, uint32_t groupnumber, const uint8
306 */ 306 */
307int group_action_send(const Group_Chats *g_c, uint32_t groupnumber, const uint8_t *action, uint16_t length); 307int group_action_send(const Group_Chats *g_c, uint32_t groupnumber, const uint8_t *action, uint16_t length);
308 308
309/* send message to announce leaving group
310 * return true on success
311 * return false on failure
312 */
313bool group_leave(const Group_Chats *g_c, uint32_t groupnumber);
314
309/* set the group's title, limited to MAX_NAME_LENGTH 315/* set the group's title, limited to MAX_NAME_LENGTH
310 * return 0 on success 316 * return 0 on success
311 * return -1 if groupnumber is invalid. 317 * return -1 if groupnumber is invalid.
@@ -455,8 +461,11 @@ uint32_t conferences_size(const Group_Chats *g_c);
455uint8_t *conferences_save(const Group_Chats *g_c, uint8_t *data); 461uint8_t *conferences_save(const Group_Chats *g_c, uint8_t *data);
456 462
457/** 463/**
458 * Load a section. 464 * Load a state section.
459 * 465 *
466 * @param data Data to load
467 * @param length Length of data
468 * @param type Type of section (STATE_TYPE_*)
460 * @param status Result of loading section is stored here if the section is handled. 469 * @param status Result of loading section is stored here if the section is handled.
461 * @return true iff section handled. 470 * @return true iff section handled.
462 */ 471 */
diff --git a/toxcore/state.h b/toxcore/state.h
index 872b1e9d..6e3c897e 100644
--- a/toxcore/state.h
+++ b/toxcore/state.h
@@ -31,6 +31,7 @@ typedef enum State_Type {
31 STATE_TYPE_STATUS = 6, 31 STATE_TYPE_STATUS = 6,
32 STATE_TYPE_TCP_RELAY = 10, 32 STATE_TYPE_TCP_RELAY = 10,
33 STATE_TYPE_PATH_NODE = 11, 33 STATE_TYPE_PATH_NODE = 11,
34 STATE_TYPE_CONFERENCES = 20,
34 STATE_TYPE_END = 255, 35 STATE_TYPE_END = 255,
35} State_Type; 36} State_Type;
36 37
diff --git a/toxcore/tox.c b/toxcore/tox.c
index 629cc1c5..88a9bd50 100644
--- a/toxcore/tox.c
+++ b/toxcore/tox.c
@@ -1533,6 +1533,7 @@ uint32_t tox_conference_new(Tox *tox, Tox_Err_Conference_New *error)
1533bool tox_conference_delete(Tox *tox, uint32_t conference_number, Tox_Err_Conference_Delete *error) 1533bool tox_conference_delete(Tox *tox, uint32_t conference_number, Tox_Err_Conference_Delete *error)
1534{ 1534{
1535 Messenger *m = tox->m; 1535 Messenger *m = tox->m;
1536 group_leave(m->conferences_object, conference_number);
1536 int ret = del_groupchat(m->conferences_object, conference_number); 1537 int ret = del_groupchat(m->conferences_object, conference_number);
1537 1538
1538 if (ret == -1) { 1539 if (ret == -1) {