From 9d57d3256bd7d5c119daa44c651013be8eab9546 Mon Sep 17 00:00:00 2001 From: iphydf Date: Wed, 29 Dec 2021 02:18:00 +0000 Subject: [PATCH 1/3] feat: Add back the `tox_loop` implementation for low latency. Copied code from https://github.com/TokTok/c-toxcore/pull/335. --- CMakeLists.txt | 1 + auto_tests/tox_loop_test.c | 105 +++++++++++++ toxcore/Messenger.c | 24 ++- toxcore/Messenger.h | 11 ++ toxcore/TCP_client.c | 24 +++ toxcore/TCP_client.h | 1 + toxcore/TCP_connection.c | 32 ++++ toxcore/TCP_connection.h | 4 + toxcore/network.c | 24 +++ toxcore/network.h | 1 + toxcore/tox.c | 299 +++++++++++++++++++++++++++++++++++++ toxcore/tox.h | 70 +++++++++ 12 files changed, 594 insertions(+), 2 deletions(-) create mode 100644 auto_tests/tox_loop_test.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 59ed2ffb7c..a2b5de9861 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -437,6 +437,7 @@ auto_test(send_message) auto_test(set_name) auto_test(set_status_message) auto_test(skeleton) +auto_test(tox_loop) auto_test(tox_many) auto_test(tox_many_tcp) auto_test(tox_one) diff --git a/auto_tests/tox_loop_test.c b/auto_tests/tox_loop_test.c new file mode 100644 index 0000000000..66dc716bdc --- /dev/null +++ b/auto_tests/tox_loop_test.c @@ -0,0 +1,105 @@ +#include +#include +#include +#include + +#include "../toxcore/tox.h" + +#include "check_compat.h" + +#define TCP_RELAY_PORT 33448 +/* The Travis-CI container responds poorly to ::1 as a localhost address + * You're encouraged to -D FORCE_TESTS_IPV6 on a local test */ +#ifdef FORCE_TESTS_IPV6 +#define TOX_LOCALHOST "::1" +#else +#define TOX_LOCALHOST "127.0.0.1" +#endif + +typedef struct Loop_Test { + int start_count; + int stop_count; + pthread_mutex_t mutex; + Tox *tox; +} Loop_Test; + +static void tox_loop_cb_start(Tox *tox, void *user_data) +{ + Loop_Test *userdata = (Loop_Test *)user_data; + pthread_mutex_lock(&userdata->mutex); + userdata->start_count++; +} + +static void tox_loop_cb_stop(Tox *tox, void *user_data) +{ + Loop_Test *userdata = (Loop_Test *) user_data; + userdata->stop_count++; + pthread_mutex_unlock(&userdata->mutex); +} + +static void *tox_loop_worker(void *data) +{ + Loop_Test *userdata = (Loop_Test *) data; + tox_loop(userdata->tox, data, nullptr); + return nullptr; +} + +static void test_tox_loop(void) +{ + pthread_t worker, worker_tcp; + struct Tox_Options *opts = tox_options_new(nullptr); + Loop_Test userdata; + uint8_t dpk[TOX_PUBLIC_KEY_SIZE]; + int retval; + + userdata.start_count = 0; + userdata.stop_count = 0; + pthread_mutex_init(&userdata.mutex, nullptr); + + tox_options_set_tcp_port(opts, TCP_RELAY_PORT); + userdata.tox = tox_new(opts, nullptr); + tox_callback_loop_begin(userdata.tox, tox_loop_cb_start); + tox_callback_loop_end(userdata.tox, tox_loop_cb_stop); + pthread_create(&worker, nullptr, tox_loop_worker, &userdata); + + tox_self_get_dht_id(userdata.tox, dpk); + + tox_options_default(opts); + Loop_Test userdata_tcp; + userdata_tcp.start_count = 0; + userdata_tcp.stop_count = 0; + pthread_mutex_init(&userdata_tcp.mutex, nullptr); + userdata_tcp.tox = tox_new(opts, nullptr); + tox_callback_loop_begin(userdata_tcp.tox, tox_loop_cb_start); + tox_callback_loop_end(userdata_tcp.tox, tox_loop_cb_stop); + pthread_create(&worker_tcp, nullptr, tox_loop_worker, &userdata_tcp); + + pthread_mutex_lock(&userdata_tcp.mutex); + TOX_ERR_BOOTSTRAP error; + ck_assert_msg(tox_add_tcp_relay(userdata_tcp.tox, TOX_LOCALHOST, TCP_RELAY_PORT, dpk, &error), "Add relay error, %i", + error); + ck_assert_msg(tox_bootstrap(userdata_tcp.tox, TOX_LOCALHOST, 33445, dpk, &error), "Bootstrap error, %i", error); + pthread_mutex_unlock(&userdata_tcp.mutex); + + sleep(10); + + tox_loop_stop(userdata.tox); + pthread_join(worker, (void **)(void *)&retval); + ck_assert_msg(retval == 0, "tox_loop didn't return 0"); + + tox_kill(userdata.tox); + ck_assert_msg(userdata.start_count == userdata.stop_count, "start and stop must match"); + + tox_loop_stop(userdata_tcp.tox); + pthread_join(worker_tcp, (void **)(void *)&retval); + ck_assert_msg(retval == 0, "tox_loop didn't return 0"); + + tox_kill(userdata_tcp.tox); + ck_assert_msg(userdata_tcp.start_count == userdata_tcp.stop_count, "start and stop must match"); +} + +int main(int argc, char *argv[]) +{ + test_tox_loop(); + return 0; +} diff --git a/toxcore/Messenger.c b/toxcore/Messenger.c index bf1a3c4016..70fa348fda 100644 --- a/toxcore/Messenger.c +++ b/toxcore/Messenger.c @@ -1888,15 +1888,31 @@ Messenger *new_messenger(Mono_Time *mono_time, Messenger_Options *options, unsig Messenger *m = (Messenger *)calloc(1, sizeof(Messenger)); - if (!m) { + if (m == nullptr) { return nullptr; } + +#ifdef HAVE_LIBEV + m->dispatcher = ev_loop_new(0); +#else + m->loop_run = false; +#endif // HAVE_LIBEV + +#if defined(HAVE_LIBEV) + + if (m->dispatcher == nullptr) { + free(m); + return nullptr; + } + +#endif // HAVE_LIBEV + m->mono_time = mono_time; m->fr = friendreq_new(); - if (!m->fr) { + if (m->fr == nullptr) { free(m); return nullptr; } @@ -2044,6 +2060,10 @@ void kill_messenger(Messenger *m) clear_receipts(m, i); } +#ifdef HAVE_LIBEV + ev_loop_destroy(m->dispatcher); +#endif + logger_kill(m->log); free(m->friendlist); friendreq_kill(m->fr); diff --git a/toxcore/Messenger.h b/toxcore/Messenger.h index bbe1633a2f..6a729a8c12 100644 --- a/toxcore/Messenger.h +++ b/toxcore/Messenger.h @@ -16,6 +16,10 @@ #include "net_crypto.h" #include "state.h" +#ifdef HAVE_LIBEV +#include +#endif + #define MAX_NAME_LENGTH 128 /* TODO(irungentoo): this must depend on other variable. */ #define MAX_STATUSMESSAGE_LENGTH 1007 @@ -291,6 +295,13 @@ struct Messenger { m_self_connection_status_cb *core_connection_change; unsigned int last_connection_status; +#ifdef HAVE_LIBEV + struct ev_loop *dispatcher; + ev_async stop_loop; +#else + bool loop_run; +#endif + Messenger_Options options; }; diff --git a/toxcore/TCP_client.c b/toxcore/TCP_client.c index 9899a93958..e0a20b6b03 100644 --- a/toxcore/TCP_client.c +++ b/toxcore/TCP_client.c @@ -12,6 +12,10 @@ #include #include +#ifdef HAVE_LIBEV +#include +#endif + #include "mono_time.h" #include "util.h" @@ -22,9 +26,19 @@ typedef struct TCP_Client_Conn { uint32_t number; } TCP_Client_Conn; +#ifdef HAVE_LIBEV +typedef struct TCP_Client_Socket_Listener { + ev_io listener; + struct ev_loop *dispatcher; +} TCP_Client_Socket_Listener; +#endif + struct TCP_Client_Connection { TCP_Client_Status status; Socket sock; +#ifdef HAVE_LIBEV + TCP_Client_Socket_Listener sock_listener; +#endif uint8_t self_public_key[CRYPTO_PUBLIC_KEY_SIZE]; /* our public key */ uint8_t public_key[CRYPTO_PUBLIC_KEY_SIZE]; /* public key of the server */ IP_Port ip_port; /* The ip and port of the server */ @@ -79,6 +93,11 @@ IP_Port tcp_con_ip_port(const TCP_Client_Connection *con) return con->ip_port; } +Socket tcp_con_sock(const TCP_Client_Connection *con) +{ + return con->sock; +} + TCP_Client_Status tcp_con_status(const TCP_Client_Connection *con) { return con->status; @@ -1052,6 +1071,11 @@ void kill_TCP_connection(TCP_Client_Connection *tcp_connection) wipe_priority_list(tcp_connection->priority_queue_start); kill_sock(tcp_connection->sock); + +#ifdef HAVE_LIBEV + ev_io_stop(tcp_connection->sock_listener.dispatcher, &tcp_connection->sock_listener.listener); +#endif + crypto_memzero(tcp_connection, sizeof(TCP_Client_Connection)); free(tcp_connection); } diff --git a/toxcore/TCP_client.h b/toxcore/TCP_client.h index fed8b63738..c221daf5b8 100644 --- a/toxcore/TCP_client.h +++ b/toxcore/TCP_client.h @@ -40,6 +40,7 @@ typedef struct TCP_Client_Connection TCP_Client_Connection; const uint8_t *tcp_con_public_key(const TCP_Client_Connection *con); IP_Port tcp_con_ip_port(const TCP_Client_Connection *con); +Socket tcp_con_sock(const TCP_Client_Connection *con); TCP_Client_Status tcp_con_status(const TCP_Client_Connection *con); void *tcp_con_custom_object(const TCP_Client_Connection *con); diff --git a/toxcore/TCP_connection.c b/toxcore/TCP_connection.c index e128ca0fbf..6a2eab3fb9 100644 --- a/toxcore/TCP_connection.c +++ b/toxcore/TCP_connection.c @@ -56,6 +56,38 @@ uint32_t tcp_connections_count(const TCP_Connections *tcp_c) return tcp_c->tcp_connections_length; } + +/** + * Return number of elements of TCP connection array. + * + * @param tcp_c struct containing TCP_con array. + * + * @return number of elements of TCP connection array. + */ +uint32_t tcp_connections_length(const TCP_Connections *tcp_c) +{ + return tcp_c->tcp_connections_length; +} + + +/** + * Return TCP connection stored at "idx" position. + * + * @param tcp_c struct containing TCP_con array. + * @param idx index of TCP connection to return (values from 0 to tcp_connections_length() - 1). + * + * @return TCP connection stored at "idx" position, or NULL if errors occurred. + */ +const TCP_con *tcp_connections_connection_at(const TCP_Connections *tcp_c, uint32_t idx) +{ + if (idx >= tcp_c->tcp_connections_length) { + return nullptr; + } + + return &tcp_c->tcp_connections[idx]; +} + + /** Set the size of the array to num. * * return -1 if realloc fails. diff --git a/toxcore/TCP_connection.h b/toxcore/TCP_connection.h index d27b3e941d..048b9fc183 100644 --- a/toxcore/TCP_connection.h +++ b/toxcore/TCP_connection.h @@ -70,6 +70,10 @@ typedef struct TCP_Connections TCP_Connections; const uint8_t *tcp_connections_public_key(const TCP_Connections *tcp_c); +uint32_t tcp_connections_length(const TCP_Connections *tcp_c); + +const TCP_con *tcp_connections_connection_at(const TCP_Connections *tcp_c, uint32_t idx); + uint32_t tcp_connections_count(const TCP_Connections *tcp_c); /** Returns the number of connected TCP relays */ diff --git a/toxcore/network.c b/toxcore/network.c index 00be27476d..6b34568064 100644 --- a/toxcore/network.c +++ b/toxcore/network.c @@ -86,6 +86,10 @@ #include #include +#ifdef HAVE_LIBEV +#include +#endif + #ifndef VANILLA_NACL // Used for sodium_init() #include @@ -482,6 +486,13 @@ typedef struct Packet_Handler { void *object; } Packet_Handler; +#ifdef HAVE_LIBEV +typedef struct Networking_Socket_Listener { + ev_io listener; + struct ev_loop *dispatcher; +} Networking_Socket_Listener; +#endif + struct Networking_Core { const Logger *log; Packet_Handler packethandlers[256]; @@ -490,6 +501,9 @@ struct Networking_Core { uint16_t port; /* Our UDP socket. */ Socket sock; +#ifdef HAVE_LIBEV + Networking_Socket_Listener sock_listener; +#endif }; Family net_family(const Networking_Core *net) @@ -502,6 +516,11 @@ uint16_t net_port(const Networking_Core *net) return net->port; } +Socket net_sock(const Networking_Core *net) +{ + return net->sock; +} + /* Basic network functions: */ @@ -1003,6 +1022,11 @@ void kill_networking(Networking_Core *net) kill_sock(net->sock); } + +#ifdef HAVE_LIBEV + ev_io_stop(net->sock_listener.dispatcher, &net->sock_listener.listener); +#endif + free(net); } diff --git a/toxcore/network.h b/toxcore/network.h index b3b8da246e..378e863ebb 100644 --- a/toxcore/network.h +++ b/toxcore/network.h @@ -322,6 +322,7 @@ typedef struct Networking_Core Networking_Core; Family net_family(const Networking_Core *net); uint16_t net_port(const Networking_Core *net); +Socket net_sock(const Networking_Core *net); /** Run this before creating sockets. * diff --git a/toxcore/tox.c b/toxcore/tox.c index eaf5516cf3..bd432bf56d 100644 --- a/toxcore/tox.c +++ b/toxcore/tox.c @@ -21,9 +21,19 @@ #include "group.h" #include "logger.h" #include "mono_time.h" +#include "net_crypto.h" #include "../toxencryptsave/defines.h" +#include +#if !defined(HAVE_LIBEV) +#if defined (WIN32) || defined(_WIN32) || defined(__WIN32__) +#include +#else +#include +#endif // WIN32 || _WIN32 || __WIN32__ +#endif // !HAVE_LIBEV + #define SET_ERROR_PARAMETER(param, x) \ do { \ if (param) { \ @@ -48,6 +58,13 @@ static_assert(TOX_MAX_NAME_LENGTH == MAX_NAME_LENGTH, static_assert(TOX_MAX_STATUS_MESSAGE_LENGTH == MAX_STATUSMESSAGE_LENGTH, "TOX_MAX_STATUS_MESSAGE_LENGTH is assumed to be equal to MAX_STATUSMESSAGE_LENGTH"); +#if defined(HAVE_LIBEV) +typedef struct Event_Arg { + Tox *tox; + void *user_data; +} Event_Arg; +#endif + struct Tox { // XXX: Messenger *must* be the first member, because toxav casts its // `Tox *` to `Messenger **`. @@ -77,6 +94,9 @@ struct Tox { tox_friend_lossy_packet_cb *friend_lossy_packet_callback_per_pktid[UINT8_MAX + 1]; tox_friend_lossless_packet_cb *friend_lossless_packet_callback_per_pktid[UINT8_MAX + 1]; + tox_loop_begin_cb *loop_begin_callback; + tox_loop_end_cb *loop_end_callback; + void *toxav_object; // workaround to store a ToxAV object (setter and getter functions are available) }; @@ -612,6 +632,7 @@ void tox_kill(Tox *tox) lock(tox); LOGGER_ASSERT(tox->m->log, tox->m->msi_packet == nullptr, "Attempted to kill tox while toxav is still alive"); + tox_loop_stop(tox); kill_groupchats(tox->m->conferences_object); kill_messenger(tox->m); mono_time_free(tox->mono_time); @@ -817,6 +838,284 @@ void tox_iterate(Tox *tox, void *user_data) unlock(tox); } +void tox_callback_loop_begin(Tox *tox, tox_loop_begin_cb *callback) +{ + if (tox == nullptr) { + return; + } + + tox->loop_begin_callback = callback; +} + +void tox_callback_loop_end(Tox *tox, tox_loop_end_cb *callback) +{ + if (tox == nullptr) { + return; + } + + tox->loop_end_callback = callback; +} + +#ifdef HAVE_LIBEV +static void tox_stop_loop_async(struct ev_loop *dispatcher, ev_async *listener, int events) +{ + if (dispatcher == nullptr || listener == nullptr) { + return; + } + + Event_Arg *tmp = (Event_Arg *) listener->data; + Messenger *m = tmp->tox; + + if (ev_is_active(&m->net->sock_listener.listener) || ev_is_pending(&m->net->sock_listener.listener)) { + ev_io_stop(dispatcher, &m->net->sock_listener.listener); + } + + uint32_t len = tcp_connections_length(nc_get_tcp_c(m->net_crypto)); + + for (uint32_t i = 0; i < len; ++i) { + const TCP_con *conn = tcp_connections_connection_at(nc_get_tcp_c(m->net_crypto), i); + + if (ev_is_active(&conn->connection->sock_listener.listener) + || ev_is_pending(&conn->connection->sock_listener.listener)) { + ev_io_stop(dispatcher, &conn->connection->sock_listener.listener); + } + } + + ev_async_stop(dispatcher, listener); + + ev_break(dispatcher, EVBREAK_ALL); +} + +static void tox_do_iterate(struct ev_loop *dispatcher, ev_io *sock_listener, int events) +{ + if (dispatcher == nullptr || sock_listener == nullptr) { + return; + } + + Event_Arg *tmp = (Event_Arg *)sock_listener->data; + Messenger *m = tmp->tox->m; + + if (tmp->tox->loop_begin_callback) { + tmp->tox->loop_begin_callback(tmp->tox, tmp->user_data); + } + + tox_iterate(tmp->tox, tmp->user_data); + + if (!ev_is_active(&m->net->sock_listener.listener) && !ev_is_pending(&m->net->sock_listener.listener)) { + m->net->sock_listener.dispatcher = dispatcher; + ev_io_init(&m->net->sock_listener.listener, tox_do_iterate, net_sock(m->net), EV_READ); + m->net->sock_listener.listener.data = sock_listener->data; + ev_io_start(dispatcher, &m->net->sock_listener.listener); + } + + uint32_t len = tcp_connections_length(nc_get_tcp_c(m->net_crypto)); + + for (uint32_t i = 0; i < len; ++i) { + const TCP_con *conn = tcp_connections_connection_at(nc_get_tcp_c(m->net_crypto), i); + + if (!ev_is_active(&conn->connection->sock_listener.listener) + && !ev_is_pending(&conn->connection->sock_listener.listener)) { + conn->connection->sock_listener.dispatcher = dispatcher; + ev_io_init(&conn->connection->sock_listener.listener, tox_do_iterate, tcp_con_sock(conn->connection), EV_READ); + conn->connection->sock_listener.listener.data = sock_listener->data; + ev_io_start(m->dispatcher, &conn->connection->sock_listener.listener); + } + } + + if (m->loop_end_callback) { + m->loop_end_callback(m, tmp->user_data); + } +} +#else +/** + * Gathers a list of every network file descriptor, + * where an activity is expected on. + * + * @param sockets a pointer to an array (the pointed array can be NULL). + * @param sockets_num the number of current known sockets (will be updated by the funciton). + * + * @return false if errors occurred, true otherwise. + */ +static bool tox_fds(Messenger *m, Socket **sockets, uint32_t *sockets_num) +{ + if (m == nullptr || sockets == nullptr || sockets_num == nullptr) { + return false; + } + + Socket *tmp_sockets = *sockets; + + uint32_t len = tcp_connections_length(nc_get_tcp_c(m->net_crypto)); + uint32_t fdcount = 1 + len; + + if (fdcount != *sockets_num || tmp_sockets == nullptr) { + tmp_sockets = (Socket *)realloc(*sockets, fdcount * sizeof(Socket)); + + if (tmp_sockets == nullptr) { + return false; + } + + *sockets = tmp_sockets; + *sockets_num = fdcount; + } + + tmp_sockets[0] = net_sock(m->net); + + uint32_t i = 0; + + while (i < fdcount - 1 && i < len) { + const TCP_con *conn = tcp_connections_connection_at(nc_get_tcp_c(m->net_crypto), i); + ++i; + + if (conn != nullptr) { + tmp_sockets[i] = tcp_con_sock(conn->connection); + } else { + tmp_sockets[i] = (Socket) { + 0 + }; + } + } + + return true; +} +#endif + +bool tox_loop(Tox *tox, void *user_data, Tox_Err_Loop *error) +{ + Messenger *m = tox->m; + +#ifdef HAVE_LIBEV + bool ret = true; + Event_Arg *tmp = (Event_Arg *) calloc(1, sizeof(Event_Arg)); + + if (tmp == nullptr) { + SET_ERROR_PARAMETER(error, TOX_ERR_LOOP_MALLOC); + + return false; + } + + tmp->tox = tox; + tmp->user_data = user_data; + + ev_async_init(&m->stop_loop, tox_stop_loop_async); + m->stop_loop.data = tmp; + ev_async_start(m->dispatcher, &m->stop_loop); + + ev_io stub_listener; + ev_init(&stub_listener, tox_do_iterate); + stub_listener.data = tmp; + tox_do_iterate(m->dispatcher, &stub_listener, 0); + + // TODO(Ansa89): travis states that "ev_run" returns "void", + // but "man 3 ev" states it returns "bool" +#if 0 + ret = !ev_run(m->dispatcher, 0); + + if (ret) { + SET_ERROR_PARAMETER(error, TOX_ERR_LOOP_OK); + } else { + SET_ERROR_PARAMETER(error, TOX_ERR_LOOP_BREAK); + } + +#endif + + ev_run(m->dispatcher, 0); + + SET_ERROR_PARAMETER(error, TOX_ERR_LOOP_OK); + + free(tmp); +#else + bool ret = true; + uint32_t fdcount = 0; + Socket *fdlist = nullptr; + + m->loop_run = true; + + while (m->loop_run) { + Socket maxfd; + fd_set readable; + + if (tox->loop_begin_callback) { + tox->loop_begin_callback(tox, user_data); + } + + tox_iterate(tox, user_data); + + maxfd = (Socket) { + 0 + }; + FD_ZERO(&readable); + + // TODO(cleverca22): is it a good idea to reuse previous fdlist when + // fdcount!=0 && tox_fds()==false? + if (fdcount == 0 && !tox_fds(m, &fdlist, &fdcount)) { + // We must stop because maxfd won't be set. + // TODO(cleverca22): should we call loop_end_callback() on error? + if (tox->loop_end_callback) { + tox->loop_end_callback(tox, user_data); + } + + SET_ERROR_PARAMETER(error, TOX_ERR_LOOP_GET_FDS); + + free(fdlist); + + return false; + } + + for (uint32_t i = 0; i < fdcount; ++i) { + if (fdlist[i].socket == 0) { + continue; + } + + FD_SET(fdlist[i].socket, &readable); + + if (fdlist[i].socket > maxfd.socket) { + maxfd = fdlist[i]; + } + } + + struct timeval timeout; + + timeout.tv_sec = 0; + + // TODO(cleverca22): use a longer timeout. + timeout.tv_usec = tox_iteration_interval(tox) * 1000 * 2; + + if (tox->loop_end_callback) { + tox->loop_end_callback(tox, user_data); + } + + if (select(maxfd.socket, &readable, nullptr, nullptr, &timeout) < 0 && errno != EBADF) { + SET_ERROR_PARAMETER(error, TOX_ERR_LOOP_SELECT); + + free(fdlist); + + return false; + } + } + + SET_ERROR_PARAMETER(error, TOX_ERR_LOOP_OK); + + free(fdlist); +#endif + + return ret; +} + +void tox_loop_stop(Tox *tox) +{ + if (tox == nullptr) { + return; + } + + Messenger *m = tox->m; + +#ifdef HAVE_LIBEV + ev_async_send(m->dispatcher, &m->stop_loop); +#else + m->loop_run = false; +#endif +} + void tox_self_get_address(const Tox *tox, uint8_t *address) { assert(tox != nullptr); diff --git a/toxcore/tox.h b/toxcore/tox.h index 72f36f7dba..580acc00b2 100644 --- a/toxcore/tox.h +++ b/toxcore/tox.h @@ -1050,6 +1050,76 @@ uint32_t tox_iteration_interval(const Tox *tox); void tox_iterate(Tox *tox, void *user_data); +/** + * Error codes for tox_loop(). + */ +typedef enum Tox_Err_Loop { + + /** + * The function returned successfully. + */ + TOX_ERR_LOOP_OK, + + /** + * Memory allocation failed when creating an event listener. + */ + TOX_ERR_LOOP_MALLOC, + + /** + * Failed running events dispatcher. + */ + TOX_ERR_LOOP_BREAK, + + /** + * Failed running select(). + */ + TOX_ERR_LOOP_SELECT, + + /** + * Failed getting sockets file descriptors. + */ + TOX_ERR_LOOP_GET_FDS, + +} Tox_Err_Loop; + + +/** + * Run tox_iterate() any time a packet arrives, returns after tox_loop_stop() or tox_kill(). + */ +bool tox_loop(Tox *tox, void *user_data, Tox_Err_Loop *error); + +/** + * Tell tox_loop() to return. + */ +void tox_loop_stop(Tox *tox); + +/** + * No extra parameters. + */ +typedef void tox_loop_begin_cb(Tox *tox, void *user_data); + + +/** + * Set the callback for the `loop_begin` event. Pass NULL to unset. + * + * This callback is invoked when tox_loop() calls into tox_iterate(), the client can lock a mutex here. + */ +void tox_callback_loop_begin(Tox *tox, tox_loop_begin_cb *callback); + +/** + * No extra parameters. + */ +typedef void tox_loop_end_cb(Tox *tox, void *user_data); + + +/** + * Set the callback for the `loop_end` event. Pass NULL to unset. + * + * This callback is invoked when tox_loop() is finished with tox_iterate(), the client can unlock the mutex here. + */ +void tox_callback_loop_end(Tox *tox, tox_loop_end_cb *callback); + + /******************************************************************************* * * :: Internal client information (Tox address/id) From 6d95f60afd0517d17f7465874cd229f3c71d70a5 Mon Sep 17 00:00:00 2001 From: iphydf Date: Wed, 29 Dec 2021 12:31:13 +0000 Subject: [PATCH 2/3] slight refactoring --- toxcore/TCP_client.c | 23 +++++++++++++++++++++++ toxcore/TCP_client.h | 12 ++++++++++++ toxcore/network.c | 27 ++++++++++++++++++++++++--- toxcore/network.h | 12 ++++++++++++ toxcore/tox.c | 33 +++++++++++++-------------------- 5 files changed, 84 insertions(+), 23 deletions(-) diff --git a/toxcore/TCP_client.c b/toxcore/TCP_client.c index e0a20b6b03..ec0fd487c0 100644 --- a/toxcore/TCP_client.c +++ b/toxcore/TCP_client.c @@ -102,6 +102,29 @@ TCP_Client_Status tcp_con_status(const TCP_Client_Connection *con) { return con->status; } + +#ifdef HAVE_LIBEV +bool tcp_con_ev_is_active(TCP_Client_Connection *con) { + return ev_is_active(&con->sock_listener.listener) + || ev_is_pending(&con->sock_listener.listener); +} + +void tcp_con_ev_listen(TCP_Client_Connection *con, struct ev_loop *dispatcher, tcp_con_ev_listen_cb *callback, void *data) +{ + con->sock_listener.dispatcher = dispatcher; + con->sock_listener.listener.data = data; + + ev_io_init(&con->sock_listener.listener, callback, tcp_con_sock(con).socket, EV_READ); + ev_io_start(dispatcher, &con->sock_listener.listener); +} +#endif + +void tcp_con_ev_stop(TCP_Client_Connection *con) { +#ifdef HAVE_LIBEV + ev_io_stop(con->sock_listener.dispatcher, &con->sock_listener.listener); +#endif +} + void *tcp_con_custom_object(const TCP_Client_Connection *con) { return con->custom_object; diff --git a/toxcore/TCP_client.h b/toxcore/TCP_client.h index c221daf5b8..f36bd4728b 100644 --- a/toxcore/TCP_client.h +++ b/toxcore/TCP_client.h @@ -12,6 +12,10 @@ #include "TCP_server.h" #include "crypto_core.h" +#ifdef HAVE_LIBEV +#include +#endif + #define TCP_CONNECTION_TIMEOUT 10 typedef enum TCP_Proxy_Type { @@ -43,6 +47,14 @@ IP_Port tcp_con_ip_port(const TCP_Client_Connection *con); Socket tcp_con_sock(const TCP_Client_Connection *con); TCP_Client_Status tcp_con_status(const TCP_Client_Connection *con); +#ifdef HAVE_LIBEV +bool tcp_con_ev_is_active(TCP_Client_Connection *con); + +typedef void tcp_con_ev_listen_cb(struct ev_loop *dispatcher, ev_io *sock_listener, int events); +void tcp_con_ev_listen(TCP_Client_Connection *con, struct ev_loop *dispatcher, tcp_con_ev_listen_cb *callback, void *data); +#endif +void tcp_con_ev_stop(TCP_Client_Connection *con); + void *tcp_con_custom_object(const TCP_Client_Connection *con); uint32_t tcp_con_custom_uint(const TCP_Client_Connection *con); void tcp_con_set_custom_object(TCP_Client_Connection *con, void *object); diff --git a/toxcore/network.c b/toxcore/network.c index 6b34568064..b358f8872c 100644 --- a/toxcore/network.c +++ b/toxcore/network.c @@ -521,6 +521,29 @@ Socket net_sock(const Networking_Core *net) return net->sock; } +#ifdef HAVE_LIBEV +bool net_ev_is_active(Networking_Core *net) +{ + return ev_is_active(&net->sock_listener.listener) || ev_is_pending(&net->sock_listener.listener); +} + +void net_ev_listen(Networking_Core *net, struct ev_loop *dispatcher, net_ev_listen_cb *callback, void *data) +{ + net->sock_listener.dispatcher = dispatcher; + net->sock_listener.listener.data = data; + + ev_io_init(&net->sock_listener.listener, callback, net_sock(net).socket, EV_READ); + ev_io_start(dispatcher, &net->sock_listener.listener); +} +#endif + +void net_ev_stop(Networking_Core *net) +{ +#ifdef HAVE_LIBEV + ev_io_stop(net->sock_listener.dispatcher, &net->sock_listener.listener); +#endif +} + /* Basic network functions: */ @@ -1023,9 +1046,7 @@ void kill_networking(Networking_Core *net) } -#ifdef HAVE_LIBEV - ev_io_stop(net->sock_listener.dispatcher, &net->sock_listener.listener); -#endif + net_ev_stop(net); free(net); } diff --git a/toxcore/network.h b/toxcore/network.h index 378e863ebb..82db948ccc 100644 --- a/toxcore/network.h +++ b/toxcore/network.h @@ -15,6 +15,10 @@ #include // size_t #include // uint*_t +#ifdef HAVE_LIBEV +#include // uint*_t +#endif + #ifdef __cplusplus extern "C" { #endif @@ -324,6 +328,14 @@ Family net_family(const Networking_Core *net); uint16_t net_port(const Networking_Core *net); Socket net_sock(const Networking_Core *net); +#ifdef HAVE_LIBEV +bool net_ev_is_active(Networking_Core *net); + +typedef void net_ev_listen_cb(struct ev_loop *dispatcher, ev_io *sock_listener, int events); +void net_ev_listen(Networking_Core *net, struct ev_loop *dispatcher, net_ev_listen_cb *callback, void *data); +#endif +void net_ev_stop(Networking_Core *net); + /** Run this before creating sockets. * * return 0 on success diff --git a/toxcore/tox.c b/toxcore/tox.c index bd432bf56d..b71062e939 100644 --- a/toxcore/tox.c +++ b/toxcore/tox.c @@ -864,10 +864,10 @@ static void tox_stop_loop_async(struct ev_loop *dispatcher, ev_async *listener, } Event_Arg *tmp = (Event_Arg *) listener->data; - Messenger *m = tmp->tox; + Messenger *m = tmp->tox->m; - if (ev_is_active(&m->net->sock_listener.listener) || ev_is_pending(&m->net->sock_listener.listener)) { - ev_io_stop(dispatcher, &m->net->sock_listener.listener); + if (net_ev_is_active(m->net)) { + net_ev_stop(m->net); } uint32_t len = tcp_connections_length(nc_get_tcp_c(m->net_crypto)); @@ -875,9 +875,8 @@ static void tox_stop_loop_async(struct ev_loop *dispatcher, ev_async *listener, for (uint32_t i = 0; i < len; ++i) { const TCP_con *conn = tcp_connections_connection_at(nc_get_tcp_c(m->net_crypto), i); - if (ev_is_active(&conn->connection->sock_listener.listener) - || ev_is_pending(&conn->connection->sock_listener.listener)) { - ev_io_stop(dispatcher, &conn->connection->sock_listener.listener); + if (tcp_con_ev_is_active(conn->connection)) { + tcp_con_ev_stop(conn->connection); } } @@ -893,7 +892,8 @@ static void tox_do_iterate(struct ev_loop *dispatcher, ev_io *sock_listener, int } Event_Arg *tmp = (Event_Arg *)sock_listener->data; - Messenger *m = tmp->tox->m; + Tox *tox = tmp->tox; + Messenger *m = tox->m; if (tmp->tox->loop_begin_callback) { tmp->tox->loop_begin_callback(tmp->tox, tmp->user_data); @@ -901,11 +901,8 @@ static void tox_do_iterate(struct ev_loop *dispatcher, ev_io *sock_listener, int tox_iterate(tmp->tox, tmp->user_data); - if (!ev_is_active(&m->net->sock_listener.listener) && !ev_is_pending(&m->net->sock_listener.listener)) { - m->net->sock_listener.dispatcher = dispatcher; - ev_io_init(&m->net->sock_listener.listener, tox_do_iterate, net_sock(m->net), EV_READ); - m->net->sock_listener.listener.data = sock_listener->data; - ev_io_start(dispatcher, &m->net->sock_listener.listener); + if (!net_ev_is_active(m->net)) { + net_ev_listen(m->net, dispatcher, tox_do_iterate, tmp); } uint32_t len = tcp_connections_length(nc_get_tcp_c(m->net_crypto)); @@ -913,17 +910,13 @@ static void tox_do_iterate(struct ev_loop *dispatcher, ev_io *sock_listener, int for (uint32_t i = 0; i < len; ++i) { const TCP_con *conn = tcp_connections_connection_at(nc_get_tcp_c(m->net_crypto), i); - if (!ev_is_active(&conn->connection->sock_listener.listener) - && !ev_is_pending(&conn->connection->sock_listener.listener)) { - conn->connection->sock_listener.dispatcher = dispatcher; - ev_io_init(&conn->connection->sock_listener.listener, tox_do_iterate, tcp_con_sock(conn->connection), EV_READ); - conn->connection->sock_listener.listener.data = sock_listener->data; - ev_io_start(m->dispatcher, &conn->connection->sock_listener.listener); + if (!tcp_con_ev_is_active(conn->connection)) { + tcp_con_ev_listen(conn->connection, dispatcher, tox_do_iterate, tmp); } } - if (m->loop_end_callback) { - m->loop_end_callback(m, tmp->user_data); + if (tox->loop_end_callback) { + tox->loop_end_callback(tox, tmp->user_data); } } #else From d8ad78bdd9eed2fc4f97758ba42525095a044b5e Mon Sep 17 00:00:00 2001 From: "Restyled.io" Date: Wed, 29 Dec 2021 12:31:45 +0000 Subject: [PATCH 3/3] Restyled by astyle --- toxcore/TCP_client.c | 11 +++++++---- toxcore/TCP_client.h | 3 ++- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/toxcore/TCP_client.c b/toxcore/TCP_client.c index ec0fd487c0..60fe3fa7cc 100644 --- a/toxcore/TCP_client.c +++ b/toxcore/TCP_client.c @@ -104,12 +104,14 @@ TCP_Client_Status tcp_con_status(const TCP_Client_Connection *con) } #ifdef HAVE_LIBEV -bool tcp_con_ev_is_active(TCP_Client_Connection *con) { +bool tcp_con_ev_is_active(TCP_Client_Connection *con) +{ return ev_is_active(&con->sock_listener.listener) - || ev_is_pending(&con->sock_listener.listener); + || ev_is_pending(&con->sock_listener.listener); } -void tcp_con_ev_listen(TCP_Client_Connection *con, struct ev_loop *dispatcher, tcp_con_ev_listen_cb *callback, void *data) +void tcp_con_ev_listen(TCP_Client_Connection *con, struct ev_loop *dispatcher, tcp_con_ev_listen_cb *callback, + void *data) { con->sock_listener.dispatcher = dispatcher; con->sock_listener.listener.data = data; @@ -119,7 +121,8 @@ void tcp_con_ev_listen(TCP_Client_Connection *con, struct ev_loop *dispatcher, t } #endif -void tcp_con_ev_stop(TCP_Client_Connection *con) { +void tcp_con_ev_stop(TCP_Client_Connection *con) +{ #ifdef HAVE_LIBEV ev_io_stop(con->sock_listener.dispatcher, &con->sock_listener.listener); #endif diff --git a/toxcore/TCP_client.h b/toxcore/TCP_client.h index f36bd4728b..73a213388e 100644 --- a/toxcore/TCP_client.h +++ b/toxcore/TCP_client.h @@ -51,7 +51,8 @@ TCP_Client_Status tcp_con_status(const TCP_Client_Connection *con); bool tcp_con_ev_is_active(TCP_Client_Connection *con); typedef void tcp_con_ev_listen_cb(struct ev_loop *dispatcher, ev_io *sock_listener, int events); -void tcp_con_ev_listen(TCP_Client_Connection *con, struct ev_loop *dispatcher, tcp_con_ev_listen_cb *callback, void *data); +void tcp_con_ev_listen(TCP_Client_Connection *con, struct ev_loop *dispatcher, tcp_con_ev_listen_cb *callback, + void *data); #endif void tcp_con_ev_stop(TCP_Client_Connection *con);