summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorirungentoo <irungentoo@gmail.com>2015-03-10 17:31:50 -0400
committerirungentoo <irungentoo@gmail.com>2015-03-10 17:31:50 -0400
commit0207fcdfb0e43d425abb026b08c074a6822e0349 (patch)
tree2cb06c6c8dd13b4230be005282adf7fb44ad0915
parentf5eca31637cbcbdd44f3fefc9139aa8ef0d1bd5e (diff)
Implementation of new api file transfers.
Everything should work except resuming.
-rw-r--r--auto_tests/tox_test.c135
-rw-r--r--toxcore/Messenger.c466
-rw-r--r--toxcore/Messenger.h74
-rw-r--r--toxcore/tox.c167
-rw-r--r--toxcore/tox.h18
5 files changed, 627 insertions, 233 deletions
diff --git a/auto_tests/tox_test.c b/auto_tests/tox_test.c
index d7a44fb2..077e51fb 100644
--- a/auto_tests/tox_test.c
+++ b/auto_tests/tox_test.c
@@ -21,6 +21,7 @@
21#define c_sleep(x) usleep(1000*x) 21#define c_sleep(x) usleep(1000*x)
22#endif 22#endif
23 23
24
24void accept_friend_request(Tox *m, const uint8_t *public_key, const uint8_t *data, size_t length, void *userdata) 25void accept_friend_request(Tox *m, const uint8_t *public_key, const uint8_t *data, size_t length, void *userdata)
25{ 26{
26 if (*((uint32_t *)userdata) != 974536) 27 if (*((uint32_t *)userdata) != 974536)
@@ -83,7 +84,7 @@ void handle_custom_packet(Tox *m, uint32_t friend_num, const uint8_t *data, size
83 if (memcmp(f_data, data, len) == 0) { 84 if (memcmp(f_data, data, len) == 0) {
84 ++custom_packet; 85 ++custom_packet;
85 } else { 86 } else {
86 printf("Custom packet fail. %u\n", number ); 87 ck_abort_msg("Custom packet fail. %u", number);
87 } 88 }
88 89
89 return; 90 return;
@@ -92,44 +93,103 @@ void handle_custom_packet(Tox *m, uint32_t friend_num, const uint8_t *data, size
92uint8_t filenum; 93uint8_t filenum;
93uint32_t file_accepted; 94uint32_t file_accepted;
94uint64_t file_size; 95uint64_t file_size;
95void file_request_accept(Tox *m, int friendnumber, uint8_t filenumber, uint64_t filesize, const uint8_t *filename, 96void tox_file_receive(Tox *tox, uint32_t friend_number, uint32_t file_number, TOX_FILE_KIND kind, uint64_t filesize,
96 uint16_t filename_length, void *userdata) 97 const uint8_t *filename, size_t filename_length, void *userdata)
97{ 98{
98 if (*((uint32_t *)userdata) != 974536) 99 if (*((uint32_t *)userdata) != 974536)
99 return; 100 return;
100 101
101 if (filename_length == sizeof("Gentoo.exe") && memcmp(filename, "Gentoo.exe", sizeof("Gentoo.exe")) == 0) 102 if (kind != TOX_FILE_KIND_DATA) {
102 ++file_accepted; 103 ck_abort_msg("Bad kind");
104 return;
105 }
106
107 if (!(filename_length == sizeof("Gentoo.exe") && memcmp(filename, "Gentoo.exe", sizeof("Gentoo.exe")) == 0)) {
108 ck_abort_msg("Bad filename");
109 return;
110 }
103 111
104 file_size = filesize; 112 file_size = filesize;
105 tox_file_send_control(m, friendnumber, 1, filenumber, TOX_FILECONTROL_ACCEPT, NULL, 0); 113
114 TOX_ERR_FILE_CONTROL error;
115
116 if (tox_file_control(tox, friend_number, file_number, TOX_FILE_CONTROL_RESUME, &error)) {
117 ++file_accepted;
118 } else {
119 ck_abort_msg("tox_file_control failed. %i", error);
120 }
106} 121}
107 122
108uint32_t file_sent;
109uint32_t sendf_ok; 123uint32_t sendf_ok;
110void file_print_control(Tox *m, int friendnumber, uint8_t receive_send, uint8_t filenumber, uint8_t control_type, 124void file_print_control(Tox *tox, uint32_t friend_number, uint32_t file_number, TOX_FILE_CONTROL control,
111 const uint8_t *data, uint16_t length, void *userdata) 125 void *userdata)
112{ 126{
113 if (*((uint32_t *)userdata) != 974536) 127 if (*((uint32_t *)userdata) != 974536)
114 return; 128 return;
115 129
116 if (receive_send == 0 && control_type == TOX_FILECONTROL_FINISHED) 130 /* First send file num is 0.*/
117 tox_file_send_control(m, friendnumber, 1, filenumber, TOX_FILECONTROL_FINISHED, NULL, 0); 131 if (file_number == 0 && control == TOX_FILE_CONTROL_RESUME)
132 sendf_ok = 1;
133}
118 134
119 if (receive_send == 1 && control_type == TOX_FILECONTROL_FINISHED) 135uint8_t sending_num;
120 file_sent = 1; 136uint64_t sending_pos;
137_Bool file_sending_done;
138void tox_file_request_chunk(Tox *tox, uint32_t friend_number, uint32_t file_number, uint64_t position, size_t length,
139 void *user_data)
140{
141 if (*((uint32_t *)user_data) != 974536)
142 return;
121 143
122 if (receive_send == 1 && control_type == TOX_FILECONTROL_ACCEPT) 144 if (!sendf_ok) {
123 sendf_ok = 1; 145 ck_abort_msg("Didn't get resume control");
146 }
124 147
148 if (sending_pos != position) {
149 ck_abort_msg("Bad position");
150 return;
151 }
152
153 if (length == 0) {
154 file_sending_done = 1;
155 return;
156 }
157
158 TOX_ERR_FILE_SEND_CHUNK error;
159 uint8_t f_data[length];
160 memset(f_data, sending_num, length);
161
162 if (tox_file_send_chunk(tox, friend_number, file_number, f_data, length, &error)) {
163 ++sending_num;
164 sending_pos += length;
165 } else {
166 ck_abort_msg("Could not send chunk %i", error);
167 }
168
169 if (error != TOX_ERR_FILE_SEND_CHUNK_OK) {
170 ck_abort_msg("Wrong error code");
171 }
125} 172}
126 173
174
127uint64_t size_recv; 175uint64_t size_recv;
128uint8_t num; 176uint8_t num;
129void write_file(Tox *m, int friendnumber, uint8_t filenumber, const uint8_t *data, uint16_t length, void *userdata) 177_Bool file_recv;
178void write_file(Tox *tox, uint32_t friendnumber, uint32_t filenumber, uint64_t position, const uint8_t *data,
179 size_t length, void *user_data)
130{ 180{
131 if (*((uint32_t *)userdata) != 974536) 181 if (*((uint32_t *)user_data) != 974536)
182 return;
183
184 if (size_recv != position) {
185 ck_abort_msg("Bad position");
132 return; 186 return;
187 }
188
189 if (length == 0) {
190 file_recv = 1;
191 return;
192 }
133 193
134 uint8_t f_data[length]; 194 uint8_t f_data[length];
135 memset(f_data, num, length); 195 memset(f_data, num, length);
@@ -138,7 +198,7 @@ void write_file(Tox *m, int friendnumber, uint8_t filenumber, const uint8_t *dat
138 if (memcmp(f_data, data, length) == 0) { 198 if (memcmp(f_data, data, length) == 0) {
139 size_recv += length; 199 size_recv += length;
140 } else { 200 } else {
141 printf("FILE_CORRUPTED\n"); 201 ck_abort_msg("FILE_CORRUPTED");
142 } 202 }
143} 203}
144 204
@@ -371,41 +431,32 @@ START_TEST(test_few_clients)
371 c_sleep(50); 431 c_sleep(50);
372 } 432 }
373 433
374 filenum = file_accepted = file_size = file_sent = sendf_ok = size_recv = 0; 434 file_accepted = file_size = file_recv = sendf_ok = size_recv = 0;
375 long long unsigned int f_time = time(NULL); 435 long long unsigned int f_time = time(NULL);
376 tox_callback_file_data(tox3, write_file, &to_compare); 436 tox_callback_file_receive_chunk(tox3, write_file, &to_compare);
377 tox_callback_file_control(tox2, file_print_control, &to_compare); 437 tox_callback_file_control(tox2, file_print_control, &to_compare);
438 tox_callback_file_request_chunk(tox2, tox_file_request_chunk, &to_compare);
378 tox_callback_file_control(tox3, file_print_control, &to_compare); 439 tox_callback_file_control(tox3, file_print_control, &to_compare);
379 tox_callback_file_send_request(tox3, file_request_accept, &to_compare); 440 tox_callback_file_receive(tox3, tox_file_receive, &to_compare);
380 uint64_t totalf_size = 100 * 1024 * 1024; 441 uint64_t totalf_size = 100 * 1024 * 1024;
381 int fnum = tox_new_file_sender(tox2, 0, totalf_size, (uint8_t *)"Gentoo.exe", sizeof("Gentoo.exe")); 442 uint32_t fnum = tox_file_send(tox2, 0, TOX_FILE_KIND_DATA, totalf_size, (uint8_t *)"Gentoo.exe", sizeof("Gentoo.exe"),
382 ck_assert_msg(fnum != -1, "tox_new_file_sender fail"); 443 0);
383 int fpiece_size = tox_file_data_size(tox2, 0); 444 ck_assert_msg(fnum != UINT32_MAX, "tox_new_file_sender fail");
384 uint8_t f_data[fpiece_size]; 445
385 uint8_t num = 0;
386 memset(f_data, num, fpiece_size);
387 446
388 while (1) { 447 while (1) {
389 file_sent = 0;
390 tox_iteration(tox1); 448 tox_iteration(tox1);
391 tox_iteration(tox2); 449 tox_iteration(tox2);
392 tox_iteration(tox3); 450 tox_iteration(tox3);
393 451
394 if (sendf_ok) 452 if (file_sending_done) {
395 while (tox_file_send_data(tox2, 0, fnum, f_data, fpiece_size < totalf_size ? fpiece_size : totalf_size) == 0) { 453 if (sendf_ok && file_recv && totalf_size == file_size && size_recv == file_size && sending_pos == size_recv) {
396 if (totalf_size <= fpiece_size) { 454 break;
397 sendf_ok = 0; 455 } else {
398 tox_file_send_control(tox2, 0, 0, fnum, TOX_FILECONTROL_FINISHED, NULL, 0); 456 ck_abort_msg("Something went wrong in file transfer %u %u %u %u %u", sendf_ok, file_recv, totalf_size == file_size,
399 } 457 size_recv == file_size, sending_pos == size_recv);
400
401 ++num;
402 memset(f_data, num, fpiece_size);
403
404 totalf_size -= fpiece_size;
405 } 458 }
406 459 }
407 if (file_sent && size_recv == file_size)
408 break;
409 460
410 uint32_t tox1_interval = tox_iteration_interval(tox1); 461 uint32_t tox1_interval = tox_iteration_interval(tox1);
411 uint32_t tox2_interval = tox_iteration_interval(tox2); 462 uint32_t tox2_interval = tox_iteration_interval(tox2);
diff --git a/toxcore/Messenger.c b/toxcore/Messenger.c
index ee76b103..08b62660 100644
--- a/toxcore/Messenger.c
+++ b/toxcore/Messenger.c
@@ -349,6 +349,18 @@ static int add_receipt(Messenger *m, int32_t friendnumber, uint32_t packet_num,
349 new->next = NULL; 349 new->next = NULL;
350 return 0; 350 return 0;
351} 351}
352/*
353 * return -1 on failure.
354 * return 0 if packet was received.
355 */
356static int friend_received_packet(const Messenger *m, int32_t friendnumber, uint32_t number)
357{
358 if (friend_not_valid(m, friendnumber))
359 return -1;
360
361 return cryptpacket_received(m->net_crypto, friend_connection_crypt_connection_id(m->fr_c,
362 m->friendlist[friendnumber].friendcon_id), number);
363}
352 364
353static int do_receipts(Messenger *m, int32_t friendnumber) 365static int do_receipts(Messenger *m, int32_t friendnumber)
354{ 366{
@@ -360,8 +372,7 @@ static int do_receipts(Messenger *m, int32_t friendnumber)
360 while (receipts) { 372 while (receipts) {
361 struct Receipts *temp_r = receipts->next; 373 struct Receipts *temp_r = receipts->next;
362 374
363 if (cryptpacket_received(m->net_crypto, friend_connection_crypt_connection_id(m->fr_c, 375 if (friend_received_packet(m, friendnumber, receipts->packet_num) == -1)
364 m->friendlist[friendnumber].friendcon_id), receipts->packet_num) == -1)
365 break; 376 break;
366 377
367 if (m->read_receipt) 378 if (m->read_receipt)
@@ -970,11 +981,11 @@ void callback_file_sendrequest(Messenger *m, void (*function)(Messenger *m, uin
970 981
971/* Set the callback for file control requests. 982/* Set the callback for file control requests.
972 * 983 *
973 * 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) 984 * Function(Tox *tox, uint32_t friendnumber, uint32_t filenumber, unsigned int control_type, void *userdata)
974 * 985 *
975 */ 986 */
976void callback_file_control(Messenger *m, void (*function)(Messenger *m, uint32_t, uint8_t, uint8_t, uint8_t, 987void callback_file_control(Messenger *m, void (*function)(Messenger *m, uint32_t, uint32_t, unsigned int, void *),
977 const uint8_t *, uint16_t, void *), void *userdata) 988 void *userdata)
978{ 989{
979 m->file_filecontrol = function; 990 m->file_filecontrol = function;
980 m->file_filecontrol_userdata = userdata; 991 m->file_filecontrol_userdata = userdata;
@@ -982,17 +993,28 @@ void callback_file_control(Messenger *m, void (*function)(Messenger *m, uint32_t
982 993
983/* Set the callback for file data. 994/* Set the callback for file data.
984 * 995 *
985 * Function(Tox *tox, uint32_t friendnumber, uint8_t filenumber, uint8_t *data, uint16_t length, void *userdata) 996 * Function(Tox *tox, uint32_t friendnumber, uint32_t filenumber, uint64_t position, uint8_t *data, size_t length, void *userdata)
986 * 997 *
987 */ 998 */
988void callback_file_data(Messenger *m, void (*function)(Messenger *m, uint32_t, uint8_t, const uint8_t *, 999void callback_file_data(Messenger *m, void (*function)(Messenger *m, uint32_t, uint32_t, uint64_t, const uint8_t *,
989 uint16_t length, 1000 size_t, void *), void *userdata)
990 void *), void *userdata)
991{ 1001{
992 m->file_filedata = function; 1002 m->file_filedata = function;
993 m->file_filedata_userdata = userdata; 1003 m->file_filedata_userdata = userdata;
994} 1004}
995 1005
1006/* Set the callback for file request chunk.
1007 *
1008 * Function(Tox *tox, uint32_t friendnumber, uint32_t filenumber, uint64_t position, size_t length, void *userdata)
1009 *
1010 */
1011void callback_file_reqchunk(Messenger *m, void (*function)(Messenger *m, uint32_t, uint32_t, uint64_t, size_t, void *),
1012 void *userdata)
1013{
1014 m->file_reqchunk = function;
1015 m->file_reqchunk_userdata = userdata;
1016}
1017
996#define MAX_FILENAME_LENGTH 255 1018#define MAX_FILENAME_LENGTH 255
997 1019
998/* Send a file send request. 1020/* Send a file send request.
@@ -1053,132 +1075,182 @@ long int new_filesender(const Messenger *m, int32_t friendnumber, uint32_t file_
1053 m->friendlist[friendnumber].file_sending[i].status = FILESTATUS_NOT_ACCEPTED; 1075 m->friendlist[friendnumber].file_sending[i].status = FILESTATUS_NOT_ACCEPTED;
1054 m->friendlist[friendnumber].file_sending[i].size = filesize; 1076 m->friendlist[friendnumber].file_sending[i].size = filesize;
1055 m->friendlist[friendnumber].file_sending[i].transferred = 0; 1077 m->friendlist[friendnumber].file_sending[i].transferred = 0;
1056 m->friendlist[friendnumber].file_sending[i].type = file_type; 1078 m->friendlist[friendnumber].file_sending[i].paused = FILE_PAUSE_NOT;
1079 ++m->friendlist[friendnumber].num_sending_files;
1080
1057 return i; 1081 return i;
1058} 1082}
1059 1083
1084int send_file_control_packet(const Messenger *m, int32_t friendnumber, uint8_t send_receive, uint8_t filenumber,
1085 uint8_t control_type, uint8_t *data, uint16_t data_length)
1086{
1087 if (1 + 3 + data_length > MAX_CRYPTO_DATA_SIZE)
1088 return -1;
1089
1090 uint8_t packet[3 + data_length];
1091
1092 packet[0] = send_receive;
1093 packet[1] = filenumber;
1094 packet[2] = control_type;
1095
1096 if (data_length) {
1097 memcpy(packet, packet + 3, data_length);
1098 }
1099
1100 return write_cryptpacket_id(m, friendnumber, PACKET_ID_FILE_CONTROL, packet, sizeof(packet), 0);
1101}
1102
1060/* Send a file control request. 1103/* Send a file control request.
1061 * send_receive is 0 if we want the control packet to target a sending file, 1 if it targets a receiving file.
1062 * 1104 *
1063 * return 0 on success 1105 * return 0 on success
1064 * return -1 on failure 1106 * return -1 if friend not valid.
1107 * return -2 if friend not online.
1108 * return -3 if file number invalid.
1109 * return -4 if file control is bad.
1110 * return -5 if file already paused.
1111 * return -6 if resume file failed because it was only paused by the other.
1112 * return -7 if resume file failed because it wasn't paused.
1113 * return -8 if packet failed to send.
1065 */ 1114 */
1066int file_control(const Messenger *m, int32_t friendnumber, uint8_t send_receive, uint8_t filenumber, uint8_t message_id, 1115int file_control(const Messenger *m, int32_t friendnumber, uint32_t filenumber, unsigned int control)
1067 const uint8_t *data, uint16_t length)
1068{ 1116{
1069 if (length > MAX_CRYPTO_DATA_SIZE - 3)
1070 return -1;
1071
1072 if (friend_not_valid(m, friendnumber)) 1117 if (friend_not_valid(m, friendnumber))
1073 return -1; 1118 return -1;
1074 1119
1075 if (send_receive == 1) { 1120 if (m->friendlist[friendnumber].status != FRIEND_ONLINE)
1076 if (m->friendlist[friendnumber].file_receiving[filenumber].status == FILESTATUS_NONE) 1121 return -2;
1077 return -1; 1122
1123 uint32_t temp_filenum;
1124 uint8_t send_receive, file_number;
1125
1126 if (filenumber >= (1 << 16)) {
1127 send_receive = 1;
1128 temp_filenum = (filenumber >> 16) - 1;
1078 } else { 1129 } else {
1079 if (m->friendlist[friendnumber].file_sending[filenumber].status == FILESTATUS_NONE) 1130 send_receive = 0;
1080 return -1; 1131 temp_filenum = filenumber;
1081 } 1132 }
1082 1133
1083 if (send_receive > 1) 1134 if (temp_filenum >= MAX_CONCURRENT_FILE_PIPES)
1084 return -1; 1135 return -3;
1085 1136
1086 uint8_t packet[MAX_CRYPTO_DATA_SIZE]; 1137 file_number = temp_filenum;
1087 packet[0] = send_receive;
1088 packet[1] = filenumber;
1089 packet[2] = message_id;
1090 uint64_t transferred = 0;
1091 1138
1092 if (message_id == FILECONTROL_RESUME_BROKEN) { 1139 struct File_Transfers *ft;
1093 if (length != sizeof(uint64_t))
1094 return -1;
1095 1140
1096 uint8_t remaining[sizeof(uint64_t)]; 1141 if (send_receive) {
1097 memcpy(remaining, data, sizeof(uint64_t)); 1142 ft = &m->friendlist[friendnumber].file_receiving[file_number];
1098 host_to_net(remaining, sizeof(uint64_t));
1099 memcpy(packet + 3, remaining, sizeof(uint64_t));
1100 memcpy(&transferred, data, sizeof(uint64_t));
1101 } else { 1143 } else {
1102 memcpy(packet + 3, data, length); 1144 ft = &m->friendlist[friendnumber].file_sending[file_number];
1103 } 1145 }
1104 1146
1105 if (write_cryptpacket_id(m, friendnumber, PACKET_ID_FILE_CONTROL, packet, length + 3, 0)) { 1147 if (ft->status == FILESTATUS_NONE)
1106 if (send_receive == 1) 1148 return -3;
1107 switch (message_id) {
1108 case FILECONTROL_ACCEPT:
1109 m->friendlist[friendnumber].file_receiving[filenumber].status = FILESTATUS_TRANSFERRING;
1110 break;
1111 1149
1112 case FILECONTROL_PAUSE: 1150 if (control > FILECONTROL_KILL)
1113 m->friendlist[friendnumber].file_receiving[filenumber].status = FILESTATUS_PAUSED_BY_US; 1151 return -4;
1114 break;
1115 1152
1116 case FILECONTROL_KILL: 1153 if (control == FILECONTROL_PAUSE && (ft->paused & FILE_PAUSE_US))
1117 case FILECONTROL_FINISHED: 1154 return -5;
1118 m->friendlist[friendnumber].file_receiving[filenumber].status = FILESTATUS_NONE;
1119 break;
1120 1155
1121 case FILECONTROL_RESUME_BROKEN: 1156 if (control == FILECONTROL_ACCEPT && ft->status == FILESTATUS_TRANSFERRING) {
1122 m->friendlist[friendnumber].file_receiving[filenumber].status = FILESTATUS_PAUSED_BY_OTHER; 1157 if (!(ft->paused & FILE_PAUSE_US)) {
1123 m->friendlist[friendnumber].file_receiving[filenumber].transferred = transferred; 1158 if (ft->paused & FILE_PAUSE_OTHER) {
1124 break; 1159 return -6;
1160 } else {
1161 return -7;
1125 } 1162 }
1126 else 1163 }
1127 switch (message_id) { 1164 }
1128 case FILECONTROL_ACCEPT:
1129 m->friendlist[friendnumber].file_sending[filenumber].status = FILESTATUS_TRANSFERRING;
1130 break;
1131
1132 case FILECONTROL_PAUSE:
1133 m->friendlist[friendnumber].file_sending[filenumber].status = FILESTATUS_PAUSED_BY_US;
1134 break;
1135 1165
1136 case FILECONTROL_KILL: 1166 if (send_file_control_packet(m, friendnumber, send_receive, file_number, control, 0, 0)) {
1137 m->friendlist[friendnumber].file_sending[filenumber].status = FILESTATUS_NONE; 1167 if (control == FILECONTROL_KILL) {
1138 break; 1168 ft->status = FILESTATUS_NONE;
1139 1169
1140 case FILECONTROL_FINISHED: 1170 if (send_receive == 0) {
1141 break; 1171 --m->friendlist[friendnumber].num_sending_files;
1142 } 1172 }
1173 } else if (control == FILECONTROL_PAUSE) {
1174 ft->paused |= FILE_PAUSE_US;
1175 } else if (control == FILECONTROL_ACCEPT) {
1176 ft->status = FILESTATUS_TRANSFERRING;
1143 1177
1144 return 0; 1178 if (ft->paused & FILE_PAUSE_US) {
1179 ft->paused ^= FILE_PAUSE_US;
1180 }
1181 }
1145 } else { 1182 } else {
1146 return -1; 1183 return -8;
1147 } 1184 }
1185
1186 return 0;
1148} 1187}
1149 1188
1150#define MIN_SLOTS_FREE (CRYPTO_MIN_QUEUE_LENGTH / 2) 1189#define MIN_SLOTS_FREE (CRYPTO_MIN_QUEUE_LENGTH / 2)
1151/* Send file data. 1190/* Send file data.
1152 * 1191 *
1153 * return 0 on success 1192 * return 0 on success
1154 * return -1 on failure 1193 * return -1 if friend not valid.
1194 * return -2 if friend not online.
1195 * return -3 if filenumber invalid.
1196 * return -4 if file transfer not transferring.
1197 * return -5 if trying to send too much data.
1198 * return -6 if packet queue full.
1155 */ 1199 */
1156int file_data(const Messenger *m, int32_t friendnumber, uint8_t filenumber, const uint8_t *data, uint16_t length) 1200int file_data(const Messenger *m, int32_t friendnumber, uint32_t filenumber, const uint8_t *data, uint16_t length)
1157{ 1201{
1158 if (length > MAX_CRYPTO_DATA_SIZE - 1)
1159 return -1;
1160
1161 if (friend_not_valid(m, friendnumber)) 1202 if (friend_not_valid(m, friendnumber))
1162 return -1; 1203 return -1;
1163 1204
1164 if (m->friendlist[friendnumber].file_sending[filenumber].status != FILESTATUS_TRANSFERRING) 1205 if (m->friendlist[friendnumber].status != FRIEND_ONLINE)
1165 return -1; 1206 return -2;
1207
1208 if (filenumber > MAX_CONCURRENT_FILE_PIPES)
1209 return -3;
1210
1211 struct File_Transfers *ft = &m->friendlist[friendnumber].file_sending[filenumber];
1212
1213 if (ft->status != FILESTATUS_TRANSFERRING)
1214 return -4;
1215
1216 if (ft->paused != FILE_PAUSE_NOT)
1217 return -4;
1218
1219 if (length > MAX_CRYPTO_DATA_SIZE - 2)
1220 return -5;
1221
1222 if (ft->size) {
1223 if (ft->size - ft->transferred < length) {
1224 return -5;
1225 }
1226 }
1166 1227
1167 /* Prevent file sending from filling up the entire buffer preventing messages from being sent. TODO: remove */ 1228 /* Prevent file sending from filling up the entire buffer preventing messages from being sent. TODO: remove */
1168 if (crypto_num_free_sendqueue_slots(m->net_crypto, friend_connection_crypt_connection_id(m->fr_c, 1229 if (crypto_num_free_sendqueue_slots(m->net_crypto, friend_connection_crypt_connection_id(m->fr_c,
1169 m->friendlist[friendnumber].friendcon_id)) < MIN_SLOTS_FREE) 1230 m->friendlist[friendnumber].friendcon_id)) < MIN_SLOTS_FREE)
1170 return -1; 1231 return -6;
1171 1232
1172 uint8_t packet[MAX_CRYPTO_DATA_SIZE]; 1233 uint8_t packet[2 + length];
1173 packet[0] = filenumber; 1234 packet[0] = PACKET_ID_FILE_DATA;
1174 memcpy(packet + 1, data, length); 1235 packet[1] = filenumber;
1236 memcpy(packet + 2, data, length);
1237
1238 int64_t ret = write_cryptpacket(m->net_crypto, friend_connection_crypt_connection_id(m->fr_c,
1239 m->friendlist[friendnumber].friendcon_id), packet, sizeof(packet), 1);
1240
1241 if (ret != -1) {
1242 //TODO record packet ids to check if other received complete file.
1243 ft->transferred += length;
1244
1245 if (length == 0 || ft->size == ft->transferred) {
1246 ft->status = FILESTATUS_FINISHED;
1247 ft->last_packet_number = ret;
1248 }
1175 1249
1176 if (write_cryptpacket_id(m, friendnumber, PACKET_ID_FILE_DATA, packet, length + 1, 1)) {
1177 m->friendlist[friendnumber].file_sending[filenumber].transferred += length;
1178 return 0; 1250 return 0;
1179 } 1251 }
1180 1252
1181 return -1; 1253 return -6;
1182 1254
1183} 1255}
1184 1256
@@ -1209,105 +1281,142 @@ uint64_t file_dataremaining(const Messenger *m, int32_t friendnumber, uint8_t fi
1209 } 1281 }
1210} 1282}
1211 1283
1284static void do_reqchunk_filecb(Messenger *m, int32_t friendnumber)
1285{
1286 if (!m->friendlist[friendnumber].num_sending_files)
1287 return;
1288
1289 int free_slots = crypto_num_free_sendqueue_slots(m->net_crypto, friend_connection_crypt_connection_id(m->fr_c,
1290 m->friendlist[friendnumber].friendcon_id));
1291
1292 if (free_slots <= MIN_SLOTS_FREE)
1293 return;
1294
1295 free_slots -= MIN_SLOTS_FREE;
1296
1297 unsigned int i, num = m->friendlist[friendnumber].num_sending_files;
1298
1299 for (i = 0; i < MAX_CONCURRENT_FILE_PIPES; ++i) {
1300 struct File_Transfers *ft = &m->friendlist[friendnumber].file_sending[i];
1301
1302 if (ft->status != FILESTATUS_NONE) {
1303 --num;
1304
1305 if (ft->status == FILESTATUS_FINISHED) {
1306 /* Check if file was entirely sent. */
1307 if (friend_received_packet(m, friendnumber, ft->last_packet_number) == 0) {
1308 if (m->file_reqchunk)
1309 (*m->file_reqchunk)(m, friendnumber, i, ft->transferred, 0, m->file_reqchunk_userdata);
1310
1311 ft->status = FILESTATUS_NONE;
1312 --m->friendlist[friendnumber].num_sending_files;
1313 }
1314 }
1315 }
1316
1317 while (ft->status == FILESTATUS_TRANSFERRING && (ft->paused == FILE_PAUSE_NOT)) {
1318 if (free_slots == 0)
1319 break;
1320
1321 uint16_t length = MAX_CRYPTO_DATA_SIZE - 2;
1322
1323 if (ft->size) {
1324 if (ft->size == ft->transferred) {
1325 break;
1326 }
1327
1328 if (ft->size - ft->transferred < length) {
1329 length = ft->size - ft->transferred;
1330 }
1331 }
1332
1333 if (m->file_reqchunk)
1334 (*m->file_reqchunk)(m, friendnumber, i, ft->transferred, length, m->file_reqchunk_userdata);
1335
1336 --free_slots;
1337 }
1338
1339 if (num == 0)
1340 break;
1341 }
1342}
1343
1212/* Run this when the friend disconnects. 1344/* Run this when the friend disconnects.
1213 * Sets all current file transfers to broken. 1345 * Sets all current file transfers to broken.
1214 */ 1346 */
1215static void break_files(const Messenger *m, int32_t friendnumber) 1347static void break_files(const Messenger *m, int32_t friendnumber)
1216{ 1348{
1217 uint32_t i; 1349 uint32_t i;
1350 /* TODO
1351 for (i = 0; i < MAX_CONCURRENT_FILE_PIPES; ++i) {
1352 if (m->friendlist[friendnumber].file_sending[i].status != FILESTATUS_NONE)
1353 m->friendlist[friendnumber].file_sending[i].status = FILESTATUS_BROKEN;
1218 1354
1219 for (i = 0; i < MAX_CONCURRENT_FILE_PIPES; ++i) { 1355 if (m->friendlist[friendnumber].file_receiving[i].status != FILESTATUS_NONE)
1220 if (m->friendlist[friendnumber].file_sending[i].status != FILESTATUS_NONE) 1356 m->friendlist[friendnumber].file_receiving[i].status = FILESTATUS_BROKEN;
1221 m->friendlist[friendnumber].file_sending[i].status = FILESTATUS_BROKEN; 1357 }*/
1222
1223 if (m->friendlist[friendnumber].file_receiving[i].status != FILESTATUS_NONE)
1224 m->friendlist[friendnumber].file_receiving[i].status = FILESTATUS_BROKEN;
1225 }
1226} 1358}
1227 1359
1228static int handle_filecontrol(const Messenger *m, int32_t friendnumber, uint8_t receive_send, uint8_t filenumber, 1360/* return -1 on failure, 0 on success.
1229 uint8_t message_id, uint8_t *data, 1361 */
1230 uint16_t length) 1362static int handle_filecontrol(Messenger *m, int32_t friendnumber, uint8_t receive_send, uint8_t filenumber,
1363 uint8_t control_type, uint8_t *data, uint16_t length)
1231{ 1364{
1232 if (receive_send > 1) 1365 if (receive_send > 1)
1233 return -1; 1366 return -1;
1234 1367
1235 if (receive_send == 0) { 1368 if (control_type > FILECONTROL_RESUME_BROKEN)
1236 if (m->friendlist[friendnumber].file_receiving[filenumber].status == FILESTATUS_NONE) { 1369 return -1;
1237 /* Tell the other to kill the file sending if we don't know this one. */
1238 m->friendlist[friendnumber].file_receiving[filenumber].status = FILESTATUS_TEMPORARY;
1239 file_control(m, friendnumber, !receive_send, filenumber, FILECONTROL_KILL, NULL, 0);
1240 m->friendlist[friendnumber].file_receiving[filenumber].status = FILESTATUS_NONE;
1241 return -1;
1242
1243 }
1244
1245 switch (message_id) {
1246 case FILECONTROL_ACCEPT:
1247 if (m->friendlist[friendnumber].file_receiving[filenumber].status != FILESTATUS_PAUSED_BY_US) {
1248 m->friendlist[friendnumber].file_receiving[filenumber].status = FILESTATUS_TRANSFERRING;
1249 return 0;
1250 }
1251 1370
1252 return -1; 1371 uint32_t real_filenumber = filenumber;
1372 struct File_Transfers *ft;
1253 1373
1254 case FILECONTROL_PAUSE: 1374 if (receive_send == 0) {
1255 if (m->friendlist[friendnumber].file_receiving[filenumber].status != FILESTATUS_PAUSED_BY_US) { 1375 real_filenumber += 1;
1256 m->friendlist[friendnumber].file_receiving[filenumber].status = FILESTATUS_PAUSED_BY_OTHER; 1376 real_filenumber <<= 16;
1257 return 0; 1377 ft = &m->friendlist[friendnumber].file_receiving[filenumber];
1258 } 1378 } else {
1379 ft = &m->friendlist[friendnumber].file_sending[filenumber];
1380 }
1259 1381
1260 return -1; 1382 if (ft->status == FILESTATUS_NONE) {
1383 /* File transfer doesn't exist, tell the other to kill it. */
1384 send_file_control_packet(m, friendnumber, !receive_send, filenumber, FILECONTROL_KILL, 0, 0);
1385 return -1;
1386 }
1261 1387
1262 case FILECONTROL_KILL: 1388 if (control_type == FILECONTROL_ACCEPT) {
1263 m->friendlist[friendnumber].file_receiving[filenumber].status = FILESTATUS_NONE; 1389 ft->status = FILESTATUS_TRANSFERRING;
1264 1390
1265 case FILECONTROL_FINISHED: 1391 if (ft->paused & FILE_PAUSE_OTHER) {
1266 return 0; 1392 ft->paused ^= FILE_PAUSE_OTHER;
1267 } 1393 }
1268 } else {
1269 if (m->friendlist[friendnumber].file_sending[filenumber].status == FILESTATUS_NONE) {
1270 /* Tell the other to kill the file sending if we don't know this one. */
1271 m->friendlist[friendnumber].file_sending[filenumber].status = FILESTATUS_TEMPORARY;
1272 file_control(m, friendnumber, !receive_send, filenumber, FILECONTROL_KILL, NULL, 0);
1273 m->friendlist[friendnumber].file_sending[filenumber].status = FILESTATUS_NONE;
1274 return -1;
1275 }
1276
1277 switch (message_id) {
1278 case FILECONTROL_ACCEPT:
1279 if (m->friendlist[friendnumber].file_sending[filenumber].status != FILESTATUS_PAUSED_BY_US) {
1280 m->friendlist[friendnumber].file_sending[filenumber].status = FILESTATUS_TRANSFERRING;
1281 return 0;
1282 }
1283 1394
1284 return -1; 1395 if (m->file_filecontrol)
1396 (*m->file_filecontrol)(m, friendnumber, real_filenumber, control_type, m->file_filecontrol_userdata);
1397 } else if (control_type == FILECONTROL_PAUSE) {
1398 ft->paused |= FILE_PAUSE_OTHER;
1285 1399
1286 case FILECONTROL_PAUSE: 1400 if (m->file_filecontrol)
1287 if (m->friendlist[friendnumber].file_sending[filenumber].status != FILESTATUS_PAUSED_BY_US) { 1401 (*m->file_filecontrol)(m, friendnumber, real_filenumber, control_type, m->file_filecontrol_userdata);
1288 m->friendlist[friendnumber].file_sending[filenumber].status = FILESTATUS_PAUSED_BY_OTHER; 1402 } else if (control_type == FILECONTROL_KILL) {
1289 }
1290 1403
1291 return 0; 1404 if (m->file_filecontrol)
1405 (*m->file_filecontrol)(m, friendnumber, real_filenumber, control_type, m->file_filecontrol_userdata);
1292 1406
1293 case FILECONTROL_KILL: 1407 ft->status = FILESTATUS_NONE;
1294 case FILECONTROL_FINISHED:
1295 m->friendlist[friendnumber].file_sending[filenumber].status = FILESTATUS_NONE;
1296 return 0;
1297
1298 case FILECONTROL_RESUME_BROKEN: {
1299 if (m->friendlist[friendnumber].file_sending[filenumber].status == FILESTATUS_BROKEN && length == sizeof(uint64_t)) {
1300 m->friendlist[friendnumber].file_sending[filenumber].status = FILESTATUS_PAUSED_BY_US;
1301 net_to_host(data, sizeof(uint64_t));
1302 return 0;
1303 }
1304 1408
1305 return -1; 1409 if (receive_send) {
1306 } 1410 --m->friendlist[friendnumber].num_sending_files;
1307 } 1411 }
1412
1413 } else if (control_type == FILECONTROL_RESUME_BROKEN) {
1414 //TODO
1415 } else {
1416 return -1;
1308 } 1417 }
1309 1418
1310 return -1; 1419 return 0;
1311} 1420}
1312 1421
1313/**************************************/ 1422/**************************************/
@@ -1766,6 +1875,7 @@ static int handle_packet(void *object, int i, uint8_t *temp, uint16_t len)
1766 m->friendlist[i].file_receiving[filenumber].status = FILESTATUS_NOT_ACCEPTED; 1875 m->friendlist[i].file_receiving[filenumber].status = FILESTATUS_NOT_ACCEPTED;
1767 m->friendlist[i].file_receiving[filenumber].size = filesize; 1876 m->friendlist[i].file_receiving[filenumber].size = filesize;
1768 m->friendlist[i].file_receiving[filenumber].transferred = 0; 1877 m->friendlist[i].file_receiving[filenumber].transferred = 0;
1878 m->friendlist[i].file_receiving[filenumber].paused = FILE_PAUSE_NOT;
1769 1879
1770 /* Force NULL terminate file name. */ 1880 /* Force NULL terminate file name. */
1771 uint8_t filename_terminated[data_length - head_length + 1]; 1881 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)
1794 if (handle_filecontrol(m, i, send_receive, filenumber, control_type, data + 3, data_length - 3) == -1) 1904 if (handle_filecontrol(m, i, send_receive, filenumber, control_type, data + 3, data_length - 3) == -1)
1795 break; 1905 break;
1796 1906
1797 if (m->file_filecontrol)
1798 (*m->file_filecontrol)(m, i, send_receive, filenumber, control_type, data + 3, data_length - 3,
1799 m->file_filecontrol_userdata);
1800
1801 break; 1907 break;
1802 } 1908 }
1803 1909
1804 case PACKET_ID_FILE_DATA: { 1910 case PACKET_ID_FILE_DATA: {
1805 if (data_length < 2) 1911 if (data_length <= 1)
1806 break; 1912 break;
1807 1913
1808 uint8_t filenumber = data[0]; 1914 uint8_t filenumber = data[0];
1915 struct File_Transfers *ft = &m->friendlist[i].file_receiving[filenumber];
1809 1916
1810 if (m->friendlist[i].file_receiving[filenumber].status == FILESTATUS_NONE) 1917 if (ft->status == FILESTATUS_NONE)
1811 break; 1918 break;
1812 1919
1813 m->friendlist[i].file_receiving[filenumber].transferred += (data_length - 1); 1920 uint64_t position = ft->transferred;
1921 uint32_t real_filenumber = filenumber;
1922 real_filenumber += 1;
1923 real_filenumber <<= 16;
1924 uint16_t file_data_length = (data_length - 1);
1925 uint8_t *file_data;
1926
1927 if (file_data_length == 0) {
1928 file_data = NULL;
1929 } else {
1930 file_data = data + 1;
1931 }
1814 1932
1815 if (m->file_filedata) 1933 if (m->file_filedata)
1816 (*m->file_filedata)(m, i, filenumber, data + 1, data_length - 1, m->file_filedata_userdata); 1934 (*m->file_filedata)(m, i, real_filenumber, position, file_data, file_data_length, m->file_filedata_userdata);
1935
1936 ft->transferred += file_data_length;
1937
1938 if (ft->size && ft->transferred >= ft->size) {
1939 file_data_length = 0;
1940 file_data = NULL;
1941 position = ft->transferred;
1942
1943 /* Full file received. */
1944 if (m->file_filedata)
1945 (*m->file_filedata)(m, i, real_filenumber, position, file_data, file_data_length, m->file_filedata_userdata);
1946 }
1947
1948 /* Data is zero, filetransfer is over. */
1949 if (file_data_length == 0) {
1950 ft->status = FILESTATUS_NONE;
1951 }
1817 1952
1818 break; 1953 break;
1819 } 1954 }
@@ -1907,6 +2042,7 @@ void do_friends(Messenger *m)
1907 2042
1908 check_friend_tcp_udp(m, i); 2043 check_friend_tcp_udp(m, i);
1909 do_receipts(m, i); 2044 do_receipts(m, i);
2045 do_reqchunk_filecb(m, i);
1910 } 2046 }
1911 } 2047 }
1912} 2048}
diff --git a/toxcore/Messenger.h b/toxcore/Messenger.h
index ca6b4896..5215f989 100644
--- a/toxcore/Messenger.h
+++ b/toxcore/Messenger.h
@@ -128,18 +128,25 @@ USERSTATUS;
128struct File_Transfers { 128struct File_Transfers {
129 uint64_t size; 129 uint64_t size;
130 uint64_t transferred; 130 uint64_t transferred;
131 uint8_t status; /* 0 == no transfer, 1 = not accepted, 2 = paused by the other, 3 = transferring, 4 = broken, 5 = paused by us */ 131 uint8_t status; /* 0 == no transfer, 1 = not accepted, 3 = transferring, 4 = broken, 5 = finished */
132 unsigned int type; 132 uint8_t paused; /* 0: not paused, 1 = paused by us, 2 = paused by other, 3 = paused by both. */
133 uint32_t last_packet_number; /* number of the last packet sent. */
133}; 134};
134enum { 135enum {
135 FILESTATUS_NONE, 136 FILESTATUS_NONE,
136 FILESTATUS_NOT_ACCEPTED, 137 FILESTATUS_NOT_ACCEPTED,
137 FILESTATUS_PAUSED_BY_OTHER,
138 FILESTATUS_TRANSFERRING, 138 FILESTATUS_TRANSFERRING,
139 FILESTATUS_BROKEN, 139 //FILESTATUS_BROKEN,
140 FILESTATUS_PAUSED_BY_US, 140 FILESTATUS_FINISHED
141 FILESTATUS_TEMPORARY
142}; 141};
142
143enum {
144 FILE_PAUSE_NOT,
145 FILE_PAUSE_US,
146 FILE_PAUSE_OTHER,
147 FILE_PAUSE_BOTH
148};
149
143/* This cannot be bigger than 256 */ 150/* This cannot be bigger than 256 */
144#define MAX_CONCURRENT_FILE_PIPES 256 151#define MAX_CONCURRENT_FILE_PIPES 256
145 152
@@ -147,7 +154,6 @@ enum {
147 FILECONTROL_ACCEPT, 154 FILECONTROL_ACCEPT,
148 FILECONTROL_PAUSE, 155 FILECONTROL_PAUSE,
149 FILECONTROL_KILL, 156 FILECONTROL_KILL,
150 FILECONTROL_FINISHED,
151 FILECONTROL_RESUME_BROKEN 157 FILECONTROL_RESUME_BROKEN
152}; 158};
153 159
@@ -179,6 +185,7 @@ typedef struct {
179 uint64_t share_relays_lastsent; 185 uint64_t share_relays_lastsent;
180 uint8_t last_connection_udp_tcp; 186 uint8_t last_connection_udp_tcp;
181 struct File_Transfers file_sending[MAX_CONCURRENT_FILE_PIPES]; 187 struct File_Transfers file_sending[MAX_CONCURRENT_FILE_PIPES];
188 unsigned int num_sending_files;
182 struct File_Transfers file_receiving[MAX_CONCURRENT_FILE_PIPES]; 189 struct File_Transfers file_receiving[MAX_CONCURRENT_FILE_PIPES];
183 190
184 struct { 191 struct {
@@ -249,10 +256,12 @@ struct Messenger {
249 void (*file_sendrequest)(struct Messenger *m, uint32_t, uint32_t, unsigned int, uint64_t, const uint8_t *, size_t, 256 void (*file_sendrequest)(struct Messenger *m, uint32_t, uint32_t, unsigned int, uint64_t, const uint8_t *, size_t,
250 void *); 257 void *);
251 void *file_sendrequest_userdata; 258 void *file_sendrequest_userdata;
252 void (*file_filecontrol)(struct Messenger *m, uint32_t, uint8_t, uint8_t, uint8_t, const uint8_t *, uint16_t, void *); 259 void (*file_filecontrol)(struct Messenger *m, uint32_t, uint32_t, unsigned int, void *);
253 void *file_filecontrol_userdata; 260 void *file_filecontrol_userdata;
254 void (*file_filedata)(struct Messenger *m, uint32_t, uint8_t, const uint8_t *, uint16_t length, void *); 261 void (*file_filedata)(struct Messenger *m, uint32_t, uint32_t, uint64_t, const uint8_t *, size_t, void *);
255 void *file_filedata_userdata; 262 void *file_filedata_userdata;
263 void (*file_reqchunk)(struct Messenger *m, uint32_t, uint32_t, uint64_t, size_t, void *);
264 void *file_reqchunk_userdata;
256 265
257 void (*msi_packet)(struct Messenger *m, uint32_t, const uint8_t *, uint16_t, void *); 266 void (*msi_packet)(struct Messenger *m, uint32_t, const uint8_t *, uint16_t, void *);
258 void *msi_packet_userdata; 267 void *msi_packet_userdata;
@@ -562,20 +571,27 @@ void callback_file_sendrequest(Messenger *m, void (*function)(Messenger *m, uin
562 571
563/* Set the callback for file control requests. 572/* Set the callback for file control requests.
564 * 573 *
565 * 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) 574 * Function(Tox *tox, uint32_t friendnumber, uint32_t filenumber, unsigned int control_type, void *userdata)
566 * 575 *
567 */ 576 */
568void callback_file_control(Messenger *m, void (*function)(Messenger *m, uint32_t, uint8_t, uint8_t, uint8_t, 577void callback_file_control(Messenger *m, void (*function)(Messenger *m, uint32_t, uint32_t, unsigned int, void *),
569 const uint8_t *, uint16_t, void *), void *userdata); 578 void *userdata);
570 579
571/* Set the callback for file data. 580/* Set the callback for file data.
572 * 581 *
573 * Function(Tox *tox, uint32_t friendnumber, uint8_t filenumber, uint8_t *data, uint16_t length, void *userdata) 582 * Function(Tox *tox, uint32_t friendnumber, uint32_t filenumber, uint64_t position, uint8_t *data, size_t length, void *userdata)
574 * 583 *
575 */ 584 */
576void callback_file_data(Messenger *m, void (*function)(Messenger *m, uint32_t, uint8_t, const uint8_t *, 585void callback_file_data(Messenger *m, void (*function)(Messenger *m, uint32_t, uint32_t, uint64_t, const uint8_t *,
577 uint16_t length, 586 size_t, void *), void *userdata);
578 void *), void *userdata); 587
588/* Set the callback for file request chunk.
589 *
590 * Function(Tox *tox, uint32_t friendnumber, uint32_t filenumber, uint64_t position, size_t length, void *userdata)
591 *
592 */
593void callback_file_reqchunk(Messenger *m, void (*function)(Messenger *m, uint32_t, uint32_t, uint64_t, size_t, void *),
594 void *userdata);
579 595
580/* Send a file send request. 596/* Send a file send request.
581 * Maximum filename length is 255 bytes. 597 * Maximum filename length is 255 bytes.
@@ -590,20 +606,30 @@ long int new_filesender(const Messenger *m, int32_t friendnumber, uint32_t file_
590 const uint8_t *filename, uint16_t filename_length); 606 const uint8_t *filename, uint16_t filename_length);
591 607
592/* Send a file control request. 608/* Send a file control request.
593 * send_receive is 0 if we want the control packet to target a sending file, 1 if it targets a receiving file.
594 * 609 *
595 * return 1 on success 610 * return 0 on success
596 * return 0 on failure 611 * return -1 if friend not valid.
612 * return -2 if friend not online.
613 * return -3 if file number invalid.
614 * return -4 if file control is bad.
615 * return -5 if file already paused.
616 * return -6 if resume file failed because it was only paused by the other.
617 * return -7 if resume file failed because it wasn't paused.
618 * return -8 if packet failed to send.
597 */ 619 */
598int file_control(const Messenger *m, int32_t friendnumber, uint8_t send_receive, uint8_t filenumber, uint8_t message_id, 620int file_control(const Messenger *m, int32_t friendnumber, uint32_t filenumber, unsigned int control);
599 const uint8_t *data, uint16_t length);
600 621
601/* Send file data. 622/* Send file data.
602 * 623 *
603 * return 1 on success 624 * return 0 on success
604 * return 0 on failure 625 * return -1 if friend not valid.
626 * return -2 if friend not online.
627 * return -3 if filenumber invalid.
628 * return -4 if file transfer not transferring.
629 * return -5 if trying to send too much data.
630 * return -6 if packet queue full.
605 */ 631 */
606int file_data(const Messenger *m, int32_t friendnumber, uint8_t filenumber, const uint8_t *data, uint16_t length); 632int file_data(const Messenger *m, int32_t friendnumber, uint32_t filenumber, const uint8_t *data, uint16_t length);
607 633
608/* Give the number of bytes left to be sent/received. 634/* Give the number of bytes left to be sent/received.
609 * 635 *
diff --git a/toxcore/tox.c b/toxcore/tox.c
index fc6ffc2b..bcb871fc 100644
--- a/toxcore/tox.c
+++ b/toxcore/tox.c
@@ -811,6 +811,173 @@ void tox_callback_friend_action(Tox *tox, tox_friend_action_cb *function, void *
811 m_callback_action(m, function, user_data); 811 m_callback_action(m, function, user_data);
812} 812}
813 813
814bool tox_hash(uint8_t *hash, const uint8_t *data, size_t length)
815{
816 if (!hash || !data) {
817 return 0;
818 }
819
820 crypto_hash_sha256(hash, data, length);
821 return 1;
822}
823
824bool tox_file_control(Tox *tox, uint32_t friend_number, uint32_t file_number, TOX_FILE_CONTROL control,
825 TOX_ERR_FILE_CONTROL *error)
826{
827 Messenger *m = tox;
828 int ret = file_control(m, friend_number, file_number, control);
829
830 if (ret == 0) {
831 SET_ERROR_PARAMETER(error, TOX_ERR_FILE_CONTROL_OK);
832 return 1;
833 }
834
835 switch (ret) {
836 case -1:
837 SET_ERROR_PARAMETER(error, TOX_ERR_FILE_CONTROL_FRIEND_NOT_FOUND);
838 return 0;
839
840 case -2:
841 SET_ERROR_PARAMETER(error, TOX_ERR_FILE_CONTROL_FRIEND_NOT_CONNECTED);
842 return 0;
843
844 case -3:
845 SET_ERROR_PARAMETER(error, TOX_ERR_FILE_CONTROL_NOT_FOUND);
846 return 0;
847
848 case -4:
849 /* can't happen */
850 return 0;
851
852 case -5:
853 SET_ERROR_PARAMETER(error, TOX_ERR_FILE_CONTROL_ALREADY_PAUSED);
854 return 0;
855
856 case -6:
857 SET_ERROR_PARAMETER(error, TOX_ERR_FILE_CONTROL_DENIED);
858 return 0;
859
860 case -7:
861 SET_ERROR_PARAMETER(error, TOX_ERR_FILE_CONTROL_NOT_PAUSED);
862 return 0;
863
864 case -8:
865 SET_ERROR_PARAMETER(error, TOX_ERR_FILE_CONTROL_SEND_FAILED);
866 return 0;
867 }
868
869 /* can't happen */
870 return 0;
871}
872
873void tox_callback_file_control(Tox *tox, tox_file_control_cb *function, void *user_data)
874{
875 Messenger *m = tox;
876 callback_file_control(m, function, user_data);
877}
878
879uint32_t tox_file_send(Tox *tox, uint32_t friend_number, TOX_FILE_KIND kind, uint64_t file_size,
880 const uint8_t *filename, size_t filename_length, TOX_ERR_FILE_SEND *error)
881{
882 if (!filename) {
883 SET_ERROR_PARAMETER(error, TOX_ERR_FILE_SEND_NULL);
884 return UINT32_MAX;
885 }
886
887 if (!filename_length) {
888 SET_ERROR_PARAMETER(error, TOX_ERR_FILE_SEND_NAME_EMPTY);
889 return UINT32_MAX;
890 }
891
892 Messenger *m = tox;
893 long int file_num = new_filesender(m, friend_number, kind, file_size, filename, filename_length);
894
895 if (file_num >= 0) {
896 SET_ERROR_PARAMETER(error, TOX_ERR_FILE_SEND_OK);
897 return file_num;
898 }
899
900 switch (file_num) {
901 case -1:
902 SET_ERROR_PARAMETER(error, TOX_ERR_FILE_SEND_FRIEND_NOT_FOUND);
903 return UINT32_MAX;
904
905 case -2:
906 SET_ERROR_PARAMETER(error, TOX_ERR_FILE_SEND_NAME_TOO_LONG);
907 return UINT32_MAX;
908
909 case -3:
910 SET_ERROR_PARAMETER(error, TOX_ERR_FILE_SEND_TOO_MANY);
911 return UINT32_MAX;
912
913 case -4:
914 SET_ERROR_PARAMETER(error, TOX_ERR_FILE_SEND_FRIEND_NOT_CONNECTED);
915 return UINT32_MAX;
916 }
917
918 /* can't happen */
919 return UINT32_MAX;
920}
921
922bool tox_file_send_chunk(Tox *tox, uint32_t friend_number, uint32_t file_number, const uint8_t *data, size_t length,
923 TOX_ERR_FILE_SEND_CHUNK *error)
924{
925 Messenger *m = tox;
926 int ret = file_data(m, friend_number, file_number, data, length);
927
928 if (ret == 0) {
929 SET_ERROR_PARAMETER(error, TOX_ERR_FILE_SEND_CHUNK_OK);
930 return 1;
931 }
932
933 switch (ret) {
934 case -1:
935 SET_ERROR_PARAMETER(error, TOX_ERR_FILE_SEND_CHUNK_FRIEND_NOT_FOUND);
936 return 0;
937
938 case -2:
939 SET_ERROR_PARAMETER(error, TOX_ERR_FILE_SEND_CHUNK_FRIEND_NOT_CONNECTED);
940 return 0;
941
942 case -3:
943 SET_ERROR_PARAMETER(error, TOX_ERR_FILE_SEND_CHUNK_NOT_FOUND);
944 return 0;
945
946 case -4:
947 SET_ERROR_PARAMETER(error, TOX_ERR_FILE_SEND_CHUNK_NOT_TRANSFERRING);
948 return 0;
949
950 case -5:
951 SET_ERROR_PARAMETER(error, TOX_ERR_FILE_SEND_CHUNK_TOO_LARGE);
952 return 0;
953
954 case -6:
955 SET_ERROR_PARAMETER(error, TOX_ERR_FILE_SEND_CHUNK_QUEUE_FULL);
956 return 0;
957 }
958
959 /* can't happen */
960 return 0;
961}
962
963void tox_callback_file_request_chunk(Tox *tox, tox_file_request_chunk_cb *function, void *user_data)
964{
965 Messenger *m = tox;
966 callback_file_reqchunk(m, function, user_data);
967}
968
969void tox_callback_file_receive(Tox *tox, tox_file_receive_cb *function, void *user_data)
970{
971 Messenger *m = tox;
972 callback_file_sendrequest(m, function, user_data);
973}
974
975void tox_callback_file_receive_chunk(Tox *tox, tox_file_receive_chunk_cb *function, void *user_data)
976{
977 Messenger *m = tox;
978 callback_file_data(m, function, user_data);
979}
980
814static void set_custom_packet_error(int ret, TOX_ERR_SEND_CUSTOM_PACKET *error) 981static void set_custom_packet_error(int ret, TOX_ERR_SEND_CUSTOM_PACKET *error)
815{ 982{
816 switch (ret) { 983 switch (ret) {
diff --git a/toxcore/tox.h b/toxcore/tox.h
index 23d37cd9..b8cac443 100644
--- a/toxcore/tox.h
+++ b/toxcore/tox.h
@@ -1485,7 +1485,11 @@ typedef enum TOX_ERR_FILE_CONTROL {
1485 /** 1485 /**
1486 * A PAUSE control was sent, but the file transfer was already paused. 1486 * A PAUSE control was sent, but the file transfer was already paused.
1487 */ 1487 */
1488 TOX_ERR_FILE_CONTROL_ALREADY_PAUSED 1488 TOX_ERR_FILE_CONTROL_ALREADY_PAUSED,
1489 /**
1490 * Packet failed to send.
1491 */
1492 TOX_ERR_FILE_CONTROL_SEND_FAILED
1489} TOX_ERR_FILE_CONTROL; 1493} TOX_ERR_FILE_CONTROL;
1490 1494
1491/** 1495/**
@@ -1612,6 +1616,7 @@ typedef enum TOX_ERR_FILE_SEND {
1612 * 1616 *
1613 * @return A file number used as an identifier in subsequent callbacks. This 1617 * @return A file number used as an identifier in subsequent callbacks. This
1614 * number is per friend. File numbers are reused after a transfer terminates. 1618 * number is per friend. File numbers are reused after a transfer terminates.
1619 * on failure, this function returns UINT32_MAX.
1615 */ 1620 */
1616uint32_t tox_file_send(Tox *tox, uint32_t friend_number, TOX_FILE_KIND kind, uint64_t file_size, 1621uint32_t tox_file_send(Tox *tox, uint32_t friend_number, TOX_FILE_KIND kind, uint64_t file_size,
1617 const uint8_t *filename, size_t filename_length, TOX_ERR_FILE_SEND *error); 1622 const uint8_t *filename, size_t filename_length, TOX_ERR_FILE_SEND *error);
@@ -1636,11 +1641,20 @@ typedef enum TOX_ERR_FILE_SEND_CHUNK {
1636 */ 1641 */
1637 TOX_ERR_FILE_SEND_CHUNK_NOT_FOUND, 1642 TOX_ERR_FILE_SEND_CHUNK_NOT_FOUND,
1638 /** 1643 /**
1644 * File transfer was found but isn't in a transferring state: (paused, done,
1645 * broken, etc...) (happens only when not called from the request chunk callback).
1646 */
1647 TOX_ERR_FILE_SEND_CHUNK_NOT_TRANSFERRING,
1648 /**
1639 * Attempted to send more data than requested. The requested data size is 1649 * Attempted to send more data than requested. The requested data size is
1640 * adjusted according to maximum transmission unit and the expected end of 1650 * adjusted according to maximum transmission unit and the expected end of
1641 * the file. Trying to send more will result in no data being sent. 1651 * the file. Trying to send more will result in no data being sent.
1642 */ 1652 */
1643 TOX_ERR_FILE_SEND_CHUNK_TOO_LARGE 1653 TOX_ERR_FILE_SEND_CHUNK_TOO_LARGE,
1654 /**
1655 * Packet queue is full.
1656 */
1657 TOX_ERR_FILE_SEND_CHUNK_QUEUE_FULL
1644} TOX_ERR_FILE_SEND_CHUNK; 1658} TOX_ERR_FILE_SEND_CHUNK;
1645 1659
1646/** 1660/**