mirror of
https://github.com/irungentoo/toxcore.git
synced 2024-03-22 13:30:51 +08:00
Added and implemented file_id parameter to file tranfers.
file_id is a 32byte identifier that can be used by users to identify file tranfers across core/client restarts in order to resume broken file tranfers. In avatar tranfers it corresponds to the hash of the avatar. Added tox_file_get_file_id() function to api to obtain the file_id of an ongoing file transfer. If not set, core will generate a random one.
This commit is contained in:
parent
2757b254fe
commit
24c70c9e84
|
@ -100,6 +100,7 @@ void handle_custom_packet(Tox *m, uint32_t friend_num, const uint8_t *data, size
|
|||
return;
|
||||
}
|
||||
|
||||
uint8_t file_cmp_id[TOX_FILE_ID_LENGTH];
|
||||
uint8_t filenum;
|
||||
uint32_t file_accepted;
|
||||
uint64_t file_size;
|
||||
|
@ -119,6 +120,22 @@ void tox_file_receive(Tox *tox, uint32_t friend_number, uint32_t file_number, ui
|
|||
return;
|
||||
}
|
||||
|
||||
uint8_t file_id[TOX_FILE_ID_LENGTH];
|
||||
|
||||
if (!tox_file_get_file_id(tox, friend_number, file_number, file_id, 0)) {
|
||||
ck_abort_msg("tox_file_get_file_id error");
|
||||
}
|
||||
|
||||
if (memcmp(file_id, file_cmp_id, TOX_FILE_ID_LENGTH) != 0) {
|
||||
ck_abort_msg("bad file_id");
|
||||
}
|
||||
|
||||
uint8_t empty[TOX_FILE_ID_LENGTH] = {0};
|
||||
|
||||
if (memcmp(empty, file_cmp_id, TOX_FILE_ID_LENGTH) == 0) {
|
||||
ck_abort_msg("empty file_id");
|
||||
}
|
||||
|
||||
file_size = filesize;
|
||||
|
||||
TOX_ERR_FILE_CONTROL error;
|
||||
|
@ -520,10 +537,18 @@ START_TEST(test_few_clients)
|
|||
tox_callback_file_recv_control(tox3, file_print_control, &to_compare);
|
||||
tox_callback_file_receive(tox3, tox_file_receive, &to_compare);
|
||||
uint64_t totalf_size = 100 * 1024 * 1024;
|
||||
uint32_t fnum = tox_file_send(tox2, 0, TOX_FILE_KIND_DATA, totalf_size, (uint8_t *)"Gentoo.exe", sizeof("Gentoo.exe"),
|
||||
0);
|
||||
uint32_t fnum = tox_file_send(tox2, 0, TOX_FILE_KIND_DATA, totalf_size, 0, (uint8_t *)"Gentoo.exe",
|
||||
sizeof("Gentoo.exe"), 0);
|
||||
ck_assert_msg(fnum != UINT32_MAX, "tox_new_file_sender fail");
|
||||
|
||||
TOX_ERR_FILE_GET gfierr;
|
||||
ck_assert_msg(!tox_file_get_file_id(tox2, 1, fnum, file_cmp_id, &gfierr), "tox_file_get_file_id didn't fail");
|
||||
ck_assert_msg(gfierr == TOX_ERR_FILE_GET_FRIEND_NOT_FOUND, "wrong error");
|
||||
ck_assert_msg(!tox_file_get_file_id(tox2, 0, fnum + 1, file_cmp_id, &gfierr), "tox_file_get_file_id didn't fail");
|
||||
ck_assert_msg(gfierr == TOX_ERR_FILE_GET_NOT_FOUND, "wrong error");
|
||||
ck_assert_msg(tox_file_get_file_id(tox2, 0, fnum, file_cmp_id, &gfierr), "tox_file_get_file_id failed");
|
||||
ck_assert_msg(gfierr == TOX_ERR_FILE_GET_OK, "wrong error");
|
||||
|
||||
|
||||
while (1) {
|
||||
tox_iterate(tox1);
|
||||
|
|
|
@ -158,8 +158,8 @@ uint32_t add_filesender(Tox *m, uint16_t friendnum, char *filename)
|
|||
fseek(tempfile, 0, SEEK_END);
|
||||
uint64_t filesize = ftell(tempfile);
|
||||
fseek(tempfile, 0, SEEK_SET);
|
||||
uint32_t filenum = tox_file_send(m, friendnum, TOX_FILE_KIND_DATA, filesize, (uint8_t *)filename, strlen(filename) + 1,
|
||||
0);
|
||||
uint32_t filenum = tox_file_send(m, friendnum, TOX_FILE_KIND_DATA, filesize, 0, (uint8_t *)filename,
|
||||
strlen(filename), 0);
|
||||
|
||||
if (filenum == -1)
|
||||
return -1;
|
||||
|
|
|
@ -88,8 +88,8 @@ uint32_t add_filesender(Tox *m, uint16_t friendnum, char *filename)
|
|||
fseek(tempfile, 0, SEEK_END);
|
||||
uint64_t filesize = ftell(tempfile);
|
||||
fseek(tempfile, 0, SEEK_SET);
|
||||
uint32_t filenum = tox_file_send(m, friendnum, TOX_FILE_KIND_DATA, filesize, (uint8_t *)filename, strlen(filename) + 1,
|
||||
0);
|
||||
uint32_t filenum = tox_file_send(m, friendnum, TOX_FILE_KIND_DATA, filesize, 0, (uint8_t *)filename,
|
||||
strlen(filename), 0);
|
||||
|
||||
if (filenum == -1)
|
||||
return -1;
|
||||
|
|
|
@ -1023,13 +1023,58 @@ void callback_file_reqchunk(Messenger *m, void (*function)(Messenger *m, uint32_
|
|||
|
||||
#define MAX_FILENAME_LENGTH 255
|
||||
|
||||
/* Copy the file transfer file id to file_id
|
||||
*
|
||||
* return 0 on success.
|
||||
* return -1 if friend not valid.
|
||||
* return -2 if filenumber not valid
|
||||
*/
|
||||
int file_get_id(const Messenger *m, int32_t friendnumber, uint32_t filenumber, uint8_t *file_id)
|
||||
{
|
||||
if (friend_not_valid(m, friendnumber))
|
||||
return -1;
|
||||
|
||||
if (m->friendlist[friendnumber].status != FRIEND_ONLINE)
|
||||
return -2;
|
||||
|
||||
uint32_t temp_filenum;
|
||||
uint8_t send_receive, file_number;
|
||||
|
||||
if (filenumber >= (1 << 16)) {
|
||||
send_receive = 1;
|
||||
temp_filenum = (filenumber >> 16) - 1;
|
||||
} else {
|
||||
send_receive = 0;
|
||||
temp_filenum = filenumber;
|
||||
}
|
||||
|
||||
if (temp_filenum >= MAX_CONCURRENT_FILE_PIPES)
|
||||
return -2;
|
||||
|
||||
file_number = temp_filenum;
|
||||
|
||||
struct File_Transfers *ft;
|
||||
|
||||
if (send_receive) {
|
||||
ft = &m->friendlist[friendnumber].file_receiving[file_number];
|
||||
} else {
|
||||
ft = &m->friendlist[friendnumber].file_sending[file_number];
|
||||
}
|
||||
|
||||
if (ft->status == FILESTATUS_NONE)
|
||||
return -2;
|
||||
|
||||
memcpy(file_id, ft->id, FILE_ID_LENGTH);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Send a file send request.
|
||||
* Maximum filename length is 255 bytes.
|
||||
* return 1 on success
|
||||
* return 0 on failure
|
||||
*/
|
||||
static int file_sendrequest(const Messenger *m, int32_t friendnumber, uint8_t filenumber, uint32_t file_type,
|
||||
uint64_t filesize, const uint8_t *filename, uint16_t filename_length)
|
||||
uint64_t filesize, const uint8_t *file_id, const uint8_t *filename, uint16_t filename_length)
|
||||
{
|
||||
if (friend_not_valid(m, friendnumber))
|
||||
return 0;
|
||||
|
@ -1037,13 +1082,18 @@ static int file_sendrequest(const Messenger *m, int32_t friendnumber, uint8_t fi
|
|||
if (filename_length > MAX_FILENAME_LENGTH)
|
||||
return 0;
|
||||
|
||||
uint8_t packet[1 + sizeof(file_type) + sizeof(filesize) + filename_length];
|
||||
uint8_t packet[1 + sizeof(file_type) + sizeof(filesize) + FILE_ID_LENGTH + filename_length];
|
||||
packet[0] = filenumber;
|
||||
file_type = htonl(file_type);
|
||||
memcpy(packet + 1, &file_type, sizeof(file_type));
|
||||
host_to_net((uint8_t *)&filesize, sizeof(filesize));
|
||||
memcpy(packet + 1 + sizeof(file_type), &filesize, sizeof(filesize));
|
||||
memcpy(packet + 1 + sizeof(file_type) + sizeof(filesize), filename, filename_length);
|
||||
memcpy(packet + 1 + sizeof(file_type) + sizeof(filesize), file_id, FILE_ID_LENGTH);
|
||||
|
||||
if (filename_length) {
|
||||
memcpy(packet + 1 + sizeof(file_type) + sizeof(filesize) + FILE_ID_LENGTH, filename, filename_length);
|
||||
}
|
||||
|
||||
return write_cryptpacket_id(m, friendnumber, PACKET_ID_FILE_SENDREQUEST, packet, sizeof(packet), 0);
|
||||
}
|
||||
|
||||
|
@ -1057,7 +1107,7 @@ static int file_sendrequest(const Messenger *m, int32_t friendnumber, uint8_t fi
|
|||
*
|
||||
*/
|
||||
long int new_filesender(const Messenger *m, int32_t friendnumber, uint32_t file_type, uint64_t filesize,
|
||||
const uint8_t *filename, uint16_t filename_length)
|
||||
const uint8_t *file_id, const uint8_t *filename, uint16_t filename_length)
|
||||
{
|
||||
if (friend_not_valid(m, friendnumber))
|
||||
return -1;
|
||||
|
@ -1078,7 +1128,7 @@ long int new_filesender(const Messenger *m, int32_t friendnumber, uint32_t file_
|
|||
if (i == MAX_CONCURRENT_FILE_PIPES)
|
||||
return -3;
|
||||
|
||||
if (file_sendrequest(m, friendnumber, i, file_type, filesize, filename, filename_length) == 0)
|
||||
if (file_sendrequest(m, friendnumber, i, file_type, filesize, file_id, filename, filename_length) == 0)
|
||||
return -4;
|
||||
|
||||
struct File_Transfers *ft = &m->friendlist[friendnumber].file_sending[i];
|
||||
|
@ -1088,6 +1138,7 @@ long int new_filesender(const Messenger *m, int32_t friendnumber, uint32_t file_
|
|||
ft->requested = 0;
|
||||
ft->slots_allocated = 0;
|
||||
ft->paused = FILE_PAUSE_NOT;
|
||||
memcpy(ft->id, file_id, FILE_ID_LENGTH);
|
||||
|
||||
++m->friendlist[friendnumber].num_sending_files;
|
||||
|
||||
|
@ -1932,9 +1983,9 @@ static int handle_packet(void *object, int i, uint8_t *temp, uint16_t len)
|
|||
}
|
||||
|
||||
case PACKET_ID_FILE_SENDREQUEST: {
|
||||
const unsigned int head_length = 1 + sizeof(uint32_t) + sizeof(uint64_t);
|
||||
const unsigned int head_length = 1 + sizeof(uint32_t) + sizeof(uint64_t) + FILE_ID_LENGTH;
|
||||
|
||||
if (data_length < head_length + 1)
|
||||
if (data_length < head_length)
|
||||
break;
|
||||
|
||||
uint8_t filenumber = data[0];
|
||||
|
@ -1944,16 +1995,15 @@ static int handle_packet(void *object, int i, uint8_t *temp, uint16_t len)
|
|||
memcpy(&file_type, data + 1, sizeof(file_type));
|
||||
file_type = ntohl(file_type);
|
||||
|
||||
/* Check if the name is the right size if file is avatar. */
|
||||
if (file_type == FILEKIND_AVATAR && filename_length != crypto_hash_sha256_BYTES)
|
||||
break;
|
||||
|
||||
memcpy(&filesize, data + 1 + sizeof(uint32_t), sizeof(filesize));
|
||||
net_to_host((uint8_t *) &filesize, sizeof(filesize));
|
||||
m->friendlist[i].file_receiving[filenumber].status = FILESTATUS_NOT_ACCEPTED;
|
||||
m->friendlist[i].file_receiving[filenumber].size = filesize;
|
||||
m->friendlist[i].file_receiving[filenumber].transferred = 0;
|
||||
m->friendlist[i].file_receiving[filenumber].paused = FILE_PAUSE_NOT;
|
||||
struct File_Transfers *ft = &m->friendlist[i].file_receiving[filenumber];
|
||||
|
||||
ft->status = FILESTATUS_NOT_ACCEPTED;
|
||||
ft->size = filesize;
|
||||
ft->transferred = 0;
|
||||
ft->paused = FILE_PAUSE_NOT;
|
||||
memcpy(ft->id, data + 1 + sizeof(uint32_t) + sizeof(uint64_t), FILE_ID_LENGTH);
|
||||
|
||||
/* Force NULL terminate file name. */
|
||||
uint8_t filename_terminated[filename_length + 1];
|
||||
|
@ -1965,7 +2015,7 @@ static int handle_packet(void *object, int i, uint8_t *temp, uint16_t len)
|
|||
real_filenumber <<= 16;
|
||||
|
||||
if (m->file_sendrequest)
|
||||
(*m->file_sendrequest)(m, i, real_filenumber, file_type, filesize, filename_terminated, filename_length,
|
||||
(*m->file_sendrequest)(m, i, real_filenumber, file_type, filesize, filename, filename_length,
|
||||
m->file_sendrequest_userdata);
|
||||
|
||||
break;
|
||||
|
|
|
@ -125,6 +125,8 @@ typedef enum {
|
|||
}
|
||||
USERSTATUS;
|
||||
|
||||
#define FILE_ID_LENGTH 32
|
||||
|
||||
struct File_Transfers {
|
||||
uint64_t size;
|
||||
uint64_t transferred;
|
||||
|
@ -133,6 +135,7 @@ struct File_Transfers {
|
|||
uint32_t last_packet_number; /* number of the last packet sent. */
|
||||
uint64_t requested; /* total data requested by the request chunk callback */
|
||||
unsigned int slots_allocated; /* number of slots allocated to this transfer. */
|
||||
uint8_t id[FILE_ID_LENGTH];
|
||||
};
|
||||
enum {
|
||||
FILESTATUS_NONE,
|
||||
|
@ -610,6 +613,15 @@ void callback_file_data(Messenger *m, void (*function)(Messenger *m, uint32_t, u
|
|||
void callback_file_reqchunk(Messenger *m, void (*function)(Messenger *m, uint32_t, uint32_t, uint64_t, size_t, void *),
|
||||
void *userdata);
|
||||
|
||||
|
||||
/* Copy the file transfer file id to file_id
|
||||
*
|
||||
* return 0 on success.
|
||||
* return -1 if friend not valid.
|
||||
* return -2 if filenumber not valid
|
||||
*/
|
||||
int file_get_id(const Messenger *m, int32_t friendnumber, uint32_t filenumber, uint8_t *file_id);
|
||||
|
||||
/* Send a file send request.
|
||||
* Maximum filename length is 255 bytes.
|
||||
* return file number on success
|
||||
|
@ -620,7 +632,7 @@ void callback_file_reqchunk(Messenger *m, void (*function)(Messenger *m, uint32_
|
|||
*
|
||||
*/
|
||||
long int new_filesender(const Messenger *m, int32_t friendnumber, uint32_t file_type, uint64_t filesize,
|
||||
const uint8_t *filename, uint16_t filename_length);
|
||||
const uint8_t *file_id, const uint8_t *filename, uint16_t filename_length);
|
||||
|
||||
/* Send a file control request.
|
||||
*
|
||||
|
|
|
@ -889,21 +889,42 @@ void tox_callback_file_recv_control(Tox *tox, tox_file_recv_control_cb *function
|
|||
callback_file_control(m, function, user_data);
|
||||
}
|
||||
|
||||
uint32_t tox_file_send(Tox *tox, uint32_t friend_number, uint32_t kind, uint64_t file_size, const uint8_t *filename,
|
||||
size_t filename_length, TOX_ERR_FILE_SEND *error)
|
||||
bool tox_file_get_file_id(const Tox *tox, uint32_t friend_number, uint32_t file_number, uint8_t *file_id,
|
||||
TOX_ERR_FILE_GET *error)
|
||||
{
|
||||
const Messenger *m = tox;
|
||||
int ret = file_get_id(m, friend_number, file_number, file_id);
|
||||
|
||||
if (ret == 0) {
|
||||
SET_ERROR_PARAMETER(error, TOX_ERR_FILE_GET_OK);
|
||||
return 1;
|
||||
} else if (ret == -1) {
|
||||
SET_ERROR_PARAMETER(error, TOX_ERR_FILE_GET_FRIEND_NOT_FOUND);
|
||||
} else {
|
||||
SET_ERROR_PARAMETER(error, TOX_ERR_FILE_GET_NOT_FOUND);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t tox_file_send(Tox *tox, uint32_t friend_number, uint32_t kind, uint64_t file_size, const uint8_t *file_id,
|
||||
const uint8_t *filename, size_t filename_length, TOX_ERR_FILE_SEND *error)
|
||||
{
|
||||
if (!filename) {
|
||||
SET_ERROR_PARAMETER(error, TOX_ERR_FILE_SEND_NULL);
|
||||
return UINT32_MAX;
|
||||
}
|
||||
|
||||
if (!filename_length) {
|
||||
SET_ERROR_PARAMETER(error, TOX_ERR_FILE_SEND_NAME_EMPTY);
|
||||
return UINT32_MAX;
|
||||
uint8_t f_id[FILE_ID_LENGTH];
|
||||
|
||||
if (!file_id) {
|
||||
/* Tox keys are 32 bytes like FILE_ID_LENGTH. */
|
||||
new_symmetric_key(f_id);
|
||||
file_id = f_id;
|
||||
}
|
||||
|
||||
Messenger *m = tox;
|
||||
long int file_num = new_filesender(m, friend_number, kind, file_size, filename, filename_length);
|
||||
long int file_num = new_filesender(m, friend_number, kind, file_size, file_id, filename, filename_length);
|
||||
|
||||
if (file_num >= 0) {
|
||||
SET_ERROR_PARAMETER(error, TOX_ERR_FILE_SEND_OK);
|
||||
|
|
|
@ -255,6 +255,11 @@ bool tox_version_is_compatible(uint32_t major, uint32_t minor, uint32_t patch);
|
|||
*/
|
||||
#define TOX_HASH_LENGTH /*crypto_hash_sha256_BYTES*/ 32
|
||||
|
||||
/**
|
||||
* The number of bytes in a file id.
|
||||
*/
|
||||
#define TOX_FILE_ID_LENGTH 32
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* :: Global enumerations
|
||||
|
@ -1412,9 +1417,9 @@ enum TOX_FILE_KIND {
|
|||
*
|
||||
* Clients who receive avatar send requests can reject it (by sending
|
||||
* TOX_FILE_CONTROL_CANCEL before any other controls), or accept it (by
|
||||
* sending TOX_FILE_CONTROL_RESUME). The filename of length TOX_HASH_LENGTH bytes
|
||||
* will contain the hash. A client can compare this hash with a
|
||||
* saved hash and send TOX_FILE_CONTROL_CANCEL to terminate the avatar
|
||||
* sending TOX_FILE_CONTROL_RESUME). The file_id of length TOX_HASH_LENGTH bytes
|
||||
* (same length as TOX_FILE_ID_LENGTH) will contain the hash. A client can compare
|
||||
* this hash with a saved hash and send TOX_FILE_CONTROL_CANCEL to terminate the avatar
|
||||
* transfer if it matches.
|
||||
*/
|
||||
TOX_FILE_KIND_AVATAR
|
||||
|
@ -1534,6 +1539,32 @@ typedef void tox_file_recv_control_cb(Tox *tox, uint32_t friend_number, uint32_t
|
|||
void tox_callback_file_recv_control(Tox *tox, tox_file_recv_control_cb *function, void *user_data);
|
||||
|
||||
|
||||
typedef enum TOX_ERR_FILE_GET {
|
||||
TOX_ERR_FILE_GET_OK,
|
||||
/**
|
||||
* The friend_number passed did not designate a valid friend.
|
||||
*/
|
||||
TOX_ERR_FILE_GET_FRIEND_NOT_FOUND,
|
||||
/**
|
||||
* No file transfer with the given file number was found for the given friend.
|
||||
*/
|
||||
TOX_ERR_FILE_GET_NOT_FOUND
|
||||
} TOX_ERR_FILE_GET;
|
||||
|
||||
/**
|
||||
* Copy the file id associated to the file transfer to a byte array.
|
||||
*
|
||||
* @param friend_number The friend number of the friend the file is being
|
||||
* transferred to.
|
||||
* @param file_number The friend-specific identifier for the file transfer.
|
||||
* @param file_id A memory region of at least TOX_FILE_ID_LENGTH bytes. If
|
||||
* this parameter is NULL, this function has no effect.
|
||||
*
|
||||
* @return true on success.
|
||||
*/
|
||||
bool tox_file_get_file_id(const Tox *tox, uint32_t friend_number, uint32_t file_number, uint8_t *file_id,
|
||||
TOX_ERR_FILE_GET *error);
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* :: File transmission: sending
|
||||
|
@ -1557,8 +1588,7 @@ typedef enum TOX_ERR_FILE_SEND {
|
|||
*/
|
||||
TOX_ERR_FILE_SEND_NAME_EMPTY,
|
||||
/**
|
||||
* Filename length exceeded 255 bytes or if kind was equal to TOX_FILE_KIND_AVATAR
|
||||
* the length was not TOX_HASH_LENGTH.
|
||||
* Filename length exceeded 255 bytes.
|
||||
*/
|
||||
TOX_ERR_FILE_SEND_NAME_INVALID_LENGTH,
|
||||
/**
|
||||
|
@ -1581,11 +1611,6 @@ typedef enum TOX_ERR_FILE_SEND {
|
|||
* File transmission occurs in chunks, which are requested through the
|
||||
* `file_request_chunk` event.
|
||||
*
|
||||
* File numbers are stable across tox_save/tox_load cycles, so that file
|
||||
* transfers can be resumed when a client restarts. The client needs to
|
||||
* associate (friend Public Key, file number) with the local path of the file and
|
||||
* persist this information to support resuming of transfers across restarts.
|
||||
*
|
||||
* If the file contents change during a transfer, the behaviour is unspecified
|
||||
* in general. What will actually happen depends on the mode in which the file
|
||||
* was modified and how the client determines the file size.
|
||||
|
@ -1616,6 +1641,9 @@ typedef enum TOX_ERR_FILE_SEND {
|
|||
* @param kind The meaning of the file to be sent.
|
||||
* @param file_size Size in bytes of the file the client wants to send, 0 if
|
||||
* unknown or streaming.
|
||||
* @param file_id A file identifier of length TOX_FILE_ID_LENGTH that can be used to
|
||||
* uniquely identify file transfers across core restarts. If NULL, a random one will
|
||||
* be generated by core. It can then be obtained by using tox_file_get_file_id().
|
||||
* @param filename Name of the file. Does not need to be the actual name. This
|
||||
* name will be sent along with the file send request.
|
||||
* @param filename_length Size in bytes of the filename.
|
||||
|
@ -1624,8 +1652,8 @@ typedef enum TOX_ERR_FILE_SEND {
|
|||
* number is per friend. File numbers are reused after a transfer terminates.
|
||||
* on failure, this function returns UINT32_MAX.
|
||||
*/
|
||||
uint32_t tox_file_send(Tox *tox, uint32_t friend_number, uint32_t kind, uint64_t file_size, const uint8_t *filename,
|
||||
size_t filename_length, TOX_ERR_FILE_SEND *error);
|
||||
uint32_t tox_file_send(Tox *tox, uint32_t friend_number, uint32_t kind, uint64_t file_size, const uint8_t *file_id,
|
||||
const uint8_t *filename, size_t filename_length, TOX_ERR_FILE_SEND *error);
|
||||
|
||||
|
||||
typedef enum TOX_ERR_FILE_SEND_CHUNK {
|
||||
|
|
Loading…
Reference in New Issue
Block a user