diff options
author | irungentoo <irungentoo@gmail.com> | 2015-03-10 17:31:50 -0400 |
---|---|---|
committer | irungentoo <irungentoo@gmail.com> | 2015-03-10 17:31:50 -0400 |
commit | 0207fcdfb0e43d425abb026b08c074a6822e0349 (patch) | |
tree | 2cb06c6c8dd13b4230be005282adf7fb44ad0915 | |
parent | f5eca31637cbcbdd44f3fefc9139aa8ef0d1bd5e (diff) |
Implementation of new api file transfers.
Everything should work except resuming.
-rw-r--r-- | auto_tests/tox_test.c | 135 | ||||
-rw-r--r-- | toxcore/Messenger.c | 466 | ||||
-rw-r--r-- | toxcore/Messenger.h | 74 | ||||
-rw-r--r-- | toxcore/tox.c | 167 | ||||
-rw-r--r-- | toxcore/tox.h | 18 |
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 | |||
24 | void accept_friend_request(Tox *m, const uint8_t *public_key, const uint8_t *data, size_t length, void *userdata) | 25 | void 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 | |||
92 | uint8_t filenum; | 93 | uint8_t filenum; |
93 | uint32_t file_accepted; | 94 | uint32_t file_accepted; |
94 | uint64_t file_size; | 95 | uint64_t file_size; |
95 | void file_request_accept(Tox *m, int friendnumber, uint8_t filenumber, uint64_t filesize, const uint8_t *filename, | 96 | void 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 | ||
108 | uint32_t file_sent; | ||
109 | uint32_t sendf_ok; | 123 | uint32_t sendf_ok; |
110 | void file_print_control(Tox *m, int friendnumber, uint8_t receive_send, uint8_t filenumber, uint8_t control_type, | 124 | void 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) | 135 | uint8_t sending_num; |
120 | file_sent = 1; | 136 | uint64_t sending_pos; |
137 | _Bool file_sending_done; | ||
138 | void 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 | |||
127 | uint64_t size_recv; | 175 | uint64_t size_recv; |
128 | uint8_t num; | 176 | uint8_t num; |
129 | void write_file(Tox *m, int friendnumber, uint8_t filenumber, const uint8_t *data, uint16_t length, void *userdata) | 177 | _Bool file_recv; |
178 | void 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 | */ | ||
356 | static 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 | ||
353 | static int do_receipts(Messenger *m, int32_t friendnumber) | 365 | static 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 | */ |
976 | void callback_file_control(Messenger *m, void (*function)(Messenger *m, uint32_t, uint8_t, uint8_t, uint8_t, | 987 | void 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 | */ |
988 | void callback_file_data(Messenger *m, void (*function)(Messenger *m, uint32_t, uint8_t, const uint8_t *, | 999 | void 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 | */ | ||
1011 | void 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 | ||
1084 | int 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 | */ |
1066 | int file_control(const Messenger *m, int32_t friendnumber, uint8_t send_receive, uint8_t filenumber, uint8_t message_id, | 1115 | int 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 | */ |
1156 | int file_data(const Messenger *m, int32_t friendnumber, uint8_t filenumber, const uint8_t *data, uint16_t length) | 1200 | int 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 | ||
1284 | static 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 | */ |
1215 | static void break_files(const Messenger *m, int32_t friendnumber) | 1347 | static 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 | ||
1228 | static 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) | 1362 | static 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; | |||
128 | struct File_Transfers { | 128 | struct 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 | }; |
134 | enum { | 135 | enum { |
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 | |||
143 | enum { | ||
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 | */ |
568 | void callback_file_control(Messenger *m, void (*function)(Messenger *m, uint32_t, uint8_t, uint8_t, uint8_t, | 577 | void 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 | */ |
576 | void callback_file_data(Messenger *m, void (*function)(Messenger *m, uint32_t, uint8_t, const uint8_t *, | 585 | void 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 | */ | ||
593 | void 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 | */ |
598 | int file_control(const Messenger *m, int32_t friendnumber, uint8_t send_receive, uint8_t filenumber, uint8_t message_id, | 620 | int 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 | */ |
606 | int file_data(const Messenger *m, int32_t friendnumber, uint8_t filenumber, const uint8_t *data, uint16_t length); | 632 | int 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 | ||
814 | bool 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 | |||
824 | bool 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 | |||
873 | void 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 | |||
879 | uint32_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 | |||
922 | bool 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 | |||
963 | void 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 | |||
969 | void 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 | |||
975 | void 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 | |||
814 | static void set_custom_packet_error(int ret, TOX_ERR_SEND_CUSTOM_PACKET *error) | 981 | static 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 | */ |
1616 | uint32_t tox_file_send(Tox *tox, uint32_t friend_number, TOX_FILE_KIND kind, uint64_t file_size, | 1621 | uint32_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 | /** |