Merge branch 'master' into harden

Conflicts:
	toxcore/DHT.c
This commit is contained in:
irungentoo 2013-11-10 14:32:46 -05:00
commit 57763f2737
15 changed files with 339 additions and 164 deletions

View File

@ -54,6 +54,11 @@ make check
sudo make install
cd ..
```
If your default prefix is /usr/local and you happen to get an error that says "error while loading shared libraries: libtoxcore.so.0: cannot open shared object file: No such file or directory", then you can try running ```sudo ldconfig```. If that doesn't fix it, run:
```
sudo echo "/usr/local/lib/" >> /etc/ld.so.conf.d/locallib.conf
sudo ldconfig
```
You also need recent [FFmpeg](http://git.videolan.org/?p=ffmpeg.git) libraries:
```bash

View File

@ -4,15 +4,12 @@ TESTS = messenger_autotest crypto_test network_test
check_PROGRAMS = messenger_autotest crypto_test network_test
messenger_autotest_SOURCES = \
../auto_tests/messenger_test.c
messenger_autotest_CFLAGS = \
$(LIBSODIUM_CFLAGS) \
$(NACL_CFLAGS) \
$(CHECK_CFLAGS)
messenger_autotest_LDADD = \
AUTOTEST_CFLAGS = \
$(LIBSODIUM_CFLAGS) \
$(NACL_CFLAGS) \
$(CHECK_CFLAGS)
AUTOTEST_LDADD = \
$(LIBSODIUM_LDFLAGS) \
$(NACL_LDFLAGS) \
libtoxcore.la \
@ -20,35 +17,26 @@ messenger_autotest_LDADD = \
$(NACL_LIBS) \
$(CHECK_LIBS)
messenger_autotest_SOURCES = ../auto_tests/messenger_test.c
messenger_autotest_CFLAGS = $(AUTOTEST_CFLAGS)
messenger_autotest_LDADD = $(AUTOTEST_LDADD)
crypto_test_SOURCES = ../auto_tests/crypto_test.c
crypto_test_CFLAGS = $(LIBSODIUM_CFLAGS) \
$(NACL_CFLAGS) \
$(CHECK_CFLAGS)
crypto_test_CFLAGS = $(AUTOTEST_CFLAGS)
crypto_test_LDADD = $(LIBSODIUM_LDFLAGS) \
$(NACL_LDFLAGS) \
libtoxcore.la \
$(LIBSODIUM_LIBS) \
$(NACL_LIBS) \
$(CHECK_LIBS)
crypto_test_LDADD = $(AUTOTEST_LDADD)
network_test_SOURCES = \
../auto_tests/network_test.c
network_test_CFLAGS = \
$(LIBSODIUM_CFLAGS) \
$(NACL_CFLAGS) \
$(CHECK_CFLAGS)
network_test_SOURCES = ../auto_tests/network_test.c
network_test_CFLAGS = $(AUTOTEST_CFLAGS)
network_test_LDADD = $(AUTOTEST_LDADD)
network_test_LDADD = \
$(LIBSODIUM_LDFLAGS) \
$(NACL_LDFLAGS) \
libtoxcore.la \
$(LIBSODIUM_LIBS) \
$(NACL_LIBS) \
$(CHECK_LIBS)
endif

View File

