summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--auto_tests/CMakeLists.txt4
-rw-r--r--auto_tests/cmake/crypto_test.cmake10
-rw-r--r--auto_tests/crypto_test.c230
-rwxr-xr-xauto_tests/run_tests2
-rw-r--r--core/DHT.c35
-rw-r--r--core/DHT.h8
-rw-r--r--core/LAN_discovery.c10
-rw-r--r--core/LAN_discovery.h6
-rw-r--r--core/Lossless_UDP.c26
-rw-r--r--core/Lossless_UDP.h6
-rw-r--r--core/Messenger.c38
-rw-r--r--core/friend_requests.c7
-rw-r--r--core/friend_requests.h6
-rw-r--r--core/net_crypto.c106
-rw-r--r--core/net_crypto.h16
-rw-r--r--core/network.c24
-rw-r--r--core/network.h14
-rw-r--r--core/ping.c4
-rw-r--r--core/ping.h4
-rw-r--r--other/CMakeLists.txt2
-rw-r--r--other/DHT_bootstrap.c12
-rw-r--r--other/bootstrap_serverdaemon/DHT_bootstrap_daemon.c20
-rw-r--r--testing/CMakeLists.txt1
-rw-r--r--testing/DHT_test.c11
-rw-r--r--testing/Lossless_UDP_testclient.c12
-rw-r--r--testing/Lossless_UDP_testserver.c23
-rw-r--r--testing/cmake/crypto_speed_test.cmake9
-rw-r--r--testing/crypto_speed_test.c130
-rw-r--r--testing/toxic/prompt.c48
29 files changed, 644 insertions, 180 deletions
diff --git a/auto_tests/CMakeLists.txt b/auto_tests/CMakeLists.txt
index fbbcb7d7..c0b6aee4 100644
--- a/auto_tests/CMakeLists.txt
+++ b/auto_tests/CMakeLists.txt
@@ -5,16 +5,18 @@ include_directories(${CHECK_INCLUDE_DIRS})
5 5
6find_package(Check REQUIRED) 6find_package(Check REQUIRED)
7include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/messenger_test.cmake) 7include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/messenger_test.cmake)
8include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/crypto_test.cmake)
8include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/friends_test.cmake) 9include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/friends_test.cmake)
9 10
10include( CTest ) 11include( CTest )
11enable_testing() 12enable_testing()
12 13
13add_test(messenger messenger_test) 14add_test(messenger messenger_test)
15add_test(crypto crypto_test)
14# TODO enable once test is fixed 16# TODO enable once test is fixed
15#add_test(friends friends_test) 17#add_test(friends friends_test)
16 18
17add_custom_target( 19add_custom_target(
18 test COMMAND ${CMAKE_CTEST_COMMAND} -V 20 test COMMAND ${CMAKE_CTEST_COMMAND} -V
19 DEPENDS messenger_test 21 DEPENDS messenger_test crypto_test
20) 22)
diff --git a/auto_tests/cmake/crypto_test.cmake b/auto_tests/cmake/crypto_test.cmake
new file mode 100644
index 00000000..9ca9a331
--- /dev/null
+++ b/auto_tests/cmake/crypto_test.cmake
@@ -0,0 +1,10 @@
1cmake_minimum_required(VERSION 2.6.0)
2project(crypto_test C)
3set(exe_name crypto_test)
4
5add_executable(${exe_name}
6 crypto_test.c)
7
8linkCoreLibraries(${exe_name})
9add_dependencies(${exe_name} Check)
10target_link_libraries(${exe_name} check)
diff --git a/auto_tests/crypto_test.c b/auto_tests/crypto_test.c
new file mode 100644
index 00000000..9ac81349
--- /dev/null
+++ b/auto_tests/crypto_test.c
@@ -0,0 +1,230 @@
1#include "../core/net_crypto.h"
2#include <sys/types.h>
3#include <stdint.h>
4#include <string.h>
5#include <check.h>
6#include <stdlib.h>
7#include <time.h>
8#include <sodium.h>
9
10void rand_bytes(uint8_t *b, size_t blen)
11{
12 size_t i;
13 for (i = 0; i < blen; i++)
14 {
15 b[i] = rand();
16 }
17}
18
19// These test vectors are from libsodium's test suite
20
21unsigned char alicesk[32] = {
22 0x77,0x07,0x6d,0x0a,0x73,0x18,0xa5,0x7d,
23 0x3c,0x16,0xc1,0x72,0x51,0xb2,0x66,0x45,
24 0xdf,0x4c,0x2f,0x87,0xeb,0xc0,0x99,0x2a,
25 0xb1,0x77,0xfb,0xa5,0x1d,0xb9,0x2c,0x2a
26};
27
28unsigned char bobpk[32] = {
29 0xde,0x9e,0xdb,0x7d,0x7b,0x7d,0xc1,0xb4,
30 0xd3,0x5b,0x61,0xc2,0xec,0xe4,0x35,0x37,
31 0x3f,0x83,0x43,0xc8,0x5b,0x78,0x67,0x4d,
32 0xad,0xfc,0x7e,0x14,0x6f,0x88,0x2b,0x4f
33};
34
35unsigned char nonce[24] = {
36 0x69,0x69,0x6e,0xe9,0x55,0xb6,0x2b,0x73,
37 0xcd,0x62,0xbd,0xa8,0x75,0xfc,0x73,0xd6,
38 0x82,0x19,0xe0,0x03,0x6b,0x7a,0x0b,0x37
39};
40
41unsigned char test_m[131] = {
42 0xbe,0x07,0x5f,0xc5,0x3c,0x81,0xf2,0xd5,
43 0xcf,0x14,0x13,0x16,0xeb,0xeb,0x0c,0x7b,
44 0x52,0x28,0xc5,0x2a,0x4c,0x62,0xcb,0xd4,
45 0x4b,0x66,0x84,0x9b,0x64,0x24,0x4f,0xfc,
46 0xe5,0xec,0xba,0xaf,0x33,0xbd,0x75,0x1a,
47 0x1a,0xc7,0x28,0xd4,0x5e,0x6c,0x61,0x29,
48 0x6c,0xdc,0x3c,0x01,0x23,0x35,0x61,0xf4,
49 0x1d,0xb6,0x6c,0xce,0x31,0x4a,0xdb,0x31,
50 0x0e,0x3b,0xe8,0x25,0x0c,0x46,0xf0,0x6d,
51 0xce,0xea,0x3a,0x7f,0xa1,0x34,0x80,0x57,
52 0xe2,0xf6,0x55,0x6a,0xd6,0xb1,0x31,0x8a,
53 0x02,0x4a,0x83,0x8f,0x21,0xaf,0x1f,0xde,
54 0x04,0x89,0x77,0xeb,0x48,0xf5,0x9f,0xfd,
55 0x49,0x24,0xca,0x1c,0x60,0x90,0x2e,0x52,
56 0xf0,0xa0,0x89,0xbc,0x76,0x89,0x70,0x40,
57 0xe0,0x82,0xf9,0x37,0x76,0x38,0x48,0x64,
58 0x5e,0x07,0x05
59};
60
61unsigned char test_c[147] = {
62 0xf3,0xff,0xc7,0x70,0x3f,0x94,0x00,0xe5,
63 0x2a,0x7d,0xfb,0x4b,0x3d,0x33,0x05,0xd9,
64 0x8e,0x99,0x3b,0x9f,0x48,0x68,0x12,0x73,
65 0xc2,0x96,0x50,0xba,0x32,0xfc,0x76,0xce,
66 0x48,0x33,0x2e,0xa7,0x16,0x4d,0x96,0xa4,
67 0x47,0x6f,0xb8,0xc5,0x31,0xa1,0x18,0x6a,
68 0xc0,0xdf,0xc1,0x7c,0x98,0xdc,0xe8,0x7b,
69 0x4d,0xa7,0xf0,0x11,0xec,0x48,0xc9,0x72,
70 0x71,0xd2,0xc2,0x0f,0x9b,0x92,0x8f,0xe2,
71 0x27,0x0d,0x6f,0xb8,0x63,0xd5,0x17,0x38,
72 0xb4,0x8e,0xee,0xe3,0x14,0xa7,0xcc,0x8a,
73 0xb9,0x32,0x16,0x45,0x48,0xe5,0x26,0xae,
74 0x90,0x22,0x43,0x68,0x51,0x7a,0xcf,0xea,
75 0xbd,0x6b,0xb3,0x73,0x2b,0xc0,0xe9,0xda,
76 0x99,0x83,0x2b,0x61,0xca,0x01,0xb6,0xde,
77 0x56,0x24,0x4a,0x9e,0x88,0xd5,0xf9,0xb3,
78 0x79,0x73,0xf6,0x22,0xa4,0x3d,0x14,0xa6,
79 0x59,0x9b,0x1f,0x65,0x4c,0xb4,0x5a,0x74,
80 0xe3,0x55,0xa5
81};
82
83START_TEST(test_known)
84{
85 unsigned char c[147];
86 unsigned char m[131];
87 int clen, mlen;
88
89 ck_assert_msg(sizeof(c) == sizeof(m) + ENCRYPTION_PADDING * sizeof(unsigned char), "cyphertext should be ENCRYPTION_PADDING bytes longer than plaintext");
90 ck_assert_msg(sizeof(test_c) == sizeof(c), "sanity check failed");
91 ck_assert_msg(sizeof(test_m) == sizeof(m), "sanity check failed");
92
93 clen = encrypt_data(bobpk, alicesk, nonce, test_m, sizeof(test_m)/sizeof(unsigned char), c);
94
95 ck_assert_msg(memcmp(test_c, c, sizeof(c)) == 0, "cyphertext doesn't match test vector");
96 ck_assert_msg(clen == sizeof(c)/sizeof(unsigned char), "wrong ciphertext length");
97
98 mlen = decrypt_data(bobpk, alicesk, nonce, test_c, sizeof(test_c)/sizeof(unsigned char), m);
99
100 ck_assert_msg(memcmp(test_m, m, sizeof(m)) == 0, "decrypted text doesn't match test vector");
101 ck_assert_msg(mlen == sizeof(m)/sizeof(unsigned char), "wrong plaintext length");
102}
103END_TEST
104
105START_TEST(test_fast_known)
106{
107 unsigned char k[crypto_box_BEFORENMBYTES];
108 unsigned char c[147];
109 unsigned char m[131];
110 int clen, mlen;
111
112 encrypt_precompute(bobpk, alicesk, k);
113
114 ck_assert_msg(sizeof(c) == sizeof(m) + ENCRYPTION_PADDING * sizeof(unsigned char), "cyphertext should be ENCRYPTION_PADDING bytes longer than plaintext");
115 ck_assert_msg(sizeof(test_c) == sizeof(c), "sanity check failed");
116 ck_assert_msg(sizeof(test_m) == sizeof(m), "sanity check failed");
117
118 clen = encrypt_data_fast(k, nonce, test_m, sizeof(test_m)/sizeof(unsigned char), c);
119
120 ck_assert_msg(memcmp(test_c, c, sizeof(c)) == 0, "cyphertext doesn't match test vector");
121 ck_assert_msg(clen == sizeof(c)/sizeof(unsigned char), "wrong ciphertext length");
122
123 mlen = decrypt_data_fast(k, nonce, test_c, sizeof(test_c)/sizeof(unsigned char), m);
124
125 ck_assert_msg(memcmp(test_m, m, sizeof(m)) == 0, "decrypted text doesn't match test vector");
126 ck_assert_msg(mlen == sizeof(m)/sizeof(unsigned char), "wrong plaintext length");
127
128}
129END_TEST
130
131START_TEST(test_endtoend)
132{
133 unsigned char pk1[crypto_box_PUBLICKEYBYTES];
134 unsigned char sk1[crypto_box_SECRETKEYBYTES];
135 unsigned char pk2[crypto_box_PUBLICKEYBYTES];
136 unsigned char sk2[crypto_box_SECRETKEYBYTES];
137 unsigned char k1[crypto_box_BEFORENMBYTES];
138 unsigned char k2[crypto_box_BEFORENMBYTES];
139
140 unsigned char n[crypto_box_NONCEBYTES];
141
142 unsigned char m[500];
143 unsigned char c1[sizeof(m) + ENCRYPTION_PADDING];
144 unsigned char c2[sizeof(m) + ENCRYPTION_PADDING];
145 unsigned char c3[sizeof(m) + ENCRYPTION_PADDING];
146 unsigned char c4[sizeof(m) + ENCRYPTION_PADDING];
147 unsigned char m1[sizeof(m)];
148 unsigned char m2[sizeof(m)];
149 unsigned char m3[sizeof(m)];
150 unsigned char m4[sizeof(m)];
151
152 int mlen;
153 int c1len, c2len, c3len, c4len;
154 int m1len, m2len, m3len, m4len;
155
156 int testno;
157
158 // Test 100 random messages and keypairs
159 for (testno = 0; testno < 100; testno++)
160 {
161 //Generate random message (random length from 100 to 500)
162 mlen = (rand() % 400) + 100;
163 rand_bytes(m, mlen);
164 rand_bytes(n, crypto_box_NONCEBYTES);
165
166 //Generate keypairs
167 crypto_box_keypair(pk1,sk1);
168 crypto_box_keypair(pk2,sk2);
169
170 //Precompute shared keys
171 encrypt_precompute(pk2, sk1, k1);
172 encrypt_precompute(pk1, sk2, k2);
173
174 ck_assert_msg(memcmp(k1, k2, crypto_box_BEFORENMBYTES) == 0, "encrypt_precompute: bad");
175
176 //Encrypt all four ways
177 c1len = encrypt_data(pk2, sk1, n, m, mlen, c1);
178 c2len = encrypt_data(pk1, sk2, n, m, mlen, c2);
179 c3len = encrypt_data_fast(k1, n, m, mlen, c3);
180 c4len = encrypt_data_fast(k2, n, m, mlen, c4);
181
182 ck_assert_msg(c1len == c2len && c1len == c3len && c1len == c4len, "cyphertext lengths differ");
183 ck_assert_msg(c1len == mlen + ENCRYPTION_PADDING, "wrong cyphertext length");
184 ck_assert_msg(memcmp(c1, c2, c1len) == 0 && memcmp(c1, c3, c1len) == 0 && memcmp(c1, c4, c1len) == 0, "crypertexts differ");
185
186 //Decrypt all four ways
187 m1len = decrypt_data(pk2, sk1, n, c1, c1len, m1);
188 m2len = decrypt_data(pk1, sk2, n, c1, c1len, m2);
189 m3len = decrypt_data_fast(k1, n, c1, c1len, m3);
190 m4len = decrypt_data_fast(k2, n, c1, c1len, m4);
191
192 ck_assert_msg(m1len == m2len && m1len == m3len && m1len == m4len, "decrypted text lengths differ");
193 ck_assert_msg(m1len == mlen, "wrong decrypted text length");
194 ck_assert_msg(memcmp(m1, m2, mlen) == 0 && memcmp(m1, m3, mlen) == 0 && memcmp(m1, m4, mlen) == 0, "decrypted texts differ");
195 ck_assert_msg(memcmp(m1, m, mlen) == 0, "wrong decrypted text");
196 }
197}
198END_TEST
199
200#define DEFTESTCASE(NAME) \
201 TCase *NAME = tcase_create(#NAME); \
202 tcase_add_test(NAME, test_##NAME); \
203 suite_add_tcase(s, NAME);
204
205Suite* crypto_suite(void)
206{
207 Suite *s = suite_create("Crypto");
208
209 DEFTESTCASE(known);
210 DEFTESTCASE(fast_known);
211 DEFTESTCASE(endtoend);
212
213 return s;
214}
215
216int main(int argc, char* argv[])
217{
218 srand((unsigned int) time(NULL));
219
220 Suite *crypto = crypto_suite();
221 SRunner *test_runner = srunner_create(crypto);
222 int number_failed = 0;
223
224 srunner_run_all(test_runner, CK_NORMAL);
225 number_failed = srunner_ntests_failed(test_runner);
226
227 srunner_free(test_runner);
228
229 return number_failed;
230}
diff --git a/auto_tests/run_tests b/auto_tests/run_tests
index 4448b2e2..1899f354 100755
--- a/auto_tests/run_tests
+++ b/auto_tests/run_tests
@@ -2,4 +2,4 @@
2# run_tests - run the current tests for tox core 2# run_tests - run the current tests for tox core
3set -e 3set -e
4 4
5./messenger_test && ./friends_test 5./messenger_test && ./friends_test && ./crypto_test
diff --git a/core/DHT.c b/core/DHT.c
index 7e3af9d2..d359076d 100644
--- a/core/DHT.c
+++ b/core/DHT.c
@@ -554,7 +554,7 @@ static int sendnodes(IP_Port ip_port, uint8_t * public_key, uint8_t * client_id,
554 return sendpacket(ip_port, data, 1 + CLIENT_ID_SIZE + crypto_box_NONCEBYTES + len); 554 return sendpacket(ip_port, data, 1 + CLIENT_ID_SIZE + crypto_box_NONCEBYTES + len);
555} 555}
556 556
557static int handle_getnodes(uint8_t * packet, uint32_t length, IP_Port source) 557static int handle_getnodes(IP_Port source, uint8_t * packet, uint32_t length)
558{ 558{
559 uint64_t ping_id; 559 uint64_t ping_id;
560 560
@@ -586,7 +586,7 @@ static int handle_getnodes(uint8_t * packet, uint32_t length, IP_Port source)
586 return 0; 586 return 0;
587} 587}
588 588
589static int handle_sendnodes(uint8_t * packet, uint32_t length, IP_Port source) 589static int handle_sendnodes(IP_Port source, uint8_t * packet, uint32_t length)
590{ 590{
591 uint64_t ping_id; 591 uint64_t ping_id;
592 uint32_t cid_size = 1 + CLIENT_ID_SIZE; 592 uint32_t cid_size = 1 + CLIENT_ID_SIZE;
@@ -930,7 +930,7 @@ static int send_NATping(uint8_t * public_key, uint64_t ping_id, uint8_t type)
930} 930}
931 931
932/* Handle a received ping request for */ 932/* Handle a received ping request for */
933static int handle_NATping(uint8_t * packet, uint32_t length, IP_Port source) 933static int handle_NATping(IP_Port source, uint8_t * packet, uint32_t length)
934{ 934{
935 if (length < crypto_box_PUBLICKEYBYTES * 2 + crypto_box_NONCEBYTES + ENCRYPTION_PADDING 935 if (length < crypto_box_PUBLICKEYBYTES * 2 + crypto_box_NONCEBYTES + ENCRYPTION_PADDING
936 || length > MAX_DATA_SIZE + ENCRYPTION_PADDING) 936 || length > MAX_DATA_SIZE + ENCRYPTION_PADDING)
@@ -1074,30 +1074,13 @@ static void doNAT(void)
1074/*----------------------------------------------------------------------------------*/ 1074/*----------------------------------------------------------------------------------*/
1075/*-----------------------END OF NAT PUNCHING FUNCTIONS------------------------------*/ 1075/*-----------------------END OF NAT PUNCHING FUNCTIONS------------------------------*/
1076 1076
1077int DHT_handlepacket(uint8_t * packet, uint32_t length, IP_Port source) 1077void DHT_init(void)
1078{ 1078{
1079 switch (packet[0]) { 1079 networking_registerhandler(0, &handle_ping_request);
1080 case 0: 1080 networking_registerhandler(1, &handle_ping_response);
1081 return handle_ping_request(packet, length, source); 1081 networking_registerhandler(2, &handle_getnodes);
1082 1082 networking_registerhandler(3, &handle_sendnodes);
1083 case 1: 1083 networking_registerhandler(254, &handle_NATping);
1084 return handle_ping_response(packet, length, source);
1085
1086 case 2:
1087 return handle_getnodes(packet, length, source);
1088
1089 case 3:
1090 return handle_sendnodes(packet, length, source);
1091
1092 case 254:
1093 return handle_NATping(packet, length, source);
1094
1095 default:
1096 return 1;
1097
1098 }
1099
1100 return 0;
1101} 1084}
1102 1085
1103void doDHT(void) 1086void doDHT(void)
diff --git a/core/DHT.h b/core/DHT.h
index cb5697ea..0e05f132 100644
--- a/core/DHT.h
+++ b/core/DHT.h
@@ -58,11 +58,6 @@ IP_Port DHT_getfriendip(uint8_t *client_id);
58/* Run this function at least a couple times per second (It's the main loop) */ 58/* Run this function at least a couple times per second (It's the main loop) */
59void doDHT(void); 59void doDHT(void);
60 60
61/* if we receive a DHT packet we call this function so it can be handled.
62 return 0 if packet is handled correctly.
63 return 1 if it didn't handle the packet or if the packet was shit. */
64int DHT_handlepacket(uint8_t *packet, uint32_t length, IP_Port source);
65
66/* Use this function to bootstrap the client 61/* Use this function to bootstrap the client
67 Sends a get nodes request to the given node with ip port and public_key */ 62 Sends a get nodes request to the given node with ip port and public_key */
68void DHT_bootstrap(IP_Port ip_port, uint8_t *public_key); 63void DHT_bootstrap(IP_Port ip_port, uint8_t *public_key);
@@ -93,6 +88,9 @@ uint32_t DHT_size(void);
93/* save the DHT in data where data is an array of size DHT_size() */ 88/* save the DHT in data where data is an array of size DHT_size() */
94void DHT_save(uint8_t *data); 89void DHT_save(uint8_t *data);
95 90
91/* init DHT */
92void DHT_init(void);
93
96/* load the DHT from data of size size; 94/* load the DHT from data of size size;
97 return -1 if failure 95 return -1 if failure
98 return 0 if success */ 96 return 0 if success */
diff --git a/core/LAN_discovery.c b/core/LAN_discovery.c
index 26b3930c..67dc656b 100644
--- a/core/LAN_discovery.c
+++ b/core/LAN_discovery.c
@@ -111,7 +111,7 @@ static int LAN_ip(IP ip)
111 return -1; 111 return -1;
112} 112}
113 113
114static int handle_LANdiscovery(uint8_t *packet, uint32_t length, IP_Port source) 114static int handle_LANdiscovery(IP_Port source, uint8_t *packet, uint32_t length)
115{ 115{
116 if (LAN_ip(source.ip) == -1) 116 if (LAN_ip(source.ip) == -1)
117 return 1; 117 return 1;
@@ -125,16 +125,14 @@ static int handle_LANdiscovery(uint8_t *packet, uint32_t length, IP_Port source)
125int send_LANdiscovery(uint16_t port) 125int send_LANdiscovery(uint16_t port)
126{ 126{
127 uint8_t data[crypto_box_PUBLICKEYBYTES + 1]; 127 uint8_t data[crypto_box_PUBLICKEYBYTES + 1];
128 data[0] = 32; 128 data[0] = 33;
129 memcpy(data + 1, self_public_key, crypto_box_PUBLICKEYBYTES); 129 memcpy(data + 1, self_public_key, crypto_box_PUBLICKEYBYTES);
130 IP_Port ip_port = {broadcast_ip(), port}; 130 IP_Port ip_port = {broadcast_ip(), port};
131 return sendpacket(ip_port, data, 1 + crypto_box_PUBLICKEYBYTES); 131 return sendpacket(ip_port, data, 1 + crypto_box_PUBLICKEYBYTES);
132} 132}
133 133
134 134
135int LANdiscovery_handlepacket(uint8_t *packet, uint32_t length, IP_Port source) 135void LANdiscovery_init(void)
136{ 136{
137 if (packet[0] == 32) 137 networking_registerhandler(33, &handle_LANdiscovery);
138 return handle_LANdiscovery(packet, length, source);
139 return 1;
140} 138}
diff --git a/core/LAN_discovery.h b/core/LAN_discovery.h
index 96a6e6ad..6b5b8c75 100644
--- a/core/LAN_discovery.h
+++ b/core/LAN_discovery.h
@@ -43,10 +43,8 @@ extern "C" {
43int send_LANdiscovery(uint16_t port); 43int send_LANdiscovery(uint16_t port);
44 44
45 45
46/* if we receive a packet we call this function so it can be handled. 46/* sets up packet handlers */
47 return 0 if packet is handled correctly. 47void LANdiscovery_init(void);
48 return 1 if it didn't handle the packet or if the packet was shit. */
49int LANdiscovery_handlepacket(uint8_t *packet, uint32_t length, IP_Port source);
50 48
51 49
52 50
diff --git a/core/Lossless_UDP.c b/core/Lossless_UDP.c
index 3a289735..002e2cf8 100644
--- a/core/Lossless_UDP.c
+++ b/core/Lossless_UDP.c
@@ -555,7 +555,7 @@ static int send_DATA(uint32_t connection_id)
555 555
556 556
557/* Return 0 if handled correctly, 1 if packet is bad. */ 557/* Return 0 if handled correctly, 1 if packet is bad. */
558static int handle_handshake(uint8_t * packet, uint32_t length, IP_Port source) 558static int handle_handshake(IP_Port source, uint8_t * packet, uint32_t length)
559{ 559{
560 if (length != (1 + 4 + 4)) 560 if (length != (1 + 4 + 4))
561 return 1; 561 return 1;
@@ -669,7 +669,7 @@ static int handle_SYNC3(int connection_id, uint8_t counter, uint32_t recv_packet
669 return 1; 669 return 1;
670} 670}
671 671
672static int handle_SYNC(uint8_t *packet, uint32_t length, IP_Port source) 672static int handle_SYNC(IP_Port source, uint8_t *packet, uint32_t length)
673{ 673{
674 674
675 if (!SYNC_valid(length)) 675 if (!SYNC_valid(length))
@@ -742,7 +742,7 @@ static int add_recv(int connection_id, uint32_t data_num, uint8_t *data, uint16_
742 return 0; 742 return 0;
743} 743}
744 744
745static int handle_data(uint8_t *packet, uint32_t length, IP_Port source) 745static int handle_data(IP_Port source, uint8_t *packet, uint32_t length)
746{ 746{
747 int connection = getconnection_id(source); 747 int connection = getconnection_id(source);
748 748
@@ -770,23 +770,11 @@ static int handle_data(uint8_t *packet, uint32_t length, IP_Port source)
770 * END of packet handling functions 770 * END of packet handling functions
771 */ 771 */
772 772
773int LosslessUDP_handlepacket(uint8_t *packet, uint32_t length, IP_Port source) 773void LosslessUDP_init(void)
774{ 774{
775 switch (packet[0]) { 775 networking_registerhandler(16, &handle_handshake);
776 case 16: 776 networking_registerhandler(17, &handle_SYNC);
777 return handle_handshake(packet, length, source); 777 networking_registerhandler(18, &handle_data);
778
779 case 17:
780 return handle_SYNC(packet, length, source);
781
782 case 18:
783 return handle_data(packet, length, source);
784
785 default:
786 return 1;
787 }
788
789 return 0;
790} 778}
791 779
792/* 780/*
diff --git a/core/Lossless_UDP.h b/core/Lossless_UDP.h
index b4cb186a..53afe606 100644
--- a/core/Lossless_UDP.h
+++ b/core/Lossless_UDP.h
@@ -113,11 +113,9 @@ int is_connected(int connection_id);
113void doLossless_UDP(void); 113void doLossless_UDP(void);
114 114
115/* 115/*
116 * If we receive a Lossless_UDP packet, call this function so it can be handled. 116 * This function sets up LosslessUDP packet handling.
117 * Return 0 if packet is handled correctly.
118 * Return 1 if it didn't handle the packet or if the packet was shit.
119 */ 117 */
120int LosslessUDP_handlepacket(uint8_t *packet, uint32_t length, IP_Port source); 118void LosslessUDP_init(void);
121 119
122#ifdef __cplusplus 120#ifdef __cplusplus
123} 121}
diff --git a/core/Messenger.c b/core/Messenger.c
index dd651107..d26bba56 100644
--- a/core/Messenger.c
+++ b/core/Messenger.c
@@ -138,7 +138,7 @@ int m_addfriend(uint8_t *client_id, uint8_t *data, uint16_t length)
138 for (i = 0; i <= numfriends; ++i) { 138 for (i = 0; i <= numfriends; ++i) {
139 if (friendlist[i].status == NOFRIEND) { 139 if (friendlist[i].status == NOFRIEND) {
140 DHT_addfriend(client_id); 140 DHT_addfriend(client_id);
141 set_friend_status(i, FRIEND_ADDED); 141 friendlist[i].status = FRIEND_ADDED;
142 friendlist[i].crypt_connection_id = -1; 142 friendlist[i].crypt_connection_id = -1;
143 friendlist[i].friend_request_id = -1; 143 friendlist[i].friend_request_id = -1;
144 memcpy(friendlist[i].client_id, client_id, CLIENT_ID_SIZE); 144 memcpy(friendlist[i].client_id, client_id, CLIENT_ID_SIZE);
@@ -231,7 +231,11 @@ uint32_t m_sendmessage(int friendnumber, uint8_t *message, uint32_t length)
231 uint32_t msgid = ++friendlist[friendnumber].message_id; 231 uint32_t msgid = ++friendlist[friendnumber].message_id;
232 if (msgid == 0) 232 if (msgid == 0)
233 msgid = 1; /* otherwise, false error */ 233 msgid = 1; /* otherwise, false error */
234 return m_sendmessage_withid(friendnumber, msgid, message, length); 234 if(m_sendmessage_withid(friendnumber, msgid, message, length)) {
235 return msgid;
236 }
237
238 return 0;
235} 239}
236 240
237uint32_t m_sendmessage_withid(int friendnumber, uint32_t theid, uint8_t *message, uint32_t length) 241uint32_t m_sendmessage_withid(int friendnumber, uint32_t theid, uint8_t *message, uint32_t length)
@@ -518,6 +522,11 @@ int initMessenger(void)
518 if(init_networking(ip,PORT) == -1) 522 if(init_networking(ip,PORT) == -1)
519 return -1; 523 return -1;
520 524
525 DHT_init();
526 LosslessUDP_init();
527 friendreq_init();
528 LANdiscovery_init();
529
521 return 0; 530 return 0;
522} 531}
523 532
@@ -684,29 +693,8 @@ static void LANdiscovery(void)
684/* the main loop that needs to be run at least 200 times per second. */ 693/* the main loop that needs to be run at least 200 times per second. */
685void doMessenger(void) 694void doMessenger(void)
686{ 695{
687 IP_Port ip_port; 696 networking_poll();
688 uint8_t data[MAX_UDP_PACKET_SIZE]; 697
689 uint32_t length;
690 while (receivepacket(&ip_port, data, &length) != -1) {
691#ifdef DEBUG
692 /* if(rand() % 3 != 1) //simulate packet loss */
693 /* { */
694 if (DHT_handlepacket(data, length, ip_port) && LosslessUDP_handlepacket(data, length, ip_port) &&
695 friendreq_handlepacket(data, length, ip_port) && LANdiscovery_handlepacket(data, length, ip_port))
696 /* if packet is discarded */
697 printf("Received unhandled packet with length: %u\n", length);
698 else
699 printf("Received handled packet with length: %u\n", length);
700 /* } */
701 printf("Status: %u %u %u\n",friendlist[0].status ,is_cryptoconnected(friendlist[0].crypt_connection_id), friendlist[0].crypt_connection_id);
702#else
703 DHT_handlepacket(data, length, ip_port);
704 LosslessUDP_handlepacket(data, length, ip_port);
705 friendreq_handlepacket(data, length, ip_port);
706 LANdiscovery_handlepacket(data, length, ip_port);
707#endif
708
709 }
710 doDHT(); 698 doDHT();
711 doLossless_UDP(); 699 doLossless_UDP();
712 doNetCrypto(); 700 doNetCrypto();
diff --git a/core/friend_requests.c b/core/friend_requests.c
index b8dab87e..422cc028 100644
--- a/core/friend_requests.c
+++ b/core/friend_requests.c
@@ -101,7 +101,7 @@ static int request_received(uint8_t * client_id)
101} 101}
102 102
103 103
104int friendreq_handlepacket(uint8_t * packet, uint32_t length, IP_Port source) 104static int friendreq_handlepacket(IP_Port source, uint8_t * packet, uint32_t length)
105{ 105{
106 if (packet[0] == 32) { 106 if (packet[0] == 32) {
107 if (length <= crypto_box_PUBLICKEYBYTES * 2 + crypto_box_NONCEBYTES + 1 + ENCRYPTION_PADDING || 107 if (length <= crypto_box_PUBLICKEYBYTES * 2 + crypto_box_NONCEBYTES + 1 + ENCRYPTION_PADDING ||
@@ -129,3 +129,8 @@ int friendreq_handlepacket(uint8_t * packet, uint32_t length, IP_Port source)
129 } 129 }
130 return 1; 130 return 1;
131} 131}
132
133void friendreq_init(void)
134{
135 networking_registerhandler(32, &friendreq_handlepacket);
136}
diff --git a/core/friend_requests.h b/core/friend_requests.h
index 4dfc5130..708d8f66 100644
--- a/core/friend_requests.h
+++ b/core/friend_requests.h
@@ -39,10 +39,8 @@ int send_friendrequest(uint8_t *public_key, uint8_t *data, uint32_t length);
39 function format is function(uint8_t * public_key, uint8_t * data, uint16_t length) */ 39 function format is function(uint8_t * public_key, uint8_t * data, uint16_t length) */
40void callback_friendrequest(void (*function)(uint8_t *, uint8_t *, uint16_t)); 40void callback_friendrequest(void (*function)(uint8_t *, uint8_t *, uint16_t));
41 41
42/* if we receive a packet we call this function so it can be handled. 42/* sets up friendreq packet handlers */
43 return 0 if packet is handled correctly. 43void friendreq_init(void);
44 return 1 if it didn't handle the packet or if the packet was shit. */
45int friendreq_handlepacket(uint8_t *packet, uint32_t length, IP_Port source);
46 44
47#ifdef __cplusplus 45#ifdef __cplusplus
48} 46}
diff --git a/core/net_crypto.c b/core/net_crypto.c
index 1c56b95a..07c43c40 100644
--- a/core/net_crypto.c
+++ b/core/net_crypto.c
@@ -37,6 +37,7 @@ typedef struct {
37 uint8_t sessionpublic_key[crypto_box_PUBLICKEYBYTES]; /* our public key for this session. */ 37 uint8_t sessionpublic_key[crypto_box_PUBLICKEYBYTES]; /* our public key for this session. */
38 uint8_t sessionsecret_key[crypto_box_SECRETKEYBYTES]; /* our private key for this session. */ 38 uint8_t sessionsecret_key[crypto_box_SECRETKEYBYTES]; /* our private key for this session. */
39 uint8_t peersessionpublic_key[crypto_box_PUBLICKEYBYTES]; /* The public key of the peer. */ 39 uint8_t peersessionpublic_key[crypto_box_PUBLICKEYBYTES]; /* The public key of the peer. */
40 uint8_t shared_key[crypto_box_BEFORENMBYTES]; /* the precomputed shared key from encrypt_precompute */
40 uint8_t status; /* 0 if no connection, 1 we have sent a handshake, 2 if connexion is not confirmed yet 41 uint8_t status; /* 0 if no connection, 1 we have sent a handshake, 2 if connexion is not confirmed yet
41 (we have received a handshake but no empty data packet), 3 if the connection is established. 42 (we have received a handshake but no empty data packet), 3 if the connection is established.
42 4 if the connection is timed out. */ 43 4 if the connection is timed out. */
@@ -59,6 +60,17 @@ static Crypto_Connection crypto_connections[MAX_CRYPTO_CONNECTIONS];
59/* keeps track of the connection numbers for friends request so we can check later if they were sent */ 60/* keeps track of the connection numbers for friends request so we can check later if they were sent */
60static int incoming_connections[MAX_INCOMING]; 61static int incoming_connections[MAX_INCOMING];
61 62
63/* Use this instead of memcmp; not vulnerable to timing attacks. */
64uint8_t crypto_iszero(uint8_t *mem, uint32_t length)
65{
66 uint8_t check = 0;
67 uint32_t i;
68 for (i = 0; i < length; ++i) {
69 check |= mem[i];
70 }
71 return check; // We return zero if mem is made out of zeroes.
72}
73
62/* encrypts plain of length length to encrypted of length + 16 using the 74/* encrypts plain of length length to encrypted of length + 16 using the
63 public key(32 bytes) of the receiver and the secret key of the sender and a 24 byte nonce 75 public key(32 bytes) of the receiver and the secret key of the sender and a 24 byte nonce
64 return -1 if there was a problem. 76 return -1 if there was a problem.
@@ -78,12 +90,38 @@ int encrypt_data(uint8_t *public_key, uint8_t *secret_key, uint8_t *nonce,
78 90
79 /* if encryption is successful the first crypto_box_BOXZEROBYTES of the message will be zero 91 /* if encryption is successful the first crypto_box_BOXZEROBYTES of the message will be zero
80 apparently memcmp should not be used so we do this instead:*/ 92 apparently memcmp should not be used so we do this instead:*/
81 uint32_t i; 93 if(crypto_iszero(temp_encrypted, crypto_box_BOXZEROBYTES) != 0)
82 uint32_t check = 0; 94 return -1;
83 for(i = 0; i < crypto_box_BOXZEROBYTES; ++i) { 95
84 check |= temp_encrypted[i] ^ 0; 96 /* unpad the encrypted message */
85 } 97 memcpy(encrypted, temp_encrypted + crypto_box_BOXZEROBYTES, length + crypto_box_MACBYTES);
86 if(check != 0) 98 return length - crypto_box_BOXZEROBYTES + crypto_box_ZEROBYTES;
99}
100
101/* Precomputes the shared key from their public_key and our secret_key.
102 This way we can avoid an expensive elliptic curve scalar multiply for each
103 encrypt/decrypt operation.
104 enc_key has to be crypto_box_BEFORENMBYTES bytes long. */
105void encrypt_precompute(uint8_t *public_key, uint8_t *secret_key, uint8_t *enc_key)
106{
107 crypto_box_beforenm(enc_key, public_key, secret_key);
108}
109
110/* Fast encrypt. Depends on enc_key from encrypt_precompute. */
111int encrypt_data_fast(uint8_t *enc_key, uint8_t *nonce,
112 uint8_t *plain, uint32_t length, uint8_t *encrypted)
113{
114 if (length + crypto_box_MACBYTES > MAX_DATA_SIZE || length == 0)
115 return -1;
116
117 uint8_t temp_plain[MAX_DATA_SIZE + crypto_box_BOXZEROBYTES] = {0};
118 uint8_t temp_encrypted[MAX_DATA_SIZE + crypto_box_BOXZEROBYTES];
119
120 memcpy(temp_plain + crypto_box_ZEROBYTES, plain, length); /* pad the message with 32 0 bytes. */
121
122 crypto_box_afternm(temp_encrypted, temp_plain, length + crypto_box_ZEROBYTES, nonce, enc_key);
123
124 if(crypto_iszero(temp_encrypted, crypto_box_BOXZEROBYTES) != 0)
87 return -1; 125 return -1;
88 126
89 /* unpad the encrypted message */ 127 /* unpad the encrypted message */
@@ -112,12 +150,33 @@ int decrypt_data(uint8_t *public_key, uint8_t *secret_key, uint8_t *nonce,
112 150
113 /* if decryption is successful the first crypto_box_ZEROBYTES of the message will be zero 151 /* if decryption is successful the first crypto_box_ZEROBYTES of the message will be zero
114 apparently memcmp should not be used so we do this instead:*/ 152 apparently memcmp should not be used so we do this instead:*/
115 uint32_t i; 153 if(crypto_iszero(temp_plain, crypto_box_ZEROBYTES) != 0)
116 uint32_t check = 0; 154 return -1;
117 for(i = 0; i < crypto_box_ZEROBYTES; ++i) { 155
118 check |= temp_plain[i] ^ 0; 156 /* unpad the plain message */
119 } 157 memcpy(plain, temp_plain + crypto_box_ZEROBYTES, length - crypto_box_MACBYTES);
120 if(check != 0) 158 return length - crypto_box_ZEROBYTES + crypto_box_BOXZEROBYTES;
159}
160
161/* Fast decrypt. Depends on enc_ley from encrypt_precompute. */
162int decrypt_data_fast(uint8_t *enc_key, uint8_t *nonce,
163 uint8_t *encrypted, uint32_t length, uint8_t *plain)
164{
165 if (length > MAX_DATA_SIZE || length <= crypto_box_BOXZEROBYTES)
166 return -1;
167
168 uint8_t temp_plain[MAX_DATA_SIZE + crypto_box_BOXZEROBYTES];
169 uint8_t temp_encrypted[MAX_DATA_SIZE + crypto_box_BOXZEROBYTES] = {0};
170
171 memcpy(temp_encrypted + crypto_box_BOXZEROBYTES, encrypted, length); /* pad the message with 16 0 bytes. */
172
173 if (crypto_box_open_afternm(temp_plain, temp_encrypted, length + crypto_box_BOXZEROBYTES,
174 nonce, enc_key) == -1)
175 return -1;
176
177 /* if decryption is successful the first crypto_box_ZEROBYTES of the message will be zero
178 apparently memcmp should not be used so we do this instead:*/
179 if(crypto_iszero(temp_plain, crypto_box_ZEROBYTES) != 0)
121 return -1; 180 return -1;
122 181
123 /* unpad the plain message */ 182 /* unpad the plain message */
@@ -161,9 +220,9 @@ int read_cryptpacket(int crypt_connection_id, uint8_t *data)
161 return 0; 220 return 0;
162 if (temp_data[0] != 3) 221 if (temp_data[0] != 3)
163 return -1; 222 return -1;
164 int len = decrypt_data(crypto_connections[crypt_connection_id].peersessionpublic_key, 223 int len = decrypt_data_fast(crypto_connections[crypt_connection_id].shared_key,
165 crypto_connections[crypt_connection_id].sessionsecret_key, 224 crypto_connections[crypt_connection_id].recv_nonce,
166 crypto_connections[crypt_connection_id].recv_nonce, temp_data + 1, length - 1, data); 225 temp_data + 1, length - 1, data);
167 if (len != -1) { 226 if (len != -1) {
168 increment_nonce(crypto_connections[crypt_connection_id].recv_nonce); 227 increment_nonce(crypto_connections[crypt_connection_id].recv_nonce);
169 return len; 228 return len;
@@ -182,9 +241,9 @@ int write_cryptpacket(int crypt_connection_id, uint8_t *data, uint32_t length)
182 if (crypto_connections[crypt_connection_id].status != CONN_ESTABLISHED) 241 if (crypto_connections[crypt_connection_id].status != CONN_ESTABLISHED)
183 return 0; 242 return 0;
184 uint8_t temp_data[MAX_DATA_SIZE]; 243 uint8_t temp_data[MAX_DATA_SIZE];
185 int len = encrypt_data(crypto_connections[crypt_connection_id].peersessionpublic_key, 244 int len = encrypt_data_fast(crypto_connections[crypt_connection_id].shared_key,
186 crypto_connections[crypt_connection_id].sessionsecret_key, 245 crypto_connections[crypt_connection_id].sent_nonce,
187 crypto_connections[crypt_connection_id].sent_nonce, data, length, temp_data + 1); 246 data, length, temp_data + 1);
188 if (len == -1) 247 if (len == -1)
189 return 0; 248 return 0;
190 temp_data[0] = 3; 249 temp_data[0] = 3;
@@ -417,6 +476,9 @@ int accept_crypto_inbound(int connection_id, uint8_t *public_key, uint8_t *secre
417 crypto_connections[i].sessionpublic_key) == 1) { 476 crypto_connections[i].sessionpublic_key) == 1) {
418 increment_nonce(crypto_connections[i].recv_nonce); 477 increment_nonce(crypto_connections[i].recv_nonce);
419 uint32_t zero = 0; 478 uint32_t zero = 0;
479 encrypt_precompute(crypto_connections[i].peersessionpublic_key,
480 crypto_connections[i].sessionsecret_key,
481 crypto_connections[i].shared_key);
420 crypto_connections[i].status = CONN_ESTABLISHED; /* connection status needs to be 3 for write_cryptpacket() to work */ 482 crypto_connections[i].status = CONN_ESTABLISHED; /* connection status needs to be 3 for write_cryptpacket() to work */
421 write_cryptpacket(i, ((uint8_t *)&zero), sizeof(zero)); 483 write_cryptpacket(i, ((uint8_t *)&zero), sizeof(zero));
422 crypto_connections[i].status = CONN_NOT_CONFIRMED; /* set it to its proper value right after. */ 484 crypto_connections[i].status = CONN_NOT_CONFIRMED; /* set it to its proper value right after. */
@@ -511,6 +573,9 @@ static void receive_crypto(void)
511 memcpy(crypto_connections[i].peersessionpublic_key, session_key, crypto_box_PUBLICKEYBYTES); 573 memcpy(crypto_connections[i].peersessionpublic_key, session_key, crypto_box_PUBLICKEYBYTES);
512 increment_nonce(crypto_connections[i].sent_nonce); 574 increment_nonce(crypto_connections[i].sent_nonce);
513 uint32_t zero = 0; 575 uint32_t zero = 0;
576 encrypt_precompute(crypto_connections[i].peersessionpublic_key,
577 crypto_connections[i].sessionsecret_key,
578 crypto_connections[i].shared_key);
514 crypto_connections[i].status = CONN_ESTABLISHED; /* connection status needs to be 3 for write_cryptpacket() to work */ 579 crypto_connections[i].status = CONN_ESTABLISHED; /* connection status needs to be 3 for write_cryptpacket() to work */
515 write_cryptpacket(i, ((uint8_t *)&zero), sizeof(zero)); 580 write_cryptpacket(i, ((uint8_t *)&zero), sizeof(zero));
516 crypto_connections[i].status = CONN_NOT_CONFIRMED; /* set it to its proper value right after. */ 581 crypto_connections[i].status = CONN_NOT_CONFIRMED; /* set it to its proper value right after. */
@@ -521,7 +586,7 @@ static void receive_crypto(void)
521 586
522 } 587 }
523 if (crypto_connections[i].status == CONN_NOT_CONFIRMED) { 588 if (crypto_connections[i].status == CONN_NOT_CONFIRMED) {
524 if (id_packet(crypto_connections[i].number) == CONN_ESTABLISHED) { 589 if (id_packet(crypto_connections[i].number) == 3) {
525 uint8_t temp_data[MAX_DATA_SIZE]; 590 uint8_t temp_data[MAX_DATA_SIZE];
526 uint8_t data[MAX_DATA_SIZE]; 591 uint8_t data[MAX_DATA_SIZE];
527 int length = read_packet(crypto_connections[i].number, temp_data); 592 int length = read_packet(crypto_connections[i].number, temp_data);
@@ -531,6 +596,9 @@ static void receive_crypto(void)
531 uint32_t zero = 0; 596 uint32_t zero = 0;
532 if (len == sizeof(uint32_t) && memcmp(((uint8_t *)&zero), data, sizeof(uint32_t)) == 0) { 597 if (len == sizeof(uint32_t) && memcmp(((uint8_t *)&zero), data, sizeof(uint32_t)) == 0) {
533 increment_nonce(crypto_connections[i].recv_nonce); 598 increment_nonce(crypto_connections[i].recv_nonce);
599 encrypt_precompute(crypto_connections[i].peersessionpublic_key,
600 crypto_connections[i].sessionsecret_key,
601 crypto_connections[i].shared_key);
534 crypto_connections[i].status = CONN_ESTABLISHED; 602 crypto_connections[i].status = CONN_ESTABLISHED;
535 603
536 /* connection is accepted so we disable the auto kill by setting it to about 1 month from now. */ 604 /* connection is accepted so we disable the auto kill by setting it to about 1 month from now. */
diff --git a/core/net_crypto.h b/core/net_crypto.h
index 66634d45..135e099d 100644
--- a/core/net_crypto.h
+++ b/core/net_crypto.h
@@ -36,6 +36,9 @@ extern uint8_t self_secret_key[crypto_box_SECRETKEYBYTES];
36 36
37#define ENCRYPTION_PADDING (crypto_box_ZEROBYTES - crypto_box_BOXZEROBYTES) 37#define ENCRYPTION_PADDING (crypto_box_ZEROBYTES - crypto_box_BOXZEROBYTES)
38 38
39/* returns zero if the buffer contains only zeros */
40uint8_t crypto_iszero(uint8_t* buffer, uint32_t blen);
41
39/* encrypts plain of length length to encrypted of length + 16 using the 42/* encrypts plain of length length to encrypted of length + 16 using the
40 public key(32 bytes) of the receiver and the secret key of the sender and a 24 byte nonce 43 public key(32 bytes) of the receiver and the secret key of the sender and a 24 byte nonce
41 return -1 if there was a problem. 44 return -1 if there was a problem.
@@ -51,6 +54,19 @@ int encrypt_data(uint8_t *public_key, uint8_t *secret_key, uint8_t *nonce,
51int decrypt_data(uint8_t *public_key, uint8_t *secret_key, uint8_t *nonce, 54int decrypt_data(uint8_t *public_key, uint8_t *secret_key, uint8_t *nonce,
52 uint8_t *encrypted, uint32_t length, uint8_t *plain); 55 uint8_t *encrypted, uint32_t length, uint8_t *plain);
53 56
57/* Fast encrypt/decrypt operations. Use if this is not a one-time communication.
58 encrypt_precompute does the shared-key generation once so it does not have
59 to be preformed on every encrypt/decrypt. */
60void encrypt_precompute(uint8_t *public_key, uint8_t *secret_key, uint8_t *enc_key);
61
62/* Fast encrypt. Depends on enc_key from encrypt_precompute. */
63int encrypt_data_fast(uint8_t *enc_key, uint8_t *nonce,
64 uint8_t *plain, uint32_t length, uint8_t *encrypted);
65
66/* Fast decrypt. Depends on enc_ley from encrypt_precompute. */
67int decrypt_data_fast(uint8_t *enc_key, uint8_t *nonce,
68 uint8_t *encrypted, uint32_t length, uint8_t *plain);
69
54 70
55/* fill the given nonce with random bytes. */ 71/* fill the given nonce with random bytes. */
56void random_nonce(uint8_t *nonce); 72void random_nonce(uint8_t *nonce);
diff --git a/core/network.c b/core/network.c
index 8c6fa7b6..7e3b344a 100644
--- a/core/network.c
+++ b/core/network.c
@@ -71,7 +71,7 @@ int sendpacket(IP_Port ip_port, uint8_t * data, uint32_t length)
71 the packet data into data 71 the packet data into data
72 the packet length into length. 72 the packet length into length.
73 dump all empty packets. */ 73 dump all empty packets. */
74int receivepacket(IP_Port * ip_port, uint8_t * data, uint32_t * length) 74static int receivepacket(IP_Port * ip_port, uint8_t * data, uint32_t * length)
75{ 75{
76 ADDR addr; 76 ADDR addr;
77#ifdef WIN32 77#ifdef WIN32
@@ -88,6 +88,27 @@ int receivepacket(IP_Port * ip_port, uint8_t * data, uint32_t * length)
88 return 0; 88 return 0;
89} 89}
90 90
91static packet_handler_callback packethandlers[256] = {0};
92
93void networking_registerhandler(uint8_t byte, packet_handler_callback cb)
94{
95 packethandlers[byte] = cb;
96}
97
98void networking_poll()
99{
100 IP_Port ip_port;
101 uint8_t data[MAX_UDP_PACKET_SIZE];
102 uint32_t length;
103
104 while (receivepacket(&ip_port, data, &length) != -1)
105 {
106 if (length < 1) continue;
107 if (!packethandlers[data[0]]) continue;
108 packethandlers[data[0]](ip_port, data, length);
109 }
110}
111
91/* initialize networking 112/* initialize networking
92 bind to ip and port 113 bind to ip and port
93 ip must be in network order EX: 127.0.0.1 = (7F000001) 114 ip must be in network order EX: 127.0.0.1 = (7F000001)
@@ -149,7 +170,6 @@ int init_networking(IP ip, uint16_t port)
149 bind(sock, (struct sockaddr*)&addr, sizeof(addr)); 170 bind(sock, (struct sockaddr*)&addr, sizeof(addr));
150 171
151 return 0; 172 return 0;
152
153} 173}
154 174
155/* function to cleanup networking stuff */ 175/* function to cleanup networking stuff */
diff --git a/core/network.h b/core/network.h
index d3c39333..7c95d84d 100644
--- a/core/network.h
+++ b/core/network.h
@@ -94,6 +94,11 @@ typedef struct {
94#endif 94#endif
95} ADDR; 95} ADDR;
96 96
97/* Function to receive data, ip and port of sender is put into ip_port
98 the packet data into data
99 the packet length into length. */
100typedef int (*packet_handler_callback)(IP_Port ip_port, uint8_t *data, uint32_t len);
101
97/* returns current time in milleseconds since the epoch. */ 102/* returns current time in milleseconds since the epoch. */
98uint64_t current_time(void); 103uint64_t current_time(void);
99 104
@@ -106,10 +111,11 @@ uint32_t random_int(void);
106/* Function to send packet(data) of length length to ip_port */ 111/* Function to send packet(data) of length length to ip_port */
107int sendpacket(IP_Port ip_port, uint8_t *data, uint32_t length); 112int sendpacket(IP_Port ip_port, uint8_t *data, uint32_t length);
108 113
109/* Function to receive data, ip and port of sender is put into ip_port 114/* Function to call when packet beginning with byte is received */
110 the packet data into data 115void networking_registerhandler(uint8_t byte, packet_handler_callback cb);
111 the packet length into length. */ 116
112int receivepacket(IP_Port *ip_port, uint8_t *data, uint32_t *length); 117/* call this several times a second */
118void networking_poll();
113 119
114/* initialize networking 120/* initialize networking
115 bind to ip and port 121 bind to ip and port
diff --git a/core/ping.c b/core/ping.c
index 6a1fbb7e..24ece06a 100644
--- a/core/ping.c
+++ b/core/ping.c
@@ -163,7 +163,7 @@ int send_ping_response(IP_Port ipp, clientid_t* client_id, uint64_t ping_id)
163 return sendpacket(ipp, (uint8_t*) &pk, sizeof(pk)); 163 return sendpacket(ipp, (uint8_t*) &pk, sizeof(pk));
164} 164}
165 165
166int handle_ping_request(uint8_t* packet, uint32_t length, IP_Port source) 166int handle_ping_request(IP_Port source, uint8_t* packet, uint32_t length)
167{ 167{
168 pingreq_t* p = (pingreq_t*) packet; 168 pingreq_t* p = (pingreq_t*) packet;
169 int rc; 169 int rc;
@@ -190,7 +190,7 @@ int handle_ping_request(uint8_t* packet, uint32_t length, IP_Port source)
190 return 0; 190 return 0;
191} 191}
192 192
193int handle_ping_response(uint8_t* packet, uint32_t length, IP_Port source) 193int handle_ping_response(IP_Port source, uint8_t* packet, uint32_t length)
194{ 194{
195 pingres_t* p = (pingres_t*) packet; 195 pingres_t* p = (pingres_t*) packet;
196 int rc; 196 int rc;
diff --git a/core/ping.h b/core/ping.h
index 2cab7d59..1ccfabac 100644
--- a/core/ping.h
+++ b/core/ping.h
@@ -12,5 +12,5 @@ uint64_t add_ping(IP_Port ipp);
12bool is_pinging(IP_Port ipp, uint64_t ping_id); 12bool is_pinging(IP_Port ipp, uint64_t ping_id);
13int send_ping_request(IP_Port ipp, clientid_t* client_id); 13int send_ping_request(IP_Port ipp, clientid_t* client_id);
14int send_ping_response(IP_Port ipp, clientid_t* client_id, uint64_t ping_id); 14int send_ping_response(IP_Port ipp, clientid_t* client_id, uint64_t ping_id);
15int handle_ping_request(uint8_t* packet, uint32_t length, IP_Port source); 15int handle_ping_request(IP_Port source, uint8_t* packet, uint32_t length);
16int handle_ping_response(uint8_t* packet, uint32_t length, IP_Port source); 16int handle_ping_response(IP_Port source, uint8_t* packet, uint32_t length);
diff --git a/other/CMakeLists.txt b/other/CMakeLists.txt
index 05b24f06..db742e3e 100644
--- a/other/CMakeLists.txt
+++ b/other/CMakeLists.txt
@@ -4,6 +4,6 @@ cmake_policy(SET CMP0011 NEW)
4 4
5include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/DHT_bootstrap.cmake) 5include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/DHT_bootstrap.cmake)
6 6
7if(NOT WIN32) 7if(LINUX)
8 add_subdirectory(bootstrap_serverdaemon) 8 add_subdirectory(bootstrap_serverdaemon)
9endif() 9endif()
diff --git a/other/DHT_bootstrap.c b/other/DHT_bootstrap.c
index befe2225..4b0adeff 100644
--- a/other/DHT_bootstrap.c
+++ b/other/DHT_bootstrap.c
@@ -113,9 +113,8 @@ int main(int argc, char *argv[])
113 free(bootstrap_key); 113 free(bootstrap_key);
114 } 114 }
115 115
116 IP_Port ip_port; 116 DHT_init();
117 uint8_t data[MAX_UDP_PACKET_SIZE]; 117 friendreq_init();
118 uint32_t length;
119 118
120 int is_waiting_for_dht_connection = 1; 119 int is_waiting_for_dht_connection = 1;
121 while(1) 120 while(1)
@@ -127,11 +126,8 @@ int main(int argc, char *argv[])
127 } 126 }
128 doDHT(); 127 doDHT();
129 128
130 while(receivepacket(&ip_port, data, &length) != -1) 129 networking_poll();
131 { 130
132 DHT_handlepacket(data, length, ip_port);
133 friendreq_handlepacket(data, length, ip_port);
134 }
135 c_sleep(1); 131 c_sleep(1);
136 } 132 }
137 shutdown_networking(); 133 shutdown_networking();
diff --git a/other/bootstrap_serverdaemon/DHT_bootstrap_daemon.c b/other/bootstrap_serverdaemon/DHT_bootstrap_daemon.c
index 48152744..6ce542c1 100644
--- a/other/bootstrap_serverdaemon/DHT_bootstrap_daemon.c
+++ b/other/bootstrap_serverdaemon/DHT_bootstrap_daemon.c
@@ -81,10 +81,6 @@ int connect_to_servers(struct server_info_s *info)
81 int i; 81 int i;
82 int c; 82 int c;
83 83
84 IP_Port ip_port;
85 uint8_t data[MAX_UDP_PACKET_SIZE];
86 uint32_t length;
87
88 for(i = 0; i < 32; ++i) { 84 for(i = 0; i < 32; ++i) {
89 if(info[i].valid) { 85 if(info[i].valid) {
90 /* Actual bootstrapping code goes here */ 86 /* Actual bootstrapping code goes here */
@@ -109,10 +105,7 @@ int connect_to_servers(struct server_info_s *info)
109 105
110 doDHT(); 106 doDHT();
111 107
112 while(receivepacket(&ip_port, data, &length) != -1) 108 networking_poll();
113 {
114 DHT_handlepacket(data, length, ip_port);
115 }
116 } 109 }
117 110
118 /* This probably never happens */ 111 /* This probably never happens */
@@ -337,6 +330,7 @@ int main(int argc, char *argv[]) {
337 /* Bootstrap the DHT 330 /* Bootstrap the DHT
338 This one throws odd errors, too. Ignore. I assume they come 331 This one throws odd errors, too. Ignore. I assume they come
339 from somewhere in the core. */ 332 from somewhere in the core. */
333 DHT_init();
340 tmperr = errno; 334 tmperr = errno;
341 connect_to_servers(server_conf.info); 335 connect_to_servers(server_conf.info);
342 errno = tmperr; 336 errno = tmperr;
@@ -400,19 +394,13 @@ int main(int argc, char *argv[]) {
400 close(STDERR_FILENO); 394 close(STDERR_FILENO);
401 395
402 /* Main loop */ 396 /* Main loop */
403 IP_Port ip_port; 397 friendreq_init();
404 uint8_t data[MAX_UDP_PACKET_SIZE];
405 uint32_t length;
406 398
407 while(1) 399 while(1)
408 { 400 {
409 doDHT(); 401 doDHT();
410 402
411 while(receivepacket(&ip_port, data, &length) != -1) 403 networking_poll();
412 {
413 DHT_handlepacket(data, length, ip_port);
414 friendreq_handlepacket(data, length, ip_port);
415 }
416 usleep(10000); 404 usleep(10000);
417 } 405 }
418 406
diff --git a/testing/CMakeLists.txt b/testing/CMakeLists.txt
index f2a2e95e..7322509a 100644
--- a/testing/CMakeLists.txt
+++ b/testing/CMakeLists.txt
@@ -8,6 +8,7 @@ include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/DHT_test.cmake)
8include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/Lossless_UDP_testclient.cmake) 8include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/Lossless_UDP_testclient.cmake)
9include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/Lossless_UDP_testserver.cmake) 9include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/Lossless_UDP_testserver.cmake)
10include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/Messenger_test.cmake) 10include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/Messenger_test.cmake)
11include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/crypto_speed_test.cmake)
11 12
12if(WIN32) 13if(WIN32)
13 include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/nTox_win32.cmake) 14 include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/nTox_win32.cmake)
diff --git a/testing/DHT_test.c b/testing/DHT_test.c
index c8feaf4b..350093fd 100644
--- a/testing/DHT_test.c
+++ b/testing/DHT_test.c
@@ -156,14 +156,20 @@ int main(int argc, char *argv[])
156 bootstrap_ip_port.ip.i = inet_addr(argv[1]); 156 bootstrap_ip_port.ip.i = inet_addr(argv[1]);
157 DHT_bootstrap(bootstrap_ip_port, hex_string_to_bin(argv[3])); 157 DHT_bootstrap(bootstrap_ip_port, hex_string_to_bin(argv[3]));
158 158
159/*
159 IP_Port ip_port; 160 IP_Port ip_port;
160 uint8_t data[MAX_UDP_PACKET_SIZE]; 161 uint8_t data[MAX_UDP_PACKET_SIZE];
161 uint32_t length; 162 uint32_t length;
163*/
164
165 DHT_init();
166 friendreq_init();
162 167
163 while(1) { 168 while(1) {
164 169
165 doDHT(); 170 doDHT();
166 171
172/* slvrTODO:
167 while(receivepacket(&ip_port, data, &length) != -1) { 173 while(receivepacket(&ip_port, data, &length) != -1) {
168 if(DHT_handlepacket(data, length, ip_port) && friendreq_handlepacket(data, length, ip_port)) { 174 if(DHT_handlepacket(data, length, ip_port) && friendreq_handlepacket(data, length, ip_port)) {
169 //unhandled packet 175 //unhandled packet
@@ -172,11 +178,14 @@ int main(int argc, char *argv[])
172 printf("Received handled packet with length: %u\n", length); 178 printf("Received handled packet with length: %u\n", length);
173 } 179 }
174 } 180 }
181*/
182 networking_poll();
183
175 print_clientlist(); 184 print_clientlist();
176 print_friendlist(); 185 print_friendlist();
177 c_sleep(300); 186 c_sleep(300);
178 } 187 }
179 188
180 shutdown_networking(); 189 shutdown_networking();
181 return 0; 190 return 0;
182} 191}
diff --git a/testing/Lossless_UDP_testclient.c b/testing/Lossless_UDP_testclient.c
index 78aff1a3..7efafa4f 100644
--- a/testing/Lossless_UDP_testclient.c
+++ b/testing/Lossless_UDP_testclient.c
@@ -120,20 +120,23 @@ void printconnection(int connection_id)
120/*run doLossless_UDP(); */ 120/*run doLossless_UDP(); */
121void Lossless_UDP() 121void Lossless_UDP()
122{ 122{
123 IP_Port ip_port; 123/* IP_Port ip_port;
124 uint8_t data[MAX_UDP_PACKET_SIZE]; 124 uint8_t data[MAX_UDP_PACKET_SIZE];
125 uint32_t length; 125 uint32_t length;
126 while (receivepacket(&ip_port, data, &length) != -1) { 126 while (receivepacket(&ip_port, data, &length) != -1) {
127 printf("packet with length: %u\n", length); 127 printf("packet with length: %u\n", length); */
128 /* if(rand() % 3 != 1)//add packet loss 128 /* if(rand() % 3 != 1)//add packet loss
129 { */ 129 { */
130/*
130 if (LosslessUDP_handlepacket(data, length, ip_port)) 131 if (LosslessUDP_handlepacket(data, length, ip_port))
131 printpacket(data, length, ip_port); 132 printpacket(data, length, ip_port);
132 else 133 else
133 printf("Received handled packet with length: %u\n", length); //printconnection(0); 134 printf("Received handled packet with length: %u\n", length); //printconnection(0); */
134 135
135 /* } */ 136 /* } */
136 } 137 /* }*/
138
139 networking_poll();
137 140
138 doLossless_UDP(); 141 doLossless_UDP();
139 142
@@ -181,6 +184,7 @@ int main(int argc, char *argv[])
181 } 184 }
182 timer = current_time(); 185 timer = current_time();
183 186
187 LosslessUDP_init();
184 188
185 /*read first part of file */ 189 /*read first part of file */
186 read = fread(buffer, 1, 512, file); 190 read = fread(buffer, 1, 512, file);
diff --git a/testing/Lossless_UDP_testserver.c b/testing/Lossless_UDP_testserver.c
index f4b144b4..bc4fed7a 100644
--- a/testing/Lossless_UDP_testserver.c
+++ b/testing/Lossless_UDP_testserver.c
@@ -117,20 +117,22 @@ void printconnection(int connection_id)
117 * run doLossless_UDP(); */ 117 * run doLossless_UDP(); */
118void Lossless_UDP() 118void Lossless_UDP()
119{ 119{
120 IP_Port ip_port; 120// IP_Port ip_port;
121 uint8_t data[MAX_UDP_PACKET_SIZE]; 121// uint8_t data[MAX_UDP_PACKET_SIZE];
122 uint32_t length; 122// uint32_t length;
123 while (receivepacket(&ip_port, data, &length) != -1) { 123// while (receivepacket(&ip_port, data, &length) != -1) {
124 //if(rand() % 3 != 1)//add packet loss 124 //if(rand() % 3 != 1)//add packet loss
125 //{ 125 //{
126 if (LosslessUDP_handlepacket(data, length, ip_port)) { 126// if (LosslessUDP_handlepacket(data, length, ip_port)) {
127 printpacket(data, length, ip_port); 127// printpacket(data, length, ip_port);
128 } else { 128// } else {
129 //printconnection(0); 129 //printconnection(0);
130 printf("Received handled packet with length: %u\n", length); 130// printf("Received handled packet with length: %u\n", length);
131 } 131// }
132 //} 132 //}
133 } 133// }
134
135 networking_poll();
134 136
135 doLossless_UDP(); 137 doLossless_UDP();
136} 138}
@@ -161,6 +163,7 @@ int main(int argc, char *argv[])
161 int connection; 163 int connection;
162 uint64_t timer = current_time(); 164 uint64_t timer = current_time();
163 165
166 LosslessUDP_init();
164 167
165 while (1) { 168 while (1) {
166 Lossless_UDP(); 169 Lossless_UDP();
diff --git a/testing/cmake/crypto_speed_test.cmake b/testing/cmake/crypto_speed_test.cmake
new file mode 100644
index 00000000..c269af5b
--- /dev/null
+++ b/testing/cmake/crypto_speed_test.cmake
@@ -0,0 +1,9 @@
1cmake_minimum_required(VERSION 2.6.0)
2project(crypto_speed_test C)
3
4set(exe_name crypto_speed_test)
5
6add_executable(${exe_name}
7 crypto_speed_test.c)
8
9linkCoreLibraries(${exe_name})
diff --git a/testing/crypto_speed_test.c b/testing/crypto_speed_test.c
new file mode 100644
index 00000000..81be92c6
--- /dev/null
+++ b/testing/crypto_speed_test.c
@@ -0,0 +1,130 @@
1// Hi-resolution timer
2#ifdef WIN32
3
4#include <windows.h>
5double get_time()
6{
7 LARGE_INTEGER t, f;
8 QueryPerformanceCounter(&t);
9 QueryPerformanceFrequency(&f);
10 return (double)t.QuadPart/(double)f.QuadPart;
11}
12
13#else
14
15#include <sys/time.h>
16#include <sys/resource.h>
17
18double get_time()
19{
20 struct timeval t;
21 struct timezone tzp;
22 gettimeofday(&t, &tzp);
23 return t.tv_sec + t.tv_usec*1e-6;
24}
25
26#endif
27
28#include "../core/net_crypto.h"
29#include <stdlib.h>
30#include <time.h>
31
32void rand_bytes(uint8_t *b, size_t blen)
33{
34 size_t i;
35 for (i = 0; i < blen; i++)
36 {
37 b[i] = rand();
38 }
39}
40
41int main(int argc, char* argv[])
42{
43 const int numtrials = 10000;
44
45 unsigned char pk1[crypto_box_PUBLICKEYBYTES];
46 unsigned char sk1[crypto_box_SECRETKEYBYTES];
47 unsigned char pk2[crypto_box_PUBLICKEYBYTES];
48 unsigned char sk2[crypto_box_SECRETKEYBYTES];
49 unsigned char k1[crypto_box_BEFORENMBYTES];
50 unsigned char k2[crypto_box_BEFORENMBYTES];
51
52 unsigned char n[crypto_box_NONCEBYTES];
53
54 unsigned char m[500];
55 unsigned char c[sizeof(m) + ENCRYPTION_PADDING];
56
57 unsigned char k[crypto_box_BEFORENMBYTES];
58
59 int trialno;
60
61 double starttime;
62 double endtime;
63 double slow_time;
64 double fast_time;
65 double keygen_time;
66 double precompute_time;
67
68 // Pregenerate
69 crypto_box_keypair(pk1, sk1);
70 crypto_box_keypair(pk2, sk2);
71 encrypt_precompute(pk1, sk2, k1);
72 encrypt_precompute(pk2, sk1, k2);
73 rand_bytes(m, sizeof(m));
74 rand_bytes(n, sizeof(n));
75
76 printf("starting slow...\n");
77 starttime = get_time();
78 for (trialno = 0; trialno < numtrials; trialno++)
79 {
80 encrypt_data(pk1, sk2, n, m, sizeof(m), c);
81 decrypt_data(pk2, sk1, n, c, sizeof(c), m);
82 }
83 endtime = get_time();
84 slow_time = endtime-starttime;
85
86 printf("starting fast...\n");
87 starttime = get_time();
88 for (trialno = 0; trialno < numtrials; trialno++)
89 {
90 encrypt_data_fast(k1, n, m, sizeof(m), c);
91 decrypt_data_fast(k2, n, c, sizeof(c), m);
92 }
93 endtime = get_time();
94 fast_time = endtime-starttime;
95
96 printf("starting keygen...\n");
97 starttime = get_time();
98 for (trialno = 0; trialno < numtrials; trialno++)
99 {
100 crypto_box_keypair(pk1, sk1);
101 crypto_box_keypair(pk2, sk2);
102 }
103 endtime = get_time();
104 keygen_time = endtime-starttime;
105
106 printf("starting precompute...\n");
107 starttime = get_time();
108 for (trialno = 0; trialno < numtrials; trialno++)
109 {
110 encrypt_precompute(pk1, sk2, k);
111 encrypt_precompute(pk2, sk1, k);
112 }
113 endtime = get_time();
114 precompute_time = endtime-starttime;
115
116 printf("\n");
117 printf("trials: %i\n", 2*numtrials);
118 printf("\n");
119 printf("slow time: %f sec\n", slow_time);
120 printf("fast time: %f sec\n", fast_time);
121 printf("keygen time: %f sec\n", keygen_time);
122 printf("precompute time: %f sec\n", precompute_time);
123 printf("\n");
124 printf("Speed boost: %.1f%%\n", slow_time * 100 / fast_time);
125 printf("\n");
126 printf("slow: %.1f per second\n", 2*numtrials/slow_time);
127 printf("fast: %.1f per second\n", 2*numtrials/fast_time);
128
129 return 0;
130}
diff --git a/testing/toxic/prompt.c b/testing/toxic/prompt.c
index e4eb259b..ab44e960 100644
--- a/testing/toxic/prompt.c
+++ b/testing/toxic/prompt.c
@@ -40,7 +40,7 @@ static struct {
40 void (*func)(ToxWindow *, char **); 40 void (*func)(ToxWindow *, char **);
41} commands[] = { 41} commands[] = {
42 { "accept", 1, cmd_accept }, 42 { "accept", 1, cmd_accept },
43 { "add", 2, cmd_add }, 43 { "add", 1, cmd_add },
44 { "clear", 0, cmd_clear }, 44 { "clear", 0, cmd_clear },
45 { "connect", 3, cmd_connect }, 45 { "connect", 3, cmd_connect },
46 { "exit", 0, cmd_quit }, 46 { "exit", 0, cmd_quit },
@@ -300,36 +300,54 @@ static void execute(ToxWindow *self, char *u_cmd)
300 break; 300 break;
301 cmd[cmd_end + 1] = '\0'; 301 cmd[cmd_end + 1] = '\0';
302 302
303 char *args[4]; 303 /* insert \0 at argument boundaries */
304 args[0] = strtok(cmd, " "); 304 int numargs = 0;
305 for (i = 0; i < MAX_STR_SIZE; i++) {
306 if (cmd[i] == '\"')
307 while (cmd[++i] != '\"'); /* skip over strings */
308 if (cmd[i] == ' ') {
309 cmd[i] = '\0';
310 numargs++;
311 }
312 }
313
314 /* excessive arguments */
315 if (numargs > 3) {
316 wprintw(self->window, "Invalid command: too many arguments.\n");
317 return;
318 }
319
320 /* read arguments into array */
321 char *cmdargs[5];
322 int pos = 0;
323 for (i = 0; i < 5; i++) {
324 cmdargs[i] = cmd + pos;
325 pos += strlen(cmdargs[i]) + 1;
326 }
305 327
306 /* no input */ 328 /* no input */
307 if (!args[0]) 329 if (strlen(cmdargs[0]) == 0)
308 return; 330 return;
309 331
310 /* match input to command list */ 332 /* match input to command list */
311 for (i = 0; i < NUM_COMMANDS; i++) { 333 for (i = 0; i < NUM_COMMANDS; i++) {
312 if (!strcmp(args[0], commands[i].name)) { 334 if (!strcmp(cmdargs[0], commands[i].name)) {
313 /* read in arguments */ 335 /* check for missing arguments */
314 int j; 336 int j;
315 for (j = 1; j <= commands[i].numargs; j++) { 337 for (j = 0; j <= commands[i].numargs; j++) {
316 args[j] = strtok(NULL, " "); 338 if (strlen(cmdargs[j]) == 0) {
317 /* check for missing arguments */
318 /* add is special because it can take either 1 or 2 arguments */
319 if (strcmp(args[0], "add") != 0 && args[j] == NULL) {
320 wprintw(self->window, "Invalid command: %s expected %d arguments, got %d.\n", 339 wprintw(self->window, "Invalid command: %s expected %d arguments, got %d.\n",
321 commands[i].name, commands[i].numargs, j - 1); 340 commands[i].name, commands[i].numargs, j - 1);
322 return; 341 return;
323 } 342 }
324 } 343 }
325 /* check for excess arguments */ 344 /* check for excess arguments */
326 /* add is special because the add message may contain spaces */ 345 if (strcmp(cmdargs[0], "add") && strlen(cmdargs[j]) != 0) {
327 if (strcmp(args[0], "add") != 0 && strtok(NULL, " ") != NULL) {
328 wprintw(self->window, "Invalid command: too many arguments to %s.\n", commands[i].name); 346 wprintw(self->window, "Invalid command: too many arguments to %s.\n", commands[i].name);
329 return; 347 return;
330 } 348 }
331 /* pass arguments to command function */ 349 /* pass arguments to command function */
332 (commands[i].func)(self, args); 350 (commands[i].func)(self, cmdargs);
333 return; 351 return;
334 } 352 }
335 } 353 }