From 11ddb1aacdf44d8517480a030db425181952b777 Mon Sep 17 00:00:00 2001 From: FRIGN Date: Tue, 14 Oct 2014 18:48:22 +0200 Subject: Fortify and optimize file-sending Do this in two ways: 1) only allow ratox to stay in the file-sender for a certain amount of time 2) Stop hammering tox_file_send_data(). When it returns -1, we put the given friend into a cooldown-state, because all internal transmission slots are full. File sending thus now works in bursts, reading from file_in as long as tox_do() allows or until tox_file_send_data() fails. An easy way to see why we need to do the former is piping /dev/urandom to file_in, which never blocks. Effectively, the user goes "offline" after a while given he is trapped inside the loop. Piping to /dev/urandom is not an unrealistic testcase. Imagine a researcher who desperately needs true random data from his special RNG in his lab using ratox and piping it through /dev/urandom. --- ratox.c | 39 ++++++++++++++++++++++++++++++++++++--- 1 file changed, 36 insertions(+), 3 deletions(-) diff --git a/ratox.c b/ratox.c index 264836c..2829672 100644 --- a/ratox.c +++ b/ratox.c @@ -161,6 +161,8 @@ struct transfer { ssize_t n; int pendingbuf; int state; + struct timespec lastblock; + int cooldown; }; struct call { @@ -777,6 +779,9 @@ cbfilecontrol(Tox *m, int32_t frnum, uint8_t rec_sen, uint8_t fnum, uint8_t ctrl f->tx.state = TRANSFER_NONE; free(f->tx.buf); f->tx.buf = NULL; + f->tx.lastblock.tv_sec = 0; + f->tx.lastblock.tv_nsec = 0; + f->tx.cooldown = 0; fiforeset(f->dirfd, &f->fd[FFILE_IN], ffiles[FFILE_IN]); } else { logmsg(": %s : Rx > Cancelled by Sender\n", f->name); @@ -789,6 +794,9 @@ cbfilecontrol(Tox *m, int32_t frnum, uint8_t rec_sen, uint8_t fnum, uint8_t ctrl f->tx.state = TRANSFER_NONE; free(f->tx.buf); f->tx.buf = NULL; + f->tx.lastblock.tv_sec = 0; + f->tx.lastblock.tv_nsec = 0; + f->tx.cooldown = 0; } else { logmsg(": %s : Rx > Complete\n", f->name); if (tox_file_send_control(tox, f->num, 1, 0, TOX_FILECONTROL_FINISHED, NULL, 0) < 0) @@ -882,6 +890,9 @@ canceltxtransfer(struct friend *f) f->tx.state = TRANSFER_NONE; free(f->tx.buf); f->tx.buf = NULL; + f->tx.lastblock.tv_sec = 0; + f->tx.lastblock.tv_nsec = 0; + f->tx.cooldown = 0; fiforeset(f->dirfd, &f->fd[FFILE_IN], ffiles[FFILE_IN]); } @@ -906,8 +917,11 @@ static void sendfriendfile(struct friend *f) { ssize_t n; + struct timespec start, now, diff = {0, 0}; - while (1) { + clock_gettime(CLOCK_MONOTONIC, &start); + + while (diff.tv_sec == 0 && diff.tv_nsec < tox_do_interval(tox) * 1E6) { /* Attempt to transmit the pending buffer */ if (f->tx.pendingbuf == 1) { if (tox_file_send_data(tox, f->num, f->tx.fnum, f->tx.buf, f->tx.n) == -1) { @@ -927,14 +941,20 @@ sendfriendfile(struct friend *f) f->tx.state = TRANSFER_NONE; break; } - if (n == -1) + if (n == -1) { + printf("fiforead in sendfriendfile failed. fix this. errno = %d\n", errno); break; + } /* Store transfer size in case we can't send it right now */ f->tx.n = n; if (tox_file_send_data(tox, f->num, f->tx.fnum, f->tx.buf, f->tx.n) == -1) { + clock_gettime(CLOCK_MONOTONIC, &f->tx.lastblock); + f->tx.cooldown = 1; f->tx.pendingbuf = 1; return; } + clock_gettime(CLOCK_MONOTONIC, &now); + diff = timediff(start, now); } } @@ -1591,6 +1611,7 @@ loop(void) char c; fd_set rfds; struct timeval tv; + struct timespec curtime, diff; struct file reqfifo; t0 = time(NULL); @@ -1637,13 +1658,25 @@ loop(void) } TAILQ_FOREACH(f, &friendhead, entry) { + /* Check cooldown state of file transfers */ + if (f->tx.cooldown) { + clock_gettime(CLOCK_MONOTONIC, &curtime); + diff = timediff(f->tx.lastblock, curtime); + + if (diff.tv_sec > 0 || diff.tv_nsec > tox_do_interval(tox) * 3 * 1E6) { + f->tx.lastblock.tv_sec = 0; + f->tx.lastblock.tv_nsec = 0; + f->tx.cooldown = 0; + } + } + /* Only monitor friends that are online */ if (tox_get_friend_connection_status(tox, f->num) == 1) { FD_SET(f->fd[FTEXT_IN], &rfds); if (f->fd[FTEXT_IN] > fdmax) fdmax = f->fd[FTEXT_IN]; if (f->tx.state == TRANSFER_NONE || - f->tx.state == TRANSFER_INPROGRESS) { + (f->tx.state == TRANSFER_INPROGRESS && !f->tx.cooldown)) { FD_SET(f->fd[FFILE_IN], &rfds); if (f->fd[FFILE_IN] > fdmax) fdmax = f->fd[FFILE_IN]; -- cgit v1.2.3