mirror of
https://github.com/irungentoo/toxcore.git
synced 2024-03-22 13:30:51 +08:00
Implementation of new api file transfers.
Everything should work except resuming.
This commit is contained in:
parent
f5eca31637
commit
0207fcdfb0
|
@ -21,6 +21,7 @@
|
|||
#define c_sleep(x) usleep(1000*x)
|
||||
#endif
|
||||
|
||||
|
||||
void accept_friend_request(Tox *m, const uint8_t *public_key, const uint8_t *data, size_t length, void *userdata)
|
||||
{
|
||||
if (*((uint32_t *)userdata) != 974536)
|
||||
|
@ -83,7 +84,7 @@ void handle_custom_packet(Tox *m, uint32_t friend_num, const uint8_t *data, size
|
|||
if (memcmp(f_data, data, len) == 0) {
|
||||
++custom_packet;
|
||||
} else {
|
||||
printf("Custom packet fail. %u\n", number );
|
||||
ck_abort_msg("Custom packet fail. %u", number);
|
||||
}
|
||||
|
||||
return;
|
||||
|
@ -92,45 +93,104 @@ void handle_custom_packet(Tox *m, uint32_t friend_num, const uint8_t *data, size
|
|||
uint8_t filenum;
|
||||
uint32_t file_accepted;
|
||||
uint64_t file_size;
|
||||
void file_request_accept(Tox *m, int friendnumber, uint8_t filenumber, uint64_t filesize, const uint8_t *filename,
|
||||
uint16_t filename_length, void *userdata)
|
||||
void tox_file_receive(Tox *tox, uint32_t friend_number, uint32_t file_number, TOX_FILE_KIND kind, uint64_t filesize,
|
||||
const uint8_t *filename, size_t filename_length, void *userdata)
|
||||
{
|
||||
if (*((uint32_t *)userdata) != 974536)
|
||||
return;
|
||||
|
||||
if (filename_length == sizeof("Gentoo.exe") && memcmp(filename, "Gentoo.exe", sizeof("Gentoo.exe")) == 0)
|
||||
++file_accepted;
|
||||
if (kind != TOX_FILE_KIND_DATA) {
|
||||
ck_abort_msg("Bad kind");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(filename_length == sizeof("Gentoo.exe") && memcmp(filename, "Gentoo.exe", sizeof("Gentoo.exe")) == 0)) {
|
||||
ck_abort_msg("Bad filename");
|
||||
return;
|
||||
}
|
||||
|
||||
file_size = filesize;
|
||||
tox_file_send_control(m, friendnumber, 1, filenumber, TOX_FILECONTROL_ACCEPT, NULL, 0);
|
||||
|
||||
TOX_ERR_FILE_CONTROL error;
|
||||
|
||||
if (tox_file_control(tox, friend_number, file_number, TOX_FILE_CONTROL_RESUME, &error)) {
|
||||
++file_accepted;
|
||||
} else {
|
||||
ck_abort_msg("tox_file_control failed. %i", error);
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t file_sent;
|
||||
uint32_t sendf_ok;
|
||||
void file_print_control(Tox *m, int friendnumber, uint8_t receive_send, uint8_t filenumber, uint8_t control_type,
|
||||
const uint8_t *data, uint16_t length, void *userdata)
|
||||
void file_print_control(Tox *tox, uint32_t friend_number, uint32_t file_number, TOX_FILE_CONTROL control,
|
||||
void *userdata)
|
||||
{
|
||||
if (*((uint32_t *)userdata) != 974536)
|
||||
return;
|
||||
|
||||
if (receive_send == 0 && control_type == TOX_FILECONTROL_FINISHED)
|
||||
tox_file_send_control(m, friendnumber, 1, filenumber, TOX_FILECONTROL_FINISHED, NULL, 0);
|
||||
|
||||
if (receive_send == 1 && control_type == TOX_FILECONTROL_FINISHED)
|
||||
file_sent = 1;
|
||||
|
||||
if (receive_send == 1 && control_type == TOX_FILECONTROL_ACCEPT)
|
||||
/* First send file num is 0.*/
|
||||
if (file_number == 0 && control == TOX_FILE_CONTROL_RESUME)
|
||||
sendf_ok = 1;
|
||||
|
||||
}
|
||||
|
||||
uint8_t sending_num;
|
||||
uint64_t sending_pos;
|
||||
_Bool file_sending_done;
|
||||
void tox_file_request_chunk(Tox *tox, uint32_t friend_number, uint32_t file_number, uint64_t position, size_t length,
|
||||
void *user_data)
|
||||
{
|
||||
if (*((uint32_t *)user_data) != 974536)
|
||||
return;
|
||||
|
||||
if (!sendf_ok) {
|
||||
ck_abort_msg("Didn't get resume control");
|
||||
}
|
||||
|
||||
if (sending_pos != position) {
|
||||
ck_abort_msg("Bad position");
|
||||
return;
|
||||
}
|
||||
|
||||
if (length == 0) {
|
||||
file_sending_done = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
TOX_ERR_FILE_SEND_CHUNK error;
|
||||
uint8_t f_data[length];
|
||||
memset(f_data, sending_num, length);
|
||||
|
||||
if (tox_file_send_chunk(tox, friend_number, file_number, f_data, length, &error)) {
|
||||
++sending_num;
|
||||
sending_pos += length;
|
||||
} else {
|
||||
ck_abort_msg("Could not send chunk %i", error);
|
||||
}
|
||||
|
||||
if (error != TOX_ERR_FILE_SEND_CHUNK_OK) {
|
||||
ck_abort_msg("Wrong error code");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
uint64_t size_recv;
|
||||
uint8_t num;
|
||||
void write_file(Tox *m, int friendnumber, uint8_t filenumber, const uint8_t *data, uint16_t length, void *userdata)
|
||||
_Bool file_recv;
|
||||
void write_file(Tox *tox, uint32_t friendnumber, uint32_t filenumber, uint64_t position, const uint8_t *data,
|
||||
size_t length, void *user_data)
|
||||
{
|
||||
if (*((uint32_t *)userdata) != 974536)
|
||||
if (*((uint32_t *)user_data) != 974536)
|
||||
return;
|
||||
|
||||
if (size_recv != position) {
|
||||
ck_abort_msg("Bad position");
|
||||
return;
|
||||
}
|
||||
|
||||
if (length == 0) {
|
||||
file_recv = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
uint8_t f_data[length];
|
||||
memset(f_data, num, length);
|
||||
++num;
|
||||
|
@ -138,7 +198,7 @@ void write_file(Tox *m, int friendnumber, uint8_t filenumber, const uint8_t *dat
|
|||
if (memcmp(f_data, data, length) == 0) {
|
||||
size_recv += length;
|
||||
} else {
|
||||
printf("FILE_CORRUPTED\n");
|
||||
ck_abort_msg("FILE_CORRUPTED");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -371,41 +431,32 @@ START_TEST(test_few_clients)
|
|||
c_sleep(50);
|
||||
}
|
||||
|
||||
filenum = file_accepted = file_size = file_sent = sendf_ok = size_recv = 0;
|
||||
file_accepted = file_size = file_recv = sendf_ok = size_recv = 0;
|
||||
long long unsigned int f_time = time(NULL);
|
||||
tox_callback_file_data(tox3, write_file, &to_compare);
|
||||
tox_callback_file_receive_chunk(tox3, write_file, &to_compare);
|
||||
tox_callback_file_control(tox2, file_print_control, &to_compare);
|
||||
tox_callback_file_request_chunk(tox2, tox_file_request_chunk, &to_compare);
|
||||
tox_callback_file_control(tox3, file_print_control, &to_compare);
|
||||
tox_callback_file_send_request(tox3, file_request_accept, &to_compare);
|
||||
tox_callback_file_receive(tox3, tox_file_receive, &to_compare);
|
||||
uint64_t totalf_size = 100 * 1024 * 1024;
|
||||
int fnum = tox_new_file_sender(tox2, 0, totalf_size, (uint8_t *)"Gentoo.exe", sizeof("Gentoo.exe"));
|
||||
ck_assert_msg(fnum != -1, "tox_new_file_sender fail");
|
||||
int fpiece_size = tox_file_data_size(tox2, 0);
|
||||
uint8_t f_data[fpiece_size];
|
||||
uint8_t num = 0;
|
||||
memset(f_data, num, fpiece_size);
|
||||
uint32_t fnum = tox_file_send(tox2, 0, TOX_FILE_KIND_DATA, totalf_size, (uint8_t *)"Gentoo.exe", sizeof("Gentoo.exe"),
|
||||
0);
|
||||
ck_assert_msg(fnum != UINT32_MAX, "tox_new_file_sender fail");
|
||||
|
||||
|
||||
while (1) {
|
||||
file_sent = 0;
|
||||
tox_iteration(tox1);
|
||||
tox_iteration(tox2);
|
||||
tox_iteration(tox3);
|
||||
|
||||
if (sendf_ok)
|
||||
while (tox_file_send_data(tox2, 0, fnum, f_data, fpiece_size < totalf_size ? fpiece_size : totalf_size) == 0) {
|
||||
if (totalf_size <= fpiece_size) {
|
||||
sendf_ok = 0;
|
||||
tox_file_send_control(tox2, 0, 0, fnum, TOX_FILECONTROL_FINISHED, NULL, 0);
|
||||
}
|
||||
|
||||
++num;
|
||||
memset(f_data, num, fpiece_size);
|
||||
|
||||
totalf_size -= fpiece_size;
|
||||
if (file_sending_done) {
|
||||
if (sendf_ok && file_recv && totalf_size == file_size && size_recv == file_size && sending_pos == size_recv) {
|
||||
break;
|
||||
} else {
|
||||
ck_abort_msg("Something went wrong in file transfer %u %u %u %u %u", sendf_ok, file_recv, totalf_size == file_size,
|
||||
size_recv == file_size, sending_pos == size_recv);
|
||||
}
|
||||
|
||||
if (file_sent && size_recv == file_size)
|
||||
break;
|
||||
}
|
||||
|
||||
uint32_t tox1_interval = tox_iteration_interval(tox1);
|
||||
uint32_t tox2_interval = tox_iteration_interval(tox2);
|
||||
|
|
|
@ -349,6 +349,18 @@ static int add_receipt(Messenger *m, int32_t friendnumber, uint32_t packet_num,
|
|||
new->next = NULL;
|
||||
return 0;
|
||||
}
|
||||
/*
|
||||
* return -1 on failure.
|
||||
* return 0 if packet was received.
|
||||
*/
|
||||
static int friend_received_packet(const Messenger *m, int32_t friendnumber, uint32_t number)
|
||||
{
|
||||
if (friend_not_valid(m, friendnumber))
|
||||
return -1;
|
||||
|
||||
return cryptpacket_received(m->net_crypto, friend_connection_crypt_connection_id(m->fr_c,
|
||||
m->friendlist[friendnumber].friendcon_id), number);
|
||||
}
|
||||
|
||||
static int do_receipts(Messenger *m, int32_t friendnumber)
|
||||
{
|
||||
|
@ -360,8 +372,7 @@ static int do_receipts(Messenger *m, int32_t friendnumber)
|
|||
while (receipts) {
|
||||
struct Receipts *temp_r = receipts->next;
|
||||
|
||||
if (cryptpacket_received(m->net_crypto, friend_connection_crypt_connection_id(m->fr_c,
|
||||
m->friendlist[friendnumber].friendcon_id), receipts->packet_num) == -1)
|
||||
if (friend_received_packet(m, friendnumber, receipts->packet_num) == -1)
|
||||
break;
|
||||
|
||||
if (m->read_receipt)
|
||||
|
@ -970,11 +981,11 @@ void callback_file_sendrequest(Messenger *m, void (*function)(Messenger *m, uin
|
|||
|
||||
/* Set the callback for file control requests.
|
||||
*
|
||||
* Function(Tox *tox, uint32_t friendnumber, uint8_t send_receive, uint8_t filenumber, uint8_t control_type, uint8_t *data, uint16_t length, void *userdata)
|
||||
* Function(Tox *tox, uint32_t friendnumber, uint32_t filenumber, unsigned int control_type, void *userdata)
|
||||
*
|
||||
*/
|
||||
void callback_file_control(Messenger *m, void (*function)(Messenger *m, uint32_t, uint8_t, uint8_t, uint8_t,
|
||||
const uint8_t *, uint16_t, void *), void *userdata)
|
||||
void callback_file_control(Messenger *m, void (*function)(Messenger *m, uint32_t, uint32_t, unsigned int, void *),
|
||||
void *userdata)
|
||||
{
|
||||
m->file_filecontrol = function;
|
||||
m->file_filecontrol_userdata = userdata;
|
||||
|
@ -982,17 +993,28 @@ void callback_file_control(Messenger *m, void (*function)(Messenger *m, uint32_t
|
|||
|
||||
/* Set the callback for file data.
|
||||
*
|
||||
* Function(Tox *tox, uint32_t friendnumber, uint8_t filenumber, uint8_t *data, uint16_t length, void *userdata)
|
||||
* Function(Tox *tox, uint32_t friendnumber, uint32_t filenumber, uint64_t position, uint8_t *data, size_t length, void *userdata)
|
||||
*
|
||||
*/
|
||||
void callback_file_data(Messenger *m, void (*function)(Messenger *m, uint32_t, uint8_t, const uint8_t *,
|
||||
uint16_t length,
|
||||
void *), void *userdata)
|
||||
void callback_file_data(Messenger *m, void (*function)(Messenger *m, uint32_t, uint32_t, uint64_t, const uint8_t *,
|
||||
size_t, void *), void *userdata)
|
||||
{
|
||||
m->file_filedata = function;
|
||||
m->file_filedata_userdata = userdata;
|
||||
}
|
||||
|
||||
/* Set the callback for file request chunk.
|
||||
*
|
||||
* Function(Tox *tox, uint32_t friendnumber, uint32_t filenumber, uint64_t position, size_t length, void *userdata)
|
||||
*
|
||||
*/
|
||||
void callback_file_reqchunk(Messenger *m, void (*function)(Messenger *m, uint32_t, uint32_t, uint64_t, size_t, void *),
|
||||
void *userdata)
|
||||
{
|
||||
m->file_reqchunk = function;
|
||||
m->file_reqchunk_userdata = userdata;
|
||||
}
|
||||
|
||||
#define MAX_FILENAME_LENGTH 255
|
||||
|
||||
/* Send a file send request.
|
||||
|
@ -1053,132 +1075,182 @@ long int new_filesender(const Messenger *m, int32_t friendnumber, uint32_t file_
|
|||
m->friendlist[friendnumber].file_sending[i].status = FILESTATUS_NOT_ACCEPTED;
|
||||
m->friendlist[friendnumber].file_sending[i].size = filesize;
|
||||
m->friendlist[friendnumber].file_sending[i].transferred = 0;
|
||||
m->friendlist[friendnumber].file_sending[i].type = file_type;
|
||||
m->friendlist[friendnumber].file_sending[i].paused = FILE_PAUSE_NOT;
|
||||
++m->friendlist[friendnumber].num_sending_files;
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
/* Send a file control request.
|
||||
* send_receive is 0 if we want the control packet to target a sending file, 1 if it targets a receiving file.
|
||||
*
|
||||
* return 0 on success
|
||||
* return -1 on failure
|
||||
*/
|
||||
int file_control(const Messenger *m, int32_t friendnumber, uint8_t send_receive, uint8_t filenumber, uint8_t message_id,
|
||||
const uint8_t *data, uint16_t length)
|
||||
int send_file_control_packet(const Messenger *m, int32_t friendnumber, uint8_t send_receive, uint8_t filenumber,
|
||||
uint8_t control_type, uint8_t *data, uint16_t data_length)
|
||||
{
|
||||
if (length > MAX_CRYPTO_DATA_SIZE - 3)
|
||||
if (1 + 3 + data_length > MAX_CRYPTO_DATA_SIZE)
|
||||
return -1;
|
||||
|
||||
uint8_t packet[3 + data_length];
|
||||
|
||||
packet[0] = send_receive;
|
||||
packet[1] = filenumber;
|
||||
packet[2] = control_type;
|
||||
|
||||
if (data_length) {
|
||||
memcpy(packet, packet + 3, data_length);
|
||||
}
|
||||
|
||||
return write_cryptpacket_id(m, friendnumber, PACKET_ID_FILE_CONTROL, packet, sizeof(packet), 0);
|
||||
}
|
||||
|
||||
/* Send a file control request.
|
||||
*
|
||||
* return 0 on success
|
||||
* return -1 if friend not valid.
|
||||
* return -2 if friend not online.
|
||||
* return -3 if file number invalid.
|
||||
* return -4 if file control is bad.
|
||||
* return -5 if file already paused.
|
||||
* return -6 if resume file failed because it was only paused by the other.
|
||||
* return -7 if resume file failed because it wasn't paused.
|
||||
* return -8 if packet failed to send.
|
||||
*/
|
||||
int file_control(const Messenger *m, int32_t friendnumber, uint32_t filenumber, unsigned int control)
|
||||
{
|
||||
if (friend_not_valid(m, friendnumber))
|
||||
return -1;
|
||||
|
||||
if (send_receive == 1) {
|
||||
if (m->friendlist[friendnumber].file_receiving[filenumber].status == FILESTATUS_NONE)
|
||||
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 {
|
||||
if (m->friendlist[friendnumber].file_sending[filenumber].status == FILESTATUS_NONE)
|
||||
return -1;
|
||||
send_receive = 0;
|
||||
temp_filenum = filenumber;
|
||||
}
|
||||
|
||||
if (send_receive > 1)
|
||||
return -1;
|
||||
if (temp_filenum >= MAX_CONCURRENT_FILE_PIPES)
|
||||
return -3;
|
||||
|
||||
uint8_t packet[MAX_CRYPTO_DATA_SIZE];
|
||||
packet[0] = send_receive;
|
||||
packet[1] = filenumber;
|
||||
packet[2] = message_id;
|
||||
uint64_t transferred = 0;
|
||||
file_number = temp_filenum;
|
||||
|
||||
if (message_id == FILECONTROL_RESUME_BROKEN) {
|
||||
if (length != sizeof(uint64_t))
|
||||
return -1;
|
||||
struct File_Transfers *ft;
|
||||
|
||||
uint8_t remaining[sizeof(uint64_t)];
|
||||
memcpy(remaining, data, sizeof(uint64_t));
|
||||
host_to_net(remaining, sizeof(uint64_t));
|
||||
memcpy(packet + 3, remaining, sizeof(uint64_t));
|
||||
memcpy(&transferred, data, sizeof(uint64_t));
|
||||
if (send_receive) {
|
||||
ft = &m->friendlist[friendnumber].file_receiving[file_number];
|
||||
} else {
|
||||
memcpy(packet + 3, data, length);
|
||||
ft = &m->friendlist[friendnumber].file_sending[file_number];
|
||||
}
|
||||
|
||||
if (write_cryptpacket_id(m, friendnumber, PACKET_ID_FILE_CONTROL, packet, length + 3, 0)) {
|
||||
if (send_receive == 1)
|
||||
switch (message_id) {
|
||||
case FILECONTROL_ACCEPT:
|
||||
m->friendlist[friendnumber].file_receiving[filenumber].status = FILESTATUS_TRANSFERRING;
|
||||
break;
|
||||
if (ft->status == FILESTATUS_NONE)
|
||||
return -3;
|
||||
|
||||
case FILECONTROL_PAUSE:
|
||||
m->friendlist[friendnumber].file_receiving[filenumber].status = FILESTATUS_PAUSED_BY_US;
|
||||
break;
|
||||
if (control > FILECONTROL_KILL)
|
||||
return -4;
|
||||
|
||||
case FILECONTROL_KILL:
|
||||
case FILECONTROL_FINISHED:
|
||||
m->friendlist[friendnumber].file_receiving[filenumber].status = FILESTATUS_NONE;
|
||||
break;
|
||||
if (control == FILECONTROL_PAUSE && (ft->paused & FILE_PAUSE_US))
|
||||
return -5;
|
||||
|
||||
case FILECONTROL_RESUME_BROKEN:
|
||||
m->friendlist[friendnumber].file_receiving[filenumber].status = FILESTATUS_PAUSED_BY_OTHER;
|
||||
m->friendlist[friendnumber].file_receiving[filenumber].transferred = transferred;
|
||||
break;
|
||||
if (control == FILECONTROL_ACCEPT && ft->status == FILESTATUS_TRANSFERRING) {
|
||||
if (!(ft->paused & FILE_PAUSE_US)) {
|
||||
if (ft->paused & FILE_PAUSE_OTHER) {
|
||||
return -6;
|
||||
} else {
|
||||
return -7;
|
||||
}
|
||||
else
|
||||
switch (message_id) {
|
||||
case FILECONTROL_ACCEPT:
|
||||
m->friendlist[friendnumber].file_sending[filenumber].status = FILESTATUS_TRANSFERRING;
|
||||
break;
|
||||
|
||||
case FILECONTROL_PAUSE:
|
||||
m->friendlist[friendnumber].file_sending[filenumber].status = FILESTATUS_PAUSED_BY_US;
|
||||
break;
|
||||
|
||||
case FILECONTROL_KILL:
|
||||
m->friendlist[friendnumber].file_sending[filenumber].status = FILESTATUS_NONE;
|
||||
break;
|
||||
|
||||
case FILECONTROL_FINISHED:
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (send_file_control_packet(m, friendnumber, send_receive, file_number, control, 0, 0)) {
|
||||
if (control == FILECONTROL_KILL) {
|
||||
ft->status = FILESTATUS_NONE;
|
||||
|
||||
if (send_receive == 0) {
|
||||
--m->friendlist[friendnumber].num_sending_files;
|
||||
}
|
||||
} else if (control == FILECONTROL_PAUSE) {
|
||||
ft->paused |= FILE_PAUSE_US;
|
||||
} else if (control == FILECONTROL_ACCEPT) {
|
||||
ft->status = FILESTATUS_TRANSFERRING;
|
||||
|
||||
if (ft->paused & FILE_PAUSE_US) {
|
||||
ft->paused ^= FILE_PAUSE_US;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return -8;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define MIN_SLOTS_FREE (CRYPTO_MIN_QUEUE_LENGTH / 2)
|
||||
/* Send file data.
|
||||
*
|
||||
* return 0 on success
|
||||
* return -1 on failure
|
||||
* return -1 if friend not valid.
|
||||
* return -2 if friend not online.
|
||||
* return -3 if filenumber invalid.
|
||||
* return -4 if file transfer not transferring.
|
||||
* return -5 if trying to send too much data.
|
||||
* return -6 if packet queue full.
|
||||
*/
|
||||
int file_data(const Messenger *m, int32_t friendnumber, uint8_t filenumber, const uint8_t *data, uint16_t length)
|
||||
int file_data(const Messenger *m, int32_t friendnumber, uint32_t filenumber, const uint8_t *data, uint16_t length)
|
||||
{
|
||||
if (length > MAX_CRYPTO_DATA_SIZE - 1)
|
||||
return -1;
|
||||
|
||||
if (friend_not_valid(m, friendnumber))
|
||||
return -1;
|
||||
|
||||
if (m->friendlist[friendnumber].file_sending[filenumber].status != FILESTATUS_TRANSFERRING)
|
||||
return -1;
|
||||
if (m->friendlist[friendnumber].status != FRIEND_ONLINE)
|
||||
return -2;
|
||||
|
||||
if (filenumber > MAX_CONCURRENT_FILE_PIPES)
|
||||
return -3;
|
||||
|
||||
struct File_Transfers *ft = &m->friendlist[friendnumber].file_sending[filenumber];
|
||||
|
||||
if (ft->status != FILESTATUS_TRANSFERRING)
|
||||
return -4;
|
||||
|
||||
if (ft->paused != FILE_PAUSE_NOT)
|
||||
return -4;
|
||||
|
||||
if (length > MAX_CRYPTO_DATA_SIZE - 2)
|
||||
return -5;
|
||||
|
||||
if (ft->size) {
|
||||
if (ft->size - ft->transferred < length) {
|
||||
return -5;
|
||||
}
|
||||
}
|
||||
|
||||
/* Prevent file sending from filling up the entire buffer preventing messages from being sent. TODO: remove */
|
||||
if (crypto_num_free_sendqueue_slots(m->net_crypto, friend_connection_crypt_connection_id(m->fr_c,
|
||||
m->friendlist[friendnumber].friendcon_id)) < MIN_SLOTS_FREE)
|
||||
return -1;
|
||||
return -6;
|
||||
|
||||
uint8_t packet[MAX_CRYPTO_DATA_SIZE];
|
||||
packet[0] = filenumber;
|
||||
memcpy(packet + 1, data, length);
|
||||
uint8_t packet[2 + length];
|
||||
packet[0] = PACKET_ID_FILE_DATA;
|
||||
packet[1] = filenumber;
|
||||
memcpy(packet + 2, data, length);
|
||||
|
||||
int64_t ret = write_cryptpacket(m->net_crypto, friend_connection_crypt_connection_id(m->fr_c,
|
||||
m->friendlist[friendnumber].friendcon_id), packet, sizeof(packet), 1);
|
||||
|
||||
if (ret != -1) {
|
||||
//TODO record packet ids to check if other received complete file.
|
||||
ft->transferred += length;
|
||||
|
||||
if (length == 0 || ft->size == ft->transferred) {
|
||||
ft->status = FILESTATUS_FINISHED;
|
||||
ft->last_packet_number = ret;
|
||||
}
|
||||
|
||||
if (write_cryptpacket_id(m, friendnumber, PACKET_ID_FILE_DATA, packet, length + 1, 1)) {
|
||||
m->friendlist[friendnumber].file_sending[filenumber].transferred += length;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -1;
|
||||
return -6;
|
||||
|
||||
}
|
||||
|
||||
|
@ -1209,105 +1281,142 @@ uint64_t file_dataremaining(const Messenger *m, int32_t friendnumber, uint8_t fi
|
|||
}
|
||||
}
|
||||
|
||||
static void do_reqchunk_filecb(Messenger *m, int32_t friendnumber)
|
||||
{
|
||||
if (!m->friendlist[friendnumber].num_sending_files)
|
||||
return;
|
||||
|
||||
int free_slots = crypto_num_free_sendqueue_slots(m->net_crypto, friend_connection_crypt_connection_id(m->fr_c,
|
||||
m->friendlist[friendnumber].friendcon_id));
|
||||
|
||||
if (free_slots <= MIN_SLOTS_FREE)
|
||||
return;
|
||||
|
||||
free_slots -= MIN_SLOTS_FREE;
|
||||
|
||||
unsigned int i, num = m->friendlist[friendnumber].num_sending_files;
|
||||
|
||||
for (i = 0; i < MAX_CONCURRENT_FILE_PIPES; ++i) {
|
||||
struct File_Transfers *ft = &m->friendlist[friendnumber].file_sending[i];
|
||||
|
||||
if (ft->status != FILESTATUS_NONE) {
|
||||
--num;
|
||||
|
||||
if (ft->status == FILESTATUS_FINISHED) {
|
||||
/* Check if file was entirely sent. */
|
||||
if (friend_received_packet(m, friendnumber, ft->last_packet_number) == 0) {
|
||||
if (m->file_reqchunk)
|
||||
(*m->file_reqchunk)(m, friendnumber, i, ft->transferred, 0, m->file_reqchunk_userdata);
|
||||
|
||||
ft->status = FILESTATUS_NONE;
|
||||
--m->friendlist[friendnumber].num_sending_files;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
while (ft->status == FILESTATUS_TRANSFERRING && (ft->paused == FILE_PAUSE_NOT)) {
|
||||
if (free_slots == 0)
|
||||
break;
|
||||
|
||||
uint16_t length = MAX_CRYPTO_DATA_SIZE - 2;
|
||||
|
||||
if (ft->size) {
|
||||
if (ft->size == ft->transferred) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (ft->size - ft->transferred < length) {
|
||||
length = ft->size - ft->transferred;
|
||||
}
|
||||
}
|
||||
|
||||
if (m->file_reqchunk)
|
||||
(*m->file_reqchunk)(m, friendnumber, i, ft->transferred, length, m->file_reqchunk_userdata);
|
||||
|
||||
--free_slots;
|
||||
}
|
||||
|
||||
if (num == 0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Run this when the friend disconnects.
|
||||
* Sets all current file transfers to broken.
|
||||
*/
|
||||
static void break_files(const Messenger *m, int32_t friendnumber)
|
||||
{
|
||||
uint32_t i;
|
||||
/* TODO
|
||||
for (i = 0; i < MAX_CONCURRENT_FILE_PIPES; ++i) {
|
||||
if (m->friendlist[friendnumber].file_sending[i].status != FILESTATUS_NONE)
|
||||
m->friendlist[friendnumber].file_sending[i].status = FILESTATUS_BROKEN;
|
||||
|
||||
for (i = 0; i < MAX_CONCURRENT_FILE_PIPES; ++i) {
|
||||
if (m->friendlist[friendnumber].file_sending[i].status != FILESTATUS_NONE)
|
||||
m->friendlist[friendnumber].file_sending[i].status = FILESTATUS_BROKEN;
|
||||
|
||||
if (m->friendlist[friendnumber].file_receiving[i].status != FILESTATUS_NONE)
|
||||
m->friendlist[friendnumber].file_receiving[i].status = FILESTATUS_BROKEN;
|
||||
}
|
||||
if (m->friendlist[friendnumber].file_receiving[i].status != FILESTATUS_NONE)
|
||||
m->friendlist[friendnumber].file_receiving[i].status = FILESTATUS_BROKEN;
|
||||
}*/
|
||||
}
|
||||
|
||||
static int handle_filecontrol(const Messenger *m, int32_t friendnumber, uint8_t receive_send, uint8_t filenumber,
|
||||
uint8_t message_id, uint8_t *data,
|
||||
uint16_t length)
|
||||
/* return -1 on failure, 0 on success.
|
||||
*/
|
||||
static int handle_filecontrol(Messenger *m, int32_t friendnumber, uint8_t receive_send, uint8_t filenumber,
|
||||
uint8_t control_type, uint8_t *data, uint16_t length)
|
||||
{
|
||||
if (receive_send > 1)
|
||||
return -1;
|
||||
|
||||
if (control_type > FILECONTROL_RESUME_BROKEN)
|
||||
return -1;
|
||||
|
||||
uint32_t real_filenumber = filenumber;
|
||||
struct File_Transfers *ft;
|
||||
|
||||
if (receive_send == 0) {
|
||||
if (m->friendlist[friendnumber].file_receiving[filenumber].status == FILESTATUS_NONE) {
|
||||
/* Tell the other to kill the file sending if we don't know this one. */
|
||||
m->friendlist[friendnumber].file_receiving[filenumber].status = FILESTATUS_TEMPORARY;
|
||||
file_control(m, friendnumber, !receive_send, filenumber, FILECONTROL_KILL, NULL, 0);
|
||||
m->friendlist[friendnumber].file_receiving[filenumber].status = FILESTATUS_NONE;
|
||||
return -1;
|
||||
|
||||
}
|
||||
|
||||
switch (message_id) {
|
||||
case FILECONTROL_ACCEPT:
|
||||
if (m->friendlist[friendnumber].file_receiving[filenumber].status != FILESTATUS_PAUSED_BY_US) {
|
||||
m->friendlist[friendnumber].file_receiving[filenumber].status = FILESTATUS_TRANSFERRING;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -1;
|
||||
|
||||
case FILECONTROL_PAUSE:
|
||||
if (m->friendlist[friendnumber].file_receiving[filenumber].status != FILESTATUS_PAUSED_BY_US) {
|
||||
m->friendlist[friendnumber].file_receiving[filenumber].status = FILESTATUS_PAUSED_BY_OTHER;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -1;
|
||||
|
||||
case FILECONTROL_KILL:
|
||||
m->friendlist[friendnumber].file_receiving[filenumber].status = FILESTATUS_NONE;
|
||||
|
||||
case FILECONTROL_FINISHED:
|
||||
return 0;
|
||||
}
|
||||
real_filenumber += 1;
|
||||
real_filenumber <<= 16;
|
||||
ft = &m->friendlist[friendnumber].file_receiving[filenumber];
|
||||
} else {
|
||||
if (m->friendlist[friendnumber].file_sending[filenumber].status == FILESTATUS_NONE) {
|
||||
/* Tell the other to kill the file sending if we don't know this one. */
|
||||
m->friendlist[friendnumber].file_sending[filenumber].status = FILESTATUS_TEMPORARY;
|
||||
file_control(m, friendnumber, !receive_send, filenumber, FILECONTROL_KILL, NULL, 0);
|
||||
m->friendlist[friendnumber].file_sending[filenumber].status = FILESTATUS_NONE;
|
||||
return -1;
|
||||
}
|
||||
|
||||
switch (message_id) {
|
||||
case FILECONTROL_ACCEPT:
|
||||
if (m->friendlist[friendnumber].file_sending[filenumber].status != FILESTATUS_PAUSED_BY_US) {
|
||||
m->friendlist[friendnumber].file_sending[filenumber].status = FILESTATUS_TRANSFERRING;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -1;
|
||||
|
||||
case FILECONTROL_PAUSE:
|
||||
if (m->friendlist[friendnumber].file_sending[filenumber].status != FILESTATUS_PAUSED_BY_US) {
|
||||
m->friendlist[friendnumber].file_sending[filenumber].status = FILESTATUS_PAUSED_BY_OTHER;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
case FILECONTROL_KILL:
|
||||
case FILECONTROL_FINISHED:
|
||||
m->friendlist[friendnumber].file_sending[filenumber].status = FILESTATUS_NONE;
|
||||
return 0;
|
||||
|
||||
case FILECONTROL_RESUME_BROKEN: {
|
||||
if (m->friendlist[friendnumber].file_sending[filenumber].status == FILESTATUS_BROKEN && length == sizeof(uint64_t)) {
|
||||
m->friendlist[friendnumber].file_sending[filenumber].status = FILESTATUS_PAUSED_BY_US;
|
||||
net_to_host(data, sizeof(uint64_t));
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
ft = &m->friendlist[friendnumber].file_sending[filenumber];
|
||||
}
|
||||
|
||||
return -1;
|
||||
if (ft->status == FILESTATUS_NONE) {
|
||||
/* File transfer doesn't exist, tell the other to kill it. */
|
||||
send_file_control_packet(m, friendnumber, !receive_send, filenumber, FILECONTROL_KILL, 0, 0);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (control_type == FILECONTROL_ACCEPT) {
|
||||
ft->status = FILESTATUS_TRANSFERRING;
|
||||
|
||||
if (ft->paused & FILE_PAUSE_OTHER) {
|
||||
ft->paused ^= FILE_PAUSE_OTHER;
|
||||
}
|
||||
|
||||
if (m->file_filecontrol)
|
||||
(*m->file_filecontrol)(m, friendnumber, real_filenumber, control_type, m->file_filecontrol_userdata);
|
||||
} else if (control_type == FILECONTROL_PAUSE) {
|
||||
ft->paused |= FILE_PAUSE_OTHER;
|
||||
|
||||
if (m->file_filecontrol)
|
||||
(*m->file_filecontrol)(m, friendnumber, real_filenumber, control_type, m->file_filecontrol_userdata);
|
||||
} else if (control_type == FILECONTROL_KILL) {
|
||||
|
||||
if (m->file_filecontrol)
|
||||
(*m->file_filecontrol)(m, friendnumber, real_filenumber, control_type, m->file_filecontrol_userdata);
|
||||
|
||||
ft->status = FILESTATUS_NONE;
|
||||
|
||||
if (receive_send) {
|
||||
--m->friendlist[friendnumber].num_sending_files;
|
||||
}
|
||||
|
||||
} else if (control_type == FILECONTROL_RESUME_BROKEN) {
|
||||
//TODO
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**************************************/
|
||||
|
@ -1766,6 +1875,7 @@ static int handle_packet(void *object, int i, uint8_t *temp, uint16_t len)
|
|||
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;
|
||||
|
||||
/* Force NULL terminate file name. */
|
||||
uint8_t filename_terminated[data_length - head_length + 1];
|
||||
|
@ -1794,26 +1904,51 @@ static int handle_packet(void *object, int i, uint8_t *temp, uint16_t len)
|
|||
if (handle_filecontrol(m, i, send_receive, filenumber, control_type, data + 3, data_length - 3) == -1)
|
||||
break;
|
||||
|
||||
if (m->file_filecontrol)
|
||||
(*m->file_filecontrol)(m, i, send_receive, filenumber, control_type, data + 3, data_length - 3,
|
||||
m->file_filecontrol_userdata);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case PACKET_ID_FILE_DATA: {
|
||||
if (data_length < 2)
|
||||
if (data_length <= 1)
|
||||
break;
|
||||
|
||||
uint8_t filenumber = data[0];
|
||||
struct File_Transfers *ft = &m->friendlist[i].file_receiving[filenumber];
|
||||
|
||||
if (m->friendlist[i].file_receiving[filenumber].status == FILESTATUS_NONE)
|
||||
if (ft->status == FILESTATUS_NONE)
|
||||
break;
|
||||
|
||||
m->friendlist[i].file_receiving[filenumber].transferred += (data_length - 1);
|
||||
uint64_t position = ft->transferred;
|
||||
uint32_t real_filenumber = filenumber;
|
||||
real_filenumber += 1;
|
||||
real_filenumber <<= 16;
|
||||
uint16_t file_data_length = (data_length - 1);
|
||||
uint8_t *file_data;
|
||||
|
||||
if (file_data_length == 0) {
|
||||
file_data = NULL;
|
||||
} else {
|
||||
file_data = data + 1;
|
||||
}
|
||||
|
||||
if (m->file_filedata)
|
||||
(*m->file_filedata)(m, i, filenumber, data + 1, data_length - 1, m->file_filedata_userdata);
|
||||
(*m->file_filedata)(m, i, real_filenumber, position, file_data, file_data_length, m->file_filedata_userdata);
|
||||
|
||||
ft->transferred += file_data_length;
|
||||
|
||||
if (ft->size && ft->transferred >= ft->size) {
|
||||
file_data_length = 0;
|
||||
file_data = NULL;
|
||||
position = ft->transferred;
|
||||
|
||||
/* Full file received. */
|
||||
if (m->file_filedata)
|
||||
(*m->file_filedata)(m, i, real_filenumber, position, file_data, file_data_length, m->file_filedata_userdata);
|
||||
}
|
||||
|
||||
/* Data is zero, filetransfer is over. */
|
||||
if (file_data_length == 0) {
|
||||
ft->status = FILESTATUS_NONE;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
@ -1907,6 +2042,7 @@ void do_friends(Messenger *m)
|
|||
|
||||
check_friend_tcp_udp(m, i);
|
||||
do_receipts(m, i);
|
||||
do_reqchunk_filecb(m, i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -128,18 +128,25 @@ USERSTATUS;
|
|||
struct File_Transfers {
|
||||
uint64_t size;
|
||||
uint64_t transferred;
|
||||
uint8_t status; /* 0 == no transfer, 1 = not accepted, 2 = paused by the other, 3 = transferring, 4 = broken, 5 = paused by us */
|
||||
unsigned int type;
|
||||
uint8_t status; /* 0 == no transfer, 1 = not accepted, 3 = transferring, 4 = broken, 5 = finished */
|
||||
uint8_t paused; /* 0: not paused, 1 = paused by us, 2 = paused by other, 3 = paused by both. */
|
||||
uint32_t last_packet_number; /* number of the last packet sent. */
|
||||
};
|
||||
enum {
|
||||
FILESTATUS_NONE,
|
||||
FILESTATUS_NOT_ACCEPTED,
|
||||
FILESTATUS_PAUSED_BY_OTHER,
|
||||
FILESTATUS_TRANSFERRING,
|
||||
FILESTATUS_BROKEN,
|
||||
FILESTATUS_PAUSED_BY_US,
|
||||
FILESTATUS_TEMPORARY
|
||||
//FILESTATUS_BROKEN,
|
||||
FILESTATUS_FINISHED
|
||||
};
|
||||
|
||||
enum {
|
||||
FILE_PAUSE_NOT,
|
||||
FILE_PAUSE_US,
|
||||
FILE_PAUSE_OTHER,
|
||||
FILE_PAUSE_BOTH
|
||||
};
|
||||
|
||||
/* This cannot be bigger than 256 */
|
||||
#define MAX_CONCURRENT_FILE_PIPES 256
|
||||
|
||||
|
@ -147,7 +154,6 @@ enum {
|
|||
FILECONTROL_ACCEPT,
|
||||
FILECONTROL_PAUSE,
|
||||
FILECONTROL_KILL,
|
||||
FILECONTROL_FINISHED,
|
||||
FILECONTROL_RESUME_BROKEN
|
||||
};
|
||||
|
||||
|
@ -179,6 +185,7 @@ typedef struct {
|
|||
uint64_t share_relays_lastsent;
|
||||
uint8_t last_connection_udp_tcp;
|
||||
struct File_Transfers file_sending[MAX_CONCURRENT_FILE_PIPES];
|
||||
unsigned int num_sending_files;
|
||||
struct File_Transfers file_receiving[MAX_CONCURRENT_FILE_PIPES];
|
||||
|
||||
struct {
|
||||
|
@ -249,10 +256,12 @@ struct Messenger {
|
|||
void (*file_sendrequest)(struct Messenger *m, uint32_t, uint32_t, unsigned int, uint64_t, const uint8_t *, size_t,
|
||||
void *);
|
||||
void *file_sendrequest_userdata;
|
||||
void (*file_filecontrol)(struct Messenger *m, uint32_t, uint8_t, uint8_t, uint8_t, const uint8_t *, uint16_t, void *);
|
||||
void (*file_filecontrol)(struct Messenger *m, uint32_t, uint32_t, unsigned int, void *);
|
||||
void *file_filecontrol_userdata;
|
||||
void (*file_filedata)(struct Messenger *m, uint32_t, uint8_t, const uint8_t *, uint16_t length, void *);
|
||||
void (*file_filedata)(struct Messenger *m, uint32_t, uint32_t, uint64_t, const uint8_t *, size_t, void *);
|
||||
void *file_filedata_userdata;
|
||||
void (*file_reqchunk)(struct Messenger *m, uint32_t, uint32_t, uint64_t, size_t, void *);
|
||||
void *file_reqchunk_userdata;
|
||||
|
||||
void (*msi_packet)(struct Messenger *m, uint32_t, const uint8_t *, uint16_t, void *);
|
||||
void *msi_packet_userdata;
|
||||
|
@ -562,20 +571,27 @@ void callback_file_sendrequest(Messenger *m, void (*function)(Messenger *m, uin
|
|||
|
||||
/* Set the callback for file control requests.
|
||||
*
|
||||
* Function(Tox *tox, uint32_t friendnumber, uint8_t send_receive, uint8_t filenumber, uint8_t control_type, uint8_t *data, uint16_t length, void *userdata)
|
||||
* Function(Tox *tox, uint32_t friendnumber, uint32_t filenumber, unsigned int control_type, void *userdata)
|
||||
*
|
||||
*/
|
||||
void callback_file_control(Messenger *m, void (*function)(Messenger *m, uint32_t, uint8_t, uint8_t, uint8_t,
|
||||
const uint8_t *, uint16_t, void *), void *userdata);
|
||||
void callback_file_control(Messenger *m, void (*function)(Messenger *m, uint32_t, uint32_t, unsigned int, void *),
|
||||
void *userdata);
|
||||
|
||||
/* Set the callback for file data.
|
||||
*
|
||||
* Function(Tox *tox, uint32_t friendnumber, uint8_t filenumber, uint8_t *data, uint16_t length, void *userdata)
|
||||
* Function(Tox *tox, uint32_t friendnumber, uint32_t filenumber, uint64_t position, uint8_t *data, size_t length, void *userdata)
|
||||
*
|
||||
*/
|
||||
void callback_file_data(Messenger *m, void (*function)(Messenger *m, uint32_t, uint8_t, const uint8_t *,
|
||||
uint16_t length,
|
||||
void *), void *userdata);
|
||||
void callback_file_data(Messenger *m, void (*function)(Messenger *m, uint32_t, uint32_t, uint64_t, const uint8_t *,
|
||||
size_t, void *), void *userdata);
|
||||
|
||||
/* Set the callback for file request chunk.
|
||||
*
|
||||
* Function(Tox *tox, uint32_t friendnumber, uint32_t filenumber, uint64_t position, size_t length, void *userdata)
|
||||
*
|
||||
*/
|
||||
void callback_file_reqchunk(Messenger *m, void (*function)(Messenger *m, uint32_t, uint32_t, uint64_t, size_t, void *),
|
||||
void *userdata);
|
||||
|
||||
/* Send a file send request.
|
||||
* Maximum filename length is 255 bytes.
|
||||
|
@ -590,20 +606,30 @@ long int new_filesender(const Messenger *m, int32_t friendnumber, uint32_t file_
|
|||
const uint8_t *filename, uint16_t filename_length);
|
||||
|
||||
/* Send a file control request.
|
||||
* send_receive is 0 if we want the control packet to target a sending file, 1 if it targets a receiving file.
|
||||
*
|
||||
* return 1 on success
|
||||
* return 0 on failure
|
||||
* return 0 on success
|
||||
* return -1 if friend not valid.
|
||||
* return -2 if friend not online.
|
||||
* return -3 if file number invalid.
|
||||
* return -4 if file control is bad.
|
||||
* return -5 if file already paused.
|
||||
* return -6 if resume file failed because it was only paused by the other.
|
||||
* return -7 if resume file failed because it wasn't paused.
|
||||
* return -8 if packet failed to send.
|
||||
*/
|
||||
int file_control(const Messenger *m, int32_t friendnumber, uint8_t send_receive, uint8_t filenumber, uint8_t message_id,
|
||||
const uint8_t *data, uint16_t length);
|
||||
int file_control(const Messenger *m, int32_t friendnumber, uint32_t filenumber, unsigned int control);
|
||||
|
||||
/* Send file data.
|
||||
*
|
||||
* return 1 on success
|
||||
* return 0 on failure
|
||||
* return 0 on success
|
||||
* return -1 if friend not valid.
|
||||
* return -2 if friend not online.
|
||||
* return -3 if filenumber invalid.
|
||||
* return -4 if file transfer not transferring.
|
||||
* return -5 if trying to send too much data.
|
||||
* return -6 if packet queue full.
|
||||
*/
|
||||
int file_data(const Messenger *m, int32_t friendnumber, uint8_t filenumber, const uint8_t *data, uint16_t length);
|
||||
int file_data(const Messenger *m, int32_t friendnumber, uint32_t filenumber, const uint8_t *data, uint16_t length);
|
||||
|
||||
/* Give the number of bytes left to be sent/received.
|
||||
*
|
||||
|
|
167
toxcore/tox.c
167
toxcore/tox.c
|
@ -811,6 +811,173 @@ void tox_callback_friend_action(Tox *tox, tox_friend_action_cb *function, void *
|
|||
m_callback_action(m, function, user_data);
|
||||
}
|
||||
|
||||
bool tox_hash(uint8_t *hash, const uint8_t *data, size_t length)
|
||||
{
|
||||
if (!hash || !data) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
crypto_hash_sha256(hash, data, length);
|
||||
return 1;
|
||||
}
|
||||
|
||||
bool tox_file_control(Tox *tox, uint32_t friend_number, uint32_t file_number, TOX_FILE_CONTROL control,
|
||||
TOX_ERR_FILE_CONTROL *error)
|
||||
{
|
||||
Messenger *m = tox;
|
||||
int ret = file_control(m, friend_number, file_number, control);
|
||||
|
||||
if (ret == 0) {
|
||||
SET_ERROR_PARAMETER(error, TOX_ERR_FILE_CONTROL_OK);
|
||||
return 1;
|
||||
}
|
||||
|
||||
switch (ret) {
|
||||
case -1:
|
||||
SET_ERROR_PARAMETER(error, TOX_ERR_FILE_CONTROL_FRIEND_NOT_FOUND);
|
||||
return 0;
|
||||
|
||||
case -2:
|
||||
SET_ERROR_PARAMETER(error, TOX_ERR_FILE_CONTROL_FRIEND_NOT_CONNECTED);
|
||||
return 0;
|
||||
|
||||
case -3:
|
||||
SET_ERROR_PARAMETER(error, TOX_ERR_FILE_CONTROL_NOT_FOUND);
|
||||
return 0;
|
||||
|
||||
case -4:
|
||||
/* can't happen */
|
||||
return 0;
|
||||
|
||||
case -5:
|
||||
SET_ERROR_PARAMETER(error, TOX_ERR_FILE_CONTROL_ALREADY_PAUSED);
|
||||
return 0;
|
||||
|
||||
case -6:
|
||||
SET_ERROR_PARAMETER(error, TOX_ERR_FILE_CONTROL_DENIED);
|
||||
return 0;
|
||||
|
||||
case -7:
|
||||
SET_ERROR_PARAMETER(error, TOX_ERR_FILE_CONTROL_NOT_PAUSED);
|
||||
return 0;
|
||||
|
||||
case -8:
|
||||
SET_ERROR_PARAMETER(error, TOX_ERR_FILE_CONTROL_SEND_FAILED);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* can't happen */
|
||||
return 0;
|
||||
}
|
||||
|
||||
void tox_callback_file_control(Tox *tox, tox_file_control_cb *function, void *user_data)
|
||||
{
|
||||
Messenger *m = tox;
|
||||
callback_file_control(m, function, user_data);
|
||||
}
|
||||
|
||||
uint32_t tox_file_send(Tox *tox, uint32_t friend_number, TOX_FILE_KIND kind, uint64_t file_size,
|
||||
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;
|
||||
}
|
||||
|
||||
Messenger *m = tox;
|
||||
long int file_num = new_filesender(m, friend_number, kind, file_size, filename, filename_length);
|
||||
|
||||
if (file_num >= 0) {
|
||||
SET_ERROR_PARAMETER(error, TOX_ERR_FILE_SEND_OK);
|
||||
return file_num;
|
||||
}
|
||||
|
||||
switch (file_num) {
|
||||
case -1:
|
||||
SET_ERROR_PARAMETER(error, TOX_ERR_FILE_SEND_FRIEND_NOT_FOUND);
|
||||
return UINT32_MAX;
|
||||
|
||||
case -2:
|
||||
SET_ERROR_PARAMETER(error, TOX_ERR_FILE_SEND_NAME_TOO_LONG);
|
||||
return UINT32_MAX;
|
||||
|
||||
case -3:
|
||||
SET_ERROR_PARAMETER(error, TOX_ERR_FILE_SEND_TOO_MANY);
|
||||
return UINT32_MAX;
|
||||
|
||||
case -4:
|
||||
SET_ERROR_PARAMETER(error, TOX_ERR_FILE_SEND_FRIEND_NOT_CONNECTED);
|
||||
return UINT32_MAX;
|
||||
}
|
||||
|
||||
/* can't happen */
|
||||
return UINT32_MAX;
|
||||
}
|
||||
|
||||
bool tox_file_send_chunk(Tox *tox, uint32_t friend_number, uint32_t file_number, const uint8_t *data, size_t length,
|
||||
TOX_ERR_FILE_SEND_CHUNK *error)
|
||||
{
|
||||
Messenger *m = tox;
|
||||
int ret = file_data(m, friend_number, file_number, data, length);
|
||||
|
||||
if (ret == 0) {
|
||||
SET_ERROR_PARAMETER(error, TOX_ERR_FILE_SEND_CHUNK_OK);
|
||||
return 1;
|
||||
}
|
||||
|
||||
switch (ret) {
|
||||
case -1:
|
||||
SET_ERROR_PARAMETER(error, TOX_ERR_FILE_SEND_CHUNK_FRIEND_NOT_FOUND);
|
||||
return 0;
|
||||
|
||||
case -2:
|
||||
SET_ERROR_PARAMETER(error, TOX_ERR_FILE_SEND_CHUNK_FRIEND_NOT_CONNECTED);
|
||||
return 0;
|
||||
|
||||
case -3:
|
||||
SET_ERROR_PARAMETER(error, TOX_ERR_FILE_SEND_CHUNK_NOT_FOUND);
|
||||
return 0;
|
||||
|
||||
case -4:
|
||||
SET_ERROR_PARAMETER(error, TOX_ERR_FILE_SEND_CHUNK_NOT_TRANSFERRING);
|
||||
return 0;
|
||||
|
||||
case -5:
|
||||
SET_ERROR_PARAMETER(error, TOX_ERR_FILE_SEND_CHUNK_TOO_LARGE);
|
||||
return 0;
|
||||
|
||||
case -6:
|
||||
SET_ERROR_PARAMETER(error, TOX_ERR_FILE_SEND_CHUNK_QUEUE_FULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* can't happen */
|
||||
return 0;
|
||||
}
|
||||
|
||||
void tox_callback_file_request_chunk(Tox *tox, tox_file_request_chunk_cb *function, void *user_data)
|
||||
{
|
||||
Messenger *m = tox;
|
||||
callback_file_reqchunk(m, function, user_data);
|
||||
}
|
||||
|
||||
void tox_callback_file_receive(Tox *tox, tox_file_receive_cb *function, void *user_data)
|
||||
{
|
||||
Messenger *m = tox;
|
||||
callback_file_sendrequest(m, function, user_data);
|
||||
}
|
||||
|
||||
void tox_callback_file_receive_chunk(Tox *tox, tox_file_receive_chunk_cb *function, void *user_data)
|
||||
{
|
||||
Messenger *m = tox;
|
||||
callback_file_data(m, function, user_data);
|
||||
}
|
||||
|
||||
static void set_custom_packet_error(int ret, TOX_ERR_SEND_CUSTOM_PACKET *error)
|
||||
{
|
||||
switch (ret) {
|
||||
|
|
|
@ -1485,7 +1485,11 @@ typedef enum TOX_ERR_FILE_CONTROL {
|
|||
/**
|
||||
* A PAUSE control was sent, but the file transfer was already paused.
|
||||
*/
|
||||
TOX_ERR_FILE_CONTROL_ALREADY_PAUSED
|
||||
TOX_ERR_FILE_CONTROL_ALREADY_PAUSED,
|
||||
/**
|
||||
* Packet failed to send.
|
||||
*/
|
||||
TOX_ERR_FILE_CONTROL_SEND_FAILED
|
||||
} TOX_ERR_FILE_CONTROL;
|
||||
|
||||
/**
|
||||
|
@ -1612,6 +1616,7 @@ typedef enum TOX_ERR_FILE_SEND {
|
|||
*
|
||||
* @return A file number used as an identifier in subsequent callbacks. This
|
||||
* 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, TOX_FILE_KIND kind, uint64_t file_size,
|
||||
const uint8_t *filename, size_t filename_length, TOX_ERR_FILE_SEND *error);
|
||||
|
@ -1635,12 +1640,21 @@ typedef enum TOX_ERR_FILE_SEND_CHUNK {
|
|||
* No file transfer with the given file number was found for the given friend.
|
||||
*/
|
||||
TOX_ERR_FILE_SEND_CHUNK_NOT_FOUND,
|
||||
/**
|
||||
* File transfer was found but isn't in a transferring state: (paused, done,
|
||||
* broken, etc...) (happens only when not called from the request chunk callback).
|
||||
*/
|
||||
TOX_ERR_FILE_SEND_CHUNK_NOT_TRANSFERRING,
|
||||
/**
|
||||
* Attempted to send more data than requested. The requested data size is
|
||||
* adjusted according to maximum transmission unit and the expected end of
|
||||
* the file. Trying to send more will result in no data being sent.
|
||||
*/
|
||||
TOX_ERR_FILE_SEND_CHUNK_TOO_LARGE
|
||||
TOX_ERR_FILE_SEND_CHUNK_TOO_LARGE,
|
||||
/**
|
||||
* Packet queue is full.
|
||||
*/
|
||||
TOX_ERR_FILE_SEND_CHUNK_QUEUE_FULL
|
||||
} TOX_ERR_FILE_SEND_CHUNK;
|
||||
|
||||
/**
|
||||
|
|
Loading…
Reference in New Issue
Block a user