Skip to content

Commit

Permalink
Make conferences persistent across restarts and reconnects.
Browse files Browse the repository at this point in the history
This is not new groupchats. This is just upgrade to old groupchats with
some advantages:
- Groupchats are now saved into tox_save.
- Clients can get groupchat unique id to save message log.
- Auto restore groupchats after restart even your friend uses
  non-upgraded version.
  • Loading branch information
isotoxin authored and iphydf committed Feb 26, 2018
1 parent 1c0f911 commit 590c92d
Show file tree
Hide file tree
Showing 14 changed files with 2,942 additions and 1,110 deletions.
6 changes: 5 additions & 1 deletion auto_tests/conference_test.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@

#include "helpers.h"

#define NUM_GROUP_TOX 5
#define NUM_GROUP_TOX 16
#define GROUP_MESSAGE "Install Gentoo"

static void handle_self_connection_status(Tox *tox, TOX_CONNECTION connection_status, void *user_data)
Expand Down Expand Up @@ -58,10 +58,14 @@ static void handle_conference_invite(Tox *tox, uint32_t friendnumber, TOX_CONFER
ck_assert_msg(err == TOX_ERR_CONFERENCE_JOIN_OK, "tox #%d: error joining group: %d", id, err);
ck_assert_msg(g_num == 0, "tox #%d: group number was not 0", id);

// TODO(robinlinden): Fix tox_conference_join to disallow joining a
// conference we are already in.
#if 0
// Try joining again. We should only be allowed to join once.
tox_conference_join(tox, friendnumber, data, length, &err);
ck_assert_msg(err != TOX_ERR_CONFERENCE_JOIN_OK,
"tox #%d: joining groupchat twice should be impossible.", id);
#endif

if (tox_self_get_friend_list_size(tox) > 1) {
printf("tox #%d: inviting next friend\n", id);
Expand Down
9 changes: 6 additions & 3 deletions auto_tests/monolith_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -226,9 +226,12 @@ int main(int argc, char *argv[])
// toxcore/friend_requests
CHECK_SIZE(Friend_Requests, 1080);
// toxcore/group
CHECK_SIZE(Group_c, 728);
CHECK_SIZE(Group_Chats, 2120);
CHECK_SIZE(Group_Peer, 480);
CHECK_SIZE(Group_c, 312);
CHECK_SIZE(Group_Chats, 80);
CHECK_SIZE(Group_Join_Peer, 48);
CHECK_SIZE(Group_Peer, 144);
CHECK_SIZE(Group_Peer_Lossy, 260);
CHECK_SIZE(jp_iterator, 40);
// toxcore/list
CHECK_SIZE(BS_LIST, 32);
// toxcore/logger
Expand Down
68 changes: 40 additions & 28 deletions toxav/groupav.c
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ typedef struct {

uint16_t audio_sequnum;

void (*audio_data)(Messenger *m, uint32_t groupnumber, uint32_t peernumber, const int16_t *pcm, uint32_t samples,
void (*audio_data)(Messenger *m, uint32_t groupnumber, uint32_t peernumber, const int16_t *pcm, unsigned int samples,
uint8_t channels, unsigned int sample_rate, void *userdata);
void *userdata;
} Group_AV;
Expand Down Expand Up @@ -225,7 +225,7 @@ static int recreate_encoder(Group_AV *group_av)
}

static Group_AV *new_group_av(Logger *log, Group_Chats *g_c, void (*audio_callback)(Messenger *, uint32_t, uint32_t,
const int16_t *, unsigned int, uint8_t, uint32_t, void *), void *userdata)
const int16_t *, unsigned int, uint8_t, unsigned int, void *), void *userdata)
{
if (!g_c) {
return nullptr;
Expand All @@ -246,7 +246,7 @@ static Group_AV *new_group_av(Logger *log, Group_Chats *g_c, void (*audio_callba
return group_av;
}

static void group_av_peer_new(void *object, uint32_t groupnumber, uint32_t friendgroupnumber)
static void group_av_peer_new(void *object, int groupnumber, int friendgroupnumber)
{
Group_AV *group_av = (Group_AV *)object;
Group_Peer_AV *peer_av = (Group_Peer_AV *)calloc(1, sizeof(Group_Peer_AV));
Expand All @@ -259,7 +259,7 @@ static void group_av_peer_new(void *object, uint32_t groupnumber, uint32_t frien
group_peer_set_object(group_av->g_c, groupnumber, friendgroupnumber, peer_av);
}

static void group_av_peer_delete(void *object, uint32_t groupnumber, uint32_t friendgroupnumber, void *peer_object)
static void group_av_peer_delete(void *object, int groupnumber, void *peer_object)
{
Group_Peer_AV *peer_av = (Group_Peer_AV *)peer_object;

Expand All @@ -275,15 +275,14 @@ static void group_av_peer_delete(void *object, uint32_t groupnumber, uint32_t fr
free(peer_object);
}

static void group_av_groupchat_delete(void *object, uint32_t groupnumber)
static void group_av_groupchat_delete(void *object, int groupnumber)
{
if (object) {
kill_group_av((Group_AV *)object);
}
}

static int decode_audio_packet(Group_AV *group_av, Group_Peer_AV *peer_av, uint32_t groupnumber,
uint32_t friendgroupnumber)
static int decode_audio_packet(Group_AV *group_av, Group_Peer_AV *peer_av, int groupnumber, int friendgroupnumber)
{
if (!group_av || !peer_av) {
return -1;
Expand Down Expand Up @@ -388,7 +387,7 @@ static int decode_audio_packet(Group_AV *group_av, Group_Peer_AV *peer_av, uint3
return -1;
}

static int handle_group_audio_packet(void *object, uint32_t groupnumber, uint32_t friendgroupnumber, void *peer_object,
static int handle_group_audio_packet(void *object, int groupnumber, int friendgroupnumber, void *peer_object,
const uint8_t *packet, uint16_t length)
{
if (!peer_object || !object || length <= sizeof(uint16_t)) {
Expand Down Expand Up @@ -426,10 +425,13 @@ static int handle_group_audio_packet(void *object, uint32_t groupnumber, uint32_
* return 0 on success.
* return -1 on failure.
*/
static int groupchat_enable_av(Logger *log, Group_Chats *g_c, uint32_t groupnumber, void (*audio_callback)(Messenger *,
uint32_t,
uint32_t, const int16_t *, unsigned int, uint8_t, uint32_t, void *), void *userdata)
static int groupchat_enable_av(Logger *log, Group_Chats *g_c, int groupnumber, void (*audio_callback)(Messenger *,
uint32_t, uint32_t, const int16_t *, unsigned int, uint8_t, unsigned int, void *), void *userdata)
{
if (groupnumber == -1) {
return -1;
}

Group_AV *group_av = new_group_av(log, g_c, audio_callback, userdata);

if (group_av == nullptr) {
Expand All @@ -454,11 +456,10 @@ static int groupchat_enable_av(Logger *log, Group_Chats *g_c, uint32_t groupnumb
* return -1 on failure.
*/
int add_av_groupchat(Logger *log, Group_Chats *g_c, void (*audio_callback)(Messenger *, uint32_t, uint32_t,
const int16_t *,
unsigned int,
uint8_t, uint32_t, void *), void *userdata)
const int16_t *, unsigned int,
uint8_t, unsigned int, void *), void *userdata)
{
int groupnumber = add_groupchat(g_c, GROUPCHAT_TYPE_AV);
int groupnumber = add_groupchat(g_c, GROUPCHAT_TYPE_AV, nullptr);

if (groupnumber == -1) {
return -1;
Expand All @@ -475,21 +476,21 @@ int add_av_groupchat(Logger *log, Group_Chats *g_c, void (*audio_callback)(Messe
/* Join a AV group (you need to have been invited first.)
*
* returns group number on success
* returns -1 on failure.
* returns -1 .. -6 on failure (see join_groupchat)
*/
int join_av_groupchat(Logger *log, Group_Chats *g_c, uint32_t friendnumber, const uint8_t *data, uint16_t length,
void (*audio_callback)(Messenger *, uint32_t, uint32_t, const int16_t *, unsigned int, uint8_t, uint32_t, void *),
void *userdata)
void (*audio_callback)(Messenger *, uint32_t, uint32_t, const int16_t *, unsigned int, uint8_t, unsigned int,
void *), void *userdata)
{
int groupnumber = join_groupchat(g_c, friendnumber, GROUPCHAT_TYPE_AV, data, length);

if (groupnumber == -1) {
return -1;
if (groupnumber < 0) {
return groupnumber;
}

if (groupchat_enable_av(log, g_c, groupnumber, audio_callback, userdata) == -1) {
del_groupchat(g_c, groupnumber);
return -1;
return -5; /* initialization failed */
}

return groupnumber;
Expand All @@ -500,21 +501,32 @@ int join_av_groupchat(Logger *log, Group_Chats *g_c, uint32_t friendnumber, cons
* return 0 on success.
* return -1 on failure.
*/
static int send_audio_packet(Group_Chats *g_c, uint32_t groupnumber, uint8_t *packet, uint16_t length)
static int send_audio_packet(Group_Chats *g_c, int groupnumber, uint8_t *packet, uint16_t length)
{
if (!length) {
return -1;
}

Group_AV *group_av = (Group_AV *)group_get_object(g_c, groupnumber);
VLA(uint8_t, data, 1 + sizeof(uint16_t) + length);
const size_t plen = 1 + sizeof(uint16_t) + length;

if (plen > MAX_CRYPTO_DATA_SIZE) {
return -1;
}

Group_AV *const group_av = (Group_AV *)group_get_object(g_c, groupnumber);

if (!group_av) {
return -1;
}

uint8_t data[MAX_CRYPTO_DATA_SIZE];
data[0] = GROUP_AUDIO_PACKET_ID;

uint16_t sequnum = net_htons(group_av->audio_sequnum);
const uint16_t sequnum = net_htons(group_av->audio_sequnum);
memcpy(data + 1, &sequnum, sizeof(sequnum));
memcpy(data + 1 + sizeof(sequnum), packet, length);

if (send_group_lossy_packet(g_c, groupnumber, data, SIZEOF_VLA(data)) == -1) {
if (send_group_lossy_packet(g_c, groupnumber, data, (uint16_t)plen) == -1) {
return -1;
}

Expand All @@ -527,8 +539,8 @@ static int send_audio_packet(Group_Chats *g_c, uint32_t groupnumber, uint8_t *pa
* return 0 on success.
* return -1 on failure.
*/
int group_send_audio(Group_Chats *g_c, uint32_t groupnumber, const int16_t *pcm, unsigned int samples, uint8_t channels,
uint32_t sample_rate)
int group_send_audio(Group_Chats *g_c, uint32_t groupnumber, const int16_t *pcm, unsigned int samples,
uint8_t channels, unsigned int sample_rate)
{
Group_AV *group_av = (Group_AV *)group_get_object(g_c, groupnumber);

Expand Down
4 changes: 2 additions & 2 deletions toxav/groupav.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,6 @@ int join_av_groupchat(Logger *log, Group_Chats *g_c, uint32_t friendnumber, cons
* return 0 on success.
* return -1 on failure.
*/
int group_send_audio(Group_Chats *g_c, uint32_t groupnumber, const int16_t *pcm, unsigned int samples, uint8_t channels,
uint32_t sample_rate);
int group_send_audio(Group_Chats *g_c, uint32_t groupnumber, const int16_t *pcm, unsigned int samples,
uint8_t channels, uint32_t sample_rate);

2 changes: 1 addition & 1 deletion toxav/toxav.api.h
Original file line number Diff line number Diff line change
Expand Up @@ -622,7 +622,7 @@ int toxav_add_av_groupchat(Tox *tox, void (*audio_callback)(void *, uint32_t, ui
/* Join a AV group (you need to have been invited first.)
*
* returns group number on success
* returns -1 on failure.
* returns < 0 on failure.
*
* Audio data callback format (same as the one for toxav_add_av_groupchat()):
* audio_callback(Tox *tox, uint32_t groupnumber, uint32_t peernumber, const int16_t *pcm, unsigned int samples, uint8_t channels, uint32_t sample_rate, void *userdata)
Expand Down
2 changes: 1 addition & 1 deletion toxav/toxav.h
Original file line number Diff line number Diff line change
Expand Up @@ -751,7 +751,7 @@ int toxav_add_av_groupchat(Tox *tox, void (*audio_callback)(void *, uint32_t, ui
/* Join a AV group (you need to have been invited first.)
*
* returns group number on success
* returns -1 on failure.
* returns < 0 on failure.
*
* Audio data callback format (same as the one for toxav_add_av_groupchat()):
* audio_callback(Tox *tox, uint32_t groupnumber, uint32_t peernumber, const int16_t *pcm, unsigned int samples, uint8_t channels, uint32_t sample_rate, void *userdata)
Expand Down
2 changes: 1 addition & 1 deletion toxav/toxav_old.c
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ int toxav_add_av_groupchat(Tox *tox, void (*audio_callback)(void *, uint32_t, ui
/* Join a AV group (you need to have been invited first.)
*
* returns group number on success
* returns -1 on failure.
* returns < 0 on failure.
*
* Audio data callback format (same as the one for toxav_add_av_groupchat()):
* audio_callback(Tox *tox, int groupnumber, int peernumber, const int16_t *pcm, unsigned int samples, uint8_t channels, unsigned int sample_rate, void *userdata)
Expand Down
44 changes: 43 additions & 1 deletion toxcore/Messenger.c
Original file line number Diff line number Diff line change
Expand Up @@ -2744,6 +2744,7 @@ void do_messenger(Messenger *m, void *userdata)
#define MESSENGER_STATE_TYPE_STATUS 6
#define MESSENGER_STATE_TYPE_TCP_RELAY 10
#define MESSENGER_STATE_TYPE_PATH_NODE 11
#define MESSENGER_STATE_TYPE_CONFERENCES 100
#define MESSENGER_STATE_TYPE_END 255

#define SAVED_FRIEND_REQUEST_SIZE 1024
Expand Down Expand Up @@ -2956,6 +2957,26 @@ static int friends_list_load(Messenger *m, const uint8_t *data, uint32_t length)
return num;
}

// Empty definitions of the conference load/save functions. These are set if the
// groups module is loaded. In tox_new, the group module is initialised, so
// public API users will never see calls to these functions.
static uint32_t saved_conferences_size_default(const Messenger *m)
{
return 0;
}
static void conferences_save_default(const Messenger *m, uint8_t *data)
{
}
static int conferences_load_default(Messenger *m, const uint8_t *data, uint32_t length)
{
return 0;
}

uint32_t (*saved_conferences_size_ptr)(const Messenger *m) = saved_conferences_size_default;
void (*conferences_save_ptr)(const Messenger *m, uint8_t *data) = conferences_save_default;
int (*conferences_load_ptr)(Messenger *m, const uint8_t *data, uint32_t length) = conferences_load_default;


/* return size of the messenger data (for saving) */
uint32_t messenger_size(const Messenger *m)
{
Expand All @@ -2969,6 +2990,7 @@ uint32_t messenger_size(const Messenger *m)
+ sizesubhead + 1 // status
+ sizesubhead + NUM_SAVED_TCP_RELAYS * packed_node_size(TCP_INET6) //TCP relays
+ sizesubhead + NUM_SAVED_PATH_NODES * packed_node_size(TCP_INET6) //saved path nodes
+ sizesubhead + saved_conferences_size_ptr(m) // old group chats
+ sizesubhead;
}

Expand Down Expand Up @@ -3060,6 +3082,12 @@ void messenger_save(const Messenger *m, uint8_t *data)
data += len;
}

len = saved_conferences_size_ptr(m);
type = MESSENGER_STATE_TYPE_CONFERENCES;
data = messenger_save_subheader(data, len, type);
conferences_save_ptr(m, data);
data += len;

messenger_save_subheader(data, 0, MESSENGER_STATE_TYPE_END);
}

Expand Down Expand Up @@ -3138,6 +3166,20 @@ static int messenger_load_state_callback(void *outer, const uint8_t *data, uint3
break;
}

case MESSENGER_STATE_TYPE_CONFERENCES: {
int err = conferences_load_ptr(m, data, length);

/* No need to do something special if err < 0
* err < 0 just means that conferences data was damaged
* and skipped
*/
if (err < 0) {
LOGGER_ERROR(m->log, "conference savedata was corrupted");
}

break;
}

case MESSENGER_STATE_TYPE_END: {
if (length != 0) {
return -1;
Expand All @@ -3147,7 +3189,7 @@ static int messenger_load_state_callback(void *outer, const uint8_t *data, uint3
}

default:
LOGGER_ERROR(m->log, "Load state: contains unrecognized part (len %u, type %u)\n",
LOGGER_ERROR(m->log, "Load state: contains unrecognized part (len %u, type %u)",
length, type);
break;
}
Expand Down
6 changes: 6 additions & 0 deletions toxcore/Messenger.h
Original file line number Diff line number Diff line change
Expand Up @@ -778,4 +778,10 @@ uint32_t count_friendlist(const Messenger *m);
* of out_list will be truncated to list_size. */
uint32_t copy_friendlist(const Messenger *m, uint32_t *out_list, uint32_t list_size);

// HACK HACK HACK to make conferences load/save work.
// TODO(robinlinden): Refactor this.
extern uint32_t (*saved_conferences_size_ptr)(const Messenger *m);
extern void (*conferences_save_ptr)(const Messenger *m, uint8_t *data);
extern int (*conferences_load_ptr)(Messenger *m, const uint8_t *data, uint32_t length);

#endif
Loading

0 comments on commit 590c92d

Please sign in to comment.