summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorirungentoo <irungentoo@gmail.com>2014-09-27 18:25:03 -0400
committerirungentoo <irungentoo@gmail.com>2014-09-27 18:25:03 -0400
commit6c71bb7e64c557d13e7eea4102f1e0bb41ec172f (patch)
tree46fe923003f134b1e68fb36881c82a4d9e612f36
parent834ffee47dab5a03c0a0f8d08809c377f7b8ef7c (diff)
Moved all the connection stuff from messenger to friend_connection.
Messenger was doing way do many things. friend_connection takes care of finding and establishing a connection to friends.
-rw-r--r--toxcore/DHT.h2
-rw-r--r--toxcore/Makefile.inc2
-rw-r--r--toxcore/Messenger.c245
-rw-r--r--toxcore/Messenger.h27
-rw-r--r--toxcore/friend_connection.c565
-rw-r--r--toxcore/friend_connection.h140
6 files changed, 745 insertions, 236 deletions
diff --git a/toxcore/DHT.h b/toxcore/DHT.h
index 5339d3e6..e1e14cd9 100644
--- a/toxcore/DHT.h
+++ b/toxcore/DHT.h
@@ -122,7 +122,7 @@ typedef struct {
122 uint64_t NATping_timestamp; 122 uint64_t NATping_timestamp;
123} NAT; 123} NAT;
124 124
125#define DHT_FRIEND_MAX_LOCKS 2 125#define DHT_FRIEND_MAX_LOCKS 32
126 126
127typedef struct { 127typedef struct {
128 uint8_t client_id[CLIENT_ID_SIZE]; 128 uint8_t client_id[CLIENT_ID_SIZE];
diff --git a/toxcore/Makefile.inc b/toxcore/Makefile.inc
index 8af793c8..9fd1f94a 100644
--- a/toxcore/Makefile.inc
+++ b/toxcore/Makefile.inc
@@ -19,6 +19,8 @@ libtoxcore_la_SOURCES = ../toxcore/DHT.h \
19 ../toxcore/friend_requests.c \ 19 ../toxcore/friend_requests.c \
20 ../toxcore/LAN_discovery.h \ 20 ../toxcore/LAN_discovery.h \
21 ../toxcore/LAN_discovery.c \ 21 ../toxcore/LAN_discovery.c \
22 ../toxcore/friend_connection.h \
23 ../toxcore/friend_connection.c \
22 ../toxcore/Messenger.h \ 24 ../toxcore/Messenger.h \
23 ../toxcore/Messenger.c \ 25 ../toxcore/Messenger.c \
24 ../toxcore/ping.h \ 26 ../toxcore/ping.h \
diff --git a/toxcore/Messenger.c b/toxcore/Messenger.c
index 8faa7f03..04830260 100644
--- a/toxcore/Messenger.c
+++ b/toxcore/Messenger.c
@@ -153,73 +153,9 @@ void getaddress(const Messenger *m, uint8_t *address)
153 memcpy(address + crypto_box_PUBLICKEYBYTES + sizeof(nospam), &checksum, sizeof(checksum)); 153 memcpy(address + crypto_box_PUBLICKEYBYTES + sizeof(nospam), &checksum, sizeof(checksum));
154} 154}
155 155
156/* callback for recv TCP relay nodes. */ 156static int handle_status(void *object, int i, uint8_t status);
157static int tcp_relay_node_callback(void *object, uint32_t number, IP_Port ip_port, const uint8_t *public_key) 157static int handle_packet(void *object, int i, uint8_t *temp, uint16_t len);
158{ 158static int handle_custom_lossy_packet(void *object, int friend_num, const uint8_t *packet, uint16_t length);
159 Messenger *m = object;
160
161 if (friend_not_valid(m, number))
162 return -1;
163
164 if (m->friendlist[number].crypt_connection_id != -1) {
165 return add_tcp_relay_peer(m->net_crypto, m->friendlist[number].crypt_connection_id, ip_port, public_key);
166 } else {
167 return add_tcp_relay(m->net_crypto, ip_port, public_key);
168 }
169}
170
171static int friend_new_connection(Messenger *m, int32_t friendnumber, const uint8_t *real_public_key);
172/* Callback for DHT ip_port changes. */
173static void dht_ip_callback(void *data, int32_t number, IP_Port ip_port)
174{
175 Messenger *m = data;
176
177 if (friend_not_valid(m, number))
178 return;
179
180 if (m->friendlist[number].crypt_connection_id == -1) {
181 friend_new_connection(m, number, m->friendlist[number].client_id);
182 }
183
184 set_direct_ip_port(m->net_crypto, m->friendlist[number].crypt_connection_id, ip_port);
185 m->friendlist[number].dht_ip_port = ip_port;
186 m->friendlist[number].dht_ip_port_lastrecv = unix_time();
187}
188
189/* Callback for dht public key changes. */
190static void dht_pk_callback(void *data, int32_t number, const uint8_t *dht_public_key)
191{
192 Messenger *m = data;
193
194 if (friend_not_valid(m, number))
195 return;
196
197 m->friendlist[number].dht_ping_lastrecv = unix_time();
198
199 if (memcmp(m->friendlist[number].dht_temp_pk, dht_public_key, crypto_box_PUBLICKEYBYTES) == 0)
200 return;
201
202 if (m->friendlist[number].dht_lock) {
203 if (DHT_delfriend(m->dht, m->friendlist[number].dht_temp_pk, m->friendlist[number].dht_lock) != 0) {
204 printf("a. Could not delete dht peer. Please report this.\n");
205 return;
206 }
207
208 m->friendlist[number].dht_lock = 0;
209 }
210
211 DHT_addfriend(m->dht, dht_public_key, dht_ip_callback, data, number, &m->friendlist[number].dht_lock);
212
213 if (m->friendlist[number].crypt_connection_id == -1) {
214 friend_new_connection(m, number, m->friendlist[number].client_id);
215 }
216
217 set_connection_dht_public_key(m->net_crypto, m->friendlist[number].crypt_connection_id, dht_public_key);
218 onion_set_friend_DHT_pubkey(m->onion_c, m->friendlist[number].onion_friendnum, dht_public_key);
219
220 memcpy(m->friendlist[number].dht_temp_pk, dht_public_key, crypto_box_PUBLICKEYBYTES);
221}
222
223 159
224/* 160/*
225 * Add a friend. 161 * Add a friend.
@@ -283,18 +219,17 @@ int32_t m_addfriend(Messenger *m, const uint8_t *address, const uint8_t *data, u
283 219
284 memset(&(m->friendlist[m->numfriends]), 0, sizeof(Friend)); 220 memset(&(m->friendlist[m->numfriends]), 0, sizeof(Friend));
285 221
286 int32_t onion_friendnum = onion_addfriend(m->onion_c, client_id); 222 int friendcon_id = new_friend_connection(m->fr_c, client_id);
287 223
288 if (onion_friendnum == -1) 224 if (friendcon_id == -1)
289 return FAERR_UNKNOWN; 225 return -1;
290 226
291 uint32_t i; 227 uint32_t i;
292 228
293 for (i = 0; i <= m->numfriends; ++i) { 229 for (i = 0; i <= m->numfriends; ++i) {
294 if (m->friendlist[i].status == NOFRIEND) { 230 if (m->friendlist[i].status == NOFRIEND) {
295 m->friendlist[i].onion_friendnum = onion_friendnum;
296 m->friendlist[i].status = FRIEND_ADDED; 231 m->friendlist[i].status = FRIEND_ADDED;
297 m->friendlist[i].crypt_connection_id = -1; 232 m->friendlist[i].friendcon_id = friendcon_id;
298 m->friendlist[i].friendrequest_lastsent = 0; 233 m->friendlist[i].friendrequest_lastsent = 0;
299 m->friendlist[i].friendrequest_timeout = FRIENDREQUEST_TIMEOUT; 234 m->friendlist[i].friendrequest_timeout = FRIENDREQUEST_TIMEOUT;
300 id_copy(m->friendlist[i].client_id, client_id); 235 id_copy(m->friendlist[i].client_id, client_id);
@@ -311,8 +246,9 @@ int32_t m_addfriend(Messenger *m, const uint8_t *address, const uint8_t *data, u
311 m->friendlist[i].message_id = 0; 246 m->friendlist[i].message_id = 0;
312 m->friendlist[i].receives_read_receipts = 1; /* Default: YES. */ 247 m->friendlist[i].receives_read_receipts = 1; /* Default: YES. */
313 memcpy(&(m->friendlist[i].friendrequest_nospam), address + crypto_box_PUBLICKEYBYTES, sizeof(uint32_t)); 248 memcpy(&(m->friendlist[i].friendrequest_nospam), address + crypto_box_PUBLICKEYBYTES, sizeof(uint32_t));
314 recv_tcp_relay_handler(m->onion_c, onion_friendnum, &tcp_relay_node_callback, m, i); 249 friend_connection_callbacks(m->fr_c, friendcon_id, MESSENGER_CALLBACK_INDEX, &handle_status, &handle_packet,
315 onion_dht_pk_callback(m->onion_c, onion_friendnum, &dht_pk_callback, m, i); 250 &handle_custom_lossy_packet, m, i);
251
316 252
317 if (m->numfriends == i) 253 if (m->numfriends == i)
318 ++m->numfriends; 254 ++m->numfriends;
@@ -341,18 +277,17 @@ int32_t m_addfriend_norequest(Messenger *m, const uint8_t *client_id)
341 277
342 memset(&(m->friendlist[m->numfriends]), 0, sizeof(Friend)); 278 memset(&(m->friendlist[m->numfriends]), 0, sizeof(Friend));
343 279
344 int32_t onion_friendnum = onion_addfriend(m->onion_c, client_id); 280 int friendcon_id = new_friend_connection(m->fr_c, client_id);
345 281
346 if (onion_friendnum == -1) 282 if (friendcon_id == -1)
347 return -1; 283 return -1;
348 284
349 uint32_t i; 285 uint32_t i;
350 286
351 for (i = 0; i <= m->numfriends; ++i) { 287 for (i = 0; i <= m->numfriends; ++i) {
352 if (m->friendlist[i].status == NOFRIEND) { 288 if (m->friendlist[i].status == NOFRIEND) {
353 m->friendlist[i].onion_friendnum = onion_friendnum;
354 m->friendlist[i].status = FRIEND_CONFIRMED; 289 m->friendlist[i].status = FRIEND_CONFIRMED;
355 m->friendlist[i].crypt_connection_id = -1; 290 m->friendlist[i].friendcon_id = friendcon_id;
356 m->friendlist[i].friendrequest_lastsent = 0; 291 m->friendlist[i].friendrequest_lastsent = 0;
357 id_copy(m->friendlist[i].client_id, client_id); 292 id_copy(m->friendlist[i].client_id, client_id);
358 m->friendlist[i].statusmessage = calloc(1, 1); 293 m->friendlist[i].statusmessage = calloc(1, 1);
@@ -365,8 +300,8 @@ int32_t m_addfriend_norequest(Messenger *m, const uint8_t *client_id)
365 m->friendlist[i].is_typing = 0; 300 m->friendlist[i].is_typing = 0;
366 m->friendlist[i].message_id = 0; 301 m->friendlist[i].message_id = 0;
367 m->friendlist[i].receives_read_receipts = 1; /* Default: YES. */ 302 m->friendlist[i].receives_read_receipts = 1; /* Default: YES. */
368 recv_tcp_relay_handler(m->onion_c, onion_friendnum, &tcp_relay_node_callback, m, i); 303 friend_connection_callbacks(m->fr_c, friendcon_id, MESSENGER_CALLBACK_INDEX, &handle_status, &handle_packet,
369 onion_dht_pk_callback(m->onion_c, onion_friendnum, &dht_pk_callback, m, i); 304 &handle_custom_lossy_packet, m, i);
370 305
371 if (m->numfriends == i) 306 if (m->numfriends == i)
372 ++m->numfriends; 307 ++m->numfriends;
@@ -391,16 +326,11 @@ int m_delfriend(Messenger *m, int32_t friendnumber)
391 if (m->friendlist[friendnumber].status == FRIEND_ONLINE) 326 if (m->friendlist[friendnumber].status == FRIEND_ONLINE)
392 remove_online_friend(m, friendnumber); 327 remove_online_friend(m, friendnumber);
393 328
394 onion_delfriend(m->onion_c, m->friendlist[friendnumber].onion_friendnum);
395
396 if (m->friendlist[friendnumber].dht_lock) {
397 DHT_delfriend(m->dht, m->friendlist[friendnumber].dht_temp_pk, m->friendlist[friendnumber].dht_lock);
398 }
399
400 crypto_kill(m->net_crypto, m->friendlist[friendnumber].crypt_connection_id);
401 free(m->friendlist[friendnumber].statusmessage); 329 free(m->friendlist[friendnumber].statusmessage);
402 free(m->friendlist[friendnumber].avatar_recv_data); 330 free(m->friendlist[friendnumber].avatar_recv_data);
403 remove_request_received(&(m->fr), m->friendlist[friendnumber].client_id); 331 remove_request_received(&(m->fr), m->friendlist[friendnumber].client_id);
332 friend_connection_callbacks(m->fr_c, m->friendlist[friendnumber].friendcon_id, MESSENGER_CALLBACK_INDEX, 0, 0, 0, 0, 0);
333 kill_friend_connection(m->fr_c, m->friendlist[friendnumber].friendcon_id);
404 memset(&(m->friendlist[friendnumber]), 0, sizeof(Friend)); 334 memset(&(m->friendlist[friendnumber]), 0, sizeof(Friend));
405 uint32_t i; 335 uint32_t i;
406 336
@@ -867,16 +797,6 @@ static int send_user_istyping(const Messenger *m, int32_t friendnumber, uint8_t
867 return write_cryptpacket_id(m, friendnumber, PACKET_ID_TYPING, &typing, sizeof(typing), 0); 797 return write_cryptpacket_id(m, friendnumber, PACKET_ID_TYPING, &typing, sizeof(typing), 0);
868} 798}
869 799
870static int send_ping(const Messenger *m, int32_t friendnumber)
871{
872 int ret = write_cryptpacket_id(m, friendnumber, PACKET_ID_ALIVE, 0, 0, 0);
873
874 if (ret == 1)
875 m->friendlist[friendnumber].ping_lastsent = unix_time();
876
877 return ret;
878}
879
880static int send_relays(const Messenger *m, int32_t friendnumber) 800static int send_relays(const Messenger *m, int32_t friendnumber)
881{ 801{
882 Node_format nodes[MAX_SHARED_RELAYS]; 802 Node_format nodes[MAX_SHARED_RELAYS];
@@ -1023,8 +943,6 @@ static void check_friend_connectionstatus(Messenger *m, int32_t friendnumber, ui
1023 const uint8_t was_online = m->friendlist[friendnumber].status == FRIEND_ONLINE; 943 const uint8_t was_online = m->friendlist[friendnumber].status == FRIEND_ONLINE;
1024 const uint8_t is_online = status == FRIEND_ONLINE; 944 const uint8_t is_online = status == FRIEND_ONLINE;
1025 945
1026 onion_set_friend_online(m->onion_c, m->friendlist[friendnumber].onion_friendnum, is_online);
1027
1028 if (is_online != was_online) { 946 if (is_online != was_online) {
1029 if (was_online) { 947 if (was_online) {
1030 break_files(m, friendnumber); 948 break_files(m, friendnumber);
@@ -1065,8 +983,8 @@ static int write_cryptpacket_id(const Messenger *m, int32_t friendnumber, uint8_
1065 if (length != 0) 983 if (length != 0)
1066 memcpy(packet + 1, data, length); 984 memcpy(packet + 1, data, length);
1067 985
1068 return write_cryptpacket(m->net_crypto, m->friendlist[friendnumber].crypt_connection_id, packet, length + 1, 986 return write_cryptpacket(m->net_crypto, friend_connection_crypt_connection_id(m->fr_c,
1069 congestion_control) != -1; 987 m->friendlist[friendnumber].friendcon_id), packet, length + 1, congestion_control) != -1;
1070} 988}
1071 989
1072/**********GROUP CHATS************/ 990/**********GROUP CHATS************/
@@ -1311,8 +1229,8 @@ int file_data(const Messenger *m, int32_t friendnumber, uint8_t filenumber, cons
1311 if (m->friendlist[friendnumber].file_sending[filenumber].status != FILESTATUS_TRANSFERRING) 1229 if (m->friendlist[friendnumber].file_sending[filenumber].status != FILESTATUS_TRANSFERRING)
1312 return -1; 1230 return -1;
1313 1231
1314 /* Prevent file sending from filling up the entire buffer preventing messages from being sent. */ 1232 /* Prevent file sending from filling up the entire buffer preventing messages from being sent. TODO: remove */
1315 if (crypto_num_free_sendqueue_slots(m->net_crypto, m->friendlist[friendnumber].crypt_connection_id) < MIN_SLOTS_FREE) 1233 if (crypto_num_free_sendqueue_slots(m->net_crypto, friend_connection_crypt_connection_id(m->fr_c, m->friendlist[friendnumber].friendcon_id)) < MIN_SLOTS_FREE)
1316 return -1; 1234 return -1;
1317 1235
1318 uint8_t packet[MAX_CRYPTO_DATA_SIZE]; 1236 uint8_t packet[MAX_CRYPTO_DATA_SIZE];
@@ -1518,10 +1436,8 @@ int send_custom_lossy_packet(const Messenger *m, int32_t friendnumber, const uin
1518 if (m->friendlist[friendnumber].status != FRIEND_ONLINE) 1436 if (m->friendlist[friendnumber].status != FRIEND_ONLINE)
1519 return -1; 1437 return -1;
1520 1438
1521 if (m->friendlist[friendnumber].crypt_connection_id == -1) 1439 return send_lossy_cryptpacket(m->net_crypto, friend_connection_crypt_connection_id(m->fr_c,
1522 return -1; 1440 m->friendlist[friendnumber].friendcon_id), data, length);
1523
1524 return send_lossy_cryptpacket(m->net_crypto, m->friendlist[friendnumber].crypt_connection_id, data, length);
1525} 1441}
1526 1442
1527static int handle_custom_lossless_packet(void *object, int friend_num, const uint8_t *packet, uint16_t length) 1443static int handle_custom_lossless_packet(void *object, int friend_num, const uint8_t *packet, uint16_t length)
@@ -1579,10 +1495,8 @@ int send_custom_lossless_packet(const Messenger *m, int32_t friendnumber, const
1579 if (m->friendlist[friendnumber].status != FRIEND_ONLINE) 1495 if (m->friendlist[friendnumber].status != FRIEND_ONLINE)
1580 return -1; 1496 return -1;
1581 1497
1582 if (m->friendlist[friendnumber].crypt_connection_id == -1) 1498 if (write_cryptpacket(m->net_crypto, friend_connection_crypt_connection_id(m->fr_c,
1583 return -1; 1499 m->friendlist[friendnumber].friendcon_id), data, length, 1) == -1) {
1584
1585 if (write_cryptpacket(m->net_crypto, m->friendlist[friendnumber].crypt_connection_id, data, length, 1) == -1) {
1586 return -1; 1500 return -1;
1587 } else { 1501 } else {
1588 return 0; 1502 return 0;
@@ -1609,42 +1523,6 @@ static void LANdiscovery(Messenger *m)
1609 } 1523 }
1610} 1524}
1611 1525
1612static int handle_status(void *object, int i, uint8_t status);
1613static int handle_packet(void *object, int i, uint8_t *temp, uint16_t len);
1614
1615static int handle_new_connections(void *object, New_Connection *n_c)
1616{
1617 Messenger *m = object;
1618 int friend_id = getfriend_id(m, n_c->public_key);
1619
1620 if (friend_id != -1) {
1621 if (m->friendlist[friend_id].crypt_connection_id != -1)
1622 return -1;
1623
1624 int id = accept_crypto_connection(m->net_crypto, n_c);
1625 connection_status_handler(m->net_crypto, id, &handle_status, m, friend_id);
1626 connection_data_handler(m->net_crypto, id, &handle_packet, m, friend_id);
1627 connection_lossy_data_handler(m->net_crypto, id, &handle_custom_lossy_packet, m, friend_id);
1628 m->friendlist[friend_id].crypt_connection_id = id;
1629 set_friend_status(m, friend_id, FRIEND_CONFIRMED);
1630
1631 if (n_c->source.ip.family != AF_INET && n_c->source.ip.family != AF_INET6) {
1632 set_direct_ip_port(m->net_crypto, m->friendlist[friend_id].crypt_connection_id, m->friendlist[friend_id].dht_ip_port);
1633 } else {
1634 m->friendlist[friend_id].dht_ip_port = n_c->source;
1635 m->friendlist[friend_id].dht_ip_port_lastrecv = unix_time();
1636 }
1637
1638 dht_pk_callback(m, friend_id, n_c->dht_public_key);
1639
1640 nc_dht_pk_callback(m->net_crypto, id, &dht_pk_callback, m, friend_id);
1641 return 0;
1642 }
1643
1644 return -1;
1645}
1646
1647
1648/* Run this at startup. */ 1526/* Run this at startup. */
1649Messenger *new_messenger(Messenger_Options *options) 1527Messenger *new_messenger(Messenger_Options *options)
1650{ 1528{
@@ -1691,13 +1569,13 @@ Messenger *new_messenger(Messenger_Options *options)
1691 return NULL; 1569 return NULL;
1692 } 1570 }
1693 1571
1694 new_connection_handler(m->net_crypto, &handle_new_connections, m);
1695
1696 m->onion = new_onion(m->dht); 1572 m->onion = new_onion(m->dht);
1697 m->onion_a = new_onion_announce(m->dht); 1573 m->onion_a = new_onion_announce(m->dht);
1698 m->onion_c = new_onion_client(m->net_crypto); 1574 m->onion_c = new_onion_client(m->net_crypto);
1575 m->fr_c = new_friend_connections(m->onion_c);
1699 1576
1700 if (!(m->onion && m->onion_a && m->onion_c)) { 1577 if (!(m->onion && m->onion_a && m->onion_c)) {
1578 kill_friend_connections(m->fr_c);
1701 kill_onion(m->onion); 1579 kill_onion(m->onion);
1702 kill_onion_announce(m->onion_a); 1580 kill_onion_announce(m->onion_a);
1703 kill_onion_client(m->onion_c); 1581 kill_onion_client(m->onion_c);
@@ -1722,6 +1600,7 @@ void kill_messenger(Messenger *m)
1722{ 1600{
1723 uint32_t i; 1601 uint32_t i;
1724 1602
1603 kill_friend_connections(m->fr_c);
1725 kill_onion(m->onion); 1604 kill_onion(m->onion);
1726 kill_onion_announce(m->onion_a); 1605 kill_onion_announce(m->onion_a);
1727 kill_onion_client(m->onion_c); 1606 kill_onion_client(m->onion_c);
@@ -1769,10 +1648,6 @@ static int handle_status(void *object, int i, uint8_t status)
1769 m->friendlist[i].statusmessage_sent = 0; 1648 m->friendlist[i].statusmessage_sent = 0;
1770 m->friendlist[i].ping_lastrecv = temp_time; 1649 m->friendlist[i].ping_lastrecv = temp_time;
1771 } else { /* Went offline. */ 1650 } else { /* Went offline. */
1772 m->friendlist[i].crypt_connection_id = -1;
1773
1774 m->friendlist[i].dht_ping_lastrecv = temp_time;
1775
1776 if (m->friendlist[i].status == FRIEND_ONLINE) { 1651 if (m->friendlist[i].status == FRIEND_ONLINE) {
1777 set_friend_status(m, i, FRIEND_CONFIRMED); 1652 set_friend_status(m, i, FRIEND_CONFIRMED);
1778 } 1653 }
@@ -2072,11 +1947,6 @@ static int handle_packet(void *object, int i, uint8_t *temp, uint16_t len)
2072 return -1; 1947 return -1;
2073 1948
2074 switch (packet_id) { 1949 switch (packet_id) {
2075 case PACKET_ID_ALIVE: {
2076 m->friendlist[i].ping_lastrecv = temp_time;
2077 break;
2078 }
2079
2080 case PACKET_ID_NICKNAME: { 1950 case PACKET_ID_NICKNAME: {
2081 if (data_length > MAX_NAME_LENGTH || data_length == 0) 1951 if (data_length > MAX_NAME_LENGTH || data_length == 0)
2082 break; 1952 break;
@@ -2359,29 +2229,6 @@ static int handle_packet(void *object, int i, uint8_t *temp, uint16_t len)
2359 return 0; 2229 return 0;
2360} 2230}
2361 2231
2362static int friend_new_connection(Messenger *m, int32_t friendnumber, const uint8_t *real_public_key)
2363{
2364 if (friend_not_valid(m, friendnumber))
2365 return -1;
2366
2367 if (m->friendlist[friendnumber].crypt_connection_id != -1) {
2368 return -1;
2369 }
2370
2371 int id = new_crypto_connection(m->net_crypto, real_public_key);
2372
2373 if (id == -1)
2374 return -1;
2375
2376 m->friendlist[friendnumber].crypt_connection_id = id;
2377 connection_status_handler(m->net_crypto, id, &handle_status, m, friendnumber);
2378 connection_data_handler(m->net_crypto, id, &handle_packet, m, friendnumber);
2379 connection_lossy_data_handler(m->net_crypto, id, &handle_custom_lossy_packet, m, friendnumber);
2380 nc_dht_pk_callback(m->net_crypto, id, &dht_pk_callback, m, friendnumber);
2381
2382 return 0;
2383}
2384
2385/* TODO: Make this function not suck. */ 2232/* TODO: Make this function not suck. */
2386void do_friends(Messenger *m) 2233void do_friends(Messenger *m)
2387{ 2234{
@@ -2407,27 +2254,7 @@ void do_friends(Messenger *m)
2407 * unsuccessful so we set the status back to FRIEND_ADDED and try again. 2254 * unsuccessful so we set the status back to FRIEND_ADDED and try again.
2408 */ 2255 */
2409 check_friend_request_timed_out(m, i, temp_time); 2256 check_friend_request_timed_out(m, i, temp_time);
2410
2411 } else {
2412 if (m->friendlist[i].dht_ping_lastrecv + FRIEND_DHT_TIMEOUT < temp_time) {
2413 if (m->friendlist[i].dht_lock) {
2414 DHT_delfriend(m->dht, m->friendlist[i].dht_temp_pk, m->friendlist[i].dht_lock);
2415 m->friendlist[i].dht_lock = 0;
2416 }
2417 }
2418
2419 if (m->friendlist[i].dht_ip_port_lastrecv + FRIEND_DHT_TIMEOUT < temp_time) {
2420 m->friendlist[i].dht_ip_port.ip.family = 0;
2421 }
2422 } 2257 }
2423
2424 if (friend_new_connection(m, i, m->friendlist[i].client_id) == 0) {
2425 if (m->friendlist[i].dht_lock)
2426 set_connection_dht_public_key(m->net_crypto, m->friendlist[i].crypt_connection_id, m->friendlist[i].dht_temp_pk);
2427
2428 set_direct_ip_port(m->net_crypto, m->friendlist[i].crypt_connection_id, m->friendlist[i].dht_ip_port);
2429 }
2430
2431 } 2258 }
2432 2259
2433 if (m->friendlist[i].status == FRIEND_ONLINE) { /* friend is online. */ 2260 if (m->friendlist[i].status == FRIEND_ONLINE) { /* friend is online. */
@@ -2456,17 +2283,6 @@ void do_friends(Messenger *m)
2456 m->friendlist[i].user_istyping_sent = 1; 2283 m->friendlist[i].user_istyping_sent = 1;
2457 } 2284 }
2458 2285
2459 if (m->friendlist[i].ping_lastsent + FRIEND_PING_INTERVAL < temp_time) {
2460 send_ping(m, i);
2461 }
2462
2463 if (m->friendlist[i].ping_lastrecv + FRIEND_CONNECTION_TIMEOUT < temp_time) {
2464 /* If we stopped receiving ping packets, kill it. */
2465 crypto_kill(m->net_crypto, m->friendlist[i].crypt_connection_id);
2466 m->friendlist[i].crypt_connection_id = -1;
2467 set_friend_status(m, i, FRIEND_CONFIRMED);
2468 }
2469
2470 if (m->friendlist[i].share_relays_lastsent + FRIEND_SHARE_RELAYS_INTERVAL < temp_time) { 2286 if (m->friendlist[i].share_relays_lastsent + FRIEND_SHARE_RELAYS_INTERVAL < temp_time) {
2471 send_relays(m, i); 2287 send_relays(m, i);
2472 } 2288 }
@@ -2536,6 +2352,7 @@ void do_messenger(Messenger *m)
2536 2352
2537 do_net_crypto(m->net_crypto); 2353 do_net_crypto(m->net_crypto);
2538 do_onion_client(m->onion_c); 2354 do_onion_client(m->onion_c);
2355 do_friend_connections(m->fr_c);
2539 do_friends(m); 2356 do_friends(m);
2540 LANdiscovery(m); 2357 LANdiscovery(m);
2541 2358
@@ -2616,8 +2433,8 @@ void do_messenger(Messenger *m)
2616 if (ping_lastrecv > 999) 2433 if (ping_lastrecv > 999)
2617 ping_lastrecv = 999; 2434 ping_lastrecv = 999;
2618 2435
2619 LOGGER_INFO("F[%2u:%2u] <%s> %02i [%03u] %s", 2436 LOGGER_INFO("F[%2u:%2u] <%s> [%03u] %s",
2620 dht2m[friend], friend, msgfptr->name, msgfptr->crypt_connection_id, 2437 dht2m[friend], friend, msgfptr->name,
2621 ping_lastrecv, ID2String(msgfptr->client_id)); 2438 ping_lastrecv, ID2String(msgfptr->client_id));
2622 } else { 2439 } else {
2623 LOGGER_INFO("F[--:%2u] %s", friend, ID2String(dhtfptr->client_id)); 2440 LOGGER_INFO("F[--:%2u] %s", friend, ID2String(dhtfptr->client_id));
diff --git a/toxcore/Messenger.h b/toxcore/Messenger.h
index 60d00225..454c31cb 100644
--- a/toxcore/Messenger.h
+++ b/toxcore/Messenger.h
@@ -26,11 +26,9 @@
26#ifndef MESSENGER_H 26#ifndef MESSENGER_H
27#define MESSENGER_H 27#define MESSENGER_H
28 28
29#include "net_crypto.h"
30#include "DHT.h"
31#include "friend_requests.h" 29#include "friend_requests.h"
32#include "LAN_discovery.h" 30#include "LAN_discovery.h"
33#include "onion_client.h" 31#include "friend_connection.h"
34 32
35#define MAX_NAME_LENGTH 128 33#define MAX_NAME_LENGTH 128
36/* TODO: this must depend on other variable. */ 34/* TODO: this must depend on other variable. */
@@ -41,8 +39,7 @@
41 39
42#define FRIEND_ADDRESS_SIZE (crypto_box_PUBLICKEYBYTES + sizeof(uint32_t) + sizeof(uint16_t)) 40#define FRIEND_ADDRESS_SIZE (crypto_box_PUBLICKEYBYTES + sizeof(uint32_t) + sizeof(uint16_t))
43 41
44/* NOTE: Packet ids below 16 must never be used. */ 42/* NOTE: Packet ids below 17 must never be used. */
45#define PACKET_ID_ALIVE 16
46#define PACKET_ID_SHARE_RELAYS 17 43#define PACKET_ID_SHARE_RELAYS 17
47#define PACKET_ID_NICKNAME 48 44#define PACKET_ID_NICKNAME 48
48#define PACKET_ID_STATUSMESSAGE 49 45#define PACKET_ID_STATUSMESSAGE 49
@@ -104,15 +101,9 @@ enum {
104/* Default start timeout in seconds between friend requests. */ 101/* Default start timeout in seconds between friend requests. */
105#define FRIENDREQUEST_TIMEOUT 5; 102#define FRIENDREQUEST_TIMEOUT 5;
106 103
107/* Interval between the sending of ping packets. */
108#define FRIEND_PING_INTERVAL 6
109
110/* Interval between the sending of tcp relay information */ 104/* Interval between the sending of tcp relay information */
111#define FRIEND_SHARE_RELAYS_INTERVAL (5 * 60) 105#define FRIEND_SHARE_RELAYS_INTERVAL (5 * 60)
112 106
113/* If no packets are received from friend in this time interval, kill the connection. */
114#define FRIEND_CONNECTION_TIMEOUT (FRIEND_PING_INTERVAL * 3)
115
116/* Must be < MAX_CRYPTO_DATA_SIZE */ 107/* Must be < MAX_CRYPTO_DATA_SIZE */
117#define AVATAR_DATA_MAX_CHUNK_SIZE (MAX_CRYPTO_DATA_SIZE-1) 108#define AVATAR_DATA_MAX_CHUNK_SIZE (MAX_CRYPTO_DATA_SIZE-1)
118 109
@@ -120,7 +111,6 @@ enum {
120#define AVATAR_DATA_TRANSFER_LIMIT (10*AVATAR_MAX_DATA_LENGTH) 111#define AVATAR_DATA_TRANSFER_LIMIT (10*AVATAR_MAX_DATA_LENGTH)
121#define AVATAR_DATA_TRANSFER_TIMEOUT (60) /* 164kB every 60 seconds is not a lot */ 112#define AVATAR_DATA_TRANSFER_TIMEOUT (60) /* 164kB every 60 seconds is not a lot */
122 113
123#define FRIEND_DHT_TIMEOUT BAD_NODE_TIMEOUT /* Time before friend is removed from the DHT after last hearing about him. */
124 114
125/* USERSTATUS - 115/* USERSTATUS -
126 * Represents userstatuses someone can have. 116 * Represents userstatuses someone can have.
@@ -197,14 +187,8 @@ enum {
197 187
198typedef struct { 188typedef struct {
199 uint8_t client_id[crypto_box_PUBLICKEYBYTES]; 189 uint8_t client_id[crypto_box_PUBLICKEYBYTES];
190 int friendcon_id;
200 191
201 uint8_t dht_temp_pk[crypto_box_PUBLICKEYBYTES];
202 uint16_t dht_lock;
203 IP_Port dht_ip_port;
204 uint64_t dht_ping_lastrecv, dht_ip_port_lastrecv;
205
206 uint32_t onion_friendnum;
207 int crypt_connection_id;
208 uint64_t friendrequest_lastsent; // Time at which the last friend request was sent. 192 uint64_t friendrequest_lastsent; // Time at which the last friend request was sent.
209 uint32_t friendrequest_timeout; // The timeout between successful friendrequest sending attempts. 193 uint32_t friendrequest_timeout; // The timeout between successful friendrequest sending attempts.
210 uint8_t status; // 0 if no friend, 1 if added, 2 if friend request sent, 3 if confirmed friend, 4 if online. 194 uint8_t status; // 0 if no friend, 1 if added, 2 if friend request sent, 3 if confirmed friend, 4 if online.
@@ -225,8 +209,7 @@ typedef struct {
225 uint32_t message_id; // a semi-unique id used in read receipts. 209 uint32_t message_id; // a semi-unique id used in read receipts.
226 uint8_t receives_read_receipts; // shall we send read receipts to this person? 210 uint8_t receives_read_receipts; // shall we send read receipts to this person?
227 uint32_t friendrequest_nospam; // The nospam number used in the friend request. 211 uint32_t friendrequest_nospam; // The nospam number used in the friend request.
228 uint64_t ping_lastrecv; 212 uint64_t ping_lastrecv;//TODO remove
229 uint64_t ping_lastsent;
230 uint64_t share_relays_lastsent; 213 uint64_t share_relays_lastsent;
231 struct File_Transfers file_sending[MAX_CONCURRENT_FILE_PIPES]; 214 struct File_Transfers file_sending[MAX_CONCURRENT_FILE_PIPES];
232 struct File_Transfers file_receiving[MAX_CONCURRENT_FILE_PIPES]; 215 struct File_Transfers file_receiving[MAX_CONCURRENT_FILE_PIPES];
@@ -256,6 +239,8 @@ typedef struct Messenger {
256 Onion_Announce *onion_a; 239 Onion_Announce *onion_a;
257 Onion_Client *onion_c; 240 Onion_Client *onion_c;
258 241
242 Friend_Connections *fr_c;
243
259 Friend_Requests fr; 244 Friend_Requests fr;
260 uint8_t name[MAX_NAME_LENGTH]; 245 uint8_t name[MAX_NAME_LENGTH];
261 uint16_t name_length; 246 uint16_t name_length;
diff --git a/toxcore/friend_connection.c b/toxcore/friend_connection.c
new file mode 100644
index 00000000..09dea4c3
--- /dev/null
+++ b/toxcore/friend_connection.c
@@ -0,0 +1,565 @@
1/* friend_connection.c
2 *
3 * Connection to friends.
4 *
5 * Copyright (C) 2014 Tox project All Rights Reserved.
6 *
7 * This file is part of Tox.
8 *
9 * Tox is free software: you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation, either version 3 of the License, or
12 * (at your option) any later version.
13 *
14 * Tox is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with Tox. If not, see <http://www.gnu.org/licenses/>.
21 *
22 */
23
24#ifdef HAVE_CONFIG_H
25#include "config.h"
26#endif
27
28#include "friend_connection.h"
29#include "util.h"
30
31/* return 1 if the friendcon_id is not valid.
32 * return 0 if the friendcon_id is valid.
33 */
34static uint8_t friendconn_id_not_valid(const Friend_Connections *fr_c, int friendcon_id)
35{
36 if ((unsigned int)friendcon_id >= fr_c->num_cons)
37 return 1;
38
39 if (fr_c->conns == NULL)
40 return 1;
41
42 if (fr_c->conns[friendcon_id].status == FRIENDCONN_STATUS_NONE)
43 return 1;
44
45 return 0;
46}
47
48
49/* Set the size of the friend connections list to num.
50 *
51 * return -1 if realloc fails.
52 * return 0 if it succeeds.
53 */
54static int realloc_friendconns(Friend_Connections *fr_c, uint32_t num)
55{
56 if (num == 0) {
57 free(fr_c->conns);
58 fr_c->conns = NULL;
59 return 0;
60 }
61
62 Friend_Conn *newgroup_cons = realloc(fr_c->conns, num * sizeof(Friend_Conn));
63
64 if (newgroup_cons == NULL)
65 return -1;
66
67 fr_c->conns = newgroup_cons;
68 return 0;
69}
70
71/* Create a new empty friend connection.
72 *
73 * return -1 on failure.
74 * return friendcon_id on success.
75 */
76static int create_friend_conn(Friend_Connections *fr_c)
77{
78 uint32_t i;
79
80 for (i = 0; i < fr_c->num_cons; ++i) {
81 if (fr_c->conns[i].status == FRIENDCONN_STATUS_NONE)
82 return i;
83 }
84
85 int id = -1;
86
87 if (realloc_friendconns(fr_c, fr_c->num_cons + 1) == 0) {
88 id = fr_c->num_cons;
89 ++fr_c->num_cons;
90 memset(&(fr_c->conns[id]), 0, sizeof(Friend_Conn));
91 }
92
93 return id;
94}
95
96/* Wipe a friend connection.
97 *
98 * return -1 on failure.
99 * return 0 on success.
100 */
101static int wipe_friend_conn(Friend_Connections *fr_c, int friendcon_id)
102{
103 if (friendconn_id_not_valid(fr_c, friendcon_id))
104 return -1;
105
106 uint32_t i;
107 memset(&(fr_c->conns[friendcon_id]), 0 , sizeof(Friend_Conn));
108
109 for (i = fr_c->num_cons; i != 0; --i) {
110 if (fr_c->conns[i - 1].status != FRIENDCONN_STATUS_NONE)
111 break;
112 }
113
114 if (fr_c->num_cons != i) {
115 fr_c->num_cons = i;
116 realloc_friendconns(fr_c, fr_c->num_cons);
117 }
118
119 return 0;
120}
121
122static Friend_Conn *get_conn(const Friend_Connections *fr_c, int friendcon_id)
123{
124 if (friendconn_id_not_valid(fr_c, friendcon_id))
125 return 0;
126
127 return &fr_c->conns[friendcon_id];
128}
129
130/* return friendcon_id corresponding to the real public key on success.
131 * return -1 on failure.
132 */
133int getfriend_conn_id_pk(Friend_Connections *fr_c, const uint8_t *real_pk)
134{
135 uint32_t i;
136
137 for (i = 0; i < fr_c->num_cons; ++i) {
138 Friend_Conn *friend_con = get_conn(fr_c, i);
139
140 if (friend_con) {
141 if (memcmp(friend_con->real_public_key, real_pk, crypto_box_PUBLICKEYBYTES) == 0)
142 return i;
143 }
144 }
145
146 return -1;
147}
148
149/* callback for recv TCP relay nodes. */
150static int tcp_relay_node_callback(void *object, uint32_t number, IP_Port ip_port, const uint8_t *public_key)
151{
152 Friend_Connections *fr_c = object;
153 Friend_Conn *friend_con = get_conn(fr_c, number);
154
155 if (!friend_con)
156 return -1;
157
158 if (friend_con->crypt_connection_id != -1) {
159 return add_tcp_relay_peer(fr_c->net_crypto, friend_con->crypt_connection_id, ip_port, public_key);
160 } else {
161 return add_tcp_relay(fr_c->net_crypto, ip_port, public_key);
162 }
163}
164
165static int friend_new_connection(Friend_Connections *fr_c, int friendcon_id);
166/* Callback for DHT ip_port changes. */
167static void dht_ip_callback(void *object, int32_t number, IP_Port ip_port)
168{
169 Friend_Connections *fr_c = object;
170 Friend_Conn *friend_con = get_conn(fr_c, number);
171
172 if (!friend_con)
173 return;
174
175 if (friend_con->crypt_connection_id == -1) {
176 friend_new_connection(fr_c, number);
177 }
178
179 set_direct_ip_port(fr_c->net_crypto, friend_con->crypt_connection_id, ip_port);
180 friend_con->dht_ip_port = ip_port;
181 friend_con->dht_ip_port_lastrecv = unix_time();
182}
183
184/* Callback for dht public key changes. */
185static void dht_pk_callback(void *object, int32_t number, const uint8_t *dht_public_key)
186{
187 Friend_Connections *fr_c = object;
188 Friend_Conn *friend_con = get_conn(fr_c, number);
189
190 if (!friend_con)
191 return;
192
193 friend_con->dht_ping_lastrecv = unix_time();
194
195 if (memcmp(friend_con->dht_temp_pk, dht_public_key, crypto_box_PUBLICKEYBYTES) == 0)
196 return;
197
198 if (friend_con->dht_lock) {
199 if (DHT_delfriend(fr_c->dht, friend_con->dht_temp_pk, friend_con->dht_lock) != 0) {
200 printf("a. Could not delete dht peer. Please report this.\n");
201 return;
202 }
203
204 friend_con->dht_lock = 0;
205 }
206
207 DHT_addfriend(fr_c->dht, dht_public_key, dht_ip_callback, object, number, &friend_con->dht_lock);
208
209 if (friend_con->crypt_connection_id == -1) {
210 friend_new_connection(fr_c, number);
211 }
212
213 set_connection_dht_public_key(fr_c->net_crypto, friend_con->crypt_connection_id, dht_public_key);
214 onion_set_friend_DHT_pubkey(fr_c->onion_c, friend_con->onion_friendnum, dht_public_key);
215
216 memcpy(friend_con->dht_temp_pk, dht_public_key, crypto_box_PUBLICKEYBYTES);
217}
218
219static int handle_status(void *object, int number, uint8_t status)
220{
221 Friend_Connections *fr_c = object;
222 Friend_Conn *friend_con = get_conn(fr_c, number);
223
224 if (!friend_con)
225 return -1;
226
227 if (status) { /* Went online. */
228 friend_con->status = FRIENDCONN_STATUS_CONNECTED;
229 friend_con->ping_lastrecv = unix_time();
230 onion_set_friend_online(fr_c->onion_c, friend_con->onion_friendnum, status);
231 } else { /* Went offline. */
232 friend_con->status = FRIENDCONN_STATUS_CONNECTING;
233 friend_con->crypt_connection_id = -1;
234 friend_con->dht_ping_lastrecv = unix_time();
235 }
236
237 unsigned int i;
238
239 for (i = 0; i < MAX_FRIEND_CONNECTION_CALLBACKS; ++i) {
240 if (friend_con->callbacks[i].status_callback)
241 friend_con->callbacks[i].status_callback(friend_con->callbacks[i].status_callback_object,
242 friend_con->callbacks[i].status_callback_id, status);
243 }
244
245 return 0;
246}
247
248static int handle_packet(void *object, int number, uint8_t *data, uint16_t length)
249{
250 if (length == 0)
251 return -1;
252
253 Friend_Connections *fr_c = object;
254 Friend_Conn *friend_con = get_conn(fr_c, number);
255
256 if (!friend_con)
257 return -1;
258
259 if (data[0] == PACKET_ID_ALIVE) {
260 friend_con->ping_lastrecv = unix_time();
261 return 0;
262 }
263
264 unsigned int i;
265
266 for (i = 0; i < MAX_FRIEND_CONNECTION_CALLBACKS; ++i) {
267 if (friend_con->callbacks[i].data_callback)
268 friend_con->callbacks[i].data_callback(friend_con->callbacks[i].data_callback_object,
269 friend_con->callbacks[i].data_callback_id, data, length);
270 }
271
272 return 0;
273}
274
275static int handle_lossy_packet(void *object, int number, const uint8_t *data, uint16_t length)
276{
277 if (length == 0)
278 return -1;
279
280 Friend_Connections *fr_c = object;
281 Friend_Conn *friend_con = get_conn(fr_c, number);
282
283 if (!friend_con)
284 return -1;
285
286 unsigned int i;
287
288 for (i = 0; i < MAX_FRIEND_CONNECTION_CALLBACKS; ++i) {
289 if (friend_con->callbacks[i].lossy_data_callback)
290 friend_con->callbacks[i].lossy_data_callback(friend_con->callbacks[i].lossy_data_callback_object,
291 friend_con->callbacks[i].lossy_data_callback_id, data, length);
292 }
293
294 return 0;
295}
296
297static int handle_new_connections(void *object, New_Connection *n_c)
298{
299 Friend_Connections *fr_c = object;
300 int friendcon_id = getfriend_conn_id_pk(fr_c, n_c->public_key);
301 Friend_Conn *friend_con = get_conn(fr_c, friendcon_id);
302
303 if (friend_con) {
304
305 if (friend_con->crypt_connection_id != -1)
306 return -1;
307
308 int id = accept_crypto_connection(fr_c->net_crypto, n_c);
309 connection_status_handler(fr_c->net_crypto, id, &handle_status, fr_c, friendcon_id);
310 connection_data_handler(fr_c->net_crypto, id, &handle_packet, fr_c, friendcon_id);
311 connection_lossy_data_handler(fr_c->net_crypto, id, &handle_lossy_packet, fr_c, friendcon_id);
312 friend_con->crypt_connection_id = id;
313
314 if (n_c->source.ip.family != AF_INET && n_c->source.ip.family != AF_INET6) {
315 set_direct_ip_port(fr_c->net_crypto, friend_con->crypt_connection_id, friend_con->dht_ip_port);
316 } else {
317 friend_con->dht_ip_port = n_c->source;
318 friend_con->dht_ip_port_lastrecv = unix_time();
319 }
320
321 dht_pk_callback(fr_c, friendcon_id, n_c->dht_public_key);
322
323 nc_dht_pk_callback(fr_c->net_crypto, id, &dht_pk_callback, fr_c, friendcon_id);
324 return 0;
325 }
326
327 return -1;
328}
329
330static int friend_new_connection(Friend_Connections *fr_c, int friendcon_id)
331{
332 Friend_Conn *friend_con = get_conn(fr_c, friendcon_id);
333
334 if (!friend_con)
335 return -1;
336
337 if (friend_con->crypt_connection_id != -1) {
338 return -1;
339 }
340
341 int id = new_crypto_connection(fr_c->net_crypto, friend_con->real_public_key);
342
343 if (id == -1)
344 return -1;
345
346 friend_con->crypt_connection_id = id;
347 connection_status_handler(fr_c->net_crypto, id, &handle_status, fr_c, friendcon_id);
348 connection_data_handler(fr_c->net_crypto, id, &handle_packet, fr_c, friendcon_id);
349 connection_lossy_data_handler(fr_c->net_crypto, id, &handle_lossy_packet, fr_c, friendcon_id);
350 nc_dht_pk_callback(fr_c->net_crypto, id, &dht_pk_callback, fr_c, friendcon_id);
351
352 return 0;
353}
354
355static int send_ping(const Friend_Connections *fr_c, int friendcon_id)
356{
357 Friend_Conn *friend_con = get_conn(fr_c, friendcon_id);
358
359 if (!friend_con)
360 return -1;
361
362 uint8_t ping = PACKET_ID_ALIVE;
363 int64_t ret = write_cryptpacket(fr_c->net_crypto, friend_con->crypt_connection_id, &ping, sizeof(ping), 0);
364
365 if (ret != -1) {
366 friend_con->ping_lastsent = unix_time();
367 return 0;
368 }
369
370 return -1;
371}
372
373/* Set the callbacks for the friend connection.
374 * index is the index (0 to (MAX_FRIEND_CONNECTION_CALLBACKS - 1)) we want the callback to set in the array.
375 *
376 * return 0 on success.
377 * return -1 on failure
378 */
379int friend_connection_callbacks(Friend_Connections *fr_c, int friendcon_id, unsigned int index,
380 int (*status_callback)(void *object, int id, uint8_t status), int (*data_callback)(void *object, int id, uint8_t *data,
381 uint16_t length), int (*lossy_data_callback)(void *object, int id, const uint8_t *data, uint16_t length), void *object,
382 int number)
383{
384 Friend_Conn *friend_con = get_conn(fr_c, friendcon_id);
385
386 if (!friend_con)
387 return -1;
388
389 if (index >= MAX_FRIEND_CONNECTION_CALLBACKS)
390 return -1;
391
392 friend_con->callbacks[index].status_callback = status_callback;
393 friend_con->callbacks[index].data_callback = data_callback;
394 friend_con->callbacks[index].lossy_data_callback = lossy_data_callback;
395
396 friend_con->callbacks[index].status_callback_object =
397 friend_con->callbacks[index].data_callback_object =
398 friend_con->callbacks[index].lossy_data_callback_object = object;
399
400 friend_con->callbacks[index].status_callback_id =
401 friend_con->callbacks[index].data_callback_id =
402 friend_con->callbacks[index].lossy_data_callback_id = number;
403 return 0;
404}
405
406/* return the crypt_connection_id for the connection.
407 *
408 * return crypt_connection_id on success.
409 * return -1 on failure.
410 */
411int friend_connection_crypt_connection_id(Friend_Connections *fr_c, int friendcon_id)
412{
413 Friend_Conn *friend_con = get_conn(fr_c, friendcon_id);
414
415 if (!friend_con)
416 return -1;
417
418 return friend_con->crypt_connection_id;
419}
420
421/* Create a new friend connection.
422 * If one to that real public key already exists, increase lock count and return it.
423 *
424 * return -1 on failure.
425 * return connection id on success.
426 */
427int new_friend_connection(Friend_Connections *fr_c, const uint8_t *real_public_key)
428{
429 int friendcon_id = getfriend_conn_id_pk(fr_c, real_public_key);
430
431 if (friendcon_id != -1) {
432 ++fr_c->conns[friendcon_id].lock_count;
433 return friendcon_id;
434 }
435
436 friendcon_id = create_friend_conn(fr_c);
437
438 if (friendcon_id == -1)
439 return -1;
440
441 int32_t onion_friendnum = onion_addfriend(fr_c->onion_c, real_public_key);
442
443 if (onion_friendnum == -1)
444 return -1;
445
446 Friend_Conn *friend_con = &fr_c->conns[friendcon_id];
447
448 friend_con->crypt_connection_id = -1;
449 friend_con->status = FRIENDCONN_STATUS_CONNECTING;
450 memcpy(friend_con->real_public_key, real_public_key, crypto_box_PUBLICKEYBYTES);
451 friend_con->onion_friendnum = onion_friendnum;
452
453 recv_tcp_relay_handler(fr_c->onion_c, onion_friendnum, &tcp_relay_node_callback, fr_c, friendcon_id);
454 onion_dht_pk_callback(fr_c->onion_c, onion_friendnum, &dht_pk_callback, fr_c, friendcon_id);
455
456 return friendcon_id;
457}
458
459/* Kill a friend connection.
460 *
461 * return -1 on failure.
462 * return 0 on success.
463 */
464int kill_friend_connection(Friend_Connections *fr_c, int friendcon_id)
465{
466 Friend_Conn *friend_con = get_conn(fr_c, friendcon_id);
467
468 if (!friend_con)
469 return -1;
470
471 if (friend_con->lock_count) {
472 --friend_con->lock_count;
473 return 0;
474 }
475
476 onion_delfriend(fr_c->onion_c, friend_con->onion_friendnum);
477 crypto_kill(fr_c->net_crypto, friend_con->crypt_connection_id);
478
479 if (friend_con->dht_lock) {
480 DHT_delfriend(fr_c->dht, friend_con->dht_temp_pk, friend_con->dht_lock);
481 }
482
483 return wipe_friend_conn(fr_c, friendcon_id);
484}
485
486
487/* Create new friend_connections instance. */
488Friend_Connections *new_friend_connections(Onion_Client *onion_c)
489{
490 if (!onion_c)
491 return NULL;
492
493 Friend_Connections *temp = calloc(1, sizeof(Friend_Connections));
494
495 if (temp == NULL)
496 return NULL;
497
498 temp->dht = onion_c->dht;
499 temp->net_crypto = onion_c->c;
500 temp->onion_c = onion_c;
501
502 new_connection_handler(temp->net_crypto, &handle_new_connections, temp);
503
504 return temp;
505}
506
507/* main friend_connections loop. */
508void do_friend_connections(Friend_Connections *fr_c)
509{
510 uint32_t i;
511 uint64_t temp_time = unix_time();
512
513 for (i = 0; i < fr_c->num_cons; ++i) {
514 Friend_Conn *friend_con = get_conn(fr_c, i);
515
516 if (friend_con) {
517 if (friend_con->status == FRIENDCONN_STATUS_CONNECTING) {
518 if (friend_con->dht_ping_lastrecv + FRIEND_DHT_TIMEOUT < temp_time) {
519 if (friend_con->dht_lock) {
520 DHT_delfriend(fr_c->dht, friend_con->dht_temp_pk, friend_con->dht_lock);
521 friend_con->dht_lock = 0;
522 }
523 }
524
525 if (friend_con->dht_ip_port_lastrecv + FRIEND_DHT_TIMEOUT < temp_time) {
526 friend_con->dht_ip_port.ip.family = 0;
527 }
528
529 if (friend_con->dht_lock) {
530 if (friend_new_connection(fr_c, i) == 0) {
531 set_connection_dht_public_key(fr_c->net_crypto, friend_con->crypt_connection_id, friend_con->dht_temp_pk);
532 set_direct_ip_port(fr_c->net_crypto, friend_con->crypt_connection_id, friend_con->dht_ip_port);
533 }
534 }
535
536 } else if (friend_con->status == FRIENDCONN_STATUS_CONNECTED) {
537 if (friend_con->ping_lastsent + FRIEND_PING_INTERVAL < temp_time) {
538 send_ping(fr_c, i);
539 }
540
541 if (friend_con->ping_lastrecv + FRIEND_CONNECTION_TIMEOUT < temp_time) {
542 /* If we stopped receiving ping packets, kill it. */
543 crypto_kill(fr_c->net_crypto, friend_con->crypt_connection_id);
544 friend_con->crypt_connection_id = -1;
545 handle_status(fr_c, i, 0); /* Going offline. */
546 }
547 }
548 }
549 }
550}
551
552/* Free everything related with friend_connections. */
553void kill_friend_connections(Friend_Connections *fr_c)
554{
555 if (!fr_c)
556 return;
557
558 uint32_t i;
559
560 for (i = 0; i < fr_c->num_cons; ++i) {
561 kill_friend_connection(fr_c, i);
562 }
563
564 free(fr_c);
565}
diff --git a/toxcore/friend_connection.h b/toxcore/friend_connection.h
new file mode 100644
index 00000000..62b82dc2
--- /dev/null
+++ b/toxcore/friend_connection.h
@@ -0,0 +1,140 @@
1/* friend_connection.h
2 *
3 * Connection to friends.
4 *
5 * Copyright (C) 2014 Tox project All Rights Reserved.
6 *
7 * This file is part of Tox.
8 *
9 * Tox is free software: you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation, either version 3 of the License, or
12 * (at your option) any later version.
13 *
14 * Tox is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with Tox. If not, see <http://www.gnu.org/licenses/>.
21 *
22 */
23
24
25#ifndef FRIEND_CONNECTION_H
26#define FRIEND_CONNECTION_H
27
28#include "net_crypto.h"
29#include "DHT.h"
30#include "LAN_discovery.h"
31#include "onion_client.h"
32
33
34#define MAX_FRIEND_CONNECTION_CALLBACKS 2
35#define MESSENGER_CALLBACK_INDEX 0
36#define GROUPCHAT_CALLBACK_INDEX 1
37
38#define PACKET_ID_ALIVE 16
39
40/* Interval between the sending of ping packets. */
41#define FRIEND_PING_INTERVAL 6
42
43/* If no packets are received from friend in this time interval, kill the connection. */
44#define FRIEND_CONNECTION_TIMEOUT (FRIEND_PING_INTERVAL * 3)
45
46/* Time before friend is removed from the DHT after last hearing about him. */
47#define FRIEND_DHT_TIMEOUT BAD_NODE_TIMEOUT
48
49
50enum {
51 FRIENDCONN_STATUS_NONE,
52 FRIENDCONN_STATUS_CONNECTING,
53 FRIENDCONN_STATUS_CONNECTED
54};
55
56typedef struct {
57 uint8_t status;
58
59 uint8_t real_public_key[crypto_box_PUBLICKEYBYTES];
60 uint8_t dht_temp_pk[crypto_box_PUBLICKEYBYTES];
61 uint16_t dht_lock;
62 IP_Port dht_ip_port;
63 uint64_t dht_ping_lastrecv, dht_ip_port_lastrecv;
64
65 int onion_friendnum;
66 int crypt_connection_id;
67
68 uint64_t ping_lastrecv, ping_lastsent;
69
70 struct {
71 int (*status_callback)(void *object, int id, uint8_t status);
72 void *status_callback_object;
73 int status_callback_id;
74
75 int (*data_callback)(void *object, int id, uint8_t *data, uint16_t length);
76 void *data_callback_object;
77 int data_callback_id;
78
79 int (*lossy_data_callback)(void *object, int id, const uint8_t *data, uint16_t length);
80 void *lossy_data_callback_object;
81 int lossy_data_callback_id;
82 } callbacks[MAX_FRIEND_CONNECTION_CALLBACKS];
83
84 uint16_t lock_count;
85} Friend_Conn;
86
87
88typedef struct {
89 Net_Crypto *net_crypto;
90 DHT *dht;
91 Onion_Client *onion_c;
92
93 Friend_Conn *conns;
94 uint32_t num_cons;
95
96} Friend_Connections;
97
98/* Set the callbacks for the friend connection.
99 * index is the index (0 to (MAX_FRIEND_CONNECTION_CALLBACKS - 1)) we want the callback to set in the array.
100 *
101 * return 0 on success.
102 * return -1 on failure
103 */
104int friend_connection_callbacks(Friend_Connections *fr_c, int friendcon_id, unsigned int index,
105 int (*status_callback)(void *object, int id, uint8_t status), int (*data_callback)(void *object, int id, uint8_t *data,
106 uint16_t length), int (*lossy_data_callback)(void *object, int id, const uint8_t *data, uint16_t length), void *object,
107 int number);
108
109/* return the crypt_connection_id for the connection.
110 *
111 * return crypt_connection_id on success.
112 * return -1 on failure.
113 */
114int friend_connection_crypt_connection_id(Friend_Connections *fr_c, int friendcon_id);
115
116/* Create a new friend connection.
117 * If one to that real public key already exists, increase lock count and return it.
118 *
119 * return -1 on failure.
120 * return connection id on success.
121 */
122int new_friend_connection(Friend_Connections *fr_c, const uint8_t *real_public_key);
123
124/* Kill a friend connection.
125 *
126 * return -1 on failure.
127 * return 0 on success.
128 */
129int kill_friend_connection(Friend_Connections *fr_c, int friendcon_id);
130
131/* Create new friend_connections instance. */
132Friend_Connections *new_friend_connections(Onion_Client *onion_c);
133
134/* main friend_connections loop. */
135void do_friend_connections(Friend_Connections *fr_c);
136
137/* Free everything related with friend_connections. */
138void kill_friend_connections(Friend_Connections *fr_c);
139
140#endif