Make saving and loading the responsibility of Tox rather than Messenger

This commit is contained in:
zugz (tox) 2018-09-09 23:21:20 +02:00
parent aa5c782880
commit 744dc2f5da
No known key found for this signature in database
GPG Key ID: 6F2BDA289D04F249
10 changed files with 208 additions and 194 deletions

View File

@ -265,54 +265,11 @@ START_TEST(test_dht_state_saveloadsave)
}
END_TEST
START_TEST(test_messenger_state_saveloadsave)
{
/* validate that:
* a) saving stays within the confined space
* b) a save()d state can be load()ed back successfully
* c) a second save() is of equal size
* d) the second save() is of equal content */
const size_t extra = 64;
const size_t size = messenger_size(m);
VLA(uint8_t, buffer, size + 2 * extra);
memset(buffer, 0xCD, extra);
memset(buffer + extra + size, 0xCD, extra);
messenger_save(m, buffer + extra);
for (size_t i = 0; i < extra; i++) {
ck_assert_msg(buffer[i] == 0xCD, "Buffer underwritten from messenger_save() @%u", (unsigned)i);
ck_assert_msg(buffer[extra + size + i] == 0xCD, "Buffer overwritten from messenger_save() @%u", (unsigned)i);
}
const int res = messenger_load(m, buffer + extra, size);
if (res == -1) {
ck_assert_msg(res == 0, "Failed to load back stored buffer: res == -1");
} else {
const size_t offset = res >> 4;
const uint8_t *ptr = buffer + extra + offset;
ck_assert_msg(res == 0, "Failed to load back stored buffer: 0x%02x%02x%02x%02x%02x%02x%02x%02x @%u/%u, code %d",
ptr[-2], ptr[-1], ptr[0], ptr[1], ptr[2], ptr[3], ptr[4], ptr[5],
(unsigned)offset, (unsigned)size, res & 0x0F);
}
const size_t size2 = messenger_size(m);
ck_assert_msg(size == size2, "Messenger \"grew\" in size from a store/load cycle: %u -> %u",
(unsigned)size, (unsigned)size2);
VLA(uint8_t, buffer2, size2);
messenger_save(m, buffer2);
ck_assert_msg(!memcmp(buffer + extra, buffer2, size), "Messenger state changed by store/load/store cycle");
}
END_TEST
static Suite *messenger_suite(void)
{
Suite *s = suite_create("Messenger");
DEFTESTCASE(dht_state_saveloadsave);
DEFTESTCASE(messenger_state_saveloadsave);
DEFTESTCASE(getself_name);
DEFTESTCASE(m_get_userstatus_size);

View File

@ -100,10 +100,8 @@ int main(int argc, char *argv[])
}
/* with optional --ipvx, now it can be 1-4 arguments... */
if ((argc != argvoffset + 2) && (argc != argvoffset + 4)) {
if (argc != argvoffset + 4) {
printf("Usage: %s [--ipv4|--ipv6] ip port public_key (of the DHT bootstrap node)\n", argv[0]);
printf("or\n");
printf(" %s [--ipv4|--ipv6] Save.bak (to read Save.bak as state file)\n", argv[0]);
exit(0);
}
@ -134,19 +132,6 @@ int main(int argc, char *argv[])
printf("Failed to convert \"%s\" into an IP address. Exiting...\n", argv[argvoffset + 1]);
exit(1);
}
} else {
FILE *file = fopen(argv[argvoffset + 1], "rb");
if (file == nullptr) {
printf("Failed to open \"%s\" - does it exist?\n", argv[argvoffset + 1]);
return 1;
}
int read;
uint8_t buffer[128000];
read = fread(buffer, 1, 128000, file);
printf("Messenger loaded: %i\n", messenger_load(m, buffer, read));
fclose(file);
}
m_callback_friendrequest(m, print_request);

View File

