summaryrefslogtreecommitdiff
path: root/toxcore
diff options
context:
space:
mode:
authorCoren[m] <Break@Ocean>2013-09-16 09:29:08 +0200
committerCoren[m] <Break@Ocean>2013-09-16 09:29:08 +0200
commit57d10f0a805b606c6f2df81879f71de0ed09dd96 (patch)
tree36ad8501efabe2ac85ed2f69aa5f0cd2fc4ffdab /toxcore
parenta341b259b6342962e209f1b50708abe40f1cdad2 (diff)
parent7a69f2de287747eb31e143fd502951dd7d4ab2de (diff)
Merge remote-tracking branch 'upstream/master' into MessengerLoadSave
Conflicts: toxcore/Messenger.c toxcore/util.c toxcore/util.h
Diffstat (limited to 'toxcore')
-rw-r--r--toxcore/DHT.c479
-rw-r--r--toxcore/DHT.h54
-rw-r--r--toxcore/LAN_discovery.c153
-rw-r--r--toxcore/Lossless_UDP.c77
-rw-r--r--toxcore/Lossless_UDP.h6
-rw-r--r--toxcore/Messenger.c181
-rw-r--r--toxcore/Messenger.h2
-rw-r--r--toxcore/friend_requests.c12
-rw-r--r--toxcore/group_chats.c4
-rw-r--r--toxcore/net_crypto.c12
-rw-r--r--toxcore/network.c692
-rw-r--r--toxcore/network.h150
-rw-r--r--toxcore/ping.c10
-rw-r--r--toxcore/tox.c14
-rw-r--r--toxcore/tox.h106
-rw-r--r--toxcore/util.c38
-rw-r--r--toxcore/util.h13
17 files changed, 1705 insertions, 298 deletions
diff --git a/toxcore/DHT.c b/toxcore/DHT.c
index fcd15686..1b2af12c 100644
--- a/toxcore/DHT.c
+++ b/toxcore/DHT.c
@@ -28,8 +28,10 @@
28#endif 28#endif
29 29
30#include "DHT.h" 30#include "DHT.h"
31#include "network.h"
31#include "ping.h" 32#include "ping.h"
32#include "misc_tools.h" 33#include "misc_tools.h"
34#include "util.h"
33 35
34/* The number of seconds for a non responsive node to become bad. */ 36/* The number of seconds for a non responsive node to become bad. */
35#define BAD_NODE_TIMEOUT 70 37#define BAD_NODE_TIMEOUT 70
@@ -115,11 +117,6 @@ static int client_id_cmp(ClientPair p1, ClientPair p2)
115 return c; 117 return c;
116} 118}
117 119
118static int ipport_equal(IP_Port a, IP_Port b)
119{
120 return (a.ip.uint32 == b.ip.uint32) && (a.port == b.port);
121}
122
123static int id_equal(uint8_t *a, uint8_t *b) 120static int id_equal(uint8_t *a, uint8_t *b)
124{ 121{
125 return memcmp(a, b, CLIENT_ID_SIZE) == 0; 122 return memcmp(a, b, CLIENT_ID_SIZE) == 0;
@@ -142,20 +139,23 @@ static int client_in_list(Client_data *list, uint32_t length, uint8_t *client_id
142 uint32_t i; 139 uint32_t i;
143 uint64_t temp_time = unix_time(); 140 uint64_t temp_time = unix_time();
144 141
145 for (i = 0; i < length; ++i) { 142 /* if client_id is in list, find it and maybe overwrite ip_port */
146 /* If ip_port is assigned to a different client_id replace it */ 143 for (i = 0; i < length; ++i)
147 if (ipport_equal(list[i].ip_port, ip_port)) { 144 if (id_equal(list[i].client_id, client_id)) {
148 memcpy(list[i].client_id, client_id, CLIENT_ID_SIZE); 145 /* Refresh the client timestamp. */
146 list[i].timestamp = temp_time;
147 list[i].ip_port = ip_port;
148 return 1;
149 } 149 }
150 150
151 if (id_equal(list[i].client_id, client_id)) { 151 /* client_id not in list yet: find ip_port to overwrite */
152 for (i = 0; i < length; ++i)
153 if (ipport_equal(&list[i].ip_port, &ip_port)) {
152 /* Refresh the client timestamp. */ 154 /* Refresh the client timestamp. */
153 list[i].timestamp = temp_time; 155 list[i].timestamp = temp_time;
154 list[i].ip_port.ip.uint32 = ip_port.ip.uint32; 156 memcpy(list[i].client_id, client_id, CLIENT_ID_SIZE);
155 list[i].ip_port.port = ip_port.port;
156 return 1; 157 return 1;
157 } 158 }
158 }
159 159
160 return 0; 160 return 0;
161} 161}
@@ -192,92 +192,98 @@ static int friend_number(DHT *dht, uint8_t *client_id)
192 return -1; 192 return -1;
193} 193}
194 194
195/* Find MAX_SENT_NODES nodes closest to the client_id for the send nodes request: 195/*
196 * put them in the nodes_list and return how many were found. 196 * helper for get_close_nodes(). argument list is a monster :D
197 *
198 * TODO: For the love of based Allah make this function cleaner and much more efficient.
199 */ 197 */
200static int get_close_nodes(DHT *dht, uint8_t *client_id, Node_format *nodes_list) 198static void get_close_nodes_inner(DHT *dht, uint8_t *client_id, Node_format *nodes_list,
199 sa_family_t sa_family, Client_data *client_list, uint32_t client_list_length,
200 time_t timestamp, int *num_nodes_ptr)
201{ 201{
202 uint32_t i, j, k; 202 int num_nodes = *num_nodes_ptr;
203 uint64_t temp_time = unix_time(); 203 int i, tout, inlist, ipv46x, j, closest;
204 int num_nodes = 0, closest, tout, inlist; 204
205 for (i = 0; i < client_list_length; i++) {
206 Client_data *client = &client_list[i];
207 tout = is_timeout(timestamp, client->timestamp, BAD_NODE_TIMEOUT);
208 inlist = client_in_nodelist(nodes_list, MAX_SENT_NODES, client->client_id);
209
210#ifdef TOX_ENABLE_IPV6
211 IP *client_ip = &client->ip_port.ip;
212
213 /*
214 * Careful: AF_INET isn't seen as AF_INET on dual-stack sockets for
215 * our connections, instead we have to look if it is an embedded
216 * IPv4-in-IPv6 here and convert it down in sendnodes().
217 */
218 sa_family_t ip_treat_as_family = client_ip->family;
219
220 if ((dht->c->lossless_udp->net->family == AF_INET6) &&
221 (client_ip->family == AF_INET6)) {
222 /* socket is AF_INET6, address claims AF_INET6:
223 * check for embedded IPv4-in-IPv6 */
224 if (IN6_IS_ADDR_V4MAPPED(&client_ip->ip6.in6_addr))
225 ip_treat_as_family = AF_INET;
226 }
205 227
206 for (i = 0; i < LCLIENT_LIST; ++i) { 228 ipv46x = !(sa_family == ip_treat_as_family);
207 tout = is_timeout(temp_time, dht->close_clientlist[i].timestamp, BAD_NODE_TIMEOUT); 229#else
208 inlist = client_in_nodelist(nodes_list, MAX_SENT_NODES, dht->close_clientlist[i].client_id); 230 ipv46x = !(sa_family == AF_INET);
231#endif
209 232
210 /* If node isn't good or is already in list. */ 233 /* If node isn't good or is already in list. */
211 if (tout || inlist) 234 if (tout || inlist || ipv46x)
212 continue; 235 continue;
213 236
214 if (num_nodes < MAX_SENT_NODES) { 237 if (num_nodes < MAX_SENT_NODES) {
238 memcpy(nodes_list[num_nodes].client_id,
239 client->client_id,
240 CLIENT_ID_SIZE );
215 241
216 memcpy( nodes_list[num_nodes].client_id, 242 nodes_list[num_nodes].ip_port = client->ip_port;
217 dht->close_clientlist[i].client_id,
218 CLIENT_ID_SIZE );
219
220 nodes_list[num_nodes].ip_port = dht->close_clientlist[i].ip_port;
221 num_nodes++; 243 num_nodes++;
222
223 } else { 244 } else {
224 245 /* see if node_list contains a client_id that's "further away"
246 * compared to the one we're looking at at the moment, if there
247 * is, replace it
248 */
225 for (j = 0; j < MAX_SENT_NODES; ++j) { 249 for (j = 0; j < MAX_SENT_NODES; ++j) {
226 closest = id_closest( client_id, 250 closest = id_closest( client_id,
227 nodes_list[j].client_id, 251 nodes_list[j].client_id,
228 dht->close_clientlist[i].client_id ); 252 client->client_id );
229 253
254 /* second client_id is closer than current: change to it */
230 if (closest == 2) { 255 if (closest == 2) {
231 memcpy( nodes_list[j].client_id, 256 memcpy( nodes_list[j].client_id,
232 dht->close_clientlist[i].client_id, 257 client->client_id,
233 CLIENT_ID_SIZE); 258 CLIENT_ID_SIZE);
234 259
235 nodes_list[j].ip_port = dht->close_clientlist[i].ip_port; 260 nodes_list[j].ip_port = client->ip_port;
236 break; 261 break;
237 } 262 }
238 } 263 }
239 } 264 }
240 } 265 }
241 266
242 for (i = 0; i < dht->num_friends; ++i) { 267 *num_nodes_ptr = num_nodes;
243 for (j = 0; j < MAX_FRIEND_CLIENTS; ++j) { 268}
244
245 tout = is_timeout(temp_time, dht->friends_list[i].client_list[j].timestamp, BAD_NODE_TIMEOUT);
246 inlist = client_in_nodelist( nodes_list,
247 MAX_SENT_NODES,
248 dht->friends_list[i].client_list[j].client_id);
249
250 /* If node isn't good or is already in list. */
251 if (tout || inlist)
252 continue;
253
254 if (num_nodes < MAX_SENT_NODES) {
255
256 memcpy( nodes_list[num_nodes].client_id,
257 dht->friends_list[i].client_list[j].client_id,
258 CLIENT_ID_SIZE);
259
260 nodes_list[num_nodes].ip_port = dht->friends_list[i].client_list[j].ip_port;
261 num_nodes++;
262 } else {
263 for (k = 0; k < MAX_SENT_NODES; ++k) {
264 269
265 closest = id_closest( client_id, 270/* Find MAX_SENT_NODES nodes closest to the client_id for the send nodes request:
266 nodes_list[k].client_id, 271 * put them in the nodes_list and return how many were found.
267 dht->friends_list[i].client_list[j].client_id ); 272 *
273 * TODO: For the love of based <your favorite deity, in doubt use "love"> make
274 * this function cleaner and much more efficient.
275 */
276static int get_close_nodes(DHT *dht, uint8_t *client_id, Node_format *nodes_list, sa_family_t sa_family)
277{
278 time_t timestamp = unix_time();
279 int num_nodes = 0, i;
280 get_close_nodes_inner(dht, client_id, nodes_list, sa_family,
281 dht->close_clientlist, LCLIENT_LIST, timestamp, &num_nodes);
268 282
269 if (closest == 2) { 283 for (i = 0; i < dht->num_friends; ++i)
270 memcpy( nodes_list[k].client_id, 284 get_close_nodes_inner(dht, client_id, nodes_list, sa_family,
271 dht->friends_list[i].client_list[j].client_id, 285 dht->friends_list[i].client_list, MAX_FRIEND_CLIENTS,
272 CLIENT_ID_SIZE ); 286 timestamp, &num_nodes);
273
274 nodes_list[k].ip_port = dht->friends_list[i].client_list[j].ip_port;
275 break;
276 }
277 }
278 }
279 }
280 }
281 287
282 return num_nodes; 288 return num_nodes;
283} 289}
@@ -301,7 +307,7 @@ static int replace_bad( Client_data *list,
301 memcpy(list[i].client_id, client_id, CLIENT_ID_SIZE); 307 memcpy(list[i].client_id, client_id, CLIENT_ID_SIZE);
302 list[i].ip_port = ip_port; 308 list[i].ip_port = ip_port;
303 list[i].timestamp = temp_time; 309 list[i].timestamp = temp_time;
304 list[i].ret_ip_port.ip.uint32 = 0; 310 ip_reset(&list[i].ret_ip_port.ip);
305 list[i].ret_ip_port.port = 0; 311 list[i].ret_ip_port.port = 0;
306 list[i].ret_timestamp = 0; 312 list[i].ret_timestamp = 0;
307 return 0; 313 return 0;
@@ -349,7 +355,7 @@ static int replace_good( Client_data *list,
349 memcpy(list[i].client_id, client_id, CLIENT_ID_SIZE); 355 memcpy(list[i].client_id, client_id, CLIENT_ID_SIZE);
350 list[i].ip_port = ip_port; 356 list[i].ip_port = ip_port;
351 list[i].timestamp = temp_time; 357 list[i].timestamp = temp_time;
352 list[i].ret_ip_port.ip.uint32 = 0; 358 ip_reset(&list[i].ret_ip_port.ip);
353 list[i].ret_ip_port.port = 0; 359 list[i].ret_ip_port.port = 0;
354 list[i].ret_timestamp = 0; 360 list[i].ret_timestamp = 0;
355 return 0; 361 return 0;
@@ -447,13 +453,13 @@ static int is_gettingnodes(DHT *dht, IP_Port ip_port, uint64_t ping_id)
447 if (!is_timeout(temp_time, dht->send_nodes[i].timestamp, PING_TIMEOUT)) { 453 if (!is_timeout(temp_time, dht->send_nodes[i].timestamp, PING_TIMEOUT)) {
448 pinging = 0; 454 pinging = 0;
449 455
450 if (ip_port.ip.uint32 != 0 && ipport_equal(dht->send_nodes[i].ip_port, ip_port)) 456 if (ping_id != 0 && dht->send_nodes[i].ping_id == ping_id)
451 ++pinging; 457 ++pinging;
452 458
453 if (ping_id != 0 && dht->send_nodes[i].ping_id == ping_id) 459 if (ip_isset(&ip_port.ip) && ipport_equal(&dht->send_nodes[i].ip_port, &ip_port))
454 ++pinging; 460 ++pinging;
455 461
456 if (pinging == (ping_id != 0) + (ip_port.ip.uint32 != 0)) 462 if (pinging == (ping_id != 0) + ip_isset(&ip_port.ip))
457 return 1; 463 return 1;
458 } 464 }
459 } 465 }
@@ -518,44 +524,75 @@ static int getnodes(DHT *dht, IP_Port ip_port, uint8_t *public_key, uint8_t *cli
518 memcpy(data + 1 + CLIENT_ID_SIZE, nonce, crypto_box_NONCEBYTES); 524 memcpy(data + 1 + CLIENT_ID_SIZE, nonce, crypto_box_NONCEBYTES);
519 memcpy(data + 1 + CLIENT_ID_SIZE + crypto_box_NONCEBYTES, encrypt, len); 525 memcpy(data + 1 + CLIENT_ID_SIZE + crypto_box_NONCEBYTES, encrypt, len);
520 526
521 return sendpacket(dht->c->lossless_udp->net->sock, ip_port, data, sizeof(data)); 527 return sendpacket(dht->c->lossless_udp->net, ip_port, data, sizeof(data));
522} 528}
523 529
524/* Send a send nodes response. */ 530/* Send a send nodes response. */
531/* because of BINARY compatibility, the Node_format MUST BE Node4_format,
532 * IPv6 nodes are sent in a different message */
525static int sendnodes(DHT *dht, IP_Port ip_port, uint8_t *public_key, uint8_t *client_id, uint64_t ping_id) 533static int sendnodes(DHT *dht, IP_Port ip_port, uint8_t *public_key, uint8_t *client_id, uint64_t ping_id)
526{ 534{
527 /* Check if packet is going to be sent to ourself. */ 535 /* Check if packet is going to be sent to ourself. */
528 if (id_equal(public_key, dht->c->self_public_key)) 536 if (id_equal(public_key, dht->c->self_public_key))
529 return -1; 537 return -1;
530 538
539 size_t Node4_format_size = sizeof(Node4_format);
531 uint8_t data[1 + CLIENT_ID_SIZE + crypto_box_NONCEBYTES + sizeof(ping_id) 540 uint8_t data[1 + CLIENT_ID_SIZE + crypto_box_NONCEBYTES + sizeof(ping_id)
532 + sizeof(Node_format) * MAX_SENT_NODES + ENCRYPTION_PADDING]; 541 + Node4_format_size * MAX_SENT_NODES + ENCRYPTION_PADDING];
533 542
534 Node_format nodes_list[MAX_SENT_NODES]; 543 Node_format nodes_list[MAX_SENT_NODES];
535 int num_nodes = get_close_nodes(dht, client_id, nodes_list); 544 int num_nodes = get_close_nodes(dht, client_id, nodes_list, AF_INET);
536 545
537 if (num_nodes == 0) 546 if (num_nodes == 0)
538 return 0; 547 return 0;
539 548
540 uint8_t plain[sizeof(ping_id) + sizeof(Node_format) * MAX_SENT_NODES]; 549 uint8_t plain[sizeof(ping_id) + Node4_format_size * MAX_SENT_NODES];
541 uint8_t encrypt[sizeof(ping_id) + sizeof(Node_format) * MAX_SENT_NODES + ENCRYPTION_PADDING]; 550 uint8_t encrypt[sizeof(ping_id) + Node4_format_size * MAX_SENT_NODES + ENCRYPTION_PADDING];
542 uint8_t nonce[crypto_box_NONCEBYTES]; 551 uint8_t nonce[crypto_box_NONCEBYTES];
543 new_nonce(nonce); 552 new_nonce(nonce);
544 553
545 memcpy(plain, &ping_id, sizeof(ping_id)); 554 memcpy(plain, &ping_id, sizeof(ping_id));
546 memcpy(plain + sizeof(ping_id), nodes_list, num_nodes * sizeof(Node_format)); 555#ifdef TOX_ENABLE_IPV6
556 Node4_format *nodes4_list = (Node4_format *)(plain + sizeof(ping_id));
557 int i, num_nodes_ok = 0;
558
559 for (i = 0; i < num_nodes; i++) {
560 memcpy(nodes4_list[num_nodes_ok].client_id, nodes_list[i].client_id, CLIENT_ID_SIZE);
561 nodes4_list[num_nodes_ok].ip_port.port = nodes_list[i].ip_port.port;
562
563 IP *node_ip = &nodes_list[i].ip_port.ip;
564
565 if ((node_ip->family == AF_INET6) && IN6_IS_ADDR_V4MAPPED(&node_ip->ip6.in6_addr))
566 /* embedded IPv4-in-IPv6 address: return it in regular sendnodes packet */
567 nodes4_list[num_nodes_ok].ip_port.ip.uint32 = node_ip->ip6.uint32[3];
568 else if (node_ip->family == AF_INET)
569 nodes4_list[num_nodes_ok].ip_port.ip.uint32 = node_ip->ip4.uint32;
570 else /* shouldn't happen */
571 continue;
572
573 num_nodes_ok++;
574 }
575
576 if (num_nodes_ok < num_nodes) {
577 /* shouldn't happen */
578 num_nodes = num_nodes_ok;
579 }
580
581#else
582 memcpy(plain + sizeof(ping_id), nodes_list, num_nodes * Node4_format_size);
583#endif
547 584
548 int len = encrypt_data( public_key, 585 int len = encrypt_data( public_key,
549 dht->c->self_secret_key, 586 dht->c->self_secret_key,
550 nonce, 587 nonce,
551 plain, 588 plain,
552 sizeof(ping_id) + num_nodes * sizeof(Node_format), 589 sizeof(ping_id) + num_nodes * Node4_format_size,
553 encrypt ); 590 encrypt );
554 591
555 if (len == -1) 592 if (len == -1)
556 return -1; 593 return -1;
557 594
558 if ((unsigned int)len != sizeof(ping_id) + num_nodes * sizeof(Node_format) + ENCRYPTION_PADDING) 595 if ((unsigned int)len != sizeof(ping_id) + num_nodes * Node4_format_size + ENCRYPTION_PADDING)
559 return -1; 596 return -1;
560 597
561 data[0] = NET_PACKET_SEND_NODES; 598 data[0] = NET_PACKET_SEND_NODES;
@@ -563,9 +600,57 @@ static int sendnodes(DHT *dht, IP_Port ip_port, uint8_t *public_key, uint8_t *cl
563 memcpy(data + 1 + CLIENT_ID_SIZE, nonce, crypto_box_NONCEBYTES); 600 memcpy(data + 1 + CLIENT_ID_SIZE, nonce, crypto_box_NONCEBYTES);
564 memcpy(data + 1 + CLIENT_ID_SIZE + crypto_box_NONCEBYTES, encrypt, len); 601 memcpy(data + 1 + CLIENT_ID_SIZE + crypto_box_NONCEBYTES, encrypt, len);
565 602
566 return sendpacket(dht->c->lossless_udp->net->sock, ip_port, data, 1 + CLIENT_ID_SIZE + crypto_box_NONCEBYTES + len); 603 return sendpacket(dht->c->lossless_udp->net, ip_port, data, 1 + CLIENT_ID_SIZE + crypto_box_NONCEBYTES + len);
567} 604}
568 605
606#ifdef TOX_ENABLE_IPV6
607/* Send a send nodes response: message for IPv6 nodes */
608static int sendnodes_ipv6(DHT *dht, IP_Port ip_port, uint8_t *public_key, uint8_t *client_id, uint64_t ping_id)
609{
610 /* Check if packet is going to be sent to ourself. */
611 if (id_equal(public_key, dht->c->self_public_key))
612 return -1;
613
614 size_t Node_format_size = sizeof(Node_format);
615 uint8_t data[1 + CLIENT_ID_SIZE + crypto_box_NONCEBYTES + sizeof(ping_id)
616 + Node_format_size * MAX_SENT_NODES + ENCRYPTION_PADDING];
617
618 Node_format nodes_list[MAX_SENT_NODES];
619 int num_nodes = get_close_nodes(dht, client_id, nodes_list, AF_INET6);
620
621 if (num_nodes == 0)
622 return 0;
623
624 uint8_t plain[sizeof(ping_id) + Node_format_size * MAX_SENT_NODES];
625 uint8_t encrypt[sizeof(ping_id) + Node_format_size * MAX_SENT_NODES + ENCRYPTION_PADDING];
626 uint8_t nonce[crypto_box_NONCEBYTES];
627 new_nonce(nonce);
628
629 memcpy(plain, &ping_id, sizeof(ping_id));
630 memcpy(plain + sizeof(ping_id), nodes_list, num_nodes * Node_format_size);
631
632 int len = encrypt_data( public_key,
633 dht->c->self_secret_key,
634 nonce,
635 plain,
636 sizeof(ping_id) + num_nodes * Node_format_size,
637 encrypt );
638
639 if (len == -1)
640 return -1;
641
642 if ((unsigned int)len != sizeof(ping_id) + num_nodes * Node_format_size + ENCRYPTION_PADDING)
643 return -1;
644
645 data[0] = NET_PACKET_SEND_NODES_IPV6;
646 memcpy(data + 1, dht->c->self_public_key, CLIENT_ID_SIZE);
647 memcpy(data + 1 + CLIENT_ID_SIZE, nonce, crypto_box_NONCEBYTES);
648 memcpy(data + 1 + CLIENT_ID_SIZE + crypto_box_NONCEBYTES, encrypt, len);
649
650 return sendpacket(dht->c->lossless_udp->net, ip_port, data, 1 + CLIENT_ID_SIZE + crypto_box_NONCEBYTES + len);
651}
652#endif
653
569static int handle_getnodes(void *object, IP_Port source, uint8_t *packet, uint32_t length) 654static int handle_getnodes(void *object, IP_Port source, uint8_t *packet, uint32_t length)
570{ 655{
571 DHT *dht = object; 656 DHT *dht = object;
@@ -593,6 +678,10 @@ static int handle_getnodes(void *object, IP_Port source, uint8_t *packet, uint32
593 678
594 memcpy(&ping_id, plain, sizeof(ping_id)); 679 memcpy(&ping_id, plain, sizeof(ping_id));
595 sendnodes(dht, source, packet + 1, plain + sizeof(ping_id), ping_id); 680 sendnodes(dht, source, packet + 1, plain + sizeof(ping_id), ping_id);
681#ifdef TOX_ENABLE_IPV6
682 sendnodes_ipv6(dht, source, packet + 1, plain + sizeof(ping_id),
683 ping_id); /* TODO: prevent possible amplification attacks */
684#endif
596 685
597 //send_ping_request(dht, source, packet + 1); /* TODO: make this smarter? */ 686 //send_ping_request(dht, source, packet + 1); /* TODO: make this smarter? */
598 687
@@ -606,22 +695,24 @@ static int handle_sendnodes(void *object, IP_Port source, uint8_t *packet, uint3
606 uint32_t cid_size = 1 + CLIENT_ID_SIZE; 695 uint32_t cid_size = 1 + CLIENT_ID_SIZE;
607 cid_size += crypto_box_NONCEBYTES + sizeof(ping_id) + ENCRYPTION_PADDING; 696 cid_size += crypto_box_NONCEBYTES + sizeof(ping_id) + ENCRYPTION_PADDING;
608 697
609 if (length > (cid_size + sizeof(Node_format) * MAX_SENT_NODES) || 698 size_t Node4_format_size = sizeof(Node4_format);
610 ((length - cid_size) % sizeof(Node_format)) != 0 || 699
611 (length < cid_size + sizeof(Node_format))) 700 if (length > (cid_size + Node4_format_size * MAX_SENT_NODES) ||
701 ((length - cid_size) % Node4_format_size) != 0 ||
702 (length < cid_size + Node4_format_size))
612 return 1; 703 return 1;
613 704
614 uint32_t num_nodes = (length - cid_size) / sizeof(Node_format); 705 uint32_t num_nodes = (length - cid_size) / Node4_format_size;
615 uint8_t plain[sizeof(ping_id) + sizeof(Node_format) * MAX_SENT_NODES]; 706 uint8_t plain[sizeof(ping_id) + Node4_format_size * MAX_SENT_NODES];
616 707
617 int len = decrypt_data( 708 int len = decrypt_data(
618 packet + 1, 709 packet + 1,
619 dht->c->self_secret_key, 710 dht->c->self_secret_key,
620 packet + 1 + CLIENT_ID_SIZE, 711 packet + 1 + CLIENT_ID_SIZE,
621 packet + 1 + CLIENT_ID_SIZE + crypto_box_NONCEBYTES, 712 packet + 1 + CLIENT_ID_SIZE + crypto_box_NONCEBYTES,
622 sizeof(ping_id) + num_nodes * sizeof(Node_format) + ENCRYPTION_PADDING, plain ); 713 sizeof(ping_id) + num_nodes * Node4_format_size + ENCRYPTION_PADDING, plain );
623 714
624 if ((unsigned int)len != sizeof(ping_id) + num_nodes * sizeof(Node_format)) 715 if ((unsigned int)len != sizeof(ping_id) + num_nodes * Node4_format_size)
625 return 1; 716 return 1;
626 717
627 memcpy(&ping_id, plain, sizeof(ping_id)); 718 memcpy(&ping_id, plain, sizeof(ping_id));
@@ -629,12 +720,81 @@ static int handle_sendnodes(void *object, IP_Port source, uint8_t *packet, uint3
629 if (!is_gettingnodes(dht, source, ping_id)) 720 if (!is_gettingnodes(dht, source, ping_id))
630 return 1; 721 return 1;
631 722
723 uint32_t i;
632 Node_format nodes_list[MAX_SENT_NODES]; 724 Node_format nodes_list[MAX_SENT_NODES];
725
726#ifdef TOX_ENABLE_IPV6
727 Node4_format *nodes4_list = (Node4_format *)(plain + sizeof(ping_id));
728
729 int num_nodes_ok = 0;
730
731 for (i = 0; i < num_nodes; i++)
732 if ((nodes4_list[i].ip_port.ip.uint32 != 0) && (nodes4_list[i].ip_port.ip.uint32 != ~0)) {
733 memcpy(nodes_list[num_nodes_ok].client_id, nodes4_list[i].client_id, CLIENT_ID_SIZE);
734 nodes_list[num_nodes_ok].ip_port.ip.family = AF_INET;
735 nodes_list[num_nodes_ok].ip_port.ip.ip4.uint32 = nodes4_list[i].ip_port.ip.uint32;
736 nodes_list[num_nodes_ok].ip_port.port = nodes4_list[i].ip_port.port;
737
738 num_nodes_ok++;
739 }
740
741 if (num_nodes_ok < num_nodes) {
742 /* shouldn't happen */
743 num_nodes = num_nodes_ok;
744 }
745
746#else
633 memcpy(nodes_list, plain + sizeof(ping_id), num_nodes * sizeof(Node_format)); 747 memcpy(nodes_list, plain + sizeof(ping_id), num_nodes * sizeof(Node_format));
748#endif
634 749
635 addto_lists(dht, source, packet + 1); 750 addto_lists(dht, source, packet + 1);
636 751
752 for (i = 0; i < num_nodes; ++i) {
753 send_ping_request(dht->ping, dht->c, nodes_list[i].ip_port, nodes_list[i].client_id);
754 returnedip_ports(dht, nodes_list[i].ip_port, nodes_list[i].client_id, packet + 1);
755 }
756
757 return 0;
758}
759
760#ifdef TOX_ENABLE_IPV6
761static int handle_sendnodes_ipv6(void *object, IP_Port source, uint8_t *packet, uint32_t length)
762{
763 DHT *dht = object;
764 uint64_t ping_id;
765 uint32_t cid_size = 1 + CLIENT_ID_SIZE;
766 cid_size += crypto_box_NONCEBYTES + sizeof(ping_id) + ENCRYPTION_PADDING;
767
768 size_t Node_format_size = sizeof(Node_format);
769
770 if (length > (cid_size + Node_format_size * MAX_SENT_NODES) ||
771 ((length - cid_size) % Node_format_size) != 0 ||
772 (length < cid_size + Node_format_size))
773 return 1;
774
775 uint32_t num_nodes = (length - cid_size) / Node_format_size;
776 uint8_t plain[sizeof(ping_id) + Node_format_size * MAX_SENT_NODES];
777
778 int len = decrypt_data(
779 packet + 1,
780 dht->c->self_secret_key,
781 packet + 1 + CLIENT_ID_SIZE,
782 packet + 1 + CLIENT_ID_SIZE + crypto_box_NONCEBYTES,
783 sizeof(ping_id) + num_nodes * Node_format_size + ENCRYPTION_PADDING, plain );
784
785 if ((unsigned int)len != sizeof(ping_id) + num_nodes * Node_format_size)
786 return 1;
787
788 memcpy(&ping_id, plain, sizeof(ping_id));
789
790 if (!is_gettingnodes(dht, source, ping_id))
791 return 1;
792
637 uint32_t i; 793 uint32_t i;
794 Node_format nodes_list[MAX_SENT_NODES];
795 memcpy(nodes_list, plain + sizeof(ping_id), num_nodes * sizeof(Node_format));
796
797 addto_lists(dht, source, packet + 1);
638 798
639 for (i = 0; i < num_nodes; ++i) { 799 for (i = 0; i < num_nodes; ++i) {
640 send_ping_request(dht->ping, dht->c, nodes_list[i].ip_port, nodes_list[i].client_id); 800 send_ping_request(dht->ping, dht->c, nodes_list[i].ip_port, nodes_list[i].client_id);
@@ -643,10 +803,29 @@ static int handle_sendnodes(void *object, IP_Port source, uint8_t *packet, uint3
643 803
644 return 0; 804 return 0;
645} 805}
806#endif
646 807
647/*----------------------------------------------------------------------------------*/ 808/*----------------------------------------------------------------------------------*/
648/*------------------------END of packet handling functions--------------------------*/ 809/*------------------------END of packet handling functions--------------------------*/
649 810
811/*
812 * Send get nodes requests with client_id to max_num peers in list of length length
813 */
814static void get_bunchnodes(DHT *dht, Client_data *list, uint16_t length, uint16_t max_num, uint8_t *client_id)
815{
816 uint64_t temp_time = unix_time();
817 uint32_t i, num = 0;
818
819 for (i = 0; i < length; ++i)
820 if (ipport_isset(&(list[i].ip_port)) && !is_timeout(temp_time, list[i].ret_timestamp, BAD_NODE_TIMEOUT)) {
821 getnodes(dht, list[i].ip_port, list[i].client_id, client_id);
822 ++num;
823
824 if (num >= max_num)
825 return;
826 }
827}
828
650int DHT_addfriend(DHT *dht, uint8_t *client_id) 829int DHT_addfriend(DHT *dht, uint8_t *client_id)
651{ 830{
652 if (friend_number(dht, client_id) != -1) /* Is friend already in DHT? */ 831 if (friend_number(dht, client_id) != -1) /* Is friend already in DHT? */
@@ -664,6 +843,7 @@ int DHT_addfriend(DHT *dht, uint8_t *client_id)
664 843
665 dht->friends_list[dht->num_friends].NATping_id = ((uint64_t)random_int() << 32) + random_int(); 844 dht->friends_list[dht->num_friends].NATping_id = ((uint64_t)random_int() << 32) + random_int();
666 ++dht->num_friends; 845 ++dht->num_friends;
846 get_bunchnodes(dht, dht->close_clientlist, LCLIENT_LIST, MAX_FRIEND_CLIENTS, client_id);/*TODO: make this better?*/
667 return 0; 847 return 0;
668} 848}
669 849
@@ -703,27 +883,30 @@ int DHT_delfriend(DHT *dht, uint8_t *client_id)
703} 883}
704 884
705/* TODO: Optimize this. */ 885/* TODO: Optimize this. */
706IP_Port DHT_getfriendip(DHT *dht, uint8_t *client_id) 886int DHT_getfriendip(DHT *dht, uint8_t *client_id, IP_Port *ip_port)
707{ 887{
708 uint32_t i, j; 888 uint32_t i, j;
709 uint64_t temp_time = unix_time(); 889 uint64_t temp_time = unix_time();
710 IP_Port empty = {{{{0}}, 0, 0}}; 890
891 ip_reset(&ip_port->ip);
892 ip_port->port = 0;
711 893
712 for (i = 0; i < dht->num_friends; ++i) { 894 for (i = 0; i < dht->num_friends; ++i) {
713 /* Equal */ 895 /* Equal */
714 if (id_equal(dht->friends_list[i].client_id, client_id)) { 896 if (id_equal(dht->friends_list[i].client_id, client_id)) {
715 for (j = 0; j < MAX_FRIEND_CLIENTS; ++j) { 897 for (j = 0; j < MAX_FRIEND_CLIENTS; ++j) {
716 if (id_equal(dht->friends_list[i].client_list[j].client_id, client_id) 898 if (id_equal(dht->friends_list[i].client_list[j].client_id, client_id)
717 && !is_timeout(temp_time, dht->friends_list[i].client_list[j].timestamp, BAD_NODE_TIMEOUT)) 899 && !is_timeout(temp_time, dht->friends_list[i].client_list[j].timestamp, BAD_NODE_TIMEOUT)) {
718 return dht->friends_list[i].client_list[j].ip_port; 900 *ip_port = dht->friends_list[i].client_list[j].ip_port;
901 return 1;
902 }
719 } 903 }
720 904
721 return empty; 905 return 0;
722 } 906 }
723 } 907 }
724 908
725 empty.ip.uint32 = 1; 909 return -1;
726 return empty;
727} 910}
728 911
729/* Ping each client in the "friends" list every PING_INTERVAL seconds. Send a get nodes request 912/* Ping each client in the "friends" list every PING_INTERVAL seconds. Send a get nodes request
@@ -808,6 +991,40 @@ void DHT_bootstrap(DHT *dht, IP_Port ip_port, uint8_t *public_key)
808 getnodes(dht, ip_port, public_key, dht->c->self_public_key); 991 getnodes(dht, ip_port, public_key, dht->c->self_public_key);
809 send_ping_request(dht->ping, dht->c, ip_port, public_key); 992 send_ping_request(dht->ping, dht->c, ip_port, public_key);
810} 993}
994int DHT_bootstrap_from_address(DHT *dht, const char *address, uint8_t ipv6enabled,
995 uint16_t port, uint8_t *public_key)
996{
997 IP_Port ip_port_v64;
998 IP *ip_extra = NULL;
999#ifdef TOX_ENABLE_IPV6
1000 IP_Port ip_port_v4;
1001 ip_init(&ip_port_v64.ip, ipv6enabled);
1002
1003 if (ipv6enabled) {
1004 ip_port_v64.ip.family = AF_UNSPEC;
1005 ip_reset(&ip_port_v4.ip);
1006 ip_extra = &ip_port_v4.ip;
1007 }
1008
1009#else
1010 ip_init(&ip_port_v64.ip, 0);
1011#endif
1012
1013 if (addr_resolve_or_parse_ip(address, &ip_port_v64.ip, ip_extra)) {
1014 ip_port_v64.port = port;
1015 DHT_bootstrap(dht, ip_port_v64, public_key);
1016#ifdef TOX_ENABLE_IPV6
1017
1018 if ((ip_extra != NULL) && ip_isset(ip_extra)) {
1019 ip_port_v4.port = port;
1020 DHT_bootstrap(dht, ip_port_v4, public_key);
1021 }
1022
1023#endif
1024 return 1;
1025 } else
1026 return 0;
1027}
811 1028
812/* Send the given packet to node with client_id 1029/* Send the given packet to node with client_id
813 * 1030 *
@@ -819,7 +1036,7 @@ int route_packet(DHT *dht, uint8_t *client_id, uint8_t *packet, uint32_t length)
819 1036
820 for (i = 0; i < LCLIENT_LIST; ++i) { 1037 for (i = 0; i < LCLIENT_LIST; ++i) {
821 if (id_equal(client_id, dht->close_clientlist[i].client_id)) 1038 if (id_equal(client_id, dht->close_clientlist[i].client_id))
822 return sendpacket(dht->c->lossless_udp->net->sock, dht->close_clientlist[i].ip_port, packet, length); 1039 return sendpacket(dht->c->lossless_udp->net, dht->close_clientlist[i].ip_port, packet, length);
823 } 1040 }
824 1041
825 return -1; 1042 return -1;
@@ -848,7 +1065,7 @@ static int friend_iplist(DHT *dht, IP_Port *ip_portlist, uint16_t friend_num)
848 client = &friend->client_list[i]; 1065 client = &friend->client_list[i];
849 1066
850 /* If ip is not zero and node is good. */ 1067 /* If ip is not zero and node is good. */
851 if (client->ret_ip_port.ip.uint32 != 0 && !is_timeout(temp_time, client->ret_timestamp, BAD_NODE_TIMEOUT)) { 1068 if (ip_isset(&client->ret_ip_port.ip) && !is_timeout(temp_time, client->ret_timestamp, BAD_NODE_TIMEOUT)) {
852 1069
853 if (id_equal(client->client_id, friend->client_id)) 1070 if (id_equal(client->client_id, friend->client_id))
854 return 0; 1071 return 0;
@@ -890,8 +1107,8 @@ int route_tofriend(DHT *dht, uint8_t *friend_id, uint8_t *packet, uint32_t lengt
890 client = &friend->client_list[i]; 1107 client = &friend->client_list[i];
891 1108
892 /* If ip is not zero and node is good. */ 1109 /* If ip is not zero and node is good. */
893 if (client->ret_ip_port.ip.uint32 != 0 && !is_timeout(temp_time, client->ret_timestamp, BAD_NODE_TIMEOUT)) { 1110 if (ip_isset(&client->ret_ip_port.ip) && !is_timeout(temp_time, client->ret_timestamp, BAD_NODE_TIMEOUT)) {
894 int retval = sendpacket(dht->c->lossless_udp->net->sock, client->ip_port, packet, length); 1111 int retval = sendpacket(dht->c->lossless_udp->net, client->ip_port, packet, length);
895 1112
896 if ((unsigned int)retval == length) 1113 if ((unsigned int)retval == length)
897 ++sent; 1114 ++sent;
@@ -924,7 +1141,7 @@ static int routeone_tofriend(DHT *dht, uint8_t *friend_id, uint8_t *packet, uint
924 client = &friend->client_list[i]; 1141 client = &friend->client_list[i];
925 1142
926 /* If ip is not zero and node is good. */ 1143 /* If ip is not zero and node is good. */
927 if (client->ret_ip_port.ip.uint32 != 0 && !is_timeout(temp_time, client->ret_timestamp, BAD_NODE_TIMEOUT)) { 1144 if (ip_isset(&client->ret_ip_port.ip) && !is_timeout(temp_time, client->ret_timestamp, BAD_NODE_TIMEOUT)) {
928 ip_list[n] = client->ip_port; 1145 ip_list[n] = client->ip_port;
929 ++n; 1146 ++n;
930 } 1147 }
@@ -933,7 +1150,7 @@ static int routeone_tofriend(DHT *dht, uint8_t *friend_id, uint8_t *packet, uint
933 if (n < 1) 1150 if (n < 1)
934 return 0; 1151 return 0;
935 1152
936 int retval = sendpacket(dht->c->lossless_udp->net->sock, ip_list[rand() % n], packet, length); 1153 int retval = sendpacket(dht->c->lossless_udp->net, ip_list[rand() % n], packet, length);
937 1154
938 if ((unsigned int)retval == length) 1155 if ((unsigned int)retval == length)
939 return 1; 1156 return 1;
@@ -1032,7 +1249,8 @@ static int handle_NATping(void *object, IP_Port source, uint8_t *source_pubkey,
1032 */ 1249 */
1033static IP NAT_commonip(IP_Port *ip_portlist, uint16_t len, uint16_t min_num) 1250static IP NAT_commonip(IP_Port *ip_portlist, uint16_t len, uint16_t min_num)
1034{ 1251{
1035 IP zero = {{0}}; 1252 IP zero;
1253 ip_reset(&zero);
1036 1254
1037 if (len > MAX_FRIEND_CLIENTS) 1255 if (len > MAX_FRIEND_CLIENTS)
1038 return zero; 1256 return zero;
@@ -1042,7 +1260,7 @@ static IP NAT_commonip(IP_Port *ip_portlist, uint16_t len, uint16_t min_num)
1042 1260
1043 for (i = 0; i < len; ++i) { 1261 for (i = 0; i < len; ++i) {
1044 for (j = 0; j < len; ++j) { 1262 for (j = 0; j < len; ++j) {
1045 if (ip_portlist[i].ip.uint32 == ip_portlist[j].ip.uint32) 1263 if (ip_equal(&ip_portlist[i].ip, &ip_portlist[j].ip))
1046 ++numbers[i]; 1264 ++numbers[i];
1047 } 1265 }
1048 1266
@@ -1065,7 +1283,7 @@ static uint16_t NAT_getports(uint16_t *portlist, IP_Port *ip_portlist, uint16_t
1065 uint16_t num = 0; 1283 uint16_t num = 0;
1066 1284
1067 for (i = 0; i < len; ++i) { 1285 for (i = 0; i < len; ++i) {
1068 if (ip_portlist[i].ip.uint32 == ip.uint32) { 1286 if (ip_equal(&ip_portlist[i].ip, &ip)) {
1069 portlist[num] = ntohs(ip_portlist[i].port); 1287 portlist[num] = ntohs(ip_portlist[i].port);
1070 ++num; 1288 ++num;
1071 } 1289 }
@@ -1085,7 +1303,9 @@ static void punch_holes(DHT *dht, IP ip, uint16_t *port_list, uint16_t numports,
1085 for (i = dht->friends_list[friend_num].punching_index; i != top; i++) { 1303 for (i = dht->friends_list[friend_num].punching_index; i != top; i++) {
1086 /* TODO: Improve port guessing algorithm. */ 1304 /* TODO: Improve port guessing algorithm. */
1087 uint16_t port = port_list[(i / 2) % numports] + (i / (2 * numports)) * ((i % 2) ? -1 : 1); 1305 uint16_t port = port_list[(i / 2) % numports] + (i / (2 * numports)) * ((i % 2) ? -1 : 1);
1088 IP_Port pinging = {{ip, htons(port), 0}}; 1306 IP_Port pinging;
1307 ip_copy(&pinging.ip, &ip);
1308 pinging.port = htons(port);
1089 send_ping_request(dht->ping, dht->c, pinging, dht->friends_list[friend_num].client_id); 1309 send_ping_request(dht->ping, dht->c, pinging, dht->friends_list[friend_num].client_id);
1090 } 1310 }
1091 1311
@@ -1116,7 +1336,7 @@ static void do_NAT(DHT *dht)
1116 1336
1117 IP ip = NAT_commonip(ip_list, num, MAX_FRIEND_CLIENTS / 2); 1337 IP ip = NAT_commonip(ip_list, num, MAX_FRIEND_CLIENTS / 2);
1118 1338
1119 if (ip.uint32 == 0) 1339 if (!ip_isset(&ip))
1120 continue; 1340 continue;
1121 1341
1122 uint16_t port_list[MAX_FRIEND_CLIENTS]; 1342 uint16_t port_list[MAX_FRIEND_CLIENTS];
@@ -1145,16 +1365,15 @@ static void do_NAT(DHT *dht)
1145 */ 1365 */
1146int add_toping(DHT *dht, uint8_t *client_id, IP_Port ip_port) 1366int add_toping(DHT *dht, uint8_t *client_id, IP_Port ip_port)
1147{ 1367{
1148 if (ip_port.ip.uint32 == 0) 1368 if (!ip_isset(&ip_port.ip))
1149 return -1; 1369 return -1;
1150 1370
1151 uint32_t i; 1371 uint32_t i;
1152 1372
1153 for (i = 0; i < MAX_TOPING; ++i) { 1373 for (i = 0; i < MAX_TOPING; ++i) {
1154 if (dht->toping[i].ip_port.ip.uint32 == 0) { 1374 if (!ip_isset(&dht->toping[i].ip_port.ip)) {
1155 memcpy(dht->toping[i].client_id, client_id, CLIENT_ID_SIZE); 1375 memcpy(dht->toping[i].client_id, client_id, CLIENT_ID_SIZE);
1156 dht->toping[i].ip_port.ip.uint32 = ip_port.ip.uint32; 1376 ipport_copy(&dht->toping[i].ip_port, &ip_port);
1157 dht->toping[i].ip_port.port = ip_port.port;
1158 return 0; 1377 return 0;
1159 } 1378 }
1160 } 1379 }
@@ -1162,8 +1381,7 @@ int add_toping(DHT *dht, uint8_t *client_id, IP_Port ip_port)
1162 for (i = 0; i < MAX_TOPING; ++i) { 1381 for (i = 0; i < MAX_TOPING; ++i) {
1163 if (id_closest(dht->c->self_public_key, dht->toping[i].client_id, client_id) == 2) { 1382 if (id_closest(dht->c->self_public_key, dht->toping[i].client_id, client_id) == 2) {
1164 memcpy(dht->toping[i].client_id, client_id, CLIENT_ID_SIZE); 1383 memcpy(dht->toping[i].client_id, client_id, CLIENT_ID_SIZE);
1165 dht->toping[i].ip_port.ip.uint32 = ip_port.ip.uint32; 1384 ipport_copy(&dht->toping[i].ip_port, &ip_port);
1166 dht->toping[i].ip_port.port = ip_port.port;
1167 return 0; 1385 return 0;
1168 } 1386 }
1169 } 1387 }
@@ -1185,11 +1403,11 @@ static void do_toping(DHT *dht)
1185 uint32_t i; 1403 uint32_t i;
1186 1404
1187 for (i = 0; i < MAX_TOPING; ++i) { 1405 for (i = 0; i < MAX_TOPING; ++i) {
1188 if (dht->toping[i].ip_port.ip.uint32 == 0) 1406 if (!ip_isset(&dht->toping[i].ip_port.ip))
1189 return; 1407 return;
1190 1408
1191 send_ping_request(dht->ping, dht->c, dht->toping[i].ip_port, dht->toping[i].client_id); 1409 send_ping_request(dht->ping, dht->c, dht->toping[i].ip_port, dht->toping[i].client_id);
1192 dht->toping[i].ip_port.ip.uint32 = 0; 1410 ip_reset(&dht->toping[i].ip_port.ip);
1193 } 1411 }
1194} 1412}
1195 1413
@@ -1216,6 +1434,9 @@ DHT *new_DHT(Net_Crypto *c)
1216 networking_registerhandler(c->lossless_udp->net, NET_PACKET_PING_RESPONSE, &handle_ping_response, temp); 1434 networking_registerhandler(c->lossless_udp->net, NET_PACKET_PING_RESPONSE, &handle_ping_response, temp);
1217 networking_registerhandler(c->lossless_udp->net, NET_PACKET_GET_NODES, &handle_getnodes, temp); 1435 networking_registerhandler(c->lossless_udp->net, NET_PACKET_GET_NODES, &handle_getnodes, temp);
1218 networking_registerhandler(c->lossless_udp->net, NET_PACKET_SEND_NODES, &handle_sendnodes, temp); 1436 networking_registerhandler(c->lossless_udp->net, NET_PACKET_SEND_NODES, &handle_sendnodes, temp);
1437#ifdef TOX_ENABLE_IPV6
1438 networking_registerhandler(c->lossless_udp->net, NET_PACKET_SEND_NODES_IPV6, &handle_sendnodes_ipv6, temp);
1439#endif
1219 init_cryptopackets(temp); 1440 init_cryptopackets(temp);
1220 cryptopacket_registerhandler(c, CRYPTO_PACKET_NAT_PING, &handle_NATping, temp); 1441 cryptopacket_registerhandler(c, CRYPTO_PACKET_NAT_PING, &handle_NATping, temp);
1221 return temp; 1442 return temp;
@@ -1255,24 +1476,26 @@ void DHT_save_old(DHT *dht, uint8_t *data)
1255 */ 1476 */
1256int DHT_load_old(DHT *dht, uint8_t *data, uint32_t size) 1477int DHT_load_old(DHT *dht, uint8_t *data, uint32_t size)
1257{ 1478{
1258 if (size < sizeof(dht->close_clientlist)) 1479 if (size < sizeof(dht->close_clientlist)) {
1480 fprintf(stderr, "DHT_load: Expected at least %lu bytes, got %u.\n", sizeof(dht->close_clientlist), size);
1259 return -1; 1481 return -1;
1482 }
1483
1484 uint32_t friendlistsize = size - sizeof(dht->close_clientlist);
1260 1485
1261 if ((size - sizeof(dht->close_clientlist)) % sizeof(DHT_Friend) != 0) 1486 if (friendlistsize % sizeof(DHT_Friend) != 0) {
1487 fprintf(stderr, "DHT_load: Expected a multiple of %lu, got %u.\n", sizeof(DHT_Friend), friendlistsize);
1262 return -1; 1488 return -1;
1489 }
1263 1490
1264 uint32_t i, j; 1491 uint32_t i, j;
1265 uint16_t temp;
1266 /* uint64_t temp_time = unix_time(); */
1267
1268 Client_data *client; 1492 Client_data *client;
1493 uint16_t friends_num = friendlistsize / sizeof(DHT_Friend);
1269 1494
1270 temp = (size - sizeof(dht->close_clientlist)) / sizeof(DHT_Friend); 1495 if (friends_num != 0) {
1271
1272 if (temp != 0) {
1273 DHT_Friend *tempfriends_list = (DHT_Friend *)(data + sizeof(dht->close_clientlist)); 1496 DHT_Friend *tempfriends_list = (DHT_Friend *)(data + sizeof(dht->close_clientlist));
1274 1497
1275 for (i = 0; i < temp; ++i) { 1498 for (i = 0; i < friends_num; ++i) {
1276 DHT_addfriend(dht, tempfriends_list[i].client_id); 1499 DHT_addfriend(dht, tempfriends_list[i].client_id);
1277 1500
1278 for (j = 0; j < MAX_FRIEND_CLIENTS; ++j) { 1501 for (j = 0; j < MAX_FRIEND_CLIENTS; ++j) {
diff --git a/toxcore/DHT.h b/toxcore/DHT.h
index ce885163..e6f227f7 100644
--- a/toxcore/DHT.h
+++ b/toxcore/DHT.h
@@ -75,10 +75,22 @@ typedef struct {
75 uint64_t NATping_timestamp; 75 uint64_t NATping_timestamp;
76} DHT_Friend; 76} DHT_Friend;
77 77
78/* this must be kept even if IP_Port is expanded: wire compatibility */
79typedef struct {
80 uint8_t client_id[CLIENT_ID_SIZE];
81 IP4_Port ip_port;
82} Node4_format;
83
78typedef struct { 84typedef struct {
79 uint8_t client_id[CLIENT_ID_SIZE]; 85 uint8_t client_id[CLIENT_ID_SIZE];
80 IP_Port ip_port; 86 IP_Port ip_port;
81} Node_format; 87} Node46_format;
88
89#ifdef TOX_ENABLE_IPV6
90typedef Node46_format Node_format;
91#else
92typedef Node4_format Node_format;
93#endif
82 94
83typedef struct { 95typedef struct {
84 IP_Port ip_port; 96 IP_Port ip_port;
@@ -88,15 +100,15 @@ typedef struct {
88 100
89/*----------------------------------------------------------------------------------*/ 101/*----------------------------------------------------------------------------------*/
90typedef struct { 102typedef struct {
91 Net_Crypto *c; 103 Net_Crypto *c;
92 Client_data close_clientlist[LCLIENT_LIST]; 104 Client_data close_clientlist[LCLIENT_LIST];
93 DHT_Friend *friends_list; 105 DHT_Friend *friends_list;
94 uint16_t num_friends; 106 uint16_t num_friends;
95 Pinged send_nodes[LSEND_NODES_ARRAY]; 107 Pinged send_nodes[LSEND_NODES_ARRAY];
96 Node_format toping[MAX_TOPING]; 108 Node_format toping[MAX_TOPING];
97 uint64_t last_toping; 109 uint64_t last_toping;
98 uint64_t close_lastgetnodes; 110 uint64_t close_lastgetnodes;
99 void *ping; 111 void *ping;
100} DHT; 112} DHT;
101/*----------------------------------------------------------------------------------*/ 113/*----------------------------------------------------------------------------------*/
102 114
@@ -124,19 +136,45 @@ int DHT_delfriend(DHT *dht, uint8_t *client_id);
124 * ip must be 4 bytes long. 136 * ip must be 4 bytes long.
125 * port must be 2 bytes long. 137 * port must be 2 bytes long.
126 * 138 *
139 * !!! Signature changed !!!
140 *
141 * OLD: IP_Port DHT_getfriendip(DHT *dht, uint8_t *client_id);
142 *
127 * return ip if success. 143 * return ip if success.
128 * return ip of 0 if failure (This means the friend is either offline or we have not found him yet). 144 * return ip of 0 if failure (This means the friend is either offline or we have not found him yet).
129 * return ip of 1 if friend is not in list. 145 * return ip of 1 if friend is not in list.
146 *
147 * NEW: int DHT_getfriendip(DHT *dht, uint8_t *client_id, IP_Port *ip_port);
148 *
149 * return -1, -- if client_id does NOT refer to a friend
150 * return 0, -- if client_id refers to a friend and we failed to find the friend (yet)
151 * return 1, ip if client_id refers to a friend and we found him
130 */ 152 */
131IP_Port DHT_getfriendip(DHT *dht, uint8_t *client_id); 153int DHT_getfriendip(DHT *dht, uint8_t *client_id, IP_Port *ip_port);
132 154
133/* Run this function at least a couple times per second (It's the main loop). */ 155/* Run this function at least a couple times per second (It's the main loop). */
134void do_DHT(DHT *dht); 156void do_DHT(DHT *dht);
135 157
136/* Use this function to bootstrap the client. 158/*
137 * Sends a get nodes request to the given node with ip port and public_key. 159 * Use these two functions to bootstrap the client.
160 */
161/* Sends a "get nodes" request to the given node with ip, port and public_key
162 * to setup connections
138 */ 163 */
139void DHT_bootstrap(DHT *dht, IP_Port ip_port, uint8_t *public_key); 164void DHT_bootstrap(DHT *dht, IP_Port ip_port, uint8_t *public_key);
165/* Resolves address into an IP address. If successful, sends a "get nodes"
166 * request to the given node with ip, port and public_key to setup connections
167 *
168 * address can be a hostname or an IP address (IPv4 or IPv6).
169 * if ipv6enabled is 0 (zero), the resolving sticks STRICTLY to IPv4 addresses
170 * if ipv6enabled is not 0 (zero), the resolving looks for IPv6 addresses first,
171 * then IPv4 addresses.
172 *
173 * returns 1 if the address could be converted into an IP address
174 * returns 0 otherwise
175 */
176int DHT_bootstrap_from_address(DHT *dht, const char *address, uint8_t ipv6enabled,
177 uint16_t port, uint8_t *public_key);
140 178
141/* Add nodes to the toping list. 179/* Add nodes to the toping list.
142 * All nodes in this list are pinged every TIME_TOPING seconds 180 * All nodes in this list are pinged every TIME_TOPING seconds
diff --git a/toxcore/LAN_discovery.c b/toxcore/LAN_discovery.c
index 1980cd93..cf4196d2 100644
--- a/toxcore/LAN_discovery.c
+++ b/toxcore/LAN_discovery.c
@@ -30,12 +30,15 @@
30#define MAX_INTERFACES 16 30#define MAX_INTERFACES 16
31 31
32#ifdef __linux 32#ifdef __linux
33#ifndef TOX_ENABLE_IPV6
33/* Send packet to all broadcast addresses 34/* Send packet to all broadcast addresses
34 * 35 *
35 * return higher than 0 on success. 36 * return higher than 0 on success.
36 * return 0 on error. 37 * return 0 on error.
38 *
39 * TODO: Make this work with IPv6 and remove the #ifndef TOX_ENABLE_IPV6.
37 */ 40 */
38static uint32_t send_broadcasts(Networking_Core *net, uint16_t port, uint8_t * data, uint16_t length) 41static uint32_t send_broadcasts(Networking_Core *net, uint16_t port, uint8_t *data, uint16_t length)
39{ 42{
40 /* Not sure how many platforms this will run on, 43 /* Not sure how many platforms this will run on,
41 * so it's wrapped in __linux for now. 44 * so it's wrapped in __linux for now.
@@ -63,28 +66,64 @@ static uint32_t send_broadcasts(Networking_Core *net, uint16_t port, uint8_t * d
63 } 66 }
64 67
65 for (i = 0; i < count; i++) { 68 for (i = 0; i < count; i++) {
66 if (ioctl(sock, SIOCGIFBRDADDR, &i_faces[i]) < 0) { 69 if (ioctl(sock, SIOCGIFBRDADDR, &i_faces[i]) < 0) {
67 return 1; 70 return 1;
68 } 71 }
69 72
70 /* Just to clarify where we're getting the values from. */ 73 /* Just to clarify where we're getting the values from. */
71 sock_holder = (struct sockaddr_in *)&i_faces[i].ifr_broadaddr; 74 sock_holder = (struct sockaddr_in *)&i_faces[i].ifr_broadaddr;
72 if (sock_holder != NULL) { 75
73 IP_Port ip_port = {{{{sock_holder->sin_addr.s_addr}}, port, 0}}; 76 if (sock_holder != NULL) {
74 sendpacket(net->sock, ip_port, data, 1 + crypto_box_PUBLICKEYBYTES); 77 IP_Port ip_port = {{{{sock_holder->sin_addr.s_addr}}, port, 0}};
75 } 78 sendpacket(net, ip_port, data, 1 + crypto_box_PUBLICKEYBYTES);
79 }
76 } 80 }
77 81
78 close(sock); 82 close(sock);
79 return 0; 83 return 0;
80} 84}
81#endif 85#endif
86#endif
82 87
83/* Return the broadcast ip. */ 88/* Return the broadcast ip. */
84static IP broadcast_ip(void) 89static IP broadcast_ip(sa_family_t family_socket, sa_family_t family_broadcast)
85{ 90{
86 IP ip; 91 IP ip;
87 ip.uint32 = ~0; 92 ip_reset(&ip);
93
94#ifdef TOX_ENABLE_IPV6
95
96 if (family_socket == AF_INET6) {
97 if (family_broadcast == AF_INET6) {
98 ip.family = AF_INET6;
99 /* FF02::1 is - according to RFC 4291 - multicast all-nodes link-local */
100 /* FE80::*: MUST be exact, for that we would need to look over all
101 * interfaces and check in which status they are */
102 ip.ip6.uint8[ 0] = 0xFF;
103 ip.ip6.uint8[ 1] = 0x02;
104 ip.ip6.uint8[15] = 0x01;
105 } else if (family_broadcast == AF_INET) {
106 ip.family = AF_INET6;
107 ip.ip6.uint32[0] = 0;
108 ip.ip6.uint32[1] = 0;
109 ip.ip6.uint32[2] = htonl(0xFFFF);
110 ip.ip6.uint32[3] = INADDR_BROADCAST;
111 }
112 } else if (family_socket == AF_INET) {
113 if (family_broadcast == AF_INET) {
114 ip.family = AF_INET;
115 ip.ip4.uint32 = INADDR_BROADCAST;
116 }
117 }
118
119#else
120
121 if (family_socket == AF_INET)
122 if (family_broadcast == AF_INET)
123 ip.uint32 = INADDR_BROADCAST;
124
125#endif
126
88 return ip; 127 return ip;
89} 128}
90 129
@@ -93,21 +132,54 @@ static IP broadcast_ip(void)
93 */ 132 */
94static int LAN_ip(IP ip) 133static int LAN_ip(IP ip)
95{ 134{
96 if (ip.uint8[0] == 127) /* Loopback. */ 135#ifdef TOX_ENABLE_IPV6
97 return 0;
98
99 if (ip.uint8[0] == 10) /* 10.0.0.0 to 10.255.255.255 range. */
100 return 0;
101 136
102 if (ip.uint8[0] == 172 && ip.uint8[1] >= 16 && ip.uint8[1] <= 31) /* 172.16.0.0 to 172.31.255.255 range. */ 137 if (ip.family == AF_INET) {
103 return 0; 138 IP4 ip4 = ip.ip4;
139#else
140 IP4 ip4 = ip;
141#endif
104 142
105 if (ip.uint8[0] == 192 && ip.uint8[1] == 168) /* 192.168.0.0 to 192.168.255.255 range. */ 143 /* Loopback. */
106 return 0; 144 if (ip4.uint8[0] == 127)
145 return 0;
146
147 /* 10.0.0.0 to 10.255.255.255 range. */
148 if (ip4.uint8[0] == 10)
149 return 0;
150
151 /* 172.16.0.0 to 172.31.255.255 range. */
152 if (ip4.uint8[0] == 172 && ip4.uint8[1] >= 16 && ip4.uint8[1] <= 31)
153 return 0;
154
155 /* 192.168.0.0 to 192.168.255.255 range. */
156 if (ip4.uint8[0] == 192 && ip4.uint8[1] == 168)
157 return 0;
158
159 /* 169.254.1.0 to 169.254.254.255 range. */
160 if (ip4.uint8[0] == 169 && ip4.uint8[1] == 254 && ip4.uint8[2] != 0
161 && ip4.uint8[2] != 255)
162 return 0;
163
164#ifdef TOX_ENABLE_IPV6
165 } else if (ip.family == AF_INET6)
166 {
167 /* autogenerated for each interface: FE80::* (up to FEBF::*)
168 FF02::1 is - according to RFC 4291 - multicast all-nodes link-local */
169 if (((ip.ip6.uint8[0] == 0xFF) && (ip.ip6.uint8[1] < 3) && (ip.ip6.uint8[15] == 1)) ||
170 ((ip.ip6.uint8[0] == 0xFE) && ((ip.ip6.uint8[1] & 0xC0) == 0x80)))
171 return 0;
172
173 /* embedded IPv4-in-IPv6 */
174 if (IN6_IS_ADDR_V4MAPPED(&ip.ip6.in6_addr)) {
175 IP ip4;
176 ip4.family = AF_INET;
177 ip4.ip4.uint32 = ip.ip6.uint32[3];
178 return LAN_ip(ip4);
179 }
180 }
107 181
108 if (ip.uint8[0] == 169 && ip.uint8[1] == 254 && ip.uint8[2] != 0 182#endif
109 && ip.uint8[2] != 255)/* 169.254.1.0 to 169.254.254.255 range. */
110 return 0;
111 183
112 return -1; 184 return -1;
113} 185}
@@ -132,11 +204,38 @@ int send_LANdiscovery(uint16_t port, Net_Crypto *c)
132 uint8_t data[crypto_box_PUBLICKEYBYTES + 1]; 204 uint8_t data[crypto_box_PUBLICKEYBYTES + 1];
133 data[0] = NET_PACKET_LAN_DISCOVERY; 205 data[0] = NET_PACKET_LAN_DISCOVERY;
134 memcpy(data + 1, c->self_public_key, crypto_box_PUBLICKEYBYTES); 206 memcpy(data + 1, c->self_public_key, crypto_box_PUBLICKEYBYTES);
207
135#ifdef __linux 208#ifdef __linux
209#ifndef TOX_ENABLE_IPV6
136 send_broadcasts(c->lossless_udp->net, port, data, 1 + crypto_box_PUBLICKEYBYTES); 210 send_broadcasts(c->lossless_udp->net, port, data, 1 + crypto_box_PUBLICKEYBYTES);
137#endif 211#endif
138 IP_Port ip_port = {{broadcast_ip(), port, 0}}; 212#endif
139 return sendpacket(c->lossless_udp->net->sock, ip_port, data, 1 + crypto_box_PUBLICKEYBYTES); 213 int res = -1;
214 IP_Port ip_port;
215 ip_port.port = port;
216
217#ifdef TOX_ENABLE_IPV6
218
219 /* IPv6 multicast */
220 if (c->lossless_udp->net->family == AF_INET6) {
221 ip_port.ip = broadcast_ip(AF_INET6, AF_INET6);
222
223 if (ip_isset(&ip_port.ip))
224 if (sendpacket(c->lossless_udp->net, ip_port, data, 1 + crypto_box_PUBLICKEYBYTES) > 0)
225 res = 1;
226 }
227
228 /* IPv4 broadcast (has to be IPv4-in-IPv6 mapping if socket is AF_INET6 */
229 ip_port.ip = broadcast_ip(c->lossless_udp->net->family, AF_INET);
230#else
231 ip_port.ip = broadcast_ip(AF_INET, AF_INET);
232#endif
233
234 if (ip_isset(&ip_port.ip))
235 if (sendpacket(c->lossless_udp->net, ip_port, data, 1 + crypto_box_PUBLICKEYBYTES))
236 res = 1;
237
238 return res;
140} 239}
141 240
142 241
diff --git a/toxcore/Lossless_UDP.c b/toxcore/Lossless_UDP.c
index fbb473e7..46b0bed1 100644
--- a/toxcore/Lossless_UDP.c
+++ b/toxcore/Lossless_UDP.c
@@ -44,9 +44,7 @@
44int getconnection_id(Lossless_UDP *ludp, IP_Port ip_port) 44int getconnection_id(Lossless_UDP *ludp, IP_Port ip_port)
45{ 45{
46 tox_array_for_each(&ludp->connections, Connection, tmp) { 46 tox_array_for_each(&ludp->connections, Connection, tmp) {
47 if (tmp->ip_port.ip.uint32 == ip_port.ip.uint32 && 47 if (tmp-> status > 0 && ipport_equal(&tmp->ip_port, &ip_port)) {
48 tmp->ip_port.port == ip_port.port &&
49 tmp->status > 0) {
50 return tmp_i; 48 return tmp_i;
51 } 49 }
52 } 50 }
@@ -61,17 +59,53 @@ int getconnection_id(Lossless_UDP *ludp, IP_Port ip_port)
61 * 59 *
62 * TODO: make this better 60 * TODO: make this better
63 */ 61 */
62
63static uint8_t randtable_initget(Lossless_UDP *ludp, uint32_t index, uint8_t value)
64{
65 if (ludp->randtable[index][value] == 0)
66 ludp->randtable[index][value] = random_int();
67
68 return ludp->randtable[index][value];
69}
70
64static uint32_t handshake_id(Lossless_UDP *ludp, IP_Port source) 71static uint32_t handshake_id(Lossless_UDP *ludp, IP_Port source)
65{ 72{
66 uint32_t id = 0, i; 73 uint32_t id = 0, i = 0;
74
75 uint8_t *uint8;
76 uint8 = (uint8_t *)&source.port;
77 id ^= randtable_initget(ludp, i, *uint8);
78 i++, uint8++;
79 id ^= randtable_initget(ludp, i, *uint8);
80 i++;
67 81
68 for (i = 0; i < 6; ++i) { 82#ifdef TOX_ENABLE_IPV6
69 if (ludp->randtable[i][source.uint8[i]] == 0)
70 ludp->randtable[i][source.uint8[i]] = random_int();
71 83
72 id ^= ludp->randtable[i][source.uint8[i]]; 84 if (source.ip.family == AF_INET) {
85 IP4 ip4 = source.ip.ip4;
86#else
87 IP4 ip4 = source.ip;
88#endif
89 int k;
90
91 for (k = 0; k < 4; k++) {
92 id ^= randtable_initget(ludp, i++, ip4.uint8[k]);
93 }
94
95#ifdef TOX_ENABLE_IPV6
73 } 96 }
74 97
98 if (source.ip.family == AF_INET6)
99 {
100 int k;
101
102 for (k = 0; k < 16; k++) {
103 id ^= randtable_initget(ludp, i++, source.ip.ip6.uint8[k]);
104 }
105 }
106
107#endif
108
75 /* id can't be zero. */ 109 /* id can't be zero. */
76 if (id == 0) 110 if (id == 0)
77 id = 1; 111 id = 1;
@@ -86,8 +120,21 @@ static uint32_t handshake_id(Lossless_UDP *ludp, IP_Port source)
86 */ 120 */
87static void change_handshake(Lossless_UDP *ludp, IP_Port source) 121static void change_handshake(Lossless_UDP *ludp, IP_Port source)
88{ 122{
89 uint8_t rand = random_int() % 4; 123#ifdef TOX_ENABLE_IPV6
90 ludp->randtable[rand][((uint8_t *)&source)[rand]] = random_int(); 124 uint8_t rand;
125
126 if (source.ip.family == AF_INET) {
127 rand = 2 + random_int() % 4;
128 } else if (source.ip.family == AF_INET6) {
129 rand = 2 + random_int() % 16;
130 } else {
131 return;
132 }
133
134#else
135 uint8_t rand = 2 + random_int() % 4;
136#endif
137 ludp->randtable[rand][((uint8_t *)&source.ip)[rand]] = random_int();
91} 138}
92 139
93/* 140/*
@@ -290,7 +337,9 @@ IP_Port connection_ip(Lossless_UDP *ludp, int connection_id)
290 if ((unsigned int)connection_id < ludp->connections.len) 337 if ((unsigned int)connection_id < ludp->connections.len)
291 return tox_array_get(&ludp->connections, connection_id, Connection).ip_port; 338 return tox_array_get(&ludp->connections, connection_id, Connection).ip_port;
292 339
293 IP_Port zero = {{{{0}}, 0, 0}}; 340 IP_Port zero;
341 ip_reset(&zero.ip);
342 zero.port = 0;
294 return zero; 343 return zero;
295} 344}
296 345
@@ -429,7 +478,7 @@ static int send_handshake(Lossless_UDP *ludp, IP_Port ip_port, uint32_t handshak
429 temp = htonl(handshake_id2); 478 temp = htonl(handshake_id2);
430 memcpy(packet + 5, &temp, 4); 479 memcpy(packet + 5, &temp, 4);
431 480
432 return sendpacket(ludp->net->sock, ip_port, packet, sizeof(packet)); 481 return sendpacket(ludp->net, ip_port, packet, sizeof(packet));
433} 482}
434 483
435static int send_SYNC(Lossless_UDP *ludp, int connection_id) 484static int send_SYNC(Lossless_UDP *ludp, int connection_id)
@@ -456,7 +505,7 @@ static int send_SYNC(Lossless_UDP *ludp, int connection_id)
456 index += 4; 505 index += 4;
457 memcpy(packet + index, requested, 4 * number); 506 memcpy(packet + index, requested, 4 * number);
458 507
459 return sendpacket(ludp->net->sock, ip_port, packet, (number * 4 + 4 + 4 + 2)); 508 return sendpacket(ludp->net, ip_port, packet, (number * 4 + 4 + 4 + 2));
460 509
461} 510}
462 511
@@ -471,7 +520,7 @@ static int send_data_packet(Lossless_UDP *ludp, int connection_id, uint32_t pack
471 temp = htonl(packet_num); 520 temp = htonl(packet_num);
472 memcpy(packet + 1, &temp, 4); 521 memcpy(packet + 1, &temp, 4);
473 memcpy(packet + 5, connection->sendbuffer[index].data, connection->sendbuffer[index].size); 522 memcpy(packet + 5, connection->sendbuffer[index].data, connection->sendbuffer[index].size);
474 return sendpacket(ludp->net->sock, connection->ip_port, packet, 1 + 4 + connection->sendbuffer[index].size); 523 return sendpacket(ludp->net, connection->ip_port, packet, 1 + 4 + connection->sendbuffer[index].size);
475} 524}
476 525
477/* Sends 1 data packet. */ 526/* Sends 1 data packet. */
diff --git a/toxcore/Lossless_UDP.h b/toxcore/Lossless_UDP.h
index 20471b0a..f0ce0e87 100644
--- a/toxcore/Lossless_UDP.h
+++ b/toxcore/Lossless_UDP.h
@@ -123,7 +123,13 @@ typedef struct {
123 tox_array connections; 123 tox_array connections;
124 124
125 /* Table of random numbers used in handshake_id. */ 125 /* Table of random numbers used in handshake_id. */
126#ifdef TOX_ENABLE_IPV6
127 /* IPv6 (16) + port (2)*/
128 uint32_t randtable[18][256];
129#else
130 /* IPv4 (4) + port (2) */
126 uint32_t randtable[6][256]; 131 uint32_t randtable[6][256];
132#endif
127 133
128} Lossless_UDP; 134} Lossless_UDP;
129 135
diff --git a/toxcore/Messenger.c b/toxcore/Messenger.c
index 2fbb1d3f..5736c4e5 100644
--- a/toxcore/Messenger.c
+++ b/toxcore/Messenger.c
@@ -26,6 +26,7 @@
26#endif 26#endif
27 27
28#include "Messenger.h" 28#include "Messenger.h"
29#include "util.h"
29 30
30#define MIN(a,b) (((a)<(b))?(a):(b)) 31#define MIN(a,b) (((a)<(b))?(a):(b))
31 32
@@ -901,19 +902,17 @@ static void do_allgroupchats(Messenger *m)
901 902
902/*********************************/ 903/*********************************/
903 904
904#define PORT 33445
905
906/* Send a LAN discovery packet every LAN_DISCOVERY_INTERVAL seconds. */ 905/* Send a LAN discovery packet every LAN_DISCOVERY_INTERVAL seconds. */
907static void LANdiscovery(Messenger *m) 906static void LANdiscovery(Messenger *m)
908{ 907{
909 if (m->last_LANdiscovery + LAN_DISCOVERY_INTERVAL < unix_time()) { 908 if (m->last_LANdiscovery + LAN_DISCOVERY_INTERVAL < unix_time()) {
910 send_LANdiscovery(htons(PORT), m->net_crypto); 909 send_LANdiscovery(htons(TOX_PORT_DEFAULT), m->net_crypto);
911 m->last_LANdiscovery = unix_time(); 910 m->last_LANdiscovery = unix_time();
912 } 911 }
913} 912}
914 913
915/* Run this at startup. */ 914/* Run this at startup. */
916Messenger *initMessenger(void) 915Messenger *initMessenger(uint8_t ipv6enabled)
917{ 916{
918 Messenger *m = calloc(1, sizeof(Messenger)); 917 Messenger *m = calloc(1, sizeof(Messenger));
919 918
@@ -921,8 +920,8 @@ Messenger *initMessenger(void)
921 return NULL; 920 return NULL;
922 921
923 IP ip; 922 IP ip;
924 ip.uint32 = 0; 923 ip_init(&ip, ipv6enabled);
925 m->net = new_networking(ip, PORT); 924 m->net = new_networking(ip, TOX_PORT_DEFAULT);
926 925
927 if (m->net == NULL) { 926 if (m->net == NULL) {
928 free(m); 927 free(m);
@@ -1006,11 +1005,12 @@ void doFriends(Messenger *m)
1006 } 1005 }
1007 } 1006 }
1008 1007
1009 IP_Port friendip = DHT_getfriendip(m->dht, m->friendlist[i].client_id); 1008 IP_Port friendip;
1009 int friendok = DHT_getfriendip(m->dht, m->friendlist[i].client_id, &friendip);
1010 1010
1011 switch (is_cryptoconnected(m->net_crypto, m->friendlist[i].crypt_connection_id)) { 1011 switch (is_cryptoconnected(m->net_crypto, m->friendlist[i].crypt_connection_id)) {
1012 case 0: 1012 case 0:
1013 if (friendip.ip.uint32 > 1) 1013 if (friendok == 1)
1014 m->friendlist[i].crypt_connection_id = crypto_connect(m->net_crypto, m->friendlist[i].client_id, friendip); 1014 m->friendlist[i].crypt_connection_id = crypto_connect(m->net_crypto, m->friendlist[i].client_id, friendip);
1015 1015
1016 break; 1016 break;
@@ -1219,6 +1219,22 @@ void doInbound(Messenger *m)
1219 } 1219 }
1220} 1220}
1221 1221
1222#ifdef LOGGING
1223#define DUMPING_CLIENTS_FRIENDS_EVERY_N_SECONDS 60
1224static time_t lastdump = 0;
1225static char IDString[CLIENT_ID_SIZE * 2 + 1];
1226static char *ID2String(uint8_t *client_id)
1227{
1228 uint32_t i;
1229
1230 for (i = 0; i < CLIENT_ID_SIZE; i++)
1231 sprintf(&IDString[i], "%02X", client_id[i]);
1232
1233 IDString[CLIENT_ID_SIZE * 2] = 0;
1234 return IDString;
1235}
1236#endif
1237
1222/* The main loop that needs to be run at least 20 times per second. */ 1238/* The main loop that needs to be run at least 20 times per second. */
1223void doMessenger(Messenger *m) 1239void doMessenger(Messenger *m)
1224{ 1240{
@@ -1230,6 +1246,88 @@ void doMessenger(Messenger *m)
1230 doFriends(m); 1246 doFriends(m);
1231 do_allgroupchats(m); 1247 do_allgroupchats(m);
1232 LANdiscovery(m); 1248 LANdiscovery(m);
1249
1250#ifdef LOGGING
1251
1252 if (now() > lastdump + DUMPING_CLIENTS_FRIENDS_EVERY_N_SECONDS) {
1253 loglog(" = = = = = = = = \n");
1254
1255 lastdump = now();
1256 uint32_t client, last_pinged;
1257
1258 for (client = 0; client < LCLIENT_LIST; client++) {
1259 Client_data *cptr = &m->dht->close_clientlist[client];
1260
1261 if (ip_isset(&cptr->ip_port.ip)) {
1262 last_pinged = lastdump - cptr->last_pinged;
1263
1264 if (last_pinged > 999)
1265 last_pinged = 999;
1266
1267 snprintf(logbuffer, sizeof(logbuffer), "C[%2u] %s:%u [%3u] %s\n",
1268 client, ip_ntoa(&cptr->ip_port.ip), ntohs(cptr->ip_port.port),
1269 last_pinged, ID2String(cptr->client_id));
1270 loglog(logbuffer);
1271 }
1272 }
1273
1274 loglog(" = = = = = = = = \n");
1275
1276 uint32_t num_friends = MIN(m->numfriends, m->dht->num_friends);
1277
1278 if (m->numfriends != m->dht->num_friends) {
1279 sprintf(logbuffer, "Friend num in DHT %u != friend num in msger %u\n",
1280 m->dht->num_friends, m->numfriends);
1281 loglog(logbuffer);
1282 }
1283
1284 uint32_t friend, ping_lastrecv;
1285
1286 for (friend = 0; friend < num_friends; friend++) {
1287 Friend *msgfptr = &m->friendlist[friend];
1288 DHT_Friend *dhtfptr = &m->dht->friends_list[friend];
1289
1290 if (memcmp(msgfptr->client_id, dhtfptr->client_id, CLIENT_ID_SIZE)) {
1291 if (sizeof(logbuffer) > 2 * CLIENT_ID_SIZE + 64) {
1292 sprintf(logbuffer, "F[%2u] ID(m) %s != ID(d) ", friend,
1293 ID2String(msgfptr->client_id));
1294 strcat(logbuffer + strlen(logbuffer), ID2String(dhtfptr->client_id));
1295 strcat(logbuffer + strlen(logbuffer), "\n");
1296 } else
1297 sprintf(logbuffer, "F[%2u] ID(m) != ID(d) ", friend);
1298
1299 loglog(logbuffer);
1300 }
1301
1302 ping_lastrecv = lastdump - msgfptr->ping_lastrecv;
1303
1304 if (ping_lastrecv > 999)
1305 ping_lastrecv = 999;
1306
1307 snprintf(logbuffer, sizeof(logbuffer), "F[%2u] <%s> %02u [%03u] %s\n",
1308 friend, msgfptr->name, msgfptr->crypt_connection_id,
1309 ping_lastrecv, ID2String(msgfptr->client_id));
1310 loglog(logbuffer);
1311
1312 for (client = 0; client < MAX_FRIEND_CLIENTS; client++) {
1313 Client_data *cptr = &dhtfptr->client_list[client];
1314 last_pinged = lastdump - cptr->last_pinged;
1315
1316 if (last_pinged > 999)
1317 last_pinged = 999;
1318
1319 snprintf(logbuffer, sizeof(logbuffer), "F[%2u] => C[%2u] %s:%u [%3u] %s\n",
1320 friend, client, ip_ntoa(&cptr->ip_port.ip),
1321 ntohs(cptr->ip_port.port), last_pinged,
1322 ID2String(cptr->client_id));
1323 loglog(logbuffer);
1324 }
1325 }
1326
1327 loglog(" = = = = = = = = \n");
1328 }
1329
1330#endif
1233} 1331}
1234 1332
1235/* return size of the messenger data (for saving) */ 1333/* return size of the messenger data (for saving) */
@@ -1251,19 +1349,23 @@ static void Messenger_save_old(Messenger *m, uint8_t *data)
1251{ 1349{
1252 save_keys(m->net_crypto, data); 1350 save_keys(m->net_crypto, data);
1253 data += crypto_box_PUBLICKEYBYTES + crypto_box_SECRETKEYBYTES; 1351 data += crypto_box_PUBLICKEYBYTES + crypto_box_SECRETKEYBYTES;
1352
1254 uint32_t nospam = get_nospam(&(m->fr)); 1353 uint32_t nospam = get_nospam(&(m->fr));
1255 memcpy(data, &nospam, sizeof(nospam)); 1354 memcpy(data, &nospam, sizeof(nospam));
1256 data += sizeof(nospam); 1355 data += sizeof(nospam);
1356
1257 uint32_t size = DHT_size(m->dht); 1357 uint32_t size = DHT_size(m->dht);
1258 memcpy(data, &size, sizeof(size)); 1358 memcpy(data, &size, sizeof(size));
1259 data += sizeof(size); 1359 data += sizeof(size);
1260 DHT_save(m->dht, data); 1360 DHT_save(m->dht, data);
1261 data += size; 1361 data += size;
1362
1262 size = sizeof(Friend) * m->numfriends; 1363 size = sizeof(Friend) * m->numfriends;
1263 memcpy(data, &size, sizeof(size)); 1364 memcpy(data, &size, sizeof(size));
1264 data += sizeof(size); 1365 data += sizeof(size);
1265 memcpy(data, m->friendlist, sizeof(Friend) * m->numfriends); 1366 memcpy(data, m->friendlist, sizeof(Friend) * m->numfriends);
1266 data += size; 1367 data += size;
1368
1267 uint16_t small_size = m->name_length; 1369 uint16_t small_size = m->name_length;
1268 memcpy(data, &small_size, sizeof(small_size)); 1370 memcpy(data, &small_size, sizeof(small_size));
1269 data += sizeof(small_size); 1371 data += sizeof(small_size);
@@ -1276,60 +1378,69 @@ static int Messenger_load_old(Messenger *m, uint8_t *data, uint32_t length)
1276 if (length == ~((uint32_t)0)) 1378 if (length == ~((uint32_t)0))
1277 return -1; 1379 return -1;
1278 1380
1279 if (length < crypto_box_PUBLICKEYBYTES + crypto_box_SECRETKEYBYTES + sizeof(uint32_t) * 3) 1381 /* BLOCK1: PUBKEY, SECKEY, NOSPAM, SIZE */
1382 if (length < crypto_box_PUBLICKEYBYTES + crypto_box_SECRETKEYBYTES + sizeof(uint32_t) * 2)
1280 return -1; 1383 return -1;
1281 1384
1282 length -= crypto_box_PUBLICKEYBYTES + crypto_box_SECRETKEYBYTES + sizeof(uint32_t) * 3;
1283 load_keys(m->net_crypto, data); 1385 load_keys(m->net_crypto, data);
1284 data += crypto_box_PUBLICKEYBYTES + crypto_box_SECRETKEYBYTES; 1386 data += crypto_box_PUBLICKEYBYTES + crypto_box_SECRETKEYBYTES;
1387 length -= crypto_box_PUBLICKEYBYTES + crypto_box_SECRETKEYBYTES;
1388
1285 uint32_t nospam; 1389 uint32_t nospam;
1286 memcpy(&nospam, data, sizeof(nospam)); 1390 memcpy(&nospam, data, sizeof(nospam));
1287 set_nospam(&(m->fr), nospam); 1391 set_nospam(&(m->fr), nospam);
1288 data += sizeof(nospam); 1392 data += sizeof(nospam);
1393 length -= sizeof(nospam);
1394
1289 uint32_t size; 1395 uint32_t size;
1290 memcpy(&size, data, sizeof(size)); 1396 memcpy(&size, data, sizeof(size));
1291 data += sizeof(size); 1397 data += sizeof(size);
1398 length -= sizeof(size);
1292 1399
1293 if (length < size) 1400 if (length < size)
1294 return -1; 1401 return -1;
1295 1402
1296 length -= size;
1297
1298 if (DHT_load_old(m->dht, data, size) == -1) 1403 if (DHT_load_old(m->dht, data, size) == -1)
1299 fprintf(stderr, "Data file: Something wicked happened to the stored connections...\n"); 1404 fprintf(stderr, "Data file: Something wicked happened to the stored connections...\n");
1300 /* DO go on, friends/name still might be intact */ 1405 /* DO go on, friends/name still might be intact */
1301 1406
1302 data += size; 1407 data += size;
1303 memcpy(&size, data, sizeof(size)); 1408 length -= size;
1304 data += sizeof(size);
1305 1409
1306 if (length < size || size % sizeof(Friend) != 0) 1410 if (length < sizeof(size))
1307 return -1; 1411 return -1;
1308 1412
1309 Friend *temp = malloc(size); 1413 memcpy(&size, data, sizeof(size));
1310 memcpy(temp, data, size); 1414 data += sizeof(size);
1311 1415 length -= sizeof(size);
1312 uint16_t num = size / sizeof(Friend);
1313 1416
1314 uint32_t i; 1417 if (length < size)
1418 return -1;
1315 1419
1316 for (i = 0; i < num; ++i) { 1420 if (!(size % sizeof(Friend))) {
1317 if (temp[i].status >= 3) { 1421 uint16_t num = size / sizeof(Friend);
1318 int fnum = m_addfriend_norequest(m, temp[i].client_id); 1422 Friend temp[num];
1319 setfriendname(m, fnum, temp[i].name, temp[i].name_length); 1423 memcpy(temp, data, size);
1320 /* set_friend_statusmessage(fnum, temp[i].statusmessage, temp[i].statusmessage_length); */ 1424
1321 } else if (temp[i].status != 0) { 1425 uint32_t i;
1322 /* TODO: This is not a good way to do this. */ 1426
1323 uint8_t address[FRIEND_ADDRESS_SIZE]; 1427 for (i = 0; i < num; ++i) {
1324 memcpy(address, temp[i].client_id, crypto_box_PUBLICKEYBYTES); 1428 if (temp[i].status >= 3) {
1325 memcpy(address + crypto_box_PUBLICKEYBYTES, &(temp[i].friendrequest_nospam), sizeof(uint32_t)); 1429 int fnum = m_addfriend_norequest(m, temp[i].client_id);
1326 uint16_t checksum = address_checksum(address, FRIEND_ADDRESS_SIZE - sizeof(checksum)); 1430 setfriendname(m, fnum, temp[i].name, temp[i].name_length);
1327 memcpy(address + crypto_box_PUBLICKEYBYTES + sizeof(uint32_t), &checksum, sizeof(checksum)); 1431 /* set_friend_statusmessage(fnum, temp[i].statusmessage, temp[i].statusmessage_length); */
1328 m_addfriend(m, address, temp[i].info, temp[i].info_size); 1432 } else if (temp[i].status != 0) {
1433 /* TODO: This is not a good way to do this. */
1434 uint8_t address[FRIEND_ADDRESS_SIZE];
1435 memcpy(address, temp[i].client_id, crypto_box_PUBLICKEYBYTES);
1436 memcpy(address + crypto_box_PUBLICKEYBYTES, &(temp[i].friendrequest_nospam), sizeof(uint32_t));
1437 uint16_t checksum = address_checksum(address, FRIEND_ADDRESS_SIZE - sizeof(checksum));
1438 memcpy(address + crypto_box_PUBLICKEYBYTES + sizeof(uint32_t), &checksum, sizeof(checksum));
1439 m_addfriend(m, address, temp[i].info, temp[i].info_size);
1440 }
1329 } 1441 }
1330 } 1442 }
1331 1443
1332 free(temp);
1333 data += size; 1444 data += size;
1334 length -= size; 1445 length -= size;
1335 1446
diff --git a/toxcore/Messenger.h b/toxcore/Messenger.h
index 0656c736..bfcc69df 100644
--- a/toxcore/Messenger.h
+++ b/toxcore/Messenger.h
@@ -427,7 +427,7 @@ int group_message_send(Messenger *m, int groupnumber, uint8_t *message, uint32_t
427 * return allocated instance of Messenger on success. 427 * return allocated instance of Messenger on success.
428 * return 0 if there are problems. 428 * return 0 if there are problems.
429 */ 429 */
430Messenger *initMessenger(void); 430Messenger *initMessenger(uint8_t ipv6enabled);
431 431
432/* Run this before closing shop 432/* Run this before closing shop
433 * Free all datastructures. 433 * Free all datastructures.
diff --git a/toxcore/friend_requests.c b/toxcore/friend_requests.c
index b01015c4..c821d998 100644
--- a/toxcore/friend_requests.c
+++ b/toxcore/friend_requests.c
@@ -50,18 +50,22 @@ int send_friendrequest(DHT *dht, uint8_t *public_key, uint32_t nospam_num, uint8
50 if (len == -1) 50 if (len == -1)
51 return -1; 51 return -1;
52 52
53 IP_Port ip_port = DHT_getfriendip(dht, public_key); 53 IP_Port ip_port;
54 int friendok = DHT_getfriendip(dht, public_key, &ip_port);
54 55
55 if (ip_port.ip.uint32 == 1) 56 // not a friend
57 if (friendok == -1)
56 return -1; 58 return -1;
57 59
58 if (ip_port.ip.uint32 != 0) { 60 // is a friend and we know how to reach him
59 if (sendpacket(dht->c->lossless_udp->net->sock, ip_port, packet, len) != -1) 61 if (friendok == 1) {
62 if (sendpacket(dht->c->lossless_udp->net, ip_port, packet, len) != -1)
60 return 0; 63 return 0;
61 64
62 return -1; 65 return -1;
63 } 66 }
64 67
68 // is a friend, we DON'T know how to reach him
65 int num = route_tofriend(dht, public_key, packet, len); 69 int num = route_tofriend(dht, public_key, packet, len);
66 70
67 if (num == 0) 71 if (num == 0)
diff --git a/toxcore/group_chats.c b/toxcore/group_chats.c
index 1e5309ad..f37c6a9c 100644
--- a/toxcore/group_chats.c
+++ b/toxcore/group_chats.c
@@ -189,7 +189,7 @@ static int send_groupchatpacket(Group_Chat *chat, IP_Port ip_port, uint8_t *publ
189 if (len == -1) 189 if (len == -1)
190 return -1; 190 return -1;
191 191
192 if (sendpacket(chat->net->sock, ip_port, packet, len) == len) 192 if (sendpacket(chat->net, ip_port, packet, len) == len)
193 return 0; 193 return 0;
194 194
195 return -1; 195 return -1;
@@ -208,7 +208,7 @@ static uint8_t sendto_allpeers(Group_Chat *chat, uint8_t *data, uint16_t length,
208 uint64_t temp_time = unix_time(); 208 uint64_t temp_time = unix_time();
209 209
210 for (i = 0; i < GROUP_CLOSE_CONNECTIONS; ++i) { 210 for (i = 0; i < GROUP_CLOSE_CONNECTIONS; ++i) {
211 if (chat->close[i].ip_port.ip.uint32 != 0 && chat->close[i].last_recv + BAD_NODE_TIMEOUT > temp_time) { 211 if (ip_isset(&chat->close[i].ip_port.ip) && chat->close[i].last_recv + BAD_NODE_TIMEOUT > temp_time) {
212 if (send_groupchatpacket(chat, chat->close[i].ip_port, chat->close[i].client_id, data, length, request_id) == 0) 212 if (send_groupchatpacket(chat, chat->close[i].ip_port, chat->close[i].client_id, data, length, request_id) == 0)
213 ++sent; 213 ++sent;
214 } 214 }
diff --git a/toxcore/net_crypto.c b/toxcore/net_crypto.c
index 8163701e..1de32cb0 100644
--- a/toxcore/net_crypto.c
+++ b/toxcore/net_crypto.c
@@ -451,11 +451,12 @@ int crypto_connect(Net_Crypto *c, uint8_t *public_key, IP_Port ip_port)
451 if (id != -1) { 451 if (id != -1) {
452 IP_Port c_ip = connection_ip(c->lossless_udp, c->crypto_connections[id].number); 452 IP_Port c_ip = connection_ip(c->lossless_udp, c->crypto_connections[id].number);
453 453
454 if (c_ip.ip.uint32 == ip_port.ip.uint32 && c_ip.port == ip_port.port) 454 if (ipport_equal(&c_ip, &ip_port))
455 return -1; 455 return -1;
456 } 456 }
457 457
458 if (realloc_cryptoconnection(c, c->crypto_connections_length + 1) == -1) 458 if (realloc_cryptoconnection(c, c->crypto_connections_length + 1) == -1
459 || c->crypto_connections == NULL)
459 return -1; 460 return -1;
460 461
461 memset(&(c->crypto_connections[c->crypto_connections_length]), 0, sizeof(Crypto_Connection)); 462 memset(&(c->crypto_connections[c->crypto_connections_length]), 0, sizeof(Crypto_Connection));
@@ -578,7 +579,8 @@ int accept_crypto_inbound(Net_Crypto *c, int connection_id, uint8_t *public_key,
578 * return -1; 579 * return -1;
579 * } 580 * }
580 */ 581 */
581 if (realloc_cryptoconnection(c, c->crypto_connections_length + 1) == -1) 582 if (realloc_cryptoconnection(c, c->crypto_connections_length + 1) == -1
583 || c->crypto_connections == NULL)
582 return -1; 584 return -1;
583 585
584 memset(&(c->crypto_connections[c->crypto_connections_length]), 0, sizeof(Crypto_Connection)); 586 memset(&(c->crypto_connections[c->crypto_connections_length]), 0, sizeof(Crypto_Connection));
@@ -778,8 +780,10 @@ Net_Crypto *new_net_crypto(Networking_Core *net)
778 780
779 temp->lossless_udp = new_lossless_udp(net); 781 temp->lossless_udp = new_lossless_udp(net);
780 782
781 if (temp->lossless_udp == NULL) 783 if (temp->lossless_udp == NULL) {
784 free(temp);
782 return NULL; 785 return NULL;
786 }
783 787
784 memset(temp->incoming_connections, -1 , sizeof(int) * MAX_INCOMING); 788 memset(temp->incoming_connections, -1 , sizeof(int) * MAX_INCOMING);
785 return temp; 789 return temp;
diff --git a/toxcore/network.c b/toxcore/network.c
index c6c4965e..4b6dc3be 100644
--- a/toxcore/network.c
+++ b/toxcore/network.c
@@ -26,6 +26,7 @@
26#endif 26#endif
27 27
28#include "network.h" 28#include "network.h"
29#include "util.h"
29 30
30/* return current UNIX time in microseconds (us). */ 31/* return current UNIX time in microseconds (us). */
31uint64_t current_time(void) 32uint64_t current_time(void)
@@ -62,17 +63,83 @@ uint32_t random_int(void)
62#endif 63#endif
63} 64}
64 65
66#ifdef LOGGING
67static void loglogdata(char *message, uint8_t *buffer, size_t buflen, IP_Port *ip_port, ssize_t res);
68#endif
69
65/* Basic network functions: 70/* Basic network functions:
66 * Function to send packet(data) of length length to ip_port. 71 * Function to send packet(data) of length length to ip_port.
67 */ 72 */
68#ifdef WIN32 73int sendpacket(Networking_Core *net, IP_Port ip_port, uint8_t *data, uint32_t length)
69int sendpacket(unsigned int sock, IP_Port ip_port, uint8_t *data, uint32_t length) 74{
75#ifdef TOX_ENABLE_IPV6
76
77 /* socket AF_INET, but target IP NOT: can't send */
78 if ((net->family == AF_INET) && (ip_port.ip.family != AF_INET))
79 return -1;
80
81#endif
82
83 struct sockaddr_storage addr;
84 size_t addrsize = 0;
85
86#ifdef TOX_ENABLE_IPV6
87
88 if (ip_port.ip.family == AF_INET) {
89 if (net->family == AF_INET6) {
90 /* must convert to IPV4-in-IPV6 address */
91 addrsize = sizeof(struct sockaddr_in6);
92 struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)&addr;
93 addr6->sin6_family = AF_INET6;
94 addr6->sin6_port = ip_port.port;
95
96 /* there should be a macro for this in a standards compliant
97 * environment, not found */
98 IP6 ip6;
99
100 ip6.uint32[0] = 0;
101 ip6.uint32[1] = 0;
102 ip6.uint32[2] = htonl(0xFFFF);
103 ip6.uint32[3] = ip_port.ip.ip4.uint32;
104 addr6->sin6_addr = ip6.in6_addr;
105
106 addr6->sin6_flowinfo = 0;
107 addr6->sin6_scope_id = 0;
108 } else {
109 IP4 ip4 = ip_port.ip.ip4;
70#else 110#else
71int sendpacket(int sock, IP_Port ip_port, uint8_t *data, uint32_t length) 111 IP4 ip4 = ip_port.ip;
72#endif 112#endif
73{ 113 addrsize = sizeof(struct sockaddr_in);
74 ADDR addr = {AF_INET, ip_port.port, ip_port.ip, {0}}; 114 struct sockaddr_in *addr4 = (struct sockaddr_in *)&addr;
75 return sendto(sock, (char *) data, length, 0, (struct sockaddr *)&addr, sizeof(addr)); 115 addr4->sin_family = AF_INET;
116 addr4->sin_addr = ip4.in_addr;
117 addr4->sin_port = ip_port.port;
118#ifdef TOX_ENABLE_IPV6
119 }
120 } else if (ip_port.ip.family == AF_INET6)
121 {
122 addrsize = sizeof(struct sockaddr_in6);
123 struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)&addr;
124 addr6->sin6_family = AF_INET6;
125 addr6->sin6_port = ip_port.port;
126 addr6->sin6_addr = ip_port.ip.ip6.in6_addr;
127
128 addr6->sin6_flowinfo = 0;
129 addr6->sin6_scope_id = 0;
130 } else
131 {
132 /* unknown address type*/
133 return -1;
134 }
135
136#endif
137
138 int res = sendto(net->sock, (char *) data, length, 0, (struct sockaddr *)&addr, addrsize);
139#ifdef LOGGING
140 loglogdata("O=>", data, length, &ip_port, res);
141#endif
142 return res;
76} 143}
77 144
78/* Function to receive data 145/* Function to receive data
@@ -81,13 +148,9 @@ int sendpacket(int sock, IP_Port ip_port, uint8_t *data, uint32_t length)
81 * Packet length is put into length. 148 * Packet length is put into length.
82 * Dump all empty packets. 149 * Dump all empty packets.
83 */ 150 */
84#ifdef WIN32 151static int receivepacket(sock_t sock, IP_Port *ip_port, uint8_t *data, uint32_t *length)
85static int receivepacket(unsigned int sock, IP_Port *ip_port, uint8_t *data, uint32_t *length)
86#else
87static int receivepacket(int sock, IP_Port *ip_port, uint8_t *data, uint32_t *length)
88#endif
89{ 152{
90 ADDR addr; 153 struct sockaddr_storage addr;
91#ifdef WIN32 154#ifdef WIN32
92 int addrlen = sizeof(addr); 155 int addrlen = sizeof(addr);
93#else 156#else
@@ -95,11 +158,48 @@ static int receivepacket(int sock, IP_Port *ip_port, uint8_t *data, uint32_t *le
95#endif 158#endif
96 (*(int32_t *)length) = recvfrom(sock, (char *) data, MAX_UDP_PACKET_SIZE, 0, (struct sockaddr *)&addr, &addrlen); 159 (*(int32_t *)length) = recvfrom(sock, (char *) data, MAX_UDP_PACKET_SIZE, 0, (struct sockaddr *)&addr, &addrlen);
97 160
98 if (*(int32_t *)length <= 0) 161 if (*(int32_t *)length <= 0) {
162#ifdef LOGGING
163
164 if ((length < 0) && (errno != EWOULDBLOCK)) {
165 sprintf(logbuffer, "Unexpected error reading from socket: %u, %s\n", errno, strerror(errno));
166 loglog(logbuffer);
167 }
168
169#endif
99 return -1; /* Nothing received or empty packet. */ 170 return -1; /* Nothing received or empty packet. */
171 }
172
173#ifdef TOX_ENABLE_IPV6
174
175 if (addr.ss_family == AF_INET) {
176 struct sockaddr_in *addr_in = (struct sockaddr_in *)&addr;
177 ip_port->ip.family = addr_in->sin_family;
178 ip_port->ip.ip4.in_addr = addr_in->sin_addr;
179 ip_port->port = addr_in->sin_port;
180 } else if (addr.ss_family == AF_INET6) {
181 struct sockaddr_in6 *addr_in6 = (struct sockaddr_in6 *)&addr;
182 ip_port->ip.family = addr_in6->sin6_family;
183 ip_port->ip.ip6.in6_addr = addr_in6->sin6_addr;
184 ip_port->port = addr_in6->sin6_port;
185 } else
186 return -1;
187
188#else
189
190 if (addr.ss_family == AF_INET) {
191 struct sockaddr_in *addr_in = (struct sockaddr_in *)&addr;
192 ip_port->ip.in_addr = addr_in->sin_addr;
193 ip_port->port = addr_in->sin_port;
194 } else
195 return -1;
196
197#endif
198
199#ifdef LOGGING
200 loglogdata("=>O", data, MAX_UDP_PACKET_SIZE, ip_port, *length);
201#endif
100 202
101 ip_port->ip = addr.ip;
102 ip_port->port = addr.port;
103 return 0; 203 return 0;
104} 204}
105 205
@@ -118,13 +218,20 @@ void networking_poll(Networking_Core *net)
118 while (receivepacket(net->sock, &ip_port, data, &length) != -1) { 218 while (receivepacket(net->sock, &ip_port, data, &length) != -1) {
119 if (length < 1) continue; 219 if (length < 1) continue;
120 220
121 if (!(net->packethandlers[data[0]].function)) continue; 221 if (!(net->packethandlers[data[0]].function)) {
222#ifdef LOGGING
223 sprintf(logbuffer, "[%02u] -- Packet has no handler.\n", data[0]);
224 loglog(logbuffer);
225#endif
226 continue;
227 }
122 228
123 net->packethandlers[data[0]].function(net->packethandlers[data[0]].object, ip_port, data, length); 229 net->packethandlers[data[0]].function(net->packethandlers[data[0]].object, ip_port, data, length);
124 } 230 }
125} 231}
126 232
127uint8_t at_startup_ran; 233
234uint8_t at_startup_ran = 0;
128static int at_startup(void) 235static int at_startup(void)
129{ 236{
130 if (at_startup_ran != 0) 237 if (at_startup_ran != 0)
@@ -163,16 +270,34 @@ static void at_shutdown(void)
163 */ 270 */
164Networking_Core *new_networking(IP ip, uint16_t port) 271Networking_Core *new_networking(IP ip, uint16_t port)
165{ 272{
273#ifdef TOX_ENABLE_IPV6
274
275 /* maybe check for invalid IPs like 224+.x.y.z? if there is any IP set ever */
276 if (ip.family != AF_INET && ip.family != AF_INET6) {
277 fprintf(stderr, "Invalid address family: %u\n", ip.family);
278 return NULL;
279 }
280
281#endif
282
166 if (at_startup() != 0) 283 if (at_startup() != 0)
167 return NULL; 284 return NULL;
168 285
169 /* Initialize our socket. */
170 Networking_Core *temp = calloc(1, sizeof(Networking_Core)); 286 Networking_Core *temp = calloc(1, sizeof(Networking_Core));
171 287
172 if (temp == NULL) 288 if (temp == NULL)
173 return NULL; 289 return NULL;
174 290
175 temp->sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); 291#ifdef TOX_ENABLE_IPV6
292 temp->family = ip.family;
293#else
294 temp->family = AF_INET;
295#endif
296 temp->port = 0;
297
298 /* Initialize our socket. */
299 /* add log message what we're creating */
300 temp->sock = socket(temp->family, SOCK_DGRAM, IPPROTO_UDP);
176 301
177 /* Check for socket error. */ 302 /* Check for socket error. */
178#ifdef WIN32 303#ifdef WIN32
@@ -185,6 +310,7 @@ Networking_Core *new_networking(IP ip, uint16_t port)
185#else 310#else
186 311
187 if (temp->sock < 0) { 312 if (temp->sock < 0) {
313 fprintf(stderr, "Failed to get a socket?! %u, %s\n", errno, strerror(errno));
188 free(temp); 314 free(temp);
189 return NULL; 315 return NULL;
190 } 316 }
@@ -205,7 +331,7 @@ Networking_Core *new_networking(IP ip, uint16_t port)
205 return -1; 331 return -1;
206 */ 332 */
207 333
208 /* Enable broadcast on socket. */ 334 /* Enable broadcast on socket */
209 int broadcast = 1; 335 int broadcast = 1;
210 setsockopt(temp->sock, SOL_SOCKET, SO_BROADCAST, (char *)&broadcast, sizeof(broadcast)); 336 setsockopt(temp->sock, SOL_SOCKET, SO_BROADCAST, (char *)&broadcast, sizeof(broadcast));
211 337
@@ -219,10 +345,140 @@ Networking_Core *new_networking(IP ip, uint16_t port)
219 fcntl(temp->sock, F_SETFL, O_NONBLOCK, 1); 345 fcntl(temp->sock, F_SETFL, O_NONBLOCK, 1);
220#endif 346#endif
221 347
222 /* Bind our socket to port PORT and address 0.0.0.0 */ 348#ifdef LOGGING
223 ADDR addr = {AF_INET, htons(port), ip, {0}}; 349 loginit(ntohs(port));
224 bind(temp->sock, (struct sockaddr *)&addr, sizeof(addr)); 350#endif
225 return temp; 351
352 /* Bind our socket to port PORT and the given IP address (usually 0.0.0.0 or ::) */
353 uint16_t *portptr = NULL;
354 struct sockaddr_storage addr;
355 size_t addrsize;
356#ifdef TOX_ENABLE_IPV6
357
358 if (temp->family == AF_INET) {
359 IP4 ip4 = ip.ip4;
360#else
361 IP4 ip4 = ip;
362#endif
363 addrsize = sizeof(struct sockaddr_in);
364 struct sockaddr_in *addr4 = (struct sockaddr_in *)&addr;
365 addr4->sin_family = AF_INET;
366 addr4->sin_port = 0;
367 addr4->sin_addr = ip4.in_addr;
368
369 portptr = &addr4->sin_port;
370#ifdef TOX_ENABLE_IPV6
371 } else if (temp->family == AF_INET6)
372 {
373 addrsize = sizeof(struct sockaddr_in6);
374 struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)&addr;
375 addr6->sin6_family = AF_INET6;
376 addr6->sin6_port = 0;
377 addr6->sin6_addr = ip.ip6.in6_addr;
378
379 addr6->sin6_flowinfo = 0;
380 addr6->sin6_scope_id = 0;
381
382 portptr = &addr6->sin6_port;
383 } else
384 return NULL;
385
386 if (ip.family == AF_INET6)
387 {
388 char ipv6only = 0;
389#ifdef LOGGING
390 int res =
391#endif
392 setsockopt(temp->sock, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&ipv6only, sizeof(ipv6only));
393#ifdef LOGGING
394
395 if (res < 0) {
396 sprintf(logbuffer,
397 "Failed to enable dual-stack on IPv6 socket, won't be able to receive from/send to IPv4 addresses. (%u, %s)\n",
398 errno, strerror(errno));
399 loglog(logbuffer);
400 } else
401 loglog("Embedded IPv4 addresses enabled successfully.\n");
402
403#endif
404
405 /* multicast local nodes */
406 struct ipv6_mreq mreq;
407 memset(&mreq, 0, sizeof(mreq));
408 mreq.ipv6mr_multiaddr.s6_addr[ 0] = 0xFF;
409 mreq.ipv6mr_multiaddr.s6_addr[ 1] = 0x02;
410 mreq.ipv6mr_multiaddr.s6_addr[15] = 0x01;
411 mreq.ipv6mr_interface = 0;
412#ifdef LOGGING
413 res =
414#endif
415 setsockopt(temp->sock, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, &mreq, sizeof(mreq));
416#ifdef LOGGING
417
418 if (res < 0) {
419 sprintf(logbuffer, "Failed to activate local multicast membership. (%u, %s)\n",
420 errno, strerror(errno));
421 loglog(logbuffer);
422 } else
423 loglog("Local multicast group FF02::1 joined successfully.\n");
424
425#endif
426 }
427
428#endif
429
430 /* a hanging program or a different user might block the standard port;
431 * as long as it isn't a parameter coming from the commandline,
432 * try a few ports after it, to see if we can find a "free" one
433 *
434 * if we go on without binding, the first sendto() automatically binds to
435 * a free port chosen by the system (i.e. anything from 1024 to 65535)
436 *
437 * returning NULL after bind fails has both advantages and disadvantages:
438 * advantage:
439 * we can rely on getting the port in the range 33445..33450, which
440 * enables us to tell joe user to open their firewall to a small range
441 *
442 * disadvantage:
443 * some clients might not test return of tox_new(), blindly assuming that
444 * it worked ok (which it did previously without a successful bind)
445 */
446 uint16_t port_to_try = port;
447 *portptr = htons(port_to_try);
448 int tries, res;
449
450 for (tries = TOX_PORTRANGE_FROM; tries <= TOX_PORTRANGE_TO; tries++)
451 {
452 res = bind(temp->sock, (struct sockaddr *)&addr, addrsize);
453
454 if (!res) {
455 temp->port = *portptr;
456#ifdef LOGGING
457 sprintf(logbuffer, "Bound successfully to %s:%u.\n", ip_ntoa(&ip), ntohs(temp->port));
458 loglog(logbuffer);
459#endif
460
461 /* errno isn't reset on success, only set on failure, the failed
462 * binds with parallel clients yield a -EPERM to the outside if
463 * errno isn't cleared here */
464 if (tries > 0)
465 errno = 0;
466
467 return temp;
468 }
469
470 port_to_try++;
471
472 if (port_to_try > TOX_PORTRANGE_TO)
473 port_to_try = TOX_PORTRANGE_FROM;
474
475 *portptr = htons(port_to_try);
476 }
477
478 fprintf(stderr, "Failed to bind socket: %u, %s (IP/Port: %s:%u\n", errno,
479 strerror(errno), ip_ntoa(&ip), port);
480 kill_networking(temp);
481 return NULL;
226} 482}
227 483
228/* Function to cleanup networking stuff. */ 484/* Function to cleanup networking stuff. */
@@ -236,3 +492,391 @@ void kill_networking(Networking_Core *net)
236 free(net); 492 free(net);
237 return; 493 return;
238} 494}
495
496/* ip_equal
497 * compares two IPAny structures
498 * unset means unequal
499 *
500 * returns 0 when not equal or when uninitialized
501 */
502int ip_equal(IP *a, IP *b)
503{
504 if (!a || !b)
505 return 0;
506
507#ifdef TOX_ENABLE_IPV6
508
509 /* same family */
510 if (a->family == b->family) {
511 if (a->family == AF_INET)
512 return (a->ip4.in_addr.s_addr == b->ip4.in_addr.s_addr);
513 else if (a->family == AF_INET6)
514 return IN6_ARE_ADDR_EQUAL(&a->ip6.in6_addr, &b->ip6.in6_addr);
515 else
516 return 0;
517 }
518
519 /* different family: check on the IPv6 one if it is the IPv4 one embedded */
520 if ((a->family == AF_INET) && (b->family == AF_INET6)) {
521 if (IN6_IS_ADDR_V4MAPPED(&b->ip6.in6_addr))
522 return (a->ip4.in_addr.s_addr == b->ip6.uint32[3]);
523 } else if ((a->family == AF_INET6) && (b->family == AF_INET)) {
524 if (IN6_IS_ADDR_V4MAPPED(&a->ip6.in6_addr))
525 return (a->ip6.uint32[3] == b->ip4.in_addr.s_addr);
526 }
527
528 return 0;
529#else
530 return (a->uint32 == b->uint32);
531#endif
532};
533
534/* ipport_equal
535 * compares two IPAny_Port structures
536 * unset means unequal
537 *
538 * returns 0 when not equal or when uninitialized
539 */
540int ipport_equal(IP_Port *a, IP_Port *b)
541{
542 if (!a || !b)
543 return 0;
544
545 if (!a->port || (a->port != b->port))
546 return 0;
547
548 return ip_equal(&a->ip, &b->ip);
549};
550
551/* nulls out ip */
552void ip_reset(IP *ip)
553{
554 if (!ip)
555 return;
556
557#ifdef TOX_ENABLE_IPV6
558 memset(ip, 0, sizeof(IP));
559#else
560 ip->uint32 = 0;
561#endif
562};
563
564/* nulls out ip, sets family according to flag */
565void ip_init(IP *ip, uint8_t ipv6enabled)
566{
567 if (!ip)
568 return;
569
570#ifdef TOX_ENABLE_IPV6
571 memset(ip, 0, sizeof(IP));
572 ip->family = ipv6enabled ? AF_INET6 : AF_INET;
573#else
574 ip->uint32 = 0;
575#endif
576};
577
578/* checks if ip is valid */
579int ip_isset(IP *ip)
580{
581 if (!ip)
582 return 0;
583
584#ifdef TOX_ENABLE_IPV6
585 return (ip->family != 0);
586#else
587 return (ip->uint32 != 0);
588#endif
589};
590
591/* checks if ip is valid */
592int ipport_isset(IP_Port *ipport)
593{
594 if (!ipport)
595 return 0;
596
597 if (!ipport->port)
598 return 0;
599
600 return ip_isset(&ipport->ip);
601};
602
603/* copies an ip structure (careful about direction!) */
604void ip_copy(IP *target, IP *source)
605{
606 if (!source || !target)
607 return;
608
609 memcpy(target, source, sizeof(IP));
610};
611
612/* copies an ip_port structure (careful about direction!) */
613void ipport_copy(IP_Port *target, IP_Port *source)
614{
615 if (!source || !target)
616 return;
617
618 memcpy(target, source, sizeof(IP_Port));
619};
620
621/* ip_ntoa
622 * converts ip into a string
623 * uses a static buffer, so mustn't used multiple times in the same output
624 */
625/* there would be INET6_ADDRSTRLEN, but it might be too short for the error message */
626static char addresstext[96];
627const char *ip_ntoa(IP *ip)
628{
629 if (ip) {
630#ifdef TOX_ENABLE_IPV6
631
632 if (ip->family == AF_INET) {
633 addresstext[0] = 0;
634 struct in_addr *addr = (struct in_addr *)&ip->ip4;
635 inet_ntop(ip->family, addr, addresstext, sizeof(addresstext));
636 } else if (ip->family == AF_INET6) {
637 addresstext[0] = '[';
638 struct in6_addr *addr = (struct in6_addr *)&ip->ip6;
639 inet_ntop(ip->family, addr, &addresstext[1], sizeof(addresstext) - 3);
640 size_t len = strlen(addresstext);
641 addresstext[len] = ']';
642 addresstext[len + 1] = 0;
643 } else
644 snprintf(addresstext, sizeof(addresstext), "(IP invalid, family %u)", ip->family);
645
646#else
647 addresstext[0] = 0;
648 struct in_addr *addr = (struct in_addr *)&ip;
649 inet_ntop(AF_INET, addr, addresstext, sizeof(addresstext));
650#endif
651 } else
652 snprintf(addresstext, sizeof(addresstext), "(IP invalid: NULL)");
653
654 /* brute force protection against lacking termination */
655 addresstext[sizeof(addresstext) - 1] = 0;
656 return addresstext;
657};
658
659/*
660 * addr_parse_ip
661 * directly parses the input into an IP structure
662 * tries IPv4 first, then IPv6
663 *
664 * input
665 * address: dotted notation (IPv4: quad, IPv6: 16) or colon notation (IPv6)
666 *
667 * output
668 * IP: family and the value is set on success
669 *
670 * returns 1 on success, 0 on failure
671 */
672
673int addr_parse_ip(const char *address, IP *to)
674{
675 if (!address || !to)
676 return 0;
677
678#ifdef TOX_ENABLE_IPV6
679 struct in_addr addr4;
680
681 if (1 == inet_pton(AF_INET, address, &addr4)) {
682 to->family = AF_INET;
683 to->ip4.in_addr = addr4;
684 return 1;
685 };
686
687 struct in6_addr addr6;
688
689 if (1 == inet_pton(AF_INET6, address, &addr6)) {
690 to->family = AF_INET6;
691 to->ip6.in6_addr = addr6;
692 return 1;
693 };
694
695#else
696 struct in_addr addr4;
697
698 if (1 == inet_pton(AF_INET, address, &addr4)) {
699 to->in_addr = addr4;
700 return 1;
701 };
702
703#endif
704
705 return 0;
706};
707
708/*
709 * addr_resolve():
710 * uses getaddrinfo to resolve an address into an IP address
711 * uses the first IPv4/IPv6 addresses returned by getaddrinfo
712 *
713 * input
714 * address: a hostname (or something parseable to an IP address)
715 * to: to.family MUST be initialized, either set to a specific IP version
716 * (AF_INET/AF_INET6) or to the unspecified AF_UNSPEC (= 0), if both
717 * IP versions are acceptable
718 * extra can be NULL and is only set in special circumstances, see returns
719 *
720 * returns in *to a valid IPAny (v4/v6),
721 * prefers v6 if ip.family was AF_UNSPEC and both available
722 * returns in *extra an IPv4 address, if family was AF_UNSPEC and *to is AF_INET6
723 * returns 0 on failure
724 */
725
726int addr_resolve(const char *address, IP *to, IP *extra)
727{
728 if (!address || !to)
729 return 0;
730
731 sa_family_t family;
732#ifdef TOX_ENABLE_IPV6
733 family = to->family;
734#else
735 family = AF_INET;
736#endif
737
738 struct addrinfo *server = NULL;
739 struct addrinfo *walker = NULL;
740 struct addrinfo hints;
741 int rc;
742
743 memset(&hints, 0, sizeof(hints));
744 hints.ai_family = family;
745 hints.ai_socktype = SOCK_DGRAM; // type of socket Tox uses.
746
747 if (at_startup() != 0)
748 return 0;
749
750 rc = getaddrinfo(address, NULL, &hints, &server);
751
752 // Lookup failed.
753 if (rc != 0) {
754 return 0;
755 }
756
757#ifdef TOX_ENABLE_IPV6
758 IP4 ip4;
759 memset(&ip4, 0, sizeof(ip4));
760 IP6 ip6;
761 memset(&ip6, 0, sizeof(ip6));
762#endif
763
764 for (walker = server; (walker != NULL) && (rc != 3); walker = walker->ai_next) {
765 switch (walker->ai_family) {
766 case AF_INET:
767 if (walker->ai_family == family) { /* AF_INET requested, done */
768 struct sockaddr_in *addr = (struct sockaddr_in *)walker->ai_addr;
769#ifdef TOX_ENABLE_IPV6
770 to->ip4.in_addr = addr->sin_addr;
771#else
772 to->in_addr = addr->sin_addr;
773#endif
774 rc = 3;
775 }
776
777#ifdef TOX_ENABLE_IPV6
778 else if (!(rc & 1)) { /* AF_UNSPEC requested, store away */
779 struct sockaddr_in *addr = (struct sockaddr_in *)walker->ai_addr;
780 ip4.in_addr = addr->sin_addr;
781 rc |= 1;
782 }
783
784#endif
785 break; /* switch */
786#ifdef TOX_ENABLE_IPV6
787
788 case AF_INET6:
789 if (walker->ai_family == family) { /* AF_INET6 requested, done */
790 if (walker->ai_addrlen == sizeof(struct sockaddr_in6)) {
791 struct sockaddr_in6 *addr = (struct sockaddr_in6 *)walker->ai_addr;
792 to->ip6.in6_addr = addr->sin6_addr;
793 rc = 3;
794 }
795 } else if (!(rc & 2)) { /* AF_UNSPEC requested, store away */
796 if (walker->ai_addrlen == sizeof(struct sockaddr_in6)) {
797 struct sockaddr_in6 *addr = (struct sockaddr_in6 *)walker->ai_addr;
798 ip6.in6_addr = addr->sin6_addr;
799 rc |= 2;
800 }
801 }
802
803 break; /* switch */
804#endif
805 }
806 }
807
808#ifdef TOX_ENABLE_IPV6
809
810 if (to->family == AF_UNSPEC) {
811 if (rc & 2) {
812 to->family = AF_INET6;
813 to->ip6 = ip6;
814
815 if ((rc & 1) && (extra != NULL)) {
816 extra->family = AF_INET;
817 extra->ip4 = ip4;
818 }
819 } else if (rc & 1) {
820 to->family = AF_INET;
821 to->ip4 = ip4;
822 } else
823 rc = 0;
824 }
825
826#endif
827
828
829 freeaddrinfo(server);
830 return rc;
831}
832
833/*
834 * addr_resolve_or_parse_ip
835 * resolves string into an IP address
836 *
837 * address: a hostname (or something parseable to an IP address)
838 * to: to.family MUST be initialized, either set to a specific IP version
839 * (AF_INET/AF_INET6) or to the unspecified AF_UNSPEC (= 0), if both
840 * IP versions are acceptable
841 * extra can be NULL and is only set in special circumstances, see returns
842 *
843 * returns in *tro a matching address (IPv6 or IPv4)
844 * returns in *extra, if not NULL, an IPv4 address, if to->family was AF_UNSPEC
845 * returns 1 on success
846 * returns 0 on failure
847 */
848int addr_resolve_or_parse_ip(const char *address, IP *to, IP *extra)
849{
850 if (!addr_resolve(address, to, extra))
851 if (!addr_parse_ip(address, to))
852 return 0;
853
854 return 1;
855};
856
857#ifdef LOGGING
858static void loglogdata(char *message, uint8_t *buffer, size_t buflen, IP_Port *ip_port, ssize_t res)
859{
860 if (res < 0)
861 snprintf(logbuffer, sizeof(logbuffer), "[%2u] %s %3u%c %s:%u (%u: %s) | %04x%04x\n",
862 buffer[0], message, buflen < 999 ? buflen : 999, 'E',
863 ip_ntoa(&ip_port->ip), ntohs(ip_port->port), errno,
864 strerror(errno), buflen > 4 ? ntohl(*(uint32_t *)&buffer[1]) : 0,
865 buflen > 7 ? ntohl(*(uint32_t *)(&buffer[5])) : 0);
866 else if ((res > 0) && (res <= buflen))
867 snprintf(logbuffer, sizeof(logbuffer), "[%2u] %s %3u%c %s:%u (%u: %s) | %04x%04x\n",
868 buffer[0], message, res < 999 ? res : 999, res < buflen ? '<' : '=',
869 ip_ntoa(&ip_port->ip), ntohs(ip_port->port), 0,
870 "OK", buflen > 4 ? ntohl(*(uint32_t *)&buffer[1]) : 0,
871 buflen > 7 ? ntohl(*(uint32_t *)(&buffer[5])) : 0);
872 else /* empty or overwrite */
873 snprintf(logbuffer, sizeof(logbuffer), "[%2u] %s %u%c%u %s:%u (%u: %s) | %04x%04x\n",
874 buffer[0], message, res, !res ? '0' : '>', buflen,
875 ip_ntoa(&ip_port->ip), ntohs(ip_port->port), 0,
876 "OK", buflen > 4 ? ntohl(*(uint32_t *)&buffer[1]) : 0,
877 buflen > 7 ? ntohl(*(uint32_t *)(&buffer[5])) : 0);
878
879 logbuffer[sizeof(logbuffer) - 1] = 0;
880 loglog(logbuffer);
881}
882#endif
diff --git a/toxcore/network.h b/toxcore/network.h
index e1f9b212..4432baed 100644
--- a/toxcore/network.h
+++ b/toxcore/network.h
@@ -39,17 +39,22 @@
39#include <windows.h> 39#include <windows.h>
40#include <ws2tcpip.h> 40#include <ws2tcpip.h>
41 41
42typedef unsigned int sock_t;
43
42#else // Linux includes 44#else // Linux includes
43 45
44#include <fcntl.h> 46#include <fcntl.h>
45#include <sys/socket.h> 47#include <sys/socket.h>
46#include <netinet/in.h> 48#include <netinet/in.h>
49#include <arpa/inet.h>
47#include <errno.h> 50#include <errno.h>
48#include <sys/time.h> 51#include <sys/time.h>
49#include <sys/types.h> 52#include <sys/types.h>
50#include <netdb.h> 53#include <netdb.h>
51#include <unistd.h> 54#include <unistd.h>
52 55
56typedef int sock_t;
57
53#endif 58#endif
54 59
55#ifndef VANILLA_NACL 60#ifndef VANILLA_NACL
@@ -61,13 +66,20 @@
61#define crypto_box_MACBYTES (crypto_box_ZEROBYTES - crypto_box_BOXZEROBYTES) 66#define crypto_box_MACBYTES (crypto_box_ZEROBYTES - crypto_box_BOXZEROBYTES)
62#endif 67#endif
63 68
69#ifndef IPV6_ADD_MEMBERSHIP
70#ifdef IPV6_JOIN_GROUP
71#define IPV6_ADD_MEMBERSHIP IPV6_JOIN_GROUP
72#define IPV6_DROP_MEMBERSHIP IPV6_LEAVE_GROUP
73#endif
74#endif
64 75
65#define MAX_UDP_PACKET_SIZE 65507 76#define MAX_UDP_PACKET_SIZE 65507
66 77
67#define NET_PACKET_PING_REQUEST 0 /* Ping request packet ID. */ 78#define NET_PACKET_PING_REQUEST 0 /* Ping request packet ID. */
68#define NET_PACKET_PING_RESPONSE 1 /* Ping response packet ID. */ 79#define NET_PACKET_PING_RESPONSE 1 /* Ping response packet ID. */
69#define NET_PACKET_GET_NODES 2 /* Get nodes request packet ID. */ 80#define NET_PACKET_GET_NODES 2 /* Get nodes request packet ID. */
70#define NET_PACKET_SEND_NODES 3 /* Send nodes response packet ID. */ 81#define NET_PACKET_SEND_NODES 3 /* Send nodes response packet ID for IPv4 addresses. */
82#define NET_PACKET_SEND_NODES_IPV6 4 /* Send nodes response packet ID for other addresses. */
71#define NET_PACKET_HANDSHAKE 16 /* Handshake packet ID. */ 83#define NET_PACKET_HANDSHAKE 16 /* Handshake packet ID. */
72#define NET_PACKET_SYNC 17 /* SYNC packet ID. */ 84#define NET_PACKET_SYNC 17 /* SYNC packet ID. */
73#define NET_PACKET_DATA 18 /* Data packet ID. */ 85#define NET_PACKET_DATA 18 /* Data packet ID. */
@@ -75,6 +87,10 @@
75#define NET_PACKET_LAN_DISCOVERY 33 /* LAN discovery packet ID. */ 87#define NET_PACKET_LAN_DISCOVERY 33 /* LAN discovery packet ID. */
76#define NET_PACKET_GROUP_CHATS 48 /* Group chats packet ID. */ 88#define NET_PACKET_GROUP_CHATS 48 /* Group chats packet ID. */
77 89
90#define TOX_PORTRANGE_FROM 33445
91#define TOX_PORTRANGE_TO 33455
92#define TOX_PORT_DEFAULT TOX_PORTRANGE_FROM
93
78/* Current time, unix format */ 94/* Current time, unix format */
79#define unix_time() ((uint64_t)time(NULL)) 95#define unix_time() ((uint64_t)time(NULL))
80 96
@@ -83,27 +99,123 @@ typedef union {
83 uint8_t uint8[4]; 99 uint8_t uint8[4];
84 uint16_t uint16[2]; 100 uint16_t uint16[2];
85 uint32_t uint32; 101 uint32_t uint32;
86} IP; 102 struct in_addr in_addr;
103} IP4;
104
105typedef union {
106 uint8_t uint8[16];
107 uint16_t uint16[8];
108 uint32_t uint32[4];
109 struct in6_addr in6_addr;
110} IP6;
111
112typedef struct {
113 sa_family_t family;
114 union {
115 IP4 ip4;
116 IP6 ip6;
117 };
118} IPAny;
87 119
88typedef union { 120typedef union {
89 struct { 121 struct {
90 IP ip; 122 IP4 ip;
91 uint16_t port; 123 uint16_t port;
92 /* Not used for anything right now. */ 124 /* Not used for anything right now. */
93 uint16_t padding; 125 uint16_t padding;
94 }; 126 };
95 uint8_t uint8[8]; 127 uint8_t uint8[8];
96} IP_Port; 128} IP4_Port;
97 129
130/* will replace IP_Port as soon as the complete infrastructure is in place
131 * removed the unused union and padding also */
98typedef struct { 132typedef struct {
99 int16_t family; 133 IPAny ip;
100 uint16_t port; 134 uint16_t port;
101 IP ip; 135} IPAny_Port;
102 uint8_t zeroes[8]; 136
103#ifdef ENABLE_IPV6 137/* #undef TOX_ENABLE_IPV6 */
104 uint8_t zeroes2[12]; 138#define TOX_ENABLE_IPV6
139#ifdef TOX_ENABLE_IPV6
140#define TOX_ENABLE_IPV6_DEFAULT 1
141typedef IPAny IP;
142typedef IPAny_Port IP_Port;
143#else
144#define TOX_ENABLE_IPV6_DEFAULT 0
145typedef IP4 IP;
146typedef IP4_Port IP_Port;
105#endif 147#endif
106} ADDR; 148
149/* ip_ntoa
150 * converts ip into a string
151 * uses a static buffer, so mustn't used multiple times in the same output
152 */
153const char *ip_ntoa(IP *ip);
154
155/* ip_equal
156 * compares two IPAny structures
157 * unset means unequal
158 *
159 * returns 0 when not equal or when uninitialized
160 */
161int ip_equal(IP *a, IP *b);
162
163/* ipport_equal
164 * compares two IPAny_Port structures
165 * unset means unequal
166 *
167 * returns 0 when not equal or when uninitialized
168 */
169int ipport_equal(IP_Port *a, IP_Port *b);
170
171/* nulls out ip */
172void ip_reset(IP *ip);
173/* nulls out ip, sets family according to flag */
174void ip_init(IP *ip, uint8_t ipv6enabled);
175/* checks if ip is valid */
176int ip_isset(IP *ip);
177/* checks if ip is valid */
178int ipport_isset(IP_Port *ipport);
179/* copies an ip structure */
180void ip_copy(IP *target, IP *source);
181/* copies an ip_port structure */
182void ipport_copy(IP_Port *target, IP_Port *source);
183
184/*
185 * addr_resolve():
186 * uses getaddrinfo to resolve an address into an IP address
187 * uses the first IPv4/IPv6 addresses returned by getaddrinfo
188 *
189 * input
190 * address: a hostname (or something parseable to an IP address)
191 * to: to.family MUST be initialized, either set to a specific IP version
192 * (AF_INET/AF_INET6) or to the unspecified AF_UNSPEC (= 0), if both
193 * IP versions are acceptable
194 * extra can be NULL and is only set in special circumstances, see returns
195 *
196 * returns in *to a valid IPAny (v4/v6),
197 * prefers v6 if ip.family was AF_UNSPEC and both available
198 * returns in *extra an IPv4 address, if family was AF_UNSPEC and *to is AF_INET6
199 * returns 0 on failure
200 */
201int addr_resolve(const char *address, IP *to, IP *extra);
202
203/*
204 * addr_resolve_or_parse_ip
205 * resolves string into an IP address
206 *
207 * address: a hostname (or something parseable to an IP address)
208 * to: to.family MUST be initialized, either set to a specific IP version
209 * (AF_INET/AF_INET6) or to the unspecified AF_UNSPEC (= 0), if both
210 * IP versions are acceptable
211 * extra can be NULL and is only set in special circumstances, see returns
212 *
213 * returns in *tro a matching address (IPv6 or IPv4)
214 * returns in *extra, if not NULL, an IPv4 address, if to->family was AF_UNSPEC
215 * returns 1 on success
216 * returns 0 on failure
217 */
218int addr_resolve_or_parse_ip(const char *address, IP *to, IP *extra);
107 219
108/* Function to receive data, ip and port of sender is put into ip_port. 220/* Function to receive data, ip and port of sender is put into ip_port.
109 * Packet data is put into data. 221 * Packet data is put into data.
@@ -118,13 +230,11 @@ typedef struct {
118 230
119typedef struct { 231typedef struct {
120 Packet_Handles packethandlers[256]; 232 Packet_Handles packethandlers[256];
121 /* Our UDP socket. */
122#ifdef WIN32
123 unsigned int sock;
124#else
125 int sock;
126#endif
127 233
234 /* Our UDP socket. */
235 sa_family_t family;
236 uint16_t port;
237 sock_t sock;
128} Networking_Core; 238} Networking_Core;
129 239
130/* return current time in milleseconds since the epoch. */ 240/* return current time in milleseconds since the epoch. */
@@ -137,12 +247,7 @@ uint32_t random_int(void);
137/* Basic network functions: */ 247/* Basic network functions: */
138 248
139/* Function to send packet(data) of length length to ip_port. */ 249/* Function to send packet(data) of length length to ip_port. */
140#ifdef WIN32 250int sendpacket(Networking_Core *net, IP_Port ip_port, uint8_t *data, uint32_t length);
141int sendpacket(unsigned int sock, IP_Port ip_port, uint8_t *data, uint32_t length);
142#else
143int sendpacket(int sock, IP_Port ip_port, uint8_t *data, uint32_t length);
144#endif
145
146 251
147/* Function to call when packet beginning with byte is received. */ 252/* Function to call when packet beginning with byte is received. */
148void networking_registerhandler(Networking_Core *net, uint8_t byte, packet_handler_callback cb, void *object); 253void networking_registerhandler(Networking_Core *net, uint8_t byte, packet_handler_callback cb, void *object);
@@ -163,5 +268,4 @@ Networking_Core *new_networking(IP ip, uint16_t port);
163/* Function to cleanup networking stuff (doesn't do much right now). */ 268/* Function to cleanup networking stuff (doesn't do much right now). */
164void kill_networking(Networking_Core *net); 269void kill_networking(Networking_Core *net);
165 270
166
167#endif 271#endif
diff --git a/toxcore/ping.c b/toxcore/ping.c
index 3a189f23..56ce2f59 100644
--- a/toxcore/ping.c
+++ b/toxcore/ping.c
@@ -100,7 +100,8 @@ bool is_pinging(void *ping, IP_Port ipp, uint64_t ping_id) // O(n) TODO: Repl
100{ 100{
101 PING *png = ping; 101 PING *png = ping;
102 102
103 if (ipp.ip.uint32 == 0 && ping_id == 0) 103 /* shouldn't that be an OR ? */
104 if (!ip_isset(&ipp.ip) && ping_id == 0)
104 return false; 105 return false;
105 106
106 size_t i, id; 107 size_t i, id;
@@ -111,7 +112,8 @@ bool is_pinging(void *ping, IP_Port ipp, uint64_t ping_id) // O(n) TODO: Repl
111 id = (png->pos_pings + i) % PING_NUM_MAX; 112 id = (png->pos_pings + i) % PING_NUM_MAX;
112 113
113 /* ping_id = 0 means match any id. */ 114 /* ping_id = 0 means match any id. */
114 if ((ipp_eq(png->pings[id].ipp, ipp) || ipp.ip.uint32 == 0) && (png->pings[id].id == ping_id || ping_id == 0)) { 115 if ((!ip_isset(&ipp.ip) || ipport_equal(&png->pings[id].ipp, &ipp)) &&
116 (png->pings[id].id == ping_id || ping_id == 0)) {
115 return true; 117 return true;
116 } 118 }
117 } 119 }
@@ -147,7 +149,7 @@ int send_ping_request(void *ping, Net_Crypto *c, IP_Port ipp, uint8_t *client_id
147 if (rc != sizeof(ping_id) + ENCRYPTION_PADDING) 149 if (rc != sizeof(ping_id) + ENCRYPTION_PADDING)
148 return 1; 150 return 1;
149 151
150 return sendpacket(c->lossless_udp->net->sock, ipp, pk, sizeof(pk)); 152 return sendpacket(c->lossless_udp->net, ipp, pk, sizeof(pk));
151} 153}
152 154
153int send_ping_response(Net_Crypto *c, IP_Port ipp, uint8_t *client_id, uint64_t ping_id) 155int send_ping_response(Net_Crypto *c, IP_Port ipp, uint8_t *client_id, uint64_t ping_id)
@@ -172,7 +174,7 @@ int send_ping_response(Net_Crypto *c, IP_Port ipp, uint8_t *client_id, uint64_t
172 if (rc != sizeof(ping_id) + ENCRYPTION_PADDING) 174 if (rc != sizeof(ping_id) + ENCRYPTION_PADDING)
173 return 1; 175 return 1;
174 176
175 return sendpacket(c->lossless_udp->net->sock, ipp, pk, sizeof(pk)); 177 return sendpacket(c->lossless_udp->net, ipp, pk, sizeof(pk));
176} 178}
177 179
178int handle_ping_request(void *object, IP_Port source, uint8_t *packet, uint32_t length) 180int handle_ping_request(void *object, IP_Port source, uint8_t *packet, uint32_t length)
diff --git a/toxcore/tox.c b/toxcore/tox.c
index 417f1af3..80d64626 100644
--- a/toxcore/tox.c
+++ b/toxcore/tox.c
@@ -441,14 +441,20 @@ int tox_group_message_send(void *tox, int groupnumber, uint8_t *message, uint32_
441 441
442/******************END OF GROUP CHAT FUNCTIONS************************/ 442/******************END OF GROUP CHAT FUNCTIONS************************/
443 443
444/* Use this function to bootstrap the client. 444/* Use these functions to bootstrap the client.
445 * Sends a get nodes request to the given node with ip port and public_key. 445 * Sends a get nodes request to the given node with ip port and public_key.
446 */ 446 */
447void tox_bootstrap(void *tox, IP_Port ip_port, uint8_t *public_key) 447void tox_bootstrap_from_ip(void *tox, IP_Port ip_port, uint8_t *public_key)
448{ 448{
449 Messenger *m = tox; 449 Messenger *m = tox;
450 DHT_bootstrap(m->dht, ip_port, public_key); 450 DHT_bootstrap(m->dht, ip_port, public_key);
451} 451}
452int tox_bootstrap_from_address(void *tox, const char *address,
453 uint8_t ipv6enabled, uint16_t port, uint8_t *public_key)
454{
455 Messenger *m = tox;
456 return DHT_bootstrap_from_address(m->dht, address, ipv6enabled, port, public_key);
457};
452 458
453/* return 0 if we are not connected to the DHT. 459/* return 0 if we are not connected to the DHT.
454 * return 1 if we are. 460 * return 1 if we are.
@@ -464,9 +470,9 @@ int tox_isconnected(void *tox)
464 * return allocated instance of tox on success. 470 * return allocated instance of tox on success.
465 * return 0 if there are problems. 471 * return 0 if there are problems.
466 */ 472 */
467void *tox_new(void) 473void *tox_new(uint8_t ipv6enabled)
468{ 474{
469 return initMessenger(); 475 return initMessenger(ipv6enabled);
470} 476}
471 477
472/* Run this before closing shop. 478/* Run this before closing shop.
diff --git a/toxcore/tox.h b/toxcore/tox.h
index 6d5db49f..89242f1f 100644
--- a/toxcore/tox.h
+++ b/toxcore/tox.h
@@ -26,6 +26,22 @@
26 26
27#include <stdint.h> 27#include <stdint.h>
28 28
29#ifdef WIN32
30#ifndef WINVER
31//Windows XP
32#define WINVER 0x0501
33#endif
34
35#include <winsock2.h>
36#include <windows.h>
37#include <ws2tcpip.h>
38
39#else
40
41#include <netinet/ip.h>
42
43#endif
44
29#ifdef __cplusplus 45#ifdef __cplusplus
30extern "C" { 46extern "C" {
31#endif 47#endif
@@ -36,19 +52,61 @@ extern "C" {
36 52
37#define TOX_FRIEND_ADDRESS_SIZE (TOX_CLIENT_ID_SIZE + sizeof(uint32_t) + sizeof(uint16_t)) 53#define TOX_FRIEND_ADDRESS_SIZE (TOX_CLIENT_ID_SIZE + sizeof(uint32_t) + sizeof(uint16_t))
38 54
55#define TOX_PORTRANGE_FROM 33445
56#define TOX_PORTRANGE_TO 33455
57#define TOX_PORT_DEFAULT TOX_PORTRANGE_FROM
39 58
40typedef union { 59typedef union {
41 uint8_t c[4]; 60 uint8_t c[4];
42 uint16_t s[2]; 61 uint16_t s[2];
43 uint32_t i; 62 uint32_t i;
44} tox_IP; 63} tox_IP4;
64
65
66typedef union {
67 uint8_t uint8[16];
68 uint16_t uint16[8];
69 uint32_t uint32[4];
70 struct in6_addr in6_addr;
71} tox_IP6;
72
73typedef struct {
74 sa_family_t family;
75 union {
76 tox_IP4 ip4;
77 tox_IP6 ip6;
78 };
79} tox_IPAny;
45 80
81typedef union {
82 struct {
83 tox_IP4 ip;
84 uint16_t port;
85 /* Not used for anything right now. */
86 uint16_t padding;
87 };
88 uint8_t uint8[8];
89} tox_IP4_Port;
90
91/* will replace IP_Port as soon as the complete infrastructure is in place
92 * removed the unused union and padding also */
46typedef struct { 93typedef struct {
47 tox_IP ip; 94 tox_IPAny ip;
48 uint16_t port; 95 uint16_t port;
49 /* Not used for anything right now. */ 96} tox_IPAny_Port;
50 uint16_t padding; 97
51} tox_IP_Port; 98/* #undef TOX_ENABLE_IPV6 */
99#define TOX_ENABLE_IPV6
100#ifdef TOX_ENABLE_IPV6
101#define TOX_ENABLE_IPV6_DEFAULT 1
102typedef tox_IPAny tox_IP;
103typedef tox_IPAny_Port tox_IP_Port;
104#else
105#define TOX_ENABLE_IPV6_DEFAULT 0
106typedef tox_IP4 tox_IP;
107typedef tox_IP4_Port tox_IP_Port;
108#endif
109
52 110
53/* Errors for m_addfriend 111/* Errors for m_addfriend
54 * FAERR - Friend Add Error 112 * FAERR - Friend Add Error
@@ -342,22 +400,46 @@ int tox_group_message_send(Tox *tox, int groupnumber, uint8_t *message, uint32_t
342 400
343/******************END OF GROUP CHAT FUNCTIONS************************/ 401/******************END OF GROUP CHAT FUNCTIONS************************/
344 402
345/* Use this function to bootstrap the client. 403/*
346 * Sends a get nodes request to the given node with ip port and public_key. 404 * Use these two functions to bootstrap the client.
405 */
406/* Sends a "get nodes" request to the given node with ip, port and public_key
407 * to setup connections
347 */ 408 */
348void tox_bootstrap(Tox *tox, tox_IP_Port ip_port, uint8_t *public_key); 409void tox_bootstrap_from_ip(Tox *tox, tox_IP_Port ip_port, uint8_t *public_key);
410/* Resolves address into an IP address. If successful, sends a "get nodes"
411 * request to the given node with ip, port and public_key to setup connections
412 *
413 * address can be a hostname or an IP address (IPv4 or IPv6).
414 * if ipv6enabled is 0 (zero), the resolving sticks STRICTLY to IPv4 addresses
415 * if ipv6enabled is not 0 (zero), the resolving looks for IPv6 addresses first,
416 * then IPv4 addresses.
417 *
418 * returns 1 if the address could be converted into an IP address
419 * returns 0 otherwise
420 */
421int tox_bootstrap_from_address(Tox *tox, const char *address, uint8_t ipv6enabled,
422 uint16_t port, uint8_t *public_key);
349 423
350/* return 0 if we are not connected to the DHT. 424/* return 0 if we are not connected to the DHT.
351 * return 1 if we are. 425 * return 1 if we are.
352 */ 426 */
353int tox_isconnected(Tox *tox); 427int tox_isconnected(Tox *tox);
354 428
355/* Run this at startup. 429/*
430 * Run this function at startup.
431 *
432 * Initializes a tox structure
433 * The type of communication socket depends on ipv6enabled:
434 * If set to 0 (zero), creates an IPv4 socket which subsequently only allows
435 * IPv4 communication
436 * If set to anything else, creates an IPv6 socket which allows both IPv4 AND
437 * IPv6 communication
356 * 438 *
357 * return allocated instance of tox on success. 439 * return allocated instance of tox on success.
358 * return 0 if there are problems. 440 * return 0 if there are problems.
359 */ 441 */
360Tox *tox_new(void); 442Tox *tox_new(uint8_t ipv6enabled);
361 443
362/* Run this before closing shop. 444/* Run this before closing shop.
363 * Free all datastructures. */ 445 * Free all datastructures. */
diff --git a/toxcore/util.c b/toxcore/util.c
index 653e8d5f..ad6a4a83 100644
--- a/toxcore/util.c
+++ b/toxcore/util.c
@@ -10,9 +10,8 @@
10#endif 10#endif
11 11
12#include <time.h> 12#include <time.h>
13#include <stdint.h>
14#include <stdbool.h>
15 13
14/* for CLIENT_ID_SIZE */
16#include "DHT.h" 15#include "DHT.h"
17#include "util.h" 16#include "util.h"
18 17
@@ -33,11 +32,6 @@ uint64_t random_64b()
33 return r; 32 return r;
34} 33}
35 34
36bool ipp_eq(IP_Port a, IP_Port b)
37{
38 return (a.ip.uint32 == b.ip.uint32) && (a.port == b.port);
39}
40
41bool id_eq(uint8_t *dest, uint8_t *src) 35bool id_eq(uint8_t *dest, uint8_t *src)
42{ 36{
43 return memcmp(dest, src, CLIENT_ID_SIZE) == 0; 37 return memcmp(dest, src, CLIENT_ID_SIZE) == 0;
@@ -88,3 +82,33 @@ int load_state(load_state_callback_func load_state_callback, void *outer,
88 82
89 return length == 0 ? 0 : - 1; 83 return length == 0 ? 0 : - 1;
90}; 84};
85
86#ifdef LOGGING
87time_t starttime = 0;
88char logbuffer[512];
89static FILE *logfile = NULL;
90void loginit(uint16_t port)
91{
92 if (logfile)
93 fclose(logfile);
94
95 sprintf(logbuffer, "%u-%u.log", ntohs(port), now());
96 logfile = fopen(logbuffer, "w");
97 starttime = now();
98};
99void loglog(char *text)
100{
101 if (logfile) {
102 fprintf(logfile, "%4u ", now() - starttime);
103 fprintf(logfile, text);
104 fflush(logfile);
105 }
106};
107void logexit()
108{
109 if (logfile) {
110 fclose(logfile);
111 logfile = NULL;
112 }
113};
114#endif
diff --git a/toxcore/util.h b/toxcore/util.h
index 00482862..6937f7d4 100644
--- a/toxcore/util.h
+++ b/toxcore/util.h
@@ -8,9 +8,11 @@
8#ifndef __UTIL_H__ 8#ifndef __UTIL_H__
9#define __UTIL_H__ 9#define __UTIL_H__
10 10
11#include <stdbool.h>
12#include <stdint.h>
13
11uint64_t now(); 14uint64_t now();
12uint64_t random_64b(); 15uint64_t random_64b();
13bool ipp_eq(IP_Port a, IP_Port b);
14bool id_eq(uint8_t *dest, uint8_t *src); 16bool id_eq(uint8_t *dest, uint8_t *src);
15void id_cpy(uint8_t *dest, uint8_t *src); 17void id_cpy(uint8_t *dest, uint8_t *src);
16 18
@@ -18,4 +20,13 @@ typedef int (*load_state_callback_func)(void *outer, uint8_t *data, uint32_t len
18int load_state(load_state_callback_func load_state_callback, void *outer, 20int load_state(load_state_callback_func load_state_callback, void *outer,
19 uint8_t *data, uint32_t length, uint16_t cookie_inner); 21 uint8_t *data, uint32_t length, uint16_t cookie_inner);
20 22
23#undef LOGGING
24/* #define LOGGING */
25#ifdef LOGGING
26extern char logbuffer[512];
27void loginit(uint16_t port);
28void loglog(char *text);
29void logexit();
30#endif
31
21#endif /* __UTIL_H__ */ 32#endif /* __UTIL_H__ */