diff --git a/toxcore/Messenger.c b/toxcore/Messenger.c index e4387fcb..dfd32d40 100644 --- a/toxcore/Messenger.c +++ b/toxcore/Messenger.c @@ -1394,14 +1394,19 @@ void doMessenger(Messenger *m) */ int waitprepareMessenger(Messenger *m, uint8_t *data, uint16_t *lenptr) { - return networking_wait_prepare(m->net, sendqueue_total(m->net_crypto->lossless_udp), data, lenptr); + return networking_wait_prepare(m->net, sendqueue_total(m->net_crypto->lossless_udp), data, lenptr); } int waitexecuteMessenger(Messenger *m, uint8_t *data, uint16_t len, uint16_t milliseconds) { - return networking_wait_execute(data, len, milliseconds); + return networking_wait_execute(data, len, milliseconds); }; +void waitcleanupMessenger(Messenger *m, uint8_t *data, uint16_t len) +{ + networking_wait_cleanup(m->net, data, len); +} + /* return size of the messenger data (for saving) */ uint32_t Messenger_size_old(Messenger *m) { diff --git a/toxcore/Messenger.h b/toxcore/Messenger.h index 80450b1a..a59cec29 100644 --- a/toxcore/Messenger.h +++ b/toxcore/Messenger.h @@ -460,6 +460,7 @@ void doMessenger(Messenger *m); */ int waitprepareMessenger(Messenger *m, uint8_t *data, uint16_t *lenptr); int waitexecuteMessenger(Messenger *m, uint8_t *data, uint16_t len, uint16_t milliseconds); +void waitcleanupMessenger(Messenger *m, uint8_t *data, uint16_t len); /* SAVING AND LOADING FUNCTIONS: */ diff --git a/toxcore/network.c b/toxcore/network.c index 3e533799..51f064e7 100644 --- a/toxcore/network.c +++ b/toxcore/network.c @@ -209,6 +209,12 @@ int sendpacket(Networking_Core *net, IP_Port ip_port, uint8_t *data, uint32_t le #ifdef LOGGING loglogdata("O=>", data, length, &ip_port, res); #endif + + if (res == length) + net->send_fail_eagain = 0; + else if ((res < 0) && (errno == EAGAIN)) + net->send_fail_eagain = current_time(); + return res; } @@ -308,24 +314,28 @@ void networking_poll(Networking_Core *net) */ typedef struct { - sock_t sock; - uint32_t sendqueue_length; + sock_t sock; + uint32_t sendqueue_length; + uint16_t send_fail_reset; + uint64_t send_fail_eagain; } select_info; int networking_wait_prepare(Networking_Core *net, uint32_t sendqueue_length, uint8_t *data, uint16_t *lenptr) { - if ((data == NULL) || (*lenptr < sizeof(select_info))) - { - *lenptr = sizeof(select_info); - return 0; - } + if ((data == NULL) || (*lenptr < sizeof(select_info))) + { + *lenptr = sizeof(select_info); + return 0; + } - *lenptr = sizeof(select_info); - select_info *s = (select_info *)data; - s->sock = net->sock; - s->sendqueue_length = sendqueue_length; + *lenptr = sizeof(select_info); + select_info *s = (select_info *)data; + s->sock = net->sock; + s->sendqueue_length = sendqueue_length; + s->send_fail_reset = 0; + s->send_fail_eagain = net->send_fail_eagain; - return 1; + return 1; } int networking_wait_execute(uint8_t *data, uint16_t len, uint16_t milliseconds) @@ -333,9 +343,23 @@ int networking_wait_execute(uint8_t *data, uint16_t len, uint16_t milliseconds) /* WIN32: supported since Win2K, but might need some adjustements */ /* UNIX: this should work for any remotely Unix'ish system */ - select_info *s = (select_info *)data; + select_info *s = (select_info *)data; - int nfds = 1 + s->sock; + /* add only if we had a failed write */ + int writefds_add = 0; + if (s->send_fail_eagain != 0) + { + // current_time(): microseconds + uint64_t now = current_time(); + + /* s->sendqueue_length: might be used to guess how long we keep checking */ + /* for now, threshold is hardcoded to 500ms, too long for a really really + * fast link, but too short for a sloooooow link... */ + if (now - s->send_fail_eagain < 500000) + writefds_add = 1; + } + + int nfds = 1 + s->sock; /* the FD_ZERO calls might be superfluous */ fd_set readfds; @@ -344,8 +368,7 @@ int networking_wait_execute(uint8_t *data, uint16_t len, uint16_t milliseconds) fd_set writefds; FD_ZERO(&writefds); - /* add only if we have packets queued, signals that a write won't block */ - if (s->sendqueue_length > 0) + if (writefds_add) FD_SET(s->sock, &writefds); fd_set exceptfds; @@ -368,9 +391,19 @@ int networking_wait_execute(uint8_t *data, uint16_t len, uint16_t milliseconds) loglog(logbuffer); #endif + if (FD_ISSET(s->sock, &writefds)) + s->send_fail_reset = 1; + return res > 0 ? 1 : 0; }; +void networking_wait_cleanup(Networking_Core *net, uint8_t *data, uint16_t len) +{ + select_info *s = (select_info *)data; + if (s->send_fail_reset) + net->send_fail_eagain = 0; +} + uint8_t at_startup_ran = 0; static int at_startup(void) { @@ -996,10 +1029,10 @@ int addr_resolve_or_parse_ip(const char *address, IP *to, IP *extra) static char errmsg_ok[3] = "OK"; static void loglogdata(char *message, uint8_t *buffer, size_t buflen, IP_Port *ip_port, ssize_t res) { - uint16_t port = ntohs(ip_port->port); - uint32_t data[2]; - data[0] = buflen > 4 ? ntohl(*(uint32_t *)&buffer[1]) : 0; - data[1] = buflen > 7 ? ntohl(*(uint32_t *)&buffer[5]) : 0; + uint16_t port = ntohs(ip_port->port); + uint32_t data[2]; + data[0] = buflen > 4 ? ntohl(*(uint32_t *)&buffer[1]) : 0; + data[1] = buflen > 7 ? ntohl(*(uint32_t *)&buffer[5]) : 0; if (res < 0) { int written = snprintf(logbuffer, sizeof(logbuffer), "[%2u] %s %3hu%c %s:%hu (%u: %s) | %04x%04x\n", diff --git a/toxcore/network.h b/toxcore/network.h index 54df7d2e..8a0e20dc 100644 --- a/toxcore/network.h +++ b/toxcore/network.h @@ -244,6 +244,7 @@ typedef struct { sa_family_t family; uint16_t port; sock_t sock; + uint64_t send_fail_eagain; } Networking_Core; /* return current time in milleseconds since the epoch. */ @@ -269,6 +270,7 @@ void networking_poll(Networking_Core *net); */ int networking_wait_prepare(Networking_Core *net, uint32_t sendqueue_length, uint8_t *data, uint16_t *lenptr); int networking_wait_execute(uint8_t *data, uint16_t len, uint16_t milliseconds); +void networking_wait_cleanup(Networking_Core *net, uint8_t *data, uint16_t len); /* Initialize networking. * bind to ip and port. diff --git a/toxcore/tox.c b/toxcore/tox.c index b2107389..5868a8e1 100644 --- a/toxcore/tox.c +++ b/toxcore/tox.c @@ -551,6 +551,12 @@ int tox_wait_execute(Tox *tox, uint8_t *data, uint16_t len, uint16_t millisecond waitexecuteMessenger(m, data, len, milliseconds); } +void tox_wait_cleanup(Tox *tox, uint8_t *data, uint16_t len) +{ + Messenger *m = tox; + waitcleanupMessenger(m, data, len); +} + /* SAVING AND LOADING FUNCTIONS: */ /* return size of the messenger data (for saving). */ diff --git a/toxcore/tox.h b/toxcore/tox.h index 3278a9d3..7b8af15e 100644 --- a/toxcore/tox.h +++ b/toxcore/tox.h @@ -491,6 +491,7 @@ void tox_do(Tox *tox); * returns 1 on success * returns 0 on failure (length is insufficient) * + * * tox_wait_execute(): function can be called asynchronously * Waits for something to happen on the socket for up to milliseconds milliseconds. * *** Function MUSTN'T poll. *** @@ -501,9 +502,17 @@ void tox_do(Tox *tox); * returns 0 if the timeout was reached * returns -1 if data was NULL or len too short * + * + * tox_wait_cleanup(): function should be called under lock + * Stores results from tox_wait_execute(). + * + * data[]/len shall be the exact same as given to tox_wait_execute() + * */ int tox_wait_prepare(Tox *tox, uint8_t *data, uint16_t *lenptr); int tox_wait_execute(Tox *tox, uint8_t *data, uint16_t len, uint16_t milliseconds); +void tox_wait_cleanup(Tox *tox, uint8_t *data, uint16_t len); + /* SAVING AND LOADING FUNCTIONS: */ diff --git a/toxcore/util.h b/toxcore/util.h index 13ab4792..1c1898a0 100644 --- a/toxcore/util.h +++ b/toxcore/util.h @@ -20,6 +20,7 @@ typedef int (*load_state_callback_func)(void *outer, uint8_t *data, uint32_t len int load_state(load_state_callback_func load_state_callback, void *outer, uint8_t *data, uint32_t length, uint16_t cookie_inner); +#define LOGGING #ifdef LOGGING extern char logbuffer[512]; void loginit(uint16_t port);