From db78c99ff45a99ac0a5944317b679b5139e3a2c0 Mon Sep 17 00:00:00 2001 From: irungentoo Date: Fri, 2 May 2014 21:25:23 -0400 Subject: [PATCH] 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. --- toxcore/Messenger.c | 604 ++++++++++++++++++++++------------------- toxcore/net_crypto.c | 141 ++++++++-- toxcore/net_crypto.h | 76 +++++- toxcore/onion_client.c | 31 ++- toxcore/onion_client.h | 7 + 5 files changed, 526 insertions(+), 333 deletions(-) diff --git a/toxcore/Messenger.c b/toxcore/Messenger.c index 7fdae8f0..9889d666 100644 --- a/toxcore/Messenger.c +++ b/toxcore/Messenger.c @@ -1857,12 +1857,307 @@ static void check_friend_request_timed_out(Messenger *m, uint32_t i, uint64_t t) } } +static int handle_status(void *object, int i, uint8_t status) +{ + uint64_t temp_time = unix_time(); + Messenger *m = object; + + 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; + } else { /* Went offline. */ + m->friendlist[i].crypt_connection_id = -1; + + if (m->friendlist[i].status == FRIEND_ONLINE) { + set_friend_status(m, i, FRIEND_CONFIRMED); + } + } + + return 0; +} + +static int handle_packet(void *object, int i, uint8_t *temp, uint16_t len) +{ + if (len == 0) + return -1; + + 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; + break; + } + + case PACKET_ID_NICKNAME: { + if (data_length > MAX_NAME_LENGTH || data_length == 0) + break; + + /* Make sure the NULL terminator is present. */ + uint8_t data_terminated[data_length + 1]; + memcpy(data_terminated, data, data_length); + data_terminated[data_length] = 0; + + /* inform of namechange before we overwrite the old name */ + if (m->friend_namechange) + m->friend_namechange(m, i, data_terminated, data_length, m->friend_namechange_userdata); + + memcpy(m->friendlist[i].name, data_terminated, data_length); + m->friendlist[i].name_length = data_length; + + break; + } + + case PACKET_ID_STATUSMESSAGE: { + if (data_length == 0 || data_length > MAX_STATUSMESSAGE_LENGTH) + break; + + /* Make sure the NULL terminator is present. */ + uint8_t data_terminated[data_length + 1]; + memcpy(data_terminated, data, data_length); + data_terminated[data_length] = 0; + + if (m->friend_statusmessagechange) + m->friend_statusmessagechange(m, i, data_terminated, data_length, + m->friend_statuschange_userdata); + + set_friend_statusmessage(m, i, data_terminated, data_length); + break; + } + + case PACKET_ID_USERSTATUS: { + if (data_length != 1) + break; + + USERSTATUS status = data[0]; + + if (status >= USERSTATUS_INVALID) + break; + + if (m->friend_userstatuschange) + m->friend_userstatuschange(m, i, status, m->friend_userstatuschange_userdata); + + set_friend_userstatus(m, i, status); + break; + } + + case PACKET_ID_TYPING: { + if (data_length != 1) + break; + + uint8_t typing = data[0]; + + set_friend_typing(m, i, typing); + + if (m->friend_typingchange) + m->friend_typingchange(m, i, typing, m->friend_typingchange_userdata); + + break; + } + + case PACKET_ID_MESSAGE: { + uint8_t *message_id = data; + uint8_t message_id_length = 4; + + if (data_length <= message_id_length) + break; + + uint8_t *message = data + message_id_length; + uint16_t message_length = data_length - message_id_length; + + /* Make sure the NULL terminator is present. */ + uint8_t message_terminated[message_length + 1]; + memcpy(message_terminated, message, message_length); + message_terminated[message_length] = 0; + + if (m->friendlist[i].receives_read_receipts) { + write_cryptpacket_id(m, i, PACKET_ID_RECEIPT, message_id, message_id_length); + } + + if (m->friend_message) + (*m->friend_message)(m, i, message_terminated, message_length, m->friend_message_userdata); + + break; + } + + case PACKET_ID_ACTION: { + uint8_t *message_id = data; + uint8_t message_id_length = 4; + + if (data_length <= message_id_length) + break; + + uint8_t *action = data + message_id_length; + uint16_t action_length = data_length - message_id_length; + + /* Make sure the NULL terminator is present. */ + uint8_t action_terminated[action_length + 1]; + memcpy(action_terminated, action, action_length); + action_terminated[action_length] = 0; + + if (m->friendlist[i].receives_read_receipts) { + write_cryptpacket_id(m, i, PACKET_ID_RECEIPT, message_id, message_id_length); + } + + if (m->friend_action) + (*m->friend_action)(m, i, action_terminated, action_length, m->friend_action_userdata); + + break; + } + + case PACKET_ID_RECEIPT: { + uint32_t msgid; + + if (data_length < sizeof(msgid)) + break; + + memcpy(&msgid, data, sizeof(msgid)); + msgid = ntohl(msgid); + + if (m->read_receipt) + (*m->read_receipt)(m, i, msgid, m->read_receipt_userdata); + + break; + } + + case PACKET_ID_INVITE_GROUPCHAT: { + if (data_length != crypto_box_PUBLICKEYBYTES) + break; + + if (m->group_invite) + (*m->group_invite)(m, i, data, m->group_invite_userdata); + + break; + } + + case PACKET_ID_JOIN_GROUPCHAT: { + if (data_length != crypto_box_PUBLICKEYBYTES * 2) + break; + + int groupnum = group_num(m, data); + + if (groupnum == -1) + break; + + if (!group_invited(m, i, groupnum)) + break; + + group_newpeer(m->chats[groupnum], data + crypto_box_PUBLICKEYBYTES); + /* This is just there to speedup joining. */ + chat_bootstrap(m->chats[groupnum], get_friend_ipport(m, i), data + crypto_box_PUBLICKEYBYTES); + break; + } + + case PACKET_ID_FILE_SENDREQUEST: { + if (data_length < 1 + sizeof(uint64_t) + 1) + break; + + uint8_t filenumber = data[0]; + uint64_t filesize; + net_to_host(data + 1, sizeof(filesize)); + memcpy(&filesize, data + 1, sizeof(filesize)); + m->friendlist[i].file_receiving[filenumber].status = FILESTATUS_NOT_ACCEPTED; + m->friendlist[i].file_receiving[filenumber].size = filesize; + m->friendlist[i].file_receiving[filenumber].transferred = 0; + + /* Force NULL terminate file name. */ + uint8_t filename_terminated[data_length - 1 - sizeof(uint64_t) + 1]; + memcpy(filename_terminated, data + 1 + sizeof(uint64_t), data_length - 1 - sizeof(uint64_t)); + filename_terminated[data_length - 1 - sizeof(uint64_t)] = 0; + + if (m->file_sendrequest) + (*m->file_sendrequest)(m, i, filenumber, filesize, filename_terminated, data_length - 1 - sizeof(uint64_t), + m->file_sendrequest_userdata); + + break; + } + + case PACKET_ID_FILE_CONTROL: { + if (data_length < 3) + break; + + uint8_t send_receive = data[0]; + uint8_t filenumber = data[1]; + uint8_t control_type = data[2]; + + if (handle_filecontrol(m, i, send_receive, filenumber, control_type, data + 3, data_length - 3) == -1) + break; + + if (m->file_filecontrol) + (*m->file_filecontrol)(m, i, send_receive, filenumber, control_type, data + 3, data_length - 3, + m->file_filecontrol_userdata); + + break; + } + + case PACKET_ID_FILE_DATA: { + if (data_length < 2) + break; + + uint8_t filenumber = data[0]; + + if (m->friendlist[i].file_receiving[filenumber].status == FILESTATUS_NONE) + break; + + m->friendlist[i].file_receiving[filenumber].transferred += (data_length - 1); + + if (m->file_filedata) + (*m->file_filedata)(m, i, filenumber, data + 1, data_length - 1, m->file_filedata_userdata); + + break; + } + + case PACKET_ID_MSI: { + if (data_length == 0) + break; + + if (m->msi_packet) + (*m->msi_packet)(m, i, data, data_length, m->msi_packet_userdata); + } + + default: { + break; + } + } + + 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; - int len; - uint8_t temp[MAX_CRYPTO_DATA_SIZE]; uint64_t temp_time = unix_time(); for (i = 0; i < m->numfriends; ++i) { @@ -1886,35 +2181,21 @@ void do_friends(Messenger *m) 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; - 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. */ - 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); - m->friendlist[i].crypt_connection_id = -1; - break; - - default: - break; + 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); } } - while (m->friendlist[i].status == FRIEND_ONLINE) { /* friend is online. */ + 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; @@ -1939,265 +2220,18 @@ void do_friends(Messenger *m) send_ping(m, i); } - len = read_cryptpacket(m->net_crypto, m->friendlist[i].crypt_connection_id, temp); - - if (len > 0) { - uint8_t packet_id = temp[0]; - uint8_t *data = temp + 1; - uint32_t data_length = len - 1; - - switch (packet_id) { - case PACKET_ID_ALIVE: { - m->friendlist[i].ping_lastrecv = temp_time; - break; - } - - case PACKET_ID_NICKNAME: { - if (data_length > MAX_NAME_LENGTH || data_length == 0) - break; - - /* Make sure the NULL terminator is present. */ - uint8_t data_terminated[data_length + 1]; - memcpy(data_terminated, data, data_length); - data_terminated[data_length] = 0; - - /* inform of namechange before we overwrite the old name */ - if (m->friend_namechange) - m->friend_namechange(m, i, data_terminated, data_length, m->friend_namechange_userdata); - - memcpy(m->friendlist[i].name, data_terminated, data_length); - m->friendlist[i].name_length = data_length; - - break; - } - - case PACKET_ID_STATUSMESSAGE: { - if (data_length == 0 || data_length > MAX_STATUSMESSAGE_LENGTH) - break; - - /* Make sure the NULL terminator is present. */ - uint8_t data_terminated[data_length + 1]; - memcpy(data_terminated, data, data_length); - data_terminated[data_length] = 0; - - if (m->friend_statusmessagechange) - m->friend_statusmessagechange(m, i, data_terminated, data_length, - m->friend_statuschange_userdata); - - set_friend_statusmessage(m, i, data_terminated, data_length); - break; - } - - case PACKET_ID_USERSTATUS: { - if (data_length != 1) - break; - - USERSTATUS status = data[0]; - - if (status >= USERSTATUS_INVALID) - break; - - if (m->friend_userstatuschange) - m->friend_userstatuschange(m, i, status, m->friend_userstatuschange_userdata); - - set_friend_userstatus(m, i, status); - break; - } - - case PACKET_ID_TYPING: { - if (data_length != 1) - break; - - uint8_t typing = data[0]; - - set_friend_typing(m, i, typing); - - if (m->friend_typingchange) - m->friend_typingchange(m, i, typing, m->friend_typingchange_userdata); - - break; - } - - case PACKET_ID_MESSAGE: { - uint8_t *message_id = data; - uint8_t message_id_length = 4; - - if (data_length <= message_id_length) - break; - - uint8_t *message = data + message_id_length; - uint16_t message_length = data_length - message_id_length; - - /* Make sure the NULL terminator is present. */ - uint8_t message_terminated[message_length + 1]; - memcpy(message_terminated, message, message_length); - message_terminated[message_length] = 0; - - if (m->friendlist[i].receives_read_receipts) { - write_cryptpacket_id(m, i, PACKET_ID_RECEIPT, message_id, message_id_length); - } - - if (m->friend_message) - (*m->friend_message)(m, i, message_terminated, message_length, m->friend_message_userdata); - - break; - } - - case PACKET_ID_ACTION: { - uint8_t *message_id = data; - uint8_t message_id_length = 4; - - if (data_length <= message_id_length) - break; - - uint8_t *action = data + message_id_length; - uint16_t action_length = data_length - message_id_length; - - /* Make sure the NULL terminator is present. */ - uint8_t action_terminated[action_length + 1]; - memcpy(action_terminated, action, action_length); - action_terminated[action_length] = 0; - - if (m->friendlist[i].receives_read_receipts) { - write_cryptpacket_id(m, i, PACKET_ID_RECEIPT, message_id, message_id_length); - } - - if (m->friend_action) - (*m->friend_action)(m, i, action_terminated, action_length, m->friend_action_userdata); - - break; - } - - case PACKET_ID_RECEIPT: { - uint32_t msgid; - - if (data_length < sizeof(msgid)) - break; - - memcpy(&msgid, data, sizeof(msgid)); - msgid = ntohl(msgid); - - if (m->read_receipt) - (*m->read_receipt)(m, i, msgid, m->read_receipt_userdata); - - break; - } - - case PACKET_ID_INVITE_GROUPCHAT: { - if (data_length != crypto_box_PUBLICKEYBYTES) - break; - - if (m->group_invite) - (*m->group_invite)(m, i, data, m->group_invite_userdata); - - break; - } - - case PACKET_ID_JOIN_GROUPCHAT: { - if (data_length != crypto_box_PUBLICKEYBYTES * 2) - break; - - int groupnum = group_num(m, data); - - if (groupnum == -1) - break; - - if (!group_invited(m, i, groupnum)) - break; - - group_newpeer(m->chats[groupnum], data + crypto_box_PUBLICKEYBYTES); - /* This is just there to speedup joining. */ - chat_bootstrap(m->chats[groupnum], get_friend_ipport(m, i), data + crypto_box_PUBLICKEYBYTES); - break; - } - - case PACKET_ID_FILE_SENDREQUEST: { - if (data_length < 1 + sizeof(uint64_t) + 1) - break; - - uint8_t filenumber = data[0]; - uint64_t filesize; - net_to_host(data + 1, sizeof(filesize)); - memcpy(&filesize, data + 1, sizeof(filesize)); - m->friendlist[i].file_receiving[filenumber].status = FILESTATUS_NOT_ACCEPTED; - m->friendlist[i].file_receiving[filenumber].size = filesize; - m->friendlist[i].file_receiving[filenumber].transferred = 0; - - /* Force NULL terminate file name. */ - uint8_t filename_terminated[data_length - 1 - sizeof(uint64_t) + 1]; - memcpy(filename_terminated, data + 1 + sizeof(uint64_t), data_length - 1 - sizeof(uint64_t)); - filename_terminated[data_length - 1 - sizeof(uint64_t)] = 0; - - if (m->file_sendrequest) - (*m->file_sendrequest)(m, i, filenumber, filesize, filename_terminated, data_length - 1 - sizeof(uint64_t), - m->file_sendrequest_userdata); - - break; - } - - case PACKET_ID_FILE_CONTROL: { - if (data_length < 3) - break; - - uint8_t send_receive = data[0]; - uint8_t filenumber = data[1]; - uint8_t control_type = data[2]; - - if (handle_filecontrol(m, i, send_receive, filenumber, control_type, data + 3, data_length - 3) == -1) - break; - - if (m->file_filecontrol) - (*m->file_filecontrol)(m, i, send_receive, filenumber, control_type, data + 3, data_length - 3, - m->file_filecontrol_userdata); - - break; - } - - case PACKET_ID_FILE_DATA: { - if (data_length < 2) - break; - - uint8_t filenumber = data[0]; - - if (m->friendlist[i].file_receiving[filenumber].status == FILESTATUS_NONE) - break; - - m->friendlist[i].file_receiving[filenumber].transferred += (data_length - 1); - - if (m->file_filedata) - (*m->file_filedata)(m, i, filenumber, data + 1, data_length - 1, m->file_filedata_userdata); - - break; - } - - case PACKET_ID_MSI: { - if (data_length == 0) - break; - - if (m->msi_packet) - (*m->msi_packet)(m, i, data, data_length, m->msi_packet_userdata); - } - - default: { - break; - } - } - } else { - 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); - m->friendlist[i].crypt_connection_id = -1; - set_friend_status(m, i, FRIEND_CONFIRMED); - } - - if (m->friendlist[i].ping_lastrecv + FRIEND_CONNECTION_TIMEOUT < temp_time) { - /* If we stopped recieving ping packets, kill it. */ - crypto_kill(m->net_crypto, m->friendlist[i].crypt_connection_id); - m->friendlist[i].crypt_connection_id = -1; - set_friend_status(m, i, FRIEND_CONFIRMED); - } - - break; + 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); + m->friendlist[i].crypt_connection_id = -1; + set_friend_status(m, i, FRIEND_CONFIRMED); + } + + if (m->friendlist[i].ping_lastrecv + FRIEND_CONNECTION_TIMEOUT < temp_time) { + /* If we stopped recieving ping packets, kill it. */ + crypto_kill(m->net_crypto, m->friendlist[i].crypt_connection_id); + m->friendlist[i].crypt_connection_id = -1; + set_friend_status(m, i, FRIEND_CONFIRMED); } } } diff --git a/toxcore/net_crypto.c b/toxcore/net_crypto.c index a0a913d2..9425afba 100644 --- a/toxcore/net_crypto.c +++ b/toxcore/net_crypto.c @@ -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? + } } } diff --git a/toxcore/net_crypto.h b/toxcore/net_crypto.h index 3d58e5c1..5d4ff35b 100644 --- a/toxcore/net_crypto.h +++ b/toxcore/net_crypto.h @@ -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); diff --git a/toxcore/onion_client.c b/toxcore/onion_client.c index c7ebcd15..ca92ee42 100644 --- a/toxcore/onion_client.c +++ b/toxcore/onion_client.c @@ -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. * diff --git a/toxcore/onion_client.h b/toxcore/onion_client.h index 6b960e40..4affcc6a 100644 --- a/toxcore/onion_client.h +++ b/toxcore/onion_client.h @@ -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)