@ -0,0 +1,53 @@
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <sys/types.h>
#include <stdint.h>
#include <string.h>
#include <check.h>
#include <stdlib.h>
#include <time.h>
/*
#include "../<stuff to test>"
*/
START_TEST(test_creativetestnamegoeshere)
{
uint8_t test = 0;
ck_assert_msg(test == 0, "test: expected result 0, got %u.", test);
}
END_TEST
#define DEFTESTCASE(NAME) \
TCase *tc_##NAME = tcase_create(#NAME); \
tcase_add_test(tc_##NAME, test_##NAME); \
suite_add_tcase(s, tc_##NAME);
Suite *creativesuitenamegoeshere_suite(void)
{
Suite *s = suite_create("creativesuitedescritptiongoeshere");
DEFTESTCASE(/* remove test_ from test function names */ creativetestnamegoeshere);
return s;
}
int main(int argc, char *argv[])
{
srand((unsigned int) time(NULL));
Suite *creativesuitenamegoeshere = creativesuitenamegoeshere_suite();
SRunner *test_runner = srunner_create(creativesuitenamegoeshere);
int number_failed = 0;
srunner_run_all(test_runner, CK_NORMAL);
number_failed = srunner_ntests_failed(test_runner);
srunner_free(test_runner);
return number_failed;
}

View File

@ -45,4 +45,16 @@ to us then it is good.
Problems with this: People don't always have at least one online friend.
2. ...
2. Pick random nodes (add ourselves some random (fake) friends to increase the
pool of available nodes) and make then send requests to other nodes, the
response is then relayed back to us and compared to how the node should have
behaved. If the node is found to be behaving correctly, it is set as trusted.
Only trusted nodes are sent in send node packets, that is unless the exact node
being queried for in the getnode packet is present, it will be sent in the
sendnode packet even if it is not trusted.
The hypothesis is that if to be part of the network nodes have to behave
correctly it should prevent disruption from nodes that behave incorrectly.
(This idea is currently being implemented in the harden branch.)
...

View File

@ -1,10 +1,13 @@
A/V API reference
#A/V API reference
Take toxmsi/phone.c as a reference
##Take toxmsi/phone.c as a reference
Initialization:
###Initialization:
```
phone_t* initPhone(uint16_t _listen_port, uint16_t _send_port);
```
function initializes sample phone. _listen_port and _send_port are variables only meant
for local testing. You will not have to do anything regarding to that since
everything will be started within a mesenger.
@ -13,17 +16,22 @@ everything will be started within a mesenger.
Phone requires one msi session and two rtp sessions ( one for audio and one for
video ).
```
msi_session_t* msi_init_session( void* _core_handler, const uint8_t* _user_agent );
```
initializes msi session.
Params:
```
void* _core_handler - pointer to an object handling networking,
const uint8_t* _user_agent - string describing phone client version.
```
Return value:
msi_session_t* - pointer to a newly created msi session handler.
msi_session_t reference:
###msi_session_t reference:
How to handle msi session:
Controling is done via callbacks and action handlers.
@ -32,6 +40,7 @@ NOT TO PLACE SOMETHING LIKE LOOPS THAT TAKES A LOT OF TIME TO EXECUTE; every cal
directly from event loop. You can find examples in phone.c.
Register callbacks:
```
void msi_register_callback_call_started ( MCALLBACK );
void msi_register_callback_call_canceled ( MCALLBACK );
void msi_register_callback_call_rejected ( MCALLBACK );
@ -44,52 +53,72 @@ void msi_register_callback_recv_ending ( MCALLBACK );
void msi_register_callback_recv_error ( MCALLBACK );
void msi_register_callback_requ_timeout ( MCALLBACK );
```
MCALLBACK is defined as: void (*callback) (void* _arg)
msi_session_t* handler is being thrown as _arg so you can use that and _agent_handler to get to your own phone handler
msi_session_t* handler is being thrown as \_arg so you can use that and \_agent_handler to get to your own phone handler
directly from callback.
Actions:
```
int msi_invite ( msi_session_t* _session, call_type _call_type, uint32_t _timeoutms );
```
Sends call invite. Before calling/sending invite msi_session_t::_friend_id is needed to be set or else
it will not work. _call_type is type of the call ( Audio/Video ) and _timeoutms is how long
will poll wait until request is terminated.
```
int msi_hangup ( msi_session_t* _session );
```
Hangs up active call
```
int msi_answer ( msi_session_t* _session, call_type _call_type );
```
Answer incomming call. _call_type set's callee call type.
```
int msi_cancel ( msi_session_t* _session );
```
Cancel current request.
```
int msi_reject ( msi_session_t* _session );
```
Reject incomming call.
###Now for rtp:
Now for rtp:
You will need 2 sessions; one for audio one for video.
You start them with:
```
rtp_session_t* rtp_init_session ( int _max_users, int _multi_session );
```
Params:
```
int _max_users - max users. -1 if undefined
int _multi_session - any positive number means uses multi session; -1 if not.
```
Return value:
```
rtp_session_t* - pointer to a newly created rtp session handler.
```
How to handle rtp session:
###How to handle rtp session:
Take a look at
```
void* phone_handle_media_transport_poll ( void* _hmtc_args_p ) in phone.c
```
on example. Basically what you do is just receive a message via:
```
struct rtp_msg_s* rtp_recv_msg ( rtp_session_t* _session );
```
and then you use payload within the rtp_msg_s struct. Don't forget to deallocate it with:
void rtp_free_msg ( rtp_session_t* _session, struct rtp_msg_s* _msg );
@ -98,17 +127,20 @@ Receiving should be thread safe so don't worry about that.
When you capture and encode a payload you want to send it ( obviously ).
first create a new message with:
```
struct rtp_msg_s* rtp_msg_new ( rtp_session_t* _session, const uint8_t* _data, uint32_t _length );
```
and then send it with:
```
int rtp_send_msg ( rtp_session_t* _session, struct rtp_msg_s* _msg, void* _core_handler );
```
_core_handler is the same network handler as in msi_session_s struct.
A/V initialization:
##A/V initialization:
```
int init_receive_audio(codec_state *cs);
int init_receive_video(codec_state *cs);
Initialises the A/V decoders. On failure it will print the reason and return 0. On success it will return 1.
@ -122,30 +154,36 @@ int video_encoder_refresh(codec_state *cs, int bps);
Reinitialises the video encoder with a new bitrate. ffmpeg does not expose the needed VP8 feature to change the bitrate on the fly, so this serves as a workaround.
In the future, VP8 should be used directly and ffmpeg should be dropped from the dependencies.
The variable bps is the required bitrate in bits per second.
```
A/V encoding/decoding:
###A/V encoding/decoding:
```
void *encode_video_thread(void *arg);
```
Spawns the video encoding thread. The argument should hold a pointer to a codec_state.
This function should only be called if video encoding is supported (when init_send_video returns 1).
Each video frame gets encoded into a packet, which is sent via RTP. Every 60 frames a new bidirectional interframe is encoded.
```
void *encode_audio_thread(void *arg);
```
Spawns the audio encoding thread. The argument should hold a pointer to a codec_state.
This function should only be called if audio encoding is supported (when init_send_audio returns 1).
Audio frames are read from the selected audio capture device during intitialisation. This audio capturing can be rerouted to a different device on the fly.
Each audio frame is encoded into a packet, and sent via RTP. All audio frames have the same amount of samples, which is defined in AV_codec.h.
```
int video_decoder_refresh(codec_state *cs, int width, int height);
```
Sets the SDL window dimensions and creates a pixel buffer with the requested size. It also creates a scaling context, which will be used to convert the input image format to YUV420P.
```
void *decode_video_thread(void *arg);
```
Spawns a video decoding thread. The argument should hold a pointer to a codec_state. The codec_state is assumed to contain a successfully initialised video decoder.
This function reads video packets and feeds them to the video decoder. If the video frame's resolution has changed, video_decoder_refresh() is called. Afterwards, the frame is displayed on the SDL window.
```
void *decode_audio_thread(void *arg);
```
Spawns an audio decoding thread. The argument should hold a pointer to a codec_state. The codec_state is assumed to contain a successfully initialised audio decoder.
All received audio packets are pushed into a jitter buffer and are reordered. If there is a missing packet, or a packet has arrived too late, it is treated as a lost packet and the audio decoder is informed of the packet loss. The audio decoder will then try to reconstruct the lost packet, based on information from previous packets.
Audio is played on the default OpenAL output device.
@ -153,4 +191,4 @@ Audio is played on the default OpenAL output device.
If you have any more qustions/bug reports/feature request contact the following users on the irc channel #tox-dev on irc.freenode.net:
For RTP and MSI: mannol
For audio and video: Martijnvdc
For audio and video: Martijnvdc

View File

@ -814,110 +814,109 @@ static uint8_t sent_getnode_to_node(DHT *dht, uint8_t *client_id, IP_Port node_i
/* Function is needed in following functions. */
static int send_hardening_getnode_res(DHT *dht, Node_format *sendto, Node_format *list, uint16_t num_nodes);
static int handle_sendnodes(void *object, IP_Port source, uint8_t *packet, uint32_t length)
static int handle_sendnodes_core(void *object, IP_Port source, uint8_t *packet, uint32_t length,
size_t node_format_size, uint8_t *plain, uint16_t plain_length, uint32_t *num_nodes_out, Node_format *sendback_node)
{
DHT *dht = object;
uint32_t cid_size = 1 + CLIENT_ID_SIZE;
cid_size += crypto_box_NONCEBYTES + NODES_ENCRYPTED_MESSAGE_LENGTH + crypto_box_MACBYTES;
size_t Node4_format_size = sizeof(Node4_format);
if (length > (cid_size + Node4_format_size * MAX_SENT_NODES) ||
((length - cid_size) % Node4_format_size) != 0 ||
(length < cid_size + Node4_format_size))
if (plain_length != MAX_SENT_NODES * node_format_size + NODES_ENCRYPTED_MESSAGE_LENGTH)
return 1;
uint32_t num_nodes = (length - cid_size) / Node4_format_size;
uint8_t plain[Node4_format_size * MAX_SENT_NODES + NODES_ENCRYPTED_MESSAGE_LENGTH];
DHT *dht = object;
uint32_t cid_size = 1 + CLIENT_ID_SIZE + crypto_box_NONCEBYTES + NODES_ENCRYPTED_MESSAGE_LENGTH + crypto_box_MACBYTES;
if (length <= cid_size) /* too short */
return 1;
uint32_t data_size = length - cid_size;
if ((data_size % node_format_size) != 0) /* invalid length */
return 1;
uint32_t num_nodes = data_size / node_format_size;
if (num_nodes > MAX_SENT_NODES) /* too long */
return 1;
int len = decrypt_data(
packet + 1,
dht->c->self_secret_key,
packet + 1 + CLIENT_ID_SIZE,
packet + 1 + CLIENT_ID_SIZE + crypto_box_NONCEBYTES,
num_nodes * Node4_format_size + NODES_ENCRYPTED_MESSAGE_LENGTH + crypto_box_MACBYTES, plain );
num_nodes * node_format_size + NODES_ENCRYPTED_MESSAGE_LENGTH + crypto_box_MACBYTES,
plain);
if ((unsigned int)len != num_nodes * Node4_format_size + NODES_ENCRYPTED_MESSAGE_LENGTH)
if ((unsigned int)len != num_nodes * node_format_size + NODES_ENCRYPTED_MESSAGE_LENGTH)
return 1;
if (!sent_getnode_to_node(dht, packet + 1, source, plain + num_nodes * node_format_size, sendback_node))
return 1;
/* store the address the *request* was sent to */
addto_lists(dht, source, packet + 1);
*num_nodes_out = num_nodes;
return 0;
}
static int handle_sendnodes(void *object, IP_Port source, uint8_t *packet, uint32_t length)
{
DHT *dht = object;
size_t node4_format_size = sizeof(Node4_format);
uint8_t plain[node4_format_size * MAX_SENT_NODES + NODES_ENCRYPTED_MESSAGE_LENGTH];
uint32_t num_nodes;
Node_format sendback_node;
if (!sent_getnode_to_node(dht, packet + 1, source, plain + num_nodes * Node4_format_size, &sendback_node))
if (handle_sendnodes_core(object, source, packet, length, node4_format_size, plain, sizeof(plain), &num_nodes,
&sendback_node))
return 1;
Node4_format *nodes4_list = (Node4_format *)(plain);
Node_format nodes_list[MAX_SENT_NODES];
uint32_t i, num_nodes_ok = 0;
uint32_t i;
IP_Port ipp;
ipp.ip.family = AF_INET;
Node_format nodes_list[MAX_SENT_NODES];
/* blow up from Node4 (IPv4) wire format to Node (IPv4/IPv6) structure */
for (i = 0; i < num_nodes; i++)
if ((nodes4_list[i].ip_port.ip.uint32 != 0) && (nodes4_list[i].ip_port.ip.uint32 != (uint32_t)~0)) {
memcpy(nodes_list[num_nodes_ok].client_id, nodes4_list[i].client_id, CLIENT_ID_SIZE);
nodes_list[num_nodes_ok].ip_port.ip.family = AF_INET;
nodes_list[num_nodes_ok].ip_port.ip.ip4.uint32 = nodes4_list[i].ip_port.ip.uint32;
nodes_list[num_nodes_ok].ip_port.port = nodes4_list[i].ip_port.port;
ipp.ip.ip4.uint32 = nodes4_list[i].ip_port.ip.uint32;
ipp.port = nodes4_list[i].ip_port.port;
num_nodes_ok++;
send_ping_request(dht->ping, ipp, nodes4_list[i].client_id);
returnedip_ports(dht, ipp, nodes4_list[i].client_id, packet + 1);
memcpy(nodes_list[i].client_id, nodes4_list[i].client_id, CLIENT_ID_SIZE);
ipport_copy(&nodes_list[i].ip_port, &ipp);
}
if (num_nodes_ok < num_nodes) {
/* shouldn't happen */
num_nodes = num_nodes_ok;
}
send_hardening_getnode_res(dht, &sendback_node, nodes_list, num_nodes);
addto_lists(dht, source, packet + 1);
for (i = 0; i < num_nodes; ++i) {
send_ping_request(dht->ping, nodes_list[i].ip_port, nodes_list[i].client_id);
returnedip_ports(dht, nodes_list[i].ip_port, nodes_list[i].client_id, packet + 1);
}
return 0;
}
static int handle_sendnodes_ipv6(void *object, IP_Port source, uint8_t *packet, uint32_t length)
{
DHT *dht = object;
uint32_t cid_size = 1 + CLIENT_ID_SIZE;
cid_size += crypto_box_NONCEBYTES + NODES_ENCRYPTED_MESSAGE_LENGTH + crypto_box_MACBYTES;
size_t Node_format_size = sizeof(Node_format);
if (length > (cid_size + Node_format_size * MAX_SENT_NODES) ||
((length - cid_size) % Node_format_size) != 0 ||
(length < cid_size + Node_format_size))
return 1;
uint32_t num_nodes = (length - cid_size) / Node_format_size;
uint8_t plain[Node_format_size * MAX_SENT_NODES + NODES_ENCRYPTED_MESSAGE_LENGTH];
int len = decrypt_data(
packet + 1,
dht->c->self_secret_key,
packet + 1 + CLIENT_ID_SIZE,
packet + 1 + CLIENT_ID_SIZE + crypto_box_NONCEBYTES,
num_nodes * Node_format_size + NODES_ENCRYPTED_MESSAGE_LENGTH + crypto_box_MACBYTES, plain );
if ((unsigned int)len != num_nodes * Node_format_size + NODES_ENCRYPTED_MESSAGE_LENGTH)
return 1;
size_t node_format_size = sizeof(Node_format);
uint8_t plain[node_format_size * MAX_SENT_NODES + NODES_ENCRYPTED_MESSAGE_LENGTH];
uint32_t num_nodes;
Node_format sendback_node;
if (!sent_getnode_to_node(dht, packet + 1, source, plain + num_nodes * Node_format_size, &sendback_node))
if (handle_sendnodes_core(object, source, packet, length, node_format_size, plain, sizeof(plain), &num_nodes,
&sendback_node))
return 1;
Node_format *nodes_list = (Node_format *)(plain);
uint32_t i;
Node_format nodes_list[MAX_SENT_NODES];
memcpy(nodes_list, plain, num_nodes * sizeof(Node_format));
send_hardening_getnode_res(dht, &sendback_node, nodes_list, num_nodes);
addto_lists(dht, source, packet + 1);
for (i = 0; i < num_nodes; ++i) {
send_ping_request(dht->ping, nodes_list[i].ip_port, nodes_list[i].client_id);
returnedip_ports(dht, nodes_list[i].ip_port, nodes_list[i].client_id, packet + 1);
}
for (i = 0; i < num_nodes; i++)
if (ipport_isset(&nodes_list[i].ip_port)) {
send_ping_request(dht->ping, nodes_list[i].ip_port, nodes_list[i].client_id);
returnedip_ports(dht, nodes_list[i].ip_port, nodes_list[i].client_id, packet + 1);
}
return 0;
}

View File

@ -833,8 +833,7 @@ static int handle_SYNC2(Lossless_UDP *ludp, int connection_id, uint8_t counter,
{
Connection *connection = &tox_array_get(&ludp->connections, connection_id, Connection);
if (recv_packetnum == connection->orecv_packetnum) {
/* && sent_packetnum == connection->osent_packetnum) */
if (recv_packetnum == connection->orecv_packetnum && sent_packetnum == connection->osent_packetnum) {
connection->status = LUDP_ESTABLISHED;
connection->recv_counter = counter;
++connection->send_counter;
@ -862,8 +861,8 @@ static void adjust_datasendspeed(Connection *connection, uint32_t req_packets)
return;
}
if (req_packets <= (connection->data_rate / connection->SYNC_rate) / 5 || req_packets <= 10) {
connection->data_rate += (connection->data_rate / 8) + 1;
if (req_packets <= (connection->data_rate / connection->SYNC_rate) / 4 || req_packets <= 10) {
connection->data_rate += (connection->data_rate / 4) + 1;
if (connection->data_rate > connection->sendbuffer_length * connection->SYNC_rate)
connection->data_rate = connection->sendbuffer_length * connection->SYNC_rate;

View File

@ -868,13 +868,36 @@ int m_group_peername(Messenger *m, int groupnumber, int peernumber, uint8_t *nam
return group_peername(m->chats[groupnumber], peernumber, name);
}
/* Store the fact that we invited a specific friend.
*/
static void group_store_friendinvite(Messenger *m, int friendnumber, int groupnumber)
{
/* Add 1 to the groupchat number because 0 (default value in invited_groups) is a valid groupchat number */
m->friendlist[friendnumber].invited_groups[m->friendlist[friendnumber].invited_groups_num % MAX_INVITED_GROUPS] =
groupnumber + 1;
++m->friendlist[friendnumber].invited_groups_num;
}
/* return 1 if that friend was invited to the group
* return 0 if the friend was not or error.
*/
static uint8_t group_invited(Messenger *m, int friendnumber, int groupnumber)
{
//TODO: this function;
return 1;
uint32_t i;
uint16_t num = MAX_INVITED_GROUPS;
if (MAX_INVITED_GROUPS > m->friendlist[friendnumber].invited_groups_num)
num = m->friendlist[friendnumber].invited_groups_num;
for (i = 0; i < num; ++i) {
if (m->friendlist[friendnumber].invited_groups[i] == groupnumber + 1) {
return 1;
}
}
return 0;
}
/* invite friendnumber to groupnumber
@ -892,7 +915,8 @@ int invite_friend(Messenger *m, int friendnumber, int groupnumber)
if (m->friendlist[friendnumber].status == NOFRIEND || m->chats[groupnumber] == NULL)
return -1;
//TODO: store invited friends.
group_store_friendinvite(m, friendnumber, groupnumber);
if (write_cryptpacket_id(m, friendnumber, PACKET_ID_INVITE_GROUPCHAT, m->chats[groupnumber]->self_public_key,
crypto_box_PUBLICKEYBYTES) == 0)
return -1;
@ -1782,10 +1806,10 @@ void do_messenger(Messenger *m)
#ifdef LOGGING
if (now() > lastdump + DUMPING_CLIENTS_FRIENDS_EVERY_N_SECONDS) {
if (unix_time() > lastdump + DUMPING_CLIENTS_FRIENDS_EVERY_N_SECONDS) {
loglog(" = = = = = = = = \n");
lastdump = now();
lastdump = unix_time();
uint32_t client, last_pinged;
for (client = 0; client < LCLIENT_LIST; client++) {

View File

@ -52,6 +52,9 @@
#define PACKET_ID_JOIN_GROUPCHAT 145
#define PACKET_ID_ACCEPT_GROUPCHAT 146
/* Max number of groups we can invite someone at the same time to. */
#define MAX_INVITED_GROUPS 64
/* Status definitions. */
enum {
NOFRIEND,
@ -148,6 +151,8 @@ typedef struct {
uint64_t ping_lastsent;
struct File_Transfers file_sending[MAX_CONCURRENT_FILE_PIPES];
struct File_Transfers file_receiving[MAX_CONCURRENT_FILE_PIPES];
int invited_groups[MAX_INVITED_GROUPS];
uint16_t invited_groups_num;
} Friend;
typedef struct Messenger {

View File

@ -205,13 +205,15 @@ static int addpeer(Group_Chat *chat, uint8_t *client_id)
Group_Peer *temp;
temp = realloc(chat->group, sizeof(Group_Peer) * (chat->numpeers + 1));
memset(&(temp[chat->numpeers]), 0, sizeof(Group_Peer));
if (temp == NULL)
return -1;
memset(&(temp[chat->numpeers]), 0, sizeof(Group_Peer));
chat->group = temp;
id_copy(chat->group[chat->numpeers].client_id, client_id);
chat->group[chat->numpeers].last_recv = unix_time();
chat->group[chat->numpeers].last_recv_msgping = unix_time();
++chat->numpeers;
return (chat->numpeers - 1);
}
@ -287,7 +289,8 @@ static int send_getnodes(Group_Chat *chat, IP_Port ip_port, int peernum)
chat->group[peernum].last_pinged = unix_time();
chat->group[peernum].pingid = contents.pingid;
return send_groupchatpacket(chat, ip_port, chat->group[peernum].client_id, (uint8_t *)&contents, sizeof(contents), 48);
return send_groupchatpacket(chat, ip_port, chat->group[peernum].client_id, (uint8_t *)&contents, sizeof(contents),
CRYPTO_PACKET_GROUP_CHAT_GET_NODES);
}
static int send_sendnodes(Group_Chat *chat, IP_Port ip_port, int peernum, uint64_t pingid)
@ -308,7 +311,7 @@ static int send_sendnodes(Group_Chat *chat, IP_Port ip_port, int peernum, uint64
}
return send_groupchatpacket(chat, ip_port, chat->group[peernum].client_id, (uint8_t *)&contents,
sizeof(contents.pingid) + sizeof(groupchat_nodes) * j, 49);
sizeof(contents.pingid) + sizeof(groupchat_nodes) * j, CRYPTO_PACKET_GROUP_CHAT_SEND_NODES);
}
static int handle_getnodes(Group_Chat *chat, IP_Port source, int peernum, uint8_t *data, uint32_t len)
@ -392,9 +395,9 @@ static int handle_data(Group_Chat *chat, uint8_t *data, uint32_t len)
if (chat->group[peernum].last_recv == temp_time)
return 1;
chat->group[peernum].last_recv = temp_time;
*/
chat->group[peernum].last_recv = unix_time();
uint32_t message_num;
memcpy(&message_num, data + crypto_box_PUBLICKEYBYTES, sizeof(uint32_t));
message_num = ntohl(message_num);
@ -412,21 +415,21 @@ static int handle_data(Group_Chat *chat, uint8_t *data, uint32_t len)
uint16_t contents_len = len - GROUP_DATA_MIN_SIZE;
switch (data[crypto_box_PUBLICKEYBYTES + sizeof(message_num)]) {
case 0: /* If message is ping */
case GROUP_CHAT_PING: /* If message is ping */
if (contents_len != 0)
return 1;
chat->group[peernum].last_recv_msgping = unix_time();
break;
case 16: /* If message is new peer */
case GROUP_CHAT_NEW_PEER: /* If message is new peer */
if (contents_len != crypto_box_PUBLICKEYBYTES)
return 1;
addpeer(chat, contents);
break;
case 64: /* If message is chat message */
case GROUP_CHAT_CHAT_MESSAGE: /* If message is chat message */
if (chat->group_message != NULL)
(*chat->group_message)(chat, peernum, contents, contents_len, chat->group_message_userdata);
@ -439,7 +442,7 @@ static int handle_data(Group_Chat *chat, uint8_t *data, uint32_t len)
}
if (handled == 1) {
sendto_allpeers(chat, data, len, 50);
sendto_allpeers(chat, data, len, CRYPTO_PACKET_GROUP_CHAT_BROADCAST);
return 0;
}
@ -461,9 +464,12 @@ static uint8_t send_data(Group_Chat *chat, uint8_t *data, uint32_t len, uint8_t
//TODO
id_copy(packet, chat->self_public_key);
memcpy(packet + crypto_box_PUBLICKEYBYTES, &message_num, sizeof(message_num));
memcpy(packet + GROUP_DATA_MIN_SIZE, data, len);
if (len != 0)
memcpy(packet + GROUP_DATA_MIN_SIZE, data, len);
packet[crypto_box_PUBLICKEYBYTES + sizeof(message_num)] = message_id;
return sendto_allpeers(chat, packet, len + GROUP_DATA_MIN_SIZE, 50);
return sendto_allpeers(chat, packet, len + GROUP_DATA_MIN_SIZE, CRYPTO_PACKET_GROUP_CHAT_BROADCAST);
}
/*
* Handle get nodes group packet.
@ -494,13 +500,13 @@ int handle_groupchatpacket(Group_Chat *chat, IP_Port source, uint8_t *packet, ui
return 1;
switch (number) {
case 48:
case CRYPTO_PACKET_GROUP_CHAT_GET_NODES:
return handle_getnodes(chat, source, peernum, data, len);
case 49:
case CRYPTO_PACKET_GROUP_CHAT_SEND_NODES:
return handle_sendnodes(chat, source, peernum, data, len);
case 50:
case CRYPTO_PACKET_GROUP_CHAT_BROADCAST:
return handle_data(chat, data, len);
default:
@ -512,13 +518,13 @@ int handle_groupchatpacket(Group_Chat *chat, IP_Port source, uint8_t *packet, ui
uint32_t group_sendmessage(Group_Chat *chat, uint8_t *message, uint32_t length)
{
return send_data(chat, message, length, 64); //TODO: better return values?
return send_data(chat, message, length, GROUP_CHAT_CHAT_MESSAGE); //TODO: better return values?
}
uint32_t group_newpeer(Group_Chat *chat, uint8_t *client_id)
{
addpeer(chat, client_id);
return send_data(chat, client_id, crypto_box_PUBLICKEYBYTES, 16); //TODO: better return values?
return send_data(chat, client_id, crypto_box_PUBLICKEYBYTES, GROUP_CHAT_NEW_PEER); //TODO: better return values?
}
void callback_groupmessage(Group_Chat *chat, void (*function)(Group_Chat *chat, int, uint8_t *, uint16_t, void *),
@ -561,10 +567,35 @@ static void ping_close(Group_Chat *chat)
}
}
/* Interval in seconds to send ping messages */
#define GROUP_PING_INTERVAL 30
static void ping_group(Group_Chat *chat)
{
if (is_timeout(chat->last_sent_ping, GROUP_PING_INTERVAL)) {
if (send_data(chat, 0, 0, GROUP_CHAT_PING) != 0) /* Ping */
chat->last_sent_ping = unix_time();
}
}
static void del_dead_peers(Group_Chat *chat)
{
uint32_t i;
for (i = 0; i < chat->numpeers; ++i) {
if (is_timeout(chat->group[i].last_recv_msgping, GROUP_PING_INTERVAL * 2)) {
delpeer(chat, chat->group[i].client_id);
}
}
}
void do_groupchat(Group_Chat *chat)
{
unix_time_update();
ping_close(chat);
ping_group(chat);
/* TODO: Maybe run this less? */
del_dead_peers(chat);
}
void kill_groupchat(Group_Chat *chat)

View File

@ -63,9 +63,14 @@ typedef struct Group_Chat {
uint32_t message_number;
void (*group_message)(struct Group_Chat *m, int, uint8_t *, uint16_t, void *);
void *group_message_userdata;
uint64_t last_sent_ping;
} Group_Chat;
#define GROUP_CHAT_PING 0
#define GROUP_CHAT_NEW_PEER 16
#define GROUP_CHAT_CHAT_MESSAGE 64
/* Copy the name of peernum to name.
* name must be at least MAX_NICK_BYTES long.
*

View File

@ -29,6 +29,9 @@
#define CRYPTO_PACKET_FRIEND_REQ 32 /* Friend request crypto packet ID. */
#define CRYPTO_PACKET_HARDENING 48 /* Hardening crypto packet ID. */
#define CRYPTO_PACKET_NAT_PING 254 /* NAT ping crypto packet ID. */
#define CRYPTO_PACKET_GROUP_CHAT_GET_NODES 48 /* Group chat get Nodes packet */
#define CRYPTO_PACKET_GROUP_CHAT_SEND_NODES 49 /* Group chat send Nodes packet */
#define CRYPTO_PACKET_GROUP_CHAT_BROADCAST 50 /* Group chat broadcast packet */
#define CRYPTO_HANDSHAKE_TIMEOUT (CONNECTION_TIMEOUT * 2)
#define CRYPTO_CONN_NO_CONNECTION 0

View File

@ -114,28 +114,35 @@ static uint64_t add_ping(PING *ping, IP_Port ipp) // O(n)
return ping->pings[p].id;
}
static bool is_pinging(PING *ping, IP_Port ipp, uint64_t ping_id) // O(n) TODO: Replace this with something else.
/* checks if ip/port or ping_id are already in the list to ping
* if both are set, both must match, otherwise the set must match
*
* returns 0 if neither is set or no match was found
* returns the (index + 1) of the match if one was found
*/
static int is_pinging(PING *ping, IP_Port ipp, uint64_t ping_id)
{
// O(n) TODO: Replace this with something else.
/* shouldn't that be an OR ? */
if (!ip_isset(&ipp.ip) && ping_id == 0)
return false;
/* at least one MUST be set */
uint8_t ip_valid = ip_isset(&ipp.ip);
size_t i, id;
if (!ip_valid && !ping_id)
return 0;
size_t i;
remove_timeouts(ping);
for (i = 0; i < ping->num_pings; i++) {
id = (ping->pos_pings + i) % PING_NUM_MAX;
size_t id = (ping->pos_pings + i) % PING_NUM_MAX;
/* ping_id = 0 means match any id. */
if ((!ip_isset(&ipp.ip) || ipport_equal(&ping->pings[id].ip_port, &ipp)) &&
(ping->pings[id].id == ping_id || ping_id == 0)) {
return true;
}
if (!ping_id || (ping->pings[id].id == ping_id))
if (!ip_valid || ipport_equal(&ping->pings[id].ip_port, &ipp))
return id + 1;
}
return false;
return 0;
}
#define DHT_PING_SIZE (1 + CLIENT_ID_SIZE + crypto_box_NONCEBYTES + sizeof(uint64_t) + crypto_box_MACBYTES)
@ -252,11 +259,13 @@ static int handle_ping_response(void *_dht, IP_Port source, uint8_t *packet, uin
return 1;
/* Make sure ping_id is correct. */
if (!is_pinging(ping, source, ping_id))
int ping_index = is_pinging(ping, source, ping_id);
if (!ping_index)
return 1;
// Associate source ip with client_id
addto_lists(dht, source, packet + 1);
/* Associate client_id with the ip the request was sent to */
addto_lists(dht, ping->pings[ping_index - 1].ip_port, packet + 1);
return 0;
}

View File

@ -521,7 +521,7 @@ uint64_t tox_file_dataremaining(Tox *tox, int friendnumber, uint8_t filenumber,
void tox_bootstrap_from_ip(Tox *tox, tox_IP_Port ip_port, uint8_t *public_key);
/* Resolves address into an IP address. If successful, sends a "get nodes"
* request to the given node with ip, port (in network byte order, HINT: use htons())
* request to the given node with ip, port (in network byte order, HINT: use htons())
* and public_key to setup connections
*
* address can be a hostname or an IP address (IPv4 or IPv6).

View File

@ -139,8 +139,10 @@ void loginit(uint16_t port)
if (logfile)
fclose(logfile);
if (!starttime)
starttime = now();
if (!starttime) {
unix_time_update();
starttime = unix_time();
}
struct tm *tm = localtime(&starttime);
@ -164,7 +166,7 @@ void loginit(uint16_t port)
void loglog(char *text)
{
if (logfile) {
fprintf(logfile, "%4u %s", (uint32_t)(now() - starttime), text);
fprintf(logfile, "%4u %s", (uint32_t)(unix_time() - starttime), text);
fflush(logfile);
return;
@ -175,7 +177,9 @@ void loglog(char *text)
size_t len = strlen(text);
if (!starttime) {
starttime = now();
unix_time_update();
starttime = unix_time();
logbufferprelen = 1024 + len - (len % 1024);
logbufferpredata = malloc(logbufferprelen);
logbufferprehead = logbufferpredata;
@ -193,7 +197,7 @@ void loglog(char *text)
logbufferprelen = lennew;
}
int written = sprintf(logbufferprehead, "%4u %s", (uint32_t)(now() - starttime), text);
int written = sprintf(logbufferprehead, "%4u %s", (uint32_t)(unix_time() - starttime), text);
logbufferprehead += written;
}