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