commit 11ddb1aacdf44d8517480a030db425181952b777
parent 9e1d2b5522bfb88474570ffebd6546f2d4bf445f
Author: FRIGN <dev@frign.de>
Date: Tue, 14 Oct 2014 18:48:22 +0200
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.
Diffstat:
M | ratox.c | | | 39 | ++++++++++++++++++++++++++++++++++++--- |
1 file changed, 36 insertions(+), 3 deletions(-)
diff --git 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];