diff options
author | irungentoo <irungentoo@gmail.com> | 2014-09-27 18:25:03 -0400 |
---|---|---|
committer | irungentoo <irungentoo@gmail.com> | 2014-09-27 18:25:03 -0400 |
commit | 6c71bb7e64c557d13e7eea4102f1e0bb41ec172f (patch) | |
tree | 46fe923003f134b1e68fb36881c82a4d9e612f36 | |
parent | 834ffee47dab5a03c0a0f8d08809c377f7b8ef7c (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.h | 2 | ||||
-rw-r--r-- | toxcore/Makefile.inc | 2 | ||||
-rw-r--r-- | toxcore/Messenger.c | 245 | ||||
-rw-r--r-- | toxcore/Messenger.h | 27 | ||||
-rw-r--r-- | toxcore/friend_connection.c | 565 | ||||
-rw-r--r-- | toxcore/friend_connection.h | 140 |
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 | ||
127 | typedef struct { | 127 | typedef 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. */ | 156 | static int handle_status(void *object, int i, uint8_t status); |
157 | static int tcp_relay_node_callback(void *object, uint32_t number, IP_Port ip_port, const uint8_t *public_key) | 157 | static int handle_packet(void *object, int i, uint8_t *temp, uint16_t len); |
158 | { | 158 | static 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 | |||
171 | static int friend_new_connection(Messenger *m, int32_t friendnumber, const uint8_t *real_public_key); | ||
172 | /* Callback for DHT ip_port changes. */ | ||
173 | static 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. */ | ||
190 | static 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 | ||
870 | static 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 | |||
880 | static int send_relays(const Messenger *m, int32_t friendnumber) | 800 | static 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 | ||
1527 | static int handle_custom_lossless_packet(void *object, int friend_num, const uint8_t *packet, uint16_t length) | 1443 | static 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 | ||
1612 | static int handle_status(void *object, int i, uint8_t status); | ||
1613 | static int handle_packet(void *object, int i, uint8_t *temp, uint16_t len); | ||
1614 | |||
1615 | static 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. */ |
1649 | Messenger *new_messenger(Messenger_Options *options) | 1527 | Messenger *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 | ||
2362 | static 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. */ |
2386 | void do_friends(Messenger *m) | 2233 | void 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 | ||
198 | typedef struct { | 188 | typedef 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 | */ | ||
34 | static 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 | */ | ||
54 | static 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 | */ | ||
76 | static 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 | */ | ||
101 | static 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 | |||
122 | static 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 | */ | ||
133 | int 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. */ | ||
150 | static 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 | |||
165 | static int friend_new_connection(Friend_Connections *fr_c, int friendcon_id); | ||
166 | /* Callback for DHT ip_port changes. */ | ||
167 | static 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. */ | ||
185 | static 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 | |||
219 | static 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 | |||
248 | static 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 | |||
275 | static 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 | |||
297 | static 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 | |||
330 | static 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 | |||
355 | static 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 | */ | ||
379 | int 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 | */ | ||
411 | int 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 | */ | ||
427 | int 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 | */ | ||
464 | int 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. */ | ||
488 | Friend_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. */ | ||
508 | void 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. */ | ||
553 | void 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 | |||
50 | enum { | ||
51 | FRIENDCONN_STATUS_NONE, | ||
52 | FRIENDCONN_STATUS_CONNECTING, | ||
53 | FRIENDCONN_STATUS_CONNECTED | ||
54 | }; | ||
55 | |||
56 | typedef 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 | |||
88 | typedef 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 | */ | ||
104 | int 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 | */ | ||
114 | int 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 | */ | ||
122 | int 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 | */ | ||
129 | int kill_friend_connection(Friend_Connections *fr_c, int friendcon_id); | ||
130 | |||
131 | /* Create new friend_connections instance. */ | ||
132 | Friend_Connections *new_friend_connections(Onion_Client *onion_c); | ||
133 | |||
134 | /* main friend_connections loop. */ | ||
135 | void do_friend_connections(Friend_Connections *fr_c); | ||
136 | |||
137 | /* Free everything related with friend_connections. */ | ||
138 | void kill_friend_connections(Friend_Connections *fr_c); | ||
139 | |||
140 | #endif | ||