Some refactoring done.

This commit is contained in:
irungentoo 2013-08-19 23:54:28 -04:00
parent b16906d5e4
commit afa6edecc1
13 changed files with 756 additions and 665 deletions

View File

@ -544,7 +544,7 @@ static int getnodes(IP_Port ip_port, uint8_t *public_key, uint8_t *client_id)
memcpy(data + 1 + CLIENT_ID_SIZE, nonce, crypto_box_NONCEBYTES); memcpy(data + 1 + CLIENT_ID_SIZE, nonce, crypto_box_NONCEBYTES);
memcpy(data + 1 + CLIENT_ID_SIZE + crypto_box_NONCEBYTES, encrypt, len); memcpy(data + 1 + CLIENT_ID_SIZE + crypto_box_NONCEBYTES, encrypt, len);
return sendpacket(ip_port, data, sizeof(data)); return sendpacket(temp_net->sock, ip_port, data, sizeof(data));
} }
/* send a send nodes response */ /* send a send nodes response */
@ -586,10 +586,10 @@ static int sendnodes(IP_Port ip_port, uint8_t *public_key, uint8_t *client_id, u
memcpy(data + 1 + CLIENT_ID_SIZE, nonce, crypto_box_NONCEBYTES); memcpy(data + 1 + CLIENT_ID_SIZE, nonce, crypto_box_NONCEBYTES);
memcpy(data + 1 + CLIENT_ID_SIZE + crypto_box_NONCEBYTES, encrypt, len); memcpy(data + 1 + CLIENT_ID_SIZE + crypto_box_NONCEBYTES, encrypt, len);
return sendpacket(ip_port, data, 1 + CLIENT_ID_SIZE + crypto_box_NONCEBYTES + len); return sendpacket(temp_net->sock, ip_port, data, 1 + CLIENT_ID_SIZE + crypto_box_NONCEBYTES + len);
} }
static int handle_getnodes(IP_Port source, uint8_t *packet, uint32_t length) static int handle_getnodes(void * object, IP_Port source, uint8_t *packet, uint32_t length)
{ {
uint64_t ping_id; uint64_t ping_id;
@ -621,7 +621,7 @@ static int handle_getnodes(IP_Port source, uint8_t *packet, uint32_t length)
return 0; return 0;
} }
static int handle_sendnodes(IP_Port source, uint8_t *packet, uint32_t length) static int handle_sendnodes(void * object, IP_Port source, uint8_t *packet, uint32_t length)
{ {
uint64_t ping_id; uint64_t ping_id;
uint32_t cid_size = 1 + CLIENT_ID_SIZE; uint32_t cid_size = 1 + CLIENT_ID_SIZE;
@ -841,7 +841,7 @@ int route_packet(uint8_t *client_id, uint8_t *packet, uint32_t length)
for (i = 0; i < LCLIENT_LIST; ++i) { for (i = 0; i < LCLIENT_LIST; ++i) {
if (id_equal(client_id, close_clientlist[i].client_id)) if (id_equal(client_id, close_clientlist[i].client_id))
return sendpacket(close_clientlist[i].ip_port, packet, length); return sendpacket(temp_net->sock, close_clientlist[i].ip_port, packet, length);
} }
return -1; return -1;
@ -912,7 +912,7 @@ int route_tofriend(uint8_t *friend_id, uint8_t *packet, uint32_t length)
/*If ip is not zero and node is good */ /*If ip is not zero and node is good */
if (client->ret_ip_port.ip.i != 0 && !is_timeout(temp_time, client->ret_timestamp, BAD_NODE_TIMEOUT)) { if (client->ret_ip_port.ip.i != 0 && !is_timeout(temp_time, client->ret_timestamp, BAD_NODE_TIMEOUT)) {
if (sendpacket(client->ip_port, packet, length) == length) if (sendpacket(temp_net->sock, client->ip_port, packet, length) == length)
++sent; ++sent;
} }
} }
@ -951,7 +951,7 @@ static int routeone_tofriend(uint8_t *friend_id, uint8_t *packet, uint32_t lengt
if (n < 1) if (n < 1)
return 0; return 0;
if (sendpacket(ip_list[rand() % n], packet, length) == length) if (sendpacket(temp_net->sock, ip_list[rand() % n], packet, length) == length)
return 1; return 1;
return 0; return 0;
@ -989,7 +989,7 @@ static int send_NATping(uint8_t *public_key, uint64_t ping_id, uint8_t type)
data[0] = type; data[0] = type;
memcpy(data + 1, &ping_id, sizeof(uint64_t)); memcpy(data + 1, &ping_id, sizeof(uint64_t));
/* 254 is NAT ping request packet id */ /* 254 is NAT ping request packet id */
int len = create_request(packet, public_key, data, sizeof(uint64_t) + 1, 254); int len = create_request(self_public_key, self_secret_key, packet, public_key, data, sizeof(uint64_t) + 1, 254);
if (len == -1) if (len == -1)
return -1; return -1;
@ -1201,11 +1201,11 @@ static void do_toping()
void DHT_init(void) void DHT_init(void)
{ {
networking_registerhandler(0, &handle_ping_request); networking_registerhandler(temp_net, 0, &handle_ping_request, NULL);
networking_registerhandler(1, &handle_ping_response); networking_registerhandler(temp_net, 1, &handle_ping_response, NULL);
networking_registerhandler(2, &handle_getnodes); networking_registerhandler(temp_net, 2, &handle_getnodes, NULL);
networking_registerhandler(3, &handle_sendnodes); networking_registerhandler(temp_net, 3, &handle_sendnodes, NULL);
cryptopacket_registerhandler(254, &handle_NATping); cryptopacket_registerhandler(temp_net_crypto, 254, &handle_NATping);
} }
void doDHT(void) void doDHT(void)

View File

@ -121,7 +121,7 @@ static int LAN_ip(IP ip)
return -1; return -1;
} }
static int handle_LANdiscovery(IP_Port source, uint8_t *packet, uint32_t length) static int handle_LANdiscovery(void * object, IP_Port source, uint8_t *packet, uint32_t length)
{ {
if (LAN_ip(source.ip) == -1) if (LAN_ip(source.ip) == -1)
return 1; return 1;
@ -140,11 +140,11 @@ int send_LANdiscovery(uint16_t port)
data[0] = 33; data[0] = 33;
memcpy(data + 1, self_public_key, crypto_box_PUBLICKEYBYTES); memcpy(data + 1, self_public_key, crypto_box_PUBLICKEYBYTES);
IP_Port ip_port = {broadcast_ip(), port}; IP_Port ip_port = {broadcast_ip(), port};
return sendpacket(ip_port, data, 1 + crypto_box_PUBLICKEYBYTES); return sendpacket(temp_net->sock, ip_port, data, 1 + crypto_box_PUBLICKEYBYTES);
} }
void LANdiscovery_init(void) void LANdiscovery_init(void)
{ {
networking_registerhandler(33, &handle_LANdiscovery); networking_registerhandler(temp_net, 33, &handle_LANdiscovery, NULL);
} }

View File

