/work/auto_tests/conference_simple_test.c
Line | Count | Source (jump to first uncovered line) |
1 | | #include <stdio.h> |
2 | | #include <stdlib.h> |
3 | | |
4 | | #include "../testing/misc_tools.h" |
5 | | #include "../toxcore/tox.h" |
6 | | #include "../toxcore/tox_dispatch.h" |
7 | | #include "../toxcore/tox_events.h" |
8 | | #include "auto_test_support.h" |
9 | | #include "check_compat.h" |
10 | | |
11 | | typedef struct State { |
12 | | uint32_t id; |
13 | | Tox *tox; |
14 | | bool self_online; |
15 | | bool friend_online; |
16 | | bool invited_next; |
17 | | |
18 | | bool joined; |
19 | | uint32_t conference; |
20 | | |
21 | | bool received; |
22 | | |
23 | | uint32_t peers; |
24 | | } State; |
25 | | |
26 | | static void handle_self_connection_status(const Tox_Event_Self_Connection_Status *event, void *user_data) |
27 | 3 | { |
28 | 3 | State *state = (State *)user_data; |
29 | | |
30 | 3 | const Tox_Connection connection_status = tox_event_self_connection_status_get_connection_status(event); |
31 | 3 | fprintf(stderr, "self_connection_status(#%u, %u, _)\n", state->id, connection_status); |
32 | 3 | state->self_online = connection_status != TOX_CONNECTION_NONE; |
33 | 3 | } |
34 | | |
35 | | static void handle_friend_connection_status(const Tox_Event_Friend_Connection_Status *event, |
36 | | void *user_data) |
37 | 4 | { |
38 | 4 | State *state = (State *)user_data; |
39 | | |
40 | 4 | const uint32_t friend_number = tox_event_friend_connection_status_get_friend_number(event); |
41 | 4 | const Tox_Connection connection_status = tox_event_friend_connection_status_get_connection_status(event); |
42 | 4 | fprintf(stderr, "handle_friend_connection_status(#%u, %u, %u, _)\n", state->id, friend_number, connection_status); |
43 | 4 | state->friend_online = connection_status != TOX_CONNECTION_NONE; |
44 | 4 | } |
45 | | |
46 | | static void handle_conference_invite(const Tox_Event_Conference_Invite *event, void *user_data) |
47 | 3 | { |
48 | 3 | State *state = (State *)user_data; |
49 | | |
50 | 3 | const uint32_t friend_number = tox_event_conference_invite_get_friend_number(event); |
51 | 3 | const Tox_Conference_Type type = tox_event_conference_invite_get_type(event); |
52 | 3 | const uint8_t *cookie = tox_event_conference_invite_get_cookie(event); |
53 | 3 | const size_t length = tox_event_conference_invite_get_cookie_length(event); |
54 | 3 | fprintf(stderr, "handle_conference_invite(#%u, %u, %u, uint8_t[%u], _)\n", |
55 | 3 | state->id, friend_number, type, (unsigned)length); |
56 | 3 | fprintf(stderr, "tox%u joining conference\n", state->id); |
57 | | |
58 | 3 | { |
59 | 3 | Tox_Err_Conference_Join err; |
60 | 3 | state->conference = tox_conference_join(state->tox, friend_number, cookie, length, &err); |
61 | 3 | ck_assert_msg(err == TOX_ERR_CONFERENCE_JOIN_OK, "failed to join a conference: err = %u", err); |
62 | 3 | fprintf(stderr, "tox%u Joined conference %u\n", state->id, state->conference); |
63 | 3 | state->joined = true; |
64 | 3 | } |
65 | 3 | } |
66 | | |
67 | | static void handle_conference_message(const Tox_Event_Conference_Message *event, void *user_data) |
68 | 2 | { |
69 | 2 | State *state = (State *)user_data; |
70 | | |
71 | 2 | const uint32_t conference_number = tox_event_conference_message_get_conference_number(event); |
72 | 2 | const uint32_t peer_number = tox_event_conference_message_get_peer_number(event); |
73 | 2 | const Tox_Message_Type type = tox_event_conference_message_get_type(event); |
74 | 2 | const uint8_t *message = tox_event_conference_message_get_message(event); |
75 | 2 | const size_t length = tox_event_conference_message_get_message_length(event); |
76 | | |
77 | 2 | fprintf(stderr, "handle_conference_message(#%u, %u, %u, %u, uint8_t[%u], _)\n", |
78 | 2 | state->id, conference_number, peer_number, type, (unsigned)length); |
79 | | |
80 | 2 | fprintf(stderr, "tox%u got message: %s\n", state->id, (const char *)message); |
81 | 2 | state->received = true; |
82 | 2 | } |
83 | | |
84 | | static void handle_conference_peer_list_changed(const Tox_Event_Conference_Peer_List_Changed *event, void *user_data) |
85 | 8 | { |
86 | 8 | State *state = (State *)user_data; |
87 | | |
88 | 8 | const uint32_t conference_number = tox_event_conference_peer_list_changed_get_conference_number(event); |
89 | 8 | fprintf(stderr, "handle_conference_peer_list_changed(#%u, %u, _)\n", |
90 | 8 | state->id, conference_number); |
91 | | |
92 | 8 | Tox_Err_Conference_Peer_Query err; |
93 | 8 | uint32_t count = tox_conference_peer_count(state->tox, conference_number, &err); |
94 | | |
95 | 8 | if (err != TOX_ERR_CONFERENCE_PEER_QUERY_OK) { |
96 | 0 | fprintf(stderr, "ERROR: %u\n", err); |
97 | 0 | exit(EXIT_FAILURE); |
98 | 0 | } |
99 | | |
100 | 8 | fprintf(stderr, "tox%u has %u peers online\n", state->id, count); |
101 | 8 | state->peers = count; |
102 | 8 | } |
103 | | |
104 | | static void handle_conference_connected(const Tox_Event_Conference_Connected *event, void *user_data) |
105 | 2 | { |
106 | 2 | State *state = (State *)user_data; |
107 | | |
108 | | // We're tox2, so now we invite tox3. |
109 | 2 | if (state->id == 2 && !state->invited_next) { |
110 | 1 | Tox_Err_Conference_Invite err; |
111 | 1 | tox_conference_invite(state->tox, 1, state->conference, &err); |
112 | 1 | ck_assert_msg(err == TOX_ERR_CONFERENCE_INVITE_OK, "tox2 failed to invite tox3: err = %u", err); |
113 | | |
114 | 1 | state->invited_next = true; |
115 | 1 | fprintf(stderr, "tox2 invited tox3\n"); |
116 | 1 | } |
117 | 2 | } |
118 | | |
119 | | static void iterate_one( |
120 | | Tox *tox, State *state, const Tox_Dispatch *dispatch) |
121 | 291 | { |
122 | 291 | Tox_Err_Events_Iterate err; |
123 | 291 | Tox_Events *events = tox_events_iterate(tox, true, &err); |
124 | 291 | ck_assert(err == TOX_ERR_EVENTS_ITERATE_OK); |
125 | 291 | tox_dispatch_invoke(dispatch, events, state); |
126 | 291 | tox_events_free(events); |
127 | 291 | } |
128 | | |
129 | | static void iterate3_wait( |
130 | | State *state1, State *state2, State *state3, |
131 | | const Tox_Dispatch *dispatch, int interval) |
132 | 97 | { |
133 | 97 | iterate_one(state1->tox, state1, dispatch); |
134 | 97 | iterate_one(state2->tox, state2, dispatch); |
135 | 97 | iterate_one(state3->tox, state3, dispatch); |
136 | | |
137 | 97 | c_sleep(interval); |
138 | 97 | } |
139 | | |
140 | | int main(void) |
141 | 1 | { |
142 | 1 | setvbuf(stdout, nullptr, _IONBF, 0); |
143 | | |
144 | 1 | State state1 = {1}; |
145 | 1 | State state2 = {2}; |
146 | 1 | State state3 = {3}; |
147 | | |
148 | | // Create toxes. |
149 | 1 | state1.tox = tox_new_log(nullptr, nullptr, &state1.id); |
150 | 1 | state2.tox = tox_new_log(nullptr, nullptr, &state2.id); |
151 | 1 | state3.tox = tox_new_log(nullptr, nullptr, &state3.id); |
152 | | |
153 | 1 | tox_events_init(state1.tox); |
154 | 1 | tox_events_init(state2.tox); |
155 | 1 | tox_events_init(state3.tox); |
156 | | |
157 | | // tox1 <-> tox2, tox2 <-> tox3 |
158 | 1 | uint8_t key[TOX_PUBLIC_KEY_SIZE]; |
159 | 1 | tox_self_get_public_key(state2.tox, key); |
160 | 1 | tox_friend_add_norequest(state1.tox, key, nullptr); // tox1 -> tox2 |
161 | 1 | tox_self_get_public_key(state1.tox, key); |
162 | 1 | tox_friend_add_norequest(state2.tox, key, nullptr); // tox2 -> tox1 |
163 | 1 | tox_self_get_public_key(state3.tox, key); |
164 | 1 | tox_friend_add_norequest(state2.tox, key, nullptr); // tox2 -> tox3 |
165 | 1 | tox_self_get_public_key(state2.tox, key); |
166 | 1 | tox_friend_add_norequest(state3.tox, key, nullptr); // tox3 -> tox2 |
167 | | |
168 | 1 | printf("bootstrapping tox2 and tox3 off tox1\n"); |
169 | 1 | uint8_t dht_key[TOX_PUBLIC_KEY_SIZE]; |
170 | 1 | tox_self_get_dht_id(state1.tox, dht_key); |
171 | 1 | const uint16_t dht_port = tox_self_get_udp_port(state1.tox, nullptr); |
172 | | |
173 | 1 | tox_bootstrap(state2.tox, "localhost", dht_port, dht_key, nullptr); |
174 | 1 | tox_bootstrap(state3.tox, "localhost", dht_port, dht_key, nullptr); |
175 | | |
176 | 1 | Tox_Dispatch *dispatch = tox_dispatch_new(nullptr); |
177 | 1 | ck_assert(dispatch != nullptr); |
178 | | |
179 | | // Connection callbacks. |
180 | 1 | tox_events_callback_self_connection_status(dispatch, handle_self_connection_status); |
181 | 1 | tox_events_callback_friend_connection_status(dispatch, handle_friend_connection_status); |
182 | | |
183 | | // Conference callbacks. |
184 | 1 | tox_events_callback_conference_invite(dispatch, handle_conference_invite); |
185 | 1 | tox_events_callback_conference_connected(dispatch, handle_conference_connected); |
186 | 1 | tox_events_callback_conference_message(dispatch, handle_conference_message); |
187 | 1 | tox_events_callback_conference_peer_list_changed(dispatch, handle_conference_peer_list_changed); |
188 | | |
189 | | // Wait for self connection. |
190 | 1 | fprintf(stderr, "Waiting for toxes to come online\n"); |
191 | | |
192 | 78 | do { |
193 | 78 | iterate3_wait(&state1, &state2, &state3, dispatch, 100); |
194 | 78 | } while (!state1.self_online || !state2.self_online || !state3.self_online); |
195 | | |
196 | 1 | fprintf(stderr, "Toxes are online\n"); |
197 | | |
198 | | // Wait for friend connection. |
199 | 1 | fprintf(stderr, "Waiting for friends to connect\n"); |
200 | | |
201 | 15 | do { |
202 | 15 | iterate3_wait(&state1, &state2, &state3, dispatch, 100); |
203 | 15 | } while (!state1.friend_online || !state2.friend_online || !state3.friend_online); |
204 | | |
205 | 1 | fprintf(stderr, "Friends are connected\n"); |
206 | | |
207 | 1 | { |
208 | | // Create new conference, tox1 is the founder. |
209 | 1 | Tox_Err_Conference_New err; |
210 | 1 | state1.conference = tox_conference_new(state1.tox, &err); |
211 | 1 | state1.joined = true; |
212 | 1 | ck_assert_msg(err == TOX_ERR_CONFERENCE_NEW_OK, "failed to create a conference: err = %u", err); |
213 | 1 | fprintf(stderr, "Created conference: id = %u\n", state1.conference); |
214 | 1 | } |
215 | | |
216 | 0 | { |
217 | | // Invite friend. |
218 | 1 | Tox_Err_Conference_Invite err; |
219 | 1 | tox_conference_invite(state1.tox, 0, state1.conference, &err); |
220 | 1 | ck_assert_msg(err == TOX_ERR_CONFERENCE_INVITE_OK, "failed to invite a friend: err = %u", err); |
221 | 1 | state1.invited_next = true; |
222 | 1 | fprintf(stderr, "tox1 invited tox2\n"); |
223 | 1 | } |
224 | | |
225 | 0 | fprintf(stderr, "Waiting for invitation to arrive\n"); |
226 | | |
227 | 2 | do { |
228 | 2 | iterate3_wait(&state1, &state2, &state3, dispatch, 100); |
229 | 2 | } while (!state1.joined || !state2.joined || !state3.joined); |
230 | | |
231 | 1 | fprintf(stderr, "Invitations accepted\n"); |
232 | | |
233 | 1 | fprintf(stderr, "Waiting for peers to come online\n"); |
234 | | |
235 | 1 | do { |
236 | 1 | iterate3_wait(&state1, &state2, &state3, dispatch, 100); |
237 | 1 | } while (state1.peers == 0 || state2.peers == 0 || state3.peers == 0); |
238 | | |
239 | 1 | fprintf(stderr, "All peers are online\n"); |
240 | | |
241 | 1 | { |
242 | 1 | fprintf(stderr, "tox1 sends a message to the group: \"hello!\"\n"); |
243 | 1 | Tox_Err_Conference_Send_Message err; |
244 | 1 | tox_conference_send_message(state1.tox, state1.conference, TOX_MESSAGE_TYPE_NORMAL, |
245 | 1 | (const uint8_t *)"hello!", 7, &err); |
246 | | |
247 | 1 | if (err != TOX_ERR_CONFERENCE_SEND_MESSAGE_OK) { |
248 | 0 | fprintf(stderr, "ERROR: %u\n", err); |
249 | 0 | exit(EXIT_FAILURE); |
250 | 0 | } |
251 | 1 | } |
252 | | |
253 | 1 | fprintf(stderr, "Waiting for messages to arrive\n"); |
254 | | |
255 | 1 | do { |
256 | 1 | iterate3_wait(&state1, &state2, &state3, dispatch, 100); |
257 | 1 | c_sleep(100); |
258 | 1 | } while (!state2.received || !state3.received); |
259 | | |
260 | 1 | fprintf(stderr, "Messages received. Test complete.\n"); |
261 | | |
262 | 1 | tox_dispatch_free(dispatch); |
263 | 1 | tox_kill(state3.tox); |
264 | 1 | tox_kill(state2.tox); |
265 | 1 | tox_kill(state1.tox); |
266 | | |
267 | 1 | return 0; |
268 | 1 | } |