1
0
mirror of https://github.com/Tha14/toxic.git synced 2024-11-23 02:23:02 +01:00

Fix some filetransfer issues

- File transfers now timeout properly
- Small refactor related to creating new transfers
This commit is contained in:
Jfreegman 2015-08-18 15:12:48 -04:00
parent 327259c4c8
commit 2a787c1097
No known key found for this signature in database
GPG Key ID: 3627F3144076AE63
6 changed files with 116 additions and 49 deletions

View File

@ -63,7 +63,7 @@ int avatar_send(Tox *m, uint32_t friendnum)
return -1; 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) if (!ft)
return -1; 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); snprintf(ft->file_name, sizeof(ft->file_name), "%s", Avatar.name);
ft->file_size = Avatar.size; 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; 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); fprintf(stderr, "tox_file_send_chunk failed in avatar callback (error %d)\n", err);
ft->position += send_length; ft->position += send_length;
ft->last_keep_alive = get_unix_time();
} }

View File

@ -373,6 +373,7 @@ static void chat_onFileChunkRequest(ToxWindow *self, Tox *m, uint32_t friendnum,
ft->position += send_length; ft->position += send_length;
ft->bps += 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, 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->bps += length;
ft->position += 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) 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]; char msg[MAX_STR_SIZE];
switch (control) { switch (control) {
case TOX_FILE_CONTROL_RESUME: case TOX_FILE_CONTROL_RESUME: {
ft->last_keep_alive = get_unix_time();
/* transfer is accepted */ /* transfer is accepted */
if (ft->state == FILE_TRANSFER_PENDING) { if (ft->state == FILE_TRANSFER_PENDING) {
ft->state = FILE_TRANSFER_STARTED; ft->state = FILE_TRANSFER_STARTED;
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File transfer [%d] for '%s' accepted.", line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File transfer [%d] for '%s' accepted.",
ft->index, ft->file_name); ft->index, ft->file_name);
char progline[MAX_STR_SIZE]; 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); 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); sound_notify(self, silent, NT_NOFOCUS | NT_BEEP | NT_WNDALERT_2, NULL);
ft->line_id = self->chatwin->hst->line_end->id + 2; ft->line_id = self->chatwin->hst->line_end->id + 2;
@ -443,16 +447,17 @@ static void chat_onFileControl(ToxWindow *self, Tox *m, uint32_t friendnum, uint
} }
break; break;
}
case TOX_FILE_CONTROL_PAUSE: case TOX_FILE_CONTROL_PAUSE: {
ft->state = FILE_TRANSFER_PAUSED; ft->state = FILE_TRANSFER_PAUSED;
break; break;
}
case TOX_FILE_CONTROL_CANCEL: case TOX_FILE_CONTROL_CANCEL: {
snprintf(msg, sizeof(msg), "File transfer for '%s' was aborted.", ft->file_name); snprintf(msg, sizeof(msg), "File transfer for '%s' was aborted.", ft->file_name);
close_file_transfer(self, m, ft, -1, msg, notif_error); close_file_transfer(self, m, ft, -1, msg, notif_error);
break; break;
} }
}
} }
/* Attempts to resume a broken inbound file transfer. /* Attempts to resume a broken inbound file transfer.
@ -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) { if (memcmp(ft->file_id, file_id, TOX_FILE_ID_LENGTH) == 0) {
ft->filenum = filenum; ft->filenum = filenum;
ft->state = FILE_TRANSFER_STARTED;
ft->last_keep_alive = get_unix_time();
resuming = true; resuming = true;
break; 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)) if (!tox_file_control(m, ft->friendnum, ft->filenum, TOX_FILE_CONTROL_RESUME, NULL))
goto on_error; goto on_error;
ft->state = FILE_TRANSFER_STARTED;
return true; return true;
on_error: 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)) if (chat_resume_broken_ft(self, m, friendnum, filenum))
return; 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) { if (!ft) {
tox_file_control(m, friendnum, filenum, TOX_FILE_CONTROL_CANCEL, NULL); 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); 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->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_path, sizeof(ft->file_path), "%s", file_path);
snprintf(ft->file_name, sizeof(ft->file_name), "%s", filename); snprintf(ft->file_name, sizeof(ft->file_name), "%s", filename);
tox_file_get_file_id(m, friendnum, filenum, ft->file_id, NULL); tox_file_get_file_id(m, friendnum, filenum, ft->file_id, NULL);

View File

@ -181,7 +181,7 @@ void cmd_savefile(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv
/* prep progress bar line */ /* prep progress bar line */
char progline[MAX_STR_SIZE]; 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); line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "%s", progline);
ft->line_id = self->chatwin->hst->line_end->id + 2; 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) if (err != TOX_ERR_FILE_SEND_OK)
goto on_send_error; 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) { if (!ft) {
err = TOX_ERR_FILE_SEND_TOO_MANY; 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); memcpy(ft->file_name, file_name, namelen + 1);
ft->state = FILE_TRANSFER_PENDING;
ft->file = file_to_send; ft->file = file_to_send;
ft->file_size = filesize; 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); tox_file_get_file_id(m, self->num, filenum, ft->file_id, NULL);
char sizestr[32]; char sizestr[32];

View File

