Messenger now works with the new net_crypto api.

Added callbacks in net_crypto for the data packets and status changes.

Added onion_getfriend_DHT_pubkey to onion_client.

Net crypto isn't done yet so connections between toxes are not
lossless, this means file sending is broken hence why the test fails.
This commit is contained in:
irungentoo 2014-05-02 21:25:23 -04:00
parent 8ae0a79305
commit db78c99ff4
No known key found for this signature in database
GPG Key ID: 10349DC9BED89E98
5 changed files with 526 additions and 333 deletions

View File

@ -1857,95 +1857,42 @@ static void check_friend_request_timed_out(Messenger *m, uint32_t i, uint64_t t)
}
}
/* TODO: Make this function not suck. */
void do_friends(Messenger *m)
static int handle_status(void *object, int i, uint8_t status)
{
uint32_t i;
int len;
uint8_t temp[MAX_CRYPTO_DATA_SIZE];
uint64_t temp_time = unix_time();
Messenger *m = object;
for (i = 0; i < m->numfriends; ++i) {
if (m->friendlist[i].status == FRIEND_ADDED) {
int fr = send_friendrequest(m->onion_c, m->friendlist[i].client_id, m->friendlist[i].friendrequest_nospam,
m->friendlist[i].info,
m->friendlist[i].info_size);
if (fr >= 0) {
set_friend_status(m, i, FRIEND_REQUESTED);
m->friendlist[i].friendrequest_lastsent = temp_time;
}
}
if (m->friendlist[i].status == FRIEND_REQUESTED
|| m->friendlist[i].status == FRIEND_CONFIRMED) { /* friend is not online. */
if (m->friendlist[i].status == FRIEND_REQUESTED) {
/* If we didn't connect to friend after successfully sending him a friend request the request is deemed
* unsuccessful so we set the status back to FRIEND_ADDED and try again.
*/
check_friend_request_timed_out(m, i, temp_time);
}
IP_Port friendip;
int friendok = onion_getfriendip(m->onion_c, m->friendlist[i].onion_friendnum, &friendip);
switch (is_cryptoconnected(m->net_crypto, m->friendlist[i].crypt_connection_id)) {
case CRYPTO_CONN_NO_CONNECTION:
if (friendok == 1)
m->friendlist[i].crypt_connection_id = crypto_connect(m->net_crypto, m->friendlist[i].client_id, friendip);
break;
case CRYPTO_CONN_ESTABLISHED: /* Connection is established. */
if (status) { /* Went online. */
set_friend_status(m, i, FRIEND_ONLINE);
m->friendlist[i].name_sent = 0;
m->friendlist[i].userstatus_sent = 0;
m->friendlist[i].statusmessage_sent = 0;
m->friendlist[i].ping_lastrecv = temp_time;
break;
case CRYPTO_CONN_TIMED_OUT:
crypto_kill(m->net_crypto, m->friendlist[i].crypt_connection_id);
} else { /* Went offline. */
m->friendlist[i].crypt_connection_id = -1;
break;
default:
break;
if (m->friendlist[i].status == FRIEND_ONLINE) {
set_friend_status(m, i, FRIEND_CONFIRMED);
}
}
while (m->friendlist[i].status == FRIEND_ONLINE) { /* friend is online. */
if (m->friendlist[i].name_sent == 0) {
if (m_sendname(m, i, m->name, m->name_length))
m->friendlist[i].name_sent = 1;
return 0;
}
if (m->friendlist[i].statusmessage_sent == 0) {
if (send_statusmessage(m, i, m->statusmessage, m->statusmessage_length))
m->friendlist[i].statusmessage_sent = 1;
}
static int handle_packet(void *object, int i, uint8_t *temp, uint16_t len)
{
if (len == 0)
return -1;
if (m->friendlist[i].userstatus_sent == 0) {
if (send_userstatus(m, i, m->userstatus))
m->friendlist[i].userstatus_sent = 1;
}
if (m->friendlist[i].user_istyping_sent == 0) {
if (send_user_istyping(m, i, m->friendlist[i].user_istyping))
m->friendlist[i].user_istyping_sent = 1;
}
if (m->friendlist[i].ping_lastsent + FRIEND_PING_INTERVAL < temp_time) {
send_ping(m, i);
}
len = read_cryptpacket(m->net_crypto, m->friendlist[i].crypt_connection_id, temp);
if (len > 0) {
Messenger *m = object;
uint64_t temp_time = unix_time();
uint8_t packet_id = temp[0];
uint8_t *data = temp + 1;
uint32_t data_length = len - 1;
if (m->friendlist[i].status != FRIEND_ONLINE)
return -1;
switch (packet_id) {
case PACKET_ID_ALIVE: {
m->friendlist[i].ping_lastrecv = temp_time;
@ -2182,7 +2129,97 @@ void do_friends(Messenger *m)
break;
}
}
} else {
return 0;
}
static int friend_new_connection(Messenger *m, int32_t friendnumber, uint8_t *real_public_key)
{
if (friend_not_valid(m, friendnumber))
return -1;
if (m->friendlist[friendnumber].crypt_connection_id != -1) {
return -1;
}
int id = new_crypto_connection(m->net_crypto, real_public_key);
if (id == -1)
return -1;
m->friendlist[friendnumber].crypt_connection_id = id;
connection_status_handler(m->net_crypto, id, &handle_status, m, friendnumber);
connection_data_handler(m->net_crypto, id, &handle_packet, m, friendnumber);
return 0;
}
/* TODO: Make this function not suck. */
void do_friends(Messenger *m)
{
uint32_t i;
uint64_t temp_time = unix_time();
for (i = 0; i < m->numfriends; ++i) {
if (m->friendlist[i].status == FRIEND_ADDED) {
int fr = send_friendrequest(m->onion_c, m->friendlist[i].client_id, m->friendlist[i].friendrequest_nospam,
m->friendlist[i].info,
m->friendlist[i].info_size);
if (fr >= 0) {
set_friend_status(m, i, FRIEND_REQUESTED);
m->friendlist[i].friendrequest_lastsent = temp_time;
}
}
if (m->friendlist[i].status == FRIEND_REQUESTED
|| m->friendlist[i].status == FRIEND_CONFIRMED) { /* friend is not online. */
if (m->friendlist[i].status == FRIEND_REQUESTED) {
/* If we didn't connect to friend after successfully sending him a friend request the request is deemed
* unsuccessful so we set the status back to FRIEND_ADDED and try again.
*/
check_friend_request_timed_out(m, i, temp_time);
}
friend_new_connection(m, i, m->friendlist[i].client_id);
uint8_t dht_public_key[crypto_box_PUBLICKEYBYTES];
if (onion_getfriend_DHT_pubkey(m->onion_c, m->friendlist[i].onion_friendnum, dht_public_key) == 0) {
set_conection_dht_public_key(m->net_crypto, m->friendlist[i].crypt_connection_id, dht_public_key);
}
IP_Port friendip;
if (onion_getfriendip(m->onion_c, m->friendlist[i].onion_friendnum, &friendip) == 1) {
set_direct_ip_port(m->net_crypto, m->friendlist[i].crypt_connection_id, friendip);
}
}
if (m->friendlist[i].status == FRIEND_ONLINE) { /* friend is online. */
if (m->friendlist[i].name_sent == 0) {
if (m_sendname(m, i, m->name, m->name_length))
m->friendlist[i].name_sent = 1;
}
if (m->friendlist[i].statusmessage_sent == 0) {
if (send_statusmessage(m, i, m->statusmessage, m->statusmessage_length))
m->friendlist[i].statusmessage_sent = 1;
}
if (m->friendlist[i].userstatus_sent == 0) {
if (send_userstatus(m, i, m->userstatus))
m->friendlist[i].userstatus_sent = 1;
}
if (m->friendlist[i].user_istyping_sent == 0) {
if (send_user_istyping(m, i, m->friendlist[i].user_istyping))
m->friendlist[i].user_istyping_sent = 1;
}
if (m->friendlist[i].ping_lastsent + FRIEND_PING_INTERVAL < temp_time) {
send_ping(m, i);
}
if (is_cryptoconnected(m->net_crypto,
m->friendlist[i].crypt_connection_id) == CRYPTO_CONN_TIMED_OUT) { /* If the connection timed out, kill it. */
crypto_kill(m->net_crypto, m->friendlist[i].crypt_connection_id);
@ -2196,9 +2233,6 @@ void do_friends(Messenger *m)
m->friendlist[i].crypt_connection_id = -1;
set_friend_status(m, i, FRIEND_CONFIRMED);
}
break;
}
}
}
}

View File

@ -379,6 +379,7 @@ static int send_data_packet(Net_Crypto *c, int crypt_connection_id, uint8_t *dat
return -1;
increment_nonce(conn->sent_nonce);
conn->last_data_packet_sent = current_time(); //TODO remove this.
return send_packet_to(c, crypt_connection_id, packet, sizeof(packet));
}
@ -459,6 +460,7 @@ static int new_temp_packet(Net_Crypto *c, int crypt_connection_id, uint8_t *pack
conn->temp_packet = temp_packet;
conn->temp_packet_length = length;
conn->temp_packet_sent_time = 0;
conn->temp_packet_num_sent = 0;
return 0;
}
@ -480,6 +482,7 @@ static int clear_temp_packet(Net_Crypto *c, int crypt_connection_id)
conn->temp_packet = 0;
conn->temp_packet_length = 0;
conn->temp_packet_sent_time = 0;
conn->temp_packet_num_sent = 0;
return 0;
}
@ -503,6 +506,7 @@ static int send_temp_packet(Net_Crypto *c, int crypt_connection_id)
return -1;
conn->temp_packet_sent_time = current_time();
++conn->temp_packet_num_sent;
return 0;
}
@ -594,7 +598,24 @@ static int handle_packet_connection(Net_Crypto *c, int crypt_connection_id, uint
case NET_PACKET_CRYPTO_DATA: {
if (conn->status == CRYPTO_CONN_NOT_CONFIRMED || conn->status == CRYPTO_CONN_ESTABLISHED) {
//TODO
uint8_t data[MAX_DATA_DATA_PACKET_SIZE];
int len = handle_data_packet(c, crypt_connection_id, data, packet, length);
if (len == -1)
return -1;
if (conn->status == CRYPTO_CONN_NOT_CONFIRMED) {
if (conn->connection_status_callback)
conn->connection_status_callback(conn->connection_status_callback_object, conn->connection_status_callback_id, 1);
clear_temp_packet(c, crypt_connection_id);
conn->status = CRYPTO_CONN_ESTABLISHED;
}
if (conn->connection_data_callback)
conn->connection_data_callback(conn->connection_data_callback_object, conn->connection_data_callback_id, data, len);
//TODO add buffers and packet requesting.
} else {
return -1;
}
@ -870,6 +891,9 @@ int set_conection_dht_public_key(Net_Crypto *c, int crypt_connection_id, uint8_t
if (conn == 0)
return -1;
if (conn->dht_public_key_set == 1 && memcmp(conn->dht_public_key, dht_public_key, crypto_box_PUBLICKEYBYTES) == 0)
return -1;
memcpy(conn->dht_public_key, dht_public_key, crypto_box_PUBLICKEYBYTES);
conn->dht_public_key_set = 1;
@ -908,6 +932,52 @@ int set_direct_ip_port(Net_Crypto *c, int crypt_connection_id, IP_Port ip_port)
return 0;
}
/* Set function to be called when connection with crypt_connection_id goes connects/disconnects.
*
* The set function should return -1 on failure and 0 on success.
* Note that if this function is set, the connection will clear itself on disconnect.
* Object and id will be passed to this function untouched.
* status is 1 if the connection is going online, 0 if it is going offline.
*
* return -1 on failure.
* return 0 on success.
*/
int connection_status_handler(Net_Crypto *c, int crypt_connection_id, int (*connection_status_callback)(void *object,
int id, uint8_t status), void *object, int id)
{
Crypto_Connection *conn = get_crypto_connection(c, crypt_connection_id);
if (conn == 0)
return -1;
conn->connection_status_callback = connection_status_callback;
conn->connection_status_callback_object = object;
conn->connection_status_callback_id = id;
return 0;
}
/* Set function to be called when connection with crypt_connection_id receives a data packet of length.
*
* The set function should return -1 on failure and 0 on success.
* Object and id will be passed to this function untouched.
*
* return -1 on failure.
* return 0 on success.
*/
int connection_data_handler(Net_Crypto *c, int crypt_connection_id, int (*connection_data_callback)(void *object,
int id, uint8_t *data, uint16_t length), void *object, int id)
{
Crypto_Connection *conn = get_crypto_connection(c, crypt_connection_id);
if (conn == 0)
return -1;
conn->connection_data_callback = connection_data_callback;
conn->connection_data_callback_object = object;
conn->connection_data_callback_id = id;
return 0;
}
/* Get the crypto connection id from the ip_port.
*
* return -1 on failure.
@ -977,27 +1047,26 @@ static void send_crypto_packets(Net_Crypto *c)
if (conn == 0)
return;
if ((CRYPTO_SEND_PACKET_INTERVAL * 1000UL) + conn->temp_packet_sent_time < temp_time) {
if ((CRYPTO_SEND_PACKET_INTERVAL * 1000ULL) + conn->temp_packet_sent_time < temp_time) {
send_temp_packet(c, i);
}
if (conn->status >= CRYPTO_CONN_NOT_CONFIRMED
&& (500ULL * 1000ULL) + conn->last_data_packet_sent < temp_time) {//TODO remove this.
uint8_t data[4] = {};
send_data_packet(c, i, data, 4);
}
}
}
/* return 0 if there is no received data in the buffer.
* return -1 if the packet was discarded.
* return length of received data if successful.
*/
int read_cryptpacket(Net_Crypto *c, int crypt_connection_id, uint8_t *data)
{
}
/* returns the number of packet slots left in the sendbuffer.
* return 0 if failure.
*/
uint32_t crypto_num_free_sendqueue_slots(Net_Crypto *c, int crypt_connection_id)
{
//TODO
return 0;
}
/* return 0 if data could not be put in packet queue.
@ -1005,28 +1074,22 @@ uint32_t crypto_num_free_sendqueue_slots(Net_Crypto *c, int crypt_connection_id)
*/
int write_cryptpacket(Net_Crypto *c, int crypt_connection_id, uint8_t *data, uint32_t length)
{
//TODO
if (send_data_packet(c, crypt_connection_id, data, length) == 0)
return 1;
}
/* Start a secure connection with other peer who has public_key and ip_port.
*
* return -1 if failure.
* return crypt_connection_id of the initialized connection if everything went well.
*/
int crypto_connect(Net_Crypto *c, uint8_t *public_key, IP_Port ip_port)
{
return 0;
}
/* Kill a crypto connection.
*
* return 0 if killed successfully.
* return 1 if there was a problem.
* return -1 on failure.
* return 0 on success.
*/
int crypto_kill(Net_Crypto *c, int crypt_connection_id)
{
//TODO
return wipe_crypto_connection(c, crypt_connection_id);
}
/* return 0 if no connection.
@ -1096,9 +1159,35 @@ Net_Crypto *new_net_crypto(DHT *dht)
static void kill_timedout(Net_Crypto *c)
{
uint32_t i;
uint64_t temp_time = current_time();
for (i = 0; i < c->crypto_connections_length; ++i) {
//TODO
Crypto_Connection *conn = get_crypto_connection(c, i);
if (conn == 0)
return;
if (conn->status == CRYPTO_CONN_NO_CONNECTION || conn->status == CRYPTO_CONN_TIMED_OUT)
continue;
if (conn->status == CRYPTO_CONN_COOKIE_REQUESTING || conn->status == CRYPTO_CONN_HANDSHAKE_SENT
|| conn->status == CRYPTO_CONN_NOT_CONFIRMED) {
if (conn->temp_packet_num_sent < MAX_NUM_SENDPACKET_TRIES)
continue;
if (conn->connection_status_callback) {
conn->connection_status_callback(conn->connection_status_callback_object, conn->connection_status_callback_id, 0);
crypto_kill(c, i);
continue;
}
conn->status = CRYPTO_CONN_TIMED_OUT;
continue;
}
if (conn->status == CRYPTO_CONN_ESTABLISHED) {
//TODO: add a timeout here?
}
}
}

View File

@ -44,6 +44,9 @@
/* Interval in ms between sending cookie request/handshake packets. */
#define CRYPTO_SEND_PACKET_INTERVAL 500
/* The maximum number of times we try to send the cookie request and handshake
before giving up. */
#define MAX_NUM_SENDPACKET_TRIES 10
typedef struct {
uint8_t public_key[crypto_box_PUBLICKEYBYTES]; /* The real public key of the peer. */
@ -59,8 +62,6 @@ typedef struct {
* 4 if the connection is established.
* 5 if the connection is timed out.
*/
uint64_t timeout;
uint64_t cookie_request_number; /* number used in the cookie request packets for this connection */
uint8_t dht_public_key[crypto_box_PUBLICKEYBYTES]; /* The dht public key of the peer */
uint8_t dht_public_key_set; /* True if the dht public key is set, false if it isn't. */
@ -68,9 +69,20 @@ typedef struct {
uint8_t *temp_packet; /* Where the cookie request/handshake packet is stored while it is being sent. */
uint16_t temp_packet_length;
uint64_t temp_packet_sent_time; /* The time at which the last temp_packet was sent in ms. */
uint32_t temp_packet_num_sent;
IP_Port ip_port; /* The ip and port to contact this guy directly.*/
uint64_t direct_lastrecv_time; /* The Time at which we last receive a direct packet. */
int (*connection_status_callback)(void *object, int id, uint8_t status);
void *connection_status_callback_object;
int connection_status_callback_id;
int (*connection_data_callback)(void *object, int id, uint8_t *data, uint16_t length);
void *connection_data_callback_object;
int connection_data_callback_id;
uint64_t last_data_packet_sent;
} Crypto_Connection;
typedef struct {
@ -117,12 +129,52 @@ void new_connection_handler(Net_Crypto *c, int (*new_connection_callback)(void *
*/
int accept_crypto_connection(Net_Crypto *c, New_Connection *n_c);
/* return 0 if there is no received data in the buffer.
* return -1 if the packet was discarded.
* return length of received data if successful.
/* Create a crypto connection.
* If one to that real public key already exists, return it.
*
* return -1 on failure.
* return connection id on success.
*/
int read_cryptpacket(Net_Crypto *c, int crypt_connection_id, uint8_t *data);
int new_crypto_connection(Net_Crypto *c, uint8_t *real_public_key);
/* Set the DHT public key of the crypto connection.
*
* return -1 on failure.
* return 0 on success.
*/
int set_conection_dht_public_key(Net_Crypto *c, int crypt_connection_id, uint8_t *dht_public_key);
/* Set the direct ip of the crypto connection.
*
* return -1 on failure.
* return 0 on success.
*/
int set_direct_ip_port(Net_Crypto *c, int crypt_connection_id, IP_Port ip_port);
/* Set function to be called when connection with crypt_connection_id goes connects/disconnects.
*
* The set function should return -1 on failure and 0 on success.
* Note that if this function is set, the connection will clear itself on disconnect.
* Object and id will be passed to this function untouched.
* status is 1 if the connection is going online, 0 if it is going offline.
*
* return -1 on failure.
* return 0 on success.
*/
int connection_status_handler(Net_Crypto *c, int crypt_connection_id, int (*connection_status_callback)(void *object,
int id, uint8_t status), void *object, int id);
/* Set function to be called when connection with crypt_connection_id receives a data packet of length.
*
* The set function should return -1 on failure and 0 on success.
* Object and id will be passed to this function untouched.
*
* return -1 on failure.
* return 0 on success.
*/
int connection_data_handler(Net_Crypto *c, int crypt_connection_id, int (*connection_data_callback)(void *object,
int id, uint8_t *data, uint16_t length), void *object, int id);
/* returns the number of packet slots left in the sendbuffer.
* return 0 if failure.
@ -134,17 +186,11 @@ uint32_t crypto_num_free_sendqueue_slots(Net_Crypto *c, int crypt_connection_id)
*/
int write_cryptpacket(Net_Crypto *c, int crypt_connection_id, uint8_t *data, uint32_t length);
/* Start a secure connection with other peer who has public_key and ip_port.
*
* return -1 if failure.
* return crypt_connection_id of the initialized connection if everything went well.
*/
int crypto_connect(Net_Crypto *c, uint8_t *public_key, IP_Port ip_port);
/* Kill a crypto connection.
*
* return 0 if killed successfully.
* return 1 if there was a problem.
* return -1 on failure.
* return 0 on success.
*/
int crypto_kill(Net_Crypto *c, int crypt_connection_id);

View File

@ -796,14 +796,12 @@ int onion_delfriend(Onion_Client *onion_c, int friend_num)
return friend_num;
}
/* Get the ip of friend friendnum and put it in ip_port
*
* return -1, -- if client_id does NOT refer to a friend
* return 0, -- if client_id refers to a friend and we failed to find the friend (yet)
* return 1, ip if client_id refers to a friend and we found him
/* Copy friends DHT public key into dht_key.
*
* return -1 on failure (no key copied).
* return 0 on success (key copied).
*/
int onion_getfriendip(Onion_Client *onion_c, int friend_num, IP_Port *ip_port)
int onion_getfriend_DHT_pubkey(Onion_Client *onion_c, int friend_num, uint8_t *dht_key)
{
if ((uint32_t)friend_num >= onion_c->num_friends)
return -1;
@ -814,9 +812,28 @@ int onion_getfriendip(Onion_Client *onion_c, int friend_num, IP_Port *ip_port)
if (!onion_c->friends_list[friend_num].is_fake_clientid)
return -1;
return DHT_getfriendip(onion_c->dht, onion_c->friends_list[friend_num].fake_client_id, ip_port);
memcpy(dht_key, onion_c->friends_list[friend_num].fake_client_id, crypto_box_PUBLICKEYBYTES);
return 0;
}
/* Get the ip of friend friendnum and put it in ip_port
*
* return -1, -- if client_id does NOT refer to a friend
* return 0, -- if client_id refers to a friend and we failed to find the friend (yet)
* return 1, ip if client_id refers to a friend and we found him
*
*/
int onion_getfriendip(Onion_Client *onion_c, int friend_num, IP_Port *ip_port)
{
uint8_t dht_public_key[crypto_box_PUBLICKEYBYTES];
if (onion_getfriend_DHT_pubkey(onion_c, friend_num, dht_public_key) != 0)
return -1;
return DHT_getfriendip(onion_c->dht, dht_public_key, ip_port);
}
/* Set if friend is online or not.
* NOTE: This function is there and should be used so that we don't send useless packets to the friend if he is online.
*

View File

@ -172,6 +172,13 @@ int onion_set_friend_online(Onion_Client *onion_c, int friend_num, uint8_t is_on
*/
int onion_getfriendip(Onion_Client *onion_c, int friend_num, IP_Port *ip_port);
/* Copy friends DHT public key into dht_key.
*
* return -1 on failure (no key copied).
* return 0 on success (key copied).
*/
int onion_getfriend_DHT_pubkey(Onion_Client *onion_c, int friend_num, uint8_t *dht_key);
#define ONION_DATA_IN_RESPONSE_MIN_SIZE (crypto_box_PUBLICKEYBYTES + crypto_box_MACBYTES)
#define ONION_CLIENT_MAX_DATA_SIZE (MAX_DATA_REQUEST_SIZE - ONION_DATA_IN_RESPONSE_MIN_SIZE)