1 /* SPDX-License-Identifier: GPL-3.0-or-later
2 * Copyright © 2016-2018 The TokTok team.
3 * Copyright © 2013 Tox project.
4 */
5
6 /*
7 * An implementation of a simple text chat only messenger on the tox network core.
8 */
9 #ifdef HAVE_CONFIG_H
10 #include "config.h"
11 #endif
12
13 #include "Messenger.h"
14
15 #include <assert.h>
16 #include <stdio.h>
17 #include <stdlib.h>
18 #include <string.h>
19 #include <time.h>
20
21 #include "logger.h"
22 #include "mono_time.h"
23 #include "network.h"
24 #include "state.h"
25 #include "util.h"
26
27 static int write_cryptpacket_id(const Messenger *m, int32_t friendnumber, uint8_t packet_id, const uint8_t *data,
28 uint32_t length, uint8_t congestion_control);
29 static void m_register_default_plugins(Messenger *m);
30
31 /**
32 * Determines if the friendnumber passed is valid in the Messenger object.
33 *
34 * @param friendnumber The index in the friend list.
35 */
friend_is_valid(const Messenger * m,int32_t friendnumber)36 static bool friend_is_valid(const Messenger *m, int32_t friendnumber)
37 {
38 return (unsigned int)friendnumber < m->numfriends && m->friendlist[friendnumber].status != 0;
39 }
40
41 /* Set the size of the friend list to numfriends.
42 *
43 * return -1 if realloc fails.
44 */
realloc_friendlist(Messenger * m,uint32_t num)45 static int realloc_friendlist(Messenger *m, uint32_t num)
46 {
47 if (num == 0) {
48 free(m->friendlist);
49 m->friendlist = nullptr;
50 return 0;
51 }
52
53 Friend *newfriendlist = (Friend *)realloc(m->friendlist, num * sizeof(Friend));
54
55 if (newfriendlist == nullptr) {
56 return -1;
57 }
58
59 m->friendlist = newfriendlist;
60 return 0;
61 }
62
63 /* return the friend id associated to that public key.
64 * return -1 if no such friend.
65 */
getfriend_id(const Messenger * m,const uint8_t * real_pk)66 int32_t getfriend_id(const Messenger *m, const uint8_t *real_pk)
67 {
68 uint32_t i;
69
70 for (i = 0; i < m->numfriends; ++i) {
71 if (m->friendlist[i].status > 0) {
72 if (id_equal(real_pk, m->friendlist[i].real_pk)) {
73 return i;
74 }
75 }
76 }
77
78 return -1;
79 }
80
81 /* Copies the public key associated to that friend id into real_pk buffer.
82 * Make sure that real_pk is of size CRYPTO_PUBLIC_KEY_SIZE.
83 *
84 * return 0 if success.
85 * return -1 if failure.
86 */
get_real_pk(const Messenger * m,int32_t friendnumber,uint8_t * real_pk)87 int get_real_pk(const Messenger *m, int32_t friendnumber, uint8_t *real_pk)
88 {
89 if (!friend_is_valid(m, friendnumber)) {
90 return -1;
91 }
92
93 memcpy(real_pk, m->friendlist[friendnumber].real_pk, CRYPTO_PUBLIC_KEY_SIZE);
94 return 0;
95 }
96
97 /* return friend connection id on success.
98 * return -1 if failure.
99 */
getfriendcon_id(const Messenger * m,int32_t friendnumber)100 int getfriendcon_id(const Messenger *m, int32_t friendnumber)
101 {
102 if (!friend_is_valid(m, friendnumber)) {
103 return -1;
104 }
105
106 return m->friendlist[friendnumber].friendcon_id;
107 }
108
109 /*
110 * return a uint16_t that represents the checksum of address of length len.
111 */
address_checksum(const uint8_t * address,uint32_t len)112 static uint16_t address_checksum(const uint8_t *address, uint32_t len)
113 {
114 uint8_t checksum[2] = {0};
115 uint16_t check;
116 uint32_t i;
117
118 for (i = 0; i < len; ++i) {
119 checksum[i % 2] ^= address[i];
120 }
121
122 memcpy(&check, checksum, sizeof(check));
123 return check;
124 }
125
126 /* Format: `[real_pk (32 bytes)][nospam number (4 bytes)][checksum (2 bytes)]`
127 *
128 * return FRIEND_ADDRESS_SIZE byte address to give to others.
129 */
getaddress(const Messenger * m,uint8_t * address)130 void getaddress(const Messenger *m, uint8_t *address)
131 {
132 id_copy(address, nc_get_self_public_key(m->net_crypto));
133 uint32_t nospam = get_nospam(m->fr);
134 memcpy(address + CRYPTO_PUBLIC_KEY_SIZE, &nospam, sizeof(nospam));
135 uint16_t checksum = address_checksum(address, FRIEND_ADDRESS_SIZE - sizeof(checksum));
136 memcpy(address + CRYPTO_PUBLIC_KEY_SIZE + sizeof(nospam), &checksum, sizeof(checksum));
137 }
138
send_online_packet(Messenger * m,int32_t friendnumber)139 static int send_online_packet(Messenger *m, int32_t friendnumber)
140 {
141 if (!friend_is_valid(m, friendnumber)) {
142 return 0;
143 }
144
145 uint8_t packet = PACKET_ID_ONLINE;
146 return write_cryptpacket(m->net_crypto, friend_connection_crypt_connection_id(m->fr_c,
147 m->friendlist[friendnumber].friendcon_id), &packet, sizeof(packet), 0) != -1;
148 }
149
send_offline_packet(Messenger * m,int friendcon_id)150 static int send_offline_packet(Messenger *m, int friendcon_id)
151 {
152 uint8_t packet = PACKET_ID_OFFLINE;
153 return write_cryptpacket(m->net_crypto, friend_connection_crypt_connection_id(m->fr_c, friendcon_id), &packet,
154 sizeof(packet), 0) != -1;
155 }
156
157 static int m_handle_status(void *object, int i, uint8_t status, void *userdata);
158 static int m_handle_packet(void *object, int i, const uint8_t *temp, uint16_t len, void *userdata);
159 static int m_handle_lossy_packet(void *object, int friend_num, const uint8_t *packet, uint16_t length,
160 void *userdata);
161
init_new_friend(Messenger * m,const uint8_t * real_pk,uint8_t status)162 static int32_t init_new_friend(Messenger *m, const uint8_t *real_pk, uint8_t status)
163 {
164 if (m->numfriends == UINT32_MAX) {
165 LOGGER_ERROR(m->log, "Friend list full: we have more than 4 billion friends");
166 /* This is technically incorrect, but close enough. */
167 return FAERR_NOMEM;
168 }
169
170 /* Resize the friend list if necessary. */
171 if (realloc_friendlist(m, m->numfriends + 1) != 0) {
172 return FAERR_NOMEM;
173 }
174
175 memset(&m->friendlist[m->numfriends], 0, sizeof(Friend));
176
177 int friendcon_id = new_friend_connection(m->fr_c, real_pk);
178
179 if (friendcon_id == -1) {
180 return FAERR_NOMEM;
181 }
182
183 uint32_t i;
184
185 for (i = 0; i <= m->numfriends; ++i) {
186 if (m->friendlist[i].status == NOFRIEND) {
187 m->friendlist[i].status = status;
188 m->friendlist[i].friendcon_id = friendcon_id;
189 m->friendlist[i].friendrequest_lastsent = 0;
190 id_copy(m->friendlist[i].real_pk, real_pk);
191 m->friendlist[i].statusmessage_length = 0;
192 m->friendlist[i].userstatus = USERSTATUS_NONE;
193 m->friendlist[i].is_typing = 0;
194 m->friendlist[i].message_id = 0;
195 friend_connection_callbacks(m->fr_c, friendcon_id, MESSENGER_CALLBACK_INDEX, &m_handle_status, &m_handle_packet,
196 &m_handle_lossy_packet, m, i);
197
198 if (m->numfriends == i) {
199 ++m->numfriends;
200 }
201
202 if (friend_con_connected(m->fr_c, friendcon_id) == FRIENDCONN_STATUS_CONNECTED) {
203 send_online_packet(m, i);
204 }
205
206 return i;
207 }
208 }
209
210 return FAERR_NOMEM;
211 }
212
213 /*
214 * Add a friend.
215 * Set the data that will be sent along with friend request.
216 * Address is the address of the friend (returned by getaddress of the friend you wish to add) it must be FRIEND_ADDRESS_SIZE bytes.
217 * data is the data and length is the length.
218 *
219 * return the friend number if success.
220 * return FA_TOOLONG if message length is too long.
221 * return FAERR_NOMESSAGE if no message (message length must be >= 1 byte).
222 * return FAERR_OWNKEY if user's own key.
223 * return FAERR_ALREADYSENT if friend request already sent or already a friend.
224 * return FAERR_BADCHECKSUM if bad checksum in address.
225 * return FAERR_SETNEWNOSPAM if the friend was already there but the nospam was different.
226 * (the nospam for that friend was set to the new one).
227 * return FAERR_NOMEM if increasing the friend list size fails.
228 */
m_addfriend(Messenger * m,const uint8_t * address,const uint8_t * data,uint16_t length)229 int32_t m_addfriend(Messenger *m, const uint8_t *address, const uint8_t *data, uint16_t length)
230 {
231 if (length > MAX_FRIEND_REQUEST_DATA_SIZE) {
232 return FAERR_TOOLONG;
233 }
234
235 uint8_t real_pk[CRYPTO_PUBLIC_KEY_SIZE];
236 id_copy(real_pk, address);
237
238 if (!public_key_valid(real_pk)) {
239 return FAERR_BADCHECKSUM;
240 }
241
242 uint16_t check;
243 uint16_t checksum = address_checksum(address, FRIEND_ADDRESS_SIZE - sizeof(checksum));
244 memcpy(&check, address + CRYPTO_PUBLIC_KEY_SIZE + sizeof(uint32_t), sizeof(check));
245
246 if (check != checksum) {
247 return FAERR_BADCHECKSUM;
248 }
249
250 if (length < 1) {
251 return FAERR_NOMESSAGE;
252 }
253
254 if (id_equal(real_pk, nc_get_self_public_key(m->net_crypto))) {
255 return FAERR_OWNKEY;
256 }
257
258 int32_t friend_id = getfriend_id(m, real_pk);
259
260 if (friend_id != -1) {
261 if (m->friendlist[friend_id].status >= FRIEND_CONFIRMED) {
262 return FAERR_ALREADYSENT;
263 }
264
265 uint32_t nospam;
266 memcpy(&nospam, address + CRYPTO_PUBLIC_KEY_SIZE, sizeof(nospam));
267
268 if (m->friendlist[friend_id].friendrequest_nospam == nospam) {
269 return FAERR_ALREADYSENT;
270 }
271
272 m->friendlist[friend_id].friendrequest_nospam = nospam;
273 return FAERR_SETNEWNOSPAM;
274 }
275
276 int32_t ret = init_new_friend(m, real_pk, FRIEND_ADDED);
277
278 if (ret < 0) {
279 return ret;
280 }
281
282 m->friendlist[ret].friendrequest_timeout = FRIENDREQUEST_TIMEOUT;
283 memcpy(m->friendlist[ret].info, data, length);
284 m->friendlist[ret].info_size = length;
285 memcpy(&m->friendlist[ret].friendrequest_nospam, address + CRYPTO_PUBLIC_KEY_SIZE, sizeof(uint32_t));
286
287 return ret;
288 }
289
m_addfriend_norequest(Messenger * m,const uint8_t * real_pk)290 int32_t m_addfriend_norequest(Messenger *m, const uint8_t *real_pk)
291 {
292 if (getfriend_id(m, real_pk) != -1) {
293 return FAERR_ALREADYSENT;
294 }
295
296 if (!public_key_valid(real_pk)) {
297 return FAERR_BADCHECKSUM;
298 }
299
300 if (id_equal(real_pk, nc_get_self_public_key(m->net_crypto))) {
301 return FAERR_OWNKEY;
302 }
303
304 return init_new_friend(m, real_pk, FRIEND_CONFIRMED);
305 }
306
clear_receipts(Messenger * m,int32_t friendnumber)307 static int clear_receipts(Messenger *m, int32_t friendnumber)
308 {
309 if (!friend_is_valid(m, friendnumber)) {
310 return -1;
311 }
312
313 struct Receipts *receipts = m->friendlist[friendnumber].receipts_start;
314
315 while (receipts) {
316 struct Receipts *temp_r = receipts->next;
317 free(receipts);
318 receipts = temp_r;
319 }
320
321 m->friendlist[friendnumber].receipts_start = nullptr;
322 m->friendlist[friendnumber].receipts_end = nullptr;
323 return 0;
324 }
325
add_receipt(Messenger * m,int32_t friendnumber,uint32_t packet_num,uint32_t msg_id)326 static int add_receipt(Messenger *m, int32_t friendnumber, uint32_t packet_num, uint32_t msg_id)
327 {
328 if (!friend_is_valid(m, friendnumber)) {
329 return -1;
330 }
331
332 struct Receipts *new_receipts = (struct Receipts *)calloc(1, sizeof(struct Receipts));
333
334 if (!new_receipts) {
335 return -1;
336 }
337
338 new_receipts->packet_num = packet_num;
339 new_receipts->msg_id = msg_id;
340
341 if (!m->friendlist[friendnumber].receipts_start) {
342 m->friendlist[friendnumber].receipts_start = new_receipts;
343 } else {
344 m->friendlist[friendnumber].receipts_end->next = new_receipts;
345 }
346
347 m->friendlist[friendnumber].receipts_end = new_receipts;
348 new_receipts->next = nullptr;
349 return 0;
350 }
351 /*
352 * return -1 on failure.
353 * return 0 if packet was received.
354 */
friend_received_packet(const Messenger * m,int32_t friendnumber,uint32_t number)355 static int friend_received_packet(const Messenger *m, int32_t friendnumber, uint32_t number)
356 {
357 if (!friend_is_valid(m, friendnumber)) {
358 return -1;
359 }
360
361 return cryptpacket_received(m->net_crypto, friend_connection_crypt_connection_id(m->fr_c,
362 m->friendlist[friendnumber].friendcon_id), number);
363 }
364
do_receipts(Messenger * m,int32_t friendnumber,void * userdata)365 static int do_receipts(Messenger *m, int32_t friendnumber, void *userdata)
366 {
367 if (!friend_is_valid(m, friendnumber)) {
368 return -1;
369 }
370
371 struct Receipts *receipts = m->friendlist[friendnumber].receipts_start;
372
373 while (receipts) {
374 if (friend_received_packet(m, friendnumber, receipts->packet_num) == -1) {
375 break;
376 }
377
378 if (m->read_receipt) {
379 m->read_receipt(m, friendnumber, receipts->msg_id, userdata);
380 }
381
382 struct Receipts *r_next = receipts->next;
383
384 free(receipts);
385
386 m->friendlist[friendnumber].receipts_start = r_next;
387
388 receipts = r_next;
389 }
390
391 if (!m->friendlist[friendnumber].receipts_start) {
392 m->friendlist[friendnumber].receipts_end = nullptr;
393 }
394
395 return 0;
396 }
397
398 /* Remove a friend.
399 *
400 * return 0 if success.
401 * return -1 if failure.
402 */
m_delfriend(Messenger * m,int32_t friendnumber)403 int m_delfriend(Messenger *m, int32_t friendnumber)
404 {
405 if (!friend_is_valid(m, friendnumber)) {
406 return -1;
407 }
408
409 if (m->friend_connectionstatuschange_internal) {
410 m->friend_connectionstatuschange_internal(m, friendnumber, 0, m->friend_connectionstatuschange_internal_userdata);
411 }
412
413 clear_receipts(m, friendnumber);
414 remove_request_received(m->fr, m->friendlist[friendnumber].real_pk);
415 friend_connection_callbacks(m->fr_c, m->friendlist[friendnumber].friendcon_id, MESSENGER_CALLBACK_INDEX, nullptr,
416 nullptr, nullptr, nullptr, 0);
417
418 if (friend_con_connected(m->fr_c, m->friendlist[friendnumber].friendcon_id) == FRIENDCONN_STATUS_CONNECTED) {
419 send_offline_packet(m, m->friendlist[friendnumber].friendcon_id);
420 }
421
422 kill_friend_connection(m->fr_c, m->friendlist[friendnumber].friendcon_id);
423 memset(&m->friendlist[friendnumber], 0, sizeof(Friend));
424 uint32_t i;
425
426 for (i = m->numfriends; i != 0; --i) {
427 if (m->friendlist[i - 1].status != NOFRIEND) {
428 break;
429 }
430 }
431
432 m->numfriends = i;
433
434 if (realloc_friendlist(m, m->numfriends) != 0) {
435 return FAERR_NOMEM;
436 }
437
438 return 0;
439 }
440
m_get_friend_connectionstatus(const Messenger * m,int32_t friendnumber)441 int m_get_friend_connectionstatus(const Messenger *m, int32_t friendnumber)
442 {
443 if (!friend_is_valid(m, friendnumber)) {
444 return -1;
445 }
446
447 if (m->friendlist[friendnumber].status != FRIEND_ONLINE) {
448 return CONNECTION_NONE;
449 }
450
451 bool direct_connected = 0;
452 unsigned int num_online_relays = 0;
453 int crypt_conn_id = friend_connection_crypt_connection_id(m->fr_c, m->friendlist[friendnumber].friendcon_id);
454
455 if (!crypto_connection_status(m->net_crypto, crypt_conn_id, &direct_connected, &num_online_relays)) {
456 return CONNECTION_NONE;
457 }
458
459 if (direct_connected) {
460 return CONNECTION_UDP;
461 }
462
463 if (num_online_relays) {
464 return CONNECTION_TCP;
465 }
466
467 /* if we have a valid friend connection but do not have an established connection
468 * we leave the connection status unchanged until the friend connection is either
469 * established or dropped.
470 */
471 return m->friendlist[friendnumber].last_connection_udp_tcp;
472 }
473
m_friend_exists(const Messenger * m,int32_t friendnumber)474 int m_friend_exists(const Messenger *m, int32_t friendnumber)
475 {
476 if (!friend_is_valid(m, friendnumber)) {
477 return 0;
478 }
479
480 return 1;
481 }
482
483 /* Send a message of type.
484 *
485 * return -1 if friend not valid.
486 * return -2 if too large.
487 * return -3 if friend not online.
488 * return -4 if send failed (because queue is full).
489 * return -5 if bad type.
490 * return 0 if success.
491 */
m_send_message_generic(Messenger * m,int32_t friendnumber,uint8_t type,const uint8_t * message,uint32_t length,uint32_t * message_id)492 int m_send_message_generic(Messenger *m, int32_t friendnumber, uint8_t type, const uint8_t *message, uint32_t length,
493 uint32_t *message_id)
494 {
495 if (type > MESSAGE_ACTION) {
496 LOGGER_ERROR(m->log, "Message type %d is invalid", type);
497 return -5;
498 }
499
500 if (!friend_is_valid(m, friendnumber)) {
501 LOGGER_ERROR(m->log, "Friend number %d is invalid", friendnumber);
502 return -1;
503 }
504
505 if (length >= MAX_CRYPTO_DATA_SIZE) {
506 LOGGER_ERROR(m->log, "Message length %u is too large", length);
507 return -2;
508 }
509
510 if (m->friendlist[friendnumber].status != FRIEND_ONLINE) {
511 LOGGER_ERROR(m->log, "Friend %d is not online", friendnumber);
512 return -3;
513 }
514
515 VLA(uint8_t, packet, length + 1);
516 packet[0] = PACKET_ID_MESSAGE + type;
517
518 if (length != 0) {
519 memcpy(packet + 1, message, length);
520 }
521
522 int64_t packet_num = write_cryptpacket(m->net_crypto, friend_connection_crypt_connection_id(m->fr_c,
523 m->friendlist[friendnumber].friendcon_id), packet, length + 1, 0);
524
525 if (packet_num == -1) {
526 LOGGER_ERROR(m->log, "Failed to write crypto packet for message of length %d to friend %d",
527 length, friendnumber);
528 return -4;
529 }
530
531 uint32_t msg_id = ++m->friendlist[friendnumber].message_id;
532
533 add_receipt(m, friendnumber, packet_num, msg_id);
534
535 if (message_id) {
536 *message_id = msg_id;
537 }
538
539 return 0;
540 }
541
542 /* Send a name packet to friendnumber.
543 * length is the length with the NULL terminator.
544 */
m_sendname(const Messenger * m,int32_t friendnumber,const uint8_t * name,uint16_t length)545 static int m_sendname(const Messenger *m, int32_t friendnumber, const uint8_t *name, uint16_t length)
546 {
547 if (length > MAX_NAME_LENGTH) {
548 return 0;
549 }
550
551 return write_cryptpacket_id(m, friendnumber, PACKET_ID_NICKNAME, name, length, 0);
552 }
553
554 /* Set the name and name_length of a friend.
555 *
556 * return 0 if success.
557 * return -1 if failure.
558 */
setfriendname(Messenger * m,int32_t friendnumber,const uint8_t * name,uint16_t length)559 int setfriendname(Messenger *m, int32_t friendnumber, const uint8_t *name, uint16_t length)
560 {
561 if (!friend_is_valid(m, friendnumber)) {
562 return -1;
563 }
564
565 if (length > MAX_NAME_LENGTH || length == 0) {
566 return -1;
567 }
568
569 m->friendlist[friendnumber].name_length = length;
570 memcpy(m->friendlist[friendnumber].name, name, length);
571 return 0;
572 }
573
574 /* Set our nickname
575 * name must be a string of maximum MAX_NAME_LENGTH length.
576 * length must be at least 1 byte.
577 * length is the length of name with the NULL terminator.
578 *
579 * return 0 if success.
580 * return -1 if failure.
581 */
setname(Messenger * m,const uint8_t * name,uint16_t length)582 int setname(Messenger *m, const uint8_t *name, uint16_t length)
583 {
584 if (length > MAX_NAME_LENGTH) {
585 return -1;
586 }
587
588 if (m->name_length == length && (length == 0 || memcmp(name, m->name, length) == 0)) {
589 return 0;
590 }
591
592 if (length) {
593 memcpy(m->name, name, length);
594 }
595
596 m->name_length = length;
597 uint32_t i;
598
599 for (i = 0; i < m->numfriends; ++i) {
600 m->friendlist[i].name_sent = 0;
601 }
602
603 return 0;
604 }
605
606 /* Get our nickname and put it in name.
607 * name needs to be a valid memory location with a size of at least MAX_NAME_LENGTH bytes.
608 *
609 * return the length of the name.
610 */
getself_name(const Messenger * m,uint8_t * name)611 uint16_t getself_name(const Messenger *m, uint8_t *name)
612 {
613 if (name == nullptr) {
614 return 0;
615 }
616
617 memcpy(name, m->name, m->name_length);
618
619 return m->name_length;
620 }
621
622 /* Get name of friendnumber and put it in name.
623 * name needs to be a valid memory location with a size of at least MAX_NAME_LENGTH bytes.
624 *
625 * return length of name if success.
626 * return -1 if failure.
627 */
getname(const Messenger * m,int32_t friendnumber,uint8_t * name)628 int getname(const Messenger *m, int32_t friendnumber, uint8_t *name)
629 {
630 if (!friend_is_valid(m, friendnumber)) {
631 return -1;
632 }
633
634 memcpy(name, m->friendlist[friendnumber].name, m->friendlist[friendnumber].name_length);
635 return m->friendlist[friendnumber].name_length;
636 }
637
m_get_name_size(const Messenger * m,int32_t friendnumber)638 int m_get_name_size(const Messenger *m, int32_t friendnumber)
639 {
640 if (!friend_is_valid(m, friendnumber)) {
641 return -1;
642 }
643
644 return m->friendlist[friendnumber].name_length;
645 }
646
m_get_self_name_size(const Messenger * m)647 int m_get_self_name_size(const Messenger *m)
648 {
649 return m->name_length;
650 }
651
m_set_statusmessage(Messenger * m,const uint8_t * status,uint16_t length)652 int m_set_statusmessage(Messenger *m, const uint8_t *status, uint16_t length)
653 {
654 if (length > MAX_STATUSMESSAGE_LENGTH) {
655 return -1;
656 }
657
658 if (m->statusmessage_length == length && (length == 0 || memcmp(m->statusmessage, status, length) == 0)) {
659 return 0;
660 }
661
662 if (length) {
663 memcpy(m->statusmessage, status, length);
664 }
665
666 m->statusmessage_length = length;
667
668 uint32_t i;
669
670 for (i = 0; i < m->numfriends; ++i) {
671 m->friendlist[i].statusmessage_sent = 0;
672 }
673
674 return 0;
675 }
676
m_set_userstatus(Messenger * m,uint8_t status)677 int m_set_userstatus(Messenger *m, uint8_t status)
678 {
679 if (status >= USERSTATUS_INVALID) {
680 return -1;
681 }
682
683 if (m->userstatus == status) {
684 return 0;
685 }
686
687 m->userstatus = (Userstatus)status;
688 uint32_t i;
689
690 for (i = 0; i < m->numfriends; ++i) {
691 m->friendlist[i].userstatus_sent = 0;
692 }
693
694 return 0;
695 }
696
697 /* return the size of friendnumber's user status.
698 * Guaranteed to be at most MAX_STATUSMESSAGE_LENGTH.
699 */
m_get_statusmessage_size(const Messenger * m,int32_t friendnumber)700 int m_get_statusmessage_size(const Messenger *m, int32_t friendnumber)
701 {
702 if (!friend_is_valid(m, friendnumber)) {
703 return -1;
704 }
705
706 return m->friendlist[friendnumber].statusmessage_length;
707 }
708
709 /* Copy the user status of friendnumber into buf, truncating if needed to maxlen
710 * bytes, use m_get_statusmessage_size to find out how much you need to allocate.
711 */
m_copy_statusmessage(const Messenger * m,int32_t friendnumber,uint8_t * buf,uint32_t maxlen)712 int m_copy_statusmessage(const Messenger *m, int32_t friendnumber, uint8_t *buf, uint32_t maxlen)
713 {
714 if (!friend_is_valid(m, friendnumber)) {
715 return -1;
716 }
717
718 // TODO(iphydf): This should be uint16_t and min_u16. If maxlen exceeds
719 // uint16_t's range, it won't affect the result.
720 uint32_t msglen = min_u32(maxlen, m->friendlist[friendnumber].statusmessage_length);
721
722 memcpy(buf, m->friendlist[friendnumber].statusmessage, msglen);
723 memset(buf + msglen, 0, maxlen - msglen);
724 return msglen;
725 }
726
727 /* return the size of friendnumber's user status.
728 * Guaranteed to be at most MAX_STATUSMESSAGE_LENGTH.
729 */
m_get_self_statusmessage_size(const Messenger * m)730 int m_get_self_statusmessage_size(const Messenger *m)
731 {
732 return m->statusmessage_length;
733 }
734
m_copy_self_statusmessage(const Messenger * m,uint8_t * buf)735 int m_copy_self_statusmessage(const Messenger *m, uint8_t *buf)
736 {
737 memcpy(buf, m->statusmessage, m->statusmessage_length);
738 return m->statusmessage_length;
739 }
740
m_get_userstatus(const Messenger * m,int32_t friendnumber)741 uint8_t m_get_userstatus(const Messenger *m, int32_t friendnumber)
742 {
743 if (!friend_is_valid(m, friendnumber)) {
744 return USERSTATUS_INVALID;
745 }
746
747 uint8_t status = m->friendlist[friendnumber].userstatus;
748
749 if (status >= USERSTATUS_INVALID) {
750 status = USERSTATUS_NONE;
751 }
752
753 return status;
754 }
755
m_get_self_userstatus(const Messenger * m)756 uint8_t m_get_self_userstatus(const Messenger *m)
757 {
758 return m->userstatus;
759 }
760
m_get_last_online(const Messenger * m,int32_t friendnumber)761 uint64_t m_get_last_online(const Messenger *m, int32_t friendnumber)
762 {
763 if (!friend_is_valid(m, friendnumber)) {
764 return UINT64_MAX;
765 }
766
767 return m->friendlist[friendnumber].last_seen_time;
768 }
769
m_set_usertyping(Messenger * m,int32_t friendnumber,uint8_t is_typing)770 int m_set_usertyping(Messenger *m, int32_t friendnumber, uint8_t is_typing)
771 {
772 if (is_typing != 0 && is_typing != 1) {
773 return -1;
774 }
775
776 if (!friend_is_valid(m, friendnumber)) {
777 return -1;
778 }
779
780 if (m->friendlist[friendnumber].user_istyping == is_typing) {
781 return 0;
782 }
783
784 m->friendlist[friendnumber].user_istyping = is_typing;
785 m->friendlist[friendnumber].user_istyping_sent = 0;
786
787 return 0;
788 }
789
m_get_istyping(const Messenger * m,int32_t friendnumber)790 int m_get_istyping(const Messenger *m, int32_t friendnumber)
791 {
792 if (!friend_is_valid(m, friendnumber)) {
793 return -1;
794 }
795
796 return m->friendlist[friendnumber].is_typing;
797 }
798
send_statusmessage(const Messenger * m,int32_t friendnumber,const uint8_t * status,uint16_t length)799 static int send_statusmessage(const Messenger *m, int32_t friendnumber, const uint8_t *status, uint16_t length)
800 {
801 return write_cryptpacket_id(m, friendnumber, PACKET_ID_STATUSMESSAGE, status, length, 0);
802 }
803
send_userstatus(const Messenger * m,int32_t friendnumber,uint8_t status)804 static int send_userstatus(const Messenger *m, int32_t friendnumber, uint8_t status)
805 {
806 return write_cryptpacket_id(m, friendnumber, PACKET_ID_USERSTATUS, &status, sizeof(status), 0);
807 }
808
send_user_istyping(const Messenger * m,int32_t friendnumber,uint8_t is_typing)809 static int send_user_istyping(const Messenger *m, int32_t friendnumber, uint8_t is_typing)
810 {
811 uint8_t typing = is_typing;
812 return write_cryptpacket_id(m, friendnumber, PACKET_ID_TYPING, &typing, sizeof(typing), 0);
813 }
814
set_friend_statusmessage(const Messenger * m,int32_t friendnumber,const uint8_t * status,uint16_t length)815 static int set_friend_statusmessage(const Messenger *m, int32_t friendnumber, const uint8_t *status, uint16_t length)
816 {
817 if (!friend_is_valid(m, friendnumber)) {
818 return -1;
819 }
820
821 if (length > MAX_STATUSMESSAGE_LENGTH) {
822 return -1;
823 }
824
825 if (length) {
826 memcpy(m->friendlist[friendnumber].statusmessage, status, length);
827 }
828
829 m->friendlist[friendnumber].statusmessage_length = length;
830 return 0;
831 }
832
set_friend_userstatus(const Messenger * m,int32_t friendnumber,uint8_t status)833 static void set_friend_userstatus(const Messenger *m, int32_t friendnumber, uint8_t status)
834 {
835 m->friendlist[friendnumber].userstatus = (Userstatus)status;
836 }
837
set_friend_typing(const Messenger * m,int32_t friendnumber,uint8_t is_typing)838 static void set_friend_typing(const Messenger *m, int32_t friendnumber, uint8_t is_typing)
839 {
840 m->friendlist[friendnumber].is_typing = is_typing;
841 }
842
843 /* Set the function that will be executed when a friend request is received. */
m_callback_friendrequest(Messenger * m,m_friend_request_cb * function)844 void m_callback_friendrequest(Messenger *m, m_friend_request_cb *function)
845 {
846 callback_friendrequest(m->fr, (fr_friend_request_cb *)function, m);
847 }
848
849 /* Set the function that will be executed when a message from a friend is received. */
m_callback_friendmessage(Messenger * m,m_friend_message_cb * function)850 void m_callback_friendmessage(Messenger *m, m_friend_message_cb *function)
851 {
852 m->friend_message = function;
853 }
854
m_callback_namechange(Messenger * m,m_friend_name_cb * function)855 void m_callback_namechange(Messenger *m, m_friend_name_cb *function)
856 {
857 m->friend_namechange = function;
858 }
859
m_callback_statusmessage(Messenger * m,m_friend_status_message_cb * function)860 void m_callback_statusmessage(Messenger *m, m_friend_status_message_cb *function)
861 {
862 m->friend_statusmessagechange = function;
863 }
864
m_callback_userstatus(Messenger * m,m_friend_status_cb * function)865 void m_callback_userstatus(Messenger *m, m_friend_status_cb *function)
866 {
867 m->friend_userstatuschange = function;
868 }
869
m_callback_typingchange(Messenger * m,m_friend_typing_cb * function)870 void m_callback_typingchange(Messenger *m, m_friend_typing_cb *function)
871 {
872 m->friend_typingchange = function;
873 }
874
m_callback_read_receipt(Messenger * m,m_friend_read_receipt_cb * function)875 void m_callback_read_receipt(Messenger *m, m_friend_read_receipt_cb *function)
876 {
877 m->read_receipt = function;
878 }
879
m_callback_connectionstatus(Messenger * m,m_friend_connection_status_cb * function)880 void m_callback_connectionstatus(Messenger *m, m_friend_connection_status_cb *function)
881 {
882 m->friend_connectionstatuschange = function;
883 }
884
m_callback_core_connection(Messenger * m,m_self_connection_status_cb * function)885 void m_callback_core_connection(Messenger *m, m_self_connection_status_cb *function)
886 {
887 m->core_connection_change = function;
888 }
889
m_callback_connectionstatus_internal_av(Messenger * m,m_friend_connectionstatuschange_internal_cb * function,void * userdata)890 void m_callback_connectionstatus_internal_av(Messenger *m, m_friend_connectionstatuschange_internal_cb *function,
891 void *userdata)
892 {
893 m->friend_connectionstatuschange_internal = function;
894 m->friend_connectionstatuschange_internal_userdata = userdata;
895 }
896
check_friend_tcp_udp(Messenger * m,int32_t friendnumber,void * userdata)897 static void check_friend_tcp_udp(Messenger *m, int32_t friendnumber, void *userdata)
898 {
899 int last_connection_udp_tcp = m->friendlist[friendnumber].last_connection_udp_tcp;
900
901 int ret = m_get_friend_connectionstatus(m, friendnumber);
902
903 if (ret == -1) {
904 return;
905 }
906
907 if (last_connection_udp_tcp != ret) {
908 if (m->friend_connectionstatuschange) {
909 m->friend_connectionstatuschange(m, friendnumber, ret, userdata);
910 }
911 }
912
913 m->friendlist[friendnumber].last_connection_udp_tcp = (Connection_Status)ret;
914 }
915
916 static void break_files(const Messenger *m, int32_t friendnumber);
check_friend_connectionstatus(Messenger * m,int32_t friendnumber,uint8_t status,void * userdata)917 static void check_friend_connectionstatus(Messenger *m, int32_t friendnumber, uint8_t status, void *userdata)
918 {
919 if (status == NOFRIEND) {
920 return;
921 }
922
923 const uint8_t was_online = m->friendlist[friendnumber].status == FRIEND_ONLINE;
924 const uint8_t is_online = status == FRIEND_ONLINE;
925
926 if (is_online != was_online) {
927 if (was_online) {
928 break_files(m, friendnumber);
929 clear_receipts(m, friendnumber);
930 } else {
931 m->friendlist[friendnumber].name_sent = 0;
932 m->friendlist[friendnumber].userstatus_sent = 0;
933 m->friendlist[friendnumber].statusmessage_sent = 0;
934 m->friendlist[friendnumber].user_istyping_sent = 0;
935 }
936
937 m->friendlist[friendnumber].status = status;
938
939 check_friend_tcp_udp(m, friendnumber, userdata);
940
941 if (m->friend_connectionstatuschange_internal) {
942 m->friend_connectionstatuschange_internal(m, friendnumber, is_online,
943 m->friend_connectionstatuschange_internal_userdata);
944 }
945 }
946 }
947
set_friend_status(Messenger * m,int32_t friendnumber,uint8_t status,void * userdata)948 static void set_friend_status(Messenger *m, int32_t friendnumber, uint8_t status, void *userdata)
949 {
950 check_friend_connectionstatus(m, friendnumber, status, userdata);
951 m->friendlist[friendnumber].status = status;
952 }
953
write_cryptpacket_id(const Messenger * m,int32_t friendnumber,uint8_t packet_id,const uint8_t * data,uint32_t length,uint8_t congestion_control)954 static int write_cryptpacket_id(const Messenger *m, int32_t friendnumber, uint8_t packet_id, const uint8_t *data,
955 uint32_t length, uint8_t congestion_control)
956 {
957 if (!friend_is_valid(m, friendnumber)) {
958 return 0;
959 }
960
961 if (length >= MAX_CRYPTO_DATA_SIZE || m->friendlist[friendnumber].status != FRIEND_ONLINE) {
962 return 0;
963 }
964
965 VLA(uint8_t, packet, length + 1);
966 packet[0] = packet_id;
967
968 if (length != 0) {
969 memcpy(packet + 1, data, length);
970 }
971
972 return write_cryptpacket(m->net_crypto, friend_connection_crypt_connection_id(m->fr_c,
973 m->friendlist[friendnumber].friendcon_id), packet, length + 1, congestion_control) != -1;
974 }
975
976 /** CONFERENCES */
977
978
979 /* Set the callback for conference invites.
980 */
m_callback_conference_invite(Messenger * m,m_conference_invite_cb * function)981 void m_callback_conference_invite(Messenger *m, m_conference_invite_cb *function)
982 {
983 m->conference_invite = function;
984 }
985
986
987 /* Send a conference invite packet.
988 *
989 * return 1 on success
990 * return 0 on failure
991 */
send_conference_invite_packet(const Messenger * m,int32_t friendnumber,const uint8_t * data,uint16_t length)992 int send_conference_invite_packet(const Messenger *m, int32_t friendnumber, const uint8_t *data, uint16_t length)
993 {
994 return write_cryptpacket_id(m, friendnumber, PACKET_ID_INVITE_CONFERENCE, data, length, 0);
995 }
996
997 /** FILE SENDING */
998
999
1000 /* Set the callback for file send requests.
1001 */
callback_file_sendrequest(Messenger * m,m_file_recv_cb * function)1002 void callback_file_sendrequest(Messenger *m, m_file_recv_cb *function)
1003 {
1004 m->file_sendrequest = function;
1005 }
1006
1007 /* Set the callback for file control requests.
1008 */
callback_file_control(Messenger * m,m_file_recv_control_cb * function)1009 void callback_file_control(Messenger *m, m_file_recv_control_cb *function)
1010 {
1011 m->file_filecontrol = function;
1012 }
1013
1014 /* Set the callback for file data.
1015 */
callback_file_data(Messenger * m,m_file_recv_chunk_cb * function)1016 void callback_file_data(Messenger *m, m_file_recv_chunk_cb *function)
1017 {
1018 m->file_filedata = function;
1019 }
1020
1021 /* Set the callback for file request chunk.
1022 */
callback_file_reqchunk(Messenger * m,m_file_chunk_request_cb * function)1023 void callback_file_reqchunk(Messenger *m, m_file_chunk_request_cb *function)
1024 {
1025 m->file_reqchunk = function;
1026 }
1027
1028 #define MAX_FILENAME_LENGTH 255
1029
1030 /* Copy the file transfer file id to file_id
1031 *
1032 * return 0 on success.
1033 * return -1 if friend not valid.
1034 * return -2 if filenumber not valid
1035 */
file_get_id(const Messenger * m,int32_t friendnumber,uint32_t filenumber,uint8_t * file_id)1036 int file_get_id(const Messenger *m, int32_t friendnumber, uint32_t filenumber, uint8_t *file_id)
1037 {
1038 if (!friend_is_valid(m, friendnumber)) {
1039 return -1;
1040 }
1041
1042 if (m->friendlist[friendnumber].status != FRIEND_ONLINE) {
1043 return -2;
1044 }
1045
1046 uint32_t temp_filenum;
1047 uint8_t send_receive;
1048 uint8_t file_number;
1049
1050 if (filenumber >= (1 << 16)) {
1051 send_receive = 1;
1052 temp_filenum = (filenumber >> 16) - 1;
1053 } else {
1054 send_receive = 0;
1055 temp_filenum = filenumber;
1056 }
1057
1058 if (temp_filenum >= MAX_CONCURRENT_FILE_PIPES) {
1059 return -2;
1060 }
1061
1062 file_number = temp_filenum;
1063
1064 struct File_Transfers *ft;
1065
1066 if (send_receive) {
1067 ft = &m->friendlist[friendnumber].file_receiving[file_number];
1068 } else {
1069 ft = &m->friendlist[friendnumber].file_sending[file_number];
1070 }
1071
1072 if (ft->status == FILESTATUS_NONE) {
1073 return -2;
1074 }
1075
1076 memcpy(file_id, ft->id, FILE_ID_LENGTH);
1077 return 0;
1078 }
1079
1080 /* Send a file send request.
1081 * Maximum filename length is 255 bytes.
1082 * return 1 on success
1083 * return 0 on failure
1084 */
file_sendrequest(const Messenger * m,int32_t friendnumber,uint8_t filenumber,uint32_t file_type,uint64_t filesize,const uint8_t * file_id,const uint8_t * filename,uint16_t filename_length)1085 static int file_sendrequest(const Messenger *m, int32_t friendnumber, uint8_t filenumber, uint32_t file_type,
1086 uint64_t filesize, const uint8_t *file_id, const uint8_t *filename, uint16_t filename_length)
1087 {
1088 if (!friend_is_valid(m, friendnumber)) {
1089 return 0;
1090 }
1091
1092 if (filename_length > MAX_FILENAME_LENGTH) {
1093 return 0;
1094 }
1095
1096 VLA(uint8_t, packet, 1 + sizeof(file_type) + sizeof(filesize) + FILE_ID_LENGTH + filename_length);
1097 packet[0] = filenumber;
1098 file_type = net_htonl(file_type);
1099 memcpy(packet + 1, &file_type, sizeof(file_type));
1100 net_pack_u64(packet + 1 + sizeof(file_type), filesize);
1101 memcpy(packet + 1 + sizeof(file_type) + sizeof(filesize), file_id, FILE_ID_LENGTH);
1102
1103 if (filename_length) {
1104 memcpy(packet + 1 + sizeof(file_type) + sizeof(filesize) + FILE_ID_LENGTH, filename, filename_length);
1105 }
1106
1107 return write_cryptpacket_id(m, friendnumber, PACKET_ID_FILE_SENDREQUEST, packet, SIZEOF_VLA(packet), 0);
1108 }
1109
1110 /* Send a file send request.
1111 * Maximum filename length is 255 bytes.
1112 * return file number on success
1113 * return -1 if friend not found.
1114 * return -2 if filename length invalid.
1115 * return -3 if no more file sending slots left.
1116 * return -4 if could not send packet (friend offline).
1117 *
1118 */
new_filesender(const Messenger * m,int32_t friendnumber,uint32_t file_type,uint64_t filesize,const uint8_t * file_id,const uint8_t * filename,uint16_t filename_length)1119 long int new_filesender(const Messenger *m, int32_t friendnumber, uint32_t file_type, uint64_t filesize,
1120 const uint8_t *file_id, const uint8_t *filename, uint16_t filename_length)
1121 {
1122 if (!friend_is_valid(m, friendnumber)) {
1123 return -1;
1124 }
1125
1126 if (filename_length > MAX_FILENAME_LENGTH) {
1127 return -2;
1128 }
1129
1130 uint32_t i;
1131
1132 for (i = 0; i < MAX_CONCURRENT_FILE_PIPES; ++i) {
1133 if (m->friendlist[friendnumber].file_sending[i].status == FILESTATUS_NONE) {
1134 break;
1135 }
1136 }
1137
1138 if (i == MAX_CONCURRENT_FILE_PIPES) {
1139 return -3;
1140 }
1141
1142 if (file_sendrequest(m, friendnumber, i, file_type, filesize, file_id, filename, filename_length) == 0) {
1143 return -4;
1144 }
1145
1146 struct File_Transfers *ft = &m->friendlist[friendnumber].file_sending[i];
1147
1148 ft->status = FILESTATUS_NOT_ACCEPTED;
1149
1150 ft->size = filesize;
1151
1152 ft->transferred = 0;
1153
1154 ft->requested = 0;
1155
1156 ft->paused = FILE_PAUSE_NOT;
1157
1158 memcpy(ft->id, file_id, FILE_ID_LENGTH);
1159
1160 ++m->friendlist[friendnumber].num_sending_files;
1161
1162 return i;
1163 }
1164
send_file_control_packet(const Messenger * m,int32_t friendnumber,uint8_t send_receive,uint8_t filenumber,uint8_t control_type,uint8_t * data,uint16_t data_length)1165 static int send_file_control_packet(const Messenger *m, int32_t friendnumber, uint8_t send_receive, uint8_t filenumber,
1166 uint8_t control_type, uint8_t *data, uint16_t data_length)
1167 {
1168 if ((unsigned int)(1 + 3 + data_length) > MAX_CRYPTO_DATA_SIZE) {
1169 return -1;
1170 }
1171
1172 VLA(uint8_t, packet, 3 + data_length);
1173
1174 packet[0] = send_receive;
1175 packet[1] = filenumber;
1176 packet[2] = control_type;
1177
1178 if (data_length) {
1179 memcpy(packet + 3, data, data_length);
1180 }
1181
1182 return write_cryptpacket_id(m, friendnumber, PACKET_ID_FILE_CONTROL, packet, SIZEOF_VLA(packet), 0);
1183 }
1184
1185 /* Send a file control request.
1186 *
1187 * return 0 on success
1188 * return -1 if friend not valid.
1189 * return -2 if friend not online.
1190 * return -3 if file number invalid.
1191 * return -4 if file control is bad.
1192 * return -5 if file already paused.
1193 * return -6 if resume file failed because it was only paused by the other.
1194 * return -7 if resume file failed because it wasn't paused.
1195 * return -8 if packet failed to send.
1196 */
file_control(const Messenger * m,int32_t friendnumber,uint32_t filenumber,unsigned int control)1197 int file_control(const Messenger *m, int32_t friendnumber, uint32_t filenumber, unsigned int control)
1198 {
1199 if (!friend_is_valid(m, friendnumber)) {
1200 return -1;
1201 }
1202
1203 if (m->friendlist[friendnumber].status != FRIEND_ONLINE) {
1204 return -2;
1205 }
1206
1207 uint32_t temp_filenum;
1208 uint8_t send_receive;
1209 uint8_t file_number;
1210
1211 if (filenumber >= (1 << 16)) {
1212 send_receive = 1;
1213 temp_filenum = (filenumber >> 16) - 1;
1214 } else {
1215 send_receive = 0;
1216 temp_filenum = filenumber;
1217 }
1218
1219 if (temp_filenum >= MAX_CONCURRENT_FILE_PIPES) {
1220 return -3;
1221 }
1222
1223 file_number = temp_filenum;
1224
1225 struct File_Transfers *ft;
1226
1227 if (send_receive) {
1228 ft = &m->friendlist[friendnumber].file_receiving[file_number];
1229 } else {
1230 ft = &m->friendlist[friendnumber].file_sending[file_number];
1231 }
1232
1233 if (ft->status == FILESTATUS_NONE) {
1234 return -3;
1235 }
1236
1237 if (control > FILECONTROL_KILL) {
1238 return -4;
1239 }
1240
1241 if (control == FILECONTROL_PAUSE && ((ft->paused & FILE_PAUSE_US) || ft->status != FILESTATUS_TRANSFERRING)) {
1242 return -5;
1243 }
1244
1245 if (control == FILECONTROL_ACCEPT) {
1246 if (ft->status == FILESTATUS_TRANSFERRING) {
1247 if (!(ft->paused & FILE_PAUSE_US)) {
1248 if (ft->paused & FILE_PAUSE_OTHER) {
1249 return -6;
1250 }
1251
1252 return -7;
1253 }
1254 } else {
1255 if (ft->status != FILESTATUS_NOT_ACCEPTED) {
1256 return -7;
1257 }
1258
1259 if (!send_receive) {
1260 return -6;
1261 }
1262 }
1263 }
1264
1265 if (send_file_control_packet(m, friendnumber, send_receive, file_number, control, nullptr, 0)) {
1266 if (control == FILECONTROL_KILL) {
1267 ft->status = FILESTATUS_NONE;
1268
1269 if (send_receive == 0) {
1270 --m->friendlist[friendnumber].num_sending_files;
1271 }
1272 } else if (control == FILECONTROL_PAUSE) {
1273 ft->paused |= FILE_PAUSE_US;
1274 } else if (control == FILECONTROL_ACCEPT) {
1275 ft->status = FILESTATUS_TRANSFERRING;
1276
1277 if (ft->paused & FILE_PAUSE_US) {
1278 ft->paused ^= FILE_PAUSE_US;
1279 }
1280 }
1281 } else {
1282 return -8;
1283 }
1284
1285 return 0;
1286 }
1287
1288 /* Send a seek file control request.
1289 *
1290 * return 0 on success
1291 * return -1 if friend not valid.
1292 * return -2 if friend not online.
1293 * return -3 if file number invalid.
1294 * return -4 if not receiving file.
1295 * return -5 if file status wrong.
1296 * return -6 if position bad.
1297 * return -8 if packet failed to send.
1298 */
file_seek(const Messenger * m,int32_t friendnumber,uint32_t filenumber,uint64_t position)1299 int file_seek(const Messenger *m, int32_t friendnumber, uint32_t filenumber, uint64_t position)
1300 {
1301 if (!friend_is_valid(m, friendnumber)) {
1302 return -1;
1303 }
1304
1305 if (m->friendlist[friendnumber].status != FRIEND_ONLINE) {
1306 return -2;
1307 }
1308
1309 if (filenumber < (1 << 16)) {
1310 // Not receiving.
1311 return -4;
1312 }
1313
1314 uint32_t temp_filenum = (filenumber >> 16) - 1;
1315
1316 if (temp_filenum >= MAX_CONCURRENT_FILE_PIPES) {
1317 return -3;
1318 }
1319
1320 assert(temp_filenum <= UINT8_MAX);
1321 uint8_t file_number = temp_filenum;
1322
1323 // We're always receiving at this point.
1324 struct File_Transfers *ft = &m->friendlist[friendnumber].file_receiving[file_number];
1325
1326 if (ft->status == FILESTATUS_NONE) {
1327 return -3;
1328 }
1329
1330 if (ft->status != FILESTATUS_NOT_ACCEPTED) {
1331 return -5;
1332 }
1333
1334 if (position >= ft->size) {
1335 return -6;
1336 }
1337
1338 uint8_t sending_pos[sizeof(uint64_t)];
1339 net_pack_u64(sending_pos, position);
1340
1341 if (send_file_control_packet(m, friendnumber, 1, file_number, FILECONTROL_SEEK, sending_pos,
1342 sizeof(sending_pos))) {
1343 ft->transferred = position;
1344 } else {
1345 return -8;
1346 }
1347
1348 return 0;
1349 }
1350
1351 /* return packet number on success.
1352 * return -1 on failure.
1353 */
send_file_data_packet(const Messenger * m,int32_t friendnumber,uint8_t filenumber,const uint8_t * data,uint16_t length)1354 static int64_t send_file_data_packet(const Messenger *m, int32_t friendnumber, uint8_t filenumber, const uint8_t *data,
1355 uint16_t length)
1356 {
1357 if (!friend_is_valid(m, friendnumber)) {
1358 return -1;
1359 }
1360
1361 VLA(uint8_t, packet, 2 + length);
1362 packet[0] = PACKET_ID_FILE_DATA;
1363 packet[1] = filenumber;
1364
1365 if (length) {
1366 memcpy(packet + 2, data, length);
1367 }
1368
1369 return write_cryptpacket(m->net_crypto, friend_connection_crypt_connection_id(m->fr_c,
1370 m->friendlist[friendnumber].friendcon_id), packet, SIZEOF_VLA(packet), 1);
1371 }
1372
1373 #define MAX_FILE_DATA_SIZE (MAX_CRYPTO_DATA_SIZE - 2)
1374 #define MIN_SLOTS_FREE (CRYPTO_MIN_QUEUE_LENGTH / 4)
1375 /* Send file data.
1376 *
1377 * return 0 on success
1378 * return -1 if friend not valid.
1379 * return -2 if friend not online.
1380 * return -3 if filenumber invalid.
1381 * return -4 if file transfer not transferring.
1382 * return -5 if bad data size.
1383 * return -6 if packet queue full.
1384 * return -7 if wrong position.
1385 */
file_data(const Messenger * m,int32_t friendnumber,uint32_t filenumber,uint64_t position,const uint8_t * data,uint16_t length)1386 int file_data(const Messenger *m, int32_t friendnumber, uint32_t filenumber, uint64_t position, const uint8_t *data,
1387 uint16_t length)
1388 {
1389 if (!friend_is_valid(m, friendnumber)) {
1390 return -1;
1391 }
1392
1393 if (m->friendlist[friendnumber].status != FRIEND_ONLINE) {
1394 return -2;
1395 }
1396
1397 if (filenumber >= MAX_CONCURRENT_FILE_PIPES) {
1398 return -3;
1399 }
1400
1401 struct File_Transfers *ft = &m->friendlist[friendnumber].file_sending[filenumber];
1402
1403 if (ft->status != FILESTATUS_TRANSFERRING) {
1404 return -4;
1405 }
1406
1407 if (length > MAX_FILE_DATA_SIZE) {
1408 return -5;
1409 }
1410
1411 if (ft->size - ft->transferred < length) {
1412 return -5;
1413 }
1414
1415 if (ft->size != UINT64_MAX && length != MAX_FILE_DATA_SIZE && (ft->transferred + length) != ft->size) {
1416 return -5;
1417 }
1418
1419 if (position != ft->transferred || (ft->requested <= position && ft->size != 0)) {
1420 return -7;
1421 }
1422
1423 /* Prevent file sending from filling up the entire buffer preventing messages from being sent.
1424 * TODO(irungentoo): remove */
1425 if (crypto_num_free_sendqueue_slots(m->net_crypto, friend_connection_crypt_connection_id(m->fr_c,
1426 m->friendlist[friendnumber].friendcon_id)) < MIN_SLOTS_FREE) {
1427 return -6;
1428 }
1429
1430 int64_t ret = send_file_data_packet(m, friendnumber, filenumber, data, length);
1431
1432 if (ret != -1) {
1433 // TODO(irungentoo): record packet ids to check if other received complete file.
1434 ft->transferred += length;
1435
1436 if (length != MAX_FILE_DATA_SIZE || ft->size == ft->transferred) {
1437 ft->status = FILESTATUS_FINISHED;
1438 ft->last_packet_number = ret;
1439 }
1440
1441 return 0;
1442 }
1443
1444 return -6;
1445 }
1446
1447 /**
1448 * Iterate over all file transfers and request chunks (from the client) for each
1449 * of them.
1450 *
1451 * The free_slots parameter is updated by this function.
1452 *
1453 * @param m Our messenger object.
1454 * @param friendnumber The friend we're sending files to.
1455 * @param userdata The client userdata to pass along to chunk request callbacks.
1456 * @param free_slots A pointer to the number of free send queue slots in the
1457 * crypto connection.
1458 * @return true if there's still work to do, false otherwise.
1459 *
1460 */
do_all_filetransfers(Messenger * m,int32_t friendnumber,void * userdata,uint32_t * free_slots)1461 static bool do_all_filetransfers(Messenger *m, int32_t friendnumber, void *userdata, uint32_t *free_slots)
1462 {
1463 Friend *const friendcon = &m->friendlist[friendnumber];
1464
1465 // Iterate over file transfers as long as we're sending files
1466 for (uint32_t i = 0; i < MAX_CONCURRENT_FILE_PIPES; ++i) {
1467 if (friendcon->num_sending_files == 0) {
1468 // no active file transfers anymore
1469 return false;
1470 }
1471
1472 if (*free_slots == 0) {
1473 // send buffer full enough
1474 return false;
1475 }
1476
1477 if (max_speed_reached(m->net_crypto, friend_connection_crypt_connection_id(
1478 m->fr_c, friendcon->friendcon_id))) {
1479 LOGGER_TRACE(m->log, "Maximum connection speed reached");
1480 // connection doesn't support any more data
1481 return false;
1482 }
1483
1484 struct File_Transfers *const ft = &friendcon->file_sending[i];
1485
1486 // If the file transfer is complete, we request a chunk of size 0.
1487 if (ft->status == FILESTATUS_FINISHED && friend_received_packet(m, friendnumber, ft->last_packet_number) == 0) {
1488 if (m->file_reqchunk) {
1489 m->file_reqchunk(m, friendnumber, i, ft->transferred, 0, userdata);
1490 }
1491
1492 // Now it's inactive, we're no longer sending this.
1493 ft->status = FILESTATUS_NONE;
1494 --friendcon->num_sending_files;
1495 }
1496
1497 if (ft->status == FILESTATUS_TRANSFERRING && ft->paused == FILE_PAUSE_NOT) {
1498 if (ft->size == 0) {
1499 /* Send 0 data to friend if file is 0 length. */
1500 file_data(m, friendnumber, i, 0, nullptr, 0);
1501 continue;
1502 }
1503
1504 if (ft->size == ft->requested) {
1505 // This file transfer is done.
1506 continue;
1507 }
1508
1509 const uint16_t length = min_u64(ft->size - ft->requested, MAX_FILE_DATA_SIZE);
1510 const uint64_t position = ft->requested;
1511 ft->requested += length;
1512
1513 if (m->file_reqchunk) {
1514 m->file_reqchunk(m, friendnumber, i, position, length, userdata);
1515 }
1516
1517 // The allocated slot is no longer free.
1518 --*free_slots;
1519 }
1520 }
1521
1522 return true;
1523 }
1524
do_reqchunk_filecb(Messenger * m,int32_t friendnumber,void * userdata)1525 static void do_reqchunk_filecb(Messenger *m, int32_t friendnumber, void *userdata)
1526 {
1527 // We're not currently doing any file transfers.
1528 if (m->friendlist[friendnumber].num_sending_files == 0) {
1529 return;
1530 }
1531
1532 // The number of packet slots left in the sendbuffer.
1533 // This is a per friend count (CRYPTO_PACKET_BUFFER_SIZE).
1534 uint32_t free_slots = crypto_num_free_sendqueue_slots(
1535 m->net_crypto,
1536 friend_connection_crypt_connection_id(
1537 m->fr_c,
1538 m->friendlist[friendnumber].friendcon_id));
1539
1540 // We keep MIN_SLOTS_FREE slots free for other packets, otherwise file
1541 // transfers might block other traffic for a long time.
1542 free_slots = max_s32(0, (int32_t)free_slots - MIN_SLOTS_FREE);
1543
1544 // Maximum number of outer loops below. If the client doesn't send file
1545 // chunks from within the chunk request callback handler, we never realise
1546 // that the file transfer has finished and may end up in an infinite loop.
1547 //
1548 // Request up to that number of chunks per file from the client
1549 const uint32_t max_ft_loops = 16;
1550
1551 for (uint32_t i = 0; i < max_ft_loops; ++i) {
1552 if (!do_all_filetransfers(m, friendnumber, userdata, &free_slots)) {
1553 break;
1554 }
1555
1556 if (free_slots == 0) {
1557 // stop when the buffer is full enough
1558 break;
1559 }
1560 }
1561 }
1562
1563
1564 /* Run this when the friend disconnects.
1565 * Kill all current file transfers.
1566 */
break_files(const Messenger * m,int32_t friendnumber)1567 static void break_files(const Messenger *m, int32_t friendnumber)
1568 {
1569 // TODO(irungentoo): Inform the client which file transfers get killed with a callback?
1570 for (uint32_t i = 0; i < MAX_CONCURRENT_FILE_PIPES; ++i) {
1571 if (m->friendlist[friendnumber].file_sending[i].status != FILESTATUS_NONE) {
1572 m->friendlist[friendnumber].file_sending[i].status = FILESTATUS_NONE;
1573 }
1574
1575 if (m->friendlist[friendnumber].file_receiving[i].status != FILESTATUS_NONE) {
1576 m->friendlist[friendnumber].file_receiving[i].status = FILESTATUS_NONE;
1577 }
1578 }
1579 }
1580
get_file_transfer(uint8_t receive_send,uint8_t filenumber,uint32_t * real_filenumber,Friend * sender)1581 static struct File_Transfers *get_file_transfer(uint8_t receive_send, uint8_t filenumber,
1582 uint32_t *real_filenumber, Friend *sender)
1583 {
1584 struct File_Transfers *ft;
1585
1586 if (receive_send == 0) {
1587 *real_filenumber = (filenumber + 1) << 16;
1588 ft = &sender->file_receiving[filenumber];
1589 } else {
1590 *real_filenumber = filenumber;
1591 ft = &sender->file_sending[filenumber];
1592 }
1593
1594 if (ft->status == FILESTATUS_NONE) {
1595 return nullptr;
1596 }
1597
1598 return ft;
1599 }
1600
1601 /* return -1 on failure, 0 on success.
1602 */
handle_filecontrol(Messenger * m,int32_t friendnumber,uint8_t receive_send,uint8_t filenumber,uint8_t control_type,const uint8_t * data,uint16_t length,void * userdata)1603 static int handle_filecontrol(Messenger *m, int32_t friendnumber, uint8_t receive_send, uint8_t filenumber,
1604 uint8_t control_type, const uint8_t *data, uint16_t length, void *userdata)
1605 {
1606 if (receive_send > 1) {
1607 LOGGER_DEBUG(m->log, "file control (friend %d, file %d): receive_send value is invalid (should be 0 or 1): %d",
1608 friendnumber, filenumber, receive_send);
1609 return -1;
1610 }
1611
1612 uint32_t real_filenumber;
1613 struct File_Transfers *ft = get_file_transfer(receive_send, filenumber, &real_filenumber, &m->friendlist[friendnumber]);
1614
1615 if (ft == nullptr) {
1616 LOGGER_DEBUG(m->log, "file control (friend %d, file %d): file transfer does not exist; telling the other to kill it",
1617 friendnumber, filenumber);
1618 send_file_control_packet(m, friendnumber, !receive_send, filenumber, FILECONTROL_KILL, nullptr, 0);
1619 return -1;
1620 }
1621
1622 switch (control_type) {
1623 case FILECONTROL_ACCEPT: {
1624 if (receive_send && ft->status == FILESTATUS_NOT_ACCEPTED) {
1625 ft->status = FILESTATUS_TRANSFERRING;
1626 } else {
1627 if (ft->paused & FILE_PAUSE_OTHER) {
1628 ft->paused ^= FILE_PAUSE_OTHER;
1629 } else {
1630 LOGGER_DEBUG(m->log, "file control (friend %d, file %d): friend told us to resume file transfer that wasn't paused",
1631 friendnumber, filenumber);
1632 return -1;
1633 }
1634 }
1635
1636 if (m->file_filecontrol) {
1637 m->file_filecontrol(m, friendnumber, real_filenumber, control_type, userdata);
1638 }
1639
1640 return 0;
1641 }
1642
1643 case FILECONTROL_PAUSE: {
1644 if ((ft->paused & FILE_PAUSE_OTHER) || ft->status != FILESTATUS_TRANSFERRING) {
1645 LOGGER_DEBUG(m->log, "file control (friend %d, file %d): friend told us to pause file transfer that is already paused",
1646 friendnumber, filenumber);
1647 return -1;
1648 }
1649
1650 ft->paused |= FILE_PAUSE_OTHER;
1651
1652 if (m->file_filecontrol) {
1653 m->file_filecontrol(m, friendnumber, real_filenumber, control_type, userdata);
1654 }
1655
1656 return 0;
1657 }
1658
1659 case FILECONTROL_KILL: {
1660 if (m->file_filecontrol) {
1661 m->file_filecontrol(m, friendnumber, real_filenumber, control_type, userdata);
1662 }
1663
1664 ft->status = FILESTATUS_NONE;
1665
1666 if (receive_send) {
1667 --m->friendlist[friendnumber].num_sending_files;
1668 }
1669
1670 return 0;
1671 }
1672
1673 case FILECONTROL_SEEK: {
1674 uint64_t position;
1675
1676 if (length != sizeof(position)) {
1677 LOGGER_DEBUG(m->log, "file control (friend %d, file %d): expected payload of length %d, but got %d",
1678 friendnumber, filenumber, (uint32_t)sizeof(position), length);
1679 return -1;
1680 }
1681
1682 /* seek can only be sent by the receiver to seek before resuming broken transfers. */
1683 if (ft->status != FILESTATUS_NOT_ACCEPTED || !receive_send) {
1684 LOGGER_DEBUG(m->log,
1685 "file control (friend %d, file %d): seek was either sent by a sender or by the receiver after accepting",
1686 friendnumber, filenumber);
1687 return -1;
1688 }
1689
1690 net_unpack_u64(data, &position);
1691
1692 if (position >= ft->size) {
1693 LOGGER_DEBUG(m->log,
1694 "file control (friend %d, file %d): seek position %ld exceeds file size %ld",
1695 friendnumber, filenumber, (unsigned long)position, (unsigned long)ft->size);
1696 return -1;
1697 }
1698
1699 ft->requested = position;
1700 ft->transferred = position;
1701 return 0;
1702 }
1703
1704 default: {
1705 LOGGER_DEBUG(m->log, "file control (friend %d, file %d): invalid file control: %d",
1706 friendnumber, filenumber, control_type);
1707 return -1;
1708 }
1709 }
1710 }
1711
1712 /* Set the callback for msi packets.
1713 */
m_callback_msi_packet(Messenger * m,m_msi_packet_cb * function,void * userdata)1714 void m_callback_msi_packet(Messenger *m, m_msi_packet_cb *function, void *userdata)
1715 {
1716 m->msi_packet = function;
1717 m->msi_packet_userdata = userdata;
1718 }
1719
1720 /* Send an msi packet.
1721 *
1722 * return 1 on success
1723 * return 0 on failure
1724 */
m_msi_packet(const Messenger * m,int32_t friendnumber,const uint8_t * data,uint16_t length)1725 int m_msi_packet(const Messenger *m, int32_t friendnumber, const uint8_t *data, uint16_t length)
1726 {
1727 return write_cryptpacket_id(m, friendnumber, PACKET_ID_MSI, data, length, 0);
1728 }
1729
m_handle_lossy_packet(void * object,int friend_num,const uint8_t * packet,uint16_t length,void * userdata)1730 static int m_handle_lossy_packet(void *object, int friend_num, const uint8_t *packet, uint16_t length,
1731 void *userdata)
1732 {
1733 Messenger *m = (Messenger *)object;
1734
1735 if (!friend_is_valid(m, friend_num)) {
1736 return 1;
1737 }
1738
1739 if (packet[0] <= PACKET_ID_RANGE_LOSSY_AV_END) {
1740 const RTP_Packet_Handler *const ph =
1741 &m->friendlist[friend_num].lossy_rtp_packethandlers[packet[0] % PACKET_ID_RANGE_LOSSY_AV_SIZE];
1742
1743 if (ph->function) {
1744 return ph->function(m, friend_num, packet, length, ph->object);
1745 }
1746
1747 return 1;
1748 }
1749
1750 if (m->lossy_packethandler) {
1751 m->lossy_packethandler(m, friend_num, packet[0], packet, length, userdata);
1752 }
1753
1754 return 1;
1755 }
1756
custom_lossy_packet_registerhandler(Messenger * m,m_friend_lossy_packet_cb * lossy_packethandler)1757 void custom_lossy_packet_registerhandler(Messenger *m, m_friend_lossy_packet_cb *lossy_packethandler)
1758 {
1759 m->lossy_packethandler = lossy_packethandler;
1760 }
1761
m_callback_rtp_packet(Messenger * m,int32_t friendnumber,uint8_t byte,m_lossy_rtp_packet_cb * function,void * object)1762 int m_callback_rtp_packet(Messenger *m, int32_t friendnumber, uint8_t byte, m_lossy_rtp_packet_cb *function,
1763 void *object)
1764 {
1765 if (!friend_is_valid(m, friendnumber)) {
1766 return -1;
1767 }
1768
1769 if (byte < PACKET_ID_RANGE_LOSSY_AV_START || byte > PACKET_ID_RANGE_LOSSY_AV_END) {
1770 return -1;
1771 }
1772
1773 m->friendlist[friendnumber].lossy_rtp_packethandlers[byte % PACKET_ID_RANGE_LOSSY_AV_SIZE].function = function;
1774 m->friendlist[friendnumber].lossy_rtp_packethandlers[byte % PACKET_ID_RANGE_LOSSY_AV_SIZE].object = object;
1775 return 0;
1776 }
1777
1778
1779 /* TODO(oxij): this name is confusing, because this function sends both av and custom lossy packets.
1780 * Meanwhile, m_handle_lossy_packet routes custom packets to custom_lossy_packet_registerhandler
1781 * as you would expect from its name.
1782 *
1783 * I.e. custom_lossy_packet_registerhandler's "custom lossy packet" and this "custom lossy packet"
1784 * are not the same set of packets.
1785 */
m_send_custom_lossy_packet(const Messenger * m,int32_t friendnumber,const uint8_t * data,uint32_t length)1786 int m_send_custom_lossy_packet(const Messenger *m, int32_t friendnumber, const uint8_t *data, uint32_t length)
1787 {
1788 if (!friend_is_valid(m, friendnumber)) {
1789 return -1;
1790 }
1791
1792 if (length == 0 || length > MAX_CRYPTO_DATA_SIZE) {
1793 return -2;
1794 }
1795
1796 // TODO(oxij): send_lossy_cryptpacket makes this check already, similarly for other similar places
1797 if (data[0] < PACKET_ID_RANGE_LOSSY_START || data[0] > PACKET_ID_RANGE_LOSSY_END) {
1798 return -3;
1799 }
1800
1801 if (m->friendlist[friendnumber].status != FRIEND_ONLINE) {
1802 return -4;
1803 }
1804
1805 if (send_lossy_cryptpacket(m->net_crypto, friend_connection_crypt_connection_id(m->fr_c,
1806 m->friendlist[friendnumber].friendcon_id), data, length) == -1) {
1807 return -5;
1808 }
1809
1810 return 0;
1811 }
1812
handle_custom_lossless_packet(void * object,int friend_num,const uint8_t * packet,uint16_t length,void * userdata)1813 static int handle_custom_lossless_packet(void *object, int friend_num, const uint8_t *packet, uint16_t length,
1814 void *userdata)
1815 {
1816 Messenger *m = (Messenger *)object;
1817
1818 if (!friend_is_valid(m, friend_num)) {
1819 return -1;
1820 }
1821
1822 if (packet[0] < PACKET_ID_RANGE_LOSSLESS_CUSTOM_START || packet[0] > PACKET_ID_RANGE_LOSSLESS_CUSTOM_END) {
1823 return -1;
1824 }
1825
1826 if (m->lossless_packethandler) {
1827 m->lossless_packethandler(m, friend_num, packet[0], packet, length, userdata);
1828 }
1829
1830 return 1;
1831 }
1832
custom_lossless_packet_registerhandler(Messenger * m,m_friend_lossless_packet_cb * lossless_packethandler)1833 void custom_lossless_packet_registerhandler(Messenger *m, m_friend_lossless_packet_cb *lossless_packethandler)
1834 {
1835 m->lossless_packethandler = lossless_packethandler;
1836 }
1837
send_custom_lossless_packet(const Messenger * m,int32_t friendnumber,const uint8_t * data,uint32_t length)1838 int send_custom_lossless_packet(const Messenger *m, int32_t friendnumber, const uint8_t *data, uint32_t length)
1839 {
1840 if (!friend_is_valid(m, friendnumber)) {
1841 return -1;
1842 }
1843
1844 if (length == 0 || length > MAX_CRYPTO_DATA_SIZE) {
1845 return -2;
1846 }
1847
1848 if ((data[0] < PACKET_ID_RANGE_LOSSLESS_CUSTOM_START || data[0] > PACKET_ID_RANGE_LOSSLESS_CUSTOM_END)
1849 && data[0] != PACKET_ID_MSI) {
1850 return -3;
1851 }
1852
1853 if (m->friendlist[friendnumber].status != FRIEND_ONLINE) {
1854 return -4;
1855 }
1856
1857 if (write_cryptpacket(m->net_crypto, friend_connection_crypt_connection_id(m->fr_c,
1858 m->friendlist[friendnumber].friendcon_id), data, length, 1) == -1) {
1859 return -5;
1860 }
1861
1862 return 0;
1863 }
1864
1865 /* Function to filter out some friend requests*/
friend_already_added(const uint8_t * real_pk,void * data)1866 static int friend_already_added(const uint8_t *real_pk, void *data)
1867 {
1868 const Messenger *m = (const Messenger *)data;
1869
1870 if (getfriend_id(m, real_pk) == -1) {
1871 return 0;
1872 }
1873
1874 return -1;
1875 }
1876
1877 /* Run this at startup. */
new_messenger(Mono_Time * mono_time,Messenger_Options * options,unsigned int * error)1878 Messenger *new_messenger(Mono_Time *mono_time, Messenger_Options *options, unsigned int *error)
1879 {
1880 if (!options) {
1881 return nullptr;
1882 }
1883
1884 if (error) {
1885 *error = MESSENGER_ERROR_OTHER;
1886 }
1887
1888 Messenger *m = (Messenger *)calloc(1, sizeof(Messenger));
1889
1890 if (!m) {
1891 return nullptr;
1892 }
1893
1894 m->mono_time = mono_time;
1895
1896 m->fr = friendreq_new();
1897
1898 if (!m->fr) {
1899 free(m);
1900 return nullptr;
1901 }
1902
1903 m->log = logger_new();
1904
1905 if (m->log == nullptr) {
1906 friendreq_kill(m->fr);
1907 free(m);
1908 return nullptr;
1909 }
1910
1911 logger_callback_log(m->log, options->log_callback, options->log_context, options->log_user_data);
1912
1913 unsigned int net_err = 0;
1914
1915 if (!options->udp_disabled && options->proxy_info.proxy_type != TCP_PROXY_NONE) {
1916 // We don't currently support UDP over proxy.
1917 LOGGER_WARNING(m->log, "UDP enabled and proxy set: disabling UDP");
1918 options->udp_disabled = true;
1919 }
1920
1921 if (options->udp_disabled) {
1922 m->net = new_networking_no_udp(m->log);
1923 } else {
1924 IP ip;
1925 ip_init(&ip, options->ipv6enabled);
1926 m->net = new_networking_ex(m->log, ip, options->port_range[0], options->port_range[1], &net_err);
1927 }
1928
1929 if (m->net == nullptr) {
1930 friendreq_kill(m->fr);
1931 logger_kill(m->log);
1932 free(m);
1933
1934 if (error && net_err == 1) {
1935 *error = MESSENGER_ERROR_PORT;
1936 }
1937
1938 return nullptr;
1939 }
1940
1941 m->dht = new_dht(m->log, m->mono_time, m->net, options->hole_punching_enabled);
1942
1943 if (m->dht == nullptr) {
1944 kill_networking(m->net);
1945 friendreq_kill(m->fr);
1946 logger_kill(m->log);
1947 free(m);
1948 return nullptr;
1949 }
1950
1951 m->net_crypto = new_net_crypto(m->log, m->mono_time, m->dht, &options->proxy_info);
1952
1953 if (m->net_crypto == nullptr) {
1954 kill_dht(m->dht);
1955 kill_networking(m->net);
1956 friendreq_kill(m->fr);
1957 logger_kill(m->log);
1958 free(m);
1959 return nullptr;
1960 }
1961
1962 m->onion = new_onion(m->mono_time, m->dht);
1963 m->onion_a = new_onion_announce(m->mono_time, m->dht);
1964 m->onion_c = new_onion_client(m->log, m->mono_time, m->net_crypto);
1965 m->fr_c = new_friend_connections(m->log, m->mono_time, m->onion_c, options->local_discovery_enabled);
1966
1967 if (!(m->onion && m->onion_a && m->onion_c && m->fr_c)) {
1968 kill_friend_connections(m->fr_c);
1969 kill_onion(m->onion);
1970 kill_onion_announce(m->onion_a);
1971 kill_onion_client(m->onion_c);
1972 kill_net_crypto(m->net_crypto);
1973 kill_dht(m->dht);
1974 kill_networking(m->net);
1975 friendreq_kill(m->fr);
1976 logger_kill(m->log);
1977 free(m);
1978 return nullptr;
1979 }
1980
1981 if (options->tcp_server_port) {
1982 m->tcp_server = new_TCP_server(m->log, options->ipv6enabled, 1, &options->tcp_server_port,
1983 dht_get_self_secret_key(m->dht), m->onion);
1984
1985 if (m->tcp_server == nullptr) {
1986 kill_friend_connections(m->fr_c);
1987 kill_onion(m->onion);
1988 kill_onion_announce(m->onion_a);
1989 kill_onion_client(m->onion_c);
1990 kill_net_crypto(m->net_crypto);
1991 kill_dht(m->dht);
1992 kill_networking(m->net);
1993 friendreq_kill(m->fr);
1994 logger_kill(m->log);
1995 free(m);
1996
1997 if (error) {
1998 *error = MESSENGER_ERROR_TCP_SERVER;
1999 }
2000
2001 return nullptr;
2002 }
2003 }
2004
2005 m->options = *options;
2006 friendreq_init(m->fr, m->fr_c);
2007 set_nospam(m->fr, random_u32());
2008 set_filter_function(m->fr, &friend_already_added, m);
2009
2010 m->lastdump = 0;
2011
2012 m_register_default_plugins(m);
2013
2014 if (error) {
2015 *error = MESSENGER_ERROR_NONE;
2016 }
2017
2018 return m;
2019 }
2020
2021 /* Run this before closing shop. */
kill_messenger(Messenger * m)2022 void kill_messenger(Messenger *m)
2023 {
2024 if (!m) {
2025 return;
2026 }
2027
2028 uint32_t i;
2029
2030 if (m->tcp_server) {
2031 kill_TCP_server(m->tcp_server);
2032 }
2033
2034 kill_friend_connections(m->fr_c);
2035 kill_onion(m->onion);
2036 kill_onion_announce(m->onion_a);
2037 kill_onion_client(m->onion_c);
2038 kill_net_crypto(m->net_crypto);
2039 kill_dht(m->dht);
2040 kill_networking(m->net);
2041
2042 for (i = 0; i < m->numfriends; ++i) {
2043 clear_receipts(m, i);
2044 }
2045
2046 logger_kill(m->log);
2047 free(m->friendlist);
2048 friendreq_kill(m->fr);
2049
2050 free(m->options.state_plugins);
2051 free(m);
2052 }
2053
2054 /* Check for and handle a timed-out friend request. If the request has
2055 * timed-out then the friend status is set back to FRIEND_ADDED.
2056 * i: friendlist index of the timed-out friend
2057 * t: time
2058 */
check_friend_request_timed_out(Messenger * m,uint32_t i,uint64_t t,void * userdata)2059 static void check_friend_request_timed_out(Messenger *m, uint32_t i, uint64_t t, void *userdata)
2060 {
2061 Friend *f = &m->friendlist[i];
2062
2063 if (f->friendrequest_lastsent + f->friendrequest_timeout < t) {
2064 set_friend_status(m, i, FRIEND_ADDED, userdata);
2065 /* Double the default timeout every time if friendrequest is assumed
2066 * to have been sent unsuccessfully.
2067 */
2068 f->friendrequest_timeout *= 2;
2069 }
2070 }
2071
m_handle_status(void * object,int i,uint8_t status,void * userdata)2072 static int m_handle_status(void *object, int i, uint8_t status, void *userdata)
2073 {
2074 Messenger *m = (Messenger *)object;
2075
2076 if (status) { /* Went online. */
2077 send_online_packet(m, i);
2078 } else { /* Went offline. */
2079 if (m->friendlist[i].status == FRIEND_ONLINE) {
2080 set_friend_status(m, i, FRIEND_CONFIRMED, userdata);
2081 }
2082 }
2083
2084 return 0;
2085 }
2086
m_handle_packet(void * object,int i,const uint8_t * temp,uint16_t len,void * userdata)2087 static int m_handle_packet(void *object, int i, const uint8_t *temp, uint16_t len, void *userdata)
2088 {
2089 if (len == 0) {
2090 return -1;
2091 }
2092
2093 Messenger *m = (Messenger *)object;
2094 uint8_t packet_id = temp[0];
2095 const uint8_t *data = temp + 1;
2096 uint32_t data_length = len - 1;
2097
2098 if (m->friendlist[i].status != FRIEND_ONLINE) {
2099 if (packet_id == PACKET_ID_ONLINE && len == 1) {
2100 set_friend_status(m, i, FRIEND_ONLINE, userdata);
2101 send_online_packet(m, i);
2102 } else {
2103 return -1;
2104 }
2105 }
2106
2107 switch (packet_id) {
2108 case PACKET_ID_OFFLINE: {
2109 if (data_length != 0) {
2110 break;
2111 }
2112
2113 set_friend_status(m, i, FRIEND_CONFIRMED, userdata);
2114 break;
2115 }
2116
2117 case PACKET_ID_NICKNAME: {
2118 if (data_length > MAX_NAME_LENGTH) {
2119 break;
2120 }
2121
2122 /* Make sure the NULL terminator is present. */
2123 VLA(uint8_t, data_terminated, data_length + 1);
2124 memcpy(data_terminated, data, data_length);
2125 data_terminated[data_length] = 0;
2126
2127 /* inform of namechange before we overwrite the old name */
2128 if (m->friend_namechange) {
2129 m->friend_namechange(m, i, data_terminated, data_length, userdata);
2130 }
2131
2132 memcpy(m->friendlist[i].name, data_terminated, data_length);
2133 m->friendlist[i].name_length = data_length;
2134
2135 break;
2136 }
2137
2138 case PACKET_ID_STATUSMESSAGE: {
2139 if (data_length > MAX_STATUSMESSAGE_LENGTH) {
2140 break;
2141 }
2142
2143 /* Make sure the NULL terminator is present. */
2144 VLA(uint8_t, data_terminated, data_length + 1);
2145 memcpy(data_terminated, data, data_length);
2146 data_terminated[data_length] = 0;
2147
2148 if (m->friend_statusmessagechange) {
2149 m->friend_statusmessagechange(m, i, data_terminated, data_length, userdata);
2150 }
2151
2152 set_friend_statusmessage(m, i, data_terminated, data_length);
2153 break;
2154 }
2155
2156 case PACKET_ID_USERSTATUS: {
2157 if (data_length != 1) {
2158 break;
2159 }
2160
2161 Userstatus status = (Userstatus)data[0];
2162
2163 if (status >= USERSTATUS_INVALID) {
2164 break;
2165 }
2166
2167 if (m->friend_userstatuschange) {
2168 m->friend_userstatuschange(m, i, status, userdata);
2169 }
2170
2171 set_friend_userstatus(m, i, status);
2172 break;
2173 }
2174
2175 case PACKET_ID_TYPING: {
2176 if (data_length != 1) {
2177 break;
2178 }
2179
2180 bool typing = !!data[0];
2181
2182 set_friend_typing(m, i, typing);
2183
2184 if (m->friend_typingchange) {
2185 m->friend_typingchange(m, i, typing, userdata);
2186 }
2187
2188 break;
2189 }
2190
2191 case PACKET_ID_MESSAGE: // fall-through
2192 case PACKET_ID_ACTION: {
2193 if (data_length == 0) {
2194 break;
2195 }
2196
2197 const uint8_t *message = data;
2198 uint16_t message_length = data_length;
2199
2200 /* Make sure the NULL terminator is present. */
2201 VLA(uint8_t, message_terminated, message_length + 1);
2202 memcpy(message_terminated, message, message_length);
2203 message_terminated[message_length] = 0;
2204 uint8_t type = packet_id - PACKET_ID_MESSAGE;
2205
2206 if (m->friend_message) {
2207 (*m->friend_message)(m, i, type, message_terminated, message_length, userdata);
2208 }
2209
2210 break;
2211 }
2212
2213 case PACKET_ID_INVITE_CONFERENCE: {
2214 if (data_length == 0) {
2215 break;
2216 }
2217
2218 if (m->conference_invite) {
2219 (*m->conference_invite)(m, i, data, data_length, userdata);
2220 }
2221
2222 break;
2223 }
2224
2225 case PACKET_ID_FILE_SENDREQUEST: {
2226 const unsigned int head_length = 1 + sizeof(uint32_t) + sizeof(uint64_t) + FILE_ID_LENGTH;
2227
2228 if (data_length < head_length) {
2229 break;
2230 }
2231
2232 uint8_t filenumber = data[0];
2233
2234 #if UINT8_MAX >= MAX_CONCURRENT_FILE_PIPES
2235
2236 if (filenumber >= MAX_CONCURRENT_FILE_PIPES) {
2237 break;
2238 }
2239
2240 #endif
2241
2242 uint64_t filesize;
2243 uint32_t file_type;
2244 uint16_t filename_length = data_length - head_length;
2245
2246 if (filename_length > MAX_FILENAME_LENGTH) {
2247 break;
2248 }
2249
2250 memcpy(&file_type, data + 1, sizeof(file_type));
2251 file_type = net_ntohl(file_type);
2252
2253 net_unpack_u64(data + 1 + sizeof(uint32_t), &filesize);
2254 struct File_Transfers *ft = &m->friendlist[i].file_receiving[filenumber];
2255
2256 if (ft->status != FILESTATUS_NONE) {
2257 break;
2258 }
2259
2260 ft->status = FILESTATUS_NOT_ACCEPTED;
2261 ft->size = filesize;
2262 ft->transferred = 0;
2263 ft->paused = FILE_PAUSE_NOT;
2264 memcpy(ft->id, data + 1 + sizeof(uint32_t) + sizeof(uint64_t), FILE_ID_LENGTH);
2265
2266 VLA(uint8_t, filename_terminated, filename_length + 1);
2267 uint8_t *filename = nullptr;
2268
2269 if (filename_length) {
2270 /* Force NULL terminate file name. */
2271 memcpy(filename_terminated, data + head_length, filename_length);
2272 filename_terminated[filename_length] = 0;
2273 filename = filename_terminated;
2274 }
2275
2276 uint32_t real_filenumber = filenumber;
2277 real_filenumber += 1;
2278 real_filenumber <<= 16;
2279
2280 if (m->file_sendrequest) {
2281 (*m->file_sendrequest)(m, i, real_filenumber, file_type, filesize, filename, filename_length,
2282 userdata);
2283 }
2284
2285 break;
2286 }
2287
2288 case PACKET_ID_FILE_CONTROL: {
2289 if (data_length < 3) {
2290 break;
2291 }
2292
2293 uint8_t send_receive = data[0];
2294 uint8_t filenumber = data[1];
2295 uint8_t control_type = data[2];
2296
2297 #if UINT8_MAX >= MAX_CONCURRENT_FILE_PIPES
2298
2299 if (filenumber >= MAX_CONCURRENT_FILE_PIPES) {
2300 break;
2301 }
2302
2303 #endif
2304
2305 if (handle_filecontrol(m, i, send_receive, filenumber, control_type, data + 3, data_length - 3, userdata) == -1) {
2306 // TODO(iphydf): Do something different here? Right now, this
2307 // check is pointless.
2308 break;
2309 }
2310
2311 break;
2312 }
2313
2314 case PACKET_ID_FILE_DATA: {
2315 if (data_length < 1) {
2316 break;
2317 }
2318
2319 uint8_t filenumber = data[0];
2320
2321 #if UINT8_MAX >= MAX_CONCURRENT_FILE_PIPES
2322
2323 if (filenumber >= MAX_CONCURRENT_FILE_PIPES) {
2324 break;
2325 }
2326
2327 #endif
2328
2329 struct File_Transfers *ft = &m->friendlist[i].file_receiving[filenumber];
2330
2331 if (ft->status != FILESTATUS_TRANSFERRING) {
2332 break;
2333 }
2334
2335 uint64_t position = ft->transferred;
2336 uint32_t real_filenumber = filenumber;
2337 real_filenumber += 1;
2338 real_filenumber <<= 16;
2339 uint16_t file_data_length = (data_length - 1);
2340 const uint8_t *file_data;
2341
2342 if (file_data_length == 0) {
2343 file_data = nullptr;
2344 } else {
2345 file_data = data + 1;
2346 }
2347
2348 /* Prevent more data than the filesize from being passed to clients. */
2349 if ((ft->transferred + file_data_length) > ft->size) {
2350 file_data_length = ft->size - ft->transferred;
2351 }
2352
2353 if (m->file_filedata) {
2354 (*m->file_filedata)(m, i, real_filenumber, position, file_data, file_data_length, userdata);
2355 }
2356
2357 ft->transferred += file_data_length;
2358
2359 if (file_data_length && (ft->transferred >= ft->size || file_data_length != MAX_FILE_DATA_SIZE)) {
2360 file_data_length = 0;
2361 file_data = nullptr;
2362 position = ft->transferred;
2363
2364 /* Full file received. */
2365 if (m->file_filedata) {
2366 (*m->file_filedata)(m, i, real_filenumber, position, file_data, file_data_length, userdata);
2367 }
2368 }
2369
2370 /* Data is zero, filetransfer is over. */
2371 if (file_data_length == 0) {
2372 ft->status = FILESTATUS_NONE;
2373 }
2374
2375 break;
2376 }
2377
2378 case PACKET_ID_MSI: {
2379 if (data_length == 0) {
2380 break;
2381 }
2382
2383 if (m->msi_packet) {
2384 (*m->msi_packet)(m, i, data, data_length, m->msi_packet_userdata);
2385 }
2386
2387 break;
2388 }
2389
2390 default: {
2391 handle_custom_lossless_packet(object, i, temp, len, userdata);
2392 break;
2393 }
2394 }
2395
2396 return 0;
2397 }
2398
do_friends(Messenger * m,void * userdata)2399 static void do_friends(Messenger *m, void *userdata)
2400 {
2401 uint32_t i;
2402 uint64_t temp_time = mono_time_get(m->mono_time);
2403
2404 for (i = 0; i < m->numfriends; ++i) {
2405 if (m->friendlist[i].status == FRIEND_ADDED) {
2406 int fr = send_friend_request_packet(m->fr_c, m->friendlist[i].friendcon_id, m->friendlist[i].friendrequest_nospam,
2407 m->friendlist[i].info,
2408 m->friendlist[i].info_size);
2409
2410 if (fr >= 0) {
2411 set_friend_status(m, i, FRIEND_REQUESTED, userdata);
2412 m->friendlist[i].friendrequest_lastsent = temp_time;
2413 }
2414 }
2415
2416 if (m->friendlist[i].status == FRIEND_REQUESTED
2417 || m->friendlist[i].status == FRIEND_CONFIRMED) { /* friend is not online. */
2418 if (m->friendlist[i].status == FRIEND_REQUESTED) {
2419 /* If we didn't connect to friend after successfully sending him a friend request the request is deemed
2420 * unsuccessful so we set the status back to FRIEND_ADDED and try again.
2421 */
2422 check_friend_request_timed_out(m, i, temp_time, userdata);
2423 }
2424 }
2425
2426 if (m->friendlist[i].status == FRIEND_ONLINE) { /* friend is online. */
2427 if (m->friendlist[i].name_sent == 0) {
2428 if (m_sendname(m, i, m->name, m->name_length)) {
2429 m->friendlist[i].name_sent = 1;
2430 }
2431 }
2432
2433 if (m->friendlist[i].statusmessage_sent == 0) {
2434 if (send_statusmessage(m, i, m->statusmessage, m->statusmessage_length)) {
2435 m->friendlist[i].statusmessage_sent = 1;
2436 }
2437 }
2438
2439 if (m->friendlist[i].userstatus_sent == 0) {
2440 if (send_userstatus(m, i, m->userstatus)) {
2441 m->friendlist[i].userstatus_sent = 1;
2442 }
2443 }
2444
2445 if (m->friendlist[i].user_istyping_sent == 0) {
2446 if (send_user_istyping(m, i, m->friendlist[i].user_istyping)) {
2447 m->friendlist[i].user_istyping_sent = 1;
2448 }
2449 }
2450
2451 check_friend_tcp_udp(m, i, userdata);
2452 do_receipts(m, i, userdata);
2453 do_reqchunk_filecb(m, i, userdata);
2454
2455 m->friendlist[i].last_seen_time = (uint64_t) time(nullptr);
2456 }
2457 }
2458 }
2459
connection_status_callback(Messenger * m,void * userdata)2460 static void connection_status_callback(Messenger *m, void *userdata)
2461 {
2462 unsigned int conn_status = onion_connection_status(m->onion_c);
2463
2464 if (conn_status != m->last_connection_status) {
2465 if (m->core_connection_change) {
2466 (*m->core_connection_change)(m, conn_status, userdata);
2467 }
2468
2469 m->last_connection_status = conn_status;
2470 }
2471 }
2472
2473
2474 #define DUMPING_CLIENTS_FRIENDS_EVERY_N_SECONDS 60UL
2475
2476 #define IDSTRING_LEN (CRYPTO_PUBLIC_KEY_SIZE * 2 + 1)
2477 /* id_str should be of length at least IDSTRING_LEN */
id_to_string(const uint8_t * pk,char * id_str,size_t length)2478 static char *id_to_string(const uint8_t *pk, char *id_str, size_t length)
2479 {
2480 if (length < IDSTRING_LEN) {
2481 snprintf(id_str, length, "Bad buf length");
2482 return id_str;
2483 }
2484
2485 for (uint32_t i = 0; i < CRYPTO_PUBLIC_KEY_SIZE; ++i) {
2486 sprintf(&id_str[i * 2], "%02X", pk[i]);
2487 }
2488
2489 id_str[CRYPTO_PUBLIC_KEY_SIZE * 2] = 0;
2490 return id_str;
2491 }
2492
2493 /* Minimum messenger run interval in ms
2494 * TODO(mannol): A/V */
2495 #define MIN_RUN_INTERVAL 50
2496
2497 /* Return the time in milliseconds before do_messenger() should be called again
2498 * for optimal performance.
2499 *
2500 * returns time (in ms) before the next do_messenger() needs to be run on success.
2501 */
messenger_run_interval(const Messenger * m)2502 uint32_t messenger_run_interval(const Messenger *m)
2503 {
2504 uint32_t crypto_interval = crypto_run_interval(m->net_crypto);
2505
2506 if (crypto_interval > MIN_RUN_INTERVAL) {
2507 return MIN_RUN_INTERVAL;
2508 }
2509
2510 return crypto_interval;
2511 }
2512
2513 /* The main loop that needs to be run at least 20 times per second. */
do_messenger(Messenger * m,void * userdata)2514 void do_messenger(Messenger *m, void *userdata)
2515 {
2516 // Add the TCP relays, but only if this is the first time calling do_messenger
2517 if (!m->has_added_relays) {
2518 m->has_added_relays = true;
2519
2520 for (uint16_t i = 0; i < m->num_loaded_relays; ++i) {
2521 add_tcp_relay(m->net_crypto, m->loaded_relays[i].ip_port, m->loaded_relays[i].public_key);
2522 }
2523
2524 m->num_loaded_relays = 0;
2525
2526 if (m->tcp_server) {
2527 /* Add self tcp server. */
2528 IP_Port local_ip_port;
2529 local_ip_port.port = m->options.tcp_server_port;
2530 local_ip_port.ip.family = net_family_ipv4;
2531 local_ip_port.ip.ip.v4 = get_ip4_loopback();
2532 add_tcp_relay(m->net_crypto, local_ip_port,
2533 tcp_server_public_key(m->tcp_server));
2534 }
2535 }
2536
2537 if (!m->options.udp_disabled) {
2538 networking_poll(m->net, userdata);
2539 do_dht(m->dht);
2540 }
2541
2542 if (m->tcp_server) {
2543 do_TCP_server(m->tcp_server, m->mono_time);
2544 }
2545
2546 do_net_crypto(m->net_crypto, userdata);
2547 do_onion_client(m->onion_c);
2548 do_friend_connections(m->fr_c, userdata);
2549 do_friends(m, userdata);
2550 connection_status_callback(m, userdata);
2551
2552 if (mono_time_get(m->mono_time) > m->lastdump + DUMPING_CLIENTS_FRIENDS_EVERY_N_SECONDS) {
2553 m->lastdump = mono_time_get(m->mono_time);
2554 uint32_t last_pinged;
2555
2556 for (uint32_t client = 0; client < LCLIENT_LIST; ++client) {
2557 const Client_data *cptr = dht_get_close_client(m->dht, client);
2558 const IPPTsPng *const assocs[] = { &cptr->assoc4, &cptr->assoc6, nullptr };
2559
2560 for (const IPPTsPng * const *it = assocs; *it; ++it) {
2561 const IPPTsPng *const assoc = *it;
2562
2563 if (ip_isset(&assoc->ip_port.ip)) {
2564 last_pinged = m->lastdump - assoc->last_pinged;
2565
2566 if (last_pinged > 999) {
2567 last_pinged = 999;
2568 }
2569
2570 char ip_str[IP_NTOA_LEN];
2571 char id_str[IDSTRING_LEN];
2572 LOGGER_TRACE(m->log, "C[%2u] %s:%u [%3u] %s",
2573 client, ip_ntoa(&assoc->ip_port.ip, ip_str, sizeof(ip_str)),
2574 net_ntohs(assoc->ip_port.port), last_pinged,
2575 id_to_string(cptr->public_key, id_str, sizeof(id_str)));
2576 }
2577 }
2578 }
2579
2580
2581 /* dht contains additional "friends" (requests) */
2582 uint32_t num_dhtfriends = dht_get_num_friends(m->dht);
2583 VLA(int32_t, m2dht, num_dhtfriends);
2584 VLA(int32_t, dht2m, num_dhtfriends);
2585
2586 for (uint32_t friend_idx = 0; friend_idx < num_dhtfriends; ++friend_idx) {
2587 m2dht[friend_idx] = -1;
2588 dht2m[friend_idx] = -1;
2589
2590 if (friend_idx >= m->numfriends) {
2591 continue;
2592 }
2593
2594 for (uint32_t dhtfriend = 0; dhtfriend < dht_get_num_friends(m->dht); ++dhtfriend) {
2595 if (id_equal(m->friendlist[friend_idx].real_pk, dht_get_friend_public_key(m->dht, dhtfriend))) {
2596 m2dht[friend_idx] = dhtfriend;
2597 break;
2598 }
2599 }
2600 }
2601
2602 for (uint32_t friend_idx = 0; friend_idx < num_dhtfriends; ++friend_idx) {
2603 if (m2dht[friend_idx] >= 0) {
2604 dht2m[m2dht[friend_idx]] = friend_idx;
2605 }
2606 }
2607
2608 if (m->numfriends != dht_get_num_friends(m->dht)) {
2609 LOGGER_TRACE(m->log, "Friend num in DHT %u != friend num in msger %u", dht_get_num_friends(m->dht), m->numfriends);
2610 }
2611
2612 Friend *msgfptr;
2613 DHT_Friend *dhtfptr;
2614
2615 for (uint32_t friend_idx = 0; friend_idx < num_dhtfriends; ++friend_idx) {
2616 if (dht2m[friend_idx] >= 0) {
2617 msgfptr = &m->friendlist[dht2m[friend_idx]];
2618 } else {
2619 msgfptr = nullptr;
2620 }
2621
2622 dhtfptr = dht_get_friend(m->dht, friend_idx);
2623
2624 if (msgfptr) {
2625 char id_str[IDSTRING_LEN];
2626 LOGGER_TRACE(m->log, "F[%2u:%2u] <%s> %s",
2627 dht2m[friend_idx], friend_idx, msgfptr->name,
2628 id_to_string(msgfptr->real_pk, id_str, sizeof(id_str)));
2629 } else {
2630 char id_str[IDSTRING_LEN];
2631 LOGGER_TRACE(m->log, "F[--:%2u] %s", friend_idx,
2632 id_to_string(dht_friend_public_key(dhtfptr), id_str, sizeof(id_str)));
2633 }
2634
2635 for (uint32_t client = 0; client < MAX_FRIEND_CLIENTS; ++client) {
2636 const Client_data *cptr = dht_friend_client(dhtfptr, client);
2637 const IPPTsPng *const assocs[] = {&cptr->assoc4, &cptr->assoc6};
2638
2639 for (size_t a = 0; a < sizeof(assocs) / sizeof(assocs[0]); ++a) {
2640 const IPPTsPng *const assoc = assocs[a];
2641
2642 if (ip_isset(&assoc->ip_port.ip)) {
2643 last_pinged = m->lastdump - assoc->last_pinged;
2644
2645 if (last_pinged > 999) {
2646 last_pinged = 999;
2647 }
2648
2649 char ip_str[IP_NTOA_LEN];
2650 char id_str[IDSTRING_LEN];
2651 LOGGER_TRACE(m->log, "F[%2u] => C[%2u] %s:%u [%3u] %s",
2652 friend_idx, client, ip_ntoa(&assoc->ip_port.ip, ip_str, sizeof(ip_str)),
2653 net_ntohs(assoc->ip_port.port), last_pinged,
2654 id_to_string(cptr->public_key, id_str, sizeof(id_str)));
2655 }
2656 }
2657 }
2658 }
2659 }
2660 }
2661
2662 /* new messenger format for load/save, more robust and forward compatible */
2663
2664 #define SAVED_FRIEND_REQUEST_SIZE 1024
2665 #define NUM_SAVED_PATH_NODES 8
2666
2667 struct Saved_Friend {
2668 uint8_t status;
2669 uint8_t real_pk[CRYPTO_PUBLIC_KEY_SIZE];
2670 uint8_t info[SAVED_FRIEND_REQUEST_SIZE]; // the data that is sent during the friend requests we do.
2671 uint16_t info_size; // Length of the info.
2672 uint8_t name[MAX_NAME_LENGTH];
2673 uint16_t name_length;
2674 uint8_t statusmessage[MAX_STATUSMESSAGE_LENGTH];
2675 uint16_t statusmessage_length;
2676 uint8_t userstatus;
2677 uint32_t friendrequest_nospam;
2678 uint8_t last_seen_time[sizeof(uint64_t)];
2679 };
2680
friend_size(void)2681 static uint32_t friend_size(void)
2682 {
2683 uint32_t data = 0;
2684 const struct Saved_Friend *const temp = nullptr;
2685
2686 #define VALUE_MEMBER(name) do { data += sizeof(temp->name); } while (0)
2687 #define ARRAY_MEMBER(name) do { data += sizeof(temp->name); } while (0)
2688
2689 // Exactly the same in friend_load, friend_save, and friend_size
2690 VALUE_MEMBER(status);
2691 ARRAY_MEMBER(real_pk);
2692 ARRAY_MEMBER(info);
2693 ++data; // padding
2694 VALUE_MEMBER(info_size);
2695 ARRAY_MEMBER(name);
2696 VALUE_MEMBER(name_length);
2697 ARRAY_MEMBER(statusmessage);
2698 ++data; // padding
2699 VALUE_MEMBER(statusmessage_length);
2700 VALUE_MEMBER(userstatus);
2701 data += 3; // padding
2702 VALUE_MEMBER(friendrequest_nospam);
2703 ARRAY_MEMBER(last_seen_time);
2704
2705 #undef VALUE_MEMBER
2706 #undef ARRAY_MEMBER
2707
2708 return data;
2709 }
2710
friend_save(const struct Saved_Friend * temp,uint8_t * data)2711 static uint8_t *friend_save(const struct Saved_Friend *temp, uint8_t *data)
2712 {
2713 #define VALUE_MEMBER(name) do { \
2714 memcpy(data, &temp->name, sizeof(temp->name)); \
2715 data += sizeof(temp->name); \
2716 } while (0)
2717
2718 #define ARRAY_MEMBER(name) do { \
2719 memcpy(data, temp->name, sizeof(temp->name)); \
2720 data += sizeof(temp->name); \
2721 } while (0)
2722
2723 // Exactly the same in friend_load, friend_save, and friend_size
2724 VALUE_MEMBER(status);
2725 ARRAY_MEMBER(real_pk);
2726 ARRAY_MEMBER(info);
2727 ++data; // padding
2728 VALUE_MEMBER(info_size);
2729 ARRAY_MEMBER(name);
2730 VALUE_MEMBER(name_length);
2731 ARRAY_MEMBER(statusmessage);
2732 ++data; // padding
2733 VALUE_MEMBER(statusmessage_length);
2734 VALUE_MEMBER(userstatus);
2735 data += 3; // padding
2736 VALUE_MEMBER(friendrequest_nospam);
2737 ARRAY_MEMBER(last_seen_time);
2738
2739 #undef VALUE_MEMBER
2740 #undef ARRAY_MEMBER
2741
2742 return data;
2743 }
2744
2745
friend_load(struct Saved_Friend * temp,const uint8_t * data)2746 static const uint8_t *friend_load(struct Saved_Friend *temp, const uint8_t *data)
2747 {
2748 #define VALUE_MEMBER(name) do { \
2749 memcpy(&temp->name, data, sizeof(temp->name)); \
2750 data += sizeof(temp->name); \
2751 } while (0)
2752
2753 #define ARRAY_MEMBER(name) do { \
2754 memcpy(temp->name, data, sizeof(temp->name)); \
2755 data += sizeof(temp->name); \
2756 } while (0)
2757
2758 // Exactly the same in friend_load, friend_save, and friend_size
2759 VALUE_MEMBER(status);
2760 ARRAY_MEMBER(real_pk);
2761 ARRAY_MEMBER(info);
2762 ++data; // padding
2763 VALUE_MEMBER(info_size);
2764 ARRAY_MEMBER(name);
2765 VALUE_MEMBER(name_length);
2766 ARRAY_MEMBER(statusmessage);
2767 ++data; // padding
2768 VALUE_MEMBER(statusmessage_length);
2769 VALUE_MEMBER(userstatus);
2770 data += 3; // padding
2771 VALUE_MEMBER(friendrequest_nospam);
2772 ARRAY_MEMBER(last_seen_time);
2773
2774 #undef VALUE_MEMBER
2775 #undef ARRAY_MEMBER
2776
2777 return data;
2778 }
2779
2780
m_state_plugins_size(const Messenger * m)2781 static uint32_t m_state_plugins_size(const Messenger *m)
2782 {
2783 const uint32_t size32 = sizeof(uint32_t);
2784 const uint32_t sizesubhead = size32 * 2;
2785
2786 uint32_t size = 0;
2787
2788 for (const Messenger_State_Plugin *plugin = m->options.state_plugins;
2789 plugin != m->options.state_plugins + m->options.state_plugins_length;
2790 ++plugin) {
2791 size += sizesubhead + plugin->size(m);
2792 }
2793
2794 return size;
2795 }
2796
2797 /*
2798 * Registers a state plugin with the messenger
2799 * returns true on success
2800 * returns false on failure
2801 */
m_register_state_plugin(Messenger * m,State_Type type,m_state_size_cb size_callback,m_state_load_cb load_callback,m_state_save_cb save_callback)2802 bool m_register_state_plugin(Messenger *m, State_Type type, m_state_size_cb size_callback,
2803 m_state_load_cb load_callback,
2804 m_state_save_cb save_callback)
2805 {
2806 Messenger_State_Plugin *temp = (Messenger_State_Plugin *)realloc(m->options.state_plugins,
2807 sizeof(Messenger_State_Plugin) * (m->options.state_plugins_length + 1));
2808
2809 if (!temp) {
2810 return false;
2811 }
2812
2813 m->options.state_plugins = temp;
2814 ++m->options.state_plugins_length;
2815
2816 const uint8_t index = m->options.state_plugins_length - 1;
2817 m->options.state_plugins[index].type = type;
2818 m->options.state_plugins[index].size = size_callback;
2819 m->options.state_plugins[index].load = load_callback;
2820 m->options.state_plugins[index].save = save_callback;
2821
2822 return true;
2823 }
2824
m_plugin_size(const Messenger * m,State_Type type)2825 static uint32_t m_plugin_size(const Messenger *m, State_Type type)
2826 {
2827 for (uint8_t i = 0; i < m->options.state_plugins_length; ++i) {
2828 const Messenger_State_Plugin plugin = m->options.state_plugins[i];
2829
2830 if (plugin.type == type) {
2831 return plugin.size(m);
2832 }
2833 }
2834
2835 LOGGER_ERROR(m->log, "Unknown type encountered: %u", type);
2836
2837 return UINT32_MAX;
2838 }
2839
2840 /* return size of the messenger data (for saving) */
messenger_size(const Messenger * m)2841 uint32_t messenger_size(const Messenger *m)
2842 {
2843 return m_state_plugins_size(m);
2844 }
2845
2846 /* Save the messenger in data of size messenger_size(). */
messenger_save(const Messenger * m,uint8_t * data)2847 uint8_t *messenger_save(const Messenger *m, uint8_t *data)
2848 {
2849 for (uint8_t i = 0; i < m->options.state_plugins_length; ++i) {
2850 const Messenger_State_Plugin plugin = m->options.state_plugins[i];
2851 data = plugin.save(m, data);
2852 }
2853
2854 return data;
2855 }
2856
2857 // nospam state plugin
nospam_keys_size(const Messenger * m)2858 static uint32_t nospam_keys_size(const Messenger *m)
2859 {
2860 return sizeof(uint32_t) + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_SECRET_KEY_SIZE;
2861 }
2862
load_nospam_keys(Messenger * m,const uint8_t * data,uint32_t length)2863 static State_Load_Status load_nospam_keys(Messenger *m, const uint8_t *data, uint32_t length)
2864 {
2865 if (length != m_plugin_size(m, STATE_TYPE_NOSPAMKEYS)) {
2866 return STATE_LOAD_STATUS_ERROR;
2867 }
2868
2869 uint32_t nospam;
2870 lendian_bytes_to_host32(&nospam, data);
2871 set_nospam(m->fr, nospam);
2872 load_secret_key(m->net_crypto, data + sizeof(uint32_t) + CRYPTO_PUBLIC_KEY_SIZE);
2873
2874 if (public_key_cmp(data + sizeof(uint32_t), nc_get_self_public_key(m->net_crypto)) != 0) {
2875 return STATE_LOAD_STATUS_ERROR;
2876 }
2877
2878 return STATE_LOAD_STATUS_CONTINUE;
2879 }
2880
save_nospam_keys(const Messenger * m,uint8_t * data)2881 static uint8_t *save_nospam_keys(const Messenger *m, uint8_t *data)
2882 {
2883 const uint32_t len = m_plugin_size(m, STATE_TYPE_NOSPAMKEYS);
2884 assert(sizeof(get_nospam(m->fr)) == sizeof(uint32_t));
2885 data = state_write_section_header(data, STATE_COOKIE_TYPE, len, STATE_TYPE_NOSPAMKEYS);
2886 uint32_t nospam = get_nospam(m->fr);
2887 host_to_lendian_bytes32(data, nospam);
2888 save_keys(m->net_crypto, data + sizeof(uint32_t));
2889 data += len;
2890 return data;
2891 }
2892
2893 // DHT state plugin
m_dht_size(const Messenger * m)2894 static uint32_t m_dht_size(const Messenger *m)
2895 {
2896 return dht_size(m->dht);
2897 }
2898
save_dht(const Messenger * m,uint8_t * data)2899 static uint8_t *save_dht(const Messenger *m, uint8_t *data)
2900 {
2901 const uint32_t len = m_plugin_size(m, STATE_TYPE_DHT);
2902 data = state_write_section_header(data, STATE_COOKIE_TYPE, len, STATE_TYPE_DHT);
2903 dht_save(m->dht, data);
2904 data += len;
2905 return data;
2906 }
2907
m_dht_load(Messenger * m,const uint8_t * data,uint32_t length)2908 static State_Load_Status m_dht_load(Messenger *m, const uint8_t *data, uint32_t length)
2909 {
2910 dht_load(m->dht, data, length); // TODO(endoffile78): Should we throw an error if dht_load fails?
2911 return STATE_LOAD_STATUS_CONTINUE;
2912 }
2913
2914 // friendlist state plugin
saved_friendslist_size(const Messenger * m)2915 static uint32_t saved_friendslist_size(const Messenger *m)
2916 {
2917 return count_friendlist(m) * friend_size();
2918 }
2919
friends_list_save(const Messenger * m,uint8_t * data)2920 static uint8_t *friends_list_save(const Messenger *m, uint8_t *data)
2921 {
2922 const uint32_t len = m_plugin_size(m, STATE_TYPE_FRIENDS);
2923 data = state_write_section_header(data, STATE_COOKIE_TYPE, len, STATE_TYPE_FRIENDS);
2924
2925 uint32_t num = 0;
2926 uint8_t *cur_data = data;
2927
2928 for (uint32_t i = 0; i < m->numfriends; ++i) {
2929 if (m->friendlist[i].status > 0) {
2930 struct Saved_Friend temp = { 0 };
2931 temp.status = m->friendlist[i].status;
2932 memcpy(temp.real_pk, m->friendlist[i].real_pk, CRYPTO_PUBLIC_KEY_SIZE);
2933
2934 if (temp.status < 3) {
2935 // TODO(iphydf): Use uint16_t and min_u16 here.
2936 const size_t friendrequest_length =
2937 min_u32(m->friendlist[i].info_size,
2938 min_u32(SAVED_FRIEND_REQUEST_SIZE, MAX_FRIEND_REQUEST_DATA_SIZE));
2939 memcpy(temp.info, m->friendlist[i].info, friendrequest_length);
2940
2941 temp.info_size = net_htons(m->friendlist[i].info_size);
2942 temp.friendrequest_nospam = m->friendlist[i].friendrequest_nospam;
2943 } else {
2944 temp.status = 3;
2945 memcpy(temp.name, m->friendlist[i].name, m->friendlist[i].name_length);
2946 temp.name_length = net_htons(m->friendlist[i].name_length);
2947 memcpy(temp.statusmessage, m->friendlist[i].statusmessage, m->friendlist[i].statusmessage_length);
2948 temp.statusmessage_length = net_htons(m->friendlist[i].statusmessage_length);
2949 temp.userstatus = m->friendlist[i].userstatus;
2950
2951 net_pack_u64(temp.last_seen_time, m->friendlist[i].last_seen_time);
2952 }
2953
2954 uint8_t *next_data = friend_save(&temp, cur_data);
2955 assert(next_data - cur_data == friend_size());
2956 #ifdef __LP64__
2957 assert(memcmp(cur_data, &temp, friend_size()) == 0);
2958 #endif
2959 cur_data = next_data;
2960 ++num;
2961 }
2962 }
2963
2964 assert(cur_data - data == num * friend_size());
2965 data += len;
2966
2967 return data;
2968 }
2969
friends_list_load(Messenger * m,const uint8_t * data,uint32_t length)2970 static State_Load_Status friends_list_load(Messenger *m, const uint8_t *data, uint32_t length)
2971 {
2972 if (length % friend_size() != 0) {
2973 return STATE_LOAD_STATUS_ERROR; // TODO(endoffile78): error or continue?
2974 }
2975
2976 uint32_t num = length / friend_size();
2977 uint32_t i;
2978 const uint8_t *cur_data = data;
2979
2980 for (i = 0; i < num; ++i) {
2981 struct Saved_Friend temp = { 0 };
2982 const uint8_t *next_data = friend_load(&temp, cur_data);
2983 assert(next_data - cur_data == friend_size());
2984 #ifdef __LP64__
2985 assert(memcmp(&temp, cur_data, friend_size()) == 0);
2986 #endif
2987 cur_data = next_data;
2988
2989 if (temp.status >= 3) {
2990 int fnum = m_addfriend_norequest(m, temp.real_pk);
2991
2992 if (fnum < 0) {
2993 continue;
2994 }
2995
2996 setfriendname(m, fnum, temp.name, net_ntohs(temp.name_length));
2997 set_friend_statusmessage(m, fnum, temp.statusmessage, net_ntohs(temp.statusmessage_length));
2998 set_friend_userstatus(m, fnum, temp.userstatus);
2999 net_unpack_u64(temp.last_seen_time, &m->friendlist[fnum].last_seen_time);
3000 } else if (temp.status != 0) {
3001 /* TODO(irungentoo): This is not a good way to do this. */
3002 uint8_t address[FRIEND_ADDRESS_SIZE];
3003 id_copy(address, temp.real_pk);
3004 memcpy(address + CRYPTO_PUBLIC_KEY_SIZE, &temp.friendrequest_nospam, sizeof(uint32_t));
3005 uint16_t checksum = address_checksum(address, FRIEND_ADDRESS_SIZE - sizeof(checksum));
3006 memcpy(address + CRYPTO_PUBLIC_KEY_SIZE + sizeof(uint32_t), &checksum, sizeof(checksum));
3007 m_addfriend(m, address, temp.info, net_ntohs(temp.info_size));
3008 }
3009 }
3010
3011 return STATE_LOAD_STATUS_CONTINUE;
3012 }
3013
3014 // name state plugin
name_size(const Messenger * m)3015 static uint32_t name_size(const Messenger *m)
3016 {
3017 return m->name_length;
3018 }
3019
save_name(const Messenger * m,uint8_t * data)3020 static uint8_t *save_name(const Messenger *m, uint8_t *data)
3021 {
3022 const uint32_t len = m_plugin_size(m, STATE_TYPE_NAME);
3023 data = state_write_section_header(data, STATE_COOKIE_TYPE, len, STATE_TYPE_NAME);
3024 memcpy(data, m->name, len);
3025 data += len;
3026 return data;
3027 }
3028
load_name(Messenger * m,const uint8_t * data,uint32_t length)3029 static State_Load_Status load_name(Messenger *m, const uint8_t *data, uint32_t length)
3030 {
3031 if (length > 0 && length <= MAX_NAME_LENGTH) {
3032 setname(m, data, length);
3033 }
3034
3035 return STATE_LOAD_STATUS_CONTINUE;
3036 }
3037
3038 // status message state plugin
status_message_size(const Messenger * m)3039 static uint32_t status_message_size(const Messenger *m)
3040 {
3041 return m->statusmessage_length;
3042 }
3043
save_status_message(const Messenger * m,uint8_t * data)3044 static uint8_t *save_status_message(const Messenger *m, uint8_t *data)
3045 {
3046 const uint32_t len = m_plugin_size(m, STATE_TYPE_STATUSMESSAGE);
3047 data = state_write_section_header(data, STATE_COOKIE_TYPE, len, STATE_TYPE_STATUSMESSAGE);
3048 memcpy(data, m->statusmessage, len);
3049 data += len;
3050 return data;
3051 }
3052
load_status_message(Messenger * m,const uint8_t * data,uint32_t length)3053 static State_Load_Status load_status_message(Messenger *m, const uint8_t *data, uint32_t length)
3054 {
3055 if (length > 0 && length <= MAX_STATUSMESSAGE_LENGTH) {
3056 m_set_statusmessage(m, data, length);
3057 }
3058
3059 return STATE_LOAD_STATUS_CONTINUE;
3060 }
3061
3062 // status state plugin
status_size(const Messenger * m)3063 static uint32_t status_size(const Messenger *m)
3064 {
3065 return 1;
3066 }
3067
save_status(const Messenger * m,uint8_t * data)3068 static uint8_t *save_status(const Messenger *m, uint8_t *data)
3069 {
3070 const uint32_t len = m_plugin_size(m, STATE_TYPE_STATUS);
3071 data = state_write_section_header(data, STATE_COOKIE_TYPE, len, STATE_TYPE_STATUS);
3072 *data = m->userstatus;
3073 data += len;
3074 return data;
3075 }
3076
load_status(Messenger * m,const uint8_t * data,uint32_t length)3077 static State_Load_Status load_status(Messenger *m, const uint8_t *data, uint32_t length)
3078 {
3079 if (length == 1) {
3080 m_set_userstatus(m, *data);
3081 }
3082
3083 return STATE_LOAD_STATUS_CONTINUE;
3084 }
3085
3086 // TCP Relay state plugin
tcp_relay_size(const Messenger * m)3087 static uint32_t tcp_relay_size(const Messenger *m)
3088 {
3089 return NUM_SAVED_TCP_RELAYS * packed_node_size(net_family_tcp_ipv6);
3090 }
3091
save_tcp_relays(const Messenger * m,uint8_t * data)3092 static uint8_t *save_tcp_relays(const Messenger *m, uint8_t *data)
3093 {
3094 Node_format relays[NUM_SAVED_TCP_RELAYS];
3095 uint8_t *temp_data = data;
3096 data = state_write_section_header(temp_data, STATE_COOKIE_TYPE, 0, STATE_TYPE_TCP_RELAY);
3097
3098 if (m->num_loaded_relays > 0) {
3099 memcpy(relays, m->loaded_relays, sizeof(Node_format) * m->num_loaded_relays);
3100 }
3101
3102 uint32_t num = m->num_loaded_relays;
3103 num += copy_connected_tcp_relays(m->net_crypto, relays + num, NUM_SAVED_TCP_RELAYS - num);
3104
3105 int l = pack_nodes(data, NUM_SAVED_TCP_RELAYS * packed_node_size(net_family_tcp_ipv6), relays, num);
3106
3107 if (l > 0) {
3108 const uint32_t len = l;
3109 data = state_write_section_header(temp_data, STATE_COOKIE_TYPE, len, STATE_TYPE_TCP_RELAY);
3110 data += len;
3111 }
3112
3113 return data;
3114 }
3115
load_tcp_relays(Messenger * m,const uint8_t * data,uint32_t length)3116 static State_Load_Status load_tcp_relays(Messenger *m, const uint8_t *data, uint32_t length)
3117 {
3118 if (length != 0) {
3119 const int num = unpack_nodes(m->loaded_relays, NUM_SAVED_TCP_RELAYS, nullptr, data, length, 1);
3120
3121 if (num == -1) {
3122 m->num_loaded_relays = 0;
3123 return STATE_LOAD_STATUS_CONTINUE;
3124 }
3125
3126 m->num_loaded_relays = num;
3127 m->has_added_relays = false;
3128 }
3129
3130 return STATE_LOAD_STATUS_CONTINUE;
3131 }
3132
3133 // path node state plugin
path_node_size(const Messenger * m)3134 static uint32_t path_node_size(const Messenger *m)
3135 {
3136 return NUM_SAVED_PATH_NODES * packed_node_size(net_family_tcp_ipv6);
3137 }
3138
save_path_nodes(const Messenger * m,uint8_t * data)3139 static uint8_t *save_path_nodes(const Messenger *m, uint8_t *data)
3140 {
3141 Node_format nodes[NUM_SAVED_PATH_NODES];
3142 uint8_t *temp_data = data;
3143 data = state_write_section_header(data, STATE_COOKIE_TYPE, 0, STATE_TYPE_PATH_NODE);
3144 memset(nodes, 0, sizeof(nodes));
3145 const unsigned int num = onion_backup_nodes(m->onion_c, nodes, NUM_SAVED_PATH_NODES);
3146 const int l = pack_nodes(data, NUM_SAVED_PATH_NODES * packed_node_size(net_family_tcp_ipv6), nodes, num);
3147
3148 if (l > 0) {
3149 const uint32_t len = l;
3150 data = state_write_section_header(temp_data, STATE_COOKIE_TYPE, len, STATE_TYPE_PATH_NODE);
3151 data += len;
3152 }
3153
3154 return data;
3155 }
3156
load_path_nodes(Messenger * m,const uint8_t * data,uint32_t length)3157 static State_Load_Status load_path_nodes(Messenger *m, const uint8_t *data, uint32_t length)
3158 {
3159 Node_format nodes[NUM_SAVED_PATH_NODES];
3160
3161 if (length != 0) {
3162 const int num = unpack_nodes(nodes, NUM_SAVED_PATH_NODES, nullptr, data, length, 0);
3163
3164 if (num == -1) {
3165 return STATE_LOAD_STATUS_CONTINUE;
3166 }
3167
3168 for (int i = 0; i < num; ++i) {
3169 onion_add_bs_path_node(m->onion_c, nodes[i].ip_port, nodes[i].public_key);
3170 }
3171 }
3172
3173 return STATE_LOAD_STATUS_CONTINUE;
3174 }
3175
m_register_default_plugins(Messenger * m)3176 static void m_register_default_plugins(Messenger *m)
3177 {
3178 m_register_state_plugin(m, STATE_TYPE_NOSPAMKEYS, nospam_keys_size, load_nospam_keys, save_nospam_keys);
3179 m_register_state_plugin(m, STATE_TYPE_DHT, m_dht_size, m_dht_load, save_dht);
3180 m_register_state_plugin(m, STATE_TYPE_FRIENDS, saved_friendslist_size, friends_list_load, friends_list_save);
3181 m_register_state_plugin(m, STATE_TYPE_NAME, name_size, load_name, save_name);
3182 m_register_state_plugin(m, STATE_TYPE_STATUSMESSAGE, status_message_size, load_status_message,
3183 save_status_message);
3184 m_register_state_plugin(m, STATE_TYPE_STATUS, status_size, load_status, save_status);
3185 m_register_state_plugin(m, STATE_TYPE_TCP_RELAY, tcp_relay_size, load_tcp_relays, save_tcp_relays);
3186 m_register_state_plugin(m, STATE_TYPE_PATH_NODE, path_node_size, load_path_nodes, save_path_nodes);
3187 }
3188
messenger_load_state_section(Messenger * m,const uint8_t * data,uint32_t length,uint16_t type,State_Load_Status * status)3189 bool messenger_load_state_section(Messenger *m, const uint8_t *data, uint32_t length, uint16_t type,
3190 State_Load_Status *status)
3191 {
3192 for (uint8_t i = 0; i < m->options.state_plugins_length; ++i) {
3193 const Messenger_State_Plugin *const plugin = &m->options.state_plugins[i];
3194
3195 if (plugin->type == type) {
3196 *status = plugin->load(m, data, length);
3197 return true;
3198 }
3199 }
3200
3201 return false;
3202 }
3203
3204 /* Return the number of friends in the instance m.
3205 * You should use this to determine how much memory to allocate
3206 * for copy_friendlist. */
count_friendlist(const Messenger * m)3207 uint32_t count_friendlist(const Messenger *m)
3208 {
3209 uint32_t ret = 0;
3210 uint32_t i;
3211
3212 for (i = 0; i < m->numfriends; ++i) {
3213 if (m->friendlist[i].status > 0) {
3214 ++ret;
3215 }
3216 }
3217
3218 return ret;
3219 }
3220
3221 /* Copy a list of valid friend IDs into the array out_list.
3222 * If out_list is NULL, returns 0.
3223 * Otherwise, returns the number of elements copied.
3224 * If the array was too small, the contents
3225 * of out_list will be truncated to list_size. */
copy_friendlist(Messenger const * m,uint32_t * out_list,uint32_t list_size)3226 uint32_t copy_friendlist(Messenger const *m, uint32_t *out_list, uint32_t list_size)
3227 {
3228 if (!out_list) {
3229 return 0;
3230 }
3231
3232 if (m->numfriends == 0) {
3233 return 0;
3234 }
3235
3236 uint32_t i;
3237 uint32_t ret = 0;
3238
3239 for (i = 0; i < m->numfriends; ++i) {
3240 if (ret >= list_size) {
3241 break; /* Abandon ship */
3242 }
3243
3244 if (m->friendlist[i].status > 0) {
3245 out_list[ret] = i;
3246 ++ret;
3247 }
3248 }
3249
3250 return ret;
3251 }
3252