@ -35,11 +35,52 @@
extern FriendsList Friends; 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. /* creates initial progress line that will be updated during file transfer.
Assumes progline is of size MAX_STR_SIZE */ 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 ["); strcpy(progline, "0.0 B/s [");
int i; 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); 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) if (ft->state == FILE_TRANSFER_INACTIVE)
return; return;
/* Timeout must be set to 1 second to show correct bytes per second */ /* 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; return;
double remain = ft->file_size - ft->position; 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); print_progress_bar(self, ft->bps, pct_done, ft->line_id);
ft->bps = 0; 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) void refresh_file_transfer_progress(ToxWindow *self, Tox *m, uint32_t friendnum)
{ {
size_t i; size_t i;
for (i = 0; i < MAX_FILES; ++i) { for (i = 0; i < MAX_FILES; ++i) {
refresh_progress_helper(self, &Friends.list[friendnum].file_receiver[i]); refresh_progress_helper(self, m, &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_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 a pointer to an unused file sender.
* Returns NULL if all file senders are in use. * 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; 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]; struct FileTransfer *ft = &Friends.list[friendnum].file_sender[i];
if (ft->state == FILE_TRANSFER_INACTIVE) { if (ft->state == FILE_TRANSFER_INACTIVE) {
memset(ft, 0, sizeof(struct FileTransfer));
ft->window = window;
ft->index = i; 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; return ft;
} }
} }
@ -175,7 +224,7 @@ struct FileTransfer *get_new_file_sender(uint32_t friendnum)
/* Returns a pointer to an unused file receiver. /* Returns a pointer to an unused file receiver.
* Returns NULL if all file receivers are in use. * 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; 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]; struct FileTransfer *ft = &Friends.list[friendnum].file_receiver[i];
if (ft->state == FILE_TRANSFER_INACTIVE) { if (ft->state == FILE_TRANSFER_INACTIVE) {
memset(ft, 0, sizeof(struct FileTransfer));
ft->window = window;
ft->index = i; 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; return ft;
} }
} }
@ -191,6 +248,22 @@ struct FileTransfer *get_new_file_receiver(uint32_t friendnum)
return NULL; 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. /* Closes file transfer ft.
* *
* Set CTRL to -1 if we don't want to send a control signal. * Set CTRL to -1 if we don't want to send a control signal.

View File

@ -38,9 +38,9 @@
typedef enum FILE_TRANSFER_STATE { typedef enum FILE_TRANSFER_STATE {
FILE_TRANSFER_INACTIVE, FILE_TRANSFER_INACTIVE,
FILE_TRANSFER_PAUSED,
FILE_TRANSFER_PENDING, FILE_TRANSFER_PENDING,
FILE_TRANSFER_STARTED, FILE_TRANSFER_STARTED,
FILE_TRANSFER_PAUSED,
} FILE_TRANSFER_STATE; } FILE_TRANSFER_STATE;
typedef enum FILE_TRANSFER_DIRECTION { typedef enum FILE_TRANSFER_DIRECTION {
@ -49,6 +49,7 @@ typedef enum FILE_TRANSFER_DIRECTION {
} FILE_TRANSFER_DIRECTION; } FILE_TRANSFER_DIRECTION;
struct FileTransfer { struct FileTransfer {
ToxWindow *window;
FILE *file; FILE *file;
FILE_TRANSFER_STATE state; FILE_TRANSFER_STATE state;
FILE_TRANSFER_DIRECTION direction; FILE_TRANSFER_DIRECTION direction;
@ -61,19 +62,23 @@ struct FileTransfer {
size_t index; size_t index;
uint64_t file_size; uint64_t file_size;
uint64_t position; 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; uint32_t line_id;
uint8_t file_id[TOX_FILE_ID_LENGTH]; 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. /* creates initial progress line that will be updated during file transfer.
progline must be at lesat MAX_STR_SIZE bytes */ 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 */ /* prints a progress bar for file transfers */
void print_progress_bar(ToxWindow *self, double pct_done, double bps, uint32_t line_id); 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); void refresh_file_transfer_progress(ToxWindow *self, Tox *m, uint32_t friendnum);
/* Returns a pointer to friendnum's FileTransfer struct associated with filenum. /* 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, struct FileTransfer *get_file_transfer_struct_index(uint32_t friendnum, uint32_t index,
FILE_TRANSFER_DIRECTION direction); FILE_TRANSFER_DIRECTION direction);
/* Returns a pointer to an unused file sender. /* Initializes an unused file transfer and returns its pointer.
* Returns NULL if all file senders are in use. * Returns NULL on failure.
*/ */
struct FileTransfer *get_new_file_sender(uint32_t friendnum); struct FileTransfer *new_file_transfer(ToxWindow *window, uint32_t friendnum, uint32_t filenum,
FILE_TRANSFER_DIRECTION direction, uint8_t type);
/* 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);
/* Closes file transfer ft. /* Closes file transfer ft.
* *

View File

@ -780,6 +780,7 @@ static void do_toxic(Tox *m, ToxWindow *prompt)
pthread_mutex_lock(&Winthread.lock); pthread_mutex_lock(&Winthread.lock);
tox_iterate(m); tox_iterate(m);
do_bootstrap(m); do_bootstrap(m);
check_file_transfer_timeouts(m);
pthread_mutex_unlock(&Winthread.lock); pthread_mutex_unlock(&Winthread.lock);
} }