From 1a39c397c57cfc2008d432cc38458a45b961aff0 Mon Sep 17 00:00:00 2001 From: slvr Date: Mon, 12 Aug 2013 13:08:03 +0100 Subject: [PATCH 1/8] Implemented Deadline Timer and timer_test --- core/CMakeLists.txt | 3 +- core/timer.c | 273 +++++++++++++++++++++++++++++++++ core/timer.h | 104 +++++++++++++ testing/CMakeLists.txt | 1 + testing/cmake/timer_test.cmake | 9 ++ testing/timer_test.c | 66 ++++++++ 6 files changed, 455 insertions(+), 1 deletion(-) create mode 100644 core/timer.c create mode 100644 core/timer.h create mode 100644 testing/cmake/timer_test.cmake create mode 100644 testing/timer_test.c diff --git a/core/CMakeLists.txt b/core/CMakeLists.txt index 55a41912..ad6eea01 100644 --- a/core/CMakeLists.txt +++ b/core/CMakeLists.txt @@ -10,7 +10,8 @@ set(core_sources LAN_discovery.c Messenger.c util.c - ping.c) + ping.c + timer.c) if(SHARED_TOXCORE) add_library(toxcore SHARED ${core_sources}) diff --git a/core/timer.c b/core/timer.c new file mode 100644 index 00000000..74a2831d --- /dev/null +++ b/core/timer.c @@ -0,0 +1,273 @@ +#include "timer.h" +#include "network.h" +#include + +/* +A nested linked list increases efficiency of insertions. +Depending on the number of timers we have, we might need to have nested linked lists +in order to improve insertion efficiency. +The code below is preperation for that end, should it be necessary. + +typedef struct { + struct timer_package* _next; + union { + timer_packet* _inner; + timer* queue; + }; + uint64_t pkgtime; +} timer_package; + +timer_package* timer_package_pool; + +static timer_package* new_package() +{ + timer_package* ret; + if (timer_package_pool) { + ret = timer_package_pool; + timer_package_pool = timer_package_pool->_next; + } else { + ret = calloc(1, sizeof(struct timer_package)); + } + return ret; +} + +static void delete_package(timer_package* p) +{ + p->_next = timer_package_pool; + timer_package_pool = p; +} +*/ + +enum timer_state { + STATE_INACTIVE = 0, + STATE_ACTIVE, + STATE_CALLBACK +}; + +struct timer +{ + enum timer_state state; + timer* _prev; + timer* _next; + timer_callback cb; + void* userdata; + uint64_t deadline; +}; + +static timer* timer_main_queue; +static timer* timer_us_queue; /* hi-speed queue */ + +inline static void timer_dequeue(timer* t, timer** queue) +{ + if (t->state == STATE_INACTIVE) return; /* not in a queue */ + + if (t->_prev) { + t->_prev->_next = t->_next; + } else { + *queue = t->_next; + } + if (t->_next) t->_next->_prev = t->_prev; + t->state = STATE_INACTIVE; +} + +static void timer_enqueue(timer* t, timer** queue, timer* prev) +{ + t->state = STATE_ACTIVE; + while (true) { + if (!*queue) { + t->_next = 0; + t->_prev = prev; + *queue = t; + return; + } + + if ((*queue)->deadline > t->deadline) { + (*queue)->_prev = t; + t->_next = *queue; + t->_prev = prev; + *queue = t; + return; + } + + prev = *queue; + queue = &((*queue)->_next); + } +} + +/*** interface ***/ + +void timer_init() +{ + /* Nothing needs to be done... yet. */ +} + +/* Do not depend on fields being zeroed */ +static timer* timer_pool; /* timer_pool is SINGLY LINKED!! */ + +timer* timer_new(void) +{ + timer* ret; + if (timer_pool) { + ret = timer_pool; + timer_pool = timer_pool->_next; + } else { + ret = calloc(1, sizeof(struct timer)); + } + ret->state = STATE_INACTIVE; + return ret; +} + +void timer_delete(timer* t) +{ + timer_dequeue(t, &timer_main_queue); + t->_next = timer_pool; + t->state = STATE_INACTIVE; + timer_pool = t; +} + +void timer_setup(timer* t, timer_callback cb, void* userarg) +{ + t->cb = cb; + t->userdata = userarg; +} + +void* timer_get_userdata(timer* t) +{ + return t->userdata; +} + +static void timer_delay_us(timer* t, int us) +{ + t->deadline += us; + timer** queue = t->_prev ? &(t->_prev->_next) : &timer_main_queue; + timer_dequeue(t, &timer_main_queue); + timer_enqueue(t, queue, t->_prev); +} + +/* Starts the timer so that it's called in sec seconds in the future. + * A non-positive value of sec results in the callback being called immediately. + * This function may be called again after a timer has been started to adjust + * the expiry time. */ +void timer_start(timer* t, int sec) +{ + uint64_t newdeadline = current_time() + sec * US_PER_SECOND; + if (timer_is_active(t)){ + if (t->deadline < newdeadline) { + timer_delay_us(t, newdeadline - t->deadline); + return; + } + timer_dequeue(t, &timer_main_queue); + } + t->deadline = newdeadline; + timer_enqueue(t, &timer_main_queue, 0); +} + +/* Stops the timer. Returns -1 if the timer was not active. */ +int timer_stop(timer* t) +{ + int ret = timer_is_active(t) ? -1 : 0; + timer_dequeue(t, &timer_main_queue); + return ret; +} + +/* Adds additionalsec seconds to the timer. + * Returns -1 and does nothing if the timer was not active. */ +int timer_delay(timer* t, int additonalsec) +{ + if (!timer_is_active(t)) return -1; + timer_delay_us(t, additonalsec * US_PER_SECOND); + return 0; +} + +static uint64_t timer_diff(timer* t, uint64_t time) +{ + if (t->deadline <= time) return 0; + return time - t->deadline; +} + +/* Returns the time remaining on a timer in seconds. + * Returns -1 if the timer is not active. + * Returns 0 if the timer has expired and will be called upon the next call to timer_poll. */ +int timer_time_remaining(timer* t) +{ + if (!timer_is_active(t)) return -1; + return timer_diff(t, current_time()) / US_PER_SECOND; +} + +bool timer_is_active(timer* t) +{ + return t->state != STATE_INACTIVE; +} + +/* Single-use timer. + * Creates a new timer, preforms setup and starts it. */ +void timer_single(timer_callback cb, void* userarg, int sec) +{ + timer* t = timer_new(); + timer_setup(t, cb, userarg); + timer_start(t, sec); +} + +/* Single-use microsecond timer. */ +void timer_us(timer_callback cb, void* userarg, int us) +{ + timer* t = timer_new(); + timer_setup(t, cb, userarg); + t->deadline = current_time() + us; + t->state = STATE_ACTIVE; + timer_enqueue(t, &timer_us_queue, 0); +} + +uint64_t prevtime = 0; +void timer_poll(void) +{ + uint64_t time = current_time(); + + /* Handle millisecond timers */ + while (timer_us_queue) { + if (timer_diff(timer_us_queue, time) != 0) break; + timer* t = timer_us_queue; + timer_dequeue(t, &timer_us_queue); + t->cb(0, t->userdata); + timer_delete(t); + } + + if (time - prevtime > US_PER_SECOND || prevtime == 0 || prevtime > time) { + /* time moving backwards is just a sanity check */ + prevtime = time; + + while (timer_main_queue) { + if (timer_diff(timer_main_queue, time) != 0) break; + timer* t = timer_main_queue; + t->state = STATE_CALLBACK; + int rv = t->cb(t, t->userdata); + if (rv != 0) { + timer_dequeue(t, &timer_main_queue); + timer_delete(t); + continue; + } + if (t->state != STATE_ACTIVE) { + timer_dequeue(t, &timer_main_queue); + } + } + } +} + +/*** Internal Testing ***/ + +/* I do not want to expose internals to the public, + * which is why internals testing is done this way. */ +void timer_internal_tests(bool (*assert)(bool, char*)) +{ + +} + +void timer_debug_print() +{ + timer* t = timer_main_queue; + printf("Queue:\n"); + while (t) { + printf("%lli (%lli) : %s\n", t->deadline, t->deadline/US_PER_SECOND, (char*)t->userdata); + t = t->_next; + } +} diff --git a/core/timer.h b/core/timer.h new file mode 100644 index 00000000..fee66f29 --- /dev/null +++ b/core/timer.h @@ -0,0 +1,104 @@ +/* timer.h + * + * Timing subsystem. Provides deadline timers. + * All times are aliased to a second for efficiency. + * + * Timer Guarantees: + * - The callback will not be called before the timer expires. + * - The callback will be called sometime after the timer expires, + * on a best effort basis. + * - If timer_poll is called at least once a second, the callback + * will be called at most one second after it expires. + * + * Copyright (C) 2013 Tox project All Rights Reserved. + * + * This file is part of Tox. + * + * Tox is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Tox is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Tox. If not, see . + * + */ + +#ifndef TIMER_H +#define TIMER_H + +#include +#include + +#define US_PER_SECOND 1000000 /* 1 s = 10^6 us */ + +struct timer; +typedef struct timer timer; + +/* If time_callback returns a non-zero value, timer t is deleted. + * You may call any of the timer functions within the callback: + * For example, you may call timer_start to restart the timer from + * within a callback. */ +typedef int (*timer_callback)(timer* t, void* userarg); + +/* Initisalise timer subsystem */ +void timer_init(void); + +/* Poll. (I will eventually replace all polling in Tox with an async system.) */ +void timer_poll(void); + +/* Creates a new timer. Does not enqueue/start it. */ +timer* timer_new(void); + +/* Destroys a timer instance. */ +void timer_delete(timer* t); + +/* Sets up the timer callback. */ +void timer_setup(timer* t, timer_callback cb, void* userarg); + +/* Accessor Function. */ +void* timer_get_userdata(timer* t); + +/* Starts the timer so that it's called in sec seconds in the future from now. + * A non-positive value of sec results in the callback being called immediately. + * This function may be called again after a timer has been started to adjust + * the expiry time. */ +void timer_start(timer* t, int sec); + +/* Stops the timer. Returns -1 if the timer was not active. */ +int timer_stop(timer* t); + +/* Adds additionalsec seconds to the timer. + * Returns -1 and does nothing if the timer was not active. */ +int timer_delay(timer* t, int additonalsec); + +/* Returns the time remaining on a timer in seconds. + * Returns -1 if the timer is not active. + * Returns 0 if the timer has expired and the callback hasn't been called yet. */ +int timer_time_remaining(timer* t); + +/* Determines if timer is active. Returns TRUE if it is active */ +bool timer_is_active(timer* t); + +/* Single-use timer. + * Creates a new timer, preforms setup and starts it. + * Callback must return a non-zero value to prevent memory leak. */ +void timer_single(timer_callback cb, void* userarg, int sec); + +/* Single-use microsecond timer. + * Creates a new timer, preforms setup and starts it. + * Please do not use this when accuracy is not absolutely required. + * Use when one needs to time a period < 1 s. + * Use the more coarse timers above for periods > 5 s. + * WARNING: the callback will be called with NULL as the first argument */ +void timer_us(timer_callback cb, void* userarg, int us); + +/* Internal Testing */ +void timer_internal_tests(bool(*)(bool, char*)); + +#endif diff --git a/testing/CMakeLists.txt b/testing/CMakeLists.txt index 7322509a..65ba35c0 100644 --- a/testing/CMakeLists.txt +++ b/testing/CMakeLists.txt @@ -9,6 +9,7 @@ include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/Lossless_UDP_testclient.cmake) include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/Lossless_UDP_testserver.cmake) include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/Messenger_test.cmake) include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/crypto_speed_test.cmake) +include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/timer_test.cmake) if(WIN32) include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/nTox_win32.cmake) diff --git a/testing/cmake/timer_test.cmake b/testing/cmake/timer_test.cmake new file mode 100644 index 00000000..a5f8c5ec --- /dev/null +++ b/testing/cmake/timer_test.cmake @@ -0,0 +1,9 @@ +cmake_minimum_required(VERSION 2.6.0) +project(timer_test C) + +set(exe_name timer_test) + +add_executable(${exe_name} + timer_test.c) + +linkCoreLibraries(${exe_name}) diff --git a/testing/timer_test.c b/testing/timer_test.c new file mode 100644 index 00000000..50c4cda7 --- /dev/null +++ b/testing/timer_test.c @@ -0,0 +1,66 @@ +#include "../core/timer.h" +#include + +#ifdef WINDOWS +#include +#else +#include +#endif + +void mssleep(int ms) +{ +#ifdef WINDOWS + Sleep(ms); +#else + usleep(ms * 1000); +#endif +} + +int callback(timer* t, void* arg){ + printf("%s\n", (char*)arg); + return 1; +} + +int repeating(timer* t, void *arg) { + printf("%s\n", (char*)arg); + timer_start(t, 3); + return 0; +} + +extern void timer_debug_print(); + +int main(int argc, char** argv) +{ + timer_init(); + timer_debug_print(); + + timer* t = timer_new(); + timer_setup(t, &callback, "Long setup method, 4 seconds"); + timer_start(t, 4); + timer_debug_print(); + + timer_single(&repeating, (void*)"This repeats every 3 seconds", 3); + timer_debug_print(); + + timer_single(&callback, "Short method, 4 seconds", 4); + timer_debug_print(); + + timer_single(&callback, "1 second", 1); + timer_debug_print(); + + timer_single(&callback, "15 seconds", 15); + timer_debug_print(); + + timer_single(&callback, "10 seconds", 10); + timer_debug_print(); + + timer_us(&callback, "100000us", 100000); + timer_us(&callback, "13s", 13 * US_PER_SECOND); + + while (true) { + timer_poll(); + mssleep(10); + } + + return 0; +} From f3511db29bb3f4a931c6efe66415981d73483262 Mon Sep 17 00:00:00 2001 From: slvr Date: Mon, 12 Aug 2013 14:19:25 +0100 Subject: [PATCH 2/8] Added LAN discovery timer --- core/Messenger.c | 57 ++++++++++++++++++++++++------------------------ 1 file changed, 29 insertions(+), 28 deletions(-) diff --git a/core/Messenger.c b/core/Messenger.c index 92c83b9b..e70b0378 100644 --- a/core/Messenger.c +++ b/core/Messenger.c @@ -22,6 +22,8 @@ */ #include "Messenger.h" +#include "timer.h" + #define MIN(a,b) (((a)<(b))?(a):(b)) typedef struct { @@ -520,27 +522,6 @@ static int write_cryptpacket_id(int friendnumber, uint8_t packet_id, uint8_t *da return write_cryptpacket(friendlist[friendnumber].crypt_connection_id, packet, length + 1); } -#define PORT 33445 -/* run this at startup */ -int initMessenger(void) -{ - new_keys(); - m_set_statusmessage((uint8_t*)"Online", sizeof("Online")); - initNetCrypto(); - IP ip; - ip.i = 0; - - if(init_networking(ip,PORT) == -1) - return -1; - - DHT_init(); - LosslessUDP_init(); - friendreq_init(); - LANdiscovery_init(); - - return 0; -} - //TODO: make this function not suck. static void doFriends(void) { @@ -692,17 +673,37 @@ static void doInbound(void) /*Interval in seconds between LAN discovery packet sending*/ #define LAN_DISCOVERY_INTERVAL 60 -static uint64_t last_LANdiscovery; - /*Send a LAN discovery packet every LAN_DISCOVERY_INTERVAL seconds*/ -static void LANdiscovery(void) +static int LANdiscovery_timercallback(timer* t, void*) { - if (last_LANdiscovery + LAN_DISCOVERY_INTERVAL < unix_time()) { - send_LANdiscovery(htons(PORT)); - last_LANdiscovery = unix_time(); - } + send_LANdiscovery(htons(PORT)); + timer_start(t, LAN_DISCOVERY_INTERVAL); + return 0; } +#define PORT 33445 +/* run this at startup */ +int initMessenger(void) +{ + timer_init(); + new_keys(); + m_set_statusmessage((uint8_t*)"Online", sizeof("Online")); + initNetCrypto(); + IP ip; + ip.i = 0; + + if(init_networking(ip,PORT) == -1) + return -1; + + DHT_init(); + LosslessUDP_init(); + friendreq_init(); + LANdiscovery_init(); + + timer_single(&LANdiscovery_timercallback, 0, LAN_DISCOVERY_INTERVAL); + + return 0; +} /* the main loop that needs to be run at least 200 times per second. */ void doMessenger(void) From c6b496d85b60e0177d0baa0f9cbbbc2c2199f924 Mon Sep 17 00:00:00 2001 From: slvr Date: Mon, 12 Aug 2013 14:44:59 +0100 Subject: [PATCH 3/8] Messenger Timer --- core/Messenger.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/core/Messenger.c b/core/Messenger.c index e70b0378..e88206f3 100644 --- a/core/Messenger.c +++ b/core/Messenger.c @@ -670,18 +670,19 @@ static void doInbound(void) } } +#define PORT 33445 + /*Interval in seconds between LAN discovery packet sending*/ #define LAN_DISCOVERY_INTERVAL 60 /*Send a LAN discovery packet every LAN_DISCOVERY_INTERVAL seconds*/ -static int LANdiscovery_timercallback(timer* t, void*) +static int LANdiscovery_timercallback(timer* t, void* ignore) { send_LANdiscovery(htons(PORT)); timer_start(t, LAN_DISCOVERY_INTERVAL); return 0; } -#define PORT 33445 /* run this at startup */ int initMessenger(void) { @@ -715,7 +716,6 @@ void doMessenger(void) doNetCrypto(); doInbound(); doFriends(); - LANdiscovery(); } /* returns the size of the messenger data (for saving) */ From a56d87cd3f7e20939e7f877a5c6419f28d9b8b24 Mon Sep 17 00:00:00 2001 From: slvr Date: Mon, 12 Aug 2013 14:54:40 +0100 Subject: [PATCH 4/8] remember to call timer_poll --- core/Messenger.c | 1 + 1 file changed, 1 insertion(+) diff --git a/core/Messenger.c b/core/Messenger.c index e88206f3..88f71b3d 100644 --- a/core/Messenger.c +++ b/core/Messenger.c @@ -710,6 +710,7 @@ int initMessenger(void) void doMessenger(void) { networking_poll(); + timer_poll(); doDHT(); doLossless_UDP(); From a0c6296d6c38341202b1802d3c85b8a6c47ddc83 Mon Sep 17 00:00:00 2001 From: slvr Date: Mon, 12 Aug 2013 23:47:15 +0100 Subject: [PATCH 5/8] Resolve Merge Conflict --- core/Messenger.c | 70 ++++++++++++------------------------------------ 1 file changed, 17 insertions(+), 53 deletions(-) diff --git a/core/Messenger.c b/core/Messenger.c index 58993a08..eb151a6a 100644 --- a/core/Messenger.c +++ b/core/Messenger.c @@ -482,9 +482,20 @@ int write_cryptpacket_id(Messenger *m, int friendnumber, uint8_t packet_id, uint return write_cryptpacket(m->friendlist[friendnumber].crypt_connection_id, packet, length + 1); } -<<<<<<< HEAD -======= + +/*Interval in seconds between LAN discovery packet sending*/ +#define LAN_DISCOVERY_INTERVAL 60 + #define PORT 33445 + +/*Send a LAN discovery packet every LAN_DISCOVERY_INTERVAL seconds*/ +int LANdiscovery(timer* t, void* arg) +{ + send_LANdiscovery(htons(PORT)); + timer_start(t, LAN_DISCOVERY_INTERVAL); + return 0; +} + /* run this at startup */ Messenger * initMessenger(void) { @@ -506,6 +517,8 @@ Messenger * initMessenger(void) friendreq_init(); LANdiscovery_init(); + timer_single(&LANdiscovery, 0, LAN_DISCOVERY_INTERVAL); + return m; } @@ -515,7 +528,6 @@ void cleanupMessenger(Messenger *m){ free(m); } ->>>>>>> upstream/master //TODO: make this function not suck. void doFriends(Messenger *m) { @@ -665,67 +677,19 @@ void doInbound(Messenger *m) } } -#define PORT 33445 - -/*Interval in seconds between LAN discovery packet sending*/ -#define LAN_DISCOVERY_INTERVAL 60 - -/*Send a LAN discovery packet every LAN_DISCOVERY_INTERVAL seconds*/ -<<<<<<< HEAD -static int LANdiscovery_timercallback(timer* t, void* ignore) -======= -void LANdiscovery(Messenger *m) ->>>>>>> upstream/master -{ - send_LANdiscovery(htons(PORT)); - timer_start(t, LAN_DISCOVERY_INTERVAL); - return 0; -} - -/* run this at startup */ -int initMessenger(void) -{ - timer_init(); - new_keys(); - m_set_statusmessage((uint8_t*)"Online", sizeof("Online")); - initNetCrypto(); - IP ip; - ip.i = 0; - - if(init_networking(ip,PORT) == -1) - return -1; - - DHT_init(); - LosslessUDP_init(); - friendreq_init(); - LANdiscovery_init(); - - timer_single(&LANdiscovery_timercallback, 0, LAN_DISCOVERY_INTERVAL); - - return 0; -} /* the main loop that needs to be run at least 200 times per second. */ void doMessenger(Messenger *m) { networking_poll(); -<<<<<<< HEAD - timer_poll(); - - doDHT(); - doLossless_UDP(); - doNetCrypto(); - doInbound(); - doFriends(); -======= doDHT(); doLossless_UDP(); doNetCrypto(); doInbound(m); doFriends(m); - LANdiscovery(m); ->>>>>>> upstream/master + + timer_poll(); } /* returns the size of the messenger data (for saving) */ From 4bfeb2f483e3f98b964e4e1ba3cbed85dd1bbce9 Mon Sep 17 00:00:00 2001 From: slvr Date: Tue, 13 Aug 2013 09:45:11 +0100 Subject: [PATCH 6/8] timer_new -> new_timer and timer_delete -> delete_timer to avoid name conflict --- core/Messenger.c.orig | 795 ++++++++++++++++++++++++++++++++++++++++++ core/timer.c | 12 +- core/timer.h | 4 +- testing/timer_test.c | 2 +- 4 files changed, 804 insertions(+), 9 deletions(-) create mode 100644 core/Messenger.c.orig diff --git a/core/Messenger.c.orig b/core/Messenger.c.orig new file mode 100644 index 00000000..58993a08 --- /dev/null +++ b/core/Messenger.c.orig @@ -0,0 +1,795 @@ +/* Messenger.c + * + * An implementation of a simple text chat only messenger on the tox network core. + * + * Copyright (C) 2013 Tox project All Rights Reserved. + * + * This file is part of Tox. + * + * Tox is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Tox is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Tox. If not, see . + * + */ + +#include "Messenger.h" +#include "timer.h" + +#define MIN(a,b) (((a)<(b))?(a):(b)) + +static void set_friend_status(Messenger *m, int friendnumber, uint8_t status); +static int write_cryptpacket_id(Messenger *m, int friendnumber, uint8_t packet_id, uint8_t *data, uint32_t length); + +/* 1 if we are online + 0 if we are offline + static uint8_t online; */ + +/* set the size of the friend list to numfriends + return -1 if realloc fails */ +int realloc_friendlist(Messenger *m, uint32_t num) { + Friend *newfriendlist = realloc(m->friendlist, num*sizeof(Friend)); + if (newfriendlist == NULL) + return -1; + memset(&newfriendlist[num-1], 0, sizeof(Friend)); + m->friendlist = newfriendlist; + return 0; +} + +/* return the friend id associated to that public key. + return -1 if no such friend */ +int getfriend_id(Messenger *m, uint8_t *client_id) +{ + uint32_t i; + + for (i = 0; i < m->numfriends; ++i) { + if (m->friendlist[i].status > 0) + if (memcmp(client_id, m->friendlist[i].client_id, crypto_box_PUBLICKEYBYTES) == 0) + return i; + } + + return -1; +} + +/* copies the public key associated to that friend id into client_id buffer. + make sure that client_id is of size CLIENT_ID_SIZE. + return 0 if success + return -1 if failure. */ +int getclient_id(Messenger *m, int friend_id, uint8_t *client_id) +{ + if (friend_id >= m->numfriends || friend_id < 0) + return -1; + + if (m->friendlist[friend_id].status > 0) { + memcpy(client_id, m->friendlist[friend_id].client_id, CLIENT_ID_SIZE); + return 0; + } + + return -1; +} + +/* + * add a friend + * set the data that will be sent along with friend request + * client_id is the client id of the friend + * data is the data and length is the length + * returns the friend number if success + * return FA_TOOLONG if message length is too long + * return FAERR_NOMESSAGE if no message (message length must be >= 1 byte) + * return FAERR_OWNKEY if user's own key + * return FAERR_ALREADYSENT if friend request already sent or already a friend + * return FAERR_UNKNOWN for unknown error + */ +int m_addfriend(Messenger *m, uint8_t *client_id, uint8_t *data, uint16_t length) +{ + if (length >= (MAX_DATA_SIZE - crypto_box_PUBLICKEYBYTES + - crypto_box_NONCEBYTES - crypto_box_BOXZEROBYTES + + crypto_box_ZEROBYTES)) + return FAERR_TOOLONG; + if (length < 1) + return FAERR_NOMESSAGE; + if (memcmp(client_id, self_public_key, crypto_box_PUBLICKEYBYTES) == 0) + return FAERR_OWNKEY; + if (getfriend_id(m, client_id) != -1) + return FAERR_ALREADYSENT; + + /* resize the friend list if necessary */ + realloc_friendlist(m, m->numfriends + 1); + + uint32_t i; + for (i = 0; i <= m->numfriends; ++i) { + if (m->friendlist[i].status == NOFRIEND) { + DHT_addfriend(client_id); + m->friendlist[i].status = FRIEND_ADDED; + m->friendlist[i].crypt_connection_id = -1; + m->friendlist[i].friend_request_id = -1; + memcpy(m->friendlist[i].client_id, client_id, CLIENT_ID_SIZE); + m->friendlist[i].statusmessage = calloc(1, 1); + m->friendlist[i].statusmessage_length = 1; + m->friendlist[i].userstatus = USERSTATUS_NONE; + memcpy(m->friendlist[i].info, data, length); + m->friendlist[i].info_size = length; + m->friendlist[i].message_id = 0; + m->friendlist[i].receives_read_receipts = 1; /* default: YES */ + + ++ m->numfriends; + return i; + } + } + return FAERR_UNKNOWN; +} + +int m_addfriend_norequest(Messenger *m, uint8_t * client_id) +{ + if (getfriend_id(m, client_id) != -1) + return -1; + + /* resize the friend list if necessary */ + realloc_friendlist(m, m->numfriends + 1); + + uint32_t i; + for (i = 0; i <= m->numfriends; ++i) { + if(m->friendlist[i].status == NOFRIEND) { + DHT_addfriend(client_id); + m->friendlist[i].status = FRIEND_REQUESTED; + m->friendlist[i].crypt_connection_id = -1; + m->friendlist[i].friend_request_id = -1; + memcpy(m->friendlist[i].client_id, client_id, CLIENT_ID_SIZE); + m->friendlist[i].statusmessage = calloc(1, 1); + m->friendlist[i].statusmessage_length = 1; + m->friendlist[i].userstatus = USERSTATUS_NONE; + m->friendlist[i].message_id = 0; + m->friendlist[i].receives_read_receipts = 1; /* default: YES */ + ++ m->numfriends; + return i; + } + } + return -1; +} + +/* remove a friend + return 0 if success + return -1 if failure */ +int m_delfriend(Messenger *m, int friendnumber) +{ + if (friendnumber >= m->numfriends || friendnumber < 0) + return -1; + + DHT_delfriend(m->friendlist[friendnumber].client_id); + crypto_kill(m->friendlist[friendnumber].crypt_connection_id); + free(m->friendlist[friendnumber].statusmessage); + memset(&(m->friendlist[friendnumber]), 0, sizeof(Friend)); + uint32_t i; + + for (i = m->numfriends; i != 0; --i) { + if (m->friendlist[i-1].status != NOFRIEND) + break; + } + m->numfriends = i; + realloc_friendlist(m, m->numfriends + 1); + + return 0; +} + +/* return FRIEND_ONLINE if friend is online + return FRIEND_CONFIRMED if friend is confirmed + return FRIEND_REQUESTED if the friend request was sent + return FRIEND_ADDED if the friend was added + return NOFRIEND if there is no friend with that number */ +int m_friendstatus(Messenger *m, int friendnumber) +{ + if (friendnumber < 0 || friendnumber >= m->numfriends) + return NOFRIEND; + return m->friendlist[friendnumber].status; +} + +/* send a text chat message to an online friend + return the message id if packet was successfully put into the send queue + return 0 if it was not */ +uint32_t m_sendmessage(Messenger *m, int friendnumber, uint8_t *message, uint32_t length) +{ + if (friendnumber < 0 || friendnumber >= m->numfriends) + return 0; + uint32_t msgid = ++m->friendlist[friendnumber].message_id; + if (msgid == 0) + msgid = 1; /* otherwise, false error */ + if(m_sendmessage_withid(m, friendnumber, msgid, message, length)) { + return msgid; + } + + return 0; +} + +uint32_t m_sendmessage_withid(Messenger *m, int friendnumber, uint32_t theid, uint8_t *message, uint32_t length) +{ + if (length >= (MAX_DATA_SIZE - sizeof(theid))) + return 0; + uint8_t temp[MAX_DATA_SIZE]; + theid = htonl(theid); + memcpy(temp, &theid, sizeof(theid)); + memcpy(temp + sizeof(theid), message, length); + return write_cryptpacket_id(m, friendnumber, PACKET_ID_MESSAGE, temp, length + sizeof(theid)); +} + +/* send an action to an online friend + return 1 if packet was successfully put into the send queue + return 0 if it was not */ +int m_sendaction(Messenger *m, int friendnumber, uint8_t *action, uint32_t length) +{ + return write_cryptpacket_id(m, friendnumber, PACKET_ID_ACTION, action, length); +} + +/* send a name packet to friendnumber + length is the length with the NULL terminator*/ +static int m_sendname(Messenger *m, int friendnumber, uint8_t * name, uint16_t length) +{ + if(length > MAX_NAME_LENGTH || length == 0) + return 0; + return write_cryptpacket_id(m, friendnumber, PACKET_ID_NICKNAME, name, length); +} + +/* set the name of a friend + return 0 if success + return -1 if failure */ +static int setfriendname(Messenger *m, int friendnumber, uint8_t * name) +{ + if (friendnumber >= m->numfriends || friendnumber < 0) + return -1; + memcpy(m->friendlist[friendnumber].name, name, MAX_NAME_LENGTH); + return 0; +} + +/* Set our nickname + name must be a string of maximum MAX_NAME_LENGTH length. + length must be at least 1 byte + length is the length of name with the NULL terminator + return 0 if success + return -1 if failure */ +int setname(Messenger *m, uint8_t * name, uint16_t length) +{ + if (length > MAX_NAME_LENGTH || length == 0) + return -1; + memcpy(m->name, name, length); + m->name_length = length; + uint32_t i; + for (i = 0; i < m->numfriends; ++i) + m->friendlist[i].name_sent = 0; + return 0; +} + +/* get our nickname + put it in name + name needs to be a valid memory location with a size of at least MAX_NAME_LENGTH bytes. + return the length of the name */ +uint16_t getself_name(Messenger *m, uint8_t *name) +{ + memcpy(name, m->name, m->name_length); + return m->name_length; +} + +/* get name of friendnumber + put it in name + name needs to be a valid memory location with a size of at least MAX_NAME_LENGTH bytes. + return 0 if success + return -1 if failure */ +int getname(Messenger *m, int friendnumber, uint8_t * name) +{ + if (friendnumber >= m->numfriends || friendnumber < 0) + return -1; + memcpy(name, m->friendlist[friendnumber].name, MAX_NAME_LENGTH); + return 0; +} + +int m_set_statusmessage(Messenger *m, uint8_t *status, uint16_t length) +{ + if (length > MAX_STATUSMESSAGE_LENGTH) + return -1; + memcpy(m->statusmessage, status, length); + m->statusmessage_length = length; + + uint32_t i; + for (i = 0; i < m->numfriends; ++i) + m->friendlist[i].statusmessage_sent = 0; + return 0; +} + +int m_set_userstatus(Messenger *m, USERSTATUS status) +{ + if (status >= USERSTATUS_INVALID) { + return -1; + } + m->userstatus = status; + uint32_t i; + for (i = 0; i < m->numfriends; ++i) + m->friendlist[i].userstatus_sent = 0; + return 0; +} + +/* return the size of friendnumber's user status + guaranteed to be at most MAX_STATUSMESSAGE_LENGTH */ +int m_get_statusmessage_size(Messenger *m, int friendnumber) +{ + if (friendnumber >= m->numfriends || friendnumber < 0) + return -1; + return m->friendlist[friendnumber].statusmessage_length; +} + +/* copy the user status of friendnumber into buf, truncating if needed to maxlen + bytes, use m_get_statusmessage_size to find out how much you need to allocate */ +int m_copy_statusmessage(Messenger *m, int friendnumber, uint8_t * buf, uint32_t maxlen) +{ + if (friendnumber >= m->numfriends || friendnumber < 0) + return -1; + memset(buf, 0, maxlen); + memcpy(buf, m->friendlist[friendnumber].statusmessage, MIN(maxlen, MAX_STATUSMESSAGE_LENGTH) - 1); + return 0; +} + +int m_copy_self_statusmessage(Messenger *m, uint8_t * buf, uint32_t maxlen) +{ + memset(buf, 0, maxlen); + memcpy(buf, m->statusmessage, MIN(maxlen, MAX_STATUSMESSAGE_LENGTH) - 1); + return 0; +} + +USERSTATUS m_get_userstatus(Messenger *m, int friendnumber) +{ + if (friendnumber >= m->numfriends || friendnumber < 0) + return USERSTATUS_INVALID; + USERSTATUS status = m->friendlist[friendnumber].userstatus; + if (status >= USERSTATUS_INVALID) { + status = USERSTATUS_NONE; + } + return status; +} + +USERSTATUS m_get_self_userstatus(Messenger *m) +{ + return m->userstatus; +} + +static int send_statusmessage(Messenger *m, int friendnumber, uint8_t * status, uint16_t length) +{ + return write_cryptpacket_id(m, friendnumber, PACKET_ID_STATUSMESSAGE, status, length); +} + +static int send_userstatus(Messenger *m, int friendnumber, USERSTATUS status) +{ + uint8_t stat = status; + return write_cryptpacket_id(m, friendnumber, PACKET_ID_USERSTATUS, &stat, sizeof(stat)); +} + +static int set_friend_statusmessage(Messenger *m, int friendnumber, uint8_t * status, uint16_t length) +{ + if (friendnumber >= m->numfriends || friendnumber < 0) + return -1; + uint8_t *newstatus = calloc(length, 1); + memcpy(newstatus, status, length); + free(m->friendlist[friendnumber].statusmessage); + m->friendlist[friendnumber].statusmessage = newstatus; + m->friendlist[friendnumber].statusmessage_length = length; + return 0; +} + +static void set_friend_userstatus(Messenger *m, int friendnumber, USERSTATUS status) +{ + m->friendlist[friendnumber].userstatus = status; +} + +/* Sets whether we send read receipts for friendnumber. */ +void m_set_sends_receipts(Messenger *m, int friendnumber, int yesno) +{ + if (yesno != 0 || yesno != 1) + return; + if (friendnumber >= m->numfriends || friendnumber < 0) + return; + m->friendlist[friendnumber].receives_read_receipts = yesno; +} + +/* static void (*friend_request)(uint8_t *, uint8_t *, uint16_t); +static uint8_t friend_request_isset = 0; */ +/* set the function that will be executed when a friend request is received. */ +void m_callback_friendrequest(Messenger *m, void (*function)(uint8_t *, uint8_t *, uint16_t, void*), void* userdata) +{ + callback_friendrequest(function, userdata); +} + +/* set the function that will be executed when a message from a friend is received. */ +void m_callback_friendmessage(Messenger *m, void (*function)(Messenger *m, int, uint8_t *, uint16_t, void*), void* userdata) +{ + m->friend_message = function; + m->friend_message_isset = 1; + m->friend_message_userdata = userdata; +} + +void m_callback_action(Messenger *m, void (*function)(Messenger *m, int, uint8_t *, uint16_t, void*), void* userdata) +{ + m->friend_action = function; + m->friend_action_isset = 1; + m->friend_action_userdata = userdata; +} + +void m_callback_namechange(Messenger *m, void (*function)(Messenger *m, int, uint8_t *, uint16_t, void*), void* userdata) +{ + m->friend_namechange = function; + m->friend_namechange_isset = 1; + m->friend_namechange_userdata = userdata; +} + +void m_callback_statusmessage(Messenger *m, void (*function)(Messenger *m, int, uint8_t *, uint16_t, void*), void* userdata) +{ + m->friend_statusmessagechange = function; + m->friend_statusmessagechange_isset = 1; + m->friend_statuschange_userdata = userdata; +} + +void m_callback_userstatus(Messenger *m, void (*function)(Messenger *m, int, USERSTATUS, void*), void* userdata) +{ + m->friend_userstatuschange = function; + m->friend_userstatuschange_isset = 1; + m->friend_userstatuschange_userdata = userdata; +} + +void m_callback_read_receipt(Messenger *m, void (*function)(Messenger *m, int, uint32_t, void*), void* userdata) +{ + m->read_receipt = function; + m->read_receipt_isset = 1; + m->read_receipt_userdata = userdata; +} + +void m_callback_connectionstatus(Messenger *m, void (*function)(Messenger *m, int, uint8_t, void*), void* userdata) +{ + m->friend_connectionstatuschange = function; + m->friend_connectionstatuschange_isset = 1; + m->friend_connectionstatuschange_userdata = userdata; +} + +static void check_friend_connectionstatus(Messenger *m, int friendnumber, uint8_t status) +{ + if (!m->friend_connectionstatuschange_isset) + return; + if (status == NOFRIEND) + return; + const uint8_t was_connected = m->friendlist[friendnumber].status == FRIEND_ONLINE; + const uint8_t is_connected = status == FRIEND_ONLINE; + if (is_connected != was_connected) + m->friend_connectionstatuschange(m, friendnumber, is_connected, m->friend_connectionstatuschange_userdata); +} + +void set_friend_status(Messenger *m, int friendnumber, uint8_t status) +{ + check_friend_connectionstatus(m, friendnumber, status); + m->friendlist[friendnumber].status = status; +} + +int write_cryptpacket_id(Messenger *m, int friendnumber, uint8_t packet_id, uint8_t *data, uint32_t length) +{ + if (friendnumber < 0 || friendnumber >= m->numfriends) + return 0; + if (length >= MAX_DATA_SIZE || m->friendlist[friendnumber].status != FRIEND_ONLINE) + return 0; + uint8_t packet[length + 1]; + packet[0] = packet_id; + memcpy(packet + 1, data, length); + return write_cryptpacket(m->friendlist[friendnumber].crypt_connection_id, packet, length + 1); +} + +<<<<<<< HEAD +======= +#define PORT 33445 +/* run this at startup */ +Messenger * initMessenger(void) +{ + Messenger *m = calloc(1, sizeof(Messenger)); + if( ! m ) + return 0; + + new_keys(); + m_set_statusmessage(m, (uint8_t*)"Online", sizeof("Online")); + initNetCrypto(); + IP ip; + ip.i = 0; + + if(init_networking(ip,PORT) == -1) + return 0; + + DHT_init(); + LosslessUDP_init(); + friendreq_init(); + LANdiscovery_init(); + + return m; +} + +/* run this before closing shop */ +void cleanupMessenger(Messenger *m){ + /* FIXME TODO it seems no one frees friendlist or all the elements status */ + free(m); +} + +>>>>>>> upstream/master +//TODO: make this function not suck. +void doFriends(Messenger *m) +{ + /* TODO: add incoming connections and some other stuff. */ + uint32_t i; + int len; + uint8_t temp[MAX_DATA_SIZE]; + for (i = 0; i < m->numfriends; ++i) { + if (m->friendlist[i].status == FRIEND_ADDED) { + int fr = send_friendrequest(m->friendlist[i].client_id, m->friendlist[i].info, m->friendlist[i].info_size); + if (fr == 0) /* TODO: This needs to be fixed so that it sends the friend requests a couple of times in case of packet loss */ + set_friend_status(m, i, FRIEND_REQUESTED); + else if (fr > 0) + set_friend_status(m, i, FRIEND_REQUESTED); + } + if (m->friendlist[i].status == FRIEND_REQUESTED || m->friendlist[i].status == FRIEND_CONFIRMED) { /* friend is not online */ + if (m->friendlist[i].status == FRIEND_REQUESTED) { + if (m->friendlist[i].friend_request_id + 10 < unix_time()) { /*I know this is hackish but it should work.*/ + send_friendrequest(m->friendlist[i].client_id, m->friendlist[i].info, m->friendlist[i].info_size); + m->friendlist[i].friend_request_id = unix_time(); + } + } + IP_Port friendip = DHT_getfriendip(m->friendlist[i].client_id); + switch (is_cryptoconnected(m->friendlist[i].crypt_connection_id)) { + case 0: + if (friendip.ip.i > 1) + m->friendlist[i].crypt_connection_id = crypto_connect(m->friendlist[i].client_id, friendip); + break; + case 3: /* Connection is established */ + set_friend_status(m, i, FRIEND_ONLINE); + m->friendlist[i].name_sent = 0; + m->friendlist[i].userstatus_sent = 0; + m->friendlist[i].statusmessage_sent = 0; + break; + case 4: + crypto_kill(m->friendlist[i].crypt_connection_id); + m->friendlist[i].crypt_connection_id = -1; + break; + default: + break; + } + } + while (m->friendlist[i].status == FRIEND_ONLINE) { /* friend is online */ + if (m->friendlist[i].name_sent == 0) { + if (m_sendname(m, i, m->name, m->name_length)) + m->friendlist[i].name_sent = 1; + } + if (m->friendlist[i].statusmessage_sent == 0) { + if (send_statusmessage(m, i, m->statusmessage, m->statusmessage_length)) + m->friendlist[i].statusmessage_sent = 1; + } + if (m->friendlist[i].userstatus_sent == 0) { + if (send_userstatus(m, i, m->userstatus)) + m->friendlist[i].userstatus_sent = 1; + } + len = read_cryptpacket(m->friendlist[i].crypt_connection_id, temp); + uint8_t packet_id = temp[0]; + uint8_t* data = temp + 1; + int data_length = len - 1; + if (len > 0) { + switch (packet_id) { + case PACKET_ID_NICKNAME: { + if (data_length >= MAX_NAME_LENGTH || data_length == 0) + break; + if(m->friend_namechange_isset) + m->friend_namechange(m, i, data, data_length, m->friend_namechange_userdata); + memcpy(m->friendlist[i].name, data, data_length); + m->friendlist[i].name[data_length - 1] = 0; /* make sure the NULL terminator is present. */ + break; + } + case PACKET_ID_STATUSMESSAGE: { + if (data_length == 0) + break; + uint8_t *status = calloc(MIN(data_length, MAX_STATUSMESSAGE_LENGTH), 1); + memcpy(status, data, MIN(data_length, MAX_STATUSMESSAGE_LENGTH)); + if (m->friend_statusmessagechange_isset) + m->friend_statusmessagechange(m, i, status, MIN(data_length, MAX_STATUSMESSAGE_LENGTH), + m->friend_statuschange_userdata); + set_friend_statusmessage(m, i, status, MIN(data_length, MAX_STATUSMESSAGE_LENGTH)); + free(status); + break; + } + case PACKET_ID_USERSTATUS: { + if (data_length != 1) + break; + USERSTATUS status = data[0]; + if (m->friend_userstatuschange_isset) + m->friend_userstatuschange(m, i, status, m->friend_userstatuschange_userdata); + set_friend_userstatus(m, i, status); + break; + } + case PACKET_ID_MESSAGE: { + uint8_t *message_id = data; + uint8_t message_id_length = 4; + uint8_t *message = data + message_id_length; + uint16_t message_length = data_length - message_id_length; + if (m->friendlist[i].receives_read_receipts) { + write_cryptpacket_id(m, i, PACKET_ID_RECEIPT, message_id, message_id_length); + } + if (m->friend_message_isset) + (*m->friend_message)(m, i, message, message_length, m->friend_message_userdata); + break; + } + case PACKET_ID_ACTION: { + if (m->friend_action_isset) + (*m->friend_action)(m, i, data, data_length, m->friend_action_userdata); + break; + } + case PACKET_ID_RECEIPT: { + uint32_t msgid; + if (data_length < sizeof(msgid)) + break; + memcpy(&msgid, data, sizeof(msgid)); + msgid = ntohl(msgid); + if (m->read_receipt_isset) + (*m->read_receipt)(m, i, msgid, m->read_receipt_userdata); + break; + } + } + } else { + if (is_cryptoconnected(m->friendlist[i].crypt_connection_id) == 4) { /* if the connection timed out, kill it */ + crypto_kill(m->friendlist[i].crypt_connection_id); + m->friendlist[i].crypt_connection_id = -1; + set_friend_status(m, i, FRIEND_CONFIRMED); + } + break; + } + } + } +} + +void doInbound(Messenger *m) +{ + uint8_t secret_nonce[crypto_box_NONCEBYTES]; + uint8_t public_key[crypto_box_PUBLICKEYBYTES]; + uint8_t session_key[crypto_box_PUBLICKEYBYTES]; + int inconnection = crypto_inbound(public_key, secret_nonce, session_key); + if (inconnection != -1) { + int friend_id = getfriend_id(m, public_key); + if (friend_id != -1) { + crypto_kill(m->friendlist[friend_id].crypt_connection_id); + m->friendlist[friend_id].crypt_connection_id = + accept_crypto_inbound(inconnection, public_key, secret_nonce, session_key); + + set_friend_status(m, friend_id, FRIEND_CONFIRMED); + } + } +} + +#define PORT 33445 + +/*Interval in seconds between LAN discovery packet sending*/ +#define LAN_DISCOVERY_INTERVAL 60 + +/*Send a LAN discovery packet every LAN_DISCOVERY_INTERVAL seconds*/ +<<<<<<< HEAD +static int LANdiscovery_timercallback(timer* t, void* ignore) +======= +void LANdiscovery(Messenger *m) +>>>>>>> upstream/master +{ + send_LANdiscovery(htons(PORT)); + timer_start(t, LAN_DISCOVERY_INTERVAL); + return 0; +} + +/* run this at startup */ +int initMessenger(void) +{ + timer_init(); + new_keys(); + m_set_statusmessage((uint8_t*)"Online", sizeof("Online")); + initNetCrypto(); + IP ip; + ip.i = 0; + + if(init_networking(ip,PORT) == -1) + return -1; + + DHT_init(); + LosslessUDP_init(); + friendreq_init(); + LANdiscovery_init(); + + timer_single(&LANdiscovery_timercallback, 0, LAN_DISCOVERY_INTERVAL); + + return 0; +} + +/* the main loop that needs to be run at least 200 times per second. */ +void doMessenger(Messenger *m) +{ + networking_poll(); +<<<<<<< HEAD + timer_poll(); + + doDHT(); + doLossless_UDP(); + doNetCrypto(); + doInbound(); + doFriends(); +======= + + doDHT(); + doLossless_UDP(); + doNetCrypto(); + doInbound(m); + doFriends(m); + LANdiscovery(m); +>>>>>>> upstream/master +} + +/* returns the size of the messenger data (for saving) */ +uint32_t Messenger_size(Messenger *m) +{ + return crypto_box_PUBLICKEYBYTES + crypto_box_SECRETKEYBYTES + + sizeof(uint32_t) + DHT_size() + sizeof(uint32_t) + sizeof(Friend) * m->numfriends; +} + +/* save the messenger in data of size Messenger_size() */ +void Messenger_save(Messenger *m, uint8_t *data) +{ + save_keys(data); + data += crypto_box_PUBLICKEYBYTES + crypto_box_SECRETKEYBYTES; + uint32_t size = DHT_size(); + memcpy(data, &size, sizeof(size)); + data += sizeof(size); + DHT_save(data); + data += size; + size = sizeof(Friend) * m->numfriends; + memcpy(data, &size, sizeof(size)); + data += sizeof(size); + memcpy(data, m->friendlist, sizeof(Friend) * m->numfriends); +} + +/* load the messenger from data of size length. */ +int Messenger_load(Messenger *m, uint8_t * data, uint32_t length) +{ + if (length == ~0) + return -1; + if (length < crypto_box_PUBLICKEYBYTES + crypto_box_SECRETKEYBYTES + sizeof(uint32_t) * 2) + return -1; + length -= crypto_box_PUBLICKEYBYTES + crypto_box_SECRETKEYBYTES + sizeof(uint32_t) * 2; + load_keys(data); + data += crypto_box_PUBLICKEYBYTES + crypto_box_SECRETKEYBYTES; + uint32_t size; + memcpy(&size, data, sizeof(size)); + data += sizeof(size); + + if (length < size) + return -1; + length -= size; + if (DHT_load(data, size) == -1) + return -1; + data += size; + memcpy(&size, data, sizeof(size)); + data += sizeof(size); + if (length != size || length % sizeof(Friend) != 0) + return -1; + + Friend * temp = malloc(size); + memcpy(temp, data, size); + + uint16_t num = size / sizeof(Friend); + + uint32_t i; + for (i = 0; i < num; ++i) { + if(temp[i].status != 0) { + int fnum = m_addfriend_norequest(m, temp[i].client_id); + setfriendname(m, fnum, temp[i].name); + /* set_friend_statusmessage(fnum, temp[i].statusmessage, temp[i].statusmessage_length); */ + } + } + free(temp); + return 0; +} + diff --git a/core/timer.c b/core/timer.c index 74a2831d..8c278434 100644 --- a/core/timer.c +++ b/core/timer.c @@ -104,7 +104,7 @@ void timer_init() /* Do not depend on fields being zeroed */ static timer* timer_pool; /* timer_pool is SINGLY LINKED!! */ -timer* timer_new(void) +timer* new_timer(void) { timer* ret; if (timer_pool) { @@ -117,7 +117,7 @@ timer* timer_new(void) return ret; } -void timer_delete(timer* t) +void delete_timer(timer* t) { timer_dequeue(t, &timer_main_queue); t->_next = timer_pool; @@ -203,7 +203,7 @@ bool timer_is_active(timer* t) * Creates a new timer, preforms setup and starts it. */ void timer_single(timer_callback cb, void* userarg, int sec) { - timer* t = timer_new(); + timer* t = new_timer(); timer_setup(t, cb, userarg); timer_start(t, sec); } @@ -211,7 +211,7 @@ void timer_single(timer_callback cb, void* userarg, int sec) /* Single-use microsecond timer. */ void timer_us(timer_callback cb, void* userarg, int us) { - timer* t = timer_new(); + timer* t = new_timer(); timer_setup(t, cb, userarg); t->deadline = current_time() + us; t->state = STATE_ACTIVE; @@ -229,7 +229,7 @@ void timer_poll(void) timer* t = timer_us_queue; timer_dequeue(t, &timer_us_queue); t->cb(0, t->userdata); - timer_delete(t); + delete_timer(t); } if (time - prevtime > US_PER_SECOND || prevtime == 0 || prevtime > time) { @@ -243,7 +243,7 @@ void timer_poll(void) int rv = t->cb(t, t->userdata); if (rv != 0) { timer_dequeue(t, &timer_main_queue); - timer_delete(t); + delete_timer(t); continue; } if (t->state != STATE_ACTIVE) { diff --git a/core/timer.h b/core/timer.h index fee66f29..8844a1dd 100644 --- a/core/timer.h +++ b/core/timer.h @@ -53,10 +53,10 @@ void timer_init(void); void timer_poll(void); /* Creates a new timer. Does not enqueue/start it. */ -timer* timer_new(void); +timer* new_timer(void); /* Destroys a timer instance. */ -void timer_delete(timer* t); +void delete_timer(timer* t); /* Sets up the timer callback. */ void timer_setup(timer* t, timer_callback cb, void* userarg); diff --git a/testing/timer_test.c b/testing/timer_test.c index 50c4cda7..63083940 100644 --- a/testing/timer_test.c +++ b/testing/timer_test.c @@ -34,7 +34,7 @@ int main(int argc, char** argv) timer_init(); timer_debug_print(); - timer* t = timer_new(); + timer* t = new_timer(); timer_setup(t, &callback, "Long setup method, 4 seconds"); timer_start(t, 4); timer_debug_print(); From 9e3f48c1653137a9211076a7644b8333bb78fe23 Mon Sep 17 00:00:00 2001 From: slvr Date: Tue, 13 Aug 2013 09:50:24 +0100 Subject: [PATCH 7/8] Removed core/Messenger.c.orig Cleanup from merge conflict. --- core/Messenger.c.orig | 795 ------------------------------------------ 1 file changed, 795 deletions(-) delete mode 100644 core/Messenger.c.orig diff --git a/core/Messenger.c.orig b/core/Messenger.c.orig deleted file mode 100644 index 58993a08..00000000 --- a/core/Messenger.c.orig +++ /dev/null @@ -1,795 +0,0 @@ -/* Messenger.c - * - * An implementation of a simple text chat only messenger on the tox network core. - * - * Copyright (C) 2013 Tox project All Rights Reserved. - * - * This file is part of Tox. - * - * Tox is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Tox is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Tox. If not, see . - * - */ - -#include "Messenger.h" -#include "timer.h" - -#define MIN(a,b) (((a)<(b))?(a):(b)) - -static void set_friend_status(Messenger *m, int friendnumber, uint8_t status); -static int write_cryptpacket_id(Messenger *m, int friendnumber, uint8_t packet_id, uint8_t *data, uint32_t length); - -/* 1 if we are online - 0 if we are offline - static uint8_t online; */ - -/* set the size of the friend list to numfriends - return -1 if realloc fails */ -int realloc_friendlist(Messenger *m, uint32_t num) { - Friend *newfriendlist = realloc(m->friendlist, num*sizeof(Friend)); - if (newfriendlist == NULL) - return -1; - memset(&newfriendlist[num-1], 0, sizeof(Friend)); - m->friendlist = newfriendlist; - return 0; -} - -/* return the friend id associated to that public key. - return -1 if no such friend */ -int getfriend_id(Messenger *m, uint8_t *client_id) -{ - uint32_t i; - - for (i = 0; i < m->numfriends; ++i) { - if (m->friendlist[i].status > 0) - if (memcmp(client_id, m->friendlist[i].client_id, crypto_box_PUBLICKEYBYTES) == 0) - return i; - } - - return -1; -} - -/* copies the public key associated to that friend id into client_id buffer. - make sure that client_id is of size CLIENT_ID_SIZE. - return 0 if success - return -1 if failure. */ -int getclient_id(Messenger *m, int friend_id, uint8_t *client_id) -{ - if (friend_id >= m->numfriends || friend_id < 0) - return -1; - - if (m->friendlist[friend_id].status > 0) { - memcpy(client_id, m->friendlist[friend_id].client_id, CLIENT_ID_SIZE); - return 0; - } - - return -1; -} - -/* - * add a friend - * set the data that will be sent along with friend request - * client_id is the client id of the friend - * data is the data and length is the length - * returns the friend number if success - * return FA_TOOLONG if message length is too long - * return FAERR_NOMESSAGE if no message (message length must be >= 1 byte) - * return FAERR_OWNKEY if user's own key - * return FAERR_ALREADYSENT if friend request already sent or already a friend - * return FAERR_UNKNOWN for unknown error - */ -int m_addfriend(Messenger *m, uint8_t *client_id, uint8_t *data, uint16_t length) -{ - if (length >= (MAX_DATA_SIZE - crypto_box_PUBLICKEYBYTES - - crypto_box_NONCEBYTES - crypto_box_BOXZEROBYTES - + crypto_box_ZEROBYTES)) - return FAERR_TOOLONG; - if (length < 1) - return FAERR_NOMESSAGE; - if (memcmp(client_id, self_public_key, crypto_box_PUBLICKEYBYTES) == 0) - return FAERR_OWNKEY; - if (getfriend_id(m, client_id) != -1) - return FAERR_ALREADYSENT; - - /* resize the friend list if necessary */ - realloc_friendlist(m, m->numfriends + 1); - - uint32_t i; - for (i = 0; i <= m->numfriends; ++i) { - if (m->friendlist[i].status == NOFRIEND) { - DHT_addfriend(client_id); - m->friendlist[i].status = FRIEND_ADDED; - m->friendlist[i].crypt_connection_id = -1; - m->friendlist[i].friend_request_id = -1; - memcpy(m->friendlist[i].client_id, client_id, CLIENT_ID_SIZE); - m->friendlist[i].statusmessage = calloc(1, 1); - m->friendlist[i].statusmessage_length = 1; - m->friendlist[i].userstatus = USERSTATUS_NONE; - memcpy(m->friendlist[i].info, data, length); - m->friendlist[i].info_size = length; - m->friendlist[i].message_id = 0; - m->friendlist[i].receives_read_receipts = 1; /* default: YES */ - - ++ m->numfriends; - return i; - } - } - return FAERR_UNKNOWN; -} - -int m_addfriend_norequest(Messenger *m, uint8_t * client_id) -{ - if (getfriend_id(m, client_id) != -1) - return -1; - - /* resize the friend list if necessary */ - realloc_friendlist(m, m->numfriends + 1); - - uint32_t i; - for (i = 0; i <= m->numfriends; ++i) { - if(m->friendlist[i].status == NOFRIEND) { - DHT_addfriend(client_id); - m->friendlist[i].status = FRIEND_REQUESTED; - m->friendlist[i].crypt_connection_id = -1; - m->friendlist[i].friend_request_id = -1; - memcpy(m->friendlist[i].client_id, client_id, CLIENT_ID_SIZE); - m->friendlist[i].statusmessage = calloc(1, 1); - m->friendlist[i].statusmessage_length = 1; - m->friendlist[i].userstatus = USERSTATUS_NONE; - m->friendlist[i].message_id = 0; - m->friendlist[i].receives_read_receipts = 1; /* default: YES */ - ++ m->numfriends; - return i; - } - } - return -1; -} - -/* remove a friend - return 0 if success - return -1 if failure */ -int m_delfriend(Messenger *m, int friendnumber) -{ - if (friendnumber >= m->numfriends || friendnumber < 0) - return -1; - - DHT_delfriend(m->friendlist[friendnumber].client_id); - crypto_kill(m->friendlist[friendnumber].crypt_connection_id); - free(m->friendlist[friendnumber].statusmessage); - memset(&(m->friendlist[friendnumber]), 0, sizeof(Friend)); - uint32_t i; - - for (i = m->numfriends; i != 0; --i) { - if (m->friendlist[i-1].status != NOFRIEND) - break; - } - m->numfriends = i; - realloc_friendlist(m, m->numfriends + 1); - - return 0; -} - -/* return FRIEND_ONLINE if friend is online - return FRIEND_CONFIRMED if friend is confirmed - return FRIEND_REQUESTED if the friend request was sent - return FRIEND_ADDED if the friend was added - return NOFRIEND if there is no friend with that number */ -int m_friendstatus(Messenger *m, int friendnumber) -{ - if (friendnumber < 0 || friendnumber >= m->numfriends) - return NOFRIEND; - return m->friendlist[friendnumber].status; -} - -/* send a text chat message to an online friend - return the message id if packet was successfully put into the send queue - return 0 if it was not */ -uint32_t m_sendmessage(Messenger *m, int friendnumber, uint8_t *message, uint32_t length) -{ - if (friendnumber < 0 || friendnumber >= m->numfriends) - return 0; - uint32_t msgid = ++m->friendlist[friendnumber].message_id; - if (msgid == 0) - msgid = 1; /* otherwise, false error */ - if(m_sendmessage_withid(m, friendnumber, msgid, message, length)) { - return msgid; - } - - return 0; -} - -uint32_t m_sendmessage_withid(Messenger *m, int friendnumber, uint32_t theid, uint8_t *message, uint32_t length) -{ - if (length >= (MAX_DATA_SIZE - sizeof(theid))) - return 0; - uint8_t temp[MAX_DATA_SIZE]; - theid = htonl(theid); - memcpy(temp, &theid, sizeof(theid)); - memcpy(temp + sizeof(theid), message, length); - return write_cryptpacket_id(m, friendnumber, PACKET_ID_MESSAGE, temp, length + sizeof(theid)); -} - -/* send an action to an online friend - return 1 if packet was successfully put into the send queue - return 0 if it was not */ -int m_sendaction(Messenger *m, int friendnumber, uint8_t *action, uint32_t length) -{ - return write_cryptpacket_id(m, friendnumber, PACKET_ID_ACTION, action, length); -} - -/* send a name packet to friendnumber - length is the length with the NULL terminator*/ -static int m_sendname(Messenger *m, int friendnumber, uint8_t * name, uint16_t length) -{ - if(length > MAX_NAME_LENGTH || length == 0) - return 0; - return write_cryptpacket_id(m, friendnumber, PACKET_ID_NICKNAME, name, length); -} - -/* set the name of a friend - return 0 if success - return -1 if failure */ -static int setfriendname(Messenger *m, int friendnumber, uint8_t * name) -{ - if (friendnumber >= m->numfriends || friendnumber < 0) - return -1; - memcpy(m->friendlist[friendnumber].name, name, MAX_NAME_LENGTH); - return 0; -} - -/* Set our nickname - name must be a string of maximum MAX_NAME_LENGTH length. - length must be at least 1 byte - length is the length of name with the NULL terminator - return 0 if success - return -1 if failure */ -int setname(Messenger *m, uint8_t * name, uint16_t length) -{ - if (length > MAX_NAME_LENGTH || length == 0) - return -1; - memcpy(m->name, name, length); - m->name_length = length; - uint32_t i; - for (i = 0; i < m->numfriends; ++i) - m->friendlist[i].name_sent = 0; - return 0; -} - -/* get our nickname - put it in name - name needs to be a valid memory location with a size of at least MAX_NAME_LENGTH bytes. - return the length of the name */ -uint16_t getself_name(Messenger *m, uint8_t *name) -{ - memcpy(name, m->name, m->name_length); - return m->name_length; -} - -/* get name of friendnumber - put it in name - name needs to be a valid memory location with a size of at least MAX_NAME_LENGTH bytes. - return 0 if success - return -1 if failure */ -int getname(Messenger *m, int friendnumber, uint8_t * name) -{ - if (friendnumber >= m->numfriends || friendnumber < 0) - return -1; - memcpy(name, m->friendlist[friendnumber].name, MAX_NAME_LENGTH); - return 0; -} - -int m_set_statusmessage(Messenger *m, uint8_t *status, uint16_t length) -{ - if (length > MAX_STATUSMESSAGE_LENGTH) - return -1; - memcpy(m->statusmessage, status, length); - m->statusmessage_length = length; - - uint32_t i; - for (i = 0; i < m->numfriends; ++i) - m->friendlist[i].statusmessage_sent = 0; - return 0; -} - -int m_set_userstatus(Messenger *m, USERSTATUS status) -{ - if (status >= USERSTATUS_INVALID) { - return -1; - } - m->userstatus = status; - uint32_t i; - for (i = 0; i < m->numfriends; ++i) - m->friendlist[i].userstatus_sent = 0; - return 0; -} - -/* return the size of friendnumber's user status - guaranteed to be at most MAX_STATUSMESSAGE_LENGTH */ -int m_get_statusmessage_size(Messenger *m, int friendnumber) -{ - if (friendnumber >= m->numfriends || friendnumber < 0) - return -1; - return m->friendlist[friendnumber].statusmessage_length; -} - -/* copy the user status of friendnumber into buf, truncating if needed to maxlen - bytes, use m_get_statusmessage_size to find out how much you need to allocate */ -int m_copy_statusmessage(Messenger *m, int friendnumber, uint8_t * buf, uint32_t maxlen) -{ - if (friendnumber >= m->numfriends || friendnumber < 0) - return -1; - memset(buf, 0, maxlen); - memcpy(buf, m->friendlist[friendnumber].statusmessage, MIN(maxlen, MAX_STATUSMESSAGE_LENGTH) - 1); - return 0; -} - -int m_copy_self_statusmessage(Messenger *m, uint8_t * buf, uint32_t maxlen) -{ - memset(buf, 0, maxlen); - memcpy(buf, m->statusmessage, MIN(maxlen, MAX_STATUSMESSAGE_LENGTH) - 1); - return 0; -} - -USERSTATUS m_get_userstatus(Messenger *m, int friendnumber) -{ - if (friendnumber >= m->numfriends || friendnumber < 0) - return USERSTATUS_INVALID; - USERSTATUS status = m->friendlist[friendnumber].userstatus; - if (status >= USERSTATUS_INVALID) { - status = USERSTATUS_NONE; - } - return status; -} - -USERSTATUS m_get_self_userstatus(Messenger *m) -{ - return m->userstatus; -} - -static int send_statusmessage(Messenger *m, int friendnumber, uint8_t * status, uint16_t length) -{ - return write_cryptpacket_id(m, friendnumber, PACKET_ID_STATUSMESSAGE, status, length); -} - -static int send_userstatus(Messenger *m, int friendnumber, USERSTATUS status) -{ - uint8_t stat = status; - return write_cryptpacket_id(m, friendnumber, PACKET_ID_USERSTATUS, &stat, sizeof(stat)); -} - -static int set_friend_statusmessage(Messenger *m, int friendnumber, uint8_t * status, uint16_t length) -{ - if (friendnumber >= m->numfriends || friendnumber < 0) - return -1; - uint8_t *newstatus = calloc(length, 1); - memcpy(newstatus, status, length); - free(m->friendlist[friendnumber].statusmessage); - m->friendlist[friendnumber].statusmessage = newstatus; - m->friendlist[friendnumber].statusmessage_length = length; - return 0; -} - -static void set_friend_userstatus(Messenger *m, int friendnumber, USERSTATUS status) -{ - m->friendlist[friendnumber].userstatus = status; -} - -/* Sets whether we send read receipts for friendnumber. */ -void m_set_sends_receipts(Messenger *m, int friendnumber, int yesno) -{ - if (yesno != 0 || yesno != 1) - return; - if (friendnumber >= m->numfriends || friendnumber < 0) - return; - m->friendlist[friendnumber].receives_read_receipts = yesno; -} - -/* static void (*friend_request)(uint8_t *, uint8_t *, uint16_t); -static uint8_t friend_request_isset = 0; */ -/* set the function that will be executed when a friend request is received. */ -void m_callback_friendrequest(Messenger *m, void (*function)(uint8_t *, uint8_t *, uint16_t, void*), void* userdata) -{ - callback_friendrequest(function, userdata); -} - -/* set the function that will be executed when a message from a friend is received. */ -void m_callback_friendmessage(Messenger *m, void (*function)(Messenger *m, int, uint8_t *, uint16_t, void*), void* userdata) -{ - m->friend_message = function; - m->friend_message_isset = 1; - m->friend_message_userdata = userdata; -} - -void m_callback_action(Messenger *m, void (*function)(Messenger *m, int, uint8_t *, uint16_t, void*), void* userdata) -{ - m->friend_action = function; - m->friend_action_isset = 1; - m->friend_action_userdata = userdata; -} - -void m_callback_namechange(Messenger *m, void (*function)(Messenger *m, int, uint8_t *, uint16_t, void*), void* userdata) -{ - m->friend_namechange = function; - m->friend_namechange_isset = 1; - m->friend_namechange_userdata = userdata; -} - -void m_callback_statusmessage(Messenger *m, void (*function)(Messenger *m, int, uint8_t *, uint16_t, void*), void* userdata) -{ - m->friend_statusmessagechange = function; - m->friend_statusmessagechange_isset = 1; - m->friend_statuschange_userdata = userdata; -} - -void m_callback_userstatus(Messenger *m, void (*function)(Messenger *m, int, USERSTATUS, void*), void* userdata) -{ - m->friend_userstatuschange = function; - m->friend_userstatuschange_isset = 1; - m->friend_userstatuschange_userdata = userdata; -} - -void m_callback_read_receipt(Messenger *m, void (*function)(Messenger *m, int, uint32_t, void*), void* userdata) -{ - m->read_receipt = function; - m->read_receipt_isset = 1; - m->read_receipt_userdata = userdata; -} - -void m_callback_connectionstatus(Messenger *m, void (*function)(Messenger *m, int, uint8_t, void*), void* userdata) -{ - m->friend_connectionstatuschange = function; - m->friend_connectionstatuschange_isset = 1; - m->friend_connectionstatuschange_userdata = userdata; -} - -static void check_friend_connectionstatus(Messenger *m, int friendnumber, uint8_t status) -{ - if (!m->friend_connectionstatuschange_isset) - return; - if (status == NOFRIEND) - return; - const uint8_t was_connected = m->friendlist[friendnumber].status == FRIEND_ONLINE; - const uint8_t is_connected = status == FRIEND_ONLINE; - if (is_connected != was_connected) - m->friend_connectionstatuschange(m, friendnumber, is_connected, m->friend_connectionstatuschange_userdata); -} - -void set_friend_status(Messenger *m, int friendnumber, uint8_t status) -{ - check_friend_connectionstatus(m, friendnumber, status); - m->friendlist[friendnumber].status = status; -} - -int write_cryptpacket_id(Messenger *m, int friendnumber, uint8_t packet_id, uint8_t *data, uint32_t length) -{ - if (friendnumber < 0 || friendnumber >= m->numfriends) - return 0; - if (length >= MAX_DATA_SIZE || m->friendlist[friendnumber].status != FRIEND_ONLINE) - return 0; - uint8_t packet[length + 1]; - packet[0] = packet_id; - memcpy(packet + 1, data, length); - return write_cryptpacket(m->friendlist[friendnumber].crypt_connection_id, packet, length + 1); -} - -<<<<<<< HEAD -======= -#define PORT 33445 -/* run this at startup */ -Messenger * initMessenger(void) -{ - Messenger *m = calloc(1, sizeof(Messenger)); - if( ! m ) - return 0; - - new_keys(); - m_set_statusmessage(m, (uint8_t*)"Online", sizeof("Online")); - initNetCrypto(); - IP ip; - ip.i = 0; - - if(init_networking(ip,PORT) == -1) - return 0; - - DHT_init(); - LosslessUDP_init(); - friendreq_init(); - LANdiscovery_init(); - - return m; -} - -/* run this before closing shop */ -void cleanupMessenger(Messenger *m){ - /* FIXME TODO it seems no one frees friendlist or all the elements status */ - free(m); -} - ->>>>>>> upstream/master -//TODO: make this function not suck. -void doFriends(Messenger *m) -{ - /* TODO: add incoming connections and some other stuff. */ - uint32_t i; - int len; - uint8_t temp[MAX_DATA_SIZE]; - for (i = 0; i < m->numfriends; ++i) { - if (m->friendlist[i].status == FRIEND_ADDED) { - int fr = send_friendrequest(m->friendlist[i].client_id, m->friendlist[i].info, m->friendlist[i].info_size); - if (fr == 0) /* TODO: This needs to be fixed so that it sends the friend requests a couple of times in case of packet loss */ - set_friend_status(m, i, FRIEND_REQUESTED); - else if (fr > 0) - set_friend_status(m, i, FRIEND_REQUESTED); - } - if (m->friendlist[i].status == FRIEND_REQUESTED || m->friendlist[i].status == FRIEND_CONFIRMED) { /* friend is not online */ - if (m->friendlist[i].status == FRIEND_REQUESTED) { - if (m->friendlist[i].friend_request_id + 10 < unix_time()) { /*I know this is hackish but it should work.*/ - send_friendrequest(m->friendlist[i].client_id, m->friendlist[i].info, m->friendlist[i].info_size); - m->friendlist[i].friend_request_id = unix_time(); - } - } - IP_Port friendip = DHT_getfriendip(m->friendlist[i].client_id); - switch (is_cryptoconnected(m->friendlist[i].crypt_connection_id)) { - case 0: - if (friendip.ip.i > 1) - m->friendlist[i].crypt_connection_id = crypto_connect(m->friendlist[i].client_id, friendip); - break; - case 3: /* Connection is established */ - set_friend_status(m, i, FRIEND_ONLINE); - m->friendlist[i].name_sent = 0; - m->friendlist[i].userstatus_sent = 0; - m->friendlist[i].statusmessage_sent = 0; - break; - case 4: - crypto_kill(m->friendlist[i].crypt_connection_id); - m->friendlist[i].crypt_connection_id = -1; - break; - default: - break; - } - } - while (m->friendlist[i].status == FRIEND_ONLINE) { /* friend is online */ - if (m->friendlist[i].name_sent == 0) { - if (m_sendname(m, i, m->name, m->name_length)) - m->friendlist[i].name_sent = 1; - } - if (m->friendlist[i].statusmessage_sent == 0) { - if (send_statusmessage(m, i, m->statusmessage, m->statusmessage_length)) - m->friendlist[i].statusmessage_sent = 1; - } - if (m->friendlist[i].userstatus_sent == 0) { - if (send_userstatus(m, i, m->userstatus)) - m->friendlist[i].userstatus_sent = 1; - } - len = read_cryptpacket(m->friendlist[i].crypt_connection_id, temp); - uint8_t packet_id = temp[0]; - uint8_t* data = temp + 1; - int data_length = len - 1; - if (len > 0) { - switch (packet_id) { - case PACKET_ID_NICKNAME: { - if (data_length >= MAX_NAME_LENGTH || data_length == 0) - break; - if(m->friend_namechange_isset) - m->friend_namechange(m, i, data, data_length, m->friend_namechange_userdata); - memcpy(m->friendlist[i].name, data, data_length); - m->friendlist[i].name[data_length - 1] = 0; /* make sure the NULL terminator is present. */ - break; - } - case PACKET_ID_STATUSMESSAGE: { - if (data_length == 0) - break; - uint8_t *status = calloc(MIN(data_length, MAX_STATUSMESSAGE_LENGTH), 1); - memcpy(status, data, MIN(data_length, MAX_STATUSMESSAGE_LENGTH)); - if (m->friend_statusmessagechange_isset) - m->friend_statusmessagechange(m, i, status, MIN(data_length, MAX_STATUSMESSAGE_LENGTH), - m->friend_statuschange_userdata); - set_friend_statusmessage(m, i, status, MIN(data_length, MAX_STATUSMESSAGE_LENGTH)); - free(status); - break; - } - case PACKET_ID_USERSTATUS: { - if (data_length != 1) - break; - USERSTATUS status = data[0]; - if (m->friend_userstatuschange_isset) - m->friend_userstatuschange(m, i, status, m->friend_userstatuschange_userdata); - set_friend_userstatus(m, i, status); - break; - } - case PACKET_ID_MESSAGE: { - uint8_t *message_id = data; - uint8_t message_id_length = 4; - uint8_t *message = data + message_id_length; - uint16_t message_length = data_length - message_id_length; - if (m->friendlist[i].receives_read_receipts) { - write_cryptpacket_id(m, i, PACKET_ID_RECEIPT, message_id, message_id_length); - } - if (m->friend_message_isset) - (*m->friend_message)(m, i, message, message_length, m->friend_message_userdata); - break; - } - case PACKET_ID_ACTION: { - if (m->friend_action_isset) - (*m->friend_action)(m, i, data, data_length, m->friend_action_userdata); - break; - } - case PACKET_ID_RECEIPT: { - uint32_t msgid; - if (data_length < sizeof(msgid)) - break; - memcpy(&msgid, data, sizeof(msgid)); - msgid = ntohl(msgid); - if (m->read_receipt_isset) - (*m->read_receipt)(m, i, msgid, m->read_receipt_userdata); - break; - } - } - } else { - if (is_cryptoconnected(m->friendlist[i].crypt_connection_id) == 4) { /* if the connection timed out, kill it */ - crypto_kill(m->friendlist[i].crypt_connection_id); - m->friendlist[i].crypt_connection_id = -1; - set_friend_status(m, i, FRIEND_CONFIRMED); - } - break; - } - } - } -} - -void doInbound(Messenger *m) -{ - uint8_t secret_nonce[crypto_box_NONCEBYTES]; - uint8_t public_key[crypto_box_PUBLICKEYBYTES]; - uint8_t session_key[crypto_box_PUBLICKEYBYTES]; - int inconnection = crypto_inbound(public_key, secret_nonce, session_key); - if (inconnection != -1) { - int friend_id = getfriend_id(m, public_key); - if (friend_id != -1) { - crypto_kill(m->friendlist[friend_id].crypt_connection_id); - m->friendlist[friend_id].crypt_connection_id = - accept_crypto_inbound(inconnection, public_key, secret_nonce, session_key); - - set_friend_status(m, friend_id, FRIEND_CONFIRMED); - } - } -} - -#define PORT 33445 - -/*Interval in seconds between LAN discovery packet sending*/ -#define LAN_DISCOVERY_INTERVAL 60 - -/*Send a LAN discovery packet every LAN_DISCOVERY_INTERVAL seconds*/ -<<<<<<< HEAD -static int LANdiscovery_timercallback(timer* t, void* ignore) -======= -void LANdiscovery(Messenger *m) ->>>>>>> upstream/master -{ - send_LANdiscovery(htons(PORT)); - timer_start(t, LAN_DISCOVERY_INTERVAL); - return 0; -} - -/* run this at startup */ -int initMessenger(void) -{ - timer_init(); - new_keys(); - m_set_statusmessage((uint8_t*)"Online", sizeof("Online")); - initNetCrypto(); - IP ip; - ip.i = 0; - - if(init_networking(ip,PORT) == -1) - return -1; - - DHT_init(); - LosslessUDP_init(); - friendreq_init(); - LANdiscovery_init(); - - timer_single(&LANdiscovery_timercallback, 0, LAN_DISCOVERY_INTERVAL); - - return 0; -} - -/* the main loop that needs to be run at least 200 times per second. */ -void doMessenger(Messenger *m) -{ - networking_poll(); -<<<<<<< HEAD - timer_poll(); - - doDHT(); - doLossless_UDP(); - doNetCrypto(); - doInbound(); - doFriends(); -======= - - doDHT(); - doLossless_UDP(); - doNetCrypto(); - doInbound(m); - doFriends(m); - LANdiscovery(m); ->>>>>>> upstream/master -} - -/* returns the size of the messenger data (for saving) */ -uint32_t Messenger_size(Messenger *m) -{ - return crypto_box_PUBLICKEYBYTES + crypto_box_SECRETKEYBYTES - + sizeof(uint32_t) + DHT_size() + sizeof(uint32_t) + sizeof(Friend) * m->numfriends; -} - -/* save the messenger in data of size Messenger_size() */ -void Messenger_save(Messenger *m, uint8_t *data) -{ - save_keys(data); - data += crypto_box_PUBLICKEYBYTES + crypto_box_SECRETKEYBYTES; - uint32_t size = DHT_size(); - memcpy(data, &size, sizeof(size)); - data += sizeof(size); - DHT_save(data); - data += size; - size = sizeof(Friend) * m->numfriends; - memcpy(data, &size, sizeof(size)); - data += sizeof(size); - memcpy(data, m->friendlist, sizeof(Friend) * m->numfriends); -} - -/* load the messenger from data of size length. */ -int Messenger_load(Messenger *m, uint8_t * data, uint32_t length) -{ - if (length == ~0) - return -1; - if (length < crypto_box_PUBLICKEYBYTES + crypto_box_SECRETKEYBYTES + sizeof(uint32_t) * 2) - return -1; - length -= crypto_box_PUBLICKEYBYTES + crypto_box_SECRETKEYBYTES + sizeof(uint32_t) * 2; - load_keys(data); - data += crypto_box_PUBLICKEYBYTES + crypto_box_SECRETKEYBYTES; - uint32_t size; - memcpy(&size, data, sizeof(size)); - data += sizeof(size); - - if (length < size) - return -1; - length -= size; - if (DHT_load(data, size) == -1) - return -1; - data += size; - memcpy(&size, data, sizeof(size)); - data += sizeof(size); - if (length != size || length % sizeof(Friend) != 0) - return -1; - - Friend * temp = malloc(size); - memcpy(temp, data, size); - - uint16_t num = size / sizeof(Friend); - - uint32_t i; - for (i = 0; i < num; ++i) { - if(temp[i].status != 0) { - int fnum = m_addfriend_norequest(m, temp[i].client_id); - setfriendname(m, fnum, temp[i].name); - /* set_friend_statusmessage(fnum, temp[i].statusmessage, temp[i].statusmessage_length); */ - } - } - free(temp); - return 0; -} - From 471c14809004bd0ac531cbb79b06906f128cb666 Mon Sep 17 00:00:00 2001 From: slvr Date: Tue, 13 Aug 2013 09:55:49 +0100 Subject: [PATCH 8/8] Portabily print out uint64_t using PRIu64 --- core/timer.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/core/timer.c b/core/timer.c index 8c278434..06e25693 100644 --- a/core/timer.c +++ b/core/timer.c @@ -1,6 +1,8 @@ +#define __STDC_FORMAT_MACROS +#include + #include "timer.h" #include "network.h" -#include /* A nested linked list increases efficiency of insertions. @@ -267,7 +269,7 @@ void timer_debug_print() timer* t = timer_main_queue; printf("Queue:\n"); while (t) { - printf("%lli (%lli) : %s\n", t->deadline, t->deadline/US_PER_SECOND, (char*)t->userdata); + printf("%" PRIu64 " (%" PRIu64 ") : %s\n", t->deadline, t->deadline/US_PER_SECOND, (char*)t->userdata); t = t->_next; } }