@ -28,97 +28,6 @@
#include "Lossless_UDP.h" #include "Lossless_UDP.h"
/* maximum data packets in sent and receive queues. */
#define MAX_QUEUE_NUM 16
/* maximum number of data packets in the buffer */
#define BUFFER_PACKET_NUM (16-1)
/* timeout per connection is randomly set between CONNEXION_TIMEOUT and 2*CONNEXION_TIMEOUT */
#define CONNEXION_TIMEOUT 5
/* initial amount of sync/hanshake packets to send per second. */
#define SYNC_RATE 2
/* initial send rate of data. */
#define DATA_SYNC_RATE 30
typedef struct {
uint8_t data[MAX_DATA_SIZE];
uint16_t size;
} Data;
typedef struct {
IP_Port ip_port;
/*
* 0 if connection is dead, 1 if attempting handshake,
* 2 if handshake is done (we start sending SYNC packets)
* 3 if we are sending SYNC packets and can send data
* 4 if the connection has timed out.
*/
uint8_t status;
/*
* 1 or 2 if connection was initiated by someone else, 0 if not.
* 2 if incoming_connection() has not returned it yet, 1 if it has.
*/
uint8_t inbound;
uint16_t SYNC_rate; /* current SYNC packet send rate packets per second. */
uint16_t data_rate; /* current data packet send rate packets per second. */
uint64_t last_SYNC; /* time our last SYNC packet was sent. */
uint64_t last_sent; /* time our last data or handshake packet was sent. */
uint64_t last_recvSYNC; /* time we last received a SYNC packet from the other */
uint64_t last_recvdata; /* time we last received a DATA packet from the other */
uint64_t killat; /* time to kill the connection */
Data sendbuffer[MAX_QUEUE_NUM]; /* packet send buffer. */
Data recvbuffer[MAX_QUEUE_NUM]; /* packet receive buffer. */
uint32_t handshake_id1;
uint32_t handshake_id2;
/* number of data packets received (also used as handshake_id1) */
uint32_t recv_packetnum;
/* number of packets received by the other peer */
uint32_t orecv_packetnum;
/* number of data packets sent */
uint32_t sent_packetnum;
/* number of packets sent by the other peer. */
uint32_t osent_packetnum;
/* number of latest packet written onto the sendbuffer */
uint32_t sendbuff_packetnum;
/* we know all packets before that number were successfully sent */
uint32_t successful_sent;
/* packet number of last packet read with the read_packet function */
uint32_t successful_read;
/* list of currently requested packet numbers(by the other person) */
uint32_t req_packets[BUFFER_PACKET_NUM];
/* total number of currently requested packets(by the other person) */
uint16_t num_req_paquets;
uint8_t recv_counter;
uint8_t send_counter;
uint8_t timeout; /* connection timeout in seconds. */
} Connection;
static Connection *connections;
static uint32_t connections_length; /* Length of connections array */
static uint32_t connections_number; /* Number of connections in connections array */
#define MAX_CONNECTIONS connections_length
/* Functions */ /* Functions */
@ -127,22 +36,20 @@ static uint32_t connections_number; /* Number of connections in connections arra
* Return -1 if there are no connections like we are looking for * Return -1 if there are no connections like we are looking for
* Return id if it found it * Return id if it found it
*/ */
int getconnection_id(IP_Port ip_port) int getconnection_id(Lossless_UDP * ludp, IP_Port ip_port)
{ {
uint32_t i; uint32_t i;
for (i = 0; i < MAX_CONNECTIONS; ++i) { for (i = 0; i < ludp->connections_length; ++i) {
if (connections[i].ip_port.ip.i == ip_port.ip.i && if (ludp->connections[i].ip_port.ip.i == ip_port.ip.i &&
connections[i].ip_port.port == ip_port.port && ludp->connections[i].ip_port.port == ip_port.port &&
connections[i].status > 0) ludp->connections[i].status > 0)
return i; return i;
} }
return -1; return -1;
} }
/* table of random numbers used below. */
static uint32_t randtable[6][256];
/* /*
* Generate a handshake_id which depends on the ip_port. * Generate a handshake_id which depends on the ip_port.
@ -150,15 +57,15 @@ static uint32_t randtable[6][256];
* *
* TODO: make this better * TODO: make this better
*/ */
static uint32_t handshake_id(IP_Port source) static uint32_t handshake_id(Lossless_UDP * ludp, IP_Port source)
{ {
uint32_t id = 0, i; uint32_t id = 0, i;
for (i = 0; i < 6; ++i) { for (i = 0; i < 6; ++i) {
if (randtable[i][((uint8_t *)&source)[i]] == 0) if (ludp->randtable[i][((uint8_t *)&source)[i]] == 0)
randtable[i][((uint8_t *)&source)[i]] = random_int(); ludp->randtable[i][((uint8_t *)&source)[i]] = random_int();
id ^= randtable[i][((uint8_t *)&source)[i]]; id ^= ludp->randtable[i][((uint8_t *)&source)[i]];
} }
if (id == 0) /* id can't be zero */ if (id == 0) /* id can't be zero */
@ -172,10 +79,10 @@ static uint32_t handshake_id(IP_Port source)
* *
* TODO: make this better * TODO: make this better
*/ */
static void change_handshake(IP_Port source) static void change_handshake(Lossless_UDP * ludp, IP_Port source)
{ {
uint8_t rand = random_int() % 4; uint8_t rand = random_int() % 4;
randtable[rand][((uint8_t *)&source)[rand]] = random_int(); ludp->randtable[rand][((uint8_t *)&source)[rand]] = random_int();
} }
/* /*
@ -184,33 +91,33 @@ static void change_handshake(IP_Port source)
* Return -1 if it could not initialize the connectiont * Return -1 if it could not initialize the connectiont
* If there already was an existing connection to that ip_port return its number. * If there already was an existing connection to that ip_port return its number.
*/ */
int new_connection(IP_Port ip_port) int new_connection(Lossless_UDP * ludp, IP_Port ip_port)
{ {
int connect = getconnection_id(ip_port); int connect = getconnection_id(ludp, ip_port);
if (connect != -1) if (connect != -1)
return connect; return connect;
if (connections_number == connections_length) { if (ludp->connections_number == ludp->connections_length) {
Connection *temp; Connection *temp;
temp = realloc(connections, sizeof(Connection) * (connections_length + 1)); temp = realloc(ludp->connections, sizeof(Connection) * (ludp->connections_length + 1));
if (temp == NULL) if (temp == NULL)
return -1; return -1;
memset(&temp[connections_length], 0, sizeof(Connection)); memset(&temp[ludp->connections_length], 0, sizeof(Connection));
++connections_length; ++ludp->connections_length;
connections = temp; ludp->connections = temp;
} }
uint32_t i; uint32_t i;
for (i = 0; i < MAX_CONNECTIONS; ++i) { for (i = 0; i < ludp->connections_length; ++i) {
if (connections[i].status == 0) { if (ludp->connections[i].status == 0) {
memset(&connections[i], 0, sizeof(Connection)); memset(&ludp->connections[i], 0, sizeof(Connection));
uint32_t handshake_id1 = handshake_id(ip_port); uint32_t handshake_id1 = handshake_id(ludp, ip_port);
connections[i] = (Connection) { ludp->connections[i] = (Connection) {
.ip_port = ip_port, .ip_port = ip_port,
.status = 1, .status = 1,
.inbound = 0, .inbound = 0,
@ -227,7 +134,7 @@ int new_connection(IP_Port ip_port)
/* add randomness to timeout to prevent connections getting stuck in a loop. */ /* add randomness to timeout to prevent connections getting stuck in a loop. */
.timeout = CONNEXION_TIMEOUT + rand() % CONNEXION_TIMEOUT .timeout = CONNEXION_TIMEOUT + rand() % CONNEXION_TIMEOUT
}; };
++connections_number; ++ludp->connections_number;
return i; return i;
} }
@ -241,31 +148,31 @@ int new_connection(IP_Port ip_port)
* Returns an integer corresponding to the connection id. * Returns an integer corresponding to the connection id.
* Return -1 if it could not initialize the connection. * Return -1 if it could not initialize the connection.
*/ */
static int new_inconnection(IP_Port ip_port) static int new_inconnection(Lossless_UDP * ludp, IP_Port ip_port)
{ {
if (getconnection_id(ip_port) != -1) if (getconnection_id(ludp, ip_port) != -1)
return -1; return -1;
if (connections_number == connections_length) { if (ludp->connections_number == ludp->connections_length) {
Connection *temp; Connection *temp;
temp = realloc(connections, sizeof(Connection) * (connections_length + 1)); temp = realloc(ludp->connections, sizeof(Connection) * (ludp->connections_length + 1));
if (temp == NULL) if (temp == NULL)
return -1; return -1;
memset(&temp[connections_length], 0, sizeof(Connection)); memset(&temp[ludp->connections_length], 0, sizeof(Connection));
++connections_length; ++ludp->connections_length;
connections = temp; ludp->connections = temp;
} }
uint32_t i; uint32_t i;
for (i = 0; i < MAX_CONNECTIONS; ++i) { for (i = 0; i < ludp->connections_length; ++i) {
if (connections[i].status == 0) { if (ludp->connections[i].status == 0) {
memset(&connections[i], 0, sizeof(Connection)); memset(&ludp->connections[i], 0, sizeof(Connection));
uint64_t timeout = CONNEXION_TIMEOUT + rand() % CONNEXION_TIMEOUT; uint64_t timeout = CONNEXION_TIMEOUT + rand() % CONNEXION_TIMEOUT;
connections[i] = (Connection) { ludp->connections[i] = (Connection) {
.ip_port = ip_port, .ip_port = ip_port,
.status = 2, .status = 2,
.inbound = 2, .inbound = 2,
@ -281,7 +188,7 @@ static int new_inconnection(IP_Port ip_port)
/* if this connection isn't handled within the timeout kill it. */ /* if this connection isn't handled within the timeout kill it. */
.killat = current_time() + 1000000UL * timeout .killat = current_time() + 1000000UL * timeout
}; };
++connections_number; ++ludp->connections_number;
return i; return i;
} }
} }
@ -293,13 +200,13 @@ static int new_inconnection(IP_Port ip_port)
* Returns an integer corresponding to the next connection in our incoming connection list. * Returns an integer corresponding to the next connection in our incoming connection list.
* Return -1 if there are no new incoming connections in the list. * Return -1 if there are no new incoming connections in the list.
*/ */
int incoming_connection(void) int incoming_connection(Lossless_UDP * ludp)
{ {
uint32_t i; uint32_t i;
for (i = 0; i < MAX_CONNECTIONS; ++i) { for (i = 0; i < ludp->connections_length; ++i) {
if (connections[i].inbound == 2) { if (ludp->connections[i].inbound == 2) {
connections[i].inbound = 1; ludp->connections[i].inbound = 1;
return i; return i;
} }
} }
@ -308,46 +215,46 @@ int incoming_connection(void)
} }
/* Try to free some memory from the connections array. */ /* Try to free some memory from the connections array. */
static void free_connections(void) static void free_connections(Lossless_UDP * ludp)
{ {
uint32_t i; uint32_t i;
for (i = connections_length; i != 0; --i) for (i = ludp->connections_length; i != 0; --i)
if (connections[i - 1].status != 0) if (ludp->connections[i - 1].status != 0)
break; break;
if (connections_length == i) if (ludp->connections_length == i)
return; return;
if (i == 0) { if (i == 0) {
free(connections); free(ludp->connections);
connections = NULL; ludp->connections = NULL;
connections_length = i; ludp->connections_length = i;
return; return;
} }
Connection *temp; Connection *temp;
temp = realloc(connections, sizeof(Connection) * i); temp = realloc(ludp->connections, sizeof(Connection) * i);
if (temp == NULL && i != 0) if (temp == NULL && i != 0)
return; return;
connections = temp; ludp->connections = temp;
connections_length = i; ludp->connections_length = i;
} }
/* /*
* Return -1 if it could not kill the connection. * Return -1 if it could not kill the connection.
* Return 0 if killed successfully * Return 0 if killed successfully
*/ */
int kill_connection(int connection_id) int kill_connection(Lossless_UDP * ludp, int connection_id)
{ {
if (connection_id >= 0 && connection_id < MAX_CONNECTIONS) { if (connection_id >= 0 && connection_id < ludp->connections_length) {
if (connections[connection_id].status > 0) { if (ludp->connections[connection_id].status > 0) {
connections[connection_id].status = 0; ludp->connections[connection_id].status = 0;
change_handshake(connections[connection_id].ip_port); change_handshake(ludp, ludp->connections[connection_id].ip_port);
--connections_number; --ludp->connections_number;
free_connections(); free_connections(ludp);
return 0; return 0;
} }
} }
@ -360,11 +267,11 @@ int kill_connection(int connection_id)
* Return -1 if it can not kill the connection. * Return -1 if it can not kill the connection.
* Return 0 if it will kill it. * Return 0 if it will kill it.
*/ */
int kill_connection_in(int connection_id, uint32_t seconds) int kill_connection_in(Lossless_UDP * ludp, int connection_id, uint32_t seconds)
{ {
if (connection_id >= 0 && connection_id < MAX_CONNECTIONS) { if (connection_id >= 0 && connection_id < ludp->connections_length) {
if (connections[connection_id].status > 0) { if (ludp->connections[connection_id].status > 0) {
connections[connection_id].killat = current_time() + 1000000UL * seconds; ludp->connections[connection_id].killat = current_time() + 1000000UL * seconds;
return 0; return 0;
} }
} }
@ -380,65 +287,65 @@ int kill_connection_in(int connection_id, uint32_t seconds)
* Return 3 if fully connected. * Return 3 if fully connected.
* Return 4 if timed out and waiting to be killed. * Return 4 if timed out and waiting to be killed.
*/ */
int is_connected(int connection_id) int is_connected(Lossless_UDP * ludp, int connection_id)
{ {
if (connection_id >= 0 && connection_id < MAX_CONNECTIONS) if (connection_id >= 0 && connection_id < ludp->connections_length)
return connections[connection_id].status; return ludp->connections[connection_id].status;
return 0; return 0;
} }
/* returns the ip_port of the corresponding connection. */ /* returns the ip_port of the corresponding connection. */
IP_Port connection_ip(int connection_id) IP_Port connection_ip(Lossless_UDP * ludp, int connection_id)
{ {
if (connection_id >= 0 && connection_id < MAX_CONNECTIONS) if (connection_id >= 0 && connection_id < ludp->connections_length)
return connections[connection_id].ip_port; return ludp->connections[connection_id].ip_port;
IP_Port zero = {{{0}}, 0}; IP_Port zero = {{{0}}, 0};
return zero; return zero;
} }
/* returns the number of packets in the queue waiting to be successfully sent. */ /* returns the number of packets in the queue waiting to be successfully sent. */
uint32_t sendqueue(int connection_id) uint32_t sendqueue(Lossless_UDP * ludp, int connection_id)
{ {
if (connection_id < 0 || connection_id >= MAX_CONNECTIONS) if (connection_id < 0 || connection_id >= ludp->connections_length)
return 0; return 0;
return connections[connection_id].sendbuff_packetnum - connections[connection_id].successful_sent; return ludp->connections[connection_id].sendbuff_packetnum - ludp->connections[connection_id].successful_sent;
} }
/* returns the number of packets in the queue waiting to be successfully read with read_packet(...) */ /* returns the number of packets in the queue waiting to be successfully read with read_packet(...) */
uint32_t recvqueue(int connection_id) uint32_t recvqueue(Lossless_UDP * ludp, int connection_id)
{ {
if (connection_id < 0 || connection_id >= MAX_CONNECTIONS) if (connection_id < 0 || connection_id >= ludp->connections_length)
return 0; return 0;
return connections[connection_id].recv_packetnum - connections[connection_id].successful_read; return ludp->connections[connection_id].recv_packetnum - ludp->connections[connection_id].successful_read;
} }
/* returns the id of the next packet in the queue /* returns the id of the next packet in the queue
return -1 if no packet in queue */ return -1 if no packet in queue */
char id_packet(int connection_id) char id_packet(Lossless_UDP * ludp, int connection_id)
{ {
if (connection_id < 0 || connection_id >= MAX_CONNECTIONS) if (connection_id < 0 || connection_id >= ludp->connections_length)
return -1; return -1;
if (recvqueue(connection_id) != 0 && connections[connection_id].status != 0) if (recvqueue(ludp, connection_id) != 0 && ludp->connections[connection_id].status != 0)
return connections[connection_id].recvbuffer[connections[connection_id].successful_read % MAX_QUEUE_NUM].data[0]; return ludp->connections[connection_id].recvbuffer[ludp->connections[connection_id].successful_read % MAX_QUEUE_NUM].data[0];
return -1; return -1;
} }
/* return 0 if there is no received data in the buffer. /* return 0 if there is no received data in the buffer.
return length of received packet if successful */ return length of received packet if successful */
int read_packet(int connection_id, uint8_t *data) int read_packet(Lossless_UDP * ludp, int connection_id, uint8_t *data)
{ {
if (recvqueue(connection_id) != 0) { if (recvqueue(ludp, connection_id) != 0) {
uint16_t index = connections[connection_id].successful_read % MAX_QUEUE_NUM; uint16_t index = ludp->connections[connection_id].successful_read % MAX_QUEUE_NUM;
uint16_t size = connections[connection_id].recvbuffer[index].size; uint16_t size = ludp->connections[connection_id].recvbuffer[index].size;
memcpy(data, connections[connection_id].recvbuffer[index].data, size); memcpy(data, ludp->connections[connection_id].recvbuffer[index].data, size);
++connections[connection_id].successful_read; ++ludp->connections[connection_id].successful_read;
connections[connection_id].recvbuffer[index].size = 0; ludp->connections[connection_id].recvbuffer[index].size = 0;
return size; return size;
} }
@ -449,16 +356,16 @@ int read_packet(int connection_id, uint8_t *data)
* Return 0 if data could not be put in packet queue * Return 0 if data could not be put in packet queue
* Return 1 if data was put into the queue * Return 1 if data was put into the queue
*/ */
int write_packet(int connection_id, uint8_t *data, uint32_t length) int write_packet(Lossless_UDP * ludp, int connection_id, uint8_t *data, uint32_t length)
{ {
if (length > MAX_DATA_SIZE || length == 0) if (length > MAX_DATA_SIZE || length == 0)
return 0; return 0;
if (sendqueue(connection_id) < BUFFER_PACKET_NUM) { if (sendqueue(ludp, connection_id) < BUFFER_PACKET_NUM) {
uint32_t index = connections[connection_id].sendbuff_packetnum % MAX_QUEUE_NUM; uint32_t index = ludp->connections[connection_id].sendbuff_packetnum % MAX_QUEUE_NUM;
memcpy(connections[connection_id].sendbuffer[index].data, data, length); memcpy(ludp->connections[connection_id].sendbuffer[index].data, data, length);
connections[connection_id].sendbuffer[index].size = length; ludp->connections[connection_id].sendbuffer[index].size = length;
connections[connection_id].sendbuff_packetnum++; ludp->connections[connection_id].sendbuff_packetnum++;
return 1; return 1;
} }
@ -466,18 +373,18 @@ int write_packet(int connection_id, uint8_t *data, uint32_t length)
} }
/* put the packet numbers the we are missing in requested and return the number */ /* put the packet numbers the we are missing in requested and return the number */
uint32_t missing_packets(int connection_id, uint32_t *requested) uint32_t missing_packets(Lossless_UDP * ludp, int connection_id, uint32_t *requested)
{ {
uint32_t number = 0; uint32_t number = 0;
uint32_t i; uint32_t i;
uint32_t temp; uint32_t temp;
/* don't request packets if the buffer is full. */ /* don't request packets if the buffer is full. */
if (recvqueue(connection_id) >= (BUFFER_PACKET_NUM - 1)) if (recvqueue(ludp, connection_id) >= (BUFFER_PACKET_NUM - 1))
return 0; return 0;
for (i = connections[connection_id].recv_packetnum; i != connections[connection_id].osent_packetnum; i++) { for (i = ludp->connections[connection_id].recv_packetnum; i != ludp->connections[connection_id].osent_packetnum; i++) {
if (connections[connection_id].recvbuffer[i % MAX_QUEUE_NUM].size == 0) { if (ludp->connections[connection_id].recvbuffer[i % MAX_QUEUE_NUM].size == 0) {
temp = htonl(i); temp = htonl(i);
memcpy(requested + number, &temp, 4); memcpy(requested + number, &temp, 4);
++number; ++number;
@ -485,7 +392,7 @@ uint32_t missing_packets(int connection_id, uint32_t *requested)
} }
if (number == 0) if (number == 0)
connections[connection_id].recv_packetnum = connections[connection_id].osent_packetnum; ludp->connections[connection_id].recv_packetnum = ludp->connections[connection_id].osent_packetnum;
return number; return number;
} }
@ -496,7 +403,7 @@ uint32_t missing_packets(int connection_id, uint32_t *requested)
* see http://wiki.tox.im/index.php/Lossless_UDP for more information. * see http://wiki.tox.im/index.php/Lossless_UDP for more information.
*/ */
static int send_handshake(IP_Port ip_port, uint32_t handshake_id1, uint32_t handshake_id2) static int send_handshake(Lossless_UDP * ludp, IP_Port ip_port, uint32_t handshake_id1, uint32_t handshake_id2)
{ {
uint8_t packet[1 + 4 + 4]; uint8_t packet[1 + 4 + 4];
uint32_t temp; uint32_t temp;
@ -507,21 +414,21 @@ static int send_handshake(IP_Port ip_port, uint32_t handshake_id1, uint32_t hand
temp = htonl(handshake_id2); temp = htonl(handshake_id2);
memcpy(packet + 5, &temp, 4); memcpy(packet + 5, &temp, 4);
return sendpacket(ip_port, packet, sizeof(packet)); return sendpacket(ludp->net->sock, ip_port, packet, sizeof(packet));
} }
static int send_SYNC(uint32_t connection_id) static int send_SYNC(Lossless_UDP * ludp, uint32_t connection_id)
{ {
uint8_t packet[(BUFFER_PACKET_NUM * 4 + 4 + 4 + 2)]; uint8_t packet[(BUFFER_PACKET_NUM * 4 + 4 + 4 + 2)];
uint16_t index = 0; uint16_t index = 0;
IP_Port ip_port = connections[connection_id].ip_port; IP_Port ip_port = ludp->connections[connection_id].ip_port;
uint8_t counter = connections[connection_id].send_counter; uint8_t counter = ludp->connections[connection_id].send_counter;
uint32_t recv_packetnum = htonl(connections[connection_id].recv_packetnum); uint32_t recv_packetnum = htonl(ludp->connections[connection_id].recv_packetnum);
uint32_t sent_packetnum = htonl(connections[connection_id].sent_packetnum); uint32_t sent_packetnum = htonl(ludp->connections[connection_id].sent_packetnum);
uint32_t requested[BUFFER_PACKET_NUM]; uint32_t requested[BUFFER_PACKET_NUM];
uint32_t number = missing_packets(connection_id, requested); uint32_t number = missing_packets(ludp, connection_id, requested);
packet[0] = 17; packet[0] = 17;
index += 1; index += 1;
@ -533,11 +440,11 @@ static int send_SYNC(uint32_t connection_id)
index += 4; index += 4;
memcpy(packet + index, requested, 4 * number); memcpy(packet + index, requested, 4 * number);
return sendpacket(ip_port, packet, (number * 4 + 4 + 4 + 2)); return sendpacket(ludp->net->sock, ip_port, packet, (number * 4 + 4 + 4 + 2));
} }
static int send_data_packet(uint32_t connection_id, uint32_t packet_num) static int send_data_packet(Lossless_UDP * ludp, uint32_t connection_id, uint32_t packet_num)
{ {
uint32_t index = packet_num % MAX_QUEUE_NUM; uint32_t index = packet_num % MAX_QUEUE_NUM;
uint32_t temp; uint32_t temp;
@ -545,29 +452,29 @@ static int send_data_packet(uint32_t connection_id, uint32_t packet_num)
packet[0] = 18; packet[0] = 18;
temp = htonl(packet_num); temp = htonl(packet_num);
memcpy(packet + 1, &temp, 4); memcpy(packet + 1, &temp, 4);
memcpy(packet + 5, connections[connection_id].sendbuffer[index].data, memcpy(packet + 5, ludp->connections[connection_id].sendbuffer[index].data,
connections[connection_id].sendbuffer[index].size); ludp->connections[connection_id].sendbuffer[index].size);
return sendpacket(connections[connection_id].ip_port, packet, return sendpacket(ludp->net->sock, ludp->connections[connection_id].ip_port, packet,
1 + 4 + connections[connection_id].sendbuffer[index].size); 1 + 4 + ludp->connections[connection_id].sendbuffer[index].size);
} }
/* sends 1 data packet */ /* sends 1 data packet */
static int send_DATA(uint32_t connection_id) static int send_DATA(Lossless_UDP * ludp, uint32_t connection_id)
{ {
int ret; int ret;
uint32_t buffer[BUFFER_PACKET_NUM]; uint32_t buffer[BUFFER_PACKET_NUM];
if (connections[connection_id].num_req_paquets > 0) { if (ludp->connections[connection_id].num_req_paquets > 0) {
ret = send_data_packet(connection_id, connections[connection_id].req_packets[0]); ret = send_data_packet(ludp, connection_id, ludp->connections[connection_id].req_packets[0]);
connections[connection_id].num_req_paquets--; ludp->connections[connection_id].num_req_paquets--;
memcpy(buffer, connections[connection_id].req_packets + 1, connections[connection_id].num_req_paquets * 4); memcpy(buffer, ludp->connections[connection_id].req_packets + 1, ludp->connections[connection_id].num_req_paquets * 4);
memcpy(connections[connection_id].req_packets, buffer, connections[connection_id].num_req_paquets * 4); memcpy(ludp->connections[connection_id].req_packets, buffer, ludp->connections[connection_id].num_req_paquets * 4);
return ret; return ret;
} }
if (connections[connection_id].sendbuff_packetnum != connections[connection_id].sent_packetnum) { if (ludp->connections[connection_id].sendbuff_packetnum != ludp->connections[connection_id].sent_packetnum) {
ret = send_data_packet(connection_id, connections[connection_id].sent_packetnum); ret = send_data_packet(ludp, connection_id, ludp->connections[connection_id].sent_packetnum);
connections[connection_id].sent_packetnum++; ludp->connections[connection_id].sent_packetnum++;
return ret; return ret;
} }
@ -584,37 +491,38 @@ static int send_DATA(uint32_t connection_id)
/* Return 0 if handled correctly, 1 if packet is bad. */ /* Return 0 if handled correctly, 1 if packet is bad. */
static int handle_handshake(IP_Port source, uint8_t *packet, uint32_t length) static int handle_handshake(void * object, IP_Port source, uint8_t *packet, uint32_t length)
{ {
Lossless_UDP * ludp = object;
if (length != (1 + 4 + 4)) if (length != (1 + 4 + 4))
return 1; return 1;
uint32_t temp; uint32_t temp;
uint32_t handshake_id1, handshake_id2; uint32_t handshake_id1, handshake_id2;
int connection = getconnection_id(source); int connection = getconnection_id(ludp, source);
memcpy(&temp, packet + 1, 4); memcpy(&temp, packet + 1, 4);
handshake_id1 = ntohl(temp); handshake_id1 = ntohl(temp);
memcpy(&temp, packet + 5, 4); memcpy(&temp, packet + 5, 4);
handshake_id2 = ntohl(temp); handshake_id2 = ntohl(temp);
if (handshake_id2 == 0 && is_connected(connection) < 3) { if (handshake_id2 == 0 && is_connected(ludp, connection) < 3) {
send_handshake(source, handshake_id(source), handshake_id1); send_handshake(ludp, source, handshake_id(ludp, source), handshake_id1);
return 0; return 0;
} }
if (is_connected(connection) != 1) if (is_connected(ludp, connection) != 1)
return 1; return 1;
/* if handshake_id2 is what we sent previously as handshake_id1 */ /* if handshake_id2 is what we sent previously as handshake_id1 */
if (handshake_id2 == connections[connection].handshake_id1) { if (handshake_id2 == ludp->connections[connection].handshake_id1) {
connections[connection].status = 2; ludp->connections[connection].status = 2;
/* NOTE: is this necessary? /* NOTE: is this necessary?
connections[connection].handshake_id2 = handshake_id1; */ ludp->connections[connection].handshake_id2 = handshake_id1; */
connections[connection].orecv_packetnum = handshake_id2; ludp->connections[connection].orecv_packetnum = handshake_id2;
connections[connection].osent_packetnum = handshake_id1; ludp->connections[connection].osent_packetnum = handshake_id1;
connections[connection].recv_packetnum = handshake_id1; ludp->connections[connection].recv_packetnum = handshake_id1;
connections[connection].successful_read = handshake_id1; ludp->connections[connection].successful_read = handshake_id1;
} }
return 0; return 0;
@ -634,19 +542,19 @@ static int SYNC_valid(uint32_t length)
} }
/* case 1 in handle_SYNC: */ /* case 1 in handle_SYNC: */
static int handle_SYNC1(IP_Port source, uint32_t recv_packetnum, uint32_t sent_packetnum) static int handle_SYNC1(Lossless_UDP * ludp, IP_Port source, uint32_t recv_packetnum, uint32_t sent_packetnum)
{ {
if (handshake_id(source) == recv_packetnum) { if (handshake_id(ludp, source) == recv_packetnum) {
int x = new_inconnection(source); int x = new_inconnection(ludp, source);
if (x != -1) { if (x != -1) {
connections[x].orecv_packetnum = recv_packetnum; ludp->connections[x].orecv_packetnum = recv_packetnum;
connections[x].sent_packetnum = recv_packetnum; ludp->connections[x].sent_packetnum = recv_packetnum;
connections[x].sendbuff_packetnum = recv_packetnum; ludp->connections[x].sendbuff_packetnum = recv_packetnum;
connections[x].successful_sent = recv_packetnum; ludp->connections[x].successful_sent = recv_packetnum;
connections[x].osent_packetnum = sent_packetnum; ludp->connections[x].osent_packetnum = sent_packetnum;
connections[x].recv_packetnum = sent_packetnum; ludp->connections[x].recv_packetnum = sent_packetnum;
connections[x].successful_read = sent_packetnum; ludp->connections[x].successful_read = sent_packetnum;
return x; return x;
} }
@ -656,63 +564,63 @@ static int handle_SYNC1(IP_Port source, uint32_t recv_packetnum, uint32_t sent_p
} }
/* case 2 in handle_SYNC: */ /* case 2 in handle_SYNC: */
static int handle_SYNC2(int connection_id, uint8_t counter, uint32_t recv_packetnum, uint32_t sent_packetnum) static int handle_SYNC2(Lossless_UDP * ludp, int connection_id, uint8_t counter, uint32_t recv_packetnum, uint32_t sent_packetnum)
{ {
if (recv_packetnum == connections[connection_id].orecv_packetnum) { if (recv_packetnum == ludp->connections[connection_id].orecv_packetnum) {
/* && sent_packetnum == connections[connection_id].osent_packetnum) */ /* && sent_packetnum == ludp->connections[connection_id].osent_packetnum) */
connections[connection_id].status = 3; ludp->connections[connection_id].status = 3;
connections[connection_id].recv_counter = counter; ludp->connections[connection_id].recv_counter = counter;
++connections[connection_id].send_counter; ++ludp->connections[connection_id].send_counter;
send_SYNC(connection_id); send_SYNC(ludp, connection_id);
return 0; return 0;
} }
return 1; return 1;
} }
/* case 3 in handle_SYNC: */ /* case 3 in handle_SYNC: */
static int handle_SYNC3(int connection_id, uint8_t counter, uint32_t recv_packetnum, uint32_t sent_packetnum, static int handle_SYNC3(Lossless_UDP * ludp, int connection_id, uint8_t counter, uint32_t recv_packetnum, uint32_t sent_packetnum,
uint32_t *req_packets, uint32_t *req_packets,
uint16_t number) uint16_t number)
{ {
uint8_t comp_counter = (counter - connections[connection_id].recv_counter ); uint8_t comp_counter = (counter - ludp->connections[connection_id].recv_counter );
uint32_t i, temp; uint32_t i, temp;
/* uint32_t comp_1 = (recv_packetnum - connections[connection_id].successful_sent); /* uint32_t comp_1 = (recv_packetnum - ludp->connections[connection_id].successful_sent);
uint32_t comp_2 = (sent_packetnum - connections[connection_id].successful_read); */ uint32_t comp_2 = (sent_packetnum - ludp->connections[connection_id].successful_read); */
uint32_t comp_1 = (recv_packetnum - connections[connection_id].orecv_packetnum); uint32_t comp_1 = (recv_packetnum - ludp->connections[connection_id].orecv_packetnum);
uint32_t comp_2 = (sent_packetnum - connections[connection_id].osent_packetnum); uint32_t comp_2 = (sent_packetnum - ludp->connections[connection_id].osent_packetnum);
/* packet valid */ /* packet valid */
if (comp_1 <= BUFFER_PACKET_NUM && if (comp_1 <= BUFFER_PACKET_NUM &&
comp_2 <= BUFFER_PACKET_NUM && comp_2 <= BUFFER_PACKET_NUM &&
comp_counter < 10 && comp_counter != 0) { comp_counter < 10 && comp_counter != 0) {
connections[connection_id].orecv_packetnum = recv_packetnum; ludp->connections[connection_id].orecv_packetnum = recv_packetnum;
connections[connection_id].osent_packetnum = sent_packetnum; ludp->connections[connection_id].osent_packetnum = sent_packetnum;
connections[connection_id].successful_sent = recv_packetnum; ludp->connections[connection_id].successful_sent = recv_packetnum;
connections[connection_id].last_recvSYNC = current_time(); ludp->connections[connection_id].last_recvSYNC = current_time();
connections[connection_id].recv_counter = counter; ludp->connections[connection_id].recv_counter = counter;
++connections[connection_id].send_counter; ++ludp->connections[connection_id].send_counter;
for (i = 0; i < number; ++i) { for (i = 0; i < number; ++i) {
temp = ntohl(req_packets[i]); temp = ntohl(req_packets[i]);
memcpy(connections[connection_id].req_packets + i, &temp, 4 * number); memcpy(ludp->connections[connection_id].req_packets + i, &temp, 4 * number);
} }
connections[connection_id].num_req_paquets = number; ludp->connections[connection_id].num_req_paquets = number;
return 0; return 0;
} }
return 1; return 1;
} }
static int handle_SYNC(IP_Port source, uint8_t *packet, uint32_t length) static int handle_SYNC(void * object, IP_Port source, uint8_t *packet, uint32_t length)
{ {
Lossless_UDP * ludp = object;
if (!SYNC_valid(length)) if (!SYNC_valid(length))
return 1; return 1;
int connection = getconnection_id(source); int connection = getconnection_id(ludp, source);
uint8_t counter; uint8_t counter;
uint32_t temp; uint32_t temp;
uint32_t recv_packetnum, sent_packetnum; uint32_t recv_packetnum, sent_packetnum;
@ -729,14 +637,14 @@ static int handle_SYNC(IP_Port source, uint8_t *packet, uint32_t length)
memcpy(req_packets, packet + 10, 4 * number); memcpy(req_packets, packet + 10, 4 * number);
if (connection == -1) if (connection == -1)
return handle_SYNC1(source, recv_packetnum, sent_packetnum); return handle_SYNC1(ludp, source, recv_packetnum, sent_packetnum);
if (connections[connection].status == 2) if (ludp->connections[connection].status == 2)
return handle_SYNC2(connection, counter, return handle_SYNC2(ludp, connection, counter,
recv_packetnum, sent_packetnum); recv_packetnum, sent_packetnum);
if (connections[connection].status == 3) if (ludp->connections[connection].status == 3)
return handle_SYNC3(connection, counter, recv_packetnum, return handle_SYNC3(ludp, connection, counter, recv_packetnum,
sent_packetnum, req_packets, number); sent_packetnum, req_packets, number);
return 0; return 0;
@ -746,33 +654,33 @@ static int handle_SYNC(IP_Port source, uint8_t *packet, uint32_t length)
* Add a packet to the received buffer and set the recv_packetnum of the * Add a packet to the received buffer and set the recv_packetnum of the
* connection to its proper value. Return 1 if data was too big, 0 if not. * connection to its proper value. Return 1 if data was too big, 0 if not.
*/ */
static int add_recv(int connection_id, uint32_t data_num, uint8_t *data, uint16_t size) static int add_recv(Lossless_UDP * ludp, int connection_id, uint32_t data_num, uint8_t *data, uint16_t size)
{ {
if (size > MAX_DATA_SIZE) if (size > MAX_DATA_SIZE)
return 1; return 1;
uint32_t i; uint32_t i;
uint32_t maxnum = connections[connection_id].successful_read + BUFFER_PACKET_NUM; uint32_t maxnum = ludp->connections[connection_id].successful_read + BUFFER_PACKET_NUM;
uint32_t sent_packet = data_num - connections[connection_id].osent_packetnum; uint32_t sent_packet = data_num - ludp->connections[connection_id].osent_packetnum;
for (i = connections[connection_id].recv_packetnum; i != maxnum; ++i) { for (i = ludp->connections[connection_id].recv_packetnum; i != maxnum; ++i) {
if (i == data_num) { if (i == data_num) {
memcpy(connections[connection_id].recvbuffer[i % MAX_QUEUE_NUM].data, data, size); memcpy(ludp->connections[connection_id].recvbuffer[i % MAX_QUEUE_NUM].data, data, size);
connections[connection_id].recvbuffer[i % MAX_QUEUE_NUM].size = size; ludp->connections[connection_id].recvbuffer[i % MAX_QUEUE_NUM].size = size;
connections[connection_id].last_recvdata = current_time(); ludp->connections[connection_id].last_recvdata = current_time();
if (sent_packet < BUFFER_PACKET_NUM) { if (sent_packet < BUFFER_PACKET_NUM) {
connections[connection_id].osent_packetnum = data_num; ludp->connections[connection_id].osent_packetnum = data_num;
} }
break; break;
} }
} }
for (i = connections[connection_id].recv_packetnum; i != maxnum; ++i) { for (i = ludp->connections[connection_id].recv_packetnum; i != maxnum; ++i) {
if (connections[connection_id].recvbuffer[i % MAX_QUEUE_NUM].size != 0) if (ludp->connections[connection_id].recvbuffer[i % MAX_QUEUE_NUM].size != 0)
connections[connection_id].recv_packetnum = i; ludp->connections[connection_id].recv_packetnum = i;
else else
break; break;
} }
@ -780,15 +688,16 @@ static int add_recv(int connection_id, uint32_t data_num, uint8_t *data, uint16_
return 0; return 0;
} }
static int handle_data(IP_Port source, uint8_t *packet, uint32_t length) static int handle_data(void * object, IP_Port source, uint8_t *packet, uint32_t length)
{ {
int connection = getconnection_id(source); Lossless_UDP * ludp = object;
int connection = getconnection_id(ludp, source);
if (connection == -1) if (connection == -1)
return 1; return 1;
/* Drop the data packet if connection is not connected. */ /* Drop the data packet if connection is not connected. */
if (connections[connection].status != 3) if (ludp->connections[connection].status != 3)
return 1; return 1;
if (length > 1 + 4 + MAX_DATA_SIZE || length < 1 + 4 + 1) if (length > 1 + 4 + MAX_DATA_SIZE || length < 1 + 4 + 1)
@ -801,76 +710,81 @@ static int handle_data(IP_Port source, uint8_t *packet, uint32_t length)
memcpy(&temp, packet + 1, 4); memcpy(&temp, packet + 1, 4);
number = ntohl(temp); number = ntohl(temp);
return add_recv(connection, number, packet + 5, size); return add_recv(ludp, connection, number, packet + 5, size);
} }
/* /*
* END of packet handling functions * END of packet handling functions
*/ */
void LosslessUDP_init(void) Lossless_UDP * new_lossless_udp(Networking_Core * net)
{ {
networking_registerhandler(16, &handle_handshake); Lossless_UDP * temp = calloc(1, sizeof(Lossless_UDP));
networking_registerhandler(17, &handle_SYNC); if (temp == NULL)
networking_registerhandler(18, &handle_data); return NULL;
temp->net = net;
networking_registerhandler(net, 16, &handle_handshake, temp);
networking_registerhandler(net, 17, &handle_SYNC, temp);
networking_registerhandler(net, 18, &handle_data, temp);
return temp;
} }
/* /*
* Send handshake requests * Send handshake requests
* handshake packets are sent at the same rate as SYNC packets * handshake packets are sent at the same rate as SYNC packets
*/ */
static void doNew(void) static void do_new(Lossless_UDP * ludp)
{ {
uint32_t i; uint32_t i;
uint64_t temp_time = current_time(); uint64_t temp_time = current_time();
for (i = 0; i < MAX_CONNECTIONS; ++i) { for (i = 0; i < ludp->connections_length; ++i) {
if (connections[i].status == 1) if (ludp->connections[i].status == 1)
if ((connections[i].last_sent + (1000000UL / connections[i].SYNC_rate)) <= temp_time) { if ((ludp->connections[i].last_sent + (1000000UL / ludp->connections[i].SYNC_rate)) <= temp_time) {
send_handshake(connections[i].ip_port, connections[i].handshake_id1, 0); send_handshake(ludp, ludp->connections[i].ip_port, ludp->connections[i].handshake_id1, 0);
connections[i].last_sent = temp_time; ludp->connections[i].last_sent = temp_time;
} }
/* kill all timed out connections */ /* kill all timed out connections */
if (connections[i].status > 0 && if (ludp->connections[i].status > 0 &&
(connections[i].last_recvSYNC + connections[i].timeout * 1000000UL) < temp_time && (ludp->connections[i].last_recvSYNC + ludp->connections[i].timeout * 1000000UL) < temp_time &&
connections[i].status != 4) { ludp->connections[i].status != 4) {
connections[i].status = 4; ludp->connections[i].status = 4;
/* kill_connection(i); */ /* kill_connection(i); */
} }
if (connections[i].status > 0 && connections[i].killat < temp_time) if (ludp->connections[i].status > 0 && ludp->connections[i].killat < temp_time)
kill_connection(i); kill_connection(ludp, i);
} }
} }
static void doSYNC(void) static void do_SYNC(Lossless_UDP * ludp)
{ {
uint32_t i; uint32_t i;
uint64_t temp_time = current_time(); uint64_t temp_time = current_time();
for (i = 0; i < MAX_CONNECTIONS; ++i) { for (i = 0; i < ludp->connections_length; ++i) {
if (connections[i].status == 2 || connections[i].status == 3) if (ludp->connections[i].status == 2 || ludp->connections[i].status == 3)
if ((connections[i].last_SYNC + (1000000UL / connections[i].SYNC_rate)) <= temp_time) { if ((ludp->connections[i].last_SYNC + (1000000UL / ludp->connections[i].SYNC_rate)) <= temp_time) {
send_SYNC(i); send_SYNC(ludp, i);
connections[i].last_SYNC = temp_time; ludp->connections[i].last_SYNC = temp_time;
} }
} }
} }
static void doData(void) static void do_data(Lossless_UDP * ludp)
{ {
uint32_t i; uint32_t i;
uint64_t j; uint64_t j;
uint64_t temp_time = current_time(); uint64_t temp_time = current_time();
for (i = 0; i < MAX_CONNECTIONS; ++i) for (i = 0; i < ludp->connections_length; ++i)
if (connections[i].status == 3 && sendqueue(i) != 0) if (ludp->connections[i].status == 3 && sendqueue(ludp, i) != 0)
if ((connections[i].last_sent + (1000000UL / connections[i].data_rate)) <= temp_time) { if ((ludp->connections[i].last_sent + (1000000UL / ludp->connections[i].data_rate)) <= temp_time) {
for (j = connections[i].last_sent; j < temp_time; j += (1000000UL / connections[i].data_rate)) for (j = ludp->connections[i].last_sent; j < temp_time; j += (1000000UL / ludp->connections[i].data_rate))
send_DATA(i); send_DATA(ludp, i);
connections[i].last_sent = temp_time; ludp->connections[i].last_sent = temp_time;
} }
} }
@ -881,32 +795,38 @@ static void doData(void)
* *
* TODO: flow control. * TODO: flow control.
*/ */
static void adjustRates(void) static void adjust_rates(Lossless_UDP * ludp)
{ {
uint32_t i; uint32_t i;
uint64_t temp_time = current_time(); uint64_t temp_time = current_time();
for (i = 0; i < MAX_CONNECTIONS; ++i) { for (i = 0; i < ludp->connections_length; ++i) {
if (connections[i].status == 1 || connections[i].status == 2) if (ludp->connections[i].status == 1 || ludp->connections[i].status == 2)
connections[i].SYNC_rate = MAX_SYNC_RATE; ludp->connections[i].SYNC_rate = MAX_SYNC_RATE;
if (connections[i].status == 3) { if (ludp->connections[i].status == 3) {
if (sendqueue(i) != 0) { if (sendqueue(ludp, i) != 0) {
connections[i].data_rate = (BUFFER_PACKET_NUM - connections[i].num_req_paquets) * MAX_SYNC_RATE; ludp->connections[i].data_rate = (BUFFER_PACKET_NUM - ludp->connections[i].num_req_paquets) * MAX_SYNC_RATE;
connections[i].SYNC_rate = MAX_SYNC_RATE; ludp->connections[i].SYNC_rate = MAX_SYNC_RATE;
} else if (connections[i].last_recvdata + 1000000UL > temp_time) } else if (ludp->connections[i].last_recvdata + 1000000UL > temp_time)
connections[i].SYNC_rate = MAX_SYNC_RATE; ludp->connections[i].SYNC_rate = MAX_SYNC_RATE;
else else
connections[i].SYNC_rate = SYNC_RATE; ludp->connections[i].SYNC_rate = SYNC_RATE;
} }
} }
} }
/* Call this function a couple times per second It's the main loop. */ /* Call this function a couple times per second It's the main loop. */
void doLossless_UDP(void) void do_lossless_udp(Lossless_UDP * ludp)
{ {
doNew(); do_new(ludp);
doSYNC(); do_SYNC(ludp);
doData(); do_data(ludp);
adjustRates(); adjust_rates(ludp);
} }
void kill_lossless_udp(Lossless_UDP * ludp)
{
free(ludp->connections);
free(ludp);
}

View File

@ -33,72 +33,168 @@ extern "C" {
/* maximum length of the data in the data packets */ /* maximum length of the data in the data packets */
#define MAX_DATA_SIZE 1024 #define MAX_DATA_SIZE 1024
/* maximum data packets in sent and receive queues. */
#define MAX_QUEUE_NUM 16
/* maximum number of data packets in the buffer */
#define BUFFER_PACKET_NUM (16-1)
/* timeout per connection is randomly set between CONNEXION_TIMEOUT and 2*CONNEXION_TIMEOUT */
#define CONNEXION_TIMEOUT 5
/* initial amount of sync/hanshake packets to send per second. */
#define SYNC_RATE 2
/* initial send rate of data. */
#define DATA_SYNC_RATE 30
typedef struct {
uint8_t data[MAX_DATA_SIZE];
uint16_t size;
} Data;
typedef struct {
IP_Port ip_port;
/*
* 0 if connection is dead, 1 if attempting handshake,
* 2 if handshake is done (we start sending SYNC packets)
* 3 if we are sending SYNC packets and can send data
* 4 if the connection has timed out.
*/
uint8_t status;
/*
* 1 or 2 if connection was initiated by someone else, 0 if not.
* 2 if incoming_connection() has not returned it yet, 1 if it has.
*/
uint8_t inbound;
uint16_t SYNC_rate; /* current SYNC packet send rate packets per second. */
uint16_t data_rate; /* current data packet send rate packets per second. */
uint64_t last_SYNC; /* time our last SYNC packet was sent. */
uint64_t last_sent; /* time our last data or handshake packet was sent. */
uint64_t last_recvSYNC; /* time we last received a SYNC packet from the other */
uint64_t last_recvdata; /* time we last received a DATA packet from the other */
uint64_t killat; /* time to kill the connection */
Data sendbuffer[MAX_QUEUE_NUM]; /* packet send buffer. */
Data recvbuffer[MAX_QUEUE_NUM]; /* packet receive buffer. */
uint32_t handshake_id1;
uint32_t handshake_id2;
/* number of data packets received (also used as handshake_id1) */
uint32_t recv_packetnum;
/* number of packets received by the other peer */
uint32_t orecv_packetnum;
/* number of data packets sent */
uint32_t sent_packetnum;
/* number of packets sent by the other peer. */
uint32_t osent_packetnum;
/* number of latest packet written onto the sendbuffer */
uint32_t sendbuff_packetnum;
/* we know all packets before that number were successfully sent */
uint32_t successful_sent;
/* packet number of last packet read with the read_packet function */
uint32_t successful_read;
/* list of currently requested packet numbers(by the other person) */
uint32_t req_packets[BUFFER_PACKET_NUM];
/* total number of currently requested packets(by the other person) */
uint16_t num_req_paquets;
uint8_t recv_counter;
uint8_t send_counter;
uint8_t timeout; /* connection timeout in seconds. */
} Connection;
typedef struct {
Networking_Core *net;
Connection *connections;
uint32_t connections_length; /* Length of connections array */
uint32_t connections_number; /* Number of connections in connections array */
/* table of random numbers used in handshake_id. */
uint32_t randtable[6][256];
} Lossless_UDP;
/* /*
* Initialize a new connection to ip_port * Initialize a new connection to ip_port
* Returns an integer corresponding to the connection id. * Returns an integer corresponding to the connection id.
* Return -1 if it could not initialize the connection. * Return -1 if it could not initialize the connection.
* Return number if there already was an existing connection to that ip_port. * Return number if there already was an existing connection to that ip_port.
*/ */
int new_connection(IP_Port ip_port); int new_connection(Lossless_UDP * ludp, IP_Port ip_port);
/* /*
* Get connection id from IP_Port. * Get connection id from IP_Port.
* Return -1 if there are no connections like we are looking for. * Return -1 if there are no connections like we are looking for.
* Return id if it found it . * Return id if it found it .
*/ */
int getconnection_id(IP_Port ip_port); int getconnection_id(Lossless_UDP * ludp, IP_Port ip_port);
/* /*
* Returns an int corresponding to the next connection in our imcoming connection list * Returns an int corresponding to the next connection in our imcoming connection list
* Return -1 if there are no new incoming connections in the list. * Return -1 if there are no new incoming connections in the list.
*/ */
int incoming_connection(void); int incoming_connection(Lossless_UDP * ludp);
/* /*
* Return -1 if it could not kill the connection. * Return -1 if it could not kill the connection.
* Return 0 if killed successfully * Return 0 if killed successfully
*/ */
int kill_connection(int connection_id); int kill_connection(Lossless_UDP * ludp, int connection_id);
/* /*
* Kill connection in seconds seconds. * Kill connection in seconds seconds.
* Return -1 if it can not kill the connection. * Return -1 if it can not kill the connection.
* Return 0 if it will kill it * Return 0 if it will kill it
*/ */
int kill_connection_in(int connection_id, uint32_t seconds); int kill_connection_in(Lossless_UDP * ludp, int connection_id, uint32_t seconds);
/* /*
* Returns the ip_port of the corresponding connection. * Returns the ip_port of the corresponding connection.
* Return 0 if there is no such connection. * Return 0 if there is no such connection.
*/ */
IP_Port connection_ip(int connection_id); IP_Port connection_ip(Lossless_UDP * ludp, int connection_id);
/* /*
* Returns the id of the next packet in the queue * Returns the id of the next packet in the queue
* Return -1 if no packet in queue * Return -1 if no packet in queue
*/ */
char id_packet(int connection_id); char id_packet(Lossless_UDP * ludp, int connection_id);
/* /*
* Return 0 if there is no received data in the buffer. * Return 0 if there is no received data in the buffer.
* Return length of received packet if successful * Return length of received packet if successful
*/ */
int read_packet(int connection_id, uint8_t *data); int read_packet(Lossless_UDP * ludp, int connection_id, uint8_t *data);
/* /*
* Return 0 if data could not be put in packet queue * Return 0 if data could not be put in packet queue
* Return 1 if data was put into the queue * Return 1 if data was put into the queue
*/ */
int write_packet(int connection_id, uint8_t *data, uint32_t length); int write_packet(Lossless_UDP * ludp, int connection_id, uint8_t *data, uint32_t length);
/* Returns the number of packets in the queue waiting to be successfully sent. */ /* Returns the number of packets in the queue waiting to be successfully sent. */
uint32_t sendqueue(int connection_id); uint32_t sendqueue(Lossless_UDP * ludp, int connection_id);
/* /*
* returns the number of packets in the queue waiting to be successfully * returns the number of packets in the queue waiting to be successfully
* read with read_packet(...) * read with read_packet(...)
*/ */
uint32_t recvqueue(int connection_id); uint32_t recvqueue(Lossless_UDP * ludp, int connection_id);
/* Check if connection is connected: /* Check if connection is connected:
* Return 0 no. * Return 0 no.
@ -107,15 +203,17 @@ uint32_t recvqueue(int connection_id);
* Return 3 if fully connected. * Return 3 if fully connected.
* Return 4 if timed out and wating to be killed. * Return 4 if timed out and wating to be killed.
*/ */
int is_connected(int connection_id); int is_connected(Lossless_UDP * ludp, int connection_id);
/* Call this function a couple times per second It's the main loop. */ /* Call this function a couple times per second It's the main loop. */
void doLossless_UDP(void); void do_lossless_udp(Lossless_UDP * ludp);
/* /*
* This function sets up LosslessUDP packet handling. * This function sets up LosslessUDP packet handling.
*/ */
void LosslessUDP_init(void); Lossless_UDP * new_lossless_udp(Networking_Core * net);
void kill_lossless_udp(Lossless_UDP * ludp);
#ifdef __cplusplus #ifdef __cplusplus
} }

View File

@ -246,7 +246,7 @@ int m_delfriend(Messenger *m, int friendnumber)
return -1; return -1;
DHT_delfriend(m->friendlist[friendnumber].client_id); DHT_delfriend(m->friendlist[friendnumber].client_id);
crypto_kill(m->friendlist[friendnumber].crypt_connection_id); crypto_kill(m->net_crypto, m->friendlist[friendnumber].crypt_connection_id);
free(m->friendlist[friendnumber].statusmessage); free(m->friendlist[friendnumber].statusmessage);
memset(&(m->friendlist[friendnumber]), 0, sizeof(Friend)); memset(&(m->friendlist[friendnumber]), 0, sizeof(Friend));
uint32_t i; uint32_t i;
@ -606,7 +606,7 @@ int write_cryptpacket_id(Messenger *m, int friendnumber, uint8_t packet_id, uint
if (length != 0) if (length != 0)
memcpy(packet + 1, data, length); memcpy(packet + 1, data, length);
return write_cryptpacket(m->friendlist[friendnumber].crypt_connection_id, packet, length + 1); return write_cryptpacket(m->net_crypto, m->friendlist[friendnumber].crypt_connection_id, packet, length + 1);
} }
@ -626,21 +626,25 @@ int LANdiscovery(timer *t, void *arg)
Messenger *initMessenger(void) Messenger *initMessenger(void)
{ {
Messenger *m = calloc(1, sizeof(Messenger)); Messenger *m = calloc(1, sizeof(Messenger));
if ( ! m ) if ( ! m )
return 0; return 0;
new_keys();
m_set_statusmessage(m, (uint8_t *)"Online", sizeof("Online"));
initNetCrypto();
IP ip; IP ip;
ip.i = 0; ip.i = 0;
m->net = new_networking(ip, PORT);
if (init_networking(ip, PORT) == -1) if (m->net == NULL) {
return 0; free(m);
return NULL;
}
m->net_crypto = new_net_crypto(m->net);
if (m->net_crypto == NULL) {
free(m);
free(m->net);
return NULL;
}
new_keys(m->net_crypto);
m_set_statusmessage(m, (uint8_t *)"Online", sizeof("Online"));
DHT_init(); DHT_init();
LosslessUDP_init();
friendreq_init(); friendreq_init();
LANdiscovery_init(); LANdiscovery_init();
set_nospam(random_int()); set_nospam(random_int());
@ -657,6 +661,7 @@ void cleanupMessenger(Messenger *m)
/* FIXME TODO ideally cleanupMessenger will mirror initMessenger /* FIXME TODO ideally cleanupMessenger will mirror initMessenger
* this requires the other modules to expose cleanup functions * this requires the other modules to expose cleanup functions
*/ */
kill_net_crypto(m->net_crypto);
free(m->friendlist); free(m->friendlist);
free(m); free(m);
} }
@ -696,10 +701,10 @@ void doFriends(Messenger *m)
IP_Port friendip = DHT_getfriendip(m->friendlist[i].client_id); IP_Port friendip = DHT_getfriendip(m->friendlist[i].client_id);
switch (is_cryptoconnected(m->friendlist[i].crypt_connection_id)) { switch (is_cryptoconnected(m->net_crypto, m->friendlist[i].crypt_connection_id)) {
case 0: case 0:
if (friendip.ip.i > 1) if (friendip.ip.i > 1)
m->friendlist[i].crypt_connection_id = crypto_connect(m->friendlist[i].client_id, friendip); m->friendlist[i].crypt_connection_id = crypto_connect(m->net_crypto, m->friendlist[i].client_id, friendip);
break; break;
@ -712,7 +717,7 @@ void doFriends(Messenger *m)
break; break;
case 4: case 4:
crypto_kill(m->friendlist[i].crypt_connection_id); crypto_kill(m->net_crypto, m->friendlist[i].crypt_connection_id);
m->friendlist[i].crypt_connection_id = -1; m->friendlist[i].crypt_connection_id = -1;
break; break;
@ -741,7 +746,7 @@ void doFriends(Messenger *m)
send_ping(m, i); send_ping(m, i);
} }
len = read_cryptpacket(m->friendlist[i].crypt_connection_id, temp); len = read_cryptpacket(m->net_crypto, m->friendlist[i].crypt_connection_id, temp);
uint8_t packet_id = temp[0]; uint8_t packet_id = temp[0];
uint8_t *data = temp + 1; uint8_t *data = temp + 1;
int data_length = len - 1; int data_length = len - 1;
@ -833,8 +838,8 @@ void doFriends(Messenger *m)
} }
} }
} else { } else {
if (is_cryptoconnected(m->friendlist[i].crypt_connection_id) == 4) { /* if the connection timed out, kill it */ if (is_cryptoconnected(m->net_crypto, m->friendlist[i].crypt_connection_id) == 4) { /* if the connection timed out, kill it */
crypto_kill(m->friendlist[i].crypt_connection_id); crypto_kill(m->net_crypto, m->friendlist[i].crypt_connection_id);
m->friendlist[i].crypt_connection_id = -1; m->friendlist[i].crypt_connection_id = -1;
set_friend_status(m, i, FRIEND_CONFIRMED); set_friend_status(m, i, FRIEND_CONFIRMED);
} }
@ -844,7 +849,7 @@ void doFriends(Messenger *m)
if (m->friendlist[i].ping_lastrecv + FRIEND_CONNECTION_TIMEOUT < temp_time) { if (m->friendlist[i].ping_lastrecv + FRIEND_CONNECTION_TIMEOUT < temp_time) {
/* if we stopped recieving ping packets kill it */ /* if we stopped recieving ping packets kill it */
crypto_kill(m->friendlist[i].crypt_connection_id); crypto_kill(m->net_crypto, m->friendlist[i].crypt_connection_id);
m->friendlist[i].crypt_connection_id = -1; m->friendlist[i].crypt_connection_id = -1;
set_friend_status(m, i, FRIEND_CONFIRMED); set_friend_status(m, i, FRIEND_CONFIRMED);
} }
@ -857,15 +862,15 @@ void doInbound(Messenger *m)
uint8_t secret_nonce[crypto_box_NONCEBYTES]; uint8_t secret_nonce[crypto_box_NONCEBYTES];
uint8_t public_key[crypto_box_PUBLICKEYBYTES]; uint8_t public_key[crypto_box_PUBLICKEYBYTES];
uint8_t session_key[crypto_box_PUBLICKEYBYTES]; uint8_t session_key[crypto_box_PUBLICKEYBYTES];
int inconnection = crypto_inbound(public_key, secret_nonce, session_key); int inconnection = crypto_inbound(m->net_crypto, public_key, secret_nonce, session_key);
if (inconnection != -1) { if (inconnection != -1) {
int friend_id = getfriend_id(m, public_key); int friend_id = getfriend_id(m, public_key);
if (friend_id != -1) { if (friend_id != -1) {
crypto_kill(m->friendlist[friend_id].crypt_connection_id); crypto_kill(m->net_crypto, m->friendlist[friend_id].crypt_connection_id);
m->friendlist[friend_id].crypt_connection_id = m->friendlist[friend_id].crypt_connection_id =
accept_crypto_inbound(inconnection, public_key, secret_nonce, session_key); accept_crypto_inbound(m->net_crypto, inconnection, public_key, secret_nonce, session_key);
set_friend_status(m, friend_id, FRIEND_CONFIRMED); set_friend_status(m, friend_id, FRIEND_CONFIRMED);
} }
@ -873,14 +878,13 @@ void doInbound(Messenger *m)
} }
/* the main loop that needs to be run at least 200 times per second. */ /* the main loop that needs to be run at least 20 times per second. */
void doMessenger(Messenger *m) void doMessenger(Messenger *m)
{ {
networking_poll(); networking_poll(m->net);
doDHT(); doDHT();
doLossless_UDP(); do_net_crypto(m->net_crypto);
doNetCrypto();
doInbound(m); doInbound(m);
doFriends(m); doFriends(m);
@ -904,7 +908,7 @@ uint32_t Messenger_size(Messenger *m)
/* save the messenger in data of size Messenger_size() */ /* save the messenger in data of size Messenger_size() */
void Messenger_save(Messenger *m, uint8_t *data) void Messenger_save(Messenger *m, uint8_t *data)
{ {
save_keys(data); save_keys(m->net_crypto, data);
data += crypto_box_PUBLICKEYBYTES + crypto_box_SECRETKEYBYTES; data += crypto_box_PUBLICKEYBYTES + crypto_box_SECRETKEYBYTES;
uint32_t nospam = get_nospam(); uint32_t nospam = get_nospam();
memcpy(data, &nospam, sizeof(nospam)); memcpy(data, &nospam, sizeof(nospam));
@ -935,7 +939,7 @@ int Messenger_load(Messenger *m, uint8_t *data, uint32_t length)
return -1; return -1;
length -= crypto_box_PUBLICKEYBYTES + crypto_box_SECRETKEYBYTES + sizeof(uint32_t) * 3; length -= crypto_box_PUBLICKEYBYTES + crypto_box_SECRETKEYBYTES + sizeof(uint32_t) * 3;
load_keys(data); load_keys(m->net_crypto, data);
data += crypto_box_PUBLICKEYBYTES + crypto_box_SECRETKEYBYTES; data += crypto_box_PUBLICKEYBYTES + crypto_box_SECRETKEYBYTES;
uint32_t nospam; uint32_t nospam;
memcpy(&nospam, data, sizeof(nospam)); memcpy(&nospam, data, sizeof(nospam));

View File

@ -112,8 +112,9 @@ typedef struct {
} Friend; } Friend;
typedef struct Messenger { typedef struct Messenger {
uint8_t public_key[crypto_box_PUBLICKEYBYTES];
Networking_Core *net;
Net_Crypto * net_crypto;
uint8_t name[MAX_NAME_LENGTH]; uint8_t name[MAX_NAME_LENGTH];
uint16_t name_length; uint16_t name_length;

View File

@ -24,7 +24,7 @@
#include "friend_requests.h" #include "friend_requests.h"
uint8_t self_public_key[crypto_box_PUBLICKEYBYTES]; uint8_t self_public_key[crypto_box_PUBLICKEYBYTES];
uint8_t self_secret_key[crypto_box_SECRETKEYBYTES];
/* Try to send a friendrequest to peer with public_key /* Try to send a friendrequest to peer with public_key
data is the data in the request and length is the length. data is the data in the request and length is the length.
@ -40,7 +40,7 @@ int send_friendrequest(uint8_t *public_key, uint32_t nospam_num, uint8_t *data,
memcpy(temp, &nospam_num, sizeof(nospam_num)); memcpy(temp, &nospam_num, sizeof(nospam_num));
memcpy(temp + sizeof(nospam_num), data, length); memcpy(temp + sizeof(nospam_num), data, length);
uint8_t packet[MAX_DATA_SIZE]; uint8_t packet[MAX_DATA_SIZE];
int len = create_request(packet, public_key, temp, length + sizeof(nospam_num), int len = create_request(self_public_key, self_secret_key, packet, public_key, temp, length + sizeof(nospam_num),
32); /* 32 is friend request packet id */ 32); /* 32 is friend request packet id */
if (len == -1) if (len == -1)
@ -52,7 +52,7 @@ int send_friendrequest(uint8_t *public_key, uint32_t nospam_num, uint8_t *data,
return -1; return -1;
if (ip_port.ip.i != 0) { if (ip_port.ip.i != 0) {
if (sendpacket(ip_port, packet, len) != -1) if (sendpacket(temp_net->sock, ip_port, packet, len) != -1)
return 0; return 0;
return -1; return -1;
@ -146,5 +146,5 @@ static int friendreq_handlepacket(IP_Port source, uint8_t *source_pubkey, uint8_
void friendreq_init(void) void friendreq_init(void)
{ {
cryptopacket_registerhandler(32, &friendreq_handlepacket); cryptopacket_registerhandler(temp_net_crypto, 32, &friendreq_handlepacket);
} }

View File

@ -26,42 +26,12 @@
#include "net_crypto.h" #include "net_crypto.h"
/* Our public and secret keys. */
uint8_t self_public_key[crypto_box_PUBLICKEYBYTES];
uint8_t self_secret_key[crypto_box_SECRETKEYBYTES];
typedef struct {
uint8_t public_key[crypto_box_PUBLICKEYBYTES]; /* the real public key of the peer. */
uint8_t recv_nonce[crypto_box_NONCEBYTES]; /* nonce of received packets */
uint8_t sent_nonce[crypto_box_NONCEBYTES]; /* nonce of sent packets. */
uint8_t sessionpublic_key[crypto_box_PUBLICKEYBYTES]; /* our public key for this session. */
uint8_t sessionsecret_key[crypto_box_SECRETKEYBYTES]; /* our private key for this session. */
uint8_t peersessionpublic_key[crypto_box_PUBLICKEYBYTES]; /* The public key of the peer. */
uint8_t shared_key[crypto_box_BEFORENMBYTES]; /* the precomputed shared key from encrypt_precompute */
uint8_t status; /* 0 if no connection, 1 we have sent a handshake, 2 if connexion is not confirmed yet
(we have received a handshake but no empty data packet), 3 if the connection is established.
4 if the connection is timed out. */
uint16_t number; /* Lossless_UDP connection number corresponding to this connection. */
} Crypto_Connection;
static Crypto_Connection *crypto_connections;
static uint32_t crypto_connections_length; /* Length of connections array */
#define MAX_CRYPTO_CONNECTIONS crypto_connections_length
#define CONN_NO_CONNECTION 0 #define CONN_NO_CONNECTION 0
#define CONN_HANDSHAKE_SENT 1 #define CONN_HANDSHAKE_SENT 1
#define CONN_NOT_CONFIRMED 2 #define CONN_NOT_CONFIRMED 2
#define CONN_ESTABLISHED 3 #define CONN_ESTABLISHED 3
#define CONN_TIMED_OUT 4 #define CONN_TIMED_OUT 4
#define MAX_INCOMING 64
/* keeps track of the connection numbers for friends request so we can check later if they were sent */
static int incoming_connections[MAX_INCOMING];
/* Use this instead of memcmp; not vulnerable to timing attacks. */ /* Use this instead of memcmp; not vulnerable to timing attacks. */
uint8_t crypto_iszero(uint8_t *mem, uint32_t length) uint8_t crypto_iszero(uint8_t *mem, uint32_t length)
{ {
@ -175,16 +145,16 @@ void random_nonce(uint8_t *nonce)
/* return 0 if there is no received data in the buffer /* return 0 if there is no received data in the buffer
return -1 if the packet was discarded. return -1 if the packet was discarded.
return length of received data if successful */ return length of received data if successful */
int read_cryptpacket(int crypt_connection_id, uint8_t *data) int read_cryptpacket(Net_Crypto *c, int crypt_connection_id, uint8_t *data)
{ {
if (crypt_connection_id < 0 || crypt_connection_id >= MAX_CRYPTO_CONNECTIONS) if (crypt_connection_id < 0 || crypt_connection_id >= c->crypto_connections_length)
return 0; return 0;
if (crypto_connections[crypt_connection_id].status != CONN_ESTABLISHED) if (c->crypto_connections[crypt_connection_id].status != CONN_ESTABLISHED)
return 0; return 0;
uint8_t temp_data[MAX_DATA_SIZE]; uint8_t temp_data[MAX_DATA_SIZE];
int length = read_packet(crypto_connections[crypt_connection_id].number, temp_data); int length = read_packet(c->lossless_udp, c->crypto_connections[crypt_connection_id].number, temp_data);
if (length == 0) if (length == 0)
return 0; return 0;
@ -192,12 +162,12 @@ int read_cryptpacket(int crypt_connection_id, uint8_t *data)
if (temp_data[0] != 3) if (temp_data[0] != 3)
return -1; return -1;
int len = decrypt_data_fast(crypto_connections[crypt_connection_id].shared_key, int len = decrypt_data_fast(c->crypto_connections[crypt_connection_id].shared_key,
crypto_connections[crypt_connection_id].recv_nonce, c->crypto_connections[crypt_connection_id].recv_nonce,
temp_data + 1, length - 1, data); temp_data + 1, length - 1, data);
if (len != -1) { if (len != -1) {
increment_nonce(crypto_connections[crypt_connection_id].recv_nonce); increment_nonce(c->crypto_connections[crypt_connection_id].recv_nonce);
return len; return len;
} }
@ -206,20 +176,20 @@ int read_cryptpacket(int crypt_connection_id, uint8_t *data)
/* return 0 if data could not be put in packet queue /* return 0 if data could not be put in packet queue
return 1 if data was put into the queue */ return 1 if data was put into the queue */
int write_cryptpacket(int crypt_connection_id, uint8_t *data, uint32_t length) int write_cryptpacket(Net_Crypto *c, int crypt_connection_id, uint8_t *data, uint32_t length)
{ {
if (crypt_connection_id < 0 || crypt_connection_id >= MAX_CRYPTO_CONNECTIONS) if (crypt_connection_id < 0 || crypt_connection_id >= c->crypto_connections_length)
return 0; return 0;
if (length - crypto_box_BOXZEROBYTES + crypto_box_ZEROBYTES > MAX_DATA_SIZE - 1) if (length - crypto_box_BOXZEROBYTES + crypto_box_ZEROBYTES > MAX_DATA_SIZE - 1)
return 0; return 0;
if (crypto_connections[crypt_connection_id].status != CONN_ESTABLISHED) if (c->crypto_connections[crypt_connection_id].status != CONN_ESTABLISHED)
return 0; return 0;
uint8_t temp_data[MAX_DATA_SIZE]; uint8_t temp_data[MAX_DATA_SIZE];
int len = encrypt_data_fast(crypto_connections[crypt_connection_id].shared_key, int len = encrypt_data_fast(c->crypto_connections[crypt_connection_id].shared_key,
crypto_connections[crypt_connection_id].sent_nonce, c->crypto_connections[crypt_connection_id].sent_nonce,
data, length, temp_data + 1); data, length, temp_data + 1);
if (len == -1) if (len == -1)
@ -227,20 +197,22 @@ int write_cryptpacket(int crypt_connection_id, uint8_t *data, uint32_t length)
temp_data[0] = 3; temp_data[0] = 3;
if (write_packet(crypto_connections[crypt_connection_id].number, temp_data, len + 1) == 0) if (write_packet(c->lossless_udp, c->crypto_connections[crypt_connection_id].number, temp_data, len + 1) == 0)
return 0; return 0;
increment_nonce(crypto_connections[crypt_connection_id].sent_nonce); increment_nonce(c->crypto_connections[crypt_connection_id].sent_nonce);
return 1; return 1;
} }
/* create a request to peer with public_key. /* create a request to peer.
send_public_key and send_secret_key are the pub/secret keys of the sender
recv_public_key is public key of reciever
packet must be an array of MAX_DATA_SIZE big. packet must be an array of MAX_DATA_SIZE big.
Data represents the data we send with the request with length being the length of the data. Data represents the data we send with the request with length being the length of the data.
request_id is the id of the request (32 = friend request, 254 = ping request) request_id is the id of the request (32 = friend request, 254 = ping request)
returns -1 on failure returns -1 on failure
returns the length of the created packet on success */ returns the length of the created packet on success */
int create_request(uint8_t *packet, uint8_t *public_key, uint8_t *data, uint32_t length, uint8_t request_id) int create_request(uint8_t *send_public_key, uint8_t *send_secret_key, uint8_t *packet, uint8_t *recv_public_key, uint8_t *data, uint32_t length, uint8_t request_id)
{ {
if (MAX_DATA_SIZE < length + 1 + crypto_box_PUBLICKEYBYTES * 2 + crypto_box_NONCEBYTES + 1 + ENCRYPTION_PADDING) if (MAX_DATA_SIZE < length + 1 + crypto_box_PUBLICKEYBYTES * 2 + crypto_box_NONCEBYTES + 1 + ENCRYPTION_PADDING)
return -1; return -1;
@ -250,15 +222,15 @@ int create_request(uint8_t *packet, uint8_t *public_key, uint8_t *data, uint32_t
memcpy(temp + 1, data, length); memcpy(temp + 1, data, length);
temp[0] = request_id; temp[0] = request_id;
random_nonce(nonce); random_nonce(nonce);
int len = encrypt_data(public_key, self_secret_key, nonce, temp, length + 1, int len = encrypt_data(recv_public_key, send_secret_key, nonce, temp, length + 1,
1 + crypto_box_PUBLICKEYBYTES * 2 + crypto_box_NONCEBYTES + packet); 1 + crypto_box_PUBLICKEYBYTES * 2 + crypto_box_NONCEBYTES + packet);
if (len == -1) if (len == -1)
return -1; return -1;
packet[0] = 32; packet[0] = 32;
memcpy(packet + 1, public_key, crypto_box_PUBLICKEYBYTES); memcpy(packet + 1, recv_public_key, crypto_box_PUBLICKEYBYTES);
memcpy(packet + 1 + crypto_box_PUBLICKEYBYTES, self_public_key, crypto_box_PUBLICKEYBYTES); memcpy(packet + 1 + crypto_box_PUBLICKEYBYTES, send_public_key, crypto_box_PUBLICKEYBYTES);
memcpy(packet + 1 + crypto_box_PUBLICKEYBYTES * 2, nonce, crypto_box_NONCEBYTES); memcpy(packet + 1 + crypto_box_PUBLICKEYBYTES * 2, nonce, crypto_box_NONCEBYTES);
return len + 1 + crypto_box_PUBLICKEYBYTES * 2 + crypto_box_NONCEBYTES; return len + 1 + crypto_box_PUBLICKEYBYTES * 2 + crypto_box_NONCEBYTES;
@ -268,17 +240,17 @@ int create_request(uint8_t *packet, uint8_t *public_key, uint8_t *data, uint32_t
in data if a friend or ping request was sent to us and returns the length of the data. in data if a friend or ping request was sent to us and returns the length of the data.
packet is the request packet and length is its length packet is the request packet and length is its length
return -1 if not valid request. */ return -1 if not valid request. */
static int handle_request(uint8_t *public_key, uint8_t *data, uint8_t *request_id, uint8_t *packet, uint16_t length) static int handle_request(Net_Crypto *c, uint8_t *public_key, uint8_t *data, uint8_t *request_id, uint8_t *packet, uint16_t length)
{ {
if (length > crypto_box_PUBLICKEYBYTES * 2 + crypto_box_NONCEBYTES + 1 + ENCRYPTION_PADDING && if (length > crypto_box_PUBLICKEYBYTES * 2 + crypto_box_NONCEBYTES + 1 + ENCRYPTION_PADDING &&
length <= MAX_DATA_SIZE + ENCRYPTION_PADDING && length <= MAX_DATA_SIZE + ENCRYPTION_PADDING &&
memcmp(packet + 1, self_public_key, crypto_box_PUBLICKEYBYTES) == 0) { memcmp(packet + 1, c->self_public_key, crypto_box_PUBLICKEYBYTES) == 0) {
memcpy(public_key, packet + 1 + crypto_box_PUBLICKEYBYTES, crypto_box_PUBLICKEYBYTES); memcpy(public_key, packet + 1 + crypto_box_PUBLICKEYBYTES, crypto_box_PUBLICKEYBYTES);
uint8_t nonce[crypto_box_NONCEBYTES]; uint8_t nonce[crypto_box_NONCEBYTES];
uint8_t temp[MAX_DATA_SIZE]; uint8_t temp[MAX_DATA_SIZE];
memcpy(nonce, packet + 1 + crypto_box_PUBLICKEYBYTES * 2, crypto_box_NONCEBYTES); memcpy(nonce, packet + 1 + crypto_box_PUBLICKEYBYTES * 2, crypto_box_NONCEBYTES);
int len1 = decrypt_data(public_key, self_secret_key, nonce, int len1 = decrypt_data(public_key, c->self_secret_key, nonce,
packet + 1 + crypto_box_PUBLICKEYBYTES * 2 + crypto_box_NONCEBYTES, packet + 1 + crypto_box_PUBLICKEYBYTES * 2 + crypto_box_NONCEBYTES,
length - (crypto_box_PUBLICKEYBYTES * 2 + crypto_box_NONCEBYTES + 1), temp); length - (crypto_box_PUBLICKEYBYTES * 2 + crypto_box_NONCEBYTES + 1), temp);
@ -293,15 +265,14 @@ static int handle_request(uint8_t *public_key, uint8_t *data, uint8_t *request_i
return -1; return -1;
} }
static cryptopacket_handler_callback cryptopackethandlers[256] = {0}; void cryptopacket_registerhandler(Net_Crypto *c, uint8_t byte, cryptopacket_handler_callback cb)
void cryptopacket_registerhandler(uint8_t byte, cryptopacket_handler_callback cb)
{ {
cryptopackethandlers[byte] = cb; c->cryptopackethandlers[byte] = cb;
} }
static int cryptopacket_handle(IP_Port source, uint8_t *packet, uint32_t length) static int cryptopacket_handle(void *object, IP_Port source, uint8_t *packet, uint32_t length)
{ {
Net_Crypto *c = object;
if (packet[0] == 32) { if (packet[0] == 32) {
if (length <= crypto_box_PUBLICKEYBYTES * 2 + crypto_box_NONCEBYTES + 1 + ENCRYPTION_PADDING || if (length <= crypto_box_PUBLICKEYBYTES * 2 + crypto_box_NONCEBYTES + 1 + ENCRYPTION_PADDING ||
length > MAX_DATA_SIZE + ENCRYPTION_PADDING) length > MAX_DATA_SIZE + ENCRYPTION_PADDING)
@ -311,17 +282,17 @@ static int cryptopacket_handle(IP_Port source, uint8_t *packet, uint32_t length)
uint8_t public_key[crypto_box_PUBLICKEYBYTES]; uint8_t public_key[crypto_box_PUBLICKEYBYTES];
uint8_t data[MAX_DATA_SIZE]; uint8_t data[MAX_DATA_SIZE];
uint8_t number; uint8_t number;
int len = handle_request(public_key, data, &number, packet, length); int len = handle_request(c, public_key, data, &number, packet, length);
if (len == -1 || len == 0) if (len == -1 || len == 0)
return 1; return 1;
if (!cryptopackethandlers[number]) return 1; if (!c->cryptopackethandlers[number]) return 1;
cryptopackethandlers[number](source, public_key, data, len); c->cryptopackethandlers[number](source, public_key, data, len);
} else { /* if request is not for us, try routing it. */ } else { /* if request is not for us, try routing it. */
if (route_packet(packet + 1, packet, length) == length) if (route_packet(packet + 1, packet, length) == length) //NOTE
return 0; return 0;
} }
} }
@ -332,7 +303,7 @@ static int cryptopacket_handle(IP_Port source, uint8_t *packet, uint32_t length)
/* Send a crypto handshake packet containing an encrypted secret nonce and session public key /* Send a crypto handshake packet containing an encrypted secret nonce and session public key
to peer with connection_id and public_key to peer with connection_id and public_key
the packet is encrypted with a random nonce which is sent in plain text with the packet */ the packet is encrypted with a random nonce which is sent in plain text with the packet */
static int send_cryptohandshake(int connection_id, uint8_t *public_key, uint8_t *secret_nonce, uint8_t *session_key) static int send_cryptohandshake(Net_Crypto *c, int connection_id, uint8_t *public_key, uint8_t *secret_nonce, uint8_t *session_key)
{ {
uint8_t temp_data[MAX_DATA_SIZE]; uint8_t temp_data[MAX_DATA_SIZE];
uint8_t temp[crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES]; uint8_t temp[crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES];
@ -342,22 +313,22 @@ static int send_cryptohandshake(int connection_id, uint8_t *public_key, uint8_t
memcpy(temp, secret_nonce, crypto_box_NONCEBYTES); memcpy(temp, secret_nonce, crypto_box_NONCEBYTES);
memcpy(temp + crypto_box_NONCEBYTES, session_key, crypto_box_PUBLICKEYBYTES); memcpy(temp + crypto_box_NONCEBYTES, session_key, crypto_box_PUBLICKEYBYTES);
int len = encrypt_data(public_key, self_secret_key, nonce, temp, crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES, int len = encrypt_data(public_key, c->self_secret_key, nonce, temp, crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES,
1 + crypto_box_PUBLICKEYBYTES + crypto_box_NONCEBYTES + temp_data); 1 + crypto_box_PUBLICKEYBYTES + crypto_box_NONCEBYTES + temp_data);
if (len == -1) if (len == -1)
return 0; return 0;
temp_data[0] = 2; temp_data[0] = 2;
memcpy(temp_data + 1, self_public_key, crypto_box_PUBLICKEYBYTES); memcpy(temp_data + 1, c->self_public_key, crypto_box_PUBLICKEYBYTES);
memcpy(temp_data + 1 + crypto_box_PUBLICKEYBYTES, nonce, crypto_box_NONCEBYTES); memcpy(temp_data + 1 + crypto_box_PUBLICKEYBYTES, nonce, crypto_box_NONCEBYTES);
return write_packet(connection_id, temp_data, len + 1 + crypto_box_PUBLICKEYBYTES + crypto_box_NONCEBYTES); return write_packet(c->lossless_udp, connection_id, temp_data, len + 1 + crypto_box_PUBLICKEYBYTES + crypto_box_NONCEBYTES);
} }
/* Extract secret nonce, session public key and public_key from a packet(data) with length length /* Extract secret nonce, session public key and public_key from a packet(data) with length length
return 1 if successful return 1 if successful
return 0 if failure */ return 0 if failure */
static int handle_cryptohandshake(uint8_t *public_key, uint8_t *secret_nonce, static int handle_cryptohandshake(Net_Crypto *c, uint8_t *public_key, uint8_t *secret_nonce,
uint8_t *session_key, uint8_t *data, uint16_t length) uint8_t *session_key, uint8_t *data, uint16_t length)
{ {
int pad = (- crypto_box_BOXZEROBYTES + crypto_box_ZEROBYTES); int pad = (- crypto_box_BOXZEROBYTES + crypto_box_ZEROBYTES);
@ -374,7 +345,7 @@ static int handle_cryptohandshake(uint8_t *public_key, uint8_t *secret_nonce,
memcpy(public_key, data + 1, crypto_box_PUBLICKEYBYTES); memcpy(public_key, data + 1, crypto_box_PUBLICKEYBYTES);
int len = decrypt_data(public_key, self_secret_key, data + 1 + crypto_box_PUBLICKEYBYTES, int len = decrypt_data(public_key, c->self_secret_key, data + 1 + crypto_box_PUBLICKEYBYTES,
data + 1 + crypto_box_PUBLICKEYBYTES + crypto_box_NONCEBYTES, data + 1 + crypto_box_PUBLICKEYBYTES + crypto_box_NONCEBYTES,
crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES + pad, temp); crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES + pad, temp);
@ -389,13 +360,13 @@ static int handle_cryptohandshake(uint8_t *public_key, uint8_t *secret_nonce,
/* get crypto connection id from public key of peer /* get crypto connection id from public key of peer
return -1 if there are no connections like we are looking for return -1 if there are no connections like we are looking for
return id if it found it */ return id if it found it */
static int getcryptconnection_id(uint8_t *public_key) static int getcryptconnection_id(Net_Crypto *c, uint8_t *public_key)
{ {
uint32_t i; uint32_t i;
for (i = 0; i < MAX_CRYPTO_CONNECTIONS; ++i) { for (i = 0; i < c->crypto_connections_length; ++i) {
if (crypto_connections[i].status != CONN_NO_CONNECTION) if (c->crypto_connections[i].status != CONN_NO_CONNECTION)
if (memcmp(public_key, crypto_connections[i].public_key, crypto_box_PUBLICKEYBYTES) == 0) if (memcmp(public_key, c->crypto_connections[i].public_key, crypto_box_PUBLICKEYBYTES) == 0)
return i; return i;
} }
@ -404,63 +375,63 @@ static int getcryptconnection_id(uint8_t *public_key)
/* set the size of the friend list to numfriends /* set the size of the friend list to numfriends
return -1 if realloc fails */ return -1 if realloc fails */
int realloc_cryptoconnection(uint32_t num) int realloc_cryptoconnection(Net_Crypto *c, uint32_t num)
{ {
if (num == 0) { if (num == 0) {
free(crypto_connections); free(c->crypto_connections);
crypto_connections = NULL; c->crypto_connections = NULL;
return 0; return 0;
} }
Crypto_Connection *newcrypto_connections = realloc(crypto_connections, num * sizeof(Crypto_Connection)); Crypto_Connection *newcrypto_connections = realloc(c->crypto_connections, num * sizeof(Crypto_Connection));
if (newcrypto_connections == NULL) if (newcrypto_connections == NULL)
return -1; return -1;
crypto_connections = newcrypto_connections; c->crypto_connections = newcrypto_connections;
return 0; return 0;
} }
/* Start a secure connection with other peer who has public_key and ip_port /* Start a secure connection with other peer who has public_key and ip_port
returns -1 if failure returns -1 if failure
returns crypt_connection_id of the initialized connection if everything went well. */ returns crypt_connection_id of the initialized connection if everything went well. */
int crypto_connect(uint8_t *public_key, IP_Port ip_port) int crypto_connect(Net_Crypto *c, uint8_t *public_key, IP_Port ip_port)
{ {
uint32_t i; uint32_t i;
int id = getcryptconnection_id(public_key); int id = getcryptconnection_id(c, public_key);
if (id != -1) { if (id != -1) {
IP_Port c_ip = connection_ip(crypto_connections[id].number); IP_Port c_ip = connection_ip(c->lossless_udp, c->crypto_connections[id].number);
if (c_ip.ip.i == ip_port.ip.i && c_ip.port == ip_port.port) if (c_ip.ip.i == ip_port.ip.i && c_ip.port == ip_port.port)
return -1; return -1;
} }
if (realloc_cryptoconnection(crypto_connections_length + 1) == -1) if (realloc_cryptoconnection(c, c->crypto_connections_length + 1) == -1)
return -1; return -1;
memset(&crypto_connections[crypto_connections_length], 0, sizeof(Crypto_Connection)); memset(&(c->crypto_connections[c->crypto_connections_length]), 0, sizeof(Crypto_Connection));
crypto_connections[crypto_connections_length].number = ~0; c->crypto_connections[c->crypto_connections_length].number = ~0;
for (i = 0; i <= MAX_CRYPTO_CONNECTIONS; ++i) { for (i = 0; i <= c->crypto_connections_length; ++i) {
if (crypto_connections[i].status == CONN_NO_CONNECTION) { if (c->crypto_connections[i].status == CONN_NO_CONNECTION) {
int id = new_connection(ip_port); int id = new_connection(c->lossless_udp, ip_port);
if (id == -1) if (id == -1)
return -1; return -1;
crypto_connections[i].number = id; c->crypto_connections[i].number = id;
crypto_connections[i].status = CONN_HANDSHAKE_SENT; c->crypto_connections[i].status = CONN_HANDSHAKE_SENT;
random_nonce(crypto_connections[i].recv_nonce); random_nonce(c->crypto_connections[i].recv_nonce);
memcpy(crypto_connections[i].public_key, public_key, crypto_box_PUBLICKEYBYTES); memcpy(c->crypto_connections[i].public_key, public_key, crypto_box_PUBLICKEYBYTES);
crypto_box_keypair(crypto_connections[i].sessionpublic_key, crypto_connections[i].sessionsecret_key); crypto_box_keypair(c->crypto_connections[i].sessionpublic_key, c->crypto_connections[i].sessionsecret_key);
if (crypto_connections_length == i) if (c->crypto_connections_length == i)
++crypto_connections_length; ++c->crypto_connections_length;
if (send_cryptohandshake(id, public_key, crypto_connections[i].recv_nonce, if (send_cryptohandshake(c, id, public_key, c->crypto_connections[i].recv_nonce,
crypto_connections[i].sessionpublic_key) == 1) { c->crypto_connections[i].sessionpublic_key) == 1) {
increment_nonce(crypto_connections[i].recv_nonce); increment_nonce(c->crypto_connections[i].recv_nonce);
return i; return i;
} }
@ -478,25 +449,25 @@ int crypto_connect(uint8_t *public_key, IP_Port ip_port)
and the session public key for the connection in session_key and the session public key for the connection in session_key
to accept it see: accept_crypto_inbound(...) to accept it see: accept_crypto_inbound(...)
to refuse it just call kill_connection(...) on the connection id */ to refuse it just call kill_connection(...) on the connection id */
int crypto_inbound(uint8_t *public_key, uint8_t *secret_nonce, uint8_t *session_key) int crypto_inbound(Net_Crypto *c, uint8_t *public_key, uint8_t *secret_nonce, uint8_t *session_key)
{ {
uint32_t i; uint32_t i;
for (i = 0; i < MAX_INCOMING; ++i) { for (i = 0; i < MAX_INCOMING; ++i) {
if (incoming_connections[i] != -1) { if (c->incoming_connections[i] != -1) {
if (is_connected(incoming_connections[i]) == 4 || is_connected(incoming_connections[i]) == 0) { if (is_connected(c->lossless_udp, c->incoming_connections[i]) == 4 || is_connected(c->lossless_udp, c->incoming_connections[i]) == 0) {
kill_connection(incoming_connections[i]); kill_connection(c->lossless_udp, c->incoming_connections[i]);
incoming_connections[i] = -1; c->incoming_connections[i] = -1;
continue; continue;
} }
if (id_packet(incoming_connections[i]) == 2) { if (id_packet(c->lossless_udp, c->incoming_connections[i]) == 2) {
uint8_t temp_data[MAX_DATA_SIZE]; uint8_t temp_data[MAX_DATA_SIZE];
uint16_t len = read_packet(incoming_connections[i], temp_data); uint16_t len = read_packet(c->lossless_udp, c->incoming_connections[i], temp_data);
if (handle_cryptohandshake(public_key, secret_nonce, session_key, temp_data, len)) { if (handle_cryptohandshake(c, public_key, secret_nonce, session_key, temp_data, len)) {
int connection_id = incoming_connections[i]; int connection_id = c->incoming_connections[i];
incoming_connections[i] = -1; /* remove this connection from the incoming connection list. */ c->incoming_connections[i] = -1; /* remove this connection from the incoming connection list. */
return connection_id; return connection_id;
} }
} }
@ -509,25 +480,25 @@ int crypto_inbound(uint8_t *public_key, uint8_t *secret_nonce, uint8_t *session_
/* kill a crypto connection /* kill a crypto connection
return 0 if killed successfully return 0 if killed successfully
return 1 if there was a problem. */ return 1 if there was a problem. */
int crypto_kill(int crypt_connection_id) int crypto_kill(Net_Crypto *c, int crypt_connection_id)
{ {
if (crypt_connection_id < 0 || crypt_connection_id >= MAX_CRYPTO_CONNECTIONS) if (crypt_connection_id < 0 || crypt_connection_id >= c->crypto_connections_length)
return 1; return 1;
if (crypto_connections[crypt_connection_id].status != CONN_NO_CONNECTION) { if (c->crypto_connections[crypt_connection_id].status != CONN_NO_CONNECTION) {
crypto_connections[crypt_connection_id].status = CONN_NO_CONNECTION; c->crypto_connections[crypt_connection_id].status = CONN_NO_CONNECTION;
kill_connection(crypto_connections[crypt_connection_id].number); kill_connection(c->lossless_udp, c->crypto_connections[crypt_connection_id].number);
memset(&crypto_connections[crypt_connection_id], 0 , sizeof(Crypto_Connection)); memset(&(c->crypto_connections[crypt_connection_id]), 0 , sizeof(Crypto_Connection));
crypto_connections[crypt_connection_id].number = ~0; c->crypto_connections[crypt_connection_id].number = ~0;
uint32_t i; uint32_t i;
for (i = crypto_connections_length; i != 0; --i) { for (i = c->crypto_connections_length; i != 0; --i) {
if (crypto_connections[i - 1].status != CONN_NO_CONNECTION) if (c->crypto_connections[i - 1].status != CONN_NO_CONNECTION)
break; break;
} }
crypto_connections_length = i; c->crypto_connections_length = i;
realloc_cryptoconnection(crypto_connections_length); realloc_cryptoconnection(c, c->crypto_connections_length);
return 0; return 0;
} }
@ -537,7 +508,7 @@ int crypto_kill(int crypt_connection_id)
/* accept an incoming connection using the parameters provided by crypto_inbound /* accept an incoming connection using the parameters provided by crypto_inbound
return -1 if not successful return -1 if not successful
returns the crypt_connection_id if successful */ returns the crypt_connection_id if successful */
int accept_crypto_inbound(int connection_id, uint8_t *public_key, uint8_t *secret_nonce, uint8_t *session_key) int accept_crypto_inbound(Net_Crypto *c, int connection_id, uint8_t *public_key, uint8_t *secret_nonce, uint8_t *session_key)
{ {
uint32_t i; uint32_t i;
@ -549,37 +520,37 @@ int accept_crypto_inbound(int connection_id, uint8_t *public_key, uint8_t *secre
{ {
return -1; return -1;
}*/ }*/
if (realloc_cryptoconnection(crypto_connections_length + 1) == -1) if (realloc_cryptoconnection(c, c->crypto_connections_length + 1) == -1)
return -1; return -1;
memset(&crypto_connections[crypto_connections_length], 0, sizeof(Crypto_Connection)); memset(&(c->crypto_connections[c->crypto_connections_length]), 0, sizeof(Crypto_Connection));
crypto_connections[crypto_connections_length].number = ~0; c->crypto_connections[c->crypto_connections_length].number = ~0;
for (i = 0; i <= MAX_CRYPTO_CONNECTIONS; ++i) { for (i = 0; i <= c->crypto_connections_length; ++i) {
if (crypto_connections[i].status == CONN_NO_CONNECTION) { if (c->crypto_connections[i].status == CONN_NO_CONNECTION) {
crypto_connections[i].number = connection_id; c->crypto_connections[i].number = connection_id;
crypto_connections[i].status = CONN_NOT_CONFIRMED; c->crypto_connections[i].status = CONN_NOT_CONFIRMED;
random_nonce(crypto_connections[i].recv_nonce); random_nonce(c->crypto_connections[i].recv_nonce);
memcpy(crypto_connections[i].sent_nonce, secret_nonce, crypto_box_NONCEBYTES); memcpy(c->crypto_connections[i].sent_nonce, secret_nonce, crypto_box_NONCEBYTES);
memcpy(crypto_connections[i].peersessionpublic_key, session_key, crypto_box_PUBLICKEYBYTES); memcpy(c->crypto_connections[i].peersessionpublic_key, session_key, crypto_box_PUBLICKEYBYTES);
increment_nonce(crypto_connections[i].sent_nonce); increment_nonce(c->crypto_connections[i].sent_nonce);
memcpy(crypto_connections[i].public_key, public_key, crypto_box_PUBLICKEYBYTES); memcpy(c->crypto_connections[i].public_key, public_key, crypto_box_PUBLICKEYBYTES);
crypto_box_keypair(crypto_connections[i].sessionpublic_key, crypto_connections[i].sessionsecret_key); crypto_box_keypair(c->crypto_connections[i].sessionpublic_key, c->crypto_connections[i].sessionsecret_key);
if (crypto_connections_length == i) if (c->crypto_connections_length == i)
++crypto_connections_length; ++c->crypto_connections_length;
if (send_cryptohandshake(connection_id, public_key, crypto_connections[i].recv_nonce, if (send_cryptohandshake(c, connection_id, public_key, c->crypto_connections[i].recv_nonce,
crypto_connections[i].sessionpublic_key) == 1) { c->crypto_connections[i].sessionpublic_key) == 1) {
increment_nonce(crypto_connections[i].recv_nonce); increment_nonce(c->crypto_connections[i].recv_nonce);
uint32_t zero = 0; uint32_t zero = 0;
encrypt_precompute(crypto_connections[i].peersessionpublic_key, encrypt_precompute(c->crypto_connections[i].peersessionpublic_key,
crypto_connections[i].sessionsecret_key, c->crypto_connections[i].sessionsecret_key,
crypto_connections[i].shared_key); c->crypto_connections[i].shared_key);
crypto_connections[i].status = CONN_ESTABLISHED; /* connection status needs to be 3 for write_cryptpacket() to work */ c->crypto_connections[i].status = CONN_ESTABLISHED; /* connection status needs to be 3 for write_cryptpacket() to work */
write_cryptpacket(i, ((uint8_t *)&zero), sizeof(zero)); write_cryptpacket(c, i, ((uint8_t *)&zero), sizeof(zero));
crypto_connections[i].status = CONN_NOT_CONFIRMED; /* set it to its proper value right after. */ c->crypto_connections[i].status = CONN_NOT_CONFIRMED; /* set it to its proper value right after. */
return i; return i;
} }
@ -593,48 +564,54 @@ int accept_crypto_inbound(int connection_id, uint8_t *public_key, uint8_t *secre
/* return 0 if no connection, 1 we have sent a handshake, 2 if connection is not confirmed yet /* return 0 if no connection, 1 we have sent a handshake, 2 if connection is not confirmed yet
(we have received a handshake but no empty data packet), 3 if the connection is established. (we have received a handshake but no empty data packet), 3 if the connection is established.
4 if the connection is timed out and waiting to be killed */ 4 if the connection is timed out and waiting to be killed */
int is_cryptoconnected(int crypt_connection_id) int is_cryptoconnected(Net_Crypto *c, int crypt_connection_id)
{ {
if (crypt_connection_id >= 0 && crypt_connection_id < MAX_CRYPTO_CONNECTIONS) if (crypt_connection_id >= 0 && crypt_connection_id < c->crypto_connections_length)
return crypto_connections[crypt_connection_id].status; return c->crypto_connections[crypt_connection_id].status;
return CONN_NO_CONNECTION; return CONN_NO_CONNECTION;
} }
/* Generate our public and private keys /* Generate our public and private keys
Only call this function the first time the program starts. */ Only call this function the first time the program starts. */
void new_keys(void)
extern uint8_t self_public_key[crypto_box_PUBLICKEYBYTES];//TODO: Remove this
extern uint8_t self_secret_key[crypto_box_SECRETKEYBYTES];
void new_keys(Net_Crypto *c)
{ {
crypto_box_keypair(self_public_key, self_secret_key); crypto_box_keypair(c->self_public_key, c->self_secret_key);
memcpy(self_public_key, c->self_public_key, crypto_box_PUBLICKEYBYTES);
memcpy(self_secret_key, c->self_secret_key, crypto_box_PUBLICKEYBYTES);
} }
/* save the public and private keys to the keys array /* save the public and private keys to the keys array
Length must be crypto_box_PUBLICKEYBYTES + crypto_box_SECRETKEYBYTES */ Length must be crypto_box_PUBLICKEYBYTES + crypto_box_SECRETKEYBYTES */
void save_keys(uint8_t *keys) void save_keys(Net_Crypto *c, uint8_t *keys)
{ {
memcpy(keys, self_public_key, crypto_box_PUBLICKEYBYTES); memcpy(keys, c->self_public_key, crypto_box_PUBLICKEYBYTES);
memcpy(keys + crypto_box_PUBLICKEYBYTES, self_secret_key, crypto_box_SECRETKEYBYTES); memcpy(keys + crypto_box_PUBLICKEYBYTES, c->self_secret_key, crypto_box_SECRETKEYBYTES);
} }
/* load the public and private keys from the keys array /* load the public and private keys from the keys array
Length must be crypto_box_PUBLICKEYBYTES + crypto_box_SECRETKEYBYTES */ Length must be crypto_box_PUBLICKEYBYTES + crypto_box_SECRETKEYBYTES */
void load_keys(uint8_t *keys) void load_keys(Net_Crypto *c, uint8_t *keys)
{ {
memcpy(self_public_key, keys, crypto_box_PUBLICKEYBYTES); memcpy(c->self_public_key, keys, crypto_box_PUBLICKEYBYTES);
memcpy(self_secret_key, keys + crypto_box_PUBLICKEYBYTES, crypto_box_SECRETKEYBYTES); memcpy(c->self_secret_key, keys + crypto_box_PUBLICKEYBYTES, crypto_box_SECRETKEYBYTES);
} }
/* TODO: optimize this /* TODO: optimize this
adds an incoming connection to the incoming_connection list. adds an incoming connection to the incoming_connection list.
returns 0 if successful returns 0 if successful
returns 1 if failure */ returns 1 if failure */
static int new_incoming(int id) static int new_incoming(Net_Crypto *c, int id)
{ {
uint32_t i; uint32_t i;
for (i = 0; i < MAX_INCOMING; ++i) { for (i = 0; i < MAX_INCOMING; ++i) {
if (incoming_connections[i] == -1) { if (c->incoming_connections[i] == -1) {
incoming_connections[i] = id; c->incoming_connections[i] = id;
return 0; return 0;
} }
} }
@ -644,81 +621,81 @@ static int new_incoming(int id)
/* TODO: optimize this /* TODO: optimize this
handle all new incoming connections. */ handle all new incoming connections. */
static void handle_incomings(void) static void handle_incomings(Net_Crypto *c)
{ {
int income; int income;
while (1) { while (1) {
income = incoming_connection(); income = incoming_connection(c->lossless_udp);
if (income == -1 || new_incoming(income) ) if (income == -1 || new_incoming(c, income) )
break; break;
} }
} }
/* handle received packets for not yet established crypto connections. */ /* handle received packets for not yet established crypto connections. */
static void receive_crypto(void) static void receive_crypto(Net_Crypto *c)
{ {
uint32_t i; uint32_t i;
for (i = 0; i < MAX_CRYPTO_CONNECTIONS; ++i) { for (i = 0; i < c->crypto_connections_length; ++i) {
if (crypto_connections[i].status == CONN_HANDSHAKE_SENT) { if (c->crypto_connections[i].status == CONN_HANDSHAKE_SENT) {
uint8_t temp_data[MAX_DATA_SIZE]; uint8_t temp_data[MAX_DATA_SIZE];
uint8_t secret_nonce[crypto_box_NONCEBYTES]; uint8_t secret_nonce[crypto_box_NONCEBYTES];
uint8_t public_key[crypto_box_PUBLICKEYBYTES]; uint8_t public_key[crypto_box_PUBLICKEYBYTES];
uint8_t session_key[crypto_box_PUBLICKEYBYTES]; uint8_t session_key[crypto_box_PUBLICKEYBYTES];
uint16_t len; uint16_t len;
if (id_packet(crypto_connections[i].number) == 2) { /* handle handshake packet. */ if (id_packet(c->lossless_udp, c->crypto_connections[i].number) == 2) { /* handle handshake packet. */
len = read_packet(crypto_connections[i].number, temp_data); len = read_packet(c->lossless_udp, c->crypto_connections[i].number, temp_data);
if (handle_cryptohandshake(public_key, secret_nonce, session_key, temp_data, len)) { if (handle_cryptohandshake(c, public_key, secret_nonce, session_key, temp_data, len)) {
if (memcmp(public_key, crypto_connections[i].public_key, crypto_box_PUBLICKEYBYTES) == 0) { if (memcmp(public_key, c->crypto_connections[i].public_key, crypto_box_PUBLICKEYBYTES) == 0) {
memcpy(crypto_connections[i].sent_nonce, secret_nonce, crypto_box_NONCEBYTES); memcpy(c->crypto_connections[i].sent_nonce, secret_nonce, crypto_box_NONCEBYTES);
memcpy(crypto_connections[i].peersessionpublic_key, session_key, crypto_box_PUBLICKEYBYTES); memcpy(c->crypto_connections[i].peersessionpublic_key, session_key, crypto_box_PUBLICKEYBYTES);
increment_nonce(crypto_connections[i].sent_nonce); increment_nonce(c->crypto_connections[i].sent_nonce);
uint32_t zero = 0; uint32_t zero = 0;
encrypt_precompute(crypto_connections[i].peersessionpublic_key, encrypt_precompute(c->crypto_connections[i].peersessionpublic_key,
crypto_connections[i].sessionsecret_key, c->crypto_connections[i].sessionsecret_key,
crypto_connections[i].shared_key); c->crypto_connections[i].shared_key);
crypto_connections[i].status = CONN_ESTABLISHED; /* connection status needs to be 3 for write_cryptpacket() to work */ c->crypto_connections[i].status = CONN_ESTABLISHED; /* connection status needs to be 3 for write_cryptpacket() to work */
write_cryptpacket(i, ((uint8_t *)&zero), sizeof(zero)); write_cryptpacket(c, i, ((uint8_t *)&zero), sizeof(zero));
crypto_connections[i].status = CONN_NOT_CONFIRMED; /* set it to its proper value right after. */ c->crypto_connections[i].status = CONN_NOT_CONFIRMED; /* set it to its proper value right after. */
} }
} }
} else if (id_packet(crypto_connections[i].number) != -1) { // This should not happen kill the connection if it does } else if (id_packet(c->lossless_udp, c->crypto_connections[i].number) != -1) { // This should not happen kill the connection if it does
crypto_kill(crypto_connections[i].number); crypto_kill(c, i);
return; return;
} }
} }
if (crypto_connections[i].status == CONN_NOT_CONFIRMED) { if (c->crypto_connections[i].status == CONN_NOT_CONFIRMED) {
if (id_packet(crypto_connections[i].number) == 3) { if (id_packet(c->lossless_udp, c->crypto_connections[i].number) == 3) {
uint8_t temp_data[MAX_DATA_SIZE]; uint8_t temp_data[MAX_DATA_SIZE];
uint8_t data[MAX_DATA_SIZE]; uint8_t data[MAX_DATA_SIZE];
int length = read_packet(crypto_connections[i].number, temp_data); int length = read_packet(c->lossless_udp, c->crypto_connections[i].number, temp_data);
int len = decrypt_data(crypto_connections[i].peersessionpublic_key, int len = decrypt_data(c->crypto_connections[i].peersessionpublic_key,
crypto_connections[i].sessionsecret_key, c->crypto_connections[i].sessionsecret_key,
crypto_connections[i].recv_nonce, temp_data + 1, length - 1, data); c->crypto_connections[i].recv_nonce, temp_data + 1, length - 1, data);
uint32_t zero = 0; uint32_t zero = 0;
if (len == sizeof(uint32_t) && memcmp(((uint8_t *)&zero), data, sizeof(uint32_t)) == 0) { if (len == sizeof(uint32_t) && memcmp(((uint8_t *)&zero), data, sizeof(uint32_t)) == 0) {
increment_nonce(crypto_connections[i].recv_nonce); increment_nonce(c->crypto_connections[i].recv_nonce);
encrypt_precompute(crypto_connections[i].peersessionpublic_key, encrypt_precompute(c->crypto_connections[i].peersessionpublic_key,
crypto_connections[i].sessionsecret_key, c->crypto_connections[i].sessionsecret_key,
crypto_connections[i].shared_key); c->crypto_connections[i].shared_key);
crypto_connections[i].status = CONN_ESTABLISHED; c->crypto_connections[i].status = CONN_ESTABLISHED;
/* connection is accepted so we disable the auto kill by setting it to about 1 month from now. */ /* connection is accepted so we disable the auto kill by setting it to about 1 month from now. */
kill_connection_in(crypto_connections[i].number, 3000000); kill_connection_in(c->lossless_udp, c->crypto_connections[i].number, 3000000);
} else { } else {
crypto_kill(crypto_connections[i].number); // This should not happen kill the connection if it does crypto_kill(c, i); // This should not happen kill the connection if it does
return; return;
} }
} else if (id_packet(crypto_connections[i].number) != -1) } else if (id_packet(c->lossless_udp, c->crypto_connections[i].number) != -1)
/* This should not happen /* This should not happen
kill the connection if it does */ kill the connection if it does */
crypto_kill(crypto_connections[i].number); crypto_kill(c, i);
return; return;
} }
@ -727,33 +704,52 @@ static void receive_crypto(void)
/* run this to (re)initialize net_crypto /* run this to (re)initialize net_crypto
sets all the global connection variables to their default values. */ sets all the global connection variables to their default values. */
void initNetCrypto(void) Net_Crypto * new_net_crypto(Networking_Core * net)
{ {
memset(incoming_connections, -1 , sizeof(incoming_connections)); Net_Crypto * temp = calloc(1, sizeof(Net_Crypto));
networking_registerhandler(32, &cryptopacket_handle); if (temp == NULL)
return NULL;
temp->lossless_udp = new_lossless_udp(net);
if (temp->lossless_udp == NULL)
return NULL;
memset(temp->incoming_connections, -1 , sizeof(int) * MAX_INCOMING);
//networking_registerhandler(temp, 32, &cryptopacket_handle);
networking_registerhandler(net, 32, &cryptopacket_handle, temp);
temp_net_crypto = temp; //TODO remove
return temp;
} }
static void killTimedout(void) static void kill_timedout(Net_Crypto *c)
{ {
uint32_t i; uint32_t i;
for (i = 0; i < MAX_CRYPTO_CONNECTIONS; ++i) { for (i = 0; i < c->crypto_connections_length; ++i) {
if (crypto_connections[i].status != CONN_NO_CONNECTION && is_connected(crypto_connections[i].number) == 4) if (c->crypto_connections[i].status != CONN_NO_CONNECTION && is_connected(c->lossless_udp, c->crypto_connections[i].number) == 4)
crypto_connections[i].status = CONN_TIMED_OUT; c->crypto_connections[i].status = CONN_TIMED_OUT;
else if (is_connected(crypto_connections[i].number) == 4) { else if (is_connected(c->lossless_udp, c->crypto_connections[i].number) == 4) {
kill_connection(crypto_connections[i].number); kill_connection(c->lossless_udp, c->crypto_connections[i].number);
crypto_connections[i].number = ~0; c->crypto_connections[i].number = ~0;
} }
} }
} }
/* main loop */ /* main loop */
void doNetCrypto(void) void do_net_crypto(Net_Crypto *c)
{ {
/* TODO:check if friend requests were sent correctly do_lossless_udp(c->lossless_udp);
handle new incoming connections handle_incomings(c);
handle friend requests */ receive_crypto(c);
handle_incomings(); kill_timedout(c);
receive_crypto(); }
killTimedout();
void kill_net_crypto(Net_Crypto *c)
{
uint32_t i;
for (i = 0; i < c->crypto_connections_length; ++i) {
crypto_kill(c, i);
}
kill_lossless_udp(c->lossless_udp);
memset(c, 0, sizeof(Net_Crypto));
free(c);
} }

View File

@ -31,10 +31,47 @@
extern "C" { extern "C" {
#endif #endif
/* Our public key. */ #define MAX_INCOMING 64
extern uint8_t self_public_key[crypto_box_PUBLICKEYBYTES];
extern uint8_t self_public_key[crypto_box_PUBLICKEYBYTES];//TODO: Remove this
extern uint8_t self_secret_key[crypto_box_SECRETKEYBYTES]; extern uint8_t self_secret_key[crypto_box_SECRETKEYBYTES];
typedef struct {
uint8_t public_key[crypto_box_PUBLICKEYBYTES]; /* the real public key of the peer. */
uint8_t recv_nonce[crypto_box_NONCEBYTES]; /* nonce of received packets */
uint8_t sent_nonce[crypto_box_NONCEBYTES]; /* nonce of sent packets. */
uint8_t sessionpublic_key[crypto_box_PUBLICKEYBYTES]; /* our public key for this session. */
uint8_t sessionsecret_key[crypto_box_SECRETKEYBYTES]; /* our private key for this session. */
uint8_t peersessionpublic_key[crypto_box_PUBLICKEYBYTES]; /* The public key of the peer. */
uint8_t shared_key[crypto_box_BEFORENMBYTES]; /* the precomputed shared key from encrypt_precompute */
uint8_t status; /* 0 if no connection, 1 we have sent a handshake, 2 if connexion is not confirmed yet
(we have received a handshake but no empty data packet), 3 if the connection is established.
4 if the connection is timed out. */
uint16_t number; /* Lossless_UDP connection number corresponding to this connection. */
} Crypto_Connection;
typedef int (*cryptopacket_handler_callback)(IP_Port ip_port, uint8_t *source_pubkey, uint8_t *data, uint32_t len);
typedef struct {
Lossless_UDP * lossless_udp;
Crypto_Connection *crypto_connections;
uint32_t crypto_connections_length; /* Length of connections array */
/* Our public and secret keys. */
uint8_t self_public_key[crypto_box_PUBLICKEYBYTES];
uint8_t self_secret_key[crypto_box_SECRETKEYBYTES];
/* keeps track of the connection numbers for friends request so we can check later if they were sent */
int incoming_connections[MAX_INCOMING];
cryptopacket_handler_callback cryptopackethandlers[256];
} Net_Crypto;
Net_Crypto * temp_net_crypto; //TODO: remove this
#define ENCRYPTION_PADDING (crypto_box_ZEROBYTES - crypto_box_BOXZEROBYTES) #define ENCRYPTION_PADDING (crypto_box_ZEROBYTES - crypto_box_BOXZEROBYTES)
/* returns zero if the buffer contains only zeros */ /* returns zero if the buffer contains only zeros */
@ -75,34 +112,35 @@ void random_nonce(uint8_t *nonce);
/* return 0 if there is no received data in the buffer /* return 0 if there is no received data in the buffer
return -1 if the packet was discarded. return -1 if the packet was discarded.
return length of received data if successful */ return length of received data if successful */
int read_cryptpacket(int crypt_connection_id, uint8_t *data); int read_cryptpacket(Net_Crypto *c, int crypt_connection_id, uint8_t *data);
/* return 0 if data could not be put in packet queue /* return 0 if data could not be put in packet queue
return 1 if data was put into the queue */ return 1 if data was put into the queue */
int write_cryptpacket(int crypt_connection_id, uint8_t *data, uint32_t length); int write_cryptpacket(Net_Crypto *c, int crypt_connection_id, uint8_t *data, uint32_t length);
/* create a request to peer with public_key. /* create a request to peer.
packet must be an array of MAX_DATA_SIZE big. send_public_key and send_secret_key are the pub/secret keys of the sender
Data represents the data we send with the request with length being the length of the data. recv_public_key is public key of reciever
request_id is the id of the request (32 = friend request, 254 = ping request) packet must be an array of MAX_DATA_SIZE big.
returns -1 on failure Data represents the data we send with the request with length being the length of the data.
returns the length of the created packet on success */ request_id is the id of the request (32 = friend request, 254 = ping request)
int create_request(uint8_t *packet, uint8_t *public_key, uint8_t *data, uint32_t length, uint8_t request_id); returns -1 on failure
returns the length of the created packet on success */
int create_request(uint8_t *send_public_key, uint8_t *send_secret_key, uint8_t *packet, uint8_t *recv_public_key, uint8_t *data, uint32_t length, uint8_t request_id);
typedef int (*cryptopacket_handler_callback)(IP_Port ip_port, uint8_t *source_pubkey, uint8_t *data, uint32_t len);
/* Function to call when request beginning with byte is received */ /* Function to call when request beginning with byte is received */
void cryptopacket_registerhandler(uint8_t byte, cryptopacket_handler_callback cb); void cryptopacket_registerhandler(Net_Crypto *c, uint8_t byte, cryptopacket_handler_callback cb);
/* Start a secure connection with other peer who has public_key and ip_port /* Start a secure connection with other peer who has public_key and ip_port
returns -1 if failure returns -1 if failure
returns crypt_connection_id of the initialized connection if everything went well. */ returns crypt_connection_id of the initialized connection if everything went well. */
int crypto_connect(uint8_t *public_key, IP_Port ip_port); int crypto_connect(Net_Crypto *c, uint8_t *public_key, IP_Port ip_port);
/* kill a crypto connection /* kill a crypto connection
return 0 if killed successfully return 0 if killed successfully
return 1 if there was a problem. */ return 1 if there was a problem. */
int crypto_kill(int crypt_connection_id); int crypto_kill(Net_Crypto *c, int crypt_connection_id);
/* handle an incoming connection /* handle an incoming connection
return -1 if no crypto inbound connection return -1 if no crypto inbound connection
@ -111,37 +149,39 @@ int crypto_kill(int crypt_connection_id);
and the session public key for the connection in session_key and the session public key for the connection in session_key
to accept it see: accept_crypto_inbound(...) to accept it see: accept_crypto_inbound(...)
to refuse it just call kill_connection(...) on the connection id */ to refuse it just call kill_connection(...) on the connection id */
int crypto_inbound(uint8_t *public_key, uint8_t *secret_nonce, uint8_t *session_key); int crypto_inbound(Net_Crypto *c, uint8_t *public_key, uint8_t *secret_nonce, uint8_t *session_key);
/* accept an incoming connection using the parameters provided by crypto_inbound /* accept an incoming connection using the parameters provided by crypto_inbound
return -1 if not successful return -1 if not successful
returns the crypt_connection_id if successful */ returns the crypt_connection_id if successful */
int accept_crypto_inbound(int connection_id, uint8_t *public_key, uint8_t *secret_nonce, uint8_t *session_key); int accept_crypto_inbound(Net_Crypto *c, int connection_id, uint8_t *public_key, uint8_t *secret_nonce, uint8_t *session_key);
/* return 0 if no connection, 1 we have sent a handshake, 2 if connexion is not confirmed yet /* return 0 if no connection, 1 we have sent a handshake, 2 if connexion is not confirmed yet
(we have received a handshake but no empty data packet), 3 if the connection is established. (we have received a handshake but no empty data packet), 3 if the connection is established.
4 if the connection is timed out and waiting to be killed */ 4 if the connection is timed out and waiting to be killed */
int is_cryptoconnected(int crypt_connection_id); int is_cryptoconnected(Net_Crypto *c, int crypt_connection_id);
/* Generate our public and private keys /* Generate our public and private keys
Only call this function the first time the program starts. */ Only call this function the first time the program starts. */
void new_keys(void); void new_keys(Net_Crypto *c);
/* save the public and private keys to the keys array /* save the public and private keys to the keys array
Length must be crypto_box_PUBLICKEYBYTES + crypto_box_SECRETKEYBYTES */ Length must be crypto_box_PUBLICKEYBYTES + crypto_box_SECRETKEYBYTES */
void save_keys(uint8_t *keys); void save_keys(Net_Crypto *c, uint8_t *keys);
/* load the public and private keys from the keys array /* load the public and private keys from the keys array
Length must be crypto_box_PUBLICKEYBYTES + crypto_box_SECRETKEYBYTES */ Length must be crypto_box_PUBLICKEYBYTES + crypto_box_SECRETKEYBYTES */
void load_keys(uint8_t *keys); void load_keys(Net_Crypto *c, uint8_t *keys);
/* run this to (re)initialize net_crypto /* create new instance of Net_Crypto
sets all the global connection variables to their default values. */ sets all the global connection variables to their default values. */
void initNetCrypto(void); Net_Crypto * new_net_crypto(Networking_Core * net);
/* main loop */ /* main loop */
void doNetCrypto(void); void do_net_crypto(Net_Crypto *c);
void kill_net_crypto(Net_Crypto *c);
#ifdef __cplusplus #ifdef __cplusplus
} }

View File

@ -56,12 +56,9 @@ uint32_t random_int(void)
#endif #endif
} }
/* our UDP socket, a global variable. */
static int sock;
/* Basic network functions: /* Basic network functions:
Function to send packet(data) of length length to ip_port */ Function to send packet(data) of length length to ip_port */
int sendpacket(IP_Port ip_port, uint8_t *data, uint32_t length) int sendpacket(int sock, IP_Port ip_port, uint8_t *data, uint32_t length)
{ {
ADDR addr = {AF_INET, ip_port.port, ip_port.ip}; ADDR addr = {AF_INET, ip_port.port, ip_port.ip};
return sendto(sock, (char *) data, length, 0, (struct sockaddr *)&addr, sizeof(addr)); return sendto(sock, (char *) data, length, 0, (struct sockaddr *)&addr, sizeof(addr));
@ -71,7 +68,7 @@ int sendpacket(IP_Port ip_port, uint8_t *data, uint32_t length)
the packet data into data the packet data into data
the packet length into length. the packet length into length.
dump all empty packets. */ dump all empty packets. */
static int receivepacket(IP_Port *ip_port, uint8_t *data, uint32_t *length) static int receivepacket(int sock, IP_Port *ip_port, uint8_t *data, uint32_t *length)
{ {
ADDR addr; ADDR addr;
#ifdef WIN32 #ifdef WIN32
@ -89,36 +86,32 @@ static int receivepacket(IP_Port *ip_port, uint8_t *data, uint32_t *length)
return 0; return 0;
} }
static packet_handler_callback packethandlers[256] = {0}; void networking_registerhandler(Networking_Core * net, uint8_t byte, packet_handler_callback cb, void * object)
void networking_registerhandler(uint8_t byte, packet_handler_callback cb)
{ {
packethandlers[byte] = cb; net->packethandlers[byte].function = cb;
net->packethandlers[byte].object = object;
} }
void networking_poll() void networking_poll(Networking_Core * net)
{ {
IP_Port ip_port; IP_Port ip_port;
uint8_t data[MAX_UDP_PACKET_SIZE]; uint8_t data[MAX_UDP_PACKET_SIZE];
uint32_t length; uint32_t length;
while (receivepacket(&ip_port, data, &length) != -1) { while (receivepacket(net->sock, &ip_port, data, &length) != -1) {
if (length < 1) continue; if (length < 1) continue;
if (!packethandlers[data[0]]) continue; if (!(net->packethandlers[data[0]].function)) continue;
packethandlers[data[0]](ip_port, data, length); net->packethandlers[data[0]].function(net->packethandlers[data[0]].object, ip_port, data, length);
} }
} }
/* initialize networking uint8_t at_startup_ran;
bind to ip and port static void at_startup(void)
ip must be in network order EX: 127.0.0.1 = (7F000001)
port is in host byte order (this means don't worry about it)
returns 0 if no problems
returns -1 if there are problems */
int init_networking(IP ip, uint16_t port)
{ {
if (at_startup_ran != 0)
return;
#ifdef WIN32 #ifdef WIN32
WSADATA wsaData; WSADATA wsaData;
@ -128,21 +121,48 @@ int init_networking(IP ip, uint16_t port)
#else #else
srandom((uint32_t)current_time()); srandom((uint32_t)current_time());
#endif #endif
srand((uint32_t)current_time()); srand((uint32_t)current_time());
at_startup_ran = 1;
}
/* TODO: put this somewhere
static void at_shutdown(void)
{
#ifdef WIN32
WSACleanup();
#endif
}
*/
/* initialize networking
bind to ip and port
ip must be in network order EX: 127.0.0.1 = (7F000001)
port is in host byte order (this means don't worry about it)
returns Networking_Core object if no problems
returns NULL if there are problems */
Networking_Core * new_networking(IP ip, uint16_t port)
{
at_startup();
/* initialize our socket */ /* initialize our socket */
sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); Networking_Core * temp = calloc(1, sizeof(Networking_Core));
if (temp == NULL)
return NULL;
temp->sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
/* Check for socket error */ /* Check for socket error */
#ifdef WIN32 #ifdef WIN32
if (sock == INVALID_SOCKET) /* MSDN recommends this */ if (temp->sock == INVALID_SOCKET) { /* MSDN recommends this */
return -1; free(temp);
return NULL;
}
#else #else
if (sock < 0) if (temp->sock < 0) {
return -1; free(temp);
return NULL;
}
#endif #endif
@ -161,34 +181,34 @@ int init_networking(IP ip, uint16_t port)
/* Enable broadcast on socket */ /* Enable broadcast on socket */
int broadcast = 1; int broadcast = 1;
setsockopt(sock, SOL_SOCKET, SO_BROADCAST, (char *)&broadcast, sizeof(broadcast)); setsockopt(temp->sock, SOL_SOCKET, SO_BROADCAST, (char *)&broadcast, sizeof(broadcast));
/* Set socket nonblocking */ /* Set socket nonblocking */
#ifdef WIN32 #ifdef WIN32
/* I think this works for windows */ /* I think this works for windows */
u_long mode = 1; u_long mode = 1;
/* ioctl(sock, FIONBIO, &mode); */ /* ioctl(sock, FIONBIO, &mode); */
ioctlsocket(sock, FIONBIO, &mode); ioctlsocket(temp->sock, FIONBIO, &mode);
#else #else
fcntl(sock, F_SETFL, O_NONBLOCK, 1); fcntl(temp->sock, F_SETFL, O_NONBLOCK, 1);
#endif #endif
/* Bind our socket to port PORT and address 0.0.0.0 */ /* Bind our socket to port PORT and address 0.0.0.0 */
ADDR addr = {AF_INET, htons(port), ip}; ADDR addr = {AF_INET, htons(port), ip};
bind(sock, (struct sockaddr *)&addr, sizeof(addr)); bind(temp->sock, (struct sockaddr *)&addr, sizeof(addr));
temp_net = temp;
return 0; return temp;
} }
/* function to cleanup networking stuff */ /* function to cleanup networking stuff */
void shutdown_networking(void) void kill_networking(Networking_Core * net)
{ {
#ifdef WIN32 #ifdef WIN32
closesocket(sock); closesocket(net->sock);
WSACleanup();
#else #else
close(sock); close(net->sock);
#endif #endif
free(net);
return; return;
} }

View File

@ -99,8 +99,20 @@ typedef struct {
/* Function to receive data, ip and port of sender is put into ip_port /* Function to receive data, ip and port of sender is put into ip_port
the packet data into data the packet data into data
the packet length into length. */ the packet length into length. */
typedef int (*packet_handler_callback)(IP_Port ip_port, uint8_t *data, uint32_t len); typedef int (*packet_handler_callback)(void * object, IP_Port ip_port, uint8_t *data, uint32_t len);
typedef struct {
packet_handler_callback function;
void * object;
}Packet_Handles;
typedef struct {
Packet_Handles packethandlers[256];
/* our UDP socket */
int sock;
}Networking_Core;
Networking_Core * temp_net;
/* returns current time in milleseconds since the epoch. */ /* returns current time in milleseconds since the epoch. */
uint64_t current_time(void); uint64_t current_time(void);
@ -111,13 +123,13 @@ uint32_t random_int(void);
/* Basic network functions: */ /* Basic network functions: */
/* Function to send packet(data) of length length to ip_port */ /* Function to send packet(data) of length length to ip_port */
int sendpacket(IP_Port ip_port, uint8_t *data, uint32_t length); int sendpacket(int sock, IP_Port ip_port, uint8_t *data, uint32_t length);
/* Function to call when packet beginning with byte is received */ /* Function to call when packet beginning with byte is received */
void networking_registerhandler(uint8_t byte, packet_handler_callback cb); void networking_registerhandler(Networking_Core * net, uint8_t byte, packet_handler_callback cb, void * object);
/* call this several times a second */ /* call this several times a second */
void networking_poll(); void networking_poll(Networking_Core * net);
/* initialize networking /* initialize networking
bind to ip and port bind to ip and port
@ -125,10 +137,10 @@ void networking_poll();
port is in host byte order (this means don't worry about it) port is in host byte order (this means don't worry about it)
returns 0 if no problems returns 0 if no problems
returns -1 if there were problems */ returns -1 if there were problems */
int init_networking(IP ip, uint16_t port); Networking_Core * new_networking(IP ip, uint16_t port);
/* function to cleanup networking stuff(doesn't do much right now) */ /* function to cleanup networking stuff(doesn't do much right now) */
void shutdown_networking(void); void kill_networking(Networking_Core * net);
/* /*
resolve_addr(): resolve_addr():

View File

@ -135,7 +135,7 @@ int send_ping_request(IP_Port ipp, clientid_t *client_id)
if (rc != sizeof(ping_id) + ENCRYPTION_PADDING) if (rc != sizeof(ping_id) + ENCRYPTION_PADDING)
return 1; return 1;
return sendpacket(ipp, (uint8_t *) &pk, sizeof(pk)); return sendpacket(temp_net->sock, ipp, (uint8_t *) &pk, sizeof(pk));
} }
int send_ping_response(IP_Port ipp, clientid_t *client_id, uint64_t ping_id) int send_ping_response(IP_Port ipp, clientid_t *client_id, uint64_t ping_id)
@ -160,10 +160,10 @@ int send_ping_response(IP_Port ipp, clientid_t *client_id, uint64_t ping_id)
if (rc != sizeof(ping_id) + ENCRYPTION_PADDING) if (rc != sizeof(ping_id) + ENCRYPTION_PADDING)
return 1; return 1;
return sendpacket(ipp, (uint8_t *) &pk, sizeof(pk)); return sendpacket(temp_net->sock, ipp, (uint8_t *) &pk, sizeof(pk));
} }
int handle_ping_request(IP_Port source, uint8_t *packet, uint32_t length) int handle_ping_request(void * object, IP_Port source, uint8_t *packet, uint32_t length)
{ {
pingreq_t *p = (pingreq_t *) packet; pingreq_t *p = (pingreq_t *) packet;
int rc; int rc;
@ -190,7 +190,7 @@ int handle_ping_request(IP_Port source, uint8_t *packet, uint32_t length)
return 0; return 0;
} }
int handle_ping_response(IP_Port source, uint8_t *packet, uint32_t length) int handle_ping_response(void * object, IP_Port source, uint8_t *packet, uint32_t length)
{ {
pingres_t *p = (pingres_t *) packet; pingres_t *p = (pingres_t *) packet;
int rc; int rc;

View File

@ -12,5 +12,5 @@ uint64_t add_ping(IP_Port ipp);
bool is_pinging(IP_Port ipp, uint64_t ping_id); bool is_pinging(IP_Port ipp, uint64_t ping_id);
int send_ping_request(IP_Port ipp, clientid_t *client_id); int send_ping_request(IP_Port ipp, clientid_t *client_id);
int send_ping_response(IP_Port ipp, clientid_t *client_id, uint64_t ping_id); int send_ping_response(IP_Port ipp, clientid_t *client_id, uint64_t ping_id);
int handle_ping_request(IP_Port source, uint8_t *packet, uint32_t length); int handle_ping_request(void * object, IP_Port source, uint8_t *packet, uint32_t length);
int handle_ping_response(IP_Port source, uint8_t *packet, uint32_t length); int handle_ping_response(void * object, IP_Port source, uint8_t *packet, uint32_t length);