@ -2831,7 +2831,7 @@ uint32_t dht_size(const DHT *dht)
/* Save the DHT in data where data is an array of size dht_size(). */
void dht_save(const DHT *dht, uint8_t *data)
{
host_to_lendian32(data, DHT_STATE_COOKIE_GLOBAL);
host_to_lendian_bytes32(data, DHT_STATE_COOKIE_GLOBAL);
data += sizeof(uint32_t);
uint8_t *const old_data = data;
@ -2960,7 +2960,7 @@ int dht_load(DHT *dht, const uint8_t *data, uint32_t length)
if (length > cookie_len) {
uint32_t data32;
lendian_to_host32(&data32, data);
lendian_bytes_to_host32(&data32, data);
if (data32 == DHT_STATE_COOKIE_GLOBAL) {
return state_load(dht->log, dht_load_state_callback, dht, data + cookie_len,

View File

@ -2739,10 +2739,6 @@ void do_messenger(Messenger *m, void *userdata)
/* new messenger format for load/save, more robust and forward compatible */
#define MESSENGER_STATE_COOKIE_GLOBAL 0x15ed1b1f
#define MESSENGER_STATE_COOKIE_TYPE 0x01ce
#define SAVED_FRIEND_REQUEST_SIZE 1024
#define NUM_SAVED_PATH_NODES 8
@ -2881,7 +2877,7 @@ static uint32_t m_state_plugins_size(const Messenger *m)
* returns true on success
* returns false on failure
*/
bool m_register_state_plugin(Messenger *m, Messenger_State_Type type, m_state_size_cb size_callback,
bool m_register_state_plugin(Messenger *m, State_Type type, m_state_size_cb size_callback,
m_state_load_cb load_callback,
m_state_save_cb save_callback)
{
@ -2904,7 +2900,7 @@ bool m_register_state_plugin(Messenger *m, Messenger_State_Type type, m_state_si
return true;
}
static uint32_t m_plugin_size(const Messenger *m, Messenger_State_Type type)
static uint32_t m_plugin_size(const Messenger *m, State_Type type)
{
for (uint8_t i = 0; i < m->options.state_plugins_length; ++i) {
const Messenger_State_Plugin plugin = m->options.state_plugins[i];
@ -2922,30 +2918,18 @@ static uint32_t m_plugin_size(const Messenger *m, Messenger_State_Type type)
/* return size of the messenger data (for saving) */
uint32_t messenger_size(const Messenger *m)
{
const uint32_t size32 = sizeof(uint32_t);
const uint32_t sizesubhead = size32 * 2;
return size32 * 2 // global cookie
+ m_state_plugins_size(m)
+ sizesubhead;
return m_state_plugins_size(m);
}
/* Save the messenger in data of size Messenger_size(). */
void messenger_save(const Messenger *m, uint8_t *data)
/* Save the messenger in data of size messenger_size(). */
uint8_t *messenger_save(const Messenger *m, uint8_t *data)
{
memset(data, 0, messenger_size(m));
const uint32_t size32 = sizeof(uint32_t);
// write cookie
memset(data, 0, size32);
data += size32;
host_to_lendian32(data, MESSENGER_STATE_COOKIE_GLOBAL);
data += size32;
for (uint8_t i = 0; i < m->options.state_plugins_length; ++i) {
const Messenger_State_Plugin plugin = m->options.state_plugins[i];
data = plugin.save(m, data);
}
return data;
}
// nospam state plugin
@ -2956,12 +2940,12 @@ static uint32_t nospam_keys_size(const Messenger *m)
static State_Load_Status load_nospam_keys(Messenger *m, const uint8_t *data, uint32_t length)
{
if (length != m_plugin_size(m, MESSENGER_STATE_TYPE_NOSPAMKEYS)) {
if (length != m_plugin_size(m, STATE_TYPE_NOSPAMKEYS)) {
return STATE_LOAD_STATUS_ERROR;
}
uint32_t nospam;
lendian_to_host32(&nospam, data);
lendian_bytes_to_host32(&nospam, data);
set_nospam(m->fr, nospam);
load_secret_key(m->net_crypto, data + sizeof(uint32_t) + CRYPTO_PUBLIC_KEY_SIZE);
@ -2974,11 +2958,11 @@ static State_Load_Status load_nospam_keys(Messenger *m, const uint8_t *data, uin
static uint8_t *save_nospam_keys(const Messenger *m, uint8_t *data)
{
const uint32_t len = m_plugin_size(m, MESSENGER_STATE_TYPE_NOSPAMKEYS);
const uint32_t len = m_plugin_size(m, STATE_TYPE_NOSPAMKEYS);
assert(sizeof(get_nospam(m->fr)) == sizeof(uint32_t));
data = state_write_section_header(data, MESSENGER_STATE_COOKIE_TYPE, len, MESSENGER_STATE_TYPE_NOSPAMKEYS);
data = state_write_section_header(data, STATE_COOKIE_TYPE, len, STATE_TYPE_NOSPAMKEYS);
uint32_t nospam = get_nospam(m->fr);
host_to_lendian32(data, nospam);
host_to_lendian_bytes32(data, nospam);
save_keys(m->net_crypto, data + sizeof(uint32_t));
data += len;
return data;
@ -2992,8 +2976,8 @@ static uint32_t m_dht_size(const Messenger *m)
static uint8_t *save_dht(const Messenger *m, uint8_t *data)
{
const uint32_t len = m_plugin_size(m, MESSENGER_STATE_TYPE_DHT);
data = state_write_section_header(data, MESSENGER_STATE_COOKIE_TYPE, len, MESSENGER_STATE_TYPE_DHT);
const uint32_t len = m_plugin_size(m, STATE_TYPE_DHT);
data = state_write_section_header(data, STATE_COOKIE_TYPE, len, STATE_TYPE_DHT);
dht_save(m->dht, data);
data += len;
return data;
@ -3013,8 +2997,8 @@ static uint32_t saved_friendslist_size(const Messenger *m)
static uint8_t *friends_list_save(const Messenger *m, uint8_t *data)
{
const uint32_t len = m_plugin_size(m, MESSENGER_STATE_TYPE_FRIENDS);
data = state_write_section_header(data, MESSENGER_STATE_COOKIE_TYPE, len, MESSENGER_STATE_TYPE_FRIENDS);
const uint32_t len = m_plugin_size(m, STATE_TYPE_FRIENDS);
data = state_write_section_header(data, STATE_COOKIE_TYPE, len, STATE_TYPE_FRIENDS);
uint32_t num = 0;
uint8_t *cur_data = data;
@ -3119,8 +3103,8 @@ static uint32_t name_size(const Messenger *m)
static uint8_t *save_name(const Messenger *m, uint8_t *data)
{
const uint32_t len = m_plugin_size(m, MESSENGER_STATE_TYPE_NAME);
data = state_write_section_header(data, MESSENGER_STATE_COOKIE_TYPE, len, MESSENGER_STATE_TYPE_NAME);
const uint32_t len = m_plugin_size(m, STATE_TYPE_NAME);
data = state_write_section_header(data, STATE_COOKIE_TYPE, len, STATE_TYPE_NAME);
memcpy(data, m->name, len);
data += len;
return data;
@ -3143,8 +3127,8 @@ static uint32_t status_message_size(const Messenger *m)
static uint8_t *save_status_message(const Messenger *m, uint8_t *data)
{
const uint32_t len = m_plugin_size(m, MESSENGER_STATE_TYPE_STATUSMESSAGE);
data = state_write_section_header(data, MESSENGER_STATE_COOKIE_TYPE, len, MESSENGER_STATE_TYPE_STATUSMESSAGE);
const uint32_t len = m_plugin_size(m, STATE_TYPE_STATUSMESSAGE);
data = state_write_section_header(data, STATE_COOKIE_TYPE, len, STATE_TYPE_STATUSMESSAGE);
memcpy(data, m->statusmessage, len);
data += len;
return data;
@ -3167,8 +3151,8 @@ static uint32_t status_size(const Messenger *m)
static uint8_t *save_status(const Messenger *m, uint8_t *data)
{
const uint32_t len = m_plugin_size(m, MESSENGER_STATE_TYPE_STATUS);
data = state_write_section_header(data, MESSENGER_STATE_COOKIE_TYPE, len, MESSENGER_STATE_TYPE_STATUS);
const uint32_t len = m_plugin_size(m, STATE_TYPE_STATUS);
data = state_write_section_header(data, STATE_COOKIE_TYPE, len, STATE_TYPE_STATUS);
*data = m->userstatus;
data += len;
return data;
@ -3193,7 +3177,7 @@ static uint8_t *save_tcp_relays(const Messenger *m, uint8_t *data)
{
Node_format relays[NUM_SAVED_TCP_RELAYS];
uint8_t *temp_data = data;
data = state_write_section_header(temp_data, MESSENGER_STATE_COOKIE_TYPE, 0, MESSENGER_STATE_TYPE_TCP_RELAY);
data = state_write_section_header(temp_data, STATE_COOKIE_TYPE, 0, STATE_TYPE_TCP_RELAY);
uint32_t num = copy_connected_tcp_relays(m->net_crypto, relays, NUM_SAVED_TCP_RELAYS);
if (m->num_loaded_relays > 0) {
@ -3205,7 +3189,7 @@ static uint8_t *save_tcp_relays(const Messenger *m, uint8_t *data)
if (l > 0) {
const uint32_t len = l;
data = state_write_section_header(temp_data, MESSENGER_STATE_COOKIE_TYPE, len, MESSENGER_STATE_TYPE_TCP_RELAY);
data = state_write_section_header(temp_data, STATE_COOKIE_TYPE, len, STATE_TYPE_TCP_RELAY);
data += len;
}
@ -3232,14 +3216,14 @@ static uint8_t *save_path_nodes(const Messenger *m, uint8_t *data)
{
Node_format nodes[NUM_SAVED_PATH_NODES];
uint8_t *temp_data = data;
data = state_write_section_header(data, MESSENGER_STATE_COOKIE_TYPE, 0, MESSENGER_STATE_TYPE_PATH_NODE);
data = state_write_section_header(data, STATE_COOKIE_TYPE, 0, STATE_TYPE_PATH_NODE);
memset(nodes, 0, sizeof(nodes));
const unsigned int num = onion_backup_nodes(m->onion_c, nodes, NUM_SAVED_PATH_NODES);
const int l = pack_nodes(data, NUM_SAVED_PATH_NODES * packed_node_size(net_family_tcp_ipv6), nodes, num);
if (l > 0) {
const uint32_t len = l;
data = state_write_section_header(temp_data, MESSENGER_STATE_COOKIE_TYPE, len, MESSENGER_STATE_TYPE_PATH_NODE);
data = state_write_section_header(temp_data, STATE_COOKIE_TYPE, len, STATE_TYPE_PATH_NODE);
data += len;
}
@ -3261,77 +3245,32 @@ static State_Load_Status load_path_nodes(Messenger *m, const uint8_t *data, uint
return STATE_LOAD_STATUS_CONTINUE;
}
// end state plugin
static uint32_t end_size(const Messenger *m)
{
return 0;
}
static uint8_t *save_end(const Messenger *m, uint8_t *data)
{
return state_write_section_header(data, MESSENGER_STATE_COOKIE_TYPE, 0, MESSENGER_STATE_TYPE_END);
}
static State_Load_Status load_end(Messenger *m, const uint8_t *data, uint32_t length)
{
if (length != 0) {
return STATE_LOAD_STATUS_ERROR;
}
return STATE_LOAD_STATUS_END;
}
static void m_register_default_plugins(Messenger *m)
{
m_register_state_plugin(m, MESSENGER_STATE_TYPE_NOSPAMKEYS, nospam_keys_size, load_nospam_keys, save_nospam_keys);
m_register_state_plugin(m, MESSENGER_STATE_TYPE_DHT, m_dht_size, m_dht_load, save_dht);
m_register_state_plugin(m, MESSENGER_STATE_TYPE_FRIENDS, saved_friendslist_size, friends_list_load, friends_list_save);
m_register_state_plugin(m, MESSENGER_STATE_TYPE_NAME, name_size, load_name, save_name);
m_register_state_plugin(m, MESSENGER_STATE_TYPE_STATUSMESSAGE, status_message_size, load_status_message,
m_register_state_plugin(m, STATE_TYPE_NOSPAMKEYS, nospam_keys_size, load_nospam_keys, save_nospam_keys);
m_register_state_plugin(m, STATE_TYPE_DHT, m_dht_size, m_dht_load, save_dht);
m_register_state_plugin(m, STATE_TYPE_FRIENDS, saved_friendslist_size, friends_list_load, friends_list_save);
m_register_state_plugin(m, STATE_TYPE_NAME, name_size, load_name, save_name);
m_register_state_plugin(m, STATE_TYPE_STATUSMESSAGE, status_message_size, load_status_message,
save_status_message);
m_register_state_plugin(m, MESSENGER_STATE_TYPE_STATUS, status_size, load_status, save_status);
m_register_state_plugin(m, MESSENGER_STATE_TYPE_TCP_RELAY, tcp_relay_size, load_tcp_relays, save_tcp_relays);
m_register_state_plugin(m, MESSENGER_STATE_TYPE_PATH_NODE, path_node_size, load_path_nodes, save_path_nodes);
m_register_state_plugin(m, MESSENGER_STATE_TYPE_END, end_size, load_end, save_end);
m_register_state_plugin(m, STATE_TYPE_STATUS, status_size, load_status, save_status);
m_register_state_plugin(m, STATE_TYPE_TCP_RELAY, tcp_relay_size, load_tcp_relays, save_tcp_relays);
m_register_state_plugin(m, STATE_TYPE_PATH_NODE, path_node_size, load_path_nodes, save_path_nodes);
}
static State_Load_Status messenger_load_state_callback(void *outer, const uint8_t *data, uint32_t length, uint16_t type)
bool messenger_load_state_section(Messenger *m, const uint8_t *data, uint32_t length, uint16_t type,
State_Load_Status *status)
{
Messenger *m = (Messenger *)outer;
for (uint8_t i = 0; i < m->options.state_plugins_length; ++i) {
const Messenger_State_Plugin *const plugin = &m->options.state_plugins[i];
if (plugin->type == type) {
return plugin->load(m, data, length);
*status = plugin->load(m, data, length);
return true;
}
}
LOGGER_ERROR(m->log, "Load state: contains unrecognized part (len %u, type %u)\n",
length, type);
return STATE_LOAD_STATUS_CONTINUE;
}
/* Load the messenger from data of size length. */
int messenger_load(Messenger *m, const uint8_t *data, uint32_t length)
{
uint32_t data32[2];
uint32_t cookie_len = sizeof(data32);
if (length < cookie_len) {
return -1;
}
memcpy(data32, data, sizeof(uint32_t));
lendian_to_host32(data32 + 1, data + sizeof(uint32_t));
if (!data32[0] && (data32[1] == MESSENGER_STATE_COOKIE_GLOBAL)) {
return state_load(m->log, messenger_load_state_callback, m, data + cookie_len,
length - cookie_len, MESSENGER_STATE_COOKIE_TYPE);
}
return -1;
return false;
}
/* Return the number of friends in the instance m.

View File

@ -62,20 +62,8 @@ typedef uint8_t *m_state_save_cb(const Messenger *m, uint8_t *data);
// Returns if there were any erros during loading
typedef State_Load_Status m_state_load_cb(Messenger *m, const uint8_t *data, uint32_t length);
typedef enum Messenger_State_Type {
MESSENGER_STATE_TYPE_NOSPAMKEYS = 1,
MESSENGER_STATE_TYPE_DHT = 2,
MESSENGER_STATE_TYPE_FRIENDS = 3,
MESSENGER_STATE_TYPE_NAME = 4,
MESSENGER_STATE_TYPE_STATUSMESSAGE = 5,
MESSENGER_STATE_TYPE_STATUS = 6,
MESSENGER_STATE_TYPE_TCP_RELAY = 10,
MESSENGER_STATE_TYPE_PATH_NODE = 11,
MESSENGER_STATE_TYPE_END = 255,
} Messenger_State_Type;
typedef struct Messenger_State_Plugin {
Messenger_State_Type type;
State_Type type;
m_state_size_cb *size;
m_state_save_cb *save;
m_state_load_cb *load;
@ -797,17 +785,22 @@ uint32_t messenger_run_interval(const Messenger *m);
* returns true on success
* returns false on error
*/
bool m_register_state_plugin(Messenger *m, Messenger_State_Type type, m_state_size_cb size_callback,
bool m_register_state_plugin(Messenger *m, State_Type type, m_state_size_cb size_callback,
m_state_load_cb load_callback, m_state_save_cb save_callback);
/* return size of the messenger data (for saving). */
uint32_t messenger_size(const Messenger *m);
/* Save the messenger in data (must be allocated memory of size Messenger_size()) */
void messenger_save(const Messenger *m, uint8_t *data);
/* Save the messenger in data (must be allocated memory of size at least Messenger_size()) */
uint8_t *messenger_save(const Messenger *m, uint8_t *data);
/* Load the messenger from data of size length. */
int messenger_load(Messenger *m, const uint8_t *data, uint32_t length);
/* Load a state section.
*
* @param status Result of loading section is stored here if the section is handled.
* @return true iff section handled.
*/
bool messenger_load_state_section(Messenger *m, const uint8_t *data, uint32_t length, uint16_t type,
State_Load_Status *status);
/* Return the number of friends in the instance m.
* You should use this to determine how much memory to allocate

View File

@ -2875,6 +2875,22 @@ void send_name_all_groups(Group_Chats *g_c)
}
}
uint32_t conferences_size(const Group_Chats *g_c)
{
return 0;
}
uint8_t *conferences_save(const Group_Chats *g_c, uint8_t *data)
{
return data;
}
bool conferences_load_state_section(Group_Chats *g_c, const uint8_t *data, uint32_t length, uint16_t type,
State_Load_Status *status)
{
return false;
}
/* Create new groupchat instance. */
Group_Chats *new_groupchats(Mono_Time *mono_time, Messenger *m)
{

View File

@ -448,6 +448,21 @@ int callback_groupchat_peer_delete(Group_Chats *g_c, uint32_t groupnumber, peer_
*/
int callback_groupchat_delete(Group_Chats *g_c, uint32_t groupnumber, group_on_delete_cb *function);
/* Return size of the conferences data (for saving). */
uint32_t conferences_size(const Group_Chats *g_c);
/* Save the conferences in data (must be allocated memory of size at least conferences_size()) */
uint8_t *conferences_save(const Group_Chats *g_c, uint8_t *data);
/**
* Load a section.
*
* @param status Result of loading section is stored here if the section is handled.
* @return true iff section handled.
*/
bool conferences_load_state_section(Group_Chats *g_c, const uint8_t *data, uint32_t length, uint16_t type,
State_Load_Status *status);
/* Create new groupchat instance. */
Group_Chats *new_groupchats(Mono_Time *mono_time, Messenger *m);

View File

@ -16,10 +16,10 @@ int state_load(const Logger *log, state_load_cb *state_load_callback, void *oute
while (length >= size_head) {
uint32_t length_sub;
lendian_to_host32(&length_sub, data);
lendian_bytes_to_host32(&length_sub, data);
uint32_t cookie_type;
lendian_to_host32(&cookie_type, data + sizeof(uint32_t));
lendian_bytes_to_host32(&cookie_type, data + sizeof(uint32_t));
data += size_head;
length -= size_head;
@ -63,9 +63,9 @@ int state_load(const Logger *log, state_load_cb *state_load_callback, void *oute
uint8_t *state_write_section_header(uint8_t *data, uint16_t cookie_type, uint32_t len, uint32_t section_type)
{
host_to_lendian32(data, len);
host_to_lendian_bytes32(data, len);
data += sizeof(uint32_t);
host_to_lendian32(data, (host_tolendian16(cookie_type) << 16) | host_tolendian16(section_type));
host_to_lendian_bytes32(data, (host_to_lendian16(cookie_type) << 16) | host_to_lendian16(section_type));
data += sizeof(uint32_t);
return data;
}
@ -79,12 +79,12 @@ uint16_t lendian_to_host16(uint16_t lendian)
#endif
}
uint16_t host_tolendian16(uint16_t host)
uint16_t host_to_lendian16(uint16_t host)
{
return lendian_to_host16(host);
}
void host_to_lendian32(uint8_t *dest, uint32_t num)
void host_to_lendian_bytes32(uint8_t *dest, uint32_t num)
{
#ifdef WORDS_BIGENDIAN
num = ((num << 8) & 0xFF00FF00) | ((num >> 8) & 0xFF00FF);
@ -93,7 +93,7 @@ void host_to_lendian32(uint8_t *dest, uint32_t num)
memcpy(dest, &num, sizeof(uint32_t));
}
void lendian_to_host32(uint32_t *dest, const uint8_t *lendian)
void lendian_bytes_to_host32(uint32_t *dest, const uint8_t *lendian)
{
uint32_t d;
memcpy(&d, lendian, sizeof(uint32_t));
@ -103,3 +103,21 @@ void lendian_to_host32(uint32_t *dest, const uint8_t *lendian)
#endif
*dest = d;
}
void host_to_lendian_bytes16(uint8_t *dest, uint16_t num)
{
#ifdef WORDS_BIGENDIAN
num = (num << 8) | (num >> 8);
#endif
memcpy(dest, &num, sizeof(uint16_t));
}
void lendian_bytes_to_host16(uint16_t *dest, const uint8_t *lendian)
{
uint16_t d;
memcpy(&d, lendian, sizeof(uint16_t));
#ifdef WORDS_BIGENDIAN
d = (d << 8) | (d >> 8);
#endif
*dest = d;
}

View File

@ -18,6 +18,22 @@
extern "C" {
#endif
#define STATE_COOKIE_GLOBAL 0x15ed1b1f
#define STATE_COOKIE_TYPE 0x01ce
typedef enum State_Type {
STATE_TYPE_NOSPAMKEYS = 1,
STATE_TYPE_DHT = 2,
STATE_TYPE_FRIENDS = 3,
STATE_TYPE_NAME = 4,
STATE_TYPE_STATUSMESSAGE = 5,
STATE_TYPE_STATUS = 6,
STATE_TYPE_TCP_RELAY = 10,
STATE_TYPE_PATH_NODE = 11,
STATE_TYPE_END = 255,
} State_Type;
// Returned by the state_load_cb to instruct the loader on what to do next.
typedef enum State_Load_Status {
// Continue loading state data sections.
@ -39,10 +55,13 @@ uint8_t *state_write_section_header(uint8_t *data, uint16_t cookie_type, uint32_
// Utilities for state data serialisation.
uint16_t lendian_to_host16(uint16_t lendian);
uint16_t host_tolendian16(uint16_t host);
uint16_t host_to_lendian16(uint16_t host);
void host_to_lendian32(uint8_t *dest, uint32_t num);
void lendian_to_host32(uint32_t *dest, const uint8_t *lendian);
void host_to_lendian_bytes32(uint8_t *dest, uint32_t num);
void lendian_bytes_to_host32(uint32_t *dest, const uint8_t *lendian);
void host_to_lendian_bytes16(uint8_t *dest, uint16_t num);
void lendian_bytes_to_host16(uint16_t *dest, const uint8_t *lendian);
#ifdef __cplusplus
} // extern "C"

View File

@ -328,6 +328,51 @@ bool tox_version_is_compatible(uint32_t major, uint32_t minor, uint32_t patch)
return TOX_VERSION_IS_API_COMPATIBLE(major, minor, patch);
}
static State_Load_Status state_load_callback(void *outer, const uint8_t *data, uint32_t length, uint16_t type)
{
Tox *tox = (Tox *)outer;
State_Load_Status status = STATE_LOAD_STATUS_CONTINUE;
if (messenger_load_state_section(tox->m, data, length, type, &status)
|| conferences_load_state_section(tox->m->conferences_object, data, length, type, &status)) {
return status;
}
if (type == STATE_TYPE_END) {
if (length != 0) {
return STATE_LOAD_STATUS_ERROR;
}
return STATE_LOAD_STATUS_END;
}
LOGGER_ERROR(tox->m->log, "Load state: contains unrecognized part (len %u, type %u)\n",
length, type);
return STATE_LOAD_STATUS_CONTINUE;
}
/* Load tox from data of size length. */
static int tox_load(Tox *tox, const uint8_t *data, uint32_t length)
{
uint32_t data32[2];
uint32_t cookie_len = sizeof(data32);
if (length < cookie_len) {
return -1;
}
memcpy(data32, data, sizeof(uint32_t));
lendian_bytes_to_host32(data32 + 1, data + sizeof(uint32_t));
if (data32[0] != 0 || data32[1] != STATE_COOKIE_GLOBAL) {
return -1;
}
return state_load(tox->m->log, state_load_callback, tox, data + cookie_len,
length - cookie_len, STATE_COOKIE_TYPE);
}
Tox *tox_new(const struct Tox_Options *options, Tox_Err_New *error)
{
@ -488,7 +533,7 @@ Tox *tox_new(const struct Tox_Options *options, Tox_Err_New *error)
}
if (load_savedata_tox
&& messenger_load(m, tox_options_get_savedata_data(opts), tox_options_get_savedata_length(opts)) == -1) {
&& tox_load(tox, tox_options_get_savedata_data(opts), tox_options_get_savedata_length(opts)) == -1) {
SET_ERROR_PARAMETER(error, TOX_ERR_NEW_LOAD_BAD_FORMAT);
} else if (load_savedata_sk) {
load_secret_key(m->net_crypto, tox_options_get_savedata_data(opts));
@ -537,18 +582,45 @@ void tox_kill(Tox *tox)
free(tox);
}
static uint32_t end_size(void)
{
return 2 * sizeof(uint32_t);
}
static void end_save(uint8_t *data)
{
state_write_section_header(data, STATE_COOKIE_TYPE, 0, STATE_TYPE_END);
}
size_t tox_get_savedata_size(const Tox *tox)
{
const Messenger *m = tox->m;
return messenger_size(m);
return 2 * sizeof(uint32_t)
+ messenger_size(m)
+ conferences_size(m->conferences_object)
+ end_size();
}
void tox_get_savedata(const Tox *tox, uint8_t *savedata)
{
if (savedata) {
const Messenger *m = tox->m;
messenger_save(m, savedata);
if (savedata == nullptr) {
return;
}
memset(savedata, 0, tox_get_savedata_size(tox));
const uint32_t size32 = sizeof(uint32_t);
// write cookie
memset(savedata, 0, size32);
savedata += size32;
host_to_lendian_bytes32(savedata, STATE_COOKIE_GLOBAL);
savedata += size32;
const Messenger *m = tox->m;
savedata = messenger_save(m, savedata);
savedata = conferences_save(m->conferences_object, savedata);
end_save(savedata);
}
bool tox_bootstrap(Tox *tox, const char *host, uint16_t port, const uint8_t *public_key, Tox_Err_Bootstrap *error)