Merge branch 'master' into Jeffail-master

Conflicts:
	core/DHT.c
This commit is contained in:
irungentoo 2013-08-02 10:41:03 -04:00
commit b9176974a8
29 changed files with 1217 additions and 421 deletions

View File

@ -21,12 +21,15 @@ before_script:
- cd ..
# creating librarys' links and updating cache
- sudo ldconfig
# installing sphinx, needed for documentation
- sudo apt-get install python-sphinx
script:
- mkdir build && cd build
- cmake ..
- make -j3
# build docs separately
- make docs
notifications:
email: false

View File

@ -48,3 +48,4 @@ cmake_policy(SET CMP0011 NEW)
add_subdirectory(core)
add_subdirectory(testing)
add_subdirectory(other)
add_subdirectory(docs)

View File

@ -6,7 +6,6 @@
- [Homebrew](#homebrew)
- [Non-Homebrew](#non-homebrew)
- [Windows](#windows)
- [Usage](#usage)
<a name="installation" />
##Installation
@ -32,11 +31,14 @@ sudo checkinstall --install --pkgname libsodium --pkgversion 0.4.2 --nodoc
sudo ldconfig
```
Then clone this repo and run:
Then clone this repo and generate makefile:
```bash
git clone git://github.com/irungentoo/ProjectTox-Core.git
cd ProjectTox-Core
mkdir build && cd build
cmake ..
```
Note that you should call cmake on the root [`CMakeLists.txt`](/CMakeLists.txt) file only.
Then you can build any of the [`/testing`](/testing) and [`/other`](/other) that are currently supported on your platform by running:
```bash
@ -102,6 +104,7 @@ Navigate in `cmd` to this repo and run:
mkdir build && cd build
cmake -G "MinGW Makefiles" ..
```
Note that you should call cmake on the root [`CMakeLists.txt`](/CMakeLists.txt) file only.
Then you can build any of the [`/testing`](/testing) and [`/other`](/other) that are currently supported on your platform by running:
```cmd
@ -117,7 +120,3 @@ Or you could just build everything that is supported on your platform by running
mingw32-make
```
<a name="usage" />
## Usage
- [Start Guide](start_guide.md)

View File

@ -13,7 +13,7 @@ With the rise of governmental monitoring programs, Tox aims to be an easy to use
**How to build Tox on Linux**: [YouTube video](http://www.youtube.com/watch?v=M4WXE4VKmyg)<br />
**How to use Tox on Windows**: [YouTube video](http://www.youtube.com/watch?v=qg_j_sDb6WQ)<br />
**For Mac OSX read INSTALL.md**
**For Mac OSX read** [INSTALL.md](INSTALL.md)
### Objectives:
@ -35,13 +35,13 @@ Keep everything really simple.
- [ ] Streaming media
- [ ] ???
For further information, check our [To-do list](https://github.com/irungentoo/ProjectTox-Core/wiki/TODO)
For further information, check our [To-do list](http://wiki.tox.im/index.php/TODO)
### Why are you doing this? There are already a bunch of free skype alternatives.
The goal of this project is to create a configuration-free P2P skype
replacement. Configuration-free means that the user will simply have to open the program and
without any account configuration will be capable of adding people to his
friends list and start conversing with them. There are many so called skype replacements and all of them are either hard to
friends list and start conversing with them. There are many so-called skype replacements and all of them are either hard to
configure for the normal user or suffer from being way too centralized.
### Documentation:

View File

@ -1,9 +0,0 @@
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" => Text, tab and indent related
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" Use spaces instead of tabs
set expandtab
" 1 tab == 4 spaces
set shiftwidth=4
set tabstop=4

16
cmake/FindSphinx.cmake Normal file
View File

@ -0,0 +1,16 @@
find_program(SPHINX_EXECUTABLE NAMES sphinx-build
HINTS
$ENV{SPHINX_DIR}
PATH_SUFFIXES bin
DOC "Sphinx documentation generator"
)
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(Sphinx DEFAULT_MSG
SPHINX_EXECUTABLE
)
mark_as_advanced(
SPHINX_EXECUTABLE
)

View File

@ -85,7 +85,7 @@ typedef struct {
uint8_t hole_punching;
uint32_t punching_index;
uint32_t punching_timestamp;
uint32_t recvNATping_timestamp;
int64_t recvNATping_timestamp;
uint64_t NATping_id;
uint32_t NATping_timestamp;
} Friend;
@ -98,7 +98,7 @@ typedef struct {
typedef struct {
IP_Port ip_port;
uint64_t ping_id;
uint32_t timestamp;
int64_t timestamp;
} Pinged;
/*----------------------------------------------------------------------------------*/
@ -145,7 +145,8 @@ int id_closest(uint8_t * client_id, uint8_t * client_id1, uint8_t * client_id2)
*/
int client_in_list(Client_data * list, uint32_t length, uint8_t * client_id, IP_Port ip_port)
{
uint32_t i, temp_time = unix_time();
uint32_t i;
int64_t temp_time = unix_time();
for(i = 0; i < length; ++i) {
/*If ip_port is assigned to a different client_id replace it*/
@ -197,7 +198,8 @@ static int friend_number(uint8_t * client_id)
*/
int get_close_nodes(uint8_t * client_id, Node_format * nodes_list)
{
uint32_t i, j, k, temp_time = unix_time();
uint32_t i, j, k;
int64_t temp_time = unix_time();
int num_nodes = 0, closest, tout, inlist;
for (i = 0; i < LCLIENT_LIST; ++i) {
@ -283,7 +285,7 @@ int replace_bad( Client_data * list,
IP_Port ip_port )
{
uint32_t i;
uint32_t temp_time = unix_time();
int64_t temp_time = unix_time();
for(i = 0; i < length; ++i) {
/* if node is bad */
if(list[i].timestamp + BAD_NODE_TIMEOUT < temp_time) {
@ -308,7 +310,7 @@ int replace_good( Client_data * list,
uint8_t * comp_client_id )
{
uint32_t i;
uint32_t temp_time = unix_time();
int64_t temp_time = unix_time();
for(i = 0; i < length; ++i)
if(id_closest(comp_client_id, list[i].client_id, client_id) == 2) {
@ -371,7 +373,8 @@ void addto_lists(IP_Port ip_port, uint8_t * client_id)
*/
void returnedip_ports(IP_Port ip_port, uint8_t * client_id, uint8_t * nodeclient_id)
{
uint32_t i, j, temp_time = unix_time();
uint32_t i, j;
int64_t temp_time = unix_time();
if (memcmp(client_id, self_public_key, CLIENT_ID_SIZE) == 0) {
for (i = 0; i < LCLIENT_LIST; ++i) {
@ -411,8 +414,9 @@ void returnedip_ports(IP_Port ip_port, uint8_t * client_id, uint8_t * nodeclient
*/
int is_pinging(IP_Port ip_port, uint64_t ping_id)
{
uint32_t i, temp_time = unix_time();
uint32_t i;
uint8_t pinging;
int64_t temp_time = unix_time();
for (i = 0; i < LPING_ARRAY; ++i ) {
if ((pings[i].timestamp + PING_TIMEOUT) > temp_time) {
@ -434,8 +438,9 @@ int is_pinging(IP_Port ip_port, uint64_t ping_id)
/* Same as last function but for get_node requests. */
int is_gettingnodes(IP_Port ip_port, uint64_t ping_id)
{
uint32_t i, temp_time = unix_time();
uint32_t i;
uint8_t pinging;
int64_t temp_time = unix_time();
for(i = 0; i < LSEND_NODES_ARRAY; ++i ) {
if((send_nodes[i].timestamp + PING_TIMEOUT) > temp_time) {
@ -462,8 +467,10 @@ int is_gettingnodes(IP_Port ip_port, uint64_t ping_id)
*/
uint64_t add_pinging(IP_Port ip_port)
{
uint32_t i, j, temp_time = unix_time();
uint32_t i, j;
uint64_t ping_id = ((uint64_t)random_int() << 32) + random_int();
int64_t temp_time = unix_time();
for(i = 0; i < PING_TIMEOUT; ++i ) {
for(j = 0; j < LPING_ARRAY; ++j ) {
@ -484,7 +491,7 @@ uint64_t add_gettingnodes(IP_Port ip_port)
{
uint32_t i, j;
uint64_t ping_id = ((uint64_t)random_int() << 32) + random_int();
uint32_t temp_time = unix_time();
int64_t temp_time = unix_time();
for(i = 0; i < PING_TIMEOUT; ++i ) {
for(j = 0; j < LSEND_NODES_ARRAY; ++j ) {
@ -823,7 +830,8 @@ int DHT_delfriend(uint8_t * client_id)
/* TODO: Optimize this. */
IP_Port DHT_getfriendip(uint8_t * client_id)
{
uint32_t i, j, temp_time = unix_time();
uint32_t i, j;
int64_t temp_time = unix_time();
IP_Port empty = {{{0}}, 0};
for (i = 0; i < num_friends; ++i) {
@ -849,7 +857,7 @@ IP_Port DHT_getfriendip(uint8_t * client_id)
void doDHTFriends()
{
uint32_t i, j;
uint32_t temp_time = unix_time();
int64_t temp_time = unix_time();
uint32_t rand_node;
uint32_t index[MAX_FRIEND_CLIENTS];
@ -888,7 +896,7 @@ static uint32_t close_lastgetnodes;
void doClose()
{
uint32_t i;
uint32_t temp_time = unix_time();
int64_t temp_time = unix_time();
uint32_t num_nodes = 0;
uint32_t rand_node;
uint32_t index[LCLIENT_LIST];
@ -945,8 +953,9 @@ int route_packet(uint8_t * client_id, uint8_t * packet, uint32_t length)
static int friend_iplist(IP_Port * ip_portlist, uint16_t friend_num)
{
int num_ips = 0;
uint32_t i, temp_time = unix_time();
uint32_t i;
int64_t temp_time = unix_time();
if (friend_num >= num_friends)
return -1;
@ -979,7 +988,8 @@ int route_tofriend(uint8_t * friend_id, uint8_t * packet, uint32_t length)
if (num == -1)
return 0;
uint32_t i, sent = 0, temp_time = unix_time();
uint32_t i, sent = 0;
int64_t temp_time = unix_time();
Friend * friend = &friends_list[num];
Client_data * client;
@ -1012,6 +1022,7 @@ int routeone_tofriend(uint8_t * friend_id, uint8_t * packet, uint32_t length)
IP_Port ip_list[MAX_FRIEND_CLIENTS];
int n = 0;
uint32_t i, temp_time = unix_time();
int64_t temp_time = unix_time();
for (i = 0; i < MAX_FRIEND_CLIENTS; ++i) {
client = &friend->client_list[i];
@ -1184,7 +1195,8 @@ static void punch_holes(IP ip, uint16_t * port_list, uint16_t numports, uint16_t
static void doNAT()
{
uint32_t i, temp_time = unix_time();
uint32_t i;
int64_t temp_time = unix_time();
for (i = 0; i < num_friends; ++i) {
IP_Port ip_list[MAX_FRIEND_CLIENTS];
@ -1279,7 +1291,7 @@ int DHT_load(uint8_t * data, uint32_t size)
uint32_t i, j;
uint16_t temp;
/* uint32_t temp_time = unix_time(); */
/* int64_t temp_time = unix_time(); */
Client_data * client;
@ -1314,6 +1326,7 @@ int DHT_load(uint8_t * data, uint32_t size)
int DHT_isconnected()
{
uint32_t i, temp_time = unix_time();
int64_t temp_time = unix_time();
for(i = 0; i < LCLIENT_LIST; ++i) {
if(close_clientlist[i].timestamp + BAD_NODE_TIMEOUT > temp_time)

View File

@ -31,7 +31,7 @@ extern "C" {
#endif
/* Current time, unix format */
#define unix_time() ((uint32_t)time(NULL))
#define unix_time() ((int64_t)time(NULL))
/* size of the client_id in bytes */
#define CLIENT_ID_SIZE crypto_box_PUBLICKEYBYTES

View File

@ -23,13 +23,70 @@
#include "LAN_discovery.h"
#define MAX_INTERFACES 16
/*Return the broadcast ip
TODO: make it return the real one, not the 255.255.255.255 one.*/
#ifdef __linux
/* get the first working broadcast address that's not from "lo"
* returns higher than 0 on success
* returns 0 on error */
uint32_t get_broadcast(void)
{
/* not sure how many platforms this will
* run on, so it's wrapped in __linux for now */
struct sockaddr_in *sock_holder = NULL;
struct ifreq i_faces[MAX_INTERFACES];
struct ifconf ifconf;
int count = 0;
int sock = 0;
int i = 0;
/* configure ifconf for the ioctl call */
if((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
perror("[!] get_broadcast: socket() error");
return 0;
}
memset(i_faces, 0, sizeof(struct ifreq) * MAX_INTERFACES);
ifconf.ifc_buf = (char *)i_faces;
ifconf.ifc_len = sizeof(i_faces);
count = ifconf.ifc_len / sizeof(struct ifreq);
if(ioctl(sock, SIOCGIFCONF, &ifconf) < 0) {
perror("get_broadcast: ioctl() error");
return 0;
}
for(i = 0; i < count; i++) {
/* skip the loopback interface, as it's useless */
if(strcmp(i_faces[i].ifr_name, "lo") != 0) {
if(ioctl(sock, SIOCGIFBRDADDR, &i_faces[i]) < 0) {
perror("[!] get_broadcast: ioctl error");
return 0;
}
/* just to clarify where we're getting the values from */
sock_holder = (struct sockaddr_in *)&i_faces[i].ifr_broadaddr;
break;
}
}
close(sock);
return sock_holder->sin_addr.s_addr;
}
#endif
/* Return the broadcast ip */
IP broadcast_ip()
{
IP ip;
#ifdef __linux
ip.i = get_broadcast();
if(ip.i == 0)
/* error errored, but try anyway? */
ip.i = ~0;
#else
ip.i = ~0;
#endif
return ip;
}

View File

@ -28,6 +28,13 @@
#include "DHT.h"
/* used for get_broadcast() */
#ifdef __linux
#include <sys/ioctl.h>
#include <arpa/inet.h>
#include <linux/netdevice.h>
#endif
#ifdef __cplusplus
extern "C" {
#endif

View File

@ -21,67 +21,95 @@
*
*/
/* TODO: clean this file a bit.
There are a couple of useless variables to get rid of. */
/*
* TODO: clean this file a bit.
* There are a couple of useless variables to get rid of.
*/
#include "Lossless_UDP.h"
/* maximum data packets in sent and receive queues. */
#define MAX_QUEUE_NUM 16
/* maximum length of the data in the data packets */
/* #define MAX_DATA_SIZE 1024 */ /* defined in Lossless_UDP.h */
#define MAX_QUEUE_NUM 16
/* maximum number of data packets in the buffer */
#define BUFFER_PACKET_NUM (16-1)
/* Lossless UDP connection timeout.
timeout per connection is randomly set between CONNEXION_TIMEOUT and 2*CONNEXION_TIMEOUT */
/* 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
#define SYNC_RATE 2
/* initial send rate of data. */
#define DATA_SYNC_RATE 30
#define DATA_SYNC_RATE 30
typedef struct {
uint8_t data[MAX_DATA_SIZE];
uint8_t data[MAX_DATA_SIZE];
uint16_t size;
} Data;
typedef struct {
IP_Port ip_port;
uint8_t status; /* 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 inbound; /* 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. */
/*
* 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;
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 at which our last SYNC packet was sent. */
uint64_t last_sent; /* time at which our last data or handshake packet was sent. */
uint64_t last_recvSYNC; /* time at which we last received a SYNC packet from the other */
uint64_t last_recvdata; /* time at which we last received a DATA packet from the other */
uint64_t killat; /* time at which 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;
uint32_t recv_packetnum; /* number of data packets received (also used as handshake_id1) */
uint32_t orecv_packetnum; /* number of packets received by the other peer */
uint32_t sent_packetnum; /* number of data packets sent */
uint32_t osent_packetnum; /* number of packets sent by the other peer. */
uint32_t sendbuff_packetnum; /* number of latest packet written onto the sendbuffer */
uint32_t successful_sent; /* we know all packets before that number were successfully sent */
uint32_t successful_read; /* packet number of last packet read with the read_packet function */
uint32_t req_packets[BUFFER_PACKET_NUM]; /* list of currently requested packet numbers(by the other person) */
uint16_t num_req_paquets; /* total number of currently requested packets(by the other person) */
uint8_t recv_counter;
uint8_t send_counter;
uint8_t timeout; /* connection timeout in seconds. */
/*
* 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;
@ -94,26 +122,33 @@ static uint32_t connections_number; /* Number of connections in connections arra
/* Functions */
/* get connection id from IP_Port
return -1 if there are no connections like we are looking for
return id if it found it */
/*
* Get connection id from IP_Port
* Return -1 if there are no connections like we are looking for
* Return id if it found it
*/
int getconnection_id(IP_Port ip_port)
{
uint32_t i;
for (i = 0; i < MAX_CONNECTIONS; ++i) {
if (connections[i].ip_port.ip.i == ip_port.ip.i &&
connections[i].ip_port.port == ip_port.port && connections[i].status > 0)
connections[i].ip_port.port == ip_port.port &&
connections[i].status > 0)
return i;
}
return -1;
}
/* table of random numbers used below. */
static uint32_t randtable[6][256];
/* generate a handshake_id which depends on the ip_port.
this function will always give one unique handshake_id per ip_port.
TODO: make this better */
/*
* Generate a handshake_id which depends on the ip_port.
* This function will always give one unique handshake_id per ip_port.
*
* TODO: make this better
*/
uint32_t handshake_id(IP_Port source)
{
uint32_t id = 0, i;
@ -124,21 +159,27 @@ uint32_t handshake_id(IP_Port source)
}
if (id == 0) /* id can't be zero */
id = 1;
return id;
}
/* change the hnshake id associated with that ip_port
TODO: make this better */
/*
* Change the hanshake id associated with that ip_port
*
* TODO: make this better
*/
void change_handshake(IP_Port source)
{
uint8_t rand = random_int() % 4;
randtable[rand][((uint8_t *)&source)[rand]] = random_int();
}
/* initialize a new connection to ip_port
returns an integer corresponding to the connection id.
return -1 if it could not initialize the connection.
if there already was an existing connection to that ip_port return its number. */
/*
* Initialize a new connection to ip_port
* Returns an integer corresponding to the connection idt
* Return -1 if it could not initialize the connectiont
* If there already was an existing connection to that ip_port return its number.
*/
int new_connection(IP_Port ip_port)
{
int connect = getconnection_id(ip_port);
@ -148,8 +189,10 @@ int new_connection(IP_Port ip_port)
if(connections_number == connections_length) {
Connection * temp;
temp = realloc(connections, sizeof(Connection) * (connections_length + 1));
if(temp == NULL)
return -1;
memset(&temp[connections_length], 0, sizeof(Connection));
++connections_length;
connections = temp;
@ -159,31 +202,37 @@ int new_connection(IP_Port ip_port)
for (i = 0; i < MAX_CONNECTIONS; ++i) {
if(connections[i].status == 0) {
memset(&connections[i], 0, sizeof(Connection));
connections[i].ip_port = ip_port;
connections[i].status = 1;
connections[i].inbound = 0;
connections[i].handshake_id1 = handshake_id(ip_port);
connections[i].sent_packetnum = connections[i].handshake_id1;
connections[i].sendbuff_packetnum = connections[i].handshake_id1;
connections[i].successful_sent = connections[i].handshake_id1;
connections[i].SYNC_rate = SYNC_RATE;
connections[i].data_rate = DATA_SYNC_RATE;
connections[i].last_recvSYNC = current_time();
connections[i].last_sent = current_time();
connections[i].killat = ~0;
connections[i].send_counter = 0;
/* add randomness to timeout to prevent connections getting stuck in a loop. */
connections[i].timeout = CONNEXION_TIMEOUT + rand() % CONNEXION_TIMEOUT;
connections[i] = (Connection) {
.ip_port = ip_port,
.status = 1,
.inbound = 0,
.handshake_id1 = handshake_id(ip_port),
.sent_packetnum = connections[i].handshake_id1,
.sendbuff_packetnum = connections[i].handshake_id1,
.successful_sent = connections[i].handshake_id1,
.SYNC_rate = SYNC_RATE,
.data_rate = DATA_SYNC_RATE,
.last_recvSYNC = current_time(),
.last_sent = current_time(),
.killat = ~0,
.send_counter = 0,
/* add randomness to timeout to prevent connections getting stuck in a loop. */
.timeout = CONNEXION_TIMEOUT + rand() % CONNEXION_TIMEOUT
};
++connections_number;
return i;
}
}
return -1;
}
/* initialize a new inbound connection from ip_port
returns an integer corresponding to the connection id.
return -1 if it could not initialize the connection. */
/*
* Initialize a new inbound connection from ip_port
* Returns an integer corresponding to the connection id.
* Return -1 if it could not initialize the connection.
*/
int new_inconnection(IP_Port ip_port)
{
if (getconnection_id(ip_port) != -1)
@ -192,8 +241,10 @@ int new_inconnection(IP_Port ip_port)
if(connections_number == connections_length) {
Connection * temp;
temp = realloc(connections, sizeof(Connection) * (connections_length + 1));
if(temp == NULL)
return -1;
memset(&temp[connections_length], 0, sizeof(Connection));
++connections_length;
connections = temp;
@ -203,18 +254,23 @@ int new_inconnection(IP_Port ip_port)
for (i = 0; i < MAX_CONNECTIONS; ++i) {
if (connections[i].status == 0) {
memset(&connections[i], 0, sizeof(Connection));
connections[i].ip_port = ip_port;
connections[i].status = 2;
connections[i].inbound = 2;
connections[i].SYNC_rate = SYNC_RATE;
connections[i].data_rate = DATA_SYNC_RATE;
connections[i].last_recvSYNC = current_time();
connections[i].last_sent = current_time();
/* add randomness to timeout to prevent connections getting stuck in a loop. */
connections[i].timeout = CONNEXION_TIMEOUT + rand() % CONNEXION_TIMEOUT;
/* if this connection isn't handled within the timeout kill it. */
connections[i].killat = current_time() + 1000000UL*connections[i].timeout;
connections[i].send_counter = 127;
connections[i] = (Connection){
.ip_port = ip_port,
.status = 2,
.inbound = 2,
.SYNC_rate = SYNC_RATE,
.data_rate = DATA_SYNC_RATE,
.last_recvSYNC = current_time(),
.last_sent = current_time(),
.send_counter = 127,
/* add randomness to timeout to prevent connections getting stuck in a loop. */
.timeout = CONNEXION_TIMEOUT + rand() % CONNEXION_TIMEOUT,
/* if this connection isn't handled within the timeout kill it. */
.killat = current_time() + 1000000UL*connections[i].timeout
};
++connections_number;
return i;
}
@ -222,8 +278,10 @@ int new_inconnection(IP_Port ip_port)
return -1;
}
/* 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. */
/*
* 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.
*/
int incoming_connection()
{
uint32_t i;
@ -233,9 +291,11 @@ int incoming_connection()
return i;
}
}
return -1;
}
/*Try to free some memory from the connections array.*/
/* Try to free some memory from the connections array. */
static void free_connections()
{
uint32_t i;
@ -245,16 +305,20 @@ static void free_connections()
if(connections_length == i)
return;
Connection * temp;
temp = realloc(connections, sizeof(Connection) * i);
if(temp == NULL && i != 0)
return;
connections = temp;
connections_length = i;
}
/* return -1 if it could not kill the connection.
return 0 if killed successfully */
/*
* Return -1 if it could not kill the connection.
* Return 0 if killed successfully
*/
int kill_connection(int connection_id)
{
if (connection_id >= 0 && connection_id < MAX_CONNECTIONS) {
@ -269,9 +333,11 @@ int kill_connection(int connection_id)
return -1;
}
/* kill connection in seconds seconds.
return -1 if it can not kill the connection.
return 0 if it will kill it */
/*
* Kill connection in seconds.
* Return -1 if it can not kill the connection.
* Return 0 if it will kill it.
*/
int kill_connection_in(int connection_id, uint32_t seconds)
{
if (connection_id >= 0 && connection_id < MAX_CONNECTIONS) {
@ -283,12 +349,14 @@ int kill_connection_in(int connection_id, uint32_t seconds)
return -1;
}
/* check if connection is connected
return 0 no.
return 1 if attempting handshake
return 2 if handshake is done
return 3 if fully connected
return 4 if timed out and waiting to be killed */
/*
* Check if connection is connected:
* Return 0 no.
* Return 1 if attempting handshake.
* Return 2 if handshake is done.
* Return 3 if fully connected.
* Return 4 if timed out and waiting to be killed.
*/
int is_connected(int connection_id)
{
if (connection_id >= 0 && connection_id < MAX_CONNECTIONS)
@ -327,8 +395,10 @@ char id_packet(int connection_id)
{
if (connection_id < 0 || connection_id >= MAX_CONNECTIONS)
return -1;
if (recvqueue(connection_id) != 0 && connections[connection_id].status != 0)
return connections[connection_id].recvbuffer[connections[connection_id].successful_read % MAX_QUEUE_NUM].data[0];
return -1;
}
@ -338,7 +408,7 @@ int read_packet(int connection_id, uint8_t * data)
{
if (recvqueue(connection_id) != 0) {
uint16_t index = connections[connection_id].successful_read % MAX_QUEUE_NUM;
uint16_t size = connections[connection_id].recvbuffer[index].size;
uint16_t size = connections[connection_id].recvbuffer[index].size;
memcpy(data, connections[connection_id].recvbuffer[index].data, size);
++connections[connection_id].successful_read;
connections[connection_id].recvbuffer[index].size = 0;
@ -347,14 +417,15 @@ int read_packet(int connection_id, uint8_t * data)
return 0;
}
/* return 0 if data could not be put in packet queue
return 1 if data was put into the queue */
/*
* Return 0 if data could not be put in packet queue
* Return 1 if data was put into the queue
*/
int write_packet(int connection_id, uint8_t * data, uint32_t length)
{
if (length > MAX_DATA_SIZE)
return 0;
if (length == 0)
if (length > MAX_DATA_SIZE || length == 0)
return 0;
if (sendqueue(connection_id) < BUFFER_PACKET_NUM) {
uint32_t index = connections[connection_id].sendbuff_packetnum % MAX_QUEUE_NUM;
memcpy(connections[connection_id].sendbuffer[index].data, data, length);
@ -362,6 +433,7 @@ int write_packet(int connection_id, uint8_t * data, uint32_t length)
connections[connection_id].sendbuff_packetnum++;
return 1;
}
return 0;
}
@ -371,8 +443,11 @@ uint32_t missing_packets(int connection_id, uint32_t * requested)
uint32_t number = 0;
uint32_t i;
uint32_t temp;
if (recvqueue(connection_id) >= (BUFFER_PACKET_NUM - 1)) /* 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))
return 0;
for (i = connections[connection_id].recv_packetnum; i != connections[connection_id].osent_packetnum; i++) {
if(connections[connection_id].recvbuffer[i % MAX_QUEUE_NUM].size == 0) {
temp = htonl(i);
@ -380,14 +455,19 @@ uint32_t missing_packets(int connection_id, uint32_t * requested)
++number;
}
}
if(number == 0)
connections[connection_id].recv_packetnum = connections[connection_id].osent_packetnum;
return number;
}
/* Packet sending functions
One per packet type.
see docs/Lossless_UDP.txt for more information. */
/*
* BEGIN Packet sending functions
* One per packet type.
* see docs/Lossless_UDP.txt for more information.
*/
int send_handshake(IP_Port ip_port, uint32_t handshake_id1, uint32_t handshake_id2)
{
uint8_t packet[1 + 4 + 4];
@ -398,21 +478,22 @@ int send_handshake(IP_Port ip_port, uint32_t handshake_id1, uint32_t handshake_i
memcpy(packet + 1, &temp, 4);
temp = htonl(handshake_id2);
memcpy(packet + 5, &temp, 4);
return sendpacket(ip_port, packet, sizeof(packet));
}
int send_SYNC(uint32_t connection_id)
{
uint8_t packet[(BUFFER_PACKET_NUM*4 + 4 + 4 + 2)];
uint16_t index = 0;
IP_Port ip_port = connections[connection_id].ip_port;
uint8_t counter = connections[connection_id].send_counter;
IP_Port ip_port = connections[connection_id].ip_port;
uint8_t counter = connections[connection_id].send_counter;
uint32_t recv_packetnum = htonl(connections[connection_id].recv_packetnum);
uint32_t sent_packetnum = htonl(connections[connection_id].sent_packetnum);
uint32_t requested[BUFFER_PACKET_NUM];
uint32_t number = missing_packets(connection_id, requested);
uint32_t number = missing_packets(connection_id, requested);
packet[0] = 17;
index += 1;
@ -462,17 +543,24 @@ int send_DATA(uint32_t connection_id)
return 0;
}
/* END of packet sending functions */
/*
* END of packet sending functions
*
*
* BEGIN Packet handling functions
* One to handle each type of packets we receive
*/
/* Packet handling functions
One to handle each type of packets we receive
return 0 if handled correctly, 1 if packet is bad. */
/* Return 0 if handled correctly, 1 if packet is bad. */
int handle_handshake(uint8_t * packet, uint32_t length, IP_Port source)
{
if (length != (1 + 4 + 4))
return 1;
uint32_t temp;
uint32_t handshake_id1, handshake_id2;
int connection = getconnection_id(source);
memcpy(&temp, packet + 1, 4);
handshake_id1 = ntohl(temp);
@ -485,21 +573,22 @@ int handle_handshake(uint8_t * packet, uint32_t length, IP_Port source)
}
if (is_connected(connection) != 1)
return 1;
if (handshake_id2 == connections[connection].handshake_id1) { /* 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) {
connections[connection].status = 2;
/* NOTE: is this necessary?
connections[connection].handshake_id2 = handshake_id1; */
connections[connection].orecv_packetnum = handshake_id2;
connections[connection].osent_packetnum = handshake_id1;
connections[connection].recv_packetnum = handshake_id1;
connections[connection].recv_packetnum = handshake_id1;
connections[connection].successful_read = handshake_id1;
}
return 0;
return 0;
}
/* returns 1 if sync packet is valid
0 if not. */
/* returns 1 if sync packet is valid 0 if not. */
int SYNC_valid(uint32_t length)
{
if (length < 4 + 4 + 2)
@ -510,19 +599,19 @@ int SYNC_valid(uint32_t length)
return 1;
}
/* case 1: */
/* case 1 in handle_SYNC: */
int handle_SYNC1(IP_Port source, uint32_t recv_packetnum, uint32_t sent_packetnum)
{
if (handshake_id(source) == recv_packetnum) {
int x = new_inconnection(source);
if (x != -1) {
connections[x].orecv_packetnum = recv_packetnum;
connections[x].sent_packetnum = recv_packetnum;
connections[x].orecv_packetnum = recv_packetnum;
connections[x].sent_packetnum = recv_packetnum;
connections[x].sendbuff_packetnum = recv_packetnum;
connections[x].successful_sent = recv_packetnum;
connections[x].osent_packetnum = sent_packetnum;
connections[x].recv_packetnum = sent_packetnum;
connections[x].successful_read = sent_packetnum;
connections[x].successful_sent = recv_packetnum;
connections[x].osent_packetnum = sent_packetnum;
connections[x].recv_packetnum = sent_packetnum;
connections[x].successful_read = sent_packetnum;
return x;
}
@ -530,7 +619,7 @@ int handle_SYNC1(IP_Port source, uint32_t recv_packetnum, uint32_t sent_packetnu
return -1;
}
/* case 2: */
/* case 2 in handle_SYNC: */
int handle_SYNC2(int connection_id, uint8_t counter, uint32_t recv_packetnum, uint32_t sent_packetnum)
{
if (recv_packetnum == connections[connection_id].orecv_packetnum) {
@ -543,7 +632,7 @@ int handle_SYNC2(int connection_id, uint8_t counter, uint32_t recv_packetnum, ui
}
return 1;
}
/* case 3: */
/* case 3 in handle_SYNC: */
int handle_SYNC3(int connection_id, uint8_t counter, uint32_t recv_packetnum, uint32_t sent_packetnum, uint32_t * req_packets,
uint16_t number)
{
@ -553,17 +642,25 @@ int handle_SYNC3(int connection_id, uint8_t counter, uint32_t recv_packetnum, ui
uint32_t comp_2 = (sent_packetnum - connections[connection_id].successful_read); */
uint32_t comp_1 = (recv_packetnum - connections[connection_id].orecv_packetnum);
uint32_t comp_2 = (sent_packetnum - connections[connection_id].osent_packetnum);
if (comp_1 <= BUFFER_PACKET_NUM && comp_2 <= BUFFER_PACKET_NUM && comp_counter < 10 && comp_counter != 0) { /* packet valid */
/* packet valid */
if (comp_1 <= BUFFER_PACKET_NUM &&
comp_2 <= BUFFER_PACKET_NUM &&
comp_counter < 10 && comp_counter != 0) {
connections[connection_id].orecv_packetnum = recv_packetnum;
connections[connection_id].osent_packetnum = sent_packetnum;
connections[connection_id].successful_sent = recv_packetnum;
connections[connection_id].last_recvSYNC = current_time();
connections[connection_id].recv_counter = counter;
connections[connection_id].last_recvSYNC = current_time();
connections[connection_id].recv_counter = counter;
++connections[connection_id].send_counter;
for (i = 0; i < number; ++i) {
temp = ntohl(req_packets[i]);
memcpy(connections[connection_id].req_packets + i, &temp, 4 * number);
}
connections[connection_id].num_req_paquets = number;
return 0;
}
@ -575,6 +672,7 @@ int handle_SYNC(uint8_t *packet, uint32_t length, IP_Port source)
if (!SYNC_valid(length))
return 1;
int connection = getconnection_id(source);
uint8_t counter;
uint32_t temp;
@ -587,19 +685,27 @@ int handle_SYNC(uint8_t *packet, uint32_t length, IP_Port source)
recv_packetnum = ntohl(temp);
memcpy(&temp,packet + 6, 4);
sent_packetnum = ntohl(temp);
if (number != 0)
memcpy(req_packets, packet + 10, 4 * number);
if (connection == -1)
return handle_SYNC1(source, recv_packetnum, sent_packetnum);
if (connections[connection].status == 2)
return handle_SYNC2(connection, counter, recv_packetnum, sent_packetnum);
return handle_SYNC2(connection, counter,
recv_packetnum, sent_packetnum);
if (connections[connection].status == 3)
return handle_SYNC3(connection, counter, recv_packetnum, sent_packetnum, req_packets, number);
return handle_SYNC3(connection, counter, recv_packetnum,
sent_packetnum, req_packets, number);
return 0;
}
/* 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. */
/*
* 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.
*/
int add_recv(int connection_id, uint32_t data_num, uint8_t *data, uint16_t size)
{
if (size > MAX_DATA_SIZE)
@ -608,16 +714,22 @@ int add_recv(int connection_id, uint32_t data_num, uint8_t *data, uint16_t size)
uint32_t i;
uint32_t maxnum = connections[connection_id].successful_read + BUFFER_PACKET_NUM;
uint32_t sent_packet = data_num - connections[connection_id].osent_packetnum;
for (i = connections[connection_id].recv_packetnum; i != maxnum; ++i) {
if (i == data_num) {
memcpy(connections[connection_id].recvbuffer[i % MAX_QUEUE_NUM].data, data, size);
connections[connection_id].recvbuffer[i % MAX_QUEUE_NUM].size = size;
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;
}
break;
}
}
for (i = connections[connection_id].recv_packetnum; i != maxnum; ++i) {
if (connections[connection_id].recvbuffer[i % MAX_QUEUE_NUM].size != 0)
connections[connection_id].recv_packetnum = i;
@ -635,25 +747,30 @@ int handle_data(uint8_t *packet, uint32_t length, IP_Port source)
if (connection == -1)
return 1;
if (connections[connection].status != 3) /* Drop the data packet if connection is not connected. */
/* Drop the data packet if connection is not connected. */
if (connections[connection].status != 3)
return 1;
if (length > 1 + 4 + MAX_DATA_SIZE || length < 1 + 4 + 1)
return 1;
uint32_t temp;
uint32_t number;
uint16_t size = length - 1 - 4;
memcpy(&temp, packet + 1, 4);
number = ntohl(temp);
return add_recv(connection, number, packet + 5, size);
}
/* END of packet handling functions */
/*
* END of packet handling functions
*/
int LosslessUDP_handlepacket(uint8_t *packet, uint32_t length, IP_Port source)
{
switch (packet[0]) { //TODO: check if no break statement is correct???
switch (packet[0]) {
case 16:
return handle_handshake(packet, length, source);
@ -670,8 +787,10 @@ int LosslessUDP_handlepacket(uint8_t *packet, uint32_t length, IP_Port source)
return 0;
}
/* Send handshake requests
handshake packets are sent at the same rate as SYNC packets */
/*
* Send handshake requests
* handshake packets are sent at the same rate as SYNC packets
*/
void doNew()
{
uint32_t i;
@ -684,10 +803,13 @@ void doNew()
}
/* kill all timed out connections */
if ( connections[i].status > 0 && (connections[i].last_recvSYNC + connections[i].timeout * 1000000UL) < temp_time &&
connections[i].status != 4)
/* kill_connection(i); */
if (connections[i].status > 0 &&
(connections[i].last_recvSYNC + connections[i].timeout * 1000000UL) < temp_time &&
connections[i].status != 4) {
connections[i].status = 4;
/* kill_connection(i); */
}
if (connections[i].status > 0 && connections[i].killat < temp_time)
kill_connection(i);
}
@ -720,11 +842,13 @@ void doData()
}
}
/* TODO: flow control.
automatically adjusts send rates of packets for optimal transmission. */
#define MAX_SYNC_RATE 10
/*
* Automatically adjusts send rates of packets for optimal transmission.
*
* TODO: flow control.
*/
void adjustRates()
{
uint32_t i;
@ -744,8 +868,7 @@ void adjustRates()
}
}
/* 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()
{
doNew();

View File

@ -33,70 +33,90 @@ extern "C" {
/* maximum length of the data in the data packets */
#define MAX_DATA_SIZE 1024
/* Functions */
/* initialize a new connection to ip_port
returns an integer corresponding to the connection id.
return -1 if it could not initialize the connection.
if there already was an existing connection to that ip_port return its number. */
/*
* Initialize a new connection to ip_port
* Returns an integer corresponding to the connection id.
* Return -1 if it could not initialize the connection.
* Return number if there already was an existing connection to that ip_port.
*/
int new_connection(IP_Port ip_port);
/* get connection id from IP_Port
return -1 if there are no connections like we are looking for
return id if it found it */
/*
* Get connection id from IP_Port.
* Return -1 if there are no connections like we are looking for.
* Return id if it found it .
*/
int getconnection_id(IP_Port ip_port);
/* returns an integer corresponding to the next connection in our imcoming connection list
return -1 if there are no new incoming connections in the 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.
*/
int incoming_connection();
/* return -1 if it could not kill the connection.
return 0 if killed successfully */
/*
* Return -1 if it could not kill the connection.
* Return 0 if killed successfully
*/
int kill_connection(int connection_id);
/* kill connection in seconds seconds.
return -1 if it can not kill the connection.
return 0 if it will kill it */
/*
* Kill connection in seconds seconds.
* Return -1 if it can not kill the connection.
* Return 0 if it will kill it
*/
int kill_connection_in(int connection_id, uint32_t seconds);
/* returns the ip_port of the corresponding connection.
return 0 if there is no such connection. */
/*
* Returns the ip_port of the corresponding connection.
* Return 0 if there is no such connection.
*/
IP_Port connection_ip(int connection_id);
/* returns the id of the next packet in the queue
return -1 if no packet in queue */
/*
* Returns the id of the next packet in the queue
* Return -1 if no packet in queue
*/
char id_packet(int connection_id);
/* return 0 if there is no received data in the buffer.
return length of received packet if successful */
/*
* Return 0 if there is no received data in the buffer.
* Return length of received packet if successful
*/
int read_packet(int connection_id, uint8_t *data);
/* return 0 if data could not be put in packet queue
return 1 if data was put into the queue */
/*
* Return 0 if data could not be put in packet queue
* Return 1 if data was put into the queue
*/
int write_packet(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);
/* 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);
/* check if connection is connected
return 0 no.
return 1 if attempting handshake
return 2 if handshake is done
return 3 if fully connected
return 4 if timed out and wating to be killed */
/* Check if connection is connected:
* Return 0 no.
* Return 1 if attempting handshake.
* Return 2 if handshake is done.
* Return 3 if fully connected.
* Return 4 if timed out and wating to be killed.
*/
int is_connected(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();
/* if we receive a Lossless_UDP packet we call this function so it can be handled.
return 0 if packet is handled correctly.
return 1 if it didn't handle the packet or if the packet was shit. */
/*
* If we receive a Lossless_UDP packet, call this function so it can be handled.
* Return 0 if packet is handled correctly.
* Return 1 if it didn't handle the packet or if the packet was shit.
*/
int LosslessUDP_handlepacket(uint8_t *packet, uint32_t length, IP_Port source);
#ifdef __cplusplus

View File

@ -27,7 +27,7 @@
typedef struct {
uint8_t client_id[CLIENT_ID_SIZE];
int crypt_connection_id;
int friend_request_id; /* id of the friend request corresponding to the current friend request to the current friend. */
int64_t friend_request_id; /* id of the friend request corresponding to the current friend request to the current friend. */
uint8_t status; /* 0 if no friend, 1 if added, 2 if friend request sent, 3 if confirmed friend, 4 if online. */
uint8_t info[MAX_DATA_SIZE]; /* the data that is sent during the friend requests we do */
uint8_t name[MAX_NAME_LENGTH];
@ -94,24 +94,31 @@ int getclient_id(int friend_id, uint8_t *client_id)
return -1;
}
/* add a friend
set the data that will be sent along with friend request
client_id is the client id of the friend
data is the data and length is the length
returns the friend number if success
return -1 if key length is wrong.
return -2 if user's own key
return -3 if already a friend
return -4 for other*/
/*
* add a friend
* set the data that will be sent along with friend request
* client_id is the client id of the friend
* data is the data and length is the length
* returns the friend number if success
* return -1 if message length is too long
* return -2 if no message (message length must be >= 1 byte)
* return -3 if user's own key
* return -4 if friend request already sent or already a friend
* return -5 for unknown error
*/
int m_addfriend(uint8_t *client_id, uint8_t *data, uint16_t length)
{
if (length == 0 || length >=
(MAX_DATA_SIZE - crypto_box_PUBLICKEYBYTES - crypto_box_NONCEBYTES - crypto_box_BOXZEROBYTES + crypto_box_ZEROBYTES))
if (length >= (MAX_DATA_SIZE - crypto_box_PUBLICKEYBYTES
- crypto_box_NONCEBYTES - crypto_box_BOXZEROBYTES
+ crypto_box_ZEROBYTES))
return -1;
if (memcmp(client_id, self_public_key, crypto_box_PUBLICKEYBYTES) == 0)
if (length < 1)
return -2;
if (getfriend_id(client_id) != -1)
if (memcmp(client_id, self_public_key, crypto_box_PUBLICKEYBYTES) == 0)
return -3;
if (getfriend_id(client_id) != -1)
return -4;
uint32_t i;
for (i = 0; i <= numfriends; ++i) { /*TODO: dynamic memory allocation, this will segfault if there are more than MAX_NUM_FRIENDS*/
if(friendlist[i].status == 0) {
@ -129,7 +136,7 @@ int m_addfriend(uint8_t *client_id, uint8_t *data, uint16_t length)
return i;
}
}
return -4;
return -5;
}
int m_addfriend_norequest(uint8_t * client_id)
@ -484,7 +491,7 @@ static void doInbound()
/*Interval in seconds between LAN discovery packet sending*/
#define LAN_DISCOVERY_INTERVAL 60
static uint32_t last_LANdiscovery;
static int64_t last_LANdiscovery;
/*Send a LAN discovery packet every LAN_DISCOVERY_INTERVAL seconds*/
static void LANdiscovery()

View File

@ -45,15 +45,18 @@ extern "C" {
/* don't assume MAX_USERSTATUS_LENGTH will stay at 128, it may be increased
to an absurdly large number later */
/* add a friend
set the data that will be sent along with friend request
client_id is the client id of the friend
data is the data and length is the length
returns the friend number if success
return -1 if key length is wrong.
return -2 if user's own key
return -3 if already a friend
return -4 for other*/
/*
* add a friend
* set the data that will be sent along with friend request
* client_id is the client id of the friend
* data is the data and length is the length
* returns the friend number if success
* return -1 if message length is too long
* return -2 if no message (message length must be >= 1 byte)
* return -3 if user's own key
* return -4 if friend request already sent or already a friend
* return -5 for unknown error
*/
int m_addfriend(uint8_t *client_id, uint8_t *data, uint16_t length);

View File

@ -48,6 +48,12 @@ typedef struct {
static Crypto_Connection crypto_connections[MAX_CRYPTO_CONNECTIONS];
#define CONN_NO_CONNECTION 0
#define CONN_HANDSHAKE_SENT 1
#define CONN_NOT_CONFIRMED 2
#define CONN_ESTABLISHED 3
#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 */
@ -75,10 +81,9 @@ int encrypt_data(uint8_t *public_key, uint8_t *secret_key, uint8_t *nonce,
uint32_t i;
uint32_t check = 0;
for(i = 0; i < crypto_box_BOXZEROBYTES; ++i) {
if (temp_encrypted[i] != 0)
check = 1;
check |= temp_encrypted[i] ^ 0;
}
if(check == 1)
if(check != 0)
return -1;
/* unpad the encrypted message */
@ -110,10 +115,9 @@ int decrypt_data(uint8_t *public_key, uint8_t *secret_key, uint8_t *nonce,
uint32_t i;
uint32_t check = 0;
for(i = 0; i < crypto_box_ZEROBYTES; ++i) {
if (temp_plain[i] != 0)
check = 1;
check |= temp_plain[i] ^ 0;
}
if(check == 1)
if(check != 0)
return -1;
/* unpad the plain message */
@ -149,7 +153,7 @@ int read_cryptpacket(int crypt_connection_id, uint8_t *data)
{
if (crypt_connection_id < 0 || crypt_connection_id >= MAX_CRYPTO_CONNECTIONS)
return 0;
if (crypto_connections[crypt_connection_id].status != 3)
if (crypto_connections[crypt_connection_id].status != CONN_ESTABLISHED)
return 0;
uint8_t temp_data[MAX_DATA_SIZE];
int length = read_packet(crypto_connections[crypt_connection_id].number, temp_data);
@ -175,7 +179,7 @@ int write_cryptpacket(int crypt_connection_id, uint8_t *data, uint32_t length)
return 0;
if (length - crypto_box_BOXZEROBYTES + crypto_box_ZEROBYTES > MAX_DATA_SIZE - 1)
return 0;
if (crypto_connections[crypt_connection_id].status != 3)
if (crypto_connections[crypt_connection_id].status != CONN_ESTABLISHED)
return 0;
uint8_t temp_data[MAX_DATA_SIZE];
int len = encrypt_data(crypto_connections[crypt_connection_id].peersessionpublic_key,
@ -295,7 +299,7 @@ int getcryptconnection_id(uint8_t *public_key)
{
uint32_t i;
for (i = 0; i < MAX_CRYPTO_CONNECTIONS; ++i) {
if (crypto_connections[i].status > 0)
if (crypto_connections[i].status != CONN_NO_CONNECTION)
if (memcmp(public_key, crypto_connections[i].public_key, crypto_box_PUBLICKEYBYTES) == 0)
return i;
}
@ -315,12 +319,12 @@ int crypto_connect(uint8_t *public_key, IP_Port ip_port)
return -1;
}
for (i = 0; i < MAX_CRYPTO_CONNECTIONS; ++i) {
if (crypto_connections[i].status == 0) {
if (crypto_connections[i].status == CONN_NO_CONNECTION) {
int id = new_connection(ip_port);
if (id == -1)
return -1;
crypto_connections[i].number = id;
crypto_connections[i].status = 1;
crypto_connections[i].status = CONN_HANDSHAKE_SENT;
random_nonce(crypto_connections[i].recv_nonce);
memcpy(crypto_connections[i].public_key, public_key, crypto_box_PUBLICKEYBYTES);
crypto_box_keypair(crypto_connections[i].sessionpublic_key, crypto_connections[i].sessionsecret_key);
@ -374,8 +378,8 @@ int crypto_kill(int crypt_connection_id)
{
if (crypt_connection_id < 0 || crypt_connection_id >= MAX_CRYPTO_CONNECTIONS)
return 1;
if (crypto_connections[crypt_connection_id].status != 0) {
crypto_connections[crypt_connection_id].status = 0;
if (crypto_connections[crypt_connection_id].status != CONN_NO_CONNECTION) {
crypto_connections[crypt_connection_id].status = CONN_NO_CONNECTION;
kill_connection(crypto_connections[crypt_connection_id].number);
memset(&crypto_connections[crypt_connection_id], 0 ,sizeof(Crypto_Connection));
crypto_connections[crypt_connection_id].number = ~0;
@ -398,9 +402,9 @@ int accept_crypto_inbound(int connection_id, uint8_t *public_key, uint8_t *secre
return -1;
}*/
for (i = 0; i < MAX_CRYPTO_CONNECTIONS; ++i) {
if(crypto_connections[i].status == 0) {
if(crypto_connections[i].status == CONN_NO_CONNECTION) {
crypto_connections[i].number = connection_id;
crypto_connections[i].status = 2;
crypto_connections[i].status = CONN_NOT_CONFIRMED;
random_nonce(crypto_connections[i].recv_nonce);
memcpy(crypto_connections[i].sent_nonce, secret_nonce, crypto_box_NONCEBYTES);
memcpy(crypto_connections[i].peersessionpublic_key, session_key, crypto_box_PUBLICKEYBYTES);
@ -413,9 +417,9 @@ int accept_crypto_inbound(int connection_id, uint8_t *public_key, uint8_t *secre
crypto_connections[i].sessionpublic_key) == 1) {
increment_nonce(crypto_connections[i].recv_nonce);
uint32_t zero = 0;
crypto_connections[i].status = 3; /* connection status needs to be 3 for write_cryptpacket() to work */
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));
crypto_connections[i].status = 2; /* set it to its proper value right after. */
crypto_connections[i].status = CONN_NOT_CONFIRMED; /* set it to its proper value right after. */
return i;
}
return -1; /* this should never happen. */
@ -431,7 +435,7 @@ int is_cryptoconnected(int crypt_connection_id)
{
if (crypt_connection_id >= 0 && crypt_connection_id < MAX_CRYPTO_CONNECTIONS)
return crypto_connections[crypt_connection_id].status;
return 0;
return CONN_NO_CONNECTION;
}
/* Generate our public and private keys
@ -490,7 +494,7 @@ static void receive_crypto()
{
uint32_t i;
for (i = 0; i < MAX_CRYPTO_CONNECTIONS; ++i) {
if (crypto_connections[i].status == 1) {
if (crypto_connections[i].status == CONN_HANDSHAKE_SENT) {
uint8_t temp_data[MAX_DATA_SIZE];
uint8_t secret_nonce[crypto_box_NONCEBYTES];
uint8_t public_key[crypto_box_PUBLICKEYBYTES];
@ -507,17 +511,17 @@ static void receive_crypto()
memcpy(crypto_connections[i].peersessionpublic_key, session_key, crypto_box_PUBLICKEYBYTES);
increment_nonce(crypto_connections[i].sent_nonce);
uint32_t zero = 0;
crypto_connections[i].status = 3; /* connection status needs to be 3 for write_cryptpacket() to work */
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));
crypto_connections[i].status = 2; /* set it to its proper value right after. */
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
crypto_kill(crypto_connections[i].number);
}
if (crypto_connections[i].status == 2) {
if (id_packet(crypto_connections[i].number) == 3) {
if (crypto_connections[i].status == CONN_NOT_CONFIRMED) {
if (id_packet(crypto_connections[i].number) == CONN_ESTABLISHED) {
uint8_t temp_data[MAX_DATA_SIZE];
uint8_t data[MAX_DATA_SIZE];
int length = read_packet(crypto_connections[i].number, temp_data);
@ -527,7 +531,7 @@ static void receive_crypto()
uint32_t zero = 0;
if (len == sizeof(uint32_t) && memcmp(((uint8_t *)&zero), data, sizeof(uint32_t)) == 0) {
increment_nonce(crypto_connections[i].recv_nonce);
crypto_connections[i].status = 3;
crypto_connections[i].status = CONN_ESTABLISHED;
/* 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);
@ -556,8 +560,8 @@ static void killTimedout()
{
uint32_t i;
for (i = 0; i < MAX_CRYPTO_CONNECTIONS; ++i) {
if (crypto_connections[i].status != 0 && is_connected(crypto_connections[i].number) == 4)
crypto_connections[i].status = 4;
if (crypto_connections[i].status != CONN_NO_CONNECTION && is_connected(crypto_connections[i].number) == 4)
crypto_connections[i].status = CONN_TIMED_OUT;
else if (is_connected(crypto_connections[i].number) == 4) {
kill_connection(crypto_connections[i].number);
crypto_connections[i].number = ~0;

40
docs/CMakeLists.txt Normal file
View File

@ -0,0 +1,40 @@
# cmake should not fail if sphinx is missing
find_package(Sphinx)
if(SPHINX_EXECUTABLE)
if(NOT DEFINED SPHINX_THEME)
set(SPHINX_THEME default)
endif()
if(NOT DEFINED SPHINX_THEME_DIR)
set(SPHINX_THEME_DIR)
endif()
# configured documentation tools and intermediate build results
set(BINARY_BUILD_DIR "${CMAKE_CURRENT_BINARY_DIR}/_build")
# Sphinx cache with pickled ReST documents
set(SPHINX_CACHE_DIR "${CMAKE_CURRENT_BINARY_DIR}/_doctrees")
# HTML output directory
set(SPHINX_HTML_DIR "${CMAKE_CURRENT_BINARY_DIR}/html")
configure_file(
"${CMAKE_CURRENT_SOURCE_DIR}/conf.py"
"${BINARY_BUILD_DIR}/conf.py"
@ONLY)
add_custom_target(docs
${SPHINX_EXECUTABLE}
-b html
-c "${BINARY_BUILD_DIR}"
"${CMAKE_CURRENT_SOURCE_DIR}"
"${SPHINX_HTML_DIR}"
COMMENT "Building HTML documentation with Sphinx")
else()
add_custom_target(docs
echo
"Please install python-sphinx to build the docs or read the docs online: https://projecttox.readthedocs.org/en/latest"
COMMENT "No sphinx executebale found")
endif()

View File

@ -1,25 +0,0 @@
# Tox User Commands
Here's a list of commands that nTox accepts,
which can all be used by starting your line with
a */*. Currently there can be no spaces before this.
* */f* [ID]
+ Add a friend with ID [ID].
* */d*
+ Call doMessenger() which does...something?
* */m* \[FRIEND\_NUM\] \[MESSAGE\]
+ Message \[FRIEND\_NUM\] \[MESSAGE\].
* */n* \[NAME\]
+ Change your username to \[NAME\].
* */l*
+ Print your list of friends. (like you have any)
* */s* \[STATUS\]
+ Set your status to \[STATUS\].
* */a* \[ID\]
+ Accept friend request from \[ID\].
* */i*
+ Print useful info about your client.
* */h*
+ Print some help.
* */q/*
+ Quit Tox. (why ;_;)

48
docs/commands.rst Normal file
View File

@ -0,0 +1,48 @@
Tox User Commands
=================
Here's a list of commands that nTox accepts, which can all be used by
starting your line with a */*. Currently there can be no spaces before
this.
- */f* [ID]
- Add a friend with ID [ID].
- */d*
- Call doMessenger() which does...something?
- */m* [FRIEND\_NUM] [MESSAGE]
- Message [FRIEND\_NUM] [MESSAGE].
- */n* [NAME]
- Change your username to [NAME].
- */l*
- Print your list of friends. (like you have any)
- */s* [STATUS]
- Set your status to [STATUS].
- */a* [ID]
- Accept friend request from [ID].
- */i*
- Print useful info about your client.
- */h*
- Print some help.
- */q/*
- Quit Tox. (why ;\_;)

242
docs/conf.py Normal file
View File

@ -0,0 +1,242 @@
# -*- coding: utf-8 -*-
#
# ProjectTox documentation build configuration file, created by
# sphinx-quickstart on Wed Jul 31 23:07:35 2013.
#
# This file is execfile()d with the current directory set to its containing dir.
#
# Note that not all possible configuration values are present in this
# autogenerated file.
#
# All configuration values have a default; values that are commented out
# serve to show the default.
import sys, os
# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
#sys.path.insert(0, os.path.abspath('.'))
# -- General configuration -----------------------------------------------------
# If your documentation needs a minimal Sphinx version, state it here.
#needs_sphinx = '1.0'
# Add any Sphinx extension module names here, as strings. They can be extensions
# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
extensions = []
# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']
# The suffix of source filenames.
source_suffix = '.rst'
# The encoding of source files.
#source_encoding = 'utf-8-sig'
# The master toctree document.
master_doc = 'index'
# General information about the project.
project = u'ProjectTox'
copyright = u'2013, Tox Team'
# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
# built documents.
#
# The short X.Y version.
version = '0.1'
# The full version, including alpha/beta/rc tags.
release = '0.1'
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
#language = None
# There are two options for replacing |today|: either, you set today to some
# non-false value, then it is used:
#today = ''
# Else, today_fmt is used as the format for a strftime call.
#today_fmt = '%B %d, %Y'
# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
exclude_patterns = ['_build']
# The reST default role (used for this markup: `text`) to use for all documents.
#default_role = None
# If true, '()' will be appended to :func: etc. cross-reference text.
#add_function_parentheses = True
# If true, the current module name will be prepended to all description
# unit titles (such as .. function::).
#add_module_names = True
# If true, sectionauthor and moduleauthor directives will be shown in the
# output. They are ignored by default.
#show_authors = False
# The name of the Pygments (syntax highlighting) style to use.
pygments_style = 'sphinx'
# A list of ignored prefixes for module index sorting.
#modindex_common_prefix = []
# -- Options for HTML output ---------------------------------------------------
# The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes.
html_theme = 'default'
# Theme options are theme-specific and customize the look and feel of a theme
# further. For a list of options available for each theme, see the
# documentation.
#html_theme_options = {}
# Add any paths that contain custom themes here, relative to this directory.
#html_theme_path = []
# The name for this set of Sphinx documents. If None, it defaults to
# "<project> v<release> documentation".
#html_title = None
# A shorter title for the navigation bar. Default is the same as html_title.
#html_short_title = None
# The name of an image file (relative to this directory) to place at the top
# of the sidebar.
#html_logo = None
# The name of an image file (within the static path) to use as favicon of the
# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
# pixels large.
#html_favicon = None
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
html_static_path = ['_static']
# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
# using the given strftime format.
#html_last_updated_fmt = '%b %d, %Y'
# If true, SmartyPants will be used to convert quotes and dashes to
# typographically correct entities.
#html_use_smartypants = True
# Custom sidebar templates, maps document names to template names.
#html_sidebars = {}
# Additional templates that should be rendered to pages, maps page names to
# template names.
#html_additional_pages = {}
# If false, no module index is generated.
#html_domain_indices = True
# If false, no index is generated.
#html_use_index = True
# If true, the index is split into individual pages for each letter.
#html_split_index = False
# If true, links to the reST sources are added to the pages.
#html_show_sourcelink = True
# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
#html_show_sphinx = True
# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
#html_show_copyright = True
# If true, an OpenSearch description file will be output, and all pages will
# contain a <link> tag referring to it. The value of this option must be the
# base URL from which the finished HTML is served.
#html_use_opensearch = ''
# This is the file name suffix for HTML files (e.g. ".xhtml").
#html_file_suffix = None
# Output file base name for HTML help builder.
htmlhelp_basename = 'ProjectToxdoc'
# -- Options for LaTeX output --------------------------------------------------
latex_elements = {
# The paper size ('letterpaper' or 'a4paper').
#'papersize': 'letterpaper',
# The font size ('10pt', '11pt' or '12pt').
#'pointsize': '10pt',
# Additional stuff for the LaTeX preamble.
#'preamble': '',
}
# Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title, author, documentclass [howto/manual]).
latex_documents = [
('index', 'ProjectTox.tex', u'ProjectTox Documentation',
u'Tox Team', 'manual'),
]
# The name of an image file (relative to this directory) to place at the top of
# the title page.
#latex_logo = None
# For "manual" documents, if this is true, then toplevel headings are parts,
# not chapters.
#latex_use_parts = False
# If true, show page references after internal links.
#latex_show_pagerefs = False
# If true, show URL addresses after external links.
#latex_show_urls = False
# Documents to append as an appendix to all manuals.
#latex_appendices = []
# If false, no module index is generated.
#latex_domain_indices = True
# -- Options for manual page output --------------------------------------------
# One entry per manual page. List of tuples
# (source start file, name, description, authors, manual section).
man_pages = [
('index', 'projecttox', u'ProjectTox Documentation',
[u'Tox Team'], 1)
]
# If true, show URL addresses after external links.
#man_show_urls = False
# -- Options for Texinfo output ------------------------------------------------
# Grouping the document tree into Texinfo files. List of tuples
# (source start file, target name, title, author,
# dir menu entry, description, category)
texinfo_documents = [
('index', 'ProjectTox', u'ProjectTox Documentation',
u'Tox Team', 'ProjectTox', 'One line description of project.',
'Miscellaneous'),
]
# Documents to append as an appendix to all manuals.
#texinfo_appendices = []
# If false, no module index is generated.
#texinfo_domain_indices = True
# How to display URL addresses: 'footnote', 'no', or 'inline'.
#texinfo_show_urls = 'footnote'

25
docs/index.rst Normal file
View File

@ -0,0 +1,25 @@
.. ProjectTox documentation master file, created by
sphinx-quickstart on Wed Jul 31 23:07:35 2013.
You can adapt this file completely to your liking, but it should at least
contain the root `toctree` directive.
Welcome to ProjectTox's documentation!
======================================
Contents:
.. toctree::
start_guide.rst
install.rst
commands.rst
:maxdepth: 2
Indices and tables
==================
* :ref:`genindex`
* :ref:`modindex`
* :ref:`search`

129
docs/install.rst Normal file
View File

@ -0,0 +1,129 @@
Install Instructions
====================
Linux
---------
First, install the build dependencies ::
bash apt-get install build-essential libtool autotools-dev automake libconfig-dev ncurses-dev cmake checkinstall
.. note :: ``libconfig-dev`` should be >= 1.4.
Then you'll need a recent version of `libsodium <https://github.com/jedisct1/libsodium>`_ ::
git clone git://github.com/jedisct1/libsodium.git
cd libsodium
git checkout tags/0.4.2
./autogen.sh
./configure && make check
sudo checkinstall --install --pkgname libsodium --pkgversion 0.4.2 --nodoc
sudo ldconfig``
Finally, fetch the Tox source code and run cmake ::
git clone git://github.com/irungentoo/ProjectTox-Core.git
cd ProjectTox-Core && mkdir build && cd build
cmake ..
Then you can build any of the files in `/testing`_ and `/other`_ that are currently
supported on your platform by running ::
make name_of_c_file
For example, to build `Messenger_test.c`_ you would run ::
make Messenger_test
Or you could just build everything that is supported on your platform by
running ::
bash make
OS X
------
Homebrew
~~~~~~~~~~
::
brew install libtool automake autoconf libconfig libsodium cmake
cmake .
make
sudo make install
Non-homebrew
~~~~~~~~~~~~
Much the same as Linux, remember to install the latest XCode and the
developer tools (Preferences -> Downloads -> Command Line Tools). Users
running Mountain Lion and the latest version of XCode (4.6.3) will also
need to install libtool, automake and autoconf. They are easy enough to
install, grab them from http://www.gnu.org/software/libtool/,
http://www.gnu.org/software/autoconf/ and
http://www.gnu.org/software/automake/, then follow these steps for each:
::
./configure
make
sudo make install
Do not install them from macports (or any dependencies for that matter)
as they get shoved in the wrong directory and make your life more
annoying.
Another thing you may want to install is the latest gcc, this caused me
a few problems as XCode from 4.3 no longer includes gcc and instead uses
LLVM-GCC, a nice install guide can be found at
http://caiustheory.com/install-gcc-421-apple-build-56663-with-xcode-42
Windows
---------
You should install:
* `MinGW <http://sourceforge.net/projects/mingw/>`_'s C compiler
* `CMake <http://www.cmake.org/cmake/resources/software.html>`_
You have to `modify your PATH environment
variable <http://www.computerhope.com/issues/ch000549.htm>`_ so that it
contains MinGW's bin folder path. With default settings, the bin folder
is located at ``C:\MinGW\bin``, which means that you would have to
append ``;C:\MinGW\bin`` to the PATH variable.
Then you should either clone this repo by using git, or just download a
`zip of current Master
branch <https://github.com/irungentoo/ProjectTox-Core/archive/master.zip>`_
and extract it somewhere.
After that you should get precompiled package of libsodium from
`here <https://download.libsodium.org/libsodium/releases/libsodium-win32-0.4.2.tar.gz>`_
and extract the archive into this repo's root. That is, ``sodium``
folder should be along with ``core``, ``testing`` and other folders.
Navigate in ``cmd`` to this repo and run::
mkdir build && cd build
cmake -G "MinGW Makefiles" ..
Then you can build any of the `/testing`_ and `/other`_ that are currently
supported on your platform by running::
mingw32-make name_of_c_file
For example, to build `Messenger_test.c`_ you would run::
mingw32-make Messenger_test``
Or you could just build everything that is supported on your platform by
running::
mingw32-make
.. _/testing: https://github.com/irungentoo/ProjectTox-Core/tree/master/testing
.. _/other: https://github.com/irungentoo/ProjectTox-Core/tree/master/other
.. _Messenger_test.c: https://github.com/irungentoo/ProjectTox-Core/tree/master/other/Messanger_test.c

View File

@ -1,40 +0,0 @@
# Tox nutzen
1. Tox erstellen
2. Fehler korrigieren
3. Im IRC nach Hilfe fragen
4. Auf Debug-Reise für Entwickler
5. Tox wirklich erstellen
6. ???
Trotz der ganzen Arbeit, die wir bisher in Tox
gesteckt haben, gibt es noch keine richtige
Anleitung, wie man Tox _benutzt_.
Dies ist ein anwenderfreundlicher Versuch.
1. Verbinde dich zum Netzwerk!
+ Du musst dich zu einem Bootstrap-Server verbinden, um einen öffentlichen Schlüssel zu erhalten.
+ Wo finde ich einen öffentlichen Server? Zur Zeit hier:
(die Hilfe-Nachricht von nTox ohne Kommandos hilft auch)
+ 198.46.136.167 33445 728925473812C7AAC482BE7250BCCAD0B8CB9F737BF3D42ABD34459C1768F854
+ 192.81.133.111 33445 8CD5A9BF0A6CE358BA36F7A653F99FA6B258FF756E490F52C1F98CC420F78858
+ 66.175.223.88 33445 AC4112C975240CAD260BB2FCD134266521FAAF0A5D159C5FD3201196191E4F5D
+ 192.184.81.118 33445 5CD7EB176C19A2FD840406CD56177BB8E75587BB366F7BB3004B19E3EDC04143
2. Finde einen Freund!
+ Jetzt, da du im Netzwerk bist, brauchst du einen Freund. Um einen zu bekommen,
musst du eine Anfrage senden oder erhalten. Was eine Anfrage ist?
Es ist wie eine Freundschaftsanfrage, jedoch benutzen wir unglaublich schaurige
und kryptische Nummern anstatt Namen. When nTox startet, erscheint _deine_ lange,
schaurige Nummer, auch *öffentlicher Schlüssel* genannt. Diesen kannst du an
andere Personen weitergeben und sie können dich als "Freund" hinzufügen. Oder du
fügst andere Personen mit dem */f*-Befehl hinzu, wenn du möchtest.
3. Chatte drauf los!
+ Benutze nun den */m*-Befehl, um eine Nachricht an jemanden zu senden. Wow, du chattest!
4. Mach etwas kaputt!
+ Jep, pre-alpha-alpha-Software stürzt manchmal ab. Wir arbeiten daran.
+ Bitte melde alle Abstürze entweder an die GitHub-Seite oder #tox-dev im freenode-IRC.
5. Nichts ist kaputt, aber was bedeutet */f*?
+ nTox liest einen Text als Befehl, wenn das erste Zeichen ein Schrägstrich ist ('/').
Du kannst alle Befehle in commands.md nachlesen.
6. Benutze und unterstütze Tox!
+ Programmiere, debugge, dokumentiere, übersetze für uns, oder sprich einfach über uns!
+ Je mehr Interesse wir erhalten, desto mehr Arbeit wird getan und desto besser wird Tox.

66
docs/start_guide.de.rst Normal file
View File

@ -0,0 +1,66 @@
Tox nutzen
==========
1. :doc:`Tox erstellen <install>`
2. Fehler korrigieren
3. Im IRC nach Hilfe fragen
4. Auf Debug-Reise für Entwickler
5. Tox wirklich erstellen
6. ???
Trotz der ganzen Arbeit, die wir bisher in Tox gesteckt haben, gibt es
noch keine richtige Anleitung, wie man Tox *benutzt*. Dies ist ein
anwenderfreundlicher Versuch.
1. Verbinde dich zum Netzwerk!
- Du musst dich zu einem Bootstrap-Server verbinden, um einen
öffentlichen Schlüssel zu erhalten.
- Wo finde ich einen öffentlichen Server? Zur Zeit hier: (die
Hilfe-Nachricht von nTox ohne Kommandos hilft auch)
- 198.46.136.167 33445
728925473812C7AAC482BE7250BCCAD0B8CB9F737BF3D42ABD34459C1768F854
- 192.81.133.111 33445
8CD5A9BF0A6CE358BA36F7A653F99FA6B258FF756E490F52C1F98CC420F78858
- 66.175.223.88 33445
AC4112C975240CAD260BB2FCD134266521FAAF0A5D159C5FD3201196191E4F5D
- 192.184.81.118 33445
5CD7EB176C19A2FD840406CD56177BB8E75587BB366F7BB3004B19E3EDC04143
2. Finde einen Freund!
- Jetzt, da du im Netzwerk bist, brauchst du einen Freund. Um einen
zu bekommen, musst du eine Anfrage senden oder erhalten. Was eine
Anfrage ist? Es ist wie eine Freundschaftsanfrage, jedoch benutzen
wir unglaublich schaurige und kryptische Nummern anstatt Namen.
When nTox startet, erscheint *deine* lange, schaurige Nummer, auch
*öffentlicher Schlüssel* genannt. Diesen kannst du an andere
Personen weitergeben und sie können dich als "Freund" hinzufügen.
Oder du fügst andere Personen mit dem */f*-Befehl hinzu, wenn du
möchtest.
3. Chatte drauf los!
- Benutze nun den */m*-Befehl, um eine Nachricht an jemanden zu
senden. Wow, du chattest!
4. Mach etwas kaputt!
- Jep, pre-alpha-alpha-Software stürzt manchmal ab. Wir arbeiten
daran.
- Bitte melde alle Abstürze entweder an die GitHub-Seite oder
#tox-dev im freenode-IRC.
5. Nichts ist kaputt, aber was bedeutet */f*?
- nTox liest einen Text als Befehl, wenn das erste Zeichen ein
Schrägstrich ist ('/'). Du kannst alle Befehle in commands.md
nachlesen.
6. Benutze und unterstütze Tox!
- Programmiere, debugge, dokumentiere, übersetze für uns, oder
sprich einfach über uns!
- Je mehr Interesse wir erhalten, desto mehr Arbeit wird getan und
desto besser wird Tox.

View File

@ -1,38 +0,0 @@
# Using Tox
1. [Build Tox](../INSTALL.md)
2. Fix errors
3. Consult IRC for help
4. Go on debugging journey for devs
5. Build Tox for real
6. ???
For all the work we've put into Tox so far,
there isn't yet a decent guide for how you _use_
Tox. Here's a user-friendly attempt at it.
1. Connect to the network!
+ You need to connect to a bootstrapping server, to give you a public key.
+ Where can I find a public server? Right here, as of now:
(the help message from running `nTox` with no args will help)
+ `198.46.136.167 33445 728925473812C7AAC482BE7250BCCAD0B8CB9F737BF3D42ABD34459C1768F854`
+ `192.81.133.111 33445 8CD5A9BF0A6CE358BA36F7A653F99FA6B258FF756E490F52C1F98CC420F78858`
+ `66.175.223.88 33445 AC4112C975240CAD260BB2FCD134266521FAAF0A5D159C5FD3201196191E4F5D`
+ `192.184.81.118 33445 5CD7EB176C19A2FD840406CD56177BB8E75587BB366F7BB3004B19E3EDC04143`
2. Find a friend!
+ Now that you're on the network, you need a friend. To get one of those,
you need to to send or receive a request. What's a request, you ask?
It's like a friend request, but we use really scary and cryptic numbers
instead of names. When `nTox` starts, it shows _your_ long, scary number,
called your *public key*. Give that to people, and they can add you as
a "friend". Or, you can add someone else, with the `/f` command, if you like.
3. Chat it up!
+ Now use the `/m` command to send a message to someone. Wow, you're chatting!
4. But something broke!
+ Yeah, pre-alpha-alpha software tends to do that. We're working on it.
+ Please report all crashes to either the GitHub page, or `#tox-dev` on freenode.
5. Nothing broke, but what does `/f` mean?
+ `nTox` parses text as a command if the first character is a forward-slash (`/`).
You can check all commands in commands.md.
6. Use and support Tox!
+ Code for us, debug for us, document for us, translate for us, even just talk about us!
+ The more interest we get, the more work gets done, the better Tox is.

63
docs/start_guide.rst Normal file
View File

@ -0,0 +1,63 @@
Using Tox
=========
.. note:: There is a German version of this page available: :doc:`start_guide.de`
1. :doc:`Build Tox <install>`
2. Fix errors
3. Consult IRC for help
4. Go on debugging journey for devs
5. Build Tox for real
6. ???
For all the work we've put into Tox so far, there isn't yet a decent
guide for how you *use* Tox. Here's a user-friendly attempt at it.
1. Connect to the network!
- You need to connect to a bootstrapping server, to give you a
public key.
- Where can I find a public server? Right here, as of now: (the help
message from running ``nTox`` with no args will help)
- ``198.46.136.167 33445 728925473812C7AAC482BE7250BCCAD0B8CB9F737BF3D42ABD34459C1768F854``
- ``192.81.133.111 33445 8CD5A9BF0A6CE358BA36F7A653F99FA6B258FF756E490F52C1F98CC420F78858``
- ``66.175.223.88 33445 AC4112C975240CAD260BB2FCD134266521FAAF0A5D159C5FD3201196191E4F5D``
- ``192.184.81.118 33445 5CD7EB176C19A2FD840406CD56177BB8E75587BB366F7BB3004B19E3EDC04143``
2. Find a friend!
- Now that you're on the network, you need a friend. To get one of
those, you need to to send or receive a request. What's a request,
you ask? It's like a friend request, but we use really scary and
cryptic numbers instead of names. When ``nTox`` starts, it shows
*your* long, scary number, called your *public key*. Give that to
people, and they can add you as a "friend". Or, you can add
someone else, with the ``/f`` command, if you like.
3. Chat it up!
- Now use the ``/m`` command to send a message to someone. Wow,
you're chatting!
4. But something broke!
- Yeah, pre-alpha-alpha software tends to do that. We're working on
it.
- Please report all crashes to either the GitHub page, or
``#tox-dev`` on freenode.
5. Nothing broke, but what does ``/f`` mean?
- ``nTox`` parses text as a command if the first character is a
forward-slash (``/``). You can check all commands in commands.md.
6. Use and support Tox!
- Code for us, debug for us, document for us, translate for us, even
just talk about us!
- The more interest we get, the more work gets done, the better Tox
is.

View File

@ -89,7 +89,12 @@ char *format_message(char *message, int friendnum)
char* time = asctime(timeinfo);
size_t len = strlen(time);
time[len-1] = '\0';
sprintf(msg, "[%d] %s <%s> %s", friendnum, time, name, message); // timestamp
if (friendnum != -1) {
sprintf(msg, "[%d] %s <%s> %s", friendnum, time, name, message);
} else {
// This message came from ourselves
sprintf(msg, "%s <%s> %s", time, name, message);
}
return msg;
}
@ -106,24 +111,28 @@ void line_eval(char lines[HISTORY][STRING_LENGTH], char *line)
char temp_id[128];
for (i = 0; i < 128; i++)
temp_id[i] = line[i+prompt_offset];
int num = m_addfriend(hex_string_to_bin(temp_id), (uint8_t*)"Install Gentoo", sizeof("Install Gentoo"));
char numstring[100];
switch (num) {
case -1:
sprintf(numstring, "[i] Incorrect key length");
break;
case -2:
sprintf(numstring, "[i] That appears to be your own key");
break;
case -3:
sprintf(numstring, "[i] Friend request already sent");
break;
case -4:
sprintf(numstring, "[i] Could not add friend");
break;
default:
sprintf(numstring, "[i] Added friend %d", num);
break;
case -1:
sprintf(numstring, "[i] Message is too long.");
break;
case -2:
sprintf(numstring, "[i] Please add a message to your request.");
break;
case -3:
sprintf(numstring, "[i] That appears to be your own ID.");
break;
case -4:
sprintf(numstring, "[i] Friend request already sent.");
break;
case -5:
sprintf(numstring, "[i] Undefined error when adding friend.");
break;
default:
sprintf(numstring, "[i] Added friend as %d.", num);
break;
}
new_lines(numstring);
do_refresh();
@ -133,6 +142,9 @@ void line_eval(char lines[HISTORY][STRING_LENGTH], char *line)
}
else if (inpt_command == 'm') { //message command: /m friendnumber messsage
size_t len = strlen(line);
if(len < 3)
return;
char numstring[len-3];
char message[len-3];
int i;
@ -141,13 +153,13 @@ void line_eval(char lines[HISTORY][STRING_LENGTH], char *line)
numstring[i] = line[i+3];
} else {
int j;
for (j = (i+1); j < len; j++)
for (j = (i+1); j < (len+1); j++)
message[j-i-1] = line[j+3];
break;
}
}
int num = atoi(numstring);
if (m_sendmessage(num, (uint8_t*) message, sizeof(message)) != 1) {
if (m_sendmessage(num, (uint8_t*) message, strlen(message) + 1) != 1) {
new_lines("[i] could not send message");
} else {
new_lines(format_message(message, -1));
@ -162,7 +174,7 @@ void line_eval(char lines[HISTORY][STRING_LENGTH], char *line)
name[i-3] = line[i];
}
name[i-3] = 0;
setname(name, i);
setname(name, i - 2);
char numstring[100];
sprintf(numstring, "[i] changed nick to %s", (char*)name);
new_lines(numstring);
@ -179,7 +191,7 @@ void line_eval(char lines[HISTORY][STRING_LENGTH], char *line)
status[i-3] = line[i];
}
status[i-3] = 0;
m_set_userstatus(status, strlen((char*)status));
m_set_userstatus(status, strlen((char*)status) + 1);
char numstring[100];
sprintf(numstring, "[i] changed status to %s", (char*)status);
new_lines(numstring);
@ -313,17 +325,6 @@ void print_request(uint8_t *public_key, uint8_t *data, uint16_t length)
void print_message(int friendnumber, uint8_t * string, uint16_t length)
{
char name[MAX_NAME_LENGTH];
getname(friendnumber, (uint8_t*)name);
char msg[100+length+strlen(name)+1];
time_t rawtime;
struct tm * timeinfo;
time ( &rawtime );
timeinfo = localtime ( &rawtime );
char* temp = asctime(timeinfo);
size_t len = strlen(temp);
temp[len-1] = '\0';
sprintf(msg, "[%d] %s <%s> %s", friendnumber, temp, name, string); // timestamp
new_lines(format_message((char*)string, friendnumber));
}

View File

@ -132,13 +132,15 @@ void line_eval(char* line)
printf(numstring);
}
else if (num == -1)
printf("\nWrong key size\n\n");
printf("\n[i] Message is too long.\n\n");
else if (num == -2)
printf("\nYou can't add yourself\n\n");
printf("\n[i] Please add a message to your friend request.\n\n");
else if (num == -3)
printf("\nYou already have this person added\n\n");
printf("\n[i] That appears to be your own ID.\n\n");
else if (num == -4)
printf("\nUndefined error when adding friend");
printf("\n[i] Friend request already sent.\n\n");
else if (num == -5)
printf("\n[i] Undefined error when adding friend\n\n");
}
else if (inpt_command == 'r') {

View File

@ -280,6 +280,26 @@ void prepare_window(WINDOW* w) {
wresize(w, LINES-2, COLS);
}
/*
* Draws cursor relative to input on prompt window.
* Removes cursor on friends window and chat windows.
*
* TODO: Make it work for chat windows
*/
void position_cursor(WINDOW* w, char* title)
{
curs_set(1);
if (strcmp(title, "[prompt]") == 0) { // main/prompt window
int x, y;
getyx(w, y, x);
move(y, x);
}
else if (strcmp(title, "[friends]") == 0) // friends window
curs_set(0);
else // any other window (i.e chat)
curs_set(0);
}
int main(int argc, char* argv[]) {
int ch;
ToxWindow* a;
@ -299,6 +319,7 @@ int main(int argc, char* argv[]) {
a->blink = false;
a->onDraw(a);
draw_bar();
position_cursor(a->window, a->title);
// Handle input.
ch = getch();

View File

@ -134,10 +134,28 @@ static void execute(ToxWindow* self, char* cmd) {
}
num = m_addfriend(id_bin, (uint8_t*) msg, strlen(msg)+1);
wprintw(self->window, "Friend added as %d.\n", num);
on_friendadded(num);
switch (num) {
case -1:
wprintw(self->window, "Message is too long.\n");
break;
case -2:
wprintw(self->window, "Please add a message to your request.\n");
case -3:
wprintw(self->window, "That appears to be your own ID.\n");
break;
case -4:
wprintw(self->window, "Friend request already sent.\n");
break;
case -5:
wprintw(self->window, "[i] Undefined error when adding friend.\n");
break;
default:
wprintw(self->window, "Friend added as %d.\n", num);
on_friendadded(num);
break;
}
}
else if(!strcmp(cmd, "help")) {
print_usage(self);
}