diff --git a/auto_tests/messenger_test.c b/auto_tests/messenger_test.c index dd644e50..e885e652 100644 --- a/auto_tests/messenger_test.c +++ b/auto_tests/messenger_test.c @@ -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); diff --git a/testing/Messenger_test.c b/testing/Messenger_test.c index 5abb3998..a61d0dcf 100644 --- a/testing/Messenger_test.c +++ b/testing/Messenger_test.c @@ -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); diff --git a/toxcore/DHT.c b/toxcore/DHT.c index 8208052d..4908de32 100644 --- a/toxcore/DHT.c +++ b/toxcore/DHT.c @@ -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, diff --git a/toxcore/Messenger.c b/toxcore/Messenger.c index e092a9f2..ae2d1d3b 100644 --- a/toxcore/Messenger.c +++ b/toxcore/Messenger.c @@ -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. diff --git a/toxcore/Messenger.h b/toxcore/Messenger.h index 0d80bd0d..1651315e 100644 --- a/toxcore/Messenger.h +++ b/toxcore/Messenger.h @@ -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 diff --git a/toxcore/group.c b/toxcore/group.c index 5feb483b..ee9548a1 100644 --- a/toxcore/group.c +++ b/toxcore/group.c @@ -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) { diff --git a/toxcore/group.h b/toxcore/group.h index 7acd4637..8673abdb 100644 --- a/toxcore/group.h +++ b/toxcore/group.h @@ -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); diff --git a/toxcore/state.c b/toxcore/state.c index 29b4af88..919c2e8c 100644 --- a/toxcore/state.c +++ b/toxcore/state.c @@ -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; +} diff --git a/toxcore/state.h b/toxcore/state.h index 2d1f62c3..872b1e9d 100644 --- a/toxcore/state.h +++ b/toxcore/state.h @@ -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" diff --git a/toxcore/tox.c b/toxcore/tox.c index e679a168..629cc1c5 100644 --- a/toxcore/tox.c +++ b/toxcore/tox.c @@ -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)