diff options
author | zoff99 <zoff@zoff.cc> | 2018-02-05 21:07:26 +0100 |
---|---|---|
committer | iphydf <iphydf@users.noreply.github.com> | 2018-02-17 16:32:25 +0000 |
commit | 82662d4e16937997c36d2090a17c3b2389fa4ad5 (patch) | |
tree | 2edd3ed06711e7b04a0584daac6986026e299dcd | |
parent | 35f13ef51dbf99c3d45d04f572e9e88795df7ae6 (diff) |
Make outgoing Filetransfers round-robin.
Instead of 1 FT blocking all others.
-rw-r--r-- | CMakeLists.txt | 1 | ||||
-rw-r--r-- | auto_tests/file_transfer_test.c | 429 | ||||
-rw-r--r-- | auto_tests/helpers.h | 10 | ||||
-rw-r--r-- | auto_tests/tox_test.c | 311 | ||||
-rw-r--r-- | toxcore/Messenger.c | 158 | ||||
-rw-r--r-- | toxcore/Messenger.h | 2 | ||||
-rw-r--r-- | toxcore/util.c | 10 | ||||
-rw-r--r-- | toxcore/util.h | 3 |
8 files changed, 544 insertions, 380 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index 8bba3519..9acb97d2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt | |||
@@ -524,6 +524,7 @@ auto_test(conference) | |||
524 | auto_test(crypto MSVC_DONT_BUILD) | 524 | auto_test(crypto MSVC_DONT_BUILD) |
525 | auto_test(dht MSVC_DONT_BUILD) | 525 | auto_test(dht MSVC_DONT_BUILD) |
526 | auto_test(encryptsave) | 526 | auto_test(encryptsave) |
527 | auto_test(file_transfer) | ||
527 | auto_test(lan_discovery) | 528 | auto_test(lan_discovery) |
528 | auto_test(messenger MSVC_DONT_BUILD) | 529 | auto_test(messenger MSVC_DONT_BUILD) |
529 | auto_test(network) | 530 | auto_test(network) |
diff --git a/auto_tests/file_transfer_test.c b/auto_tests/file_transfer_test.c new file mode 100644 index 00000000..7247a188 --- /dev/null +++ b/auto_tests/file_transfer_test.c | |||
@@ -0,0 +1,429 @@ | |||
1 | /* File transfer test. | ||
2 | */ | ||
3 | |||
4 | #ifndef _XOPEN_SOURCE | ||
5 | #define _XOPEN_SOURCE 600 | ||
6 | #endif | ||
7 | |||
8 | #ifdef HAVE_CONFIG_H | ||
9 | #include "config.h" | ||
10 | #endif | ||
11 | |||
12 | #include "check_compat.h" | ||
13 | |||
14 | #include <stdio.h> | ||
15 | #include <stdlib.h> | ||
16 | #include <time.h> | ||
17 | |||
18 | #include "../toxcore/ccompat.h" | ||
19 | #include "../toxcore/tox.h" | ||
20 | #include "../toxcore/util.h" | ||
21 | |||
22 | #include "helpers.h" | ||
23 | |||
24 | /* The Travis-CI container responds poorly to ::1 as a localhost address | ||
25 | * You're encouraged to -D FORCE_TESTS_IPV6 on a local test */ | ||
26 | #ifdef FORCE_TESTS_IPV6 | ||
27 | #define TOX_LOCALHOST "::1" | ||
28 | #else | ||
29 | #define TOX_LOCALHOST "127.0.0.1" | ||
30 | #endif | ||
31 | |||
32 | static void accept_friend_request(Tox *m, const uint8_t *public_key, const uint8_t *data, size_t length, void *userdata) | ||
33 | { | ||
34 | if (length == 7 && memcmp("Gentoo", data, 7) == 0) { | ||
35 | tox_friend_add_norequest(m, public_key, nullptr); | ||
36 | } | ||
37 | } | ||
38 | |||
39 | static uint64_t size_recv; | ||
40 | static uint64_t sending_pos; | ||
41 | |||
42 | static uint8_t file_cmp_id[TOX_FILE_ID_LENGTH]; | ||
43 | static uint32_t file_accepted; | ||
44 | static uint64_t file_size; | ||
45 | static void tox_file_receive(Tox *tox, uint32_t friend_number, uint32_t file_number, uint32_t kind, uint64_t filesize, | ||
46 | const uint8_t *filename, size_t filename_length, void *userdata) | ||
47 | { | ||
48 | if (kind != TOX_FILE_KIND_DATA) { | ||
49 | ck_abort_msg("Bad kind"); | ||
50 | } | ||
51 | |||
52 | if (!(filename_length == sizeof("Gentoo.exe") && memcmp(filename, "Gentoo.exe", sizeof("Gentoo.exe")) == 0)) { | ||
53 | ck_abort_msg("Bad filename"); | ||
54 | } | ||
55 | |||
56 | uint8_t file_id[TOX_FILE_ID_LENGTH]; | ||
57 | |||
58 | if (!tox_file_get_file_id(tox, friend_number, file_number, file_id, nullptr)) { | ||
59 | ck_abort_msg("tox_file_get_file_id error"); | ||
60 | } | ||
61 | |||
62 | if (memcmp(file_id, file_cmp_id, TOX_FILE_ID_LENGTH) != 0) { | ||
63 | ck_abort_msg("bad file_id"); | ||
64 | } | ||
65 | |||
66 | uint8_t empty[TOX_FILE_ID_LENGTH] = {0}; | ||
67 | |||
68 | if (memcmp(empty, file_cmp_id, TOX_FILE_ID_LENGTH) == 0) { | ||
69 | ck_abort_msg("empty file_id"); | ||
70 | } | ||
71 | |||
72 | file_size = filesize; | ||
73 | |||
74 | if (filesize) { | ||
75 | sending_pos = size_recv = 1337; | ||
76 | |||
77 | TOX_ERR_FILE_SEEK err_s; | ||
78 | |||
79 | if (!tox_file_seek(tox, friend_number, file_number, 1337, &err_s)) { | ||
80 | ck_abort_msg("tox_file_seek error"); | ||
81 | } | ||
82 | |||
83 | ck_assert_msg(err_s == TOX_ERR_FILE_SEEK_OK, "tox_file_seek wrong error"); | ||
84 | } else { | ||
85 | sending_pos = size_recv = 0; | ||
86 | } | ||
87 | |||
88 | TOX_ERR_FILE_CONTROL error; | ||
89 | |||
90 | if (tox_file_control(tox, friend_number, file_number, TOX_FILE_CONTROL_RESUME, &error)) { | ||
91 | ++file_accepted; | ||
92 | } else { | ||
93 | ck_abort_msg("tox_file_control failed. %i", error); | ||
94 | } | ||
95 | |||
96 | TOX_ERR_FILE_SEEK err_s; | ||
97 | |||
98 | if (tox_file_seek(tox, friend_number, file_number, 1234, &err_s)) { | ||
99 | ck_abort_msg("tox_file_seek no error"); | ||
100 | } | ||
101 | |||
102 | ck_assert_msg(err_s == TOX_ERR_FILE_SEEK_DENIED, "tox_file_seek wrong error"); | ||
103 | } | ||
104 | |||
105 | static uint32_t sendf_ok; | ||
106 | static void file_print_control(Tox *tox, uint32_t friend_number, uint32_t file_number, TOX_FILE_CONTROL control, | ||
107 | void *userdata) | ||
108 | { | ||
109 | /* First send file num is 0.*/ | ||
110 | if (file_number == 0 && control == TOX_FILE_CONTROL_RESUME) { | ||
111 | sendf_ok = 1; | ||
112 | } | ||
113 | } | ||
114 | |||
115 | static uint64_t max_sending; | ||
116 | static bool m_send_reached; | ||
117 | static uint8_t sending_num; | ||
118 | static bool file_sending_done; | ||
119 | static void tox_file_chunk_request(Tox *tox, uint32_t friend_number, uint32_t file_number, uint64_t position, | ||
120 | size_t length, void *user_data) | ||
121 | { | ||
122 | if (!sendf_ok) { | ||
123 | ck_abort_msg("Didn't get resume control"); | ||
124 | } | ||
125 | |||
126 | if (sending_pos != position) { | ||
127 | ck_abort_msg("Bad position %llu", (unsigned long long)position); | ||
128 | } | ||
129 | |||
130 | if (length == 0) { | ||
131 | if (file_sending_done) { | ||
132 | ck_abort_msg("File sending already done."); | ||
133 | } | ||
134 | |||
135 | file_sending_done = 1; | ||
136 | return; | ||
137 | } | ||
138 | |||
139 | if (position + length > max_sending) { | ||
140 | if (m_send_reached) { | ||
141 | ck_abort_msg("Requested done file transfer."); | ||
142 | } | ||
143 | |||
144 | length = max_sending - position; | ||
145 | m_send_reached = 1; | ||
146 | } | ||
147 | |||
148 | TOX_ERR_FILE_SEND_CHUNK error; | ||
149 | VLA(uint8_t, f_data, length); | ||
150 | memset(f_data, sending_num, length); | ||
151 | |||
152 | if (tox_file_send_chunk(tox, friend_number, file_number, position, f_data, length, &error)) { | ||
153 | ++sending_num; | ||
154 | sending_pos += length; | ||
155 | } else { | ||
156 | ck_abort_msg("Could not send chunk, error num=%d pos=%d len=%d", (int)error, (int)position, (int)length); | ||
157 | } | ||
158 | |||
159 | if (error != TOX_ERR_FILE_SEND_CHUNK_OK) { | ||
160 | ck_abort_msg("Wrong error code"); | ||
161 | } | ||
162 | } | ||
163 | |||
164 | |||
165 | static uint8_t num; | ||
166 | static bool file_recv; | ||
167 | static void write_file(Tox *tox, uint32_t friendnumber, uint32_t filenumber, uint64_t position, const uint8_t *data, | ||
168 | size_t length, void *user_data) | ||
169 | { | ||
170 | if (size_recv != position) { | ||
171 | ck_abort_msg("Bad position"); | ||
172 | } | ||
173 | |||
174 | if (length == 0) { | ||
175 | file_recv = 1; | ||
176 | return; | ||
177 | } | ||
178 | |||
179 | VLA(uint8_t, f_data, length); | ||
180 | memset(f_data, num, length); | ||
181 | ++num; | ||
182 | |||
183 | if (memcmp(f_data, data, length) == 0) { | ||
184 | size_recv += length; | ||
185 | } else { | ||
186 | ck_abort_msg("FILE_CORRUPTED"); | ||
187 | } | ||
188 | } | ||
189 | |||
190 | START_TEST(test_few_clients) | ||
191 | { | ||
192 | printf("Starting test: few_clients\n"); | ||
193 | uint32_t index[] = { 1, 2, 3 }; | ||
194 | long long unsigned int cur_time = time(nullptr); | ||
195 | TOX_ERR_NEW t_n_error; | ||
196 | Tox *tox1 = tox_new_log(nullptr, &t_n_error, &index[0]); | ||
197 | ck_assert_msg(t_n_error == TOX_ERR_NEW_OK, "wrong error"); | ||
198 | Tox *tox2 = tox_new_log(nullptr, &t_n_error, &index[1]); | ||
199 | ck_assert_msg(t_n_error == TOX_ERR_NEW_OK, "wrong error"); | ||
200 | Tox *tox3 = tox_new_log(nullptr, &t_n_error, &index[2]); | ||
201 | ck_assert_msg(t_n_error == TOX_ERR_NEW_OK, "wrong error"); | ||
202 | |||
203 | ck_assert_msg(tox1 && tox2 && tox3, "Failed to create 3 tox instances"); | ||
204 | |||
205 | { | ||
206 | TOX_ERR_GET_PORT error; | ||
207 | uint16_t first_port = tox_self_get_udp_port(tox1, &error); | ||
208 | ck_assert_msg(33445 <= first_port && first_port <= 33545 - 2, | ||
209 | "First Tox instance did not bind to udp port inside [33445, 33543].\n"); | ||
210 | ck_assert_msg(error == TOX_ERR_GET_PORT_OK, "wrong error"); | ||
211 | |||
212 | ck_assert_msg(tox_self_get_udp_port(tox2, &error) == first_port + 1, | ||
213 | "Second Tox instance did not bind to udp port %d.\n", first_port + 1); | ||
214 | ck_assert_msg(error == TOX_ERR_GET_PORT_OK, "wrong error"); | ||
215 | |||
216 | ck_assert_msg(tox_self_get_udp_port(tox3, &error) == first_port + 2, | ||
217 | "Third Tox instance did not bind to udp port %d.\n", first_port + 2); | ||
218 | ck_assert_msg(error == TOX_ERR_GET_PORT_OK, "wrong error"); | ||
219 | } | ||
220 | |||
221 | tox_callback_friend_request(tox2, accept_friend_request); | ||
222 | uint8_t address[TOX_ADDRESS_SIZE]; | ||
223 | tox_self_get_address(tox2, address); | ||
224 | uint32_t test = tox_friend_add(tox3, address, (const uint8_t *)"Gentoo", 7, nullptr); | ||
225 | ck_assert_msg(test == 0, "Failed to add friend error code: %i", test); | ||
226 | |||
227 | uint8_t dhtKey[TOX_PUBLIC_KEY_SIZE]; | ||
228 | tox_self_get_dht_id(tox1, dhtKey); | ||
229 | uint16_t dhtPort = tox_self_get_udp_port(tox1, nullptr); | ||
230 | |||
231 | tox_bootstrap(tox2, TOX_LOCALHOST, dhtPort, dhtKey, nullptr); | ||
232 | tox_bootstrap(tox3, TOX_LOCALHOST, dhtPort, dhtKey, nullptr); | ||
233 | |||
234 | printf("Waiting for toxes to come online\n"); | ||
235 | |||
236 | while (tox_self_get_connection_status(tox1) == TOX_CONNECTION_NONE || | ||
237 | tox_self_get_connection_status(tox2) == TOX_CONNECTION_NONE || | ||
238 | tox_self_get_connection_status(tox3) == TOX_CONNECTION_NONE || | ||
239 | tox_friend_get_connection_status(tox2, 0, nullptr) == TOX_CONNECTION_NONE || | ||
240 | tox_friend_get_connection_status(tox3, 0, nullptr) == TOX_CONNECTION_NONE) { | ||
241 | tox_iterate(tox1, nullptr); | ||
242 | tox_iterate(tox2, nullptr); | ||
243 | tox_iterate(tox3, nullptr); | ||
244 | |||
245 | printf("Connections: self (%d, %d, %d), friends (%d, %d)\n", | ||
246 | tox_self_get_connection_status(tox1), | ||
247 | tox_self_get_connection_status(tox2), | ||
248 | tox_self_get_connection_status(tox3), | ||
249 | tox_friend_get_connection_status(tox2, 0, nullptr), | ||
250 | tox_friend_get_connection_status(tox3, 0, nullptr)); | ||
251 | c_sleep(1000); | ||
252 | } | ||
253 | |||
254 | printf("Starting file transfer test.\n"); | ||
255 | |||
256 | file_accepted = file_size = sendf_ok = size_recv = 0; | ||
257 | file_recv = 0; | ||
258 | max_sending = UINT64_MAX; | ||
259 | long long unsigned int f_time = time(nullptr); | ||
260 | tox_callback_file_recv_chunk(tox3, write_file); | ||
261 | tox_callback_file_recv_control(tox2, file_print_control); | ||
262 | tox_callback_file_chunk_request(tox2, tox_file_chunk_request); | ||
263 | tox_callback_file_recv_control(tox3, file_print_control); | ||
264 | tox_callback_file_recv(tox3, tox_file_receive); | ||
265 | uint64_t totalf_size = 100 * 1024 * 1024; | ||
266 | uint32_t fnum = tox_file_send(tox2, 0, TOX_FILE_KIND_DATA, totalf_size, nullptr, (const uint8_t *)"Gentoo.exe", | ||
267 | sizeof("Gentoo.exe"), nullptr); | ||
268 | ck_assert_msg(fnum != UINT32_MAX, "tox_new_file_sender fail"); | ||
269 | |||
270 | TOX_ERR_FILE_GET gfierr; | ||
271 | ck_assert_msg(!tox_file_get_file_id(tox2, 1, fnum, file_cmp_id, &gfierr), "tox_file_get_file_id didn't fail"); | ||
272 | ck_assert_msg(gfierr == TOX_ERR_FILE_GET_FRIEND_NOT_FOUND, "wrong error"); | ||
273 | ck_assert_msg(!tox_file_get_file_id(tox2, 0, fnum + 1, file_cmp_id, &gfierr), "tox_file_get_file_id didn't fail"); | ||
274 | ck_assert_msg(gfierr == TOX_ERR_FILE_GET_NOT_FOUND, "wrong error"); | ||
275 | ck_assert_msg(tox_file_get_file_id(tox2, 0, fnum, file_cmp_id, &gfierr), "tox_file_get_file_id failed"); | ||
276 | ck_assert_msg(gfierr == TOX_ERR_FILE_GET_OK, "wrong error"); | ||
277 | |||
278 | while (1) { | ||
279 | tox_iterate(tox1, nullptr); | ||
280 | tox_iterate(tox2, nullptr); | ||
281 | tox_iterate(tox3, nullptr); | ||
282 | |||
283 | if (file_sending_done) { | ||
284 | if (sendf_ok && file_recv && totalf_size == file_size && size_recv == file_size && sending_pos == size_recv | ||
285 | && file_accepted == 1) { | ||
286 | break; | ||
287 | } | ||
288 | |||
289 | ck_abort_msg("Something went wrong in file transfer %u %u %u %u %u %u %llu %llu %llu", sendf_ok, file_recv, | ||
290 | totalf_size == file_size, size_recv == file_size, sending_pos == size_recv, file_accepted == 1, | ||
291 | (unsigned long long)totalf_size, (unsigned long long)size_recv, | ||
292 | (unsigned long long)sending_pos); | ||
293 | } | ||
294 | |||
295 | uint32_t tox1_interval = tox_iteration_interval(tox1); | ||
296 | uint32_t tox2_interval = tox_iteration_interval(tox2); | ||
297 | uint32_t tox3_interval = tox_iteration_interval(tox3); | ||
298 | |||
299 | c_sleep(MIN(tox1_interval, MIN(tox2_interval, tox3_interval))); | ||
300 | } | ||
301 | |||
302 | printf("100MB file sent in %llu seconds\n", time(nullptr) - f_time); | ||
303 | |||
304 | printf("Starting file streaming transfer test.\n"); | ||
305 | |||
306 | file_sending_done = file_accepted = file_size = sendf_ok = size_recv = 0; | ||
307 | file_recv = 0; | ||
308 | tox_callback_file_recv_chunk(tox3, write_file); | ||
309 | tox_callback_file_recv_control(tox2, file_print_control); | ||
310 | tox_callback_file_chunk_request(tox2, tox_file_chunk_request); | ||
311 | tox_callback_file_recv_control(tox3, file_print_control); | ||
312 | tox_callback_file_recv(tox3, tox_file_receive); | ||
313 | totalf_size = UINT64_MAX; | ||
314 | fnum = tox_file_send(tox2, 0, TOX_FILE_KIND_DATA, totalf_size, nullptr, | ||
315 | (const uint8_t *)"Gentoo.exe", sizeof("Gentoo.exe"), nullptr); | ||
316 | ck_assert_msg(fnum != UINT32_MAX, "tox_new_file_sender fail"); | ||
317 | |||
318 | ck_assert_msg(!tox_file_get_file_id(tox2, 1, fnum, file_cmp_id, &gfierr), "tox_file_get_file_id didn't fail"); | ||
319 | ck_assert_msg(gfierr == TOX_ERR_FILE_GET_FRIEND_NOT_FOUND, "wrong error"); | ||
320 | ck_assert_msg(!tox_file_get_file_id(tox2, 0, fnum + 1, file_cmp_id, &gfierr), "tox_file_get_file_id didn't fail"); | ||
321 | ck_assert_msg(gfierr == TOX_ERR_FILE_GET_NOT_FOUND, "wrong error"); | ||
322 | ck_assert_msg(tox_file_get_file_id(tox2, 0, fnum, file_cmp_id, &gfierr), "tox_file_get_file_id failed"); | ||
323 | ck_assert_msg(gfierr == TOX_ERR_FILE_GET_OK, "wrong error"); | ||
324 | |||
325 | max_sending = 100 * 1024; | ||
326 | m_send_reached = 0; | ||
327 | |||
328 | while (1) { | ||
329 | tox_iterate(tox1, nullptr); | ||
330 | tox_iterate(tox2, nullptr); | ||
331 | tox_iterate(tox3, nullptr); | ||
332 | |||
333 | if (file_sending_done) { | ||
334 | if (sendf_ok && file_recv && m_send_reached && totalf_size == file_size && size_recv == max_sending | ||
335 | && sending_pos == size_recv && file_accepted == 1) { | ||
336 | break; | ||
337 | } | ||
338 | |||
339 | ck_abort_msg("Something went wrong in file transfer %u %u %u %u %u %u %u %llu %llu %llu %llu", sendf_ok, file_recv, | ||
340 | m_send_reached, totalf_size == file_size, size_recv == max_sending, sending_pos == size_recv, file_accepted == 1, | ||
341 | (unsigned long long)totalf_size, (unsigned long long)file_size, | ||
342 | (unsigned long long)size_recv, (unsigned long long)sending_pos); | ||
343 | } | ||
344 | |||
345 | uint32_t tox1_interval = tox_iteration_interval(tox1); | ||
346 | uint32_t tox2_interval = tox_iteration_interval(tox2); | ||
347 | uint32_t tox3_interval = tox_iteration_interval(tox3); | ||
348 | |||
349 | c_sleep(MIN(tox1_interval, MIN(tox2_interval, tox3_interval))); | ||
350 | } | ||
351 | |||
352 | printf("Starting file 0 transfer test.\n"); | ||
353 | |||
354 | file_sending_done = file_accepted = file_size = sendf_ok = size_recv = 0; | ||
355 | file_recv = 0; | ||
356 | tox_callback_file_recv_chunk(tox3, write_file); | ||
357 | tox_callback_file_recv_control(tox2, file_print_control); | ||
358 | tox_callback_file_chunk_request(tox2, tox_file_chunk_request); | ||
359 | tox_callback_file_recv_control(tox3, file_print_control); | ||
360 | tox_callback_file_recv(tox3, tox_file_receive); | ||
361 | totalf_size = 0; | ||
362 | fnum = tox_file_send(tox2, 0, TOX_FILE_KIND_DATA, totalf_size, nullptr, | ||
363 | (const uint8_t *)"Gentoo.exe", sizeof("Gentoo.exe"), nullptr); | ||
364 | ck_assert_msg(fnum != UINT32_MAX, "tox_new_file_sender fail"); | ||
365 | |||
366 | ck_assert_msg(!tox_file_get_file_id(tox2, 1, fnum, file_cmp_id, &gfierr), "tox_file_get_file_id didn't fail"); | ||
367 | ck_assert_msg(gfierr == TOX_ERR_FILE_GET_FRIEND_NOT_FOUND, "wrong error"); | ||
368 | ck_assert_msg(!tox_file_get_file_id(tox2, 0, fnum + 1, file_cmp_id, &gfierr), "tox_file_get_file_id didn't fail"); | ||
369 | ck_assert_msg(gfierr == TOX_ERR_FILE_GET_NOT_FOUND, "wrong error"); | ||
370 | ck_assert_msg(tox_file_get_file_id(tox2, 0, fnum, file_cmp_id, &gfierr), "tox_file_get_file_id failed"); | ||
371 | ck_assert_msg(gfierr == TOX_ERR_FILE_GET_OK, "wrong error"); | ||
372 | |||
373 | while (1) { | ||
374 | tox_iterate(tox1, nullptr); | ||
375 | tox_iterate(tox2, nullptr); | ||
376 | tox_iterate(tox3, nullptr); | ||
377 | |||
378 | if (file_sending_done) { | ||
379 | if (sendf_ok && file_recv && totalf_size == file_size && size_recv == file_size && sending_pos == size_recv | ||
380 | && file_accepted == 1) { | ||
381 | break; | ||
382 | } | ||
383 | |||
384 | ck_abort_msg("Something went wrong in file transfer %u %u %u %u %u %u %llu %llu %llu", sendf_ok, file_recv, | ||
385 | totalf_size == file_size, size_recv == file_size, sending_pos == size_recv, file_accepted == 1, | ||
386 | (unsigned long long)totalf_size, (unsigned long long)size_recv, | ||
387 | (unsigned long long)sending_pos); | ||
388 | } | ||
389 | |||
390 | uint32_t tox1_interval = tox_iteration_interval(tox1); | ||
391 | uint32_t tox2_interval = tox_iteration_interval(tox2); | ||
392 | uint32_t tox3_interval = tox_iteration_interval(tox3); | ||
393 | |||
394 | c_sleep(MIN(tox1_interval, MIN(tox2_interval, tox3_interval))); | ||
395 | } | ||
396 | |||
397 | printf("test_few_clients succeeded, took %llu seconds\n", time(nullptr) - cur_time); | ||
398 | |||
399 | tox_kill(tox1); | ||
400 | tox_kill(tox2); | ||
401 | tox_kill(tox3); | ||
402 | } | ||
403 | END_TEST | ||
404 | |||
405 | static Suite *tox_suite(void) | ||
406 | { | ||
407 | Suite *s = suite_create("Tox few clients"); | ||
408 | |||
409 | DEFTESTCASE(few_clients); | ||
410 | |||
411 | return s; | ||
412 | } | ||
413 | |||
414 | int main(int argc, char *argv[]) | ||
415 | { | ||
416 | setvbuf(stdout, nullptr, _IONBF, 0); | ||
417 | srand((unsigned int) time(nullptr)); | ||
418 | |||
419 | Suite *tox = tox_suite(); | ||
420 | SRunner *test_runner = srunner_create(tox); | ||
421 | |||
422 | int number_failed = 0; | ||
423 | srunner_run_all(test_runner, CK_NORMAL); | ||
424 | number_failed = srunner_ntests_failed(test_runner); | ||
425 | |||
426 | srunner_free(test_runner); | ||
427 | |||
428 | return number_failed; | ||
429 | } | ||
diff --git a/auto_tests/helpers.h b/auto_tests/helpers.h index ac58684d..0c88f4a1 100644 --- a/auto_tests/helpers.h +++ b/auto_tests/helpers.h | |||
@@ -42,18 +42,10 @@ static const char *tox_log_level_name(TOX_LOG_LEVEL level) | |||
42 | static void print_debug_log(Tox *m, TOX_LOG_LEVEL level, const char *path, uint32_t line, const char *func, | 42 | static void print_debug_log(Tox *m, TOX_LOG_LEVEL level, const char *path, uint32_t line, const char *func, |
43 | const char *message, void *user_data) | 43 | const char *message, void *user_data) |
44 | { | 44 | { |
45 | if (level == TOX_LOG_LEVEL_TRACE) { | ||
46 | return; | ||
47 | } | ||
48 | |||
49 | if (strncmp(message, "Bound successfully to ", strlen("Bound successfully to "))) { | ||
50 | return; | ||
51 | } | ||
52 | |||
53 | uint32_t index = user_data ? *(uint32_t *)user_data : 0; | 45 | uint32_t index = user_data ? *(uint32_t *)user_data : 0; |
54 | const char *file = strrchr(path, '/'); | 46 | const char *file = strrchr(path, '/'); |
55 | file = file ? file + 1 : path; | 47 | file = file ? file + 1 : path; |
56 | printf("[#%d] %s %s:%d\t%s:\t%s\n", index, tox_log_level_name(level), file, line, func, message); | 48 | fprintf(stderr, "[#%d] %s %s:%d\t%s:\t%s\n", index, tox_log_level_name(level), file, line, func, message); |
57 | } | 49 | } |
58 | 50 | ||
59 | Tox *tox_new_log(struct Tox_Options *options, TOX_ERR_NEW *err, void *log_user_data) | 51 | Tox *tox_new_log(struct Tox_Options *options, TOX_ERR_NEW *err, void *log_user_data) |
diff --git a/auto_tests/tox_test.c b/auto_tests/tox_test.c index 82c18b37..d6613a9a 100644 --- a/auto_tests/tox_test.c +++ b/auto_tests/tox_test.c | |||
@@ -133,174 +133,6 @@ static void handle_custom_packet(Tox *m, uint32_t friend_num, const uint8_t *dat | |||
133 | return; | 133 | return; |
134 | } | 134 | } |
135 | 135 | ||
136 | static uint64_t size_recv; | ||
137 | static uint64_t sending_pos; | ||
138 | |||
139 | static uint8_t file_cmp_id[TOX_FILE_ID_LENGTH]; | ||
140 | static uint32_t file_accepted; | ||
141 | static uint64_t file_size; | ||
142 | static void tox_file_receive(Tox *tox, uint32_t friend_number, uint32_t file_number, uint32_t kind, uint64_t filesize, | ||
143 | const uint8_t *filename, size_t filename_length, void *userdata) | ||
144 | { | ||
145 | if (*((uint32_t *)userdata) != 974536) { | ||
146 | return; | ||
147 | } | ||
148 | |||
149 | if (kind != TOX_FILE_KIND_DATA) { | ||
150 | ck_abort_msg("Bad kind"); | ||
151 | } | ||
152 | |||
153 | if (!(filename_length == sizeof("Gentoo.exe") && memcmp(filename, "Gentoo.exe", sizeof("Gentoo.exe")) == 0)) { | ||
154 | ck_abort_msg("Bad filename"); | ||
155 | } | ||
156 | |||
157 | uint8_t file_id[TOX_FILE_ID_LENGTH]; | ||
158 | |||
159 | if (!tox_file_get_file_id(tox, friend_number, file_number, file_id, nullptr)) { | ||
160 | ck_abort_msg("tox_file_get_file_id error"); | ||
161 | } | ||
162 | |||
163 | if (memcmp(file_id, file_cmp_id, TOX_FILE_ID_LENGTH) != 0) { | ||
164 | ck_abort_msg("bad file_id"); | ||
165 | } | ||
166 | |||
167 | uint8_t empty[TOX_FILE_ID_LENGTH] = {0}; | ||
168 | |||
169 | if (memcmp(empty, file_cmp_id, TOX_FILE_ID_LENGTH) == 0) { | ||
170 | ck_abort_msg("empty file_id"); | ||
171 | } | ||
172 | |||
173 | file_size = filesize; | ||
174 | |||
175 | if (filesize) { | ||
176 | sending_pos = size_recv = 1337; | ||
177 | |||
178 | TOX_ERR_FILE_SEEK err_s; | ||
179 | |||
180 | if (!tox_file_seek(tox, friend_number, file_number, 1337, &err_s)) { | ||
181 | ck_abort_msg("tox_file_seek error"); | ||
182 | } | ||
183 | |||
184 | ck_assert_msg(err_s == TOX_ERR_FILE_SEEK_OK, "tox_file_seek wrong error"); | ||
185 | } else { | ||
186 | sending_pos = size_recv = 0; | ||
187 | } | ||
188 | |||
189 | TOX_ERR_FILE_CONTROL error; | ||
190 | |||
191 | if (tox_file_control(tox, friend_number, file_number, TOX_FILE_CONTROL_RESUME, &error)) { | ||
192 | ++file_accepted; | ||
193 | } else { | ||
194 | ck_abort_msg("tox_file_control failed. %i", error); | ||
195 | } | ||
196 | |||
197 | TOX_ERR_FILE_SEEK err_s; | ||
198 | |||
199 | if (tox_file_seek(tox, friend_number, file_number, 1234, &err_s)) { | ||
200 | ck_abort_msg("tox_file_seek no error"); | ||
201 | } | ||
202 | |||
203 | ck_assert_msg(err_s == TOX_ERR_FILE_SEEK_DENIED, "tox_file_seek wrong error"); | ||
204 | } | ||
205 | |||
206 | static uint32_t sendf_ok; | ||
207 | static void file_print_control(Tox *tox, uint32_t friend_number, uint32_t file_number, TOX_FILE_CONTROL control, | ||
208 | void *userdata) | ||
209 | { | ||
210 | if (*((uint32_t *)userdata) != 974536) { | ||
211 | return; | ||
212 | } | ||
213 | |||
214 | /* First send file num is 0.*/ | ||
215 | if (file_number == 0 && control == TOX_FILE_CONTROL_RESUME) { | ||
216 | sendf_ok = 1; | ||
217 | } | ||
218 | } | ||
219 | |||
220 | static uint64_t max_sending; | ||
221 | static bool m_send_reached; | ||
222 | static uint8_t sending_num; | ||
223 | static bool file_sending_done; | ||
224 | static void tox_file_chunk_request(Tox *tox, uint32_t friend_number, uint32_t file_number, uint64_t position, | ||
225 | size_t length, | ||
226 | void *user_data) | ||
227 | { | ||
228 | if (*((uint32_t *)user_data) != 974536) { | ||
229 | return; | ||
230 | } | ||
231 | |||
232 | if (!sendf_ok) { | ||
233 | ck_abort_msg("Didn't get resume control"); | ||
234 | } | ||
235 | |||
236 | if (sending_pos != position) { | ||
237 | ck_abort_msg("Bad position %llu", (unsigned long long)position); | ||
238 | } | ||
239 | |||
240 | if (length == 0) { | ||
241 | if (file_sending_done) { | ||
242 | ck_abort_msg("File sending already done."); | ||
243 | } | ||
244 | |||
245 | file_sending_done = 1; | ||
246 | return; | ||
247 | } | ||
248 | |||
249 | if (position + length > max_sending) { | ||
250 | if (m_send_reached) { | ||
251 | ck_abort_msg("Requested done file transfer."); | ||
252 | } | ||
253 | |||
254 | length = max_sending - position; | ||
255 | m_send_reached = 1; | ||
256 | } | ||
257 | |||
258 | TOX_ERR_FILE_SEND_CHUNK error; | ||
259 | VLA(uint8_t, f_data, length); | ||
260 | memset(f_data, sending_num, length); | ||
261 | |||
262 | if (tox_file_send_chunk(tox, friend_number, file_number, position, f_data, length, &error)) { | ||
263 | ++sending_num; | ||
264 | sending_pos += length; | ||
265 | } else { | ||
266 | ck_abort_msg("Could not send chunk %i", error); | ||
267 | } | ||
268 | |||
269 | if (error != TOX_ERR_FILE_SEND_CHUNK_OK) { | ||
270 | ck_abort_msg("Wrong error code"); | ||
271 | } | ||
272 | } | ||
273 | |||
274 | |||
275 | static uint8_t num; | ||
276 | static bool file_recv; | ||
277 | static void write_file(Tox *tox, uint32_t friendnumber, uint32_t filenumber, uint64_t position, const uint8_t *data, | ||
278 | size_t length, void *user_data) | ||
279 | { | ||
280 | if (*((uint32_t *)user_data) != 974536) { | ||
281 | return; | ||
282 | } | ||
283 | |||
284 | if (size_recv != position) { | ||
285 | ck_abort_msg("Bad position"); | ||
286 | } | ||
287 | |||
288 | if (length == 0) { | ||
289 | file_recv = 1; | ||
290 | return; | ||
291 | } | ||
292 | |||
293 | VLA(uint8_t, f_data, length); | ||
294 | memset(f_data, num, length); | ||
295 | ++num; | ||
296 | |||
297 | if (memcmp(f_data, data, length) == 0) { | ||
298 | size_recv += length; | ||
299 | } else { | ||
300 | ck_abort_msg("FILE_CORRUPTED"); | ||
301 | } | ||
302 | } | ||
303 | |||
304 | static unsigned int connected_t1; | 136 | static unsigned int connected_t1; |
305 | static void tox_connection_status(Tox *tox, TOX_CONNECTION connection_status, void *user_data) | 137 | static void tox_connection_status(Tox *tox, TOX_CONNECTION connection_status, void *user_data) |
306 | { | 138 | { |
@@ -578,149 +410,6 @@ START_TEST(test_few_clients) | |||
578 | c_sleep(50); | 410 | c_sleep(50); |
579 | } | 411 | } |
580 | 412 | ||
581 | printf("Starting file transfer test.\n"); | ||
582 | |||
583 | file_accepted = file_size = sendf_ok = size_recv = 0; | ||
584 | file_recv = 0; | ||
585 | max_sending = UINT64_MAX; | ||
586 | long long unsigned int f_time = time(nullptr); | ||
587 | tox_callback_file_recv_chunk(tox3, write_file); | ||
588 | tox_callback_file_recv_control(tox2, file_print_control); | ||
589 | tox_callback_file_chunk_request(tox2, tox_file_chunk_request); | ||
590 | tox_callback_file_recv_control(tox3, file_print_control); | ||
591 | tox_callback_file_recv(tox3, tox_file_receive); | ||
592 | uint64_t totalf_size = 100 * 1024 * 1024; | ||
593 | uint32_t fnum = tox_file_send(tox2, 0, TOX_FILE_KIND_DATA, totalf_size, nullptr, (const uint8_t *)"Gentoo.exe", | ||
594 | sizeof("Gentoo.exe"), nullptr); | ||
595 | ck_assert_msg(fnum != UINT32_MAX, "tox_new_file_sender fail"); | ||
596 | |||
597 | TOX_ERR_FILE_GET gfierr; | ||
598 | ck_assert_msg(!tox_file_get_file_id(tox2, 1, fnum, file_cmp_id, &gfierr), "tox_file_get_file_id didn't fail"); | ||
599 | ck_assert_msg(gfierr == TOX_ERR_FILE_GET_FRIEND_NOT_FOUND, "wrong error"); | ||
600 | ck_assert_msg(!tox_file_get_file_id(tox2, 0, fnum + 1, file_cmp_id, &gfierr), "tox_file_get_file_id didn't fail"); | ||
601 | ck_assert_msg(gfierr == TOX_ERR_FILE_GET_NOT_FOUND, "wrong error"); | ||
602 | ck_assert_msg(tox_file_get_file_id(tox2, 0, fnum, file_cmp_id, &gfierr), "tox_file_get_file_id failed"); | ||
603 | ck_assert_msg(gfierr == TOX_ERR_FILE_GET_OK, "wrong error"); | ||
604 | |||
605 | while (1) { | ||
606 | tox_iterate(tox1, &to_compare); | ||
607 | tox_iterate(tox2, &to_compare); | ||
608 | tox_iterate(tox3, &to_compare); | ||
609 | |||
610 | if (file_sending_done) { | ||
611 | if (sendf_ok && file_recv && totalf_size == file_size && size_recv == file_size && sending_pos == size_recv | ||
612 | && file_accepted == 1) { | ||
613 | break; | ||
614 | } | ||
615 | |||
616 | ck_abort_msg("Something went wrong in file transfer %u %u %u %u %u %u %llu %llu %llu", sendf_ok, file_recv, | ||
617 | totalf_size == file_size, size_recv == file_size, sending_pos == size_recv, file_accepted == 1, | ||
618 | (unsigned long long)totalf_size, (unsigned long long)size_recv, | ||
619 | (unsigned long long)sending_pos); | ||
620 | } | ||
621 | |||
622 | uint32_t tox1_interval = tox_iteration_interval(tox1); | ||
623 | uint32_t tox2_interval = tox_iteration_interval(tox2); | ||
624 | uint32_t tox3_interval = tox_iteration_interval(tox3); | ||
625 | |||
626 | c_sleep(MIN(tox1_interval, MIN(tox2_interval, tox3_interval))); | ||
627 | } | ||
628 | |||
629 | printf("100MB file sent in %llu seconds\n", time(nullptr) - f_time); | ||
630 | |||
631 | printf("Starting file streaming transfer test.\n"); | ||
632 | |||
633 | file_sending_done = file_accepted = file_size = sendf_ok = size_recv = 0; | ||
634 | file_recv = 0; | ||
635 | tox_callback_file_recv_chunk(tox3, write_file); | ||
636 | tox_callback_file_recv_control(tox2, file_print_control); | ||
637 | tox_callback_file_chunk_request(tox2, tox_file_chunk_request); | ||
638 | tox_callback_file_recv_control(tox3, file_print_control); | ||
639 | tox_callback_file_recv(tox3, tox_file_receive); | ||
640 | totalf_size = UINT64_MAX; | ||
641 | fnum = tox_file_send(tox2, 0, TOX_FILE_KIND_DATA, totalf_size, nullptr, | ||
642 | (const uint8_t *)"Gentoo.exe", sizeof("Gentoo.exe"), nullptr); | ||
643 | ck_assert_msg(fnum != UINT32_MAX, "tox_new_file_sender fail"); | ||
644 | |||
645 | ck_assert_msg(!tox_file_get_file_id(tox2, 1, fnum, file_cmp_id, &gfierr), "tox_file_get_file_id didn't fail"); | ||
646 | ck_assert_msg(gfierr == TOX_ERR_FILE_GET_FRIEND_NOT_FOUND, "wrong error"); | ||
647 | ck_assert_msg(!tox_file_get_file_id(tox2, 0, fnum + 1, file_cmp_id, &gfierr), "tox_file_get_file_id didn't fail"); | ||
648 | ck_assert_msg(gfierr == TOX_ERR_FILE_GET_NOT_FOUND, "wrong error"); | ||
649 | ck_assert_msg(tox_file_get_file_id(tox2, 0, fnum, file_cmp_id, &gfierr), "tox_file_get_file_id failed"); | ||
650 | ck_assert_msg(gfierr == TOX_ERR_FILE_GET_OK, "wrong error"); | ||
651 | |||
652 | max_sending = 100 * 1024; | ||
653 | m_send_reached = 0; | ||
654 | |||
655 | while (1) { | ||
656 | tox_iterate(tox1, &to_compare); | ||
657 | tox_iterate(tox2, &to_compare); | ||
658 | tox_iterate(tox3, &to_compare); | ||
659 | |||
660 | if (file_sending_done) { | ||
661 | if (sendf_ok && file_recv && m_send_reached && totalf_size == file_size && size_recv == max_sending | ||
662 | && sending_pos == size_recv && file_accepted == 1) { | ||
663 | break; | ||
664 | } | ||
665 | |||
666 | ck_abort_msg("Something went wrong in file transfer %u %u %u %u %u %u %u %llu %llu %llu %llu", sendf_ok, file_recv, | ||
667 | m_send_reached, totalf_size == file_size, size_recv == max_sending, sending_pos == size_recv, file_accepted == 1, | ||
668 | (unsigned long long)totalf_size, (unsigned long long)file_size, | ||
669 | (unsigned long long)size_recv, (unsigned long long)sending_pos); | ||
670 | } | ||
671 | |||
672 | uint32_t tox1_interval = tox_iteration_interval(tox1); | ||
673 | uint32_t tox2_interval = tox_iteration_interval(tox2); | ||
674 | uint32_t tox3_interval = tox_iteration_interval(tox3); | ||
675 | |||
676 | c_sleep(MIN(tox1_interval, MIN(tox2_interval, tox3_interval))); | ||
677 | } | ||
678 | |||
679 | printf("Starting file 0 transfer test.\n"); | ||
680 | |||
681 | file_sending_done = file_accepted = file_size = sendf_ok = size_recv = 0; | ||
682 | file_recv = 0; | ||
683 | tox_callback_file_recv_chunk(tox3, write_file); | ||
684 | tox_callback_file_recv_control(tox2, file_print_control); | ||
685 | tox_callback_file_chunk_request(tox2, tox_file_chunk_request); | ||
686 | tox_callback_file_recv_control(tox3, file_print_control); | ||
687 | tox_callback_file_recv(tox3, tox_file_receive); | ||
688 | totalf_size = 0; | ||
689 | fnum = tox_file_send(tox2, 0, TOX_FILE_KIND_DATA, totalf_size, nullptr, | ||
690 | (const uint8_t *)"Gentoo.exe", sizeof("Gentoo.exe"), nullptr); | ||
691 | ck_assert_msg(fnum != UINT32_MAX, "tox_new_file_sender fail"); | ||
692 | |||
693 | ck_assert_msg(!tox_file_get_file_id(tox2, 1, fnum, file_cmp_id, &gfierr), "tox_file_get_file_id didn't fail"); | ||
694 | ck_assert_msg(gfierr == TOX_ERR_FILE_GET_FRIEND_NOT_FOUND, "wrong error"); | ||
695 | ck_assert_msg(!tox_file_get_file_id(tox2, 0, fnum + 1, file_cmp_id, &gfierr), "tox_file_get_file_id didn't fail"); | ||
696 | ck_assert_msg(gfierr == TOX_ERR_FILE_GET_NOT_FOUND, "wrong error"); | ||
697 | ck_assert_msg(tox_file_get_file_id(tox2, 0, fnum, file_cmp_id, &gfierr), "tox_file_get_file_id failed"); | ||
698 | ck_assert_msg(gfierr == TOX_ERR_FILE_GET_OK, "wrong error"); | ||
699 | |||
700 | while (1) { | ||
701 | tox_iterate(tox1, &to_compare); | ||
702 | tox_iterate(tox2, &to_compare); | ||
703 | tox_iterate(tox3, &to_compare); | ||
704 | |||
705 | if (file_sending_done) { | ||
706 | if (sendf_ok && file_recv && totalf_size == file_size && size_recv == file_size && sending_pos == size_recv | ||
707 | && file_accepted == 1) { | ||
708 | break; | ||
709 | } | ||
710 | |||
711 | ck_abort_msg("Something went wrong in file transfer %u %u %u %u %u %u %llu %llu %llu", sendf_ok, file_recv, | ||
712 | totalf_size == file_size, size_recv == file_size, sending_pos == size_recv, file_accepted == 1, | ||
713 | (unsigned long long)totalf_size, (unsigned long long)size_recv, | ||
714 | (unsigned long long)sending_pos); | ||
715 | } | ||
716 | |||
717 | uint32_t tox1_interval = tox_iteration_interval(tox1); | ||
718 | uint32_t tox2_interval = tox_iteration_interval(tox2); | ||
719 | uint32_t tox3_interval = tox_iteration_interval(tox3); | ||
720 | |||
721 | c_sleep(MIN(tox1_interval, MIN(tox2_interval, tox3_interval))); | ||
722 | } | ||
723 | |||
724 | printf("test_few_clients succeeded, took %llu seconds\n", time(nullptr) - cur_time); | 413 | printf("test_few_clients succeeded, took %llu seconds\n", time(nullptr) - cur_time); |
725 | 414 | ||
726 | tox_options_free(options); | 415 | tox_options_free(options); |
diff --git a/toxcore/Messenger.c b/toxcore/Messenger.c index 3baf7401..a6bccfdc 100644 --- a/toxcore/Messenger.c +++ b/toxcore/Messenger.c | |||
@@ -1482,119 +1482,159 @@ uint64_t file_dataremaining(const Messenger *m, int32_t friendnumber, uint8_t fi | |||
1482 | return 0; | 1482 | return 0; |
1483 | } | 1483 | } |
1484 | 1484 | ||
1485 | const struct File_Transfers *const sending = &m->friendlist[friendnumber].file_sending[filenumber]; | ||
1486 | |||
1485 | if (send_receive == 0) { | 1487 | if (send_receive == 0) { |
1486 | if (m->friendlist[friendnumber].file_sending[filenumber].status == FILESTATUS_NONE) { | 1488 | if (sending->status == FILESTATUS_NONE) { |
1487 | return 0; | 1489 | return 0; |
1488 | } | 1490 | } |
1489 | 1491 | ||
1490 | return m->friendlist[friendnumber].file_sending[filenumber].size - | 1492 | return sending->size - sending->transferred; |
1491 | m->friendlist[friendnumber].file_sending[filenumber].transferred; | ||
1492 | } | 1493 | } |
1493 | 1494 | ||
1494 | if (m->friendlist[friendnumber].file_receiving[filenumber].status == FILESTATUS_NONE) { | 1495 | const struct File_Transfers *const receiving = &m->friendlist[friendnumber].file_receiving[filenumber]; |
1496 | |||
1497 | if (receiving->status == FILESTATUS_NONE) { | ||
1495 | return 0; | 1498 | return 0; |
1496 | } | 1499 | } |
1497 | 1500 | ||
1498 | return m->friendlist[friendnumber].file_receiving[filenumber].size - | 1501 | return receiving->size - receiving->transferred; |
1499 | m->friendlist[friendnumber].file_receiving[filenumber].transferred; | ||
1500 | } | 1502 | } |
1501 | 1503 | ||
1502 | static void do_reqchunk_filecb(Messenger *m, int32_t friendnumber, void *userdata) | 1504 | /** |
1505 | * Iterate over all file transfers and request chunks (from the client) for each | ||
1506 | * of them. | ||
1507 | * | ||
1508 | * The free_slots parameter is updated by this function. | ||
1509 | * | ||
1510 | * @param m Our messenger object. | ||
1511 | * @param friendnumber The friend we're sending files to. | ||
1512 | * @param userdata The client userdata to pass along to chunk request callbacks. | ||
1513 | * @param free_slots A pointer to the number of free send queue slots in the | ||
1514 | * crypto connection. | ||
1515 | * | ||
1516 | * @return true if there are still file transfers ongoing, false if all file | ||
1517 | * transfers are complete. | ||
1518 | */ | ||
1519 | static bool do_all_filetransfers(Messenger *m, int32_t friendnumber, void *userdata, uint32_t *free_slots) | ||
1503 | { | 1520 | { |
1504 | if (!m->friendlist[friendnumber].num_sending_files) { | 1521 | Friend *const friendcon = &m->friendlist[friendnumber]; |
1505 | return; | 1522 | uint32_t num = friendcon->num_sending_files; |
1506 | } | ||
1507 | 1523 | ||
1508 | int free_slots = crypto_num_free_sendqueue_slots(m->net_crypto, friend_connection_crypt_connection_id(m->fr_c, | 1524 | bool any_active_fts = false; |
1509 | m->friendlist[friendnumber].friendcon_id)); | ||
1510 | |||
1511 | if (free_slots < MIN_SLOTS_FREE) { | ||
1512 | free_slots = 0; | ||
1513 | } else { | ||
1514 | free_slots -= MIN_SLOTS_FREE; | ||
1515 | } | ||
1516 | 1525 | ||
1517 | unsigned int i, num = m->friendlist[friendnumber].num_sending_files; | 1526 | // Iterate over all file transfers, including inactive ones. I.e. we always |
1518 | 1527 | // iterate exactly MAX_CONCURRENT_FILE_PIPES times. | |
1519 | for (i = 0; i < MAX_CONCURRENT_FILE_PIPES; ++i) { | 1528 | for (uint32_t i = 0; i < MAX_CONCURRENT_FILE_PIPES; ++i) { |
1520 | struct File_Transfers *ft = &m->friendlist[friendnumber].file_sending[i]; | 1529 | struct File_Transfers *const ft = &friendcon->file_sending[i]; |
1521 | 1530 | ||
1531 | // Any status other than NONE means the file transfer is active. | ||
1522 | if (ft->status != FILESTATUS_NONE) { | 1532 | if (ft->status != FILESTATUS_NONE) { |
1533 | any_active_fts = true; | ||
1523 | --num; | 1534 | --num; |
1524 | 1535 | ||
1525 | if (ft->status == FILESTATUS_FINISHED) { | 1536 | // If the file transfer is complete, we request a chunk of size 0. |
1526 | /* Check if file was entirely sent. */ | 1537 | if (ft->status == FILESTATUS_FINISHED && friend_received_packet(m, friendnumber, ft->last_packet_number) == 0) { |
1527 | if (friend_received_packet(m, friendnumber, ft->last_packet_number) == 0) { | 1538 | if (m->file_reqchunk) { |
1528 | if (m->file_reqchunk) { | 1539 | m->file_reqchunk(m, friendnumber, i, ft->transferred, 0, userdata); |
1529 | (*m->file_reqchunk)(m, friendnumber, i, ft->transferred, 0, userdata); | ||
1530 | } | ||
1531 | |||
1532 | ft->status = FILESTATUS_NONE; | ||
1533 | --m->friendlist[friendnumber].num_sending_files; | ||
1534 | } | 1540 | } |
1535 | } | ||
1536 | 1541 | ||
1537 | /* TODO(irungentoo): if file is too slow, switch to the next. */ | 1542 | // Now it's inactive, we're no longer sending this. |
1538 | if (ft->slots_allocated > (unsigned int)free_slots) { | 1543 | ft->status = FILESTATUS_NONE; |
1539 | free_slots = 0; | 1544 | --friendcon->num_sending_files; |
1540 | } else { | ||
1541 | free_slots -= ft->slots_allocated; | ||
1542 | } | 1545 | } |
1546 | |||
1547 | // Decrease free slots by the number of slots this FT uses. | ||
1548 | *free_slots = max_s32(0, (int32_t) * free_slots - ft->slots_allocated); | ||
1543 | } | 1549 | } |
1544 | 1550 | ||
1545 | while (ft->status == FILESTATUS_TRANSFERRING && (ft->paused == FILE_PAUSE_NOT)) { | 1551 | if (ft->status == FILESTATUS_TRANSFERRING && ft->paused == FILE_PAUSE_NOT) { |
1546 | if (max_speed_reached(m->net_crypto, friend_connection_crypt_connection_id(m->fr_c, | 1552 | if (max_speed_reached(m->net_crypto, friend_connection_crypt_connection_id( |
1547 | m->friendlist[friendnumber].friendcon_id))) { | 1553 | m->fr_c, friendcon->friendcon_id))) { |
1548 | free_slots = 0; | 1554 | *free_slots = 0; |
1549 | } | 1555 | } |
1550 | 1556 | ||
1551 | if (free_slots == 0) { | 1557 | if (*free_slots == 0) { |
1552 | break; | 1558 | continue; |
1553 | } | 1559 | } |
1554 | 1560 | ||
1555 | uint16_t length = MAX_FILE_DATA_SIZE; | ||
1556 | |||
1557 | if (ft->size == 0) { | 1561 | if (ft->size == 0) { |
1558 | /* Send 0 data to friend if file is 0 length. */ | 1562 | /* Send 0 data to friend if file is 0 length. */ |
1559 | file_data(m, friendnumber, i, 0, nullptr, 0); | 1563 | file_data(m, friendnumber, i, 0, nullptr, 0); |
1560 | break; | 1564 | continue; |
1561 | } | 1565 | } |
1562 | 1566 | ||
1563 | if (ft->size == ft->requested) { | 1567 | if (ft->size == ft->requested) { |
1564 | break; | 1568 | // This file transfer is done. |
1565 | } | 1569 | continue; |
1566 | |||
1567 | if (ft->size - ft->requested < length) { | ||
1568 | length = ft->size - ft->requested; | ||
1569 | } | 1570 | } |
1570 | 1571 | ||
1571 | ++ft->slots_allocated; | 1572 | // Allocate 1 slot to this file transfer. |
1573 | ft->slots_allocated++; | ||
1572 | 1574 | ||
1573 | uint64_t position = ft->requested; | 1575 | const uint16_t length = min_u64(ft->size - ft->requested, MAX_FILE_DATA_SIZE); |
1576 | const uint64_t position = ft->requested; | ||
1574 | ft->requested += length; | 1577 | ft->requested += length; |
1575 | 1578 | ||
1576 | if (m->file_reqchunk) { | 1579 | if (m->file_reqchunk) { |
1577 | (*m->file_reqchunk)(m, friendnumber, i, position, length, userdata); | 1580 | m->file_reqchunk(m, friendnumber, i, position, length, userdata); |
1578 | } | 1581 | } |
1579 | 1582 | ||
1580 | --free_slots; | 1583 | // The allocated slot is no longer free. |
1584 | --*free_slots; | ||
1581 | } | 1585 | } |
1582 | 1586 | ||
1583 | if (num == 0) { | 1587 | if (num == 0) { |
1584 | break; | 1588 | continue; |
1585 | } | 1589 | } |
1586 | } | 1590 | } |
1591 | |||
1592 | return any_active_fts; | ||
1587 | } | 1593 | } |
1588 | 1594 | ||
1595 | static void do_reqchunk_filecb(Messenger *m, int32_t friendnumber, void *userdata) | ||
1596 | { | ||
1597 | // We're not currently doing any file transfers. | ||
1598 | if (m->friendlist[friendnumber].num_sending_files == 0) { | ||
1599 | return; | ||
1600 | } | ||
1601 | |||
1602 | // The number of packet slots left in the sendbuffer. | ||
1603 | // This is a per friend count (CRYPTO_PACKET_BUFFER_SIZE). | ||
1604 | uint32_t free_slots = crypto_num_free_sendqueue_slots( | ||
1605 | m->net_crypto, | ||
1606 | friend_connection_crypt_connection_id( | ||
1607 | m->fr_c, | ||
1608 | m->friendlist[friendnumber].friendcon_id)); | ||
1609 | |||
1610 | // We keep MIN_SLOTS_FREE slots free for other packets, otherwise file | ||
1611 | // transfers might block other traffic for a long time. | ||
1612 | free_slots = max_s32(0, (int32_t)free_slots - MIN_SLOTS_FREE); | ||
1613 | |||
1614 | bool any_active_fts = true; | ||
1615 | uint32_t loop_counter = 0; | ||
1616 | // Maximum number of outer loops below. If the client doesn't send file | ||
1617 | // chunks from within the chunk request callback handler, we never realise | ||
1618 | // that the file transfer has finished and may end up in an infinite loop. | ||
1619 | // | ||
1620 | // TODO(zoff99): Fix this to exit the loop properly when we're done | ||
1621 | // requesting all chunks for all file transfers. | ||
1622 | const uint32_t MAX_FT_LOOPS = 4; | ||
1623 | |||
1624 | while (((free_slots > 0) || loop_counter == 0) && any_active_fts && (loop_counter < MAX_FT_LOOPS)) { | ||
1625 | any_active_fts = do_all_filetransfers(m, friendnumber, userdata, &free_slots); | ||
1626 | loop_counter++; | ||
1627 | } | ||
1628 | } | ||
1629 | |||
1630 | |||
1589 | /* Run this when the friend disconnects. | 1631 | /* Run this when the friend disconnects. |
1590 | * Kill all current file transfers. | 1632 | * Kill all current file transfers. |
1591 | */ | 1633 | */ |
1592 | static void break_files(const Messenger *m, int32_t friendnumber) | 1634 | static void break_files(const Messenger *m, int32_t friendnumber) |
1593 | { | 1635 | { |
1594 | uint32_t i; | ||
1595 | |||
1596 | // TODO(irungentoo): Inform the client which file transfers get killed with a callback? | 1636 | // TODO(irungentoo): Inform the client which file transfers get killed with a callback? |
1597 | for (i = 0; i < MAX_CONCURRENT_FILE_PIPES; ++i) { | 1637 | for (uint32_t i = 0; i < MAX_CONCURRENT_FILE_PIPES; ++i) { |
1598 | if (m->friendlist[friendnumber].file_sending[i].status != FILESTATUS_NONE) { | 1638 | if (m->friendlist[friendnumber].file_sending[i].status != FILESTATUS_NONE) { |
1599 | m->friendlist[friendnumber].file_sending[i].status = FILESTATUS_NONE; | 1639 | m->friendlist[friendnumber].file_sending[i].status = FILESTATUS_NONE; |
1600 | } | 1640 | } |
diff --git a/toxcore/Messenger.h b/toxcore/Messenger.h index 6bf1bce8..956f8ac5 100644 --- a/toxcore/Messenger.h +++ b/toxcore/Messenger.h | |||
@@ -206,7 +206,7 @@ typedef struct { | |||
206 | uint64_t last_seen_time; | 206 | uint64_t last_seen_time; |
207 | uint8_t last_connection_udp_tcp; | 207 | uint8_t last_connection_udp_tcp; |
208 | struct File_Transfers file_sending[MAX_CONCURRENT_FILE_PIPES]; | 208 | struct File_Transfers file_sending[MAX_CONCURRENT_FILE_PIPES]; |
209 | unsigned int num_sending_files; | 209 | uint32_t num_sending_files; |
210 | struct File_Transfers file_receiving[MAX_CONCURRENT_FILE_PIPES]; | 210 | struct File_Transfers file_receiving[MAX_CONCURRENT_FILE_PIPES]; |
211 | 211 | ||
212 | struct { | 212 | struct { |
diff --git a/toxcore/util.c b/toxcore/util.c index ff612b1a..e19808a2 100644 --- a/toxcore/util.c +++ b/toxcore/util.c | |||
@@ -195,3 +195,13 @@ int create_recursive_mutex(pthread_mutex_t *mutex) | |||
195 | 195 | ||
196 | return 0; | 196 | return 0; |
197 | } | 197 | } |
198 | |||
199 | int32_t max_s32(int32_t a, int32_t b) | ||
200 | { | ||
201 | return a > b ? a : b; | ||
202 | } | ||
203 | |||
204 | uint64_t min_u64(uint64_t a, uint64_t b) | ||
205 | { | ||
206 | return a < b ? a : b; | ||
207 | } | ||
diff --git a/toxcore/util.h b/toxcore/util.h index 8c86158b..a9faa863 100644 --- a/toxcore/util.h +++ b/toxcore/util.h | |||
@@ -65,6 +65,9 @@ int load_state(load_state_callback_func load_state_callback, Logger *log, void * | |||
65 | /* Returns -1 if failed or 0 if success */ | 65 | /* Returns -1 if failed or 0 if success */ |
66 | int create_recursive_mutex(pthread_mutex_t *mutex); | 66 | int create_recursive_mutex(pthread_mutex_t *mutex); |
67 | 67 | ||
68 | int32_t max_s32(int32_t a, int32_t b); | ||
69 | uint64_t min_u64(uint64_t a, uint64_t b); | ||
70 | |||
68 | #ifdef __cplusplus | 71 | #ifdef __cplusplus |
69 | } // extern "C" | 72 | } // extern "C" |
70 | #endif | 73 | #endif |