/work/auto_tests/scenarios/scenario_file_transfer_test.c
Line | Count | Source (jump to first uncovered line) |
1 | | #include "framework/framework.h" |
2 | | #include <stdio.h> |
3 | | #include <string.h> |
4 | | #include <stdlib.h> |
5 | | |
6 | 1 | #define FILE_SIZE (1024 * 1024) |
7 | 2 | #define FILENAME "Gentoo.exe" |
8 | | |
9 | | typedef struct { |
10 | | bool file_received; |
11 | | bool file_sending_done; |
12 | | uint64_t size_recv; |
13 | | uint64_t sending_pos; |
14 | | uint8_t file_id[TOX_FILE_ID_LENGTH]; |
15 | | uint32_t file_accepted; |
16 | | uint64_t file_size; |
17 | | bool sendf_ok; |
18 | | uint8_t num; |
19 | | uint8_t sending_num; |
20 | | bool m_send_reached; |
21 | | } FileTransferState; |
22 | | |
23 | | static void on_file_receive(const Tox_Event_File_Recv *event, void *user_data) |
24 | 1 | { |
25 | 1 | ToxNode *self = (ToxNode *)user_data; |
26 | 1 | FileTransferState *state = (FileTransferState *)tox_node_get_script_ctx(self); |
27 | | |
28 | 1 | const uint32_t friend_number = tox_event_file_recv_get_friend_number(event); |
29 | 1 | const uint32_t file_number = tox_event_file_recv_get_file_number(event); |
30 | 1 | const uint64_t filesize = tox_event_file_recv_get_file_size(event); |
31 | | |
32 | 1 | state->file_size = filesize; |
33 | 1 | state->sending_pos = state->size_recv = 0; |
34 | | |
35 | 1 | Tox_Err_File_Control error; |
36 | 1 | tox_file_control(tox_node_get_tox(self), friend_number, file_number, TOX_FILE_CONTROL_RESUME, &error); |
37 | 1 | state->file_accepted++; |
38 | 1 | tox_node_log(self, "File receive: %u bytes, accepted", (uint32_t)filesize); |
39 | 1 | } |
40 | | |
41 | | static void on_file_recv_control(const Tox_Event_File_Recv_Control *event, void *user_data) |
42 | 2 | { |
43 | 2 | ToxNode *self = (ToxNode *)user_data; |
44 | 2 | FileTransferState *state = (FileTransferState *)tox_node_get_script_ctx(self); |
45 | 2 | const Tox_File_Control control = tox_event_file_recv_control_get_control(event); |
46 | | |
47 | 2 | if (control == TOX_FILE_CONTROL_RESUME) { |
48 | 2 | state->sendf_ok = true; |
49 | 2 | tox_node_log(self, "Received RESUME control"); |
50 | 2 | } |
51 | 2 | } |
52 | | |
53 | | static void on_file_chunk_request(const Tox_Event_File_Chunk_Request *event, void *user_data) |
54 | 766 | { |
55 | 766 | ToxNode *self = (ToxNode *)user_data; |
56 | 766 | FileTransferState *state = (FileTransferState *)tox_node_get_script_ctx(self); |
57 | | |
58 | 766 | const uint32_t friend_number = tox_event_file_chunk_request_get_friend_number(event); |
59 | 766 | const uint32_t file_number = tox_event_file_chunk_request_get_file_number(event); |
60 | 766 | const uint64_t position = tox_event_file_chunk_request_get_position(event); |
61 | 766 | size_t length = tox_event_file_chunk_request_get_length(event); |
62 | | |
63 | 766 | if (length == 0) { |
64 | 1 | state->file_sending_done = true; |
65 | 1 | tox_node_log(self, "File sending done"); |
66 | 1 | return; |
67 | 1 | } |
68 | | |
69 | 765 | uint8_t *f_data = (uint8_t *)malloc(length); |
70 | 765 | memset(f_data, state->sending_num, length); |
71 | | |
72 | 765 | tox_file_send_chunk(tox_node_get_tox(self), friend_number, file_number, position, f_data, length, nullptr); |
73 | 765 | free(f_data); |
74 | | |
75 | 765 | state->sending_num++; |
76 | 765 | state->sending_pos += length; |
77 | 765 | } |
78 | | |
79 | | static void on_file_recv_chunk(const Tox_Event_File_Recv_Chunk *event, void *user_data) |
80 | 766 | { |
81 | 766 | ToxNode *self = (ToxNode *)user_data; |
82 | 766 | FileTransferState *state = (FileTransferState *)tox_node_get_script_ctx(self); |
83 | | |
84 | 766 | const size_t length = tox_event_file_recv_chunk_get_data_length(event); |
85 | | |
86 | 766 | if (length == 0) { |
87 | 1 | state->file_received = true; |
88 | 1 | tox_node_log(self, "File reception done"); |
89 | 1 | return; |
90 | 1 | } |
91 | | |
92 | 765 | state->num++; |
93 | 765 | state->size_recv += length; |
94 | 765 | } |
95 | | |
96 | | static void sender_script(ToxNode *self, void *ctx) |
97 | 1 | { |
98 | 1 | const FileTransferState *state = (const FileTransferState *)ctx; |
99 | | |
100 | 1 | tox_events_callback_file_recv_control(tox_node_get_dispatch(self), on_file_recv_control); |
101 | 1 | tox_events_callback_file_chunk_request(tox_node_get_dispatch(self), on_file_chunk_request); |
102 | | |
103 | 1 | WAIT_UNTIL(tox_node_is_self_connected(self)); |
104 | 1 | WAIT_UNTIL(tox_node_is_friend_connected(self, 0)); |
105 | | |
106 | 1 | uint32_t fnum = tox_file_send(tox_node_get_tox(self), 0, TOX_FILE_KIND_DATA, FILE_SIZE, nullptr, (const uint8_t *)FILENAME, sizeof(FILENAME), nullptr); |
107 | 1 | tox_node_log(self, "Started sending file %u", fnum); |
108 | | |
109 | 1 | Tox_File_Id file_id; |
110 | 1 | if (!tox_file_get_file_id(tox_node_get_tox(self), 0, fnum, file_id, nullptr)) { |
111 | 0 | tox_node_log(self, "Failed to get file id for file %u", fnum); |
112 | 0 | abort(); |
113 | 0 | } |
114 | | |
115 | 1 | Tox_Err_File_By_Id err; |
116 | 1 | Tox_File_Number found_fnum = tox_file_by_id(tox_node_get_tox(self), 0, file_id, &err); |
117 | 1 | if (found_fnum != fnum) { |
118 | 0 | tox_node_log(self, "tox_file_by_id failed: expected %u, got %u, error %u", fnum, found_fnum, err); |
119 | 0 | abort(); |
120 | 0 | } |
121 | | |
122 | | /* Test with invalid friend number */ |
123 | 1 | found_fnum = tox_file_by_id(tox_node_get_tox(self), 1234, file_id, &err); |
124 | 1 | if (found_fnum != UINT32_MAX || err != TOX_ERR_FILE_BY_ID_FRIEND_NOT_FOUND) { |
125 | 0 | tox_node_log(self, "tox_file_by_id with invalid friend failed: expected UINT32_MAX and FRIEND_NOT_FOUND, got %u and error %u", found_fnum, err); |
126 | 0 | abort(); |
127 | 0 | } |
128 | | |
129 | | /* Test with invalid file id */ |
130 | 1 | Tox_File_Id invalid_id = {0}; |
131 | 1 | found_fnum = tox_file_by_id(tox_node_get_tox(self), 0, invalid_id, &err); |
132 | 1 | if (found_fnum != UINT32_MAX || err != TOX_ERR_FILE_BY_ID_NOT_FOUND) { |
133 | 0 | tox_node_log(self, "tox_file_by_id with invalid id failed: expected UINT32_MAX and NOT_FOUND, got %u and error %u", found_fnum, err); |
134 | 0 | abort(); |
135 | 0 | } |
136 | | |
137 | 1 | WAIT_UNTIL(state->file_sending_done); |
138 | 1 | tox_node_log(self, "Done"); |
139 | 1 | } |
140 | | |
141 | | static void receiver_script(ToxNode *self, void *ctx) |
142 | 1 | { |
143 | 1 | const FileTransferState *state = (const FileTransferState *)ctx; |
144 | | |
145 | 1 | tox_events_callback_file_recv(tox_node_get_dispatch(self), on_file_receive); |
146 | 1 | tox_events_callback_file_recv_chunk(tox_node_get_dispatch(self), on_file_recv_chunk); |
147 | | |
148 | 1 | WAIT_UNTIL(tox_node_is_self_connected(self)); |
149 | | |
150 | 1 | WAIT_UNTIL(state->file_received); |
151 | 1 | tox_node_log(self, "Done"); |
152 | 1 | } |
153 | | |
154 | | int main(int argc, char *argv[]) |
155 | 31 | { |
156 | 31 | ToxScenario *s = tox_scenario_new(argc, argv, 300000); |
157 | 31 | FileTransferState state_sender = {0}; |
158 | 31 | FileTransferState state_receiver = {0}; |
159 | | |
160 | 31 | ToxNode *sender = tox_scenario_add_node(s, "Sender", sender_script, &state_sender, sizeof(FileTransferState)); |
161 | 31 | ToxNode *receiver = tox_scenario_add_node(s, "Receiver", receiver_script, &state_receiver, sizeof(FileTransferState)); |
162 | | |
163 | 31 | tox_node_friend_add(sender, receiver); |
164 | 31 | tox_node_friend_add(receiver, sender); |
165 | 31 | tox_node_bootstrap(sender, receiver); |
166 | 31 | tox_node_bootstrap(receiver, sender); |
167 | | |
168 | 31 | ToxScenarioStatus res = tox_scenario_run(s); |
169 | 31 | if (res != TOX_SCENARIO_DONE) { |
170 | 0 | tox_scenario_log(s, "Test failed with status %u", res); |
171 | 0 | return 1; |
172 | 0 | } |
173 | | |
174 | 31 | tox_scenario_free(s); |
175 | 31 | return 0; |
176 | 31 | } |
177 | | |
178 | | #undef FILE_SIZE |