tRework file-transfers - ratox - FIFO based tox client
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) README
 (DIR) LICENSE
       ---
 (DIR) commit 9ec6ecb6fc5ef2551b705aa01c01dbe880696881
 (DIR) parent 184804c60c2112538fa3adbe8e4d06c1bdcb29e7
 (HTM) Author: sin <sin@2f30.org>
       Date:   Thu, 18 Sep 2014 10:45:55 +0100
       
       Rework file-transfers
       
       For aborted transfers, we will have to move the transfer to the
       TRANSFER_KILLED state.  Then we'll have to wait until the input
       FIFO stops being readable (the user ^C the transfer).  Only then can
       we move to TRANSFER_NONE.
       
       If we move to TRANSFER_NONE immediately then we will initiate a
       new transfer which we don't want to do.
       
       The basic idea is:
       
       If we move into the TRANSFER_KILLED state and timeout has expired (50ms?)
       without the fd being readable (the user did a ^C on cat file > file_in)
       tthen move the transfer to TRANSFER_NONE state.
       
       Diffstat:
         M ratox.c                             |      81 +++++++++++++++++++++----------
       
       1 file changed, 55 insertions(+), 26 deletions(-)
       ---
 (DIR) diff --git a/ratox.c b/ratox.c
       t@@ -108,6 +108,7 @@ struct transfer {
                ssize_t n;
                int pending;
                int state;
       +        time_t lastsent;
        };
        
        struct friend {
       t@@ -146,6 +147,7 @@ static void cbnamechange(Tox *, int32_t, const uint8_t *, uint16_t, void *);
        static void cbstatusmessage(Tox *, int32_t, const uint8_t *, uint16_t, void *);
        static void cbuserstatus(Tox *, int32_t, uint8_t, void *);
        static void cbfilecontrol(Tox *, int32_t, uint8_t, uint8_t, uint8_t, const uint8_t *, uint16_t, void *);
       +static void completefile(struct friend *);
        static void sendfriendfile(struct friend *);
        static void dataload(void);
        static void datasave(void);
       t@@ -422,6 +424,7 @@ cbfilecontrol(Tox *m, int32_t fid, uint8_t rec_sen, uint8_t fnum, uint8_t ctrlty
                                        f->t.n = 0;
                                        f->t.pending = 0;
                                        f->t.state = TRANSFER_INPROGRESS;
       +                                f->t.lastsent = time(NULL);
                                        break;
                                }
                        }
       t@@ -443,6 +446,13 @@ cbfilecontrol(Tox *m, int32_t fid, uint8_t rec_sen, uint8_t fnum, uint8_t ctrlty
        }
        
        static void
       +completefile(struct friend *f)
       +{
       +        tox_file_send_control(tox, f->fid, 0, f->t.fnum,
       +                              TOX_FILECONTROL_FINISHED, NULL, 0);
       +}
       +
       +static void
        sendfriendfile(struct friend *f)
        {
                ssize_t n;
       t@@ -454,6 +464,7 @@ sendfriendfile(struct friend *f)
                                        /* bad luck - we will try again later */
                                        break;
                                }
       +                        f->t.lastsent = time(NULL);
                                f->t.pending = 0;
                        }
                        /* grab another buffer from the FIFO */
       t@@ -467,13 +478,6 @@ sendfriendfile(struct friend *f)
                                perror("read");
                                exit(EXIT_FAILURE);
                        }
       -                /* we are done */
       -                if (n == 0) {
       -                        tox_file_send_control(tox, f->fid, 0, f->t.fnum,
       -                                              TOX_FILECONTROL_FINISHED, NULL, 0);
       -                        f->t.state = TRANSFER_DONE;
       -                        break;
       -                }
                        /* store transfer size in case we can't send it right now */
                        f->t.n = n;
                        if (tox_file_send_data(tox, f->fid, f->t.fnum, f->t.buf, f->t.n) == -1) {
       t@@ -481,6 +485,7 @@ sendfriendfile(struct friend *f)
                                f->t.pending = 1;
                                return;
                        }
       +                f->t.lastsent = time(NULL);
                }
        }
        
       t@@ -1029,7 +1034,7 @@ static void
        loop(void)
        {
                struct friend *f;
       -        time_t t0, t1;
       +        time_t t0, t1, now;
                int connected = 0;
                int i, n;
                int fdmax;
       t@@ -1069,11 +1074,20 @@ loop(void)
                        TAILQ_FOREACH(f, &friendhead, entry) {
                                /* Only monitor friends that are online */
                                if (tox_get_friend_connection_status(tox, f->fid) == 1) {
       -                                for (i = 0; i < NR_FFIFOS; i++) {
       -                                        FD_SET(f->fd[i], &rfds);
       -                                        if (f->fd[i] > fdmax)
       -                                                fdmax = f->fd[i];
       -                                }
       +                                FD_SET(f->fd[TEXT_IN_FIFO], &rfds);
       +                                if (f->fd[TEXT_IN_FIFO] > fdmax)
       +                                        fdmax = f->fd[TEXT_IN_FIFO];
       +                                /* If the transfer has just been initiated
       +                                 * wait until we have a state change before we start
       +                                 * polling.  Avoids spinning endlessly while waiting
       +                                 * for the transfer to be accepted by the other
       +                                 * party.
       +                                 */
       +                                if (f->t.state == TRANSFER_INITIATED)
       +                                        continue;
       +                                FD_SET(f->fd[FILE_IN_FIFO], &rfds);
       +                                if (f->fd[FILE_IN_FIFO] > fdmax)
       +                                        fdmax = f->fd[FILE_IN_FIFO];
                                }
                        }
        
       t@@ -1096,6 +1110,7 @@ loop(void)
                                                printout("Stale transfer detected, friend offline\n");
                                                f->t.state = TRANSFER_NONE;
                                                free(f->t.buf);
       +                                        f->t.buf = NULL;
                                        }
                                }
                        }
       t@@ -1111,18 +1126,37 @@ loop(void)
                        TAILQ_FOREACH(f, &friendhead, entry) {
                                if (tox_get_friend_connection_status(tox, f->fid) == 0)
                                        continue;
       -                        if (f->t.state == TRANSFER_NONE)
       +                        if (f->t.state != TRANSFER_INPROGRESS)
                                        continue;
       -                        if (f->t.pending == 0)
       +                        if (f->t.pending == 1)
       +                                sendfriendfile(f);
       +                }
       +
       +                /* Check for completed file transfers */
       +                now = time(NULL);
       +                TAILQ_FOREACH(f, &friendhead, entry) {
       +                        if (tox_get_friend_connection_status(tox, f->fid) == 0)
                                        continue;
                                switch (f->t.state) {
       +                        case TRANSFER_NONE:
       +                        case TRANSFER_INITIATED:
       +                                break;
                                case TRANSFER_INPROGRESS:
       -                                sendfriendfile(f);
       -                                if (f->t.state == TRANSFER_DONE) {
       -                                        printout("Transfer complete\n");
       -                                        f->t.state = TRANSFER_NONE;
       -                                        free(f->t.buf);
       -                                }
       +                                /* We use a 1 second grace period, if no reads
       +                                 * happen during that period we consider the transfer
       +                                 * to have completed and signal the end of transmission
       +                                 * control packet.  If we knew the size of the file
       +                                 * it would have been easier to do this but since we are
       +                                 * reading from a FIFO this is not really a possibility.
       +                                 */
       +                                if (now > f->t.lastsent + 1)
       +                                        completefile(f);
       +                                break;
       +                        case TRANSFER_DONE:
       +                                printout("Transfer complete\n");
       +                                f->t.state = TRANSFER_NONE;
       +                                free(f->t.buf);
       +                                f->t.buf = NULL;
                                        break;
                                }
                        }
       t@@ -1159,11 +1193,6 @@ loop(void)
                                                        break;
                                                case TRANSFER_INPROGRESS:
                                                        sendfriendfile(f);
       -                                                if (f->t.state == TRANSFER_DONE) {
       -                                                        printout("Transfer complete\n");
       -                                                        f->t.state = TRANSFER_NONE;
       -                                                        free(f->t.buf);
       -                                                }
                                                        break;
                                                }
                                                break;