From c546df3917a8304f3fb2265c205e8fa227fd5f63 Mon Sep 17 00:00:00 2001 From: Jfreegman Date: Tue, 18 Aug 2015 15:12:48 -0400 Subject: [PATCH] Fix some filetransfer issues - File transfers now timeout properly - Small refactor related to creating new transfers --- src/avatars.c | 8 +--- src/chat.c | 27 ++++++------- src/chat_commands.c | 9 +---- src/file_transfers.c | 93 +++++++++++++++++++++++++++++++++++++++----- src/file_transfers.h | 27 ++++++------- src/toxic.c | 1 + 6 files changed, 116 insertions(+), 49 deletions(-) diff --git a/src/avatars.c b/src/avatars.c index a17c3be..d58b27e 100644 --- a/src/avatars.c +++ b/src/avatars.c @@ -63,7 +63,7 @@ int avatar_send(Tox *m, uint32_t friendnum) return -1; } - struct FileTransfer *ft = get_new_file_sender(friendnum); + struct FileTransfer *ft = new_file_transfer(NULL, friendnum, filenum, FILE_TRANSFER_SEND, TOX_FILE_KIND_AVATAR); if (!ft) return -1; @@ -75,11 +75,6 @@ int avatar_send(Tox *m, uint32_t friendnum) snprintf(ft->file_name, sizeof(ft->file_name), "%s", Avatar.name); ft->file_size = Avatar.size; - ft->state = FILE_TRANSFER_PENDING; - ft->filenum = filenum; - ft->friendnum = friendnum; - ft->direction = FILE_TRANSFER_SEND; - ft->file_type = TOX_FILE_KIND_AVATAR; return 0; } @@ -206,4 +201,5 @@ void on_avatar_chunk_request(Tox *m, struct FileTransfer *ft, uint64_t position, fprintf(stderr, "tox_file_send_chunk failed in avatar callback (error %d)\n", err); ft->position += send_length; + ft->last_keep_alive = get_unix_time(); } diff --git a/src/chat.c b/src/chat.c index 880f5bd..659b6eb 100644 --- a/src/chat.c +++ b/src/chat.c @@ -373,6 +373,7 @@ static void chat_onFileChunkRequest(ToxWindow *self, Tox *m, uint32_t friendnum, ft->position += send_length; ft->bps += send_length; + ft->last_keep_alive = get_unix_time(); } static void chat_onFileRecvChunk(ToxWindow *self, Tox *m, uint32_t friendnum, uint32_t filenum, uint64_t position, @@ -412,6 +413,7 @@ static void chat_onFileRecvChunk(ToxWindow *self, Tox *m, uint32_t friendnum, ui ft->bps += length; ft->position += length; + ft->last_keep_alive = get_unix_time(); } static void chat_onFileControl(ToxWindow *self, Tox *m, uint32_t friendnum, uint32_t filenum, TOX_FILE_CONTROL control) @@ -427,14 +429,16 @@ static void chat_onFileControl(ToxWindow *self, Tox *m, uint32_t friendnum, uint char msg[MAX_STR_SIZE]; switch (control) { - case TOX_FILE_CONTROL_RESUME: + case TOX_FILE_CONTROL_RESUME: { + ft->last_keep_alive = get_unix_time(); + /* transfer is accepted */ if (ft->state == FILE_TRANSFER_PENDING) { ft->state = FILE_TRANSFER_STARTED; line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File transfer [%d] for '%s' accepted.", ft->index, ft->file_name); char progline[MAX_STR_SIZE]; - prep_prog_line(progline); + init_progress_bar(progline); line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "%s", progline); sound_notify(self, silent, NT_NOFOCUS | NT_BEEP | NT_WNDALERT_2, NULL); ft->line_id = self->chatwin->hst->line_end->id + 2; @@ -443,15 +447,16 @@ static void chat_onFileControl(ToxWindow *self, Tox *m, uint32_t friendnum, uint } break; - - case TOX_FILE_CONTROL_PAUSE: + } + case TOX_FILE_CONTROL_PAUSE: { ft->state = FILE_TRANSFER_PAUSED; break; - - case TOX_FILE_CONTROL_CANCEL: + } + case TOX_FILE_CONTROL_CANCEL: { snprintf(msg, sizeof(msg), "File transfer for '%s' was aborted.", ft->file_name); close_file_transfer(self, m, ft, -1, msg, notif_error); break; + } } } @@ -479,6 +484,8 @@ static bool chat_resume_broken_ft(ToxWindow *self, Tox *m, uint32_t friendnum, u if (memcmp(ft->file_id, file_id, TOX_FILE_ID_LENGTH) == 0) { ft->filenum = filenum; + ft->state = FILE_TRANSFER_STARTED; + ft->last_keep_alive = get_unix_time(); resuming = true; break; } @@ -493,7 +500,6 @@ static bool chat_resume_broken_ft(ToxWindow *self, Tox *m, uint32_t friendnum, u if (!tox_file_control(m, ft->friendnum, ft->filenum, TOX_FILE_CONTROL_RESUME, NULL)) goto on_error; - ft->state = FILE_TRANSFER_STARTED; return true; on_error: @@ -512,7 +518,7 @@ static void chat_onFileRecv(ToxWindow *self, Tox *m, uint32_t friendnum, uint32_ if (chat_resume_broken_ft(self, m, friendnum, filenum)) return; - struct FileTransfer *ft = get_new_file_receiver(friendnum); + struct FileTransfer *ft = new_file_transfer(self, friendnum, filenum, FILE_TRANSFER_RECV, TOX_FILE_KIND_DATA); if (!ft) { tox_file_control(m, friendnum, filenum, TOX_FILE_CONTROL_CANCEL, NULL); @@ -570,12 +576,7 @@ static void chat_onFileRecv(ToxWindow *self, Tox *m, uint32_t friendnum, uint32_ line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Type '/savefile %d' to accept the file transfer.", ft->index); - ft->state = FILE_TRANSFER_PENDING; - ft->direction = FILE_TRANSFER_RECV; ft->file_size = file_size; - ft->friendnum = friendnum; - ft->filenum = filenum; - ft->file_type = TOX_FILE_KIND_DATA; snprintf(ft->file_path, sizeof(ft->file_path), "%s", file_path); snprintf(ft->file_name, sizeof(ft->file_name), "%s", filename); tox_file_get_file_id(m, friendnum, filenum, ft->file_id, NULL); diff --git a/src/chat_commands.c b/src/chat_commands.c index d5c5c5a..5201987 100644 --- a/src/chat_commands.c +++ b/src/chat_commands.c @@ -181,7 +181,7 @@ void cmd_savefile(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv /* prep progress bar line */ char progline[MAX_STR_SIZE]; - prep_prog_line(progline); + init_progress_bar(progline); line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "%s", progline); ft->line_id = self->chatwin->hst->line_end->id + 2; @@ -263,7 +263,7 @@ void cmd_sendfile(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv if (err != TOX_ERR_FILE_SEND_OK) goto on_send_error; - struct FileTransfer *ft = get_new_file_sender(self->num); + struct FileTransfer *ft = new_file_transfer(self, self->num, filenum, FILE_TRANSFER_SEND, TOX_FILE_KIND_DATA); if (!ft) { err = TOX_ERR_FILE_SEND_TOO_MANY; @@ -271,13 +271,8 @@ void cmd_sendfile(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv } memcpy(ft->file_name, file_name, namelen + 1); - ft->state = FILE_TRANSFER_PENDING; ft->file = file_to_send; ft->file_size = filesize; - ft->filenum = filenum; - ft->friendnum = self->num; - ft->direction = FILE_TRANSFER_SEND; - ft->file_type = TOX_FILE_KIND_DATA; tox_file_get_file_id(m, self->num, filenum, ft->file_id, NULL); char sizestr[32]; diff --git a/src/file_transfers.c b/src/file_transfers.c index 3b1db20..7cd915f 100644 --- a/src/file_transfers.c +++ b/src/file_transfers.c @@ -35,11 +35,52 @@ extern FriendsList Friends; -#define NUM_PROG_MARKS 50 /* number of "#"'s in file transfer progress bar. Keep well below MAX_STR_SIZE */ +/* number of "#"'s in file transfer progress bar. Keep well below MAX_STR_SIZE */ +#define NUM_PROG_MARKS 50 + +/* Checks for timed out file transfers and closes them. */ +#define CHECK_FILE_TIMEOUT_INTERAVAL 5 +void check_file_transfer_timeouts(Tox *m) +{ + char msg[MAX_STR_SIZE]; + static uint64_t last_check = 0; + + if (!timed_out(last_check, CHECK_FILE_TIMEOUT_INTERAVAL)) + return; + + last_check = get_unix_time(); + + size_t i, j; + + for (i = 0; i < Friends.max_idx; ++i) { + if (!Friends.list[i].active) + continue; + + for (j = 0; j < MAX_FILES; ++j) { + struct FileTransfer *ft_send = &Friends.list[i].file_sender[j]; + + if (ft_send->state > FILE_TRANSFER_PAUSED) { + if (timed_out(ft_send->last_keep_alive, TIMEOUT_FILESENDER)) { + snprintf(msg, sizeof(msg), "File transfer for '%s' timed out.", ft_send->file_name); + close_file_transfer(ft_send->window, m, ft_send, TOX_FILE_CONTROL_CANCEL, msg, notif_error); + } + } + + struct FileTransfer *ft_recv = &Friends.list[i].file_receiver[j]; + + if (ft_recv->state > FILE_TRANSFER_PAUSED) { + if (timed_out(ft_recv->last_keep_alive, TIMEOUT_FILESENDER)) { + snprintf(msg, sizeof(msg), "File transfer for '%s' timed out.", ft_recv->file_name); + close_file_transfer(ft_recv->window, m, ft_recv, TOX_FILE_CONTROL_CANCEL, msg, notif_error); + } + } + } + } +} /* creates initial progress line that will be updated during file transfer. Assumes progline is of size MAX_STR_SIZE */ -void prep_prog_line(char *progline) +void init_progress_bar(char *progline) { strcpy(progline, "0.0 B/s ["); int i; @@ -80,13 +121,13 @@ void print_progress_bar(ToxWindow *self, double bps, double pct_done, uint32_t l line_info_set(self, line_id, msg); } -static void refresh_progress_helper(ToxWindow *self, struct FileTransfer *ft) +static void refresh_progress_helper(ToxWindow *self, Tox *m, struct FileTransfer *ft) { if (ft->state == FILE_TRANSFER_INACTIVE) return; /* Timeout must be set to 1 second to show correct bytes per second */ - if (!timed_out(ft->last_progress, 1)) + if (!timed_out(ft->last_line_progress, 1)) return; double remain = ft->file_size - ft->position; @@ -94,17 +135,17 @@ static void refresh_progress_helper(ToxWindow *self, struct FileTransfer *ft) print_progress_bar(self, ft->bps, pct_done, ft->line_id); ft->bps = 0; - ft->last_progress = get_unix_time(); + ft->last_line_progress = get_unix_time(); } -/* refreshes active file receiver status bars for friendnum */ +/* refreshes active file transfer status bars. */ void refresh_file_transfer_progress(ToxWindow *self, Tox *m, uint32_t friendnum) { size_t i; for (i = 0; i < MAX_FILES; ++i) { - refresh_progress_helper(self, &Friends.list[friendnum].file_receiver[i]); - refresh_progress_helper(self, &Friends.list[friendnum].file_sender[i]); + refresh_progress_helper(self, m, &Friends.list[friendnum].file_receiver[i]); + refresh_progress_helper(self, m, &Friends.list[friendnum].file_sender[i]); } } @@ -156,7 +197,7 @@ struct FileTransfer *get_file_transfer_struct_index(uint32_t friendnum, uint32_t /* Returns a pointer to an unused file sender. * Returns NULL if all file senders are in use. */ -struct FileTransfer *get_new_file_sender(uint32_t friendnum) +static struct FileTransfer *new_file_sender(ToxWindow *window, uint32_t friendnum, uint32_t filenum, uint8_t type) { size_t i; @@ -164,7 +205,15 @@ struct FileTransfer *get_new_file_sender(uint32_t friendnum) struct FileTransfer *ft = &Friends.list[friendnum].file_sender[i]; if (ft->state == FILE_TRANSFER_INACTIVE) { + memset(ft, 0, sizeof(struct FileTransfer)); + ft->window = window; ft->index = i; + ft->friendnum = friendnum; + ft->filenum = filenum; + ft->file_type = type; + ft->last_keep_alive = get_unix_time(); + ft->state = FILE_TRANSFER_PENDING; + ft->direction = FILE_TRANSFER_SEND; return ft; } } @@ -175,7 +224,7 @@ struct FileTransfer *get_new_file_sender(uint32_t friendnum) /* Returns a pointer to an unused file receiver. * Returns NULL if all file receivers are in use. */ -struct FileTransfer *get_new_file_receiver(uint32_t friendnum) +static struct FileTransfer *new_file_receiver(ToxWindow *window, uint32_t friendnum, uint32_t filenum, uint8_t type) { size_t i; @@ -183,7 +232,15 @@ struct FileTransfer *get_new_file_receiver(uint32_t friendnum) struct FileTransfer *ft = &Friends.list[friendnum].file_receiver[i]; if (ft->state == FILE_TRANSFER_INACTIVE) { + memset(ft, 0, sizeof(struct FileTransfer)); + ft->window = window; ft->index = i; + ft->friendnum = friendnum; + ft->filenum = filenum; + ft->file_type = type; + ft->last_keep_alive = get_unix_time(); + ft->state = FILE_TRANSFER_PENDING; + ft->direction = FILE_TRANSFER_RECV; return ft; } } @@ -191,6 +248,22 @@ struct FileTransfer *get_new_file_receiver(uint32_t friendnum) return NULL; } +/* Initializes an unused file transfer and returns its pointer. + * Returns NULL on failure. + */ +struct FileTransfer *new_file_transfer(ToxWindow *window, uint32_t friendnum, uint32_t filenum, + FILE_TRANSFER_DIRECTION direction, uint8_t type) +{ + if (direction == FILE_TRANSFER_RECV) + return new_file_receiver(window, friendnum, filenum, type); + + if (direction == FILE_TRANSFER_SEND) + return new_file_sender(window, friendnum, filenum, type); + + return NULL; +} + + /* Closes file transfer ft. * * Set CTRL to -1 if we don't want to send a control signal. diff --git a/src/file_transfers.h b/src/file_transfers.h index 39b2c30..f5181a6 100644 --- a/src/file_transfers.h +++ b/src/file_transfers.h @@ -38,9 +38,9 @@ typedef enum FILE_TRANSFER_STATE { FILE_TRANSFER_INACTIVE, + FILE_TRANSFER_PAUSED, FILE_TRANSFER_PENDING, FILE_TRANSFER_STARTED, - FILE_TRANSFER_PAUSED, } FILE_TRANSFER_STATE; typedef enum FILE_TRANSFER_DIRECTION { @@ -49,31 +49,36 @@ typedef enum FILE_TRANSFER_DIRECTION { } FILE_TRANSFER_DIRECTION; struct FileTransfer { + ToxWindow *window; FILE *file; FILE_TRANSFER_STATE state; FILE_TRANSFER_DIRECTION direction; uint8_t file_type; char file_name[TOX_MAX_FILENAME_LENGTH + 1]; char file_path[PATH_MAX + 1]; /* Not used by senders */ - double bps; + double bps; uint32_t filenum; uint32_t friendnum; size_t index; uint64_t file_size; uint64_t position; - uint64_t last_progress; + uint64_t last_line_progress; /* The last time we updated the progress bar */ + uint64_t last_keep_alive; /* The last time we sent or received data */ uint32_t line_id; uint8_t file_id[TOX_FILE_ID_LENGTH]; }; +/* Checks for timed out file transfers and closes them. */ +void check_file_transfer_timeouts(Tox *m); + /* creates initial progress line that will be updated during file transfer. progline must be at lesat MAX_STR_SIZE bytes */ -void prep_prog_line(char *progline); +void init_progress_bar(char *progline); /* prints a progress bar for file transfers */ void print_progress_bar(ToxWindow *self, double pct_done, double bps, uint32_t line_id); -/* refreshes active file transfer status bars for friendnum */ +/* refreshes active file transfer status bars. */ void refresh_file_transfer_progress(ToxWindow *self, Tox *m, uint32_t friendnum); /* Returns a pointer to friendnum's FileTransfer struct associated with filenum. @@ -88,15 +93,11 @@ struct FileTransfer *get_file_transfer_struct(uint32_t friendnum, uint32_t filen struct FileTransfer *get_file_transfer_struct_index(uint32_t friendnum, uint32_t index, FILE_TRANSFER_DIRECTION direction); -/* Returns a pointer to an unused file sender. - * Returns NULL if all file senders are in use. +/* Initializes an unused file transfer and returns its pointer. + * Returns NULL on failure. */ -struct FileTransfer *get_new_file_sender(uint32_t friendnum); - -/* Returns a pointer to an unused file receiver. - * Returns NULL if all file receivers are in use. - */ -struct FileTransfer *get_new_file_receiver(uint32_t friendnum); +struct FileTransfer *new_file_transfer(ToxWindow *window, uint32_t friendnum, uint32_t filenum, + FILE_TRANSFER_DIRECTION direction, uint8_t type); /* Closes file transfer ft. * diff --git a/src/toxic.c b/src/toxic.c index 9bea636..04c4ff2 100644 --- a/src/toxic.c +++ b/src/toxic.c @@ -788,6 +788,7 @@ static void do_toxic(Tox *m, ToxWindow *prompt) pthread_mutex_lock(&Winthread.lock); tox_iterate(m); do_bootstrap(m); + check_file_transfer_timeouts(m); pthread_mutex_unlock(&Winthread.lock); }