/work/toxcore/group_common.h
Line | Count | Source |
1 | | /* SPDX-License-Identifier: GPL-3.0-or-later |
2 | | * Copyright © 2016-2022 The TokTok team. |
3 | | */ |
4 | | |
5 | | /** |
6 | | * Common groupchat data structures. |
7 | | */ |
8 | | |
9 | | #ifndef C_TOXCORE_TOXCORE_GROUP_COMMON_H |
10 | | #define C_TOXCORE_TOXCORE_GROUP_COMMON_H |
11 | | |
12 | | #include <stdbool.h> |
13 | | #include <stdint.h> |
14 | | |
15 | | #include "DHT.h" |
16 | | #include "TCP_connection.h" |
17 | | #include "group_moderation.h" |
18 | | |
19 | 1.16k | #define MAX_GC_PART_MESSAGE_SIZE 128 |
20 | 4.91k | #define MAX_GC_NICK_SIZE 128 |
21 | 1.81k | #define MAX_GC_TOPIC_SIZE 512 |
22 | 6.94k | #define MAX_GC_GROUP_NAME_SIZE 48 |
23 | 55.9k | #define GC_MESSAGE_PSEUDO_ID_SIZE 4 |
24 | 18.6k | #define GROUP_MAX_MESSAGE_LENGTH 1372 |
25 | | |
26 | | /* Max size of a packet chunk. Packets larger than this must be split up. |
27 | | * |
28 | | * For an explanation on why this value was chosen, see the following link: https://archive.ph/vsCOG |
29 | | */ |
30 | 39.8k | #define MAX_GC_PACKET_CHUNK_SIZE 500 |
31 | | /* Max size of an incoming packet chunk that is allowed */ |
32 | 27.8k | #define MAX_GC_PACKET_INCOMING_CHUNK_SIZE 1372 |
33 | | |
34 | 18.6k | #define MAX_GC_MESSAGE_SIZE GROUP_MAX_MESSAGE_LENGTH |
35 | 18.6k | #define MAX_GC_MESSAGE_RAW_SIZE (MAX_GC_MESSAGE_SIZE + GC_MESSAGE_PSEUDO_ID_SIZE) |
36 | 4 | #define MAX_GC_CUSTOM_LOSSLESS_PACKET_SIZE 1373 |
37 | 13.6k | #define MAX_GC_CUSTOM_LOSSY_PACKET_SIZE 1373 |
38 | 7.32k | #define MAX_GC_PASSWORD_SIZE 32 |
39 | 186 | #define MAX_GC_SAVED_INVITES 10 |
40 | 229 | #define MAX_GC_PEERS_DEFAULT 100 |
41 | 5.74k | #define MAX_GC_SAVED_TIMEOUTS 12 |
42 | 83.5k | #define GC_MAX_SAVED_PEERS 100 |
43 | 1.27k | #define GC_SAVED_PEER_SIZE (ENC_PUBLIC_KEY_SIZE + sizeof(Node_format) + sizeof(IP_Port)) |
44 | | |
45 | | /* Max size of a complete encrypted packet including headers. */ |
46 | 11.0k | #define MAX_GC_PACKET_SIZE (MAX_GC_PACKET_CHUNK_SIZE * 100) |
47 | | |
48 | | /* Max number of messages to store in the send/recv arrays */ |
49 | 5.19M | #define GCC_BUFFER_SIZE 8192 |
50 | | |
51 | | /** Self UDP status. Must correspond to return values from `ipport_self_copy()`. */ |
52 | | typedef enum Self_UDP_Status { |
53 | | SELF_UDP_STATUS_NONE = 0x00, |
54 | | SELF_UDP_STATUS_WAN = 0x01, |
55 | | SELF_UDP_STATUS_LAN = 0x02, |
56 | | } Self_UDP_Status; |
57 | | |
58 | | /** Group exit types. */ |
59 | | typedef enum Group_Exit_Type { |
60 | | GC_EXIT_TYPE_QUIT = 0x00, // Peer left the group |
61 | | GC_EXIT_TYPE_TIMEOUT = 0x01, // Peer connection timed out |
62 | | GC_EXIT_TYPE_DISCONNECTED = 0x02, // Peer diconnected from group |
63 | | GC_EXIT_TYPE_SELF_DISCONNECTED = 0x03, // Self disconnected from group |
64 | | GC_EXIT_TYPE_KICKED = 0x04, // Peer was kicked from the group |
65 | | GC_EXIT_TYPE_SYNC_ERR = 0x05, // Peer failed to sync with the group |
66 | | GC_EXIT_TYPE_NO_CALLBACK = 0x06, // The peer exit callback should not be triggered |
67 | | } Group_Exit_Type; |
68 | | |
69 | | typedef struct GC_Exit_Info { |
70 | | uint8_t part_message[MAX_GC_PART_MESSAGE_SIZE]; |
71 | | uint16_t length; |
72 | | Group_Exit_Type exit_type; |
73 | | } GC_Exit_Info; |
74 | | |
75 | | typedef struct GC_PeerAddress { |
76 | | uint8_t public_key[EXT_PUBLIC_KEY_SIZE]; |
77 | | IP_Port ip_port; |
78 | | } GC_PeerAddress; |
79 | | |
80 | | typedef struct GC_Message_Array_Entry { |
81 | | uint8_t *data; |
82 | | uint16_t data_length; |
83 | | uint8_t packet_type; |
84 | | uint64_t message_id; |
85 | | uint64_t time_added; |
86 | | uint64_t last_send_try; |
87 | | } GC_Message_Array_Entry; |
88 | | |
89 | | typedef struct GC_Connection { |
90 | | uint64_t send_message_id; /* message_id of the next message we send to peer */ |
91 | | |
92 | | uint16_t send_array_start; /* send_array index of oldest item */ |
93 | | GC_Message_Array_Entry *send_array; |
94 | | |
95 | | uint64_t received_message_id; /* message_id of peer's last message to us */ |
96 | | GC_Message_Array_Entry *recv_array; |
97 | | |
98 | | uint64_t last_chunk_id; /* The message ID of the last packet fragment we received */ |
99 | | |
100 | | GC_PeerAddress addr; /* holds peer's extended real public key and ip_port */ |
101 | | uint32_t public_key_hash; /* Jenkins one at a time hash of peer's real encryption public key */ |
102 | | |
103 | | uint8_t session_public_key[ENC_PUBLIC_KEY_SIZE]; /* self session public key for this peer */ |
104 | | uint8_t session_secret_key[ENC_SECRET_KEY_SIZE]; /* self session secret key for this peer */ |
105 | | uint8_t session_shared_key[CRYPTO_SHARED_KEY_SIZE]; /* made with our session sk and peer's session pk */ |
106 | | |
107 | | int tcp_connection_num; |
108 | | uint64_t last_sent_tcp_relays_time; /* the last time we attempted to send this peer our tcp relays */ |
109 | | uint16_t tcp_relay_share_index; |
110 | | uint64_t last_received_direct_time; /* the last time we received a direct UDP packet from this connection */ |
111 | | uint64_t last_sent_ip_time; /* the last time we sent our ip info to this peer in a ping packet */ |
112 | | |
113 | | Node_format connected_tcp_relays[MAX_FRIEND_TCP_CONNECTIONS]; |
114 | | uint16_t tcp_relays_count; |
115 | | |
116 | | uint64_t last_received_packet_time; /* The last time we successfully processed any packet from this peer */ |
117 | | uint64_t last_requested_packet_time; /* The last time we requested a missing packet from this peer */ |
118 | | uint64_t last_sent_ping_time; |
119 | | uint64_t last_sync_response; /* the last time we sent this peer a sync response */ |
120 | | uint8_t oob_relay_pk[CRYPTO_PUBLIC_KEY_SIZE]; |
121 | | bool self_is_closer; /* true if we're "closer" to the chat_id than this peer (uses real pk's) */ |
122 | | |
123 | | bool confirmed; /* true if this peer has given us their info */ |
124 | | bool handshaked; /* true if we've successfully handshaked with this peer */ |
125 | | uint16_t handshake_attempts; |
126 | | uint64_t last_handshake_request; |
127 | | uint64_t last_handshake_response; |
128 | | uint8_t pending_handshake_type; |
129 | | bool is_pending_handshake_response; |
130 | | bool is_oob_handshake; |
131 | | |
132 | | uint64_t last_key_rotation; /* the last time we rotated session keys for this peer */ |
133 | | bool pending_key_rotation_request; |
134 | | |
135 | | bool pending_delete; /* true if this peer has been marked for deletion */ |
136 | | bool delete_this_iteration; /* true if this peer should be deleted this do_gc() iteration*/ |
137 | | GC_Exit_Info exit_info; |
138 | | } GC_Connection; |
139 | | |
140 | | /*** |
141 | | * Group roles. Roles are hierarchical in that each role has a set of privileges plus |
142 | | * all the privileges of the roles below it. |
143 | | */ |
144 | | typedef enum Group_Role { |
145 | | /** Group creator. All-powerful. Cannot be demoted or kicked. */ |
146 | | GR_FOUNDER = 0x00, |
147 | | |
148 | | /** |
149 | | * May promote or demote peers below them to any role below them. |
150 | | * May also kick peers below them and set the topic. |
151 | | */ |
152 | | GR_MODERATOR = 0x01, |
153 | | |
154 | | /** may interact normally with the group. */ |
155 | | GR_USER = 0x02, |
156 | | |
157 | | /** May not interact with the group but may observe. */ |
158 | | GR_OBSERVER = 0x03, |
159 | | } Group_Role; |
160 | | |
161 | | typedef enum Group_Peer_Status { |
162 | | GS_NONE = 0x00, |
163 | | GS_AWAY = 0x01, |
164 | | GS_BUSY = 0x02, |
165 | | } Group_Peer_Status; |
166 | | |
167 | | /** |
168 | | * Group voice states. The state determines which Group Roles have permission to speak. |
169 | | */ |
170 | | typedef enum Group_Voice_State { |
171 | | /** Every group role except Observers may speak. */ |
172 | | GV_ALL = 0x00, |
173 | | |
174 | | /** Only Moderators and the Founder may speak. */ |
175 | | GV_MODS = 0x01, |
176 | | |
177 | | /** Only the Founder may speak. */ |
178 | | GV_FOUNDER = 0x02, |
179 | | } Group_Voice_State; |
180 | | |
181 | | /** Group connection states. */ |
182 | | typedef enum GC_Conn_State { |
183 | | CS_NONE = 0x00, // Indicates a group is not initialized |
184 | | CS_DISCONNECTED = 0x01, // Not receiving or sending any packets |
185 | | CS_CONNECTING = 0x02, // Attempting to establish a connection with peers in the group |
186 | | CS_CONNECTED = 0x03, // Has successfully received a sync response from a peer in the group |
187 | | } GC_Conn_State; |
188 | | |
189 | | /** Group privacy states. */ |
190 | | typedef enum Group_Privacy_State { |
191 | | GI_PUBLIC = 0x00, // Anyone with the chat ID may join the group |
192 | | GI_PRIVATE = 0x01, // Peers may only join the group via a friend invite |
193 | | } Group_Privacy_State; |
194 | | |
195 | | /** Handshake join types. */ |
196 | | typedef enum Group_Handshake_Join_Type { |
197 | | HJ_PUBLIC = 0x00, // Indicates the group was joined via the DHT |
198 | | HJ_PRIVATE = 0x01, // Indicates the group was joined via private friend invite |
199 | | } Group_Handshake_Join_Type; |
200 | | |
201 | | typedef struct GC_SavedPeerInfo { |
202 | | uint8_t public_key[ENC_PUBLIC_KEY_SIZE]; |
203 | | Node_format tcp_relay; |
204 | | IP_Port ip_port; |
205 | | } GC_SavedPeerInfo; |
206 | | |
207 | | /** Holds info about peers who recently timed out */ |
208 | | typedef struct GC_TimedOutPeer { |
209 | | GC_SavedPeerInfo addr; |
210 | | uint64_t last_seen; // the time the peer disconnected |
211 | | uint64_t last_reconn_try; // the last time we tried to establish a new connection |
212 | | } GC_TimedOutPeer; |
213 | | |
214 | | typedef struct GC_Peer { |
215 | | /* Below state is sent to other peers in peer info exchange */ |
216 | | uint8_t nick[MAX_GC_NICK_SIZE]; |
217 | | uint16_t nick_length; |
218 | | uint8_t status; |
219 | | |
220 | | /* Below state is local only */ |
221 | | Group_Role role; |
222 | | uint32_t peer_id; // permanent ID (used for the public API) |
223 | | bool ignore; |
224 | | |
225 | | GC_Connection gconn; |
226 | | } GC_Peer; |
227 | | |
228 | | typedef struct GC_SharedState { |
229 | | uint32_t version; |
230 | | uint8_t founder_public_key[EXT_PUBLIC_KEY_SIZE]; |
231 | | uint16_t maxpeers; |
232 | | uint16_t group_name_len; |
233 | | uint8_t group_name[MAX_GC_GROUP_NAME_SIZE]; |
234 | | Group_Privacy_State privacy_state; // GI_PUBLIC (uses DHT) or GI_PRIVATE (invite only) |
235 | | uint16_t password_length; |
236 | | uint8_t password[MAX_GC_PASSWORD_SIZE]; |
237 | | uint8_t mod_list_hash[MOD_MODERATION_HASH_SIZE]; |
238 | | uint32_t topic_lock; // equal to GC_TOPIC_LOCK_ENABLED when lock is enabled |
239 | | Group_Voice_State voice_state; |
240 | | } GC_SharedState; |
241 | | |
242 | | typedef struct GC_TopicInfo { |
243 | | uint32_t version; |
244 | | uint16_t length; |
245 | | uint16_t checksum; // used for syncing problems. the checksum with the highest value gets priority. |
246 | | uint8_t topic[MAX_GC_TOPIC_SIZE]; |
247 | | uint8_t public_sig_key[SIG_PUBLIC_KEY_SIZE]; // Public signature key of the topic setter |
248 | | } GC_TopicInfo; |
249 | | |
250 | | typedef struct GC_Chat { |
251 | | Mono_Time *mono_time; |
252 | | const Logger *log; |
253 | | const Memory *mem; |
254 | | const Random *rng; |
255 | | |
256 | | uint32_t connected_tcp_relays; |
257 | | Self_UDP_Status self_udp_status; |
258 | | IP_Port self_ip_port; |
259 | | |
260 | | Networking_Core *net; |
261 | | TCP_Connections *tcp_conn; |
262 | | |
263 | | uint64_t last_checked_tcp_relays; |
264 | | Group_Handshake_Join_Type join_type; |
265 | | |
266 | | GC_Peer *group; |
267 | | Moderation moderation; |
268 | | |
269 | | GC_Conn_State connection_state; |
270 | | |
271 | | GC_SharedState shared_state; |
272 | | uint8_t shared_state_sig[SIGNATURE_SIZE]; // signed by founder using the chat secret key |
273 | | |
274 | | GC_TopicInfo topic_info; |
275 | | uint8_t topic_sig[SIGNATURE_SIZE]; // signed by the peer who set the current topic |
276 | | uint16_t topic_prev_checksum; // checksum of the previous topic |
277 | | uint64_t topic_time_set; |
278 | | |
279 | | uint16_t peers_checksum; // sum of the public key hash of every confirmed peer in the group |
280 | | uint16_t roles_checksum; // sum of every confirmed peer's role plus the first byte of their public key |
281 | | |
282 | | uint32_t numpeers; |
283 | | int group_number; |
284 | | |
285 | | uint8_t chat_public_key[EXT_PUBLIC_KEY_SIZE]; // the chat_id is the sig portion |
286 | | uint8_t chat_secret_key[EXT_SECRET_KEY_SIZE]; // only used by the founder |
287 | | |
288 | | uint8_t self_public_key[EXT_PUBLIC_KEY_SIZE]; |
289 | | uint8_t self_secret_key[EXT_SECRET_KEY_SIZE]; |
290 | | |
291 | | uint64_t time_connected; |
292 | | uint64_t last_ping_interval; |
293 | | uint64_t last_sync_request; // The last time we sent a sync request to any peer |
294 | | uint64_t last_sync_response_peer_list; // The last time we sent the peer list to any peer |
295 | | uint64_t last_time_peers_loaded; |
296 | | |
297 | | /* keeps track of frequency of new inbound connections */ |
298 | | uint8_t connection_o_metre; |
299 | | uint64_t connection_cooldown_timer; |
300 | | bool block_handshakes; |
301 | | |
302 | | int32_t saved_invites[MAX_GC_SAVED_INVITES]; |
303 | | uint8_t saved_invites_index; |
304 | | |
305 | | /** A list of recently seen peers in case we disconnect from a private group. |
306 | | * Peers are added once they're confirmed, and only if there are vacant |
307 | | * spots (older connections get priority). An entry is removed only when the list |
308 | | * is full, its respective peer goes offline, and an online peer who isn't yet |
309 | | * present in the list can be added. |
310 | | */ |
311 | | GC_SavedPeerInfo saved_peers[GC_MAX_SAVED_PEERS]; |
312 | | |
313 | | GC_TimedOutPeer timeout_list[MAX_GC_SAVED_TIMEOUTS]; |
314 | | size_t timeout_list_index; |
315 | | uint64_t last_timed_out_reconn_try; // the last time we tried to reconnect to timed out peers |
316 | | |
317 | | bool update_self_announces; // true if we should try to update our announcements |
318 | | uint64_t last_self_announce_check; // the last time we checked if we should update our announcements |
319 | | uint64_t last_time_self_announce; // the last time we announced the group |
320 | | uint8_t announced_tcp_relay_pk[CRYPTO_PUBLIC_KEY_SIZE]; // The pk of the last TCP relay we announced |
321 | | |
322 | | uint8_t m_group_public_key[CRYPTO_PUBLIC_KEY_SIZE]; // public key for group's messenger friend connection |
323 | | int friend_connection_id; // identifier for group's messenger friend connection |
324 | | } GC_Chat; |
325 | | |
326 | | #ifndef MESSENGER_DEFINED |
327 | | #define MESSENGER_DEFINED |
328 | | typedef struct Messenger Messenger; |
329 | | #endif /* MESSENGER_DEFINED */ |
330 | | |
331 | | typedef void gc_message_cb(const Messenger *m, uint32_t group_number, uint32_t peer_id, unsigned int type, |
332 | | const uint8_t *message, size_t length, uint32_t message_id, void *user_data); |
333 | | typedef void gc_private_message_cb(const Messenger *m, uint32_t group_number, uint32_t peer_id, unsigned int type, |
334 | | const uint8_t *message, size_t length, void *user_data); |
335 | | typedef void gc_custom_packet_cb(const Messenger *m, uint32_t group_number, uint32_t peer_id, const uint8_t *data, |
336 | | size_t length, void *user_data); |
337 | | typedef void gc_custom_private_packet_cb(const Messenger *m, uint32_t group_number, uint32_t peer_id, |
338 | | const uint8_t *data, size_t length, void *user_data); |
339 | | typedef void gc_moderation_cb(const Messenger *m, uint32_t group_number, uint32_t source_peer_number, |
340 | | uint32_t target_peer_number, unsigned int mod_type, void *user_data); |
341 | | typedef void gc_nick_change_cb(const Messenger *m, uint32_t group_number, uint32_t peer_id, const uint8_t *name, |
342 | | size_t length, void *user_data); |
343 | | typedef void gc_status_change_cb(const Messenger *m, uint32_t group_number, uint32_t peer_id, unsigned int status, |
344 | | void *user_data); |
345 | | typedef void gc_topic_change_cb(const Messenger *m, uint32_t group_number, uint32_t peer_id, const uint8_t *topic, |
346 | | size_t length, void *user_data); |
347 | | typedef void gc_topic_lock_cb(const Messenger *m, uint32_t group_number, unsigned int topic_lock, void *user_data); |
348 | | typedef void gc_voice_state_cb(const Messenger *m, uint32_t group_number, unsigned int voice_state, void *user_data); |
349 | | typedef void gc_peer_limit_cb(const Messenger *m, uint32_t group_number, uint32_t peer_limit, void *user_data); |
350 | | typedef void gc_privacy_state_cb(const Messenger *m, uint32_t group_number, unsigned int privacy_state, void *user_data); |
351 | | typedef void gc_password_cb(const Messenger *m, uint32_t group_number, const uint8_t *password, size_t length, |
352 | | void *user_data); |
353 | | typedef void gc_peer_join_cb(const Messenger *m, uint32_t group_number, uint32_t peer_id, void *user_data); |
354 | | typedef void gc_peer_exit_cb(const Messenger *m, uint32_t group_number, uint32_t peer_id, unsigned int exit_type, |
355 | | const uint8_t *name, size_t name_length, const uint8_t *part_message, size_t length, |
356 | | void *user_data); |
357 | | typedef void gc_self_join_cb(const Messenger *m, uint32_t group_number, void *user_data); |
358 | | typedef void gc_rejected_cb(const Messenger *m, uint32_t group_number, unsigned int fail_type, void *user_data); |
359 | | |
360 | | typedef struct GC_Session { |
361 | | Messenger *messenger; |
362 | | GC_Chat *chats; |
363 | | struct GC_Announces_List *announces_list; |
364 | | |
365 | | uint32_t chats_index; |
366 | | |
367 | | gc_message_cb *message; |
368 | | gc_private_message_cb *private_message; |
369 | | gc_custom_packet_cb *custom_packet; |
370 | | gc_custom_private_packet_cb *custom_private_packet; |
371 | | gc_moderation_cb *moderation; |
372 | | gc_nick_change_cb *nick_change; |
373 | | gc_status_change_cb *status_change; |
374 | | gc_topic_change_cb *topic_change; |
375 | | gc_topic_lock_cb *topic_lock; |
376 | | gc_voice_state_cb *voice_state; |
377 | | gc_peer_limit_cb *peer_limit; |
378 | | gc_privacy_state_cb *privacy_state; |
379 | | gc_password_cb *password; |
380 | | gc_peer_join_cb *peer_join; |
381 | | gc_peer_exit_cb *peer_exit; |
382 | | gc_self_join_cb *self_join; |
383 | | gc_rejected_cb *rejected; |
384 | | } GC_Session; |
385 | | |
386 | | /** @brief Adds a new peer to group_number's peer list. |
387 | | * |
388 | | * Return peer_number on success. |
389 | | * Return -1 on failure. |
390 | | * Return -2 if a peer with public_key is already in our peerlist. |
391 | | */ |
392 | | non_null(1, 3) nullable(2) |
393 | | int peer_add(GC_Chat *chat, const IP_Port *ipp, const uint8_t *public_key); |
394 | | |
395 | | /** @brief Unpacks saved peers from `data` of size `length` into `chat`. |
396 | | * |
397 | | * Returns the number of unpacked peers on success. |
398 | | * Returns -1 on failure. |
399 | | */ |
400 | | non_null() |
401 | | int unpack_gc_saved_peers(GC_Chat *chat, const uint8_t *data, uint16_t length); |
402 | | |
403 | | /** @brief Packs all valid entries from saved peerlist into `data`. |
404 | | * |
405 | | * If `processed` is non-null it will be set to the length of the packed data |
406 | | * on success, and will be untouched on error. |
407 | | * |
408 | | * Return the number of packed saved peers on success. |
409 | | * Return -1 if buffer is too small. |
410 | | */ |
411 | | non_null(1, 2) nullable(4) |
412 | | int pack_gc_saved_peers(const GC_Chat *chat, uint8_t *data, uint16_t length, uint16_t *processed); |
413 | | |
414 | | #endif /* C_TOXCORE_TOXCORE_GROUP_COMMON_H */ |