ffi-tox 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/ProjectTox-Core/CMakeLists.txt +28 -0
- data/ProjectTox-Core/COPYING +674 -0
- data/ProjectTox-Core/INSTALL.md +91 -0
- data/ProjectTox-Core/README.md +54 -0
- data/ProjectTox-Core/core/CMakeLists.txt +17 -0
- data/ProjectTox-Core/core/DHT.c +1104 -0
- data/ProjectTox-Core/core/DHT.h +111 -0
- data/ProjectTox-Core/core/LAN_discovery.c +79 -0
- data/ProjectTox-Core/core/LAN_discovery.h +50 -0
- data/ProjectTox-Core/core/Lossless_UDP.c +749 -0
- data/ProjectTox-Core/core/Lossless_UDP.h +106 -0
- data/ProjectTox-Core/core/Messenger.c +581 -0
- data/ProjectTox-Core/core/Messenger.h +157 -0
- data/ProjectTox-Core/core/friend_requests.c +131 -0
- data/ProjectTox-Core/core/friend_requests.h +51 -0
- data/ProjectTox-Core/core/net_crypto.c +564 -0
- data/ProjectTox-Core/core/net_crypto.h +134 -0
- data/ProjectTox-Core/core/network.c +188 -0
- data/ProjectTox-Core/core/network.h +134 -0
- data/ProjectTox-Core/other/CMakeLists.txt +9 -0
- data/ProjectTox-Core/other/DHT_bootstrap.c +139 -0
- data/ProjectTox-Core/testing/CMakeLists.txt +18 -0
- data/ProjectTox-Core/testing/DHT_cryptosendfiletest.c +228 -0
- data/ProjectTox-Core/testing/DHT_sendfiletest.c +176 -0
- data/ProjectTox-Core/testing/DHT_test.c +182 -0
- data/ProjectTox-Core/testing/Lossless_UDP_testclient.c +214 -0
- data/ProjectTox-Core/testing/Lossless_UDP_testserver.c +201 -0
- data/ProjectTox-Core/testing/Messenger_test.c +145 -0
- data/ProjectTox-Core/testing/misc_tools.c +40 -0
- data/ProjectTox-Core/testing/misc_tools.h +29 -0
- data/ProjectTox-Core/testing/nTox.c +381 -0
- data/ProjectTox-Core/testing/nTox.h +50 -0
- data/ProjectTox-Core/testing/nTox_win32.c +323 -0
- data/ProjectTox-Core/testing/nTox_win32.h +31 -0
- data/ProjectTox-Core/testing/rect.py +45 -0
- data/ext/ffi-tox/extconf.rb +16 -0
- data/interfaces/libtox.i +18 -0
- data/lib/ffi-tox/libtox.rb +37 -0
- data/lib/ffi-tox.rb +1 -0
- metadata +116 -0
@@ -0,0 +1,106 @@
|
|
1
|
+
/* Lossless_UDP.h
|
2
|
+
*
|
3
|
+
* An implementation of the Lossless_UDP protocol as seen in docs/Lossless_UDP.txt
|
4
|
+
*
|
5
|
+
* Copyright (C) 2013 Tox project All Rights Reserved.
|
6
|
+
*
|
7
|
+
* This file is part of Tox.
|
8
|
+
*
|
9
|
+
* Tox is free software: you can redistribute it and/or modify
|
10
|
+
* it under the terms of the GNU General Public License as published by
|
11
|
+
* the Free Software Foundation, either version 3 of the License, or
|
12
|
+
* (at your option) any later version.
|
13
|
+
*
|
14
|
+
* Tox is distributed in the hope that it will be useful,
|
15
|
+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
16
|
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
17
|
+
* GNU General Public License for more details.
|
18
|
+
*
|
19
|
+
* You should have received a copy of the GNU General Public License
|
20
|
+
* along with Tox. If not, see <http://www.gnu.org/licenses/>.
|
21
|
+
*
|
22
|
+
*/
|
23
|
+
|
24
|
+
#ifndef LOSSLESS_UDP_H
|
25
|
+
#define LOSSLESS_UDP_H
|
26
|
+
|
27
|
+
#include "network.h"
|
28
|
+
|
29
|
+
#ifdef __cplusplus
|
30
|
+
extern "C" {
|
31
|
+
#endif
|
32
|
+
|
33
|
+
/* maximum length of the data in the data packets */
|
34
|
+
#define MAX_DATA_SIZE 1024
|
35
|
+
|
36
|
+
/* Functions */
|
37
|
+
|
38
|
+
/* initialize a new connection to ip_port
|
39
|
+
returns an integer corresponding to the connection id.
|
40
|
+
return -1 if it could not initialize the connection.
|
41
|
+
if there already was an existing connection to that ip_port return its number. */
|
42
|
+
int new_connection(IP_Port ip_port);
|
43
|
+
|
44
|
+
/* get connection id from IP_Port
|
45
|
+
return -1 if there are no connections like we are looking for
|
46
|
+
return id if it found it */
|
47
|
+
int getconnection_id(IP_Port ip_port);
|
48
|
+
|
49
|
+
/* returns an integer corresponding to the next connection in our imcoming connection list
|
50
|
+
return -1 if there are no new incoming connections in the list. */
|
51
|
+
int incoming_connection();
|
52
|
+
|
53
|
+
/* return -1 if it could not kill the connection.
|
54
|
+
return 0 if killed successfully */
|
55
|
+
int kill_connection(int connection_id);
|
56
|
+
|
57
|
+
/* kill connection in seconds seconds.
|
58
|
+
return -1 if it can not kill the connection.
|
59
|
+
return 0 if it will kill it */
|
60
|
+
int kill_connection_in(int connection_id, uint32_t seconds);
|
61
|
+
|
62
|
+
/* returns the ip_port of the corresponding connection.
|
63
|
+
return 0 if there is no such connection. */
|
64
|
+
IP_Port connection_ip(int connection_id);
|
65
|
+
|
66
|
+
/* returns the id of the next packet in the queue
|
67
|
+
return -1 if no packet in queue */
|
68
|
+
char id_packet(int connection_id);
|
69
|
+
|
70
|
+
/* return 0 if there is no received data in the buffer.
|
71
|
+
return length of received packet if successful */
|
72
|
+
int read_packet(int connection_id, uint8_t *data);
|
73
|
+
|
74
|
+
/* return 0 if data could not be put in packet queue
|
75
|
+
return 1 if data was put into the queue */
|
76
|
+
int write_packet(int connection_id, uint8_t *data, uint32_t length);
|
77
|
+
|
78
|
+
/* returns the number of packets in the queue waiting to be successfully sent. */
|
79
|
+
uint32_t sendqueue(int connection_id);
|
80
|
+
|
81
|
+
/* returns the number of packets in the queue waiting to be successfully read with read_packet(...) */
|
82
|
+
uint32_t recvqueue(int connection_id);
|
83
|
+
|
84
|
+
/* check if connection is connected
|
85
|
+
return 0 no.
|
86
|
+
return 1 if attempting handshake
|
87
|
+
return 2 if handshake is done
|
88
|
+
return 3 if fully connected
|
89
|
+
return 4 if timed out and wating to be killed */
|
90
|
+
int is_connected(int connection_id);
|
91
|
+
|
92
|
+
/* Call this function a couple times per second
|
93
|
+
It's the main loop. */
|
94
|
+
void doLossless_UDP();
|
95
|
+
|
96
|
+
|
97
|
+
/* if we receive a Lossless_UDP packet we call this function so it can be handled.
|
98
|
+
return 0 if packet is handled correctly.
|
99
|
+
return 1 if it didn't handle the packet or if the packet was shit. */
|
100
|
+
int LosslessUDP_handlepacket(uint8_t *packet, uint32_t length, IP_Port source);
|
101
|
+
|
102
|
+
#ifdef __cplusplus
|
103
|
+
}
|
104
|
+
#endif
|
105
|
+
|
106
|
+
#endif
|
@@ -0,0 +1,581 @@
|
|
1
|
+
/* Messenger.c
|
2
|
+
*
|
3
|
+
* An implementation of a simple text chat only messenger on the tox network core.
|
4
|
+
*
|
5
|
+
* Copyright (C) 2013 Tox project All Rights Reserved.
|
6
|
+
*
|
7
|
+
* This file is part of Tox.
|
8
|
+
*
|
9
|
+
* Tox is free software: you can redistribute it and/or modify
|
10
|
+
* it under the terms of the GNU General Public License as published by
|
11
|
+
* the Free Software Foundation, either version 3 of the License, or
|
12
|
+
* (at your option) any later version.
|
13
|
+
*
|
14
|
+
* Tox is distributed in the hope that it will be useful,
|
15
|
+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
16
|
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
17
|
+
* GNU General Public License for more details.
|
18
|
+
*
|
19
|
+
* You should have received a copy of the GNU General Public License
|
20
|
+
* along with Tox. If not, see <http://www.gnu.org/licenses/>.
|
21
|
+
*
|
22
|
+
*/
|
23
|
+
|
24
|
+
#include "Messenger.h"
|
25
|
+
#define MIN(a,b) (((a)<(b))?(a):(b))
|
26
|
+
|
27
|
+
typedef struct {
|
28
|
+
uint8_t client_id[CLIENT_ID_SIZE];
|
29
|
+
int crypt_connection_id;
|
30
|
+
int friend_request_id; /* id of the friend request corresponding to the current friend request to the current friend. */
|
31
|
+
uint8_t status; /* 0 if no friend, 1 if added, 2 if friend request sent, 3 if confirmed friend, 4 if online. */
|
32
|
+
uint8_t info[MAX_DATA_SIZE]; /* the data that is sent during the friend requests we do */
|
33
|
+
uint8_t name[MAX_NAME_LENGTH];
|
34
|
+
uint8_t name_sent; /* 0 if we didn't send our name to this friend 1 if we have. */
|
35
|
+
uint8_t *userstatus;
|
36
|
+
uint16_t userstatus_length;
|
37
|
+
uint8_t userstatus_sent;
|
38
|
+
uint16_t info_size; /* length of the info */
|
39
|
+
} Friend;
|
40
|
+
|
41
|
+
uint8_t self_public_key[crypto_box_PUBLICKEYBYTES];
|
42
|
+
|
43
|
+
static uint8_t self_name[MAX_NAME_LENGTH];
|
44
|
+
static uint16_t self_name_length;
|
45
|
+
|
46
|
+
static uint8_t *self_userstatus;
|
47
|
+
static uint16_t self_userstatus_len;
|
48
|
+
|
49
|
+
#define MAX_NUM_FRIENDS 256
|
50
|
+
|
51
|
+
static Friend friendlist[MAX_NUM_FRIENDS];
|
52
|
+
|
53
|
+
static uint32_t numfriends;
|
54
|
+
|
55
|
+
/* 1 if we are online
|
56
|
+
0 if we are offline
|
57
|
+
static uint8_t online; */
|
58
|
+
|
59
|
+
/* return the friend id associated to that public key.
|
60
|
+
return -1 if no such friend */
|
61
|
+
int getfriend_id(uint8_t *client_id)
|
62
|
+
{
|
63
|
+
uint32_t i;
|
64
|
+
|
65
|
+
for (i = 0; i < numfriends; ++i) {
|
66
|
+
if (friendlist[i].status > 0)
|
67
|
+
if (memcmp(client_id, friendlist[i].client_id, crypto_box_PUBLICKEYBYTES) == 0)
|
68
|
+
return i;
|
69
|
+
}
|
70
|
+
|
71
|
+
return -1;
|
72
|
+
}
|
73
|
+
|
74
|
+
/* Returns number of friends */
|
75
|
+
int getnumfriends()
|
76
|
+
{
|
77
|
+
return numfriends;
|
78
|
+
}
|
79
|
+
|
80
|
+
/* copies the public key associated to that friend id into client_id buffer.
|
81
|
+
make sure that client_id is of size CLIENT_ID_SIZE.
|
82
|
+
return 0 if success
|
83
|
+
return -1 if failure. */
|
84
|
+
int getclient_id(int friend_id, uint8_t *client_id)
|
85
|
+
{
|
86
|
+
if (friend_id >= numfriends || friend_id < 0)
|
87
|
+
return -1;
|
88
|
+
|
89
|
+
if (friendlist[friend_id].status > 0) {
|
90
|
+
memcpy(client_id, friendlist[friend_id].client_id, CLIENT_ID_SIZE);
|
91
|
+
return 0;
|
92
|
+
}
|
93
|
+
|
94
|
+
return -1;
|
95
|
+
}
|
96
|
+
|
97
|
+
/* add a friend
|
98
|
+
set the data that will be sent along with friend request
|
99
|
+
client_id is the client id of the friend
|
100
|
+
data is the data and length is the length
|
101
|
+
returns the friend number if success
|
102
|
+
return -1 if failure. */
|
103
|
+
int m_addfriend(uint8_t *client_id, uint8_t *data, uint16_t length)
|
104
|
+
{
|
105
|
+
if (length == 0 || length >=
|
106
|
+
(MAX_DATA_SIZE - crypto_box_PUBLICKEYBYTES - crypto_box_NONCEBYTES - crypto_box_BOXZEROBYTES + crypto_box_ZEROBYTES))
|
107
|
+
return -1;
|
108
|
+
if (memcmp(client_id, self_public_key, crypto_box_PUBLICKEYBYTES) == 0)
|
109
|
+
return -1;
|
110
|
+
if (getfriend_id(client_id) != -1)
|
111
|
+
return -1;
|
112
|
+
uint32_t i;
|
113
|
+
for (i = 0; i <= numfriends; ++i) {
|
114
|
+
if(friendlist[i].status == 0) {
|
115
|
+
DHT_addfriend(client_id);
|
116
|
+
friendlist[i].status = 1;
|
117
|
+
friendlist[i].crypt_connection_id = -1;
|
118
|
+
friendlist[i].friend_request_id = -1;
|
119
|
+
memcpy(friendlist[i].client_id, client_id, CLIENT_ID_SIZE);
|
120
|
+
friendlist[i].userstatus = calloc(1, 1);
|
121
|
+
friendlist[i].userstatus_length = 1;
|
122
|
+
memcpy(friendlist[i].info, data, length);
|
123
|
+
friendlist[i].info_size = length;
|
124
|
+
|
125
|
+
++numfriends;
|
126
|
+
return i;
|
127
|
+
}
|
128
|
+
}
|
129
|
+
return -1;
|
130
|
+
}
|
131
|
+
|
132
|
+
int m_addfriend_norequest(uint8_t * client_id)
|
133
|
+
{
|
134
|
+
if (getfriend_id(client_id) != -1)
|
135
|
+
return -1;
|
136
|
+
uint32_t i;
|
137
|
+
for (i = 0; i <= numfriends; ++i) {
|
138
|
+
if(friendlist[i].status == 0) {
|
139
|
+
DHT_addfriend(client_id);
|
140
|
+
friendlist[i].status = 2;
|
141
|
+
friendlist[i].crypt_connection_id = -1;
|
142
|
+
friendlist[i].friend_request_id = -1;
|
143
|
+
memcpy(friendlist[i].client_id, client_id, CLIENT_ID_SIZE);
|
144
|
+
friendlist[i].userstatus = calloc(1, 1);
|
145
|
+
friendlist[i].userstatus_length = 1;
|
146
|
+
numfriends++;
|
147
|
+
return i;
|
148
|
+
}
|
149
|
+
}
|
150
|
+
return -1;
|
151
|
+
}
|
152
|
+
|
153
|
+
/* remove a friend
|
154
|
+
return 0 if success
|
155
|
+
return -1 if failure */
|
156
|
+
int m_delfriend(int friendnumber)
|
157
|
+
{
|
158
|
+
if (friendnumber >= numfriends || friendnumber < 0)
|
159
|
+
return -1;
|
160
|
+
|
161
|
+
DHT_delfriend(friendlist[friendnumber].client_id);
|
162
|
+
crypto_kill(friendlist[friendnumber].crypt_connection_id);
|
163
|
+
free(friendlist[friendnumber].userstatus);
|
164
|
+
memset(&friendlist[friendnumber], 0, sizeof(Friend));
|
165
|
+
uint32_t i;
|
166
|
+
for (i = numfriends; i != 0; --i) {
|
167
|
+
if (friendlist[i].status != 0)
|
168
|
+
break;
|
169
|
+
}
|
170
|
+
numfriends = i;
|
171
|
+
return 0;
|
172
|
+
}
|
173
|
+
|
174
|
+
/* return 4 if friend is online
|
175
|
+
return 3 if friend is confirmed
|
176
|
+
return 2 if the friend request was sent
|
177
|
+
return 1 if the friend was added
|
178
|
+
return 0 if there is no friend with that number */
|
179
|
+
int m_friendstatus(int friendnumber)
|
180
|
+
{
|
181
|
+
if (friendnumber < 0 || friendnumber >= MAX_NUM_FRIENDS)
|
182
|
+
return 0;
|
183
|
+
return friendlist[friendnumber].status;
|
184
|
+
}
|
185
|
+
|
186
|
+
/* send a text chat message to an online friend
|
187
|
+
return 1 if packet was successfully put into the send queue
|
188
|
+
return 0 if it was not */
|
189
|
+
int m_sendmessage(int friendnumber, uint8_t *message, uint32_t length)
|
190
|
+
{
|
191
|
+
if (friendnumber < 0 || friendnumber >= MAX_NUM_FRIENDS)
|
192
|
+
return 0;
|
193
|
+
if (length >= MAX_DATA_SIZE || friendlist[friendnumber].status != 4)
|
194
|
+
/* this does not mean the maximum message length is MAX_DATA_SIZE - 1, it is actually 17 bytes less. */
|
195
|
+
return 0;
|
196
|
+
uint8_t temp[MAX_DATA_SIZE];
|
197
|
+
temp[0] = PACKET_ID_MESSAGE;
|
198
|
+
memcpy(temp + 1, message, length);
|
199
|
+
return write_cryptpacket(friendlist[friendnumber].crypt_connection_id, temp, length + 1);
|
200
|
+
}
|
201
|
+
|
202
|
+
/* send a name packet to friendnumber
|
203
|
+
length is the length with the NULL terminator*/
|
204
|
+
static int m_sendname(int friendnumber, uint8_t * name, uint16_t length)
|
205
|
+
{
|
206
|
+
if(length > MAX_NAME_LENGTH || length == 0)
|
207
|
+
return 0;
|
208
|
+
uint8_t temp[MAX_NAME_LENGTH + 1];
|
209
|
+
memcpy(temp + 1, name, length);
|
210
|
+
temp[0] = PACKET_ID_NICKNAME;
|
211
|
+
return write_cryptpacket(friendlist[friendnumber].crypt_connection_id, temp, length + 1);
|
212
|
+
}
|
213
|
+
|
214
|
+
/* set the name of a friend
|
215
|
+
return 0 if success
|
216
|
+
return -1 if failure */
|
217
|
+
static int setfriendname(int friendnumber, uint8_t * name)
|
218
|
+
{
|
219
|
+
if (friendnumber >= numfriends || friendnumber < 0)
|
220
|
+
return -1;
|
221
|
+
memcpy(friendlist[friendnumber].name, name, MAX_NAME_LENGTH);
|
222
|
+
return 0;
|
223
|
+
}
|
224
|
+
|
225
|
+
/* Set our nickname
|
226
|
+
name must be a string of maximum MAX_NAME_LENGTH length.
|
227
|
+
length must be at least 1 byte
|
228
|
+
length is the length of name with the NULL terminator
|
229
|
+
return 0 if success
|
230
|
+
return -1 if failure */
|
231
|
+
int setname(uint8_t * name, uint16_t length)
|
232
|
+
{
|
233
|
+
if (length > MAX_NAME_LENGTH || length == 0)
|
234
|
+
return -1;
|
235
|
+
memcpy(self_name, name, length);
|
236
|
+
self_name_length = length;
|
237
|
+
uint32_t i;
|
238
|
+
for (i = 0; i < numfriends; ++i)
|
239
|
+
friendlist[i].name_sent = 0;
|
240
|
+
return 0;
|
241
|
+
}
|
242
|
+
|
243
|
+
/* get name of friendnumber
|
244
|
+
put it in name
|
245
|
+
name needs to be a valid memory location with a size of at least MAX_NAME_LENGTH bytes.
|
246
|
+
return 0 if success
|
247
|
+
return -1 if failure */
|
248
|
+
int getname(int friendnumber, uint8_t * name)
|
249
|
+
{
|
250
|
+
if (friendnumber >= numfriends || friendnumber < 0)
|
251
|
+
return -1;
|
252
|
+
memcpy(name, friendlist[friendnumber].name, MAX_NAME_LENGTH);
|
253
|
+
return 0;
|
254
|
+
}
|
255
|
+
|
256
|
+
int m_set_userstatus(uint8_t *status, uint16_t length)
|
257
|
+
{
|
258
|
+
if (length > MAX_USERSTATUS_LENGTH)
|
259
|
+
return -1;
|
260
|
+
uint8_t *newstatus = calloc(length, 1);
|
261
|
+
memcpy(newstatus, status, length);
|
262
|
+
free(self_userstatus);
|
263
|
+
self_userstatus = newstatus;
|
264
|
+
self_userstatus_len = length;
|
265
|
+
|
266
|
+
uint32_t i;
|
267
|
+
for (i = 0; i < numfriends; ++i)
|
268
|
+
friendlist[i].userstatus_sent = 0;
|
269
|
+
return 0;
|
270
|
+
}
|
271
|
+
|
272
|
+
/* return the size of friendnumber's user status
|
273
|
+
guaranteed to be at most MAX_USERSTATUS_LENGTH */
|
274
|
+
int m_get_userstatus_size(int friendnumber)
|
275
|
+
{
|
276
|
+
if (friendnumber >= numfriends || friendnumber < 0)
|
277
|
+
return -1;
|
278
|
+
return friendlist[friendnumber].userstatus_length;
|
279
|
+
}
|
280
|
+
|
281
|
+
/* copy the user status of friendnumber into buf, truncating if needed to maxlen
|
282
|
+
bytes, use m_get_userstatus_size to find out how much you need to allocate */
|
283
|
+
int m_copy_userstatus(int friendnumber, uint8_t * buf, uint32_t maxlen)
|
284
|
+
{
|
285
|
+
if (friendnumber >= numfriends || friendnumber < 0)
|
286
|
+
return -1;
|
287
|
+
memset(buf, 0, maxlen);
|
288
|
+
memcpy(buf, friendlist[friendnumber].userstatus, MIN(maxlen, MAX_USERSTATUS_LENGTH) - 1);
|
289
|
+
return 0;
|
290
|
+
}
|
291
|
+
|
292
|
+
static int send_userstatus(int friendnumber, uint8_t * status, uint16_t length)
|
293
|
+
{
|
294
|
+
uint8_t *thepacket = malloc(length + 1);
|
295
|
+
memcpy(thepacket + 1, status, length);
|
296
|
+
thepacket[0] = PACKET_ID_USERSTATUS;
|
297
|
+
int written = write_cryptpacket(friendlist[friendnumber].crypt_connection_id, thepacket, length + 1);
|
298
|
+
free(thepacket);
|
299
|
+
return written;
|
300
|
+
}
|
301
|
+
|
302
|
+
static int set_friend_userstatus(int friendnumber, uint8_t * status, uint16_t length)
|
303
|
+
{
|
304
|
+
if (friendnumber >= numfriends || friendnumber < 0)
|
305
|
+
return -1;
|
306
|
+
uint8_t *newstatus = calloc(length, 1);
|
307
|
+
memcpy(newstatus, status, length);
|
308
|
+
free(friendlist[friendnumber].userstatus);
|
309
|
+
friendlist[friendnumber].userstatus = newstatus;
|
310
|
+
friendlist[friendnumber].userstatus_length = length;
|
311
|
+
return 0;
|
312
|
+
}
|
313
|
+
|
314
|
+
/* static void (*friend_request)(uint8_t *, uint8_t *, uint16_t);
|
315
|
+
static uint8_t friend_request_isset = 0; */
|
316
|
+
/* set the function that will be executed when a friend request is received. */
|
317
|
+
void m_callback_friendrequest(void (*function)(uint8_t *, uint8_t *, uint16_t))
|
318
|
+
{
|
319
|
+
callback_friendrequest(function);
|
320
|
+
}
|
321
|
+
|
322
|
+
static void (*friend_message)(int, uint8_t *, uint16_t);
|
323
|
+
static uint8_t friend_message_isset = 0;
|
324
|
+
|
325
|
+
/* set the function that will be executed when a message from a friend is received. */
|
326
|
+
void m_callback_friendmessage(void (*function)(int, uint8_t *, uint16_t))
|
327
|
+
{
|
328
|
+
friend_message = function;
|
329
|
+
friend_message_isset = 1;
|
330
|
+
}
|
331
|
+
|
332
|
+
static void (*friend_namechange)(int, uint8_t *, uint16_t);
|
333
|
+
static uint8_t friend_namechange_isset = 0;
|
334
|
+
void m_callback_namechange(void (*function)(int, uint8_t *, uint16_t))
|
335
|
+
{
|
336
|
+
friend_namechange = function;
|
337
|
+
friend_namechange_isset = 1;
|
338
|
+
}
|
339
|
+
|
340
|
+
static void (*friend_statuschange)(int, uint8_t *, uint16_t);
|
341
|
+
static uint8_t friend_statuschange_isset = 0;
|
342
|
+
void m_callback_userstatus(void (*function)(int, uint8_t *, uint16_t))
|
343
|
+
{
|
344
|
+
friend_statuschange = function;
|
345
|
+
friend_statuschange_isset = 1;
|
346
|
+
}
|
347
|
+
|
348
|
+
#define PORT 33445
|
349
|
+
/* run this at startup */
|
350
|
+
int initMessenger()
|
351
|
+
{
|
352
|
+
new_keys();
|
353
|
+
m_set_userstatus((uint8_t*)"Online", sizeof("Online"));
|
354
|
+
initNetCrypto();
|
355
|
+
IP ip;
|
356
|
+
ip.i = 0;
|
357
|
+
|
358
|
+
if(init_networking(ip,PORT) == -1)
|
359
|
+
return -1;
|
360
|
+
|
361
|
+
return 0;
|
362
|
+
}
|
363
|
+
|
364
|
+
//TODO: make this function not suck.
|
365
|
+
static void doFriends()
|
366
|
+
{
|
367
|
+
/* TODO: add incoming connections and some other stuff. */
|
368
|
+
uint32_t i;
|
369
|
+
int len;
|
370
|
+
uint8_t temp[MAX_DATA_SIZE];
|
371
|
+
for (i = 0; i < numfriends; ++i) {
|
372
|
+
if (friendlist[i].status == 1) {
|
373
|
+
int fr = send_friendrequest(friendlist[i].client_id, friendlist[i].info, friendlist[i].info_size);
|
374
|
+
if (fr == 0) /* TODO: This needs to be fixed so that it sends the friend requests a couple of times in case of packet loss */
|
375
|
+
friendlist[i].status = 2;
|
376
|
+
else if (fr > 0)
|
377
|
+
friendlist[i].status = 2;
|
378
|
+
}
|
379
|
+
if (friendlist[i].status == 2 || friendlist[i].status == 3) { /* friend is not online */
|
380
|
+
if (friendlist[i].status == 2) {
|
381
|
+
if (friendlist[i].friend_request_id + 10 < unix_time()) { /*I know this is hackish but it should work.*/
|
382
|
+
send_friendrequest(friendlist[i].client_id, friendlist[i].info, friendlist[i].info_size);
|
383
|
+
friendlist[i].friend_request_id = unix_time();
|
384
|
+
}
|
385
|
+
}
|
386
|
+
IP_Port friendip = DHT_getfriendip(friendlist[i].client_id);
|
387
|
+
switch (is_cryptoconnected(friendlist[i].crypt_connection_id)) {
|
388
|
+
case 0:
|
389
|
+
if (friendip.ip.i > 1)
|
390
|
+
friendlist[i].crypt_connection_id = crypto_connect(friendlist[i].client_id, friendip);
|
391
|
+
break;
|
392
|
+
case 3: /* Connection is established */
|
393
|
+
friendlist[i].status = 4;
|
394
|
+
break;
|
395
|
+
case 4:
|
396
|
+
crypto_kill(friendlist[i].crypt_connection_id);
|
397
|
+
friendlist[i].crypt_connection_id = -1;
|
398
|
+
break;
|
399
|
+
default:
|
400
|
+
break;
|
401
|
+
}
|
402
|
+
}
|
403
|
+
while (friendlist[i].status == 4) { /* friend is online */
|
404
|
+
if (friendlist[i].name_sent == 0) {
|
405
|
+
if (m_sendname(i, self_name, self_name_length))
|
406
|
+
friendlist[i].name_sent = 1;
|
407
|
+
}
|
408
|
+
if (friendlist[i].userstatus_sent == 0) {
|
409
|
+
if (send_userstatus(i, self_userstatus, self_userstatus_len))
|
410
|
+
friendlist[i].userstatus_sent = 1;
|
411
|
+
}
|
412
|
+
len = read_cryptpacket(friendlist[i].crypt_connection_id, temp);
|
413
|
+
if (len > 0) {
|
414
|
+
switch (temp[0]) {
|
415
|
+
case PACKET_ID_NICKNAME: {
|
416
|
+
if (len >= MAX_NAME_LENGTH + 1 || len == 1)
|
417
|
+
break;
|
418
|
+
if(friend_namechange_isset)
|
419
|
+
friend_namechange(i, temp + 1, len - 1);
|
420
|
+
memcpy(friendlist[i].name, temp + 1, len - 1);
|
421
|
+
friendlist[i].name[len - 2] = 0; /* make sure the NULL terminator is present. */
|
422
|
+
break;
|
423
|
+
}
|
424
|
+
case PACKET_ID_USERSTATUS: {
|
425
|
+
uint8_t *status = calloc(MIN(len - 1, MAX_USERSTATUS_LENGTH), 1);
|
426
|
+
memcpy(status, temp + 1, MIN(len - 1, MAX_USERSTATUS_LENGTH));
|
427
|
+
if (friend_statuschange_isset)
|
428
|
+
friend_statuschange(i, status, MIN(len - 1, MAX_USERSTATUS_LENGTH));
|
429
|
+
set_friend_userstatus(i, status, MIN(len - 1, MAX_USERSTATUS_LENGTH));
|
430
|
+
free(status);
|
431
|
+
break;
|
432
|
+
}
|
433
|
+
case PACKET_ID_MESSAGE: {
|
434
|
+
if (friend_message_isset)
|
435
|
+
(*friend_message)(i, temp + 1, len - 1);
|
436
|
+
break;
|
437
|
+
}
|
438
|
+
}
|
439
|
+
} else {
|
440
|
+
if (is_cryptoconnected(friendlist[i].crypt_connection_id) == 4) { /* if the connection timed out, kill it */
|
441
|
+
crypto_kill(friendlist[i].crypt_connection_id);
|
442
|
+
friendlist[i].crypt_connection_id = -1;
|
443
|
+
friendlist[i].status = 3;
|
444
|
+
}
|
445
|
+
break;
|
446
|
+
}
|
447
|
+
}
|
448
|
+
}
|
449
|
+
}
|
450
|
+
|
451
|
+
static void doInbound()
|
452
|
+
{
|
453
|
+
uint8_t secret_nonce[crypto_box_NONCEBYTES];
|
454
|
+
uint8_t public_key[crypto_box_PUBLICKEYBYTES];
|
455
|
+
uint8_t session_key[crypto_box_PUBLICKEYBYTES];
|
456
|
+
int inconnection = crypto_inbound(public_key, secret_nonce, session_key);
|
457
|
+
if (inconnection != -1) {
|
458
|
+
int friend_id = getfriend_id(public_key);
|
459
|
+
if (friend_id != -1) {
|
460
|
+
crypto_kill(friendlist[friend_id].crypt_connection_id);
|
461
|
+
friendlist[friend_id].crypt_connection_id =
|
462
|
+
accept_crypto_inbound(inconnection, public_key, secret_nonce, session_key);
|
463
|
+
|
464
|
+
friendlist[friend_id].status = 3;
|
465
|
+
}
|
466
|
+
}
|
467
|
+
}
|
468
|
+
|
469
|
+
/*Interval in seconds between LAN discovery packet sending*/
|
470
|
+
#define LAN_DISCOVERY_INTERVAL 60
|
471
|
+
|
472
|
+
static uint32_t last_LANdiscovery;
|
473
|
+
|
474
|
+
/*Send a LAN discovery packet every LAN_DISCOVERY_INTERVAL seconds*/
|
475
|
+
static void LANdiscovery()
|
476
|
+
{
|
477
|
+
if (last_LANdiscovery + LAN_DISCOVERY_INTERVAL < unix_time()) {
|
478
|
+
send_LANdiscovery(htons(PORT));
|
479
|
+
last_LANdiscovery = unix_time();
|
480
|
+
}
|
481
|
+
}
|
482
|
+
|
483
|
+
|
484
|
+
/* the main loop that needs to be run at least 200 times per second. */
|
485
|
+
void doMessenger()
|
486
|
+
{
|
487
|
+
IP_Port ip_port;
|
488
|
+
uint8_t data[MAX_UDP_PACKET_SIZE];
|
489
|
+
uint32_t length;
|
490
|
+
while (receivepacket(&ip_port, data, &length) != -1) {
|
491
|
+
#ifdef DEBUG
|
492
|
+
/* if(rand() % 3 != 1) //simulate packet loss */
|
493
|
+
/* { */
|
494
|
+
if (DHT_handlepacket(data, length, ip_port) && LosslessUDP_handlepacket(data, length, ip_port) &&
|
495
|
+
friendreq_handlepacket(data, length, ip_port) && LANdiscovery_handlepacket(data, length, ip_port))
|
496
|
+
/* if packet is discarded */
|
497
|
+
printf("Received unhandled packet with length: %u\n", length);
|
498
|
+
else
|
499
|
+
printf("Received handled packet with length: %u\n", length);
|
500
|
+
/* } */
|
501
|
+
printf("Status: %u %u %u\n",friendlist[0].status ,is_cryptoconnected(friendlist[0].crypt_connection_id), friendlist[0].crypt_connection_id);
|
502
|
+
#else
|
503
|
+
DHT_handlepacket(data, length, ip_port);
|
504
|
+
LosslessUDP_handlepacket(data, length, ip_port);
|
505
|
+
friendreq_handlepacket(data, length, ip_port);
|
506
|
+
LANdiscovery_handlepacket(data, length, ip_port);
|
507
|
+
#endif
|
508
|
+
|
509
|
+
}
|
510
|
+
doDHT();
|
511
|
+
doLossless_UDP();
|
512
|
+
doNetCrypto();
|
513
|
+
doInbound();
|
514
|
+
doFriends();
|
515
|
+
LANdiscovery();
|
516
|
+
}
|
517
|
+
|
518
|
+
/* returns the size of the messenger data (for saving) */
|
519
|
+
uint32_t Messenger_size()
|
520
|
+
{
|
521
|
+
return crypto_box_PUBLICKEYBYTES + crypto_box_SECRETKEYBYTES
|
522
|
+
+ sizeof(uint32_t) + DHT_size() + sizeof(uint32_t) + sizeof(Friend) * numfriends;
|
523
|
+
}
|
524
|
+
|
525
|
+
/* save the messenger in data of size Messenger_size() */
|
526
|
+
void Messenger_save(uint8_t *data)
|
527
|
+
{
|
528
|
+
save_keys(data);
|
529
|
+
data += crypto_box_PUBLICKEYBYTES + crypto_box_SECRETKEYBYTES;
|
530
|
+
uint32_t size = DHT_size();
|
531
|
+
memcpy(data, &size, sizeof(size));
|
532
|
+
data += sizeof(size);
|
533
|
+
DHT_save(data);
|
534
|
+
data += size;
|
535
|
+
size = sizeof(Friend) * numfriends;
|
536
|
+
memcpy(data, &size, sizeof(size));
|
537
|
+
data += sizeof(size);
|
538
|
+
memcpy(data, friendlist, sizeof(Friend) * numfriends);
|
539
|
+
}
|
540
|
+
|
541
|
+
/* load the messenger from data of size length. */
|
542
|
+
int Messenger_load(uint8_t * data, uint32_t length)
|
543
|
+
{
|
544
|
+
if (length == ~0)
|
545
|
+
return -1;
|
546
|
+
if (length < crypto_box_PUBLICKEYBYTES + crypto_box_SECRETKEYBYTES + sizeof(uint32_t) * 2)
|
547
|
+
return -1;
|
548
|
+
length -= crypto_box_PUBLICKEYBYTES + crypto_box_SECRETKEYBYTES + sizeof(uint32_t) * 2;
|
549
|
+
load_keys(data);
|
550
|
+
data += crypto_box_PUBLICKEYBYTES + crypto_box_SECRETKEYBYTES;
|
551
|
+
uint32_t size;
|
552
|
+
memcpy(&size, data, sizeof(size));
|
553
|
+
data += sizeof(size);
|
554
|
+
|
555
|
+
if (length < size)
|
556
|
+
return -1;
|
557
|
+
length -= size;
|
558
|
+
if (DHT_load(data, size) == -1)
|
559
|
+
return -1;
|
560
|
+
data += size;
|
561
|
+
memcpy(&size, data, sizeof(size));
|
562
|
+
data += sizeof(size);
|
563
|
+
if (length != size || length % sizeof(Friend) != 0)
|
564
|
+
return -1;
|
565
|
+
|
566
|
+
Friend * temp = malloc(size);
|
567
|
+
memcpy(temp, data, size);
|
568
|
+
|
569
|
+
uint16_t num = size / sizeof(Friend);
|
570
|
+
|
571
|
+
uint32_t i;
|
572
|
+
for (i = 0; i < num; ++i) {
|
573
|
+
if(temp[i].status != 0) {
|
574
|
+
int fnum = m_addfriend_norequest(temp[i].client_id);
|
575
|
+
setfriendname(fnum, temp[i].name);
|
576
|
+
/* set_friend_userstatus(fnum, temp[i].userstatus, temp[i].userstatus_length); */
|
577
|
+
}
|
578
|
+
}
|
579
|
+
free(temp);
|
580
|
+
return 0;
|
581
|
+
}
|